diff options
Diffstat (limited to 'drivers/i2c')
-rw-r--r-- | drivers/i2c/busses/Kconfig | 23 | ||||
-rw-r--r-- | drivers/i2c/busses/Makefile | 1 | ||||
-rw-r--r-- | drivers/i2c/busses/i2c-amd8111.c | 2 | ||||
-rw-r--r-- | drivers/i2c/busses/i2c-au1550.c | 11 | ||||
-rw-r--r-- | drivers/i2c/busses/i2c-bfin-twi.c | 16 | ||||
-rw-r--r-- | drivers/i2c/busses/i2c-davinci.c | 586 | ||||
-rw-r--r-- | drivers/i2c/busses/i2c-i801.c | 5 | ||||
-rw-r--r-- | drivers/i2c/busses/i2c-ibm_iic.c | 9 | ||||
-rw-r--r-- | drivers/i2c/busses/i2c-iop3xx.c | 8 | ||||
-rw-r--r-- | drivers/i2c/busses/i2c-nforce2.c | 83 | ||||
-rw-r--r-- | drivers/i2c/busses/i2c-stub.c | 79 | ||||
-rw-r--r-- | drivers/i2c/chips/pcf8574.c | 14 | ||||
-rw-r--r-- | drivers/i2c/chips/tps65010.c | 299 | ||||
-rw-r--r-- | drivers/i2c/i2c-core.c | 58 | ||||
-rw-r--r-- | drivers/i2c/i2c-dev.c | 20 |
15 files changed, 893 insertions, 321 deletions
diff --git a/drivers/i2c/busses/Kconfig b/drivers/i2c/busses/Kconfig index 9f3a4cd0b07f..de95c75efb41 100644 --- a/drivers/i2c/busses/Kconfig +++ b/drivers/i2c/busses/Kconfig @@ -75,11 +75,19 @@ config I2C_AMD8111 config I2C_AT91 tristate "Atmel AT91 I2C Two-Wire interface (TWI)" - depends on ARCH_AT91 && EXPERIMENTAL + depends on ARCH_AT91 && EXPERIMENTAL && BROKEN help This supports the use of the I2C interface on Atmel AT91 processors. + This driver is BROKEN because the controller which it uses + will easily trigger RX overrun and TX underrun errors. Using + low I2C clock rates may partially work around those issues + on some systems. Another serious problem is that there is no + documented way to issue repeated START conditions, as needed + to support combined I2C messages. Use the i2c-gpio driver + unless your system can cope with those limitations. + config I2C_AU1550 tristate "Au1550/Au1200 SMBus interface" depends on SOC_AU1550 || SOC_AU1200 @@ -106,6 +114,19 @@ config I2C_BLACKFIN_TWI_CLK_KHZ help The unit of the TWI clock is kHz. +config I2C_DAVINCI + tristate "DaVinci I2C driver" + depends on ARCH_DAVINCI + help + Support for TI DaVinci I2C controller driver. + + This driver can also be built as a module. If so, the module + will be called i2c-davinci. + + Please note that this driver might be needed to bring up other + devices such as DaVinci NIC. + For details please see http://www.ti.com/davinci + config I2C_ELEKTOR tristate "Elektor ISA card" depends on ISA && BROKEN_ON_SMP diff --git a/drivers/i2c/busses/Makefile b/drivers/i2c/busses/Makefile index 5b752e4e1918..81d43c27cf93 100644 --- a/drivers/i2c/busses/Makefile +++ b/drivers/i2c/busses/Makefile @@ -11,6 +11,7 @@ obj-$(CONFIG_I2C_AMD8111) += i2c-amd8111.o obj-$(CONFIG_I2C_AT91) += i2c-at91.o obj-$(CONFIG_I2C_AU1550) += i2c-au1550.o obj-$(CONFIG_I2C_BLACKFIN_TWI) += i2c-bfin-twi.o +obj-$(CONFIG_I2C_DAVINCI) += i2c-davinci.o obj-$(CONFIG_I2C_ELEKTOR) += i2c-elektor.o obj-$(CONFIG_I2C_GPIO) += i2c-gpio.o obj-$(CONFIG_I2C_HYDRA) += i2c-hydra.o diff --git a/drivers/i2c/busses/i2c-amd8111.c b/drivers/i2c/busses/i2c-amd8111.c index c9fca7b49267..5d1a27ef2504 100644 --- a/drivers/i2c/busses/i2c-amd8111.c +++ b/drivers/i2c/busses/i2c-amd8111.c @@ -326,7 +326,7 @@ static u32 amd8111_func(struct i2c_adapter *adapter) I2C_FUNC_SMBUS_BYTE_DATA | I2C_FUNC_SMBUS_WORD_DATA | I2C_FUNC_SMBUS_BLOCK_DATA | I2C_FUNC_SMBUS_PROC_CALL | I2C_FUNC_SMBUS_BLOCK_PROC_CALL | - I2C_FUNC_SMBUS_I2C_BLOCK | I2C_FUNC_SMBUS_HWPEC_CALC; + I2C_FUNC_SMBUS_I2C_BLOCK | I2C_FUNC_SMBUS_PEC; } static const struct i2c_algorithm smbus_algorithm = { diff --git a/drivers/i2c/busses/i2c-au1550.c b/drivers/i2c/busses/i2c-au1550.c index d7e7c359fc36..2f684166c43d 100644 --- a/drivers/i2c/busses/i2c-au1550.c +++ b/drivers/i2c/busses/i2c-au1550.c @@ -48,17 +48,14 @@ wait_xfer_done(struct i2c_au1550_data *adap) sp = (volatile psc_smb_t *)(adap->psc_base); - /* Wait for Tx FIFO Underflow. + /* Wait for Tx Buffer Empty */ for (i = 0; i < adap->xfer_timeout; i++) { - stat = sp->psc_smbevnt; + stat = sp->psc_smbstat; au_sync(); - if ((stat & PSC_SMBEVNT_TU) != 0) { - /* Clear it. */ - sp->psc_smbevnt = PSC_SMBEVNT_TU; - au_sync(); + if ((stat & PSC_SMBSTAT_TE) != 0) return 0; - } + udelay(1); } diff --git a/drivers/i2c/busses/i2c-bfin-twi.c b/drivers/i2c/busses/i2c-bfin-twi.c index 6311039dfe60..67224a424aba 100644 --- a/drivers/i2c/busses/i2c-bfin-twi.c +++ b/drivers/i2c/busses/i2c-bfin-twi.c @@ -44,7 +44,6 @@ #define TWI_I2C_MODE_COMBINED 0x04 struct bfin_twi_iface { - struct mutex twi_lock; int irq; spinlock_t lock; char read_write; @@ -228,12 +227,8 @@ static int bfin_twi_master_xfer(struct i2c_adapter *adap, if (!(bfin_read_TWI_CONTROL() & TWI_ENA)) return -ENXIO; - mutex_lock(&iface->twi_lock); - while (bfin_read_TWI_MASTER_STAT() & BUSBUSY) { - mutex_unlock(&iface->twi_lock); yield(); - mutex_lock(&iface->twi_lock); } ret = 0; @@ -310,9 +305,6 @@ static int bfin_twi_master_xfer(struct i2c_adapter *adap, break; } - /* Release mutex */ - mutex_unlock(&iface->twi_lock); - return ret; } @@ -330,12 +322,8 @@ int bfin_twi_smbus_xfer(struct i2c_adapter *adap, u16 addr, if (!(bfin_read_TWI_CONTROL() & TWI_ENA)) return -ENXIO; - mutex_lock(&iface->twi_lock); - while (bfin_read_TWI_MASTER_STAT() & BUSBUSY) { - mutex_unlock(&iface->twi_lock); yield(); - mutex_lock(&iface->twi_lock); } iface->writeNum = 0; @@ -502,9 +490,6 @@ int bfin_twi_smbus_xfer(struct i2c_adapter *adap, u16 addr, rc = (iface->result >= 0) ? 0 : -1; - /* Release mutex */ - mutex_unlock(&iface->twi_lock); - return rc; } @@ -555,7 +540,6 @@ static int i2c_bfin_twi_probe(struct platform_device *dev) struct i2c_adapter *p_adap; int rc; - mutex_init(&(iface->twi_lock)); spin_lock_init(&(iface->lock)); init_completion(&(iface->complete)); iface->irq = IRQ_TWI; diff --git a/drivers/i2c/busses/i2c-davinci.c b/drivers/i2c/busses/i2c-davinci.c new file mode 100644 index 000000000000..bd7aaff35240 --- /dev/null +++ b/drivers/i2c/busses/i2c-davinci.c @@ -0,0 +1,586 @@ +/* + * TI DAVINCI I2C adapter driver. + * + * Copyright (C) 2006 Texas Instruments. + * Copyright (C) 2007 MontaVista Software Inc. + * + * Updated by Vinod & Sudhakar Feb 2005 + * + * ---------------------------------------------------------------------------- + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * 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. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * ---------------------------------------------------------------------------- + * + */ +#include <linux/kernel.h> +#include <linux/module.h> +#include <linux/delay.h> +#include <linux/i2c.h> +#include <linux/clk.h> +#include <linux/errno.h> +#include <linux/sched.h> +#include <linux/err.h> +#include <linux/interrupt.h> +#include <linux/platform_device.h> +#include <linux/io.h> + +#include <asm/hardware.h> +#include <asm/mach-types.h> + +#include <asm/arch/i2c.h> + +/* ----- global defines ----------------------------------------------- */ + +#define DAVINCI_I2C_TIMEOUT (1*HZ) +#define I2C_DAVINCI_INTR_ALL (DAVINCI_I2C_IMR_AAS | \ + DAVINCI_I2C_IMR_SCD | \ + DAVINCI_I2C_IMR_ARDY | \ + DAVINCI_I2C_IMR_NACK | \ + DAVINCI_I2C_IMR_AL) + +#define DAVINCI_I2C_OAR_REG 0x00 +#define DAVINCI_I2C_IMR_REG 0x04 +#define DAVINCI_I2C_STR_REG 0x08 +#define DAVINCI_I2C_CLKL_REG 0x0c +#define DAVINCI_I2C_CLKH_REG 0x10 +#define DAVINCI_I2C_CNT_REG 0x14 +#define DAVINCI_I2C_DRR_REG 0x18 +#define DAVINCI_I2C_SAR_REG 0x1c +#define DAVINCI_I2C_DXR_REG 0x20 +#define DAVINCI_I2C_MDR_REG 0x24 +#define DAVINCI_I2C_IVR_REG 0x28 +#define DAVINCI_I2C_EMDR_REG 0x2c +#define DAVINCI_I2C_PSC_REG 0x30 + +#define DAVINCI_I2C_IVR_AAS 0x07 +#define DAVINCI_I2C_IVR_SCD 0x06 +#define DAVINCI_I2C_IVR_XRDY 0x05 +#define DAVINCI_I2C_IVR_RDR 0x04 +#define DAVINCI_I2C_IVR_ARDY 0x03 +#define DAVINCI_I2C_IVR_NACK 0x02 +#define DAVINCI_I2C_IVR_AL 0x01 + +#define DAVINCI_I2C_STR_BB (1 << 12) +#define DAVINCI_I2C_STR_RSFULL (1 << 11) +#define DAVINCI_I2C_STR_SCD (1 << 5) +#define DAVINCI_I2C_STR_ARDY (1 << 2) +#define DAVINCI_I2C_STR_NACK (1 << 1) +#define DAVINCI_I2C_STR_AL (1 << 0) + +#define DAVINCI_I2C_MDR_NACK (1 << 15) +#define DAVINCI_I2C_MDR_STT (1 << 13) +#define DAVINCI_I2C_MDR_STP (1 << 11) +#define DAVINCI_I2C_MDR_MST (1 << 10) +#define DAVINCI_I2C_MDR_TRX (1 << 9) +#define DAVINCI_I2C_MDR_XA (1 << 8) +#define DAVINCI_I2C_MDR_IRS (1 << 5) + +#define DAVINCI_I2C_IMR_AAS (1 << 6) +#define DAVINCI_I2C_IMR_SCD (1 << 5) +#define DAVINCI_I2C_IMR_XRDY (1 << 4) +#define DAVINCI_I2C_IMR_RRDY (1 << 3) +#define DAVINCI_I2C_IMR_ARDY (1 << 2) +#define DAVINCI_I2C_IMR_NACK (1 << 1) +#define DAVINCI_I2C_IMR_AL (1 << 0) + +#define MOD_REG_BIT(val, mask, set) do { \ + if (set) { \ + val |= mask; \ + } else { \ + val &= ~mask; \ + } \ +} while (0) + +struct davinci_i2c_dev { + struct device *dev; + void __iomem *base; + struct completion cmd_complete; + struct clk *clk; + int cmd_err; + u8 *buf; + size_t buf_len; + int irq; + struct i2c_adapter adapter; +}; + +/* default platform data to use if not supplied in the platform_device */ +static struct davinci_i2c_platform_data davinci_i2c_platform_data_default = { + .bus_freq = 100, + .bus_delay = 0, +}; + +static inline void davinci_i2c_write_reg(struct davinci_i2c_dev *i2c_dev, + int reg, u16 val) +{ + __raw_writew(val, i2c_dev->base + reg); +} + +static inline u16 davinci_i2c_read_reg(struct davinci_i2c_dev *i2c_dev, int reg) +{ + return __raw_readw(i2c_dev->base + reg); +} + +/* + * This functions configures I2C and brings I2C out of reset. + * This function is called during I2C init function. This function + * also gets called if I2C encounters any errors. + */ +static int i2c_davinci_init(struct davinci_i2c_dev *dev) +{ + struct davinci_i2c_platform_data *pdata = dev->dev->platform_data; + u16 psc; + u32 clk; + u32 clkh; + u32 clkl; + u32 input_clock = clk_get_rate(dev->clk); + u16 w; + + if (!pdata) + pdata = &davinci_i2c_platform_data_default; + + /* put I2C into reset */ + w = davinci_i2c_read_reg(dev, DAVINCI_I2C_MDR_REG); + MOD_REG_BIT(w, DAVINCI_I2C_MDR_IRS, 0); + davinci_i2c_write_reg(dev, DAVINCI_I2C_MDR_REG, w); + + /* NOTE: I2C Clock divider programming info + * As per I2C specs the following formulas provide prescaler + * and low/high divider values + * input clk --> PSC Div -----------> ICCL/H Div --> output clock + * module clk + * + * output clk = module clk / (PSC + 1) [ (ICCL + d) + (ICCH + d) ] + * + * Thus, + * (ICCL + ICCH) = clk = (input clk / ((psc +1) * output clk)) - 2d; + * + * where if PSC == 0, d = 7, + * if PSC == 1, d = 6 + * if PSC > 1 , d = 5 + */ + + psc = 26; /* To get 1MHz clock */ + + clk = ((input_clock / (psc + 1)) / (pdata->bus_freq * 1000)) - 10; + clkh = (50 * clk) / 100; + clkl = clk - clkh; + + davinci_i2c_write_reg(dev, DAVINCI_I2C_PSC_REG, psc); + davinci_i2c_write_reg(dev, DAVINCI_I2C_CLKH_REG, clkh); + davinci_i2c_write_reg(dev, DAVINCI_I2C_CLKL_REG, clkl); + + dev_dbg(dev->dev, "CLK = %d\n", clk); + dev_dbg(dev->dev, "PSC = %d\n", + davinci_i2c_read_reg(dev, DAVINCI_I2C_PSC_REG)); + dev_dbg(dev->dev, "CLKL = %d\n", + davinci_i2c_read_reg(dev, DAVINCI_I2C_CLKL_REG)); + dev_dbg(dev->dev, "CLKH = %d\n", + davinci_i2c_read_reg(dev, DAVINCI_I2C_CLKH_REG)); + + /* Take the I2C module out of reset: */ + w = davinci_i2c_read_reg(dev, DAVINCI_I2C_MDR_REG); + MOD_REG_BIT(w, DAVINCI_I2C_MDR_IRS, 1); + davinci_i2c_write_reg(dev, DAVINCI_I2C_MDR_REG, w); + + /* Enable interrupts */ + davinci_i2c_write_reg(dev, DAVINCI_I2C_IMR_REG, I2C_DAVINCI_INTR_ALL); + + return 0; +} + +/* + * Waiting for bus not busy + */ +static int i2c_davinci_wait_bus_not_busy(struct davinci_i2c_dev *dev, + char allow_sleep) +{ + unsigned long timeout; + + timeout = jiffies + DAVINCI_I2C_TIMEOUT; + while (davinci_i2c_read_reg(dev, DAVINCI_I2C_STR_REG) + & DAVINCI_I2C_STR_BB) { + if (time_after(jiffies, timeout)) { + dev_warn(dev->dev, + "timeout waiting for bus ready\n"); + return -ETIMEDOUT; + } + if (allow_sleep) + schedule_timeout(1); + } + + return 0; +} + +/* + * Low level master read/write transaction. This function is called + * from i2c_davinci_xfer. + */ +static int +i2c_davinci_xfer_msg(struct i2c_adapter *adap, struct i2c_msg *msg, int stop) +{ + struct davinci_i2c_dev *dev = i2c_get_adapdata(adap); + struct davinci_i2c_platform_data *pdata = dev->dev->platform_data; + u32 flag; + u32 stat; + u16 w; + int r; + + if (msg->len == 0) + return -EINVAL; + + if (!pdata) + pdata = &davinci_i2c_platform_data_default; + /* Introduce a delay, required for some boards (e.g Davinci EVM) */ + if (pdata->bus_delay) + udelay(pdata->bus_delay); + + /* set the slave address */ + davinci_i2c_write_reg(dev, DAVINCI_I2C_SAR_REG, msg->addr); + + dev->buf = msg->buf; + dev->buf_len = msg->len; + + davinci_i2c_write_reg(dev, DAVINCI_I2C_CNT_REG, dev->buf_len); + + init_completion(&dev->cmd_complete); + dev->cmd_err = 0; + + /* Clear any pending interrupts by reading the IVR */ + stat = davinci_i2c_read_reg(dev, DAVINCI_I2C_IVR_REG); + + /* Take I2C out of reset, configure it as master and set the + * start bit */ + flag = DAVINCI_I2C_MDR_IRS | DAVINCI_I2C_MDR_MST | DAVINCI_I2C_MDR_STT; + + /* if the slave address is ten bit address, enable XA bit */ + if (msg->flags & I2C_M_TEN) + flag |= DAVINCI_I2C_MDR_XA; + if (!(msg->flags & I2C_M_RD)) + flag |= DAVINCI_I2C_MDR_TRX; + if (stop) + flag |= DAVINCI_I2C_MDR_STP; + + /* Enable receive or transmit interrupts */ + w = davinci_i2c_read_reg(dev, DAVINCI_I2C_IMR_REG); + if (msg->flags & I2C_M_RD) + MOD_REG_BIT(w, DAVINCI_I2C_IMR_RRDY, 1); + else + MOD_REG_BIT(w, DAVINCI_I2C_IMR_XRDY, 1); + davinci_i2c_write_reg(dev, DAVINCI_I2C_IMR_REG, w); + + /* write the data into mode register */ + davinci_i2c_write_reg(dev, DAVINCI_I2C_MDR_REG, flag); + + r = wait_for_completion_interruptible_timeout(&dev->cmd_complete, + DAVINCI_I2C_TIMEOUT); + dev->buf_len = 0; + if (r < 0) + return r; + + if (r == 0) { + dev_err(dev->dev, "controller timed out\n"); + i2c_davinci_init(dev); + return -ETIMEDOUT; + } + + /* no error */ + if (likely(!dev->cmd_err)) + return msg->len; + + /* We have an error */ + if (dev->cmd_err & DAVINCI_I2C_STR_AL) { + i2c_davinci_init(dev); + return -EIO; + } + + if (dev->cmd_err & DAVINCI_I2C_STR_NACK) { + if (msg->flags & I2C_M_IGNORE_NAK) + return msg->len; + if (stop) { + w = davinci_i2c_read_reg(dev, DAVINCI_I2C_MDR_REG); + MOD_REG_BIT(w, DAVINCI_I2C_MDR_STP, 1); + davinci_i2c_write_reg(dev, DAVINCI_I2C_MDR_REG, w); + } + return -EREMOTEIO; + } + return -EIO; +} + +/* + * Prepare controller for a transaction and call i2c_davinci_xfer_msg + */ +static int +i2c_davinci_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[], int num) +{ + struct davinci_i2c_dev *dev = i2c_get_adapdata(adap); + int i; + int ret; + + dev_dbg(dev->dev, "%s: msgs: %d\n", __FUNCTION__, num); + + ret = i2c_davinci_wait_bus_not_busy(dev, 1); + if (ret < 0) { + dev_warn(dev->dev, "timeout waiting for bus ready\n"); + return ret; + } + + for (i = 0; i < num; i++) { + ret = i2c_davinci_xfer_msg(adap, &msgs[i], (i == (num - 1))); + if (ret < 0) + return ret; + } + + dev_dbg(dev->dev, "%s:%d ret: %d\n", __FUNCTION__, __LINE__, ret); + + return num; +} + +static u32 i2c_davinci_func(struct i2c_adapter *adap) +{ + return I2C_FUNC_I2C | (I2C_FUNC_SMBUS_EMUL & ~I2C_FUNC_SMBUS_QUICK); +} + +/* + * Interrupt service routine. This gets called whenever an I2C interrupt + * occurs. + */ +static irqreturn_t i2c_davinci_isr(int this_irq, void *dev_id) +{ + struct davinci_i2c_dev *dev = dev_id; + u32 stat; + int count = 0; + u16 w; + + while ((stat = davinci_i2c_read_reg(dev, DAVINCI_I2C_IVR_REG))) { + dev_dbg(dev->dev, "%s: stat=0x%x\n", __FUNCTION__, stat); + if (count++ == 100) { + dev_warn(dev->dev, "Too much work in one IRQ\n"); + break; + } + + switch (stat) { + case DAVINCI_I2C_IVR_AL: + dev->cmd_err |= DAVINCI_I2C_STR_AL; + complete(&dev->cmd_complete); + break; + + case DAVINCI_I2C_IVR_NACK: + dev->cmd_err |= DAVINCI_I2C_STR_NACK; + complete(&dev->cmd_complete); + break; + + case DAVINCI_I2C_IVR_ARDY: + w = davinci_i2c_read_reg(dev, DAVINCI_I2C_STR_REG); + MOD_REG_BIT(w, DAVINCI_I2C_STR_ARDY, 1); + davinci_i2c_write_reg(dev, DAVINCI_I2C_STR_REG, w); + complete(&dev->cmd_complete); + break; + + case DAVINCI_I2C_IVR_RDR: + if (dev->buf_len) { + *dev->buf++ = + davinci_i2c_read_reg(dev, + DAVINCI_I2C_DRR_REG); + dev->buf_len--; + if (dev->buf_len) + continue; + + w = davinci_i2c_read_reg(dev, + DAVINCI_I2C_STR_REG); + MOD_REG_BIT(w, DAVINCI_I2C_IMR_RRDY, 0); + davinci_i2c_write_reg(dev, + DAVINCI_I2C_STR_REG, + w); + } else + dev_err(dev->dev, "RDR IRQ while no" + "data requested\n"); + break; + + case DAVINCI_I2C_IVR_XRDY: + if (dev->buf_len) { + davinci_i2c_write_reg(dev, DAVINCI_I2C_DXR_REG, + *dev->buf++); + dev->buf_len--; + if (dev->buf_len) + continue; + + w = davinci_i2c_read_reg(dev, + DAVINCI_I2C_IMR_REG); + MOD_REG_BIT(w, DAVINCI_I2C_IMR_XRDY, 0); + davinci_i2c_write_reg(dev, + DAVINCI_I2C_IMR_REG, + w); + } else + dev_err(dev->dev, "TDR IRQ while no data to" + "send\n"); + break; + + case DAVINCI_I2C_IVR_SCD: + w = davinci_i2c_read_reg(dev, DAVINCI_I2C_STR_REG); + MOD_REG_BIT(w, DAVINCI_I2C_STR_SCD, 1); + davinci_i2c_write_reg(dev, DAVINCI_I2C_STR_REG, w); + complete(&dev->cmd_complete); + break; + + case DAVINCI_I2C_IVR_AAS: + dev_warn(dev->dev, "Address as slave interrupt\n"); + }/* switch */ + }/* while */ + + return count ? IRQ_HANDLED : IRQ_NONE; +} + +static struct i2c_algorithm i2c_davinci_algo = { + .master_xfer = i2c_davinci_xfer, + .functionality = i2c_davinci_func, +}; + +static int davinci_i2c_probe(struct platform_device *pdev) +{ + struct davinci_i2c_dev *dev; + struct i2c_adapter *adap; + struct resource *mem, *irq, *ioarea; + int r; + + /* NOTE: driver uses the static register mapping */ + mem = platform_get_resource(pdev, IORESOURCE_MEM, 0); + if (!mem) { + dev_err(&pdev->dev, "no mem resource?\n"); + return -ENODEV; + } + + irq = platform_get_resource(pdev, IORESOURCE_IRQ, 0); + if (!irq) { + dev_err(&pdev->dev, "no irq resource?\n"); + return -ENODEV; + } + + ioarea = request_mem_region(mem->start, (mem->end - mem->start) + 1, + pdev->name); + if (!ioarea) { + dev_err(&pdev->dev, "I2C region already claimed\n"); + return -EBUSY; + } + + dev = kzalloc(sizeof(struct davinci_i2c_dev), GFP_KERNEL); + if (!dev) { + r = -ENOMEM; + goto err_release_region; + } + + dev->dev = get_device(&pdev->dev); + dev->irq = irq->start; + platform_set_drvdata(pdev, dev); + + dev->clk = clk_get(&pdev->dev, "I2CCLK"); + if (IS_ERR(dev->clk)) { + r = -ENODEV; + goto err_free_mem; + } + clk_enable(dev->clk); + + dev->base = (void __iomem *)IO_ADDRESS(mem->start); + i2c_davinci_init(dev); + + r = request_irq(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; + } + + adap = &dev->adapter; + i2c_set_adapdata(adap, dev); + adap->owner = THIS_MODULE; + adap->class = I2C_CLASS_HWMON; + strlcpy(adap->name, "DaVinci I2C adapter", sizeof(adap->name)); + adap->algo = &i2c_davinci_algo; + adap->dev.parent = &pdev->dev; + + /* FIXME */ + adap->timeout = 1; + adap->retries = 1; + + adap->nr = pdev->id; + r = i2c_add_numbered_adapter(adap); + if (r) { + dev_err(&pdev->dev, "failure adding adapter\n"); + goto err_free_irq; + } + + return 0; + +err_free_irq: + free_irq(dev->irq, dev); +err_unuse_clocks: + clk_disable(dev->clk); + clk_put(dev->clk); + dev->clk = NULL; +err_free_mem: + platform_set_drvdata(pdev, NULL); + put_device(&pdev->dev); + kfree(dev); +err_release_region: + release_mem_region(mem->start, (mem->end - mem->start) + 1); + + return r; +} + +static int davinci_i2c_remove(struct platform_device *pdev) +{ + struct davinci_i2c_dev *dev = platform_get_drvdata(pdev); + struct resource *mem; + + platform_set_drvdata(pdev, NULL); + i2c_del_adapter(&dev->adapter); + put_device(&pdev->dev); + + clk_disable(dev->clk); + clk_put(dev->clk); + dev->clk = NULL; + + davinci_i2c_write_reg(dev, DAVINCI_I2C_MDR_REG, 0); + free_irq(IRQ_I2C, dev); + kfree(dev); + + mem = platform_get_resource(pdev, IORESOURCE_MEM, 0); + release_mem_region(mem->start, (mem->end - mem->start) + 1); + return 0; +} + +static struct platform_driver davinci_i2c_driver = { + .probe = davinci_i2c_probe, + .remove = davinci_i2c_remove, + .driver = { + .name = "i2c_davinci", + .owner = THIS_MODULE, + }, +}; + +/* I2C may be needed to bring up other drivers */ +static int __init davinci_i2c_init_driver(void) +{ + return platform_driver_register(&davinci_i2c_driver); +} +subsys_initcall(davinci_i2c_init_driver); + +static void __exit davinci_i2c_exit_driver(void) +{ + platform_driver_unregister(&davinci_i2c_driver); +} +module_exit(davinci_i2c_exit_driver); + +MODULE_AUTHOR("Texas Instruments India"); +MODULE_DESCRIPTION("TI DaVinci I2C bus adapter"); +MODULE_LICENSE("GPL"); diff --git a/drivers/i2c/busses/i2c-i801.c b/drivers/i2c/busses/i2c-i801.c index 289816db52ae..ac27e5f84ebe 100644 --- a/drivers/i2c/busses/i2c-i801.c +++ b/drivers/i2c/busses/i2c-i801.c @@ -34,6 +34,7 @@ ESB2 269B ICH8 283E ICH9 2930 + Tolapai 5032 This driver supports several versions of Intel's I/O Controller Hubs (ICH). For SMBus support, they are similar to the PIIX4 and are part of Intel's '810' and other chipsets. @@ -515,7 +516,7 @@ static u32 i801_func(struct i2c_adapter *adapter) return I2C_FUNC_SMBUS_QUICK | I2C_FUNC_SMBUS_BYTE | I2C_FUNC_SMBUS_BYTE_DATA | I2C_FUNC_SMBUS_WORD_DATA | I2C_FUNC_SMBUS_BLOCK_DATA | I2C_FUNC_SMBUS_WRITE_I2C_BLOCK - | (isich4 ? I2C_FUNC_SMBUS_HWPEC_CALC : 0); + | (isich4 ? I2C_FUNC_SMBUS_PEC : 0); } static const struct i2c_algorithm smbus_algorithm = { @@ -543,6 +544,7 @@ static struct pci_device_id i801_ids[] = { { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ESB2_17) }, { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ICH8_5) }, { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ICH9_6) }, + { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_TOLAPAI_1) }, { 0, } }; @@ -563,6 +565,7 @@ static int __devinit i801_probe(struct pci_dev *dev, const struct pci_device_id case PCI_DEVICE_ID_INTEL_ESB2_17: case PCI_DEVICE_ID_INTEL_ICH8_5: case PCI_DEVICE_ID_INTEL_ICH9_6: + case PCI_DEVICE_ID_INTEL_TOLAPAI_1: isich4 = 1; break; default: diff --git a/drivers/i2c/busses/i2c-ibm_iic.c b/drivers/i2c/busses/i2c-ibm_iic.c index 8b14d14e60ca..e08bacadd6bc 100644 --- a/drivers/i2c/busses/i2c-ibm_iic.c +++ b/drivers/i2c/busses/i2c-ibm_iic.c @@ -738,7 +738,14 @@ static int __devinit iic_probe(struct ocp_device *ocp){ adap->timeout = 1; adap->retries = 1; - if ((ret = i2c_add_adapter(adap)) != 0){ + /* + * If "dev->idx" is negative we consider it as zero. + * The reason to do so is to avoid sysfs names that only make + * sense when there are multiple adapters. + */ + adap->nr = dev->idx >= 0 ? dev->idx : 0; + + if ((ret = i2c_add_numbered_adapter(adap)) < 0) { printk(KERN_CRIT "ibm-iic%d: failed to register i2c adapter\n", dev->idx); goto fail; diff --git a/drivers/i2c/busses/i2c-iop3xx.c b/drivers/i2c/busses/i2c-iop3xx.c index ace644e21b14..c70146e4c2c0 100644 --- a/drivers/i2c/busses/i2c-iop3xx.c +++ b/drivers/i2c/busses/i2c-iop3xx.c @@ -389,13 +389,6 @@ iop3xx_i2c_master_xfer(struct i2c_adapter *i2c_adap, struct i2c_msg *msgs, return im; } -static int -iop3xx_i2c_algo_control(struct i2c_adapter *adapter, unsigned int cmd, - unsigned long arg) -{ - return 0; -} - static u32 iop3xx_i2c_func(struct i2c_adapter *adap) { @@ -404,7 +397,6 @@ iop3xx_i2c_func(struct i2c_adapter *adap) static const struct i2c_algorithm iop3xx_i2c_algo = { .master_xfer = iop3xx_i2c_master_xfer, - .algo_control = iop3xx_i2c_algo_control, .functionality = iop3xx_i2c_func, }; diff --git a/drivers/i2c/busses/i2c-nforce2.c b/drivers/i2c/busses/i2c-nforce2.c index c48140f782d0..1bf590c74166 100644 --- a/drivers/i2c/busses/i2c-nforce2.c +++ b/drivers/i2c/busses/i2c-nforce2.c @@ -62,6 +62,7 @@ struct nforce2_smbus { int base; int size; int blockops; + int can_abort; }; @@ -83,7 +84,14 @@ struct nforce2_smbus { #define NVIDIA_SMB_DATA (smbus->base + 0x04) /* 32 data registers */ #define NVIDIA_SMB_BCNT (smbus->base + 0x24) /* number of data bytes */ - +#define NVIDIA_SMB_STATUS_ABRT (smbus->base + 0x3c) /* register used to + check the status of + the abort command */ +#define NVIDIA_SMB_CTRL (smbus->base + 0x3e) /* control register */ + +#define NVIDIA_SMB_STATUS_ABRT_STS 0x01 /* Bit to notify that + abort succeeded */ +#define NVIDIA_SMB_CTRL_ABORT 0x20 #define NVIDIA_SMB_STS_DONE 0x80 #define NVIDIA_SMB_STS_ALRM 0x40 #define NVIDIA_SMB_STS_RES 0x20 @@ -98,15 +106,61 @@ struct nforce2_smbus { #define NVIDIA_SMB_PRTCL_BLOCK_DATA 0x0a #define NVIDIA_SMB_PRTCL_PEC 0x80 +/* Misc definitions */ +#define MAX_TIMEOUT 100 + static struct pci_driver nforce2_driver; +static void nforce2_abort(struct i2c_adapter *adap) +{ + struct nforce2_smbus *smbus = adap->algo_data; + int timeout = 0; + unsigned char temp; + + dev_dbg(&adap->dev, "Aborting current transaction\n"); + + outb_p(NVIDIA_SMB_CTRL_ABORT, NVIDIA_SMB_CTRL); + do { + msleep(1); + temp = inb_p(NVIDIA_SMB_STATUS_ABRT); + } while (!(temp & NVIDIA_SMB_STATUS_ABRT_STS) && + (timeout++ < MAX_TIMEOUT)); + if (!(temp & NVIDIA_SMB_STATUS_ABRT_STS)) + dev_err(&adap->dev, "Can't reset the smbus\n"); + outb_p(NVIDIA_SMB_STATUS_ABRT_STS, NVIDIA_SMB_STATUS_ABRT); +} + +static int nforce2_check_status(struct i2c_adapter *adap) +{ + struct nforce2_smbus *smbus = adap->algo_data; + int timeout = 0; + unsigned char temp; + + do { + msleep(1); + temp = inb_p(NVIDIA_SMB_STS); + } while ((!temp) && (timeout++ < MAX_TIMEOUT)); + + if (timeout >= MAX_TIMEOUT) { + dev_dbg(&adap->dev, "SMBus Timeout!\n"); + if (smbus->can_abort) + nforce2_abort(adap); + return -1; + } + if (!(temp & NVIDIA_SMB_STS_DONE) || (temp & NVIDIA_SMB_STS_STATUS)) { + dev_dbg(&adap->dev, "Transaction failed (0x%02x)!\n", temp); + return -1; + } + return 0; +} + /* Return -1 on error */ static s32 nforce2_access(struct i2c_adapter * adap, u16 addr, unsigned short flags, char read_write, u8 command, int size, union i2c_smbus_data * data) { struct nforce2_smbus *smbus = adap->algo_data; - unsigned char protocol, pec, temp; + unsigned char protocol, pec; u8 len; int i; @@ -170,21 +224,8 @@ static s32 nforce2_access(struct i2c_adapter * adap, u16 addr, outb_p((addr & 0x7f) << 1, NVIDIA_SMB_ADDR); outb_p(protocol, NVIDIA_SMB_PRTCL); - temp = inb_p(NVIDIA_SMB_STS); - - if (~temp & NVIDIA_SMB_STS_DONE) { - udelay(500); - temp = inb_p(NVIDIA_SMB_STS); - } - if (~temp & NVIDIA_SMB_STS_DONE) { - msleep(10); - temp = inb_p(NVIDIA_SMB_STS); - } - - if ((~temp & NVIDIA_SMB_STS_DONE) || (temp & NVIDIA_SMB_STS_STATUS)) { - dev_dbg(&adap->dev, "SMBus Timeout! (0x%02x)\n", temp); + if (nforce2_check_status(adap)) return -1; - } if (read_write == I2C_SMBUS_WRITE) return 0; @@ -202,7 +243,12 @@ static s32 nforce2_access(struct i2c_adapter * adap, u16 addr, case I2C_SMBUS_BLOCK_DATA: len = inb_p(NVIDIA_SMB_BCNT); - len = min_t(u8, len, I2C_SMBUS_BLOCK_MAX); + if ((len <= 0) || (len > I2C_SMBUS_BLOCK_MAX)) { + dev_err(&adap->dev, "Transaction failed " + "(received block size: 0x%02x)\n", + len); + return -1; + } for (i = 0; i < len; i++) data->block[i+1] = inb_p(NVIDIA_SMB_DATA + i); data->block[0] = len; @@ -218,6 +264,7 @@ static u32 nforce2_func(struct i2c_adapter *adapter) /* other functionality might be possible, but is not tested */ return I2C_FUNC_SMBUS_QUICK | I2C_FUNC_SMBUS_BYTE | I2C_FUNC_SMBUS_BYTE_DATA | I2C_FUNC_SMBUS_WORD_DATA | + I2C_FUNC_SMBUS_PEC | (((struct nforce2_smbus*)adapter->algo_data)->blockops ? I2C_FUNC_SMBUS_BLOCK_DATA : 0); } @@ -308,6 +355,8 @@ static int __devinit nforce2_probe(struct pci_dev *dev, const struct pci_device_ case PCI_DEVICE_ID_NVIDIA_NFORCE_MCP55_SMBUS: smbuses[0].blockops = 1; smbuses[1].blockops = 1; + smbuses[0].can_abort = 1; + smbuses[1].can_abort = 1; } /* SMBus adapter 1 */ diff --git a/drivers/i2c/busses/i2c-stub.c b/drivers/i2c/busses/i2c-stub.c index a54adc50d162..84df29da1ddc 100644 --- a/drivers/i2c/busses/i2c-stub.c +++ b/drivers/i2c/busses/i2c-stub.c @@ -24,24 +24,41 @@ #include <linux/init.h> #include <linux/module.h> #include <linux/kernel.h> +#include <linux/slab.h> #include <linux/errno.h> #include <linux/i2c.h> -static unsigned short chip_addr; -module_param(chip_addr, ushort, S_IRUGO); -MODULE_PARM_DESC(chip_addr, "Chip address (between 0x03 and 0x77)\n"); +#define MAX_CHIPS 10 -static u8 stub_pointer; -static u8 stub_bytes[256]; -static u16 stub_words[256]; +static unsigned short chip_addr[MAX_CHIPS]; +module_param_array(chip_addr, ushort, NULL, S_IRUGO); +MODULE_PARM_DESC(chip_addr, + "Chip addresses (up to 10, between 0x03 and 0x77)\n"); + +struct stub_chip { + u8 pointer; + u8 bytes[256]; + u16 words[256]; +}; + +static struct stub_chip *stub_chips; /* Return -1 on error. */ static s32 stub_xfer(struct i2c_adapter * adap, u16 addr, unsigned short flags, char read_write, u8 command, int size, union i2c_smbus_data * data) { s32 ret; - - if (addr != chip_addr) + int i; + struct stub_chip *chip = NULL; + + /* Search for the right chip */ + for (i = 0; i < MAX_CHIPS && chip_addr[i]; i++) { + if (addr == chip_addr[i]) { + chip = stub_chips + i; + break; + } + } + if (!chip) return -ENODEV; switch (size) { @@ -53,12 +70,12 @@ static s32 stub_xfer(struct i2c_adapter * adap, u16 addr, unsigned short flags, case I2C_SMBUS_BYTE: if (read_write == I2C_SMBUS_WRITE) { - stub_pointer = command; + chip->pointer = command; dev_dbg(&adap->dev, "smbus byte - addr 0x%02x, " "wrote 0x%02x.\n", addr, command); } else { - data->byte = stub_bytes[stub_pointer++]; + data->byte = chip->bytes[chip->pointer++]; dev_dbg(&adap->dev, "smbus byte - addr 0x%02x, " "read 0x%02x.\n", addr, data->byte); @@ -69,29 +86,29 @@ static s32 stub_xfer(struct i2c_adapter * adap, u16 addr, unsigned short flags, case I2C_SMBUS_BYTE_DATA: if (read_write == I2C_SMBUS_WRITE) { - stub_bytes[command] = data->byte; + chip->bytes[command] = data->byte; dev_dbg(&adap->dev, "smbus byte data - addr 0x%02x, " "wrote 0x%02x at 0x%02x.\n", addr, data->byte, command); } else { - data->byte = stub_bytes[command]; + data->byte = chip->bytes[command]; dev_dbg(&adap->dev, "smbus byte data - addr 0x%02x, " "read 0x%02x at 0x%02x.\n", addr, data->byte, command); } - stub_pointer = command + 1; + chip->pointer = command + 1; ret = 0; break; case I2C_SMBUS_WORD_DATA: if (read_write == I2C_SMBUS_WRITE) { - stub_words[command] = data->word; + chip->words[command] = data->word; dev_dbg(&adap->dev, "smbus word data - addr 0x%02x, " "wrote 0x%04x at 0x%02x.\n", addr, data->word, command); } else { - data->word = stub_words[command]; + data->word = chip->words[command]; dev_dbg(&adap->dev, "smbus word data - addr 0x%02x, " "read 0x%04x at 0x%02x.\n", addr, data->word, command); @@ -129,23 +146,41 @@ static struct i2c_adapter stub_adapter = { static int __init i2c_stub_init(void) { - if (!chip_addr) { + int i, ret; + + if (!chip_addr[0]) { printk(KERN_ERR "i2c-stub: Please specify a chip address\n"); return -ENODEV; } - if (chip_addr < 0x03 || chip_addr > 0x77) { - printk(KERN_ERR "i2c-stub: Invalid chip address 0x%02x\n", - chip_addr); - return -EINVAL; + + for (i = 0; i < MAX_CHIPS && chip_addr[i]; i++) { + if (chip_addr[i] < 0x03 || chip_addr[i] > 0x77) { + printk(KERN_ERR "i2c-stub: Invalid chip address " + "0x%02x\n", chip_addr[i]); + return -EINVAL; + } + + printk(KERN_INFO "i2c-stub: Virtual chip at 0x%02x\n", + chip_addr[i]); } - printk(KERN_INFO "i2c-stub: Virtual chip at 0x%02x\n", chip_addr); - return i2c_add_adapter(&stub_adapter); + /* Allocate memory for all chips at once */ + stub_chips = kzalloc(i * sizeof(struct stub_chip), GFP_KERNEL); + if (!stub_chips) { + printk(KERN_ERR "i2c-stub: Out of memory\n"); + return -ENOMEM; + } + + ret = i2c_add_adapter(&stub_adapter); + if (ret) + kfree(stub_chips); + return ret; } static void __exit i2c_stub_exit(void) { i2c_del_adapter(&stub_adapter); + kfree(stub_chips); } MODULE_AUTHOR("Mark M. Hoffman <mhoffman@lightlink.com>"); diff --git a/drivers/i2c/chips/pcf8574.c b/drivers/i2c/chips/pcf8574.c index 32b25427eaba..21c6dd69193c 100644 --- a/drivers/i2c/chips/pcf8574.c +++ b/drivers/i2c/chips/pcf8574.c @@ -48,14 +48,11 @@ static unsigned short normal_i2c[] = { 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, /* Insmod parameters */ I2C_CLIENT_INSMOD_2(pcf8574, pcf8574a); -/* Initial values */ -#define PCF8574_INIT 255 /* All outputs on (input mode) */ - /* Each client has this additional data */ struct pcf8574_data { struct i2c_client client; - u8 write; /* Remember last written value */ + int write; /* Remember last written value */ }; static int pcf8574_attach_adapter(struct i2c_adapter *adapter); @@ -85,7 +82,11 @@ static DEVICE_ATTR(read, S_IRUGO, show_read, NULL); static ssize_t show_write(struct device *dev, struct device_attribute *attr, char *buf) { struct pcf8574_data *data = i2c_get_clientdata(to_i2c_client(dev)); - return sprintf(buf, "%u\n", data->write); + + if (data->write < 0) + return data->write; + + return sprintf(buf, "%d\n", data->write); } static ssize_t set_write(struct device *dev, struct device_attribute *attr, const char *buf, @@ -206,8 +207,7 @@ static int pcf8574_detach_client(struct i2c_client *client) static void pcf8574_init_client(struct i2c_client *client) { struct pcf8574_data *data = i2c_get_clientdata(client); - data->write = PCF8574_INIT; - i2c_smbus_write_byte(client, data->write); + data->write = -EAGAIN; } static int __init pcf8574_init(void) diff --git a/drivers/i2c/chips/tps65010.c b/drivers/i2c/chips/tps65010.c index 503ffec2ce07..e320994b981c 100644 --- a/drivers/i2c/chips/tps65010.c +++ b/drivers/i2c/chips/tps65010.c @@ -24,20 +24,13 @@ #include <linux/init.h> #include <linux/slab.h> #include <linux/interrupt.h> -#include <linux/device.h> #include <linux/i2c.h> #include <linux/delay.h> #include <linux/workqueue.h> -#include <linux/suspend.h> #include <linux/debugfs.h> #include <linux/seq_file.h> #include <linux/mutex.h> -#include <asm/irq.h> -#include <asm/mach-types.h> - -#include <asm/arch/gpio.h> -#include <asm/arch/mux.h> #include <asm/arch/tps65010.h> /*-------------------------------------------------------------------------*/ @@ -48,10 +41,6 @@ MODULE_DESCRIPTION("TPS6501x Power Management Driver"); MODULE_LICENSE("GPL"); -static unsigned short normal_i2c[] = { 0x48, /* 0x49, */ I2C_CLIENT_END }; - -I2C_CLIENT_INSMOD; - static struct i2c_driver tps65010_driver; /*-------------------------------------------------------------------------*/ @@ -79,9 +68,8 @@ enum tps_model { }; struct tps65010 { - struct i2c_client client; + struct i2c_client *client; struct mutex lock; - int irq; struct delayed_work work; struct dentry *file; unsigned charging:1; @@ -229,22 +217,22 @@ static int dbg_show(struct seq_file *s, void *_) /* registers for monitoring battery charging and status; note * that reading chgstat and regstat may ack IRQs... */ - value = i2c_smbus_read_byte_data(&tps->client, TPS_CHGCONFIG); + value = i2c_smbus_read_byte_data(tps->client, TPS_CHGCONFIG); dbg_chgconf(tps->por, buf, sizeof buf, value); seq_printf(s, "chgconfig %s", buf); - value = i2c_smbus_read_byte_data(&tps->client, TPS_CHGSTATUS); + value = i2c_smbus_read_byte_data(tps->client, TPS_CHGSTATUS); dbg_chgstat(buf, sizeof buf, value); seq_printf(s, "chgstat %s", buf); - value = i2c_smbus_read_byte_data(&tps->client, TPS_MASK1); + value = i2c_smbus_read_byte_data(tps->client, TPS_MASK1); dbg_chgstat(buf, sizeof buf, value); seq_printf(s, "mask1 %s", buf); /* ignore ackint1 */ - value = i2c_smbus_read_byte_data(&tps->client, TPS_REGSTATUS); + value = i2c_smbus_read_byte_data(tps->client, TPS_REGSTATUS); dbg_regstat(buf, sizeof buf, value); seq_printf(s, "regstat %s", buf); - value = i2c_smbus_read_byte_data(&tps->client, TPS_MASK2); + value = i2c_smbus_read_byte_data(tps->client, TPS_MASK2); dbg_regstat(buf, sizeof buf, value); seq_printf(s, "mask2 %s\n", buf); /* ignore ackint2 */ @@ -253,21 +241,21 @@ static int dbg_show(struct seq_file *s, void *_) /* VMAIN voltage, enable lowpower, etc */ - value = i2c_smbus_read_byte_data(&tps->client, TPS_VDCDC1); + value = i2c_smbus_read_byte_data(tps->client, TPS_VDCDC1); seq_printf(s, "vdcdc1 %02x\n", value); /* VCORE voltage, vibrator on/off */ - value = i2c_smbus_read_byte_data(&tps->client, TPS_VDCDC2); + value = i2c_smbus_read_byte_data(tps->client, TPS_VDCDC2); seq_printf(s, "vdcdc2 %02x\n", value); /* both LD0s, and their lowpower behavior */ - value = i2c_smbus_read_byte_data(&tps->client, TPS_VREGS1); + value = i2c_smbus_read_byte_data(tps->client, TPS_VREGS1); seq_printf(s, "vregs1 %02x\n\n", value); /* LEDs and GPIOs */ - value = i2c_smbus_read_byte_data(&tps->client, TPS_LED1_ON); - v2 = i2c_smbus_read_byte_data(&tps->client, TPS_LED1_PER); + value = i2c_smbus_read_byte_data(tps->client, TPS_LED1_ON); + v2 = i2c_smbus_read_byte_data(tps->client, TPS_LED1_PER); seq_printf(s, "led1 %s, on=%02x, per=%02x, %d/%d msec\n", (value & 0x80) ? ((v2 & 0x80) ? "on" : "off") @@ -275,8 +263,8 @@ static int dbg_show(struct seq_file *s, void *_) value, v2, (value & 0x7f) * 10, (v2 & 0x7f) * 100); - value = i2c_smbus_read_byte_data(&tps->client, TPS_LED2_ON); - v2 = i2c_smbus_read_byte_data(&tps->client, TPS_LED2_PER); + value = i2c_smbus_read_byte_data(tps->client, TPS_LED2_ON); + v2 = i2c_smbus_read_byte_data(tps->client, TPS_LED2_PER); seq_printf(s, "led2 %s, on=%02x, per=%02x, %d/%d msec\n", (value & 0x80) ? ((v2 & 0x80) ? "on" : "off") @@ -284,8 +272,8 @@ static int dbg_show(struct seq_file *s, void *_) value, v2, (value & 0x7f) * 10, (v2 & 0x7f) * 100); - value = i2c_smbus_read_byte_data(&tps->client, TPS_DEFGPIO); - v2 = i2c_smbus_read_byte_data(&tps->client, TPS_MASK3); + value = i2c_smbus_read_byte_data(tps->client, TPS_DEFGPIO); + v2 = i2c_smbus_read_byte_data(tps->client, TPS_MASK3); seq_printf(s, "defgpio %02x mask3 %02x\n", value, v2); for (i = 0; i < 4; i++) { @@ -335,7 +323,7 @@ static void tps65010_interrupt(struct tps65010 *tps) /* regstatus irqs */ if (tps->nmask2) { - tmp = i2c_smbus_read_byte_data(&tps->client, TPS_REGSTATUS); + tmp = i2c_smbus_read_byte_data(tps->client, TPS_REGSTATUS); mask = tmp ^ tps->regstatus; tps->regstatus = tmp; mask &= tps->nmask2; @@ -362,7 +350,7 @@ static void tps65010_interrupt(struct tps65010 *tps) /* chgstatus irqs */ if (tps->nmask1) { - tmp = i2c_smbus_read_byte_data(&tps->client, TPS_CHGSTATUS); + tmp = i2c_smbus_read_byte_data(tps->client, TPS_CHGSTATUS); mask = tmp ^ tps->chgstatus; tps->chgstatus = tmp; mask &= tps->nmask1; @@ -426,7 +414,7 @@ static void tps65010_work(struct work_struct *work) int status; u8 chgconfig, tmp; - chgconfig = i2c_smbus_read_byte_data(&tps->client, + chgconfig = i2c_smbus_read_byte_data(tps->client, TPS_CHGCONFIG); chgconfig &= ~(TPS_VBUS_500MA | TPS_VBUS_CHARGING); if (tps->vbus == 500) @@ -434,17 +422,17 @@ static void tps65010_work(struct work_struct *work) else if (tps->vbus >= 100) chgconfig |= TPS_VBUS_CHARGING; - status = i2c_smbus_write_byte_data(&tps->client, + status = i2c_smbus_write_byte_data(tps->client, TPS_CHGCONFIG, chgconfig); /* vbus update fails unless VBUS is connected! */ - tmp = i2c_smbus_read_byte_data(&tps->client, TPS_CHGCONFIG); + tmp = i2c_smbus_read_byte_data(tps->client, TPS_CHGCONFIG); tps->chgconf = tmp; show_chgconfig(tps->por, "update vbus", tmp); } if (test_and_clear_bit(FLAG_IRQ_ENABLE, &tps->flags)) - enable_irq(tps->irq); + enable_irq(tps->client->irq); mutex_unlock(&tps->lock); } @@ -463,114 +451,75 @@ static irqreturn_t tps65010_irq(int irq, void *_tps) static struct tps65010 *the_tps; -static int __exit tps65010_detach_client(struct i2c_client *client) +static int __exit tps65010_remove(struct i2c_client *client) { - struct tps65010 *tps; + struct tps65010 *tps = i2c_get_clientdata(client); - tps = container_of(client, struct tps65010, client); - free_irq(tps->irq, tps); -#ifdef CONFIG_ARM - if (machine_is_omap_h2()) - omap_free_gpio(58); - if (machine_is_omap_osk()) - omap_free_gpio(OMAP_MPUIO(1)); -#endif + if (client->irq > 0) + free_irq(client->irq, tps); cancel_delayed_work(&tps->work); flush_scheduled_work(); debugfs_remove(tps->file); - if (i2c_detach_client(client) == 0) - kfree(tps); + kfree(tps); the_tps = NULL; return 0; } -static int tps65010_noscan(struct i2c_adapter *bus) -{ - /* pure paranoia, in case someone adds another i2c bus - * after our init section's gone... - */ - return -ENODEV; -} - -/* no error returns, they'd just make bus scanning stop */ -static int __init -tps65010_probe(struct i2c_adapter *bus, int address, int kind) +static int tps65010_probe(struct i2c_client *client) { struct tps65010 *tps; int status; - unsigned long irqflags; if (the_tps) { - dev_dbg(&bus->dev, "only one %s for now\n", DRIVER_NAME); - return 0; + dev_dbg(&client->dev, "only one tps6501x chip allowed\n"); + return -ENODEV; } + if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_BYTE_DATA)) + return -EINVAL; + tps = kzalloc(sizeof *tps, GFP_KERNEL); if (!tps) - return 0; + return -ENOMEM; mutex_init(&tps->lock); INIT_DELAYED_WORK(&tps->work, tps65010_work); - tps->irq = -1; - tps->client.addr = address; - tps->client.adapter = bus; - tps->client.driver = &tps65010_driver; - strlcpy(tps->client.name, DRIVER_NAME, I2C_NAME_SIZE); - - status = i2c_attach_client(&tps->client); - if (status < 0) { - dev_dbg(&bus->dev, "can't attach %s to device %d, err %d\n", - DRIVER_NAME, address, status); - goto fail1; - } + tps->client = client; - /* the IRQ is active low, but many gpio lines can't support that - * so this driver can use falling-edge triggers instead. - */ - irqflags = IRQF_SAMPLE_RANDOM; -#ifdef CONFIG_ARM - if (machine_is_omap_h2()) { - tps->model = TPS65010; - omap_cfg_reg(W4_GPIO58); - tps->irq = OMAP_GPIO_IRQ(58); - omap_request_gpio(58); - omap_set_gpio_direction(58, 1); - irqflags |= IRQF_TRIGGER_FALLING; - } - if (machine_is_omap_osk()) { + if (strcmp(client->name, "tps65010") == 0) tps->model = TPS65010; - // omap_cfg_reg(U19_1610_MPUIO1); - tps->irq = OMAP_GPIO_IRQ(OMAP_MPUIO(1)); - omap_request_gpio(OMAP_MPUIO(1)); - omap_set_gpio_direction(OMAP_MPUIO(1), 1); - irqflags |= IRQF_TRIGGER_FALLING; - } - if (machine_is_omap_h3()) { + else if (strcmp(client->name, "tps65011") == 0) + tps->model = TPS65011; + else if (strcmp(client->name, "tps65012") == 0) + tps->model = TPS65012; + else if (strcmp(client->name, "tps65013") == 0) tps->model = TPS65013; - - // FIXME set up this board's IRQ ... + else { + dev_warn(&client->dev, "unknown chip '%s'\n", client->name); + status = -ENODEV; + goto fail1; } -#endif - if (tps->irq > 0) { - status = request_irq(tps->irq, tps65010_irq, - irqflags, DRIVER_NAME, tps); + /* the IRQ is active low, but many gpio lines can't support that + * so this driver uses falling-edge triggers instead. + */ + if (client->irq > 0) { + status = request_irq(client->irq, tps65010_irq, + IRQF_SAMPLE_RANDOM | IRQF_TRIGGER_FALLING, + DRIVER_NAME, tps); if (status < 0) { - dev_dbg(&tps->client.dev, "can't get IRQ %d, err %d\n", - tps->irq, status); - i2c_detach_client(&tps->client); + dev_dbg(&client->dev, "can't get IRQ %d, err %d\n", + client->irq, status); goto fail1; } -#ifdef CONFIG_ARM /* annoying race here, ideally we'd have an option * to claim the irq now and enable it later. + * FIXME genirq IRQF_NOAUTOEN now solves that ... */ - disable_irq(tps->irq); + disable_irq(client->irq); set_bit(FLAG_IRQ_ENABLE, &tps->flags); -#endif } else - printk(KERN_WARNING "%s: IRQ not configured!\n", - DRIVER_NAME); + dev_warn(&client->dev, "IRQ not configured!\n"); switch (tps->model) { @@ -583,23 +532,22 @@ tps65010_probe(struct i2c_adapter *bus, int address, int kind) break; /* else CHGCONFIG.POR is replaced by AUA, enabling a WAIT mode */ } - tps->chgconf = i2c_smbus_read_byte_data(&tps->client, TPS_CHGCONFIG); + tps->chgconf = i2c_smbus_read_byte_data(client, TPS_CHGCONFIG); show_chgconfig(tps->por, "conf/init", tps->chgconf); show_chgstatus("chg/init", - i2c_smbus_read_byte_data(&tps->client, TPS_CHGSTATUS)); + i2c_smbus_read_byte_data(client, TPS_CHGSTATUS)); show_regstatus("reg/init", - i2c_smbus_read_byte_data(&tps->client, TPS_REGSTATUS)); + i2c_smbus_read_byte_data(client, TPS_REGSTATUS)); pr_debug("%s: vdcdc1 0x%02x, vdcdc2 %02x, vregs1 %02x\n", DRIVER_NAME, - i2c_smbus_read_byte_data(&tps->client, TPS_VDCDC1), - i2c_smbus_read_byte_data(&tps->client, TPS_VDCDC2), - i2c_smbus_read_byte_data(&tps->client, TPS_VREGS1)); + i2c_smbus_read_byte_data(client, TPS_VDCDC1), + i2c_smbus_read_byte_data(client, TPS_VDCDC2), + i2c_smbus_read_byte_data(client, TPS_VREGS1)); pr_debug("%s: defgpio 0x%02x, mask3 0x%02x\n", DRIVER_NAME, - i2c_smbus_read_byte_data(&tps->client, TPS_DEFGPIO), - i2c_smbus_read_byte_data(&tps->client, TPS_MASK3)); + i2c_smbus_read_byte_data(client, TPS_DEFGPIO), + i2c_smbus_read_byte_data(client, TPS_MASK3)); - tps65010_driver.attach_adapter = tps65010_noscan; the_tps = tps; #if defined(CONFIG_USB_GADGET) && !defined(CONFIG_USB_OTG) @@ -615,15 +563,15 @@ tps65010_probe(struct i2c_adapter *bus, int address, int kind) * registers, and maybe disable VBUS draw. */ tps->nmask1 = ~0; - (void) i2c_smbus_write_byte_data(&tps->client, TPS_MASK1, ~tps->nmask1); + (void) i2c_smbus_write_byte_data(client, TPS_MASK1, ~tps->nmask1); tps->nmask2 = TPS_REG_ONOFF; if (tps->model == TPS65013) tps->nmask2 |= TPS_REG_NO_CHG; - (void) i2c_smbus_write_byte_data(&tps->client, TPS_MASK2, ~tps->nmask2); + (void) i2c_smbus_write_byte_data(client, TPS_MASK2, ~tps->nmask2); - (void) i2c_smbus_write_byte_data(&tps->client, TPS_MASK3, 0x0f - | i2c_smbus_read_byte_data(&tps->client, TPS_MASK3)); + (void) i2c_smbus_write_byte_data(client, TPS_MASK3, 0x0f + | i2c_smbus_read_byte_data(client, TPS_MASK3)); tps65010_work(&tps->work.work); @@ -632,22 +580,15 @@ tps65010_probe(struct i2c_adapter *bus, int address, int kind) return 0; fail1: kfree(tps); - return 0; -} - -static int __init tps65010_scan_bus(struct i2c_adapter *bus) -{ - if (!i2c_check_functionality(bus, I2C_FUNC_SMBUS_BYTE_DATA)) - return -EINVAL; - return i2c_probe(bus, &addr_data, tps65010_probe); + return status; } static struct i2c_driver tps65010_driver = { .driver = { .name = "tps65010", }, - .attach_adapter = tps65010_scan_bus, - .detach_client = __exit_p(tps65010_detach_client), + .probe = tps65010_probe, + .remove = __exit_p(tps65010_remove), }; /*-------------------------------------------------------------------------*/ @@ -702,7 +643,7 @@ int tps65010_set_gpio_out_value(unsigned gpio, unsigned value) mutex_lock(&the_tps->lock); - defgpio = i2c_smbus_read_byte_data(&the_tps->client, TPS_DEFGPIO); + defgpio = i2c_smbus_read_byte_data(the_tps->client, TPS_DEFGPIO); /* Configure GPIO for output */ defgpio |= 1 << (gpio + 3); @@ -718,12 +659,12 @@ int tps65010_set_gpio_out_value(unsigned gpio, unsigned value) break; } - status = i2c_smbus_write_byte_data(&the_tps->client, + status = i2c_smbus_write_byte_data(the_tps->client, TPS_DEFGPIO, defgpio); pr_debug("%s: gpio%dout = %s, defgpio 0x%02x\n", DRIVER_NAME, gpio, value ? "high" : "low", - i2c_smbus_read_byte_data(&the_tps->client, TPS_DEFGPIO)); + i2c_smbus_read_byte_data(the_tps->client, TPS_DEFGPIO)); mutex_unlock(&the_tps->lock); return status; @@ -753,11 +694,11 @@ int tps65010_set_led(unsigned led, unsigned mode) mutex_lock(&the_tps->lock); pr_debug("%s: led%i_on 0x%02x\n", DRIVER_NAME, led, - i2c_smbus_read_byte_data(&the_tps->client, + i2c_smbus_read_byte_data(the_tps->client, TPS_LED1_ON + offs)); pr_debug("%s: led%i_per 0x%02x\n", DRIVER_NAME, led, - i2c_smbus_read_byte_data(&the_tps->client, + i2c_smbus_read_byte_data(the_tps->client, TPS_LED1_PER + offs)); switch (mode) { @@ -780,7 +721,7 @@ int tps65010_set_led(unsigned led, unsigned mode) return -EINVAL; } - status = i2c_smbus_write_byte_data(&the_tps->client, + status = i2c_smbus_write_byte_data(the_tps->client, TPS_LED1_ON + offs, led_on); if (status != 0) { @@ -791,9 +732,9 @@ int tps65010_set_led(unsigned led, unsigned mode) } pr_debug("%s: led%i_on 0x%02x\n", DRIVER_NAME, led, - i2c_smbus_read_byte_data(&the_tps->client, TPS_LED1_ON + offs)); + i2c_smbus_read_byte_data(the_tps->client, TPS_LED1_ON + offs)); - status = i2c_smbus_write_byte_data(&the_tps->client, + status = i2c_smbus_write_byte_data(the_tps->client, TPS_LED1_PER + offs, led_per); if (status != 0) { @@ -804,7 +745,7 @@ int tps65010_set_led(unsigned led, unsigned mode) } pr_debug("%s: led%i_per 0x%02x\n", DRIVER_NAME, led, - i2c_smbus_read_byte_data(&the_tps->client, + i2c_smbus_read_byte_data(the_tps->client, TPS_LED1_PER + offs)); mutex_unlock(&the_tps->lock); @@ -827,11 +768,11 @@ int tps65010_set_vib(unsigned value) mutex_lock(&the_tps->lock); - vdcdc2 = i2c_smbus_read_byte_data(&the_tps->client, TPS_VDCDC2); + vdcdc2 = i2c_smbus_read_byte_data(the_tps->client, TPS_VDCDC2); vdcdc2 &= ~(1 << 1); if (value) vdcdc2 |= (1 << 1); - status = i2c_smbus_write_byte_data(&the_tps->client, + status = i2c_smbus_write_byte_data(the_tps->client, TPS_VDCDC2, vdcdc2); pr_debug("%s: vibrator %s\n", DRIVER_NAME, value ? "on" : "off"); @@ -857,9 +798,9 @@ int tps65010_set_low_pwr(unsigned mode) pr_debug("%s: %s low_pwr, vdcdc1 0x%02x\n", DRIVER_NAME, mode ? "enable" : "disable", - i2c_smbus_read_byte_data(&the_tps->client, TPS_VDCDC1)); + i2c_smbus_read_byte_data(the_tps->client, TPS_VDCDC1)); - vdcdc1 = i2c_smbus_read_byte_data(&the_tps->client, TPS_VDCDC1); + vdcdc1 = i2c_smbus_read_byte_data(the_tps->client, TPS_VDCDC1); switch (mode) { case OFF: @@ -871,7 +812,7 @@ int tps65010_set_low_pwr(unsigned mode) break; } - status = i2c_smbus_write_byte_data(&the_tps->client, + status = i2c_smbus_write_byte_data(the_tps->client, TPS_VDCDC1, vdcdc1); if (status != 0) @@ -879,7 +820,7 @@ int tps65010_set_low_pwr(unsigned mode) DRIVER_NAME); else pr_debug("%s: vdcdc1 0x%02x\n", DRIVER_NAME, - i2c_smbus_read_byte_data(&the_tps->client, TPS_VDCDC1)); + i2c_smbus_read_byte_data(the_tps->client, TPS_VDCDC1)); mutex_unlock(&the_tps->lock); @@ -902,9 +843,9 @@ int tps65010_config_vregs1(unsigned value) mutex_lock(&the_tps->lock); pr_debug("%s: vregs1 0x%02x\n", DRIVER_NAME, - i2c_smbus_read_byte_data(&the_tps->client, TPS_VREGS1)); + i2c_smbus_read_byte_data(the_tps->client, TPS_VREGS1)); - status = i2c_smbus_write_byte_data(&the_tps->client, + status = i2c_smbus_write_byte_data(the_tps->client, TPS_VREGS1, value); if (status != 0) @@ -912,7 +853,7 @@ int tps65010_config_vregs1(unsigned value) DRIVER_NAME); else pr_debug("%s: vregs1 0x%02x\n", DRIVER_NAME, - i2c_smbus_read_byte_data(&the_tps->client, TPS_VREGS1)); + i2c_smbus_read_byte_data(the_tps->client, TPS_VREGS1)); mutex_unlock(&the_tps->lock); @@ -941,11 +882,11 @@ int tps65013_set_low_pwr(unsigned mode) pr_debug("%s: %s low_pwr, chgconfig 0x%02x vdcdc1 0x%02x\n", DRIVER_NAME, mode ? "enable" : "disable", - i2c_smbus_read_byte_data(&the_tps->client, TPS_CHGCONFIG), - i2c_smbus_read_byte_data(&the_tps->client, TPS_VDCDC1)); + i2c_smbus_read_byte_data(the_tps->client, TPS_CHGCONFIG), + i2c_smbus_read_byte_data(the_tps->client, TPS_VDCDC1)); - chgconfig = i2c_smbus_read_byte_data(&the_tps->client, TPS_CHGCONFIG); - vdcdc1 = i2c_smbus_read_byte_data(&the_tps->client, TPS_VDCDC1); + chgconfig = i2c_smbus_read_byte_data(the_tps->client, TPS_CHGCONFIG); + vdcdc1 = i2c_smbus_read_byte_data(the_tps->client, TPS_VDCDC1); switch (mode) { case OFF: @@ -959,7 +900,7 @@ int tps65013_set_low_pwr(unsigned mode) break; } - status = i2c_smbus_write_byte_data(&the_tps->client, + status = i2c_smbus_write_byte_data(the_tps->client, TPS_CHGCONFIG, chgconfig); if (status != 0) { printk(KERN_ERR "%s: Failed to write chconfig register\n", @@ -968,11 +909,11 @@ int tps65013_set_low_pwr(unsigned mode) return status; } - chgconfig = i2c_smbus_read_byte_data(&the_tps->client, TPS_CHGCONFIG); + chgconfig = i2c_smbus_read_byte_data(the_tps->client, TPS_CHGCONFIG); the_tps->chgconf = chgconfig; show_chgconfig(0, "chgconf", chgconfig); - status = i2c_smbus_write_byte_data(&the_tps->client, + status = i2c_smbus_write_byte_data(the_tps->client, TPS_VDCDC1, vdcdc1); if (status != 0) @@ -980,7 +921,7 @@ int tps65013_set_low_pwr(unsigned mode) DRIVER_NAME); else pr_debug("%s: vdcdc1 0x%02x\n", DRIVER_NAME, - i2c_smbus_read_byte_data(&the_tps->client, TPS_VDCDC1)); + i2c_smbus_read_byte_data(the_tps->client, TPS_VDCDC1)); mutex_unlock(&the_tps->lock); @@ -1011,52 +952,6 @@ static int __init tps_init(void) msleep(10); } -#ifdef CONFIG_ARM - if (machine_is_omap_osk()) { - - // FIXME: More should be placed in the initialization code - // of the submodules (DSP, ethernet, power management, - // board-osk.c). Careful: I2C is initialized "late". - - /* Let LED1 (D9) blink */ - tps65010_set_led(LED1, BLINK); - - /* Disable LED 2 (D2) */ - tps65010_set_led(LED2, OFF); - - /* Set GPIO 1 HIGH to disable VBUS power supply; - * OHCI driver powers it up/down as needed. - */ - tps65010_set_gpio_out_value(GPIO1, HIGH); - - /* Set GPIO 2 low to turn on LED D3 */ - tps65010_set_gpio_out_value(GPIO2, HIGH); - - /* Set GPIO 3 low to take ethernet out of reset */ - tps65010_set_gpio_out_value(GPIO3, LOW); - - /* gpio4 for VDD_DSP */ - - /* Enable LOW_PWR */ - tps65010_set_low_pwr(ON); - - /* Switch VLDO2 to 3.0V for AIC23 */ - tps65010_config_vregs1(TPS_LDO2_ENABLE | TPS_VLDO2_3_0V | TPS_LDO1_ENABLE); - - } else if (machine_is_omap_h2()) { - /* gpio3 for SD, gpio4 for VDD_DSP */ - - /* Enable LOW_PWR */ - tps65010_set_low_pwr(ON); - } else if (machine_is_omap_h3()) { - /* gpio4 for SD, gpio3 for VDD_DSP */ -#ifdef CONFIG_PM - /* Enable LOW_PWR */ - tps65013_set_low_pwr(ON); -#endif - } -#endif - return status; } /* NOTE: this MUST be initialized before the other parts of the system diff --git a/drivers/i2c/i2c-core.c b/drivers/i2c/i2c-core.c index d663e6960d93..e73d58c43f38 100644 --- a/drivers/i2c/i2c-core.c +++ b/drivers/i2c/i2c-core.c @@ -67,20 +67,16 @@ static int i2c_device_match(struct device *dev, struct device_driver *drv) #ifdef CONFIG_HOTPLUG /* uevent helps with hotplug: modprobe -q $(MODALIAS) */ -static int i2c_device_uevent(struct device *dev, char **envp, int num_envp, - char *buffer, int buffer_size) +static int i2c_device_uevent(struct device *dev, struct kobj_uevent_env *env) { struct i2c_client *client = to_i2c_client(dev); - int i = 0, length = 0; /* by definition, legacy drivers can't hotplug */ if (dev->driver || !client->driver_name) return 0; - if (add_uevent_var(envp, num_envp, &i, buffer, buffer_size, &length, - "MODALIAS=%s", client->driver_name)) + if (add_uevent_var(env, "MODALIAS=%s", client->driver_name)) return -ENOMEM; - envp[i] = NULL; dev_dbg(dev, "uevent\n"); return 0; } @@ -190,7 +186,7 @@ static struct device_attribute i2c_dev_attrs[] = { { }, }; -struct bus_type i2c_bus_type = { +static struct bus_type i2c_bus_type = { .name = "i2c", .dev_attrs = i2c_dev_attrs, .match = i2c_device_match, @@ -201,7 +197,6 @@ struct bus_type i2c_bus_type = { .suspend = i2c_device_suspend, .resume = i2c_device_resume, }; -EXPORT_SYMBOL_GPL(i2c_bus_type); /** * i2c_new_device - instantiate an i2c device for use with a new style driver @@ -230,7 +225,9 @@ i2c_new_device(struct i2c_adapter *adap, struct i2c_board_info const *info) client->adapter = adap; client->dev.platform_data = info->platform_data; - client->flags = info->flags; + device_init_wakeup(&client->dev, info->flags & I2C_CLIENT_WAKE); + + client->flags = info->flags & ~I2C_CLIENT_WAKE; client->addr = info->addr; client->irq = info->irq; @@ -283,7 +280,7 @@ EXPORT_SYMBOL_GPL(i2c_unregister_device); /* I2C bus adapters -- one roots each I2C or SMBUS segment */ -void i2c_adapter_dev_release(struct device *dev) +static void i2c_adapter_dev_release(struct device *dev) { struct i2c_adapter *adap = to_i2c_adapter(dev); complete(&adap->dev_released); @@ -301,7 +298,7 @@ static struct device_attribute i2c_adapter_attrs[] = { { }, }; -struct class i2c_adapter_class = { +static struct class i2c_adapter_class = { .owner = THIS_MODULE, .name = "i2c-adapter", .dev_attrs = i2c_adapter_attrs, @@ -934,28 +931,6 @@ int i2c_master_recv(struct i2c_client *client, char *buf ,int count) } EXPORT_SYMBOL(i2c_master_recv); -int i2c_control(struct i2c_client *client, - unsigned int cmd, unsigned long arg) -{ - int ret = 0; - struct i2c_adapter *adap = client->adapter; - - dev_dbg(&client->adapter->dev, "i2c ioctl, cmd: 0x%x, arg: %#lx\n", cmd, arg); - switch (cmd) { - case I2C_RETRIES: - adap->retries = arg; - break; - case I2C_TIMEOUT: - adap->timeout = arg; - break; - default: - if (adap->algo->algo_control!=NULL) - ret = adap->algo->algo_control(adap,cmd,arg); - } - return ret; -} -EXPORT_SYMBOL(i2c_control); - /* ---------------------------------------------------- * the i2c address scanning function * Will not work for 10-bit addresses! @@ -1310,7 +1285,22 @@ s32 i2c_smbus_write_word_data(struct i2c_client *client, u8 command, u16 value) } EXPORT_SYMBOL(i2c_smbus_write_word_data); -/* Returns the number of read bytes */ +/** + * i2c_smbus_read_block_data - SMBus block read request + * @client: Handle to slave device + * @command: Command byte issued to let the slave know what data should + * be returned + * @values: Byte array into which data will be read; big enough to hold + * the data returned by the slave. SMBus allows at most 32 bytes. + * + * Returns the number of bytes read in the slave's response, else a + * negative number to indicate some kind of error. + * + * Note that using this function requires that the client's adapter support + * the I2C_FUNC_SMBUS_READ_BLOCK_DATA functionality. Not all adapter drivers + * support this; its emulation through I2C messaging relies on a specific + * mechanism (I2C_M_RECV_LEN) which may not be implemented. + */ s32 i2c_smbus_read_block_data(struct i2c_client *client, u8 command, u8 *values) { diff --git a/drivers/i2c/i2c-dev.c b/drivers/i2c/i2c-dev.c index 64eee9551b22..5a15e50748de 100644 --- a/drivers/i2c/i2c-dev.c +++ b/drivers/i2c/i2c-dev.c @@ -226,8 +226,10 @@ static int i2cdev_ioctl(struct inode *inode, struct file *file, res = 0; for( i=0; i<rdwr_arg.nmsgs; i++ ) { - /* Limit the size of the message to a sane amount */ - if (rdwr_pa[i].len > 8192) { + /* Limit the size of the message to a sane amount; + * and don't let length change either. */ + if ((rdwr_pa[i].len > 8192) || + (rdwr_pa[i].flags & I2C_M_RECV_LEN)) { res = -EINVAL; break; } @@ -352,9 +354,19 @@ static int i2cdev_ioctl(struct inode *inode, struct file *file, return -EFAULT; } return res; - + case I2C_RETRIES: + client->adapter->retries = arg; + break; + case I2C_TIMEOUT: + client->adapter->timeout = arg; + break; default: - return i2c_control(client,cmd,arg); + /* NOTE: returning a fault code here could cause trouble + * in buggy userspace code. Some old kernel bugs returned + * zero in this case, and userspace code might accidentally + * have depended on that bug. + */ + return -ENOTTY; } return 0; } |