m5602_s5k4aa.c 17 KB

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