diff options
author | Hans Verkuil <hverkuil@xs4all.nl> | 2008-09-07 07:01:39 -0400 |
---|---|---|
committer | Mauro Carvalho Chehab <mchehab@redhat.com> | 2008-10-17 16:20:13 -0400 |
commit | 23848b655ab5fc2fe88ef99e90ad8e4c41304d76 (patch) | |
tree | ae755bfdc215a2b09163ca0f0c226db4a98cc644 /drivers/media/video/vpx3220.c | |
parent | 0afb351e62f855b1c3584fb54bc6b91b54b32a9a (diff) |
V4L/DVB (9208): vpx3220: convert i2c driver for new i2c API
- Convert to use v4l2-i2c-drv-legacy.h to be able to handle the new i2c API
- Cleanups
- Use v4l_dbg/v4l_info to have uniform kernel messages
Signed-off-by: Hans Verkuil <hverkuil@xs4all.nl>
Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com>
Diffstat (limited to 'drivers/media/video/vpx3220.c')
-rw-r--r-- | drivers/media/video/vpx3220.c | 328 |
1 files changed, 91 insertions, 237 deletions
diff --git a/drivers/media/video/vpx3220.c b/drivers/media/video/vpx3220.c index 45be9ec8edc4..67aa0db4b81a 100644 --- a/drivers/media/video/vpx3220.c +++ b/drivers/media/video/vpx3220.c | |||
@@ -22,32 +22,21 @@ | |||
22 | #include <linux/init.h> | 22 | #include <linux/init.h> |
23 | #include <linux/delay.h> | 23 | #include <linux/delay.h> |
24 | #include <linux/types.h> | 24 | #include <linux/types.h> |
25 | #include <linux/slab.h> | ||
26 | |||
27 | #include <asm/io.h> | ||
28 | #include <asm/uaccess.h> | 25 | #include <asm/uaccess.h> |
29 | |||
30 | #include <linux/i2c.h> | 26 | #include <linux/i2c.h> |
31 | |||
32 | #define I2C_NAME(x) (x)->name | ||
33 | |||
34 | #include <linux/videodev.h> | ||
35 | #include <media/v4l2-common.h> | 27 | #include <media/v4l2-common.h> |
28 | #include <media/v4l2-i2c-drv-legacy.h> | ||
29 | #include <linux/videodev.h> | ||
36 | #include <linux/video_decoder.h> | 30 | #include <linux/video_decoder.h> |
37 | 31 | ||
38 | #define I2C_VPX3220 0x86 | 32 | MODULE_DESCRIPTION("vpx3220a/vpx3216b/vpx3214c video decoder driver"); |
39 | #define VPX3220_DEBUG KERN_DEBUG "vpx3220: " | 33 | MODULE_AUTHOR("Laurent Pinchart"); |
34 | MODULE_LICENSE("GPL"); | ||
40 | 35 | ||
41 | static int debug; | 36 | static int debug; |
42 | module_param(debug, int, 0); | 37 | module_param(debug, int, 0); |
43 | MODULE_PARM_DESC(debug, "Debug level (0-1)"); | 38 | MODULE_PARM_DESC(debug, "Debug level (0-1)"); |
44 | 39 | ||
45 | #define dprintk(num, format, args...) \ | ||
46 | do { \ | ||
47 | if (debug >= num) \ | ||
48 | printk(format, ##args); \ | ||
49 | } while (0) | ||
50 | |||
51 | #define VPX_TIMEOUT_COUNT 10 | 40 | #define VPX_TIMEOUT_COUNT 10 |
52 | 41 | ||
53 | /* ----------------------------------------------------------------------- */ | 42 | /* ----------------------------------------------------------------------- */ |
@@ -67,10 +56,8 @@ struct vpx3220 { | |||
67 | static char *inputs[] = { "internal", "composite", "svideo" }; | 56 | static char *inputs[] = { "internal", "composite", "svideo" }; |
68 | 57 | ||
69 | /* ----------------------------------------------------------------------- */ | 58 | /* ----------------------------------------------------------------------- */ |
70 | static inline int | 59 | |
71 | vpx3220_write (struct i2c_client *client, | 60 | static inline int vpx3220_write(struct i2c_client *client, u8 reg, u8 value) |
72 | u8 reg, | ||
73 | u8 value) | ||
74 | { | 61 | { |
75 | struct vpx3220 *decoder = i2c_get_clientdata(client); | 62 | struct vpx3220 *decoder = i2c_get_clientdata(client); |
76 | 63 | ||
@@ -78,15 +65,12 @@ vpx3220_write (struct i2c_client *client, | |||
78 | return i2c_smbus_write_byte_data(client, reg, value); | 65 | return i2c_smbus_write_byte_data(client, reg, value); |
79 | } | 66 | } |
80 | 67 | ||
81 | static inline int | 68 | static inline int vpx3220_read(struct i2c_client *client, u8 reg) |
82 | vpx3220_read (struct i2c_client *client, | ||
83 | u8 reg) | ||
84 | { | 69 | { |
85 | return i2c_smbus_read_byte_data(client, reg); | 70 | return i2c_smbus_read_byte_data(client, reg); |
86 | } | 71 | } |
87 | 72 | ||
88 | static int | 73 | static int vpx3220_fp_status(struct i2c_client *client) |
89 | vpx3220_fp_status (struct i2c_client *client) | ||
90 | { | 74 | { |
91 | unsigned char status; | 75 | unsigned char status; |
92 | unsigned int i; | 76 | unsigned int i; |
@@ -106,14 +90,11 @@ vpx3220_fp_status (struct i2c_client *client) | |||
106 | return -1; | 90 | return -1; |
107 | } | 91 | } |
108 | 92 | ||
109 | static int | 93 | static int vpx3220_fp_write(struct i2c_client *client, u8 fpaddr, u16 data) |
110 | vpx3220_fp_write (struct i2c_client *client, | ||
111 | u8 fpaddr, | ||
112 | u16 data) | ||
113 | { | 94 | { |
114 | /* Write the 16-bit address to the FPWR register */ | 95 | /* Write the 16-bit address to the FPWR register */ |
115 | if (i2c_smbus_write_word_data(client, 0x27, swab16(fpaddr)) == -1) { | 96 | if (i2c_smbus_write_word_data(client, 0x27, swab16(fpaddr)) == -1) { |
116 | dprintk(1, VPX3220_DEBUG "%s: failed\n", __func__); | 97 | v4l_dbg(1, debug, client, "%s: failed\n", __func__); |
117 | return -1; | 98 | return -1; |
118 | } | 99 | } |
119 | 100 | ||
@@ -122,22 +103,20 @@ vpx3220_fp_write (struct i2c_client *client, | |||
122 | 103 | ||
123 | /* Write the 16-bit data to the FPDAT register */ | 104 | /* Write the 16-bit data to the FPDAT register */ |
124 | if (i2c_smbus_write_word_data(client, 0x28, swab16(data)) == -1) { | 105 | if (i2c_smbus_write_word_data(client, 0x28, swab16(data)) == -1) { |
125 | dprintk(1, VPX3220_DEBUG "%s: failed\n", __func__); | 106 | v4l_dbg(1, debug, client, "%s: failed\n", __func__); |
126 | return -1; | 107 | return -1; |
127 | } | 108 | } |
128 | 109 | ||
129 | return 0; | 110 | return 0; |
130 | } | 111 | } |
131 | 112 | ||
132 | static u16 | 113 | static u16 vpx3220_fp_read(struct i2c_client *client, u16 fpaddr) |
133 | vpx3220_fp_read (struct i2c_client *client, | ||
134 | u16 fpaddr) | ||
135 | { | 114 | { |
136 | s16 data; | 115 | s16 data; |
137 | 116 | ||
138 | /* Write the 16-bit address to the FPRD register */ | 117 | /* Write the 16-bit address to the FPRD register */ |
139 | if (i2c_smbus_write_word_data(client, 0x26, swab16(fpaddr)) == -1) { | 118 | if (i2c_smbus_write_word_data(client, 0x26, swab16(fpaddr)) == -1) { |
140 | dprintk(1, VPX3220_DEBUG "%s: failed\n", __func__); | 119 | v4l_dbg(1, debug, client, "%s: failed\n", __func__); |
141 | return -1; | 120 | return -1; |
142 | } | 121 | } |
143 | 122 | ||
@@ -147,25 +126,22 @@ vpx3220_fp_read (struct i2c_client *client, | |||
147 | /* Read the 16-bit data from the FPDAT register */ | 126 | /* Read the 16-bit data from the FPDAT register */ |
148 | data = i2c_smbus_read_word_data(client, 0x28); | 127 | data = i2c_smbus_read_word_data(client, 0x28); |
149 | if (data == -1) { | 128 | if (data == -1) { |
150 | dprintk(1, VPX3220_DEBUG "%s: failed\n", __func__); | 129 | v4l_dbg(1, debug, client, "%s: failed\n", __func__); |
151 | return -1; | 130 | return -1; |
152 | } | 131 | } |
153 | 132 | ||
154 | return swab16(data); | 133 | return swab16(data); |
155 | } | 134 | } |
156 | 135 | ||
157 | static int | 136 | static int vpx3220_write_block(struct i2c_client *client, const u8 *data, unsigned int len) |
158 | vpx3220_write_block (struct i2c_client *client, | ||
159 | const u8 *data, | ||
160 | unsigned int len) | ||
161 | { | 137 | { |
162 | u8 reg; | 138 | u8 reg; |
163 | int ret = -1; | 139 | int ret = -1; |
164 | 140 | ||
165 | while (len >= 2) { | 141 | while (len >= 2) { |
166 | reg = *data++; | 142 | reg = *data++; |
167 | if ((ret = | 143 | ret = vpx3220_write(client, reg, *data++); |
168 | vpx3220_write(client, reg, *data++)) < 0) | 144 | if (ret < 0) |
169 | break; | 145 | break; |
170 | len -= 2; | 146 | len -= 2; |
171 | } | 147 | } |
@@ -173,10 +149,8 @@ vpx3220_write_block (struct i2c_client *client, | |||
173 | return ret; | 149 | return ret; |
174 | } | 150 | } |
175 | 151 | ||
176 | static int | 152 | static int vpx3220_write_fp_block(struct i2c_client *client, |
177 | vpx3220_write_fp_block (struct i2c_client *client, | 153 | const u16 *data, unsigned int len) |
178 | const u16 *data, | ||
179 | unsigned int len) | ||
180 | { | 154 | { |
181 | u8 reg; | 155 | u8 reg; |
182 | int ret = 0; | 156 | int ret = 0; |
@@ -285,25 +259,20 @@ static const unsigned short init_fp[] = { | |||
285 | 0x4b, 0x298, /* PLL gain */ | 259 | 0x4b, 0x298, /* PLL gain */ |
286 | }; | 260 | }; |
287 | 261 | ||
288 | static void | 262 | static void vpx3220_dump_i2c(struct i2c_client *client) |
289 | vpx3220_dump_i2c (struct i2c_client *client) | ||
290 | { | 263 | { |
291 | int len = sizeof(init_common); | 264 | int len = sizeof(init_common); |
292 | const unsigned char *data = init_common; | 265 | const unsigned char *data = init_common; |
293 | 266 | ||
294 | while (len > 1) { | 267 | while (len > 1) { |
295 | dprintk(1, | 268 | v4l_dbg(1, debug, client, "i2c reg 0x%02x data 0x%02x\n", |
296 | KERN_DEBUG "vpx3216b i2c reg 0x%02x data 0x%02x\n", | ||
297 | *data, vpx3220_read(client, *data)); | 269 | *data, vpx3220_read(client, *data)); |
298 | data += 2; | 270 | data += 2; |
299 | len -= 2; | 271 | len -= 2; |
300 | } | 272 | } |
301 | } | 273 | } |
302 | 274 | ||
303 | static int | 275 | static int vpx3220_command(struct i2c_client *client, unsigned cmd, void *arg) |
304 | vpx3220_command (struct i2c_client *client, | ||
305 | unsigned int cmd, | ||
306 | void *arg) | ||
307 | { | 276 | { |
308 | struct vpx3220 *decoder = i2c_get_clientdata(client); | 277 | struct vpx3220 *decoder = i2c_get_clientdata(client); |
309 | 278 | ||
@@ -315,7 +284,6 @@ vpx3220_command (struct i2c_client *client, | |||
315 | vpx3220_write_fp_block(client, init_fp, | 284 | vpx3220_write_fp_block(client, init_fp, |
316 | sizeof(init_fp) >> 1); | 285 | sizeof(init_fp) >> 1); |
317 | switch (decoder->norm) { | 286 | switch (decoder->norm) { |
318 | |||
319 | case VIDEO_MODE_NTSC: | 287 | case VIDEO_MODE_NTSC: |
320 | vpx3220_write_fp_block(client, init_ntsc, | 288 | vpx3220_write_fp_block(client, init_ntsc, |
321 | sizeof(init_ntsc) >> 1); | 289 | sizeof(init_ntsc) >> 1); |
@@ -334,21 +302,20 @@ vpx3220_command (struct i2c_client *client, | |||
334 | sizeof(init_pal) >> 1); | 302 | sizeof(init_pal) >> 1); |
335 | break; | 303 | break; |
336 | } | 304 | } |
337 | } | ||
338 | break; | 305 | break; |
306 | } | ||
339 | 307 | ||
340 | case DECODER_DUMP: | 308 | case DECODER_DUMP: |
341 | { | 309 | { |
342 | vpx3220_dump_i2c(client); | 310 | vpx3220_dump_i2c(client); |
343 | } | ||
344 | break; | 311 | break; |
312 | } | ||
345 | 313 | ||
346 | case DECODER_GET_CAPABILITIES: | 314 | case DECODER_GET_CAPABILITIES: |
347 | { | 315 | { |
348 | struct video_decoder_capability *cap = arg; | 316 | struct video_decoder_capability *cap = arg; |
349 | 317 | ||
350 | dprintk(1, KERN_DEBUG "%s: DECODER_GET_CAPABILITIES\n", | 318 | v4l_dbg(1, debug, client, "DECODER_GET_CAPABILITIES\n"); |
351 | I2C_NAME(client)); | ||
352 | 319 | ||
353 | cap->flags = VIDEO_DECODER_PAL | | 320 | cap->flags = VIDEO_DECODER_PAL | |
354 | VIDEO_DECODER_NTSC | | 321 | VIDEO_DECODER_NTSC | |
@@ -357,20 +324,18 @@ vpx3220_command (struct i2c_client *client, | |||
357 | VIDEO_DECODER_CCIR; | 324 | VIDEO_DECODER_CCIR; |
358 | cap->inputs = 3; | 325 | cap->inputs = 3; |
359 | cap->outputs = 1; | 326 | cap->outputs = 1; |
360 | } | ||
361 | break; | 327 | break; |
328 | } | ||
362 | 329 | ||
363 | case DECODER_GET_STATUS: | 330 | case DECODER_GET_STATUS: |
364 | { | 331 | { |
365 | int res = 0, status; | 332 | int res = 0, status; |
366 | 333 | ||
367 | dprintk(1, KERN_INFO "%s: DECODER_GET_STATUS\n", | 334 | v4l_dbg(1, debug, client, "DECODER_GET_STATUS\n"); |
368 | I2C_NAME(client)); | ||
369 | 335 | ||
370 | status = vpx3220_fp_read(client, 0x0f3); | 336 | status = vpx3220_fp_read(client, 0x0f3); |
371 | 337 | ||
372 | dprintk(1, KERN_INFO "%s: status: 0x%04x\n", I2C_NAME(client), | 338 | v4l_dbg(1, debug, client, "status: 0x%04x\n", status); |
373 | status); | ||
374 | 339 | ||
375 | if (status < 0) | 340 | if (status < 0) |
376 | return status; | 341 | return status; |
@@ -379,7 +344,6 @@ vpx3220_command (struct i2c_client *client, | |||
379 | res |= DECODER_STATUS_GOOD | DECODER_STATUS_COLOR; | 344 | res |= DECODER_STATUS_GOOD | DECODER_STATUS_COLOR; |
380 | 345 | ||
381 | switch (status & 0x18) { | 346 | switch (status & 0x18) { |
382 | |||
383 | case 0x00: | 347 | case 0x00: |
384 | case 0x10: | 348 | case 0x10: |
385 | case 0x14: | 349 | case 0x14: |
@@ -400,8 +364,8 @@ vpx3220_command (struct i2c_client *client, | |||
400 | } | 364 | } |
401 | 365 | ||
402 | *(int *) arg = res; | 366 | *(int *) arg = res; |
403 | } | ||
404 | break; | 367 | break; |
368 | } | ||
405 | 369 | ||
406 | case DECODER_SET_NORM: | 370 | case DECODER_SET_NORM: |
407 | { | 371 | { |
@@ -413,50 +377,43 @@ vpx3220_command (struct i2c_client *client, | |||
413 | choosen video norm */ | 377 | choosen video norm */ |
414 | temp_input = vpx3220_fp_read(client, 0xf2); | 378 | temp_input = vpx3220_fp_read(client, 0xf2); |
415 | 379 | ||
416 | dprintk(1, KERN_DEBUG "%s: DECODER_SET_NORM %d\n", | 380 | v4l_dbg(1, debug, client, "DECODER_SET_NORM %d\n", *iarg); |
417 | I2C_NAME(client), *iarg); | ||
418 | switch (*iarg) { | 381 | switch (*iarg) { |
419 | |||
420 | case VIDEO_MODE_NTSC: | 382 | case VIDEO_MODE_NTSC: |
421 | vpx3220_write_fp_block(client, init_ntsc, | 383 | vpx3220_write_fp_block(client, init_ntsc, |
422 | sizeof(init_ntsc) >> 1); | 384 | sizeof(init_ntsc) >> 1); |
423 | dprintk(1, KERN_INFO "%s: norm switched to NTSC\n", | 385 | v4l_dbg(1, debug, client, "norm switched to NTSC\n"); |
424 | I2C_NAME(client)); | ||
425 | break; | 386 | break; |
426 | 387 | ||
427 | case VIDEO_MODE_PAL: | 388 | case VIDEO_MODE_PAL: |
428 | vpx3220_write_fp_block(client, init_pal, | 389 | vpx3220_write_fp_block(client, init_pal, |
429 | sizeof(init_pal) >> 1); | 390 | sizeof(init_pal) >> 1); |
430 | dprintk(1, KERN_INFO "%s: norm switched to PAL\n", | 391 | v4l_dbg(1, debug, client, "norm switched to PAL\n"); |
431 | I2C_NAME(client)); | ||
432 | break; | 392 | break; |
433 | 393 | ||
434 | case VIDEO_MODE_SECAM: | 394 | case VIDEO_MODE_SECAM: |
435 | vpx3220_write_fp_block(client, init_secam, | 395 | vpx3220_write_fp_block(client, init_secam, |
436 | sizeof(init_secam) >> 1); | 396 | sizeof(init_secam) >> 1); |
437 | dprintk(1, KERN_INFO "%s: norm switched to SECAM\n", | 397 | v4l_dbg(1, debug, client, "norm switched to SECAM\n"); |
438 | I2C_NAME(client)); | ||
439 | break; | 398 | break; |
440 | 399 | ||
441 | case VIDEO_MODE_AUTO: | 400 | case VIDEO_MODE_AUTO: |
442 | /* FIXME This is only preliminary support */ | 401 | /* FIXME This is only preliminary support */ |
443 | data = vpx3220_fp_read(client, 0xf2) & 0x20; | 402 | data = vpx3220_fp_read(client, 0xf2) & 0x20; |
444 | vpx3220_fp_write(client, 0xf2, 0x00c0 | data); | 403 | vpx3220_fp_write(client, 0xf2, 0x00c0 | data); |
445 | dprintk(1, KERN_INFO "%s: norm switched to Auto\n", | 404 | v4l_dbg(1, debug, client, "norm switched to AUTO\n"); |
446 | I2C_NAME(client)); | ||
447 | break; | 405 | break; |
448 | 406 | ||
449 | default: | 407 | default: |
450 | return -EINVAL; | 408 | return -EINVAL; |
451 | |||
452 | } | 409 | } |
453 | decoder->norm = *iarg; | 410 | decoder->norm = *iarg; |
454 | 411 | ||
455 | /* And here we set the backed up video input again */ | 412 | /* And here we set the backed up video input again */ |
456 | vpx3220_fp_write(client, 0xf2, temp_input | 0x0010); | 413 | vpx3220_fp_write(client, 0xf2, temp_input | 0x0010); |
457 | udelay(10); | 414 | udelay(10); |
458 | } | ||
459 | break; | 415 | break; |
416 | } | ||
460 | 417 | ||
461 | case DECODER_SET_INPUT: | 418 | case DECODER_SET_INPUT: |
462 | { | 419 | { |
@@ -475,8 +432,7 @@ vpx3220_command (struct i2c_client *client, | |||
475 | if (*iarg < 0 || *iarg > 2) | 432 | if (*iarg < 0 || *iarg > 2) |
476 | return -EINVAL; | 433 | return -EINVAL; |
477 | 434 | ||
478 | dprintk(1, KERN_INFO "%s: input switched to %s\n", | 435 | v4l_dbg(1, debug, client, "input switched to %s\n", inputs[*iarg]); |
479 | I2C_NAME(client), inputs[*iarg]); | ||
480 | 436 | ||
481 | vpx3220_write(client, 0x33, input[*iarg][0]); | 437 | vpx3220_write(client, 0x33, input[*iarg][0]); |
482 | 438 | ||
@@ -488,8 +444,8 @@ vpx3220_command (struct i2c_client *client, | |||
488 | data | (input[*iarg][1] << 5) | 0x0010); | 444 | data | (input[*iarg][1] << 5) | 0x0010); |
489 | 445 | ||
490 | udelay(10); | 446 | udelay(10); |
491 | } | ||
492 | break; | 447 | break; |
448 | } | ||
493 | 449 | ||
494 | case DECODER_SET_OUTPUT: | 450 | case DECODER_SET_OUTPUT: |
495 | { | 451 | { |
@@ -499,19 +455,18 @@ vpx3220_command (struct i2c_client *client, | |||
499 | if (*iarg != 0) { | 455 | if (*iarg != 0) { |
500 | return -EINVAL; | 456 | return -EINVAL; |
501 | } | 457 | } |
502 | } | ||
503 | break; | 458 | break; |
459 | } | ||
504 | 460 | ||
505 | case DECODER_ENABLE_OUTPUT: | 461 | case DECODER_ENABLE_OUTPUT: |
506 | { | 462 | { |
507 | int *iarg = arg; | 463 | int *iarg = arg; |
508 | 464 | ||
509 | dprintk(1, KERN_DEBUG "%s: DECODER_ENABLE_OUTPUT %d\n", | 465 | v4l_dbg(1, debug, client, "DECODER_ENABLE_OUTPUT %d\n", *iarg); |
510 | I2C_NAME(client), *iarg); | ||
511 | 466 | ||
512 | vpx3220_write(client, 0xf2, (*iarg ? 0x1b : 0x00)); | 467 | vpx3220_write(client, 0xf2, (*iarg ? 0x1b : 0x00)); |
513 | } | ||
514 | break; | 468 | break; |
469 | } | ||
515 | 470 | ||
516 | case DECODER_SET_PICTURE: | 471 | case DECODER_SET_PICTURE: |
517 | { | 472 | { |
@@ -542,8 +497,8 @@ vpx3220_command (struct i2c_client *client, | |||
542 | vpx3220_fp_write(client, 0x1c, | 497 | vpx3220_fp_write(client, 0x1c, |
543 | ((decoder->hue - 32768) >> 6) & 0xFFF); | 498 | ((decoder->hue - 32768) >> 6) & 0xFFF); |
544 | } | 499 | } |
545 | } | ||
546 | break; | 500 | break; |
501 | } | ||
547 | 502 | ||
548 | default: | 503 | default: |
549 | return -EINVAL; | 504 | return -EINVAL; |
@@ -552,8 +507,7 @@ vpx3220_command (struct i2c_client *client, | |||
552 | return 0; | 507 | return 0; |
553 | } | 508 | } |
554 | 509 | ||
555 | static int | 510 | static int vpx3220_init_client(struct i2c_client *client) |
556 | vpx3220_init_client (struct i2c_client *client) | ||
557 | { | 511 | { |
558 | vpx3220_write_block(client, init_common, sizeof(init_common)); | 512 | vpx3220_write_block(client, init_common, sizeof(init_common)); |
559 | vpx3220_write_fp_block(client, init_fp, sizeof(init_fp) >> 1); | 513 | vpx3220_write_fp_block(client, init_fp, sizeof(init_fp) >> 1); |
@@ -567,115 +521,26 @@ vpx3220_init_client (struct i2c_client *client) | |||
567 | * Client management code | 521 | * Client management code |
568 | */ | 522 | */ |
569 | 523 | ||
570 | /* | 524 | static unsigned short normal_i2c[] = { 0x86 >> 1, 0x8e >> 1, I2C_CLIENT_END }; |
571 | * Generic i2c probe | ||
572 | * concerning the addresses: i2c wants 7 bit (without the r/w bit), so '>>1' | ||
573 | */ | ||
574 | static unsigned short normal_i2c[] = | ||
575 | { I2C_VPX3220 >> 1, (I2C_VPX3220 >> 1) + 4, | ||
576 | I2C_CLIENT_END | ||
577 | }; | ||
578 | |||
579 | static unsigned short ignore = I2C_CLIENT_END; | ||
580 | 525 | ||
581 | static struct i2c_client_address_data addr_data = { | 526 | I2C_CLIENT_INSMOD; |
582 | .normal_i2c = normal_i2c, | ||
583 | .probe = &ignore, | ||
584 | .ignore = &ignore, | ||
585 | }; | ||
586 | |||
587 | static struct i2c_driver vpx3220_i2c_driver; | ||
588 | |||
589 | static int | ||
590 | vpx3220_detach_client (struct i2c_client *client) | ||
591 | { | ||
592 | struct vpx3220 *decoder = i2c_get_clientdata(client); | ||
593 | int err; | ||
594 | |||
595 | err = i2c_detach_client(client); | ||
596 | if (err) { | ||
597 | return err; | ||
598 | } | ||
599 | |||
600 | kfree(decoder); | ||
601 | kfree(client); | ||
602 | |||
603 | return 0; | ||
604 | } | ||
605 | 527 | ||
606 | static int | 528 | static int vpx3220_probe(struct i2c_client *client, |
607 | vpx3220_detect_client (struct i2c_adapter *adapter, | 529 | const struct i2c_device_id *id) |
608 | int address, | ||
609 | int kind) | ||
610 | { | 530 | { |
611 | int err; | ||
612 | struct i2c_client *client; | ||
613 | struct vpx3220 *decoder; | 531 | struct vpx3220 *decoder; |
614 | 532 | const char *name = NULL; | |
615 | dprintk(1, VPX3220_DEBUG "%s\n", __func__); | 533 | u8 ver; |
534 | u16 pn; | ||
616 | 535 | ||
617 | /* Check if the adapter supports the needed features */ | 536 | /* Check if the adapter supports the needed features */ |
618 | if (!i2c_check_functionality | 537 | if (!i2c_check_functionality(client->adapter, |
619 | (adapter, I2C_FUNC_SMBUS_BYTE_DATA | I2C_FUNC_SMBUS_WORD_DATA)) | 538 | I2C_FUNC_SMBUS_BYTE_DATA | I2C_FUNC_SMBUS_WORD_DATA)) |
620 | return 0; | 539 | return -ENODEV; |
621 | |||
622 | client = kzalloc(sizeof(struct i2c_client), GFP_KERNEL); | ||
623 | if (client == NULL) { | ||
624 | return -ENOMEM; | ||
625 | } | ||
626 | |||
627 | client->addr = address; | ||
628 | client->adapter = adapter; | ||
629 | client->driver = &vpx3220_i2c_driver; | ||
630 | |||
631 | /* Check for manufacture ID and part number */ | ||
632 | if (kind < 0) { | ||
633 | u8 id; | ||
634 | u16 pn; | ||
635 | |||
636 | id = vpx3220_read(client, 0x00); | ||
637 | if (id != 0xec) { | ||
638 | dprintk(1, | ||
639 | KERN_INFO | ||
640 | "vpx3220_attach: Wrong manufacturer ID (0x%02x)\n", | ||
641 | id); | ||
642 | kfree(client); | ||
643 | return 0; | ||
644 | } | ||
645 | |||
646 | pn = (vpx3220_read(client, 0x02) << 8) + | ||
647 | vpx3220_read(client, 0x01); | ||
648 | switch (pn) { | ||
649 | case 0x4680: | ||
650 | strlcpy(I2C_NAME(client), "vpx3220a", | ||
651 | sizeof(I2C_NAME(client))); | ||
652 | break; | ||
653 | case 0x4260: | ||
654 | strlcpy(I2C_NAME(client), "vpx3216b", | ||
655 | sizeof(I2C_NAME(client))); | ||
656 | break; | ||
657 | case 0x4280: | ||
658 | strlcpy(I2C_NAME(client), "vpx3214c", | ||
659 | sizeof(I2C_NAME(client))); | ||
660 | break; | ||
661 | default: | ||
662 | dprintk(1, | ||
663 | KERN_INFO | ||
664 | "%s: Wrong part number (0x%04x)\n", | ||
665 | __func__, pn); | ||
666 | kfree(client); | ||
667 | return 0; | ||
668 | } | ||
669 | } else { | ||
670 | strlcpy(I2C_NAME(client), "forced vpx32xx", | ||
671 | sizeof(I2C_NAME(client))); | ||
672 | } | ||
673 | 540 | ||
674 | decoder = kzalloc(sizeof(struct vpx3220), GFP_KERNEL); | 541 | decoder = kzalloc(sizeof(struct vpx3220), GFP_KERNEL); |
675 | if (decoder == NULL) { | 542 | if (decoder == NULL) |
676 | kfree(client); | ||
677 | return -ENOMEM; | 543 | return -ENOMEM; |
678 | } | ||
679 | decoder->norm = VIDEO_MODE_PAL; | 544 | decoder->norm = VIDEO_MODE_PAL; |
680 | decoder->input = 0; | 545 | decoder->input = 0; |
681 | decoder->enable = 1; | 546 | decoder->enable = 1; |
@@ -685,63 +550,52 @@ vpx3220_detect_client (struct i2c_adapter *adapter, | |||
685 | decoder->sat = 32768; | 550 | decoder->sat = 32768; |
686 | i2c_set_clientdata(client, decoder); | 551 | i2c_set_clientdata(client, decoder); |
687 | 552 | ||
688 | err = i2c_attach_client(client); | 553 | ver = i2c_smbus_read_byte_data(client, 0x00); |
689 | if (err) { | 554 | pn = (i2c_smbus_read_byte_data(client, 0x02) << 8) + |
690 | kfree(client); | 555 | i2c_smbus_read_byte_data(client, 0x01); |
691 | kfree(decoder); | 556 | if (ver == 0xec) { |
692 | return err; | 557 | switch (pn) { |
558 | case 0x4680: | ||
559 | name = "vpx3220a"; | ||
560 | break; | ||
561 | case 0x4260: | ||
562 | name = "vpx3216b"; | ||
563 | break; | ||
564 | case 0x4280: | ||
565 | name = "vpx3214c"; | ||
566 | break; | ||
567 | } | ||
693 | } | 568 | } |
694 | 569 | if (name) | |
695 | dprintk(1, KERN_INFO "%s: vpx32xx client found at address 0x%02x\n", | 570 | v4l_info(client, "%s found @ 0x%x (%s)\n", name, |
696 | I2C_NAME(client), client->addr << 1); | 571 | client->addr << 1, client->adapter->name); |
572 | else | ||
573 | v4l_info(client, "chip (%02x:%04x) found @ 0x%x (%s)\n", | ||
574 | ver, pn, client->addr << 1, client->adapter->name); | ||
697 | 575 | ||
698 | vpx3220_init_client(client); | 576 | vpx3220_init_client(client); |
699 | |||
700 | return 0; | 577 | return 0; |
701 | } | 578 | } |
702 | 579 | ||
703 | static int | 580 | static int vpx3220_remove(struct i2c_client *client) |
704 | vpx3220_attach_adapter (struct i2c_adapter *adapter) | ||
705 | { | 581 | { |
706 | int ret; | 582 | kfree(i2c_get_clientdata(client)); |
707 | 583 | return 0; | |
708 | ret = i2c_probe(adapter, &addr_data, &vpx3220_detect_client); | ||
709 | dprintk(1, VPX3220_DEBUG "%s: i2c_probe returned %d\n", | ||
710 | __func__, ret); | ||
711 | return ret; | ||
712 | } | 584 | } |
713 | 585 | ||
714 | /* ----------------------------------------------------------------------- | 586 | static const struct i2c_device_id vpx3220_id[] = { |
715 | * Driver initialization and cleanup code | 587 | { "vpx3220a", 0 }, |
716 | */ | 588 | { "vpx3216b", 0 }, |
717 | 589 | { "vpx3214c", 0 }, | |
718 | static struct i2c_driver vpx3220_i2c_driver = { | 590 | { } |
719 | .driver = { | 591 | }; |
720 | .name = "vpx3220", | 592 | MODULE_DEVICE_TABLE(i2c, vpx3220_id); |
721 | }, | ||
722 | |||
723 | .id = I2C_DRIVERID_VPX3220, | ||
724 | 593 | ||
725 | .attach_adapter = vpx3220_attach_adapter, | 594 | static struct v4l2_i2c_driver_data v4l2_i2c_data = { |
726 | .detach_client = vpx3220_detach_client, | 595 | .name = "vpx3220", |
596 | .driverid = I2C_DRIVERID_VPX3220, | ||
727 | .command = vpx3220_command, | 597 | .command = vpx3220_command, |
598 | .probe = vpx3220_probe, | ||
599 | .remove = vpx3220_remove, | ||
600 | .id_table = vpx3220_id, | ||
728 | }; | 601 | }; |
729 | |||
730 | static int __init | ||
731 | vpx3220_init (void) | ||
732 | { | ||
733 | return i2c_add_driver(&vpx3220_i2c_driver); | ||
734 | } | ||
735 | |||
736 | static void __exit | ||
737 | vpx3220_cleanup (void) | ||
738 | { | ||
739 | i2c_del_driver(&vpx3220_i2c_driver); | ||
740 | } | ||
741 | |||
742 | module_init(vpx3220_init); | ||
743 | module_exit(vpx3220_cleanup); | ||
744 | |||
745 | MODULE_DESCRIPTION("vpx3220a/vpx3216b/vpx3214c video decoder driver"); | ||
746 | MODULE_AUTHOR("Laurent Pinchart"); | ||
747 | MODULE_LICENSE("GPL"); | ||