diff options
Diffstat (limited to 'drivers/media/video/msp3400.c')
-rw-r--r-- | drivers/media/video/msp3400.c | 1876 |
1 files changed, 1876 insertions, 0 deletions
diff --git a/drivers/media/video/msp3400.c b/drivers/media/video/msp3400.c new file mode 100644 index 000000000000..d996ec99caff --- /dev/null +++ b/drivers/media/video/msp3400.c | |||
@@ -0,0 +1,1876 @@ | |||
1 | /* | ||
2 | * programming the msp34* sound processor family | ||
3 | * | ||
4 | * (c) 1997-2001 Gerd Knorr <kraxel@bytesex.org> | ||
5 | * | ||
6 | * what works and what doesn't: | ||
7 | * | ||
8 | * AM-Mono | ||
9 | * Support for Hauppauge cards added (decoding handled by tuner) added by | ||
10 | * Frederic Crozat <fcrozat@mail.dotcom.fr> | ||
11 | * | ||
12 | * FM-Mono | ||
13 | * should work. The stereo modes are backward compatible to FM-mono, | ||
14 | * therefore FM-Mono should be allways available. | ||
15 | * | ||
16 | * FM-Stereo (B/G, used in germany) | ||
17 | * should work, with autodetect | ||
18 | * | ||
19 | * FM-Stereo (satellite) | ||
20 | * should work, no autodetect (i.e. default is mono, but you can | ||
21 | * switch to stereo -- untested) | ||
22 | * | ||
23 | * NICAM (B/G, L , used in UK, Scandinavia, Spain and France) | ||
24 | * should work, with autodetect. Support for NICAM was added by | ||
25 | * Pekka Pietikainen <pp@netppl.fi> | ||
26 | * | ||
27 | * | ||
28 | * TODO: | ||
29 | * - better SAT support | ||
30 | * | ||
31 | * | ||
32 | * 980623 Thomas Sailer (sailer@ife.ee.ethz.ch) | ||
33 | * using soundcore instead of OSS | ||
34 | * | ||
35 | */ | ||
36 | |||
37 | #include <linux/config.h> | ||
38 | #include <linux/module.h> | ||
39 | #include <linux/moduleparam.h> | ||
40 | #include <linux/kernel.h> | ||
41 | #include <linux/sched.h> | ||
42 | #include <linux/string.h> | ||
43 | #include <linux/timer.h> | ||
44 | #include <linux/delay.h> | ||
45 | #include <linux/errno.h> | ||
46 | #include <linux/slab.h> | ||
47 | #include <linux/i2c.h> | ||
48 | #include <linux/videodev.h> | ||
49 | #include <linux/init.h> | ||
50 | #include <linux/smp_lock.h> | ||
51 | #include <linux/kthread.h> | ||
52 | #include <linux/suspend.h> | ||
53 | #include <asm/semaphore.h> | ||
54 | #include <asm/pgtable.h> | ||
55 | |||
56 | #include <media/audiochip.h> | ||
57 | #include <media/id.h> | ||
58 | #include "msp3400.h" | ||
59 | |||
60 | #define OPMODE_AUTO -1 | ||
61 | #define OPMODE_MANUAL 0 | ||
62 | #define OPMODE_SIMPLE 1 /* use short programming (>= msp3410 only) */ | ||
63 | #define OPMODE_SIMPLER 2 /* use shorter programming (>= msp34xxG) */ | ||
64 | |||
65 | /* insmod parameters */ | ||
66 | static int opmode = OPMODE_AUTO; | ||
67 | static int debug = 0; /* debug output */ | ||
68 | static int once = 0; /* no continous stereo monitoring */ | ||
69 | static int amsound = 0; /* hard-wire AM sound at 6.5 Hz (france), | ||
70 | the autoscan seems work well only with FM... */ | ||
71 | static int standard = 1; /* Override auto detect of audio standard, if needed. */ | ||
72 | static int dolby = 0; | ||
73 | |||
74 | static int stereo_threshold = 0x190; /* a2 threshold for stereo/bilingual | ||
75 | (msp34xxg only) 0x00a0-0x03c0 */ | ||
76 | |||
77 | struct msp3400c { | ||
78 | int rev1,rev2; | ||
79 | |||
80 | int opmode; | ||
81 | int mode; | ||
82 | int norm; | ||
83 | int nicam_on; | ||
84 | int acb; | ||
85 | int main, second; /* sound carrier */ | ||
86 | int input; | ||
87 | int source; /* see msp34xxg_set_source */ | ||
88 | |||
89 | /* v4l2 */ | ||
90 | int audmode; | ||
91 | int rxsubchans; | ||
92 | |||
93 | int muted; | ||
94 | int volume, balance; | ||
95 | int bass, treble; | ||
96 | |||
97 | /* thread */ | ||
98 | struct task_struct *kthread; | ||
99 | wait_queue_head_t wq; | ||
100 | int restart:1; | ||
101 | int watch_stereo:1; | ||
102 | }; | ||
103 | |||
104 | #define HAVE_NICAM(msp) (((msp->rev2>>8) & 0xff) != 00) | ||
105 | #define HAVE_SIMPLE(msp) ((msp->rev1 & 0xff) >= 'D'-'@') | ||
106 | #define HAVE_SIMPLER(msp) ((msp->rev1 & 0xff) >= 'G'-'@') | ||
107 | #define HAVE_RADIO(msp) ((msp->rev1 & 0xff) >= 'G'-'@') | ||
108 | |||
109 | #define VIDEO_MODE_RADIO 16 /* norm magic for radio mode */ | ||
110 | |||
111 | /* ---------------------------------------------------------------------- */ | ||
112 | |||
113 | #define dprintk if (debug >= 1) printk | ||
114 | #define d2printk if (debug >= 2) printk | ||
115 | |||
116 | /* read-only */ | ||
117 | module_param(opmode, int, 0444); | ||
118 | |||
119 | /* read-write */ | ||
120 | module_param(once, int, 0644); | ||
121 | module_param(debug, int, 0644); | ||
122 | module_param(stereo_threshold, int, 0644); | ||
123 | module_param(standard, int, 0644); | ||
124 | module_param(amsound, int, 0644); | ||
125 | module_param(dolby, int, 0644); | ||
126 | |||
127 | MODULE_PARM_DESC(once, "No continuous stereo monitoring"); | ||
128 | MODULE_PARM_DESC(debug, "Enable debug messages"); | ||
129 | MODULE_PARM_DESC(standard, "Specify audio standard: 32 = NTSC, 64 = radio, Default: Autodetect"); | ||
130 | MODULE_PARM_DESC(amsound, "Hardwire AM sound at 6.5Hz (France), FM can autoscan"); | ||
131 | |||
132 | MODULE_DESCRIPTION("device driver for msp34xx TV sound processor"); | ||
133 | MODULE_AUTHOR("Gerd Knorr"); | ||
134 | MODULE_LICENSE("Dual BSD/GPL"); /* FreeBSD uses this too */ | ||
135 | |||
136 | /* ---------------------------------------------------------------------- */ | ||
137 | |||
138 | #define I2C_MSP3400C 0x80 | ||
139 | #define I2C_MSP3400C_ALT 0x88 | ||
140 | |||
141 | #define I2C_MSP3400C_DEM 0x10 | ||
142 | #define I2C_MSP3400C_DFP 0x12 | ||
143 | |||
144 | /* Addresses to scan */ | ||
145 | static unsigned short normal_i2c[] = { | ||
146 | I2C_MSP3400C >> 1, | ||
147 | I2C_MSP3400C_ALT >> 1, | ||
148 | I2C_CLIENT_END | ||
149 | }; | ||
150 | static unsigned short normal_i2c_range[] = {I2C_CLIENT_END,I2C_CLIENT_END}; | ||
151 | I2C_CLIENT_INSMOD; | ||
152 | |||
153 | /* ----------------------------------------------------------------------- */ | ||
154 | /* functions for talking to the MSP3400C Sound processor */ | ||
155 | |||
156 | static int msp3400c_reset(struct i2c_client *client) | ||
157 | { | ||
158 | /* reset and read revision code */ | ||
159 | static char reset_off[3] = { 0x00, 0x80, 0x00 }; | ||
160 | static char reset_on[3] = { 0x00, 0x00, 0x00 }; | ||
161 | static char write[3] = { I2C_MSP3400C_DFP + 1, 0x00, 0x1e }; | ||
162 | char read[2]; | ||
163 | struct i2c_msg reset[2] = { | ||
164 | { client->addr, I2C_M_IGNORE_NAK, 3, reset_off }, | ||
165 | { client->addr, I2C_M_IGNORE_NAK, 3, reset_on }, | ||
166 | }; | ||
167 | struct i2c_msg test[2] = { | ||
168 | { client->addr, 0, 3, write }, | ||
169 | { client->addr, I2C_M_RD, 2, read }, | ||
170 | }; | ||
171 | |||
172 | if ( (1 != i2c_transfer(client->adapter,&reset[0],1)) || | ||
173 | (1 != i2c_transfer(client->adapter,&reset[1],1)) || | ||
174 | (2 != i2c_transfer(client->adapter,test,2)) ) { | ||
175 | printk(KERN_ERR "msp3400: chip reset failed\n"); | ||
176 | return -1; | ||
177 | } | ||
178 | return 0; | ||
179 | } | ||
180 | |||
181 | static int | ||
182 | msp3400c_read(struct i2c_client *client, int dev, int addr) | ||
183 | { | ||
184 | int err; | ||
185 | |||
186 | unsigned char write[3]; | ||
187 | unsigned char read[2]; | ||
188 | struct i2c_msg msgs[2] = { | ||
189 | { client->addr, 0, 3, write }, | ||
190 | { client->addr, I2C_M_RD, 2, read } | ||
191 | }; | ||
192 | write[0] = dev+1; | ||
193 | write[1] = addr >> 8; | ||
194 | write[2] = addr & 0xff; | ||
195 | |||
196 | for (err = 0; err < 3;) { | ||
197 | if (2 == i2c_transfer(client->adapter,msgs,2)) | ||
198 | break; | ||
199 | err++; | ||
200 | printk(KERN_WARNING "msp34xx: I/O error #%d (read 0x%02x/0x%02x)\n", | ||
201 | err, dev, addr); | ||
202 | msleep(10); | ||
203 | } | ||
204 | if (3 == err) { | ||
205 | printk(KERN_WARNING "msp34xx: giving up, reseting chip. Sound will go off, sorry folks :-|\n"); | ||
206 | msp3400c_reset(client); | ||
207 | return -1; | ||
208 | } | ||
209 | return read[0] << 8 | read[1]; | ||
210 | } | ||
211 | |||
212 | static int | ||
213 | msp3400c_write(struct i2c_client *client, int dev, int addr, int val) | ||
214 | { | ||
215 | int err; | ||
216 | unsigned char buffer[5]; | ||
217 | |||
218 | buffer[0] = dev; | ||
219 | buffer[1] = addr >> 8; | ||
220 | buffer[2] = addr & 0xff; | ||
221 | buffer[3] = val >> 8; | ||
222 | buffer[4] = val & 0xff; | ||
223 | |||
224 | for (err = 0; err < 3;) { | ||
225 | if (5 == i2c_master_send(client, buffer, 5)) | ||
226 | break; | ||
227 | err++; | ||
228 | printk(KERN_WARNING "msp34xx: I/O error #%d (write 0x%02x/0x%02x)\n", | ||
229 | err, dev, addr); | ||
230 | msleep(10); | ||
231 | } | ||
232 | if (3 == err) { | ||
233 | printk(KERN_WARNING "msp34xx: giving up, reseting chip. Sound will go off, sorry folks :-|\n"); | ||
234 | msp3400c_reset(client); | ||
235 | return -1; | ||
236 | } | ||
237 | return 0; | ||
238 | } | ||
239 | |||
240 | /* ------------------------------------------------------------------------ */ | ||
241 | |||
242 | /* This macro is allowed for *constants* only, gcc must calculate it | ||
243 | at compile time. Remember -- no floats in kernel mode */ | ||
244 | #define MSP_CARRIER(freq) ((int)((float)(freq/18.432)*(1<<24))) | ||
245 | |||
246 | #define MSP_MODE_AM_DETECT 0 | ||
247 | #define MSP_MODE_FM_RADIO 2 | ||
248 | #define MSP_MODE_FM_TERRA 3 | ||
249 | #define MSP_MODE_FM_SAT 4 | ||
250 | #define MSP_MODE_FM_NICAM1 5 | ||
251 | #define MSP_MODE_FM_NICAM2 6 | ||
252 | #define MSP_MODE_AM_NICAM 7 | ||
253 | #define MSP_MODE_BTSC 8 | ||
254 | #define MSP_MODE_EXTERN 9 | ||
255 | |||
256 | static struct MSP_INIT_DATA_DEM { | ||
257 | int fir1[6]; | ||
258 | int fir2[6]; | ||
259 | int cdo1; | ||
260 | int cdo2; | ||
261 | int ad_cv; | ||
262 | int mode_reg; | ||
263 | int dfp_src; | ||
264 | int dfp_matrix; | ||
265 | } msp_init_data[] = { | ||
266 | /* AM (for carrier detect / msp3400) */ | ||
267 | { { 75, 19, 36, 35, 39, 40 }, { 75, 19, 36, 35, 39, 40 }, | ||
268 | MSP_CARRIER(5.5), MSP_CARRIER(5.5), | ||
269 | 0x00d0, 0x0500, 0x0020, 0x3000}, | ||
270 | |||
271 | /* AM (for carrier detect / msp3410) */ | ||
272 | { { -1, -1, -8, 2, 59, 126 }, { -1, -1, -8, 2, 59, 126 }, | ||
273 | MSP_CARRIER(5.5), MSP_CARRIER(5.5), | ||
274 | 0x00d0, 0x0100, 0x0020, 0x3000}, | ||
275 | |||
276 | /* FM Radio */ | ||
277 | { { -8, -8, 4, 6, 78, 107 }, { -8, -8, 4, 6, 78, 107 }, | ||
278 | MSP_CARRIER(10.7), MSP_CARRIER(10.7), | ||
279 | 0x00d0, 0x0480, 0x0020, 0x3000 }, | ||
280 | |||
281 | /* Terrestial FM-mono + FM-stereo */ | ||
282 | { { 3, 18, 27, 48, 66, 72 }, { 3, 18, 27, 48, 66, 72 }, | ||
283 | MSP_CARRIER(5.5), MSP_CARRIER(5.5), | ||
284 | 0x00d0, 0x0480, 0x0030, 0x3000}, | ||
285 | |||
286 | /* Sat FM-mono */ | ||
287 | { { 1, 9, 14, 24, 33, 37 }, { 3, 18, 27, 48, 66, 72 }, | ||
288 | MSP_CARRIER(6.5), MSP_CARRIER(6.5), | ||
289 | 0x00c6, 0x0480, 0x0000, 0x3000}, | ||
290 | |||
291 | /* NICAM/FM -- B/G (5.5/5.85), D/K (6.5/5.85) */ | ||
292 | { { -2, -8, -10, 10, 50, 86 }, { 3, 18, 27, 48, 66, 72 }, | ||
293 | MSP_CARRIER(5.5), MSP_CARRIER(5.5), | ||
294 | 0x00d0, 0x0040, 0x0120, 0x3000}, | ||
295 | |||
296 | /* NICAM/FM -- I (6.0/6.552) */ | ||
297 | { { 2, 4, -6, -4, 40, 94 }, { 3, 18, 27, 48, 66, 72 }, | ||
298 | MSP_CARRIER(6.0), MSP_CARRIER(6.0), | ||
299 | 0x00d0, 0x0040, 0x0120, 0x3000}, | ||
300 | |||
301 | /* NICAM/AM -- L (6.5/5.85) */ | ||
302 | { { -2, -8, -10, 10, 50, 86 }, { -4, -12, -9, 23, 79, 126 }, | ||
303 | MSP_CARRIER(6.5), MSP_CARRIER(6.5), | ||
304 | 0x00c6, 0x0140, 0x0120, 0x7c03}, | ||
305 | }; | ||
306 | |||
307 | struct CARRIER_DETECT { | ||
308 | int cdo; | ||
309 | char *name; | ||
310 | }; | ||
311 | |||
312 | static struct CARRIER_DETECT carrier_detect_main[] = { | ||
313 | /* main carrier */ | ||
314 | { MSP_CARRIER(4.5), "4.5 NTSC" }, | ||
315 | { MSP_CARRIER(5.5), "5.5 PAL B/G" }, | ||
316 | { MSP_CARRIER(6.0), "6.0 PAL I" }, | ||
317 | { MSP_CARRIER(6.5), "6.5 PAL D/K + SAT + SECAM" } | ||
318 | }; | ||
319 | |||
320 | static struct CARRIER_DETECT carrier_detect_55[] = { | ||
321 | /* PAL B/G */ | ||
322 | { MSP_CARRIER(5.7421875), "5.742 PAL B/G FM-stereo" }, | ||
323 | { MSP_CARRIER(5.85), "5.85 PAL B/G NICAM" } | ||
324 | }; | ||
325 | |||
326 | static struct CARRIER_DETECT carrier_detect_65[] = { | ||
327 | /* PAL SAT / SECAM */ | ||
328 | { MSP_CARRIER(5.85), "5.85 PAL D/K + SECAM NICAM" }, | ||
329 | { MSP_CARRIER(6.2578125), "6.25 PAL D/K1 FM-stereo" }, | ||
330 | { MSP_CARRIER(6.7421875), "6.74 PAL D/K2 FM-stereo" }, | ||
331 | { MSP_CARRIER(7.02), "7.02 PAL SAT FM-stereo s/b" }, | ||
332 | { MSP_CARRIER(7.20), "7.20 PAL SAT FM-stereo s" }, | ||
333 | { MSP_CARRIER(7.38), "7.38 PAL SAT FM-stereo b" }, | ||
334 | }; | ||
335 | |||
336 | #define CARRIER_COUNT(x) (sizeof(x)/sizeof(struct CARRIER_DETECT)) | ||
337 | |||
338 | /* ----------------------------------------------------------------------- */ | ||
339 | |||
340 | static int scarts[3][9] = { | ||
341 | /* MASK IN1 IN2 IN1_DA IN2_DA IN3 IN4 MONO MUTE */ | ||
342 | { 0x0320, 0x0000, 0x0200, -1, -1, 0x0300, 0x0020, 0x0100, 0x0320 }, | ||
343 | { 0x0c40, 0x0440, 0x0400, 0x0c00, 0x0040, 0x0000, 0x0840, 0x0800, 0x0c40 }, | ||
344 | { 0x3080, 0x1000, 0x1080, 0x0000, 0x0080, 0x2080, 0x3080, 0x2000, 0x3000 }, | ||
345 | }; | ||
346 | |||
347 | static char *scart_names[] = { | ||
348 | "mask", "in1", "in2", "in1 da", "in2 da", "in3", "in4", "mono", "mute" | ||
349 | }; | ||
350 | |||
351 | static void | ||
352 | msp3400c_set_scart(struct i2c_client *client, int in, int out) | ||
353 | { | ||
354 | struct msp3400c *msp = i2c_get_clientdata(client); | ||
355 | |||
356 | if (-1 == scarts[out][in]) | ||
357 | return; | ||
358 | |||
359 | dprintk(KERN_DEBUG | ||
360 | "msp34xx: scart switch: %s => %d\n",scart_names[in],out); | ||
361 | msp->acb &= ~scarts[out][SCART_MASK]; | ||
362 | msp->acb |= scarts[out][in]; | ||
363 | msp3400c_write(client,I2C_MSP3400C_DFP, 0x0013, msp->acb); | ||
364 | } | ||
365 | |||
366 | /* ------------------------------------------------------------------------ */ | ||
367 | |||
368 | static void msp3400c_setcarrier(struct i2c_client *client, int cdo1, int cdo2) | ||
369 | { | ||
370 | msp3400c_write(client,I2C_MSP3400C_DEM, 0x0093, cdo1 & 0xfff); | ||
371 | msp3400c_write(client,I2C_MSP3400C_DEM, 0x009b, cdo1 >> 12); | ||
372 | msp3400c_write(client,I2C_MSP3400C_DEM, 0x00a3, cdo2 & 0xfff); | ||
373 | msp3400c_write(client,I2C_MSP3400C_DEM, 0x00ab, cdo2 >> 12); | ||
374 | msp3400c_write(client,I2C_MSP3400C_DEM, 0x0056, 0); /*LOAD_REG_1/2*/ | ||
375 | } | ||
376 | |||
377 | static void msp3400c_setvolume(struct i2c_client *client, | ||
378 | int muted, int volume, int balance) | ||
379 | { | ||
380 | int val = 0, bal = 0; | ||
381 | |||
382 | if (!muted) { | ||
383 | val = (volume * 0x7F / 65535) << 8; | ||
384 | } | ||
385 | if (val) { | ||
386 | bal = (balance / 256) - 128; | ||
387 | } | ||
388 | dprintk(KERN_DEBUG | ||
389 | "msp34xx: setvolume: mute=%s %d:%d v=0x%02x b=0x%02x\n", | ||
390 | muted ? "on" : "off", volume, balance, val>>8, bal); | ||
391 | msp3400c_write(client,I2C_MSP3400C_DFP, 0x0000, val); /* loudspeaker */ | ||
392 | msp3400c_write(client,I2C_MSP3400C_DFP, 0x0006, val); /* headphones */ | ||
393 | msp3400c_write(client,I2C_MSP3400C_DFP, 0x0007, | ||
394 | muted ? 0x01 : (val | 0x01)); | ||
395 | msp3400c_write(client,I2C_MSP3400C_DFP, 0x0001, bal << 8); | ||
396 | } | ||
397 | |||
398 | static void msp3400c_setbass(struct i2c_client *client, int bass) | ||
399 | { | ||
400 | int val = ((bass-32768) * 0x60 / 65535) << 8; | ||
401 | |||
402 | dprintk(KERN_DEBUG "msp34xx: setbass: %d 0x%02x\n",bass, val>>8); | ||
403 | msp3400c_write(client,I2C_MSP3400C_DFP, 0x0002, val); /* loudspeaker */ | ||
404 | } | ||
405 | |||
406 | static void msp3400c_settreble(struct i2c_client *client, int treble) | ||
407 | { | ||
408 | int val = ((treble-32768) * 0x60 / 65535) << 8; | ||
409 | |||
410 | dprintk(KERN_DEBUG "msp34xx: settreble: %d 0x%02x\n",treble, val>>8); | ||
411 | msp3400c_write(client,I2C_MSP3400C_DFP, 0x0003, val); /* loudspeaker */ | ||
412 | } | ||
413 | |||
414 | static void msp3400c_setmode(struct i2c_client *client, int type) | ||
415 | { | ||
416 | struct msp3400c *msp = i2c_get_clientdata(client); | ||
417 | int i; | ||
418 | |||
419 | dprintk(KERN_DEBUG "msp3400: setmode: %d\n",type); | ||
420 | msp->mode = type; | ||
421 | msp->audmode = V4L2_TUNER_MODE_MONO; | ||
422 | msp->rxsubchans = V4L2_TUNER_SUB_MONO; | ||
423 | |||
424 | msp3400c_write(client,I2C_MSP3400C_DEM, 0x00bb, /* ad_cv */ | ||
425 | msp_init_data[type].ad_cv); | ||
426 | |||
427 | for (i = 5; i >= 0; i--) /* fir 1 */ | ||
428 | msp3400c_write(client,I2C_MSP3400C_DEM, 0x0001, | ||
429 | msp_init_data[type].fir1[i]); | ||
430 | |||
431 | msp3400c_write(client,I2C_MSP3400C_DEM, 0x0005, 0x0004); /* fir 2 */ | ||
432 | msp3400c_write(client,I2C_MSP3400C_DEM, 0x0005, 0x0040); | ||
433 | msp3400c_write(client,I2C_MSP3400C_DEM, 0x0005, 0x0000); | ||
434 | for (i = 5; i >= 0; i--) | ||
435 | msp3400c_write(client,I2C_MSP3400C_DEM, 0x0005, | ||
436 | msp_init_data[type].fir2[i]); | ||
437 | |||
438 | msp3400c_write(client,I2C_MSP3400C_DEM, 0x0083, /* MODE_REG */ | ||
439 | msp_init_data[type].mode_reg); | ||
440 | |||
441 | msp3400c_setcarrier(client, msp_init_data[type].cdo1, | ||
442 | msp_init_data[type].cdo2); | ||
443 | |||
444 | msp3400c_write(client,I2C_MSP3400C_DEM, 0x0056, 0); /*LOAD_REG_1/2*/ | ||
445 | |||
446 | if (dolby) { | ||
447 | msp3400c_write(client,I2C_MSP3400C_DFP, 0x0008, | ||
448 | 0x0520); /* I2S1 */ | ||
449 | msp3400c_write(client,I2C_MSP3400C_DFP, 0x0009, | ||
450 | 0x0620); /* I2S2 */ | ||
451 | msp3400c_write(client,I2C_MSP3400C_DFP, 0x000b, | ||
452 | msp_init_data[type].dfp_src); | ||
453 | } else { | ||
454 | msp3400c_write(client,I2C_MSP3400C_DFP, 0x0008, | ||
455 | msp_init_data[type].dfp_src); | ||
456 | msp3400c_write(client,I2C_MSP3400C_DFP, 0x0009, | ||
457 | msp_init_data[type].dfp_src); | ||
458 | msp3400c_write(client,I2C_MSP3400C_DFP, 0x000b, | ||
459 | msp_init_data[type].dfp_src); | ||
460 | } | ||
461 | msp3400c_write(client,I2C_MSP3400C_DFP, 0x000a, | ||
462 | msp_init_data[type].dfp_src); | ||
463 | msp3400c_write(client,I2C_MSP3400C_DFP, 0x000e, | ||
464 | msp_init_data[type].dfp_matrix); | ||
465 | |||
466 | if (HAVE_NICAM(msp)) { | ||
467 | /* nicam prescale */ | ||
468 | msp3400c_write(client,I2C_MSP3400C_DFP, 0x0010, 0x5a00); /* was: 0x3000 */ | ||
469 | } | ||
470 | } | ||
471 | |||
472 | static int best_audio_mode(int rxsubchans) | ||
473 | { | ||
474 | if (rxsubchans & V4L2_TUNER_SUB_STEREO) | ||
475 | return V4L2_TUNER_MODE_STEREO; | ||
476 | if (rxsubchans & V4L2_TUNER_SUB_LANG1) | ||
477 | return V4L2_TUNER_MODE_LANG1; | ||
478 | if (rxsubchans & V4L2_TUNER_SUB_LANG2) | ||
479 | return V4L2_TUNER_MODE_LANG2; | ||
480 | return V4L2_TUNER_MODE_MONO; | ||
481 | } | ||
482 | |||
483 | /* turn on/off nicam + stereo */ | ||
484 | static void msp3400c_set_audmode(struct i2c_client *client, int audmode) | ||
485 | { | ||
486 | static char *strmode[16] = { | ||
487 | #if __GNUC__ >= 3 | ||
488 | [ 0 ... 15 ] = "invalid", | ||
489 | #endif | ||
490 | [ V4L2_TUNER_MODE_MONO ] = "mono", | ||
491 | [ V4L2_TUNER_MODE_STEREO ] = "stereo", | ||
492 | [ V4L2_TUNER_MODE_LANG1 ] = "lang1", | ||
493 | [ V4L2_TUNER_MODE_LANG2 ] = "lang2", | ||
494 | }; | ||
495 | struct msp3400c *msp = i2c_get_clientdata(client); | ||
496 | int nicam=0; /* channel source: FM/AM or nicam */ | ||
497 | int src=0; | ||
498 | |||
499 | BUG_ON(msp->opmode == OPMODE_SIMPLER); | ||
500 | msp->audmode = audmode; | ||
501 | |||
502 | /* switch demodulator */ | ||
503 | switch (msp->mode) { | ||
504 | case MSP_MODE_FM_TERRA: | ||
505 | dprintk(KERN_DEBUG "msp3400: FM setstereo: %s\n", | ||
506 | strmode[audmode]); | ||
507 | msp3400c_setcarrier(client,msp->second,msp->main); | ||
508 | switch (audmode) { | ||
509 | case V4L2_TUNER_MODE_STEREO: | ||
510 | msp3400c_write(client,I2C_MSP3400C_DFP, 0x000e, 0x3001); | ||
511 | break; | ||
512 | case V4L2_TUNER_MODE_MONO: | ||
513 | case V4L2_TUNER_MODE_LANG1: | ||
514 | case V4L2_TUNER_MODE_LANG2: | ||
515 | msp3400c_write(client,I2C_MSP3400C_DFP, 0x000e, 0x3000); | ||
516 | break; | ||
517 | } | ||
518 | break; | ||
519 | case MSP_MODE_FM_SAT: | ||
520 | dprintk(KERN_DEBUG "msp3400: SAT setstereo: %s\n", | ||
521 | strmode[audmode]); | ||
522 | switch (audmode) { | ||
523 | case V4L2_TUNER_MODE_MONO: | ||
524 | msp3400c_setcarrier(client, MSP_CARRIER(6.5), MSP_CARRIER(6.5)); | ||
525 | break; | ||
526 | case V4L2_TUNER_MODE_STEREO: | ||
527 | msp3400c_setcarrier(client, MSP_CARRIER(7.2), MSP_CARRIER(7.02)); | ||
528 | break; | ||
529 | case V4L2_TUNER_MODE_LANG1: | ||
530 | msp3400c_setcarrier(client, MSP_CARRIER(7.38), MSP_CARRIER(7.02)); | ||
531 | break; | ||
532 | case V4L2_TUNER_MODE_LANG2: | ||
533 | msp3400c_setcarrier(client, MSP_CARRIER(7.38), MSP_CARRIER(7.02)); | ||
534 | break; | ||
535 | } | ||
536 | break; | ||
537 | case MSP_MODE_FM_NICAM1: | ||
538 | case MSP_MODE_FM_NICAM2: | ||
539 | case MSP_MODE_AM_NICAM: | ||
540 | dprintk(KERN_DEBUG "msp3400: NICAM setstereo: %s\n", | ||
541 | strmode[audmode]); | ||
542 | msp3400c_setcarrier(client,msp->second,msp->main); | ||
543 | if (msp->nicam_on) | ||
544 | nicam=0x0100; | ||
545 | break; | ||
546 | case MSP_MODE_BTSC: | ||
547 | dprintk(KERN_DEBUG "msp3400: BTSC setstereo: %s\n", | ||
548 | strmode[audmode]); | ||
549 | nicam=0x0300; | ||
550 | break; | ||
551 | case MSP_MODE_EXTERN: | ||
552 | dprintk(KERN_DEBUG "msp3400: extern setstereo: %s\n", | ||
553 | strmode[audmode]); | ||
554 | nicam = 0x0200; | ||
555 | break; | ||
556 | case MSP_MODE_FM_RADIO: | ||
557 | dprintk(KERN_DEBUG "msp3400: FM-Radio setstereo: %s\n", | ||
558 | strmode[audmode]); | ||
559 | break; | ||
560 | default: | ||
561 | dprintk(KERN_DEBUG "msp3400: mono setstereo\n"); | ||
562 | return; | ||
563 | } | ||
564 | |||
565 | /* switch audio */ | ||
566 | switch (audmode) { | ||
567 | case V4L2_TUNER_MODE_STEREO: | ||
568 | src = 0x0020 | nicam; | ||
569 | #if 0 | ||
570 | /* spatial effect */ | ||
571 | msp3400c_write(client,I2C_MSP3400C_DFP, 0x0005,0x4000); | ||
572 | #endif | ||
573 | break; | ||
574 | case V4L2_TUNER_MODE_MONO: | ||
575 | if (msp->mode == MSP_MODE_AM_NICAM) { | ||
576 | dprintk("msp3400: switching to AM mono\n"); | ||
577 | /* AM mono decoding is handled by tuner, not MSP chip */ | ||
578 | /* SCART switching control register */ | ||
579 | msp3400c_set_scart(client,SCART_MONO,0); | ||
580 | src = 0x0200; | ||
581 | break; | ||
582 | } | ||
583 | case V4L2_TUNER_MODE_LANG1: | ||
584 | src = 0x0000 | nicam; | ||
585 | break; | ||
586 | case V4L2_TUNER_MODE_LANG2: | ||
587 | src = 0x0010 | nicam; | ||
588 | break; | ||
589 | } | ||
590 | dprintk(KERN_DEBUG | ||
591 | "msp3400: setstereo final source/matrix = 0x%x\n", src); | ||
592 | |||
593 | if (dolby) { | ||
594 | msp3400c_write(client,I2C_MSP3400C_DFP, 0x0008,0x0520); | ||
595 | msp3400c_write(client,I2C_MSP3400C_DFP, 0x0009,0x0620); | ||
596 | msp3400c_write(client,I2C_MSP3400C_DFP, 0x000a,src); | ||
597 | msp3400c_write(client,I2C_MSP3400C_DFP, 0x000b,src); | ||
598 | } else { | ||
599 | msp3400c_write(client,I2C_MSP3400C_DFP, 0x0008,src); | ||
600 | msp3400c_write(client,I2C_MSP3400C_DFP, 0x0009,src); | ||
601 | msp3400c_write(client,I2C_MSP3400C_DFP, 0x000a,src); | ||
602 | msp3400c_write(client,I2C_MSP3400C_DFP, 0x000b,src); | ||
603 | } | ||
604 | } | ||
605 | |||
606 | static void | ||
607 | msp3400c_print_mode(struct msp3400c *msp) | ||
608 | { | ||
609 | if (msp->main == msp->second) { | ||
610 | printk(KERN_DEBUG "msp3400: mono sound carrier: %d.%03d MHz\n", | ||
611 | msp->main/910000,(msp->main/910)%1000); | ||
612 | } else { | ||
613 | printk(KERN_DEBUG "msp3400: main sound carrier: %d.%03d MHz\n", | ||
614 | msp->main/910000,(msp->main/910)%1000); | ||
615 | } | ||
616 | if (msp->mode == MSP_MODE_FM_NICAM1 || | ||
617 | msp->mode == MSP_MODE_FM_NICAM2) | ||
618 | printk(KERN_DEBUG "msp3400: NICAM/FM carrier : %d.%03d MHz\n", | ||
619 | msp->second/910000,(msp->second/910)%1000); | ||
620 | if (msp->mode == MSP_MODE_AM_NICAM) | ||
621 | printk(KERN_DEBUG "msp3400: NICAM/AM carrier : %d.%03d MHz\n", | ||
622 | msp->second/910000,(msp->second/910)%1000); | ||
623 | if (msp->mode == MSP_MODE_FM_TERRA && | ||
624 | msp->main != msp->second) { | ||
625 | printk(KERN_DEBUG "msp3400: FM-stereo carrier : %d.%03d MHz\n", | ||
626 | msp->second/910000,(msp->second/910)%1000); | ||
627 | } | ||
628 | } | ||
629 | |||
630 | /* ----------------------------------------------------------------------- */ | ||
631 | |||
632 | struct REGISTER_DUMP { | ||
633 | int addr; | ||
634 | char *name; | ||
635 | }; | ||
636 | |||
637 | static int | ||
638 | autodetect_stereo(struct i2c_client *client) | ||
639 | { | ||
640 | struct msp3400c *msp = i2c_get_clientdata(client); | ||
641 | int val; | ||
642 | int rxsubchans = msp->rxsubchans; | ||
643 | int newnicam = msp->nicam_on; | ||
644 | int update = 0; | ||
645 | |||
646 | switch (msp->mode) { | ||
647 | case MSP_MODE_FM_TERRA: | ||
648 | val = msp3400c_read(client, I2C_MSP3400C_DFP, 0x18); | ||
649 | if (val > 32767) | ||
650 | val -= 65536; | ||
651 | dprintk(KERN_DEBUG | ||
652 | "msp34xx: stereo detect register: %d\n",val); | ||
653 | if (val > 4096) { | ||
654 | rxsubchans = V4L2_TUNER_SUB_STEREO | V4L2_TUNER_SUB_MONO; | ||
655 | } else if (val < -4096) { | ||
656 | rxsubchans = V4L2_TUNER_SUB_LANG1 | V4L2_TUNER_SUB_LANG2; | ||
657 | } else { | ||
658 | rxsubchans = V4L2_TUNER_SUB_MONO; | ||
659 | } | ||
660 | newnicam = 0; | ||
661 | break; | ||
662 | case MSP_MODE_FM_NICAM1: | ||
663 | case MSP_MODE_FM_NICAM2: | ||
664 | case MSP_MODE_AM_NICAM: | ||
665 | val = msp3400c_read(client, I2C_MSP3400C_DEM, 0x23); | ||
666 | dprintk(KERN_DEBUG | ||
667 | "msp34xx: nicam sync=%d, mode=%d\n", | ||
668 | val & 1, (val & 0x1e) >> 1); | ||
669 | |||
670 | if (val & 1) { | ||
671 | /* nicam synced */ | ||
672 | switch ((val & 0x1e) >> 1) { | ||
673 | case 0: | ||
674 | case 8: | ||
675 | rxsubchans = V4L2_TUNER_SUB_STEREO; | ||
676 | break; | ||
677 | case 1: | ||
678 | case 9: | ||
679 | rxsubchans = V4L2_TUNER_SUB_MONO | ||
680 | | V4L2_TUNER_SUB_LANG1; | ||
681 | break; | ||
682 | case 2: | ||
683 | case 10: | ||
684 | rxsubchans = V4L2_TUNER_SUB_MONO | ||
685 | | V4L2_TUNER_SUB_LANG1 | ||
686 | | V4L2_TUNER_SUB_LANG2; | ||
687 | break; | ||
688 | default: | ||
689 | rxsubchans = V4L2_TUNER_SUB_MONO; | ||
690 | break; | ||
691 | } | ||
692 | newnicam=1; | ||
693 | } else { | ||
694 | newnicam = 0; | ||
695 | rxsubchans = V4L2_TUNER_SUB_MONO; | ||
696 | } | ||
697 | break; | ||
698 | case MSP_MODE_BTSC: | ||
699 | val = msp3400c_read(client, I2C_MSP3400C_DEM, 0x200); | ||
700 | dprintk(KERN_DEBUG | ||
701 | "msp3410: status=0x%x (pri=%s, sec=%s, %s%s%s)\n", | ||
702 | val, | ||
703 | (val & 0x0002) ? "no" : "yes", | ||
704 | (val & 0x0004) ? "no" : "yes", | ||
705 | (val & 0x0040) ? "stereo" : "mono", | ||
706 | (val & 0x0080) ? ", nicam 2nd mono" : "", | ||
707 | (val & 0x0100) ? ", bilingual/SAP" : ""); | ||
708 | rxsubchans = V4L2_TUNER_SUB_MONO; | ||
709 | if (val & 0x0040) rxsubchans |= V4L2_TUNER_SUB_STEREO; | ||
710 | if (val & 0x0100) rxsubchans |= V4L2_TUNER_SUB_LANG1; | ||
711 | break; | ||
712 | } | ||
713 | if (rxsubchans != msp->rxsubchans) { | ||
714 | update = 1; | ||
715 | dprintk(KERN_DEBUG "msp34xx: watch: rxsubchans %d => %d\n", | ||
716 | msp->rxsubchans,rxsubchans); | ||
717 | msp->rxsubchans = rxsubchans; | ||
718 | } | ||
719 | if (newnicam != msp->nicam_on) { | ||
720 | update = 1; | ||
721 | dprintk(KERN_DEBUG "msp34xx: watch: nicam %d => %d\n", | ||
722 | msp->nicam_on,newnicam); | ||
723 | msp->nicam_on = newnicam; | ||
724 | } | ||
725 | return update; | ||
726 | } | ||
727 | |||
728 | /* | ||
729 | * A kernel thread for msp3400 control -- we don't want to block the | ||
730 | * in the ioctl while doing the sound carrier & stereo detect | ||
731 | */ | ||
732 | |||
733 | static int msp34xx_sleep(struct msp3400c *msp, int timeout) | ||
734 | { | ||
735 | DECLARE_WAITQUEUE(wait, current); | ||
736 | |||
737 | again: | ||
738 | add_wait_queue(&msp->wq, &wait); | ||
739 | if (!kthread_should_stop()) { | ||
740 | if (timeout < 0) { | ||
741 | set_current_state(TASK_INTERRUPTIBLE); | ||
742 | schedule(); | ||
743 | } else { | ||
744 | #if 0 | ||
745 | /* hmm, that one doesn't return on wakeup ... */ | ||
746 | msleep_interruptible(timeout); | ||
747 | #else | ||
748 | set_current_state(TASK_INTERRUPTIBLE); | ||
749 | schedule_timeout(msecs_to_jiffies(timeout)); | ||
750 | #endif | ||
751 | } | ||
752 | } | ||
753 | |||
754 | remove_wait_queue(&msp->wq, &wait); | ||
755 | |||
756 | if (try_to_freeze(PF_FREEZE)) | ||
757 | goto again; | ||
758 | |||
759 | return msp->restart; | ||
760 | } | ||
761 | |||
762 | /* stereo/multilang monitoring */ | ||
763 | static void watch_stereo(struct i2c_client *client) | ||
764 | { | ||
765 | struct msp3400c *msp = i2c_get_clientdata(client); | ||
766 | |||
767 | if (autodetect_stereo(client)) | ||
768 | msp3400c_set_audmode(client,best_audio_mode(msp->rxsubchans)); | ||
769 | if (once) | ||
770 | msp->watch_stereo = 0; | ||
771 | } | ||
772 | |||
773 | static int msp3400c_thread(void *data) | ||
774 | { | ||
775 | struct i2c_client *client = data; | ||
776 | struct msp3400c *msp = i2c_get_clientdata(client); | ||
777 | struct CARRIER_DETECT *cd; | ||
778 | int count, max1,max2,val1,val2, val,this; | ||
779 | |||
780 | printk("msp3400: kthread started\n"); | ||
781 | for (;;) { | ||
782 | d2printk("msp3400: thread: sleep\n"); | ||
783 | msp34xx_sleep(msp,-1); | ||
784 | d2printk("msp3400: thread: wakeup\n"); | ||
785 | |||
786 | restart: | ||
787 | dprintk("msp3410: thread: restart scan\n"); | ||
788 | msp->restart = 0; | ||
789 | if (kthread_should_stop()) | ||
790 | break; | ||
791 | |||
792 | if (VIDEO_MODE_RADIO == msp->norm || | ||
793 | MSP_MODE_EXTERN == msp->mode) { | ||
794 | /* no carrier scan, just unmute */ | ||
795 | printk("msp3400: thread: no carrier scan\n"); | ||
796 | msp3400c_setvolume(client, msp->muted, | ||
797 | msp->volume, msp->balance); | ||
798 | continue; | ||
799 | } | ||
800 | |||
801 | /* mute */ | ||
802 | msp3400c_setvolume(client, msp->muted, 0, 0); | ||
803 | msp3400c_setmode(client, MSP_MODE_AM_DETECT /* +1 */ ); | ||
804 | val1 = val2 = 0; | ||
805 | max1 = max2 = -1; | ||
806 | msp->watch_stereo = 0; | ||
807 | |||
808 | /* some time for the tuner to sync */ | ||
809 | if (msp34xx_sleep(msp,200)) | ||
810 | goto restart; | ||
811 | |||
812 | /* carrier detect pass #1 -- main carrier */ | ||
813 | cd = carrier_detect_main; count = CARRIER_COUNT(carrier_detect_main); | ||
814 | |||
815 | if (amsound && (msp->norm == VIDEO_MODE_SECAM)) { | ||
816 | /* autodetect doesn't work well with AM ... */ | ||
817 | max1 = 3; | ||
818 | count = 0; | ||
819 | dprintk("msp3400: AM sound override\n"); | ||
820 | } | ||
821 | |||
822 | for (this = 0; this < count; this++) { | ||
823 | msp3400c_setcarrier(client, cd[this].cdo,cd[this].cdo); | ||
824 | if (msp34xx_sleep(msp,100)) | ||
825 | goto restart; | ||
826 | val = msp3400c_read(client, I2C_MSP3400C_DFP, 0x1b); | ||
827 | if (val > 32767) | ||
828 | val -= 65536; | ||
829 | if (val1 < val) | ||
830 | val1 = val, max1 = this; | ||
831 | dprintk("msp3400: carrier1 val: %5d / %s\n", val,cd[this].name); | ||
832 | } | ||
833 | |||
834 | /* carrier detect pass #2 -- second (stereo) carrier */ | ||
835 | switch (max1) { | ||
836 | case 1: /* 5.5 */ | ||
837 | cd = carrier_detect_55; | ||
838 | count = CARRIER_COUNT(carrier_detect_55); | ||
839 | break; | ||
840 | case 3: /* 6.5 */ | ||
841 | cd = carrier_detect_65; | ||
842 | count = CARRIER_COUNT(carrier_detect_65); | ||
843 | break; | ||
844 | case 0: /* 4.5 */ | ||
845 | case 2: /* 6.0 */ | ||
846 | default: | ||
847 | cd = NULL; count = 0; | ||
848 | break; | ||
849 | } | ||
850 | |||
851 | if (amsound && (msp->norm == VIDEO_MODE_SECAM)) { | ||
852 | /* autodetect doesn't work well with AM ... */ | ||
853 | cd = NULL; count = 0; max2 = 0; | ||
854 | } | ||
855 | for (this = 0; this < count; this++) { | ||
856 | msp3400c_setcarrier(client, cd[this].cdo,cd[this].cdo); | ||
857 | if (msp34xx_sleep(msp,100)) | ||
858 | goto restart; | ||
859 | val = msp3400c_read(client, I2C_MSP3400C_DFP, 0x1b); | ||
860 | if (val > 32767) | ||
861 | val -= 65536; | ||
862 | if (val2 < val) | ||
863 | val2 = val, max2 = this; | ||
864 | dprintk("msp3400: carrier2 val: %5d / %s\n", val,cd[this].name); | ||
865 | } | ||
866 | |||
867 | /* programm the msp3400 according to the results */ | ||
868 | msp->main = carrier_detect_main[max1].cdo; | ||
869 | switch (max1) { | ||
870 | case 1: /* 5.5 */ | ||
871 | if (max2 == 0) { | ||
872 | /* B/G FM-stereo */ | ||
873 | msp->second = carrier_detect_55[max2].cdo; | ||
874 | msp3400c_setmode(client, MSP_MODE_FM_TERRA); | ||
875 | msp->nicam_on = 0; | ||
876 | msp3400c_set_audmode(client, V4L2_TUNER_MODE_MONO); | ||
877 | msp->watch_stereo = 1; | ||
878 | } else if (max2 == 1 && HAVE_NICAM(msp)) { | ||
879 | /* B/G NICAM */ | ||
880 | msp->second = carrier_detect_55[max2].cdo; | ||
881 | msp3400c_setmode(client, MSP_MODE_FM_NICAM1); | ||
882 | msp->nicam_on = 1; | ||
883 | msp3400c_setcarrier(client, msp->second, msp->main); | ||
884 | msp->watch_stereo = 1; | ||
885 | } else { | ||
886 | goto no_second; | ||
887 | } | ||
888 | break; | ||
889 | case 2: /* 6.0 */ | ||
890 | /* PAL I NICAM */ | ||
891 | msp->second = MSP_CARRIER(6.552); | ||
892 | msp3400c_setmode(client, MSP_MODE_FM_NICAM2); | ||
893 | msp->nicam_on = 1; | ||
894 | msp3400c_setcarrier(client, msp->second, msp->main); | ||
895 | msp->watch_stereo = 1; | ||
896 | break; | ||
897 | case 3: /* 6.5 */ | ||
898 | if (max2 == 1 || max2 == 2) { | ||
899 | /* D/K FM-stereo */ | ||
900 | msp->second = carrier_detect_65[max2].cdo; | ||
901 | msp3400c_setmode(client, MSP_MODE_FM_TERRA); | ||
902 | msp->nicam_on = 0; | ||
903 | msp3400c_set_audmode(client, V4L2_TUNER_MODE_MONO); | ||
904 | msp->watch_stereo = 1; | ||
905 | } else if (max2 == 0 && | ||
906 | msp->norm == VIDEO_MODE_SECAM) { | ||
907 | /* L NICAM or AM-mono */ | ||
908 | msp->second = carrier_detect_65[max2].cdo; | ||
909 | msp3400c_setmode(client, MSP_MODE_AM_NICAM); | ||
910 | msp->nicam_on = 0; | ||
911 | msp3400c_set_audmode(client, V4L2_TUNER_MODE_MONO); | ||
912 | msp3400c_setcarrier(client, msp->second, msp->main); | ||
913 | /* volume prescale for SCART (AM mono input) */ | ||
914 | msp3400c_write(client,I2C_MSP3400C_DFP, 0x000d, 0x1900); | ||
915 | msp->watch_stereo = 1; | ||
916 | } else if (max2 == 0 && HAVE_NICAM(msp)) { | ||
917 | /* D/K NICAM */ | ||
918 | msp->second = carrier_detect_65[max2].cdo; | ||
919 | msp3400c_setmode(client, MSP_MODE_FM_NICAM1); | ||
920 | msp->nicam_on = 1; | ||
921 | msp3400c_setcarrier(client, msp->second, msp->main); | ||
922 | msp->watch_stereo = 1; | ||
923 | } else { | ||
924 | goto no_second; | ||
925 | } | ||
926 | break; | ||
927 | case 0: /* 4.5 */ | ||
928 | default: | ||
929 | no_second: | ||
930 | msp->second = carrier_detect_main[max1].cdo; | ||
931 | msp3400c_setmode(client, MSP_MODE_FM_TERRA); | ||
932 | msp->nicam_on = 0; | ||
933 | msp3400c_setcarrier(client, msp->second, msp->main); | ||
934 | msp->rxsubchans = V4L2_TUNER_SUB_MONO; | ||
935 | msp3400c_set_audmode(client, V4L2_TUNER_MODE_MONO); | ||
936 | break; | ||
937 | } | ||
938 | |||
939 | /* unmute */ | ||
940 | msp3400c_setvolume(client, msp->muted, | ||
941 | msp->volume, msp->balance); | ||
942 | if (debug) | ||
943 | msp3400c_print_mode(msp); | ||
944 | |||
945 | /* monitor tv audio mode */ | ||
946 | while (msp->watch_stereo) { | ||
947 | if (msp34xx_sleep(msp,5000)) | ||
948 | goto restart; | ||
949 | watch_stereo(client); | ||
950 | } | ||
951 | } | ||
952 | dprintk(KERN_DEBUG "msp3400: thread: exit\n"); | ||
953 | return 0; | ||
954 | } | ||
955 | |||
956 | /* ----------------------------------------------------------------------- */ | ||
957 | /* this one uses the automatic sound standard detection of newer */ | ||
958 | /* msp34xx chip versions */ | ||
959 | |||
960 | static struct MODES { | ||
961 | int retval; | ||
962 | int main, second; | ||
963 | char *name; | ||
964 | } modelist[] = { | ||
965 | { 0x0000, 0, 0, "ERROR" }, | ||
966 | { 0x0001, 0, 0, "autodetect start" }, | ||
967 | { 0x0002, MSP_CARRIER(4.5), MSP_CARRIER(4.72), "4.5/4.72 M Dual FM-Stereo" }, | ||
968 | { 0x0003, MSP_CARRIER(5.5), MSP_CARRIER(5.7421875), "5.5/5.74 B/G Dual FM-Stereo" }, | ||
969 | { 0x0004, MSP_CARRIER(6.5), MSP_CARRIER(6.2578125), "6.5/6.25 D/K1 Dual FM-Stereo" }, | ||
970 | { 0x0005, MSP_CARRIER(6.5), MSP_CARRIER(6.7421875), "6.5/6.74 D/K2 Dual FM-Stereo" }, | ||
971 | { 0x0006, MSP_CARRIER(6.5), MSP_CARRIER(6.5), "6.5 D/K FM-Mono (HDEV3)" }, | ||
972 | { 0x0008, MSP_CARRIER(5.5), MSP_CARRIER(5.85), "5.5/5.85 B/G NICAM FM" }, | ||
973 | { 0x0009, MSP_CARRIER(6.5), MSP_CARRIER(5.85), "6.5/5.85 L NICAM AM" }, | ||
974 | { 0x000a, MSP_CARRIER(6.0), MSP_CARRIER(6.55), "6.0/6.55 I NICAM FM" }, | ||
975 | { 0x000b, MSP_CARRIER(6.5), MSP_CARRIER(5.85), "6.5/5.85 D/K NICAM FM" }, | ||
976 | { 0x000c, MSP_CARRIER(6.5), MSP_CARRIER(5.85), "6.5/5.85 D/K NICAM FM (HDEV2)" }, | ||
977 | { 0x0020, MSP_CARRIER(4.5), MSP_CARRIER(4.5), "4.5 M BTSC-Stereo" }, | ||
978 | { 0x0021, MSP_CARRIER(4.5), MSP_CARRIER(4.5), "4.5 M BTSC-Mono + SAP" }, | ||
979 | { 0x0030, MSP_CARRIER(4.5), MSP_CARRIER(4.5), "4.5 M EIA-J Japan Stereo" }, | ||
980 | { 0x0040, MSP_CARRIER(10.7), MSP_CARRIER(10.7), "10.7 FM-Stereo Radio" }, | ||
981 | { 0x0050, MSP_CARRIER(6.5), MSP_CARRIER(6.5), "6.5 SAT-Mono" }, | ||
982 | { 0x0051, MSP_CARRIER(7.02), MSP_CARRIER(7.20), "7.02/7.20 SAT-Stereo" }, | ||
983 | { 0x0060, MSP_CARRIER(7.2), MSP_CARRIER(7.2), "7.2 SAT ADR" }, | ||
984 | { -1, 0, 0, NULL }, /* EOF */ | ||
985 | }; | ||
986 | |||
987 | static inline const char *msp34xx_standard_mode_name(int mode) | ||
988 | { | ||
989 | int i; | ||
990 | for (i = 0; modelist[i].name != NULL; i++) | ||
991 | if (modelist[i].retval == mode) | ||
992 | return modelist[i].name; | ||
993 | return "unknown"; | ||
994 | } | ||
995 | |||
996 | static int msp34xx_modus(int norm) | ||
997 | { | ||
998 | switch (norm) { | ||
999 | case VIDEO_MODE_PAL: | ||
1000 | return 0x1003; | ||
1001 | case VIDEO_MODE_NTSC: /* BTSC */ | ||
1002 | return 0x2003; | ||
1003 | case VIDEO_MODE_SECAM: | ||
1004 | return 0x0003; | ||
1005 | case VIDEO_MODE_RADIO: | ||
1006 | return 0x0003; | ||
1007 | case VIDEO_MODE_AUTO: | ||
1008 | return 0x2003; | ||
1009 | default: | ||
1010 | return 0x0003; | ||
1011 | } | ||
1012 | } | ||
1013 | |||
1014 | static int msp34xx_standard(int norm) | ||
1015 | { | ||
1016 | switch (norm) { | ||
1017 | case VIDEO_MODE_PAL: | ||
1018 | return 1; | ||
1019 | case VIDEO_MODE_NTSC: /* BTSC */ | ||
1020 | return 0x0020; | ||
1021 | case VIDEO_MODE_SECAM: | ||
1022 | return 1; | ||
1023 | case VIDEO_MODE_RADIO: | ||
1024 | return 0x0040; | ||
1025 | default: | ||
1026 | return 1; | ||
1027 | } | ||
1028 | } | ||
1029 | |||
1030 | static int msp3410d_thread(void *data) | ||
1031 | { | ||
1032 | struct i2c_client *client = data; | ||
1033 | struct msp3400c *msp = i2c_get_clientdata(client); | ||
1034 | int mode,val,i,std; | ||
1035 | |||
1036 | printk("msp3410: daemon started\n"); | ||
1037 | for (;;) { | ||
1038 | d2printk(KERN_DEBUG "msp3410: thread: sleep\n"); | ||
1039 | msp34xx_sleep(msp,-1); | ||
1040 | d2printk(KERN_DEBUG "msp3410: thread: wakeup\n"); | ||
1041 | |||
1042 | restart: | ||
1043 | dprintk("msp3410: thread: restart scan\n"); | ||
1044 | msp->restart = 0; | ||
1045 | if (kthread_should_stop()) | ||
1046 | break; | ||
1047 | |||
1048 | if (msp->mode == MSP_MODE_EXTERN) { | ||
1049 | /* no carrier scan needed, just unmute */ | ||
1050 | dprintk(KERN_DEBUG "msp3410: thread: no carrier scan\n"); | ||
1051 | msp3400c_setvolume(client, msp->muted, | ||
1052 | msp->volume, msp->balance); | ||
1053 | continue; | ||
1054 | } | ||
1055 | |||
1056 | /* put into sane state (and mute) */ | ||
1057 | msp3400c_reset(client); | ||
1058 | |||
1059 | /* some time for the tuner to sync */ | ||
1060 | if (msp34xx_sleep(msp,200)) | ||
1061 | goto restart; | ||
1062 | |||
1063 | /* start autodetect */ | ||
1064 | mode = msp34xx_modus(msp->norm); | ||
1065 | std = msp34xx_standard(msp->norm); | ||
1066 | msp3400c_write(client, I2C_MSP3400C_DEM, 0x30, mode); | ||
1067 | msp3400c_write(client, I2C_MSP3400C_DEM, 0x20, std); | ||
1068 | msp->watch_stereo = 0; | ||
1069 | |||
1070 | if (debug) | ||
1071 | printk(KERN_DEBUG "msp3410: setting mode: %s (0x%04x)\n", | ||
1072 | msp34xx_standard_mode_name(std) ,std); | ||
1073 | |||
1074 | if (std != 1) { | ||
1075 | /* programmed some specific mode */ | ||
1076 | val = std; | ||
1077 | } else { | ||
1078 | /* triggered autodetect */ | ||
1079 | for (;;) { | ||
1080 | if (msp34xx_sleep(msp,100)) | ||
1081 | goto restart; | ||
1082 | |||
1083 | /* check results */ | ||
1084 | val = msp3400c_read(client, I2C_MSP3400C_DEM, 0x7e); | ||
1085 | if (val < 0x07ff) | ||
1086 | break; | ||
1087 | dprintk(KERN_DEBUG "msp3410: detection still in progress\n"); | ||
1088 | } | ||
1089 | } | ||
1090 | for (i = 0; modelist[i].name != NULL; i++) | ||
1091 | if (modelist[i].retval == val) | ||
1092 | break; | ||
1093 | dprintk(KERN_DEBUG "msp3410: current mode: %s (0x%04x)\n", | ||
1094 | modelist[i].name ? modelist[i].name : "unknown", | ||
1095 | val); | ||
1096 | msp->main = modelist[i].main; | ||
1097 | msp->second = modelist[i].second; | ||
1098 | |||
1099 | if (amsound && (msp->norm == VIDEO_MODE_SECAM) && (val != 0x0009)) { | ||
1100 | /* autodetection has failed, let backup */ | ||
1101 | dprintk(KERN_DEBUG "msp3410: autodetection failed," | ||
1102 | " switching to backup mode: %s (0x%04x)\n", | ||
1103 | modelist[8].name ? modelist[8].name : "unknown",val); | ||
1104 | val = 0x0009; | ||
1105 | msp3400c_write(client, I2C_MSP3400C_DEM, 0x20, val); | ||
1106 | } | ||
1107 | |||
1108 | /* set various prescales */ | ||
1109 | msp3400c_write(client, I2C_MSP3400C_DFP, 0x0d, 0x1900); /* scart */ | ||
1110 | msp3400c_write(client, I2C_MSP3400C_DFP, 0x0e, 0x2403); /* FM */ | ||
1111 | msp3400c_write(client, I2C_MSP3400C_DFP, 0x10, 0x5a00); /* nicam */ | ||
1112 | |||
1113 | /* set stereo */ | ||
1114 | switch (val) { | ||
1115 | case 0x0008: /* B/G NICAM */ | ||
1116 | case 0x000a: /* I NICAM */ | ||
1117 | if (val == 0x0008) | ||
1118 | msp->mode = MSP_MODE_FM_NICAM1; | ||
1119 | else | ||
1120 | msp->mode = MSP_MODE_FM_NICAM2; | ||
1121 | /* just turn on stereo */ | ||
1122 | msp->rxsubchans = V4L2_TUNER_SUB_STEREO; | ||
1123 | msp->nicam_on = 1; | ||
1124 | msp->watch_stereo = 1; | ||
1125 | msp3400c_set_audmode(client,V4L2_TUNER_MODE_STEREO); | ||
1126 | break; | ||
1127 | case 0x0009: | ||
1128 | msp->mode = MSP_MODE_AM_NICAM; | ||
1129 | msp->rxsubchans = V4L2_TUNER_SUB_MONO; | ||
1130 | msp->nicam_on = 1; | ||
1131 | msp3400c_set_audmode(client,V4L2_TUNER_MODE_MONO); | ||
1132 | msp->watch_stereo = 1; | ||
1133 | break; | ||
1134 | case 0x0020: /* BTSC */ | ||
1135 | /* just turn on stereo */ | ||
1136 | msp->mode = MSP_MODE_BTSC; | ||
1137 | msp->rxsubchans = V4L2_TUNER_SUB_STEREO; | ||
1138 | msp->nicam_on = 0; | ||
1139 | msp->watch_stereo = 1; | ||
1140 | msp3400c_set_audmode(client,V4L2_TUNER_MODE_STEREO); | ||
1141 | break; | ||
1142 | case 0x0040: /* FM radio */ | ||
1143 | msp->mode = MSP_MODE_FM_RADIO; | ||
1144 | msp->rxsubchans = V4L2_TUNER_SUB_STEREO; | ||
1145 | msp->audmode = V4L2_TUNER_MODE_STEREO; | ||
1146 | msp->nicam_on = 0; | ||
1147 | msp->watch_stereo = 0; | ||
1148 | /* not needed in theory if HAVE_RADIO(), but | ||
1149 | short programming enables carrier mute */ | ||
1150 | msp3400c_setmode(client,MSP_MODE_FM_RADIO); | ||
1151 | msp3400c_setcarrier(client, MSP_CARRIER(10.7), | ||
1152 | MSP_CARRIER(10.7)); | ||
1153 | /* scart routing */ | ||
1154 | msp3400c_set_scart(client,SCART_IN2,0); | ||
1155 | #if 0 | ||
1156 | /* radio from SCART_IN2 */ | ||
1157 | msp3400c_write(client,I2C_MSP3400C_DFP, 0x08, 0x0220); | ||
1158 | msp3400c_write(client,I2C_MSP3400C_DFP, 0x09, 0x0220); | ||
1159 | msp3400c_write(client,I2C_MSP3400C_DFP, 0x0b, 0x0220); | ||
1160 | #else | ||
1161 | /* msp34xx does radio decoding */ | ||
1162 | msp3400c_write(client,I2C_MSP3400C_DFP, 0x08, 0x0020); | ||
1163 | msp3400c_write(client,I2C_MSP3400C_DFP, 0x09, 0x0020); | ||
1164 | msp3400c_write(client,I2C_MSP3400C_DFP, 0x0b, 0x0020); | ||
1165 | #endif | ||
1166 | break; | ||
1167 | case 0x0003: | ||
1168 | case 0x0004: | ||
1169 | case 0x0005: | ||
1170 | msp->mode = MSP_MODE_FM_TERRA; | ||
1171 | msp->rxsubchans = V4L2_TUNER_SUB_MONO; | ||
1172 | msp->audmode = V4L2_TUNER_MODE_MONO; | ||
1173 | msp->nicam_on = 0; | ||
1174 | msp->watch_stereo = 1; | ||
1175 | break; | ||
1176 | } | ||
1177 | |||
1178 | /* unmute, restore misc registers */ | ||
1179 | msp3400c_setbass(client, msp->bass); | ||
1180 | msp3400c_settreble(client, msp->treble); | ||
1181 | msp3400c_setvolume(client, msp->muted, | ||
1182 | msp->volume, msp->balance); | ||
1183 | msp3400c_write(client, I2C_MSP3400C_DFP, 0x0013, msp->acb); | ||
1184 | |||
1185 | /* monitor tv audio mode */ | ||
1186 | while (msp->watch_stereo) { | ||
1187 | if (msp34xx_sleep(msp,5000)) | ||
1188 | goto restart; | ||
1189 | watch_stereo(client); | ||
1190 | } | ||
1191 | } | ||
1192 | dprintk(KERN_DEBUG "msp3410: thread: exit\n"); | ||
1193 | return 0; | ||
1194 | } | ||
1195 | |||
1196 | /* ----------------------------------------------------------------------- */ | ||
1197 | /* msp34xxG + (simpler no-thread) */ | ||
1198 | /* this one uses both automatic standard detection and automatic sound */ | ||
1199 | /* select which are available in the newer G versions */ | ||
1200 | /* struct msp: only norm, acb and source are really used in this mode */ | ||
1201 | |||
1202 | static void msp34xxg_set_source(struct i2c_client *client, int source); | ||
1203 | |||
1204 | /* (re-)initialize the msp34xxg, according to the current norm in msp->norm | ||
1205 | * return 0 if it worked, -1 if it failed | ||
1206 | */ | ||
1207 | static int msp34xxg_init(struct i2c_client *client) | ||
1208 | { | ||
1209 | struct msp3400c *msp = i2c_get_clientdata(client); | ||
1210 | int modus,std; | ||
1211 | |||
1212 | if (msp3400c_reset(client)) | ||
1213 | return -1; | ||
1214 | |||
1215 | /* make sure that input/output is muted (paranoid mode) */ | ||
1216 | if (msp3400c_write(client, | ||
1217 | I2C_MSP3400C_DFP, | ||
1218 | 0x13, /* ACB */ | ||
1219 | 0x0f20 /* mute DSP input, mute SCART 1 */)) | ||
1220 | return -1; | ||
1221 | |||
1222 | /* step-by-step initialisation, as described in the manual */ | ||
1223 | modus = msp34xx_modus(msp->norm); | ||
1224 | std = msp34xx_standard(msp->norm); | ||
1225 | modus &= ~0x03; /* STATUS_CHANGE=0 */ | ||
1226 | modus |= 0x01; /* AUTOMATIC_SOUND_DETECTION=1 */ | ||
1227 | if (msp3400c_write(client, | ||
1228 | I2C_MSP3400C_DEM, | ||
1229 | 0x30/*MODUS*/, | ||
1230 | modus)) | ||
1231 | return -1; | ||
1232 | if (msp3400c_write(client, | ||
1233 | I2C_MSP3400C_DEM, | ||
1234 | 0x20/*stanard*/, | ||
1235 | std)) | ||
1236 | return -1; | ||
1237 | |||
1238 | /* write the dfps that may have an influence on | ||
1239 | standard/audio autodetection right now */ | ||
1240 | msp34xxg_set_source(client, msp->source); | ||
1241 | |||
1242 | if (msp3400c_write(client, I2C_MSP3400C_DFP, | ||
1243 | 0x0e, /* AM/FM Prescale */ | ||
1244 | 0x3000 /* default: [15:8] 75khz deviation */)) | ||
1245 | return -1; | ||
1246 | |||
1247 | if (msp3400c_write(client, I2C_MSP3400C_DFP, | ||
1248 | 0x10, /* NICAM Prescale */ | ||
1249 | 0x5a00 /* default: 9db gain (as recommended) */)) | ||
1250 | return -1; | ||
1251 | |||
1252 | if (msp3400c_write(client, | ||
1253 | I2C_MSP3400C_DEM, | ||
1254 | 0x20, /* STANDARD SELECT */ | ||
1255 | standard /* default: 0x01 for automatic standard select*/)) | ||
1256 | return -1; | ||
1257 | return 0; | ||
1258 | } | ||
1259 | |||
1260 | static int msp34xxg_thread(void *data) | ||
1261 | { | ||
1262 | struct i2c_client *client = data; | ||
1263 | struct msp3400c *msp = i2c_get_clientdata(client); | ||
1264 | int val, std, i; | ||
1265 | |||
1266 | printk("msp34xxg: daemon started\n"); | ||
1267 | for (;;) { | ||
1268 | d2printk(KERN_DEBUG "msp34xxg: thread: sleep\n"); | ||
1269 | msp34xx_sleep(msp,-1); | ||
1270 | d2printk(KERN_DEBUG "msp34xxg: thread: wakeup\n"); | ||
1271 | |||
1272 | restart: | ||
1273 | dprintk("msp34xxg: thread: restart scan\n"); | ||
1274 | msp->restart = 0; | ||
1275 | if (kthread_should_stop()) | ||
1276 | break; | ||
1277 | |||
1278 | /* setup the chip*/ | ||
1279 | msp34xxg_init(client); | ||
1280 | std = standard; | ||
1281 | if (std != 0x01) | ||
1282 | goto unmute; | ||
1283 | |||
1284 | /* watch autodetect */ | ||
1285 | dprintk("msp34xxg: triggered autodetect, waiting for result\n"); | ||
1286 | for (i = 0; i < 10; i++) { | ||
1287 | if (msp34xx_sleep(msp,100)) | ||
1288 | goto restart; | ||
1289 | |||
1290 | /* check results */ | ||
1291 | val = msp3400c_read(client, I2C_MSP3400C_DEM, 0x7e); | ||
1292 | if (val < 0x07ff) { | ||
1293 | std = val; | ||
1294 | break; | ||
1295 | } | ||
1296 | dprintk("msp34xxg: detection still in progress\n"); | ||
1297 | } | ||
1298 | if (0x01 == std) { | ||
1299 | dprintk("msp34xxg: detection still in progress after 10 tries. giving up.\n"); | ||
1300 | continue; | ||
1301 | } | ||
1302 | |||
1303 | unmute: | ||
1304 | dprintk("msp34xxg: current mode: %s (0x%04x)\n", | ||
1305 | msp34xx_standard_mode_name(std), std); | ||
1306 | |||
1307 | /* unmute: dispatch sound to scart output, set scart volume */ | ||
1308 | dprintk("msp34xxg: unmute\n"); | ||
1309 | |||
1310 | msp3400c_setbass(client, msp->bass); | ||
1311 | msp3400c_settreble(client, msp->treble); | ||
1312 | msp3400c_setvolume(client, msp->muted, msp->volume, msp->balance); | ||
1313 | |||
1314 | /* restore ACB */ | ||
1315 | if (msp3400c_write(client, | ||
1316 | I2C_MSP3400C_DFP, | ||
1317 | 0x13, /* ACB */ | ||
1318 | msp->acb)) | ||
1319 | return -1; | ||
1320 | } | ||
1321 | dprintk(KERN_DEBUG "msp34xxg: thread: exit\n"); | ||
1322 | return 0; | ||
1323 | } | ||
1324 | |||
1325 | /* set the same 'source' for the loudspeaker, scart and quasi-peak detector | ||
1326 | * the value for source is the same as bit 15:8 of DFP registers 0x08, | ||
1327 | * 0x0a and 0x0c: 0=mono, 1=stereo or A|B, 2=SCART, 3=stereo or A, 4=stereo or B | ||
1328 | * | ||
1329 | * this function replaces msp3400c_setstereo | ||
1330 | */ | ||
1331 | static void msp34xxg_set_source(struct i2c_client *client, int source) | ||
1332 | { | ||
1333 | struct msp3400c *msp = i2c_get_clientdata(client); | ||
1334 | |||
1335 | /* fix matrix mode to stereo and let the msp choose what | ||
1336 | * to output according to 'source', as recommended | ||
1337 | */ | ||
1338 | int value = (source&0x07)<<8|(source==0 ? 0x00:0x20); | ||
1339 | dprintk("msp34xxg: set source to %d (0x%x)\n", source, value); | ||
1340 | msp3400c_write(client, | ||
1341 | I2C_MSP3400C_DFP, | ||
1342 | 0x08, /* Loudspeaker Output */ | ||
1343 | value); | ||
1344 | msp3400c_write(client, | ||
1345 | I2C_MSP3400C_DFP, | ||
1346 | 0x0a, /* SCART1 DA Output */ | ||
1347 | value); | ||
1348 | msp3400c_write(client, | ||
1349 | I2C_MSP3400C_DFP, | ||
1350 | 0x0c, /* Quasi-peak detector */ | ||
1351 | value); | ||
1352 | /* | ||
1353 | * set identification threshold. Personally, I | ||
1354 | * I set it to a higher value that the default | ||
1355 | * of 0x190 to ignore noisy stereo signals. | ||
1356 | * this needs tuning. (recommended range 0x00a0-0x03c0) | ||
1357 | * 0x7f0 = forced mono mode | ||
1358 | */ | ||
1359 | msp3400c_write(client, | ||
1360 | I2C_MSP3400C_DEM, | ||
1361 | 0x22, /* a2 threshold for stereo/bilingual */ | ||
1362 | source==0 ? 0x7f0:stereo_threshold); | ||
1363 | msp->source=source; | ||
1364 | } | ||
1365 | |||
1366 | static void msp34xxg_detect_stereo(struct i2c_client *client) | ||
1367 | { | ||
1368 | struct msp3400c *msp = i2c_get_clientdata(client); | ||
1369 | |||
1370 | int status = msp3400c_read(client, | ||
1371 | I2C_MSP3400C_DEM, | ||
1372 | 0x0200 /* STATUS */); | ||
1373 | int is_bilingual = status&0x100; | ||
1374 | int is_stereo = status&0x40; | ||
1375 | |||
1376 | msp->rxsubchans = 0; | ||
1377 | if (is_stereo) | ||
1378 | msp->rxsubchans |= V4L2_TUNER_SUB_STEREO; | ||
1379 | else | ||
1380 | msp->rxsubchans |= V4L2_TUNER_SUB_MONO; | ||
1381 | if (is_bilingual) { | ||
1382 | msp->rxsubchans |= V4L2_TUNER_SUB_LANG1|V4L2_TUNER_SUB_LANG2; | ||
1383 | /* I'm supposed to check whether it's SAP or not | ||
1384 | * and set only LANG2/SAP in this case. Yet, the MSP | ||
1385 | * does a lot of work to hide this and handle everything | ||
1386 | * the same way. I don't want to work around it so unless | ||
1387 | * this is a problem, I'll handle SAP just like lang1/lang2. | ||
1388 | */ | ||
1389 | } | ||
1390 | dprintk("msp34xxg: status=0x%x, stereo=%d, bilingual=%d -> rxsubchans=%d\n", | ||
1391 | status, is_stereo, is_bilingual, msp->rxsubchans); | ||
1392 | } | ||
1393 | |||
1394 | static void msp34xxg_set_audmode(struct i2c_client *client, int audmode) | ||
1395 | { | ||
1396 | struct msp3400c *msp = i2c_get_clientdata(client); | ||
1397 | int source = 0; | ||
1398 | |||
1399 | switch (audmode) { | ||
1400 | case V4L2_TUNER_MODE_MONO: | ||
1401 | source=0; /* mono only */ | ||
1402 | break; | ||
1403 | case V4L2_TUNER_MODE_STEREO: | ||
1404 | source=1; /* stereo or A|B, see comment in msp34xxg_get_v4l2_stereo() */ | ||
1405 | /* problem: that could also mean 2 (scart input) */ | ||
1406 | break; | ||
1407 | case V4L2_TUNER_MODE_LANG1: | ||
1408 | source=3; /* stereo or A */ | ||
1409 | break; | ||
1410 | case V4L2_TUNER_MODE_LANG2: | ||
1411 | source=4; /* stereo or B */ | ||
1412 | break; | ||
1413 | default: /* doing nothing: a safe, sane default */ | ||
1414 | audmode = 0; | ||
1415 | return; | ||
1416 | } | ||
1417 | msp->audmode = audmode; | ||
1418 | msp34xxg_set_source(client, source); | ||
1419 | } | ||
1420 | |||
1421 | |||
1422 | /* ----------------------------------------------------------------------- */ | ||
1423 | |||
1424 | static int msp_attach(struct i2c_adapter *adap, int addr, int kind); | ||
1425 | static int msp_detach(struct i2c_client *client); | ||
1426 | static int msp_probe(struct i2c_adapter *adap); | ||
1427 | static int msp_command(struct i2c_client *client, unsigned int cmd, void *arg); | ||
1428 | |||
1429 | static int msp_suspend(struct device * dev, u32 state, u32 level); | ||
1430 | static int msp_resume(struct device * dev, u32 level); | ||
1431 | |||
1432 | static void msp_wake_thread(struct i2c_client *client); | ||
1433 | |||
1434 | static struct i2c_driver driver = { | ||
1435 | .owner = THIS_MODULE, | ||
1436 | .name = "i2c msp3400 driver", | ||
1437 | .id = I2C_DRIVERID_MSP3400, | ||
1438 | .flags = I2C_DF_NOTIFY, | ||
1439 | .attach_adapter = msp_probe, | ||
1440 | .detach_client = msp_detach, | ||
1441 | .command = msp_command, | ||
1442 | .driver = { | ||
1443 | .suspend = msp_suspend, | ||
1444 | .resume = msp_resume, | ||
1445 | }, | ||
1446 | }; | ||
1447 | |||
1448 | static struct i2c_client client_template = | ||
1449 | { | ||
1450 | I2C_DEVNAME("(unset)"), | ||
1451 | .flags = I2C_CLIENT_ALLOW_USE, | ||
1452 | .driver = &driver, | ||
1453 | }; | ||
1454 | |||
1455 | static int msp_attach(struct i2c_adapter *adap, int addr, int kind) | ||
1456 | { | ||
1457 | struct msp3400c *msp; | ||
1458 | struct i2c_client *c; | ||
1459 | int (*thread_func)(void *data) = NULL; | ||
1460 | |||
1461 | client_template.adapter = adap; | ||
1462 | client_template.addr = addr; | ||
1463 | |||
1464 | if (-1 == msp3400c_reset(&client_template)) { | ||
1465 | dprintk("msp3400: no chip found\n"); | ||
1466 | return -1; | ||
1467 | } | ||
1468 | |||
1469 | if (NULL == (c = kmalloc(sizeof(struct i2c_client),GFP_KERNEL))) | ||
1470 | return -ENOMEM; | ||
1471 | memcpy(c,&client_template,sizeof(struct i2c_client)); | ||
1472 | if (NULL == (msp = kmalloc(sizeof(struct msp3400c),GFP_KERNEL))) { | ||
1473 | kfree(c); | ||
1474 | return -ENOMEM; | ||
1475 | } | ||
1476 | |||
1477 | memset(msp,0,sizeof(struct msp3400c)); | ||
1478 | msp->volume = 58880; /* 0db gain */ | ||
1479 | msp->balance = 32768; | ||
1480 | msp->bass = 32768; | ||
1481 | msp->treble = 32768; | ||
1482 | msp->input = -1; | ||
1483 | msp->muted = 1; | ||
1484 | |||
1485 | i2c_set_clientdata(c, msp); | ||
1486 | init_waitqueue_head(&msp->wq); | ||
1487 | |||
1488 | if (-1 == msp3400c_reset(c)) { | ||
1489 | kfree(msp); | ||
1490 | kfree(c); | ||
1491 | dprintk("msp3400: no chip found\n"); | ||
1492 | return -1; | ||
1493 | } | ||
1494 | |||
1495 | msp->rev1 = msp3400c_read(c, I2C_MSP3400C_DFP, 0x1e); | ||
1496 | if (-1 != msp->rev1) | ||
1497 | msp->rev2 = msp3400c_read(c, I2C_MSP3400C_DFP, 0x1f); | ||
1498 | if ((-1 == msp->rev1) || (0 == msp->rev1 && 0 == msp->rev2)) { | ||
1499 | kfree(msp); | ||
1500 | kfree(c); | ||
1501 | printk("msp3400: error while reading chip version\n"); | ||
1502 | return -1; | ||
1503 | } | ||
1504 | |||
1505 | #if 0 | ||
1506 | /* this will turn on a 1kHz beep - might be useful for debugging... */ | ||
1507 | msp3400c_write(c,I2C_MSP3400C_DFP, 0x0014, 0x1040); | ||
1508 | #endif | ||
1509 | msp3400c_setvolume(c, msp->muted, msp->volume, msp->balance); | ||
1510 | |||
1511 | snprintf(c->name, sizeof(c->name), "MSP34%02d%c-%c%d", | ||
1512 | (msp->rev2>>8)&0xff, (msp->rev1&0xff)+'@', | ||
1513 | ((msp->rev1>>8)&0xff)+'@', msp->rev2&0x1f); | ||
1514 | |||
1515 | msp->opmode = opmode; | ||
1516 | if (OPMODE_AUTO == msp->opmode) { | ||
1517 | #if 0 /* seems to work for ivtv only, disable by default for now ... */ | ||
1518 | if (HAVE_SIMPLER(msp)) | ||
1519 | msp->opmode = OPMODE_SIMPLER; | ||
1520 | else | ||
1521 | #endif | ||
1522 | if (HAVE_SIMPLE(msp)) | ||
1523 | msp->opmode = OPMODE_SIMPLE; | ||
1524 | else | ||
1525 | msp->opmode = OPMODE_MANUAL; | ||
1526 | } | ||
1527 | |||
1528 | /* hello world :-) */ | ||
1529 | printk(KERN_INFO "msp34xx: init: chip=%s",i2c_clientname(c)); | ||
1530 | if (HAVE_NICAM(msp)) | ||
1531 | printk(" +nicam"); | ||
1532 | if (HAVE_SIMPLE(msp)) | ||
1533 | printk(" +simple"); | ||
1534 | if (HAVE_SIMPLER(msp)) | ||
1535 | printk(" +simpler"); | ||
1536 | if (HAVE_RADIO(msp)) | ||
1537 | printk(" +radio"); | ||
1538 | |||
1539 | /* version-specific initialization */ | ||
1540 | switch (msp->opmode) { | ||
1541 | case OPMODE_MANUAL: | ||
1542 | printk(" mode=manual"); | ||
1543 | thread_func = msp3400c_thread; | ||
1544 | break; | ||
1545 | case OPMODE_SIMPLE: | ||
1546 | printk(" mode=simple"); | ||
1547 | thread_func = msp3410d_thread; | ||
1548 | break; | ||
1549 | case OPMODE_SIMPLER: | ||
1550 | printk(" mode=simpler"); | ||
1551 | thread_func = msp34xxg_thread; | ||
1552 | break; | ||
1553 | } | ||
1554 | printk("\n"); | ||
1555 | |||
1556 | /* startup control thread if needed */ | ||
1557 | if (thread_func) { | ||
1558 | msp->kthread = kthread_run(thread_func, c, "msp34xx"); | ||
1559 | if (NULL == msp->kthread) | ||
1560 | printk(KERN_WARNING "msp34xx: kernel_thread() failed\n"); | ||
1561 | msp_wake_thread(c); | ||
1562 | } | ||
1563 | |||
1564 | /* done */ | ||
1565 | i2c_attach_client(c); | ||
1566 | return 0; | ||
1567 | } | ||
1568 | |||
1569 | static int msp_detach(struct i2c_client *client) | ||
1570 | { | ||
1571 | struct msp3400c *msp = i2c_get_clientdata(client); | ||
1572 | |||
1573 | /* shutdown control thread */ | ||
1574 | if (msp->kthread >= 0) { | ||
1575 | msp->restart = 1; | ||
1576 | kthread_stop(msp->kthread); | ||
1577 | } | ||
1578 | msp3400c_reset(client); | ||
1579 | |||
1580 | i2c_detach_client(client); | ||
1581 | kfree(msp); | ||
1582 | kfree(client); | ||
1583 | return 0; | ||
1584 | } | ||
1585 | |||
1586 | static int msp_probe(struct i2c_adapter *adap) | ||
1587 | { | ||
1588 | if (adap->class & I2C_CLASS_TV_ANALOG) | ||
1589 | return i2c_probe(adap, &addr_data, msp_attach); | ||
1590 | return 0; | ||
1591 | } | ||
1592 | |||
1593 | static void msp_wake_thread(struct i2c_client *client) | ||
1594 | { | ||
1595 | struct msp3400c *msp = i2c_get_clientdata(client); | ||
1596 | |||
1597 | if (NULL == msp->kthread) | ||
1598 | return; | ||
1599 | msp3400c_setvolume(client,msp->muted,0,0); | ||
1600 | msp->watch_stereo = 0; | ||
1601 | msp->restart = 1; | ||
1602 | wake_up_interruptible(&msp->wq); | ||
1603 | } | ||
1604 | |||
1605 | /* ----------------------------------------------------------------------- */ | ||
1606 | |||
1607 | static int mode_v4l2_to_v4l1(int rxsubchans) | ||
1608 | { | ||
1609 | int mode = 0; | ||
1610 | |||
1611 | if (rxsubchans & V4L2_TUNER_SUB_STEREO) | ||
1612 | mode |= VIDEO_SOUND_STEREO; | ||
1613 | if (rxsubchans & V4L2_TUNER_SUB_LANG2) | ||
1614 | mode |= VIDEO_SOUND_LANG2; | ||
1615 | if (rxsubchans & V4L2_TUNER_SUB_LANG1) | ||
1616 | mode |= VIDEO_SOUND_LANG1; | ||
1617 | if (0 == mode) | ||
1618 | mode |= VIDEO_SOUND_MONO; | ||
1619 | return mode; | ||
1620 | } | ||
1621 | |||
1622 | static int mode_v4l1_to_v4l2(int mode) | ||
1623 | { | ||
1624 | if (mode & VIDEO_SOUND_STEREO) | ||
1625 | return V4L2_TUNER_MODE_STEREO; | ||
1626 | if (mode & VIDEO_SOUND_LANG2) | ||
1627 | return V4L2_TUNER_MODE_LANG2; | ||
1628 | if (mode & VIDEO_SOUND_LANG1) | ||
1629 | return V4L2_TUNER_MODE_LANG1; | ||
1630 | return V4L2_TUNER_MODE_MONO; | ||
1631 | } | ||
1632 | |||
1633 | static void msp_any_detect_stereo(struct i2c_client *client) | ||
1634 | { | ||
1635 | struct msp3400c *msp = i2c_get_clientdata(client); | ||
1636 | |||
1637 | switch (msp->opmode) { | ||
1638 | case OPMODE_MANUAL: | ||
1639 | case OPMODE_SIMPLE: | ||
1640 | autodetect_stereo(client); | ||
1641 | break; | ||
1642 | case OPMODE_SIMPLER: | ||
1643 | msp34xxg_detect_stereo(client); | ||
1644 | break; | ||
1645 | } | ||
1646 | } | ||
1647 | |||
1648 | static void msp_any_set_audmode(struct i2c_client *client, int audmode) | ||
1649 | { | ||
1650 | struct msp3400c *msp = i2c_get_clientdata(client); | ||
1651 | |||
1652 | switch (msp->opmode) { | ||
1653 | case OPMODE_MANUAL: | ||
1654 | case OPMODE_SIMPLE: | ||
1655 | msp->watch_stereo = 0; | ||
1656 | msp3400c_set_audmode(client, audmode); | ||
1657 | break; | ||
1658 | case OPMODE_SIMPLER: | ||
1659 | msp34xxg_set_audmode(client, audmode); | ||
1660 | break; | ||
1661 | } | ||
1662 | } | ||
1663 | |||
1664 | static int msp_command(struct i2c_client *client, unsigned int cmd, void *arg) | ||
1665 | { | ||
1666 | struct msp3400c *msp = i2c_get_clientdata(client); | ||
1667 | __u16 *sarg = arg; | ||
1668 | int scart = 0; | ||
1669 | |||
1670 | switch (cmd) { | ||
1671 | |||
1672 | case AUDC_SET_INPUT: | ||
1673 | dprintk(KERN_DEBUG "msp34xx: AUDC_SET_INPUT(%d)\n",*sarg); | ||
1674 | if (*sarg == msp->input) | ||
1675 | break; | ||
1676 | msp->input = *sarg; | ||
1677 | switch (*sarg) { | ||
1678 | case AUDIO_RADIO: | ||
1679 | /* Hauppauge uses IN2 for the radio */ | ||
1680 | msp->mode = MSP_MODE_FM_RADIO; | ||
1681 | scart = SCART_IN2; | ||
1682 | break; | ||
1683 | case AUDIO_EXTERN_1: | ||
1684 | /* IN1 is often used for external input ... */ | ||
1685 | msp->mode = MSP_MODE_EXTERN; | ||
1686 | scart = SCART_IN1; | ||
1687 | break; | ||
1688 | case AUDIO_EXTERN_2: | ||
1689 | /* ... sometimes it is IN2 through ;) */ | ||
1690 | msp->mode = MSP_MODE_EXTERN; | ||
1691 | scart = SCART_IN2; | ||
1692 | break; | ||
1693 | case AUDIO_TUNER: | ||
1694 | msp->mode = -1; | ||
1695 | break; | ||
1696 | default: | ||
1697 | if (*sarg & AUDIO_MUTE) | ||
1698 | msp3400c_set_scart(client,SCART_MUTE,0); | ||
1699 | break; | ||
1700 | } | ||
1701 | if (scart) { | ||
1702 | msp->rxsubchans = V4L2_TUNER_SUB_STEREO; | ||
1703 | msp->audmode = V4L2_TUNER_MODE_STEREO; | ||
1704 | msp3400c_set_scart(client,scart,0); | ||
1705 | msp3400c_write(client,I2C_MSP3400C_DFP,0x000d,0x1900); | ||
1706 | if (msp->opmode != OPMODE_SIMPLER) | ||
1707 | msp3400c_set_audmode(client, msp->audmode); | ||
1708 | } | ||
1709 | msp_wake_thread(client); | ||
1710 | break; | ||
1711 | |||
1712 | case AUDC_SET_RADIO: | ||
1713 | dprintk(KERN_DEBUG "msp34xx: AUDC_SET_RADIO\n"); | ||
1714 | msp->norm = VIDEO_MODE_RADIO; | ||
1715 | dprintk(KERN_DEBUG "msp34xx: switching to radio mode\n"); | ||
1716 | msp->watch_stereo = 0; | ||
1717 | switch (msp->opmode) { | ||
1718 | case OPMODE_MANUAL: | ||
1719 | /* set msp3400 to FM radio mode */ | ||
1720 | msp3400c_setmode(client,MSP_MODE_FM_RADIO); | ||
1721 | msp3400c_setcarrier(client, MSP_CARRIER(10.7), | ||
1722 | MSP_CARRIER(10.7)); | ||
1723 | msp3400c_setvolume(client, msp->muted, | ||
1724 | msp->volume, msp->balance); | ||
1725 | break; | ||
1726 | case OPMODE_SIMPLE: | ||
1727 | case OPMODE_SIMPLER: | ||
1728 | /* the thread will do for us */ | ||
1729 | msp_wake_thread(client); | ||
1730 | break; | ||
1731 | } | ||
1732 | break; | ||
1733 | |||
1734 | /* --- v4l ioctls --- */ | ||
1735 | /* take care: bttv does userspace copying, we'll get a | ||
1736 | kernel pointer here... */ | ||
1737 | case VIDIOCGAUDIO: | ||
1738 | { | ||
1739 | struct video_audio *va = arg; | ||
1740 | |||
1741 | dprintk(KERN_DEBUG "msp34xx: VIDIOCGAUDIO\n"); | ||
1742 | va->flags |= VIDEO_AUDIO_VOLUME | | ||
1743 | VIDEO_AUDIO_BASS | | ||
1744 | VIDEO_AUDIO_TREBLE | | ||
1745 | VIDEO_AUDIO_MUTABLE; | ||
1746 | if (msp->muted) | ||
1747 | va->flags |= VIDEO_AUDIO_MUTE; | ||
1748 | |||
1749 | va->volume = msp->volume; | ||
1750 | va->balance = (va->volume) ? msp->balance : 32768; | ||
1751 | va->bass = msp->bass; | ||
1752 | va->treble = msp->treble; | ||
1753 | |||
1754 | msp_any_detect_stereo(client); | ||
1755 | va->mode = mode_v4l2_to_v4l1(msp->rxsubchans); | ||
1756 | break; | ||
1757 | } | ||
1758 | case VIDIOCSAUDIO: | ||
1759 | { | ||
1760 | struct video_audio *va = arg; | ||
1761 | |||
1762 | dprintk(KERN_DEBUG "msp34xx: VIDIOCSAUDIO\n"); | ||
1763 | msp->muted = (va->flags & VIDEO_AUDIO_MUTE); | ||
1764 | msp->volume = va->volume; | ||
1765 | msp->balance = va->balance; | ||
1766 | msp->bass = va->bass; | ||
1767 | msp->treble = va->treble; | ||
1768 | |||
1769 | msp3400c_setvolume(client, msp->muted, | ||
1770 | msp->volume, msp->balance); | ||
1771 | msp3400c_setbass(client,msp->bass); | ||
1772 | msp3400c_settreble(client,msp->treble); | ||
1773 | |||
1774 | if (va->mode != 0 && msp->norm != VIDEO_MODE_RADIO) | ||
1775 | msp_any_set_audmode(client,mode_v4l1_to_v4l2(va->mode)); | ||
1776 | break; | ||
1777 | } | ||
1778 | case VIDIOCSCHAN: | ||
1779 | { | ||
1780 | struct video_channel *vc = arg; | ||
1781 | |||
1782 | dprintk(KERN_DEBUG "msp34xx: VIDIOCSCHAN (norm=%d)\n",vc->norm); | ||
1783 | msp->norm = vc->norm; | ||
1784 | msp_wake_thread(client); | ||
1785 | break; | ||
1786 | } | ||
1787 | |||
1788 | case VIDIOCSFREQ: | ||
1789 | case VIDIOC_S_FREQUENCY: | ||
1790 | { | ||
1791 | /* new channel -- kick audio carrier scan */ | ||
1792 | dprintk(KERN_DEBUG "msp34xx: VIDIOCSFREQ\n"); | ||
1793 | msp_wake_thread(client); | ||
1794 | break; | ||
1795 | } | ||
1796 | |||
1797 | /* --- v4l2 ioctls --- */ | ||
1798 | case VIDIOC_G_TUNER: | ||
1799 | { | ||
1800 | struct v4l2_tuner *vt = arg; | ||
1801 | |||
1802 | msp_any_detect_stereo(client); | ||
1803 | vt->audmode = msp->audmode; | ||
1804 | vt->rxsubchans = msp->rxsubchans; | ||
1805 | vt->capability = V4L2_TUNER_CAP_STEREO | | ||
1806 | V4L2_TUNER_CAP_LANG1| | ||
1807 | V4L2_TUNER_CAP_LANG2; | ||
1808 | break; | ||
1809 | } | ||
1810 | case VIDIOC_S_TUNER: | ||
1811 | { | ||
1812 | struct v4l2_tuner *vt=(struct v4l2_tuner *)arg; | ||
1813 | |||
1814 | /* only set audmode */ | ||
1815 | if (vt->audmode != -1 && vt->audmode != 0) | ||
1816 | msp_any_set_audmode(client, vt->audmode); | ||
1817 | break; | ||
1818 | } | ||
1819 | |||
1820 | /* msp34xx specific */ | ||
1821 | case MSP_SET_MATRIX: | ||
1822 | { | ||
1823 | struct msp_matrix *mspm = arg; | ||
1824 | |||
1825 | dprintk(KERN_DEBUG "msp34xx: MSP_SET_MATRIX\n"); | ||
1826 | msp3400c_set_scart(client, mspm->input, mspm->output); | ||
1827 | break; | ||
1828 | } | ||
1829 | |||
1830 | default: | ||
1831 | /* nothing */ | ||
1832 | break; | ||
1833 | } | ||
1834 | return 0; | ||
1835 | } | ||
1836 | |||
1837 | static int msp_suspend(struct device * dev, u32 state, u32 level) | ||
1838 | { | ||
1839 | struct i2c_client *c = container_of(dev, struct i2c_client, dev); | ||
1840 | |||
1841 | dprintk("msp34xx: suspend\n"); | ||
1842 | msp3400c_reset(c); | ||
1843 | return 0; | ||
1844 | } | ||
1845 | |||
1846 | static int msp_resume(struct device * dev, u32 level) | ||
1847 | { | ||
1848 | struct i2c_client *c = container_of(dev, struct i2c_client, dev); | ||
1849 | |||
1850 | dprintk("msp34xx: resume\n"); | ||
1851 | msp_wake_thread(c); | ||
1852 | return 0; | ||
1853 | } | ||
1854 | |||
1855 | /* ----------------------------------------------------------------------- */ | ||
1856 | |||
1857 | static int __init msp3400_init_module(void) | ||
1858 | { | ||
1859 | return i2c_add_driver(&driver); | ||
1860 | } | ||
1861 | |||
1862 | static void __exit msp3400_cleanup_module(void) | ||
1863 | { | ||
1864 | i2c_del_driver(&driver); | ||
1865 | } | ||
1866 | |||
1867 | module_init(msp3400_init_module); | ||
1868 | module_exit(msp3400_cleanup_module); | ||
1869 | |||
1870 | /* | ||
1871 | * Overrides for Emacs so that we follow Linus's tabbing style. | ||
1872 | * --------------------------------------------------------------------------- | ||
1873 | * Local variables: | ||
1874 | * c-basic-offset: 8 | ||
1875 | * End: | ||
1876 | */ | ||