[media] rtl2832: convert to regmap API
authorAntti Palosaari <crope@iki.fi>
Sun, 14 Dec 2014 07:45:57 +0000 (04:45 -0300)
committerMauro Carvalho Chehab <mchehab@osg.samsung.com>
Tue, 3 Feb 2015 18:05:33 +0000 (16:05 -0200)
Use regmap to cover register access routines.

Signed-off-by: Antti Palosaari <crope@iki.fi>
Signed-off-by: Mauro Carvalho Chehab <mchehab@osg.samsung.com>
drivers/media/dvb-frontends/Kconfig
drivers/media/dvb-frontends/rtl2832.c
drivers/media/dvb-frontends/rtl2832_priv.h

index 0e1263456922484c3b29ecc0d70d2e6793196cda..bb76727d924ebd0931bedf2940e8cee3143a67a5 100644 (file)
@@ -452,6 +452,7 @@ config DVB_RTL2830
 config DVB_RTL2832
        tristate "Realtek RTL2832 DVB-T"
        depends on DVB_CORE && I2C && I2C_MUX
+       select REGMAP
        default m if !MEDIA_SUBDRV_AUTOSELECT
        help
          Say Y when you want to support this frontend.
index 31240bbce8ff25a2ddaf18a7475390b681c27c55..5d7ea23f02f70b6f87e8f5f14df8dae638d94d03 100644 (file)
@@ -22,8 +22,6 @@
 #include "dvb_math.h"
 #include <linux/bitops.h>
 
-/* Max transfer size done by I2C transfer functions */
-#define MAX_XFER_SIZE  64
 #define REG_MASK(b) (BIT(b + 1) - 1)
 
 static const struct rtl2832_reg_entry registers[] = {
@@ -156,103 +154,53 @@ static const struct rtl2832_reg_entry registers[] = {
        [DVBT_REG_4MSEL]        = {0x0, 0x13,  0, 0},
 };
 
-/* write multiple hardware registers */
-static int rtl2832_wr(struct rtl2832_dev *dev, u8 reg, u8 *val, int len)
+/* Our regmap is bypassing I2C adapter lock, thus we do it! */
+int rtl2832_bulk_write(struct i2c_client *client, unsigned int reg,
+                      const void *val, size_t val_count)
 {
-       struct i2c_client *client = dev->client;
+       struct rtl2832_dev *dev = i2c_get_clientdata(client);
        int ret;
-       u8 buf[MAX_XFER_SIZE];
-       struct i2c_msg msg[1] = {
-               {
-                       .addr = client->addr,
-                       .flags = 0,
-                       .len = 1 + len,
-                       .buf = buf,
-               }
-       };
 
-       if (1 + len > sizeof(buf)) {
-               dev_warn(&client->dev, "i2c wr reg=%04x: len=%d is too big!\n",
-                        reg, len);
-               return -EINVAL;
-       }
-
-       buf[0] = reg;
-       memcpy(&buf[1], val, len);
-
-       ret = i2c_transfer(dev->i2c_adapter, msg, 1);
-       if (ret == 1) {
-               ret = 0;
-       } else {
-               dev_warn(&client->dev, "i2c wr failed=%d reg=%02x len=%d\n",
-                        ret, reg, len);
-               ret = -EREMOTEIO;
-       }
+       i2c_lock_adapter(client->adapter);
+       ret = regmap_bulk_write(dev->regmap, reg, val, val_count);
+       i2c_unlock_adapter(client->adapter);
        return ret;
 }
 
-/* read multiple hardware registers */
-static int rtl2832_rd(struct rtl2832_dev *dev, u8 reg, u8 *val, int len)
+int rtl2832_update_bits(struct i2c_client *client, unsigned int reg,
+                       unsigned int mask, unsigned int val)
 {
-       struct i2c_client *client = dev->client;
+       struct rtl2832_dev *dev = i2c_get_clientdata(client);
        int ret;
-       struct i2c_msg msg[2] = {
-               {
-                       .addr = client->addr,
-                       .flags = 0,
-                       .len = 1,
-                       .buf = &reg,
-               }, {
-                       .addr = client->addr,
-                       .flags = I2C_M_RD,
-                       .len = len,
-                       .buf = val,
-               }
-       };
 
-       ret = i2c_transfer(dev->i2c_adapter, msg, 2);
-       if (ret == 2) {
-               ret = 0;
-       } else {
-               dev_warn(&client->dev, "i2c rd failed=%d reg=%02x len=%d\n",
-                        ret, reg, len);
-               ret = -EREMOTEIO;
-       }
+       i2c_lock_adapter(client->adapter);
+       ret = regmap_update_bits(dev->regmap, reg, mask, val);
+       i2c_unlock_adapter(client->adapter);
        return ret;
 }
 
-/* write multiple registers */
-static int rtl2832_wr_regs(struct rtl2832_dev *dev, u8 reg, u8 page, u8 *val,
-       int len)
+int rtl2832_bulk_read(struct i2c_client *client, unsigned int reg, void *val,
+                     size_t val_count)
 {
+       struct rtl2832_dev *dev = i2c_get_clientdata(client);
        int ret;
 
-       /* switch bank if needed */
-       if (page != dev->page) {
-               ret = rtl2832_wr(dev, 0x00, &page, 1);
-               if (ret)
-                       return ret;
+       i2c_lock_adapter(client->adapter);
+       ret = regmap_bulk_read(dev->regmap, reg, val, val_count);
+       i2c_unlock_adapter(client->adapter);
+       return ret;
+}
 
-               dev->page = page;
-       }
-       return rtl2832_wr(dev, reg, val, len);
+/* write multiple registers */
+static int rtl2832_wr_regs(struct rtl2832_dev *dev, u8 reg, u8 page, u8 *val, int len)
+{
+       return rtl2832_bulk_write(dev->client, page << 8 | reg, val, len);
 }
 
 /* read multiple registers */
-static int rtl2832_rd_regs(struct rtl2832_dev *dev, u8 reg, u8 page, u8 *val,
-       int len)
+static int rtl2832_rd_regs(struct rtl2832_dev *dev, u8 reg, u8 page, u8 *val, int len)
 {
-       int ret;
-
-       /* switch bank if needed */
-       if (page != dev->page) {
-               ret = rtl2832_wr(dev, 0x00, &page, 1);
-               if (ret)
-                       return ret;
-
-               dev->page = page;
-       }
-       return rtl2832_rd(dev, reg, val, len);
+       return rtl2832_bulk_read(dev->client, page << 8 | reg, val, len);
 }
 
 /* write single register */
@@ -385,7 +333,6 @@ err:
        return ret;
 }
 
