linux-i2c.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH v11 1/4] drivers/i2c/busses/i2c-at91.c: remove old polling driver
       [not found] ` <cover.1345618760.git.n.voss-+umVssTZoCsb1SvskN2V4Q@public.gmane.org>
@ 2011-11-08 10:49   ` Nikolaus Voss
  2011-11-08 10:49   ` [PATCH v11 3/4] drivers/i2c/busses/i2c-at91.c: add new driver Nikolaus Voss
                     ` (2 subsequent siblings)
  3 siblings, 0 replies; 21+ messages in thread
From: Nikolaus Voss @ 2011-11-08 10:49 UTC (permalink / raw)
  To: linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r,
	linux-kernel-u79uwXL29TY76Z2rM5mHXA,
	linux-i2c-u79uwXL29TY76Z2rM5mHXA
  Cc: nicolas.ferre-AIFe0yeh4nAAvxtiuMwx3w,
	ben-linux-elnMNo+KYs3YtjvyW6yDsg, balbi-l0cyMroinI0,
	h.feurstein-Re5JQEeQqe8AvxtiuMwx3w,
	rmallon-Re5JQEeQqe8AvxtiuMwx3w, adrian.yanes-uOixanVlb7U,
	ludovic.desroches-AIFe0yeh4nAAvxtiuMwx3w,
	carsten.behling-0M7HhAU3Y85FsXB23wyQUg

Signed-off-by: Nikolaus Voss <n.voss-+umVssTZoCsb1SvskN2V4Q@public.gmane.org>
---
 arch/arm/mach-at91/include/mach/at91_twi.h |   68 ------
 drivers/i2c/busses/Makefile                |    1 -
 drivers/i2c/busses/i2c-at91.c              |  314 ----------------------------
 3 files changed, 383 deletions(-)
 delete mode 100644 arch/arm/mach-at91/include/mach/at91_twi.h
 delete mode 100644 drivers/i2c/busses/i2c-at91.c

diff --git a/arch/arm/mach-at91/include/mach/at91_twi.h b/arch/arm/mach-at91/include/mach/at91_twi.h
deleted file mode 100644
index bb2880f..0000000
--- a/arch/arm/mach-at91/include/mach/at91_twi.h
+++ /dev/null
@@ -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
-
diff --git a/drivers/i2c/busses/Makefile b/drivers/i2c/busses/Makefile
index ce3c2be..4f46873 100644
--- a/drivers/i2c/busses/Makefile
+++ b/drivers/i2c/busses/Makefile
@@ -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
diff --git a/drivers/i2c/busses/i2c-at91.c b/drivers/i2c/busses/i2c-at91.c
deleted file mode 100644
index 1679dee..0000000
--- a/drivers/i2c/busses/i2c-at91.c
+++ /dev/null
@@ -1,314 +0,0 @@
-/*
-    i2c Support for Atmel's AT91 Two-Wire Interface (TWI)
-
-    Copyright (C) 2004 Rick Bronson
-    Converted to 2.6 by Andrew Victor <andrew-eS41wJS13H5l57MIdRCFDg@public.gmane.org>
-
-    Borrowed heavily from original work by:
-    Copyright (C) 2000 Philip Edelbrock <phil-LT64U7CwzWEZMC/lefXSXFaTQe2KTcn/@public.gmane.org>
-
-    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/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/io.h>
-
-#include <mach/at91_twi.h>
-#include <mach/board.h>
-#include <mach/cpu.h>
-
-#define TWI_CLOCK		100000		/* Hz. max 400 Kbits/sec */
-
-
-static struct clk *twi_clk;
-static void __iomem *twi_base;
-
-#define at91_twi_read(reg)		__raw_readl(twi_base + (reg))
-#define at91_twi_write(reg, val)	__raw_writel((val), twi_base + (reg))
-
-
-/*
- * Initialize the TWI hardware registers.
- */
-static void __devinit at91_twi_hwinit(void)
-{
-	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;
-	}
-
-	if (cpu_is_at91rm9200()) {			/* AT91RM9200 Errata #22 */
-		if (ckdiv > 5) {
-			printk(KERN_ERR "AT91 I2C: Invalid TWI_CLOCK value!\n");
-			ckdiv = 5;
-		}
-	}
-
-	at91_twi_write(AT91_TWI_CWGR, (ckdiv << 16) | (cdiv << 8) | cdiv);
-}
-
-/*
- * 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)
-{
-	int loop_cntr = 10000;
-
-	do {
-		udelay(10);
-	} while (!(at91_twi_read(AT91_TWI_SR) & bit) && (--loop_cntr > 0));
-
-	return (loop_cntr > 0);
-}
-
-static int xfer_read(struct i2c_adapter *adap, unsigned char *buf, int length)
-{
-	/* 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);
-	}
-
-	return 0;
-}
-
-static int xfer_write(struct i2c_adapter *adap, unsigned char *buf, int length)
-{
-	/* Load first byte into transmitter */
-	at91_twi_write(AT91_TWI_THR, *buf++);
-
-	/* Send Start */
-	at91_twi_write(AT91_TWI_CR, AT91_TWI_START);
-
-	do {
-		if (!at91_poll_status(AT91_TWI_TXRDY)) {
-			dev_dbg(&adap->dev, "TXRDY timeout\n");
-			return -ETIMEDOUT;
-		}
-
-		length--;	/* byte was transmitted */
-
-		if (length > 0)		/* more data to send? */
-			at91_twi_write(AT91_TWI_THR, *buf++);
-	} while (length);
-
-	/* Send Stop */
-	at91_twi_write(AT91_TWI_CR, AT91_TWI_STOP);
-
-	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)
-{
-	int i, ret;
-
-	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;
-			}
-		}
-		dev_dbg(&adap->dev, "transfer complete\n");
-		pmsg++;		/* next message */
-	}
-	return i;
-}
-
-/*
- * Return list of supported functionality.
- */
-static u32 at91_func(struct i2c_adapter *adapter)
-{
-	return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL;
-}
-
-static struct i2c_algorithm at91_algorithm = {
-	.master_xfer	= at91_xfer,
-	.functionality	= at91_func,
-};
-
-/*
- * Main initialization routine.
- */
-static int __devinit at91_i2c_probe(struct platform_device *pdev)
-{
-	struct i2c_adapter *adapter;
-	struct resource *res;
-	int rc;
-
-	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-	if (!res)
-		return -ENXIO;
-
-	if (!request_mem_region(res->start, resource_size(res), "at91_i2c"))
-		return -EBUSY;
-
-	twi_base = ioremap(res->start, resource_size(res));
-	if (!twi_base) {
-		rc = -ENOMEM;
-		goto fail0;
-	}
-
-	twi_clk = clk_get(NULL, "twi_clk");
-	if (IS_ERR(twi_clk)) {
-		dev_err(&pdev->dev, "no clock defined\n");
-		rc = -ENODEV;
-		goto fail1;
-	}
-
-	adapter = kzalloc(sizeof(struct i2c_adapter), GFP_KERNEL);
-	if (adapter == NULL) {
-		dev_err(&pdev->dev, "can't allocate inteface!\n");
-		rc = -ENOMEM;
-		goto fail2;
-	}
-	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 */
-
-	platform_set_drvdata(pdev, adapter);
-
-	clk_enable(twi_clk);		/* enable peripheral clock */
-	at91_twi_hwinit();		/* initialize TWI controller */
-
-	rc = i2c_add_numbered_adapter(adapter);
-	if (rc) {
-		dev_err(&pdev->dev, "Adapter %s registration failed\n",
-				adapter->name);
-		goto fail3;
-	}
-
-	dev_info(&pdev->dev, "AT91 i2c bus driver.\n");
-	return 0;
-
-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));
-
-	return rc;
-}
-
-static int __devexit at91_i2c_remove(struct platform_device *pdev)
-{
-	struct i2c_adapter *adapter = platform_get_drvdata(pdev);
-	struct resource *res;
-	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);
-
-	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 platform_device *pdev, pm_message_t mesg)
-{
-	clk_disable(twi_clk);
-	return 0;
-}
-
-static int at91_i2c_resume(struct platform_device *pdev)
-{
-	return clk_enable(twi_clk);
-}
-
-#else
-#define at91_i2c_suspend	NULL
-#define at91_i2c_resume		NULL
-#endif
-
-static struct platform_driver at91_i2c_driver = {
-	.probe		= at91_i2c_probe,
-	.remove		= __devexit_p(at91_i2c_remove),
-	.suspend	= at91_i2c_suspend,
-	.resume		= at91_i2c_resume,
-	.driver		= {
-		.name	= "at91_i2c",
-		.owner	= THIS_MODULE,
-	},
-};
-
-module_platform_driver(at91_i2c_driver);
-
-MODULE_AUTHOR("Rick Bronson");
-MODULE_DESCRIPTION("I2C (TWI) driver for Atmel AT91");
-MODULE_LICENSE("GPL");
-MODULE_ALIAS("platform:at91_i2c");
-- 
1.7.9.5

^ permalink raw reply related	[flat|nested] 21+ messages in thread

* [PATCH v11 3/4] drivers/i2c/busses/i2c-at91.c: add new driver
       [not found] ` <cover.1345618760.git.n.voss-+umVssTZoCsb1SvskN2V4Q@public.gmane.org>
  2011-11-08 10:49   ` [PATCH v11 1/4] drivers/i2c/busses/i2c-at91.c: remove old polling driver Nikolaus Voss
