From 97c202968a0e560194121b4b803ed0b63fe62869 Mon Sep 17 00:00:00 2001 From: John Crispin Date: Mon, 6 Oct 2014 20:05:13 +0000 Subject: [PATCH] ralink: various i2c fixes the driver did not handle all states correctly causing a deadlock of the i2c hw block. Signed-off-by: Ing.Michele Mogioni SVN-Revision: 42807 --- ...0052-i2c-MIPS-adds-ralink-I2C-driver.patch | 97 +++++++++++++------ 1 file changed, 66 insertions(+), 31 deletions(-) diff --git a/target/linux/ramips/patches-3.14/0052-i2c-MIPS-adds-ralink-I2C-driver.patch b/target/linux/ramips/patches-3.14/0052-i2c-MIPS-adds-ralink-I2C-driver.patch index 3522bda103..a3b03116e2 100644 --- a/target/linux/ramips/patches-3.14/0052-i2c-MIPS-adds-ralink-I2C-driver.patch +++ b/target/linux/ramips/patches-3.14/0052-i2c-MIPS-adds-ralink-I2C-driver.patch @@ -13,8 +13,10 @@ Signed-off-by: John Crispin create mode 100644 Documentation/devicetree/bindings/i2c/i2c-ralink.txt create mode 100644 drivers/i2c/busses/i2c-ralink.c ---- /dev/null -+++ b/Documentation/devicetree/bindings/i2c/i2c-ralink.txt +Index: linux-3.14.18/Documentation/devicetree/bindings/i2c/i2c-ralink.txt +=================================================================== +--- /dev/null 1970-01-01 00:00:00.000000000 +0000 ++++ linux-3.14.18/Documentation/devicetree/bindings/i2c/i2c-ralink.txt 2014-10-06 14:28:14.296590159 +0200 @@ -0,0 +1,27 @@ +I2C for Ralink platforms + @@ -43,9 +45,11 @@ Signed-off-by: John Crispin + }; + }; +}; ---- a/drivers/i2c/busses/Kconfig -+++ b/drivers/i2c/busses/Kconfig -@@ -659,6 +659,10 @@ config I2C_RIIC +Index: linux-3.14.18/drivers/i2c/busses/Kconfig +=================================================================== +--- linux-3.14.18.orig/drivers/i2c/busses/Kconfig 2014-09-06 01:34:59.000000000 +0200 ++++ linux-3.14.18/drivers/i2c/busses/Kconfig 2014-10-06 14:28:14.296590159 +0200 +@@ -659,6 +659,10 @@ This driver can also be built as a module. If so, the module will be called i2c-riic. @@ -56,9 +60,11 @@ Signed-off-by: John Crispin config HAVE_S3C2410_I2C bool help ---- a/drivers/i2c/busses/Makefile -+++ b/drivers/i2c/busses/Makefile -@@ -63,6 +63,7 @@ obj-$(CONFIG_I2C_PNX) += i2c-pnx.o +Index: linux-3.14.18/drivers/i2c/busses/Makefile +=================================================================== +--- linux-3.14.18.orig/drivers/i2c/busses/Makefile 2014-09-06 01:34:59.000000000 +0200 ++++ linux-3.14.18/drivers/i2c/busses/Makefile 2014-10-06 14:28:14.296590159 +0200 +@@ -63,6 +63,7 @@ obj-$(CONFIG_I2C_PUV3) += i2c-puv3.o obj-$(CONFIG_I2C_PXA) += i2c-pxa.o obj-$(CONFIG_I2C_PXA_PCI) += i2c-pxa-pci.o @@ -66,14 +72,19 @@ Signed-off-by: John Crispin obj-$(CONFIG_I2C_RIIC) += i2c-riic.o obj-$(CONFIG_I2C_S3C2410) += i2c-s3c2410.o obj-$(CONFIG_I2C_S6000) += i2c-s6000.o ---- /dev/null -+++ b/drivers/i2c/busses/i2c-ralink.c -@@ -0,0 +1,271 @@ +Index: linux-3.14.18/drivers/i2c/busses/i2c-ralink.c +=================================================================== +--- /dev/null 1970-01-01 00:00:00.000000000 +0000 ++++ linux-3.14.18/drivers/i2c/busses/i2c-ralink.c 2014-10-06 15:53:32.416500362 +0200 +@@ -0,0 +1,298 @@ +/* + * drivers/i2c/busses/i2c-ralink.c + * + * Copyright (C) 2013 Steven Liu + * ++ * Improve driver for i2cdetect from i2c-tools to detect i2c devices on the bus. ++ * (C) 2014 Sittisak ++ * + * This software is licensed under the terms of the GNU General Public + * License version 2, as published by the Free Software Foundation, and + * may be copied, distributed, and modified under those terms. @@ -96,6 +107,7 @@ Signed-off-by: John Crispin +#include +#include +#include ++#include +#include + +#include @@ -119,7 +131,7 @@ Signed-off-by: John Crispin +#define I2C_DEVADLEN_7 (6 << 2) +#define I2C_ADDRDIS BIT(1) + -+#define I2C_RETRY 0x400 ++#define I2C_RETRY 0x1000 + +#define CLKDIV_VALUE 200 // clock rate is 40M, 40M / (200*2) = 100k (standard i2c bus rate). +//#define CLKDIV_VALUE 50 // clock rate is 40M, 40M / (50*2) = 400k (fast i2c bus rate). @@ -141,6 +153,11 @@ Signed-off-by: John Crispin + return ioread32(membase + reg); +} + ++static inline int rt_i2c_get_ack(void) ++{ ++ return (rt_i2c_r32(REG_STATUS_REG) & I2C_ACKERR) ? -EIO : 0; ++} ++ +static inline int rt_i2c_wait_rx_done(void) +{ + int retries = I2C_RETRY; @@ -150,7 +167,7 @@ Signed-off-by: John Crispin + break; + } while(!(rt_i2c_r32(REG_STATUS_REG) & I2C_DATARDY)); + -+ return (retries < 0); ++ return (retries < 0) ? -ETIMEDOUT : 0; +} + +static inline int rt_i2c_wait_idle(void) @@ -174,7 +191,7 @@ Signed-off-by: John Crispin + break; + } while(!(rt_i2c_r32(REG_STATUS_REG) & I2C_SDOEMPTY)); + -+ return (retries < 0); ++ return (retries < 0) ? -ETIMEDOUT : 0; +} + +static int rt_i2c_handle_msg(struct i2c_adapter *a, struct i2c_msg* msg) @@ -182,7 +199,8 @@ Signed-off-by: John Crispin + int i = 0, j = 0, pos = 0; + int nblock = msg->len / READ_BLOCK; + int rem = msg->len % READ_BLOCK; -+ ++ int ret = 0; ++ /*printk("i2c handle msg len:%d\n",msg->len);*/ + if (msg->flags & I2C_M_TEN) { + printk("10 bits addr not supported\n"); + return -EINVAL; @@ -190,36 +208,51 @@ Signed-off-by: John Crispin + + if (msg->flags & I2C_M_RD) { + for (i = 0; i < nblock; i++) { -+ rt_i2c_wait_idle(); ++ if (rt_i2c_wait_idle()) { ++ printk("i2c-read line busy\n"); ++ return -ETIMEDOUT; ++ } + rt_i2c_w32(READ_BLOCK - 1, REG_BYTECNT_REG); + rt_i2c_w32(READ_CMD, REG_STARTXFR_REG); + for (j = 0; j < READ_BLOCK; j++) { -+ if (rt_i2c_wait_rx_done()) -+ return -1; ++ if (rt_i2c_wait_rx_done()<0) ret = rt_i2c_wait_rx_done(); ++ if (rt_i2c_get_ack()<0) ret = rt_i2c_get_ack(); + msg->buf[pos++] = rt_i2c_r32(REG_DATAIN_REG); + } + } + -+ rt_i2c_wait_idle(); ++ if (rt_i2c_wait_idle()) { ++ printk("i2c-read line busy\n"); ++ return -ETIMEDOUT; ++ } ++ if (rem){ + rt_i2c_w32(rem - 1, REG_BYTECNT_REG); + rt_i2c_w32(READ_CMD, REG_STARTXFR_REG); ++ } + for (i = 0; i < rem; i++) { -+ if (rt_i2c_wait_rx_done()) -+ return -1; ++ if (rt_i2c_wait_rx_done()<0) ret = rt_i2c_wait_rx_done(); ++ if (rt_i2c_get_ack() <0) ret = rt_i2c_get_ack(); ++ + msg->buf[pos++] = rt_i2c_r32(REG_DATAIN_REG); + } + } else { -+ rt_i2c_wait_idle(); ++ if (rt_i2c_wait_idle()) { ++ printk("i2c-write line busy\n"); ++ return -ETIMEDOUT; ++ } + rt_i2c_w32(msg->len - 1, REG_BYTECNT_REG); + for (i = 0; i < msg->len; i++) { + rt_i2c_w32(msg->buf[i], REG_DATAOUT_REG); + rt_i2c_w32(WRITE_CMD, REG_STARTXFR_REG); -+ if (rt_i2c_wait_tx_done()) -+ return -1; ++ ++ if (rt_i2c_wait_tx_done()<0) ret = rt_i2c_wait_tx_done(); ++ if (rt_i2c_get_ack()<0) ret = rt_i2c_get_ack(); ++ ++ + } + } + -+ return 0; ++ return ret; +} + +static int rt_i2c_master_xfer(struct i2c_adapter *a, struct i2c_msg *m, int n) @@ -228,8 +261,8 @@ Signed-off-by: John Crispin + int ret = 0; + + if (rt_i2c_wait_idle()) { -+ printk("i2c transfer failed\n"); -+ return 0; ++ printk("i2c-master_xfer line busy\n"); ++ return -ETIMEDOUT; + } + + device_reset(a->dev.parent); @@ -238,12 +271,12 @@ Signed-off-by: John Crispin + rt_i2c_w32(I2C_DEVADLEN_7 | I2C_ADDRDIS, REG_CONFIG_REG); + rt_i2c_w32(CLKDIV_VALUE, REG_CLKDIV_REG); + -+ for (i = 0; i < n && !ret; i++) ++ for (i = 0; i < n && !ret; i++) { + ret = rt_i2c_handle_msg(a, &m[i]); + -+ if (ret) { -+ printk("i2c transfer failed\n"); -+ return 0; ++ if (ret < 0) { ++ return ret; ++ } + } + + return n; @@ -292,6 +325,8 @@ Signed-off-by: John Crispin + if (ret) + return ret; + ++ of_i2c_register_devices(adapter); ++ + platform_set_drvdata(pdev, adapter); + + dev_info(&pdev->dev, "loaded\n"); -- 2.30.2