m5602_s5k4aa.c 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527
  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
  20. const
  21. struct dmi_system_id s5k4aa_vflip_dmi_table[] = {
  22. {
  23. .ident = "Fujitsu-Siemens Amilo Xa 2528",
  24. .matches = {
  25. DMI_MATCH(DMI_SYS_VENDOR, "FUJITSU SIEMENS"),
  26. DMI_MATCH(DMI_PRODUCT_NAME, "AMILO Xa 2528")
  27. }
  28. }, {
  29. .ident = "Fujitsu-Siemens Amilo Xi 2550",
  30. .matches = {
  31. DMI_MATCH(DMI_SYS_VENDOR, "FUJITSU SIEMENS"),
  32. DMI_MATCH(DMI_PRODUCT_NAME, "AMILO Xi 2550")
  33. }
  34. }, {
  35. .ident = "MSI GX700",
  36. .matches = {
  37. DMI_MATCH(DMI_SYS_VENDOR, "Micro-Star International"),
  38. DMI_MATCH(DMI_PRODUCT_NAME, "GX700"),
  39. DMI_MATCH(DMI_BIOS_DATE, "07/26/2007")
  40. }
  41. }, {
  42. .ident = "MSI GX700/GX705/EX700",
  43. .matches = {
  44. DMI_MATCH(DMI_SYS_VENDOR, "Micro-Star International"),
  45. DMI_MATCH(DMI_PRODUCT_NAME, "GX700/GX705/EX700")
  46. }
  47. },
  48. { }
  49. };
  50. static struct v4l2_pix_format s5k4aa_modes[] = {
  51. {
  52. 640,
  53. 480,
  54. V4L2_PIX_FMT_SBGGR8,
  55. V4L2_FIELD_NONE,
  56. .sizeimage =
  57. 640 * 480,
  58. .bytesperline = 640,
  59. .colorspace = V4L2_COLORSPACE_SRGB,
  60. .priv = 0
  61. }
  62. };
  63. const static struct ctrl s5k4aa_ctrls[] = {
  64. {
  65. {
  66. .id = V4L2_CID_VFLIP,
  67. .type = V4L2_CTRL_TYPE_BOOLEAN,
  68. .name = "vertical flip",
  69. .minimum = 0,
  70. .maximum = 1,
  71. .step = 1,
  72. .default_value = 0
  73. },
  74. .set = s5k4aa_set_vflip,
  75. .get = s5k4aa_get_vflip
  76. }, {
  77. {
  78. .id = V4L2_CID_HFLIP,
  79. .type = V4L2_CTRL_TYPE_BOOLEAN,
  80. .name = "horizontal flip",
  81. .minimum = 0,
  82. .maximum = 1,
  83. .step = 1,
  84. .default_value = 0
  85. },
  86. .set = s5k4aa_set_hflip,
  87. .get = s5k4aa_get_hflip
  88. }, {
  89. {
  90. .id = V4L2_CID_GAIN,
  91. .type = V4L2_CTRL_TYPE_INTEGER,
  92. .name = "Gain",
  93. .minimum = 0,
  94. .maximum = 127,
  95. .step = 1,
  96. .default_value = 0xa0,
  97. .flags = V4L2_CTRL_FLAG_SLIDER
  98. },
  99. .set = s5k4aa_set_gain,
  100. .get = s5k4aa_get_gain
  101. }, {
  102. {
  103. .id = V4L2_CID_EXPOSURE,
  104. .type = V4L2_CTRL_TYPE_INTEGER,
  105. .name = "Exposure",
  106. .minimum = 13,
  107. .maximum = 0xfff,
  108. .step = 1,
  109. .default_value = 0x100,
  110. .flags = V4L2_CTRL_FLAG_SLIDER
  111. },
  112. .set = s5k4aa_set_exposure,
  113. .get = s5k4aa_get_exposure
  114. }
  115. };
  116. static void s5k4aa_dump_registers(struct sd *sd);
  117. int s5k4aa_probe(struct sd *sd)
  118. {
  119. u8 prod_id[6] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
  120. const u8 expected_prod_id[6] = {0x00, 0x10, 0x00, 0x4b, 0x33, 0x75};
  121. int i, err = 0;
  122. if (force_sensor) {
  123. if (force_sensor == S5K4AA_SENSOR) {
  124. info("Forcing a %s sensor", s5k4aa.name);
  125. goto sensor_found;
  126. }
  127. /* If we want to force another sensor, don't try to probe this
  128. * one */
  129. return -ENODEV;
  130. }
  131. info("Probing for a s5k4aa sensor");
  132. /* Preinit the sensor */
  133. for (i = 0; i < ARRAY_SIZE(preinit_s5k4aa) && !err; i++) {
  134. u8 data[2] = {0x00, 0x00};
  135. switch (preinit_s5k4aa[i][0]) {
  136. case BRIDGE:
  137. err = m5602_write_bridge(sd,
  138. preinit_s5k4aa[i][1],
  139. preinit_s5k4aa[i][2]);
  140. break;
  141. case SENSOR:
  142. data[0] = preinit_s5k4aa[i][2];
  143. err = m5602_write_sensor(sd,
  144. preinit_s5k4aa[i][1],
  145. data, 1);
  146. break;
  147. case SENSOR_LONG:
  148. data[0] = preinit_s5k4aa[i][2];
  149. data[1] = preinit_s5k4aa[i][3];
  150. err = m5602_write_sensor(sd,
  151. preinit_s5k4aa[i][1],
  152. data, 2);
  153. break;
  154. default:
  155. info("Invalid stream command, exiting init");
  156. return -EINVAL;
  157. }
  158. }
  159. /* Test some registers, but we don't know their exact meaning yet */
  160. if (m5602_read_sensor(sd, 0x00, prod_id, 2))
  161. return -ENODEV;
  162. if (m5602_read_sensor(sd, 0x02, prod_id+2, 2))
  163. return -ENODEV;
  164. if (m5602_read_sensor(sd, 0x04, prod_id+4, 2))
  165. return -ENODEV;
  166. if (memcmp(prod_id, expected_prod_id, sizeof(prod_id)))
  167. return -ENODEV;
  168. else
  169. info("Detected a s5k4aa sensor");
  170. sensor_found:
  171. sd->gspca_dev.cam.cam_mode = s5k4aa_modes;
  172. sd->gspca_dev.cam.nmodes = ARRAY_SIZE(s5k4aa_modes);
  173. sd->desc->ctrls = s5k4aa_ctrls;
  174. sd->desc->nctrls = ARRAY_SIZE(s5k4aa_ctrls);
  175. return 0;
  176. }
  177. int s5k4aa_start(struct sd *sd)
  178. {
  179. int i, err = 0;
  180. u8 data[2];
  181. struct cam *cam = &sd->gspca_dev.cam;
  182. switch (cam->cam_mode[sd->gspca_dev.curr_mode].width)
  183. {
  184. case 640:
  185. PDEBUG(D_V4L2, "Configuring camera for VGA mode");
  186. for (i = 0; i < ARRAY_SIZE(VGA_s5k4aa); i++) {
  187. switch (VGA_s5k4aa[i][0]) {
  188. case BRIDGE:
  189. err = m5602_write_bridge(sd,
  190. VGA_s5k4aa[i][1],
  191. VGA_s5k4aa[i][2]);
  192. break;
  193. case SENSOR:
  194. data[0] = VGA_s5k4aa[i][2];
  195. err = m5602_write_sensor(sd,
  196. VGA_s5k4aa[i][1],
  197. data, 1);
  198. break;
  199. case SENSOR_LONG:
  200. data[0] = VGA_s5k4aa[i][2];
  201. data[1] = VGA_s5k4aa[i][3];
  202. err = m5602_write_sensor(sd,
  203. VGA_s5k4aa[i][1],
  204. data, 2);
  205. break;
  206. default:
  207. err("Invalid stream command, exiting init");
  208. return -EINVAL;
  209. }
  210. }
  211. }
  212. return err;
  213. }
  214. int s5k4aa_init(struct sd *sd)
  215. {
  216. int i, err = 0;
  217. for (i = 0; i < ARRAY_SIZE(init_s5k4aa) && !err; i++) {
  218. u8 data[2] = {0x00, 0x00};
  219. switch (init_s5k4aa[i][0]) {
  220. case BRIDGE:
  221. err = m5602_write_bridge(sd,
  222. init_s5k4aa[i][1],
  223. init_s5k4aa[i][2]);
  224. break;
  225. case SENSOR:
  226. data[0] = init_s5k4aa[i][2];
  227. err = m5602_write_sensor(sd,
  228. init_s5k4aa[i][1], data, 1);
  229. break;
  230. case SENSOR_LONG:
  231. data[0] = init_s5k4aa[i][2];
  232. data[1] = init_s5k4aa[i][3];
  233. err = m5602_write_sensor(sd,
  234. init_s5k4aa[i][1], data, 2);
  235. break;
  236. default:
  237. info("Invalid stream command, exiting init");
  238. return -EINVAL;
  239. }
  240. }
  241. if (dump_sensor)
  242. s5k4aa_dump_registers(sd);
  243. if (!err && dmi_check_system(s5k4aa_vflip_dmi_table)) {
  244. u8 data = 0x02;
  245. info("vertical flip quirk active");
  246. m5602_write_sensor(sd, S5K4AA_PAGE_MAP, &data, 1);
  247. m5602_read_sensor(sd, S5K4AA_READ_MODE, &data, 1);
  248. data |= S5K4AA_RM_V_FLIP;
  249. data &= ~S5K4AA_RM_H_FLIP;
  250. m5602_write_sensor(sd, S5K4AA_READ_MODE, &data, 1);
  251. /* Decrement COLSTART to preserve color order (BGGR) */
  252. m5602_read_sensor(sd, S5K4AA_COLSTART_LO, &data, 1);
  253. data--;
  254. m5602_write_sensor(sd, S5K4AA_COLSTART_LO, &data, 1);
  255. /* Increment ROWSTART to preserve color order (BGGR) */
  256. m5602_read_sensor(sd, S5K4AA_ROWSTART_LO, &data, 1);
  257. data++;
  258. m5602_write_sensor(sd, S5K4AA_ROWSTART_LO, &data, 1);
  259. }
  260. return (err < 0) ? err : 0;
  261. }
  262. int s5k4aa_power_down(struct sd *sd)
  263. {
  264. return 0;
  265. }
  266. int s5k4aa_get_exposure(struct gspca_dev *gspca_dev, __s32 *val)
  267. {
  268. struct sd *sd = (struct sd *) gspca_dev;
  269. u8 data = S5K4AA_PAGE_MAP_2;
  270. int err;
  271. err = m5602_write_sensor(sd, S5K4AA_PAGE_MAP, &data, 1);
  272. if (err < 0)
  273. return err;
  274. err = m5602_read_sensor(sd, S5K4AA_EXPOSURE_HI, &data, 1);
  275. if (err < 0)
  276. return err;
  277. *val = data << 8;
  278. err = m5602_read_sensor(sd, S5K4AA_EXPOSURE_LO, &data, 1);
  279. *val |= data;
  280. PDEBUG(D_V4L2, "Read exposure %d", *val);
  281. return err;
  282. }
  283. int s5k4aa_set_exposure(struct gspca_dev *gspca_dev, __s32 val)
  284. {
  285. struct sd *sd = (struct sd *) gspca_dev;
  286. u8 data = S5K4AA_PAGE_MAP_2;
  287. int err;
  288. PDEBUG(D_V4L2, "Set exposure to %d", val);
  289. err = m5602_write_sensor(sd, S5K4AA_PAGE_MAP, &data, 1);
  290. if (err < 0)
  291. return err;
  292. data = (val >> 8) & 0xff;
  293. err = m5602_write_sensor(sd, S5K4AA_EXPOSURE_HI, &data, 1);
  294. if (err < 0)
  295. return err;
  296. data = val & 0xff;
  297. err = m5602_write_sensor(sd, S5K4AA_EXPOSURE_LO, &data, 1);
  298. return err;
  299. }
  300. int s5k4aa_get_vflip(struct gspca_dev *gspca_dev, __s32 *val)
  301. {
  302. struct sd *sd = (struct sd *) gspca_dev;
  303. u8 data = S5K4AA_PAGE_MAP_2;
  304. int err;
  305. err = m5602_write_sensor(sd, S5K4AA_PAGE_MAP, &data, 1);
  306. if (err < 0)
  307. return err;
  308. err = m5602_read_sensor(sd, S5K4AA_PAGE_MAP, &data, 1);
  309. *val = (data & S5K4AA_RM_V_FLIP) >> 7;
  310. PDEBUG(D_V4L2, "Read vertical flip %d", *val);
  311. return err;
  312. }
  313. int s5k4aa_set_vflip(struct gspca_dev *gspca_dev, __s32 val)
  314. {
  315. struct sd *sd = (struct sd *) gspca_dev;
  316. u8 data = S5K4AA_PAGE_MAP_2;
  317. int err;
  318. PDEBUG(D_V4L2, "Set vertical flip to %d", val);
  319. err = m5602_write_sensor(sd, S5K4AA_PAGE_MAP, &data, 1);
  320. if (err < 0)
  321. return err;
  322. err = m5602_write_sensor(sd, S5K4AA_READ_MODE, &data, 1);
  323. if (err < 0)
  324. return err;
  325. data = ((data & ~S5K4AA_RM_V_FLIP)
  326. | ((val & 0x01) << 7));
  327. err = m5602_write_sensor(sd, S5K4AA_READ_MODE, &data, 1);
  328. if (err < 0)
  329. return err;
  330. if (val) {
  331. err = m5602_read_sensor(sd, S5K4AA_ROWSTART_LO, &data, 1);
  332. if (err < 0)
  333. return err;
  334. data++;
  335. err = m5602_write_sensor(sd, S5K4AA_ROWSTART_LO, &data, 1);
  336. } else {
  337. err = m5602_read_sensor(sd, S5K4AA_ROWSTART_LO, &data, 1);
  338. if (err < 0)
  339. return err;
  340. data--;
  341. err = m5602_write_sensor(sd, S5K4AA_ROWSTART_LO, &data, 1);
  342. }
  343. return err;
  344. }
  345. int s5k4aa_get_hflip(struct gspca_dev *gspca_dev, __s32 *val)
  346. {
  347. struct sd *sd = (struct sd *) gspca_dev;
  348. u8 data = S5K4AA_PAGE_MAP_2;
  349. int err;
  350. err = m5602_write_sensor(sd, S5K4AA_PAGE_MAP, &data, 1);
  351. if (err < 0)
  352. return err;
  353. err = m5602_read_sensor(sd, S5K4AA_PAGE_MAP, &data, 1);
  354. *val = (data & S5K4AA_RM_H_FLIP) >> 6;
  355. PDEBUG(D_V4L2, "Read horizontal flip %d", *val);
  356. return err;
  357. }
  358. int s5k4aa_set_hflip(struct gspca_dev *gspca_dev, __s32 val)
  359. {
  360. struct sd *sd = (struct sd *) gspca_dev;
  361. u8 data = S5K4AA_PAGE_MAP_2;
  362. int err;
  363. PDEBUG(D_V4L2, "Set horizontal flip to %d",
  364. val);
  365. err = m5602_write_sensor(sd, S5K4AA_PAGE_MAP, &data, 1);
  366. if (err < 0)
  367. return err;
  368. err = m5602_write_sensor(sd, S5K4AA_READ_MODE, &data, 1);
  369. if (err < 0)
  370. return err;
  371. data = ((data & ~S5K4AA_RM_H_FLIP) | ((val & 0x01) << 6));
  372. err = m5602_write_sensor(sd, S5K4AA_READ_MODE, &data, 1);
  373. if (err < 0)
  374. return err;
  375. if (val) {
  376. err = m5602_read_sensor(sd, S5K4AA_COLSTART_LO, &data, 1);
  377. if (err < 0)
  378. return err;
  379. data++;
  380. err = m5602_write_sensor(sd, S5K4AA_COLSTART_LO, &data, 1);
  381. if (err < 0)
  382. return err;
  383. } else {
  384. err = m5602_read_sensor(sd, S5K4AA_COLSTART_LO, &data, 1);
  385. if (err < 0)
  386. return err;
  387. data--;
  388. err = m5602_write_sensor(sd, S5K4AA_COLSTART_LO, &data, 1);
  389. }
  390. return err;
  391. }
  392. int s5k4aa_get_gain(struct gspca_dev *gspca_dev, __s32 *val)
  393. {
  394. struct sd *sd = (struct sd *) gspca_dev;
  395. u8 data = S5K4AA_PAGE_MAP_2;
  396. int err;
  397. err = m5602_write_sensor(sd, S5K4AA_PAGE_MAP, &data, 1);
  398. if (err < 0)
  399. return err;
  400. err = m5602_read_sensor(sd, S5K4AA_GAIN_2, &data, 1);
  401. *val = data;
  402. PDEBUG(D_V4L2, "Read gain %d", *val);
  403. return err;
  404. }
  405. int s5k4aa_set_gain(struct gspca_dev *gspca_dev, __s32 val)
  406. {
  407. struct sd *sd = (struct sd *) gspca_dev;
  408. u8 data = S5K4AA_PAGE_MAP_2;
  409. int err;
  410. PDEBUG(D_V4L2, "Set gain to %d", val);
  411. err = m5602_write_sensor(sd, S5K4AA_PAGE_MAP, &data, 1);
  412. if (err < 0)
  413. return err;
  414. data = val & 0xff;
  415. err = m5602_write_sensor(sd, S5K4AA_GAIN_2, &data, 1);
  416. return err;
  417. }
  418. static void s5k4aa_dump_registers(struct sd *sd)
  419. {
  420. int address;
  421. u8 page, old_page;
  422. m5602_read_sensor(sd, S5K4AA_PAGE_MAP, &old_page, 1);
  423. for (page = 0; page < 16; page++) {
  424. m5602_write_sensor(sd, S5K4AA_PAGE_MAP, &page, 1);
  425. info("Dumping the s5k4aa register state for page 0x%x", page);
  426. for (address = 0; address <= 0xff; address++) {
  427. u8 value = 0;
  428. m5602_read_sensor(sd, address, &value, 1);
  429. info("register 0x%x contains 0x%x",
  430. address, value);
  431. }
  432. }
  433. info("s5k4aa register state dump complete");
  434. for (page = 0; page < 16; page++) {
  435. m5602_write_sensor(sd, S5K4AA_PAGE_MAP, &page, 1);
  436. info("Probing for which registers that are "
  437. "read/write for page 0x%x", page);
  438. for (address = 0; address <= 0xff; address++) {
  439. u8 old_value, ctrl_value, test_value = 0xff;
  440. m5602_read_sensor(sd, address, &old_value, 1);
  441. m5602_write_sensor(sd, address, &test_value, 1);
  442. m5602_read_sensor(sd, address, &ctrl_value, 1);
  443. if (ctrl_value == test_value)
  444. info("register 0x%x is writeable", address);
  445. else
  446. info("register 0x%x is read only", address);
  447. /* Restore original value */
  448. m5602_write_sensor(sd, address, &old_value, 1);
  449. }
  450. }
  451. info("Read/write register probing complete");
  452. m5602_write_sensor(sd, S5K4AA_PAGE_MAP, &old_page, 1);
  453. }