m5602_s5k4aa.c 17 KB

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