aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorPete Eberlein <pete@sensoray.com>2009-11-16 13:15:07 -0500
committerMauro Carvalho Chehab <mchehab@redhat.com>2009-12-05 15:42:18 -0500
commit05d76f2da1e5ccb68a3610246501334e5bc42542 (patch)
treed574f51b3d1e44c4ab1cc6436783b41228d8c15e
parent832b6a8917f050a9cbeeb69e080733128d562f59 (diff)
V4L/DVB (13457): s2250: subdev conversion
Convert the s2250 i2c driver to use v4l2 subdev interface. Signed-off-by: Pete Eberlein <pete@sensoray.com> Signed-off-by: Hans Verkuil <hverkuil@xs4all.nl> Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com>
-rw-r--r--drivers/staging/go7007/s2250-board.c507
1 files changed, 261 insertions, 246 deletions
diff --git a/drivers/staging/go7007/s2250-board.c b/drivers/staging/go7007/s2250-board.c
index a69f7682295e..8cf7f2750b3f 100644
--- a/drivers/staging/go7007/s2250-board.c
+++ b/drivers/staging/go7007/s2250-board.c
@@ -23,6 +23,7 @@
23#include <media/v4l2-device.h> 23#include <media/v4l2-device.h>
24#include <media/v4l2-common.h> 24#include <media/v4l2-common.h>
25#include <media/v4l2-i2c-drv.h> 25#include <media/v4l2-i2c-drv.h>
26#include <media/v4l2-subdev.h>
26#include "go7007-priv.h" 27#include "go7007-priv.h"
27 28
28MODULE_DESCRIPTION("Sensoray 2250/2251 i2c v4l2 subdev driver"); 29MODULE_DESCRIPTION("Sensoray 2250/2251 i2c v4l2 subdev driver");
@@ -115,6 +116,7 @@ static u16 vid_regs_fp_pal[] =
115}; 116};
116 117
117struct s2250 { 118struct s2250 {
119 struct v4l2_subdev sd;
118 v4l2_std_id std; 120 v4l2_std_id std;
119 int input; 121 int input;
120 int brightness; 122 int brightness;
@@ -126,6 +128,11 @@ struct s2250 {
126 struct i2c_client *audio; 128 struct i2c_client *audio;
127}; 129};
128 130
131static inline struct s2250 *to_state(struct v4l2_subdev *sd)
132{
133 return container_of(sd, struct s2250, sd);
134}
135
129/* from go7007-usb.c which is Copyright (C) 2005-2006 Micronas USA Inc.*/ 136/* from go7007-usb.c which is Copyright (C) 2005-2006 Micronas USA Inc.*/
130static int go7007_usb_vendor_request(struct go7007 *go, u16 request, 137static int go7007_usb_vendor_request(struct go7007 *go, u16 request,
131 u16 value, u16 index, void *transfer_buffer, int length, int in) 138 u16 value, u16 index, void *transfer_buffer, int length, int in)
@@ -309,253 +316,262 @@ static int write_regs_fp(struct i2c_client *client, u16 *regs)
309} 316}
310 317
311 318
312static int s2250_command(struct i2c_client *client, 319/* ------------------------------------------------------------------------- */
313 unsigned int cmd, void *arg) 320
321static int s2250_s_video_routing(struct v4l2_subdev *sd, u32 input, u32 output,
322 u32 config)
314{ 323{
315 struct s2250 *dec = i2c_get_clientdata(client); 324 struct s2250 *state = to_state(sd);
325 struct i2c_client *client = v4l2_get_subdevdata(sd);
326 int vidsys;
327
328 vidsys = (state->std == V4L2_STD_NTSC) ? 0x01 : 0x00;
329 if (input == 0) {
330 /* composite */
331 write_reg_fp(client, 0x20, 0x020 | vidsys);
332 write_reg_fp(client, 0x21, 0x662);
333 write_reg_fp(client, 0x140, 0x060);
334 } else if (input == 1) {
335 /* S-Video */
336 write_reg_fp(client, 0x20, 0x040 | vidsys);
337 write_reg_fp(client, 0x21, 0x666);
338 write_reg_fp(client, 0x140, 0x060);
339 } else {
340 return -EINVAL;
341 }
342 state->input = input;
343 return 0;
344}
316 345
317 switch (cmd) { 346static int s2250_s_std(struct v4l2_subdev *sd, v4l2_std_id norm)
318 case VIDIOC_S_INPUT: 347{
319 { 348 struct s2250 *state = to_state(sd);
320 int vidsys; 349 struct i2c_client *client = v4l2_get_subdevdata(sd);
321 int *input = arg; 350 u16 vidsource;
322 351
323 vidsys = (dec->std == V4L2_STD_NTSC) ? 0x01 : 0x00; 352 vidsource = (state->input == 1) ? 0x040 : 0x020;
324 if (*input == 0) { 353 switch (norm) {
325 /* composite */ 354 case V4L2_STD_NTSC:
326 write_reg_fp(client, 0x20, 0x020 | vidsys); 355 write_regs_fp(client, vid_regs_fp);
327 write_reg_fp(client, 0x21, 0x662); 356 write_reg_fp(client, 0x20, vidsource | 1);
328 write_reg_fp(client, 0x140, 0x060);
329 } else {
330 /* S-Video */
331 write_reg_fp(client, 0x20, 0x040 | vidsys);
332 write_reg_fp(client, 0x21, 0x666);
333 write_reg_fp(client, 0x140, 0x060);
334 }
335 dec->input = *input;
336 break; 357 break;
337 } 358 case V4L2_STD_PAL:
338 case VIDIOC_S_STD: 359 write_regs_fp(client, vid_regs_fp);
339 { 360 write_regs_fp(client, vid_regs_fp_pal);
340 v4l2_std_id *std = arg; 361 write_reg_fp(client, 0x20, vidsource);
341 u16 vidsource;
342
343 vidsource = (dec->input == 1) ? 0x040 : 0x020;
344 dec->std = *std;
345 switch (dec->std) {
346 case V4L2_STD_NTSC:
347 write_regs_fp(client, vid_regs_fp);
348 write_reg_fp(client, 0x20, vidsource | 1);
349 break;
350 case V4L2_STD_PAL:
351 write_regs_fp(client, vid_regs_fp);
352 write_regs_fp(client, vid_regs_fp_pal);
353 write_reg_fp(client, 0x20, vidsource);
354 break;
355 default:
356 return -EINVAL;
357 }
358 break; 362 break;
363 default:
364 return -EINVAL;
359 } 365 }
360 case VIDIOC_QUERYCTRL: 366 state->std = norm;
361 { 367 return 0;
362 struct v4l2_queryctrl *ctrl = arg; 368}
363 static const u32 user_ctrls[] = { 369
364 V4L2_CID_BRIGHTNESS, 370static int s2250_queryctrl(struct v4l2_subdev *sd, struct v4l2_queryctrl *query)
365 V4L2_CID_CONTRAST, 371{
366 V4L2_CID_SATURATION, 372 switch (query->id) {
367 V4L2_CID_HUE, 373 case V4L2_CID_BRIGHTNESS:
368 0 374 return v4l2_ctrl_query_fill(query, 0, 100, 1, 50);
369 }; 375 case V4L2_CID_CONTRAST:
370 static const u32 *ctrl_classes[] = { 376 return v4l2_ctrl_query_fill(query, 0, 100, 1, 50);
371 user_ctrls, 377 case V4L2_CID_SATURATION:
372 NULL 378 return v4l2_ctrl_query_fill(query, 0, 100, 1, 50);
373 }; 379 case V4L2_CID_HUE:
374 380 return v4l2_ctrl_query_fill(query, -50, 50, 1, 0);
375 ctrl->id = v4l2_ctrl_next(ctrl_classes, ctrl->id); 381 default:
376 switch (ctrl->id) { 382 return -EINVAL;
377 case V4L2_CID_BRIGHTNESS:
378 v4l2_ctrl_query_fill(ctrl, 0, 100, 1, 50);
379 break;
380 case V4L2_CID_CONTRAST:
381 v4l2_ctrl_query_fill(ctrl, 0, 100, 1, 50);
382 break;
383 case V4L2_CID_SATURATION:
384 v4l2_ctrl_query_fill(ctrl, 0, 100, 1, 50);
385 break;
386 case V4L2_CID_HUE:
387 v4l2_ctrl_query_fill(ctrl, -50, 50, 1, 0);
388 break;
389 default:
390 ctrl->name[0] = '\0';
391 return -EINVAL;
392 }
393 break;
394 } 383 }
395 case VIDIOC_S_CTRL: 384 return 0;
396 { 385}
397 struct v4l2_control *ctrl = arg; 386
398 int value1; 387static int s2250_s_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl)
399 u16 oldvalue; 388{
400 389 struct s2250 *state = to_state(sd);
401 switch (ctrl->id) { 390 struct i2c_client *client = v4l2_get_subdevdata(sd);
402 case V4L2_CID_BRIGHTNESS: 391 int value1;
403 if (ctrl->value > 100) 392 u16 oldvalue;
404 dec->brightness = 100; 393
405 else if (ctrl->value < 0) 394 switch (ctrl->id) {
406 dec->brightness = 0; 395 case V4L2_CID_BRIGHTNESS:
407 else 396 if (ctrl->value > 100)
408 dec->brightness = ctrl->value; 397 state->brightness = 100;
409 value1 = (dec->brightness - 50) * 255 / 100; 398 else if (ctrl->value < 0)
410 read_reg_fp(client, VPX322_ADDR_BRIGHTNESS0, &oldvalue); 399 state->brightness = 0;
411 write_reg_fp(client, VPX322_ADDR_BRIGHTNESS0, 400 else
412 value1 | (oldvalue & ~0xff)); 401 state->brightness = ctrl->value;
413 read_reg_fp(client, VPX322_ADDR_BRIGHTNESS1, &oldvalue); 402 value1 = (state->brightness - 50) * 255 / 100;
414 write_reg_fp(client, VPX322_ADDR_BRIGHTNESS1, 403 read_reg_fp(client, VPX322_ADDR_BRIGHTNESS0, &oldvalue);
415 value1 | (oldvalue & ~0xff)); 404 write_reg_fp(client, VPX322_ADDR_BRIGHTNESS0,
416 write_reg_fp(client, 0x140, 0x60); 405 value1 | (oldvalue & ~0xff));
417 break; 406 read_reg_fp(client, VPX322_ADDR_BRIGHTNESS1, &oldvalue);
418 case V4L2_CID_CONTRAST: 407 write_reg_fp(client, VPX322_ADDR_BRIGHTNESS1,
419 if (ctrl->value > 100) 408 value1 | (oldvalue & ~0xff));
420 dec->contrast = 100; 409 write_reg_fp(client, 0x140, 0x60);
421 else if (ctrl->value < 0)
422 dec->contrast = 0;
423 else
424 dec->contrast = ctrl->value;
425 value1 = dec->contrast * 0x40 / 100;
426 if (value1 > 0x3f)
427 value1 = 0x3f; /* max */
428 read_reg_fp(client, VPX322_ADDR_CONTRAST0, &oldvalue);
429 write_reg_fp(client, VPX322_ADDR_CONTRAST0,
430 value1 | (oldvalue & ~0x3f));
431 read_reg_fp(client, VPX322_ADDR_CONTRAST1, &oldvalue);
432 write_reg_fp(client, VPX322_ADDR_CONTRAST1,
433 value1 | (oldvalue & ~0x3f));
434 write_reg_fp(client, 0x140, 0x60);
435 break;
436 case V4L2_CID_SATURATION:
437 if (ctrl->value > 127)
438 dec->saturation = 127;
439 else if (ctrl->value < 0)
440 dec->saturation = 0;
441 else
442 dec->saturation = ctrl->value;
443
444 value1 = dec->saturation * 4140 / 100;
445 if (value1 > 4094)
446 value1 = 4094;
447 write_reg_fp(client, VPX322_ADDR_SAT, value1);
448 break;
449 case V4L2_CID_HUE:
450 if (ctrl->value > 50)
451 dec->hue = 50;
452 else if (ctrl->value < -50)
453 dec->hue = -50;
454 else
455 dec->hue = ctrl->value;
456 /* clamp the hue range */
457 value1 = dec->hue * 280 / 50;
458 write_reg_fp(client, VPX322_ADDR_HUE, value1);
459 break;
460 }
461 break; 410 break;
462 } 411 case V4L2_CID_CONTRAST:
463 case VIDIOC_G_CTRL: 412 if (ctrl->value > 100)
464 { 413 state->contrast = 100;
465 struct v4l2_control *ctrl = arg; 414 else if (ctrl->value < 0)
466 415 state->contrast = 0;
467 switch (ctrl->id) { 416 else
468 case V4L2_CID_BRIGHTNESS: 417 state->contrast = ctrl->value;
469 ctrl->value = dec->brightness; 418 value1 = state->contrast * 0x40 / 100;
470 break; 419 if (value1 > 0x3f)
471 case V4L2_CID_CONTRAST: 420 value1 = 0x3f; /* max */
472 ctrl->value = dec->contrast; 421 read_reg_fp(client, VPX322_ADDR_CONTRAST0, &oldvalue);
473 break; 422 write_reg_fp(client, VPX322_ADDR_CONTRAST0,
474 case V4L2_CID_SATURATION: 423 value1 | (oldvalue & ~0x3f));
475 ctrl->value = dec->saturation; 424 read_reg_fp(client, VPX322_ADDR_CONTRAST1, &oldvalue);
476 break; 425 write_reg_fp(client, VPX322_ADDR_CONTRAST1,
477 case V4L2_CID_HUE: 426 value1 | (oldvalue & ~0x3f));
478 ctrl->value = dec->hue; 427 write_reg_fp(client, 0x140, 0x60);
479 break;
480 }
481 break; 428 break;
429 case V4L2_CID_SATURATION:
430 if (ctrl->value > 100)
431 state->saturation = 100;
432 else if (ctrl->value < 0)
433 state->saturation = 0;
434 else
435 state->saturation = ctrl->value;
436 value1 = state->saturation * 4140 / 100;
437 if (value1 > 4094)
438 value1 = 4094;
439 write_reg_fp(client, VPX322_ADDR_SAT, value1);
440 break;
441 case V4L2_CID_HUE:
442 if (ctrl->value > 50)
443 state->hue = 50;
444 else if (ctrl->value < -50)
445 state->hue = -50;
446 else
447 state->hue = ctrl->value;
448 /* clamp the hue range */
449 value1 = state->hue * 280 / 50;
450 write_reg_fp(client, VPX322_ADDR_HUE, value1);
451 break;
452 default:
453 return -EINVAL;
482 } 454 }
483 case VIDIOC_S_FMT: 455 return 0;
484 { 456}
485 struct v4l2_format *fmt = arg;
486 if (fmt->fmt.pix.height < 640) {
487 write_reg_fp(client, 0x12b, dec->reg12b_val | 0x400);
488 write_reg_fp(client, 0x140, 0x060);
489 } else {
490 write_reg_fp(client, 0x12b, dec->reg12b_val & ~0x400);
491 write_reg_fp(client, 0x140, 0x060);
492 }
493 return 0;
494 }
495 case VIDIOC_G_AUDIO:
496 {
497 struct v4l2_audio *audio = arg;
498 457
499 memset(audio, 0, sizeof(*audio)); 458static int s2250_g_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl)
500 audio->index = dec->audio_input; 459{
501 /* fall through */ 460 struct s2250 *state = to_state(sd);
502 } 461
503 case VIDIOC_ENUMAUDIO: 462 switch (ctrl->id) {
504 { 463 case V4L2_CID_BRIGHTNESS:
505 struct v4l2_audio *audio = arg; 464 ctrl->value = state->brightness;
506 465 break;
507 switch (audio->index) { 466 case V4L2_CID_CONTRAST:
508 case 0: 467 ctrl->value = state->contrast;
509 strcpy(audio->name, "Line In"); 468 break;
510 break; 469 case V4L2_CID_SATURATION:
511 case 1: 470 ctrl->value = state->saturation;
512 strcpy(audio->name, "Mic"); 471 break;
513 break; 472 case V4L2_CID_HUE:
514 case 2: 473 ctrl->value = state->hue;
515 strcpy(audio->name, "Mic Boost"); 474 break;
516 break; 475 default:
517 default: 476 return -EINVAL;
518 audio->name[0] = '\0';
519 return 0;
520 }
521 audio->capability = V4L2_AUDCAP_STEREO;
522 audio->mode = 0;
523 return 0;
524 } 477 }
525 case VIDIOC_S_AUDIO: 478 return 0;
526 { 479}
527 struct v4l2_audio *audio = arg; 480
528 481static int s2250_s_fmt(struct v4l2_subdev *sd, struct v4l2_format *fmt)
529 switch (audio->index) { 482{
530 case 0: 483 struct s2250 *state = to_state(sd);
531 write_reg(dec->audio, 0x08, 0x02); /* Line In */ 484 struct i2c_client *client = v4l2_get_subdevdata(sd);
532 break; 485
533 case 1: 486 if (fmt->fmt.pix.height < 640) {
534 write_reg(dec->audio, 0x08, 0x04); /* Mic */ 487 write_reg_fp(client, 0x12b, state->reg12b_val | 0x400);
535 break; 488 write_reg_fp(client, 0x140, 0x060);
536 case 2: 489 } else {
537 write_reg(dec->audio, 0x08, 0x05); /* Mic Boost */ 490 write_reg_fp(client, 0x12b, state->reg12b_val & ~0x400);
538 break; 491 write_reg_fp(client, 0x140, 0x060);
539 default:
540 return -EINVAL;
541 }
542 dec->audio_input = audio->index;
543 return 0;
544 } 492 }
493 return 0;
494}
545 495
546 default: 496static int s2250_s_audio_routing(struct v4l2_subdev *sd, u32 input, u32 output,
547 printk(KERN_INFO "s2250: unknown command 0x%x\n", cmd); 497 u32 config)
498{
499 struct s2250 *state = to_state(sd);
500
501 switch (input) {
502 case 0:
503 write_reg(state->audio, 0x08, 0x02); /* Line In */
504 break;
505 case 1:
506 write_reg(state->audio, 0x08, 0x04); /* Mic */
548 break; 507 break;
508 case 2:
509 write_reg(state->audio, 0x08, 0x05); /* Mic Boost */
510 break;
511 default:
512 return -EINVAL;
549 } 513 }
514 state->audio_input = input;
515 return 0;
516}
517
518
519static int s2250_log_status(struct v4l2_subdev *sd)
520{
521 struct s2250 *state = to_state(sd);
522
523 v4l2_info(sd, "Standard: %s\n", state->std == V4L2_STD_NTSC ? "NTSC" :
524 state->std == V4L2_STD_PAL ? "PAL" :
525 state->std == V4L2_STD_SECAM ? "SECAM" :
526 "unknown");
527 v4l2_info(sd, "Input: %s\n", state->input == 0 ? "Composite" :
528 state->input == 1 ? "S-video" :
529 "error");
530 v4l2_info(sd, "Brightness: %d\n", state->brightness);
531 v4l2_info(sd, "Contrast: %d\n", state->contrast);
532 v4l2_info(sd, "Saturation: %d\n", state->saturation);
533 v4l2_info(sd, "Hue: %d\n", state->hue); return 0;
534 v4l2_info(sd, "Audio input: %s\n", state->audio_input == 0 ? "Line In" :
535 state->audio_input == 1 ? "Mic" :
536 state->audio_input == 2 ? "Mic Boost" :
537 "error");
550 return 0; 538 return 0;
551} 539}
552 540
541/* --------------------------------------------------------------------------*/
542
543static const struct v4l2_subdev_core_ops s2250_core_ops = {
544 .log_status = s2250_log_status,
545 .g_ctrl = s2250_g_ctrl,
546 .s_ctrl = s2250_s_ctrl,
547 .queryctrl = s2250_queryctrl,
548 .s_std = s2250_s_std,
549};
550
551static const struct v4l2_subdev_audio_ops s2250_audio_ops = {
552 .s_routing = s2250_s_audio_routing,
553};
554
555static const struct v4l2_subdev_video_ops s2250_video_ops = {
556 .s_routing = s2250_s_video_routing,
557 .s_fmt = s2250_s_fmt,
558};
559
560static const struct v4l2_subdev_ops s2250_ops = {
561 .core = &s2250_core_ops,
562 .audio = &s2250_audio_ops,
563 .video = &s2250_video_ops,
564};
565
566/* --------------------------------------------------------------------------*/
567
553static int s2250_probe(struct i2c_client *client, 568static int s2250_probe(struct i2c_client *client,
554 const struct i2c_device_id *id) 569 const struct i2c_device_id *id)
555{ 570{
556 struct i2c_client *audio; 571 struct i2c_client *audio;
557 struct i2c_adapter *adapter = client->adapter; 572 struct i2c_adapter *adapter = client->adapter;
558 struct s2250 *dec; 573 struct s2250 *state;
574 struct v4l2_subdev *sd;
559 u8 *data; 575 u8 *data;
560 struct go7007 *go = i2c_get_adapdata(adapter); 576 struct go7007 *go = i2c_get_adapdata(adapter);
561 struct go7007_usb *usb = go->hpi_context; 577 struct go7007_usb *usb = go->hpi_context;
@@ -564,30 +580,31 @@ static int s2250_probe(struct i2c_client *client,
564 if (audio == NULL) 580 if (audio == NULL)
565 return -ENOMEM; 581 return -ENOMEM;
566 582
567 dec = kmalloc(sizeof(struct s2250), GFP_KERNEL); 583 state = kmalloc(sizeof(struct s2250), GFP_KERNEL);
568 if (dec == NULL) { 584 if (state == NULL) {
569 i2c_unregister_device(audio); 585 i2c_unregister_device(audio);
570 return -ENOMEM; 586 return -ENOMEM;
571 } 587 }
572 588
573 dec->std = V4L2_STD_NTSC; 589 sd = &state->sd;
574 dec->brightness = 50; 590 v4l2_i2c_subdev_init(sd, client, &s2250_ops);
575 dec->contrast = 50;
576 dec->saturation = 50;
577 dec->hue = 0;
578 dec->audio = audio;
579 i2c_set_clientdata(client, dec);
580 591
581 printk(KERN_INFO 592 v4l2_info(sd, "initializing %s at address 0x%x on %s\n",
582 "s2250: initializing video decoder on %s\n", 593 "Sensoray 2250/2251", client->addr, client->adapter->name);
583 adapter->name); 594
595 state->std = V4L2_STD_NTSC;
596 state->brightness = 50;
597 state->contrast = 50;
598 state->saturation = 50;
599 state->hue = 0;
600 state->audio = audio;
584 601
585 /* initialize the audio */ 602 /* initialize the audio */
586 if (write_regs(audio, aud_regs) < 0) { 603 if (write_regs(audio, aud_regs) < 0) {
587 printk(KERN_ERR 604 printk(KERN_ERR
588 "s2250: error initializing audio\n"); 605 "s2250: error initializing audio\n");
589 i2c_unregister_device(audio); 606 i2c_unregister_device(audio);
590 kfree(dec); 607 kfree(state);
591 return 0; 608 return 0;
592 } 609 }
593 610
@@ -595,14 +612,14 @@ static int s2250_probe(struct i2c_client *client,
595 printk(KERN_ERR 612 printk(KERN_ERR
596 "s2250: error initializing decoder\n"); 613 "s2250: error initializing decoder\n");
597 i2c_unregister_device(audio); 614 i2c_unregister_device(audio);
598 kfree(dec); 615 kfree(state);
599 return 0; 616 return 0;
600 } 617 }
601 if (write_regs_fp(client, vid_regs_fp) < 0) { 618 if (write_regs_fp(client, vid_regs_fp) < 0) {
602 printk(KERN_ERR 619 printk(KERN_ERR
603 "s2250: error initializing decoder\n"); 620 "s2250: error initializing decoder\n");
604 i2c_unregister_device(audio); 621 i2c_unregister_device(audio);
605 kfree(dec); 622 kfree(state);
606 return 0; 623 return 0;
607 } 624 }
608 /* set default channel */ 625 /* set default channel */
@@ -612,7 +629,7 @@ static int s2250_probe(struct i2c_client *client,
612 write_reg_fp(client, 0x140, 0x060); 629 write_reg_fp(client, 0x140, 0x060);
613 630
614 /* set default audio input */ 631 /* set default audio input */
615 dec->audio_input = 0; 632 state->audio_input = 0;
616 write_reg(client, 0x08, 0x02); /* Line In */ 633 write_reg(client, 0x08, 0x02); /* Line In */
617 634
618 if (mutex_lock_interruptible(&usb->i2c_lock) == 0) { 635 if (mutex_lock_interruptible(&usb->i2c_lock) == 0) {
@@ -637,17 +654,16 @@ static int s2250_probe(struct i2c_client *client,
637 mutex_unlock(&usb->i2c_lock); 654 mutex_unlock(&usb->i2c_lock);
638 } 655 }
639 656
640 printk("s2250: initialized successfully\n"); 657 v4l2_info(sd, "initialized successfully\n");
641 return 0; 658 return 0;
642} 659}
643 660
644static int s2250_remove(struct i2c_client *client) 661static int s2250_remove(struct i2c_client *client)
645{ 662{
646 struct s2250 *dec = i2c_get_clientdata(client); 663 struct v4l2_subdev *sd = i2c_get_clientdata(client);
647 664
648 i2c_set_clientdata(client, NULL); 665 v4l2_device_unregister_subdev(sd);
649 i2c_unregister_device(dec->audio); 666 kfree(to_state(sd));
650 kfree(dec);
651 return 0; 667 return 0;
652} 668}
653 669
@@ -661,6 +677,5 @@ static struct v4l2_i2c_driver_data v4l2_i2c_data = {
661 .name = "s2250", 677 .name = "s2250",
662 .probe = s2250_probe, 678 .probe = s2250_probe,
663 .remove = s2250_remove, 679 .remove = s2250_remove,
664 .command = s2250_command,
665 .id_table = s2250_id, 680 .id_table = s2250_id,
666}; 681};