[PATCH 5/9] cxd2820r: wrap legacy DVBv3 statistics via DVBv5 statistics
Return DVBv5 statistics via legacy DVBv3 API. Signed-off-by: Antti Palosaari --- drivers/media/dvb-frontends/cxd2820r_c.c| 108 drivers/media/dvb-frontends/cxd2820r_core.c | 85 ++ drivers/media/dvb-frontends/cxd2820r_priv.h | 25 +-- drivers/media/dvb-frontends/cxd2820r_t.c| 94 drivers/media/dvb-frontends/cxd2820r_t2.c | 87 -- 5 files changed, 22 insertions(+), 377 deletions(-) diff --git a/drivers/media/dvb-frontends/cxd2820r_c.c b/drivers/media/dvb-frontends/cxd2820r_c.c index 7cdcd55..82df944 100644 --- a/drivers/media/dvb-frontends/cxd2820r_c.c +++ b/drivers/media/dvb-frontends/cxd2820r_c.c @@ -149,114 +149,6 @@ error: return ret; } -int cxd2820r_read_ber_c(struct dvb_frontend *fe, u32 *ber) -{ - struct cxd2820r_priv *priv = fe->demodulator_priv; - int ret; - u8 buf[3], start_ber = 0; - *ber = 0; - - if (priv->ber_running) { - ret = cxd2820r_rd_regs(priv, 0x10076, buf, sizeof(buf)); - if (ret) - goto error; - - if ((buf[2] >> 7) & 0x01 || (buf[2] >> 4) & 0x01) { - *ber = (buf[2] & 0x0f) << 16 | buf[1] << 8 | buf[0]; - start_ber = 1; - } - } else { - priv->ber_running = true; - start_ber = 1; - } - - if (start_ber) { - /* (re)start BER */ - ret = cxd2820r_wr_reg(priv, 0x10079, 0x01); - if (ret) - goto error; - } - - return ret; -error: - dev_dbg(&priv->i2c->dev, "%s: failed=%d\n", __func__, ret); - return ret; -} - -int cxd2820r_read_signal_strength_c(struct dvb_frontend *fe, - u16 *strength) -{ - struct cxd2820r_priv *priv = fe->demodulator_priv; - int ret; - u8 buf[2]; - u16 tmp; - - ret = cxd2820r_rd_regs(priv, 0x10049, buf, sizeof(buf)); - if (ret) - goto error; - - tmp = (buf[0] & 0x03) << 8 | buf[1]; - tmp = (~tmp & 0x03ff); - - if (tmp == 512) - /* ~no signal */ - tmp = 0; - else if (tmp > 350) - tmp = 350; - - /* scale value to 0x-0x */ - *strength = tmp * 0x / (350-0); - - return ret; -error: - dev_dbg(&priv->i2c->dev, "%s: failed=%d\n", __func__, ret); - return ret; -} - -int cxd2820r_read_snr_c(struct dvb_frontend *fe, u16 *snr) -{ - struct cxd2820r_priv *priv = fe->demodulator_priv; - int ret; - u8 tmp; - unsigned int A, B; - /* report SNR in dB * 10 */ - - ret = cxd2820r_rd_reg(priv, 0x10019, &tmp); - if (ret) - goto error; - - if (((tmp >> 0) & 0x03) % 2) { - A = 875; - B = 650; - } else { - A = 950; - B = 760; - } - - ret = cxd2820r_rd_reg(priv, 0x1004d, &tmp); - if (ret) - goto error; - - #define CXD2820R_LOG2_E_24 24204406 /* log2(e) << 24 */ - if (tmp) - *snr = A * (intlog2(B / tmp) >> 5) / (CXD2820R_LOG2_E_24 >> 5) - / 10; - else - *snr = 0; - - return ret; -error: - dev_dbg(&priv->i2c->dev, "%s: failed=%d\n", __func__, ret); - return ret; -} - -int cxd2820r_read_ucblocks_c(struct dvb_frontend *fe, u32 *ucblocks) -{ - *ucblocks = 0; - /* no way to read ? */ - return 0; -} - int cxd2820r_read_status_c(struct dvb_frontend *fe, enum fe_status *status) { struct cxd2820r_priv *priv = fe->demodulator_priv; diff --git a/drivers/media/dvb-frontends/cxd2820r_core.c b/drivers/media/dvb-frontends/cxd2820r_core.c index 314d3b8..66da821 100644 --- a/drivers/media/dvb-frontends/cxd2820r_core.c +++ b/drivers/media/dvb-frontends/cxd2820r_core.c @@ -345,101 +345,58 @@ static int cxd2820r_get_frontend(struct dvb_frontend *fe, static int cxd2820r_read_ber(struct dvb_frontend *fe, u32 *ber) { struct cxd2820r_priv *priv = fe->demodulator_priv; - int ret; dev_dbg(&priv->i2c->dev, "%s: delsys=%d\n", __func__, fe->dtv_property_cache.delivery_system); - switch (fe->dtv_property_cache.delivery_system) { - case SYS_DVBT: - ret = cxd2820r_read_ber_t(fe, ber); - break; - case SYS_DVBT2: - ret = cxd2820r_read_ber_t2(fe, ber); - break; - case SYS_DVBC_ANNEX_A: - ret = cxd2820r_read_ber_c(fe, ber); - break; - default: - ret = -EINVAL; - break; - } - return ret; + *ber =
[PATCH 6/9] cxd2820r: add I2C driver bindings
Add I2C driver bindings in order to support proper I2C driver registration with driver core. Signed-off-by: Antti Palosaari --- drivers/media/dvb-frontends/cxd2820r.h | 26 drivers/media/dvb-frontends/cxd2820r_c.c| 6 +- drivers/media/dvb-frontends/cxd2820r_core.c | 190 ++-- drivers/media/dvb-frontends/cxd2820r_priv.h | 7 +- drivers/media/dvb-frontends/cxd2820r_t.c| 6 +- drivers/media/dvb-frontends/cxd2820r_t2.c | 8 +- 6 files changed, 191 insertions(+), 52 deletions(-) diff --git a/drivers/media/dvb-frontends/cxd2820r.h b/drivers/media/dvb-frontends/cxd2820r.h index 56d4276..d77afe0 100644 --- a/drivers/media/dvb-frontends/cxd2820r.h +++ b/drivers/media/dvb-frontends/cxd2820r.h @@ -37,6 +37,32 @@ #define CXD2820R_TS_PARALLEL 0x30 #define CXD2820R_TS_PARALLEL_MSB 0x70 +/* + * I2C address: 0x6c, 0x6d + */ + +/** + * struct cxd2820r_platform_data - Platform data for the cxd2820r driver + * @ts_mode: TS mode. + * @ts_clk_inv: TS clock inverted. + * @if_agc_polarity: IF AGC polarity. + * @spec_inv: Input spectrum inverted. + * @gpio_chip_base: GPIO. + * @get_dvb_frontend: Get DVB frontend. + */ + +struct cxd2820r_platform_data { + u8 ts_mode; + bool ts_clk_inv; + bool if_agc_polarity; + bool spec_inv; + int **gpio_chip_base; + + struct dvb_frontend* (*get_dvb_frontend)(struct i2c_client *); +/* private: For legacy media attach wrapper. Do not set value. */ + bool attach_in_use; +}; + struct cxd2820r_config { /* Demodulator I2C address. * Driver determines DVB-C slave I2C address automatically from master diff --git a/drivers/media/dvb-frontends/cxd2820r_c.c b/drivers/media/dvb-frontends/cxd2820r_c.c index 82df944..0d036e1 100644 --- a/drivers/media/dvb-frontends/cxd2820r_c.c +++ b/drivers/media/dvb-frontends/cxd2820r_c.c @@ -42,9 +42,9 @@ int cxd2820r_set_frontend_c(struct dvb_frontend *fe) { 0x10059, 0x50, 0xff }, { 0x10087, 0x0c, 0x3c }, { 0x1008b, 0x07, 0xff }, - { 0x1001f, priv->cfg.if_agc_polarity << 7, 0x80 }, - { 0x10070, priv->cfg.ts_mode, 0xff }, - { 0x10071, !priv->cfg.ts_clock_inv << 4, 0x10 }, + { 0x1001f, priv->if_agc_polarity << 7, 0x80 }, + { 0x10070, priv->ts_mode, 0xff }, + { 0x10071, !priv->ts_clk_inv << 4, 0x10 }, }; dev_dbg(&priv->i2c->dev, "%s: frequency=%d symbol_rate=%d\n", __func__, diff --git a/drivers/media/dvb-frontends/cxd2820r_core.c b/drivers/media/dvb-frontends/cxd2820r_core.c index 66da821..cf5eed4 100644 --- a/drivers/media/dvb-frontends/cxd2820r_core.c +++ b/drivers/media/dvb-frontends/cxd2820r_core.c @@ -49,7 +49,7 @@ static int cxd2820r_wr_regs_i2c(struct cxd2820r_priv *priv, u8 i2c, u8 reg, buf[0] = reg; memcpy(&buf[1], val, len); - ret = i2c_transfer(priv->i2c, msg, 1); + ret = i2c_transfer(priv->client[0]->adapter, msg, 1); if (ret == 1) { ret = 0; } else { @@ -87,7 +87,7 @@ static int cxd2820r_rd_regs_i2c(struct cxd2820r_priv *priv, u8 i2c, u8 reg, return -EINVAL; } - ret = i2c_transfer(priv->i2c, msg, 2); + ret = i2c_transfer(priv->client[0]->adapter, msg, 2); if (ret == 2) { memcpy(val, buf, len); ret = 0; @@ -112,9 +112,9 @@ int cxd2820r_wr_regs(struct cxd2820r_priv *priv, u32 reginfo, u8 *val, /* select I2C */ if (i2c) - i2c_addr = priv->cfg.i2c_address | (1 << 1); /* DVB-C */ + i2c_addr = priv->client[1]->addr; /* DVB-C */ else - i2c_addr = priv->cfg.i2c_address; /* DVB-T/T2 */ + i2c_addr = priv->client[0]->addr; /* DVB-T/T2 */ /* switch bank if needed */ if (bank != priv->bank[i2c]) { @@ -138,9 +138,9 @@ int cxd2820r_rd_regs(struct cxd2820r_priv *priv, u32 reginfo, u8 *val, /* select I2C */ if (i2c) - i2c_addr = priv->cfg.i2c_address | (1 << 1); /* DVB-C */ + i2c_addr = priv->client[1]->addr; /* DVB-C */ else - i2c_addr = priv->cfg.i2c_address; /* DVB-T/T2 */ + i2c_addr = priv->client[0]->addr; /* DVB-T/T2 */ /* switch bank if needed */ if (bank != priv->bank[i2c]) { @@ -537,16 +537,12 @@ static int cxd2820r_get_frontend_algo(struct dvb_frontend *fe) static void cxd2820r_release(struct dvb_frontend *fe) { struct cxd2820r_priv *priv = fe->demodulator_priv; + struct i2c_client *client = priv->client[0]; dev_dbg(&priv->i2c->dev, "%s\n", __func__); -#ifdef CONFIG_GPIOLIB - /* remove GPIOs */ - if (priv->gpio_chip.label) - g
[PATCH 1/9] cxd2820r: improve IF frequency setting
Use 64-bit calculation. Return error if tuner does not provide get_if_frequency() callback. All currently used tuners has it. Signed-off-by: Antti Palosaari --- drivers/media/dvb-frontends/cxd2820r_c.c| 26 +++ drivers/media/dvb-frontends/cxd2820r_priv.h | 2 ++ drivers/media/dvb-frontends/cxd2820r_t.c| 27 --- drivers/media/dvb-frontends/cxd2820r_t2.c | 33 ++--- 4 files changed, 43 insertions(+), 45 deletions(-) diff --git a/drivers/media/dvb-frontends/cxd2820r_c.c b/drivers/media/dvb-frontends/cxd2820r_c.c index a674a63..957ec94 100644 --- a/drivers/media/dvb-frontends/cxd2820r_c.c +++ b/drivers/media/dvb-frontends/cxd2820r_c.c @@ -26,10 +26,9 @@ int cxd2820r_set_frontend_c(struct dvb_frontend *fe) struct cxd2820r_priv *priv = fe->demodulator_priv; struct dtv_frontend_properties *c = &fe->dtv_property_cache; int ret, i; + unsigned int utmp; u8 buf[2]; - u32 if_freq; - u16 if_ctl; - u64 num; + u32 if_frequency; struct reg_val_mask tab[] = { { 0x00080, 0x01, 0xff }, { 0x00081, 0x05, 0xff }, @@ -69,20 +68,19 @@ int cxd2820r_set_frontend_c(struct dvb_frontend *fe) /* program IF frequency */ if (fe->ops.tuner_ops.get_if_frequency) { - ret = fe->ops.tuner_ops.get_if_frequency(fe, &if_freq); + ret = fe->ops.tuner_ops.get_if_frequency(fe, &if_frequency); if (ret) goto error; - } else - if_freq = 0; - - dev_dbg(&priv->i2c->dev, "%s: if_freq=%d\n", __func__, if_freq); - - num = if_freq / 1000; /* Hz => kHz */ - num *= 0x4000; - if_ctl = 0x4000 - DIV_ROUND_CLOSEST_ULL(num, 41000); - buf[0] = (if_ctl >> 8) & 0x3f; - buf[1] = (if_ctl >> 0) & 0xff; + dev_dbg(&priv->i2c->dev, "%s: if_frequency=%u\n", __func__, + if_frequency); + } else { + ret = -EINVAL; + goto error; + } + utmp = 0x4000 - DIV_ROUND_CLOSEST_ULL((u64)if_frequency * 0x4000, CXD2820R_CLK); + buf[0] = (utmp >> 8) & 0xff; + buf[1] = (utmp >> 0) & 0xff; ret = cxd2820r_wr_regs(priv, 0x10042, buf, 2); if (ret) goto error; diff --git a/drivers/media/dvb-frontends/cxd2820r_priv.h b/drivers/media/dvb-frontends/cxd2820r_priv.h index e31c48e..acfae17 100644 --- a/drivers/media/dvb-frontends/cxd2820r_priv.h +++ b/drivers/media/dvb-frontends/cxd2820r_priv.h @@ -34,6 +34,8 @@ struct reg_val_mask { u8 mask; }; +#define CXD2820R_CLK 4100 + struct cxd2820r_priv { struct i2c_adapter *i2c; struct dvb_frontend fe; diff --git a/drivers/media/dvb-frontends/cxd2820r_t.c b/drivers/media/dvb-frontends/cxd2820r_t.c index 75ce7d8..67cc33b 100644 --- a/drivers/media/dvb-frontends/cxd2820r_t.c +++ b/drivers/media/dvb-frontends/cxd2820r_t.c @@ -26,8 +26,8 @@ int cxd2820r_set_frontend_t(struct dvb_frontend *fe) struct cxd2820r_priv *priv = fe->demodulator_priv; struct dtv_frontend_properties *c = &fe->dtv_property_cache; int ret, i, bw_i; - u32 if_freq, if_ctl; - u64 num; + unsigned int utmp; + u32 if_frequency; u8 buf[3], bw_param; u8 bw_params1[][5] = { { 0x17, 0xea, 0xaa, 0xaa, 0xaa }, /* 6 MHz */ @@ -93,21 +93,20 @@ int cxd2820r_set_frontend_t(struct dvb_frontend *fe) /* program IF frequency */ if (fe->ops.tuner_ops.get_if_frequency) { - ret = fe->ops.tuner_ops.get_if_frequency(fe, &if_freq); + ret = fe->ops.tuner_ops.get_if_frequency(fe, &if_frequency); if (ret) goto error; - } else - if_freq = 0; - - dev_dbg(&priv->i2c->dev, "%s: if_freq=%d\n", __func__, if_freq); - - num = if_freq / 1000; /* Hz => kHz */ - num *= 0x100; - if_ctl = DIV_ROUND_CLOSEST_ULL(num, 41000); - buf[0] = ((if_ctl >> 16) & 0xff); - buf[1] = ((if_ctl >> 8) & 0xff); - buf[2] = ((if_ctl >> 0) & 0xff); + dev_dbg(&priv->i2c->dev, "%s: if_frequency=%u\n", __func__, + if_frequency); + } else { + ret = -EINVAL; + goto error; + } + utmp = DIV_ROUND_CLOSEST_ULL((u64)if_frequency * 0x100, CXD2820R_CLK); + buf[0] = (utmp >> 16) & 0xff; + buf[1] = (utmp >> 8) & 0xff; + buf[2] = (utmp >> 0) & 0xff; ret = cxd2820r_wr_regs(priv, 0x000b6, buf, 3); if (ret) goto error; diff --git a/drivers/media/dvb-frontends/cxd2820r_t2.c b/drivers/media/
[PATCH 8/9] cxd2820r: improve lock detection
Check demod and ts locks and report lock status according to those. Signed-off-by: Antti Palosaari --- drivers/media/dvb-frontends/cxd2820r_c.c | 29 drivers/media/dvb-frontends/cxd2820r_t.c | 44 --- drivers/media/dvb-frontends/cxd2820r_t2.c | 26 ++ 3 files changed, 50 insertions(+), 49 deletions(-) diff --git a/drivers/media/dvb-frontends/cxd2820r_c.c b/drivers/media/dvb-frontends/cxd2820r_c.c index beb46a6..0f96add 100644 --- a/drivers/media/dvb-frontends/cxd2820r_c.c +++ b/drivers/media/dvb-frontends/cxd2820r_c.c @@ -160,25 +160,32 @@ int cxd2820r_read_status_c(struct dvb_frontend *fe, enum fe_status *status) struct i2c_client *client = priv->client[0]; struct dtv_frontend_properties *c = &fe->dtv_property_cache; int ret; - unsigned int utmp; + unsigned int utmp, utmp1, utmp2; u8 buf[3]; - *status = 0; - ret = cxd2820r_rd_regs(priv, 0x10088, buf, 2); + /* Lock detection */ + ret = cxd2820r_rd_reg(priv, 0x10088, &buf[0]); + if (ret) + goto error; + ret = cxd2820r_rd_reg(priv, 0x10073, &buf[1]); if (ret) goto error; - if (((buf[0] >> 0) & 0x01) == 1) { - *status |= FE_HAS_SIGNAL | FE_HAS_CARRIER | - FE_HAS_VITERBI | FE_HAS_SYNC; + utmp1 = (buf[0] >> 0) & 0x01; + utmp2 = (buf[1] >> 3) & 0x01; - if (((buf[1] >> 3) & 0x01) == 1) { - *status |= FE_HAS_SIGNAL | FE_HAS_CARRIER | - FE_HAS_VITERBI | FE_HAS_SYNC | FE_HAS_LOCK; - } + if (utmp1 == 1 && utmp2 == 1) { + *status = FE_HAS_SIGNAL | FE_HAS_CARRIER | + FE_HAS_VITERBI | FE_HAS_SYNC | FE_HAS_LOCK; + } else if (utmp1 == 1 || utmp2 == 1) { + *status = FE_HAS_SIGNAL | FE_HAS_CARRIER | + FE_HAS_VITERBI | FE_HAS_SYNC; + } else { + *status = 0; } - dev_dbg(&client->dev, "lock=%*ph\n", 2, buf); + dev_dbg(&client->dev, "status=%02x raw=%*ph sync=%u ts=%u\n", + *status, 2, buf, utmp1, utmp2); /* Signal strength */ if (*status & FE_HAS_SIGNAL) { diff --git a/drivers/media/dvb-frontends/cxd2820r_t.c b/drivers/media/dvb-frontends/cxd2820r_t.c index 174d916..19f72cd 100644 --- a/drivers/media/dvb-frontends/cxd2820r_t.c +++ b/drivers/media/dvb-frontends/cxd2820r_t.c @@ -265,42 +265,32 @@ int cxd2820r_read_status_t(struct dvb_frontend *fe, enum fe_status *status) struct i2c_client *client = priv->client[0]; struct dtv_frontend_properties *c = &fe->dtv_property_cache; int ret; - unsigned int utmp; - u8 buf[4]; - *status = 0; + unsigned int utmp, utmp1, utmp2; + u8 buf[3]; + /* Lock detection */ ret = cxd2820r_rd_reg(priv, 0x00010, &buf[0]); if (ret) goto error; + ret = cxd2820r_rd_reg(priv, 0x00073, &buf[1]); + if (ret) + goto error; - if ((buf[0] & 0x07) == 6) { - ret = cxd2820r_rd_reg(priv, 0x00073, &buf[1]); - if (ret) - goto error; + utmp1 = (buf[0] >> 0) & 0x07; + utmp2 = (buf[1] >> 3) & 0x01; - if (((buf[1] >> 3) & 0x01) == 1) { - *status |= FE_HAS_SIGNAL | FE_HAS_CARRIER | - FE_HAS_VITERBI | FE_HAS_SYNC | FE_HAS_LOCK; - } else { - *status |= FE_HAS_SIGNAL | FE_HAS_CARRIER | - FE_HAS_VITERBI | FE_HAS_SYNC; - } + if (utmp1 == 6 && utmp2 == 1) { + *status = FE_HAS_SIGNAL | FE_HAS_CARRIER | + FE_HAS_VITERBI | FE_HAS_SYNC | FE_HAS_LOCK; + } else if (utmp1 == 6 || utmp2 == 1) { + *status = FE_HAS_SIGNAL | FE_HAS_CARRIER | + FE_HAS_VITERBI | FE_HAS_SYNC; } else { - ret = cxd2820r_rd_reg(priv, 0x00014, &buf[2]); - if (ret) - goto error; - - if ((buf[2] & 0x0f) >= 4) { - ret = cxd2820r_rd_reg(priv, 0x00a14, &buf[3]); - if (ret) - goto error; - - if (((buf[3] >> 4) & 0x01) == 1) - *status |= FE_HAS_SIGNAL; - } + *status = 0; } - dev_dbg(&client->dev, "lock=%*ph\n", 4, buf); + dev_dbg(&client->dev, "status=%02x raw=%*ph sync=%u ts=%u\n", + *status, 2, buf, utmp1, utmp2); /* Signal s
[PATCH 2/9] cxd2820r: dvbv5 statistics for DVB-T
Implement dvbv5 statistics for DVB-T. Signed-off-by: Antti Palosaari --- drivers/media/dvb-frontends/cxd2820r_priv.h | 2 + drivers/media/dvb-frontends/cxd2820r_t.c| 88 + 2 files changed, 90 insertions(+) diff --git a/drivers/media/dvb-frontends/cxd2820r_priv.h b/drivers/media/dvb-frontends/cxd2820r_priv.h index acfae17..a97570b 100644 --- a/drivers/media/dvb-frontends/cxd2820r_priv.h +++ b/drivers/media/dvb-frontends/cxd2820r_priv.h @@ -27,6 +27,7 @@ #include "dvb_math.h" #include "cxd2820r.h" #include +#include struct reg_val_mask { u32 reg; @@ -40,6 +41,7 @@ struct cxd2820r_priv { struct i2c_adapter *i2c; struct dvb_frontend fe; struct cxd2820r_config cfg; + u64 post_bit_error; bool ber_running; diff --git a/drivers/media/dvb-frontends/cxd2820r_t.c b/drivers/media/dvb-frontends/cxd2820r_t.c index 67cc33b..d402ab6 100644 --- a/drivers/media/dvb-frontends/cxd2820r_t.c +++ b/drivers/media/dvb-frontends/cxd2820r_t.c @@ -351,7 +351,9 @@ int cxd2820r_read_ucblocks_t(struct dvb_frontend *fe, u32 *ucblocks) int cxd2820r_read_status_t(struct dvb_frontend *fe, enum fe_status *status) { struct cxd2820r_priv *priv = fe->demodulator_priv; + struct dtv_frontend_properties *c = &fe->dtv_property_cache; int ret; + unsigned int utmp; u8 buf[4]; *status = 0; @@ -388,6 +390,92 @@ int cxd2820r_read_status_t(struct dvb_frontend *fe, enum fe_status *status) dev_dbg(&priv->i2c->dev, "%s: lock=%*ph\n", __func__, 4, buf); + /* Signal strength */ + if (*status & FE_HAS_SIGNAL) { + unsigned int strength; + + ret = cxd2820r_rd_regs(priv, 0x00026, buf, 2); + if (ret) + goto error; + + utmp = buf[0] << 8 | buf[1] << 0; + utmp = ~utmp & 0x0fff; + /* Scale value to 0x-0x */ + strength = utmp << 4 | utmp >> 8; + + c->strength.len = 1; + c->strength.stat[0].scale = FE_SCALE_RELATIVE; + c->strength.stat[0].uvalue = strength; + } else { + c->strength.len = 1; + c->strength.stat[0].scale = FE_SCALE_NOT_AVAILABLE; + } + + /* CNR */ + if (*status & FE_HAS_VITERBI) { + unsigned int cnr; + + ret = cxd2820r_rd_regs(priv, 0x0002c, buf, 2); + if (ret) + goto error; + + utmp = buf[0] << 8 | buf[1] << 0; + if (utmp) + cnr = div_u64((u64)(intlog10(utmp) + - intlog10(32000 - utmp) + 55532585) + * 1, (1 << 24)); + else + cnr = 0; + + c->cnr.len = 1; + c->cnr.stat[0].scale = FE_SCALE_DECIBEL; + c->cnr.stat[0].svalue = cnr; + } else { + c->cnr.len = 1; + c->cnr.stat[0].scale = FE_SCALE_NOT_AVAILABLE; + } + + /* BER */ + if (*status & FE_HAS_SYNC) { + unsigned int post_bit_error; + bool start_ber; + + if (priv->ber_running) { + ret = cxd2820r_rd_regs(priv, 0x00076, buf, 3); + if (ret) + goto error; + + if ((buf[2] >> 7) & 0x01) { + post_bit_error = buf[2] << 16 | buf[1] << 8 | +buf[0] << 0; + post_bit_error &= 0x0f; + start_ber = true; + } else { + post_bit_error = 0; + start_ber = false; + } + } else { + post_bit_error = 0; + start_ber = true; + } + + if (start_ber) { + ret = cxd2820r_wr_reg(priv, 0x00079, 0x01); + if (ret) + goto error; + priv->ber_running = true; + } + + priv->post_bit_error += post_bit_error; + + c->post_bit_error.len = 1; + c->post_bit_error.stat[0].scale = FE_SCALE_COUNTER; + c->post_bit_error.stat[0].uvalue = priv->post_bit_error; + } else { + c->post_bit_error.len = 1; + c->post_bit_error.stat[0].scale = FE_SCALE_NOT_AVAILABLE; + } + return ret; error: dev_dbg(&priv->i2c->dev, "%s: failed=%d\n", __func__, ret); -- http://palosaari.fi/ -- To unsubscribe from this list: send the line "unsubscribe linux-media" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
[PATCH 7/9] cxd2820r: correct logging
Use correct device for logging functions as we now have it due to proper I2C client bindings. Signed-off-by: Antti Palosaari --- drivers/media/dvb-frontends/cxd2820r_c.c| 33 +--- drivers/media/dvb-frontends/cxd2820r_core.c | 115 +++- drivers/media/dvb-frontends/cxd2820r_t.c| 32 +--- drivers/media/dvb-frontends/cxd2820r_t2.c | 34 4 files changed, 123 insertions(+), 91 deletions(-) diff --git a/drivers/media/dvb-frontends/cxd2820r_c.c b/drivers/media/dvb-frontends/cxd2820r_c.c index 0d036e1..beb46a6 100644 --- a/drivers/media/dvb-frontends/cxd2820r_c.c +++ b/drivers/media/dvb-frontends/cxd2820r_c.c @@ -24,6 +24,7 @@ int cxd2820r_set_frontend_c(struct dvb_frontend *fe) { struct cxd2820r_priv *priv = fe->demodulator_priv; + struct i2c_client *client = priv->client[0]; struct dtv_frontend_properties *c = &fe->dtv_property_cache; int ret, i; unsigned int utmp; @@ -47,8 +48,10 @@ int cxd2820r_set_frontend_c(struct dvb_frontend *fe) { 0x10071, !priv->ts_clk_inv << 4, 0x10 }, }; - dev_dbg(&priv->i2c->dev, "%s: frequency=%d symbol_rate=%d\n", __func__, - c->frequency, c->symbol_rate); + dev_dbg(&client->dev, + "delivery_system=%d modulation=%d frequency=%u symbol_rate=%u inversion=%d\n", + c->delivery_system, c->modulation, c->frequency, + c->symbol_rate, c->inversion); /* program tuner */ if (fe->ops.tuner_ops.set_params) @@ -71,8 +74,7 @@ int cxd2820r_set_frontend_c(struct dvb_frontend *fe) ret = fe->ops.tuner_ops.get_if_frequency(fe, &if_frequency); if (ret) goto error; - dev_dbg(&priv->i2c->dev, "%s: if_frequency=%u\n", __func__, - if_frequency); + dev_dbg(&client->dev, "if_frequency=%u\n", if_frequency); } else { ret = -EINVAL; goto error; @@ -95,7 +97,7 @@ int cxd2820r_set_frontend_c(struct dvb_frontend *fe) return ret; error: - dev_dbg(&priv->i2c->dev, "%s: failed=%d\n", __func__, ret); + dev_dbg(&client->dev, "failed=%d\n", ret); return ret; } @@ -103,9 +105,12 @@ int cxd2820r_get_frontend_c(struct dvb_frontend *fe, struct dtv_frontend_properties *c) { struct cxd2820r_priv *priv = fe->demodulator_priv; + struct i2c_client *client = priv->client[0]; int ret; u8 buf[2]; + dev_dbg(&client->dev, "\n"); + ret = cxd2820r_rd_regs(priv, 0x1001a, buf, 2); if (ret) goto error; @@ -145,13 +150,14 @@ int cxd2820r_get_frontend_c(struct dvb_frontend *fe, return ret; error: - dev_dbg(&priv->i2c->dev, "%s: failed=%d\n", __func__, ret); + dev_dbg(&client->dev, "failed=%d\n", ret); return ret; } int cxd2820r_read_status_c(struct dvb_frontend *fe, enum fe_status *status) { struct cxd2820r_priv *priv = fe->demodulator_priv; + struct i2c_client *client = priv->client[0]; struct dtv_frontend_properties *c = &fe->dtv_property_cache; int ret; unsigned int utmp; @@ -172,8 +178,7 @@ int cxd2820r_read_status_c(struct dvb_frontend *fe, enum fe_status *status) } } - dev_dbg(&priv->i2c->dev, "%s: lock=%02x %02x\n", __func__, buf[0], - buf[1]); + dev_dbg(&client->dev, "lock=%*ph\n", 2, buf); /* Signal strength */ if (*status & FE_HAS_SIGNAL) { @@ -275,28 +280,32 @@ int cxd2820r_read_status_c(struct dvb_frontend *fe, enum fe_status *status) return ret; error: - dev_dbg(&priv->i2c->dev, "%s: failed=%d\n", __func__, ret); + dev_dbg(&client->dev, "failed=%d\n", ret); return ret; } int cxd2820r_init_c(struct dvb_frontend *fe) { struct cxd2820r_priv *priv = fe->demodulator_priv; + struct i2c_client *client = priv->client[0]; int ret; + dev_dbg(&client->dev, "\n"); + ret = cxd2820r_wr_reg(priv, 0x00085, 0x07); if (ret) goto error; return ret; error: - dev_dbg(&priv->i2c->dev, "%s: failed=%d\n", __func__, ret); + dev_dbg(&client->dev, "failed=%d\n", ret); return ret; } int cxd2820r_sleep_c(struct dvb_frontend *fe) { struct cxd2820r_priv *priv = fe->demodulator_priv; + struct i2c_client *client = priv->client[0]; int ret, i; struct reg_val_mask tab[] = {
[PATCH 9/9] cxd2820r: convert to regmap api
Use regmap for I2C register access. Signed-off-by: Antti Palosaari --- drivers/media/dvb-frontends/Kconfig | 1 + drivers/media/dvb-frontends/cxd2820r_c.c| 56 +++--- drivers/media/dvb-frontends/cxd2820r_core.c | 259 ++-- drivers/media/dvb-frontends/cxd2820r_priv.h | 6 +- drivers/media/dvb-frontends/cxd2820r_t.c| 55 +++--- drivers/media/dvb-frontends/cxd2820r_t2.c | 55 +++--- 6 files changed, 173 insertions(+), 259 deletions(-) diff --git a/drivers/media/dvb-frontends/Kconfig b/drivers/media/dvb-frontends/Kconfig index c645aa8..c4b67f7 100644 --- a/drivers/media/dvb-frontends/Kconfig +++ b/drivers/media/dvb-frontends/Kconfig @@ -463,6 +463,7 @@ config DVB_STV0367 config DVB_CXD2820R tristate "Sony CXD2820R" depends on DVB_CORE && I2C + select REGMAP_I2C default m if !MEDIA_SUBDRV_AUTOSELECT help Say Y when you want to support this frontend. diff --git a/drivers/media/dvb-frontends/cxd2820r_c.c b/drivers/media/dvb-frontends/cxd2820r_c.c index 0f96add..d75b077 100644 --- a/drivers/media/dvb-frontends/cxd2820r_c.c +++ b/drivers/media/dvb-frontends/cxd2820r_c.c @@ -26,7 +26,7 @@ int cxd2820r_set_frontend_c(struct dvb_frontend *fe) struct cxd2820r_priv *priv = fe->demodulator_priv; struct i2c_client *client = priv->client[0]; struct dtv_frontend_properties *c = &fe->dtv_property_cache; - int ret, i; + int ret; unsigned int utmp; u8 buf[2]; u32 if_frequency; @@ -58,12 +58,9 @@ int cxd2820r_set_frontend_c(struct dvb_frontend *fe) fe->ops.tuner_ops.set_params(fe); if (priv->delivery_system != SYS_DVBC_ANNEX_A) { - for (i = 0; i < ARRAY_SIZE(tab); i++) { - ret = cxd2820r_wr_reg_mask(priv, tab[i].reg, - tab[i].val, tab[i].mask); - if (ret) - goto error; - } + ret = cxd2820r_wr_reg_val_mask_tab(priv, tab, ARRAY_SIZE(tab)); + if (ret) + goto error; } priv->delivery_system = SYS_DVBC_ANNEX_A; @@ -83,15 +80,15 @@ int cxd2820r_set_frontend_c(struct dvb_frontend *fe) utmp = 0x4000 - DIV_ROUND_CLOSEST_ULL((u64)if_frequency * 0x4000, CXD2820R_CLK); buf[0] = (utmp >> 8) & 0xff; buf[1] = (utmp >> 0) & 0xff; - ret = cxd2820r_wr_regs(priv, 0x10042, buf, 2); + ret = regmap_bulk_write(priv->regmap[1], 0x0042, buf, 2); if (ret) goto error; - ret = cxd2820r_wr_reg(priv, 0x000ff, 0x08); + ret = regmap_write(priv->regmap[0], 0x00ff, 0x08); if (ret) goto error; - ret = cxd2820r_wr_reg(priv, 0x000fe, 0x01); + ret = regmap_write(priv->regmap[0], 0x00fe, 0x01); if (ret) goto error; @@ -107,21 +104,22 @@ int cxd2820r_get_frontend_c(struct dvb_frontend *fe, struct cxd2820r_priv *priv = fe->demodulator_priv; struct i2c_client *client = priv->client[0]; int ret; + unsigned int utmp; u8 buf[2]; dev_dbg(&client->dev, "\n"); - ret = cxd2820r_rd_regs(priv, 0x1001a, buf, 2); + ret = regmap_bulk_read(priv->regmap[1], 0x001a, buf, 2); if (ret) goto error; c->symbol_rate = 2500 * ((buf[0] & 0x0f) << 8 | buf[1]); - ret = cxd2820r_rd_reg(priv, 0x10019, &buf[0]); + ret = regmap_read(priv->regmap[1], 0x0019, &utmp); if (ret) goto error; - switch ((buf[0] >> 0) & 0x07) { + switch ((utmp >> 0) & 0x07) { case 0: c->modulation = QAM_16; break; @@ -139,7 +137,7 @@ int cxd2820r_get_frontend_c(struct dvb_frontend *fe, break; } - switch ((buf[0] >> 7) & 0x01) { + switch ((utmp >> 7) & 0x01) { case 0: c->inversion = INVERSION_OFF; break; @@ -164,10 +162,10 @@ int cxd2820r_read_status_c(struct dvb_frontend *fe, enum fe_status *status) u8 buf[3]; /* Lock detection */ - ret = cxd2820r_rd_reg(priv, 0x10088, &buf[0]); + ret = regmap_bulk_read(priv->regmap[1], 0x0088, &buf[0], 1); if (ret) goto error; - ret = cxd2820r_rd_reg(priv, 0x10073, &buf[1]); + ret = regmap_bulk_read(priv->regmap[1], 0x0073, &buf[1], 1); if (ret) goto error; @@ -191,7 +189,7 @@ int cxd2820r_read_status_c(struct dvb_frontend *fe, enum fe_status *status) if (*status & FE_HAS_SIGNAL) { unsigned int strength; - ret = cxd2820r_rd_regs(priv, 0x10049, buf, 2); + ret = regmap_bu
[PATCH 3/9] cxd2820r: dvbv5 statistics for DVB-T2
Implement dvbv5 statistics for DVB-T2. Signed-off-by: Antti Palosaari --- drivers/media/dvb-frontends/cxd2820r_t2.c | 77 ++- 1 file changed, 76 insertions(+), 1 deletion(-) diff --git a/drivers/media/dvb-frontends/cxd2820r_t2.c b/drivers/media/dvb-frontends/cxd2820r_t2.c index 14c9a26..e2875f2 100644 --- a/drivers/media/dvb-frontends/cxd2820r_t2.c +++ b/drivers/media/dvb-frontends/cxd2820r_t2.c @@ -286,8 +286,10 @@ error: int cxd2820r_read_status_t2(struct dvb_frontend *fe, enum fe_status *status) { struct cxd2820r_priv *priv = fe->demodulator_priv; + struct dtv_frontend_properties *c = &fe->dtv_property_cache; int ret; - u8 buf[1]; + unsigned int utmp; + u8 buf[4]; *status = 0; ret = cxd2820r_rd_reg(priv, 0x02010 , &buf[0]); @@ -306,6 +308,79 @@ int cxd2820r_read_status_t2(struct dvb_frontend *fe, enum fe_status *status) dev_dbg(&priv->i2c->dev, "%s: lock=%02x\n", __func__, buf[0]); + /* Signal strength */ + if (*status & FE_HAS_SIGNAL) { + unsigned int strength; + + ret = cxd2820r_rd_regs(priv, 0x02026, buf, 2); + if (ret) + goto error; + + utmp = buf[0] << 8 | buf[1] << 0; + utmp = ~utmp & 0x0fff; + /* Scale value to 0x-0x */ + strength = utmp << 4 | utmp >> 8; + + c->strength.len = 1; + c->strength.stat[0].scale = FE_SCALE_RELATIVE; + c->strength.stat[0].uvalue = strength; + } else { + c->strength.len = 1; + c->strength.stat[0].scale = FE_SCALE_NOT_AVAILABLE; + } + + /* CNR */ + if (*status & FE_HAS_VITERBI) { + unsigned int cnr; + + ret = cxd2820r_rd_regs(priv, 0x02028, buf, 2); + if (ret) + goto error; + + utmp = buf[0] << 8 | buf[1] << 0; + utmp = utmp & 0x0fff; + #define CXD2820R_LOG10_8_24 15151336 /* log10(8) << 24 */ + if (utmp) + cnr = div_u64((u64)(intlog10(utmp) + - CXD2820R_LOG10_8_24) * 1, + (1 << 24)); + else + cnr = 0; + + c->cnr.len = 1; + c->cnr.stat[0].scale = FE_SCALE_DECIBEL; + c->cnr.stat[0].svalue = cnr; + } else { + c->cnr.len = 1; + c->cnr.stat[0].scale = FE_SCALE_NOT_AVAILABLE; + } + + /* BER */ + if (*status & FE_HAS_SYNC) { + unsigned int post_bit_error; + + ret = cxd2820r_rd_regs(priv, 0x02039, buf, 4); + if (ret) + goto error; + + if ((buf[0] >> 4) & 0x01) { + post_bit_error = buf[0] << 24 | buf[1] << 16 | +buf[2] << 8 | buf[3] << 0; + post_bit_error &= 0x0fff; + } else { + post_bit_error = 0; + } + + priv->post_bit_error += post_bit_error; + + c->post_bit_error.len = 1; + c->post_bit_error.stat[0].scale = FE_SCALE_COUNTER; + c->post_bit_error.stat[0].uvalue = priv->post_bit_error; + } else { + c->post_bit_error.len = 1; + c->post_bit_error.stat[0].scale = FE_SCALE_NOT_AVAILABLE; + } + return ret; error: dev_dbg(&priv->i2c->dev, "%s: failed=%d\n", __func__, ret); -- http://palosaari.fi/ -- To unsubscribe from this list: send the line "unsubscribe linux-media" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
[PATCH 4/9] cxd2820r: dvbv5 statistics for DVB-C
Implement dvbv5 statistics for DVB-C. Signed-off-by: Antti Palosaari --- drivers/media/dvb-frontends/cxd2820r_c.c | 104 ++- 1 file changed, 102 insertions(+), 2 deletions(-) diff --git a/drivers/media/dvb-frontends/cxd2820r_c.c b/drivers/media/dvb-frontends/cxd2820r_c.c index 957ec94..7cdcd55 100644 --- a/drivers/media/dvb-frontends/cxd2820r_c.c +++ b/drivers/media/dvb-frontends/cxd2820r_c.c @@ -260,11 +260,13 @@ int cxd2820r_read_ucblocks_c(struct dvb_frontend *fe, u32 *ucblocks) int cxd2820r_read_status_c(struct dvb_frontend *fe, enum fe_status *status) { struct cxd2820r_priv *priv = fe->demodulator_priv; + struct dtv_frontend_properties *c = &fe->dtv_property_cache; int ret; - u8 buf[2]; + unsigned int utmp; + u8 buf[3]; *status = 0; - ret = cxd2820r_rd_regs(priv, 0x10088, buf, sizeof(buf)); + ret = cxd2820r_rd_regs(priv, 0x10088, buf, 2); if (ret) goto error; @@ -281,6 +283,104 @@ int cxd2820r_read_status_c(struct dvb_frontend *fe, enum fe_status *status) dev_dbg(&priv->i2c->dev, "%s: lock=%02x %02x\n", __func__, buf[0], buf[1]); + /* Signal strength */ + if (*status & FE_HAS_SIGNAL) { + unsigned int strength; + + ret = cxd2820r_rd_regs(priv, 0x10049, buf, 2); + if (ret) + goto error; + + utmp = buf[0] << 8 | buf[1] << 0; + utmp = 511 - sign_extend32(utmp, 9); + /* Scale value to 0x-0x */ + strength = utmp << 6 | utmp >> 4; + + c->strength.len = 1; + c->strength.stat[0].scale = FE_SCALE_RELATIVE; + c->strength.stat[0].uvalue = strength; + } else { + c->strength.len = 1; + c->strength.stat[0].scale = FE_SCALE_NOT_AVAILABLE; + } + + /* CNR */ + if (*status & FE_HAS_VITERBI) { + unsigned int cnr, const_a, const_b; + + ret = cxd2820r_rd_reg(priv, 0x10019, &buf[0]); + if (ret) + goto error; + + if (((buf[0] >> 0) & 0x03) % 2) { + const_a = 8750; + const_b = 650; + } else { + const_a = 9500; + const_b = 760; + } + + ret = cxd2820r_rd_reg(priv, 0x1004d, &buf[0]); + if (ret) + goto error; + + utmp = buf[0] << 0; + #define CXD2820R_LOG2_E_24 24204406 /* log2(e) << 24 */ + if (utmp) + cnr = div_u64((u64)(intlog2(const_b) - intlog2(utmp)) + * const_a, CXD2820R_LOG2_E_24); + else + cnr = 0; + + c->cnr.len = 1; + c->cnr.stat[0].scale = FE_SCALE_DECIBEL; + c->cnr.stat[0].svalue = cnr; + } else { + c->cnr.len = 1; + c->cnr.stat[0].scale = FE_SCALE_NOT_AVAILABLE; + } + + /* BER */ + if (*status & FE_HAS_SYNC) { + unsigned int post_bit_error; + bool start_ber; + + if (priv->ber_running) { + ret = cxd2820r_rd_regs(priv, 0x10076, buf, 3); + if (ret) + goto error; + + if ((buf[2] >> 7) & 0x01) { + post_bit_error = buf[2] << 16 | buf[1] << 8 | +buf[0] << 0; + post_bit_error &= 0x0f; + start_ber = true; + } else { + post_bit_error = 0; + start_ber = false; + } + } else { + post_bit_error = 0; + start_ber = true; + } + + if (start_ber) { + ret = cxd2820r_wr_reg(priv, 0x10079, 0x01); + if (ret) + goto error; + priv->ber_running = true; + } + + priv->post_bit_error += post_bit_error; + + c->post_bit_error.len = 1; + c->post_bit_error.stat[0].scale = FE_SCALE_COUNTER; + c->post_bit_error.stat[0].uvalue = priv->post_bit_error; + } else { + c->post_bit_error.len = 1; + c->post_bit_error.stat[0].scale = FE_SCALE_NOT_AVAILABLE; + } + return ret; error: dev_dbg(&priv->i2c->dev, "%s: failed=%d\n&
[PATCH] af9035: fix dual tuner detection with PCTV 79e
From: Stefan Pöschel The value 5 of the EEPROM_TS_MODE register (meaning dual tuner presence) is only valid for AF9035 devices. For IT9135 devices it is invalid and led to a false positive dual tuner mode detection with PCTV 79e. Therefore on non-AF9035 devices and with value 5 the driver now defaults to single tuner mode and outputs a regarding info message to log. This fixes Bugzilla bug #118561. (backport of 4.7) Fixes: b8278f8b961a ("[media] af9035: add support for 2nd tuner of MSI DigiVox Diversity") Cc: # 4.6 Reported-by: Marc Duponcheel Signed-off-by: Stefan Pöschel Signed-off-by: Antti Palosaari --- drivers/media/usb/dvb-usb-v2/af9035.c | 53 +++ drivers/media/usb/dvb-usb-v2/af9035.h | 2 +- 2 files changed, 36 insertions(+), 19 deletions(-) diff --git a/drivers/media/usb/dvb-usb-v2/af9035.c b/drivers/media/usb/dvb-usb-v2/af9035.c index 2638e32..14dbfeb 100644 --- a/drivers/media/usb/dvb-usb-v2/af9035.c +++ b/drivers/media/usb/dvb-usb-v2/af9035.c @@ -475,7 +475,8 @@ static struct i2c_algorithm af9035_i2c_algo = { static int af9035_identify_state(struct dvb_usb_device *d, const char **name) { struct state *state = d_to_priv(d); - int ret; + int ret, ts_mode_invalid; + u8 tmp; u8 wbuf[1] = { 1 }; u8 rbuf[4]; struct usb_req req = { CMD_FW_QUERYINFO, 0, sizeof(wbuf), wbuf, @@ -511,6 +512,38 @@ static int af9035_identify_state(struct dvb_usb_device *d, const char **name) state->eeprom_addr = EEPROM_BASE_AF9035; } + + /* check for dual tuner mode */ + ret = af9035_rd_reg(d, state->eeprom_addr + EEPROM_TS_MODE, &tmp); + if (ret < 0) + goto err; + + ts_mode_invalid = 0; + switch (tmp) { + case 0: + break; + case 1: + case 3: + state->dual_mode = true; + break; + case 5: + if (state->chip_type != 0x9135 && state->chip_type != 0x9306) + state->dual_mode = true;/* AF9035 */ + else + ts_mode_invalid = 1; + break; + default: + ts_mode_invalid = 1; + } + + dev_dbg(&d->udev->dev, "%s: ts mode=%d dual mode=%d\n", + __func__, tmp, state->dual_mode); + + if (ts_mode_invalid) + dev_info(&d->udev->dev, "%s: ts mode=%d not supported, defaulting to single tuner mode!", + __func__, tmp); + + ret = af9035_ctrl_msg(d, &req); if (ret < 0) goto err; @@ -680,11 +713,7 @@ static int af9035_download_firmware(struct dvb_usb_device *d, * which is done by master demod. * Master feeds also clock and controls power via GPIO. */ - ret = af9035_rd_reg(d, state->eeprom_addr + EEPROM_TS_MODE, &tmp); - if (ret < 0) - goto err; - - if (tmp == 1 || tmp == 3 || tmp == 5) { + if (state->dual_mode) { /* configure gpioh1, reset & power slave demod */ ret = af9035_wr_reg_mask(d, 0x00d8b0, 0x01, 0x01); if (ret < 0) @@ -817,18 +846,6 @@ static int af9035_read_config(struct dvb_usb_device *d) } - - /* check if there is dual tuners */ - ret = af9035_rd_reg(d, state->eeprom_addr + EEPROM_TS_MODE, &tmp); - if (ret < 0) - goto err; - - if (tmp == 1 || tmp == 3 || tmp == 5) - state->dual_mode = true; - - dev_dbg(&d->udev->dev, "%s: ts mode=%d dual mode=%d\n", __func__, - tmp, state->dual_mode); - if (state->dual_mode) { /* read 2nd demodulator I2C address */ ret = af9035_rd_reg(d, diff --git a/drivers/media/usb/dvb-usb-v2/af9035.h b/drivers/media/usb/dvb-usb-v2/af9035.h index df22001..d50ff15 100644 --- a/drivers/media/usb/dvb-usb-v2/af9035.h +++ b/drivers/media/usb/dvb-usb-v2/af9035.h @@ -112,7 +112,7 @@ static const u32 clock_lut_it9135[] = { * 0 TS * 1 DCA + PIP * 3 PIP - * 5 DCA + PIP + * 5 DCA + PIP (AF9035 only) * n DCA * * Values 0, 3 and 5 are seen to this day. 0 for single TS and 3/5 for dual TS. -- http://palosaari.fi/ -- To unsubscribe from this list: send the line "unsubscribe linux-media" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
[GIT PULL STABLE 4.6] af9035 regression
The following changes since commit 2dcd0af568b0cf583645c8a317dd12e344b1c72a: Linux 4.6 (2016-05-15 15:43:13 -0700) are available in the git repository at: git://linuxtv.org/anttip/media_tree.git af9035_fix for you to fetch changes up to 7bb87ff5255defe87916f32cd1fcef163a489339: af9035: fix dual tuner detection with PCTV 79e (2016-09-03 02:23:44 +0300) Stefan Pöschel (1): af9035: fix dual tuner detection with PCTV 79e drivers/media/usb/dvb-usb-v2/af9035.c | 53 +++-- drivers/media/usb/dvb-usb-v2/af9035.h | 2 +- 2 files changed, 36 insertions(+), 19 deletions(-) -- http://palosaari.fi/ -- To unsubscribe from this list: send the line "unsubscribe linux-media" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
Re: [GIT PULL STABLE 4.6] af9035 regression
On 09/09/2016 05:49 PM, Mauro Carvalho Chehab wrote: Hi Antti, Em Sat, 3 Sep 2016 02:40:52 +0300 Antti Palosaari escreveu: The following changes since commit 2dcd0af568b0cf583645c8a317dd12e344b1c72a: Linux 4.6 (2016-05-15 15:43:13 -0700) Is this patchset really meant to Kernel 4.6? if so, you should send the path to sta...@vger.kernel.org, c/c the mailing list. It helps to point the original patch that fixed the issue upstream, as they won't apply the fix if it was not fixed upstream yet. I think you already applied upstream patch, that one is just back-ported to 4.6. It is that patch: https://patchwork.linuxtv.org/patch/36795/ and it contains all the needed tags including Cc stable. Could you send it to stable? Antti Regards, Mauro are available in the git repository at: git://linuxtv.org/anttip/media_tree.git af9035_fix for you to fetch changes up to 7bb87ff5255defe87916f32cd1fcef163a489339: af9035: fix dual tuner detection with PCTV 79e (2016-09-03 02:23:44 +0300) Stefan Pöschel (1): af9035: fix dual tuner detection with PCTV 79e drivers/media/usb/dvb-usb-v2/af9035.c | 53 +++-- drivers/media/usb/dvb-usb-v2/af9035.h | 2 +- 2 files changed, 36 insertions(+), 19 deletions(-) Thanks, Mauro -- http://palosaari.fi/ -- To unsubscribe from this list: send the line "unsubscribe linux-media" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
[GIT PULL] cxd2820r improvements
The following changes since commit fb6609280db902bd5d34445fba1c926e95e63914: [media] dvb_frontend: Use memdup_user() rather than duplicating its implementation (2016-08-24 17:20:45 -0300) are available in the git repository at: git://linuxtv.org/anttip/media_tree.git cxd2820r for you to fetch changes up to 18905adf08ffc82417663539d1a703014505582f: cxd2820r: convert to regmap api (2016-09-03 01:30:22 +0300) Antti Palosaari (9): cxd2820r: improve IF frequency setting cxd2820r: dvbv5 statistics for DVB-T cxd2820r: dvbv5 statistics for DVB-T2 cxd2820r: dvbv5 statistics for DVB-C cxd2820r: wrap legacy DVBv3 statistics via DVBv5 statistics cxd2820r: add I2C driver bindings cxd2820r: correct logging cxd2820r: improve lock detection cxd2820r: convert to regmap api drivers/media/dvb-frontends/Kconfig | 1 + drivers/media/dvb-frontends/cxd2820r.h | 26 ++ drivers/media/dvb-frontends/cxd2820r_c.c| 302 +++--- drivers/media/dvb-frontends/cxd2820r_core.c | 597 +- drivers/media/dvb-frontends/cxd2820r_priv.h | 42 -- drivers/media/dvb-frontends/cxd2820r_t.c| 300 ++--- drivers/media/dvb-frontends/cxd2820r_t2.c | 278 +++- 7 files changed, 770 insertions(+), 776 deletions(-) -- http://palosaari.fi/ -- To unsubscribe from this list: send the line "unsubscribe linux-media" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
Re: [PATCH] [media] staging/media/cec: fix coding style error
On 09/11/2016 07:07 PM, Richard wrote: Greetings Linux Kernel Developers, This is Task 10 of the Eudyptula Challenge, i fix few line over 80 characters, hope you will accept this pacth. /Richard For the eudyptula challenge (http://eudyptula-challenge.org/). Simple style fix for few line over 80 characters - if (!is_broadcast && !is_reply && !adap->follower_cnt && + if (is_directed && !is_reply && !adap->follower_cnt && !! Antti -- http://palosaari.fi/ -- To unsubscribe from this list: send the line "unsubscribe linux-media" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
Re: [PATCH 00/26] Don't use stack for DMA transers on dvb-usb drivers
Hello If you use usb buffers from the state you will need add lock in order to protect concurrent access to buffer. There may have multiple concurrent operations from rc-polling/demux/frontend. Lets say you are reading ber and it sets data to buffer (state), then context switch to remote controller polling => buffer in state is overwritten, then context is changed back to ber reading and now there is bad data. regards Antti On 10/07/2016 08:24 PM, Mauro Carvalho Chehab wrote: Sending URB control messages from stack was never supported. Yet, on x86, the stack was usually at a memory region that allows DMA transfer. So, several drivers got it wrong. On Kernel 4.9, if VMAP_STACK=y, none of those drivers will work, as the stack won't be on a DMA-able area anymore. So, fix the dvb-usb drivers that requre it. Please notice that, while all those patches compile, I don't have devices using those drivers to test. So, I really appreciate if people with devices using those drivers could test and report if they don't break anything. Thanks! Mauro Mauro Carvalho Chehab (26): af9005: don't do DMA on stack cinergyT2-core: don't do DMA on stack cinergyT2-core:: handle error code on RC query cinergyT2-fe: cache stats at cinergyt2_fe_read_status() cinergyT2-fe: don't do DMA on stack cxusb: don't do DMA on stack dib0700: be sure that dib0700_ctrl_rd() users can do DMA dib0700_core: don't use stack on I2C reads dibusb: don't do DMA on stack dibusb: handle error code on RC query digitv: don't do DMA on stack dtt200u-fe: don't do DMA on stack dtt200u-fe: handle errors on USB control messages dtt200u: don't do DMA on stack dtt200u: handle USB control message errors dtv5100: : don't do DMA on stack gp8psk: don't do DMA on stack gp8psk: don't go past the buffer size nova-t-usb2: don't do DMA on stack pctv452e: don't do DMA on stack pctv452e: don't call BUG_ON() on non-fatal error technisat-usb2: use DMA buffers for I2C transfers dvb-usb: warn if return value for USB read/write routines is not checked nova-t-usb2: handle error code on RC query dw2102: return error if su3000_power_ctrl() fails digitv: handle error code on RC query drivers/media/usb/dvb-usb/af9005.c | 211 +++- drivers/media/usb/dvb-usb/cinergyT2-core.c | 52 --- drivers/media/usb/dvb-usb/cinergyT2-fe.c| 91 drivers/media/usb/dvb-usb/cxusb.c | 20 +-- drivers/media/usb/dvb-usb/cxusb.h | 5 + drivers/media/usb/dvb-usb/dib0700_core.c| 31 +++- drivers/media/usb/dvb-usb/dib0700_devices.c | 25 ++-- drivers/media/usb/dvb-usb/dibusb-common.c | 112 +++ drivers/media/usb/dvb-usb/dibusb.h | 5 + drivers/media/usb/dvb-usb/digitv.c | 26 ++-- drivers/media/usb/dvb-usb/digitv.h | 3 + drivers/media/usb/dvb-usb/dtt200u-fe.c | 90 drivers/media/usb/dvb-usb/dtt200u.c | 80 +++ drivers/media/usb/dvb-usb/dtv5100.c | 10 +- drivers/media/usb/dvb-usb/dvb-usb.h | 6 +- drivers/media/usb/dvb-usb/dw2102.c | 2 +- drivers/media/usb/dvb-usb/gp8psk.c | 25 +++- drivers/media/usb/dvb-usb/nova-t-usb2.c | 25 +++- drivers/media/usb/dvb-usb/pctv452e.c| 118 drivers/media/usb/dvb-usb/technisat-usb2.c | 16 ++- 20 files changed, 577 insertions(+), 376 deletions(-) -- http://palosaari.fi/ -- To unsubscribe from this list: send the line "unsubscribe linux-media" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
Re: [PATCH] [media] tda18212: fix use-after-free in tda18212_remove()
ridge] [ 154.028695] ddb_remove+0x3c/0xb0 [ddbridge] [ 154.028697] pci_device_remove+0x93/0x1d0 [ 154.028700] device_release_driver_internal+0x267/0x510 [ 154.028702] driver_detach+0xb9/0x1b0 [ 154.028705] bus_remove_driver+0xd0/0x1f0 [ 154.028707] pci_unregister_driver+0x25/0x210 [ 154.028711] module_exit_ddbridge+0xc/0x45 [ddbridge] [ 154.028714] SyS_delete_module+0x314/0x440 [ 154.028716] do_syscall_64+0x179/0x4c0 [ 154.028718] return_from_SYSCALL_64+0x0/0x65 [ 154.028729] The buggy address belongs to the object at 880108b55340 which belongs to the cache kmalloc-2048 of size 2048 [ 154.028755] The buggy address is located 408 bytes inside of 2048-byte region [880108b55340, 880108b55b40) [ 154.028778] The buggy address belongs to the page: [ 154.028792] page:ea00039e7a60 count:1 mapcount:0 mapping:880108b54240 index:0x0 compound_mapcount: 0 [ 154.028814] flags: 0x80008100(slab|head) [ 154.028830] raw: 80008100 880108b54240 00010003 [ 154.028848] raw: ea00039e7310 ea00039e7bd0 88010b000800 [ 154.028862] page dumped because: kasan: bad access detected [ 154.028883] Memory state around the buggy address: [ 154.028896] 880108b55380: fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb [ 154.028913] 880108b55400: fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb [ 154.028929] >880108b55480: fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb [ 154.028945] ^ [ 154.028960] 880108b55500: fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb [ 154.028976] 880108b55580: fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb [ 154.028991] == [ 154.029006] Disabling lock debugging due to kernel taint Fix this by removing the memcpy and the NULL assign. Cc: Antti Palosaari Signed-off-by: Daniel Scheller --- drivers/media/tuners/tda18212.c | 5 - 1 file changed, 5 deletions(-) diff --git a/drivers/media/tuners/tda18212.c b/drivers/media/tuners/tda18212.c index 7b8068354fea..ebccf8a8729d 100644 --- a/drivers/media/tuners/tda18212.c +++ b/drivers/media/tuners/tda18212.c @@ -258,12 +258,7 @@ static int tda18212_probe(struct i2c_client *client, static int tda18212_remove(struct i2c_client *client) { struct tda18212_dev *dev = i2c_get_clientdata(client); - struct dvb_frontend *fe = dev->cfg.fe; - dev_dbg(&client->dev, "\n"); - - memset(&fe->ops.tuner_ops, 0, sizeof(struct dvb_tuner_ops)); - fe->tuner_priv = NULL; kfree(dev); return 0; -- http://palosaari.fi/
Re: [PATCH] [media] tda18212: fix use-after-free in tda18212_remove()
On 12/15/2017 08:00 PM, Daniel Scheller wrote: Hi, On Fri, 15 Dec 2017 19:30:18 +0200 Antti Palosaari wrote: Thanks for your reply. Hello I think shared frontend structure, which is owned by demod driver, should be there and valid on time tuner driver is removed. And thus should not happen. Did you make driver unload on different order eg. not just reverse order than driver load? IMHO these should go always on load: 1) load demod driver (which makes shared frontend structure where also some tuner driver data lives) 2) load tuner driver 3) register frontend on unload 1) unregister frontend 2) remove tuner driver 3) remove demod driver (frees shared data) In ddbridge, we do (like in usb/em28xx and platform/sti/c8sectpfe, both also use some demod+tda18212 combo): dvb_unregister_frontend(); dvb_frontend_detach(); module_put(tda18212client->...owner); i2c_unregister_device(tda18212client); fe_detach() clears out the frontend references and frees/invalidates the allocated resources. tuner_ops obviously isn't there then anymore. yeah, but that's even ideally wrong. frontend design currently relies to shared data which is owned by demod driver and thus it should be last thing to be removed. Sure change like you did prevents issue, but logically it is still wrong and may not work on some other case. The two mentioned drivers will very likely yield the same (or similar) KASAN report. em28xx was even changed lately to do the teardown the way ddbridge does in 910b0797fa9e8 ([1], cc'ing Matthias here). With that commit in mind I'm a bit unsure on what is correct or not. OTOH, as dvb_frontend_detach() cleans up everything, IMHO there's no need for the tuner driver to try to clean up further. Please advise. [1] https://git.linuxtv.org/media_tree.git/commit/?id=910b0797fa9e8. em28xx does it currently just correct. 1) unregister frontend 2) remove I2C SEC 3) remove I2C tuner 4) remove I2C demod (frees shared frontend data) regards Antti -- http://palosaari.fi/
Re: [PATCH] [media] tda18212: fix use-after-free in tda18212_remove()
On 12/15/2017 08:40 PM, Daniel Scheller wrote: On Fri, 15 Dec 2017 20:12:18 +0200 Antti Palosaari wrote: On 12/15/2017 08:00 PM, Daniel Scheller wrote: Hi, On Fri, 15 Dec 2017 19:30:18 +0200 Antti Palosaari wrote: Thanks for your reply. Hello I think shared frontend structure, which is owned by demod driver, should be there and valid on time tuner driver is removed. And thus should not happen. Did you make driver unload on different order eg. not just reverse order than driver load? IMHO these should go always on load: 1) load demod driver (which makes shared frontend structure where also some tuner driver data lives) 2) load tuner driver 3) register frontend on unload 1) unregister frontend 2) remove tuner driver 3) remove demod driver (frees shared data) In ddbridge, we do (like in usb/em28xx and platform/sti/c8sectpfe, both also use some demod+tda18212 combo): dvb_unregister_frontend(); dvb_frontend_detach(); module_put(tda18212client->...owner); i2c_unregister_device(tda18212client); fe_detach() clears out the frontend references and frees/invalidates the allocated resources. tuner_ops obviously isn't there then anymore. yeah, but that's even ideally wrong. frontend design currently relies to shared data which is owned by demod driver and thus it should be last thing to be removed. Sure change like you did prevents issue, but logically it is still wrong and may not work on some other case. The two mentioned drivers will very likely yield the same (or similar) KASAN report. em28xx was even changed lately to do the teardown the way ddbridge does in 910b0797fa9e8 ([1], cc'ing Matthias here). With that commit in mind I'm a bit unsure on what is correct or not. OTOH, as dvb_frontend_detach() cleans up everything, IMHO there's no need for the tuner driver to try to clean up further. Please advise. [1] https://git.linuxtv.org/media_tree.git/commit/?id=910b0797fa9e8. em28xx does it currently just correct. 1) unregister frontend Note that this is a call to em28xx_unregister_dvb(), which in turn does dvb_unregister_frontend() and then dvb_frontend_detach() (at this stage, fe resources are gone). 2) remove I2C SEC 3) remove I2C tuner 4) remove I2C demod (frees shared frontend data) Yes, but ie. EM2874_BOARD_KWORLD_UB435Q_V3 is a combination of a "legacy" demod frontend - lgdt3305 actually - plus the tda18212 i2cclient (just like in ddb with stv0367+tda18212 or cxd2841er+tda18212), I'm sure this will yield the same report. Maybe another approach: Implement the tuner_ops.release callback, and then move the memset+NULL assignment right there (instead of just removing it), but this likely will cause issues when the i2c client is removed before detach if we don't keep track of this ie somewhere in tda18212_dev (new state var - if _remove is called, check if the tuner was released, and if not, call release (memset/set NULL), then free). Still with the two other drivers in mind though. If they're wrong aswell, I'll rather fix up ddbridge of course. Whole memset thing could be removed from tda18212, there is something likely wrong if those are needed. But it is another issue. Your main issue is somehow to get order of demod/tuner destroy correct. I don't even like idea whole shared frontend data is owned by the demod driver instance, but currently it is there and due to that this should be released lastly. General design goal is also do things like register things in order and unregister just reverse-order. regards Antti -- http://palosaari.fi/
Re: [PATCH 3/7] si2157: Add hybrid tuner support
stance) { + case 0: + goto fail; + case 1: + /* new tuner instance */ + dev_dbg(&client->dev, "%s(): new instance for tuner @0x%02x\n", + __func__, addr); + dev->addr = addr; + i2c_set_clientdata(client, dev); + + dev->fe = fe; + dev->chiptype = SI2157_CHIPTYPE_SI2157; + dev->if_frequency = 0; + dev->if_port = cfg->if_port; + dev->inversion = cfg->inversion; + + mutex_init(&dev->i2c_mutex); + INIT_DELAYED_WORK(&dev->stat_work, si2157_stat_work); + + break; + default: + /* existing tuner instance */ + dev_dbg(&client->dev, + "%s(): using existing instance for tuner @0x%02x\n", +__func__, addr); + break; + } + + /* check if the tuner is there */ + cmd.wlen = 0; + cmd.rlen = 1; + ret = si2157_cmd_execute(client, &cmd); + /* verify no i2c error and CTS is set */ + if (ret) { + dev_warn(&client->dev, "no HW found ret=%d\n", ret); + goto fail_instance; + } + + memcpy(&fe->ops.tuner_ops, &si2157_ops, sizeof(struct dvb_tuner_ops)); + +#ifdef CONFIG_MEDIA_CONTROLLER + if (instance == 1 && cfg->mdev) { + dev->mdev = cfg->mdev; + + dev->ent.name = KBUILD_MODNAME; + dev->ent.function = MEDIA_ENT_F_TUNER; + + dev->pad[TUNER_PAD_RF_INPUT].flags = MEDIA_PAD_FL_SINK; + dev->pad[TUNER_PAD_OUTPUT].flags = MEDIA_PAD_FL_SOURCE; + dev->pad[TUNER_PAD_AUD_OUT].flags = MEDIA_PAD_FL_SOURCE; + + ret = media_entity_pads_init(&dev->ent, TUNER_NUM_PADS, +&dev->pad[0]); + + if (ret) + goto fail_instance; + + ret = media_device_register_entity(cfg->mdev, &dev->ent); + if (ret) { + dev_warn(&client->dev, + "media_device_regiser_entity returns %d\n", ret); + media_entity_cleanup(&dev->ent); + goto fail_instance; + } + } +#endif + mutex_unlock(&si2157_list_mutex); + + if (instance != 1) + dev_info(&client->dev, "Silicon Labs %s successfully attached\n", + dev->chiptype == SI2157_CHIPTYPE_SI2141 ? "Si2141" : + dev->chiptype == SI2157_CHIPTYPE_SI2146 ? + "Si2146" : "Si2147/2148/2157/2158"); + + return fe; +fail_instance: + mutex_unlock(&si2157_list_mutex); + + si2157_release(fe); +fail: + dev_warn(&client->dev, "Attach failed\n"); + return NULL; +} +EXPORT_SYMBOL(si2157_attach); + +MODULE_DESCRIPTION("Silicon Labs Si2141/2146/2147/2148/2157/2158 silicon tuner driver"); MODULE_AUTHOR("Antti Palosaari "); MODULE_LICENSE("GPL"); MODULE_FIRMWARE(SI2158_A20_FIRMWARE); diff --git a/drivers/media/tuners/si2157.h b/drivers/media/tuners/si2157.h index de597fa..26b94ca 100644 --- a/drivers/media/tuners/si2157.h +++ b/drivers/media/tuners/si2157.h @@ -46,4 +46,18 @@ struct si2157_config { u8 if_port; }; +#if IS_REACHABLE(CONFIG_MEDIA_TUNER_SI2157) +extern struct dvb_frontend *si2157_attach(struct dvb_frontend *fe, u8 addr, + struct i2c_adapter *i2c, + struct si2157_config *cfg); +#else +static inline struct dvb_frontend *si2157_attach(struct dvb_frontend *fe, + u8 addr, + struct i2c_adapter *i2c, + struct si2157_config *cfg) +{ + pr_err("%s: driver disabled by Kconfig\n", __func__); + return NULL; +} +#endif #endif diff --git a/drivers/media/tuners/si2157_priv.h b/drivers/media/tuners/si2157_priv.h index e6436f7..2801aaa 100644 --- a/drivers/media/tuners/si2157_priv.h +++ b/drivers/media/tuners/si2157_priv.h @@ -19,15 +19,20 @@ #include #include +#include "tuner-i2c.h" #include "si2157.h" /* state struct */ struct si2157_dev { + struct list_head hybrid_tuner_instance_list; + struct tuner_i2c_props i2c_props; + struct mutex i2c_mutex; struct dvb_frontend *fe; bool active; bool inversion; u8 chiptype; + u8 addr; u8 if_port; u32 if_frequency; struct delayed_work stat_work; -- http://palosaari.fi/
Re: [PATCH 4/7] si2168: Add ts bus coontrol, turn off bus on sleep
Hello And what is rationale here, is there some use case demod must be active and ts set to tristate (disabled)? Just put demod sleep when you don't use it. regards Antti On 01/12/2018 06:19 PM, Brad Love wrote: Includes a function to set TS MODE property os si2168. The function either disables the TS output bus, or sets mode to config option. When going to sleep the TS bus is turned off, this makes the driver compatible with multiple frontend usage. Signed-off-by: Brad Love --- drivers/media/dvb-frontends/si2168.c | 38 drivers/media/dvb-frontends/si2168.h | 1 + 2 files changed, 31 insertions(+), 8 deletions(-) diff --git a/drivers/media/dvb-frontends/si2168.c b/drivers/media/dvb-frontends/si2168.c index 539399d..429c03a 100644 --- a/drivers/media/dvb-frontends/si2168.c +++ b/drivers/media/dvb-frontends/si2168.c @@ -409,6 +409,30 @@ static int si2168_set_frontend(struct dvb_frontend *fe) return ret; } +static int si2168_ts_bus_ctrl(struct dvb_frontend *fe, int acquire) +{ + struct i2c_client *client = fe->demodulator_priv; + struct si2168_dev *dev = i2c_get_clientdata(client); + struct si2168_cmd cmd; + int ret = 0; + + dev_dbg(&client->dev, "%s acquire: %d\n", __func__, acquire); + + /* set TS_MODE property */ + memcpy(cmd.args, "\x14\x00\x01\x10\x10\x00", 6); + if (acquire) + cmd.args[4] |= dev->ts_mode; + else + cmd.args[4] |= SI2168_TS_TRISTATE; + if (dev->ts_clock_gapped) + cmd.args[4] |= 0x40; + cmd.wlen = 6; + cmd.rlen = 4; + ret = si2168_cmd_execute(client, &cmd); + + return ret; +} + static int si2168_init(struct dvb_frontend *fe) { struct i2c_client *client = fe->demodulator_priv; @@ -540,14 +564,7 @@ static int si2168_init(struct dvb_frontend *fe) dev->version >> 24 & 0xff, dev->version >> 16 & 0xff, dev->version >> 8 & 0xff, dev->version >> 0 & 0xff); - /* set ts mode */ - memcpy(cmd.args, "\x14\x00\x01\x10\x10\x00", 6); - cmd.args[4] |= dev->ts_mode; - if (dev->ts_clock_gapped) - cmd.args[4] |= 0x40; - cmd.wlen = 6; - cmd.rlen = 4; - ret = si2168_cmd_execute(client, &cmd); + ret = si2168_ts_bus_ctrl(fe, 1); if (ret) goto err; @@ -584,6 +601,9 @@ static int si2168_sleep(struct dvb_frontend *fe) dev->active = false; + /* tri-state data bus */ + si2168_ts_bus_ctrl(fe, 0); + /* Firmware B 4.0-11 or later loses warm state during sleep */ if (dev->version > ('B' << 24 | 4 << 16 | 0 << 8 | 11 << 0)) dev->warm = false; @@ -681,6 +701,8 @@ static const struct dvb_frontend_ops si2168_ops = { .init = si2168_init, .sleep = si2168_sleep, + .ts_bus_ctrl = si2168_ts_bus_ctrl, + .set_frontend = si2168_set_frontend, .read_status = si2168_read_status, diff --git a/drivers/media/dvb-frontends/si2168.h b/drivers/media/dvb-frontends/si2168.h index 3225d0c..f48f0fb 100644 --- a/drivers/media/dvb-frontends/si2168.h +++ b/drivers/media/dvb-frontends/si2168.h @@ -38,6 +38,7 @@ struct si2168_config { /* TS mode */ #define SI2168_TS_PARALLEL0x06 #define SI2168_TS_SERIAL 0x03 +#define SI2168_TS_TRISTATE 0x00 u8 ts_mode; /* TS clock inverted */ -- http://palosaari.fi/
Re: [PATCH 6/7] si2168: Announce frontend creation failure
hmmm, IIRC driver core even prints some error when driver probe fails? After that you could enable module debug logging to see more information. So I don't see point for that change. regards Antti On 01/12/2018 06:19 PM, Brad Love wrote: The driver outputs on success, but is silent on failure. Give one message that probe failed. Signed-off-by: Brad Love --- drivers/media/dvb-frontends/si2168.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/media/dvb-frontends/si2168.c b/drivers/media/dvb-frontends/si2168.c index 429c03a..c1a638c 100644 --- a/drivers/media/dvb-frontends/si2168.c +++ b/drivers/media/dvb-frontends/si2168.c @@ -810,7 +810,7 @@ static int si2168_probe(struct i2c_client *client, err_kfree: kfree(dev); err: - dev_dbg(&client->dev, "failed=%d\n", ret); + dev_warn(&client->dev, "probe failed = %d\n", ret); return ret; } -- http://palosaari.fi/
Re: [PATCH 4/7] si2168: Add ts bus coontrol, turn off bus on sleep
On 01/16/2018 07:31 PM, Brad Love wrote: On 2018-01-15 23:07, Antti Palosaari wrote: Hello And what is rationale here, is there some use case demod must be active and ts set to tristate (disabled)? Just put demod sleep when you don't use it. regards Antti Hello Antti, Perhaps the .ts_bus_ctrl callback does not need to be included in ops, but the function is necessary. The demod is already put to sleep when not in use, but it leaves the ts bus open. The ts bus has no reason to be open when the demod is put to sleep. Leaving the ts bus open during sleep affects the other connected demod and nothing is received by it. The lgdt3306a driver already tri states its ts bus when put to sleep, the si2168 should as well. Sounds possible, but unlikely as chip is firmware driven. When you put chip to sleep you usually want set ts pins to tristate (also other unused pins) in order to save energy. I haven't never tested it anyway though, so it could be possible it leaves those pins to some other state like random output at given time. And if you cannot get stream from lgdt3306a, which is connected to same bus, it really sounds like ts bus pins are left some state (cannot work if same pin is driven high to other demod whilst other tries to drive it low. Setting ts pins to tri-state during sleep should resolve your issue. regards Antti -- http://palosaari.fi/
Re: [PATCH 4/7] si2168: Add ts bus coontrol, turn off bus on sleep
On 01/16/2018 10:14 PM, Brad Love wrote: On 2018-01-16 13:32, Antti Palosaari wrote: On 01/16/2018 07:31 PM, Brad Love wrote: On 2018-01-15 23:07, Antti Palosaari wrote: Hello And what is rationale here, is there some use case demod must be active and ts set to tristate (disabled)? Just put demod sleep when you don't use it. regards Antti Hello Antti, Perhaps the .ts_bus_ctrl callback does not need to be included in ops, but the function is necessary. The demod is already put to sleep when not in use, but it leaves the ts bus open. The ts bus has no reason to be open when the demod is put to sleep. Leaving the ts bus open during sleep affects the other connected demod and nothing is received by it. The lgdt3306a driver already tri states its ts bus when put to sleep, the si2168 should as well. Sounds possible, but unlikely as chip is firmware driven. When you put chip to sleep you usually want set ts pins to tristate (also other unused pins) in order to save energy. I haven't never tested it anyway though, so it could be possible it leaves those pins to some other state like random output at given time. And if you cannot get stream from lgdt3306a, which is connected to same bus, it really sounds like ts bus pins are left some state (cannot work if same pin is driven high to other demod whilst other tries to drive it low. Setting ts pins to tri-state during sleep should resolve your issue. Hello Antti, This patch fixes the issue I'm describing, hence why I submitted it. The ts bus must be tristated before putting the chip to sleep for the other demod to get a stream. I can test tri-state using power meter on some day, but it may be so small current that it cannot be seen usb power meter I use (YZXstudio, very nice small power meter). regards Antti -- http://palosaari.fi/
Re: [PATCH v2 1/2] si2168: Add spectrum inversion property
On 01/17/2018 11:52 PM, Brad Love wrote: Some tuners produce inverted spectrum, but the si2168 is not currently set up to accept it. This adds an optional parameter to set the frontend up to receive inverted spectrum. Parameter is optional and only boards who enable inversion will utilize this. Signed-off-by: Brad Love --- Changes since v1: - Embarassing build failure due to missing declaration. drivers/media/dvb-frontends/si2168.c | 3 +++ drivers/media/dvb-frontends/si2168.h | 3 +++ 2 files changed, 6 insertions(+) diff --git a/drivers/media/dvb-frontends/si2168.c b/drivers/media/dvb-frontends/si2168.c index c041e79..048b815 100644 --- a/drivers/media/dvb-frontends/si2168.c +++ b/drivers/media/dvb-frontends/si2168.c @@ -213,6 +213,7 @@ static int si2168_set_frontend(struct dvb_frontend *fe) struct i2c_client *client = fe->demodulator_priv; struct si2168_dev *dev = i2c_get_clientdata(client); struct dtv_frontend_properties *c = &fe->dtv_property_cache; + struct si2168_config *config = client->dev.platform_data; hmmm, are you sure platform data pointer points is const? I usually tend to store all config information to device state. Then there is no need to care if pointer is valid or not anymore. And inversion happens when those wires are cross-connected int ret; struct si2168_cmd cmd; u8 bandwidth, delivery_system; @@ -339,6 +340,8 @@ static int si2168_set_frontend(struct dvb_frontend *fe) memcpy(cmd.args, "\x14\x00\x0a\x10\x00\x00", 6); cmd.args[4] = delivery_system | bandwidth; + if (config->spectral_inversion) + cmd.args[5] |= 1; cmd.wlen = 6; cmd.rlen = 4; ret = si2168_cmd_execute(client, &cmd); diff --git a/drivers/media/dvb-frontends/si2168.h b/drivers/media/dvb-frontends/si2168.h index f48f0fb..d519edd 100644 --- a/drivers/media/dvb-frontends/si2168.h +++ b/drivers/media/dvb-frontends/si2168.h @@ -46,6 +46,9 @@ struct si2168_config { /* TS clock gapped */ bool ts_clock_gapped; + + /* Inverted spectrum */ + bool spectral_inversion; }; #endif -- http://palosaari.fi/
Re: [PATCH v2 1/2] si2168: Add spectrum inversion property
On 01/18/2018 03:58 AM, Brad Love wrote: On 2018-01-17 16:08, Brad Love wrote: On 2018-01-17 16:02, Antti Palosaari wrote: On 01/17/2018 11:52 PM, Brad Love wrote: Some tuners produce inverted spectrum, but the si2168 is not currently set up to accept it. This adds an optional parameter to set the frontend up to receive inverted spectrum. Parameter is optional and only boards who enable inversion will utilize this. Signed-off-by: Brad Love --- Changes since v1: - Embarassing build failure due to missing declaration. drivers/media/dvb-frontends/si2168.c | 3 +++ drivers/media/dvb-frontends/si2168.h | 3 +++ 2 files changed, 6 insertions(+) diff --git a/drivers/media/dvb-frontends/si2168.c b/drivers/media/dvb-frontends/si2168.c index c041e79..048b815 100644 --- a/drivers/media/dvb-frontends/si2168.c +++ b/drivers/media/dvb-frontends/si2168.c @@ -213,6 +213,7 @@ static int si2168_set_frontend(struct dvb_frontend *fe) struct i2c_client *client = fe->demodulator_priv; struct si2168_dev *dev = i2c_get_clientdata(client); struct dtv_frontend_properties *c = &fe->dtv_property_cache; + struct si2168_config *config = client->dev.platform_data; hmmm, are you sure platform data pointer points is const? I usually tend to store all config information to device state. Then there is no need to care if pointer is valid or not anymore. And inversion happens when those wires are cross-connected It just dawned on me that the platform_data is stack allocated and therefore not safe to access outside of probe. I will fix this momentarily. I was informed by one of our hardware guys that the two models in patch 2/2 are inverted spectrum, so I guess they have wires cross-connected. I can verify this again to be sure. Hello Antti, I have confirmation. No 'cross-connected' / swapped differential pair polarities (if that's what you meant) on the IF pins. The si2157 inverted spectrum output is configurable though, and Hauppauge have the tuner set up to output inverted. Sounds like it was a decision based on interoperability with older demods. yeah, that was what I was thinking for. That board single tuner and two demods which other demod does not support if spectrum inversion? If there is just si2168 and si2157, you can set both to invert or both to non-invert - the end result is same. Antti -- http://palosaari.fi/
Re: [PATCH 1/4] si2157: add detection of si2177 tuner
On 12/20/18 11:57 PM, Brad Love wrote: Works in ATSC and QAM as is, DVB is completely untested. Firmware required. Signed-off-by: Brad Love --- drivers/media/tuners/si2157.c | 6 ++ drivers/media/tuners/si2157_priv.h | 3 ++- #define SI2158_A20_FIRMWARE "dvb-tuner-si2158-a20-01.fw" #define SI2141_A10_FIRMWARE "dvb-tuner-si2141-a10-01.fw" - +#define SI2157_A30_FIRMWARE "dvb-tuner-si2157-a30-05.fw" Why you added 05 to that file name? I added that spare number for cases you have to replace firmware to another for some reason thus by default case it should be 01. regards Antti -- http://palosaari.fi/
Re: [PATCH 02/13] si2157: Check error status bit on cmd execute
On 12/29/18 7:51 PM, Brad Love wrote: Check error status bit on command execute, if error bit is set return -EAGAIN. Ignore -EAGAIN in probe during device check. Signed-off-by: Brad Love --- drivers/media/tuners/si2157.c | 12 +--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/drivers/media/tuners/si2157.c b/drivers/media/tuners/si2157.c index 4855448..3924c42 100644 --- a/drivers/media/tuners/si2157.c +++ b/drivers/media/tuners/si2157.c @@ -56,14 +56,20 @@ static int si2157_cmd_execute(struct i2c_client *client, struct si2157_cmd *cmd) break; } - dev_dbg(&client->dev, "cmd execution took %d ms\n", + dev_dbg(&client->dev, "cmd execution took %d ms, status=%x\n", jiffies_to_msecs(jiffies) - - (jiffies_to_msecs(timeout) - TIMEOUT)); + (jiffies_to_msecs(timeout) - TIMEOUT), + cmd->args[0]); if (!((cmd->args[0] >> 7) & 0x01)) { ret = -ETIMEDOUT; goto err_mutex_unlock; } + /* check error status bit */ + if (cmd->args[0] & 0x40) { + ret = -EAGAIN; + goto err_mutex_unlock; + } } mutex_unlock(&dev->i2c_mutex); @@ -477,7 +483,7 @@ static int si2157_probe(struct i2c_client *client, cmd.wlen = 0; cmd.rlen = 1; ret = si2157_cmd_execute(client, &cmd); - if (ret) + if (ret && (ret != -EAGAIN)) goto err_kfree; memcpy(&fe->ops.tuner_ops, &si2157_ops, sizeof(struct dvb_tuner_ops)); So you added check if firmware returns error during command execution, but that error is still skipped during probe, which does not feel correct. Chip should work during probe and ideally driver should ensure it is correct chip. At least you should read some property value or execute some other command without failure. regards Antti -- http://palosaari.fi/
Re: [PATCH] media: m88ds3103: serialize reset messages in m88ds3103_set_frontend
On 1/13/19 11:13 PM, James Hutchinson wrote: Ref: https://bugzilla.kernel.org/show_bug.cgi?id=199323 Users are experiencing problems with the DVBSky S960/S960C USB devices since the following commit: 9d659ae: ("locking/mutex: Add lock handoff to avoid starvation") The device malfunctions after running for an indeterminable period of time, and the problem can only be cleared by rebooting the machine. It is possible to encourage the problem to surface by blocking the signal to the LNB. Further debugging revealed the cause of the problem. In the following capture: - thread #1325 is running m88ds3103_set_frontend - thread #42 is running ts2020_stat_work a> [1325] usb 1-1: dvb_usb_v2_generic_io: >>> 08 68 02 07 80 [1325] usb 1-1: dvb_usb_v2_generic_io: <<< 08 [42] usb 1-1: dvb_usb_v2_generic_io: >>> 09 01 01 68 3f [42] usb 1-1: dvb_usb_v2_generic_io: <<< 08 ff [42] usb 1-1: dvb_usb_v2_generic_io: >>> 08 68 02 03 11 [42] usb 1-1: dvb_usb_v2_generic_io: <<< 07 [42] usb 1-1: dvb_usb_v2_generic_io: >>> 09 01 01 60 3d [42] usb 1-1: dvb_usb_v2_generic_io: <<< 07 ff b> [1325] usb 1-1: dvb_usb_v2_generic_io: >>> 08 68 02 07 00 [1325] usb 1-1: dvb_usb_v2_generic_io: <<< 07 [42] usb 1-1: dvb_usb_v2_generic_io: >>> 08 68 02 03 11 [42] usb 1-1: dvb_usb_v2_generic_io: <<< 07 [42] usb 1-1: dvb_usb_v2_generic_io: >>> 09 01 01 60 21 [42] usb 1-1: dvb_usb_v2_generic_io: <<< 07 ff [42] usb 1-1: dvb_usb_v2_generic_io: >>> 08 68 02 03 11 [42] usb 1-1: dvb_usb_v2_generic_io: <<< 07 [42] usb 1-1: dvb_usb_v2_generic_io: >>> 09 01 01 60 66 [42] usb 1-1: dvb_usb_v2_generic_io: <<< 07 ff [1325] usb 1-1: dvb_usb_v2_generic_io: >>> 08 68 02 03 11 [1325] usb 1-1: dvb_usb_v2_generic_io: <<< 07 [1325] usb 1-1: dvb_usb_v2_generic_io: >>> 08 60 02 10 0b [1325] usb 1-1: dvb_usb_v2_generic_io: <<< 07 Two i2c messages are sent to perform a reset in m88ds3103_set_frontend: a. 0x07, 0x80 b. 0x07, 0x00 However, as shown in the capture, the regmap mutex is being handed over to another thread (ts2020_stat_work) in between these two messages. From here, the device responds to every i2c message with an 07 message, and will only return to normal operation following a power cycle. Use regmap_multi_reg_write to group the two reset messages, ensuring both are processed before the regmap mutex is unlocked. I tried to reproduce that issue with pctv 461e, which has em28xx usb-interface, but without success. Even when I added some sleep between reset commands and increased tuner statistic polling interval such that it polls all the time, it works correctly. Device has tuner is connected to demod i2c bus, which I think is same for your device (it calls demod i2c mux select for every tuner i2c access). Taking into account tests I made it is probably issue with usb-interface i2c adapter instead - for some reason it stops working and starts returning 07 error all the time. Did any other I2C command succeed after failure? I mean is there any other i2c client on that bus you could test if it fails too on error situation? All in all, fix should be done to usb-interface i2c adapter if possible unless it has proven issue is somewhere else. You could try to add some sleep or repeat to i2c adapter in order to see if it helps. regards Antti -- http://palosaari.fi/
Re: [PATCH 04/13] si2157: Add clock and pin setup for si2141
On 12/29/18 7:51 PM, Brad Love wrote: Include some missing setup for si2141 Signed-off-by: Brad Love --- drivers/media/tuners/si2157.c | 17 + 1 file changed, 17 insertions(+) diff --git a/drivers/media/tuners/si2157.c b/drivers/media/tuners/si2157.c index f3a60a1..1ad2d42 100644 --- a/drivers/media/tuners/si2157.c +++ b/drivers/media/tuners/si2157.c @@ -236,6 +236,23 @@ static int si2157_init(struct dvb_frontend *fe) dev_info(&client->dev, "firmware version: %c.%c.%d\n", cmd.args[6], cmd.args[7], cmd.args[8]); + if (dev->chiptype == SI2157_CHIPTYPE_SI2141) { + /* set clock */ + memcpy(cmd.args, "\xc0\x00\x0d", 3); + cmd.wlen = 3; + cmd.rlen = 1; + ret = si2157_cmd_execute(client, &cmd); + if (ret) + goto err; + /* setup PIN */ + memcpy(cmd.args, "\x12\x80\x80\x85\x00\x81\x00", 7); + cmd.wlen = 7; + cmd.rlen = 7; + ret = si2157_cmd_execute(client, &cmd); + if (ret) + goto err; + } + /* enable tuner status flags */ memcpy(cmd.args, "\x14\x00\x01\x05\x01\x00", 6); cmd.wlen = 6; Si2141 is working in my understanding, why these are required? regards Antti -- http://palosaari.fi/
Re: [PATCH 12/13] si2157: add on-demand rf strength func
On 12/29/18 7:51 PM, Brad Love wrote: Add get_rf_strength callback to get RSSI from the tuner. DVBv5 stat cache is updated. Signed-off-by: Brad Love --- drivers/media/tuners/si2157.c | 38 +- 1 file changed, 37 insertions(+), 1 deletion(-) diff --git a/drivers/media/tuners/si2157.c b/drivers/media/tuners/si2157.c index 1737007..f28bf7f 100644 --- a/drivers/media/tuners/si2157.c +++ b/drivers/media/tuners/si2157.c @@ -752,6 +752,40 @@ static int si2157_get_if_frequency(struct dvb_frontend *fe, u32 *frequency) return 0; } +static int si2157_get_rf_strength(struct dvb_frontend *fe, u16 *rssi) +{ + struct i2c_client *client = fe->tuner_priv; + struct dtv_frontend_properties *c = &fe->dtv_property_cache; + struct si2157_cmd cmd; + int ret; + int strength; + + dev_dbg(&client->dev, "\n"); + + memcpy(cmd.args, "\x42\x00", 2); + cmd.wlen = 2; + cmd.rlen = 12; + ret = si2157_cmd_execute(client, &cmd); + if (ret) + goto err; + + c->strength.stat[0].scale = FE_SCALE_DECIBEL; + c->strength.stat[0].svalue = (s8) cmd.args[3] * 1000; + + strength = (s8)cmd.args[3]; + strength = (strength > -80) ? (u16)(strength + 100) : 0; + strength = strength > 80 ? 100 : strength; + + *rssi = (u16)(strength * 0x / 100); + dev_dbg(&client->dev, "%s: strength=%d rssi=%u\n", + __func__, (s8)cmd.args[3], *rssi); + + return 0; +err: + dev_dbg(&client->dev, "failed=%d\n", ret); + return ret; +} + static const struct dvb_tuner_ops si2157_ops = { .info = { .name = "Silicon Labs Si2141/Si2146/2147/2148/2157/2158", @@ -765,7 +799,9 @@ static const struct dvb_tuner_ops si2157_ops = { .set_analog_params = si2157_set_analog_params, .get_frequency = si2157_get_frequency, .get_bandwidth = si2157_get_bandwidth, - .get_if_frequency = si2157_get_if_frequency, + .get_if_frequency = si2157_get_if_frequency, + + .get_rf_strength = si2157_get_rf_strength, }; static void si2157_stat_work(struct work_struct *work) Where that is called from? It is also hard to read how you convert dBm RSSI value to some other scale. There is various clamp() macros for limiting value to desired range. __func__ should not be passed to dev_ macros, check some manual how to use. Driver already polls rssi for digital tv, but I assume that is somehow related to analog. regards Antti -- http://palosaari.fi/
Re: [PATCH] media: m88ds3103: serialize reset messages in m88ds3103_set_frontend
On 1/22/19 1:08 PM, James Hutchinson wrote: On Sun, Jan 20, 2019 at 04:43:08PM +0200, Antti Palosaari wrote: On 1/13/19 11:13 PM, James Hutchinson wrote: Ref: https://bugzilla.kernel.org/show_bug.cgi?id=199323 Users are experiencing problems with the DVBSky S960/S960C USB devices since the following commit: 9d659ae: ("locking/mutex: Add lock handoff to avoid starvation") The device malfunctions after running for an indeterminable period of time, and the problem can only be cleared by rebooting the machine. It is possible to encourage the problem to surface by blocking the signal to the LNB. Further debugging revealed the cause of the problem. In the following capture: - thread #1325 is running m88ds3103_set_frontend - thread #42 is running ts2020_stat_work a> [1325] usb 1-1: dvb_usb_v2_generic_io: >>> 08 68 02 07 80 [1325] usb 1-1: dvb_usb_v2_generic_io: <<< 08 [42] usb 1-1: dvb_usb_v2_generic_io: >>> 09 01 01 68 3f [42] usb 1-1: dvb_usb_v2_generic_io: <<< 08 ff [42] usb 1-1: dvb_usb_v2_generic_io: >>> 08 68 02 03 11 [42] usb 1-1: dvb_usb_v2_generic_io: <<< 07 [42] usb 1-1: dvb_usb_v2_generic_io: >>> 09 01 01 60 3d [42] usb 1-1: dvb_usb_v2_generic_io: <<< 07 ff b> [1325] usb 1-1: dvb_usb_v2_generic_io: >>> 08 68 02 07 00 [1325] usb 1-1: dvb_usb_v2_generic_io: <<< 07 [42] usb 1-1: dvb_usb_v2_generic_io: >>> 08 68 02 03 11 [42] usb 1-1: dvb_usb_v2_generic_io: <<< 07 [42] usb 1-1: dvb_usb_v2_generic_io: >>> 09 01 01 60 21 [42] usb 1-1: dvb_usb_v2_generic_io: <<< 07 ff [42] usb 1-1: dvb_usb_v2_generic_io: >>> 08 68 02 03 11 [42] usb 1-1: dvb_usb_v2_generic_io: <<< 07 [42] usb 1-1: dvb_usb_v2_generic_io: >>> 09 01 01 60 66 [42] usb 1-1: dvb_usb_v2_generic_io: <<< 07 ff [1325] usb 1-1: dvb_usb_v2_generic_io: >>> 08 68 02 03 11 [1325] usb 1-1: dvb_usb_v2_generic_io: <<< 07 [1325] usb 1-1: dvb_usb_v2_generic_io: >>> 08 60 02 10 0b [1325] usb 1-1: dvb_usb_v2_generic_io: <<< 07 Two i2c messages are sent to perform a reset in m88ds3103_set_frontend: a. 0x07, 0x80 b. 0x07, 0x00 However, as shown in the capture, the regmap mutex is being handed over to another thread (ts2020_stat_work) in between these two messages. From here, the device responds to every i2c message with an 07 message, and will only return to normal operation following a power cycle. Use regmap_multi_reg_write to group the two reset messages, ensuring both are processed before the regmap mutex is unlocked. I tried to reproduce that issue with pctv 461e, which has em28xx usb-interface, but without success. Even when I added some sleep between reset commands and increased tuner statistic polling interval such that it polls all the time, it works correctly. Device has tuner is connected to demod i2c bus, which I think is same for your device (it calls demod i2c mux select for every tuner i2c access). Taking into account tests I made it is probably issue with usb-interface i2c adapter instead - for some reason it stops working and starts returning 07 error all the time. Did any other I2C command succeed after failure? I mean is there any other i2c client on that bus you could test if it fails too on error situation? All in all, fix should be done to usb-interface i2c adapter if possible unless it has proven issue is somewhere else. You could try to add some sleep or repeat to i2c adapter in order to see if it helps. regards Antti -- http://palosaari.fi/ Thanks for taking the time to review my patch. My device is the dvbsky usb s960 which is a pretty popular device and hasn't been working for several users since commit 9d659ae. I did some further investigation and can now see that the issue likely only affects adapters which use the m88ds3103_get_agc_pwm function to get the AGC from the demodulator as part of ts2020_stat_work. This is the 3f message in my original capture, which gets an ff response. [42] usb 1-1: dvb_usb_v2_generic_io: >>> 09 01 01 68 3f [42] usb 1-1: dvb_usb_v2_generic_io: <<< 08 ff The m88ds3103_get_agc_pwm function looks to be used by a subset of devices and their variants from the dvbsky usb-interface (s960 & s960c), and the cx23885-dvb pci-interface (s950, s950c, s952). The problem does NOT occur if I disable auto-gain correction by removing the following line from dvbsky_s960_attach: ts2020_config.get_agc_pwm = m88ds3103_get_agc_pwm; I then have the same experience as you; I can add a sleep between the reset commands and increase the tuner statistic polling interval, and it still works correctly. I can also reproduce the issue on older kernels (pre-commit 9d659ae) by adding a sleep between the two reset commands and leaving the agc re
Re: [PATCH] dvb_usb_dvbsky: Mygica T230C2 add support for T230C hw version 2
On 6/8/19 5:49 AM, JP wrote: I made the Mygica T230c2 work on kernel 5.1.7, but I have no idea how to submit this. http://jpvw.nl/pub/test/dvb/linux-5.1.7-t230c2.patch Please can someone help me out. It looks like the extra code in the demodulator does not effect other drivers that use it. Tested with a T230, they bothseem to work OK. Jan Pieter van Woerkom diff -ru a/drivers/media/dvb-frontends/si2168.c b/drivers/media/dvb-frontends/si2168.c --- a/drivers/media/dvb-frontends/si2168.c 2019-06-04 07:59:45.0 +0200 +++ b/drivers/media/dvb-frontends/si2168.c 2019-06-07 22:49:21.226337473 +0200 @@ -91,8 +91,16 @@ dev_dbg(&client->dev, "%s acquire: %d\n", __func__, acquire); + /* set ts clock freq to 10Mhz */ + memcpy(cmd.args, "\x14\x00\x0d\x10\xe8\x03", 6); + cmd.wlen = 6; + cmd.rlen = 4; + ret = si2168_cmd_execute(client, &cmd); + if (ret) return ret; + 0x03e8 is 1000 and value used is 10 000Hz steps ==> 10 000 000 = 10MHz. Which means 8bit parallel ts bus has capacity of 80Mbit/s which sounds correct max for DVB-T2. What is default value set to that property? Many times those default values are just correct. /* set TS_MODE property */ - memcpy(cmd.args, "\x14\x00\x01\x10\x10\x00", 6); + memcpy(cmd.args, "\x14\x00\x01\x10\x00\x00", 6); + cmd.args[4] = dev->ts_mode & 0x30; if (acquire) cmd.args[4] |= dev->ts_mode; else And that enables use of own value. Anyhow, I don't like idea of piggybacking those "magic" bits on ts mode configuration variable. It is better to define own configuration value for ts clock on use it when it is set. diff -ru a/drivers/media/usb/dvb-usb-v2/dvbsky.c b/drivers/media/usb/dvb-usb-v2/dvbsky.c --- a/drivers/media/usb/dvb-usb-v2/dvbsky.c 2019-06-04 07:59:45.0 +0200 +++ b/drivers/media/usb/dvb-usb-v2/dvbsky.c 2019-06-07 16:47:32.141530489 +0200 @@ -560,6 +560,9 @@ si2168_config.i2c_adapter = &i2c_adapter; si2168_config.fe = &adap->fe[0]; si2168_config.ts_mode = SI2168_TS_PARALLEL; + if (d->udev->descriptor.idProduct == USB_PID_MYGICA_T230C2) + si2168_config.ts_mode |= 0x20; si2168_config.ts_clock_inv = 1; state->i2c_client_demod = dvb_module_probe("si2168", NULL, @@ -799,6 +802,9 @@ { DVB_USB_DEVICE(USB_VID_CONEXANT, USB_PID_MYGICA_T230C, &mygica_t230c_props, "MyGica Mini DVB-T2 USB Stick T230C", RC_MAP_TOTAL_MEDIA_IN_HAND_02) }, + { DVB_USB_DEVICE(USB_VID_CONEXANT, USB_PID_MYGICA_T230C2, + &mygica_t230c_props, "MyGica Mini DVB-T2 USB Stick T230C2", + RC_MAP_TOTAL_MEDIA_IN_HAND_02) }, { } }; MODULE_DEVICE_TABLE(usb, dvbsky_id_table); diff -ru a/include/media/dvb-usb-ids.h b/include/media/dvb-usb-ids.h --- a/include/media/dvb-usb-ids.h 2019-06-04 07:59:45.0 +0200 +++ b/include/media/dvb-usb-ids.h 2019-06-06 17:32:32.159187000 +0200 @@ -387,6 +387,7 @@ #define USB_PID_MYGICA_D689 0xd811 #define USB_PID_MYGICA_T230 0xc688 #define USB_PID_MYGICA_T230C 0xc689 +#define USB_PID_MYGICA_T230C2 0xc68a #define USB_PID_ELGATO_EYETV_DIVERSITY 0x0011 #define USB_PID_ELGATO_EYETV_DTT 0x0021 #define USB_PID_ELGATO_EYETV_DTT_2 0x003f What is that T230C2 stick? Naming sounds like a DVB-C2 capable, but I found only T230C model from MyGica site. Where I can get one? And also patch should be split to two logical parts, first add manual ts frequency support to si2168 and then other patch which adds device itself. And which are tuner and demod versions/revisions used for that device? regards Antti -- http://palosaari.fi/
Re: [PATCH] dvb_usb_dvbsky: Mygica T230C2 add support for T230C hw version 2
On 6/12/19 2:27 AM, JP wrote: On 6/12/19 12:28 AM, Antti Palosaari wrote: On 6/8/19 5:49 AM, JP wrote: I made the Mygica T230c2 work on kernel 5.1.7, but I have no idea how to submit this. http://jpvw.nl/pub/test/dvb/linux-5.1.7-t230c2.patch Please can someone help me out. It looks like the extra code in the demodulator does not effect other drivers that use it. Tested with a T230, they bothseem to work OK. Jan Pieter van Woerkom diff -ru a/drivers/media/dvb-frontends/si2168.c b/drivers/media/dvb-frontends/si2168.c --- a/drivers/media/dvb-frontends/si2168.c 2019-06-04 07:59:45.0 +0200 +++ b/drivers/media/dvb-frontends/si2168.c 2019-06-07 22:49:21.226337473 +0200 @@ -91,8 +91,16 @@ dev_dbg(&client->dev, "%s acquire: %d\n", __func__, acquire); + /* set ts clock freq to 10Mhz */ + memcpy(cmd.args, "\x14\x00\x0d\x10\xe8\x03", 6); + cmd.wlen = 6; + cmd.rlen = 4; + ret = si2168_cmd_execute(client, &cmd); + if (ret) return ret; + 0x03e8 is 1000 and value used is 10 000Hz steps ==> 10 000 000 = 10MHz. Which means 8bit parallel ts bus has capacity of 80Mbit/s which sounds correct max for DVB-T2. What is default value set to that property? Many times those default values are just correct. The default value *is* 10Mhz. On all other si2168 hardware this does not need to be set but for some reason, on this hardware it needs to be set manually. The actual value has been scanned from the running windows driver by means of a USB logger. My best guess is that this whole si2168 driver has been written with the help of such a logger. If the default value is already 10MHz then there is no need to set it at all. I am a bit too lazy to start dumping that default value out from the chip atm. /* set TS_MODE property */ - memcpy(cmd.args, "\x14\x00\x01\x10\x10\x00", 6); + memcpy(cmd.args, "\x14\x00\x01\x10\x00\x00", 6); + cmd.args[4] = dev->ts_mode & 0x30; if (acquire) cmd.args[4] |= dev->ts_mode; else And that enables use of own value. Anyhow, I don't like idea of piggybacking those "magic" bits on ts mode configuration variable. It is better to define own configuration value for ts clock on use it when it is set. In other cases I immediately would agree, but actually, all bits in the hw register correspond with the bits in the ts mode configuration variable. When I discovered that, I could not resist making use of it. The code is very compact this way. But all right, you convinced me. I guess :-) You may also define flag for TS_MODE_PARALLEL_10MHZ or so. IIRC, (haven't been there for a while), it is 10 and 16MHz used widely for parallel ts. So freely configurable ts clock may be a bit overkill still :] Own media/dvb wide datatype for ts settings could be nice if someone ever wants to implement such. diff -ru a/drivers/media/usb/dvb-usb-v2/dvbsky.c b/drivers/media/usb/dvb-usb-v2/dvbsky.c --- a/drivers/media/usb/dvb-usb-v2/dvbsky.c 2019-06-04 07:59:45.0 +0200 +++ b/drivers/media/usb/dvb-usb-v2/dvbsky.c 2019-06-07 16:47:32.141530489 +0200 @@ -560,6 +560,9 @@ si2168_config.i2c_adapter = &i2c_adapter; si2168_config.fe = &adap->fe[0]; si2168_config.ts_mode = SI2168_TS_PARALLEL; + if (d->udev->descriptor.idProduct == USB_PID_MYGICA_T230C2) + si2168_config.ts_mode |= 0x20; si2168_config.ts_clock_inv = 1; state->i2c_client_demod = dvb_module_probe("si2168", NULL, @@ -799,6 +802,9 @@ { DVB_USB_DEVICE(USB_VID_CONEXANT, USB_PID_MYGICA_T230C, &mygica_t230c_props, "MyGica Mini DVB-T2 USB Stick T230C", RC_MAP_TOTAL_MEDIA_IN_HAND_02) }, + { DVB_USB_DEVICE(USB_VID_CONEXANT, USB_PID_MYGICA_T230C2, + &mygica_t230c_props, "MyGica Mini DVB-T2 USB Stick T230C2", + RC_MAP_TOTAL_MEDIA_IN_HAND_02) }, { } }; MODULE_DEVICE_TABLE(usb, dvbsky_id_table); diff -ru a/include/media/dvb-usb-ids.h b/include/media/dvb-usb-ids.h --- a/include/media/dvb-usb-ids.h 2019-06-04 07:59:45.0 +0200 +++ b/include/media/dvb-usb-ids.h 2019-06-06 17:32:32.159187000 +0200 @@ -387,6 +387,7 @@ #define USB_PID_MYGICA_D689 0xd811 #define USB_PID_MYGICA_T230 0xc688 #define USB_PID_MYGICA_T230C 0xc689 +#define USB_PID_MYGICA_T230C2 0xc68a #define USB_PID_ELGATO_EYETV_DIVERSITY 0x0011 #define USB_PID_ELGATO_EYETV_DTT 0x0021 #define USB_PID_ELGATO_EYETV_DTT_2 0x003f What is that T230C2 stick? Naming sounds like a DVB-C2 capable, but I found only T230C model from MyGica site. Where I can get one? The T230C2 is sold as T230C. Apart from that it needs the TS clock be set they both are exactly the same. I bought it from China. Aliexpress. The old T230C is out of stock. And al
Re: [PATCH] dvb_usb_dvbsky: Mygica T230C2 add support for T230C hw version 2
On 6/12/19 2:49 AM, Antti Palosaari wrote: + /* set ts clock freq to 10Mhz */ + memcpy(cmd.args, "\x14\x00\x0d\x10\xe8\x03", 6); + cmd.wlen = 6; + cmd.rlen = 4; + ret = si2168_cmd_execute(client, &cmd); + if (ret) return ret; + 0x03e8 is 1000 and value used is 10 000Hz steps ==> 10 000 000 = 10MHz. Which means 8bit parallel ts bus has capacity of 80Mbit/s which sounds correct max for DVB-T2. What is default value set to that property? Many times those default values are just correct. The default value *is* 10Mhz. On all other si2168 hardware this does not need to be set but for some reason, on this hardware it needs to be set manually. The actual value has been scanned from the running windows driver by means of a USB logger. My best guess is that this whole si2168 driver has been written with the help of such a logger. If the default value is already 10MHz then there is no need to set it at all. I am a bit too lazy to start dumping that default value out from the chip atm. Looked from the pctv 292e sniffs, and it seems default is set to 7.2MHz. $ grep -A1 "\\\x14\\\x00\\\x0d\\\x10" l.c i2c_master_send_DEMOD(s->client, "\x14\x00\x0d\x10\xd0\x02", 6); //014597 i2c_master_recv_DEMOD(s->client, buf, 4); //014598 "\x80\x00\xd0\x02" T230C windows driver does not touch that value at all. In theory default may be different on different chip revisions, but I haven't never seen such case so I suspect it is still 7.2MHz on your device. regards Antti -- http://palosaari.fi/
Re: [PATCH] dvb_usb_dvbsky: Mygica T230C2 add support for T230C hw version 2
On 6/13/19 4:15 AM, JP wrote: And according to old usb sniffs from pctv 292e [Si2168B] default manual ts clock is set to 7.2MHz, which means 57.6Mbit/s datarate, it should be quite optimal for DVB-T2 max. In theory it could be a little higher only when 10MHz channel bandwidth and most less error correction FEC in use. And currently driver is using some config that uses dynamic ts clock which clocks only when there is data to feed. For some reason, usb-ts-bridge does not understand that and manual configuration is needed (ts valid or ts-sync connection?). If possible use 7.2MHz, if not: set to 10MHz. That's perfectly alright with me. I'm now testing that 7.2Mhz value. Hold on. The driver crashes with the 7.2Mhz value! That was totally not what I ever expected. Recompiled the whole kernel: crashes again. Then tried on debian kernel 4.19: same thing. Food for thought? It should sure never crash the kernel. Changing a ts bitrate no, no, no, you trapped a hidden bug. Found where it is :] regards Antti -- http://palosaari.fi/
Re: [PATCH] dvb_usb_dvbsky: Mygica T230C2 add support for T230C hw version 2
On 6/12/19 11:07 PM, Frantisek Rysanek wrote: On 12 Jun 2019 at 1:28, Antti Palosaari wrote: [...] What is that T230C2 stick? JP has already explained the details, how that name was arrived at. As previously suggested, I can call it T230C v2 in the descriptive texts. I'd suggest keeping T230C2 in the USB ID macro (or suggest a more appropriate name for the macro). Here in CZ, a company called Abacus imports and distributes consumer electronics gadgets under a private brand "EvolveO" - and this is how the "rebadged OEM Mygica" has reached me. http://m.evolveo.com/cz/sigma-t2 This particular T2 dongle is "allover the place" around here, no other dongle is this broadly available. (Well on our modest market. We're a nation of 10M people.) Naming sounds like a DVB-C2 capable, but I found only T230C model from MyGica site. The local brand's site only mentions DVB-T2. The 2-page "brief datasheet" of the si2168 that's publically available only mentions DVB-C, apart from T/T2. And also patch should be split to two logical parts, first add manual ts frequency support to si2168 and then other patch which adds device itself. I'll try to find some time and massage that approach into the code. I have read all the past attempts (example patches) and the maintainer's polite objections. And which are tuner and demod versions/revisions used for that device? That's reported in dmesg if memory serves... I'll try to find the answer. Frank Rysanek Yeah, all-in-all: 1) name it T230C v2 2) use manual ts clock speed And according to old usb sniffs from pctv 292e [Si2168B] default manual ts clock is set to 7.2MHz, which means 57.6Mbit/s datarate, it should be quite optimal for DVB-T2 max. In theory it could be a little higher only when 10MHz channel bandwidth and most less error correction FEC in use. And currently driver is using some config that uses dynamic ts clock which clocks only when there is data to feed. For some reason, usb-ts-bridge does not understand that and manual configuration is needed (ts valid or ts-sync connection?). If possible use 7.2MHz, if not: set to 10MHz. regards Antti -- http://palosaari.fi/
Re: si2168 gapped clock
Hello, On 6/18/19 7:47 PM, Marc Gonzalez wrote: Hello, In the qcom SoC, the TS interface has two modes of operation. - with 3 signals (clk, valid, data) - with 4 signals (clk, valid, data, sync) In the si2168 short datasheet, I can see a diagram with these 4 signals. My question is: how do we configure the si2168 demod to be in the first mode or the second mode? Is it the ts_clock_gapped parameter? ts_clock_gapped=0 means no sync ts_clock_gapped=1 means with sync ??? Regards. In general for mpeg ts you will need: data + clock + valid : when clock is running continuously or data + clock : when clock is running only when there is data Valid is used to tell there is new data when clock is running continuously - when valid signal is not set there is no data even clock is running. When only data and clock lines are used, clock is ran only when there is data. Sync signal is set for beginning of every TS packet (and it is not hardly needed if you parse ts data by software for example). Thus ts_clock_gapped means demod will flip clock only when there is data to feed ==> no need for valid signal. Configuring demod to first *or* second mode should be just ts_clock_gapped=false. regards Antti -- http://palosaari.fi/
Re: [PATCH 1/2] dvbsky: add support for "Mygica T230C v2"
On 6/25/19 6:41 PM, JP wrote: On 6/25/19 1:16 PM, Sean Young wrote: On Sun, Jun 16, 2019 at 02:39:29AM +0200, Jan Pieter van Woerkom wrote: From: Jan Pieter van Woerkom Adds support for the "Mygica T230C v2" into the "dvbsky" driver. A small enhancement is also needed in the si2168 demodulator driver, and a USB device ID in dvb-usb-ids.h . This is v3.3 of the proposed patch, based on feedback from Sean Young and Antti Palosaari. Tested by patch author on a T230C v2. Tested by Frank Rysanek on a T230C v2: can tune into locally available DVB-T and DVB-T2 muxes, video and audio playback works. Applies cleanly against Linux 5.1.10 . The T230C v2 hardware needs a mode of the si2168 chip to be set for which the si2168 driver previously had no support. This patch uses a specific measure to configure this on the T230C v2 hardware only - see the flag passed via the ts_mode attribute and its dependency on USB_PID_MYGICA_T230C2. Other devices using the si2168 demodulator driver are not affected in any way. Signed-off-by: Jan Pieter van Woerkom Tested-by: Frank Rysanek --- diff -ru a/drivers/media/dvb-frontends/si2168.c b/drivers/media/dvb-frontends/si2168.c --- a/drivers/media/dvb-frontends/si2168.c 2019-06-04 07:59:45.0 +0200 +++ b/drivers/media/dvb-frontends/si2168.c 2019-06-08 19:47:32.385526558 +0200 @@ -91,8 +91,18 @@ dev_dbg(&client->dev, "%s acquire: %d\n", __func__, acquire); + /* set manual value */ + if (dev->ts_mode | SI2168_TS_CLK_MANUAL) { This looks wrong. Should it not be "dev->ts_mode & SI2168_TS_CLK_MANUAL"? Now the expression is always true. You're absolutely right. Silly me. What now? Correct and repost? yes, and next indentation looks also wrong + memcpy(cmd.args, "\x14\x00\x0d\x10\xe8\x03", 6); + cmd.wlen = 6; + cmd.rlen = 4; + ret = si2168_cmd_execute(client, &cmd); + if (ret) + return ret; + } /* set TS_MODE property */ - memcpy(cmd.args, "\x14\x00\x01\x10\x10\x00", 6); + memcpy(cmd.args, "\x14\x00\x01\x10\x00\x00", 6); + cmd.args[4] = dev->ts_mode & (SI2168_TS_CLK_AUTO|SI2168_TS_CLK_MANUAL); if (acquire) cmd.args[4] |= dev->ts_mode; else diff -ru a/drivers/media/dvb-frontends/si2168.h b/drivers/media/dvb-frontends/si2168.h --- a/drivers/media/dvb-frontends/si2168.h 2019-06-04 07:59:45.0 +0200 +++ b/drivers/media/dvb-frontends/si2168.h 2019-06-08 19:32:52.400320490 +0200 @@ -39,6 +39,8 @@ #define SI2168_TS_PARALLEL 0x06 #define SI2168_TS_SERIAL 0x03 #define SI2168_TS_TRISTATE 0x00 +#define SI2168_TS_CLK_AUTO 0x10 +#define SI2168_TS_CLK_MANUAL 0x20 u8 ts_mode; /* TS clock inverted */ Thanks, Sean Thank you, Jan Pieter. regards Antti -- http://palosaari.fi/
Re: [PATCH] media: tm6000: Spelling s/diconencted/diconnected/
On 7/31/19 4:41 PM, Geert Uytterhoeven wrote: Signed-off-by: Geert Uytterhoeven --- drivers/media/usb/tm6000/tm6000-cards.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/media/usb/tm6000/tm6000-cards.c b/drivers/media/usb/tm6000/tm6000-cards.c index 23df50aa0a4af6da..9a0ffe678524987c 100644 --- a/drivers/media/usb/tm6000/tm6000-cards.c +++ b/drivers/media/usb/tm6000/tm6000-cards.c @@ -1328,7 +1328,7 @@ static int tm6000_usb_probe(struct usb_interface *interface, /* * tm6000_usb_disconnect() - * called when the device gets diconencted + * called when the device gets diconnected disconnected ? For the both patches. * video device will be unregistered on v4l2_close in case it is still open */ static void tm6000_usb_disconnect(struct usb_interface *interface) regards Antti -- http://palosaari.fi/
Re: [PATCH v4] dvb-usb/friio, dvb-usb-v2/gl861: decompose friio and merge with gl861
On 03/27/2018 08:47 PM, tsk...@gmail.com wrote: From: Akihiro Tsukada Friio device contains "gl861" bridge and "tc90522" demod, for which the separate drivers are already in the kernel. But friio driver was monolithic and did not use them, practically copying those features. This patch decomposes friio driver into sub drivers and re-uses existing ones, thus reduces some code. It adds some features to gl861, to support the friio-specific init/config of the devices and implement i2c communications to the tuner via demod with USB vendor requests. You should implement i2c adapter to demod driver and not add such glue to that USB-bridge. I mean that "relayed" stuff, i2c communication to tuner via demod. I2C-mux may not work I think as there is no gate-style multiplexing so you probably need plain i2c adapter. There is few examples already on some demod drivers. regards Antti -- http://palosaari.fi/
Re: [PATCH v3 1/5] dvb-frontends/dvb-pll: add i2c driver support
On 03/26/2018 09:06 PM, tsk...@gmail.com wrote: From: Akihiro Tsukada registers the module as an i2c driver, but keeps dvb_pll_attach() untouched for compatibility. Signed-off-by: Akihiro Tsukada --- drivers/media/dvb-frontends/dvb-pll.c | 49 +++ drivers/media/dvb-frontends/dvb-pll.h | 6 + 2 files changed, 55 insertions(+) diff --git a/drivers/media/dvb-frontends/dvb-pll.c b/drivers/media/dvb-frontends/dvb-pll.c index 5553b89b804..614a5ea3b00 100644 --- a/drivers/media/dvb-frontends/dvb-pll.c +++ b/drivers/media/dvb-frontends/dvb-pll.c @@ -827,6 +827,55 @@ struct dvb_frontend *dvb_pll_attach(struct dvb_frontend *fe, int pll_addr, } EXPORT_SYMBOL(dvb_pll_attach); + +static int +dvb_pll_probe(struct i2c_client *client, const struct i2c_device_id *id) +{ + struct dvb_pll_config *cfg; + struct dvb_frontend *fe; + unsigned int desc_id; + + cfg = client->dev.platform_data; + fe = cfg->fe; + i2c_set_clientdata(client, fe); + desc_id = cfg->desc_id; + + if (!dvb_pll_attach(fe, client->addr, client->adapter, desc_id)) + return -ENOMEM; + + dev_info(&client->dev, "DVB Simple Tuner attached.\n"); + return 0; +} + +static int dvb_pll_remove(struct i2c_client *client) +{ + struct dvb_frontend *fe; + + fe = i2c_get_clientdata(client); + dvb_pll_release(fe); + return 0; +} + + +static const struct i2c_device_id dvb_pll_id[] = { + {"dvb_pll", 0}, + {} +}; + + +MODULE_DEVICE_TABLE(i2c, dvb_pll_id); + +static struct i2c_driver dvb_pll_driver = { + .driver = { + .name = "dvb_pll", + }, + .probe= dvb_pll_probe, + .remove = dvb_pll_remove, + .id_table = dvb_pll_id, +}; + +module_i2c_driver(dvb_pll_driver); + MODULE_DESCRIPTION("dvb pll library"); MODULE_AUTHOR("Gerd Knorr"); MODULE_LICENSE("GPL"); diff --git a/drivers/media/dvb-frontends/dvb-pll.h b/drivers/media/dvb-frontends/dvb-pll.h index ca885e71d2f..15bda0d0c15 100644 --- a/drivers/media/dvb-frontends/dvb-pll.h +++ b/drivers/media/dvb-frontends/dvb-pll.h @@ -30,6 +30,12 @@ #define DVB_PLL_TDEE418 #define DVB_PLL_THOMSON_DTT7520X 19 +struct dvb_pll_config { + struct dvb_frontend *fe; + + unsigned int desc_id; +}; + #if IS_REACHABLE(CONFIG_DVB_PLL) /** * Attach a dvb-pll to the supplied frontend structure. Hello Idea is correct, but I would use pll chip names for passing correct pll type for driver - that field is just for that. Like that: static const struct i2c_device_id dvb_pll_id[] = { {"PLL-NAME1", 0}, {"PLL-NAME2", 1}, {"PLL-NAME3", 2}, {} }; See si2157 for example. regards Antti -- http://palosaari.fi/
Re: [PATCH v4] dvb-usb/friio, dvb-usb-v2/gl861: decompose friio and merge with gl861
On 03/28/2018 03:37 PM, Akihiro TSUKADA wrote: Hi, thanks for the comment. You should implement i2c adapter to demod driver and not add such glue to that USB-bridge. I mean that "relayed" stuff, i2c communication to tuner via demod. I2C-mux may not work I think as there is no gate-style multiplexing so you probably need plain i2c adapter. There is few examples already on some demod drivers. I am afraid that the glue is actually necessary. host - USB -> gl861 - I2C(1) -> tc90522 (addr:X) \- I2C(2) -> tua6034 (addr:Y) To send an i2c read message to tua6034, one has to issue two transactions: 1. write via I2C(1) to addr:X, [ reg:0xfe, val: Y ] 2. read via I2C(1) from addr:X, [ out_data0, out_data1, ] The problem is that the transaction 1 is (somehow) implemented with the different USB request than the other i2c transactions on I2C(1). (this is confirmed by a packet capture on Windows box). Although tc90522 already creats the i2c adapter for I2C(2), tc90522 cannot know/control the USB implementation of I2C(1), only the bridge driver can do this. I simply cannot see why it cannot work. Just add i2c adapter and suitable logic there. Transaction on your example is simply and there is no problem to implement that kind of logic to demod i2c adapter. If gl861 driver i2c adapter logic is broken it can be fixed easily too. It seems to support only i2c writes with len 1 and 2 bytes, but fixing it should be easy if you has some sniffs. Antti -- http://palosaari.fi/
Re: [PATCH v4 1/5] dvb-frontends/dvb-pll: add i2c driver support
On 03/28/2018 08:00 PM, tsk...@gmail.com wrote: From: Akihiro Tsukada registers the module as an i2c driver, but keeps dvb_pll_attach() untouched for compatibility. Signed-off-by: Akihiro Tsukada --- Changes since v3: - use standard i2c_device_id instead of dvb_pll_config drivers/media/dvb-frontends/dvb-pll.c | 67 +++ drivers/media/dvb-frontends/dvb-pll.h | 24 + 2 files changed, 91 insertions(+) diff --git a/drivers/media/dvb-frontends/dvb-pll.c b/drivers/media/dvb-frontends/dvb-pll.c index 5553b89b804..e2a93aae04f 100644 --- a/drivers/media/dvb-frontends/dvb-pll.c +++ b/drivers/media/dvb-frontends/dvb-pll.c @@ -827,6 +827,73 @@ struct dvb_frontend *dvb_pll_attach(struct dvb_frontend *fe, int pll_addr, } EXPORT_SYMBOL(dvb_pll_attach); + +static int +dvb_pll_probe(struct i2c_client *client, const struct i2c_device_id *id) +{ + struct dvb_pll_config *cfg; + struct dvb_frontend *fe; + unsigned int desc_id; + + cfg = client->dev.platform_data; + fe = cfg->fe; + i2c_set_clientdata(client, fe); + desc_id = (unsigned int) id->driver_data; + + if (!dvb_pll_attach(fe, client->addr, client->adapter, desc_id)) + return -ENOMEM; + + dev_info(&client->dev, "DVB Simple Tuner attached.\n"); Print used pll chip name here + return 0; +} + +static int dvb_pll_remove(struct i2c_client *client) +{ + struct dvb_frontend *fe; + + fe = i2c_get_clientdata(client); + dvb_pll_release(fe); + return 0; +} + + +static const struct i2c_device_id dvb_pll_id[] = { + {DVB_PLL_THOMSON_DTT7579_NAME,DVB_PLL_THOMSON_DTT7579}, + {DVB_PLL_THOMSON_DTT759X_NAME,DVB_PLL_THOMSON_DTT759X}, + {DVB_PLL_LG_Z201_NAME,DVB_PLL_LG_Z201}, + {DVB_PLL_UNKNOWN_1_NAME, DVB_PLL_UNKNOWN_1}, + {DVB_PLL_TUA6010XS_NAME, DVB_PLL_TUA6010XS}, + {DVB_PLL_ENV57H1XD5_NAME, DVB_PLL_ENV57H1XD5}, + {DVB_PLL_TUA6034_NAME,DVB_PLL_TUA6034}, + {DVB_PLL_TDA665X_NAME,DVB_PLL_TDA665X}, + {DVB_PLL_TDED4_NAME, DVB_PLL_TDED4}, + {DVB_PLL_TDHU2_NAME, DVB_PLL_TDHU2}, + {DVB_PLL_SAMSUNG_TBMV_NAME, DVB_PLL_SAMSUNG_TBMV}, + {DVB_PLL_PHILIPS_SD1878_TDA8261_NAME, DVB_PLL_PHILIPS_SD1878_TDA8261}, + {DVB_PLL_OPERA1_NAME, DVB_PLL_OPERA1}, + {DVB_PLL_SAMSUNG_DTOS403IH102A_NAME, DVB_PLL_SAMSUNG_DTOS403IH102A}, + {DVB_PLL_SAMSUNG_TDTC9251DH0_NAME,DVB_PLL_SAMSUNG_TDTC9251DH0}, + {DVB_PLL_SAMSUNG_TBDU18132_NAME, DVB_PLL_SAMSUNG_TBDU18132}, + {DVB_PLL_SAMSUNG_TBMU24112_NAME, DVB_PLL_SAMSUNG_TBMU24112}, + {DVB_PLL_TDEE4_NAME, DVB_PLL_TDEE4}, + {DVB_PLL_THOMSON_DTT7520X_NAME, DVB_PLL_THOMSON_DTT7520X}, + {} +}; + + +MODULE_DEVICE_TABLE(i2c, dvb_pll_id); + +static struct i2c_driver dvb_pll_driver = { + .driver = { + .name = "dvb_pll", + }, + .probe= dvb_pll_probe, + .remove = dvb_pll_remove, + .id_table = dvb_pll_id, +}; + +module_i2c_driver(dvb_pll_driver); + MODULE_DESCRIPTION("dvb pll library"); MODULE_AUTHOR("Gerd Knorr"); MODULE_LICENSE("GPL"); diff --git a/drivers/media/dvb-frontends/dvb-pll.h b/drivers/media/dvb-frontends/dvb-pll.h index ca885e71d2f..e96994bf668 100644 --- a/drivers/media/dvb-frontends/dvb-pll.h +++ b/drivers/media/dvb-frontends/dvb-pll.h @@ -30,6 +30,30 @@ #define DVB_PLL_TDEE418 #define DVB_PLL_THOMSON_DTT7520X 19 +#define DVB_PLL_THOMSON_DTT7579_NAME "dtt7579" +#define DVB_PLL_THOMSON_DTT759X_NAME"dtt759x" +#define DVB_PLL_LG_Z201_NAME"z201" +#define DVB_PLL_UNKNOWN_1_NAME "unknown_1" +#define DVB_PLL_TUA6010XS_NAME "tua6010xs" +#define DVB_PLL_ENV57H1XD5_NAME "env57h1xd5" +#define DVB_PLL_TUA6034_NAME"tua6034" +#define DVB_PLL_TDA665X_NAME"tda665x" +#define DVB_PLL_TDED4_NAME "tded4" +#define DVB_PLL_TDHU2_NAME "tdhu2" +#define DVB_PLL_SAMSUNG_TBMV_NAME "tbmv" +#define DVB_PLL_PHILIPS_SD1878_TDA8261_NAME "sd1878_tda8261" +#define DVB_PLL_OPERA1_NAME "opera1" +#define DVB_PLL_SAMSUNG_DTOS403IH102A_NAME "dtos403ih102a" +#define DVB_PLL_SAMSUNG_TDTC9251DH0_NAME"tdtc9251dh0" +#define DVB_PLL_SAMSUNG_TBDU18132_NAME "tbdu18132" +#define DVB_PLL_SAMSUNG_TBMU24112_NAME "tbmu24112" +#define DVB_PLL_TDEE4_NAME "tdee4" +#define DVB_PLL_THOMSON_DTT7520X_NAME "dtt7520x" Defining these names like that does not give any value. IMHO better to just add those chip names directly to chip id table. + +struct dvb_pll_config { + struct dvb_frontend *fe; +}; + #if IS_REACHABLE(CONFIG_DVB_PLL) /** * Attach a dvb-pll to the
Re: [PATCH v4] dvb-usb/friio, dvb-usb-v2/gl861: decompose friio and merge with gl861
On 03/30/2018 04:21 PM, Akihiro TSUKADA wrote: I simply cannot see why it cannot work. Just add i2c adapter and suitable logic there. Transaction on your example is simply and there is no problem to implement that kind of logic to demod i2c adapter. I might be totally wrong, but... i2c transactions to a tuner must use: 1. usb_control_msg(request:3) for the first half (write) of reads 2. usb_control_msg(request:1) for the other writes 3. usb_control_msg(request:2) for (all) reads How can the demod driver control the 'request' argument of USB messages that are sent to its parent (not to the demod itself), when the bridge of tc90522 cannot be limited to gl861 (or even to USB) ? I don't understand those control message parts and it is bit too hard to read i2c adapter implementation to get understanding. Could you offer simple 2 sniff examples, register write to demod and register write to tuner. Anyhow, demod i2c adapter gets request from tuner and then does some demod specific i2c algo stuff and then pass proper request to usb-bridge i2c adapter. IIR it was somehing like write_tuner_reg(0xaa, 0xbb); ==> demod i2c algo: * write_demod_reg(0xfe, 0x60) // set tuner i2c addr + start i2c write * write_demod_reg(0xaa, 0xbb) so those command now goes to i2c-bridge i2c algo which uses gl861 i2c algo regards Antti -- http://palosaari.fi/
Re: Regression: DVBSky S960 USB tuner doesn't work in 4.10 or newer
On 04/18/2018 07:49 AM, Olli Salonen wrote: Thank you for your response Peter! Indeed, it seems strange. dvbsky.c driver seems to use mutex_lock in very much the same way as many other drivers. I've now confirmed that I can get a 4.10 kernel with working DVBSky S960 by reverting the following 4 patches: 549bdd3 Revert "locking/mutex: Add lock handoff to avoid starvation" 3210f31 Revert "locking/mutex: Restructure wait loop" 418a170 Revert "locking/mutex: Simplify some ww_mutex code in __mutex_lock_common()" 0b1fb8f Revert "locking/mutex: Enable optimistic spinning of woken waiter" c470abd Linux 4.10 These kind of issues tend to be timing issues very often. Just add some sleeps to i2c adapter algo / usb control messages and test. regards Antti -- http://palosaari.fi/
[PATCH] msi2500: assign SPI bus number dynamically
SPI bus number must be assigned dynamically for each device, otherwise it will crash when multiple devices are plugged to system. Cc: sta...@vger.kernel.org Reported-and-tested-by: syzbot+c60ddb60b685777d9...@syzkaller.appspotmail.com Signed-off-by: Antti Palosaari --- drivers/media/usb/msi2500/msi2500.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/media/usb/msi2500/msi2500.c b/drivers/media/usb/msi2500/msi2500.c index 65be6f140fe8..1c60dfb647e5 100644 --- a/drivers/media/usb/msi2500/msi2500.c +++ b/drivers/media/usb/msi2500/msi2500.c @@ -1230,7 +1230,7 @@ static int msi2500_probe(struct usb_interface *intf, } dev->master = master; - master->bus_num = 0; + master->bus_num = -1; master->num_chipselect = 1; master->transfer_one_message = msi2500_transfer_one_message; spi_master_set_devdata(master, dev); -- 2.21.0
Re: [PATCH] dvb-usb-v2/gl861: fix wrong memcpy
On 8/17/19 4:22 PM, Akihiro TSUKADA wrote: Could you please test the patch and check if the return results are now consistent and that it won't break anything? I have tested the patch and it worked without problems. Testd-by: Akihiro Tsukada I could not noticed the bug because the device was registered without any error messages, and it seemed to work even with the bug. (Though actually I was wrong and missed that the device does not work after reboot or re-plugging). After applying this patch, I have confirmed that the device now works after reboot/re-plugging without any problems. note: The patched func: gl861_i2c_read_ex was used in device's early init, called from d->props->power_ctrl (from dvb_usbv2_init). But dvb_usbv2_init does not check the return value of it, and if the device had been initialized previously it can work even with the interrupted init process in power_ctrl(). I suspect all whole friio_reset() function is not needed as it has worked even I/O has been broken. Also tuner I2C adapter is implemented wrong (I think I mentioned that earlier). As tuner sits behind demod I2C-adapter/gate that whole logic should be on demod driver. regards Antti -- http://palosaari.fi/
Re: [PATCH] dvb-usb-v2/gl861: fix wrong memcpy
On 8/22/19 5:00 AM, Akihiro TSUKADA wrote: Hi, I suspect all whole friio_reset() function is not needed as it has worked even I/O has been broken. It worked because the old driver (that I rmmod'ed before installing the testing driver) properly init'ed the device. If I re-plug it (or reboot), it does not work. So it is needed. Also tuner I2C adapter is implemented wrong (I think I mentioned that earlier). As tuner sits behind demod I2C-adapter/gate that whole logic should be on demod driver. But according to USB packet capture logs of the windows version, it makes eccentric use of USB messages ('bRequest' field), that (I believe) necessitates the current implementation, as I mentioned in the past thread. That is because it has 2 i2c write methods - one using only usb_control_msg() header and other header + payload data. When 1 or 2 byte long i2c message is send it is wise to use only "header" to reduce IO as it could carry needed data. Anyhow, I will send patch soon which adds needed logic to i2c adapter. Then it is easier to understand. regards Antti -- http://palosaari.fi/
[PATCH] gl861: re-implement i2c adapter logic
Device I2C adapter is capable of writing and reading large messages. For I2C writes there is 2 methods: simple for max 2 byte messages and usb_control_msg() with payload data for larger I2C messages. Add I2C adapter logic which selects suitable method according to message size. Cc: Akihiro TSUKADA Signed-off-by: Antti Palosaari --- drivers/media/usb/dvb-usb-v2/gl861.c | 206 +++ 1 file changed, 149 insertions(+), 57 deletions(-) diff --git a/drivers/media/usb/dvb-usb-v2/gl861.c b/drivers/media/usb/dvb-usb-v2/gl861.c index b784d9da1a82..b8358cd2e4b7 100644 --- a/drivers/media/usb/dvb-usb-v2/gl861.c +++ b/drivers/media/usb/dvb-usb-v2/gl861.c @@ -14,6 +14,144 @@ DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr); +struct gl861 { + /* USB control message buffer */ + u8 buf[16]; + + struct i2c_adapter *demod_sub_i2c; + struct i2c_client *i2c_client_demod; + struct i2c_client *i2c_client_tuner; + struct i2c_adapter tuner_adap; +}; + +#define CMD_WRITE_SHORT 0x01 +#define CMD_READ0x02 +#define CMD_WRITE 0x03 + +static int gl861_ctrl_msg(struct dvb_usb_device *d, u8 request, u16 value, + u16 index, void *data, u16 size) +{ + struct gl861 *ctx = d_to_priv(d); + struct usb_interface *intf = d->intf; + int ret; + unsigned int pipe; + u8 requesttype; + + mutex_lock(&d->usb_mutex); + + switch (request) { + case CMD_WRITE_SHORT: + pipe = usb_sndctrlpipe(d->udev, 0); + requesttype = USB_TYPE_VENDOR | USB_DIR_OUT; + break; + case CMD_READ: + pipe = usb_rcvctrlpipe(d->udev, 0); + requesttype = USB_TYPE_VENDOR | USB_DIR_IN; + break; + case CMD_WRITE: + pipe = usb_sndctrlpipe(d->udev, 0); + requesttype = USB_TYPE_VENDOR | USB_DIR_OUT; + memcpy(ctx->buf, data, size); + break; + default: + ret = -EINVAL; + goto err_mutex_unlock; + } + + ret = usb_control_msg(d->udev, pipe, request, requesttype, value, + index, ctx->buf, size, 200); + dev_dbg(&intf->dev, "%d | %02x %02x %*ph %*ph %*ph %s %*ph\n", + ret, requesttype, request, 2, &value, 2, &index, 2, &size, + (requesttype & USB_DIR_IN) ? "<<<" : ">>>", size, ctx->buf); + if (ret < 0) + goto err_mutex_unlock; + + if (request == CMD_READ) + memcpy(data, ctx->buf, size); + + usleep_range(1000, 2000); /* Avoid I2C errors */ + + mutex_unlock(&d->usb_mutex); + + return 0; + +err_mutex_unlock: + mutex_unlock(&d->usb_mutex); + dev_dbg(&intf->dev, "failed %d\n", ret); + return ret; +} + +static int gl861_i2c_master_xfer(struct i2c_adapter *adap, struct i2c_msg msg[], +int num) +{ + struct dvb_usb_device *d = i2c_get_adapdata(adap); + struct usb_interface *intf = d->intf; + struct gl861 *ctx = d_to_priv(d); + int ret; + u8 request, *data; + u16 value, index, size; + + /* XXX: I2C adapter maximum data lengths are not tested */ + if (num == 1 && !(msg[0].flags & I2C_M_RD)) { + /* I2C write */ + if (msg[0].len < 2 || msg[0].len > sizeof(ctx->buf)) { + ret = -EOPNOTSUPP; + goto err; + } + + value = (msg[0].addr << 1) << 8; + index = msg[0].buf[0]; + + if (msg[0].len == 2) { + request = CMD_WRITE_SHORT; + value |= msg[0].buf[1]; + size = 0; + data = NULL; + } else { + request = CMD_WRITE; + size = msg[0].len - 1; + data = &msg[0].buf[1]; + } + + ret = gl861_ctrl_msg(d, request, value, index, data, size); + } else if (num == 2 && !(msg[0].flags & I2C_M_RD) && + (msg[1].flags & I2C_M_RD)) { + /* I2C write + read */ + if (msg[0].len > 1 || msg[1].len > sizeof(ctx->buf)) { + ret = -EOPNOTSUPP; + goto err; + } + + value = (msg[0].addr << 1) << 8; + index = msg[0].buf[0]; + request = CMD_READ; + + ret = gl861_ctrl_msg(d, request, value, index, +msg[1].buf, msg[1].len); + } else { + /* Unsupported I2C message */ + dev_dbg(&intf->dev, "
Re: [PATCH] gl861: re-implement i2c adapter logic
On 8/22/19 8:34 AM, Antti Palosaari wrote: Device I2C adapter is capable of writing and reading large messages. For I2C writes there is 2 methods: simple for max 2 byte messages and usb_control_msg() with payload data for larger I2C messages. Add I2C adapter logic which selects suitable method according to message size. Here is debug log I tested multibyte i2c writes using zl10353 demod. All returned bytes are not same, but it due to write only register bits I think. dvb_usb_gl861 1-13:1.0: 1 | c0 02 00 1e 50 00 01 00 <<< 03 dvb_usb_gl861 1-13:1.0: 1 | c0 02 00 1e 51 00 01 00 <<< 44 dvb_usb_gl861 1-13:1.0: 1 | c0 02 00 1e 52 00 01 00 <<< 46 dvb_usb_gl861 1-13:1.0: 1 | c0 02 00 1e 53 00 01 00 <<< 15 dvb_usb_gl861 1-13:1.0: 1 | c0 02 00 1e 54 00 01 00 <<< 0f dvb_usb_gl861 1-13:1.0: 5 | 40 03 00 1e 50 00 05 00 >>> 0c 77 aa bb cc dvb_usb_gl861 1-13:1.0: 1 | c0 02 00 1e 50 00 01 00 <<< 0c dvb_usb_gl861 1-13:1.0: 1 | c0 02 00 1e 51 00 01 00 <<< 77 dvb_usb_gl861 1-13:1.0: 1 | c0 02 00 1e 52 00 01 00 <<< aa dvb_usb_gl861 1-13:1.0: 1 | c0 02 00 1e 53 00 01 00 <<< 3b dvb_usb_gl861 1-13:1.0: 1 | c0 02 00 1e 54 00 01 00 <<< 4c Now if you look your tuner i2c implementation... buf[0] = msg->addr << 1; memcpy(buf + 1, msg->buf, msg->len); ret = usb_control_msg(d->udev, usb_sndctrlpipe(d->udev, 0), GL861_REQ_I2C_RAW, GL861_WRITE, priv->i2c_client_demod->addr << (8 + 1), 0xFE, buf, msg->len + 1, 2000); ...it translates same. It writes i2c message to demod which; byte0 0xfe, demod register/cmd/mailbox for tuner i2c bus byte1 tuner i2c address byte2-n tuner i2c data Antti -- http://palosaari.fi/
Re: [PATCH] gl861: re-implement i2c adapter logic
On 8/23/19 8:28 PM, Akihiro TSUKADA wrote: Hi, thanks for the example patch. Here is debug log I tested multibyte i2c writes using zl10353 demod. All returned bytes are not same, but it due to write only register bits I think. dvb_usb_gl861 1-13:1.0: 1 | c0 02 00 1e 50 00 01 00 <<< 03 dvb_usb_gl861 1-13:1.0: 1 | c0 02 00 1e 51 00 01 00 <<< 44 dvb_usb_gl861 1-13:1.0: 1 | c0 02 00 1e 52 00 01 00 <<< 46 dvb_usb_gl861 1-13:1.0: 1 | c0 02 00 1e 53 00 01 00 <<< 15 dvb_usb_gl861 1-13:1.0: 1 | c0 02 00 1e 54 00 01 00 <<< 0f dvb_usb_gl861 1-13:1.0: 5 | 40 03 00 1e 50 00 05 00 >>> 0c 77 aa bb cc dvb_usb_gl861 1-13:1.0: 1 | c0 02 00 1e 50 00 01 00 <<< 0c dvb_usb_gl861 1-13:1.0: 1 | c0 02 00 1e 51 00 01 00 <<< 77 dvb_usb_gl861 1-13:1.0: 1 | c0 02 00 1e 52 00 01 00 <<< aa dvb_usb_gl861 1-13:1.0: 1 | c0 02 00 1e 53 00 01 00 <<< 3b dvb_usb_gl861 1-13:1.0: 1 | c0 02 00 1e 54 00 01 00 <<< 4c Now if you look your tuner i2c implementation... buf[0] = msg->addr << 1; memcpy(buf + 1, msg->buf, msg->len); ret = usb_control_msg(d->udev, usb_sndctrlpipe(d->udev, 0), GL861_REQ_I2C_RAW, GL861_WRITE, priv->i2c_client_demod->addr << (8 + 1), 0xFE, buf, msg->len + 1, 2000); ...it translates same. Log of an 1-byte read from tuner in Friio looks like the following: (re-formatted from my past post: https://patchwork.linuxtv.org/comment/92946/ ) 40 03 00 30 fe 00 01 00 >>> c1 # command a read from the tuner@0x60 (hence 0xc1) c0 02 00 30 00 01 01 00 <<< 7c # get the result (return value: 0x7c) so, - One read is composed of *two* USB messages. (note that friio_tuner_i2c_xfer() does NOT combine the two I2C messages of one read, and issues separate USB message for each, contrary to gl861_i2c_master_xfer()). - The second USB message uses CMD_READ but 'index'(demod register addr) value exceeds 8bit (0x0100), thus cannot use the normal gl861_i2c_master_xfer() as is. It looks to me different. It looks just read command done with 2 separate I2C messages (look I2C specs REPEATED START vs. STOP START). OK, I will add support for bulk I2C READs for adapter too, no problem. Antti -- http://palosaari.fi/
[PATCH v2] gl861: re-implement I2C adapter logic
Device I2C adapter is capable of writing and reading large messages. For I2C writes there is 2 methods: simple for max 2 byte messages and usb_control_msg() with payload data for larger I2C messages. Add I2C adapter logic which selects suitable method according to message size. Add also support for plain I2C read. Cc: Akihiro TSUKADA Signed-off-by: Antti Palosaari --- drivers/media/usb/dvb-usb-v2/gl861.c | 216 --- 1 file changed, 159 insertions(+), 57 deletions(-) diff --git a/drivers/media/usb/dvb-usb-v2/gl861.c b/drivers/media/usb/dvb-usb-v2/gl861.c index b784d9da1a82..ead6268af7ad 100644 --- a/drivers/media/usb/dvb-usb-v2/gl861.c +++ b/drivers/media/usb/dvb-usb-v2/gl861.c @@ -14,6 +14,154 @@ DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr); +struct gl861 { + /* USB control message buffer */ + u8 buf[16]; + + struct i2c_adapter *demod_sub_i2c; + struct i2c_client *i2c_client_demod; + struct i2c_client *i2c_client_tuner; + struct i2c_adapter tuner_adap; +}; + +#define CMD_WRITE_SHORT 0x01 +#define CMD_READ0x02 +#define CMD_WRITE 0x03 + +static int gl861_ctrl_msg(struct dvb_usb_device *d, u8 request, u16 value, + u16 index, void *data, u16 size) +{ + struct gl861 *ctx = d_to_priv(d); + struct usb_interface *intf = d->intf; + int ret; + unsigned int pipe; + u8 requesttype; + + mutex_lock(&d->usb_mutex); + + switch (request) { + case CMD_WRITE: + memcpy(ctx->buf, data, size); + /* Fall through */ + case CMD_WRITE_SHORT: + pipe = usb_sndctrlpipe(d->udev, 0); + requesttype = USB_TYPE_VENDOR | USB_DIR_OUT; + break; + case CMD_READ: + pipe = usb_rcvctrlpipe(d->udev, 0); + requesttype = USB_TYPE_VENDOR | USB_DIR_IN; + break; + default: + ret = -EINVAL; + goto err_mutex_unlock; + } + + ret = usb_control_msg(d->udev, pipe, request, requesttype, value, + index, ctx->buf, size, 200); + dev_dbg(&intf->dev, "%d | %02x %02x %*ph %*ph %*ph %s %*ph\n", + ret, requesttype, request, 2, &value, 2, &index, 2, &size, + (requesttype & USB_DIR_IN) ? "<<<" : ">>>", size, ctx->buf); + if (ret < 0) + goto err_mutex_unlock; + + if (request == CMD_READ) + memcpy(data, ctx->buf, size); + + usleep_range(1000, 2000); /* Avoid I2C errors */ + + mutex_unlock(&d->usb_mutex); + + return 0; + +err_mutex_unlock: + mutex_unlock(&d->usb_mutex); + dev_dbg(&intf->dev, "failed %d\n", ret); + return ret; +} + +static int gl861_i2c_master_xfer(struct i2c_adapter *adap, struct i2c_msg msg[], +int num) +{ + struct dvb_usb_device *d = i2c_get_adapdata(adap); + struct usb_interface *intf = d->intf; + struct gl861 *ctx = d_to_priv(d); + int ret; + u8 request, *data; + u16 value, index, size; + + /* XXX: I2C adapter maximum data lengths are not tested */ + if (num == 1 && !(msg[0].flags & I2C_M_RD)) { + /* I2C write */ + if (msg[0].len < 2 || msg[0].len > sizeof(ctx->buf)) { + ret = -EOPNOTSUPP; + goto err; + } + + value = (msg[0].addr << 1) << 8; + index = msg[0].buf[0]; + + if (msg[0].len == 2) { + request = CMD_WRITE_SHORT; + value |= msg[0].buf[1]; + size = 0; + data = NULL; + } else { + request = CMD_WRITE; + size = msg[0].len - 1; + data = &msg[0].buf[1]; + } + + ret = gl861_ctrl_msg(d, request, value, index, data, size); + } else if (num == 2 && !(msg[0].flags & I2C_M_RD) && + (msg[1].flags & I2C_M_RD)) { + /* I2C write + read */ + if (msg[0].len > 1 || msg[1].len > sizeof(ctx->buf)) { + ret = -EOPNOTSUPP; + goto err; + } + + value = (msg[0].addr << 1) << 8; + index = msg[0].buf[0]; + request = CMD_READ; + + ret = gl861_ctrl_msg(d, request, value, index, +msg[1].buf, msg[1].len); + } else if (num == 1 && (msg[0].flags & I2C_M_RD)) { + /* I2C read */ + if (msg[0].len > sizeof(ctx->buf)) { + ret =
Re: [PATCH] gl861: re-implement i2c adapter logic
On 8/24/19 2:33 AM, Antti Palosaari wrote: On 8/23/19 8:28 PM, Akihiro TSUKADA wrote: Hi, thanks for the example patch. Here is debug log I tested multibyte i2c writes using zl10353 demod. All returned bytes are not same, but it due to write only register bits I think. dvb_usb_gl861 1-13:1.0: 1 | c0 02 00 1e 50 00 01 00 <<< 03 dvb_usb_gl861 1-13:1.0: 1 | c0 02 00 1e 51 00 01 00 <<< 44 dvb_usb_gl861 1-13:1.0: 1 | c0 02 00 1e 52 00 01 00 <<< 46 dvb_usb_gl861 1-13:1.0: 1 | c0 02 00 1e 53 00 01 00 <<< 15 dvb_usb_gl861 1-13:1.0: 1 | c0 02 00 1e 54 00 01 00 <<< 0f dvb_usb_gl861 1-13:1.0: 5 | 40 03 00 1e 50 00 05 00 >>> 0c 77 aa bb cc dvb_usb_gl861 1-13:1.0: 1 | c0 02 00 1e 50 00 01 00 <<< 0c dvb_usb_gl861 1-13:1.0: 1 | c0 02 00 1e 51 00 01 00 <<< 77 dvb_usb_gl861 1-13:1.0: 1 | c0 02 00 1e 52 00 01 00 <<< aa dvb_usb_gl861 1-13:1.0: 1 | c0 02 00 1e 53 00 01 00 <<< 3b dvb_usb_gl861 1-13:1.0: 1 | c0 02 00 1e 54 00 01 00 <<< 4c Now if you look your tuner i2c implementation... buf[0] = msg->addr << 1; memcpy(buf + 1, msg->buf, msg->len); ret = usb_control_msg(d->udev, usb_sndctrlpipe(d->udev, 0), GL861_REQ_I2C_RAW, GL861_WRITE, priv->i2c_client_demod->addr << (8 + 1), 0xFE, buf, msg->len + 1, 2000); ...it translates same. Log of an 1-byte read from tuner in Friio looks like the following: (re-formatted from my past post: https://patchwork.linuxtv.org/comment/92946/ ) 40 03 00 30 fe 00 01 00 >>> c1 # command a read from the tuner@0x60 (hence 0xc1) c0 02 00 30 00 01 01 00 <<< 7c # get the result (return value: 0x7c) so, - One read is composed of *two* USB messages. (note that friio_tuner_i2c_xfer() does NOT combine the two I2C messages of one read, and issues separate USB message for each, contrary to gl861_i2c_master_xfer()). - The second USB message uses CMD_READ but 'index'(demod register addr) value exceeds 8bit (0x0100), thus cannot use the normal gl861_i2c_master_xfer() as is. It looks to me different. It looks just read command done with 2 separate I2C messages (look I2C specs REPEATED START vs. STOP START). OK, I will add support for bulk I2C READs for adapter too, no problem. See updated patch on ml. Tested it quickly against qt1010 tuner and results are expected: dvb_usb_gl861 1-14:1.0: 0 | 40 01 1a 1e 62 00 00 00 >>> dvb_usb_gl861 1-14:1.0: 1 | c0 02 00 c4 29 00 01 00 <<< 39 dvb_usb_gl861 1-14:1.0: 0 | 40 03 00 c4 29 00 00 00 >>> dvb_usb_gl861 1-14:1.0: 1 | c0 02 00 c4 00 01 01 00 <<< 39 dvb_usb_gl861 1-14:1.0: 1 | c0 02 00 c4 00 01 01 00 <<< 39 dvb_usb_gl861 1-14:1.0: 1 | c0 02 00 c4 00 01 01 00 <<< 39 dvb_usb_gl861 1-14:1.0: 1 | c0 02 00 c4 00 01 01 00 <<< 39 dvb_usb_gl861 1-14:1.0: 0 | 40 01 0a 1e 62 00 00 00 >>> Register 29 is likely chip id and its value is always 39. So it first makes normal write+write to that register which sets and leaves chip registers address counter to that. After that each plain I2C read request gives 39 which is correct content for that register. Antti -- http://palosaari.fi/
Re: Logilink VG0022A firmware/si2157 probe
Hello, On 10/17/19 12:08 PM, Sean Young wrote: Hi Antti, I have a Logilink VG0022A device which is an af9035.c type device (with ITE 9xxx frontned). The probe of the si2146 tuner fails and returns 0xffs. Now I would like to work on fixing this. Mauro suggested the firmware might be incorrect. Any tips on extracting the firmware? I can try and dump usb traffic from Windows and see what firmware is being used there. How did you extract the firmware? Any other suggestions for this device? You might be able to save me a lot of time since you have experience with these types of devices, I do not. Extracting firmware is done almost always by following steps: 1) take sniffs from the some bus (usb/i2c) 2) identify firmware download section, detect it starting point and ending point ~few first and last bytes 3) find that firmware binary located inside of binary driver * grep, hexeditor, etc * example LANG=C grep -obUaP "\x08\x05\x00" driver.sys 4) use dd command to copy firmware blob from binary driver to separate file (you need to know firmware location and length inside binary) It is also possible to dump firmware to file from bus sniffs too, but it requires writing some simple script. Dumping it from the binary driver is usually still most easiest way. At some point I downloaded bunch of drivers to find out multiple firmware versions for si2168 and made simple script to ease things. Script is attached. After all, I suspect root of issue may be still be buggy i2c... regards Antti -- http://palosaari.fi/ #!/usr/bin/env python # Silicon Labs Si2168 firmware extractor. # Copyright (C) 2015 Antti Palosaari # Usage: si2168_extract_firmware.py binary_driver_name.sys import sys import struct import md5 fread = file(sys.argv[1], 'rb') binary = fread.read() offset = 0 # Known firmware md5 and its version fw_ver_tab = { '02c9b1e751f362621c649ea831410b61' : '4.0.7', 'b2670d8ae5e3369fc71edbb98cdd8f6e' : '4.0.11', '8dfc2483d90282bbb05817fbbc282376' : '4.0.19', 'c8e089c351e9834060e962356f8697b8' : '4.0.25', } while True: # Match 17-byte firmware header # 04 01 00 00 00 00 9a 41 05 1b af 33 02 1b 3e 7d 2a | A20 (not supported) # 08 05 00 xx xx xx xx xx xx 00 00 00 00 00 00 00 00 | B40 offset = binary.find('\x08\x05\x00', offset) if offset == -1: print "Done" break if (binary[offset + 9:offset + 17] != '\x00\x00\x00\x00\x00\x00\x00\x00'): offset = offset + 1 continue print "Possible 17-byte Si2168-B40 firmware header found at 0x%x" % (offset) fw_filename = 'dvb-demod-si2168-b40-01.fw_' + str(offset) fw_write = open(fw_filename, 'wb') fw_md5 = md5.new() while True: fields = struct.unpack("B", binary[offset]) fw_data_len = fields[0] # Firmware chunk first byte tells bytes to upload - 16 is max if fw_data_len == 0 or fw_data_len > 16: break # Check remaining (unused) bytes on firmware 17-byte chunk are all zero data_valid = True for x in range(offset + fw_data_len + 1, offset + 17): if (binary[x] != '\x00'): data_valid = False break if data_valid == False: break # Firmware chunk validated, write it to file fw_write.write(binary[offset + 0:offset + 17]) fw_md5.update(binary[offset + 0:offset + 17]) offset = offset + 17 fw_write.close() if fw_md5.hexdigest() in fw_ver_tab: fw_ver = fw_ver_tab[fw_md5.hexdigest()] else: fw_ver = '' print "Firmware md5 '%s'" % (fw_md5.hexdigest()) print "Firmware version '%s'" % (fw_ver) print "Firmware stored to file '%s'" % (fw_filename) offset = offset + 1 fread.close()
Re: Logilink VG0022A firmware/si2157 probe
On 10/17/19 4:46 PM, JP wrote: Hi there, On 10/17/19 2:15 PM, Antti Palosaari wrote: Hello, On 10/17/19 12:08 PM, Sean Young wrote: Hi Antti, I have a Logilink VG0022A device which is an af9035.c type device (with ITE 9xxx frontned). The probe of the si2146 tuner fails and returns 0xffs. Now I would like to work on fixing this. Mauro suggested the firmware might be incorrect. Any tips on extracting the firmware? I can try and dump usb traffic from Windows and see what firmware is being used there. How did you extract the firmware? If the receiver has onboard firmware, isn't that the right one? Then the windows driver has no need to load one. Or am I missing the point here? Actually I am not even 100% sure what are used chips of that device, but I expect those are: usb-interface: IT9303, needs firmware, cannot be loaded from the eeprom IIRC demodulator: Si2168 (revision B or C?), chip has rom that contains firmware, but usually it is replaced newer by downloading tuner: Si2157 or same family, similar firmware solution than Si2168. Si2157 I originally used didn't uploaded firmware update at all, later there was added more and more Silabs tuner versions and firmware downloading. Si2168B could be started (and it worked at the time I tested) with default rom firmware by using that kind of stub firmware: $ hexdump -C dvb-demod-si2168-b40-01.fw 05 00 00 00 00 00 00 00 || 0008 Not sure if that works any other than just Si2168B. Any other suggestions for this device? You might be able to save me a lot of time since you have experience with these types of devices, I do not. Extracting firmware is done almost always by following steps: 1) take sniffs from the some bus (usb/i2c) 2) identify firmware download section, detect it starting point and ending point ~few first and last bytes 3) find that firmware binary located inside of binary driver * grep, hexeditor, etc * example LANG=C grep -obUaP "\x08\x05\x00" driver.sys 4) use dd command to copy firmware blob from binary driver to separate file (you need to know firmware location and length inside binary) It is also possible to dump firmware to file from bus sniffs too, but it requires writing some simple script. Dumping it from the binary driver is usually still most easiest way. At some point I downloaded bunch of drivers to find out multiple firmware versions for si2168 and made simple script to ease things. Script is attached. After all, I suspect root of issue may be still be buggy i2c... Me too. Jan Pieter. It could be interesting to see from the sniffs what kind of firmwares windows driver downloads to different chips AND if i2c communication is working properly. regards Antti -- http://palosaari.fi/
Re: [PATCH 1/3] rtl2832: add support for slave ts pid filter
Patch looks acceptable, but it is broken in a mean it does not apply :( $ wget -O - https://patchwork.linuxtv.org/patch/32030/mbox/ | git am -3 -s --2015-12-21 04:40:46-- https://patchwork.linuxtv.org/patch/32030/mbox/ Resolving patchwork.linuxtv.org (patchwork.linuxtv.org)... 130.149.80.248 Connecting to patchwork.linuxtv.org (patchwork.linuxtv.org)|130.149.80.248|:443... connected. HTTP request sent, awaiting response... 200 OK Length: unspecified [text/plain] Saving to: ‘STDOUT’ - [ <=> ] 2.73K --.-KB/s in 0s 2015-12-21 04:40:46 (60.4 MB/s) - written to stdout [2796] Applying: rtl2832: add support for slave ts pid filter fatal: corrupt patch at line 39 Repository lacks necessary blobs to fall back on 3-way merge. Cannot fall back to three-way merge. Patch failed at 0001 rtl2832: add support for slave ts pid filter The copy of the patch that failed is found in: /home/crope/linuxtv/code/media_tree/.git/rebase-apply/patch When you have resolved this problem, run "git am --continue". If you prefer to skip this patch, run "git am --skip" instead. To restore the original branch and stop patching, run "git am --abort". [crope@localhost media_tree]$ patch -p1 < .git/rebase-apply/patch patching file drivers/media/dvb-frontends/rtl2832.c patch: malformed patch at line 39: @@ -1178,14 +1185,22 @@ static int rtl2832_pid_filter(struct dvb_frontend *fe, u8 index, u16 pid, [crope@localhost media_tree]$ git am --abort [crope@localhost media_tree]$ git am ~/\[PATCH\ 1_3\]\ rtl2832\:\ add\ support\ for\ slave\ ts\ pid\ filter.eml Applying: rtl2832: add support for slave ts pid filter fatal: corrupt patch at line 39 Patch failed at 0001 rtl2832: add support for slave ts pid filter The copy of the patch that failed is found in: /home/crope/linuxtv/code/media_tree/.git/rebase-apply/patch When you have resolved this problem, run "git am --continue". If you prefer to skip this patch, run "git am --skip" instead. To restore the original branch and stop patching, run "git am --abort". [crope@localhost media_tree]$ git am --abort Antti On 11/29/2015 04:10 AM, Benjamin Larsson wrote: Signed-off-by: Benjamin Larsson --- drivers/media/dvb-frontends/rtl2832.c | 21 ++--- drivers/media/dvb-frontends/rtl2832_priv.h | 1 + 2 files changed, 19 insertions(+), 3 deletions(-) diff --git a/drivers/media/dvb-frontends/rtl2832.c b/drivers/media/dvb-frontends/rtl2832.c index 78b87b2..e054079 100644 --- a/drivers/media/dvb-frontends/rtl2832.c +++ b/drivers/media/dvb-frontends/rtl2832.c @@ -407,6 +407,7 @@ static int rtl2832_init(struct dvb_frontend *fe) /* start statistics polling */ schedule_delayed_work(&dev->stat_work, msecs_to_jiffies(2000)); dev->sleeping = false; + dev->slave_ts = false; return 0; err: @@ -1122,6 +1123,8 @@ static int rtl2832_enable_slave_ts(struct i2c_client *client) if (ret) goto err; + dev->slave_ts = true; + return 0; err: dev_dbg(&client->dev, "failed=%d\n", ret); @@ -1143,7 +1146,11 @@ static int rtl2832_pid_filter_ctrl(struct dvb_frontend *fe, int onoff) else u8tmp = 0x00; - ret = rtl2832_update_bits(client, 0x061, 0xc0, u8tmp); + if (dev->slave_ts) + ret = rtl2832_update_bits(client, 0x021, 0xc0, u8tmp); + else + ret = rtl2832_update_bits(client, 0x061, 0xc0, u8tmp); if (ret) goto err; @@ -1178,14 +1185,22 @@ static int rtl2832_pid_filter(struct dvb_frontend *fe, u8 index, u16 pid, buf[1] = (dev->filters >> 8) & 0xff; buf[2] = (dev->filters >> 16) & 0xff; buf[3] = (dev->filters >> 24) & 0xff; - ret = rtl2832_bulk_write(client, 0x062, buf, 4); + + if (dev->slave_ts) + ret = rtl2832_bulk_write(client, 0x022, buf, 4); + else + ret = rtl2832_bulk_write(client, 0x062, buf, 4); if (ret) goto err; /* add PID */ buf[0] = (pid >> 8) & 0xff; buf[1] = (pid >> 0) & 0xff; - ret = rtl2832_bulk_write(client, 0x066 + 2 * index, buf, 2); + + if (dev->slave_ts) + ret = rtl2832_bulk_write(client, 0x026 + 2 * index, buf, 2); + else + ret = rtl2832_bulk_write(client, 0x066 + 2 * index, buf, 2); if (ret) goto err; diff --git a/drivers/media/dvb-frontends/rtl2832_priv.h b/drivers/media/dvb-frontends/rtl2832_priv.h index 5dcd3a4..efc230f 100644 --- a/drivers/media/dvb-frontends/rtl2832_priv.h +++ b/drivers/media/dvb-frontends/rtl2832_priv.h @@ -46,6 +46,7 @@ struct rtl2832_dev { bool sleeping; struct delayed_work i2c_gate_work; unsigned long filters; /* PID filter */ + bool slave_ts; }; struct rtl2832_reg_entry { -- http://palosaari.fi/ -- To unsubscribe from this list: send the line "unsubscribe linu
Re: [PATCH 2/3] mn88472: add work around for failing firmware loading
Hello I am not sure if problem is I2C adapter/bus or that demodulator I2C slave. If it is demod, then that workaround is correct place, but if it is not, then that is wrong and I2C adapter repeating logic should be used. I did some testing again... Loading mn88472 firmware 1000 times, it failed: 61 times RC polling disabled 68 times RC polling enabled 83 times RC polling enabled, but repeated failed message due to that patch I don't want apply that patch until I find some time myself to examine that problem - or someone else does some study to point out whats wrong. There is many things to test in order to get better understanding. regards Antti On 11/29/2015 04:10 AM, Benjamin Larsson wrote: Sometimes the firmware fails to load because of an i2c error. Work around that by adding retry logic. This kind of logic also exist in the binary driver and failures have been observed there also. Thus this seems to be a property of the hardware and a fix like this is needed. Signed-off-by: Benjamin Larsson --- drivers/staging/media/mn88472/mn88472.c | 15 ++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/drivers/staging/media/mn88472/mn88472.c b/drivers/staging/media/mn88472/mn88472.c index cf2e96b..80c5807 100644 --- a/drivers/staging/media/mn88472/mn88472.c +++ b/drivers/staging/media/mn88472/mn88472.c @@ -282,7 +282,7 @@ static int mn88472_init(struct dvb_frontend *fe) int ret, len, remaining; const struct firmware *fw = NULL; u8 *fw_file = MN88472_FIRMWARE; - unsigned int tmp; + unsigned int tmp, retry_cnt; dev_dbg(&client->dev, "\n"); @@ -330,9 +330,22 @@ static int mn88472_init(struct dvb_frontend *fe) if (len > (dev->i2c_wr_max - 1)) len = dev->i2c_wr_max - 1; + /* I2C transfers during firmware load might fail sometimes, +* just retry in that case. 4 consecutive failures have +* been observed thus a retry limit of 20 is used. +*/ + retry_cnt = 20; +retry: ret = regmap_bulk_write(dev->regmap[0], 0xf6, &fw->data[fw->size - remaining], len); if (ret) { + if (retry_cnt) { + dev_dbg(&client->dev, + "i2c error, retry %d triggered\n", retry_cnt); + retry_cnt--; + usleep_range(200, 1); + goto retry; + } dev_err(&client->dev, "firmware download failed=%d\n", ret); goto firmware_release; -- http://palosaari.fi/ -- To unsubscribe from this list: send the line "unsubscribe linux-media" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
[GIT PULL 4.5] rtl2832u changes
The following changes since commit 0aff8a894a2be4c22e6414db33061153a4b35bc9: [media] uvcvideo: small cleanup in uvc_video_clock_update() (2015-12-18 15:21:35 -0200) are available in the git repository at: git://linuxtv.org/anttip/media_tree.git rtl2832u_pull for you to fetch changes up to bbed859d68218c043fa88ccdd9785d9567d8fb5d: rtl2832: do not filter out slave TS null packets (2015-12-20 04:57:20 +0200) Antti Palosaari (3): rtl28xxu: return demod reg page from driver cache rtl2832: print reg number on error case rtl2832: do not filter out slave TS null packets drivers/media/dvb-frontends/rtl2832.c | 21 ++--- drivers/media/usb/dvb-usb-v2/rtl28xxu.c | 16 +++- 2 files changed, 17 insertions(+), 20 deletions(-) -- http://palosaari.fi/ -- To unsubscribe from this list: send the line "unsubscribe linux-media" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
[PATCH] si2168: use i2c controlled mux interface
Recent i2c mux locking update offers support for i2c controlled i2c muxes. Use it and get the rid of homemade hackish i2c adapter locking code. Cc: Peter Rosin Cc: Peter Rosin Signed-off-by: Antti Palosaari --- drivers/media/dvb-frontends/si2168.c | 61 1 file changed, 6 insertions(+), 55 deletions(-) diff --git a/drivers/media/dvb-frontends/si2168.c b/drivers/media/dvb-frontends/si2168.c index ae217b5..d2a5608 100644 --- a/drivers/media/dvb-frontends/si2168.c +++ b/drivers/media/dvb-frontends/si2168.c @@ -18,48 +18,15 @@ static const struct dvb_frontend_ops si2168_ops; -/* Own I2C adapter locking is needed because of I2C gate logic. */ -static int si2168_i2c_master_send_unlocked(const struct i2c_client *client, - const char *buf, int count) -{ - int ret; - struct i2c_msg msg = { - .addr = client->addr, - .flags = 0, - .len = count, - .buf = (char *)buf, - }; - - ret = __i2c_transfer(client->adapter, &msg, 1); - return (ret == 1) ? count : ret; -} - -static int si2168_i2c_master_recv_unlocked(const struct i2c_client *client, - char *buf, int count) -{ - int ret; - struct i2c_msg msg = { - .addr = client->addr, - .flags = I2C_M_RD, - .len = count, - .buf = buf, - }; - - ret = __i2c_transfer(client->adapter, &msg, 1); - return (ret == 1) ? count : ret; -} - /* execute firmware command */ -static int si2168_cmd_execute_unlocked(struct i2c_client *client, - struct si2168_cmd *cmd) +static int si2168_cmd_execute(struct i2c_client *client, struct si2168_cmd *cmd) { int ret; unsigned long timeout; if (cmd->wlen) { /* write cmd and args for firmware */ - ret = si2168_i2c_master_send_unlocked(client, cmd->args, - cmd->wlen); + ret = i2c_master_send(client, cmd->args, cmd->wlen); if (ret < 0) { goto err; } else if (ret != cmd->wlen) { @@ -73,8 +40,7 @@ static int si2168_cmd_execute_unlocked(struct i2c_client *client, #define TIMEOUT 70 timeout = jiffies + msecs_to_jiffies(TIMEOUT); while (!time_after(jiffies, timeout)) { - ret = si2168_i2c_master_recv_unlocked(client, cmd->args, - cmd->rlen); + ret = i2c_master_recv(client, cmd->args, cmd->rlen); if (ret < 0) { goto err; } else if (ret != cmd->rlen) { @@ -109,17 +75,6 @@ err: return ret; } -static int si2168_cmd_execute(struct i2c_client *client, struct si2168_cmd *cmd) -{ - int ret; - - i2c_lock_adapter(client->adapter); - ret = si2168_cmd_execute_unlocked(client, cmd); - i2c_unlock_adapter(client->adapter); - - return ret; -} - static int si2168_read_status(struct dvb_frontend *fe, enum fe_status *status) { struct i2c_client *client = fe->demodulator_priv; @@ -610,11 +565,6 @@ static int si2168_get_tune_settings(struct dvb_frontend *fe, return 0; } -/* - * I2C gate logic - * We must use unlocked I2C I/O because I2C adapter lock is already taken - * by the caller (usually tuner driver). - */ static int si2168_select(struct i2c_mux_core *muxc, u32 chan) { struct i2c_client *client = i2c_mux_priv(muxc); @@ -625,7 +575,7 @@ static int si2168_select(struct i2c_mux_core *muxc, u32 chan) memcpy(cmd.args, "\xc0\x0d\x01", 3); cmd.wlen = 3; cmd.rlen = 0; - ret = si2168_cmd_execute_unlocked(client, &cmd); + ret = si2168_cmd_execute(client, &cmd); if (ret) goto err; @@ -645,7 +595,7 @@ static int si2168_deselect(struct i2c_mux_core *muxc, u32 chan) memcpy(cmd.args, "\xc0\x0d\x00", 3); cmd.wlen = 3; cmd.rlen = 0; - ret = si2168_cmd_execute_unlocked(client, &cmd); + ret = si2168_cmd_execute(client, &cmd); if (ret) goto err; @@ -717,6 +667,7 @@ static int si2168_probe(struct i2c_client *client, dev->muxc->parent = client->adapter; dev->muxc->select = si2168_select; dev->muxc->deselect = si2168_deselect; + dev->muxc->i2c_controlled = true; /* create mux i2c adapter for tuner */ ret = i2c_add_mux_adapter(dev->muxc, 0, 0, 0); -- http://palosaari.fi/ -- To unsubscribe from this list: send the line "unsubscribe linux-media" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
Re: [PATCH] si2168: use i2c controlled mux interface
Moikka! On 01/06/2016 09:14 AM, Peter Rosin wrote: Hi Antti, On 2016-01-06 06:42, Antti Palosaari wrote: Recent i2c mux locking update offers support for i2c controlled i2c muxes. Use it and get the rid of homemade hackish i2c adapter locking code. That looks good on a first glance, and I'm sure it felt good to get rid of the locking workaround :-) And I forgot mutext to protect si2168_cmd_execute()... However, is this safe? From looking at the short datasheet of the si2168, it seems that the mux is used to open up the channel to the tuner? But what happens is there are two parallel accesses, one to the tuner and one to the si2168 chip? With your change, it could happen that the access to the si2168 happens while the gate to the tuner is open. Can that break anything? I.e. thread one thread two -- -- open gate access si2168 access tuner close gate If that is safe, then I don't understand why the gate isn't left open at all times? The short datasheet is too short to answer my questions... It is often called I2C Gate or repeater, and yes it is there to block noise traveling to tuner. I think that noise could be unnecessary I2C traffic as well some digital noise travelling via I2C wires. Tuners are usually build using pure digital logic + analog circuits (RF mixers, RF filters, RF amplifiers). Leaving gate open usually does not harm and there is even some designs it is connected directly to main bus (but almost all demodulators still has that kind of gate to connect tuner). All in all, I don't see it very big issue if only few unwanted I2C messages are sent to bus tuner is connected. Also, my series needs some Tested-by (and Reviewed-by for that matter), and I assume that you have tested it? Is it ok to add something like that from you? I understand that you may only be able to test your corner of the series, but that would still be very helpful. Thanks! Yes it worked, but I haven't examined it care enough yet. However, I think I see one problem: i2c muxes that deselects channel automatically, usually after the first i2c stop (P) condition is seen. regards Antti Cheers, Peter Cc: Peter Rosin Cc: Peter Rosin Signed-off-by: Antti Palosaari --- drivers/media/dvb-frontends/si2168.c | 61 1 file changed, 6 insertions(+), 55 deletions(-) diff --git a/drivers/media/dvb-frontends/si2168.c b/drivers/media/dvb-frontends/si2168.c index ae217b5..d2a5608 100644 --- a/drivers/media/dvb-frontends/si2168.c +++ b/drivers/media/dvb-frontends/si2168.c @@ -18,48 +18,15 @@ static const struct dvb_frontend_ops si2168_ops; -/* Own I2C adapter locking is needed because of I2C gate logic. */ -static int si2168_i2c_master_send_unlocked(const struct i2c_client *client, - const char *buf, int count) -{ - int ret; - struct i2c_msg msg = { - .addr = client->addr, - .flags = 0, - .len = count, - .buf = (char *)buf, - }; - - ret = __i2c_transfer(client->adapter, &msg, 1); - return (ret == 1) ? count : ret; -} - -static int si2168_i2c_master_recv_unlocked(const struct i2c_client *client, - char *buf, int count) -{ - int ret; - struct i2c_msg msg = { - .addr = client->addr, - .flags = I2C_M_RD, - .len = count, - .buf = buf, - }; - - ret = __i2c_transfer(client->adapter, &msg, 1); - return (ret == 1) ? count : ret; -} - /* execute firmware command */ -static int si2168_cmd_execute_unlocked(struct i2c_client *client, - struct si2168_cmd *cmd) +static int si2168_cmd_execute(struct i2c_client *client, struct si2168_cmd *cmd) { int ret; unsigned long timeout; if (cmd->wlen) { /* write cmd and args for firmware */ - ret = si2168_i2c_master_send_unlocked(client, cmd->args, - cmd->wlen); + ret = i2c_master_send(client, cmd->args, cmd->wlen); if (ret < 0) { goto err; } else if (ret != cmd->wlen) { @@ -73,8 +40,7 @@ static int si2168_cmd_execute_unlocked(struct i2c_client *client, #define TIMEOUT 70 timeout = jiffies + msecs_to_jiffies(TIMEOUT); while (!time_after(jiffies, timeout)) { - ret = si2168_i2c_master_recv_unlocked(client, cmd->args, - cmd->rlen); + ret = i2c_master_recv(client, cmd->args, cmd->rlen);
Re: [PATCH v2 0/8] i2c mux cleanup and locking update
On 01/05/2016 05:57 PM, Peter Rosin wrote: From: Peter Rosin Hi! I have a pair of boards with this i2c topology: GPIO ---| -- BAT1 | v / I2C -+--B---+ MUX | \ EEPROM -- BAT2 (B denotes the boundary between the boards) Handling of I2C muxes that close channel automatically, after the first I2C stop (P) is seen? For example channel is selected to BAT1 => there is EEPROM write => mux closes channel BAT1 => access to BAT1 will fail. Is it possible to lock whole adapter, but allow only traffic to i2c mux client? regards Antti The problem with this is that the GPIO controller sits on the same i2c bus that it MUXes. For pca954x devices this is worked around by using unlocked transfers when updating the MUX. I have no such luck as the GPIO is a general purpose IO expander and the MUX is just a random bidirectional MUX, unaware of the fact that it is muxing an i2c bus, and extending unlocked transfers into the GPIO subsystem is too ugly to even think about. But the general hw approach is sane in my opinion, with the number of connections between the two boards minimized. To put is plainly, I need support for it. So, I observe that while it is needed to have the i2c bus locked during the actual MUX update in order to avoid random garbage on the slave side, it is not strictly a must to have it locked over the whole sequence of a full select-transfer-deselect operation. The MUX itself needs to be locked, so transfers to clients behind the mux are serialized, and the MUX needs to be stable during all i2c traffic (otherwise individual mux slave segments might see garbage). This series accomplishes this by adding a dt property to i2c-mux-gpio and i2c-mux-pinctrl that can be used to state that the mux is updated by means of the muxed master bus, and that the select-transfer-deselect operations should be locked individually. When this holds, the i2c bus *is* locked during muxing, since the muxing happens as part of i2c transfers. This is true even if the MUX is updated with several transfers to the GPIO (at least as long as *all* MUX changes are using the i2s master bus). A lock is added to the mux so that transfers through the mux are serialized. Concerns: - The locking is perhaps too complex? - I worry about the priority inheritance aspect of the adapter lock. When the transfers behind the mux are divided into select-transfer-deselect all locked individually, low priority transfers get more chances to interfere with high priority transfers. - When doing an i2c_transfer() in_atomic() context of with irqs_disabled(), there is a higher possibility that the mux is not returned to its idle state after a failed (-EAGAIN) transfer due to trylock. To summarize the series, there's some i2c-mux infrastructure cleanup work first (I think that part stands by itself as desireable regardless), the locking changes are in the last three patches of the series, with the real meat in 8/8. PS. needs a bunch of testing, I do not have access to all the involved hw Changes since v1: - Allocate mux core and (optional) priv in a combined allocation. - Killed dev_err messages triggered by memory allocation failure. - Fix the device specific i2c muxes that I had overlooked. - Rebased on top of v4.4-rc8 (was based on v4.4-rc6 previously). Cheers, Peter Peter Rosin (8): i2c-mux: add common core data for every mux instance i2c-mux: move select and deselect ops to i2c_mux_core i2c-mux: move the slave side adapter management to i2c_mux_core i2c-mux: remove the mux dev pointer from the mux per channel data i2c-mux: pinctrl: get rid of the driver private struct device pointer i2c: allow adapter drivers to override the adapter locking i2c: muxes always lock the parent adapter i2c-mux: relax locking of the top i2c adapter during i2c controlled muxing .../devicetree/bindings/i2c/i2c-mux-gpio.txt | 2 + .../devicetree/bindings/i2c/i2c-mux-pinctrl.txt| 4 + drivers/i2c/i2c-core.c | 59 ++--- drivers/i2c/i2c-mux.c | 272 + drivers/i2c/muxes/i2c-arb-gpio-challenge.c | 46 ++-- drivers/i2c/muxes/i2c-mux-gpio.c | 58 ++--- drivers/i2c/muxes/i2c-mux-pca9541.c| 58 +++-- drivers/i2c/muxes/i2c-mux-pca954x.c| 66 ++--- drivers/i2c/muxes/i2c-mux-pinctrl.c| 89 +++ drivers/i2c/muxes/i2c-mux-reg.c| 63 ++--- drivers/iio/imu/inv_mpu6050/inv_mpu_core.c | 33 +-- drivers/iio/imu/inv_mpu6050/inv_mpu_iio.h | 2 +- drivers/media/dvb-frontends/m88ds3103.c| 23 +- drivers/media/dvb-frontends/m88ds3103_priv.h | 2 +- drivers/media/dvb-frontends/rtl2830.c | 24 +- drivers/media/dvb-frontends/rtl2830_p
[PATCH] rtl28xxu: retry failed i2c messages
Sometimes i2c transfer fails. That happens especially when large amount of data is written sequentially eg. firmware download. Problem arises with both integrated rtl2832 demod and external mn88472 demod, which is clear indicator it is busy i2c bus issue. Use i2c core retry logic in order fix the issue by repeating failed message. Another solution which also works is to add ~100us delay between i2c messages - but repeating sounds more elegant and does not cause any extra delay for success cases. Signed-off-by: Antti Palosaari --- drivers/media/usb/dvb-usb-v2/rtl28xxu.c | 8 1 file changed, 8 insertions(+) diff --git a/drivers/media/usb/dvb-usb-v2/rtl28xxu.c b/drivers/media/usb/dvb-usb-v2/rtl28xxu.c index eb5787a..c4c6e92 100644 --- a/drivers/media/usb/dvb-usb-v2/rtl28xxu.c +++ b/drivers/media/usb/dvb-usb-v2/rtl28xxu.c @@ -259,6 +259,10 @@ static int rtl28xxu_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msg[], ret = -EOPNOTSUPP; } + /* Retry failed I2C messages */ + if (ret == -EPIPE) + ret = -EAGAIN; + err_mutex_unlock: mutex_unlock(&d->i2c_mutex); @@ -619,6 +623,10 @@ static int rtl28xxu_identify_state(struct dvb_usb_device *d, const char **name) } dev_dbg(&d->intf->dev, "chip_id=%u\n", dev->chip_id); + /* Retry failed I2C messages */ + d->i2c_adap.retries = 1; + d->i2c_adap.timeout = msecs_to_jiffies(10); + return WARM; err: dev_dbg(&d->intf->dev, "failed=%d\n", ret); -- http://palosaari.fi/ -- To unsubscribe from this list: send the line "unsubscribe linux-media" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
[GIT PULL] mn88473: move out of staging
Resend, just forgot [GIT PULL] subject prefix earlier. The following changes since commit 210bd104c6acd31c3c6b8b075b3f12d4a9f6b60d: [media] xc2028: unlock on error in xc2028_set_config() (2016-02-04 09:30:31 -0200) are available in the git repository at: git://linuxtv.org/anttip/media_tree.git mn88473_pull for you to fetch changes up to 05886118dd140b4d96cf4de5c76b4fb6155316f5: rtl2832: move stats polling to read status (2016-02-14 04:29:33 +0200) Antti Palosaari (4): mn88473: move out of staging mn88473: finalize driver rtl2832: improve slave TS control rtl2832: move stats polling to read status MAINTAINERS | 4 +- drivers/media/dvb-frontends/Kconfig | 8 +++ drivers/media/dvb-frontends/Makefile | 1 + drivers/{staging/media/mn88473 => media/dvb-frontends}/mn88473.c | 388 drivers/media/dvb-frontends/mn88473.h | 14 ++--- drivers/{staging/media/mn88473 => media/dvb-frontends}/mn88473_priv.h | 7 +-- drivers/media/dvb-frontends/rtl2832.c | 151 +--- drivers/media/dvb-frontends/rtl2832.h | 4 +- drivers/media/dvb-frontends/rtl2832_priv.h | 1 - drivers/media/usb/dvb-usb-v2/rtl28xxu.c | 24 +++ drivers/staging/media/Kconfig | 2 - drivers/staging/media/Makefile | 1 - drivers/staging/media/mn88473/Kconfig | 7 --- drivers/staging/media/mn88473/Makefile | 5 -- drivers/staging/media/mn88473/TODO | 21 --- 15 files changed, 340 insertions(+), 298 deletions(-) rename drivers/{staging/media/mn88473 => media/dvb-frontends}/mn88473.c (61%) rename drivers/{staging/media/mn88473 => media/dvb-frontends}/mn88473_priv.h (89%) delete mode 100644 drivers/staging/media/mn88473/Kconfig delete mode 100644 drivers/staging/media/mn88473/Makefile delete mode 100644 drivers/staging/media/mn88473/TODO -- http://palosaari.fi/ -- To unsubscribe from this list: send the line "unsubscribe linux-media" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
[PATCH] si2168: add lock to cmd execute
Mauro do not apply that patch, it is fix for Peter I2C-mux serie! Peter, please meld that fix to main patch: [media] si2168: declare that the i2c gate is self-locked We need lock to make sure only single caller could execute firmware command at the time. Earlier there was manual I2C locking which did the same job. Cc: Peter Rosin Signed-off-by: Antti Palosaari --- drivers/media/dvb-frontends/si2168.c | 21 ++--- drivers/media/dvb-frontends/si2168_priv.h | 1 + 2 files changed, 15 insertions(+), 7 deletions(-) diff --git a/drivers/media/dvb-frontends/si2168.c b/drivers/media/dvb-frontends/si2168.c index 4a9b73b..786808f 100644 --- a/drivers/media/dvb-frontends/si2168.c +++ b/drivers/media/dvb-frontends/si2168.c @@ -21,17 +21,20 @@ static const struct dvb_frontend_ops si2168_ops; /* execute firmware command */ static int si2168_cmd_execute(struct i2c_client *client, struct si2168_cmd *cmd) { + struct si2168_dev *dev = i2c_get_clientdata(client); int ret; unsigned long timeout; + mutex_lock(&dev->i2c_mutex); + if (cmd->wlen) { /* write cmd and args for firmware */ ret = i2c_master_send(client, cmd->args, cmd->wlen); if (ret < 0) { - goto err; + goto err_mutex_unlock; } else if (ret != cmd->wlen) { ret = -EREMOTEIO; - goto err; + goto err_mutex_unlock; } } @@ -42,10 +45,10 @@ static int si2168_cmd_execute(struct i2c_client *client, struct si2168_cmd *cmd) while (!time_after(jiffies, timeout)) { ret = i2c_master_recv(client, cmd->args, cmd->rlen); if (ret < 0) { - goto err; + goto err_mutex_unlock; } else if (ret != cmd->rlen) { ret = -EREMOTEIO; - goto err; + goto err_mutex_unlock; } /* firmware ready? */ @@ -60,17 +63,19 @@ static int si2168_cmd_execute(struct i2c_client *client, struct si2168_cmd *cmd) /* error bit set? */ if ((cmd->args[0] >> 6) & 0x01) { ret = -EREMOTEIO; - goto err; + goto err_mutex_unlock; } if (!((cmd->args[0] >> 7) & 0x01)) { ret = -ETIMEDOUT; - goto err; + goto err_mutex_unlock; } } + mutex_unlock(&dev->i2c_mutex); return 0; -err: +err_mutex_unlock: + mutex_unlock(&dev->i2c_mutex); dev_dbg(&client->dev, "failed=%d\n", ret); return ret; } @@ -658,6 +663,8 @@ static int si2168_probe(struct i2c_client *client, goto err; } + mutex_init(&dev->i2c_mutex); + /* create mux i2c adapter for tuner */ dev->muxc = i2c_mux_one_adapter(client->adapter, &client->dev, 0, I2C_MUX_SELF_LOCKED, 0, 0, 0, diff --git a/drivers/media/dvb-frontends/si2168_priv.h b/drivers/media/dvb-frontends/si2168_priv.h index 165bf14..8a1f36d 100644 --- a/drivers/media/dvb-frontends/si2168_priv.h +++ b/drivers/media/dvb-frontends/si2168_priv.h @@ -29,6 +29,7 @@ /* state struct */ struct si2168_dev { + struct mutex i2c_mutex; struct i2c_mux_core *muxc; struct dvb_frontend fe; enum fe_delivery_system delivery_system; -- http://palosaari.fi/ -- To unsubscribe from this list: send the line "unsubscribe linux-media" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
Re: [PATCH v4 00/18] i2c mux cleanup and locking update
On 03/15/2016 04:09 PM, Peter Rosin wrote: The series will be posted again for review. This is just a heads up. v5 compared to v4: - Rebase on top of v4.5-rc7. - A new patch making me maintainer of i2c muxes (also sent separately). - A new file Documentation/i2c/i2c-topology that describes various muxing issues. - Rename "i2c-controlled" muxes "self-locked" instead, as it is perfectly reasonable to have i2c-controlled muxes that use the pre-existing locking scheme. The pre-existing locking scheme for i2c muxes is from here on called "parent-locked". - Rename i2c-mux.c:i2c_mux_master_xfer to __i2c_mux_master_xfer since it calls __i2c_transfer, which leaves room for a new i2c_mux_master_xfer that calls i2c_transfer. Similar rename shuffle for i2c_mux_smbus_xfer. - Use sizeof(*priv) instead of sizeof(struct i2c_mux_priv). One instance. - Some follow-up patches that were posted in response to v2-v4 cleaning up and simplifying various i2c muxes outside drivers/i2c/, among those is an unrelated cleanup patch to drivers/media/dvb-frontends/rtl2832.c that I carry here since it conflicts (trivially) with this series. That unrelated patch is (currently) the last patch in the series. The series looks like this now: The following changes since commit f6cede5b49e822ebc41a099fe41ab4989f64e2cb: Linux 4.5-rc7 (2016-03-06 14:48:03 -0800) are available in the git repository at: https://github.com/peda-r/i2c-mux.git mux-core-and-locking-5 I reviewed and tested these patches: c1ef4a2 [media] rtl2832: regmap is aware of lockdep, drop local locking hack 6636178 [media] rtl2832_sdr: get rid of empty regmap wrappers 001ad6b [media] rtl2832: declare that the i2c gate is self-locked e2e82e4 [media] si2168: declare that the i2c gate is self-locked b52f766 [media] si2168: convert to use an explicit i2c mux core 4ba9115 [media] rtl2832: convert to use an explicit i2c mux core 3f1778b [media] rtl2830: convert to use an explicit i2c mux core 5c8bfc8 [media] m88ds3103: convert to use an explicit i2c mux core Reviewed-by: Antti Palosaari Tested-by: Antti Palosaari regards Antti -- http://palosaari.fi/ -- To unsubscribe from this list: send the line "unsubscribe linux-media" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
Re: [PATCH] si2168: use i2c controlled mux interface
On 03/23/2016 06:58 PM, Peter Rosin wrote: On 2016-01-06 06:42, Antti Palosaari wrote: Recent i2c mux locking update offers support for i2c controlled i2c muxes. Use it and get the rid of homemade hackish i2c adapter locking code. [actual patch elided] I had a 2nd look and it seems that the saa7164 driver has support for a HVR2055 card with dual si2168 chips. These two chips appear to sit on the same i2c-bus with different i2c-addresses (0x64 and 0x66) and with gates (implemented as muxes) to two identical tuners with the same i2c-address (0x60). Do I read it right? saa7164 has 3 different I2C adapters. saa7164 I2C bus #0: * eeprom * Si2157 #1 saa7164 I2C bus #1: * Si2157 #2 saa7164 I2C bus #2: * Si2168 #1 * Si2168 #2 So both of the Si2157 tuners could have same addresses. (It is Hauppauge WinTV-HVR2205, not HVR-2055). With the current i2c-mux-locking (parent-locked muxes), this works fine as an access to one of the tuners locks the root i2c adapter and thus the other tuner is also locked out. But with the upcoming i2c-mux-locking for i2c-controlled muxes (self-locked muxes), the root i2c adapter would no longer be locked for the full transaction when one of the tuners is accessed. This means that accesses to the two tuners may interleave and cause all kinds of trouble, should both gates be open at the same time. So, is it really correct and safe to change the si2168 driver to use a self-locked mux? Unless there is some other mechanism that prevents the two tuners from being accessed in parallel, I think not. But maybe there is such a mechanism? Good point. Actually there is pretty often this kind of configuration used for those dual tuner devices and it will cause problems... Currently all of those implements hackish i2c_gate_ctrl() callback to switch mux. |I2C-adapter | | I2C-mux | | I2C-client | || || || || | addr 0x1c | | addr 0x60 | || || || ||-+-I2C---|-/ -|---I2C---|| || | || || | | | I2C-mux | | I2C-client | | || || | | addr 0x1d | | addr 0x60 | | || || +-I2C---|-/ -|---I2C---|| || || regards Antti -- http://palosaari.fi/ -- To unsubscribe from this list: send the line "unsubscribe linux-media" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
Re: AVerMedia HD Volar (A867) AF9035 + MXL5007T driver issues
On 04/02/2016 01:44 PM, Alessandro Radicati wrote: Hi, In trying to understand why my DVB USB tuner doesn't work with stock kernel drivers (4.2.0), I decided to pull out my logic analyser and sniff the I2C bus between the AF9035 and MXL5007T. I seem to have uncovered a couple of issues: 1) Attach fails because MXL5007T driver I2C soft reset fails. This is due to the preceding chip id read request that seems to hang the I2C bus and cause subsequent I2C commands to fail. In my understanding MXL5007T register read is done in a two transactions. First you should write wanted register to register 0xfb. After that single byte read from the chip returns value for register configured to 0xfb. Write+read with repeated start is not supported and driver is buggy as it request that which usually leads to bogus value. 2) AF9035 driver I2C master xfer incorrectly implements "Write read" case. The FW expects register address fields to be used to send the I2C writes for register selection. The current implementation ignores these fields and the result is that only an I2C read is issued. Therefore the "0x3f" returned by the MXL5007T chip id query is not from the expected register. This is what is seen on the I2C bus: S | Read 0x60 + ACK | 0x3F + NAK | ... After which SDA is held low for ~6sec; reason for subsequent commands failing. You should use "S | W | P | S | R | P", no "S | W | S | R | P" == write read with repeated start condition. 3) After modifying the AF9035 driver to fix point 2 and use the register address field, the following is seen on the I2C bus: S | Write 0x60 + ACK | 0xFB + ACK | 0xD9 + ACK | P S | Read 0x60 + ACK | 0x14 + NAK | ... That is correct sequence. You are trying to read more than 1 byte and it fails? This time we get an expected response, but the I2C bus still hangs with SDA held low and no Stop sequence. It seems that the MXL5007T is holding SDA low since the AF9035 happily cycles SCL trying to execute the subsequent writes. Without a solution to this, it seems that avoiding the I2C read is the best way to have the driver work correctly. There are no other tuner reads so point 2 above becomes moot for at least this device. Does anyone have any insight on the MXL5007T chip ID command and whether it should be issued in certain conditions? Any suggestions on how to resolve this given the above? I tried to fix it earlier: http://www.spinics.net/lists/linux-media/msg62264.html Feel free to fix! It should not be very hard as you could even sniff data from the I2C bus directly. I don't have any AF9035+MXL5007T device, but I have tested it with older AF9015+MXL5007T. regards Antti -- http://palosaari.fi/ -- To unsubscribe from this list: send the line "unsubscribe linux-media" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
Re: AVerMedia HD Volar (A867) AF9035 + MXL5007T driver issues
I found one stick having AF9035 + MXL5007T. It is HP branded A867, so it should be similar. It seems to work all three 12.13.15.0 6.20.15.0 firmwares: http://palosaari.fi/linux/v4l-dvb/firmware/af9035/ mxl5007t 5-0060: creating new instance mxl5007t_get_chip_id: unknown rev (3f) mxl5007t_get_chip_id: MxL5007T detected @ 5-0060 That is what AF9035 reports (with debug) as a chip version: dvb_usb_af9035: prechip_version=00 chip_version=03 chip_type=3802 Do you have different chip version? regards Antti -- http://palosaari.fi/ -- To unsubscribe from this list: send the line "unsubscribe linux-media" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
Re: AVerMedia HD Volar (A867) AF9035 + MXL5007T driver issues
uh, how it could be so hard? I just made few tests and found 3 ways to read it. OK, one is that Alessandro already pointed out and I don't feel it correct. But those 2 are one for look. CMD_I2C_WR / CMD_I2C_RD with 1st priority, then CMD_GENERIC_I2C_WR / CMD_GENERIC_I2C_RD { u8 buf[MAX_XFER_SIZE]; struct usb_req req = {0, 0, 0, buf, 0, buf}; #if 0 req.cmd = CMD_GENERIC_I2C_WR; req.wlen = 3 + 2; req.rlen = 0; buf[0] = 2; // write len buf[1] = 0x02; /* I2C bus */ // NOK 3, 1, 0 buf[2] = 0x60 << 1; // I2C addr buf[3] = 0xfb; /* reg addr MSB */ buf[4] = 0xd9; /* reg addr LSB */ ret = af9035_ctrl_msg(d, &req); dev_dbg(&d->udev->dev, "1mxl5007t %02x\n", 0); req.cmd = CMD_GENERIC_I2C_RD; req.wlen = 3; req.rlen = 1; buf[0] = 1; // read len buf[1] = 0x02; /* I2C bus */ // NOK 3, 1, 0 buf[2] = 0x60 << 1; // I2C addr ret = af9035_ctrl_msg(d, &req); dev_dbg(&d->udev->dev, "1mxl5007t %02x\n", buf[0]); #endif #if 0 req.cmd = CMD_I2C_RD; req.wlen = 5; req.rlen = 1; buf[0] = 1; // read len buf[1] = 0x60 << 1; // I2C addr buf[2] = 2; /* reg addr len */ buf[3] = 0xfb; /* reg addr MSB */ buf[4] = 0xd9; /* reg addr LSB */ ret = af9035_ctrl_msg(d, &req); dev_dbg(&d->udev->dev, "4mxl5007t %02x\n", buf[0]); #endif #if 1 req.cmd = CMD_I2C_WR; req.wlen = 7; req.rlen = 0; buf[0] = 2; // write len msg[0].len; buf[1] = 0x60 << 1; // I2C addr buf[2] = 0x00; /* reg addr len */ buf[3] = 0x00; /* reg addr MSB */ buf[4] = 0x00; /* reg addr LSB */ buf[5] = 0xfb; buf[6] = 0xd9; ret = af9035_ctrl_msg(d, &req); dev_dbg(&d->udev->dev, "9mxl5007t %02x\n", buf[0]); req.cmd = CMD_I2C_RD; req.wlen = 5; req.rlen = 1; buf[0] = 1; // read len buf[1] = 0x60 << 1; // I2C addr buf[2] = 0x00; /* reg addr len */ buf[3] = 0x00; /* reg addr MSB */ buf[4] = 0x00; /* reg addr LSB */ ret = af9035_ctrl_msg(d, &req); dev_dbg(&d->udev->dev, "9mxl5007t %02x\n", buf[0]); #endif } On 04/09/2016 02:59 AM, Alessandro Radicati wrote: Jose, Antti, The no_probe option or similar is the only fix I could find (in fact i was going to propose a similar patch to what you have). I've tried all combinations of firmware and also tried issuing the read command to the tuner in different states (e.g. sleep, just after soft/hard reset) to no avail. I've modified AverMedia's linux driver to probe as well, and the same thing happens. I found the following behavior in further testing: - I can arbitrarily read as many bytes as I want from any valid register and the tuner will continue responding until the af9035 issues the expected NAK to signal the end of the read so that the mxl5007t can release the bus. The bus doesn't get released and it stays stuck either high or low indefinitely so subsequent I2C commands fail. - Hard reset of the tuner by cycling af9035 GPIOH12 seems like the only way to recover. So mxl5007t is probably at fault. Perhaps I2C speed is too fast (SCL cycles at ~100KHz)? Faulty hardware design of the usb stick? - Doesn't seem like the OEM drivers ever issue I2C read commands. Maybe it's a known issue to them. I'm pretty much out of ideas to test. Suggestions are welcome. Otherwise I'll try to push through a patch for just "no_probe". Thanks, Alessandro On Sat, Apr 9, 2016 at 1:13 AM, Jose Alberto Reguero wrote: I made a patch long time ago, but it was not accepted. https://patchwork.linuxtv.org/patch/16242/ Jose Alberto El 06/04/2016 01:00, Alessandro Radicati escribió: On Wed, Apr 6, 2016 at 12:33 AM, Antti Palosaari wrote: I found one stick having AF9035 + MXL5007T. It is HP branded A867, so it should be similar. It seems to work all three 12.13.15.0 6.20.15.0 firmwares: http://palosaari.fi/linux/v4l-dvb/firmware/af9035/ mxl5007t 5-0060: creating new instance mxl5007t_get_chip_id: unknown rev (3f) mxl5007t_get_chip_id: MxL5007T detected @ 5-0060 That is what AF9035 reports (with debug) as a chip version: dvb_usb_af9035: prechip_version=00 chip_version=03 chip_type=3802 Do you have different chip version? I have a Sky Italy DVB stick with the same chip version. I see that you get the 0x3f response as well... that should be fixed by the I2C patch I proposed. However, your stick seems to handle the read properly and process subsequent I2C commands - something that doesn't happen with mine. The vendor drivers in linux and windows never seem issue the USB I2C commands to read from the tuner. I'll test with other firmware versions to see if something changes. Regards, Alessandro -- To unsubscribe from this list: send the line "unsubscribe linux-media" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html -- http://palosaari.fi/ -- To unsubscribe from this list: send the line "unsubscribe linux-media" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
Re: AVerMedia HD Volar (A867) AF9035 + MXL5007T driver issues
Here is patches to test: http://git.linuxtv.org/anttip/media_tree.git/log/?h=af9035 After that both af9015+mxl5007t and af9035+mxl5007t started working. Earlier both were returning bogus values for chip id read. Also I am interested to known which kind of communication there is actually seen on I2C bus? If it starts working then have to find out way to fix it properly so that any earlier device didn't broke. regards Antti On 04/09/2016 03:50 AM, Antti Palosaari wrote: uh, how it could be so hard? I just made few tests and found 3 ways to read it. OK, one is that Alessandro already pointed out and I don't feel it correct. But those 2 are one for look. CMD_I2C_WR / CMD_I2C_RD with 1st priority, then CMD_GENERIC_I2C_WR / CMD_GENERIC_I2C_RD { u8 buf[MAX_XFER_SIZE]; struct usb_req req = {0, 0, 0, buf, 0, buf}; #if 0 req.cmd = CMD_GENERIC_I2C_WR; req.wlen = 3 + 2; req.rlen = 0; buf[0] = 2; // write len buf[1] = 0x02; /* I2C bus */ // NOK 3, 1, 0 buf[2] = 0x60 << 1; // I2C addr buf[3] = 0xfb; /* reg addr MSB */ buf[4] = 0xd9; /* reg addr LSB */ ret = af9035_ctrl_msg(d, &req); dev_dbg(&d->udev->dev, "1mxl5007t %02x\n", 0); req.cmd = CMD_GENERIC_I2C_RD; req.wlen = 3; req.rlen = 1; buf[0] = 1; // read len buf[1] = 0x02; /* I2C bus */ // NOK 3, 1, 0 buf[2] = 0x60 << 1; // I2C addr ret = af9035_ctrl_msg(d, &req); dev_dbg(&d->udev->dev, "1mxl5007t %02x\n", buf[0]); #endif #if 0 req.cmd = CMD_I2C_RD; req.wlen = 5; req.rlen = 1; buf[0] = 1; // read len buf[1] = 0x60 << 1; // I2C addr buf[2] = 2; /* reg addr len */ buf[3] = 0xfb; /* reg addr MSB */ buf[4] = 0xd9; /* reg addr LSB */ ret = af9035_ctrl_msg(d, &req); dev_dbg(&d->udev->dev, "4mxl5007t %02x\n", buf[0]); #endif #if 1 req.cmd = CMD_I2C_WR; req.wlen = 7; req.rlen = 0; buf[0] = 2; // write len msg[0].len; buf[1] = 0x60 << 1; // I2C addr buf[2] = 0x00; /* reg addr len */ buf[3] = 0x00; /* reg addr MSB */ buf[4] = 0x00; /* reg addr LSB */ buf[5] = 0xfb; buf[6] = 0xd9; ret = af9035_ctrl_msg(d, &req); dev_dbg(&d->udev->dev, "9mxl5007t %02x\n", buf[0]); req.cmd = CMD_I2C_RD; req.wlen = 5; req.rlen = 1; buf[0] = 1; // read len buf[1] = 0x60 << 1; // I2C addr buf[2] = 0x00; /* reg addr len */ buf[3] = 0x00; /* reg addr MSB */ buf[4] = 0x00; /* reg addr LSB */ ret = af9035_ctrl_msg(d, &req); dev_dbg(&d->udev->dev, "9mxl5007t %02x\n", buf[0]); #endif } On 04/09/2016 02:59 AM, Alessandro Radicati wrote: Jose, Antti, The no_probe option or similar is the only fix I could find (in fact i was going to propose a similar patch to what you have). I've tried all combinations of firmware and also tried issuing the read command to the tuner in different states (e.g. sleep, just after soft/hard reset) to no avail. I've modified AverMedia's linux driver to probe as well, and the same thing happens. I found the following behavior in further testing: - I can arbitrarily read as many bytes as I want from any valid register and the tuner will continue responding until the af9035 issues the expected NAK to signal the end of the read so that the mxl5007t can release the bus. The bus doesn't get released and it stays stuck either high or low indefinitely so subsequent I2C commands fail. - Hard reset of the tuner by cycling af9035 GPIOH12 seems like the only way to recover. So mxl5007t is probably at fault. Perhaps I2C speed is too fast (SCL cycles at ~100KHz)? Faulty hardware design of the usb stick? - Doesn't seem like the OEM drivers ever issue I2C read commands. Maybe it's a known issue to them. I'm pretty much out of ideas to test. Suggestions are welcome. Otherwise I'll try to push through a patch for just "no_probe". Thanks, Alessandro On Sat, Apr 9, 2016 at 1:13 AM, Jose Alberto Reguero wrote: I made a patch long time ago, but it was not accepted. https://patchwork.linuxtv.org/patch/16242/ Jose Alberto El 06/04/2016 01:00, Alessandro Radicati escribió: On Wed, Apr 6, 2016 at 12:33 AM, Antti Palosaari wrote: I found one stick having AF9035 + MXL5007T. It is HP branded A867, so it should be similar. It seems to work all three 12.13.15.0 6.20.15.0 firmwares: http://palosaari.fi/linux/v4l-dvb/firmware/af9035/ mxl5007t 5-0060: creating new instance mxl5007t_get_chip_id: unknown rev (3f) mxl5007t_get_chip_id: MxL5007T detected @ 5-0060 That is what AF9035 reports (with debug) as a chip version: dvb_usb_af9035: prechip_version=00 chip_version=03 chip_type=3802 Do you have different chip version? I have a Sky Italy DVB stick with the same chip version. I see that you get the 0x3f response as well... that should be fixed by the I2C patch I proposed. However, your stick seems to handle the read properly and process subsequent I2C commands - something that doesn't happen with mine. The vendor drivers in linux and windows nev
Re: AVerMedia HD Volar (A867) AF9035 + MXL5007T driver issues
On 04/09/2016 04:52 AM, Alessandro Radicati wrote: On Sat, Apr 9, 2016 at 3:22 AM, Antti Palosaari wrote: Here is patches to test: http://git.linuxtv.org/anttip/media_tree.git/log/?h=af9035 I've done this already in my testing, and it works for getting a correct chip_id response, but only because it's avoiding the issue with the write/read case in the af9035 driver. Don't have an af9015... perhaps there's a similar issue with that code or we are dealing with two separate issues since af9035 never does a repeated start? I am pretty sure mxl5007t requires stop between read and write. Usually chips are not caring too much if it is repeated start or not, whilst datasheets are often register read is S Wr S Rw P. Even af9035 i2c adapter implementation implements repeated start wrong, I would not like to add anymore hacks there. It is currently ugly and complex as hell. I should be re-written totally in any case. Those tuner I2C adapters should be moved to demod. Demod has 1 I2C adapter. USB-bridge has 2 adapters, one for each demod. I have to find out af9015 datasheets and check how it is there. But I still remember one case where I implemented one FX2 firmware and that same issues raises there as well. After that both af9015+mxl5007t and af9035+mxl5007t started working. Earlier both were returning bogus values for chip id read. Also I am interested to known which kind of communication there is actually seen on I2C bus? With this or the patch I proposed, you see exactly what you expect on the I2C bus with repeated stops, as detailed in my previous mails. So it is good? If it starts working then have to find out way to fix it properly so that any earlier device didn't broke. I hope that by now I've made abundantly clear that my mxl5007t locks up after *any* read. It doesn't matter if we are reading the correct register after any of the proposed patches. So it still locks up after any read after the chip id read? And does not work then? On my devices I can add multiple mxl5007t_get_chip_id() calls and all are returning correct values. Could you test what happens if you use that CMD_GENERIC_I2C_WR + CMD_GENERIC_I2C_RD ? I suspect it is lower level I2C xfer than those CMD_I2C_RD + CMD_I2C_WR, which are likely somehow handled by demod core. regards Antti -- http://palosaari.fi/ -- To unsubscribe from this list: send the line "unsubscribe linux-media" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
Re: AVerMedia HD Volar (A867) AF9035 + MXL5007T driver issues
On 04/09/2016 11:13 AM, Alessandro Radicati wrote: On Sat, Apr 9, 2016 at 4:17 AM, Antti Palosaari wrote: On 04/09/2016 04:52 AM, Alessandro Radicati wrote: On Sat, Apr 9, 2016 at 3:22 AM, Antti Palosaari wrote: Here is patches to test: http://git.linuxtv.org/anttip/media_tree.git/log/?h=af9035 I've done this already in my testing, and it works for getting a correct chip_id response, but only because it's avoiding the issue with the write/read case in the af9035 driver. Don't have an af9015... perhaps there's a similar issue with that code or we are dealing with two separate issues since af9035 never does a repeated start? I am pretty sure mxl5007t requires stop between read and write. Usually chips are not caring too much if it is repeated start or not, whilst datasheets are often register read is S Wr S Rw P. Even af9035 i2c adapter implementation implements repeated start wrong, I Where does the assumption that CMD_I2C_RD should issue a repeated start sequence come from? From the datasheet? Maybe it was never intended as repeated start. Perhaps if there is another stick with mxl5007t and a chip that does repeated start, we can put this to bed. Assumption was coming from it just does it as a single USB transaction. Datasheet says there is no repeated start. And kernel I2C API says all messages send using single i2c_transfer() should be send with repeated start, so now it is violating it, but that's not the biggest problem... would not like to add anymore hacks there. It is currently ugly and complex Bugfix != hack. Don't see how putting the register address in the address fields is a hack (perhaps semantics around the fact that 0xFB is not really part of the address?); this is the only and intended way to use that command for write/read. I did bunch of testing and find it is really wrong. Dumped out registers from some tuner chips and those seems to be mostly off by one. I think that skeleton is correct way (and it ends about same you did) if (msg[0].len == 0) // probe message, payload 0 buf[0] = msg[0].len; buf[1] = msg[0].addr << 1; buf[2] = 0x00; /* reg addr len */ buf[3] = 0x00; /* reg addr MSB */ buf[4] = 0x00; /* reg addr LSB */ else if (msg[0].len == 1) buf[0] = msg[0].len; buf[1] = msg[0].addr << 1; buf[2] = 1; /* reg addr len */ buf[3] = 0x00; /* reg addr MSB */ buf[4] = msg[0].buf[0]; /* reg addr LSB */ else if (msg[0].len == 2) buf[0] = msg[0].len; buf[1] = msg[0].addr << 1; buf[2] = 2; /* reg addr len */ buf[3] = msg[0].buf[0]; /* reg addr MSB */ buf[4] = msg[0].buf[1]; /* reg addr LSB */ else buf[0] = msg[0].len; buf[1] = msg[0].addr << 1; buf[2] = 2; /* reg addr len */ buf[3] = msg[0].buf[0]; /* reg addr MSB */ buf[4] = msg[0].buf[1]; /* reg addr LSB */ memcpy(&buf[5], msg[2].buf, msg[0].len - 2); as hell. I should be re-written totally in any case. Those tuner I2C adapters should be moved to demod. Demod has 1 I2C adapter. USB-bridge has 2 adapters, one for each demod. Agreed that it can be refactored and improved. Also to support n transactions with a simple while loop and only issuing single writes and reads. Only downside would be increased USB traffic for 2 commands vs 1 - hence negligible. there is i2c_adapter_quirks nowadays for these adapters which could do only limited set of commands. include/linux/i2c.h In my understanding that is how those chips are wired: +---+ ++ | I2C adapter-1 | --> | eeprom | +---+ ++ +---+ +-+ +-+ | I2C adapter-2 | --> | demod-1 | --> | tuner-1 | +---+ +-+ +-+ +---+ +-+ +-+ | I2C adapter-3 | --> | demod-2 | --> | tuner-2 | +---+ +-+ +-+ I have to find out af9015 datasheets and check how it is there. But I still remember one case where I implemented one FX2 firmware and that same issues raises there as well. After that both af9015+mxl5007t and af9035+mxl5007t started working. Earlier both were returning bogus values for chip id read. Also I am interested to known which kind of communication there is actually seen on I2C bus? With this or the patch I proposed, you see exactly what you expect on the I2C bus with repeated stops, as detailed in my previous mails. So it is good? Yes, I2C looks good. If it starts working then have to find out way to fix it properly so that any earlier device didn't broke. I hope that by now I've made abundantly clear that my mxl5007t locks up after *any* read. It doesn't matter if we are reading the correct register after any of the proposed patches. So it still locks up after any read after the chip id read? And does not work then? On my devices I can add multiple mxl5007t_get_chip_id() calls and all are returning correct values. No
Re: AVerMedia HD Volar (A867) AF9035 + MXL5007T driver issues
On 04/09/2016 07:11 PM, Alessandro Radicati wrote: On Sat, Apr 9, 2016 at 4:25 PM, Antti Palosaari wrote: On 04/09/2016 11:13 AM, Alessandro Radicati wrote: On Sat, Apr 9, 2016 at 4:17 AM, Antti Palosaari wrote: On 04/09/2016 04:52 AM, Alessandro Radicati wrote: On Sat, Apr 9, 2016 at 3:22 AM, Antti Palosaari wrote: Here is patches to test: http://git.linuxtv.org/anttip/media_tree.git/log/?h=af9035 I've done this already in my testing, and it works for getting a correct chip_id response, but only because it's avoiding the issue with the write/read case in the af9035 driver. Don't have an af9015... perhaps there's a similar issue with that code or we are dealing with two separate issues since af9035 never does a repeated start? I am pretty sure mxl5007t requires stop between read and write. Usually chips are not caring too much if it is repeated start or not, whilst datasheets are often register read is S Wr S Rw P. Even af9035 i2c adapter implementation implements repeated start wrong, I Where does the assumption that CMD_I2C_RD should issue a repeated start sequence come from? From the datasheet? Maybe it was never intended as repeated start. Perhaps if there is another stick with mxl5007t and a chip that does repeated start, we can put this to bed. Assumption was coming from it just does it as a single USB transaction. Datasheet says there is no repeated start. And kernel I2C API says all messages send using single i2c_transfer() should be send with repeated start, so now it is violating it, but that's not the biggest problem... Unfortunately there is no way around that problem, but at least it means that you can reduce the whole function to just read and write since at the I2C level nothing changes. would not like to add anymore hacks there. It is currently ugly and complex Bugfix != hack. Don't see how putting the register address in the address fields is a hack (perhaps semantics around the fact that 0xFB is not really part of the address?); this is the only and intended way to use that command for write/read. I did bunch of testing and find it is really wrong. Dumped out registers from some tuner chips and those seems to be mostly off by one. I think that skeleton is correct way (and it ends about same you did) if (msg[0].len == 0) // probe message, payload 0 buf[0] = msg[0].len; buf[1] = msg[0].addr << 1; buf[2] = 0x00; /* reg addr len */ buf[3] = 0x00; /* reg addr MSB */ buf[4] = 0x00; /* reg addr LSB */ else if (msg[0].len == 1) buf[0] = msg[0].len; buf[1] = msg[0].addr << 1; buf[2] = 1; /* reg addr len */ buf[3] = 0x00; /* reg addr MSB */ buf[4] = msg[0].buf[0]; /* reg addr LSB */ else if (msg[0].len == 2) buf[0] = msg[0].len; buf[1] = msg[0].addr << 1; buf[2] = 2; /* reg addr len */ buf[3] = msg[0].buf[0]; /* reg addr MSB */ buf[4] = msg[0].buf[1]; /* reg addr LSB */ else buf[0] = msg[0].len; buf[1] = msg[0].addr << 1; buf[2] = 2; /* reg addr len */ buf[3] = msg[0].buf[0]; /* reg addr MSB */ buf[4] = msg[0].buf[1]; /* reg addr LSB */ memcpy(&buf[5], msg[2].buf, msg[0].len - 2); Yes, this is the same, except I kept the original behavior when write len > 2. Hence with my patch the I2C bus would only see a read transaction. With the above, you would write the first two bytes and ignore the rest, then read. This may be worse than just doing a read because if a future tuner reg read setup/address is > 2 then you may get into a strange situation. If that case needs to be addressed, then might as well get rid of the single write/read usb transaction and just support write or read. Last else branch should do it - but no idea if it works at all and none of tuners are using it and it is very unlikely there will never be. It is easy to test, but I suspect if you write S Wr[11 11 12 13] P S Rw P it will return value from register 13 on a case chip supports writing multiple registers using reg address auto-increment as usually. as hell. I should be re-written totally in any case. Those tuner I2C adapters should be moved to demod. Demod has 1 I2C adapter. USB-bridge has 2 adapters, one for each demod. Agreed that it can be refactored and improved. Also to support n transactions with a simple while loop and only issuing single writes and reads. Only downside would be increased USB traffic for 2 commands vs 1 - hence negligible. there is i2c_adapter_quirks nowadays for these adapters which could do only limited set of commands. include/linux/i2c.h Perhaps just supporting write or read can be done with: struct i2c_adapter_quirks just_rw = { .flags=0, .max_num_msgs=1, .max_write_len=40, .max_read_len=40, }; Otherwise as is: struct i2c_adapter_quirks as_is = { .flags=I2C_AQ_COMB_WRITE_THEN_READ, .max_num_msgs=2, .max_write_len=40, .max_read_len=40, .max_comb_1st_msg_len=2, .max_comb_2nd_msg_len
[GIT PULL 4.6] m88ds3103 fix
That is actually bug fix for 3.19+, but according to my tests its effect is very minor, so no need for stable. It fixes demod carrier offset calculation. The following changes since commit da470473c9cf9c4ebb40d046b306c76427b6df94: [media] media: au0828 fix to clear enable/disable/change source handlers (2016-03-13 10:12:53 -0300) are available in the git repository at: git://linuxtv.org/anttip/media_tree.git m88ds3103_fix for you to fetch changes up to d717c129756c46321e277045706c70f602595ba1: m88ds3103: fix undefined division (2016-04-11 01:07:59 +0300) Peter Rosin (1): m88ds3103: fix undefined division drivers/media/dvb-frontends/m88ds3103_priv.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) -- http://palosaari.fi/ -- To unsubscribe from this list: send the line "unsubscribe linux-media" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
Fwd: [Bug 116551] media_gobj_create NULL pointer dereference
Can you look that bug as I think it is media controller related. regards Antti Forwarded Message Subject: [Bug 116551] media_gobj_create NULL pointer dereference Date: Sat, 16 Apr 2016 20:40:18 + From: bugzilla-dae...@bugzilla.kernel.org To: cr...@iki.fi https://bugzilla.kernel.org/show_bug.cgi?id=116551 Konstantin Nikiforov changed: What|Removed |Added CC||cr...@iki.fi -- You are receiving this mail because: You are on the CC list for the bug. -- To unsubscribe from this list: send the line "unsubscribe linux-media" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
Re: [PATCH] [media] af9035: fix for MXL5007T devices with I2C read issues
Hello I am not happy with that new module parameter as I cannot see real need for it. So get rid of it. Better to compare both VID and PID when enabling that work-around. Driver supports currently quite many different USB IDs and there is still small risk duplicate PID will exists at some point enabling work-around for wrong device. regards Antti On 04/15/2016 06:37 PM, Alessandro Radicati wrote: The MXL5007T tuner will lock-up on some devices after an I2C read transaction. This patch adds a kernel module parameter "no_read" to work around this issue by inhibiting such operations and emulating a 0x00 response. The workaround is applied automatically to USB product IDs known to exhibit this flaw, unless the kernel module parameter is specified. Signed-off-by: Alessandro Radicati --- drivers/media/usb/dvb-usb-v2/af9035.c | 27 +++ drivers/media/usb/dvb-usb-v2/af9035.h | 1 + 2 files changed, 28 insertions(+) diff --git a/drivers/media/usb/dvb-usb-v2/af9035.c b/drivers/media/usb/dvb-usb-v2/af9035.c index 2638e32..8225403 100644 --- a/drivers/media/usb/dvb-usb-v2/af9035.c +++ b/drivers/media/usb/dvb-usb-v2/af9035.c @@ -24,6 +24,10 @@ /* Max transfer size done by I2C transfer functions */ #define MAX_XFER_SIZE 64 +static int dvb_usb_af9035_no_read = -1; +module_param_named(no_read, dvb_usb_af9035_no_read, int, 0644); +MODULE_PARM_DESC(no_read, "Emulate I2C reads for devices that do not support them."); + DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr); static u16 af9035_checksum(const u8 *buf, size_t len) @@ -348,6 +352,9 @@ static int af9035_i2c_master_xfer(struct i2c_adapter *adap, ret = af9035_rd_regs(d, reg, &msg[1].buf[0], msg[1].len); + } else if (state->no_read) { + memset(msg[1].buf, 0, msg[1].len); + ret = 0; } else { /* I2C write + read */ u8 buf[MAX_XFER_SIZE]; @@ -421,6 +428,9 @@ static int af9035_i2c_master_xfer(struct i2c_adapter *adap, if (msg[0].len > 40) { /* TODO: correct limits > 40 */ ret = -EOPNOTSUPP; + } else if (state->no_read) { + memset(msg[0].buf, 0, msg[0].len); + ret = 0; } else { /* I2C read */ u8 buf[5]; @@ -962,6 +972,23 @@ skip_eeprom: state->af9033_config[i].clock = clock_lut_af9035[tmp]; } + /* Some MXL5007T devices cannot properly handle tuner I2C read ops. */ + if (dvb_usb_af9035_no_read != -1) { /* Override with module param */ + state->no_read = dvb_usb_af9035_no_read == 0 ? false : true; + } else { + switch (le16_to_cpu(d->udev->descriptor.idProduct)) { + case USB_PID_AVERMEDIA_A867: + case USB_PID_AVERMEDIA_TWINSTAR: + dev_info(&d->udev->dev, + "%s: Device may have issues with I2C read operations. Enabling fix.\n", + KBUILD_MODNAME); + state->no_read = true; + break; + default: + state->no_read = false; + } + } + return 0; err: diff --git a/drivers/media/usb/dvb-usb-v2/af9035.h b/drivers/media/usb/dvb-usb-v2/af9035.h index df22001..a76dafa 100644 --- a/drivers/media/usb/dvb-usb-v2/af9035.h +++ b/drivers/media/usb/dvb-usb-v2/af9035.h @@ -62,6 +62,7 @@ struct state { u8 chip_version; u16 chip_type; u8 dual_mode:1; + u8 no_read:1; u16 eeprom_addr; u8 af9033_i2c_addr[2]; struct af9033_config af9033_config[2]; -- http://palosaari.fi/ -- To unsubscribe from this list: send the line "unsubscribe linux-media" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
Re: [PATCH] [media] af9035: fix for MXL5007T devices with I2C read issues
On 04/20/2016 12:13 PM, Alex Rad wrote: On Wed, Apr 20, 2016 at 1:02 AM, Antti Palosaari wrote: Hello I am not happy with that new module parameter as I cannot see real need for it. So get rid of it. My reasoning for this is: 1) We know of just two devices which may have the issue, but there are probably more. The module parameter allows a user to apply the workaround to other devices we did not consider or test. Should we perhaps apply for all mxl5007t devices? So what. It is easier for me add just new IDs to driver when problematic device is found than adding new module parameter which allows user to work-around issues and I will likely newer even hear about those issues. 2) Not all devices that match VID and PID have the issue, so it allows the user to disable the workaround. Due to that better to add three checks 1) it is Avermedia VID 2) it is known problematic Avermedia device PID 3) it has tuner MxL5007t It is not surprise it is just only Avermedia which has this kind of problems. Not first time at all. I have added such Avermedia hacks for af9015 driver too and if you look af9035 there is tuner id hack - which was added also due to Avermedia. Worst case there could be is some mxl5007t device having reference design ID. But even on that case returning fake values is pretty much OK. regards Antti Better to compare both VID and PID when enabling that work-around. Driver supports currently quite many different USB IDs and there is still small risk duplicate PID will exists at some point enabling work-around for wrong device. OK. Will wait for comments on above before a v2. Thanks, Alessandro regards Antti On 04/15/2016 06:37 PM, Alessandro Radicati wrote: The MXL5007T tuner will lock-up on some devices after an I2C read transaction. This patch adds a kernel module parameter "no_read" to work around this issue by inhibiting such operations and emulating a 0x00 response. The workaround is applied automatically to USB product IDs known to exhibit this flaw, unless the kernel module parameter is specified. Signed-off-by: Alessandro Radicati --- drivers/media/usb/dvb-usb-v2/af9035.c | 27 +++ drivers/media/usb/dvb-usb-v2/af9035.h | 1 + 2 files changed, 28 insertions(+) diff --git a/drivers/media/usb/dvb-usb-v2/af9035.c b/drivers/media/usb/dvb-usb-v2/af9035.c index 2638e32..8225403 100644 --- a/drivers/media/usb/dvb-usb-v2/af9035.c +++ b/drivers/media/usb/dvb-usb-v2/af9035.c @@ -24,6 +24,10 @@ /* Max transfer size done by I2C transfer functions */ #define MAX_XFER_SIZE 64 +static int dvb_usb_af9035_no_read = -1; +module_param_named(no_read, dvb_usb_af9035_no_read, int, 0644); +MODULE_PARM_DESC(no_read, "Emulate I2C reads for devices that do not support them."); + DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr); static u16 af9035_checksum(const u8 *buf, size_t len) @@ -348,6 +352,9 @@ static int af9035_i2c_master_xfer(struct i2c_adapter *adap, ret = af9035_rd_regs(d, reg, &msg[1].buf[0], msg[1].len); + } else if (state->no_read) { + memset(msg[1].buf, 0, msg[1].len); + ret = 0; } else { /* I2C write + read */ u8 buf[MAX_XFER_SIZE]; @@ -421,6 +428,9 @@ static int af9035_i2c_master_xfer(struct i2c_adapter *adap, if (msg[0].len > 40) { /* TODO: correct limits > 40 */ ret = -EOPNOTSUPP; + } else if (state->no_read) { + memset(msg[0].buf, 0, msg[0].len); + ret = 0; } else { /* I2C read */ u8 buf[5]; @@ -962,6 +972,23 @@ skip_eeprom: state->af9033_config[i].clock = clock_lut_af9035[tmp]; } + /* Some MXL5007T devices cannot properly handle tuner I2C read ops. */ + if (dvb_usb_af9035_no_read != -1) { /* Override with module param */ + state->no_read = dvb_usb_af9035_no_read == 0 ? false : true; + } else { + switch (le16_to_cpu(d->udev->descriptor.idProduct)) { + case USB_PID_AVERMEDIA_A867: + case USB_PID_AVERMEDIA_TWINSTAR: + dev_info(&d->udev->dev, + "%s: Device may have issues with I2C read operations. Enabling fix.\n", + KBUILD_MODNAME); + state->no_read = true; + break; + default: + state->no_read = false; + } + } + return 0; err: diff --git a/drivers/media/usb/dvb-usb-v2/af9035.h b/drivers/media/usb/dvb-usb-v2/af9035.h index df22001..a76dafa 100644 --- a/drivers/media/us
Re: [PATCH v7 00/24] i2c mux cleanup and locking update
On 04/20/2016 06:17 PM, Peter Rosin wrote: Retested all the previously tested + now I tested also cx231xx with Hauppauge 930C HD device having eeprom other mux port and demod on the other port. [media] si2168: change the i2c gate to be mux-locked [media] m88ds3103: convert to use an explicit i2c mux core [media] rtl2830: convert to use an explicit i2c mux core [media] rtl2832: convert to use an explicit i2c mux core [media] si2168: convert to use an explicit i2c mux core [media] cx231xx: convert to use an explicit i2c mux core [media] rtl2832: change the i2c gate to be mux-locked [media] rtl2832_sdr: get rid of empty regmap wrappers [media] rtl2832: regmap is aware of lockdep, drop local locking hack I really hope that this whole patch series will arrive asap to mainline. regards Antti -- http://palosaari.fi/ -- To unsubscribe from this list: send the line "unsubscribe linux-media" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
[PATCH] af9035: correct eeprom offsets
Used memory mapped eeprom offsets were off-by 8 bytes. Signed-off-by: Antti Palosaari --- drivers/media/usb/dvb-usb-v2/af9035.h | 24 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/drivers/media/usb/dvb-usb-v2/af9035.h b/drivers/media/usb/dvb-usb-v2/af9035.h index df22001..89e629a 100644 --- a/drivers/media/usb/dvb-usb-v2/af9035.h +++ b/drivers/media/usb/dvb-usb-v2/af9035.h @@ -118,20 +118,20 @@ static const u32 clock_lut_it9135[] = { * Values 0, 3 and 5 are seen to this day. 0 for single TS and 3/5 for dual TS. */ -#define EEPROM_BASE_AF90350x42fd -#define EEPROM_BASE_IT91350x499c +#define EEPROM_BASE_AF90350x42f5 +#define EEPROM_BASE_IT91350x4994 #define EEPROM_SHIFT0x10 -#define EEPROM_IR_MODE 0x10 -#define EEPROM_TS_MODE 0x29 -#define EEPROM_2ND_DEMOD_ADDR 0x2a -#define EEPROM_IR_TYPE 0x2c -#define EEPROM_1_IF_L 0x30 -#define EEPROM_1_IF_H 0x31 -#define EEPROM_1_TUNER_ID 0x34 -#define EEPROM_2_IF_L 0x40 -#define EEPROM_2_IF_H 0x41 -#define EEPROM_2_TUNER_ID 0x44 +#define EEPROM_IR_MODE 0x18 +#define EEPROM_TS_MODE 0x31 +#define EEPROM_2ND_DEMOD_ADDR 0x32 +#define EEPROM_IR_TYPE 0x34 +#define EEPROM_1_IF_L 0x38 +#define EEPROM_1_IF_H 0x39 +#define EEPROM_1_TUNER_ID 0x3c +#define EEPROM_2_IF_L 0x48 +#define EEPROM_2_IF_H 0x49 +#define EEPROM_2_TUNER_ID 0x4c /* USB commands */ #define CMD_MEM_RD 0x00 -- http://palosaari.fi/ -- To unsubscribe from this list: send the line "unsubscribe linux-media" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
Re: [media-af9013] question about return value in function af9013_wr_regs()
Gustavo A. R. Silva kirjoitti 2017-06-09 00:51: Hello everybody, While looking into Coverity ID 1227035 I ran into the following piece of code at drivers/media/dvb-frontends/af9013.c:595: The issue here is that the value stored in variable _ret_ at line 608, is not being evaluated as it happens at line 662, 667, 672 and 677. Then after looking into function af9013_wr_regs(), I noticed that this function always returns zero, no matter what, as you can see below: 121static int af9013_wr_regs(struct af9013_state *priv, u16 reg, const u8 *val, 122int len) 123{ 124int ret, i; 125u8 mbox = (0 << 7)|(0 << 6)|(1 << 1)|(1 << 0); 126 127if ((priv->config.ts_mode == AF9013_TS_USB) && 128((reg & 0xff00) != 0xff00) && ((reg & 0xff00) != 0xae00)) { 129mbox |= ((len - 1) << 2); 130ret = af9013_wr_regs_i2c(priv, mbox, reg, val, len); 131} else { 132for (i = 0; i < len; i++) { 133ret = af9013_wr_regs_i2c(priv, mbox, reg+i, val+i, 1); 134if (ret) 135goto err; 136} 137} 138 139err: 140return 0; 141} That function should return error code on error case, not zero always. regards Antti -- http://palosaari.fi/
Re: [PATCH] dvb-usb-af9035: load HID table
Hello Jaroslav Škarvada kirjoitti 2017-06-09 20:46: Automatically load sniffed HID table from Windows driver if USB_VID_ITETECH:USB_PID_ITETECH_IT9135_9006 device is present (e.g. Evolveo Mars) or if module parameter force_hid_tab_load is set. There is few issues I don't like this approach. Mostly that module parameter to select HID table. There is existing solution to select remote controller, it is ir-keytable and it should be used rather than defining device specific module parameter. If you look that HID table you could see there is 4 bytes NEC code and 3 bytes HID code. Remote controller seems to have 34 keys. Remote controller address bytes are 0x02bd, grepping existing remote controller keytables it could be Total Media In Hand remote controller (rc-total-media-in-hand.c). If not, then defining new keytable is needed. I did some research about issue and found 2 better solutions. 1) Configure HID table dynamically. Remote controller keytable has some needed information, but those KEY_* events needed to be translated to HID codes somehow. 2) Kill HID and then use CMD_IR_GET to get remote controller scancodes by polling. Solution 1 sounds most correct. No need to poll and decode by sw as hw does all the job. But it is most hardest to implement, I am not aware if anyone has done it yet. regards Antti -- http://palosaari.fi/
[PATCH 04/15] af9033: use kernel 64-bit division
Replace own binary division with 64-bit multiply and division. Signed-off-by: Antti Palosaari --- drivers/media/dvb-frontends/af9013.c | 34 +++ drivers/media/dvb-frontends/af9013_priv.h | 1 + 2 files changed, 4 insertions(+), 31 deletions(-) diff --git a/drivers/media/dvb-frontends/af9013.c b/drivers/media/dvb-frontends/af9013.c index f644182..dd7ac0a 100644 --- a/drivers/media/dvb-frontends/af9013.c +++ b/drivers/media/dvb-frontends/af9013.c @@ -277,33 +277,6 @@ static int af9013_set_gpio(struct af9013_state *state, u8 gpio, u8 gpioval) return ret; } -static u32 af9013_div(struct af9013_state *state, u32 a, u32 b, u32 x) -{ - u32 r = 0, c = 0, i; - - dev_dbg(&state->client->dev, "%s: a=%d b=%d x=%d\n", __func__, a, b, x); - - if (a > b) { - c = a / b; - a = a - c * b; - } - - for (i = 0; i < x; i++) { - if (a >= b) { - r += 1; - a -= b; - } - a <<= 1; - r <<= 1; - } - r = (c << (u32)x) + r; - - dev_dbg(&state->client->dev, "%s: a=%d b=%d x=%d r=%d r=%x\n", - __func__, a, b, x, r, r); - - return r; -} - static int af9013_power_ctrl(struct af9013_state *state, u8 onoff) { int ret, i; @@ -638,8 +611,8 @@ static int af9013_set_frontend(struct dvb_frontend *fe) spec_inv = !state->spec_inv; } - freq_cw = af9013_div(state, sampling_freq, state->clk, - 23); + freq_cw = DIV_ROUND_CLOSEST_ULL((u64)sampling_freq * 0x80, + state->clk); if (spec_inv) freq_cw = 0x80 - freq_cw; @@ -1108,11 +1081,10 @@ static int af9013_init(struct dvb_frontend *fe) return -EINVAL; } - adc_cw = af9013_div(state, state->clk, 100ul, 19); + adc_cw = div_u64((u64)state->clk * 0x8, 100); buf[0] = (adc_cw >> 0) & 0xff; buf[1] = (adc_cw >> 8) & 0xff; buf[2] = (adc_cw >> 16) & 0xff; - ret = af9013_wr_regs(state, 0xd180, buf, 3); if (ret) goto err; diff --git a/drivers/media/dvb-frontends/af9013_priv.h b/drivers/media/dvb-frontends/af9013_priv.h index 31d6538..97b5b0c 100644 --- a/drivers/media/dvb-frontends/af9013_priv.h +++ b/drivers/media/dvb-frontends/af9013_priv.h @@ -24,6 +24,7 @@ #include "dvb_frontend.h" #include "af9013.h" #include +#include #define AF9013_FIRMWARE "dvb-fe-af9013.fw" -- http://palosaari.fi/
[PATCH 06/15] af9013: convert to regmap api
Use regmap for register access. Own low level i2c read and write routines for regmap is still needed because chip uses single command byte in addition to typical i2c register access. Signed-off-by: Antti Palosaari --- drivers/media/dvb-frontends/Kconfig | 1 + drivers/media/dvb-frontends/af9013.c | 598 +++--- drivers/media/dvb-frontends/af9013_priv.h | 1 + 3 files changed, 294 insertions(+), 306 deletions(-) diff --git a/drivers/media/dvb-frontends/Kconfig b/drivers/media/dvb-frontends/Kconfig index e8c6554..3a260b8 100644 --- a/drivers/media/dvb-frontends/Kconfig +++ b/drivers/media/dvb-frontends/Kconfig @@ -436,6 +436,7 @@ config DVB_TDA10048 config DVB_AF9013 tristate "Afatech AF9013 demodulator" depends on DVB_CORE && I2C + select REGMAP default m if !MEDIA_SUBDRV_AUTOSELECT help Say Y when you want to support this frontend. diff --git a/drivers/media/dvb-frontends/af9013.c b/drivers/media/dvb-frontends/af9013.c index 781e958..70102c1 100644 --- a/drivers/media/dvb-frontends/af9013.c +++ b/drivers/media/dvb-frontends/af9013.c @@ -20,11 +20,9 @@ #include "af9013_priv.h" -/* Max transfer size done by I2C transfer functions */ -#define MAX_XFER_SIZE 64 - struct af9013_state { struct i2c_client *client; + struct regmap *regmap; struct dvb_frontend fe; u32 clk; u8 tuner; @@ -50,181 +48,6 @@ struct af9013_state { struct delayed_work statistics_work; }; -/* write multiple registers */ -static int af9013_wr_regs_i2c(struct af9013_state *state, u8 mbox, u16 reg, - const u8 *val, int len) -{ - struct i2c_client *client = state->client; - int ret; - u8 buf[MAX_XFER_SIZE]; - struct i2c_msg msg[1] = { - { - .addr = state->client->addr, - .flags = 0, - .len = 3 + len, - .buf = buf, - } - }; - - if (3 + len > sizeof(buf)) { - dev_warn(&client->dev, "i2c wr reg %04x, len %d, is too big!\n", -reg, len); - return -EINVAL; - } - - buf[0] = (reg >> 8) & 0xff; - buf[1] = (reg >> 0) & 0xff; - buf[2] = mbox; - memcpy(&buf[3], val, len); - - ret = i2c_transfer(state->client->adapter, msg, 1); - if (ret == 1) { - ret = 0; - } else { - dev_warn(&client->dev, "i2c wr failed %d, reg %04x, len %d\n", -ret, reg, len); - ret = -EREMOTEIO; - } - return ret; -} - -/* read multiple registers */ -static int af9013_rd_regs_i2c(struct af9013_state *state, u8 mbox, u16 reg, - u8 *val, int len) -{ - struct i2c_client *client = state->client; - int ret; - u8 buf[3]; - struct i2c_msg msg[2] = { - { - .addr = state->client->addr, - .flags = 0, - .len = 3, - .buf = buf, - }, { - .addr = state->client->addr, - .flags = I2C_M_RD, - .len = len, - .buf = val, - } - }; - - buf[0] = (reg >> 8) & 0xff; - buf[1] = (reg >> 0) & 0xff; - buf[2] = mbox; - - ret = i2c_transfer(state->client->adapter, msg, 2); - if (ret == 2) { - ret = 0; - } else { - dev_warn(&client->dev, "i2c rd failed %d, reg %04x, len %d\n", -ret, reg, len); - ret = -EREMOTEIO; - } - return ret; -} - -/* write multiple registers */ -static int af9013_wr_regs(struct af9013_state *state, u16 reg, const u8 *val, - int len) -{ - int ret, i; - u8 mbox = (0 << 7)|(0 << 6)|(1 << 1)|(1 << 0); - - if ((state->ts_mode == AF9013_TS_USB) && - ((reg & 0xff00) != 0xff00) && ((reg & 0xff00) != 0xae00)) { - mbox |= ((len - 1) << 2); - ret = af9013_wr_regs_i2c(state, mbox, reg, val, len); - } else { - for (i = 0; i < len; i++) { - ret = af9013_wr_regs_i2c(state, mbox, reg+i, val+i, 1); - if (ret) - goto err; - } - } - -err: - return 0; -} - -/* read multiple registers */ -static int af9013_rd_regs(struct af9013_state *state, u16 reg, u8 *val, int len) -{ - int ret, i; - u8 mbox = (0 << 7)|(0 << 6)|(1 << 1)|(0 << 0); - - if ((state->ts_mode == AF9013_TS_USB) && - ((reg & 0xff00) != 0xff00)
[PATCH 12/15] af9013: remove unneeded register writes
Removed register writes are already chip defaults, are not required, are set later or belong to AF9015 USB interface. Signed-off-by: Antti Palosaari --- drivers/media/dvb-frontends/af9013.c | 42 1 file changed, 42 deletions(-) diff --git a/drivers/media/dvb-frontends/af9013.c b/drivers/media/dvb-frontends/af9013.c index 6b86437..63c532a 100644 --- a/drivers/media/dvb-frontends/af9013.c +++ b/drivers/media/dvb-frontends/af9013.c @@ -894,11 +894,6 @@ static int af9013_init(struct dvb_frontend *fe) if (ret) goto err; - /* enable ADC */ - ret = regmap_write(state->regmap, 0xd73a, 0xa4); - if (ret) - goto err; - /* write API version to firmware */ ret = regmap_bulk_write(state->regmap, 0x9bf2, state->api_version, 4); if (ret) @@ -935,43 +930,6 @@ static int af9013_init(struct dvb_frontend *fe) if (ret) goto err; - /* set I2C master clock */ - ret = regmap_write(state->regmap, 0xd416, 0x14); - if (ret) - goto err; - - /* set 16 embx */ - ret = regmap_update_bits(state->regmap, 0xd700, 0x02, 0x02); - if (ret) - goto err; - - /* set no trigger */ - ret = regmap_update_bits(state->regmap, 0xd700, 0x04, 0x00); - if (ret) - goto err; - - /* set read-update bit for constellation */ - ret = regmap_update_bits(state->regmap, 0xd371, 0x02, 0x02); - if (ret) - goto err; - - /* settings for mp2if */ - if (state->ts_mode == AF9013_TS_MODE_USB) { - /* AF9015 split PSB to 1.5k + 0.5k */ - ret = regmap_update_bits(state->regmap, 0xd50b, 0x04, 0x04); - if (ret) - goto err; - } else { - /* AF9013 set mpeg to full speed */ - ret = regmap_update_bits(state->regmap, 0xd502, 0x10, 0x10); - if (ret) - goto err; - } - - ret = regmap_update_bits(state->regmap, 0xd520, 0x10, 0x10); - if (ret) - goto err; - /* load OFSM settings */ dev_dbg(&client->dev, "load ofsm settings\n"); len = ARRAY_SIZE(ofsm_init); -- http://palosaari.fi/
[PATCH 09/15] af9015: fix and refactor i2c adapter algo logic
* fix write+read when write has more than one byte * remove lock, not needed on that case * remove useless i2c msg send loop, as we support only write, read and write+read as one go and nothing more Signed-off-by: Antti Palosaari --- drivers/media/usb/dvb-usb-v2/af9015.c | 153 ++ 1 file changed, 79 insertions(+), 74 deletions(-) diff --git a/drivers/media/usb/dvb-usb-v2/af9015.c b/drivers/media/usb/dvb-usb-v2/af9015.c index 138416c..54c1d47 100644 --- a/drivers/media/usb/dvb-usb-v2/af9015.c +++ b/drivers/media/usb/dvb-usb-v2/af9015.c @@ -205,9 +205,9 @@ static int af9015_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msg[], { struct dvb_usb_device *d = i2c_get_adapdata(adap); struct af9015_state *state = d_to_priv(d); - int ret = 0, i = 0; + int ret; u16 addr; - u8 uninitialized_var(mbox), addr_len; + u8 mbox, addr_len; struct req_t req; /* @@ -232,84 +232,89 @@ Due to that the only way to select correct tuner is use demodulator I2C-gate. | addr 0x3a | | addr 0xc6 | || || */ - if (mutex_lock_interruptible(&d->i2c_mutex) < 0) - return -EAGAIN; - while (i < num) { - if (msg[i].addr == state->af9013_config[0].i2c_addr || - msg[i].addr == state->af9013_config[1].i2c_addr) { - addr = msg[i].buf[0] << 8; - addr += msg[i].buf[1]; - mbox = msg[i].buf[2]; - addr_len = 3; - } else { - addr = msg[i].buf[0]; - addr_len = 1; - /* mbox is don't care in that case */ - } + if (msg[0].len == 0 || msg[0].flags & I2C_M_RD) { + addr = 0x; + mbox = 0; + addr_len = 0; + } else if (msg[0].len == 1) { + addr = msg[0].buf[0]; + mbox = 0; + addr_len = 1; + } else if (msg[0].len == 2) { + addr = msg[0].buf[0] << 8|msg[0].buf[1] << 0; + mbox = 0; + addr_len = 2; + } else { + addr = msg[0].buf[0] << 8|msg[0].buf[1] << 0; + mbox = msg[0].buf[2]; + addr_len = 3; + } - if (num > i + 1 && (msg[i+1].flags & I2C_M_RD)) { - if (msg[i].len > 3 || msg[i+1].len > 61) { - ret = -EOPNOTSUPP; - goto error; - } - if (msg[i].addr == state->af9013_config[0].i2c_addr) - req.cmd = READ_MEMORY; - else - req.cmd = READ_I2C; - req.i2c_addr = msg[i].addr; - req.addr = addr; - req.mbox = mbox; - req.addr_len = addr_len; - req.data_len = msg[i+1].len; - req.data = &msg[i+1].buf[0]; - ret = af9015_ctrl_msg(d, &req); - i += 2; - } else if (msg[i].flags & I2C_M_RD) { - if (msg[i].len > 61) { - ret = -EOPNOTSUPP; - goto error; - } - if (msg[i].addr == state->af9013_config[0].i2c_addr) { - ret = -EINVAL; - goto error; - } + if (num == 1 && !(msg[0].flags & I2C_M_RD)) { + /* i2c write */ + if (msg[0].len > 21) { + ret = -EOPNOTSUPP; + goto err; + } + if (msg[0].addr == state->af9013_config[0].i2c_addr) + req.cmd = WRITE_MEMORY; + else + req.cmd = WRITE_I2C; + req.i2c_addr = msg[0].addr; + req.addr = addr; + req.mbox = mbox; + req.addr_len = addr_len; + req.data_len = msg[0].len-addr_len; + req.data = &msg[0].buf[addr_len]; + ret = af9015_ctrl_msg(d, &req); + } else if (num == 2 && !(msg[0].flags & I2C_M_RD) && + (msg[1].flags & I2C_M_RD)) { + /* i2c write + read */ + if (msg[0].len > 3 || msg[1].len > 61) { + ret = -EOPNOTSUPP; + goto err; + } + if (msg[0].addr == state->af9013_config[0].i2c_addr) + req.cmd = READ_MEMOR
[PATCH 08/15] af9013: add dvbv5 cnr
Add support for DVBv5 CNR. Signed-off-by: Antti Palosaari --- drivers/media/dvb-frontends/af9013.c | 9 + 1 file changed, 9 insertions(+) diff --git a/drivers/media/dvb-frontends/af9013.c b/drivers/media/dvb-frontends/af9013.c index a6b88ae..68091f2 100644 --- a/drivers/media/dvb-frontends/af9013.c +++ b/drivers/media/dvb-frontends/af9013.c @@ -228,6 +228,7 @@ static int af9013_statistics_snr_result(struct dvb_frontend *fe) { struct af9013_state *state = fe->demodulator_priv; struct i2c_client *client = state->client; + struct dtv_frontend_properties *c = &fe->dtv_property_cache; int ret, i, len; unsigned int utmp; u8 buf[3]; @@ -283,6 +284,9 @@ static int af9013_statistics_snr_result(struct dvb_frontend *fe) } state->snr = utmp * 10; /* dB/10 */ + c->cnr.stat[0].svalue = 1000 * utmp; + c->cnr.stat[0].scale = FE_SCALE_DECIBEL; + return 0; err: dev_dbg(&client->dev, "failed %d\n", ret); @@ -1508,6 +1512,7 @@ static int af9013_probe(struct i2c_client *client, { struct af9013_state *state; struct af9013_platform_data *pdata = client->dev.platform_data; + struct dtv_frontend_properties *c; int ret, i; u8 firmware_version[4]; static const struct regmap_bus regmap_bus = { @@ -1572,6 +1577,10 @@ static int af9013_probe(struct i2c_client *client, /* Setup callbacks */ pdata->get_dvb_frontend = af9013_get_dvb_frontend; + /* Init stats to indicate which stats are supported */ + c = &state->fe.dtv_property_cache; + c->cnr.len = 1; + dev_info(&client->dev, "Afatech AF9013 successfully attached\n"); dev_info(&client->dev, "firmware version: %d.%d.%d.%d\n", firmware_version[0], firmware_version[1], -- http://palosaari.fi/
[PATCH 05/15] af9013: fix logging
We can simplify logging as we now have a proper i2c client to pass for kernel dev_* logging functions. Signed-off-by: Antti Palosaari --- drivers/media/dvb-frontends/af9013.c | 202 +-- 1 file changed, 100 insertions(+), 102 deletions(-) diff --git a/drivers/media/dvb-frontends/af9013.c b/drivers/media/dvb-frontends/af9013.c index dd7ac0a..781e958 100644 --- a/drivers/media/dvb-frontends/af9013.c +++ b/drivers/media/dvb-frontends/af9013.c @@ -51,14 +51,15 @@ struct af9013_state { }; /* write multiple registers */ -static int af9013_wr_regs_i2c(struct af9013_state *priv, u8 mbox, u16 reg, +static int af9013_wr_regs_i2c(struct af9013_state *state, u8 mbox, u16 reg, const u8 *val, int len) { + struct i2c_client *client = state->client; int ret; u8 buf[MAX_XFER_SIZE]; struct i2c_msg msg[1] = { { - .addr = priv->client->addr, + .addr = state->client->addr, .flags = 0, .len = 3 + len, .buf = buf, @@ -66,9 +67,8 @@ static int af9013_wr_regs_i2c(struct af9013_state *priv, u8 mbox, u16 reg, }; if (3 + len > sizeof(buf)) { - dev_warn(&priv->client->dev, -"%s: i2c wr reg=%04x: len=%d is too big!\n", -KBUILD_MODNAME, reg, len); + dev_warn(&client->dev, "i2c wr reg %04x, len %d, is too big!\n", +reg, len); return -EINVAL; } @@ -77,31 +77,32 @@ static int af9013_wr_regs_i2c(struct af9013_state *priv, u8 mbox, u16 reg, buf[2] = mbox; memcpy(&buf[3], val, len); - ret = i2c_transfer(priv->client->adapter, msg, 1); + ret = i2c_transfer(state->client->adapter, msg, 1); if (ret == 1) { ret = 0; } else { - dev_warn(&priv->client->dev, "%s: i2c wr failed=%d reg=%04x " \ - "len=%d\n", KBUILD_MODNAME, ret, reg, len); + dev_warn(&client->dev, "i2c wr failed %d, reg %04x, len %d\n", +ret, reg, len); ret = -EREMOTEIO; } return ret; } /* read multiple registers */ -static int af9013_rd_regs_i2c(struct af9013_state *priv, u8 mbox, u16 reg, +static int af9013_rd_regs_i2c(struct af9013_state *state, u8 mbox, u16 reg, u8 *val, int len) { + struct i2c_client *client = state->client; int ret; u8 buf[3]; struct i2c_msg msg[2] = { { - .addr = priv->client->addr, + .addr = state->client->addr, .flags = 0, .len = 3, .buf = buf, }, { - .addr = priv->client->addr, + .addr = state->client->addr, .flags = I2C_M_RD, .len = len, .buf = val, @@ -112,31 +113,31 @@ static int af9013_rd_regs_i2c(struct af9013_state *priv, u8 mbox, u16 reg, buf[1] = (reg >> 0) & 0xff; buf[2] = mbox; - ret = i2c_transfer(priv->client->adapter, msg, 2); + ret = i2c_transfer(state->client->adapter, msg, 2); if (ret == 2) { ret = 0; } else { - dev_warn(&priv->client->dev, "%s: i2c rd failed=%d reg=%04x " \ - "len=%d\n", KBUILD_MODNAME, ret, reg, len); + dev_warn(&client->dev, "i2c rd failed %d, reg %04x, len %d\n", +ret, reg, len); ret = -EREMOTEIO; } return ret; } /* write multiple registers */ -static int af9013_wr_regs(struct af9013_state *priv, u16 reg, const u8 *val, +static int af9013_wr_regs(struct af9013_state *state, u16 reg, const u8 *val, int len) { int ret, i; u8 mbox = (0 << 7)|(0 << 6)|(1 << 1)|(1 << 0); - if ((priv->ts_mode == AF9013_TS_USB) && + if ((state->ts_mode == AF9013_TS_USB) && ((reg & 0xff00) != 0xff00) && ((reg & 0xff00) != 0xae00)) { mbox |= ((len - 1) << 2); - ret = af9013_wr_regs_i2c(priv, mbox, reg, val, len); + ret = af9013_wr_regs_i2c(state, mbox, reg, val, len); } else { for (i = 0; i < len; i++) { - ret = af9013_wr_regs_i2c(priv, mbox, reg+i, val+i, 1); + ret = af9013_wr_regs_i2c(state, mbox, reg+i, val+i, 1); if (ret) goto err;
[PATCH 15/15] af9013: refactor power control
Move power-up and power-down functionality to init/sleep ops and get rid of old function. Fixes and simplifies power-up functionality slightly. Signed-off-by: Antti Palosaari --- drivers/media/dvb-frontends/af9013.c | 93 ++-- 1 file changed, 36 insertions(+), 57 deletions(-) diff --git a/drivers/media/dvb-frontends/af9013.c b/drivers/media/dvb-frontends/af9013.c index 40fd2ea..128d915 100644 --- a/drivers/media/dvb-frontends/af9013.c +++ b/drivers/media/dvb-frontends/af9013.c @@ -101,59 +101,6 @@ static int af9013_set_gpio(struct af9013_state *state, u8 gpio, u8 gpioval) return ret; } -static int af9013_power_ctrl(struct af9013_state *state, u8 onoff) -{ - struct i2c_client *client = state->client; - int ret; - unsigned int utmp; - - dev_dbg(&client->dev, "onoff %d\n", onoff); - - /* enable reset */ - ret = regmap_update_bits(state->regmap, 0xd417, 0x10, 0x10); - if (ret) - goto err; - - /* start reset mechanism */ - ret = regmap_write(state->regmap, 0xaeff, 0x01); - if (ret) - goto err; - - /* wait reset performs */ - ret = regmap_read_poll_timeout(state->regmap, 0xd417, utmp, - (utmp >> 1) & 0x01, 5000, 100); - if (ret) - goto err; - - if (!((utmp >> 1) & 0x01)) - return -ETIMEDOUT; - - if (onoff) { - /* clear reset */ - ret = regmap_update_bits(state->regmap, 0xd417, 0x02, 0x00); - if (ret) - goto err; - /* disable reset */ - ret = regmap_update_bits(state->regmap, 0xd417, 0x10, 0x00); - if (ret) - goto err; - /* power on */ - ret = regmap_update_bits(state->regmap, 0xd73a, 0x08, 0x00); - if (ret) - goto err; - } else { - /* power off */ - ret = regmap_update_bits(state->regmap, 0xd73a, 0x08, 0x08); - if (ret) - goto err; - } - - return 0; -err: - dev_dbg(&client->dev, "failed %d\n", ret); - return ret; -} - static int af9013_statistics_ber_unc_start(struct dvb_frontend *fe) { struct af9013_state *state = fe->demodulator_priv; @@ -889,8 +836,18 @@ static int af9013_init(struct dvb_frontend *fe) dev_dbg(&client->dev, "\n"); - /* power on */ - ret = af9013_power_ctrl(state, 1); + /* ADC on */ + ret = regmap_update_bits(state->regmap, 0xd73a, 0x08, 0x00); + if (ret) + goto err; + + /* Clear reset */ + ret = regmap_update_bits(state->regmap, 0xd417, 0x02, 0x00); + if (ret) + goto err; + + /* Disable reset */ + ret = regmap_update_bits(state->regmap, 0xd417, 0x10, 0x00); if (ret) goto err; @@ -1070,6 +1027,7 @@ static int af9013_sleep(struct dvb_frontend *fe) struct af9013_state *state = fe->demodulator_priv; struct i2c_client *client = state->client; int ret; + unsigned int utmp; dev_dbg(&client->dev, "\n"); @@ -1081,8 +1039,29 @@ static int af9013_sleep(struct dvb_frontend *fe) if (ret) goto err; - /* power off */ - ret = af9013_power_ctrl(state, 0); + /* Enable reset */ + ret = regmap_update_bits(state->regmap, 0xd417, 0x10, 0x10); + if (ret) + goto err; + + /* Start reset execution */ + ret = regmap_write(state->regmap, 0xaeff, 0x01); + if (ret) + goto err; + + /* Wait reset performs */ + ret = regmap_read_poll_timeout(state->regmap, 0xd417, utmp, + (utmp >> 1) & 0x01, 5000, 100); + if (ret) + goto err; + + if (!((utmp >> 1) & 0x01)) { + ret = -ETIMEDOUT; + goto err; + } + + /* ADC off */ + ret = regmap_update_bits(state->regmap, 0xd73a, 0x08, 0x08); if (ret) goto err; -- http://palosaari.fi/
[PATCH 02/15] af9013: move config values directly under driver state
It shorten, as typed chars, access to config values as there is one pointer less. Also, when config/platform data is passed to driver there could be some values that are not relevant to store state as such or not needed to store at all. Signed-off-by: Antti Palosaari --- drivers/media/dvb-frontends/af9013.c | 62 ++-- 1 file changed, 38 insertions(+), 24 deletions(-) diff --git a/drivers/media/dvb-frontends/af9013.c b/drivers/media/dvb-frontends/af9013.c index b978002..7880a63 100644 --- a/drivers/media/dvb-frontends/af9013.c +++ b/drivers/media/dvb-frontends/af9013.c @@ -26,7 +26,14 @@ struct af9013_state { struct i2c_adapter *i2c; struct dvb_frontend fe; - struct af9013_config config; + u8 i2c_addr; + u32 clk; + u8 tuner; + u32 if_frequency; + u8 ts_mode; + bool spec_inv; + u8 api_version[4]; + u8 gpio[4]; /* tuner/demod RF and IF AGC limits used for signal strength calc */ u8 signal_strength_en, rf_50, rf_80, if_50, if_80; @@ -52,7 +59,7 @@ static int af9013_wr_regs_i2c(struct af9013_state *priv, u8 mbox, u16 reg, u8 buf[MAX_XFER_SIZE]; struct i2c_msg msg[1] = { { - .addr = priv->config.i2c_addr, + .addr = priv->i2c_addr, .flags = 0, .len = 3 + len, .buf = buf, @@ -90,12 +97,12 @@ static int af9013_rd_regs_i2c(struct af9013_state *priv, u8 mbox, u16 reg, u8 buf[3]; struct i2c_msg msg[2] = { { - .addr = priv->config.i2c_addr, + .addr = priv->i2c_addr, .flags = 0, .len = 3, .buf = buf, }, { - .addr = priv->config.i2c_addr, + .addr = priv->i2c_addr, .flags = I2C_M_RD, .len = len, .buf = val, @@ -124,7 +131,7 @@ static int af9013_wr_regs(struct af9013_state *priv, u16 reg, const u8 *val, int ret, i; u8 mbox = (0 << 7)|(0 << 6)|(1 << 1)|(1 << 0); - if ((priv->config.ts_mode == AF9013_TS_USB) && + if ((priv->ts_mode == AF9013_TS_USB) && ((reg & 0xff00) != 0xff00) && ((reg & 0xff00) != 0xae00)) { mbox |= ((len - 1) << 2); ret = af9013_wr_regs_i2c(priv, mbox, reg, val, len); @@ -146,7 +153,7 @@ static int af9013_rd_regs(struct af9013_state *priv, u16 reg, u8 *val, int len) int ret, i; u8 mbox = (0 << 7)|(0 << 6)|(1 << 1)|(0 << 0); - if ((priv->config.ts_mode == AF9013_TS_USB) && + if ((priv->ts_mode == AF9013_TS_USB) && ((reg & 0xff00) != 0xff00) && ((reg & 0xff00) != 0xae00)) { mbox |= ((len - 1) << 2); ret = af9013_rd_regs_i2c(priv, mbox, reg, val, len); @@ -595,7 +602,7 @@ static int af9013_set_frontend(struct dvb_frontend *fe) /* program CFOE coefficients */ if (c->bandwidth_hz != state->bandwidth_hz) { for (i = 0; i < ARRAY_SIZE(coeff_lut); i++) { - if (coeff_lut[i].clock == state->config.clock && + if (coeff_lut[i].clock == state->clk && coeff_lut[i].bandwidth_hz == c->bandwidth_hz) { break; } @@ -615,24 +622,24 @@ static int af9013_set_frontend(struct dvb_frontend *fe) if (fe->ops.tuner_ops.get_if_frequency) fe->ops.tuner_ops.get_if_frequency(fe, &if_frequency); else - if_frequency = state->config.if_frequency; + if_frequency = state->if_frequency; dev_dbg(&state->i2c->dev, "%s: if_frequency=%d\n", __func__, if_frequency); sampling_freq = if_frequency; - while (sampling_freq > (state->config.clock / 2)) - sampling_freq -= state->config.clock; + while (sampling_freq > (state->clk / 2)) + sampling_freq -= state->clk; if (sampling_freq < 0) { sampling_freq *= -1; - spec_inv = state->config.spec_inv; + spec_inv = state->spec_inv; } else { - spec_inv = !state->config.spec_inv; + spec_inv = !state->spec_inv; } - freq_cw = af9013_div(state, sampling_freq, state->config.clock,
[PATCH 14/15] af9013: refactor firmware download routine
Refactor firmware download routine. Signed-off-by: Antti Palosaari --- drivers/media/dvb-frontends/af9013.c | 65 +--- 1 file changed, 30 insertions(+), 35 deletions(-) diff --git a/drivers/media/dvb-frontends/af9013.c b/drivers/media/dvb-frontends/af9013.c index 63c532a..40fd2ea 100644 --- a/drivers/media/dvb-frontends/af9013.c +++ b/drivers/media/dvb-frontends/af9013.c @@ -1136,64 +1136,59 @@ static const struct dvb_frontend_ops af9013_ops; static int af9013_download_firmware(struct af9013_state *state) { struct i2c_client *client = state->client; - int ret, i, len, remaining; + int ret, i, len, rem; unsigned int utmp; - const struct firmware *fw; + u8 buf[4]; u16 checksum = 0; - u8 fw_params[4]; - u8 *fw_file = AF9013_FIRMWARE; + const struct firmware *firmware; + const char *name = AF9013_FIRMWARE; - msleep(100); - /* check whether firmware is already running */ + dev_dbg(&client->dev, "\n"); + + /* Check whether firmware is already running */ ret = regmap_read(state->regmap, 0x98be, &utmp); if (ret) goto err; dev_dbg(&client->dev, "firmware status %02x\n", utmp); - if (utmp == 0x0c) /* fw is running, no need for download */ + if (utmp == 0x0c) return 0; dev_info(&client->dev, "found a '%s' in cold state, will try to load a firmware\n", af9013_ops.info.name); - /* request the firmware, this will block and timeout */ - ret = request_firmware(&fw, fw_file, &client->dev); + /* Request the firmware, will block and timeout */ + ret = request_firmware(&firmware, name, &client->dev); if (ret) { dev_info(&client->dev, "firmware file '%s' not found %d\n", -fw_file, ret); +name, ret); goto err; } dev_info(&client->dev, "downloading firmware from file '%s'\n", -fw_file); - - /* calc checksum */ - for (i = 0; i < fw->size; i++) - checksum += fw->data[i]; +name); - fw_params[0] = checksum >> 8; - fw_params[1] = checksum & 0xff; - fw_params[2] = fw->size >> 8; - fw_params[3] = fw->size & 0xff; - - /* write fw checksum & size */ - ret = regmap_bulk_write(state->regmap, 0x50fc, fw_params, - sizeof(fw_params)); + /* Write firmware checksum & size */ + for (i = 0; i < firmware->size; i++) + checksum += firmware->data[i]; + buf[0] = (checksum >> 8) & 0xff; + buf[1] = (checksum >> 0) & 0xff; + buf[2] = (firmware->size >> 8) & 0xff; + buf[3] = (firmware->size >> 0) & 0xff; + ret = regmap_bulk_write(state->regmap, 0x50fc, buf, 4); if (ret) goto err_release_firmware; - #define FW_ADDR 0x5100 /* firmware start address */ - #define LEN_MAX 16 /* max packet size */ - for (remaining = fw->size; remaining > 0; remaining -= LEN_MAX) { - len = remaining; - if (len > LEN_MAX) - len = LEN_MAX; - + /* Download firmware */ + #define LEN_MAX 16 + for (rem = firmware->size; rem > 0; rem -= LEN_MAX) { + len = min(LEN_MAX, rem); ret = regmap_bulk_write(state->regmap, - FW_ADDR + fw->size - remaining, - &fw->data[fw->size - remaining], len); + 0x5100 + firmware->size - rem, + &firmware->data[firmware->size - rem], + len); if (ret) { dev_err(&client->dev, "firmware download failed %d\n", ret); @@ -1201,9 +1196,9 @@ static int af9013_download_firmware(struct af9013_state *state) } } - release_firmware(fw); + release_firmware(firmware); - /* request boot firmware */ + /* Boot firmware */ ret = regmap_write(state->regmap, 0xe205, 0x01); if (ret) goto err; @@ -1232,7 +1227,7 @@ static int af9013_download_firmware(struct af9013_state *state) return 0; err_release_firmware: - release_firmware(fw); + release_firmware(firmware); err: dev_dbg(&client->dev, "failed %d\n", ret); return ret; -- http://palosaari.fi/
[PATCH 01/15] af9015: use correct 7-bit i2c addresses
Driver was using wrong "8-bit" i2c addresses for demods and tuners. Internal demod i2c address was not set at all. These are needed to be fixed before proper i2c client binding is used. Signed-off-by: Antti Palosaari --- drivers/media/usb/dvb-usb-v2/af9015.c | 24 +--- drivers/media/usb/dvb-usb-v2/af9015.h | 4 ++-- 2 files changed, 15 insertions(+), 13 deletions(-) diff --git a/drivers/media/usb/dvb-usb-v2/af9015.c b/drivers/media/usb/dvb-usb-v2/af9015.c index caa1e61..138416c 100644 --- a/drivers/media/usb/dvb-usb-v2/af9015.c +++ b/drivers/media/usb/dvb-usb-v2/af9015.c @@ -36,7 +36,7 @@ static int af9015_ctrl_msg(struct dvb_usb_device *d, struct req_t *req) state->buf[0] = req->cmd; state->buf[1] = state->seq++; - state->buf[2] = req->i2c_addr; + state->buf[2] = req->i2c_addr << 1; state->buf[3] = req->addr >> 8; state->buf[4] = req->addr & 0xff; state->buf[5] = req->mbox; @@ -471,6 +471,8 @@ static int af9015_read_config(struct dvb_usb_device *d) if (d->udev->speed == USB_SPEED_FULL) state->dual_mode = 0; + state->af9013_config[0].i2c_addr = AF9015_I2C_DEMOD; + if (state->dual_mode) { /* read 2nd demodulator I2C address */ req.addr = AF9015_EEPROM_DEMOD2_I2C; @@ -478,7 +480,7 @@ static int af9015_read_config(struct dvb_usb_device *d) if (ret) goto error; - state->af9013_config[1].i2c_addr = val; + state->af9013_config[1].i2c_addr = val >> 1; } for (i = 0; i < state->dual_mode + 1; i++) { @@ -870,12 +872,12 @@ static int af9015_af9013_frontend_attach(struct dvb_usb_adapter *adap) } static struct mt2060_config af9015_mt2060_config = { - .i2c_address = 0xc0, + .i2c_address = 0x60, .clock_out = 0, }; static struct qt1010_config af9015_qt1010_config = { - .i2c_address = 0xc4, + .i2c_address = 0x62, }; static struct tda18271_config af9015_tda18271_config = { @@ -884,7 +886,7 @@ static struct tda18271_config af9015_tda18271_config = { }; static struct mxl5005s_config af9015_mxl5003_config = { - .i2c_address = 0xc6, + .i2c_address = 0x63, .if_freq = IF_FREQ_457HZ, .xtal_freq = CRYSTAL_FREQ_1600HZ, .agc_mode= MXL_SINGLE_AGC, @@ -901,7 +903,7 @@ static struct mxl5005s_config af9015_mxl5003_config = { }; static struct mxl5005s_config af9015_mxl5005_config = { - .i2c_address = 0xc6, + .i2c_address = 0x63, .if_freq = IF_FREQ_457HZ, .xtal_freq = CRYSTAL_FREQ_1600HZ, .agc_mode= MXL_SINGLE_AGC, @@ -918,12 +920,12 @@ static struct mxl5005s_config af9015_mxl5005_config = { }; static struct mc44s803_config af9015_mc44s803_config = { - .i2c_address = 0xc0, + .i2c_address = 0x60, .dig_out = 1, }; static struct tda18218_config af9015_tda18218_config = { - .i2c_address = 0xc0, + .i2c_address = 0x60, .i2c_wr_max = 21, /* max wr bytes AF9015 I2C adap can handle at once */ }; @@ -954,7 +956,7 @@ static int af9015_tuner_attach(struct dvb_usb_adapter *adap) &af9015_qt1010_config) == NULL ? -ENODEV : 0; break; case AF9013_TUNER_TDA18271: - ret = dvb_attach(tda18271_attach, adap->fe[0], 0xc0, + ret = dvb_attach(tda18271_attach, adap->fe[0], 0x60, &adap_to_d(adap)->i2c_adap, &af9015_tda18271_config) == NULL ? -ENODEV : 0; break; @@ -975,7 +977,7 @@ static int af9015_tuner_attach(struct dvb_usb_adapter *adap) &af9015_mxl5005_config) == NULL ? -ENODEV : 0; break; case AF9013_TUNER_ENV77H11D5: - ret = dvb_attach(dvb_pll_attach, adap->fe[0], 0xc0, + ret = dvb_attach(dvb_pll_attach, adap->fe[0], 0x60, &adap_to_d(adap)->i2c_adap, DVB_PLL_TDA665X) == NULL ? -ENODEV : 0; break; @@ -987,7 +989,7 @@ static int af9015_tuner_attach(struct dvb_usb_adapter *adap) case AF9013_TUNER_MXL5007T: ret = dvb_attach(mxl5007t_attach, adap->fe[0], &adap_to_d(adap)->i2c_adap, - 0xc0, &af9015_mxl5007t_config) == NULL ? -ENODEV : 0; + 0x60, &af9015_mxl5007t_config) == NULL ? -ENODEV : 0; break; case AF9013_TUNER_UNKNOWN: default: diff --git a/drivers/media/usb/dvb-usb-v2/af9015.h b/drivers/media/usb/dvb-usb-v2/af9015.h index 2dd9231..3a9d981 100644 --- a/drivers/media/usb/dvb-usb-v2/af9015.h +++ b/drivers/media/usb/dv
[PATCH 10/15] af9015: enable 2nd TS flow control when dual mode
It needs to be enabled in order to get stream from slave af9013 demod. Signed-off-by: Antti Palosaari --- drivers/media/usb/dvb-usb-v2/af9015.c | 15 +-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/drivers/media/usb/dvb-usb-v2/af9015.c b/drivers/media/usb/dvb-usb-v2/af9015.c index 54c1d47..ee0e354 100644 --- a/drivers/media/usb/dvb-usb-v2/af9015.c +++ b/drivers/media/usb/dvb-usb-v2/af9015.c @@ -1131,10 +1131,21 @@ static int af9015_init_endpoint(struct dvb_usb_device *d) } /* enable / disable mp2if2 */ - if (state->dual_mode) + if (state->dual_mode) { ret = af9015_set_reg_bit(d, 0xd50b, 0); - else + if (ret) + goto error; + ret = af9015_set_reg_bit(d, 0xd520, 4); + if (ret) + goto error; + } else { ret = af9015_clear_reg_bit(d, 0xd50b, 0); + if (ret) + goto error; + ret = af9015_clear_reg_bit(d, 0xd520, 4); + if (ret) + goto error; + } error: if (ret) -- http://palosaari.fi/
[PATCH 07/15] af9013: fix error handling
Use typical (return 0/goto err/return err) error handling everywhere. Add missing error handling where missing. Signed-off-by: Antti Palosaari --- drivers/media/dvb-frontends/af9013.c | 86 +--- 1 file changed, 51 insertions(+), 35 deletions(-) diff --git a/drivers/media/dvb-frontends/af9013.c b/drivers/media/dvb-frontends/af9013.c index 70102c1..a6b88ae 100644 --- a/drivers/media/dvb-frontends/af9013.c +++ b/drivers/media/dvb-frontends/af9013.c @@ -94,7 +94,7 @@ static int af9013_set_gpio(struct af9013_state *state, u8 gpio, u8 gpioval) if (ret) goto err; - return ret; + return 0; err: dev_dbg(&client->dev, "failed %d\n", ret); return ret; @@ -147,7 +147,7 @@ static int af9013_power_ctrl(struct af9013_state *state, u8 onoff) goto err; } - return ret; + return 0; err: dev_dbg(&client->dev, "failed %d\n", ret); return ret; @@ -166,7 +166,7 @@ static int af9013_statistics_ber_unc_start(struct dvb_frontend *fe) if (ret) goto err; - return ret; + return 0; err: dev_dbg(&client->dev, "failed %d\n", ret); return ret; @@ -199,7 +199,7 @@ static int af9013_statistics_ber_unc_result(struct dvb_frontend *fe) state->ber = (buf[2] << 16) | (buf[1] << 8) | buf[0]; state->ucblocks += (buf[4] << 8) | buf[3]; - return ret; + return 0; err: dev_dbg(&client->dev, "failed %d\n", ret); return ret; @@ -218,7 +218,7 @@ static int af9013_statistics_snr_start(struct dvb_frontend *fe) if (ret) goto err; - return ret; + return 0; err: dev_dbg(&client->dev, "failed %d\n", ret); return ret; @@ -283,7 +283,7 @@ static int af9013_statistics_snr_result(struct dvb_frontend *fe) } state->snr = utmp * 10; /* dB/10 */ - return ret; + return 0; err: dev_dbg(&client->dev, "failed %d\n", ret); return ret; @@ -321,7 +321,7 @@ static int af9013_statistics_signal_strength(struct dvb_frontend *fe) state->signal_strength = signal_strength; - return ret; + return 0; err: dev_dbg(&client->dev, "failed %d\n", ret); return ret; @@ -398,8 +398,11 @@ static int af9013_set_frontend(struct dvb_frontend *fe) c->frequency, c->bandwidth_hz); /* program tuner */ - if (fe->ops.tuner_ops.set_params) - fe->ops.tuner_ops.set_params(fe); + if (fe->ops.tuner_ops.set_params) { + ret = fe->ops.tuner_ops.set_params(fe); + if (ret) + goto err; + } /* program CFOE coefficients */ if (c->bandwidth_hz != state->bandwidth_hz) { @@ -411,20 +414,28 @@ static int af9013_set_frontend(struct dvb_frontend *fe) } /* Return an error if can't find bandwidth or the right clock */ - if (i == ARRAY_SIZE(coeff_lut)) - return -EINVAL; + if (i == ARRAY_SIZE(coeff_lut)) { + ret = -EINVAL; + goto err; + } ret = regmap_bulk_write(state->regmap, 0xae00, coeff_lut[i].val, sizeof(coeff_lut[i].val)); + if (ret) + goto err; } /* program frequency control */ if (c->bandwidth_hz != state->bandwidth_hz || state->first_tune) { /* get used IF frequency */ - if (fe->ops.tuner_ops.get_if_frequency) - fe->ops.tuner_ops.get_if_frequency(fe, &if_frequency); - else + if (fe->ops.tuner_ops.get_if_frequency) { + ret = fe->ops.tuner_ops.get_if_frequency(fe, +&if_frequency); + if (ret) + goto err; + } else { if_frequency = state->if_frequency; + } dev_dbg(&client->dev, "if_frequency %u\n", if_frequency); @@ -659,7 +670,7 @@ static int af9013_set_frontend(struct dvb_frontend *fe) state->set_frontend_jiffies = jiffies; state->first_tune = false; - return ret; + return 0; err: dev_dbg(&client->dev, "failed %d\n", ret); return ret; @@ -777,7 +788,7 @@ static int af9013_get_frontend(struct dvb_frontend *fe, break; } - return ret; + return 0; err: dev_dbg(&client->dev, "failed %d\n", ret);
[PATCH 13/15] af9015: move 2nd demod power-up wait different location
We need to wait 2nd demod power-up before download firmware. Move that wait to more correct location. Signed-off-by: Antti Palosaari --- drivers/media/usb/dvb-usb-v2/af9015.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/media/usb/dvb-usb-v2/af9015.c b/drivers/media/usb/dvb-usb-v2/af9015.c index ee0e354..53d478d 100644 --- a/drivers/media/usb/dvb-usb-v2/af9015.c +++ b/drivers/media/usb/dvb-usb-v2/af9015.c @@ -740,9 +740,6 @@ static int af9015_copy_firmware(struct dvb_usb_device *d) fw_params[2] = state->firmware_checksum >> 8; fw_params[3] = state->firmware_checksum & 0xff; - /* wait 2nd demodulator ready */ - msleep(100); - ret = af9015_read_reg_i2c(d, state->af9013_config[1].i2c_addr, 0x98be, &val); if (ret) @@ -830,6 +827,9 @@ static int af9015_af9013_frontend_attach(struct dvb_usb_adapter *adap) /* copy firmware to 2nd demodulator */ if (state->dual_mode) { + /* Wait 2nd demodulator ready */ + msleep(100); + ret = af9015_copy_firmware(adap_to_d(adap)); if (ret) { dev_err(&adap_to_d(adap)->udev->dev, -- http://palosaari.fi/
[PATCH 11/15] af9013: add configurable TS output pin
On serial TS mode output pin could be selected from D0 or D7. Add configuration option to for it. Rename TS mode config option prefix from AF9013_TS_ to AF9013_TS_MODE_. Signed-off-by: Antti Palosaari --- drivers/media/dvb-frontends/af9013.c | 27 ++- drivers/media/dvb-frontends/af9013.h | 2 ++ 2 files changed, 16 insertions(+), 13 deletions(-) diff --git a/drivers/media/dvb-frontends/af9013.c b/drivers/media/dvb-frontends/af9013.c index 68091f2..6b86437 100644 --- a/drivers/media/dvb-frontends/af9013.c +++ b/drivers/media/dvb-frontends/af9013.c @@ -28,6 +28,7 @@ struct af9013_state { u8 tuner; u32 if_frequency; u8 ts_mode; + u8 ts_output_pin; bool spec_inv; u8 api_version[4]; u8 gpio[4]; @@ -955,17 +956,12 @@ static int af9013_init(struct dvb_frontend *fe) goto err; /* settings for mp2if */ - if (state->ts_mode == AF9013_TS_USB) { + if (state->ts_mode == AF9013_TS_MODE_USB) { /* AF9015 split PSB to 1.5k + 0.5k */ ret = regmap_update_bits(state->regmap, 0xd50b, 0x04, 0x04); if (ret) goto err; } else { - /* AF9013 change the output bit to data7 */ - ret = regmap_update_bits(state->regmap, 0xd500, 0x08, 0x08); - if (ret) - goto err; - /* AF9013 set mpeg to full speed */ ret = regmap_update_bits(state->regmap, 0xd502, 0x10, 0x10); if (ret) @@ -1046,9 +1042,12 @@ static int af9013_init(struct dvb_frontend *fe) goto err; } - /* TS mode */ - ret = regmap_update_bits(state->regmap, 0xd500, 0x06, -state->ts_mode << 1); + /* TS interface */ + if (state->ts_output_pin == 7) + utmp = 1 << 3 | state->ts_mode << 1; + else + utmp = 0 << 3 | state->ts_mode << 1; + ret = regmap_update_bits(state->regmap, 0xd500, 0x0e, utmp); if (ret) goto err; @@ -1147,7 +1146,7 @@ static int af9013_i2c_gate_ctrl(struct dvb_frontend *fe, int enable) if (state->i2c_gate_state == enable) return 0; - if (state->ts_mode == AF9013_TS_USB) + if (state->ts_mode == AF9013_TS_MODE_USB) ret = regmap_update_bits(state->regmap, 0xd417, 0x08, enable << 3); else @@ -1297,6 +1296,7 @@ struct dvb_frontend *af9013_attach(const struct af9013_config *config, pdata.tuner = config->tuner; pdata.if_frequency = config->if_frequency; pdata.ts_mode = config->ts_mode; + pdata.ts_output_pin = 7; pdata.spec_inv = config->spec_inv; memcpy(&pdata.api_version, config->api_version, sizeof(pdata.api_version)); memcpy(&pdata.gpio, config->gpio, sizeof(pdata.gpio)); @@ -1450,7 +1450,7 @@ static int af9013_regmap_write(void *context, const void *data, size_t count) u8 *val = &((u8 *)data)[2]; const unsigned int len = count - 2; - if (state->ts_mode == AF9013_TS_USB && (reg & 0xff00) != 0xae00) { + if (state->ts_mode == AF9013_TS_MODE_USB && (reg & 0xff00) != 0xae00) { cmd = 0 << 7|0 << 6|(len - 1) << 2|1 << 1|1 << 0; ret = af9013_wregs(client, cmd, reg, val, len); if (ret) @@ -1487,7 +1487,7 @@ static int af9013_regmap_read(void *context, const void *reg_buf, u8 *val = &((u8 *)val_buf)[0]; const unsigned int len = val_size; - if (state->ts_mode == AF9013_TS_USB && (reg & 0xff00) != 0xae00) { + if (state->ts_mode == AF9013_TS_MODE_USB && (reg & 0xff00) != 0xae00) { cmd = 0 << 7|0 << 6|(len - 1) << 2|1 << 1|0 << 0; ret = af9013_rregs(client, cmd, reg, val_buf, len); if (ret) @@ -1537,6 +1537,7 @@ static int af9013_probe(struct i2c_client *client, state->tuner = pdata->tuner; state->if_frequency = pdata->if_frequency; state->ts_mode = pdata->ts_mode; + state->ts_output_pin = pdata->ts_output_pin; state->spec_inv = pdata->spec_inv; memcpy(&state->api_version, pdata->api_version, sizeof(state->api_version)); memcpy(&state->gpio, pdata->gpio, sizeof(state->gpio)); @@ -1549,7 +1550,7 @@ static int af9013_probe(struct i2c_client *client, } /* Download firmware */ - if (state->ts_mode != AF9013_TS_USB) { + if (state->ts_mode != AF9013_TS_MODE_USB) { ret = af9013_download_firmware(state); if (ret)
[PATCH 03/15] af9013: add i2c client bindings
Add kernel i2c driver bindings. That allows dev_* logging, regmap and more. Signed-off-by: Antti Palosaari --- drivers/media/dvb-frontends/af9013.c | 321 ++- drivers/media/dvb-frontends/af9013.h | 84 + 2 files changed, 241 insertions(+), 164 deletions(-) diff --git a/drivers/media/dvb-frontends/af9013.c b/drivers/media/dvb-frontends/af9013.c index 7880a63..f644182 100644 --- a/drivers/media/dvb-frontends/af9013.c +++ b/drivers/media/dvb-frontends/af9013.c @@ -24,9 +24,8 @@ #define MAX_XFER_SIZE 64 struct af9013_state { - struct i2c_adapter *i2c; + struct i2c_client *client; struct dvb_frontend fe; - u8 i2c_addr; u32 clk; u8 tuner; u32 if_frequency; @@ -59,7 +58,7 @@ static int af9013_wr_regs_i2c(struct af9013_state *priv, u8 mbox, u16 reg, u8 buf[MAX_XFER_SIZE]; struct i2c_msg msg[1] = { { - .addr = priv->i2c_addr, + .addr = priv->client->addr, .flags = 0, .len = 3 + len, .buf = buf, @@ -67,7 +66,7 @@ static int af9013_wr_regs_i2c(struct af9013_state *priv, u8 mbox, u16 reg, }; if (3 + len > sizeof(buf)) { - dev_warn(&priv->i2c->dev, + dev_warn(&priv->client->dev, "%s: i2c wr reg=%04x: len=%d is too big!\n", KBUILD_MODNAME, reg, len); return -EINVAL; @@ -78,11 +77,11 @@ static int af9013_wr_regs_i2c(struct af9013_state *priv, u8 mbox, u16 reg, buf[2] = mbox; memcpy(&buf[3], val, len); - ret = i2c_transfer(priv->i2c, msg, 1); + ret = i2c_transfer(priv->client->adapter, msg, 1); if (ret == 1) { ret = 0; } else { - dev_warn(&priv->i2c->dev, "%s: i2c wr failed=%d reg=%04x " \ + dev_warn(&priv->client->dev, "%s: i2c wr failed=%d reg=%04x " \ "len=%d\n", KBUILD_MODNAME, ret, reg, len); ret = -EREMOTEIO; } @@ -97,12 +96,12 @@ static int af9013_rd_regs_i2c(struct af9013_state *priv, u8 mbox, u16 reg, u8 buf[3]; struct i2c_msg msg[2] = { { - .addr = priv->i2c_addr, + .addr = priv->client->addr, .flags = 0, .len = 3, .buf = buf, }, { - .addr = priv->i2c_addr, + .addr = priv->client->addr, .flags = I2C_M_RD, .len = len, .buf = val, @@ -113,11 +112,11 @@ static int af9013_rd_regs_i2c(struct af9013_state *priv, u8 mbox, u16 reg, buf[1] = (reg >> 0) & 0xff; buf[2] = mbox; - ret = i2c_transfer(priv->i2c, msg, 2); + ret = i2c_transfer(priv->client->adapter, msg, 2); if (ret == 2) { ret = 0; } else { - dev_warn(&priv->i2c->dev, "%s: i2c rd failed=%d reg=%04x " \ + dev_warn(&priv->client->dev, "%s: i2c rd failed=%d reg=%04x " \ "len=%d\n", KBUILD_MODNAME, ret, reg, len); ret = -EREMOTEIO; } @@ -231,7 +230,7 @@ static int af9013_set_gpio(struct af9013_state *state, u8 gpio, u8 gpioval) u8 pos; u16 addr; - dev_dbg(&state->i2c->dev, "%s: gpio=%d gpioval=%02x\n", + dev_dbg(&state->client->dev, "%s: gpio=%d gpioval=%02x\n", __func__, gpio, gpioval); /* @@ -250,7 +249,7 @@ static int af9013_set_gpio(struct af9013_state *state, u8 gpio, u8 gpioval) break; default: - dev_err(&state->i2c->dev, "%s: invalid gpio=%d\n", + dev_err(&state->client->dev, "%s: invalid gpio=%d\n", KBUILD_MODNAME, gpio); ret = -EINVAL; goto err; @@ -274,7 +273,7 @@ static int af9013_set_gpio(struct af9013_state *state, u8 gpio, u8 gpioval) return ret; err: - dev_dbg(&state->i2c->dev, "%s: failed=%d\n", __func__, ret); + dev_dbg(&state->client->dev, "%s: failed=%d\n", __func__, ret); return ret; } @@ -282,7 +281,7 @@ static u32 af9013_div(struct af9013_state *state, u32 a, u32 b, u32 x) { u32 r = 0, c = 0, i; - dev_dbg(&state->i2c->dev, "%s: a=%d b=%d x=%d\n", __func__, a, b, x); + dev_dbg(&state->client->dev, "%s: a=%d b=%d x=%
[GIT PULL 4.13] af9015/af9013 changes
The following changes since commit 3622d3e77ecef090b5111e3c5423313f11711dfa: [media] ov2640: print error if devm_*_optional*() fails (2017-04-25 07:08:21 -0300) are available in the git repository at: git://linuxtv.org/anttip/media_tree.git af9015_pull for you to fetch changes up to 2a32db020ab01e3ac99febad90a42112aa28b2ee: af9013: refactor power control (2017-06-18 05:42:25 +0300) Antti Palosaari (15): af9015: use correct 7-bit i2c addresses af9013: move config values directly under driver state af9013: add i2c client bindings af9013: use kernel 64-bit division af9013: fix logging af9013: convert to regmap api af9013: fix error handling af9013: add dvbv5 cnr af9015: fix and refactor i2c adapter algo logic af9015: enable 2nd TS flow control when dual mode af9013: add configurable TS output pin af9013: remove unneeded register writes af9015: move 2nd demod power-up wait different location af9013: refactor firmware download routine af9013: refactor power control Gustavo A. R. Silva (1): af9013: add check on af9013_wr_regs() return value drivers/media/dvb-frontends/Kconfig |1 + drivers/media/dvb-frontends/af9013.c | 1185 ++- drivers/media/dvb-frontends/af9013.h | 86 +-- drivers/media/dvb-frontends/af9013_priv.h |2 + drivers/media/usb/dvb-usb-v2/af9015.c | 198 +--- drivers/media/usb/dvb-usb-v2/af9015.h |4 +- 6 files changed, 752 insertions(+), 724 deletions(-) -- http://palosaari.fi/
Re: [PATCH] [media] ddbridge: use pr_* macros in favor of printk
On 06/20/2017 08:44 PM, Daniel Scheller wrote: From: Daniel Scheller Side effect: KERN_DEBUG messages aren't written to the kernel log anymore. This also improves the tda18212_ping reporting a bit so users know that if pinging wasn't successful, bad things might happen. It is device, not library, thus you should really use dev_ logging instead. With dev_ logging system could print better info, bus id etc. regards Antti -- http://palosaari.fi/
Re: [PATCH 1/4] [media] dvb-frontends/stv0367: initial DDB DVBv5 stats, implement ucblocks
On 06/20/2017 08:45 PM, Daniel Scheller wrote: From: Daniel Scheller This adds the basics to stv0367ddb_get_frontend() to be able to properly provide signal statistics in DVBv5 format. Also adds UCB readout and provides those values. Signed-off-by: Daniel Scheller --- drivers/media/dvb-frontends/stv0367.c | 59 --- 1 file changed, 55 insertions(+), 4 deletions(-) diff --git a/drivers/media/dvb-frontends/stv0367.c b/drivers/media/dvb-frontends/stv0367.c index e726c2e00460..5374d4eaabd6 100644 --- a/drivers/media/dvb-frontends/stv0367.c +++ b/drivers/media/dvb-frontends/stv0367.c @@ -2997,21 +2997,64 @@ static int stv0367ddb_read_status(struct dvb_frontend *fe, return -EINVAL; } +static void stv0367ddb_read_ucblocks(struct dvb_frontend *fe) +{ + struct stv0367_state *state = fe->demodulator_priv; + struct dtv_frontend_properties *p = &fe->dtv_property_cache; + u32 ucblocks = 0; + + switch (state->activedemod) { + case demod_ter: + stv0367ter_read_ucblocks(fe, &ucblocks); + break; + case demod_cab: + stv0367cab_read_ucblcks(fe, &ucblocks); + break; + default: + p->block_error.stat[0].scale = FE_SCALE_NOT_AVAILABLE; + return; + } + + p->block_error.stat[0].scale = FE_SCALE_COUNTER; + p->block_error.stat[0].uvalue = ucblocks; +} + static int stv0367ddb_get_frontend(struct dvb_frontend *fe, struct dtv_frontend_properties *p) { struct stv0367_state *state = fe->demodulator_priv; + int ret = -EINVAL; + enum fe_status status = 0; switch (state->activedemod) { case demod_ter: - return stv0367ter_get_frontend(fe, p); + ret = stv0367ter_get_frontend(fe, p); + break; case demod_cab: - return stv0367cab_get_frontend(fe, p); - default: + ret = stv0367cab_get_frontend(fe, p); break; + default: + p->strength.stat[0].scale = FE_SCALE_NOT_AVAILABLE; + p->cnr.stat[0].scale = FE_SCALE_NOT_AVAILABLE; + p->block_error.stat[0].scale = FE_SCALE_NOT_AVAILABLE; + return ret; } - return -EINVAL; + /* read fe lock status */ + if (!ret) + ret = stv0367ddb_read_status(fe, &status); + + /* stop if get_frontend failed or if demod isn't locked */ + if (ret || !(status & FE_HAS_LOCK)) { + p->strength.stat[0].scale = FE_SCALE_NOT_AVAILABLE; + p->cnr.stat[0].scale = FE_SCALE_NOT_AVAILABLE; + p->block_error.stat[0].scale = FE_SCALE_NOT_AVAILABLE; + return ret; + } Requiring LOCK for strength and cnr sounds wrong. Demod usually calculates strength from IF and RF AGC and those are available even there is no signal at all (demod set those gains to max on that case). CNR is pretty often available when inner FEC (viterbi, LDPC) is on sync. And for ber and per you need outer fec (reed-solomon, bch) too which is FE_HAS_SYNC flag on api. ber is error bit and count after inner fec, per is error packet and count after outer fec. Usually ber is counted as a bits and per is counted as a 204 ts packets. Also having that statistics stuff updated inside a get_frontend() sounds wrong. I think that callback is optional and is not called unless userspace polls it. + + stv0367ddb_read_ucblocks(fe); + + return 0; } static int stv0367ddb_sleep(struct dvb_frontend *fe) @@ -3035,6 +3078,7 @@ static int stv0367ddb_sleep(struct dvb_frontend *fe) static int stv0367ddb_init(struct stv0367_state *state) { struct stv0367ter_state *ter_state = state->ter_state; + struct dtv_frontend_properties *p = &state->fe.dtv_property_cache; stv0367_writereg(state, R367TER_TOPCTRL, 0x10); @@ -3109,6 +3153,13 @@ static int stv0367ddb_init(struct stv0367_state *state) ter_state->first_lock = 0; ter_state->unlock_counter = 2; + p->strength.len = 1; + p->strength.stat[0].scale = FE_SCALE_NOT_AVAILABLE; + p->cnr.len = 1; + p->cnr.stat[0].scale = FE_SCALE_NOT_AVAILABLE; + p->block_error.len = 1; + p->block_error.stat[0].scale = FE_SCALE_NOT_AVAILABLE; + return 0; } regards Antti -- http://palosaari.fi/
Re: [PATCH 3/4] [media] dvb-frontends/stv0367: SNR DVBv5 statistics for DVB-C and T
On 06/20/2017 08:45 PM, Daniel Scheller wrote: From: Daniel Scheller Add signal-to-noise-ratio as provided by the demodulator in decibel scale. QAM/DVB-C needs some intlog calculation to have usable dB values, OFDM/ DVB-T values from the demod look alright already and are provided as-is. Signed-off-by: Daniel Scheller --- drivers/media/dvb-frontends/stv0367.c | 33 + 1 file changed, 33 insertions(+) diff --git a/drivers/media/dvb-frontends/stv0367.c b/drivers/media/dvb-frontends/stv0367.c index bb498f942ebd..0b13a407df23 100644 --- a/drivers/media/dvb-frontends/stv0367.c +++ b/drivers/media/dvb-frontends/stv0367.c @@ -25,6 +25,8 @@ #include #include +#include "dvb_math.h" + #include "stv0367.h" #include "stv0367_defs.h" #include "stv0367_regs.h" @@ -33,6 +35,9 @@ /* Max transfer size done by I2C transfer functions */ #define MAX_XFER_SIZE 64 +/* snr logarithmic calc */ +#define INTLOG10X100(x) ((u32) (((u64) intlog10(x) * 100) >> 24)) + static int stvdebug; module_param_named(debug, stvdebug, int, 0644); @@ -3013,6 +3018,33 @@ static int stv0367ddb_read_status(struct dvb_frontend *fe, return -EINVAL; } +static void stv0367ddb_read_snr(struct dvb_frontend *fe) +{ + struct stv0367_state *state = fe->demodulator_priv; + struct dtv_frontend_properties *p = &fe->dtv_property_cache; + int cab_pwr; + u32 regval, tmpval, snrval = 0; + + switch (state->activedemod) { + case demod_ter: + snrval = stv0367ter_snr_readreg(fe); + break; + case demod_cab: + cab_pwr = stv0367cab_snr_power(fe); + regval = stv0367cab_snr_readreg(fe, 0); + + tmpval = (cab_pwr * 320) / regval; + snrval = ((tmpval != 0) ? INTLOG10X100(tmpval) : 0) * 100; How much there will be rounding errors due to that signal/noise division? I would convert it to calculation of sums (tip logarithm calculation rules). Also, that INTLOG10X100 is pretty much useless. Use just what intlog10/intlog2 offers without yet again another conversion. + break; + default: + p->cnr.stat[0].scale = FE_SCALE_NOT_AVAILABLE; + return; + } + + p->cnr.stat[0].scale = FE_SCALE_DECIBEL; + p->cnr.stat[0].uvalue = snrval; +} + static void stv0367ddb_read_ucblocks(struct dvb_frontend *fe) { struct stv0367_state *state = fe->demodulator_priv; @@ -3069,6 +3101,7 @@ static int stv0367ddb_get_frontend(struct dvb_frontend *fe, } stv0367ddb_read_ucblocks(fe); + stv0367ddb_read_snr(fe); return 0; } regards Antti -- http://palosaari.fi/