From 89ff2c22036ffc6716d66ed30aea02a8803a22ca Mon Sep 17 00:00:00 2001 From: Jean-Christophe PLAGNIOL-VILLARD Date: Mon, 17 Oct 2011 21:09:39 +0800 Subject: [PATCH] ARM: at91: gpio add DT support Signed-off-by: Jean-Christophe PLAGNIOL-VILLARD --- .../devicetree/bindings/gpio/gpio_at91.txt | 9 ++ arch/arm/boot/dts/at91sam9g20.dtsi | 27 ++++ arch/arm/boot/dts/at91sam9g45.dtsi | 45 +++++++ arch/arm/mach-at91/gpio.c | 120 +++++++++++++++--- 4 files changed, 182 insertions(+), 19 deletions(-) create mode 100644 Documentation/devicetree/bindings/gpio/gpio_at91.txt diff --git a/Documentation/devicetree/bindings/gpio/gpio_at91.txt b/Documentation/devicetree/bindings/gpio/gpio_at91.txt new file mode 100644 index 000000000000..e6dafdf30f34 --- /dev/null +++ b/Documentation/devicetree/bindings/gpio/gpio_at91.txt @@ -0,0 +1,9 @@ +Atmel AT91 GPIO controller + +Required properties: + - compatible : "atmel,at91rm9200-gpio" + - interrupts : Should be the port interrupt shared by all 32 pins. + - #gpio-cells : Should be two. The first cell is the pin number and + the second cell is used to specify optional parameters (currently + unused). + - gpio-controller : Marks the device node as a GPIO controller. diff --git a/arch/arm/boot/dts/at91sam9g20.dtsi b/arch/arm/boot/dts/at91sam9g20.dtsi index 410ae6e8f535..477f1692705a 100644 --- a/arch/arm/boot/dts/at91sam9g20.dtsi +++ b/arch/arm/boot/dts/at91sam9g20.dtsi @@ -23,6 +23,9 @@ serial4 = &usart3; serial5 = &usart4; serial6 = &usart5; + gpio0 = &pioA; + gpio1 = &pioB; + gpio2 = &pioC; }; cpus { cpu@0 { @@ -60,6 +63,30 @@ interrupts = <1>; }; + pioA: gpio@fffff400 { + compatible = "atmel,at91rm9200-gpio"; + reg = < 0xfffff400 0x200 >; + interrupts = <2>; + #gpio-cells = <2>; + gpio-controller; + }; + + pioB: gpio@fffff600 { + compatible = "atmel,at91rm9200-gpio"; + reg = < 0xfffff600 0x200 >; + interrupts = <3>; + #gpio-cells = <2>; + gpio-controller; + }; + + pioC: gpio@fffff800 { + compatible = "atmel,at91rm9200-gpio"; + reg = < 0xfffff800 0x200 >; + interrupts = <4>; + #gpio-cells = <2>; + gpio-controller; + }; + dbgu: serial@fffff200 { compatible = "atmel,at91sam9260-usart"; reg = <0xfffff200 0x200>; diff --git a/arch/arm/boot/dts/at91sam9g45.dtsi b/arch/arm/boot/dts/at91sam9g45.dtsi index a09b102cc3ae..0dd7c1105bbe 100644 --- a/arch/arm/boot/dts/at91sam9g45.dtsi +++ b/arch/arm/boot/dts/at91sam9g45.dtsi @@ -22,6 +22,11 @@ serial2 = &usart1; serial3 = &usart2; serial4 = &usart3; + gpio0 = &pioA; + gpio1 = &pioB; + gpio2 = &pioC; + gpio3 = &pioD; + gpio4 = &pioE; }; cpus { cpu@0 { @@ -65,6 +70,46 @@ interrupts = <21>; }; + pioA: gpio@fffff200 { + compatible = "atmel,at91rm9200-gpio"; + reg = < 0xfffff200 0x200 >; + interrupts = <2>; + #gpio-cells = <2>; + gpio-controller; + }; + + pioB: gpio@fffff400 { + compatible = "atmel,at91rm9200-gpio"; + reg = < 0xfffff400 0x200 >; + interrupts = <3>; + #gpio-cells = <2>; + gpio-controller; + }; + + pioC: gpio@fffff600 { + compatible = "atmel,at91rm9200-gpio"; + reg = < 0xfffff600 0x200 >; + interrupts = <4>; + #gpio-cells = <2>; + gpio-controller; + }; + + pioD: gpio@fffff800 { + compatible = "atmel,at91rm9200-gpio"; + reg = < 0xfffff800 0x200 >; + interrupts = <5>; + #gpio-cells = <2>; + gpio-controller; + }; + + pioE: gpio@fffffa00 { + compatible = "atmel,at91rm9200-gpio"; + reg = < 0xfffffa00 0x200 >; + interrupts = <5>; + #gpio-cells = <2>; + gpio-controller; + }; + dbgu: serial@ffffee00 { compatible = "atmel,at91sam9260-usart"; reg = <0xffffee00 0x200>; diff --git a/arch/arm/mach-at91/gpio.c b/arch/arm/mach-at91/gpio.c index 74d6783eeabb..63d25574675c 100644 --- a/arch/arm/mach-at91/gpio.c +++ b/arch/arm/mach-at91/gpio.c @@ -20,6 +20,8 @@ #include #include #include +#include +#include #include #include @@ -600,6 +602,97 @@ static void at91_gpiolib_dbg_show(struct seq_file *s, struct gpio_chip *chip) } } +#ifdef CONFIG_OF_GPIO +static void __init of_at91_gpio_init_one(struct device_node *np) +{ + int i; + struct at91_gpio_chip *at91_gpio; + const unsigned int *intspec; + + if (!np) + return; + + i = of_alias_get_id(np, "gpio"); + if (i >= MAX_GPIO_BANKS) { + pr_err("at91_gpio, failed id(%d) > MAX_GPIO_BANKS(%d), ignoring.\n", i, MAX_GPIO_BANKS); + return; + } + + at91_gpio = &gpio_chip[i]; + at91_gpio->chip.base = i * 32; + + at91_gpio->regbase = of_iomap(np, 0); + if (!at91_gpio->regbase) { + pr_err("at91_gpio.%d, failed to map registers, ignoring.\n", i); + return; + } + + /* Get the interrupts property */ + intspec = of_get_property(np, "interrupts", NULL); + BUG_ON(!intspec); + at91_gpio->id = be32_to_cpup(intspec); + + at91_gpio->clock = clk_get_sys(NULL, at91_gpio->chip.label); + if (!at91_gpio->clock) { + pr_err("at91_gpio.%d, failed to get clock, ignoring.\n", i); + return; + } + + /* enable PIO controller's clock */ + clk_enable(at91_gpio->clock); + + at91_gpio->chip.of_node = np; + gpio_banks = max(gpio_banks, i + 1); +} + +static int __init of_at91_gpio_init(void) +{ + struct device_node *np = NULL; + + gpio_banks = 0; + + /* + * This isn't ideal, but it gets things hooked up until this + * driver is converted into a platform_device + */ + do { + np = of_find_compatible_node(np, NULL, "atmel,at91rm9200-gpio"); + + of_at91_gpio_init_one(np); + } while (np); + + return gpio_banks > 0 ? 0 : -EINVAL; +} +#else +static int __init of_at91_gpio_init(void) +{ + return -EINVAL; +} +#endif + +static void __init at91_gpio_init_one(int i, u32 regbase, int id) +{ + struct at91_gpio_chip *at91_gpio = &gpio_chip[i]; + + at91_gpio->chip.base = i * 32; + at91_gpio->id = id; + + at91_gpio->regbase = ioremap(regbase, 512); + if (!at91_gpio->regbase) { + pr_err("at91_gpio.%d, failed to map registers, ignoring.\n", i); + return; + } + + at91_gpio->clock = clk_get_sys(NULL, at91_gpio->chip.label); + if (!at91_gpio->clock) { + pr_err("at91_gpio.%d, failed to get clock, ignoring.\n", i); + return; + } + + /* enable PIO controller's clock */ + clk_enable(at91_gpio->clock); +} + /* * Called from the processor-specific init to enable GPIO pin support. */ @@ -610,28 +703,17 @@ void __init at91_gpio_init(struct at91_gpio_bank *data, int nr_banks) BUG_ON(nr_banks > MAX_GPIO_BANKS); - gpio_banks = nr_banks; - - for (i = 0; i < nr_banks; i++) { - at91_gpio = &gpio_chip[i]; + if (!of_at91_gpio_init()) + goto fixup; - at91_gpio->id = data[i].id; - at91_gpio->chip.base = i * 32; - - at91_gpio->regbase = ioremap(data[i].regbase, 512); - if (!at91_gpio->regbase) { - pr_err("at91_gpio.%d, failed to map registers, ignoring.\n", i); - continue; - } + gpio_banks = nr_banks; - at91_gpio->clock = clk_get_sys(NULL, at91_gpio->chip.label); - if (!at91_gpio->clock) { - pr_err("at91_gpio.%d, failed to get clock, ignoring.\n", i); - continue; - } + for (i = 0; i < nr_banks; i++) + at91_gpio_init_one(i, data[i].regbase, data[i].id); - /* enable PIO controller's clock */ - clk_enable(at91_gpio->clock); +fixup: + for (i = 0; i < gpio_banks; i++) { + at91_gpio = &gpio_chip[i]; /* AT91SAM9263_ID_PIOCDE groups PIOC, PIOD, PIOE */ if (last && last->id == at91_gpio->id) -- 2.39.5