diff options
Diffstat (limited to 'drivers/i2c/busses/i2c-mxs.c')
-rw-r--r-- | drivers/i2c/busses/i2c-mxs.c | 144 |
1 files changed, 85 insertions, 59 deletions
diff --git a/drivers/i2c/busses/i2c-mxs.c b/drivers/i2c/busses/i2c-mxs.c index 120f24646696..2039f230482d 100644 --- a/drivers/i2c/busses/i2c-mxs.c +++ b/drivers/i2c/busses/i2c-mxs.c @@ -31,7 +31,6 @@ #include <linux/of_i2c.h> #include <linux/dma-mapping.h> #include <linux/dmaengine.h> -#include <linux/fsl/mxs-dma.h> #define DRIVER_NAME "mxs-i2c" @@ -56,6 +55,7 @@ #define MXS_I2C_CTRL1_SET (0x44) #define MXS_I2C_CTRL1_CLR (0x48) +#define MXS_I2C_CTRL1_CLR_GOT_A_NAK 0x10000000 #define MXS_I2C_CTRL1_BUS_FREE_IRQ 0x80 #define MXS_I2C_CTRL1_DATA_ENGINE_CMPLT_IRQ 0x40 #define MXS_I2C_CTRL1_NO_SLAVE_ACK_IRQ 0x20 @@ -65,6 +65,10 @@ #define MXS_I2C_CTRL1_SLAVE_STOP_IRQ 0x02 #define MXS_I2C_CTRL1_SLAVE_IRQ 0x01 +#define MXS_I2C_STAT (0x50) +#define MXS_I2C_STAT_BUS_BUSY 0x00000800 +#define MXS_I2C_STAT_CLK_GEN_BUSY 0x00000400 + #define MXS_I2C_DATA (0xa0) #define MXS_I2C_DEBUG0 (0xb0) @@ -113,9 +117,7 @@ struct mxs_i2c_dev { uint32_t timing1; /* DMA support components */ - int dma_channel; struct dma_chan *dmach; - struct mxs_dma_data dma_data; uint32_t pio_data[2]; uint32_t addr_data; struct scatterlist sg_io[2]; @@ -297,12 +299,10 @@ static int mxs_i2c_pio_wait_dmareq(struct mxs_i2c_dev *i2c) cond_resched(); } - writel(MXS_I2C_DEBUG0_DMAREQ, i2c->regs + MXS_I2C_DEBUG0_CLR); - return 0; } -static int mxs_i2c_pio_wait_cplt(struct mxs_i2c_dev *i2c) +static int mxs_i2c_pio_wait_cplt(struct mxs_i2c_dev *i2c, int last) { unsigned long timeout = jiffies + msecs_to_jiffies(1000); @@ -323,9 +323,50 @@ static int mxs_i2c_pio_wait_cplt(struct mxs_i2c_dev *i2c) writel(MXS_I2C_CTRL1_DATA_ENGINE_CMPLT_IRQ, i2c->regs + MXS_I2C_CTRL1_CLR); + /* + * When ending a transfer with a stop, we have to wait for the bus to + * go idle before we report the transfer as completed. Otherwise the + * start of the next transfer may race with the end of the current one. + */ + while (last && (readl(i2c->regs + MXS_I2C_STAT) & + (MXS_I2C_STAT_BUS_BUSY | MXS_I2C_STAT_CLK_GEN_BUSY))) { + if (time_after(jiffies, timeout)) + return -ETIMEDOUT; + cond_resched(); + } + return 0; } +static int mxs_i2c_pio_check_error_state(struct mxs_i2c_dev *i2c) +{ + u32 state; + + state = readl(i2c->regs + MXS_I2C_CTRL1_CLR) & MXS_I2C_IRQ_MASK; + + if (state & MXS_I2C_CTRL1_NO_SLAVE_ACK_IRQ) + i2c->cmd_err = -ENXIO; + else if (state & (MXS_I2C_CTRL1_EARLY_TERM_IRQ | + MXS_I2C_CTRL1_MASTER_LOSS_IRQ | + MXS_I2C_CTRL1_SLAVE_STOP_IRQ | + MXS_I2C_CTRL1_SLAVE_IRQ)) + i2c->cmd_err = -EIO; + + return i2c->cmd_err; +} + +static void mxs_i2c_pio_trigger_cmd(struct mxs_i2c_dev *i2c, u32 cmd) +{ + u32 reg; + + writel(cmd, i2c->regs + MXS_I2C_CTRL0); + + /* readback makes sure the write is latched into hardware */ + reg = readl(i2c->regs + MXS_I2C_CTRL0); + reg |= MXS_I2C_CTRL0_RUN; + writel(reg, i2c->regs + MXS_I2C_CTRL0); +} + static int mxs_i2c_pio_setup_xfer(struct i2c_adapter *adap, struct i2c_msg *msg, uint32_t flags) { @@ -341,23 +382,26 @@ static int mxs_i2c_pio_setup_xfer(struct i2c_adapter *adap, addr_data |= I2C_SMBUS_READ; /* SELECT command. */ - writel(MXS_I2C_CTRL0_RUN | MXS_CMD_I2C_SELECT, - i2c->regs + MXS_I2C_CTRL0); + mxs_i2c_pio_trigger_cmd(i2c, MXS_CMD_I2C_SELECT); ret = mxs_i2c_pio_wait_dmareq(i2c); if (ret) return ret; writel(addr_data, i2c->regs + MXS_I2C_DATA); + writel(MXS_I2C_DEBUG0_DMAREQ, i2c->regs + MXS_I2C_DEBUG0_CLR); - ret = mxs_i2c_pio_wait_cplt(i2c); + ret = mxs_i2c_pio_wait_cplt(i2c, 0); if (ret) return ret; + if (mxs_i2c_pio_check_error_state(i2c)) + goto cleanup; + /* READ command. */ - writel(MXS_I2C_CTRL0_RUN | MXS_CMD_I2C_READ | flags | - MXS_I2C_CTRL0_XFER_COUNT(msg->len), - i2c->regs + MXS_I2C_CTRL0); + mxs_i2c_pio_trigger_cmd(i2c, + MXS_CMD_I2C_READ | flags | + MXS_I2C_CTRL0_XFER_COUNT(msg->len)); for (i = 0; i < msg->len; i++) { if ((i & 3) == 0) { @@ -365,6 +409,8 @@ static int mxs_i2c_pio_setup_xfer(struct i2c_adapter *adap, if (ret) return ret; data = readl(i2c->regs + MXS_I2C_DATA); + writel(MXS_I2C_DEBUG0_DMAREQ, + i2c->regs + MXS_I2C_DEBUG0_CLR); } msg->buf[i] = data & 0xff; data >>= 8; @@ -373,9 +419,9 @@ static int mxs_i2c_pio_setup_xfer(struct i2c_adapter *adap, addr_data |= I2C_SMBUS_WRITE; /* WRITE command. */ - writel(MXS_I2C_CTRL0_RUN | MXS_CMD_I2C_WRITE | flags | - MXS_I2C_CTRL0_XFER_COUNT(msg->len + 1), - i2c->regs + MXS_I2C_CTRL0); + mxs_i2c_pio_trigger_cmd(i2c, + MXS_CMD_I2C_WRITE | flags | + MXS_I2C_CTRL0_XFER_COUNT(msg->len + 1)); /* * The LSB of data buffer is the first byte blasted across @@ -391,6 +437,8 @@ static int mxs_i2c_pio_setup_xfer(struct i2c_adapter *adap, if (ret) return ret; writel(data, i2c->regs + MXS_I2C_DATA); + writel(MXS_I2C_DEBUG0_DMAREQ, + i2c->regs + MXS_I2C_DEBUG0_CLR); } } @@ -401,13 +449,19 @@ static int mxs_i2c_pio_setup_xfer(struct i2c_adapter *adap, if (ret) return ret; writel(data, i2c->regs + MXS_I2C_DATA); + writel(MXS_I2C_DEBUG0_DMAREQ, + i2c->regs + MXS_I2C_DEBUG0_CLR); } } - ret = mxs_i2c_pio_wait_cplt(i2c); + ret = mxs_i2c_pio_wait_cplt(i2c, flags & MXS_I2C_CTRL0_POST_SEND_STOP); if (ret) return ret; + /* make sure we capture any occurred error into cmd_err */ + mxs_i2c_pio_check_error_state(i2c); + +cleanup: /* Clear any dangling IRQs and re-enable interrupts. */ writel(MXS_I2C_IRQ_MASK, i2c->regs + MXS_I2C_CTRL1_CLR); writel(MXS_I2C_IRQ_MASK << 8, i2c->regs + MXS_I2C_CTRL1_SET); @@ -439,12 +493,12 @@ static int mxs_i2c_xfer_msg(struct i2c_adapter *adap, struct i2c_msg *msg, * using PIO mode while longer transfers use DMA. The 8 byte border is * based on this empirical measurement and a lot of previous frobbing. */ + i2c->cmd_err = 0; if (msg->len < 8) { ret = mxs_i2c_pio_setup_xfer(adap, msg, flags); if (ret) mxs_i2c_reset(i2c); } else { - i2c->cmd_err = 0; INIT_COMPLETION(i2c->cmd_complete); ret = mxs_i2c_dma_setup_xfer(adap, msg, flags); if (ret) @@ -454,13 +508,19 @@ static int mxs_i2c_xfer_msg(struct i2c_adapter *adap, struct i2c_msg *msg, msecs_to_jiffies(1000)); if (ret == 0) goto timeout; + } - if (i2c->cmd_err == -ENXIO) - mxs_i2c_reset(i2c); - - ret = i2c->cmd_err; + if (i2c->cmd_err == -ENXIO) { + /* + * If the transfer fails with a NAK from the slave the + * controller halts until it gets told to return to idle state. + */ + writel(MXS_I2C_CTRL1_CLR_GOT_A_NAK, + i2c->regs + MXS_I2C_CTRL1_SET); } + ret = i2c->cmd_err; + dev_dbg(i2c->dev, "Done with err=%d\n", ret); return ret; @@ -518,21 +578,6 @@ static const struct i2c_algorithm mxs_i2c_algo = { .functionality = mxs_i2c_func, }; -static bool mxs_i2c_dma_filter(struct dma_chan *chan, void *param) -{ - struct mxs_i2c_dev *i2c = param; - - if (!mxs_dma_is_apbx(chan)) - return false; - - if (chan->chan_id != i2c->dma_channel) - return false; - - chan->private = &i2c->dma_data; - - return true; -} - static void mxs_i2c_derive_timing(struct mxs_i2c_dev *i2c, int speed) { /* The I2C block clock run at 24MHz */ @@ -577,17 +622,6 @@ static int mxs_i2c_get_ofdata(struct mxs_i2c_dev *i2c) struct device_node *node = dev->of_node; int ret; - /* - * TODO: This is a temporary solution and should be changed - * to use generic DMA binding later when the helpers get in. - */ - ret = of_property_read_u32(node, "fsl,i2c-dma-channel", - &i2c->dma_channel); - if (ret) { - dev_err(dev, "Failed to get DMA channel!\n"); - return -ENODEV; - } - ret = of_property_read_u32(node, "clock-frequency", &speed); if (ret) { dev_warn(dev, "No I2C speed selected, using 100kHz\n"); @@ -607,8 +641,7 @@ static int mxs_i2c_probe(struct platform_device *pdev) struct pinctrl *pinctrl; struct resource *res; resource_size_t res_size; - int err, irq, dmairq; - dma_cap_mask_t mask; + int err, irq; pinctrl = devm_pinctrl_get_select_default(dev); if (IS_ERR(pinctrl)) @@ -620,9 +653,8 @@ static int mxs_i2c_probe(struct platform_device *pdev) res = platform_get_resource(pdev, IORESOURCE_MEM, 0); irq = platform_get_irq(pdev, 0); - dmairq = platform_get_irq(pdev, 1); - if (!res || irq < 0 || dmairq < 0) + if (!res || irq < 0) return -ENOENT; res_size = resource_size(res); @@ -648,10 +680,7 @@ static int mxs_i2c_probe(struct platform_device *pdev) } /* Setup the DMA */ - dma_cap_zero(mask); - dma_cap_set(DMA_SLAVE, mask); - i2c->dma_data.chan_irq = dmairq; - i2c->dmach = dma_request_channel(mask, mxs_i2c_dma_filter, i2c); + i2c->dmach = dma_request_slave_channel(dev, "rx-tx"); if (!i2c->dmach) { dev_err(dev, "Failed to request dma\n"); return -ENODEV; @@ -686,11 +715,8 @@ static int mxs_i2c_probe(struct platform_device *pdev) static int mxs_i2c_remove(struct platform_device *pdev) { struct mxs_i2c_dev *i2c = platform_get_drvdata(pdev); - int ret; - ret = i2c_del_adapter(&i2c->adapter); - if (ret) - return -EBUSY; + i2c_del_adapter(&i2c->adapter); if (i2c->dmach) dma_release_channel(i2c->dmach); |