diff options
Diffstat (limited to 'drivers/media/tuners/tea5767.c')
-rw-r--r-- | drivers/media/tuners/tea5767.c | 475 |
1 files changed, 475 insertions, 0 deletions
diff --git a/drivers/media/tuners/tea5767.c b/drivers/media/tuners/tea5767.c new file mode 100644 index 000000000000..36e85d81acb2 --- /dev/null +++ b/drivers/media/tuners/tea5767.c | |||
@@ -0,0 +1,475 @@ | |||
1 | /* | ||
2 | * For Philips TEA5767 FM Chip used on some TV Cards like Prolink Pixelview | ||
3 | * I2C address is allways 0xC0. | ||
4 | * | ||
5 | * | ||
6 | * Copyright (c) 2005 Mauro Carvalho Chehab (mchehab@infradead.org) | ||
7 | * This code is placed under the terms of the GNU General Public License | ||
8 | * | ||
9 | * tea5767 autodetection thanks to Torsten Seeboth and Atsushi Nakagawa | ||
10 | * from their contributions on DScaler. | ||
11 | */ | ||
12 | |||
13 | #include <linux/i2c.h> | ||
14 | #include <linux/slab.h> | ||
15 | #include <linux/delay.h> | ||
16 | #include <linux/videodev2.h> | ||
17 | #include "tuner-i2c.h" | ||
18 | #include "tea5767.h" | ||
19 | |||
20 | static int debug; | ||
21 | module_param(debug, int, 0644); | ||
22 | MODULE_PARM_DESC(debug, "enable verbose debug messages"); | ||
23 | |||
24 | /*****************************************************************************/ | ||
25 | |||
26 | struct tea5767_priv { | ||
27 | struct tuner_i2c_props i2c_props; | ||
28 | u32 frequency; | ||
29 | struct tea5767_ctrl ctrl; | ||
30 | }; | ||
31 | |||
32 | /*****************************************************************************/ | ||
33 | |||
34 | /****************************** | ||
35 | * Write mode register values * | ||
36 | ******************************/ | ||
37 | |||
38 | /* First register */ | ||
39 | #define TEA5767_MUTE 0x80 /* Mutes output */ | ||
40 | #define TEA5767_SEARCH 0x40 /* Activates station search */ | ||
41 | /* Bits 0-5 for divider MSB */ | ||
42 | |||
43 | /* Second register */ | ||
44 | /* Bits 0-7 for divider LSB */ | ||
45 | |||
46 | /* Third register */ | ||
47 | |||
48 | /* Station search from botton to up */ | ||
49 | #define TEA5767_SEARCH_UP 0x80 | ||
50 | |||
51 | /* Searches with ADC output = 10 */ | ||
52 | #define TEA5767_SRCH_HIGH_LVL 0x60 | ||
53 | |||
54 | /* Searches with ADC output = 10 */ | ||
55 | #define TEA5767_SRCH_MID_LVL 0x40 | ||
56 | |||
57 | /* Searches with ADC output = 5 */ | ||
58 | #define TEA5767_SRCH_LOW_LVL 0x20 | ||
59 | |||
60 | /* if on, div=4*(Frf+Fif)/Fref otherwise, div=4*(Frf-Fif)/Freq) */ | ||
61 | #define TEA5767_HIGH_LO_INJECT 0x10 | ||
62 | |||
63 | /* Disable stereo */ | ||
64 | #define TEA5767_MONO 0x08 | ||
65 | |||
66 | /* Disable right channel and turns to mono */ | ||
67 | #define TEA5767_MUTE_RIGHT 0x04 | ||
68 | |||
69 | /* Disable left channel and turns to mono */ | ||
70 | #define TEA5767_MUTE_LEFT 0x02 | ||
71 | |||
72 | #define TEA5767_PORT1_HIGH 0x01 | ||
73 | |||
74 | /* Fourth register */ | ||
75 | #define TEA5767_PORT2_HIGH 0x80 | ||
76 | /* Chips stops working. Only I2C bus remains on */ | ||
77 | #define TEA5767_STDBY 0x40 | ||
78 | |||
79 | /* Japan freq (76-108 MHz. If disabled, 87.5-108 MHz */ | ||
80 | #define TEA5767_JAPAN_BAND 0x20 | ||
81 | |||
82 | /* Unselected means 32.768 KHz freq as reference. Otherwise Xtal at 13 MHz */ | ||
83 | #define TEA5767_XTAL_32768 0x10 | ||
84 | |||
85 | /* Cuts weak signals */ | ||
86 | #define TEA5767_SOFT_MUTE 0x08 | ||
87 | |||
88 | /* Activates high cut control */ | ||
89 | #define TEA5767_HIGH_CUT_CTRL 0x04 | ||
90 | |||
91 | /* Activates stereo noise control */ | ||
92 | #define TEA5767_ST_NOISE_CTL 0x02 | ||
93 | |||
94 | /* If activate PORT 1 indicates SEARCH or else it is used as PORT1 */ | ||
95 | #define TEA5767_SRCH_IND 0x01 | ||
96 | |||
97 | /* Fifth register */ | ||
98 | |||
99 | /* By activating, it will use Xtal at 13 MHz as reference for divider */ | ||
100 | #define TEA5767_PLLREF_ENABLE 0x80 | ||
101 | |||
102 | /* By activating, deemphasis=50, or else, deemphasis of 50us */ | ||
103 | #define TEA5767_DEEMPH_75 0X40 | ||
104 | |||
105 | /***************************** | ||
106 | * Read mode register values * | ||
107 | *****************************/ | ||
108 | |||
109 | /* First register */ | ||
110 | #define TEA5767_READY_FLAG_MASK 0x80 | ||
111 | #define TEA5767_BAND_LIMIT_MASK 0X40 | ||
112 | /* Bits 0-5 for divider MSB after search or preset */ | ||
113 | |||
114 | /* Second register */ | ||
115 | /* Bits 0-7 for divider LSB after search or preset */ | ||
116 | |||
117 | /* Third register */ | ||
118 | #define TEA5767_STEREO_MASK 0x80 | ||
119 | #define TEA5767_IF_CNTR_MASK 0x7f | ||
120 | |||
121 | /* Fourth register */ | ||
122 | #define TEA5767_ADC_LEVEL_MASK 0xf0 | ||
123 | |||
124 | /* should be 0 */ | ||
125 | #define TEA5767_CHIP_ID_MASK 0x0f | ||
126 | |||
127 | /* Fifth register */ | ||
128 | /* Reserved for future extensions */ | ||
129 | #define TEA5767_RESERVED_MASK 0xff | ||
130 | |||
131 | /*****************************************************************************/ | ||
132 | |||
133 | static void tea5767_status_dump(struct tea5767_priv *priv, | ||
134 | unsigned char *buffer) | ||
135 | { | ||
136 | unsigned int div, frq; | ||
137 | |||
138 | if (TEA5767_READY_FLAG_MASK & buffer[0]) | ||
139 | tuner_info("Ready Flag ON\n"); | ||
140 | else | ||
141 | tuner_info("Ready Flag OFF\n"); | ||
142 | |||
143 | if (TEA5767_BAND_LIMIT_MASK & buffer[0]) | ||
144 | tuner_info("Tuner at band limit\n"); | ||
145 | else | ||
146 | tuner_info("Tuner not at band limit\n"); | ||
147 | |||
148 | div = ((buffer[0] & 0x3f) << 8) | buffer[1]; | ||
149 | |||
150 | switch (priv->ctrl.xtal_freq) { | ||
151 | case TEA5767_HIGH_LO_13MHz: | ||
152 | frq = (div * 50000 - 700000 - 225000) / 4; /* Freq in KHz */ | ||
153 | break; | ||
154 | case TEA5767_LOW_LO_13MHz: | ||
155 | frq = (div * 50000 + 700000 + 225000) / 4; /* Freq in KHz */ | ||
156 | break; | ||
157 | case TEA5767_LOW_LO_32768: | ||
158 | frq = (div * 32768 + 700000 + 225000) / 4; /* Freq in KHz */ | ||
159 | break; | ||
160 | case TEA5767_HIGH_LO_32768: | ||
161 | default: | ||
162 | frq = (div * 32768 - 700000 - 225000) / 4; /* Freq in KHz */ | ||
163 | break; | ||
164 | } | ||
165 | buffer[0] = (div >> 8) & 0x3f; | ||
166 | buffer[1] = div & 0xff; | ||
167 | |||
168 | tuner_info("Frequency %d.%03d KHz (divider = 0x%04x)\n", | ||
169 | frq / 1000, frq % 1000, div); | ||
170 | |||
171 | if (TEA5767_STEREO_MASK & buffer[2]) | ||
172 | tuner_info("Stereo\n"); | ||
173 | else | ||
174 | tuner_info("Mono\n"); | ||
175 | |||
176 | tuner_info("IF Counter = %d\n", buffer[2] & TEA5767_IF_CNTR_MASK); | ||
177 | |||
178 | tuner_info("ADC Level = %d\n", | ||
179 | (buffer[3] & TEA5767_ADC_LEVEL_MASK) >> 4); | ||
180 | |||
181 | tuner_info("Chip ID = %d\n", (buffer[3] & TEA5767_CHIP_ID_MASK)); | ||
182 | |||
183 | tuner_info("Reserved = 0x%02x\n", | ||
184 | (buffer[4] & TEA5767_RESERVED_MASK)); | ||
185 | } | ||
186 | |||
187 | /* Freq should be specifyed at 62.5 Hz */ | ||
188 | static int set_radio_freq(struct dvb_frontend *fe, | ||
189 | struct analog_parameters *params) | ||
190 | { | ||
191 | struct tea5767_priv *priv = fe->tuner_priv; | ||
192 | unsigned int frq = params->frequency; | ||
193 | unsigned char buffer[5]; | ||
194 | unsigned div; | ||
195 | int rc; | ||
196 | |||
197 | tuner_dbg("radio freq = %d.%03d MHz\n", frq/16000,(frq/16)%1000); | ||
198 | |||
199 | buffer[2] = 0; | ||
200 | |||
201 | if (priv->ctrl.port1) | ||
202 | buffer[2] |= TEA5767_PORT1_HIGH; | ||
203 | |||
204 | if (params->audmode == V4L2_TUNER_MODE_MONO) { | ||
205 | tuner_dbg("TEA5767 set to mono\n"); | ||
206 | buffer[2] |= TEA5767_MONO; | ||
207 | } else { | ||
208 | tuner_dbg("TEA5767 set to stereo\n"); | ||
209 | } | ||
210 | |||
211 | |||
212 | buffer[3] = 0; | ||
213 | |||
214 | if (priv->ctrl.port2) | ||
215 | buffer[3] |= TEA5767_PORT2_HIGH; | ||
216 | |||
217 | if (priv->ctrl.high_cut) | ||
218 | buffer[3] |= TEA5767_HIGH_CUT_CTRL; | ||
219 | |||
220 | if (priv->ctrl.st_noise) | ||
221 | buffer[3] |= TEA5767_ST_NOISE_CTL; | ||
222 | |||
223 | if (priv->ctrl.soft_mute) | ||
224 | buffer[3] |= TEA5767_SOFT_MUTE; | ||
225 | |||
226 | if (priv->ctrl.japan_band) | ||
227 | buffer[3] |= TEA5767_JAPAN_BAND; | ||
228 | |||
229 | buffer[4] = 0; | ||
230 | |||
231 | if (priv->ctrl.deemph_75) | ||
232 | buffer[4] |= TEA5767_DEEMPH_75; | ||
233 | |||
234 | if (priv->ctrl.pllref) | ||
235 | buffer[4] |= TEA5767_PLLREF_ENABLE; | ||
236 | |||
237 | |||
238 | /* Rounds freq to next decimal value - for 62.5 KHz step */ | ||
239 | /* frq = 20*(frq/16)+radio_frq[frq%16]; */ | ||
240 | |||
241 | switch (priv->ctrl.xtal_freq) { | ||
242 | case TEA5767_HIGH_LO_13MHz: | ||
243 | tuner_dbg("radio HIGH LO inject xtal @ 13 MHz\n"); | ||
244 | buffer[2] |= TEA5767_HIGH_LO_INJECT; | ||
245 | div = (frq * (4000 / 16) + 700000 + 225000 + 25000) / 50000; | ||
246 | break; | ||
247 | case TEA5767_LOW_LO_13MHz: | ||
248 | tuner_dbg("radio LOW LO inject xtal @ 13 MHz\n"); | ||
249 | |||
250 | div = (frq * (4000 / 16) - 700000 - 225000 + 25000) / 50000; | ||
251 | break; | ||
252 | case TEA5767_LOW_LO_32768: | ||
253 | tuner_dbg("radio LOW LO inject xtal @ 32,768 MHz\n"); | ||
254 | buffer[3] |= TEA5767_XTAL_32768; | ||
255 | /* const 700=4000*175 Khz - to adjust freq to right value */ | ||
256 | div = ((frq * (4000 / 16) - 700000 - 225000) + 16384) >> 15; | ||
257 | break; | ||
258 | case TEA5767_HIGH_LO_32768: | ||
259 | default: | ||
260 | tuner_dbg("radio HIGH LO inject xtal @ 32,768 MHz\n"); | ||
261 | |||
262 | buffer[2] |= TEA5767_HIGH_LO_INJECT; | ||
263 | buffer[3] |= TEA5767_XTAL_32768; | ||
264 | div = ((frq * (4000 / 16) + 700000 + 225000) + 16384) >> 15; | ||
265 | break; | ||
266 | } | ||
267 | buffer[0] = (div >> 8) & 0x3f; | ||
268 | buffer[1] = div & 0xff; | ||
269 | |||
270 | if (5 != (rc = tuner_i2c_xfer_send(&priv->i2c_props, buffer, 5))) | ||
271 | tuner_warn("i2c i/o error: rc == %d (should be 5)\n", rc); | ||
272 | |||
273 | if (debug) { | ||
274 | if (5 != (rc = tuner_i2c_xfer_recv(&priv->i2c_props, buffer, 5))) | ||
275 | tuner_warn("i2c i/o error: rc == %d (should be 5)\n", rc); | ||
276 | else | ||
277 | tea5767_status_dump(priv, buffer); | ||
278 | } | ||
279 | |||
280 | priv->frequency = frq * 125 / 2; | ||
281 | |||
282 | return 0; | ||
283 | } | ||
284 | |||
285 | static int tea5767_read_status(struct dvb_frontend *fe, char *buffer) | ||
286 | { | ||
287 | struct tea5767_priv *priv = fe->tuner_priv; | ||
288 | int rc; | ||
289 | |||
290 | memset(buffer, 0, 5); | ||
291 | if (5 != (rc = tuner_i2c_xfer_recv(&priv->i2c_props, buffer, 5))) { | ||
292 | tuner_warn("i2c i/o error: rc == %d (should be 5)\n", rc); | ||
293 | return -EREMOTEIO; | ||
294 | } | ||
295 | |||
296 | return 0; | ||
297 | } | ||
298 | |||
299 | static inline int tea5767_signal(struct dvb_frontend *fe, const char *buffer) | ||
300 | { | ||
301 | struct tea5767_priv *priv = fe->tuner_priv; | ||
302 | |||
303 | int signal = ((buffer[3] & TEA5767_ADC_LEVEL_MASK) << 8); | ||
304 | |||
305 | tuner_dbg("Signal strength: %d\n", signal); | ||
306 | |||
307 | return signal; | ||
308 | } | ||
309 | |||
310 | static inline int tea5767_stereo(struct dvb_frontend *fe, const char *buffer) | ||
311 | { | ||
312 | struct tea5767_priv *priv = fe->tuner_priv; | ||
313 | |||
314 | int stereo = buffer[2] & TEA5767_STEREO_MASK; | ||
315 | |||
316 | tuner_dbg("Radio ST GET = %02x\n", stereo); | ||
317 | |||
318 | return (stereo ? V4L2_TUNER_SUB_STEREO : 0); | ||
319 | } | ||
320 | |||
321 | static int tea5767_get_status(struct dvb_frontend *fe, u32 *status) | ||
322 | { | ||
323 | unsigned char buffer[5]; | ||
324 | |||
325 | *status = 0; | ||
326 | |||
327 | if (0 == tea5767_read_status(fe, buffer)) { | ||
328 | if (tea5767_signal(fe, buffer)) | ||
329 | *status = TUNER_STATUS_LOCKED; | ||
330 | if (tea5767_stereo(fe, buffer)) | ||
331 | *status |= TUNER_STATUS_STEREO; | ||
332 | } | ||
333 | |||
334 | return 0; | ||
335 | } | ||
336 | |||
337 | static int tea5767_get_rf_strength(struct dvb_frontend *fe, u16 *strength) | ||
338 | { | ||
339 | unsigned char buffer[5]; | ||
340 | |||
341 | *strength = 0; | ||
342 | |||
343 | if (0 == tea5767_read_status(fe, buffer)) | ||
344 | *strength = tea5767_signal(fe, buffer); | ||
345 | |||
346 | return 0; | ||
347 | } | ||
348 | |||
349 | static int tea5767_standby(struct dvb_frontend *fe) | ||
350 | { | ||
351 | unsigned char buffer[5]; | ||
352 | struct tea5767_priv *priv = fe->tuner_priv; | ||
353 | unsigned div, rc; | ||
354 | |||
355 | div = (87500 * 4 + 700 + 225 + 25) / 50; /* Set frequency to 87.5 MHz */ | ||
356 | buffer[0] = (div >> 8) & 0x3f; | ||
357 | buffer[1] = div & 0xff; | ||
358 | buffer[2] = TEA5767_PORT1_HIGH; | ||
359 | buffer[3] = TEA5767_PORT2_HIGH | TEA5767_HIGH_CUT_CTRL | | ||
360 | TEA5767_ST_NOISE_CTL | TEA5767_JAPAN_BAND | TEA5767_STDBY; | ||
361 | buffer[4] = 0; | ||
362 | |||
363 | if (5 != (rc = tuner_i2c_xfer_send(&priv->i2c_props, buffer, 5))) | ||
364 | tuner_warn("i2c i/o error: rc == %d (should be 5)\n", rc); | ||
365 | |||
366 | return 0; | ||
367 | } | ||
368 | |||
369 | int tea5767_autodetection(struct i2c_adapter* i2c_adap, u8 i2c_addr) | ||
370 | { | ||
371 | struct tuner_i2c_props i2c = { .adap = i2c_adap, .addr = i2c_addr }; | ||
372 | unsigned char buffer[7] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff }; | ||
373 | int rc; | ||
374 | |||
375 | if ((rc = tuner_i2c_xfer_recv(&i2c, buffer, 7))< 5) { | ||
376 | printk(KERN_WARNING "It is not a TEA5767. Received %i bytes.\n", rc); | ||
377 | return -EINVAL; | ||
378 | } | ||
379 | |||
380 | /* If all bytes are the same then it's a TV tuner and not a tea5767 */ | ||
381 | if (buffer[0] == buffer[1] && buffer[0] == buffer[2] && | ||
382 | buffer[0] == buffer[3] && buffer[0] == buffer[4]) { | ||
383 | printk(KERN_WARNING "All bytes are equal. It is not a TEA5767\n"); | ||
384 | return -EINVAL; | ||
385 | } | ||
386 | |||
387 | /* Status bytes: | ||
388 | * Byte 4: bit 3:1 : CI (Chip Identification) == 0 | ||
389 | * bit 0 : internally set to 0 | ||
390 | * Byte 5: bit 7:0 : == 0 | ||
391 | */ | ||
392 | if (((buffer[3] & 0x0f) != 0x00) || (buffer[4] != 0x00)) { | ||
393 | printk(KERN_WARNING "Chip ID is not zero. It is not a TEA5767\n"); | ||
394 | return -EINVAL; | ||
395 | } | ||
396 | |||
397 | |||
398 | return 0; | ||
399 | } | ||
400 | |||
401 | static int tea5767_release(struct dvb_frontend *fe) | ||
402 | { | ||
403 | kfree(fe->tuner_priv); | ||
404 | fe->tuner_priv = NULL; | ||
405 | |||
406 | return 0; | ||
407 | } | ||
408 | |||
409 | static int tea5767_get_frequency(struct dvb_frontend *fe, u32 *frequency) | ||
410 | { | ||
411 | struct tea5767_priv *priv = fe->tuner_priv; | ||
412 | *frequency = priv->frequency; | ||
413 | |||
414 | return 0; | ||
415 | } | ||
416 | |||
417 | static int tea5767_set_config (struct dvb_frontend *fe, void *priv_cfg) | ||
418 | { | ||
419 | struct tea5767_priv *priv = fe->tuner_priv; | ||
420 | |||
421 | memcpy(&priv->ctrl, priv_cfg, sizeof(priv->ctrl)); | ||
422 | |||
423 | return 0; | ||
424 | } | ||
425 | |||
426 | static struct dvb_tuner_ops tea5767_tuner_ops = { | ||
427 | .info = { | ||
428 | .name = "tea5767", // Philips TEA5767HN FM Radio | ||
429 | }, | ||
430 | |||
431 | .set_analog_params = set_radio_freq, | ||
432 | .set_config = tea5767_set_config, | ||
433 | .sleep = tea5767_standby, | ||
434 | .release = tea5767_release, | ||
435 | .get_frequency = tea5767_get_frequency, | ||
436 | .get_status = tea5767_get_status, | ||
437 | .get_rf_strength = tea5767_get_rf_strength, | ||
438 | }; | ||
439 | |||
440 | struct dvb_frontend *tea5767_attach(struct dvb_frontend *fe, | ||
441 | struct i2c_adapter* i2c_adap, | ||
442 | u8 i2c_addr) | ||
443 | { | ||
444 | struct tea5767_priv *priv = NULL; | ||
445 | |||
446 | priv = kzalloc(sizeof(struct tea5767_priv), GFP_KERNEL); | ||
447 | if (priv == NULL) | ||
448 | return NULL; | ||
449 | fe->tuner_priv = priv; | ||
450 | |||
451 | priv->i2c_props.addr = i2c_addr; | ||
452 | priv->i2c_props.adap = i2c_adap; | ||
453 | priv->i2c_props.name = "tea5767"; | ||
454 | |||
455 | priv->ctrl.xtal_freq = TEA5767_HIGH_LO_32768; | ||
456 | priv->ctrl.port1 = 1; | ||
457 | priv->ctrl.port2 = 1; | ||
458 | priv->ctrl.high_cut = 1; | ||
459 | priv->ctrl.st_noise = 1; | ||
460 | priv->ctrl.japan_band = 1; | ||
461 | |||
462 | memcpy(&fe->ops.tuner_ops, &tea5767_tuner_ops, | ||
463 | sizeof(struct dvb_tuner_ops)); | ||
464 | |||
465 | tuner_info("type set to %s\n", "Philips TEA5767HN FM Radio"); | ||
466 | |||
467 | return fe; | ||
468 | } | ||
469 | |||
470 | EXPORT_SYMBOL_GPL(tea5767_attach); | ||
471 | EXPORT_SYMBOL_GPL(tea5767_autodetection); | ||
472 | |||
473 | MODULE_DESCRIPTION("Philips TEA5767 FM tuner driver"); | ||
474 | MODULE_AUTHOR("Mauro Carvalho Chehab <mchehab@infradead.org>"); | ||
475 | MODULE_LICENSE("GPL"); | ||