Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

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