Commit | Line | Data |
---|---|---|
1da177e4 | 1 | /* |
1da177e4 LT |
2 | * |
3 | * i2c tv tuner chip device driver | |
4 | * controls all those simple 4-control-bytes style tuners. | |
5 | */ | |
6 | #include <linux/delay.h> | |
7 | #include <linux/i2c.h> | |
8 | #include <linux/videodev.h> | |
9 | #include <media/tuner.h> | |
10 | ||
5c07db0c MCC |
11 | static int offset = 0; |
12 | module_param(offset, int, 0666); | |
13 | MODULE_PARM_DESC(offset,"Allows to specify an offset for tuner"); | |
14 | ||
1da177e4 LT |
15 | /* ---------------------------------------------------------------------- */ |
16 | ||
17 | /* tv standard selection for Temic 4046 FM5 | |
18 | this value takes the low bits of control byte 2 | |
19 | from datasheet Rev.01, Feb.00 | |
20 | standard BG I L L2 D | |
21 | picture IF 38.9 38.9 38.9 33.95 38.9 | |
22 | sound 1 33.4 32.9 32.4 40.45 32.4 | |
23 | sound 2 33.16 | |
24 | NICAM 33.05 32.348 33.05 33.05 | |
25 | */ | |
26 | #define TEMIC_SET_PAL_I 0x05 | |
27 | #define TEMIC_SET_PAL_DK 0x09 | |
28 | #define TEMIC_SET_PAL_L 0x0a // SECAM ? | |
29 | #define TEMIC_SET_PAL_L2 0x0b // change IF ! | |
30 | #define TEMIC_SET_PAL_BG 0x0c | |
31 | ||
32 | /* tv tuner system standard selection for Philips FQ1216ME | |
33 | this value takes the low bits of control byte 2 | |
34 | from datasheet "1999 Nov 16" (supersedes "1999 Mar 23") | |
35 | standard BG DK I L L` | |
36 | picture carrier 38.90 38.90 38.90 38.90 33.95 | |
37 | colour 34.47 34.47 34.47 34.47 38.38 | |
38 | sound 1 33.40 32.40 32.90 32.40 40.45 | |
39 | sound 2 33.16 - - - - | |
40 | NICAM 33.05 33.05 32.35 33.05 39.80 | |
41 | */ | |
42 | #define PHILIPS_SET_PAL_I 0x01 /* Bit 2 always zero !*/ | |
43 | #define PHILIPS_SET_PAL_BGDK 0x09 | |
44 | #define PHILIPS_SET_PAL_L2 0x0a | |
45 | #define PHILIPS_SET_PAL_L 0x0b | |
46 | ||
47 | /* system switching for Philips FI1216MF MK2 | |
48 | from datasheet "1996 Jul 09", | |
49 | standard BG L L' | |
50 | picture carrier 38.90 38.90 33.95 | |
51 | colour 34.47 34.37 38.38 | |
52 | sound 1 33.40 32.40 40.45 | |
53 | sound 2 33.16 - - | |
54 | NICAM 33.05 33.05 39.80 | |
55 | */ | |
56 | #define PHILIPS_MF_SET_BG 0x01 /* Bit 2 must be zero, Bit 3 is system output */ | |
57 | #define PHILIPS_MF_SET_PAL_L 0x03 // France | |
58 | #define PHILIPS_MF_SET_PAL_L2 0x02 // L' | |
59 | ||
f7ce3cc6 MCC |
60 | /* Control byte */ |
61 | ||
62 | #define TUNER_RATIO_MASK 0x06 /* Bit cb1:cb2 */ | |
63 | #define TUNER_RATIO_SELECT_50 0x00 | |
64 | #define TUNER_RATIO_SELECT_32 0x02 | |
65 | #define TUNER_RATIO_SELECT_166 0x04 | |
66 | #define TUNER_RATIO_SELECT_62 0x06 | |
67 | ||
68 | #define TUNER_CHARGE_PUMP 0x40 /* Bit cb6 */ | |
69 | ||
70 | /* Status byte */ | |
71 | ||
72 | #define TUNER_POR 0x80 | |
73 | #define TUNER_FL 0x40 | |
74 | #define TUNER_MODE 0x38 | |
75 | #define TUNER_AFC 0x07 | |
76 | #define TUNER_SIGNAL 0x07 | |
77 | #define TUNER_STEREO 0x10 | |
78 | ||
79 | #define TUNER_PLL_LOCKED 0x40 | |
80 | #define TUNER_STEREO_MK3 0x04 | |
1da177e4 | 81 | |
7b0ac9cd MK |
82 | #define TUNER_PARAM_ANALOG 0 /* to be removed */ |
83 | /* FIXME: | |
84 | * Right now, all tuners are using the first tuner_params[] array element | |
85 | * for analog mode. In the future, we will be merging similar tuner | |
86 | * definitions together, such that each tuner definition will have a | |
87 | * tuner_params struct for each available video standard. At that point, | |
88 | * TUNER_PARAM_ANALOG will be removed, and the tuner_params[] array | |
89 | * element will be chosen based on the video standard in use. | |
90 | * | |
1da177e4 | 91 | */ |
1da177e4 LT |
92 | |
93 | /* ---------------------------------------------------------------------- */ | |
94 | ||
95 | static int tuner_getstatus(struct i2c_client *c) | |
96 | { | |
97 | unsigned char byte; | |
98 | ||
99 | if (1 != i2c_master_recv(c,&byte,1)) | |
100 | return 0; | |
56fc08ca | 101 | |
1da177e4 LT |
102 | return byte; |
103 | } | |
104 | ||
1da177e4 LT |
105 | static int tuner_signal(struct i2c_client *c) |
106 | { | |
56fc08ca | 107 | return (tuner_getstatus(c) & TUNER_SIGNAL) << 13; |
1da177e4 LT |
108 | } |
109 | ||
110 | static int tuner_stereo(struct i2c_client *c) | |
111 | { | |
56fc08ca MCC |
112 | int stereo, status; |
113 | struct tuner *t = i2c_get_clientdata(c); | |
114 | ||
115 | status = tuner_getstatus (c); | |
116 | ||
117 | switch (t->type) { | |
4ac97914 | 118 | case TUNER_PHILIPS_FM1216ME_MK3: |
56fc08ca MCC |
119 | case TUNER_PHILIPS_FM1236_MK3: |
120 | case TUNER_PHILIPS_FM1256_IH3: | |
121 | stereo = ((status & TUNER_SIGNAL) == TUNER_STEREO_MK3); | |
122 | break; | |
123 | default: | |
124 | stereo = status & TUNER_STEREO; | |
125 | } | |
126 | ||
127 | return stereo; | |
1da177e4 LT |
128 | } |
129 | ||
1da177e4 LT |
130 | |
131 | /* ---------------------------------------------------------------------- */ | |
132 | ||
133 | static void default_set_tv_freq(struct i2c_client *c, unsigned int freq) | |
134 | { | |
135 | struct tuner *t = i2c_get_clientdata(c); | |
3fc46d35 | 136 | u8 config, cb, tuneraddr; |
1da177e4 LT |
137 | u16 div; |
138 | struct tunertype *tun; | |
27487d44 | 139 | u8 buffer[4]; |
7b0ac9cd | 140 | int rc, IFPCoff, i, j; |
1da177e4 LT |
141 | |
142 | tun = &tuners[t->type]; | |
7b0ac9cd MK |
143 | j = TUNER_PARAM_ANALOG; |
144 | ||
145 | for (i = 0; i < tun->params[j].count; i++) { | |
146 | if (freq > tun->params[j].ranges[i].limit) | |
90200d2b MK |
147 | continue; |
148 | break; | |
1da177e4 | 149 | } |
27487d44 HV |
150 | if (i == tun->params[j].count) { |
151 | tuner_dbg("TV frequency out of range (%d > %d)", | |
152 | freq, tun->params[j].ranges[i - 1].limit); | |
153 | freq = tun->params[j].ranges[--i].limit; | |
154 | } | |
3fc46d35 | 155 | config = tun->params[j].ranges[i].config; |
ab66b22f | 156 | cb = tun->params[j].ranges[i].cb; |
90200d2b MK |
157 | /* i == 0 -> VHF_LO */ |
158 | /* i == 1 -> VHF_HI */ | |
159 | /* i == 2 -> UHF */ | |
160 | tuner_dbg("tv: range %d\n",i); | |
1da177e4 LT |
161 | |
162 | /* tv norm specific stuff for multi-norm tuners */ | |
163 | switch (t->type) { | |
164 | case TUNER_PHILIPS_SECAM: // FI1216MF | |
165 | /* 0x01 -> ??? no change ??? */ | |
166 | /* 0x02 -> PAL BDGHI / SECAM L */ | |
167 | /* 0x04 -> ??? PAL others / SECAM others ??? */ | |
ab66b22f | 168 | cb &= ~0x02; |
1da177e4 | 169 | if (t->std & V4L2_STD_SECAM) |
ab66b22f | 170 | cb |= 0x02; |
1da177e4 LT |
171 | break; |
172 | ||
173 | case TUNER_TEMIC_4046FM5: | |
ab66b22f | 174 | cb &= ~0x0f; |
1da177e4 LT |
175 | |
176 | if (t->std & V4L2_STD_PAL_BG) { | |
ab66b22f | 177 | cb |= TEMIC_SET_PAL_BG; |
1da177e4 LT |
178 | |
179 | } else if (t->std & V4L2_STD_PAL_I) { | |
ab66b22f | 180 | cb |= TEMIC_SET_PAL_I; |
1da177e4 LT |
181 | |
182 | } else if (t->std & V4L2_STD_PAL_DK) { | |
ab66b22f | 183 | cb |= TEMIC_SET_PAL_DK; |
1da177e4 LT |
184 | |
185 | } else if (t->std & V4L2_STD_SECAM_L) { | |
ab66b22f | 186 | cb |= TEMIC_SET_PAL_L; |
1da177e4 LT |
187 | |
188 | } | |
189 | break; | |
190 | ||
191 | case TUNER_PHILIPS_FQ1216ME: | |
ab66b22f | 192 | cb &= ~0x0f; |
1da177e4 LT |
193 | |
194 | if (t->std & (V4L2_STD_PAL_BG|V4L2_STD_PAL_DK)) { | |
ab66b22f | 195 | cb |= PHILIPS_SET_PAL_BGDK; |
1da177e4 LT |
196 | |
197 | } else if (t->std & V4L2_STD_PAL_I) { | |
ab66b22f | 198 | cb |= PHILIPS_SET_PAL_I; |
1da177e4 LT |
199 | |
200 | } else if (t->std & V4L2_STD_SECAM_L) { | |
ab66b22f | 201 | cb |= PHILIPS_SET_PAL_L; |
1da177e4 LT |
202 | |
203 | } | |
204 | break; | |
205 | ||
206 | case TUNER_PHILIPS_ATSC: | |
207 | /* 0x00 -> ATSC antenna input 1 */ | |
208 | /* 0x01 -> ATSC antenna input 2 */ | |
209 | /* 0x02 -> NTSC antenna input 1 */ | |
210 | /* 0x03 -> NTSC antenna input 2 */ | |
ab66b22f | 211 | cb &= ~0x03; |
1da177e4 | 212 | if (!(t->std & V4L2_STD_ATSC)) |
ab66b22f | 213 | cb |= 2; |
1da177e4 LT |
214 | /* FIXME: input */ |
215 | break; | |
216 | ||
217 | case TUNER_MICROTUNE_4042FI5: | |
218 | /* Set the charge pump for fast tuning */ | |
3fc46d35 | 219 | config |= TUNER_CHARGE_PUMP; |
1da177e4 | 220 | break; |
e976f937 KL |
221 | |
222 | case TUNER_PHILIPS_TUV1236D: | |
223 | /* 0x40 -> ATSC antenna input 1 */ | |
224 | /* 0x48 -> ATSC antenna input 2 */ | |
225 | /* 0x00 -> NTSC antenna input 1 */ | |
226 | /* 0x08 -> NTSC antenna input 2 */ | |
fde6d31e KL |
227 | buffer[0] = 0x14; |
228 | buffer[1] = 0x00; | |
229 | buffer[2] = 0x17; | |
230 | buffer[3] = 0x00; | |
ab66b22f | 231 | cb &= ~0x40; |
fde6d31e | 232 | if (t->std & V4L2_STD_ATSC) { |
ab66b22f | 233 | cb |= 0x40; |
fde6d31e KL |
234 | buffer[1] = 0x04; |
235 | } | |
236 | /* set to the correct mode (analog or digital) */ | |
fde6d31e KL |
237 | tuneraddr = c->addr; |
238 | c->addr = 0x0a; | |
239 | if (2 != (rc = i2c_master_send(c,&buffer[0],2))) | |
240 | tuner_warn("i2c i/o error: rc == %d (should be 2)\n",rc); | |
241 | if (2 != (rc = i2c_master_send(c,&buffer[2],2))) | |
242 | tuner_warn("i2c i/o error: rc == %d (should be 2)\n",rc); | |
243 | c->addr = tuneraddr; | |
e976f937 KL |
244 | /* FIXME: input */ |
245 | break; | |
1da177e4 LT |
246 | } |
247 | ||
1faf11a3 MCC |
248 | /* IFPCoff = Video Intermediate Frequency - Vif: |
249 | 940 =16*58.75 NTSC/J (Japan) | |
250 | 732 =16*45.75 M/N STD | |
251 | 704 =16*44 ATSC (at DVB code) | |
252 | 632 =16*39.50 I U.K. | |
253 | 622.4=16*38.90 B/G D/K I, L STD | |
254 | 592 =16*37.00 D China | |
255 | 590 =16.36.875 B Australia | |
256 | 543.2=16*33.95 L' STD | |
257 | 171.2=16*10.70 FM Radio (at set_radio_freq) | |
258 | */ | |
259 | ||
a1789d3a | 260 | if (t->std == V4L2_STD_NTSC_M_JP) { |
1faf11a3 | 261 | IFPCoff = 940; |
a1789d3a HV |
262 | } else if ((t->std & V4L2_STD_MN) && |
263 | !(t->std & ~V4L2_STD_MN)) { | |
1faf11a3 | 264 | IFPCoff = 732; |
a1789d3a | 265 | } else if (t->std == V4L2_STD_SECAM_LC) { |
1faf11a3 MCC |
266 | IFPCoff = 543; |
267 | } else { | |
268 | IFPCoff = 623; | |
269 | } | |
270 | ||
5c07db0c | 271 | div=freq + IFPCoff + offset; |
f5b90a27 MCC |
272 | |
273 | tuner_dbg("Freq= %d.%02d MHz, V_IF=%d.%02d MHz, Offset=%d.%02d MHz, div=%0d\n", | |
274 | freq / 16, freq % 16 * 100 / 16, | |
275 | IFPCoff / 16, IFPCoff % 16 * 100 / 16, | |
276 | offset / 16, offset % 16 * 100 / 16, | |
277 | div); | |
278 | ||
27487d44 | 279 | if (tuners[t->type].params->cb_first_if_lower_freq && div < t->last_div) { |
3fc46d35 | 280 | buffer[0] = config; |
ab66b22f | 281 | buffer[1] = cb; |
1da177e4 LT |
282 | buffer[2] = (div>>8) & 0x7f; |
283 | buffer[3] = div & 0xff; | |
284 | } else { | |
285 | buffer[0] = (div>>8) & 0x7f; | |
286 | buffer[1] = div & 0xff; | |
3fc46d35 | 287 | buffer[2] = config; |
ab66b22f | 288 | buffer[3] = cb; |
1da177e4 | 289 | } |
27487d44 | 290 | t->last_div = div; |
1da177e4 LT |
291 | tuner_dbg("tv 0x%02x 0x%02x 0x%02x 0x%02x\n", |
292 | buffer[0],buffer[1],buffer[2],buffer[3]); | |
293 | ||
4ac97914 | 294 | if (4 != (rc = i2c_master_send(c,buffer,4))) |
1da177e4 LT |
295 | tuner_warn("i2c i/o error: rc == %d (should be 4)\n",rc); |
296 | ||
297 | if (t->type == TUNER_MICROTUNE_4042FI5) { | |
298 | // FIXME - this may also work for other tuners | |
299 | unsigned long timeout = jiffies + msecs_to_jiffies(1); | |
300 | u8 status_byte = 0; | |
301 | ||
302 | /* Wait until the PLL locks */ | |
303 | for (;;) { | |
304 | if (time_after(jiffies,timeout)) | |
305 | return; | |
306 | if (1 != (rc = i2c_master_recv(c,&status_byte,1))) { | |
307 | tuner_warn("i2c i/o read error: rc == %d (should be 1)\n",rc); | |
308 | break; | |
309 | } | |
f7ce3cc6 | 310 | if (status_byte & TUNER_PLL_LOCKED) |
1da177e4 LT |
311 | break; |
312 | udelay(10); | |
313 | } | |
314 | ||
315 | /* Set the charge pump for optimized phase noise figure */ | |
3fc46d35 | 316 | config &= ~TUNER_CHARGE_PUMP; |
1da177e4 LT |
317 | buffer[0] = (div>>8) & 0x7f; |
318 | buffer[1] = div & 0xff; | |
3fc46d35 | 319 | buffer[2] = config; |
ab66b22f | 320 | buffer[3] = cb; |
1da177e4 LT |
321 | tuner_dbg("tv 0x%02x 0x%02x 0x%02x 0x%02x\n", |
322 | buffer[0],buffer[1],buffer[2],buffer[3]); | |
323 | ||
324 | if (4 != (rc = i2c_master_send(c,buffer,4))) | |
325 | tuner_warn("i2c i/o error: rc == %d (should be 4)\n",rc); | |
326 | } | |
327 | } | |
328 | ||
329 | static void default_set_radio_freq(struct i2c_client *c, unsigned int freq) | |
330 | { | |
331 | struct tunertype *tun; | |
332 | struct tuner *t = i2c_get_clientdata(c); | |
27487d44 HV |
333 | u8 buffer[4]; |
334 | u16 div; | |
7b0ac9cd | 335 | int rc, j; |
1da177e4 | 336 | |
f7ce3cc6 | 337 | tun = &tuners[t->type]; |
7b0ac9cd MK |
338 | j = TUNER_PARAM_ANALOG; |
339 | ||
f7ce3cc6 | 340 | div = (20 * freq / 16000) + (int)(20*10.7); /* IF 10.7 MHz */ |
3fc46d35 | 341 | buffer[2] = (tun->params[j].ranges[0].config & ~TUNER_RATIO_MASK) | TUNER_RATIO_SELECT_50; /* 50 kHz step */ |
1da177e4 LT |
342 | |
343 | switch (t->type) { | |
56fc08ca | 344 | case TUNER_TENA_9533_DI: |
391cd727 | 345 | case TUNER_YMEC_TVF_5533MF: |
f7ce3cc6 MCC |
346 | tuner_dbg ("This tuner doesn't have FM. Most cards has a TEA5767 for FM\n"); |
347 | return; | |
1da177e4 LT |
348 | case TUNER_PHILIPS_FM1216ME_MK3: |
349 | case TUNER_PHILIPS_FM1236_MK3: | |
586b0cab | 350 | case TUNER_PHILIPS_FMD1216ME_MK3: |
1da177e4 LT |
351 | buffer[3] = 0x19; |
352 | break; | |
353 | case TUNER_PHILIPS_FM1256_IH3: | |
f7ce3cc6 | 354 | div = (20 * freq) / 16000 + (int)(33.3 * 20); /* IF 33.3 MHz */ |
1da177e4 LT |
355 | buffer[3] = 0x19; |
356 | break; | |
357 | case TUNER_LG_PAL_FM: | |
358 | buffer[3] = 0xa5; | |
359 | break; | |
33ac6b52 MCC |
360 | case TUNER_MICROTUNE_4049FM5: |
361 | div = (20 * freq) / 16000 + (int)(33.3 * 20); /* IF 33.3 MHz */ | |
362 | buffer[3] = 0xa4; | |
363 | break; | |
1da177e4 LT |
364 | default: |
365 | buffer[3] = 0xa4; | |
366 | break; | |
367 | } | |
4ac97914 MCC |
368 | buffer[0] = (div>>8) & 0x7f; |
369 | buffer[1] = div & 0xff; | |
27487d44 HV |
370 | if (tuners[t->type].params->cb_first_if_lower_freq && div < t->last_div) { |
371 | buffer[0] = buffer[2]; | |
372 | buffer[1] = buffer[3]; | |
373 | buffer[2] = (div>>8) & 0x7f; | |
374 | buffer[3] = div & 0xff; | |
375 | } else { | |
376 | buffer[0] = (div>>8) & 0x7f; | |
377 | buffer[1] = div & 0xff; | |
378 | } | |
1da177e4 LT |
379 | |
380 | tuner_dbg("radio 0x%02x 0x%02x 0x%02x 0x%02x\n", | |
381 | buffer[0],buffer[1],buffer[2],buffer[3]); | |
27487d44 | 382 | t->last_div = div; |
1da177e4 | 383 | |
4ac97914 | 384 | if (4 != (rc = i2c_master_send(c,buffer,4))) |
1da177e4 LT |
385 | tuner_warn("i2c i/o error: rc == %d (should be 4)\n",rc); |
386 | } | |
387 | ||
388 | int default_tuner_init(struct i2c_client *c) | |
389 | { | |
390 | struct tuner *t = i2c_get_clientdata(c); | |
391 | ||
392 | tuner_info("type set to %d (%s)\n", | |
393 | t->type, tuners[t->type].name); | |
394 | strlcpy(c->name, tuners[t->type].name, sizeof(c->name)); | |
395 | ||
27487d44 HV |
396 | t->set_tv_freq = default_set_tv_freq; |
397 | t->set_radio_freq = default_set_radio_freq; | |
1da177e4 | 398 | t->has_signal = tuner_signal; |
27487d44 | 399 | t->is_stereo = tuner_stereo; |
793cf9e6 | 400 | t->standby = NULL; |
586b0cab | 401 | |
1da177e4 LT |
402 | return 0; |
403 | } | |
404 | ||
405 | /* | |
406 | * Overrides for Emacs so that we follow Linus's tabbing style. | |
407 | * --------------------------------------------------------------------------- | |
408 | * Local variables: | |
409 | * c-basic-offset: 8 | |
410 | * End: | |
411 | */ |