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];
+ u8 buf[2], val;
struct i2c_msg msg[1] = {
{
.addr = priv->cfg.i2c_addr,
.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)
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;
}
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)
{
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,
/* 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, NULL);
+ 0, 1, 0, rtl2832_select, rtl2832_deselect);
if (priv->i2c_adapter_tuner == NULL)
goto err;