V4L/DVB (9149): hvr950q: led feedback based on snr

Signed-off-by: Michael Krufky <mkrufky@linuxtv.org>
Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com>
This commit is contained in:
Michael Krufky 2008-04-05 20:55:14 -03:00 committed by Mauro Carvalho Chehab
parent 641015ab2c
commit adeeac3b79
3 changed files with 188 additions and 1 deletions

View file

@ -40,6 +40,8 @@ struct au8522_state {
u32 current_frequency;
fe_modulation_t current_modulation;
u32 fe_status;
unsigned int led_state;
};
static int debug;
@ -538,11 +540,98 @@ static int au8522_init(struct dvb_frontend *fe)
return 0;
}
static int au8522_led_gpio_enable(struct au8522_state *state, int onoff)
{
struct au8522_led_config *led_config = state->config->led_cfg;
u8 val;
/* bail out if we cant control an LED */
if (!led_config || !led_config->gpio_output ||
!led_config->gpio_output_enable || !led_config->gpio_output_disable)
return 0;
val = au8522_readreg(state, 0x4000 |
(led_config->gpio_output & ~0xc000));
if (onoff) {
/* enable GPIO output */
val &= ~((led_config->gpio_output_enable >> 8) & 0xff);
val |= (led_config->gpio_output_enable & 0xff);
} else {
/* disable GPIO output */
val &= ~((led_config->gpio_output_disable >> 8) & 0xff);
val |= (led_config->gpio_output_disable & 0xff);
}
return au8522_writereg(state, 0x8000 |
(led_config->gpio_output & ~0xc000), val);
}
/* led = 0 | off
* led = 1 | signal ok
* led = 2 | signal strong
* led < 0 | only light led if leds are currently off
*/
static int au8522_led_ctrl(struct au8522_state *state, int led)
{
struct au8522_led_config *led_config = state->config->led_cfg;
int i, ret = 0;
/* bail out if we cant control an LED */
if (!led_config || !led_config->gpio_leds ||
!led_config->num_led_states || !led_config->led_states)
return 0;
if (led < 0) {
/* if LED is already lit, then leave it as-is */
if (state->led_state)
return 0;
else
led *= -1;
}
/* toggle LED if changing state */
if (state->led_state != led) {
u8 val;
dprintk("%s: %d\n", __func__, led);
au8522_led_gpio_enable(state, 1);
val = au8522_readreg(state, 0x4000 |
(led_config->gpio_leds & ~0xc000));
/* start with all leds off */
for (i = 0; i < led_config->num_led_states; i++)
val &= ~led_config->led_states[i];
/* set selected LED state */
if (led < led_config->num_led_states)
val |= led_config->led_states[led];
else if (led_config->num_led_states)
val |=
led_config->led_states[led_config->num_led_states - 1];
ret = au8522_writereg(state, 0x8000 |
(led_config->gpio_leds & ~0xc000), val);
if (ret < 0)
return ret;
state->led_state = led;
if (led == 0)
au8522_led_gpio_enable(state, 0);
}
return 0;
}
static int au8522_sleep(struct dvb_frontend *fe)
{
struct au8522_state *state = fe->demodulator_priv;
dprintk("%s()\n", __func__);
/* turn off led */
au8522_led_ctrl(state, 0);
state->current_frequency = 0;
return 0;
@ -592,12 +681,53 @@ static int au8522_read_status(struct dvb_frontend *fe, fe_status_t *status)
*status |= FE_HAS_CARRIER | FE_HAS_SIGNAL;
break;
}
state->fe_status = *status;
if (*status & FE_HAS_LOCK)
/* turn on LED, if it isn't on already */
au8522_led_ctrl(state, -1);
else
/* turn off LED */
au8522_led_ctrl(state, 0);
dprintk("%s() status 0x%08x\n", __func__, *status);
return 0;
}
static int au8522_led_status(struct au8522_state *state, const u16 *snr)
{
struct au8522_led_config *led_config = state->config->led_cfg;
int led;
u16 strong;
/* bail out if we cant control an LED */
if (!led_config)
return 0;
if (0 == (state->fe_status & FE_HAS_LOCK))
return au8522_led_ctrl(state, 0);
else if (state->current_modulation == QAM_256)
strong = led_config->qam256_strong;
else if (state->current_modulation == QAM_64)
strong = led_config->qam64_strong;
else /* (state->current_modulation == VSB_8) */
strong = led_config->vsb8_strong;
if (*snr >= strong)
led = 2;
else
led = 1;
if ((state->led_state) &&
(((strong < *snr) ? (*snr - strong) : (strong - *snr)) <= 10))
/* snr didn't change enough to bother
* changing the color of the led */
return 0;
return au8522_led_ctrl(state, led);
}
static int au8522_read_snr(struct dvb_frontend *fe, u16 *snr)
{
struct au8522_state *state = fe->demodulator_priv;
@ -621,6 +751,9 @@ static int au8522_read_snr(struct dvb_frontend *fe, u16 *snr)
au8522_readreg(state, 0x4311),
snr);
if (state->config->led_cfg)
au8522_led_status(state, snr);
return ret;
}