-
 static int rtl2832_set_if(struct dvb_frontend *fe, u32 if_freq)
 {
        struct rtl2832_dev *dev = fe->demodulator_priv;
@@ -897,44 +844,22 @@ err:
 }
 
 /*
- * 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
+ * I2C gate/mux/repeater logic
+ * We must use unlocked __i2c_transfer() here (through regmap) because of I2C
+ * adapter lock is already taken by tuner driver.
+ * There is 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_dev *dev = container_of(work,
-                       struct rtl2832_dev, i2c_gate_work.work);
+       struct rtl2832_dev *dev = container_of(work, struct rtl2832_dev, i2c_gate_work.work);
        struct i2c_client *client = dev->client;
        int ret;
-       u8 buf[2];
-       struct i2c_msg msg[1] = {
-               {
-                       .addr = client->addr,
-                       .flags = 0,
-                       .len = sizeof(buf),
-                       .buf = buf,
-               }
-       };
-
-       dev_dbg(&client->dev, "\n");
 
-       /* select reg bank 1 */
-       buf[0] = 0x00;
-       buf[1] = 0x01;
-       ret = __i2c_transfer(client->adapter, msg, 1);
-       if (ret != 1)
-               goto err;
-
-       dev->page = 1;
-
-       /* close I2C repeater gate */
-       buf[0] = 0x01;
-       buf[1] = 0x10;
-       ret = __i2c_transfer(client->adapter, msg, 1);
-       if (ret != 1)
+       /* close gate */
+       ret = rtl2832_update_bits(dev->client, 0x101, 0x08, 0x00);
+       if (ret)
                goto err;
 
        dev->i2c_gate_state = false;
@@ -950,58 +875,24 @@ static int rtl2832_select(struct i2c_adapter *adap, void *mux_priv, u32 chan_id)
        struct rtl2832_dev *dev = mux_priv;
        struct i2c_client *client = dev->client;
        int ret;
-       u8 buf[2], val;
-       struct i2c_msg msg[1] = {
-               {
-                       .addr = client->addr,
-                       .flags = 0,
-                       .len = sizeof(buf),
-                       .buf = buf,
-               }
-       };
-       struct i2c_msg msg_rd[2] = {
-               {
-                       .addr = client->addr,
-                       .flags = 0,
-                       .len = 1,
-                       .buf = "\x01",
-               }, {
-                       .addr = client->addr,
-                       .flags = I2C_M_RD,
-                       .len = 1,
-                       .buf = &val,
-               }
-       };
 
        /* terminate possible gate closing */
