diff options
author | Mauro Carvalho Chehab <mchehab@redhat.com> | 2012-08-14 15:23:43 -0400 |
---|---|---|
committer | Mauro Carvalho Chehab <mchehab@redhat.com> | 2012-08-15 15:42:14 -0400 |
commit | cb7a01ac324bf2ee2c666f37ac867e4135f9785a (patch) | |
tree | 7246b915a9334d4bc823c93ba9acab65ef882678 /drivers/media/i2c/msp3400-kthreads.c | |
parent | f0af8fa4dad0839f844fd0633e1936493f6d685a (diff) |
[media] move i2c files into drivers/media/i2c
Move ancillary I2C drivers into drivers/media/i2c, in order to
better organize them.
Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com>
Diffstat (limited to 'drivers/media/i2c/msp3400-kthreads.c')
-rw-r--r-- | drivers/media/i2c/msp3400-kthreads.c | 1165 |
1 files changed, 1165 insertions, 0 deletions
diff --git a/drivers/media/i2c/msp3400-kthreads.c b/drivers/media/i2c/msp3400-kthreads.c new file mode 100644 index 000000000000..f8b51714f2f9 --- /dev/null +++ b/drivers/media/i2c/msp3400-kthreads.c | |||
@@ -0,0 +1,1165 @@ | |||
1 | /* | ||
2 | * Programming the mspx4xx sound processor family | ||
3 | * | ||
4 | * (c) 1997-2001 Gerd Knorr <kraxel@bytesex.org> | ||
5 | * | ||
6 | * This program is free software; you can redistribute it and/or | ||
7 | * modify it under the terms of the GNU General Public License | ||
8 | * as published by the Free Software Foundation; either version 2 | ||
9 | * of the License, or (at your option) any later version. | ||
10 | * | ||
11 | * This program is distributed in the hope that it will be useful, | ||
12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
14 | * GNU General Public License for more details. | ||
15 | * | ||
16 | * You should have received a copy of the GNU General Public License | ||
17 | * along with this program; if not, write to the Free Software | ||
18 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA | ||
19 | * 02110-1301, USA. | ||
20 | */ | ||
21 | |||
22 | |||
23 | #include <linux/kernel.h> | ||
24 | #include <linux/module.h> | ||
25 | #include <linux/i2c.h> | ||
26 | #include <linux/freezer.h> | ||
27 | #include <linux/videodev2.h> | ||
28 | #include <media/v4l2-common.h> | ||
29 | #include <media/msp3400.h> | ||
30 | #include <linux/kthread.h> | ||
31 | #include <linux/suspend.h> | ||
32 | #include "msp3400-driver.h" | ||
33 | |||
34 | /* this one uses the automatic sound standard detection of newer msp34xx | ||
35 | chip versions */ | ||
36 | static struct { | ||
37 | int retval; | ||
38 | int main, second; | ||
39 | char *name; | ||
40 | v4l2_std_id std; | ||
41 | } msp_stdlist[] = { | ||
42 | { 0x0000, 0, 0, "could not detect sound standard", V4L2_STD_ALL }, | ||
43 | { 0x0001, 0, 0, "autodetect start", V4L2_STD_ALL }, | ||
44 | { 0x0002, MSP_CARRIER(4.5), MSP_CARRIER(4.72), | ||
45 | "4.5/4.72 M Dual FM-Stereo", V4L2_STD_MN }, | ||
46 | { 0x0003, MSP_CARRIER(5.5), MSP_CARRIER(5.7421875), | ||
47 | "5.5/5.74 B/G Dual FM-Stereo", V4L2_STD_BG }, | ||
48 | { 0x0004, MSP_CARRIER(6.5), MSP_CARRIER(6.2578125), | ||
49 | "6.5/6.25 D/K1 Dual FM-Stereo", V4L2_STD_DK }, | ||
50 | { 0x0005, MSP_CARRIER(6.5), MSP_CARRIER(6.7421875), | ||
51 | "6.5/6.74 D/K2 Dual FM-Stereo", V4L2_STD_DK }, | ||
52 | { 0x0006, MSP_CARRIER(6.5), MSP_CARRIER(6.5), | ||
53 | "6.5 D/K FM-Mono (HDEV3)", V4L2_STD_DK }, | ||
54 | { 0x0007, MSP_CARRIER(6.5), MSP_CARRIER(5.7421875), | ||
55 | "6.5/5.74 D/K3 Dual FM-Stereo", V4L2_STD_DK }, | ||
56 | { 0x0008, MSP_CARRIER(5.5), MSP_CARRIER(5.85), | ||
57 | "5.5/5.85 B/G NICAM FM", V4L2_STD_BG }, | ||
58 | { 0x0009, MSP_CARRIER(6.5), MSP_CARRIER(5.85), | ||
59 | "6.5/5.85 L NICAM AM", V4L2_STD_L }, | ||
60 | { 0x000a, MSP_CARRIER(6.0), MSP_CARRIER(6.55), | ||
61 | "6.0/6.55 I NICAM FM", V4L2_STD_PAL_I }, | ||
62 | { 0x000b, MSP_CARRIER(6.5), MSP_CARRIER(5.85), | ||
63 | "6.5/5.85 D/K NICAM FM", V4L2_STD_DK }, | ||
64 | { 0x000c, MSP_CARRIER(6.5), MSP_CARRIER(5.85), | ||
65 | "6.5/5.85 D/K NICAM FM (HDEV2)", V4L2_STD_DK }, | ||
66 | { 0x000d, MSP_CARRIER(6.5), MSP_CARRIER(5.85), | ||
67 | "6.5/5.85 D/K NICAM FM (HDEV3)", V4L2_STD_DK }, | ||
68 | { 0x0020, MSP_CARRIER(4.5), MSP_CARRIER(4.5), | ||
69 | "4.5 M BTSC-Stereo", V4L2_STD_MTS }, | ||
70 | { 0x0021, MSP_CARRIER(4.5), MSP_CARRIER(4.5), | ||
71 | "4.5 M BTSC-Mono + SAP", V4L2_STD_MTS }, | ||
72 | { 0x0030, MSP_CARRIER(4.5), MSP_CARRIER(4.5), | ||
73 | "4.5 M EIA-J Japan Stereo", V4L2_STD_NTSC_M_JP }, | ||
74 | { 0x0040, MSP_CARRIER(10.7), MSP_CARRIER(10.7), | ||
75 | "10.7 FM-Stereo Radio", V4L2_STD_ALL }, | ||
76 | { 0x0050, MSP_CARRIER(6.5), MSP_CARRIER(6.5), | ||
77 | "6.5 SAT-Mono", V4L2_STD_ALL }, | ||
78 | { 0x0051, MSP_CARRIER(7.02), MSP_CARRIER(7.20), | ||
79 | "7.02/7.20 SAT-Stereo", V4L2_STD_ALL }, | ||
80 | { 0x0060, MSP_CARRIER(7.2), MSP_CARRIER(7.2), | ||
81 | "7.2 SAT ADR", V4L2_STD_ALL }, | ||
82 | { -1, 0, 0, NULL, 0 }, /* EOF */ | ||
83 | }; | ||
84 | |||
85 | static struct msp3400c_init_data_dem { | ||
86 | int fir1[6]; | ||
87 | int fir2[6]; | ||
88 | int cdo1; | ||
89 | int cdo2; | ||
90 | int ad_cv; | ||
91 | int mode_reg; | ||
92 | int dsp_src; | ||
93 | int dsp_matrix; | ||
94 | } msp3400c_init_data[] = { | ||
95 | { /* AM (for carrier detect / msp3400) */ | ||
96 | {75, 19, 36, 35, 39, 40}, | ||
97 | {75, 19, 36, 35, 39, 40}, | ||
98 | MSP_CARRIER(5.5), MSP_CARRIER(5.5), | ||
99 | 0x00d0, 0x0500, 0x0020, 0x3000 | ||
100 | }, { /* AM (for carrier detect / msp3410) */ | ||
101 | {-1, -1, -8, 2, 59, 126}, | ||
102 | {-1, -1, -8, 2, 59, 126}, | ||
103 | MSP_CARRIER(5.5), MSP_CARRIER(5.5), | ||
104 | 0x00d0, 0x0100, 0x0020, 0x3000 | ||
105 | }, { /* FM Radio */ | ||
106 | {-8, -8, 4, 6, 78, 107}, | ||
107 | {-8, -8, 4, 6, 78, 107}, | ||
108 | MSP_CARRIER(10.7), MSP_CARRIER(10.7), | ||
109 | 0x00d0, 0x0480, 0x0020, 0x3000 | ||
110 | }, { /* Terrestrial FM-mono + FM-stereo */ | ||
111 | {3, 18, 27, 48, 66, 72}, | ||
112 | {3, 18, 27, 48, 66, 72}, | ||
113 | MSP_CARRIER(5.5), MSP_CARRIER(5.5), | ||
114 | 0x00d0, 0x0480, 0x0030, 0x3000 | ||
115 | }, { /* Sat FM-mono */ | ||
116 | { 1, 9, 14, 24, 33, 37}, | ||
117 | { 3, 18, 27, 48, 66, 72}, | ||
118 | MSP_CARRIER(6.5), MSP_CARRIER(6.5), | ||
119 | 0x00c6, 0x0480, 0x0000, 0x3000 | ||
120 | }, { /* NICAM/FM -- B/G (5.5/5.85), D/K (6.5/5.85) */ | ||
121 | {-2, -8, -10, 10, 50, 86}, | ||
122 | {3, 18, 27, 48, 66, 72}, | ||
123 | MSP_CARRIER(5.5), MSP_CARRIER(5.5), | ||
124 | 0x00d0, 0x0040, 0x0120, 0x3000 | ||
125 | }, { /* NICAM/FM -- I (6.0/6.552) */ | ||
126 | {2, 4, -6, -4, 40, 94}, | ||
127 | {3, 18, 27, 48, 66, 72}, | ||
128 | MSP_CARRIER(6.0), MSP_CARRIER(6.0), | ||
129 | 0x00d0, 0x0040, 0x0120, 0x3000 | ||
130 | }, { /* NICAM/AM -- L (6.5/5.85) */ | ||
131 | {-2, -8, -10, 10, 50, 86}, | ||
132 | {-4, -12, -9, 23, 79, 126}, | ||
133 | MSP_CARRIER(6.5), MSP_CARRIER(6.5), | ||
134 | 0x00c6, 0x0140, 0x0120, 0x7c00 | ||
135 | }, | ||
136 | }; | ||
137 | |||
138 | struct msp3400c_carrier_detect { | ||
139 | int cdo; | ||
140 | char *name; | ||
141 | }; | ||
142 | |||
143 | static struct msp3400c_carrier_detect msp3400c_carrier_detect_main[] = { | ||
144 | /* main carrier */ | ||
145 | { MSP_CARRIER(4.5), "4.5 NTSC" }, | ||
146 | { MSP_CARRIER(5.5), "5.5 PAL B/G" }, | ||
147 | { MSP_CARRIER(6.0), "6.0 PAL I" }, | ||
148 | { MSP_CARRIER(6.5), "6.5 PAL D/K + SAT + SECAM" } | ||
149 | }; | ||
150 | |||
151 | static struct msp3400c_carrier_detect msp3400c_carrier_detect_55[] = { | ||
152 | /* PAL B/G */ | ||
153 | { MSP_CARRIER(5.7421875), "5.742 PAL B/G FM-stereo" }, | ||
154 | { MSP_CARRIER(5.85), "5.85 PAL B/G NICAM" } | ||
155 | }; | ||
156 | |||
157 | static struct msp3400c_carrier_detect msp3400c_carrier_detect_65[] = { | ||
158 | /* PAL SAT / SECAM */ | ||
159 | { MSP_CARRIER(5.85), "5.85 PAL D/K + SECAM NICAM" }, | ||
160 | { MSP_CARRIER(6.2578125), "6.25 PAL D/K1 FM-stereo" }, | ||
161 | { MSP_CARRIER(6.7421875), "6.74 PAL D/K2 FM-stereo" }, | ||
162 | { MSP_CARRIER(7.02), "7.02 PAL SAT FM-stereo s/b" }, | ||
163 | { MSP_CARRIER(7.20), "7.20 PAL SAT FM-stereo s" }, | ||
164 | { MSP_CARRIER(7.38), "7.38 PAL SAT FM-stereo b" }, | ||
165 | }; | ||
166 | |||
167 | /* ------------------------------------------------------------------------ */ | ||
168 | |||
169 | const char *msp_standard_std_name(int std) | ||
170 | { | ||
171 | int i; | ||
172 | |||
173 | for (i = 0; msp_stdlist[i].name != NULL; i++) | ||
174 | if (msp_stdlist[i].retval == std) | ||
175 | return msp_stdlist[i].name; | ||
176 | return "unknown"; | ||
177 | } | ||
178 | |||
179 | static v4l2_std_id msp_standard_std(int std) | ||
180 | { | ||
181 | int i; | ||
182 | |||
183 | for (i = 0; msp_stdlist[i].name != NULL; i++) | ||
184 | if (msp_stdlist[i].retval == std) | ||
185 | return msp_stdlist[i].std; | ||
186 | return V4L2_STD_ALL; | ||
187 | } | ||
188 | |||
189 | static void msp_set_source(struct i2c_client *client, u16 src) | ||
190 | { | ||
191 | struct msp_state *state = to_state(i2c_get_clientdata(client)); | ||
192 | |||
193 | if (msp_dolby) { | ||
194 | msp_write_dsp(client, 0x0008, 0x0520); /* I2S1 */ | ||
195 | msp_write_dsp(client, 0x0009, 0x0620); /* I2S2 */ | ||
196 | } else { | ||
197 | msp_write_dsp(client, 0x0008, src); | ||
198 | msp_write_dsp(client, 0x0009, src); | ||
199 | } | ||
200 | msp_write_dsp(client, 0x000a, src); | ||
201 | msp_write_dsp(client, 0x000b, src); | ||
202 | msp_write_dsp(client, 0x000c, src); | ||
203 | if (state->has_scart2_out) | ||
204 | msp_write_dsp(client, 0x0041, src); | ||
205 | } | ||
206 | |||
207 | void msp3400c_set_carrier(struct i2c_client *client, int cdo1, int cdo2) | ||
208 | { | ||
209 | msp_write_dem(client, 0x0093, cdo1 & 0xfff); | ||
210 | msp_write_dem(client, 0x009b, cdo1 >> 12); | ||
211 | msp_write_dem(client, 0x00a3, cdo2 & 0xfff); | ||
212 | msp_write_dem(client, 0x00ab, cdo2 >> 12); | ||
213 | msp_write_dem(client, 0x0056, 0); /* LOAD_REG_1/2 */ | ||
214 | } | ||
215 | |||
216 | void msp3400c_set_mode(struct i2c_client *client, int mode) | ||
217 | { | ||
218 | struct msp_state *state = to_state(i2c_get_clientdata(client)); | ||
219 | struct msp3400c_init_data_dem *data = &msp3400c_init_data[mode]; | ||
220 | int tuner = (state->route_in >> 3) & 1; | ||
221 | int i; | ||
222 | |||
223 | v4l_dbg(1, msp_debug, client, "set_mode: %d\n", mode); | ||
224 | state->mode = mode; | ||
225 | state->rxsubchans = V4L2_TUNER_SUB_MONO; | ||
226 | |||
227 | msp_write_dem(client, 0x00bb, data->ad_cv | (tuner ? 0x100 : 0)); | ||
228 | |||
229 | for (i = 5; i >= 0; i--) /* fir 1 */ | ||
230 | msp_write_dem(client, 0x0001, data->fir1[i]); | ||
231 | |||
232 | msp_write_dem(client, 0x0005, 0x0004); /* fir 2 */ | ||
233 | msp_write_dem(client, 0x0005, 0x0040); | ||
234 | msp_write_dem(client, 0x0005, 0x0000); | ||
235 | for (i = 5; i >= 0; i--) | ||
236 | msp_write_dem(client, 0x0005, data->fir2[i]); | ||
237 | |||
238 | msp_write_dem(client, 0x0083, data->mode_reg); | ||
239 | |||
240 | msp3400c_set_carrier(client, data->cdo1, data->cdo2); | ||
241 | |||
242 | msp_set_source(client, data->dsp_src); | ||
243 | /* set prescales */ | ||
244 | |||
245 | /* volume prescale for SCART (AM mono input) */ | ||
246 | msp_write_dsp(client, 0x000d, 0x1900); | ||
247 | msp_write_dsp(client, 0x000e, data->dsp_matrix); | ||
248 | if (state->has_nicam) /* nicam prescale */ | ||
249 | msp_write_dsp(client, 0x0010, 0x5a00); | ||
250 | } | ||
251 | |||
252 | /* Set audio mode. Note that the pre-'G' models do not support BTSC+SAP, | ||
253 | nor do they support stereo BTSC. */ | ||
254 | static void msp3400c_set_audmode(struct i2c_client *client) | ||
255 | { | ||
256 | static char *strmode[] = { | ||
257 | "mono", "stereo", "lang2", "lang1", "lang1+lang2" | ||
258 | }; | ||
259 | struct msp_state *state = to_state(i2c_get_clientdata(client)); | ||
260 | char *modestr = (state->audmode >= 0 && state->audmode < 5) ? | ||
261 | strmode[state->audmode] : "unknown"; | ||
262 | int src = 0; /* channel source: FM/AM, nicam or SCART */ | ||
263 | int audmode = state->audmode; | ||
264 | |||
265 | if (state->opmode == OPMODE_AUTOSELECT) { | ||
266 | /* this method would break everything, let's make sure | ||
267 | * it's never called | ||
268 | */ | ||
269 | v4l_dbg(1, msp_debug, client, | ||
270 | "set_audmode called with mode=%d instead of set_source (ignored)\n", | ||
271 | state->audmode); | ||
272 | return; | ||
273 | } | ||
274 | |||
275 | /* Note: for the C and D revs no NTSC stereo + SAP is possible as | ||
276 | the hardware does not support SAP. So the rxsubchans combination | ||
277 | of STEREO | LANG2 does not occur. */ | ||
278 | |||
279 | if (state->mode != MSP_MODE_EXTERN) { | ||
280 | /* switch to mono if only mono is available */ | ||
281 | if (state->rxsubchans == V4L2_TUNER_SUB_MONO) | ||
282 | audmode = V4L2_TUNER_MODE_MONO; | ||
283 | /* if bilingual */ | ||
284 | else if (state->rxsubchans & V4L2_TUNER_SUB_LANG2) { | ||
285 | /* and mono or stereo, then fallback to lang1 */ | ||
286 | if (audmode == V4L2_TUNER_MODE_MONO || | ||
287 | audmode == V4L2_TUNER_MODE_STEREO) | ||
288 | audmode = V4L2_TUNER_MODE_LANG1; | ||
289 | } | ||
290 | /* if stereo, and audmode is not mono, then switch to stereo */ | ||
291 | else if (audmode != V4L2_TUNER_MODE_MONO) | ||
292 | audmode = V4L2_TUNER_MODE_STEREO; | ||
293 | } | ||
294 | |||
295 | /* switch demodulator */ | ||
296 | switch (state->mode) { | ||
297 | case MSP_MODE_FM_TERRA: | ||
298 | v4l_dbg(1, msp_debug, client, "FM set_audmode: %s\n", modestr); | ||
299 | switch (audmode) { | ||
300 | case V4L2_TUNER_MODE_STEREO: | ||
301 | msp_write_dsp(client, 0x000e, 0x3001); | ||
302 | break; | ||
303 | case V4L2_TUNER_MODE_MONO: | ||
304 | case V4L2_TUNER_MODE_LANG1: | ||
305 | case V4L2_TUNER_MODE_LANG2: | ||
306 | case V4L2_TUNER_MODE_LANG1_LANG2: | ||
307 | msp_write_dsp(client, 0x000e, 0x3000); | ||
308 | break; | ||
309 | } | ||
310 | break; | ||
311 | case MSP_MODE_FM_SAT: | ||
312 | v4l_dbg(1, msp_debug, client, "SAT set_audmode: %s\n", modestr); | ||
313 | switch (audmode) { | ||
314 | case V4L2_TUNER_MODE_MONO: | ||
315 | msp3400c_set_carrier(client, MSP_CARRIER(6.5), MSP_CARRIER(6.5)); | ||
316 | break; | ||
317 | case V4L2_TUNER_MODE_STEREO: | ||
318 | case V4L2_TUNER_MODE_LANG1_LANG2: | ||
319 | msp3400c_set_carrier(client, MSP_CARRIER(7.2), MSP_CARRIER(7.02)); | ||
320 | break; | ||
321 | case V4L2_TUNER_MODE_LANG1: | ||
322 | msp3400c_set_carrier(client, MSP_CARRIER(7.38), MSP_CARRIER(7.02)); | ||
323 | break; | ||
324 | case V4L2_TUNER_MODE_LANG2: | ||
325 | msp3400c_set_carrier(client, MSP_CARRIER(7.38), MSP_CARRIER(7.02)); | ||
326 | break; | ||
327 | } | ||
328 | break; | ||
329 | case MSP_MODE_FM_NICAM1: | ||
330 | case MSP_MODE_FM_NICAM2: | ||
331 | case MSP_MODE_AM_NICAM: | ||
332 | v4l_dbg(1, msp_debug, client, | ||
333 | "NICAM set_audmode: %s\n", modestr); | ||
334 | if (state->nicam_on) | ||
335 | src = 0x0100; /* NICAM */ | ||
336 | break; | ||
337 | case MSP_MODE_BTSC: | ||
338 | v4l_dbg(1, msp_debug, client, | ||
339 | "BTSC set_audmode: %s\n", modestr); | ||
340 | break; | ||
341 | case MSP_MODE_EXTERN: | ||
342 | v4l_dbg(1, msp_debug, client, | ||
343 | "extern set_audmode: %s\n", modestr); | ||
344 | src = 0x0200; /* SCART */ | ||
345 | break; | ||
346 | case MSP_MODE_FM_RADIO: | ||
347 | v4l_dbg(1, msp_debug, client, | ||
348 | "FM-Radio set_audmode: %s\n", modestr); | ||
349 | break; | ||
350 | default: | ||
351 | v4l_dbg(1, msp_debug, client, "mono set_audmode\n"); | ||
352 | return; | ||
353 | } | ||
354 | |||
355 | /* switch audio */ | ||
356 | v4l_dbg(1, msp_debug, client, "set audmode %d\n", audmode); | ||
357 | switch (audmode) { | ||
358 | case V4L2_TUNER_MODE_STEREO: | ||
359 | case V4L2_TUNER_MODE_LANG1_LANG2: | ||
360 | src |= 0x0020; | ||
361 | break; | ||
362 | case V4L2_TUNER_MODE_MONO: | ||
363 | if (state->mode == MSP_MODE_AM_NICAM) { | ||
364 | v4l_dbg(1, msp_debug, client, "switching to AM mono\n"); | ||
365 | /* AM mono decoding is handled by tuner, not MSP chip */ | ||
366 | /* SCART switching control register */ | ||
367 | msp_set_scart(client, SCART_MONO, 0); | ||
368 | src = 0x0200; | ||
369 | break; | ||
370 | } | ||
371 | if (state->rxsubchans & V4L2_TUNER_SUB_STEREO) | ||
372 | src = 0x0030; | ||
373 | break; | ||
374 | case V4L2_TUNER_MODE_LANG1: | ||
375 | break; | ||
376 | case V4L2_TUNER_MODE_LANG2: | ||
377 | src |= 0x0010; | ||
378 | break; | ||
379 | } | ||
380 | v4l_dbg(1, msp_debug, client, | ||
381 | "set_audmode final source/matrix = 0x%x\n", src); | ||
382 | |||
383 | msp_set_source(client, src); | ||
384 | } | ||
385 | |||
386 | static void msp3400c_print_mode(struct i2c_client *client) | ||
387 | { | ||
388 | struct msp_state *state = to_state(i2c_get_clientdata(client)); | ||
389 | |||
390 | if (state->main == state->second) | ||
391 | v4l_dbg(1, msp_debug, client, | ||
392 | "mono sound carrier: %d.%03d MHz\n", | ||
393 | state->main / 910000, (state->main / 910) % 1000); | ||
394 | else | ||
395 | v4l_dbg(1, msp_debug, client, | ||
396 | "main sound carrier: %d.%03d MHz\n", | ||
397 | state->main / 910000, (state->main / 910) % 1000); | ||
398 | if (state->mode == MSP_MODE_FM_NICAM1 || state->mode == MSP_MODE_FM_NICAM2) | ||
399 | v4l_dbg(1, msp_debug, client, | ||
400 | "NICAM/FM carrier : %d.%03d MHz\n", | ||
401 | state->second / 910000, (state->second/910) % 1000); | ||
402 | if (state->mode == MSP_MODE_AM_NICAM) | ||
403 | v4l_dbg(1, msp_debug, client, | ||
404 | "NICAM/AM carrier : %d.%03d MHz\n", | ||
405 | state->second / 910000, (state->second / 910) % 1000); | ||
406 | if (state->mode == MSP_MODE_FM_TERRA && state->main != state->second) { | ||
407 | v4l_dbg(1, msp_debug, client, | ||
408 | "FM-stereo carrier : %d.%03d MHz\n", | ||
409 | state->second / 910000, (state->second / 910) % 1000); | ||
410 | } | ||
411 | } | ||
412 | |||
413 | /* ----------------------------------------------------------------------- */ | ||
414 | |||
415 | static int msp3400c_detect_stereo(struct i2c_client *client) | ||
416 | { | ||
417 | struct msp_state *state = to_state(i2c_get_clientdata(client)); | ||
418 | int val; | ||
419 | int rxsubchans = state->rxsubchans; | ||
420 | int newnicam = state->nicam_on; | ||
421 | int update = 0; | ||
422 | |||
423 | switch (state->mode) { | ||
424 | case MSP_MODE_FM_TERRA: | ||
425 | val = msp_read_dsp(client, 0x18); | ||
426 | if (val > 32767) | ||
427 | val -= 65536; | ||
428 | v4l_dbg(2, msp_debug, client, | ||
429 | "stereo detect register: %d\n", val); | ||
430 | if (val > 8192) { | ||
431 | rxsubchans = V4L2_TUNER_SUB_STEREO; | ||
432 | } else if (val < -4096) { | ||
433 | rxsubchans = V4L2_TUNER_SUB_LANG1 | V4L2_TUNER_SUB_LANG2; | ||
434 | } else { | ||
435 | rxsubchans = V4L2_TUNER_SUB_MONO; | ||
436 | } | ||
437 | newnicam = 0; | ||
438 | break; | ||
439 | case MSP_MODE_FM_NICAM1: | ||
440 | case MSP_MODE_FM_NICAM2: | ||
441 | case MSP_MODE_AM_NICAM: | ||
442 | val = msp_read_dem(client, 0x23); | ||
443 | v4l_dbg(2, msp_debug, client, "nicam sync=%d, mode=%d\n", | ||
444 | val & 1, (val & 0x1e) >> 1); | ||
445 | |||
446 | if (val & 1) { | ||
447 | /* nicam synced */ | ||
448 | switch ((val & 0x1e) >> 1) { | ||
449 | case 0: | ||
450 | case 8: | ||
451 | rxsubchans = V4L2_TUNER_SUB_STEREO; | ||
452 | break; | ||
453 | case 1: | ||
454 | case 9: | ||
455 | rxsubchans = V4L2_TUNER_SUB_MONO; | ||
456 | break; | ||
457 | case 2: | ||
458 | case 10: | ||
459 | rxsubchans = V4L2_TUNER_SUB_LANG1 | V4L2_TUNER_SUB_LANG2; | ||
460 | break; | ||
461 | default: | ||
462 | rxsubchans = V4L2_TUNER_SUB_MONO; | ||
463 | break; | ||
464 | } | ||
465 | newnicam = 1; | ||
466 | } else { | ||
467 | newnicam = 0; | ||
468 | rxsubchans = V4L2_TUNER_SUB_MONO; | ||
469 | } | ||
470 | break; | ||
471 | } | ||
472 | if (rxsubchans != state->rxsubchans) { | ||
473 | update = 1; | ||
474 | v4l_dbg(1, msp_debug, client, | ||
475 | "watch: rxsubchans %02x => %02x\n", | ||
476 | state->rxsubchans, rxsubchans); | ||
477 | state->rxsubchans = rxsubchans; | ||
478 | } | ||
479 | if (newnicam != state->nicam_on) { | ||
480 | update = 1; | ||
481 | v4l_dbg(1, msp_debug, client, "watch: nicam %d => %d\n", | ||
482 | state->nicam_on, newnicam); | ||
483 | state->nicam_on = newnicam; | ||
484 | } | ||
485 | return update; | ||
486 | } | ||
487 | |||
488 | /* | ||
489 | * A kernel thread for msp3400 control -- we don't want to block the | ||
490 | * in the ioctl while doing the sound carrier & stereo detect | ||
491 | */ | ||
492 | /* stereo/multilang monitoring */ | ||
493 | static void watch_stereo(struct i2c_client *client) | ||
494 | { | ||
495 | struct msp_state *state = to_state(i2c_get_clientdata(client)); | ||
496 | |||
497 | if (msp_detect_stereo(client)) | ||
498 | msp_set_audmode(client); | ||
499 | |||
500 | if (msp_once) | ||
501 | state->watch_stereo = 0; | ||
502 | } | ||
503 | |||
504 | int msp3400c_thread(void *data) | ||
505 | { | ||
506 | struct i2c_client *client = data; | ||
507 | struct msp_state *state = to_state(i2c_get_clientdata(client)); | ||
508 | struct msp3400c_carrier_detect *cd; | ||
509 | int count, max1, max2, val1, val2, val, i; | ||
510 | |||
511 | v4l_dbg(1, msp_debug, client, "msp3400 daemon started\n"); | ||
512 | state->detected_std = V4L2_STD_ALL; | ||
513 | set_freezable(); | ||
514 | for (;;) { | ||
515 | v4l_dbg(2, msp_debug, client, "msp3400 thread: sleep\n"); | ||
516 | msp_sleep(state, -1); | ||
517 | v4l_dbg(2, msp_debug, client, "msp3400 thread: wakeup\n"); | ||
518 | |||
519 | restart: | ||
520 | v4l_dbg(2, msp_debug, client, "thread: restart scan\n"); | ||
521 | state->restart = 0; | ||
522 | if (kthread_should_stop()) | ||
523 | break; | ||
524 | |||
525 | if (state->radio || MSP_MODE_EXTERN == state->mode) { | ||
526 | /* no carrier scan, just unmute */ | ||
527 | v4l_dbg(1, msp_debug, client, | ||
528 | "thread: no carrier scan\n"); | ||
529 | state->scan_in_progress = 0; | ||
530 | msp_update_volume(state); | ||
531 | continue; | ||
532 | } | ||
533 | |||
534 | /* mute audio */ | ||
535 | state->scan_in_progress = 1; | ||
536 | msp_update_volume(state); | ||
537 | |||
538 | msp3400c_set_mode(client, MSP_MODE_AM_DETECT); | ||
539 | val1 = val2 = 0; | ||
540 | max1 = max2 = -1; | ||
541 | state->watch_stereo = 0; | ||
542 | state->nicam_on = 0; | ||
543 | |||
544 | /* wait for tuner to settle down after a channel change */ | ||
545 | if (msp_sleep(state, 200)) | ||
546 | goto restart; | ||
547 | |||
548 | /* carrier detect pass #1 -- main carrier */ | ||
549 | cd = msp3400c_carrier_detect_main; | ||
550 | count = ARRAY_SIZE(msp3400c_carrier_detect_main); | ||
551 | |||
552 | if (msp_amsound && (state->v4l2_std & V4L2_STD_SECAM)) { | ||
553 | /* autodetect doesn't work well with AM ... */ | ||
554 | max1 = 3; | ||
555 | count = 0; | ||
556 | v4l_dbg(1, msp_debug, client, "AM sound override\n"); | ||
557 | } | ||
558 | |||
559 | for (i = 0; i < count; i++) { | ||
560 | msp3400c_set_carrier(client, cd[i].cdo, cd[i].cdo); | ||
561 | if (msp_sleep(state, 100)) | ||
562 | goto restart; | ||
563 | val = msp_read_dsp(client, 0x1b); | ||
564 | if (val > 32767) | ||
565 | val -= 65536; | ||
566 | if (val1 < val) | ||
567 | val1 = val, max1 = i; | ||
568 | v4l_dbg(1, msp_debug, client, | ||
569 | "carrier1 val: %5d / %s\n", val, cd[i].name); | ||
570 | } | ||
571 | |||
572 | /* carrier detect pass #2 -- second (stereo) carrier */ | ||
573 | switch (max1) { | ||
574 | case 1: /* 5.5 */ | ||
575 | cd = msp3400c_carrier_detect_55; | ||
576 | count = ARRAY_SIZE(msp3400c_carrier_detect_55); | ||
577 | break; | ||
578 | case 3: /* 6.5 */ | ||
579 | cd = msp3400c_carrier_detect_65; | ||
580 | count = ARRAY_SIZE(msp3400c_carrier_detect_65); | ||
581 | break; | ||
582 | case 0: /* 4.5 */ | ||
583 | case 2: /* 6.0 */ | ||
584 | default: | ||
585 | cd = NULL; | ||
586 | count = 0; | ||
587 | break; | ||
588 | } | ||
589 | |||
590 | if (msp_amsound && (state->v4l2_std & V4L2_STD_SECAM)) { | ||
591 | /* autodetect doesn't work well with AM ... */ | ||
592 | cd = NULL; | ||
593 | count = 0; | ||
594 | max2 = 0; | ||
595 | } | ||
596 | for (i = 0; i < count; i++) { | ||
597 | msp3400c_set_carrier(client, cd[i].cdo, cd[i].cdo); | ||
598 | if (msp_sleep(state, 100)) | ||
599 | goto restart; | ||
600 | val = msp_read_dsp(client, 0x1b); | ||
601 | if (val > 32767) | ||
602 | val -= 65536; | ||
603 | if (val2 < val) | ||
604 | val2 = val, max2 = i; | ||
605 | v4l_dbg(1, msp_debug, client, | ||
606 | "carrier2 val: %5d / %s\n", val, cd[i].name); | ||
607 | } | ||
608 | |||
609 | /* program the msp3400 according to the results */ | ||
610 | state->main = msp3400c_carrier_detect_main[max1].cdo; | ||
611 | switch (max1) { | ||
612 | case 1: /* 5.5 */ | ||
613 | state->detected_std = V4L2_STD_BG | V4L2_STD_PAL_H; | ||
614 | if (max2 == 0) { | ||
615 | /* B/G FM-stereo */ | ||
616 | state->second = msp3400c_carrier_detect_55[max2].cdo; | ||
617 | msp3400c_set_mode(client, MSP_MODE_FM_TERRA); | ||
618 | state->watch_stereo = 1; | ||
619 | } else if (max2 == 1 && state->has_nicam) { | ||
620 | /* B/G NICAM */ | ||
621 | state->second = msp3400c_carrier_detect_55[max2].cdo; | ||
622 | msp3400c_set_mode(client, MSP_MODE_FM_NICAM1); | ||
623 | state->nicam_on = 1; | ||
624 | state->watch_stereo = 1; | ||
625 | } else { | ||
626 | goto no_second; | ||
627 | } | ||
628 | break; | ||
629 | case 2: /* 6.0 */ | ||
630 | /* PAL I NICAM */ | ||
631 | state->detected_std = V4L2_STD_PAL_I; | ||
632 | state->second = MSP_CARRIER(6.552); | ||
633 | msp3400c_set_mode(client, MSP_MODE_FM_NICAM2); | ||
634 | state->nicam_on = 1; | ||
635 | state->watch_stereo = 1; | ||
636 | break; | ||
637 | case 3: /* 6.5 */ | ||
638 | if (max2 == 1 || max2 == 2) { | ||
639 | /* D/K FM-stereo */ | ||
640 | state->second = msp3400c_carrier_detect_65[max2].cdo; | ||
641 | msp3400c_set_mode(client, MSP_MODE_FM_TERRA); | ||
642 | state->watch_stereo = 1; | ||
643 | state->detected_std = V4L2_STD_DK; | ||
644 | } else if (max2 == 0 && (state->v4l2_std & V4L2_STD_SECAM)) { | ||
645 | /* L NICAM or AM-mono */ | ||
646 | state->second = msp3400c_carrier_detect_65[max2].cdo; | ||
647 | msp3400c_set_mode(client, MSP_MODE_AM_NICAM); | ||
648 | state->watch_stereo = 1; | ||
649 | state->detected_std = V4L2_STD_L; | ||
650 | } else if (max2 == 0 && state->has_nicam) { | ||
651 | /* D/K NICAM */ | ||
652 | state->second = msp3400c_carrier_detect_65[max2].cdo; | ||
653 | msp3400c_set_mode(client, MSP_MODE_FM_NICAM1); | ||
654 | state->nicam_on = 1; | ||
655 | state->watch_stereo = 1; | ||
656 | state->detected_std = V4L2_STD_DK; | ||
657 | } else { | ||
658 | goto no_second; | ||
659 | } | ||
660 | break; | ||
661 | case 0: /* 4.5 */ | ||
662 | state->detected_std = V4L2_STD_MN; | ||
663 | default: | ||
664 | no_second: | ||
665 | state->second = msp3400c_carrier_detect_main[max1].cdo; | ||
666 | msp3400c_set_mode(client, MSP_MODE_FM_TERRA); | ||
667 | break; | ||
668 | } | ||
669 | msp3400c_set_carrier(client, state->second, state->main); | ||
670 | |||
671 | /* unmute */ | ||
672 | state->scan_in_progress = 0; | ||
673 | msp3400c_set_audmode(client); | ||
674 | msp_update_volume(state); | ||
675 | |||
676 | if (msp_debug) | ||
677 | msp3400c_print_mode(client); | ||
678 | |||
679 | /* monitor tv audio mode, the first time don't wait | ||
680 | so long to get a quick stereo/bilingual result */ | ||
681 | count = 3; | ||
682 | while (state->watch_stereo) { | ||
683 | if (msp_sleep(state, count ? 1000 : 5000)) | ||
684 | goto restart; | ||
685 | if (count) | ||
686 | count--; | ||
687 | watch_stereo(client); | ||
688 | } | ||
689 | } | ||
690 | v4l_dbg(1, msp_debug, client, "thread: exit\n"); | ||
691 | return 0; | ||
692 | } | ||
693 | |||
694 | |||
695 | int msp3410d_thread(void *data) | ||
696 | { | ||
697 | struct i2c_client *client = data; | ||
698 | struct msp_state *state = to_state(i2c_get_clientdata(client)); | ||
699 | int val, i, std, count; | ||
700 | |||
701 | v4l_dbg(1, msp_debug, client, "msp3410 daemon started\n"); | ||
702 | state->detected_std = V4L2_STD_ALL; | ||
703 | set_freezable(); | ||
704 | for (;;) { | ||
705 | v4l_dbg(2, msp_debug, client, "msp3410 thread: sleep\n"); | ||
706 | msp_sleep(state, -1); | ||
707 | v4l_dbg(2, msp_debug, client, "msp3410 thread: wakeup\n"); | ||
708 | |||
709 | restart: | ||
710 | v4l_dbg(2, msp_debug, client, "thread: restart scan\n"); | ||
711 | state->restart = 0; | ||
712 | if (kthread_should_stop()) | ||
713 | break; | ||
714 | |||
715 | if (state->mode == MSP_MODE_EXTERN) { | ||
716 | /* no carrier scan needed, just unmute */ | ||
717 | v4l_dbg(1, msp_debug, client, | ||
718 | "thread: no carrier scan\n"); | ||
719 | state->scan_in_progress = 0; | ||
720 | msp_update_volume(state); | ||
721 | continue; | ||
722 | } | ||
723 | |||
724 | /* mute audio */ | ||
725 | state->scan_in_progress = 1; | ||
726 | msp_update_volume(state); | ||
727 | |||
728 | /* start autodetect. Note: autodetect is not supported for | ||
729 | NTSC-M and radio, hence we force the standard in those | ||
730 | cases. */ | ||
731 | if (state->radio) | ||
732 | std = 0x40; | ||
733 | else | ||
734 | std = (state->v4l2_std & V4L2_STD_NTSC) ? 0x20 : 1; | ||
735 | state->watch_stereo = 0; | ||
736 | state->nicam_on = 0; | ||
737 | |||
738 | /* wait for tuner to settle down after a channel change */ | ||
739 | if (msp_sleep(state, 200)) | ||
740 | goto restart; | ||
741 | |||
742 | if (msp_debug) | ||
743 | v4l_dbg(2, msp_debug, client, | ||
744 | "setting standard: %s (0x%04x)\n", | ||
745 | msp_standard_std_name(std), std); | ||
746 | |||
747 | if (std != 1) { | ||
748 | /* programmed some specific mode */ | ||
749 | val = std; | ||
750 | } else { | ||
751 | /* triggered autodetect */ | ||
752 | msp_write_dem(client, 0x20, std); | ||
753 | for (;;) { | ||
754 | if (msp_sleep(state, 100)) | ||
755 | goto restart; | ||
756 | |||
757 | /* check results */ | ||
758 | val = msp_read_dem(client, 0x7e); | ||
759 | if (val < 0x07ff) | ||
760 | break; | ||
761 | v4l_dbg(2, msp_debug, client, | ||
762 | "detection still in progress\n"); | ||
763 | } | ||
764 | } | ||
765 | for (i = 0; msp_stdlist[i].name != NULL; i++) | ||
766 | if (msp_stdlist[i].retval == val) | ||
767 | break; | ||
768 | v4l_dbg(1, msp_debug, client, "current standard: %s (0x%04x)\n", | ||
769 | msp_standard_std_name(val), val); | ||
770 | state->main = msp_stdlist[i].main; | ||
771 | state->second = msp_stdlist[i].second; | ||
772 | state->std = val; | ||
773 | state->rxsubchans = V4L2_TUNER_SUB_MONO; | ||
774 | |||
775 | if (msp_amsound && !state->radio && | ||
776 | (state->v4l2_std & V4L2_STD_SECAM) && (val != 0x0009)) { | ||
777 | /* autodetection has failed, let backup */ | ||
778 | v4l_dbg(1, msp_debug, client, "autodetection failed," | ||
779 | " switching to backup standard: %s (0x%04x)\n", | ||
780 | msp_stdlist[8].name ? | ||
781 | msp_stdlist[8].name : "unknown", val); | ||
782 | state->std = val = 0x0009; | ||
783 | msp_write_dem(client, 0x20, val); | ||
784 | } else { | ||
785 | state->detected_std = msp_standard_std(state->std); | ||
786 | } | ||
787 | |||
788 | /* set stereo */ | ||
789 | switch (val) { | ||
790 | case 0x0008: /* B/G NICAM */ | ||
791 | case 0x000a: /* I NICAM */ | ||
792 | case 0x000b: /* D/K NICAM */ | ||
793 | if (val == 0x000a) | ||
794 | state->mode = MSP_MODE_FM_NICAM2; | ||
795 | else | ||
796 | state->mode = MSP_MODE_FM_NICAM1; | ||
797 | /* just turn on stereo */ | ||
798 | state->nicam_on = 1; | ||
799 | state->watch_stereo = 1; | ||
800 | break; | ||
801 | case 0x0009: | ||
802 | state->mode = MSP_MODE_AM_NICAM; | ||
803 | state->nicam_on = 1; | ||
804 | state->watch_stereo = 1; | ||
805 | break; | ||
806 | case 0x0020: /* BTSC */ | ||
807 | /* The pre-'G' models only have BTSC-mono */ | ||
808 | state->mode = MSP_MODE_BTSC; | ||
809 | break; | ||
810 | case 0x0040: /* FM radio */ | ||
811 | state->mode = MSP_MODE_FM_RADIO; | ||
812 | state->rxsubchans = V4L2_TUNER_SUB_STEREO; | ||
813 | /* not needed in theory if we have radio, but | ||
814 | short programming enables carrier mute */ | ||
815 | msp3400c_set_mode(client, MSP_MODE_FM_RADIO); | ||
816 | msp3400c_set_carrier(client, MSP_CARRIER(10.7), | ||
817 | MSP_CARRIER(10.7)); | ||
818 | break; | ||
819 | case 0x0002: | ||
820 | case 0x0003: | ||
821 | case 0x0004: | ||
822 | case 0x0005: | ||
823 | state->mode = MSP_MODE_FM_TERRA; | ||
824 | state->watch_stereo = 1; | ||
825 | break; | ||
826 | } | ||
827 | |||
828 | /* set various prescales */ | ||
829 | msp_write_dsp(client, 0x0d, 0x1900); /* scart */ | ||
830 | msp_write_dsp(client, 0x0e, 0x3000); /* FM */ | ||
831 | if (state->has_nicam) | ||
832 | msp_write_dsp(client, 0x10, 0x5a00); /* nicam */ | ||
833 | |||
834 | if (state->has_i2s_conf) | ||
835 | msp_write_dem(client, 0x40, state->i2s_mode); | ||
836 | |||
837 | /* unmute */ | ||
838 | msp3400c_set_audmode(client); | ||
839 | state->scan_in_progress = 0; | ||
840 | msp_update_volume(state); | ||
841 | |||
842 | /* monitor tv audio mode, the first time don't wait | ||
843 | so long to get a quick stereo/bilingual result */ | ||
844 | count = 3; | ||
845 | while (state->watch_stereo) { | ||
846 | if (msp_sleep(state, count ? 1000 : 5000)) | ||
847 | goto restart; | ||
848 | if (count) | ||
849 | count--; | ||
850 | watch_stereo(client); | ||
851 | } | ||
852 | } | ||
853 | v4l_dbg(1, msp_debug, client, "thread: exit\n"); | ||
854 | return 0; | ||
855 | } | ||
856 | |||
857 | /* ----------------------------------------------------------------------- */ | ||
858 | |||
859 | /* msp34xxG + (autoselect no-thread) | ||
860 | * this one uses both automatic standard detection and automatic sound | ||
861 | * select which are available in the newer G versions | ||
862 | * struct msp: only norm, acb and source are really used in this mode | ||
863 | */ | ||
864 | |||
865 | static int msp34xxg_modus(struct i2c_client *client) | ||
866 | { | ||
867 | struct msp_state *state = to_state(i2c_get_clientdata(client)); | ||
868 | |||
869 | if (state->radio) { | ||
870 | v4l_dbg(1, msp_debug, client, "selected radio modus\n"); | ||
871 | return 0x0001; | ||
872 | } | ||
873 | if (state->v4l2_std == V4L2_STD_NTSC_M_JP) { | ||
874 | v4l_dbg(1, msp_debug, client, "selected M (EIA-J) modus\n"); | ||
875 | return 0x4001; | ||
876 | } | ||
877 | if (state->v4l2_std == V4L2_STD_NTSC_M_KR) { | ||
878 | v4l_dbg(1, msp_debug, client, "selected M (A2) modus\n"); | ||
879 | return 0x0001; | ||
880 | } | ||
881 | if (state->v4l2_std == V4L2_STD_SECAM_L) { | ||
882 | v4l_dbg(1, msp_debug, client, "selected SECAM-L modus\n"); | ||
883 | return 0x6001; | ||
884 | } | ||
885 | if (state->v4l2_std & V4L2_STD_MN) { | ||
886 | v4l_dbg(1, msp_debug, client, "selected M (BTSC) modus\n"); | ||
887 | return 0x2001; | ||
888 | } | ||
889 | return 0x7001; | ||
890 | } | ||
891 | |||
892 | static void msp34xxg_set_source(struct i2c_client *client, u16 reg, int in) | ||
893 | { | ||
894 | struct msp_state *state = to_state(i2c_get_clientdata(client)); | ||
895 | int source, matrix; | ||
896 | |||
897 | switch (state->audmode) { | ||
898 | case V4L2_TUNER_MODE_MONO: | ||
899 | source = 0; /* mono only */ | ||
900 | matrix = 0x30; | ||
901 | break; | ||
902 | case V4L2_TUNER_MODE_LANG2: | ||
903 | source = 4; /* stereo or B */ | ||
904 | matrix = 0x10; | ||
905 | break; | ||
906 | case V4L2_TUNER_MODE_LANG1_LANG2: | ||
907 | source = 1; /* stereo or A|B */ | ||
908 | matrix = 0x20; | ||
909 | break; | ||
910 | case V4L2_TUNER_MODE_LANG1: | ||
911 | source = 3; /* stereo or A */ | ||
912 | matrix = 0x00; | ||
913 | break; | ||
914 | case V4L2_TUNER_MODE_STEREO: | ||
915 | default: | ||
916 | source = 3; /* stereo or A */ | ||
917 | matrix = 0x20; | ||
918 | break; | ||
919 | } | ||
920 | |||
921 | if (in == MSP_DSP_IN_TUNER) | ||
922 | source = (source << 8) | 0x20; | ||
923 | /* the msp34x2g puts the MAIN_AVC, MAIN and AUX sources in 12, 13, 14 | ||
924 | instead of 11, 12, 13. So we add one for that msp version. */ | ||
925 | else if (in >= MSP_DSP_IN_MAIN_AVC && state->has_dolby_pro_logic) | ||
926 | source = ((in + 1) << 8) | matrix; | ||
927 | else | ||
928 | source = (in << 8) | matrix; | ||
929 | |||
930 | v4l_dbg(1, msp_debug, client, | ||
931 | "set source to %d (0x%x) for output %02x\n", in, source, reg); | ||
932 | msp_write_dsp(client, reg, source); | ||
933 | } | ||
934 | |||
935 | static void msp34xxg_set_sources(struct i2c_client *client) | ||
936 | { | ||
937 | struct msp_state *state = to_state(i2c_get_clientdata(client)); | ||
938 | u32 in = state->route_in; | ||
939 | |||
940 | msp34xxg_set_source(client, 0x0008, (in >> 4) & 0xf); | ||
941 | /* quasi-peak detector is set to same input as the loudspeaker (MAIN) */ | ||
942 | msp34xxg_set_source(client, 0x000c, (in >> 4) & 0xf); | ||
943 | msp34xxg_set_source(client, 0x0009, (in >> 8) & 0xf); | ||
944 | msp34xxg_set_source(client, 0x000a, (in >> 12) & 0xf); | ||
945 | if (state->has_scart2_out) | ||
946 | msp34xxg_set_source(client, 0x0041, (in >> 16) & 0xf); | ||
947 | msp34xxg_set_source(client, 0x000b, (in >> 20) & 0xf); | ||
948 | } | ||
949 | |||
950 | /* (re-)initialize the msp34xxg */ | ||
951 | static void msp34xxg_reset(struct i2c_client *client) | ||
952 | { | ||
953 | struct msp_state *state = to_state(i2c_get_clientdata(client)); | ||
954 | int tuner = (state->route_in >> 3) & 1; | ||
955 | int modus; | ||
956 | |||
957 | /* initialize std to 1 (autodetect) to signal that no standard is | ||
958 | selected yet. */ | ||
959 | state->std = 1; | ||
960 | |||
961 | msp_reset(client); | ||
962 | |||
963 | if (state->has_i2s_conf) | ||
964 | msp_write_dem(client, 0x40, state->i2s_mode); | ||
965 | |||
966 | /* step-by-step initialisation, as described in the manual */ | ||
967 | modus = msp34xxg_modus(client); | ||
968 | modus |= tuner ? 0x100 : 0; | ||
969 | msp_write_dem(client, 0x30, modus); | ||
970 | |||
971 | /* write the dsps that may have an influence on | ||
972 | standard/audio autodetection right now */ | ||
973 | msp34xxg_set_sources(client); | ||
974 | |||
975 | msp_write_dsp(client, 0x0d, 0x1900); /* scart */ | ||
976 | msp_write_dsp(client, 0x0e, 0x3000); /* FM */ | ||
977 | if (state->has_nicam) | ||
978 | msp_write_dsp(client, 0x10, 0x5a00); /* nicam */ | ||
979 | |||
980 | /* set identification threshold. Personally, I | ||
981 | * I set it to a higher value than the default | ||
982 | * of 0x190 to ignore noisy stereo signals. | ||
983 | * this needs tuning. (recommended range 0x00a0-0x03c0) | ||
984 | * 0x7f0 = forced mono mode | ||
985 | * | ||
986 | * a2 threshold for stereo/bilingual. | ||
987 | * Note: this register is part of the Manual/Compatibility mode. | ||
988 | * It is supported by all 'G'-family chips. | ||
989 | */ | ||
990 | msp_write_dem(client, 0x22, msp_stereo_thresh); | ||
991 | } | ||
992 | |||
993 | int msp34xxg_thread(void *data) | ||
994 | { | ||
995 | struct i2c_client *client = data; | ||
996 | struct msp_state *state = to_state(i2c_get_clientdata(client)); | ||
997 | int val, i; | ||
998 | |||
999 | v4l_dbg(1, msp_debug, client, "msp34xxg daemon started\n"); | ||
1000 | state->detected_std = V4L2_STD_ALL; | ||
1001 | set_freezable(); | ||
1002 | for (;;) { | ||
1003 | v4l_dbg(2, msp_debug, client, "msp34xxg thread: sleep\n"); | ||
1004 | msp_sleep(state, -1); | ||
1005 | v4l_dbg(2, msp_debug, client, "msp34xxg thread: wakeup\n"); | ||
1006 | |||
1007 | restart: | ||
1008 | v4l_dbg(1, msp_debug, client, "thread: restart scan\n"); | ||
1009 | state->restart = 0; | ||
1010 | if (kthread_should_stop()) | ||
1011 | break; | ||
1012 | |||
1013 | if (state->mode == MSP_MODE_EXTERN) { | ||
1014 | /* no carrier scan needed, just unmute */ | ||
1015 | v4l_dbg(1, msp_debug, client, | ||
1016 | "thread: no carrier scan\n"); | ||
1017 | state->scan_in_progress = 0; | ||
1018 | msp_update_volume(state); | ||
1019 | continue; | ||
1020 | } | ||
1021 | |||
1022 | /* setup the chip*/ | ||
1023 | msp34xxg_reset(client); | ||
1024 | state->std = state->radio ? 0x40 : | ||
1025 | (state->force_btsc && msp_standard == 1) ? 32 : msp_standard; | ||
1026 | msp_write_dem(client, 0x20, state->std); | ||
1027 | /* start autodetect */ | ||
1028 | if (state->std != 1) | ||
1029 | goto unmute; | ||
1030 | |||
1031 | /* watch autodetect */ | ||
1032 | v4l_dbg(1, msp_debug, client, | ||
1033 | "started autodetect, waiting for result\n"); | ||
1034 | for (i = 0; i < 10; i++) { | ||
1035 | if (msp_sleep(state, 100)) | ||
1036 | goto restart; | ||
1037 | |||
1038 | /* check results */ | ||
1039 | val = msp_read_dem(client, 0x7e); | ||
1040 | if (val < 0x07ff) { | ||
1041 | state->std = val; | ||
1042 | break; | ||
1043 | } | ||
1044 | v4l_dbg(2, msp_debug, client, | ||
1045 | "detection still in progress\n"); | ||
1046 | } | ||
1047 | if (state->std == 1) { | ||
1048 | v4l_dbg(1, msp_debug, client, | ||
1049 | "detection still in progress after 10 tries. giving up.\n"); | ||
1050 | continue; | ||
1051 | } | ||
1052 | |||
1053 | unmute: | ||
1054 | v4l_dbg(1, msp_debug, client, | ||
1055 | "detected standard: %s (0x%04x)\n", | ||
1056 | msp_standard_std_name(state->std), state->std); | ||
1057 | state->detected_std = msp_standard_std(state->std); | ||
1058 | |||
1059 | if (state->std == 9) { | ||
1060 | /* AM NICAM mode */ | ||
1061 | msp_write_dsp(client, 0x0e, 0x7c00); | ||
1062 | } | ||
1063 | |||
1064 | /* unmute: dispatch sound to scart output, set scart volume */ | ||
1065 | msp_update_volume(state); | ||
1066 | |||
1067 | /* restore ACB */ | ||
1068 | if (msp_write_dsp(client, 0x13, state->acb)) | ||
1069 | return -1; | ||
1070 | |||
1071 | /* the periodic stereo/SAP check is only relevant for | ||
1072 | the 0x20 standard (BTSC) */ | ||
1073 | if (state->std != 0x20) | ||
1074 | continue; | ||
1075 | |||
1076 | state->watch_stereo = 1; | ||
1077 | |||
1078 | /* monitor tv audio mode, the first time don't wait | ||
1079 | in order to get a quick stereo/SAP update */ | ||
1080 | watch_stereo(client); | ||
1081 | while (state->watch_stereo) { | ||
1082 | watch_stereo(client); | ||
1083 | if (msp_sleep(state, 5000)) | ||
1084 | goto restart; | ||
1085 | } | ||
1086 | } | ||
1087 | v4l_dbg(1, msp_debug, client, "thread: exit\n"); | ||
1088 | return 0; | ||
1089 | } | ||
1090 | |||
1091 | static int msp34xxg_detect_stereo(struct i2c_client *client) | ||
1092 | { | ||
1093 | struct msp_state *state = to_state(i2c_get_clientdata(client)); | ||
1094 | int status = msp_read_dem(client, 0x0200); | ||
1095 | int is_bilingual = status & 0x100; | ||
1096 | int is_stereo = status & 0x40; | ||
1097 | int oldrx = state->rxsubchans; | ||
1098 | |||
1099 | if (state->mode == MSP_MODE_EXTERN) | ||
1100 | return 0; | ||
1101 | |||
1102 | state->rxsubchans = 0; | ||
1103 | if (is_stereo) | ||
1104 | state->rxsubchans = V4L2_TUNER_SUB_STEREO; | ||
1105 | else | ||
1106 | state->rxsubchans = V4L2_TUNER_SUB_MONO; | ||
1107 | if (is_bilingual) { | ||
1108 | if (state->std == 0x20) | ||
1109 | state->rxsubchans |= V4L2_TUNER_SUB_SAP; | ||
1110 | else | ||
1111 | state->rxsubchans = | ||
1112 | V4L2_TUNER_SUB_LANG1 | V4L2_TUNER_SUB_LANG2; | ||
1113 | } | ||
1114 | v4l_dbg(1, msp_debug, client, | ||
1115 | "status=0x%x, stereo=%d, bilingual=%d -> rxsubchans=%d\n", | ||
1116 | status, is_stereo, is_bilingual, state->rxsubchans); | ||
1117 | return (oldrx != state->rxsubchans); | ||
1118 | } | ||
1119 | |||
1120 | static void msp34xxg_set_audmode(struct i2c_client *client) | ||
1121 | { | ||
1122 | struct msp_state *state = to_state(i2c_get_clientdata(client)); | ||
1123 | |||
1124 | if (state->std == 0x20) { | ||
1125 | if ((state->rxsubchans & V4L2_TUNER_SUB_SAP) && | ||
1126 | (state->audmode == V4L2_TUNER_MODE_LANG1_LANG2 || | ||
1127 | state->audmode == V4L2_TUNER_MODE_LANG2)) { | ||
1128 | msp_write_dem(client, 0x20, 0x21); | ||
1129 | } else { | ||
1130 | msp_write_dem(client, 0x20, 0x20); | ||
1131 | } | ||
1132 | } | ||
1133 | |||
1134 | msp34xxg_set_sources(client); | ||
1135 | } | ||
1136 | |||
1137 | void msp_set_audmode(struct i2c_client *client) | ||
1138 | { | ||
1139 | struct msp_state *state = to_state(i2c_get_clientdata(client)); | ||
1140 | |||
1141 | switch (state->opmode) { | ||
1142 | case OPMODE_MANUAL: | ||
1143 | case OPMODE_AUTODETECT: | ||
1144 | msp3400c_set_audmode(client); | ||
1145 | break; | ||
1146 | case OPMODE_AUTOSELECT: | ||
1147 | msp34xxg_set_audmode(client); | ||
1148 | break; | ||
1149 | } | ||
1150 | } | ||
1151 | |||
1152 | int msp_detect_stereo(struct i2c_client *client) | ||
1153 | { | ||
1154 | struct msp_state *state = to_state(i2c_get_clientdata(client)); | ||
1155 | |||
1156 | switch (state->opmode) { | ||
1157 | case OPMODE_MANUAL: | ||
1158 | case OPMODE_AUTODETECT: | ||
1159 | return msp3400c_detect_stereo(client); | ||
1160 | case OPMODE_AUTOSELECT: | ||
1161 | return msp34xxg_detect_stereo(client); | ||
1162 | } | ||
1163 | return 0; | ||
1164 | } | ||
1165 | |||