Merge branch 'at91-3.4-cleanup2+DT' of git://github.com/at91linux/linux-at91 into...
authorArnd Bergmann <arnd@arndb.de>
Fri, 2 Mar 2012 13:22:28 +0000 (13:22 +0000)
committerArnd Bergmann <arnd@arndb.de>
Fri, 2 Mar 2012 13:22:28 +0000 (13:22 +0000)
* 'at91-3.4-cleanup2+DT' of git://github.com/at91linux/linux-at91: (22 commits)
  ARM: at91: at91sam9x5cm/dt: add leds support
  ARM: at91: usb_a9g20/dt: add gpio-keys support
  ARM: at91: at91sam9m10g45ek/dt: add gpio-keys support
  ARM: at91: at91sam9m10g45ek/dt: add leds support
  ARM: at91: usb_a9g20/dt: add leds support
  ARM: at91/pio: add new PIO3 features
  ARM: at91: add sam9_smc.o to at91sam9x5 build
  ARM: at91/tc/clocksource: Add 32 bit variant to Timer Counter
  ARM: at91/tc: add device tree support to atmel_tclib
  ARM: at91/tclib: take iomem size from resource
  ARM: at91/pit: add traces in case of error
  ARM: at91: pit add DT support
  ARM: at91: AIC and GPIO IRQ device tree initialization
  ARM: at91/board-dt: remove AIC irq domain from board file
  ARM: at91/gpio: remove the static specification of gpio_chip.base
  ARM: at91/gpio: add .to_irq gpio_chip handler
  ARM: at91/gpio: non-DT builds do not have gpio_chip.of_node field
  ARM: at91/gpio: add irqdomain and DT support
  ARM: at91/gpio: change comments and one variable name
  ARM/USB: at91/ohci-at91: remove the use of irq_to_gpio
  ...

28 files changed:
Documentation/devicetree/bindings/arm/atmel-aic.txt [new file with mode: 0644]
Documentation/devicetree/bindings/arm/atmel-at91.txt [new file with mode: 0644]
Documentation/devicetree/bindings/gpio/gpio_atmel.txt [new file with mode: 0644]
arch/arm/Kconfig
arch/arm/boot/dts/at91sam9g20.dtsi
arch/arm/boot/dts/at91sam9g45.dtsi
arch/arm/boot/dts/at91sam9m10g45ek.dts
arch/arm/boot/dts/at91sam9x5.dtsi
arch/arm/boot/dts/at91sam9x5cm.dtsi
arch/arm/boot/dts/usb_a9g20.dts
arch/arm/mach-at91/Makefile
arch/arm/mach-at91/at91sam9260.c
arch/arm/mach-at91/at91sam9260_devices.c
arch/arm/mach-at91/at91sam926x_time.c
arch/arm/mach-at91/at91sam9g45.c
arch/arm/mach-at91/at91sam9g45_devices.c
arch/arm/mach-at91/at91sam9x5.c
arch/arm/mach-at91/board-dt.c
arch/arm/mach-at91/board-snapper9260.c
arch/arm/mach-at91/generic.h
arch/arm/mach-at91/gpio.c
arch/arm/mach-at91/include/mach/at91_pio.h
arch/arm/mach-at91/include/mach/gpio.h
arch/arm/mach-at91/irq.c
drivers/clocksource/tcb_clksrc.c
drivers/misc/atmel_tclib.c
drivers/usb/host/ohci-at91.c
include/linux/atmel_tc.h

diff --git a/Documentation/devicetree/bindings/arm/atmel-aic.txt b/Documentation/devicetree/bindings/arm/atmel-aic.txt
new file mode 100644 (file)
index 0000000..aabca4f
--- /dev/null
@@ -0,0 +1,38 @@
+* Advanced Interrupt Controller (AIC)
+
+Required properties:
+- compatible: Should be "atmel,<chip>-aic"
+- interrupt-controller: Identifies the node as an interrupt controller.
+- interrupt-parent: For single AIC system, it is an empty property.
+- #interrupt-cells: The number of cells to define the interrupts. It sould be 2.
+  The first cell is the IRQ number (aka "Peripheral IDentifier" on datasheet).
+  The second cell is used to specify flags:
+    bits[3:0] trigger type and level flags:
+      1 = low-to-high edge triggered.
+      2 = high-to-low edge triggered.
+      4 = active high level-sensitive.
+      8 = active low level-sensitive.
+      Valid combinations are 1, 2, 3, 4, 8.
+      Default flag for internal sources should be set to 4 (active high).
+- reg: Should contain AIC registers location and length
+
+Examples:
+       /*
+        * AIC
+        */
+       aic: interrupt-controller@fffff000 {
+               compatible = "atmel,at91rm9200-aic";
+               interrupt-controller;
+               interrupt-parent;
+               #interrupt-cells = <2>;
+               reg = <0xfffff000 0x200>;
+       };
+
+       /*
+        * An interrupt generating device that is wired to an AIC.
+        */
+       dma: dma-controller@ffffec00 {
+               compatible = "atmel,at91sam9g45-dma";
+               reg = <0xffffec00 0x200>;
+               interrupts = <21 4>;
+       };
diff --git a/Documentation/devicetree/bindings/arm/atmel-at91.txt b/Documentation/devicetree/bindings/arm/atmel-at91.txt
new file mode 100644 (file)
index 0000000..1aeaf6f
--- /dev/null
@@ -0,0 +1,32 @@
+Atmel AT91 device tree bindings.
+================================
+
+PIT Timer required properties:
+- compatible: Should be "atmel,at91sam9260-pit"
+- reg: Should contain registers location and length
+- interrupts: Should contain interrupt for the PIT which is the IRQ line
+  shared across all System Controller members.
+
+TC/TCLIB Timer required properties:
+- compatible: Should be "atmel,<chip>-pit".
+  <chip> can be "at91rm9200" or "at91sam9x5"
+- reg: Should contain registers location and length
+- interrupts: Should contain all interrupts for the TC block
+  Note that you can specify several interrupt cells if the TC
+  block has one interrupt per channel.
+
+Examples:
+
+One interrupt per TC block:
+       tcb0: timer@fff7c000 {
+               compatible = "atmel,at91rm9200-tcb";
+               reg = <0xfff7c000 0x100>;
+               interrupts = <18 4>;
+       };
+
+One interrupt per TC channel in a TC block:
+       tcb1: timer@fffdc000 {
+               compatible = "atmel,at91rm9200-tcb";
+               reg = <0xfffdc000 0x100>;
+               interrupts = <26 4 27 4 28 4>;
+       };
diff --git a/Documentation/devicetree/bindings/gpio/gpio_atmel.txt b/Documentation/devicetree/bindings/gpio/gpio_atmel.txt
new file mode 100644 (file)
index 0000000..66efc80
--- /dev/null
@@ -0,0 +1,20 @@
+* Atmel GPIO controller (PIO)
+
+Required properties:
+- compatible: "atmel,<chip>-gpio", where <chip> is at91rm9200 or at91sam9x5.
+- reg: Should contain GPIO controller registers location and length
+- interrupts: Should be the port interrupt shared by all the 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.
+
+Example:
+       pioA: gpio@fffff200 {
+               compatible = "atmel,at91rm9200-gpio";
+               reg = <0xfffff200 0x100>;
+               interrupts = <2 4>;
+               #gpio-cells = <2>;
+               gpio-controller;
+       };
+
index 92c9c79c140c83b14b7ee628ae077b76f4a86719..cabd8f556a1f71a2f87eddf166cadd5c02035b80 100644 (file)
@@ -322,6 +322,7 @@ config ARCH_AT91
        select ARCH_REQUIRE_GPIOLIB
        select HAVE_CLK
        select CLKDEV_LOOKUP
+       select IRQ_DOMAIN
        help
          This enables support for systems based on the Atmel AT91RM9200,
          AT91SAM9 processors.
index 07603b8c95037b10d85739e2dfcafc77d62be7c7..a100db03ec90f511dda6f9cbe45ea9ab96c73401 100644 (file)
                serial4 = &usart3;
                serial5 = &usart4;
                serial6 = &usart5;
