diff options
Diffstat (limited to 'drivers/media/video/indycam.c')
-rw-r--r-- | drivers/media/video/indycam.c | 128 |
1 files changed, 71 insertions, 57 deletions
diff --git a/drivers/media/video/indycam.c b/drivers/media/video/indycam.c index 54099e303c8d..eb5078c07a33 100644 --- a/drivers/media/video/indycam.c +++ b/drivers/media/video/indycam.c | |||
@@ -22,7 +22,8 @@ | |||
22 | /* IndyCam decodes stream of photons into digital image representation ;-) */ | 22 | /* IndyCam decodes stream of photons into digital image representation ;-) */ |
23 | #include <linux/videodev2.h> | 23 | #include <linux/videodev2.h> |
24 | #include <linux/i2c.h> | 24 | #include <linux/i2c.h> |
25 | #include <media/v4l2-common.h> | 25 | #include <media/v4l2-device.h> |
26 | #include <media/v4l2-chip-ident.h> | ||
26 | #include <media/v4l2-i2c-drv-legacy.h> | 27 | #include <media/v4l2-i2c-drv-legacy.h> |
27 | 28 | ||
28 | #include "indycam.h" | 29 | #include "indycam.h" |
@@ -49,10 +50,15 @@ I2C_CLIENT_INSMOD; | |||
49 | #endif | 50 | #endif |
50 | 51 | ||
51 | struct indycam { | 52 | struct indycam { |
52 | struct i2c_client *client; | 53 | struct v4l2_subdev sd; |
53 | u8 version; | 54 | u8 version; |
54 | }; | 55 | }; |
55 | 56 | ||
57 | static inline struct indycam *to_indycam(struct v4l2_subdev *sd) | ||
58 | { | ||
59 | return container_of(sd, struct indycam, sd); | ||
60 | } | ||
61 | |||
56 | static const u8 initseq[] = { | 62 | static const u8 initseq[] = { |
57 | INDYCAM_CONTROL_AGCENA, /* INDYCAM_CONTROL */ | 63 | INDYCAM_CONTROL_AGCENA, /* INDYCAM_CONTROL */ |
58 | INDYCAM_SHUTTER_60, /* INDYCAM_SHUTTER */ | 64 | INDYCAM_SHUTTER_60, /* INDYCAM_SHUTTER */ |
@@ -66,8 +72,9 @@ static const u8 initseq[] = { | |||
66 | 72 | ||
67 | /* IndyCam register handling */ | 73 | /* IndyCam register handling */ |
68 | 74 | ||
69 | static int indycam_read_reg(struct i2c_client *client, u8 reg, u8 *value) | 75 | static int indycam_read_reg(struct v4l2_subdev *sd, u8 reg, u8 *value) |
70 | { | 76 | { |
77 | struct i2c_client *client = v4l2_get_subdevdata(sd); | ||
71 | int ret; | 78 | int ret; |
72 | 79 | ||
73 | if (reg == INDYCAM_REG_RESET) { | 80 | if (reg == INDYCAM_REG_RESET) { |
@@ -90,12 +97,12 @@ static int indycam_read_reg(struct i2c_client *client, u8 reg, u8 *value) | |||
90 | return 0; | 97 | return 0; |
91 | } | 98 | } |
92 | 99 | ||
93 | static int indycam_write_reg(struct i2c_client *client, u8 reg, u8 value) | 100 | static int indycam_write_reg(struct v4l2_subdev *sd, u8 reg, u8 value) |
94 | { | 101 | { |
102 | struct i2c_client *client = v4l2_get_subdevdata(sd); | ||
95 | int err; | 103 | int err; |
96 | 104 | ||
97 | if ((reg == INDYCAM_REG_BRIGHTNESS) | 105 | if (reg == INDYCAM_REG_BRIGHTNESS || reg == INDYCAM_REG_VERSION) { |
98 | || (reg == INDYCAM_REG_VERSION)) { | ||
99 | dprintk("indycam_write_reg(): " | 106 | dprintk("indycam_write_reg(): " |
100 | "skipping read-only register %d\n", reg); | 107 | "skipping read-only register %d\n", reg); |
101 | return 0; | 108 | return 0; |
@@ -111,13 +118,13 @@ static int indycam_write_reg(struct i2c_client *client, u8 reg, u8 value) | |||
111 | return err; | 118 | return err; |
112 | } | 119 | } |
113 | 120 | ||
114 | static int indycam_write_block(struct i2c_client *client, u8 reg, | 121 | static int indycam_write_block(struct v4l2_subdev *sd, u8 reg, |
115 | u8 length, u8 *data) | 122 | u8 length, u8 *data) |
116 | { | 123 | { |
117 | int i, err; | 124 | int i, err; |
118 | 125 | ||
119 | for (i = 0; i < length; i++) { | 126 | for (i = 0; i < length; i++) { |
120 | err = indycam_write_reg(client, reg + i, data[i]); | 127 | err = indycam_write_reg(sd, reg + i, data[i]); |
121 | if (err) | 128 | if (err) |
122 | return err; | 129 | return err; |
123 | } | 130 | } |
@@ -128,29 +135,28 @@ static int indycam_write_block(struct i2c_client *client, u8 reg, | |||
128 | /* Helper functions */ | 135 | /* Helper functions */ |
129 | 136 | ||
130 | #ifdef INDYCAM_DEBUG | 137 | #ifdef INDYCAM_DEBUG |
131 | static void indycam_regdump_debug(struct i2c_client *client) | 138 | static void indycam_regdump_debug(struct v4l2_subdev *sd) |
132 | { | 139 | { |
133 | int i; | 140 | int i; |
134 | u8 val; | 141 | u8 val; |
135 | 142 | ||
136 | for (i = 0; i < 9; i++) { | 143 | for (i = 0; i < 9; i++) { |
137 | indycam_read_reg(client, i, &val); | 144 | indycam_read_reg(sd, i, &val); |
138 | dprintk("Reg %d = 0x%02x\n", i, val); | 145 | dprintk("Reg %d = 0x%02x\n", i, val); |
139 | } | 146 | } |
140 | } | 147 | } |
141 | #endif | 148 | #endif |
142 | 149 | ||
143 | static int indycam_get_control(struct i2c_client *client, | 150 | static int indycam_g_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl) |
144 | struct v4l2_control *ctrl) | ||
145 | { | 151 | { |
146 | struct indycam *camera = i2c_get_clientdata(client); | 152 | struct indycam *camera = to_indycam(sd); |
147 | u8 reg; | 153 | u8 reg; |
148 | int ret = 0; | 154 | int ret = 0; |
149 | 155 | ||
150 | switch (ctrl->id) { | 156 | switch (ctrl->id) { |
151 | case V4L2_CID_AUTOGAIN: | 157 | case V4L2_CID_AUTOGAIN: |
152 | case V4L2_CID_AUTO_WHITE_BALANCE: | 158 | case V4L2_CID_AUTO_WHITE_BALANCE: |
153 | ret = indycam_read_reg(client, INDYCAM_REG_CONTROL, ®); | 159 | ret = indycam_read_reg(sd, INDYCAM_REG_CONTROL, ®); |
154 | if (ret) | 160 | if (ret) |
155 | return -EIO; | 161 | return -EIO; |
156 | if (ctrl->id == V4L2_CID_AUTOGAIN) | 162 | if (ctrl->id == V4L2_CID_AUTOGAIN) |
@@ -161,38 +167,38 @@ static int indycam_get_control(struct i2c_client *client, | |||
161 | ? 1 : 0; | 167 | ? 1 : 0; |
162 | break; | 168 | break; |
163 | case V4L2_CID_EXPOSURE: | 169 | case V4L2_CID_EXPOSURE: |
164 | ret = indycam_read_reg(client, INDYCAM_REG_SHUTTER, ®); | 170 | ret = indycam_read_reg(sd, INDYCAM_REG_SHUTTER, ®); |
165 | if (ret) | 171 | if (ret) |
166 | return -EIO; | 172 | return -EIO; |
167 | ctrl->value = ((s32)reg == 0x00) ? 0xff : ((s32)reg - 1); | 173 | ctrl->value = ((s32)reg == 0x00) ? 0xff : ((s32)reg - 1); |
168 | break; | 174 | break; |
169 | case V4L2_CID_GAIN: | 175 | case V4L2_CID_GAIN: |
170 | ret = indycam_read_reg(client, INDYCAM_REG_GAIN, ®); | 176 | ret = indycam_read_reg(sd, INDYCAM_REG_GAIN, ®); |
171 | if (ret) | 177 | if (ret) |
172 | return -EIO; | 178 | return -EIO; |
173 | ctrl->value = (s32)reg; | 179 | ctrl->value = (s32)reg; |
174 | break; | 180 | break; |
175 | case V4L2_CID_RED_BALANCE: | 181 | case V4L2_CID_RED_BALANCE: |
176 | ret = indycam_read_reg(client, INDYCAM_REG_RED_BALANCE, ®); | 182 | ret = indycam_read_reg(sd, INDYCAM_REG_RED_BALANCE, ®); |
177 | if (ret) | 183 | if (ret) |
178 | return -EIO; | 184 | return -EIO; |
179 | ctrl->value = (s32)reg; | 185 | ctrl->value = (s32)reg; |
180 | break; | 186 | break; |
181 | case V4L2_CID_BLUE_BALANCE: | 187 | case V4L2_CID_BLUE_BALANCE: |
182 | ret = indycam_read_reg(client, INDYCAM_REG_BLUE_BALANCE, ®); | 188 | ret = indycam_read_reg(sd, INDYCAM_REG_BLUE_BALANCE, ®); |
183 | if (ret) | 189 | if (ret) |
184 | return -EIO; | 190 | return -EIO; |
185 | ctrl->value = (s32)reg; | 191 | ctrl->value = (s32)reg; |
186 | break; | 192 | break; |
187 | case INDYCAM_CONTROL_RED_SATURATION: | 193 | case INDYCAM_CONTROL_RED_SATURATION: |
188 | ret = indycam_read_reg(client, | 194 | ret = indycam_read_reg(sd, |
189 | INDYCAM_REG_RED_SATURATION, ®); | 195 | INDYCAM_REG_RED_SATURATION, ®); |
190 | if (ret) | 196 | if (ret) |
191 | return -EIO; | 197 | return -EIO; |
192 | ctrl->value = (s32)reg; | 198 | ctrl->value = (s32)reg; |
193 | break; | 199 | break; |
194 | case INDYCAM_CONTROL_BLUE_SATURATION: | 200 | case INDYCAM_CONTROL_BLUE_SATURATION: |
195 | ret = indycam_read_reg(client, | 201 | ret = indycam_read_reg(sd, |
196 | INDYCAM_REG_BLUE_SATURATION, ®); | 202 | INDYCAM_REG_BLUE_SATURATION, ®); |
197 | if (ret) | 203 | if (ret) |
198 | return -EIO; | 204 | return -EIO; |
@@ -200,7 +206,7 @@ static int indycam_get_control(struct i2c_client *client, | |||
200 | break; | 206 | break; |
201 | case V4L2_CID_GAMMA: | 207 | case V4L2_CID_GAMMA: |
202 | if (camera->version == CAMERA_VERSION_MOOSE) { | 208 | if (camera->version == CAMERA_VERSION_MOOSE) { |
203 | ret = indycam_read_reg(client, | 209 | ret = indycam_read_reg(sd, |
204 | INDYCAM_REG_GAMMA, ®); | 210 | INDYCAM_REG_GAMMA, ®); |
205 | if (ret) | 211 | if (ret) |
206 | return -EIO; | 212 | return -EIO; |
@@ -216,17 +222,16 @@ static int indycam_get_control(struct i2c_client *client, | |||
216 | return ret; | 222 | return ret; |
217 | } | 223 | } |
218 | 224 | ||
219 | static int indycam_set_control(struct i2c_client *client, | 225 | static int indycam_s_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl) |
220 | struct v4l2_control *ctrl) | ||
221 | { | 226 | { |
222 | struct indycam *camera = i2c_get_clientdata(client); | 227 | struct indycam *camera = to_indycam(sd); |
223 | u8 reg; | 228 | u8 reg; |
224 | int ret = 0; | 229 | int ret = 0; |
225 | 230 | ||
226 | switch (ctrl->id) { | 231 | switch (ctrl->id) { |
227 | case V4L2_CID_AUTOGAIN: | 232 | case V4L2_CID_AUTOGAIN: |
228 | case V4L2_CID_AUTO_WHITE_BALANCE: | 233 | case V4L2_CID_AUTO_WHITE_BALANCE: |
229 | ret = indycam_read_reg(client, INDYCAM_REG_CONTROL, ®); | 234 | ret = indycam_read_reg(sd, INDYCAM_REG_CONTROL, ®); |
230 | if (ret) | 235 | if (ret) |
231 | break; | 236 | break; |
232 | 237 | ||
@@ -242,34 +247,34 @@ static int indycam_set_control(struct i2c_client *client, | |||
242 | reg &= ~INDYCAM_CONTROL_AWBCTL; | 247 | reg &= ~INDYCAM_CONTROL_AWBCTL; |
243 | } | 248 | } |
244 | 249 | ||
245 | ret = indycam_write_reg(client, INDYCAM_REG_CONTROL, reg); | 250 | ret = indycam_write_reg(sd, INDYCAM_REG_CONTROL, reg); |
246 | break; | 251 | break; |
247 | case V4L2_CID_EXPOSURE: | 252 | case V4L2_CID_EXPOSURE: |
248 | reg = (ctrl->value == 0xff) ? 0x00 : (ctrl->value + 1); | 253 | reg = (ctrl->value == 0xff) ? 0x00 : (ctrl->value + 1); |
249 | ret = indycam_write_reg(client, INDYCAM_REG_SHUTTER, reg); | 254 | ret = indycam_write_reg(sd, INDYCAM_REG_SHUTTER, reg); |
250 | break; | 255 | break; |
251 | case V4L2_CID_GAIN: | 256 | case V4L2_CID_GAIN: |
252 | ret = indycam_write_reg(client, INDYCAM_REG_GAIN, ctrl->value); | 257 | ret = indycam_write_reg(sd, INDYCAM_REG_GAIN, ctrl->value); |
253 | break; | 258 | break; |
254 | case V4L2_CID_RED_BALANCE: | 259 | case V4L2_CID_RED_BALANCE: |
255 | ret = indycam_write_reg(client, INDYCAM_REG_RED_BALANCE, | 260 | ret = indycam_write_reg(sd, INDYCAM_REG_RED_BALANCE, |
256 | ctrl->value); | 261 | ctrl->value); |
257 | break; | 262 | break; |
258 | case V4L2_CID_BLUE_BALANCE: | 263 | case V4L2_CID_BLUE_BALANCE: |
259 | ret = indycam_write_reg(client, INDYCAM_REG_BLUE_BALANCE, | 264 | ret = indycam_write_reg(sd, INDYCAM_REG_BLUE_BALANCE, |
260 | ctrl->value); | 265 | ctrl->value); |
261 | break; | 266 | break; |
262 | case INDYCAM_CONTROL_RED_SATURATION: | 267 | case INDYCAM_CONTROL_RED_SATURATION: |
263 | ret = indycam_write_reg(client, INDYCAM_REG_RED_SATURATION, | 268 | ret = indycam_write_reg(sd, INDYCAM_REG_RED_SATURATION, |
264 | ctrl->value); | 269 | ctrl->value); |
265 | break; | 270 | break; |
266 | case INDYCAM_CONTROL_BLUE_SATURATION: | 271 | case INDYCAM_CONTROL_BLUE_SATURATION: |
267 | ret = indycam_write_reg(client, INDYCAM_REG_BLUE_SATURATION, | 272 | ret = indycam_write_reg(sd, INDYCAM_REG_BLUE_SATURATION, |
268 | ctrl->value); | 273 | ctrl->value); |
269 | break; | 274 | break; |
270 | case V4L2_CID_GAMMA: | 275 | case V4L2_CID_GAMMA: |
271 | if (camera->version == CAMERA_VERSION_MOOSE) { | 276 | if (camera->version == CAMERA_VERSION_MOOSE) { |
272 | ret = indycam_write_reg(client, INDYCAM_REG_GAMMA, | 277 | ret = indycam_write_reg(sd, INDYCAM_REG_GAMMA, |
273 | ctrl->value); | 278 | ctrl->value); |
274 | } | 279 | } |
275 | break; | 280 | break; |
@@ -282,30 +287,39 @@ static int indycam_set_control(struct i2c_client *client, | |||
282 | 287 | ||
283 | /* I2C-interface */ | 288 | /* I2C-interface */ |
284 | 289 | ||
285 | static int indycam_command(struct i2c_client *client, unsigned int cmd, | 290 | static int indycam_g_chip_ident(struct v4l2_subdev *sd, |
286 | void *arg) | 291 | struct v4l2_dbg_chip_ident *chip) |
287 | { | 292 | { |
288 | /* The old video_decoder interface just isn't enough, | 293 | struct i2c_client *client = v4l2_get_subdevdata(sd); |
289 | * so we'll use some custom commands. */ | 294 | struct indycam *camera = to_indycam(sd); |
290 | switch (cmd) { | ||
291 | case VIDIOC_G_CTRL: | ||
292 | return indycam_get_control(client, arg); | ||
293 | |||
294 | case VIDIOC_S_CTRL: | ||
295 | return indycam_set_control(client, arg); | ||
296 | 295 | ||
297 | default: | 296 | return v4l2_chip_ident_i2c_client(client, chip, V4L2_IDENT_INDYCAM, |
298 | return -EINVAL; | 297 | camera->version); |
299 | } | 298 | } |
300 | 299 | ||
301 | return 0; | 300 | static int indycam_command(struct i2c_client *client, unsigned cmd, void *arg) |
301 | { | ||
302 | return v4l2_subdev_command(i2c_get_clientdata(client), cmd, arg); | ||
302 | } | 303 | } |
303 | 304 | ||
305 | /* ----------------------------------------------------------------------- */ | ||
306 | |||
307 | static const struct v4l2_subdev_core_ops indycam_core_ops = { | ||
308 | .g_chip_ident = indycam_g_chip_ident, | ||
309 | .g_ctrl = indycam_g_ctrl, | ||
310 | .s_ctrl = indycam_s_ctrl, | ||
311 | }; | ||
312 | |||
313 | static const struct v4l2_subdev_ops indycam_ops = { | ||
314 | .core = &indycam_core_ops, | ||
315 | }; | ||
316 | |||
304 | static int indycam_probe(struct i2c_client *client, | 317 | static int indycam_probe(struct i2c_client *client, |
305 | const struct i2c_device_id *id) | 318 | const struct i2c_device_id *id) |
306 | { | 319 | { |
307 | int err = 0; | 320 | int err = 0; |
308 | struct indycam *camera; | 321 | struct indycam *camera; |
322 | struct v4l2_subdev *sd; | ||
309 | 323 | ||
310 | v4l_info(client, "chip found @ 0x%x (%s)\n", | 324 | v4l_info(client, "chip found @ 0x%x (%s)\n", |
311 | client->addr << 1, client->adapter->name); | 325 | client->addr << 1, client->adapter->name); |
@@ -314,9 +328,8 @@ static int indycam_probe(struct i2c_client *client, | |||
314 | if (!camera) | 328 | if (!camera) |
315 | return -ENOMEM; | 329 | return -ENOMEM; |
316 | 330 | ||
317 | i2c_set_clientdata(client, camera); | 331 | sd = &camera->sd; |
318 | 332 | v4l2_i2c_subdev_init(sd, client, &indycam_ops); | |
319 | camera->client = client; | ||
320 | 333 | ||
321 | camera->version = i2c_smbus_read_byte_data(client, | 334 | camera->version = i2c_smbus_read_byte_data(client, |
322 | INDYCAM_REG_VERSION); | 335 | INDYCAM_REG_VERSION); |
@@ -330,20 +343,20 @@ static int indycam_probe(struct i2c_client *client, | |||
330 | INDYCAM_VERSION_MAJOR(camera->version), | 343 | INDYCAM_VERSION_MAJOR(camera->version), |
331 | INDYCAM_VERSION_MINOR(camera->version)); | 344 | INDYCAM_VERSION_MINOR(camera->version)); |
332 | 345 | ||
333 | indycam_regdump(client); | 346 | indycam_regdump(sd); |
334 | 347 | ||
335 | // initialize | 348 | // initialize |
336 | err = indycam_write_block(client, 0, sizeof(initseq), (u8 *)&initseq); | 349 | err = indycam_write_block(sd, 0, sizeof(initseq), (u8 *)&initseq); |
337 | if (err) { | 350 | if (err) { |
338 | printk(KERN_ERR "IndyCam initialization failed\n"); | 351 | printk(KERN_ERR "IndyCam initialization failed\n"); |
339 | kfree(camera); | 352 | kfree(camera); |
340 | return -EIO; | 353 | return -EIO; |
341 | } | 354 | } |
342 | 355 | ||
343 | indycam_regdump(client); | 356 | indycam_regdump(sd); |
344 | 357 | ||
345 | // white balance | 358 | // white balance |
346 | err = indycam_write_reg(client, INDYCAM_REG_CONTROL, | 359 | err = indycam_write_reg(sd, INDYCAM_REG_CONTROL, |
347 | INDYCAM_CONTROL_AGCENA | INDYCAM_CONTROL_AWBCTL); | 360 | INDYCAM_CONTROL_AGCENA | INDYCAM_CONTROL_AWBCTL); |
348 | if (err) { | 361 | if (err) { |
349 | printk(KERN_ERR "IndyCam: White balancing camera failed\n"); | 362 | printk(KERN_ERR "IndyCam: White balancing camera failed\n"); |
@@ -351,7 +364,7 @@ static int indycam_probe(struct i2c_client *client, | |||
351 | return -EIO; | 364 | return -EIO; |
352 | } | 365 | } |
353 | 366 | ||
354 | indycam_regdump(client); | 367 | indycam_regdump(sd); |
355 | 368 | ||
356 | printk(KERN_INFO "IndyCam initialized\n"); | 369 | printk(KERN_INFO "IndyCam initialized\n"); |
357 | 370 | ||
@@ -360,9 +373,10 @@ static int indycam_probe(struct i2c_client *client, | |||
360 | 373 | ||
361 | static int indycam_remove(struct i2c_client *client) | 374 | static int indycam_remove(struct i2c_client *client) |
362 | { | 375 | { |
363 | struct indycam *camera = i2c_get_clientdata(client); | 376 | struct v4l2_subdev *sd = i2c_get_clientdata(client); |
364 | 377 | ||
365 | kfree(camera); | 378 | v4l2_device_unregister_subdev(sd); |
379 | kfree(to_indycam(sd)); | ||
366 | return 0; | 380 | return 0; |
367 | } | 381 | } |
368 | 382 | ||