diff options
Diffstat (limited to 'drivers/media/dvb-frontends/rtl2832.c')
-rw-r--r-- | drivers/media/dvb-frontends/rtl2832.c | 191 |
1 files changed, 169 insertions, 22 deletions
diff --git a/drivers/media/dvb-frontends/rtl2832.c b/drivers/media/dvb-frontends/rtl2832.c index ff73da9365e3..fdbed35c87fa 100644 --- a/drivers/media/dvb-frontends/rtl2832.c +++ b/drivers/media/dvb-frontends/rtl2832.c @@ -24,11 +24,6 @@ /* Max transfer size done by I2C transfer functions */ #define MAX_XFER_SIZE 64 - -int rtl2832_debug; -module_param_named(debug, rtl2832_debug, int, 0644); -MODULE_PARM_DESC(debug, "Turn on/off frontend debugging (default:off)."); - #define REG_MASK(b) (BIT(b + 1) - 1) static const struct rtl2832_reg_entry registers[] = { @@ -185,12 +180,13 @@ static int rtl2832_wr(struct rtl2832_priv *priv, u8 reg, u8 *val, int len) buf[0] = reg; memcpy(&buf[1], val, len); - ret = i2c_transfer(priv->i2c, msg, 1); + ret = i2c_transfer(priv->i2c_adapter, msg, 1); if (ret == 1) { ret = 0; } else { - dev_warn(&priv->i2c->dev, "%s: i2c wr failed=%d reg=%02x " \ - "len=%d\n", KBUILD_MODNAME, ret, reg, len); + dev_warn(&priv->i2c->dev, + "%s: i2c wr failed=%d reg=%02x len=%d\n", + KBUILD_MODNAME, ret, reg, len); ret = -EREMOTEIO; } return ret; @@ -214,12 +210,13 @@ static int rtl2832_rd(struct rtl2832_priv *priv, u8 reg, u8 *val, int len) } }; - ret = i2c_transfer(priv->i2c, msg, 2); + ret = i2c_transfer(priv->i2c_adapter, msg, 2); if (ret == 2) { ret = 0; } else { - dev_warn(&priv->i2c->dev, "%s: i2c rd failed=%d reg=%02x " \ - "len=%d\n", KBUILD_MODNAME, ret, reg, len); + dev_warn(&priv->i2c->dev, + "%s: i2c rd failed=%d reg=%02x len=%d\n", + KBUILD_MODNAME, ret, reg, len); ret = -EREMOTEIO; } return ret; @@ -417,7 +414,7 @@ static int rtl2832_set_if(struct dvb_frontend *fe, u32 if_freq) ret = rtl2832_wr_demod_reg(priv, DVBT_PSET_IFFREQ, pset_iffreq); - return (ret); + return ret; } static int rtl2832_init(struct dvb_frontend *fe) @@ -514,15 +511,10 @@ static int rtl2832_init(struct dvb_frontend *fe) goto err; } - if (!fe->ops.tuner_ops.get_if_frequency) { - ret = rtl2832_set_if(fe, priv->cfg.if_dvbt); - if (ret) - goto err; - } - /* * r820t NIM code does a software reset here at the demod - - * may not be needed, as there's already a software reset at set_params() + * may not be needed, as there's already a software reset at + * set_params() */ #if 1 /* soft reset */ @@ -599,9 +591,9 @@ static int rtl2832_set_frontend(struct dvb_frontend *fe) }; - dev_dbg(&priv->i2c->dev, "%s: frequency=%d bandwidth_hz=%d " \ - "inversion=%d\n", __func__, c->frequency, - c->bandwidth_hz, c->inversion); + dev_dbg(&priv->i2c->dev, + "%s: frequency=%d bandwidth_hz=%d inversion=%d\n", + __func__, c->frequency, c->bandwidth_hz, c->inversion); /* program tuner */ if (fe->ops.tuner_ops.set_params) @@ -899,9 +891,149 @@ static void rtl2832_release(struct dvb_frontend *fe) struct rtl2832_priv *priv = fe->demodulator_priv; dev_dbg(&priv->i2c->dev, "%s:\n", __func__); + cancel_delayed_work_sync(&priv->i2c_gate_work); + i2c_del_mux_adapter(priv->i2c_adapter_tuner); + i2c_del_mux_adapter(priv->i2c_adapter); kfree(priv); } +/* + * Delay mechanism to avoid unneeded I2C gate open / close. Gate close is + * delayed here a little bit in order to see if there is sequence of I2C + * messages sent to same I2C bus. + * We must use unlocked version of __i2c_transfer() in order to avoid deadlock + * as lock is already taken by calling muxed i2c_transfer(). + */ +static void rtl2832_i2c_gate_work(struct work_struct *work) +{ + struct rtl2832_priv *priv = container_of(work, + struct rtl2832_priv, i2c_gate_work.work); + struct i2c_adapter *adap = priv->i2c; + int ret; + u8 buf[2]; + struct i2c_msg msg[1] = { + { + .addr = priv->cfg.i2c_addr, + .flags = 0, + .len = sizeof(buf), + .buf = buf, + } + }; + + /* select reg bank 1 */ + buf[0] = 0x00; + buf[1] = 0x01; + ret = __i2c_transfer(adap, msg, 1); + if (ret != 1) + goto err; + + priv->page = 1; + + /* close I2C repeater gate */ + buf[0] = 0x01; + buf[1] = 0x10; + ret = __i2c_transfer(adap, msg, 1); + if (ret != 1) + goto err; + + priv->i2c_gate_state = 0; + + return; +err: + dev_dbg(&priv->i2c->dev, "%s: failed=%d\n", __func__, ret); + + return; +} + +static int rtl2832_select(struct i2c_adapter *adap, void *mux_priv, u32 chan_id) +{ + struct rtl2832_priv *priv = mux_priv; + int ret; + u8 buf[2], val; + struct i2c_msg msg[1] = { + { + .addr = priv->cfg.i2c_addr, + .flags = 0, + .len = sizeof(buf), + .buf = buf, + } + }; + struct i2c_msg msg_rd[2] = { + { + .addr = priv->cfg.i2c_addr, + .flags = 0, + .len = 1, + .buf = "\x01", + }, { + .addr = priv->cfg.i2c_addr, + .flags = I2C_M_RD, + .len = 1, + .buf = &val, + } + }; + + /* terminate possible gate closing */ + cancel_delayed_work_sync(&priv->i2c_gate_work); + + if (priv->i2c_gate_state == chan_id) + return 0; + + /* select reg bank 1 */ + buf[0] = 0x00; + buf[1] = 0x01; + ret = __i2c_transfer(adap, msg, 1); + if (ret != 1) + goto err; + + priv->page = 1; + + /* we must read that register, otherwise there will be errors */ + ret = __i2c_transfer(adap, msg_rd, 2); + if (ret != 2) + goto err; + + /* open or close I2C repeater gate */ + buf[0] = 0x01; + if (chan_id == 1) + buf[1] = 0x18; /* open */ + else + buf[1] = 0x10; /* close */ + + ret = __i2c_transfer(adap, msg, 1); + if (ret != 1) + goto err; + + priv->i2c_gate_state = chan_id; + + return 0; +err: + dev_dbg(&priv->i2c->dev, "%s: failed=%d\n", __func__, ret); + + return -EREMOTEIO; +} + +static int rtl2832_deselect(struct i2c_adapter *adap, void *mux_priv, + u32 chan_id) +{ + struct rtl2832_priv *priv = mux_priv; + schedule_delayed_work(&priv->i2c_gate_work, usecs_to_jiffies(100)); + return 0; +} + +struct i2c_adapter *rtl2832_get_i2c_adapter(struct dvb_frontend *fe) +{ + struct rtl2832_priv *priv = fe->demodulator_priv; + return priv->i2c_adapter_tuner; +} +EXPORT_SYMBOL(rtl2832_get_i2c_adapter); + +struct i2c_adapter *rtl2832_get_private_i2c_adapter(struct dvb_frontend *fe) +{ + struct rtl2832_priv *priv = fe->demodulator_priv; + return priv->i2c_adapter; +} +EXPORT_SYMBOL(rtl2832_get_private_i2c_adapter); + struct dvb_frontend *rtl2832_attach(const struct rtl2832_config *cfg, struct i2c_adapter *i2c) { @@ -920,12 +1052,25 @@ struct dvb_frontend *rtl2832_attach(const struct rtl2832_config *cfg, priv->i2c = i2c; priv->tuner = cfg->tuner; memcpy(&priv->cfg, cfg, sizeof(struct rtl2832_config)); + INIT_DELAYED_WORK(&priv->i2c_gate_work, rtl2832_i2c_gate_work); + + /* create muxed i2c adapter for demod itself */ + priv->i2c_adapter = i2c_add_mux_adapter(i2c, &i2c->dev, priv, 0, 0, 0, + rtl2832_select, NULL); + if (priv->i2c_adapter == NULL) + goto err; /* check if the demod is there */ ret = rtl2832_rd_reg(priv, 0x00, 0x0, &tmp); if (ret) goto err; + /* create muxed i2c adapter for demod tuner bus */ + priv->i2c_adapter_tuner = i2c_add_mux_adapter(i2c, &i2c->dev, priv, + 0, 1, 0, rtl2832_select, rtl2832_deselect); + if (priv->i2c_adapter_tuner == NULL) + goto err; + /* create dvb_frontend */ memcpy(&priv->fe.ops, &rtl2832_ops, sizeof(struct dvb_frontend_ops)); priv->fe.demodulator_priv = priv; @@ -936,6 +1081,8 @@ struct dvb_frontend *rtl2832_attach(const struct rtl2832_config *cfg, return &priv->fe; err: dev_dbg(&i2c->dev, "%s: failed=%d\n", __func__, ret); + if (priv && priv->i2c_adapter) + i2c_del_mux_adapter(priv->i2c_adapter); kfree(priv); return NULL; } |