aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/media/video
diff options
context:
space:
mode:
authorHans Verkuil <hverkuil@xs4all.nl>2009-02-19 12:36:53 -0500
committerMauro Carvalho Chehab <mchehab@redhat.com>2009-03-30 11:42:58 -0400
commit7e5eaadcbd8894b25f715aa03cb632d0df63269c (patch)
tree837686b574b31204df05c4c972a222ecc7f1f433 /drivers/media/video
parent780d8e1552efb61122c269382b3fa8987aca3e89 (diff)
V4L/DVB (10726): vpx3220: convert to v4l2_subdev.
Signed-off-by: Hans Verkuil <hverkuil@xs4all.nl> Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com>
Diffstat (limited to 'drivers/media/video')
-rw-r--r--drivers/media/video/vpx3220.c497
1 files changed, 266 insertions, 231 deletions
diff --git a/drivers/media/video/vpx3220.c b/drivers/media/video/vpx3220.c
index cd2064e7733..476a204dcf9 100644
--- a/drivers/media/video/vpx3220.c
+++ b/drivers/media/video/vpx3220.c
@@ -24,11 +24,10 @@
24#include <linux/types.h> 24#include <linux/types.h>
25#include <asm/uaccess.h> 25#include <asm/uaccess.h>
26#include <linux/i2c.h> 26#include <linux/i2c.h>
27#include <media/v4l2-common.h>
28#include <media/v4l2-i2c-drv-legacy.h>
29#include <linux/videodev.h>
30#include <linux/videodev2.h> 27#include <linux/videodev2.h>
31#include <linux/video_decoder.h> 28#include <media/v4l2-device.h>
29#include <media/v4l2-chip-ident.h>
30#include <media/v4l2-i2c-drv-legacy.h>
32 31
33MODULE_DESCRIPTION("vpx3220a/vpx3216b/vpx3214c video decoder driver"); 32MODULE_DESCRIPTION("vpx3220a/vpx3216b/vpx3214c video decoder driver");
34MODULE_AUTHOR("Laurent Pinchart"); 33MODULE_AUTHOR("Laurent Pinchart");
@@ -38,14 +37,20 @@ static int debug;
38module_param(debug, int, 0); 37module_param(debug, int, 0);
39MODULE_PARM_DESC(debug, "Debug level (0-1)"); 38MODULE_PARM_DESC(debug, "Debug level (0-1)");
40 39
40static unsigned short normal_i2c[] = { 0x86 >> 1, 0x8e >> 1, I2C_CLIENT_END };
41
42I2C_CLIENT_INSMOD;
43
41#define VPX_TIMEOUT_COUNT 10 44#define VPX_TIMEOUT_COUNT 10
42 45
43/* ----------------------------------------------------------------------- */ 46/* ----------------------------------------------------------------------- */
44 47
45struct vpx3220 { 48struct vpx3220 {
49 struct v4l2_subdev sd;
46 unsigned char reg[255]; 50 unsigned char reg[255];
47 51
48 v4l2_std_id norm; 52 v4l2_std_id norm;
53 int ident;
49 int input; 54 int input;
50 int enable; 55 int enable;
51 int bright; 56 int bright;
@@ -54,30 +59,38 @@ struct vpx3220 {
54 int sat; 59 int sat;
55}; 60};
56 61
62static inline struct vpx3220 *to_vpx3220(struct v4l2_subdev *sd)
63{
64 return container_of(sd, struct vpx3220, sd);
65}
66
57static char *inputs[] = { "internal", "composite", "svideo" }; 67static char *inputs[] = { "internal", "composite", "svideo" };
58 68
59/* ----------------------------------------------------------------------- */ 69/* ----------------------------------------------------------------------- */
60 70
61static inline int vpx3220_write(struct i2c_client *client, u8 reg, u8 value) 71static inline int vpx3220_write(struct v4l2_subdev *sd, u8 reg, u8 value)
62{ 72{
73 struct i2c_client *client = v4l2_get_subdevdata(sd);
63 struct vpx3220 *decoder = i2c_get_clientdata(client); 74 struct vpx3220 *decoder = i2c_get_clientdata(client);
64 75
65 decoder->reg[reg] = value; 76 decoder->reg[reg] = value;
66 return i2c_smbus_write_byte_data(client, reg, value); 77 return i2c_smbus_write_byte_data(client, reg, value);
67} 78}
68 79
69static inline int vpx3220_read(struct i2c_client *client, u8 reg) 80static inline int vpx3220_read(struct v4l2_subdev *sd, u8 reg)
70{ 81{
82 struct i2c_client *client = v4l2_get_subdevdata(sd);
83
71 return i2c_smbus_read_byte_data(client, reg); 84 return i2c_smbus_read_byte_data(client, reg);
72} 85}
73 86
74static int vpx3220_fp_status(struct i2c_client *client) 87static int vpx3220_fp_status(struct v4l2_subdev *sd)
75{ 88{
76 unsigned char status; 89 unsigned char status;
77 unsigned int i; 90 unsigned int i;
78 91
79 for (i = 0; i < VPX_TIMEOUT_COUNT; i++) { 92 for (i = 0; i < VPX_TIMEOUT_COUNT; i++) {
80 status = vpx3220_read(client, 0x29); 93 status = vpx3220_read(sd, 0x29);
81 94
82 if (!(status & 4)) 95 if (!(status & 4))
83 return 0; 96 return 0;
@@ -91,57 +104,60 @@ static int vpx3220_fp_status(struct i2c_client *client)
91 return -1; 104 return -1;
92} 105}
93 106
94static int vpx3220_fp_write(struct i2c_client *client, u8 fpaddr, u16 data) 107static int vpx3220_fp_write(struct v4l2_subdev *sd, u8 fpaddr, u16 data)
95{ 108{
109 struct i2c_client *client = v4l2_get_subdevdata(sd);
110
96 /* Write the 16-bit address to the FPWR register */ 111 /* Write the 16-bit address to the FPWR register */
97 if (i2c_smbus_write_word_data(client, 0x27, swab16(fpaddr)) == -1) { 112 if (i2c_smbus_write_word_data(client, 0x27, swab16(fpaddr)) == -1) {
98 v4l_dbg(1, debug, client, "%s: failed\n", __func__); 113 v4l2_dbg(1, debug, sd, "%s: failed\n", __func__);
99 return -1; 114 return -1;
100 } 115 }
101 116
102 if (vpx3220_fp_status(client) < 0) 117 if (vpx3220_fp_status(sd) < 0)
103 return -1; 118 return -1;
104 119
105 /* Write the 16-bit data to the FPDAT register */ 120 /* Write the 16-bit data to the FPDAT register */
106 if (i2c_smbus_write_word_data(client, 0x28, swab16(data)) == -1) { 121 if (i2c_smbus_write_word_data(client, 0x28, swab16(data)) == -1) {
107 v4l_dbg(1, debug, client, "%s: failed\n", __func__); 122 v4l2_dbg(1, debug, sd, "%s: failed\n", __func__);
108 return -1; 123 return -1;
109 } 124 }
110 125
111 return 0; 126 return 0;
112} 127}
113 128
114static u16 vpx3220_fp_read(struct i2c_client *client, u16 fpaddr) 129static u16 vpx3220_fp_read(struct v4l2_subdev *sd, u16 fpaddr)
115{ 130{
131 struct i2c_client *client = v4l2_get_subdevdata(sd);
116 s16 data; 132 s16 data;
117 133
118 /* Write the 16-bit address to the FPRD register */ 134 /* Write the 16-bit address to the FPRD register */
119 if (i2c_smbus_write_word_data(client, 0x26, swab16(fpaddr)) == -1) { 135 if (i2c_smbus_write_word_data(client, 0x26, swab16(fpaddr)) == -1) {
120 v4l_dbg(1, debug, client, "%s: failed\n", __func__); 136 v4l2_dbg(1, debug, sd, "%s: failed\n", __func__);
121 return -1; 137 return -1;
122 } 138 }
123 139
124 if (vpx3220_fp_status(client) < 0) 140 if (vpx3220_fp_status(sd) < 0)
125 return -1; 141 return -1;
126 142
127 /* Read the 16-bit data from the FPDAT register */ 143 /* Read the 16-bit data from the FPDAT register */
128 data = i2c_smbus_read_word_data(client, 0x28); 144 data = i2c_smbus_read_word_data(client, 0x28);
129 if (data == -1) { 145 if (data == -1) {
130 v4l_dbg(1, debug, client, "%s: failed\n", __func__); 146 v4l2_dbg(1, debug, sd, "%s: failed\n", __func__);
131 return -1; 147 return -1;
132 } 148 }
133 149
134 return swab16(data); 150 return swab16(data);
135} 151}
136 152
137static int vpx3220_write_block(struct i2c_client *client, const u8 *data, unsigned int len) 153static int vpx3220_write_block(struct v4l2_subdev *sd, const u8 *data, unsigned int len)
138{ 154{
139 u8 reg; 155 u8 reg;
140 int ret = -1; 156 int ret = -1;
141 157
142 while (len >= 2) { 158 while (len >= 2) {
143 reg = *data++; 159 reg = *data++;
144 ret = vpx3220_write(client, reg, *data++); 160 ret = vpx3220_write(sd, reg, *data++);
145 if (ret < 0) 161 if (ret < 0)
146 break; 162 break;
147 len -= 2; 163 len -= 2;
@@ -150,7 +166,7 @@ static int vpx3220_write_block(struct i2c_client *client, const u8 *data, unsign
150 return ret; 166 return ret;
151} 167}
152 168
153static int vpx3220_write_fp_block(struct i2c_client *client, 169static int vpx3220_write_fp_block(struct v4l2_subdev *sd,
154 const u16 *data, unsigned int len) 170 const u16 *data, unsigned int len)
155{ 171{
156 u8 reg; 172 u8 reg;
@@ -158,7 +174,7 @@ static int vpx3220_write_fp_block(struct i2c_client *client,
158 174
159 while (len > 1) { 175 while (len > 1) {
160 reg = *data++; 176 reg = *data++;
161 ret |= vpx3220_fp_write(client, reg, *data++); 177 ret |= vpx3220_fp_write(sd, reg, *data++);
162 len -= 2; 178 len -= 2;
163 } 179 }
164 180
@@ -261,272 +277,281 @@ static const unsigned short init_fp[] = {
261}; 277};
262 278
263 279
264static int vpx3220_command(struct i2c_client *client, unsigned cmd, void *arg) 280static int vpx3220_init(struct v4l2_subdev *sd, u32 val)
265{ 281{
266 struct vpx3220 *decoder = i2c_get_clientdata(client); 282 struct vpx3220 *decoder = to_vpx3220(sd);
267 283
268 switch (cmd) { 284 vpx3220_write_block(sd, init_common, sizeof(init_common));
269 case VIDIOC_INT_INIT: 285 vpx3220_write_fp_block(sd, init_fp, sizeof(init_fp) >> 1);
270 { 286 if (decoder->norm & V4L2_STD_NTSC)
271 vpx3220_write_block(client, init_common, 287 vpx3220_write_fp_block(sd, init_ntsc, sizeof(init_ntsc) >> 1);
272 sizeof(init_common)); 288 else if (decoder->norm & V4L2_STD_PAL)
273 vpx3220_write_fp_block(client, init_fp, 289 vpx3220_write_fp_block(sd, init_pal, sizeof(init_pal) >> 1);
274 sizeof(init_fp) >> 1); 290 else if (decoder->norm & V4L2_STD_SECAM)
275 if (decoder->norm & V4L2_STD_NTSC) { 291 vpx3220_write_fp_block(sd, init_secam, sizeof(init_secam) >> 1);
276 vpx3220_write_fp_block(client, init_ntsc, 292 else
277 sizeof(init_ntsc) >> 1); 293 vpx3220_write_fp_block(sd, init_pal, sizeof(init_pal) >> 1);
278 } else if (decoder->norm & V4L2_STD_PAL) { 294 return 0;
279 vpx3220_write_fp_block(client, init_pal, 295}
280 sizeof(init_pal) >> 1);
281 } else if (decoder->norm & V4L2_STD_SECAM) {
282 vpx3220_write_fp_block(client, init_secam,
283 sizeof(init_secam) >> 1);
284 } else {
285 vpx3220_write_fp_block(client, init_pal,
286 sizeof(init_pal) >> 1);
287 }
288 break;
289 }
290 296
291 case VIDIOC_QUERYSTD: 297static int vpx3220_status(struct v4l2_subdev *sd, u32 *pstatus, v4l2_std_id *pstd)
292 case VIDIOC_INT_G_INPUT_STATUS: 298{
293 { 299 int res = V4L2_IN_ST_NO_SIGNAL, status;
294 int res = V4L2_IN_ST_NO_SIGNAL, status; 300 v4l2_std_id std = 0;
295 v4l2_std_id std = 0;
296 301
297 v4l_dbg(1, debug, client, "VIDIOC_QUERYSTD/VIDIOC_INT_G_INPUT_STATUS\n"); 302 v4l2_dbg(1, debug, sd, "VIDIOC_QUERYSTD/VIDIOC_INT_G_INPUT_STATUS\n");
298 303
299 status = vpx3220_fp_read(client, 0x0f3); 304 status = vpx3220_fp_read(sd, 0x0f3);
300 305
301 v4l_dbg(1, debug, client, "status: 0x%04x\n", status); 306 v4l2_dbg(1, debug, sd, "status: 0x%04x\n", status);
302 307
303 if (status < 0) 308 if (status < 0)
304 return status; 309 return status;
305 310
306 if ((status & 0x20) == 0) { 311 if ((status & 0x20) == 0) {
307 res = 0; 312 res = 0;
308 313
309 switch (status & 0x18) { 314 switch (status & 0x18) {
310 case 0x00: 315 case 0x00:
311 case 0x10: 316 case 0x10:
312 case 0x14: 317 case 0x14:
313 case 0x18: 318 case 0x18:
314 std = V4L2_STD_PAL; 319 std = V4L2_STD_PAL;
315 break; 320 break;
316 321
317 case 0x08: 322 case 0x08:
318 std = V4L2_STD_SECAM; 323 std = V4L2_STD_SECAM;
319 break; 324 break;
320 325
321 case 0x04: 326 case 0x04:
322 case 0x0c: 327 case 0x0c:
323 case 0x1c: 328 case 0x1c:
324 std = V4L2_STD_NTSC; 329 std = V4L2_STD_NTSC;
325 break; 330 break;
326 }
327 } 331 }
328
329 if (cmd == VIDIOC_QUERYSTD)
330 *(v4l2_std_id *)arg = std;
331 else
332 *(int *)arg = res;
333 break;
334 } 332 }
333 if (pstd)
334 *pstd = std;
335 if (pstatus)
336 *pstatus = status;
337 return 0;
338}
335 339
336 case VIDIOC_S_STD: 340static int vpx3220_querystd(struct v4l2_subdev *sd, v4l2_std_id *std)
337 { 341{
338 v4l2_std_id *iarg = arg; 342 return vpx3220_status(sd, NULL, std);
339 int temp_input; 343}
340
341 /* Here we back up the input selection because it gets
342 overwritten when we fill the registers with the
343 choosen video norm */
344 temp_input = vpx3220_fp_read(client, 0xf2);
345
346 v4l_dbg(1, debug, client, "VIDIOC_S_STD %llx\n", *iarg);
347 if (*iarg & V4L2_STD_NTSC) {
348 vpx3220_write_fp_block(client, init_ntsc,
349 sizeof(init_ntsc) >> 1);
350 v4l_dbg(1, debug, client, "norm switched to NTSC\n");
351 } else if (*iarg & V4L2_STD_PAL) {
352 vpx3220_write_fp_block(client, init_pal,
353 sizeof(init_pal) >> 1);
354 v4l_dbg(1, debug, client, "norm switched to PAL\n");
355 } else if (*iarg & V4L2_STD_SECAM) {
356 vpx3220_write_fp_block(client, init_secam,
357 sizeof(init_secam) >> 1);
358 v4l_dbg(1, debug, client, "norm switched to SECAM\n");
359 } else {
360 return -EINVAL;
361 }
362 344
363 decoder->norm = *iarg; 345static int vpx3220_g_input_status(struct v4l2_subdev *sd, u32 *status)
346{
347 return vpx3220_status(sd, status, NULL);
348}
364 349
365 /* And here we set the backed up video input again */ 350static int vpx3220_s_std(struct v4l2_subdev *sd, v4l2_std_id std)
366 vpx3220_fp_write(client, 0xf2, temp_input | 0x0010); 351{
367 udelay(10); 352 struct vpx3220 *decoder = to_vpx3220(sd);
368 break; 353 int temp_input;
354
355 /* Here we back up the input selection because it gets
356 overwritten when we fill the registers with the
357 choosen video norm */
358 temp_input = vpx3220_fp_read(sd, 0xf2);
359
360 v4l2_dbg(1, debug, sd, "VIDIOC_S_STD %llx\n", std);
361 if (std & V4L2_STD_NTSC) {
362 vpx3220_write_fp_block(sd, init_ntsc, sizeof(init_ntsc) >> 1);
363 v4l2_dbg(1, debug, sd, "norm switched to NTSC\n");
364 } else if (std & V4L2_STD_PAL) {
365 vpx3220_write_fp_block(sd, init_pal, sizeof(init_pal) >> 1);
366 v4l2_dbg(1, debug, sd, "norm switched to PAL\n");
367 } else if (std & V4L2_STD_SECAM) {
368 vpx3220_write_fp_block(sd, init_secam, sizeof(init_secam) >> 1);
369 v4l2_dbg(1, debug, sd, "norm switched to SECAM\n");
370 } else {
371 return -EINVAL;
369 } 372 }
370 373
371 case VIDIOC_INT_S_VIDEO_ROUTING: 374 decoder->norm = std;
372 {
373 struct v4l2_routing *route = arg;
374 int data;
375 375
376 /* RJ: *iarg = 0: ST8 (PCTV) input 376 /* And here we set the backed up video input again */
377 *iarg = 1: COMPOSITE input 377 vpx3220_fp_write(sd, 0xf2, temp_input | 0x0010);
378 *iarg = 2: SVHS input */ 378 udelay(10);
379 return 0;
380}
379 381
380 const int input[3][2] = { 382static int vpx3220_s_routing(struct v4l2_subdev *sd, const struct v4l2_routing *route)
381 {0x0c, 0}, 383{
382 {0x0d, 0}, 384 int data;
383 {0x0e, 1}
384 };
385 385
386 if (route->input < 0 || route->input > 2) 386 /* RJ: route->input = 0: ST8 (PCTV) input
387 return -EINVAL; 387 route->input = 1: COMPOSITE input
388 route->input = 2: SVHS input */
388 389
389 v4l_dbg(1, debug, client, "input switched to %s\n", inputs[route->input]); 390 const int input[3][2] = {
391 {0x0c, 0},
392 {0x0d, 0},
393 {0x0e, 1}
394 };
390 395
391 vpx3220_write(client, 0x33, input[route->input][0]); 396 if (route->input < 0 || route->input > 2)
397 return -EINVAL;
392 398
393 data = vpx3220_fp_read(client, 0xf2) & ~(0x0020); 399 v4l2_dbg(1, debug, sd, "input switched to %s\n", inputs[route->input]);
394 if (data < 0)
395 return data;
396 /* 0x0010 is required to latch the setting */
397 vpx3220_fp_write(client, 0xf2,
398 data | (input[route->input][1] << 5) | 0x0010);
399 400
400 udelay(10); 401 vpx3220_write(sd, 0x33, input[route->input][0]);
401 break;
402 }
403 402
404 case VIDIOC_STREAMON: 403 data = vpx3220_fp_read(sd, 0xf2) & ~(0x0020);
405 case VIDIOC_STREAMOFF: 404 if (data < 0)
406 { 405 return data;
407 int on = cmd == VIDIOC_STREAMON; 406 /* 0x0010 is required to latch the setting */
408 v4l_dbg(1, debug, client, "VIDIOC_STREAM%s\n", on ? "ON" : "OFF"); 407 vpx3220_fp_write(sd, 0xf2,
408 data | (input[route->input][1] << 5) | 0x0010);
409 409
410 vpx3220_write(client, 0xf2, (on ? 0x1b : 0x00)); 410 udelay(10);
411 break; 411 return 0;
412 } 412}
413 413
414 case VIDIOC_QUERYCTRL: 414static int vpx3220_s_stream(struct v4l2_subdev *sd, int enable)
415 { 415{
416 struct v4l2_queryctrl *qc = arg; 416 v4l2_dbg(1, debug, sd, "VIDIOC_STREAM%s\n", enable ? "ON" : "OFF");
417 417
418 switch (qc->id) { 418 vpx3220_write(sd, 0xf2, (enable ? 0x1b : 0x00));
419 case V4L2_CID_BRIGHTNESS: 419 return 0;
420 v4l2_ctrl_query_fill(qc, -128, 127, 1, 0); 420}
421 break;
422 421
423 case V4L2_CID_CONTRAST: 422static int vpx3220_queryctrl(struct v4l2_subdev *sd, struct v4l2_queryctrl *qc)
424 v4l2_ctrl_query_fill(qc, 0, 63, 1, 32); 423{
425 break; 424 switch (qc->id) {
425 case V4L2_CID_BRIGHTNESS:
426 v4l2_ctrl_query_fill(qc, -128, 127, 1, 0);
427 break;
426 428
427 case V4L2_CID_SATURATION: 429 case V4L2_CID_CONTRAST:
428 v4l2_ctrl_query_fill(qc, 0, 4095, 1, 2048); 430 v4l2_ctrl_query_fill(qc, 0, 63, 1, 32);
429 break; 431 break;
430 432
431 case V4L2_CID_HUE: 433 case V4L2_CID_SATURATION:
432 v4l2_ctrl_query_fill(qc, -512, 511, 1, 0); 434 v4l2_ctrl_query_fill(qc, 0, 4095, 1, 2048);
433 break; 435 break;
434 436
435 default: 437 case V4L2_CID_HUE:
436 return -EINVAL; 438 v4l2_ctrl_query_fill(qc, -512, 511, 1, 0);
437 }
438 break; 439 break;
440
441 default:
442 return -EINVAL;
439 } 443 }
444 return 0;
445}
440 446
441 case VIDIOC_G_CTRL: 447static int vpx3220_g_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl)
442 { 448{
443 struct v4l2_control *ctrl = arg; 449 struct vpx3220 *decoder = to_vpx3220(sd);
444 450
445 switch (ctrl->id) { 451 switch (ctrl->id) {
446 case V4L2_CID_BRIGHTNESS: 452 case V4L2_CID_BRIGHTNESS:
447 ctrl->value = decoder->bright; 453 ctrl->value = decoder->bright;
448 break; 454 break;
449 case V4L2_CID_CONTRAST: 455 case V4L2_CID_CONTRAST:
450 ctrl->value = decoder->contrast; 456 ctrl->value = decoder->contrast;
451 break;
452 case V4L2_CID_SATURATION:
453 ctrl->value = decoder->sat;
454 break;
455 case V4L2_CID_HUE:
456 ctrl->value = decoder->hue;
457 break;
458 default:
459 return -EINVAL;
460 }
461 break; 457 break;
458 case V4L2_CID_SATURATION:
459 ctrl->value = decoder->sat;
460 break;
461 case V4L2_CID_HUE:
462 ctrl->value = decoder->hue;
463 break;
464 default:
465 return -EINVAL;
462 } 466 }
467 return 0;
468}
463 469
464 case VIDIOC_S_CTRL: 470static int vpx3220_s_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl)
465 { 471{
466 struct v4l2_control *ctrl = arg; 472 struct vpx3220 *decoder = to_vpx3220(sd);
467 473
468 switch (ctrl->id) { 474 switch (ctrl->id) {
469 case V4L2_CID_BRIGHTNESS: 475 case V4L2_CID_BRIGHTNESS:
470 if (decoder->bright != ctrl->value) { 476 if (decoder->bright != ctrl->value) {
471 decoder->bright = ctrl->value; 477 decoder->bright = ctrl->value;
472 vpx3220_write(client, 0xe6, decoder->bright); 478 vpx3220_write(sd, 0xe6, decoder->bright);
473 } 479 }
474 break; 480 break;
475 case V4L2_CID_CONTRAST: 481 case V4L2_CID_CONTRAST:
476 if (decoder->contrast != ctrl->value) { 482 if (decoder->contrast != ctrl->value) {
477 /* Bit 7 and 8 is for noise shaping */ 483 /* Bit 7 and 8 is for noise shaping */
478 decoder->contrast = ctrl->value; 484 decoder->contrast = ctrl->value;
479 vpx3220_write(client, 0xe7, 485 vpx3220_write(sd, 0xe7, decoder->contrast + 192);
480 decoder->contrast + 192); 486 }
481 } 487 break;
482 break; 488 case V4L2_CID_SATURATION:
483 case V4L2_CID_SATURATION: 489 if (decoder->sat != ctrl->value) {
484 if (decoder->sat != ctrl->value) { 490 decoder->sat = ctrl->value;
485 decoder->sat = ctrl->value; 491 vpx3220_fp_write(sd, 0xa0, decoder->sat);
486 vpx3220_fp_write(client, 0xa0, decoder->sat); 492 }
487 } 493 break;
488 break; 494 case V4L2_CID_HUE:
489 case V4L2_CID_HUE: 495 if (decoder->hue != ctrl->value) {
490 if (decoder->hue != ctrl->value) { 496 decoder->hue = ctrl->value;
491 decoder->hue = ctrl->value; 497 vpx3220_fp_write(sd, 0x1c, decoder->hue);
492 vpx3220_fp_write(client, 0x1c, decoder->hue);
493 }
494 break;
495 default:
496 return -EINVAL;
497 } 498 }
498 break; 499 break;
499 }
500
501 default: 500 default:
502 return -EINVAL; 501 return -EINVAL;
503 } 502 }
504
505 return 0; 503 return 0;
506} 504}
507 505
508static int vpx3220_init_client(struct i2c_client *client) 506static int vpx3220_g_chip_ident(struct v4l2_subdev *sd, struct v4l2_dbg_chip_ident *chip)
509{ 507{
510 vpx3220_write_block(client, init_common, sizeof(init_common)); 508 struct vpx3220 *decoder = to_vpx3220(sd);
511 vpx3220_write_fp_block(client, init_fp, sizeof(init_fp) >> 1); 509 struct i2c_client *client = v4l2_get_subdevdata(sd);
512 /* Default to PAL */
513 vpx3220_write_fp_block(client, init_pal, sizeof(init_pal) >> 1);
514 510
515 return 0; 511 return v4l2_chip_ident_i2c_client(client, chip, decoder->ident, 0);
516} 512}
517 513
514static int vpx3220_command(struct i2c_client *client, unsigned cmd, void *arg)
515{
516 return v4l2_subdev_command(i2c_get_clientdata(client), cmd, arg);
517}
518
519/* ----------------------------------------------------------------------- */
520
521static const struct v4l2_subdev_core_ops vpx3220_core_ops = {
522 .g_chip_ident = vpx3220_g_chip_ident,
523 .init = vpx3220_init,
524 .g_ctrl = vpx3220_g_ctrl,
525 .s_ctrl = vpx3220_s_ctrl,
526 .queryctrl = vpx3220_queryctrl,
527};
528
529static const struct v4l2_subdev_tuner_ops vpx3220_tuner_ops = {
530 .s_std = vpx3220_s_std,
531};
532
533static const struct v4l2_subdev_video_ops vpx3220_video_ops = {
534 .s_routing = vpx3220_s_routing,
535 .s_stream = vpx3220_s_stream,
536 .querystd = vpx3220_querystd,
537 .g_input_status = vpx3220_g_input_status,
538};
539
540static const struct v4l2_subdev_ops vpx3220_ops = {
541 .core = &vpx3220_core_ops,
542 .tuner = &vpx3220_tuner_ops,
543 .video = &vpx3220_video_ops,
544};
545
518/* ----------------------------------------------------------------------- 546/* -----------------------------------------------------------------------
519 * Client management code 547 * Client management code
520 */ 548 */
521 549
522static unsigned short normal_i2c[] = { 0x86 >> 1, 0x8e >> 1, I2C_CLIENT_END };
523
524I2C_CLIENT_INSMOD;
525
526static int vpx3220_probe(struct i2c_client *client, 550static int vpx3220_probe(struct i2c_client *client,
527 const struct i2c_device_id *id) 551 const struct i2c_device_id *id)
528{ 552{
529 struct vpx3220 *decoder; 553 struct vpx3220 *decoder;
554 struct v4l2_subdev *sd;
530 const char *name = NULL; 555 const char *name = NULL;
531 u8 ver; 556 u8 ver;
532 u16 pn; 557 u16 pn;
@@ -539,6 +564,8 @@ static int vpx3220_probe(struct i2c_client *client,
539 decoder = kzalloc(sizeof(struct vpx3220), GFP_KERNEL); 564 decoder = kzalloc(sizeof(struct vpx3220), GFP_KERNEL);
540 if (decoder == NULL) 565 if (decoder == NULL)
541 return -ENOMEM; 566 return -ENOMEM;
567 sd = &decoder->sd;
568 v4l2_i2c_subdev_init(sd, client, &vpx3220_ops);
542 decoder->norm = V4L2_STD_PAL; 569 decoder->norm = V4L2_STD_PAL;
543 decoder->input = 0; 570 decoder->input = 0;
544 decoder->enable = 1; 571 decoder->enable = 1;
@@ -546,11 +573,11 @@ static int vpx3220_probe(struct i2c_client *client,
546 decoder->contrast = 32768; 573 decoder->contrast = 32768;
547 decoder->hue = 32768; 574 decoder->hue = 32768;
548 decoder->sat = 32768; 575 decoder->sat = 32768;
549 i2c_set_clientdata(client, decoder);
550 576
551 ver = i2c_smbus_read_byte_data(client, 0x00); 577 ver = i2c_smbus_read_byte_data(client, 0x00);
552 pn = (i2c_smbus_read_byte_data(client, 0x02) << 8) + 578 pn = (i2c_smbus_read_byte_data(client, 0x02) << 8) +
553 i2c_smbus_read_byte_data(client, 0x01); 579 i2c_smbus_read_byte_data(client, 0x01);
580 decoder->ident = V4L2_IDENT_VPX3220A;
554 if (ver == 0xec) { 581 if (ver == 0xec) {
555 switch (pn) { 582 switch (pn) {
556 case 0x4680: 583 case 0x4680:
@@ -558,26 +585,34 @@ static int vpx3220_probe(struct i2c_client *client,
558 break; 585 break;
559 case 0x4260: 586 case 0x4260:
560 name = "vpx3216b"; 587 name = "vpx3216b";
588 decoder->ident = V4L2_IDENT_VPX3216B;
561 break; 589 break;
562 case 0x4280: 590 case 0x4280:
563 name = "vpx3214c"; 591 name = "vpx3214c";
592 decoder->ident = V4L2_IDENT_VPX3214C;
564 break; 593 break;
565 } 594 }
566 } 595 }
567 if (name) 596 if (name)
568 v4l_info(client, "%s found @ 0x%x (%s)\n", name, 597 v4l2_info(sd, "%s found @ 0x%x (%s)\n", name,
569 client->addr << 1, client->adapter->name); 598 client->addr << 1, client->adapter->name);
570 else 599 else
571 v4l_info(client, "chip (%02x:%04x) found @ 0x%x (%s)\n", 600 v4l2_info(sd, "chip (%02x:%04x) found @ 0x%x (%s)\n",
572 ver, pn, client->addr << 1, client->adapter->name); 601 ver, pn, client->addr << 1, client->adapter->name);
573 602
574 vpx3220_init_client(client); 603 vpx3220_write_block(sd, init_common, sizeof(init_common));
604 vpx3220_write_fp_block(sd, init_fp, sizeof(init_fp) >> 1);
605 /* Default to PAL */
606 vpx3220_write_fp_block(sd, init_pal, sizeof(init_pal) >> 1);
575 return 0; 607 return 0;
576} 608}
577 609
578static int vpx3220_remove(struct i2c_client *client) 610static int vpx3220_remove(struct i2c_client *client)
579{ 611{
580 kfree(i2c_get_clientdata(client)); 612 struct v4l2_subdev *sd = i2c_get_clientdata(client);
613
614 v4l2_device_unregister_subdev(sd);
615 kfree(to_vpx3220(sd));
581 return 0; 616 return 0;
582} 617}
583 618