AT91: replace broken TWI driver i2c-at91.c
Subsystems (5)
v8 cover AT91: replace broken TWI driver i2c-at91.c
The old driver has two main deficencies:
i) No repeated start (Sr) condiction is possible, this makes it unusable e.g. for most SMBus transfers.
ii) I/O was done with polling/busy waiting what caused over-/underruns
even at light system loads and clock speeds.
The new driver overcomes these deficencies and in addition allows for more than one TWI interface.
A remaining limitation is the fact, that only one repeated start is possible (two concatenated messages). This limitation is imposed by the hardware. However, this should not be a problem as all common i2c-client communication does not rely on more than one repeated start.
v8: Patch 6/7: remove local include
Patch 7/7: remove cpu_is_rm9200() and put twi hw bug info
in platform_device
Patch 3/7: use readl/writel_relaxed instead of __raw_readl/writel
v7: Patch 4/5: i) fix bug if internal address > 1 byte
ii) send stop when len == 1
(both reported by Carsten Behling)
v6: Patch 5/5: support for I2C_SMBUS_BLOCK_DATA transfers.
Better use of clk_(un)prepare().
More sensible transfer timeout.
v5: Another round of review comments from Ryan Mallon, Felipe Balbi
and Russell King: convert twi clk to use .dev_id, cleanups
v4: Integrated more review comments from Ryan Mallon and Felipe Balbi:
Moved register include file to local include, code cleanups
v3: Integrated review comments from Ryan Mallon and Felipe Balbi
v2: Fixed whitespace issue
Nikolaus Voss (7):
drivers/i2c/busses/i2c-at91.c: remove broken driver Replace clk_lookup.con_id with clk_lookup.dev_id entries for twi clk drivers/i2c/busses/i2c-at91.c: add new driver
G45 TWI: remove open drain setting for twi function gpios i2c-at91.c: add SMBUS_READ_BLOCK_DATA functionality
i2c-at91: removed local include
i2c-at91: make ckdiv bug a property of the platform_device
arch/arm/mach-at91/at91cap9.c | 1 + arch/arm/mach-at91/at91cap9_devices.c | 9 + arch/arm/mach-at91/at91rm9200.c | 1 + arch/arm/mach-at91/at91rm9200_devices.c | 9 + arch/arm/mach-at91/at91sam9260.c | 1 + arch/arm/mach-at91/at91sam9260_devices.c | 9 + arch/arm/mach-at91/at91sam9261.c | 1 + arch/arm/mach-at91/at91sam9261_devices.c | 9 + arch/arm/mach-at91/at91sam9263.c | 1 + arch/arm/mach-at91/at91sam9263_devices.c | 9 + arch/arm/mach-at91/at91sam9g45.c | 2 + arch/arm/mach-at91/at91sam9g45_devices.c | 16 +- arch/arm/mach-at91/at91sam9rl.c | 2 + arch/arm/mach-at91/at91sam9rl_devices.c | 9 + arch/arm/mach-at91/include/mach/at91_twi.h | 68 ---- drivers/i2c/busses/Kconfig | 11 +- drivers/i2c/busses/i2c-at91.c | 563 +++++++++++++++++----------- 17 files changed, 424 insertions(+), 297 deletions(-) delete mode 100644 arch/arm/mach-at91/include/mach/at91_twi.h
Signature · 1 line
1.7.5.4
PATCH v8 1/7 drivers/i2c/busses/i2c-at91.c: remove broken driver
--- arch/arm/mach-at91/include/mach/at91_twi.h | 68 ------ drivers/i2c/busses/Makefile | 1 - drivers/i2c/busses/i2c-at91.c | 327 ---------------------------- 3 files changed, 0 insertions(+), 396 deletions(-) delete mode 100644 arch/arm/mach-at91/include/mach/at91_twi.h delete mode 100644 drivers/i2c/busses/i2c-at91.c
arch/arm/mach-at91/include/mach/at91_twi.h deleted +0 -68
@@ -1,68 +0,0 @@ -/* -* arch/arm/mach-at91/include/mach/at91_twi.h -* -* Copyright (C) 2005 Ivan Kokshaysky -* Copyright (C) SAN People -* -* Two-wire Interface (TWI) registers. -* Based on AT91RM9200 datasheet revision E. -* -* 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. -*/ - -#ifndef AT91_TWI_H -#define AT91_TWI_H - -#define AT91_TWI_CR 0x00/* Control Register */ -#define AT91_TWI_START (1 << 0)/* Send a Start Condition */ -#define AT91_TWI_STOP (1 << 1)/* Send a Stop Condition */ -#define AT91_TWI_MSEN (1 << 2)/* Master Transfer Enable */ -#define AT91_TWI_MSDIS (1 << 3)/* Master Transfer Disable */ -#define AT91_TWI_SVEN (1 << 4)/* Slave Transfer Enable [SAM9260 only] */ -#define AT91_TWI_SVDIS (1 << 5)/* Slave Transfer Disable [SAM9260 only] */ -#define AT91_TWI_SWRST (1 << 7)/* Software Reset */ - -#define AT91_TWI_MMR 0x04/* Master Mode Register */ -#define AT91_TWI_IADRSZ (3 << 8)/* Internal Device Address Size */ -#define AT91_TWI_IADRSZ_NO (0 << 8) -#define AT91_TWI_IADRSZ_1 (1 << 8) -#define AT91_TWI_IADRSZ_2 (2 << 8) -#define AT91_TWI_IADRSZ_3 (3 << 8) -#define AT91_TWI_MREAD (1 << 12)/* Master Read Direction */ -#define AT91_TWI_DADR (0x7f << 16)/* Device Address */ - -#define AT91_TWI_SMR 0x08/* Slave Mode Register [SAM9260 only] */ -#define AT91_TWI_SADR (0x7f << 16)/* Slave Address */ - -#define AT91_TWI_IADR 0x0c/* Internal Address Register */ - -#define AT91_TWI_CWGR 0x10/* Clock Waveform Generator Register */ -#define AT91_TWI_CLDIV (0xff << 0)/* Clock Low Divisor */ -#define AT91_TWI_CHDIV (0xff << 8)/* Clock High Divisor */ -#define AT91_TWI_CKDIV (7 << 16)/* Clock Divider */ - -#define AT91_TWI_SR 0x20/* Status Register */ -#define AT91_TWI_TXCOMP (1 << 0)/* Transmission Complete */ -#define AT91_TWI_RXRDY (1 << 1)/* Receive Holding Register Ready */ -#define AT91_TWI_TXRDY (1 << 2)/* Transmit Holding Register Ready */ -#define AT91_TWI_SVREAD (1 << 3)/* Slave Read [SAM9260 only] */ -#define AT91_TWI_SVACC (1 << 4)/* Slave Access [SAM9260 only] */ -#define AT91_TWI_GACC (1 << 5)/* General Call Access [SAM9260 only] */ -#define AT91_TWI_OVRE (1 << 6)/* Overrun Error [AT91RM9200 only] */ -#define AT91_TWI_UNRE (1 << 7)/* Underrun Error [AT91RM9200 only] */ -#define AT91_TWI_NACK (1 << 8)/* Not Acknowledged */ -#define AT91_TWI_ARBLST (1 << 9)/* Arbitration Lost [SAM9260 only] */ -#define AT91_TWI_SCLWS (1 << 10)/* Clock Wait State [SAM9260 only] */ -#define AT91_TWI_EOSACC (1 << 11)/* End of Slave Address [SAM9260 only] */ - -#define AT91_TWI_IER 0x24/* Interrupt Enable Register */ -#define AT91_TWI_IDR 0x28/* Interrupt Disable Register */ -#define AT91_TWI_IMR 0x2c/* Interrupt Mask Register */ -#define AT91_TWI_RHR 0x30/* Receive Holding Register */ -#define AT91_TWI_THR 0x34/* Transmit Holding Register */ - -#endif -
drivers/i2c/busses/Makefile +0 -1
@@ -28,7 +28,6 @@ obj-$(CONFIG_I2C_HYDRA) += i2c-hydra.o obj-$(CONFIG_I2C_POWERMAC) += i2c-powermac.o # Embedded system I2C/SMBus host controller drivers -obj-$(CONFIG_I2C_AT91) += i2c-at91.o obj-$(CONFIG_I2C_AU1550) += i2c-au1550.o obj-$(CONFIG_I2C_BLACKFIN_TWI) += i2c-bfin-twi.o obj-$(CONFIG_I2C_CPM) += i2c-cpm.o
drivers/i2c/busses/i2c-at91.c deleted +0 -327
327 lines not on this page · raw message
Signature · 1 line
1.7.5.4
PATCH v8 2/7 Replace clk_lookup.con_id with clk_lookup.dev_id entries for twi clk
In reply to Nikolaus VossThe old driver used con_id clock entries. Convert to use dev_id for clock lookup via standard method.
--- arch/arm/mach-at91/at91cap9.c | 1 + arch/arm/mach-at91/at91rm9200.c | 1 + arch/arm/mach-at91/at91sam9260.c | 1 + arch/arm/mach-at91/at91sam9261.c | 1 + arch/arm/mach-at91/at91sam9263.c | 1 + arch/arm/mach-at91/at91sam9g45.c | 2 ++ arch/arm/mach-at91/at91sam9rl.c | 2 ++ 7 files changed, 9 insertions(+), 0 deletions(-)
arch/arm/mach-at91/at91cap9.c +1 -0
@@ -219,6 +219,7 @@ static struct clk_lookup periph_clocks_lookups[] = {CLKDEV_CON_DEV_ID ("t0_clk" ,"atmel_tcb.0" , &tcb_clk),CLKDEV_CON_DEV_ID ("pclk" ,"ssc.0" , &ssc0_clk),CLKDEV_CON_DEV_ID ("pclk" ,"ssc.1" , &ssc1_clk), +CLKDEV_CON_DEV_ID (NULL ,"at91_i2c" , &twi_clk),/* fake hclk clock */ CLKDEV_CON_DEV_ID("hclk", "at91_ohci", &ohci_clk), };
arch/arm/mach-at91/at91rm9200.c +1 -0
@@ -193,6 +193,7 @@ static struct clk_lookup periph_clocks_lookups[] = {CLKDEV_CON_DEV_ID ("pclk" ,"ssc.0" , &ssc0_clk),CLKDEV_CON_DEV_ID ("pclk" ,"ssc.1" , &ssc1_clk),CLKDEV_CON_DEV_ID ("pclk" ,"ssc.2" , &ssc2_clk), +CLKDEV_CON_DEV_ID (NULL ,"at91_i2c" , &twi_clk),/* fake hclk clock */ CLKDEV_CON_DEV_ID("hclk", "at91_ohci", &ohci_clk), };
arch/arm/mach-at91/at91sam9260.c +1 -0
@@ -199,6 +199,7 @@ static struct clk_lookup periph_clocks_lookups[] = {CLKDEV_CON_DEV_ID ("t4_clk" ,"atmel_tcb.1" , &tc4_clk),CLKDEV_CON_DEV_ID ("t5_clk" ,"atmel_tcb.1" , &tc5_clk),CLKDEV_CON_DEV_ID ("pclk" ,"ssc.0" , &ssc_clk), +CLKDEV_CON_DEV_ID (NULL ,"at91_i2c" , &twi_clk),/* more usart lookup table for DT entries */ CLKDEV_CON_DEV_ID ("usart" ,"fffff200.serial" , &mck), CLKDEV_CON_DEV_ID("usart", "fffb0000.serial", &usart0_clk),
arch/arm/mach-at91/at91sam9261.c +1 -0
@@ -176,6 +176,7 @@ static struct clk_lookup periph_clocks_lookups[] = {CLKDEV_CON_DEV_ID ("pclk" ,"ssc.1" , &ssc1_clk),CLKDEV_CON_DEV_ID ("pclk" ,"ssc.2" , &ssc2_clk),CLKDEV_CON_DEV_ID ("hclk" ,"at91_ohci" , &hck0), + CLKDEV_CON_DEV_ID(NULL, "at91_i2c", &twi_clk), }; static struct clk_lookup usart_clocks_lookups[] = {
arch/arm/mach-at91/at91sam9263.c +1 -0
@@ -189,6 +189,7 @@ static struct clk_lookup periph_clocks_lookups[] = {CLKDEV_CON_DEV_ID ("spi_clk" ,"atmel_spi.0" , &spi0_clk),CLKDEV_CON_DEV_ID ("spi_clk" ,"atmel_spi.1" , &spi1_clk),CLKDEV_CON_DEV_ID ("t0_clk" ,"atmel_tcb.0" , &tcb_clk), +CLKDEV_CON_DEV_ID (NULL ,"at91_i2c" , &twi_clk),/* fake hclk clock */ CLKDEV_CON_DEV_ID("hclk", "at91_ohci", &ohci_clk), };
arch/arm/mach-at91/at91sam9g45.c +2 -0
@@ -220,6 +220,8 @@ static struct clk_lookup periph_clocks_lookups[] = {CLKDEV_CON_DEV_ID ("spi_clk" ,"atmel_spi.1" , &spi1_clk),CLKDEV_CON_DEV_ID ("t0_clk" ,"atmel_tcb.0" , &tcb0_clk),CLKDEV_CON_DEV_ID ("t0_clk" ,"atmel_tcb.1" , &tcb0_clk), +CLKDEV_CON_DEV_ID (NULL ,"at91_i2c.0" , &twi0_clk), +CLKDEV_CON_DEV_ID (NULL ,"at91_i2c.1" , &twi1_clk),CLKDEV_CON_DEV_ID ("pclk" ,"ssc.0" , &ssc0_clk),CLKDEV_CON_DEV_ID ("pclk" ,"ssc.1" , &ssc1_clk), CLKDEV_CON_DEV_ID(NULL, "atmel-trng", &trng_clk),
arch/arm/mach-at91/at91sam9rl.c +2 -0
@@ -184,6 +184,8 @@ static struct clk_lookup periph_clocks_lookups[] = {CLKDEV_CON_DEV_ID ("t2_clk" ,"atmel_tcb.0" , &tc2_clk),CLKDEV_CON_DEV_ID ("pclk" ,"ssc.0" , &ssc0_clk),CLKDEV_CON_DEV_ID ("pclk" ,"ssc.1" , &ssc1_clk), +CLKDEV_CON_DEV_ID (NULL ,"at91_i2c.0" , &twi0_clk), + CLKDEV_CON_DEV_ID(NULL, "at91_i2c.1", &twi1_clk), }; static struct clk_lookup usart_clocks_lookups[] = {
Signature · 1 line
1.7.5.4
PATCH v8 3/7 drivers/i2c/busses/i2c-at91.c: add new driver
In reply to Nikolaus VossThis driver has the following properties compared to the old driver:
1. Support for multiple interfaces.
2. Interrupt driven I/O as opposed to polling/busy waiting.
3. Support for _one_ repeated start (Sr) condition, which is enough for most real-world applications including all SMBus transfer types. (The hardware does not support issuing arbitrary Sr conditions on the
bus.)
Tested on Atmel G45 with BQ20Z80 battery SMBus client.
--- drivers/i2c/busses/Kconfig | 11 +- drivers/i2c/busses/Makefile | 1 + drivers/i2c/busses/i2c-at91.c | 412 +++++++++++++++++++++++++++++++++++++++++ drivers/i2c/busses/i2c-at91.h | 80 ++++++++ 4 files changed, 497 insertions(+), 7 deletions(-) create mode 100644 drivers/i2c/busses/i2c-at91.c create mode 100644 drivers/i2c/busses/i2c-at91.h
drivers/i2c/busses/Kconfig +4 -7
@@ -285,18 +285,15 @@ 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. config I2C_AU1550 tristate "Au1550/Au1200 SMBus interface"
drivers/i2c/busses/Makefile +1 -0
@@ -28,6 +28,7 @@ obj-$(CONFIG_I2C_HYDRA) += i2c-hydra.o obj-$(CONFIG_I2C_POWERMAC) += i2c-powermac.o # Embedded system I2C/SMBus host controller drivers +obj-$(CONFIG_I2C_AT91) += i2c-at91.o obj-$(CONFIG_I2C_AU1550) += i2c-au1550.o obj-$(CONFIG_I2C_BLACKFIN_TWI) += i2c-bfin-twi.o obj-$(CONFIG_I2C_CPM) += i2c-cpm.o
drivers/i2c/busses/i2c-at91.c new file +412 -0
412 lines not on this page · raw message
drivers/i2c/busses/i2c-at91.h new file +80 -0
80 lines not on this page · raw message
Signature · 1 line
1.7.5.4
PATCH v8 4/7 G45 TWI: remove open drain setting for twi function gpios
In reply to Nikolaus VossThe G45 datasheets explicitly states that setting the open drain property on peripheral function gpios is not allowed. (How about other A91 chips?)
--- arch/arm/mach-at91/at91sam9g45_devices.c | 6 ------ 1 files changed, 0 insertions(+), 6 deletions(-)
arch/arm/mach-at91/at91sam9g45_devices.c +0 -6
@@ -684,18 +684,12 @@ void __init at91_add_device_i2c(short i2c_id, struct i2c_board_info *devices, in/* pins used for TWI interface */ if (i2c_id ==0 ) {at91_set_A_periph (AT91_PIN_PA20 ,0 );/* TWD */ -at91_set_multi_drive (AT91_PIN_PA20 ,1 ); -at91_set_A_periph (AT91_PIN_PA21 ,0 );/* TWCK */ -at91_set_multi_drive (AT91_PIN_PA21 ,1 );platform_device_register (&at91sam9g45_twi0_device); }else {at91_set_A_periph (AT91_PIN_PB10 ,0 );/* TWD */ -at91_set_multi_drive (AT91_PIN_PB10 ,1 ); -at91_set_A_periph (AT91_PIN_PB11 ,0 );/* TWCK */ -at91_set_multi_drive (AT91_PIN_PB11 ,1 );platform_device_register (&at91sam9g45_twi1_device); }
Signature · 1 line
1.7.5.4
PATCH v8 5/7 i2c-at91.c: add SMBUS_READ_BLOCK_DATA functionality
In reply to Nikolaus VossSMBus emulation uses I2C_M_RECV_LEN flag to indicate a SMBus block read operation in which the length of a transfer is inicated by the first received byte.
Make better use of clk_prepare()/clk_unprepare().
More sensible transfer timeout.
--- drivers/i2c/busses/i2c-at91.c | 44 +++++++++++++++++++++++++++------------- 1 files changed, 30 insertions(+), 14 deletions(-)
drivers/i2c/busses/i2c-at91.c +30 -14
@@ -32,7 +32,7 @@#include "i2c-at91.h" #define TWI_CLK_HZ 100000/* max 400 Kbits/s */ -#define AT91_I2C_TIMEOUT msecs_to_jiffies(10)/* transfer timeout */ +#define AT91_I2C_TIMEOUT msecs_to_jiffies(100)/* transfer timeout */ struct at91_twi_dev {struct device *dev;
@@ -41,6 +41,7 @@ struct at91_twi_dev {struct clk *clk;u8 *buf;size_t buf_len; +struct i2c_msg *msg;int irq;unsigned transfer_status;struct i2c_adapter adapter;
@@ -113,9 +114,18 @@ static void at91_twi_write_next_byte(struct at91_twi_dev *dev)static void at91_twi_read_next_byte (struct at91_twi_dev *dev) { *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 ) +if (dev->buf_len ==1 )at91_twi_write (dev,AT91_TWI_CR ,AT91_TWI_STOP );dev_dbg (dev->dev,"read 0x%x, to go %d\n" , *dev->buf, dev->buf_len);
@@ -144,17 +154,21 @@ static irqreturn_t atmel_twi_interrupt(int irq, void *dev_id)return IRQ_HANDLED ; } -static int at91_do_twi_transfer (struct at91_twi_dev *dev,bool is_read) +static int at91_do_twi_transfer (struct at91_twi_dev *dev) {int ret; +dev_dbg (dev->dev,"transfer: %s %d bytes.\n" , + (dev->msg->flags &I2C_M_RD ) ?"read" :"write" , dev->buf_len); +INIT_COMPLETION (dev->cmd_complete); -if (is_read) { -if (dev->buf_len <=1 ) -at91_twi_write (dev,AT91_TWI_CR , -AT91_TWI_START |AT91_TWI_STOP ); -else -at91_twi_write (dev,AT91_TWI_CR ,AT91_TWI_START ); +if (dev->msg->flags &I2C_M_RD ) { +unsigned start_flags =AT91_TWI_START ; + +/* 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 {
@@ -229,17 +243,17 @@ static int at91_twi_xfer(struct i2c_adapter *adap, struct i2c_msg *msg, int num) dev->buf_len = m_start->len; dev->buf = m_start->buf; + dev->msg = m_start; - ret =at91_do_twi_transfer (dev, m_start->flags &I2C_M_RD ); -if (ret <0 ) -return ret; + ret =at91_do_twi_transfer (dev); -return num; +return (ret <0 ) ? ret : num; }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_twi_algorithm = {
@@ -326,6 +340,7 @@ err_unuse_clocks:iounmap (dev->base); err_mem_ioremap:clk_disable (dev->clk); +clk_unprepare (dev->clk);clk_put (dev->clk); err_free_mem:kfree (dev);
@@ -343,6 +358,7 @@ static int __devexit at91_twi_remove(struct platform_device *pdev) rc =i2c_del_adapter (&dev->adapter);clk_disable (dev->clk); +clk_unprepare (dev->clk);clk_put (dev->clk);free_irq (dev->irq, dev);iounmap (dev->base);
Signature · 1 line
1.7.5.4
PATCH v8 6/7 i2c-at91: removed local include
In reply to Nikolaus VossRegister definitions are directly placed into the driver file.
--- drivers/i2c/busses/i2c-at91.c | 33 ++++++++++++++++- drivers/i2c/busses/i2c-at91.h | 80 ----------------------------------------- 2 files changed, 31 insertions(+), 82 deletions(-) delete mode 100644 drivers/i2c/busses/i2c-at91.h
drivers/i2c/busses/i2c-at91.c +31 -2
@@ -29,11 +29,40 @@#include <mach/cpu.h> -#include "i2c-at91.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 */ + +#define AT91_TWI_OVRE 0x0040/* Overrun Error */ +#define AT91_TWI_UNRE 0x0080/* Underrun Error */ +#define AT91_TWI_NACK 0x0100/* Not Acknowledged */ + +#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_dev {struct device *dev;void __iomem *base;
drivers/i2c/busses/i2c-at91.h deleted +0 -80
80 lines not on this page · raw message
Signature · 1 line
1.7.5.4
PATCH v8 7/7 i2c-at91: make ckdiv bug a property of the platform_device
In reply to Nikolaus VossThe twi IP of AT91RM9200 has a bug which limits ckdiv to be less than or equal to 5. Previously, this was checked in the driver with cpu_is_rm9200(). This patch moves this information into the platform_device as suggested by Arnd Bergmann.
--- arch/arm/mach-at91/at91cap9_devices.c | 9 +++++++++ arch/arm/mach-at91/at91rm9200_devices.c | 9 +++++++++ arch/arm/mach-at91/at91sam9260_devices.c | 9 +++++++++ arch/arm/mach-at91/at91sam9261_devices.c | 9 +++++++++ arch/arm/mach-at91/at91sam9263_devices.c | 9 +++++++++ arch/arm/mach-at91/at91sam9g45_devices.c | 10 ++++++++++ arch/arm/mach-at91/at91sam9rl_devices.c | 9 +++++++++ drivers/i2c/busses/i2c-at91.c | 7 ++++--- 8 files changed, 68 insertions(+), 3 deletions(-)
arch/arm/mach-at91/at91cap9_devices.c +9 -0
@@ -496,9 +496,18 @@ static struct resource twi_resources[] = { }, }; +static const struct platform_device_id twi_id = { +/* +* driver_data is "1" for hardware with ckdiv upper limit == 5 +* (AT91RM9200 erratum 22), "0" for twi modules without this bug +*/ + .driver_data =0 , +}; +static struct platform_device at91cap9_twi_device = { .name ="at91_i2c" , .id =-1 , + .id_entry = &twi_id, .resource = twi_resources, .num_resources =ARRAY_SIZE (twi_resources), };
arch/arm/mach-at91/at91rm9200_devices.c +9 -0
@@ -493,9 +493,18 @@ static struct resource twi_resources[] = { }, }; +static const struct platform_device_id twi_id = { +/* +* driver_data is "1" for hardware with ckdiv upper limit == 5 +* (AT91RM9200 erratum 22), "0" for twi modules without this bug +*/ + .driver_data =1 , +}; +static struct platform_device at91rm9200_twi_device = { .name ="at91_i2c" , .id =-1 , + .id_entry = &twi_id, .resource = twi_resources, .num_resources =ARRAY_SIZE (twi_resources), };
arch/arm/mach-at91/at91sam9260_devices.c +9 -0
@@ -498,9 +498,18 @@ static struct resource twi_resources[] = { }, }; +static const struct platform_device_id twi_id = { +/* +* driver_data is "1" for hardware with ckdiv upper limit == 5 +* (AT91RM9200 erratum 22), "0" for twi modules without this bug +*/ + .driver_data =0 , +}; +static struct platform_device at91sam9260_twi_device = { .name ="at91_i2c" , .id =-1 , + .id_entry = &twi_id, .resource = twi_resources, .num_resources =ARRAY_SIZE (twi_resources), };
arch/arm/mach-at91/at91sam9261_devices.c +9 -0
@@ -315,9 +315,18 @@ static struct resource twi_resources[] = { }, }; +static const struct platform_device_id twi_id = { +/* +* driver_data is "1" for hardware with ckdiv upper limit == 5 +* (AT91RM9200 erratum 22), "0" for twi modules without this bug +*/ + .driver_data =0 , +}; +static struct platform_device at91sam9261_twi_device = { .name ="at91_i2c" , .id =-1 , + .id_entry = &twi_id, .resource = twi_resources, .num_resources =ARRAY_SIZE (twi_resources), };
arch/arm/mach-at91/at91sam9263_devices.c +9 -0
@@ -571,9 +571,18 @@ static struct resource twi_resources[] = { }, }; +static const struct platform_device_id twi_id = { +/* +* driver_data is "1" for hardware with ckdiv upper limit == 5 +* (AT91RM9200 erratum 22), "0" for twi modules without this bug +*/ + .driver_data =0 , +}; +static struct platform_device at91sam9263_twi_device = { .name ="at91_i2c" , .id =-1 , + .id_entry = &twi_id, .resource = twi_resources, .num_resources =ARRAY_SIZE (twi_resources), };
arch/arm/mach-at91/at91sam9g45_devices.c +10 -0
@@ -650,9 +650,18 @@ static struct resource twi0_resources[] = { }, }; +static const struct platform_device_id twi_id = { +/* +* driver_data is "1" for hardware with ckdiv upper limit == 5 +* (AT91RM9200 erratum 22), "0" for twi modules without this bug +*/ + .driver_data =0 , +}; +static struct platform_device at91sam9g45_twi0_device = { .name ="at91_i2c" , .id =0 , + .id_entry = &twi_id, .resource = twi0_resources, .num_resources =ARRAY_SIZE (twi0_resources), };
@@ -673,6 +682,7 @@ static struct resource twi1_resources[] = {static struct platform_device at91sam9g45_twi1_device = { .name ="at91_i2c" , .id =1 , + .id_entry = &twi_id, .resource = twi1_resources, .num_resources =ARRAY_SIZE (twi1_resources), };
arch/arm/mach-at91/at91sam9rl_devices.c +9 -0
@@ -350,9 +350,18 @@ static struct resource twi_resources[] = { }, }; +static const struct platform_device_id twi_id = { +/* +* driver_data is "1" for hardware with ckdiv upper limit == 5 +* (AT91RM9200 erratum 22), "0" for twi modules without this bug +*/ + .driver_data =0 , +}; +static struct platform_device at91sam9rl_twi_device = { .name ="at91_i2c" , .id =-1 , + .id_entry = &twi_id, .resource = twi_resources, .num_resources =ARRAY_SIZE (twi_resources), };
drivers/i2c/busses/i2c-at91.c +4 -3
@@ -27,8 +27,6 @@#include <linux/platform_device.h> #include <linux/slab.h> -#include <mach/cpu.h> -#define TWI_CLK_HZ 100000/* max 400 Kbits/s */ #define AT91_I2C_TIMEOUT msecs_to_jiffies(100)/* transfer timeout */
@@ -74,6 +72,7 @@ struct at91_twi_dev {int irq;unsigned transfer_status;struct i2c_adapter adapter; +bool has_ckdiv_limit_bug; };static unsigned at91_twi_read (struct at91_twi_dev *dev,unsigned reg)
@@ -110,7 +109,7 @@ static void __devinit at91_set_twi_clock(struct at91_twi_dev *dev, int twi_clk)int ckdiv =fls (div >>8 );const int cdiv = div >> ckdiv; -if (cpu_is_at91rm9200 () && (ckdiv >5 )) { +if (dev->has_ckdiv_limit_bug && (ckdiv >5 )) {dev_warn (dev->dev,"AT91RM9200 erratum 22: using ckdiv = 5.\n" ); ckdiv =5 ; }
@@ -314,6 +313,8 @@ static int __devinit at91_twi_probe(struct platform_device *pdev) goto err_release_region; } + dev->has_ckdiv_limit_bug = pdev->id_entry->driver_data ==1 ; +init_completion (&dev->cmd_complete); dev->dev = &pdev->dev;
Signature · 1 line
1.7.5.4