From c4cea7fc1bfd8a36d08f8114efcb11d649d97d5a Mon Sep 17 00:00:00 2001 From: Roland Stigge Date: Sun, 22 Apr 2012 11:59:47 +0200 Subject: i2c: pnx: Disable clk in suspend In the driver's suspend function, clk_enable() was used instead of clk_disable(). This is corrected with this patch. Signed-off-by: Roland Stigge Reviewed-by: Arnd Bergmann Signed-off-by: Wolfram Sang CC: stable@vger.kernel.org --- drivers/i2c/busses/i2c-pnx.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'drivers/i2c') diff --git a/drivers/i2c/busses/i2c-pnx.c b/drivers/i2c/busses/i2c-pnx.c index 04be9f82e14b..eb8ad538c79f 100644 --- a/drivers/i2c/busses/i2c-pnx.c +++ b/drivers/i2c/busses/i2c-pnx.c @@ -546,8 +546,7 @@ static int i2c_pnx_controller_suspend(struct platform_device *pdev, { struct i2c_pnx_algo_data *alg_data = platform_get_drvdata(pdev); - /* FIXME: shouldn't this be clk_disable? */ - clk_enable(alg_data->clk); + clk_disable(alg_data->clk); return 0; } -- cgit v1.2.3 From 1451ba3a5fa52d874e03a3380d053f3e6a5fcae4 Mon Sep 17 00:00:00 2001 From: Roland Stigge Date: Sun, 22 Apr 2012 11:59:47 +0200 Subject: i2c-pnx.c: Use resources in platforms As a precondition for device tree conversion, the platforms using i2c-pnx.c are converted to using mem and irq resources instead of platform data. Signed-off-by: Roland Stigge Reviewed-by: Arnd Bergmann Signed-off-by: Wolfram Sang --- arch/arm/mach-lpc32xx/common.c | 67 ++++++++++++++++++++++++++---------------- arch/arm/mach-pnx4008/i2c.c | 64 ++++++++++++++++++++++++---------------- drivers/i2c/busses/i2c-pnx.c | 47 +++++++++++++++-------------- include/linux/i2c-pnx.h | 9 ++---- 4 files changed, 108 insertions(+), 79 deletions(-) (limited to 'drivers/i2c') diff --git a/arch/arm/mach-lpc32xx/common.c b/arch/arm/mach-lpc32xx/common.c index bbbf063a74c2..6f255600fc97 100644 --- a/arch/arm/mach-lpc32xx/common.c +++ b/arch/arm/mach-lpc32xx/common.c @@ -27,7 +27,6 @@ #include -#include #include #include #include "common.h" @@ -53,46 +52,64 @@ struct platform_device lpc32xx_watchdog_device = { /* * I2C busses */ -static struct i2c_pnx_data i2c0_data = { - .name = I2C_CHIP_NAME "1", - .base = LPC32XX_I2C1_BASE, - .irq = IRQ_LPC32XX_I2C_1, +static struct resource i2c0_resources[] = { + [0] = { + .start = LPC32XX_I2C1_BASE, + .end = LPC32XX_I2C1_BASE + 0x100 - 1, + .flags = IORESOURCE_MEM, + }, + [1] = { + .start = IRQ_LPC32XX_I2C_1, + .end = IRQ_LPC32XX_I2C_1, + .flags = IORESOURCE_IRQ, + }, }; -static struct i2c_pnx_data i2c1_data = { - .name = I2C_CHIP_NAME "2", - .base = LPC32XX_I2C2_BASE, - .irq = IRQ_LPC32XX_I2C_2, +static struct resource i2c1_resources[] = { + [0] = { + .start = LPC32XX_I2C2_BASE, + .end = LPC32XX_I2C2_BASE + 0x100 - 1, + .flags = IORESOURCE_MEM, + }, + [1] = { + .start = IRQ_LPC32XX_I2C_2, + .end = IRQ_LPC32XX_I2C_2, + .flags = IORESOURCE_IRQ, + }, }; -static struct i2c_pnx_data i2c2_data = { - .name = "USB-I2C", - .base = LPC32XX_OTG_I2C_BASE, - .irq = IRQ_LPC32XX_USB_I2C, +static struct resource i2c2_resources[] = { + [0] = { + .start = LPC32XX_OTG_I2C_BASE, + .end = LPC32XX_OTG_I2C_BASE + 0x100 - 1, + .flags = IORESOURCE_MEM, + }, + [1] = { + .start = IRQ_LPC32XX_USB_I2C, + .end = IRQ_LPC32XX_USB_I2C, + .flags = IORESOURCE_IRQ, + }, }; struct platform_device lpc32xx_i2c0_device = { - .name = "pnx-i2c", + .name = "pnx-i2c.0", .id = 0, - .dev = { - .platform_data = &i2c0_data, - }, + .num_resources = ARRAY_SIZE(i2c0_resources), + .resource = i2c0_resources, }; struct platform_device lpc32xx_i2c1_device = { - .name = "pnx-i2c", + .name = "pnx-i2c.1", .id = 1, - .dev = { - .platform_data = &i2c1_data, - }, + .num_resources = ARRAY_SIZE(i2c1_resources), + .resource = i2c1_resources, }; struct platform_device lpc32xx_i2c2_device = { - .name = "pnx-i2c", + .name = "pnx-i2c.2", .id = 2, - .dev = { - .platform_data = &i2c2_data, - }, + .num_resources = ARRAY_SIZE(i2c2_resources), + .resource = i2c2_resources, }; /* TSC (Touch Screen Controller) */ diff --git a/arch/arm/mach-pnx4008/i2c.c b/arch/arm/mach-pnx4008/i2c.c index 8103f9644e2d..550cfc2a1f2e 100644 --- a/arch/arm/mach-pnx4008/i2c.c +++ b/arch/arm/mach-pnx4008/i2c.c @@ -16,48 +16,62 @@ #include #include #include -#include -static struct i2c_pnx_data i2c0_data = { - .name = I2C_CHIP_NAME "0", - .base = PNX4008_I2C1_BASE, - .irq = I2C_1_INT, +static struct resource i2c0_resources[] = { + { + .start = PNX4008_I2C1_BASE, + .end = PNX4008_I2C1_BASE + SZ_4K - 1, + .flags = IORESOURCE_MEM, + }, { + .start = I2C_1_INT, + .end = I2C_1_INT, + .flags = IORESOURCE_IRQ, + }, }; -static struct i2c_pnx_data i2c1_data = { - .name = I2C_CHIP_NAME "1", - .base = PNX4008_I2C2_BASE, - .irq = I2C_2_INT, +static struct resource i2c1_resources[] = { + { + .start = PNX4008_I2C2_BASE, + .end = PNX4008_I2C2_BASE + SZ_4K - 1, + .flags = IORESOURCE_MEM, + }, { + .start = I2C_2_INT, + .end = I2C_2_INT, + .flags = IORESOURCE_IRQ, + }, }; -static struct i2c_pnx_data i2c2_data = { - .name = "USB-I2C", - .base = (PNX4008_USB_CONFIG_BASE + 0x300), - .irq = USB_I2C_INT, +static struct resource i2c2_resources[] = { + { + .start = PNX4008_USB_CONFIG_BASE + 0x300, + .end = PNX4008_USB_CONFIG_BASE + 0x300 + SZ_4K - 1, + .flags = IORESOURCE_MEM, + }, { + .start = USB_I2C_INT, + .end = USB_I2C_INT, + .flags = IORESOURCE_IRQ, + }, }; static struct platform_device i2c0_device = { - .name = "pnx-i2c", + .name = "pnx-i2c.0", .id = 0, - .dev = { - .platform_data = &i2c0_data, - }, + .resource = i2c0_resources, + .num_resources = ARRAY_SIZE(i2c0_resources), }; static struct platform_device i2c1_device = { - .name = "pnx-i2c", + .name = "pnx-i2c.1", .id = 1, - .dev = { - .platform_data = &i2c1_data, - }, + .resource = i2c1_resources, + .num_resources = ARRAY_SIZE(i2c1_resources), }; static struct platform_device i2c2_device = { - .name = "pnx-i2c", + .name = "pnx-i2c.2", .id = 2, - .dev = { - .platform_data = &i2c2_data, - }, + .resource = i2c2_resources, + .num_resources = ARRAY_SIZE(i2c2_resources), }; static struct platform_device *devices[] __initdata = { diff --git a/drivers/i2c/busses/i2c-pnx.c b/drivers/i2c/busses/i2c-pnx.c index eb8ad538c79f..6fb97aef0465 100644 --- a/drivers/i2c/busses/i2c-pnx.c +++ b/drivers/i2c/busses/i2c-pnx.c @@ -568,14 +568,7 @@ static int __devinit i2c_pnx_probe(struct platform_device *pdev) int ret = 0; struct i2c_pnx_algo_data *alg_data; unsigned long freq; - struct i2c_pnx_data *i2c_pnx = pdev->dev.platform_data; - - if (!i2c_pnx || !i2c_pnx->name) { - dev_err(&pdev->dev, "%s: no platform data supplied\n", - __func__); - ret = -EINVAL; - goto out; - } + struct resource *res; alg_data = kzalloc(sizeof(*alg_data), GFP_KERNEL); if (!alg_data) { @@ -585,13 +578,10 @@ static int __devinit i2c_pnx_probe(struct platform_device *pdev) platform_set_drvdata(pdev, alg_data); - strlcpy(alg_data->adapter.name, i2c_pnx->name, - sizeof(alg_data->adapter.name)); alg_data->adapter.dev.parent = &pdev->dev; alg_data->adapter.algo = &pnx_algorithm; alg_data->adapter.algo_data = alg_data; alg_data->adapter.nr = pdev->id; - alg_data->i2c_pnx = i2c_pnx; alg_data->clk = clk_get(&pdev->dev, NULL); if (IS_ERR(alg_data->clk)) { @@ -603,17 +593,27 @@ static int __devinit i2c_pnx_probe(struct platform_device *pdev) alg_data->mif.timer.function = i2c_pnx_timeout; alg_data->mif.timer.data = (unsigned long)alg_data; + snprintf(alg_data->adapter.name, sizeof(alg_data->adapter.name), + "%s", pdev->name); + /* Register I/O resource */ - if (!request_mem_region(i2c_pnx->base, I2C_PNX_REGION_SIZE, + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + if (!res) { + dev_err(&pdev->dev, "Unable to get mem resource.\n"); + ret = -EBUSY; + goto out_clkget; + } + if (!request_mem_region(res->start, I2C_PNX_REGION_SIZE, pdev->name)) { dev_err(&pdev->dev, "I/O region 0x%08x for I2C already in use.\n", - i2c_pnx->base); + res->start); ret = -ENODEV; goto out_clkget; } - alg_data->ioaddr = ioremap(i2c_pnx->base, I2C_PNX_REGION_SIZE); + alg_data->base = res->start; + alg_data->ioaddr = ioremap(res->start, I2C_PNX_REGION_SIZE); if (!alg_data->ioaddr) { dev_err(&pdev->dev, "Couldn't ioremap I2C I/O region\n"); ret = -ENOMEM; @@ -650,7 +650,12 @@ static int __devinit i2c_pnx_probe(struct platform_device *pdev) } init_completion(&alg_data->mif.complete); - ret = request_irq(i2c_pnx->irq, i2c_pnx_interrupt, + alg_data->irq = platform_get_irq(pdev, 0); + if (alg_data->irq < 0) { + dev_err(&pdev->dev, "Failed to get IRQ from platform resource\n"); + goto out_irq; + } + ret = request_irq(alg_data->irq, i2c_pnx_interrupt, 0, pdev->name, alg_data); if (ret) goto out_clock; @@ -663,38 +668,36 @@ static int __devinit i2c_pnx_probe(struct platform_device *pdev) } dev_dbg(&pdev->dev, "%s: Master at %#8x, irq %d.\n", - alg_data->adapter.name, i2c_pnx->base, i2c_pnx->irq); + alg_data->adapter.name, res->start, alg_data->irq); return 0; out_irq: - free_irq(i2c_pnx->irq, alg_data); + free_irq(alg_data->irq, alg_data); out_clock: clk_disable(alg_data->clk); out_unmap: iounmap(alg_data->ioaddr); out_release: - release_mem_region(i2c_pnx->base, I2C_PNX_REGION_SIZE); + release_mem_region(res->start, I2C_PNX_REGION_SIZE); out_clkget: clk_put(alg_data->clk); out_drvdata: kfree(alg_data); err_kzalloc: platform_set_drvdata(pdev, NULL); -out: return ret; } static int __devexit i2c_pnx_remove(struct platform_device *pdev) { struct i2c_pnx_algo_data *alg_data = platform_get_drvdata(pdev); - struct i2c_pnx_data *i2c_pnx = alg_data->i2c_pnx; - free_irq(i2c_pnx->irq, alg_data); + free_irq(alg_data->irq, alg_data); i2c_del_adapter(&alg_data->adapter); clk_disable(alg_data->clk); iounmap(alg_data->ioaddr); - release_mem_region(i2c_pnx->base, I2C_PNX_REGION_SIZE); + release_mem_region(alg_data->base, I2C_PNX_REGION_SIZE); clk_put(alg_data->clk); kfree(alg_data); platform_set_drvdata(pdev, NULL); diff --git a/include/linux/i2c-pnx.h b/include/linux/i2c-pnx.h index a87124d4d533..6e8efb7afd7c 100644 --- a/include/linux/i2c-pnx.h +++ b/include/linux/i2c-pnx.h @@ -29,14 +29,9 @@ struct i2c_pnx_algo_data { struct i2c_pnx_mif mif; int last; struct clk *clk; - struct i2c_pnx_data *i2c_pnx; struct i2c_adapter adapter; -}; - -struct i2c_pnx_data { - const char *name; - u32 base; - int irq; + phys_addr_t base; + int irq; }; #endif /* __I2C_PNX_H__ */ -- cgit v1.2.3 From be460385af1c40905dd6858a475bc949a3072b08 Mon Sep 17 00:00:00 2001 From: Roland Stigge Date: Sun, 22 Apr 2012 11:59:47 +0200 Subject: i2c-pnx.c: Remove duplicated i2c.h The platforms using i2c-pnx.c both defined a duplicated i2c.h (used nowhere else). This patch removes those and integrates the contents into the driver itself. Signed-off-by: Roland Stigge Reviewed-by: Arnd Bergmann Signed-off-by: Wolfram Sang --- arch/arm/mach-lpc32xx/include/mach/i2c.h | 63 ------------------------------- arch/arm/mach-pnx4008/include/mach/i2c.h | 64 -------------------------------- drivers/i2c/busses/i2c-pnx.c | 49 ++++++++++++++++++++++-- 3 files changed, 46 insertions(+), 130 deletions(-) delete mode 100644 arch/arm/mach-lpc32xx/include/mach/i2c.h delete mode 100644 arch/arm/mach-pnx4008/include/mach/i2c.h (limited to 'drivers/i2c') diff --git a/arch/arm/mach-lpc32xx/include/mach/i2c.h b/arch/arm/mach-lpc32xx/include/mach/i2c.h deleted file mode 100644 index 034dc9286bcc..000000000000 --- a/arch/arm/mach-lpc32xx/include/mach/i2c.h +++ /dev/null @@ -1,63 +0,0 @@ -/* - * PNX4008-specific tweaks for I2C IP3204 block - * - * Author: Vitaly Wool - * - * 2005 (c) MontaVista Software, Inc. This file is licensed under - * the terms of the GNU General Public License version 2. This program - * is licensed "as is" without any warranty of any kind, whether express - * or implied. - */ - -#ifndef __ASM_ARCH_I2C_H -#define __ASM_ARCH_I2C_H - -enum { - mstatus_tdi = 0x00000001, - mstatus_afi = 0x00000002, - mstatus_nai = 0x00000004, - mstatus_drmi = 0x00000008, - mstatus_active = 0x00000020, - mstatus_scl = 0x00000040, - mstatus_sda = 0x00000080, - mstatus_rff = 0x00000100, - mstatus_rfe = 0x00000200, - mstatus_tff = 0x00000400, - mstatus_tfe = 0x00000800, -}; - -enum { - mcntrl_tdie = 0x00000001, - mcntrl_afie = 0x00000002, - mcntrl_naie = 0x00000004, - mcntrl_drmie = 0x00000008, - mcntrl_daie = 0x00000020, - mcntrl_rffie = 0x00000040, - mcntrl_tffie = 0x00000080, - mcntrl_reset = 0x00000100, - mcntrl_cdbmode = 0x00000400, -}; - -enum { - rw_bit = 1 << 0, - start_bit = 1 << 8, - stop_bit = 1 << 9, -}; - -#define I2C_REG_RX(a) ((a)->ioaddr) /* Rx FIFO reg (RO) */ -#define I2C_REG_TX(a) ((a)->ioaddr) /* Tx FIFO reg (WO) */ -#define I2C_REG_STS(a) ((a)->ioaddr + 0x04) /* Status reg (RO) */ -#define I2C_REG_CTL(a) ((a)->ioaddr + 0x08) /* Ctl reg */ -#define I2C_REG_CKL(a) ((a)->ioaddr + 0x0c) /* Clock divider low */ -#define I2C_REG_CKH(a) ((a)->ioaddr + 0x10) /* Clock divider high */ -#define I2C_REG_ADR(a) ((a)->ioaddr + 0x14) /* I2C address */ -#define I2C_REG_RFL(a) ((a)->ioaddr + 0x18) /* Rx FIFO level (RO) */ -#define I2C_REG_TFL(a) ((a)->ioaddr + 0x1c) /* Tx FIFO level (RO) */ -#define I2C_REG_RXB(a) ((a)->ioaddr + 0x20) /* Num of bytes Rx-ed (RO) */ -#define I2C_REG_TXB(a) ((a)->ioaddr + 0x24) /* Num of bytes Tx-ed (RO) */ -#define I2C_REG_TXS(a) ((a)->ioaddr + 0x28) /* Tx slave FIFO (RO) */ -#define I2C_REG_STFL(a) ((a)->ioaddr + 0x2c) /* Tx slave FIFO level (RO) */ - -#define I2C_CHIP_NAME "PNX4008-I2C" - -#endif /* __ASM_ARCH_I2C_H */ diff --git a/arch/arm/mach-pnx4008/include/mach/i2c.h b/arch/arm/mach-pnx4008/include/mach/i2c.h deleted file mode 100644 index 259ac53abf40..000000000000 --- a/arch/arm/mach-pnx4008/include/mach/i2c.h +++ /dev/null @@ -1,64 +0,0 @@ -/* - * PNX4008-specific tweaks for I2C IP3204 block - * - * Author: Vitaly Wool - * - * 2005 (c) MontaVista Software, Inc. This file is licensed under - * the terms of the GNU General Public License version 2. This program - * is licensed "as is" without any warranty of any kind, whether express - * or implied. - */ - -#ifndef __ASM_ARCH_I2C_H__ -#define __ASM_ARCH_I2C_H__ - -enum { - mstatus_tdi = 0x00000001, - mstatus_afi = 0x00000002, - mstatus_nai = 0x00000004, - mstatus_drmi = 0x00000008, - mstatus_active = 0x00000020, - mstatus_scl = 0x00000040, - mstatus_sda = 0x00000080, - mstatus_rff = 0x00000100, - mstatus_rfe = 0x00000200, - mstatus_tff = 0x00000400, - mstatus_tfe = 0x00000800, -}; - -enum { - mcntrl_tdie = 0x00000001, - mcntrl_afie = 0x00000002, - mcntrl_naie = 0x00000004, - mcntrl_drmie = 0x00000008, - mcntrl_daie = 0x00000020, - mcntrl_rffie = 0x00000040, - mcntrl_tffie = 0x00000080, - mcntrl_reset = 0x00000100, - mcntrl_cdbmode = 0x00000400, -}; - -enum { - rw_bit = 1 << 0, - start_bit = 1 << 8, - stop_bit = 1 << 9, -}; - -#define I2C_REG_RX(a) ((a)->ioaddr) /* Rx FIFO reg (RO) */ -#define I2C_REG_TX(a) ((a)->ioaddr) /* Tx FIFO reg (WO) */ -#define I2C_REG_STS(a) ((a)->ioaddr + 0x04) /* Status reg (RO) */ -#define I2C_REG_CTL(a) ((a)->ioaddr + 0x08) /* Ctl reg */ -#define I2C_REG_CKL(a) ((a)->ioaddr + 0x0c) /* Clock divider low */ -#define I2C_REG_CKH(a) ((a)->ioaddr + 0x10) /* Clock divider high */ -#define I2C_REG_ADR(a) ((a)->ioaddr + 0x14) /* I2C address */ -#define I2C_REG_RFL(a) ((a)->ioaddr + 0x18) /* Rx FIFO level (RO) */ -#define I2C_REG_TFL(a) ((a)->ioaddr + 0x1c) /* Tx FIFO level (RO) */ -#define I2C_REG_RXB(a) ((a)->ioaddr + 0x20) /* Num of bytes Rx-ed (RO) */ -#define I2C_REG_TXB(a) ((a)->ioaddr + 0x24) /* Num of bytes Tx-ed (RO) */ -#define I2C_REG_TXS(a) ((a)->ioaddr + 0x28) /* Tx slave FIFO (RO) */ -#define I2C_REG_STFL(a) ((a)->ioaddr + 0x2c) /* Tx slave FIFO level (RO) */ - -#define HCLK_MHZ 13 -#define I2C_CHIP_NAME "PNX4008-I2C" - -#endif /* __ASM_ARCH_I2C_H___ */ diff --git a/drivers/i2c/busses/i2c-pnx.c b/drivers/i2c/busses/i2c-pnx.c index 6fb97aef0465..f69d80b8d736 100644 --- a/drivers/i2c/busses/i2c-pnx.c +++ b/drivers/i2c/busses/i2c-pnx.c @@ -24,13 +24,56 @@ #include #include -#include -#include - #define I2C_PNX_TIMEOUT 10 /* msec */ #define I2C_PNX_SPEED_KHZ 100 #define I2C_PNX_REGION_SIZE 0x100 +enum { + mstatus_tdi = 0x00000001, + mstatus_afi = 0x00000002, + mstatus_nai = 0x00000004, + mstatus_drmi = 0x00000008, + mstatus_active = 0x00000020, + mstatus_scl = 0x00000040, + mstatus_sda = 0x00000080, + mstatus_rff = 0x00000100, + mstatus_rfe = 0x00000200, + mstatus_tff = 0x00000400, + mstatus_tfe = 0x00000800, +}; + +enum { + mcntrl_tdie = 0x00000001, + mcntrl_afie = 0x00000002, + mcntrl_naie = 0x00000004, + mcntrl_drmie = 0x00000008, + mcntrl_daie = 0x00000020, + mcntrl_rffie = 0x00000040, + mcntrl_tffie = 0x00000080, + mcntrl_reset = 0x00000100, + mcntrl_cdbmode = 0x00000400, +}; + +enum { + rw_bit = 1 << 0, + start_bit = 1 << 8, + stop_bit = 1 << 9, +}; + +#define I2C_REG_RX(a) ((a)->ioaddr) /* Rx FIFO reg (RO) */ +#define I2C_REG_TX(a) ((a)->ioaddr) /* Tx FIFO reg (WO) */ +#define I2C_REG_STS(a) ((a)->ioaddr + 0x04) /* Status reg (RO) */ +#define I2C_REG_CTL(a) ((a)->ioaddr + 0x08) /* Ctl reg */ +#define I2C_REG_CKL(a) ((a)->ioaddr + 0x0c) /* Clock divider low */ +#define I2C_REG_CKH(a) ((a)->ioaddr + 0x10) /* Clock divider high */ +#define I2C_REG_ADR(a) ((a)->ioaddr + 0x14) /* I2C address */ +#define I2C_REG_RFL(a) ((a)->ioaddr + 0x18) /* Rx FIFO level (RO) */ +#define I2C_REG_TFL(a) ((a)->ioaddr + 0x1c) /* Tx FIFO level (RO) */ +#define I2C_REG_RXB(a) ((a)->ioaddr + 0x20) /* Num of bytes Rx-ed (RO) */ +#define I2C_REG_TXB(a) ((a)->ioaddr + 0x24) /* Num of bytes Tx-ed (RO) */ +#define I2C_REG_TXS(a) ((a)->ioaddr + 0x28) /* Tx slave FIFO (RO) */ +#define I2C_REG_STFL(a) ((a)->ioaddr + 0x2c) /* Tx slave FIFO level (RO) */ + static inline int wait_timeout(long timeout, struct i2c_pnx_algo_data *data) { while (timeout > 0 && -- cgit v1.2.3 From b41a216dafe4dd23c95cb4203de288f773a097a6 Mon Sep 17 00:00:00 2001 From: Roland Stigge Date: Sun, 22 Apr 2012 11:59:47 +0200 Subject: i2c: Add device tree support to i2c-pnx.c This patch adds device tree support to the pnx-i2c driver by using platform resources for memory region and irq and removing dependency on mach includes. The following platforms are affected: * PNX * LPC31xx (WIP) * LPC32xx The patch is based on a patch by Jon Smirl, working on lpc31xx integration Signed-off-by: Roland Stigge Signed-off-by: Wolfram Sang --- Documentation/devicetree/bindings/i2c/pnx.txt | 36 +++++++++++++++ drivers/i2c/busses/i2c-pnx.c | 63 ++++++++++++++++++++------- include/linux/i2c-pnx.h | 1 + 3 files changed, 84 insertions(+), 16 deletions(-) create mode 100644 Documentation/devicetree/bindings/i2c/pnx.txt (limited to 'drivers/i2c') diff --git a/Documentation/devicetree/bindings/i2c/pnx.txt b/Documentation/devicetree/bindings/i2c/pnx.txt new file mode 100644 index 000000000000..fe98ada33ee4 --- /dev/null +++ b/Documentation/devicetree/bindings/i2c/pnx.txt @@ -0,0 +1,36 @@ +* NXP PNX I2C Controller + +Required properties: + + - reg: Offset and length of the register set for the device + - compatible: should be "nxp,pnx-i2c" + - interrupts: configure one interrupt line + - #address-cells: always 1 (for i2c addresses) + - #size-cells: always 0 + - interrupt-parent: the phandle for the interrupt controller that + services interrupts for this device. + +Optional properties: + + - clock-frequency: desired I2C bus clock frequency in Hz, Default: 100000 Hz + +Examples: + + i2c1: i2c@400a0000 { + compatible = "nxp,pnx-i2c"; + reg = <0x400a0000 0x100>; + interrupt-parent = <&mic>; + interrupts = <51 0>; + #address-cells = <1>; + #size-cells = <0>; + }; + + i2c2: i2c@400a8000 { + compatible = "nxp,pnx-i2c"; + reg = <0x400a8000 0x100>; + interrupt-parent = <&mic>; + interrupts = <50 0>; + #address-cells = <1>; + #size-cells = <0>; + clock-frequency = <100000>; + }; diff --git a/drivers/i2c/busses/i2c-pnx.c b/drivers/i2c/busses/i2c-pnx.c index f69d80b8d736..99389d2eae51 100644 --- a/drivers/i2c/busses/i2c-pnx.c +++ b/drivers/i2c/busses/i2c-pnx.c @@ -23,10 +23,11 @@ #include #include #include +#include -#define I2C_PNX_TIMEOUT 10 /* msec */ -#define I2C_PNX_SPEED_KHZ 100 -#define I2C_PNX_REGION_SIZE 0x100 +#define I2C_PNX_TIMEOUT_DEFAULT 10 /* msec */ +#define I2C_PNX_SPEED_KHZ_DEFAULT 100 +#define I2C_PNX_REGION_SIZE 0x100 enum { mstatus_tdi = 0x00000001, @@ -74,8 +75,9 @@ enum { #define I2C_REG_TXS(a) ((a)->ioaddr + 0x28) /* Tx slave FIFO (RO) */ #define I2C_REG_STFL(a) ((a)->ioaddr + 0x2c) /* Tx slave FIFO level (RO) */ -static inline int wait_timeout(long timeout, struct i2c_pnx_algo_data *data) +static inline int wait_timeout(struct i2c_pnx_algo_data *data) { + long timeout = data->timeout; while (timeout > 0 && (ioread32(I2C_REG_STS(data)) & mstatus_active)) { mdelay(1); @@ -84,8 +86,9 @@ static inline int wait_timeout(long timeout, struct i2c_pnx_algo_data *data) return (timeout <= 0); } -static inline int wait_reset(long timeout, struct i2c_pnx_algo_data *data) +static inline int wait_reset(struct i2c_pnx_algo_data *data) { + long timeout = data->timeout; while (timeout > 0 && (ioread32(I2C_REG_CTL(data)) & mcntrl_reset)) { mdelay(1); @@ -97,7 +100,7 @@ static inline int wait_reset(long timeout, struct i2c_pnx_algo_data *data) static inline void i2c_pnx_arm_timer(struct i2c_pnx_algo_data *alg_data) { struct timer_list *timer = &alg_data->mif.timer; - unsigned long expires = msecs_to_jiffies(I2C_PNX_TIMEOUT); + unsigned long expires = msecs_to_jiffies(alg_data->timeout); if (expires <= 1) expires = 2; @@ -135,7 +138,7 @@ static int i2c_pnx_start(unsigned char slave_addr, } /* First, make sure bus is idle */ - if (wait_timeout(I2C_PNX_TIMEOUT, alg_data)) { + if (wait_timeout(alg_data)) { /* Somebody else is monopolizing the bus */ dev_err(&alg_data->adapter.dev, "%s: Bus busy. Slave addr = %02x, cntrl = %x, stat = %x\n", @@ -228,7 +231,7 @@ static int i2c_pnx_master_xmit(struct i2c_pnx_algo_data *alg_data) if (alg_data->mif.len == 0) { if (alg_data->last) { /* Wait until the STOP is seen. */ - if (wait_timeout(I2C_PNX_TIMEOUT, alg_data)) + if (wait_timeout(alg_data)) dev_err(&alg_data->adapter.dev, "The bus is still active after timeout\n"); } @@ -326,7 +329,7 @@ static int i2c_pnx_master_rcv(struct i2c_pnx_algo_data *alg_data) if (alg_data->mif.len == 0) { if (alg_data->last) /* Wait until the STOP is seen. */ - if (wait_timeout(I2C_PNX_TIMEOUT, alg_data)) + if (wait_timeout(alg_data)) dev_err(&alg_data->adapter.dev, "The bus is still active after timeout\n"); @@ -442,7 +445,7 @@ static void i2c_pnx_timeout(unsigned long data) ctl |= mcntrl_reset; iowrite32(ctl, I2C_REG_CTL(alg_data)); - wait_reset(I2C_PNX_TIMEOUT, alg_data); + wait_reset(alg_data); alg_data->mif.ret = -EIO; complete(&alg_data->mif.complete); } @@ -457,18 +460,18 @@ static inline void bus_reset_if_active(struct i2c_pnx_algo_data *alg_data) alg_data->adapter.name); iowrite32(ioread32(I2C_REG_CTL(alg_data)) | mcntrl_reset, I2C_REG_CTL(alg_data)); - wait_reset(I2C_PNX_TIMEOUT, alg_data); + wait_reset(alg_data); } else if (!(stat & mstatus_rfe) || !(stat & mstatus_tfe)) { /* If there is data in the fifo's after transfer, * flush fifo's by reset. */ iowrite32(ioread32(I2C_REG_CTL(alg_data)) | mcntrl_reset, I2C_REG_CTL(alg_data)); - wait_reset(I2C_PNX_TIMEOUT, alg_data); + wait_reset(alg_data); } else if (stat & mstatus_nai) { iowrite32(ioread32(I2C_REG_CTL(alg_data)) | mcntrl_reset, I2C_REG_CTL(alg_data)); - wait_reset(I2C_PNX_TIMEOUT, alg_data); + wait_reset(alg_data); } } @@ -612,6 +615,7 @@ static int __devinit i2c_pnx_probe(struct platform_device *pdev) struct i2c_pnx_algo_data *alg_data; unsigned long freq; struct resource *res; + u32 speed = I2C_PNX_SPEED_KHZ_DEFAULT * 1000; alg_data = kzalloc(sizeof(*alg_data), GFP_KERNEL); if (!alg_data) { @@ -626,6 +630,22 @@ static int __devinit i2c_pnx_probe(struct platform_device *pdev) alg_data->adapter.algo_data = alg_data; alg_data->adapter.nr = pdev->id; + alg_data->timeout = I2C_PNX_TIMEOUT_DEFAULT; +#ifdef CONFIG_OF + alg_data->adapter.dev.of_node = of_node_get(pdev->dev.of_node); + if (pdev->dev.of_node) { + of_property_read_u32(pdev->dev.of_node, "clock-frequency", + &speed); + /* + * At this point, it is planned to add an OF timeout property. + * As soon as there is a consensus about how to call and handle + * this, sth. like the following can be put here: + * + * of_property_read_u32(pdev->dev.of_node, "timeout", + * &alg_data->timeout); + */ + } +#endif alg_data->clk = clk_get(&pdev->dev, NULL); if (IS_ERR(alg_data->clk)) { ret = PTR_ERR(alg_data->clk); @@ -651,7 +671,7 @@ static int __devinit i2c_pnx_probe(struct platform_device *pdev) dev_err(&pdev->dev, "I/O region 0x%08x for I2C already in use.\n", res->start); - ret = -ENODEV; + ret = -ENOMEM; goto out_clkget; } @@ -680,14 +700,14 @@ static int __devinit i2c_pnx_probe(struct platform_device *pdev) * the deglitching filter length. */ - tmp = ((freq / 1000) / I2C_PNX_SPEED_KHZ) / 2 - 2; + tmp = (freq / speed) / 2 - 2; if (tmp > 0x3FF) tmp = 0x3FF; iowrite32(tmp, I2C_REG_CKH(alg_data)); iowrite32(tmp, I2C_REG_CKL(alg_data)); iowrite32(mcntrl_reset, I2C_REG_CTL(alg_data)); - if (wait_reset(I2C_PNX_TIMEOUT, alg_data)) { + if (wait_reset(alg_data)) { ret = -ENODEV; goto out_clock; } @@ -710,6 +730,8 @@ static int __devinit i2c_pnx_probe(struct platform_device *pdev) goto out_irq; } + of_i2c_register_devices(&alg_data->adapter); + dev_dbg(&pdev->dev, "%s: Master at %#8x, irq %d.\n", alg_data->adapter.name, res->start, alg_data->irq); @@ -748,10 +770,19 @@ static int __devexit i2c_pnx_remove(struct platform_device *pdev) return 0; } +#ifdef CONFIG_OF +static const struct of_device_id i2c_pnx_of_match[] = { + { .compatible = "nxp,pnx-i2c" }, + { }, +}; +MODULE_DEVICE_TABLE(of, i2c_pnx_of_match); +#endif + static struct platform_driver i2c_pnx_driver = { .driver = { .name = "pnx-i2c", .owner = THIS_MODULE, + .of_match_table = of_match_ptr(i2c_pnx_of_match), }, .probe = i2c_pnx_probe, .remove = __devexit_p(i2c_pnx_remove), diff --git a/include/linux/i2c-pnx.h b/include/linux/i2c-pnx.h index 6e8efb7afd7c..1bc74afe7a35 100644 --- a/include/linux/i2c-pnx.h +++ b/include/linux/i2c-pnx.h @@ -32,6 +32,7 @@ struct i2c_pnx_algo_data { struct i2c_adapter adapter; phys_addr_t base; int irq; + u32 timeout; }; #endif /* __I2C_PNX_H__ */ -- cgit v1.2.3