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