Commit | Line | Data |
---|---|---|
866b8695 GKH |
1 | /* |
2 | * Copyright (C) 2005-2006 Micronas USA Inc. | |
3 | * | |
4 | * This program is free software; you can redistribute it and/or modify | |
5 | * it under the terms of the GNU General Public License (Version 2) as | |
6 | * published by the Free Software Foundation. | |
7 | * | |
8 | * This program is distributed in the hope that it will be useful, | |
9 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
10 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
11 | * GNU General Public License for more details. | |
12 | * | |
13 | * You should have received a copy of the GNU General Public License | |
14 | * along with this program; if not, write to the Free Software Foundation, | |
15 | * Inc., 59 Temple Place - Suite 330, Boston MA 02111-1307, USA. | |
16 | */ | |
17 | ||
18 | #include <linux/module.h> | |
19 | #include <linux/init.h> | |
866b8695 | 20 | #include <linux/i2c.h> |
df20d69e | 21 | #include <linux/videodev2.h> |
866b8695 GKH |
22 | #include <media/tuner.h> |
23 | #include <media/v4l2-common.h> | |
df20d69e | 24 | #include <media/v4l2-ioctl.h> |
866b8695 GKH |
25 | |
26 | #include "wis-i2c.h" | |
27 | ||
28 | /* #define MPX_DEBUG */ | |
29 | ||
30 | /* AS(IF/MPX) pin: LOW HIGH/OPEN | |
31 | * IF/MPX address: 0x42/0x40 0x43/0x44 | |
32 | */ | |
33 | #define IF_I2C_ADDR 0x43 | |
34 | #define MPX_I2C_ADDR 0x44 | |
35 | ||
36 | static v4l2_std_id force_band; | |
37 | static char force_band_str[] = "-"; | |
38 | module_param_string(force_band, force_band_str, sizeof(force_band_str), 0644); | |
39 | static int force_mpx_mode = -1; | |
40 | module_param(force_mpx_mode, int, 0644); | |
41 | ||
42 | /* Store tuner info in the same format as tuner.c, so maybe we can put the | |
43 | * Sony tuner support in there. */ | |
44 | struct sony_tunertype { | |
45 | char *name; | |
46 | unsigned char Vendor; /* unused here */ | |
47 | unsigned char Type; /* unused here */ | |
48 | ||
49 | unsigned short thresh1; /* band switch VHF_LO <=> VHF_HI */ | |
50 | unsigned short thresh2; /* band switch VHF_HI <=> UHF */ | |
51 | unsigned char VHF_L; | |
52 | unsigned char VHF_H; | |
53 | unsigned char UHF; | |
54 | unsigned char config; | |
55 | unsigned short IFPCoff; | |
56 | }; | |
57 | ||
58 | /* This array is indexed by (tuner_type - 200) */ | |
59 | static struct sony_tunertype sony_tuners[] = { | |
60 | { "Sony PAL+SECAM (BTF-PG472Z)", 0, 0, | |
61 | 16*144.25, 16*427.25, 0x01, 0x02, 0x04, 0xc6, 623}, | |
62 | { "Sony NTSC_JP (BTF-PK467Z)", 0, 0, | |
63 | 16*220.25, 16*467.25, 0x01, 0x02, 0x04, 0xc6, 940}, | |
64 | { "Sony NTSC (BTF-PB463Z)", 0, 0, | |
65 | 16*130.25, 16*364.25, 0x01, 0x02, 0x04, 0xc6, 732}, | |
66 | }; | |
67 | ||
68 | struct wis_sony_tuner { | |
69 | int type; | |
70 | v4l2_std_id std; | |
71 | unsigned int freq; | |
72 | int mpxmode; | |
73 | u32 audmode; | |
74 | }; | |
75 | ||
76 | /* Basically the same as default_set_tv_freq() in tuner.c */ | |
77 | static int set_freq(struct i2c_client *client, int freq) | |
78 | { | |
79 | struct wis_sony_tuner *t = i2c_get_clientdata(client); | |
80 | char *band_name; | |
81 | int n; | |
82 | int band_select; | |
83 | struct sony_tunertype *tun; | |
84 | u8 buffer[4]; | |
85 | ||
86 | tun = &sony_tuners[t->type - 200]; | |
87 | if (freq < tun->thresh1) { | |
88 | band_name = "VHF_L"; | |
89 | band_select = tun->VHF_L; | |
90 | } else if (freq < tun->thresh2) { | |
91 | band_name = "VHF_H"; | |
92 | band_select = tun->VHF_H; | |
93 | } else { | |
94 | band_name = "UHF"; | |
95 | band_select = tun->UHF; | |
96 | } | |
97 | printk(KERN_DEBUG "wis-sony-tuner: tuning to frequency %d.%04d (%s)\n", | |
98 | freq / 16, (freq % 16) * 625, band_name); | |
99 | n = freq + tun->IFPCoff; | |
100 | ||
101 | buffer[0] = n >> 8; | |
102 | buffer[1] = n & 0xff; | |
103 | buffer[2] = tun->config; | |
104 | buffer[3] = band_select; | |
105 | i2c_master_send(client, buffer, 4); | |
106 | ||
107 | return 0; | |
108 | } | |
109 | ||
110 | static int mpx_write(struct i2c_client *client, int dev, int addr, int val) | |
111 | { | |
112 | u8 buffer[5]; | |
113 | struct i2c_msg msg; | |
114 | ||
115 | buffer[0] = dev; | |
116 | buffer[1] = addr >> 8; | |
117 | buffer[2] = addr & 0xff; | |
118 | buffer[3] = val >> 8; | |
119 | buffer[4] = val & 0xff; | |
120 | msg.addr = MPX_I2C_ADDR; | |
121 | msg.flags = 0; | |
122 | msg.len = 5; | |
123 | msg.buf = buffer; | |
124 | i2c_transfer(client->adapter, &msg, 1); | |
125 | return 0; | |
126 | } | |
127 | ||
128 | /* | |
129 | * MPX register values for the BTF-PG472Z: | |
130 | * | |
131 | * FM_ NICAM_ SCART_ | |
132 | * MODUS SOURCE ACB PRESCAL PRESCAL PRESCAL SYSTEM VOLUME | |
133 | * 10/0030 12/0008 12/0013 12/000E 12/0010 12/0000 10/0020 12/0000 | |
134 | * --------------------------------------------------------------- | |
135 | * Auto 1003 0020 0100 2603 5000 XXXX 0001 7500 | |
136 | * | |
137 | * B/G | |
138 | * Mono 1003 0020 0100 2603 5000 XXXX 0003 7500 | |
139 | * A2 1003 0020 0100 2601 5000 XXXX 0003 7500 | |
140 | * NICAM 1003 0120 0100 2603 5000 XXXX 0008 7500 | |
141 | * | |
142 | * I | |
143 | * Mono 1003 0020 0100 2603 7900 XXXX 000A 7500 | |
144 | * NICAM 1003 0120 0100 2603 7900 XXXX 000A 7500 | |
145 | * | |
146 | * D/K | |
147 | * Mono 1003 0020 0100 2603 5000 XXXX 0004 7500 | |
148 | * A2-1 1003 0020 0100 2601 5000 XXXX 0004 7500 | |
149 | * A2-2 1003 0020 0100 2601 5000 XXXX 0005 7500 | |
150 | * A2-3 1003 0020 0100 2601 5000 XXXX 0007 7500 | |
151 | * NICAM 1003 0120 0100 2603 5000 XXXX 000B 7500 | |
152 | * | |
153 | * L/L' | |
154 | * Mono 0003 0200 0100 7C03 5000 2200 0009 7500 | |
155 | * NICAM 0003 0120 0100 7C03 5000 XXXX 0009 7500 | |
156 | * | |
157 | * M | |
158 | * Mono 1003 0200 0100 2B03 5000 2B00 0002 7500 | |
159 | * | |
160 | * For Asia, replace the 0x26XX in FM_PRESCALE with 0x14XX. | |
161 | * | |
162 | * Bilingual selection in A2/NICAM: | |
163 | * | |
164 | * High byte of SOURCE Left chan Right chan | |
165 | * 0x01 MAIN SUB | |
166 | * 0x03 MAIN MAIN | |
167 | * 0x04 SUB SUB | |
168 | * | |
169 | * Force mono in NICAM by setting the high byte of SOURCE to 0x02 (L/L') or | |
170 | * 0x00 (all other bands). Force mono in A2 with FMONO_A2: | |
171 | * | |
172 | * FMONO_A2 | |
173 | * 10/0022 | |
174 | * -------- | |
175 | * Forced mono ON 07F0 | |
176 | * Forced mono OFF 0190 | |
177 | */ | |
178 | ||
179 | static struct { | |
180 | enum { AUD_MONO, AUD_A2, AUD_NICAM, AUD_NICAM_L } audio_mode; | |
181 | u16 modus; | |
182 | u16 source; | |
183 | u16 acb; | |
184 | u16 fm_prescale; | |
185 | u16 nicam_prescale; | |
186 | u16 scart_prescale; | |
187 | u16 system; | |
188 | u16 volume; | |
189 | } mpx_audio_modes[] = { | |
190 | /* Auto */ { AUD_MONO, 0x1003, 0x0020, 0x0100, 0x2603, | |
191 | 0x5000, 0x0000, 0x0001, 0x7500 }, | |
192 | /* B/G Mono */ { AUD_MONO, 0x1003, 0x0020, 0x0100, 0x2603, | |
193 | 0x5000, 0x0000, 0x0003, 0x7500 }, | |
194 | /* B/G A2 */ { AUD_A2, 0x1003, 0x0020, 0x0100, 0x2601, | |
195 | 0x5000, 0x0000, 0x0003, 0x7500 }, | |
196 | /* B/G NICAM */ { AUD_NICAM, 0x1003, 0x0120, 0x0100, 0x2603, | |
197 | 0x5000, 0x0000, 0x0008, 0x7500 }, | |
198 | /* I Mono */ { AUD_MONO, 0x1003, 0x0020, 0x0100, 0x2603, | |
199 | 0x7900, 0x0000, 0x000A, 0x7500 }, | |
200 | /* I NICAM */ { AUD_NICAM, 0x1003, 0x0120, 0x0100, 0x2603, | |
201 | 0x7900, 0x0000, 0x000A, 0x7500 }, | |
202 | /* D/K Mono */ { AUD_MONO, 0x1003, 0x0020, 0x0100, 0x2603, | |
203 | 0x5000, 0x0000, 0x0004, 0x7500 }, | |
204 | /* D/K A2-1 */ { AUD_A2, 0x1003, 0x0020, 0x0100, 0x2601, | |
205 | 0x5000, 0x0000, 0x0004, 0x7500 }, | |
206 | /* D/K A2-2 */ { AUD_A2, 0x1003, 0x0020, 0x0100, 0x2601, | |
207 | 0x5000, 0x0000, 0x0005, 0x7500 }, | |
208 | /* D/K A2-3 */ { AUD_A2, 0x1003, 0x0020, 0x0100, 0x2601, | |
209 | 0x5000, 0x0000, 0x0007, 0x7500 }, | |
210 | /* D/K NICAM */ { AUD_NICAM, 0x1003, 0x0120, 0x0100, 0x2603, | |
211 | 0x5000, 0x0000, 0x000B, 0x7500 }, | |
212 | /* L/L' Mono */ { AUD_MONO, 0x0003, 0x0200, 0x0100, 0x7C03, | |
213 | 0x5000, 0x2200, 0x0009, 0x7500 }, | |
214 | /* L/L' NICAM */{ AUD_NICAM_L, 0x0003, 0x0120, 0x0100, 0x7C03, | |
215 | 0x5000, 0x0000, 0x0009, 0x7500 }, | |
216 | }; | |
217 | ||
218 | #define MPX_NUM_MODES ARRAY_SIZE(mpx_audio_modes) | |
219 | ||
220 | static int mpx_setup(struct i2c_client *client) | |
221 | { | |
222 | struct wis_sony_tuner *t = i2c_get_clientdata(client); | |
223 | u16 source = 0; | |
224 | u8 buffer[3]; | |
225 | struct i2c_msg msg; | |
226 | ||
227 | /* reset MPX */ | |
228 | buffer[0] = 0x00; | |
229 | buffer[1] = 0x80; | |
230 | buffer[2] = 0x00; | |
231 | msg.addr = MPX_I2C_ADDR; | |
232 | msg.flags = 0; | |
233 | msg.len = 3; | |
234 | msg.buf = buffer; | |
235 | i2c_transfer(client->adapter, &msg, 1); | |
236 | buffer[1] = 0x00; | |
237 | i2c_transfer(client->adapter, &msg, 1); | |
238 | ||
239 | if (mpx_audio_modes[t->mpxmode].audio_mode != AUD_MONO) { | |
240 | switch (t->audmode) { | |
241 | case V4L2_TUNER_MODE_MONO: | |
242 | switch (mpx_audio_modes[t->mpxmode].audio_mode) { | |
243 | case AUD_A2: | |
244 | source = mpx_audio_modes[t->mpxmode].source; | |
245 | break; | |
246 | case AUD_NICAM: | |
247 | source = 0x0000; | |
248 | break; | |
249 | case AUD_NICAM_L: | |
250 | source = 0x0200; | |
251 | break; | |
252 | default: | |
253 | break; | |
254 | } | |
255 | break; | |
256 | case V4L2_TUNER_MODE_STEREO: | |
257 | source = mpx_audio_modes[t->mpxmode].source; | |
258 | break; | |
259 | case V4L2_TUNER_MODE_LANG1: | |
260 | source = 0x0300; | |
261 | break; | |
262 | case V4L2_TUNER_MODE_LANG2: | |
263 | source = 0x0400; | |
264 | break; | |
265 | } | |
266 | source |= mpx_audio_modes[t->mpxmode].source & 0x00ff; | |
267 | } else | |
268 | source = mpx_audio_modes[t->mpxmode].source; | |
269 | ||
270 | mpx_write(client, 0x10, 0x0030, mpx_audio_modes[t->mpxmode].modus); | |
271 | mpx_write(client, 0x12, 0x0008, source); | |
272 | mpx_write(client, 0x12, 0x0013, mpx_audio_modes[t->mpxmode].acb); | |
273 | mpx_write(client, 0x12, 0x000e, | |
274 | mpx_audio_modes[t->mpxmode].fm_prescale); | |
275 | mpx_write(client, 0x12, 0x0010, | |
276 | mpx_audio_modes[t->mpxmode].nicam_prescale); | |
277 | mpx_write(client, 0x12, 0x000d, | |
278 | mpx_audio_modes[t->mpxmode].scart_prescale); | |
279 | mpx_write(client, 0x10, 0x0020, mpx_audio_modes[t->mpxmode].system); | |
280 | mpx_write(client, 0x12, 0x0000, mpx_audio_modes[t->mpxmode].volume); | |
281 | if (mpx_audio_modes[t->mpxmode].audio_mode == AUD_A2) | |
282 | mpx_write(client, 0x10, 0x0022, | |
283 | t->audmode == V4L2_TUNER_MODE_MONO ? 0x07f0 : 0x0190); | |
284 | ||
285 | #ifdef MPX_DEBUG | |
286 | { | |
287 | u8 buf1[3], buf2[2]; | |
288 | struct i2c_msg msgs[2]; | |
289 | ||
290 | printk(KERN_DEBUG "wis-sony-tuner: MPX registers: %04x %04x " | |
291 | "%04x %04x %04x %04x %04x %04x\n", | |
292 | mpx_audio_modes[t->mpxmode].modus, | |
293 | source, | |
294 | mpx_audio_modes[t->mpxmode].acb, | |
295 | mpx_audio_modes[t->mpxmode].fm_prescale, | |
296 | mpx_audio_modes[t->mpxmode].nicam_prescale, | |
297 | mpx_audio_modes[t->mpxmode].scart_prescale, | |
298 | mpx_audio_modes[t->mpxmode].system, | |
299 | mpx_audio_modes[t->mpxmode].volume); | |
300 | buf1[0] = 0x11; | |
301 | buf1[1] = 0x00; | |
302 | buf1[2] = 0x7e; | |
303 | msgs[0].addr = MPX_I2C_ADDR; | |
304 | msgs[0].flags = 0; | |
305 | msgs[0].len = 3; | |
306 | msgs[0].buf = buf1; | |
307 | msgs[1].addr = MPX_I2C_ADDR; | |
308 | msgs[1].flags = I2C_M_RD; | |
309 | msgs[1].len = 2; | |
310 | msgs[1].buf = buf2; | |
311 | i2c_transfer(client->adapter, msgs, 2); | |
312 | printk(KERN_DEBUG "wis-sony-tuner: MPX system: %02x%02x\n", | |
313 | buf2[0], buf2[1]); | |
314 | buf1[0] = 0x11; | |
315 | buf1[1] = 0x02; | |
316 | buf1[2] = 0x00; | |
317 | i2c_transfer(client->adapter, msgs, 2); | |
318 | printk(KERN_DEBUG "wis-sony-tuner: MPX status: %02x%02x\n", | |
319 | buf2[0], buf2[1]); | |
320 | } | |
321 | #endif | |
322 | return 0; | |
323 | } | |
324 | ||
325 | /* | |
326 | * IF configuration values for the BTF-PG472Z: | |
327 | * | |
328 | * B/G: 0x94 0x70 0x49 | |
329 | * I: 0x14 0x70 0x4a | |
330 | * D/K: 0x14 0x70 0x4b | |
331 | * L: 0x04 0x70 0x4b | |
332 | * L': 0x44 0x70 0x53 | |
333 | * M: 0x50 0x30 0x4c | |
334 | */ | |
335 | ||
336 | static int set_if(struct i2c_client *client) | |
337 | { | |
338 | struct wis_sony_tuner *t = i2c_get_clientdata(client); | |
339 | u8 buffer[4]; | |
340 | struct i2c_msg msg; | |
341 | int default_mpx_mode = 0; | |
342 | ||
343 | /* configure IF */ | |
344 | buffer[0] = 0; | |
345 | if (t->std & V4L2_STD_PAL_BG) { | |
346 | buffer[1] = 0x94; | |
347 | buffer[2] = 0x70; | |
348 | buffer[3] = 0x49; | |
349 | default_mpx_mode = 1; | |
350 | } else if (t->std & V4L2_STD_PAL_I) { | |
351 | buffer[1] = 0x14; | |
352 | buffer[2] = 0x70; | |
353 | buffer[3] = 0x4a; | |
354 | default_mpx_mode = 4; | |
355 | } else if (t->std & V4L2_STD_PAL_DK) { | |
356 | buffer[1] = 0x14; | |
357 | buffer[2] = 0x70; | |
358 | buffer[3] = 0x4b; | |
359 | default_mpx_mode = 6; | |
360 | } else if (t->std & V4L2_STD_SECAM_L) { | |
361 | buffer[1] = 0x04; | |
362 | buffer[2] = 0x70; | |
363 | buffer[3] = 0x4b; | |
364 | default_mpx_mode = 11; | |
365 | } | |
366 | msg.addr = IF_I2C_ADDR; | |
367 | msg.flags = 0; | |
368 | msg.len = 4; | |
369 | msg.buf = buffer; | |
370 | i2c_transfer(client->adapter, &msg, 1); | |
371 | ||
372 | /* Select MPX mode if not forced by the user */ | |
315d7fa9 | 373 | if (force_mpx_mode >= 0 && force_mpx_mode < MPX_NUM_MODES) |
866b8695 GKH |
374 | t->mpxmode = force_mpx_mode; |
375 | else | |
376 | t->mpxmode = default_mpx_mode; | |
377 | printk(KERN_DEBUG "wis-sony-tuner: setting MPX to mode %d\n", | |
378 | t->mpxmode); | |
379 | mpx_setup(client); | |
380 | ||
381 | return 0; | |
382 | } | |
383 | ||
384 | static int tuner_command(struct i2c_client *client, unsigned int cmd, void *arg) | |
385 | { | |
386 | struct wis_sony_tuner *t = i2c_get_clientdata(client); | |
387 | ||
388 | switch (cmd) { | |
86a79d2e | 389 | #if 0 |
866b8695 GKH |
390 | #ifdef TUNER_SET_TYPE_ADDR |
391 | case TUNER_SET_TYPE_ADDR: | |
392 | { | |
393 | struct tuner_setup *tun_setup = arg; | |
394 | int *type = &tun_setup->type; | |
395 | #else | |
396 | case TUNER_SET_TYPE: | |
397 | { | |
398 | int *type = arg; | |
399 | #endif | |
400 | ||
401 | if (t->type >= 0) { | |
402 | if (t->type != *type) | |
403 | printk(KERN_ERR "wis-sony-tuner: type already " | |
404 | "set to %d, ignoring request for %d\n", | |
405 | t->type, *type); | |
406 | break; | |
407 | } | |
408 | t->type = *type; | |
409 | switch (t->type) { | |
410 | case TUNER_SONY_BTF_PG472Z: | |
411 | switch (force_band_str[0]) { | |
412 | case 'b': | |
413 | case 'B': | |
414 | case 'g': | |
415 | case 'G': | |
416 | printk(KERN_INFO "wis-sony-tuner: forcing " | |
417 | "tuner to PAL-B/G bands\n"); | |
418 | force_band = V4L2_STD_PAL_BG; | |
419 | break; | |
420 | case 'i': | |
421 | case 'I': | |
422 | printk(KERN_INFO "wis-sony-tuner: forcing " | |
423 | "tuner to PAL-I band\n"); | |
424 | force_band = V4L2_STD_PAL_I; | |
425 | break; | |
426 | case 'd': | |
427 | case 'D': | |
428 | case 'k': | |
429 | case 'K': | |
430 | printk(KERN_INFO "wis-sony-tuner: forcing " | |
431 | "tuner to PAL-D/K bands\n"); | |
432 | force_band = V4L2_STD_PAL_I; | |
433 | break; | |
434 | case 'l': | |
435 | case 'L': | |
436 | printk(KERN_INFO "wis-sony-tuner: forcing " | |
437 | "tuner to SECAM-L band\n"); | |
438 | force_band = V4L2_STD_SECAM_L; | |
439 | break; | |
440 | default: | |
441 | force_band = 0; | |
442 | break; | |
443 | } | |
444 | if (force_band) | |
445 | t->std = force_band; | |
446 | else | |
447 | t->std = V4L2_STD_PAL_BG; | |
448 | set_if(client); | |
449 | break; | |
450 | case TUNER_SONY_BTF_PK467Z: | |
451 | t->std = V4L2_STD_NTSC_M_JP; | |
452 | break; | |
453 | case TUNER_SONY_BTF_PB463Z: | |
454 | t->std = V4L2_STD_NTSC_M; | |
455 | break; | |
456 | default: | |
457 | printk(KERN_ERR "wis-sony-tuner: tuner type %d is not " | |
458 | "supported by this module\n", *type); | |
459 | break; | |
460 | } | |
461 | if (type >= 0) | |
462 | printk(KERN_INFO | |
463 | "wis-sony-tuner: type set to %d (%s)\n", | |
464 | t->type, sony_tuners[t->type - 200].name); | |
465 | break; | |
466 | } | |
86a79d2e | 467 | #endif |
866b8695 GKH |
468 | case VIDIOC_G_FREQUENCY: |
469 | { | |
470 | struct v4l2_frequency *f = arg; | |
471 | ||
472 | f->frequency = t->freq; | |
473 | break; | |
474 | } | |
475 | case VIDIOC_S_FREQUENCY: | |
476 | { | |
477 | struct v4l2_frequency *f = arg; | |
478 | ||
479 | t->freq = f->frequency; | |
480 | set_freq(client, t->freq); | |
481 | break; | |
482 | } | |
483 | case VIDIOC_ENUMSTD: | |
484 | { | |
485 | struct v4l2_standard *std = arg; | |
486 | ||
487 | switch (t->type) { | |
488 | case TUNER_SONY_BTF_PG472Z: | |
489 | switch (std->index) { | |
490 | case 0: | |
491 | v4l2_video_std_construct(std, | |
492 | V4L2_STD_PAL_BG, "PAL-B/G"); | |
493 | break; | |
494 | case 1: | |
495 | v4l2_video_std_construct(std, | |
496 | V4L2_STD_PAL_I, "PAL-I"); | |
497 | break; | |
498 | case 2: | |
499 | v4l2_video_std_construct(std, | |
500 | V4L2_STD_PAL_DK, "PAL-D/K"); | |
501 | break; | |
502 | case 3: | |
503 | v4l2_video_std_construct(std, | |
504 | V4L2_STD_SECAM_L, "SECAM-L"); | |
505 | break; | |
506 | default: | |
507 | std->id = 0; /* hack to indicate EINVAL */ | |
508 | break; | |
509 | } | |
510 | break; | |
511 | case TUNER_SONY_BTF_PK467Z: | |
512 | if (std->index != 0) { | |
513 | std->id = 0; /* hack to indicate EINVAL */ | |
514 | break; | |
515 | } | |
516 | v4l2_video_std_construct(std, | |
517 | V4L2_STD_NTSC_M_JP, "NTSC-J"); | |
518 | break; | |
519 | case TUNER_SONY_BTF_PB463Z: | |
520 | if (std->index != 0) { | |
521 | std->id = 0; /* hack to indicate EINVAL */ | |
522 | break; | |
523 | } | |
524 | v4l2_video_std_construct(std, V4L2_STD_NTSC_M, "NTSC"); | |
525 | break; | |
526 | } | |
527 | break; | |
528 | } | |
529 | case VIDIOC_G_STD: | |
530 | { | |
531 | v4l2_std_id *std = arg; | |
532 | ||
533 | *std = t->std; | |
534 | break; | |
535 | } | |
536 | case VIDIOC_S_STD: | |
537 | { | |
538 | v4l2_std_id *std = arg; | |
539 | v4l2_std_id old = t->std; | |
540 | ||
541 | switch (t->type) { | |
542 | case TUNER_SONY_BTF_PG472Z: | |
543 | if (force_band && (*std & force_band) != *std && | |
544 | *std != V4L2_STD_PAL && | |
545 | *std != V4L2_STD_SECAM) { | |
546 | printk(KERN_DEBUG "wis-sony-tuner: ignoring " | |
547 | "requested TV standard in " | |
548 | "favor of force_band value\n"); | |
549 | t->std = force_band; | |
550 | } else if (*std & V4L2_STD_PAL_BG) { /* default */ | |
551 | t->std = V4L2_STD_PAL_BG; | |
552 | } else if (*std & V4L2_STD_PAL_I) { | |
553 | t->std = V4L2_STD_PAL_I; | |
554 | } else if (*std & V4L2_STD_PAL_DK) { | |
555 | t->std = V4L2_STD_PAL_DK; | |
556 | } else if (*std & V4L2_STD_SECAM_L) { | |
557 | t->std = V4L2_STD_SECAM_L; | |
558 | } else { | |
559 | printk(KERN_ERR "wis-sony-tuner: TV standard " | |
560 | "not supported\n"); | |
561 | *std = 0; /* hack to indicate EINVAL */ | |
562 | break; | |
563 | } | |
564 | if (old != t->std) | |
565 | set_if(client); | |
566 | break; | |
567 | case TUNER_SONY_BTF_PK467Z: | |
568 | if (!(*std & V4L2_STD_NTSC_M_JP)) { | |
569 | printk(KERN_ERR "wis-sony-tuner: TV standard " | |
570 | "not supported\n"); | |
571 | *std = 0; /* hack to indicate EINVAL */ | |
572 | } | |
573 | break; | |
574 | case TUNER_SONY_BTF_PB463Z: | |
575 | if (!(*std & V4L2_STD_NTSC_M)) { | |
576 | printk(KERN_ERR "wis-sony-tuner: TV standard " | |
577 | "not supported\n"); | |
578 | *std = 0; /* hack to indicate EINVAL */ | |
579 | } | |
580 | break; | |
581 | } | |
582 | break; | |
583 | } | |
584 | case VIDIOC_QUERYSTD: | |
585 | { | |
586 | v4l2_std_id *std = arg; | |
587 | ||
588 | switch (t->type) { | |
589 | case TUNER_SONY_BTF_PG472Z: | |
590 | if (force_band) | |
591 | *std = force_band; | |
592 | else | |
593 | *std = V4L2_STD_PAL_BG | V4L2_STD_PAL_I | | |
594 | V4L2_STD_PAL_DK | V4L2_STD_SECAM_L; | |
595 | break; | |
596 | case TUNER_SONY_BTF_PK467Z: | |
597 | *std = V4L2_STD_NTSC_M_JP; | |
598 | break; | |
599 | case TUNER_SONY_BTF_PB463Z: | |
600 | *std = V4L2_STD_NTSC_M; | |
601 | break; | |
602 | } | |
603 | break; | |
604 | } | |
605 | case VIDIOC_G_TUNER: | |
606 | { | |
607 | struct v4l2_tuner *tun = arg; | |
608 | ||
d73f822c | 609 | memset(tun, 0, sizeof(*tun)); |
866b8695 GKH |
610 | strcpy(tun->name, "Television"); |
611 | tun->type = V4L2_TUNER_ANALOG_TV; | |
612 | tun->rangelow = 0UL; /* does anything use these? */ | |
613 | tun->rangehigh = 0xffffffffUL; | |
614 | switch (t->type) { | |
615 | case TUNER_SONY_BTF_PG472Z: | |
616 | tun->capability = V4L2_TUNER_CAP_NORM | | |
617 | V4L2_TUNER_CAP_STEREO | V4L2_TUNER_CAP_LANG1 | | |
618 | V4L2_TUNER_CAP_LANG2; | |
619 | tun->rxsubchans = V4L2_TUNER_SUB_MONO | | |
620 | V4L2_TUNER_SUB_STEREO | V4L2_TUNER_SUB_LANG1 | | |
621 | V4L2_TUNER_SUB_LANG2; | |
622 | break; | |
623 | case TUNER_SONY_BTF_PK467Z: | |
624 | case TUNER_SONY_BTF_PB463Z: | |
625 | tun->capability = V4L2_TUNER_CAP_STEREO; | |
626 | tun->rxsubchans = V4L2_TUNER_SUB_MONO | | |
627 | V4L2_TUNER_SUB_STEREO; | |
628 | break; | |
629 | } | |
630 | tun->audmode = t->audmode; | |
631 | return 0; | |
632 | } | |
633 | case VIDIOC_S_TUNER: | |
634 | { | |
635 | struct v4l2_tuner *tun = arg; | |
636 | ||
637 | switch (t->type) { | |
638 | case TUNER_SONY_BTF_PG472Z: | |
639 | if (tun->audmode != t->audmode) { | |
640 | t->audmode = tun->audmode; | |
641 | mpx_setup(client); | |
642 | } | |
643 | break; | |
644 | case TUNER_SONY_BTF_PK467Z: | |
645 | case TUNER_SONY_BTF_PB463Z: | |
646 | break; | |
647 | } | |
648 | return 0; | |
649 | } | |
650 | default: | |
651 | break; | |
652 | } | |
653 | return 0; | |
654 | } | |
655 | ||
7400516a JD |
656 | static int wis_sony_tuner_probe(struct i2c_client *client, |
657 | const struct i2c_device_id *id) | |
866b8695 | 658 | { |
7400516a | 659 | struct i2c_adapter *adapter = client->adapter; |
866b8695 GKH |
660 | struct wis_sony_tuner *t; |
661 | ||
662 | if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_I2C_BLOCK)) | |
7400516a | 663 | return -ENODEV; |
866b8695 GKH |
664 | |
665 | t = kmalloc(sizeof(struct wis_sony_tuner), GFP_KERNEL); | |
7400516a | 666 | if (t == NULL) |
866b8695 | 667 | return -ENOMEM; |
7400516a | 668 | |
866b8695 GKH |
669 | t->type = -1; |
670 | t->freq = 0; | |
671 | t->mpxmode = 0; | |
672 | t->audmode = V4L2_TUNER_MODE_STEREO; | |
673 | i2c_set_clientdata(client, t); | |
674 | ||
675 | printk(KERN_DEBUG | |
676 | "wis-sony-tuner: initializing tuner at address %d on %s\n", | |
7400516a | 677 | client->addr, adapter->name); |
866b8695 GKH |
678 | |
679 | return 0; | |
680 | } | |
681 | ||
7400516a | 682 | static int wis_sony_tuner_remove(struct i2c_client *client) |
866b8695 GKH |
683 | { |
684 | struct wis_sony_tuner *t = i2c_get_clientdata(client); | |
866b8695 | 685 | |
7400516a | 686 | i2c_set_clientdata(client, NULL); |
866b8695 | 687 | kfree(t); |
866b8695 GKH |
688 | return 0; |
689 | } | |
690 | ||
7400516a JD |
691 | static struct i2c_device_id wis_sony_tuner_id[] = { |
692 | { "wis_sony_tuner", 0 }, | |
693 | { } | |
694 | }; | |
695 | ||
866b8695 GKH |
696 | static struct i2c_driver wis_sony_tuner_driver = { |
697 | .driver = { | |
698 | .name = "WIS Sony TV Tuner I2C driver", | |
699 | }, | |
7400516a JD |
700 | .probe = wis_sony_tuner_probe, |
701 | .remove = wis_sony_tuner_remove, | |
866b8695 | 702 | .command = tuner_command, |
7400516a | 703 | .id_table = wis_sony_tuner_id, |
866b8695 GKH |
704 | }; |
705 | ||
706 | static int __init wis_sony_tuner_init(void) | |
707 | { | |
7400516a | 708 | return i2c_add_driver(&wis_sony_tuner_driver); |
866b8695 GKH |
709 | } |
710 | ||
711 | static void __exit wis_sony_tuner_cleanup(void) | |
712 | { | |
866b8695 GKH |
713 | i2c_del_driver(&wis_sony_tuner_driver); |
714 | } | |
715 | ||
716 | module_init(wis_sony_tuner_init); | |
717 | module_exit(wis_sony_tuner_cleanup); | |
718 | ||
719 | MODULE_LICENSE("GPL v2"); |