diff options
Diffstat (limited to 'linux/drivers/media/dvb/frontends/cx24116.c')
-rw-r--r-- | linux/drivers/media/dvb/frontends/cx24116.c | 177 |
1 files changed, 129 insertions, 48 deletions
diff --git a/linux/drivers/media/dvb/frontends/cx24116.c b/linux/drivers/media/dvb/frontends/cx24116.c index 163190d54..3c58b9f57 100644 --- a/linux/drivers/media/dvb/frontends/cx24116.c +++ b/linux/drivers/media/dvb/frontends/cx24116.c @@ -57,8 +57,9 @@ static int debug = 0; #define CX24116_REG_RESET (0x20) /* reset status > 0 */ #define CX24116_REG_SIGNAL (0x9e) /* signal low */ #define CX24116_REG_SSTATUS (0x9d) /* signal high / status */ +#define CX24116_REG_QUALITY8 (0xa3) #define CX24116_REG_QSTATUS (0xbc) -#define CX24116_REG_QUALITY (0xd5) +#define CX24116_REG_QUALITY0 (0xd5) #define CX24116_REG_BER0 (0xc9) #define CX24116_REG_BER8 (0xc8) #define CX24116_REG_BER16 (0xc7) @@ -84,7 +85,8 @@ static int debug = 0; #define CX24116_ROLLOFF_035 (0x02) /* pilot bit */ -#define CX24116_PILOT (0x40) +#define CX24116_PILOT_OFF (0x00) +#define CX24116_PILOT_ON (0x40) /* signal status */ #define CX24116_HAS_SIGNAL (0x01) @@ -115,6 +117,9 @@ static int debug = 0; /* DiSEqC tone burst */ static int toneburst = 1; +/* SNR measurements */ +static int esno_snr = 0; + enum cmds { CMD_SET_VCO = 0x10, @@ -148,6 +153,7 @@ struct cx24116_tuning u8 fec_val; u8 fec_mask; u8 inversion_val; + u8 pilot_val; u8 rolloff_val; }; @@ -342,6 +348,7 @@ static int cx24116_set_inversion(struct cx24116_state* state, fe_spectral_invers * a scheme are support. Especially, no auto detect when in S2 mode. */ struct cx24116_modfec { + fe_delivery_system_t delivery_system; fe_modulation_t modulation; fe_code_rate_t fec; u8 mask; /* In DVBS mode this is used to autodetect */ @@ -350,32 +357,32 @@ struct cx24116_modfec { /* QPSK. For unknown rates we set hardware to auto detect 0xfe 0x30 */ /*mod fec mask val */ - { QPSK, FEC_NONE, 0xfe, 0x30 }, - { QPSK, FEC_1_2, 0x02, 0x2e }, /* 00000010 00101110 */ - { QPSK, FEC_2_3, 0x04, 0x2f }, /* 00000100 00101111 */ - { QPSK, FEC_3_4, 0x08, 0x30 }, /* 00001000 00110000 */ - { QPSK, FEC_4_5, 0xfe, 0x30 }, /* 000?0000 ? */ - { QPSK, FEC_5_6, 0x20, 0x31 }, /* 00100000 00110001 */ - { QPSK, FEC_6_7, 0xfe, 0x30 }, /* 0?000000 ? */ - { QPSK, FEC_7_8, 0x80, 0x32 }, /* 10000000 00110010 */ - { QPSK, FEC_8_9, 0xfe, 0x30 }, /* 0000000? ? */ - { QPSK, FEC_AUTO, 0xfe, 0x30 }, + { SYS_DVBS, QPSK, FEC_NONE, 0xfe, 0x30 }, + { SYS_DVBS, QPSK, FEC_1_2, 0x02, 0x2e }, /* 00000010 00101110 */ + { SYS_DVBS, QPSK, FEC_2_3, 0x04, 0x2f }, /* 00000100 00101111 */ + { SYS_DVBS, QPSK, FEC_3_4, 0x08, 0x30 }, /* 00001000 00110000 */ + { SYS_DVBS, QPSK, FEC_4_5, 0xfe, 0x30 }, /* 000?0000 ? */ + { SYS_DVBS, QPSK, FEC_5_6, 0x20, 0x31 }, /* 00100000 00110001 */ + { SYS_DVBS, QPSK, FEC_6_7, 0xfe, 0x30 }, /* 0?000000 ? */ + { SYS_DVBS, QPSK, FEC_7_8, 0x80, 0x32 }, /* 10000000 00110010 */ + { SYS_DVBS, QPSK, FEC_8_9, 0xfe, 0x30 }, /* 0000000? ? */ + { SYS_DVBS, QPSK, FEC_AUTO, 0xfe, 0x30 }, /* NBC-QPSK */ - { NBC_QPSK, FEC_1_2, 0x00, 0x04 }, - { NBC_QPSK, FEC_3_5, 0x00, 0x05 }, - { NBC_QPSK, FEC_2_3, 0x00, 0x06 }, - { NBC_QPSK, FEC_3_4, 0x00, 0x07 }, - { NBC_QPSK, FEC_4_5, 0x00, 0x08 }, - { NBC_QPSK, FEC_5_6, 0x00, 0x09 }, - { NBC_QPSK, FEC_8_9, 0x00, 0x0a }, - { NBC_QPSK, FEC_9_10, 0x00, 0x0b }, + { SYS_DVBS2, QPSK, FEC_1_2, 0x00, 0x04 }, + { SYS_DVBS2, QPSK, FEC_3_5, 0x00, 0x05 }, + { SYS_DVBS2, QPSK, FEC_2_3, 0x00, 0x06 }, + { SYS_DVBS2, QPSK, FEC_3_4, 0x00, 0x07 }, + { SYS_DVBS2, QPSK, FEC_4_5, 0x00, 0x08 }, + { SYS_DVBS2, QPSK, FEC_5_6, 0x00, 0x09 }, + { SYS_DVBS2, QPSK, FEC_8_9, 0x00, 0x0a }, + { SYS_DVBS2, QPSK, FEC_9_10, 0x00, 0x0b }, /* 8PSK */ - { _8PSK, FEC_3_5, 0x00, 0x0c }, - { _8PSK, FEC_2_3, 0x00, 0x0d }, - { _8PSK, FEC_3_4, 0x00, 0x0e }, - { _8PSK, FEC_5_6, 0x00, 0x0f }, - { _8PSK, FEC_8_9, 0x00, 0x10 }, - { _8PSK, FEC_9_10, 0x00, 0x11 }, + { SYS_DVBS2, PSK_8, FEC_3_5, 0x00, 0x0c }, + { SYS_DVBS2, PSK_8, FEC_2_3, 0x00, 0x0d }, + { SYS_DVBS2, PSK_8, FEC_3_4, 0x00, 0x0e }, + { SYS_DVBS2, PSK_8, FEC_5_6, 0x00, 0x0f }, + { SYS_DVBS2, PSK_8, FEC_8_9, 0x00, 0x10 }, + { SYS_DVBS2, PSK_8, FEC_9_10, 0x00, 0x11 }, /* * `val' can be found in the FECSTATUS register when tuning. * FECSTATUS will give the actual FEC in use if tuning was successful. @@ -700,7 +707,7 @@ static int cx24116_read_signal_strength(struct dvb_frontend* fe, u16* signal_str } /* SNR (0..100)% = (sig & 0xf0) * 10 + (sig & 0x0f) * 10 / 16 */ -static int cx24116_read_snr(struct dvb_frontend* fe, u16* snr) +static int cx24116_read_snr_pct(struct dvb_frontend* fe, u16* snr) { struct cx24116_state *state = fe->demodulator_priv; u8 snr_reading; @@ -711,7 +718,7 @@ static int cx24116_read_snr(struct dvb_frontend* fe, u16* snr) dprintk("%s()\n", __func__); - snr_reading = cx24116_readreg(state, CX24116_REG_QUALITY); + snr_reading = cx24116_readreg(state, CX24116_REG_QUALITY0); if(snr_reading >= 0xa0 /* 100% */) *snr = 0xffff; @@ -725,6 +732,32 @@ static int cx24116_read_snr(struct dvb_frontend* fe, u16* snr) return 0; } +/* The reelbox patches show the value in the registers represents + * ESNO, from 0->30db (values 0->300). We provide this value by + * default. + */ +static int cx24116_read_snr_esno(struct dvb_frontend* fe, u16* snr) +{ + struct cx24116_state *state = fe->demodulator_priv; + + dprintk("%s()\n", __func__); + + *snr = cx24116_readreg(state, CX24116_REG_QUALITY8) << 8 | + cx24116_readreg(state, CX24116_REG_QUALITY0); + + dprintk("%s: raw 0x%04x\n", __func__, *snr); + + return 0; +} + +static int cx24116_read_snr(struct dvb_frontend* fe, u16* snr) +{ + if (esno_snr == 1) + return cx24116_read_snr_esno(fe, snr); + else + return cx24116_read_snr_pct(fe, snr); +} + static int cx24116_read_ucblocks(struct dvb_frontend* fe, u32* ucblocks) { struct cx24116_state *state = fe->demodulator_priv; @@ -1138,25 +1171,62 @@ static int cx24116_set_frontend(struct dvb_frontend* fe, struct dvb_frontend_par struct dtv_frontend_properties *c = &fe->dtv_property_cache; struct cx24116_cmd cmd; fe_status_t tunerstat; - int i, status, ret, retune = 1; + int i, status, ret, retune; dprintk("%s()\n",__func__); - state->dnxt.modulation = c->modulation; - state->dnxt.frequency = c->frequency; - switch(c->delivery_system) { case SYS_DVBS: dprintk("%s: DVB-S delivery system selected\n",__func__); - state->dnxt.pilot = PILOT_OFF; + + /* Only QPSK is supported for DVB-S */ + if(c->modulation != QPSK) { + dprintk("%s: unsupported modulation selected (%d)\n", + __func__, c->modulation); + return -EOPNOTSUPP; + } + + /* Pilot doesn't exist in DVB-S, turn bit off */ + state->dnxt.pilot_val = CX24116_PILOT_OFF; + retune = 1; + + /* DVB-S only supports 0.35 */ + if(c->rolloff != ROLLOFF_35) { + dprintk("%s: unsupported rolloff selected (%d)\n", + __func__, c->rolloff); + return -EOPNOTSUPP; + } state->dnxt.rolloff_val = CX24116_ROLLOFF_035; - state->dnxt.rolloff = c->rolloff; break; + case SYS_DVBS2: dprintk("%s: DVB-S2 delivery system selected\n",__func__); - if(c->pilot == PILOT_AUTO) - retune++; - state->dnxt.pilot = c->pilot; + + /* + * NBC 8PSK/QPSK with DVB-S is supported for DVB-S2, + * but not hardware auto detection + */ + if(c->modulation != PSK_8 && c->modulation != QPSK) { + dprintk("%s: unsupported modulation selected (%d)\n", + __func__, c->modulation); + return -EOPNOTSUPP; + } + + switch(c->pilot) { + case PILOT_AUTO: /* Not supported but emulated */ + retune = 2; /* Fall-through */ + case PILOT_OFF: + state->dnxt.pilot_val = CX24116_PILOT_OFF; + break; + case PILOT_ON: + state->dnxt.pilot_val = CX24116_PILOT_ON; + break; + default: + dprintk("%s: unsupported pilot mode selected (%d)\n", + __func__, c->pilot); + return -EOPNOTSUPP; + } + switch(c->rolloff) { case ROLLOFF_20: state->dnxt.rolloff_val= CX24116_ROLLOFF_020; @@ -1167,20 +1237,28 @@ static int cx24116_set_frontend(struct dvb_frontend* fe, struct dvb_frontend_par case ROLLOFF_35: state->dnxt.rolloff_val= CX24116_ROLLOFF_035; break; - case ROLLOFF_AUTO: + case ROLLOFF_AUTO: /* Rolloff must be explicit */ + default: + dprintk("%s: unsupported rolloff selected (%d)\n", + __func__, c->rolloff); return -EOPNOTSUPP; } - state->dnxt.rolloff = c->rolloff; break; + default: dprintk("%s: unsupported delivery system selected (%d)\n", __func__, c->delivery_system); return -EOPNOTSUPP; } + state->dnxt.modulation = c->modulation; + state->dnxt.frequency = c->frequency; + state->dnxt.pilot = c->pilot; + state->dnxt.rolloff = c->rolloff; if ((ret = cx24116_set_inversion(state, c->inversion)) != 0) return ret; + /* FEC_NONE/AUTO for DVB-S2 is not supported and detected here */ if ((ret = cx24116_set_fec(state, c->modulation, c->fec_inner)) != 0) return ret; @@ -1190,10 +1268,13 @@ static int cx24116_set_frontend(struct dvb_frontend* fe, struct dvb_frontend_par /* discard the 'current' tuning parameters and prepare to tune */ cx24116_clone_params(fe); - dprintk("%s: retune = %d\n", __func__, retune); - dprintk("%s: rolloff = %d\n", __func__, state->dcur.rolloff); - dprintk("%s: pilot = %d\n", __func__, state->dcur.pilot); + dprintk("%s: modulation = %d\n", __func__, state->dcur.modulation); dprintk("%s: frequency = %d\n", __func__, state->dcur.frequency); + dprintk("%s: pilot = %d (val = 0x%02x)\n", __func__, + state->dcur.pilot, state->dcur.pilot_val); + dprintk("%s: retune = %d\n", __func__, retune); + dprintk("%s: rolloff = %d (val = 0x%02x)\n", __func__, + state->dcur.rolloff, state->dcur.rolloff_val); dprintk("%s: symbol_rate = %d\n", __func__, state->dcur.symbol_rate); dprintk("%s: FEC = %d (mask/val = 0x%02x/0x%02x)\n", __func__, state->dcur.fec, state->dcur.fec_mask, state->dcur.fec_val); @@ -1227,11 +1308,8 @@ static int cx24116_set_frontend(struct dvb_frontend* fe, struct dvb_frontend_par /* Automatic Inversion */ cmd.args[0x06] = state->dcur.inversion_val; - /* Modulation / FEC & Pilot Off */ - cmd.args[0x07] = state->dcur.fec_val; - - if (state->dcur.pilot == PILOT_ON) - cmd.args[0x07] |= CX24116_PILOT; + /* Modulation / FEC / Pilot */ + cmd.args[0x07] = state->dcur.fec_val | state->dcur.pilot_val; cmd.args[0x08] = CX24116_SEARCH_RANGE_KHZ >> 8; cmd.args[0x09] = CX24116_SEARCH_RANGE_KHZ & 0xff; @@ -1294,7 +1372,7 @@ static int cx24116_set_frontend(struct dvb_frontend* fe, struct dvb_frontend_par /* Toggle pilot bit when in auto-pilot */ if(state->dcur.pilot == PILOT_AUTO) - cmd.args[0x07] ^= CX24116_PILOT; + cmd.args[0x07] ^= CX24116_PILOT_ON; } while(--retune); @@ -1352,6 +1430,9 @@ MODULE_PARM_DESC(debug, "Activates frontend debugging (default:0)"); module_param(toneburst, int, 0644); MODULE_PARM_DESC(toneburst, "DiSEqC toneburst 0=OFF, 1=TONE CACHE, 2=MESSAGE CACHE (default:1)"); +module_param(esno_snr, int, 0644); +MODULE_PARM_DESC(debug, "SNR return units, 0=PERCENTAGE 0-100, 1=ESNO(db * 10) (default:0)"); + MODULE_DESCRIPTION("DVB Frontend module for Conexant cx24116/cx24118 hardware"); MODULE_AUTHOR("Steven Toth"); MODULE_LICENSE("GPL"); |