View file

@ -30,6 +30,21 @@ enum au8522_if_freq {
AU8522_IF_3_25MHZ,
};
struct au8522_led_config {
u16 vsb8_strong;
u16 qam64_strong;
u16 qam256_strong;
u16 gpio_output;
/* unset hi bits, set low bits */
u16 gpio_output_enable;
u16 gpio_output_disable;
u16 gpio_leds;
u8 *led_states;
unsigned int num_led_states;
};
struct au8522_config {
/* the demodulator's i2c address */
u8 demod_address;
@ -39,6 +54,8 @@ struct au8522_config {
#define AU8522_DEMODLOCKING 1
u8 status_mode;
struct au8522_led_config *led_cfg;
enum au8522_if_freq vsb_if;
enum au8522_if_freq qam_if;
};

View file

@ -36,11 +36,39 @@ DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr);
#define _AU0828_BULKPIPE 0x83
#define _BULKPIPESIZE 0xe522
static u8 hauppauge_hvr950q_led_states[] = {
0x00, /* off */
0x02, /* yellow */
0x04, /* green */
};
static struct au8522_led_config hauppauge_hvr950q_led_cfg = {
.gpio_output = 0x00e0,
.gpio_output_enable = 0x6006,
.gpio_output_disable = 0x0660,
.gpio_leds = 0x00e2,
.led_states = hauppauge_hvr950q_led_states,
.num_led_states = sizeof(hauppauge_hvr950q_led_states),
.vsb8_strong = 20 /* dB */ * 10,
.qam64_strong = 25 /* dB */ * 10,
.qam256_strong = 32 /* dB */ * 10,
};
static struct au8522_config hauppauge_hvr950q_config = {
.demod_address = 0x8e >> 1,
.status_mode = AU8522_DEMODLOCKING,
.qam_if = AU8522_IF_6MHZ,
.vsb_if = AU8522_IF_6MHZ,
.led_cfg = &hauppauge_hvr950q_led_cfg,
};
static struct au8522_config fusionhdtv7usb_config = {
.demod_address = 0x8e >> 1,
.status_mode = AU8522_DEMODLOCKING,
.qam_if = AU8522_IF_6MHZ,
.vsb_if = AU8522_IF_6MHZ,
};
static struct au8522_config hauppauge_woodbury_config = {
@ -352,7 +380,6 @@ int au0828_dvb_register(struct au0828_dev *dev)
switch (dev->board) {
case AU0828_BOARD_HAUPPAUGE_HVR850:
case AU0828_BOARD_HAUPPAUGE_HVR950Q:
case AU0828_BOARD_DVICO_FUSIONHDTV7:
dvb->frontend = dvb_attach(au8522_attach,
&hauppauge_hvr950q_config,
&dev->i2c_adap);
@ -378,6 +405,16 @@ int au0828_dvb_register(struct au0828_dev *dev)
0x60, &dev->i2c_adap,
&hauppauge_woodbury_tunerconfig);
break;
case AU0828_BOARD_DVICO_FUSIONHDTV7:
dvb->frontend = dvb_attach(au8522_attach,
&fusionhdtv7usb_config,
&dev->i2c_adap);
if (dvb->frontend != NULL) {
dvb_attach(xc5000_attach, dvb->frontend,
&dev->i2c_adap,
&hauppauge_hvr950q_tunerconfig);
}
break;
default:
printk(KERN_WARNING "The frontend of your DVB/ATSC card "
"isn't supported yet\n");