m5602_s5k4aa.c 17 KB

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