diff options
author | Hans Verkuil <hverkuil@xs4all.nl> | 2008-11-24 16:16:46 -0500 |
---|---|---|
committer | Mauro Carvalho Chehab <mchehab@redhat.com> | 2008-12-30 06:38:39 -0500 |
commit | 76efd62f1546c6fab2116d3ba832403387bd3d4a (patch) | |
tree | 2dacbc15f37de125aa573708f599913f5fe05e91 | |
parent | 5d302f2e2c5fce46d88a9f6b3c1f74f9e9240e25 (diff) |
V4L/DVB (9825): msp3400: convert to v4l2_subdev.
Signed-off-by: Hans Verkuil <hverkuil@xs4all.nl>
Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com>
-rw-r--r-- | drivers/media/video/msp3400-driver.c | 402 | ||||
-rw-r--r-- | drivers/media/video/msp3400-driver.h | 7 | ||||
-rw-r--r-- | drivers/media/video/msp3400-kthreads.c | 34 |
3 files changed, 247 insertions, 196 deletions
diff --git a/drivers/media/video/msp3400-driver.c b/drivers/media/video/msp3400-driver.c index 3da74dcee902..79ae7bd23528 100644 --- a/drivers/media/video/msp3400-driver.c +++ b/drivers/media/video/msp3400-driver.c | |||
@@ -51,14 +51,14 @@ | |||
51 | #include <linux/module.h> | 51 | #include <linux/module.h> |
52 | #include <linux/slab.h> | 52 | #include <linux/slab.h> |
53 | #include <linux/i2c.h> | 53 | #include <linux/i2c.h> |
54 | #include <linux/kthread.h> | ||
55 | #include <linux/freezer.h> | ||
54 | #include <linux/videodev2.h> | 56 | #include <linux/videodev2.h> |
55 | #include <media/v4l2-common.h> | 57 | #include <media/v4l2-device.h> |
56 | #include <media/v4l2-ioctl.h> | 58 | #include <media/v4l2-ioctl.h> |
57 | #include <media/v4l2-i2c-drv-legacy.h> | 59 | #include <media/v4l2-i2c-drv-legacy.h> |
58 | #include <media/tvaudio.h> | ||
59 | #include <media/msp3400.h> | 60 | #include <media/msp3400.h> |
60 | #include <linux/kthread.h> | 61 | #include <media/tvaudio.h> |
61 | #include <linux/freezer.h> | ||
62 | #include "msp3400-driver.h" | 62 | #include "msp3400-driver.h" |
63 | 63 | ||
64 | /* ---------------------------------------------------------------------- */ | 64 | /* ---------------------------------------------------------------------- */ |
@@ -265,7 +265,7 @@ static char *scart_names[] = { | |||
265 | 265 | ||
266 | void msp_set_scart(struct i2c_client *client, int in, int out) | 266 | void msp_set_scart(struct i2c_client *client, int in, int out) |
267 | { | 267 | { |
268 | struct msp_state *state = i2c_get_clientdata(client); | 268 | struct msp_state *state = to_state(i2c_get_clientdata(client)); |
269 | 269 | ||
270 | state->in_scart = in; | 270 | state->in_scart = in; |
271 | 271 | ||
@@ -289,7 +289,7 @@ void msp_set_scart(struct i2c_client *client, int in, int out) | |||
289 | 289 | ||
290 | void msp_set_audio(struct i2c_client *client) | 290 | void msp_set_audio(struct i2c_client *client) |
291 | { | 291 | { |
292 | struct msp_state *state = i2c_get_clientdata(client); | 292 | struct msp_state *state = to_state(i2c_get_clientdata(client)); |
293 | int bal = 0, bass, treble, loudness; | 293 | int bal = 0, bass, treble, loudness; |
294 | int val = 0; | 294 | int val = 0; |
295 | int reallymuted = state->muted | state->scan_in_progress; | 295 | int reallymuted = state->muted | state->scan_in_progress; |
@@ -336,7 +336,7 @@ void msp_set_audio(struct i2c_client *client) | |||
336 | 336 | ||
337 | static void msp_wake_thread(struct i2c_client *client) | 337 | static void msp_wake_thread(struct i2c_client *client) |
338 | { | 338 | { |
339 | struct msp_state *state = i2c_get_clientdata(client); | 339 | struct msp_state *state = to_state(i2c_get_clientdata(client)); |
340 | 340 | ||
341 | if (NULL == state->kthread) | 341 | if (NULL == state->kthread) |
342 | return; | 342 | return; |
@@ -390,9 +390,9 @@ static int msp_mode_v4l1_to_v4l2(int mode) | |||
390 | } | 390 | } |
391 | #endif | 391 | #endif |
392 | 392 | ||
393 | static int msp_get_ctrl(struct i2c_client *client, struct v4l2_control *ctrl) | 393 | static int msp_g_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl) |
394 | { | 394 | { |
395 | struct msp_state *state = i2c_get_clientdata(client); | 395 | struct msp_state *state = to_state(sd); |
396 | 396 | ||
397 | switch (ctrl->id) { | 397 | switch (ctrl->id) { |
398 | case V4L2_CID_AUDIO_VOLUME: | 398 | case V4L2_CID_AUDIO_VOLUME: |
@@ -433,9 +433,10 @@ static int msp_get_ctrl(struct i2c_client *client, struct v4l2_control *ctrl) | |||
433 | return 0; | 433 | return 0; |
434 | } | 434 | } |
435 | 435 | ||
436 | static int msp_set_ctrl(struct i2c_client *client, struct v4l2_control *ctrl) | 436 | static int msp_s_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl) |
437 | { | 437 | { |
438 | struct msp_state *state = i2c_get_clientdata(client); | 438 | struct msp_state *state = to_state(sd); |
439 | struct i2c_client *client = v4l2_get_subdevdata(sd); | ||
439 | 440 | ||
440 | switch (ctrl->id) { | 441 | switch (ctrl->id) { |
441 | case V4L2_CID_AUDIO_VOLUME: | 442 | case V4L2_CID_AUDIO_VOLUME: |
@@ -481,40 +482,16 @@ static int msp_set_ctrl(struct i2c_client *client, struct v4l2_control *ctrl) | |||
481 | return 0; | 482 | return 0; |
482 | } | 483 | } |
483 | 484 | ||
484 | static int msp_command(struct i2c_client *client, unsigned int cmd, void *arg) | 485 | #ifdef CONFIG_VIDEO_ALLOW_V4L1 |
486 | static int msp_ioctl(struct v4l2_subdev *sd, int cmd, void *arg) | ||
485 | { | 487 | { |
486 | struct msp_state *state = i2c_get_clientdata(client); | 488 | struct msp_state *state = to_state(sd); |
487 | 489 | struct i2c_client *client = v4l2_get_subdevdata(sd); | |
488 | if (msp_debug >= 2) | ||
489 | v4l_i2c_print_ioctl(client, cmd); | ||
490 | 490 | ||
491 | switch (cmd) { | 491 | switch (cmd) { |
492 | case AUDC_SET_RADIO: | ||
493 | if (state->radio) | ||
494 | return 0; | ||
495 | state->radio = 1; | ||
496 | v4l_dbg(1, msp_debug, client, "switching to radio mode\n"); | ||
497 | state->watch_stereo = 0; | ||
498 | switch (state->opmode) { | ||
499 | case OPMODE_MANUAL: | ||
500 | /* set msp3400 to FM radio mode */ | ||
501 | msp3400c_set_mode(client, MSP_MODE_FM_RADIO); | ||
502 | msp3400c_set_carrier(client, MSP_CARRIER(10.7), | ||
503 | MSP_CARRIER(10.7)); | ||
504 | msp_set_audio(client); | ||
505 | break; | ||
506 | case OPMODE_AUTODETECT: | ||
507 | case OPMODE_AUTOSELECT: | ||
508 | /* the thread will do for us */ | ||
509 | msp_wake_thread(client); | ||
510 | break; | ||
511 | } | ||
512 | break; | ||
513 | |||
514 | /* --- v4l ioctls --- */ | 492 | /* --- v4l ioctls --- */ |
515 | /* take care: bttv does userspace copying, we'll get a | 493 | /* take care: bttv does userspace copying, we'll get a |
516 | kernel pointer here... */ | 494 | kernel pointer here... */ |
517 | #ifdef CONFIG_VIDEO_ALLOW_V4L1 | ||
518 | case VIDIOCGAUDIO: | 495 | case VIDIOCGAUDIO: |
519 | { | 496 | { |
520 | struct video_audio *va = arg; | 497 | struct video_audio *va = arg; |
@@ -588,105 +565,137 @@ static int msp_command(struct i2c_client *client, unsigned int cmd, void *arg) | |||
588 | msp_wake_thread(client); | 565 | msp_wake_thread(client); |
589 | break; | 566 | break; |
590 | } | 567 | } |
591 | #endif | 568 | default: |
592 | case VIDIOC_S_FREQUENCY: | 569 | return -ENOIOCTLCMD; |
593 | { | ||
594 | /* new channel -- kick audio carrier scan */ | ||
595 | msp_wake_thread(client); | ||
596 | break; | ||
597 | } | 570 | } |
571 | return 0; | ||
572 | } | ||
573 | #endif | ||
598 | 574 | ||
599 | /* --- v4l2 ioctls --- */ | 575 | /* --- v4l2 ioctls --- */ |
600 | case VIDIOC_S_STD: | 576 | static int msp_s_radio(struct v4l2_subdev *sd) |
601 | { | 577 | { |
602 | v4l2_std_id *id = arg; | 578 | struct msp_state *state = to_state(sd); |
603 | int update = state->radio || state->v4l2_std != *id; | 579 | struct i2c_client *client = v4l2_get_subdevdata(sd); |
604 | 580 | ||
605 | state->v4l2_std = *id; | 581 | if (state->radio) |
606 | state->radio = 0; | ||
607 | if (update) | ||
608 | msp_wake_thread(client); | ||
609 | return 0; | 582 | return 0; |
583 | state->radio = 1; | ||
584 | v4l_dbg(1, msp_debug, client, "switching to radio mode\n"); | ||
585 | state->watch_stereo = 0; | ||
586 | switch (state->opmode) { | ||
587 | case OPMODE_MANUAL: | ||
588 | /* set msp3400 to FM radio mode */ | ||
589 | msp3400c_set_mode(client, MSP_MODE_FM_RADIO); | ||
590 | msp3400c_set_carrier(client, MSP_CARRIER(10.7), | ||
591 | MSP_CARRIER(10.7)); | ||
592 | msp_set_audio(client); | ||
593 | break; | ||
594 | case OPMODE_AUTODETECT: | ||
595 | case OPMODE_AUTOSELECT: | ||
596 | /* the thread will do for us */ | ||
597 | msp_wake_thread(client); | ||
598 | break; | ||
610 | } | 599 | } |
600 | return 0; | ||
601 | } | ||
611 | 602 | ||
612 | case VIDIOC_INT_G_AUDIO_ROUTING: | 603 | static int msp_s_frequency(struct v4l2_subdev *sd, struct v4l2_frequency *freq) |
613 | { | 604 | { |
614 | struct v4l2_routing *rt = arg; | 605 | struct i2c_client *client = v4l2_get_subdevdata(sd); |
615 | 606 | ||
616 | *rt = state->routing; | 607 | /* new channel -- kick audio carrier scan */ |
617 | break; | 608 | msp_wake_thread(client); |
618 | } | 609 | return 0; |
610 | } | ||
619 | 611 | ||
620 | case VIDIOC_INT_S_AUDIO_ROUTING: | 612 | static int msp_s_std(struct v4l2_subdev *sd, v4l2_std_id id) |
621 | { | 613 | { |
622 | struct v4l2_routing *rt = arg; | 614 | struct msp_state *state = to_state(sd); |
623 | int tuner = (rt->input >> 3) & 1; | 615 | struct i2c_client *client = v4l2_get_subdevdata(sd); |
624 | int sc_in = rt->input & 0x7; | 616 | int update = state->radio || state->v4l2_std != id; |
625 | int sc1_out = rt->output & 0xf; | 617 | |
626 | int sc2_out = (rt->output >> 4) & 0xf; | 618 | state->v4l2_std = id; |
627 | u16 val, reg; | 619 | state->radio = 0; |
628 | int i; | 620 | if (update) |
629 | int extern_input = 1; | ||
630 | |||
631 | if (state->routing.input == rt->input && | ||
632 | state->routing.output == rt->output) | ||
633 | break; | ||
634 | state->routing = *rt; | ||
635 | /* check if the tuner input is used */ | ||
636 | for (i = 0; i < 5; i++) { | ||
637 | if (((rt->input >> (4 + i * 4)) & 0xf) == 0) | ||
638 | extern_input = 0; | ||
639 | } | ||
640 | state->mode = extern_input ? MSP_MODE_EXTERN : MSP_MODE_AM_DETECT; | ||
641 | state->rxsubchans = V4L2_TUNER_SUB_STEREO; | ||
642 | msp_set_scart(client, sc_in, 0); | ||
643 | msp_set_scart(client, sc1_out, 1); | ||
644 | msp_set_scart(client, sc2_out, 2); | ||
645 | msp_set_audmode(client); | ||
646 | reg = (state->opmode == OPMODE_AUTOSELECT) ? 0x30 : 0xbb; | ||
647 | val = msp_read_dem(client, reg); | ||
648 | msp_write_dem(client, reg, (val & ~0x100) | (tuner << 8)); | ||
649 | /* wake thread when a new input is chosen */ | ||
650 | msp_wake_thread(client); | 621 | msp_wake_thread(client); |
651 | break; | 622 | return 0; |
623 | } | ||
624 | |||
625 | static int msp_s_routing(struct v4l2_subdev *sd, const struct v4l2_routing *rt) | ||
626 | { | ||
627 | struct msp_state *state = to_state(sd); | ||
628 | struct i2c_client *client = v4l2_get_subdevdata(sd); | ||
629 | int tuner = (rt->input >> 3) & 1; | ||
630 | int sc_in = rt->input & 0x7; | ||
631 | int sc1_out = rt->output & 0xf; | ||
632 | int sc2_out = (rt->output >> 4) & 0xf; | ||
633 | u16 val, reg; | ||
634 | int i; | ||
635 | int extern_input = 1; | ||
636 | |||
637 | if (state->routing.input == rt->input && | ||
638 | state->routing.output == rt->output) | ||
639 | return 0; | ||
640 | state->routing = *rt; | ||
641 | /* check if the tuner input is used */ | ||
642 | for (i = 0; i < 5; i++) { | ||
643 | if (((rt->input >> (4 + i * 4)) & 0xf) == 0) | ||
644 | extern_input = 0; | ||
652 | } | 645 | } |
646 | state->mode = extern_input ? MSP_MODE_EXTERN : MSP_MODE_AM_DETECT; | ||
647 | state->rxsubchans = V4L2_TUNER_SUB_STEREO; | ||
648 | msp_set_scart(client, sc_in, 0); | ||
649 | msp_set_scart(client, sc1_out, 1); | ||
650 | msp_set_scart(client, sc2_out, 2); | ||
651 | msp_set_audmode(client); | ||
652 | reg = (state->opmode == OPMODE_AUTOSELECT) ? 0x30 : 0xbb; | ||
653 | val = msp_read_dem(client, reg); | ||
654 | msp_write_dem(client, reg, (val & ~0x100) | (tuner << 8)); | ||
655 | /* wake thread when a new input is chosen */ | ||
656 | msp_wake_thread(client); | ||
657 | return 0; | ||
658 | } | ||
653 | 659 | ||
654 | case VIDIOC_G_TUNER: | 660 | static int msp_g_tuner(struct v4l2_subdev *sd, struct v4l2_tuner *vt) |
655 | { | 661 | { |
656 | struct v4l2_tuner *vt = arg; | 662 | struct msp_state *state = to_state(sd); |
663 | struct i2c_client *client = v4l2_get_subdevdata(sd); | ||
657 | 664 | ||
658 | if (state->radio) | 665 | if (state->radio) |
659 | break; | 666 | return 0; |
660 | if (state->opmode == OPMODE_AUTOSELECT) | 667 | if (state->opmode == OPMODE_AUTOSELECT) |
661 | msp_detect_stereo(client); | 668 | msp_detect_stereo(client); |
662 | vt->audmode = state->audmode; | 669 | vt->audmode = state->audmode; |
663 | vt->rxsubchans = state->rxsubchans; | 670 | vt->rxsubchans = state->rxsubchans; |
664 | vt->capability |= V4L2_TUNER_CAP_STEREO | | 671 | vt->capability |= V4L2_TUNER_CAP_STEREO | |
665 | V4L2_TUNER_CAP_LANG1 | V4L2_TUNER_CAP_LANG2; | 672 | V4L2_TUNER_CAP_LANG1 | V4L2_TUNER_CAP_LANG2; |
666 | break; | 673 | return 0; |
667 | } | 674 | } |
668 | 675 | ||
669 | case VIDIOC_S_TUNER: | 676 | static int msp_s_tuner(struct v4l2_subdev *sd, struct v4l2_tuner *vt) |
670 | { | 677 | { |
671 | struct v4l2_tuner *vt = (struct v4l2_tuner *)arg; | 678 | struct msp_state *state = to_state(sd); |
679 | struct i2c_client *client = v4l2_get_subdevdata(sd); | ||
672 | 680 | ||
673 | if (state->radio) /* TODO: add mono/stereo support for radio */ | 681 | if (state->radio) /* TODO: add mono/stereo support for radio */ |
674 | break; | 682 | return 0; |
675 | if (state->audmode == vt->audmode) | 683 | if (state->audmode == vt->audmode) |
676 | break; | 684 | return 0; |
677 | state->audmode = vt->audmode; | 685 | state->audmode = vt->audmode; |
678 | /* only set audmode */ | 686 | /* only set audmode */ |
679 | msp_set_audmode(client); | 687 | msp_set_audmode(client); |
680 | break; | 688 | return 0; |
681 | } | 689 | } |
682 | 690 | ||
683 | case VIDIOC_INT_I2S_CLOCK_FREQ: | 691 | static int msp_s_i2s_clock_freq(struct v4l2_subdev *sd, u32 freq) |
684 | { | 692 | { |
685 | u32 *a = (u32 *)arg; | 693 | struct msp_state *state = to_state(sd); |
694 | struct i2c_client *client = v4l2_get_subdevdata(sd); | ||
686 | 695 | ||
687 | v4l_dbg(1, msp_debug, client, "Setting I2S speed to %d\n", *a); | 696 | v4l_dbg(1, msp_debug, client, "Setting I2S speed to %d\n", freq); |
688 | 697 | ||
689 | switch (*a) { | 698 | switch (freq) { |
690 | case 1024000: | 699 | case 1024000: |
691 | state->i2s_mode = 0; | 700 | state->i2s_mode = 0; |
692 | break; | 701 | break; |
@@ -695,24 +704,24 @@ static int msp_command(struct i2c_client *client, unsigned int cmd, void *arg) | |||
695 | break; | 704 | break; |
696 | default: | 705 | default: |
697 | return -EINVAL; | 706 | return -EINVAL; |
698 | } | ||
699 | break; | ||
700 | } | 707 | } |
708 | return 0; | ||
709 | } | ||
701 | 710 | ||
702 | case VIDIOC_QUERYCTRL: | 711 | static int msp_queryctrl(struct v4l2_subdev *sd, struct v4l2_queryctrl *qc) |
703 | { | 712 | { |
704 | struct v4l2_queryctrl *qc = arg; | 713 | struct msp_state *state = to_state(sd); |
705 | 714 | ||
706 | switch (qc->id) { | 715 | switch (qc->id) { |
707 | case V4L2_CID_AUDIO_VOLUME: | 716 | case V4L2_CID_AUDIO_VOLUME: |
708 | case V4L2_CID_AUDIO_MUTE: | 717 | case V4L2_CID_AUDIO_MUTE: |
709 | return v4l2_ctrl_query_fill_std(qc); | 718 | return v4l2_ctrl_query_fill_std(qc); |
710 | default: | 719 | default: |
711 | break; | 720 | break; |
712 | } | 721 | } |
713 | if (!state->has_sound_processing) | 722 | if (!state->has_sound_processing) |
714 | return -EINVAL; | 723 | return -EINVAL; |
715 | switch (qc->id) { | 724 | switch (qc->id) { |
716 | case V4L2_CID_AUDIO_LOUDNESS: | 725 | case V4L2_CID_AUDIO_LOUDNESS: |
717 | case V4L2_CID_AUDIO_BALANCE: | 726 | case V4L2_CID_AUDIO_BALANCE: |
718 | case V4L2_CID_AUDIO_BASS: | 727 | case V4L2_CID_AUDIO_BASS: |
@@ -720,32 +729,38 @@ static int msp_command(struct i2c_client *client, unsigned int cmd, void *arg) | |||
720 | return v4l2_ctrl_query_fill_std(qc); | 729 | return v4l2_ctrl_query_fill_std(qc); |
721 | default: | 730 | default: |
722 | return -EINVAL; | 731 | return -EINVAL; |
723 | } | ||
724 | } | 732 | } |
733 | return 0; | ||
734 | } | ||
725 | 735 | ||
726 | case VIDIOC_G_CTRL: | 736 | static int msp_g_chip_ident(struct v4l2_subdev *sd, struct v4l2_chip_ident *chip) |
727 | return msp_get_ctrl(client, arg); | 737 | { |
728 | 738 | struct msp_state *state = to_state(sd); | |
729 | case VIDIOC_S_CTRL: | 739 | struct i2c_client *client = v4l2_get_subdevdata(sd); |
730 | return msp_set_ctrl(client, arg); | ||
731 | 740 | ||
732 | case VIDIOC_LOG_STATUS: | 741 | return v4l2_chip_ident_i2c_client(client, chip, state->ident, |
733 | { | 742 | (state->rev1 << 16) | state->rev2); |
734 | const char *p; | 743 | } |
735 | 744 | ||
736 | if (state->opmode == OPMODE_AUTOSELECT) | 745 | static int msp_log_status(struct v4l2_subdev *sd) |
737 | msp_detect_stereo(client); | 746 | { |
738 | v4l_info(client, "%s rev1 = 0x%04x rev2 = 0x%04x\n", | 747 | struct msp_state *state = to_state(sd); |
739 | client->name, state->rev1, state->rev2); | 748 | struct i2c_client *client = v4l2_get_subdevdata(sd); |
740 | v4l_info(client, "Audio: volume %d%s\n", | 749 | const char *p; |
741 | state->volume, state->muted ? " (muted)" : ""); | 750 | |
742 | if (state->has_sound_processing) { | 751 | if (state->opmode == OPMODE_AUTOSELECT) |
743 | v4l_info(client, "Audio: balance %d bass %d treble %d loudness %s\n", | 752 | msp_detect_stereo(client); |
744 | state->balance, state->bass, | 753 | v4l_info(client, "%s rev1 = 0x%04x rev2 = 0x%04x\n", |
745 | state->treble, | 754 | client->name, state->rev1, state->rev2); |
746 | state->loudness ? "on" : "off"); | 755 | v4l_info(client, "Audio: volume %d%s\n", |
747 | } | 756 | state->volume, state->muted ? " (muted)" : ""); |
748 | switch (state->mode) { | 757 | if (state->has_sound_processing) { |
758 | v4l_info(client, "Audio: balance %d bass %d treble %d loudness %s\n", | ||
759 | state->balance, state->bass, | ||
760 | state->treble, | ||
761 | state->loudness ? "on" : "off"); | ||
762 | } | ||
763 | switch (state->mode) { | ||
749 | case MSP_MODE_AM_DETECT: p = "AM (for carrier detect)"; break; | 764 | case MSP_MODE_AM_DETECT: p = "AM (for carrier detect)"; break; |
750 | case MSP_MODE_FM_RADIO: p = "FM Radio"; break; | 765 | case MSP_MODE_FM_RADIO: p = "FM Radio"; break; |
751 | case MSP_MODE_FM_TERRA: p = "Terrestial FM-mono/stereo"; break; | 766 | case MSP_MODE_FM_TERRA: p = "Terrestial FM-mono/stereo"; break; |
@@ -756,36 +771,25 @@ static int msp_command(struct i2c_client *client, unsigned int cmd, void *arg) | |||
756 | case MSP_MODE_BTSC: p = "BTSC"; break; | 771 | case MSP_MODE_BTSC: p = "BTSC"; break; |
757 | case MSP_MODE_EXTERN: p = "External input"; break; | 772 | case MSP_MODE_EXTERN: p = "External input"; break; |
758 | default: p = "unknown"; break; | 773 | default: p = "unknown"; break; |
759 | } | 774 | } |
760 | if (state->mode == MSP_MODE_EXTERN) { | 775 | if (state->mode == MSP_MODE_EXTERN) { |
761 | v4l_info(client, "Mode: %s\n", p); | 776 | v4l_info(client, "Mode: %s\n", p); |
762 | } else if (state->opmode == OPMODE_MANUAL) { | 777 | } else if (state->opmode == OPMODE_MANUAL) { |
763 | v4l_info(client, "Mode: %s (%s%s)\n", p, | 778 | v4l_info(client, "Mode: %s (%s%s)\n", p, |
764 | (state->rxsubchans & V4L2_TUNER_SUB_STEREO) ? "stereo" : "mono", | 779 | (state->rxsubchans & V4L2_TUNER_SUB_STEREO) ? "stereo" : "mono", |
765 | (state->rxsubchans & V4L2_TUNER_SUB_LANG2) ? ", dual" : ""); | 780 | (state->rxsubchans & V4L2_TUNER_SUB_LANG2) ? ", dual" : ""); |
766 | } else { | 781 | } else { |
767 | if (state->opmode == OPMODE_AUTODETECT) | 782 | if (state->opmode == OPMODE_AUTODETECT) |
768 | v4l_info(client, "Mode: %s\n", p); | 783 | v4l_info(client, "Mode: %s\n", p); |
769 | v4l_info(client, "Standard: %s (%s%s)\n", | 784 | v4l_info(client, "Standard: %s (%s%s)\n", |
770 | msp_standard_std_name(state->std), | 785 | msp_standard_std_name(state->std), |
771 | (state->rxsubchans & V4L2_TUNER_SUB_STEREO) ? "stereo" : "mono", | 786 | (state->rxsubchans & V4L2_TUNER_SUB_STEREO) ? "stereo" : "mono", |
772 | (state->rxsubchans & V4L2_TUNER_SUB_LANG2) ? ", dual" : ""); | 787 | (state->rxsubchans & V4L2_TUNER_SUB_LANG2) ? ", dual" : ""); |
773 | } | ||
774 | v4l_info(client, "Audmode: 0x%04x\n", state->audmode); | ||
775 | v4l_info(client, "Routing: 0x%08x (input) 0x%08x (output)\n", | ||
776 | state->routing.input, state->routing.output); | ||
777 | v4l_info(client, "ACB: 0x%04x\n", state->acb); | ||
778 | break; | ||
779 | } | ||
780 | |||
781 | case VIDIOC_G_CHIP_IDENT: | ||
782 | return v4l2_chip_ident_i2c_client(client, arg, state->ident, | ||
783 | (state->rev1 << 16) | state->rev2); | ||
784 | |||
785 | default: | ||
786 | /* unknown */ | ||
787 | return -EINVAL; | ||
788 | } | 788 | } |
789 | v4l_info(client, "Audmode: 0x%04x\n", state->audmode); | ||
790 | v4l_info(client, "Routing: 0x%08x (input) 0x%08x (output)\n", | ||
791 | state->routing.input, state->routing.output); | ||
792 | v4l_info(client, "ACB: 0x%04x\n", state->acb); | ||
789 | return 0; | 793 | return 0; |
790 | } | 794 | } |
791 | 795 | ||
@@ -803,11 +807,49 @@ static int msp_resume(struct i2c_client *client) | |||
803 | return 0; | 807 | return 0; |
804 | } | 808 | } |
805 | 809 | ||
810 | static int msp_command(struct i2c_client *client, unsigned cmd, void *arg) | ||
811 | { | ||
812 | return v4l2_subdev_command(i2c_get_clientdata(client), cmd, arg); | ||
813 | } | ||
814 | |||
815 | /* ----------------------------------------------------------------------- */ | ||
816 | |||
817 | static const struct v4l2_subdev_core_ops msp_core_ops = { | ||
818 | .log_status = msp_log_status, | ||
819 | .g_chip_ident = msp_g_chip_ident, | ||
820 | .g_ctrl = msp_g_ctrl, | ||
821 | .s_ctrl = msp_s_ctrl, | ||
822 | .queryctrl = msp_queryctrl, | ||
823 | #ifdef CONFIG_VIDEO_ALLOW_V4L1 | ||
824 | .ioctl = msp_ioctl, | ||
825 | #endif | ||
826 | }; | ||
827 | |||
828 | static const struct v4l2_subdev_tuner_ops msp_tuner_ops = { | ||
829 | .s_frequency = msp_s_frequency, | ||
830 | .g_tuner = msp_g_tuner, | ||
831 | .s_tuner = msp_s_tuner, | ||
832 | .s_radio = msp_s_radio, | ||
833 | .s_std = msp_s_std, | ||
834 | }; | ||
835 | |||
836 | static const struct v4l2_subdev_audio_ops msp_audio_ops = { | ||
837 | .s_routing = msp_s_routing, | ||
838 | .s_i2s_clock_freq = msp_s_i2s_clock_freq, | ||
839 | }; | ||
840 | |||
841 | static const struct v4l2_subdev_ops msp_ops = { | ||
842 | .core = &msp_core_ops, | ||
843 | .tuner = &msp_tuner_ops, | ||
844 | .audio = &msp_audio_ops, | ||
845 | }; | ||
846 | |||
806 | /* ----------------------------------------------------------------------- */ | 847 | /* ----------------------------------------------------------------------- */ |
807 | 848 | ||
808 | static int msp_probe(struct i2c_client *client, const struct i2c_device_id *id) | 849 | static int msp_probe(struct i2c_client *client, const struct i2c_device_id *id) |
809 | { | 850 | { |
810 | struct msp_state *state; | 851 | struct msp_state *state; |
852 | struct v4l2_subdev *sd; | ||
811 | int (*thread_func)(void *data) = NULL; | 853 | int (*thread_func)(void *data) = NULL; |
812 | int msp_hard; | 854 | int msp_hard; |
813 | int msp_family; | 855 | int msp_family; |
@@ -827,7 +869,8 @@ static int msp_probe(struct i2c_client *client, const struct i2c_device_id *id) | |||
827 | if (!state) | 869 | if (!state) |
828 | return -ENOMEM; | 870 | return -ENOMEM; |
829 | 871 | ||
830 | i2c_set_clientdata(client, state); | 872 | sd = &state->sd; |
873 | v4l2_i2c_subdev_init(sd, client, &msp_ops); | ||
831 | 874 | ||
832 | state->v4l2_std = V4L2_STD_NTSC; | 875 | state->v4l2_std = V4L2_STD_NTSC; |
833 | state->audmode = V4L2_TUNER_MODE_STEREO; | 876 | state->audmode = V4L2_TUNER_MODE_STEREO; |
@@ -972,8 +1015,9 @@ static int msp_probe(struct i2c_client *client, const struct i2c_device_id *id) | |||
972 | 1015 | ||
973 | static int msp_remove(struct i2c_client *client) | 1016 | static int msp_remove(struct i2c_client *client) |
974 | { | 1017 | { |
975 | struct msp_state *state = i2c_get_clientdata(client); | 1018 | struct msp_state *state = to_state(i2c_get_clientdata(client)); |
976 | 1019 | ||
1020 | v4l2_device_unregister_subdev(&state->sd); | ||
977 | /* shutdown control thread */ | 1021 | /* shutdown control thread */ |
978 | if (state->kthread) { | 1022 | if (state->kthread) { |
979 | state->restart = 1; | 1023 | state->restart = 1; |
diff --git a/drivers/media/video/msp3400-driver.h b/drivers/media/video/msp3400-driver.h index ab69a290e5dc..3fe1c1b10f53 100644 --- a/drivers/media/video/msp3400-driver.h +++ b/drivers/media/video/msp3400-driver.h | |||
@@ -5,6 +5,7 @@ | |||
5 | #define MSP3400_DRIVER_H | 5 | #define MSP3400_DRIVER_H |
6 | 6 | ||
7 | #include <media/msp3400.h> | 7 | #include <media/msp3400.h> |
8 | #include <media/v4l2-device.h> | ||
8 | 9 | ||
9 | /* ---------------------------------------------------------------------- */ | 10 | /* ---------------------------------------------------------------------- */ |
10 | 11 | ||
@@ -49,6 +50,7 @@ extern int msp_dolby; | |||
49 | extern int msp_stereo_thresh; | 50 | extern int msp_stereo_thresh; |
50 | 51 | ||
51 | struct msp_state { | 52 | struct msp_state { |
53 | struct v4l2_subdev sd; | ||
52 | int rev1, rev2; | 54 | int rev1, rev2; |
53 | int ident; | 55 | int ident; |
54 | u8 has_nicam; | 56 | u8 has_nicam; |
@@ -96,6 +98,11 @@ struct msp_state { | |||
96 | unsigned int watch_stereo:1; | 98 | unsigned int watch_stereo:1; |
97 | }; | 99 | }; |
98 | 100 | ||
101 | static inline struct msp_state *to_state(struct v4l2_subdev *sd) | ||
102 | { | ||
103 | return container_of(sd, struct msp_state, sd); | ||
104 | } | ||
105 | |||
99 | /* msp3400-driver.c */ | 106 | /* msp3400-driver.c */ |
100 | int msp_write_dem(struct i2c_client *client, int addr, int val); | 107 | int msp_write_dem(struct i2c_client *client, int addr, int val); |
101 | int msp_write_dsp(struct i2c_client *client, int addr, int val); | 108 | int msp_write_dsp(struct i2c_client *client, int addr, int val); |
diff --git a/drivers/media/video/msp3400-kthreads.c b/drivers/media/video/msp3400-kthreads.c index 846a14a61fd1..a655e9c30146 100644 --- a/drivers/media/video/msp3400-kthreads.c +++ b/drivers/media/video/msp3400-kthreads.c | |||
@@ -159,7 +159,7 @@ const char *msp_standard_std_name(int std) | |||
159 | 159 | ||
160 | static void msp_set_source(struct i2c_client *client, u16 src) | 160 | static void msp_set_source(struct i2c_client *client, u16 src) |
161 | { | 161 | { |
162 | struct msp_state *state = i2c_get_clientdata(client); | 162 | struct msp_state *state = to_state(i2c_get_clientdata(client)); |
163 | 163 | ||
164 | if (msp_dolby) { | 164 | if (msp_dolby) { |
165 | msp_write_dsp(client, 0x0008, 0x0520); /* I2S1 */ | 165 | msp_write_dsp(client, 0x0008, 0x0520); /* I2S1 */ |
@@ -186,7 +186,7 @@ void msp3400c_set_carrier(struct i2c_client *client, int cdo1, int cdo2) | |||
186 | 186 | ||
187 | void msp3400c_set_mode(struct i2c_client *client, int mode) | 187 | void msp3400c_set_mode(struct i2c_client *client, int mode) |
188 | { | 188 | { |
189 | struct msp_state *state = i2c_get_clientdata(client); | 189 | struct msp_state *state = to_state(i2c_get_clientdata(client)); |
190 | struct msp3400c_init_data_dem *data = &msp3400c_init_data[mode]; | 190 | struct msp3400c_init_data_dem *data = &msp3400c_init_data[mode]; |
191 | int tuner = (state->routing.input >> 3) & 1; | 191 | int tuner = (state->routing.input >> 3) & 1; |
192 | int i; | 192 | int i; |
@@ -227,7 +227,7 @@ static void msp3400c_set_audmode(struct i2c_client *client) | |||
227 | static char *strmode[] = { | 227 | static char *strmode[] = { |
228 | "mono", "stereo", "lang2", "lang1", "lang1+lang2" | 228 | "mono", "stereo", "lang2", "lang1", "lang1+lang2" |
229 | }; | 229 | }; |
230 | struct msp_state *state = i2c_get_clientdata(client); | 230 | struct msp_state *state = to_state(i2c_get_clientdata(client)); |
231 | char *modestr = (state->audmode >= 0 && state->audmode < 5) ? | 231 | char *modestr = (state->audmode >= 0 && state->audmode < 5) ? |
232 | strmode[state->audmode] : "unknown"; | 232 | strmode[state->audmode] : "unknown"; |
233 | int src = 0; /* channel source: FM/AM, nicam or SCART */ | 233 | int src = 0; /* channel source: FM/AM, nicam or SCART */ |
@@ -356,7 +356,7 @@ static void msp3400c_set_audmode(struct i2c_client *client) | |||
356 | 356 | ||
357 | static void msp3400c_print_mode(struct i2c_client *client) | 357 | static void msp3400c_print_mode(struct i2c_client *client) |
358 | { | 358 | { |
359 | struct msp_state *state = i2c_get_clientdata(client); | 359 | struct msp_state *state = to_state(i2c_get_clientdata(client)); |
360 | 360 | ||
361 | if (state->main == state->second) | 361 | if (state->main == state->second) |
362 | v4l_dbg(1, msp_debug, client, | 362 | v4l_dbg(1, msp_debug, client, |
@@ -385,7 +385,7 @@ static void msp3400c_print_mode(struct i2c_client *client) | |||
385 | 385 | ||
386 | static int msp3400c_detect_stereo(struct i2c_client *client) | 386 | static int msp3400c_detect_stereo(struct i2c_client *client) |
387 | { | 387 | { |
388 | struct msp_state *state = i2c_get_clientdata(client); | 388 | struct msp_state *state = to_state(i2c_get_clientdata(client)); |
389 | int val; | 389 | int val; |
390 | int rxsubchans = state->rxsubchans; | 390 | int rxsubchans = state->rxsubchans; |
391 | int newnicam = state->nicam_on; | 391 | int newnicam = state->nicam_on; |
@@ -463,7 +463,7 @@ static int msp3400c_detect_stereo(struct i2c_client *client) | |||
463 | /* stereo/multilang monitoring */ | 463 | /* stereo/multilang monitoring */ |
464 | static void watch_stereo(struct i2c_client *client) | 464 | static void watch_stereo(struct i2c_client *client) |
465 | { | 465 | { |
466 | struct msp_state *state = i2c_get_clientdata(client); | 466 | struct msp_state *state = to_state(i2c_get_clientdata(client)); |
467 | 467 | ||
468 | if (msp_detect_stereo(client)) | 468 | if (msp_detect_stereo(client)) |
469 | msp_set_audmode(client); | 469 | msp_set_audmode(client); |
@@ -475,7 +475,7 @@ static void watch_stereo(struct i2c_client *client) | |||
475 | int msp3400c_thread(void *data) | 475 | int msp3400c_thread(void *data) |
476 | { | 476 | { |
477 | struct i2c_client *client = data; | 477 | struct i2c_client *client = data; |
478 | struct msp_state *state = i2c_get_clientdata(client); | 478 | struct msp_state *state = to_state(i2c_get_clientdata(client)); |
479 | struct msp3400c_carrier_detect *cd; | 479 | struct msp3400c_carrier_detect *cd; |
480 | int count, max1, max2, val1, val2, val, i; | 480 | int count, max1, max2, val1, val2, val, i; |
481 | 481 | ||
@@ -659,7 +659,7 @@ no_second: | |||
659 | int msp3410d_thread(void *data) | 659 | int msp3410d_thread(void *data) |
660 | { | 660 | { |
661 | struct i2c_client *client = data; | 661 | struct i2c_client *client = data; |
662 | struct msp_state *state = i2c_get_clientdata(client); | 662 | struct msp_state *state = to_state(i2c_get_clientdata(client)); |
663 | int val, i, std, count; | 663 | int val, i, std, count; |
664 | 664 | ||
665 | v4l_dbg(1, msp_debug, client, "msp3410 daemon started\n"); | 665 | v4l_dbg(1, msp_debug, client, "msp3410 daemon started\n"); |
@@ -825,7 +825,7 @@ restart: | |||
825 | 825 | ||
826 | static int msp34xxg_modus(struct i2c_client *client) | 826 | static int msp34xxg_modus(struct i2c_client *client) |
827 | { | 827 | { |
828 | struct msp_state *state = i2c_get_clientdata(client); | 828 | struct msp_state *state = to_state(i2c_get_clientdata(client)); |
829 | 829 | ||
830 | if (state->radio) { | 830 | if (state->radio) { |
831 | v4l_dbg(1, msp_debug, client, "selected radio modus\n"); | 831 | v4l_dbg(1, msp_debug, client, "selected radio modus\n"); |
@@ -852,7 +852,7 @@ static int msp34xxg_modus(struct i2c_client *client) | |||
852 | 852 | ||
853 | static void msp34xxg_set_source(struct i2c_client *client, u16 reg, int in) | 853 | static void msp34xxg_set_source(struct i2c_client *client, u16 reg, int in) |
854 | { | 854 | { |
855 | struct msp_state *state = i2c_get_clientdata(client); | 855 | struct msp_state *state = to_state(i2c_get_clientdata(client)); |
856 | int source, matrix; | 856 | int source, matrix; |
857 | 857 | ||
858 | switch (state->audmode) { | 858 | switch (state->audmode) { |
@@ -895,7 +895,7 @@ static void msp34xxg_set_source(struct i2c_client *client, u16 reg, int in) | |||
895 | 895 | ||
896 | static void msp34xxg_set_sources(struct i2c_client *client) | 896 | static void msp34xxg_set_sources(struct i2c_client *client) |
897 | { | 897 | { |
898 | struct msp_state *state = i2c_get_clientdata(client); | 898 | struct msp_state *state = to_state(i2c_get_clientdata(client)); |
899 | u32 in = state->routing.input; | 899 | u32 in = state->routing.input; |
900 | 900 | ||
901 | msp34xxg_set_source(client, 0x0008, (in >> 4) & 0xf); | 901 | msp34xxg_set_source(client, 0x0008, (in >> 4) & 0xf); |
@@ -911,7 +911,7 @@ static void msp34xxg_set_sources(struct i2c_client *client) | |||
911 | /* (re-)initialize the msp34xxg */ | 911 | /* (re-)initialize the msp34xxg */ |
912 | static void msp34xxg_reset(struct i2c_client *client) | 912 | static void msp34xxg_reset(struct i2c_client *client) |
913 | { | 913 | { |
914 | struct msp_state *state = i2c_get_clientdata(client); | 914 | struct msp_state *state = to_state(i2c_get_clientdata(client)); |
915 | int tuner = (state->routing.input >> 3) & 1; | 915 | int tuner = (state->routing.input >> 3) & 1; |
916 | int modus; | 916 | int modus; |
917 | 917 | ||
@@ -954,7 +954,7 @@ static void msp34xxg_reset(struct i2c_client *client) | |||
954 | int msp34xxg_thread(void *data) | 954 | int msp34xxg_thread(void *data) |
955 | { | 955 | { |
956 | struct i2c_client *client = data; | 956 | struct i2c_client *client = data; |
957 | struct msp_state *state = i2c_get_clientdata(client); | 957 | struct msp_state *state = to_state(i2c_get_clientdata(client)); |
958 | int val, i; | 958 | int val, i; |
959 | 959 | ||
960 | v4l_dbg(1, msp_debug, client, "msp34xxg daemon started\n"); | 960 | v4l_dbg(1, msp_debug, client, "msp34xxg daemon started\n"); |
@@ -1049,7 +1049,7 @@ unmute: | |||
1049 | 1049 | ||
1050 | static int msp34xxg_detect_stereo(struct i2c_client *client) | 1050 | static int msp34xxg_detect_stereo(struct i2c_client *client) |
1051 | { | 1051 | { |
1052 | struct msp_state *state = i2c_get_clientdata(client); | 1052 | struct msp_state *state = to_state(i2c_get_clientdata(client)); |
1053 | int status = msp_read_dem(client, 0x0200); | 1053 | int status = msp_read_dem(client, 0x0200); |
1054 | int is_bilingual = status & 0x100; | 1054 | int is_bilingual = status & 0x100; |
1055 | int is_stereo = status & 0x40; | 1055 | int is_stereo = status & 0x40; |
@@ -1078,7 +1078,7 @@ static int msp34xxg_detect_stereo(struct i2c_client *client) | |||
1078 | 1078 | ||
1079 | static void msp34xxg_set_audmode(struct i2c_client *client) | 1079 | static void msp34xxg_set_audmode(struct i2c_client *client) |
1080 | { | 1080 | { |
1081 | struct msp_state *state = i2c_get_clientdata(client); | 1081 | struct msp_state *state = to_state(i2c_get_clientdata(client)); |
1082 | 1082 | ||
1083 | if (state->std == 0x20) { | 1083 | if (state->std == 0x20) { |
1084 | if ((state->rxsubchans & V4L2_TUNER_SUB_SAP) && | 1084 | if ((state->rxsubchans & V4L2_TUNER_SUB_SAP) && |
@@ -1095,7 +1095,7 @@ static void msp34xxg_set_audmode(struct i2c_client *client) | |||
1095 | 1095 | ||
1096 | void msp_set_audmode(struct i2c_client *client) | 1096 | void msp_set_audmode(struct i2c_client *client) |
1097 | { | 1097 | { |
1098 | struct msp_state *state = i2c_get_clientdata(client); | 1098 | struct msp_state *state = to_state(i2c_get_clientdata(client)); |
1099 | 1099 | ||
1100 | switch (state->opmode) { | 1100 | switch (state->opmode) { |
1101 | case OPMODE_MANUAL: | 1101 | case OPMODE_MANUAL: |
@@ -1110,7 +1110,7 @@ void msp_set_audmode(struct i2c_client *client) | |||
1110 | 1110 | ||
1111 | int msp_detect_stereo(struct i2c_client *client) | 1111 | int msp_detect_stereo(struct i2c_client *client) |
1112 | { | 1112 | { |
1113 | struct msp_state *state = i2c_get_clientdata(client); | 1113 | struct msp_state *state = to_state(i2c_get_clientdata(client)); |
1114 | 1114 | ||
1115 | switch (state->opmode) { | 1115 | switch (state->opmode) { |
1116 | case OPMODE_MANUAL: | 1116 | case OPMODE_MANUAL: |