2 * indycam.c - Silicon Graphics IndyCam digital camera driver
4 * Copyright (C) 2003 Ladislav Michl <ladis@linux-mips.org>
5 * Copyright (C) 2004,2005 Mikael Nousiainen <tmnousia@cc.hut.fi>
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.
12 #include <linux/delay.h>
13 #include <linux/errno.h>
15 #include <linux/init.h>
16 #include <linux/kernel.h>
17 #include <linux/major.h>
18 #include <linux/module.h>
20 #include <linux/slab.h>
22 #include <linux/videodev.h>
23 /* IndyCam decodes stream of photons into digital image representation ;-) */
24 #include <linux/video_decoder.h>
25 #include <linux/i2c.h>
29 #define INDYCAM_MODULE_VERSION "0.0.5"
31 MODULE_DESCRIPTION("SGI IndyCam driver");
32 MODULE_VERSION(INDYCAM_MODULE_VERSION
);
33 MODULE_AUTHOR("Mikael Nousiainen <tmnousia@cc.hut.fi>");
34 MODULE_LICENSE("GPL");
36 // #define INDYCAM_DEBUG
39 #define dprintk(x...) printk("IndyCam: " x);
40 #define indycam_regdump(client) indycam_regdump_debug(client)
43 #define indycam_regdump(client)
47 struct i2c_client
*client
;
51 static struct i2c_driver i2c_driver_indycam
;
53 static const u8 initseq
[] = {
54 INDYCAM_CONTROL_AGCENA
, /* INDYCAM_CONTROL */
55 INDYCAM_SHUTTER_60
, /* INDYCAM_SHUTTER */
56 INDYCAM_GAIN_DEFAULT
, /* INDYCAM_GAIN */
57 0x00, /* INDYCAM_BRIGHTNESS (read-only) */
58 INDYCAM_RED_BALANCE_DEFAULT
, /* INDYCAM_RED_BALANCE */
59 INDYCAM_BLUE_BALANCE_DEFAULT
, /* INDYCAM_BLUE_BALANCE */
60 INDYCAM_RED_SATURATION_DEFAULT
, /* INDYCAM_RED_SATURATION */
61 INDYCAM_BLUE_SATURATION_DEFAULT
,/* INDYCAM_BLUE_SATURATION */
64 /* IndyCam register handling */
66 static int indycam_read_reg(struct i2c_client
*client
, u8 reg
, u8
*value
)
70 if (reg
== INDYCAM_REG_RESET
) {
71 dprintk("indycam_read_reg(): "
72 "skipping write-only register %d\n", reg
);
77 ret
= i2c_smbus_read_byte_data(client
, reg
);
80 printk(KERN_ERR
"IndyCam: indycam_read_reg(): read failed, "
81 "register = 0x%02x\n", reg
);
90 static int indycam_write_reg(struct i2c_client
*client
, u8 reg
, u8 value
)
94 if ((reg
== INDYCAM_REG_BRIGHTNESS
)
95 || (reg
== INDYCAM_REG_VERSION
)) {
96 dprintk("indycam_write_reg(): "
97 "skipping read-only register %d\n", reg
);
101 dprintk("Writing Reg %d = 0x%02x\n", reg
, value
);
102 err
= i2c_smbus_write_byte_data(client
, reg
, value
);
105 printk(KERN_ERR
"IndyCam: indycam_write_reg(): write failed, "
106 "register = 0x%02x, value = 0x%02x\n", reg
, value
);
111 static int indycam_write_block(struct i2c_client
*client
, u8 reg
,
116 for (i
= 0; i
< length
; i
++) {
117 err
= indycam_write_reg(client
, reg
+ i
, data
[i
]);
125 /* Helper functions */
128 static void indycam_regdump_debug(struct i2c_client
*client
)
133 for (i
= 0; i
< 9; i
++) {
134 indycam_read_reg(client
, i
, &val
);
135 dprintk("Reg %d = 0x%02x\n", i
, val
);
140 static int indycam_get_control(struct i2c_client
*client
,
141 struct indycam_control
*ctrl
)
143 struct indycam
*camera
= i2c_get_clientdata(client
);
147 switch (ctrl
->type
) {
148 case INDYCAM_CONTROL_AGC
:
149 case INDYCAM_CONTROL_AWB
:
150 ret
= indycam_read_reg(client
, INDYCAM_REG_CONTROL
, ®
);
153 if (ctrl
->type
== INDYCAM_CONTROL_AGC
)
154 ctrl
->value
= (reg
& INDYCAM_CONTROL_AGCENA
)
157 ctrl
->value
= (reg
& INDYCAM_CONTROL_AWBCTL
)
160 case INDYCAM_CONTROL_SHUTTER
:
161 ret
= indycam_read_reg(client
, INDYCAM_REG_SHUTTER
, ®
);
164 ctrl
->value
= ((s32
)reg
== 0x00) ? 0xff : ((s32
)reg
- 1);
166 case INDYCAM_CONTROL_GAIN
:
167 ret
= indycam_read_reg(client
, INDYCAM_REG_GAIN
, ®
);
170 ctrl
->value
= (s32
)reg
;
172 case INDYCAM_CONTROL_RED_BALANCE
:
173 ret
= indycam_read_reg(client
, INDYCAM_REG_RED_BALANCE
, ®
);
176 ctrl
->value
= (s32
)reg
;
178 case INDYCAM_CONTROL_BLUE_BALANCE
:
179 ret
= indycam_read_reg(client
, INDYCAM_REG_BLUE_BALANCE
, ®
);
182 ctrl
->value
= (s32
)reg
;
184 case INDYCAM_CONTROL_RED_SATURATION
:
185 ret
= indycam_read_reg(client
,
186 INDYCAM_REG_RED_SATURATION
, ®
);
189 ctrl
->value
= (s32
)reg
;
191 case INDYCAM_CONTROL_BLUE_SATURATION
:
192 ret
= indycam_read_reg(client
,
193 INDYCAM_REG_BLUE_SATURATION
, ®
);
196 ctrl
->value
= (s32
)reg
;
198 case INDYCAM_CONTROL_GAMMA
:
199 if (camera
->version
== CAMERA_VERSION_MOOSE
) {
200 ret
= indycam_read_reg(client
,
201 INDYCAM_REG_GAMMA
, ®
);
204 ctrl
->value
= (s32
)reg
;
206 ctrl
->value
= INDYCAM_GAMMA_DEFAULT
;
216 static int indycam_set_control(struct i2c_client
*client
,
217 struct indycam_control
*ctrl
)
219 struct indycam
*camera
= i2c_get_clientdata(client
);
223 switch (ctrl
->type
) {
224 case INDYCAM_CONTROL_AGC
:
225 case INDYCAM_CONTROL_AWB
:
226 ret
= indycam_read_reg(client
, INDYCAM_REG_CONTROL
, ®
);
230 if (ctrl
->type
== INDYCAM_CONTROL_AGC
) {
232 reg
|= INDYCAM_CONTROL_AGCENA
;
234 reg
&= ~INDYCAM_CONTROL_AGCENA
;
237 reg
|= INDYCAM_CONTROL_AWBCTL
;
239 reg
&= ~INDYCAM_CONTROL_AWBCTL
;
242 ret
= indycam_write_reg(client
, INDYCAM_REG_CONTROL
, reg
);
244 case INDYCAM_CONTROL_SHUTTER
:
245 reg
= (ctrl
->value
== 0xff) ? 0x00 : (ctrl
->value
+ 1);
246 ret
= indycam_write_reg(client
, INDYCAM_REG_SHUTTER
, reg
);
248 case INDYCAM_CONTROL_GAIN
:
249 ret
= indycam_write_reg(client
, INDYCAM_REG_GAIN
, ctrl
->value
);
251 case INDYCAM_CONTROL_RED_BALANCE
:
252 ret
= indycam_write_reg(client
, INDYCAM_REG_RED_BALANCE
,
255 case INDYCAM_CONTROL_BLUE_BALANCE
:
256 ret
= indycam_write_reg(client
, INDYCAM_REG_BLUE_BALANCE
,
259 case INDYCAM_CONTROL_RED_SATURATION
:
260 ret
= indycam_write_reg(client
, INDYCAM_REG_RED_SATURATION
,
263 case INDYCAM_CONTROL_BLUE_SATURATION
:
264 ret
= indycam_write_reg(client
, INDYCAM_REG_BLUE_SATURATION
,
267 case INDYCAM_CONTROL_GAMMA
:
268 if (camera
->version
== CAMERA_VERSION_MOOSE
) {
269 ret
= indycam_write_reg(client
, INDYCAM_REG_GAMMA
,
282 static int indycam_attach(struct i2c_adapter
*adap
, int addr
, int kind
)
285 struct indycam
*camera
;
286 struct i2c_client
*client
;
288 printk(KERN_INFO
"SGI IndyCam driver version %s\n",
289 INDYCAM_MODULE_VERSION
);
291 client
= kzalloc(sizeof(struct i2c_client
), GFP_KERNEL
);
294 camera
= kzalloc(sizeof(struct indycam
), GFP_KERNEL
);
297 goto out_free_client
;
301 client
->adapter
= adap
;
302 client
->driver
= &i2c_driver_indycam
;
304 strcpy(client
->name
, "IndyCam client");
305 i2c_set_clientdata(client
, camera
);
307 camera
->client
= client
;
309 err
= i2c_attach_client(client
);
311 goto out_free_camera
;
313 camera
->version
= i2c_smbus_read_byte_data(client
,
314 INDYCAM_REG_VERSION
);
315 if (camera
->version
!= CAMERA_VERSION_INDY
&&
316 camera
->version
!= CAMERA_VERSION_MOOSE
) {
318 goto out_detach_client
;
320 printk(KERN_INFO
"IndyCam v%d.%d detected\n",
321 INDYCAM_VERSION_MAJOR(camera
->version
),
322 INDYCAM_VERSION_MINOR(camera
->version
));
324 indycam_regdump(client
);
327 err
= indycam_write_block(client
, 0, sizeof(initseq
), (u8
*)&initseq
);
329 printk(KERN_ERR
"IndyCam initialization failed\n");
331 goto out_detach_client
;
334 indycam_regdump(client
);
337 err
= indycam_write_reg(client
, INDYCAM_REG_CONTROL
,
338 INDYCAM_CONTROL_AGCENA
| INDYCAM_CONTROL_AWBCTL
);
340 printk(KERN_ERR
"IndyCam: White balancing camera failed\n");
342 goto out_detach_client
;
345 indycam_regdump(client
);
347 printk(KERN_INFO
"IndyCam initialized\n");
352 i2c_detach_client(client
);
360 static int indycam_probe(struct i2c_adapter
*adap
)
362 /* Indy specific crap */
363 if (adap
->id
== I2C_HW_SGI_VINO
)
364 return indycam_attach(adap
, INDYCAM_ADDR
, 0);
365 /* Feel free to add probe here :-) */
369 static int indycam_detach(struct i2c_client
*client
)
371 struct indycam
*camera
= i2c_get_clientdata(client
);
373 i2c_detach_client(client
);
379 static int indycam_command(struct i2c_client
*client
, unsigned int cmd
,
382 // struct indycam *camera = i2c_get_clientdata(client);
384 /* The old video_decoder interface just isn't enough,
385 * so we'll use some custom commands. */
387 case DECODER_GET_CAPABILITIES
: {
388 struct video_decoder_capability
*cap
= arg
;
390 cap
->flags
= VIDEO_DECODER_NTSC
;
395 case DECODER_GET_STATUS
: {
398 *iarg
= DECODER_STATUS_GOOD
| DECODER_STATUS_NTSC
|
399 DECODER_STATUS_COLOR
;
402 case DECODER_SET_NORM
: {
406 case VIDEO_MODE_NTSC
:
413 case DECODER_SET_INPUT
: {
420 case DECODER_SET_OUTPUT
: {
427 case DECODER_ENABLE_OUTPUT
: {
431 case DECODER_SET_PICTURE
: {
432 // struct video_picture *pic = arg;
433 /* TODO: convert values for indycam_set_controls() */
436 case DECODER_INDYCAM_GET_CONTROL
: {
437 return indycam_get_control(client
, arg
);
439 case DECODER_INDYCAM_SET_CONTROL
: {
440 return indycam_set_control(client
, arg
);
449 static struct i2c_driver i2c_driver_indycam
= {
453 .id
= I2C_DRIVERID_INDYCAM
,
454 .attach_adapter
= indycam_probe
,
455 .detach_client
= indycam_detach
,
456 .command
= indycam_command
,
459 static int __init
indycam_init(void)
461 return i2c_add_driver(&i2c_driver_indycam
);
464 static void __exit
indycam_exit(void)
466 i2c_del_driver(&i2c_driver_indycam
);
469 module_init(indycam_init
);
470 module_exit(indycam_exit
);