diff options
Diffstat (limited to 'drivers/i2c')
-rw-r--r-- | drivers/i2c/algos/i2c-algo-pca.c | 6 | ||||
-rw-r--r-- | drivers/i2c/busses/Kconfig | 8 | ||||
-rw-r--r-- | drivers/i2c/busses/Makefile | 5 | ||||
-rw-r--r-- | drivers/i2c/busses/i2c-designware-core.c | 11 | ||||
-rw-r--r-- | drivers/i2c/busses/i2c-i801.c | 3 | ||||
-rw-r--r-- | drivers/i2c/busses/i2c-iop3xx.c | 121 | ||||
-rw-r--r-- | drivers/i2c/busses/i2c-mxs.c | 13 | ||||
-rw-r--r-- | drivers/i2c/busses/i2c-pnx.c | 53 | ||||
-rw-r--r-- | drivers/i2c/i2c-core.c | 22 |
9 files changed, 145 insertions, 97 deletions
diff --git a/drivers/i2c/algos/i2c-algo-pca.c b/drivers/i2c/algos/i2c-algo-pca.c index 73133b1063f..6f5f98d69af 100644 --- a/drivers/i2c/algos/i2c-algo-pca.c +++ b/drivers/i2c/algos/i2c-algo-pca.c @@ -476,17 +476,17 @@ static int pca_init(struct i2c_adapter *adap) /* To avoid integer overflow, use clock/100 for calculations */ clock = pca_clock(pca_data) / 100; - if (pca_data->i2c_clock > 10000) { + if (pca_data->i2c_clock > 1000000) { mode = I2C_PCA_MODE_TURBO; min_tlow = 14; min_thi = 5; raise_fall_time = 22; /* Raise 11e-8s, Fall 11e-8s */ - } else if (pca_data->i2c_clock > 4000) { + } else if (pca_data->i2c_clock > 400000) { mode = I2C_PCA_MODE_FASTP; min_tlow = 17; min_thi = 9; raise_fall_time = 22; /* Raise 11e-8s, Fall 11e-8s */ - } else if (pca_data->i2c_clock > 1000) { + } else if (pca_data->i2c_clock > 100000) { mode = I2C_PCA_MODE_FAST; min_tlow = 44; min_thi = 20; diff --git a/drivers/i2c/busses/Kconfig b/drivers/i2c/busses/Kconfig index b4aaa1bd672..42d9fdd63de 100644 --- a/drivers/i2c/busses/Kconfig +++ b/drivers/i2c/busses/Kconfig @@ -104,6 +104,7 @@ config I2C_I801 DH89xxCC (PCH) Panther Point (PCH) Lynx Point (PCH) + Lynx Point-LP (PCH) This driver can also be built as a module. If so, the module will be called i2c-i801. @@ -354,9 +355,13 @@ config I2C_DAVINCI devices such as DaVinci NIC. For details please see http://www.ti.com/davinci +config I2C_DESIGNWARE_CORE + tristate + config I2C_DESIGNWARE_PLATFORM tristate "Synopsys DesignWare Platform" depends on HAVE_CLK + select I2C_DESIGNWARE_CORE help If you say yes to this option, support will be included for the Synopsys DesignWare I2C adapter. Only master mode is supported. @@ -367,6 +372,7 @@ config I2C_DESIGNWARE_PLATFORM config I2C_DESIGNWARE_PCI tristate "Synopsys DesignWare PCI" depends on PCI + select I2C_DESIGNWARE_CORE help If you say yes to this option, support will be included for the Synopsys DesignWare I2C adapter. Only master mode is supported. @@ -545,7 +551,7 @@ config I2C_PMCMSP config I2C_PNX tristate "I2C bus support for Philips PNX and NXP LPC targets" - depends on ARCH_PNX4008 || ARCH_LPC32XX + depends on ARCH_LPC32XX help This driver supports the Philips IP3204 I2C IP block master and/or slave controller diff --git a/drivers/i2c/busses/Makefile b/drivers/i2c/busses/Makefile index ce3c2be7fb4..37c4182cc98 100644 --- a/drivers/i2c/busses/Makefile +++ b/drivers/i2c/busses/Makefile @@ -33,10 +33,11 @@ obj-$(CONFIG_I2C_AU1550) += i2c-au1550.o obj-$(CONFIG_I2C_BLACKFIN_TWI) += i2c-bfin-twi.o obj-$(CONFIG_I2C_CPM) += i2c-cpm.o obj-$(CONFIG_I2C_DAVINCI) += i2c-davinci.o +obj-$(CONFIG_I2C_DESIGNWARE_CORE) += i2c-designware-core.o obj-$(CONFIG_I2C_DESIGNWARE_PLATFORM) += i2c-designware-platform.o -i2c-designware-platform-objs := i2c-designware-platdrv.o i2c-designware-core.o +i2c-designware-platform-objs := i2c-designware-platdrv.o obj-$(CONFIG_I2C_DESIGNWARE_PCI) += i2c-designware-pci.o -i2c-designware-pci-objs := i2c-designware-pcidrv.o i2c-designware-core.o +i2c-designware-pci-objs := i2c-designware-pcidrv.o obj-$(CONFIG_I2C_EG20T) += i2c-eg20t.o obj-$(CONFIG_I2C_GPIO) += i2c-gpio.o obj-$(CONFIG_I2C_HIGHLANDER) += i2c-highlander.o diff --git a/drivers/i2c/busses/i2c-designware-core.c b/drivers/i2c/busses/i2c-designware-core.c index 1e48bec80ed..7b8ebbefb58 100644 --- a/drivers/i2c/busses/i2c-designware-core.c +++ b/drivers/i2c/busses/i2c-designware-core.c @@ -25,6 +25,7 @@ * ---------------------------------------------------------------------------- * */ +#include <linux/export.h> #include <linux/clk.h> #include <linux/errno.h> #include <linux/err.h> @@ -316,6 +317,7 @@ int i2c_dw_init(struct dw_i2c_dev *dev) dw_writel(dev, dev->master_cfg , DW_IC_CON); return 0; } +EXPORT_SYMBOL_GPL(i2c_dw_init); /* * Waiting for bus not busy @@ -568,12 +570,14 @@ done: return ret; } +EXPORT_SYMBOL_GPL(i2c_dw_xfer); u32 i2c_dw_func(struct i2c_adapter *adap) { struct dw_i2c_dev *dev = i2c_get_adapdata(adap); return dev->functionality; } +EXPORT_SYMBOL_GPL(i2c_dw_func); static u32 i2c_dw_read_clear_intrbits(struct dw_i2c_dev *dev) { @@ -678,17 +682,20 @@ tx_aborted: return IRQ_HANDLED; } +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); } +EXPORT_SYMBOL_GPL(i2c_dw_enable); u32 i2c_dw_is_enabled(struct dw_i2c_dev *dev) { return dw_readl(dev, DW_IC_ENABLE); } +EXPORT_SYMBOL_GPL(i2c_dw_is_enabled); void i2c_dw_disable(struct dw_i2c_dev *dev) { @@ -699,18 +706,22 @@ void i2c_dw_disable(struct dw_i2c_dev *dev) dw_writel(dev, 0, DW_IC_INTR_MASK); dw_readl(dev, DW_IC_CLR_INTR); } +EXPORT_SYMBOL_GPL(i2c_dw_disable); void i2c_dw_clear_int(struct dw_i2c_dev *dev) { dw_readl(dev, DW_IC_CLR_INTR); } +EXPORT_SYMBOL_GPL(i2c_dw_clear_int); void i2c_dw_disable_int(struct dw_i2c_dev *dev) { dw_writel(dev, 0, DW_IC_INTR_MASK); } +EXPORT_SYMBOL_GPL(i2c_dw_disable_int); u32 i2c_dw_read_comp_param(struct dw_i2c_dev *dev) { return dw_readl(dev, DW_IC_COMP_PARAM_1); } +EXPORT_SYMBOL_GPL(i2c_dw_read_comp_param); diff --git a/drivers/i2c/busses/i2c-i801.c b/drivers/i2c/busses/i2c-i801.c index 898dcf9c7ad..33e9b0c09af 100644 --- a/drivers/i2c/busses/i2c-i801.c +++ b/drivers/i2c/busses/i2c-i801.c @@ -52,6 +52,7 @@ DH89xxCC (PCH) 0x2330 32 hard yes yes yes Panther Point (PCH) 0x1e22 32 hard yes yes yes Lynx Point (PCH) 0x8c22 32 hard yes yes yes + Lynx Point-LP (PCH) 0x9c22 32 hard yes yes yes Features supported by this driver: Software PEC no @@ -155,6 +156,7 @@ #define PCI_DEVICE_ID_INTEL_DH89XXCC_SMBUS 0x2330 #define PCI_DEVICE_ID_INTEL_5_3400_SERIES_SMBUS 0x3b30 #define PCI_DEVICE_ID_INTEL_LYNXPOINT_SMBUS 0x8c22 +#define PCI_DEVICE_ID_INTEL_LYNXPOINT_LP_SMBUS 0x9c22 struct i801_priv { struct i2c_adapter adapter; @@ -771,6 +773,7 @@ static DEFINE_PCI_DEVICE_TABLE(i801_ids) = { { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_DH89XXCC_SMBUS) }, { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_PANTHERPOINT_SMBUS) }, { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_LYNXPOINT_SMBUS) }, + { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_LYNXPOINT_LP_SMBUS) }, { 0, } }; diff --git a/drivers/i2c/busses/i2c-iop3xx.c b/drivers/i2c/busses/i2c-iop3xx.c index 93f147a96b6..2f99613fd67 100644 --- a/drivers/i2c/busses/i2c-iop3xx.c +++ b/drivers/i2c/busses/i2c-iop3xx.c @@ -4,13 +4,13 @@ /* Copyright (C) 2003 Peter Milne, D-TACQ Solutions Ltd * <Peter dot Milne at D hyphen TACQ dot com> * - * With acknowledgements to i2c-algo-ibm_ocp.c by + * With acknowledgements to i2c-algo-ibm_ocp.c by * Ian DaSilva, MontaVista Software, Inc. idasilva@mvista.com * * And i2c-algo-pcf.c, which was created by Simon G. Vogl and Hans Berglund: * * Copyright (C) 1995-1997 Simon G. Vogl, 1998-2000 Hans Berglund - * + * * And which acknowledged Kyösti Mälkki <kmalkki@cc.hut.fi>, * Frodo Looijaard <frodol@dds.nl>, Martin Bailey<mbailey@littlefeet-inc.com> * @@ -39,14 +39,15 @@ #include <linux/platform_device.h> #include <linux/i2c.h> #include <linux/io.h> +#include <linux/gpio.h> #include "i2c-iop3xx.h" /* global unit counter */ static int i2c_id; -static inline unsigned char -iic_cook_addr(struct i2c_msg *msg) +static inline unsigned char +iic_cook_addr(struct i2c_msg *msg) { unsigned char addr; @@ -55,38 +56,38 @@ iic_cook_addr(struct i2c_msg *msg) if (msg->flags & I2C_M_RD) addr |= 1; - return addr; + return addr; } -static void +static void iop3xx_i2c_reset(struct i2c_algo_iop3xx_data *iop3xx_adap) { /* Follows devman 9.3 */ __raw_writel(IOP3XX_ICR_UNIT_RESET, iop3xx_adap->ioaddr + CR_OFFSET); __raw_writel(IOP3XX_ISR_CLEARBITS, iop3xx_adap->ioaddr + SR_OFFSET); __raw_writel(0, iop3xx_adap->ioaddr + CR_OFFSET); -} +} -static void +static void iop3xx_i2c_enable(struct i2c_algo_iop3xx_data *iop3xx_adap) { u32 cr = IOP3XX_ICR_GCD | IOP3XX_ICR_SCLEN | IOP3XX_ICR_UE; - /* + /* * Every time unit enable is asserted, GPOD needs to be cleared * on IOP3XX to avoid data corruption on the bus. */ #if defined(CONFIG_ARCH_IOP32X) || defined(CONFIG_ARCH_IOP33X) if (iop3xx_adap->id == 0) { - gpio_line_set(IOP3XX_GPIO_LINE(7), GPIO_LOW); - gpio_line_set(IOP3XX_GPIO_LINE(6), GPIO_LOW); + gpio_set_value(7, 0); + gpio_set_value(6, 0); } else { - gpio_line_set(IOP3XX_GPIO_LINE(5), GPIO_LOW); - gpio_line_set(IOP3XX_GPIO_LINE(4), GPIO_LOW); + gpio_set_value(5, 0); + gpio_set_value(4, 0); } #endif /* NB SR bits not same position as CR IE bits :-( */ - iop3xx_adap->SR_enabled = + iop3xx_adap->SR_enabled = IOP3XX_ISR_ALD | IOP3XX_ISR_BERRD | IOP3XX_ISR_RXFULL | IOP3XX_ISR_TXEMPTY; @@ -96,23 +97,23 @@ iop3xx_i2c_enable(struct i2c_algo_iop3xx_data *iop3xx_adap) __raw_writel(cr, iop3xx_adap->ioaddr + CR_OFFSET); } -static void +static void iop3xx_i2c_transaction_cleanup(struct i2c_algo_iop3xx_data *iop3xx_adap) { unsigned long cr = __raw_readl(iop3xx_adap->ioaddr + CR_OFFSET); - - cr &= ~(IOP3XX_ICR_MSTART | IOP3XX_ICR_TBYTE | + + cr &= ~(IOP3XX_ICR_MSTART | IOP3XX_ICR_TBYTE | IOP3XX_ICR_MSTOP | IOP3XX_ICR_SCLEN); __raw_writel(cr, iop3xx_adap->ioaddr + CR_OFFSET); } -/* - * NB: the handler has to clear the source of the interrupt! +/* + * NB: the handler has to clear the source of the interrupt! * Then it passes the SR flags of interest to BH via adap data */ -static irqreturn_t -iop3xx_i2c_irq_handler(int this_irq, void *dev_id) +static irqreturn_t +iop3xx_i2c_irq_handler(int this_irq, void *dev_id) { struct i2c_algo_iop3xx_data *iop3xx_adap = dev_id; u32 sr = __raw_readl(iop3xx_adap->ioaddr + SR_OFFSET); @@ -126,7 +127,7 @@ iop3xx_i2c_irq_handler(int this_irq, void *dev_id) } /* check all error conditions, clear them , report most important */ -static int +static int iop3xx_i2c_error(u32 sr) { int rc = 0; @@ -135,12 +136,12 @@ iop3xx_i2c_error(u32 sr) if ( !rc ) rc = -I2C_ERR_BERR; } if ((sr & IOP3XX_ISR_ALD)) { - if ( !rc ) rc = -I2C_ERR_ALD; + if ( !rc ) rc = -I2C_ERR_ALD; } - return rc; + return rc; } -static inline u32 +static inline u32 iop3xx_i2c_get_srstat(struct i2c_algo_iop3xx_data *iop3xx_adap) { unsigned long flags; @@ -161,8 +162,8 @@ iop3xx_i2c_get_srstat(struct i2c_algo_iop3xx_data *iop3xx_adap) typedef int (* compare_func)(unsigned test, unsigned mask); /* returns 1 on correct comparison */ -static int -iop3xx_i2c_wait_event(struct i2c_algo_iop3xx_data *iop3xx_adap, +static int +iop3xx_i2c_wait_event(struct i2c_algo_iop3xx_data *iop3xx_adap, unsigned flags, unsigned* status, compare_func compare) { @@ -192,47 +193,47 @@ iop3xx_i2c_wait_event(struct i2c_algo_iop3xx_data *iop3xx_adap, } /* - * Concrete compare_funcs + * Concrete compare_funcs */ -static int +static int all_bits_clear(unsigned test, unsigned mask) { return (test & mask) == 0; } -static int +static int any_bits_set(unsigned test, unsigned mask) { return (test & mask) != 0; } -static int +static int iop3xx_i2c_wait_tx_done(struct i2c_algo_iop3xx_data *iop3xx_adap, int *status) { - return iop3xx_i2c_wait_event( - iop3xx_adap, + return iop3xx_i2c_wait_event( + iop3xx_adap, IOP3XX_ISR_TXEMPTY | IOP3XX_ISR_ALD | IOP3XX_ISR_BERRD, status, any_bits_set); } -static int +static int iop3xx_i2c_wait_rx_done(struct i2c_algo_iop3xx_data *iop3xx_adap, int *status) { - return iop3xx_i2c_wait_event( - iop3xx_adap, + return iop3xx_i2c_wait_event( + iop3xx_adap, IOP3XX_ISR_RXFULL | IOP3XX_ISR_ALD | IOP3XX_ISR_BERRD, status, any_bits_set); } -static int +static int iop3xx_i2c_wait_idle(struct i2c_algo_iop3xx_data *iop3xx_adap, int *status) { - return iop3xx_i2c_wait_event( + return iop3xx_i2c_wait_event( iop3xx_adap, IOP3XX_ISR_UNITBUSY, status, all_bits_clear); } -static int -iop3xx_i2c_send_target_addr(struct i2c_algo_iop3xx_data *iop3xx_adap, +static int +iop3xx_i2c_send_target_addr(struct i2c_algo_iop3xx_data *iop3xx_adap, struct i2c_msg* msg) { unsigned long cr = __raw_readl(iop3xx_adap->ioaddr + CR_OFFSET); @@ -247,7 +248,7 @@ iop3xx_i2c_send_target_addr(struct i2c_algo_iop3xx_data *iop3xx_adap, } __raw_writel(iic_cook_addr(msg), iop3xx_adap->ioaddr + DBR_OFFSET); - + cr &= ~(IOP3XX_ICR_MSTOP | IOP3XX_ICR_NACK); cr |= IOP3XX_ICR_MSTART | IOP3XX_ICR_TBYTE; @@ -257,8 +258,8 @@ iop3xx_i2c_send_target_addr(struct i2c_algo_iop3xx_data *iop3xx_adap, return rc; } -static int -iop3xx_i2c_write_byte(struct i2c_algo_iop3xx_data *iop3xx_adap, char byte, +static int +iop3xx_i2c_write_byte(struct i2c_algo_iop3xx_data *iop3xx_adap, char byte, int stop) { unsigned long cr = __raw_readl(iop3xx_adap->ioaddr + CR_OFFSET); @@ -277,10 +278,10 @@ iop3xx_i2c_write_byte(struct i2c_algo_iop3xx_data *iop3xx_adap, char byte, rc = iop3xx_i2c_wait_tx_done(iop3xx_adap, &status); return rc; -} +} -static int -iop3xx_i2c_read_byte(struct i2c_algo_iop3xx_data *iop3xx_adap, char* byte, +static int +iop3xx_i2c_read_byte(struct i2c_algo_iop3xx_data *iop3xx_adap, char* byte, int stop) { unsigned long cr = __raw_readl(iop3xx_adap->ioaddr + CR_OFFSET); @@ -304,19 +305,19 @@ iop3xx_i2c_read_byte(struct i2c_algo_iop3xx_data *iop3xx_adap, char* byte, return rc; } -static int +static int iop3xx_i2c_writebytes(struct i2c_adapter *i2c_adap, const char *buf, int count) { struct i2c_algo_iop3xx_data *iop3xx_adap = i2c_adap->algo_data; int ii; int rc = 0; - for (ii = 0; rc == 0 && ii != count; ++ii) + for (ii = 0; rc == 0 && ii != count; ++ii) rc = iop3xx_i2c_write_byte(iop3xx_adap, buf[ii], ii==count-1); return rc; } -static int +static int iop3xx_i2c_readbytes(struct i2c_adapter *i2c_adap, char *buf, int count) { struct i2c_algo_iop3xx_data *iop3xx_adap = i2c_adap->algo_data; @@ -325,7 +326,7 @@ iop3xx_i2c_readbytes(struct i2c_adapter *i2c_adap, char *buf, int count) for (ii = 0; rc == 0 && ii != count; ++ii) rc = iop3xx_i2c_read_byte(iop3xx_adap, &buf[ii], ii==count-1); - + return rc; } @@ -336,8 +337,8 @@ iop3xx_i2c_readbytes(struct i2c_adapter *i2c_adap, char *buf, int count) * Each transfer (i.e. a read or a write) is separated by a repeated start * condition. */ -static int -iop3xx_i2c_handle_msg(struct i2c_adapter *i2c_adap, struct i2c_msg* pmsg) +static int +iop3xx_i2c_handle_msg(struct i2c_adapter *i2c_adap, struct i2c_msg* pmsg) { struct i2c_algo_iop3xx_data *iop3xx_adap = i2c_adap->algo_data; int rc; @@ -357,8 +358,8 @@ iop3xx_i2c_handle_msg(struct i2c_adapter *i2c_adap, struct i2c_msg* pmsg) /* * master_xfer() - main read/write entry */ -static int -iop3xx_i2c_master_xfer(struct i2c_adapter *i2c_adap, struct i2c_msg *msgs, +static int +iop3xx_i2c_master_xfer(struct i2c_adapter *i2c_adap, struct i2c_msg *msgs, int num) { struct i2c_algo_iop3xx_data *iop3xx_adap = i2c_adap->algo_data; @@ -375,14 +376,14 @@ iop3xx_i2c_master_xfer(struct i2c_adapter *i2c_adap, struct i2c_msg *msgs, } iop3xx_i2c_transaction_cleanup(iop3xx_adap); - + if(ret) return ret; - return im; + return im; } -static u32 +static u32 iop3xx_i2c_func(struct i2c_adapter *adap) { return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL; @@ -393,11 +394,11 @@ static const struct i2c_algorithm iop3xx_i2c_algo = { .functionality = iop3xx_i2c_func, }; -static int +static int iop3xx_i2c_remove(struct platform_device *pdev) { struct i2c_adapter *padapter = platform_get_drvdata(pdev); - struct i2c_algo_iop3xx_data *adapter_data = + struct i2c_algo_iop3xx_data *adapter_data = (struct i2c_algo_iop3xx_data *)padapter->algo_data; struct resource *res = platform_get_resource(pdev, IORESOURCE_MEM, 0); unsigned long cr = __raw_readl(adapter_data->ioaddr + CR_OFFSET); @@ -419,7 +420,7 @@ iop3xx_i2c_remove(struct platform_device *pdev) return 0; } -static int +static int iop3xx_i2c_probe(struct platform_device *pdev) { struct resource *res; diff --git a/drivers/i2c/busses/i2c-mxs.c b/drivers/i2c/busses/i2c-mxs.c index 088c5c1ed17..51f05b8520e 100644 --- a/drivers/i2c/busses/i2c-mxs.c +++ b/drivers/i2c/busses/i2c-mxs.c @@ -365,10 +365,6 @@ static int mxs_i2c_get_ofdata(struct mxs_i2c_dev *i2c) struct device_node *node = dev->of_node; int ret; - if (!node) - return -EINVAL; - - i2c->speed = &mxs_i2c_95kHz_config; ret = of_property_read_u32(node, "clock-frequency", &speed); if (ret) dev_warn(dev, "No I2C speed selected, using 100kHz\n"); @@ -419,10 +415,13 @@ static int __devinit mxs_i2c_probe(struct platform_device *pdev) return err; i2c->dev = dev; + i2c->speed = &mxs_i2c_95kHz_config; - err = mxs_i2c_get_ofdata(i2c); - if (err) - return err; + if (dev->of_node) { + err = mxs_i2c_get_ofdata(i2c); + if (err) + return err; + } platform_set_drvdata(pdev, i2c); diff --git a/drivers/i2c/busses/i2c-pnx.c b/drivers/i2c/busses/i2c-pnx.c index 5d54416770b..8488bddfe46 100644 --- a/drivers/i2c/busses/i2c-pnx.c +++ b/drivers/i2c/busses/i2c-pnx.c @@ -48,8 +48,9 @@ enum { mcntrl_afie = 0x00000002, mcntrl_naie = 0x00000004, mcntrl_drmie = 0x00000008, - mcntrl_daie = 0x00000020, - mcntrl_rffie = 0x00000040, + mcntrl_drsie = 0x00000010, + mcntrl_rffie = 0x00000020, + mcntrl_daie = 0x00000040, mcntrl_tffie = 0x00000080, mcntrl_reset = 0x00000100, mcntrl_cdbmode = 0x00000400, @@ -290,31 +291,37 @@ static int i2c_pnx_master_rcv(struct i2c_pnx_algo_data *alg_data) * or we didn't 'ask' for it yet. */ if (ioread32(I2C_REG_STS(alg_data)) & mstatus_rfe) { - dev_dbg(&alg_data->adapter.dev, - "%s(): Write dummy data to fill Rx-fifo...\n", - __func__); + /* 'Asking' is done asynchronously, e.g. dummy TX of several + * bytes is done before the first actual RX arrives in FIFO. + * Therefore, ordered bytes (via TX) are counted separately. + */ + if (alg_data->mif.order) { + dev_dbg(&alg_data->adapter.dev, + "%s(): Write dummy data to fill Rx-fifo...\n", + __func__); - if (alg_data->mif.len == 1) { - /* Last byte, do not acknowledge next rcv. */ - val |= stop_bit; + if (alg_data->mif.order == 1) { + /* Last byte, do not acknowledge next rcv. */ + val |= stop_bit; + + /* + * Enable interrupt RFDAIE (data in Rx fifo), + * and disable DRMIE (need data for Tx) + */ + ctl = ioread32(I2C_REG_CTL(alg_data)); + ctl |= mcntrl_rffie | mcntrl_daie; + ctl &= ~mcntrl_drmie; + iowrite32(ctl, I2C_REG_CTL(alg_data)); + } /* - * Enable interrupt RFDAIE (data in Rx fifo), - * and disable DRMIE (need data for Tx) + * Now we'll 'ask' for data: + * For each byte we want to receive, we must + * write a (dummy) byte to the Tx-FIFO. */ - ctl = ioread32(I2C_REG_CTL(alg_data)); - ctl |= mcntrl_rffie | mcntrl_daie; - ctl &= ~mcntrl_drmie; - iowrite32(ctl, I2C_REG_CTL(alg_data)); + iowrite32(val, I2C_REG_TX(alg_data)); + alg_data->mif.order--; } - - /* - * Now we'll 'ask' for data: - * For each byte we want to receive, we must - * write a (dummy) byte to the Tx-FIFO. - */ - iowrite32(val, I2C_REG_TX(alg_data)); - return 0; } @@ -514,6 +521,7 @@ i2c_pnx_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs, int num) alg_data->mif.buf = pmsg->buf; alg_data->mif.len = pmsg->len; + alg_data->mif.order = pmsg->len; alg_data->mif.mode = (pmsg->flags & I2C_M_RD) ? I2C_SMBUS_READ : I2C_SMBUS_WRITE; alg_data->mif.ret = 0; @@ -566,6 +574,7 @@ i2c_pnx_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs, int num) /* Cleanup to be sure... */ alg_data->mif.buf = NULL; alg_data->mif.len = 0; + alg_data->mif.order = 0; dev_dbg(&alg_data->adapter.dev, "%s(): exiting, stat = %x\n", __func__, ioread32(I2C_REG_STS(alg_data))); diff --git a/drivers/i2c/i2c-core.c b/drivers/i2c/i2c-core.c index 2efa56c5ff2..2091ae8f539 100644 --- a/drivers/i2c/i2c-core.c +++ b/drivers/i2c/i2c-core.c @@ -637,6 +637,22 @@ static void i2c_adapter_dev_release(struct device *dev) } /* + * This function is only needed for mutex_lock_nested, so it is never + * called unless locking correctness checking is enabled. Thus we + * make it inline to avoid a compiler warning. That's what gcc ends up + * doing anyway. + */ +static inline unsigned int i2c_adapter_depth(struct i2c_adapter *adapter) +{ + unsigned int depth = 0; + + while ((adapter = i2c_parent_is_i2c_adapter(adapter))) + depth++; + + return depth; +} + +/* * Let users instantiate I2C devices through sysfs. This can be used when * platform initialization code doesn't contain the proper data for * whatever reason. Also useful for drivers that do device detection and @@ -726,7 +742,8 @@ i2c_sysfs_delete_device(struct device *dev, struct device_attribute *attr, /* Make sure the device was added through sysfs */ res = -ENOENT; - mutex_lock(&adap->userspace_clients_lock); + mutex_lock_nested(&adap->userspace_clients_lock, + i2c_adapter_depth(adap)); list_for_each_entry_safe(client, next, &adap->userspace_clients, detected) { if (client->addr == addr) { @@ -1073,7 +1090,8 @@ int i2c_del_adapter(struct i2c_adapter *adap) return res; /* Remove devices instantiated from sysfs */ - mutex_lock(&adap->userspace_clients_lock); + mutex_lock_nested(&adap->userspace_clients_lock, + i2c_adapter_depth(adap)); list_for_each_entry_safe(client, next, &adap->userspace_clients, detected) { dev_dbg(&adap->dev, "Removing %s at 0x%x\n", client->name, |