forked from Minki/linux
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:
parent
641015ab2c
commit
adeeac3b79
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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;
|
||||
};
|
||||
|
@ -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");
|
||||
|
Loading…
Reference in New Issue
Block a user