summaryrefslogtreecommitdiffstats
path: root/drivers/media/dvb/frontends
diff options
context:
space:
mode:
authorAntti Palosaari <crope@iki.fi>2011-08-04 20:27:19 -0300
committerMauro Carvalho Chehab <mchehab@redhat.com>2012-02-28 18:42:23 -0300
commit0485a7089b8d6c11fe2db1123a1ed39a2676592f (patch)
tree261da4a1082977e6ea3fdcfd668995764cb3fd98 /drivers/media/dvb/frontends
parent34ec2933485b6b047245ccbb7fa2b3513bed46af (diff)
[media] rtl2830: correct I2C functionality
Implement I2C functionality according to real RTL2830 demod. Do not send register page in first byte of each I2C write, instead use logic to set page using own write when needed. Page register is physical register 0 as generally used. Signed-off-by: Antti Palosaari <crope@iki.fi> Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com>
Diffstat (limited to 'drivers/media/dvb/frontends')
-rw-r--r--drivers/media/dvb/frontends/rtl2830.c67
-rw-r--r--drivers/media/dvb/frontends/rtl2830_priv.h2
2 files changed, 52 insertions, 17 deletions
diff --git a/drivers/media/dvb/frontends/rtl2830.c b/drivers/media/dvb/frontends/rtl2830.c
index 37a9fa29874..f036701c12e 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 = &reg,
}, {
.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 2bc662ee87a..49de01dd5e8 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 {