@ 2011-11-08 10:49   ` Nikolaus Voss
  2012-08-27 10:16     ` ludovic.desroches
  2012-08-28 15:10     ` ludovic.desroches
  2011-11-08 11:09   ` [PATCH v11 2/4] Replace clk_lookup.con_id with clk_lookup.dev_id entries for twi clk Nikolaus Voss
  2011-11-08 11:11   ` [PATCH v11 4/4] G45 TWI: remove open drain setting for twi function gpios Nikolaus Voss
  3 siblings, 2 replies; 21+ messages in thread
From: Nikolaus Voss @ 2011-11-08 10:49 UTC (permalink / raw)
  To: linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r,
	linux-kernel-u79uwXL29TY76Z2rM5mHXA,
	linux-i2c-u79uwXL29TY76Z2rM5mHXA
  Cc: nicolas.ferre-AIFe0yeh4nAAvxtiuMwx3w,
	ben-linux-elnMNo+KYs3YtjvyW6yDsg, balbi-l0cyMroinI0,
	h.feurstein-Re5JQEeQqe8AvxtiuMwx3w,
	rmallon-Re5JQEeQqe8AvxtiuMwx3w, adrian.yanes-uOixanVlb7U,
	ludovic.desroches-AIFe0yeh4nAAvxtiuMwx3w,
	carsten.behling-0M7HhAU3Y85FsXB23wyQUg

This 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.)

testing: SoC: at91sam9g45
	 - BQ20Z80 battery SMBus client.
	 - on a 2.6.38 kernel with several i2c clients (temp-sensor,
	   audio-codec, touchscreen-controller, w1-bridge, io-expanders)

Signed-off-by: Nikolaus Voss <n.voss-+umVssTZoCsb1SvskN2V4Q@public.gmane.org>
Reviewed-by: Felipe Balbi <balbi-l0cyMroinI0@public.gmane.org>
Tested-by: Hubert Feurstein <h.feurstein-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org>

v11: - fix for flags persistency suggested by Carsten Behling
     - calc_twi_clock fix for sam9261 by Ludovic Desroches
v10: - applied fix for RXRDY overrun bug submitted by Hubert Feurstein
     - applied fix for calculating twi_clk
v9: - merge i2c-at91.c patches to single patch
    - rewrite cwgr reg after timeout
v8: - remove local include
    - remove cpu_is_rm9200() and put twi hw bug info in platform_device
    - use readl/writel_relaxed instead of __raw_readl/writel
v7: i)  fix bug if internal address > 1 byte
    ii) send stop when len == 1 (both reported by Carsten Behling)
v6: 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
---
 arch/arm/mach-at91/at91rm9200_devices.c  |    9 +
 arch/arm/mach-at91/at91sam9261_devices.c |    9 +
 drivers/i2c/busses/Kconfig               |   11 +-
 drivers/i2c/busses/Makefile              |    1 +
 drivers/i2c/busses/i2c-at91.c            |  493 ++++++++++++++++++++++++++++++
 5 files changed, 516 insertions(+), 7 deletions(-)
 create mode 100644 drivers/i2c/busses/i2c-at91.c

diff --git a/arch/arm/mach-at91/at91rm9200_devices.c b/arch/arm/mach-at91/at91rm9200_devices.c
index e6b7d05..2977a2d 100644
--- a/arch/arm/mach-at91/at91rm9200_devices.c
+++ b/arch/arm/mach-at91/at91rm9200_devices.c
@@ -494,9 +494,18 @@ static struct resource twi_resources[] = {
 	},
 };
 
+static const struct platform_device_id twi_ip_type = {
+	/*
+	 * driver_data is 1 for RM9200 compatible ip, see enum twi_ip_id in
+	 * drivers/i2c/busses/i2c-at91.c
+	 */
+	.driver_data	= 1,
+};
+
 static struct platform_device at91rm9200_twi_device = {
 	.name		= "at91_i2c",
 	.id		= -1,
+	.id_entry	= &twi_ip_type,
 	.resource	= twi_resources,
 	.num_resources	= ARRAY_SIZE(twi_resources),
 };
diff --git a/arch/arm/mach-at91/at91sam9261_devices.c b/arch/arm/mach-at91/at91sam9261_devices.c
index 9295e90..27fddc1 100644
--- a/arch/arm/mach-at91/at91sam9261_devices.c
+++ b/arch/arm/mach-at91/at91sam9261_devices.c
@@ -283,9 +283,18 @@ static struct i2c_gpio_platform_data pdata = {
 	.udelay			= 2,		/* ~100 kHz */
 };
 
+static const struct platform_device_id twi_ip_type = {
+	/*
+	 * driver_data is 2 for SAM9261 compatible ip, see enum twi_ip_id in
+	 * drivers/i2c/busses/i2c-at91.c
+	 */
+	.driver_data	= 2,
+};
+
 static struct platform_device at91sam9261_twi_device = {
 	.name			= "i2c-gpio",
 	.id			= -1,
+	.id_entry		= &twi_ip_type,
 	.dev.platform_data	= &pdata,
 };
 
diff --git a/drivers/i2c/busses/Kconfig b/drivers/i2c/busses/Kconfig
index 7244c8b..6b74287 100644
--- a/drivers/i2c/busses/Kconfig
+++ b/drivers/i2c/busses/Kconfig
@@ -286,18 +286,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/Au1300 SMBus interface"
diff --git a/drivers/i2c/busses/Makefile b/drivers/i2c/busses/Makefile
index 4f46873..ce3c2be 100644
--- a/drivers/i2c/busses/Makefile
+++ b/drivers/i2c/busses/Makefile
@@ -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
diff --git a/drivers/i2c/busses/i2c-at91.c b/drivers/i2c/busses/i2c-at91.c
new file mode 100644
index 0000000..2b8b2c2
--- /dev/null
+++ b/drivers/i2c/busses/i2c-at91.c
@@ -0,0 +1,493 @@
+/*
+ *  i2c Support for Atmel's AT91 Two-Wire Interface (TWI)
+ *
+ *  Copyright (C) 2011 Weinmann Medical GmbH
+ *  Author: Nikolaus Voss <n.voss-+umVssTZoCsb1SvskN2V4Q@public.gmane.org>
+ *
+ *  Evolved from original work by:
+ *  Copyright (C) 2004 Rick Bronson
+ *  Converted to 2.6 by Andrew Victor <andrew-eS41wJS13H5l57MIdRCFDg@public.gmane.org>
+ *
+ *  Borrowed heavily from original work by:
+ *  Copyright (C) 2000 Philip Edelbrock <phil-LT64U7CwzWEZMC/lefXSXFaTQe2KTcn/@public.gmane.org>
+ *
+ *  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/clk.h>
+#include <linux/completion.h>
+#include <linux/err.h>
+#include <linux/i2c.h>
+#include <linux/interrupt.h>
+#include <linux/io.h>
+#include <linux/module.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 */
+
+#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 */
+
+enum twi_ip_id {
+	DEFAULT		= 0, /* default ip, no known limitations */
+	RM9200		= 1,
+	SAM9261		= 2,
+};
+
+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;
+	enum twi_ip_id		ip_id;
+	unsigned		twi_cwgr_reg;
+};
+
+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);
+}
+
+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);
+}
+
+/*
+ * Calculate symmetric clock as stated in datasheet:
+ * twi_clk = F_MAIN / (2 * (cdiv * (1 << ckdiv) + offset))
+ */
+static void __devinit at91_calc_twi_clock(struct at91_twi_dev *dev, int twi_clk)
+{
+	int ckdiv, cdiv, div;
+	int offset = 4;
+	int max_ckdiv = 7;
+
+	if (dev->ip_id == RM9200) {
+		offset = 3;
+		max_ckdiv = 5;
+	} else if (dev->ip_id == SAM9261) {
+		offset = 4;
+		max_ckdiv = 5;
+	}
+
+	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;
+	}
+
+	dev->twi_cwgr_reg = (ckdiv << 16) | (cdiv << 8) | cdiv;
+	dev_dbg(dev->dev, "cdiv %d ckdiv %d\n", cdiv, ckdiv);
+}
+
+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;
+}
+
+static void at91_twi_read_next_byte(struct at91_twi_dev *dev)
+{
+	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);
+
+	dev_dbg(dev->dev, "read 0x%x, to go %d\n", *dev->buf, dev->buf_len);
+
+	++dev->buf;
+}
+
+static irqreturn_t atmel_twi_interrupt(int irq, void *dev_id)
+{
+	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 IRQ_HANDLED;
+}
+
+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);
+	dev->transfer_status = 0;
+	if (dev->msg->flags & I2C_M_RD) {
+		unsigned start_flags = AT91_TWI_START;
+
+		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 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);
+	}
+
+	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 (dev->transfer_status & AT91_TWI_UNRE && dev->ip_id == RM9200) {
+		dev_err(dev->dev, "underrun while writing\n");
+		return -EIO;
+	}
+	dev_dbg(dev->dev, "transfer complete\n");
+
+	return 0;
+}
+
+static int at91_twi_xfer(struct i2c_adapter *adap, struct i2c_msg *msg, int num)
+{
+	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);
+
+	/*
+	 * 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;
+		}
+		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);
+	}
+
+	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;
+}
+
+static u32 at91_twi_func(struct i2c_adapter *adapter)
+{
+	return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL
+		| I2C_FUNC_SMBUS_READ_BLOCK_DATA;
+}
+
+static struct i2c_algorithm at91_twi_algorithm = {
+	.master_xfer	= at91_twi_xfer,
+	.functionality	= at91_twi_func,
+};
+
+static int __devinit at91_twi_probe(struct platform_device *pdev)
+{
+	struct at91_twi_dev *dev;
+	struct resource *mem, *ioarea;
+	int irq, rc;
+
+	mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	if (!mem)
+		return -ENODEV;
+
+	irq = platform_get_irq(pdev, 0);
+	if (irq < 0)
+		return irq;
+
+	ioarea = request_mem_region(mem->start, resource_size(mem), pdev->name);
+	if (!ioarea)
+		return -EBUSY;
+
+	dev = kzalloc(sizeof(*dev), GFP_KERNEL);
+	if (!dev) {
+		rc = -ENOMEM;
+		goto err_release_region;
+	}
+
+	if (pdev->id_entry)
+		dev->ip_id = pdev->id_entry->driver_data;
+
+	init_completion(&dev->cmd_complete);
+
+	dev->dev = &pdev->dev;
+	dev->irq = irq;
+	platform_set_drvdata(pdev, dev);
+
+	dev->clk = clk_get(dev->dev, NULL);
+	if (IS_ERR(dev->clk)) {
+		dev_err(dev->dev, "no clock defined\n");
+		rc = -ENODEV;
+		goto err_free_mem;
+	}
+	clk_prepare(dev->clk);
+	clk_enable(dev->clk);
+
+	dev->base = ioremap(mem->start, resource_size(mem));
+	if (!dev->base) {
+		rc = -EBUSY;
+		goto err_mem_ioremap;
+	}
+
+	at91_calc_twi_clock(dev, TWI_CLK_HZ);
+	at91_init_twi_bus(dev);
+
+	rc = request_irq(dev->irq, atmel_twi_interrupt, 0,
+			 dev_name(dev->dev), dev);
+	if (rc) {
+		dev_err(dev->dev, "Cannot get irq %d: %d\n", dev->irq, rc);
+		goto err_unuse_clocks;
+	}
+
+	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;
+
+	rc = i2c_add_numbered_adapter(&dev->adapter);
+	if (rc) {
+		dev_err(dev->dev, "Adapter %s registration failed\n",
+			dev->adapter.name);
+		goto err_free_irq;
+	}
+
+	dev_info(dev->dev, "AT91 i2c bus driver.\n");
+	return 0;
+
+err_free_irq:
+	free_irq(dev->irq, dev);
+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);
+err_release_region:
+	release_mem_region(mem->start, resource_size(mem));
+
+	return rc;
+}
+
+static int __devexit at91_twi_remove(struct platform_device *pdev)
+{
+	struct at91_twi_dev *dev = platform_get_drvdata(pdev);
+	struct resource *mem;
+	int rc;
+
+	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);
+	kfree(dev);
+
+	mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	release_mem_region(mem->start, resource_size(mem));
+
+	return rc;
+}
+
+#ifdef CONFIG_PM
+
+static int at91_twi_runtime_suspend(struct device *dev)
+{
+	struct at91_twi_dev *twi_dev = dev_get_drvdata(dev);
+
+	clk_disable(twi_dev->clk);
+
+	return 0;
+}
+
+static int at91_twi_runtime_resume(struct device *dev)
+{
+	struct at91_twi_dev *twi_dev = dev_get_drvdata(dev);
+
+	return clk_enable(twi_dev->clk);
+}
+
+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_twi_pm_ops NULL
+#endif
+
+static struct platform_driver at91_twi_driver = {
+	.probe		= at91_twi_probe,
+	.remove		= __devexit_p(at91_twi_remove),
+	.driver		= {
+		.name	= "at91_i2c",
+		.owner	= THIS_MODULE,
+		.pm	= at91_twi_pm_ops,
+	},
+};
+
+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("Nikolaus Voss <n.voss-+umVssTZoCsb1SvskN2V4Q@public.gmane.org>");
+MODULE_DESCRIPTION("I2C (TWI) driver for Atmel AT91");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:at91_i2c");
-- 
1.7.9.5

^ permalink raw reply related	[flat|nested] 21+ messages in thread

* [PATCH v11 3/4] drivers/i2c/busses/i2c-at91.c: add new driver
       [not found] ` <cover.1346225321.git.n.voss-+umVssTZoCsb1SvskN2V4Q@public.gmane.org>
