diff --git a/drivers/media/dvb/frontends/rtl2830.c b/drivers/media/dvb/frontends/rtl2830.c index 37a9fa29874e..f036701c12ee 100644 --- a/drivers/media/dvb/frontends/rtl2830.c +++ b/drivers/media/dvb/frontends/rtl2830.c @@ -31,45 +31,43 @@ int rtl2830_debug; module_param_named(debug, rtl2830_debug, int, 0644); MODULE_PARM_DESC(debug, "Turn on/off frontend debugging (default:off)."); -/* write multiple registers */ -static int rtl2830_wr_regs(struct rtl2830_priv *priv, u16 reg, u8 *val, int len) +/* write multiple hardware registers */ +static int rtl2830_wr(struct rtl2830_priv *priv, u8 reg, u8 *val, int len) { int ret; - u8 buf[2+len]; + u8 buf[1+len]; struct i2c_msg msg[1] = { { .addr = priv->cfg.i2c_addr, .flags = 0, - .len = sizeof(buf), + .len = 1+len, .buf = buf, } }; - buf[0] = (reg >> 8) & 0xff; - buf[1] = (reg >> 0) & 0xff; - memcpy(&buf[2], val, len); + buf[0] = reg; + memcpy(&buf[1], val, len); ret = i2c_transfer(priv->i2c, msg, 1); if (ret == 1) { ret = 0; } else { - warn("i2c wr failed=%d reg=%04x len=%d", ret, reg, len); + warn("i2c wr failed=%d reg=%02x len=%d", ret, reg, len); ret = -EREMOTEIO; } return ret; } -/* read multiple registers */ -static int rtl2830_rd_regs(struct rtl2830_priv *priv, u16 reg, u8 *val, int len) +/* read multiple hardware registers */ +static int rtl2830_rd(struct rtl2830_priv *priv, u8 reg, u8 *val, int len) { int ret; - u8 buf[2]; struct i2c_msg msg[2] = { { .addr = priv->cfg.i2c_addr, .flags = 0, - .len = sizeof(buf), - .buf = buf, + .len = 1, + .buf = ®, }, { .addr = priv->cfg.i2c_addr, .flags = I2C_M_RD, @@ -78,19 +76,54 @@ static int rtl2830_rd_regs(struct rtl2830_priv *priv, u16 reg, u8 *val, int len) } }; - buf[0] = (reg >> 8) & 0xff; - buf[1] = (reg >> 0) & 0xff; - ret = i2c_transfer(priv->i2c, msg, 2); if (ret == 2) { ret = 0; } else { - warn("i2c rd failed=%d reg=%04x len=%d", ret, reg, len); + warn("i2c rd failed=%d reg=%02x len=%d", ret, reg, len); ret = -EREMOTEIO; } return ret; } +/* write multiple registers */ +static int rtl2830_wr_regs(struct rtl2830_priv *priv, u16 reg, u8 *val, int len) +{ + int ret; + u8 reg2 = (reg >> 0) & 0xff; + u8 page = (reg >> 8) & 0xff; + + /* switch bank if needed */ + if (page != priv->page) { + ret = rtl2830_wr(priv, 0x00, &page, 1); + if (ret) + return ret; + + priv->page = page; + } + + return rtl2830_wr(priv, reg2, val, len); +} + +/* read multiple registers */ +static int rtl2830_rd_regs(struct rtl2830_priv *priv, u16 reg, u8 *val, int len) +{ + int ret; + u8 reg2 = (reg >> 0) & 0xff; + u8 page = (reg >> 8) & 0xff; + + /* switch bank if needed */ + if (page != priv->page) { + ret = rtl2830_wr(priv, 0x00, &page, 1); + if (ret) + return ret; + + priv->page = page; + } + + return rtl2830_rd(priv, reg2, val, len); +} + #if 0 /* currently not used */ /* write single register */ static int rtl2830_wr_reg(struct rtl2830_priv *priv, u16 reg, u8 val) diff --git a/drivers/media/dvb/frontends/rtl2830_priv.h b/drivers/media/dvb/frontends/rtl2830_priv.h index 2bc662ee87a0..49de01dd5e83 100644 --- a/drivers/media/dvb/frontends/rtl2830_priv.h +++ b/drivers/media/dvb/frontends/rtl2830_priv.h @@ -42,6 +42,8 @@ struct rtl2830_priv { struct dvb_frontend fe; struct rtl2830_config cfg; struct i2c_adapter tuner_i2c_adapter; + + u8 page; /* active register page */ }; struct rtl2830_reg_val_mask {