]> git.proxmox.com Git - mirror_ubuntu-hirsute-kernel.git/commitdiff
i2c: designware: Convert driver to using regmap API
authorSerge Semin <Sergey.Semin@baikalelectronics.ru>
Thu, 28 May 2020 09:33:18 +0000 (12:33 +0300)
committerWolfram Sang <wsa@kernel.org>
Sat, 30 May 2020 21:02:22 +0000 (23:02 +0200)
Seeing the DW I2C driver is using flags-based accessors with two
conditional clauses it would be better to replace them with the regmap
API IO methods and to initialize the regmap object with read/write
callbacks specific to the controller registers map implementation. This
will be also handy for the drivers with non-standard registers mapping
(like an embedded into the Baikal-T1 System Controller DW I2C block, which
glue-driver is a part of this series).

As before the driver tries to detect the mapping setup at probe stage and
creates a regmap object accordingly, which will be used by the rest of the
code to correctly access the controller registers. In two places it was
appropriate to convert the hand-written read-modify-write and
read-poll-loop design patterns to the corresponding regmap API
ready-to-use methods.

Note the regmap IO methods return value is checked only at the probe
stage. The rest of the code won't do this because basically we have
MMIO-based regmap so non of the read/write methods can fail (this also
won't be needed for the Baikal-T1-specific I2C controller).

Suggested-by: Andy Shevchenko <andriy.shevchenko@linux.intel.com>
Signed-off-by: Serge Semin <Sergey.Semin@baikalelectronics.ru>
Tested-by: Jarkko Nikula <jarkko.nikula@linux.intel.com>
Acked-by: Jarkko Nikula <jarkko.nikula@linux.intel.com>
Reviewed-by: Andy Shevchenko <andriy.shevchenko@linux.intel.com>
[wsa: fix type of 'rx_valid' and remove outdated kdoc var description]
Signed-off-by: Wolfram Sang <wsa@kernel.org>
drivers/i2c/busses/Kconfig
drivers/i2c/busses/i2c-designware-common.c
drivers/i2c/busses/i2c-designware-core.h
drivers/i2c/busses/i2c-designware-master.c
drivers/i2c/busses/i2c-designware-slave.c

index 6a6fadfc3f930a160ecd68be26d3e4e6e6df96d3..c748beaaa8903912b77cd1509edfce88c79471ff 100644 (file)
@@ -526,6 +526,7 @@ config I2C_DAVINCI
 
 config I2C_DESIGNWARE_CORE
        tristate
+       select REGMAP
 
 config I2C_DESIGNWARE_SLAVE
        bool "Synopsys DesignWare Slave"
index ed302342f8db104d82575544afbe33f366636b9c..e3a8640db7da1ebafcac7a00aaeea8dab672d5d5 100644 (file)
@@ -21,6 +21,7 @@
 #include <linux/kernel.h>
 #include <linux/module.h>
 #include <linux/pm_runtime.h>
+#include <linux/regmap.h>
 #include <linux/swab.h>
 #include <linux/types.h>
 
@@ -57,66 +58,122 @@ static char *abort_sources[] = {
                "incorrect slave-transmitter mode configuration",
 };
 
-u32 dw_readl(struct dw_i2c_dev *dev, int offset)
+static int dw_reg_read(void *context, unsigned int reg, unsigned int *val)
 {
-       u32 value;
+       struct dw_i2c_dev *dev = context;
 
-       if (dev->flags & ACCESS_16BIT)
-               value = readw_relaxed(dev->base + offset) |
-                       (readw_relaxed(dev->base + offset + 2) << 16);
-       else
-               value = readl_relaxed(dev->base + offset);
+       *val = readl_relaxed(dev->base + reg);
 
-       if (dev->flags & ACCESS_SWAP)
-               return swab32(value);
-       else
-               return value;
+       return 0;
 }
 
-void dw_writel(struct dw_i2c_dev *dev, u32 b, int offset)
+static int dw_reg_write(void *context, unsigned int reg, unsigned int val)
 {
-       if (dev->flags & ACCESS_SWAP)
-               b = swab32(b);
-
-       if (dev->flags & ACCESS_16BIT) {
-               writew_relaxed((u16)b, dev->base + offset);
-               writew_relaxed((u16)(b >> 16), dev->base + offset + 2);
-       } else {
-               writel_relaxed(b, dev->base + offset);
-       }
+       struct dw_i2c_dev *dev = context;
+
+       writel_relaxed(val, dev->base + reg);
+
+       return 0;
+}
+
+static int dw_reg_read_swab(void *context, unsigned int reg, unsigned int *val)
+{
+       struct dw_i2c_dev *dev = context;
+
+       *val = swab32(readl_relaxed(dev->base + reg));
+
+       return 0;
+}
+
+static int dw_reg_write_swab(void *context, unsigned int reg, unsigned int val)
+{
+       struct dw_i2c_dev *dev = context;
+
+       writel_relaxed(swab32(val), dev->base + reg);
+
+       return 0;
+}
+
+static int dw_reg_read_word(void *context, unsigned int reg, unsigned int *val)
+{
+       struct dw_i2c_dev *dev = context;
+
+       *val = readw_relaxed(dev->base + reg) |
+               (readw_relaxed(dev->base + reg + 2) << 16);
+
+       return 0;
+}
+
+static int dw_reg_write_word(void *context, unsigned int reg, unsigned int val)
+{
+       struct dw_i2c_dev *dev = context;
+
+       writew_relaxed(val, dev->base + reg);
+       writew_relaxed(val >> 16, dev->base + reg + 2);
+
+       return 0;
 }
 
 /**
- * i2c_dw_set_reg_access() - Set register access flags
+ * i2c_dw_init_regmap() - Initialize registers map
  * @dev: device private data
  *
- * Autodetects needed register access mode and sets access flags accordingly.
- * This must be called before doing any other register access.
+ * Autodetects needed register access mode and creates the regmap with
+ * corresponding read/write callbacks. This must be called before doing any
+ * other register access.
  */
-int i2c_dw_set_reg_access(struct dw_i2c_dev *dev)
+int i2c_dw_init_regmap(struct dw_i2c_dev *dev)
 {
+       struct regmap_config map_cfg = {
+               .reg_bits = 32,
+               .val_bits = 32,
+               .reg_stride = 4,
+               .disable_locking = true,
+               .reg_read = dw_reg_read,
+               .reg_write = dw_reg_write,
+               .max_register = DW_IC_COMP_TYPE,
+       };
        u32 reg;
        int ret;
 
+       /*
+        * Skip detecting the registers map configuration if the regmap has
+        * already been provided by a higher code.
+        */
+       if (dev->map)
+               return 0;
+
        ret = i2c_dw_acquire_lock(dev);
        if (ret)
                return ret;
 
-       reg = dw_readl(dev, DW_IC_COMP_TYPE);
+       reg = readl(dev->base + DW_IC_COMP_TYPE);
        i2c_dw_release_lock(dev);
 
        if (reg == swab32(DW_IC_COMP_TYPE_VALUE)) {
-               /* Configure register endianness access */
-               dev->flags |= ACCESS_SWAP;
+               map_cfg.reg_read = dw_reg_read_swab;
+               map_cfg.reg_write = dw_reg_write_swab;
        } else if (reg == (DW_IC_COMP_TYPE_VALUE & 0x0000ffff)) {
-               /* Configure register access mode 16bit */
-               dev->flags |= ACCESS_16BIT;
+               map_cfg.reg_read = dw_reg_read_word;
+               map_cfg.reg_write = dw_reg_write_word;
        } else if (reg != DW_IC_COMP_TYPE_VALUE) {
                dev_err(dev->dev,
                        "Unknown Synopsys component type: 0x%08x\n", reg);
                return -ENODEV;
        }
 
+       /*
+        * Note we'll check the return value of the regmap IO accessors only
+        * at the probe stage. The rest of the code won't do this because
+        * basically we have MMIO-based regmap so non of the read/write methods
+        * can fail.
+        */
+       dev->map = devm_regmap_init(dev->dev, NULL, dev, &map_cfg);
+       if (IS_ERR(dev->map)) {
+               dev_err(dev->dev, "Failed to init the registers map\n");
+               return PTR_ERR(dev->map);
+       }
+
        return 0;
 }
 
@@ -327,11 +384,17 @@ int i2c_dw_set_sda_hold(struct dw_i2c_dev *dev)
                return ret;
 
        /* Configure SDA Hold Time if required */
-       reg = dw_readl(dev, DW_IC_COMP_VERSION);
+       ret = regmap_read(dev->map, DW_IC_COMP_VERSION, &reg);
+       if (ret)
+               goto err_release_lock;
+
        if (reg >= DW_IC_SDA_HOLD_MIN_VERS) {
                if (!dev->sda_hold_time) {
                        /* Keep previous hold time setting if no one set it */
-                       dev->sda_hold_time = dw_readl(dev, DW_IC_SDA_HOLD);
+                       ret = regmap_read(dev->map, DW_IC_SDA_HOLD,
+                                         &dev->sda_hold_time);
+                       if (ret)
+                               goto err_release_lock;
                }
 
                /*
@@ -355,14 +418,16 @@ int i2c_dw_set_sda_hold(struct dw_i2c_dev *dev)
                dev->sda_hold_time = 0;
        }
 
+err_release_lock:
        i2c_dw_release_lock(dev);
 
-       return 0;
+       return ret;
 }
 
 void __i2c_dw_disable(struct dw_i2c_dev *dev)
 {
        int timeout = 100;
+       u32 status;
 
        do {
                __i2c_dw_disable_nowait(dev);
@@ -370,7 +435,8 @@ void __i2c_dw_disable(struct dw_i2c_dev *dev)
                 * The enable status register may be unimplemented, but
                 * in that case this test reads zero and exits the loop.
                 */
-               if ((dw_readl(dev, DW_IC_ENABLE_STATUS) & 1) == 0)
+               regmap_read(dev->map, DW_IC_ENABLE_STATUS, &status);
+               if ((status & 1) == 0)
                        return;
 
                /*
@@ -449,22 +515,23 @@ void i2c_dw_release_lock(struct dw_i2c_dev *dev)
  */
 int i2c_dw_wait_bus_not_busy(struct dw_i2c_dev *dev)
 {
-       int timeout = TIMEOUT;
+       u32 status;
+       int ret;
 
-       while (dw_readl(dev, DW_IC_STATUS) & DW_IC_STATUS_ACTIVITY) {
-               if (timeout <= 0) {
-                       dev_warn(dev->dev, "timeout waiting for bus ready\n");
-                       i2c_recover_bus(&dev->adapter);
+       ret = regmap_read_poll_timeout(dev->map, DW_IC_STATUS, status,
+                                      !(status & DW_IC_STATUS_ACTIVITY),
+                                      1100, 20000);
+       if (ret) {
+               dev_warn(dev->dev, "timeout waiting for bus ready\n");
 
-                       if (dw_readl(dev, DW_IC_STATUS) & DW_IC_STATUS_ACTIVITY)
-                               return -ETIMEDOUT;
-                       return 0;
-               }
-               timeout--;
-               usleep_range(1000, 1100);
+               i2c_recover_bus(&dev->adapter);
+
+               regmap_read(dev->map, DW_IC_STATUS, &status);
+               if (!(status & DW_IC_STATUS_ACTIVITY))
+                       ret = 0;
        }
 
-       return 0;
+       return ret;
 }
 
 int i2c_dw_handle_tx_abort(struct dw_i2c_dev *dev)
@@ -490,15 +557,19 @@ int i2c_dw_handle_tx_abort(struct dw_i2c_dev *dev)
                return -EIO;
 }
 
-void i2c_dw_set_fifo_size(struct dw_i2c_dev *dev)
+int i2c_dw_set_fifo_size(struct dw_i2c_dev *dev)
 {
        u32 param, tx_fifo_depth, rx_fifo_depth;
+       int ret;
 
        /*
         * Try to detect the FIFO depth if not set by interface driver,
         * the depth could be from 2 to 256 from HW spec.
         */
-       param = dw_readl(dev, DW_IC_COMP_PARAM_1);
+       ret = regmap_read(dev->map, DW_IC_COMP_PARAM_1, &param);
+       if (ret)
+               return ret;
+
        tx_fifo_depth = ((param >> 16) & 0xff) + 1;
        rx_fifo_depth = ((param >> 8)  & 0xff) + 1;
        if (!dev->tx_fifo_depth) {
@@ -510,6 +581,8 @@ void i2c_dw_set_fifo_size(struct dw_i2c_dev *dev)
                dev->rx_fifo_depth = min_t(u32, dev->rx_fifo_depth,
                                rx_fifo_depth);
        }
+
+       return 0;
 }
 
 u32 i2c_dw_func(struct i2c_adapter *adap)
@@ -521,17 +594,19 @@ u32 i2c_dw_func(struct i2c_adapter *adap)
 
 void i2c_dw_disable(struct dw_i2c_dev *dev)
 {
+       u32 dummy;
+
        /* Disable controller */
        __i2c_dw_disable(dev);
 
        /* Disable all interrupts */
-       dw_writel(dev, 0, DW_IC_INTR_MASK);
-       dw_readl(dev, DW_IC_CLR_INTR);
+       regmap_write(dev->map, DW_IC_INTR_MASK, 0);
+       regmap_read(dev->map, DW_IC_CLR_INTR, &dummy);
 }
 
 void i2c_dw_disable_int(struct dw_i2c_dev *dev)
 {
-       dw_writel(dev, 0, DW_IC_INTR_MASK);
+       regmap_write(dev->map, DW_IC_INTR_MASK, 0);
 }
 
 MODULE_DESCRIPTION("Synopsys DesignWare I2C bus adapter core");
index b9ef9b0deef0d75267800a38714d9d4ef7894182..f5bbe3d6bcf8bab2b0eda1ac6ae6a0efa13825cf 100644 (file)
@@ -15,6 +15,7 @@
 #include <linux/dev_printk.h>
 #include <linux/errno.h>
 #include <linux/i2c.h>
+#include <linux/regmap.h>
 #include <linux/types.h>
 
 #define DW_IC_DEFAULT_FUNCTIONALITY (I2C_FUNC_I2C |                    \
 #define STATUS_WRITE_IN_PROGRESS       0x1
 #define STATUS_READ_IN_PROGRESS                0x2
 
-#define TIMEOUT                        20 /* ms */
-
 /*
  * operation modes
  */
@@ -183,7 +182,9 @@ struct reset_control;
 /**
  * struct dw_i2c_dev - private i2c-designware data
  * @dev: driver model device node
+ * @map: IO registers map
  * @base: IO registers pointer
+ * @ext: Extended IO registers pointer
  * @cmd_complete: tx completion indicator
  * @clk: input reference clock
  * @pclk: clock required to access the registers
@@ -233,6 +234,7 @@ struct reset_control;
  */
 struct dw_i2c_dev {
        struct device           *dev;
+       struct regmap           *map;
        void __iomem            *base;
        void __iomem            *ext;
        struct completion       cmd_complete;
@@ -284,17 +286,13 @@ struct dw_i2c_dev {
        bool                    suspended;
 };
 
-#define ACCESS_SWAP            0x00000001
-#define ACCESS_16BIT           0x00000002
-#define ACCESS_INTR_MASK       0x00000004
-#define ACCESS_NO_IRQ_SUSPEND  0x00000008
+#define ACCESS_INTR_MASK       0x00000001
+#define ACCESS_NO_IRQ_SUSPEND  0x00000002
 
 #define MODEL_MSCC_OCELOT      0x00000100
 #define MODEL_MASK             0x00000f00
 
-u32 dw_readl(struct dw_i2c_dev *dev, int offset);
-void dw_writel(struct dw_i2c_dev *dev, u32 b, int offset);
-int i2c_dw_set_reg_access(struct dw_i2c_dev *dev);
+int i2c_dw_init_regmap(struct dw_i2c_dev *dev);
 u32 i2c_dw_scl_hcnt(u32 ic_clk, u32 tSYMBOL, u32 tf, int cond, int offset);
 u32 i2c_dw_scl_lcnt(u32 ic_clk, u32 tLOW, u32 tf, int offset);
 int i2c_dw_set_sda_hold(struct dw_i2c_dev *dev);
@@ -304,19 +302,19 @@ int i2c_dw_acquire_lock(struct dw_i2c_dev *dev);
 void i2c_dw_release_lock(struct dw_i2c_dev *dev);
 int i2c_dw_wait_bus_not_busy(struct dw_i2c_dev *dev);
 int i2c_dw_handle_tx_abort(struct dw_i2c_dev *dev);
-void i2c_dw_set_fifo_size(struct dw_i2c_dev *dev);
+int i2c_dw_set_fifo_size(struct dw_i2c_dev *dev);
 u32 i2c_dw_func(struct i2c_adapter *adap);
 void i2c_dw_disable(struct dw_i2c_dev *dev);
 void i2c_dw_disable_int(struct dw_i2c_dev *dev);
 
 static inline void __i2c_dw_enable(struct dw_i2c_dev *dev)
 {
-       dw_writel(dev, 1, DW_IC_ENABLE);
+       regmap_write(dev->map, DW_IC_ENABLE, 1);
 }
 
 static inline void __i2c_dw_disable_nowait(struct dw_i2c_dev *dev)
 {
-       dw_writel(dev, 0, DW_IC_ENABLE);
+       regmap_write(dev->map, DW_IC_ENABLE, 0);
 }
 
 void __i2c_dw_disable(struct dw_i2c_dev *dev);
index 95eeec53c744fd300f62a5299b6427418801cf62..d6425ad6e6a38bffaa7bc331cf925e9a4bdf50d1 100644 (file)
@@ -18,6 +18,7 @@
 #include <linux/io.h>
 #include <linux/module.h>
 #include <linux/pm_runtime.h>
+#include <linux/regmap.h>
 #include <linux/reset.h>
 
 #include "i2c-designware-core.h"
 static void i2c_dw_configure_fifo_master(struct dw_i2c_dev *dev)
 {
        /* Configure Tx/Rx FIFO threshold levels */
-       dw_writel(dev, dev->tx_fifo_depth / 2, DW_IC_TX_TL);
-       dw_writel(dev, 0, DW_IC_RX_TL);
+       regmap_write(dev->map, DW_IC_TX_TL, dev->tx_fifo_depth / 2);
+       regmap_write(dev->map, DW_IC_RX_TL, 0);
 
        /* Configure the I2C master */
-       dw_writel(dev, dev->master_cfg, DW_IC_CON);
+       regmap_write(dev->map, DW_IC_CON, dev->master_cfg);
 }
 
 static int i2c_dw_set_timings_master(struct dw_i2c_dev *dev)
@@ -44,8 +45,11 @@ static int i2c_dw_set_timings_master(struct dw_i2c_dev *dev)
        ret = i2c_dw_acquire_lock(dev);
        if (ret)
                return ret;
-       comp_param1 = dw_readl(dev, DW_IC_COMP_PARAM_1);
+
+       ret = regmap_read(dev->map, DW_IC_COMP_PARAM_1, &comp_param1);
        i2c_dw_release_lock(dev);
+       if (ret)
+               return ret;
 
        /* Set standard and fast speed dividers for high/low periods */
        sda_falling_time = t->sda_fall_ns ?: 300; /* ns */
@@ -187,22 +191,22 @@ static int i2c_dw_init_master(struct dw_i2c_dev *dev)
        __i2c_dw_disable(dev);
 
        /* Write standard speed timing parameters */
-       dw_writel(dev, dev->ss_hcnt, DW_IC_SS_SCL_HCNT);
-       dw_writel(dev, dev->ss_lcnt, DW_IC_SS_SCL_LCNT);
+       regmap_write(dev->map, DW_IC_SS_SCL_HCNT, dev->ss_hcnt);
+       regmap_write(dev->map, DW_IC_SS_SCL_LCNT, dev->ss_lcnt);
 
        /* Write fast mode/fast mode plus timing parameters */
-       dw_writel(dev, dev->fs_hcnt, DW_IC_FS_SCL_HCNT);
-       dw_writel(dev, dev->fs_lcnt, DW_IC_FS_SCL_LCNT);
+       regmap_write(dev->map, DW_IC_FS_SCL_HCNT, dev->fs_hcnt);
+       regmap_write(dev->map, DW_IC_FS_SCL_LCNT, dev->fs_lcnt);
 
        /* Write high speed timing parameters if supported */
        if (dev->hs_hcnt && dev->hs_lcnt) {
-               dw_writel(dev, dev->hs_hcnt, DW_IC_HS_SCL_HCNT);
-               dw_writel(dev, dev->hs_lcnt, DW_IC_HS_SCL_LCNT);
+               regmap_write(dev->map, DW_IC_HS_SCL_HCNT, dev->hs_hcnt);
+               regmap_write(dev->map, DW_IC_HS_SCL_LCNT, dev->hs_lcnt);
        }
 
        /* Write SDA hold time if supported */
        if (dev->sda_hold_time)
-               dw_writel(dev, dev->sda_hold_time, DW_IC_SDA_HOLD);
+               regmap_write(dev->map, DW_IC_SDA_HOLD, dev->sda_hold_time);
 
        i2c_dw_configure_fifo_master(dev);
        i2c_dw_release_lock(dev);
@@ -213,15 +217,15 @@ static int i2c_dw_init_master(struct dw_i2c_dev *dev)
 static void i2c_dw_xfer_init(struct dw_i2c_dev *dev)
 {
        struct i2c_msg *msgs = dev->msgs;
-       u32 ic_con, ic_tar = 0;
+       u32 ic_con = 0, ic_tar = 0;
+       u32 dummy;
 
        /* Disable the adapter */
        __i2c_dw_disable(dev);
 
        /* If the slave address is ten bit address, enable 10BITADDR */
-       ic_con = dw_readl(dev, DW_IC_CON);
        if (msgs[dev->msg_write_idx].flags & I2C_M_TEN) {
-               ic_con |= DW_IC_CON_10BITADDR_MASTER;
+               ic_con = DW_IC_CON_10BITADDR_MASTER;
                /*
                 * If I2C_DYNAMIC_TAR_UPDATE is set, the 10-bit addressing
                 * mode has to be enabled via bit 12 of IC_TAR register.
@@ -229,17 +233,17 @@ static void i2c_dw_xfer_init(struct dw_i2c_dev *dev)
                 * detected from registers.
                 */
                ic_tar = DW_IC_TAR_10BITADDR_MASTER;
-       } else {
-               ic_con &= ~DW_IC_CON_10BITADDR_MASTER;
        }
 
-       dw_writel(dev, ic_con, DW_IC_CON);
+       regmap_update_bits(dev->map, DW_IC_CON, DW_IC_CON_10BITADDR_MASTER,
+                          ic_con);
 
        /*
         * Set the slave (target) address and enable 10-bit addressing mode
         * if applicable.
         */
-       dw_writel(dev, msgs[dev->msg_write_idx].addr | ic_tar, DW_IC_TAR);
+       regmap_write(dev->map, DW_IC_TAR,
+                    msgs[dev->msg_write_idx].addr | ic_tar);
 
        /* Enforce disabled interrupts (due to HW issues) */
        i2c_dw_disable_int(dev);
@@ -248,11 +252,11 @@ static void i2c_dw_xfer_init(struct dw_i2c_dev *dev)
        __i2c_dw_enable(dev);
 
        /* Dummy read to avoid the register getting stuck on Bay Trail */
-       dw_readl(dev, DW_IC_ENABLE_STATUS);
+       regmap_read(dev->map, DW_IC_ENABLE_STATUS, &dummy);
 
        /* Clear and enable interrupts */
-       dw_readl(dev, DW_IC_CLR_INTR);
-       dw_writel(dev, DW_IC_INTR_MASTER_MASK, DW_IC_INTR_MASK);
+       regmap_read(dev->map, DW_IC_CLR_INTR, &dummy);
+       regmap_write(dev->map, DW_IC_INTR_MASK, DW_IC_INTR_MASTER_MASK);
 }
 
 /*
@@ -271,6 +275,7 @@ i2c_dw_xfer_msg(struct dw_i2c_dev *dev)
        u32 buf_len = dev->tx_buf_len;
        u8 *buf = dev->tx_buf;
        bool need_restart = false;
+       unsigned int flr;
 
        intr_mask = DW_IC_INTR_MASTER_MASK;
 
@@ -303,8 +308,11 @@ i2c_dw_xfer_msg(struct dw_i2c_dev *dev)
                                need_restart = true;
                }
 
-               tx_limit = dev->tx_fifo_depth - dw_readl(dev, DW_IC_TXFLR);
-               rx_limit = dev->rx_fifo_depth - dw_readl(dev, DW_IC_RXFLR);
+               regmap_read(dev->map, DW_IC_TXFLR, &flr);
+               tx_limit = dev->tx_fifo_depth - flr;
+
+               regmap_read(dev->map, DW_IC_RXFLR, &flr);
+               rx_limit = dev->rx_fifo_depth - flr;
 
                while (buf_len > 0 && tx_limit > 0 && rx_limit > 0) {
                        u32 cmd = 0;
@@ -337,11 +345,14 @@ i2c_dw_xfer_msg(struct dw_i2c_dev *dev)
                                if (dev->rx_outstanding >= dev->rx_fifo_depth)
                                        break;
 
-                               dw_writel(dev, cmd | 0x100, DW_IC_DATA_CMD);
+                               regmap_write(dev->map, DW_IC_DATA_CMD,
+                                            cmd | 0x100);
                                rx_limit--;
                                dev->rx_outstanding++;
-                       } else
-                               dw_writel(dev, cmd | *buf++, DW_IC_DATA_CMD);
+                       } else {
+                               regmap_write(dev->map, DW_IC_DATA_CMD,
+                                            cmd | *buf++);
+                       }
                        tx_limit--; buf_len--;
                }
 
@@ -371,7 +382,7 @@ i2c_dw_xfer_msg(struct dw_i2c_dev *dev)
        if (dev->msg_err)
                intr_mask = 0;
 
-       dw_writel(dev, intr_mask,  DW_IC_INTR_MASK);
+       regmap_write(dev->map,  DW_IC_INTR_MASK, intr_mask);
 }
 
 static u8
@@ -396,10 +407,10 @@ static void
 i2c_dw_read(struct dw_i2c_dev *dev)
 {
        struct i2c_msg *msgs = dev->msgs;
-       int rx_valid;
+       unsigned int rx_valid;
 
        for (; dev->msg_read_idx < dev->msgs_num; dev->msg_read_idx++) {
-               u32 len;
+               u32 len, tmp;
                u8 *buf;
 
                if (!(msgs[dev->msg_read_idx].flags & I2C_M_RD))
@@ -413,18 +424,18 @@ i2c_dw_read(struct dw_i2c_dev *dev)
                        buf = dev->rx_buf;
                }
 
-               rx_valid = dw_readl(dev, DW_IC_RXFLR);
+               regmap_read(dev->map, DW_IC_RXFLR, &rx_valid);
 
                for (; len > 0 && rx_valid > 0; len--, rx_valid--) {
                        u32 flags = msgs[dev->msg_read_idx].flags;
 
-                       *buf = dw_readl(dev, DW_IC_DATA_CMD);
+                       regmap_read(dev->map, DW_IC_DATA_CMD, &tmp);
                        /* Ensure length byte is a valid value */
                        if (flags & I2C_M_RECV_LEN &&
-                               *buf <= I2C_SMBUS_BLOCK_MAX && *buf > 0) {
-                               len = i2c_dw_recv_len(dev, *buf);
+                           tmp <= I2C_SMBUS_BLOCK_MAX && tmp > 0) {
+                               len = i2c_dw_recv_len(dev, tmp);
                        }
-                       buf++;
+                       *buf++ = tmp;
                        dev->rx_outstanding--;
                }
 
@@ -542,7 +553,7 @@ static const struct i2c_adapter_quirks i2c_dw_quirks = {
 
 static u32 i2c_dw_read_clear_intrbits(struct dw_i2c_dev *dev)
 {
-       u32 stat;
+       u32 stat, dummy;
 
        /*
         * The IC_INTR_STAT register just indicates "enabled" interrupts.
@@ -550,47 +561,47 @@ static u32 i2c_dw_read_clear_intrbits(struct dw_i2c_dev *dev)
         * in the IC_RAW_INTR_STAT register.
         *
         * That is,
-        *   stat = dw_readl(IC_INTR_STAT);
+        *   stat = readl(IC_INTR_STAT);
         * equals to,
-        *   stat = dw_readl(IC_RAW_INTR_STAT) & dw_readl(IC_INTR_MASK);
+        *   stat = readl(IC_RAW_INTR_STAT) & readl(IC_INTR_MASK);
         *
         * The raw version might be useful for debugging purposes.
         */
-       stat = dw_readl(dev, DW_IC_INTR_STAT);
+       regmap_read(dev->map, DW_IC_INTR_STAT, &stat);
 
        /*
         * Do not use the IC_CLR_INTR register to clear interrupts, or
         * you'll miss some interrupts, triggered during the period from
-        * dw_readl(IC_INTR_STAT) to dw_readl(IC_CLR_INTR).
+        * readl(IC_INTR_STAT) to readl(IC_CLR_INTR).
         *
         * Instead, use the separately-prepared IC_CLR_* registers.
         */
        if (stat & DW_IC_INTR_RX_UNDER)
-               dw_readl(dev, DW_IC_CLR_RX_UNDER);
+               regmap_read(dev->map, DW_IC_CLR_RX_UNDER, &dummy);
        if (stat & DW_IC_INTR_RX_OVER)
-               dw_readl(dev, DW_IC_CLR_RX_OVER);
+               regmap_read(dev->map, DW_IC_CLR_RX_OVER, &dummy);
        if (stat & DW_IC_INTR_TX_OVER)
-               dw_readl(dev, DW_IC_CLR_TX_OVER);
+               regmap_read(dev->map, DW_IC_CLR_TX_OVER, &dummy);
        if (stat & DW_IC_INTR_RD_REQ)
-               dw_readl(dev, DW_IC_CLR_RD_REQ);
+               regmap_read(dev->map, DW_IC_CLR_RD_REQ, &dummy);
        if (stat & DW_IC_INTR_TX_ABRT) {
                /*
                 * The IC_TX_ABRT_SOURCE register is cleared whenever
                 * the IC_CLR_TX_ABRT is read.  Preserve it beforehand.
                 */
-               dev->abort_source = dw_readl(dev, DW_IC_TX_ABRT_SOURCE);
-               dw_readl(dev, DW_IC_CLR_TX_ABRT);
+               regmap_read(dev->map, DW_IC_TX_ABRT_SOURCE, &dev->abort_source);
+               regmap_read(dev->map, DW_IC_CLR_TX_ABRT, &dummy);
        }
        if (stat & DW_IC_INTR_RX_DONE)
-               dw_readl(dev, DW_IC_CLR_RX_DONE);
+               regmap_read(dev->map, DW_IC_CLR_RX_DONE, &dummy);
        if (stat & DW_IC_INTR_ACTIVITY)
-               dw_readl(dev, DW_IC_CLR_ACTIVITY);
+               regmap_read(dev->map, DW_IC_CLR_ACTIVITY, &dummy);
        if (stat & DW_IC_INTR_STOP_DET)
-               dw_readl(dev, DW_IC_CLR_STOP_DET);
+               regmap_read(dev->map, DW_IC_CLR_STOP_DET, &dummy);
        if (stat & DW_IC_INTR_START_DET)
-               dw_readl(dev, DW_IC_CLR_START_DET);
+               regmap_read(dev->map, DW_IC_CLR_START_DET, &dummy);
        if (stat & DW_IC_INTR_GEN_CALL)
-               dw_readl(dev, DW_IC_CLR_GEN_CALL);
+               regmap_read(dev->map, DW_IC_CLR_GEN_CALL, &dummy);
 
        return stat;
 }
@@ -612,7 +623,7 @@ static int i2c_dw_irq_handler_master(struct dw_i2c_dev *dev)
                 * Anytime TX_ABRT is set, the contents of the tx/rx
                 * buffers are flushed. Make sure to skip them.
                 */
-               dw_writel(dev, 0, DW_IC_INTR_MASK);
+               regmap_write(dev->map, DW_IC_INTR_MASK, 0);
                goto tx_aborted;
        }
 
@@ -633,9 +644,9 @@ tx_aborted:
                complete(&dev->cmd_complete);
        else if (unlikely(dev->flags & ACCESS_INTR_MASK)) {
                /* Workaround to trigger pending interrupt */
-               stat = dw_readl(dev, DW_IC_INTR_MASK);
+               regmap_read(dev->map, DW_IC_INTR_MASK, &stat);
                i2c_dw_disable_int(dev);
-               dw_writel(dev, stat, DW_IC_INTR_MASK);
+               regmap_write(dev->map, DW_IC_INTR_MASK, stat);
        }
 
        return 0;
@@ -646,8 +657,8 @@ static irqreturn_t i2c_dw_isr(int this_irq, void *dev_id)
        struct dw_i2c_dev *dev = dev_id;
        u32 stat, enabled;
 
-       enabled = dw_readl(dev, DW_IC_ENABLE);
-       stat = dw_readl(dev, DW_IC_RAW_INTR_STAT);
+       regmap_read(dev->map, DW_IC_ENABLE, &enabled);
+       regmap_read(dev->map, DW_IC_RAW_INTR_STAT, &stat);
        dev_dbg(dev->dev, "enabled=%#x stat=%#x\n", enabled, stat);
        if (!enabled || !(stat & ~DW_IC_INTR_ACTIVITY))
                return IRQ_NONE;
@@ -739,7 +750,7 @@ int i2c_dw_probe_master(struct dw_i2c_dev *dev)
        dev->disable = i2c_dw_disable;
        dev->disable_int = i2c_dw_disable_int;
 
-       ret = i2c_dw_set_reg_access(dev);
+       ret = i2c_dw_init_regmap(dev);
        if (ret)
                return ret;
 
@@ -747,7 +758,9 @@ int i2c_dw_probe_master(struct dw_i2c_dev *dev)
        if (ret)
                return ret;
 
-       i2c_dw_set_fifo_size(dev);
+       ret = i2c_dw_set_fifo_size(dev);
+       if (ret)
+               return ret;
 
        ret = dev->init(dev);
        if (ret)
index 576e7af4e94bec9ffe4ab5eab42a1b8ea0796f1f..44974b53a6268149007cff3c5c394ba3c6b56b63 100644 (file)
 #include <linux/io.h>
 #include <linux/module.h>
 #include <linux/pm_runtime.h>
+#include <linux/regmap.h>
 
 #include "i2c-designware-core.h"
 
 static void i2c_dw_configure_fifo_slave(struct dw_i2c_dev *dev)
 {
        /* Configure Tx/Rx FIFO threshold levels. */
-       dw_writel(dev, 0, DW_IC_TX_TL);
-       dw_writel(dev, 0, DW_IC_RX_TL);
+       regmap_write(dev->map, DW_IC_TX_TL, 0);
+       regmap_write(dev->map, DW_IC_RX_TL, 0);
 
        /* Configure the I2C slave. */
-       dw_writel(dev, dev->slave_cfg, DW_IC_CON);
-       dw_writel(dev, DW_IC_INTR_SLAVE_MASK, DW_IC_INTR_MASK);
+       regmap_write(dev->map, DW_IC_CON, dev->slave_cfg);
+       regmap_write(dev->map, DW_IC_INTR_MASK, DW_IC_INTR_SLAVE_MASK);
 }
 
 /**
@@ -49,7 +50,7 @@ static int i2c_dw_init_slave(struct dw_i2c_dev *dev)
 
        /* Write SDA hold time if supported */
        if (dev->sda_hold_time)
-               dw_writel(dev, dev->sda_hold_time, DW_IC_SDA_HOLD);
+               regmap_write(dev->map, DW_IC_SDA_HOLD, dev->sda_hold_time);
 
        i2c_dw_configure_fifo_slave(dev);
        i2c_dw_release_lock(dev);
@@ -72,7 +73,7 @@ static int i2c_dw_reg_slave(struct i2c_client *slave)
         * the address to which the DW_apb_i2c responds.
         */
        __i2c_dw_disable_nowait(dev);
-       dw_writel(dev, slave->addr, DW_IC_SAR);
+       regmap_write(dev->map, DW_IC_SAR, slave->addr);
        dev->slave = slave;
 
        __i2c_dw_enable(dev);
@@ -103,7 +104,7 @@ static int i2c_dw_unreg_slave(struct i2c_client *slave)
 
 static u32 i2c_dw_read_clear_intrbits_slave(struct dw_i2c_dev *dev)
 {
-       u32 stat;
+       u32 stat, dummy;
 
        /*
         * The IC_INTR_STAT register just indicates "enabled" interrupts.
@@ -111,39 +112,39 @@ static u32 i2c_dw_read_clear_intrbits_slave(struct dw_i2c_dev *dev)
         * in the IC_RAW_INTR_STAT register.
         *
         * That is,
-        *   stat = dw_readl(IC_INTR_STAT);
+        *   stat = readl(IC_INTR_STAT);
         * equals to,
-        *   stat = dw_readl(IC_RAW_INTR_STAT) & dw_readl(IC_INTR_MASK);
+        *   stat = readl(IC_RAW_INTR_STAT) & readl(IC_INTR_MASK);
         *
         * The raw version might be useful for debugging purposes.
         */
-       stat = dw_readl(dev, DW_IC_INTR_STAT);
+       regmap_read(dev->map, DW_IC_INTR_STAT, &stat);
 
        /*
         * Do not use the IC_CLR_INTR register to clear interrupts, or
         * you'll miss some interrupts, triggered during the period from
-        * dw_readl(IC_INTR_STAT) to dw_readl(IC_CLR_INTR).
+        * readl(IC_INTR_STAT) to readl(IC_CLR_INTR).
         *
         * Instead, use the separately-prepared IC_CLR_* registers.
         */
        if (stat & DW_IC_INTR_TX_ABRT)
-               dw_readl(dev, DW_IC_CLR_TX_ABRT);
+               regmap_read(dev->map, DW_IC_CLR_TX_ABRT, &dummy);
        if (stat & DW_IC_INTR_RX_UNDER)
-               dw_readl(dev, DW_IC_CLR_RX_UNDER);
+               regmap_read(dev->map, DW_IC_CLR_RX_UNDER, &dummy);
        if (stat & DW_IC_INTR_RX_OVER)
-               dw_readl(dev, DW_IC_CLR_RX_OVER);
+               regmap_read(dev->map, DW_IC_CLR_RX_OVER, &dummy);
        if (stat & DW_IC_INTR_TX_OVER)
-               dw_readl(dev, DW_IC_CLR_TX_OVER);
+               regmap_read(dev->map, DW_IC_CLR_TX_OVER, &dummy);
        if (stat & DW_IC_INTR_RX_DONE)
-               dw_readl(dev, DW_IC_CLR_RX_DONE);
+               regmap_read(dev->map, DW_IC_CLR_RX_DONE, &dummy);
        if (stat & DW_IC_INTR_ACTIVITY)
-               dw_readl(dev, DW_IC_CLR_ACTIVITY);
+               regmap_read(dev->map, DW_IC_CLR_ACTIVITY, &dummy);
        if (stat & DW_IC_INTR_STOP_DET)
-               dw_readl(dev, DW_IC_CLR_STOP_DET);
+               regmap_read(dev->map, DW_IC_CLR_STOP_DET, &dummy);
        if (stat & DW_IC_INTR_START_DET)
-               dw_readl(dev, DW_IC_CLR_START_DET);
+               regmap_read(dev->map, DW_IC_CLR_START_DET, &dummy);
        if (stat & DW_IC_INTR_GEN_CALL)
-               dw_readl(dev, DW_IC_CLR_GEN_CALL);
+               regmap_read(dev->map, DW_IC_CLR_GEN_CALL, &dummy);
 
        return stat;
 }
@@ -155,14 +156,14 @@ static u32 i2c_dw_read_clear_intrbits_slave(struct dw_i2c_dev *dev)
 
 static int i2c_dw_irq_handler_slave(struct dw_i2c_dev *dev)
 {
-       u32 raw_stat, stat, enabled;
-       u8 val, slave_activity;
+       u32 raw_stat, stat, enabled, tmp;
+       u8 val = 0, slave_activity;
 
-       stat = dw_readl(dev, DW_IC_INTR_STAT);
-       enabled = dw_readl(dev, DW_IC_ENABLE);
-       raw_stat = dw_readl(dev, DW_IC_RAW_INTR_STAT);
-       slave_activity = ((dw_readl(dev, DW_IC_STATUS) &
-               DW_IC_STATUS_SLAVE_ACTIVITY) >> 6);
+       regmap_read(dev->map, DW_IC_INTR_STAT, &stat);
+       regmap_read(dev->map, DW_IC_ENABLE, &enabled);
+       regmap_read(dev->map, DW_IC_RAW_INTR_STAT, &raw_stat);
+       regmap_read(dev->map, DW_IC_STATUS, &tmp);
+       slave_activity = ((tmp & DW_IC_STATUS_SLAVE_ACTIVITY) >> 6);
 
        if (!enabled || !(raw_stat & ~DW_IC_INTR_ACTIVITY) || !dev->slave)
                return 0;
@@ -177,7 +178,8 @@ static int i2c_dw_irq_handler_slave(struct dw_i2c_dev *dev)
        if (stat & DW_IC_INTR_RD_REQ) {
                if (slave_activity) {
                        if (stat & DW_IC_INTR_RX_FULL) {
-                               val = dw_readl(dev, DW_IC_DATA_CMD);
+                               regmap_read(dev->map, DW_IC_DATA_CMD, &tmp);
+                               val = tmp;
 
                                if (!i2c_slave_event(dev->slave,
                                                     I2C_SLAVE_WRITE_RECEIVED,
@@ -185,24 +187,24 @@ static int i2c_dw_irq_handler_slave(struct dw_i2c_dev *dev)
                                        dev_vdbg(dev->dev, "Byte %X acked!",
                                                 val);
                                }
-                               dw_readl(dev, DW_IC_CLR_RD_REQ);
+                               regmap_read(dev->map, DW_IC_CLR_RD_REQ, &tmp);
                                stat = i2c_dw_read_clear_intrbits_slave(dev);
                        } else {
-                               dw_readl(dev, DW_IC_CLR_RD_REQ);
-                               dw_readl(dev, DW_IC_CLR_RX_UNDER);
+                               regmap_read(dev->map, DW_IC_CLR_RD_REQ, &tmp);
+                               regmap_read(dev->map, DW_IC_CLR_RX_UNDER, &tmp);
                                stat = i2c_dw_read_clear_intrbits_slave(dev);
                        }
                        if (!i2c_slave_event(dev->slave,
                                             I2C_SLAVE_READ_REQUESTED,
                                             &val))
-                               dw_writel(dev, val, DW_IC_DATA_CMD);
+                               regmap_write(dev->map, DW_IC_DATA_CMD, val);
                }
        }
 
        if (stat & DW_IC_INTR_RX_DONE) {
                if (!i2c_slave_event(dev->slave, I2C_SLAVE_READ_PROCESSED,
                                     &val))
-                       dw_readl(dev, DW_IC_CLR_RX_DONE);
+                       regmap_read(dev->map, DW_IC_CLR_RX_DONE, &tmp);
 
                i2c_slave_event(dev->slave, I2C_SLAVE_STOP, &val);
                stat = i2c_dw_read_clear_intrbits_slave(dev);
@@ -210,7 +212,8 @@ static int i2c_dw_irq_handler_slave(struct dw_i2c_dev *dev)
        }
 
        if (stat & DW_IC_INTR_RX_FULL) {
-               val = dw_readl(dev, DW_IC_DATA_CMD);
+               regmap_read(dev->map, DW_IC_DATA_CMD, &tmp);
+               val = tmp;
                if (!i2c_slave_event(dev->slave, I2C_SLAVE_WRITE_RECEIVED,
                                     &val))
                        dev_vdbg(dev->dev, "Byte %X acked!", val);
@@ -263,7 +266,7 @@ int i2c_dw_probe_slave(struct dw_i2c_dev *dev)
        dev->disable = i2c_dw_disable;
        dev->disable_int = i2c_dw_disable_int;
 
-       ret = i2c_dw_set_reg_access(dev);
+       ret = i2c_dw_init_regmap(dev);
        if (ret)
                return ret;
 
@@ -271,7 +274,9 @@ int i2c_dw_probe_slave(struct dw_i2c_dev *dev)
        if (ret)
                return ret;
 
-       i2c_dw_set_fifo_size(dev);
+       ret = i2c_dw_set_fifo_size(dev);
+       if (ret)
+               return ret;
 
        ret = dev->init(dev);
        if (ret)