@ 2011-11-08 10:49   ` Nikolaus Voss
  0 siblings, 0 replies; 21+ messages in thread
From: Nikolaus Voss @ 2011-11-08 10:49 UTC (permalink / raw)
  To: linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r,
	linux-kernel-u79uwXL29TY76Z2rM5mHXA,
	linux-i2c-u79uwXL29TY76Z2rM5mHXA
  Cc: nicolas.ferre-AIFe0yeh4nAAvxtiuMwx3w,
	ben-linux-elnMNo+KYs3YtjvyW6yDsg, balbi-l0cyMroinI0,
	h.feurstein-Re5JQEeQqe8AvxtiuMwx3w,
	rmallon-Re5JQEeQqe8AvxtiuMwx3w, adrian.yanes-uOixanVlb7U,
	ludovic.desroches-AIFe0yeh4nAAvxtiuMwx3w,
	carsten.behling-0M7HhAU3Y85FsXB23wyQUg

This 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.)

testing: SoC: at91sam9g45
	 - BQ20Z80 battery SMBus client.
	 - on a 2.6.38 kernel with several i2c clients (temp-sensor,
	   audio-codec, touchscreen-controller, w1-bridge, io-expanders)

Signed-off-by: Nikolaus Voss <n.voss-+umVssTZoCsb1SvskN2V4Q@public.gmane.org>
Reviewed-by: Felipe Balbi <balbi-l0cyMroinI0@public.gmane.org>
Tested-by: Hubert Feurstein <h.feurstein-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org>

v12: - corrected wrong id_entry on sam9261 twi gpio pdev
v11: - fix for flags persistency suggested by Carsten Behling
     - calc_twi_clock fix for sam9261 by Ludovic Desroches
v10: - applied fix for RXRDY overrun bug submitted by Hubert Feurstein
     - applied fix for calculating twi_clk
v9: - merge i2c-at91.c patches to single patch
    - rewrite cwgr reg after timeout
v8: - remove local include
    - remove cpu_is_rm9200() and put twi hw bug info in platform_device
    - use readl/writel_relaxed instead of __raw_readl/writel
v7: i)  fix bug if internal address > 1 byte
    ii) send stop when len == 1 (both reported by Carsten Behling)
v6: 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
---
 arch/arm/mach-at91/at91rm9200_devices.c  |    9 +
 arch/arm/mach-at91/at91sam9261_devices.c |    9 +
 drivers/i2c/busses/Kconfig               |   11 +-
 drivers/i2c/busses/Makefile              |    1 +
 drivers/i2c/busses/i2c-at91.c            |  493 ++++++++++++++++++++++++++++++
 5 files changed, 516 insertions(+), 7 deletions(-)
 create mode 100644 drivers/i2c/busses/i2c-at91.c

diff --git a/arch/arm/mach-at91/at91rm9200_devices.c b/arch/arm/mach-at91/at91rm9200_devices.c
index e6b7d05..2977a2d 100644
--- a/arch/arm/mach-at91/at91rm9200_devices.c
+++ b/arch/arm/mach-at91/at91rm9200_devices.c
@@ -494,9 +494,18 @@ static struct resource twi_resources[] = {
 	},
 };
 
+static const struct platform_device_id twi_ip_type = {
+	/*
+	 * driver_data is 1 for RM9200 compatible ip, see enum twi_ip_id in
+	 * drivers/i2c/busses/i2c-at91.c
+	 */
+	.driver_data	= 1,
+};
+
 static struct platform_device at91rm9200_twi_device = {
 	.name		= "at91_i2c",
 	.id		= -1,
+	.id_entry	= &twi_ip_type,
 	.resource	= twi_resources,
 	.num_resources	= ARRAY_SIZE(twi_resources),
 };
diff --git a/arch/arm/mach-at91/at91sam9261_devices.c b/arch/arm/mach-at91/at91sam9261_devices.c
index 9295e90..aeb2eed 100644
--- a/arch/arm/mach-at91/at91sam9261_devices.c
+++ b/arch/arm/mach-at91/at91sam9261_devices.c
@@ -316,9 +316,18 @@ static struct resource twi_resources[] = {
 	},
 };
 
+static const struct platform_device_id twi_ip_type = {
+	/*
+	 * driver_data is 2 for SAM9261 compatible ip, see enum twi_ip_id in
+	 * drivers/i2c/busses/i2c-at91.c
+	 */
+	.driver_data	= 2,
+};
+
 static struct platform_device at91sam9261_twi_device = {
 	.name		= "at91_i2c",
 	.id		= -1,
+	.id_entry	= &twi_ip_type,
 	.resource	= twi_resources,
 	.num_resources	= ARRAY_SIZE(twi_resources),
 };
diff --git a/drivers/i2c/busses/Kconfig b/drivers/i2c/busses/Kconfig
index 7244c8b..6b74287 100644
--- a/drivers/i2c/busses/Kconfig
+++ b/drivers/i2c/busses/Kconfig
@@ -286,18 +286,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/Au1300 SMBus interface"
diff --git a/drivers/i2c/busses/Makefile b/drivers/i2c/busses/Makefile
index 4f46873..ce3c2be 100644
--- a/drivers/i2c/busses/Makefile
+++ b/drivers/i2c/busses/Makefile
@@ -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
diff --git a/drivers/i2c/busses/i2c-at91.c b/drivers/i2c/busses/i2c-at91.c
new file mode 100644
index 0000000..2b8b2c2
--- /dev/null
+++ b/drivers/i2c/busses/i2c-at91.c
@@ -0,0 +1,493 @@
+/*
+ *  i2c Support for Atmel's AT91 Two-Wire Interface (TWI)
+ *
+ *  Copyright (C) 2011 Weinmann Medical GmbH
+ *  Author: Nikolaus Voss <n.voss-+umVssTZoCsb1SvskN2V4Q@public.gmane.org>
+ *
+ *  Evolved from original work by:
+ *  Copyright (C) 2004 Rick Bronson
+ *  Converted to 2.6 by Andrew Victor <andrew-eS41wJS13H5l57MIdRCFDg@public.gmane.org>
+ *
+ *  Borrowed heavily from original work by:
+ *  Copyright (C) 2000 Philip Edelbrock <phil-LT64U7CwzWEZMC/lefXSXFaTQe2KTcn/@public.gmane.org>
+ *
+ *  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/clk.h>
+#include <linux/completion.h>
+#include <linux/err.h>
+#include <linux/i2c.h>
+#include <linux/interrupt.h>
+#include <linux/io.h>
+#include <linux/module.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 */
+
+#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 */
+
+enum twi_ip_id {
+	DEFAULT		= 0, /* default ip, no known limitations */
+	RM9200		= 1,
+	SAM9261		= 2,
+};
+
+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;
+	enum twi_ip_id		ip_id;
+	unsigned		twi_cwgr_reg;
+};
+
+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);
+}
+
+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);
+}
+
+/*
+ * Calculate symmetric clock as stated in datasheet:
+ * twi_clk = F_MAIN / (2 * (cdiv * (1 << ckdiv) + offset))
+ */
+static void __devinit at91_calc_twi_clock(struct at91_twi_dev *dev, int twi_clk)
+{
+	int ckdiv, cdiv, div;
+	int offset = 4;
+	int max_ckdiv = 7;
+
+	if (dev->ip_id == RM9200) {
+		offset = 3;
+		max_ckdiv = 5;
+	} else if (dev->ip_id == SAM9261) {
+		offset = 4;
+		max_ckdiv = 5;
+	}
+
+	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;
+	}
+
+	dev->twi_cwgr_reg = (ckdiv << 16) | (cdiv << 8) | cdiv;
+	dev_dbg(dev->dev, "cdiv %d ckdiv %d\n", cdiv, ckdiv);
+}
+
+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;
+}
+
+static void at91_twi_read_next_byte(struct at91_twi_dev *dev)
+{
+	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);
+
+	dev_dbg(dev->dev, "read 0x%x, to go %d\n", *dev->buf, dev->buf_len);
+
+	++dev->buf;
+}
+
+static irqreturn_t atmel_twi_interrupt(int irq, void *dev_id)
+{
+	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 IRQ_HANDLED;
+}
+
+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);
+	dev->transfer_status = 0;
+	if (dev->msg->flags & I2C_M_RD) {
+		unsigned start_flags = AT91_TWI_START;
+
+		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 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);
+	}
+
+	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 (dev->transfer_status & AT91_TWI_UNRE && dev->ip_id == RM9200) {
+		dev_err(dev->dev, "underrun while writing\n");
+		return -EIO;
+	}
+	dev_dbg(dev->dev, "transfer complete\n");
+
+	return 0;
+}
+
+static int at91_twi_xfer(struct i2c_adapter *adap, struct i2c_msg *msg, int num)
+{
+	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);
+
+	/*
+	 * 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;
+		}
+		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);
+	}
+
+	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;
+}
+
+static u32 at91_twi_func(struct i2c_adapter *adapter)
+{
+	return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL
+		| I2C_FUNC_SMBUS_READ_BLOCK_DATA;
+}
+
+static struct i2c_algorithm at91_twi_algorithm = {
+	.master_xfer	= at91_twi_xfer,
+	.functionality	= at91_twi_func,
+};
+
+static int __devinit at91_twi_probe(struct platform_device *pdev)
+{
+	struct at91_twi_dev *dev;
+	struct resource *mem, *ioarea;
+	int irq, rc;
+
+	mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	if (!mem)
+		return -ENODEV;
+
+	irq = platform_get_irq(pdev, 0);
+	if (irq < 0)
+		return irq;
+
+	ioarea = request_mem_region(mem->start, resource_size(mem), pdev->name);
+	if (!ioarea)
+		return -EBUSY;
+
+	dev = kzalloc(sizeof(*dev), GFP_KERNEL);
+	if (!dev) {
+		rc = -ENOMEM;
+		goto err_release_region;
+	}
+
+	if (pdev->id_entry)
+		dev->ip_id = pdev->id_entry->driver_data;
+
+	init_completion(&dev->cmd_complete);
+
+	dev->dev = &pdev->dev;
+	dev->irq = irq;
+	platform_set_drvdata(pdev, dev);
+
+	dev->clk = clk_get(dev->dev, NULL);
+	if (IS_ERR(dev->clk)) {
+		dev_err(dev->dev, "no clock defined\n");
+		rc = -ENODEV;
+		goto err_free_mem;
+	}
+	clk_prepare(dev->clk);
+	clk_enable(dev->clk);
+
+	dev->base = ioremap(mem->start, resource_size(mem));
+	if (!dev->base) {
+		rc = -EBUSY;
+		goto err_mem_ioremap;
+	}
+
+	at91_calc_twi_clock(dev, TWI_CLK_HZ);
+	at91_init_twi_bus(dev);
+
+	rc = request_irq(dev->irq, atmel_twi_interrupt, 0,
+			 dev_name(dev->dev), dev);
+	if (rc) {
+		dev_err(dev->dev, "Cannot get irq %d: %d\n", dev->irq, rc);
+		goto err_unuse_clocks;
+	}
+
+	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;
+
+	rc = i2c_add_numbered_adapter(&dev->adapter);
+	if (rc) {
+		dev_err(dev->dev, "Adapter %s registration failed\n",
+			dev->adapter.name);
+		goto err_free_irq;
+	}
+
+	dev_info(dev->dev, "AT91 i2c bus driver.\n");
+	return 0;
+
+err_free_irq:
+	free_irq(dev->irq, dev);
+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);
+err_release_region:
+	release_mem_region(mem->start, resource_size(mem));
+
+	return rc;
+}
+
+static int __devexit at91_twi_remove(struct platform_device *pdev)
+{
+	struct at91_twi_dev *dev = platform_get_drvdata(pdev);
+	struct resource *mem;
+	int rc;
+
+	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);
+	kfree(dev);
+
+	mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	release_mem_region(mem->start, resource_size(mem));
+
+	return rc;
+}
+
+#ifdef CONFIG_PM
+
+static int at91_twi_runtime_suspend(struct device *dev)
+{
+	struct at91_twi_dev *twi_dev = dev_get_drvdata(dev);
+
+	clk_disable(twi_dev->clk);
+
+	return 0;
+}
+
+static int at91_twi_runtime_resume(struct device *dev)
+{
+	struct at91_twi_dev *twi_dev = dev_get_drvdata(dev);
+
+	return clk_enable(twi_dev->clk);
+}
+
+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_twi_pm_ops NULL
+#endif
+
+static struct platform_driver at91_twi_driver = {
+	.probe		= at91_twi_probe,
+	.remove		= __devexit_p(at91_twi_remove),
+	.driver		= {
+		.name	= "at91_i2c",
+		.owner	= THIS_MODULE,
+		.pm	= at91_twi_pm_ops,
+	},
+};
+
+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("Nikolaus Voss <n.voss-+umVssTZoCsb1SvskN2V4Q@public.gmane.org>");
+MODULE_DESCRIPTION("I2C (TWI) driver for Atmel AT91");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:at91_i2c");
-- 
1.7.9.5

^ permalink raw reply related	[flat|nested] 21+ messages in thread

* [PATCH v11 2/4] Replace clk_lookup.con_id with clk_lookup.dev_id entries for twi clk
       [not found] ` <cover.1345618760.git.n.voss-+umVssTZoCsb1SvskN2V4Q@public.gmane.org>
  2011-11-08 10:49   ` [PATCH v11 1/4] drivers/i2c/busses/i2c-at91.c: remove old polling driver Nikolaus Voss
  2011-11-08 10:49   ` [PATCH v11 3/4] drivers/i2c/busses/i2c-at91.c: add new driver Nikolaus Voss
