indycam.c 9.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391
  1. /*
  2. * indycam.c - Silicon Graphics IndyCam digital camera driver
  3. *
  4. * Copyright (C) 2003 Ladislav Michl <ladis@linux-mips.org>
  5. * Copyright (C) 2004,2005 Mikael Nousiainen <tmnousia@cc.hut.fi>
  6. *
  7. * This program is free software; you can redistribute it and/or modify
  8. * it under the terms of the GNU General Public License version 2 as
  9. * published by the Free Software Foundation.
  10. */
  11. #include <linux/delay.h>
  12. #include <linux/errno.h>
  13. #include <linux/fs.h>
  14. #include <linux/init.h>
  15. #include <linux/kernel.h>
  16. #include <linux/major.h>
  17. #include <linux/module.h>
  18. #include <linux/mm.h>
  19. #include <linux/slab.h>
  20. /* IndyCam decodes stream of photons into digital image representation ;-) */
  21. #include <linux/videodev2.h>
  22. #include <linux/i2c.h>
  23. #include <media/v4l2-device.h>
  24. #include <media/v4l2-chip-ident.h>
  25. #include "indycam.h"
  26. #define INDYCAM_MODULE_VERSION "0.0.5"
  27. MODULE_DESCRIPTION("SGI IndyCam driver");
  28. MODULE_VERSION(INDYCAM_MODULE_VERSION);
  29. MODULE_AUTHOR("Mikael Nousiainen <tmnousia@cc.hut.fi>");
  30. MODULE_LICENSE("GPL");
  31. // #define INDYCAM_DEBUG
  32. #ifdef INDYCAM_DEBUG
  33. #define dprintk(x...) printk("IndyCam: " x);
  34. #define indycam_regdump(client) indycam_regdump_debug(client)
  35. #else
  36. #define dprintk(x...)
  37. #define indycam_regdump(client)
  38. #endif
  39. struct indycam {
  40. struct v4l2_subdev sd;
  41. u8 version;
  42. };
  43. static inline struct indycam *to_indycam(struct v4l2_subdev *sd)
  44. {
  45. return container_of(sd, struct indycam, sd);
  46. }
  47. static const u8 initseq[] = {
  48. INDYCAM_CONTROL_AGCENA, /* INDYCAM_CONTROL */
  49. INDYCAM_SHUTTER_60, /* INDYCAM_SHUTTER */
  50. INDYCAM_GAIN_DEFAULT, /* INDYCAM_GAIN */
  51. 0x00, /* INDYCAM_BRIGHTNESS (read-only) */
  52. INDYCAM_RED_BALANCE_DEFAULT, /* INDYCAM_RED_BALANCE */
  53. INDYCAM_BLUE_BALANCE_DEFAULT, /* INDYCAM_BLUE_BALANCE */
  54. INDYCAM_RED_SATURATION_DEFAULT, /* INDYCAM_RED_SATURATION */
  55. INDYCAM_BLUE_SATURATION_DEFAULT,/* INDYCAM_BLUE_SATURATION */
  56. };
  57. /* IndyCam register handling */
  58. static int indycam_read_reg(struct v4l2_subdev *sd, u8 reg, u8 *value)
  59. {
  60. struct i2c_client *client = v4l2_get_subdevdata(sd);
  61. int ret;
  62. if (reg == INDYCAM_REG_RESET) {
  63. dprintk("indycam_read_reg(): "
  64. "skipping write-only register %d\n", reg);
  65. *value = 0;
  66. return 0;
  67. }
  68. ret = i2c_smbus_read_byte_data(client, reg);
  69. if (ret < 0) {
  70. printk(KERN_ERR "IndyCam: indycam_read_reg(): read failed, "
  71. "register = 0x%02x\n", reg);
  72. return ret;
  73. }
  74. *value = (u8)ret;
  75. return 0;
  76. }
  77. static int indycam_write_reg(struct v4l2_subdev *sd, u8 reg, u8 value)
  78. {
  79. struct i2c_client *client = v4l2_get_subdevdata(sd);
  80. int err;
  81. if (reg == INDYCAM_REG_BRIGHTNESS || reg == INDYCAM_REG_VERSION) {
  82. dprintk("indycam_write_reg(): "
  83. "skipping read-only register %d\n", reg);
  84. return 0;
  85. }
  86. dprintk("Writing Reg %d = 0x%02x\n", reg, value);
  87. err = i2c_smbus_write_byte_data(client, reg, value);
  88. if (err) {
  89. printk(KERN_ERR "IndyCam: indycam_write_reg(): write failed, "
  90. "register = 0x%02x, value = 0x%02x\n", reg, value);
  91. }
  92. return err;
  93. }
  94. static int indycam_write_block(struct v4l2_subdev *sd, u8 reg,
  95. u8 length, u8 *data)
  96. {
  97. int i, err;
  98. for (i = 0; i < length; i++) {
  99. err = indycam_write_reg(sd, reg + i, data[i]);
  100. if (err)
  101. return err;
  102. }
  103. return 0;
  104. }
  105. /* Helper functions */
  106. #ifdef INDYCAM_DEBUG
  107. static void indycam_regdump_debug(struct v4l2_subdev *sd)
  108. {
  109. int i;
  110. u8 val;
  111. for (i = 0; i < 9; i++) {
  112. indycam_read_reg(sd, i, &val);
  113. dprintk("Reg %d = 0x%02x\n", i, val);
  114. }
  115. }
  116. #endif
  117. static int indycam_g_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl)
  118. {
  119. struct indycam *camera = to_indycam(sd);
  120. u8 reg;
  121. int ret = 0;
  122. switch (ctrl->id) {
  123. case V4L2_CID_AUTOGAIN:
  124. case V4L2_CID_AUTO_WHITE_BALANCE:
  125. ret = indycam_read_reg(sd, INDYCAM_REG_CONTROL, &reg);
  126. if (ret)
  127. return -EIO;
  128. if (ctrl->id == V4L2_CID_AUTOGAIN)
  129. ctrl->value = (reg & INDYCAM_CONTROL_AGCENA)
  130. ? 1 : 0;
  131. else
  132. ctrl->value = (reg & INDYCAM_CONTROL_AWBCTL)
  133. ? 1 : 0;
  134. break;
  135. case V4L2_CID_EXPOSURE:
  136. ret = indycam_read_reg(sd, INDYCAM_REG_SHUTTER, &reg);
  137. if (ret)
  138. return -EIO;
  139. ctrl->value = ((s32)reg == 0x00) ? 0xff : ((s32)reg - 1);
  140. break;
  141. case V4L2_CID_GAIN:
  142. ret = indycam_read_reg(sd, INDYCAM_REG_GAIN, &reg);
  143. if (ret)
  144. return -EIO;
  145. ctrl->value = (s32)reg;
  146. break;
  147. case V4L2_CID_RED_BALANCE:
  148. ret = indycam_read_reg(sd, INDYCAM_REG_RED_BALANCE, &reg);
  149. if (ret)
  150. return -EIO;
  151. ctrl->value = (s32)reg;
  152. break;
  153. case V4L2_CID_BLUE_BALANCE:
  154. ret = indycam_read_reg(sd, INDYCAM_REG_BLUE_BALANCE, &reg);
  155. if (ret)
  156. return -EIO;
  157. ctrl->value = (s32)reg;
  158. break;
  159. case INDYCAM_CONTROL_RED_SATURATION:
  160. ret = indycam_read_reg(sd,
  161. INDYCAM_REG_RED_SATURATION, &reg);
  162. if (ret)
  163. return -EIO;
  164. ctrl->value = (s32)reg;
  165. break;
  166. case INDYCAM_CONTROL_BLUE_SATURATION:
  167. ret = indycam_read_reg(sd,
  168. INDYCAM_REG_BLUE_SATURATION, &reg);
  169. if (ret)
  170. return -EIO;
  171. ctrl->value = (s32)reg;
  172. break;
  173. case V4L2_CID_GAMMA:
  174. if (camera->version == CAMERA_VERSION_MOOSE) {
  175. ret = indycam_read_reg(sd,
  176. INDYCAM_REG_GAMMA, &reg);
  177. if (ret)
  178. return -EIO;
  179. ctrl->value = (s32)reg;
  180. } else {
  181. ctrl->value = INDYCAM_GAMMA_DEFAULT;
  182. }
  183. break;
  184. default:
  185. ret = -EINVAL;
  186. }
  187. return ret;
  188. }
  189. static int indycam_s_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl)
  190. {
  191. struct indycam *camera = to_indycam(sd);
  192. u8 reg;
  193. int ret = 0;
  194. switch (ctrl->id) {
  195. case V4L2_CID_AUTOGAIN:
  196. case V4L2_CID_AUTO_WHITE_BALANCE:
  197. ret = indycam_read_reg(sd, INDYCAM_REG_CONTROL, &reg);
  198. if (ret)
  199. break;
  200. if (ctrl->id == V4L2_CID_AUTOGAIN) {
  201. if (ctrl->value)
  202. reg |= INDYCAM_CONTROL_AGCENA;
  203. else
  204. reg &= ~INDYCAM_CONTROL_AGCENA;
  205. } else {
  206. if (ctrl->value)
  207. reg |= INDYCAM_CONTROL_AWBCTL;
  208. else
  209. reg &= ~INDYCAM_CONTROL_AWBCTL;
  210. }
  211. ret = indycam_write_reg(sd, INDYCAM_REG_CONTROL, reg);
  212. break;
  213. case V4L2_CID_EXPOSURE:
  214. reg = (ctrl->value == 0xff) ? 0x00 : (ctrl->value + 1);
  215. ret = indycam_write_reg(sd, INDYCAM_REG_SHUTTER, reg);
  216. break;
  217. case V4L2_CID_GAIN:
  218. ret = indycam_write_reg(sd, INDYCAM_REG_GAIN, ctrl->value);
  219. break;
  220. case V4L2_CID_RED_BALANCE:
  221. ret = indycam_write_reg(sd, INDYCAM_REG_RED_BALANCE,
  222. ctrl->value);
  223. break;
  224. case V4L2_CID_BLUE_BALANCE:
  225. ret = indycam_write_reg(sd, INDYCAM_REG_BLUE_BALANCE,
  226. ctrl->value);
  227. break;
  228. case INDYCAM_CONTROL_RED_SATURATION:
  229. ret = indycam_write_reg(sd, INDYCAM_REG_RED_SATURATION,
  230. ctrl->value);
  231. break;
  232. case INDYCAM_CONTROL_BLUE_SATURATION:
  233. ret = indycam_write_reg(sd, INDYCAM_REG_BLUE_SATURATION,
  234. ctrl->value);
  235. break;
  236. case V4L2_CID_GAMMA:
  237. if (camera->version == CAMERA_VERSION_MOOSE) {
  238. ret = indycam_write_reg(sd, INDYCAM_REG_GAMMA,
  239. ctrl->value);
  240. }
  241. break;
  242. default:
  243. ret = -EINVAL;
  244. }
  245. return ret;
  246. }
  247. /* I2C-interface */
  248. static int indycam_g_chip_ident(struct v4l2_subdev *sd,
  249. struct v4l2_dbg_chip_ident *chip)
  250. {
  251. struct i2c_client *client = v4l2_get_subdevdata(sd);
  252. struct indycam *camera = to_indycam(sd);
  253. return v4l2_chip_ident_i2c_client(client, chip, V4L2_IDENT_INDYCAM,
  254. camera->version);
  255. }
  256. /* ----------------------------------------------------------------------- */
  257. static const struct v4l2_subdev_core_ops indycam_core_ops = {
  258. .g_chip_ident = indycam_g_chip_ident,
  259. .g_ctrl = indycam_g_ctrl,
  260. .s_ctrl = indycam_s_ctrl,
  261. };
  262. static const struct v4l2_subdev_ops indycam_ops = {
  263. .core = &indycam_core_ops,
  264. };
  265. static int indycam_probe(struct i2c_client *client,
  266. const struct i2c_device_id *id)
  267. {
  268. int err = 0;
  269. struct indycam *camera;
  270. struct v4l2_subdev *sd;
  271. v4l_info(client, "chip found @ 0x%x (%s)\n",
  272. client->addr << 1, client->adapter->name);
  273. camera = kzalloc(sizeof(struct indycam), GFP_KERNEL);
  274. if (!camera)
  275. return -ENOMEM;
  276. sd = &camera->sd;
  277. v4l2_i2c_subdev_init(sd, client, &indycam_ops);
  278. camera->version = i2c_smbus_read_byte_data(client,
  279. INDYCAM_REG_VERSION);
  280. if (camera->version != CAMERA_VERSION_INDY &&
  281. camera->version != CAMERA_VERSION_MOOSE) {
  282. kfree(camera);
  283. return -ENODEV;
  284. }
  285. printk(KERN_INFO "IndyCam v%d.%d detected\n",
  286. INDYCAM_VERSION_MAJOR(camera->version),
  287. INDYCAM_VERSION_MINOR(camera->version));
  288. indycam_regdump(sd);
  289. // initialize
  290. err = indycam_write_block(sd, 0, sizeof(initseq), (u8 *)&initseq);
  291. if (err) {
  292. printk(KERN_ERR "IndyCam initialization failed\n");
  293. kfree(camera);
  294. return -EIO;
  295. }
  296. indycam_regdump(sd);
  297. // white balance
  298. err = indycam_write_reg(sd, INDYCAM_REG_CONTROL,
  299. INDYCAM_CONTROL_AGCENA | INDYCAM_CONTROL_AWBCTL);
  300. if (err) {
  301. printk(KERN_ERR "IndyCam: White balancing camera failed\n");
  302. kfree(camera);
  303. return -EIO;
  304. }
  305. indycam_regdump(sd);
  306. printk(KERN_INFO "IndyCam initialized\n");
  307. return 0;
  308. }
  309. static int indycam_remove(struct i2c_client *client)
  310. {
  311. struct v4l2_subdev *sd = i2c_get_clientdata(client);
  312. v4l2_device_unregister_subdev(sd);
  313. kfree(to_indycam(sd));
  314. return 0;
  315. }
  316. static const struct i2c_device_id indycam_id[] = {
  317. { "indycam", 0 },
  318. { }
  319. };
  320. MODULE_DEVICE_TABLE(i2c, indycam_id);
  321. static struct i2c_driver indycam_driver = {
  322. .driver = {
  323. .owner = THIS_MODULE,
  324. .name = "indycam",
  325. },
  326. .probe = indycam_probe,
  327. .remove = indycam_remove,
  328. .id_table = indycam_id,
  329. };
  330. module_i2c_driver(indycam_driver);