PageRenderTime 44ms CodeModel.GetById 20ms RepoModel.GetById 1ms app.codeStats 0ms

/drivers/media/video/indycam.c

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