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>
This commit is contained in:
parent
ed7357c9f9
commit
fdb7e884ad
@ -305,6 +305,8 @@ extern struct platform_device iop3xx_dma_1_channel;
|
|||||||
extern struct platform_device iop3xx_aau_channel;
|
extern struct platform_device iop3xx_aau_channel;
|
||||||
extern struct platform_device iop3xx_i2c0_device;
|
extern struct platform_device iop3xx_i2c0_device;
|
||||||
extern struct platform_device iop3xx_i2c1_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
|
#endif
|
||||||
|
|
||||||
|
@ -24,6 +24,7 @@
|
|||||||
#include <linux/platform_device.h>
|
#include <linux/platform_device.h>
|
||||||
#include <linux/i2c.h>
|
#include <linux/i2c.h>
|
||||||
#include <linux/gpio.h>
|
#include <linux/gpio.h>
|
||||||
|
#include <linux/gpio/machine.h>
|
||||||
#include <mach/hardware.h>
|
#include <mach/hardware.h>
|
||||||
#include <linux/io.h>
|
#include <linux/io.h>
|
||||||
#include <linux/irq.h>
|
#include <linux/irq.h>
|
||||||
@ -211,6 +212,8 @@ static void __init em7210_init_machine(void)
|
|||||||
{
|
{
|
||||||
register_iop32x_gpio();
|
register_iop32x_gpio();
|
||||||
platform_device_register(&em7210_serial_device);
|
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_i2c0_device);
|
||||||
platform_device_register(&iop3xx_i2c1_device);
|
platform_device_register(&iop3xx_i2c1_device);
|
||||||
platform_device_register(&em7210_flash_device);
|
platform_device_register(&em7210_flash_device);
|
||||||
|
@ -25,6 +25,7 @@
|
|||||||
#include <linux/i2c.h>
|
#include <linux/i2c.h>
|
||||||
#include <linux/platform_device.h>
|
#include <linux/platform_device.h>
|
||||||
#include <linux/io.h>
|
#include <linux/io.h>
|
||||||
|
#include <linux/gpio/machine.h>
|
||||||
#include <mach/hardware.h>
|
#include <mach/hardware.h>
|
||||||
#include <asm/irq.h>
|
#include <asm/irq.h>
|
||||||
#include <asm/mach/arch.h>
|
#include <asm/mach/arch.h>
|
||||||
@ -189,6 +190,8 @@ static void glantank_power_off(void)
|
|||||||
static void __init glantank_init_machine(void)
|
static void __init glantank_init_machine(void)
|
||||||
{
|
{
|
||||||
register_iop32x_gpio();
|
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_i2c0_device);
|
||||||
platform_device_register(&iop3xx_i2c1_device);
|
platform_device_register(&iop3xx_i2c1_device);
|
||||||
platform_device_register(&glantank_flash_device);
|
platform_device_register(&glantank_flash_device);
|
||||||
|
@ -26,6 +26,7 @@
|
|||||||
#include <linux/mtd/physmap.h>
|
#include <linux/mtd/physmap.h>
|
||||||
#include <linux/platform_device.h>
|
#include <linux/platform_device.h>
|
||||||
#include <linux/io.h>
|
#include <linux/io.h>
|
||||||
|
#include <linux/gpio/machine.h>
|
||||||
#include <mach/hardware.h>
|
#include <mach/hardware.h>
|
||||||
#include <asm/cputype.h>
|
#include <asm/cputype.h>
|
||||||
#include <asm/irq.h>
|
#include <asm/irq.h>
|
||||||
@ -285,6 +286,8 @@ void ep80219_power_off(void)
|
|||||||
static void __init iq31244_init_machine(void)
|
static void __init iq31244_init_machine(void)
|
||||||
{
|
{
|
||||||
register_iop32x_gpio();
|
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_i2c0_device);
|
||||||
platform_device_register(&iop3xx_i2c1_device);
|
platform_device_register(&iop3xx_i2c1_device);
|
||||||
platform_device_register(&iq31244_flash_device);
|
platform_device_register(&iq31244_flash_device);
|
||||||
|
@ -23,6 +23,7 @@
|
|||||||
#include <linux/mtd/physmap.h>
|
#include <linux/mtd/physmap.h>
|
||||||
#include <linux/platform_device.h>
|
#include <linux/platform_device.h>
|
||||||
#include <linux/io.h>
|
#include <linux/io.h>
|
||||||
|
#include <linux/gpio/machine.h>
|
||||||
#include <mach/hardware.h>
|
#include <mach/hardware.h>
|
||||||
#include <asm/irq.h>
|
#include <asm/irq.h>
|
||||||
#include <asm/mach/arch.h>
|
#include <asm/mach/arch.h>
|
||||||
@ -172,6 +173,8 @@ static struct platform_device iq80321_serial_device = {
|
|||||||
static void __init iq80321_init_machine(void)
|
static void __init iq80321_init_machine(void)
|
||||||
{
|
{
|
||||||
register_iop32x_gpio();
|
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_i2c0_device);
|
||||||
platform_device_register(&iop3xx_i2c1_device);
|
platform_device_register(&iop3xx_i2c1_device);
|
||||||
platform_device_register(&iq80321_flash_device);
|
platform_device_register(&iq80321_flash_device);
|
||||||
|
@ -31,6 +31,7 @@
|
|||||||
#include <linux/reboot.h>
|
#include <linux/reboot.h>
|
||||||
#include <linux/io.h>
|
#include <linux/io.h>
|
||||||
#include <linux/gpio.h>
|
#include <linux/gpio.h>
|
||||||
|
#include <linux/gpio/machine.h>
|
||||||
#include <mach/hardware.h>
|
#include <mach/hardware.h>
|
||||||
#include <asm/irq.h>
|
#include <asm/irq.h>
|
||||||
#include <asm/mach/arch.h>
|
#include <asm/mach/arch.h>
|
||||||
@ -345,6 +346,7 @@ device_initcall(n2100_request_gpios);
|
|||||||
static void __init n2100_init_machine(void)
|
static void __init n2100_init_machine(void)
|
||||||
{
|
{
|
||||||
register_iop32x_gpio();
|
register_iop32x_gpio();
|
||||||
|
gpiod_add_lookup_table(&iop3xx_i2c0_gpio_lookup);
|
||||||
platform_device_register(&iop3xx_i2c0_device);
|
platform_device_register(&iop3xx_i2c0_device);
|
||||||
platform_device_register(&n2100_flash_device);
|
platform_device_register(&n2100_flash_device);
|
||||||
platform_device_register(&n2100_serial_device);
|
platform_device_register(&n2100_serial_device);
|
||||||
|
@ -19,6 +19,7 @@
|
|||||||
#include <linux/tty.h>
|
#include <linux/tty.h>
|
||||||
#include <linux/serial_core.h>
|
#include <linux/serial_core.h>
|
||||||
#include <linux/io.h>
|
#include <linux/io.h>
|
||||||
|
#include <linux/gpio/machine.h>
|
||||||
#include <asm/pgtable.h>
|
#include <asm/pgtable.h>
|
||||||
#include <asm/page.h>
|
#include <asm/page.h>
|
||||||
#include <asm/mach/map.h>
|
#include <asm/mach/map.h>
|
||||||
@ -37,6 +38,29 @@
|
|||||||
#define IRQ_IOP3XX_I2C_1 IRQ_IOP33X_I2C_1
|
#define IRQ_IOP3XX_I2C_1 IRQ_IOP33X_I2C_1
|
||||||
#endif
|
#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[] = {
|
static struct resource iop3xx_i2c0_resources[] = {
|
||||||
[0] = {
|
[0] = {
|
||||||
.start = 0xfffff680,
|
.start = 0xfffff680,
|
||||||
|
@ -40,6 +40,7 @@ static int iop3xx_gpio_probe(struct platform_device *pdev)
|
|||||||
|
|
||||||
gc->base = 0;
|
gc->base = 0;
|
||||||
gc->owner = THIS_MODULE;
|
gc->owner = THIS_MODULE;
|
||||||
|
gc->label = "gpio-iop";
|
||||||
|
|
||||||
return devm_gpiochip_add_data(&pdev->dev, gc, NULL);
|
return devm_gpiochip_add_data(&pdev->dev, gc, NULL);
|
||||||
}
|
}
|
||||||
|
@ -38,7 +38,7 @@
|
|||||||
#include <linux/platform_device.h>
|
#include <linux/platform_device.h>
|
||||||
#include <linux/i2c.h>
|
#include <linux/i2c.h>
|
||||||
#include <linux/io.h>
|
#include <linux/io.h>
|
||||||
#include <linux/gpio.h>
|
#include <linux/gpio/consumer.h>
|
||||||
|
|
||||||
#include "i2c-iop3xx.h"
|
#include "i2c-iop3xx.h"
|
||||||
|
|
||||||
@ -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
|
* 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->gpio_scl)
|
||||||
if (iop3xx_adap->id == 0) {
|
gpiod_set_raw_value(iop3xx_adap->gpio_scl, 0);
|
||||||
gpio_set_value(7, 0);
|
if (iop3xx_adap->gpio_sda)
|
||||||
gpio_set_value(6, 0);
|
gpiod_set_raw_value(iop3xx_adap->gpio_sda, 0);
|
||||||
} else {
|
|
||||||
gpio_set_value(5, 0);
|
|
||||||
gpio_set_value(4, 0);
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
/* NB SR bits not same position as CR IE bits :-( */
|
/* NB SR bits not same position as CR IE bits :-( */
|
||||||
iop3xx_adap->SR_enabled =
|
iop3xx_adap->SR_enabled =
|
||||||
IOP3XX_ISR_ALD | IOP3XX_ISR_BERRD |
|
IOP3XX_ISR_ALD | IOP3XX_ISR_BERRD |
|
||||||
@ -434,6 +433,17 @@ iop3xx_i2c_probe(struct platform_device *pdev)
|
|||||||
goto free_adapter;
|
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);
|
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
||||||
if (!res) {
|
if (!res) {
|
||||||
ret = -ENODEV;
|
ret = -ENODEV;
|
||||||
|
@ -98,6 +98,8 @@ struct i2c_algo_iop3xx_data {
|
|||||||
spinlock_t lock;
|
spinlock_t lock;
|
||||||
u32 SR_enabled, SR_received;
|
u32 SR_enabled, SR_received;
|
||||||
int id;
|
int id;
|
||||||
|
struct gpio_desc *gpio_scl;
|
||||||
|
struct gpio_desc *gpio_sda;
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif /* I2C_IOP3XX_H */
|
#endif /* I2C_IOP3XX_H */
|
||||||
|
Loading…
x
Reference in New Issue
Block a user