diff options
Diffstat (limited to 'drivers/media/video/indycam.c')
-rw-r--r-- | drivers/media/video/indycam.c | 262 |
1 files changed, 163 insertions, 99 deletions
diff --git a/drivers/media/video/indycam.c b/drivers/media/video/indycam.c index 26dd06ec89a2..deeef125eb92 100644 --- a/drivers/media/video/indycam.c +++ b/drivers/media/video/indycam.c | |||
@@ -27,15 +27,15 @@ | |||
27 | 27 | ||
28 | #include "indycam.h" | 28 | #include "indycam.h" |
29 | 29 | ||
30 | //#define INDYCAM_DEBUG | 30 | #define INDYCAM_MODULE_VERSION "0.0.5" |
31 | |||
32 | #define INDYCAM_MODULE_VERSION "0.0.3" | ||
33 | 31 | ||
34 | MODULE_DESCRIPTION("SGI IndyCam driver"); | 32 | MODULE_DESCRIPTION("SGI IndyCam driver"); |
35 | MODULE_VERSION(INDYCAM_MODULE_VERSION); | 33 | MODULE_VERSION(INDYCAM_MODULE_VERSION); |
36 | MODULE_AUTHOR("Mikael Nousiainen <tmnousia@cc.hut.fi>"); | 34 | MODULE_AUTHOR("Mikael Nousiainen <tmnousia@cc.hut.fi>"); |
37 | MODULE_LICENSE("GPL"); | 35 | MODULE_LICENSE("GPL"); |
38 | 36 | ||
37 | // #define INDYCAM_DEBUG | ||
38 | |||
39 | #ifdef INDYCAM_DEBUG | 39 | #ifdef INDYCAM_DEBUG |
40 | #define dprintk(x...) printk("IndyCam: " x); | 40 | #define dprintk(x...) printk("IndyCam: " x); |
41 | #define indycam_regdump(client) indycam_regdump_debug(client) | 41 | #define indycam_regdump(client) indycam_regdump_debug(client) |
@@ -46,14 +46,14 @@ MODULE_LICENSE("GPL"); | |||
46 | 46 | ||
47 | struct indycam { | 47 | struct indycam { |
48 | struct i2c_client *client; | 48 | struct i2c_client *client; |
49 | int version; | 49 | u8 version; |
50 | }; | 50 | }; |
51 | 51 | ||
52 | static struct i2c_driver i2c_driver_indycam; | 52 | static struct i2c_driver i2c_driver_indycam; |
53 | 53 | ||
54 | static const unsigned char initseq[] = { | 54 | static const u8 initseq[] = { |
55 | INDYCAM_CONTROL_AGCENA, /* INDYCAM_CONTROL */ | 55 | INDYCAM_CONTROL_AGCENA, /* INDYCAM_CONTROL */ |
56 | INDYCAM_SHUTTER_DEFAULT, /* INDYCAM_SHUTTER */ | 56 | INDYCAM_SHUTTER_60, /* INDYCAM_SHUTTER */ |
57 | INDYCAM_GAIN_DEFAULT, /* INDYCAM_GAIN */ | 57 | INDYCAM_GAIN_DEFAULT, /* INDYCAM_GAIN */ |
58 | 0x00, /* INDYCAM_BRIGHTNESS (read-only) */ | 58 | 0x00, /* INDYCAM_BRIGHTNESS (read-only) */ |
59 | INDYCAM_RED_BALANCE_DEFAULT, /* INDYCAM_RED_BALANCE */ | 59 | INDYCAM_RED_BALANCE_DEFAULT, /* INDYCAM_RED_BALANCE */ |
@@ -64,12 +64,11 @@ static const unsigned char initseq[] = { | |||
64 | 64 | ||
65 | /* IndyCam register handling */ | 65 | /* IndyCam register handling */ |
66 | 66 | ||
67 | static int indycam_read_reg(struct i2c_client *client, unsigned char reg, | 67 | static int indycam_read_reg(struct i2c_client *client, u8 reg, u8 *value) |
68 | unsigned char *value) | ||
69 | { | 68 | { |
70 | int ret; | 69 | int ret; |
71 | 70 | ||
72 | if (reg == INDYCAM_RESET) { | 71 | if (reg == INDYCAM_REG_RESET) { |
73 | dprintk("indycam_read_reg(): " | 72 | dprintk("indycam_read_reg(): " |
74 | "skipping write-only register %d\n", reg); | 73 | "skipping write-only register %d\n", reg); |
75 | *value = 0; | 74 | *value = 0; |
@@ -77,24 +76,24 @@ static int indycam_read_reg(struct i2c_client *client, unsigned char reg, | |||
77 | } | 76 | } |
78 | 77 | ||
79 | ret = i2c_smbus_read_byte_data(client, reg); | 78 | ret = i2c_smbus_read_byte_data(client, reg); |
79 | |||
80 | if (ret < 0) { | 80 | if (ret < 0) { |
81 | printk(KERN_ERR "IndyCam: indycam_read_reg(): read failed, " | 81 | printk(KERN_ERR "IndyCam: indycam_read_reg(): read failed, " |
82 | "register = 0x%02x\n", reg); | 82 | "register = 0x%02x\n", reg); |
83 | return ret; | 83 | return ret; |
84 | } | 84 | } |
85 | 85 | ||
86 | *value = (unsigned char)ret; | 86 | *value = (u8)ret; |
87 | 87 | ||
88 | return 0; | 88 | return 0; |
89 | } | 89 | } |
90 | 90 | ||
91 | static int indycam_write_reg(struct i2c_client *client, unsigned char reg, | 91 | static int indycam_write_reg(struct i2c_client *client, u8 reg, u8 value) |
92 | unsigned char value) | ||
93 | { | 92 | { |
94 | int err; | 93 | int err; |
95 | 94 | ||
96 | if ((reg == INDYCAM_BRIGHTNESS) | 95 | if ((reg == INDYCAM_REG_BRIGHTNESS) |
97 | || (reg == INDYCAM_VERSION)) { | 96 | || (reg == INDYCAM_REG_VERSION)) { |
98 | dprintk("indycam_write_reg(): " | 97 | dprintk("indycam_write_reg(): " |
99 | "skipping read-only register %d\n", reg); | 98 | "skipping read-only register %d\n", reg); |
100 | return 0; | 99 | return 0; |
@@ -102,6 +101,7 @@ static int indycam_write_reg(struct i2c_client *client, unsigned char reg, | |||
102 | 101 | ||
103 | dprintk("Writing Reg %d = 0x%02x\n", reg, value); | 102 | dprintk("Writing Reg %d = 0x%02x\n", reg, value); |
104 | err = i2c_smbus_write_byte_data(client, reg, value); | 103 | err = i2c_smbus_write_byte_data(client, reg, value); |
104 | |||
105 | if (err) { | 105 | if (err) { |
106 | printk(KERN_ERR "IndyCam: indycam_write_reg(): write failed, " | 106 | printk(KERN_ERR "IndyCam: indycam_write_reg(): write failed, " |
107 | "register = 0x%02x, value = 0x%02x\n", reg, value); | 107 | "register = 0x%02x, value = 0x%02x\n", reg, value); |
@@ -109,13 +109,12 @@ static int indycam_write_reg(struct i2c_client *client, unsigned char reg, | |||
109 | return err; | 109 | return err; |
110 | } | 110 | } |
111 | 111 | ||
112 | static int indycam_write_block(struct i2c_client *client, unsigned char reg, | 112 | static int indycam_write_block(struct i2c_client *client, u8 reg, |
113 | unsigned char length, unsigned char *data) | 113 | u8 length, u8 *data) |
114 | { | 114 | { |
115 | unsigned char i; | 115 | int i, err; |
116 | int err; | ||
117 | 116 | ||
118 | for (i = reg; i < length; i++) { | 117 | for (i = 0; i < length; i++) { |
119 | err = indycam_write_reg(client, reg + i, data[i]); | 118 | err = indycam_write_reg(client, reg + i, data[i]); |
120 | if (err) | 119 | if (err) |
121 | return err; | 120 | return err; |
@@ -130,7 +129,7 @@ static int indycam_write_block(struct i2c_client *client, unsigned char reg, | |||
130 | static void indycam_regdump_debug(struct i2c_client *client) | 129 | static void indycam_regdump_debug(struct i2c_client *client) |
131 | { | 130 | { |
132 | int i; | 131 | int i; |
133 | unsigned char val; | 132 | u8 val; |
134 | 133 | ||
135 | for (i = 0; i < 9; i++) { | 134 | for (i = 0; i < 9; i++) { |
136 | indycam_read_reg(client, i, &val); | 135 | indycam_read_reg(client, i, &val); |
@@ -139,76 +138,144 @@ static void indycam_regdump_debug(struct i2c_client *client) | |||
139 | } | 138 | } |
140 | #endif | 139 | #endif |
141 | 140 | ||
142 | static int indycam_get_controls(struct i2c_client *client, | 141 | static int indycam_get_control(struct i2c_client *client, |
143 | struct indycam_control *ctrl) | 142 | struct indycam_control *ctrl) |
144 | { | 143 | { |
145 | unsigned char ctrl_reg; | 144 | struct indycam *camera = i2c_get_clientdata(client); |
146 | 145 | u8 reg; | |
147 | indycam_read_reg(client, INDYCAM_CONTROL, &ctrl_reg); | 146 | int ret = 0; |
148 | ctrl->agc = (ctrl_reg & INDYCAM_CONTROL_AGCENA) | 147 | |
149 | ? INDYCAM_VALUE_ENABLED | 148 | switch (ctrl->type) { |
150 | : INDYCAM_VALUE_DISABLED; | 149 | case INDYCAM_CONTROL_AGC: |
151 | ctrl->awb = (ctrl_reg & INDYCAM_CONTROL_AWBCTL) | 150 | case INDYCAM_CONTROL_AWB: |
152 | ? INDYCAM_VALUE_ENABLED | 151 | ret = indycam_read_reg(client, INDYCAM_REG_CONTROL, ®); |
153 | : INDYCAM_VALUE_DISABLED; | 152 | if (ret) |
154 | indycam_read_reg(client, INDYCAM_SHUTTER, | 153 | return -EIO; |
155 | (unsigned char *)&ctrl->shutter); | 154 | if (ctrl->type == INDYCAM_CONTROL_AGC) |
156 | indycam_read_reg(client, INDYCAM_GAIN, | 155 | ctrl->value = (reg & INDYCAM_CONTROL_AGCENA) |
157 | (unsigned char *)&ctrl->gain); | 156 | ? 1 : 0; |
158 | indycam_read_reg(client, INDYCAM_RED_BALANCE, | 157 | else |
159 | (unsigned char *)&ctrl->red_balance); | 158 | ctrl->value = (reg & INDYCAM_CONTROL_AWBCTL) |
160 | indycam_read_reg(client, INDYCAM_BLUE_BALANCE, | 159 | ? 1 : 0; |
161 | (unsigned char *)&ctrl->blue_balance); | 160 | break; |
162 | indycam_read_reg(client, INDYCAM_RED_SATURATION, | 161 | case INDYCAM_CONTROL_SHUTTER: |
163 | (unsigned char *)&ctrl->red_saturation); | 162 | ret = indycam_read_reg(client, INDYCAM_REG_SHUTTER, ®); |
164 | indycam_read_reg(client, INDYCAM_BLUE_SATURATION, | 163 | if (ret) |
165 | (unsigned char *)&ctrl->blue_saturation); | 164 | return -EIO; |
166 | indycam_read_reg(client, INDYCAM_GAMMA, | 165 | ctrl->value = ((s32)reg == 0x00) ? 0xff : ((s32)reg - 1); |
167 | (unsigned char *)&ctrl->gamma); | 166 | break; |
167 | case INDYCAM_CONTROL_GAIN: | ||
168 | ret = indycam_read_reg(client, INDYCAM_REG_GAIN, ®); | ||
169 | if (ret) | ||
170 | return -EIO; | ||
171 | ctrl->value = (s32)reg; | ||
172 | break; | ||
173 | case INDYCAM_CONTROL_RED_BALANCE: | ||
174 | ret = indycam_read_reg(client, INDYCAM_REG_RED_BALANCE, ®); | ||
175 | if (ret) | ||
176 | return -EIO; | ||
177 | ctrl->value = (s32)reg; | ||
178 | break; | ||
179 | case INDYCAM_CONTROL_BLUE_BALANCE: | ||
180 | ret = indycam_read_reg(client, INDYCAM_REG_BLUE_BALANCE, ®); | ||
181 | if (ret) | ||
182 | return -EIO; | ||
183 | ctrl->value = (s32)reg; | ||
184 | break; | ||
185 | case INDYCAM_CONTROL_RED_SATURATION: | ||
186 | ret = indycam_read_reg(client, | ||
187 | INDYCAM_REG_RED_SATURATION, ®); | ||
188 | if (ret) | ||
189 | return -EIO; | ||
190 | ctrl->value = (s32)reg; | ||
191 | break; | ||
192 | case INDYCAM_CONTROL_BLUE_SATURATION: | ||
193 | ret = indycam_read_reg(client, | ||
194 | INDYCAM_REG_BLUE_SATURATION, ®); | ||
195 | if (ret) | ||
196 | return -EIO; | ||
197 | ctrl->value = (s32)reg; | ||
198 | break; | ||
199 | case INDYCAM_CONTROL_GAMMA: | ||
200 | if (camera->version == CAMERA_VERSION_MOOSE) { | ||
201 | ret = indycam_read_reg(client, | ||
202 | INDYCAM_REG_GAMMA, ®); | ||
203 | if (ret) | ||
204 | return -EIO; | ||
205 | ctrl->value = (s32)reg; | ||
206 | } else { | ||
207 | ctrl->value = INDYCAM_GAMMA_DEFAULT; | ||
208 | } | ||
209 | break; | ||
210 | default: | ||
211 | ret = -EINVAL; | ||
212 | } | ||
168 | 213 | ||
169 | return 0; | 214 | return ret; |
170 | } | 215 | } |
171 | 216 | ||
172 | static int indycam_set_controls(struct i2c_client *client, | 217 | static int indycam_set_control(struct i2c_client *client, |
173 | struct indycam_control *ctrl) | 218 | struct indycam_control *ctrl) |
174 | { | 219 | { |
175 | unsigned char ctrl_reg; | 220 | struct indycam *camera = i2c_get_clientdata(client); |
221 | u8 reg; | ||
222 | int ret = 0; | ||
223 | |||
224 | switch (ctrl->type) { | ||
225 | case INDYCAM_CONTROL_AGC: | ||
226 | case INDYCAM_CONTROL_AWB: | ||
227 | ret = indycam_read_reg(client, INDYCAM_REG_CONTROL, ®); | ||
228 | if (ret) | ||
229 | break; | ||
176 | 230 | ||
177 | indycam_read_reg(client, INDYCAM_CONTROL, &ctrl_reg); | 231 | if (ctrl->type == INDYCAM_CONTROL_AGC) { |
178 | if (ctrl->agc != INDYCAM_VALUE_UNCHANGED) { | 232 | if (ctrl->value) |
179 | if (ctrl->agc) | 233 | reg |= INDYCAM_CONTROL_AGCENA; |
180 | ctrl_reg |= INDYCAM_CONTROL_AGCENA; | 234 | else |
181 | else | 235 | reg &= ~INDYCAM_CONTROL_AGCENA; |
182 | ctrl_reg &= ~INDYCAM_CONTROL_AGCENA; | 236 | } else { |
183 | } | 237 | if (ctrl->value) |
184 | if (ctrl->awb != INDYCAM_VALUE_UNCHANGED) { | 238 | reg |= INDYCAM_CONTROL_AWBCTL; |
185 | if (ctrl->awb) | 239 | else |
186 | ctrl_reg |= INDYCAM_CONTROL_AWBCTL; | 240 | reg &= ~INDYCAM_CONTROL_AWBCTL; |
187 | else | 241 | } |
188 | ctrl_reg &= ~INDYCAM_CONTROL_AWBCTL; | 242 | |
243 | ret = indycam_write_reg(client, INDYCAM_REG_CONTROL, reg); | ||
244 | break; | ||
245 | case INDYCAM_CONTROL_SHUTTER: | ||
246 | reg = (ctrl->value == 0xff) ? 0x00 : (ctrl->value + 1); | ||
247 | ret = indycam_write_reg(client, INDYCAM_REG_SHUTTER, reg); | ||
248 | break; | ||
249 | case INDYCAM_CONTROL_GAIN: | ||
250 | ret = indycam_write_reg(client, INDYCAM_REG_GAIN, ctrl->value); | ||
251 | break; | ||
252 | case INDYCAM_CONTROL_RED_BALANCE: | ||
253 | ret = indycam_write_reg(client, INDYCAM_REG_RED_BALANCE, | ||
254 | ctrl->value); | ||
255 | break; | ||
256 | case INDYCAM_CONTROL_BLUE_BALANCE: | ||
257 | ret = indycam_write_reg(client, INDYCAM_REG_BLUE_BALANCE, | ||
258 | ctrl->value); | ||
259 | break; | ||
260 | case INDYCAM_CONTROL_RED_SATURATION: | ||
261 | ret = indycam_write_reg(client, INDYCAM_REG_RED_SATURATION, | ||
262 | ctrl->value); | ||
263 | break; | ||
264 | case INDYCAM_CONTROL_BLUE_SATURATION: | ||
265 | ret = indycam_write_reg(client, INDYCAM_REG_BLUE_SATURATION, | ||
266 | ctrl->value); | ||
267 | break; | ||
268 | case INDYCAM_CONTROL_GAMMA: | ||
269 | if (camera->version == CAMERA_VERSION_MOOSE) { | ||
270 | ret = indycam_write_reg(client, INDYCAM_REG_GAMMA, | ||
271 | ctrl->value); | ||
272 | } | ||
273 | break; | ||
274 | default: | ||
275 | ret = -EINVAL; | ||
189 | } | 276 | } |
190 | indycam_write_reg(client, INDYCAM_CONTROL, ctrl_reg); | ||
191 | |||
192 | if (ctrl->shutter >= 0) | ||
193 | indycam_write_reg(client, INDYCAM_SHUTTER, ctrl->shutter); | ||
194 | if (ctrl->gain >= 0) | ||
195 | indycam_write_reg(client, INDYCAM_GAIN, ctrl->gain); | ||
196 | if (ctrl->red_balance >= 0) | ||
197 | indycam_write_reg(client, INDYCAM_RED_BALANCE, | ||
198 | ctrl->red_balance); | ||
199 | if (ctrl->blue_balance >= 0) | ||
200 | indycam_write_reg(client, INDYCAM_BLUE_BALANCE, | ||
201 | ctrl->blue_balance); | ||
202 | if (ctrl->red_saturation >= 0) | ||
203 | indycam_write_reg(client, INDYCAM_RED_SATURATION, | ||
204 | ctrl->red_saturation); | ||
205 | if (ctrl->blue_saturation >= 0) | ||
206 | indycam_write_reg(client, INDYCAM_BLUE_SATURATION, | ||
207 | ctrl->blue_saturation); | ||
208 | if (ctrl->gamma >= 0) | ||
209 | indycam_write_reg(client, INDYCAM_GAMMA, ctrl->gamma); | ||
210 | 277 | ||
211 | return 0; | 278 | return ret; |
212 | } | 279 | } |
213 | 280 | ||
214 | /* I2C-interface */ | 281 | /* I2C-interface */ |
@@ -247,7 +314,8 @@ static int indycam_attach(struct i2c_adapter *adap, int addr, int kind) | |||
247 | if (err) | 314 | if (err) |
248 | goto out_free_camera; | 315 | goto out_free_camera; |
249 | 316 | ||
250 | camera->version = i2c_smbus_read_byte_data(client, INDYCAM_VERSION); | 317 | camera->version = i2c_smbus_read_byte_data(client, |
318 | INDYCAM_REG_VERSION); | ||
251 | if (camera->version != CAMERA_VERSION_INDY && | 319 | if (camera->version != CAMERA_VERSION_INDY && |
252 | camera->version != CAMERA_VERSION_MOOSE) { | 320 | camera->version != CAMERA_VERSION_MOOSE) { |
253 | err = -ENODEV; | 321 | err = -ENODEV; |
@@ -260,8 +328,7 @@ static int indycam_attach(struct i2c_adapter *adap, int addr, int kind) | |||
260 | indycam_regdump(client); | 328 | indycam_regdump(client); |
261 | 329 | ||
262 | // initialize | 330 | // initialize |
263 | err = indycam_write_block(client, 0, sizeof(initseq), | 331 | err = indycam_write_block(client, 0, sizeof(initseq), (u8 *)&initseq); |
264 | (unsigned char *)&initseq); | ||
265 | if (err) { | 332 | if (err) { |
266 | printk(KERN_ERR "IndyCam initalization failed\n"); | 333 | printk(KERN_ERR "IndyCam initalization failed\n"); |
267 | err = -EIO; | 334 | err = -EIO; |
@@ -271,11 +338,10 @@ static int indycam_attach(struct i2c_adapter *adap, int addr, int kind) | |||
271 | indycam_regdump(client); | 338 | indycam_regdump(client); |
272 | 339 | ||
273 | // white balance | 340 | // white balance |
274 | err = indycam_write_reg(client, INDYCAM_CONTROL, | 341 | err = indycam_write_reg(client, INDYCAM_REG_CONTROL, |
275 | INDYCAM_CONTROL_AGCENA | INDYCAM_CONTROL_AWBCTL); | 342 | INDYCAM_CONTROL_AGCENA | INDYCAM_CONTROL_AWBCTL); |
276 | if (err) { | 343 | if (err) { |
277 | printk(KERN_ERR "IndyCam white balance " | 344 | printk(KERN_ERR "IndyCam: White balancing camera failed\n"); |
278 | "initialization failed\n"); | ||
279 | err = -EIO; | 345 | err = -EIO; |
280 | goto out_detach_client; | 346 | goto out_detach_client; |
281 | } | 347 | } |
@@ -371,13 +437,11 @@ static int indycam_command(struct i2c_client *client, unsigned int cmd, | |||
371 | /* TODO: convert values for indycam_set_controls() */ | 437 | /* TODO: convert values for indycam_set_controls() */ |
372 | break; | 438 | break; |
373 | } | 439 | } |
374 | case DECODER_INDYCAM_GET_CONTROLS: { | 440 | case DECODER_INDYCAM_GET_CONTROL: { |
375 | struct indycam_control *ctrl = arg; | 441 | return indycam_get_control(client, arg); |
376 | indycam_get_controls(client, ctrl); | ||
377 | } | 442 | } |
378 | case DECODER_INDYCAM_SET_CONTROLS: { | 443 | case DECODER_INDYCAM_SET_CONTROL: { |
379 | struct indycam_control *ctrl = arg; | 444 | return indycam_set_control(client, arg); |
380 | indycam_set_controls(client, ctrl); | ||
381 | } | 445 | } |
382 | default: | 446 | default: |
383 | return -EINVAL; | 447 | return -EINVAL; |
@@ -388,12 +452,12 @@ static int indycam_command(struct i2c_client *client, unsigned int cmd, | |||
388 | 452 | ||
389 | static struct i2c_driver i2c_driver_indycam = { | 453 | static struct i2c_driver i2c_driver_indycam = { |
390 | .owner = THIS_MODULE, | 454 | .owner = THIS_MODULE, |
391 | .name = "indycam", | 455 | .name = "indycam", |
392 | .id = I2C_DRIVERID_INDYCAM, | 456 | .id = I2C_DRIVERID_INDYCAM, |
393 | .flags = I2C_DF_NOTIFY, | 457 | .flags = I2C_DF_NOTIFY, |
394 | .attach_adapter = indycam_probe, | 458 | .attach_adapter = indycam_probe, |
395 | .detach_client = indycam_detach, | 459 | .detach_client = indycam_detach, |
396 | .command = indycam_command, | 460 | .command = indycam_command, |
397 | }; | 461 | }; |
398 | 462 | ||
399 | static int __init indycam_init(void) | 463 | static int __init indycam_init(void) |