aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/media/dvb/frontends/au8522.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/media/dvb/frontends/au8522.c')
-rw-r--r--drivers/media/dvb/frontends/au8522.c133
1 files changed, 133 insertions, 0 deletions
diff --git a/drivers/media/dvb/frontends/au8522.c b/drivers/media/dvb/frontends/au8522.c
index 0b82cc2a1e16..eabf9a68e7ec 100644
--- a/drivers/media/dvb/frontends/au8522.c
+++ b/drivers/media/dvb/frontends/au8522.c
@@ -40,6 +40,8 @@ struct au8522_state {
40 u32 current_frequency; 40 u32 current_frequency;
41 fe_modulation_t current_modulation; 41 fe_modulation_t current_modulation;
42 42
43 u32 fe_status;
44 unsigned int led_state;
43}; 45};
44 46
45static int debug; 47static int debug;
@@ -538,11 +540,98 @@ static int au8522_init(struct dvb_frontend *fe)
538 return 0; 540 return 0;
539} 541}
540 542
543static int au8522_led_gpio_enable(struct au8522_state *state, int onoff)
544{
545 struct au8522_led_config *led_config = state->config->led_cfg;
546 u8 val;
547
548 /* bail out if we cant control an LED */
549 if (!led_config || !led_config->gpio_output ||
550 !led_config->gpio_output_enable || !led_config->gpio_output_disable)
551 return 0;
552
553 val = au8522_readreg(state, 0x4000 |
554 (led_config->gpio_output & ~0xc000));
555 if (onoff) {
556 /* enable GPIO output */
557 val &= ~((led_config->gpio_output_enable >> 8) & 0xff);
558 val |= (led_config->gpio_output_enable & 0xff);
559 } else {
560 /* disable GPIO output */
561 val &= ~((led_config->gpio_output_disable >> 8) & 0xff);
562 val |= (led_config->gpio_output_disable & 0xff);
563 }
564 return au8522_writereg(state, 0x8000 |
565 (led_config->gpio_output & ~0xc000), val);
566}
567
568/* led = 0 | off
569 * led = 1 | signal ok
570 * led = 2 | signal strong
571 * led < 0 | only light led if leds are currently off
572 */
573static int au8522_led_ctrl(struct au8522_state *state, int led)
574{
575 struct au8522_led_config *led_config = state->config->led_cfg;
576 int i, ret = 0;
577
578 /* bail out if we cant control an LED */
579 if (!led_config || !led_config->gpio_leds ||
580 !led_config->num_led_states || !led_config->led_states)
581 return 0;
582
583 if (led < 0) {
584 /* if LED is already lit, then leave it as-is */
585 if (state->led_state)
586 return 0;
587 else
588 led *= -1;
589 }
590
591 /* toggle LED if changing state */
592 if (state->led_state != led) {
593 u8 val;
594
595 dprintk("%s: %d\n", __func__, led);
596
597 au8522_led_gpio_enable(state, 1);
598
599 val = au8522_readreg(state, 0x4000 |
600 (led_config->gpio_leds & ~0xc000));
601
602 /* start with all leds off */
603 for (i = 0; i < led_config->num_led_states; i++)
604 val &= ~led_config->led_states[i];
605
606 /* set selected LED state */
607 if (led < led_config->num_led_states)
608 val |= led_config->led_states[led];
609 else if (led_config->num_led_states)
610 val |=
611 led_config->led_states[led_config->num_led_states - 1];
612
613 ret = au8522_writereg(state, 0x8000 |
614 (led_config->gpio_leds & ~0xc000), val);
615 if (ret < 0)
616 return ret;
617
618 state->led_state = led;
619
620 if (led == 0)
621 au8522_led_gpio_enable(state, 0);
622 }
623
624 return 0;
625}
626
541static int au8522_sleep(struct dvb_frontend *fe) 627static int au8522_sleep(struct dvb_frontend *fe)
542{ 628{
543 struct au8522_state *state = fe->demodulator_priv; 629 struct au8522_state *state = fe->demodulator_priv;
544 dprintk("%s()\n", __func__); 630 dprintk("%s()\n", __func__);
545 631
632 /* turn off led */
633 au8522_led_ctrl(state, 0);
634
546 state->current_frequency = 0; 635 state->current_frequency = 0;
547 636
548 return 0; 637 return 0;
@@ -592,12 +681,53 @@ static int au8522_read_status(struct dvb_frontend *fe, fe_status_t *status)
592 *status |= FE_HAS_CARRIER | FE_HAS_SIGNAL; 681 *status |= FE_HAS_CARRIER | FE_HAS_SIGNAL;
593 break; 682 break;
594 } 683 }
684 state->fe_status = *status;
685
686 if (*status & FE_HAS_LOCK)
687 /* turn on LED, if it isn't on already */
688 au8522_led_ctrl(state, -1);
689 else
690 /* turn off LED */
691 au8522_led_ctrl(state, 0);
595 692
596 dprintk("%s() status 0x%08x\n", __func__, *status); 693 dprintk("%s() status 0x%08x\n", __func__, *status);
597 694
598 return 0; 695 return 0;
599} 696}
600 697
698static int au8522_led_status(struct au8522_state *state, const u16 *snr)
699{
700 struct au8522_led_config *led_config = state->config->led_cfg;
701 int led;
702 u16 strong;
703
704 /* bail out if we cant control an LED */
705 if (!led_config)
706 return 0;
707
708 if (0 == (state->fe_status & FE_HAS_LOCK))
709 return au8522_led_ctrl(state, 0);
710 else if (state->current_modulation == QAM_256)
711 strong = led_config->qam256_strong;
712 else if (state->current_modulation == QAM_64)
713 strong = led_config->qam64_strong;
714 else /* (state->current_modulation == VSB_8) */
715 strong = led_config->vsb8_strong;
716
717 if (*snr >= strong)
718 led = 2;
719 else
720 led = 1;
721
722 if ((state->led_state) &&
723 (((strong < *snr) ? (*snr - strong) : (strong - *snr)) <= 10))
724 /* snr didn't change enough to bother
725 * changing the color of the led */
726 return 0;
727
728 return au8522_led_ctrl(state, led);
729}
730
601static int au8522_read_snr(struct dvb_frontend *fe, u16 *snr) 731static int au8522_read_snr(struct dvb_frontend *fe, u16 *snr)
602{ 732{
603 struct au8522_state *state = fe->demodulator_priv; 733 struct au8522_state *state = fe->demodulator_priv;
@@ -621,6 +751,9 @@ static int au8522_read_snr(struct dvb_frontend *fe, u16 *snr)
621 au8522_readreg(state, 0x4311), 751 au8522_readreg(state, 0x4311),
622 snr); 752 snr);
623 753
754 if (state->config->led_cfg)
755 au8522_led_status(state, snr);
756
624 return ret; 757 return ret;
625} 758}
626 759