diff options
author | Steven Toth <stoth@linuxtv.org> | 2009-05-02 10:07:29 -0400 |
---|---|---|
committer | Mauro Carvalho Chehab <mchehab@redhat.com> | 2009-06-16 17:20:53 -0400 |
commit | d114153816ec188b20a37583e66da33d8b2798fe (patch) | |
tree | cdac5cbecdbfced7c9515b616623f9f8b5c080b7 /drivers | |
parent | 17720e07b6ac573c8929c39f9036dbc460867b72 (diff) |
V4L/DVB (11697): tda10048: Add ability to select I/F at attach time.
tda10048: Add ability to select I/F at attach time.
Signed-off-by: Steven Toth <stoth@linuxtv.org>
Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com>
Diffstat (limited to 'drivers')
-rw-r--r-- | drivers/media/dvb/frontends/tda10048.c | 219 | ||||
-rw-r--r-- | drivers/media/dvb/frontends/tda10048.h | 14 |
2 files changed, 232 insertions, 1 deletions
diff --git a/drivers/media/dvb/frontends/tda10048.c b/drivers/media/dvb/frontends/tda10048.c index 2a8bbcd44cd0..28f580f858c6 100644 --- a/drivers/media/dvb/frontends/tda10048.c +++ b/drivers/media/dvb/frontends/tda10048.c | |||
@@ -25,6 +25,7 @@ | |||
25 | #include <linux/string.h> | 25 | #include <linux/string.h> |
26 | #include <linux/slab.h> | 26 | #include <linux/slab.h> |
27 | #include <linux/delay.h> | 27 | #include <linux/delay.h> |
28 | #include <asm/div64.h> | ||
28 | #include "dvb_frontend.h" | 29 | #include "dvb_frontend.h" |
29 | #include "dvb_math.h" | 30 | #include "dvb_math.h" |
30 | #include "tda10048.h" | 31 | #include "tda10048.h" |
@@ -143,6 +144,15 @@ struct tda10048_state { | |||
143 | struct dvb_frontend frontend; | 144 | struct dvb_frontend frontend; |
144 | 145 | ||
145 | int fwloaded; | 146 | int fwloaded; |
147 | |||
148 | u32 freq_if_hz; | ||
149 | u32 xtal_hz; | ||
150 | u32 pll_mfactor; | ||
151 | u32 pll_nfactor; | ||
152 | u32 pll_pfactor; | ||
153 | u32 sample_freq; | ||
154 | |||
155 | enum fe_bandwidth bandwidth; | ||
146 | }; | 156 | }; |
147 | 157 | ||
148 | static struct init_tab { | 158 | static struct init_tab { |
@@ -271,6 +281,199 @@ error: | |||
271 | return ret; | 281 | return ret; |
272 | } | 282 | } |
273 | 283 | ||
284 | static int tda10048_set_phy2(struct dvb_frontend *fe, u32 sample_freq_hz, | ||
285 | u32 if_hz) | ||
286 | { | ||
287 | struct tda10048_state *state = fe->demodulator_priv; | ||
288 | u64 t; | ||
289 | |||
290 | dprintk(1, "%s()\n", __func__); | ||
291 | |||
292 | if (sample_freq_hz == 0) | ||
293 | return -EINVAL; | ||
294 | |||
295 | if (if_hz < (sample_freq_hz / 2)) { | ||
296 | /* PHY2 = (if2/fs) * 2^15 */ | ||
297 | t = if_hz; | ||
298 | t *= 10; | ||
299 | t *= 32768; | ||
300 | do_div(t, sample_freq_hz); | ||
301 | t += 5; | ||
302 | do_div(t, 10); | ||
303 | } else { | ||
304 | /* PHY2 = ((IF1-fs)/fs) * 2^15 */ | ||
305 | t = sample_freq_hz - if_hz; | ||
306 | t *= 10; | ||
307 | t *= 32768; | ||
308 | do_div(t, sample_freq_hz); | ||
309 | t += 5; | ||
310 | do_div(t, 10); | ||
311 | t = ~t + 1; | ||
312 | } | ||
313 | |||
314 | tda10048_writereg(state, TDA10048_FREQ_PHY2_LSB, (u8)t); | ||
315 | tda10048_writereg(state, TDA10048_FREQ_PHY2_MSB, (u8)(t >> 8)); | ||
316 | |||
317 | return 0; | ||
318 | } | ||
319 | |||
320 | static int tda10048_set_wref(struct dvb_frontend *fe, u32 sample_freq_hz, | ||
321 | u32 bw) | ||
322 | { | ||
323 | struct tda10048_state *state = fe->demodulator_priv; | ||
324 | u64 t, z; | ||
325 | u32 b = 8000000; | ||
326 | |||
327 | dprintk(1, "%s()\n", __func__); | ||
328 | |||
329 | if (sample_freq_hz == 0) | ||
330 | return -EINVAL; | ||
331 | |||
332 | if (bw == BANDWIDTH_6_MHZ) | ||
333 | b = 6000000; | ||
334 | else | ||
335 | if (bw == BANDWIDTH_7_MHZ) | ||
336 | b = 7000000; | ||
337 | |||
338 | /* WREF = (B / (7 * fs)) * 2^31 */ | ||
339 | t = b * 10; | ||
340 | /* avoid warning: this decimal constant is unsigned only in ISO C90 */ | ||
341 | /* t *= 2147483648 on 32bit platforms */ | ||
342 | t *= (2048 * 1024); | ||
343 | t *= 1024; | ||
344 | z = 7 * sample_freq_hz; | ||
345 | do_div(t, z); | ||
346 | t += 5; | ||
347 | do_div(t, 10); | ||
348 | |||
349 | tda10048_writereg(state, TDA10048_TIME_WREF_LSB, (u8)t); | ||
350 | tda10048_writereg(state, TDA10048_TIME_WREF_MID1, (u8)(t >> 8)); | ||
351 | tda10048_writereg(state, TDA10048_TIME_WREF_MID2, (u8)(t >> 16)); | ||
352 | tda10048_writereg(state, TDA10048_TIME_WREF_MSB, (u8)(t >> 24)); | ||
353 | |||
354 | return 0; | ||
355 | } | ||
356 | |||
357 | static int tda10048_set_invwref(struct dvb_frontend *fe, u32 sample_freq_hz, | ||
358 | u32 bw) | ||
359 | { | ||
360 | struct tda10048_state *state = fe->demodulator_priv; | ||
361 | u64 t; | ||
362 | u32 b = 8000000; | ||
363 | |||
364 | dprintk(1, "%s()\n", __func__); | ||
365 | |||
366 | if (sample_freq_hz == 0) | ||
367 | return -EINVAL; | ||
368 | |||
369 | if (bw == BANDWIDTH_6_MHZ) | ||
370 | b = 6000000; | ||
371 | else | ||
372 | if (bw == BANDWIDTH_7_MHZ) | ||
373 | b = 7000000; | ||
374 | |||
375 | /* INVWREF = ((7 * fs) / B) * 2^5 */ | ||
376 | t = sample_freq_hz; | ||
377 | t *= 7; | ||
378 | t *= 32; | ||
379 | t *= 10; | ||
380 | do_div(t, b); | ||
381 | t += 5; | ||
382 | do_div(t, 10); | ||
383 | |||
384 | tda10048_writereg(state, TDA10048_TIME_INVWREF_LSB, (u8)t); | ||
385 | tda10048_writereg(state, TDA10048_TIME_INVWREF_MSB, (u8)(t >> 8)); | ||
386 | |||
387 | return 0; | ||
388 | } | ||
389 | |||
390 | static int tda10048_set_bandwidth(struct dvb_frontend *fe, | ||
391 | enum fe_bandwidth bw) | ||
392 | { | ||
393 | struct tda10048_state *state = fe->demodulator_priv; | ||
394 | dprintk(1, "%s(bw=%d)\n", __func__, bw); | ||
395 | |||
396 | /* Bandwidth setting may need to be adjusted */ | ||
397 | switch (bw) { | ||
398 | case BANDWIDTH_6_MHZ: | ||
399 | case BANDWIDTH_7_MHZ: | ||
400 | case BANDWIDTH_8_MHZ: | ||
401 | tda10048_set_wref(fe, state->sample_freq, bw); | ||
402 | tda10048_set_invwref(fe, state->sample_freq, bw); | ||
403 | break; | ||
404 | default: | ||
405 | printk(KERN_ERR "%s() invalid bandwidth\n", __func__); | ||
406 | return -EINVAL; | ||
407 | } | ||
408 | |||
409 | state->bandwidth = bw; | ||
410 | |||
411 | return 0; | ||
412 | } | ||
413 | |||
414 | static int tda10048_set_pll(struct dvb_frontend *fe) | ||
415 | { | ||
416 | struct tda10048_state *state = fe->demodulator_priv; | ||
417 | int ret = 0; | ||
418 | |||
419 | dprintk(1, "%s()\n", __func__); | ||
420 | |||
421 | if ((state->config->clk_freq_khz == TDA10048_CLK_4000) && | ||
422 | (state->config->if_freq_khz == TDA10048_IF_36130)) { | ||
423 | state->freq_if_hz = TDA10048_IF_36130 * 1000; | ||
424 | state->xtal_hz = TDA10048_CLK_4000 * 1000; | ||
425 | state->pll_mfactor = 10; | ||
426 | state->pll_nfactor = 0; | ||
427 | state->pll_pfactor = 0; | ||
428 | } else | ||
429 | if ((state->config->clk_freq_khz == TDA10048_CLK_16000) && | ||
430 | (state->config->if_freq_khz == TDA10048_IF_4300)) { | ||
431 | state->freq_if_hz = TDA10048_IF_4300 * 1000; | ||
432 | state->xtal_hz = TDA10048_CLK_16000 * 1000; | ||
433 | state->pll_mfactor = 10; | ||
434 | state->pll_nfactor = 3; | ||
435 | state->pll_pfactor = 0; | ||
436 | } else | ||
437 | if ((state->config->clk_freq_khz == TDA10048_CLK_16000) && | ||
438 | (state->config->if_freq_khz == TDA10048_IF_4000)) { | ||
439 | state->freq_if_hz = TDA10048_IF_4000 * 1000; | ||
440 | state->xtal_hz = TDA10048_CLK_16000 * 1000; | ||
441 | state->pll_mfactor = 10; | ||
442 | state->pll_nfactor = 3; | ||
443 | state->pll_pfactor = 0; | ||
444 | } else | ||
445 | if ((state->config->clk_freq_khz == TDA10048_CLK_16000) && | ||
446 | (state->config->if_freq_khz == TDA10048_IF_36130)) { | ||
447 | state->freq_if_hz = TDA10048_IF_36130 * 1000; | ||
448 | state->xtal_hz = TDA10048_CLK_16000 * 1000; | ||
449 | state->pll_mfactor = 10; | ||
450 | state->pll_nfactor = 3; | ||
451 | state->pll_pfactor = 0; | ||
452 | } else { | ||
453 | printk(KERN_ERR "%s() Incorrect attach settings\n", __func__); | ||
454 | ret = -EINVAL; | ||
455 | } | ||
456 | |||
457 | dprintk(1, "- freq_if_hz = %d\n", state->freq_if_hz); | ||
458 | dprintk(1, "- xtal_hz = %d\n", state->xtal_hz); | ||
459 | dprintk(1, "- pll_mfactor = %d\n", state->pll_mfactor); | ||
460 | dprintk(1, "- pll_nfactor = %d\n", state->pll_nfactor); | ||
461 | dprintk(1, "- pll_pfactor = %d\n", state->pll_pfactor); | ||
462 | |||
463 | /* Calculate the sample frequency */ | ||
464 | state->sample_freq = state->xtal_hz * (state->pll_mfactor + 45); | ||
465 | state->sample_freq /= (state->pll_nfactor + 1); | ||
466 | state->sample_freq /= (state->pll_pfactor + 4); | ||
467 | dprintk(1, "- sample_freq = %d\n", state->sample_freq); | ||
468 | |||
469 | tda10048_set_phy2(fe, state->sample_freq, | ||
470 | state->config->if_freq_khz * 1000); | ||
471 | tda10048_set_wref(fe, state->sample_freq, state->bandwidth); | ||
472 | tda10048_set_invwref(fe, state->sample_freq, state->bandwidth); | ||
473 | |||
474 | return ret; | ||
475 | } | ||
476 | |||
274 | static int tda10048_firmware_upload(struct dvb_frontend *fe) | 477 | static int tda10048_firmware_upload(struct dvb_frontend *fe) |
275 | { | 478 | { |
276 | struct tda10048_state *state = fe->demodulator_priv; | 479 | struct tda10048_state *state = fe->demodulator_priv; |
@@ -523,6 +726,9 @@ static int tda10048_set_frontend(struct dvb_frontend *fe, | |||
523 | 726 | ||
524 | dprintk(1, "%s(frequency=%d)\n", __func__, p->frequency); | 727 | dprintk(1, "%s(frequency=%d)\n", __func__, p->frequency); |
525 | 728 | ||
729 | if (p->u.ofdm.bandwidth != state->bandwidth) | ||
730 | tda10048_set_bandwidth(fe, p->u.ofdm.bandwidth); | ||
731 | |||
526 | if (fe->ops.tuner_ops.set_params) { | 732 | if (fe->ops.tuner_ops.set_params) { |
527 | 733 | ||
528 | if (fe->ops.i2c_gate_ctrl) | 734 | if (fe->ops.i2c_gate_ctrl) |
@@ -558,9 +764,15 @@ static int tda10048_init(struct dvb_frontend *fe) | |||
558 | /* Set either serial or parallel */ | 764 | /* Set either serial or parallel */ |
559 | tda10048_output_mode(fe, state->config->output_mode); | 765 | tda10048_output_mode(fe, state->config->output_mode); |
560 | 766 | ||
561 | /* set inversion */ | 767 | /* Set inversion */ |
562 | tda10048_set_inversion(fe, state->config->inversion); | 768 | tda10048_set_inversion(fe, state->config->inversion); |
563 | 769 | ||
770 | /* Establish default PLL values */ | ||
771 | tda10048_set_pll(fe); | ||
772 | |||
773 | /* Establish default bandwidth */ | ||
774 | tda10048_set_bandwidth(fe, BANDWIDTH_8_MHZ); | ||
775 | |||
564 | /* Ensure we leave the gate closed */ | 776 | /* Ensure we leave the gate closed */ |
565 | tda10048_i2c_gate_ctrl(fe, 0); | 777 | tda10048_i2c_gate_ctrl(fe, 0); |
566 | 778 | ||
@@ -830,6 +1042,7 @@ struct dvb_frontend *tda10048_attach(const struct tda10048_config *config, | |||
830 | state->config = config; | 1042 | state->config = config; |
831 | state->i2c = i2c; | 1043 | state->i2c = i2c; |
832 | state->fwloaded = 0; | 1044 | state->fwloaded = 0; |
1045 | state->bandwidth = BANDWIDTH_8_MHZ; | ||
833 | 1046 | ||
834 | /* check if the demod is present */ | 1047 | /* check if the demod is present */ |
835 | if (tda10048_readreg(state, TDA10048_IDENTITY) != 0x048) | 1048 | if (tda10048_readreg(state, TDA10048_IDENTITY) != 0x048) |
@@ -840,6 +1053,10 @@ struct dvb_frontend *tda10048_attach(const struct tda10048_config *config, | |||
840 | sizeof(struct dvb_frontend_ops)); | 1053 | sizeof(struct dvb_frontend_ops)); |
841 | state->frontend.demodulator_priv = state; | 1054 | state->frontend.demodulator_priv = state; |
842 | 1055 | ||
1056 | /* Set the xtal and freq defaults */ | ||
1057 | if (tda10048_set_pll(&state->frontend) != 0) | ||
1058 | goto error; | ||
1059 | |||
843 | /* Leave the gate closed */ | 1060 | /* Leave the gate closed */ |
844 | tda10048_i2c_gate_ctrl(&state->frontend, 0); | 1061 | tda10048_i2c_gate_ctrl(&state->frontend, 0); |
845 | 1062 | ||
diff --git a/drivers/media/dvb/frontends/tda10048.h b/drivers/media/dvb/frontends/tda10048.h index 0457b24601fa..ab9cf5bd421e 100644 --- a/drivers/media/dvb/frontends/tda10048.h +++ b/drivers/media/dvb/frontends/tda10048.h | |||
@@ -43,6 +43,20 @@ struct tda10048_config { | |||
43 | #define TDA10048_INVERSION_OFF 0 | 43 | #define TDA10048_INVERSION_OFF 0 |
44 | #define TDA10048_INVERSION_ON 1 | 44 | #define TDA10048_INVERSION_ON 1 |
45 | u8 inversion; | 45 | u8 inversion; |
46 | |||
47 | #define TDA10048_IF_3300 3300 | ||
48 | #define TDA10048_IF_3500 3500 | ||
49 | #define TDA10048_IF_3800 3800 | ||
50 | #define TDA10048_IF_4000 4000 | ||
51 | #define TDA10048_IF_4300 4300 | ||
52 | #define TDA10048_IF_4500 4500 | ||
53 | #define TDA10048_IF_4750 4750 | ||
54 | #define TDA10048_IF_36130 36130 | ||
55 | u16 if_freq_khz; | ||
56 | |||
57 | #define TDA10048_CLK_4000 4000 | ||
58 | #define TDA10048_CLK_16000 16000 | ||
59 | u16 clk_freq_khz; | ||
46 | }; | 60 | }; |
47 | 61 | ||
48 | #if defined(CONFIG_DVB_TDA10048) || \ | 62 | #if defined(CONFIG_DVB_TDA10048) || \ |