m5602_po1030.c 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624
  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. gspca_dbg(gspca_dev, D_PROBE, "Probing for a po1030 sensor\n");
  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. gspca_dbg(gspca_dev, D_CONF, "Set exposure to %d\n", val & 0xffff);
  340. i2c_data = ((val & 0xff00) >> 8);
  341. gspca_dbg(gspca_dev, D_CONF, "Set exposure to high byte to 0x%x\n",
  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. gspca_dbg(gspca_dev, D_CONF, "Set exposure to low byte to 0x%x\n",
  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. gspca_dbg(gspca_dev, D_CONF, "Set global gain to %d\n", 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. gspca_dbg(gspca_dev, D_CONF, "Set hvflip %d %d\n",
  371. sd->hflip->val, sd->vflip->val);
  372. err = m5602_read_sensor(sd, PO1030_CONTROL2, &i2c_data, 1);
  373. if (err < 0)
  374. return err;
  375. i2c_data = (0x3f & i2c_data) | (sd->hflip->val << 7) |
  376. (sd->vflip->val << 6);
  377. err = m5602_write_sensor(sd, PO1030_CONTROL2,
  378. &i2c_data, 1);
  379. return err;
  380. }
  381. static int po1030_set_red_balance(struct gspca_dev *gspca_dev, __s32 val)
  382. {
  383. struct sd *sd = (struct sd *) gspca_dev;
  384. u8 i2c_data;
  385. int err;
  386. i2c_data = val & 0xff;
  387. gspca_dbg(gspca_dev, D_CONF, "Set red gain to %d\n", i2c_data);
  388. err = m5602_write_sensor(sd, PO1030_RED_GAIN,
  389. &i2c_data, 1);
  390. return err;
  391. }
  392. static int po1030_set_blue_balance(struct gspca_dev *gspca_dev, __s32 val)
  393. {
  394. struct sd *sd = (struct sd *) gspca_dev;
  395. u8 i2c_data;
  396. int err;
  397. i2c_data = val & 0xff;
  398. gspca_dbg(gspca_dev, D_CONF, "Set blue gain to %d\n", i2c_data);
  399. err = m5602_write_sensor(sd, PO1030_BLUE_GAIN,
  400. &i2c_data, 1);
  401. return err;
  402. }
  403. static int po1030_set_green_balance(struct gspca_dev *gspca_dev, __s32 val)
  404. {
  405. struct sd *sd = (struct sd *) gspca_dev;
  406. u8 i2c_data;
  407. int err;
  408. i2c_data = val & 0xff;
  409. gspca_dbg(gspca_dev, D_CONF, "Set green gain to %d\n", i2c_data);
  410. err = m5602_write_sensor(sd, PO1030_GREEN_1_GAIN,
  411. &i2c_data, 1);
  412. if (err < 0)
  413. return err;
  414. return m5602_write_sensor(sd, PO1030_GREEN_2_GAIN,
  415. &i2c_data, 1);
  416. }
  417. static int po1030_set_auto_white_balance(struct gspca_dev *gspca_dev,
  418. __s32 val)
  419. {
  420. struct sd *sd = (struct sd *) gspca_dev;
  421. u8 i2c_data;
  422. int err;
  423. err = m5602_read_sensor(sd, PO1030_AUTOCTRL1, &i2c_data, 1);
  424. if (err < 0)
  425. return err;
  426. gspca_dbg(gspca_dev, D_CONF, "Set auto white balance to %d\n", val);
  427. i2c_data = (i2c_data & 0xfe) | (val & 0x01);
  428. err = m5602_write_sensor(sd, PO1030_AUTOCTRL1, &i2c_data, 1);
  429. return err;
  430. }
  431. static int po1030_set_auto_exposure(struct gspca_dev *gspca_dev,
  432. __s32 val)
  433. {
  434. struct sd *sd = (struct sd *) gspca_dev;
  435. u8 i2c_data;
  436. int err;
  437. err = m5602_read_sensor(sd, PO1030_AUTOCTRL1, &i2c_data, 1);
  438. if (err < 0)
  439. return err;
  440. gspca_dbg(gspca_dev, D_CONF, "Set auto exposure to %d\n", val);
  441. val = (val == V4L2_EXPOSURE_AUTO);
  442. i2c_data = (i2c_data & 0xfd) | ((val & 0x01) << 1);
  443. return m5602_write_sensor(sd, PO1030_AUTOCTRL1, &i2c_data, 1);
  444. }
  445. void po1030_disconnect(struct sd *sd)
  446. {
  447. sd->sensor = NULL;
  448. }
  449. static int po1030_s_ctrl(struct v4l2_ctrl *ctrl)
  450. {
  451. struct gspca_dev *gspca_dev =
  452. container_of(ctrl->handler, struct gspca_dev, ctrl_handler);
  453. struct sd *sd = (struct sd *) gspca_dev;
  454. int err;
  455. if (!gspca_dev->streaming)
  456. return 0;
  457. switch (ctrl->id) {
  458. case V4L2_CID_AUTO_WHITE_BALANCE:
  459. err = po1030_set_auto_white_balance(gspca_dev, ctrl->val);
  460. if (err || ctrl->val)
  461. return err;
  462. err = po1030_set_green_balance(gspca_dev, sd->green_bal->val);
  463. if (err)
  464. return err;
  465. err = po1030_set_red_balance(gspca_dev, sd->red_bal->val);
  466. if (err)
  467. return err;
  468. err = po1030_set_blue_balance(gspca_dev, sd->blue_bal->val);
  469. break;
  470. case V4L2_CID_EXPOSURE_AUTO:
  471. err = po1030_set_auto_exposure(gspca_dev, ctrl->val);
  472. if (err || ctrl->val == V4L2_EXPOSURE_AUTO)
  473. return err;
  474. err = po1030_set_exposure(gspca_dev, sd->expo->val);
  475. break;
  476. case V4L2_CID_GAIN:
  477. err = po1030_set_gain(gspca_dev, ctrl->val);
  478. break;
  479. case V4L2_CID_HFLIP:
  480. err = po1030_set_hvflip(gspca_dev);
  481. break;
  482. default:
  483. return -EINVAL;
  484. }
  485. return err;
  486. }
  487. static void po1030_dump_registers(struct sd *sd)
  488. {
  489. int address;
  490. u8 value = 0;
  491. pr_info("Dumping the po1030 sensor core registers\n");
  492. for (address = 0; address < 0x7f; address++) {
  493. m5602_read_sensor(sd, address, &value, 1);
  494. pr_info("register 0x%x contains 0x%x\n", address, value);
  495. }
  496. pr_info("po1030 register state dump complete\n");
  497. pr_info("Probing for which registers that are read/write\n");
  498. for (address = 0; address < 0xff; address++) {
  499. u8 old_value, ctrl_value;
  500. u8 test_value[2] = {0xff, 0xff};
  501. m5602_read_sensor(sd, address, &old_value, 1);
  502. m5602_write_sensor(sd, address, test_value, 1);
  503. m5602_read_sensor(sd, address, &ctrl_value, 1);
  504. if (ctrl_value == test_value[0])
  505. pr_info("register 0x%x is writeable\n", address);
  506. else
  507. pr_info("register 0x%x is read only\n", address);
  508. /* Restore original value */
  509. m5602_write_sensor(sd, address, &old_value, 1);
  510. }
  511. }