[PATCH v2 07/23] at91: Make TWI device common

Ryan Mallon ryan at bluewatersys.com
Thu Apr 21 01:41:59 EDT 2011


Replace the individual TWI code for each at91 variant with a single
implementation in devices.c

The AT91SAM9G45 has an additional argument to at91_add_device_i2c for
the bus number. We change the other variants to use this API for
consistency.

Signed-off-by: Ryan Mallon <ryan at bluewatersys.com>
---
 arch/arm/mach-at91/at572d940hf_devices.c  |  111 +++--------------------
 arch/arm/mach-at91/at91cap9_devices.c     |   76 ++---------------
 arch/arm/mach-at91/at91rm9200_devices.c   |   77 ++---------------
 arch/arm/mach-at91/at91sam9260_devices.c  |   78 ++---------------
 arch/arm/mach-at91/at91sam9261_devices.c  |   77 ++---------------
 arch/arm/mach-at91/at91sam9263_devices.c  |   77 ++---------------
 arch/arm/mach-at91/at91sam9g45_devices.c  |  136 +++--------------------------
 arch/arm/mach-at91/at91sam9rl_devices.c   |   77 ++---------------
 arch/arm/mach-at91/board-afeb-9260v1.c    |    2 +-
 arch/arm/mach-at91/board-at572d940hf_ek.c |    2 +-
 arch/arm/mach-at91/board-cap9adk.c        |    2 +-
 arch/arm/mach-at91/board-carmeva.c        |    2 +-
 arch/arm/mach-at91/board-cpu9krea.c       |    2 +-
 arch/arm/mach-at91/board-cpuat91.c        |    2 +-
 arch/arm/mach-at91/board-csb337.c         |    2 +-
 arch/arm/mach-at91/board-csb637.c         |    2 +-
 arch/arm/mach-at91/board-eb9200.c         |    2 +-
 arch/arm/mach-at91/board-ecbat91.c        |    2 +-
 arch/arm/mach-at91/board-foxg20.c         |    2 +-
 arch/arm/mach-at91/board-gsia18s.c        |    2 +-
 arch/arm/mach-at91/board-kafa.c           |    2 +-
 arch/arm/mach-at91/board-kb9202.c         |    2 +-
 arch/arm/mach-at91/board-neocore926.c     |    2 +-
 arch/arm/mach-at91/board-pcontrol-g20.c   |    2 +-
 arch/arm/mach-at91/board-picotux200.c     |    2 +-
 arch/arm/mach-at91/board-qil-a9260.c      |    2 +-
 arch/arm/mach-at91/board-rm9200dk.c       |    2 +-
 arch/arm/mach-at91/board-rm9200ek.c       |    2 +-
 arch/arm/mach-at91/board-sam9-l9260.c     |    2 +-
 arch/arm/mach-at91/board-sam9260ek.c      |    2 +-
 arch/arm/mach-at91/board-sam9261ek.c      |    2 +-
 arch/arm/mach-at91/board-sam9263ek.c      |    2 +-
 arch/arm/mach-at91/board-sam9g20ek.c      |    2 +-
 arch/arm/mach-at91/board-sam9rlek.c       |    2 +-
 arch/arm/mach-at91/board-snapper9260.c    |    2 +-
 arch/arm/mach-at91/board-stamp9g20.c      |    4 +-
 arch/arm/mach-at91/board-usb-a9260.c      |    2 +-
 arch/arm/mach-at91/board-usb-a9263.c      |    2 +-
 arch/arm/mach-at91/board-yl-9200.c        |    2 +-
 arch/arm/mach-at91/devices.c              |  122 ++++++++++++++++++++++++++
 arch/arm/mach-at91/devices.h              |    9 ++
 arch/arm/mach-at91/include/mach/board.h   |    4 -
 42 files changed, 233 insertions(+), 675 deletions(-)

diff --git a/arch/arm/mach-at91/at572d940hf_devices.c b/arch/arm/mach-at91/at572d940hf_devices.c
index 771e1bf..482de24 100644
--- a/arch/arm/mach-at91/at572d940hf_devices.c
+++ b/arch/arm/mach-at91/at572d940hf_devices.c
@@ -122,107 +122,22 @@ static struct at91_dev_table_nand device_nand __initdata = {
  *  TWI (i2c)
  * -------------------------------------------------------------------- */
 
-/*
- * 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_PC7,
-	.sda_is_open_drain	= 1,
-	.scl_pin		= AT91_PIN_PC8,
-	.scl_is_open_drain	= 1,
-	.udelay			= 2,		/* ~100 kHz */
-};
-
-static struct platform_device at572d940hf_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_PC7, 1);		/* TWD (SDA) */
-	at91_set_multi_drive(AT91_PIN_PC7, 1);
-
-	at91_set_GPIO_periph(AT91_PIN_PA8, 1);		/* TWCK (SCL) */
-	at91_set_multi_drive(AT91_PIN_PC8, 1);
-
-	i2c_register_board_info(0, devices, nr_devices);
-	platform_device_register(&at572d940hf_twi_device);
-}
-
-#elif defined(CONFIG_I2C_AT91) || defined(CONFIG_I2C_AT91_MODULE)
-
-static struct resource twi0_resources[] = {
-	[0] = {
-		.start	= AT572D940HF_BASE_TWI0,
-		.end	= AT572D940HF_BASE_TWI0 + SZ_16K - 1,
-		.flags	= IORESOURCE_MEM,
-	},
-	[1] = {
-		.start	= AT572D940HF_ID_TWI0,
-		.end	= AT572D940HF_ID_TWI0,
-		.flags	= IORESOURCE_IRQ,
-	},
-};
-
-static struct platform_device at572d940hf_twi0_device = {
-	.name		= "at91_i2c",
-	.id		= 0,
-	.resource	= twi0_resources,
-	.num_resources	= ARRAY_SIZE(twi0_resources),
+static struct at91_dev_table_twi device_twi0 __initdata = {
+	.mmio_base	= AT572D940HF_BASE_TWI0,
+	.irq		= AT572D940HF_ID_TWI0,
+	.sda_pin 	= {AT91_PIN_PC7, AT91_PIN_PERIPH_A, 0, 0, 0},
+	.scl_pin	= {AT91_PIN_PC8, AT91_PIN_PERIPH_A, 0, 0, 0},
+	.udelay		= 2,
 };
 
-static struct resource twi1_resources[] = {
-	[0] = {
-		.start	= AT572D940HF_BASE_TWI1,
-		.end	= AT572D940HF_BASE_TWI1 + SZ_16K - 1,
-		.flags	= IORESOURCE_MEM,
-	},
-	[1] = {
-		.start	= AT572D940HF_ID_TWI1,
-		.end	= AT572D940HF_ID_TWI1,
-		.flags	= IORESOURCE_IRQ,
-	},
-};
-
-static struct platform_device at572d940hf_twi1_device = {
-	.name		= "at91_i2c",
-	.id		= 1,
-	.resource	= twi1_resources,
-	.num_resources	= ARRAY_SIZE(twi1_resources),
+static struct at91_dev_table_twi device_twi1 __initdata = {
+	.mmio_base	= AT572D940HF_BASE_TWI1,
+	.irq		= AT572D940HF_ID_TWI1,
+	.sda_pin 	= {AT91_PIN_PC7, AT91_PIN_PERIPH_A, 0, 0, 0},
+	.scl_pin	= {AT91_PIN_PC8, AT91_PIN_PERIPH_A, 0, 0, 0},
+	.udelay		= 2,
 };
 
-void __init at91_add_device_i2c(struct i2c_board_info *devices, int nr_devices)
-{
-	/* pins used for TWI0 interface */
-	at91_set_A_periph(AT91_PIN_PC7, 0);		/* TWD */
-	at91_set_multi_drive(AT91_PIN_PC7, 1);
-
-	at91_set_A_periph(AT91_PIN_PC8, 0);		/* TWCK */
-	at91_set_multi_drive(AT91_PIN_PC8, 1);
-
-	/* pins used for TWI1 interface */
-	at91_set_A_periph(AT91_PIN_PC20, 0);		/* TWD */
-	at91_set_multi_drive(AT91_PIN_PC20, 1);
-
-	at91_set_A_periph(AT91_PIN_PC21, 0);		/* TWCK */
-	at91_set_multi_drive(AT91_PIN_PC21, 1);
-
-	i2c_register_board_info(0, devices, nr_devices);
-	platform_device_register(&at572d940hf_twi0_device);
-	platform_device_register(&at572d940hf_twi1_device);
-}
-#else
-void __init at91_add_device_i2c(struct i2c_board_info *devices, int nr_devices) {}
-#endif
-
-
 /* --------------------------------------------------------------------
  *  SPI
  * -------------------------------------------------------------------- */
@@ -744,6 +659,8 @@ static struct at91_device_table at572d940hf_device_table __initdata = {
 	.udc		= &device_udc,
 	.mmc[0]		= &device_mmc,
 	.nand		= &device_nand,
+	.twi[0]		= &device_twi0,
+	.twi[1]		= &device_twi1,
 };
 
 void __init at572d940hf_init_devices(void)
diff --git a/arch/arm/mach-at91/at91cap9_devices.c b/arch/arm/mach-at91/at91cap9_devices.c
index 773eb95..a647963 100644
--- a/arch/arm/mach-at91/at91cap9_devices.c
+++ b/arch/arm/mach-at91/at91cap9_devices.c
@@ -239,77 +239,14 @@ static struct at91_dev_table_nand device_nand __initdata = {
  *  TWI (i2c)
  * -------------------------------------------------------------------- */
 
-/*
- * 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_PB4,
-	.sda_is_open_drain	= 1,
-	.scl_pin		= AT91_PIN_PB5,
-	.scl_is_open_drain	= 1,
-	.udelay			= 2,		/* ~100 kHz */
-};
-
-static struct platform_device at91cap9_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_PB4, 1);		/* TWD (SDA) */
-	at91_set_multi_drive(AT91_PIN_PB4, 1);
-
-	at91_set_GPIO_periph(AT91_PIN_PB5, 1);		/* TWCK (SCL) */
-	at91_set_multi_drive(AT91_PIN_PB5, 1);
-
-	i2c_register_board_info(0, devices, nr_devices);
-	platform_device_register(&at91cap9_twi_device);
-}
-
-#elif defined(CONFIG_I2C_AT91) || defined(CONFIG_I2C_AT91_MODULE)
-
-static struct resource twi_resources[] = {
-	[0] = {
-		.start	= AT91CAP9_BASE_TWI,
-		.end	= AT91CAP9_BASE_TWI + SZ_16K - 1,
-		.flags	= IORESOURCE_MEM,
-	},
-	[1] = {
-		.start	= AT91CAP9_ID_TWI,
-		.end	= AT91CAP9_ID_TWI,
-		.flags	= IORESOURCE_IRQ,
-	},
-};
-
-static struct platform_device at91cap9_twi_device = {
-	.name		= "at91_i2c",
-	.id		= -1,
-	.resource	= twi_resources,
-	.num_resources	= ARRAY_SIZE(twi_resources),
+static struct at91_dev_table_twi device_twi __initdata = {
+	.mmio_base	= AT91CAP9_BASE_TWI,
+	.irq		= AT91CAP9_ID_TWI,
+	.sda_pin 	= {AT91_PIN_PB4, AT91_PIN_PERIPH_B, 0, 0, 0},
+	.scl_pin	= {AT91_PIN_PB5, AT91_PIN_PERIPH_B, 0, 0, 0},
+	.udelay		= 2,
 };
 
-void __init at91_add_device_i2c(struct i2c_board_info *devices, int nr_devices)
-{
-	/* pins used for TWI interface */
-	at91_set_B_periph(AT91_PIN_PB4, 0);		/* TWD */
-	at91_set_multi_drive(AT91_PIN_PB4, 1);
-
-	at91_set_B_periph(AT91_PIN_PB5, 0);		/* TWCK */
-	at91_set_multi_drive(AT91_PIN_PB5, 1);
-
-	i2c_register_board_info(0, devices, nr_devices);
-	platform_device_register(&at91cap9_twi_device);
-}
-#else
-void __init at91_add_device_i2c(struct i2c_board_info *devices, int nr_devices) {}
-#endif
-
 /* --------------------------------------------------------------------
  *  SPI
  * -------------------------------------------------------------------- */
@@ -1051,6 +988,7 @@ static struct at91_device_table at91cap9_device_table __initdata = {
 	.mmc[0]		= &device_mmc0,
 	.mmc[1]		= &device_mmc1,
 	.nand		= &device_nand,
+	.twi[0]		= &device_twi,
 };
 
 void __init at91cap9_init_devices(void)
diff --git a/arch/arm/mach-at91/at91rm9200_devices.c b/arch/arm/mach-at91/at91rm9200_devices.c
index 90ca534..a889114 100644
--- a/arch/arm/mach-at91/at91rm9200_devices.c
+++ b/arch/arm/mach-at91/at91rm9200_devices.c
@@ -223,78 +223,14 @@ static struct at91_dev_table_nand device_nand __initdata = {
  *  TWI (i2c)
  * -------------------------------------------------------------------- */
 
-/*
- * 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_PA25,
-	.sda_is_open_drain	= 1,
-	.scl_pin		= AT91_PIN_PA26,
-	.scl_is_open_drain	= 1,
-	.udelay			= 2,		/* ~100 kHz */
-};
-
-static struct platform_device at91rm9200_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_PA25, 1);		/* TWD (SDA) */
-	at91_set_multi_drive(AT91_PIN_PA25, 1);
-
-	at91_set_GPIO_periph(AT91_PIN_PA26, 1);		/* TWCK (SCL) */
-	at91_set_multi_drive(AT91_PIN_PA26, 1);
-
-	i2c_register_board_info(0, devices, nr_devices);
-	platform_device_register(&at91rm9200_twi_device);
-}
-
-#elif defined(CONFIG_I2C_AT91) || defined(CONFIG_I2C_AT91_MODULE)
-
-static struct resource twi_resources[] = {
-	[0] = {
-		.start	= AT91RM9200_BASE_TWI,
-		.end	= AT91RM9200_BASE_TWI + SZ_16K - 1,
-		.flags	= IORESOURCE_MEM,
-	},
-	[1] = {
-		.start	= AT91RM9200_ID_TWI,
-		.end	= AT91RM9200_ID_TWI,
-		.flags	= IORESOURCE_IRQ,
-	},
+static struct at91_dev_table_twi device_twi __initdata = {
+	.mmio_base	= AT91RM9200_BASE_TWI,
+	.irq		= AT91RM9200_ID_TWI,
+	.sda_pin 	= {AT91_PIN_PA25, AT91_PIN_PERIPH_A, 0, 0, 0},
+	.scl_pin	= {AT91_PIN_PA26, AT91_PIN_PERIPH_A, 0, 0, 0},
+	.udelay		= 2,
 };
 
-static struct platform_device at91rm9200_twi_device = {
-	.name		= "at91_i2c",
-	.id		= -1,
-	.resource	= twi_resources,
-	.num_resources	= ARRAY_SIZE(twi_resources),
-};
-
-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_PA25, 0);		/* TWD */
-	at91_set_multi_drive(AT91_PIN_PA25, 1);
-
-	at91_set_A_periph(AT91_PIN_PA26, 0);		/* TWCK */
-	at91_set_multi_drive(AT91_PIN_PA26, 1);
-
-	i2c_register_board_info(0, devices, nr_devices);
-	platform_device_register(&at91rm9200_twi_device);
-}
-#else
-void __init at91_add_device_i2c(struct i2c_board_info *devices, int nr_devices) {}
-#endif
-
-
 /* --------------------------------------------------------------------
  *  SPI
  * -------------------------------------------------------------------- */
@@ -962,6 +898,7 @@ static struct at91_device_table at91rm9200_device_table __initdata = {
 	.udc		= &device_udc,
 	.mmc[0]		= &device_mmc,
 	.nand		= &device_nand,
+	.twi[0]		= &device_twi,
 };
 
 void __init at91rm9200_init_devices(void)
diff --git a/arch/arm/mach-at91/at91sam9260_devices.c b/arch/arm/mach-at91/at91sam9260_devices.c
index f48ad70..ed2e071 100644
--- a/arch/arm/mach-at91/at91sam9260_devices.c
+++ b/arch/arm/mach-at91/at91sam9260_devices.c
@@ -124,79 +124,14 @@ static struct at91_dev_table_nand device_nand __initdata = {
  *  TWI (i2c)
  * -------------------------------------------------------------------- */
 
-/*
- * 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 at91_dev_table_twi device_twi __initdata = {
+	.mmio_base	= AT91SAM9260_BASE_TWI,
+	.irq		= AT91SAM9260_ID_TWI,
+	.sda_pin 	= {AT91_PIN_PA23, AT91_PIN_PERIPH_A, 0, 0, 0},
+	.scl_pin	= {AT91_PIN_PA24, AT91_PIN_PERIPH_A, 0, 0, 0},
+	.udelay		= 2,
 };
 
-static struct platform_device at91sam9260_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(&at91sam9260_twi_device);
-}
-
-#elif defined(CONFIG_I2C_AT91) || defined(CONFIG_I2C_AT91_MODULE)
-
-static struct resource twi_resources[] = {
-	[0] = {
-		.start	= AT91SAM9260_BASE_TWI,
-		.end	= AT91SAM9260_BASE_TWI + SZ_16K - 1,
-		.flags	= IORESOURCE_MEM,
-	},
-	[1] = {
-		.start	= AT91SAM9260_ID_TWI,
-		.end	= AT91SAM9260_ID_TWI,
-		.flags	= IORESOURCE_IRQ,
-	},
-};
-
-static struct platform_device at91sam9260_twi_device = {
-	.name		= "at91_i2c",
-	.id		= -1,
-	.resource	= twi_resources,
-	.num_resources	= ARRAY_SIZE(twi_resources),
-};
-
-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 */
-	at91_set_multi_drive(AT91_PIN_PA23, 1);
-
-	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(&at91sam9260_twi_device);
-}
-#else
-void __init at91_add_device_i2c(struct i2c_board_info *devices, int nr_devices) {}
-#endif
-
-
 /* --------------------------------------------------------------------
  *  SPI
  * -------------------------------------------------------------------- */
@@ -1015,6 +950,7 @@ static struct at91_device_table at91sam9260_device_table __initdata = {
 	.udc		= &device_udc,
 	.mmc[0]		= &device_mmc,
 	.nand		= &device_nand,
+	.twi[0]		= &device_twi,
 };
 
 void __init at91sam9260_init_devices(void)
diff --git a/arch/arm/mach-at91/at91sam9261_devices.c b/arch/arm/mach-at91/at91sam9261_devices.c
index 9505ae3..15c701b 100644
--- a/arch/arm/mach-at91/at91sam9261_devices.c
+++ b/arch/arm/mach-at91/at91sam9261_devices.c
@@ -87,78 +87,14 @@ static struct at91_dev_table_nand device_nand __initdata = {
  *  TWI (i2c)
  * -------------------------------------------------------------------- */
 
-/*
- * 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_PA7,
-	.sda_is_open_drain	= 1,
-	.scl_pin		= AT91_PIN_PA8,
-	.scl_is_open_drain	= 1,
-	.udelay			= 2,		/* ~100 kHz */
-};
-
-static struct platform_device at91sam9261_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_PA7, 1);		/* TWD (SDA) */
-	at91_set_multi_drive(AT91_PIN_PA7, 1);
-
-	at91_set_GPIO_periph(AT91_PIN_PA8, 1);		/* TWCK (SCL) */
-	at91_set_multi_drive(AT91_PIN_PA8, 1);
-
-	i2c_register_board_info(0, devices, nr_devices);
-	platform_device_register(&at91sam9261_twi_device);
-}
-
-#elif defined(CONFIG_I2C_AT91) || defined(CONFIG_I2C_AT91_MODULE)
-
-static struct resource twi_resources[] = {
-	[0] = {
-		.start	= AT91SAM9261_BASE_TWI,
-		.end	= AT91SAM9261_BASE_TWI + SZ_16K - 1,
-		.flags	= IORESOURCE_MEM,
-	},
-	[1] = {
-		.start	= AT91SAM9261_ID_TWI,
-		.end	= AT91SAM9261_ID_TWI,
-		.flags	= IORESOURCE_IRQ,
-	},
+static struct at91_dev_table_twi device_twi __initdata = {
+	.mmio_base	= AT91SAM9261_BASE_TWI,
+	.irq		= AT91SAM9261_ID_TWI,
+	.sda_pin 	= {AT91_PIN_PA7, AT91_PIN_PERIPH_A, 0, 0, 0},
+	.scl_pin	= {AT91_PIN_PA8, AT91_PIN_PERIPH_A, 0, 0, 0},
+	.udelay		= 2,
 };
 
-static struct platform_device at91sam9261_twi_device = {
-	.name		= "at91_i2c",
-	.id		= -1,
-	.resource	= twi_resources,
-	.num_resources	= ARRAY_SIZE(twi_resources),
-};
-
-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_PA7, 0);		/* TWD */
-	at91_set_multi_drive(AT91_PIN_PA7, 1);
-
-	at91_set_A_periph(AT91_PIN_PA8, 0);		/* TWCK */
-	at91_set_multi_drive(AT91_PIN_PA8, 1);
-
-	i2c_register_board_info(0, devices, nr_devices);
-	platform_device_register(&at91sam9261_twi_device);
-}
-#else
-void __init at91_add_device_i2c(struct i2c_board_info *devices, int nr_devices) {}
-#endif
-
-
 /* --------------------------------------------------------------------
  *  SPI
  * -------------------------------------------------------------------- */
@@ -877,6 +813,7 @@ static struct at91_device_table at91sam9261_device_table __initdata = {
 	.udc		= &device_udc,
 	.mmc[0]		= &device_mmc,
 	.nand		= &device_nand,
+	.twi[0]		= &device_twi,
 };
 
 void __init at91sam9261_init_devices(void)
diff --git a/arch/arm/mach-at91/at91sam9263_devices.c b/arch/arm/mach-at91/at91sam9263_devices.c
index 37b06f7..d0580ef 100644
--- a/arch/arm/mach-at91/at91sam9263_devices.c
+++ b/arch/arm/mach-at91/at91sam9263_devices.c
@@ -259,78 +259,14 @@ static struct at91_dev_table_nand device_nand __initdata = {
  *  TWI (i2c)
  * -------------------------------------------------------------------- */
 
-/*
- * 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_PB4,
-	.sda_is_open_drain	= 1,
-	.scl_pin		= AT91_PIN_PB5,
-	.scl_is_open_drain	= 1,
-	.udelay			= 2,		/* ~100 kHz */
-};
-
-static struct platform_device at91sam9263_twi_device = {
-	.name			= "i2c-gpio",
-	.id			= -1,
-	.dev.platform_data	= &pdata,
+static struct at91_dev_table_twi device_twi __initdata = {
+	.mmio_base	= AT91SAM9263_BASE_TWI,
+	.irq		= AT91SAM9263_ID_TWI,
+	.sda_pin 	= {AT91_PIN_PB4, AT91_PIN_PERIPH_A, 0, 0, 0},
+	.scl_pin	= {AT91_PIN_PB5, AT91_PIN_PERIPH_A, 0, 0, 0},
+	.udelay		= 2,
 };
 
-void __init at91_add_device_i2c(struct i2c_board_info *devices, int nr_devices)
-{
-	at91_set_GPIO_periph(AT91_PIN_PB4, 1);		/* TWD (SDA) */
-	at91_set_multi_drive(AT91_PIN_PB4, 1);
-
-	at91_set_GPIO_periph(AT91_PIN_PB5, 1);		/* TWCK (SCL) */
-	at91_set_multi_drive(AT91_PIN_PB5, 1);
-
-	i2c_register_board_info(0, devices, nr_devices);
-	platform_device_register(&at91sam9263_twi_device);
-}
-
-#elif defined(CONFIG_I2C_AT91) || defined(CONFIG_I2C_AT91_MODULE)
-
-static struct resource twi_resources[] = {
-	[0] = {
-		.start	= AT91SAM9263_BASE_TWI,
-		.end	= AT91SAM9263_BASE_TWI + SZ_16K - 1,
-		.flags	= IORESOURCE_MEM,
-	},
-	[1] = {
-		.start	= AT91SAM9263_ID_TWI,
-		.end	= AT91SAM9263_ID_TWI,
-		.flags	= IORESOURCE_IRQ,
-	},
-};
-
-static struct platform_device at91sam9263_twi_device = {
-	.name		= "at91_i2c",
-	.id		= -1,
-	.resource	= twi_resources,
-	.num_resources	= ARRAY_SIZE(twi_resources),
-};
-
-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_PB4, 0);		/* TWD */
-	at91_set_multi_drive(AT91_PIN_PB4, 1);
-
-	at91_set_A_periph(AT91_PIN_PB5, 0);		/* TWCK */
-	at91_set_multi_drive(AT91_PIN_PB5, 1);
-
-	i2c_register_board_info(0, devices, nr_devices);
-	platform_device_register(&at91sam9263_twi_device);
-}
-#else
-void __init at91_add_device_i2c(struct i2c_board_info *devices, int nr_devices) {}
-#endif
-
-
 /* --------------------------------------------------------------------
  *  SPI
  * -------------------------------------------------------------------- */
@@ -1172,6 +1108,7 @@ static struct at91_device_table at91sam9263_device_table __initdata = {
 	.mmc[0]		= &device_mmc0,
 	.mmc[1]		= &device_mmc1,
 	.nand		= &device_nand,
+	.twi[0]		= &device_twi,
 };
 
 void __init at91sam9263_init_devices(void)
diff --git a/arch/arm/mach-at91/at91sam9g45_devices.c b/arch/arm/mach-at91/at91sam9g45_devices.c
index 9650547..7b83b0b 100644
--- a/arch/arm/mach-at91/at91sam9g45_devices.c
+++ b/arch/arm/mach-at91/at91sam9g45_devices.c
@@ -283,132 +283,22 @@ static struct at91_dev_table_nand device_nand __initdata = {
  *  TWI (i2c)
  * -------------------------------------------------------------------- */
 
-/*
- * 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_i2c0 = {
-	.sda_pin		= AT91_PIN_PA20,
-	.sda_is_open_drain	= 1,
-	.scl_pin		= AT91_PIN_PA21,
-	.scl_is_open_drain	= 1,
-	.udelay			= 5,		/* ~100 kHz */
-};
-
-static struct platform_device at91sam9g45_twi0_device = {
-	.name			= "i2c-gpio",
-	.id			= 0,
-	.dev.platform_data	= &pdata_i2c0,
+static struct at91_dev_table_twi device_twi0 __initdata = {
+	.mmio_base	= AT91SAM9G45_BASE_TWI0,
+	.irq		= AT91SAM9G45_ID_TWI0,
+	.sda_pin 	= {AT91_PIN_PA20, AT91_PIN_PERIPH_A, 0, 0, 0},
+	.scl_pin	= {AT91_PIN_PA21, AT91_PIN_PERIPH_A, 0, 0, 0},
+	.udelay		= 5,
 };
 
-static struct i2c_gpio_platform_data pdata_i2c1 = {
-	.sda_pin		= AT91_PIN_PB10,
-	.sda_is_open_drain	= 1,
-	.scl_pin		= AT91_PIN_PB11,
-	.scl_is_open_drain	= 1,
-	.udelay			= 5,		/* ~100 kHz */
+static struct at91_dev_table_twi device_twi1 __initdata = {
+	.mmio_base	= AT91SAM9G45_BASE_TWI1,
+	.irq		= AT91SAM9G45_ID_TWI1,
+	.sda_pin 	= {AT91_PIN_PB20, AT91_PIN_PERIPH_A, 0, 0, 0},
+	.scl_pin	= {AT91_PIN_PB21, AT91_PIN_PERIPH_A, 0, 0, 0},
+	.udelay		= 5,
 };
 
-static struct platform_device at91sam9g45_twi1_device = {
-	.name			= "i2c-gpio",
-	.id			= 1,
-	.dev.platform_data	= &pdata_i2c1,
-};
-
-void __init at91_add_device_i2c(short i2c_id, struct i2c_board_info *devices, int nr_devices)
-{
-	i2c_register_board_info(i2c_id, devices, nr_devices);
-
-	if (i2c_id == 0) {
-		at91_set_GPIO_periph(AT91_PIN_PA20, 1);		/* TWD (SDA) */
-		at91_set_multi_drive(AT91_PIN_PA20, 1);
-
-		at91_set_GPIO_periph(AT91_PIN_PA21, 1);		/* TWCK (SCL) */
-		at91_set_multi_drive(AT91_PIN_PA21, 1);
-
-		platform_device_register(&at91sam9g45_twi0_device);
-	} else {
-		at91_set_GPIO_periph(AT91_PIN_PB10, 1);		/* TWD (SDA) */
-		at91_set_multi_drive(AT91_PIN_PB10, 1);
-
-		at91_set_GPIO_periph(AT91_PIN_PB11, 1);		/* TWCK (SCL) */
-		at91_set_multi_drive(AT91_PIN_PB11, 1);
-
-		platform_device_register(&at91sam9g45_twi1_device);
-	}
-}
-
-#elif defined(CONFIG_I2C_AT91) || defined(CONFIG_I2C_AT91_MODULE)
-static struct resource twi0_resources[] = {
-	[0] = {
-		.start	= AT91SAM9G45_BASE_TWI0,
-		.end	= AT91SAM9G45_BASE_TWI0 + SZ_16K - 1,
-		.flags	= IORESOURCE_MEM,
-	},
-	[1] = {
-		.start	= AT91SAM9G45_ID_TWI0,
-		.end	= AT91SAM9G45_ID_TWI0,
-		.flags	= IORESOURCE_IRQ,
-	},
-};
-
-static struct platform_device at91sam9g45_twi0_device = {
-	.name		= "at91_i2c",
-	.id		= 0,
-	.resource	= twi0_resources,
-	.num_resources	= ARRAY_SIZE(twi0_resources),
-};
-
-static struct resource twi1_resources[] = {
-	[0] = {
-		.start	= AT91SAM9G45_BASE_TWI1,
-		.end	= AT91SAM9G45_BASE_TWI1 + SZ_16K - 1,
-		.flags	= IORESOURCE_MEM,
-	},
-	[1] = {
-		.start	= AT91SAM9G45_ID_TWI1,
-		.end	= AT91SAM9G45_ID_TWI1,
-		.flags	= IORESOURCE_IRQ,
-	},
-};
-
-static struct platform_device at91sam9g45_twi1_device = {
-	.name		= "at91_i2c",
-	.id		= 1,
-	.resource	= twi1_resources,
-	.num_resources	= ARRAY_SIZE(twi1_resources),
-};
-
-void __init at91_add_device_i2c(short i2c_id, struct i2c_board_info *devices, int nr_devices)
-{
-	i2c_register_board_info(i2c_id, devices, nr_devices);
-
-	/* 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);
-	}
-}
-#else
-void __init at91_add_device_i2c(short i2c_id, struct i2c_board_info *devices, int nr_devices) {}
-#endif
-
-
 /* --------------------------------------------------------------------
  *  SPI
  * -------------------------------------------------------------------- */
@@ -1297,6 +1187,8 @@ static struct at91_device_table at91sam9g45_device_table __initdata = {
 	.mmc[0]		= &device_mmc0,
 	.mmc[1]		= &device_mmc1,
 	.nand		= &device_nand,
+	.twi[0]		= &device_twi0,
+	.twi[1]		= &device_twi1,
 };
 
 void __init at91sam9g45_init_devices(void)
diff --git a/arch/arm/mach-at91/at91sam9rl_devices.c b/arch/arm/mach-at91/at91sam9rl_devices.c
index e0b7302..2b24e7d 100644
--- a/arch/arm/mach-at91/at91sam9rl_devices.c
+++ b/arch/arm/mach-at91/at91sam9rl_devices.c
@@ -200,78 +200,14 @@ static struct at91_dev_table_nand device_nand __initdata = {
  *  TWI (i2c)
  * -------------------------------------------------------------------- */
 
-/*
- * 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,
+static struct at91_dev_table_twi device_twi __initdata = {
+	.mmio_base	= AT91SAM9RL_BASE_TWI0,
+	.irq		= AT91SAM9RL_ID_TWI0,
+	.sda_pin 	= {AT91_PIN_PA23, AT91_PIN_PERIPH_A, 0, 0, 0},
+	.scl_pin	= {AT91_PIN_PA24, AT91_PIN_PERIPH_A, 0, 0, 0},
+	.udelay		= 2,
 };
 
-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] = {
-		.start	= AT91SAM9RL_BASE_TWI0,
-		.end	= AT91SAM9RL_BASE_TWI0 + SZ_16K - 1,
-		.flags	= IORESOURCE_MEM,
-	},
-	[1] = {
-		.start	= AT91SAM9RL_ID_TWI0,
-		.end	= AT91SAM9RL_ID_TWI0,
-		.flags	= IORESOURCE_IRQ,
-	},
-};
-
-static struct platform_device at91sam9rl_twi_device = {
-	.name		= "at91_i2c",
-	.id		= -1,
-	.resource	= twi_resources,
-	.num_resources	= ARRAY_SIZE(twi_resources),
-};
-
-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 */
-	at91_set_multi_drive(AT91_PIN_PA23, 1);
-
-	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(struct i2c_board_info *devices, int nr_devices) {}
-#endif
-
-
 /* --------------------------------------------------------------------
  *  SPI
  * -------------------------------------------------------------------- */
@@ -1098,6 +1034,7 @@ void __init at91_add_device_serial(void) {}
 static struct at91_device_table at91sam9rl_device_table __initdata = {
 	.mmc[0]		= &device_mmc,
 	.nand		= &device_nand,
+	.twi[0]		= &device_twi,
 };
 
 void __init at91sam9rl_init_devices(void)
diff --git a/arch/arm/mach-at91/board-afeb-9260v1.c b/arch/arm/mach-at91/board-afeb-9260v1.c
index 88d08ae..c64b7d6 100644
--- a/arch/arm/mach-at91/board-afeb-9260v1.c
+++ b/arch/arm/mach-at91/board-afeb-9260v1.c
@@ -208,7 +208,7 @@ static void __init afeb9260_board_init(void)
 	/* MMC */
 	at91_add_device_mmc(0, &afeb9260_mmc_data);
 	/* I2C */
-	at91_add_device_i2c(afeb9260_i2c_devices,
+	at91_add_device_i2c(0, afeb9260_i2c_devices,
 			ARRAY_SIZE(afeb9260_i2c_devices));
 	/* Audio */
 	at91_add_device_ssc(AT91SAM9260_ID_SSC, ATMEL_SSC_TX);
diff --git a/arch/arm/mach-at91/board-at572d940hf_ek.c b/arch/arm/mach-at91/board-at572d940hf_ek.c
index c9ab05d..edbbce4 100644
--- a/arch/arm/mach-at91/board-at572d940hf_ek.c
+++ b/arch/arm/mach-at91/board-at572d940hf_ek.c
@@ -301,7 +301,7 @@ static void __init eb_board_init(void)
 	/* USB Device */
 	at91_add_device_udc(&eb_udc_data);
 	/* I2C */
-	at91_add_device_i2c(NULL, 0);
+	at91_add_device_i2c(0, NULL, 0);
 	/* NOR */
 	eb_add_device_nor();
 	/* NAND */
diff --git a/arch/arm/mach-at91/board-cap9adk.c b/arch/arm/mach-at91/board-cap9adk.c
index 0d60378..4fe8c55 100644
--- a/arch/arm/mach-at91/board-cap9adk.c
+++ b/arch/arm/mach-at91/board-cap9adk.c
@@ -390,7 +390,7 @@ static void __init cap9adk_board_init(void)
 	/* NOR Flash */
 	cap9adk_add_device_nor();
 	/* I2C */
-	at91_add_device_i2c(NULL, 0);
+	at91_add_device_i2c(0, NULL, 0);
 	/* LCD Controller */
 	at91_add_device_lcdc(&cap9adk_lcdc_data);
 	/* AC97 */
diff --git a/arch/arm/mach-at91/board-carmeva.c b/arch/arm/mach-at91/board-carmeva.c
index 9d007a8..b9033cb 100644
--- a/arch/arm/mach-at91/board-carmeva.c
+++ b/arch/arm/mach-at91/board-carmeva.c
@@ -149,7 +149,7 @@ static void __init carmeva_board_init(void)
 	/* USB Device */
 	at91_add_device_udc(&carmeva_udc_data);
 	/* I2C */
-	at91_add_device_i2c(NULL, 0);
+	at91_add_device_i2c(0, NULL, 0);
 	/* SPI */
 	at91_add_device_spi(carmeva_spi_devices, ARRAY_SIZE(carmeva_spi_devices));
 	/* Compact Flash */
diff --git a/arch/arm/mach-at91/board-cpu9krea.c b/arch/arm/mach-at91/board-cpu9krea.c
index 65c6513..9a88ca0 100644
--- a/arch/arm/mach-at91/board-cpu9krea.c
+++ b/arch/arm/mach-at91/board-cpu9krea.c
@@ -361,7 +361,7 @@ static void __init cpu9krea_board_init(void)
 	/* MMC */
 	at91_add_device_mmc(0, &cpu9krea_mmc_data);
 	/* I2C */
-	at91_add_device_i2c(cpu9krea_i2c_devices,
+	at91_add_device_i2c(0, cpu9krea_i2c_devices,
 		ARRAY_SIZE(cpu9krea_i2c_devices));
 	/* LEDs */
 	at91_gpio_leds(cpu9krea_leds, ARRAY_SIZE(cpu9krea_leds));
diff --git a/arch/arm/mach-at91/board-cpuat91.c b/arch/arm/mach-at91/board-cpuat91.c
index ce3525d..fbdd54b 100644
--- a/arch/arm/mach-at91/board-cpuat91.c
+++ b/arch/arm/mach-at91/board-cpuat91.c
@@ -168,7 +168,7 @@ static void __init cpuat91_board_init(void)
 	/* MMC */
 	at91_add_device_mmc(0, &cpuat91_mmc_data);
 	/* I2C */
-	at91_add_device_i2c(NULL, 0);
+	at91_add_device_i2c(0, NULL, 0);
 	/* Platform devices */
 	platform_add_devices(platform_devices, ARRAY_SIZE(platform_devices));
 }
diff --git a/arch/arm/mach-at91/board-csb337.c b/arch/arm/mach-at91/board-csb337.c
index ff7b8c0..f611720 100644
--- a/arch/arm/mach-at91/board-csb337.c
+++ b/arch/arm/mach-at91/board-csb337.c
@@ -239,7 +239,7 @@ static void __init csb337_board_init(void)
 	/* USB Device */
 	at91_add_device_udc(&csb337_udc_data);
 	/* I2C */
-	at91_add_device_i2c(csb337_i2c_devices, ARRAY_SIZE(csb337_i2c_devices));
+	at91_add_device_i2c(0, csb337_i2c_devices, ARRAY_SIZE(csb337_i2c_devices));
 	/* Compact Flash */
 	at91_set_gpio_input(AT91_PIN_PB22, 1);		/* IOIS16 */
 	at91_add_device_cf(&csb337_cf_data);
diff --git a/arch/arm/mach-at91/board-csb637.c b/arch/arm/mach-at91/board-csb637.c
index 74d5b7e..bc26bf7 100644
--- a/arch/arm/mach-at91/board-csb637.c
+++ b/arch/arm/mach-at91/board-csb637.c
@@ -129,7 +129,7 @@ static void __init csb637_board_init(void)
 	/* USB Device */
 	at91_add_device_udc(&csb637_udc_data);
 	/* I2C */
-	at91_add_device_i2c(NULL, 0);
+	at91_add_device_i2c(0, NULL, 0);
 	/* SPI */
 	at91_add_device_spi(NULL, 0);
 	/* NOR flash */
diff --git a/arch/arm/mach-at91/board-eb9200.c b/arch/arm/mach-at91/board-eb9200.c
index 3705082..eed4d6c 100644
--- a/arch/arm/mach-at91/board-eb9200.c
+++ b/arch/arm/mach-at91/board-eb9200.c
@@ -109,7 +109,7 @@ static void __init eb9200_board_init(void)
 	/* USB Device */
 	at91_add_device_udc(&eb9200_udc_data);
 	/* I2C */
-	at91_add_device_i2c(eb9200_i2c_devices, ARRAY_SIZE(eb9200_i2c_devices));
+	at91_add_device_i2c(0, eb9200_i2c_devices, ARRAY_SIZE(eb9200_i2c_devices));
 	/* Compact Flash */
 	at91_add_device_cf(&eb9200_cf_data);
 	/* SPI */
diff --git a/arch/arm/mach-at91/board-ecbat91.c b/arch/arm/mach-at91/board-ecbat91.c
index df4a07f..b730b01 100644
--- a/arch/arm/mach-at91/board-ecbat91.c
+++ b/arch/arm/mach-at91/board-ecbat91.c
@@ -157,7 +157,7 @@ static void __init ecb_at91board_init(void)
 	at91_add_device_usbh_ohci(&ecb_at91usbh_data);
 
 	/* I2C */
-	at91_add_device_i2c(NULL, 0);
+	at91_add_device_i2c(0, NULL, 0);
 
 	/* MMC */
 	at91_add_device_mmc(0, &ecb_at91mmc_data);
diff --git a/arch/arm/mach-at91/board-foxg20.c b/arch/arm/mach-at91/board-foxg20.c
index 6688ec2..79c54fc 100644
--- a/arch/arm/mach-at91/board-foxg20.c
+++ b/arch/arm/mach-at91/board-foxg20.c
@@ -254,7 +254,7 @@ static void __init foxg20_board_init(void)
 	/* MMC */
 	at91_add_device_mmc(0, &foxg20_mmc_data);
 	/* I2C */
-	at91_add_device_i2c(foxg20_i2c_devices, ARRAY_SIZE(foxg20_i2c_devices));
+	at91_add_device_i2c(0, foxg20_i2c_devices, ARRAY_SIZE(foxg20_i2c_devices));
 	/* LEDs */
 	at91_gpio_leds(foxg20_leds, ARRAY_SIZE(foxg20_leds));
 	/* Push Buttons */
diff --git a/arch/arm/mach-at91/board-gsia18s.c b/arch/arm/mach-at91/board-gsia18s.c
index 8b1d498..e32833d 100644
--- a/arch/arm/mach-at91/board-gsia18s.c
+++ b/arch/arm/mach-at91/board-gsia18s.c
@@ -567,7 +567,7 @@ static void __init gsia18s_board_init(void)
 	gsia18s_leds_init();
 	gsia18s_pcf_leds_init();
 	gsia18s_add_device_buttons();
-	at91_add_device_i2c(gsia18s_i2c_devices,
+	at91_add_device_i2c(0, gsia18s_i2c_devices,
 				ARRAY_SIZE(gsia18s_i2c_devices));
 	at91_add_device_cf(&gsia18s_cf1_data);
 	at91_add_device_spi(gsia18s_spi_devices,
diff --git a/arch/arm/mach-at91/board-kafa.c b/arch/arm/mach-at91/board-kafa.c
index a0cac24..1edff1b 100644
--- a/arch/arm/mach-at91/board-kafa.c
+++ b/arch/arm/mach-at91/board-kafa.c
@@ -87,7 +87,7 @@ static void __init kafa_board_init(void)
 	/* USB Device */
 	at91_add_device_udc(&kafa_udc_data);
 	/* I2C */
-	at91_add_device_i2c(NULL, 0);
+	at91_add_device_i2c(0, NULL, 0);
 	/* SPI */
 	at91_add_device_spi(NULL, 0);
 }
diff --git a/arch/arm/mach-at91/board-kb9202.c b/arch/arm/mach-at91/board-kb9202.c
index 59eafa2..682e9f4 100644
--- a/arch/arm/mach-at91/board-kb9202.c
+++ b/arch/arm/mach-at91/board-kb9202.c
@@ -127,7 +127,7 @@ static void __init kb9202_board_init(void)
 	/* MMC */
 	at91_add_device_mmc(0, &kb9202_mmc_data);
 	/* I2C */
-	at91_add_device_i2c(NULL, 0);
+	at91_add_device_i2c(0, NULL, 0);
 	/* SPI */
 	at91_add_device_spi(NULL, 0);
 	/* NAND */
diff --git a/arch/arm/mach-at91/board-neocore926.c b/arch/arm/mach-at91/board-neocore926.c
index bffbbdf..f2c79fb 100644
--- a/arch/arm/mach-at91/board-neocore926.c
+++ b/arch/arm/mach-at91/board-neocore926.c
@@ -373,7 +373,7 @@ static void __init neocore926_board_init(void)
 	neocore926_add_device_nand();
 
 	/* I2C */
-	at91_add_device_i2c(NULL, 0);
+	at91_add_device_i2c(0, NULL, 0);
 
 	/* LCD Controller */
 	at91_add_device_lcdc(&neocore926_lcdc_data);
diff --git a/arch/arm/mach-at91/board-pcontrol-g20.c b/arch/arm/mach-at91/board-pcontrol-g20.c
index 4c5848d..ad9cc28 100644
--- a/arch/arm/mach-at91/board-pcontrol-g20.c
+++ b/arch/arm/mach-at91/board-pcontrol-g20.c
@@ -207,7 +207,7 @@ static void __init pcontrol_g20_board_init(void)
 	stamp9g20_board_init();
 	at91_add_device_usbh_ohci(&usbh_data);
 	at91_add_device_eth(&macb_data);
-	at91_add_device_i2c(pcontrol_g20_i2c_devices,
+	at91_add_device_i2c(0, pcontrol_g20_i2c_devices,
 		ARRAY_SIZE(pcontrol_g20_i2c_devices));
 	add_device_pcontrol();
 	at91_add_device_spi(pcontrol_g20_spi_devices,
diff --git a/arch/arm/mach-at91/board-picotux200.c b/arch/arm/mach-at91/board-picotux200.c
index 419456d..2b0958b 100644
--- a/arch/arm/mach-at91/board-picotux200.c
+++ b/arch/arm/mach-at91/board-picotux200.c
@@ -113,7 +113,7 @@ static void __init picotux200_board_init(void)
 	/* USB Host */
 	at91_add_device_usbh_ohci(&picotux200_usbh_data);
 	/* I2C */
-	at91_add_device_i2c(NULL, 0);
+	at91_add_device_i2c(0, NULL, 0);
 	/* MMC */
 	at91_set_gpio_output(AT91_PIN_PB22, 1);	/* this MMC card slot can optionally use SPI signaling (CS3). */
 	at91_add_device_mmc(0, &picotux200_mmc_data);
diff --git a/arch/arm/mach-at91/board-qil-a9260.c b/arch/arm/mach-at91/board-qil-a9260.c
index 255a984..c00b292 100644
--- a/arch/arm/mach-at91/board-qil-a9260.c
+++ b/arch/arm/mach-at91/board-qil-a9260.c
@@ -252,7 +252,7 @@ static void __init ek_board_init(void)
 	/* NAND */
 	ek_add_device_nand();
 	/* I2C */
-	at91_add_device_i2c(NULL, 0);
+	at91_add_device_i2c(0, NULL, 0);
 	/* Ethernet */
 	at91_add_device_eth(&ek_macb_data);
 	/* MMC */
diff --git a/arch/arm/mach-at91/board-rm9200dk.c b/arch/arm/mach-at91/board-rm9200dk.c
index 3d54963..746b6ea 100644
--- a/arch/arm/mach-at91/board-rm9200dk.c
+++ b/arch/arm/mach-at91/board-rm9200dk.c
@@ -204,7 +204,7 @@ static void __init dk_board_init(void)
 	/* Compact Flash */
 	at91_add_device_cf(&dk_cf_data);
 	/* I2C */
-	at91_add_device_i2c(dk_i2c_devices, ARRAY_SIZE(dk_i2c_devices));
+	at91_add_device_i2c(0, dk_i2c_devices, ARRAY_SIZE(dk_i2c_devices));
 	/* SPI */
 	at91_add_device_spi(dk_spi_devices, ARRAY_SIZE(dk_spi_devices));
 #ifdef CONFIG_MTD_AT91_DATAFLASH_CARD
diff --git a/arch/arm/mach-at91/board-rm9200ek.c b/arch/arm/mach-at91/board-rm9200ek.c
index 25fe19f..5e1dca0 100644
--- a/arch/arm/mach-at91/board-rm9200ek.c
+++ b/arch/arm/mach-at91/board-rm9200ek.c
@@ -172,7 +172,7 @@ static void __init ek_board_init(void)
 	at91_add_device_udc(&ek_udc_data);
 	at91_set_multi_drive(ek_udc_data.pullup_pin, 1);	/* pullup_pin is connected to reset */
 	/* I2C */
-	at91_add_device_i2c(ek_i2c_devices, ARRAY_SIZE(ek_i2c_devices));
+	at91_add_device_i2c(0, ek_i2c_devices, ARRAY_SIZE(ek_i2c_devices));
 	/* SPI */
 	at91_add_device_spi(ek_spi_devices, ARRAY_SIZE(ek_spi_devices));
 #ifdef CONFIG_MTD_AT91_DATAFLASH_CARD
diff --git a/arch/arm/mach-at91/board-sam9-l9260.c b/arch/arm/mach-at91/board-sam9-l9260.c
index 589e2f4..bc62008 100644
--- a/arch/arm/mach-at91/board-sam9-l9260.c
+++ b/arch/arm/mach-at91/board-sam9-l9260.c
@@ -207,7 +207,7 @@ static void __init ek_board_init(void)
 	/* MMC */
 	at91_add_device_mmc(0, &ek_mmc_data);
 	/* I2C */
-	at91_add_device_i2c(NULL, 0);
+	at91_add_device_i2c(0, NULL, 0);
 }
 
 MACHINE_START(SAM9_L9260, "Olimex SAM9-L9260")
diff --git a/arch/arm/mach-at91/board-sam9260ek.c b/arch/arm/mach-at91/board-sam9260ek.c
index b98e766..c8c53ac 100644
--- a/arch/arm/mach-at91/board-sam9260ek.c
+++ b/arch/arm/mach-at91/board-sam9260ek.c
@@ -344,7 +344,7 @@ static void __init ek_board_init(void)
 	/* MMC */
 	at91_add_device_mmc(0, &ek_mmc_data);
 	/* I2C */
-	at91_add_device_i2c(ek_i2c_devices, ARRAY_SIZE(ek_i2c_devices));
+	at91_add_device_i2c(0, ek_i2c_devices, ARRAY_SIZE(ek_i2c_devices));
 	/* SSC (to AT73C213) */
 	at73c213_set_clk(&at73c213_data);
 	at91_add_device_ssc(AT91SAM9260_ID_SSC, ATMEL_SSC_TX);
diff --git a/arch/arm/mach-at91/board-sam9261ek.c b/arch/arm/mach-at91/board-sam9261ek.c
index e631172..3e848ba 100644
--- a/arch/arm/mach-at91/board-sam9261ek.c
+++ b/arch/arm/mach-at91/board-sam9261ek.c
@@ -590,7 +590,7 @@ static void __init ek_board_init(void)
 	/* USB Device */
 	at91_add_device_udc(&ek_udc_data);
 	/* I2C */
-	at91_add_device_i2c(NULL, 0);
+	at91_add_device_i2c(0, NULL, 0);
 	/* NAND */
 	ek_add_device_nand();
 	/* DM9000 ethernet */
diff --git a/arch/arm/mach-at91/board-sam9263ek.c b/arch/arm/mach-at91/board-sam9263ek.c
index fae6ebf..5e1aac1 100644
--- a/arch/arm/mach-at91/board-sam9263ek.c
+++ b/arch/arm/mach-at91/board-sam9263ek.c
@@ -438,7 +438,7 @@ static void __init ek_board_init(void)
 	/* NAND */
 	ek_add_device_nand();
 	/* I2C */
-	at91_add_device_i2c(ek_i2c_devices, ARRAY_SIZE(ek_i2c_devices));
+	at91_add_device_i2c(0, ek_i2c_devices, ARRAY_SIZE(ek_i2c_devices));
 	/* LCD Controller */
 	at91_add_device_lcdc(&ek_lcdc_data);
 	/* Push Buttons */
diff --git a/arch/arm/mach-at91/board-sam9g20ek.c b/arch/arm/mach-at91/board-sam9g20ek.c
index c25e44c..3dd5013 100644
--- a/arch/arm/mach-at91/board-sam9g20ek.c
+++ b/arch/arm/mach-at91/board-sam9g20ek.c
@@ -393,7 +393,7 @@ static void __init ek_board_init(void)
 	/* MMC */
 	ek_add_device_mmc();
 	/* I2C */
-	at91_add_device_i2c(ek_i2c_devices, ARRAY_SIZE(ek_i2c_devices));
+	at91_add_device_i2c(0, ek_i2c_devices, ARRAY_SIZE(ek_i2c_devices));
 	/* LEDs */
 	ek_add_device_gpio_leds();
 	/* Push Buttons */
diff --git a/arch/arm/mach-at91/board-sam9rlek.c b/arch/arm/mach-at91/board-sam9rlek.c
index 3bf3408..475b485 100644
--- a/arch/arm/mach-at91/board-sam9rlek.c
+++ b/arch/arm/mach-at91/board-sam9rlek.c
@@ -308,7 +308,7 @@ static void __init ek_board_init(void)
 	/* USB HS */
 	at91_add_device_usba(&ek_usba_udc_data);
 	/* I2C */
-	at91_add_device_i2c(NULL, 0);
+	at91_add_device_i2c(0, NULL, 0);
 	/* NAND */
 	ek_add_device_nand();
 	/* SPI */
diff --git a/arch/arm/mach-at91/board-snapper9260.c b/arch/arm/mach-at91/board-snapper9260.c
index ca14290..e93a11b 100644
--- a/arch/arm/mach-at91/board-snapper9260.c
+++ b/arch/arm/mach-at91/board-snapper9260.c
@@ -166,7 +166,7 @@ static void __init snapper9260_add_device_nand(void)
 
 static void __init snapper9260_board_init(void)
 {
-	at91_add_device_i2c(snapper9260_i2c_devices,
+	at91_add_device_i2c(0, snapper9260_i2c_devices,
 			    ARRAY_SIZE(snapper9260_i2c_devices));
 	at91_add_device_serial();
 	at91_add_device_usbh_ohci(&snapper9260_usbh_data);
diff --git a/arch/arm/mach-at91/board-stamp9g20.c b/arch/arm/mach-at91/board-stamp9g20.c
index 1e7a73a..9b7f333 100644
--- a/arch/arm/mach-at91/board-stamp9g20.c
+++ b/arch/arm/mach-at91/board-stamp9g20.c
@@ -274,7 +274,7 @@ static void __init portuxg20_board_init(void)
 	/* Ethernet */
 	at91_add_device_eth(&macb_data);
 	/* I2C */
-	at91_add_device_i2c(NULL, 0);
+	at91_add_device_i2c(0, NULL, 0);
 	/* SPI */
 	at91_add_device_spi(portuxg20_spi_devices, ARRAY_SIZE(portuxg20_spi_devices));
 	/* LEDs */
@@ -291,7 +291,7 @@ static void __init stamp9g20evb_board_init(void)
 	/* Ethernet */
 	at91_add_device_eth(&macb_data);
 	/* I2C */
-	at91_add_device_i2c(NULL, 0);
+	at91_add_device_i2c(0, NULL, 0);
 	/* LEDs */
 	at91_gpio_leds(stamp9g20evb_leds, ARRAY_SIZE(stamp9g20evb_leds));
 }
diff --git a/arch/arm/mach-at91/board-usb-a9260.c b/arch/arm/mach-at91/board-usb-a9260.c
index 9b5cbf5..8c3bbde 100644
--- a/arch/arm/mach-at91/board-usb-a9260.c
+++ b/arch/arm/mach-at91/board-usb-a9260.c
@@ -214,7 +214,7 @@ static void __init ek_board_init(void)
 	/* NAND */
 	ek_add_device_nand();
 	/* I2C */
-	at91_add_device_i2c(NULL, 0);
+	at91_add_device_i2c(0, NULL, 0);
 	/* Ethernet */
 	at91_add_device_eth(&ek_macb_data);
 	/* Push Buttons */
diff --git a/arch/arm/mach-at91/board-usb-a9263.c b/arch/arm/mach-at91/board-usb-a9263.c
index 535af00..6e9f2ef 100644
--- a/arch/arm/mach-at91/board-usb-a9263.c
+++ b/arch/arm/mach-at91/board-usb-a9263.c
@@ -232,7 +232,7 @@ static void __init ek_board_init(void)
 	/* NAND */
 	ek_add_device_nand();
 	/* I2C */
-	at91_add_device_i2c(NULL, 0);
+	at91_add_device_i2c(0, NULL, 0);
 	/* Push Buttons */
 	ek_add_device_buttons();
 	/* LEDs */
diff --git a/arch/arm/mach-at91/board-yl-9200.c b/arch/arm/mach-at91/board-yl-9200.c
index bd5ebfd..ef80db1 100644
--- a/arch/arm/mach-at91/board-yl-9200.c
+++ b/arch/arm/mach-at91/board-yl-9200.c
@@ -571,7 +571,7 @@ static void __init yl9200_board_init(void)
 	/* USB Device */
 	at91_add_device_udc(&yl9200_udc_data);
 	/* I2C */
-	at91_add_device_i2c(yl9200_i2c_devices, ARRAY_SIZE(yl9200_i2c_devices));
+	at91_add_device_i2c(0, yl9200_i2c_devices, ARRAY_SIZE(yl9200_i2c_devices));
 	/* MMC */
 	at91_add_device_mmc(0, &yl9200_mmc_data);
 	/* NAND */
diff --git a/arch/arm/mach-at91/devices.c b/arch/arm/mach-at91/devices.c
index 8c70529..93eb8bd 100644
--- a/arch/arm/mach-at91/devices.c
+++ b/arch/arm/mach-at91/devices.c
@@ -17,6 +17,7 @@
 #include <linux/dma-mapping.h>
 #include <linux/interrupt.h>
 #include <linux/gpio.h>
+#include <linux/i2c-gpio.h>
 
 #include <mach/cpu.h>
 #include <mach/board.h>
@@ -607,6 +608,127 @@ void __init at91_add_device_nand(struct atmel_nand_data *data)
 void __init at91_add_device_nand(struct atmel_nand_data *data) {}
 #endif
 
+/* --------------------------------------------------------------------
+ *  TWI (i2c)
+ * -------------------------------------------------------------------- */
+
+/*
+ * 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 i2c_gpio_pdata = {
+	.sda_is_open_drain	= 1,
+	.scl_is_open_drain	= 1,
+};
+
+static struct platform_device at91_twi_device = {
+	.name			= "i2c-gpio",
+	.id			= -1,
+	.dev.platform_data	= &i2c_gpio_pdata,
+};
+
+void __init at91_add_device_i2c(short i2c_id,
+				struct i2c_board_info *i2c_devices,
+				int nr_devices)
+{
+	struct at91_dev_table_twi *info;
+
+	BUG_ON(i2c_id < 0 || i2c_id >= ARRAY_SIZE(devices->twi));
+	info = devices->twi[i2c_id];
+	BUG_ON(!info);
+
+	/* TWD (SDA) */
+	i2c_gpio_pdata.sda_pin = info->sda_pin.pin;
+	at91_set_GPIO_periph(info->sda_pin.pin, 1);
+	at91_set_multi_drive(info->sda_pin.pin, 1);
+
+	/* TWCK (SCL) */
+	i2c_gpio_pdata.scl_pin = info->scl_pin.pin;
+	at91_set_GPIO_periph(info->scl_pin.pin, 1);
+	at91_set_multi_drive(info->scl_pin.pin, 1);
+
+	i2c_register_board_info(i2c_id, i2c_devices, nr_devices);
+	platform_device_register(&at91_twi_device);
+}
+
+#elif defined(CONFIG_I2C_AT91) || defined(CONFIG_I2C_AT91_MODULE)
+
+static struct resource twi0_resources[] = {
+	[0] = {
+		.end	= SZ_16K,
+		.flags	= IORESOURCE_MEM,
+	},
+	[1] = {
+		.flags	= IORESOURCE_IRQ,
+	},
+};
+
+static struct platform_device at91_twi0_device = {
+	.name		= "at91_i2c",
+	.id		= 0,
+	.resource	= twi0_resources,
+	.num_resources	= ARRAY_SIZE(twi0_resources),
+};
+
+static struct resource twi1_resources[] = {
+	[0] = {
+		.end	= SZ_16K,
+		.flags	= IORESOURCE_MEM,
+	},
+	[1] = {
+		.flags	= IORESOURCE_IRQ,
+	},
+};
+
+static struct platform_device at91_twi1_device = {
+	.name		= "at91_i2c",
+	.id		= 1,
+	.resource	= twi1_resources,
+	.num_resources	= ARRAY_SIZE(twi1_resources),
+};
+
+void __init at91_add_device_i2c(short i2c_id,
+				struct i2c_board_info *i2c_devices,
+				int nr_devices)
+{
+	struct at91_dev_table_twi *info;
+
+	BUG_ON(i2c_id < 0 || i2c_id >= ARRAY_SIZE(devices->twi));
+	info = devices->twi[i2c_id]
+	BUG_ON(!info);
+
+	if (i2c_id == 0) {
+		init_resource_mem(&twi0_resources[0], info->mmio_base);
+		init_resource_irq(&twi0_resources[1], info->irq);
+	} else {
+		init_resource_mem(&twi1_resources[0], info->mmio_base);
+		init_resource_irq(&twi1_resources[1], info->irq);
+	}
+
+	/* TWD */
+	config_pins(&info->pin_sda, 1);
+	at91_set_multi_drive(info->pin_sda, 1);
+
+	/* TWCK */
+	config_pins(&info->pin_scl, 1);
+	at91_set_multi_drive(info->pin_scl, 1);
+
+	i2c_register_board_info(i2c_id, i2c_devices, nr_devices);
+	if (i2c_id == 0)
+		platform_device_register(&at91_twi0_device);
+	else
+		platform_device_register(&at91_twi1_device);
+}
+#else
+void __init at91_add_device_i2c(short i2c_id,
+				struct i2c_board_info *i2c_devices,
+				int nr_devices) {}
+#endif
+
 void __init at91_init_devices(struct at91_device_table *device_table)
 {
 	devices = device_table;
diff --git a/arch/arm/mach-at91/devices.h b/arch/arm/mach-at91/devices.h
index 3e9ec54..9b99be2 100644
--- a/arch/arm/mach-at91/devices.h
+++ b/arch/arm/mach-at91/devices.h
@@ -73,6 +73,14 @@ struct at91_dev_table_nand {
 	int			nr_pins;
 };
 
+struct at91_dev_table_twi {
+	unsigned		mmio_base;
+	int			irq;
+	struct at91_pin_config	scl_pin;
+	struct at91_pin_config	sda_pin;
+	int			udelay;		/* For i2c-gpio */
+};
+
 struct at91_device_table {
 	struct at91_dev_table_ethernet		*ethernet;
 	struct at91_dev_table_usb_ohci		*usbh_ohci;
@@ -80,6 +88,7 @@ struct at91_device_table {
 	struct at91_dev_table_basic_device	*udc;
 	struct at91_dev_table_mmc		*mmc[2];
 	struct at91_dev_table_nand		*nand;
+	struct at91_dev_table_twi		*twi[2];
 };
 
 extern void __init at91_init_devices(struct at91_device_table *device_table);
diff --git a/arch/arm/mach-at91/include/mach/board.h b/arch/arm/mach-at91/include/mach/board.h
index dd0855d..94232a4 100644
--- a/arch/arm/mach-at91/include/mach/board.h
+++ b/arch/arm/mach-at91/include/mach/board.h
@@ -116,11 +116,7 @@ struct atmel_nand_data {
 extern void __init at91_add_device_nand(struct atmel_nand_data *data);
 
  /* I2C*/
-#if defined(CONFIG_ARCH_AT91SAM9G45)
 extern void __init at91_add_device_i2c(short i2c_id, struct i2c_board_info *devices, int nr_devices);
-#else
-extern void __init at91_add_device_i2c(struct i2c_board_info *devices, int nr_devices);
-#endif
 
  /* SPI */
 extern void __init at91_add_device_spi(struct spi_board_info *devices, int nr_devices);
-- 
1.7.0.4




More information about the linux-arm-kernel mailing list