Hi everyone,
As I saw it's not the first time someone is asking the patch, I prefer to publish it for the future. Here the patch we used on 2.6.35 kernel :
--------------------------
diff -Naur a/arch/arm/plat-mxs/include/mach/device.h b/arch/arm/plat-mxs/include/mach/device.h
--- a/arch/arm/plat-mxs/include/mach/device.h 2013-05-02 18:20:09.000000000 +0200
+++ b/arch/arm/plat-mxs/include/mach/device.h 2013-05-02 18:32:23.000000000 +0200
@@ -62,6 +62,7 @@
struct mxs_i2c_plat_data {
unsigned int pioqueue_mode:1;
+ unsigned int speed;
};
struct mxs_lradc_plat_data {
@@ -128,7 +129,7 @@
struct mxs_spi_platform_data {
int (*hw_pin_init)(void);
int (*hw_pin_release)(void);
-
+ struct platform_device * cli;
char *clk;
};
diff -Naur a/drivers/i2c/busses/i2c-mxs.c b/drivers/i2c/busses/i2c-mxs.c
--- a/drivers/i2c/busses/i2c-mxs.c 2013-05-02 18:20:11.000000000 +0200
+++ b/drivers/i2c/busses/i2c-mxs.c 2013-05-02 18:32:23.000000000 +0200
@@ -35,15 +35,9 @@
#include <mach/regs-i2c.h>
#include <mach/system.h>
#include <mach/hardware.h>
-
+#include <linux/spinlock.h>
#include "i2c-mxs.h"
-/* 2 for read, 1 for write */
-#define NR_DESC 3
-static struct mxs_dma_desc *desc[NR_DESC];
-static dma_addr_t i2c_buf_phys;
-static u8 *i2c_buf_virt;
-
#define CMD_I2C_SELECT (BM_I2C_CTRL0_RETAIN_CLOCK | \
BM_I2C_CTRL0_PRE_SEND_START | \
BM_I2C_CTRL0_MASTER_MODE | \
@@ -67,6 +61,31 @@
#define HW_I2C_QUEUECTRL_CLR HW_I2C_VERSION
#endif
+
+/*
+ * Timing values for the default 24MHz clock supplied into the i2c block.
+ *
+ * The bus can operate at 95kHz or at 400kHz with the following timing
+ * register configurations. The 100kHz mode isn't present because it's
+ * values are not stated in the i.MX233/i.MX28 datasheet. The 95kHz mode
+ * shall be close enough replacement. Therefore when the bus is configured
+ * for 100kHz operation, 95kHz timing settings are actually loaded.
+ *
+ * For details, see i.MX233 [25.4.2 - 25.4.4] and i.MX28 [27.5.2 - 27.5.4].
+ */
+
+static const struct mxs_i2c_speed_config mxs_i2c_95kHz_config = {
+ .timing0 = 0x00780030,
+ .timing1 = 0x00800030,
+ .timing2 = 0x00300030,
+};
+
+static const struct mxs_i2c_speed_config mxs_i2c_400kHz_config = {
+ .timing0 = 0x000f0007,
+ .timing1 = 0x001f000f,
+ .timing2 = 0x00300030,
+};
+
static void hw_i2c_dmachan_reset(struct mxs_i2c_dev *dev)
{
mxs_dma_disable(dev->dma_chan);
@@ -80,6 +99,10 @@
mxs_dma_enable_irq(mxs_i2c->dma_chan, 1);
mxs_reset_block((void __iomem *)mxs_i2c->regbase, 0);
__raw_writel(0x0000FF00, mxs_i2c->regbase + HW_I2C_CTRL1_SET);
+ writel(mxs_i2c->speed.timing0, mxs_i2c->regbase + HW_I2C_TIMING0);
+ writel(mxs_i2c->speed.timing1, mxs_i2c->regbase + HW_I2C_TIMING1);
+ writel(mxs_i2c->speed.timing2, mxs_i2c->regbase + HW_I2C_TIMING2);
+
}
static int hw_i2c_dma_init(struct platform_device *pdev)
@@ -92,14 +115,14 @@
return ret;
for (i = 0; i < NR_DESC; i++) {
- desc[i] = mxs_dma_alloc_desc();
- if (desc[i] == NULL)
+ mxs_i2c->desc[i] = mxs_dma_alloc_desc();
+ if (mxs_i2c->desc[i] == NULL)
goto err;
}
- i2c_buf_virt = dma_alloc_coherent(&pdev->dev,
- PAGE_SIZE, &i2c_buf_phys, GFP_KERNEL);
- if (i2c_buf_virt == NULL)
+ mxs_i2c->i2c_buf_virt = dma_alloc_coherent(&pdev->dev,
+ PAGE_SIZE, &mxs_i2c->i2c_buf_phys, GFP_KERNEL);
+ if (mxs_i2c->i2c_buf_virt == NULL)
goto err;
hw_i2c_dmachan_reset(mxs_i2c);
@@ -109,7 +132,7 @@
err:
while (--i >= 0)
- mxs_dma_free_desc(desc[i]);
+ mxs_dma_free_desc(mxs_i2c->desc[i]);
return -ENOMEM;
}
@@ -125,11 +148,11 @@
mxs_dma_disable(mxs_i2c->dma_chan);
for (i = 0; i < NR_DESC; i++)
- mxs_dma_free_desc(desc[i]);
+ mxs_dma_free_desc(mxs_i2c->desc[i]);
hw_i2c_dmachan_reset(mxs_i2c);
- dma_free_coherent(&pdev->dev, PAGE_SIZE, i2c_buf_virt, i2c_buf_phys);
+ dma_free_coherent(&pdev->dev, PAGE_SIZE, mxs_i2c->i2c_buf_virt, mxs_i2c->i2c_buf_phys);
mxs_dma_release(mxs_i2c->dma_chan, &pdev->dev);
}
@@ -157,34 +180,34 @@
}
-static void hw_i2c_dma_setup_read(u8 addr, void *buff, int len, int flags)
+static void hw_i2c_dma_setup_read(u8 addr, void *buff, int len, int flags,struct mxs_i2c_dev *dev)
{
if (len > (PAGE_SIZE - 4))
BUG();
- memset(&desc[0]->cmd, 0, sizeof(desc[0]->cmd));
- memset(&desc[1]->cmd, 0, sizeof(desc[1]->cmd));
+ memset(&dev->desc[0]->cmd, 0, sizeof(dev->desc[0]->cmd));
+ memset(&dev->desc[1]->cmd, 0, sizeof(dev->desc[1]->cmd));
- desc[0]->cmd.cmd.bits.bytes = 1;
- desc[0]->cmd.cmd.bits.pio_words = 1;
- desc[0]->cmd.cmd.bits.wait4end = 1;
- desc[0]->cmd.cmd.bits.dec_sem = 1;
- desc[0]->cmd.cmd.bits.irq = 0;
- desc[0]->cmd.cmd.bits.chain = 1;
- desc[0]->cmd.cmd.bits.command = DMA_READ;
- desc[0]->cmd.address = i2c_buf_phys;
- desc[0]->cmd.pio_words[0] = CMD_I2C_SELECT;
- i2c_buf_virt[0] = (addr << 1) | I2C_READ;
-
- desc[1]->cmd.cmd.bits.bytes = len;
- desc[1]->cmd.cmd.bits.pio_words = 1;
- desc[1]->cmd.cmd.bits.wait4end = 1;
- desc[1]->cmd.cmd.bits.dec_sem = 1;
- desc[1]->cmd.cmd.bits.irq = 1;
- desc[1]->cmd.cmd.bits.command = DMA_WRITE;
- desc[1]->cmd.address = (u32) i2c_buf_phys + 1;
- desc[1]->cmd.pio_words[0] = CMD_I2C_READ;
- desc[1]->cmd.pio_words[0] |= BF_I2C_CTRL0_XFER_COUNT(len) | flags;
+ dev->desc[0]->cmd.cmd.bits.bytes = 1;
+ dev->desc[0]->cmd.cmd.bits.pio_words = 1;
+ dev->desc[0]->cmd.cmd.bits.wait4end = 1;
+ dev->desc[0]->cmd.cmd.bits.dec_sem = 1;
+ dev->desc[0]->cmd.cmd.bits.irq = 0;
+ dev->desc[0]->cmd.cmd.bits.chain = 1;
+ dev->desc[0]->cmd.cmd.bits.command = DMA_READ;
+ dev->desc[0]->cmd.address = dev->i2c_buf_phys;
+ dev->desc[0]->cmd.pio_words[0] = CMD_I2C_SELECT;
+ dev->i2c_buf_virt[0] = (addr << 1) | I2C_READ;
+
+ dev->desc[1]->cmd.cmd.bits.bytes = len;
+ dev->desc[1]->cmd.cmd.bits.pio_words = 1;
+ dev->desc[1]->cmd.cmd.bits.wait4end = 1;
+ dev->desc[1]->cmd.cmd.bits.dec_sem = 1;
+ dev->desc[1]->cmd.cmd.bits.irq = 1;
+ dev->desc[1]->cmd.cmd.bits.command = DMA_WRITE;
+ dev->desc[1]->cmd.address = (u32) dev->i2c_buf_phys + 1;
+ dev->desc[1]->cmd.pio_words[0] = CMD_I2C_READ;
+ dev->desc[1]->cmd.pio_words[0] |= BF_I2C_CTRL0_XFER_COUNT(len) | flags;
}
static void hw_i2c_pioq_setup_write(struct mxs_i2c_dev *dev,
@@ -219,23 +242,23 @@
__raw_writel(*buf2++, dev->regbase + HW_I2C_DATA);
}
-static void hw_i2c_dma_setup_write(u8 addr, void *buff, int len, int flags)
+static void hw_i2c_dma_setup_write(u8 addr, void *buff, int len, int flags,struct mxs_i2c_dev *dev)
{
- memset(&desc[2]->cmd, 0, sizeof(desc[2]->cmd));
+ memset(&dev->desc[2]->cmd, 0, sizeof(dev->desc[2]->cmd));
- desc[2]->cmd.cmd.bits.bytes = len + 1;
- desc[2]->cmd.cmd.bits.pio_words = 1;
- desc[2]->cmd.cmd.bits.wait4end = 1;
- desc[2]->cmd.cmd.bits.dec_sem = 1;
- desc[2]->cmd.cmd.bits.irq = 1;
- desc[2]->cmd.cmd.bits.command = DMA_READ;
- desc[2]->cmd.address = i2c_buf_phys;
- desc[2]->cmd.pio_words[0] = CMD_I2C_WRITE;
- desc[2]->cmd.pio_words[0] |= BM_I2C_CTRL0_POST_SEND_STOP;
- desc[2]->cmd.pio_words[0] |= BF_I2C_CTRL0_XFER_COUNT(len + 1) | flags;
+ dev->desc[2]->cmd.cmd.bits.bytes = len + 1;
+ dev->desc[2]->cmd.cmd.bits.pio_words = 1;
+ dev->desc[2]->cmd.cmd.bits.wait4end = 1;
+ dev->desc[2]->cmd.cmd.bits.dec_sem = 1;
+ dev->desc[2]->cmd.cmd.bits.irq = 1;
+ dev->desc[2]->cmd.cmd.bits.command = DMA_READ;
+ dev->desc[2]->cmd.address = dev->i2c_buf_phys;
+ dev->desc[2]->cmd.pio_words[0] = CMD_I2C_WRITE;
+ dev->desc[2]->cmd.pio_words[0] |= BM_I2C_CTRL0_POST_SEND_STOP;
+ dev->desc[2]->cmd.pio_words[0] |= BF_I2C_CTRL0_XFER_COUNT(len + 1) | flags;
- i2c_buf_virt[0] = (addr << 1) | I2C_WRITE;
- memcpy(&i2c_buf_virt[1], buff, len);
+ dev->i2c_buf_virt[0] = (addr << 1) | I2C_WRITE;
+ memcpy(&dev->i2c_buf_virt[1], buff, len);
}
static void hw_i2c_pioq_run(struct mxs_i2c_dev *dev)
@@ -246,10 +269,10 @@
static void hw_i2c_dma_run(struct mxs_i2c_dev *dev, int dir)
{
if (dir == I2C_READ) {
- mxs_dma_desc_append(dev->dma_chan, desc[0]);
- mxs_dma_desc_append(dev->dma_chan, desc[1]);
+ mxs_dma_desc_append(dev->dma_chan, dev->desc[0]);
+ mxs_dma_desc_append(dev->dma_chan, dev->desc[1]);
} else
- mxs_dma_desc_append(dev->dma_chan, desc[2]);
+ mxs_dma_desc_append(dev->dma_chan, dev->desc[2]);
mxs_dma_enable(dev->dma_chan);
}
@@ -276,7 +299,7 @@
memcpy(buff, buf1, len);
} else
- memcpy(buff, &i2c_buf_virt[1], len);
+ memcpy(buff, &dev->i2c_buf_virt[1], len);
}
/*
@@ -288,7 +311,7 @@
struct mxs_i2c_dev *dev = i2c_get_adapdata(adap);
int err;
int flags;
-
+
init_completion(&dev->cmd_complete);
dev->cmd_err = 0;
@@ -299,7 +322,6 @@
return -EINVAL;
flags = stop ? BM_I2C_CTRL0_POST_SEND_STOP : 0;
-
if (msg->flags & I2C_M_RD) {
if (dev->flags & MXS_I2C_PIOQUEUE_MODE) {
hw_i2c_pioq_setup_read(dev,
@@ -307,8 +329,9 @@
msg->buf, msg->len, flags);
hw_i2c_pioq_run(dev);
} else {
+
hw_i2c_dma_setup_read(msg->addr,
- msg->buf, msg->len, flags);
+ msg->buf, msg->len, flags,dev);
hw_i2c_dma_run(dev, I2C_READ);
}
@@ -320,53 +343,71 @@
hw_i2c_pioq_run(dev);
} else {
hw_i2c_dma_setup_write(msg->addr,
- msg->buf, msg->len, flags);
+ msg->buf, msg->len, flags,dev);
hw_i2c_dma_run(dev, I2C_WRITE);
+
}
}
-
err = wait_for_completion_interruptible_timeout(&dev->cmd_complete,
msecs_to_jiffies(1000)
);
- if (err <= 0) {
- mxs_i2c_reset(dev);
+ if (err == 0) {
dev_dbg(dev->dev, "controller is timed out\n");
- return -ETIMEDOUT;
+ dev->cmd_err = -ETIMEDOUT;
+ hw_i2c_dmachan_reset(dev);
+ mxs_i2c_reset(dev);
+ goto done;
}
if ((!dev->cmd_err) && (msg->flags & I2C_M_RD))
hw_i2c_finish_read(dev, msg->buf, msg->len);
+
+ /* No Slave ack */
+ if (dev->cmd_err == -ENXIO) {
+ mxs_i2c_reset(dev);
+ hw_i2c_dmachan_reset(dev);
+ goto done;
+ } else if (dev->cmd_err == -EIO) {
+ printk(KERN_WARNING "%s: I2C Fault!\n", __func__);
+ hw_i2c_dmachan_reset(dev);
+ mxs_i2c_reset(dev);
+ goto done;
+ }
- dev_dbg(dev->dev, "Done with err=%d\n", dev->cmd_err);
+ if ((!dev->cmd_err) && (msg->flags & I2C_M_RD))
+ {
+ hw_i2c_finish_read(dev, msg->buf, msg->len);
+ }
+done:
+ dev_dbg(dev->dev, "Done with err=%d\n", dev->cmd_err);
return dev->cmd_err;
}
-static int
-mxs_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[], int num)
+static int mxs_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[], int num)
{
int i;
int err;
-
if (!msgs->len)
+ {
return -EINVAL;
-
+ }
for (i = 0; i < num; i++) {
err = mxs_i2c_xfer_msg(adap, &msgs[i], (i == (num - 1)));
if (err)
break;
}
-
if (err == 0)
err = num;
- return err;
+ return err;
}
static u32 mxs_i2c_func(struct i2c_adapter *adap)
{
return I2C_FUNC_I2C | (I2C_FUNC_SMBUS_EMUL & ~I2C_FUNC_SMBUS_QUICK);
}
+#define I2C_IRQ_MASK 0x000000FF
static irqreturn_t mxs_i2c_dma_isr(int this_irq, void *dev_id)
{
@@ -389,20 +430,21 @@
complete(&mxs_i2c->cmd_complete);
}
-#define I2C_IRQ_MASK 0x000000FF
+
static irqreturn_t mxs_i2c_isr(int this_irq, void *dev_id)
{
struct mxs_i2c_dev *mxs_i2c = dev_id;
u32 stat;
u32 done_mask =
BM_I2C_CTRL1_DATA_ENGINE_CMPLT_IRQ | BM_I2C_CTRL1_BUS_FREE_IRQ;
-
stat = __raw_readl(mxs_i2c->regbase + HW_I2C_CTRL1) & I2C_IRQ_MASK;
+
if (!stat)
return IRQ_NONE;
if (stat & BM_I2C_CTRL1_NO_SLAVE_ACK_IRQ) {
- mxs_i2c->cmd_err = -EREMOTEIO;
+ mxs_i2c->cmd_err = -ENXIO;
+
/* it takes long time to reset i2c */
schedule_work(&mxs_i2c->work);
goto done;
@@ -499,6 +541,13 @@
goto no_dma_irq;
}
+
+ if (pdata->speed == 400000)
+ mxs_i2c->speed = mxs_i2c_400kHz_config;
+ else
+ mxs_i2c->speed = mxs_i2c_95kHz_config;
+
+
/* reset I2C module */
mxs_reset_block((void __iomem *)mxs_i2c->regbase, 1);
platform_set_drvdata(pdev, mxs_i2c);
@@ -537,7 +586,6 @@
}
INIT_WORK(&mxs_i2c->work, mxs_i2c_task);
-
return 0;
no_i2c_adapter:
diff -Naur a/drivers/i2c/busses/i2c-mxs.h b/drivers/i2c/busses/i2c-mxs.h
--- a/drivers/i2c/busses/i2c-mxs.h 2013-05-02 18:20:08.000000000 +0200
+++ b/drivers/i2c/busses/i2c-mxs.h 2013-05-02 18:32:23.000000000 +0200
@@ -19,8 +19,16 @@
#ifndef _I2C_H
#define _I2C_H
+/* 2 for read, 1 for write */
#define I2C_READ 1
#define I2C_WRITE 0
+#define NR_DESC 3
+
+struct mxs_i2c_speed_config {
+ u32 timing0;
+ u32 timing1;
+ u32 timing2;
+};
struct mxs_i2c_dev {
struct device *dev;
@@ -38,5 +46,9 @@
spinlock_t lock;
wait_queue_head_t queue;
struct work_struct work;
+ struct mxs_i2c_speed_config speed;
+ u8 *i2c_buf_virt;
+ dma_addr_t i2c_buf_phys;
+ struct mxs_dma_desc *desc[NR_DESC];
};
#endif
diff -Naur a/drivers/i2c/busses/Kconfig b/drivers/i2c/busses/Kconfig
--- a/drivers/i2c/busses/Kconfig 2013-05-02 18:20:05.000000000 +0200
+++ b/drivers/i2c/busses/Kconfig 2013-05-02 18:32:23.000000000 +0200
@@ -470,6 +470,12 @@
say yes if you are sure transfer length is eqaul to or less than 24 bytes.
Otherwise say no to use DMA mode by default.
+config I2C_MXS_SELECT0_400_MODE
+ bool "MXS I2C0 speed at 400kHz"
+ depends on (I2C_MXS_SELECT0 && !ARCH_MX23)
+ help
+ say yes if you want to have 400kHz speed I2C.
+
config I2C_MXS_SELECT1
bool "Enable I2C1 module"
depends on (I2C_MXS && !ARCH_MX23)
@@ -483,6 +489,12 @@
say yes if you are sure transfer length is eqaul to or less than 24 bytes.
Otherwise say no to use DMA mode by default.
+config I2C_MXS_SELECT1_400_MODE
+ bool "MXS I2C1 speed at 400kHz"
+ depends on (I2C_MXS_SELECT1 && !ARCH_MX23)
+ help
+ say yes if you want to have 400kHz speed I2C.
+
config I2C_STMP378X
tristate "STMP378x I2C adapter"
depends on MACH_STMP378X
--------------------------