Skip to content

Commit

Permalink
V4L/DVB (9149): hvr950q: led feedback based on snr
Browse files Browse the repository at this point in the history
Signed-off-by: Michael Krufky <mkrufky@linuxtv.org>
Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com>
  • Loading branch information
Michael Krufky authored and Mauro Carvalho Chehab committed Oct 13, 2008
1 parent 641015a commit adeeac3
Show file tree
Hide file tree
Showing 3 changed files with 188 additions and 1 deletion.
133 changes: 133 additions & 0 deletions drivers/media/dvb/frontends/au8522.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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;
Expand All @@ -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;
}

Expand Down
17 changes: 17 additions & 0 deletions drivers/media/dvb/frontends/au8522.h
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -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;
};
Expand Down
39 changes: 38 additions & 1 deletion drivers/media/video/au0828/au0828-dvb.c
Original file line number Diff line number Diff line change
Expand Up @@ -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 = {
Expand Down Expand Up @@ -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);
Expand All @@ -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");
Expand Down

0 comments on commit adeeac3

Please sign in to comment.