@ 2011-11-08 11:09   ` Nikolaus Voss
  2011-11-08 11:11   ` [PATCH v11 4/4] G45 TWI: remove open drain setting for twi function gpios Nikolaus Voss
  3 siblings, 0 replies; 21+ messages in thread
From: Nikolaus Voss @ 2011-11-08 11:09 UTC (permalink / raw)
  To: linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r,
	linux-kernel-u79uwXL29TY76Z2rM5mHXA,
	linux-i2c-u79uwXL29TY76Z2rM5mHXA
  Cc: nicolas.ferre-AIFe0yeh4nAAvxtiuMwx3w,
	ben-linux-elnMNo+KYs3YtjvyW6yDsg, balbi-l0cyMroinI0,
	h.feurstein-Re5JQEeQqe8AvxtiuMwx3w,
	rmallon-Re5JQEeQqe8AvxtiuMwx3w, adrian.yanes-uOixanVlb7U,
	ludovic.desroches-AIFe0yeh4nAAvxtiuMwx3w,
	carsten.behling-0M7HhAU3Y85FsXB23wyQUg

The old driver used con_id clock entries. Convert to use dev_id
for clock lookup via standard method.

Signed-off-by: Nikolaus Voss <n.voss-+umVssTZoCsb1SvskN2V4Q@public.gmane.org>
---
 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 ++
 arch/arm/mach-at91/at91sam9x5.c  |    3 +++
 7 files changed, 11 insertions(+)

diff --git a/arch/arm/mach-at91/at91rm9200.c b/arch/arm/mach-at91/at91rm9200.c
index 2691768..cf354a3 100644
--- a/arch/arm/mach-at91/at91rm9200.c
+++ b/arch/arm/mach-at91/at91rm9200.c
@@ -186,6 +186,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),
 	CLKDEV_CON_ID("pioA", &pioA_clk),
diff --git a/arch/arm/mach-at91/at91sam9260.c b/arch/arm/mach-at91/at91sam9260.c
index 2b1e438..2e56321 100644
--- a/arch/arm/mach-at91/at91sam9260.c
+++ b/arch/arm/mach-at91/at91sam9260.c
@@ -210,6 +210,7 @@ static struct clk_lookup periph_clocks_lookups[] = {
 	CLKDEV_CON_DEV_ID("t1_clk", "atmel_tcb.1", &tc4_clk),
 	CLKDEV_CON_DEV_ID("t2_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),
diff --git a/arch/arm/mach-at91/at91sam9261.c b/arch/arm/mach-at91/at91sam9261.c
index c77d503..f21196d 100644
--- a/arch/arm/mach-at91/at91sam9261.c
+++ b/arch/arm/mach-at91/at91sam9261.c
@@ -177,6 +177,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),
 	CLKDEV_CON_ID("pioA", &pioA_clk),
 	CLKDEV_CON_ID("pioB", &pioB_clk),
 	CLKDEV_CON_ID("pioC", &pioC_clk),
diff --git a/arch/arm/mach-at91/at91sam9263.c b/arch/arm/mach-at91/at91sam9263.c
index ed91c7e..71305fa 100644
--- a/arch/arm/mach-at91/at91sam9263.c
+++ b/arch/arm/mach-at91/at91sam9263.c
@@ -192,6 +192,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),
 	CLKDEV_CON_ID("pioA", &pioA_clk),
diff --git a/arch/arm/mach-at91/at91sam9g45.c b/arch/arm/mach-at91/at91sam9g45.c
index 4792682..2944fc7 100644
--- a/arch/arm/mach-at91/at91sam9g45.c
+++ b/arch/arm/mach-at91/at91sam9g45.c
@@ -228,6 +228,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),
diff --git a/arch/arm/mach-at91/at91sam9rl.c b/arch/arm/mach-at91/at91sam9rl.c
index e420085..8a97218 100644
--- a/arch/arm/mach-at91/at91sam9rl.c
+++ b/arch/arm/mach-at91/at91sam9rl.c
@@ -185,6 +185,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),
 	CLKDEV_CON_ID("pioA", &pioA_clk),
 	CLKDEV_CON_ID("pioB", &pioB_clk),
 	CLKDEV_CON_ID("pioC", &pioC_clk),
