Skip to content

Commit

Permalink
i2c: iop: Use GPIO descriptors
Browse files Browse the repository at this point in the history
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 <[email protected]>
Acked-by: Arnd Bergmann <[email protected]>
Acked-by: Dan Williams <[email protected]>
Signed-off-by: Wolfram Sang <[email protected]>
  • Loading branch information
linusw authored and Wolfram Sang committed Jun 12, 2019
1 parent ed7357c commit fdb7e88
Show file tree
Hide file tree
Showing 10 changed files with 64 additions and 11 deletions.
2 changes: 2 additions & 0 deletions arch/arm/include/asm/hardware/iop3xx.h
Original file line number Diff line number Diff line change
Expand Up @@ -305,6 +305,8 @@ extern struct platform_device iop3xx_dma_1_channel;
extern struct platform_device iop3xx_aau_channel;
extern struct platform_device iop3xx_i2c0_device;
extern struct platform_device iop3xx_i2c1_device;
extern struct gpiod_lookup_table iop3xx_i2c0_gpio_lookup;
extern struct gpiod_lookup_table iop3xx_i2c1_gpio_lookup;

#endif

Expand Down
3 changes: 3 additions & 0 deletions arch/arm/mach-iop32x/em7210.c
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@
#include <linux/platform_device.h>
#include <linux/i2c.h>
#include <linux/gpio.h>
#include <linux/gpio/machine.h>
#include <mach/hardware.h>
#include <linux/io.h>
#include <linux/irq.h>
Expand Down Expand Up @@ -211,6 +212,8 @@ static void __init em7210_init_machine(void)
{
register_iop32x_gpio();
platform_device_register(&em7210_serial_device);
gpiod_add_lookup_table(&iop3xx_i2c0_gpio_lookup);
gpiod_add_lookup_table(&iop3xx_i2c1_gpio_lookup);
platform_device_register(&iop3xx_i2c0_device);
platform_device_register(&iop3xx_i2c1_device);
platform_device_register(&em7210_flash_device);
Expand Down
3 changes: 3 additions & 0 deletions arch/arm/mach-iop32x/glantank.c
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@
#include <linux/i2c.h>
#include <linux/platform_device.h>
#include <linux/io.h>
#include <linux/gpio/machine.h>
#include <mach/hardware.h>
#include <asm/irq.h>
#include <asm/mach/arch.h>
Expand Down Expand Up @@ -189,6 +190,8 @@ static void glantank_power_off(void)
static void __init glantank_init_machine(void)
{
register_iop32x_gpio();
gpiod_add_lookup_table(&iop3xx_i2c0_gpio_lookup);
gpiod_add_lookup_table(&iop3xx_i2c1_gpio_lookup);
platform_device_register(&iop3xx_i2c0_device);
platform_device_register(&iop3xx_i2c1_device);
platform_device_register(&glantank_flash_device);
Expand Down
3 changes: 3 additions & 0 deletions arch/arm/mach-iop32x/iq31244.c
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@
#include <linux/mtd/physmap.h>
#include <linux/platform_device.h>
#include <linux/io.h>
#include <linux/gpio/machine.h>
#include <mach/hardware.h>
#include <asm/cputype.h>
#include <asm/irq.h>
Expand Down Expand Up @@ -285,6 +286,8 @@ void ep80219_power_off(void)
static void __init iq31244_init_machine(void)
{
register_iop32x_gpio();
gpiod_add_lookup_table(&iop3xx_i2c0_gpio_lookup);
gpiod_add_lookup_table(&iop3xx_i2c1_gpio_lookup);
platform_device_register(&iop3xx_i2c0_device);
platform_device_register(&iop3xx_i2c1_device);
platform_device_register(&iq31244_flash_device);
Expand Down
3 changes: 3 additions & 0 deletions arch/arm/mach-iop32x/iq80321.c
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
#include <linux/mtd/physmap.h>
#include <linux/platform_device.h>
#include <linux/io.h>
#include <linux/gpio/machine.h>
#include <mach/hardware.h>
#include <asm/irq.h>
#include <asm/mach/arch.h>
Expand Down Expand Up @@ -172,6 +173,8 @@ static struct platform_device iq80321_serial_device = {
static void __init iq80321_init_machine(void)
{
register_iop32x_gpio();
gpiod_add_lookup_table(&iop3xx_i2c0_gpio_lookup);
gpiod_add_lookup_table(&iop3xx_i2c1_gpio_lookup);
platform_device_register(&iop3xx_i2c0_device);
platform_device_register(&iop3xx_i2c1_device);
platform_device_register(&iq80321_flash_device);
Expand Down
2 changes: 2 additions & 0 deletions arch/arm/mach-iop32x/n2100.c
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@
#include <linux/reboot.h>
#include <linux/io.h>
#include <linux/gpio.h>
#include <linux/gpio/machine.h>
#include <mach/hardware.h>
#include <asm/irq.h>
#include <asm/mach/arch.h>
Expand Down Expand Up @@ -345,6 +346,7 @@ device_initcall(n2100_request_gpios);
static void __init n2100_init_machine(void)
{
register_iop32x_gpio();
gpiod_add_lookup_table(&iop3xx_i2c0_gpio_lookup);
platform_device_register(&iop3xx_i2c0_device);
platform_device_register(&n2100_flash_device);
platform_device_register(&n2100_serial_device);
Expand Down
24 changes: 24 additions & 0 deletions arch/arm/plat-iop/i2c.c
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
#include <linux/tty.h>
#include <linux/serial_core.h>
#include <linux/io.h>
#include <linux/gpio/machine.h>
#include <asm/pgtable.h>
#include <asm/page.h>
#include <asm/mach/map.h>
Expand All @@ -37,6 +38,29 @@
#define IRQ_IOP3XX_I2C_1 IRQ_IOP33X_I2C_1
#endif

/*
* Each of the I2C busses have corresponding GPIO lines, and the driver
* need to access these directly to drive the bus low at times.
*/

struct gpiod_lookup_table iop3xx_i2c0_gpio_lookup = {
.dev_id = "IOP3xx-I2C.0",
.table = {
GPIO_LOOKUP("gpio-iop", 7, "scl", GPIO_ACTIVE_HIGH),
GPIO_LOOKUP("gpio-iop", 6, "sda", GPIO_ACTIVE_HIGH),
{ }
},
};

struct gpiod_lookup_table iop3xx_i2c1_gpio_lookup = {
.dev_id = "IOP3xx-I2C.1",
.table = {
GPIO_LOOKUP("gpio-iop", 5, "scl", GPIO_ACTIVE_HIGH),
GPIO_LOOKUP("gpio-iop", 4, "sda", GPIO_ACTIVE_HIGH),
{ }
},
};

static struct resource iop3xx_i2c0_resources[] = {
[0] = {
.start = 0xfffff680,
Expand Down
1 change: 1 addition & 0 deletions drivers/gpio/gpio-iop.c
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ static int iop3xx_gpio_probe(struct platform_device *pdev)

gc->base = 0;
gc->owner = THIS_MODULE;
gc->label = "gpio-iop";

return devm_gpiochip_add_data(&pdev->dev, gc, NULL);
}
Expand Down
32 changes: 21 additions & 11 deletions drivers/i2c/busses/i2c-iop3xx.c
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@
#include <linux/platform_device.h>
#include <linux/i2c.h>
#include <linux/io.h>
#include <linux/gpio.h>
#include <linux/gpio/consumer.h>

#include "i2c-iop3xx.h"

Expand Down Expand Up @@ -71,17 +71,16 @@ iop3xx_i2c_enable(struct i2c_algo_iop3xx_data *iop3xx_adap)

/*
* Every time unit enable is asserted, GPOD needs to be cleared
* on IOP3XX to avoid data corruption on the bus.
* on IOP3XX to avoid data corruption on the bus. We use the
* gpiod_set_raw_value() to make sure the 0 hits the hardware
* GPOD register. These descriptors are only passed along to
* the device if this is necessary.
*/
#if defined(CONFIG_ARCH_IOP32X) || defined(CONFIG_ARCH_IOP33X)
if (iop3xx_adap->id == 0) {
gpio_set_value(7, 0);
gpio_set_value(6, 0);
} else {
gpio_set_value(5, 0);
gpio_set_value(4, 0);
}
#endif
if (iop3xx_adap->gpio_scl)
gpiod_set_raw_value(iop3xx_adap->gpio_scl, 0);
if (iop3xx_adap->gpio_sda)
gpiod_set_raw_value(iop3xx_adap->gpio_sda, 0);

/* NB SR bits not same position as CR IE bits :-( */
iop3xx_adap->SR_enabled =
IOP3XX_ISR_ALD | IOP3XX_ISR_BERRD |
Expand Down Expand Up @@ -434,6 +433,17 @@ iop3xx_i2c_probe(struct platform_device *pdev)
goto free_adapter;
}

adapter_data->gpio_scl = devm_gpiod_get_optional(&pdev->dev,
"scl",
GPIOD_ASIS);
if (IS_ERR(adapter_data->gpio_scl))
return PTR_ERR(adapter_data->gpio_scl);
adapter_data->gpio_sda = devm_gpiod_get_optional(&pdev->dev,
"sda",
GPIOD_ASIS);
if (IS_ERR(adapter_data->gpio_sda))
return PTR_ERR(adapter_data->gpio_sda);

res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
if (!res) {
ret = -ENODEV;
Expand Down
2 changes: 2 additions & 0 deletions drivers/i2c/busses/i2c-iop3xx.h
Original file line number Diff line number Diff line change
Expand Up @@ -98,6 +98,8 @@ struct i2c_algo_iop3xx_data {
spinlock_t lock;
u32 SR_enabled, SR_received;
int id;
struct gpio_desc *gpio_scl;
struct gpio_desc *gpio_sda;
};

#endif /* I2C_IOP3XX_H */

0 comments on commit fdb7e88

Please sign in to comment.