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