diff --git a/arch/arm/mach-at91/at91sam9x5.c b/arch/arm/mach-at91/at91sam9x5.c
index 1b144b4..def85e5 100644
--- a/arch/arm/mach-at91/at91sam9x5.c
+++ b/arch/arm/mach-at91/at91sam9x5.c
@@ -231,6 +231,9 @@ static struct clk_lookup periph_clocks_lookups[] = {
 	CLKDEV_CON_DEV_ID("t0_clk", "f800c000.timer", &tcb0_clk),
 	CLKDEV_CON_DEV_ID("dma_clk", "ffffec00.dma-controller", &dma0_clk),
 	CLKDEV_CON_DEV_ID("dma_clk", "ffffee00.dma-controller", &dma1_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(NULL, "at91_i2c.2", &twi2_clk),
 	CLKDEV_CON_ID("pioA", &pioAB_clk),
 	CLKDEV_CON_ID("pioB", &pioAB_clk),
 	CLKDEV_CON_ID("pioC", &pioCD_clk),
-- 
1.7.9.5

^ permalink raw reply related	[flat|nested] 21+ messages in thread

* [PATCH v11 4/4] G45 TWI: remove open drain setting for twi function gpios
       [not found] ` <cover.1345618760.git.n.voss-+umVssTZoCsb1SvskN2V4Q@public.gmane.org>
                     ` (2 preceding siblings ...)
  2011-11-08 11:09   ` [PATCH v11 2/4] Replace clk_lookup.con_id with clk_lookup.dev_id entries for twi clk Nikolaus Voss
@ 2011-11-08 11:11   ` Nikolaus Voss
  2012-08-27 10:24     ` ludovic.desroches
  3 siblings, 1 reply; 21+ messages in thread
From: Nikolaus Voss @ 2011-11-08 11:11 UTC (permalink / raw)
  To: linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r,
	linux-kernel-u79uwXL29TY76Z2rM5mHXA,
	linux-i2c-u79uwXL29TY76Z2rM5mHXA
  Cc: nicolas.ferre-AIFe0yeh4nAAvxtiuMwx3w,
	ben-linux-elnMNo+KYs3YtjvyW6yDsg, balbi-l0cyMroinI0,
	h.feurstein-Re5JQEeQqe8AvxtiuMwx3w,
	rmallon-Re5JQEeQqe8AvxtiuMwx3w, adrian.yanes-uOixanVlb7U,
	ludovic.desroches-AIFe0yeh4nAAvxtiuMwx3w,
	carsten.behling-0M7HhAU3Y85FsXB23wyQUg

The G45 datasheets explicitly states that setting the open drain property
on peripheral function gpios is not allowed. (How about other A91 chips?)

Signed-off-by: Nikolaus Voss <n.voss-+umVssTZoCsb1SvskN2V4Q@public.gmane.org>
---
 arch/arm/mach-at91/at91sam9g45_devices.c |    6 ------
 1 file changed, 6 deletions(-)

diff --git a/arch/arm/mach-at91/at91sam9g45_devices.c b/arch/arm/mach-at91/at91sam9g45_devices.c
index eec5eb6..2134663 100644
--- a/arch/arm/mach-at91/at91sam9g45_devices.c
+++ b/arch/arm/mach-at91/at91sam9g45_devices.c
@@ -686,18 +686,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);
 	}
-- 
1.7.9.5

^ permalink raw reply related	[flat|nested] 21+ messages in thread

* [PATCH v11 0/4] AT91: replace old i2c-at91.c TWI driver
@ 2012-08-22  6:59 Nikolaus Voss
       [not found] ` <cover.1345618760.git.n.voss-+umVssTZoCsb1SvskN2V4Q@public.gmane.org>
  0 siblings, 1 reply; 21+ messages in thread
From: Nikolaus Voss @ 2012-08-22  6:59 UTC (permalink / raw)
  To: linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r,
	linux-kernel-u79uwXL29TY76Z2rM5mHXA,
	linux-i2c-u79uwXL29TY76Z2rM5mHXA
  Cc: nicolas.ferre-AIFe0yeh4nAAvxtiuMwx3w,
	ben-linux-elnMNo+KYs3YtjvyW6yDsg, balbi-l0cyMroinI0,
	h.feurstein-Re5JQEeQqe8AvxtiuMwx3w,
	rmallon-Re5JQEeQqe8AvxtiuMwx3w, adrian.yanes-uOixanVlb7U,
	ludovic.desroches-AIFe0yeh4nAAvxtiuMwx3w,
	carsten.behling-0M7HhAU3Y85FsXB23wyQUg

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.

Changes since v10:
 - fix for flags persistency suggested and tested by Carsten Behling
 - clk_lookup.dev_id entries for at91sam9x5
 - calc_twi_clock fix for sam9261 by Ludovic Desroches

Nikolaus Voss (4):
  drivers/i2c/busses/i2c-at91.c: remove old polling 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

 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/at91sam9261.c           |    1 +
 arch/arm/mach-at91/at91sam9261_devices.c   |    9 +
 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/at91sam9x5.c            |    3 +
 arch/arm/mach-at91/include/mach/at91_twi.h |   68 ----
 drivers/i2c/busses/Kconfig                 |   11 +-
 drivers/i2c/busses/i2c-at91.c              |  591 ++++++++++++++++++----------
 13 files changed, 418 insertions(+), 287 deletions(-)
 delete mode 100644 arch/arm/mach-at91/include/mach/at91_twi.h

-- 
1.7.9.5

^ permalink raw reply	[flat|nested] 21+ messages in thread

* Re: [PATCH v11 3/4] drivers/i2c/busses/i2c-at91.c: add new driver
  2011-11-08 10:49   ` [PATCH v11 3/4] drivers/i2c/busses/i2c-at91.c: add new driver Nikolaus Voss
@ 2012-08-27 10:16     ` ludovic.desroches
  2012-08-27 10:40       ` Yanes Martinez Adrian
  2012-08-28 15:10     ` ludovic.desroches
  1 sibling, 1 reply; 21+ messages in thread
From: ludovic.desroches @ 2012-08-27 10:16 UTC (permalink / raw)
  To: Nikolaus Voss
  Cc: rmallon, nicolas.ferre, linux-kernel, balbi, h.feurstein,
	ludovic.desroches, linux-i2c, ben-linux, adrian.yanes,
	linux-arm-kernel, carsten.behling

Hi Nikolaus,

Le 11/08/2011 11:49 AM, Nikolaus Voss a écrit :
> This 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.)
>
> testing: SoC: at91sam9g45
> 	 - BQ20Z80 battery SMBus client.
> 	 - on a 2.6.38 kernel with several i2c clients (temp-sensor,
> 	   audio-codec, touchscreen-controller, w1-bridge, io-expanders)
>
> Signed-off-by: Nikolaus Voss <n.voss@weinmann.de>
> Reviewed-by: Felipe Balbi <balbi@ti.com>
> Tested-by: Hubert Feurstein <h.feurstein@gmail.com>
>

Tested-by: Ludovic Desroches <ludovic.desroches@atmel.com>

Tested on at91rm9200, at91sam9261, at91sam9g20 and at91sam9m10 with 
eeprom, temperature sensor and rtc devices (and wolfson chip for sam9g20).

Thanks for your work on this driver and sorry for the delay.

Regards

Ludovic

> v11: - fix for flags persistency suggested by Carsten Behling
>       - calc_twi_clock fix for sam9261 by Ludovic Desroches
> v10: - applied fix for RXRDY overrun bug submitted by Hubert Feurstein
>       - applied fix for calculating twi_clk
> v9: - merge i2c-at91.c patches to single patch
>      - rewrite cwgr reg after timeout
> v8: - remove local include
>      - remove cpu_is_rm9200() and put twi hw bug info in platform_device
>      - use readl/writel_relaxed instead of __raw_readl/writel
> v7: i)  fix bug if internal address > 1 byte
>      ii) send stop when len == 1 (both reported by Carsten Behling)
> v6: 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
> ---
>   arch/arm/mach-at91/at91rm9200_devices.c  |    9 +
>   arch/arm/mach-at91/at91sam9261_devices.c |    9 +
>   drivers/i2c/busses/Kconfig               |   11 +-
>   drivers/i2c/busses/Makefile              |    1 +
>   drivers/i2c/busses/i2c-at91.c            |  493 ++++++++++++++++++++++++++++++
>   5 files changed, 516 insertions(+), 7 deletions(-)
>   create mode 100644 drivers/i2c/busses/i2c-at91.c
>
> diff --git a/arch/arm/mach-at91/at91rm9200_devices.c b/arch/arm/mach-at91/at91rm9200_devices.c
> index e6b7d05..2977a2d 100644
> --- a/arch/arm/mach-at91/at91rm9200_devices.c
> +++ b/arch/arm/mach-at91/at91rm9200_devices.c
> @@ -494,9 +494,18 @@ static struct resource twi_resources[] = {
>   	},
>   };
>
> +static const struct platform_device_id twi_ip_type = {
> +	/*
> +	 * driver_data is 1 for RM9200 compatible ip, see enum twi_ip_id in
> +	 * drivers/i2c/busses/i2c-at91.c
> +	 */
> +	.driver_data	= 1,
> +};
> +
>   static struct platform_device at91rm9200_twi_device = {
>   	.name		= "at91_i2c",
>   	.id		= -1,
> +	.id_entry	= &twi_ip_type,
>   	.resource	= twi_resources,
>   	.num_resources	= ARRAY_SIZE(twi_resources),
>   };
> diff --git a/arch/arm/mach-at91/at91sam9261_devices.c b/arch/arm/mach-at91/at91sam9261_devices.c
> index 9295e90..27fddc1 100644
> --- a/arch/arm/mach-at91/at91sam9261_devices.c
> +++ b/arch/arm/mach-at91/at91sam9261_devices.c
> @@ -283,9 +283,18 @@ static struct i2c_gpio_platform_data pdata = {
>   	.udelay			= 2,		/* ~100 kHz */
>   };
>
> +static const struct platform_device_id twi_ip_type = {
> +	/*
> +	 * driver_data is 2 for SAM9261 compatible ip, see enum twi_ip_id in
> +	 * drivers/i2c/busses/i2c-at91.c
> +	 */
> +	.driver_data	= 2,
> +};
> +
>   static struct platform_device at91sam9261_twi_device = {
>   	.name			= "i2c-gpio",
>   	.id			= -1,
> +	.id_entry		= &twi_ip_type,
>   	.dev.platform_data	= &pdata,
>   };
>
> diff --git a/drivers/i2c/busses/Kconfig b/drivers/i2c/busses/Kconfig
> index 7244c8b..6b74287 100644
> --- a/drivers/i2c/busses/Kconfig
> +++ b/drivers/i2c/busses/Kconfig
> @@ -286,18 +286,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/Au1300 SMBus interface"
> diff --git a/drivers/i2c/busses/Makefile b/drivers/i2c/busses/Makefile
> index 4f46873..ce3c2be 100644
> --- a/drivers/i2c/busses/Makefile
> +++ b/drivers/i2c/busses/Makefile
> @@ -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
> diff --git a/drivers/i2c/busses/i2c-at91.c b/drivers/i2c/busses/i2c-at91.c
> new file mode 100644
> index 0000000..2b8b2c2
> --- /dev/null
> +++ b/drivers/i2c/busses/i2c-at91.c
> @@ -0,0 +1,493 @@
> +/*
> + *  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/clk.h>
> +#include <linux/completion.h>
> +#include <linux/err.h>
> +#include <linux/i2c.h>
> +#include <linux/interrupt.h>
> +#include <linux/io.h>
> +#include <linux/module.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 */
> +
> +#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 */
> +
> +enum twi_ip_id {
> +	DEFAULT		= 0, /* default ip, no known limitations */
> +	RM9200		= 1,
> +	SAM9261		= 2,
> +};
> +
> +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;
> +	enum twi_ip_id		ip_id;
> +	unsigned		twi_cwgr_reg;
> +};
> +
> +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);
> +}
> +
> +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);
> +}
> +
> +/*
> + * Calculate symmetric clock as stated in datasheet:
> + * twi_clk = F_MAIN / (2 * (cdiv * (1 << ckdiv) + offset))
> + */
> +static void __devinit at91_calc_twi_clock(struct at91_twi_dev *dev, int twi_clk)
> +{
> +	int ckdiv, cdiv, div;
> +	int offset = 4;
> +	int max_ckdiv = 7;
> +
> +	if (dev->ip_id == RM9200) {
> +		offset = 3;
> +		max_ckdiv = 5;
> +	} else if (dev->ip_id == SAM9261) {
> +		offset = 4;
> +		max_ckdiv = 5;
> +	}
> +
> +	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;
> +	}
> +
> +	dev->twi_cwgr_reg = (ckdiv << 16) | (cdiv << 8) | cdiv;
> +	dev_dbg(dev->dev, "cdiv %d ckdiv %d\n", cdiv, ckdiv);
> +}
> +
> +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;
> +}
> +
> +static void at91_twi_read_next_byte(struct at91_twi_dev *dev)
> +{
> +	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);
> +
> +	dev_dbg(dev->dev, "read 0x%x, to go %d\n", *dev->buf, dev->buf_len);
> +
> +	++dev->buf;
> +}
> +
> +static irqreturn_t atmel_twi_interrupt(int irq, void *dev_id)
> +{
> +	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 IRQ_HANDLED;
> +}
> +
> +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);
> +	dev->transfer_status = 0;
> +	if (dev->msg->flags & I2C_M_RD) {
> +		unsigned start_flags = AT91_TWI_START;
> +
> +		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 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);
> +	}
> +
> +	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 (dev->transfer_status & AT91_TWI_UNRE && dev->ip_id == RM9200) {
> +		dev_err(dev->dev, "underrun while writing\n");
> +		return -EIO;
> +	}
> +	dev_dbg(dev->dev, "transfer complete\n");
> +
> +	return 0;
> +}
> +
> +static int at91_twi_xfer(struct i2c_adapter *adap, struct i2c_msg *msg, int num)
> +{
> +	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);
> +
> +	/*
> +	 * 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;
> +		}
> +		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);
> +	}
> +
> +	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;
> +}
> +
> +static u32 at91_twi_func(struct i2c_adapter *adapter)
> +{
> +	return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL
> +		| I2C_FUNC_SMBUS_READ_BLOCK_DATA;
> +}
> +
> +static struct i2c_algorithm at91_twi_algorithm = {
> +	.master_xfer	= at91_twi_xfer,
> +	.functionality	= at91_twi_func,
> +};
> +
> +static int __devinit at91_twi_probe(struct platform_device *pdev)
> +{
> +	struct at91_twi_dev *dev;
> +	struct resource *mem, *ioarea;
> +	int irq, rc;
> +
> +	mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
> +	if (!mem)
> +		return -ENODEV;
> +
> +	irq = platform_get_irq(pdev, 0);
> +	if (irq < 0)
> +		return irq;
> +
> +	ioarea = request_mem_region(mem->start, resource_size(mem), pdev->name);
> +	if (!ioarea)
> +		return -EBUSY;
> +
> +	dev = kzalloc(sizeof(*dev), GFP_KERNEL);
> +	if (!dev) {
> +		rc = -ENOMEM;
> +		goto err_release_region;
> +	}
> +
> +	if (pdev->id_entry)
> +		dev->ip_id = pdev->id_entry->driver_data;
> +
> +	init_completion(&dev->cmd_complete);
> +
> +	dev->dev = &pdev->dev;
> +	dev->irq = irq;
> +	platform_set_drvdata(pdev, dev);
> +
> +	dev->clk = clk_get(dev->dev, NULL);
> +	if (IS_ERR(dev->clk)) {
> +		dev_err(dev->dev, "no clock defined\n");
> +		rc = -ENODEV;
> +		goto err_free_mem;
> +	}
> +	clk_prepare(dev->clk);
> +	clk_enable(dev->clk);
> +
> +	dev->base = ioremap(mem->start, resource_size(mem));
> +	if (!dev->base) {
> +		rc = -EBUSY;
> +		goto err_mem_ioremap;
> +	}
> +
> +	at91_calc_twi_clock(dev, TWI_CLK_HZ);
> +	at91_init_twi_bus(dev);
> +
> +	rc = request_irq(dev->irq, atmel_twi_interrupt, 0,
> +			 dev_name(dev->dev), dev);
> +	if (rc) {
> +		dev_err(dev->dev, "Cannot get irq %d: %d\n", dev->irq, rc);
> +		goto err_unuse_clocks;
> +	}
> +
> +	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;
> +
> +	rc = i2c_add_numbered_adapter(&dev->adapter);
> +	if (rc) {
> +		dev_err(dev->dev, "Adapter %s registration failed\n",
> +			dev->adapter.name);
> +		goto err_free_irq;
> +	}
> +
> +	dev_info(dev->dev, "AT91 i2c bus driver.\n");
> +	return 0;
> +
> +err_free_irq:
> +	free_irq(dev->irq, dev);
> +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);
> +err_release_region:
> +	release_mem_region(mem->start, resource_size(mem));
> +
> +	return rc;
> +}
> +
> +static int __devexit at91_twi_remove(struct platform_device *pdev)
> +{
> +	struct at91_twi_dev *dev = platform_get_drvdata(pdev);
> +	struct resource *mem;
> +	int rc;
> +
> +	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);
> +	kfree(dev);
> +
> +	mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
> +	release_mem_region(mem->start, resource_size(mem));
> +
> +	return rc;
> +}
> +
> +#ifdef CONFIG_PM
> +
> +static int at91_twi_runtime_suspend(struct device *dev)
> +{
> +	struct at91_twi_dev *twi_dev = dev_get_drvdata(dev);
> +
> +	clk_disable(twi_dev->clk);
> +
> +	return 0;
> +}
> +
> +static int at91_twi_runtime_resume(struct device *dev)
> +{
> +	struct at91_twi_dev *twi_dev = dev_get_drvdata(dev);
> +
> +	return clk_enable(twi_dev->clk);
> +}
> +
> +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_twi_pm_ops NULL
> +#endif
> +
> +static struct platform_driver at91_twi_driver = {
> +	.probe		= at91_twi_probe,
> +	.remove		= __devexit_p(at91_twi_remove),
> +	.driver		= {
> +		.name	= "at91_i2c",
> +		.owner	= THIS_MODULE,
> +		.pm	= at91_twi_pm_ops,
> +	},
> +};
> +
> +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("Nikolaus Voss <n.voss@weinmann.de>");
> +MODULE_DESCRIPTION("I2C (TWI) driver for Atmel AT91");
> +MODULE_LICENSE("GPL");
> +MODULE_ALIAS("platform:at91_i2c");
>

^ permalink raw reply	[flat|nested] 21+ messages in thread

* Re: [PATCH v11 4/4] G45 TWI: remove open drain setting for twi function gpios
  2011-11-08 11:11   ` [PATCH v11 4/4] G45 TWI: remove open drain setting for twi function gpios Nikolaus Voss
@ 2012-08-27 10:24     ` ludovic.desroches
  2012-08-27 13:22       ` Voss, Nikolaus
  0 siblings, 1 reply; 21+ messages in thread
From: ludovic.desroches @ 2012-08-27 10:24 UTC (permalink / raw)
  To: Nikolaus Voss
  Cc: rmallon, nicolas.ferre, linux-kernel, balbi, h.feurstein,
	ludovic.desroches, linux-i2c, ben-linux, adrian.yanes,
	linux-arm-kernel, carsten.behling

Hi Nikolaus,

Le 11/08/2011 12:11 PM, Nikolaus Voss a écrit :
> The G45 datasheets explicitly states that setting the open drain property
> on peripheral function gpios is not allowed. (How about other A91 chips?)
>


Did you remove open drain because you had some issues or because you had 
seen it into datasheet?

I tried with and without open drain. The behavior was the same. Looking 
to the G45 datasheet, I didn't see that the open drain property is not 
allowed on peripheral function gpios:

'The Multi Drive can be selected whether the I/O line
is controlled by the PIO controller or assigned to a peripheral function.'

The datasheet should have been updated or there is another place where 
it is mentioned that open drain property is not allowed in this case.


Regards

Ludovic

> Signed-off-by: Nikolaus Voss <n.voss@weinmann.de>
> ---
>   arch/arm/mach-at91/at91sam9g45_devices.c |    6 ------
>   1 file changed, 6 deletions(-)
>
> diff --git a/arch/arm/mach-at91/at91sam9g45_devices.c b/arch/arm/mach-at91/at91sam9g45_devices.c
> index eec5eb6..2134663 100644
> --- a/arch/arm/mach-at91/at91sam9g45_devices.c
> +++ b/arch/arm/mach-at91/at91sam9g45_devices.c
> @@ -686,18 +686,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);
>   	}
>

^ permalink raw reply	[flat|nested] 21+ messages in thread

* RE: [PATCH v11 3/4] drivers/i2c/busses/i2c-at91.c: add new driver
  2012-08-27 10:16     ` ludovic.desroches
@ 2012-08-27 10:40       ` Yanes Martinez Adrian
  2012-08-27 12:04         ` ludovic.desroches
  0 siblings, 1 reply; 21+ messages in thread
From: Yanes Martinez Adrian @ 2012-08-27 10:40 UTC (permalink / raw)
  To: ludovic.desroches, Nikolaus Voss
  Cc: rmallon@gmail.com, nicolas.ferre@atmel.com,
	linux-kernel@vger.kernel.org, balbi@ti.com, h.feurstein@gmail.com,
	linux-i2c@vger.kernel.org, ben-linux@fluff.org,
	linux-arm-kernel@lists.infradead.org,
	carsten.behling@garz-fricke.com

Hi Ludovic,

>Tested on at91rm9200, at91sam9261, at91sam9g20 and at91sam9m10 with
>eeprom, temperature sensor and rtc devices (and wolfson chip for
>sam9g20).

concerning the at91rm9200, what was the amount of bytes you transmitted?

Some months ago I performed some testing[1] with the previous version of
the patch and the main conclusion was that the absence of PDC in the
AT91RM9200 made this driver unusable in such platform.

Please double check this.

Thanks in advance,

Adrian.

1 - http://thread.gmane.org/gmane.linux.drivers.i2c/10367/focus=1287445

^ permalink raw reply	[flat|nested] 21+ messages in thread

* Re: [PATCH v11 3/4] drivers/i2c/busses/i2c-at91.c: add new driver
  2012-08-27 10:40       ` Yanes Martinez Adrian
@ 2012-08-27 12:04         ` ludovic.desroches
  2012-08-27 12:45           ` Yanes Martinez Adrian
  0 siblings, 1 reply; 21+ messages in thread
From: ludovic.desroches @ 2012-08-27 12:04 UTC (permalink / raw)
  To: Yanes Martinez Adrian
  Cc: rmallon@gmail.com, Nikolaus Voss, nicolas.ferre@atmel.com,
	linux-kernel@vger.kernel.org, balbi@ti.com, h.feurstein@gmail.com,
	ludovic.desroches, linux-i2c@vger.kernel.org, ben-linux@fluff.org,
	linux-arm-kernel@lists.infradead.org,
	carsten.behling@garz-fricke.com

Hi Adrian,

Le 08/27/2012 12:40 PM, Yanes Martinez Adrian a écrit :
> Hi Ludovic,
>
>> Tested on at91rm9200, at91sam9261, at91sam9g20 and at91sam9m10 with
>> eeprom, temperature sensor and rtc devices (and wolfson chip for
>> sam9g20).
>
> concerning the at91rm9200, what was the amount of bytes you transmitted?
>

I have only checked that I can communicate with i2c devices so the 
amount is very low (1-4 bytes).

> Some months ago I performed some testing[1] with the previous version of
> the patch and the main conclusion was that the absence of PDC in the
> AT91RM9200 made this driver unusable in such platform.
>

Does the new driver break something? Was it working with the old one?

There are some issues with which are not related to the driver but to 
the design of the IP. With old I2C versions, using GPIO I2C is recommended.

> Please double check this.
>
> Thanks in advance,
>
> Adrian.
>
> 1 - http://thread.gmane.org/gmane.linux.drivers.i2c/10367/focus=1287445
>

Regards

Ludovic

^ permalink raw reply	[flat|nested] 21+ messages in thread

* RE: [PATCH v11 3/4] drivers/i2c/busses/i2c-at91.c: add new driver
  2012-08-27 12:04         ` ludovic.desroches
@ 2012-08-27 12:45           ` Yanes Martinez Adrian
       [not found]             ` <BC0F374A1C27184AB96177CDFEC2F54225ECD36E-rZDk5e4OVTsRAxgRyUl6SBEi2Xg3O0b1@public.gmane.org>
  0 siblings, 1 reply; 21+ messages in thread
From: Yanes Martinez Adrian @ 2012-08-27 12:45 UTC (permalink / raw)
  To: ludovic.desroches
  Cc: rmallon@gmail.com, Nikolaus Voss, nicolas.ferre@atmel.com,
	linux-kernel@vger.kernel.org, balbi@ti.com, h.feurstein@gmail.com,
	linux-i2c@vger.kernel.org, ben-linux@fluff.org,
	linux-arm-kernel@lists.infradead.org,
	carsten.behling@garz-fricke.com

>Hi Adrian,

Le 08/27/2012 12:40 PM, Yanes Martinez Adrian a écrit :
> Hi Ludovic,
>
>> Tested on at91rm9200, at91sam9261, at91sam9g20 and at91sam9m10 with
>> eeprom, temperature sensor and rtc devices (and wolfson chip for
>> sam9g20).
>
> concerning the at91rm9200, what was the amount of bytes you transmitted?
>

> I have only checked that I can communicate with i2c devices so the
> amount is very low (1-4 bytes).

IIRC it was from >7 bytes when the issues appeared.

> Some months ago I performed some testing[1] with the previous version of
> the patch and the main conclusion was that the absence of PDC in the
> AT91RM9200 made this driver unusable in such platform.
>

> Does the new driver break something? Was it working with the old one?

The old driver never worked properly. GPIO I2C has been the only alternative
to use I2C over AT91RM9200. With the proposed driver I just encountered
the same issues mentioned in the previous thread (so at the end nothing
changed for the AT91RM9200, GPIO is the only way to go).

>There are some issues with which are not related to the driver but to
>the design of the IP. With old I2C versions, using GPIO I2C is recommended.

I think a warning should be included in the proposed driver for that reason.
Despite the driver will work in the mentioned SoCs, the users will encounter
issues in boards like AT91RM9200 and other legacy products.

Regards,

Adrian.

^ permalink raw reply	[flat|nested] 21+ messages in thread

* RE: [PATCH v11 4/4] G45 TWI: remove open drain setting for twi function gpios
  2012-08-27 10:24     ` ludovic.desroches
@ 2012-08-27 13:22       ` Voss, Nikolaus
  2012-08-27 13:27         ` ludovic.desroches
  0 siblings, 1 reply; 21+ messages in thread
From: Voss, Nikolaus @ 2012-08-27 13:22 UTC (permalink / raw)
  To: 'ludovic.desroches'
  Cc: 'rmallon@gmail.com', 'nicolas.ferre@atmel.com',
	'linux-kernel@vger.kernel.org', 'balbi@ti.com',
	'h.feurstein@gmail.com',
	'linux-i2c@vger.kernel.org',
	'ben-linux@fluff.org', 'adrian.yanes@aalto.fi',
	'linux-arm-kernel@lists.infradead.org',
	'carsten.behling@garz-fricke.com'

Hi Ludovic,

ludovic.desroches wrote on Monday, August 27, 2012 12:25 PM:
> Le 11/08/2011 12:11 PM, Nikolaus Voss a écrit :
>> The G45 datasheets explicitly states that setting the open drain property
>> on peripheral function gpios is not allowed. (How about other A91 chips?)
>
> Did you remove open drain because you had some issues or because you
> had  seen it into datasheet?
> 
> I tried with and without open drain. The behavior was the same. Looking
> to the G45 datasheet, I didn't see that the open drain property is not
> allowed on peripheral function gpios:
> 
> 'The Multi Drive can be selected whether the I/O line
> is controlled by the PIO controller or assigned to a peripheral function.'
> 
> The datasheet should have been updated or there is another place where
> it is mentioned that open drain property is not allowed in this case.

well, it didn't work on my G45. I found the following note in the
TWI chapter 31.6.1 of the G45 datasheet:
"The user must not program TWD and TWCK as open-drain.
It is already done by the hardware."

After removing the open-drain setting, it worked.

Regards,
Nikolaus

^ permalink raw reply	[flat|nested] 21+ messages in thread

* Re: [PATCH v11 4/4] G45 TWI: remove open drain setting for twi function gpios
  2012-08-27 13:22       ` Voss, Nikolaus
@ 2012-08-27 13:27         ` ludovic.desroches
  0 siblings, 0 replies; 21+ messages in thread
From: ludovic.desroches @ 2012-08-27 13:27 UTC (permalink / raw)
  To: Voss, Nikolaus
  Cc: 'rmallon@gmail.com', 'nicolas.ferre@atmel.com',
	'linux-kernel@vger.kernel.org', 'balbi@ti.com',
	'h.feurstein@gmail.com', 'ludovic.desroches',
	'linux-i2c@vger.kernel.org',
	'ben-linux@fluff.org', 'adrian.yanes@aalto.fi',
	'linux-arm-kernel@lists.infradead.org',
	'carsten.behling@garz-fricke.com'

Le 08/27/2012 03:22 PM, Voss, Nikolaus a écrit :
> Hi Ludovic,
>
> ludovic.desroches wrote on Monday, August 27, 2012 12:25 PM:
>> Le 11/08/2011 12:11 PM, Nikolaus Voss a écrit :
>>> The G45 datasheets explicitly states that setting the open drain property
>>> on peripheral function gpios is not allowed. (How about other A91 chips?)
>>
>> Did you remove open drain because you had some issues or because you
>> had  seen it into datasheet?
>>
>> I tried with and without open drain. The behavior was the same. Looking
>> to the G45 datasheet, I didn't see that the open drain property is not
>> allowed on peripheral function gpios:
>>
>> 'The Multi Drive can be selected whether the I/O line
>> is controlled by the PIO controller or assigned to a peripheral function.'
>>
>> The datasheet should have been updated or there is another place where
>> it is mentioned that open drain property is not allowed in this case.
>
> well, it didn't work on my G45. I found the following note in the
> TWI chapter 31.6.1 of the G45 datasheet:
> "The user must not program TWD and TWCK as open-drain.
> It is already done by the hardware."

Ok so it seems there is a contradiction. I'll try to inquire about this 
point.

Regards

Ludovic

>
> After removing the open-drain setting, it worked.
>
> Regards,
> Nikolaus
>
>
>
>

^ permalink raw reply	[flat|nested] 21+ messages in thread

* RE: [PATCH v11 3/4] drivers/i2c/busses/i2c-at91.c: add new driver
       [not found]             ` <BC0F374A1C27184AB96177CDFEC2F54225ECD36E-rZDk5e4OVTsRAxgRyUl6SBEi2Xg3O0b1@public.gmane.org>
@ 2012-08-27 13:32               ` Voss, Nikolaus
  2012-08-27 14:00                 ` ludovic.desroches
  2012-08-30  7:35                 ` ludovic.desroches
  0 siblings, 2 replies; 21+ messages in thread
From: Voss, Nikolaus @ 2012-08-27 13:32 UTC (permalink / raw)
  To: 'Yanes Martinez Adrian', 'ludovic.desroches'
  Cc: 'linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r@public.gmane.org',
	'linux-kernel-u79uwXL29TY76Z2rM5mHXA@public.gmane.org',
	'linux-i2c-u79uwXL29TY76Z2rM5mHXA@public.gmane.org',
	'nicolas.ferre-AIFe0yeh4nAAvxtiuMwx3w@public.gmane.org',
	'ben-linux-elnMNo+KYs3YtjvyW6yDsg@public.gmane.org',
	'balbi-l0cyMroinI0@public.gmane.org',
	'h.feurstein-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org',
	'rmallon-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org',
	'carsten.behling-0M7HhAU3Y85FsXB23wyQUg@public.gmane.org'

Hi Adian,

Yanes Martinez Adrian wrote on Monday, August 27, 2012 2:46 PM:
> Le 08/27/2012 12:40 PM, Yanes Martinez Adrian a écrit :
>> Hi Ludovic,
>>
>>> Tested on at91rm9200, at91sam9261, at91sam9g20 and at91sam9m10 with
>>> eeprom, temperature sensor and rtc devices (and wolfson chip for
>>> sam9g20).
>>
>> concerning the at91rm9200, what was the amount of bytes you
> transmitted?
>>
> 
>> I have only checked that I can communicate with i2c devices so the
>> amount is very low (1-4 bytes).
> 
> IIRC it was from >7 bytes when the issues appeared.
> 
>> Some months ago I performed some testing[1] with the previous version of
>> the patch and the main conclusion was that the absence of PDC in the
>> AT91RM9200 made this driver unusable in such platform.

I didn't get your last post  in that thread. In my opinion RM9200 should really
be excluded from being configured with this driver, what's your opinion
Ludovic?

Regards,
Niko

^ permalink raw reply	[flat|nested] 21+ messages in thread

* Re: [PATCH v11 3/4] drivers/i2c/busses/i2c-at91.c: add new driver
  2012-08-27 13:32               ` Voss, Nikolaus
@ 2012-08-27 14:00                 ` ludovic.desroches
  2012-08-27 14:29                   ` Voss, Nikolaus
  2012-08-30  7:35                 ` ludovic.desroches
  1 sibling, 1 reply; 21+ messages in thread
From: ludovic.desroches @ 2012-08-27 14:00 UTC (permalink / raw)
  To: Voss, Nikolaus
  Cc: 'ben-linux@fluff.org',
	'carsten.behling@garz-fricke.com',
	'nicolas.ferre@atmel.com',
	'linux-kernel@vger.kernel.org', 'balbi@ti.com',
	'h.feurstein@gmail.com', 'ludovic.desroches',
	'linux-i2c@vger.kernel.org',
	'Yanes Martinez Adrian',
	'linux-arm-kernel@lists.infradead.org',
	'rmallon@gmail.com'

Le 08/27/2012 03:32 PM, Voss, Nikolaus a écrit :
> Hi Adian,
>
> Yanes Martinez Adrian wrote on Monday, August 27, 2012 2:46 PM:
>> Le 08/27/2012 12:40 PM, Yanes Martinez Adrian a écrit :
>>> Hi Ludovic,
>>>
>>>> Tested on at91rm9200, at91sam9261, at91sam9g20 and at91sam9m10 with
>>>> eeprom, temperature sensor and rtc devices (and wolfson chip for
>>>> sam9g20).
>>>
>>> concerning the at91rm9200, what was the amount of bytes you
>> transmitted?
>>>
>>
>>> I have only checked that I can communicate with i2c devices so the
>>> amount is very low (1-4 bytes).
>>
>> IIRC it was from >7 bytes when the issues appeared.
>>
>>> Some months ago I performed some testing[1] with the previous version of
>>> the patch and the main conclusion was that the absence of PDC in the
>>> AT91RM9200 made this driver unusable in such platform.
>
> I didn't get your last post  in that thread. In my opinion RM9200 should really
> be excluded from being configured with this driver, what's your opinion
> Ludovic?

Yes, the use of the TWI controller may be removed for some chips since 
there are issues that are dependent on the controller itself. RM9200 is 
not the only one.

For the moment, I don't have the necessary knowledge about the TWI 
controller to take a decision. I would say it can be done in an other 
patch in order to have your driver included in the mainline quickly 
since it doesn't introduce a breakage.

Regards

Ludovic

>
> Regards,
> Niko
>
> --
> To unsubscribe from this list: send the line "unsubscribe linux-i2c" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at  http://vger.kernel.org/majordomo-info.html
>
>

^ permalink raw reply	[flat|nested] 21+ messages in thread

* RE: [PATCH v11 3/4] drivers/i2c/busses/i2c-at91.c: add new driver
  2012-08-27 14:00                 ` ludovic.desroches
@ 2012-08-27 14:29                   ` Voss, Nikolaus
  2012-09-11  8:26                     ` Nicolas Ferre
  0 siblings, 1 reply; 21+ messages in thread
From: Voss, Nikolaus @ 2012-08-27 14:29 UTC (permalink / raw)
  To: 'ludovic.desroches',
	''Wolfram Sang' (w.sang@pengutronix.de)'
  Cc: 'Yanes Martinez Adrian',
	'carsten.behling@garz-fricke.com',
	'nicolas.ferre@atmel.com',
	'linux-kernel@vger.kernel.org', 'balbi@ti.com',
	'h.feurstein@gmail.com',
	'linux-i2c@vger.kernel.org',
	'ben-linux@fluff.org',
	'linux-arm-kernel@lists.infradead.org',
	'rmallon@gmail.com'

ludovic.desroches wrote on Monday, August 27, 2012 4:00 PM :
> For the moment, I don't have the necessary knowledge about the TWI
> controller to take a decision. I would say it can be done in an other
> patch in order to have your driver included in the mainline quickly
> since it doesn't introduce a breakage.

That would be the most pragmatic approach.
Wolfram, is the anything left to do from my side?

Regards,
Niko

^ permalink raw reply	[flat|nested] 21+ messages in thread

* Re: [PATCH v11 3/4] drivers/i2c/busses/i2c-at91.c: add new driver
  2011-11-08 10:49   ` [PATCH v11 3/4] drivers/i2c/busses/i2c-at91.c: add new driver Nikolaus Voss
  2012-08-27 10:16     ` ludovic.desroches
@ 2012-08-28 15:10     ` ludovic.desroches
  2012-08-28 15:32       ` Voss, Nikolaus
  1 sibling, 1 reply; 21+ messages in thread
From: ludovic.desroches @ 2012-08-28 15:10 UTC (permalink / raw)
  To: Nikolaus Voss
  Cc: rmallon, nicolas.ferre, linux-kernel, balbi, h.feurstein,
	ludovic.desroches, linux-i2c, ben-linux, adrian.yanes,
	linux-arm-kernel, carsten.behling

Hi Nikolaus,

I forgot one correction I did in your patch:

Le 11/08/2011 11:49 AM, Nikolaus Voss a écrit :
[...]

> diff --git a/arch/arm/mach-at91/at91sam9261_devices.c b/arch/arm/mach-at91/at91sam9261_devices.c
> index 9295e90..27fddc1 100644
> --- a/arch/arm/mach-at91/at91sam9261_devices.c
> +++ b/arch/arm/mach-at91/at91sam9261_devices.c
> @@ -283,9 +283,18 @@ static struct i2c_gpio_platform_data pdata = {
>   	.udelay			= 2,		/* ~100 kHz */
>   };
>
> +static const struct platform_device_id twi_ip_type = {
> +	/*
> +	 * driver_data is 2 for SAM9261 compatible ip, see enum twi_ip_id in
> +	 * drivers/i2c/busses/i2c-at91.c
> +	 */
> +	.driver_data	= 2,
> +};
> +
>   static struct platform_device at91sam9261_twi_device = {
>   	.name			= "i2c-gpio",
>   	.id			= -1,
> +	.id_entry		= &twi_ip_type,
>   	.dev.platform_data	= &pdata,
>   };
>

