m5602_s5k4aa.c 17 KB

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