From 85859883ce603bf0db782c03294873dad39176e5 Mon Sep 17 00:00:00 2001 From: John Crispin Date: Sat, 13 Aug 2011 13:59:50 +0200 Subject: [PATCH 52/70] MIPS: lantiq: make GPIO3 work on AR9 There are 3 16bit and 1 8bit gpio ports on AR9. The gpio driver needs a hack at 2 places to make the different register layout of the GPIO3 work properly with the driver. Before only GPIO0-2 were supported. As the GPIO number scheme clashes with the new size, we also move the other gpio chips to new offsets. Signed-off-by: John Crispin Signed-off-by: Thomas Langer --- .../mips/include/asm/mach-lantiq/xway/lantiq_soc.h | 2 + arch/mips/lantiq/xway/devices.c | 3 + arch/mips/lantiq/xway/gpio.c | 84 ++++++++++++++++---- arch/mips/lantiq/xway/gpio_ebu.c | 3 +- arch/mips/lantiq/xway/gpio_stp.c | 3 +- 5 files changed, 75 insertions(+), 20 deletions(-) diff --git a/arch/mips/include/asm/mach-lantiq/xway/lantiq_soc.h b/arch/mips/include/asm/mach-lantiq/xway/lantiq_soc.h index d1b8cc8..bfdeb16 100644 --- a/arch/mips/include/asm/mach-lantiq/xway/lantiq_soc.h +++ b/arch/mips/include/asm/mach-lantiq/xway/lantiq_soc.h @@ -126,7 +126,9 @@ #define LTQ_GPIO0_BASE_ADDR 0x1E100B10 #define LTQ_GPIO1_BASE_ADDR 0x1E100B40 #define LTQ_GPIO2_BASE_ADDR 0x1E100B70 +#define LTQ_GPIO3_BASE_ADDR 0x1E100BA0 #define LTQ_GPIO_SIZE 0x30 +#define LTQ_GPIO3_SIZE 0x10 /* SSC */ #define LTQ_SSC_BASE_ADDR 0x1e100800 diff --git a/arch/mips/lantiq/xway/devices.c b/arch/mips/lantiq/xway/devices.c index 5efa4f3..e6d45bc 100644 --- a/arch/mips/lantiq/xway/devices.c +++ b/arch/mips/lantiq/xway/devices.c @@ -34,6 +34,7 @@ static struct resource ltq_gpio_resource[] = { MEM_RES("gpio0", LTQ_GPIO0_BASE_ADDR, LTQ_GPIO_SIZE), MEM_RES("gpio1", LTQ_GPIO1_BASE_ADDR, LTQ_GPIO_SIZE), MEM_RES("gpio2", LTQ_GPIO2_BASE_ADDR, LTQ_GPIO_SIZE), + MEM_RES("gpio3", LTQ_GPIO3_BASE_ADDR, LTQ_GPIO3_SIZE), }; void __init ltq_register_gpio(void) @@ -47,6 +48,8 @@ void __init ltq_register_gpio(void) if (ltq_is_ar9() || ltq_is_vr9()) { platform_device_register_simple("ltq_gpio", 2, <q_gpio_resource[2], 1); + platform_device_register_simple("ltq_gpio", 3, + <q_gpio_resource[3], 1); } } diff --git a/arch/mips/lantiq/xway/gpio.c b/arch/mips/lantiq/xway/gpio.c index 54ec6c9..375329b 100644 --- a/arch/mips/lantiq/xway/gpio.c +++ b/arch/mips/lantiq/xway/gpio.c @@ -23,9 +23,17 @@ #define LTQ_GPIO_OD 0x14 #define LTQ_GPIO_PUDSEL 0x1C #define LTQ_GPIO_PUDEN 0x20 +#define LTQ_GPIO3_OD 0x24 +#define LTQ_GPIO3_ALTSEL1 0x24 +#define LTQ_GPIO3_PUDSEL 0x28 +#define LTQ_GPIO3_PUDEN 0x2C +/* PORT3 only has 8 pins and its register layout + is slightly different */ #define PINS_PER_PORT 16 -#define MAX_PORTS 3 +#define PINS_PORT3 8 +#define MAX_PORTS 4 +#define MAX_PIN 56 #define ltq_gpio_getbit(m, r, p) (!!(ltq_r32(m + r) & (1 << p))) #define ltq_gpio_setbit(m, r, p) ltq_w32_mask(0, (1 << p), m + r) @@ -55,7 +63,7 @@ int ltq_gpio_request(struct device *dev, unsigned int pin, unsigned int mux, { int id = 0; - if (pin >= (MAX_PORTS * PINS_PER_PORT)) + if (pin >= MAX_PIN) return -EINVAL; if (devm_gpio_request(dev, pin, name)) { pr_err("failed to setup lantiq gpio: %s\n", name); @@ -75,12 +83,21 @@ int ltq_gpio_request(struct device *dev, unsigned int pin, unsigned int mux, else ltq_gpio_clearbit(ltq_gpio_port[id].membase, LTQ_GPIO_ALTSEL0, pin); - if (mux & 0x1) - ltq_gpio_setbit(ltq_gpio_port[id].membase, - LTQ_GPIO_ALTSEL1, pin); - else - ltq_gpio_clearbit(ltq_gpio_port[id].membase, - LTQ_GPIO_ALTSEL1, pin); + if (id == 3) { + if (mux & 0x1) + ltq_gpio_setbit(ltq_gpio_port[1].membase, + LTQ_GPIO3_ALTSEL1, pin); + else + ltq_gpio_clearbit(ltq_gpio_port[1].membase, + LTQ_GPIO3_ALTSEL1, pin); + } else { + if (mux & 0x1) + ltq_gpio_setbit(ltq_gpio_port[id].membase, + LTQ_GPIO_ALTSEL1, pin); + else + ltq_gpio_clearbit(ltq_gpio_port[id].membase, + LTQ_GPIO_ALTSEL1, pin); + } return 0; } EXPORT_SYMBOL(ltq_gpio_request); @@ -106,10 +123,19 @@ static int ltq_gpio_direction_input(struct gpio_chip *chip, unsigned int offset) { struct ltq_gpio *ltq_gpio = container_of(chip, struct ltq_gpio, chip); - ltq_gpio_clearbit(ltq_gpio->membase, LTQ_GPIO_OD, offset); + if (chip->ngpio == PINS_PORT3) { + ltq_gpio_clearbit(ltq_gpio_port[0].membase, + LTQ_GPIO3_OD, offset); + ltq_gpio_setbit(ltq_gpio_port[0].membase, + LTQ_GPIO3_PUDSEL, offset); + ltq_gpio_setbit(ltq_gpio_port[0].membase, + LTQ_GPIO3_PUDEN, offset); + } else { + ltq_gpio_clearbit(ltq_gpio->membase, LTQ_GPIO_OD, offset); + ltq_gpio_setbit(ltq_gpio->membase, LTQ_GPIO_PUDSEL, offset); + ltq_gpio_setbit(ltq_gpio->membase, LTQ_GPIO_PUDEN, offset); + } ltq_gpio_clearbit(ltq_gpio->membase, LTQ_GPIO_DIR, offset); - ltq_gpio_setbit(ltq_gpio->membase, LTQ_GPIO_PUDSEL, offset); - ltq_gpio_setbit(ltq_gpio->membase, LTQ_GPIO_PUDEN, offset); return 0; } @@ -119,10 +145,19 @@ static int ltq_gpio_direction_output(struct gpio_chip *chip, { struct ltq_gpio *ltq_gpio = container_of(chip, struct ltq_gpio, chip); - ltq_gpio_setbit(ltq_gpio->membase, LTQ_GPIO_OD, offset); + if (chip->ngpio == PINS_PORT3) { + ltq_gpio_setbit(ltq_gpio_port[0].membase, + LTQ_GPIO3_OD, offset); + ltq_gpio_clearbit(ltq_gpio_port[0].membase, + LTQ_GPIO3_PUDSEL, offset); + ltq_gpio_clearbit(ltq_gpio_port[0].membase, + LTQ_GPIO3_PUDEN, offset); + } else { + ltq_gpio_setbit(ltq_gpio->membase, LTQ_GPIO_OD, offset); + ltq_gpio_clearbit(ltq_gpio->membase, LTQ_GPIO_PUDSEL, offset); + ltq_gpio_clearbit(ltq_gpio->membase, LTQ_GPIO_PUDEN, offset); + } ltq_gpio_setbit(ltq_gpio->membase, LTQ_GPIO_DIR, offset); - ltq_gpio_clearbit(ltq_gpio->membase, LTQ_GPIO_PUDSEL, offset); - ltq_gpio_clearbit(ltq_gpio->membase, LTQ_GPIO_PUDEN, offset); ltq_gpio_set(chip, offset, value); return 0; @@ -133,7 +168,11 @@ static int ltq_gpio_req(struct gpio_chip *chip, unsigned offset) struct ltq_gpio *ltq_gpio = container_of(chip, struct ltq_gpio, chip); ltq_gpio_clearbit(ltq_gpio->membase, LTQ_GPIO_ALTSEL0, offset); - ltq_gpio_clearbit(ltq_gpio->membase, LTQ_GPIO_ALTSEL1, offset); + if (chip->ngpio == PINS_PORT3) + ltq_gpio_clearbit(ltq_gpio_port[1].membase, + LTQ_GPIO3_ALTSEL1, offset); + else + ltq_gpio_clearbit(ltq_gpio->membase, LTQ_GPIO_ALTSEL1, offset); return 0; } @@ -146,6 +185,16 @@ static int ltq_gpio_probe(struct platform_device *pdev) pdev->id); return -EINVAL; } + + /* dirty hack - The registers of port3 are not mapped linearly. + Port 3 may only load if Port 1/2 are mapped */ + if ((pdev->id == 3) && (!ltq_gpio_port[1].membase + || !ltq_gpio_port[2].membase)) { + dev_err(&pdev->dev, + "ports 1/2 need to be loaded before port 3 works\n"); + return -ENOMEM; + } + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); if (!res) { dev_err(&pdev->dev, "failed to get memory for gpio port %d\n", @@ -175,7 +224,10 @@ static int ltq_gpio_probe(struct platform_device *pdev) ltq_gpio_port[pdev->id].chip.set = ltq_gpio_set; ltq_gpio_port[pdev->id].chip.request = ltq_gpio_req; ltq_gpio_port[pdev->id].chip.base = PINS_PER_PORT * pdev->id; - ltq_gpio_port[pdev->id].chip.ngpio = PINS_PER_PORT; + if (pdev->id == 3) + ltq_gpio_port[pdev->id].chip.ngpio = PINS_PORT3; + else + ltq_gpio_port[pdev->id].chip.ngpio = PINS_PER_PORT; platform_set_drvdata(pdev, <q_gpio_port[pdev->id]); return gpiochip_add(<q_gpio_port[pdev->id].chip); } diff --git a/arch/mips/lantiq/xway/gpio_ebu.c b/arch/mips/lantiq/xway/gpio_ebu.c index b91c7f1..bc5696b 100644 --- a/arch/mips/lantiq/xway/gpio_ebu.c +++ b/arch/mips/lantiq/xway/gpio_ebu.c @@ -61,9 +61,8 @@ static struct gpio_chip ltq_ebu_chip = { .label = "ltq_ebu", .direction_output = ltq_ebu_direction_output, .set = ltq_ebu_set, - .base = 72, + .base = 100, .ngpio = 16, - .can_sleep = 1, .owner = THIS_MODULE, }; diff --git a/arch/mips/lantiq/xway/gpio_stp.c b/arch/mips/lantiq/xway/gpio_stp.c index da91c5e..9610c10 100644 --- a/arch/mips/lantiq/xway/gpio_stp.c +++ b/arch/mips/lantiq/xway/gpio_stp.c @@ -74,9 +74,8 @@ static struct gpio_chip ltq_stp_chip = { .label = "ltq_stp", .direction_output = ltq_stp_direction_output, .set = ltq_stp_set, - .base = 48, + .base = 200, .ngpio = 24, - .can_sleep = 1, .owner = THIS_MODULE, }; -- 1.7.9.1