m5602_s5k4aa.c 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682
  1. /*
  2. * Driver for the s5k4aa sensor
  3. *
  4. * Copyright (C) 2008 Erik Andrén
  5. * Copyright (C) 2007 Ilyes Gouta. Based on the m5603x Linux Driver Project.
  6. * Copyright (C) 2005 m5603x Linux Driver Project <m5602@x3ng.com.br>
  7. *
  8. * Portions of code to USB interface and ALi driver software,
  9. * Copyright (c) 2006 Willem Duinker
  10. * v4l2 interface modeled after the V4L2 driver
  11. * for SN9C10x PC Camera Controllers
  12. *
  13. * This program is free software; you can redistribute it and/or
  14. * modify it under the terms of the GNU General Public License as
  15. * published by the Free Software Foundation, version 2.
  16. *
  17. */
  18. #include "m5602_s5k4aa.h"
  19. static int s5k4aa_get_exposure(struct gspca_dev *gspca_dev, __s32 *val);
  20. static int s5k4aa_set_exposure(struct gspca_dev *gspca_dev, __s32 val);
  21. static int s5k4aa_get_vflip(struct gspca_dev *gspca_dev, __s32 *val);
  22. static int s5k4aa_set_vflip(struct gspca_dev *gspca_dev, __s32 val);
  23. static int s5k4aa_get_hflip(struct gspca_dev *gspca_dev, __s32 *val);
  24. static int s5k4aa_set_hflip(struct gspca_dev *gspca_dev, __s32 val);
  25. static int s5k4aa_get_gain(struct gspca_dev *gspca_dev, __s32 *val);
  26. static int s5k4aa_set_gain(struct gspca_dev *gspca_dev, __s32 val);
  27. static int s5k4aa_get_noise(struct gspca_dev *gspca_dev, __s32 *val);
  28. static int s5k4aa_set_noise(struct gspca_dev *gspca_dev, __s32 val);
  29. static int s5k4aa_get_brightness(struct gspca_dev *gspca_dev, __s32 *val);
  30. static int s5k4aa_set_brightness(struct gspca_dev *gspca_dev, __s32 val);
  31. static
  32. const
  33. struct dmi_system_id s5k4aa_vflip_dmi_table[] = {
  34. {
  35. .ident = "Fujitsu-Siemens Amilo Xa 2528",
  36. .matches = {
  37. DMI_MATCH(DMI_SYS_VENDOR, "FUJITSU SIEMENS"),
  38. DMI_MATCH(DMI_PRODUCT_NAME, "AMILO Xa 2528")
  39. }
  40. }, {
  41. .ident = "Fujitsu-Siemens Amilo Xi 2550",
  42. .matches = {
  43. DMI_MATCH(DMI_SYS_VENDOR, "FUJITSU SIEMENS"),
  44. DMI_MATCH(DMI_PRODUCT_NAME, "AMILO Xi 2550")
  45. }
  46. }, {
  47. .ident = "Fujitsu-Siemens Amilo Pa 2548",
  48. .matches = {
  49. DMI_MATCH(DMI_SYS_VENDOR, "FUJITSU SIEMENS"),
  50. DMI_MATCH(DMI_PRODUCT_NAME, "AMILO Pa 2548")
  51. }
  52. }, {
  53. .ident = "MSI GX700",
  54. .matches = {
  55. DMI_MATCH(DMI_SYS_VENDOR, "Micro-Star International"),
  56. DMI_MATCH(DMI_PRODUCT_NAME, "GX700"),
  57. DMI_MATCH(DMI_BIOS_DATE, "07/26/2007")
  58. }
  59. }, {
  60. .ident = "MSI GX700/GX705/EX700",
  61. .matches = {
  62. DMI_MATCH(DMI_SYS_VENDOR, "Micro-Star International"),
  63. DMI_MATCH(DMI_PRODUCT_NAME, "GX700/GX705/EX700")
  64. }
  65. }, {
  66. .ident = "MSI L735",
  67. .matches = {
  68. DMI_MATCH(DMI_SYS_VENDOR, "Micro-Star International"),
  69. DMI_MATCH(DMI_PRODUCT_NAME, "MS-1717X")
  70. }
  71. }, {
  72. .ident = "Lenovo Y300",
  73. .matches = {
  74. DMI_MATCH(DMI_SYS_VENDOR, "L3000 Y300"),
  75. DMI_MATCH(DMI_PRODUCT_NAME, "Y300")
  76. }
  77. },
  78. { }
  79. };
  80. static struct v4l2_pix_format s5k4aa_modes[] = {
  81. {
  82. 640,
  83. 480,
  84. V4L2_PIX_FMT_SBGGR8,
  85. V4L2_FIELD_NONE,
  86. .sizeimage =
  87. 640 * 480,
  88. .bytesperline = 640,
  89. .colorspace = V4L2_COLORSPACE_SRGB,
  90. .priv = 0
  91. },
  92. {
  93. 1280,
  94. 1024,
  95. V4L2_PIX_FMT_SBGGR8,
  96. V4L2_FIELD_NONE,
  97. .sizeimage =
  98. 1280 * 1024,
  99. .bytesperline = 1280,
  100. .colorspace = V4L2_COLORSPACE_SRGB,
  101. .priv = 0
  102. }
  103. };
  104. static const struct ctrl s5k4aa_ctrls[] = {
  105. #define VFLIP_IDX 0
  106. {
  107. {
  108. .id = V4L2_CID_VFLIP,
  109. .type = V4L2_CTRL_TYPE_BOOLEAN,
  110. .name = "vertical flip",
  111. .minimum = 0,
  112. .maximum = 1,
  113. .step = 1,
  114. .default_value = 0
  115. },
  116. .set = s5k4aa_set_vflip,
  117. .get = s5k4aa_get_vflip
  118. },
  119. #define HFLIP_IDX 1
  120. {
  121. {
  122. .id = V4L2_CID_HFLIP,
  123. .type = V4L2_CTRL_TYPE_BOOLEAN,
  124. .name = "horizontal flip",
  125. .minimum = 0,
  126. .maximum = 1,
  127. .step = 1,
  128. .default_value = 0
  129. },
  130. .set = s5k4aa_set_hflip,
  131. .get = s5k4aa_get_hflip
  132. },
  133. #define GAIN_IDX 2
  134. {
  135. {
  136. .id = V4L2_CID_GAIN,
  137. .type = V4L2_CTRL_TYPE_INTEGER,
  138. .name = "Gain",
  139. .minimum = 0,
  140. .maximum = 127,
  141. .step = 1,
  142. .default_value = S5K4AA_DEFAULT_GAIN,
  143. .flags = V4L2_CTRL_FLAG_SLIDER
  144. },
  145. .set = s5k4aa_set_gain,
  146. .get = s5k4aa_get_gain
  147. },
  148. #define EXPOSURE_IDX 3
  149. {
  150. {
  151. .id = V4L2_CID_EXPOSURE,
  152. .type = V4L2_CTRL_TYPE_INTEGER,
  153. .name = "Exposure",
  154. .minimum = 13,
  155. .maximum = 0xfff,
  156. .step = 1,
  157. .default_value = 0x100,
  158. .flags = V4L2_CTRL_FLAG_SLIDER
  159. },
  160. .set = s5k4aa_set_exposure,
  161. .get = s5k4aa_get_exposure
  162. },
  163. #define NOISE_SUPP_IDX 4
  164. {
  165. {
  166. .id = V4L2_CID_PRIVATE_BASE,
  167. .type = V4L2_CTRL_TYPE_BOOLEAN,
  168. .name = "Noise suppression (smoothing)",
  169. .minimum = 0,
  170. .maximum = 1,
  171. .step = 1,
  172. .default_value = 1,
  173. },
  174. .set = s5k4aa_set_noise,
  175. .get = s5k4aa_get_noise
  176. },
  177. #define BRIGHTNESS_IDX 5
  178. {
  179. {
  180. .id = V4L2_CID_BRIGHTNESS,
  181. .type = V4L2_CTRL_TYPE_INTEGER,
  182. .name = "Brightness",
  183. .minimum = 0,
  184. .maximum = 0x1f,
  185. .step = 1,
  186. .default_value = S5K4AA_DEFAULT_BRIGHTNESS,
  187. },
  188. .set = s5k4aa_set_brightness,
  189. .get = s5k4aa_get_brightness
  190. },
  191. };
  192. static void s5k4aa_dump_registers(struct sd *sd);
  193. int s5k4aa_probe(struct sd *sd)
  194. {
  195. u8 prod_id[6] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
  196. const u8 expected_prod_id[6] = {0x00, 0x10, 0x00, 0x4b, 0x33, 0x75};
  197. int i, err = 0;
  198. s32 *sensor_settings;
  199. if (force_sensor) {
  200. if (force_sensor == S5K4AA_SENSOR) {
  201. info("Forcing a %s sensor", s5k4aa.name);
  202. goto sensor_found;
  203. }
  204. /* If we want to force another sensor, don't try to probe this
  205. * one */
  206. return -ENODEV;
  207. }
  208. info("Probing for a s5k4aa sensor");
  209. /* Preinit the sensor */
  210. for (i = 0; i < ARRAY_SIZE(preinit_s5k4aa) && !err; i++) {
  211. u8 data[2] = {0x00, 0x00};
  212. switch (preinit_s5k4aa[i][0]) {
  213. case BRIDGE:
  214. err = m5602_write_bridge(sd,
  215. preinit_s5k4aa[i][1],
  216. preinit_s5k4aa[i][2]);
  217. break;
  218. case SENSOR:
  219. data[0] = preinit_s5k4aa[i][2];
  220. err = m5602_write_sensor(sd,
  221. preinit_s5k4aa[i][1],
  222. data, 1);
  223. break;
  224. case SENSOR_LONG:
  225. data[0] = preinit_s5k4aa[i][2];
  226. data[1] = preinit_s5k4aa[i][3];
  227. err = m5602_write_sensor(sd,
  228. preinit_s5k4aa[i][1],
  229. data, 2);
  230. break;
  231. default:
  232. info("Invalid stream command, exiting init");
  233. return -EINVAL;
  234. }
  235. }
  236. /* Test some registers, but we don't know their exact meaning yet */
  237. if (m5602_read_sensor(sd, 0x00, prod_id, 2))
  238. return -ENODEV;
  239. if (m5602_read_sensor(sd, 0x02, prod_id+2, 2))
  240. return -ENODEV;
  241. if (m5602_read_sensor(sd, 0x04, prod_id+4, 2))
  242. return -ENODEV;
  243. if (memcmp(prod_id, expected_prod_id, sizeof(prod_id)))
  244. return -ENODEV;
  245. else
  246. info("Detected a s5k4aa sensor");
  247. sensor_found:
  248. sensor_settings = kmalloc(
  249. ARRAY_SIZE(s5k4aa_ctrls) * sizeof(s32), GFP_KERNEL);
  250. if (!sensor_settings)
  251. return -ENOMEM;
  252. sd->gspca_dev.cam.cam_mode = s5k4aa_modes;
  253. sd->gspca_dev.cam.nmodes = ARRAY_SIZE(s5k4aa_modes);
  254. sd->desc->ctrls = s5k4aa_ctrls;
  255. sd->desc->nctrls = ARRAY_SIZE(s5k4aa_ctrls);
  256. for (i = 0; i < ARRAY_SIZE(s5k4aa_ctrls); i++)
  257. sensor_settings[i] = s5k4aa_ctrls[i].qctrl.default_value;
  258. sd->sensor_priv = sensor_settings;
  259. return 0;
  260. }
  261. int s5k4aa_start(struct sd *sd)
  262. {
  263. int i, err = 0;
  264. u8 data[2];
  265. struct cam *cam = &sd->gspca_dev.cam;
  266. s32 *sensor_settings = sd->sensor_priv;
  267. switch (cam->cam_mode[sd->gspca_dev.curr_mode].width) {
  268. case 1280:
  269. PDEBUG(D_V4L2, "Configuring camera for SXGA mode");
  270. for (i = 0; i < ARRAY_SIZE(SXGA_s5k4aa); i++) {
  271. switch (SXGA_s5k4aa[i][0]) {
  272. case BRIDGE:
  273. err = m5602_write_bridge(sd,
  274. SXGA_s5k4aa[i][1],
  275. SXGA_s5k4aa[i][2]);
  276. break;
  277. case SENSOR:
  278. data[0] = SXGA_s5k4aa[i][2];
  279. err = m5602_write_sensor(sd,
  280. SXGA_s5k4aa[i][1],
  281. data, 1);
  282. break;
  283. case SENSOR_LONG:
  284. data[0] = SXGA_s5k4aa[i][2];
  285. data[1] = SXGA_s5k4aa[i][3];
  286. err = m5602_write_sensor(sd,
  287. SXGA_s5k4aa[i][1],
  288. data, 2);
  289. break;
  290. default:
  291. err("Invalid stream command, exiting init");
  292. return -EINVAL;
  293. }
  294. }
  295. err = s5k4aa_set_noise(&sd->gspca_dev, 0);
  296. if (err < 0)
  297. return err;
  298. break;
  299. case 640:
  300. PDEBUG(D_V4L2, "Configuring camera for VGA mode");
  301. for (i = 0; i < ARRAY_SIZE(VGA_s5k4aa); i++) {
  302. switch (VGA_s5k4aa[i][0]) {
  303. case BRIDGE:
  304. err = m5602_write_bridge(sd,
  305. VGA_s5k4aa[i][1],
  306. VGA_s5k4aa[i][2]);
  307. break;
  308. case SENSOR:
  309. data[0] = VGA_s5k4aa[i][2];
  310. err = m5602_write_sensor(sd,
  311. VGA_s5k4aa[i][1],
  312. data, 1);
  313. break;
  314. case SENSOR_LONG:
  315. data[0] = VGA_s5k4aa[i][2];
  316. data[1] = VGA_s5k4aa[i][3];
  317. err = m5602_write_sensor(sd,
  318. VGA_s5k4aa[i][1],
  319. data, 2);
  320. break;
  321. default:
  322. err("Invalid stream command, exiting init");
  323. return -EINVAL;
  324. }
  325. }
  326. err = s5k4aa_set_noise(&sd->gspca_dev, 1);
  327. if (err < 0)
  328. return err;
  329. break;
  330. }
  331. if (err < 0)
  332. return err;
  333. err = s5k4aa_set_exposure(&sd->gspca_dev,
  334. sensor_settings[EXPOSURE_IDX]);
  335. if (err < 0)
  336. return err;
  337. err = s5k4aa_set_gain(&sd->gspca_dev, sensor_settings[GAIN_IDX]);
  338. if (err < 0)
  339. return err;
  340. err = s5k4aa_set_brightness(&sd->gspca_dev,
  341. sensor_settings[BRIGHTNESS_IDX]);
  342. if (err < 0)
  343. return err;
  344. err = s5k4aa_set_noise(&sd->gspca_dev, sensor_settings[NOISE_SUPP_IDX]);
  345. if (err < 0)
  346. return err;
  347. err = s5k4aa_set_vflip(&sd->gspca_dev, sensor_settings[VFLIP_IDX]);
  348. if (err < 0)
  349. return err;
  350. return s5k4aa_set_hflip(&sd->gspca_dev, sensor_settings[HFLIP_IDX]);
  351. }
  352. int s5k4aa_init(struct sd *sd)
  353. {
  354. int i, err = 0;
  355. for (i = 0; i < ARRAY_SIZE(init_s5k4aa) && !err; i++) {
  356. u8 data[2] = {0x00, 0x00};
  357. switch (init_s5k4aa[i][0]) {
  358. case BRIDGE:
  359. err = m5602_write_bridge(sd,
  360. init_s5k4aa[i][1],
  361. init_s5k4aa[i][2]);
  362. break;
  363. case SENSOR:
  364. data[0] = init_s5k4aa[i][2];
  365. err = m5602_write_sensor(sd,
  366. init_s5k4aa[i][1], data, 1);
  367. break;
  368. case SENSOR_LONG:
  369. data[0] = init_s5k4aa[i][2];
  370. data[1] = init_s5k4aa[i][3];
  371. err = m5602_write_sensor(sd,
  372. init_s5k4aa[i][1], data, 2);
  373. break;
  374. default:
  375. info("Invalid stream command, exiting init");
  376. return -EINVAL;
  377. }
  378. }
  379. if (dump_sensor)
  380. s5k4aa_dump_registers(sd);
  381. return err;
  382. }
  383. static int s5k4aa_get_exposure(struct gspca_dev *gspca_dev, __s32 *val)
  384. {
  385. struct sd *sd = (struct sd *) gspca_dev;
  386. s32 *sensor_settings = sd->sensor_priv;
  387. *val = sensor_settings[EXPOSURE_IDX];
  388. PDEBUG(D_V4L2, "Read exposure %d", *val);
  389. return 0;
  390. }
  391. static int s5k4aa_set_exposure(struct gspca_dev *gspca_dev, __s32 val)
  392. {
  393. struct sd *sd = (struct sd *) gspca_dev;
  394. s32 *sensor_settings = sd->sensor_priv;
  395. u8 data = S5K4AA_PAGE_MAP_2;
  396. int err;
  397. sensor_settings[EXPOSURE_IDX] = val;
  398. PDEBUG(D_V4L2, "Set exposure to %d", val);
  399. err = m5602_write_sensor(sd, S5K4AA_PAGE_MAP, &data, 1);
  400. if (err < 0)
  401. return err;
  402. data = (val >> 8) & 0xff;
  403. err = m5602_write_sensor(sd, S5K4AA_EXPOSURE_HI, &data, 1);
  404. if (err < 0)
  405. return err;
  406. data = val & 0xff;
  407. err = m5602_write_sensor(sd, S5K4AA_EXPOSURE_LO, &data, 1);
  408. return err;
  409. }
  410. static int s5k4aa_get_vflip(struct gspca_dev *gspca_dev, __s32 *val)
  411. {
  412. struct sd *sd = (struct sd *) gspca_dev;
  413. s32 *sensor_settings = sd->sensor_priv;
  414. *val = sensor_settings[VFLIP_IDX];
  415. PDEBUG(D_V4L2, "Read vertical flip %d", *val);
  416. return 0;
  417. }
  418. static int s5k4aa_set_vflip(struct gspca_dev *gspca_dev, __s32 val)
  419. {
  420. struct sd *sd = (struct sd *) gspca_dev;
  421. s32 *sensor_settings = sd->sensor_priv;
  422. u8 data = S5K4AA_PAGE_MAP_2;
  423. int err;
  424. sensor_settings[VFLIP_IDX] = val;
  425. PDEBUG(D_V4L2, "Set vertical flip to %d", val);
  426. err = m5602_write_sensor(sd, S5K4AA_PAGE_MAP, &data, 1);
  427. if (err < 0)
  428. return err;
  429. err = m5602_read_sensor(sd, S5K4AA_READ_MODE, &data, 1);
  430. if (err < 0)
  431. return err;
  432. if (dmi_check_system(s5k4aa_vflip_dmi_table))
  433. val = !val;
  434. data = ((data & ~S5K4AA_RM_V_FLIP) | ((val & 0x01) << 7));
  435. err = m5602_write_sensor(sd, S5K4AA_READ_MODE, &data, 1);
  436. if (err < 0)
  437. return err;
  438. err = m5602_read_sensor(sd, S5K4AA_ROWSTART_LO, &data, 1);
  439. if (err < 0)
  440. return err;
  441. data = (data & 0xfe) | !val;
  442. err = m5602_write_sensor(sd, S5K4AA_ROWSTART_LO, &data, 1);
  443. return err;
  444. }
  445. static int s5k4aa_get_hflip(struct gspca_dev *gspca_dev, __s32 *val)
  446. {
  447. struct sd *sd = (struct sd *) gspca_dev;
  448. s32 *sensor_settings = sd->sensor_priv;
  449. *val = sensor_settings[HFLIP_IDX];
  450. PDEBUG(D_V4L2, "Read horizontal flip %d", *val);
  451. return 0;
  452. }
  453. static int s5k4aa_set_hflip(struct gspca_dev *gspca_dev, __s32 val)
  454. {
  455. struct sd *sd = (struct sd *) gspca_dev;
  456. s32 *sensor_settings = sd->sensor_priv;
  457. u8 data = S5K4AA_PAGE_MAP_2;
  458. int err;
  459. sensor_settings[HFLIP_IDX] = val;
  460. PDEBUG(D_V4L2, "Set horizontal flip to %d", val);
  461. err = m5602_write_sensor(sd, S5K4AA_PAGE_MAP, &data, 1);
  462. if (err < 0)
  463. return err;
  464. err = m5602_read_sensor(sd, S5K4AA_READ_MODE, &data, 1);
  465. if (err < 0)
  466. return err;
  467. if (dmi_check_system(s5k4aa_vflip_dmi_table))
  468. val = !val;
  469. data = ((data & ~S5K4AA_RM_H_FLIP) | ((val & 0x01) << 6));
  470. err = m5602_write_sensor(sd, S5K4AA_READ_MODE, &data, 1);
  471. if (err < 0)
  472. return err;
  473. err = m5602_read_sensor(sd, S5K4AA_COLSTART_LO, &data, 1);
  474. if (err < 0)
  475. return err;
  476. data = (data & 0xfe) | !val;
  477. err = m5602_write_sensor(sd, S5K4AA_COLSTART_LO, &data, 1);
  478. return err;
  479. }
  480. static int s5k4aa_get_gain(struct gspca_dev *gspca_dev, __s32 *val)
  481. {
  482. struct sd *sd = (struct sd *) gspca_dev;
  483. s32 *sensor_settings = sd->sensor_priv;
  484. *val = sensor_settings[GAIN_IDX];
  485. PDEBUG(D_V4L2, "Read gain %d", *val);
  486. return 0;
  487. }
  488. static int s5k4aa_set_gain(struct gspca_dev *gspca_dev, __s32 val)
  489. {
  490. struct sd *sd = (struct sd *) gspca_dev;
  491. s32 *sensor_settings = sd->sensor_priv;
  492. u8 data = S5K4AA_PAGE_MAP_2;
  493. int err;
  494. sensor_settings[GAIN_IDX] = val;
  495. PDEBUG(D_V4L2, "Set gain to %d", val);
  496. err = m5602_write_sensor(sd, S5K4AA_PAGE_MAP, &data, 1);
  497. if (err < 0)
  498. return err;
  499. data = val & 0xff;
  500. err = m5602_write_sensor(sd, S5K4AA_GAIN, &data, 1);
  501. return err;
  502. }
  503. static int s5k4aa_get_brightness(struct gspca_dev *gspca_dev, __s32 *val)
  504. {
  505. struct sd *sd = (struct sd *) gspca_dev;
  506. s32 *sensor_settings = sd->sensor_priv;
  507. *val = sensor_settings[BRIGHTNESS_IDX];
  508. PDEBUG(D_V4L2, "Read brightness %d", *val);
  509. return 0;
  510. }
  511. static int s5k4aa_set_brightness(struct gspca_dev *gspca_dev, __s32 val)
  512. {
  513. struct sd *sd = (struct sd *) gspca_dev;
  514. s32 *sensor_settings = sd->sensor_priv;
  515. u8 data = S5K4AA_PAGE_MAP_2;
  516. int err;
  517. sensor_settings[BRIGHTNESS_IDX] = val;
  518. PDEBUG(D_V4L2, "Set brightness to %d", val);
  519. err = m5602_write_sensor(sd, S5K4AA_PAGE_MAP, &data, 1);
  520. if (err < 0)
  521. return err;
  522. data = val & 0xff;
  523. return m5602_write_sensor(sd, S5K4AA_BRIGHTNESS, &data, 1);
  524. }
  525. static int s5k4aa_get_noise(struct gspca_dev *gspca_dev, __s32 *val)
  526. {
  527. struct sd *sd = (struct sd *) gspca_dev;
  528. s32 *sensor_settings = sd->sensor_priv;
  529. *val = sensor_settings[NOISE_SUPP_IDX];
  530. PDEBUG(D_V4L2, "Read noise %d", *val);
  531. return 0;
  532. }
  533. static int s5k4aa_set_noise(struct gspca_dev *gspca_dev, __s32 val)
  534. {
  535. struct sd *sd = (struct sd *) gspca_dev;
  536. s32 *sensor_settings = sd->sensor_priv;
  537. u8 data = S5K4AA_PAGE_MAP_2;
  538. int err;
  539. sensor_settings[NOISE_SUPP_IDX] = val;
  540. PDEBUG(D_V4L2, "Set noise to %d", val);
  541. err = m5602_write_sensor(sd, S5K4AA_PAGE_MAP, &data, 1);
  542. if (err < 0)
  543. return err;
  544. data = val & 0x01;
  545. return m5602_write_sensor(sd, S5K4AA_NOISE_SUPP, &data, 1);
  546. }
  547. void s5k4aa_disconnect(struct sd *sd)
  548. {
  549. sd->sensor = NULL;
  550. kfree(sd->sensor_priv);
  551. }
  552. static void s5k4aa_dump_registers(struct sd *sd)
  553. {
  554. int address;
  555. u8 page, old_page;
  556. m5602_read_sensor(sd, S5K4AA_PAGE_MAP, &old_page, 1);
  557. for (page = 0; page < 16; page++) {
  558. m5602_write_sensor(sd, S5K4AA_PAGE_MAP, &page, 1);
  559. info("Dumping the s5k4aa register state for page 0x%x", page);
  560. for (address = 0; address <= 0xff; address++) {
  561. u8 value = 0;
  562. m5602_read_sensor(sd, address, &value, 1);
  563. info("register 0x%x contains 0x%x",
  564. address, value);
  565. }
  566. }
  567. info("s5k4aa register state dump complete");
  568. for (page = 0; page < 16; page++) {
  569. m5602_write_sensor(sd, S5K4AA_PAGE_MAP, &page, 1);
  570. info("Probing for which registers that are "
  571. "read/write for page 0x%x", page);
  572. for (address = 0; address <= 0xff; address++) {
  573. u8 old_value, ctrl_value, test_value = 0xff;
  574. m5602_read_sensor(sd, address, &old_value, 1);
  575. m5602_write_sensor(sd, address, &test_value, 1);
  576. m5602_read_sensor(sd, address, &ctrl_value, 1);
  577. if (ctrl_value == test_value)
  578. info("register 0x%x is writeable", address);
  579. else
  580. info("register 0x%x is read only", address);
  581. /* Restore original value */
  582. m5602_write_sensor(sd, address, &old_value, 1);
  583. }
  584. }
  585. info("Read/write register probing complete");
  586. m5602_write_sensor(sd, S5K4AA_PAGE_MAP, &old_page, 1);
  587. }