[...]

You add the id_entry to the i2c-gpio device instead of at91_i2c device.

Regards

Ludovic

^ permalink raw reply	[flat|nested] 21+ messages in thread

* RE: [PATCH v11 3/4] drivers/i2c/busses/i2c-at91.c: add new driver
  2012-08-28 15:10     ` ludovic.desroches
@ 2012-08-28 15:32       ` Voss, Nikolaus
  0 siblings, 0 replies; 21+ messages in thread
From: Voss, Nikolaus @ 2012-08-28 15:32 UTC (permalink / raw)
  To: 'ludovic.desroches'
  Cc: 'rmallon@gmail.com', 'nicolas.ferre@atmel.com',
	'linux-kernel@vger.kernel.org', 'balbi@ti.com',
	'h.feurstein@gmail.com',
	'linux-i2c@vger.kernel.org',
	'ben-linux@fluff.org', 'adrian.yanes@aalto.fi',
	'linux-arm-kernel@lists.infradead.org',
	'carsten.behling@garz-fricke.com'

Hi Ludovic,

ludovic.desroches wrote on Tuesday, August 28, 2012 5:10 PM:
> > +static const struct platform_device_id twi_ip_type = {
> > +	/*
> > +	 * driver_data is 2 for SAM9261 compatible ip, see enum twi_ip_id in
> > +	 * drivers/i2c/busses/i2c-at91.c
> > +	 */
> > +	.driver_data	= 2,
> > +};
> > +
> >   static struct platform_device at91sam9261_twi_device = {
> >   	.name			= "i2c-gpio",
> >   	.id			= -1,
> > +	.id_entry		= &twi_ip_type,
> >   	.dev.platform_data	= &pdata,
> >   };
> >
> 
> [...]
> 
> You add the id_entry to the i2c-gpio device instead of at91_i2c device.