-       cancel_delayed_work_sync(&dev->i2c_gate_work);
+       cancel_delayed_work(&dev->i2c_gate_work);
 
        if (dev->i2c_gate_state == chan_id)
                return 0;
 
-       /* select reg bank 1 */
-       buf[0] = 0x00;
-       buf[1] = 0x01;
-       ret = __i2c_transfer(client->adapter, msg, 1);
-       if (ret != 1)
-               goto err;
-
-       dev->page = 1;
-
-       /* we must read that register, otherwise there will be errors */
-       ret = __i2c_transfer(client->adapter, msg_rd, 2);
-       if (ret != 2)
-               goto err;
-
-       /* open or close I2C repeater gate */
-       buf[0] = 0x01;
+       /*
+        * chan_id 1 is muxed adapter demod provides and chan_id 0 is demod
+        * itself. We need open gate when request is for chan_id 1. On that case
+        * I2C adapter lock is already taken and due to that we will use
+        * regmap_update_bits() which does not lock again I2C adapter.
+        */
        if (chan_id == 1)
-               buf[1] = 0x18; /* open */
+               ret = regmap_update_bits(dev->regmap, 0x101, 0x08, 0x08);
        else
-               buf[1] = 0x10; /* close */
-
-       ret = __i2c_transfer(client->adapter, msg, 1);
-       if (ret != 1)
+               ret = rtl2832_update_bits(dev->client, 0x101, 0x08, 0x00);
+       if (ret)
                goto err;
 
        dev->i2c_gate_state = chan_id;
@@ -1009,11 +900,11 @@ static int rtl2832_select(struct i2c_adapter *adap, void *mux_priv, u32 chan_id)
        return 0;
 err:
        dev_dbg(&client->dev, "failed=%d\n", ret);
