diff options
-rw-r--r-- | target/linux/ramips/patches-4.4/0044-i2c-MIPS-adds-ralink-I2C-driver.patch | 441 | ||||
-rw-r--r-- | target/linux/ramips/patches-4.4/0045-i2c-add-mt7621-driver.patch | 541 |
2 files changed, 371 insertions, 611 deletions
diff --git a/target/linux/ramips/patches-4.4/0044-i2c-MIPS-adds-ralink-I2C-driver.patch b/target/linux/ramips/patches-4.4/0044-i2c-MIPS-adds-ralink-I2C-driver.patch index 21872082dd..31854eff4b 100644 --- a/target/linux/ramips/patches-4.4/0044-i2c-MIPS-adds-ralink-I2C-driver.patch +++ b/target/linux/ramips/patches-4.4/0044-i2c-MIPS-adds-ralink-I2C-driver.patch @@ -45,13 +45,12 @@ Signed-off-by: John Crispin <blogic@openwrt.org> +}; --- a/drivers/i2c/busses/Kconfig +++ b/drivers/i2c/busses/Kconfig -@@ -806,6 +806,11 @@ config I2C_RK3X +@@ -806,6 +806,10 @@ config I2C_RK3X This driver can also be built as a module. If so, the module will be called i2c-rk3x. +config I2C_RALINK + tristate "Ralink I2C Controller" -+ depends on RALINK && !SOC_MT7621 + select OF_I2C + config HAVE_S3C2410_I2C @@ -69,12 +68,11 @@ Signed-off-by: John Crispin <blogic@openwrt.org> obj-$(CONFIG_I2C_RK3X) += i2c-rk3x.o --- /dev/null +++ b/drivers/i2c/busses/i2c-ralink.c -@@ -0,0 +1,435 @@ +@@ -0,0 +1,327 @@ +/* + * drivers/i2c/busses/i2c-ralink.c + * + * Copyright (C) 2013 Steven Liu <steven_liu@mediatek.com> -+ * Copyright (C) 2016 Michael Lee <igvtee@gmail.com> + * + * Improve driver for i2cdetect from i2c-tools to detect i2c devices on the bus. + * (C) 2014 Sittisak <sittisaks@hotmail.com> @@ -103,7 +101,8 @@ Signed-off-by: John Crispin <blogic@openwrt.org> +#include <linux/i2c.h> +#include <linux/io.h> +#include <linux/err.h> -+#include <linux/clk.h> ++ ++#include <asm/mach-ralink/ralink_regs.h> + +#define REG_CONFIG_REG 0x00 +#define REG_CLKDIV_REG 0x04 @@ -114,250 +113,191 @@ Signed-off-by: John Crispin <blogic@openwrt.org> +#define REG_STATUS_REG 0x18 +#define REG_STARTXFR_REG 0x1C +#define REG_BYTECNT_REG 0x20 ++#define REG_SM0CFG2 0x28 ++#define REG_SM0CTL0 0x40 + -+/* REG_CONFIG_REG */ -+#define I2C_ADDRLEN_OFFSET 5 -+#define I2C_DEVADLEN_OFFSET 2 -+#define I2C_ADDRLEN_MASK 0x3 -+#define I2C_ADDR_DIS BIT(1) -+#define I2C_DEVADDR_DIS BIT(0) -+#define I2C_ADDRLEN_8 (7 << I2C_ADDRLEN_OFFSET) -+#define I2C_DEVADLEN_7 (6 << I2C_DEVADLEN_OFFSET) -+#define I2C_CONF_DEFAULT (I2C_ADDRLEN_8 | I2C_DEVADLEN_7) -+ -+/* REG_CLKDIV_REG */ -+#define I2C_CLKDIV_MASK 0xffff -+ -+/* REG_DEVADDR_REG */ -+#define I2C_DEVADDR_MASK 0x7f -+ -+/* REG_ADDR_REG */ -+#define I2C_ADDR_MASK 0xff -+ -+/* REG_STATUS_REG */ +#define I2C_STARTERR BIT(4) +#define I2C_ACKERR BIT(3) +#define I2C_DATARDY BIT(2) +#define I2C_SDOEMPTY BIT(1) +#define I2C_BUSY BIT(0) + -+/* REG_STARTXFR_REG */ -+#define NOSTOP_CMD BIT(2) -+#define NODATA_CMD BIT(1) -+#define READ_CMD BIT(0) ++#define I2C_DEVADLEN_7 (6 << 2) ++#define I2C_ADDRDIS BIT(1) + -+/* REG_BYTECNT_REG */ -+#define BYTECNT_MAX 64 -+#define SET_BYTECNT(x) (x - 1) ++#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). ++ ++#define READ_CMD 0x01 ++#define WRITE_CMD 0x00 ++#define READ_BLOCK 64 ++ ++#define SM0CTL0_OD BIT(31) ++#define SM0CTL0_VTRIG BIT(28) ++#define SM0CTL0_OUTHI BIT(6) ++#define SM0CTL0_STRETCH BIT(1) ++#define SM0CTL0_DEFAULT (SM0CTL0_OD | SM0CTL0_VTRIG | SM0CTL0_OUTHI | SM0CTL0_STRETCH) + +/* timeout waiting for I2C devices to respond (clock streching) */ -+#define TIMEOUT_MS 1000 -+#define DELAY_INTERVAL_US 100 -+ -+struct rt_i2c { -+ void __iomem *base; -+ struct clk *clk; -+ struct device *dev; -+ struct i2c_adapter adap; -+ u32 cur_clk; -+ u32 clk_div; -+ u32 flags; ++#define RT_I2C_TIMEOUT (msecs_to_jiffies(1000)) ++ ++enum { ++ I2C_TYPE_RALINK, ++ I2C_TYPE_MEDIATEK, +}; + -+static void rt_i2c_w32(struct rt_i2c *i2c, u32 val, unsigned reg) ++static void __iomem *membase; ++static struct i2c_adapter *adapter; ++static int hw_type; ++ ++static void rt_i2c_w32(u32 val, unsigned reg) +{ -+ iowrite32(val, i2c->base + reg); ++ iowrite32(val, membase + reg); +} + -+static u32 rt_i2c_r32(struct rt_i2c *i2c, unsigned reg) ++static u32 rt_i2c_r32(unsigned reg) +{ -+ return ioread32(i2c->base + reg); ++ return ioread32(membase + reg); +} + -+static int poll_down_timeout(void __iomem *addr, u32 mask) ++static inline int rt_i2c_get_ack(void) +{ -+ unsigned long timeout = jiffies + msecs_to_jiffies(TIMEOUT_MS); ++ return (rt_i2c_r32(REG_STATUS_REG) & I2C_ACKERR) ? -EIO : 0; ++} ++ ++static inline int rt_i2c_wait_rx_done(void) ++{ ++ unsigned long timeout; ++ ++ timeout = jiffies + RT_I2C_TIMEOUT; + + do { -+ if (!(readl_relaxed(addr) & mask)) -+ return 0; ++ if (time_after(jiffies, timeout)) ++ return (-ETIMEDOUT); + -+ usleep_range(DELAY_INTERVAL_US, DELAY_INTERVAL_US + 50); -+ } while (time_before(jiffies, timeout)); ++ } while (!(rt_i2c_r32(REG_STATUS_REG) & I2C_DATARDY)); + -+ return (readl_relaxed(addr) & mask) ? -EAGAIN : 0; ++ return 0; +} + -+static int rt_i2c_wait_idle(struct rt_i2c *i2c) ++static inline int rt_i2c_wait_idle(void) +{ -+ int ret; ++ unsigned long timeout; + -+ ret = poll_down_timeout(i2c->base + REG_STATUS_REG, I2C_BUSY); -+ if (ret < 0) -+ dev_dbg(i2c->dev, "idle err(%d)\n", ret); ++ timeout = jiffies + RT_I2C_TIMEOUT; + -+ return ret; ++ do { ++ if (time_after(jiffies, timeout)) { ++ printk("i2c-read line busy\n"); ++ return 1; ++ } ++ } while (rt_i2c_r32(REG_STATUS_REG) & I2C_BUSY); ++ ++ return 0; +} + -+static int poll_up_timeout(void __iomem *addr, u32 mask) ++static inline int rt_i2c_wait_tx_done(void) +{ -+ unsigned long timeout = jiffies + msecs_to_jiffies(TIMEOUT_MS); -+ u32 status; ++ unsigned long timeout; + -+ do { -+ status = readl_relaxed(addr); ++ timeout = jiffies + RT_I2C_TIMEOUT; + -+ /* check error status */ -+ if (status & I2C_STARTERR) -+ return -EAGAIN; -+ else if (status & I2C_ACKERR) -+ return -ENXIO; -+ else if (status & mask) -+ return 0; ++ do { ++ if (time_after(jiffies, timeout)) ++ return (-ETIMEDOUT); + -+ usleep_range(DELAY_INTERVAL_US, DELAY_INTERVAL_US + 50); -+ } while (time_before(jiffies, timeout)); ++ } while (!(rt_i2c_r32(REG_STATUS_REG) & I2C_SDOEMPTY)); + -+ return -ETIMEDOUT; ++ return 0; +} + -+static int rt_i2c_wait_rx_done(struct rt_i2c *i2c) ++static int rt_i2c_handle_msg(struct i2c_adapter *a, struct i2c_msg* msg) +{ -+ int ret; -+ -+ ret = poll_up_timeout(i2c->base + REG_STATUS_REG, I2C_DATARDY); -+ if (ret < 0) -+ dev_dbg(i2c->dev, "rx err(%d)\n", ret); ++ int i = 0, j = 0, pos = 0; ++ int nblock = msg->len / READ_BLOCK; ++ int rem = msg->len % READ_BLOCK; ++ int ret = 0; ++ ++ if (msg->flags & I2C_M_TEN) { ++ printk("10 bits addr not supported\n"); ++ return -EINVAL; ++ } + -+ return ret; -+} ++ if (msg->flags & I2C_M_RD) { ++ for (i = 0; i < nblock; i++) { ++ if (rt_i2c_wait_idle()) ++ 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() < 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); ++ } ++ } + -+static int rt_i2c_wait_tx_done(struct rt_i2c *i2c) -+{ -+ int ret; ++ if (rt_i2c_wait_idle()) ++ 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() < 0) ++ ret = rt_i2c_wait_rx_done(); ++ if (rt_i2c_get_ack() < 0) ++ ret = rt_i2c_get_ack(); + -+ ret = poll_up_timeout(i2c->base + REG_STATUS_REG, I2C_SDOEMPTY); -+ if (ret < 0) -+ dev_dbg(i2c->dev, "tx err(%d)\n", ret); ++ msg->buf[pos++] = rt_i2c_r32(REG_DATAIN_REG); ++ } ++ } else { ++ if (rt_i2c_wait_idle()) ++ 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() < 0) ++ ret = rt_i2c_wait_tx_done(); ++ if (rt_i2c_get_ack() < 0) ++ ret = rt_i2c_get_ack(); ++ } ++ } + + return ret; +} + -+static void rt_i2c_reset(struct rt_i2c *i2c) ++static int rt_i2c_master_xfer(struct i2c_adapter *a, struct i2c_msg *m, int n) +{ -+ device_reset(i2c->adap.dev.parent); -+ barrier(); -+ rt_i2c_w32(i2c, i2c->clk_div, REG_CLKDIV_REG); -+} ++ int i = 0; ++ int ret = 0; + -+static void rt_i2c_dump_reg(struct rt_i2c *i2c) -+{ -+ dev_dbg(i2c->dev, "conf %08x, clkdiv %08x, devaddr %08x, " \ -+ "addr %08x, dataout %08x, datain %08x, " \ -+ "status %08x, startxfr %08x, bytecnt %08x\n", -+ rt_i2c_r32(i2c, REG_CONFIG_REG), -+ rt_i2c_r32(i2c, REG_CLKDIV_REG), -+ rt_i2c_r32(i2c, REG_DEVADDR_REG), -+ rt_i2c_r32(i2c, REG_ADDR_REG), -+ rt_i2c_r32(i2c, REG_DATAOUT_REG), -+ rt_i2c_r32(i2c, REG_DATAIN_REG), -+ rt_i2c_r32(i2c, REG_STATUS_REG), -+ rt_i2c_r32(i2c, REG_STARTXFR_REG), -+ rt_i2c_r32(i2c, REG_BYTECNT_REG)); -+} ++ if (rt_i2c_wait_idle()) ++ return -ETIMEDOUT; + -+static int rt_i2c_master_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs, -+ int num) -+{ -+ struct rt_i2c *i2c; -+ struct i2c_msg *pmsg; -+ unsigned char addr; -+ int i, j, ret; -+ u32 cmd; -+ -+ i2c = i2c_get_adapdata(adap); -+ -+ for (i = 0; i < num; i++) { -+ pmsg = &msgs[i]; -+ if (i == (num - 1)) -+ cmd = 0; -+ else -+ cmd = NOSTOP_CMD; -+ -+ dev_dbg(i2c->dev, "addr: 0x%x, len: %d, flags: 0x%x, stop: %d\n", -+ pmsg->addr, pmsg->len, pmsg->flags, -+ (cmd == 0)? 1 : 0); -+ -+ /* wait hardware idle */ -+ if ((ret = rt_i2c_wait_idle(i2c))) -+ goto err_timeout; -+ -+ if (pmsg->flags & I2C_M_TEN) { -+ rt_i2c_w32(i2c, I2C_CONF_DEFAULT, REG_CONFIG_REG); -+ /* 10 bits address */ -+ addr = 0x78 | ((pmsg->addr >> 8) & 0x03); -+ rt_i2c_w32(i2c, addr & I2C_DEVADDR_MASK, -+ REG_DEVADDR_REG); -+ rt_i2c_w32(i2c, pmsg->addr & I2C_ADDR_MASK, -+ REG_ADDR_REG); -+ } else { -+ rt_i2c_w32(i2c, I2C_CONF_DEFAULT | I2C_ADDR_DIS, -+ REG_CONFIG_REG); -+ /* 7 bits address */ -+ rt_i2c_w32(i2c, pmsg->addr & I2C_DEVADDR_MASK, -+ REG_DEVADDR_REG); -+ } ++ device_reset(a->dev.parent); + -+ /* buffer length */ -+ if (pmsg->len == 0) -+ cmd |= NODATA_CMD; -+ else -+ rt_i2c_w32(i2c, SET_BYTECNT(pmsg->len), -+ REG_BYTECNT_REG); -+ -+ j = 0; -+ if (pmsg->flags & I2C_M_RD) { -+ cmd |= READ_CMD; -+ /* start transfer */ -+ barrier(); -+ rt_i2c_w32(i2c, cmd, REG_STARTXFR_REG); -+ do { -+ /* wait */ -+ if ((ret = rt_i2c_wait_rx_done(i2c))) -+ goto err_timeout; -+ /* read data */ -+ if (pmsg->len) -+ pmsg->buf[j] = rt_i2c_r32(i2c, -+ REG_DATAIN_REG); -+ j++; -+ } while (j < pmsg->len); -+ } else { -+ do { -+ /* write data */ -+ if (pmsg->len) -+ rt_i2c_w32(i2c, pmsg->buf[j], -+ REG_DATAOUT_REG); -+ /* start transfer */ -+ if (j == 0) { -+ barrier(); -+ rt_i2c_w32(i2c, cmd, REG_STARTXFR_REG); -+ } -+ /* wait */ -+ if ((ret = rt_i2c_wait_tx_done(i2c))) -+ goto err_timeout; -+ j++; -+ } while (j < pmsg->len); -+ } ++ rt_i2c_w32(m->addr, REG_DEVADDR_REG); ++ rt_i2c_w32(I2C_DEVADLEN_7 | I2C_ADDRDIS, REG_CONFIG_REG); ++ if (hw_type == I2C_TYPE_RALINK) { ++ rt_i2c_w32(CLKDIV_VALUE, REG_CLKDIV_REG); ++ } else { ++ rt_i2c_w32((CLKDIV_VALUE << 16) | SM0CTL0_DEFAULT, REG_SM0CTL0); ++ rt_i2c_w32(1, REG_SM0CFG2); + } -+ /* the return value is number of executed messages */ -+ ret = i; + -+ return ret; ++ for (i = 0; i < n && !ret; i++) { ++ ret = rt_i2c_handle_msg(a, &m[i]); + -+err_timeout: -+ rt_i2c_dump_reg(i2c); -+ rt_i2c_reset(i2c); -+ return ret; ++ if (ret < 0) { ++ return ret; ++ } ++ } ++ ++ return n; +} + +static u32 rt_i2c_func(struct i2c_adapter *a) @@ -371,110 +311,60 @@ Signed-off-by: John Crispin <blogic@openwrt.org> +}; + +static const struct of_device_id i2c_rt_dt_ids[] = { -+ { .compatible = "ralink,rt2880-i2c" }, ++ { .compatible = "ralink,rt2880-i2c", .data = (void *) I2C_TYPE_RALINK }, ++ { .compatible = "mediatek,mt7628-i2c", .data = (void *) I2C_TYPE_MEDIATEK }, + { /* sentinel */ } +}; + +MODULE_DEVICE_TABLE(of, i2c_rt_dt_ids); + -+static struct i2c_adapter_quirks rt_i2c_quirks = { -+ .max_write_len = BYTECNT_MAX, -+ .max_read_len = BYTECNT_MAX, -+}; -+ -+static int rt_i2c_init(struct rt_i2c *i2c) -+{ -+ u32 reg; -+ -+ /* i2c_sclk = periph_clk / ((2 * clk_div) + 5) */ -+ i2c->clk_div = (clk_get_rate(i2c->clk) - (5 * i2c->cur_clk)) / -+ (2 * i2c->cur_clk); -+ if (i2c->clk_div < 8) -+ i2c->clk_div = 8; -+ if (i2c->clk_div > I2C_CLKDIV_MASK) -+ i2c->clk_div = I2C_CLKDIV_MASK; -+ -+ /* check support combinde/repeated start message */ -+ rt_i2c_w32(i2c, NOSTOP_CMD, REG_STARTXFR_REG); -+ reg = rt_i2c_r32(i2c, REG_STARTXFR_REG) & NOSTOP_CMD; -+ -+ rt_i2c_reset(i2c); -+ -+ return reg; -+} -+ +static int rt_i2c_probe(struct platform_device *pdev) +{ -+ struct resource *res; -+ struct rt_i2c *i2c; -+ struct i2c_adapter *adap; ++ struct resource *res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + const struct of_device_id *match; -+ int ret, restart; ++ int ret; + + match = of_match_device(i2c_rt_dt_ids, &pdev->dev); ++ hw_type = (int) match->data; + -+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + if (!res) { + dev_err(&pdev->dev, "no memory resource found\n"); + return -ENODEV; + } + -+ i2c = devm_kzalloc(&pdev->dev, sizeof(struct rt_i2c), GFP_KERNEL); -+ if (!i2c) { ++ adapter = devm_kzalloc(&pdev->dev, sizeof(struct i2c_adapter), GFP_KERNEL); ++ if (!adapter) { + dev_err(&pdev->dev, "failed to allocate i2c_adapter\n"); + return -ENOMEM; + } + -+ i2c->base = devm_ioremap_resource(&pdev->dev, res); -+ if (IS_ERR(i2c->base)) -+ return PTR_ERR(i2c->base); -+ -+ i2c->clk = devm_clk_get(&pdev->dev, NULL); -+ if (IS_ERR(i2c->clk)) { -+ dev_err(&pdev->dev, "no clock defined\n"); -+ return -ENODEV; -+ } -+ clk_prepare_enable(i2c->clk); -+ i2c->dev = &pdev->dev; -+ -+ if (of_property_read_u32(pdev->dev.of_node, -+ "clock-frequency", &i2c->cur_clk)) -+ i2c->cur_clk = 100000; -+ -+ adap = &i2c->adap; -+ adap->owner = THIS_MODULE; -+ adap->class = I2C_CLASS_HWMON | I2C_CLASS_SPD; -+ adap->algo = &rt_i2c_algo; -+ adap->retries = 3; -+ adap->dev.parent = &pdev->dev; -+ i2c_set_adapdata(adap, i2c); -+ adap->dev.of_node = pdev->dev.of_node; -+ strlcpy(adap->name, dev_name(&pdev->dev), sizeof(adap->name)); -+ adap->quirks = &rt_i2c_quirks; -+ -+ platform_set_drvdata(pdev, i2c); -+ -+ restart = rt_i2c_init(i2c); -+ -+ ret = i2c_add_adapter(adap); -+ if (ret < 0) { -+ dev_err(&pdev->dev, "failed to add adapter\n"); -+ clk_disable_unprepare(i2c->clk); ++ membase = devm_ioremap_resource(&pdev->dev, res); ++ if (IS_ERR(membase)) ++ return PTR_ERR(membase); ++ ++ strlcpy(adapter->name, dev_name(&pdev->dev), sizeof(adapter->name)); ++ adapter->owner = THIS_MODULE; ++ adapter->nr = pdev->id; ++ adapter->timeout = HZ; ++ adapter->algo = &rt_i2c_algo; ++ adapter->class = I2C_CLASS_HWMON | I2C_CLASS_SPD; ++ adapter->dev.parent = &pdev->dev; ++ adapter->dev.of_node = pdev->dev.of_node; ++ ++ ret = i2c_add_numbered_adapter(adapter); ++ if (ret) + return ret; -+ } + -+ dev_info(&pdev->dev, "clock %uKHz, re-start %ssupport\n", -+ i2c->cur_clk/1000, restart ? "" : "not "); ++ platform_set_drvdata(pdev, adapter); + -+ return ret; ++ dev_info(&pdev->dev, "loaded\n"); ++ ++ return 0; +} + +static int rt_i2c_remove(struct platform_device *pdev) +{ -+ struct rt_i2c *i2c = platform_get_drvdata(pdev); -+ -+ i2c_del_adapter(&i2c->adap); -+ clk_disable_unprepare(i2c->clk); ++ platform_set_drvdata(pdev, NULL); + + return 0; +} @@ -499,7 +389,8 @@ Signed-off-by: John Crispin <blogic@openwrt.org> +{ + platform_driver_unregister(&rt_i2c_driver); +} -+module_exit(i2c_rt_exit); ++ ++module_exit (i2c_rt_exit); + +MODULE_AUTHOR("Steven Liu <steven_liu@mediatek.com>"); +MODULE_DESCRIPTION("Ralink I2c host driver"); diff --git a/target/linux/ramips/patches-4.4/0045-i2c-add-mt7621-driver.patch b/target/linux/ramips/patches-4.4/0045-i2c-add-mt7621-driver.patch index df8b3a4431..044991594b 100644 --- a/target/linux/ramips/patches-4.4/0045-i2c-add-mt7621-driver.patch +++ b/target/linux/ramips/patches-4.4/0045-i2c-add-mt7621-driver.patch @@ -13,13 +13,12 @@ Signed-off-by: John Crispin <blogic@openwrt.org> --- a/drivers/i2c/busses/Kconfig +++ b/drivers/i2c/busses/Kconfig -@@ -811,6 +811,11 @@ config I2C_RALINK - depends on RALINK && !SOC_MT7621 +@@ -810,6 +810,10 @@ config I2C_RALINK + tristate "Ralink I2C Controller" select OF_I2C +config I2C_MT7621 -+ tristate "MT7621/MT7628 I2C Controller" -+ depends on RALINK && (SOC_MT7620 || SOC_MT7621) ++ tristate "MT7621 I2C Controller" + select OF_I2C + config HAVE_S3C2410_I2C @@ -37,12 +36,11 @@ Signed-off-by: John Crispin <blogic@openwrt.org> obj-$(CONFIG_I2C_RK3X) += i2c-rk3x.o --- /dev/null +++ b/drivers/i2c/busses/i2c-mt7621.c -@@ -0,0 +1,433 @@ +@@ -0,0 +1,303 @@ +/* + * drivers/i2c/busses/i2c-mt7621.c + * + * Copyright (C) 2013 Steven Liu <steven_liu@mediatek.com> -+ * Copyright (C) 2016 Michael Lee <igvtee@gmail.com> + * + * Improve driver for i2cdetect from i2c-tools to detect i2c devices on the bus. + * (C) 2014 Sittisak <sittisaks@hotmail.com> @@ -67,405 +65,276 @@ Signed-off-by: John Crispin <blogic@openwrt.org> +#include <linux/init.h> +#include <linux/errno.h> +#include <linux/platform_device.h> -+#include <linux/of_platform.h> +#include <linux/i2c.h> +#include <linux/io.h> +#include <linux/err.h> -+#include <linux/clk.h> -+ -+#define REG_SM0CFG0 0x08 -+#define REG_SM0DOUT 0x10 -+#define REG_SM0DIN 0x14 -+#define REG_SM0ST 0x18 -+#define REG_SM0AUTO 0x1C -+#define REG_SM0CFG1 0x20 -+#define REG_SM0CFG2 0x28 -+#define REG_SM0CTL0 0x40 -+#define REG_SM0CTL1 0x44 -+#define REG_SM0D0 0x50 -+#define REG_SM0D1 0x54 -+#define REG_PINTEN 0x5C -+#define REG_PINTST 0x60 -+#define REG_PINTCL 0x64 -+ -+/* REG_SM0CFG0 */ -+#define I2C_DEVADDR_MASK 0x7f -+ -+/* REG_SM0ST */ -+#define I2C_DATARDY BIT(2) -+#define I2C_SDOEMPTY BIT(1) -+#define I2C_BUSY BIT(0) -+ -+/* REG_SM0AUTO */ -+#define READ_CMD BIT(0) -+ -+/* REG_SM0CFG1 */ -+#define BYTECNT_MAX 64 -+#define SET_BYTECNT(x) (x - 1) -+ -+/* REG_SM0CFG2 */ -+#define AUTOMODE_EN BIT(0) -+ -+/* REG_SM0CTL0 */ -+#define ODRAIN_HIGH_SM0 BIT(31) -+#define VSYNC_SHIFT 28 -+#define VSYNC_MASK 0x3 -+#define VSYNC_PULSE (0x1 << VSYNC_SHIFT) -+#define VSYNC_RISING (0x2 << VSYNC_SHIFT) -+#define CLK_DIV_SHIFT 16 -+#define CLK_DIV_MASK 0xfff -+#define DEG_CNT_SHIFT 8 -+#define DEG_CNT_MASK 0xff -+#define WAIT_HIGH BIT(6) -+#define DEG_EN BIT(5) -+#define CS_STATUA BIT(4) -+#define SCL_STATUS BIT(3) -+#define SDA_STATUS BIT(2) -+#define SM0_EN BIT(1) -+#define SCL_STRECH BIT(0) -+ -+/* REG_SM0CTL1 */ -+#define ACK_SHIFT 16 -+#define ACK_MASK 0xff -+#define PGLEN_SHIFT 8 -+#define PGLEN_MASK 0x7 -+#define SM0_MODE_SHIFT 4 -+#define SM0_MODE_MASK 0x7 -+#define SM0_MODE_START 0x1 -+#define SM0_MODE_WRITE 0x2 -+#define SM0_MODE_STOP 0x3 -+#define SM0_MODE_READ_NACK 0x4 -+#define SM0_MODE_READ_ACK 0x5 -+#define SM0_TRI_BUSY BIT(0) -+ -+/* timeout waiting for I2C devices to respond (clock streching) */ -+#define TIMEOUT_MS 1000 -+#define DELAY_INTERVAL_US 100 -+ -+struct mtk_i2c { -+ void __iomem *base; -+ struct clk *clk; -+ struct device *dev; -+ struct i2c_adapter adap; -+ u32 cur_clk; -+ u32 clk_div; -+ u32 flags; -+}; + -+static void mtk_i2c_w32(struct mtk_i2c *i2c, u32 val, unsigned reg) ++#include <asm/mach-ralink/ralink_regs.h> ++ ++#define REG_CONFIG_REG 0x00 ++#define REG_CLKDIV_REG 0x04 ++#define REG_DEVADDR_REG 0x08 ++#define REG_ADDR_REG 0x0C ++#define REG_DATAOUT_REG 0x10 ++#define REG_DATAIN_REG 0x14 ++#define REG_STATUS_REG 0x18 ++#define REG_STARTXFR_REG 0x1C ++#define REG_BYTECNT_REG 0x20 ++#define REG_SM0_IS_AUTOMODE 0x28 ++#define REG_SM0CTL0 0x40 ++ ++ ++#define I2C_STARTERR 0x10 ++#define I2C_ACKERR 0x08 ++#define I2C_DATARDY 0x04 ++#define I2C_SDOEMPTY 0x02 ++#define I2C_BUSY 0x01 ++ ++/* I2C_CFG register bit field */ ++#define I2C_CFG_ADDRLEN_8 (7<<5) /* 8 bits */ ++#define I2C_CFG_DEVADLEN_7 (6<<2) ++#define I2C_CFG_ADDRDIS BIT(1) ++#define I2C_CFG_DEVADDIS BIT(0) ++ ++#define I2C_CFG_DEFAULT (I2C_CFG_ADDRLEN_8 | \ ++ I2C_CFG_DEVADLEN_7 | \ ++ I2C_CFG_ADDRDIS) ++ ++#define I2C_RETRY 0x1000 ++ ++#define CLKDIV_VALUE 333 ++#define i2c_busy_loop (CLKDIV_VALUE*30) ++ ++#define READ_CMD 0x01 ++#define WRITE_CMD 0x00 ++#define READ_BLOCK 16 ++ ++#define SM0_ODRAIN BIT(31) ++#define SM0_VSYNC_MODE BIT(28) ++#define SM0_CLK_DIV (CLKDIV_VALUE << 16) ++#define SM0_WAIT_LEVEL BIT(6) ++#define SM0_EN BIT(1) ++ ++#define SM0_CFG_DEFUALT (SM0_ODRAIN | SM0_VSYNC_MODE | \ ++ SM0_CLK_DIV | SM0_WAIT_LEVEL | \ ++ SM0_EN) ++/***********************************************************/ ++ ++static void __iomem *membase; ++static struct i2c_adapter *adapter; ++ ++static void rt_i2c_w32(u32 val, unsigned reg) +{ -+ iowrite32(val, i2c->base + reg); ++ iowrite32(val, membase + reg); +} + -+static u32 mtk_i2c_r32(struct mtk_i2c *i2c, unsigned reg) ++static u32 rt_i2c_r32(unsigned reg) +{ -+ return ioread32(i2c->base + reg); ++ return ioread32(membase + reg); +} + -+static int poll_down_timeout(void __iomem *addr, u32 mask) ++static void mt7621_i2c_reset(struct i2c_adapter *a) +{ -+ unsigned long timeout = jiffies + msecs_to_jiffies(TIMEOUT_MS); -+ -+ do { -+ if (!(readl_relaxed(addr) & mask)) -+ return 0; -+ -+ usleep_range(DELAY_INTERVAL_US, DELAY_INTERVAL_US + 50); -+ } while (time_before(jiffies, timeout)); -+ -+ return (readl_relaxed(addr) & mask) ? -EAGAIN : 0; ++ device_reset(a->dev.parent); +} -+ -+static int mtk_i2c_wait_idle(struct mtk_i2c *i2c) ++static void mt7621_i2c_enable(struct i2c_msg *msg) +{ -+ int ret; -+ -+ ret = poll_down_timeout(i2c->base + REG_SM0ST, I2C_BUSY); -+ if (ret < 0) -+ dev_dbg(i2c->dev, "idle err(%d)\n", ret); -+ -+ return ret; ++ rt_i2c_w32(msg->addr,REG_DEVADDR_REG); ++ rt_i2c_w32(0,REG_ADDR_REG); +} + -+static int poll_up_timeout(void __iomem *addr, u32 mask) ++static void i2c_master_init(struct i2c_adapter *a) +{ -+ unsigned long timeout = jiffies + msecs_to_jiffies(TIMEOUT_MS); -+ u32 status; -+ -+ do { -+ status = readl_relaxed(addr); -+ if (status & mask) -+ return 0; -+ usleep_range(DELAY_INTERVAL_US, DELAY_INTERVAL_US + 50); -+ } while (time_before(jiffies, timeout)); -+ -+ return -ETIMEDOUT; ++ mt7621_i2c_reset(a); ++ rt_i2c_w32(I2C_CFG_DEFAULT,REG_CONFIG_REG); ++ rt_i2c_w32(SM0_CFG_DEFUALT,REG_SM0CTL0); ++ rt_i2c_w32(1,REG_SM0_IS_AUTOMODE);//auto mode +} + -+static int mtk_i2c_wait_rx_done(struct mtk_i2c *i2c) -+{ -+ int ret; -+ -+ ret = poll_up_timeout(i2c->base + REG_SM0ST, I2C_DATARDY); -+ if (ret < 0) -+ dev_dbg(i2c->dev, "rx err(%d)\n", ret); -+ -+ return ret; -+} + -+static int mtk_i2c_wait_tx_done(struct mtk_i2c *i2c) ++static inline int rt_i2c_wait_rx_done(void) +{ -+ int ret; -+ -+ ret = poll_up_timeout(i2c->base + REG_SM0ST, I2C_SDOEMPTY); -+ if (ret < 0) -+ dev_dbg(i2c->dev, "tx err(%d)\n", ret); -+ -+ return ret; ++ int i=0; ++ while((!(rt_i2c_r32(REG_STATUS_REG) & I2C_DATARDY)) && (i<i2c_busy_loop)) ++ i++; ++ if(i>=i2c_busy_loop){ ++ pr_err("err,wait for idle timeout"); ++ return -ETIMEDOUT; ++ } ++ return 0; +} + -+static void mtk_i2c_reset(struct mtk_i2c *i2c) ++static inline int rt_i2c_wait_idle(void) +{ -+ u32 reg; -+ device_reset(i2c->adap.dev.parent); -+ barrier(); -+ -+ /* ctrl0 */ -+ reg = ODRAIN_HIGH_SM0 | VSYNC_PULSE | (i2c->clk_div << CLK_DIV_SHIFT) | -+ WAIT_HIGH | SM0_EN; -+ mtk_i2c_w32(i2c, reg, REG_SM0CTL0); -+ -+ /* auto mode */ -+ mtk_i2c_w32(i2c, AUTOMODE_EN, REG_SM0CFG2); ++ int i=0; ++ while((rt_i2c_r32(REG_STATUS_REG) & I2C_BUSY) && (i<i2c_busy_loop)) ++ i++; ++ if(i>=i2c_busy_loop){ ++ pr_err("err,wait for idle timeout"); ++ return -ETIMEDOUT; ++ } ++ return 0; +} + -+static void mtk_i2c_dump_reg(struct mtk_i2c *i2c) ++static inline int rt_i2c_wait_tx_done(void) +{ -+ dev_dbg(i2c->dev, "cfg0 %08x, dout %08x, din %08x, " \ -+ "status %08x, auto %08x, cfg1 %08x, " \ -+ "cfg2 %08x, ctl0 %08x, ctl1 %08x\n", -+ mtk_i2c_r32(i2c, REG_SM0CFG0), -+ mtk_i2c_r32(i2c, REG_SM0DOUT), -+ mtk_i2c_r32(i2c, REG_SM0DIN), -+ mtk_i2c_r32(i2c, REG_SM0ST), -+ mtk_i2c_r32(i2c, REG_SM0AUTO), -+ mtk_i2c_r32(i2c, REG_SM0CFG1), -+ mtk_i2c_r32(i2c, REG_SM0CFG2), -+ mtk_i2c_r32(i2c, REG_SM0CTL0), -+ mtk_i2c_r32(i2c, REG_SM0CTL1)); ++ int i=0; ++ while((!(rt_i2c_r32(REG_STATUS_REG) & I2C_SDOEMPTY)) && (i<i2c_busy_loop)) ++ i++; ++ if(i>=i2c_busy_loop){ ++ pr_err("err,wait for idle timeout"); ++ return -ETIMEDOUT; ++ } ++ return 0; +} + -+static int mtk_i2c_master_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs, -+ int num) ++static int rt_i2c_handle_msg(struct i2c_adapter *a, struct i2c_msg* msg) +{ -+ struct mtk_i2c *i2c; -+ struct i2c_msg *pmsg; -+ int i, j, ret; -+ u32 cmd; -+ -+ i2c = i2c_get_adapdata(adap); -+ -+ for (i = 0; i < num; i++) { -+ pmsg = &msgs[i]; -+ cmd = 0; -+ -+ dev_dbg(i2c->dev, "addr: 0x%x, len: %d, flags: 0x%x\n", -+ pmsg->addr, pmsg->len, pmsg->flags); -+ -+ /* wait hardware idle */ -+ if ((ret = mtk_i2c_wait_idle(i2c))) -+ goto err_timeout; -+ -+ if (pmsg->flags & I2C_M_TEN) { -+ dev_dbg(i2c->dev, "10 bits addr not supported\n"); -+ return -EINVAL; -+ } else { -+ /* 7 bits address */ -+ mtk_i2c_w32(i2c, pmsg->addr & I2C_DEVADDR_MASK, -+ REG_SM0CFG0); -+ } ++ int i = 0, j = 0, pos = 0; ++ int nblock = msg->len / READ_BLOCK; ++ int rem = msg->len % READ_BLOCK; + -+ /* buffer length */ -+ if (pmsg->len == 0) { -+ dev_dbg(i2c->dev, "length is 0\n"); -+ return -EINVAL; -+ } else -+ mtk_i2c_w32(i2c, SET_BYTECNT(pmsg->len), -+ REG_SM0CFG1); -+ -+ j = 0; -+ if (pmsg->flags & I2C_M_RD) { -+ cmd |= READ_CMD; -+ /* start transfer */ -+ barrier(); -+ mtk_i2c_w32(i2c, cmd, REG_SM0AUTO); -+ do { -+ /* wait */ -+ if ((ret = mtk_i2c_wait_rx_done(i2c))) -+ goto err_timeout; -+ /* read data */ -+ if (pmsg->len) -+ pmsg->buf[j] = mtk_i2c_r32(i2c, -+ REG_SM0DIN); -+ j++; -+ } while (j < pmsg->len); -+ } else { -+ do { -+ /* write data */ -+ if (pmsg->len) -+ mtk_i2c_w32(i2c, pmsg->buf[j], -+ REG_SM0DOUT); -+ /* start transfer */ -+ if (j == 0) { -+ barrier(); -+ mtk_i2c_w32(i2c, cmd, REG_SM0AUTO); -+ } -+ /* wait */ -+ if ((ret = mtk_i2c_wait_tx_done(i2c))) ++ if (msg->flags & I2C_M_TEN) { ++ printk("10 bits addr not supported\n"); ++ return -EINVAL; ++ } ++ ++ if (msg->flags & I2C_M_RD) { ++ for (i = 0; i < nblock; i++) { ++ if (rt_i2c_wait_idle()) ++ goto err_timeout; ++ 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()) + goto err_timeout; -+ j++; -+ } while (j < pmsg->len); ++ msg->buf[pos++] = rt_i2c_r32(REG_DATAIN_REG); ++ } + } -+ } -+ /* the return value is number of executed messages */ -+ ret = i; + -+ return ret; ++ if (rt_i2c_wait_idle()) ++ goto err_timeout; ++ 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()) ++ goto err_timeout; ++ msg->buf[pos++] = rt_i2c_r32(REG_DATAIN_REG); ++ } ++ } else { ++ if (rt_i2c_wait_idle()) ++ goto err_timeout; ++ 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); ++ if(i == 0) ++ rt_i2c_w32(WRITE_CMD, REG_STARTXFR_REG); ++ ++ if (rt_i2c_wait_tx_done()) ++ goto err_timeout; ++ } ++ } + ++ return 0; +err_timeout: -+ mtk_i2c_dump_reg(i2c); -+ mtk_i2c_reset(i2c); -+ return ret; ++ return -ETIMEDOUT; +} + -+static u32 mtk_i2c_func(struct i2c_adapter *a) ++static int rt_i2c_master_xfer(struct i2c_adapter *a, struct i2c_msg *m, int n) +{ -+ return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL; ++ int i = 0; ++ int ret = 0; ++ i2c_master_init(a); ++ mt7621_i2c_enable(m); ++ ++ for (i = 0; i != n && ret==0; i++) { ++ ret = rt_i2c_handle_msg(a, &m[i]); ++ if (ret) ++ return ret; ++ } ++ return i; +} + -+static const struct i2c_algorithm mtk_i2c_algo = { -+ .master_xfer = mtk_i2c_master_xfer, -+ .functionality = mtk_i2c_func, -+}; -+ -+static const struct of_device_id i2c_mtk_dt_ids[] = { -+ { .compatible = "mediatek,mt7621-i2c" }, -+ { /* sentinel */ } -+}; -+ -+MODULE_DEVICE_TABLE(of, i2c_mtk_dt_ids); -+ -+static struct i2c_adapter_quirks mtk_i2c_quirks = { -+ .max_write_len = BYTECNT_MAX, -+ .max_read_len = BYTECNT_MAX, -+}; -+ -+static void mtk_i2c_init(struct mtk_i2c *i2c) ++static u32 rt_i2c_func(struct i2c_adapter *a) +{ -+ i2c->clk_div = clk_get_rate(i2c->clk) / i2c->cur_clk; -+ if (i2c->clk_div > CLK_DIV_MASK) -+ i2c->clk_div = CLK_DIV_MASK; -+ -+ mtk_i2c_reset(i2c); ++ return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL; +} + -+static int mtk_i2c_probe(struct platform_device *pdev) ++static const struct i2c_algorithm rt_i2c_algo = { ++ .master_xfer = rt_i2c_master_xfer, ++ .functionality = rt_i2c_func, ++}; ++ ++static int rt_i2c_probe(struct platform_device *pdev) +{ -+ struct resource *res; -+ struct mtk_i2c *i2c; -+ struct i2c_adapter *adap; -+ const struct of_device_id *match; ++ struct resource *res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + int ret; + -+ match = of_match_device(i2c_mtk_dt_ids, &pdev->dev); -+ -+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0); -+ if (!res) { -+ dev_err(&pdev->dev, "no memory resource found\n"); -+ return -ENODEV; -+ } -+ -+ i2c = devm_kzalloc(&pdev->dev, sizeof(struct mtk_i2c), GFP_KERNEL); -+ if (!i2c) { ++ adapter = devm_kzalloc(&pdev->dev,sizeof(struct i2c_adapter), GFP_KERNEL); ++ if (!adapter) { + dev_err(&pdev->dev, "failed to allocate i2c_adapter\n"); + return -ENOMEM; + } -+ -+ i2c->base = devm_ioremap_resource(&pdev->dev, res); -+ if (IS_ERR(i2c->base)) -+ return PTR_ERR(i2c->base); -+ -+ i2c->clk = devm_clk_get(&pdev->dev, NULL); -+ if (IS_ERR(i2c->clk)) { -+ dev_err(&pdev->dev, "no clock defined\n"); -+ return -ENODEV; -+ } -+ clk_prepare_enable(i2c->clk); -+ i2c->dev = &pdev->dev; -+ -+ if (of_property_read_u32(pdev->dev.of_node, -+ "clock-frequency", &i2c->cur_clk)) -+ i2c->cur_clk = 100000; -+ -+ adap = &i2c->adap; -+ adap->owner = THIS_MODULE; -+ adap->class = I2C_CLASS_HWMON | I2C_CLASS_SPD; -+ adap->algo = &mtk_i2c_algo; -+ adap->retries = 3; -+ adap->dev.parent = &pdev->dev; -+ i2c_set_adapdata(adap, i2c); -+ adap->dev.of_node = pdev->dev.of_node; -+ strlcpy(adap->name, dev_name(&pdev->dev), sizeof(adap->name)); -+ adap->quirks = &mtk_i2c_quirks; -+ -+ platform_set_drvdata(pdev, i2c); -+ -+ mtk_i2c_init(i2c); -+ -+ ret = i2c_add_adapter(adap); -+ if (ret < 0) { -+ dev_err(&pdev->dev, "failed to add adapter\n"); -+ clk_disable_unprepare(i2c->clk); ++ membase = devm_ioremap_resource(&pdev->dev, res); ++ if (IS_ERR(membase)) ++ return PTR_ERR(membase); ++ ++ strlcpy(adapter->name, dev_name(&pdev->dev), sizeof(adapter->name)); ++ ++ adapter->owner = THIS_MODULE; ++ adapter->nr = pdev->id; ++ adapter->timeout = HZ; ++ adapter->algo = &rt_i2c_algo; ++ adapter->class = I2C_CLASS_HWMON | I2C_CLASS_SPD; ++ adapter->dev.parent = &pdev->dev; ++ adapter->dev.of_node = pdev->dev.of_node; ++ ++ platform_set_drvdata(pdev, adapter); ++ ++ ret = i2c_add_numbered_adapter(adapter); ++ if (ret) + return ret; -+ } + -+ dev_info(&pdev->dev, "clock %uKHz, re-start not support\n", -+ i2c->cur_clk/1000); ++ dev_info(&pdev->dev,"loaded"); + -+ return ret; ++ return 0; +} + -+static int mtk_i2c_remove(struct platform_device *pdev) ++static int rt_i2c_remove(struct platform_device *pdev) +{ -+ struct mtk_i2c *i2c = platform_get_drvdata(pdev); -+ -+ i2c_del_adapter(&i2c->adap); -+ clk_disable_unprepare(i2c->clk); -+ ++ platform_set_drvdata(pdev, NULL); + return 0; +} + -+static struct platform_driver mtk_i2c_driver = { -+ .probe = mtk_i2c_probe, -+ .remove = mtk_i2c_remove, ++static const struct of_device_id i2c_rt_dt_ids[] = { ++ { .compatible = "ralink,i2c-mt7621", }, ++ { /* sentinel */ } ++}; ++ ++MODULE_DEVICE_TABLE(of, i2c_rt_dt_ids); ++ ++static struct platform_driver rt_i2c_driver = { ++ .probe = rt_i2c_probe, ++ .remove = rt_i2c_remove, + .driver = { + .owner = THIS_MODULE, + .name = "i2c-mt7621", -+ .of_match_table = i2c_mtk_dt_ids, ++ .of_match_table = i2c_rt_dt_ids, + }, +}; + -+static int __init i2c_mtk_init (void) ++static int __init i2c_rt_init (void) +{ -+ return platform_driver_register(&mtk_i2c_driver); ++ return platform_driver_register(&rt_i2c_driver); +} -+subsys_initcall(i2c_mtk_init); + -+static void __exit i2c_mtk_exit (void) ++static void __exit i2c_rt_exit (void) +{ -+ platform_driver_unregister(&mtk_i2c_driver); ++ platform_driver_unregister(&rt_i2c_driver); +} -+module_exit(i2c_mtk_exit); ++module_init (i2c_rt_init); ++module_exit (i2c_rt_exit); + +MODULE_AUTHOR("Steven Liu <steven_liu@mediatek.com>"); +MODULE_DESCRIPTION("MT7621 I2c host driver"); |