Oh! I'll post the complete series tomorrow.

Regards,
Niko

^ permalink raw reply	[flat|nested] 21+ messages in thread

* Re: [PATCH v11 3/4] drivers/i2c/busses/i2c-at91.c: add new driver
  2012-08-27 13:32               ` Voss, Nikolaus
  2012-08-27 14:00                 ` ludovic.desroches
@ 2012-08-30  7:35                 ` ludovic.desroches
  1 sibling, 0 replies; 21+ messages in thread
From: ludovic.desroches @ 2012-08-30  7:35 UTC (permalink / raw)
  To: Voss, Nikolaus
  Cc: 'ben-linux@fluff.org',
	'carsten.behling@garz-fricke.com',
	'nicolas.ferre@atmel.com',
	'linux-kernel@vger.kernel.org', 'balbi@ti.com',
	'h.feurstein@gmail.com', 'ludovic.desroches',
	'linux-i2c@vger.kernel.org',
	'Yanes Martinez Adrian',
	'linux-arm-kernel@lists.infradead.org',
	'rmallon@gmail.com'

Le 08/27/2012 03:32 PM, Voss, Nikolaus a écrit :
> Hi Adian,
>
> Yanes Martinez Adrian wrote on Monday, August 27, 2012 2:46 PM:
>> Le 08/27/2012 12:40 PM, Yanes Martinez Adrian a écrit :
>>> Hi Ludovic,
>>>
>>>> Tested on at91rm9200, at91sam9261, at91sam9g20 and at91sam9m10 with
>>>> eeprom, temperature sensor and rtc devices (and wolfson chip for
>>>> sam9g20).
>>>
>>> concerning the at91rm9200, what was the amount of bytes you
>> transmitted?
>>>
>>
>>> I have only checked that I can communicate with i2c devices so the
>>> amount is very low (1-4 bytes).
>>
>> IIRC it was from >7 bytes when the issues appeared.
>>
>>> Some months ago I performed some testing[1] with the previous version of
>>> the patch and the main conclusion was that the absence of PDC in the
>>> AT91RM9200 made this driver unusable in such platform.
>
> I didn't get your last post  in that thread. In my opinion RM9200 should really
> be excluded from being configured with this driver, what's your opinion
> Ludovic?
>

After investigation, the transmission issue may concern rm9200, 9261, 
9260 and 9263. The main cause of this issue is we do not have clock 
stretching.
Using a low clock frequency should reduce the underrun issue so this 
driver can be used on those chips but a warning have to be added to 
indicate this potential issue. I'll do it when I'll resend patches for 
DT support.


Regards

Ludovic

> Regards,
> Niko
>
> --
> To unsubscribe from this list: send the line "unsubscribe linux-i2c" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at  http://vger.kernel.org/majordomo-info.html
>
>

^ permalink raw reply	[flat|nested] 21+ messages in thread

* Re: [PATCH v11 3/4] drivers/i2c/busses/i2c-at91.c: add new driver
  2012-08-27 14:29                   ` Voss, Nikolaus
