diff options
Diffstat (limited to 'drivers/media/dvb/frontends/s5h1409.c')
-rw-r--r-- | drivers/media/dvb/frontends/s5h1409.c | 97 |
1 files changed, 76 insertions, 21 deletions
diff --git a/drivers/media/dvb/frontends/s5h1409.c b/drivers/media/dvb/frontends/s5h1409.c index 562d9208857a..819433485d3b 100644 --- a/drivers/media/dvb/frontends/s5h1409.c +++ b/drivers/media/dvb/frontends/s5h1409.c | |||
@@ -42,6 +42,7 @@ struct s5h1409_state { | |||
42 | fe_modulation_t current_modulation; | 42 | fe_modulation_t current_modulation; |
43 | 43 | ||
44 | u32 current_frequency; | 44 | u32 current_frequency; |
45 | int if_freq; | ||
45 | 46 | ||
46 | u32 is_qam_locked; | 47 | u32 is_qam_locked; |
47 | u32 qam_state; | 48 | u32 qam_state; |
@@ -97,7 +98,7 @@ static struct init_tab { | |||
97 | { 0xac, 0x1003, }, | 98 | { 0xac, 0x1003, }, |
98 | { 0xad, 0x103f, }, | 99 | { 0xad, 0x103f, }, |
99 | { 0xe2, 0x0100, }, | 100 | { 0xe2, 0x0100, }, |
100 | { 0xe3, 0x0000, }, | 101 | { 0xe3, 0x1000, }, |
101 | { 0x28, 0x1010, }, | 102 | { 0x28, 0x1010, }, |
102 | { 0xb1, 0x000e, }, | 103 | { 0xb1, 0x000e, }, |
103 | }; | 104 | }; |
@@ -348,28 +349,32 @@ static int s5h1409_softreset(struct dvb_frontend* fe) | |||
348 | return 0; | 349 | return 0; |
349 | } | 350 | } |
350 | 351 | ||
352 | #define S5H1409_VSB_IF_FREQ 5380 | ||
353 | #define S5H1409_QAM_IF_FREQ state->config->qam_if | ||
354 | |||
351 | static int s5h1409_set_if_freq(struct dvb_frontend* fe, int KHz) | 355 | static int s5h1409_set_if_freq(struct dvb_frontend* fe, int KHz) |
352 | { | 356 | { |
353 | struct s5h1409_state* state = fe->demodulator_priv; | 357 | struct s5h1409_state* state = fe->demodulator_priv; |
354 | int ret = 0; | ||
355 | 358 | ||
356 | dprintk("%s(%d KHz)\n", __FUNCTION__, KHz); | 359 | dprintk("%s(%d KHz)\n", __FUNCTION__, KHz); |
357 | 360 | ||
358 | if( (KHz == 44000) || (KHz == 5380) ) { | 361 | switch (KHz) { |
359 | s5h1409_writereg(state, 0x87, 0x01be); | 362 | case 4000: |
360 | s5h1409_writereg(state, 0x88, 0x0436); | ||
361 | s5h1409_writereg(state, 0x89, 0x054d); | ||
362 | } else | ||
363 | if (KHz == 4000) { | ||
364 | s5h1409_writereg(state, 0x87, 0x014b); | 363 | s5h1409_writereg(state, 0x87, 0x014b); |
365 | s5h1409_writereg(state, 0x88, 0x0cb5); | 364 | s5h1409_writereg(state, 0x88, 0x0cb5); |
366 | s5h1409_writereg(state, 0x89, 0x03e2); | 365 | s5h1409_writereg(state, 0x89, 0x03e2); |
367 | } else { | 366 | break; |
368 | printk("%s() Invalid arg = %d KHz\n", __FUNCTION__, KHz); | 367 | case 5380: |
369 | ret = -1; | 368 | case 44000: |
369 | default: | ||
370 | s5h1409_writereg(state, 0x87, 0x01be); | ||
371 | s5h1409_writereg(state, 0x88, 0x0436); | ||
372 | s5h1409_writereg(state, 0x89, 0x054d); | ||
373 | break; | ||
370 | } | 374 | } |
375 | state->if_freq = KHz; | ||
371 | 376 | ||
372 | return ret; | 377 | return 0; |
373 | } | 378 | } |
374 | 379 | ||
375 | static int s5h1409_set_spectralinversion(struct dvb_frontend* fe, int inverted) | 380 | static int s5h1409_set_spectralinversion(struct dvb_frontend* fe, int inverted) |
@@ -394,11 +399,15 @@ static int s5h1409_enable_modulation(struct dvb_frontend* fe, | |||
394 | switch(m) { | 399 | switch(m) { |
395 | case VSB_8: | 400 | case VSB_8: |
396 | dprintk("%s() VSB_8\n", __FUNCTION__); | 401 | dprintk("%s() VSB_8\n", __FUNCTION__); |
402 | if (state->if_freq != S5H1409_VSB_IF_FREQ) | ||
403 | s5h1409_set_if_freq(fe, S5H1409_VSB_IF_FREQ); | ||
397 | s5h1409_writereg(state, 0xf4, 0); | 404 | s5h1409_writereg(state, 0xf4, 0); |
398 | break; | 405 | break; |
399 | case QAM_64: | 406 | case QAM_64: |
400 | case QAM_256: | 407 | case QAM_256: |
401 | dprintk("%s() QAM_AUTO (64/256)\n", __FUNCTION__); | 408 | dprintk("%s() QAM_AUTO (64/256)\n", __FUNCTION__); |
409 | if (state->if_freq != S5H1409_QAM_IF_FREQ) | ||
410 | s5h1409_set_if_freq(fe, S5H1409_QAM_IF_FREQ); | ||
402 | s5h1409_writereg(state, 0xf4, 1); | 411 | s5h1409_writereg(state, 0xf4, 1); |
403 | s5h1409_writereg(state, 0x85, 0x110); | 412 | s5h1409_writereg(state, 0x85, 0x110); |
404 | break; | 413 | break; |
@@ -432,9 +441,11 @@ static int s5h1409_set_gpio(struct dvb_frontend* fe, int enable) | |||
432 | dprintk("%s(%d)\n", __FUNCTION__, enable); | 441 | dprintk("%s(%d)\n", __FUNCTION__, enable); |
433 | 442 | ||
434 | if (enable) | 443 | if (enable) |
435 | return s5h1409_writereg(state, 0xe3, 0x1100); | 444 | return s5h1409_writereg(state, 0xe3, |
445 | s5h1409_readreg(state, 0xe3) | 0x1100); | ||
436 | else | 446 | else |
437 | return s5h1409_writereg(state, 0xe3, 0x1000); | 447 | return s5h1409_writereg(state, 0xe3, |
448 | s5h1409_readreg(state, 0xe3) & 0xeeff); | ||
438 | } | 449 | } |
439 | 450 | ||
440 | static int s5h1409_sleep(struct dvb_frontend* fe, int enable) | 451 | static int s5h1409_sleep(struct dvb_frontend* fe, int enable) |
@@ -504,13 +515,15 @@ static void s5h1409_set_qam_interleave_mode(struct dvb_frontend *fe) | |||
504 | s5h1409_writereg(state, 0x96, 0x20); | 515 | s5h1409_writereg(state, 0x96, 0x20); |
505 | s5h1409_writereg(state, 0xad, | 516 | s5h1409_writereg(state, 0xad, |
506 | ( ((reg1 & 0xf000) >> 4) | (reg2 & 0xf0ff)) ); | 517 | ( ((reg1 & 0xf000) >> 4) | (reg2 & 0xf0ff)) ); |
507 | s5h1409_writereg(state, 0xab, 0x1100); | 518 | s5h1409_writereg(state, 0xab, |
519 | s5h1409_readreg(state, 0xab) & 0xeffe); | ||
508 | } | 520 | } |
509 | } else { | 521 | } else { |
510 | if (state->qam_state != 1) { | 522 | if (state->qam_state != 1) { |
511 | state->qam_state = 1; | 523 | state->qam_state = 1; |
512 | s5h1409_writereg(state, 0x96, 0x08); | 524 | s5h1409_writereg(state, 0x96, 0x08); |
513 | s5h1409_writereg(state, 0xab, 0x1101); | 525 | s5h1409_writereg(state, 0xab, |
526 | s5h1409_readreg(state, 0xab) | 0x1001); | ||
514 | } | 527 | } |
515 | } | 528 | } |
516 | } | 529 | } |
@@ -547,6 +560,36 @@ static int s5h1409_set_frontend (struct dvb_frontend* fe, | |||
547 | return 0; | 560 | return 0; |
548 | } | 561 | } |
549 | 562 | ||
563 | static int s5h1409_set_mpeg_timing(struct dvb_frontend *fe, int mode) | ||
564 | { | ||
565 | struct s5h1409_state *state = fe->demodulator_priv; | ||
566 | u16 val; | ||
567 | |||
568 | dprintk("%s(%d)\n", __FUNCTION__, mode); | ||
569 | |||
570 | val = s5h1409_readreg(state, 0xac) & 0xcfff; | ||
571 | switch (mode) { | ||
572 | case S5H1409_MPEGTIMING_CONTINOUS_INVERTING_CLOCK: | ||
573 | val |= 0x0000; | ||
574 | break; | ||
575 | case S5H1409_MPEGTIMING_CONTINOUS_NONINVERTING_CLOCK: | ||
576 | dprintk("%s(%d) Mode1 or Defaulting\n", __FUNCTION__, mode); | ||
577 | val |= 0x1000; | ||
578 | break; | ||
579 | case S5H1409_MPEGTIMING_NONCONTINOUS_INVERTING_CLOCK: | ||
580 | val |= 0x2000; | ||
581 | break; | ||
582 | case S5H1409_MPEGTIMING_NONCONTINOUS_NONINVERTING_CLOCK: | ||
583 | val |= 0x3000; | ||
584 | break; | ||
585 | default: | ||
586 | return -EINVAL; | ||
587 | } | ||
588 | |||
589 | /* Configure MPEG Signal Timing charactistics */ | ||
590 | return s5h1409_writereg(state, 0xac, val); | ||
591 | } | ||
592 | |||
550 | /* Reset the demod hardware and reset all of the configuration registers | 593 | /* Reset the demod hardware and reset all of the configuration registers |
551 | to a default state. */ | 594 | to a default state. */ |
552 | static int s5h1409_init (struct dvb_frontend* fe) | 595 | static int s5h1409_init (struct dvb_frontend* fe) |
@@ -566,13 +609,16 @@ static int s5h1409_init (struct dvb_frontend* fe) | |||
566 | state->current_modulation = VSB_8; | 609 | state->current_modulation = VSB_8; |
567 | 610 | ||
568 | if (state->config->output_mode == S5H1409_SERIAL_OUTPUT) | 611 | if (state->config->output_mode == S5H1409_SERIAL_OUTPUT) |
569 | s5h1409_writereg(state, 0xab, 0x100); /* Serial */ | 612 | s5h1409_writereg(state, 0xab, |
613 | s5h1409_readreg(state, 0xab) | 0x100); /* Serial */ | ||
570 | else | 614 | else |
571 | s5h1409_writereg(state, 0xab, 0x0); /* Parallel */ | 615 | s5h1409_writereg(state, 0xab, |
616 | s5h1409_readreg(state, 0xab) & 0xfeff); /* Parallel */ | ||
572 | 617 | ||
573 | s5h1409_set_spectralinversion(fe, state->config->inversion); | 618 | s5h1409_set_spectralinversion(fe, state->config->inversion); |
574 | s5h1409_set_if_freq(fe, state->config->if_freq); | 619 | s5h1409_set_if_freq(fe, state->if_freq); |
575 | s5h1409_set_gpio(fe, state->config->gpio); | 620 | s5h1409_set_gpio(fe, state->config->gpio); |
621 | s5h1409_set_mpeg_timing(fe, state->config->mpeg_timing); | ||
576 | s5h1409_softreset(fe); | 622 | s5h1409_softreset(fe); |
577 | 623 | ||
578 | /* Note: Leaving the I2C gate closed. */ | 624 | /* Note: Leaving the I2C gate closed. */ |
@@ -741,6 +787,7 @@ struct dvb_frontend* s5h1409_attach(const struct s5h1409_config* config, | |||
741 | struct i2c_adapter* i2c) | 787 | struct i2c_adapter* i2c) |
742 | { | 788 | { |
743 | struct s5h1409_state* state = NULL; | 789 | struct s5h1409_state* state = NULL; |
790 | u16 reg; | ||
744 | 791 | ||
745 | /* allocate memory for the internal state */ | 792 | /* allocate memory for the internal state */ |
746 | state = kmalloc(sizeof(struct s5h1409_state), GFP_KERNEL); | 793 | state = kmalloc(sizeof(struct s5h1409_state), GFP_KERNEL); |
@@ -751,9 +798,11 @@ struct dvb_frontend* s5h1409_attach(const struct s5h1409_config* config, | |||
751 | state->config = config; | 798 | state->config = config; |
752 | state->i2c = i2c; | 799 | state->i2c = i2c; |
753 | state->current_modulation = 0; | 800 | state->current_modulation = 0; |
801 | state->if_freq = S5H1409_VSB_IF_FREQ; | ||
754 | 802 | ||
755 | /* check if the demod exists */ | 803 | /* check if the demod exists */ |
756 | if (s5h1409_readreg(state, 0x04) != 0x0066) | 804 | reg = s5h1409_readreg(state, 0x04); |
805 | if ((reg != 0x0066) && (reg != 0x007f)) | ||
757 | goto error; | 806 | goto error; |
758 | 807 | ||
759 | /* create dvb_frontend */ | 808 | /* create dvb_frontend */ |
@@ -761,8 +810,14 @@ struct dvb_frontend* s5h1409_attach(const struct s5h1409_config* config, | |||
761 | sizeof(struct dvb_frontend_ops)); | 810 | sizeof(struct dvb_frontend_ops)); |
762 | state->frontend.demodulator_priv = state; | 811 | state->frontend.demodulator_priv = state; |
763 | 812 | ||
813 | if (s5h1409_init(&state->frontend) != 0) { | ||
814 | printk(KERN_ERR "%s: Failed to initialize correctly\n", | ||
815 | __FUNCTION__); | ||
816 | goto error; | ||
817 | } | ||
818 | |||
764 | /* Note: Leaving the I2C gate open here. */ | 819 | /* Note: Leaving the I2C gate open here. */ |
765 | s5h1409_writereg(state, 0xf3, 1); | 820 | s5h1409_i2c_gate_ctrl(&state->frontend, 1); |
766 | 821 | ||
767 | return &state->frontend; | 822 | return &state->frontend; |
768 | 823 | ||