AT91: replace broken TWI driver i2c-at91.c
Subsystems (5)
v7 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.
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 (5):
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
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/at91sam9g45_devices.c | 6 - arch/arm/mach-at91/at91sam9rl.c | 2 + arch/arm/mach-at91/include/mach/at91_twi.h | 68 ---- drivers/i2c/busses/Kconfig | 11 +- drivers/i2c/busses/i2c-at91.c | 529 +++++++++++++++++----------- drivers/i2c/busses/i2c-at91.h | 80 +++++ 12 files changed, 408 insertions(+), 295 deletions(-) delete mode 100644 arch/arm/mach-at91/include/mach/at91_twi.h create mode 100644 drivers/i2c/busses/i2c-at91.h
Signature · 1 line
1.7.5.4
PATCH v7 1/5 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 v7 2/5 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 v7 3/5 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
Re: [PATCH v7 3/5] drivers/i2c/busses/i2c-at91.c: add new driver
drivers/i2c/busses/i2c-at91.c line 57
Quoted 10 lines · Nikolaus Voss
drivers/i2c/busses/i2c-at91.c new file +10
-0+ +static unsigned at91_twi_read (struct at91_twi_dev *dev,unsigned reg) +{ +return __raw_readl (dev->base + reg); +} + +static void at91_twi_write (struct at91_twi_dev *dev,unsigned reg,unsigned val) +{ +__raw_writel (val, dev->base + reg); +}
Better use readl/writel or readl_relaxed/writel_relaxed.
Quoted 4 lines
drivers/i2c/busses/i2c-at91.c new file +4
-0+/* +* Calculate and set symmetric clock as stated in datasheet: +* twi_clk = F_MAIN / (2 * cdiv * (1 << ckdiv) + 4) +*/
drivers/i2c/busses/i2c-at91.c line 86
Quoted 10 lines
drivers/i2c/busses/i2c-at91.c new file +10
-0+static void __devinit at91_set_twi_clock (struct at91_twi_dev *dev,int twi_clk) +{ +const int div =DIV_ROUND_UP (clk_get_rate (dev->clk),2 * twi_clk) -2 ; +int ckdiv =fls (div >>8 ); +const int cdiv = div >> ckdiv; + +if (cpu_is_at91rm9200 () && (ckdiv >5 )) { +dev_warn (dev->dev,"AT91RM9200 erratum 22: using ckdiv = 5.\n" ); + ckdiv =5 ; + }
Don't check a global property like this locally in the driver. Instead, make it a property of the device that you check here and set it based on the the device name set by the platform, or by a device tree property.
drivers/i2c/busses/i2c-at91.h line 4
Quoted 10 lines
drivers/i2c/busses/i2c-at91.h new file +4
-0@@ -0,0 +1,80 @@ + +#ifndef AT91_TWI_H +#define AT91_TWI_H +
No need for a header file if all the values in it are used in only one source file. Just move everything to i2c_at91.c
drivers/i2c/busses/i2c-at91.h line 36
Quoted 9 lines
drivers/i2c/busses/i2c-at91.h new file +9
-0+#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 */
These are harder to read than just using hexadecimal bitmasks:
#define AT91_TWI_MMR 0x00000004
#define AT91_TWI_IADRSZ 0x00000300
#define AT91_TWI_IADRSZ_NO 0x00000000
#define AT91_TWI_IADRSZ_1 0x00000100
...
Arnd
RE: [PATCH v7 3/5] drivers/i2c/busses/i2c-at91.c: add new driver
Hi,
Arnd Bergmann wrote on 2011-11-23:
Quoted 11 lines · Nikolaus Voss
drivers/i2c/busses/i2c-at91.c
Quoted 9 lines
drivers/i2c/busses/i2c-at91.c new file +7
-0+ +static unsigned at91_twi_read (struct at91_twi_dev *dev,unsigned reg) +{ +return __raw_readl (dev->base + reg); +} + +static void at91_twi_write(struct at91_twi_dev *dev, unsigned reg, unsignedval)
Quoted 5 lines
drivers/i2c/busses/i2c-at91.c line 57
Quoted 3 lines
drivers/i2c/busses/i2c-at91.c new file +3
-0+{ +__raw_writel (val, dev->base + reg); +}Better use readl/writel or readl_relaxed/writel_relaxed.
ok, changed.
Quoted 7 lines
drivers/i2c/busses/i2c-at91.c
Quoted 6 lines
drivers/i2c/busses/i2c-at91.c new file +5
-0+/* +* Calculate and set symmetric clock as stated in datasheet: +* twi_clk = F_MAIN / (2 * cdiv * (1 << ckdiv) + 4) +*/ +static void __devinit at91_set_twi_clock(struct at91_twi_dev *dev, int
twi_clk)
Quoted 13 lines
drivers/i2c/busses/i2c-at91.c line 86
Quoted 9 lines
drivers/i2c/busses/i2c-at91.c new file +9
-0+{ +const int div =DIV_ROUND_UP (clk_get_rate (dev->clk),2 * twi_clk) -2 ; +int ckdiv =fls (div >>8 ); +const int cdiv = div >> ckdiv; + +if (cpu_is_at91rm9200 () && (ckdiv >5 )) { +dev_warn (dev->dev,"AT91RM9200 erratum 22: using ckdiv = 5.\n" ); + ckdiv =5 ; + }Don't check a global property like this locally in the driver. Instead, make it a property of the device that you check here and set it based on the the device name set by the platform, or by a device tree property.
Yes, this is a known problem and was discussed in
https://lkml.org/lkml/2011/11/8/217 . The main problem is that there a no revisions for specific at91 IP devices but the revision is implicitly defined by the cpu type and version. Changing this would need to add some arch infrastructure which I think is beyond the scope of this driver.
Quoted 25 lines
drivers/i2c/busses/i2c-at91.h line 4
Quoted 10 lines
drivers/i2c/busses/i2c-at91.h new file +4
-0@@ -0,0 +1,80 @@ + +#ifndef AT91_TWI_H +#define AT91_TWI_H +No need for a header file if all the values in it are used in only one source file. Just move everything to
i2c_at91.cdrivers/i2c/busses/i2c-at91.h
Quoted 8 lines
drivers/i2c/busses/i2c-at91.h new file +8
-0+#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 */
drivers/i2c/busses/i2c-at91.h line 36
Quoted 1 line
drivers/i2c/busses/i2c-at91.h new file +1
-0+#define AT91_TWI_DADR (0x7f << 16)/* Device Address */
Quoted 7 lines
These are harder to read than just using hexadecimal bitmasks:
#define
AT91_TWI_MMR0x00000004
#defineAT91_TWI_IADRSZ0x00000300
#defineAT91_TWI_IADRSZ_NO0x00000000
#defineAT91_TWI_IADRSZ_10x00000100
...
I agree, but this header file was already used by the old driver and converting would add possible errors to register definitions which are not (yet) used. That's why I've left it as is and just made it a local include.
Thanks,
Niko
Re: [PATCH v7 3/5] drivers/i2c/busses/i2c-at91.c: add new driver
Quoted 21 lines · Nikolaus
Quoted 7 lines
drivers/i2c/busses/i2c-at91.c
Quoted 6 lines
drivers/i2c/busses/i2c-at91.c new file +5
-0+/* +* Calculate and set symmetric clock as stated in datasheet: +* twi_clk = F_MAIN / (2 * cdiv * (1 << ckdiv) + 4) +*/ +static void __devinit at91_set_twi_clock(struct at91_twi_dev *dev, int
twi_clk)Quoted 13 lines
drivers/i2c/busses/i2c-at91.c line 86
Quoted 9 lines
drivers/i2c/busses/i2c-at91.c new file +9
-0+{ +const int div =DIV_ROUND_UP (clk_get_rate (dev->clk),2 * twi_clk) -2 ; +int ckdiv =fls (div >>8 ); +const int cdiv = div >> ckdiv; + +if (cpu_is_at91rm9200 () && (ckdiv >5 )) { +dev_warn (dev->dev,"AT91RM9200 erratum 22: using ckdiv = 5.\n" ); + ckdiv =5 ; + }Don't check a global property like this locally in the driver. Instead, make it a property of the device that you check here and set it based on the the device name set by the platform, or by a device tree property.
Quoted 5 lines
Yes, this is a known problem and was discussed in
https://lkml.org/lkml/2011/11/8/217 . The main problem is that there a no revisions for specific at91 IP devices but the revision is implicitly defined by the cpu type and version. Changing this would need to add some arch infrastructure which I think is beyond the scope of this driver.
Aside from the flamewar in that thread, my impression is that in general people (me certainly) prefer to have driver-local workarounds be expressed in a driver specific way, not in a platform or architecture specific way because that makes the driver less portable.
Anyway, I don't see this point as a show-stopper since the driver is already platform specific, but it's generally a good idea to write code like this defensively, if only to avoid getting comments about it.
Quoted 33 lines
Quoted 25 lines
drivers/i2c/busses/i2c-at91.h line 4
Quoted 10 lines
drivers/i2c/busses/i2c-at91.h new file +4
-0@@ -0,0 +1,80 @@ + +#ifndef AT91_TWI_H +#define AT91_TWI_H +No need for a header file if all the values in it are used in only one source file. Just move everything to
i2c_at91.cdrivers/i2c/busses/i2c-at91.h
Quoted 8 lines
drivers/i2c/busses/i2c-at91.h new file +8
-0+#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 */
drivers/i2c/busses/i2c-at91.h line 36
Quoted 1 line
drivers/i2c/busses/i2c-at91.h new file +1
-0+#define AT91_TWI_DADR (0x7f << 16)/* Device Address */ Quoted 7 lines
These are harder to read than just using hexadecimal bitmasks:
#define AT91_TWI_MMR 0x00000004 #define AT91_TWI_IADRSZ 0x00000300 #define AT91_TWI_IADRSZ_NO 0x00000000 #define AT91_TWI_IADRSZ_1 0x00000100...
Quoted 4 lines
I agree, but this header file was already used by the old driver and converting would add possible errors to register definitions which are not (yet) used. That's why I've left it as is and just made it a local include.
But you are presenting the driver as a new one, so you should be prepared to get review comments like any other new code.
Please at least move the data into the main driver file to get rid of the header file.
Arnd
RE: [PATCH v7 3/5] drivers/i2c/busses/i2c-at91.c: add new driver
Hi,
Arnd Bergmann wrote on 2011-11-24:
Quoted 30 lines · Nikolaus
Quoted 9 lines
Quoted 9 lines
drivers/i2c/busses/i2c-at91.c
Quoted 6 lines
drivers/i2c/busses/i2c-at91.c new file +5
-0+/* +* Calculate and set symmetric clock as stated in datasheet: +* twi_clk = F_MAIN / (2 * cdiv * (1 << ckdiv) + 4) +*/ +static void __devinit at91_set_twi_clock(struct at91_twi_dev *dev, int
twi_clk)Quoted 2 lines
(quoted diff) +2
-0+{ + const int div = DIV_ROUND_UP(clk_get_rate(dev->clk), 2 * twi_clk) -2;
Quoted 5 lines
Quoted 5 lines
drivers/i2c/busses/i2c-at91.c
Quoted 5 lines
drivers/i2c/busses/i2c-at91.c new file +5
-0+int ckdiv =fls (div >>8 ); +const int cdiv = div >> ckdiv; + +if (cpu_is_at91rm9200 () && (ckdiv >5 )) { + dev_warn(dev->dev, "AT91RM9200 erratum 22: using ckdiv =5.\n");
Quoted 7 lines
Quoted 6 lines
Review
Quoted 2 lines
(quoted diff) +2
-0+ ckdiv = 5; + }Don't check a global property like this locally in the driver. Instead, make it a property of the device that you check here and set it based on the the device name set by the platform, or by a device tree property.
Quoted 5 lines
Yes, this is a known problem and was discussed in
https://lkml.org/lkml/2011/11/8/217 . The main problem is that there a no revisions for specific at91 IP devices but the revision is implicitly defined by the cpu type and version. Changing this would need to add some arch infrastructure which I think is beyond the scope of this driver.
Quoted 4 lines
Aside from the flamewar in that thread, my impression is that in general people (me certainly) prefer to have driver-local workarounds be expressed in a driver specific way, not in a platform or architecture specific way because that makes the driver less portable.
I guess I see your point now. So you want something like pdev.has_bugX to be set by mach setup and later check this flag in the driver?
Quoted 42 lines
Quoted 1 line
Quoted 1 line
drivers/i2c/busses/i2c-
Quoted 1 line
drivers/i2c/busses/i2c- renamed from drivers/i2c/busses/i2c-at91.h +0
-0
at91.hQuoted 13 lines
Quoted 13 lines
drivers/i2c/busses/i2c-at91.h line 4
Quoted 9 lines
new file mode 100644
index 0000000..a898159drivers/i2c/busses/i2c-at91.h new file +4
-0@@ -0,0 +1,80 @@ + +#ifndef AT91_TWI_H +#define AT91_TWI_H +No need for a header file if all the values in it are used in only one source file. Just move everything to
i2c_at91.cQuoted 1 line
Quoted 1 line
drivers/i2c/busses/i2c-at91.h line 5
Quoted 1 line
drivers/i2c/busses/i2c-at91.h new file +1
-0+#define AT91_TWI_MMR 0x04/* Master Mode Register */
Quoted 1 line
Quoted 1 line
drivers/i2c/busses/i2c-at91.h line 6
Quoted 1 line
drivers/i2c/busses/i2c-at91.h new file +1
-0+#define AT91_TWI_IADRSZ (3 << 8)/* Internal Device Address
Quoted 6 lines
Quoted 6 lines
drivers/i2c/busses/i2c-at91.h
Quoted 6 lines
drivers/i2c/busses/i2c-at91.h new file +6
-0+* 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
Quoted 11 lines
Quoted 10 lines
*/
drivers/i2c/busses/i2c-at91.h line 36
Quoted 1 line
drivers/i2c/busses/i2c-at91.h new file +1
-0+#define AT91_TWI_DADR (0x7f << 16)/* Device Address */ These are harder to read than just using hexadecimal bitmasks:
#define AT91_TWI_MMR 0x00000004 #define AT91_TWI_IADRSZ 0x00000300 #define AT91_TWI_IADRSZ_NO 0x00000000 #define AT91_TWI_IADRSZ_1 0x00000100...
Quoted 4 lines
I agree, but this header file was already used by the old driver and converting would add possible errors to register definitions which are not (yet) used. That's why I've left it as is and just made it a local include.
Quoted 5 lines
But you are presenting the driver as a new one, so you should be prepared to get review comments like any other new code.
Please at least move the data into the main driver file to get rid of the header file.
I didn't want to appear ignorant about this, I actually appreciate your comment. I just wanted to point out that there might be a reason to keep the old file which you weren't aware of (because I presented this as a new driver). So, I will move the register definitions to the main driver.
Thanks,
Niko
Re: [PATCH v7 3/5] drivers/i2c/busses/i2c-at91.c: add new driver
Quoted 7 lines · Nikolaus
Quoted 4 lines
Aside from the flamewar in that thread, my impression is that in general people (me certainly) prefer to have driver-local workarounds be expressed in a driver specific way, not in a platform or architecture specific way because that makes the driver less portable.
I guess I see your point now. So you want something like pdev.has_bugX to be set by mach setup and later check this flag in the driver?
Yes, that would be the idea. I would not introduce platform_data for one driver just for this though, because we are generally moving away from platform_data towards device tree probing.
You can do it with a match table that has two entries with different names for the two kinds of device that you need to distinguish and set the platform_device_id->driver_data field to '1' for the type that needs the fixup.
Quoted 14 lines
Quoted 14 lines
Quoted 10 lines
Quoted 5 lines
#define AT91_TWI_MMR 0x00000004 #define AT91_TWI_IADRSZ 0x00000300 #define AT91_TWI_IADRSZ_NO 0x00000000 #define AT91_TWI_IADRSZ_1 0x00000100...
I agree, but this header file was already used by the old driver and converting would add possible errors to register definitions which are not (yet) used. That's why I've left it as is and just made it a local include.
But you are presenting the driver as a new one, so you should be prepared to get review comments like any other new code.
Quoted 7 lines
Quoted 2 lines
Please at least move the data into the main driver file to get rid of the header file.
I didn't want to appear ignorant about this, I actually appreciate your comment. I just wanted to point out that there might be a reason to keep the old file which you weren't aware of (because I presented this as a new driver). So, I will move the register definitions to the main driver.
Ok, good. Moving it into the driver is really the important part anyway, and I understand your reasoning for not wanting to modify the definitions, it just didn't apply to the one of the two comments I made about the header.
Arnd
PATCH v7 4/5 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 v7 5/5 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
Quoted 27 lines · Nikolaus Voss
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.
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 forI2C_SMBUS_BLOCK_DATAtransfers.
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
Quoted 6 lines
Nikolaus Voss (5):
drivers/i2c/busses/i2c-at91.c: remove broken driver Replace clk_lookup.con_id with clk_lookup.dev_id entries for twi clkdrivers/i2c/busses/i2c-at91.c: add new driver
G45 TWI: remove open drain setting for twi function gpiosi2c-at91.c: addSMBUS_READ_BLOCK_DATAfunctionality
Is the original driver so broken that the two could not co-exist, or are we making so many changes that there's no point in keeping the original one?
Quoted 23 lines
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/at91sam9g45_devices.c | 6 - arch/arm/mach-at91/at91sam9rl.c | 2 + arch/arm/mach-at91/include/mach/at91_twi.h | 68 ---- drivers/i2c/busses/Kconfig | 11 +- drivers/i2c/busses/i2c-at91.c | 529 +++++++++++++++++----------- drivers/i2c/busses/i2c-at91.h | 80 +++++ 12 files changed, 408 insertions(+), 295 deletions(-) delete mode 100644 arch/arm/mach-at91/include/mach/at91_twi.h create mode 100644 drivers/i2c/busses/i2c-at91.hSignature · 6 lines
1.7.5.4 -- To unsubscribe from this list: send the line "unsubscribe linux-i2c" in the body of a message to majordomo at vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
Signature · 3 lines
Ben Dooks, ben at fluff.org, http://www.fluff.org/ben/ Large Hadron Colada: A large Pina Colada that makes the universe disappear.
Hi,
Ben Dooks wrote on 2011-11-24:
Quoted 35 lines · Nikolaus Voss
Quoted 27 lines
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.
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 forI2C_SMBUS_BLOCK_DATAtransfers.
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 issueQuoted 6 lines
Nikolaus Voss (5):
drivers/i2c/busses/i2c-at91.c: remove broken driver Replace clk_lookup.con_id with clk_lookup.dev_id entries for twi clkdrivers/i2c/busses/i2c-at91.c: add new driver
G45 TWI: remove open drain setting for twi function gpiosi2c-at91.c: addSMBUS_READ_BLOCK_DATAfunctionality
Quoted 3 lines
Is the original driver so broken that the two could not co-exist, or are we making so many changes that there's no point in keeping the original one?
The old driver was marked as broken for the above reasons and I can hardly imagine any setup in which it would be preferable to i2c-gpio. So it does not make any sense to keep the old driver alive. Though inspired by the old driver, the new one is almost a rewrite from scratch, so for better reviewing, I removed the old instead of doing a diff.
Niko
Quoted 42 lines · Nikolaus
Hi,
Ben Dooks wrote on 2011-11-24:
Quoted 35 lines · Nikolaus Voss
Quoted 27 lines
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.
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 forI2C_SMBUS_BLOCK_DATAtransfers.
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 issueQuoted 6 lines
Nikolaus Voss (5):
drivers/i2c/busses/i2c-at91.c: remove broken driver Replace clk_lookup.con_id with clk_lookup.dev_id entries for twi clkdrivers/i2c/busses/i2c-at91.c: add new driver
G45 TWI: remove open drain setting for twi function gpiosi2c-at91.c: addSMBUS_READ_BLOCK_DATAfunctionalityQuoted 3 lines
Is the original driver so broken that the two could not co-exist, or are we making so many changes that there's no point in keeping the original one?
Quoted 5 lines
The old driver was marked as broken for the above reasons and I can hardly imagine any setup in which it would be preferable to i2c-gpio. So it does not make any sense to keep the old driver alive. Though inspired by the old driver, the new one is almost a rewrite from scratch, so for better reviewing, I removed the old instead of doing a diff.
I can confirm this. I worked on a number of AT91 based platforms with several different i2c client devices and we always had to use the i2c-gpio driver because the at91-i2c driver would not reliably work with our client devices.
None of the at91 defconfigs select I2C_AT91, so it should be fairly safe to remove the old driver. Getting this driver into linux-next (if it isn't already) would be good so we can see if it does cause problems for anybody.
Thanks,
~Ryan
Hi,
I've tested this driver on a 2.6.38 kernel with several i2c clients (temp-sensor, audio-codec, touchscreen-controller, w1-bridge, io-expanders) and works without problems. SoC: at91sam9g45
Because of the 2.6.38 kernel, I had to skip "[PATCH v7 2/5] Replace clk_lookup.con_id with clk_lookup.dev_id entries for twi clk" and used
instead: at91_clock_associate("twi0_clk", &at91sam9g45_twi0_device.dev, "twi_clk");
Best Regards
Hubert
Quoted 9 lines · Nikolaus Voss
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.
Carsten Behling
Tested-by Hubert FeursteinHi,
I've tested this driver with the pca953x GPIO expander driver with a PCA9554.
In the case of 8 GPIO pins (my case) "i2c_smbus_read_byte_data(...)"
is called to read the registers of the GPIO expander. This results in a at91_twi_xfer with two messages. The first message is to put the register address into the IADR and the second is to read the one byte content of the register.
At the end we have a one byte read with a repeated start condition.
I observed that reading out the GPIO status is one read delayed.
The first read to a register from the pca953x driver does not result in a RXRDY interrupt and at91_twi_read_next_byte(...) is not called. Only the completion routine is triggered with a TXCOMP interrupt.
Additionally, I took a look at the status flags just after the control flags are set (in at91_do_twi_transfer(...), AT91_TWI_START|AT91_TWI_STOP for the one byte read). Surprisingly, the AT91_TWI_RXRDY flag is zero before the first register read and one for the following reads. According to the manual this flag should be zero after a read on AT91_TWI_RHR.
Reading the AT91_TWI_RHR before the control flags are set to be sure that the AT91_TWI_RXRDY is cleared leads to a never occurring RXRDY interrupt.
This looks very strange to me. Can anyone help?
Mit freundlichen Gr??en / Best regards
Carsten Behling
Development Engineer
Garz & Fricke GmbH
Tempowerkring 2, 21079 Hamburg - Germany
Amtsgericht Hamburg HRB 60514
Gesch?ftsf?hrer: Manfred Garz, Matthias Fricke
Phone: +49 (0) 40 791 899 - 56
Fax: +49 40 / 791 899 - 39
www.garz-fricke.com
-----Urspr?ngliche Nachricht-----
Von: Hubert Feurstein [mailto:h.feurstein at gmail.com]
Gesendet: Freitag, 25. November 2011 16:42
An: Nikolaus Voss
Cc: linux-i2c at vger.kernel.org; linux-arm-kernel at lists.infradead.org; linux-kernel at vger.kernel.org; ben-linux at fluff.org; Carsten Behling
Betreff: Re: [PATCH v7 0/5] AT91: replace broken TWI driver i2c-at91.c
Hi,
I've tested this driver on a 2.6.38 kernel with several i2c clients (temp-sensor, audio-codec, touchscreen-controller, w1-bridge, io-expanders) and works without problems. SoC: at91sam9g45
Because of the 2.6.38 kernel, I had to skip "[PATCH v7 2/5] Replace clk_lookup.con_id with clk_lookup.dev_id entries for twi clk" and used
instead: at91_clock_associate("twi0_clk", &at91sam9g45_twi0_device.dev, "twi_clk");
Best Regards
Hubert
Quoted 9 lines · Nikolaus Voss
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.
Hi,
Carsten Behling wrote on 2011-12-28:
Quoted 3 lines
I've tested this driver with the pca953x GPIO expander driver with a PCA9554.
In the case of 8 GPIO pins (my case) "
i2c_smbus_read_byte_data(...)"
[...]
Quoted 4 lines
I observed that reading out the GPIO status is one read delayed. The first read to a register from the pca953x driver does not result in a RXRDY interrupt and
at91_twi_read_next_byte(...)is not called. Only the completion routine is triggered with a TXCOMP interrupt.
Which SOC are you using? This is probably a hardware bug since on my at91sam9g45 i2c_smbus_read_byte_data() works reliably without any problems. Please check the errata and see if there is a useable workaround. If not, the driver should be disabled for your SOC.
Quoted 8 lines
Additionally, I took a look at the status flags just after the control flags are set (in
at91_do_twi_transfer(...), AT91_TWI_START|AT91_TWI_STOP for the one byte read). Surprisingly, theAT91_TWI_RXRDYflag is zero before the first register read and one for the following reads. According to the manual this flag should be zero after a read onAT91_TWI_RHR.Reading the
AT91_TWI_RHRbefore the control flags are set to be sure that theAT91_TWI_RXRDYis cleared leads to a never occurring RXRDY interrupt.
Again, this behavior does not conform to the datasheet, I suspect documented or undocumented errata... At91rm9200 has at least one erratum for which I imported a workaround from the old driver (which does not use interrupts).
Niko