diff options
Diffstat (limited to 'drivers/media/dvb-frontends')
26 files changed, 1008 insertions, 316 deletions
diff --git a/drivers/media/dvb-frontends/Kconfig b/drivers/media/dvb-frontends/Kconfig index 5a134547e325..6c75418222e2 100644 --- a/drivers/media/dvb-frontends/Kconfig +++ b/drivers/media/dvb-frontends/Kconfig @@ -648,12 +648,15 @@ config DVB_MB86A20S A driver for Fujitsu mb86a20s ISDB-T/ISDB-Tsb demodulator. Say Y when you want to support this frontend. +comment "ISDB-S (satellite) & ISDB-T (terrestrial) frontends" + depends on DVB_CORE + config DVB_TC90522 tristate "Toshiba TC90522" depends on DVB_CORE && I2C default m if !MEDIA_SUBDRV_AUTOSELECT help - A Toshiba TC90522 2xISDB-T + 2xISDB-S demodulator. + Toshiba TC90522 2xISDB-S 8PSK + 2xISDB-T OFDM demodulator. Say Y when you want to support this frontend. comment "Digital terrestrial only tuners/PLL" diff --git a/drivers/media/dvb-frontends/af9033.c b/drivers/media/dvb-frontends/af9033.c index 63a89c1c59ff..82ce47bdf5dc 100644 --- a/drivers/media/dvb-frontends/af9033.c +++ b/drivers/media/dvb-frontends/af9033.c @@ -291,6 +291,12 @@ static int af9033_init(struct dvb_frontend *fe) if (clock_adc_lut[i].clock == dev->cfg.clock) break; } + if (i == ARRAY_SIZE(clock_adc_lut)) { + dev_err(&dev->client->dev, + "Couldn't find ADC config for clock=%d\n", + dev->cfg.clock); + goto err; + } adc_cw = af9033_div(dev, clock_adc_lut[i].adc, 1000000ul, 19ul); buf[0] = (adc_cw >> 0) & 0xff; @@ -580,7 +586,15 @@ static int af9033_set_frontend(struct dvb_frontend *fe) break; } } - ret = af9033_wr_regs(dev, 0x800001, + if (i == ARRAY_SIZE(coeff_lut)) { + dev_err(&dev->client->dev, + "Couldn't find LUT config for clock=%d\n", + dev->cfg.clock); + ret = -EINVAL; + goto err; + } + + ret = af9033_wr_regs(dev, 0x800001, coeff_lut[i].val, sizeof(coeff_lut[i].val)); } @@ -592,6 +606,13 @@ static int af9033_set_frontend(struct dvb_frontend *fe) if (clock_adc_lut[i].clock == dev->cfg.clock) break; } + if (i == ARRAY_SIZE(clock_adc_lut)) { + dev_err(&dev->client->dev, + "Couldn't find ADC clock for clock=%d\n", + dev->cfg.clock); + ret = -EINVAL; + goto err; + } adc_freq = clock_adc_lut[i].adc; /* get used IF frequency */ @@ -849,29 +870,97 @@ static int af9033_read_snr(struct dvb_frontend *fe, u16 *snr) { struct af9033_dev *dev = fe->demodulator_priv; struct dtv_frontend_properties *c = &dev->fe.dtv_property_cache; + int ret; + u8 u8tmp; /* use DVBv5 CNR */ - if (c->cnr.stat[0].scale == FE_SCALE_DECIBEL) - *snr = div_s64(c->cnr.stat[0].svalue, 100); /* 1000x => 10x */ - else + if (c->cnr.stat[0].scale == FE_SCALE_DECIBEL) { + /* Return 0.1 dB for AF9030 and 0-0xffff for IT9130. */ + if (dev->is_af9035) { + /* 1000x => 10x (0.1 dB) */ + *snr = div_s64(c->cnr.stat[0].svalue, 100); + } else { + /* 1000x => 1x (1 dB) */ + *snr = div_s64(c->cnr.stat[0].svalue, 1000); + + /* read current modulation */ + ret = af9033_rd_reg(dev, 0x80f903, &u8tmp); + if (ret) + goto err; + + /* scale value to 0x0000-0xffff */ + switch ((u8tmp >> 0) & 3) { + case 0: + *snr = *snr * 0xffff / 23; + break; + case 1: + *snr = *snr * 0xffff / 26; + break; + case 2: + *snr = *snr * 0xffff / 32; + break; + default: + goto err; + } + } + } else { *snr = 0; + } return 0; + +err: + dev_dbg(&dev->client->dev, "failed=%d\n", ret); + + return ret; } static int af9033_read_signal_strength(struct dvb_frontend *fe, u16 *strength) { struct af9033_dev *dev = fe->demodulator_priv; - int ret; - u8 strength2; + struct dtv_frontend_properties *c = &dev->fe.dtv_property_cache; + int ret, tmp, power_real; + u8 u8tmp, gain_offset, buf[7]; - /* read signal strength of 0-100 scale */ - ret = af9033_rd_reg(dev, 0x800048, &strength2); - if (ret < 0) - goto err; + if (dev->is_af9035) { + /* read signal strength of 0-100 scale */ + ret = af9033_rd_reg(dev, 0x800048, &u8tmp); + if (ret < 0) + goto err; + + /* scale value to 0x0000-0xffff */ + *strength = u8tmp * 0xffff / 100; + } else { + ret = af9033_rd_reg(dev, 0x8000f7, &u8tmp); + if (ret < 0) + goto err; + + ret = af9033_rd_regs(dev, 0x80f900, buf, 7); + if (ret < 0) + goto err; + + if (c->frequency <= 300000000) + gain_offset = 7; /* VHF */ + else + gain_offset = 4; /* UHF */ + + power_real = (u8tmp - 100 - gain_offset) - + power_reference[((buf[3] >> 0) & 3)][((buf[6] >> 0) & 7)]; + + if (power_real < -15) + tmp = 0; + else if ((power_real >= -15) && (power_real < 0)) + tmp = (2 * (power_real + 15)) / 3; + else if ((power_real >= 0) && (power_real < 20)) + tmp = 4 * power_real + 10; + else if ((power_real >= 20) && (power_real < 35)) + tmp = (2 * (power_real - 20)) / 3 + 90; + else + tmp = 100; - /* scale value to 0x0000-0xffff */ - *strength = strength2 * 0xffff / 100; + /* scale value to 0x0000-0xffff */ + *strength = tmp * 0xffff / 100; + } return 0; @@ -1011,6 +1100,33 @@ static void af9033_stat_work(struct work_struct *work) snr_val = (buf[2] << 16) | (buf[1] << 8) | (buf[0] << 0); + /* read superframe number */ + ret = af9033_rd_reg(dev, 0x80f78b, &u8tmp); + if (ret) + goto err; + + if (u8tmp) + snr_val /= u8tmp; + + /* read current transmission mode */ + ret = af9033_rd_reg(dev, 0x80f900, &u8tmp); + if (ret) + goto err; + + switch ((u8tmp >> 0) & 3) { + case 0: + snr_val *= 4; + break; + case 1: + snr_val *= 1; + break; + case 2: + snr_val *= 2; + break; + default: + goto err_schedule_delayed_work; + } + /* read current modulation */ ret = af9033_rd_reg(dev, 0x80f903, &u8tmp); if (ret) diff --git a/drivers/media/dvb-frontends/af9033_priv.h b/drivers/media/dvb-frontends/af9033_priv.h index c12c92cb5855..8e23275148ed 100644 --- a/drivers/media/dvb-frontends/af9033_priv.h +++ b/drivers/media/dvb-frontends/af9033_priv.h @@ -181,7 +181,10 @@ static const struct val_snr qam64_snr_lut[] = { { 0x05570d, 26 }, { 0x059feb, 27 }, { 0x05bf38, 28 }, - { 0xffffff, 29 }, + { 0x05f78f, 29 }, + { 0x0612c3, 30 }, + { 0x0626be, 31 }, + { 0xffffff, 32 }, }; static const struct reg_val ofsm_init[] = { @@ -2051,4 +2054,10 @@ static const struct reg_val tuner_init_it9135_62[] = { { 0x80fd8b, 0x00 }, }; +/* NorDig power reference table */ +static const int power_reference[][5] = { + {-93, -91, -90, -89, -88}, /* QPSK 1/2 ~ 7/8 */ + {-87, -85, -84, -83, -82}, /* 16QAM 1/2 ~ 7/8 */ + {-82, -80, -78, -77, -76}, /* 64QAM 1/2 ~ 7/8 */ +}; #endif /* AF9033_PRIV_H */ diff --git a/drivers/media/dvb-frontends/au8522_dig.c b/drivers/media/dvb-frontends/au8522_dig.c index a68974f6d708..5d06c99b0e97 100644 --- a/drivers/media/dvb-frontends/au8522_dig.c +++ b/drivers/media/dvb-frontends/au8522_dig.c @@ -29,6 +29,7 @@ #include "au8522_priv.h" static int debug; +static int zv_mode = 1; /* default to on */ #define dprintk(arg...)\ do { if (debug)\ @@ -469,6 +470,87 @@ static struct { { 0x8526, 0x01 }, }; +static struct { + u16 reg; + u16 data; +} QAM256_mod_tab_zv_mode[] = { + { 0x80a3, 0x09 }, + { 0x80a4, 0x00 }, + { 0x8081, 0xc4 }, + { 0x80a5, 0x40 }, + { 0x80b5, 0xfb }, + { 0x80b6, 0x8e }, + { 0x80b7, 0x39 }, + { 0x80aa, 0x77 }, + { 0x80ad, 0x77 }, + { 0x80a6, 0x67 }, + { 0x8262, 0x20 }, + { 0x821c, 0x30 }, + { 0x80b8, 0x3e }, + { 0x80b9, 0xf0 }, + { 0x80ba, 0x01 }, + { 0x80bb, 0x18 }, + { 0x80bc, 0x50 }, + { 0x80bd, 0x00 }, + { 0x80be, 0xea }, + { 0x80bf, 0xef }, + { 0x80c0, 0xfc }, + { 0x80c1, 0xbd }, + { 0x80c2, 0x1f }, + { 0x80c3, 0xfc }, + { 0x80c4, 0xdd }, + { 0x80c5, 0xaf }, + { 0x80c6, 0x00 }, + { 0x80c7, 0x38 }, + { 0x80c8, 0x30 }, + { 0x80c9, 0x05 }, + { 0x80ca, 0x4a }, + { 0x80cb, 0xd0 }, + { 0x80cc, 0x01 }, + { 0x80cd, 0xd9 }, + { 0x80ce, 0x6f }, + { 0x80cf, 0xf9 }, + { 0x80d0, 0x70 }, + { 0x80d1, 0xdf }, + { 0x80d2, 0xf7 }, + { 0x80d3, 0xc2 }, + { 0x80d4, 0xdf }, + { 0x80d5, 0x02 }, + { 0x80d6, 0x9a }, + { 0x80d7, 0xd0 }, + { 0x8250, 0x0d }, + { 0x8251, 0xcd }, + { 0x8252, 0xe0 }, + { 0x8253, 0x05 }, + { 0x8254, 0xa7 }, + { 0x8255, 0xff }, + { 0x8256, 0xed }, + { 0x8257, 0x5b }, + { 0x8258, 0xae }, + { 0x8259, 0xe6 }, + { 0x825a, 0x3d }, + { 0x825b, 0x0f }, + { 0x825c, 0x0d }, + { 0x825d, 0xea }, + { 0x825e, 0xf2 }, + { 0x825f, 0x51 }, + { 0x8260, 0xf5 }, + { 0x8261, 0x06 }, + { 0x821a, 0x01 }, + { 0x8546, 0x40 }, + { 0x8210, 0x26 }, + { 0x8211, 0xf6 }, + { 0x8212, 0x84 }, + { 0x8213, 0x02 }, + { 0x8502, 0x01 }, + { 0x8121, 0x04 }, + { 0x8122, 0x04 }, + { 0x852e, 0x10 }, + { 0x80a4, 0xca }, + { 0x80a7, 0x40 }, + { 0x8526, 0x01 }, +}; + static int au8522_enable_modulation(struct dvb_frontend *fe, fe_modulation_t m) { @@ -495,12 +577,23 @@ static int au8522_enable_modulation(struct dvb_frontend *fe, au8522_set_if(fe, state->config->qam_if); break; case QAM_256: - dprintk("%s() QAM 256\n", __func__); - for (i = 0; i < ARRAY_SIZE(QAM256_mod_tab); i++) - au8522_writereg(state, - QAM256_mod_tab[i].reg, - QAM256_mod_tab[i].data); - au8522_set_if(fe, state->config->qam_if); + if (zv_mode) { + dprintk("%s() QAM 256 (zv_mode)\n", __func__); + for (i = 0; i < ARRAY_SIZE(QAM256_mod_tab_zv_mode); i++) + au8522_writereg(state, + QAM256_mod_tab_zv_mode[i].reg, + QAM256_mod_tab_zv_mode[i].data); + au8522_set_if(fe, state->config->qam_if); + msleep(100); + au8522_writereg(state, 0x821a, 0x00); + } else { + dprintk("%s() QAM 256\n", __func__); + for (i = 0; i < ARRAY_SIZE(QAM256_mod_tab); i++) + au8522_writereg(state, + QAM256_mod_tab[i].reg, + QAM256_mod_tab[i].data); + au8522_set_if(fe, state->config->qam_if); + } break; default: dprintk("%s() Invalid modulation\n", __func__); @@ -537,7 +630,12 @@ static int au8522_set_frontend(struct dvb_frontend *fe) return ret; /* Allow the tuner to settle */ - msleep(100); + if (zv_mode) { + dprintk("%s() increase tuner settling time for zv_mode\n", + __func__); + msleep(250); + } else + msleep(100); au8522_enable_modulation(fe, c->modulation); @@ -823,6 +921,11 @@ static struct dvb_frontend_ops au8522_ops = { module_param(debug, int, 0644); MODULE_PARM_DESC(debug, "Enable verbose debug messages"); +module_param(zv_mode, int, 0644); +MODULE_PARM_DESC(zv_mode, "Turn on/off ZeeVee modulator compatability mode (default:on).\n" + "\t\ton - modified AU8522 QAM256 initialization.\n" + "\t\tProvides faster lock when using ZeeVee modulator based sources"); + MODULE_DESCRIPTION("Auvitek AU8522 QAM-B/ATSC Demodulator driver"); MODULE_AUTHOR("Steven Toth"); MODULE_LICENSE("GPL"); diff --git a/drivers/media/dvb-frontends/cx22700.c b/drivers/media/dvb-frontends/cx22700.c index 3d399d9a6343..86563260d0f2 100644 --- a/drivers/media/dvb-frontends/cx22700.c +++ b/drivers/media/dvb-frontends/cx22700.c @@ -169,6 +169,9 @@ static int cx22700_set_tps(struct cx22700_state *state, cx22700_writereg (state, 0x04, val); + if (p->code_rate_HP - FEC_1_2 >= sizeof(fec_tab) || + p->code_rate_LP - FEC_1_2 >= sizeof(fec_tab)) + return -EINVAL; val = fec_tab[p->code_rate_HP - FEC_1_2] << 3; val |= fec_tab[p->code_rate_LP - FEC_1_2]; diff --git a/drivers/media/dvb-frontends/cx24110.c b/drivers/media/dvb-frontends/cx24110.c index 95b981cd7115..7b510f2ae20f 100644 --- a/drivers/media/dvb-frontends/cx24110.c +++ b/drivers/media/dvb-frontends/cx24110.c @@ -177,47 +177,45 @@ static int cx24110_set_inversion (struct cx24110_state* state, fe_spectral_inver return 0; } -static int cx24110_set_fec (struct cx24110_state* state, fe_code_rate_t fec) +static int cx24110_set_fec(struct cx24110_state* state, fe_code_rate_t fec) { -/* fixme (low): error handling */ - - static const int rate[]={-1,1,2,3,5,7,-1}; - static const int g1[]={-1,0x01,0x02,0x05,0x15,0x45,-1}; - static const int g2[]={-1,0x01,0x03,0x06,0x1a,0x7a,-1}; + static const int rate[FEC_AUTO] = {-1, 1, 2, 3, 5, 7, -1}; + static const int g1[FEC_AUTO] = {-1, 0x01, 0x02, 0x05, 0x15, 0x45, -1}; + static const int g2[FEC_AUTO] = {-1, 0x01, 0x03, 0x06, 0x1a, 0x7a, -1}; /* Well, the AutoAcq engine of the cx24106 and 24110 automatically searches all enabled viterbi rates, and can handle non-standard rates as well. */ - if (fec>FEC_AUTO) - fec=FEC_AUTO; + if (fec > FEC_AUTO) + fec = FEC_AUTO; - if (fec==FEC_AUTO) { /* (re-)establish AutoAcq behaviour */ - cx24110_writereg(state,0x37,cx24110_readreg(state,0x37)&0xdf); + if (fec == FEC_AUTO) { /* (re-)establish AutoAcq behaviour */ + cx24110_writereg(state, 0x37, cx24110_readreg(state, 0x37) & 0xdf); /* clear AcqVitDis bit */ - cx24110_writereg(state,0x18,0xae); + cx24110_writereg(state, 0x18, 0xae); /* allow all DVB standard code rates */ - cx24110_writereg(state,0x05,(cx24110_readreg(state,0x05)&0xf0)|0x3); + cx24110_writereg(state, 0x05, (cx24110_readreg(state, 0x05) & 0xf0) | 0x3); /* set nominal Viterbi rate 3/4 */ - cx24110_writereg(state,0x22,(cx24110_readreg(state,0x22)&0xf0)|0x3); + cx24110_writereg(state, 0x22, (cx24110_readreg(state, 0x22) & 0xf0) | 0x3); /* set current Viterbi rate 3/4 */ - cx24110_writereg(state,0x1a,0x05); cx24110_writereg(state,0x1b,0x06); + cx24110_writereg(state, 0x1a, 0x05); + cx24110_writereg(state, 0x1b, 0x06); /* set the puncture registers for code rate 3/4 */ return 0; } else { - cx24110_writereg(state,0x37,cx24110_readreg(state,0x37)|0x20); + cx24110_writereg(state, 0x37, cx24110_readreg(state, 0x37) | 0x20); /* set AcqVitDis bit */ - if(rate[fec]>0) { - cx24110_writereg(state,0x05,(cx24110_readreg(state,0x05)&0xf0)|rate[fec]); - /* set nominal Viterbi rate */ - cx24110_writereg(state,0x22,(cx24110_readreg(state,0x22)&0xf0)|rate[fec]); - /* set current Viterbi rate */ - cx24110_writereg(state,0x1a,g1[fec]); - cx24110_writereg(state,0x1b,g2[fec]); - /* not sure if this is the right way: I always used AutoAcq mode */ - } else - return -EOPNOTSUPP; -/* fixme (low): which is the correct return code? */ + if (rate[fec] < 0) + return -EINVAL; + + cx24110_writereg(state, 0x05, (cx24110_readreg(state, 0x05) & 0xf0) | rate[fec]); + /* set nominal Viterbi rate */ + cx24110_writereg(state, 0x22, (cx24110_readreg(state, 0x22) & 0xf0) | rate[fec]); + /* set current Viterbi rate */ + cx24110_writereg(state, 0x1a, g1[fec]); + cx24110_writereg(state, 0x1b, g2[fec]); + /* not sure if this is the right way: I always used AutoAcq mode */ } return 0; } diff --git a/drivers/media/dvb-frontends/cx24117.c b/drivers/media/dvb-frontends/cx24117.c index a6c3c9e2e897..acb965ce0358 100644 --- a/drivers/media/dvb-frontends/cx24117.c +++ b/drivers/media/dvb-frontends/cx24117.c @@ -459,7 +459,7 @@ static int cx24117_firmware_ondemand(struct dvb_frontend *fe) if (state->priv->skip_fw_load) return 0; - /* check if firmware if already running */ + /* check if firmware is already running */ if (cx24117_readreg(state, 0xeb) != 0xa) { /* Load firmware */ /* request the firmware, this will block until loaded */ diff --git a/drivers/media/dvb-frontends/dib7000p.c b/drivers/media/dvb-frontends/dib7000p.c index 589134e95175..c505d696f92d 100644 --- a/drivers/media/dvb-frontends/dib7000p.c +++ b/drivers/media/dvb-frontends/dib7000p.c @@ -1780,7 +1780,7 @@ static u32 interpolate_value(u32 value, struct linear_segments *segments, } /* FIXME: may require changes - this one was borrowed from dib8000 */ -static u32 dib7000p_get_time_us(struct dvb_frontend *demod, int layer) +static u32 dib7000p_get_time_us(struct dvb_frontend *demod) { struct dtv_frontend_properties *c = &demod->dtv_property_cache; u64 time_us, tmp64; @@ -1881,7 +1881,6 @@ static int dib7000p_get_stats(struct dvb_frontend *demod, fe_status_t stat) { struct dib7000p_state *state = demod->demodulator_priv; struct dtv_frontend_properties *c = &demod->dtv_property_cache; - int i; int show_per_stats = 0; u32 time_us = 0, val, snr; u64 blocks, ucb; @@ -1935,7 +1934,7 @@ static int dib7000p_get_stats(struct dvb_frontend *demod, fe_status_t stat) /* Estimate the number of packets based on bitrate */ if (!time_us) - time_us = dib7000p_get_time_us(demod, -1); + time_us = dib7000p_get_time_us(demod); if (time_us) { blocks = 1250000ULL * 1000000ULL; @@ -1949,7 +1948,7 @@ static int dib7000p_get_stats(struct dvb_frontend *demod, fe_status_t stat) /* Get post-BER measures */ if (time_after(jiffies, state->ber_jiffies_stats)) { - time_us = dib7000p_get_time_us(demod, -1); + time_us = dib7000p_get_time_us(demod); state->ber_jiffies_stats = jiffies + msecs_to_jiffies((time_us + 500) / 1000); dprintk("Next all layers stats available in %u us.", time_us); @@ -1969,7 +1968,7 @@ static int dib7000p_get_stats(struct dvb_frontend *demod, fe_status_t stat) c->block_error.stat[0].scale = FE_SCALE_COUNTER; c->block_error.stat[0].uvalue += val; - time_us = dib7000p_get_time_us(demod, i); + time_us = dib7000p_get_time_us(demod); if (time_us) { blocks = 1250000ULL * 1000000ULL; do_div(blocks, time_us * 8 * 204); diff --git a/drivers/media/dvb-frontends/drx39xyj/drxj.c b/drivers/media/dvb-frontends/drx39xyj/drxj.c index 5ec221ffdfca..2bfa7a435974 100644 --- a/drivers/media/dvb-frontends/drx39xyj/drxj.c +++ b/drivers/media/dvb-frontends/drx39xyj/drxj.c @@ -12255,8 +12255,7 @@ static void drx39xxj_release(struct dvb_frontend *fe) kfree(demod->my_ext_attr); kfree(demod->my_common_attr); kfree(demod->my_i2c_dev_addr); - if (demod->firmware) - release_firmware(demod->firmware); + release_firmware(demod->firmware); kfree(demod); kfree(state); } diff --git a/drivers/media/dvb-frontends/drxk_hard.c b/drivers/media/dvb-frontends/drxk_hard.c index 672195147d01..d46cf5f7cd2e 100644 --- a/drivers/media/dvb-frontends/drxk_hard.c +++ b/drivers/media/dvb-frontends/drxk_hard.c @@ -166,9 +166,9 @@ static unsigned int debug; module_param(debug, int, 0644); MODULE_PARM_DESC(debug, "enable debug messages"); -#define dprintk(level, fmt, arg...) do { \ -if (debug >= level) \ - pr_debug(fmt, ##arg); \ +#define dprintk(level, fmt, arg...) do { \ +if (debug >= level) \ + printk(KERN_DEBUG KBUILD_MODNAME ": %s " fmt, __func__, ##arg); \ } while (0) @@ -6310,8 +6310,7 @@ static void drxk_release(struct dvb_frontend *fe) struct drxk_state *state = fe->demodulator_priv; dprintk(1, "\n"); - if (state->fw) - release_firmware(state->fw); + release_firmware(state->fw); kfree(state); } diff --git a/drivers/media/dvb-frontends/ds3000.c b/drivers/media/dvb-frontends/ds3000.c index 335daeff91b9..9d0d0347758f 100644 --- a/drivers/media/dvb-frontends/ds3000.c +++ b/drivers/media/dvb-frontends/ds3000.c @@ -864,6 +864,13 @@ struct dvb_frontend *ds3000_attach(const struct ds3000_config *config, memcpy(&state->frontend.ops, &ds3000_ops, sizeof(struct dvb_frontend_ops)); state->frontend.demodulator_priv = state; + + /* + * Some devices like T480 starts with voltage on. Be sure + * to turn voltage off during init, as this can otherwise + * interfere with Unicable SCR systems. + */ + ds3000_set_voltage(&state->frontend, SEC_VOLTAGE_OFF); return &state->frontend; error3: diff --git a/drivers/media/dvb-frontends/m88ds3103.c b/drivers/media/dvb-frontends/m88ds3103.c index 81657e94c5a4..ba4ee0b48834 100644 --- a/drivers/media/dvb-frontends/m88ds3103.c +++ b/drivers/media/dvb-frontends/m88ds3103.c @@ -1,5 +1,5 @@ /* - * Montage M88DS3103 demodulator driver + * Montage M88DS3103/M88RS6000 demodulator driver * * Copyright (C) 2013 Antti Palosaari <crope@iki.fi> * @@ -162,7 +162,7 @@ static int m88ds3103_wr_reg_val_tab(struct m88ds3103_priv *priv, dev_dbg(&priv->i2c->dev, "%s: tab_len=%d\n", __func__, tab_len); - if (tab_len > 83) { + if (tab_len > 86) { ret = -EINVAL; goto err; } @@ -245,9 +245,9 @@ static int m88ds3103_set_frontend(struct dvb_frontend *fe) struct dtv_frontend_properties *c = &fe->dtv_property_cache; int ret, len; const struct m88ds3103_reg_val *init; - u8 u8tmp, u8tmp1, u8tmp2; - u8 buf[2]; - u16 u16tmp, divide_ratio; + u8 u8tmp, u8tmp1 = 0, u8tmp2 = 0; /* silence compiler warning */ + u8 buf[3]; + u16 u16tmp, divide_ratio = 0; u32 tuner_frequency, target_mclk; s32 s32tmp; @@ -262,6 +262,22 @@ static int m88ds3103_set_frontend(struct dvb_frontend *fe) goto err; } + /* reset */ + ret = m88ds3103_wr_reg(priv, 0x07, 0x80); + if (ret) + goto err; + + ret = m88ds3103_wr_reg(priv, 0x07, 0x00); + if (ret) + goto err; + + /* Disable demod clock path */ + if (priv->chip_id == M88RS6000_CHIP_ID) { + ret = m88ds3103_wr_reg(priv, 0x06, 0xe0); + if (ret) + goto err; + } + /* program tuner */ if (fe->ops.tuner_ops.set_params) { ret = fe->ops.tuner_ops.set_params(fe); @@ -282,49 +298,44 @@ static int m88ds3103_set_frontend(struct dvb_frontend *fe) tuner_frequency = c->frequency; } - /* reset */ - ret = m88ds3103_wr_reg(priv, 0x07, 0x80); - if (ret) - goto err; - - ret = m88ds3103_wr_reg(priv, 0x07, 0x00); - if (ret) - goto err; - - ret = m88ds3103_wr_reg(priv, 0xb2, 0x01); - if (ret) - goto err; + /* select M88RS6000 demod main mclk and ts mclk from tuner die. */ + if (priv->chip_id == M88RS6000_CHIP_ID) { + if (c->symbol_rate > 45010000) + priv->mclk_khz = 110250; + else + priv->mclk_khz = 96000; - ret = m88ds3103_wr_reg(priv, 0x00, 0x01); - if (ret) - goto err; + if (c->delivery_system == SYS_DVBS) + target_mclk = 96000; + else + target_mclk = 144000; - switch (c->delivery_system) { - case SYS_DVBS: - len = ARRAY_SIZE(m88ds3103_dvbs_init_reg_vals); - init = m88ds3103_dvbs_init_reg_vals; - target_mclk = 96000; - break; - case SYS_DVBS2: - len = ARRAY_SIZE(m88ds3103_dvbs2_init_reg_vals); - init = m88ds3103_dvbs2_init_reg_vals; + /* Enable demod clock path */ + ret = m88ds3103_wr_reg(priv, 0x06, 0x00); + if (ret) + goto err; + usleep_range(10000, 20000); + } else { + /* set M88DS3103 mclk and ts mclk. */ + priv->mclk_khz = 96000; switch (priv->cfg->ts_mode) { case M88DS3103_TS_SERIAL: case M88DS3103_TS_SERIAL_D7: - if (c->symbol_rate < 18000000) - target_mclk = 96000; - else - target_mclk = 144000; + target_mclk = priv->cfg->ts_clk; break; case M88DS3103_TS_PARALLEL: case M88DS3103_TS_CI: - if (c->symbol_rate < 18000000) + if (c->delivery_system == SYS_DVBS) target_mclk = 96000; - else if (c->symbol_rate < 28000000) - target_mclk = 144000; - else - target_mclk = 192000; + else { + if (c->symbol_rate < 18000000) + target_mclk = 96000; + else if (c->symbol_rate < 28000000) + target_mclk = 144000; + else + target_mclk = 192000; + } break; default: dev_dbg(&priv->i2c->dev, "%s: invalid ts_mode\n", @@ -332,6 +343,55 @@ static int m88ds3103_set_frontend(struct dvb_frontend *fe) ret = -EINVAL; goto err; } + + switch (target_mclk) { + case 96000: + u8tmp1 = 0x02; /* 0b10 */ + u8tmp2 = 0x01; /* 0b01 */ + break; + case 144000: + u8tmp1 = 0x00; /* 0b00 */ + u8tmp2 = 0x01; /* 0b01 */ + break; + case 192000: + u8tmp1 = 0x03; /* 0b11 */ + u8tmp2 = 0x00; /* 0b00 */ + break; + } + ret = m88ds3103_wr_reg_mask(priv, 0x22, u8tmp1 << 6, 0xc0); + if (ret) + goto err; + ret = m88ds3103_wr_reg_mask(priv, 0x24, u8tmp2 << 6, 0xc0); + if (ret) + goto err; + } + + ret = m88ds3103_wr_reg(priv, 0xb2, 0x01); + if (ret) + goto err; + + ret = m88ds3103_wr_reg(priv, 0x00, 0x01); + if (ret) + goto err; + + switch (c->delivery_system) { + case SYS_DVBS: + if (priv->chip_id == M88RS6000_CHIP_ID) { + len = ARRAY_SIZE(m88rs6000_dvbs_init_reg_vals); + init = m88rs6000_dvbs_init_reg_vals; + } else { + len = ARRAY_SIZE(m88ds3103_dvbs_init_reg_vals); + init = m88ds3103_dvbs_init_reg_vals; + } + break; + case SYS_DVBS2: + if (priv->chip_id == M88RS6000_CHIP_ID) { + len = ARRAY_SIZE(m88rs6000_dvbs2_init_reg_vals); + init = m88rs6000_dvbs2_init_reg_vals; + } else { + len = ARRAY_SIZE(m88ds3103_dvbs2_init_reg_vals); + init = m88ds3103_dvbs2_init_reg_vals; + } break; default: dev_dbg(&priv->i2c->dev, "%s: invalid delivery_system\n", @@ -347,7 +407,30 @@ static int m88ds3103_set_frontend(struct dvb_frontend *fe) goto err; } - u8tmp1 = 0; /* silence compiler warning */ + if (priv->chip_id == M88RS6000_CHIP_ID) { + if ((c->delivery_system == SYS_DVBS2) + && ((c->symbol_rate / 1000) <= 5000)) { + ret = m88ds3103_wr_reg(priv, 0xc0, 0x04); + if (ret) + goto err; + buf[0] = 0x09; + buf[1] = 0x22; + buf[2] = 0x88; + ret = m88ds3103_wr_regs(priv, 0x8a, buf, 3); + if (ret) + goto err; + } + ret = m88ds3103_wr_reg_mask(priv, 0x9d, 0x08, 0x08); + if (ret) + goto err; + ret = m88ds3103_wr_reg(priv, 0xf1, 0x01); + if (ret) + goto err; + ret = m88ds3103_wr_reg_mask(priv, 0x30, 0x80, 0x80); + if (ret) + goto err; + } + switch (priv->cfg->ts_mode) { case M88DS3103_TS_SERIAL: u8tmp1 = 0x00; @@ -383,16 +466,15 @@ static int m88ds3103_set_frontend(struct dvb_frontend *fe) ret = m88ds3103_wr_reg_mask(priv, 0x29, u8tmp1, 0x20); if (ret) goto err; - } - - if (priv->cfg->ts_clk) { - divide_ratio = DIV_ROUND_UP(target_mclk, priv->cfg->ts_clk); - u8tmp1 = divide_ratio / 2; - u8tmp2 = DIV_ROUND_UP(divide_ratio, 2); - } else { - divide_ratio = 0; u8tmp1 = 0; u8tmp2 = 0; + break; + default: + if (priv->cfg->ts_clk) { + divide_ratio = DIV_ROUND_UP(target_mclk, priv->cfg->ts_clk); + u8tmp1 = divide_ratio / 2; + u8tmp2 = DIV_ROUND_UP(divide_ratio, 2); + } } dev_dbg(&priv->i2c->dev, @@ -420,29 +502,6 @@ static int m88ds3103_set_frontend(struct dvb_frontend *fe) if (ret) goto err; - switch (target_mclk) { - case 96000: - u8tmp1 = 0x02; /* 0b10 */ - u8tmp2 = 0x01; /* 0b01 */ - break; - case 144000: - u8tmp1 = 0x00; /* 0b00 */ - u8tmp2 = 0x01; /* 0b01 */ - break; - case 192000: - u8tmp1 = 0x03; /* 0b11 */ - u8tmp2 = 0x00; /* 0b00 */ - break; - } - - ret = m88ds3103_wr_reg_mask(priv, 0x22, u8tmp1 << 6, 0xc0); - if (ret) - goto err; - - ret = m88ds3103_wr_reg_mask(priv, 0x24, u8tmp2 << 6, 0xc0); - if (ret) - goto err; - if (c->symbol_rate <= 3000000) u8tmp = 0x20; else if (c->symbol_rate <= 10000000) @@ -466,7 +525,7 @@ static int m88ds3103_set_frontend(struct dvb_frontend *fe) if (ret) goto err; - u16tmp = DIV_ROUND_CLOSEST((c->symbol_rate / 1000) << 15, M88DS3103_MCLK_KHZ / 2); + u16tmp = DIV_ROUND_CLOSEST((c->symbol_rate / 1000) << 15, priv->mclk_khz / 2); buf[0] = (u16tmp >> 0) & 0xff; buf[1] = (u16tmp >> 8) & 0xff; ret = m88ds3103_wr_regs(priv, 0x61, buf, 2); @@ -489,7 +548,7 @@ static int m88ds3103_set_frontend(struct dvb_frontend *fe) (tuner_frequency - c->frequency)); s32tmp = 0x10000 * (tuner_frequency - c->frequency); - s32tmp = DIV_ROUND_CLOSEST(s32tmp, M88DS3103_MCLK_KHZ); + s32tmp = DIV_ROUND_CLOSEST(s32tmp, priv->mclk_khz); if (s32tmp < 0) s32tmp += 0x10000; @@ -520,7 +579,7 @@ static int m88ds3103_init(struct dvb_frontend *fe) struct m88ds3103_priv *priv = fe->demodulator_priv; int ret, len, remaining; const struct firmware *fw = NULL; - u8 *fw_file = M88DS3103_FIRMWARE; + u8 *fw_file; u8 u8tmp; dev_dbg(&priv->i2c->dev, "%s:\n", __func__); @@ -541,15 +600,6 @@ static int m88ds3103_init(struct dvb_frontend *fe) if (ret) goto err; - /* reset */ - ret = m88ds3103_wr_reg(priv, 0x07, 0x60); - if (ret) - goto err; - - ret = m88ds3103_wr_reg(priv, 0x07, 0x00); - if (ret) - goto err; - /* firmware status */ ret = m88ds3103_rd_reg(priv, 0xb9, &u8tmp); if (ret) @@ -560,10 +610,23 @@ static int m88ds3103_init(struct dvb_frontend *fe) if (u8tmp) goto skip_fw_download; + /* global reset, global diseqc reset, golbal fec reset */ + ret = m88ds3103_wr_reg(priv, 0x07, 0xe0); + if (ret) + goto err; + + ret = m88ds3103_wr_reg(priv, 0x07, 0x00); + if (ret) + goto err; + /* cold state - try to download firmware */ dev_info(&priv->i2c->dev, "%s: found a '%s' in cold state\n", KBUILD_MODNAME, m88ds3103_ops.info.name); + if (priv->chip_id == M88RS6000_CHIP_ID) + fw_file = M88RS6000_FIRMWARE; + else + fw_file = M88DS3103_FIRMWARE; /* request the firmware, this will block and timeout */ ret = request_firmware(&fw, fw_file, priv->i2c->dev.parent); if (ret) { @@ -577,7 +640,7 @@ static int m88ds3103_init(struct dvb_frontend *fe) ret = m88ds3103_wr_reg(priv, 0xb2, 0x01); if (ret) - goto err; + goto error_fw_release; for (remaining = fw->size; remaining > 0; remaining -= (priv->cfg->i2c_wr_max - 1)) { @@ -591,13 +654,13 @@ static int m88ds3103_init(struct dvb_frontend *fe) dev_err(&priv->i2c->dev, "%s: firmware download failed=%d\n", KBUILD_MODNAME, ret); - goto err; + goto error_fw_release; } } ret = m88ds3103_wr_reg(priv, 0xb2, 0x00); if (ret) - goto err; + goto error_fw_release; release_firmware(fw); fw = NULL; @@ -623,10 +686,10 @@ skip_fw_download: priv->warm = true; return 0; -err: - if (fw) - release_firmware(fw); +error_fw_release: + release_firmware(fw); +err: dev_dbg(&priv->i2c->dev, "%s: failed=%d\n", __func__, ret); return ret; } @@ -635,13 +698,18 @@ static int m88ds3103_sleep(struct dvb_frontend *fe) { struct m88ds3103_priv *priv = fe->demodulator_priv; int ret; + u8 u8tmp; dev_dbg(&priv->i2c->dev, "%s:\n", __func__); priv->delivery_system = SYS_UNDEFINED; /* TS Hi-Z */ - ret = m88ds3103_wr_reg_mask(priv, 0x27, 0x00, 0x01); + if (priv->chip_id == M88RS6000_CHIP_ID) + u8tmp = 0x29; + else + u8tmp = 0x27; + ret = m88ds3103_wr_reg_mask(priv, u8tmp, 0x00, 0x01); if (ret) goto err; @@ -830,7 +898,7 @@ static int m88ds3103_get_frontend(struct dvb_frontend *fe) goto err; c->symbol_rate = 1ull * ((buf[1] << 8) | (buf[0] << 0)) * - M88DS3103_MCLK_KHZ * 1000 / 0x10000; + priv->mclk_khz * 1000 / 0x10000; return 0; err: @@ -1310,18 +1378,22 @@ struct dvb_frontend *m88ds3103_attach(const struct m88ds3103_config *cfg, priv->i2c = i2c; mutex_init(&priv->i2c_mutex); - ret = m88ds3103_rd_reg(priv, 0x01, &chip_id); + /* 0x00: chip id[6:0], 0x01: chip ver[7:0], 0x02: chip ver[15:8] */ + ret = m88ds3103_rd_reg(priv, 0x00, &chip_id); if (ret) goto err; - dev_dbg(&priv->i2c->dev, "%s: chip_id=%02x\n", __func__, chip_id); + chip_id >>= 1; + dev_info(&priv->i2c->dev, "%s: chip_id=%02x\n", __func__, chip_id); switch (chip_id) { - case 0xd0: + case M88RS6000_CHIP_ID: + case M88DS3103_CHIP_ID: break; default: goto err; } + priv->chip_id = chip_id; switch (priv->cfg->clock_out) { case M88DS3103_CLOCK_OUT_DISABLED: @@ -1337,6 +1409,11 @@ struct dvb_frontend *m88ds3103_attach(const struct m88ds3103_config *cfg, goto err; } + /* 0x29 register is defined differently for m88rs6000. */ + /* set internal tuner address to 0x21 */ + if (chip_id == M88RS6000_CHIP_ID) + u8tmp = 0x00; + ret = m88ds3103_wr_reg(priv, 0x29, u8tmp); if (ret) goto err; @@ -1364,6 +1441,9 @@ struct dvb_frontend *m88ds3103_attach(const struct m88ds3103_config *cfg, /* create dvb_frontend */ memcpy(&priv->fe.ops, &m88ds3103_ops, sizeof(struct dvb_frontend_ops)); + if (priv->chip_id == M88RS6000_CHIP_ID) + strncpy(priv->fe.ops.info.name, + "Montage M88RS6000", sizeof(priv->fe.ops.info.name)); priv->fe.demodulator_priv = priv; return &priv->fe; @@ -1423,3 +1503,4 @@ MODULE_AUTHOR("Antti Palosaari <crope@iki.fi>"); MODULE_DESCRIPTION("Montage M88DS3103 DVB-S/S2 demodulator driver"); MODULE_LICENSE("GPL"); MODULE_FIRMWARE(M88DS3103_FIRMWARE); +MODULE_FIRMWARE(M88RS6000_FIRMWARE); diff --git a/drivers/media/dvb-frontends/m88ds3103_priv.h b/drivers/media/dvb-frontends/m88ds3103_priv.h index 9169fdd143cf..a2c0958111f8 100644 --- a/drivers/media/dvb-frontends/m88ds3103_priv.h +++ b/drivers/media/dvb-frontends/m88ds3103_priv.h @@ -25,7 +25,10 @@ #include <linux/math64.h> #define M88DS3103_FIRMWARE "dvb-demod-m88ds3103.fw" +#define M88RS6000_FIRMWARE "dvb-demod-m88rs6000.fw" #define M88DS3103_MCLK_KHZ 96000 +#define M88RS6000_CHIP_ID 0x74 +#define M88DS3103_CHIP_ID 0x70 struct m88ds3103_priv { struct i2c_adapter *i2c; @@ -38,6 +41,10 @@ struct m88ds3103_priv { u32 ber; bool warm; /* FW running */ struct i2c_adapter *i2c_adapter; + /* auto detect chip id to do different config */ + u8 chip_id; + /* main mclk is calculated for M88RS6000 dynamically */ + u32 mclk_khz; }; struct m88ds3103_reg_val { @@ -214,4 +221,178 @@ static const struct m88ds3103_reg_val m88ds3103_dvbs2_init_reg_vals[] = { {0xb8, 0x00}, }; +static const struct m88ds3103_reg_val m88rs6000_dvbs_init_reg_vals[] = { + {0x23, 0x07}, + {0x08, 0x03}, + {0x0c, 0x02}, + {0x20, 0x00}, + {0x21, 0x54}, + {0x25, 0x82}, + {0x27, 0x31}, + {0x30, 0x08}, + {0x31, 0x40}, + {0x32, 0x32}, + {0x33, 0x35}, + {0x35, 0xff}, + {0x3a, 0x00}, + {0x37, 0x10}, + {0x38, 0x10}, + {0x39, 0x02}, + {0x42, 0x60}, + {0x4a, 0x80}, + {0x4b, 0x04}, + {0x4d, 0x91}, + {0x5d, 0xc8}, + {0x50, 0x36}, + {0x51, 0x36}, + {0x52, 0x36}, + {0x53, 0x36}, + {0x63, 0x0f}, + {0x64, 0x30}, + {0x65, 0x40}, + {0x68, 0x26}, + {0x69, 0x4c}, + {0x70, 0x20}, + {0x71, 0x70}, + {0x72, 0x04}, + {0x73, 0x00}, + {0x70, 0x40}, + {0x71, 0x70}, + {0x72, 0x04}, + {0x73, 0x00}, + {0x70, 0x60}, + {0x71, 0x70}, + {0x72, 0x04}, + {0x73, 0x00}, + {0x70, 0x80}, + {0x71, 0x70}, + {0x72, 0x04}, + {0x73, 0x00}, + {0x70, 0xa0}, + {0x71, 0x70}, + {0x72, 0x04}, + {0x73, 0x00}, + {0x70, 0x1f}, + {0x76, 0x38}, + {0x77, 0xa6}, + {0x78, 0x0c}, + {0x79, 0x80}, + {0x7f, 0x14}, + {0x7c, 0x00}, + {0xae, 0x82}, + {0x80, 0x64}, + {0x81, 0x66}, + {0x82, 0x44}, + {0x85, 0x04}, + {0xcd, 0xf4}, + {0x90, 0x33}, + {0xa0, 0x44}, + {0xbe, 0x00}, + {0xc0, 0x08}, + {0xc3, 0x10}, + {0xc4, 0x08}, + {0xc5, 0xf0}, + {0xc6, 0xff}, + {0xc7, 0x00}, + {0xc8, 0x1a}, + {0xc9, 0x80}, + {0xe0, 0xf8}, + {0xe6, 0x8b}, + {0xd0, 0x40}, + {0xf8, 0x20}, + {0xfa, 0x0f}, + {0x00, 0x00}, + {0xbd, 0x01}, + {0xb8, 0x00}, + {0x29, 0x11}, +}; + +static const struct m88ds3103_reg_val m88rs6000_dvbs2_init_reg_vals[] = { + {0x23, 0x07}, + {0x08, 0x07}, + {0x0c, 0x02}, + {0x20, 0x00}, + {0x21, 0x54}, + {0x25, 0x82}, + {0x27, 0x31}, + {0x30, 0x08}, + {0x32, 0x32}, + {0x33, 0x35}, + {0x35, 0xff}, + {0x3a, 0x00}, + {0x37, 0x10}, + {0x38, 0x10}, + {0x39, 0x02}, + {0x42, 0x60}, + {0x4a, 0x80}, + {0x4b, 0x04}, + {0x4d, 0x91}, + {0x5d, 0xc8}, + {0x50, 0x36}, + {0x51, 0x36}, + {0x52, 0x36}, + {0x53, 0x36}, + {0x63, 0x0f}, + {0x64, 0x10}, + {0x65, 0x20}, + {0x68, 0x46}, + {0x69, 0xcd}, + {0x70, 0x20}, + {0x71, 0x70}, + {0x72, 0x04}, + {0x73, 0x00}, + {0x70, 0x40}, + {0x71, 0x70}, + {0x72, 0x04}, + {0x73, 0x00}, + {0x70, 0x60}, + {0x71, 0x70}, + {0x72, 0x04}, + {0x73, 0x00}, + {0x70, 0x80}, + {0x71, 0x70}, + {0x72, 0x04}, + {0x73, 0x00}, + {0x70, 0xa0}, + {0x71, 0x70}, + {0x72, 0x04}, + {0x73, 0x00}, + {0x70, 0x1f}, + {0x76, 0x38}, + {0x77, 0xa6}, + {0x78, 0x0c}, + {0x79, 0x80}, + {0x7f, 0x14}, + {0x85, 0x08}, + {0xcd, 0xf4}, + {0x90, 0x33}, + {0x86, 0x00}, + {0x87, 0x0f}, + {0x89, 0x00}, + {0x8b, 0x44}, + {0x8c, 0x66}, + {0x9d, 0xc1}, + {0x8a, 0x10}, + {0xad, 0x40}, + {0xa0, 0x44}, + {0xbe, 0x00}, + {0xc0, 0x08}, + {0xc1, 0x10}, + {0xc2, 0x08}, + {0xc3, 0x10}, + {0xc4, 0x08}, + {0xc5, 0xf0}, + {0xc6, 0xff}, + {0xc7, 0x00}, + {0xc8, 0x1a}, + {0xc9, 0x80}, + {0xca, 0x23}, + {0xcb, 0x24}, + {0xcc, 0xf4}, + {0xce, 0x74}, + {0x00, 0x00}, + {0xbd, 0x01}, + {0xb8, 0x00}, + {0x29, 0x01}, +}; #endif diff --git a/drivers/media/dvb-frontends/mn88472.h b/drivers/media/dvb-frontends/mn88472.h new file mode 100644 index 000000000000..da4558bce60f --- /dev/null +++ b/drivers/media/dvb-frontends/mn88472.h @@ -0,0 +1,38 @@ +/* + * Panasonic MN88472 DVB-T/T2/C demodulator driver + * + * Copyright (C) 2013 Antti Palosaari <crope@iki.fi> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#ifndef MN88472_H +#define MN88472_H + +#include <linux/dvb/frontend.h> + +struct mn88472_config { + /* + * Max num of bytes given I2C adapter could write at once. + * Default: none + */ + u16 i2c_wr_max; + + + /* Everything after that is returned by the driver. */ + + /* + * DVB frontend. + */ + struct dvb_frontend **fe; +}; + +#endif diff --git a/drivers/media/dvb-frontends/mn88473.h b/drivers/media/dvb-frontends/mn88473.h new file mode 100644 index 000000000000..a373ec93cbe0 --- /dev/null +++ b/drivers/media/dvb-frontends/mn88473.h @@ -0,0 +1,38 @@ +/* + * Panasonic MN88473 DVB-T/T2/C demodulator driver + * + * Copyright (C) 2014 Antti Palosaari <crope@iki.fi> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#ifndef MN88473_H +#define MN88473_H + +#include <linux/dvb/frontend.h> + +struct mn88473_config { + /* + * Max num of bytes given I2C adapter could write at once. + * Default: none + */ + u16 i2c_wr_max; + + + /* Everything after that is returned by the driver. */ + + /* + * DVB frontend. + */ + struct dvb_frontend **fe; +}; + +#endif diff --git a/drivers/media/dvb-frontends/rtl2832.c b/drivers/media/dvb-frontends/rtl2832.c index eb737cf29a36..9026e1aee163 100644 --- a/drivers/media/dvb-frontends/rtl2832.c +++ b/drivers/media/dvb-frontends/rtl2832.c @@ -258,13 +258,11 @@ static int rtl2832_rd_regs(struct rtl2832_priv *priv, u8 reg, u8 page, u8 *val, return rtl2832_rd(priv, reg, val, len); } -#if 0 /* currently not used */ /* write single register */ static int rtl2832_wr_reg(struct rtl2832_priv *priv, u8 reg, u8 page, u8 val) { return rtl2832_wr_regs(priv, reg, page, &val, 1); } -#endif /* read single register */ static int rtl2832_rd_reg(struct rtl2832_priv *priv, u8 reg, u8 page, u8 *val) @@ -599,6 +597,11 @@ static int rtl2832_set_frontend(struct dvb_frontend *fe) if (fe->ops.tuner_ops.set_params) fe->ops.tuner_ops.set_params(fe); + /* PIP mode related */ + ret = rtl2832_wr_regs(priv, 0x92, 1, "\x00\x0f\xff", 3); + if (ret) + goto err; + /* If the frontend has get_if_frequency(), use it */ if (fe->ops.tuner_ops.get_if_frequency) { u32 if_freq; @@ -661,7 +664,6 @@ static int rtl2832_set_frontend(struct dvb_frontend *fe) if (ret) goto err; - /* soft reset */ ret = rtl2832_wr_demod_reg(priv, DVBT_SOFT_RST, 0x1); if (ret) @@ -1020,6 +1022,58 @@ static int rtl2832_deselect(struct i2c_adapter *adap, void *mux_priv, return 0; } +int rtl2832_enable_external_ts_if(struct dvb_frontend *fe) +{ + struct rtl2832_priv *priv = fe->demodulator_priv; + int ret; + + dev_dbg(&priv->i2c->dev, "%s: setting PIP mode\n", __func__); + + ret = rtl2832_wr_regs(priv, 0x0c, 1, "\x5f\xff", 2); + if (ret) + goto err; + + ret = rtl2832_wr_demod_reg(priv, DVBT_PIP_ON, 0x1); + if (ret) + goto err; + + ret = rtl2832_wr_reg(priv, 0xbc, 0, 0x18); + if (ret) + goto err; + + ret = rtl2832_wr_reg(priv, 0x22, 0, 0x01); + if (ret) + goto err; + + ret = rtl2832_wr_reg(priv, 0x26, 0, 0x1f); + if (ret) + goto err; + + ret = rtl2832_wr_reg(priv, 0x27, 0, 0xff); + if (ret) + goto err; + + ret = rtl2832_wr_regs(priv, 0x92, 1, "\x7f\xf7\xff", 3); + if (ret) + goto err; + + /* soft reset */ + ret = rtl2832_wr_demod_reg(priv, DVBT_SOFT_RST, 0x1); + if (ret) + goto err; + + ret = rtl2832_wr_demod_reg(priv, DVBT_SOFT_RST, 0x0); + if (ret) + goto err; + + return 0; +err: + dev_dbg(&priv->i2c->dev, "%s: failed=%d\n", __func__, ret); + return ret; + +} +EXPORT_SYMBOL(rtl2832_enable_external_ts_if); + struct i2c_adapter *rtl2832_get_i2c_adapter(struct dvb_frontend *fe) { struct rtl2832_priv *priv = fe->demodulator_priv; diff --git a/drivers/media/dvb-frontends/rtl2832.h b/drivers/media/dvb-frontends/rtl2832.h index cb3b6b0775b8..5254c1dfc8de 100644 --- a/drivers/media/dvb-frontends/rtl2832.h +++ b/drivers/media/dvb-frontends/rtl2832.h @@ -64,6 +64,10 @@ extern struct i2c_adapter *rtl2832_get_private_i2c_adapter( struct dvb_frontend *fe ); +extern int rtl2832_enable_external_ts_if( + struct dvb_frontend *fe +); + #else static inline struct dvb_frontend *rtl2832_attach( @@ -89,6 +93,13 @@ static inline struct i2c_adapter *rtl2832_get_private_i2c_adapter( return NULL; } +static inline int rtl2832_enable_external_ts_if( + struct dvb_frontend *fe +) +{ + return -ENODEV; +} + #endif diff --git a/drivers/media/dvb-frontends/rtl2832_sdr.c b/drivers/media/dvb-frontends/rtl2832_sdr.c index 7bf98cf6bbe1..2896b47c29d8 100644 --- a/drivers/media/dvb-frontends/rtl2832_sdr.c +++ b/drivers/media/dvb-frontends/rtl2832_sdr.c @@ -1013,6 +1013,10 @@ static int rtl2832_sdr_start_streaming(struct vb2_queue *vq, unsigned int count) if (s->d->props->power_ctrl) s->d->props->power_ctrl(s->d, 1); + /* enable ADC */ + if (s->d->props->frontend_ctrl) + s->d->props->frontend_ctrl(s->fe, 1); + set_bit(POWER_ON, &s->flags); ret = rtl2832_sdr_set_tuner(s); @@ -1064,6 +1068,10 @@ static void rtl2832_sdr_stop_streaming(struct vb2_queue *vq) clear_bit(POWER_ON, &s->flags); + /* disable ADC */ + if (s->d->props->frontend_ctrl) + s->d->props->frontend_ctrl(s->fe, 0); + if (s->d->props->power_ctrl) s->d->props->power_ctrl(s->d, 0); diff --git a/drivers/media/dvb-frontends/si2168.c b/drivers/media/dvb-frontends/si2168.c index 1cd93be281ed..ce9ab442b4b6 100644 --- a/drivers/media/dvb-frontends/si2168.c +++ b/drivers/media/dvb-frontends/si2168.c @@ -308,14 +308,16 @@ static int si2168_set_frontend(struct dvb_frontend *fe) if (ret) goto err; - memcpy(cmd.args, "\x14\x00\x09\x10\xe3\x18", 6); + memcpy(cmd.args, "\x14\x00\x09\x10\xe3\x08", 6); + cmd.args[5] |= s->ts_clock_inv ? 0x00 : 0x10; cmd.wlen = 6; cmd.rlen = 4; ret = si2168_cmd_execute(s, &cmd); if (ret) goto err; - memcpy(cmd.args, "\x14\x00\x08\x10\xd7\x15", 6); + memcpy(cmd.args, "\x14\x00\x08\x10\xd7\x05", 6); + cmd.args[5] |= s->ts_clock_inv ? 0x00 : 0x10; cmd.wlen = 6; cmd.rlen = 4; ret = si2168_cmd_execute(s, &cmd); @@ -453,27 +455,45 @@ static int si2168_init(struct dvb_frontend *fe) dev_err(&s->client->dev, "firmware file '%s' not found\n", fw_file); - goto err; + goto error_fw_release; } } dev_info(&s->client->dev, "downloading firmware from file '%s'\n", fw_file); - for (remaining = fw->size; remaining > 0; remaining -= i2c_wr_max) { - len = remaining; - if (len > i2c_wr_max) - len = i2c_wr_max; - - memcpy(cmd.args, &fw->data[fw->size - remaining], len); - cmd.wlen = len; - cmd.rlen = 1; - ret = si2168_cmd_execute(s, &cmd); - if (ret) { - dev_err(&s->client->dev, - "firmware download failed=%d\n", - ret); - goto err; + if ((fw->size % 17 == 0) && (fw->data[0] > 5)) { + /* firmware is in the new format */ + for (remaining = fw->size; remaining > 0; remaining -= 17) { + len = fw->data[fw->size - remaining]; + memcpy(cmd.args, &fw->data[(fw->size - remaining) + 1], len); + cmd.wlen = len; + cmd.rlen = 1; + ret = si2168_cmd_execute(s, &cmd); + if (ret) { + dev_err(&s->client->dev, + "firmware download failed=%d\n", + ret); + goto error_fw_release; + } + } + } else { + /* firmware is in the old format */ + for (remaining = fw->size; remaining > 0; remaining -= i2c_wr_max) { + len = remaining; + if (len > i2c_wr_max) + len = i2c_wr_max; + + memcpy(cmd.args, &fw->data[fw->size - remaining], len); + cmd.wlen = len; + cmd.rlen = 1; + ret = si2168_cmd_execute(s, &cmd); + if (ret) { + dev_err(&s->client->dev, + "firmware download failed=%d\n", + ret); + goto error_fw_release; + } } } @@ -487,6 +507,17 @@ static int si2168_init(struct dvb_frontend *fe) if (ret) goto err; + /* query firmware version */ + memcpy(cmd.args, "\x11", 1); + cmd.wlen = 1; + cmd.rlen = 10; + ret = si2168_cmd_execute(s, &cmd); + if (ret) + goto err; + + dev_dbg(&s->client->dev, "firmware version: %c.%c.%d\n", + cmd.args[6], cmd.args[7], cmd.args[8]); + /* set ts mode */ memcpy(cmd.args, "\x14\x00\x01\x10\x10\x00", 6); cmd.args[4] |= s->ts_mode; @@ -498,17 +529,16 @@ static int si2168_init(struct dvb_frontend *fe) s->fw_loaded = true; -warm: dev_info(&s->client->dev, "found a '%s' in warm state\n", si2168_ops.info.name); - +warm: s->active = true; return 0; -err: - if (fw) - release_firmware(fw); +error_fw_release: + release_firmware(fw); +err: dev_dbg(&s->client->dev, "failed=%d\n", ret); return ret; } @@ -670,6 +700,7 @@ static int si2168_probe(struct i2c_client *client, *config->i2c_adapter = s->adapter; *config->fe = &s->fe; s->ts_mode = config->ts_mode; + s->ts_clock_inv = config->ts_clock_inv; s->fw_loaded = false; i2c_set_clientdata(client, s); diff --git a/drivers/media/dvb-frontends/si2168.h b/drivers/media/dvb-frontends/si2168.h index e086d6719451..87bc12146667 100644 --- a/drivers/media/dvb-frontends/si2168.h +++ b/drivers/media/dvb-frontends/si2168.h @@ -37,6 +37,10 @@ struct si2168_config { /* TS mode */ u8 ts_mode; + + /* TS clock inverted */ + bool ts_clock_inv; + }; #define SI2168_TS_PARALLEL 0x06 diff --git a/drivers/media/dvb-frontends/si2168_priv.h b/drivers/media/dvb-frontends/si2168_priv.h index e13983ed4be1..60bc3349b6c3 100644 --- a/drivers/media/dvb-frontends/si2168_priv.h +++ b/drivers/media/dvb-frontends/si2168_priv.h @@ -38,6 +38,7 @@ struct si2168 { bool active; bool fw_loaded; u8 ts_mode; + bool ts_clock_inv; }; /* firmare command struct */ diff --git a/drivers/media/dvb-frontends/sp2.c b/drivers/media/dvb-frontends/sp2.c index 9b684d5c8f91..cc1ef966f99f 100644 --- a/drivers/media/dvb-frontends/sp2.c +++ b/drivers/media/dvb-frontends/sp2.c @@ -92,6 +92,9 @@ static int sp2_write_i2c(struct sp2 *s, u8 reg, u8 *buf, int len) return -EIO; } + dev_dbg(&s->client->dev, "addr=0x%04x, reg = 0x%02x, data = %*ph\n", + client->addr, reg, len, buf); + return 0; } @@ -103,9 +106,6 @@ static int sp2_ci_op_cam(struct dvb_ca_en50221 *en50221, int slot, u8 acs, int mem, ret; int (*ci_op_cam)(void*, u8, int, u8, int*) = s->ci_control; - dev_dbg(&s->client->dev, "slot=%d, acs=0x%02x, addr=0x%04x, data = 0x%02x", - slot, acs, addr, data); - if (slot != 0) return -EINVAL; @@ -140,13 +140,16 @@ static int sp2_ci_op_cam(struct dvb_ca_en50221 *en50221, int slot, u8 acs, if (ret) return ret; - if (read) { - dev_dbg(&s->client->dev, "cam read, addr=0x%04x, data = 0x%04x", - addr, mem); + dev_dbg(&s->client->dev, "%s: slot=%d, addr=0x%04x, %s, data=%x", + (read) ? "read" : "write", slot, addr, + (acs == SP2_CI_ATTR_ACS) ? "attr" : "io", + (read) ? mem : data); + + if (read) return mem; - } else { + else return 0; - } + } int sp2_ci_read_attribute_mem(struct dvb_ca_en50221 *en50221, @@ -266,7 +269,7 @@ int sp2_ci_poll_slot_status(struct dvb_ca_en50221 *en50221, return s->status; } -int sp2_init(struct sp2 *s) +static int sp2_init(struct sp2 *s) { int ret = 0; u8 buf; @@ -348,7 +351,7 @@ err: return ret; } -int sp2_exit(struct i2c_client *client) +static int sp2_exit(struct i2c_client *client) { struct sp2 *s; @@ -407,7 +410,7 @@ err: static int sp2_remove(struct i2c_client *client) { - struct si2157 *s = i2c_get_clientdata(client); + struct sp2 *s = i2c_get_clientdata(client); dev_dbg(&client->dev, "\n"); diff --git a/drivers/media/dvb-frontends/stb0899_drv.c b/drivers/media/dvb-frontends/stb0899_drv.c index 07cd5ea7a038..19646fbb061d 100644 --- a/drivers/media/dvb-frontends/stb0899_drv.c +++ b/drivers/media/dvb-frontends/stb0899_drv.c @@ -705,7 +705,7 @@ static int stb0899_send_diseqc_msg(struct dvb_frontend *fe, struct dvb_diseqc_ma struct stb0899_state *state = fe->demodulator_priv; u8 reg, i; - if (cmd->msg_len > 8) + if (cmd->msg_len > sizeof(cmd->msg)) return -EINVAL; /* enable FIFO precharge */ diff --git a/drivers/media/dvb-frontends/stv090x.c b/drivers/media/dvb-frontends/stv090x.c index 23e872f84742..0b2a934f53e5 100644 --- a/drivers/media/dvb-frontends/stv090x.c +++ b/drivers/media/dvb-frontends/stv090x.c @@ -2146,7 +2146,7 @@ static int stv090x_get_coldlock(struct stv090x_state *state, s32 timeout_dmd) u32 reg; s32 car_step, steps, cur_step, dir, freq, timeout_lock; - int lock = 0; + int lock; if (state->srate >= 10000000) timeout_lock = timeout_dmd / 3; @@ -2154,98 +2154,96 @@ static int stv090x_get_coldlock(struct stv090x_state *state, s32 timeout_dmd) timeout_lock = timeout_dmd / 2; lock = stv090x_get_dmdlock(state, timeout_lock); /* cold start wait */ - if (!lock) { - if (state->srate >= 10000000) { - if (stv090x_chk_tmg(state)) { - if (STV090x_WRITE_DEMOD(state, DMDISTATE, 0x1f) < 0) - goto err; - if (STV090x_WRITE_DEMOD(state, DMDISTATE, 0x15) < 0) - goto err; - lock = stv090x_get_dmdlock(state, timeout_dmd); - } else { - lock = 0; - } - } else { - if (state->srate <= 4000000) - car_step = 1000; - else if (state->srate <= 7000000) - car_step = 2000; - else if (state->srate <= 10000000) - car_step = 3000; - else - car_step = 5000; - - steps = (state->search_range / 1000) / car_step; - steps /= 2; - steps = 2 * (steps + 1); - if (steps < 0) - steps = 2; - else if (steps > 12) - steps = 12; - - cur_step = 1; - dir = 1; - - if (!lock) { - freq = state->frequency; - state->tuner_bw = stv090x_car_width(state->srate, state->rolloff) + state->srate; - while ((cur_step <= steps) && (!lock)) { - if (dir > 0) - freq += cur_step * car_step; - else - freq -= cur_step * car_step; - - /* Setup tuner */ - if (stv090x_i2c_gate_ctrl(state, 1) < 0) - goto err; + if (lock) + return lock; - if (state->config->tuner_set_frequency) { - if (state->config->tuner_set_frequency(fe, freq) < 0) - goto err_gateoff; - } + if (state->srate >= 10000000) { + if (stv090x_chk_tmg(state)) { + if (STV090x_WRITE_DEMOD(state, DMDISTATE, 0x1f) < 0) + goto err; + if (STV090x_WRITE_DEMOD(state, DMDISTATE, 0x15) < 0) + goto err; + return stv090x_get_dmdlock(state, timeout_dmd); + } + return 0; + } - if (state->config->tuner_set_bandwidth) { - if (state->config->tuner_set_bandwidth(fe, state->tuner_bw) < 0) - goto err_gateoff; - } + if (state->srate <= 4000000) + car_step = 1000; + else if (state->srate <= 7000000) + car_step = 2000; + else if (state->srate <= 10000000) + car_step = 3000; + else + car_step = 5000; - if (stv090x_i2c_gate_ctrl(state, 0) < 0) - goto err; + steps = (state->search_range / 1000) / car_step; + steps /= 2; + steps = 2 * (steps + 1); + if (steps < 0) + steps = 2; + else if (steps > 12) + steps = 12; - msleep(50); + cur_step = 1; + dir = 1; - if (stv090x_i2c_gate_ctrl(state, 1) < 0) - goto err; + freq = state->frequency; + state->tuner_bw = stv090x_car_width(state->srate, state->rolloff) + state->srate; + while ((cur_step <= steps) && (!lock)) { + if (dir > 0) + freq += cur_step * car_step; + else + freq -= cur_step * car_step; - if (state->config->tuner_get_status) { - if (state->config->tuner_get_status(fe, ®) < 0) - goto err_gateoff; - } + /* Setup tuner */ + if (stv090x_i2c_gate_ctrl(state, 1) < 0) + goto err; - if (reg) - dprintk(FE_DEBUG, 1, "Tuner phase locked"); - else - dprintk(FE_DEBUG, 1, "Tuner unlocked"); + if (state->config->tuner_set_frequency) { + if (state->config->tuner_set_frequency(fe, freq) < 0) + goto err_gateoff; + } - if (stv090x_i2c_gate_ctrl(state, 0) < 0) - goto err; + if (state->config->tuner_set_bandwidth) { + if (state->config->tuner_set_bandwidth(fe, state->tuner_bw) < 0) + goto err_gateoff; + } - STV090x_WRITE_DEMOD(state, DMDISTATE, 0x1c); - if (STV090x_WRITE_DEMOD(state, CFRINIT1, 0x00) < 0) - goto err; - if (STV090x_WRITE_DEMOD(state, CFRINIT0, 0x00) < 0) - goto err; - if (STV090x_WRITE_DEMOD(state, DMDISTATE, 0x1f) < 0) - goto err; - if (STV090x_WRITE_DEMOD(state, DMDISTATE, 0x15) < 0) - goto err; - lock = stv090x_get_dmdlock(state, (timeout_dmd / 3)); + if (stv090x_i2c_gate_ctrl(state, 0) < 0) + goto err; - dir *= -1; - cur_step++; - } - } + msleep(50); + + if (stv090x_i2c_gate_ctrl(state, 1) < 0) + goto err; + + if (state->config->tuner_get_status) { + if (state->config->tuner_get_status(fe, ®) < 0) + goto err_gateoff; } + + if (reg) + dprintk(FE_DEBUG, 1, "Tuner phase locked"); + else + dprintk(FE_DEBUG, 1, "Tuner unlocked"); + + if (stv090x_i2c_gate_ctrl(state, 0) < 0) + goto err; + + STV090x_WRITE_DEMOD(state, DMDISTATE, 0x1c); + if (STV090x_WRITE_DEMOD(state, CFRINIT1, 0x00) < 0) + goto err; + if (STV090x_WRITE_DEMOD(state, CFRINIT0, 0x00) < 0) + goto err; + if (STV090x_WRITE_DEMOD(state, DMDISTATE, 0x1f) < 0) + goto err; + if (STV090x_WRITE_DEMOD(state, DMDISTATE, 0x15) < 0) + goto err; + lock = stv090x_get_dmdlock(state, (timeout_dmd / 3)); + + dir *= -1; + cur_step++; } return lock; @@ -2663,13 +2661,9 @@ static enum stv090x_signal_state stv090x_get_sig_params(struct stv090x_state *st return STV090x_RANGEOK; else if (abs(offst_freq) <= (stv090x_car_width(state->srate, state->rolloff) / 2000)) return STV090x_RANGEOK; - else - return STV090x_OUTOFRANGE; /* Out of Range */ } else { if (abs(offst_freq) <= ((state->search_range / 2000) + 500)) return STV090x_RANGEOK; - else - return STV090x_OUTOFRANGE; } return STV090x_OUTOFRANGE; @@ -2789,6 +2783,12 @@ static u8 stv090x_optimize_carloop(struct stv090x_state *state, enum stv090x_mod aclc = car_loop[i].crl_pilots_off_30; } } else { /* 16APSK and 32APSK */ + /* + * This should never happen in practice, except if + * something is really wrong at the car_loop table. + */ + if (i >= 11) + i = 10; if (state->srate <= 3000000) aclc = car_loop_apsk_low[i].crl_pilots_on_2; else if (state->srate <= 7000000) @@ -3470,7 +3470,20 @@ static enum dvbfe_search stv090x_search(struct dvb_frontend *fe) if (props->frequency == 0) return DVBFE_ALGO_SEARCH_INVALID; - state->delsys = props->delivery_system; + switch (props->delivery_system) { + case SYS_DSS: + state->delsys = STV090x_DSS; + break; + case SYS_DVBS: + state->delsys = STV090x_DVBS1; + break; + case SYS_DVBS2: + state->delsys = STV090x_DVBS2; + break; + default: + return DVBFE_ALGO_SEARCH_INVALID; + } + state->frequency = props->frequency; state->srate = props->symbol_rate; state->search_mode = STV090x_SEARCH_AUTO; @@ -4859,8 +4872,8 @@ err: return -1; } -int stv090x_set_gpio(struct dvb_frontend *fe, u8 gpio, u8 dir, u8 value, - u8 xor_value) +static int stv090x_set_gpio(struct dvb_frontend *fe, u8 gpio, u8 dir, + u8 value, u8 xor_value) { struct stv090x_state *state = fe->demodulator_priv; u8 reg = 0; @@ -4871,7 +4884,6 @@ int stv090x_set_gpio(struct dvb_frontend *fe, u8 gpio, u8 dir, u8 value, return stv090x_write_reg(state, STV090x_GPIOxCFG(gpio), reg); } -EXPORT_SYMBOL(stv090x_set_gpio); static struct dvb_frontend_ops stv090x_ops = { .delsys = { SYS_DVBS, SYS_DVBS2, SYS_DSS }, @@ -4908,7 +4920,7 @@ static struct dvb_frontend_ops stv090x_ops = { }; -struct dvb_frontend *stv090x_attach(const struct stv090x_config *config, +struct dvb_frontend *stv090x_attach(struct stv090x_config *config, struct i2c_adapter *i2c, enum stv090x_demodulator demod) { @@ -4969,6 +4981,8 @@ struct dvb_frontend *stv090x_attach(const struct stv090x_config *config, if (config->diseqc_envelope_mode) stv090x_send_diseqc_burst(&state->frontend, SEC_MINI_A); + config->set_gpio = stv090x_set_gpio; + dprintk(FE_ERROR, 1, "Attaching %s demodulator(%d) Cut=0x%02x", state->device == STV0900 ? "STV0900" : "STV0903", demod, diff --git a/drivers/media/dvb-frontends/stv090x.h b/drivers/media/dvb-frontends/stv090x.h index 0bd6adcfee8a..742eeda99000 100644 --- a/drivers/media/dvb-frontends/stv090x.h +++ b/drivers/media/dvb-frontends/stv090x.h @@ -89,29 +89,29 @@ struct stv090x_config { bool diseqc_envelope_mode; - int (*tuner_init) (struct dvb_frontend *fe); - int (*tuner_sleep) (struct dvb_frontend *fe); - int (*tuner_set_mode) (struct dvb_frontend *fe, enum tuner_mode mode); - int (*tuner_set_frequency) (struct dvb_frontend *fe, u32 frequency); - int (*tuner_get_frequency) (struct dvb_frontend *fe, u32 *frequency); - int (*tuner_set_bandwidth) (struct dvb_frontend *fe, u32 bandwidth); - int (*tuner_get_bandwidth) (struct dvb_frontend *fe, u32 *bandwidth); - int (*tuner_set_bbgain) (struct dvb_frontend *fe, u32 gain); - int (*tuner_get_bbgain) (struct dvb_frontend *fe, u32 *gain); - int (*tuner_set_refclk) (struct dvb_frontend *fe, u32 refclk); - int (*tuner_get_status) (struct dvb_frontend *fe, u32 *status); - void (*tuner_i2c_lock) (struct dvb_frontend *fe, int lock); + int (*tuner_init)(struct dvb_frontend *fe); + int (*tuner_sleep)(struct dvb_frontend *fe); + int (*tuner_set_mode)(struct dvb_frontend *fe, enum tuner_mode mode); + int (*tuner_set_frequency)(struct dvb_frontend *fe, u32 frequency); + int (*tuner_get_frequency)(struct dvb_frontend *fe, u32 *frequency); + int (*tuner_set_bandwidth)(struct dvb_frontend *fe, u32 bandwidth); + int (*tuner_get_bandwidth)(struct dvb_frontend *fe, u32 *bandwidth); + int (*tuner_set_bbgain)(struct dvb_frontend *fe, u32 gain); + int (*tuner_get_bbgain)(struct dvb_frontend *fe, u32 *gain); + int (*tuner_set_refclk)(struct dvb_frontend *fe, u32 refclk); + int (*tuner_get_status)(struct dvb_frontend *fe, u32 *status); + void (*tuner_i2c_lock)(struct dvb_frontend *fe, int lock); + + /* dir = 0 -> output, dir = 1 -> input/open-drain */ + int (*set_gpio)(struct dvb_frontend *fe, u8 gpio, u8 dir, u8 value, + u8 xor_value); }; #if IS_ENABLED(CONFIG_DVB_STV090x) -extern struct dvb_frontend *stv090x_attach(const struct stv090x_config *config, - struct i2c_adapter *i2c, - enum stv090x_demodulator demod); - -/* dir = 0 -> output, dir = 1 -> input/open-drain */ -extern int stv090x_set_gpio(struct dvb_frontend *fe, u8 gpio, - u8 dir, u8 value, u8 xor_value); +struct dvb_frontend *stv090x_attach(struct stv090x_config *config, + struct i2c_adapter *i2c, + enum stv090x_demodulator demod); #else @@ -123,12 +123,6 @@ static inline struct dvb_frontend *stv090x_attach(const struct stv090x_config *c return NULL; } -static inline int stv090x_set_gpio(struct dvb_frontend *fe, u8 gpio, - u8 opd, u8 value, u8 xor_value) -{ - printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__); - return -ENODEV; -} #endif /* CONFIG_DVB_STV090x */ #endif /* __STV090x_H */ diff --git a/drivers/media/dvb-frontends/tc90522.c b/drivers/media/dvb-frontends/tc90522.c index d9905fb52f84..b35d65c9cc05 100644 --- a/drivers/media/dvb-frontends/tc90522.c +++ b/drivers/media/dvb-frontends/tc90522.c @@ -216,32 +216,30 @@ static int tc90522s_get_frontend(struct dvb_frontend *fe) c->delivery_system = SYS_ISDBS; layers = 0; - ret = reg_read(state, 0xe8, val, 3); + ret = reg_read(state, 0xe6, val, 5); if (ret == 0) { - int slots; u8 v; + c->stream_id = val[0] << 8 | val[1]; + /* high/single layer */ - v = (val[0] & 0x70) >> 4; + v = (val[2] & 0x70) >> 4; c->modulation = (v == 7) ? PSK_8 : QPSK; c->fec_inner = fec_conv_sat[v]; c->layer[0].fec = c->fec_inner; c->layer[0].modulation = c->modulation; - c->layer[0].segment_count = val[1] & 0x3f; /* slots */ + c->layer[0].segment_count = val[3] & 0x3f; /* slots */ /* low layer */ - v = (val[0] & 0x07); + v = (val[2] & 0x07); c->layer[1].fec = fec_conv_sat[v]; if (v == 0) /* no low layer */ c->layer[1].segment_count = 0; else - c->layer[1].segment_count = val[2] & 0x3f; /* slots */ + c->layer[1].segment_count = val[4] & 0x3f; /* slots */ /* actually, BPSK if v==1, but not defined in fe_modulation_t */ c->layer[1].modulation = QPSK; layers = (v > 0) ? 2 : 1; - - slots = c->layer[0].segment_count + c->layer[1].segment_count; - c->symbol_rate = 28860000 * slots / 48; } /* statistics */ @@ -363,7 +361,7 @@ static int tc90522t_get_frontend(struct dvb_frontend *fe) u8 v; c->isdbt_partial_reception = val[0] & 0x01; - c->isdbt_sb_mode = (val[0] & 0xc0) == 0x01; + c->isdbt_sb_mode = (val[0] & 0xc0) == 0x40; /* layer A */ v = (val[2] & 0x78) >> 3; |