diff options
42 files changed, 960 insertions, 497 deletions
diff --git a/Documentation/devicetree/bindings/i2c/i2c-arb-gpio-challenge.txt b/Documentation/devicetree/bindings/i2c/i2c-arb-gpio-challenge.txt new file mode 100644 index 00000000000..1ac8ea8ade1 --- /dev/null +++ b/Documentation/devicetree/bindings/i2c/i2c-arb-gpio-challenge.txt @@ -0,0 +1,80 @@ +GPIO-based I2C Arbitration Using a Challenge & Response Mechanism +================================================================= +This uses GPIO lines and a challenge & response mechanism to arbitrate who is +the master of an I2C bus in a multimaster situation. + +In many cases using GPIOs to arbitrate is not needed and a design can use +the standard I2C multi-master rules. Using GPIOs is generally useful in +the case where there is a device on the bus that has errata and/or bugs +that makes standard multimaster mode not feasible. + + +Algorithm: + +All masters on the bus have a 'bus claim' line which is an output that the +others can see. These are all active low with pull-ups enabled. We'll +describe these lines as: + +- OUR_CLAIM: output from us signaling to other hosts that we want the bus +- THEIR_CLAIMS: output from others signaling that they want the bus + +The basic algorithm is to assert your line when you want the bus, then make +sure that the other side doesn't want it also. A detailed explanation is best +done with an example. + +Let's say we want to claim the bus. We: +1. Assert OUR_CLAIM. +2. Waits a little bit for the other sides to notice (slew time, say 10 + microseconds). +3. Check THEIR_CLAIMS. If none are asserted then the we have the bus and we are + done. +4. Otherwise, wait for a few milliseconds and see if THEIR_CLAIMS are released. +5. If not, back off, release the claim and wait for a few more milliseconds. +6. Go back to 1 (until retry time has expired). + + +Required properties: +- compatible: i2c-arb-gpio-challenge +- our-claim-gpio: The GPIO that we use to claim the bus. +- their-claim-gpios: The GPIOs that the other sides use to claim the bus. + Note that some implementations may only support a single other master. +- Standard I2C mux properties. See mux.txt in this directory. +- Single I2C child bus node at reg 0. See mux.txt in this directory. + +Optional properties: +- slew-delay-us: microseconds to wait for a GPIO to go high. Default is 10 us. +- wait-retry-us: we'll attempt another claim after this many microseconds. + Default is 3000 us. +- wait-free-us: we'll give up after this many microseconds. Default is 50000 us. + + +Example: + i2c@12CA0000 { + compatible = "acme,some-i2c-device"; + #address-cells = <1>; + #size-cells = <0>; + }; + + i2c-arbitrator { + compatible = "i2c-arb-gpio-challenge"; + #address-cells = <1>; + #size-cells = <0>; + + i2c-parent = <&{/i2c@12CA0000}>; + + our-claim-gpio = <&gpf0 3 1>; + their-claim-gpios = <&gpe0 4 1>; + slew-delay-us = <10>; + wait-retry-us = <3000>; + wait-free-us = <50000>; + + i2c@0 { + reg = <0>; + #address-cells = <1>; + #size-cells = <0>; + + i2c@52 { + // Normal I2C device + }; + }; + }; diff --git a/MAINTAINERS b/MAINTAINERS index b57e2765a34..59d708f2924 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -3919,7 +3919,6 @@ F: drivers/i2c/i2c-stub.c I2C SUBSYSTEM M: Wolfram Sang <wsa@the-dreams.de> -M: "Ben Dooks (embedded platforms)" <ben-linux@fluff.org> L: linux-i2c@vger.kernel.org W: http://i2c.wiki.kernel.org/ T: git git://git.kernel.org/pub/scm/linux/kernel/git/wsa/linux.git diff --git a/arch/arm/mach-s3c24xx/mach-rx1950.c b/arch/arm/mach-s3c24xx/mach-rx1950.c index 1f9ba2ae528..43f3ac5a1c7 100644 --- a/arch/arm/mach-s3c24xx/mach-rx1950.c +++ b/arch/arm/mach-s3c24xx/mach-rx1950.c @@ -56,7 +56,6 @@ #include <plat/cpu.h> #include <plat/devs.h> #include <plat/pm.h> -#include <plat/regs-iic.h> #include <plat/regs-serial.h> #include "common.h" diff --git a/arch/arm/mach-tegra/tegra.c b/arch/arm/mach-tegra/tegra.c index 84deeab23ee..9cf1ab17afe 100644 --- a/arch/arm/mach-tegra/tegra.c +++ b/arch/arm/mach-tegra/tegra.c @@ -31,8 +31,6 @@ #include <linux/pda_power.h> #include <linux/platform_data/tegra_usb.h> #include <linux/io.h> -#include <linux/i2c.h> -#include <linux/i2c-tegra.h> #include <linux/slab.h> #include <linux/sys_soc.h> #include <linux/usb/tegra_usb_phy.h> diff --git a/arch/arm/plat-samsung/devs.c b/arch/arm/plat-samsung/devs.c index f55d3f9b508..8f456bed4fa 100644 --- a/arch/arm/plat-samsung/devs.c +++ b/arch/arm/plat-samsung/devs.c @@ -63,7 +63,6 @@ #include <linux/platform_data/usb-s3c2410_udc.h> #include <linux/platform_data/usb-ohci-s3c2410.h> #include <plat/usb-phy.h> -#include <plat/regs-iic.h> #include <plat/regs-serial.h> #include <plat/regs-spi.h> #include <linux/platform_data/spi-s3c64xx.h> diff --git a/arch/arm/plat-samsung/include/plat/regs-iic.h b/arch/arm/plat-samsung/include/plat/regs-iic.h deleted file mode 100644 index 2f7c17de8ac..00000000000 --- a/arch/arm/plat-samsung/include/plat/regs-iic.h +++ /dev/null @@ -1,56 +0,0 @@ -/* arch/arm/mach-s3c2410/include/mach/regs-iic.h - * - * Copyright (c) 2004 Simtec Electronics <linux@simtec.co.uk> - * http://www.simtec.co.uk/products/SWLINUX/ - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * - * S3C2410 I2C Controller -*/ - -#ifndef __ASM_ARCH_REGS_IIC_H -#define __ASM_ARCH_REGS_IIC_H __FILE__ - -/* see s3c2410x user guide, v1.1, section 9 (p447) for more info */ - -#define S3C2410_IICREG(x) (x) - -#define S3C2410_IICCON S3C2410_IICREG(0x00) -#define S3C2410_IICSTAT S3C2410_IICREG(0x04) -#define S3C2410_IICADD S3C2410_IICREG(0x08) -#define S3C2410_IICDS S3C2410_IICREG(0x0C) -#define S3C2440_IICLC S3C2410_IICREG(0x10) - -#define S3C2410_IICCON_ACKEN (1<<7) -#define S3C2410_IICCON_TXDIV_16 (0<<6) -#define S3C2410_IICCON_TXDIV_512 (1<<6) -#define S3C2410_IICCON_IRQEN (1<<5) -#define S3C2410_IICCON_IRQPEND (1<<4) -#define S3C2410_IICCON_SCALE(x) ((x)&15) -#define S3C2410_IICCON_SCALEMASK (0xf) - -#define S3C2410_IICSTAT_MASTER_RX (2<<6) -#define S3C2410_IICSTAT_MASTER_TX (3<<6) -#define S3C2410_IICSTAT_SLAVE_RX (0<<6) -#define S3C2410_IICSTAT_SLAVE_TX (1<<6) -#define S3C2410_IICSTAT_MODEMASK (3<<6) - -#define S3C2410_IICSTAT_START (1<<5) -#define S3C2410_IICSTAT_BUSBUSY (1<<5) -#define S3C2410_IICSTAT_TXRXEN (1<<4) -#define S3C2410_IICSTAT_ARBITR (1<<3) -#define S3C2410_IICSTAT_ASSLAVE (1<<2) -#define S3C2410_IICSTAT_ADDR0 (1<<1) -#define S3C2410_IICSTAT_LASTBIT (1<<0) - -#define S3C2410_IICLC_SDA_DELAY0 (0 << 0) -#define S3C2410_IICLC_SDA_DELAY5 (1 << 0) -#define S3C2410_IICLC_SDA_DELAY10 (2 << 0) -#define S3C2410_IICLC_SDA_DELAY15 (3 << 0) -#define S3C2410_IICLC_SDA_DELAY_MASK (3 << 0) - -#define S3C2410_IICLC_FILTER_ON (1<<2) - -#endif /* __ASM_ARCH_REGS_IIC_H */ diff --git a/drivers/gpu/drm/gma500/oaktrail_hdmi_i2c.c b/drivers/gpu/drm/gma500/oaktrail_hdmi_i2c.c index 88627e3ba1e..1eb86c79523 100644 --- a/drivers/gpu/drm/gma500/oaktrail_hdmi_i2c.c +++ b/drivers/gpu/drm/gma500/oaktrail_hdmi_i2c.c @@ -319,8 +319,7 @@ void oaktrail_hdmi_i2c_exit(struct pci_dev *dev) struct hdmi_i2c_dev *i2c_dev; hdmi_dev = pci_get_drvdata(dev); - if (i2c_del_adapter(&oaktrail_hdmi_i2c_adapter)) - DRM_DEBUG_DRIVER("Failed to delete hdmi-i2c adapter\n"); + i2c_del_adapter(&oaktrail_hdmi_i2c_adapter); i2c_dev = hdmi_dev->i2c_dev; kfree(i2c_dev); diff --git a/drivers/i2c/busses/i2c-amd756-s4882.c b/drivers/i2c/busses/i2c-amd756-s4882.c index 378fcb5d578..07f01ac853f 100644 --- a/drivers/i2c/busses/i2c-amd756-s4882.c +++ b/drivers/i2c/busses/i2c-amd756-s4882.c @@ -169,11 +169,7 @@ static int __init amd756_s4882_init(void) } /* Unregister physical bus */ - error = i2c_del_adapter(&amd756_smbus); - if (error) { - dev_err(&amd756_smbus.dev, "Physical bus removal failed\n"); - goto ERROR0; - } + i2c_del_adapter(&amd756_smbus); printk(KERN_INFO "Enabling SMBus multiplexing for Tyan S4882\n"); /* Define the 5 virtual adapters and algorithms structures */ diff --git a/drivers/i2c/busses/i2c-at91.c b/drivers/i2c/busses/i2c-at91.c index 75195e3f5dd..6bb839b688b 100644 --- a/drivers/i2c/busses/i2c-at91.c +++ b/drivers/i2c/busses/i2c-at91.c @@ -603,15 +603,18 @@ static const struct of_device_id atmel_twi_dt_ids[] = { } }; MODULE_DEVICE_TABLE(of, atmel_twi_dt_ids); -#else -#define atmel_twi_dt_ids NULL #endif -static bool filter(struct dma_chan *chan, void *slave) +static bool filter(struct dma_chan *chan, void *pdata) { - struct at_dma_slave *sl = slave; + struct at91_twi_pdata *sl_pdata = pdata; + struct at_dma_slave *sl; + + if (!sl_pdata) + return false; - if (sl->dma_dev == chan->device->dev) { + sl = &sl_pdata->dma_slave; + if (sl && (sl->dma_dev == chan->device->dev)) { chan->private = sl; return true; } else { @@ -622,11 +625,10 @@ static bool filter(struct dma_chan *chan, void *slave) static int at91_twi_configure_dma(struct at91_twi_dev *dev, u32 phy_addr) { int ret = 0; - struct at_dma_slave *sdata; + struct at91_twi_pdata *pdata = dev->pdata; struct dma_slave_config slave_config; struct at91_twi_dma *dma = &dev->dma; - - sdata = &dev->pdata->dma_slave; + dma_cap_mask_t mask; memset(&slave_config, 0, sizeof(slave_config)); slave_config.src_addr = (dma_addr_t)phy_addr + AT91_TWI_RHR; @@ -637,25 +639,22 @@ static int at91_twi_configure_dma(struct at91_twi_dev *dev, u32 phy_addr) slave_config.dst_maxburst = 1; slave_config.device_fc = false; - if (sdata && sdata->dma_dev) { - dma_cap_mask_t mask; + dma_cap_zero(mask); + dma_cap_set(DMA_SLAVE, mask); - dma_cap_zero(mask); - dma_cap_set(DMA_SLAVE, mask); - dma->chan_tx = dma_request_channel(mask, filter, sdata); - if (!dma->chan_tx) { - dev_err(dev->dev, "no DMA channel available for tx\n"); - ret = -EBUSY; - goto error; - } - dma->chan_rx = dma_request_channel(mask, filter, sdata); - if (!dma->chan_rx) { - dev_err(dev->dev, "no DMA channel available for rx\n"); - ret = -EBUSY; - goto error; - } - } else { - ret = -EINVAL; + dma->chan_tx = dma_request_slave_channel_compat(mask, filter, pdata, + dev->dev, "tx"); + if (!dma->chan_tx) { + dev_err(dev->dev, "can't get a DMA channel for tx\n"); + ret = -EBUSY; + goto error; + } + + dma->chan_rx = dma_request_slave_channel_compat(mask, filter, pdata, + dev->dev, "rx"); + if (!dma->chan_rx) { + dev_err(dev->dev, "can't get a DMA channel for rx\n"); + ret = -EBUSY; goto error; } @@ -785,12 +784,11 @@ static int at91_twi_probe(struct platform_device *pdev) static int at91_twi_remove(struct platform_device *pdev) { struct at91_twi_dev *dev = platform_get_drvdata(pdev); - int rc; - rc = i2c_del_adapter(&dev->adapter); + i2c_del_adapter(&dev->adapter); clk_disable_unprepare(dev->clk); - return rc; + return 0; } #ifdef CONFIG_PM @@ -828,7 +826,7 @@ static struct platform_driver at91_twi_driver = { .driver = { .name = "at91_i2c", .owner = THIS_MODULE, - .of_match_table = atmel_twi_dt_ids, + .of_match_table = of_match_ptr(atmel_twi_dt_ids), .pm = at91_twi_pm_ops, }, }; diff --git a/drivers/i2c/busses/i2c-cbus-gpio.c b/drivers/i2c/busses/i2c-cbus-gpio.c index 98386d65931..1be13ac11dc 100644 --- a/drivers/i2c/busses/i2c-cbus-gpio.c +++ b/drivers/i2c/busses/i2c-cbus-gpio.c @@ -206,7 +206,9 @@ static int cbus_i2c_remove(struct platform_device *pdev) { struct i2c_adapter *adapter = platform_get_drvdata(pdev); - return i2c_del_adapter(adapter); + i2c_del_adapter(adapter); + + return 0; } static int cbus_i2c_probe(struct platform_device *pdev) diff --git a/drivers/i2c/busses/i2c-davinci.c b/drivers/i2c/busses/i2c-davinci.c index 7d1e590a7bb..cf20e06a88e 100644 --- a/drivers/i2c/busses/i2c-davinci.c +++ b/drivers/i2c/busses/i2c-davinci.c @@ -137,7 +137,7 @@ static inline u16 davinci_i2c_read_reg(struct davinci_i2c_dev *i2c_dev, int reg) } /* Generate a pulse on the i2c clock pin. */ -static void generic_i2c_clock_pulse(unsigned int scl_pin) +static void davinci_i2c_clock_pulse(unsigned int scl_pin) { u16 i; @@ -155,7 +155,7 @@ static void generic_i2c_clock_pulse(unsigned int scl_pin) /* This routine does i2c bus recovery as specified in the * i2c protocol Rev. 03 section 3.16 titled "Bus clear" */ -static void i2c_recover_bus(struct davinci_i2c_dev *dev) +static void davinci_i2c_recover_bus(struct davinci_i2c_dev *dev) { u32 flag = 0; struct davinci_i2c_platform_data *pdata = dev->pdata; @@ -166,7 +166,7 @@ static void i2c_recover_bus(struct davinci_i2c_dev *dev) flag |= DAVINCI_I2C_MDR_NACK; /* write the data into mode register */ davinci_i2c_write_reg(dev, DAVINCI_I2C_MDR_REG, flag); - generic_i2c_clock_pulse(pdata->scl_pin); + davinci_i2c_clock_pulse(pdata->scl_pin); /* Send STOP */ flag = davinci_i2c_read_reg(dev, DAVINCI_I2C_MDR_REG); flag |= DAVINCI_I2C_MDR_STP; @@ -289,7 +289,7 @@ static int i2c_davinci_wait_bus_not_busy(struct davinci_i2c_dev *dev, return -ETIMEDOUT; } else { to_cnt = 0; - i2c_recover_bus(dev); + davinci_i2c_recover_bus(dev); i2c_davinci_init(dev); } } @@ -379,7 +379,7 @@ i2c_davinci_xfer_msg(struct i2c_adapter *adap, struct i2c_msg *msg, int stop) dev->adapter.timeout); if (r == 0) { dev_err(dev->dev, "controller timed out\n"); - i2c_recover_bus(dev); + davinci_i2c_recover_bus(dev); i2c_davinci_init(dev); dev->buf_len = 0; return -ETIMEDOUT; @@ -643,7 +643,7 @@ static int davinci_i2c_probe(struct platform_device *pdev) { struct davinci_i2c_dev *dev; struct i2c_adapter *adap; - struct resource *mem, *irq, *ioarea; + struct resource *mem, *irq; int r; /* NOTE: driver uses the static register mapping */ @@ -659,24 +659,18 @@ static int davinci_i2c_probe(struct platform_device *pdev) return -ENODEV; } - ioarea = request_mem_region(mem->start, resource_size(mem), - pdev->name); - if (!ioarea) { - dev_err(&pdev->dev, "I2C region already claimed\n"); - return -EBUSY; - } - - dev = kzalloc(sizeof(struct davinci_i2c_dev), GFP_KERNEL); + dev = devm_kzalloc(&pdev->dev, sizeof(struct davinci_i2c_dev), + GFP_KERNEL); if (!dev) { - r = -ENOMEM; - goto err_release_region; + dev_err(&pdev->dev, "Memory allocation failed\n"); + return -ENOMEM; } init_completion(&dev->cmd_complete); #ifdef CONFIG_CPU_FREQ init_completion(&dev->xfr_complete); #endif - dev->dev = get_device(&pdev->dev); + dev->dev = &pdev->dev; dev->irq = irq->start; dev->pdata = dev->dev->platform_data; platform_set_drvdata(pdev, dev); @@ -686,10 +680,9 @@ static int davinci_i2c_probe(struct platform_device *pdev) dev->pdata = devm_kzalloc(&pdev->dev, sizeof(struct davinci_i2c_platform_data), GFP_KERNEL); - if (!dev->pdata) { - r = -ENOMEM; - goto err_free_mem; - } + if (!dev->pdata) + return -ENOMEM; + memcpy(dev->pdata, &davinci_i2c_platform_data_default, sizeof(struct davinci_i2c_platform_data)); if (!of_property_read_u32(pdev->dev.of_node, "clock-frequency", @@ -699,22 +692,21 @@ static int davinci_i2c_probe(struct platform_device *pdev) dev->pdata = &davinci_i2c_platform_data_default; } - dev->clk = clk_get(&pdev->dev, NULL); - if (IS_ERR(dev->clk)) { - r = -ENODEV; - goto err_free_mem; - } + dev->clk = devm_clk_get(&pdev->dev, NULL); + if (IS_ERR(dev->clk)) + return -ENODEV; clk_prepare_enable(dev->clk); - dev->base = ioremap(mem->start, resource_size(mem)); - if (!dev->base) { - r = -EBUSY; - goto err_mem_ioremap; + dev->base = devm_ioremap_resource(&pdev->dev, mem); + if (IS_ERR(dev->base)) { + r = PTR_ERR(dev->base); + goto err_unuse_clocks; } i2c_davinci_init(dev); - r = request_irq(dev->irq, i2c_davinci_isr, 0, pdev->name, dev); + r = devm_request_irq(&pdev->dev, dev->irq, i2c_davinci_isr, 0, + pdev->name, dev); if (r) { dev_err(&pdev->dev, "failure requesting irq %i\n", dev->irq); goto err_unuse_clocks; @@ -723,7 +715,7 @@ static int davinci_i2c_probe(struct platform_device *pdev) r = i2c_davinci_cpufreq_register(dev); if (r) { dev_err(&pdev->dev, "failed to register cpufreq\n"); - goto err_free_irq; + goto err_unuse_clocks; } adap = &dev->adapter; @@ -740,50 +732,31 @@ static int davinci_i2c_probe(struct platform_device *pdev) r = i2c_add_numbered_adapter(adap); if (r) { dev_err(&pdev->dev, "failure adding adapter\n"); - goto err_free_irq; + goto err_unuse_clocks; } of_i2c_register_devices(adap); return 0; -err_free_irq: - free_irq(dev->irq, dev); err_unuse_clocks: - iounmap(dev->base); -err_mem_ioremap: clk_disable_unprepare(dev->clk); - clk_put(dev->clk); dev->clk = NULL; -err_free_mem: - put_device(&pdev->dev); - kfree(dev); -err_release_region: - release_mem_region(mem->start, resource_size(mem)); - return r; } static int davinci_i2c_remove(struct platform_device *pdev) { struct davinci_i2c_dev *dev = platform_get_drvdata(pdev); - struct resource *mem; i2c_davinci_cpufreq_deregister(dev); i2c_del_adapter(&dev->adapter); - put_device(&pdev->dev); clk_disable_unprepare(dev->clk); - clk_put(dev->clk); dev->clk = NULL; davinci_i2c_write_reg(dev, DAVINCI_I2C_MDR_REG, 0); - free_irq(dev->irq, dev); - iounmap(dev->base); - kfree(dev); - mem = platform_get_resource(pdev, IORESOURCE_MEM, 0); - release_mem_region(mem->start, resource_size(mem)); return 0; } diff --git a/drivers/i2c/busses/i2c-designware-core.c b/drivers/i2c/busses/i2c-designware-core.c index 94fd8187540..21fbb340ad6 100644 --- a/drivers/i2c/busses/i2c-designware-core.c +++ b/drivers/i2c/busses/i2c-designware-core.c @@ -68,6 +68,7 @@ #define DW_IC_TXFLR 0x74 #define DW_IC_RXFLR 0x78 #define DW_IC_TX_ABRT_SOURCE 0x80 +#define DW_IC_ENABLE_STATUS 0x9c #define DW_IC_COMP_PARAM_1 0xf4 #define DW_IC_COMP_TYPE 0xfc #define DW_IC_COMP_TYPE_VALUE 0x44570140 @@ -248,6 +249,27 @@ static u32 i2c_dw_scl_lcnt(u32 ic_clk, u32 tLOW, u32 tf, int offset) return ((ic_clk * (tLOW + tf) + 5000) / 10000) - 1 + offset; } +static void __i2c_dw_enable(struct dw_i2c_dev *dev, bool enable) +{ + int timeout = 100; + + do { + dw_writel(dev, enable, DW_IC_ENABLE); + if ((dw_readl(dev, DW_IC_ENABLE_STATUS) & 1) == enable) + return; + + /* + * Wait 10 times the signaling period of the highest I2C + * transfer supported by the driver (for 400KHz this is + * 25us) as described in the DesignWare I2C databook. + */ + usleep_range(25, 250); + } while (timeout--); + + dev_warn(dev->dev, "timeout in %sabling adapter\n", + enable ? "en" : "dis"); +} + /** * i2c_dw_init() - initialize the designware i2c master hardware * @dev: device private data @@ -278,7 +300,7 @@ int i2c_dw_init(struct dw_i2c_dev *dev) } /* Disable the adapter */ - dw_writel(dev, 0, DW_IC_ENABLE); + __i2c_dw_enable(dev, false); /* set standard and fast speed deviders for high/low periods */ @@ -333,7 +355,7 @@ static int i2c_dw_wait_bus_not_busy(struct dw_i2c_dev *dev) return -ETIMEDOUT; } timeout--; - mdelay(1); + usleep_range(1000, 1100); } return 0; @@ -345,7 +367,7 @@ static void i2c_dw_xfer_init(struct dw_i2c_dev *dev) u32 ic_con; /* Disable the adapter */ - dw_writel(dev, 0, DW_IC_ENABLE); + __i2c_dw_enable(dev, false); /* set the slave (target) address */ dw_writel(dev, msgs[dev->msg_write_idx].addr, DW_IC_TAR); @@ -359,7 +381,7 @@ static void i2c_dw_xfer_init(struct dw_i2c_dev *dev) dw_writel(dev, ic_con, DW_IC_CON); /* Enable the adapter */ - dw_writel(dev, 1, DW_IC_ENABLE); + __i2c_dw_enable(dev, true); /* Enable interrupts */ dw_writel(dev, DW_IC_INTR_DEFAULT_MASK, DW_IC_INTR_MASK); @@ -565,7 +587,7 @@ i2c_dw_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[], int num) /* no error */ if (likely(!dev->cmd_err)) { /* Disable the adapter */ - dw_writel(dev, 0, DW_IC_ENABLE); + __i2c_dw_enable(dev, false); ret = num; goto done; } @@ -578,7 +600,8 @@ i2c_dw_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[], int num) ret = -EIO; done: - pm_runtime_put(dev->dev); + pm_runtime_mark_last_busy(dev->dev); + pm_runtime_put_autosuspend(dev->dev); mutex_unlock(&dev->lock); return ret; @@ -700,7 +723,7 @@ EXPORT_SYMBOL_GPL(i2c_dw_isr); void i2c_dw_enable(struct dw_i2c_dev *dev) { /* Enable the adapter */ - dw_writel(dev, 1, DW_IC_ENABLE); + __i2c_dw_enable(dev, true); } EXPORT_SYMBOL_GPL(i2c_dw_enable); @@ -713,7 +736,7 @@ EXPORT_SYMBOL_GPL(i2c_dw_is_enabled); void i2c_dw_disable(struct dw_i2c_dev *dev) { /* Disable controller */ - dw_writel(dev, 0, DW_IC_ENABLE); + __i2c_dw_enable(dev, false); /* Disable all interupts */ dw_writel(dev, 0, DW_IC_INTR_MASK); diff --git a/drivers/i2c/busses/i2c-designware-pcidrv.c b/drivers/i2c/busses/i2c-designware-pcidrv.c index 7c5e383c350..f6ed06c966e 100644 --- a/drivers/i2c/busses/i2c-designware-pcidrv.c +++ b/drivers/i2c/busses/i2c-designware-pcidrv.c @@ -208,68 +208,45 @@ static u32 i2c_dw_get_clk_rate_khz(struct dw_i2c_dev *dev) } static int i2c_dw_pci_probe(struct pci_dev *pdev, -const struct pci_device_id *id) + const struct pci_device_id *id) { struct dw_i2c_dev *dev; struct i2c_adapter *adap; - unsigned long start, len; - void __iomem *base; int r; struct dw_pci_controller *controller; if (id->driver_data >= ARRAY_SIZE(dw_pci_controllers)) { - printk(KERN_ERR "dw_i2c_pci_probe: invalid driver data %ld\n", + dev_err(&pdev->dev, "%s: invalid driver data %ld\n", __func__, id->driver_data); return -EINVAL; } controller = &dw_pci_controllers[id->driver_data]; - r = pci_enable_device(pdev); + r = pcim_enable_device(pdev); if (r) { dev_err(&pdev->dev, "Failed to enable I2C PCI device (%d)\n", r); - goto exit; + return r; } - /* Determine the address of the I2C area */ - start = pci_resource_start(pdev, 0); - len = pci_resource_len(pdev, 0); - if (!start || len == 0) { - dev_err(&pdev->dev, "base address not set\n"); - r = -ENODEV; - goto exit; - } - - r = pci_request_region(pdev, 0, DRIVER_NAME); + r = pcim_iomap_regions(pdev, 1 << 0, pci_name(pdev)); if (r) { - dev_err(&pdev->dev, "failed to request I2C region " - "0x%lx-0x%lx\n", start, - (unsigned long)pci_resource_end(pdev, 0)); - goto exit; - } - - base = ioremap_nocache(start, len); - if (!base) { dev_err(&pdev->dev, "I/O memory remapping failed\n"); - r = -ENOMEM; - goto err_release_region; + return r; } - - dev = kzalloc(sizeof(struct dw_i2c_dev), GFP_KERNEL); - if (!dev) { - r = -ENOMEM; - goto err_release_region; - } + dev = devm_kzalloc(&pdev->dev, sizeof(struct dw_i2c_dev), GFP_KERNEL); + if (!dev) + return -ENOMEM; init_completion(&dev->cmd_complete); mutex_init(&dev->lock); dev->clk = NULL; dev->controller = controller; dev->get_clk_rate_khz = i2c_dw_get_clk_rate_khz; - dev->base = base; - dev->dev = get_device(&pdev->dev); + dev->base = pcim_iomap_table(pdev)[0]; + dev->dev = &pdev->dev; dev->functionality = I2C_FUNC_I2C | I2C_FUNC_SMBUS_BYTE | @@ -284,7 +261,7 @@ const struct pci_device_id *id) dev->rx_fifo_depth = controller->rx_fifo_depth; r = i2c_dw_init(dev); if (r) - goto err_iounmap; + return r; adap = &dev->adapter; i2c_set_adapdata(adap, dev); @@ -296,10 +273,11 @@ const struct pci_device_id *id) snprintf(adap->name, sizeof(adap->name), "i2c-designware-pci-%d", adap->nr); - r = request_irq(pdev->irq, i2c_dw_isr, IRQF_SHARED, adap->name, dev); + r = devm_request_irq(&pdev->dev, pdev->irq, i2c_dw_isr, IRQF_SHARED, + adap->name, dev); if (r) { dev_err(&pdev->dev, "failure requesting irq %i\n", dev->irq); - goto err_iounmap; + return r; } i2c_dw_disable_int(dev); @@ -307,24 +285,14 @@ const struct pci_device_id *id) r = i2c_add_numbered_adapter(adap); if (r) { dev_err(&pdev->dev, "failure adding adapter\n"); - goto err_free_irq; + return r; } - pm_runtime_put_noidle(&pdev->dev); + pm_runtime_set_autosuspend_delay(&pdev->dev, 1000); + pm_runtime_use_autosuspend(&pdev->dev); pm_runtime_allow(&pdev->dev); return 0; - -err_free_irq: - free_irq(pdev->irq, dev); -err_iounmap: - iounmap(dev->base); - put_device(&pdev->dev); - kfree(dev); -err_release_region: - pci_release_region(pdev, 0); -exit: - return r; } static void i2c_dw_pci_remove(struct pci_dev *pdev) @@ -336,11 +304,6 @@ static void i2c_dw_pci_remove(struct pci_dev *pdev) pm_runtime_get_noresume(&pdev->dev); i2c_del_adapter(&dev->adapter); - put_device(&pdev->dev); - - free_irq(dev->irq, dev); - kfree(dev); - pci_release_region(pdev, 0); } /* work with hotplug and coldplug */ diff --git a/drivers/i2c/busses/i2c-designware-platdrv.c b/drivers/i2c/busses/i2c-designware-platdrv.c index e3085c487ac..8ec91335d95 100644 --- a/drivers/i2c/busses/i2c-designware-platdrv.c +++ b/drivers/i2c/busses/i2c-designware-platdrv.c @@ -56,20 +56,11 @@ static u32 i2c_dw_get_clk_rate_khz(struct dw_i2c_dev *dev) static int dw_i2c_acpi_configure(struct platform_device *pdev) { struct dw_i2c_dev *dev = platform_get_drvdata(pdev); - struct acpi_device *adev; - int busno, ret; if (!ACPI_HANDLE(&pdev->dev)) return -ENODEV; - ret = acpi_bus_get_device(ACPI_HANDLE(&pdev->dev), &adev); - if (ret) - return -ENODEV; - dev->adapter.nr = -1; - if (adev->pnp.unique_id && !kstrtoint(adev->pnp.unique_id, 0, &busno)) - dev->adapter.nr = busno; - dev->tx_fifo_depth = 32; dev->rx_fifo_depth = 32; return 0; @@ -92,7 +83,7 @@ static int dw_i2c_probe(struct platform_device *pdev) { struct dw_i2c_dev *dev; struct i2c_adapter *adap; - struct resource *mem, *ioarea; + struct resource *mem; int irq, r; /* NOTE: driver uses the static register mapping */ @@ -108,32 +99,25 @@ static int dw_i2c_probe(struct platform_device *pdev) return irq; /* -ENXIO */ } - ioarea = request_mem_region(mem->start, resource_size(mem), - pdev->name); - if (!ioarea) { - dev_err(&pdev->dev, "I2C region already claimed\n"); - return -EBUSY; - } + dev = devm_kzalloc(&pdev->dev, sizeof(struct dw_i2c_dev), GFP_KERNEL); + if (!dev) + return -ENOMEM; - dev = kzalloc(sizeof(struct dw_i2c_dev), GFP_KERNEL); - if (!dev) { - r = -ENOMEM; - goto err_release_region; - } + dev->base = devm_ioremap_resource(&pdev->dev, mem); + if (IS_ERR(dev->base)) + return PTR_ERR(dev->base); init_completion(&dev->cmd_complete); mutex_init(&dev->lock); - dev->dev = get_device(&pdev->dev); + dev->dev = &pdev->dev; dev->irq = irq; platform_set_drvdata(pdev, dev); - dev->clk = clk_get(&pdev->dev, NULL); + dev->clk = devm_clk_get(&pdev->dev, NULL); dev->get_clk_rate_khz = i2c_dw_get_clk_rate_khz; - if (IS_ERR(dev->clk)) { - r = -ENODEV; - goto err_free_mem; - } + if (IS_ERR(dev->clk)) + return PTR_ERR(dev->clk); clk_prepare_enable(dev->clk); dev->functionality = @@ -146,13 +130,6 @@ static int dw_i2c_probe(struct platform_device *pdev) dev->master_cfg = DW_IC_CON_MASTER | DW_IC_CON_SLAVE_DISABLE | DW_IC_CON_RESTART_EN | DW_IC_CON_SPEED_FAST; - dev->base = ioremap(mem->start, resource_size(mem)); - if (dev->base == NULL) { - dev_err(&pdev->dev, "failure mapping io resources\n"); - r = -EBUSY; - goto err_unuse_clocks; - } - /* Try first if we can configure the device from ACPI */ r = dw_i2c_acpi_configure(pdev); if (r) { @@ -164,13 +141,14 @@ static int dw_i2c_probe(struct platform_device *pdev) } r = i2c_dw_init(dev); if (r) - goto err_iounmap; + return r; i2c_dw_disable_int(dev); - r = request_irq(dev->irq, i2c_dw_isr, IRQF_SHARED, pdev->name, dev); + r = devm_request_irq(&pdev->dev, dev->irq, i2c_dw_isr, IRQF_SHARED, + pdev->name, dev); if (r) { dev_err(&pdev->dev, "failure requesting irq %i\n", dev->irq); - goto err_iounmap; + return r; } adap = &dev->adapter; @@ -186,57 +164,32 @@ static int dw_i2c_probe(struct platform_device *pdev) r = i2c_add_numbered_adapter(adap); if (r) { dev_err(&pdev->dev, "failure adding adapter\n"); - goto err_free_irq; + return r; } of_i2c_register_devices(adap); acpi_i2c_register_devices(adap); + pm_runtime_set_autosuspend_delay(&pdev->dev, 1000); + pm_runtime_use_autosuspend(&pdev->dev); pm_runtime_set_active(&pdev->dev); pm_runtime_enable(&pdev->dev); - pm_runtime_put(&pdev->dev); return 0; - -err_free_irq: - free_irq(dev->irq, dev); -err_iounmap: - iounmap(dev->base); -err_unuse_clocks: - clk_disable_unprepare(dev->clk); - clk_put(dev->clk); - dev->clk = NULL; -err_free_mem: - put_device(&pdev->dev); - kfree(dev); -err_release_region: - release_mem_region(mem->start, resource_size(mem)); - - return r; } static int dw_i2c_remove(struct platform_device *pdev) { struct dw_i2c_dev *dev = platform_get_drvdata(pdev); - struct resource *mem; pm_runtime_get_sync(&pdev->dev); i2c_del_adapter(&dev->adapter); - put_device(&pdev->dev); - - clk_disable_unprepare(dev->clk); - clk_put(dev->clk); - dev->clk = NULL; i2c_dw_disable(dev); - free_irq(dev->irq, dev); - kfree(dev); pm_runtime_put(&pdev->dev); pm_runtime_disable(&pdev->dev); - mem = platform_get_resource(pdev, IORESOURCE_MEM, 0); - release_mem_region(mem->start, resource_size(mem)); return 0; } diff --git a/drivers/i2c/busses/i2c-gpio.c b/drivers/i2c/busses/i2c-gpio.c index f3fa4332bbd..bc6e139c6e7 100644 --- a/drivers/i2c/busses/i2c-gpio.c +++ b/drivers/i2c/busses/i2c-gpio.c @@ -85,23 +85,29 @@ static int i2c_gpio_getscl(void *data) return gpio_get_value(pdata->scl_pin); } -static int of_i2c_gpio_probe(struct device_node *np, - struct i2c_gpio_platform_data *pdata) +static int of_i2c_gpio_get_pins(struct device_node *np, + unsigned int *sda_pin, unsigned int *scl_pin) { - u32 reg; - if (of_gpio_count(np) < 2) return -ENODEV; - pdata->sda_pin = of_get_gpio(np, 0); - pdata->scl_pin = of_get_gpio(np, 1); + *sda_pin = of_get_gpio(np, 0); + *scl_pin = of_get_gpio(np, 1); - if (!gpio_is_valid(pdata->sda_pin) || !gpio_is_valid(pdata->scl_pin)) { + if (!gpio_is_valid(*sda_pin) || !gpio_is_valid(*scl_pin)) { pr_err("%s: invalid GPIO pins, sda=%d/scl=%d\n", - np->full_name, pdata->sda_pin, pdata->scl_pin); + np->full_name, *sda_pin, *scl_pin); return -ENODEV; } + return 0; +} + +static void of_i2c_gpio_get_props(struct device_node *np, + struct i2c_gpio_platform_data *pdata) +{ + u32 reg; + of_property_read_u32(np, "i2c-gpio,delay-us", &pdata->udelay); if (!of_property_read_u32(np, "i2c-gpio,timeout-ms", ®)) @@ -113,8 +119,6 @@ static int of_i2c_gpio_probe(struct device_node *np, of_property_read_bool(np, "i2c-gpio,scl-open-drain"); pdata->scl_is_output_only = of_property_read_bool(np, "i2c-gpio,scl-output-only"); - - return 0; } static int i2c_gpio_probe(struct platform_device *pdev) @@ -123,31 +127,52 @@ static int i2c_gpio_probe(struct platform_device *pdev) struct i2c_gpio_platform_data *pdata; struct i2c_algo_bit_data *bit_data; struct i2c_adapter *adap; + unsigned int sda_pin, scl_pin; int ret; - priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL); - if (!priv) - return -ENOMEM; - adap = &priv->adap; - bit_data = &priv->bit_data; - pdata = &priv->pdata; - + /* First get the GPIO pins; if it fails, we'll defer the probe. */ if (pdev->dev.of_node) { - ret = of_i2c_gpio_probe(pdev->dev.of_node, pdata); + ret = of_i2c_gpio_get_pins(pdev->dev.of_node, + &sda_pin, &scl_pin); if (ret) return ret; } else { if (!pdev->dev.platform_data) return -ENXIO; - memcpy(pdata, pdev->dev.platform_data, sizeof(*pdata)); + pdata = pdev->dev.platform_data; + sda_pin = pdata->sda_pin; + scl_pin = pdata->scl_pin; } - ret = gpio_request(pdata->sda_pin, "sda"); - if (ret) + ret = gpio_request(sda_pin, "sda"); + if (ret) { + if (ret == -EINVAL) + ret = -EPROBE_DEFER; /* Try again later */ goto err_request_sda; - ret = gpio_request(pdata->scl_pin, "scl"); - if (ret) + } + ret = gpio_request(scl_pin, "scl"); + if (ret) { + if (ret == -EINVAL) + ret = -EPROBE_DEFER; /* Try again later */ goto err_request_scl; + } + + priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL); + if (!priv) { + ret = -ENOMEM; + goto err_add_bus; + } + adap = &priv->adap; + bit_data = &priv->bit_data; + pdata = &priv->pdata; + + if (pdev->dev.of_node) { + pdata->sda_pin = sda_pin; + pdata->scl_pin = scl_pin; + of_i2c_gpio_get_props(pdev->dev.of_node, pdata); + } else { + memcpy(pdata, pdev->dev.platform_data, sizeof(*pdata)); + } if (pdata->sda_is_open_drain) { gpio_direction_output(pdata->sda_pin, 1); @@ -211,9 +236,9 @@ static int i2c_gpio_probe(struct platform_device *pdev) return 0; err_add_bus: - gpio_free(pdata->scl_pin); + gpio_free(scl_pin); err_request_scl: - gpio_free(pdata->sda_pin); + gpio_free(sda_pin); err_request_sda: return ret; } diff --git a/drivers/i2c/busses/i2c-intel-mid.c b/drivers/i2c/busses/i2c-intel-mid.c index 323fa018ffd..0fb659726ff 100644 --- a/drivers/i2c/busses/i2c-intel-mid.c +++ b/drivers/i2c/busses/i2c-intel-mid.c @@ -1082,8 +1082,7 @@ static void intel_mid_i2c_remove(struct pci_dev *dev) { struct intel_mid_i2c_private *mrst = pci_get_drvdata(dev); intel_mid_i2c_disable(&mrst->adap); - if (i2c_del_adapter(&mrst->adap)) - dev_err(&dev->dev, "Failed to delete i2c adapter"); + i2c_del_adapter(&mrst->adap); free_irq(dev->irq, mrst); iounmap(mrst->base); diff --git a/drivers/i2c/busses/i2c-ismt.c b/drivers/i2c/busses/i2c-ismt.c index 130f02cc9d9..cd82eb44e4c 100644 --- a/drivers/i2c/busses/i2c-ismt.c +++ b/drivers/i2c/busses/i2c-ismt.c @@ -183,7 +183,7 @@ struct ismt_priv { /** * ismt_ids - PCI device IDs supported by this driver */ -static const DEFINE_PCI_DEVICE_TABLE(ismt_ids) = { +static DEFINE_PCI_DEVICE_TABLE(ismt_ids) = { { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_S1200_SMT0) }, { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_S1200_SMT1) }, { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_AVOTON_SMT) }, diff --git a/drivers/i2c/busses/i2c-mv64xxx.c b/drivers/i2c/busses/i2c-mv64xxx.c index 8b20ef8524a..3bbd65d35a5 100644 --- a/drivers/i2c/busses/i2c-mv64xxx.c +++ b/drivers/i2c/busses/i2c-mv64xxx.c @@ -701,9 +701,8 @@ static int mv64xxx_i2c_remove(struct platform_device *dev) { struct mv64xxx_i2c_data *drv_data = platform_get_drvdata(dev); - int rc; - rc = i2c_del_adapter(&drv_data->adapter); + i2c_del_adapter(&drv_data->adapter); free_irq(drv_data->irq, drv_data); mv64xxx_i2c_unmap_regs(drv_data); #if defined(CONFIG_HAVE_CLK) @@ -715,7 +714,7 @@ mv64xxx_i2c_remove(struct platform_device *dev) #endif kfree(drv_data); - return rc; + return 0; } static const struct of_device_id mv64xxx_i2c_of_match_table[] = { diff --git a/drivers/i2c/busses/i2c-mxs.c b/drivers/i2c/busses/i2c-mxs.c index 120f2464669..c67d89fc625 100644 --- a/drivers/i2c/busses/i2c-mxs.c +++ b/drivers/i2c/busses/i2c-mxs.c @@ -56,6 +56,7 @@ #define MXS_I2C_CTRL1_SET (0x44) #define MXS_I2C_CTRL1_CLR (0x48) +#define MXS_I2C_CTRL1_CLR_GOT_A_NAK 0x10000000 #define MXS_I2C_CTRL1_BUS_FREE_IRQ 0x80 #define MXS_I2C_CTRL1_DATA_ENGINE_CMPLT_IRQ 0x40 #define MXS_I2C_CTRL1_NO_SLAVE_ACK_IRQ 0x20 @@ -65,6 +66,10 @@ #define MXS_I2C_CTRL1_SLAVE_STOP_IRQ 0x02 #define MXS_I2C_CTRL1_SLAVE_IRQ 0x01 +#define MXS_I2C_STAT (0x50) +#define MXS_I2C_STAT_BUS_BUSY 0x00000800 +#define MXS_I2C_STAT_CLK_GEN_BUSY 0x00000400 + #define MXS_I2C_DATA (0xa0) #define MXS_I2C_DEBUG0 (0xb0) @@ -297,12 +302,10 @@ static int mxs_i2c_pio_wait_dmareq(struct mxs_i2c_dev *i2c) cond_resched(); } - writel(MXS_I2C_DEBUG0_DMAREQ, i2c->regs + MXS_I2C_DEBUG0_CLR); - return 0; } -static int mxs_i2c_pio_wait_cplt(struct mxs_i2c_dev *i2c) +static int mxs_i2c_pio_wait_cplt(struct mxs_i2c_dev *i2c, int last) { unsigned long timeout = jiffies + msecs_to_jiffies(1000); @@ -323,9 +326,50 @@ static int mxs_i2c_pio_wait_cplt(struct mxs_i2c_dev *i2c) writel(MXS_I2C_CTRL1_DATA_ENGINE_CMPLT_IRQ, i2c->regs + MXS_I2C_CTRL1_CLR); + /* + * When ending a transfer with a stop, we have to wait for the bus to + * go idle before we report the transfer as completed. Otherwise the + * start of the next transfer may race with the end of the current one. + */ + while (last && (readl(i2c->regs + MXS_I2C_STAT) & + (MXS_I2C_STAT_BUS_BUSY | MXS_I2C_STAT_CLK_GEN_BUSY))) { + if (time_after(jiffies, timeout)) + return -ETIMEDOUT; + cond_resched(); + } + return 0; } +static int mxs_i2c_pio_check_error_state(struct mxs_i2c_dev *i2c) +{ + u32 state; + + state = readl(i2c->regs + MXS_I2C_CTRL1_CLR) & MXS_I2C_IRQ_MASK; + + if (state & MXS_I2C_CTRL1_NO_SLAVE_ACK_IRQ) + i2c->cmd_err = -ENXIO; + else if (state & (MXS_I2C_CTRL1_EARLY_TERM_IRQ | + MXS_I2C_CTRL1_MASTER_LOSS_IRQ | + MXS_I2C_CTRL1_SLAVE_STOP_IRQ | + MXS_I2C_CTRL1_SLAVE_IRQ)) + i2c->cmd_err = -EIO; + + return i2c->cmd_err; +} + +static void mxs_i2c_pio_trigger_cmd(struct mxs_i2c_dev *i2c, u32 cmd) +{ + u32 reg; + + writel(cmd, i2c->regs + MXS_I2C_CTRL0); + + /* readback makes sure the write is latched into hardware */ + reg = readl(i2c->regs + MXS_I2C_CTRL0); + reg |= MXS_I2C_CTRL0_RUN; + writel(reg, i2c->regs + MXS_I2C_CTRL0); +} + static int mxs_i2c_pio_setup_xfer(struct i2c_adapter *adap, struct i2c_msg *msg, uint32_t flags) { @@ -341,23 +385,26 @@ static int mxs_i2c_pio_setup_xfer(struct i2c_adapter *adap, addr_data |= I2C_SMBUS_READ; /* SELECT command. */ - writel(MXS_I2C_CTRL0_RUN | MXS_CMD_I2C_SELECT, - i2c->regs + MXS_I2C_CTRL0); + mxs_i2c_pio_trigger_cmd(i2c, MXS_CMD_I2C_SELECT); ret = mxs_i2c_pio_wait_dmareq(i2c); if (ret) return ret; writel(addr_data, i2c->regs + MXS_I2C_DATA); + writel(MXS_I2C_DEBUG0_DMAREQ, i2c->regs + MXS_I2C_DEBUG0_CLR); - ret = mxs_i2c_pio_wait_cplt(i2c); + ret = mxs_i2c_pio_wait_cplt(i2c, 0); if (ret) return ret; + if (mxs_i2c_pio_check_error_state(i2c)) + goto cleanup; + /* READ command. */ - writel(MXS_I2C_CTRL0_RUN | MXS_CMD_I2C_READ | flags | - MXS_I2C_CTRL0_XFER_COUNT(msg->len), - i2c->regs + MXS_I2C_CTRL0); + mxs_i2c_pio_trigger_cmd(i2c, + MXS_CMD_I2C_READ | flags | + MXS_I2C_CTRL0_XFER_COUNT(msg->len)); for (i = 0; i < msg->len; i++) { if ((i & 3) == 0) { @@ -365,6 +412,8 @@ static int mxs_i2c_pio_setup_xfer(struct i2c_adapter *adap, if (ret) return ret; data = readl(i2c->regs + MXS_I2C_DATA); + writel(MXS_I2C_DEBUG0_DMAREQ, + i2c->regs + MXS_I2C_DEBUG0_CLR); } msg->buf[i] = data & 0xff; data >>= 8; @@ -373,9 +422,9 @@ static int mxs_i2c_pio_setup_xfer(struct i2c_adapter *adap, addr_data |= I2C_SMBUS_WRITE; /* WRITE command. */ - writel(MXS_I2C_CTRL0_RUN | MXS_CMD_I2C_WRITE | flags | - MXS_I2C_CTRL0_XFER_COUNT(msg->len + 1), - i2c->regs + MXS_I2C_CTRL0); + mxs_i2c_pio_trigger_cmd(i2c, + MXS_CMD_I2C_WRITE | flags | + MXS_I2C_CTRL0_XFER_COUNT(msg->len + 1)); /* * The LSB of data buffer is the first byte blasted across @@ -391,6 +440,8 @@ static int mxs_i2c_pio_setup_xfer(struct i2c_adapter *adap, if (ret) return ret; writel(data, i2c->regs + MXS_I2C_DATA); + writel(MXS_I2C_DEBUG0_DMAREQ, + i2c->regs + MXS_I2C_DEBUG0_CLR); } } @@ -401,13 +452,19 @@ static int mxs_i2c_pio_setup_xfer(struct i2c_adapter *adap, if (ret) return ret; writel(data, i2c->regs + MXS_I2C_DATA); + writel(MXS_I2C_DEBUG0_DMAREQ, + i2c->regs + MXS_I2C_DEBUG0_CLR); } } - ret = mxs_i2c_pio_wait_cplt(i2c); + ret = mxs_i2c_pio_wait_cplt(i2c, flags & MXS_I2C_CTRL0_POST_SEND_STOP); if (ret) return ret; + /* make sure we capture any occurred error into cmd_err */ + mxs_i2c_pio_check_error_state(i2c); + +cleanup: /* Clear any dangling IRQs and re-enable interrupts. */ writel(MXS_I2C_IRQ_MASK, i2c->regs + MXS_I2C_CTRL1_CLR); writel(MXS_I2C_IRQ_MASK << 8, i2c->regs + MXS_I2C_CTRL1_SET); @@ -439,12 +496,12 @@ static int mxs_i2c_xfer_msg(struct i2c_adapter *adap, struct i2c_msg *msg, * using PIO mode while longer transfers use DMA. The 8 byte border is * based on this empirical measurement and a lot of previous frobbing. */ + i2c->cmd_err = 0; if (msg->len < 8) { ret = mxs_i2c_pio_setup_xfer(adap, msg, flags); if (ret) mxs_i2c_reset(i2c); } else { - i2c->cmd_err = 0; INIT_COMPLETION(i2c->cmd_complete); ret = mxs_i2c_dma_setup_xfer(adap, msg, flags); if (ret) @@ -454,13 +511,19 @@ static int mxs_i2c_xfer_msg(struct i2c_adapter *adap, struct i2c_msg *msg, msecs_to_jiffies(1000)); if (ret == 0) goto timeout; + } - if (i2c->cmd_err == -ENXIO) - mxs_i2c_reset(i2c); - - ret = i2c->cmd_err; + if (i2c->cmd_err == -ENXIO) { + /* + * If the transfer fails with a NAK from the slave the + * controller halts until it gets told to return to idle state. + */ + writel(MXS_I2C_CTRL1_CLR_GOT_A_NAK, + i2c->regs + MXS_I2C_CTRL1_SET); } + ret = i2c->cmd_err; + dev_dbg(i2c->dev, "Done with err=%d\n", ret); return ret; @@ -686,11 +749,8 @@ static int mxs_i2c_probe(struct platform_device *pdev) static int mxs_i2c_remove(struct platform_device *pdev) { struct mxs_i2c_dev *i2c = platform_get_drvdata(pdev); - int ret; - ret = i2c_del_adapter(&i2c->adapter); - if (ret) - return -EBUSY; + i2c_del_adapter(&i2c->adapter); if (i2c->dmach) dma_release_channel(i2c->dmach); diff --git a/drivers/i2c/busses/i2c-nforce2-s4985.c b/drivers/i2c/busses/i2c-nforce2-s4985.c index 29015eb9ca4..2ca268d6140 100644 --- a/drivers/i2c/busses/i2c-nforce2-s4985.c +++ b/drivers/i2c/busses/i2c-nforce2-s4985.c @@ -164,11 +164,7 @@ static int __init nforce2_s4985_init(void) } /* Unregister physical bus */ - error = i2c_del_adapter(nforce2_smbus); - if (error) { - dev_err(&nforce2_smbus->dev, "Physical bus removal failed\n"); - goto ERROR0; - } + i2c_del_adapter(nforce2_smbus); printk(KERN_INFO "Enabling SMBus multiplexing for Tyan S4985\n"); /* Define the 5 virtual adapters and algorithms structures */ diff --git a/drivers/i2c/busses/i2c-octeon.c b/drivers/i2c/busses/i2c-octeon.c index 935585ef4d3..956fe320f31 100644 --- a/drivers/i2c/busses/i2c-octeon.c +++ b/drivers/i2c/busses/i2c-octeon.c @@ -183,7 +183,7 @@ static irqreturn_t octeon_i2c_isr(int irq, void *dev_id) struct octeon_i2c *i2c = dev_id; octeon_i2c_int_disable(i2c); - wake_up_interruptible(&i2c->queue); + wake_up(&i2c->queue); return IRQ_HANDLED; } @@ -206,9 +206,9 @@ static int octeon_i2c_wait(struct octeon_i2c *i2c) octeon_i2c_int_enable(i2c); - result = wait_event_interruptible_timeout(i2c->queue, - octeon_i2c_test_iflg(i2c), - i2c->adap.timeout); + result = wait_event_timeout(i2c->queue, + octeon_i2c_test_iflg(i2c), + i2c->adap.timeout); octeon_i2c_int_disable(i2c); @@ -440,7 +440,7 @@ static struct i2c_adapter octeon_i2c_ops = { .owner = THIS_MODULE, .name = "OCTEON adapter", .algo = &octeon_i2c_algo, - .timeout = 2, + .timeout = HZ / 50, }; /** diff --git a/drivers/i2c/busses/i2c-powermac.c b/drivers/i2c/busses/i2c-powermac.c index da54e673449..8dc90da1e6e 100644 --- a/drivers/i2c/busses/i2c-powermac.c +++ b/drivers/i2c/busses/i2c-powermac.c @@ -213,14 +213,8 @@ static const struct i2c_algorithm i2c_powermac_algorithm = { static int i2c_powermac_remove(struct platform_device *dev) { struct i2c_adapter *adapter = platform_get_drvdata(dev); - int rc; - - rc = i2c_del_adapter(adapter); - /* We aren't that prepared to deal with this... */ - if (rc) - printk(KERN_WARNING - "i2c-powermac.c: Failed to remove bus %s !\n", - adapter->name); + + i2c_del_adapter(adapter); memset(adapter, 0, sizeof(*adapter)); return 0; diff --git a/drivers/i2c/busses/i2c-puv3.c b/drivers/i2c/busses/i2c-puv3.c index 8acef657abf..37a84c87c5f 100644 --- a/drivers/i2c/busses/i2c-puv3.c +++ b/drivers/i2c/busses/i2c-puv3.c @@ -234,21 +234,15 @@ static int puv3_i2c_remove(struct platform_device *pdev) { struct i2c_adapter *adapter = platform_get_drvdata(pdev); struct resource *mem; - int rc; - rc = i2c_del_adapter(adapter); - if (rc) { - dev_err(&pdev->dev, "Adapter '%s' delete fail\n", - adapter->name); - return rc; - } + i2c_del_adapter(adapter); put_device(&pdev->dev); mem = platform_get_resource(pdev, IORESOURCE_MEM, 0); release_mem_region(mem->start, resource_size(mem)); - return rc; + return 0; } #ifdef CONFIG_PM diff --git a/drivers/i2c/busses/i2c-pxa.c b/drivers/i2c/busses/i2c-pxa.c index 1e88e8d66c5..ea6d45d1dcd 100644 --- a/drivers/i2c/busses/i2c-pxa.c +++ b/drivers/i2c/busses/i2c-pxa.c @@ -1053,16 +1053,13 @@ static int i2c_pxa_probe_dt(struct platform_device *pdev, struct pxa_i2c *i2c, struct device_node *np = pdev->dev.of_node; const struct of_device_id *of_id = of_match_device(i2c_pxa_dt_ids, &pdev->dev); - int ret; if (!of_id) return 1; - ret = of_alias_get_id(np, "i2c"); - if (ret < 0) { - dev_err(&pdev->dev, "failed to get alias id, errno %d\n", ret); - return ret; - } - pdev->id = ret; + + /* For device tree we always use the dynamic or alias-assigned ID */ + i2c->adap.nr = -1; + if (of_get_property(np, "mrvl,i2c-polling", NULL)) i2c->use_pio = 1; if (of_get_property(np, "mrvl,i2c-fast-mode", NULL)) @@ -1100,6 +1097,9 @@ static int i2c_pxa_probe(struct platform_device *dev) goto emalloc; } + /* Default adapter num to device id; i2c_pxa_probe_dt can override. */ + i2c->adap.nr = dev->id; + ret = i2c_pxa_probe_dt(dev, i2c, &i2c_type); if (ret > 0) ret = i2c_pxa_probe_pdata(dev, i2c, &i2c_type); @@ -1124,9 +1124,7 @@ static int i2c_pxa_probe(struct platform_device *dev) spin_lock_init(&i2c->lock); init_waitqueue_head(&i2c->wait); - i2c->adap.nr = dev->id; - snprintf(i2c->adap.name, sizeof(i2c->adap.name), "pxa_i2c-i2c.%u", - i2c->adap.nr); + strlcpy(i2c->adap.name, "pxa_i2c-i2c", sizeof(i2c->adap.name)); i2c->clk = clk_get(&dev->dev, NULL); if (IS_ERR(i2c->clk)) { @@ -1169,7 +1167,7 @@ static int i2c_pxa_probe(struct platform_device *dev) } else { i2c->adap.algo = &i2c_pxa_algorithm; ret = request_irq(irq, i2c_pxa_handler, IRQF_SHARED, - i2c->adap.name, i2c); + dev_name(&dev->dev), i2c); if (ret) goto ereqirq; } diff --git a/drivers/i2c/busses/i2c-s3c2410.c b/drivers/i2c/busses/i2c-s3c2410.c index f6b880ba193..6e8ee92ab55 100644 --- a/drivers/i2c/busses/i2c-s3c2410.c +++ b/drivers/i2c/busses/i2c-s3c2410.c @@ -42,9 +42,46 @@ #include <asm/irq.h> -#include <plat/regs-iic.h> #include <linux/platform_data/i2c-s3c2410.h> +/* see s3c2410x user guide, v1.1, section 9 (p447) for more info */ + +#define S3C2410_IICCON 0x00 +#define S3C2410_IICSTAT 0x04 +#define S3C2410_IICADD 0x08 +#define S3C2410_IICDS 0x0C +#define S3C2440_IICLC 0x10 + +#define S3C2410_IICCON_ACKEN (1 << 7) +#define S3C2410_IICCON_TXDIV_16 (0 << 6) +#define S3C2410_IICCON_TXDIV_512 (1 << 6) +#define S3C2410_IICCON_IRQEN (1 << 5) +#define S3C2410_IICCON_IRQPEND (1 << 4) +#define S3C2410_IICCON_SCALE(x) ((x) & 0xf) +#define S3C2410_IICCON_SCALEMASK (0xf) + +#define S3C2410_IICSTAT_MASTER_RX (2 << 6) +#define S3C2410_IICSTAT_MASTER_TX (3 << 6) +#define S3C2410_IICSTAT_SLAVE_RX (0 << 6) +#define S3C2410_IICSTAT_SLAVE_TX (1 << 6) +#define S3C2410_IICSTAT_MODEMASK (3 << 6) + +#define S3C2410_IICSTAT_START (1 << 5) +#define S3C2410_IICSTAT_BUSBUSY (1 << 5) +#define S3C2410_IICSTAT_TXRXEN (1 << 4) +#define S3C2410_IICSTAT_ARBITR (1 << 3) +#define S3C2410_IICSTAT_ASSLAVE (1 << 2) +#define S3C2410_IICSTAT_ADDR0 (1 << 1) +#define S3C2410_IICSTAT_LASTBIT (1 << 0) + +#define S3C2410_IICLC_SDA_DELAY0 (0 << 0) +#define S3C2410_IICLC_SDA_DELAY5 (1 << 0) +#define S3C2410_IICLC_SDA_DELAY10 (2 << 0) +#define S3C2410_IICLC_SDA_DELAY15 (3 << 0) +#define S3C2410_IICLC_SDA_DELAY_MASK (3 << 0) + +#define S3C2410_IICLC_FILTER_ON (1 << 2) + /* Treat S3C2410 as baseline hardware, anything else is supported via quirks */ #define QUIRK_S3C2440 (1 << 0) #define QUIRK_HDMIPHY (1 << 1) @@ -309,6 +346,12 @@ static inline int is_lastmsg(struct s3c24xx_i2c *i2c) static inline int is_msglast(struct s3c24xx_i2c *i2c) { + /* msg->len is always 1 for the first byte of smbus block read. + * Actual length will be read from slave. More bytes will be + * read according to the length then. */ + if (i2c->msg->flags & I2C_M_RECV_LEN && i2c->msg->len == 1) + return 0; + return i2c->msg_ptr == i2c->msg->len-1; } @@ -448,6 +491,9 @@ static int i2c_s3c_irq_nextbyte(struct s3c24xx_i2c *i2c, unsigned long iicstat) byte = readb(i2c->regs + S3C2410_IICDS); i2c->msg->buf[i2c->msg_ptr++] = byte; + /* Add actual length to read for smbus block read */ + if (i2c->msg->flags & I2C_M_RECV_LEN && i2c->msg->len == 1) + i2c->msg->len += byte; prepare_read: if (is_msglast(i2c)) { /* last byte of buffer */ diff --git a/drivers/i2c/busses/i2c-tegra.c b/drivers/i2c/busses/i2c-tegra.c index b714776b6dd..b60ff90adc3 100644 --- a/drivers/i2c/busses/i2c-tegra.c +++ b/drivers/i2c/busses/i2c-tegra.c @@ -25,7 +25,6 @@ #include <linux/interrupt.h> #include <linux/delay.h> #include <linux/slab.h> -#include <linux/i2c-tegra.h> #include <linux/of_i2c.h> #include <linux/of_device.h> #include <linux/module.h> @@ -172,7 +171,7 @@ struct tegra_i2c_dev { u8 *msg_buf; size_t msg_buf_remaining; int msg_read; - unsigned long bus_clk_rate; + u32 bus_clk_rate; bool is_suspended; }; @@ -694,7 +693,6 @@ static const struct tegra_i2c_hw_feature tegra114_i2c_hw = { .clk_divisor_std_fast_mode = 0x19, }; -#if defined(CONFIG_OF) /* Match table for of_platform binding */ static const struct of_device_id tegra_i2c_of_match[] = { { .compatible = "nvidia,tegra114-i2c", .data = &tegra114_i2c_hw, }, @@ -704,16 +702,13 @@ static const struct of_device_id tegra_i2c_of_match[] = { {}, }; MODULE_DEVICE_TABLE(of, tegra_i2c_of_match); -#endif static int tegra_i2c_probe(struct platform_device *pdev) { struct tegra_i2c_dev *i2c_dev; - struct tegra_i2c_platform_data *pdata = pdev->dev.platform_data; struct resource *res; struct clk *div_clk; struct clk *fast_clk; - const unsigned int *prop; void __iomem *base; int irq; int ret = 0; @@ -754,23 +749,16 @@ static int tegra_i2c_probe(struct platform_device *pdev) i2c_dev->cont_id = pdev->id; i2c_dev->dev = &pdev->dev; - i2c_dev->bus_clk_rate = 100000; /* default clock rate */ - if (pdata) { - i2c_dev->bus_clk_rate = pdata->bus_clk_rate; - - } else if (i2c_dev->dev->of_node) { /* if there is a device tree node ... */ - prop = of_get_property(i2c_dev->dev->of_node, - "clock-frequency", NULL); - if (prop) - i2c_dev->bus_clk_rate = be32_to_cpup(prop); - } + ret = of_property_read_u32(i2c_dev->dev->of_node, "clock-frequency", + &i2c_dev->bus_clk_rate); + if (ret) + i2c_dev->bus_clk_rate = 100000; /* default clock rate */ i2c_dev->hw = &tegra20_i2c_hw; if (pdev->dev.of_node) { const struct of_device_id *match; - match = of_match_device(of_match_ptr(tegra_i2c_of_match), - &pdev->dev); + match = of_match_device(tegra_i2c_of_match, &pdev->dev); i2c_dev->hw = match->data; i2c_dev->is_dvc = of_device_is_compatible(pdev->dev.of_node, "nvidia,tegra20-i2c-dvc"); @@ -876,7 +864,7 @@ static struct platform_driver tegra_i2c_driver = { .driver = { .name = "tegra-i2c", .owner = THIS_MODULE, - .of_match_table = of_match_ptr(tegra_i2c_of_match), + .of_match_table = tegra_i2c_of_match, .pm = TEGRA_I2C_PM, }, }; diff --git a/drivers/i2c/busses/i2c-viperboard.c b/drivers/i2c/busses/i2c-viperboard.c index f45c32c1ace..c68450cd8d5 100644 --- a/drivers/i2c/busses/i2c-viperboard.c +++ b/drivers/i2c/busses/i2c-viperboard.c @@ -421,11 +421,10 @@ error: static int vprbrd_i2c_remove(struct platform_device *pdev) { struct vprbrd_i2c *vb_i2c = platform_get_drvdata(pdev); - int ret; - ret = i2c_del_adapter(&vb_i2c->i2c); + i2c_del_adapter(&vb_i2c->i2c); - return ret; + return 0; } static struct platform_driver vprbrd_i2c_driver = { diff --git a/drivers/i2c/busses/i2c-xiic.c b/drivers/i2c/busses/i2c-xiic.c index 332c720fb3f..3d0f0520c1b 100644 --- a/drivers/i2c/busses/i2c-xiic.c +++ b/drivers/i2c/busses/i2c-xiic.c @@ -312,10 +312,8 @@ static void xiic_fill_tx_fifo(struct xiic_i2c *i2c) /* last message in transfer -> STOP */ data |= XIIC_TX_DYN_STOP_MASK; dev_dbg(i2c->adap.dev.parent, "%s TX STOP\n", __func__); - - xiic_setreg16(i2c, XIIC_DTR_REG_OFFSET, data); - } else - xiic_setreg8(i2c, XIIC_DTR_REG_OFFSET, data); + } + xiic_setreg16(i2c, XIIC_DTR_REG_OFFSET, data); } } diff --git a/drivers/i2c/i2c-core.c b/drivers/i2c/i2c-core.c index 991d38daa87..6b63cc7eb71 100644 --- a/drivers/i2c/i2c-core.c +++ b/drivers/i2c/i2c-core.c @@ -27,7 +27,9 @@ #include <linux/module.h> #include <linux/kernel.h> +#include <linux/delay.h> #include <linux/errno.h> +#include <linux/gpio.h> #include <linux/slab.h> #include <linux/i2c.h> #include <linux/init.h> @@ -47,7 +49,7 @@ /* core_lock protects i2c_adapter_idr, and guarantees that device detection, deletion of detected devices, and attach_adapter - and detach_adapter calls are serialized */ + calls are serialized */ static DEFINE_MUTEX(core_lock); static DEFINE_IDR(i2c_adapter_idr); @@ -91,7 +93,6 @@ static int i2c_device_match(struct device *dev, struct device_driver *drv) return 0; } -#ifdef CONFIG_HOTPLUG /* uevent helps with hotplug: modprobe -q $(MODALIAS) */ static int i2c_device_uevent(struct device *dev, struct kobj_uevent_env *env) @@ -105,9 +106,129 @@ static int i2c_device_uevent(struct device *dev, struct kobj_uevent_env *env) return 0; } -#else -#define i2c_device_uevent NULL -#endif /* CONFIG_HOTPLUG */ +/* i2c bus recovery routines */ +static int get_scl_gpio_value(struct i2c_adapter *adap) +{ + return gpio_get_value(adap->bus_recovery_info->scl_gpio); +} + +static void set_scl_gpio_value(struct i2c_adapter *adap, int val) +{ + gpio_set_value(adap->bus_recovery_info->scl_gpio, val); +} + +static int get_sda_gpio_value(struct i2c_adapter *adap) +{ + return gpio_get_value(adap->bus_recovery_info->sda_gpio); +} + +static int i2c_get_gpios_for_recovery(struct i2c_adapter *adap) +{ + struct i2c_bus_recovery_info *bri = adap->bus_recovery_info; + struct device *dev = &adap->dev; + int ret = 0; + + ret = gpio_request_one(bri->scl_gpio, GPIOF_OPEN_DRAIN | + GPIOF_OUT_INIT_HIGH, "i2c-scl"); + if (ret) { + dev_warn(dev, "Can't get SCL gpio: %d\n", bri->scl_gpio); + return ret; + } + + if (bri->get_sda) { + if (gpio_request_one(bri->sda_gpio, GPIOF_IN, "i2c-sda")) { + /* work without SDA polling */ + dev_warn(dev, "Can't get SDA gpio: %d. Not using SDA polling\n", + bri->sda_gpio); + bri->get_sda = NULL; + } + } + + return ret; +} + +static void i2c_put_gpios_for_recovery(struct i2c_adapter *adap) +{ + struct i2c_bus_recovery_info *bri = adap->bus_recovery_info; + + if (bri->get_sda) + gpio_free(bri->sda_gpio); + + gpio_free(bri->scl_gpio); +} + +/* + * We are generating clock pulses. ndelay() determines durating of clk pulses. + * We will generate clock with rate 100 KHz and so duration of both clock levels + * is: delay in ns = (10^6 / 100) / 2 + */ +#define RECOVERY_NDELAY 5000 +#define RECOVERY_CLK_CNT 9 + +static int i2c_generic_recovery(struct i2c_adapter *adap) +{ + struct i2c_bus_recovery_info *bri = adap->bus_recovery_info; + int i = 0, val = 1, ret = 0; + + if (bri->prepare_recovery) + bri->prepare_recovery(bri); + + /* + * By this time SCL is high, as we need to give 9 falling-rising edges + */ + while (i++ < RECOVERY_CLK_CNT * 2) { + if (val) { + /* Break if SDA is high */ + if (bri->get_sda && bri->get_sda(adap)) + break; + /* SCL shouldn't be low here */ + if (!bri->get_scl(adap)) { + dev_err(&adap->dev, + "SCL is stuck low, exit recovery\n"); + ret = -EBUSY; + break; + } + } + + val = !val; + bri->set_scl(adap, val); + ndelay(RECOVERY_NDELAY); + } + + if (bri->unprepare_recovery) + bri->unprepare_recovery(bri); + + return ret; +} + +int i2c_generic_scl_recovery(struct i2c_adapter *adap) +{ + adap->bus_recovery_info->set_scl(adap, 1); + return i2c_generic_recovery(adap); +} + +int i2c_generic_gpio_recovery(struct i2c_adapter *adap) +{ + int ret; + + ret = i2c_get_gpios_for_recovery(adap); + if (ret) + return ret; + + ret = i2c_generic_recovery(adap); + i2c_put_gpios_for_recovery(adap); + + return ret; +} + +int i2c_recover_bus(struct i2c_adapter *adap) +{ + if (!adap->bus_recovery_info) + return -EOPNOTSUPP; + + dev_dbg(&adap->dev, "Trying i2c bus recovery\n"); + return adap->bus_recovery_info->recover_bus(adap); +} static int i2c_device_probe(struct device *dev) { @@ -902,6 +1023,39 @@ static int i2c_register_adapter(struct i2c_adapter *adap) "Failed to create compatibility class link\n"); #endif + /* bus recovery specific initialization */ + if (adap->bus_recovery_info) { + struct i2c_bus_recovery_info *bri = adap->bus_recovery_info; + + if (!bri->recover_bus) { + dev_err(&adap->dev, "No recover_bus() found, not using recovery\n"); + adap->bus_recovery_info = NULL; + goto exit_recovery; + } + + /* Generic GPIO recovery */ + if (bri->recover_bus == i2c_generic_gpio_recovery) { + if (!gpio_is_valid(bri->scl_gpio)) { + dev_err(&adap->dev, "Invalid SCL gpio, not using recovery\n"); + adap->bus_recovery_info = NULL; + goto exit_recovery; + } + + if (gpio_is_valid(bri->sda_gpio)) + bri->get_sda = get_sda_gpio_value; + else + bri->get_sda = NULL; + + bri->get_scl = get_scl_gpio_value; + bri->set_scl = set_scl_gpio_value; + } else if (!bri->set_scl || !bri->get_scl) { + /* Generic SCL recovery */ + dev_err(&adap->dev, "No {get|set}_gpio() found, not using recovery\n"); + adap->bus_recovery_info = NULL; + } + } + +exit_recovery: /* create pre-declared device nodes */ if (adap->nr < __i2c_first_dynamic_bus_num) i2c_scan_static_board_info(adap); @@ -921,13 +1075,35 @@ out_list: } /** + * __i2c_add_numbered_adapter - i2c_add_numbered_adapter where nr is never -1 + * @adap: the adapter to register (with adap->nr initialized) + * Context: can sleep + * + * See i2c_add_numbered_adapter() for details. + */ +static int __i2c_add_numbered_adapter(struct i2c_adapter *adap) +{ + int id; + + mutex_lock(&core_lock); + id = idr_alloc(&i2c_adapter_idr, adap, adap->nr, adap->nr + 1, + GFP_KERNEL); + mutex_unlock(&core_lock); + if (id < 0) + return id == -ENOSPC ? -EBUSY : id; + + return i2c_register_adapter(adap); +} + +/** * i2c_add_adapter - declare i2c adapter, use dynamic bus number * @adapter: the adapter to add * Context: can sleep * * This routine is used to declare an I2C adapter when its bus number - * doesn't matter. Examples: for I2C adapters dynamically added by - * USB links or PCI plugin cards. + * doesn't matter or when its bus number is specified by an dt alias. + * Examples of bases when the bus number doesn't matter: I2C adapters + * dynamically added by USB links or PCI plugin cards. * * When this returns zero, a new bus number was allocated and stored * in adap->nr, and the specified adapter became available for clients. @@ -935,8 +1111,17 @@ out_list: */ int i2c_add_adapter(struct i2c_adapter *adapter) { + struct device *dev = &adapter->dev; int id; + if (dev->of_node) { + id = of_alias_get_id(dev->of_node, "i2c"); + if (id >= 0) { + adapter->nr = id; + return __i2c_add_numbered_adapter(adapter); + } + } + mutex_lock(&core_lock); id = idr_alloc(&i2c_adapter_idr, adapter, __i2c_first_dynamic_bus_num, 0, GFP_KERNEL); @@ -975,26 +1160,17 @@ EXPORT_SYMBOL(i2c_add_adapter); */ int i2c_add_numbered_adapter(struct i2c_adapter *adap) { - int id; - if (adap->nr == -1) /* -1 means dynamically assign bus id */ return i2c_add_adapter(adap); - mutex_lock(&core_lock); - id = idr_alloc(&i2c_adapter_idr, adap, adap->nr, adap->nr + 1, - GFP_KERNEL); - mutex_unlock(&core_lock); - if (id < 0) - return id == -ENOSPC ? -EBUSY : id; - return i2c_register_adapter(adap); + return __i2c_add_numbered_adapter(adap); } EXPORT_SYMBOL_GPL(i2c_add_numbered_adapter); -static int i2c_do_del_adapter(struct i2c_driver *driver, +static void i2c_do_del_adapter(struct i2c_driver *driver, struct i2c_adapter *adapter) { struct i2c_client *client, *_n; - int res; /* Remove the devices we created ourselves as the result of hardware * probing (using a driver's detect method) */ @@ -1006,16 +1182,6 @@ static int i2c_do_del_adapter(struct i2c_driver *driver, i2c_unregister_device(client); } } - - if (!driver->detach_adapter) - return 0; - dev_warn(&adapter->dev, "%s: detach_adapter method is deprecated\n", - driver->driver.name); - res = driver->detach_adapter(adapter); - if (res) - dev_err(&adapter->dev, "detach_adapter failed (%d) " - "for driver [%s]\n", res, driver->driver.name); - return res; } static int __unregister_client(struct device *dev, void *dummy) @@ -1036,7 +1202,8 @@ static int __unregister_dummy(struct device *dev, void *dummy) static int __process_removed_adapter(struct device_driver *d, void *data) { - return i2c_do_del_adapter(to_i2c_driver(d), data); + i2c_do_del_adapter(to_i2c_driver(d), data); + return 0; } /** @@ -1047,9 +1214,8 @@ static int __process_removed_adapter(struct device_driver *d, void *data) * This unregisters an I2C adapter which was previously registered * by @i2c_add_adapter or @i2c_add_numbered_adapter. */ -int i2c_del_adapter(struct i2c_adapter *adap) +void i2c_del_adapter(struct i2c_adapter *adap) { - int res = 0; struct i2c_adapter *found; struct i2c_client *client, *next; @@ -1060,16 +1226,14 @@ int i2c_del_adapter(struct i2c_adapter *adap) if (found != adap) { pr_debug("i2c-core: attempting to delete unregistered " "adapter [%s]\n", adap->name); - return -EINVAL; + return; } /* Tell drivers about this removal */ mutex_lock(&core_lock); - res = bus_for_each_drv(&i2c_bus_type, NULL, adap, + bus_for_each_drv(&i2c_bus_type, NULL, adap, __process_removed_adapter); mutex_unlock(&core_lock); - if (res) - return res; /* Remove devices instantiated from sysfs */ mutex_lock_nested(&adap->userspace_clients_lock, @@ -1088,8 +1252,8 @@ int i2c_del_adapter(struct i2c_adapter *adap) * we can't remove the dummy devices during the first pass: they * could have been instantiated by real devices wishing to clean * them up properly, so we give them a chance to do that first. */ - res = device_for_each_child(&adap->dev, NULL, __unregister_client); - res = device_for_each_child(&adap->dev, NULL, __unregister_dummy); + device_for_each_child(&adap->dev, NULL, __unregister_client); + device_for_each_child(&adap->dev, NULL, __unregister_dummy); #ifdef CONFIG_I2C_COMPAT class_compat_remove_link(i2c_adapter_compat_class, &adap->dev, @@ -1114,8 +1278,6 @@ int i2c_del_adapter(struct i2c_adapter *adap) /* Clear the device structure in case this adapter is ever going to be added again */ memset(&adap->dev, 0, sizeof(adap->dev)); - - return 0; } EXPORT_SYMBOL(i2c_del_adapter); @@ -1185,9 +1347,9 @@ EXPORT_SYMBOL(i2c_register_driver); static int __process_removed_driver(struct device *dev, void *data) { - if (dev->type != &i2c_adapter_type) - return 0; - return i2c_do_del_adapter(data, to_i2c_adapter(dev)); + if (dev->type == &i2c_adapter_type) + i2c_do_del_adapter(data, to_i2c_adapter(dev)); + return 0; } /** diff --git a/drivers/i2c/i2c-mux.c b/drivers/i2c/i2c-mux.c index d94e0ce7827..7409ebb33c4 100644 --- a/drivers/i2c/i2c-mux.c +++ b/drivers/i2c/i2c-mux.c @@ -191,17 +191,12 @@ struct i2c_adapter *i2c_add_mux_adapter(struct i2c_adapter *parent, } EXPORT_SYMBOL_GPL(i2c_add_mux_adapter); -int i2c_del_mux_adapter(struct i2c_adapter *adap) +void i2c_del_mux_adapter(struct i2c_adapter *adap) { struct i2c_mux_priv *priv = adap->algo_data; - int ret; - ret = i2c_del_adapter(adap); - if (ret < 0) - return ret; + i2c_del_adapter(adap); kfree(priv); - - return 0; } EXPORT_SYMBOL_GPL(i2c_del_mux_adapter); diff --git a/drivers/i2c/muxes/Kconfig b/drivers/i2c/muxes/Kconfig index 0be5b83c08f..5faf244d247 100644 --- a/drivers/i2c/muxes/Kconfig +++ b/drivers/i2c/muxes/Kconfig @@ -5,6 +5,18 @@ menu "Multiplexer I2C Chip support" depends on I2C_MUX +config I2C_ARB_GPIO_CHALLENGE + tristate "GPIO-based I2C arbitration" + depends on GENERIC_GPIO && OF + help + If you say yes to this option, support will be included for an + I2C multimaster arbitration scheme using GPIOs and a challenge & + response mechanism where masters have to claim the bus by asserting + a GPIO. + + This driver can also be built as a module. If so, the module + will be called i2c-arb-gpio-challenge. + config I2C_MUX_GPIO tristate "GPIO-based I2C multiplexer" depends on GENERIC_GPIO diff --git a/drivers/i2c/muxes/Makefile b/drivers/i2c/muxes/Makefile index 76da8692aff..465778b5d5d 100644 --- a/drivers/i2c/muxes/Makefile +++ b/drivers/i2c/muxes/Makefile @@ -1,6 +1,8 @@ # # Makefile for multiplexer I2C chip drivers. +obj-$(CONFIG_I2C_ARB_GPIO_CHALLENGE) += i2c-arb-gpio-challenge.o + obj-$(CONFIG_I2C_MUX_GPIO) += i2c-mux-gpio.o obj-$(CONFIG_I2C_MUX_PCA9541) += i2c-mux-pca9541.o obj-$(CONFIG_I2C_MUX_PCA954x) += i2c-mux-pca954x.o diff --git a/drivers/i2c/muxes/i2c-arb-gpio-challenge.c b/drivers/i2c/muxes/i2c-arb-gpio-challenge.c new file mode 100644 index 00000000000..210b6f7b902 --- /dev/null +++ b/drivers/i2c/muxes/i2c-arb-gpio-challenge.c @@ -0,0 +1,251 @@ +/* + * GPIO-based I2C Arbitration Using a Challenge & Response Mechanism + * + * Copyright (C) 2012 Google, Inc + * + * This software is licensed under the terms of the GNU General Public + * License version 2, as published by the Free Software Foundation, and + * may be copied, distributed, and modified under those terms. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + */ + +#include <linux/delay.h> +#include <linux/gpio.h> +#include <linux/kernel.h> +#include <linux/i2c.h> +#include <linux/i2c-mux.h> +#include <linux/init.h> +#include <linux/module.h> +#include <linux/of_i2c.h> +#include <linux/of_gpio.h> +#include <linux/platform_device.h> +#include <linux/slab.h> + + +/** + * struct i2c_arbitrator_data - Driver data for I2C arbitrator + * + * @parent: Parent adapter + * @child: Child bus + * @our_gpio: GPIO we'll use to claim. + * @our_gpio_release: 0 if active high; 1 if active low; AKA if the GPIO == + * this then consider it released. + * @their_gpio: GPIO that the other side will use to claim. + * @their_gpio_release: 0 if active high; 1 if active low; AKA if the GPIO == + * this then consider it released. + * @slew_delay_us: microseconds to wait for a GPIO to go high. + * @wait_retry_us: we'll attempt another claim after this many microseconds. + * @wait_free_us: we'll give up after this many microseconds. + */ + +struct i2c_arbitrator_data { + struct i2c_adapter *parent; + struct i2c_adapter *child; + int our_gpio; + int our_gpio_release; + int their_gpio; + int their_gpio_release; + unsigned int slew_delay_us; + unsigned int wait_retry_us; + unsigned int wait_free_us; +}; + + +/** + * i2c_arbitrator_select - claim the I2C bus + * + * Use the GPIO-based signalling protocol; return -EBUSY if we fail. + */ +static int i2c_arbitrator_select(struct i2c_adapter *adap, void *data, u32 chan) +{ + const struct i2c_arbitrator_data *arb = data; + unsigned long stop_retry, stop_time; + + /* Start a round of trying to claim the bus */ + stop_time = jiffies + usecs_to_jiffies(arb->wait_free_us) + 1; + do { + /* Indicate that we want to claim the bus */ + gpio_set_value(arb->our_gpio, !arb->our_gpio_release); + udelay(arb->slew_delay_us); + + /* Wait for the other master to release it */ + stop_retry = jiffies + usecs_to_jiffies(arb->wait_retry_us) + 1; + while (time_before(jiffies, stop_retry)) { + int gpio_val = !!gpio_get_value(arb->their_gpio); + + if (gpio_val == arb->their_gpio_release) { + /* We got it, so return */ + return 0; + } + + usleep_range(50, 200); + } + + /* It didn't release, so give up, wait, and try again */ + gpio_set_value(arb->our_gpio, arb->our_gpio_release); + + usleep_range(arb->wait_retry_us, arb->wait_retry_us * 2); + } while (time_before(jiffies, stop_time)); + + /* Give up, release our claim */ + gpio_set_value(arb->our_gpio, arb->our_gpio_release); + udelay(arb->slew_delay_us); + dev_err(&adap->dev, "Could not claim bus, timeout\n"); + return -EBUSY; +} + +/** + * i2c_arbitrator_deselect - release the I2C bus + * + * Release the I2C bus using the GPIO-based signalling protocol. + */ +static int i2c_arbitrator_deselect(struct i2c_adapter *adap, void *data, + u32 chan) +{ + const struct i2c_arbitrator_data *arb = data; + + /* Release the bus and wait for the other master to notice */ + gpio_set_value(arb->our_gpio, arb->our_gpio_release); + udelay(arb->slew_delay_us); + + return 0; +} + +static int i2c_arbitrator_probe(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + struct device_node *np = dev->of_node; + struct device_node *parent_np; + struct i2c_arbitrator_data *arb; + enum of_gpio_flags gpio_flags; + unsigned long out_init; + int ret; + + /* We only support probing from device tree; no platform_data */ + if (!np) { + dev_err(dev, "Cannot find device tree node\n"); + return -ENODEV; + } + if (dev->platform_data) { + dev_err(dev, "Platform data is not supported\n"); + return -EINVAL; + } + + arb = devm_kzalloc(dev, sizeof(*arb), GFP_KERNEL); + if (!arb) { + dev_err(dev, "Cannot allocate i2c_arbitrator_data\n"); + return -ENOMEM; + } + platform_set_drvdata(pdev, arb); + + /* Request GPIOs */ + ret = of_get_named_gpio_flags(np, "our-claim-gpio", 0, &gpio_flags); + if (!gpio_is_valid(ret)) { + if (ret != -EPROBE_DEFER) + dev_err(dev, "Error getting our-claim-gpio\n"); + return ret; + } + arb->our_gpio = ret; + arb->our_gpio_release = !!(gpio_flags & OF_GPIO_ACTIVE_LOW); + out_init = (gpio_flags & OF_GPIO_ACTIVE_LOW) ? + GPIOF_OUT_INIT_HIGH : GPIOF_OUT_INIT_LOW; + ret = devm_gpio_request_one(dev, arb->our_gpio, out_init, + "our-claim-gpio"); + if (ret) { + if (ret != -EPROBE_DEFER) + dev_err(dev, "Error requesting our-claim-gpio\n"); + return ret; + } + + ret = of_get_named_gpio_flags(np, "their-claim-gpios", 0, &gpio_flags); + if (!gpio_is_valid(ret)) { + if (ret != -EPROBE_DEFER) + dev_err(dev, "Error getting their-claim-gpio\n"); + return ret; + } + arb->their_gpio = ret; + arb->their_gpio_release = !!(gpio_flags & OF_GPIO_ACTIVE_LOW); + ret = devm_gpio_request_one(dev, arb->their_gpio, GPIOF_IN, + "their-claim-gpio"); + if (ret) { + if (ret != -EPROBE_DEFER) + dev_err(dev, "Error requesting their-claim-gpio\n"); + return ret; + } + + /* At the moment we only support a single two master (us + 1 other) */ + if (gpio_is_valid(of_get_named_gpio(np, "their-claim-gpios", 1))) { + dev_err(dev, "Only one other master is supported\n"); + return -EINVAL; + } + + /* Arbitration parameters */ + if (of_property_read_u32(np, "slew-delay-us", &arb->slew_delay_us)) + arb->slew_delay_us = 10; + if (of_property_read_u32(np, "wait-retry-us", &arb->wait_retry_us)) + arb->wait_retry_us = 3000; + if (of_property_read_u32(np, "wait-free-us", &arb->wait_free_us)) + arb->wait_free_us = 50000; + + /* Find our parent */ + parent_np = of_parse_phandle(np, "i2c-parent", 0); + if (!parent_np) { + dev_err(dev, "Cannot parse i2c-parent\n"); + return -EINVAL; + } + arb->parent = of_find_i2c_adapter_by_node(parent_np); + if (!arb->parent) { + dev_err(dev, "Cannot find parent bus\n"); + return -EINVAL; + } + + /* Actually add the mux adapter */ + arb->child = i2c_add_mux_adapter(arb->parent, dev, arb, 0, 0, 0, + i2c_arbitrator_select, + i2c_arbitrator_deselect); + if (!arb->child) { + dev_err(dev, "Failed to add adapter\n"); + ret = -ENODEV; + i2c_put_adapter(arb->parent); + } + + return ret; +} + +static int i2c_arbitrator_remove(struct platform_device *pdev) +{ + struct i2c_arbitrator_data *arb = platform_get_drvdata(pdev); + + i2c_del_mux_adapter(arb->child); + i2c_put_adapter(arb->parent); + + return 0; +} + +static const struct of_device_id i2c_arbitrator_of_match[] = { + { .compatible = "i2c-arb-gpio-challenge", }, + {}, +}; +MODULE_DEVICE_TABLE(of, i2c_arbitrator_of_match); + +static struct platform_driver i2c_arbitrator_driver = { + .probe = i2c_arbitrator_probe, + .remove = i2c_arbitrator_remove, + .driver = { + .owner = THIS_MODULE, + .name = "i2c-arb-gpio-challenge", + .of_match_table = of_match_ptr(i2c_arbitrator_of_match), + }, +}; + +module_platform_driver(i2c_arbitrator_driver); + +MODULE_DESCRIPTION("GPIO-based I2C Arbitration"); +MODULE_AUTHOR("Doug Anderson <dianders@chromium.org>"); +MODULE_LICENSE("GPL v2"); +MODULE_ALIAS("platform:i2c-arb-gpio-challenge"); diff --git a/drivers/i2c/muxes/i2c-mux-gpio.c b/drivers/i2c/muxes/i2c-mux-gpio.c index abc2e55aa24..5a0ce0081dc 100644 --- a/drivers/i2c/muxes/i2c-mux-gpio.c +++ b/drivers/i2c/muxes/i2c-mux-gpio.c @@ -201,10 +201,21 @@ static int i2c_mux_gpio_probe(struct platform_device *pdev) for (i = 0; i < mux->data.n_gpios; i++) { ret = gpio_request(gpio_base + mux->data.gpios[i], "i2c-mux-gpio"); - if (ret) + if (ret) { + dev_err(&pdev->dev, "Failed to request GPIO %d\n", + mux->data.gpios[i]); goto err_request_gpio; - gpio_direction_output(gpio_base + mux->data.gpios[i], - initial_state & (1 << i)); + } + + ret = gpio_direction_output(gpio_base + mux->data.gpios[i], + initial_state & (1 << i)); + if (ret) { + dev_err(&pdev->dev, + "Failed to set direction of GPIO %d to output\n", + mux->data.gpios[i]); + i++; /* gpio_request above succeeded, so must free */ + goto err_request_gpio; + } } for (i = 0; i < mux->data.n_values; i++) { diff --git a/drivers/i2c/muxes/i2c-mux-pca954x.c b/drivers/i2c/muxes/i2c-mux-pca954x.c index 8e4387235b6..a531d801dbe 100644 --- a/drivers/i2c/muxes/i2c-mux-pca954x.c +++ b/drivers/i2c/muxes/i2c-mux-pca954x.c @@ -262,13 +262,11 @@ static int pca954x_remove(struct i2c_client *client) { struct pca954x *data = i2c_get_clientdata(client); const struct chip_desc *chip = &chips[data->type]; - int i, err; + int i; for (i = 0; i < chip->nchans; ++i) if (data->virt_adaps[i]) { - err = i2c_del_mux_adapter(data->virt_adaps[i]); - if (err) - return err; + i2c_del_mux_adapter(data->virt_adaps[i]); data->virt_adaps[i] = NULL; } diff --git a/drivers/media/pci/bt8xx/bttv-i2c.c b/drivers/media/pci/bt8xx/bttv-i2c.c index b7c52dc8999..d43911deb61 100644 --- a/drivers/media/pci/bt8xx/bttv-i2c.c +++ b/drivers/media/pci/bt8xx/bttv-i2c.c @@ -397,8 +397,8 @@ int init_bttv_i2c(struct bttv *btv) int fini_bttv_i2c(struct bttv *btv) { - if (0 != btv->i2c_rc) - return 0; + if (btv->i2c_rc == 0) + i2c_del_adapter(&btv->c.i2c_adap); - return i2c_del_adapter(&btv->c.i2c_adap); + return 0; } diff --git a/drivers/media/pci/mantis/mantis_i2c.c b/drivers/media/pci/mantis/mantis_i2c.c index 937fb9d5021..895ddba3c0f 100644 --- a/drivers/media/pci/mantis/mantis_i2c.c +++ b/drivers/media/pci/mantis/mantis_i2c.c @@ -261,6 +261,8 @@ int mantis_i2c_exit(struct mantis_pci *mantis) mmwrite((intmask & ~MANTIS_INT_I2CDONE), MANTIS_INT_MASK); dprintk(MANTIS_DEBUG, 1, "Removing I2C adapter"); - return i2c_del_adapter(&mantis->adapter); + i2c_del_adapter(&mantis->adapter); + + return 0; } EXPORT_SYMBOL_GPL(mantis_i2c_exit); diff --git a/drivers/net/ethernet/sfc/falcon.c b/drivers/net/ethernet/sfc/falcon.c index 4486102fa9b..71998e7995d 100644 --- a/drivers/net/ethernet/sfc/falcon.c +++ b/drivers/net/ethernet/sfc/falcon.c @@ -1528,7 +1528,7 @@ static int falcon_probe_nic(struct efx_nic *efx) return 0; fail6: - BUG_ON(i2c_del_adapter(&board->i2c_adap)); + i2c_del_adapter(&board->i2c_adap); memset(&board->i2c_adap, 0, sizeof(board->i2c_adap)); fail5: efx_nic_free_buffer(efx, &efx->irq_status); @@ -1666,13 +1666,11 @@ static void falcon_remove_nic(struct efx_nic *efx) { struct falcon_nic_data *nic_data = efx->nic_data; struct falcon_board *board = falcon_board(efx); - int rc; board->type->fini(efx); /* Remove I2C adapter and clear it in preparation for a retry */ - rc = i2c_del_adapter(&board->i2c_adap); - BUG_ON(rc); + i2c_del_adapter(&board->i2c_adap); memset(&board->i2c_adap, 0, sizeof(board->i2c_adap)); efx_nic_free_buffer(efx, &efx->irq_status); diff --git a/drivers/staging/media/go7007/go7007-driver.c b/drivers/staging/media/go7007/go7007-driver.c index a5ca99d7c0b..3640df0aa0c 100644 --- a/drivers/staging/media/go7007/go7007-driver.c +++ b/drivers/staging/media/go7007/go7007-driver.c @@ -242,11 +242,8 @@ static void go7007_remove(struct v4l2_device *v4l2_dev) if (go->hpi_ops->release) go->hpi_ops->release(go); if (go->i2c_adapter_online) { - if (i2c_del_adapter(&go->i2c_adapter) == 0) - go->i2c_adapter_online = 0; - else - v4l2_err(&go->v4l2_dev, - "error removing I2C adapter!\n"); + i2c_del_adapter(&go->i2c_adapter); + go->i2c_adapter_online = 0; } kfree(go->boot_fw); diff --git a/include/linux/i2c-mux.h b/include/linux/i2c-mux.h index 40cb05a97b4..b5f9a007a3a 100644 --- a/include/linux/i2c-mux.h +++ b/include/linux/i2c-mux.h @@ -42,7 +42,7 @@ struct i2c_adapter *i2c_add_mux_adapter(struct i2c_adapter *parent, int (*deselect) (struct i2c_adapter *, void *mux_dev, u32 chan_id)); -int i2c_del_mux_adapter(struct i2c_adapter *adap); +void i2c_del_mux_adapter(struct i2c_adapter *adap); #endif /* __KERNEL__ */ diff --git a/include/linux/i2c-tegra.h b/include/linux/i2c-tegra.h deleted file mode 100644 index 9c85da49857..00000000000 --- a/include/linux/i2c-tegra.h +++ /dev/null @@ -1,25 +0,0 @@ -/* - * drivers/i2c/busses/i2c-tegra.c - * - * Copyright (C) 2010 Google, Inc. - * Author: Colin Cross <ccross@android.com> - * - * This software is licensed under the terms of the GNU General Public - * License version 2, as published by the Free Software Foundation, and - * may be copied, distributed, and modified under those terms. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - */ - -#ifndef _LINUX_I2C_TEGRA_H -#define _LINUX_I2C_TEGRA_H - -struct tegra_i2c_platform_data { - unsigned long bus_clk_rate; -}; - -#endif /* _LINUX_I2C_TEGRA_H */ diff --git a/include/linux/i2c.h b/include/linux/i2c.h index d0c4db7b487..e988fa935b3 100644 --- a/include/linux/i2c.h +++ b/include/linux/i2c.h @@ -125,7 +125,6 @@ extern s32 i2c_smbus_write_i2c_block_data(const struct i2c_client *client, * struct i2c_driver - represent an I2C device driver * @class: What kind of i2c device we instantiate (for detect) * @attach_adapter: Callback for bus addition (deprecated) - * @detach_adapter: Callback for bus removal (deprecated) * @probe: Callback for device binding * @remove: Callback for device unbinding * @shutdown: Callback for device shutdown @@ -162,12 +161,10 @@ extern s32 i2c_smbus_write_i2c_block_data(const struct i2c_client *client, struct i2c_driver { unsigned int class; - /* Notifies the driver that a new bus has appeared or is about to be - * removed. You should avoid using this, it will be removed in a - * near future. + /* Notifies the driver that a new bus has appeared. You should avoid + * using this, it will be removed in a near future. */ int (*attach_adapter)(struct i2c_adapter *) __deprecated; - int (*detach_adapter)(struct i2c_adapter *) __deprecated; /* Standard driver model interfaces */ int (*probe)(struct i2c_client *, const struct i2c_device_id *); @@ -370,6 +367,45 @@ struct i2c_algorithm { u32 (*functionality) (struct i2c_adapter *); }; +/** + * struct i2c_bus_recovery_info - I2C bus recovery information + * @recover_bus: Recover routine. Either pass driver's recover_bus() routine, or + * i2c_generic_scl_recovery() or i2c_generic_gpio_recovery(). + * @get_scl: This gets current value of SCL line. Mandatory for generic SCL + * recovery. Used internally for generic GPIO recovery. + * @set_scl: This sets/clears SCL line. Mandatory for generic SCL recovery. Used + * internally for generic GPIO recovery. + * @get_sda: This gets current value of SDA line. Optional for generic SCL + * recovery. Used internally, if sda_gpio is a valid GPIO, for generic GPIO + * recovery. + * @prepare_recovery: This will be called before starting recovery. Platform may + * configure padmux here for SDA/SCL line or something else they want. + * @unprepare_recovery: This will be called after completing recovery. Platform + * may configure padmux here for SDA/SCL line or something else they want. + * @scl_gpio: gpio number of the SCL line. Only required for GPIO recovery. + * @sda_gpio: gpio number of the SDA line. Only required for GPIO recovery. + */ +struct i2c_bus_recovery_info { + int (*recover_bus)(struct i2c_adapter *); + + int (*get_scl)(struct i2c_adapter *); + void (*set_scl)(struct i2c_adapter *, int val); + int (*get_sda)(struct i2c_adapter *); + + void (*prepare_recovery)(struct i2c_bus_recovery_info *bri); + void (*unprepare_recovery)(struct i2c_bus_recovery_info *bri); + + /* gpio recovery */ + int scl_gpio; + int sda_gpio; +}; + +int i2c_recover_bus(struct i2c_adapter *adap); + +/* Generic recovery routines */ +int i2c_generic_gpio_recovery(struct i2c_adapter *adap); +int i2c_generic_scl_recovery(struct i2c_adapter *adap); + /* * i2c_adapter is the structure used to identify a physical i2c bus along * with the access algorithms necessary to access it. @@ -393,6 +429,8 @@ struct i2c_adapter { struct mutex userspace_clients_lock; struct list_head userspace_clients; + + struct i2c_bus_recovery_info *bus_recovery_info; }; #define to_i2c_adapter(d) container_of(d, struct i2c_adapter, dev) @@ -450,7 +488,7 @@ void i2c_unlock_adapter(struct i2c_adapter *); */ #if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) extern int i2c_add_adapter(struct i2c_adapter *); -extern int i2c_del_adapter(struct i2c_adapter *); +extern void i2c_del_adapter(struct i2c_adapter *); extern int i2c_add_numbered_adapter(struct i2c_adapter *); extern int i2c_register_driver(struct module *, struct i2c_driver *); |