[ARM] 4650/1: AT91: New-style init of I2C, support for i2c-gpio

The AT91 I2C driver is currently marked as "broken" due to hardware
issues.  This patch enables AT91-based platforms to also use the
bitbanged GPIO for I2C.

This updates platform setup logic (setting up an i2c-gpio device
using the same pins as the i2c-at91 device, unless only the BROKEN
driver is enabled).

Also make use of the new-style initialization of I2C devices using
i2c_register_board_info().

Signed-off-by: David Brownell <dbrownell@users.sourceforge.net>
Signed-off-by: Andrew Victor <andrew@sanpeople.com>
Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
diff --git a/arch/arm/mach-at91/at91sam9rl_devices.c b/arch/arm/mach-at91/at91sam9rl_devices.c
index cd7532b..2bd60a3 100644
--- a/arch/arm/mach-at91/at91sam9rl_devices.c
+++ b/arch/arm/mach-at91/at91sam9rl_devices.c
@@ -10,8 +10,9 @@
 #include <asm/mach/map.h>
 
 #include <linux/platform_device.h>
-#include <linux/fb.h>
+#include <linux/i2c-gpio.h>
 
+#include <linux/fb.h>
 #include <video/atmel_lcdc.h>
 
 #include <asm/arch/board.h>
@@ -169,7 +170,40 @@
  *  TWI (i2c)
  * -------------------------------------------------------------------- */
 
-#if defined(CONFIG_I2C_AT91) || defined(CONFIG_I2C_AT91_MODULE)
+/*
+ * Prefer the GPIO code since the TWI controller isn't robust
+ * (gets overruns and underruns under load) and can only issue
+ * repeated STARTs in one scenario (the driver doesn't yet handle them).
+ */
+#if defined(CONFIG_I2C_GPIO) || defined(CONFIG_I2C_GPIO_MODULE)
+
+static struct i2c_gpio_platform_data pdata = {
+	.sda_pin		= AT91_PIN_PA23,
+	.sda_is_open_drain	= 1,
+	.scl_pin		= AT91_PIN_PA24,
+	.scl_is_open_drain	= 1,
+	.udelay			= 2,		/* ~100 kHz */
+};
+
+static struct platform_device at91sam9rl_twi_device = {
+	.name			= "i2c-gpio",
+	.id			= -1,
+	.dev.platform_data	= &pdata,
+};
+
+void __init at91_add_device_i2c(struct i2c_board_info *devices, int nr_devices)
+{
+	at91_set_GPIO_periph(AT91_PIN_PA23, 1);		/* TWD (SDA) */
+	at91_set_multi_drive(AT91_PIN_PA23, 1);
+
+	at91_set_GPIO_periph(AT91_PIN_PA24, 1);		/* TWCK (SCL) */
+	at91_set_multi_drive(AT91_PIN_PA24, 1);
+
+	i2c_register_board_info(0, devices, nr_devices);
+	platform_device_register(&at91sam9rl_twi_device);
+}
+
+#elif defined(CONFIG_I2C_AT91) || defined(CONFIG_I2C_AT91_MODULE)
 
 static struct resource twi_resources[] = {
 	[0] = {
@@ -191,7 +225,7 @@
 	.num_resources	= ARRAY_SIZE(twi_resources),
 };
 
-void __init at91_add_device_i2c(void)
+void __init at91_add_device_i2c(struct i2c_board_info *devices, int nr_devices)
 {
 	/* pins used for TWI interface */
 	at91_set_A_periph(AT91_PIN_PA23, 0);		/* TWD */
@@ -200,10 +234,11 @@
 	at91_set_A_periph(AT91_PIN_PA24, 0);		/* TWCK */
 	at91_set_multi_drive(AT91_PIN_PA24, 1);
 
+	i2c_register_board_info(0, devices, nr_devices);
 	platform_device_register(&at91sam9rl_twi_device);
 }
 #else
-void __init at91_add_device_i2c(void) {}
+void __init at91_add_device_i2c(struct i2c_board_info *devices, int nr_devices) {}
 #endif