mirror of
https://github.com/torvalds/linux.git
synced 2024-11-26 14:12:06 +00:00
Merge branch 'i2c/for-next' of git://git.kernel.org/pub/scm/linux/kernel/git/wsa/linux
Pull i2c changes from Wolfram Sang: - an arbitration driver. While the driver is quite simple, it caused discussion if we need additional arbitration on top of the one specified in the I2C standard. Conclusion is that I accept a few generic mechanisms, but not very specific ones. - the core lost the detach_adapter() call. It has no users anymore and was in the way for other cleanups. attach_adapter() is sadly still there since there are users waiting to be converted. - the core gained a bus recovery infrastructure. I2C defines a way to recover if the data line is stalled. This mechanism is now in the core and drivers can now pass some data to make use of it. - bigger driver cleanups for designware, s3c2410 - removing superfluous refcounting from drivers - removing Ben Dooks as second maintainer due to inactivity. Thanks for all your work so far, Ben! - bugfixes, feature additions, devicetree fixups, simplifications... * 'i2c/for-next' of git://git.kernel.org/pub/scm/linux/kernel/git/wsa/linux: (38 commits) i2c: xiic: must always write 16-bit words to TX_FIFO i2c: octeon: use HZ in timeout value i2c: octeon: Fix i2c fail problem when a process is terminated by a signal i2c: designware-pci: drop superfluous {get|put}_device i2c: designware-plat: drop superfluous {get|put}_device i2c: davinci: drop superfluous {get|put}_device MAINTAINERS: Ben Dooks is inactive regarding I2C i2c: mux: Add i2c-arb-gpio-challenge 'mux' driver i2c: at91: convert to dma_request_slave_channel_compat() i2c: mxs: do error checking and handling in PIO mode i2c: mxs: remove races in PIO code i2c-designware: switch to use runtime PM autosuspend i2c-designware: use usleep_range() in the busy-loop i2c-designware: enable/disable the controller properly i2c-designware: use dynamic adapter numbering on Lynxpoint i2c-designware-pci: use managed functions pcim_* and devm_* i2c-designware-pci: use dev_err() instead of printk() i2c-designware: move to managed functions (devm_*) i2c: remove CONFIG_HOTPLUG ifdefs i2c: s3c2410: Add SMBus emulation for block read ...
This commit is contained in:
commit
99bece775f
@ -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
|
||||
};
|
||||
};
|
||||
};
|
@ -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
|
||||
|
@ -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"
|
||||
|
@ -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>
|
||||
|
@ -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>
|
||||
|
@ -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 */
|
@ -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);
|
||||
|
@ -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 */
|
||||
|
@ -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->dma_dev == chan->device->dev) {
|
||||
if (!sl_pdata)
|
||||
return false;
|
||||
|
||||
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,
|
||||
},
|
||||
};
|
||||
|
@ -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)
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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);
|
||||
|
@ -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 */
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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);
|
||||
|
@ -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) },
|
||||
|
@ -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[] = {
|
||||
|
@ -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);
|
||||
|
@ -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 */
|
||||
|
@ -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,
|
||||
};
|
||||
|
||||
/**
|
||||
|
@ -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;
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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 */
|
||||
|
@ -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,
|
||||
},
|
||||
};
|
||||
|
@ -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 = {
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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);
|
||||
@ -920,14 +1074,36 @@ out_list:
|
||||
return res;
|
||||
}
|
||||
|
||||
/**
|
||||
* __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;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
251
drivers/i2c/muxes/i2c-arb-gpio-challenge.c
Normal file
251
drivers/i2c/muxes/i2c-arb-gpio-challenge.c
Normal file
@ -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");
|
@ -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++) {
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
|
@ -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__ */
|
||||
|
||||
|
@ -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 */
|
@ -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 *);
|
||||
|
Loading…
Reference in New Issue
Block a user