@ 2012-09-11  8:26                     ` Nicolas Ferre
       [not found]                       ` <504EF5BF.2090404-AIFe0yeh4nAAvxtiuMwx3w@public.gmane.org>
  0 siblings, 1 reply; 21+ messages in thread
From: Nicolas Ferre @ 2012-09-11  8:26 UTC (permalink / raw)
  To: ''Wolfram Sang' (w.sang@pengutronix.de)'
  Cc: 'ben-linux@fluff.org',
	'carsten.behling@garz-fricke.com', Voss, Nikolaus,
	'linux-kernel@vger.kernel.org', 'balbi@ti.com',
	'h.feurstein@gmail.com', 'ludovic.desroches',
	'linux-i2c@vger.kernel.org',
	'Yanes Martinez Adrian',
	'linux-arm-kernel@lists.infradead.org',
	'rmallon@gmail.com'

On 08/27/2012 04:29 PM, Voss, Nikolaus :
> ludovic.desroches wrote on Monday, August 27, 2012 4:00 PM :
>> For the moment, I don't have the necessary knowledge about the TWI
>> controller to take a decision. I would say it can be done in an other
>> patch in order to have your driver included in the mainline quickly
>> since it doesn't introduce a breakage.
> 
> That would be the most pragmatic approach.
> Wolfram, is the anything left to do from my side?

Wolfram, ping?

Can we imagine to have this support and the device tree patches from
Ludovic in 3.7-final?

Bye,
-- 
Nicolas Ferre

^ permalink raw reply	[flat|nested] 21+ messages in thread

* Re: [PATCH v11 3/4] drivers/i2c/busses/i2c-at91.c: add new driver
       [not found]                       ` <504EF5BF.2090404-AIFe0yeh4nAAvxtiuMwx3w@public.gmane.org>
@ 2012-09-11 22:13                         ` Wolfram Sang
  0 siblings, 0 replies; 21+ messages in thread
From: Wolfram Sang @ 2012-09-11 22:13 UTC (permalink / raw)
  To: Nicolas Ferre
  Cc: Voss, Nikolaus, 'ludovic.desroches',
	'Yanes Martinez Adrian',
	'linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r@public.gmane.org',
	'linux-kernel-u79uwXL29TY76Z2rM5mHXA@public.gmane.org',
	'linux-i2c-u79uwXL29TY76Z2rM5mHXA@public.gmane.org',
	'ben-linux-elnMNo+KYs3YtjvyW6yDsg@public.gmane.org',
	'balbi-l0cyMroinI0@public.gmane.org',
	'h.feurstein-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org',
	'rmallon-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org',
	'carsten.behling-0M7HhAU3Y85FsXB23wyQUg@public.gmane.org'

[-- Attachment #1: Type: text/plain, Size: 971 bytes --]

On Tue, Sep 11, 2012 at 10:26:39AM +0200, Nicolas Ferre wrote:
> On 08/27/2012 04:29 PM, Voss, Nikolaus :
> > ludovic.desroches wrote on Monday, August 27, 2012 4:00 PM :
> >> For the moment, I don't have the necessary knowledge about the TWI
> >> controller to take a decision. I would say it can be done in an other
> >> patch in order to have your driver included in the mainline quickly
> >> since it doesn't introduce a breakage.
> > 
> > That would be the most pragmatic approach.
> > Wolfram, is the anything left to do from my side?
> 
> Wolfram, ping?
> 
> Can we imagine to have this support and the device tree patches from
> Ludovic in 3.7-final?

Yes. I'd need your ack since it touches mach-specific stuff. Reviewed-by
would be even better since you know the HW better than me :)

-- 
Pengutronix e.K.                           | Wolfram Sang                |
Industrial Linux Solutions                 | http://www.pengutronix.de/  |

[-- Attachment #2: Digital signature --]
[-- Type: application/pgp-signature, Size: 198 bytes --]

^ permalink raw reply	[flat|nested] 21+ messages in thread

end of thread, other threads:[~2012-09-11 22:13 UTC | newest]

Thread overview: 21+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2012-08-22  6:59 [PATCH v11 0/4] AT91: replace old i2c-at91.c TWI driver Nikolaus Voss
     [not found] ` <cover.1345618760.git.n.voss-+umVssTZoCsb1SvskN2V4Q@public.gmane.org>
2011-11-08 10:49   ` [PATCH v11 1/4] drivers/i2c/busses/i2c-at91.c: remove old polling driver Nikolaus Voss
2011-11-08 10:49   ` [PATCH v11 3/4] drivers/i2c/busses/i2c-at91.c: add new driver Nikolaus Voss
2012-08-27 10:16     ` ludovic.desroches
2012-08-27 10:40       ` Yanes Martinez Adrian
2012-08-27 12:04         ` ludovic.desroches
2012-08-27 12:45           ` Yanes Martinez Adrian
     [not found]             ` <BC0F374A1C27184AB96177CDFEC2F54225ECD36E-rZDk5e4OVTsRAxgRyUl6SBEi2Xg3O0b1@public.gmane.org>
2012-08-27 13:32               ` Voss, Nikolaus
2012-08-27 14:00                 ` ludovic.desroches
2012-08-27 14:29                   ` Voss, Nikolaus
2012-09-11  8:26                     ` Nicolas Ferre
     [not found]                       ` <504EF5BF.2090404-AIFe0yeh4nAAvxtiuMwx3w@public.gmane.org>
2012-09-11 22:13                         ` Wolfram Sang
2012-08-30  7:35                 ` ludovic.desroches
2012-08-28 15:10     ` ludovic.desroches
2012-08-28 15:32       ` Voss, Nikolaus
2011-11-08 11:09   ` [PATCH v11 2/4] Replace clk_lookup.con_id with clk_lookup.dev_id entries for twi clk Nikolaus Voss
2011-11-08 11:11   ` [PATCH v11 4/4] G45 TWI: remove open drain setting for twi function gpios Nikolaus Voss
2012-08-27 10:24     ` ludovic.desroches
2012-08-27 13:22       ` Voss, Nikolaus
2012-08-27 13:27         ` ludovic.desroches
  -- strict thread matches above, loose matches on Subject: below --
2012-08-29  7:28 [PATCH v11 0/4] AT91: replace old i2c-at91.c TWI driver Nikolaus Voss
     [not found] ` <cover.1346225321.git.n.voss-+umVssTZoCsb1SvskN2V4Q@public.gmane.org>
2011-11-08 10:49   ` [PATCH v11 3/4] drivers/i2c/busses/i2c-at91.c: add new driver Nikolaus Voss

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).