diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2012-10-11 10:27:51 +0900 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2012-10-11 10:27:51 +0900 |
commit | 12250d843e8489ee00b5b7726da855e51694e792 (patch) | |
tree | 905d1577a3d91cf9906628dd65648b0006c1893f /drivers/i2c | |
parent | da06a8d7bed2f3bfc12979384b2d1247ec4873db (diff) | |
parent | 62885f59a26195d9f6a3f8c795225dfbab62a110 (diff) |
Merge branch 'i2c-embedded/for-next' of git://git.pengutronix.de/git/wsa/linux
Pull i2c-embedded changes from Wolfram Sang:
"The changes for i2c-embedded include:
- massive rework of the omap driver
- massive rework of the at91 driver. In fact, the old driver gets
removed; I am okay with this approach since the old driver was
depending on BROKEN and its limitations made it practically
unusable, so people used bitbanging instead. But even if there are
users, there is no platform_data or module parameter which would
need to be converted. It is just another driver doing I2C
transfers, just way better. Modifications of arch/arm/at91 related
files have proper acks from the maintainer.
- new driver for R-Car I2C
- devicetree and generic_clock conversions and fixes
- usual driver fixes and changes.
The rework patches have come a long way and lots of people have been
involved in creating/testing them. Most patches have been in
linux-next at least since 3.6-rc5. A few have been added in the last
week, I have to admit.
An unexpected (but welcome :)) peak in private life is the cause for
that. The "late" patches shouldn't cause any merge conflicts and I
will have a special eye on them during the stabilization phase. This
is an exception and I want to have the patches in place properly in
time again for the next kernels."
* 'i2c-embedded/for-next' of git://git.pengutronix.de/git/wsa/linux: (44 commits)
MXS: Implement DMA support into mxs-i2c
i2c: add Renesas R-Car I2C driver
i2c: s3c2410: use clk_prepare_enable and clk_disable_unprepare
ARM: OMAP: convert I2C driver to PM QoS for MPU latency constraints
i2c: nomadik: Add Device Tree support to the Nomadik I2C driver
i2c: algo: pca: Fix chip reset function for PCA9665
i2c: mpc: Wait for STOP to hit the bus
i2c: davinci: preparation for switch to common clock framework
omap-i2c: fix incorrect log message when using a device tree
i2c: omap: sanitize exit path
i2c: omap: switch over to autosuspend API
i2c: omap: remove unnecessary pm_runtime_suspended check
i2c: omap: switch to threaded IRQ support
i2c: omap: remove redundant status read
i2c: omap: get rid of the "complete" label
i2c: omap: resize fifos before each message
i2c: omap: simplify IRQ exit path
i2c: omap: always return IRQ_HANDLED
i2c: omap: simplify errata check
i2c: omap: bus: add a receiver flag
...
Diffstat (limited to 'drivers/i2c')
-rw-r--r-- | drivers/i2c/algos/i2c-algo-pca.c | 27 | ||||
-rw-r--r-- | drivers/i2c/busses/Kconfig | 27 | ||||
-rw-r--r-- | drivers/i2c/busses/Makefile | 1 | ||||
-rw-r--r-- | drivers/i2c/busses/i2c-at91.c | 667 | ||||
-rw-r--r-- | drivers/i2c/busses/i2c-davinci.c | 58 | ||||
-rw-r--r-- | drivers/i2c/busses/i2c-imx.c | 6 | ||||
-rw-r--r-- | drivers/i2c/busses/i2c-mpc.c | 18 | ||||
-rw-r--r-- | drivers/i2c/busses/i2c-mxs.c | 269 | ||||
-rw-r--r-- | drivers/i2c/busses/i2c-nomadik.c | 52 | ||||
-rw-r--r-- | drivers/i2c/busses/i2c-omap.c | 474 | ||||
-rw-r--r-- | drivers/i2c/busses/i2c-rcar.c | 709 | ||||
-rw-r--r-- | drivers/i2c/busses/i2c-s3c2410.c | 18 |
12 files changed, 1836 insertions, 490 deletions
diff --git a/drivers/i2c/algos/i2c-algo-pca.c b/drivers/i2c/algos/i2c-algo-pca.c index 6f5f98d69af..f892a424009 100644 --- a/drivers/i2c/algos/i2c-algo-pca.c +++ b/drivers/i2c/algos/i2c-algo-pca.c @@ -46,14 +46,19 @@ static int i2c_debug; #define pca_set_con(adap, val) pca_outw(adap, I2C_PCA_CON, val) #define pca_get_con(adap) pca_inw(adap, I2C_PCA_CON) #define pca_wait(adap) adap->wait_for_completion(adap->data) -#define pca_reset(adap) adap->reset_chip(adap->data) -static void pca9665_reset(void *pd) +static void pca_reset(struct i2c_algo_pca_data *adap) { - struct i2c_algo_pca_data *adap = pd; - pca_outw(adap, I2C_PCA_INDPTR, I2C_PCA_IPRESET); - pca_outw(adap, I2C_PCA_IND, 0xA5); - pca_outw(adap, I2C_PCA_IND, 0x5A); + if (adap->chip == I2C_PCA_CHIP_9665) { + /* Ignore the reset function from the module, + * we can use the parallel bus reset. + */ + pca_outw(adap, I2C_PCA_INDPTR, I2C_PCA_IPRESET); + pca_outw(adap, I2C_PCA_IND, 0xA5); + pca_outw(adap, I2C_PCA_IND, 0x5A); + } else { + adap->reset_chip(adap->data); + } } /* @@ -378,11 +383,12 @@ static unsigned int pca_probe_chip(struct i2c_adapter *adap) pca_outw(pca_data, I2C_PCA_INDPTR, I2C_PCA_IADR); if (pca_inw(pca_data, I2C_PCA_IND) == 0xAA) { printk(KERN_INFO "%s: PCA9665 detected.\n", adap->name); - return I2C_PCA_CHIP_9665; + pca_data->chip = I2C_PCA_CHIP_9665; } else { printk(KERN_INFO "%s: PCA9564 detected.\n", adap->name); - return I2C_PCA_CHIP_9564; + pca_data->chip = I2C_PCA_CHIP_9564; } + return pca_data->chip; } static int pca_init(struct i2c_adapter *adap) @@ -456,11 +462,6 @@ static int pca_init(struct i2c_adapter *adap) */ int raise_fall_time; - /* Ignore the reset function from the module, - * we can use the parallel bus reset - */ - pca_data->reset_chip = pca9665_reset; - if (pca_data->i2c_clock > 1265800) { printk(KERN_WARNING "%s: I2C clock speed too high." " Using 1265.8kHz.\n", adap->name); diff --git a/drivers/i2c/busses/Kconfig b/drivers/i2c/busses/Kconfig index ff01c389e2d..65dd599a026 100644 --- a/drivers/i2c/busses/Kconfig +++ b/drivers/i2c/busses/Kconfig @@ -294,18 +294,21 @@ comment "I2C system bus drivers (mostly embedded / system-on-chip)" config I2C_AT91 tristate "Atmel AT91 I2C Two-Wire interface (TWI)" - depends on ARCH_AT91 && EXPERIMENTAL && BROKEN + depends on ARCH_AT91 && EXPERIMENTAL 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 + A serious problem is that there is no documented way to issue + repeated START conditions for more than two messages, as needed to support combined I2C messages. Use the i2c-gpio driver - unless your system can cope with those limitations. + unless your system can cope with this limitation. + + Caution! at91rm9200, at91sam9261, at91sam9260, at91sam9263 devices + don't have clock stretching in transmission mode. For that reason, + you can encounter underrun issues causing premature stop sendings if + the latency to fill the transmission register is too long. If you + are facing this situation, use the i2c-gpio driver. config I2C_AU1550 tristate "Au1550/Au1200/Au1300 SMBus interface" @@ -718,6 +721,16 @@ config I2C_XLR This driver can also be built as a module. If so, the module will be called i2c-xlr. +config I2C_RCAR + tristate "Renesas R-Car I2C Controller" + depends on ARCH_SHMOBILE && I2C + help + If you say yes to this option, support will be included for the + R-Car I2C controller. + + This driver can also be built as a module. If so, the module + will be called i2c-rcar. + comment "External I2C/SMBus adapter drivers" config I2C_DIOLAN_U2C diff --git a/drivers/i2c/busses/Makefile b/drivers/i2c/busses/Makefile index 37c4182cc98..2d33d62952c 100644 --- a/drivers/i2c/busses/Makefile +++ b/drivers/i2c/busses/Makefile @@ -71,6 +71,7 @@ obj-$(CONFIG_I2C_VERSATILE) += i2c-versatile.o obj-$(CONFIG_I2C_OCTEON) += i2c-octeon.o obj-$(CONFIG_I2C_XILINX) += i2c-xiic.o obj-$(CONFIG_I2C_XLR) += i2c-xlr.o +obj-$(CONFIG_I2C_RCAR) += i2c-rcar.o # External I2C/SMBus adapter drivers obj-$(CONFIG_I2C_DIOLAN_U2C) += i2c-diolan-u2c.o diff --git a/drivers/i2c/busses/i2c-at91.c b/drivers/i2c/busses/i2c-at91.c index e24484beef0..aa59a254be2 100644 --- a/drivers/i2c/busses/i2c-at91.c +++ b/drivers/i2c/busses/i2c-at91.c @@ -1,315 +1,554 @@ /* - i2c Support for Atmel's AT91 Two-Wire Interface (TWI) - - Copyright (C) 2004 Rick Bronson - Converted to 2.6 by Andrew Victor <andrew@sanpeople.com> - - Borrowed heavily from original work by: - Copyright (C) 2000 Philip Edelbrock <phil@stimpy.netroedge.com> - - 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. -*/ + * i2c Support for Atmel's AT91 Two-Wire Interface (TWI) + * + * Copyright (C) 2011 Weinmann Medical GmbH + * Author: Nikolaus Voss <n.voss@weinmann.de> + * + * Evolved from original work by: + * Copyright (C) 2004 Rick Bronson + * Converted to 2.6 by Andrew Victor <andrew@sanpeople.com> + * + * Borrowed heavily from original work by: + * Copyright (C) 2000 Philip Edelbrock <phil@stimpy.netroedge.com> + * + * 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. + */ -#include <linux/module.h> -#include <linux/kernel.h> +#include <linux/clk.h> +#include <linux/completion.h> #include <linux/err.h> -#include <linux/slab.h> -#include <linux/types.h> -#include <linux/delay.h> #include <linux/i2c.h> -#include <linux/init.h> -#include <linux/clk.h> -#include <linux/platform_device.h> +#include <linux/interrupt.h> #include <linux/io.h> +#include <linux/module.h> +#include <linux/of.h> +#include <linux/of_device.h> +#include <linux/of_i2c.h> +#include <linux/platform_device.h> +#include <linux/slab.h> + +#define TWI_CLK_HZ 100000 /* max 400 Kbits/s */ +#define AT91_I2C_TIMEOUT msecs_to_jiffies(100) /* transfer timeout */ + +/* AT91 TWI register definitions */ +#define AT91_TWI_CR 0x0000 /* Control Register */ +#define AT91_TWI_START 0x0001 /* Send a Start Condition */ +#define AT91_TWI_STOP 0x0002 /* Send a Stop Condition */ +#define AT91_TWI_MSEN 0x0004 /* Master Transfer Enable */ +#define AT91_TWI_SVDIS 0x0020 /* Slave Transfer Disable */ +#define AT91_TWI_SWRST 0x0080 /* Software Reset */ + +#define AT91_TWI_MMR 0x0004 /* Master Mode Register */ +#define AT91_TWI_IADRSZ_1 0x0100 /* Internal Device Address Size */ +#define AT91_TWI_MREAD 0x1000 /* Master Read Direction */ + +#define AT91_TWI_IADR 0x000c /* Internal Address Register */ + +#define AT91_TWI_CWGR 0x0010 /* Clock Waveform Generator Reg */ + +#define AT91_TWI_SR 0x0020 /* Status Register */ +#define AT91_TWI_TXCOMP 0x0001 /* Transmission Complete */ +#define AT91_TWI_RXRDY 0x0002 /* Receive Holding Register Ready */ +#define AT91_TWI_TXRDY 0x0004 /* Transmit Holding Register Ready */ -#include <mach/at91_twi.h> -#include <mach/board.h> -#include <mach/cpu.h> +#define AT91_TWI_OVRE 0x0040 /* Overrun Error */ +#define AT91_TWI_UNRE 0x0080 /* Underrun Error */ +#define AT91_TWI_NACK 0x0100 /* Not Acknowledged */ -#define TWI_CLOCK 100000 /* Hz. max 400 Kbits/sec */ +#define AT91_TWI_IER 0x0024 /* Interrupt Enable Register */ +#define AT91_TWI_IDR 0x0028 /* Interrupt Disable Register */ +#define AT91_TWI_IMR 0x002c /* Interrupt Mask Register */ +#define AT91_TWI_RHR 0x0030 /* Receive Holding Register */ +#define AT91_TWI_THR 0x0034 /* Transmit Holding Register */ +struct at91_twi_pdata { + unsigned clk_max_div; + unsigned clk_offset; + bool has_unre_flag; +}; + +struct at91_twi_dev { + struct device *dev; + void __iomem *base; + struct completion cmd_complete; + struct clk *clk; + u8 *buf; + size_t buf_len; + struct i2c_msg *msg; + int irq; + unsigned transfer_status; + struct i2c_adapter adapter; + unsigned twi_cwgr_reg; + struct at91_twi_pdata *pdata; +}; -static struct clk *twi_clk; -static void __iomem *twi_base; +static unsigned at91_twi_read(struct at91_twi_dev *dev, unsigned reg) +{ + return readl_relaxed(dev->base + reg); +} + +static void at91_twi_write(struct at91_twi_dev *dev, unsigned reg, unsigned val) +{ + writel_relaxed(val, dev->base + reg); +} -#define at91_twi_read(reg) __raw_readl(twi_base + (reg)) -#define at91_twi_write(reg, val) __raw_writel((val), twi_base + (reg)) +static void at91_disable_twi_interrupts(struct at91_twi_dev *dev) +{ + at91_twi_write(dev, AT91_TWI_IDR, + AT91_TWI_TXCOMP | AT91_TWI_RXRDY | AT91_TWI_TXRDY); +} +static void at91_init_twi_bus(struct at91_twi_dev *dev) +{ + at91_disable_twi_interrupts(dev); + at91_twi_write(dev, AT91_TWI_CR, AT91_TWI_SWRST); + at91_twi_write(dev, AT91_TWI_CR, AT91_TWI_MSEN); + at91_twi_write(dev, AT91_TWI_CR, AT91_TWI_SVDIS); + at91_twi_write(dev, AT91_TWI_CWGR, dev->twi_cwgr_reg); +} /* - * Initialize the TWI hardware registers. + * Calculate symmetric clock as stated in datasheet: + * twi_clk = F_MAIN / (2 * (cdiv * (1 << ckdiv) + offset)) */ -static void __devinit at91_twi_hwinit(void) +static void __devinit at91_calc_twi_clock(struct at91_twi_dev *dev, int twi_clk) { - unsigned long cdiv, ckdiv; - - at91_twi_write(AT91_TWI_IDR, 0xffffffff); /* Disable all interrupts */ - at91_twi_write(AT91_TWI_CR, AT91_TWI_SWRST); /* Reset peripheral */ - at91_twi_write(AT91_TWI_CR, AT91_TWI_MSEN); /* Set Master mode */ - - /* Calcuate clock dividers */ - cdiv = (clk_get_rate(twi_clk) / (2 * TWI_CLOCK)) - 3; - cdiv = cdiv + 1; /* round up */ - ckdiv = 0; - while (cdiv > 255) { - ckdiv++; - cdiv = cdiv >> 1; + int ckdiv, cdiv, div; + struct at91_twi_pdata *pdata = dev->pdata; + int offset = pdata->clk_offset; + int max_ckdiv = pdata->clk_max_div; + + div = max(0, (int)DIV_ROUND_UP(clk_get_rate(dev->clk), + 2 * twi_clk) - offset); + ckdiv = fls(div >> 8); + cdiv = div >> ckdiv; + + if (ckdiv > max_ckdiv) { + dev_warn(dev->dev, "%d exceeds ckdiv max value which is %d.\n", + ckdiv, max_ckdiv); + ckdiv = max_ckdiv; + cdiv = 255; } - if (cpu_is_at91rm9200()) { /* AT91RM9200 Errata #22 */ - if (ckdiv > 5) { - printk(KERN_ERR "AT91 I2C: Invalid TWI_CLOCK value!\n"); - ckdiv = 5; - } - } + dev->twi_cwgr_reg = (ckdiv << 16) | (cdiv << 8) | cdiv; + dev_dbg(dev->dev, "cdiv %d ckdiv %d\n", cdiv, ckdiv); +} - at91_twi_write(AT91_TWI_CWGR, (ckdiv << 16) | (cdiv << 8) | cdiv); +static void at91_twi_write_next_byte(struct at91_twi_dev *dev) +{ + if (dev->buf_len <= 0) + return; + + at91_twi_write(dev, AT91_TWI_THR, *dev->buf); + + /* send stop when last byte has been written */ + if (--dev->buf_len == 0) + at91_twi_write(dev, AT91_TWI_CR, AT91_TWI_STOP); + + dev_dbg(dev->dev, "wrote 0x%x, to go %d\n", *dev->buf, dev->buf_len); + + ++dev->buf; } -/* - * Poll the i2c status register until the specified bit is set. - * Returns 0 if timed out (100 msec). - */ -static short at91_poll_status(unsigned long bit) +static void at91_twi_read_next_byte(struct at91_twi_dev *dev) { - int loop_cntr = 10000; + if (dev->buf_len <= 0) + return; + + *dev->buf = at91_twi_read(dev, AT91_TWI_RHR) & 0xff; + --dev->buf_len; + + /* handle I2C_SMBUS_BLOCK_DATA */ + if (unlikely(dev->msg->flags & I2C_M_RECV_LEN)) { + dev->msg->flags &= ~I2C_M_RECV_LEN; + dev->buf_len += *dev->buf; + dev->msg->len = dev->buf_len + 1; + dev_dbg(dev->dev, "received block length %d\n", dev->buf_len); + } + + /* send stop if second but last byte has been read */ + if (dev->buf_len == 1) + at91_twi_write(dev, AT91_TWI_CR, AT91_TWI_STOP); - do { - udelay(10); - } while (!(at91_twi_read(AT91_TWI_SR) & bit) && (--loop_cntr > 0)); + dev_dbg(dev->dev, "read 0x%x, to go %d\n", *dev->buf, dev->buf_len); - return (loop_cntr > 0); + ++dev->buf; } -static int xfer_read(struct i2c_adapter *adap, unsigned char *buf, int length) +static irqreturn_t atmel_twi_interrupt(int irq, void *dev_id) { - /* Send Start */ - at91_twi_write(AT91_TWI_CR, AT91_TWI_START); - - /* Read data */ - while (length--) { - if (!length) /* need to send Stop before reading last byte */ - at91_twi_write(AT91_TWI_CR, AT91_TWI_STOP); - if (!at91_poll_status(AT91_TWI_RXRDY)) { - dev_dbg(&adap->dev, "RXRDY timeout\n"); - return -ETIMEDOUT; - } - *buf++ = (at91_twi_read(AT91_TWI_RHR) & 0xff); + struct at91_twi_dev *dev = dev_id; + const unsigned status = at91_twi_read(dev, AT91_TWI_SR); + const unsigned irqstatus = status & at91_twi_read(dev, AT91_TWI_IMR); + + if (!irqstatus) + return IRQ_NONE; + else if (irqstatus & AT91_TWI_RXRDY) + at91_twi_read_next_byte(dev); + else if (irqstatus & AT91_TWI_TXRDY) + at91_twi_write_next_byte(dev); + + /* catch error flags */ + dev->transfer_status |= status; + + if (irqstatus & AT91_TWI_TXCOMP) { + at91_disable_twi_interrupts(dev); + complete(&dev->cmd_complete); } - return 0; + return IRQ_HANDLED; } -static int xfer_write(struct i2c_adapter *adap, unsigned char *buf, int length) +static int at91_do_twi_transfer(struct at91_twi_dev *dev) { - /* Load first byte into transmitter */ - at91_twi_write(AT91_TWI_THR, *buf++); + int ret; + bool has_unre_flag = dev->pdata->has_unre_flag; - /* Send Start */ - at91_twi_write(AT91_TWI_CR, AT91_TWI_START); + dev_dbg(dev->dev, "transfer: %s %d bytes.\n", + (dev->msg->flags & I2C_M_RD) ? "read" : "write", dev->buf_len); - do { - if (!at91_poll_status(AT91_TWI_TXRDY)) { - dev_dbg(&adap->dev, "TXRDY timeout\n"); - return -ETIMEDOUT; - } + INIT_COMPLETION(dev->cmd_complete); + dev->transfer_status = 0; + if (dev->msg->flags & I2C_M_RD) { + unsigned start_flags = AT91_TWI_START; - length--; /* byte was transmitted */ + if (at91_twi_read(dev, AT91_TWI_SR) & AT91_TWI_RXRDY) { + dev_err(dev->dev, "RXRDY still set!"); + at91_twi_read(dev, AT91_TWI_RHR); + } - if (length > 0) /* more data to send? */ - at91_twi_write(AT91_TWI_THR, *buf++); - } while (length); + /* if only one byte is to be read, immediately stop transfer */ + if (dev->buf_len <= 1 && !(dev->msg->flags & I2C_M_RECV_LEN)) + start_flags |= AT91_TWI_STOP; + at91_twi_write(dev, AT91_TWI_CR, start_flags); + at91_twi_write(dev, AT91_TWI_IER, + AT91_TWI_TXCOMP | AT91_TWI_RXRDY); + } else { + at91_twi_write_next_byte(dev); + at91_twi_write(dev, AT91_TWI_IER, + AT91_TWI_TXCOMP | AT91_TWI_TXRDY); + } - /* Send Stop */ - at91_twi_write(AT91_TWI_CR, AT91_TWI_STOP); + ret = wait_for_completion_interruptible_timeout(&dev->cmd_complete, + dev->adapter.timeout); + if (ret == 0) { + dev_err(dev->dev, "controller timed out\n"); + at91_init_twi_bus(dev); + return -ETIMEDOUT; + } + if (dev->transfer_status & AT91_TWI_NACK) { + dev_dbg(dev->dev, "received nack\n"); + return -EREMOTEIO; + } + if (dev->transfer_status & AT91_TWI_OVRE) { + dev_err(dev->dev, "overrun while reading\n"); + return -EIO; + } + if (has_unre_flag && dev->transfer_status & AT91_TWI_UNRE) { + dev_err(dev->dev, "underrun while writing\n"); + return -EIO; + } + dev_dbg(dev->dev, "transfer complete\n"); return 0; } -/* - * Generic i2c master transfer entrypoint. - * - * Note: We do not use Atmel's feature of storing the "internal device address". - * Instead the "internal device address" has to be written using a separate - * i2c message. - * http://lists.arm.linux.org.uk/pipermail/linux-arm-kernel/2004-September/024411.html - */ -static int at91_xfer(struct i2c_adapter *adap, struct i2c_msg *pmsg, int num) +static int at91_twi_xfer(struct i2c_adapter *adap, struct i2c_msg *msg, int num) { - int i, ret; + struct at91_twi_dev *dev = i2c_get_adapdata(adap); + int ret; + unsigned int_addr_flag = 0; + struct i2c_msg *m_start = msg; dev_dbg(&adap->dev, "at91_xfer: processing %d messages:\n", num); - for (i = 0; i < num; i++) { - dev_dbg(&adap->dev, " #%d: %sing %d byte%s %s 0x%02x\n", i, - pmsg->flags & I2C_M_RD ? "read" : "writ", - pmsg->len, pmsg->len > 1 ? "s" : "", - pmsg->flags & I2C_M_RD ? "from" : "to", pmsg->addr); - - at91_twi_write(AT91_TWI_MMR, (pmsg->addr << 16) - | ((pmsg->flags & I2C_M_RD) ? AT91_TWI_MREAD : 0)); - - if (pmsg->len && pmsg->buf) { /* sanity check */ - if (pmsg->flags & I2C_M_RD) - ret = xfer_read(adap, pmsg->buf, pmsg->len); - else - ret = xfer_write(adap, pmsg->buf, pmsg->len); - - if (ret) - return ret; - - /* Wait until transfer is finished */ - if (!at91_poll_status(AT91_TWI_TXCOMP)) { - dev_dbg(&adap->dev, "TXCOMP timeout\n"); - return -ETIMEDOUT; - } + /* + * The hardware can handle at most two messages concatenated by a + * repeated start via it's internal address feature. + */ + if (num > 2) { + dev_err(dev->dev, + "cannot handle more than two concatenated messages.\n"); + return 0; + } else if (num == 2) { + int internal_address = 0; + int i; + + if (msg->flags & I2C_M_RD) { + dev_err(dev->dev, "first transfer must be write.\n"); + return -EINVAL; } - dev_dbg(&adap->dev, "transfer complete\n"); - pmsg++; /* next message */ + if (msg->len > 3) { + dev_err(dev->dev, "first message size must be <= 3.\n"); + return -EINVAL; + } + + /* 1st msg is put into the internal address, start with 2nd */ + m_start = &msg[1]; + for (i = 0; i < msg->len; ++i) { + const unsigned addr = msg->buf[msg->len - 1 - i]; + + internal_address |= addr << (8 * i); + int_addr_flag += AT91_TWI_IADRSZ_1; + } + at91_twi_write(dev, AT91_TWI_IADR, internal_address); } - return i; + + at91_twi_write(dev, AT91_TWI_MMR, (m_start->addr << 16) | int_addr_flag + | ((m_start->flags & I2C_M_RD) ? AT91_TWI_MREAD : 0)); + + dev->buf_len = m_start->len; + dev->buf = m_start->buf; + dev->msg = m_start; + + ret = at91_do_twi_transfer(dev); + + return (ret < 0) ? ret : num; } -/* - * Return list of supported functionality. - */ -static u32 at91_func(struct i2c_adapter *adapter) +static u32 at91_twi_func(struct i2c_adapter *adapter) { - return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL; + return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL + | I2C_FUNC_SMBUS_READ_BLOCK_DATA; } -static struct i2c_algorithm at91_algorithm = { - .master_xfer = at91_xfer, - .functionality = at91_func, +static struct i2c_algorithm at91_twi_algorithm = { + .master_xfer = at91_twi_xfer, + .functionality = at91_twi_func, }; -/* - * Main initialization routine. - */ -static int __devinit at91_i2c_probe(struct platform_device *pdev) -{ - struct i2c_adapter *adapter; - struct resource *res; - int rc; +static struct at91_twi_pdata at91rm9200_config = { + .clk_max_div = 5, + .clk_offset = 3, + .has_unre_flag = true, +}; - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - if (!res) - return -ENXIO; +static struct at91_twi_pdata at91sam9261_config = { + .clk_max_div = 5, + .clk_offset = 4, + .has_unre_flag = false, +}; - if (!request_mem_region(res->start, resource_size(res), "at91_i2c")) - return -EBUSY; +static struct at91_twi_pdata at91sam9260_config = { + .clk_max_div = 7, + .clk_offset = 4, + .has_unre_flag = false, +}; + +static struct at91_twi_pdata at91sam9g20_config = { + .clk_max_div = 7, + .clk_offset = 4, + .has_unre_flag = false, +}; + +static struct at91_twi_pdata at91sam9g10_config = { + .clk_max_div = 7, + .clk_offset = 4, + .has_unre_flag = false, +}; - twi_base = ioremap(res->start, resource_size(res)); - if (!twi_base) { - rc = -ENOMEM; - goto fail0; +static struct at91_twi_pdata at91sam9x5_config = { + .clk_max_div = 7, + .clk_offset = 4, + .has_unre_flag = false, +}; + +static const struct platform_device_id at91_twi_devtypes[] = { + { + .name = "i2c-at91rm9200", + .driver_data = (unsigned long) &at91rm9200_config, + }, { + .name = "i2c-at91sam9261", + .driver_data = (unsigned long) &at91sam9261_config, + }, { + .name = "i2c-at91sam9260", + .driver_data = (unsigned long) &at91sam9260_config, + }, { + .name = "i2c-at91sam9g20", + .driver_data = (unsigned long) &at91sam9g20_config, + }, { + .name = "i2c-at91sam9g10", + .driver_data = (unsigned long) &at91sam9g10_config, + }, { + /* sentinel */ } +}; - twi_clk = clk_get(NULL, "twi_clk"); - if (IS_ERR(twi_clk)) { - dev_err(&pdev->dev, "no clock defined\n"); - rc = -ENODEV; - goto fail1; +#if defined(CONFIG_OF) +static const struct of_device_id atmel_twi_dt_ids[] = { + { + .compatible = "atmel,at91sam9260-i2c", + .data = &at91sam9260_config, + } , { + .compatible = "atmel,at91sam9g20-i2c", + .data = &at91sam9g20_config, + } , { + .compatible = "atmel,at91sam9g10-i2c", + .data = &at91sam9g10_config, + }, { + .compatible = "atmel,at91sam9x5-i2c", + .data = &at91sam9x5_config, + }, { + /* sentinel */ } +}; +MODULE_DEVICE_TABLE(of, atmel_twi_dt_ids); +#else +#define atmel_twi_dt_ids NULL +#endif - adapter = kzalloc(sizeof(struct i2c_adapter), GFP_KERNEL); - if (adapter == NULL) { - dev_err(&pdev->dev, "can't allocate inteface!\n"); - rc = -ENOMEM; - goto fail2; +static struct at91_twi_pdata * __devinit at91_twi_get_driver_data( + struct platform_device *pdev) +{ + if (pdev->dev.of_node) { + const struct of_device_id *match; + match = of_match_node(atmel_twi_dt_ids, pdev->dev.of_node); + if (!match) + return NULL; + return match->data; } - snprintf(adapter->name, sizeof(adapter->name), "AT91"); - adapter->algo = &at91_algorithm; - adapter->class = I2C_CLASS_HWMON; - adapter->dev.parent = &pdev->dev; - /* adapter->id == 0 ... only one TWI controller for now */ + return (struct at91_twi_pdata *) platform_get_device_id(pdev)->driver_data; +} + +static int __devinit at91_twi_probe(struct platform_device *pdev) +{ + struct at91_twi_dev *dev; + struct resource *mem; + int rc; + + dev = devm_kzalloc(&pdev->dev, sizeof(*dev), GFP_KERNEL); + if (!dev) + return -ENOMEM; + init_completion(&dev->cmd_complete); + dev->dev = &pdev->dev; + + mem = platform_get_resource(pdev, IORESOURCE_MEM, 0); + if (!mem) + return -ENODEV; + + dev->pdata = at91_twi_get_driver_data(pdev); + if (!dev->pdata) + return -ENODEV; - platform_set_drvdata(pdev, adapter); + dev->base = devm_request_and_ioremap(&pdev->dev, mem); + if (!dev->base) + return -EBUSY; - clk_enable(twi_clk); /* enable peripheral clock */ - at91_twi_hwinit(); /* initialize TWI controller */ + dev->irq = platform_get_irq(pdev, 0); + if (dev->irq < 0) + return dev->irq; - rc = i2c_add_numbered_adapter(adapter); + rc = devm_request_irq(&pdev->dev, dev->irq, atmel_twi_interrupt, 0, + dev_name(dev->dev), dev); if (rc) { - dev_err(&pdev->dev, "Adapter %s registration failed\n", - adapter->name); - goto fail3; + dev_err(dev->dev, "Cannot get irq %d: %d\n", dev->irq, rc); + return rc; } - dev_info(&pdev->dev, "AT91 i2c bus driver.\n"); - return 0; + platform_set_drvdata(pdev, dev); -fail3: - platform_set_drvdata(pdev, NULL); - kfree(adapter); - clk_disable(twi_clk); -fail2: - clk_put(twi_clk); -fail1: - iounmap(twi_base); -fail0: - release_mem_region(res->start, resource_size(res)); + dev->clk = devm_clk_get(dev->dev, NULL); + if (IS_ERR(dev->clk)) { + dev_err(dev->dev, "no clock defined\n"); + return -ENODEV; + } + clk_prepare_enable(dev->clk); + + at91_calc_twi_clock(dev, TWI_CLK_HZ); + at91_init_twi_bus(dev); + + snprintf(dev->adapter.name, sizeof(dev->adapter.name), "AT91"); + i2c_set_adapdata(&dev->adapter, dev); + dev->adapter.owner = THIS_MODULE; + dev->adapter.class = I2C_CLASS_HWMON; + dev->adapter.algo = &at91_twi_algorithm; + dev->adapter.dev.parent = dev->dev; + dev->adapter.nr = pdev->id; + dev->adapter.timeout = AT91_I2C_TIMEOUT; + dev->adapter.dev.of_node = pdev->dev.of_node; + + rc = i2c_add_numbered_adapter(&dev->adapter); + if (rc) { + dev_err(dev->dev, "Adapter %s registration failed\n", + dev->adapter.name); + clk_disable_unprepare(dev->clk); + return rc; + } - return rc; + of_i2c_register_devices(&dev->adapter); + + dev_info(dev->dev, "AT91 i2c bus driver.\n"); + return 0; } -static int __devexit at91_i2c_remove(struct platform_device *pdev) +static int __devexit at91_twi_remove(struct platform_device *pdev) { - struct i2c_adapter *adapter = platform_get_drvdata(pdev); - struct resource *res; + struct at91_twi_dev *dev = platform_get_drvdata(pdev); int rc; - rc = i2c_del_adapter(adapter); - platform_set_drvdata(pdev, NULL); - - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - iounmap(twi_base); - release_mem_region(res->start, resource_size(res)); - - clk_disable(twi_clk); /* disable peripheral clock */ - clk_put(twi_clk); + rc = i2c_del_adapter(&dev->adapter); + clk_disable_unprepare(dev->clk); return rc; } #ifdef CONFIG_PM -/* NOTE: could save a few mA by keeping clock off outside of at91_xfer... */ - -static int at91_i2c_suspend(struct device *dev) +static int at91_twi_runtime_suspend(struct device *dev) { - clk_disable(twi_clk); + struct at91_twi_dev *twi_dev = dev_get_drvdata(dev); + + clk_disable(twi_dev->clk); + return 0; } -static int at91_i2c_resume(struct device *dev) +static int at91_twi_runtime_resume(struct device *dev) { - return clk_enable(twi_clk); + struct at91_twi_dev *twi_dev = dev_get_drvdata(dev); + + return clk_enable(twi_dev->clk); } -static SIMPLE_DEV_PM_OPS(at91_i2c_pm, at91_i2c_suspend, at91_i2c_resume); -#define AT91_I2C_PM (&at91_i2c_pm) +static const struct dev_pm_ops at91_twi_pm = { + .runtime_suspend = at91_twi_runtime_suspend, + .runtime_resume = at91_twi_runtime_resume, +}; +#define at91_twi_pm_ops (&at91_twi_pm) #else -#define AT91_I2C_PM NULL +#define at91_twi_pm_ops NULL #endif -static struct platform_driver at91_i2c_driver = { - .probe = at91_i2c_probe, - .remove = __devexit_p(at91_i2c_remove), +static struct platform_driver at91_twi_driver = { + .probe = at91_twi_probe, + .remove = __devexit_p(at91_twi_remove), + .id_table = at91_twi_devtypes, .driver = { .name = "at91_i2c", .owner = THIS_MODULE, - .pm = AT91_I2C_PM, + .of_match_table = atmel_twi_dt_ids, + .pm = at91_twi_pm_ops, }, }; -module_platform_driver(at91_i2c_driver); +static int __init at91_twi_init(void) +{ + return platform_driver_register(&at91_twi_driver); +} + +static void __exit at91_twi_exit(void) +{ + platform_driver_unregister(&at91_twi_driver); +} + +subsys_initcall(at91_twi_init); +module_exit(at91_twi_exit); -MODULE_AUTHOR("Rick Bronson"); +MODULE_AUTHOR("Nikolaus Voss <n.voss@weinmann.de>"); MODULE_DESCRIPTION("I2C (TWI) driver for Atmel AT91"); MODULE_LICENSE("GPL"); MODULE_ALIAS("platform:at91_i2c"); diff --git a/drivers/i2c/busses/i2c-davinci.c b/drivers/i2c/busses/i2c-davinci.c index 79a2542d8c4..6a0a5531944 100644 --- a/drivers/i2c/busses/i2c-davinci.c +++ b/drivers/i2c/busses/i2c-davinci.c @@ -38,6 +38,8 @@ #include <linux/slab.h> #include <linux/cpufreq.h> #include <linux/gpio.h> +#include <linux/of_i2c.h> +#include <linux/of_device.h> #include <mach/hardware.h> #include <linux/platform_data/i2c-davinci.h> @@ -114,6 +116,7 @@ struct davinci_i2c_dev { struct completion xfr_complete; struct notifier_block freq_transition; #endif + struct davinci_i2c_platform_data *pdata; }; /* default platform data to use if not supplied in the platform_device */ @@ -155,7 +158,7 @@ static void generic_i2c_clock_pulse(unsigned int scl_pin) static void i2c_recover_bus(struct davinci_i2c_dev *dev) { u32 flag = 0; - struct davinci_i2c_platform_data *pdata = dev->dev->platform_data; + struct davinci_i2c_platform_data *pdata = dev->pdata; dev_err(dev->dev, "initiating i2c bus recovery\n"); /* Send NACK to the slave */ @@ -163,8 +166,7 @@ static void i2c_recover_bus(struct davinci_i2c_dev *dev) flag |= DAVINCI_I2C_MDR_NACK; /* write the data into mode register */ davinci_i2c_write_reg(dev, DAVINCI_I2C_MDR_REG, flag); - if (pdata) - generic_i2c_clock_pulse(pdata->scl_pin); + generic_i2c_clock_pulse(pdata->scl_pin); /* Send STOP */ flag = davinci_i2c_read_reg(dev, DAVINCI_I2C_MDR_REG); flag |= DAVINCI_I2C_MDR_STP; @@ -187,7 +189,7 @@ static inline void davinci_i2c_reset_ctrl(struct davinci_i2c_dev *i2c_dev, static void i2c_davinci_calc_clk_dividers(struct davinci_i2c_dev *dev) { - struct davinci_i2c_platform_data *pdata = dev->dev->platform_data; + struct davinci_i2c_platform_data *pdata = dev->pdata; u16 psc; u32 clk; u32 d; |