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:
committed by
Mauro Carvalho Chehab
parent
641015ab2c
commit
adeeac3b79
@ -40,6 +40,8 @@ struct au8522_state {
|
|||||||
u32 current_frequency;
|
u32 current_frequency;
|
||||||
fe_modulation_t current_modulation;
|
fe_modulation_t current_modulation;
|
||||||
|
|
||||||
|
u32 fe_status;
|
||||||
|
unsigned int led_state;
|
||||||
};
|
};
|
||||||
|
|
||||||
static int debug;
|
static int debug;
|
||||||
@ -538,11 +540,98 @@ static int au8522_init(struct dvb_frontend *fe)
|
|||||||
return 0;
|
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)
|
static int au8522_sleep(struct dvb_frontend *fe)
|
||||||
{
|
{
|
||||||
struct au8522_state *state = fe->demodulator_priv;
|
struct au8522_state *state = fe->demodulator_priv;
|
||||||
dprintk("%s()\n", __func__);
|
dprintk("%s()\n", __func__);
|
||||||
|
|
||||||
|
/* turn off led */
|
||||||
|
au8522_led_ctrl(state, 0);
|
||||||
|
|
||||||
state->current_frequency = 0;
|
state->current_frequency = 0;
|
||||||
|
|
||||||
return 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;
|
*status |= FE_HAS_CARRIER | FE_HAS_SIGNAL;
|
||||||
break;
|
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);
|
dprintk("%s() status 0x%08x\n", __func__, *status);
|
||||||
|
|
||||||
return 0;
|
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)
|
static int au8522_read_snr(struct dvb_frontend *fe, u16 *snr)
|
||||||
{
|
{
|
||||||
struct au8522_state *state = fe->demodulator_priv;
|
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),
|
au8522_readreg(state, 0x4311),
|
||||||
snr);
|
snr);
|
||||||
|
|
||||||
|
if (state->config->led_cfg)
|
||||||
|
au8522_led_status(state, snr);
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -30,6 +30,21 @@ enum au8522_if_freq {
|
|||||||
AU8522_IF_3_25MHZ,
|
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 {
|
struct au8522_config {
|
||||||
/* the demodulator's i2c address */
|
/* the demodulator's i2c address */
|
||||||
u8 demod_address;
|
u8 demod_address;
|
||||||
@ -39,6 +54,8 @@ struct au8522_config {
|
|||||||
#define AU8522_DEMODLOCKING 1
|
#define AU8522_DEMODLOCKING 1
|
||||||
u8 status_mode;
|
u8 status_mode;
|
||||||
|
|
||||||
|
struct au8522_led_config *led_cfg;
|
||||||
|
|
||||||
enum au8522_if_freq vsb_if;
|
enum au8522_if_freq vsb_if;
|
||||||
enum au8522_if_freq qam_if;
|
enum au8522_if_freq qam_if;
|
||||||
};
|
};
|
||||||
|
@ -36,11 +36,39 @@ DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr);
|
|||||||
#define _AU0828_BULKPIPE 0x83
|
#define _AU0828_BULKPIPE 0x83
|
||||||
#define _BULKPIPESIZE 0xe522
|
#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 = {
|
static struct au8522_config hauppauge_hvr950q_config = {
|
||||||
.demod_address = 0x8e >> 1,
|
.demod_address = 0x8e >> 1,
|
||||||
.status_mode = AU8522_DEMODLOCKING,
|
.status_mode = AU8522_DEMODLOCKING,
|
||||||
.qam_if = AU8522_IF_6MHZ,
|
.qam_if = AU8522_IF_6MHZ,
|
||||||
.vsb_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 = {
|
static struct au8522_config hauppauge_woodbury_config = {
|
||||||
@ -352,7 +380,6 @@ int au0828_dvb_register(struct au0828_dev *dev)
|
|||||||
switch (dev->board) {
|
switch (dev->board) {
|
||||||
case AU0828_BOARD_HAUPPAUGE_HVR850:
|
case AU0828_BOARD_HAUPPAUGE_HVR850:
|
||||||
case AU0828_BOARD_HAUPPAUGE_HVR950Q:
|
case AU0828_BOARD_HAUPPAUGE_HVR950Q:
|
||||||
case AU0828_BOARD_DVICO_FUSIONHDTV7:
|
|
||||||
dvb->frontend = dvb_attach(au8522_attach,
|
dvb->frontend = dvb_attach(au8522_attach,
|
||||||
&hauppauge_hvr950q_config,
|
&hauppauge_hvr950q_config,
|
||||||
&dev->i2c_adap);
|
&dev->i2c_adap);
|
||||||
@ -378,6 +405,16 @@ int au0828_dvb_register(struct au0828_dev *dev)
|
|||||||
0x60, &dev->i2c_adap,
|
0x60, &dev->i2c_adap,
|
||||||
&hauppauge_woodbury_tunerconfig);
|
&hauppauge_woodbury_tunerconfig);
|
||||||
break;
|
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:
|
default:
|
||||||
printk(KERN_WARNING "The frontend of your DVB/ATSC card "
|
printk(KERN_WARNING "The frontend of your DVB/ATSC card "
|
||||||
"isn't supported yet\n");
|
"isn't supported yet\n");
|
||||||
|
Reference in New Issue
Block a user