-       return -EREMOTEIO;
+       return ret;
 }
 
 static int rtl2832_deselect(struct i2c_adapter *adap, void *mux_priv,
-               u32 chan_id)
+                           u32 chan_id)
 {
        struct rtl2832_dev *dev = mux_priv;
 
@@ -1060,6 +951,91 @@ static struct dvb_frontend_ops rtl2832_ops = {
        .i2c_gate_ctrl = rtl2832_i2c_gate_ctrl,
 };
 
+/*
+ * We implement own I2C access routines for regmap in order to get manual access
+ * to I2C adapter lock, which is needed for I2C mux adapter.
+ */
+static int rtl2832_regmap_read(void *context, const void *reg_buf,
+                              size_t reg_size, void *val_buf, size_t val_size)
+{
+       struct i2c_client *client = context;
+       int ret;
+       struct i2c_msg msg[2] = {
+               {
+                       .addr = client->addr,
+                       .flags = 0,
+                       .len = reg_size,
+                       .buf = (u8 *)reg_buf,
+               }, {
+                       .addr = client->addr,
+                       .flags = I2C_M_RD,
+                       .len = val_size,
+                       .buf = val_buf,
+               }
+       };
+
+       ret = __i2c_transfer(client->adapter, msg, 2);
+       if (ret != 2) {
+               dev_warn(&client->dev, "i2c reg read failed %d\n", ret);
+               if (ret >= 0)
+                       ret = -EREMOTEIO;
+               return ret;
+       }
+       return 0;
+}
+
+static int rtl2832_regmap_write(void *context, const void *data, size_t count)
+{
+       struct i2c_client *client = context;
+       int ret;
+       struct i2c_msg msg[1] = {
+               {
+                       .addr = client->addr,
+                       .flags = 0,
+                       .len = count,
+                       .buf = (u8 *)data,
+               }
+       };
+
+       ret = __i2c_transfer(client->adapter, msg, 1);
+       if (ret != 1) {
+               dev_warn(&client->dev, "i2c reg write failed %d\n", ret);
+               if (ret >= 0)
+                       ret = -EREMOTEIO;
+               return ret;
+       }
+       return 0;
+}
+
+static int rtl2832_regmap_gather_write(void *context, const void *reg,
+                                      size_t reg_len, const void *val,
+                                      size_t val_len)
+{
+       struct i2c_client *client = context;
+       int ret;
+       u8 buf[256];
+       struct i2c_msg msg[1] = {
+               {
+                       .addr = client->addr,
+                       .flags = 0,
+                       .len = 1 + val_len,
+                       .buf = buf,
+               }
+       };
+
+       buf[0] = *(u8 const *)reg;
+       memcpy(&buf[1], val, val_len);
+
+       ret = __i2c_transfer(client->adapter, msg, 1);
+       if (ret != 1) {
+               dev_warn(&client->dev, "i2c reg write failed %d\n", ret);
+               if (ret >= 0)
+                       ret = -EREMOTEIO;
+               return ret;
+       }
+       return 0;
+}
+
 static struct dvb_frontend *rtl2832_get_dvb_frontend(struct i2c_client *client)
 {
        struct rtl2832_dev *dev = i2c_get_clientdata(client);
@@ -1142,6 +1118,30 @@ static int rtl2832_probe(struct i2c_client *client,
        struct rtl2832_dev *dev;
        int ret;
        u8 tmp;
+       static const struct regmap_bus regmap_bus = {
+               .read = rtl2832_regmap_read,
+               .write = rtl2832_regmap_write,
+               .gather_write = rtl2832_regmap_gather_write,
+               .val_format_endian_default = REGMAP_ENDIAN_NATIVE,
+       };
+       static const struct regmap_range_cfg regmap_range_cfg[] = {
+               {
+                       .selector_reg     = 0x00,
+                       .selector_mask    = 0xff,
+                       .selector_shift   = 0,
+                       .window_start     = 0,
+                       .window_len       = 0x100,
+                       .range_min        = 0 * 0x100,
+                       .range_max        = 5 * 0x100,
+               },
+       };
+       static const struct regmap_config regmap_config = {
+               .reg_bits    =  8,
+               .val_bits    =  8,
+               .max_register = 5 * 0x100,
+               .ranges = regmap_range_cfg,
+               .num_ranges = ARRAY_SIZE(regmap_range_cfg),
+       };
 
        dev_dbg(&client->dev, "\n");
 
@@ -1153,6 +1153,7 @@ static int rtl2832_probe(struct i2c_client *client,
        }
 
        /* setup the state */
+       i2c_set_clientdata(client, dev);
        dev->client = client;
        dev->pdata = client->dev.platform_data;
        if (pdata->config) {
@@ -1161,12 +1162,19 @@ static int rtl2832_probe(struct i2c_client *client,
        }
        dev->sleeping = true;
        INIT_DELAYED_WORK(&dev->i2c_gate_work, rtl2832_i2c_gate_work);
+       /* create regmap */
+       dev->regmap = regmap_init(&client->dev, &regmap_bus, client,
+                                 &regmap_config);
+       if (IS_ERR(dev->regmap)) {
+               ret = PTR_ERR(dev->regmap);
+               goto err_kfree;
+       }
        /* create muxed i2c adapter for demod itself */
        dev->i2c_adapter = i2c_add_mux_adapter(i2c, &i2c->dev, dev, 0, 0, 0,
                        rtl2832_select, NULL);
        if (dev->i2c_adapter == NULL) {
                ret = -ENODEV;
-               goto err_kfree;
+               goto err_regmap_exit;
        }
 
        /* check if the demod is there */
@@ -1185,7 +1193,6 @@ static int rtl2832_probe(struct i2c_client *client,
        /* create dvb_frontend */
        memcpy(&dev->fe.ops, &rtl2832_ops, sizeof(struct dvb_frontend_ops));
        dev->fe.demodulator_priv = dev;
-       i2c_set_clientdata(client, dev);
 
        /* setup callbacks */
        pdata->get_dvb_frontend = rtl2832_get_dvb_frontend;
@@ -1197,6 +1204,8 @@ static int rtl2832_probe(struct i2c_client *client,
        return 0;
 err_i2c_del_mux_adapter:
        i2c_del_mux_adapter(dev->i2c_adapter);
+err_regmap_exit:
+       regmap_exit(dev->regmap);
 err_kfree:
        kfree(dev);
 err:
@@ -1216,6 +1225,8 @@ static int rtl2832_remove(struct i2c_client *client)
 
        i2c_del_mux_adapter(dev->i2c_adapter);
 
+       regmap_exit(dev->regmap);
+
        kfree(dev);
 
        return 0;
index 899533241925270e4c74bde09a32d7d5c554c8a2..eacd4e4d8ea38fa570f97c2ec671940c94d0a42c 100644 (file)
 #include "dvb_frontend.h"
 #include "rtl2832.h"
 #include <linux/i2c-mux.h>
+#include <linux/regmap.h>
 
 struct rtl2832_dev {
        struct rtl2832_platform_data *pdata;
        struct i2c_client *client;
+       struct regmap *regmap;
        struct i2c_adapter *i2c_adapter;
        struct i2c_adapter *i2c_adapter_tuner;
        struct dvb_frontend fe;
 
        bool i2c_gate_state;
        bool sleeping;
-
-       u8 page; /* active register page */
        struct delayed_work i2c_gate_work;
 };