m5602_s5k4aa.c 17 KB

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