m5602_po1030.c 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622
  1. /*
  2. * Driver for the po1030 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_po1030.h"
  20. static int po1030_s_ctrl(struct v4l2_ctrl *ctrl);
  21. static void po1030_dump_registers(struct sd *sd);
  22. static const unsigned char preinit_po1030[][3] = {
  23. {BRIDGE, M5602_XB_MCU_CLK_DIV, 0x02},
  24. {BRIDGE, M5602_XB_MCU_CLK_CTRL, 0xb0},
  25. {BRIDGE, M5602_XB_SEN_CLK_DIV, 0x00},
  26. {BRIDGE, M5602_XB_SEN_CLK_CTRL, 0xb0},
  27. {BRIDGE, M5602_XB_ADC_CTRL, 0xc0},
  28. {BRIDGE, M5602_XB_SENSOR_CTRL, 0x00},
  29. {BRIDGE, M5602_XB_SENSOR_TYPE, 0x0c},
  30. {BRIDGE, M5602_XB_ADC_CTRL, 0xc0},
  31. {BRIDGE, M5602_XB_GPIO_DIR, 0x05},
  32. {BRIDGE, M5602_XB_GPIO_DAT, 0x04},
  33. {BRIDGE, M5602_XB_GPIO_EN_H, 0x06},
  34. {BRIDGE, M5602_XB_GPIO_DIR_H, 0x06},
  35. {BRIDGE, M5602_XB_GPIO_DAT_H, 0x02},
  36. {SENSOR, PO1030_AUTOCTRL2, PO1030_SENSOR_RESET | (1 << 2)},
  37. {BRIDGE, M5602_XB_SEN_CLK_DIV, 0x04},
  38. {BRIDGE, M5602_XB_SEN_CLK_CTRL, 0xb0},
  39. {BRIDGE, M5602_XB_SEN_CLK_DIV, 0x00},
  40. {BRIDGE, M5602_XB_SEN_CLK_CTRL, 0xb0},
  41. {BRIDGE, M5602_XB_SENSOR_TYPE, 0x0c},
  42. {BRIDGE, M5602_XB_GPIO_DIR, 0x05},
  43. {BRIDGE, M5602_XB_GPIO_DAT, 0x00}
  44. };
  45. static const unsigned char init_po1030[][3] = {
  46. {BRIDGE, M5602_XB_MCU_CLK_DIV, 0x02},
  47. {BRIDGE, M5602_XB_MCU_CLK_CTRL, 0xb0},
  48. {BRIDGE, M5602_XB_SEN_CLK_DIV, 0x00},
  49. {BRIDGE, M5602_XB_SEN_CLK_CTRL, 0xb0},
  50. {BRIDGE, M5602_XB_ADC_CTRL, 0xc0},
  51. {BRIDGE, M5602_XB_SENSOR_CTRL, 0x00},
  52. {BRIDGE, M5602_XB_SENSOR_TYPE, 0x0c},
  53. {SENSOR, PO1030_AUTOCTRL2, PO1030_SENSOR_RESET | (1 << 2)},
  54. {BRIDGE, M5602_XB_GPIO_DIR, 0x05},
  55. {BRIDGE, M5602_XB_GPIO_DAT, 0x04},
  56. {BRIDGE, M5602_XB_GPIO_EN_H, 0x06},
  57. {BRIDGE, M5602_XB_GPIO_EN_L, 0x00},
  58. {BRIDGE, M5602_XB_GPIO_DIR_H, 0x06},
  59. {BRIDGE, M5602_XB_GPIO_DAT_H, 0x02},
  60. {BRIDGE, M5602_XB_SEN_CLK_DIV, 0x04},
  61. {BRIDGE, M5602_XB_SEN_CLK_CTRL, 0xb0},
  62. {BRIDGE, M5602_XB_GPIO_DIR, 0x05},
  63. {BRIDGE, M5602_XB_GPIO_DAT, 0x00},
  64. {SENSOR, PO1030_AUTOCTRL2, 0x04},
  65. {SENSOR, PO1030_OUTFORMCTRL2, PO1030_RAW_RGB_BAYER},
  66. {SENSOR, PO1030_AUTOCTRL1, PO1030_WEIGHT_WIN_2X},
  67. {SENSOR, PO1030_CONTROL2, 0x03},
  68. {SENSOR, 0x21, 0x90},
  69. {SENSOR, PO1030_YTARGET, 0x60},
  70. {SENSOR, 0x59, 0x13},
  71. {SENSOR, PO1030_OUTFORMCTRL1, PO1030_HREF_ENABLE},
  72. {SENSOR, PO1030_EDGE_ENH_OFF, 0x00},
  73. {SENSOR, PO1030_EGA, 0x80},
  74. {SENSOR, 0x78, 0x14},
  75. {SENSOR, 0x6f, 0x01},
  76. {SENSOR, PO1030_GLOBALGAINMAX, 0x14},
  77. {SENSOR, PO1030_Cb_U_GAIN, 0x38},
  78. {SENSOR, PO1030_Cr_V_GAIN, 0x38},
  79. {SENSOR, PO1030_CONTROL1, PO1030_SHUTTER_MODE |
  80. PO1030_AUTO_SUBSAMPLING |
  81. PO1030_FRAME_EQUAL},
  82. {SENSOR, PO1030_GC0, 0x10},
  83. {SENSOR, PO1030_GC1, 0x20},
  84. {SENSOR, PO1030_GC2, 0x40},
  85. {SENSOR, PO1030_GC3, 0x60},
  86. {SENSOR, PO1030_GC4, 0x80},
  87. {SENSOR, PO1030_GC5, 0xa0},
  88. {SENSOR, PO1030_GC6, 0xc0},
  89. {SENSOR, PO1030_GC7, 0xff},
  90. /* Set the width to 751 */
  91. {SENSOR, PO1030_FRAMEWIDTH_H, 0x02},
  92. {SENSOR, PO1030_FRAMEWIDTH_L, 0xef},
  93. /* Set the height to 540 */
  94. {SENSOR, PO1030_FRAMEHEIGHT_H, 0x02},
  95. {SENSOR, PO1030_FRAMEHEIGHT_L, 0x1c},
  96. /* Set the x window to 1 */
  97. {SENSOR, PO1030_WINDOWX_H, 0x00},
  98. {SENSOR, PO1030_WINDOWX_L, 0x01},
  99. /* Set the y window to 1 */
  100. {SENSOR, PO1030_WINDOWY_H, 0x00},
  101. {SENSOR, PO1030_WINDOWY_L, 0x01},
  102. /* with a very low lighted environment increase the exposure but
  103. * decrease the FPS (Frame Per Second) */
  104. {BRIDGE, M5602_XB_SEN_CLK_DIV, 0x00},
  105. {BRIDGE, M5602_XB_SEN_CLK_CTRL, 0xb0},
  106. {BRIDGE, M5602_XB_GPIO_DIR, 0x05},
  107. {BRIDGE, M5602_XB_GPIO_DAT, 0x00},
  108. {BRIDGE, M5602_XB_GPIO_EN_H, 0x06},
  109. {BRIDGE, M5602_XB_GPIO_EN_L, 0x00},
  110. };
  111. static struct v4l2_pix_format po1030_modes[] = {
  112. {
  113. 640,
  114. 480,
  115. V4L2_PIX_FMT_SBGGR8,
  116. V4L2_FIELD_NONE,
  117. .sizeimage = 640 * 480,
  118. .bytesperline = 640,
  119. .colorspace = V4L2_COLORSPACE_SRGB,
  120. .priv = 2
  121. }
  122. };
  123. static const struct v4l2_ctrl_ops po1030_ctrl_ops = {
  124. .s_ctrl = po1030_s_ctrl,
  125. };
  126. static const struct v4l2_ctrl_config po1030_greenbal_cfg = {
  127. .ops = &po1030_ctrl_ops,
  128. .id = M5602_V4L2_CID_GREEN_BALANCE,
  129. .name = "Green Balance",
  130. .type = V4L2_CTRL_TYPE_INTEGER,
  131. .min = 0,
  132. .max = 255,
  133. .step = 1,
  134. .def = PO1030_GREEN_GAIN_DEFAULT,
  135. .flags = V4L2_CTRL_FLAG_SLIDER,
  136. };
  137. int po1030_probe(struct sd *sd)
  138. {
  139. u8 dev_id_h = 0, i;
  140. struct gspca_dev *gspca_dev = (struct gspca_dev *)sd;
  141. if (force_sensor) {
  142. if (force_sensor == PO1030_SENSOR) {
  143. pr_info("Forcing a %s sensor\n", po1030.name);
  144. goto sensor_found;
  145. }
  146. /* If we want to force another sensor, don't try to probe this
  147. * one */
  148. return -ENODEV;
  149. }
  150. PDEBUG(D_PROBE, "Probing for a po1030 sensor");
  151. /* Run the pre-init to actually probe the unit */
  152. for (i = 0; i < ARRAY_SIZE(preinit_po1030); i++) {
  153. u8 data = preinit_po1030[i][2];
  154. if (preinit_po1030[i][0] == SENSOR)
  155. m5602_write_sensor(sd,
  156. preinit_po1030[i][1], &data, 1);
  157. else
  158. m5602_write_bridge(sd, preinit_po1030[i][1], data);
  159. }
  160. if (m5602_read_sensor(sd, PO1030_DEVID_H, &dev_id_h, 1))
  161. return -ENODEV;
  162. if (dev_id_h == 0x30) {
  163. pr_info("Detected a po1030 sensor\n");
  164. goto sensor_found;
  165. }
  166. return -ENODEV;
  167. sensor_found:
  168. sd->gspca_dev.cam.cam_mode = po1030_modes;
  169. sd->gspca_dev.cam.nmodes = ARRAY_SIZE(po1030_modes);
  170. return 0;
  171. }
  172. int po1030_init(struct sd *sd)
  173. {
  174. int i, err = 0;
  175. /* Init the sensor */
  176. for (i = 0; i < ARRAY_SIZE(init_po1030) && !err; i++) {
  177. u8 data[2] = {0x00, 0x00};
  178. switch (init_po1030[i][0]) {
  179. case BRIDGE:
  180. err = m5602_write_bridge(sd,
  181. init_po1030[i][1],
  182. init_po1030[i][2]);
  183. break;
  184. case SENSOR:
  185. data[0] = init_po1030[i][2];
  186. err = m5602_write_sensor(sd,
  187. init_po1030[i][1], data, 1);
  188. break;
  189. default:
  190. pr_info("Invalid stream command, exiting init\n");
  191. return -EINVAL;
  192. }
  193. }
  194. if (err < 0)
  195. return err;
  196. if (dump_sensor)
  197. po1030_dump_registers(sd);
  198. return 0;
  199. }
  200. int po1030_init_controls(struct sd *sd)
  201. {
  202. struct v4l2_ctrl_handler *hdl = &sd->gspca_dev.ctrl_handler;
  203. sd->gspca_dev.vdev.ctrl_handler = hdl;
  204. v4l2_ctrl_handler_init(hdl, 9);
  205. sd->auto_white_bal = v4l2_ctrl_new_std(hdl, &po1030_ctrl_ops,
  206. V4L2_CID_AUTO_WHITE_BALANCE,
  207. 0, 1, 1, 0);
  208. sd->green_bal = v4l2_ctrl_new_custom(hdl, &po1030_greenbal_cfg, NULL);
  209. sd->red_bal = v4l2_ctrl_new_std(hdl, &po1030_ctrl_ops,
  210. V4L2_CID_RED_BALANCE, 0, 255, 1,
  211. PO1030_RED_GAIN_DEFAULT);
  212. sd->blue_bal = v4l2_ctrl_new_std(hdl, &po1030_ctrl_ops,
  213. V4L2_CID_BLUE_BALANCE, 0, 255, 1,
  214. PO1030_BLUE_GAIN_DEFAULT);
  215. sd->autoexpo = v4l2_ctrl_new_std_menu(hdl, &po1030_ctrl_ops,
  216. V4L2_CID_EXPOSURE_AUTO, 1, 0, V4L2_EXPOSURE_MANUAL);
  217. sd->expo = v4l2_ctrl_new_std(hdl, &po1030_ctrl_ops, V4L2_CID_EXPOSURE,
  218. 0, 0x2ff, 1, PO1030_EXPOSURE_DEFAULT);
  219. sd->gain = v4l2_ctrl_new_std(hdl, &po1030_ctrl_ops, V4L2_CID_GAIN, 0,
  220. 0x4f, 1, PO1030_GLOBAL_GAIN_DEFAULT);
  221. sd->hflip = v4l2_ctrl_new_std(hdl, &po1030_ctrl_ops, V4L2_CID_HFLIP,
  222. 0, 1, 1, 0);
  223. sd->vflip = v4l2_ctrl_new_std(hdl, &po1030_ctrl_ops, V4L2_CID_VFLIP,
  224. 0, 1, 1, 0);
  225. if (hdl->error) {
  226. pr_err("Could not initialize controls\n");
  227. return hdl->error;
  228. }
  229. v4l2_ctrl_auto_cluster(4, &sd->auto_white_bal, 0, false);
  230. v4l2_ctrl_auto_cluster(2, &sd->autoexpo, 0, false);
  231. v4l2_ctrl_cluster(2, &sd->hflip);
  232. return 0;
  233. }
  234. int po1030_start(struct sd *sd)
  235. {
  236. struct cam *cam = &sd->gspca_dev.cam;
  237. int i, err = 0;
  238. int width = cam->cam_mode[sd->gspca_dev.curr_mode].width;
  239. int height = cam->cam_mode[sd->gspca_dev.curr_mode].height;
  240. int ver_offs = cam->cam_mode[sd->gspca_dev.curr_mode].priv;
  241. u8 data;
  242. switch (width) {
  243. case 320:
  244. data = PO1030_SUBSAMPLING;
  245. err = m5602_write_sensor(sd, PO1030_CONTROL3, &data, 1);
  246. if (err < 0)
  247. return err;
  248. data = ((width + 3) >> 8) & 0xff;
  249. err = m5602_write_sensor(sd, PO1030_WINDOWWIDTH_H, &data, 1);
  250. if (err < 0)
  251. return err;
  252. data = (width + 3) & 0xff;
  253. err = m5602_write_sensor(sd, PO1030_WINDOWWIDTH_L, &data, 1);
  254. if (err < 0)
  255. return err;
  256. data = ((height + 1) >> 8) & 0xff;
  257. err = m5602_write_sensor(sd, PO1030_WINDOWHEIGHT_H, &data, 1);
  258. if (err < 0)
  259. return err;
  260. data = (height + 1) & 0xff;
  261. err = m5602_write_sensor(sd, PO1030_WINDOWHEIGHT_L, &data, 1);
  262. height += 6;
  263. width -= 1;
  264. break;
  265. case 640:
  266. data = 0;
  267. err = m5602_write_sensor(sd, PO1030_CONTROL3, &data, 1);
  268. if (err < 0)
  269. return err;
  270. data = ((width + 7) >> 8) & 0xff;
  271. err = m5602_write_sensor(sd, PO1030_WINDOWWIDTH_H, &data, 1);
  272. if (err < 0)
  273. return err;
  274. data = (width + 7) & 0xff;
  275. err = m5602_write_sensor(sd, PO1030_WINDOWWIDTH_L, &data, 1);
  276. if (err < 0)
  277. return err;
  278. data = ((height + 3) >> 8) & 0xff;
  279. err = m5602_write_sensor(sd, PO1030_WINDOWHEIGHT_H, &data, 1);
  280. if (err < 0)
  281. return err;
  282. data = (height + 3) & 0xff;
  283. err = m5602_write_sensor(sd, PO1030_WINDOWHEIGHT_L, &data, 1);
  284. height += 12;
  285. width -= 2;
  286. break;
  287. }
  288. err = m5602_write_bridge(sd, M5602_XB_SENSOR_TYPE, 0x0c);
  289. if (err < 0)
  290. return err;
  291. err = m5602_write_bridge(sd, M5602_XB_LINE_OF_FRAME_H, 0x81);
  292. if (err < 0)
  293. return err;
  294. err = m5602_write_bridge(sd, M5602_XB_PIX_OF_LINE_H, 0x82);
  295. if (err < 0)
  296. return err;
  297. err = m5602_write_bridge(sd, M5602_XB_SIG_INI, 0x01);
  298. if (err < 0)
  299. return err;
  300. err = m5602_write_bridge(sd, M5602_XB_VSYNC_PARA,
  301. ((ver_offs >> 8) & 0xff));
  302. if (err < 0)
  303. return err;
  304. err = m5602_write_bridge(sd, M5602_XB_VSYNC_PARA, (ver_offs & 0xff));
  305. if (err < 0)
  306. return err;
  307. for (i = 0; i < 2 && !err; i++)
  308. err = m5602_write_bridge(sd, M5602_XB_VSYNC_PARA, 0);
  309. if (err < 0)
  310. return err;
  311. err = m5602_write_bridge(sd, M5602_XB_VSYNC_PARA, (height >> 8) & 0xff);
  312. if (err < 0)
  313. return err;
  314. err = m5602_write_bridge(sd, M5602_XB_VSYNC_PARA, (height & 0xff));
  315. if (err < 0)
  316. return err;
  317. for (i = 0; i < 2 && !err; i++)
  318. err = m5602_write_bridge(sd, M5602_XB_VSYNC_PARA, 0);
  319. for (i = 0; i < 2 && !err; i++)
  320. err = m5602_write_bridge(sd, M5602_XB_SIG_INI, 0);
  321. for (i = 0; i < 2 && !err; i++)
  322. err = m5602_write_bridge(sd, M5602_XB_HSYNC_PARA, 0);
  323. if (err < 0)
  324. return err;
  325. err = m5602_write_bridge(sd, M5602_XB_HSYNC_PARA, (width >> 8) & 0xff);
  326. if (err < 0)
  327. return err;
  328. err = m5602_write_bridge(sd, M5602_XB_HSYNC_PARA, (width & 0xff));
  329. if (err < 0)
  330. return err;
  331. err = m5602_write_bridge(sd, M5602_XB_SIG_INI, 0);
  332. return err;
  333. }
  334. static int po1030_set_exposure(struct gspca_dev *gspca_dev, __s32 val)
  335. {
  336. struct sd *sd = (struct sd *) gspca_dev;
  337. u8 i2c_data;
  338. int err;
  339. PDEBUG(D_CONF, "Set exposure to %d", val & 0xffff);
  340. i2c_data = ((val & 0xff00) >> 8);
  341. PDEBUG(D_CONF, "Set exposure to high byte to 0x%x",
  342. i2c_data);
  343. err = m5602_write_sensor(sd, PO1030_INTEGLINES_H,
  344. &i2c_data, 1);
  345. if (err < 0)
  346. return err;
  347. i2c_data = (val & 0xff);
  348. PDEBUG(D_CONF, "Set exposure to low byte to 0x%x",
  349. i2c_data);
  350. err = m5602_write_sensor(sd, PO1030_INTEGLINES_M,
  351. &i2c_data, 1);
  352. return err;
  353. }
  354. static int po1030_set_gain(struct gspca_dev *gspca_dev, __s32 val)
  355. {
  356. struct sd *sd = (struct sd *) gspca_dev;
  357. u8 i2c_data;
  358. int err;
  359. i2c_data = val & 0xff;
  360. PDEBUG(D_CONF, "Set global gain to %d", i2c_data);
  361. err = m5602_write_sensor(sd, PO1030_GLOBALGAIN,
  362. &i2c_data, 1);
  363. return err;
  364. }
  365. static int po1030_set_hvflip(struct gspca_dev *gspca_dev)
  366. {
  367. struct sd *sd = (struct sd *) gspca_dev;
  368. u8 i2c_data;
  369. int err;
  370. PDEBUG(D_CONF, "Set hvflip %d %d", sd->hflip->val, sd->vflip->val);
  371. err = m5602_read_sensor(sd, PO1030_CONTROL2, &i2c_data, 1);
  372. if (err < 0)
  373. return err;
  374. i2c_data = (0x3f & i2c_data) | (sd->hflip->val << 7) |
  375. (sd->vflip->val << 6);
  376. err = m5602_write_sensor(sd, PO1030_CONTROL2,
  377. &i2c_data, 1);
  378. return err;
  379. }
  380. static int po1030_set_red_balance(struct gspca_dev *gspca_dev, __s32 val)
  381. {
  382. struct sd *sd = (struct sd *) gspca_dev;
  383. u8 i2c_data;
  384. int err;
  385. i2c_data = val & 0xff;
  386. PDEBUG(D_CONF, "Set red gain to %d", i2c_data);
  387. err = m5602_write_sensor(sd, PO1030_RED_GAIN,
  388. &i2c_data, 1);
  389. return err;
  390. }
  391. static int po1030_set_blue_balance(struct gspca_dev *gspca_dev, __s32 val)
  392. {
  393. struct sd *sd = (struct sd *) gspca_dev;
  394. u8 i2c_data;
  395. int err;
  396. i2c_data = val & 0xff;
  397. PDEBUG(D_CONF, "Set blue gain to %d", i2c_data);
  398. err = m5602_write_sensor(sd, PO1030_BLUE_GAIN,
  399. &i2c_data, 1);
  400. return err;
  401. }
  402. static int po1030_set_green_balance(struct gspca_dev *gspca_dev, __s32 val)
  403. {
  404. struct sd *sd = (struct sd *) gspca_dev;
  405. u8 i2c_data;
  406. int err;
  407. i2c_data = val & 0xff;
  408. PDEBUG(D_CONF, "Set green gain to %d", i2c_data);
  409. err = m5602_write_sensor(sd, PO1030_GREEN_1_GAIN,
  410. &i2c_data, 1);
  411. if (err < 0)
  412. return err;
  413. return m5602_write_sensor(sd, PO1030_GREEN_2_GAIN,
  414. &i2c_data, 1);
  415. }
  416. static int po1030_set_auto_white_balance(struct gspca_dev *gspca_dev,
  417. __s32 val)
  418. {
  419. struct sd *sd = (struct sd *) gspca_dev;
  420. u8 i2c_data;
  421. int err;
  422. err = m5602_read_sensor(sd, PO1030_AUTOCTRL1, &i2c_data, 1);
  423. if (err < 0)
  424. return err;
  425. PDEBUG(D_CONF, "Set auto white balance to %d", val);
  426. i2c_data = (i2c_data & 0xfe) | (val & 0x01);
  427. err = m5602_write_sensor(sd, PO1030_AUTOCTRL1, &i2c_data, 1);
  428. return err;
  429. }
  430. static int po1030_set_auto_exposure(struct gspca_dev *gspca_dev,
  431. __s32 val)
  432. {
  433. struct sd *sd = (struct sd *) gspca_dev;
  434. u8 i2c_data;
  435. int err;
  436. err = m5602_read_sensor(sd, PO1030_AUTOCTRL1, &i2c_data, 1);
  437. if (err < 0)
  438. return err;
  439. PDEBUG(D_CONF, "Set auto exposure to %d", val);
  440. val = (val == V4L2_EXPOSURE_AUTO);
  441. i2c_data = (i2c_data & 0xfd) | ((val & 0x01) << 1);
  442. return m5602_write_sensor(sd, PO1030_AUTOCTRL1, &i2c_data, 1);
  443. }
  444. void po1030_disconnect(struct sd *sd)
  445. {
  446. sd->sensor = NULL;
  447. }
  448. static int po1030_s_ctrl(struct v4l2_ctrl *ctrl)
  449. {
  450. struct gspca_dev *gspca_dev =
  451. container_of(ctrl->handler, struct gspca_dev, ctrl_handler);
  452. struct sd *sd = (struct sd *) gspca_dev;
  453. int err;
  454. if (!gspca_dev->streaming)
  455. return 0;
  456. switch (ctrl->id) {
  457. case V4L2_CID_AUTO_WHITE_BALANCE:
  458. err = po1030_set_auto_white_balance(gspca_dev, ctrl->val);
  459. if (err || ctrl->val)
  460. return err;
  461. err = po1030_set_green_balance(gspca_dev, sd->green_bal->val);
  462. if (err)
  463. return err;
  464. err = po1030_set_red_balance(gspca_dev, sd->red_bal->val);
  465. if (err)
  466. return err;
  467. err = po1030_set_blue_balance(gspca_dev, sd->blue_bal->val);
  468. break;
  469. case V4L2_CID_EXPOSURE_AUTO:
  470. err = po1030_set_auto_exposure(gspca_dev, ctrl->val);
  471. if (err || ctrl->val == V4L2_EXPOSURE_AUTO)
  472. return err;
  473. err = po1030_set_exposure(gspca_dev, sd->expo->val);
  474. break;
  475. case V4L2_CID_GAIN:
  476. err = po1030_set_gain(gspca_dev, ctrl->val);
  477. break;
  478. case V4L2_CID_HFLIP:
  479. err = po1030_set_hvflip(gspca_dev);
  480. break;
  481. default:
  482. return -EINVAL;
  483. }
  484. return err;
  485. }
  486. static void po1030_dump_registers(struct sd *sd)
  487. {
  488. int address;
  489. u8 value = 0;
  490. pr_info("Dumping the po1030 sensor core registers\n");
  491. for (address = 0; address < 0x7f; address++) {
  492. m5602_read_sensor(sd, address, &value, 1);
  493. pr_info("register 0x%x contains 0x%x\n", address, value);
  494. }
  495. pr_info("po1030 register state dump complete\n");
  496. pr_info("Probing for which registers that are read/write\n");
  497. for (address = 0; address < 0xff; address++) {
  498. u8 old_value, ctrl_value;
  499. u8 test_value[2] = {0xff, 0xff};
  500. m5602_read_sensor(sd, address, &old_value, 1);
  501. m5602_write_sensor(sd, address, test_value, 1);
  502. m5602_read_sensor(sd, address, &ctrl_value, 1);
  503. if (ctrl_value == test_value[0])
  504. pr_info("register 0x%x is writeable\n", address);
  505. else
  506. pr_info("register 0x%x is read only\n", address);
  507. /* Restore original value */
  508. m5602_write_sensor(sd, address, &old_value, 1);
  509. }
  510. }