diff options
Diffstat (limited to 'drivers/media/dvb/frontends/au8522.c')
-rw-r--r-- | drivers/media/dvb/frontends/au8522.c | 133 |
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 | ||
45 | static int debug; | 47 | static int debug; |
@@ -538,11 +540,98 @@ static int au8522_init(struct dvb_frontend *fe) | |||
538 | return 0; | 540 | return 0; |
539 | } | 541 | } |
540 | 542 | ||
543 | static 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 | */ | ||
573 | static 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 | |||
541 | static int au8522_sleep(struct dvb_frontend *fe) | 627 | static 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 | ||
698 | static 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 | |||
601 | static int au8522_read_snr(struct dvb_frontend *fe, u16 *snr) | 731 | static 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 | ||