diff options
author | Hans Verkuil <hverkuil@xs4all.nl> | 2006-04-22 09:22:46 -0400 |
---|---|---|
committer | Mauro Carvalho Chehab <mchehab@infradead.org> | 2006-06-25 01:00:16 -0400 |
commit | e2b8cf4ced47465b24d6fe911714827475fb0412 (patch) | |
tree | adc3dcf673c084ad58f3ace0c11d44141cd892a4 /drivers | |
parent | 3eb731705556b643df2cbae1bc98976335451548 (diff) |
V4L/DVB (4005): Add support for the cx25836/7 video decoder.
Signed-off-by: Scott Alfter <salfter@ssai.us>
Signed-off-by: Hans Verkuil <hverkuil@xs4all.nl>
Signed-off-by: Mauro Carvalho Chehab <mchehab@infradead.org>
Diffstat (limited to 'drivers')
-rw-r--r-- | drivers/media/video/cx25840/cx25840-audio.c | 24 | ||||
-rw-r--r-- | drivers/media/video/cx25840/cx25840-core.c | 181 | ||||
-rw-r--r-- | drivers/media/video/cx25840/cx25840-core.h | 5 |
3 files changed, 154 insertions, 56 deletions
diff --git a/drivers/media/video/cx25840/cx25840-audio.c b/drivers/media/video/cx25840/cx25840-audio.c index 9a4b813152e5..f035f2b9ffd1 100644 --- a/drivers/media/video/cx25840/cx25840-audio.c +++ b/drivers/media/video/cx25840/cx25840-audio.c | |||
@@ -31,7 +31,8 @@ static int set_audclk_freq(struct i2c_client *client, u32 freq) | |||
31 | return -EINVAL; | 31 | return -EINVAL; |
32 | 32 | ||
33 | /* assert soft reset */ | 33 | /* assert soft reset */ |
34 | cx25840_and_or(client, 0x810, ~0x1, 0x01); | 34 | if (!state->is_cx25836) |
35 | cx25840_and_or(client, 0x810, ~0x1, 0x01); | ||
35 | 36 | ||
36 | /* common for all inputs and rates */ | 37 | /* common for all inputs and rates */ |
37 | /* SA_MCLK_SEL=1, SA_MCLK_DIV=0x10 */ | 38 | /* SA_MCLK_SEL=1, SA_MCLK_DIV=0x10 */ |
@@ -46,6 +47,9 @@ static int set_audclk_freq(struct i2c_client *client, u32 freq) | |||
46 | /* AUX_PLL_FRAC */ | 47 | /* AUX_PLL_FRAC */ |
47 | cx25840_write4(client, 0x110, 0xee39bb01); | 48 | cx25840_write4(client, 0x110, 0xee39bb01); |
48 | 49 | ||
50 | if (state->is_cx25836) | ||
51 | break; | ||
52 | |||
49 | /* src3/4/6_ctl = 0x0801f77f */ | 53 | /* src3/4/6_ctl = 0x0801f77f */ |
50 | cx25840_write4(client, 0x900, 0x7ff70108); | 54 | cx25840_write4(client, 0x900, 0x7ff70108); |
51 | cx25840_write4(client, 0x904, 0x7ff70108); | 55 | cx25840_write4(client, 0x904, 0x7ff70108); |
@@ -59,6 +63,9 @@ static int set_audclk_freq(struct i2c_client *client, u32 freq) | |||
59 | /* AUX_PLL_FRAC */ | 63 | /* AUX_PLL_FRAC */ |
60 | cx25840_write4(client, 0x110, 0xd66bec00); | 64 | cx25840_write4(client, 0x110, 0xd66bec00); |
61 | 65 | ||
66 | if (state->is_cx25836) | ||
67 | break; | ||
68 | |||
62 | /* src3/4/6_ctl = 0x08016d59 */ | 69 | /* src3/4/6_ctl = 0x08016d59 */ |
63 | cx25840_write4(client, 0x900, 0x596d0108); | 70 | cx25840_write4(client, 0x900, 0x596d0108); |
64 | cx25840_write4(client, 0x904, 0x596d0108); | 71 | cx25840_write4(client, 0x904, 0x596d0108); |
@@ -72,6 +79,9 @@ static int set_audclk_freq(struct i2c_client *client, u32 freq) | |||
72 | /* AUX_PLL_FRAC */ | 79 | /* AUX_PLL_FRAC */ |
73 | cx25840_write4(client, 0x110, 0xe5d69800); | 80 | cx25840_write4(client, 0x110, 0xe5d69800); |
74 | 81 | ||
82 | if (state->is_cx25836) | ||
83 | break; | ||
84 | |||
75 | /* src3/4/6_ctl = 0x08014faa */ | 85 | /* src3/4/6_ctl = 0x08014faa */ |
76 | cx25840_write4(client, 0x900, 0xaa4f0108); | 86 | cx25840_write4(client, 0x900, 0xaa4f0108); |
77 | cx25840_write4(client, 0x904, 0xaa4f0108); | 87 | cx25840_write4(client, 0x904, 0xaa4f0108); |
@@ -87,6 +97,9 @@ static int set_audclk_freq(struct i2c_client *client, u32 freq) | |||
87 | /* AUX_PLL_FRAC */ | 97 | /* AUX_PLL_FRAC */ |
88 | cx25840_write4(client, 0x110, 0x69082a01); | 98 | cx25840_write4(client, 0x110, 0x69082a01); |
89 | 99 | ||
100 | if (state->is_cx25836) | ||
101 | break; | ||
102 | |||
90 | /* src1_ctl = 0x08010000 */ | 103 | /* src1_ctl = 0x08010000 */ |
91 | cx25840_write4(client, 0x8f8, 0x00000108); | 104 | cx25840_write4(client, 0x8f8, 0x00000108); |
92 | 105 | ||
@@ -106,6 +119,9 @@ static int set_audclk_freq(struct i2c_client *client, u32 freq) | |||
106 | /* AUX_PLL_FRAC */ | 119 | /* AUX_PLL_FRAC */ |
107 | cx25840_write4(client, 0x110, 0xd66bec00); | 120 | cx25840_write4(client, 0x110, 0xd66bec00); |
108 | 121 | ||
122 | if (state->is_cx25836) | ||
123 | break; | ||
124 | |||
109 | /* src1_ctl = 0x08010000 */ | 125 | /* src1_ctl = 0x08010000 */ |
110 | cx25840_write4(client, 0x8f8, 0xcd600108); | 126 | cx25840_write4(client, 0x8f8, 0xcd600108); |
111 | 127 | ||
@@ -122,6 +138,9 @@ static int set_audclk_freq(struct i2c_client *client, u32 freq) | |||
122 | /* AUX_PLL_FRAC */ | 138 | /* AUX_PLL_FRAC */ |
123 | cx25840_write4(client, 0x110, 0xe5d69800); | 139 | cx25840_write4(client, 0x110, 0xe5d69800); |
124 | 140 | ||
141 | if (state->is_cx25836) | ||
142 | break; | ||
143 | |||
125 | /* src1_ctl = 0x08010000 */ | 144 | /* src1_ctl = 0x08010000 */ |
126 | cx25840_write4(client, 0x8f8, 0x00800108); | 145 | cx25840_write4(client, 0x8f8, 0x00800108); |
127 | 146 | ||
@@ -134,7 +153,8 @@ static int set_audclk_freq(struct i2c_client *client, u32 freq) | |||
134 | } | 153 | } |
135 | 154 | ||
136 | /* deassert soft reset */ | 155 | /* deassert soft reset */ |
137 | cx25840_and_or(client, 0x810, ~0x1, 0x00); | 156 | if (!state->is_cx25836) |
157 | cx25840_and_or(client, 0x810, ~0x1, 0x00); | ||
138 | 158 | ||
139 | state->audclk_freq = freq; | 159 | state->audclk_freq = freq; |
140 | 160 | ||
diff --git a/drivers/media/video/cx25840/cx25840-core.c b/drivers/media/video/cx25840/cx25840-core.c index a961bb2ab0fd..e4655e3c2520 100644 --- a/drivers/media/video/cx25840/cx25840-core.c +++ b/drivers/media/video/cx25840/cx25840-core.c | |||
@@ -105,7 +105,7 @@ u32 cx25840_read4(struct i2c_client * client, u16 addr) | |||
105 | (buffer[2] << 8) | buffer[3]; | 105 | (buffer[2] << 8) | buffer[3]; |
106 | } | 106 | } |
107 | 107 | ||
108 | int cx25840_and_or(struct i2c_client *client, u16 addr, u8 and_mask, | 108 | int cx25840_and_or(struct i2c_client *client, u16 addr, unsigned and_mask, |
109 | u8 or_value) | 109 | u8 or_value) |
110 | { | 110 | { |
111 | return cx25840_write(client, addr, | 111 | return cx25840_write(client, addr, |
@@ -117,7 +117,8 @@ int cx25840_and_or(struct i2c_client *client, u16 addr, u8 and_mask, | |||
117 | 117 | ||
118 | static int set_input(struct i2c_client *client, enum cx25840_video_input vid_input, | 118 | static int set_input(struct i2c_client *client, enum cx25840_video_input vid_input, |
119 | enum cx25840_audio_input aud_input); | 119 | enum cx25840_audio_input aud_input); |
120 | static void log_status(struct i2c_client *client); | 120 | static void log_audio_status(struct i2c_client *client); |
121 | static void log_video_status(struct i2c_client *client); | ||
121 | 122 | ||
122 | /* ----------------------------------------------------------------------- */ | 123 | /* ----------------------------------------------------------------------- */ |
123 | 124 | ||
@@ -147,6 +148,33 @@ static void init_dll2(struct i2c_client *client) | |||
147 | cx25840_write(client, 0x15d, 0xe1); | 148 | cx25840_write(client, 0x15d, 0xe1); |
148 | } | 149 | } |
149 | 150 | ||
151 | static void cx25836_initialize(struct i2c_client *client) | ||
152 | { | ||
153 | /* reset configuration is described on page 3-77 of the CX25836 datasheet */ | ||
154 | /* 2. */ | ||
155 | cx25840_and_or(client, 0x000, ~0x01, 0x01); | ||
156 | cx25840_and_or(client, 0x000, ~0x01, 0x00); | ||
157 | /* 3a. */ | ||
158 | cx25840_and_or(client, 0x15a, ~0x70, 0x00); | ||
159 | /* 3b. */ | ||
160 | cx25840_and_or(client, 0x15b, ~0x1e, 0x06); | ||
161 | /* 3c. */ | ||
162 | cx25840_and_or(client, 0x159, ~0x02, 0x02); | ||
163 | /* 3d. */ | ||
164 | /* There should be a 10-us delay here, but since the | ||
165 | i2c bus already has a 10-us delay we don't need to do | ||
166 | anything */ | ||
167 | /* 3e. */ | ||
168 | cx25840_and_or(client, 0x159, ~0x02, 0x00); | ||
169 | /* 3f. */ | ||
170 | cx25840_and_or(client, 0x159, ~0xc0, 0xc0); | ||
171 | /* 3g. */ | ||
172 | cx25840_and_or(client, 0x159, ~0x01, 0x00); | ||
173 | cx25840_and_or(client, 0x159, ~0x01, 0x01); | ||
174 | /* 3h. */ | ||
175 | cx25840_and_or(client, 0x15b, ~0x1e, 0x10); | ||
176 | } | ||
177 | |||
150 | static void cx25840_initialize(struct i2c_client *client, int loadfw) | 178 | static void cx25840_initialize(struct i2c_client *client, int loadfw) |
151 | { | 179 | { |
152 | struct cx25840_state *state = i2c_get_clientdata(client); | 180 | struct cx25840_state *state = i2c_get_clientdata(client); |
@@ -319,8 +347,10 @@ static int set_input(struct i2c_client *client, enum cx25840_video_input vid_inp | |||
319 | 347 | ||
320 | state->vid_input = vid_input; | 348 | state->vid_input = vid_input; |
321 | state->aud_input = aud_input; | 349 | state->aud_input = aud_input; |
322 | cx25840_audio_set_path(client); | 350 | if (!state->is_cx25836) { |
323 | input_change(client); | 351 | cx25840_audio_set_path(client); |
352 | input_change(client); | ||
353 | } | ||
324 | return 0; | 354 | return 0; |
325 | } | 355 | } |
326 | 356 | ||
@@ -370,6 +400,7 @@ static int set_v4lstd(struct i2c_client *client, v4l2_std_id std) | |||
370 | 400 | ||
371 | v4l2_std_id cx25840_get_v4lstd(struct i2c_client * client) | 401 | v4l2_std_id cx25840_get_v4lstd(struct i2c_client * client) |
372 | { | 402 | { |
403 | struct cx25840_state *state = i2c_get_clientdata(client); | ||
373 | /* check VID_FMT_SEL first */ | 404 | /* check VID_FMT_SEL first */ |
374 | u8 fmt = cx25840_read(client, 0x400) & 0xf; | 405 | u8 fmt = cx25840_read(client, 0x400) & 0xf; |
375 | 406 | ||
@@ -383,7 +414,7 @@ v4l2_std_id cx25840_get_v4lstd(struct i2c_client * client) | |||
383 | { | 414 | { |
384 | /* if the audio std is A2-M, then this is the South Korean | 415 | /* if the audio std is A2-M, then this is the South Korean |
385 | NTSC standard */ | 416 | NTSC standard */ |
386 | if (cx25840_read(client, 0x805) == 2) | 417 | if (!state->is_cx25836 && cx25840_read(client, 0x805) == 2) |
387 | return V4L2_STD_NTSC_M_KR; | 418 | return V4L2_STD_NTSC_M_KR; |
388 | return V4L2_STD_NTSC_M; | 419 | return V4L2_STD_NTSC_M; |
389 | } | 420 | } |
@@ -456,6 +487,8 @@ static int set_v4lctrl(struct i2c_client *client, struct v4l2_control *ctrl) | |||
456 | case V4L2_CID_AUDIO_TREBLE: | 487 | case V4L2_CID_AUDIO_TREBLE: |
457 | case V4L2_CID_AUDIO_BALANCE: | 488 | case V4L2_CID_AUDIO_BALANCE: |
458 | case V4L2_CID_AUDIO_MUTE: | 489 | case V4L2_CID_AUDIO_MUTE: |
490 | if (state->is_cx25836) | ||
491 | return -EINVAL; | ||
459 | return cx25840_audio(client, VIDIOC_S_CTRL, ctrl); | 492 | return cx25840_audio(client, VIDIOC_S_CTRL, ctrl); |
460 | 493 | ||
461 | default: | 494 | default: |
@@ -490,6 +523,8 @@ static int get_v4lctrl(struct i2c_client *client, struct v4l2_control *ctrl) | |||
490 | case V4L2_CID_AUDIO_TREBLE: | 523 | case V4L2_CID_AUDIO_TREBLE: |
491 | case V4L2_CID_AUDIO_BALANCE: | 524 | case V4L2_CID_AUDIO_BALANCE: |
492 | case V4L2_CID_AUDIO_MUTE: | 525 | case V4L2_CID_AUDIO_MUTE: |
526 | if (state->is_cx25836) | ||
527 | return -EINVAL; | ||
493 | return cx25840_audio(client, VIDIOC_G_CTRL, ctrl); | 528 | return cx25840_audio(client, VIDIOC_G_CTRL, ctrl); |
494 | default: | 529 | default: |
495 | return -EINVAL; | 530 | return -EINVAL; |
@@ -579,7 +614,7 @@ static int set_v4lfmt(struct i2c_client *client, struct v4l2_format *fmt) | |||
579 | 614 | ||
580 | /* ----------------------------------------------------------------------- */ | 615 | /* ----------------------------------------------------------------------- */ |
581 | 616 | ||
582 | static struct v4l2_queryctrl cx25840_qctrl[] = { | 617 | static struct v4l2_queryctrl cx25836_qctrl[] = { |
583 | { | 618 | { |
584 | .id = V4L2_CID_BRIGHTNESS, | 619 | .id = V4L2_CID_BRIGHTNESS, |
585 | .type = V4L2_CTRL_TYPE_INTEGER, | 620 | .type = V4L2_CTRL_TYPE_INTEGER, |
@@ -616,7 +651,11 @@ static struct v4l2_queryctrl cx25840_qctrl[] = { | |||
616 | .step = 1, | 651 | .step = 1, |
617 | .default_value = 0, | 652 | .default_value = 0, |
618 | .flags = 0, | 653 | .flags = 0, |
619 | }, { | 654 | }, |
655 | }; | ||
656 | |||
657 | static struct v4l2_queryctrl cx25840_qctrl[] = { | ||
658 | { | ||
620 | .id = V4L2_CID_AUDIO_VOLUME, | 659 | .id = V4L2_CID_AUDIO_VOLUME, |
621 | .type = V4L2_CTRL_TYPE_INTEGER, | 660 | .type = V4L2_CTRL_TYPE_INTEGER, |
622 | .name = "Volume", | 661 | .name = "Volume", |
@@ -706,8 +745,8 @@ static int cx25840_command(struct i2c_client *client, unsigned int cmd, | |||
706 | 745 | ||
707 | case VIDIOC_STREAMON: | 746 | case VIDIOC_STREAMON: |
708 | v4l_dbg(1, cx25840_debug, client, "enable output\n"); | 747 | v4l_dbg(1, cx25840_debug, client, "enable output\n"); |
709 | cx25840_write(client, 0x115, 0x8c); | 748 | cx25840_write(client, 0x115, state->is_cx25836 ? 0x0c : 0x8c); |
710 | cx25840_write(client, 0x116, 0x07); | 749 | cx25840_write(client, 0x116, state->is_cx25836 ? 0x04 : 0x07); |
711 | break; | 750 | break; |
712 | 751 | ||
713 | case VIDIOC_STREAMOFF: | 752 | case VIDIOC_STREAMOFF: |
@@ -717,7 +756,9 @@ static int cx25840_command(struct i2c_client *client, unsigned int cmd, | |||
717 | break; | 756 | break; |
718 | 757 | ||
719 | case VIDIOC_LOG_STATUS: | 758 | case VIDIOC_LOG_STATUS: |
720 | log_status(client); | 759 | log_video_status(client); |
760 | if (!state->is_cx25836) | ||
761 | log_audio_status(client); | ||
721 | break; | 762 | break; |
722 | 763 | ||
723 | case VIDIOC_G_CTRL: | 764 | case VIDIOC_G_CTRL: |
@@ -731,6 +772,14 @@ static int cx25840_command(struct i2c_client *client, unsigned int cmd, | |||
731 | struct v4l2_queryctrl *qc = arg; | 772 | struct v4l2_queryctrl *qc = arg; |
732 | int i; | 773 | int i; |
733 | 774 | ||
775 | for (i = 0; i < ARRAY_SIZE(cx25836_qctrl); i++) | ||
776 | if (qc->id && qc->id == cx25836_qctrl[i].id) { | ||
777 | memcpy(qc, &cx25836_qctrl[i], sizeof(*qc)); | ||
778 | return 0; | ||
779 | } | ||
780 | if (state->is_cx25836) | ||
781 | return -EINVAL; | ||
782 | |||
734 | for (i = 0; i < ARRAY_SIZE(cx25840_qctrl); i++) | 783 | for (i = 0; i < ARRAY_SIZE(cx25840_qctrl); i++) |
735 | if (qc->id && qc->id == cx25840_qctrl[i].id) { | 784 | if (qc->id && qc->id == cx25840_qctrl[i].id) { |
736 | memcpy(qc, &cx25840_qctrl[i], sizeof(*qc)); | 785 | memcpy(qc, &cx25840_qctrl[i], sizeof(*qc)); |
@@ -760,31 +809,41 @@ static int cx25840_command(struct i2c_client *client, unsigned int cmd, | |||
760 | return set_input(client, route->input, state->aud_input); | 809 | return set_input(client, route->input, state->aud_input); |
761 | 810 | ||
762 | case VIDIOC_INT_G_AUDIO_ROUTING: | 811 | case VIDIOC_INT_G_AUDIO_ROUTING: |
812 | if (state->is_cx25836) | ||
813 | return -EINVAL; | ||
763 | route->input = state->aud_input; | 814 | route->input = state->aud_input; |
764 | route->output = 0; | 815 | route->output = 0; |
765 | break; | 816 | break; |
766 | 817 | ||
767 | case VIDIOC_INT_S_AUDIO_ROUTING: | 818 | case VIDIOC_INT_S_AUDIO_ROUTING: |
819 | if (state->is_cx25836) | ||
820 | return -EINVAL; | ||
768 | return set_input(client, state->vid_input, route->input); | 821 | return set_input(client, state->vid_input, route->input); |
769 | 822 | ||
770 | case VIDIOC_S_FREQUENCY: | 823 | case VIDIOC_S_FREQUENCY: |
771 | input_change(client); | 824 | if (!state->is_cx25836) { |
825 | input_change(client); | ||
826 | } | ||
772 | break; | 827 | break; |
773 | 828 | ||
774 | case VIDIOC_G_TUNER: | 829 | case VIDIOC_G_TUNER: |
775 | { | 830 | { |
776 | u8 mode = cx25840_read(client, 0x804); | 831 | u8 vpres = cx25840_read(client, 0x40e) & 0x20; |
777 | u8 vpres = cx25840_read(client, 0x80a) & 0x10; | 832 | u8 mode; |
778 | int val = 0; | 833 | int val = 0; |
779 | 834 | ||
780 | if (state->radio) | 835 | if (state->radio) |
781 | break; | 836 | break; |
782 | 837 | ||
838 | vt->signal = vpres ? 0xffff : 0x0; | ||
839 | if (state->is_cx25836) | ||
840 | break; | ||
841 | |||
783 | vt->capability |= | 842 | vt->capability |= |
784 | V4L2_TUNER_CAP_STEREO | V4L2_TUNER_CAP_LANG1 | | 843 | V4L2_TUNER_CAP_STEREO | V4L2_TUNER_CAP_LANG1 | |
785 | V4L2_TUNER_CAP_LANG2 | V4L2_TUNER_CAP_SAP; | 844 | V4L2_TUNER_CAP_LANG2 | V4L2_TUNER_CAP_SAP; |
786 | 845 | ||
787 | vt->signal = vpres ? 0xffff : 0x0; | 846 | mode = cx25840_read(client, 0x804); |
788 | 847 | ||
789 | /* get rxsubchans and audmode */ | 848 | /* get rxsubchans and audmode */ |
790 | if ((mode & 0xf) == 1) | 849 | if ((mode & 0xf) == 1) |
@@ -804,7 +863,7 @@ static int cx25840_command(struct i2c_client *client, unsigned int cmd, | |||
804 | } | 863 | } |
805 | 864 | ||
806 | case VIDIOC_S_TUNER: | 865 | case VIDIOC_S_TUNER: |
807 | if (state->radio) | 866 | if (state->radio || state->is_cx25836) |
808 | break; | 867 | break; |
809 | 868 | ||
810 | switch (vt->audmode) { | 869 | switch (vt->audmode) { |
@@ -846,12 +905,14 @@ static int cx25840_command(struct i2c_client *client, unsigned int cmd, | |||
846 | return set_v4lfmt(client, (struct v4l2_format *)arg); | 905 | return set_v4lfmt(client, (struct v4l2_format *)arg); |
847 | 906 | ||
848 | case VIDIOC_INT_RESET: | 907 | case VIDIOC_INT_RESET: |
849 | cx25840_initialize(client, 0); | 908 | if (state->is_cx25836) |
909 | cx25836_initialize(client); | ||
910 | else | ||
911 | cx25840_initialize(client, 0); | ||
850 | break; | 912 | break; |
851 | 913 | ||
852 | case VIDIOC_INT_G_CHIP_IDENT: | 914 | case VIDIOC_INT_G_CHIP_IDENT: |
853 | *(enum v4l2_chip_ident *)arg = | 915 | *(enum v4l2_chip_ident *)arg = state->id; |
854 | V4L2_IDENT_CX25840 + ((cx25840_read(client, 0x100) >> 4) & 0xf); | ||
855 | break; | 916 | break; |
856 | 917 | ||
857 | default: | 918 | default: |
@@ -870,6 +931,7 @@ static int cx25840_detect_client(struct i2c_adapter *adapter, int address, | |||
870 | { | 931 | { |
871 | struct i2c_client *client; | 932 | struct i2c_client *client; |
872 | struct cx25840_state *state; | 933 | struct cx25840_state *state; |
934 | enum v4l2_chip_ident id; | ||
873 | u16 device_id; | 935 | u16 device_id; |
874 | 936 | ||
875 | /* Check if the adapter supports the needed features | 937 | /* Check if the adapter supports the needed features |
@@ -878,10 +940,11 @@ static int cx25840_detect_client(struct i2c_adapter *adapter, int address, | |||
878 | if (!i2c_check_functionality(adapter, I2C_FUNC_I2C)) | 940 | if (!i2c_check_functionality(adapter, I2C_FUNC_I2C)) |
879 | return 0; | 941 | return 0; |
880 | 942 | ||
881 | client = kzalloc(sizeof(struct i2c_client), GFP_KERNEL); | 943 | state = kzalloc(sizeof(struct cx25840_state), GFP_KERNEL); |
882 | if (client == 0) | 944 | if (state == 0) |
883 | return -ENOMEM; | 945 | return -ENOMEM; |
884 | 946 | ||
947 | client = &state->c; | ||
885 | client->addr = address; | 948 | client->addr = address; |
886 | client->adapter = adapter; | 949 | client->adapter = adapter; |
887 | client->driver = &i2c_driver_cx25840; | 950 | client->driver = &i2c_driver_cx25840; |
@@ -893,10 +956,18 @@ static int cx25840_detect_client(struct i2c_adapter *adapter, int address, | |||
893 | device_id |= cx25840_read(client, 0x100); | 956 | device_id |= cx25840_read(client, 0x100); |
894 | 957 | ||
895 | /* The high byte of the device ID should be | 958 | /* The high byte of the device ID should be |
896 | * 0x84 if chip is present */ | 959 | * 0x83 for the cx2583x and 0x84 for the cx2584x */ |
897 | if ((device_id & 0xff00) != 0x8400) { | 960 | if ((device_id & 0xff00) == 0x8300) { |
961 | id = V4L2_IDENT_CX25836 + ((device_id >> 4) & 0xf) - 6; | ||
962 | state->is_cx25836 = 1; | ||
963 | } | ||
964 | else if ((device_id & 0xff00) == 0x8400) { | ||
965 | id = V4L2_IDENT_CX25840 + ((device_id >> 4) & 0xf); | ||
966 | state->is_cx25836 = 0; | ||
967 | } | ||
968 | else { | ||
898 | v4l_dbg(1, cx25840_debug, client, "cx25840 not found\n"); | 969 | v4l_dbg(1, cx25840_debug, client, "cx25840 not found\n"); |
899 | kfree(client); | 970 | kfree(state); |
900 | return 0; | 971 | return 0; |
901 | } | 972 | } |
902 | 973 | ||
@@ -905,21 +976,18 @@ static int cx25840_detect_client(struct i2c_adapter *adapter, int address, | |||
905 | (device_id & 0x0f) < 3 ? (device_id & 0x0f) + 1 : 3, | 976 | (device_id & 0x0f) < 3 ? (device_id & 0x0f) + 1 : 3, |
906 | address << 1, adapter->name); | 977 | address << 1, adapter->name); |
907 | 978 | ||
908 | state = kmalloc(sizeof(struct cx25840_state), GFP_KERNEL); | ||
909 | if (state == NULL) { | ||
910 | kfree(client); | ||
911 | return -ENOMEM; | ||
912 | } | ||
913 | |||
914 | i2c_set_clientdata(client, state); | 979 | i2c_set_clientdata(client, state); |
915 | memset(state, 0, sizeof(struct cx25840_state)); | ||
916 | state->vid_input = CX25840_COMPOSITE7; | 980 | state->vid_input = CX25840_COMPOSITE7; |
917 | state->aud_input = CX25840_AUDIO8; | 981 | state->aud_input = CX25840_AUDIO8; |
918 | state->audclk_freq = 48000; | 982 | state->audclk_freq = 48000; |
919 | state->pvr150_workaround = 0; | 983 | state->pvr150_workaround = 0; |
920 | state->audmode = V4L2_TUNER_MODE_LANG1; | 984 | state->audmode = V4L2_TUNER_MODE_LANG1; |
985 | state->id = id; | ||
921 | 986 | ||
922 | cx25840_initialize(client, 1); | 987 | if (state->is_cx25836) |
988 | cx25836_initialize(client); | ||
989 | else | ||
990 | cx25840_initialize(client, 1); | ||
923 | 991 | ||
924 | i2c_attach_client(client); | 992 | i2c_attach_client(client); |
925 | 993 | ||
@@ -944,7 +1012,6 @@ static int cx25840_detach_client(struct i2c_client *client) | |||
944 | } | 1012 | } |
945 | 1013 | ||
946 | kfree(state); | 1014 | kfree(state); |
947 | kfree(client); | ||
948 | 1015 | ||
949 | return 0; | 1016 | return 0; |
950 | } | 1017 | } |
@@ -977,7 +1044,7 @@ module_exit(m__exit); | |||
977 | 1044 | ||
978 | /* ----------------------------------------------------------------------- */ | 1045 | /* ----------------------------------------------------------------------- */ |
979 | 1046 | ||
980 | static void log_status(struct i2c_client *client) | 1047 | static void log_video_status(struct i2c_client *client) |
981 | { | 1048 | { |
982 | static const char *const fmt_strs[] = { | 1049 | static const char *const fmt_strs[] = { |
983 | "0x0", | 1050 | "0x0", |
@@ -989,9 +1056,36 @@ static void log_status(struct i2c_client *client) | |||
989 | }; | 1056 | }; |
990 | 1057 | ||
991 | struct cx25840_state *state = i2c_get_clientdata(client); | 1058 | struct cx25840_state *state = i2c_get_clientdata(client); |
992 | u8 microctrl_vidfmt = cx25840_read(client, 0x80a); | ||
993 | u8 vidfmt_sel = cx25840_read(client, 0x400) & 0xf; | 1059 | u8 vidfmt_sel = cx25840_read(client, 0x400) & 0xf; |
994 | u8 gen_stat1 = cx25840_read(client, 0x40d); | 1060 | u8 gen_stat1 = cx25840_read(client, 0x40d); |
1061 | u8 gen_stat2 = cx25840_read(client, 0x40e); | ||
1062 | int vid_input = state->vid_input; | ||
1063 | |||
1064 | v4l_info(client, "Video signal: %spresent\n", | ||
1065 | (gen_stat2 & 0x20) ? "" : "not "); | ||
1066 | v4l_info(client, "Detected format: %s\n", | ||
1067 | fmt_strs[gen_stat1 & 0xf]); | ||
1068 | |||
1069 | v4l_info(client, "Specified standard: %s\n", | ||
1070 | vidfmt_sel ? fmt_strs[vidfmt_sel] : "automatic detection"); | ||
1071 | |||
1072 | if (vid_input >= CX25840_COMPOSITE1 && | ||
1073 | vid_input <= CX25840_COMPOSITE8) { | ||
1074 | v4l_info(client, "Specified video input: Composite %d\n", | ||
1075 | vid_input - CX25840_COMPOSITE1 + 1); | ||
1076 | } else { | ||
1077 | v4l_info(client, "Specified video input: S-Video (Luma In%d, Chroma In%d)\n", | ||
1078 | (vid_input & 0xf0) >> 4, (vid_input & 0xf00) >> 8); | ||
1079 | } | ||
1080 | |||
1081 | v4l_info(client, "Specified audioclock freq: %d Hz\n", state->audclk_freq); | ||
1082 | } | ||
1083 | |||
1084 | /* ----------------------------------------------------------------------- */ | ||
1085 | |||
1086 | static void log_audio_status(struct i2c_client *client) | ||
1087 | { | ||
1088 | struct cx25840_state *state = i2c_get_clientdata(client); | ||
995 | u8 download_ctl = cx25840_read(client, 0x803); | 1089 | u8 download_ctl = cx25840_read(client, 0x803); |
996 | u8 mod_det_stat0 = cx25840_read(client, 0x804); | 1090 | u8 mod_det_stat0 = cx25840_read(client, 0x804); |
997 | u8 mod_det_stat1 = cx25840_read(client, 0x805); | 1091 | u8 mod_det_stat1 = cx25840_read(client, 0x805); |
@@ -999,15 +1093,9 @@ static void log_status(struct i2c_client *client) | |||
999 | u8 pref_mode = cx25840_read(client, 0x809); | 1093 | u8 pref_mode = cx25840_read(client, 0x809); |
1000 | u8 afc0 = cx25840_read(client, 0x80b); | 1094 | u8 afc0 = cx25840_read(client, 0x80b); |
1001 | u8 mute_ctl = cx25840_read(client, 0x8d3); | 1095 | u8 mute_ctl = cx25840_read(client, 0x8d3); |
1002 | int vid_input = state->vid_input; | ||
1003 | int aud_input = state->aud_input; | 1096 | int aud_input = state->aud_input; |
1004 | char *p; | 1097 | char *p; |
1005 | 1098 | ||
1006 | v4l_info(client, "Video signal: %spresent\n", | ||
1007 | (microctrl_vidfmt & 0x10) ? "" : "not "); | ||
1008 | v4l_info(client, "Detected format: %s\n", | ||
1009 | fmt_strs[gen_stat1 & 0xf]); | ||
1010 | |||
1011 | switch (mod_det_stat0) { | 1099 | switch (mod_det_stat0) { |
1012 | case 0x00: p = "mono"; break; | 1100 | case 0x00: p = "mono"; break; |
1013 | case 0x01: p = "stereo"; break; | 1101 | case 0x01: p = "stereo"; break; |
@@ -1107,25 +1195,12 @@ static void log_status(struct i2c_client *client) | |||
1107 | v4l_info(client, "Configured audio system: %s\n", p); | 1195 | v4l_info(client, "Configured audio system: %s\n", p); |
1108 | } | 1196 | } |
1109 | 1197 | ||
1110 | v4l_info(client, "Specified standard: %s\n", | ||
1111 | vidfmt_sel ? fmt_strs[vidfmt_sel] : "automatic detection"); | ||
1112 | |||
1113 | if (vid_input >= CX25840_COMPOSITE1 && | ||
1114 | vid_input <= CX25840_COMPOSITE8) { | ||
1115 | v4l_info(client, "Specified video input: Composite %d\n", | ||
1116 | vid_input - CX25840_COMPOSITE1 + 1); | ||
1117 | } else { | ||
1118 | v4l_info(client, "Specified video input: S-Video (Luma In%d, Chroma In%d)\n", | ||
1119 | (vid_input & 0xf0) >> 4, (vid_input & 0xf00) >> 8); | ||
1120 | } | ||
1121 | if (aud_input) { | 1198 | if (aud_input) { |
1122 | v4l_info(client, "Specified audio input: Tuner (In%d)\n", aud_input); | 1199 | v4l_info(client, "Specified audio input: Tuner (In%d)\n", aud_input); |
1123 | } else { | 1200 | } else { |
1124 | v4l_info(client, "Specified audio input: External\n"); | 1201 | v4l_info(client, "Specified audio input: External\n"); |
1125 | } | 1202 | } |
1126 | 1203 | ||
1127 | v4l_info(client, "Specified audioclock freq: %d Hz\n", state->audclk_freq); | ||
1128 | |||
1129 | switch (pref_mode & 0xf) { | 1204 | switch (pref_mode & 0xf) { |
1130 | case 0: p = "mono/language A"; break; | 1205 | case 0: p = "mono/language A"; break; |
1131 | case 1: p = "language B"; break; | 1206 | case 1: p = "language B"; break; |
diff --git a/drivers/media/video/cx25840/cx25840-core.h b/drivers/media/video/cx25840/cx25840-core.h index 1736929fc204..69d7bd2bcb29 100644 --- a/drivers/media/video/cx25840/cx25840-core.h +++ b/drivers/media/video/cx25840/cx25840-core.h | |||
@@ -33,12 +33,15 @@ | |||
33 | #define CX25840_CID_ENABLE_PVR150_WORKAROUND (V4L2_CID_PRIVATE_BASE+0) | 33 | #define CX25840_CID_ENABLE_PVR150_WORKAROUND (V4L2_CID_PRIVATE_BASE+0) |
34 | 34 | ||
35 | struct cx25840_state { | 35 | struct cx25840_state { |
36 | struct i2c_client c; | ||
36 | int pvr150_workaround; | 37 | int pvr150_workaround; |
37 | int radio; | 38 | int radio; |
38 | enum cx25840_video_input vid_input; | 39 | enum cx25840_video_input vid_input; |
39 | enum cx25840_audio_input aud_input; | 40 | enum cx25840_audio_input aud_input; |
40 | u32 audclk_freq; | 41 | u32 audclk_freq; |
41 | int audmode; | 42 | int audmode; |
43 | enum v4l2_chip_ident id; | ||
44 | int is_cx25836; | ||
42 | }; | 45 | }; |
43 | 46 | ||
44 | /* ----------------------------------------------------------------------- */ | 47 | /* ----------------------------------------------------------------------- */ |
@@ -47,7 +50,7 @@ int cx25840_write(struct i2c_client *client, u16 addr, u8 value); | |||
47 | int cx25840_write4(struct i2c_client *client, u16 addr, u32 value); | 50 | int cx25840_write4(struct i2c_client *client, u16 addr, u32 value); |
48 | u8 cx25840_read(struct i2c_client *client, u16 addr); | 51 | u8 cx25840_read(struct i2c_client *client, u16 addr); |
49 | u32 cx25840_read4(struct i2c_client *client, u16 addr); | 52 | u32 cx25840_read4(struct i2c_client *client, u16 addr); |
50 | int cx25840_and_or(struct i2c_client *client, u16 addr, u8 mask, u8 value); | 53 | int cx25840_and_or(struct i2c_client *client, u16 addr, unsigned mask, u8 value); |
51 | v4l2_std_id cx25840_get_v4lstd(struct i2c_client *client); | 54 | v4l2_std_id cx25840_get_v4lstd(struct i2c_client *client); |
52 | 55 | ||
53 | /* ----------------------------------------------------------------------- */ | 56 | /* ----------------------------------------------------------------------- */ |