Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

i2c: iop: Use GPIO descriptors

The IOP3xx has some elaborate code to directly slam the
GPIO lines multiplexed with I2C down low before enablement,
apparently a workaround for a hardware bug found in the
early chips.

After consulting the developer documentation for IOP80321
and IOP80331 I can clearly see that this may be useful for
IOP80321 family (mach-iop32x) but it is highly dubious for
any 80331 series or later chip: in these chips the lines
are not multiplexed for UARTs.

We convert the code to pass optional GPIO descriptors
and register these only on the 80321-based boards where
it makes sense, optionally obtain them in the driver and
use the gpiod_set_raw_value() to ascertain the line gets
driven low when needed.

The GPIO driver does not give the GPIO chip a reasonable
label so the patch also adds that so that these machine
descriptor tables can be used.

Signed-off-by: Linus Walleij <linus.walleij@linaro.org>
Acked-by: Arnd Bergmann <arnd@arndb.de>
Acked-by: Dan Williams <dan.j.williams@intel.com>
Signed-off-by: Wolfram Sang <wsa@the-dreams.de>

authored by

Linus Walleij and committed by
Wolfram Sang
fdb7e884 ed7357c9

+64 -11
+2
arch/arm/include/asm/hardware/iop3xx.h
··· 305 305 extern struct platform_device iop3xx_aau_channel; 306 306 extern struct platform_device iop3xx_i2c0_device; 307 307 extern struct platform_device iop3xx_i2c1_device; 308 + extern struct gpiod_lookup_table iop3xx_i2c0_gpio_lookup; 309 + extern struct gpiod_lookup_table iop3xx_i2c1_gpio_lookup; 308 310 309 311 #endif 310 312
+3
arch/arm/mach-iop32x/em7210.c
··· 24 24 #include <linux/platform_device.h> 25 25 #include <linux/i2c.h> 26 26 #include <linux/gpio.h> 27 + #include <linux/gpio/machine.h> 27 28 #include <mach/hardware.h> 28 29 #include <linux/io.h> 29 30 #include <linux/irq.h> ··· 212 211 { 213 212 register_iop32x_gpio(); 214 213 platform_device_register(&em7210_serial_device); 214 + gpiod_add_lookup_table(&iop3xx_i2c0_gpio_lookup); 215 + gpiod_add_lookup_table(&iop3xx_i2c1_gpio_lookup); 215 216 platform_device_register(&iop3xx_i2c0_device); 216 217 platform_device_register(&iop3xx_i2c1_device); 217 218 platform_device_register(&em7210_flash_device);
+3
arch/arm/mach-iop32x/glantank.c
··· 25 25 #include <linux/i2c.h> 26 26 #include <linux/platform_device.h> 27 27 #include <linux/io.h> 28 + #include <linux/gpio/machine.h> 28 29 #include <mach/hardware.h> 29 30 #include <asm/irq.h> 30 31 #include <asm/mach/arch.h> ··· 190 189 static void __init glantank_init_machine(void) 191 190 { 192 191 register_iop32x_gpio(); 192 + gpiod_add_lookup_table(&iop3xx_i2c0_gpio_lookup); 193 + gpiod_add_lookup_table(&iop3xx_i2c1_gpio_lookup); 193 194 platform_device_register(&iop3xx_i2c0_device); 194 195 platform_device_register(&iop3xx_i2c1_device); 195 196 platform_device_register(&glantank_flash_device);
+3
arch/arm/mach-iop32x/iq31244.c
··· 26 26 #include <linux/mtd/physmap.h> 27 27 #include <linux/platform_device.h> 28 28 #include <linux/io.h> 29 + #include <linux/gpio/machine.h> 29 30 #include <mach/hardware.h> 30 31 #include <asm/cputype.h> 31 32 #include <asm/irq.h> ··· 286 285 static void __init iq31244_init_machine(void) 287 286 { 288 287 register_iop32x_gpio(); 288 + gpiod_add_lookup_table(&iop3xx_i2c0_gpio_lookup); 289 + gpiod_add_lookup_table(&iop3xx_i2c1_gpio_lookup); 289 290 platform_device_register(&iop3xx_i2c0_device); 290 291 platform_device_register(&iop3xx_i2c1_device); 291 292 platform_device_register(&iq31244_flash_device);
+3
arch/arm/mach-iop32x/iq80321.c
··· 23 23 #include <linux/mtd/physmap.h> 24 24 #include <linux/platform_device.h> 25 25 #include <linux/io.h> 26 + #include <linux/gpio/machine.h> 26 27 #include <mach/hardware.h> 27 28 #include <asm/irq.h> 28 29 #include <asm/mach/arch.h> ··· 173 172 static void __init iq80321_init_machine(void) 174 173 { 175 174 register_iop32x_gpio(); 175 + gpiod_add_lookup_table(&iop3xx_i2c0_gpio_lookup); 176 + gpiod_add_lookup_table(&iop3xx_i2c1_gpio_lookup); 176 177 platform_device_register(&iop3xx_i2c0_device); 177 178 platform_device_register(&iop3xx_i2c1_device); 178 179 platform_device_register(&iq80321_flash_device);
+2
arch/arm/mach-iop32x/n2100.c
··· 31 31 #include <linux/reboot.h> 32 32 #include <linux/io.h> 33 33 #include <linux/gpio.h> 34 + #include <linux/gpio/machine.h> 34 35 #include <mach/hardware.h> 35 36 #include <asm/irq.h> 36 37 #include <asm/mach/arch.h> ··· 346 345 static void __init n2100_init_machine(void) 347 346 { 348 347 register_iop32x_gpio(); 348 + gpiod_add_lookup_table(&iop3xx_i2c0_gpio_lookup); 349 349 platform_device_register(&iop3xx_i2c0_device); 350 350 platform_device_register(&n2100_flash_device); 351 351 platform_device_register(&n2100_serial_device);
+24
arch/arm/plat-iop/i2c.c
··· 19 19 #include <linux/tty.h> 20 20 #include <linux/serial_core.h> 21 21 #include <linux/io.h> 22 + #include <linux/gpio/machine.h> 22 23 #include <asm/pgtable.h> 23 24 #include <asm/page.h> 24 25 #include <asm/mach/map.h> ··· 37 36 #define IRQ_IOP3XX_I2C_0 IRQ_IOP33X_I2C_0 38 37 #define IRQ_IOP3XX_I2C_1 IRQ_IOP33X_I2C_1 39 38 #endif 39 + 40 + /* 41 + * Each of the I2C busses have corresponding GPIO lines, and the driver 42 + * need to access these directly to drive the bus low at times. 43 + */ 44 + 45 + struct gpiod_lookup_table iop3xx_i2c0_gpio_lookup = { 46 + .dev_id = "IOP3xx-I2C.0", 47 + .table = { 48 + GPIO_LOOKUP("gpio-iop", 7, "scl", GPIO_ACTIVE_HIGH), 49 + GPIO_LOOKUP("gpio-iop", 6, "sda", GPIO_ACTIVE_HIGH), 50 + { } 51 + }, 52 + }; 53 + 54 + struct gpiod_lookup_table iop3xx_i2c1_gpio_lookup = { 55 + .dev_id = "IOP3xx-I2C.1", 56 + .table = { 57 + GPIO_LOOKUP("gpio-iop", 5, "scl", GPIO_ACTIVE_HIGH), 58 + GPIO_LOOKUP("gpio-iop", 4, "sda", GPIO_ACTIVE_HIGH), 59 + { } 60 + }, 61 + }; 40 62 41 63 static struct resource iop3xx_i2c0_resources[] = { 42 64 [0] = {
+1
drivers/gpio/gpio-iop.c
··· 40 40 41 41 gc->base = 0; 42 42 gc->owner = THIS_MODULE; 43 + gc->label = "gpio-iop"; 43 44 44 45 return devm_gpiochip_add_data(&pdev->dev, gc, NULL); 45 46 }
+21 -11
drivers/i2c/busses/i2c-iop3xx.c
··· 38 38 #include <linux/platform_device.h> 39 39 #include <linux/i2c.h> 40 40 #include <linux/io.h> 41 - #include <linux/gpio.h> 41 + #include <linux/gpio/consumer.h> 42 42 43 43 #include "i2c-iop3xx.h" 44 44 ··· 71 71 72 72 /* 73 73 * Every time unit enable is asserted, GPOD needs to be cleared 74 - * on IOP3XX to avoid data corruption on the bus. 74 + * on IOP3XX to avoid data corruption on the bus. We use the 75 + * gpiod_set_raw_value() to make sure the 0 hits the hardware 76 + * GPOD register. These descriptors are only passed along to 77 + * the device if this is necessary. 75 78 */ 76 - #if defined(CONFIG_ARCH_IOP32X) || defined(CONFIG_ARCH_IOP33X) 77 - if (iop3xx_adap->id == 0) { 78 - gpio_set_value(7, 0); 79 - gpio_set_value(6, 0); 80 - } else { 81 - gpio_set_value(5, 0); 82 - gpio_set_value(4, 0); 83 - } 84 - #endif 79 + if (iop3xx_adap->gpio_scl) 80 + gpiod_set_raw_value(iop3xx_adap->gpio_scl, 0); 81 + if (iop3xx_adap->gpio_sda) 82 + gpiod_set_raw_value(iop3xx_adap->gpio_sda, 0); 83 + 85 84 /* NB SR bits not same position as CR IE bits :-( */ 86 85 iop3xx_adap->SR_enabled = 87 86 IOP3XX_ISR_ALD | IOP3XX_ISR_BERRD | ··· 432 433 ret = -ENOMEM; 433 434 goto free_adapter; 434 435 } 436 + 437 + adapter_data->gpio_scl = devm_gpiod_get_optional(&pdev->dev, 438 + "scl", 439 + GPIOD_ASIS); 440 + if (IS_ERR(adapter_data->gpio_scl)) 441 + return PTR_ERR(adapter_data->gpio_scl); 442 + adapter_data->gpio_sda = devm_gpiod_get_optional(&pdev->dev, 443 + "sda", 444 + GPIOD_ASIS); 445 + if (IS_ERR(adapter_data->gpio_sda)) 446 + return PTR_ERR(adapter_data->gpio_sda); 435 447 436 448 res = platform_get_resource(pdev, IORESOURCE_MEM, 0); 437 449 if (!res) {
+2
drivers/i2c/busses/i2c-iop3xx.h
··· 98 98 spinlock_t lock; 99 99 u32 SR_enabled, SR_received; 100 100 int id; 101 + struct gpio_desc *gpio_scl; 102 + struct gpio_desc *gpio_sda; 101 103 }; 102 104 103 105 #endif /* I2C_IOP3XX_H */