diff options
Diffstat (limited to 'drivers/i2c')
44 files changed, 586 insertions, 823 deletions
diff --git a/drivers/i2c/Kconfig b/drivers/i2c/Kconfig index 02ce9cff5fc..d06083fdffb 100644 --- a/drivers/i2c/Kconfig +++ b/drivers/i2c/Kconfig @@ -73,7 +73,6 @@ config I2C_SMBUS source drivers/i2c/algos/Kconfig source drivers/i2c/busses/Kconfig -source drivers/i2c/chips/Kconfig config I2C_DEBUG_CORE bool "I2C Core debugging messages" @@ -98,12 +97,4 @@ config I2C_DEBUG_BUS a problem with I2C support and want to see more of what is going on. -config I2C_DEBUG_CHIP - bool "I2C Chip debugging messages" - help - Say Y here if you want the I2C chip drivers to produce a bunch of - debug messages to the system log. Select this if you are having - a problem with I2C support and want to see more of what is going - on. - endif # I2C diff --git a/drivers/i2c/Makefile b/drivers/i2c/Makefile index acd0250c16a..a7d9b4be9bb 100644 --- a/drivers/i2c/Makefile +++ b/drivers/i2c/Makefile @@ -6,7 +6,7 @@ obj-$(CONFIG_I2C_BOARDINFO) += i2c-boardinfo.o obj-$(CONFIG_I2C) += i2c-core.o obj-$(CONFIG_I2C_SMBUS) += i2c-smbus.o obj-$(CONFIG_I2C_CHARDEV) += i2c-dev.o -obj-y += busses/ chips/ algos/ +obj-y += algos/ busses/ ifeq ($(CONFIG_I2C_DEBUG_CORE),y) EXTRA_CFLAGS += -DDEBUG diff --git a/drivers/i2c/algos/i2c-algo-bit.c b/drivers/i2c/algos/i2c-algo-bit.c index e25e13980af..a39e6cff86e 100644 --- a/drivers/i2c/algos/i2c-algo-bit.c +++ b/drivers/i2c/algos/i2c-algo-bit.c @@ -24,7 +24,6 @@ #include <linux/kernel.h> #include <linux/module.h> #include <linux/delay.h> -#include <linux/slab.h> #include <linux/init.h> #include <linux/errno.h> #include <linux/sched.h> @@ -522,6 +521,12 @@ static int bit_xfer(struct i2c_adapter *i2c_adap, int i, ret; unsigned short nak_ok; + if (adap->pre_xfer) { + ret = adap->pre_xfer(i2c_adap); + if (ret < 0) + return ret; + } + bit_dbg(3, &i2c_adap->dev, "emitting start condition\n"); i2c_start(adap); for (i = 0; i < num; i++) { @@ -570,6 +575,9 @@ static int bit_xfer(struct i2c_adapter *i2c_adap, bailout: bit_dbg(3, &i2c_adap->dev, "emitting stop condition\n"); i2c_stop(adap); + + if (adap->post_xfer) + adap->post_xfer(i2c_adap); return ret; } diff --git a/drivers/i2c/algos/i2c-algo-pcf.c b/drivers/i2c/algos/i2c-algo-pcf.c index 7ce75775ec7..5eebf562ff3 100644 --- a/drivers/i2c/algos/i2c-algo-pcf.c +++ b/drivers/i2c/algos/i2c-algo-pcf.c @@ -29,7 +29,6 @@ #include <linux/kernel.h> #include <linux/module.h> #include <linux/delay.h> -#include <linux/slab.h> #include <linux/init.h> #include <linux/errno.h> #include <linux/i2c.h> @@ -176,7 +175,7 @@ static int pcf_init_8584 (struct i2c_algo_pcf_data *adap) */ if (((temp = get_pcf(adap, 1)) & 0x7f) != (0)) { DEB2(printk(KERN_ERR "i2c-algo-pcf.o: PCF detection failed -- can't select S0 (0x%02x).\n", temp)); - return -ENXIO; /* definetly not PCF8584 */ + return -ENXIO; /* definitely not PCF8584 */ } /* load own address in S0, effective address is (own << 1) */ diff --git a/drivers/i2c/busses/Kconfig b/drivers/i2c/busses/Kconfig index 9c6170cd9aa..87ab0568bb0 100644 --- a/drivers/i2c/busses/Kconfig +++ b/drivers/i2c/busses/Kconfig @@ -564,7 +564,7 @@ config I2C_STU300 config I2C_VERSATILE tristate "ARM Versatile/Realview I2C bus support" - depends on ARCH_VERSATILE || ARCH_REALVIEW + depends on ARCH_VERSATILE || ARCH_REALVIEW || ARCH_VEXPRESS select I2C_ALGOBIT help Say yes if you want to support the I2C serial bus on ARMs Versatile diff --git a/drivers/i2c/busses/i2c-amd8111.c b/drivers/i2c/busses/i2c-amd8111.c index d0dc970d737..2fbef27b6cd 100644 --- a/drivers/i2c/busses/i2c-amd8111.c +++ b/drivers/i2c/busses/i2c-amd8111.c @@ -17,6 +17,7 @@ #include <linux/i2c.h> #include <linux/delay.h> #include <linux/acpi.h> +#include <linux/slab.h> #include <asm/io.h> MODULE_LICENSE("GPL"); diff --git a/drivers/i2c/busses/i2c-bfin-twi.c b/drivers/i2c/busses/i2c-bfin-twi.c index fe3fb567317..fb26e5c6751 100644 --- a/drivers/i2c/busses/i2c-bfin-twi.c +++ b/drivers/i2c/busses/i2c-bfin-twi.c @@ -12,6 +12,7 @@ #include <linux/kernel.h> #include <linux/init.h> #include <linux/i2c.h> +#include <linux/slab.h> #include <linux/io.h> #include <linux/mm.h> #include <linux/timer.h> @@ -24,8 +25,6 @@ #include <asm/portmux.h> #include <asm/irq.h> -#define POLL_TIMEOUT (2 * HZ) - /* SMBus mode*/ #define TWI_I2C_MODE_STANDARD 1 #define TWI_I2C_MODE_STANDARDSUB 2 @@ -43,8 +42,6 @@ struct bfin_twi_iface { int cur_mode; int manual_stop; int result; - int timeout_count; - struct timer_list timeout_timer; struct i2c_adapter adap; struct completion complete; struct i2c_msg *pmsg; @@ -84,14 +81,15 @@ static const u16 pin_req[2][3] = { {P_TWI1_SCL, P_TWI1_SDA, 0}, }; -static void bfin_twi_handle_interrupt(struct bfin_twi_iface *iface) +static void bfin_twi_handle_interrupt(struct bfin_twi_iface *iface, + unsigned short twi_int_status) { - unsigned short twi_int_status = read_INT_STAT(iface); unsigned short mast_stat = read_MASTER_STAT(iface); if (twi_int_status & XMTSERV) { /* Transmit next data */ if (iface->writeNum > 0) { + SSYNC(); write_XMT_DATA8(iface, *(iface->transPtr++)); iface->writeNum--; } @@ -113,10 +111,6 @@ static void bfin_twi_handle_interrupt(struct bfin_twi_iface *iface) write_MASTER_CTL(iface, (read_MASTER_CTL(iface) | RSTART) & ~MDIR); } - SSYNC(); - /* Clear status */ - write_INT_STAT(iface, XMTSERV); - SSYNC(); } if (twi_int_status & RCVSERV) { if (iface->readNum > 0) { @@ -138,7 +132,6 @@ static void bfin_twi_handle_interrupt(struct bfin_twi_iface *iface) } else if (iface->manual_stop) { write_MASTER_CTL(iface, read_MASTER_CTL(iface) | STOP); - SSYNC(); } else if (iface->cur_mode == TWI_I2C_MODE_REPEAT && iface->cur_msg + 1 < iface->msg_num) { if (iface->pmsg[iface->cur_msg + 1].flags & I2C_M_RD) @@ -147,44 +140,37 @@ static void bfin_twi_handle_interrupt(struct bfin_twi_iface *iface) else write_MASTER_CTL(iface, (read_MASTER_CTL(iface) | RSTART) & ~MDIR); - SSYNC(); } - /* Clear interrupt source */ - write_INT_STAT(iface, RCVSERV); - SSYNC(); } if (twi_int_status & MERR) { - write_INT_STAT(iface, MERR); write_INT_MASK(iface, 0); write_MASTER_STAT(iface, 0x3e); write_MASTER_CTL(iface, 0); - SSYNC(); iface->result = -EIO; - /* if both err and complete int stats are set, return proper - * results. + + if (mast_stat & LOSTARB) + dev_dbg(&iface->adap.dev, "Lost Arbitration\n"); + if (mast_stat & ANAK) + dev_dbg(&iface->adap.dev, "Address Not Acknowledged\n"); + if (mast_stat & DNAK) + dev_dbg(&iface->adap.dev, "Data Not Acknowledged\n"); + if (mast_stat & BUFRDERR) + dev_dbg(&iface->adap.dev, "Buffer Read Error\n"); + if (mast_stat & BUFWRERR) + dev_dbg(&iface->adap.dev, "Buffer Write Error\n"); + + /* If it is a quick transfer, only address without data, + * not an err, return 1. */ - if (twi_int_status & MCOMP) { - write_INT_STAT(iface, MCOMP); - write_INT_MASK(iface, 0); - write_MASTER_CTL(iface, 0); - SSYNC(); - /* If it is a quick transfer, only address bug no data, - * not an err, return 1. - */ - if (iface->writeNum == 0 && (mast_stat & BUFRDERR)) - iface->result = 1; - /* If address not acknowledged return -1, - * else return 0. - */ - else if (!(mast_stat & ANAK)) - iface->result = 0; - } + if (iface->cur_mode == TWI_I2C_MODE_STANDARD && + iface->transPtr == NULL && + (twi_int_status & MCOMP) && (mast_stat & DNAK)) + iface->result = 1; + complete(&iface->complete); return; } if (twi_int_status & MCOMP) { - write_INT_STAT(iface, MCOMP); - SSYNC(); if (iface->cur_mode == TWI_I2C_MODE_COMBINED) { if (iface->readNum == 0) { /* set the read number to 1 and ask for manual @@ -206,7 +192,6 @@ static void bfin_twi_handle_interrupt(struct bfin_twi_iface *iface) /* remove restart bit and enable master receive */ write_MASTER_CTL(iface, read_MASTER_CTL(iface) & ~RSTART); - SSYNC(); } else if (iface->cur_mode == TWI_I2C_MODE_REPEAT && iface->cur_msg+1 < iface->msg_num) { iface->cur_msg++; @@ -225,7 +210,6 @@ static void bfin_twi_handle_interrupt(struct bfin_twi_iface *iface) write_XMT_DATA8(iface, *(iface->transPtr++)); iface->writeNum--; - SSYNC(); } } @@ -243,15 +227,13 @@ static void bfin_twi_handle_interrupt(struct bfin_twi_iface *iface) /* remove restart bit and enable master receive */ write_MASTER_CTL(iface, read_MASTER_CTL(iface) & ~RSTART); - SSYNC(); } else { iface->result = 1; write_INT_MASK(iface, 0); write_MASTER_CTL(iface, 0); - SSYNC(); - complete(&iface->complete); } } + complete(&iface->complete); } /* Interrupt handler */ @@ -259,38 +241,26 @@ static irqreturn_t bfin_twi_interrupt_entry(int irq, void *dev_id) { struct bfin_twi_iface *iface = dev_id; unsigned long flags; + unsigned short twi_int_status; spin_lock_irqsave(&iface->lock, flags); - del_timer(&iface->timeout_timer); - bfin_twi_handle_interrupt(iface); - spin_unlock_irqrestore(&iface->lock, flags); - return IRQ_HANDLED; -} - -static void bfin_twi_timeout(unsigned long data) -{ - struct bfin_twi_iface *iface = (struct bfin_twi_iface *)data; - unsigned long flags; - - spin_lock_irqsave(&iface->lock, flags); - bfin_twi_handle_interrupt(iface); - if (iface->result == 0) { - iface->timeout_count--; - if (iface->timeout_count > 0) { - iface->timeout_timer.expires = jiffies + POLL_TIMEOUT; - add_timer(&iface->timeout_timer); - } else { - iface->result = -1; - complete(&iface->complete); - } + while (1) { + twi_int_status = read_INT_STAT(iface); + if (!twi_int_status) + break; + /* Clear interrupt status */ + write_INT_STAT(iface, twi_int_status); + bfin_twi_handle_interrupt(iface, twi_int_status); + SSYNC(); } spin_unlock_irqrestore(&iface->lock, flags); + return IRQ_HANDLED; } /* - * Generic i2c master transfer entrypoint + * One i2c master transfer */ -static int bfin_twi_master_xfer(struct i2c_adapter *adap, +static int bfin_twi_do_master_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs, int num) { struct bfin_twi_iface *iface = adap->algo_data; @@ -318,7 +288,6 @@ static int bfin_twi_master_xfer(struct i2c_adapter *adap, iface->transPtr = pmsg->buf; iface->writeNum = iface->readNum = pmsg->len; iface->result = 0; - iface->timeout_count = 10; init_completion(&(iface->complete)); /* Set Transmit device address */ write_MASTER_ADDR(iface, pmsg->addr); @@ -357,30 +326,41 @@ static int bfin_twi_master_xfer(struct i2c_adapter *adap, iface->manual_stop = 1; } - iface->timeout_timer.expires = jiffies + POLL_TIMEOUT; - add_timer(&iface->timeout_timer); - /* Master enable */ write_MASTER_CTL(iface, read_MASTER_CTL(iface) | MEN | ((iface->read_write == I2C_SMBUS_READ) ? MDIR : 0) | ((CONFIG_I2C_BLACKFIN_TWI_CLK_KHZ > 100) ? FAST : 0)); SSYNC(); - wait_for_completion(&iface->complete); - - rc = iface->result; + while (!iface->result) { + if (!wait_for_completion_timeout(&iface->complete, + adap->timeout)) { + iface->result = -1; + dev_err(&adap->dev, "master transfer timeout\n"); + } + } - if (rc == 1) - return num; + if (iface->result == 1) + rc = iface->cur_msg + 1; else - return rc; + rc = iface->result; + + return rc; } /* - * SMBus type transfer entrypoint + * Generic i2c master transfer entrypoint */ +static int bfin_twi_master_xfer(struct i2c_adapter *adap, + struct i2c_msg *msgs, int num) +{ + return bfin_twi_do_master_xfer(adap, msgs, num); +} -int bfin_twi_smbus_xfer(struct i2c_adapter *adap, u16 addr, +/* + * One I2C SMBus transfer + */ +int bfin_twi_do_smbus_xfer(struct i2c_adapter *adap, u16 addr, unsigned short flags, char read_write, u8 command, int size, union i2c_smbus_data *data) { @@ -468,7 +448,6 @@ int bfin_twi_smbus_xfer(struct i2c_adapter *adap, u16 addr, iface->manual_stop = 0; iface->read_write = read_write; iface->command = command; - iface->timeout_count = 10; init_completion(&(iface->complete)); /* FIFO Initiation. Data in FIFO should be discarded before @@ -485,9 +464,6 @@ int bfin_twi_smbus_xfer(struct i2c_adapter *adap, u16 addr, write_MASTER_ADDR(iface, addr); SSYNC(); - iface->timeout_timer.expires = jiffies + POLL_TIMEOUT; - add_timer(&iface->timeout_timer); - switch (iface->cur_mode) { case TWI_I2C_MODE_STANDARDSUB: write_XMT_DATA8(iface, iface->command); @@ -549,10 +525,8 @@ int bfin_twi_smbus_xfer(struct i2c_adapter *adap, u16 addr, else if (iface->readNum > 255) { write_MASTER_CTL(iface, 0xff << 6); iface->manual_stop = 1; - } else { - del_timer(&iface->timeout_timer); + } else break; - } } } write_INT_MASK(iface, MCOMP | MERR | @@ -568,7 +542,13 @@ int bfin_twi_smbus_xfer(struct i2c_adapter *adap, u16 addr, } SSYNC(); - wait_for_completion(&iface->complete); + while (!iface->result) { + if (!wait_for_completion_timeout(&iface->complete, + adap->timeout)) { + iface->result = -1; + dev_err(&adap->dev, "smbus transfer timeout\n"); + } + } rc = (iface->result >= 0) ? 0 : -1; @@ -576,6 +556,17 @@ int bfin_twi_smbus_xfer(struct i2c_adapter *adap, u16 addr, } /* + * Generic I2C SMBus transfer entrypoint + */ +int bfin_twi_smbus_xfer(struct i2c_adapter *adap, u16 addr, + unsigned short flags, char read_write, + u8 command, int size, union i2c_smbus_data *data) +{ + return bfin_twi_do_smbus_xfer(adap, addr, flags, + read_write, command, size, data); +} + +/* * Return what the adapter supports */ static u32 bfin_twi_functionality(struct i2c_adapter *adap) @@ -666,10 +657,6 @@ static int i2c_bfin_twi_probe(struct platform_device *pdev) goto out_error_no_irq; } - init_timer(&(iface->timeout_timer)); - iface->timeout_timer.function = bfin_twi_timeout; - iface->timeout_timer.data = (unsigned long)iface; - p_adap = &iface->adap; p_adap->nr = pdev->id; strlcpy(p_adap->name, pdev->name, sizeof(p_adap->name)); @@ -677,6 +664,8 @@ static int i2c_bfin_twi_probe(struct platform_device *pdev) p_adap->algo_data = iface; p_adap->class = I2C_CLASS_HWMON | I2C_CLASS_SPD; p_adap->dev.parent = &pdev->dev; + p_adap->timeout = 5 * HZ; + p_adap->retries = 3; rc = peripheral_request_list(pin_req[pdev->id], "i2c-bfin-twi"); if (rc) { diff --git a/drivers/i2c/busses/i2c-cpm.c b/drivers/i2c/busses/i2c-cpm.c index 9c2e10082b7..16948db3897 100644 --- a/drivers/i2c/busses/i2c-cpm.c +++ b/drivers/i2c/busses/i2c-cpm.c @@ -441,7 +441,7 @@ static int __devinit cpm_i2c_setup(struct cpm_i2c *cpm) init_waitqueue_head(&cpm->i2c_wait); cpm->irq = of_irq_to_resource(ofdev->node, 0, NULL); - if (cpm->irq == NO_IRQ) + if (!cpm->irq) return -EINVAL; /* Install interrupt handler. */ diff --git a/drivers/i2c/busses/i2c-davinci.c b/drivers/i2c/busses/i2c-davinci.c index c89687a1083..4523364e672 100644 --- a/drivers/i2c/busses/i2c-davinci.c +++ b/drivers/i2c/busses/i2c-davinci.c @@ -35,6 +35,7 @@ #include <linux/interrupt.h> #include <linux/platform_device.h> #include <linux/io.h> +#include <linux/slab.h> #include <mach/hardware.h> diff --git a/drivers/i2c/busses/i2c-designware.c b/drivers/i2c/busses/i2c-designware.c index 3e72b69aa7f..b664ed8bbdb 100644 --- a/drivers/i2c/busses/i2c-designware.c +++ b/drivers/i2c/busses/i2c-designware.c @@ -36,6 +36,7 @@ #include <linux/interrupt.h> #include <linux/platform_device.h> #include <linux/io.h> +#include <linux/slab.h> /* * Registers offset diff --git a/drivers/i2c/busses/i2c-elektor.c b/drivers/i2c/busses/i2c-elektor.c index 448b4bf35eb..612255614a6 100644 --- a/drivers/i2c/busses/i2c-elektor.c +++ b/drivers/i2c/busses/i2c-elektor.c @@ -29,7 +29,6 @@ #include <linux/ioport.h> #include <linux/module.h> #include <linux/delay.h> -#include <linux/slab.h> #include <linux/init.h> #include <linux/interrupt.h> #include <linux/pci.h> diff --git a/drivers/i2c/busses/i2c-gpio.c b/drivers/i2c/busses/i2c-gpio.c index 32104eac8d3..c21077d248a 100644 --- a/drivers/i2c/busses/i2c-gpio.c +++ b/drivers/i2c/busses/i2c-gpio.c @@ -12,6 +12,7 @@ #include <linux/i2c-gpio.h> #include <linux/init.h> #include <linux/module.h> +#include <linux/slab.h> #include <linux/platform_device.h> #include <asm/gpio.h> diff --git a/drivers/i2c/busses/i2c-highlander.c b/drivers/i2c/busses/i2c-highlander.c index 87ecace415d..3df1bc80f37 100644 --- a/drivers/i2c/busses/i2c-highlander.c +++ b/drivers/i2c/busses/i2c-highlander.c @@ -19,6 +19,7 @@ #include <linux/completion.h> #include <linux/io.h> #include <linux/delay.h> +#include <linux/slab.h> #define SMCR 0x00 #define SMCR_START (1 << 0) @@ -281,7 +282,6 @@ static int highlander_i2c_smbus_xfer(struct i2c_adapter *adap, u16 addr, union i2c_smbus_data *data) { struct highlander_i2c_dev *dev = i2c_get_adapdata(adap); - int read = read_write & I2C_SMBUS_READ; u16 tmp; init_completion(&dev->cmd_complete); @@ -336,11 +336,11 @@ static int highlander_i2c_smbus_xfer(struct i2c_adapter *adap, u16 addr, highlander_i2c_done(dev); /* Set slave address */ - iowrite16((addr << 1) | read, dev->base + SMSMADR); + iowrite16((addr << 1) | read_write, dev->base + SMSMADR); highlander_i2c_command(dev, command, dev->buf_len); - if (read) + if (read_write == I2C_SMBUS_READ) return highlander_i2c_read(dev); else return highlander_i2c_write(dev); diff --git a/drivers/i2c/busses/i2c-i801.c b/drivers/i2c/busses/i2c-i801.c index 9da5b05cdb5..299b918455a 100644 --- a/drivers/i2c/busses/i2c-i801.c +++ b/drivers/i2c/busses/i2c-i801.c @@ -416,9 +416,11 @@ static int i801_block_transaction(union i2c_smbus_data *data, char read_write, data->block[0] = 32; /* max for SMBus block reads */ } + /* Experience has shown that the block buffer can only be used for + SMBus (not I2C) block transactions, even though the datasheet + doesn't mention this limitation. */ if ((i801_features & FEATURE_BLOCK_BUFFER) - && !(command == I2C_SMBUS_I2C_BLOCK_DATA - && read_write == I2C_SMBUS_READ) + && command != I2C_SMBUS_I2C_BLOCK_DATA && i801_set_block_buffer_mode() == 0) result = i801_block_transaction_by_block(data, read_write, hwpec); diff --git a/drivers/i2c/busses/i2c-ibm_iic.c b/drivers/i2c/busses/i2c-ibm_iic.c index b1bc6e277d2..2bef534cbff 100644 --- a/drivers/i2c/busses/i2c-ibm_iic.c +++ b/drivers/i2c/busses/i2c-ibm_iic.c @@ -668,12 +668,12 @@ static int __devinit iic_request_irq(struct of_device *ofdev, int irq; if (iic_force_poll) - return NO_IRQ; + return 0; irq = irq_of_parse_and_map(np, 0); - if (irq == NO_IRQ) { + if (!irq) { dev_err(&ofdev->dev, "irq_of_parse_and_map failed\n"); - return NO_IRQ; + return 0; } /* Disable interrupts until we finish initialization, assumes @@ -683,7 +683,7 @@ static int __devinit iic_request_irq(struct of_device *ofdev, if (request_irq(irq, iic_handler, 0, "IBM IIC", dev)) { dev_err(&ofdev->dev, "request_irq %d failed\n", irq); /* Fallback to the polling mode */ - return NO_IRQ; + return 0; } return irq; @@ -719,7 +719,7 @@ static int __devinit iic_probe(struct of_device *ofdev, init_waitqueue_head(&dev->wq); dev->irq = iic_request_irq(ofdev, dev); - if (dev->irq == NO_IRQ) + if (!dev->irq) dev_warn(&ofdev->dev, "using polling mode\n"); /* Board specific settings */ @@ -766,7 +766,7 @@ static int __devinit iic_probe(struct of_device *ofdev, return 0; error_cleanup: - if (dev->irq != NO_IRQ) { + if (dev->irq) { iic_interrupt_mode(dev, 0); free_irq(dev->irq, dev); } @@ -790,7 +790,7 @@ static int __devexit iic_remove(struct of_device *ofdev) i2c_del_adapter(&dev->adap); - if (dev->irq != NO_IRQ) { + if (dev->irq) { iic_interrupt_mode(dev, 0); free_irq(dev->irq, dev); } diff --git a/drivers/i2c/busses/i2c-imx.c b/drivers/i2c/busses/i2c-imx.c index 32375bddae7..d1ff9408dc1 100644 --- a/drivers/i2c/busses/i2c-imx.c +++ b/drivers/i2c/busses/i2c-imx.c @@ -47,6 +47,7 @@ #include <linux/sched.h> #include <linux/platform_device.h> #include <linux/clk.h> +#include <linux/slab.h> #include <mach/irqs.h> #include <mach/hardware.h> @@ -145,10 +146,10 @@ static int i2c_imx_bus_busy(struct imx_i2c_struct *i2c_imx, int for_busy) "<%s> I2C Interrupted\n", __func__); return -EINTR; } - if (time_after(jiffies, orig_jiffies + HZ / 1000)) { + if (time_after(jiffies, orig_jiffies + msecs_to_jiffies(500))) { dev_dbg(&i2c_imx->adapter.dev, "<%s> I2C bus is busy\n", __func__); - return -EIO; + return -ETIMEDOUT; } schedule(); } @@ -443,6 +444,8 @@ static int i2c_imx_xfer(struct i2c_adapter *adapter, result = i2c_imx_read(i2c_imx, &msgs[i]); else result = i2c_imx_write(i2c_imx, &msgs[i]); + if (result) + goto fail0; } fail0: diff --git a/drivers/i2c/busses/i2c-ixp2000.c b/drivers/i2c/busses/i2c-ixp2000.c index c016f7a2c5f..5d8aed5ec21 100644 --- a/drivers/i2c/busses/i2c-ixp2000.c +++ b/drivers/i2c/busses/i2c-ixp2000.c @@ -32,6 +32,7 @@ #include <linux/module.h> #include <linux/i2c.h> #include <linux/i2c-algo-bit.h> +#include <linux/slab.h> #include <mach/hardware.h> /* Pick up IXP2000-specific bits */ #include <mach/gpio.h> diff --git a/drivers/i2c/busses/i2c-mpc.c b/drivers/i2c/busses/i2c-mpc.c index 78a15af3294..e86cef300c7 100644 --- a/drivers/i2c/busses/i2c-mpc.c +++ b/drivers/i2c/busses/i2c-mpc.c @@ -19,6 +19,7 @@ #include <linux/init.h> #include <linux/of_platform.h> #include <linux/of_i2c.h> +#include <linux/slab.h> #include <linux/io.h> #include <linux/fsl_devices.h> @@ -117,7 +118,7 @@ static int i2c_wait(struct mpc_i2c *i2c, unsigned timeout, int writing) u32 x; int result = 0; - if (i2c->irq == NO_IRQ) { + if (!i2c->irq) { while (!(readb(i2c->base + MPC_I2C_SR) & CSR_MIF)) { schedule(); if (time_after(jiffies, orig_jiffies + timeout)) { @@ -567,7 +568,7 @@ static int __devinit fsl_i2c_probe(struct of_device *op, } i2c->irq = irq_of_parse_and_map(op->node, 0); - if (i2c->irq != NO_IRQ) { /* i2c->irq = NO_IRQ implies polling */ + if (i2c->irq) { /* no i2c->irq implies polling */ result = request_irq(i2c->irq, mpc_i2c_isr, IRQF_SHARED, "i2c-mpc", i2c); if (result < 0) { @@ -626,7 +627,7 @@ static int __devexit fsl_i2c_remove(struct of_device *op) i2c_del_adapter(&i2c->adap); dev_set_drvdata(&op->dev, NULL); - if (i2c->irq != NO_IRQ) + if (i2c->irq) free_irq(i2c->irq, i2c); irq_dispose_mapping(i2c->irq); diff --git a/drivers/i2c/busses/i2c-mv64xxx.c b/drivers/i2c/busses/i2c-mv64xxx.c index ed387ffa473..3623a449908 100644 --- a/drivers/i2c/busses/i2c-mv64xxx.c +++ b/drivers/i2c/busses/i2c-mv64xxx.c @@ -10,6 +10,7 @@ * or implied. */ #include <linux/kernel.h> +#include <linux/slab.h> #include <linux/module.h> #include <linux/spinlock.h> #include <linux/i2c.h> diff --git a/drivers/i2c/busses/i2c-nforce2.c b/drivers/i2c/busses/i2c-nforce2.c index 4a700587ef1..4a48dd4ef78 100644 --- a/drivers/i2c/busses/i2c-nforce2.c +++ b/drivers/i2c/busses/i2c-nforce2.c @@ -56,6 +56,7 @@ #include <linux/delay.h> #include <linux/dmi.h> #include <linux/acpi.h> +#include <linux/slab.h> #include <asm/io.h> MODULE_LICENSE("GPL"); diff --git a/drivers/i2c/busses/i2c-nomadik.c b/drivers/i2c/busses/i2c-nomadik.c index a15f731fa45..73de8ade10b 100644 --- a/drivers/i2c/busses/i2c-nomadik.c +++ b/drivers/i2c/busses/i2c-nomadik.c @@ -16,6 +16,7 @@ #include <linux/module.h> #include <linux/platform_device.h> #include <linux/delay.h> +#include <linux/slab.h> #include <linux/interrupt.h> #include <linux/i2c.h> #include <linux/err.h> @@ -703,7 +704,8 @@ static irqreturn_t i2c_irq_handler(int irq, void *arg) case I2C_IT_MTD: case I2C_IT_MTDWS: if (dev->cli.operation == I2C_READ) { - while (!readl(dev->virtbase + I2C_RISR) & I2C_IT_RXFE) { + while (!(readl(dev->virtbase + I2C_RISR) + & I2C_IT_RXFE)) { if (dev->cli.count == 0) break; *dev->cli.buffer = @@ -913,6 +915,7 @@ static int __devinit nmk_i2c_probe(struct platform_device *pdev) static int __devexit nmk_i2c_remove(struct platform_device *pdev) { + struct resource *res = platform_get_resource(pdev, IORESOURCE_MEM, 0); struct nmk_i2c_dev *dev = platform_get_drvdata(pdev); i2c_del_adapter(&dev->adap); @@ -923,6 +926,8 @@ static int __devexit nmk_i2c_remove(struct platform_device *pdev) i2c_clr_bit(dev->virtbase + I2C_CR, I2C_CR_PE); free_irq(dev->irq, dev); iounmap(dev->virtbase); + if (res) + release_mem_region(res->start, resource_size(res)); clk_disable(dev->clk); clk_put(dev->clk); platform_set_drvdata(pdev, NULL); diff --git a/drivers/i2c/busses/i2c-ocores.c b/drivers/i2c/busses/i2c-ocores.c index 0dabe643ec5..b4ed4ca802e 100644 --- a/drivers/i2c/busses/i2c-ocores.c +++ b/drivers/i2c/busses/i2c-ocores.c @@ -18,6 +18,7 @@ #include <linux/interrupt.h> #include <linux/wait.h> #include <linux/i2c-ocores.h> +#include <linux/slab.h> #include <asm/io.h> struct ocores_i2c { diff --git a/drivers/i2c/busses/i2c-octeon.c b/drivers/i2c/busses/i2c-octeon.c index 60375504fa4..0e9f85d0a83 100644 --- a/drivers/i2c/busses/i2c-octeon.c +++ b/drivers/i2c/busses/i2c-octeon.c @@ -14,6 +14,7 @@ #include <linux/kernel.h> #include <linux/module.h> #include <linux/sched.h> +#include <linux/slab.h> #include <linux/init.h> #include <linux/io.h> @@ -446,7 +447,7 @@ static struct i2c_adapter octeon_i2c_ops = { /** * octeon_i2c_setclock - Calculate and set clock divisors. */ -static int __init octeon_i2c_setclock(struct octeon_i2c *i2c) +static int __devinit octeon_i2c_setclock(struct octeon_i2c *i2c) { int tclk, thp_base, inc, thp_idx, mdiv_idx, ndiv_idx, foscl, diff; int thp = 0x18, mdiv = 2, ndiv = 0, delta_hz = 1000000; @@ -489,7 +490,7 @@ static int __init octeon_i2c_setclock(struct octeon_i2c *i2c) return 0; } -static int __init octeon_i2c_initlowlevel(struct octeon_i2c *i2c) +static int __devinit octeon_i2c_initlowlevel(struct octeon_i2c *i2c) { u8 status; int tries; diff --git a/drivers/i2c/busses/i2c-omap.c b/drivers/i2c/busses/i2c-omap.c index 913abd7c172..7674efb5537 100644 --- a/drivers/i2c/busses/i2c-omap.c +++ b/drivers/i2c/busses/i2c-omap.c @@ -37,6 +37,8 @@ #include <linux/platform_device.h> #include <linux/clk.h> #include <linux/io.h> +#include <linux/slab.h> +#include <linux/i2c-omap.h> /* I2C controller revisions */ #define OMAP_I2C_REV_2 0x20 @@ -44,29 +46,37 @@ /* I2C controller revisions present on specific hardware */ #define OMAP_I2C_REV_ON_2430 0x36 #define OMAP_I2C_REV_ON_3430 0x3C +#define OMAP_I2C_REV_ON_4430 0x40 /* timeout waiting for the controller to respond */ #define OMAP_I2C_TIMEOUT (msecs_to_jiffies(1000)) -#define OMAP_I2C_REV_REG 0x00 -#define OMAP_I2C_IE_REG 0x01 -#define OMAP_I2C_STAT_REG 0x02 -#define OMAP_I2C_IV_REG 0x03 /* For OMAP3 I2C_IV has changed to I2C_WE (wakeup enable) */ -#define OMAP_I2C_WE_REG 0x03 -#define OMAP_I2C_SYSS_REG 0x04 -#define OMAP_I2C_BUF_REG 0x05 -#define OMAP_I2C_CNT_REG 0x06 -#define OMAP_I2C_DATA_REG 0x07 -#define OMAP_I2C_SYSC_REG 0x08 -#define OMAP_I2C_CON_REG 0x09 -#define OMAP_I2C_OA_REG 0x0a -#define OMAP_I2C_SA_REG 0x0b -#define OMAP_I2C_PSC_REG 0x0c -#define OMAP_I2C_SCLL_REG 0x0d -#define OMAP_I2C_SCLH_REG 0x0e -#define OMAP_I2C_SYSTEST_REG 0x0f -#define OMAP_I2C_BUFSTAT_REG 0x10 +enum { + OMAP_I2C_REV_REG = 0, + OMAP_I2C_IE_REG, + OMAP_I2C_STAT_REG, + OMAP_I2C_IV_REG, + OMAP_I2C_WE_REG, + OMAP_I2C_SYSS_REG, + OMAP_I2C_BUF_REG, + OMAP_I2C_CNT_REG, + OMAP_I2C_DATA_REG, + OMAP_I2C_SYSC_REG, + OMAP_I2C_CON_REG, + OMAP_I2C_OA_REG, + OMAP_I2C_SA_REG, + OMAP_I2C_PSC_REG, + OMAP_I2C_SCLL_REG, + OMAP_I2C_SCLH_REG, + OMAP_I2C_SYSTEST_REG, + OMAP_I2C_BUFSTAT_REG, + OMAP_I2C_REVNB_LO, + OMAP_I2C_REVNB_HI, + OMAP_I2C_IRQSTATUS_RAW, + OMAP_I2C_IRQENABLE_SET, + OMAP_I2C_IRQENABLE_CLR, +}; /* I2C Interrupt Enable Register (OMAP_I2C_IE): */ #define OMAP_I2C_IE_XDR (1 << 14) /* TX Buffer drain int enable */ @@ -156,6 +166,9 @@ #define SYSC_IDLEMODE_SMART 0x2 #define SYSC_CLOCKACTIVITY_FCLK 0x2 +/* Errata definitions */ +#define I2C_OMAP_ERRATA_I207 (1 << 0) +#define I2C_OMAP3_1P153 (1 << 1) struct omap_i2c_dev { struct device *dev; @@ -166,9 +179,13 @@ struct omap_i2c_dev { struct clk *fclk; /* Functional clock */ struct completion cmd_complete; struct resource *ioarea; + u32 latency; /* maximum mpu wkup latency */ + void (*set_mpu_wkup_lat)(struct device *dev, + long latency); u32 speed; /* Speed of bus in Khz */ u16 cmd_err; u8 *buf; + u8 *regs; size_t buf_len; struct i2c_adapter adapter; u8 fifo_size; /* use as flag and value @@ -185,17 +202,67 @@ struct omap_i2c_dev { u16 bufstate; u16 syscstate; u16 westate; + u16 errata; +}; + +const static u8 reg_map[] = { + [OMAP_I2C_REV_REG] = 0x00, + [OMAP_I2C_IE_REG] = 0x01, + [OMAP_I2C_STAT_REG] = 0x02, + [OMAP_I2C_IV_REG] = 0x03, + [OMAP_I2C_WE_REG] = 0x03, + [OMAP_I2C_SYSS_REG] = 0x04, + [OMAP_I2C_BUF_REG] = 0x05, + [OMAP_I2C_CNT_REG] = 0x06, + [OMAP_I2C_DATA_REG] = 0x07, + [OMAP_I2C_SYSC_REG] = 0x08, + [OMAP_I2C_CON_REG] = 0x09, + [OMAP_I2C_OA_REG] = 0x0a, + [OMAP_I2C_SA_REG] = 0x0b, + [OMAP_I2C_PSC_REG] = 0x0c, + [OMAP_I2C_SCLL_REG] = 0x0d, + [OMAP_I2C_SCLH_REG] = 0x0e, + [OMAP_I2C_SYSTEST_REG] = 0x0f, + [OMAP_I2C_BUFSTAT_REG] = 0x10, +}; + +const static u8 omap4_reg_map[] = { + [OMAP_I2C_REV_REG] = 0x04, + [OMAP_I2C_IE_REG] = 0x2c, + [OMAP_I2C_STAT_REG] = 0x28, + [OMAP_I2C_IV_REG] = 0x34, + [OMAP_I2C_WE_REG] = 0x34, + [OMAP_I2C_SYSS_REG] = 0x90, + [OMAP_I2C_BUF_REG] = 0x94, + [OMAP_I2C_CNT_REG] = 0x98, + [OMAP_I2C_DATA_REG] = 0x9c, + [OMAP_I2C_SYSC_REG] = 0x20, + [OMAP_I2C_CON_REG] = 0xa4, + [OMAP_I2C_OA_REG] = 0xa8, + [OMAP_I2C_SA_REG] = 0xac, + [OMAP_I2C_PSC_REG] = 0xb0, + [OMAP_I2C_SCLL_REG] = 0xb4, + [OMAP_I2C_SCLH_REG] = 0xb8, + [OMAP_I2C_SYSTEST_REG] = 0xbC, + [OMAP_I2C_BUFSTAT_REG] = 0xc0, + [OMAP_I2C_REVNB_LO] = 0x00, + [OMAP_I2C_REVNB_HI] = 0x04, + [OMAP_I2C_IRQSTATUS_RAW] = 0x24, + [OMAP_I2C_IRQENABLE_SET] = 0x2c, + [OMAP_I2C_IRQENABLE_CLR] = 0x30, }; static inline void omap_i2c_write_reg(struct omap_i2c_dev *i2c_dev, int reg, u16 val) { - __raw_writew(val, i2c_dev->base + (reg << i2c_dev->reg_shift)); + __raw_writew(val, i2c_dev->base + + (i2c_dev->regs[reg] << i2c_dev->reg_shift)); } static inline u16 omap_i2c_read_reg(struct omap_i2c_dev *i2c_dev, int reg) { - return __raw_readw(i2c_dev->base + (reg << i2c_dev->reg_shift)); + return __raw_readw(i2c_dev->base + + (i2c_dev->regs[reg] << i2c_dev->reg_shift)); } static int __init omap_i2c_get_clocks(struct omap_i2c_dev *dev) @@ -264,7 +331,11 @@ static void omap_i2c_idle(struct omap_i2c_dev *dev) WARN_ON(dev->idle); dev->iestate = omap_i2c_read_reg(dev, OMAP_I2C_IE_REG); - omap_i2c_write_reg(dev, OMAP_I2C_IE_REG, 0); + if (dev->rev >= OMAP_I2C_REV_ON_4430) + omap_i2c_write_reg(dev, OMAP_I2C_IRQENABLE_CLR, 1); + else + omap_i2c_write_reg(dev, OMAP_I2C_IE_REG, 0); + if (dev->rev < OMAP_I2C_REV_2) { iv = omap_i2c_read_reg(dev, OMAP_I2C_IV_REG); /* Read clears */ } else { @@ -329,7 +400,9 @@ static int omap_i2c_init(struct omap_i2c_dev *dev) * REVISIT: Some wkup sources might not be needed. */ dev->westate = OMAP_I2C_WE_ALL; - omap_i2c_write_reg(dev, OMAP_I2C_WE_REG, dev->westate); + if (dev->rev < OMAP_I2C_REV_ON_4430) + omap_i2c_write_reg(dev, OMAP_I2C_WE_REG, + dev->westate); } } omap_i2c_write_reg(dev, OMAP_I2C_CON_REG, 0); @@ -356,7 +429,7 @@ static int omap_i2c_init(struct omap_i2c_dev *dev) psc = fclk_rate / 12000000; } - if (cpu_is_omap2430() || cpu_is_omap34xx()) { + if (!(cpu_class_is_omap1() || cpu_is_omap2420())) { /* * HSI2C controller internal clk rate should be 19.2 Mhz for @@ -429,6 +502,11 @@ static int omap_i2c_init(struct omap_i2c_dev *dev) /* Take the I2C module out of reset: */ omap_i2c_write_reg(dev, OMAP_I2C_CON_REG, OMAP_I2C_CON_EN); + dev->errata = 0; + + if (cpu_is_omap2430() || cpu_is_omap34xx()) + dev->errata |= I2C_OMAP_ERRATA_I207; + /* Enable interrupts */ dev->iestate = (OMAP_I2C_IE_XRDY | OMAP_I2C_IE_RRDY | OMAP_I2C_IE_ARDY | OMAP_I2C_IE_NACK | @@ -538,8 +616,12 @@ static int omap_i2c_xfer_msg(struct i2c_adapter *adap, * REVISIT: We should abort the transfer on signals, but the bus goes * into arbitration and we're currently unable to recover from it. */ + if (dev->set_mpu_wkup_lat != NULL) + dev->set_mpu_wkup_lat(dev->dev, dev->latency); r = wait_for_completion_timeout(&dev->cmd_complete, OMAP_I2C_TIMEOUT); + if (dev->set_mpu_wkup_lat != NULL) + dev->set_mpu_wkup_lat(dev->dev, -1); dev->buf_len = 0; if (r < 0) return r; @@ -622,6 +704,34 @@ omap_i2c_ack_stat(struct omap_i2c_dev *dev, u16 stat) omap_i2c_write_reg(dev, OMAP_I2C_STAT_REG, stat); } +static inline void i2c_omap_errata_i207(struct omap_i2c_dev *dev, u16 stat) +{ + /* + * I2C Errata(Errata Nos. OMAP2: 1.67, OMAP3: 1.8) + * Not applicable for OMAP4. + * Under certain rare conditions, RDR could be set again + * when the bus is busy, then ignore the interrupt and + * clear the interrupt. + */ + if (stat & OMAP_I2C_STAT_RDR) { + /* Step 1: If RDR is set, clear it */ + omap_i2c_ack_stat(dev, OMAP_I2C_STAT_RDR); + + /* Step 2: */ + if (!(omap_i2c_read_reg(dev, OMAP_I2C_STAT_REG) + & OMAP_I2C_STAT_BB)) { + + /* Step 3: */ + if (omap_i2c_read_reg(dev, OMAP_I2C_STAT_REG) + & OMAP_I2C_STAT_RDR) { + omap_i2c_ack_stat(dev, OMAP_I2C_STAT_RDR); + dev_dbg(dev->dev, "RDR when bus is busy.\n"); + } + + } + } +} + /* rev1 devices are apparently only on some 15xx */ #ifdef CONFIG_ARCH_OMAP15XX @@ -683,6 +793,35 @@ omap_i2c_rev1_isr(int this_irq, void *dev_id) #define omap_i2c_rev1_isr NULL #endif +/* + * OMAP3430 Errata 1.153: When an XRDY/XDR is hit, wait for XUDF before writing + * data to DATA_REG. Otherwise some data bytes can be lost while transferring + * them from the memory to the I2C interface. + */ +static int errata_omap3_1p153(struct omap_i2c_dev *dev, u16 *stat, int *err) +{ + unsigned long timeout = 10000; + + while (--timeout && !(*stat & OMAP_I2C_STAT_XUDF)) { + if (*stat & (OMAP_I2C_STAT_NACK | OMAP_I2C_STAT_AL)) { + omap_i2c_ack_stat(dev, *stat & (OMAP_I2C_STAT_XRDY | + OMAP_I2C_STAT_XDR)); + *err |= OMAP_I2C_STAT_XUDF; + return -ETIMEDOUT; + } + + cpu_relax(); + *stat = omap_i2c_read_reg(dev, OMAP_I2C_STAT_REG); + } + + if (!timeout) { + dev_err(dev->dev, "timeout waiting on XUDF bit\n"); + return 0; + } + + return 0; +} + static irqreturn_t omap_i2c_isr(int this_irq, void *dev_id) { @@ -732,6 +871,10 @@ complete: } if (stat & (OMAP_I2C_STAT_RRDY | OMAP_I2C_STAT_RDR)) { u8 num_bytes = 1; + + if (dev->errata & I2C_OMAP_ERRATA_I207) + i2c_omap_errata_i207(dev, stat); + if (dev->fifo_size) { if (stat & OMAP_I2C_STAT_RRDY) num_bytes = dev->fifo_size; @@ -746,9 +889,12 @@ complete: if (dev->buf_len) { *dev->buf++ = w; dev->buf_len--; - /* Data reg from 2430 is 8 bit wide */ - if (!cpu_is_omap2430() && - !cpu_is_omap34xx()) { + /* + * Data reg in 2430, omap3 and + * omap4 is 8 bit wide + */ + if (cpu_class_is_omap1() || + cpu_is_omap2420()) { if (dev->buf_len) { *dev->buf++ = w >> 8; dev->buf_len--; @@ -786,9 +932,12 @@ complete: if (dev->buf_len) { w = *dev->buf++; dev->buf_len--; - /* Data reg from 2430 is 8 bit wide */ - if (!cpu_is_omap2430() && - !cpu_is_omap34xx()) { + /* + * Data reg in 2430, omap3 and + * omap4 is 8 bit wide + */ + if (cpu_class_is_omap1() || + cpu_is_omap2420()) { if (dev->buf_len) { w |= *dev->buf++ << 8; dev->buf_len--; @@ -806,25 +955,9 @@ complete: break; } - /* - * OMAP3430 Errata 1.153: When an XRDY/XDR - * is hit, wait for XUDF before writing data - * to DATA_REG. Otherwise some data bytes can - * be lost while transferring them from the - * memory to the I2C interface. - */ - - if (dev->rev <= OMAP_I2C_REV_ON_3430) { - while (!(stat & OMAP_I2C_STAT_XUDF)) { - if (stat & (OMAP_I2C_STAT_NACK | OMAP_I2C_STAT_AL)) { - omap_i2c_ack_stat(dev, stat & (OMAP_I2C_STAT_XRDY | OMAP_I2C_STAT_XDR)); - err |= OMAP_I2C_STAT_XUDF; - goto complete; - } - cpu_relax(); - stat = omap_i2c_read_reg(dev, OMAP_I2C_STAT_REG); - } - } + if ((dev->errata & I2C_OMAP3_1P153) && + errata_omap3_1p153(dev, &stat, &err)) + goto complete; omap_i2c_write_reg(dev, OMAP_I2C_DATA_REG, w); } @@ -850,12 +983,13 @@ static const struct i2c_algorithm omap_i2c_algo = { .functionality = omap_i2c_func, }; -static int __init +static int __devinit omap_i2c_probe(struct platform_device *pdev) { struct omap_i2c_dev *dev; struct i2c_adapter *adap; struct resource *mem, *irq, *ioarea; + struct omap_i2c_bus_platform_data *pdata = pdev->dev.platform_data; irq_handler_t isr; int r; u32 speed = 0; @@ -885,10 +1019,13 @@ omap_i2c_probe(struct platform_device *pdev) goto err_release_region; } - if (pdev->dev.platform_data != NULL) - speed = *(u32 *)pdev->dev.platform_data; - else - speed = 100; /* Defualt speed */ + if (pdata != NULL) { + speed = pdata->clkrate; + dev->set_mpu_wkup_lat = pdata->set_mpu_wkup_lat; + } else { + speed = 100; /* Default speed */ + dev->set_mpu_wkup_lat = NULL; + } dev->speed = speed; dev->idle = 1; @@ -902,14 +1039,29 @@ omap_i2c_probe(struct platform_device *pdev) platform_set_drvdata(pdev, dev); + if (cpu_is_omap7xx()) + dev->reg_shift = 1; + else if (cpu_is_omap44xx()) + dev->reg_shift = 0; + else + dev->reg_shift = 2; + if ((r = omap_i2c_get_clocks(dev)) != 0) goto err_iounmap; + if (cpu_is_omap44xx()) + dev->regs = (u8 *) omap4_reg_map; + else + dev->regs = (u8 *) reg_map; + omap_i2c_unidle(dev); dev->rev = omap_i2c_read_reg(dev, OMAP_I2C_REV_REG) & 0xff; - if (cpu_is_omap2430() || cpu_is_omap34xx()) { + if (dev->rev <= OMAP_I2C_REV_ON_3430) + dev->errata |= I2C_OMAP3_1P153; + + if (!(cpu_class_is_omap1() || cpu_is_omap2420())) { u16 s; /* Set up the fifo size - Get total size */ @@ -921,15 +1073,19 @@ omap_i2c_probe(struct platform_device *pdev) * size. This is to ensure that we can handle the status on int * call back latencies. */ - dev->fifo_size = (dev->fifo_size / 2); - dev->b_hw = 1; /* Enable hardware fixes */ + if (dev->rev >= OMAP_I2C_REV_ON_4430) { + dev->fifo_size = 0; + dev->b_hw = 0; /* Disable hardware fixes */ + } else { + dev->fifo_size = (dev->fifo_size / 2); + dev->b_hw = 1; /* Enable hardware fixes */ + } + /* calculate wakeup latency constraint for MPU */ + if (dev->set_mpu_wkup_lat != NULL) + dev->latency = (1000000 * dev->fifo_size) / + (1000 * speed / 8); } - if (cpu_is_omap7xx()) - dev->reg_shift = 1; - else - dev->reg_shift = 2; - /* reset ASAP, clearing any IRQs */ omap_i2c_init(dev); diff --git a/drivers/i2c/busses/i2c-parport.c b/drivers/i2c/busses/i2c-parport.c index 220fca7f23a..846583ed476 100644 --- a/drivers/i2c/busses/i2c-parport.c +++ b/drivers/i2c/busses/i2c-parport.c @@ -32,6 +32,7 @@ #include <linux/i2c.h> #include <linux/i2c-algo-bit.h> #include <linux/i2c-smbus.h> +#include <linux/slab.h> #include "i2c-parport.h" /* ----- Device list ------------------------------------------------------ */ diff --git a/drivers/i2c/busses/i2c-pasemi.c b/drivers/i2c/busses/i2c-pasemi.c index 0d20ff46a51..d3d4a4b43a1 100644 --- a/drivers/i2c/busses/i2c-pasemi.c +++ b/drivers/i2c/busses/i2c-pasemi.c @@ -24,6 +24,7 @@ #include <linux/sched.h> #include <linux/i2c.h> #include <linux/delay.h> +#include <linux/slab.h> #include <asm/io.h> static struct pci_driver pasemi_smb_driver; diff --git a/drivers/i2c/busses/i2c-pnx.c b/drivers/i2c/busses/i2c-pnx.c index 9532dee6b58..a97e3fec814 100644 --- a/drivers/i2c/busses/i2c-pnx.c +++ b/drivers/i2c/busses/i2c-pnx.c @@ -22,6 +22,7 @@ #include <linux/io.h> #include <linux/err.h> #include <linux/clk.h> +#include <linux/slab.h> #include <mach/hardware.h> #include <mach/i2c.h> @@ -172,6 +173,9 @@ static int i2c_pnx_master_xmit(struct i2c_pnx_algo_data *alg_data) /* We still have something to talk about... */ val = *alg_data->mif.buf++; + if (alg_data->mif.len == 1) + val |= stop_bit; + alg_data->mif.len--; iowrite32(val, I2C_REG_TX(alg_data)); @@ -245,6 +249,9 @@ static int i2c_pnx_master_rcv(struct i2c_pnx_algo_data *alg_data) __func__); if (alg_data->mif.len == 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) @@ -632,6 +639,8 @@ static int __devinit i2c_pnx_probe(struct platform_device *pdev) */ tmp = ((freq / 1000) / I2C_PNX_SPEED_KHZ) / 2 - 2; + if (tmp > 0x3FF) + tmp = 0x3FF; iowrite32(tmp, I2C_REG_CKH(alg_data)); iowrite32(tmp, I2C_REG_CKL(alg_data)); diff --git a/drivers/i2c/busses/i2c-powermac.c b/drivers/i2c/busses/i2c-powermac.c index 1c440a70ec6..b289ec99eeb 100644 --- a/drivers/i2c/busses/i2c-powermac.c +++ b/drivers/i2c/busses/i2c-powermac.c @@ -122,9 +122,14 @@ static s32 i2c_powermac_smbus_xfer( struct i2c_adapter* adap, rc = pmac_i2c_xfer(bus, addrdir, subsize, subaddr, buf, len); if (rc) { - dev_err(&adap->dev, - "I2C transfer at 0x%02x failed, size %d, err %d\n", - addrdir >> 1, size, rc); + if (rc == -ENXIO) + dev_dbg(&adap->dev, + "I2C transfer at 0x%02x failed, size %d, " + "err %d\n", addrdir >> 1, size, rc); + else + dev_err(&adap->dev, + "I2C transfer at 0x%02x failed, size %d, " + "err %d\n", addrdir >> 1, size, rc); goto bail; } @@ -175,10 +180,16 @@ static int i2c_powermac_master_xfer( struct i2c_adapter *adap, goto bail; } rc = pmac_i2c_xfer(bus, addrdir, 0, 0, msgs->buf, msgs->len); - if (rc < 0) - dev_err(&adap->dev, "I2C %s 0x%02x failed, err %d\n", - addrdir & 1 ? "read from" : "write to", addrdir >> 1, - rc); + if (rc < 0) { + if (rc == -ENXIO) + dev_dbg(&adap->dev, "I2C %s 0x%02x failed, err %d\n", + addrdir & 1 ? "read from" : "write to", + addrdir >> 1, rc); + else + dev_err(&adap->dev, "I2C %s 0x%02x failed, err %d\n", + addrdir & 1 ? "read from" : "write to", + addrdir >> 1, rc); + } bail: pmac_i2c_close(bus); return rc < 0 ? rc : 1; diff --git a/drivers/i2c/busses/i2c-pxa.c b/drivers/i2c/busses/i2c-pxa.c index 7647a20523a..fbde6f61405 100644 --- a/drivers/i2c/busses/i2c-pxa.c +++ b/drivers/i2c/busses/i2c-pxa.c @@ -12,7 +12,7 @@ * * History: * Apr 2002: Initial version [CS] - * Jun 2002: Properly seperated algo/adap [FB] + * Jun 2002: Properly separated algo/adap [FB] * Jan 2003: Fixed several bugs concerning interrupt handling [Kai-Uwe Bloem] * Jan 2003: added limited signal handling [Kai-Uwe Bloem] * Sep 2004: Major rework to ensure efficient bus handling [RMK] @@ -33,6 +33,7 @@ #include <linux/platform_device.h> #include <linux/err.h> #include <linux/clk.h> +#include <linux/slab.h> #include <asm/irq.h> #include <asm/io.h> @@ -208,18 +209,6 @@ static void i2c_pxa_show_state(struct pxa_i2c *i2c, int lno, const char *fname) } #define show_state(i2c) i2c_pxa_show_state(i2c, __LINE__, __func__) -#else -#define i2c_debug 0 - -#define show_state(i2c) do { } while (0) -#define decode_ISR(val) do { } while (0) -#define decode_ICR(val) do { } while (0) -#endif - -#define eedbg(lvl, x...) do { if ((lvl) < 1) { printk(KERN_DEBUG "" x); } } while(0) - -static void i2c_pxa_master_complete(struct pxa_i2c *i2c, int ret); -static irqreturn_t i2c_pxa_handler(int this_irq, void *dev_id); static void i2c_pxa_scream_blue_murder(struct pxa_i2c *i2c, const char *why) { @@ -235,6 +224,20 @@ static void i2c_pxa_scream_blue_murder(struct pxa_i2c *i2c, const char *why) printk("\n"); } +#else /* ifdef DEBUG */ + +#define i2c_debug 0 + +#define show_state(i2c) do { } while (0) +#define decode_ISR(val) do { } while (0) +#define decode_ICR(val) do { } while (0) +#define i2c_pxa_scream_blue_murder(i2c, why) do { } while (0) + +#endif /* ifdef DEBUG / else */ + +static void i2c_pxa_master_complete(struct pxa_i2c *i2c, int ret); +static irqreturn_t i2c_pxa_handler(int this_irq, void *dev_id); + static inline int i2c_pxa_is_slavemode(struct pxa_i2c *i2c) { return !(readl(_ICR(i2c)) & ICR_SCLE); diff --git a/drivers/i2c/busses/i2c-s3c2410.c b/drivers/i2c/busses/i2c-s3c2410.c index 1d8c98613fa..ec3256cce91 100644 --- a/drivers/i2c/busses/i2c-s3c2410.c +++ b/drivers/i2c/busses/i2c-s3c2410.c @@ -34,6 +34,7 @@ #include <linux/platform_device.h> #include <linux/clk.h> #include <linux/cpufreq.h> +#include <linux/slab.h> #include <asm/irq.h> #include <asm/io.h> @@ -481,7 +482,8 @@ static int s3c24xx_i2c_set_master(struct s3c24xx_i2c *i2c) static int s3c24xx_i2c_doxfer(struct s3c24xx_i2c *i2c, struct i2c_msg *msgs, int num) { - unsigned long timeout; + unsigned long iicstat, timeout; + int spins = 20; int ret; if (i2c->suspended) @@ -520,7 +522,21 @@ static int s3c24xx_i2c_doxfer(struct s3c24xx_i2c *i2c, /* ensure the stop has been through the bus */ - msleep(1); + dev_dbg(i2c->dev, "waiting for bus idle\n"); + + /* first, try busy waiting briefly */ + do { + iicstat = readl(i2c->regs + S3C2410_IICSTAT); + } while ((iicstat & S3C2410_IICSTAT_START) && --spins); + + /* if that timed out sleep */ + if (!spins) { + msleep(1); + iicstat = readl(i2c->regs + S3C2410_IICSTAT); + } + + if (iicstat & S3C2410_IICSTAT_START) + dev_warn(i2c->dev, "timeout waiting for bus idle\n"); out: return ret; diff --git a/drivers/i2c/busses/i2c-scmi.c b/drivers/i2c/busses/i2c-scmi.c index 365e0becaf1..388cbdc96db 100644 --- a/drivers/i2c/busses/i2c-scmi.c +++ b/drivers/i2c/busses/i2c-scmi.c @@ -33,6 +33,7 @@ struct acpi_smbus_cmi { u8 cap_info:1; u8 cap_read:1; u8 cap_write:1; + struct smbus_methods_t *methods; }; static const struct smbus_methods_t smbus_methods = { @@ -41,10 +42,19 @@ static const struct smbus_methods_t smbus_methods = { .mt_sbw = "_SBW", }; +/* Some IBM BIOSes omit the leading underscore */ +static const struct smbus_methods_t ibm_smbus_methods = { + .mt_info = "SBI_", + .mt_sbr = "SBR_", + .mt_sbw = "SBW_", +}; + static const struct acpi_device_id acpi_smbus_cmi_ids[] = { - {"SMBUS01", 0}, + {"SMBUS01", (kernel_ulong_t)&smbus_methods}, + {ACPI_SMBUS_IBM_HID, (kernel_ulong_t)&ibm_smbus_methods}, {"", 0} }; +MODULE_DEVICE_TABLE(acpi, acpi_smbus_cmi_ids); #define ACPI_SMBUS_STATUS_OK 0x00 #define ACPI_SMBUS_STATUS_FAIL 0x07 @@ -150,11 +160,11 @@ acpi_smbus_cmi_access(struct i2c_adapter *adap, u16 addr, unsigned short flags, if (read_write == I2C_SMBUS_READ) { protocol |= ACPI_SMBUS_PRTCL_READ; - method = smbus_methods.mt_sbr; + method = smbus_cmi->methods->mt_sbr; input.count = 3; } else { protocol |= ACPI_SMBUS_PRTCL_WRITE; - method = smbus_methods.mt_sbw; + method = smbus_cmi->methods->mt_sbw; input.count = 5; } @@ -290,13 +300,13 @@ static int acpi_smbus_cmi_add_cap(struct acpi_smbus_cmi *smbus_cmi, union acpi_object *obj; acpi_status status; - if (!strcmp(name, smbus_methods.mt_info)) { + if (!strcmp(name, smbus_cmi->methods->mt_info)) { status = acpi_evaluate_object(smbus_cmi->handle, - smbus_methods.mt_info, + smbus_cmi->methods->mt_info, NULL, &buffer); if (ACPI_FAILURE(status)) { ACPI_ERROR((AE_INFO, "Evaluating %s: %i", - smbus_methods.mt_info, status)); + smbus_cmi->methods->mt_info, status)); return -EIO; } @@ -319,9 +329,9 @@ static int acpi_smbus_cmi_add_cap(struct acpi_smbus_cmi *smbus_cmi, kfree(buffer.pointer); smbus_cmi->cap_info = 1; - } else if (!strcmp(name, smbus_methods.mt_sbr)) + } else if (!strcmp(name, smbus_cmi->methods->mt_sbr)) smbus_cmi->cap_read = 1; - else if (!strcmp(name, smbus_methods.mt_sbw)) + else if (!strcmp(name, smbus_cmi->methods->mt_sbw)) smbus_cmi->cap_write = 1; else ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Unsupported CMI method: %s\n", @@ -349,6 +359,7 @@ static acpi_status acpi_smbus_cmi_query_methods(acpi_handle handle, u32 level, static int acpi_smbus_cmi_add(struct acpi_device *device) { struct acpi_smbus_cmi *smbus_cmi; + const struct acpi_device_id *id; smbus_cmi = kzalloc(sizeof(struct acpi_smbus_cmi), GFP_KERNEL); if (!smbus_cmi) @@ -362,6 +373,11 @@ static int acpi_smbus_cmi_add(struct acpi_device *device) smbus_cmi->cap_read = 0; smbus_cmi->cap_write = 0; + for (id = acpi_smbus_cmi_ids; id->id[0]; id++) + if (!strcmp(id->id, acpi_device_hid(device))) + smbus_cmi->methods = + (struct smbus_methods_t *) id->driver_data; + acpi_walk_namespace(ACPI_TYPE_METHOD, smbus_cmi->handle, 1, acpi_smbus_cmi_query_methods, NULL, smbus_cmi, NULL); diff --git a/drivers/i2c/busses/i2c-sh_mobile.c b/drivers/i2c/busses/i2c-sh_mobile.c index ccc46418ef7..ffb405d7c6f 100644 --- a/drivers/i2c/busses/i2c-sh_mobile.c +++ b/drivers/i2c/busses/i2c-sh_mobile.c @@ -31,6 +31,7 @@ #include <linux/pm_runtime.h> #include <linux/clk.h> #include <linux/io.h> +#include <linux/slab.h> /* Transmit operation: */ /* */ diff --git a/drivers/i2c/busses/i2c-simtec.c b/drivers/i2c/busses/i2c-simtec.c index 6407f47bda8..78b06107342 100644 --- a/drivers/i2c/busses/i2c-simtec.c +++ b/drivers/i2c/busses/i2c-simtec.c @@ -23,6 +23,7 @@ #include <linux/init.h> #include <linux/delay.h> #include <linux/platform_device.h> +#include <linux/slab.h> #include <linux/i2c.h> #include <linux/i2c-algo-bit.h> diff --git a/drivers/i2c/busses/i2c-stu300.c b/drivers/i2c/busses/i2c-stu300.c index d2728a28a8d..495be451d32 100644 --- a/drivers/i2c/busses/i2c-stu300.c +++ b/drivers/i2c/busses/i2c-stu300.c @@ -16,6 +16,7 @@ #include <linux/interrupt.h> #include <linux/clk.h> #include <linux/io.h> +#include <linux/slab.h> /* the name of this kernel module */ #define NAME "stu300" @@ -497,7 +498,7 @@ static int stu300_set_clk(struct stu300_dev *dev, unsigned long clkrate) int i = 0; /* Locate the apropriate clock setting */ - while (i < ARRAY_SIZE(stu300_clktable) && + while (i < ARRAY_SIZE(stu300_clktable) - 1 && stu300_clktable[i].rate < clkrate) i++; diff --git a/drivers/i2c/busses/i2c-tiny-usb.c b/drivers/i2c/busses/i2c-tiny-usb.c index b5b1bbf37d3..d03b04002f0 100644 --- a/drivers/i2c/busses/i2c-tiny-usb.c +++ b/drivers/i2c/busses/i2c-tiny-usb.c @@ -13,6 +13,7 @@ #include <linux/kernel.h> #include <linux/errno.h> #include <linux/module.h> +#include <linux/slab.h> #include <linux/types.h> /* include interfaces to usb layer */ diff --git a/drivers/i2c/busses/i2c-versatile.c b/drivers/i2c/busses/i2c-versatile.c index 70de8216346..5c473833d94 100644 --- a/drivers/i2c/busses/i2c-versatile.c +++ b/drivers/i2c/busses/i2c-versatile.c @@ -14,6 +14,7 @@ #include <linux/i2c-algo-bit.h> #include <linux/init.h> #include <linux/platform_device.h> +#include <linux/slab.h> #include <asm/io.h> diff --git a/drivers/i2c/busses/i2c-xiic.c b/drivers/i2c/busses/i2c-xiic.c index eece39a5a30..a9c419e075a 100644 --- a/drivers/i2c/busses/i2c-xiic.c +++ b/drivers/i2c/busses/i2c-xiic.c @@ -32,12 +32,14 @@ #include <linux/module.h> #include <linux/init.h> #include <linux/errno.h> +#include <linux/delay.h> #include <linux/platform_device.h> #include <linux/i2c.h> #include <linux/interrupt.h> #include <linux/wait.h> #include <linux/i2c-xiic.h> #include <linux/io.h> +#include <linux/slab.h> #define DRIVER_NAME "xiic-i2c" diff --git a/drivers/i2c/busses/scx200_acb.c b/drivers/i2c/busses/scx200_acb.c index cf994bd01d9..684395b6f3e 100644 --- a/drivers/i2c/busses/scx200_acb.c +++ b/drivers/i2c/busses/scx200_acb.c @@ -31,6 +31,7 @@ #include <linux/pci.h> #include <linux/delay.h> #include <linux/mutex.h> +#include <linux/slab.h> #include <asm/io.h> #include <linux/scx200.h> diff --git a/drivers/i2c/chips/Kconfig b/drivers/i2c/chips/Kconfig deleted file mode 100644 index ae4539d99be..00000000000 --- a/drivers/i2c/chips/Kconfig +++ /dev/null @@ -1,19 +0,0 @@ -# -# Miscellaneous I2C chip drivers configuration -# -# *** DEPRECATED! Do not add new entries! See Makefile *** -# - -menu "Miscellaneous I2C Chip support" - -config SENSORS_TSL2550 - tristate "Taos TSL2550 ambient light sensor" - depends on EXPERIMENTAL - help - If you say yes here you get support for the Taos TSL2550 - ambient light sensor. - - This driver can also be built as a module. If so, the module - will be called tsl2550. - -endmenu diff --git a/drivers/i2c/chips/Makefile b/drivers/i2c/chips/Makefile deleted file mode 100644 index fe0af0f81f2..00000000000 --- a/drivers/i2c/chips/Makefile +++ /dev/null @@ -1,18 +0,0 @@ -# -# Makefile for miscellaneous I2C chip drivers. -# -# Do not add new drivers to this directory! It is DEPRECATED. -# -# Device drivers are better grouped according to the functionality they -# implement rather than to the bus they are connected to. In particular: -# * Hardware monitoring chip drivers go to drivers/hwmon -# * RTC chip drivers go to drivers/rtc -# * I/O expander drivers go to drivers/gpio -# - -obj-$(CONFIG_SENSORS_TSL2550) += tsl2550.o - -ifeq ($(CONFIG_I2C_DEBUG_CHIP),y) -EXTRA_CFLAGS += -DDEBUG -endif - diff --git a/drivers/i2c/chips/tsl2550.c b/drivers/i2c/chips/tsl2550.c deleted file mode 100644 index a0702f36a72..00000000000 --- a/drivers/i2c/chips/tsl2550.c +++ /dev/null @@ -1,473 +0,0 @@ -/* - * tsl2550.c - Linux kernel modules for ambient light sensor - * - * Copyright (C) 2007 Rodolfo Giometti <giometti@linux.it> - * Copyright (C) 2007 Eurotech S.p.A. <info@eurotech.it> - * - * 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/module.h> -#include <linux/init.h> -#include <linux/slab.h> -#include <linux/i2c.h> -#include <linux/mutex.h> - -#define TSL2550_DRV_NAME "tsl2550" -#define DRIVER_VERSION "1.2" - -/* - * Defines - */ - -#define TSL2550_POWER_DOWN 0x00 -#define TSL2550_POWER_UP 0x03 -#define TSL2550_STANDARD_RANGE 0x18 -#define TSL2550_EXTENDED_RANGE 0x1d -#define TSL2550_READ_ADC0 0x43 -#define TSL2550_READ_ADC1 0x83 - -/* - * Structs - */ - -struct tsl2550_data { - struct i2c_client *client; - struct mutex update_lock; - - unsigned int power_state : 1; - unsigned int operating_mode : 1; -}; - -/* - * Global data - */ - -static const u8 TSL2550_MODE_RANGE[2] = { - TSL2550_STANDARD_RANGE, TSL2550_EXTENDED_RANGE, -}; - -/* - * Management functions - */ - -static int tsl2550_set_operating_mode(struct i2c_client *client, int mode) -{ - struct tsl2550_data *data = i2c_get_clientdata(client); - - int ret = i2c_smbus_write_byte(client, TSL2550_MODE_RANGE[mode]); - - data->operating_mode = mode; - - return ret; -} - -static int tsl2550_set_power_state(struct i2c_client *client, int state) -{ - struct tsl2550_data *data = i2c_get_clientdata(client); - int ret; - - if (state == 0) - ret = i2c_smbus_write_byte(client, TSL2550_POWER_DOWN); - else { - ret = i2c_smbus_write_byte(client, TSL2550_POWER_UP); - - /* On power up we should reset operating mode also... */ - tsl2550_set_operating_mode(client, data->operating_mode); - } - - data->power_state = state; - - return ret; -} - -static int tsl2550_get_adc_value(struct i2c_client *client, u8 cmd) -{ - int ret; - - ret = i2c_smbus_read_byte_data(client, cmd); - if (ret < 0) - return ret; - if (!(ret & 0x80)) - return -EAGAIN; - return ret & 0x7f; /* remove the "valid" bit */ -} - -/* - * LUX calculation - */ - -#define TSL2550_MAX_LUX 1846 - -static const u8 ratio_lut[] = { - 100, 100, 100, 100, 100, 100, 100, 100, - 100, 100, 100, 100, 100, 100, 99, 99, - 99, 99, 99, 99, 99, 99, 99, 99, - 99, 99, 99, 98, 98, 98, 98, 98, - 98, 98, 97, 97, 97, 97, 97, 96, - 96, 96, 96, 95, 95, 95, 94, 94, - 93, 93, 93, 92, 92, 91, 91, 90, - 89, 89, 88, 87, 87, 86, 85, 84, - 83, 82, 81, 80, 79, 78, 77, 75, - 74, 73, 71, 69, 68, 66, 64, 62, - 60, 58, 56, 54, 52, 49, 47, 44, - 42, 41, 40, 40, 39, 39, 38, 38, - 37, 37, 37, 36, 36, 36, 35, 35, - 35, 35, 34, 34, 34, 34, 33, 33, - 33, 33, 32, 32, 32, 32, 32, 31, - 31, 31, 31, 31, 30, 30, 30, 30, - 30, -}; - -static const u16 count_lut[] = { - 0, 1, 2, 3, 4, 5, 6, 7, - 8, 9, 10, 11, 12, 13, 14, 15, - 16, 18, 20, 22, 24, 26, 28, 30, - 32, 34, 36, 38, 40, 42, 44, 46, - 49, 53, 57, 61, 65, 69, 73, 77, - 81, 85, 89, 93, 97, 101, 105, 109, - 115, 123, 131, 139, 147, 155, 163, 171, - 179, 187, 195, 203, 211, 219, 227, 235, - 247, 263, 279, 295, 311, 327, 343, 359, - 375, 391, 407, 423, 439, 455, 471, 487, - 511, 543, 575, 607, 639, 671, 703, 735, - 767, 799, 831, 863, 895, 927, 959, 991, - 1039, 1103, 1167, 1231, 1295, 1359, 1423, 1487, - 1551, 1615, 1679, 1743, 1807, 1871, 1935, 1999, - 2095, 2223, 2351, 2479, 2607, 2735, 2863, 2991, - 3119, 3247, 3375, 3503, 3631, 3759, 3887, 4015, -}; - -/* - * This function is described into Taos TSL2550 Designer's Notebook - * pages 2, 3. - */ -static int tsl2550_calculate_lux(u8 ch0, u8 ch1) -{ - unsigned int lux; - - /* Look up count from channel values */ - u16 c0 = count_lut[ch0]; - u16 c1 = count_lut[ch1]; - - /* - * Calculate ratio. - * Note: the "128" is a scaling factor - */ - u8 r = 128; - - /* Avoid division by 0 and count 1 cannot be greater than count 0 */ - if (c1 <= c0) - if (c0) { - r = c1 * 128 / c0; - - /* Calculate LUX */ - lux = ((c0 - c1) * ratio_lut[r]) / 256; - } else - lux = 0; - else - return -EAGAIN; - - /* LUX range check */ - return lux > TSL2550_MAX_LUX ? TSL2550_MAX_LUX : lux; -} - -/* - * SysFS support - */ - -static ssize_t tsl2550_show_power_state(struct device *dev, - struct device_attribute *attr, char *buf) -{ - struct tsl2550_data *data = i2c_get_clientdata(to_i2c_client(dev)); - - return sprintf(buf, "%u\n", data->power_state); -} - -static ssize_t tsl2550_store_power_state(struct device *dev, - struct device_attribute *attr, const char *buf, size_t count) -{ - struct i2c_client *client = to_i2c_client(dev); - struct tsl2550_data *data = i2c_get_clientdata(client); - unsigned long val = simple_strtoul(buf, NULL, 10); - int ret; - - if (val < 0 || val > 1) - return -EINVAL; - - mutex_lock(&data->update_lock); - ret = tsl2550_set_power_state(client, val); - mutex_unlock(&data->update_lock); - - if (ret < 0) - return ret; - - return count; -} - -static DEVICE_ATTR(power_state, S_IWUSR | S_IRUGO, - tsl2550_show_power_state, tsl2550_store_power_state); - -static ssize_t tsl2550_show_operating_mode(struct device *dev, - struct device_attribute *attr, char *buf) -{ - struct tsl2550_data *data = i2c_get_clientdata(to_i2c_client(dev)); - - return sprintf(buf, "%u\n", data->operating_mode); -} - -static ssize_t tsl2550_store_operating_mode(struct device *dev, - struct device_attribute *attr, const char *buf, size_t count) -{ - struct i2c_client *client = to_i2c_client(dev); - struct tsl2550_data *data = i2c_get_clientdata(client); - unsigned long val = simple_strtoul(buf, NULL, 10); - int ret; - - if (val < 0 || val > 1) - return -EINVAL; - - if (data->power_state == 0) - return -EBUSY; - - mutex_lock(&data->update_lock); - ret = tsl2550_set_operating_mode(client, val); - mutex_unlock(&data->update_lock); - - if (ret < 0) - return ret; - - return count; -} - -static DEVICE_ATTR(operating_mode, S_IWUSR | S_IRUGO, - tsl2550_show_operating_mode, tsl2550_store_operating_mode); - -static ssize_t __tsl2550_show_lux(struct i2c_client *client, char *buf) -{ - struct tsl2550_data *data = i2c_get_clientdata(client); - u8 ch0, ch1; - int ret; - - ret = tsl2550_get_adc_value(client, TSL2550_READ_ADC0); - if (ret < 0) - return ret; - ch0 = ret; - - ret = tsl2550_get_adc_value(client, TSL2550_READ_ADC1); - if (ret < 0) - return ret; - ch1 = ret; - - /* Do the job */ - ret = tsl2550_calculate_lux(ch0, ch1); - if (ret < 0) - return ret; - if (data->operating_mode == 1) - ret *= 5; - - return sprintf(buf, "%d\n", ret); -} - -static ssize_t tsl2550_show_lux1_input(struct device *dev, - struct device_attribute *attr, char *buf) -{ - struct i2c_client *client = to_i2c_client(dev); - struct tsl2550_data *data = i2c_get_clientdata(client); - int ret; - - /* No LUX data if not operational */ - if (!data->power_state) - return -EBUSY; - - mutex_lock(&data->update_lock); - ret = __tsl2550_show_lux(client, buf); - mutex_unlock(&data->update_lock); - - return ret; -} - -static DEVICE_ATTR(lux1_input, S_IRUGO, - tsl2550_show_lux1_input, NULL); - -static struct attribute *tsl2550_attributes[] = { - &dev_attr_power_state.attr, - &dev_attr_operating_mode.attr, - &dev_attr_lux1_input.attr, - NULL -}; - -static const struct attribute_group tsl2550_attr_group = { - .attrs = tsl2550_attributes, -}; - -/* - * Initialization function - */ - -static int tsl2550_init_client(struct i2c_client *client) -{ - struct tsl2550_data *data = i2c_get_clientdata(client); - int err; - - /* - * Probe the chip. To do so we try to power up the device and then to - * read back the 0x03 code - */ - err = i2c_smbus_read_byte_data(client, TSL2550_POWER_UP); - if (err < 0) - return err; - if (err != TSL2550_POWER_UP) - return -ENODEV; - data->power_state = 1; - - /* Set the default operating mode */ - err = i2c_smbus_write_byte(client, - TSL2550_MODE_RANGE[data->operating_mode]); - if (err < 0) - return err; - - return 0; -} - -/* - * I2C init/probing/exit functions - */ - -static struct i2c_driver tsl2550_driver; -static int __devinit tsl2550_probe(struct i2c_client *client, - const struct i2c_device_id *id) -{ - struct i2c_adapter *adapter = to_i2c_adapter(client->dev.parent); - struct tsl2550_data *data; - int *opmode, err = 0; - - if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_WRITE_BYTE - | I2C_FUNC_SMBUS_READ_BYTE_DATA)) { - err = -EIO; - goto exit; - } - - data = kzalloc(sizeof(struct tsl2550_data), GFP_KERNEL); - if (!data) { - err = -ENOMEM; - goto exit; - } - data->client = client; - i2c_set_clientdata(client, data); - - /* Check platform data */ - opmode = client->dev.platform_data; - if (opmode) { - if (*opmode < 0 || *opmode > 1) { - dev_err(&client->dev, "invalid operating_mode (%d)\n", - *opmode); - err = -EINVAL; - goto exit_kfree; - } - data->operating_mode = *opmode; - } else - data->operating_mode = 0; /* default mode is standard */ - dev_info(&client->dev, "%s operating mode\n", - data->operating_mode ? "extended" : "standard"); - - mutex_init(&data->update_lock); - - /* Initialize the TSL2550 chip */ - err = tsl2550_init_client(client); - if (err) - goto exit_kfree; - - /* Register sysfs hooks */ - err = sysfs_create_group(&client->dev.kobj, &tsl2550_attr_group); - if (err) - goto exit_kfree; - - dev_info(&client->dev, "support ver. %s enabled\n", DRIVER_VERSION); - - return 0; - -exit_kfree: - kfree(data); -exit: - return err; -} - -static int __devexit tsl2550_remove(struct i2c_client *client) -{ - sysfs_remove_group(&client->dev.kobj, &tsl2550_attr_group); - - /* Power down the device */ - tsl2550_set_power_state(client, 0); - - kfree(i2c_get_clientdata(client)); - - return 0; -} - -#ifdef CONFIG_PM - -static int tsl2550_suspend(struct i2c_client *client, pm_message_t mesg) -{ - return tsl2550_set_power_state(client, 0); -} - -static int tsl2550_resume(struct i2c_client *client) -{ - return tsl2550_set_power_state(client, 1); -} - -#else - -#define tsl2550_suspend NULL -#define tsl2550_resume NULL - -#endif /* CONFIG_PM */ - -static const struct i2c_device_id tsl2550_id[] = { - { "tsl2550", 0 }, - { } -}; -MODULE_DEVICE_TABLE(i2c, tsl2550_id); - -static struct i2c_driver tsl2550_driver = { - .driver = { - .name = TSL2550_DRV_NAME, - .owner = THIS_MODULE, - }, - .suspend = tsl2550_suspend, - .resume = tsl2550_resume, - .probe = tsl2550_probe, - .remove = __devexit_p(tsl2550_remove), - .id_table = tsl2550_id, -}; - -static int __init tsl2550_init(void) -{ - return i2c_add_driver(&tsl2550_driver); -} - -static void __exit tsl2550_exit(void) -{ - i2c_del_driver(&tsl2550_driver); -} - -MODULE_AUTHOR("Rodolfo Giometti <giometti@linux.it>"); -MODULE_DESCRIPTION("TSL2550 ambient light sensor driver"); -MODULE_LICENSE("GPL"); -MODULE_VERSION(DRIVER_VERSION); - -module_init(tsl2550_init); -module_exit(tsl2550_exit); diff --git a/drivers/i2c/i2c-boardinfo.c b/drivers/i2c/i2c-boardinfo.c index a26a34a0664..7e6a63b5716 100644 --- a/drivers/i2c/i2c-boardinfo.c +++ b/drivers/i2c/i2c-boardinfo.c @@ -18,6 +18,7 @@ #include <linux/kernel.h> #include <linux/i2c.h> +#include <linux/slab.h> #include <linux/rwsem.h> #include "i2c-core.h" diff --git a/drivers/i2c/i2c-core.c b/drivers/i2c/i2c-core.c index 3202a86f420..7c469a62c3c 100644 --- a/drivers/i2c/i2c-core.c +++ b/drivers/i2c/i2c-core.c @@ -40,12 +40,11 @@ #include "i2c-core.h" -/* core_lock protects i2c_adapter_idr, userspace_devices, and guarantees +/* core_lock protects i2c_adapter_idr, and guarantees that device detection, deletion of detected devices, and attach_adapter and detach_adapter calls are serialized */ static DEFINE_MUTEX(core_lock); static DEFINE_IDR(i2c_adapter_idr); -static LIST_HEAD(userspace_devices); static struct device_type i2c_client_type; static int i2c_check_addr(struct i2c_adapter *adapter, int addr); @@ -117,8 +116,10 @@ static int i2c_device_probe(struct device *dev) dev_dbg(dev, "probe\n"); status = driver->probe(client, i2c_match_id(driver->id_table, client)); - if (status) + if (status) { client->driver = NULL; + i2c_set_clientdata(client, NULL); + } return status; } @@ -139,8 +140,10 @@ static int i2c_device_remove(struct device *dev) dev->driver = NULL; status = 0; } - if (status == 0) + if (status == 0) { client->driver = NULL; + i2c_set_clientdata(client, NULL); + } return status; } @@ -156,106 +159,130 @@ static void i2c_device_shutdown(struct device *dev) driver->shutdown(client); } -#ifdef CONFIG_SUSPEND -static int i2c_device_pm_suspend(struct device *dev) +#ifdef CONFIG_PM_SLEEP +static int i2c_legacy_suspend(struct device *dev, pm_message_t mesg) { - const struct dev_pm_ops *pm; + struct i2c_client *client = i2c_verify_client(dev); + struct i2c_driver *driver; - if (!dev->driver) + if (!client || !dev->driver) return 0; - pm = dev->driver->pm; - if (!pm || !pm->suspend) + driver = to_i2c_driver(dev->driver); + if (!driver->suspend) return 0; - return pm->suspend(dev); + return driver->suspend(client, mesg); } -static int i2c_device_pm_resume(struct device *dev) +static int i2c_legacy_resume(struct device *dev) { - const struct dev_pm_ops *pm; + struct i2c_client *client = i2c_verify_client(dev); + struct i2c_driver *driver; - if (!dev->driver) + if (!client || !dev->driver) return 0; - pm = dev->driver->pm; - if (!pm || !pm->resume) + driver = to_i2c_driver(dev->driver); + if (!driver->resume) return 0; - return pm->resume(dev); + return driver->resume(client); } -#else -#define i2c_device_pm_suspend NULL -#define i2c_device_pm_resume NULL -#endif -#ifdef CONFIG_PM_RUNTIME -static int i2c_device_runtime_suspend(struct device *dev) +static int i2c_device_pm_suspend(struct device *dev) { - const struct dev_pm_ops *pm; + const struct dev_pm_ops *pm = dev->driver ? dev->driver->pm : NULL; - if (!dev->driver) + if (pm_runtime_suspended(dev)) return 0; - pm = dev->driver->pm; - if (!pm || !pm->runtime_suspend) - return 0; - return pm->runtime_suspend(dev); -} -static int i2c_device_runtime_resume(struct device *dev) -{ - const struct dev_pm_ops *pm; + if (pm) + return pm->suspend ? pm->suspend(dev) : 0; - if (!dev->driver) - return 0; - pm = dev->driver->pm; - if (!pm || !pm->runtime_resume) - return 0; - return pm->runtime_resume(dev); + return i2c_legacy_suspend(dev, PMSG_SUSPEND); } -static int i2c_device_runtime_idle(struct device *dev) +static int i2c_device_pm_resume(struct device *dev) { - const struct dev_pm_ops *pm = NULL; + const struct dev_pm_ops *pm = dev->driver ? dev->driver->pm : NULL; int ret; - if (dev->driver) - pm = dev->driver->pm; - if (pm && pm->runtime_idle) { - ret = pm->runtime_idle(dev); - if (ret) - return ret; + if (pm) + ret = pm->resume ? pm->resume(dev) : 0; + else + ret = i2c_legacy_resume(dev); + + if (!ret) { + pm_runtime_disable(dev); + pm_runtime_set_active(dev); + pm_runtime_enable(dev); } - return pm_runtime_suspend(dev); + return ret; } -#else -#define i2c_device_runtime_suspend NULL -#define i2c_device_runtime_resume NULL -#define i2c_device_runtime_idle NULL -#endif -static int i2c_device_suspend(struct device *dev, pm_message_t mesg) +static int i2c_device_pm_freeze(struct device *dev) { - struct i2c_client *client = i2c_verify_client(dev); - struct i2c_driver *driver; + const struct dev_pm_ops *pm = dev->driver ? dev->driver->pm : NULL; - if (!client || !dev->driver) + if (pm_runtime_suspended(dev)) return 0; - driver = to_i2c_driver(dev->driver); - if (!driver->suspend) - return 0; - return driver->suspend(client, mesg); + + if (pm) + return pm->freeze ? pm->freeze(dev) : 0; + + return i2c_legacy_suspend(dev, PMSG_FREEZE); } -static int i2c_device_resume(struct device *dev) +static int i2c_device_pm_thaw(struct device *dev) { - struct i2c_client *client = i2c_verify_client(dev); - struct i2c_driver *driver; + const struct dev_pm_ops *pm = dev->driver ? dev->driver->pm : NULL; - if (!client || !dev->driver) + if (pm_runtime_suspended(dev)) return 0; - driver = to_i2c_driver(dev->driver); - if (!driver->resume) + + if (pm) + return pm->thaw ? pm->thaw(dev) : 0; + + return i2c_legacy_resume(dev); +} + +static int i2c_device_pm_poweroff(struct device *dev) +{ + const struct dev_pm_ops *pm = dev->driver ? dev->driver->pm : NULL; + + if (pm_runtime_suspended(dev)) return 0; - return driver->resume(client); + + if (pm) + return pm->poweroff ? pm->poweroff(dev) : 0; + + return i2c_legacy_suspend(dev, PMSG_HIBERNATE); +} + +static int i2c_device_pm_restore(struct device *dev) +{ + const struct dev_pm_ops *pm = dev->driver ? dev->driver->pm : NULL; + int ret; + + if (pm) + ret = pm->restore ? pm->restore(dev) : 0; + else + ret = i2c_legacy_resume(dev); + + if (!ret) { + pm_runtime_disable(dev); + pm_runtime_set_active(dev); + pm_runtime_enable(dev); + } + + return ret; } +#else /* !CONFIG_PM_SLEEP */ +#define i2c_device_pm_suspend NULL +#define i2c_device_pm_resume NULL +#define i2c_device_pm_freeze NULL +#define i2c_device_pm_thaw NULL +#define i2c_device_pm_poweroff NULL +#define i2c_device_pm_restore NULL +#endif /* !CONFIG_PM_SLEEP */ static void i2c_client_dev_release(struct device *dev) { @@ -298,9 +325,15 @@ static const struct attribute_group *i2c_dev_attr_groups[] = { static const struct dev_pm_ops i2c_device_pm_ops = { .suspend = i2c_device_pm_suspend, .resume = i2c_device_pm_resume, - .runtime_suspend = i2c_device_runtime_suspend, - .runtime_resume = i2c_device_runtime_resume, - .runtime_idle = i2c_device_runtime_idle, + .freeze = i2c_device_pm_freeze, + .thaw = i2c_device_pm_thaw, + .poweroff = i2c_device_pm_poweroff, + .restore = i2c_device_pm_restore, + SET_RUNTIME_PM_OPS( + pm_generic_runtime_suspend, + pm_generic_runtime_resume, + pm_generic_runtime_idle + ) }; struct bus_type i2c_bus_type = { @@ -309,8 +342,6 @@ struct bus_type i2c_bus_type = { .probe = i2c_device_probe, .remove = i2c_device_remove, .shutdown = i2c_device_shutdown, - .suspend = i2c_device_suspend, - .resume = i2c_device_resume, .pm = &i2c_device_pm_ops, }; EXPORT_SYMBOL_GPL(i2c_bus_type); @@ -538,9 +569,9 @@ i2c_sysfs_new_device(struct device *dev, struct device_attribute *attr, return -EEXIST; /* Keep track of the added device */ - mutex_lock(&core_lock); - list_add_tail(&client->detected, &userspace_devices); - mutex_unlock(&core_lock); + i2c_lock_adapter(adap); + list_add_tail(&client->detected, &adap->userspace_clients); + i2c_unlock_adapter(adap); dev_info(dev, "%s: Instantiated device %s at 0x%02hx\n", "new_device", info.type, info.addr); @@ -579,9 +610,10 @@ i2c_sysfs_delete_device(struct device *dev, struct device_attribute *attr, /* Make sure the device was added through sysfs */ res = -ENOENT; - mutex_lock(&core_lock); - list_for_each_entry_safe(client, next, &userspace_devices, detected) { - if (client->addr == addr && client->adapter == adap) { + i2c_lock_adapter(adap); + list_for_each_entry_safe(client, next, &adap->userspace_clients, + detected) { + if (client->addr == addr) { dev_info(dev, "%s: Deleting device %s at 0x%02hx\n", "delete_device", client->name, client->addr); @@ -591,7 +623,7 @@ i2c_sysfs_delete_device(struct device *dev, struct device_attribute *attr, break; } } - mutex_unlock(&core_lock); + i2c_unlock_adapter(adap); if (res < 0) dev_err(dev, "%s: Can't find device in list\n", @@ -673,6 +705,7 @@ static int i2c_register_adapter(struct i2c_adapter *adap) } rt_mutex_init(&adap->bus_lock); + INIT_LIST_HEAD(&adap->userspace_clients); /* Set default timeout to 1 second if not already set */ if (adap->timeout == 0) @@ -875,14 +908,15 @@ int i2c_del_adapter(struct i2c_adapter *adap) return res; /* Remove devices instantiated from sysfs */ - list_for_each_entry_safe(client, next, &userspace_devices, detected) { - if (client->adapter == adap) { - dev_dbg(&adap->dev, "Removing %s at 0x%x\n", - client->name, client->addr); - list_del(&client->detected); - i2c_unregister_device(client); - } + i2c_lock_adapter(adap); + list_for_each_entry_safe(client, next, &adap->userspace_clients, + detected) { + dev_dbg(&adap->dev, "Removing %s at 0x%x\n", client->name, + client->addr); + list_del(&client->detected); + i2c_unregister_device(client); } + i2c_unlock_adapter(adap); /* Detach any active clients. This can't fail, thus we do not checking the returned value. */ @@ -1260,12 +1294,23 @@ static int i2c_detect_address(struct i2c_client *temp_client, return 0; /* Make sure there is something at this address */ - if (i2c_smbus_xfer(adapter, addr, 0, 0, 0, I2C_SMBUS_QUICK, NULL) < 0) - return 0; + if (addr == 0x73 && (adapter->class & I2C_CLASS_HWMON)) { + /* Special probe for FSC hwmon chips */ + union i2c_smbus_data dummy; - /* Prevent 24RF08 corruption */ - if ((addr & ~0x0f) == 0x50) - i2c_smbus_xfer(adapter, addr, 0, 0, 0, I2C_SMBUS_QUICK, NULL); + if (i2c_smbus_xfer(adapter, addr, 0, I2C_SMBUS_READ, 0, + I2C_SMBUS_BYTE_DATA, &dummy) < 0) + return 0; + } else { + if (i2c_smbus_xfer(adapter, addr, 0, I2C_SMBUS_WRITE, 0, + I2C_SMBUS_QUICK, NULL) < 0) + return 0; + + /* Prevent 24RF08 corruption */ + if ((addr & ~0x0f) == 0x50) + i2c_smbus_xfer(adapter, addr, 0, I2C_SMBUS_WRITE, 0, + I2C_SMBUS_QUICK, NULL); + } /* Finally call the custom detection function */ memset(&info, 0, sizeof(struct i2c_board_info)); diff --git a/drivers/i2c/i2c-smbus.c b/drivers/i2c/i2c-smbus.c index 42127822124..a24e0bfe920 100644 --- a/drivers/i2c/i2c-smbus.c +++ b/drivers/i2c/i2c-smbus.c @@ -22,11 +22,11 @@ #include <linux/kernel.h> #include <linux/module.h> #include <linux/device.h> -#include <linux/semaphore.h> #include <linux/interrupt.h> #include <linux/workqueue.h> #include <linux/i2c.h> #include <linux/i2c-smbus.h> +#include <linux/slab.h> struct i2c_smbus_alert { unsigned int alert_edge_triggered:1; @@ -55,7 +55,7 @@ static int smbus_do_alert(struct device *dev, void *addrp) * Drivers should either disable alerts, or provide at least * a minimal handler. Lock so client->driver won't change. */ - down(&dev->sem); + device_lock(dev); if (client->driver) { if (client->driver->alert) client->driver->alert(client, data->flag); @@ -63,7 +63,7 @@ static int smbus_do_alert(struct device *dev, void *addrp) dev_warn(&client->dev, "no driver alert()!\n"); } else dev_dbg(&client->dev, "alert with no driver\n"); - up(&dev->sem); + device_unlock(dev); /* Stop iterating after we find the device */ return -EBUSY; |