+               gpio0 = &pioA;
+               gpio1 = &pioB;
+               gpio2 = &pioC;
+               tcb0 = &tcb0;
+               tcb1 = &tcb1;
        };
        cpus {
                cpu@0 {
                        ranges;
 
                        aic: interrupt-controller@fffff000 {
-                               #interrupt-cells = <1>;
+                               #interrupt-cells = <2>;
                                compatible = "atmel,at91rm9200-aic";
                                interrupt-controller;
                                interrupt-parent;
                                reg = <0xfffff000 0x200>;
                        };
 
+                       pit: timer@fffffd30 {
+                               compatible = "atmel,at91sam9260-pit";
+                               reg = <0xfffffd30 0xf>;
+                               interrupts = <1 4>;
+                       };
+
+                       tcb0: timer@fffa0000 {
+                               compatible = "atmel,at91rm9200-tcb";
+                               reg = <0xfffa0000 0x100>;
+                               interrupts = <17 4 18 4 19 4>;
+                       };
+
+                       tcb1: timer@fffdc000 {
+                               compatible = "atmel,at91rm9200-tcb";
+                               reg = <0xfffdc000 0x100>;
+                               interrupts = <26 4 27 4 28 4>;
+                       };
+
+                       pioA: gpio@fffff400 {
+                               compatible = "atmel,at91rm9200-gpio";
+                               reg = <0xfffff400 0x100>;
+                               interrupts = <2 4>;
+                               #gpio-cells = <2>;
+                               gpio-controller;
+                               interrupt-controller;
+                       };
+
+                       pioB: gpio@fffff600 {
+                               compatible = "atmel,at91rm9200-gpio";
+                               reg = <0xfffff600 0x100>;
+                               interrupts = <3 4>;
+                               #gpio-cells = <2>;
+                               gpio-controller;
+                               interrupt-controller;
+                       };
+
+                       pioC: gpio@fffff800 {
+                               compatible = "atmel,at91rm9200-gpio";
+                               reg = <0xfffff800 0x100>;
+                               interrupts = <4 4>;
+                               #gpio-cells = <2>;
+                               gpio-controller;
+                               interrupt-controller;
+                       };
+
                        dbgu: serial@fffff200 {
                                compatible = "atmel,at91sam9260-usart";
                                reg = <0xfffff200 0x200>;
-                               interrupts = <1>;
+                               interrupts = <1 4>;
                                status = "disabled";
                        };
 
                        usart0: serial@fffb0000 {
                                compatible = "atmel,at91sam9260-usart";
                                reg = <0xfffb0000 0x200>;
-                               interrupts = <6>;
+                               interrupts = <6 4>;
                                atmel,use-dma-rx;
                                atmel,use-dma-tx;
                                status = "disabled";
                        usart1: serial@fffb4000 {
                                compatible = "atmel,at91sam9260-usart";
                                reg = <0xfffb4000 0x200>;
-                               interrupts = <7>;
+                               interrupts = <7 4>;
                                atmel,use-dma-rx;
                                atmel,use-dma-tx;
                                status = "disabled";
                        usart2: serial@fffb8000 {
                                compatible = "atmel,at91sam9260-usart";
                                reg = <0xfffb8000 0x200>;
-                               interrupts = <8>;
+                               interrupts = <8 4>;
                                atmel,use-dma-rx;
                                atmel,use-dma-tx;
                                status = "disabled";
                        usart3: serial@fffd0000 {
                                compatible = "atmel,at91sam9260-usart";
                                reg = <0xfffd0000 0x200>;
-                               interrupts = <23>;
+                               interrupts = <23 4>;
                                atmel,use-dma-rx;
                                atmel,use-dma-tx;
                                status = "disabled";
                        usart4: serial@fffd4000 {
                                compatible = "atmel,at91sam9260-usart";
                                reg = <0xfffd4000 0x200>;
-                               interrupts = <24>;
+                               interrupts = <24 4>;
                                atmel,use-dma-rx;
                                atmel,use-dma-tx;
                                status = "disabled";
                        usart5: serial@fffd8000 {
                                compatible = "atmel,at91sam9260-usart";
                                reg = <0xfffd8000 0x200>;
-                               interrupts = <25>;
+                               interrupts = <25 4>;
                                atmel,use-dma-rx;
                                atmel,use-dma-tx;
                                status = "disabled";
                        macb0: ethernet@fffc4000 {
                                compatible = "cdns,at32ap7000-macb", "cdns,macb";
                                reg = <0xfffc4000 0x100>;
-                               interrupts = <21>;
+                               interrupts = <21 4>;
                                status = "disabled";
                        };
                };
index fffa005300a4274fa29e2c74e610333ae729ac11..f779667159b1aec4949d59c99c01e51f9a2bef43 100644 (file)
                serial2 = &usart1;
                serial3 = &usart2;
                serial4 = &usart3;
+               gpio0 = &pioA;
+               gpio1 = &pioB;
+               gpio2 = &pioC;
+               gpio3 = &pioD;
+               gpio4 = &pioE;
+               tcb0 = &tcb0;
+               tcb1 = &tcb1;
        };
        cpus {
                cpu@0 {
                        ranges;
 
                        aic: interrupt-controller@fffff000 {
-                               #interrupt-cells = <1>;
+                               #interrupt-cells = <2>;
                                compatible = "atmel,at91rm9200-aic";
                                interrupt-controller;
                                interrupt-parent;
                                reg = <0xfffff000 0x200>;
                        };
 
+                       pit: timer@fffffd30 {
+                               compatible = "atmel,at91sam9260-pit";
+                               reg = <0xfffffd30 0xf>;
+                               interrupts = <1 4>;
+                       };
+
+
+                       tcb0: timer@fff7c000 {
+                               compatible = "atmel,at91rm9200-tcb";
+                               reg = <0xfff7c000 0x100>;
+                               interrupts = <18 4>;
+                       };
+
+                       tcb1: timer@fffd4000 {
+                               compatible = "atmel,at91rm9200-tcb";
+                               reg = <0xfffd4000 0x100>;
+                               interrupts = <18 4>;
+                       };
+
                        dma: dma-controller@ffffec00 {
                                compatible = "atmel,at91sam9g45-dma";
                                reg = <0xffffec00 0x200>;
-                               interrupts = <21>;
+                               interrupts = <21 4>;
+                       };
+
+                       pioA: gpio@fffff200 {
+                               compatible = "atmel,at91rm9200-gpio";
+                               reg = <0xfffff200 0x100>;
+                               interrupts = <2 4>;
+                               #gpio-cells = <2>;
+                               gpio-controller;
+                               interrupt-controller;
+                       };
+
+                       pioB: gpio@fffff400 {
+                               compatible = "atmel,at91rm9200-gpio";
+                               reg = <0xfffff400 0x100>;
+                               interrupts = <3 4>;
+                               #gpio-cells = <2>;
+                               gpio-controller;
+                               interrupt-controller;
+                       };
+
+                       pioC: gpio@fffff600 {
+                               compatible = "atmel,at91rm9200-gpio";
+                               reg = <0xfffff600 0x100>;
+                               interrupts = <4 4>;
+                               #gpio-cells = <2>;
+                               gpio-controller;
+                               interrupt-controller;
+                       };
+
+                       pioD: gpio@fffff800 {
+                               compatible = "atmel,at91rm9200-gpio";
+                               reg = <0xfffff800 0x100>;
+                               interrupts = <5 4>;
+                               #gpio-cells = <2>;
+                               gpio-controller;
+                               interrupt-controller;
+                       };
+
+                       pioE: gpio@fffffa00 {
+                               compatible = "atmel,at91rm9200-gpio";
+                               reg = <0xfffffa00 0x100>;
+                               interrupts = <5 4>;
+                               #gpio-cells = <2>;
+                               gpio-controller;
+                               interrupt-controller;
                        };
 
                        dbgu: serial@ffffee00 {
                                compatible = "atmel,at91sam9260-usart";
                                reg = <0xffffee00 0x200>;
-                               interrupts = <1>;
+                               interrupts = <1 4>;
                                status = "disabled";
                        };
 
                        usart0: serial@fff8c000 {
                                compatible = "atmel,at91sam9260-usart";
                                reg = <0xfff8c000 0x200>;
-                               interrupts = <7>;
+                               interrupts = <7 4>;
                                atmel,use-dma-rx;
                                atmel,use-dma-tx;
                                status = "disabled";
                        usart1: serial@fff90000 {
                                compatible = "atmel,at91sam9260-usart";
                                reg = <0xfff90000 0x200>;
-                               interrupts = <8>;
+                               interrupts = <8 4>;
                                atmel,use-dma-rx;
                                atmel,use-dma-tx;
                                status = "disabled";
                        usart2: serial@fff94000 {
                                compatible = "atmel,at91sam9260-usart";
                                reg = <0xfff94000 0x200>;
-                               interrupts = <9>;
+                               interrupts = <9 4>;
                                atmel,use-dma-rx;
                                atmel,use-dma-tx;
                                status = "disabled";
                        usart3: serial@fff98000 {
                                compatible = "atmel,at91sam9260-usart";
                                reg = <0xfff98000 0x200>;
-                               interrupts = <10>;
+                               interrupts = <10 4>;
                                atmel,use-dma-rx;
                                atmel,use-dma-tx;
                                status = "disabled";
                        macb0: ethernet@fffbc000 {
                                compatible = "cdns,at32ap7000-macb", "cdns,macb";
                                reg = <0xfffbc000 0x100>;
-                               interrupts = <25>;
+                               interrupts = <25 4>;
                                status = "disabled";
                        };
                };
index a387e7704ce1e42d2647a19a85311668507a861d..15e25f903cadad9b47a570c0e7edc3216ce2fa36 100644 (file)
                        };
                };
        };
+
+       leds {
+               compatible = "gpio-leds";
+
+               d8 {
+                       label = "d8";
+                       gpios = <&pioD 30 0>;
+                       linux,default-trigger = "heartbeat";
+               };
+
+               d6 {
+                       label = "d6";
+                       gpios = <&pioD 0 1>;
+                       linux,default-trigger = "nand-disk";
+               };
+
+               d7 {
+                       label = "d7";
+                       gpios = <&pioD 31 1>;
+                       linux,default-trigger = "mmc0";
+               };
+       };
+
+       gpio_keys {
+               compatible = "gpio-keys";
+               #address-cells = <1>;
+               #size-cells = <0>;
+
+               left_click {
+                       label = "left_click";
+                       gpios = <&pioB 6 1>;
+                       linux,code = <272>;
+                       gpio-key,wakeup;
+               };
+
+               right_click {
+                       label = "right_click";
+                       gpios = <&pioB 7 1>;
+                       linux,code = <273>;
+                       gpio-key,wakeup;
+               };
+
+               left {
+                       label = "Joystick Left";
+                       gpios = <&pioB 14 1>;
+                       linux,code = <105>;
+               };
+
+               right {
+                       label = "Joystick Right";
+                       gpios = <&pioB 15 1>;
+                       linux,code = <106>;
+               };
+
+               up {
+                       label = "Joystick Up";
+                       gpios = <&pioB 16 1>;
+                       linux,code = <103>;
+               };
+
+               down {
+                       label = "Joystick Down";
+                       gpios = <&pioB 17 1>;
+                       linux,code = <108>;
+               };
+
+               enter {
+                       label = "Joystick Press";
+                       gpios = <&pioB 18 1>;
+                       linux,code = <28>;
+               };
+       };
 };
index e91391f50730d8d686c98c6578d8bfac0689509b..a02e636d8a5751f2d7fb46570d2ddc6969071f95 100644 (file)
                        };
 
                        pioA: gpio@fffff400 {
-                               compatible = "atmel,at91rm9200-gpio";
+                               compatible = "atmel,at91sam9x5-gpio", "atmel,at91rm9200-gpio";
                                reg = <0xfffff400 0x100>;
                                interrupts = <2 4>;
                                #gpio-cells = <2>;
                                gpio-controller;
+                               interrupt-controller;
                        };
 
                        pioB: gpio@fffff600 {
-                               compatible = "atmel,at91rm9200-gpio";
+                               compatible = "atmel,at91sam9x5-gpio", "atmel,at91rm9200-gpio";
                                reg = <0xfffff600 0x100>;
                                interrupts = <2 4>;
                                #gpio-cells = <2>;
                                gpio-controller;
+                               interrupt-controller;
                        };
 
                        pioC: gpio@fffff800 {
-                               compatible = "atmel,at91rm9200-gpio";
+                               compatible = "atmel,at91sam9x5-gpio", "atmel,at91rm9200-gpio";
                                reg = <0xfffff800 0x100>;
                                interrupts = <3 4>;
                                #gpio-cells = <2>;
                                gpio-controller;
+                               interrupt-controller;
                        };
 
                        pioD: gpio@fffffa00 {
-                               compatible = "atmel,at91rm9200-gpio";
+                               compatible = "atmel,at91sam9x5-gpio", "atmel,at91rm9200-gpio";
                                reg = <0xfffffa00 0x100>;
                                interrupts = <3 4>;
                                #gpio-cells = <2>;
                                gpio-controller;
+                               interrupt-controller;
                        };
 
                        dbgu: serial@fffff200 {
index 4ab5a77f4afca0518e846e37c22d86128c96d318..64ae3e890259e56ed7ab626b8e402620ab2990bb 100644 (file)
        memory@20000000 {
                reg = <0x20000000 0x8000000>;
        };
+
+       leds {
+               compatible = "gpio-leds";
+
+               pb18 {
+                       label = "pb18";
+                       gpios = <&pioB 18 1>;
+                       linux,default-trigger = "heartbeat";
+               };
+
+               pd21 {
+                       label = "pd21";
+                       gpios = <&pioD 21 0>;
+               };
+       };
 };
index f04b535477f54b5e63c688ab3294d9c826192eae..d74545a2a77cfa8cc9373c5e12e423b4ef8c0b9e 100644 (file)
                        };
                };
        };
+
+       leds {
+               compatible = "gpio-leds";
+
+               user_led {
+                       label = "user_led";
+                       gpios = <&pioB 21 1>;
+                       linux,default-trigger = "heartbeat";
+               };
+       };
+
+       gpio_keys {
+               compatible = "gpio-keys";
+               #address-cells = <1>;
+               #size-cells = <0>;
+
+               user_pb {
+                       label = "user_pb";
+                       gpios = <&pioB 10 1>;
+                       linux,code = <28>;
+                       gpio-key,wakeup;
+               };
+       };
 };
index 1b6518518d99e4e9c0ba2fddff74fb62ae766060..8512e53bed9356afb310849b7f976f895c6076d1 100644 (file)
@@ -20,7 +20,7 @@ obj-$(CONFIG_ARCH_AT91SAM9263)        += at91sam9263.o at91sam926x_time.o at91sam9263_d
 obj-$(CONFIG_ARCH_AT91SAM9RL)  += at91sam9rl.o at91sam926x_time.o at91sam9rl_devices.o sam9_smc.o
 obj-$(CONFIG_ARCH_AT91SAM9G20) += at91sam9260.o at91sam926x_time.o at91sam9260_devices.o sam9_smc.o
 obj-$(CONFIG_ARCH_AT91SAM9G45) += at91sam9g45.o at91sam926x_time.o at91sam9g45_devices.o sam9_smc.o
-obj-$(CONFIG_ARCH_AT91SAM9X5)  += at91sam9x5.o at91sam926x_time.o
+obj-$(CONFIG_ARCH_AT91SAM9X5)  += at91sam9x5.o at91sam926x_time.o sam9_smc.o
 obj-$(CONFIG_ARCH_AT91X40)     += at91x40.o at91x40_time.o
 
 # AT91RM9200 board-specific support
index 4ade265be805f97e6cca0c40cc8e509bbdcdeabc..14b5a9c9a5144c2b36215ab139596bae9a739bd5 100644 (file)
@@ -209,6 +209,13 @@ static struct clk_lookup periph_clocks_lookups[] = {
        CLKDEV_CON_DEV_ID("usart", "fffd0000.serial", &usart3_clk),
        CLKDEV_CON_DEV_ID("usart", "fffd4000.serial", &usart4_clk),
        CLKDEV_CON_DEV_ID("usart", "fffd8000.serial", &usart5_clk),
+       /* more tc lookup table for DT entries */
+       CLKDEV_CON_DEV_ID("t0_clk", "fffa0000.timer", &tc0_clk),
+       CLKDEV_CON_DEV_ID("t1_clk", "fffa0000.timer", &tc1_clk),
+       CLKDEV_CON_DEV_ID("t2_clk", "fffa0000.timer", &tc2_clk),
+       CLKDEV_CON_DEV_ID("t0_clk", "fffdc000.timer", &tc3_clk),
+       CLKDEV_CON_DEV_ID("t1_clk", "fffdc000.timer", &tc4_clk),
+       CLKDEV_CON_DEV_ID("t2_clk", "fffdc000.timer", &tc5_clk),
        /* fake hclk clock */
        CLKDEV_CON_DEV_ID("hclk", "at91_ohci", &ohci_clk),
        CLKDEV_CON_ID("pioA", &pioA_clk),
index 40f6aeaea043e27bc51214b93512dcc0eaddd4fd..7e5651ee9f859f9689b76f07ca5bc834d3aa871a 100644 (file)
@@ -642,7 +642,7 @@ void __init at91_add_device_spi(struct spi_board_info *devices, int nr_devices)
 static struct resource tcb0_resources[] = {
        [0] = {
                .start  = AT91SAM9260_BASE_TCB0,
-               .end    = AT91SAM9260_BASE_TCB0 + SZ_16K - 1,
+               .end    = AT91SAM9260_BASE_TCB0 + SZ_256 - 1,
                .flags  = IORESOURCE_MEM,
        },
        [1] = {
@@ -672,7 +672,7 @@ static struct platform_device at91sam9260_tcb0_device = {
 static struct resource tcb1_resources[] = {
        [0] = {
                .start  = AT91SAM9260_BASE_TCB1,
-               .end    = AT91SAM9260_BASE_TCB1 + SZ_16K - 1,
+               .end    = AT91SAM9260_BASE_TCB1 + SZ_256 - 1,
                .flags  = IORESOURCE_MEM,
        },
        [1] = {
@@ -699,8 +699,25 @@ static struct platform_device at91sam9260_tcb1_device = {
        .num_resources  = ARRAY_SIZE(tcb1_resources),
 };
 
+#if defined(CONFIG_OF)
+static struct of_device_id tcb_ids[] = {
+       { .compatible = "atmel,at91rm9200-tcb" },
+       { /*sentinel*/ }
+};
+#endif
+
 static void __init at91_add_device_tc(void)
 {
+#if defined(CONFIG_OF)
+       struct device_node *np;
+
+       np = of_find_matching_node(NULL, tcb_ids);
+       if (np) {
+               of_node_put(np);
+               return;
+       }
+#endif
+
        platform_device_register(&at91sam9260_tcb0_device);
        platform_device_register(&at91sam9260_tcb1_device);
 }
index d89ead740a99756b51492064eb7b3922226526e2..a94758b42737a3d33a3cdce0bee439103ea8f7ab 100644 (file)
@@ -14,6 +14,9 @@
 #include <linux/kernel.h>
 #include <linux/clk.h>
 #include <linux/clockchips.h>
+#include <linux/of.h>
+#include <linux/of_address.h>
+#include <linux/of_irq.h>
 
 #include <asm/mach/time.h>
 
@@ -133,7 +136,8 @@ static irqreturn_t at91sam926x_pit_interrupt(int irq, void *dev_id)
 static struct irqaction at91sam926x_pit_irq = {
        .name           = "at91_tick",
        .flags          = IRQF_SHARED | IRQF_DISABLED | IRQF_TIMER | IRQF_IRQPOLL,
-       .handler        = at91sam926x_pit_interrupt
+       .handler        = at91sam926x_pit_interrupt,
+       .irq            = AT91_ID_SYS,
 };
 
 static void at91sam926x_pit_reset(void)
@@ -149,6 +153,51 @@ static void at91sam926x_pit_reset(void)
        pit_write(AT91_PIT_MR, (pit_cycle - 1) | AT91_PIT_PITEN);
 }
 
+#ifdef CONFIG_OF
+static struct of_device_id pit_timer_ids[] = {
+       { .compatible = "atmel,at91sam9260-pit" },
+       { /* sentinel */ }
+};
+
+static int __init of_at91sam926x_pit_init(void)
+{
+       struct device_node      *np;
+       int                     ret;
+
+       np = of_find_matching_node(NULL, pit_timer_ids);
+       if (!np)
+               goto err;
+
+       pit_base_addr = of_iomap(np, 0);
+       if (!pit_base_addr)
+               goto node_err;
+
+       /* Get the interrupts property */
+       ret = irq_of_parse_and_map(np, 0);
+       if (!ret) {
+               pr_crit("AT91: PIT: Unable to get IRQ from DT\n");
+               goto ioremap_err;
+       }
+       at91sam926x_pit_irq.irq = ret;
+
+       of_node_put(np);
+
+       return 0;
+
+ioremap_err:
+       iounmap(pit_base_addr);
+node_err:
+       of_node_put(np);
+err:
+       return -EINVAL;
+}
+#else
+static int __init of_at91sam926x_pit_init(void)
+{
+       return -EINVAL;
+}
+#endif
+
 /*
  * Set up both clocksource and clockevent support.
  */
@@ -156,6 +205,10 @@ static void __init at91sam926x_pit_init(void)
 {
        unsigned long   pit_rate;
        unsigned        bits;
+       int             ret;
+
+       /* For device tree enabled device: initialize here */
+       of_at91sam926x_pit_init();
 
        /*
         * Use our actual MCK to figure out how many MCK/16 ticks per
@@ -177,7 +230,9 @@ static void __init at91sam926x_pit_init(void)
        clocksource_register_hz(&pit_clk, pit_rate);
 
        /* Set up irq handler */
-       setup_irq(AT91_ID_SYS, &at91sam926x_pit_irq);
+       ret = setup_irq(at91sam926x_pit_irq.irq, &at91sam926x_pit_irq);
+       if (ret)
+               pr_crit("AT91: PIT: Unable to setup IRQ\n");
 
        /* Set up and register clockevents */
        pit_clkevt.mult = div_sc(pit_rate, NSEC_PER_SEC, pit_clkevt.shift);
@@ -193,6 +248,15 @@ static void at91sam926x_pit_suspend(void)
 
 void __init at91sam926x_ioremap_pit(u32 addr)
 {
+#if defined(CONFIG_OF)
+       struct device_node *np =
+               of_find_matching_node(NULL, pit_timer_ids);
+
+       if (np) {
+               of_node_put(np);
+               return;
+       }
+#endif
        pit_base_addr = ioremap(addr, 16);
 
        if (!pit_base_addr)
index a41622ea61b848676d59ae2f388111a648c0d9d6..0014573dfe17cb293e1b303c52781de7c69d03c3 100644 (file)
@@ -229,6 +229,9 @@ static struct clk_lookup periph_clocks_lookups[] = {
        CLKDEV_CON_DEV_ID("usart", "fff90000.serial", &usart1_clk),
        CLKDEV_CON_DEV_ID("usart", "fff94000.serial", &usart2_clk),
        CLKDEV_CON_DEV_ID("usart", "fff98000.serial", &usart3_clk),
+       /* more tc lookup table for DT entries */
+       CLKDEV_CON_DEV_ID("t0_clk", "fff7c000.timer", &tcb0_clk),
+       CLKDEV_CON_DEV_ID("t0_clk", "fffd4000.timer", &tcb0_clk),
        /* fake hclk clock */
        CLKDEV_CON_DEV_ID("hclk", "at91_ohci", &uhphs_clk),
        CLKDEV_CON_ID("pioA", &pioA_clk),
index 410829532aabdb99722f0ad5155affa6d3020703..4320b2096789c73a4c5110af51324472f80890c4 100644 (file)
@@ -1052,7 +1052,7 @@ void __init at91_add_device_lcdc(struct atmel_lcdfb_info *data) {}
 static struct resource tcb0_resources[] = {
        [0] = {
                .start  = AT91SAM9G45_BASE_TCB0,
-               .end    = AT91SAM9G45_BASE_TCB0 + SZ_16K - 1,
+               .end    = AT91SAM9G45_BASE_TCB0 + SZ_256 - 1,
                .flags  = IORESOURCE_MEM,
        },
        [1] = {
@@ -1073,7 +1073,7 @@ static struct platform_device at91sam9g45_tcb0_device = {
 static struct resource tcb1_resources[] = {
        [0] = {
                .start  = AT91SAM9G45_BASE_TCB1,
-               .end    = AT91SAM9G45_BASE_TCB1 + SZ_16K - 1,
+               .end    = AT91SAM9G45_BASE_TCB1 + SZ_256 - 1,
                .flags  = IORESOURCE_MEM,
        },
        [1] = {
@@ -1090,8 +1090,25 @@ static struct platform_device at91sam9g45_tcb1_device = {
        .num_resources  = ARRAY_SIZE(tcb1_resources),
 };
 
+#if defined(CONFIG_OF)
+static struct of_device_id tcb_ids[] = {
+       { .compatible = "atmel,at91rm9200-tcb" },
+       { /*sentinel*/ }
+};
+#endif
+
 static void __init at91_add_device_tc(void)
 {
+#if defined(CONFIG_OF)
+       struct device_node *np;
+
+       np = of_find_matching_node(NULL, tcb_ids);
+       if (np) {
+               of_node_put(np);
+               return;
+       }
+#endif
+
        platform_device_register(&at91sam9g45_tcb0_device);
        platform_device_register(&at91sam9g45_tcb1_device);
 }
index d17d4262665b6bd2621ab99eb02f5f1f415569ef..a34d96afa746ff6f45815d0503d2756ae7dd0f75 100644 (file)
@@ -301,8 +301,6 @@ static void __init at91sam9x5_map_io(void)
 
 static void __init at91sam9x5_ioremap_registers(void)
 {
-       if (of_at91sam926x_pit_init() < 0)
-               panic("Impossible to find PIT\n");
        at91_ioremap_ramc(0, AT91SAM9X5_BASE_DDRSDRC0, 512);
 }
 
index 08c8ad8609b701e4a9d4220495e29e71114d2d20..583b72472ad99f7ee9ee58e48382aa164c7c6bcc 100644 (file)
@@ -15,7 +15,7 @@
 #include <linux/init.h>
 #include <linux/module.h>
 #include <linux/gpio.h>
-#include <linux/irqdomain.h>
+#include <linux/of.h>
 #include <linux/of_irq.h>
 #include <linux/of_platform.h>
 
@@ -82,15 +82,17 @@ static void __init ek_add_device_nand(void)
        at91_add_device_nand(&ek_nand_data);
 }
 
-static const struct of_device_id aic_of_match[] __initconst = {
-       { .compatible = "atmel,at91rm9200-aic", },
-       {},
+static const struct of_device_id irq_of_match[] __initconst = {
+
+       { .compatible = "atmel,at91rm9200-aic", .data = at91_aic_of_init },
+       { .compatible = "atmel,at91rm9200-gpio", .data = at91_gpio_of_irq_setup },
+       { .compatible = "atmel,at91sam9x5-gpio", .data = at91_gpio_of_irq_setup },
+       { /*sentinel*/ }
 };
 
 static void __init at91_dt_init_irq(void)
 {
-       irq_domain_generate_simple(aic_of_match, 0xfffff000, 0);
-       at91_init_irq_default();
+       of_irq_init(irq_of_match);
 }
 
 static void __init at91_dt_device_init(void)
index 4770db08e5a6c1895b52794d02eba84b499da56c..3c2e3fcc310c09668f10555dbdc1a530a35dd89f 100644 (file)
@@ -145,11 +145,11 @@ static struct i2c_board_info __initdata snapper9260_i2c_devices[] = {
                /* Audio codec */
                I2C_BOARD_INFO("tlv320aic23", 0x1a),
        },
-       {
+};
+
+static struct i2c_board_info __initdata snapper9260_i2c_isl1208 = {
                /* RTC */
                I2C_BOARD_INFO("isl1208", 0x6f),
-               .irq = gpio_to_irq(AT91_PIN_PA31),
-       },
 };
 
 static void __init snapper9260_add_device_nand(void)
@@ -163,6 +163,10 @@ static void __init snapper9260_board_init(void)
 {
        at91_add_device_i2c(snapper9260_i2c_devices,
                            ARRAY_SIZE(snapper9260_i2c_devices));
+
+       snapper9260_i2c_isl1208.irq = gpio_to_irq(AT91_PIN_PA31);
+       i2c_register_board_info(0, &snapper9260_i2c_isl1208, 1);
+
        at91_add_device_serial();
        at91_add_device_usbh(&snapper9260_usbh_data);
        at91_add_device_udc(&snapper9260_udc_data);
index 4cad85e574701904b1b40b4584722896097c074b..459f01a4a54699755eda4a2601d3b7562c963335 100644 (file)
@@ -9,6 +9,7 @@
  */
 
 #include <linux/clkdev.h>
+#include <linux/of.h>
 
  /* Map io */
 extern void __init at91_map_io(void);
@@ -25,6 +26,9 @@ extern void __init at91_init_irq_default(void);
 extern void __init at91_init_interrupts(unsigned int priority[]);
 extern void __init at91x40_init_interrupts(unsigned int priority[]);
 extern void __init at91_aic_init(unsigned int priority[]);
+extern int  __init at91_aic_of_init(struct device_node *node,
+                                   struct device_node *parent);
+
 
  /* Timer */
 struct sys_timer;
@@ -84,5 +88,7 @@ struct at91_gpio_bank {
 };
 extern void __init at91_gpio_init(struct at91_gpio_bank *, int nr_banks);
 extern void __init at91_gpio_irq_setup(void);
+extern int  __init at91_gpio_of_irq_setup(struct device_node *node,
+                                         struct device_node *parent);
 
 extern int at91_extern_irq;
index 74d6783eeabbb976c4261d299fcfe11b70d83984..325837a264c930fdbe1787d3ed2e61d3f75d1772 100644 (file)
@@ -11,6 +11,7 @@
 
 #include <linux/clk.h>
 #include <linux/errno.h>
+#include <linux/device.h>
 #include <linux/gpio.h>
 #include <linux/interrupt.h>
 #include <linux/irq.h>
 #include <linux/list.h>
 #include <linux/module.h>
 #include <linux/io.h>
+#include <linux/irqdomain.h>
+#include <linux/of_address.h>
+#include <linux/of_irq.h>
+#include <linux/of_gpio.h>
 
 #include <mach/hardware.h>
 #include <mach/at91_pio.h>
 struct at91_gpio_chip {
        struct gpio_chip        chip;
        struct at91_gpio_chip   *next;          /* Bank sharing same clock */
-       int                     id;             /* ID of register bank */
-       void __iomem            *regbase;       /* Base of register bank */
+       int                     pioc_hwirq;     /* PIO bank interrupt identifier on AIC */
+       int                     pioc_virq;      /* PIO bank Linux virtual interrupt */
+       int                     pioc_idx;       /* PIO bank index */
+       void __iomem            *regbase;       /* PIO bank virtual address */
        struct clk              *clock;         /* associated clock */
+       struct irq_domain       *domain;        /* associated irq domain */
 };
 
 #define to_at91_gpio_chip(c) container_of(c, struct at91_gpio_chip, chip)
@@ -43,8 +51,9 @@ static int at91_gpiolib_direction_output(struct gpio_chip *chip,
                                         unsigned offset, int val);
 static int at91_gpiolib_direction_input(struct gpio_chip *chip,
                                        unsigned offset);
+static int at91_gpiolib_to_irq(struct gpio_chip *chip, unsigned offset);
 
-#define AT91_GPIO_CHIP(name, base_gpio, nr_gpio)                       \
+#define AT91_GPIO_CHIP(name, nr_gpio)                                  \
        {                                                               \
                .chip = {                                               \
                        .label            = name,                       \
@@ -53,20 +62,28 @@ static int at91_gpiolib_direction_input(struct gpio_chip *chip,
                        .get              = at91_gpiolib_get,           \
                        .set              = at91_gpiolib_set,           \
                        .dbg_show         = at91_gpiolib_dbg_show,      \
-                       .base             = base_gpio,                  \
+                       .to_irq           = at91_gpiolib_to_irq,        \
                        .ngpio            = nr_gpio,                    \
                },                                                      \
        }
 
 static struct at91_gpio_chip gpio_chip[] = {
-       AT91_GPIO_CHIP("pioA", 0x00, 32),
-       AT91_GPIO_CHIP("pioB", 0x20, 32),
-       AT91_GPIO_CHIP("pioC", 0x40, 32),
-       AT91_GPIO_CHIP("pioD", 0x60, 32),
-       AT91_GPIO_CHIP("pioE", 0x80, 32),
+       AT91_GPIO_CHIP("pioA", 32),
+       AT91_GPIO_CHIP("pioB", 32),
+       AT91_GPIO_CHIP("pioC", 32),
+       AT91_GPIO_CHIP("pioD", 32),
+       AT91_GPIO_CHIP("pioE", 32),
 };
 
 static int gpio_banks;
+static unsigned long at91_gpio_caps;
+
+/* All PIO controllers support PIO3 features */
+#define AT91_GPIO_CAP_PIO3     (1 <<  0)
+
+#define has_pio3()     (at91_gpio_caps & AT91_GPIO_CAP_PIO3)
+
+/*--------------------------------------------------------------------------*/
 
 static inline void __iomem *pin_to_controller(unsigned pin)
 {
@@ -83,6 +100,25 @@ static inline unsigned pin_to_mask(unsigned pin)
 }
 
 
+static char peripheral_function(void __iomem *pio, unsigned mask)
+{
+       char    ret = 'X';
+       u8      select;
+
+       if (pio) {
+               if (has_pio3()) {
+                       select = !!(__raw_readl(pio + PIO_ABCDSR1) & mask);
+                       select |= (!!(__raw_readl(pio + PIO_ABCDSR2) & mask) << 1);
+                       ret = 'A' + select;
+               } else {
+                       ret = __raw_readl(pio + PIO_ABSR) & mask ?
+                                                       'B' : 'A';
+               }
+       }
+
+       return ret;
+}
+
 /*--------------------------------------------------------------------------*/
 
 /* Not all hardware capabilities are exposed through these calls; they
@@ -130,7 +166,14 @@ int __init_or_module at91_set_A_periph(unsigned pin, int use_pullup)
 
        __raw_writel(mask, pio + PIO_IDR);
        __raw_writel(mask, pio + (use_pullup ? PIO_PUER : PIO_PUDR));
-       __raw_writel(mask, pio + PIO_ASR);
+       if (has_pio3()) {
+               __raw_writel(__raw_readl(pio + PIO_ABCDSR1) & ~mask,
+                                                       pio + PIO_ABCDSR1);
+               __raw_writel(__raw_readl(pio + PIO_ABCDSR2) & ~mask,
+                                                       pio + PIO_ABCDSR2);
+       } else {
+               __raw_writel(mask, pio + PIO_ASR);
+       }
        __raw_writel(mask, pio + PIO_PDR);
        return 0;
 }
@@ -150,7 +193,14 @@ int __init_or_module at91_set_B_periph(unsigned pin, int use_pullup)
 
        __raw_writel(mask, pio + PIO_IDR);
        __raw_writel(mask, pio + (use_pullup ? PIO_PUER : PIO_PUDR));
-       __raw_writel(mask, pio + PIO_BSR);
+       if (has_pio3()) {
+               __raw_writel(__raw_readl(pio + PIO_ABCDSR1) | mask,
+                                                       pio + PIO_ABCDSR1);
+               __raw_writel(__raw_readl(pio + PIO_ABCDSR2) & ~mask,
+                                                       pio + PIO_ABCDSR2);
+       } else {
+               __raw_writel(mask, pio + PIO_BSR);
+       }
        __raw_writel(mask, pio + PIO_PDR);
        return 0;
 }
@@ -158,8 +208,50 @@ EXPORT_SYMBOL(at91_set_B_periph);
 
 
 /*
- * mux the pin to the gpio controller (instead of "A" or "B" peripheral), and
- * configure it for an input.
+ * mux the pin to the "C" internal peripheral role.
+ */
+int __init_or_module at91_set_C_periph(unsigned pin, int use_pullup)
+{
+       void __iomem    *pio = pin_to_controller(pin);
+       unsigned        mask = pin_to_mask(pin);
+
+       if (!pio || !has_pio3())
+               return -EINVAL;
+
+       __raw_writel(mask, pio + PIO_IDR);
+       __raw_writel(mask, pio + (use_pullup ? PIO_PUER : PIO_PUDR));
+       __raw_writel(__raw_readl(pio + PIO_ABCDSR1) & ~mask, pio + PIO_ABCDSR1);
+       __raw_writel(__raw_readl(pio + PIO_ABCDSR2) | mask, pio + PIO_ABCDSR2);
+       __raw_writel(mask, pio + PIO_PDR);
+       return 0;
+}
+EXPORT_SYMBOL(at91_set_C_periph);
+
+
+/*
+ * mux the pin to the "D" internal peripheral role.
+ */
+int __init_or_module at91_set_D_periph(unsigned pin, int use_pullup)
+{
+       void __iomem    *pio = pin_to_controller(pin);
+       unsigned        mask = pin_to_mask(pin);
+
+       if (!pio || !has_pio3())
+               return -EINVAL;
+
+       __raw_writel(mask, pio + PIO_IDR);
+       __raw_writel(mask, pio + (use_pullup ? PIO_PUER : PIO_PUDR));
+       __raw_writel(__raw_readl(pio + PIO_ABCDSR1) | mask, pio + PIO_ABCDSR1);
+       __raw_writel(__raw_readl(pio + PIO_ABCDSR2) | mask, pio + PIO_ABCDSR2);
+       __raw_writel(mask, pio + PIO_PDR);
+       return 0;
+}
+EXPORT_SYMBOL(at91_set_D_periph);
+
+
+/*
+ * mux the pin to the gpio controller (instead of "A", "B", "C"
+ * or "D" peripheral), and configure it for an input.
  */
 int __init_or_module at91_set_gpio_input(unsigned pin, int use_pullup)
 {
@@ -179,8 +271,8 @@ EXPORT_SYMBOL(at91_set_gpio_input);
 
 
 /*
- * mux the pin to the gpio controller (instead of "A" or "B" peripheral),
- * and configure it for an output.
+ * mux the pin to the gpio controller (instead of "A", "B", "C"
+ * or "D" peripheral), and configure it for an output.
  */
 int __init_or_module at91_set_gpio_output(unsigned pin, int value)
 {
@@ -210,11 +302,36 @@ int __init_or_module at91_set_deglitch(unsigned pin, int is_on)
 
        if (!pio)
                return -EINVAL;
+
+       if (has_pio3() && is_on)
+               __raw_writel(mask, pio + PIO_IFSCDR);
        __raw_writel(mask, pio + (is_on ? PIO_IFER : PIO_IFDR));
        return 0;
 }
 EXPORT_SYMBOL(at91_set_deglitch);
 
+/*
+ * enable/disable the debounce filter;
+ */
+int __init_or_module at91_set_debounce(unsigned pin, int is_on, int div)
+{
+       void __iomem    *pio = pin_to_controller(pin);
+       unsigned        mask = pin_to_mask(pin);
+
+       if (!pio || !has_pio3())
+               return -EINVAL;
+
+       if (is_on) {
+               __raw_writel(mask, pio + PIO_IFSCER);
+               __raw_writel(div & PIO_SCDR_DIV, pio + PIO_SCDR);
+               __raw_writel(mask, pio + PIO_IFER);
+       } else {
+               __raw_writel(mask, pio + PIO_IFDR);
+       }
+       return 0;
+}
+EXPORT_SYMBOL(at91_set_debounce);
+
 /*
  * enable/disable the multi-driver; This is only valid for output and
  * allows the output pin to run as an open collector output.
@@ -232,6 +349,41 @@ int __init_or_module at91_set_multi_drive(unsigned pin, int is_on)
 }
 EXPORT_SYMBOL(at91_set_multi_drive);
 
+/*
+ * enable/disable the pull-down.
+ * If pull-up already enabled while calling the function, we disable it.
+ */
+int __init_or_module at91_set_pulldown(unsigned pin, int is_on)
+{
+       void __iomem    *pio = pin_to_controller(pin);
+       unsigned        mask = pin_to_mask(pin);
+
+       if (!pio || !has_pio3())
+               return -EINVAL;
+
+       /* Disable pull-up anyway */
+       __raw_writel(mask, pio + PIO_PUDR);
+       __raw_writel(mask, pio + (is_on ? PIO_PPDER : PIO_PPDDR));
+       return 0;
+}
+EXPORT_SYMBOL(at91_set_pulldown);
+
+/*
+ * disable Schmitt trigger
+ */
+int __init_or_module at91_disable_schmitt_trig(unsigned pin)
+{
+       void __iomem    *pio = pin_to_controller(pin);
+       unsigned        mask = pin_to_mask(pin);
+
+       if (!pio || !has_pio3())
+               return -EINVAL;
+
+       __raw_writel(__raw_readl(pio + PIO_SCHMITT) | mask, pio + PIO_SCHMITT);
+       return 0;
+}
+EXPORT_SYMBOL(at91_disable_schmitt_trig);
+
 /*
  * assuming the pin is muxed as a gpio output, set its value.
  */
@@ -273,9 +425,9 @@ static u32 backups[MAX_GPIO_BANKS];
 
 static int gpio_irq_set_wake(struct irq_data *d, unsigned state)
 {
-       unsigned        pin = irq_to_gpio(d->irq);
-       unsigned        mask = pin_to_mask(pin);
-       unsigned        bank = pin / 32;
+       struct at91_gpio_chip *at91_gpio = irq_data_get_irq_chip_data(d);
+       unsigned        mask = 1 << d->hwirq;
+       unsigned        bank = at91_gpio->pioc_idx;
 
        if (unlikely(bank >= MAX_GPIO_BANKS))
                return -EINVAL;
@@ -285,7 +437,7 @@ static int gpio_irq_set_wake(struct irq_data *d, unsigned state)
        else
                wakeups[bank] &= ~mask;
 
-       irq_set_irq_wake(gpio_chip[bank].id, state);
+       irq_set_irq_wake(at91_gpio->pioc_virq, state);
 
        return 0;
 }
@@ -301,9 +453,10 @@ void at91_gpio_suspend(void)
                __raw_writel(backups[i], pio + PIO_IDR);
                __raw_writel(wakeups[i], pio + PIO_IER);
 
-               if (!wakeups[i])
+               if (!wakeups[i]) {
+                       clk_unprepare(gpio_chip[i].clock);
                        clk_disable(gpio_chip[i].clock);
-               else {
+               else {
 #ifdef CONFIG_PM_DEBUG
                        printk(KERN_DEBUG "GPIO-%c may wake for %08x\n", 'A'+i, wakeups[i]);
 #endif
@@ -318,8 +471,10 @@ void at91_gpio_resume(void)
        for (i = 0; i < gpio_banks; i++) {
                void __iomem    *pio = gpio_chip[i].regbase;
 
-               if (!wakeups[i])
-                       clk_enable(gpio_chip[i].clock);
+               if (!wakeups[i]) {
+                       if (clk_prepare(gpio_chip[i].clock) == 0)
+                               clk_enable(gpio_chip[i].clock);
+               }
 
                __raw_writel(wakeups[i], pio + PIO_IDR);
                __raw_writel(backups[i], pio + PIO_IER);
@@ -335,7 +490,10 @@ void at91_gpio_resume(void)
  * To use any AT91_PIN_* as an externally triggered IRQ, first call
  * at91_set_gpio_input() then maybe enable its glitch filter.
  * Then just request_irq() with the pin ID; it works like any ARM IRQ
- * handler, though it always triggers on rising and falling edges.
+ * handler.
+ * First implementation always triggers on rising and falling edges
+ * whereas the newer PIO3 can be additionally configured to trigger on
+ * level, edge with any polarity.
  *
  * Alternatively, certain pins may be used directly as IRQ0..IRQ6 after
  * configuring them with at91_set_a_periph() or at91_set_b_periph().
@@ -344,9 +502,9 @@ void at91_gpio_resume(void)
 
 static void gpio_irq_mask(struct irq_data *d)
 {
-       unsigned        pin = irq_to_gpio(d->irq);
-       void __iomem    *pio = pin_to_controller(pin);
-       unsigned        mask = pin_to_mask(pin);
+       struct at91_gpio_chip *at91_gpio = irq_data_get_irq_chip_data(d);
+       void __iomem    *pio = at91_gpio->regbase;
+       unsigned        mask = 1 << d->hwirq;
 
        if (pio)
                __raw_writel(mask, pio + PIO_IDR);
@@ -354,9 +512,9 @@ static void gpio_irq_mask(struct irq_data *d)
 
 static void gpio_irq_unmask(struct irq_data *d)
 {
-       unsigned        pin = irq_to_gpio(d->irq);
-       void __iomem    *pio = pin_to_controller(pin);
-       unsigned        mask = pin_to_mask(pin);
+       struct at91_gpio_chip *at91_gpio = irq_data_get_irq_chip_data(d);
+       void __iomem    *pio = at91_gpio->regbase;
+       unsigned        mask = 1 << d->hwirq;
 
        if (pio)
                __raw_writel(mask, pio + PIO_IER);
@@ -373,23 +531,66 @@ static int gpio_irq_type(struct irq_data *d, unsigned type)
        }
 }
 
+/* Alternate irq type for PIO3 support */
+static int alt_gpio_irq_type(struct irq_data *d, unsigned type)
+{
+       struct at91_gpio_chip *at91_gpio = irq_data_get_irq_chip_data(d);
+       void __iomem    *pio = at91_gpio->regbase;
+       unsigned        mask = 1 << d->hwirq;
+
+       switch (type) {
+       case IRQ_TYPE_EDGE_RISING:
+               __raw_writel(mask, pio + PIO_ESR);
+               __raw_writel(mask, pio + PIO_REHLSR);
+               break;
+       case IRQ_TYPE_EDGE_FALLING:
+               __raw_writel(mask, pio + PIO_ESR);
+               __raw_writel(mask, pio + PIO_FELLSR);
+               break;
+       case IRQ_TYPE_LEVEL_LOW:
+               __raw_writel(mask, pio + PIO_LSR);
+               __raw_writel(mask, pio + PIO_FELLSR);
+               break;
+       case IRQ_TYPE_LEVEL_HIGH:
+               __raw_writel(mask, pio + PIO_LSR);
+               __raw_writel(mask, pio + PIO_REHLSR);
+               break;
+       case IRQ_TYPE_EDGE_BOTH:
+               /*
+                * disable additional interrupt modes:
+                * fall back to default behavior
+                */
+               __raw_writel(mask, pio + PIO_AIMDR);
+               return 0;
+       case IRQ_TYPE_NONE:
+       default:
+               pr_warn("AT91: No type for irq %d\n", gpio_to_irq(d->irq));
+               return -EINVAL;
+       }
+
+       /* enable additional interrupt modes */
+       __raw_writel(mask, pio + PIO_AIMER);
+
+       return 0;
+}
+
 static struct irq_chip gpio_irqchip = {
        .name           = "GPIO",
        .irq_disable    = gpio_irq_mask,
        .irq_mask       = gpio_irq_mask,
        .irq_unmask     = gpio_irq_unmask,
-       .irq_set_type   = gpio_irq_type,
+       /* .irq_set_type is set dynamically */
        .irq_set_wake   = gpio_irq_set_wake,
 };
 
 static void gpio_irq_handler(unsigned irq, struct irq_desc *desc)
 {
-       unsigned        irq_pin;
        struct irq_data *idata = irq_desc_get_irq_data(desc);
        struct irq_chip *chip = irq_data_get_irq_chip(idata);
        struct at91_gpio_chip *at91_gpio = irq_data_get_irq_chip_data(idata);
        void __iomem    *pio = at91_gpio->regbase;
-       u32             isr;
+       unsigned long   isr;
+       int             n;
 
        /* temporarily mask (level sensitive) parent IRQ */
        chip->irq_ack(idata);
@@ -407,13 +608,10 @@ static void gpio_irq_handler(unsigned irq, struct irq_desc *desc)
                        continue;
                }
 
-               irq_pin = gpio_to_irq(at91_gpio->chip.base);
-
-               while (isr) {
-                       if (isr & 1)
-                               generic_handle_irq(irq_pin);
-                       irq_pin++;
-                       isr >>= 1;
+               n = find_first_bit(&isr, BITS_PER_LONG);
+               while (n < BITS_PER_LONG) {
+                       generic_handle_irq(irq_find_mapping(at91_gpio->domain, n));
+                       n = find_next_bit(&isr, BITS_PER_LONG, n + 1);
                }
        }
        chip->irq_unmask(idata);
@@ -424,6 +622,33 @@ static void gpio_irq_handler(unsigned irq, struct irq_desc *desc)
 
 #ifdef CONFIG_DEBUG_FS
 
+static void gpio_printf(struct seq_file *s, void __iomem *pio, unsigned mask)
+{
+       char    *trigger = NULL;
+       char    *polarity = NULL;
+
+       if (__raw_readl(pio + PIO_IMR) & mask) {
+               if (!has_pio3() || !(__raw_readl(pio + PIO_AIMMR) & mask )) {
+                       trigger = "edge";
+                       polarity = "both";
+               } else {
+                       if (__raw_readl(pio + PIO_ELSR) & mask) {
+                               trigger = "level";
+                               polarity = __raw_readl(pio + PIO_FRLHSR) & mask ?
+                                       "high" : "low";
+                       } else {
+                               trigger = "edge";
+                               polarity = __raw_readl(pio + PIO_FRLHSR) & mask ?
+                                               "rising" : "falling";
+                       }
+               }
+               seq_printf(s, "IRQ:%s-%s\t", trigger, polarity);
+       } else {
+               seq_printf(s, "GPIO:%s\t\t",
+                               __raw_readl(pio + PIO_PDSR) & mask ? "1" : "0");
+       }
+}
+
 static int at91_gpio_show(struct seq_file *s, void *unused)
 {
        int bank, j;
@@ -431,7 +656,7 @@ static int at91_gpio_show(struct seq_file *s, void *unused)
        /* print heading */
        seq_printf(s, "Pin\t");
        for (bank = 0; bank < gpio_banks; bank++) {
-               seq_printf(s, "PIO%c\t", 'A' + bank);
+               seq_printf(s, "PIO%c\t\t", 'A' + bank);
        };
        seq_printf(s, "\n\n");
 
@@ -445,11 +670,10 @@ static int at91_gpio_show(struct seq_file *s, void *unused)
                        unsigned        mask = pin_to_mask(pin);
 
                        if (__raw_readl(pio + PIO_PSR) & mask)
-                               seq_printf(s, "GPIO:%s", __raw_readl(pio + PIO_PDSR) & mask ? "1" : "0");
+                               gpio_printf(s, pio, mask);
                        else
-                               seq_printf(s, "%s", __raw_readl(pio + PIO_ABSR) & mask ? "B" : "A");
-
-                       seq_printf(s, "\t");
+                               seq_printf(s, "%c\t\t",
+                                               peripheral_function(pio, mask));
                }
 
                seq_printf(s, "\n");
@@ -488,46 +712,152 @@ postcore_initcall(at91_gpio_debugfs_init);
  */
 static struct lock_class_key gpio_lock_class;
 
+#if defined(CONFIG_OF)
+static int at91_gpio_irq_map(struct irq_domain *h, unsigned int virq,
+                                                       irq_hw_number_t hw)
+{
+       struct at91_gpio_chip   *at91_gpio = h->host_data;
+
+       irq_set_lockdep_class(virq, &gpio_lock_class);
+
+       /*
+        * Can use the "simple" and not "edge" handler since it's
+        * shorter, and the AIC handles interrupts sanely.
+        */
+       irq_set_chip_and_handler(virq, &gpio_irqchip,
+                                handle_simple_irq);
+       set_irq_flags(virq, IRQF_VALID);
+       irq_set_chip_data(virq, at91_gpio);
+
+       return 0;
+}
+
+static struct irq_domain_ops at91_gpio_ops = {
+       .map    = at91_gpio_irq_map,
+       .xlate  = irq_domain_xlate_twocell,
+};
+
+int __init at91_gpio_of_irq_setup(struct device_node *node,
+                                    struct device_node *parent)
+{
+       struct at91_gpio_chip   *prev = NULL;
+       int                     alias_idx = of_alias_get_id(node, "gpio");
+       struct at91_gpio_chip   *at91_gpio = &gpio_chip[alias_idx];
+
+       /* Setup proper .irq_set_type function */
+       if (has_pio3())
+               gpio_irqchip.irq_set_type = alt_gpio_irq_type;
+       else
+               gpio_irqchip.irq_set_type = gpio_irq_type;
+
+       /* Disable irqs of this PIO controller */
+       __raw_writel(~0, at91_gpio->regbase + PIO_IDR);
+
+       /* Setup irq domain */
+       at91_gpio->domain = irq_domain_add_linear(node, at91_gpio->chip.ngpio,
+                                               &at91_gpio_ops, at91_gpio);
+       if (!at91_gpio->domain)
+               panic("at91_gpio.%d: couldn't allocate irq domain (DT).\n",
+                       at91_gpio->pioc_idx);
+
+       /* Setup chained handler */
+       if (at91_gpio->pioc_idx)
+               prev = &gpio_chip[at91_gpio->pioc_idx - 1];
+
+       /* The toplevel handler handles one bank of GPIOs, except
+        * on some SoC it can handles up to three...
+        * We only set up the handler for the first of the list.
+        */
+       if (prev && prev->next == at91_gpio)
+               return 0;
+
+       at91_gpio->pioc_virq = irq_create_mapping(irq_find_host(parent),
+                                                       at91_gpio->pioc_hwirq);
+       irq_set_chip_data(at91_gpio->pioc_virq, at91_gpio);
+       irq_set_chained_handler(at91_gpio->pioc_virq, gpio_irq_handler);
+
+       return 0;
+}
+#else
+int __init at91_gpio_of_irq_setup(struct device_node *node,
+                                    struct device_node *parent)
+{
+       return -EINVAL;
+}
+#endif
+
+/*
+ * irqdomain initialization: pile up irqdomains on top of AIC range
+ */
+static void __init at91_gpio_irqdomain(struct at91_gpio_chip *at91_gpio)
+{
+       int irq_base;
+
+       irq_base = irq_alloc_descs(-1, 0, at91_gpio->chip.ngpio, 0);
+       if (irq_base < 0)
+               panic("at91_gpio.%d: error %d: couldn't allocate IRQ numbers.\n",
+                       at91_gpio->pioc_idx, irq_base);
+       at91_gpio->domain = irq_domain_add_legacy(NULL, at91_gpio->chip.ngpio,
+                                                 irq_base, 0,
+                                                 &irq_domain_simple_ops, NULL);
+       if (!at91_gpio->domain)
+               panic("at91_gpio.%d: couldn't allocate irq domain.\n",
+                       at91_gpio->pioc_idx);
+}
+
 /*
  * Called from the processor-specific init to enable GPIO interrupt support.
  */
 void __init at91_gpio_irq_setup(void)
 {
-       unsigned                pioc, irq = gpio_to_irq(0);
+       unsigned                pioc;
+       int                     gpio_irqnbr = 0;
        struct at91_gpio_chip   *this, *prev;
 
+       /* Setup proper .irq_set_type function */
+       if (has_pio3())
+               gpio_irqchip.irq_set_type = alt_gpio_irq_type;
+       else
+               gpio_irqchip.irq_set_type = gpio_irq_type;
+
        for (pioc = 0, this = gpio_chip, prev = NULL;
                        pioc++ < gpio_banks;
                        prev = this, this++) {
-               unsigned        id = this->id;
-               unsigned        i;
+               int offset;
 
                __raw_writel(~0, this->regbase + PIO_IDR);
 
-               for (i = 0, irq = gpio_to_irq(this->chip.base); i < 32;
-                    i++, irq++) {
-                       irq_set_lockdep_class(irq, &gpio_lock_class);
+               /* setup irq domain for this GPIO controller */
+               at91_gpio_irqdomain(this);
+
+               for (offset = 0; offset < this->chip.ngpio; offset++) {
+                       unsigned int virq = irq_find_mapping(this->domain, offset);
+                       irq_set_lockdep_class(virq, &gpio_lock_class);
 
                        /*
                         * Can use the "simple" and not "edge" handler since it's
                         * shorter, and the AIC handles interrupts sanely.
                         */
-                       irq_set_chip_and_handler(irq, &gpio_irqchip,
+                       irq_set_chip_and_handler(virq, &gpio_irqchip,
                                                 handle_simple_irq);
-                       set_irq_flags(irq, IRQF_VALID);
+                       set_irq_flags(virq, IRQF_VALID);
+                       irq_set_chip_data(virq, this);
+
+                       gpio_irqnbr++;
                }
 
                /* The toplevel handler handles one bank of GPIOs, except
-                * AT91SAM9263_ID_PIOCDE handles three... PIOC is first in
-                * the list, so we only set up that handler.
+                * on some SoC it can handles up to three...
+                * We only set up the handler for the first of the list.
                 */
                if (prev && prev->next == this)
                        continue;
 
-               irq_set_chip_data(id, this);
-               irq_set_chained_handler(id, gpio_irq_handler);
+               this->pioc_virq = irq_create_mapping(NULL, this->pioc_hwirq);
+               irq_set_chip_data(this->pioc_virq, this);
+               irq_set_chained_handler(this->pioc_virq, gpio_irq_handler);
        }
-       pr_info("AT91: %d gpio irqs in %d banks\n", irq - gpio_to_irq(0), gpio_banks);
+       pr_info("AT91: %d gpio irqs in %d banks\n", gpio_irqnbr, gpio_banks);
 }
 
 /* gpiolib support */
@@ -593,48 +923,175 @@ static void at91_gpiolib_dbg_show(struct seq_file *s, struct gpio_chip *chip)
                                           at91_get_gpio_value(pin) ?
                                           "set" : "clear");
                        else
-                               seq_printf(s, "[periph %s]\n",
-                                          __raw_readl(pio + PIO_ABSR) &
-                                          mask ? "B" : "A");
+                               seq_printf(s, "[periph %c]\n",
+                                          peripheral_function(pio, mask));
                }
        }
 }
 
+static int at91_gpiolib_to_irq(struct gpio_chip *chip, unsigned offset)
+{
+       struct at91_gpio_chip *at91_gpio = to_at91_gpio_chip(chip);
+       int virq;
+
+       if (offset < chip->ngpio)
+               virq = irq_create_mapping(at91_gpio->domain, offset);
+       else
+               virq = -ENXIO;
+
+       dev_dbg(chip->dev, "%s: request IRQ for GPIO %d, return %d\n",
+                               chip->label, offset + chip->base, virq);
+       return virq;
+}
+
+static int __init at91_gpio_setup_clk(int idx)
+{
+       struct at91_gpio_chip *at91_gpio = &gpio_chip[idx];
+
+       /* retreive PIO controller's clock */
+       at91_gpio->clock = clk_get_sys(NULL, at91_gpio->chip.label);
+       if (IS_ERR(at91_gpio->clock)) {
+               pr_err("at91_gpio.%d, failed to get clock, ignoring.\n", idx);
+               goto err;
+       }
+
+       if (clk_prepare(at91_gpio->clock))
+               goto clk_prep_err;
+
+       /* enable PIO controller's clock */
+       if (clk_enable(at91_gpio->clock)) {
+               pr_err("at91_gpio.%d, failed to enable clock, ignoring.\n", idx);
+               goto clk_err;
+       }
+
+       return 0;
+
+clk_err:
+       clk_unprepare(at91_gpio->clock);
+clk_prep_err:
+       clk_put(at91_gpio->clock);
+err:
+       return -EINVAL;
+}
+
+#ifdef CONFIG_OF_GPIO
+static void __init of_at91_gpio_init_one(struct device_node *np)
+{
+       int alias_idx;
+       struct at91_gpio_chip *at91_gpio;
+
+       if (!np)
+               return;
+
+       alias_idx = of_alias_get_id(np, "gpio");
+       if (alias_idx >= MAX_GPIO_BANKS) {
+               pr_err("at91_gpio, failed alias idx(%d) > MAX_GPIO_BANKS(%d), ignoring.\n",
+                                               alias_idx, MAX_GPIO_BANKS);
+               return;
+       }
+
+       at91_gpio = &gpio_chip[alias_idx];
+       at91_gpio->chip.base = alias_idx * at91_gpio->chip.ngpio;
+
+       at91_gpio->regbase = of_iomap(np, 0);
+       if (!at91_gpio->regbase) {
+               pr_err("at91_gpio.%d, failed to map registers, ignoring.\n",
+                                                               alias_idx);
+               return;
+       }
+
+       /* Get the interrupts property */
+       if (of_property_read_u32(np, "interrupts", &at91_gpio->pioc_hwirq)) {
+               pr_err("at91_gpio.%d, failed to get interrupts property, ignoring.\n",
+                                                               alias_idx);
+               goto ioremap_err;
+       }
+
+       /* Get capabilities from compatibility property */
+       if (of_device_is_compatible(np, "atmel,at91sam9x5-gpio"))
+               at91_gpio_caps |= AT91_GPIO_CAP_PIO3;
+
+       /* Setup clock */
+       if (at91_gpio_setup_clk(alias_idx))
+               goto ioremap_err;
+
+       at91_gpio->chip.of_node = np;
+       gpio_banks = max(gpio_banks, alias_idx + 1);
+       at91_gpio->pioc_idx = alias_idx;
+       return;
+
+ioremap_err:
+       iounmap(at91_gpio->regbase);
+}
+
+static int __init of_at91_gpio_init(void)
+{
+       struct device_node *np = NULL;
+
+       /*
+        * This isn't ideal, but it gets things hooked up until this
+        * driver is converted into a platform_device
+        */
+       for_each_compatible_node(np, NULL, "atmel,at91rm9200-gpio")
+               of_at91_gpio_init_one(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 idx, u32 regbase, int pioc_hwirq)
+{
+       struct at91_gpio_chip *at91_gpio = &gpio_chip[idx];
+
+       at91_gpio->chip.base = idx * at91_gpio->chip.ngpio;
+       at91_gpio->pioc_hwirq = pioc_hwirq;
+       at91_gpio->pioc_idx = idx;
+
+       at91_gpio->regbase = ioremap(regbase, 512);
+       if (!at91_gpio->regbase) {
+               pr_err("at91_gpio.%d, failed to map registers, ignoring.\n", idx);
+               return;
+       }
+
+       if (at91_gpio_setup_clk(idx))
+               goto ioremap_err;
+
+       gpio_banks = max(gpio_banks, idx + 1);
+       return;
+
+ioremap_err:
+       iounmap(at91_gpio->regbase);
+}
+
 /*
  * Called from the processor-specific init to enable GPIO pin support.
  */
 void __init at91_gpio_init(struct at91_gpio_bank *data, int nr_banks)
 {
-       unsigned                i;
+       unsigned i;
        struct at91_gpio_chip *at91_gpio, *last = NULL;
 
        BUG_ON(nr_banks > MAX_GPIO_BANKS);
 
-       gpio_banks = nr_banks;
+       if (of_at91_gpio_init() < 0) {
+               /* No GPIO controller found in device tree */
+               for (i = 0; i < nr_banks; i++)
+                       at91_gpio_init_one(i, data[i].regbase, data[i].id);
+       }
 
-       for (i = 0; i < nr_banks; i++) {
+       for (i = 0; i < gpio_banks; i++) {
                at91_gpio = &gpio_chip[i];
 
-               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;
-               }
-
-               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;
-               }
-
-               /* enable PIO controller's clock */
-               clk_enable(at91_gpio->clock);
-
-               /* AT91SAM9263_ID_PIOCDE groups PIOC, PIOD, PIOE */
-               if (last && last->id == at91_gpio->id)
+               /*
+                * GPIO controller are grouped on some SoC:
+                * PIOC, PIOD and PIOE can share the same IRQ line
+                */
+               if (last && last->pioc_hwirq == at91_gpio->pioc_hwirq)
                        last->next = at91_gpio;
                last = at91_gpio;
 
index c6a31bf8a5c6973b93ba8856191ca2bf04bde665..732b11c37f1a68f081508be3e6787ebb637a9540 100644 (file)
 #define PIO_PUER       0x64    /* Pull-up Enable Register */
 #define PIO_PUSR       0x68    /* Pull-up Status Register */
 #define PIO_ASR                0x70    /* Peripheral A Select Register */
+#define PIO_ABCDSR1    0x70    /* Peripheral ABCD Select Register 1 [some sam9 only] */
 #define PIO_BSR                0x74    /* Peripheral B Select Register */
+#define PIO_ABCDSR2    0x74    /* Peripheral ABCD Select Register 2 [some sam9 only] */
 #define PIO_ABSR       0x78    /* AB Status Register */
+#define PIO_IFSCDR     0x80    /* Input Filter Slow Clock Disable Register */
+#define PIO_IFSCER     0x84    /* Input Filter Slow Clock Enable Register */
+#define PIO_IFSCSR     0x88    /* Input Filter Slow Clock Status Register */
+#define PIO_SCDR       0x8c    /* Slow Clock Divider Debouncing Register */
+#define                PIO_SCDR_DIV    (0x3fff <<  0)          /* Slow Clock Divider Mask */
+#define PIO_PPDDR      0x90    /* Pad Pull-down Disable Register */
+#define PIO_PPDER      0x94    /* Pad Pull-down Enable Register */
+#define PIO_PPDSR      0x98    /* Pad Pull-down Status Register */
 #define PIO_OWER       0xa0    /* Output Write Enable Register */
 #define PIO_OWDR       0xa4    /* Output Write Disable Register */
 #define PIO_OWSR       0xa8    /* Output Write Status Register */
+#define PIO_AIMER      0xb0    /* Additional Interrupt Modes Enable Register */
+#define PIO_AIMDR      0xb4    /* Additional Interrupt Modes Disable Register */
+#define PIO_AIMMR      0xb8    /* Additional Interrupt Modes Mask Register */
+#define PIO_ESR                0xc0    /* Edge Select Register */
+#define PIO_LSR                0xc4    /* Level Select Register */
+#define PIO_ELSR       0xc8    /* Edge/Level Status Register */
+#define PIO_FELLSR     0xd0    /* Falling Edge/Low Level Select Register */
+#define PIO_REHLSR     0xd4    /* Rising Edge/ High Level Select Register */
+#define PIO_FRLHSR     0xd8    /* Fall/Rise - Low/High Status Register */
+#define PIO_SCHMITT    0x100   /* Schmitt Trigger Register */
+
+#define ABCDSR_PERIPH_A        0x0
+#define ABCDSR_PERIPH_B        0x1
+#define ABCDSR_PERIPH_C        0x2
+#define ABCDSR_PERIPH_D        0x3
 
 #endif
index e3fd225121c748f7f592b0ebedfe095028e5845b..eed465ab0dd7d14c589880f4a242ce74138e7030 100644 (file)
 extern int __init_or_module at91_set_GPIO_periph(unsigned pin, int use_pullup);
 extern int __init_or_module at91_set_A_periph(unsigned pin, int use_pullup);
 extern int __init_or_module at91_set_B_periph(unsigned pin, int use_pullup);
+extern int __init_or_module at91_set_C_periph(unsigned pin, int use_pullup);
+extern int __init_or_module at91_set_D_periph(unsigned pin, int use_pullup);
 extern int __init_or_module at91_set_gpio_input(unsigned pin, int use_pullup);
 extern int __init_or_module at91_set_gpio_output(unsigned pin, int value);
 extern int __init_or_module at91_set_deglitch(unsigned pin, int is_on);
+extern int __init_or_module at91_set_debounce(unsigned pin, int is_on, int div);
 extern int __init_or_module at91_set_multi_drive(unsigned pin, int is_on);
+extern int __init_or_module at91_set_pulldown(unsigned pin, int is_on);
+extern int __init_or_module at91_disable_schmitt_trig(unsigned pin);
 
 /* callable at any time */
 extern int at91_set_gpio_value(unsigned pin, int value);
@@ -204,18 +209,6 @@ extern int at91_get_gpio_value(unsigned pin);
 extern void at91_gpio_suspend(void);
 extern void at91_gpio_resume(void);
 
-/*-------------------------------------------------------------------------*/
-
-/* wrappers for "new style" GPIO calls. the old AT91-specific ones should
- * eventually be removed (along with this errno.h inclusion), and the
- * gpio request/free calls should probably be implemented.
- */
-
-#include <asm/errno.h>
-
-#define gpio_to_irq(gpio) (gpio + NR_AIC_IRQS)
-#define irq_to_gpio(irq)  (irq - NR_AIC_IRQS)
-
 #endif /* __ASSEMBLY__ */
 
 #endif
index be6b639ecd7b7ac431d289b79f993c9f023b1479..cfcfcbe362699d1ed04be46e2d9680bc89917e58 100644 (file)
 #include <linux/module.h>
 #include <linux/mm.h>
 #include <linux/types.h>
+#include <linux/irq.h>
+#include <linux/of.h>
+#include <linux/of_address.h>
+#include <linux/of_irq.h>
+#include <linux/irqdomain.h>
+#include <linux/err.h>
 
 #include <mach/hardware.h>
 #include <asm/irq.h>
 #include <asm/mach/map.h>
 
 void __iomem *at91_aic_base;
+static struct irq_domain *at91_aic_domain;
+static struct device_node *at91_aic_np;
 
 static void at91_aic_mask_irq(struct irq_data *d)
 {
        /* Disable interrupt on AIC */
-       at91_aic_write(AT91_AIC_IDCR, 1 << d->irq);
+       at91_aic_write(AT91_AIC_IDCR, 1 << d->hwirq);
 }
 
 static void at91_aic_unmask_irq(struct irq_data *d)
 {
        /* Enable interrupt on AIC */
-       at91_aic_write(AT91_AIC_IECR, 1 << d->irq);
+       at91_aic_write(AT91_AIC_IECR, 1 << d->hwirq);
 }
 
 unsigned int at91_extern_irq;
 
-#define is_extern_irq(irq) ((1 << (irq)) & at91_extern_irq)
+#define is_extern_irq(hwirq) ((1 << (hwirq)) & at91_extern_irq)
 
 static int at91_aic_set_type(struct irq_data *d, unsigned type)
 {
@@ -63,13 +71,13 @@ static int at91_aic_set_type(struct irq_data *d, unsigned type)
                srctype = AT91_AIC_SRCTYPE_RISING;
                break;
        case IRQ_TYPE_LEVEL_LOW:
-               if ((d->irq == AT91_ID_FIQ) || is_extern_irq(d->irq))           /* only supported on external interrupts */
+               if ((d->hwirq == AT91_ID_FIQ) || is_extern_irq(d->hwirq))               /* only supported on external interrupts */
                        srctype = AT91_AIC_SRCTYPE_LOW;
                else
                        return -EINVAL;
                break;
        case IRQ_TYPE_EDGE_FALLING:
-               if ((d->irq == AT91_ID_FIQ) || is_extern_irq(d->irq))           /* only supported on external interrupts */
+               if ((d->hwirq == AT91_ID_FIQ) || is_extern_irq(d->hwirq))               /* only supported on external interrupts */
                        srctype = AT91_AIC_SRCTYPE_FALLING;
                else
                        return -EINVAL;
@@ -78,8 +86,8 @@ static int at91_aic_set_type(struct irq_data *d, unsigned type)
                return -EINVAL;
        }
 
-       smr = at91_aic_read(AT91_AIC_SMR(d->irq)) & ~AT91_AIC_SRCTYPE;
-       at91_aic_write(AT91_AIC_SMR(d->irq), smr | srctype);
+       smr = at91_aic_read(AT91_AIC_SMR(d->hwirq)) & ~AT91_AIC_SRCTYPE;
+       at91_aic_write(AT91_AIC_SMR(d->hwirq), smr | srctype);
        return 0;
 }
 
@@ -90,13 +98,13 @@ static u32 backups;
 
 static int at91_aic_set_wake(struct irq_data *d, unsigned value)
 {
-       if (unlikely(d->irq >= 32))
+       if (unlikely(d->hwirq >= NR_AIC_IRQS))
                return -EINVAL;
 
        if (value)
-               wakeups |= (1 << d->irq);
+               wakeups |= (1 << d->hwirq);
        else
-               wakeups &= ~(1 << d->irq);
+               wakeups &= ~(1 << d->hwirq);
 
        return 0;
 }
@@ -127,46 +135,112 @@ static struct irq_chip at91_aic_chip = {
        .irq_set_wake   = at91_aic_set_wake,
 };
 
+static void __init at91_aic_hw_init(unsigned int spu_vector)
+{
+       int i;
+
+       /*
+        * Perform 8 End Of Interrupt Command to make sure AIC
+        * will not Lock out nIRQ
+        */
+       for (i = 0; i < 8; i++)
+               at91_aic_write(AT91_AIC_EOICR, 0);
+
+       /*
+        * Spurious Interrupt ID in Spurious Vector Register.
+        * When there is no current interrupt, the IRQ Vector Register
+        * reads the value stored in AIC_SPU
+        */
+       at91_aic_write(AT91_AIC_SPU, spu_vector);
+
+       /* No debugging in AIC: Debug (Protect) Control Register */
+       at91_aic_write(AT91_AIC_DCR, 0);
+
+       /* Disable and clear all interrupts initially */
+       at91_aic_write(AT91_AIC_IDCR, 0xFFFFFFFF);
+       at91_aic_write(AT91_AIC_ICCR, 0xFFFFFFFF);
+}
+
+#if defined(CONFIG_OF)
+static int at91_aic_irq_map(struct irq_domain *h, unsigned int virq,
+                                                       irq_hw_number_t hw)
+{
+       /* Put virq number in Source Vector Register */
+       at91_aic_write(AT91_AIC_SVR(hw), virq);
+
+       /* Active Low interrupt, without priority */
+       at91_aic_write(AT91_AIC_SMR(hw), AT91_AIC_SRCTYPE_LOW);
+
+       irq_set_chip_and_handler(virq, &at91_aic_chip, handle_level_irq);
+       set_irq_flags(virq, IRQF_VALID | IRQF_PROBE);
+
+       return 0;
+}
+
+static struct irq_domain_ops at91_aic_irq_ops = {
+       .map    = at91_aic_irq_map,
+       .xlate  = irq_domain_xlate_twocell,
+};
+
+int __init at91_aic_of_init(struct device_node *node,
+                                    struct device_node *parent)
+{
+       at91_aic_base = of_iomap(node, 0);
+       at91_aic_np = node;
+
+       at91_aic_domain = irq_domain_add_linear(at91_aic_np, NR_AIC_IRQS,
+                                               &at91_aic_irq_ops, NULL);
+       if (!at91_aic_domain)
+               panic("Unable to add AIC irq domain (DT)\n");
+
+       irq_set_default_host(at91_aic_domain);
+
+       at91_aic_hw_init(NR_AIC_IRQS);
+
+       return 0;
+}
+#endif
+
 /*
  * Initialize the AIC interrupt controller.
  */
 void __init at91_aic_init(unsigned int priority[NR_AIC_IRQS])
 {
        unsigned int i;
+       int irq_base;
 
        at91_aic_base = ioremap(AT91_AIC, 512);
-
        if (!at91_aic_base)
-               panic("Impossible to ioremap AT91_AIC\n");
+               panic("Unable to ioremap AIC registers\n");
+
+       /* Add irq domain for AIC */
+       irq_base = irq_alloc_descs(-1, 0, NR_AIC_IRQS, 0);
+       if (irq_base < 0) {
+               WARN(1, "Cannot allocate irq_descs, assuming pre-allocated\n");
+               irq_base = 0;
+       }
+       at91_aic_domain = irq_domain_add_legacy(at91_aic_np, NR_AIC_IRQS,
+                                               irq_base, 0,
+                                               &irq_domain_simple_ops, NULL);
+
+       if (!at91_aic_domain)
+               panic("Unable to add AIC irq domain\n");
+
+       irq_set_default_host(at91_aic_domain);
 
        /*
         * The IVR is used by macro get_irqnr_and_base to read and verify.
         * The irq number is NR_AIC_IRQS when a spurious interrupt has occurred.
         */
        for (i = 0; i < NR_AIC_IRQS; i++) {
-               /* Put irq number in Source Vector Register: */
+               /* Put hardware irq number in Source Vector Register: */
                at91_aic_write(AT91_AIC_SVR(i), i);
                /* Active Low interrupt, with the specified priority */
                at91_aic_write(AT91_AIC_SMR(i), AT91_AIC_SRCTYPE_LOW | priority[i]);
 
                irq_set_chip_and_handler(i, &at91_aic_chip, handle_level_irq);
                set_irq_flags(i, IRQF_VALID | IRQF_PROBE);
-
-               /* Perform 8 End Of Interrupt Command to make sure AIC will not Lock out nIRQ */
-               if (i < 8)
-                       at91_aic_write(AT91_AIC_EOICR, 0);
        }
 
-       /*
-        * Spurious Interrupt ID in Spurious Vector Register is NR_AIC_IRQS
-        * When there is no current interrupt, the IRQ Vector Register reads the value stored in AIC_SPU
-        */
-       at91_aic_write(AT91_AIC_SPU, NR_AIC_IRQS);
-
-       /* No debugging in AIC: Debug (Protect) Control Register */
-       at91_aic_write(AT91_AIC_DCR, 0);
-
-       /* Disable and clear all interrupts initially */
-       at91_aic_write(AT91_AIC_IDCR, 0xFFFFFFFF);
-       at91_aic_write(AT91_AIC_ICCR, 0xFFFFFFFF);
+       at91_aic_hw_init(NR_AIC_IRQS);
 }
index 55d0f95f82f9350571aca599b8480edefb5adfae..32cb929b8eb62ae387fc20b122c5d5a21da3f10b 100644 (file)
@@ -19,6 +19,8 @@
  *   - Two channels combine to create a free-running 32 bit counter
  *     with a base rate of 5+ MHz, packaged as a clocksource (with
  *     resolution better than 200 nsec).
+ *   - Some chips support 32 bit counter. A single channel is used for
+ *     this 32 bit free-running counter. the second channel is not used.
  *
  *   - The third channel may be used to provide a 16-bit clockevent
  *     source, used in either periodic or oneshot mode.  This runs
@@ -54,6 +56,11 @@ static cycle_t tc_get_cycles(struct clocksource *cs)
        return (upper << 16) | lower;
 }
 
+static cycle_t tc_get_cycles32(struct clocksource *cs)
+{
+       return __raw_readl(tcaddr + ATMEL_TC_REG(0, CV));
+}
+
 static struct clocksource clksrc = {
        .name           = "tcb_clksrc",
        .rating         = 200,
@@ -209,6 +216,48 @@ static void __init setup_clkevents(struct atmel_tc *tc, int clk32k_divisor_idx)
 
 #endif
 
+static void __init tcb_setup_dual_chan(struct atmel_tc *tc, int mck_divisor_idx)
+{
+       /* channel 0:  waveform mode, input mclk/8, clock TIOA0 on overflow */
+       __raw_writel(mck_divisor_idx                    /* likely divide-by-8 */
+                       | ATMEL_TC_WAVE
+                       | ATMEL_TC_WAVESEL_UP           /* free-run */
+                       | ATMEL_TC_ACPA_SET             /* TIOA0 rises at 0 */
+                       | ATMEL_TC_ACPC_CLEAR,          /* (duty cycle 50%) */
+                       tcaddr + ATMEL_TC_REG(0, CMR));
+       __raw_writel(0x0000, tcaddr + ATMEL_TC_REG(0, RA));
+       __raw_writel(0x8000, tcaddr + ATMEL_TC_REG(0, RC));
+       __raw_writel(0xff, tcaddr + ATMEL_TC_REG(0, IDR));      /* no irqs */
+       __raw_writel(ATMEL_TC_CLKEN, tcaddr + ATMEL_TC_REG(0, CCR));
+
+       /* channel 1:  waveform mode, input TIOA0 */
+       __raw_writel(ATMEL_TC_XC1                       /* input: TIOA0 */
+                       | ATMEL_TC_WAVE
+                       | ATMEL_TC_WAVESEL_UP,          /* free-run */
+                       tcaddr + ATMEL_TC_REG(1, CMR));
+       __raw_writel(0xff, tcaddr + ATMEL_TC_REG(1, IDR));      /* no irqs */
+       __raw_writel(ATMEL_TC_CLKEN, tcaddr + ATMEL_TC_REG(1, CCR));
+
+       /* chain channel 0 to channel 1*/
+       __raw_writel(ATMEL_TC_TC1XC1S_TIOA0, tcaddr + ATMEL_TC_BMR);
+       /* then reset all the timers */
+       __raw_writel(ATMEL_TC_SYNC, tcaddr + ATMEL_TC_BCR);
+}
+
+static void __init tcb_setup_single_chan(struct atmel_tc *tc, int mck_divisor_idx)
+{
+       /* channel 0:  waveform mode, input mclk/8 */
+       __raw_writel(mck_divisor_idx                    /* likely divide-by-8 */
+                       | ATMEL_TC_WAVE
+                       | ATMEL_TC_WAVESEL_UP,          /* free-run */
+                       tcaddr + ATMEL_TC_REG(0, CMR));
+       __raw_writel(0xff, tcaddr + ATMEL_TC_REG(0, IDR));      /* no irqs */
+       __raw_writel(ATMEL_TC_CLKEN, tcaddr + ATMEL_TC_REG(0, CCR));
+
+       /* then reset all the timers */
+       __raw_writel(ATMEL_TC_SYNC, tcaddr + ATMEL_TC_BCR);
+}
+
 static int __init tcb_clksrc_init(void)
 {
        static char bootinfo[] __initdata
@@ -260,34 +309,19 @@ static int __init tcb_clksrc_init(void)
                        divided_rate / 1000000,
                        ((divided_rate + 500000) % 1000000) / 1000);
 
-       /* tclib will give us three clocks no matter what the
-        * underlying platform supports.
-        */
-       clk_enable(tc->clk[1]);
-
-       /* channel 0:  waveform mode, input mclk/8, clock TIOA0 on overflow */
-       __raw_writel(best_divisor_idx                   /* likely divide-by-8 */
-                       | ATMEL_TC_WAVE
-                       | ATMEL_TC_WAVESEL_UP           /* free-run */
-                       | ATMEL_TC_ACPA_SET             /* TIOA0 rises at 0 */
-                       | ATMEL_TC_ACPC_CLEAR,          /* (duty cycle 50%) */
-                       tcaddr + ATMEL_TC_REG(0, CMR));
-       __raw_writel(0x0000, tcaddr + ATMEL_TC_REG(0, RA));
-       __raw_writel(0x8000, tcaddr + ATMEL_TC_REG(0, RC));
-       __raw_writel(0xff, tcaddr + ATMEL_TC_REG(0, IDR));      /* no irqs */
-       __raw_writel(ATMEL_TC_CLKEN, tcaddr + ATMEL_TC_REG(0, CCR));
-
-       /* channel 1:  waveform mode, input TIOA0 */
-       __raw_writel(ATMEL_TC_XC1                       /* input: TIOA0 */
-                       | ATMEL_TC_WAVE
-                       | ATMEL_TC_WAVESEL_UP,          /* free-run */
-                       tcaddr + ATMEL_TC_REG(1, CMR));
-       __raw_writel(0xff, tcaddr + ATMEL_TC_REG(1, IDR));      /* no irqs */
-       __raw_writel(ATMEL_TC_CLKEN, tcaddr + ATMEL_TC_REG(1, CCR));
-
-       /* chain channel 0 to channel 1, then reset all the timers */
-       __raw_writel(ATMEL_TC_TC1XC1S_TIOA0, tcaddr + ATMEL_TC_BMR);
-       __raw_writel(ATMEL_TC_SYNC, tcaddr + ATMEL_TC_BCR);
+       if (tc->tcb_config && tc->tcb_config->counter_width == 32) {
+               /* use apropriate function to read 32 bit counter */
+               clksrc.read = tc_get_cycles32;
+               /* setup ony channel 0 */
+               tcb_setup_single_chan(tc, best_divisor_idx);
+       } else {
+               /* tclib will give us three clocks no matter what the
+                * underlying platform supports.
+                */
+               clk_enable(tc->clk[1]);
+               /* setup both channel 0 & 1 */
+               tcb_setup_dual_chan(tc, best_divisor_idx);
+       }
 
        /* and away we go! */
        clocksource_register_hz(&clksrc, divided_rate);
index 4bcfc375973429a07dbcccf2558ef40237e20f00..c8d8e38d0d8ae6dc47cc0d85b581388896ae5361 100644 (file)
@@ -6,12 +6,10 @@
 #include <linux/ioport.h>
 #include <linux/kernel.h>
 #include <linux/platform_device.h>
+#include <linux/module.h>
 #include <linux/slab.h>
 #include <linux/export.h>
-
-/* Number of bytes to reserve for the iomem resource */
-#define ATMEL_TC_IOMEM_SIZE    256
-
+#include <linux/of.h>
 
 /*
  * This is a thin library to solve the problem of how to portably allocate
@@ -48,10 +46,17 @@ struct atmel_tc *atmel_tc_alloc(unsigned block, const char *name)
        struct atmel_tc         *tc;
        struct platform_device  *pdev = NULL;
        struct resource         *r;
+       size_t                  size;
 
        spin_lock(&tc_list_lock);
        list_for_each_entry(tc, &tc_list, node) {
-               if (tc->pdev->id == block) {
+               if (tc->pdev->dev.of_node) {
+                       if (of_alias_get_id(tc->pdev->dev.of_node, "tcb")
+                                       == block) {
+                               pdev = tc->pdev;
+                               break;
+                       }
+               } else if (tc->pdev->id == block) {
                        pdev = tc->pdev;
                        break;
                }
@@ -61,11 +66,15 @@ struct atmel_tc *atmel_tc_alloc(unsigned block, const char *name)
                goto fail;
 
        r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-       r = request_mem_region(r->start, ATMEL_TC_IOMEM_SIZE, name);
        if (!r)
                goto fail;
 
-       tc->regs = ioremap(r->start, ATMEL_TC_IOMEM_SIZE);
+       size = resource_size(r);
+       r = request_mem_region(r->start, size, name);
+       if (!r)
+               goto fail;
+
+       tc->regs = ioremap(r->start, size);
        if (!tc->regs)
                goto fail_ioremap;
 
@@ -76,7 +85,7 @@ out:
        return tc;
 
 fail_ioremap:
-       release_mem_region(r->start, ATMEL_TC_IOMEM_SIZE);
+       release_mem_region(r->start, size);
 fail:
        tc = NULL;
        goto out;
@@ -96,7 +105,7 @@ void atmel_tc_free(struct atmel_tc *tc)
        spin_lock(&tc_list_lock);
        if (tc->regs) {
                iounmap(tc->regs);
-               release_mem_region(tc->iomem->start, ATMEL_TC_IOMEM_SIZE);
+               release_mem_region(tc->iomem->start, resource_size(tc->iomem));
                tc->regs = NULL;
                tc->iomem = NULL;
        }
@@ -104,6 +113,30 @@ void atmel_tc_free(struct atmel_tc *tc)
 }
 EXPORT_SYMBOL_GPL(atmel_tc_free);
 
+#if defined(CONFIG_OF)
+static struct atmel_tcb_config tcb_rm9200_config = {
+       .counter_width = 16,
+};
+
+static struct atmel_tcb_config tcb_sam9x5_config = {
+       .counter_width = 32,
+};
+
+static const struct of_device_id atmel_tcb_dt_ids[] = {
+       {
+               .compatible = "atmel,at91rm9200-tcb",
+               .data = &tcb_rm9200_config,
+       }, {
+               .compatible = "atmel,at91sam9x5-tcb",
+               .data = &tcb_sam9x5_config,
+       }, {
+               /* sentinel */
+       }
+};
+
+MODULE_DEVICE_TABLE(of, atmel_tcb_dt_ids);
+#endif
+
 static int __init tc_probe(struct platform_device *pdev)
 {
        struct atmel_tc *tc;
@@ -129,6 +162,14 @@ static int __init tc_probe(struct platform_device *pdev)
                return -EINVAL;
        }
 
+       /* Now take SoC information if available */
+       if (pdev->dev.of_node) {
+               const struct of_device_id *match;
+               match = of_match_node(atmel_tcb_dt_ids, pdev->dev.of_node);
+               if (match)
+                       tc->tcb_config = match->data;
+       }
+
        tc->clk[0] = clk;
        tc->clk[1] = clk_get(&pdev->dev, "t1_clk");
        if (IS_ERR(tc->clk[1]))
@@ -153,7 +194,10 @@ static int __init tc_probe(struct platform_device *pdev)
 }
 
 static struct platform_driver tc_driver = {
-       .driver.name    = "atmel_tcb",
+       .driver = {
+               .name   = "atmel_tcb",
+               .of_match_table = of_match_ptr(atmel_tcb_dt_ids),
+       },
 };
 
 static int __init tc_init(void)
index 77afabc77f9be8d71fd4502bd5f315d9c8bd2c40..8e855eb0bf89ba1dd07934a721b8b13c6d146007 100644 (file)
@@ -448,10 +448,11 @@ static irqreturn_t ohci_hcd_at91_overcurrent_irq(int irq, void *data)
 
        /* From the GPIO notifying the over-current situation, find
         * out the corresponding port */
-       gpio = irq_to_gpio(irq);
        for (port = 0; port < ARRAY_SIZE(pdata->overcurrent_pin); port++) {
-               if (pdata->overcurrent_pin[port] == gpio)
+               if (gpio_to_irq(pdata->overcurrent_pin[port]) == irq) {
+                       gpio = pdata->overcurrent_pin[port];
                        break;
+               }
        }
 
        if (port == ARRAY_SIZE(pdata->overcurrent_pin)) {
index 53ba65e30caa2b61f9f6ab080ac9c5c1907a4b8e..1d14b1dc1aee69588ce68329e5fa71189d277016 100644 (file)
 
 struct clk;
 
+/**
+ * struct atmel_tcb_config - SoC data for a Timer/Counter Block
+ * @counter_width: size in bits of a timer counter register
+ */
+struct atmel_tcb_config {
+       size_t  counter_width;
+};
+
 /**
  * struct atmel_tc - information about a Timer/Counter Block
  * @pdev: physical device
  * @iomem: resource associated with the I/O register
  * @regs: mapping through which the I/O registers can be accessed
+ * @tcb_config: configuration data from SoC
  * @irq: irq for each of the three channels
  * @clk: internal clock source for each of the three channels
  * @node: list node, for tclib internal use
@@ -54,6 +63,7 @@ struct atmel_tc {
        struct platform_device  *pdev;
        struct resource         *iomem;
        void __iomem            *regs;
+       struct atmel_tcb_config *tcb_config;
        int                     irq[3];
        struct clk              *clk[3];
        struct list_head        node;
This page took 0.066466 seconds and 5 git commands to generate.