From 7ef0c12a280c059f4624d311bb1a7d946cbac7b7 Mon Sep 17 00:00:00 2001 From: Guennadi Liakhovetski Date: Fri, 15 Apr 2011 20:18:57 +0200 Subject: i2c: add a module alias to the sh-mobile driver This patch enables I2C driver autoloading on sh-mobile systems. Signed-off-by: Guennadi Liakhovetski Reviewed-by: Simon Horman Cc: Magnus Damm Signed-off-by: Paul Mundt --- drivers/i2c/busses/i2c-sh_mobile.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers/i2c') diff --git a/drivers/i2c/busses/i2c-sh_mobile.c b/drivers/i2c/busses/i2c-sh_mobile.c index 2707f5e1715..81ccd787562 100644 --- a/drivers/i2c/busses/i2c-sh_mobile.c +++ b/drivers/i2c/busses/i2c-sh_mobile.c @@ -729,3 +729,4 @@ module_exit(sh_mobile_i2c_adap_exit); MODULE_DESCRIPTION("SuperH Mobile I2C Bus Controller driver"); MODULE_AUTHOR("Magnus Damm"); MODULE_LICENSE("GPL v2"); +MODULE_ALIAS("platform:i2c-sh_mobile"); -- cgit v1.2.3 From 65a1a0ace554d61ea5a90377a54df1505275c1b1 Mon Sep 17 00:00:00 2001 From: Kenneth Waters Date: Mon, 25 Apr 2011 12:29:54 -0600 Subject: i2c: tegra: Enable new slave mode. For Tegra i2c controller to function properly new slave mode must be enabled. swarren notes: In particular, I found this was needed when working on enabling the Tegra audio driver on the Seaboard board. There are two different PCB layouts for this board; a "clamshell" version, which works just fine without this change, and the original non-clamshell version, which needs this change in order for I2C to operate correctly. Without it, I2C probing fails for some devices, e.g. with: wm8903 0-001a: Device with ID register 0 is not a WM8903 wm8903 0-001a: asoc: failed to probe CODEC wm8903.0-001a: -19 asoc: failed to instantiate card tegra-wm8903: -19 ALSA device list: No soundcards found. Signed-off-by: Rakesh Iyer Cc: stable Signed-off-by: Stephen Warren Signed-off-by: Ben Dooks --- drivers/i2c/busses/i2c-tegra.c | 5 +++++ 1 file changed, 5 insertions(+) (limited to 'drivers/i2c') diff --git a/drivers/i2c/busses/i2c-tegra.c b/drivers/i2c/busses/i2c-tegra.c index b4ab39b741e..5f1b92c74bd 100644 --- a/drivers/i2c/busses/i2c-tegra.c +++ b/drivers/i2c/busses/i2c-tegra.c @@ -330,6 +330,11 @@ static int tegra_i2c_init(struct tegra_i2c_dev *i2c_dev) i2c_writel(i2c_dev, 0, I2C_INT_MASK); clk_set_rate(i2c_dev->clk, i2c_dev->bus_clk_rate * 8); + if (!i2c_dev->is_dvc) { + u32 sl_cfg = i2c_readl(i2c_dev, I2C_SL_CNFG); + i2c_writel(i2c_dev, sl_cfg | I2C_SL_CNFG_NEWSL, I2C_SL_CNFG); + } + val = 7 << I2C_FIFO_CONTROL_TX_TRIG_SHIFT | 0 << I2C_FIFO_CONTROL_RX_TRIG_SHIFT; i2c_writel(i2c_dev, val, I2C_FIFO_CONTROL); -- cgit v1.2.3 From cb63c62d8ee56d169463d8125ec32e1aa0fe11de Mon Sep 17 00:00:00 2001 From: Todd Poynor Date: Mon, 25 Apr 2011 15:32:25 -0600 Subject: i2c: tegra: recover from spurious interrupt storm Re-init the I2C controller when an IRQ arrives with no I2C_INT_STATUS bits set to indicate why the interrupt was sent. Storms of such mystery interrupts are infrequently seen. Dump some more status when these interrupts arrive. Set an error for the current request and wake up the requester (rather than timing out the request or possibly silently ignoring the interrupts). If the I2C block is inside the DVC, also ACK the DVC I2C transfer done interrupt in the ISR error return path, as is done for the normal return path. Signed-off-by: Todd Poynor [swarren: Fix minor checkpatch whitespace issue, commit tag] Signed-off-by: Stephen Warren Signed-off-by: Ben Dooks --- drivers/i2c/busses/i2c-tegra.c | 26 ++++++++++++++++++++++++-- 1 file changed, 24 insertions(+), 2 deletions(-) (limited to 'drivers/i2c') diff --git a/drivers/i2c/busses/i2c-tegra.c b/drivers/i2c/busses/i2c-tegra.c index 5f1b92c74bd..c0b9aa7df0e 100644 --- a/drivers/i2c/busses/i2c-tegra.c +++ b/drivers/i2c/busses/i2c-tegra.c @@ -37,6 +37,7 @@ #define I2C_CNFG 0x000 #define I2C_CNFG_PACKET_MODE_EN (1<<10) #define I2C_CNFG_NEW_MASTER_FSM (1<<11) +#define I2C_STATUS 0x01C #define I2C_SL_CNFG 0x020 #define I2C_SL_CNFG_NEWSL (1<<2) #define I2C_SL_ADDR1 0x02c @@ -77,6 +78,7 @@ #define I2C_ERR_NONE 0x00 #define I2C_ERR_NO_ACK 0x01 #define I2C_ERR_ARBITRATION_LOST 0x02 +#define I2C_ERR_UNKNOWN_INTERRUPT 0x04 #define PACKET_HEADER0_HEADER_SIZE_SHIFT 28 #define PACKET_HEADER0_PACKET_ID_SHIFT 16 @@ -121,6 +123,7 @@ struct tegra_i2c_dev { void __iomem *base; int cont_id; int irq; + bool irq_disabled; int is_dvc; struct completion msg_complete; int msg_err; @@ -343,6 +346,12 @@ static int tegra_i2c_init(struct tegra_i2c_dev *i2c_dev) err = -ETIMEDOUT; clk_disable(i2c_dev->clk); + + if (i2c_dev->irq_disabled) { + i2c_dev->irq_disabled = 0; + enable_irq(i2c_dev->irq); + } + return err; } @@ -355,8 +364,19 @@ static irqreturn_t tegra_i2c_isr(int irq, void *dev_id) status = i2c_readl(i2c_dev, I2C_INT_STATUS); if (status == 0) { - dev_warn(i2c_dev->dev, "interrupt with no status\n"); - return IRQ_NONE; + dev_warn(i2c_dev->dev, "irq status 0 %08x %08x %08x\n", + i2c_readl(i2c_dev, I2C_PACKET_TRANSFER_STATUS), + i2c_readl(i2c_dev, I2C_STATUS), + i2c_readl(i2c_dev, I2C_CNFG)); + i2c_dev->msg_err |= I2C_ERR_UNKNOWN_INTERRUPT; + + if (!i2c_dev->irq_disabled) { + disable_irq_nosync(i2c_dev->irq); + i2c_dev->irq_disabled = 1; + } + + complete(&i2c_dev->msg_complete); + goto err; } if (unlikely(status & status_err)) { @@ -396,6 +416,8 @@ err: I2C_INT_PACKET_XFER_COMPLETE | I2C_INT_TX_FIFO_DATA_REQ | I2C_INT_RX_FIFO_DATA_REQ); i2c_writel(i2c_dev, status, I2C_INT_STATUS); + if (i2c_dev->is_dvc) + dvc_writel(i2c_dev, DVC_STATUS_I2C_DONE_INTR, DVC_STATUS); return IRQ_HANDLED; } -- cgit v1.2.3 From 2078cf3b2230cc2ee456e67d28dd9a869097e1ff Mon Sep 17 00:00:00 2001 From: Erik Gilling Date: Mon, 25 Apr 2011 15:32:26 -0600 Subject: i2c: tegra: fix repeated start handling A repeated start should be used for all but the last msg in an xfer. The NOSTART flag is for skipping the START frame (addr/rw) Signed-off-by: Erik Gilling Signed-off-by: Stephen Warren Signed-off-by: Ben Dooks --- drivers/i2c/busses/i2c-tegra.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers/i2c') diff --git a/drivers/i2c/busses/i2c-tegra.c b/drivers/i2c/busses/i2c-tegra.c index c0b9aa7df0e..6b69b7007f0 100644 --- a/drivers/i2c/busses/i2c-tegra.c +++ b/drivers/i2c/busses/i2c-tegra.c @@ -451,12 +451,12 @@ static int tegra_i2c_xfer_msg(struct tegra_i2c_dev *i2c_dev, packet_header = msg->addr << I2C_HEADER_SLAVE_ADDR_SHIFT; packet_header |= I2C_HEADER_IE_ENABLE; + if (!stop) + packet_header |= I2C_HEADER_REPEAT_START; if (msg->flags & I2C_M_TEN) packet_header |= I2C_HEADER_10BIT_ADDR; if (msg->flags & I2C_M_IGNORE_NAK) packet_header |= I2C_HEADER_CONT_ON_NAK; - if (msg->flags & I2C_M_NOSTART) - packet_header |= I2C_HEADER_REPEAT_START; if (msg->flags & I2C_M_RD) packet_header |= I2C_HEADER_READ; i2c_writel(i2c_dev, packet_header, I2C_TX_FIFO); -- cgit v1.2.3 From 40abcf772357355a04f966416eebc943fd0281d4 Mon Sep 17 00:00:00 2001 From: Jay Cheng Date: Mon, 25 Apr 2011 15:32:27 -0600 Subject: i2c: tegra: Add de-bounce cycles. This enables debouncing of the I2C lines. The debounce period is 2 * the debounce register field value, in terms of the I2C block's main clock. The Tegra TRM indicates that a setting yielding >50nS is desirable. Hence, a setting of 2 => 4 clocks @ 72MHz => ~55nS. Signed-off-by: Ken Radtke [swarren: Added commit description body, Fixed 80-column limit, Reverted file permission change] Signed-off-by: Stephen Warren Signed-off-by: Ben Dooks --- drivers/i2c/busses/i2c-tegra.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'drivers/i2c') diff --git a/drivers/i2c/busses/i2c-tegra.c b/drivers/i2c/busses/i2c-tegra.c index 6b69b7007f0..4d9319665e3 100644 --- a/drivers/i2c/busses/i2c-tegra.c +++ b/drivers/i2c/busses/i2c-tegra.c @@ -35,6 +35,7 @@ #define BYTES_PER_FIFO_WORD 4 #define I2C_CNFG 0x000 +#define I2C_CNFG_DEBOUNCE_CNT_SHIFT 12 #define I2C_CNFG_PACKET_MODE_EN (1<<10) #define I2C_CNFG_NEW_MASTER_FSM (1<<11) #define I2C_STATUS 0x01C @@ -328,7 +329,8 @@ static int tegra_i2c_init(struct tegra_i2c_dev *i2c_dev) if (i2c_dev->is_dvc) tegra_dvc_init(i2c_dev); - val = I2C_CNFG_NEW_MASTER_FSM | I2C_CNFG_PACKET_MODE_EN; + val = I2C_CNFG_NEW_MASTER_FSM | I2C_CNFG_PACKET_MODE_EN | + (0x2 << I2C_CNFG_DEBOUNCE_CNT_SHIFT); i2c_writel(i2c_dev, val, I2C_CNFG); i2c_writel(i2c_dev, 0, I2C_INT_MASK); clk_set_rate(i2c_dev->clk, i2c_dev->bus_clk_rate * 8); -- cgit v1.2.3 From 1082d5d29d9a71f43b969b89ce613374602a6946 Mon Sep 17 00:00:00 2001 From: Magnus Damm Date: Thu, 21 Apr 2011 22:20:39 +0900 Subject: i2c: i2c-sh_mobile clock string removal Remove the clock string magic from the i2c-sh_mobile driver now when all platforms support clkdev properly. Signed-off-by: Magnus Damm Signed-off-by: Ben Dooks --- drivers/i2c/busses/i2c-sh_mobile.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) (limited to 'drivers/i2c') diff --git a/drivers/i2c/busses/i2c-sh_mobile.c b/drivers/i2c/busses/i2c-sh_mobile.c index 2707f5e1715..5a1d37d0b62 100644 --- a/drivers/i2c/busses/i2c-sh_mobile.c +++ b/drivers/i2c/busses/i2c-sh_mobile.c @@ -577,7 +577,6 @@ static int sh_mobile_i2c_probe(struct platform_device *dev) struct sh_mobile_i2c_data *pd; struct i2c_adapter *adap; struct resource *res; - char clk_name[8]; int size; int ret; @@ -587,10 +586,9 @@ static int sh_mobile_i2c_probe(struct platform_device *dev) return -ENOMEM; } - snprintf(clk_name, sizeof(clk_name), "i2c%d", dev->id); - pd->clk = clk_get(&dev->dev, clk_name); + pd->clk = clk_get(&dev->dev, NULL); if (IS_ERR(pd->clk)) { - dev_err(&dev->dev, "cannot get clock \"%s\"\n", clk_name); + dev_err(&dev->dev, "cannot get clock\n"); ret = PTR_ERR(pd->clk); goto err; } -- cgit v1.2.3 From 81f8115305f821335cf9e16110bf0806f7b93283 Mon Sep 17 00:00:00 2001 From: Magnus Damm Date: Thu, 28 Apr 2011 13:25:36 +0900 Subject: i2c: i2c-sh_mobile bus speed platform data V2 Add support to the i2c-sh_mobile driver for setting the I2C bus speed using platform data. Signed-off-by: Magnus Damm Signed-off-by: Ben Dooks --- drivers/i2c/busses/i2c-sh_mobile.c | 13 +++++++++++-- include/linux/i2c/i2c-sh_mobile.h | 10 ++++++++++ 2 files changed, 21 insertions(+), 2 deletions(-) create mode 100644 include/linux/i2c/i2c-sh_mobile.h (limited to 'drivers/i2c') diff --git a/drivers/i2c/busses/i2c-sh_mobile.c b/drivers/i2c/busses/i2c-sh_mobile.c index 5a1d37d0b62..d917dd1cc09 100644 --- a/drivers/i2c/busses/i2c-sh_mobile.c +++ b/drivers/i2c/busses/i2c-sh_mobile.c @@ -32,6 +32,7 @@ #include #include #include +#include /* Transmit operation: */ /* */ @@ -117,7 +118,7 @@ struct sh_mobile_i2c_data { struct device *dev; void __iomem *reg; struct i2c_adapter adap; - + unsigned long bus_speed; struct clk *clk; u_int8_t icic; u_int8_t iccl; @@ -205,7 +206,7 @@ static void activate_ch(struct sh_mobile_i2c_data *pd) * We also round off the result. */ num = i2c_clk * 5; - denom = NORMAL_SPEED * 9; + denom = pd->bus_speed * 9; tmp = num * 10 / denom; if (tmp % 10 >= 5) pd->iccl = (u_int8_t)((num/denom) + 1); @@ -574,6 +575,7 @@ static int sh_mobile_i2c_hook_irqs(struct platform_device *dev, int hook) static int sh_mobile_i2c_probe(struct platform_device *dev) { + struct i2c_sh_mobile_platform_data *pdata = dev->dev.platform_data; struct sh_mobile_i2c_data *pd; struct i2c_adapter *adap; struct resource *res; @@ -618,6 +620,11 @@ static int sh_mobile_i2c_probe(struct platform_device *dev) goto err_irq; } + /* Use platformd data bus speed or NORMAL_SPEED */ + pd->bus_speed = NORMAL_SPEED; + if (pdata && pdata->bus_speed) + pd->bus_speed = pdata->bus_speed; + /* The IIC blocks on SH-Mobile ARM processors * come with two new bits in ICIC. */ @@ -658,6 +665,8 @@ static int sh_mobile_i2c_probe(struct platform_device *dev) goto err_all; } + dev_info(&dev->dev, "I2C adapter %d with bus speed %lu Hz\n", + adap->nr, pd->bus_speed); return 0; err_all: diff --git a/include/linux/i2c/i2c-sh_mobile.h b/include/linux/i2c/i2c-sh_mobile.h new file mode 100644 index 00000000000..beda7081aea --- /dev/null +++ b/include/linux/i2c/i2c-sh_mobile.h @@ -0,0 +1,10 @@ +#ifndef __I2C_SH_MOBILE_H__ +#define __I2C_SH_MOBILE_H__ + +#include + +struct i2c_sh_mobile_platform_data { + unsigned long bus_speed; +}; + +#endif /* __I2C_SH_MOBILE_H__ */ -- cgit v1.2.3 From 9ddabb055d73c63037878bb9346e52c7f2e07e96 Mon Sep 17 00:00:00 2001 From: Wolfram Sang Date: Fri, 29 Apr 2011 15:30:02 +0200 Subject: i2c: pnx: Fix crash due to wrong init of timer->data alg_data is already a pointer which must be passed directly. Reported-by: Dieter Ripp Signed-off-by: Wolfram Sang Cc: Russell King Cc: Ben Dooks Signed-off-by: Ben Dooks --- drivers/i2c/busses/i2c-pnx.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/i2c') diff --git a/drivers/i2c/busses/i2c-pnx.c b/drivers/i2c/busses/i2c-pnx.c index a97e3fec814..04be9f82e14 100644 --- a/drivers/i2c/busses/i2c-pnx.c +++ b/drivers/i2c/busses/i2c-pnx.c @@ -65,7 +65,7 @@ static inline void i2c_pnx_arm_timer(struct i2c_pnx_algo_data *alg_data) jiffies, expires); timer->expires = jiffies + expires; - timer->data = (unsigned long)&alg_data; + timer->data = (unsigned long)alg_data; add_timer(timer); } -- cgit v1.2.3 From b1608d69cb804e414d0887140ba08a9398e4e638 Mon Sep 17 00:00:00 2001 From: Grant Likely Date: Wed, 18 May 2011 11:19:24 -0600 Subject: drivercore: revert addition of of_match to struct device Commit b826291c, "drivercore/dt: add a match table pointer to struct device" added an of_match pointer to struct device to cache the of_match_table entry discovered at driver match time. This was unsafe because matching is not an atomic operation with probing a driver. If two or more drivers are attempted to be matched to a driver at the same time, then the cached matching entry pointer could get overwritten. This patch reverts the of_match cache pointer and reworks all users to call of_match_device() directly instead. Signed-off-by: Grant Likely --- arch/powerpc/platforms/83xx/suspend.c | 7 +++++-- arch/powerpc/sysdev/fsl_msi.c | 7 +++++-- arch/sparc/kernel/pci_sabre.c | 5 ++++- arch/sparc/kernel/pci_schizo.c | 8 ++++++-- drivers/atm/fore200e.c | 7 +++++-- drivers/char/hw_random/n2-drv.c | 7 +++++-- drivers/char/ipmi/ipmi_si_intf.c | 7 +++++-- drivers/char/xilinx_hwicap/xilinx_hwicap.c | 14 +++++++++----- drivers/edac/ppc4xx_edac.c | 2 +- drivers/i2c/busses/i2c-mpc.c | 9 ++++++--- drivers/mmc/host/sdhci-of-core.c | 7 +++++-- drivers/mtd/maps/physmap_of.c | 7 +++++-- drivers/net/can/mscan/mpc5xxx_can.c | 7 +++++-- drivers/net/fs_enet/fs_enet-main.c | 9 ++++++--- drivers/net/fs_enet/mii-fec.c | 7 +++++-- drivers/net/sunhme.c | 7 +++++-- drivers/scsi/qlogicpti.c | 7 +++++-- drivers/tty/serial/of_serial.c | 7 +++++-- drivers/usb/gadget/fsl_qe_udc.c | 7 +++++-- drivers/watchdog/mpc8xxx_wdt.c | 7 +++++-- include/linux/device.h | 1 - include/linux/of_device.h | 12 ++++++------ 22 files changed, 108 insertions(+), 50 deletions(-) (limited to 'drivers/i2c') diff --git a/arch/powerpc/platforms/83xx/suspend.c b/arch/powerpc/platforms/83xx/suspend.c index 188272934cf..104faa8aa23 100644 --- a/arch/powerpc/platforms/83xx/suspend.c +++ b/arch/powerpc/platforms/83xx/suspend.c @@ -318,17 +318,20 @@ static const struct platform_suspend_ops mpc83xx_suspend_ops = { .end = mpc83xx_suspend_end, }; +static struct of_device_id pmc_match[]; static int pmc_probe(struct platform_device *ofdev) { + const struct of_device_id *match; struct device_node *np = ofdev->dev.of_node; struct resource res; struct pmc_type *type; int ret = 0; - if (!ofdev->dev.of_match) + match = of_match_device(pmc_match, &ofdev->dev); + if (!match) return -EINVAL; - type = ofdev->dev.of_match->data; + type = match->data; if (!of_device_is_available(np)) return -ENODEV; diff --git a/arch/powerpc/sysdev/fsl_msi.c b/arch/powerpc/sysdev/fsl_msi.c index d5679dc1e20..01cd2f08951 100644 --- a/arch/powerpc/sysdev/fsl_msi.c +++ b/arch/powerpc/sysdev/fsl_msi.c @@ -304,8 +304,10 @@ static int __devinit fsl_msi_setup_hwirq(struct fsl_msi *msi, return 0; } +static const struct of_device_id fsl_of_msi_ids[]; static int __devinit fsl_of_msi_probe(struct platform_device *dev) { + const struct of_device_id *match; struct fsl_msi *msi; struct resource res; int err, i, j, irq_index, count; @@ -316,9 +318,10 @@ static int __devinit fsl_of_msi_probe(struct platform_device *dev) u32 offset; static const u32 all_avail[] = { 0, NR_MSI_IRQS }; - if (!dev->dev.of_match) + match = of_match_device(fsl_of_msi_ids, &dev->dev); + if (!match) return -EINVAL; - features = dev->dev.of_match->data; + features = match->data; printk(KERN_DEBUG "Setting up Freescale MSI support\n"); diff --git a/arch/sparc/kernel/pci_sabre.c b/arch/sparc/kernel/pci_sabre.c index 948068a083f..d1840dbdaa2 100644 --- a/arch/sparc/kernel/pci_sabre.c +++ b/arch/sparc/kernel/pci_sabre.c @@ -452,8 +452,10 @@ static void __devinit sabre_pbm_init(struct pci_pbm_info *pbm, sabre_scan_bus(pbm, &op->dev); } +static const struct of_device_id sabre_match[]; static int __devinit sabre_probe(struct platform_device *op) { + const struct of_device_id *match; const struct linux_prom64_registers *pr_regs; struct device_node *dp = op->dev.of_node; struct pci_pbm_info *pbm; @@ -463,7 +465,8 @@ static int __devinit sabre_probe(struct platform_device *op) const u32 *vdma; u64 clear_irq; - hummingbird_p = op->dev.of_match && (op->dev.of_match->data != NULL); + match = of_match_device(sabre_match, &op->dev); + hummingbird_p = match && (match->data != NULL); if (!hummingbird_p) { struct device_node *cpu_dp; diff --git a/arch/sparc/kernel/pci_schizo.c b/arch/sparc/kernel/pci_schizo.c index fecfcb2063c..283fbc329a4 100644 --- a/arch/sparc/kernel/pci_schizo.c +++ b/arch/sparc/kernel/pci_schizo.c @@ -1458,11 +1458,15 @@ out_err: return err; } +static const struct of_device_id schizo_match[]; static int __devinit schizo_probe(struct platform_device *op) { - if (!op->dev.of_match) + const struct of_device_id *match; + + match = of_match_device(schizo_match, &op->dev); + if (!match) return -EINVAL; - return __schizo_init(op, (unsigned long) op->dev.of_match->data); + return __schizo_init(op, (unsigned long)match->data); } /* The ordering of this table is very important. Some Tomatillo diff --git a/drivers/atm/fore200e.c b/drivers/atm/fore200e.c index bdd2719f3f6..bc9e702186d 100644 --- a/drivers/atm/fore200e.c +++ b/drivers/atm/fore200e.c @@ -2643,16 +2643,19 @@ fore200e_init(struct fore200e* fore200e, struct device *parent) } #ifdef CONFIG_SBUS +static const struct of_device_id fore200e_sba_match[]; static int __devinit fore200e_sba_probe(struct platform_device *op) { + const struct of_device_id *match; const struct fore200e_bus *bus; struct fore200e *fore200e; static int index = 0; int err; - if (!op->dev.of_match) + match = of_match_device(fore200e_sba_match, &op->dev); + if (!match) return -EINVAL; - bus = op->dev.of_match->data; + bus = match->data; fore200e = kzalloc(sizeof(struct fore200e), GFP_KERNEL); if (!fore200e) diff --git a/drivers/char/hw_random/n2-drv.c b/drivers/char/hw_random/n2-drv.c index 43ac61978d8..ac6739e085e 100644 --- a/drivers/char/hw_random/n2-drv.c +++ b/drivers/char/hw_random/n2-drv.c @@ -619,15 +619,18 @@ static void __devinit n2rng_driver_version(void) pr_info("%s", version); } +static const struct of_device_id n2rng_match[]; static int __devinit n2rng_probe(struct platform_device *op) { + const struct of_device_id *match; int victoria_falls; int err = -ENOMEM; struct n2rng *np; - if (!op->dev.of_match) + match = of_match_device(n2rng_match, &op->dev); + if (!match) return -EINVAL; - victoria_falls = (op->dev.of_match->data != NULL); + victoria_falls = (match->data != NULL); n2rng_driver_version(); np = kzalloc(sizeof(*np), GFP_KERNEL); diff --git a/drivers/char/ipmi/ipmi_si_intf.c b/drivers/char/ipmi/ipmi_si_intf.c index cc6c9b2546a..64c6b853061 100644 --- a/drivers/char/ipmi/ipmi_si_intf.c +++ b/drivers/char/ipmi/ipmi_si_intf.c @@ -2554,9 +2554,11 @@ static struct pci_driver ipmi_pci_driver = { }; #endif /* CONFIG_PCI */ +static struct of_device_id ipmi_match[]; static int __devinit ipmi_probe(struct platform_device *dev) { #ifdef CONFIG_OF + const struct of_device_id *match; struct smi_info *info; struct resource resource; const __be32 *regsize, *regspacing, *regshift; @@ -2566,7 +2568,8 @@ static int __devinit ipmi_probe(struct platform_device *dev) dev_info(&dev->dev, "probing via device tree\n"); - if (!dev->dev.of_match) + match = of_match_device(ipmi_match, &dev->dev); + if (!match) return -EINVAL; ret = of_address_to_resource(np, 0, &resource); @@ -2601,7 +2604,7 @@ static int __devinit ipmi_probe(struct platform_device *dev) return -ENOMEM; } - info->si_type = (enum si_type) dev->dev.of_match->data; + info->si_type = (enum si_type) match->data; info->addr_source = SI_DEVICETREE; info->irq_setup = std_irq_setup; diff --git a/drivers/char/xilinx_hwicap/xilinx_hwicap.c b/drivers/char/xilinx_hwicap/xilinx_hwicap.c index d6412c16385..39ccdeada79 100644 --- a/drivers/char/xilinx_hwicap/xilinx_hwicap.c +++ b/drivers/char/xilinx_hwicap/xilinx_hwicap.c @@ -715,13 +715,13 @@ static int __devexit hwicap_remove(struct device *dev) } #ifdef CONFIG_OF -static int __devinit hwicap_of_probe(struct platform_device *op) +static int __devinit hwicap_of_probe(struct platform_device *op, + const struct hwicap_driver_config *config) { struct resource res; const unsigned int *id; const char *family; int rc; - const struct hwicap_driver_config *config = op->dev.of_match->data; const struct config_registers *regs; @@ -751,20 +751,24 @@ static int __devinit hwicap_of_probe(struct platform_device *op) regs); } #else -static inline int hwicap_of_probe(struct platform_device *op) +static inline int hwicap_of_probe(struct platform_device *op, + const struct hwicap_driver_config *config) { return -EINVAL; } #endif /* CONFIG_OF */ +static const struct of_device_id __devinitconst hwicap_of_match[]; static int __devinit hwicap_drv_probe(struct platform_device *pdev) { + const struct of_device_id *match; struct resource *res; const struct config_registers *regs; const char *family; - if (pdev->dev.of_match) - return hwicap_of_probe(pdev); + match = of_match_device(hwicap_of_match, &pdev->dev); + if (match) + return hwicap_of_probe(pdev, match->data); res = platform_get_resource(pdev, IORESOURCE_MEM, 0); if (!res) diff --git a/drivers/edac/ppc4xx_edac.c b/drivers/edac/ppc4xx_edac.c index c1f0045ceb8..af8e7b1aa29 100644 --- a/drivers/edac/ppc4xx_edac.c +++ b/drivers/edac/ppc4xx_edac.c @@ -1019,7 +1019,7 @@ ppc4xx_edac_mc_init(struct mem_ctl_info *mci, struct ppc4xx_edac_pdata *pdata = NULL; const struct device_node *np = op->dev.of_node; - if (op->dev.of_match == NULL) + if (of_match_device(ppc4xx_edac_match, &op->dev) == NULL) return -EINVAL; /* Initial driver pointers and private data */ diff --git a/drivers/i2c/busses/i2c-mpc.c b/drivers/i2c/busses/i2c-mpc.c index 75b984c519a..107397a606b 100644 --- a/drivers/i2c/busses/i2c-mpc.c +++ b/drivers/i2c/busses/i2c-mpc.c @@ -560,15 +560,18 @@ static struct i2c_adapter mpc_ops = { .timeout = HZ, }; +static const struct of_device_id mpc_i2c_of_match[]; static int __devinit fsl_i2c_probe(struct platform_device *op) { + const struct of_device_id *match; struct mpc_i2c *i2c; const u32 *prop; u32 clock = MPC_I2C_CLOCK_LEGACY; int result = 0; int plen; - if (!op->dev.of_match) + match = of_match_device(mpc_i2c_of_match, &op->dev); + if (!match) return -EINVAL; i2c = kzalloc(sizeof(*i2c), GFP_KERNEL); @@ -605,8 +608,8 @@ static int __devinit fsl_i2c_probe(struct platform_device *op) clock = *prop; } - if (op->dev.of_match->data) { - struct mpc_i2c_data *data = op->dev.of_match->data; + if (match->data) { + struct mpc_i2c_data *data = match->data; data->setup(op->dev.of_node, i2c, clock, data->prescaler); } else { /* Backwards compatibility */ diff --git a/drivers/mmc/host/sdhci-of-core.c b/drivers/mmc/host/sdhci-of-core.c index f9b611fc773..60e4186a434 100644 --- a/drivers/mmc/host/sdhci-of-core.c +++ b/drivers/mmc/host/sdhci-of-core.c @@ -124,8 +124,10 @@ static bool __devinit sdhci_of_wp_inverted(struct device_node *np) #endif } +static const struct of_device_id sdhci_of_match[]; static int __devinit sdhci_of_probe(struct platform_device *ofdev) { + const struct of_device_id *match; struct device_node *np = ofdev->dev.of_node; struct sdhci_of_data *sdhci_of_data; struct sdhci_host *host; @@ -134,9 +136,10 @@ static int __devinit sdhci_of_probe(struct platform_device *ofdev) int size; int ret; - if (!ofdev->dev.of_match) + match = of_match_device(sdhci_of_match, &ofdev->dev); + if (!match) return -EINVAL; - sdhci_of_data = ofdev->dev.of_match->data; + sdhci_of_data = match->data; if (!of_device_is_available(np)) return -ENODEV; diff --git a/drivers/mtd/maps/physmap_of.c b/drivers/mtd/maps/physmap_of.c index bd483f0c57e..c1d33464aee 100644 --- a/drivers/mtd/maps/physmap_of.c +++ b/drivers/mtd/maps/physmap_of.c @@ -214,11 +214,13 @@ static void __devinit of_free_probes(const char **probes) } #endif +static struct of_device_id of_flash_match[]; static int __devinit of_flash_probe(struct platform_device *dev) { #ifdef CONFIG_MTD_PARTITIONS const char **part_probe_types; #endif + const struct of_device_id *match; struct device_node *dp = dev->dev.of_node; struct resource res; struct of_flash *info; @@ -232,9 +234,10 @@ static int __devinit of_flash_probe(struct platform_device *dev) struct mtd_info **mtd_list = NULL; resource_size_t res_size; - if (!dev->dev.of_match) + match = of_match_device(of_flash_match, &dev->dev); + if (!match) return -EINVAL; - probe_type = dev->dev.of_match->data; + probe_type = match->data; reg_tuple_size = (of_n_addr_cells(dp) + of_n_size_cells(dp)) * sizeof(u32); diff --git a/drivers/net/can/mscan/mpc5xxx_can.c b/drivers/net/can/mscan/mpc5xxx_can.c index bd1d811c204..5fedc337556 100644 --- a/drivers/net/can/mscan/mpc5xxx_can.c +++ b/drivers/net/can/mscan/mpc5xxx_can.c @@ -247,8 +247,10 @@ static u32 __devinit mpc512x_can_get_clock(struct platform_device *ofdev, } #endif /* CONFIG_PPC_MPC512x */ +static struct of_device_id mpc5xxx_can_table[]; static int __devinit mpc5xxx_can_probe(struct platform_device *ofdev) { + const struct of_device_id *match; struct mpc5xxx_can_data *data; struct device_node *np = ofdev->dev.of_node; struct net_device *dev; @@ -258,9 +260,10 @@ static int __devinit mpc5xxx_can_probe(struct platform_device *ofdev) int irq, mscan_clksrc = 0; int err = -ENOMEM; - if (!ofdev->dev.of_match) + match = of_match_device(mpc5xxx_can_table, &ofdev->dev); + if (!match) return -EINVAL; - data = (struct mpc5xxx_can_data *)ofdev->dev.of_match->data; + data = match->data; base = of_iomap(np, 0); if (!base) { diff --git a/drivers/net/fs_enet/fs_enet-main.c b/drivers/net/fs_enet/fs_enet-main.c index 24cb953900d..5131e61c358 100644 --- a/drivers/net/fs_enet/fs_enet-main.c +++ b/drivers/net/fs_enet/fs_enet-main.c @@ -998,8 +998,10 @@ static const struct net_device_ops fs_enet_netdev_ops = { #endif }; +static struct of_device_id fs_enet_match[]; static int __devinit fs_enet_probe(struct platform_device *ofdev) { + const struct of_device_id *match; struct net_device *ndev; struct fs_enet_private *fep; struct fs_platform_info *fpi; @@ -1007,14 +1009,15 @@ static int __devinit fs_enet_probe(struct platform_device *ofdev) const u8 *mac_addr; int privsize, len, ret = -ENODEV; - if (!ofdev->dev.of_match) + match = of_match_device(fs_enet_match, &ofdev->dev); + if (!match) return -EINVAL; fpi = kzalloc(sizeof(*fpi), GFP_KERNEL); if (!fpi) return -ENOMEM; - if (!IS_FEC(ofdev->dev.of_match)) { + if (!IS_FEC(match)) { data = of_get_property(ofdev->dev.of_node, "fsl,cpm-command", &len); if (!data || len != 4) goto out_free_fpi; @@ -1049,7 +1052,7 @@ static int __devinit fs_enet_probe(struct platform_device *ofdev) fep->dev = &ofdev->dev; fep->ndev = ndev; fep->fpi = fpi; - fep->ops = ofdev->dev.of_match->data; + fep->ops = match->data; ret = fep->ops->setup_data(ndev); if (ret) diff --git a/drivers/net/fs_enet/mii-fec.c b/drivers/net/fs_enet/mii-fec.c index 7e840d373ab..6a2e150e75b 100644 --- a/drivers/net/fs_enet/mii-fec.c +++ b/drivers/net/fs_enet/mii-fec.c @@ -101,17 +101,20 @@ static int fs_enet_fec_mii_reset(struct mii_bus *bus) return 0; } +static struct of_device_id fs_enet_mdio_fec_match[]; static int __devinit fs_enet_mdio_probe(struct platform_device *ofdev) { + const struct of_device_id *match; struct resource res; struct mii_bus *new_bus; struct fec_info *fec; int (*get_bus_freq)(struct device_node *); int ret = -ENOMEM, clock, speed; - if (!ofdev->dev.of_match) + match = of_match_device(fs_enet_mdio_fec_match, &ofdev->dev); + if (!match) return -EINVAL; - get_bus_freq = ofdev->dev.of_match->data; + get_bus_freq = match->data; new_bus = mdiobus_alloc(); if (!new_bus) diff --git a/drivers/net/sunhme.c b/drivers/net/sunhme.c index eb4f59fb01e..bff2f7999ff 100644 --- a/drivers/net/sunhme.c +++ b/drivers/net/sunhme.c @@ -3237,15 +3237,18 @@ static void happy_meal_pci_exit(void) #endif #ifdef CONFIG_SBUS +static const struct of_device_id hme_sbus_match[]; static int __devinit hme_sbus_probe(struct platform_device *op) { + const struct of_device_id *match; struct device_node *dp = op->dev.of_node; const char *model = of_get_property(dp, "model", NULL); int is_qfe; - if (!op->dev.of_match) + match = of_match_device(hme_sbus_match, &op->dev); + if (!match) return -EINVAL; - is_qfe = (op->dev.of_match->data != NULL); + is_qfe = (match->data != NULL); if (!is_qfe && model && !strcmp(model, "SUNW,sbus-qfe")) is_qfe = 1; diff --git a/drivers/scsi/qlogicpti.c b/drivers/scsi/qlogicpti.c index e2d45c91b8e..9689d41c788 100644 --- a/drivers/scsi/qlogicpti.c +++ b/drivers/scsi/qlogicpti.c @@ -1292,8 +1292,10 @@ static struct scsi_host_template qpti_template = { .use_clustering = ENABLE_CLUSTERING, }; +static const struct of_device_id qpti_match[]; static int __devinit qpti_sbus_probe(struct platform_device *op) { + const struct of_device_id *match; struct scsi_host_template *tpnt; struct device_node *dp = op->dev.of_node; struct Scsi_Host *host; @@ -1301,9 +1303,10 @@ static int __devinit qpti_sbus_probe(struct platform_device *op) static int nqptis; const char *fcode; - if (!op->dev.of_match) + match = of_match_device(qpti_match, &op->dev); + if (!match) return -EINVAL; - tpnt = op->dev.of_match->data; + tpnt = match->data; /* Sometimes Antares cards come up not completely * setup, and we get a report of a zero IRQ. diff --git a/drivers/tty/serial/of_serial.c b/drivers/tty/serial/of_serial.c index 0e8eec516df..c911b2419ab 100644 --- a/drivers/tty/serial/of_serial.c +++ b/drivers/tty/serial/of_serial.c @@ -80,14 +80,17 @@ static int __devinit of_platform_serial_setup(struct platform_device *ofdev, /* * Try to register a serial port */ +static struct of_device_id of_platform_serial_table[]; static int __devinit of_platform_serial_probe(struct platform_device *ofdev) { + const struct of_device_id *match; struct of_serial_info *info; struct uart_port port; int port_type; int ret; - if (!ofdev->dev.of_match) + match = of_match_device(of_platform_serial_table, &ofdev->dev); + if (!match) return -EINVAL; if (of_find_property(ofdev->dev.of_node, "used-by-rtas", NULL)) @@ -97,7 +100,7 @@ static int __devinit of_platform_serial_probe(struct platform_device *ofdev) if (info == NULL) return -ENOMEM; - port_type = (unsigned long)ofdev->dev.of_match->data; + port_type = (unsigned long)match->data; ret = of_platform_serial_setup(ofdev, port_type, &port); if (ret) goto out; diff --git a/drivers/usb/gadget/fsl_qe_udc.c b/drivers/usb/gadget/fsl_qe_udc.c index 36613b37c50..3a68e09309f 100644 --- a/drivers/usb/gadget/fsl_qe_udc.c +++ b/drivers/usb/gadget/fsl_qe_udc.c @@ -2539,15 +2539,18 @@ static void qe_udc_release(struct device *dev) } /* Driver probe functions */ +static const struct of_device_id qe_udc_match[]; static int __devinit qe_udc_probe(struct platform_device *ofdev) { + const struct of_device_id *match; struct device_node *np = ofdev->dev.of_node; struct qe_ep *ep; unsigned int ret = 0; unsigned int i; const void *prop; - if (!ofdev->dev.of_match) + match = of_match_device(qe_udc_match, &ofdev->dev); + if (!match) return -EINVAL; prop = of_get_property(np, "mode", NULL); @@ -2561,7 +2564,7 @@ static int __devinit qe_udc_probe(struct platform_device *ofdev) return -ENOMEM; } - udc_controller->soc_type = (unsigned long)ofdev->dev.of_match->data; + udc_controller->soc_type = (unsigned long)match->data; udc_controller->usb_regs = of_iomap(np, 0); if (!udc_controller->usb_regs) { ret = -ENOMEM; diff --git a/drivers/watchdog/mpc8xxx_wdt.c b/drivers/watchdog/mpc8xxx_wdt.c index 528bceb220f..eed5436ffb5 100644 --- a/drivers/watchdog/mpc8xxx_wdt.c +++ b/drivers/watchdog/mpc8xxx_wdt.c @@ -185,17 +185,20 @@ static struct miscdevice mpc8xxx_wdt_miscdev = { .fops = &mpc8xxx_wdt_fops, }; +static const struct of_device_id mpc8xxx_wdt_match[]; static int __devinit mpc8xxx_wdt_probe(struct platform_device *ofdev) { int ret; + const struct of_device_id *match; struct device_node *np = ofdev->dev.of_node; struct mpc8xxx_wdt_type *wdt_type; u32 freq = fsl_get_sys_freq(); bool enabled; - if (!ofdev->dev.of_match) + match = of_match_device(mpc8xxx_wdt_match, &ofdev->dev); + if (!match) return -EINVAL; - wdt_type = ofdev->dev.of_match->data; + wdt_type = match->data; if (!freq || freq == -1) return -EINVAL; diff --git a/include/linux/device.h b/include/linux/device.h index ab8dfc09570..d08399db6e2 100644 --- a/include/linux/device.h +++ b/include/linux/device.h @@ -442,7 +442,6 @@ struct device { struct dev_archdata archdata; struct device_node *of_node; /* associated device tree node */ - const struct of_device_id *of_match; /* matching of_device_id from driver */ dev_t devt; /* dev_t, creates the sysfs "dev" */ diff --git a/include/linux/of_device.h b/include/linux/of_device.h index b33d68814a7..ae5638480ef 100644 --- a/include/linux/of_device.h +++ b/include/linux/of_device.h @@ -21,12 +21,7 @@ extern void of_device_make_bus_id(struct device *dev); static inline int of_driver_match_device(struct device *dev, const struct device_driver *drv) { - const struct of_device_id *match; - - match = of_match_device(drv->of_match_table, dev); - if (match) - dev->of_match = match; - return match != NULL; + return of_match_device(drv->of_match_table, dev) != NULL; } extern struct platform_device *of_dev_get(struct platform_device *dev); @@ -62,6 +57,11 @@ static inline int of_device_uevent(struct device *dev, static inline void of_device_node_put(struct device *dev) { } +static inline const struct of_device_id *of_match_device( + const struct of_device_id *matches, const struct device *dev) +{ + return NULL; +} #endif /* CONFIG_OF_DEVICE */ #endif /* _LINUX_OF_DEVICE_H */ -- cgit v1.2.3 From e05503ef1186ad33dfe56794407891eb1dd93ef6 Mon Sep 17 00:00:00 2001 From: Jean Delvare Date: Wed, 18 May 2011 16:49:24 +0200 Subject: Haavard Skinnemoen has left Atmel Haavard's e-mail address at Atmel is no longer valid. Signed-off-by: Jean Delvare Acked-by: Havard Skinnemoen Signed-off-by: Jiri Kosina --- drivers/dma/dmatest.c | 2 +- drivers/dma/dw_dmac.c | 2 +- drivers/i2c/busses/i2c-gpio.c | 2 +- drivers/mmc/host/atmel-mci.c | 2 +- drivers/net/macb.c | 2 +- drivers/spi/atmel_spi.c | 2 +- drivers/usb/gadget/atmel_usba_udc.c | 2 +- drivers/video/backlight/ltv350qv.c | 2 +- scripts/checkstack.pl | 2 +- 9 files changed, 9 insertions(+), 9 deletions(-) (limited to 'drivers/i2c') diff --git a/drivers/dma/dmatest.c b/drivers/dma/dmatest.c index 8597ff269bf..b4f5c32b6a4 100644 --- a/drivers/dma/dmatest.c +++ b/drivers/dma/dmatest.c @@ -634,5 +634,5 @@ static void __exit dmatest_exit(void) } module_exit(dmatest_exit); -MODULE_AUTHOR("Haavard Skinnemoen "); +MODULE_AUTHOR("Haavard Skinnemoen (Atmel)"); MODULE_LICENSE("GPL v2"); diff --git a/drivers/dma/dw_dmac.c b/drivers/dma/dw_dmac.c index 9c25c7d099e..2a2e2fa00e9 100644 --- a/drivers/dma/dw_dmac.c +++ b/drivers/dma/dw_dmac.c @@ -1486,4 +1486,4 @@ module_exit(dw_exit); MODULE_LICENSE("GPL v2"); MODULE_DESCRIPTION("Synopsys DesignWare DMA Controller driver"); -MODULE_AUTHOR("Haavard Skinnemoen "); +MODULE_AUTHOR("Haavard Skinnemoen (Atmel)"); diff --git a/drivers/i2c/busses/i2c-gpio.c b/drivers/i2c/busses/i2c-gpio.c index d9aa9a649e3..a651779d9ff 100644 --- a/drivers/i2c/busses/i2c-gpio.c +++ b/drivers/i2c/busses/i2c-gpio.c @@ -219,7 +219,7 @@ static void __exit i2c_gpio_exit(void) } module_exit(i2c_gpio_exit); -MODULE_AUTHOR("Haavard Skinnemoen "); +MODULE_AUTHOR("Haavard Skinnemoen (Atmel)"); MODULE_DESCRIPTION("Platform-independent bitbanging I2C driver"); MODULE_LICENSE("GPL"); MODULE_ALIAS("platform:i2c-gpio"); diff --git a/drivers/mmc/host/atmel-mci.c b/drivers/mmc/host/atmel-mci.c index ea3888b65d5..aa8039f473c 100644 --- a/drivers/mmc/host/atmel-mci.c +++ b/drivers/mmc/host/atmel-mci.c @@ -1899,5 +1899,5 @@ late_initcall(atmci_init); /* try to load after dma driver when built-in */ module_exit(atmci_exit); MODULE_DESCRIPTION("Atmel Multimedia Card Interface driver"); -MODULE_AUTHOR("Haavard Skinnemoen "); +MODULE_AUTHOR("Haavard Skinnemoen (Atmel)"); MODULE_LICENSE("GPL v2"); diff --git a/drivers/net/macb.c b/drivers/net/macb.c index 79ccb54ab00..101cf566361 100644 --- a/drivers/net/macb.c +++ b/drivers/net/macb.c @@ -1351,5 +1351,5 @@ module_exit(macb_exit); MODULE_LICENSE("GPL"); MODULE_DESCRIPTION("Atmel MACB Ethernet driver"); -MODULE_AUTHOR("Haavard Skinnemoen "); +MODULE_AUTHOR("Haavard Skinnemoen (Atmel)"); MODULE_ALIAS("platform:macb"); diff --git a/drivers/spi/atmel_spi.c b/drivers/spi/atmel_spi.c index 1a478bf88c9..08711e9202a 100644 --- a/drivers/spi/atmel_spi.c +++ b/drivers/spi/atmel_spi.c @@ -935,6 +935,6 @@ static void __exit atmel_spi_exit(void) module_exit(atmel_spi_exit); MODULE_DESCRIPTION("Atmel AT32/AT91 SPI Controller driver"); -MODULE_AUTHOR("Haavard Skinnemoen "); +MODULE_AUTHOR("Haavard Skinnemoen (Atmel)"); MODULE_LICENSE("GPL"); MODULE_ALIAS("platform:atmel_spi"); diff --git a/drivers/usb/gadget/atmel_usba_udc.c b/drivers/usb/gadget/atmel_usba_udc.c index e7c65a4408f..db1a659702b 100644 --- a/drivers/usb/gadget/atmel_usba_udc.c +++ b/drivers/usb/gadget/atmel_usba_udc.c @@ -2095,6 +2095,6 @@ static void __exit udc_exit(void) module_exit(udc_exit); MODULE_DESCRIPTION("Atmel USBA UDC driver"); -MODULE_AUTHOR("Haavard Skinnemoen "); +MODULE_AUTHOR("Haavard Skinnemoen (Atmel)"); MODULE_LICENSE("GPL"); MODULE_ALIAS("platform:atmel_usba_udc"); diff --git a/drivers/video/backlight/ltv350qv.c b/drivers/video/backlight/ltv350qv.c index dd0e84a9bd2..cca43c06d3c 100644 --- a/drivers/video/backlight/ltv350qv.c +++ b/drivers/video/backlight/ltv350qv.c @@ -333,7 +333,7 @@ static void __exit ltv350qv_exit(void) module_init(ltv350qv_init); module_exit(ltv350qv_exit); -MODULE_AUTHOR("Haavard Skinnemoen "); +MODULE_AUTHOR("Haavard Skinnemoen (Atmel)"); MODULE_DESCRIPTION("Samsung LTV350QV LCD Driver"); MODULE_LICENSE("GPL"); MODULE_ALIAS("spi:ltv350qv"); diff --git a/scripts/checkstack.pl b/scripts/checkstack.pl index 1afff6658a7..17e38439670 100755 --- a/scripts/checkstack.pl +++ b/scripts/checkstack.pl @@ -12,7 +12,7 @@ # sh64 port by Paul Mundt # Random bits by Matt Mackall # M68k port by Geert Uytterhoeven and Andreas Schwab -# AVR32 port by Haavard Skinnemoen +# AVR32 port by Haavard Skinnemoen (Atmel) # PARISC port by Kyle McMartin # sparc port by Martin Habets # -- cgit v1.2.3 From a20d23945f30ec701a544fdd90d6537f4041af6f Mon Sep 17 00:00:00 2001 From: Jonas Aberg Date: Fri, 13 May 2011 12:29:02 +0200 Subject: i2c-nomadik: add regulator support This on-chip I2C controller needs to fetch the regulator representing its voltage domain so that it won't be switched off. Signed-off-by: Jonas Aberg Signed-off-by: Linus Walleij Signed-off-by: Ben Dooks --- drivers/i2c/busses/i2c-nomadik.c | 73 +++++++++++++++++++++++++++++++--------- 1 file changed, 58 insertions(+), 15 deletions(-) (limited to 'drivers/i2c') diff --git a/drivers/i2c/busses/i2c-nomadik.c b/drivers/i2c/busses/i2c-nomadik.c index e10e5cf3751..182761eace8 100644 --- a/drivers/i2c/busses/i2c-nomadik.c +++ b/drivers/i2c/busses/i2c-nomadik.c @@ -22,6 +22,7 @@ #include #include #include +#include #include @@ -151,6 +152,7 @@ struct i2c_nmk_client { * @stop: stop condition * @xfer_complete: acknowledge completion for a I2C message * @result: controller propogated result + * @busy: Busy doing transfer */ struct nmk_i2c_dev { struct platform_device *pdev; @@ -163,6 +165,8 @@ struct nmk_i2c_dev { int stop; struct completion xfer_complete; int result; + struct regulator *regulator; + bool busy; }; /* controller's abort causes */ @@ -257,7 +261,7 @@ static int init_hw(struct nmk_i2c_dev *dev) stat = flush_i2c_fifo(dev); if (stat) - return stat; + goto exit; /* disable the controller */ i2c_clr_bit(dev->virtbase + I2C_CR , I2C_CR_PE); @@ -268,10 +272,16 @@ static int init_hw(struct nmk_i2c_dev *dev) dev->cli.operation = I2C_NO_OPERATION; +exit: + /* TODO: Why disable clocks after init hw? */ clk_disable(dev->clk); - + /* + * TODO: What is this delay for? + * Must be pretty pointless since the hw block + * is frozen. Or? + */ udelay(I2C_DELAY); - return 0; + return stat; } /* enable peripheral, master mode operation */ @@ -562,9 +572,14 @@ static int nmk_i2c_xfer(struct i2c_adapter *i2c_adap, u32 cause; struct nmk_i2c_dev *dev = i2c_get_adapdata(i2c_adap); + dev->busy = true; + + if (dev->regulator) + regulator_enable(dev->regulator); + status = init_hw(dev); if (status) - return status; + goto out2; clk_enable(dev->clk); @@ -575,7 +590,9 @@ static int nmk_i2c_xfer(struct i2c_adapter *i2c_adap, if (unlikely(msgs[i].flags & I2C_M_TEN)) { dev_err(&dev->pdev->dev, "10 bit addressing" "not supported\n"); - return -EINVAL; + + status = -EINVAL; + goto out; } dev->cli.slave_adr = msgs[i].addr; dev->cli.buffer = msgs[i].buf; @@ -600,12 +617,19 @@ static int nmk_i2c_xfer(struct i2c_adapter *i2c_adap, dev_err(&dev->pdev->dev, "%s\n", cause >= ARRAY_SIZE(abort_causes) ? "unknown reason" : abort_causes[cause]); - clk_disable(dev->clk); - return status; + + goto out; } udelay(I2C_DELAY); } + +out: clk_disable(dev->clk); +out2: + if (dev->regulator) + regulator_disable(dev->regulator); + + dev->busy = false; /* return the no. messages processed */ if (status) @@ -805,6 +829,21 @@ static irqreturn_t i2c_irq_handler(int irq, void *arg) return IRQ_HANDLED; } + +#ifdef CONFIG_PM +static int nmk_i2c_suspend(struct platform_device *pdev, pm_message_t mesg) +{ + struct nmk_i2c_dev *dev = platform_get_drvdata(pdev); + + if (dev->busy) + return -EBUSY; + else + return 0; +} +#else +#define nmk_i2c_suspend NULL +#endif + static unsigned int nmk_i2c_functionality(struct i2c_adapter *adap) { return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL; @@ -830,7 +869,7 @@ static int __devinit nmk_i2c_probe(struct platform_device *pdev) ret = -ENOMEM; goto err_no_mem; } - + dev->busy = false; dev->pdev = pdev; platform_set_drvdata(pdev, dev); @@ -860,6 +899,12 @@ static int __devinit nmk_i2c_probe(struct platform_device *pdev) goto err_irq; } + dev->regulator = regulator_get(&pdev->dev, "v-i2c"); + if (IS_ERR(dev->regulator)) { + dev_warn(&pdev->dev, "could not get i2c regulator\n"); + dev->regulator = NULL; + } + dev->clk = clk_get(&pdev->dev, NULL); if (IS_ERR(dev->clk)) { dev_err(&pdev->dev, "could not get i2c clock\n"); @@ -887,12 +932,6 @@ static int __devinit nmk_i2c_probe(struct platform_device *pdev) i2c_set_adapdata(adap, dev); - ret = init_hw(dev); - if (ret != 0) { - dev_err(&pdev->dev, "error in initializing i2c hardware\n"); - goto err_init_hw; - } - dev_info(&pdev->dev, "initialize %s on virtual " "base %p\n", adap->name, dev->virtbase); @@ -904,10 +943,11 @@ static int __devinit nmk_i2c_probe(struct platform_device *pdev) return 0; - err_init_hw: err_add_adap: clk_put(dev->clk); err_no_clk: + if (dev->regulator) + regulator_put(dev->regulator); free_irq(dev->irq, dev); err_irq: iounmap(dev->virtbase); @@ -938,6 +978,8 @@ static int __devexit nmk_i2c_remove(struct platform_device *pdev) if (res) release_mem_region(res->start, resource_size(res)); clk_put(dev->clk); + if (dev->regulator) + regulator_put(dev->regulator); platform_set_drvdata(pdev, NULL); kfree(dev); @@ -951,6 +993,7 @@ static struct platform_driver nmk_i2c_driver = { }, .probe = nmk_i2c_probe, .remove = __devexit_p(nmk_i2c_remove), + .suspend = nmk_i2c_suspend, }; static int __init nmk_i2c_init(void) -- cgit v1.2.3 From 9772760079253cd9a428434b43d415d18b152332 Mon Sep 17 00:00:00 2001 From: Virupax Sadashivpetimath Date: Fri, 13 May 2011 12:29:12 +0200 Subject: i2c-nomadik: make i2c timeout specific per i2c bus Add option to have different i2c timeout delay for different i2c buses specified in platform data. Default to the old value unless specified. Signed-off-by: Virupax Sadashivpetimath Reviewed-by: Srinidhi Kasagar Signed-off-by: Linus Walleij Signed-off-by: Ben Dooks --- arch/arm/plat-nomadik/include/plat/i2c.h | 6 ++++-- drivers/i2c/busses/i2c-nomadik.c | 10 ++++------ 2 files changed, 8 insertions(+), 8 deletions(-) (limited to 'drivers/i2c') diff --git a/arch/arm/plat-nomadik/include/plat/i2c.h b/arch/arm/plat-nomadik/include/plat/i2c.h index 1621db67a53..4ed4e27d136 100644 --- a/arch/arm/plat-nomadik/include/plat/i2c.h +++ b/arch/arm/plat-nomadik/include/plat/i2c.h @@ -24,13 +24,15 @@ enum i2c_freq_mode { * to the values of 14, 6, 2 for a 48 MHz i2c clk * @tft: Tx FIFO Threshold in bytes * @rft: Rx FIFO Threshold in bytes + * @timeout Slave response timeout(ms) * @sm: speed mode */ struct nmk_i2c_controller { unsigned long clk_freq; unsigned short slsu; - unsigned char tft; - unsigned char rft; + unsigned char tft; + unsigned char rft; + int timeout; enum i2c_freq_mode sm; }; diff --git a/drivers/i2c/busses/i2c-nomadik.c b/drivers/i2c/busses/i2c-nomadik.c index 182761eace8..3bf95b90aba 100644 --- a/drivers/i2c/busses/i2c-nomadik.c +++ b/drivers/i2c/busses/i2c-nomadik.c @@ -121,9 +121,6 @@ enum i2c_operation { I2C_READ = 0x01 }; -/* controller response timeout in ms */ -#define I2C_TIMEOUT_MS 2000 - /** * struct i2c_nmk_client - client specific data * @slave_adr: 7-bit slave address @@ -213,7 +210,7 @@ static int flush_i2c_fifo(struct nmk_i2c_dev *dev) writel((I2C_CR_FTX | I2C_CR_FRX), dev->virtbase + I2C_CR); for (i = 0; i < LOOP_ATTEMPTS; i++) { - timeout = jiffies + msecs_to_jiffies(I2C_TIMEOUT_MS); + timeout = jiffies + msecs_to_jiffies(dev->adap.timeout); while (!time_after(jiffies, timeout)) { if ((readl(dev->virtbase + I2C_CR) & @@ -434,7 +431,7 @@ static int read_i2c(struct nmk_i2c_dev *dev) dev->virtbase + I2C_IMSCR); timeout = wait_for_completion_interruptible_timeout( - &dev->xfer_complete, msecs_to_jiffies(I2C_TIMEOUT_MS)); + &dev->xfer_complete, msecs_to_jiffies(dev->adap.timeout)); if (timeout < 0) { dev_err(&dev->pdev->dev, @@ -498,7 +495,7 @@ static int write_i2c(struct nmk_i2c_dev *dev) dev->virtbase + I2C_IMSCR); timeout = wait_for_completion_interruptible_timeout( - &dev->xfer_complete, msecs_to_jiffies(I2C_TIMEOUT_MS)); + &dev->xfer_complete, msecs_to_jiffies(dev->adap.timeout)); if (timeout < 0) { dev_err(&dev->pdev->dev, @@ -917,6 +914,7 @@ static int __devinit nmk_i2c_probe(struct platform_device *pdev) adap->owner = THIS_MODULE; adap->class = I2C_CLASS_HWMON | I2C_CLASS_SPD; adap->algo = &nmk_i2c_algo; + adap->timeout = pdata->timeout ? pdata->timeout : 20000; snprintf(adap->name, sizeof(adap->name), "Nomadik I2C%d at %lx", pdev->id, (unsigned long)res->start); -- cgit v1.2.3 From 99381bec0a569a69345148cb1ac74c2caa43a227 Mon Sep 17 00:00:00 2001 From: Virupax Sadashivpetimath Date: Fri, 13 May 2011 12:29:28 +0200 Subject: i2c-nomadik: corrrect returned error numbers The code was returning bad error numbers or just -1 in some cases. Signed-off-by: Virupax Sadashivpetimath Reviewed-by: Srinidhi Kasagar Signed-off-by: Linus Walleij Signed-off-by: Ben Dooks --- drivers/i2c/busses/i2c-nomadik.c | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) (limited to 'drivers/i2c') diff --git a/drivers/i2c/busses/i2c-nomadik.c b/drivers/i2c/busses/i2c-nomadik.c index 3bf95b90aba..a02141a9971 100644 --- a/drivers/i2c/busses/i2c-nomadik.c +++ b/drivers/i2c/busses/i2c-nomadik.c @@ -615,6 +615,8 @@ static int nmk_i2c_xfer(struct i2c_adapter *i2c_adap, cause >= ARRAY_SIZE(abort_causes) ? "unknown reason" : abort_causes[cause]); + status = status ? status : dev->result; + goto out; } udelay(I2C_DELAY); @@ -759,7 +761,7 @@ static irqreturn_t i2c_irq_handler(int irq, void *arg) | I2C_IT_RXFF | I2C_IT_RXFE)); if (dev->cli.count) { - dev->result = -1; + dev->result = -EIO; dev_err(&dev->pdev->dev, "%lu bytes still remain to be" "xfered\n", dev->cli.count); (void) init_hw(dev); @@ -770,7 +772,7 @@ static irqreturn_t i2c_irq_handler(int irq, void *arg) /* Master Arbitration lost interrupt */ case I2C_IT_MAL: - dev->result = -1; + dev->result = -EIO; (void) init_hw(dev); i2c_set_bit(dev->virtbase + I2C_ICR, I2C_IT_MAL); @@ -784,7 +786,7 @@ static irqreturn_t i2c_irq_handler(int irq, void *arg) * during the transaction. */ case I2C_IT_BERR: - dev->result = -1; + dev->result = -EIO; /* get the status */ if (((readl(dev->virtbase + I2C_SR) >> 2) & 0x3) == I2C_ABORT) (void) init_hw(dev); @@ -800,7 +802,7 @@ static irqreturn_t i2c_irq_handler(int irq, void *arg) * the Tx FIFO is full. */ case I2C_IT_TXFOVR: - dev->result = -1; + dev->result = -EIO; (void) init_hw(dev); dev_err(&dev->pdev->dev, "Tx Fifo Over run\n"); -- cgit v1.2.3 From c436f92a4646e4635554bda39407dfb907352321 Mon Sep 17 00:00:00 2001 From: srinidhi kasagar Date: Fri, 13 May 2011 12:29:38 +0200 Subject: i2c-nomadik: remove the redundant error message The abort cause string itself is an error, so remove the redundant explicit error message. Signed-off-by: Srinidhi Kasagar Reviewed-by: Jonas Aberg Signed-off-by: Linus Walleij Signed-off-by: Ben Dooks --- drivers/i2c/busses/i2c-nomadik.c | 2 -- 1 file changed, 2 deletions(-) (limited to 'drivers/i2c') diff --git a/drivers/i2c/busses/i2c-nomadik.c b/drivers/i2c/busses/i2c-nomadik.c index a02141a9971..dbd93b25d2c 100644 --- a/drivers/i2c/busses/i2c-nomadik.c +++ b/drivers/i2c/busses/i2c-nomadik.c @@ -609,8 +609,6 @@ static int nmk_i2c_xfer(struct i2c_adapter *i2c_adap, if (status || (dev->result)) { /* get the abort cause */ cause = (readl(dev->virtbase + I2C_SR) >> 4) & 0x7; - dev_err(&dev->pdev->dev, "error during I2C" - "message xfer: %d\n", cause); dev_err(&dev->pdev->dev, "%s\n", cause >= ARRAY_SIZE(abort_causes) ? "unknown reason" : abort_causes[cause]); -- cgit v1.2.3 From cd20e4fa910540c339b483d0b95ca237abf3354a Mon Sep 17 00:00:00 2001 From: Virupax Sadashivpetimath Date: Fri, 13 May 2011 12:29:46 +0200 Subject: i2c-nomadik: correct adapter timeout initialization Correct the incorrect initialization of adapter timeout not to be in milliseconds, as it needs to be done in jiffies. Signed-off-by: Virupax Sadashivpetimath Reviewed-by: Srinidhi Kasagar Signed-off-by: Linus Walleij Signed-off-by: Ben Dooks --- drivers/i2c/busses/i2c-nomadik.c | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) (limited to 'drivers/i2c') diff --git a/drivers/i2c/busses/i2c-nomadik.c b/drivers/i2c/busses/i2c-nomadik.c index dbd93b25d2c..28389c29af7 100644 --- a/drivers/i2c/busses/i2c-nomadik.c +++ b/drivers/i2c/busses/i2c-nomadik.c @@ -210,7 +210,7 @@ static int flush_i2c_fifo(struct nmk_i2c_dev *dev) writel((I2C_CR_FTX | I2C_CR_FRX), dev->virtbase + I2C_CR); for (i = 0; i < LOOP_ATTEMPTS; i++) { - timeout = jiffies + msecs_to_jiffies(dev->adap.timeout); + timeout = jiffies + dev->adap.timeout; while (!time_after(jiffies, timeout)) { if ((readl(dev->virtbase + I2C_CR) & @@ -431,7 +431,7 @@ static int read_i2c(struct nmk_i2c_dev *dev) dev->virtbase + I2C_IMSCR); timeout = wait_for_completion_interruptible_timeout( - &dev->xfer_complete, msecs_to_jiffies(dev->adap.timeout)); + &dev->xfer_complete, dev->adap.timeout); if (timeout < 0) { dev_err(&dev->pdev->dev, @@ -495,7 +495,7 @@ static int write_i2c(struct nmk_i2c_dev *dev) dev->virtbase + I2C_IMSCR); timeout = wait_for_completion_interruptible_timeout( - &dev->xfer_complete, msecs_to_jiffies(dev->adap.timeout)); + &dev->xfer_complete, dev->adap.timeout); if (timeout < 0) { dev_err(&dev->pdev->dev, @@ -914,7 +914,8 @@ static int __devinit nmk_i2c_probe(struct platform_device *pdev) adap->owner = THIS_MODULE; adap->class = I2C_CLASS_HWMON | I2C_CLASS_SPD; adap->algo = &nmk_i2c_algo; - adap->timeout = pdata->timeout ? pdata->timeout : 20000; + adap->timeout = pdata->timeout ? msecs_to_jiffies(pdata->timeout) : + msecs_to_jiffies(20000); snprintf(adap->name, sizeof(adap->name), "Nomadik I2C%d at %lx", pdev->id, (unsigned long)res->start); -- cgit v1.2.3 From 4cb3f538cd88fddaa659a924e7abdb685cd5e784 Mon Sep 17 00:00:00 2001 From: Virupax Sadashivpetimath Date: Fri, 13 May 2011 12:29:55 +0200 Subject: i2c-nomadik: print abort cause only on abort tag Modify the code to: 1)Print the cause of i2c failure only if the status is set to ABORT. 2)Print slave address on send/receive fail, will help in which slave failed. Signed-off-by: Virupax Sadashivpetimath Reviewed-by: Jonas Aberg Signed-off-by: Linus Walleij Signed-off-by: Ben Dooks --- drivers/i2c/busses/i2c-nomadik.c | 27 +++++++++++++++++++-------- 1 file changed, 19 insertions(+), 8 deletions(-) (limited to 'drivers/i2c') diff --git a/drivers/i2c/busses/i2c-nomadik.c b/drivers/i2c/busses/i2c-nomadik.c index 28389c29af7..c8bf81abcd3 100644 --- a/drivers/i2c/busses/i2c-nomadik.c +++ b/drivers/i2c/busses/i2c-nomadik.c @@ -442,7 +442,8 @@ static int read_i2c(struct nmk_i2c_dev *dev) if (timeout == 0) { /* controller has timedout, re-init the h/w */ - dev_err(&dev->pdev->dev, "controller timed out, re-init h/w\n"); + dev_err(&dev->pdev->dev, "read from slave 0x%x timed out\n", + dev->cli.slave_adr); (void) init_hw(dev); status = -ETIMEDOUT; } @@ -506,7 +507,8 @@ static int write_i2c(struct nmk_i2c_dev *dev) if (timeout == 0) { /* controller has timedout, re-init the h/w */ - dev_err(&dev->pdev->dev, "controller timed out, re-init h/w\n"); + dev_err(&dev->pdev->dev, "write to slave 0x%x timed out\n", + dev->cli.slave_adr); (void) init_hw(dev); status = -ETIMEDOUT; } @@ -568,6 +570,7 @@ static int nmk_i2c_xfer(struct i2c_adapter *i2c_adap, int i; u32 cause; struct nmk_i2c_dev *dev = i2c_get_adapdata(i2c_adap); + u32 i2c_sr; dev->busy = true; @@ -607,14 +610,22 @@ static int nmk_i2c_xfer(struct i2c_adapter *i2c_adap, status = write_i2c(dev); } if (status || (dev->result)) { - /* get the abort cause */ - cause = (readl(dev->virtbase + I2C_SR) >> 4) & 0x7; - dev_err(&dev->pdev->dev, "%s\n", - cause >= ARRAY_SIZE(abort_causes) - ? "unknown reason" : abort_causes[cause]); + i2c_sr = readl(dev->virtbase + I2C_SR); + /* + * Check if the controller I2C operation status is set + * to ABORT(11b). + */ + if (((i2c_sr >> 2) & 0x3) == 0x3) { + /* get the abort cause */ + cause = (i2c_sr >> 4) + & 0x7; + dev_err(&dev->pdev->dev, "%s\n", cause >= + ARRAY_SIZE(abort_causes) ? + "unknown reason" : + abort_causes[cause]); + } status = status ? status : dev->result; - goto out; } udelay(I2C_DELAY); -- cgit v1.2.3 From b0e751a925260e5998a76dad41d4565ef26870db Mon Sep 17 00:00:00 2001 From: Rabin Vincent Date: Fri, 13 May 2011 12:30:07 +0200 Subject: i2c-nomadik: use pm_runtime API Use the pm_runtime API for pins control. Signed-off-by: Rabin Vincent Reviewed-by: Srinidhi Kasagar Reviewed-by: Jonas Aberg [deleted some surplus runtime PM code] Signed-off-by: Linus Walleij Signed-off-by: Ben Dooks --- drivers/i2c/busses/i2c-nomadik.c | 37 +++++++++++++++++++++++++++++++------ 1 file changed, 31 insertions(+), 6 deletions(-) (limited to 'drivers/i2c') diff --git a/drivers/i2c/busses/i2c-nomadik.c b/drivers/i2c/busses/i2c-nomadik.c index c8bf81abcd3..234e4a9070b 100644 --- a/drivers/i2c/busses/i2c-nomadik.c +++ b/drivers/i2c/busses/i2c-nomadik.c @@ -23,6 +23,7 @@ #include #include #include +#include #include @@ -576,6 +577,7 @@ static int nmk_i2c_xfer(struct i2c_adapter *i2c_adap, if (dev->regulator) regulator_enable(dev->regulator); + pm_runtime_get_sync(&dev->pdev->dev); status = init_hw(dev); if (status) @@ -634,6 +636,7 @@ static int nmk_i2c_xfer(struct i2c_adapter *i2c_adap, out: clk_disable(dev->clk); out2: + pm_runtime_put_sync(&dev->pdev->dev); if (dev->regulator) regulator_disable(dev->regulator); @@ -839,19 +842,36 @@ static irqreturn_t i2c_irq_handler(int irq, void *arg) #ifdef CONFIG_PM -static int nmk_i2c_suspend(struct platform_device *pdev, pm_message_t mesg) +static int nmk_i2c_suspend(struct device *dev) { - struct nmk_i2c_dev *dev = platform_get_drvdata(pdev); + struct platform_device *pdev = to_platform_device(dev); + struct nmk_i2c_dev *nmk_i2c = platform_get_drvdata(pdev); - if (dev->busy) + if (nmk_i2c->busy) return -EBUSY; - else - return 0; + + return 0; +} + +static int nmk_i2c_resume(struct device *dev) +{ + return 0; } #else #define nmk_i2c_suspend NULL +#define nmk_i2c_resume NULL #endif +/* + * We use noirq so that we suspend late and resume before the wakeup interrupt + * to ensure that we do the !pm_runtime_suspended() check in resume before + * there has been a regular pm runtime resume (via pm_runtime_get_sync()). + */ +static const struct dev_pm_ops nmk_i2c_pm = { + .suspend_noirq = nmk_i2c_suspend, + .resume_noirq = nmk_i2c_resume, +}; + static unsigned int nmk_i2c_functionality(struct i2c_adapter *adap) { return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL; @@ -913,6 +933,9 @@ static int __devinit nmk_i2c_probe(struct platform_device *pdev) dev->regulator = NULL; } + pm_suspend_ignore_children(&pdev->dev, true); + pm_runtime_enable(&pdev->dev); + dev->clk = clk_get(&pdev->dev, NULL); if (IS_ERR(dev->clk)) { dev_err(&pdev->dev, "could not get i2c clock\n"); @@ -958,6 +981,7 @@ static int __devinit nmk_i2c_probe(struct platform_device *pdev) err_no_clk: if (dev->regulator) regulator_put(dev->regulator); + pm_runtime_disable(&pdev->dev); free_irq(dev->irq, dev); err_irq: iounmap(dev->virtbase); @@ -990,6 +1014,7 @@ static int __devexit nmk_i2c_remove(struct platform_device *pdev) clk_put(dev->clk); if (dev->regulator) regulator_put(dev->regulator); + pm_runtime_disable(&pdev->dev); platform_set_drvdata(pdev, NULL); kfree(dev); @@ -1000,10 +1025,10 @@ static struct platform_driver nmk_i2c_driver = { .driver = { .owner = THIS_MODULE, .name = DRIVER_NAME, + .pm = &nmk_i2c_pm, }, .probe = nmk_i2c_probe, .remove = __devexit_p(nmk_i2c_remove), - .suspend = nmk_i2c_suspend, }; static int __init nmk_i2c_init(void) -- cgit v1.2.3 From ebd10e0783d9fb92a147e60902e22c2d3f3ad69d Mon Sep 17 00:00:00 2001 From: Virupax Sadashivpetimath Date: Fri, 13 May 2011 12:30:23 +0200 Subject: i2c-nomadik: add code to retry on timeout failure It is seen that i2c-nomadik controller randomly stops generating the interrupts leading to a i2c timeout. As a workaround to this problem, add retries to the on going transfer on failure. Signed-off-by: Virupax Sadashivpetimath Reviewed-by: Jonas ABERG Signed-off-by: Linus Walleij Signed-off-by: Ben Dooks --- drivers/i2c/busses/i2c-nomadik.c | 97 ++++++++++++++++++++-------------------- 1 file changed, 49 insertions(+), 48 deletions(-) (limited to 'drivers/i2c') diff --git a/drivers/i2c/busses/i2c-nomadik.c b/drivers/i2c/busses/i2c-nomadik.c index 234e4a9070b..b49ff25a268 100644 --- a/drivers/i2c/busses/i2c-nomadik.c +++ b/drivers/i2c/busses/i2c-nomadik.c @@ -255,8 +255,6 @@ static int init_hw(struct nmk_i2c_dev *dev) { int stat; - clk_enable(dev->clk); - stat = flush_i2c_fifo(dev); if (stat) goto exit; @@ -271,8 +269,6 @@ static int init_hw(struct nmk_i2c_dev *dev) dev->cli.operation = I2C_NO_OPERATION; exit: - /* TODO: Why disable clocks after init hw? */ - clk_disable(dev->clk); /* * TODO: What is this delay for? * Must be pretty pointless since the hw block @@ -572,6 +568,7 @@ static int nmk_i2c_xfer(struct i2c_adapter *i2c_adap, u32 cause; struct nmk_i2c_dev *dev = i2c_get_adapdata(i2c_adap); u32 i2c_sr; + int j; dev->busy = true; @@ -579,63 +576,67 @@ static int nmk_i2c_xfer(struct i2c_adapter *i2c_adap, regulator_enable(dev->regulator); pm_runtime_get_sync(&dev->pdev->dev); + clk_enable(dev->clk); + status = init_hw(dev); if (status) - goto out2; + goto out; - clk_enable(dev->clk); - - /* setup the i2c controller */ - setup_i2c_controller(dev); + for (j = 0; j < 3; j++) { + /* setup the i2c controller */ + setup_i2c_controller(dev); - for (i = 0; i < num_msgs; i++) { - if (unlikely(msgs[i].flags & I2C_M_TEN)) { - dev_err(&dev->pdev->dev, "10 bit addressing" - "not supported\n"); + for (i = 0; i < num_msgs; i++) { + if (unlikely(msgs[i].flags & I2C_M_TEN)) { + dev_err(&dev->pdev->dev, "10 bit addressing" + "not supported\n"); - status = -EINVAL; - goto out; - } - dev->cli.slave_adr = msgs[i].addr; - dev->cli.buffer = msgs[i].buf; - dev->cli.count = msgs[i].len; - dev->stop = (i < (num_msgs - 1)) ? 0 : 1; - dev->result = 0; - - if (msgs[i].flags & I2C_M_RD) { - /* it is a read operation */ - dev->cli.operation = I2C_READ; - status = read_i2c(dev); - } else { - /* write operation */ - dev->cli.operation = I2C_WRITE; - status = write_i2c(dev); - } - if (status || (dev->result)) { - i2c_sr = readl(dev->virtbase + I2C_SR); - /* - * Check if the controller I2C operation status is set - * to ABORT(11b). - */ - if (((i2c_sr >> 2) & 0x3) == 0x3) { - /* get the abort cause */ - cause = (i2c_sr >> 4) - & 0x7; - dev_err(&dev->pdev->dev, "%s\n", cause >= - ARRAY_SIZE(abort_causes) ? + status = -EINVAL; + goto out; + } + dev->cli.slave_adr = msgs[i].addr; + dev->cli.buffer = msgs[i].buf; + dev->cli.count = msgs[i].len; + dev->stop = (i < (num_msgs - 1)) ? 0 : 1; + dev->result = 0; + + if (msgs[i].flags & I2C_M_RD) { + /* it is a read operation */ + dev->cli.operation = I2C_READ; + status = read_i2c(dev); + } else { + /* write operation */ + dev->cli.operation = I2C_WRITE; + status = write_i2c(dev); + } + if (status || (dev->result)) { + i2c_sr = readl(dev->virtbase + I2C_SR); + /* + * Check if the controller I2C operation status + * is set to ABORT(11b). + */ + if (((i2c_sr >> 2) & 0x3) == 0x3) { + /* get the abort cause */ + cause = (i2c_sr >> 4) + & 0x7; + dev_err(&dev->pdev->dev, "%s\n", cause + >= ARRAY_SIZE(abort_causes) ? "unknown reason" : abort_causes[cause]); - } + } - status = status ? status : dev->result; - goto out; + status = status ? status : dev->result; + + break; + } + udelay(I2C_DELAY); } - udelay(I2C_DELAY); + if (status == 0) + break; } out: clk_disable(dev->clk); -out2: pm_runtime_put_sync(&dev->pdev->dev); if (dev->regulator) regulator_disable(dev->regulator); -- cgit v1.2.3 From 553553413a6abdda220a697ef439ba2f4b1d4a7c Mon Sep 17 00:00:00 2001 From: Virupax Sadashivpetimath Date: Fri, 13 May 2011 12:30:34 +0200 Subject: i2c-nomadik: change the TX and RX threshold 1) Increase RX FIFO threshold so that there is a reduction in the number of interrupts handled to complete a transaction. 2) Fill TX FIFO in the write function. Signed-off-by: Virupax Sadashivpetimath Reviewed-by: Jonas Aberg Signed-off-by: Linus Walleij Signed-off-by: Ben Dooks --- drivers/i2c/busses/i2c-nomadik.c | 39 ++++++++++++++++++++++++++------------- 1 file changed, 26 insertions(+), 13 deletions(-) (limited to 'drivers/i2c') diff --git a/drivers/i2c/busses/i2c-nomadik.c b/drivers/i2c/busses/i2c-nomadik.c index b49ff25a268..e3cd62e40df 100644 --- a/drivers/i2c/busses/i2c-nomadik.c +++ b/drivers/i2c/busses/i2c-nomadik.c @@ -447,6 +447,24 @@ static int read_i2c(struct nmk_i2c_dev *dev) return status; } +static void fill_tx_fifo(struct nmk_i2c_dev *dev, int no_bytes) +{ + int count; + + for (count = (no_bytes - 2); + (count > 0) && + (dev->cli.count != 0); + count--) { + /* write to the Tx FIFO */ + writeb(*dev->cli.buffer, + dev->virtbase + I2C_TFR); + dev->cli.buffer++; + dev->cli.count--; + dev->cli.xfer_bytes++; + } + +} + /** * write_i2c() - Write data to I2C client. * @dev: private data of I2C Driver @@ -474,8 +492,13 @@ static int write_i2c(struct nmk_i2c_dev *dev) init_completion(&dev->xfer_complete); /* enable interrupts by settings the masks */ - irq_mask = (I2C_IT_TXFNE | I2C_IT_TXFOVR | - I2C_IT_MAL | I2C_IT_BERR); + irq_mask = (I2C_IT_TXFOVR | I2C_IT_MAL | I2C_IT_BERR); + + /* Fill the TX FIFO with transmit data */ + fill_tx_fifo(dev, MAX_I2C_FIFO_THRESHOLD); + + if (dev->cli.count != 0) + irq_mask |= I2C_IT_TXFNE; /* * check if we want to transfer a single or multiple bytes, if so @@ -702,17 +725,7 @@ static irqreturn_t i2c_irq_handler(int irq, void *arg) */ disable_interrupts(dev, I2C_IT_TXFNE); } else { - for (count = (MAX_I2C_FIFO_THRESHOLD - tft - 2); - (count > 0) && - (dev->cli.count != 0); - count--) { - /* write to the Tx FIFO */ - writeb(*dev->cli.buffer, - dev->virtbase + I2C_TFR); - dev->cli.buffer++; - dev->cli.count--; - dev->cli.xfer_bytes++; - } + fill_tx_fifo(dev, (MAX_I2C_FIFO_THRESHOLD - tft)); /* * if done, close the transfer by disabling the * corresponding TXFNE interrupt -- cgit v1.2.3 From b5e890f7e70707d1e10e8d4844806d2223e8b36d Mon Sep 17 00:00:00 2001 From: Virupax Sadashivpetimath Date: Fri, 13 May 2011 12:30:42 +0200 Subject: i2c-nomadik: remove the unnecessary delay The delay in the driver seems to be not needed, so remove it. Signed-off-by: Virupax Sadashivpetimath Reviewed-by: Markus Grape Tested-by: Per Persson Tested-by: Chethan Krishna N Reviewed-by: Srinidhi Kasagar Signed-off-by: Linus Walleij Signed-off-by: Ben Dooks --- drivers/i2c/busses/i2c-nomadik.c | 20 ++------------------ 1 file changed, 2 insertions(+), 18 deletions(-) (limited to 'drivers/i2c') diff --git a/drivers/i2c/busses/i2c-nomadik.c b/drivers/i2c/busses/i2c-nomadik.c index e3cd62e40df..b2de1a56dc8 100644 --- a/drivers/i2c/busses/i2c-nomadik.c +++ b/drivers/i2c/busses/i2c-nomadik.c @@ -15,7 +15,6 @@ #include #include #include -#include #include #include #include @@ -105,9 +104,6 @@ /* maximum threshold value */ #define MAX_I2C_FIFO_THRESHOLD 15 -/* per-transfer delay, required for the hardware to stabilize */ -#define I2C_DELAY 150 - enum i2c_status { I2C_NOP, I2C_ON_GOING, @@ -269,12 +265,6 @@ static int init_hw(struct nmk_i2c_dev *dev) dev->cli.operation = I2C_NO_OPERATION; exit: - /* - * TODO: What is this delay for? - * Must be pretty pointless since the hw block - * is frozen. Or? - */ - udelay(I2C_DELAY); return stat; } @@ -652,7 +642,6 @@ static int nmk_i2c_xfer(struct i2c_adapter *i2c_adap, break; } - udelay(I2C_DELAY); } if (status == 0) break; @@ -778,13 +767,8 @@ static irqreturn_t i2c_irq_handler(int irq, void *arg) } } - i2c_set_bit(dev->virtbase + I2C_ICR, I2C_IT_MTD); - i2c_set_bit(dev->virtbase + I2C_ICR, I2C_IT_MTDWS); - - disable_interrupts(dev, - (I2C_IT_TXFNE | I2C_IT_TXFE | I2C_IT_TXFF - | I2C_IT_TXFOVR | I2C_IT_RXFNF - | I2C_IT_RXFF | I2C_IT_RXFE)); + disable_all_interrupts(dev); + clear_all_interrupts(dev); if (dev->cli.count) { dev->result = -EIO; -- cgit v1.2.3 From 0511f643cbe6990daf4b53b1268b5c2ea28d1733 Mon Sep 17 00:00:00 2001 From: Virupax Sadashivpetimath Date: Fri, 13 May 2011 12:30:53 +0200 Subject: i2c-nomadik: reset the hw after status check In case of I2C timeout, reset the HW only after the HW status is read, otherwise the staus will be lost. Signed-off-by: Virupax Sadashivpetimath Reviewed-by: Jonas Aberg Reviewed-by: Srinidhi Kasagar Signed-off-by: Linus Walleij Signed-off-by: Ben Dooks --- drivers/i2c/busses/i2c-nomadik.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'drivers/i2c') diff --git a/drivers/i2c/busses/i2c-nomadik.c b/drivers/i2c/busses/i2c-nomadik.c index b2de1a56dc8..fa7b10639ce 100644 --- a/drivers/i2c/busses/i2c-nomadik.c +++ b/drivers/i2c/busses/i2c-nomadik.c @@ -428,10 +428,9 @@ static int read_i2c(struct nmk_i2c_dev *dev) } if (timeout == 0) { - /* controller has timedout, re-init the h/w */ + /* Controller timed out */ dev_err(&dev->pdev->dev, "read from slave 0x%x timed out\n", dev->cli.slave_adr); - (void) init_hw(dev); status = -ETIMEDOUT; } return status; @@ -516,10 +515,9 @@ static int write_i2c(struct nmk_i2c_dev *dev) } if (timeout == 0) { - /* controller has timedout, re-init the h/w */ + /* Controller timed out */ dev_err(&dev->pdev->dev, "write to slave 0x%x timed out\n", dev->cli.slave_adr); - (void) init_hw(dev); status = -ETIMEDOUT; } @@ -638,6 +636,8 @@ static int nmk_i2c_xfer(struct i2c_adapter *i2c_adap, abort_causes[cause]); } + (void) init_hw(dev); + status = status ? status : dev->result; break; -- cgit v1.2.3 From 82a4413450376cbce0bb2b794fb880dbfda89299 Mon Sep 17 00:00:00 2001 From: Linus Walleij Date: Fri, 13 May 2011 12:31:01 +0200 Subject: i2c-nomadik: break out single messsage transmission Reduce code size in the message transfer function by factoring out a single-message transfer function. Signed-off-by: Linus Walleij Signed-off-by: Ben Dooks --- drivers/i2c/busses/i2c-nomadik.c | 80 ++++++++++++++++++++++++---------------- 1 file changed, 48 insertions(+), 32 deletions(-) (limited to 'drivers/i2c') diff --git a/drivers/i2c/busses/i2c-nomadik.c b/drivers/i2c/busses/i2c-nomadik.c index fa7b10639ce..0c731ca69f1 100644 --- a/drivers/i2c/busses/i2c-nomadik.c +++ b/drivers/i2c/busses/i2c-nomadik.c @@ -524,6 +524,51 @@ static int write_i2c(struct nmk_i2c_dev *dev) return status; } +/** + * nmk_i2c_xfer_one() - transmit a single I2C message + * @dev: device with a message encoded into it + * @flags: message flags + */ +static int nmk_i2c_xfer_one(struct nmk_i2c_dev *dev, u16 flags) +{ + int status; + + if (flags & I2C_M_RD) { + /* read operation */ + dev->cli.operation = I2C_READ; + status = read_i2c(dev); + } else { + /* write operation */ + dev->cli.operation = I2C_WRITE; + status = write_i2c(dev); + } + + if (status || (dev->result)) { + u32 i2c_sr; + u32 cause; + + i2c_sr = readl(dev->virtbase + I2C_SR); + /* + * Check if the controller I2C operation status + * is set to ABORT(11b). + */ + if (((i2c_sr >> 2) & 0x3) == 0x3) { + /* get the abort cause */ + cause = (i2c_sr >> 4) & 0x7; + dev_err(&dev->pdev->dev, "%s\n", cause + >= ARRAY_SIZE(abort_causes) ? + "unknown reason" : + abort_causes[cause]); + } + + (void) init_hw(dev); + + status = status ? status : dev->result; + } + + return status; +} + /** * nmk_i2c_xfer() - I2C transfer function used by kernel framework * @i2c_adap: Adapter pointer to the controller @@ -576,9 +621,7 @@ static int nmk_i2c_xfer(struct i2c_adapter *i2c_adap, { int status; int i; - u32 cause; struct nmk_i2c_dev *dev = i2c_get_adapdata(i2c_adap); - u32 i2c_sr; int j; dev->busy = true; @@ -593,6 +636,7 @@ static int nmk_i2c_xfer(struct i2c_adapter *i2c_adap, if (status) goto out; + /* Attempt three times to send the message queue */ for (j = 0; j < 3; j++) { /* setup the i2c controller */ setup_i2c_controller(dev); @@ -611,37 +655,9 @@ static int nmk_i2c_xfer(struct i2c_adapter *i2c_adap, dev->stop = (i < (num_msgs - 1)) ? 0 : 1; dev->result = 0; - if (msgs[i].flags & I2C_M_RD) { - /* it is a read operation */ - dev->cli.operation = I2C_READ; - status = read_i2c(dev); - } else { - /* write operation */ - dev->cli.operation = I2C_WRITE; - status = write_i2c(dev); - } - if (status || (dev->result)) { - i2c_sr = readl(dev->virtbase + I2C_SR); - /* - * Check if the controller I2C operation status - * is set to ABORT(11b). - */ - if (((i2c_sr >> 2) & 0x3) == 0x3) { - /* get the abort cause */ - cause = (i2c_sr >> 4) - & 0x7; - dev_err(&dev->pdev->dev, "%s\n", cause - >= ARRAY_SIZE(abort_causes) ? - "unknown reason" : - abort_causes[cause]); - } - - (void) init_hw(dev); - - status = status ? status : dev->result; - + status = nmk_i2c_xfer_one(dev, msgs[i].flags); + if (status != 0) break; - } } if (status == 0) break; -- cgit v1.2.3