m5602_s5k4aa.c 16 KB

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