Commit 0daede80 authored by Serge Semin's avatar Serge Semin Committed by Wolfram Sang

i2c: designware: Convert driver to using regmap API

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: default avatarAndy Shevchenko <andriy.shevchenko@linux.intel.com>
Signed-off-by: default avatarSerge Semin <Sergey.Semin@baikalelectronics.ru>
Tested-by: default avatarJarkko Nikula <jarkko.nikula@linux.intel.com>
Acked-by: default avatarJarkko Nikula <jarkko.nikula@linux.intel.com>
Reviewed-by: default avatarAndy Shevchenko <andriy.shevchenko@linux.intel.com>
[wsa: fix type of 'rx_valid' and remove outdated kdoc var description]
Signed-off-by: default avatarWolfram Sang <wsa@kernel.org>
parent c615f5c6
...@@ -526,6 +526,7 @@ config I2C_DAVINCI ...@@ -526,6 +526,7 @@ config I2C_DAVINCI
config I2C_DESIGNWARE_CORE config I2C_DESIGNWARE_CORE
tristate tristate
select REGMAP
config I2C_DESIGNWARE_SLAVE config I2C_DESIGNWARE_SLAVE
bool "Synopsys DesignWare Slave" bool "Synopsys DesignWare Slave"
......
...@@ -21,6 +21,7 @@ ...@@ -21,6 +21,7 @@
#include <linux/kernel.h> #include <linux/kernel.h>
#include <linux/module.h> #include <linux/module.h>
#include <linux/pm_runtime.h> #include <linux/pm_runtime.h>
#include <linux/regmap.h>
#include <linux/swab.h> #include <linux/swab.h>
#include <linux/types.h> #include <linux/types.h>
...@@ -57,66 +58,122 @@ static char *abort_sources[] = { ...@@ -57,66 +58,122 @@ static char *abort_sources[] = {
"incorrect slave-transmitter mode configuration", "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) *val = readl_relaxed(dev->base + reg);
value = readw_relaxed(dev->base + offset) |
(readw_relaxed(dev->base + offset + 2) << 16);
else
value = readl_relaxed(dev->base + offset);
if (dev->flags & ACCESS_SWAP) return 0;
return swab32(value);
else
return value;
} }
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) struct dw_i2c_dev *dev = context;
b = swab32(b);
writel_relaxed(val, dev->base + reg);
if (dev->flags & ACCESS_16BIT) {
writew_relaxed((u16)b, dev->base + offset); return 0;
writew_relaxed((u16)(b >> 16), dev->base + offset + 2); }
} else {
writel_relaxed(b, dev->base + offset); 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 * @dev: device private data
* *
* Autodetects needed register access mode and sets access flags accordingly. * Autodetects needed register access mode and creates the regmap with
* This must be called before doing any other register access. * 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; u32 reg;
int ret; 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); ret = i2c_dw_acquire_lock(dev);
if (ret) if (ret)
return ret; return ret;
reg = dw_readl(dev, DW_IC_COMP_TYPE); reg = readl(dev->base + DW_IC_COMP_TYPE);
i2c_dw_release_lock(dev); i2c_dw_release_lock(dev);
if (reg == swab32(DW_IC_COMP_TYPE_VALUE)) { if (reg == swab32(DW_IC_COMP_TYPE_VALUE)) {
/* Configure register endianness access */ map_cfg.reg_read = dw_reg_read_swab;
dev->flags |= ACCESS_SWAP; map_cfg.reg_write = dw_reg_write_swab;
} else if (reg == (DW_IC_COMP_TYPE_VALUE & 0x0000ffff)) { } else if (reg == (DW_IC_COMP_TYPE_VALUE & 0x0000ffff)) {
/* Configure register access mode 16bit */ map_cfg.reg_read = dw_reg_read_word;
dev->flags |= ACCESS_16BIT; map_cfg.reg_write = dw_reg_write_word;
} else if (reg != DW_IC_COMP_TYPE_VALUE) { } else if (reg != DW_IC_COMP_TYPE_VALUE) {
dev_err(dev->dev, dev_err(dev->dev,
"Unknown Synopsys component type: 0x%08x\n", reg); "Unknown Synopsys component type: 0x%08x\n", reg);
return -ENODEV; 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; return 0;
} }
...@@ -327,11 +384,17 @@ int i2c_dw_set_sda_hold(struct dw_i2c_dev *dev) ...@@ -327,11 +384,17 @@ int i2c_dw_set_sda_hold(struct dw_i2c_dev *dev)
return ret; return ret;
/* Configure SDA Hold Time if required */ /* 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 (reg >= DW_IC_SDA_HOLD_MIN_VERS) {
if (!dev->sda_hold_time) { if (!dev->sda_hold_time) {
/* Keep previous hold time setting if no one set it */ /* 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) ...@@ -355,14 +418,16 @@ int i2c_dw_set_sda_hold(struct dw_i2c_dev *dev)
dev->sda_hold_time = 0; dev->sda_hold_time = 0;
} }
err_release_lock:
i2c_dw_release_lock(dev); i2c_dw_release_lock(dev);
return 0; return ret;
} }
void __i2c_dw_disable(struct dw_i2c_dev *dev) void __i2c_dw_disable(struct dw_i2c_dev *dev)
{ {
int timeout = 100; int timeout = 100;
u32 status;
do { do {
__i2c_dw_disable_nowait(dev); __i2c_dw_disable_nowait(dev);
...@@ -370,7 +435,8 @@ void __i2c_dw_disable(struct dw_i2c_dev *dev) ...@@ -370,7 +435,8 @@ void __i2c_dw_disable(struct dw_i2c_dev *dev)
* The enable status register may be unimplemented, but * The enable status register may be unimplemented, but
* in that case this test reads zero and exits the loop. * 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; return;
/* /*
...@@ -449,22 +515,23 @@ void i2c_dw_release_lock(struct dw_i2c_dev *dev) ...@@ -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 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) { ret = regmap_read_poll_timeout(dev->map, DW_IC_STATUS, status,
if (timeout <= 0) { !(status & DW_IC_STATUS_ACTIVITY),
dev_warn(dev->dev, "timeout waiting for bus ready\n"); 1100, 20000);
i2c_recover_bus(&dev->adapter); if (ret) {
dev_warn(dev->dev, "timeout waiting for bus ready\n");
if (dw_readl(dev, DW_IC_STATUS) & DW_IC_STATUS_ACTIVITY) i2c_recover_bus(&dev->adapter);
return -ETIMEDOUT;
return 0; regmap_read(dev->map, DW_IC_STATUS, &status);
} if (!(status & DW_IC_STATUS_ACTIVITY))
timeout--; ret = 0;
usleep_range(1000, 1100);
} }
return 0; return ret;
} }
int i2c_dw_handle_tx_abort(struct dw_i2c_dev *dev) 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) ...@@ -490,15 +557,19 @@ int i2c_dw_handle_tx_abort(struct dw_i2c_dev *dev)
return -EIO; 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; u32 param, tx_fifo_depth, rx_fifo_depth;
int ret;
/* /*
* Try to detect the FIFO depth if not set by interface driver, * Try to detect the FIFO depth if not set by interface driver,
* the depth could be from 2 to 256 from HW spec. * 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; tx_fifo_depth = ((param >> 16) & 0xff) + 1;
rx_fifo_depth = ((param >> 8) & 0xff) + 1; rx_fifo_depth = ((param >> 8) & 0xff) + 1;
if (!dev->tx_fifo_depth) { if (!dev->tx_fifo_depth) {
...@@ -510,6 +581,8 @@ void i2c_dw_set_fifo_size(struct dw_i2c_dev *dev) ...@@ -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, dev->rx_fifo_depth = min_t(u32, dev->rx_fifo_depth,
rx_fifo_depth); rx_fifo_depth);
} }
return 0;
} }
u32 i2c_dw_func(struct i2c_adapter *adap) u32 i2c_dw_func(struct i2c_adapter *adap)
...@@ -521,17 +594,19 @@ 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) void i2c_dw_disable(struct dw_i2c_dev *dev)
{ {
u32 dummy;
/* Disable controller */ /* Disable controller */
__i2c_dw_disable(dev); __i2c_dw_disable(dev);
/* Disable all interrupts */ /* Disable all interrupts */
dw_writel(dev, 0, DW_IC_INTR_MASK); regmap_write(dev->map, DW_IC_INTR_MASK, 0);
dw_readl(dev, DW_IC_CLR_INTR); regmap_read(dev->map, DW_IC_CLR_INTR, &dummy);
} }
void i2c_dw_disable_int(struct dw_i2c_dev *dev) 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"); MODULE_DESCRIPTION("Synopsys DesignWare I2C bus adapter core");
......
...@@ -15,6 +15,7 @@ ...@@ -15,6 +15,7 @@
#include <linux/dev_printk.h> #include <linux/dev_printk.h>
#include <linux/errno.h> #include <linux/errno.h>
#include <linux/i2c.h> #include <linux/i2c.h>
#include <linux/regmap.h>
#include <linux/types.h> #include <linux/types.h>
#define DW_IC_DEFAULT_FUNCTIONALITY (I2C_FUNC_I2C | \ #define DW_IC_DEFAULT_FUNCTIONALITY (I2C_FUNC_I2C | \
...@@ -126,8 +127,6 @@ ...@@ -126,8 +127,6 @@
#define STATUS_WRITE_IN_PROGRESS 0x1 #define STATUS_WRITE_IN_PROGRESS 0x1
#define STATUS_READ_IN_PROGRESS 0x2 #define STATUS_READ_IN_PROGRESS 0x2
#define TIMEOUT 20 /* ms */
/* /*
* operation modes * operation modes
*/ */
...@@ -183,7 +182,9 @@ struct reset_control; ...@@ -183,7 +182,9 @@ struct reset_control;
/** /**
* struct dw_i2c_dev - private i2c-designware data * struct dw_i2c_dev - private i2c-designware data
* @dev: driver model device node * @dev: driver model device node
* @map: IO registers map
* @base: IO registers pointer * @base: IO registers pointer
* @ext: Extended IO registers pointer
* @cmd_complete: tx completion indicator * @cmd_complete: tx completion indicator
* @clk: input reference clock * @clk: input reference clock
* @pclk: clock required to access the registers * @pclk: clock required to access the registers
...@@ -233,6 +234,7 @@ struct reset_control; ...@@ -233,6 +234,7 @@ struct reset_control;
*/ */
struct dw_i2c_dev { struct dw_i2c_dev {
struct device *dev; struct device *dev;
struct regmap *map;
void __iomem *base; void __iomem *base;
void __iomem *ext; void __iomem *ext;
struct completion cmd_complete; struct completion cmd_complete;
...@@ -284,17 +286,13 @@ struct dw_i2c_dev { ...@@ -284,17 +286,13 @@ struct dw_i2c_dev {
bool suspended; bool suspended;
}; };
#define ACCESS_SWAP 0x00000001 #define ACCESS_INTR_MASK 0x00000001
#define ACCESS_16BIT 0x00000002 #define ACCESS_NO_IRQ_SUSPEND 0x00000002
#define ACCESS_INTR_MASK 0x00000004
#define ACCESS_NO_IRQ_SUSPEND 0x00000008
#define MODEL_MSCC_OCELOT 0x00000100 #define MODEL_MSCC_OCELOT 0x00000100
#define MODEL_MASK 0x00000f00 #define MODEL_MASK 0x00000f00
u32 dw_readl(struct dw_i2c_dev *dev, int offset); int i2c_dw_init_regmap(struct dw_i2c_dev *dev);
void dw_writel(struct dw_i2c_dev *dev, u32 b, int offset);
int i2c_dw_set_reg_access(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_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); 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); 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); ...@@ -304,19 +302,19 @@ int i2c_dw_acquire_lock(struct dw_i2c_dev *dev);
void i2c_dw_release_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_wait_bus_not_busy(struct dw_i2c_dev *dev);
int i2c_dw_handle_tx_abort(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); u32 i2c_dw_func(struct i2c_adapter *adap);
void i2c_dw_disable(struct dw_i2c_dev *dev); void i2c_dw_disable(struct dw_i2c_dev *dev);
void i2c_dw_disable_int(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) 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) 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); void __i2c_dw_disable(struct dw_i2c_dev *dev);
......
This diff is collapsed.
...@@ -14,18 +14,19 @@ ...@@ -14,18 +14,19 @@
#include <linux/io.h> #include <linux/io.h>
#include <linux/module.h> #include <linux/module.h>
#include <linux/pm_runtime.h> #include <linux/pm_runtime.h>
#include <linux/regmap.h>
#include "i2c-designware-core.h" #include "i2c-designware-core.h"
static void i2c_dw_configure_fifo_slave(struct dw_i2c_dev *dev) static void i2c_dw_configure_fifo_slave(struct dw_i2c_dev *dev)
{ {
/* Configure Tx/Rx FIFO threshold levels. */ /* Configure Tx/Rx FIFO threshold levels. */
dw_writel(dev, 0, DW_IC_TX_TL); regmap_write(dev->map, DW_IC_TX_TL, 0);
dw_writel(dev, 0, DW_IC_RX_TL); regmap_write(dev->map, DW_IC_RX_TL, 0);
/* Configure the I2C slave. */ /* Configure the I2C slave. */
dw_writel(dev, dev->slave_cfg, DW_IC_CON); regmap_write(dev->map, DW_IC_CON, dev->slave_cfg);
dw_writel(dev, DW_IC_INTR_SLAVE_MASK, DW_IC_INTR_MASK); 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) ...@@ -49,7 +50,7 @@ static int i2c_dw_init_slave(struct dw_i2c_dev *dev)
/* Write SDA hold time if supported */ /* Write SDA hold time if supported */
if (dev->sda_hold_time) 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_configure_fifo_slave(dev);
i2c_dw_release_lock(dev); i2c_dw_release_lock(dev);
...@@ -72,7 +73,7 @@ static int i2c_dw_reg_slave(struct i2c_client *slave) ...@@ -72,7 +73,7 @@ static int i2c_dw_reg_slave(struct i2c_client *slave)
* the address to which the DW_apb_i2c responds. * the address to which the DW_apb_i2c responds.
*/ */
__i2c_dw_disable_nowait(dev); __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; dev->slave = slave;
__i2c_dw_enable(dev); __i2c_dw_enable(dev);
...@@ -103,7 +104,7 @@ static int i2c_dw_unreg_slave(struct i2c_client *slave) ...@@ -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) 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. * 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) ...@@ -111,39 +112,39 @@ static u32 i2c_dw_read_clear_intrbits_slave(struct dw_i2c_dev *dev)
* in the IC_RAW_INTR_STAT register. * in the IC_RAW_INTR_STAT register.
* *
* That is, * That is,
* stat = dw_readl(IC_INTR_STAT); * stat = readl(IC_INTR_STAT);
* equals to, * 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. * 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 * Do not use the IC_CLR_INTR register to clear interrupts, or
* you'll miss some interrupts, triggered during the period from * 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. * Instead, use the separately-prepared IC_CLR_* registers.
*/ */
if (stat & DW_IC_INTR_TX_ABRT) 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) 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) 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) 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) 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) 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) 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) 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) 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; return stat;
} }
...@@ -155,14 +156,14 @@ static u32 i2c_dw_read_clear_intrbits_slave(struct dw_i2c_dev *dev) ...@@ -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) static int i2c_dw_irq_handler_slave(struct dw_i2c_dev *dev)
{ {
u32 raw_stat, stat, enabled; u32 raw_stat, stat, enabled, tmp;
u8 val, slave_activity; u8 val = 0, slave_activity;
stat = dw_readl(dev, DW_IC_INTR_STAT); regmap_read(dev->map, DW_IC_INTR_STAT, &stat);
enabled = dw_readl(dev, DW_IC_ENABLE); regmap_read(dev->map, DW_IC_ENABLE, &enabled);
raw_stat = dw_readl(dev, DW_IC_RAW_INTR_STAT); regmap_read(dev->map, DW_IC_RAW_INTR_STAT, &raw_stat);
slave_activity = ((dw_readl(dev, DW_IC_STATUS) & regmap_read(dev->map, DW_IC_STATUS, &tmp);
DW_IC_STATUS_SLAVE_ACTIVITY) >> 6); slave_activity = ((tmp & DW_IC_STATUS_SLAVE_ACTIVITY) >> 6);
if (!enabled || !(raw_stat & ~DW_IC_INTR_ACTIVITY) || !dev->slave) if (!enabled || !(raw_stat & ~DW_IC_INTR_ACTIVITY) || !dev->slave)
return 0; return 0;
...@@ -177,7 +178,8 @@ static int i2c_dw_irq_handler_slave(struct dw_i2c_dev *dev) ...@@ -177,7 +178,8 @@ static int i2c_dw_irq_handler_slave(struct dw_i2c_dev *dev)
if (stat & DW_IC_INTR_RD_REQ) { if (stat & DW_IC_INTR_RD_REQ) {
if (slave_activity) { if (slave_activity) {
if (stat & DW_IC_INTR_RX_FULL) { 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, if (!i2c_slave_event(dev->slave,
I2C_SLAVE_WRITE_RECEIVED, I2C_SLAVE_WRITE_RECEIVED,
...@@ -185,24 +187,24 @@ static int i2c_dw_irq_handler_slave(struct dw_i2c_dev *dev) ...@@ -185,24 +187,24 @@ static int i2c_dw_irq_handler_slave(struct dw_i2c_dev *dev)
dev_vdbg(dev->dev, "Byte %X acked!", dev_vdbg(dev->dev, "Byte %X acked!",
val); 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); stat = i2c_dw_read_clear_intrbits_slave(dev);
} else { } else {
dw_readl(dev, DW_IC_CLR_RD_REQ); regmap_read(dev->map, DW_IC_CLR_RD_REQ, &tmp);
dw_readl(dev, DW_IC_CLR_RX_UNDER); regmap_read(dev->map, DW_IC_CLR_RX_UNDER, &tmp);
stat = i2c_dw_read_clear_intrbits_slave(dev); stat = i2c_dw_read_clear_intrbits_slave(dev);
} }
if (!i2c_slave_event(dev->slave, if (!i2c_slave_event(dev->slave,
I2C_SLAVE_READ_REQUESTED, I2C_SLAVE_READ_REQUESTED,
&val)) &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 (stat & DW_IC_INTR_RX_DONE) {
if (!i2c_slave_event(dev->slave, I2C_SLAVE_READ_PROCESSED, if (!i2c_slave_event(dev->slave, I2C_SLAVE_READ_PROCESSED,
&val)) &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); i2c_slave_event(dev->slave, I2C_SLAVE_STOP, &val);
stat = i2c_dw_read_clear_intrbits_slave(dev); stat = i2c_dw_read_clear_intrbits_slave(dev);
...@@ -210,7 +212,8 @@ static int i2c_dw_irq_handler_slave(struct dw_i2c_dev *dev) ...@@ -210,7 +212,8 @@ static int i2c_dw_irq_handler_slave(struct dw_i2c_dev *dev)
} }
if (stat & DW_IC_INTR_RX_FULL) { 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, if (!i2c_slave_event(dev->slave, I2C_SLAVE_WRITE_RECEIVED,
&val)) &val))
dev_vdbg(dev->dev, "Byte %X acked!", val); dev_vdbg(dev->dev, "Byte %X acked!", val);
...@@ -263,7 +266,7 @@ int i2c_dw_probe_slave(struct dw_i2c_dev *dev) ...@@ -263,7 +266,7 @@ int i2c_dw_probe_slave(struct dw_i2c_dev *dev)
dev->disable = i2c_dw_disable; dev->disable = i2c_dw_disable;
dev->disable_int = i2c_dw_disable_int; dev->disable_int = i2c_dw_disable_int;
ret = i2c_dw_set_reg_access(dev); ret = i2c_dw_init_regmap(dev);
if (ret) if (ret)
return ret; return ret;
...@@ -271,7 +274,9 @@ int i2c_dw_probe_slave(struct dw_i2c_dev *dev) ...@@ -271,7 +274,9 @@ int i2c_dw_probe_slave(struct dw_i2c_dev *dev)
if (ret) if (ret)
return ret; return ret;
i2c_dw_set_fifo_size(dev); ret = i2c_dw_set_fifo_size(dev);
if (ret)
return ret;
ret = dev->init(dev); ret = dev->init(dev);
if (ret) if (ret)
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment