From: Andrew Victor Date: Mon, 19 Nov 2007 12:47:20 +0000 (+0100) Subject: [ARM] 4650/1: AT91: New-style init of I2C, support for i2c-gpio X-Git-Tag: v2.6.24-rc4~19^2^2~2 X-Git-Url: https://err.no/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=f230d3f53d72d05bcb5666ab7e2eccd49c8b3a15;p=linux-2.6 [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 Signed-off-by: Andrew Victor Signed-off-by: Russell King --- diff --git a/arch/arm/mach-at91/at91rm9200_devices.c b/arch/arm/mach-at91/at91rm9200_devices.c index 0417c165d5..9296833f91 100644 --- a/arch/arm/mach-at91/at91rm9200_devices.c +++ b/arch/arm/mach-at91/at91rm9200_devices.c @@ -14,6 +14,7 @@ #include #include +#include #include #include @@ -435,7 +436,40 @@ void __init at91_add_device_nand(struct at91_nand_data *data) {} * 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_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] = { @@ -457,7 +491,7 @@ static struct platform_device at91rm9200_twi_device = { .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_PA25, 0); /* TWD */ @@ -466,10 +500,11 @@ void __init at91_add_device_i2c(void) 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(void) {} +void __init at91_add_device_i2c(struct i2c_board_info *devices, int nr_devices) {} #endif diff --git a/arch/arm/mach-at91/at91sam9260_devices.c b/arch/arm/mach-at91/at91sam9260_devices.c index ffd3154c1e..3091bf47d8 100644 --- a/arch/arm/mach-at91/at91sam9260_devices.c +++ b/arch/arm/mach-at91/at91sam9260_devices.c @@ -13,6 +13,7 @@ #include #include +#include #include #include @@ -352,7 +353,41 @@ void __init at91_add_device_nand(struct at91_nand_data *data) {} * 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 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] = { @@ -374,7 +409,7 @@ static struct platform_device at91sam9260_twi_device = { .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 */ @@ -383,10 +418,11 @@ void __init at91_add_device_i2c(void) 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(void) {} +void __init at91_add_device_i2c(struct i2c_board_info *devices, int nr_devices) {} #endif diff --git a/arch/arm/mach-at91/at91sam9261_devices.c b/arch/arm/mach-at91/at91sam9261_devices.c index 3576595b49..64979a9023 100644 --- a/arch/arm/mach-at91/at91sam9261_devices.c +++ b/arch/arm/mach-at91/at91sam9261_devices.c @@ -14,7 +14,9 @@ #include #include +#include +#include #include