]> rtime.felk.cvut.cz Git - can-eth-gw-linux.git/commitdiff
Merge remote-tracking branch 'pinctrl/samsung' into next/pinctrl-samsung
authorKukjin Kim <kgene.kim@samsung.com>
Mon, 19 Nov 2012 01:00:41 +0000 (10:00 +0900)
committerKukjin Kim <kgene.kim@samsung.com>
Mon, 19 Nov 2012 01:00:41 +0000 (10:00 +0900)
Documentation/devicetree/bindings/pinctrl/samsung-pinctrl.txt
arch/arm/boot/dts/exynos4210-pinctrl.dtsi
arch/arm/boot/dts/exynos4210.dtsi
drivers/pinctrl/pinctrl-exynos.c
drivers/pinctrl/pinctrl-exynos.h
drivers/pinctrl/pinctrl-samsung.c
drivers/pinctrl/pinctrl-samsung.h

index 03dee50532f5c3d5f94f49fb2ee0bf44232d8fa3..63806e2d49c2e010a188290506093631782ee29a 100644 (file)
@@ -13,8 +13,14 @@ Required Properties:
 - reg: Base address of the pin controller hardware module and length of
   the address space it occupies.
 
-- interrupts: interrupt specifier for the controller. The format and value of
-  the interrupt specifier depends on the interrupt parent for the controller.
+- Pin banks as child nodes: Pin banks of the controller are represented by child
+  nodes of the controller node. Bank name is taken from name of the node. Each
+  bank node must contain following properties:
+
+  - gpio-controller: identifies the node as a gpio controller and pin bank.
+  - #gpio-cells: number of cells in GPIO specifier. Since the generic GPIO
+    binding is used, the amount of cells must be specified as 2. See generic
+    GPIO binding documentation for description of particular cells.
 
 - Pin mux/config groups as child nodes: The pin mux (selecting pin function
   mode) and pin config (pull up/down, driver strength) settings are represented
@@ -72,16 +78,24 @@ used as system wakeup events.
 A. External GPIO Interrupts: For supporting external gpio interrupts, the
    following properties should be specified in the pin-controller device node.
 
-- interrupt-controller: identifies the controller node as interrupt-parent.
-- #interrupt-cells: the value of this property should be 2.
-  - First Cell: represents the external gpio interrupt number local to the
-    external gpio interrupt space of the controller.
-  - Second Cell: flags to identify the type of the interrupt
-    - 1 = rising edge triggered
-    - 2 = falling edge triggered
-    - 3 = rising and falling edge triggered
-    - 4 = high level triggered
-    - 8 = low level triggered
+   - interrupt-parent: phandle of the interrupt parent to which the external
+     GPIO interrupts are forwarded to.
+   - interrupts: interrupt specifier for the controller. The format and value of
+     the interrupt specifier depends on the interrupt parent for the controller.
+
+   In addition, following properties must be present in node of every bank
+   of pins supporting GPIO interrupts:
+
+   - interrupt-controller: identifies the controller node as interrupt-parent.
+   - #interrupt-cells: the value of this property should be 2.
+     - First Cell: represents the external gpio interrupt number local to the
+       external gpio interrupt space of the controller.
+     - Second Cell: flags to identify the type of the interrupt
+       - 1 = rising edge triggered
+       - 2 = falling edge triggered
+       - 3 = rising and falling edge triggered
+       - 4 = high level triggered
+       - 8 = low level triggered
 
 B. External Wakeup Interrupts: For supporting external wakeup interrupts, a
    child node representing the external wakeup interrupt controller should be
@@ -94,6 +108,11 @@ B. External Wakeup Interrupts: For supporting external wakeup interrupts, a
        found on Samsung Exynos4210 SoC.
    - interrupt-parent: phandle of the interrupt parent to which the external
      wakeup interrupts are forwarded to.
+   - interrupts: interrupt used by multiplexed wakeup interrupts.
+
+   In addition, following properties must be present in node of every bank
+   of pins supporting wake-up interrupts:
+
    - interrupt-controller: identifies the node as interrupt-parent.
    - #interrupt-cells: the value of this property should be 2
      - First Cell: represents the external wakeup interrupt number local to
@@ -105,11 +124,63 @@ B. External Wakeup Interrupts: For supporting external wakeup interrupts, a
        - 4 = high level triggered
        - 8 = low level triggered
 
+   Node of every bank of pins supporting direct wake-up interrupts (without
+   multiplexing) must contain following properties:
+
+   - interrupt-parent: phandle of the interrupt parent to which the external
+     wakeup interrupts are forwarded to.
+   - interrupts: interrupts of the interrupt parent which are used for external
+     wakeup interrupts from pins of the bank, must contain interrupts for all
+     pins of the bank.
+
 Aliases:
 
 All the pin controller nodes should be represented in the aliases node using
 the following format 'pinctrl{n}' where n is a unique number for the alias.
 
+Example: A pin-controller node with pin banks:
+
+       pinctrl_0: pinctrl@11400000 {
+               compatible = "samsung,pinctrl-exynos4210";
+               reg = <0x11400000 0x1000>;
+               interrupts = <0 47 0>;
+
+               /* ... */
+
+               /* Pin bank without external interrupts */
+               gpy0: gpy0 {
+                       gpio-controller;
+                       #gpio-cells = <2>;
+               };
+
+               /* ... */
+
+               /* Pin bank with external GPIO or muxed wake-up interrupts */
+               gpj0: gpj0 {
+                       gpio-controller;
+                       #gpio-cells = <2>;
+
+                       interrupt-controller;
+                       #interrupt-cells = <2>;
+               };
+
+               /* ... */
+
+               /* Pin bank with external direct wake-up interrupts */
+               gpx0: gpx0 {
+                       gpio-controller;
+                       #gpio-cells = <2>;
+
+                       interrupt-controller;
+                       interrupt-parent = <&gic>;
+                       interrupts = <0 16 0>, <0 17 0>, <0 18 0>, <0 19 0>,
+                                    <0 20 0>, <0 21 0>, <0 22 0>, <0 23 0>;
+                       #interrupt-cells = <2>;
+               };
+
+               /* ... */
+       };
+
 Example 1: A pin-controller node with pin groups.
 
        pinctrl_0: pinctrl@11400000 {
@@ -117,6 +188,8 @@ Example 1: A pin-controller node with pin groups.
                reg = <0x11400000 0x1000>;
                interrupts = <0 47 0>;
 
+               /* ... */
+
                uart0_data: uart0-data {
                        samsung,pins = "gpa0-0", "gpa0-1";
                        samsung,pin-function = <2>;
@@ -158,20 +231,14 @@ Example 2: A pin-controller node with external wakeup interrupt controller node.
        pinctrl_1: pinctrl@11000000 {
                compatible = "samsung,pinctrl-exynos4210";
                reg = <0x11000000 0x1000>;
-               interrupts = <0 46 0>;
-               interrupt-controller;
-               #interrupt-cells = <2>;
+               interrupts = <0 46 0>
 
-               wakup_eint: wakeup-interrupt-controller {
+               /* ... */
+
+               wakeup-interrupt-controller {
                        compatible = "samsung,exynos4210-wakeup-eint";
                        interrupt-parent = <&gic>;
-                       interrupt-controller;
-                       #interrupt-cells = <2>;
-                       interrupts = <0 16 0>, <0 17 0>, <0 18 0>, <0 19 0>,
-                                       <0 20 0>, <0 21 0>, <0 22 0>, <0 23 0>,
-                                       <0 24 0>, <0 25 0>, <0 26 0>, <0 27 0>,
-                                       <0 28 0>, <0 29 0>, <0 30 0>, <0 31 0>,
-                                       <0 32 0>;
+                       interrupts = <0 32 0>;
                };
        };
 
@@ -190,7 +257,8 @@ Example 4: Set up the default pin state for uart controller.
 
        static int s3c24xx_serial_probe(struct platform_device *pdev) {
                struct pinctrl *pinctrl;
-               ...
-               ...
+
+               /* ... */
+
                pinctrl = devm_pinctrl_get_select_default(&pdev->dev);
        }
index b12cf272ad0deb82c0c856de71338dd8242944e9..6a4a1a04221c316b2b4ca9ab95f2179b17bbb7a4 100644 (file)
 
 / {
        pinctrl@11400000 {
+               gpa0: gpa0 {
+                       gpio-controller;
+                       #gpio-cells = <2>;
+
+                       interrupt-controller;
+                       #interrupt-cells = <2>;
+               };
+
+               gpa1: gpa1 {
+                       gpio-controller;
+                       #gpio-cells = <2>;
+
+                       interrupt-controller;
+                       #interrupt-cells = <2>;
+               };
+
+               gpb: gpb {
+                       gpio-controller;
+                       #gpio-cells = <2>;
+
+                       interrupt-controller;
+                       #interrupt-cells = <2>;
+               };
+
+               gpc0: gpc0 {
+                       gpio-controller;
+                       #gpio-cells = <2>;
+
+                       interrupt-controller;
+                       #interrupt-cells = <2>;
+               };
+
+               gpc1: gpc1 {
+                       gpio-controller;
+                       #gpio-cells = <2>;
+
+                       interrupt-controller;
+                       #interrupt-cells = <2>;
+               };
+
+               gpd0: gpd0 {
+                       gpio-controller;
+                       #gpio-cells = <2>;
+
+                       interrupt-controller;
+                       #interrupt-cells = <2>;
+               };
+
+               gpd1: gpd1 {
+                       gpio-controller;
+                       #gpio-cells = <2>;
+
+                       interrupt-controller;
+                       #interrupt-cells = <2>;
+               };
+
+               gpe0: gpe0 {
+                       gpio-controller;
+                       #gpio-cells = <2>;
+
+                       interrupt-controller;
+                       #interrupt-cells = <2>;
+               };
+
+               gpe1: gpe1 {
+                       gpio-controller;
+                       #gpio-cells = <2>;
+
+                       interrupt-controller;
+                       #interrupt-cells = <2>;
+               };
+
+               gpe2: gpe2 {
+                       gpio-controller;
+                       #gpio-cells = <2>;
+
+                       interrupt-controller;
+                       #interrupt-cells = <2>;
+               };
+
+               gpe3: gpe3 {
+                       gpio-controller;
+                       #gpio-cells = <2>;
+
+                       interrupt-controller;
+                       #interrupt-cells = <2>;
+               };
+
+               gpe4: gpe4 {
+                       gpio-controller;
+                       #gpio-cells = <2>;
+
+                       interrupt-controller;
+                       #interrupt-cells = <2>;
+               };
+
+               gpf0: gpf0 {
+                       gpio-controller;
+                       #gpio-cells = <2>;
+
+                       interrupt-controller;
+                       #interrupt-cells = <2>;
+               };
+
+               gpf1: gpf1 {
+                       gpio-controller;
+                       #gpio-cells = <2>;
+
+                       interrupt-controller;
+                       #interrupt-cells = <2>;
+               };
+
+               gpf2: gpf2 {
+                       gpio-controller;
+                       #gpio-cells = <2>;
+
+                       interrupt-controller;
+                       #interrupt-cells = <2>;
+               };
+
+               gpf3: gpf3 {
+                       gpio-controller;
+                       #gpio-cells = <2>;
+
+                       interrupt-controller;
+                       #interrupt-cells = <2>;
+               };
+
                uart0_data: uart0-data {
                        samsung,pins = "gpa0-0", "gpa0-1";
                        samsung,pin-function = <0x2>;
        };
 
        pinctrl@11000000 {
+               gpj0: gpj0 {
+                       gpio-controller;
+                       #gpio-cells = <2>;
+
+                       interrupt-controller;
+                       #interrupt-cells = <2>;
+               };
+
+               gpj1: gpj1 {
+                       gpio-controller;
+                       #gpio-cells = <2>;
+
+                       interrupt-controller;
+                       #interrupt-cells = <2>;
+               };
+
+               gpk0: gpk0 {
+                       gpio-controller;
+                       #gpio-cells = <2>;
+
+                       interrupt-controller;
+                       #interrupt-cells = <2>;
+               };
+
+               gpk1: gpk1 {
+                       gpio-controller;
+                       #gpio-cells = <2>;
+
+                       interrupt-controller;
+                       #interrupt-cells = <2>;
+               };
+
+               gpk2: gpk2 {
+                       gpio-controller;
+                       #gpio-cells = <2>;
+
+                       interrupt-controller;
+                       #interrupt-cells = <2>;
+               };
+
+               gpk3: gpk3 {
+                       gpio-controller;
+                       #gpio-cells = <2>;
+
+                       interrupt-controller;
+                       #interrupt-cells = <2>;
+               };
+
+               gpl0: gpl0 {
+                       gpio-controller;
+                       #gpio-cells = <2>;
+
+                       interrupt-controller;
+                       #interrupt-cells = <2>;
+               };
+
+               gpl1: gpl1 {
+                       gpio-controller;
+                       #gpio-cells = <2>;
+
+                       interrupt-controller;
+                       #interrupt-cells = <2>;
+               };
+
+               gpl2: gpl2 {
+                       gpio-controller;
+                       #gpio-cells = <2>;
+
+                       interrupt-controller;
+                       #interrupt-cells = <2>;
+               };
+
+               gpy0: gpy0 {
+                       gpio-controller;
+                       #gpio-cells = <2>;
+               };
+
+               gpy1: gpy1 {
+                       gpio-controller;
+                       #gpio-cells = <2>;
+               };
+
+               gpy2: gpy2 {
+                       gpio-controller;
+                       #gpio-cells = <2>;
+               };
+
+               gpy3: gpy3 {
+                       gpio-controller;
+                       #gpio-cells = <2>;
+               };
+
+               gpy4: gpy4 {
+                       gpio-controller;
+                       #gpio-cells = <2>;
+               };
+
+               gpy5: gpy5 {
+                       gpio-controller;
+                       #gpio-cells = <2>;
+               };
+
+               gpy6: gpy6 {
+                       gpio-controller;
+                       #gpio-cells = <2>;
+               };
+
+               gpx0: gpx0 {
+                       gpio-controller;
+                       #gpio-cells = <2>;
+
+                       interrupt-controller;
+                       interrupt-parent = <&gic>;
+                       interrupts = <0 16 0>, <0 17 0>, <0 18 0>, <0 19 0>,
+                                    <0 20 0>, <0 21 0>, <0 22 0>, <0 23 0>;
+                       #interrupt-cells = <2>;
+               };
+
+               gpx1: gpx1 {
+                       gpio-controller;
+                       #gpio-cells = <2>;
+
+                       interrupt-controller;
+                       interrupt-parent = <&gic>;
+                       interrupts = <0 24 0>, <0 25 0>, <0 26 0>, <0 27 0>,
+                                    <0 28 0>, <0 29 0>, <0 30 0>, <0 31 0>;
+                       #interrupt-cells = <2>;
+               };
+
+               gpx2: gpx2 {
+                       gpio-controller;
+                       #gpio-cells = <2>;
+
+                       interrupt-controller;
+                       #interrupt-cells = <2>;
+               };
+
+               gpx3: gpx3 {
+                       gpio-controller;
+                       #gpio-cells = <2>;
+
+                       interrupt-controller;
+                       #interrupt-cells = <2>;
+               };
+
                sd0_clk: sd0-clk {
                        samsung,pins = "gpk0-0";
                        samsung,pin-function = <2>;
        };
 
        pinctrl@03860000 {
+               gpz: gpz {
+                       gpio-controller;
+                       #gpio-cells = <2>;
+               };
+
                i2s0_bus: i2s0-bus {
                        samsung,pins = "gpz-0", "gpz-1", "gpz-2", "gpz-3",
                                        "gpz-4", "gpz-5", "gpz-6";
index 214c557eda7f7119584df481bde074c43a3611d4..d877dbe7ac0e767c020e2b8bf63ebe7566a8aa65 100644 (file)
                compatible = "samsung,pinctrl-exynos4210";
                reg = <0x11400000 0x1000>;
                interrupts = <0 47 0>;
-               interrupt-controller;
-               #interrupt-cells = <2>;
        };
 
        pinctrl_1: pinctrl@11000000 {
                compatible = "samsung,pinctrl-exynos4210";
                reg = <0x11000000 0x1000>;
                interrupts = <0 46 0>;
-               interrupt-controller;
-               #interrupt-cells = <2>;
 
                wakup_eint: wakeup-interrupt-controller {
                        compatible = "samsung,exynos4210-wakeup-eint";
                        interrupt-parent = <&gic>;
-                       interrupt-controller;
-                       #interrupt-cells = <2>;
-                       interrupts = <0 16 0>, <0 17 0>, <0 18 0>, <0 19 0>,
-                                    <0 20 0>, <0 21 0>, <0 22 0>, <0 23 0>,
-                                    <0 24 0>, <0 25 0>, <0 26 0>, <0 27 0>,
-                                    <0 28 0>, <0 29 0>, <0 30 0>, <0 31 0>,
-                                    <0 32 0>;
+                       interrupts = <0 32 0>;
                };
        };
 
                compatible = "samsung,pinctrl-exynos4210";
                reg = <0x03860000 0x1000>;
        };
-
-       gpio-controllers {
-               #address-cells = <1>;
-               #size-cells = <1>;
-               gpio-controller;
-               ranges;
-
-               gpa0: gpio-controller@11400000 {
-                       compatible = "samsung,exynos4-gpio";
-                       reg = <0x11400000 0x20>;
-                       #gpio-cells = <4>;
-               };
-
-               gpa1: gpio-controller@11400020 {
-                       compatible = "samsung,exynos4-gpio";
-                       reg = <0x11400020 0x20>;
-                       #gpio-cells = <4>;
-               };
-
-               gpb: gpio-controller@11400040 {
-                       compatible = "samsung,exynos4-gpio";
-                       reg = <0x11400040 0x20>;
-                       #gpio-cells = <4>;
-               };
-
-               gpc0: gpio-controller@11400060 {
-                       compatible = "samsung,exynos4-gpio";
-                       reg = <0x11400060 0x20>;
-                       #gpio-cells = <4>;
-               };
-
-               gpc1: gpio-controller@11400080 {
-                       compatible = "samsung,exynos4-gpio";
-                       reg = <0x11400080 0x20>;
-                       #gpio-cells = <4>;
-               };
-
-               gpd0: gpio-controller@114000A0 {
-                       compatible = "samsung,exynos4-gpio";
-                       reg = <0x114000A0 0x20>;
-                       #gpio-cells = <4>;
-               };
-
-               gpd1: gpio-controller@114000C0 {
-                       compatible = "samsung,exynos4-gpio";
-                       reg = <0x114000C0 0x20>;
-                       #gpio-cells = <4>;
-               };
-
-               gpe0: gpio-controller@114000E0 {
-                       compatible = "samsung,exynos4-gpio";
-                       reg = <0x114000E0 0x20>;
-                       #gpio-cells = <4>;
-               };
-
-               gpe1: gpio-controller@11400100 {
-                       compatible = "samsung,exynos4-gpio";
-                       reg = <0x11400100 0x20>;
-                       #gpio-cells = <4>;
-               };
-
-               gpe2: gpio-controller@11400120 {
-                       compatible = "samsung,exynos4-gpio";
-                       reg = <0x11400120 0x20>;
-                       #gpio-cells = <4>;
-               };
-
-               gpe3: gpio-controller@11400140 {
-                       compatible = "samsung,exynos4-gpio";
-                       reg = <0x11400140 0x20>;
-                       #gpio-cells = <4>;
-               };
-
-               gpe4: gpio-controller@11400160 {
-                       compatible = "samsung,exynos4-gpio";
-                       reg = <0x11400160 0x20>;
-                       #gpio-cells = <4>;
-               };
-
-               gpf0: gpio-controller@11400180 {
-                       compatible = "samsung,exynos4-gpio";
-                       reg = <0x11400180 0x20>;
-                       #gpio-cells = <4>;
-               };
-
-               gpf1: gpio-controller@114001A0 {
-                       compatible = "samsung,exynos4-gpio";
-                       reg = <0x114001A0 0x20>;
-                       #gpio-cells = <4>;
-               };
-
-               gpf2: gpio-controller@114001C0 {
-                       compatible = "samsung,exynos4-gpio";
-                       reg = <0x114001C0 0x20>;
-                       #gpio-cells = <4>;
-               };
-
-               gpf3: gpio-controller@114001E0 {
-                       compatible = "samsung,exynos4-gpio";
-                       reg = <0x114001E0 0x20>;
-                       #gpio-cells = <4>;
-               };
-
-               gpj0: gpio-controller@11000000 {
-                       compatible = "samsung,exynos4-gpio";
-                       reg = <0x11000000 0x20>;
-                       #gpio-cells = <4>;
-               };
-
-               gpj1: gpio-controller@11000020 {
-                       compatible = "samsung,exynos4-gpio";
-                       reg = <0x11000020 0x20>;
-                       #gpio-cells = <4>;
-               };
-
-               gpk0: gpio-controller@11000040 {
-                       compatible = "samsung,exynos4-gpio";
-                       reg = <0x11000040 0x20>;
-                       #gpio-cells = <4>;
-               };
-
-               gpk1: gpio-controller@11000060 {
-                       compatible = "samsung,exynos4-gpio";
-                       reg = <0x11000060 0x20>;
-                       #gpio-cells = <4>;
-               };
-
-               gpk2: gpio-controller@11000080 {
-                       compatible = "samsung,exynos4-gpio";
-                       reg = <0x11000080 0x20>;
-                       #gpio-cells = <4>;
-               };
-
-               gpk3: gpio-controller@110000A0 {
-                       compatible = "samsung,exynos4-gpio";
-                       reg = <0x110000A0 0x20>;
-                       #gpio-cells = <4>;
-               };
-
-               gpl0: gpio-controller@110000C0 {
-                       compatible = "samsung,exynos4-gpio";
-                       reg = <0x110000C0 0x20>;
-                       #gpio-cells = <4>;
-               };
-
-               gpl1: gpio-controller@110000E0 {
-                       compatible = "samsung,exynos4-gpio";
-                       reg = <0x110000E0 0x20>;
-                       #gpio-cells = <4>;
-               };
-
-               gpl2: gpio-controller@11000100 {
-                       compatible = "samsung,exynos4-gpio";
-                       reg = <0x11000100 0x20>;
-                       #gpio-cells = <4>;
-               };
-
-               gpy0: gpio-controller@11000120 {
-                       compatible = "samsung,exynos4-gpio";
-                       reg = <0x11000120 0x20>;
-                       #gpio-cells = <4>;
-               };
-
-               gpy1: gpio-controller@11000140 {
-                       compatible = "samsung,exynos4-gpio";
-                       reg = <0x11000140 0x20>;
-                       #gpio-cells = <4>;
-               };
-
-               gpy2: gpio-controller@11000160 {
-                       compatible = "samsung,exynos4-gpio";
-                       reg = <0x11000160 0x20>;
-                       #gpio-cells = <4>;
-               };
-
-               gpy3: gpio-controller@11000180 {
-                       compatible = "samsung,exynos4-gpio";
-                       reg = <0x11000180 0x20>;
-                       #gpio-cells = <4>;
-               };
-
-               gpy4: gpio-controller@110001A0 {
-                       compatible = "samsung,exynos4-gpio";
-                       reg = <0x110001A0 0x20>;
-                       #gpio-cells = <4>;
-               };
-
-               gpy5: gpio-controller@110001C0 {
-                       compatible = "samsung,exynos4-gpio";
-                       reg = <0x110001C0 0x20>;
-                       #gpio-cells = <4>;
-               };
-
-               gpy6: gpio-controller@110001E0 {
-                       compatible = "samsung,exynos4-gpio";
-                       reg = <0x110001E0 0x20>;
-                       #gpio-cells = <4>;
-               };
-
-               gpx0: gpio-controller@11000C00 {
-                       compatible = "samsung,exynos4-gpio";
-                       reg = <0x11000C00 0x20>;
-                       #gpio-cells = <4>;
-               };
-
-               gpx1: gpio-controller@11000C20 {
-                       compatible = "samsung,exynos4-gpio";
-                       reg = <0x11000C20 0x20>;
-                       #gpio-cells = <4>;
-               };
-
-               gpx2: gpio-controller@11000C40 {
-                       compatible = "samsung,exynos4-gpio";
-                       reg = <0x11000C40 0x20>;
-                       #gpio-cells = <4>;
-               };
-
-               gpx3: gpio-controller@11000C60 {
-                       compatible = "samsung,exynos4-gpio";
-                       reg = <0x11000C60 0x20>;
-                       #gpio-cells = <4>;
-               };
-
-               gpz: gpio-controller@03860000 {
-                       compatible = "samsung,exynos4-gpio";
-                       reg = <0x03860000 0x20>;
-                       #gpio-cells = <4>;
-               };
-       };
 };
index 21362f48d3700424244b2870cbfa0cb437af6f66..73a0aa27cd560a45c8e5efb859140a4c6cc55bed 100644 (file)
@@ -40,46 +40,46 @@ static const struct of_device_id exynos_wkup_irq_ids[] = {
 
 static void exynos_gpio_irq_unmask(struct irq_data *irqd)
 {
-       struct samsung_pinctrl_drv_data *d = irqd->domain->host_data;
-       struct exynos_geint_data *edata = irq_data_get_irq_handler_data(irqd);
-       unsigned long reg_mask = d->ctrl->geint_mask + edata->eint_offset;
+       struct samsung_pin_bank *bank = irq_data_get_irq_chip_data(irqd);
+       struct samsung_pinctrl_drv_data *d = bank->drvdata;
+       unsigned long reg_mask = d->ctrl->geint_mask + bank->eint_offset;
        unsigned long mask;
 
        mask = readl(d->virt_base + reg_mask);
-       mask &= ~(1 << edata->pin);
+       mask &= ~(1 << irqd->hwirq);
        writel(mask, d->virt_base + reg_mask);
 }
 
 static void exynos_gpio_irq_mask(struct irq_data *irqd)
 {
-       struct samsung_pinctrl_drv_data *d = irqd->domain->host_data;
-       struct exynos_geint_data *edata = irq_data_get_irq_handler_data(irqd);
-       unsigned long reg_mask = d->ctrl->geint_mask + edata->eint_offset;
+       struct samsung_pin_bank *bank = irq_data_get_irq_chip_data(irqd);
+       struct samsung_pinctrl_drv_data *d = bank->drvdata;
+       unsigned long reg_mask = d->ctrl->geint_mask + bank->eint_offset;
        unsigned long mask;
 
        mask = readl(d->virt_base + reg_mask);
-       mask |= 1 << edata->pin;
+       mask |= 1 << irqd->hwirq;
        writel(mask, d->virt_base + reg_mask);
 }
 
 static void exynos_gpio_irq_ack(struct irq_data *irqd)
 {
-       struct samsung_pinctrl_drv_data *d = irqd->domain->host_data;
-       struct exynos_geint_data *edata = irq_data_get_irq_handler_data(irqd);
-       unsigned long reg_pend = d->ctrl->geint_pend + edata->eint_offset;
+       struct samsung_pin_bank *bank = irq_data_get_irq_chip_data(irqd);
+       struct samsung_pinctrl_drv_data *d = bank->drvdata;
+       unsigned long reg_pend = d->ctrl->geint_pend + bank->eint_offset;
 
-       writel(1 << edata->pin, d->virt_base + reg_pend);
+       writel(1 << irqd->hwirq, d->virt_base + reg_pend);
 }
 
 static int exynos_gpio_irq_set_type(struct irq_data *irqd, unsigned int type)
 {
-       struct samsung_pinctrl_drv_data *d = irqd->domain->host_data;
+       struct samsung_pin_bank *bank = irq_data_get_irq_chip_data(irqd);
+       struct samsung_pinctrl_drv_data *d = bank->drvdata;
        struct samsung_pin_ctrl *ctrl = d->ctrl;
-       struct exynos_geint_data *edata = irq_data_get_irq_handler_data(irqd);
-       struct samsung_pin_bank *bank = edata->bank;
-       unsigned int shift = EXYNOS_EINT_CON_LEN * edata->pin;
+       unsigned int pin = irqd->hwirq;
+       unsigned int shift = EXYNOS_EINT_CON_LEN * pin;
        unsigned int con, trig_type;
-       unsigned long reg_con = ctrl->geint_con + edata->eint_offset;
+       unsigned long reg_con = ctrl->geint_con + bank->eint_offset;
        unsigned int mask;
 
        switch (type) {
@@ -114,7 +114,7 @@ static int exynos_gpio_irq_set_type(struct irq_data *irqd, unsigned int type)
        writel(con, d->virt_base + reg_con);
 
        reg_con = bank->pctl_offset;
-       shift = edata->pin * bank->func_width;
+       shift = pin * bank->func_width;
        mask = (1 << bank->func_width) - 1;
 
        con = readl(d->virt_base + reg_con);
@@ -136,82 +136,23 @@ static struct irq_chip exynos_gpio_irq_chip = {
        .irq_set_type   = exynos_gpio_irq_set_type,
 };
 
-/*
- * given a controller-local external gpio interrupt number, prepare the handler
- * data for it.
- */
-static struct exynos_geint_data *exynos_get_eint_data(irq_hw_number_t hw,
-                               struct samsung_pinctrl_drv_data *d)
-{
-       struct samsung_pin_bank *bank = d->ctrl->pin_banks;
-       struct exynos_geint_data *eint_data;
-       unsigned int nr_banks = d->ctrl->nr_banks, idx;
-       unsigned int irq_base = 0, eint_offset = 0;
-
-       if (hw >= d->ctrl->nr_gint) {
-               dev_err(d->dev, "unsupported ext-gpio interrupt\n");
-               return NULL;
-       }
-
-       for (idx = 0; idx < nr_banks; idx++, bank++) {
-               if (bank->eint_type != EINT_TYPE_GPIO)
-                       continue;
-               if ((hw >= irq_base) && (hw < (irq_base + bank->nr_pins)))
-                       break;
-               irq_base += bank->nr_pins;
-               eint_offset += 4;
-       }
-
-       if (idx == nr_banks) {
-               dev_err(d->dev, "pin bank not found for ext-gpio interrupt\n");
-               return NULL;
-       }
-
-       eint_data = devm_kzalloc(d->dev, sizeof(*eint_data), GFP_KERNEL);
-       if (!eint_data) {
-               dev_err(d->dev, "no memory for eint-gpio data\n");
-               return NULL;
-       }
-
-       eint_data->bank = bank;
-       eint_data->pin = hw - irq_base;
-       eint_data->eint_offset = eint_offset;
-       return eint_data;
-}
-
 static int exynos_gpio_irq_map(struct irq_domain *h, unsigned int virq,
                                        irq_hw_number_t hw)
 {
-       struct samsung_pinctrl_drv_data *d = h->host_data;
-       struct exynos_geint_data *eint_data;
+       struct samsung_pin_bank *b = h->host_data;
 
-       eint_data = exynos_get_eint_data(hw, d);
-       if (!eint_data)
-               return -EINVAL;
-
-       irq_set_handler_data(virq, eint_data);
-       irq_set_chip_data(virq, h->host_data);
+       irq_set_chip_data(virq, b);
        irq_set_chip_and_handler(virq, &exynos_gpio_irq_chip,
                                        handle_level_irq);
        set_irq_flags(virq, IRQF_VALID);
        return 0;
 }
 
-static void exynos_gpio_irq_unmap(struct irq_domain *h, unsigned int virq)
-{
-       struct samsung_pinctrl_drv_data *d = h->host_data;
-       struct exynos_geint_data *eint_data;
-
-       eint_data = irq_get_handler_data(virq);
-       devm_kfree(d->dev, eint_data);
-}
-
 /*
  * irq domain callbacks for external gpio interrupt controller.
  */
 static const struct irq_domain_ops exynos_gpio_irqd_ops = {
        .map    = exynos_gpio_irq_map,
-       .unmap  = exynos_gpio_irq_unmap,
        .xlate  = irq_domain_xlate_twocell,
 };
 
@@ -230,7 +171,7 @@ static irqreturn_t exynos_eint_gpio_irq(int irq, void *data)
                return IRQ_HANDLED;
        bank += (group - 1);
 
-       virq = irq_linear_revmap(d->gpio_irqd, bank->irq_base + pin);
+       virq = irq_linear_revmap(bank->irq_domain, pin);
        if (!virq)
                return IRQ_NONE;
        generic_handle_irq(virq);
@@ -243,8 +184,10 @@ static irqreturn_t exynos_eint_gpio_irq(int irq, void *data)
  */
 static int exynos_eint_gpio_init(struct samsung_pinctrl_drv_data *d)
 {
+       struct samsung_pin_bank *bank;
        struct device *dev = d->dev;
        unsigned int ret;
+       unsigned int i;
 
        if (!d->irq) {
                dev_err(dev, "irq number not available\n");
@@ -258,11 +201,16 @@ static int exynos_eint_gpio_init(struct samsung_pinctrl_drv_data *d)
                return -ENXIO;
        }
 
-       d->gpio_irqd = irq_domain_add_linear(dev->of_node, d->ctrl->nr_gint,
-                               &exynos_gpio_irqd_ops, d);
-       if (!d->gpio_irqd) {
-               dev_err(dev, "gpio irq domain allocation failed\n");
-               return -ENXIO;
+       bank = d->ctrl->pin_banks;
+       for (i = 0; i < d->ctrl->nr_banks; ++i, ++bank) {
+               if (bank->eint_type != EINT_TYPE_GPIO)
+                       continue;
+               bank->irq_domain = irq_domain_add_linear(bank->of_node,
+                               bank->nr_pins, &exynos_gpio_irqd_ops, bank);
+               if (!bank->irq_domain) {
+                       dev_err(dev, "gpio irq domain add failed\n");
+                       return -ENXIO;
+               }
        }
 
        return 0;
@@ -270,48 +218,46 @@ static int exynos_eint_gpio_init(struct samsung_pinctrl_drv_data *d)
 
 static void exynos_wkup_irq_unmask(struct irq_data *irqd)
 {
-       struct samsung_pinctrl_drv_data *d = irq_data_get_irq_chip_data(irqd);
-       unsigned int bank = irqd->hwirq / EXYNOS_EINT_MAX_PER_BANK;
-       unsigned int pin = irqd->hwirq & (EXYNOS_EINT_MAX_PER_BANK - 1);
-       unsigned long reg_mask = d->ctrl->weint_mask + (bank << 2);
+       struct samsung_pin_bank *b = irq_data_get_irq_chip_data(irqd);
+       struct samsung_pinctrl_drv_data *d = b->drvdata;
+       unsigned long reg_mask = d->ctrl->weint_mask + b->eint_offset;
        unsigned long mask;
 
        mask = readl(d->virt_base + reg_mask);
-       mask &= ~(1 << pin);
+       mask &= ~(1 << irqd->hwirq);
        writel(mask, d->virt_base + reg_mask);
 }
 
 static void exynos_wkup_irq_mask(struct irq_data *irqd)
 {
-       struct samsung_pinctrl_drv_data *d = irq_data_get_irq_chip_data(irqd);
-       unsigned int bank = irqd->hwirq / EXYNOS_EINT_MAX_PER_BANK;
-       unsigned int pin = irqd->hwirq & (EXYNOS_EINT_MAX_PER_BANK - 1);
-       unsigned long reg_mask = d->ctrl->weint_mask + (bank << 2);
+       struct samsung_pin_bank *b = irq_data_get_irq_chip_data(irqd);
+       struct samsung_pinctrl_drv_data *d = b->drvdata;
+       unsigned long reg_mask = d->ctrl->weint_mask + b->eint_offset;
        unsigned long mask;
 
        mask = readl(d->virt_base + reg_mask);
-       mask |= 1 << pin;
+       mask |= 1 << irqd->hwirq;
        writel(mask, d->virt_base + reg_mask);
 }
 
 static void exynos_wkup_irq_ack(struct irq_data *irqd)
 {
-       struct samsung_pinctrl_drv_data *d = irq_data_get_irq_chip_data(irqd);
-       unsigned int bank = irqd->hwirq / EXYNOS_EINT_MAX_PER_BANK;
-       unsigned int pin = irqd->hwirq & (EXYNOS_EINT_MAX_PER_BANK - 1);
-       unsigned long pend = d->ctrl->weint_pend + (bank << 2);
+       struct samsung_pin_bank *b = irq_data_get_irq_chip_data(irqd);
+       struct samsung_pinctrl_drv_data *d = b->drvdata;
+       unsigned long pend = d->ctrl->weint_pend + b->eint_offset;
 
-       writel(1 << pin, d->virt_base + pend);
+       writel(1 << irqd->hwirq, d->virt_base + pend);
 }
 
 static int exynos_wkup_irq_set_type(struct irq_data *irqd, unsigned int type)
 {
-       struct samsung_pinctrl_drv_data *d = irq_data_get_irq_chip_data(irqd);
-       unsigned int bank = irqd->hwirq / EXYNOS_EINT_MAX_PER_BANK;
-       unsigned int pin = irqd->hwirq & (EXYNOS_EINT_MAX_PER_BANK - 1);
-       unsigned long reg_con = d->ctrl->weint_con + (bank << 2);
+       struct samsung_pin_bank *bank = irq_data_get_irq_chip_data(irqd);
+       struct samsung_pinctrl_drv_data *d = bank->drvdata;
+       unsigned int pin = irqd->hwirq;
+       unsigned long reg_con = d->ctrl->weint_con + bank->eint_offset;
        unsigned long shift = EXYNOS_EINT_CON_LEN * pin;
        unsigned long con, trig_type;
+       unsigned int mask;
 
        switch (type) {
        case IRQ_TYPE_EDGE_RISING:
@@ -343,6 +289,16 @@ static int exynos_wkup_irq_set_type(struct irq_data *irqd, unsigned int type)
        con &= ~(EXYNOS_EINT_CON_MASK << shift);
        con |= trig_type << shift;
        writel(con, d->virt_base + reg_con);
+
+       reg_con = bank->pctl_offset;
+       shift = pin * bank->func_width;
+       mask = (1 << bank->func_width) - 1;
+
+       con = readl(d->virt_base + reg_con);
+       con &= ~(mask << shift);
+       con |= EXYNOS_EINT_FUNC << shift;
+       writel(con, d->virt_base + reg_con);
+
        return 0;
 }
 
@@ -361,6 +317,7 @@ static struct irq_chip exynos_wkup_irq_chip = {
 static void exynos_irq_eint0_15(unsigned int irq, struct irq_desc *desc)
 {
        struct exynos_weint_data *eintd = irq_get_handler_data(irq);
+       struct samsung_pin_bank *bank = eintd->bank;
        struct irq_chip *chip = irq_get_chip(irq);
        int eint_irq;
 
@@ -370,20 +327,20 @@ static void exynos_irq_eint0_15(unsigned int irq, struct irq_desc *desc)
        if (chip->irq_ack)
                chip->irq_ack(&desc->irq_data);
 
-       eint_irq = irq_linear_revmap(eintd->domain, eintd->irq);
+       eint_irq = irq_linear_revmap(bank->irq_domain, eintd->irq);
        generic_handle_irq(eint_irq);
        chip->irq_unmask(&desc->irq_data);
        chained_irq_exit(chip, desc);
 }
 
-static inline void exynos_irq_demux_eint(int irq_base, unsigned long pend,
-                                       struct irq_domain *domain)
+static inline void exynos_irq_demux_eint(unsigned long pend,
+                                               struct irq_domain *domain)
 {
        unsigned int irq;
 
        while (pend) {
                irq = fls(pend) - 1;
-               generic_handle_irq(irq_find_mapping(domain, irq_base + irq));
+               generic_handle_irq(irq_find_mapping(domain, irq));
                pend &= ~(1 << irq);
        }
 }
@@ -392,18 +349,22 @@ static inline void exynos_irq_demux_eint(int irq_base, unsigned long pend,
 static void exynos_irq_demux_eint16_31(unsigned int irq, struct irq_desc *desc)
 {
        struct irq_chip *chip = irq_get_chip(irq);
-       struct exynos_weint_data *eintd = irq_get_handler_data(irq);
-       struct samsung_pinctrl_drv_data *d = eintd->domain->host_data;
+       struct exynos_muxed_weint_data *eintd = irq_get_handler_data(irq);
+       struct samsung_pinctrl_drv_data *d = eintd->banks[0]->drvdata;
+       struct samsung_pin_ctrl *ctrl = d->ctrl;
        unsigned long pend;
        unsigned long mask;
+       int i;
 
        chained_irq_enter(chip, desc);
-       pend = readl(d->virt_base + d->ctrl->weint_pend + 0x8);
-       mask = readl(d->virt_base + d->ctrl->weint_mask + 0x8);
-       exynos_irq_demux_eint(16, pend & ~mask, eintd->domain);
-       pend = readl(d->virt_base + d->ctrl->weint_pend + 0xC);
-       mask = readl(d->virt_base + d->ctrl->weint_mask + 0xC);
-       exynos_irq_demux_eint(24, pend & ~mask, eintd->domain);
+
+       for (i = 0; i < eintd->nr_banks; ++i) {
+               struct samsung_pin_bank *b = eintd->banks[i];
+               pend = readl(d->virt_base + ctrl->weint_pend + b->eint_offset);
+               mask = readl(d->virt_base + ctrl->weint_mask + b->eint_offset);
+               exynos_irq_demux_eint(pend & ~mask, b->irq_domain);
+       }
+
        chained_irq_exit(chip, desc);
 }
 
@@ -433,7 +394,11 @@ static int exynos_eint_wkup_init(struct samsung_pinctrl_drv_data *d)
        struct device *dev = d->dev;
        struct device_node *wkup_np = NULL;
        struct device_node *np;
+       struct samsung_pin_bank *bank;
        struct exynos_weint_data *weint_data;
+       struct exynos_muxed_weint_data *muxed_data;
+       unsigned int muxed_banks = 0;
+       unsigned int i;
        int idx, irq;
 
        for_each_child_of_node(dev->of_node, np) {
@@ -445,90 +410,124 @@ static int exynos_eint_wkup_init(struct samsung_pinctrl_drv_data *d)
        if (!wkup_np)
                return -ENODEV;
 
-       d->wkup_irqd = irq_domain_add_linear(wkup_np, d->ctrl->nr_wint,
-                               &exynos_wkup_irqd_ops, d);
-       if (!d->wkup_irqd) {
-               dev_err(dev, "wakeup irq domain allocation failed\n");
-               return -ENXIO;
-       }
+       bank = d->ctrl->pin_banks;
+       for (i = 0; i < d->ctrl->nr_banks; ++i, ++bank) {
+               if (bank->eint_type != EINT_TYPE_WKUP)
+                       continue;
 
-       weint_data = devm_kzalloc(dev, sizeof(*weint_data) * 17, GFP_KERNEL);
-       if (!weint_data) {
-               dev_err(dev, "could not allocate memory for weint_data\n");
-               return -ENOMEM;
-       }
+               bank->irq_domain = irq_domain_add_linear(bank->of_node,
+                               bank->nr_pins, &exynos_wkup_irqd_ops, bank);
+               if (!bank->irq_domain) {
+                       dev_err(dev, "wkup irq domain add failed\n");
+                       return -ENXIO;
+               }
 
-       irq = irq_of_parse_and_map(wkup_np, 16);
-       if (irq) {
-               weint_data[16].domain = d->wkup_irqd;
-               irq_set_chained_handler(irq, exynos_irq_demux_eint16_31);
-               irq_set_handler_data(irq, &weint_data[16]);
-       } else {
-               dev_err(dev, "irq number for EINT16-32 not found\n");
-       }
+               if (!of_find_property(bank->of_node, "interrupts", NULL)) {
+                       bank->eint_type = EINT_TYPE_WKUP_MUX;
+                       ++muxed_banks;
+                       continue;
+               }
 
-       for (idx = 0; idx < 16; idx++) {
-               weint_data[idx].domain = d->wkup_irqd;
-               weint_data[idx].irq = idx;
+               weint_data = devm_kzalloc(dev, bank->nr_pins
+                                       * sizeof(*weint_data), GFP_KERNEL);
+               if (!weint_data) {
+                       dev_err(dev, "could not allocate memory for weint_data\n");
+                       return -ENOMEM;
+               }
 
-               irq = irq_of_parse_and_map(wkup_np, idx);
-               if (irq) {
+               for (idx = 0; idx < bank->nr_pins; ++idx) {
+                       irq = irq_of_parse_and_map(bank->of_node, idx);
+                       if (!irq) {
+                               dev_err(dev, "irq number for eint-%s-%d not found\n",
+                                                       bank->name, idx);
+                               continue;
+                       }
+                       weint_data[idx].irq = idx;
+                       weint_data[idx].bank = bank;
                        irq_set_handler_data(irq, &weint_data[idx]);
                        irq_set_chained_handler(irq, exynos_irq_eint0_15);
-               } else {
-                       dev_err(dev, "irq number for eint-%x not found\n", idx);
                }
        }
+
+       if (!muxed_banks)
+               return 0;
+
+       irq = irq_of_parse_and_map(wkup_np, 0);
+       if (!irq) {
+               dev_err(dev, "irq number for muxed EINTs not found\n");
+               return 0;
+       }
+
+       muxed_data = devm_kzalloc(dev, sizeof(*muxed_data)
+               + muxed_banks*sizeof(struct samsung_pin_bank *), GFP_KERNEL);
+       if (!muxed_data) {
+               dev_err(dev, "could not allocate memory for muxed_data\n");
+               return -ENOMEM;
+       }
+
+       irq_set_chained_handler(irq, exynos_irq_demux_eint16_31);
+       irq_set_handler_data(irq, muxed_data);
+
+       bank = d->ctrl->pin_banks;
+       idx = 0;
+       for (i = 0; i < d->ctrl->nr_banks; ++i, ++bank) {
+               if (bank->eint_type != EINT_TYPE_WKUP_MUX)
+                       continue;
+
+               muxed_data->banks[idx++] = bank;
+       }
+       muxed_data->nr_banks = muxed_banks;
+
        return 0;
 }
 
 /* pin banks of exynos4210 pin-controller 0 */
 static struct samsung_pin_bank exynos4210_pin_banks0[] = {
-       EXYNOS_PIN_BANK_EINTG(0x000, EXYNOS4210_GPIO_A0, "gpa0"),
-       EXYNOS_PIN_BANK_EINTG(0x020, EXYNOS4210_GPIO_A1, "gpa1"),
-       EXYNOS_PIN_BANK_EINTG(0x040, EXYNOS4210_GPIO_B, "gpb"),
-       EXYNOS_PIN_BANK_EINTG(0x060, EXYNOS4210_GPIO_C0, "gpc0"),
-       EXYNOS_PIN_BANK_EINTG(0x080, EXYNOS4210_GPIO_C1, "gpc1"),
-       EXYNOS_PIN_BANK_EINTG(0x0A0, EXYNOS4210_GPIO_D0, "gpd0"),
-       EXYNOS_PIN_BANK_EINTG(0x0C0, EXYNOS4210_GPIO_D1, "gpd1"),
-       EXYNOS_PIN_BANK_EINTG(0x0E0, EXYNOS4210_GPIO_E0, "gpe0"),
-       EXYNOS_PIN_BANK_EINTG(0x100, EXYNOS4210_GPIO_E1, "gpe1"),
-       EXYNOS_PIN_BANK_EINTG(0x120, EXYNOS4210_GPIO_E2, "gpe2"),
-       EXYNOS_PIN_BANK_EINTG(0x140, EXYNOS4210_GPIO_E3, "gpe3"),
-       EXYNOS_PIN_BANK_EINTG(0x160, EXYNOS4210_GPIO_E4, "gpe4"),
-       EXYNOS_PIN_BANK_EINTG(0x180, EXYNOS4210_GPIO_F0, "gpf0"),
-       EXYNOS_PIN_BANK_EINTG(0x1A0, EXYNOS4210_GPIO_F1, "gpf1"),
-       EXYNOS_PIN_BANK_EINTG(0x1C0, EXYNOS4210_GPIO_F2, "gpf2"),
-       EXYNOS_PIN_BANK_EINTG(0x1E0, EXYNOS4210_GPIO_F3, "gpf3"),
+       EXYNOS_PIN_BANK_EINTG(8, 0x000, "gpa0", 0x00),
+       EXYNOS_PIN_BANK_EINTG(6, 0x020, "gpa1", 0x04),
+       EXYNOS_PIN_BANK_EINTG(8, 0x040, "gpb", 0x08),
+       EXYNOS_PIN_BANK_EINTG(5, 0x060, "gpc0", 0x0c),
+       EXYNOS_PIN_BANK_EINTG(5, 0x080, "gpc1", 0x10),
+       EXYNOS_PIN_BANK_EINTG(4, 0x0A0, "gpd0", 0x14),
+       EXYNOS_PIN_BANK_EINTG(4, 0x0C0, "gpd1", 0x18),
+       EXYNOS_PIN_BANK_EINTG(5, 0x0E0, "gpe0", 0x1c),
+       EXYNOS_PIN_BANK_EINTG(8, 0x100, "gpe1", 0x20),
+       EXYNOS_PIN_BANK_EINTG(6, 0x120, "gpe2", 0x24),
+       EXYNOS_PIN_BANK_EINTG(8, 0x140, "gpe3", 0x28),
+       EXYNOS_PIN_BANK_EINTG(8, 0x160, "gpe4", 0x2c),
+       EXYNOS_PIN_BANK_EINTG(8, 0x180, "gpf0", 0x30),
+       EXYNOS_PIN_BANK_EINTG(8, 0x1A0, "gpf1", 0x34),
+       EXYNOS_PIN_BANK_EINTG(8, 0x1C0, "gpf2", 0x38),
+       EXYNOS_PIN_BANK_EINTG(6, 0x1E0, "gpf3", 0x3c),
 };
 
 /* pin banks of exynos4210 pin-controller 1 */
 static struct samsung_pin_bank exynos4210_pin_banks1[] = {
-       EXYNOS_PIN_BANK_EINTG(0x000, EXYNOS4210_GPIO_J0, "gpj0"),
-       EXYNOS_PIN_BANK_EINTG(0x020, EXYNOS4210_GPIO_J1, "gpj1"),
-       EXYNOS_PIN_BANK_EINTG(0x040, EXYNOS4210_GPIO_K0, "gpk0"),
-       EXYNOS_PIN_BANK_EINTG(0x060, EXYNOS4210_GPIO_K1, "gpk1"),
-       EXYNOS_PIN_BANK_EINTG(0x080, EXYNOS4210_GPIO_K2, "gpk2"),
-       EXYNOS_PIN_BANK_EINTG(0x0A0, EXYNOS4210_GPIO_K3, "gpk3"),
-       EXYNOS_PIN_BANK_EINTG(0x0C0, EXYNOS4210_GPIO_L0, "gpl0"),
-       EXYNOS_PIN_BANK_EINTG(0x0E0, EXYNOS4210_GPIO_L1, "gpl1"),
-       EXYNOS_PIN_BANK_EINTG(0x100, EXYNOS4210_GPIO_L2, "gpl2"),
-       EXYNOS_PIN_BANK_EINTN(0x120, EXYNOS4210_GPIO_Y0, "gpy0"),
-       EXYNOS_PIN_BANK_EINTN(0x140, EXYNOS4210_GPIO_Y1, "gpy1"),
-       EXYNOS_PIN_BANK_EINTN(0x160, EXYNOS4210_GPIO_Y2, "gpy2"),
-       EXYNOS_PIN_BANK_EINTN(0x180, EXYNOS4210_GPIO_Y3, "gpy3"),
-       EXYNOS_PIN_BANK_EINTN(0x1A0, EXYNOS4210_GPIO_Y4, "gpy4"),
-       EXYNOS_PIN_BANK_EINTN(0x1C0, EXYNOS4210_GPIO_Y5, "gpy5"),
-       EXYNOS_PIN_BANK_EINTN(0x1E0, EXYNOS4210_GPIO_Y6, "gpy6"),
-       EXYNOS_PIN_BANK_EINTN(0xC00, EXYNOS4210_GPIO_X0, "gpx0"),
-       EXYNOS_PIN_BANK_EINTN(0xC20, EXYNOS4210_GPIO_X1, "gpx1"),
-       EXYNOS_PIN_BANK_EINTN(0xC40, EXYNOS4210_GPIO_X2, "gpx2"),
-       EXYNOS_PIN_BANK_EINTN(0xC60, EXYNOS4210_GPIO_X3, "gpx3"),
+       EXYNOS_PIN_BANK_EINTG(8, 0x000, "gpj0", 0x00),
+       EXYNOS_PIN_BANK_EINTG(5, 0x020, "gpj1", 0x04),
+       EXYNOS_PIN_BANK_EINTG(7, 0x040, "gpk0", 0x08),
+       EXYNOS_PIN_BANK_EINTG(7, 0x060, "gpk1", 0x0c),
+       EXYNOS_PIN_BANK_EINTG(7, 0x080, "gpk2", 0x10),
+       EXYNOS_PIN_BANK_EINTG(7, 0x0A0, "gpk3", 0x14),
+       EXYNOS_PIN_BANK_EINTG(8, 0x0C0, "gpl0", 0x18),
+       EXYNOS_PIN_BANK_EINTG(3, 0x0E0, "gpl1", 0x1c),
+       EXYNOS_PIN_BANK_EINTG(8, 0x100, "gpl2", 0x20),
+       EXYNOS_PIN_BANK_EINTN(6, 0x120, "gpy0"),
+       EXYNOS_PIN_BANK_EINTN(4, 0x140, "gpy1"),
+       EXYNOS_PIN_BANK_EINTN(6, 0x160, "gpy2"),
+       EXYNOS_PIN_BANK_EINTN(8, 0x180, "gpy3"),
+       EXYNOS_PIN_BANK_EINTN(8, 0x1A0, "gpy4"),
+       EXYNOS_PIN_BANK_EINTN(8, 0x1C0, "gpy5"),
+       EXYNOS_PIN_BANK_EINTN(8, 0x1E0, "gpy6"),
+       EXYNOS_PIN_BANK_EINTW(8, 0xC00, "gpx0", 0x00),
+       EXYNOS_PIN_BANK_EINTW(8, 0xC20, "gpx1", 0x04),
+       EXYNOS_PIN_BANK_EINTW(8, 0xC40, "gpx2", 0x08),
+       EXYNOS_PIN_BANK_EINTW(8, 0xC60, "gpx3", 0x0c),
 };
 
 /* pin banks of exynos4210 pin-controller 2 */
 static struct samsung_pin_bank exynos4210_pin_banks2[] = {
-       EXYNOS_PIN_BANK_EINTN(0x000, EXYNOS4210_GPIO_Z, "gpz"),
+       EXYNOS_PIN_BANK_EINTN(7, 0x000, "gpz"),
 };
 
 /*
@@ -540,9 +539,6 @@ struct samsung_pin_ctrl exynos4210_pin_ctrl[] = {
                /* pin-controller instance 0 data */
                .pin_banks      = exynos4210_pin_banks0,
                .nr_banks       = ARRAY_SIZE(exynos4210_pin_banks0),
-               .base           = EXYNOS4210_GPIO_A0_START,
-               .nr_pins        = EXYNOS4210_GPIOA_NR_PINS,
-               .nr_gint        = EXYNOS4210_GPIOA_NR_GINT,
                .geint_con      = EXYNOS_GPIO_ECON_OFFSET,
                .geint_mask     = EXYNOS_GPIO_EMASK_OFFSET,
                .geint_pend     = EXYNOS_GPIO_EPEND_OFFSET,
@@ -553,10 +549,6 @@ struct samsung_pin_ctrl exynos4210_pin_ctrl[] = {
                /* pin-controller instance 1 data */
                .pin_banks      = exynos4210_pin_banks1,
                .nr_banks       = ARRAY_SIZE(exynos4210_pin_banks1),
-               .base           = EXYNOS4210_GPIOA_NR_PINS,
-               .nr_pins        = EXYNOS4210_GPIOB_NR_PINS,
-               .nr_gint        = EXYNOS4210_GPIOB_NR_GINT,
-               .nr_wint        = 32,
                .geint_con      = EXYNOS_GPIO_ECON_OFFSET,
                .geint_mask     = EXYNOS_GPIO_EMASK_OFFSET,
                .geint_pend     = EXYNOS_GPIO_EPEND_OFFSET,
@@ -571,9 +563,6 @@ struct samsung_pin_ctrl exynos4210_pin_ctrl[] = {
                /* pin-controller instance 2 data */
                .pin_banks      = exynos4210_pin_banks2,
                .nr_banks       = ARRAY_SIZE(exynos4210_pin_banks2),
-               .base           = EXYNOS4210_GPIOA_NR_PINS +
-                                       EXYNOS4210_GPIOB_NR_PINS,
-               .nr_pins        = EXYNOS4210_GPIOC_NR_PINS,
                .label          = "exynos4210-gpio-ctrl2",
        },
 };
index 31d0a06174e4a21f53253f9c947ce1d90006a1e7..0a708890d8b4431c701c58b5af9de62782ec0a18 100644 (file)
  * (at your option) any later version.
  */
 
-#define EXYNOS_GPIO_START(__gpio)      ((__gpio##_START) + (__gpio##_NR))
-
-#define EXYNOS4210_GPIO_A0_NR  (8)
-#define EXYNOS4210_GPIO_A1_NR  (6)
-#define EXYNOS4210_GPIO_B_NR   (8)
-#define EXYNOS4210_GPIO_C0_NR  (5)
-#define EXYNOS4210_GPIO_C1_NR  (5)
-#define EXYNOS4210_GPIO_D0_NR  (4)
-#define EXYNOS4210_GPIO_D1_NR  (4)
-#define EXYNOS4210_GPIO_E0_NR  (5)
-#define EXYNOS4210_GPIO_E1_NR  (8)
-#define EXYNOS4210_GPIO_E2_NR  (6)
-#define EXYNOS4210_GPIO_E3_NR  (8)
-#define EXYNOS4210_GPIO_E4_NR  (8)
-#define EXYNOS4210_GPIO_F0_NR  (8)
-#define EXYNOS4210_GPIO_F1_NR  (8)
-#define EXYNOS4210_GPIO_F2_NR  (8)
-#define EXYNOS4210_GPIO_F3_NR  (6)
-#define EXYNOS4210_GPIO_J0_NR  (8)
-#define EXYNOS4210_GPIO_J1_NR  (5)
-#define EXYNOS4210_GPIO_K0_NR  (7)
-#define EXYNOS4210_GPIO_K1_NR  (7)
-#define EXYNOS4210_GPIO_K2_NR  (7)
-#define EXYNOS4210_GPIO_K3_NR  (7)
-#define EXYNOS4210_GPIO_L0_NR  (8)
-#define EXYNOS4210_GPIO_L1_NR  (3)
-#define EXYNOS4210_GPIO_L2_NR  (8)
-#define EXYNOS4210_GPIO_Y0_NR  (6)
-#define EXYNOS4210_GPIO_Y1_NR  (4)
-#define EXYNOS4210_GPIO_Y2_NR  (6)
-#define EXYNOS4210_GPIO_Y3_NR  (8)
-#define EXYNOS4210_GPIO_Y4_NR  (8)
-#define EXYNOS4210_GPIO_Y5_NR  (8)
-#define EXYNOS4210_GPIO_Y6_NR  (8)
-#define EXYNOS4210_GPIO_X0_NR  (8)
-#define EXYNOS4210_GPIO_X1_NR  (8)
-#define EXYNOS4210_GPIO_X2_NR  (8)
-#define EXYNOS4210_GPIO_X3_NR  (8)
-#define EXYNOS4210_GPIO_Z_NR   (7)
-
-enum exynos4210_gpio_xa_start {
-       EXYNOS4210_GPIO_A0_START        = 0,
-       EXYNOS4210_GPIO_A1_START        = EXYNOS_GPIO_START(EXYNOS4210_GPIO_A0),
-       EXYNOS4210_GPIO_B_START         = EXYNOS_GPIO_START(EXYNOS4210_GPIO_A1),
-       EXYNOS4210_GPIO_C0_START        = EXYNOS_GPIO_START(EXYNOS4210_GPIO_B),
-       EXYNOS4210_GPIO_C1_START        = EXYNOS_GPIO_START(EXYNOS4210_GPIO_C0),
-       EXYNOS4210_GPIO_D0_START        = EXYNOS_GPIO_START(EXYNOS4210_GPIO_C1),
-       EXYNOS4210_GPIO_D1_START        = EXYNOS_GPIO_START(EXYNOS4210_GPIO_D0),
-       EXYNOS4210_GPIO_E0_START        = EXYNOS_GPIO_START(EXYNOS4210_GPIO_D1),
-       EXYNOS4210_GPIO_E1_START        = EXYNOS_GPIO_START(EXYNOS4210_GPIO_E0),
-       EXYNOS4210_GPIO_E2_START        = EXYNOS_GPIO_START(EXYNOS4210_GPIO_E1),
-       EXYNOS4210_GPIO_E3_START        = EXYNOS_GPIO_START(EXYNOS4210_GPIO_E2),
-       EXYNOS4210_GPIO_E4_START        = EXYNOS_GPIO_START(EXYNOS4210_GPIO_E3),
-       EXYNOS4210_GPIO_F0_START        = EXYNOS_GPIO_START(EXYNOS4210_GPIO_E4),
-       EXYNOS4210_GPIO_F1_START        = EXYNOS_GPIO_START(EXYNOS4210_GPIO_F0),
-       EXYNOS4210_GPIO_F2_START        = EXYNOS_GPIO_START(EXYNOS4210_GPIO_F1),
-       EXYNOS4210_GPIO_F3_START        = EXYNOS_GPIO_START(EXYNOS4210_GPIO_F2),
-};
-
-enum exynos4210_gpio_xb_start {
-       EXYNOS4210_GPIO_J0_START        = 0,
-       EXYNOS4210_GPIO_J1_START        = EXYNOS_GPIO_START(EXYNOS4210_GPIO_J0),
-       EXYNOS4210_GPIO_K0_START        = EXYNOS_GPIO_START(EXYNOS4210_GPIO_J1),
-       EXYNOS4210_GPIO_K1_START        = EXYNOS_GPIO_START(EXYNOS4210_GPIO_K0),
-       EXYNOS4210_GPIO_K2_START        = EXYNOS_GPIO_START(EXYNOS4210_GPIO_K1),
-       EXYNOS4210_GPIO_K3_START        = EXYNOS_GPIO_START(EXYNOS4210_GPIO_K2),
-       EXYNOS4210_GPIO_L0_START        = EXYNOS_GPIO_START(EXYNOS4210_GPIO_K3),
-       EXYNOS4210_GPIO_L1_START        = EXYNOS_GPIO_START(EXYNOS4210_GPIO_L0),
-       EXYNOS4210_GPIO_L2_START        = EXYNOS_GPIO_START(EXYNOS4210_GPIO_L1),
-       EXYNOS4210_GPIO_Y0_START        = EXYNOS_GPIO_START(EXYNOS4210_GPIO_L2),
-       EXYNOS4210_GPIO_Y1_START        = EXYNOS_GPIO_START(EXYNOS4210_GPIO_Y0),
-       EXYNOS4210_GPIO_Y2_START        = EXYNOS_GPIO_START(EXYNOS4210_GPIO_Y1),
-       EXYNOS4210_GPIO_Y3_START        = EXYNOS_GPIO_START(EXYNOS4210_GPIO_Y2),
-       EXYNOS4210_GPIO_Y4_START        = EXYNOS_GPIO_START(EXYNOS4210_GPIO_Y3),
-       EXYNOS4210_GPIO_Y5_START        = EXYNOS_GPIO_START(EXYNOS4210_GPIO_Y4),
-       EXYNOS4210_GPIO_Y6_START        = EXYNOS_GPIO_START(EXYNOS4210_GPIO_Y5),
-       EXYNOS4210_GPIO_X0_START        = EXYNOS_GPIO_START(EXYNOS4210_GPIO_Y6),
-       EXYNOS4210_GPIO_X1_START        = EXYNOS_GPIO_START(EXYNOS4210_GPIO_X0),
-       EXYNOS4210_GPIO_X2_START        = EXYNOS_GPIO_START(EXYNOS4210_GPIO_X1),
-       EXYNOS4210_GPIO_X3_START        = EXYNOS_GPIO_START(EXYNOS4210_GPIO_X2),
-};
-
-enum exynos4210_gpio_xc_start {
-       EXYNOS4210_GPIO_Z_START         = 0,
-};
-
-#define        EXYNOS4210_GPIO_A0_IRQ          EXYNOS4210_GPIO_A0_START
-#define        EXYNOS4210_GPIO_A1_IRQ          EXYNOS4210_GPIO_A1_START
-#define        EXYNOS4210_GPIO_B_IRQ           EXYNOS4210_GPIO_B_START
-#define        EXYNOS4210_GPIO_C0_IRQ          EXYNOS4210_GPIO_C0_START
-#define        EXYNOS4210_GPIO_C1_IRQ          EXYNOS4210_GPIO_C1_START
-#define        EXYNOS4210_GPIO_D0_IRQ          EXYNOS4210_GPIO_D0_START
-#define        EXYNOS4210_GPIO_D1_IRQ          EXYNOS4210_GPIO_D1_START
-#define        EXYNOS4210_GPIO_E0_IRQ          EXYNOS4210_GPIO_E0_START
-#define        EXYNOS4210_GPIO_E1_IRQ          EXYNOS4210_GPIO_E1_START
-#define        EXYNOS4210_GPIO_E2_IRQ          EXYNOS4210_GPIO_E2_START
-#define        EXYNOS4210_GPIO_E3_IRQ          EXYNOS4210_GPIO_E3_START
-#define        EXYNOS4210_GPIO_E4_IRQ          EXYNOS4210_GPIO_E4_START
-#define        EXYNOS4210_GPIO_F0_IRQ          EXYNOS4210_GPIO_F0_START
-#define        EXYNOS4210_GPIO_F1_IRQ          EXYNOS4210_GPIO_F1_START
-#define        EXYNOS4210_GPIO_F2_IRQ          EXYNOS4210_GPIO_F2_START
-#define        EXYNOS4210_GPIO_F3_IRQ          EXYNOS4210_GPIO_F3_START
-#define        EXYNOS4210_GPIO_J0_IRQ          EXYNOS4210_GPIO_J0_START
-#define        EXYNOS4210_GPIO_J1_IRQ          EXYNOS4210_GPIO_J1_START
-#define        EXYNOS4210_GPIO_K0_IRQ          EXYNOS4210_GPIO_K0_START
-#define        EXYNOS4210_GPIO_K1_IRQ          EXYNOS4210_GPIO_K1_START
-#define        EXYNOS4210_GPIO_K2_IRQ          EXYNOS4210_GPIO_K2_START
-#define        EXYNOS4210_GPIO_K3_IRQ          EXYNOS4210_GPIO_K3_START
-#define        EXYNOS4210_GPIO_L0_IRQ          EXYNOS4210_GPIO_L0_START
-#define        EXYNOS4210_GPIO_L1_IRQ          EXYNOS4210_GPIO_L1_START
-#define        EXYNOS4210_GPIO_L2_IRQ          EXYNOS4210_GPIO_L2_START
-#define        EXYNOS4210_GPIO_Z_IRQ           EXYNOS4210_GPIO_Z_START
-
-#define EXYNOS4210_GPIOA_NR_PINS       EXYNOS_GPIO_START(EXYNOS4210_GPIO_F3)
-#define EXYNOS4210_GPIOA_NR_GINT       EXYNOS_GPIO_START(EXYNOS4210_GPIO_F3)
-#define EXYNOS4210_GPIOB_NR_PINS       EXYNOS_GPIO_START(EXYNOS4210_GPIO_X3)
-#define EXYNOS4210_GPIOB_NR_GINT       EXYNOS_GPIO_START(EXYNOS4210_GPIO_L2)
-#define EXYNOS4210_GPIOC_NR_PINS       EXYNOS_GPIO_START(EXYNOS4210_GPIO_Z)
-
 /* External GPIO and wakeup interrupt related definitions */
 #define EXYNOS_GPIO_ECON_OFFSET                0x700
 #define EXYNOS_GPIO_EMASK_OFFSET       0x900
@@ -165,11 +46,10 @@ enum exynos4210_gpio_xc_start {
 #define EXYNOS_EINT_MAX_PER_BANK       8
 #define EXYNOS_EINT_NR_WKUP_EINT
 
-#define EXYNOS_PIN_BANK_EINTN(reg, __gpio, id)         \
+#define EXYNOS_PIN_BANK_EINTN(pins, reg, id)           \
        {                                               \
                .pctl_offset    = reg,                  \
-               .pin_base       = (__gpio##_START),     \
-               .nr_pins        = (__gpio##_NR),        \
+               .nr_pins        = pins,                 \
                .func_width     = 4,                    \
                .pud_width      = 2,                    \
                .drv_width      = 2,                    \
@@ -179,40 +59,50 @@ enum exynos4210_gpio_xc_start {
                .name           = id                    \
        }
 
-#define EXYNOS_PIN_BANK_EINTG(reg, __gpio, id)         \
+#define EXYNOS_PIN_BANK_EINTG(pins, reg, id, offs)     \
        {                                               \
                .pctl_offset    = reg,                  \
-               .pin_base       = (__gpio##_START),     \
-               .nr_pins        = (__gpio##_NR),        \
+               .nr_pins        = pins,                 \
                .func_width     = 4,                    \
                .pud_width      = 2,                    \
                .drv_width      = 2,                    \
                .conpdn_width   = 2,                    \
                .pudpdn_width   = 2,                    \
                .eint_type      = EINT_TYPE_GPIO,       \
-               .irq_base       = (__gpio##_IRQ),       \
+               .eint_offset    = offs,                 \
                .name           = id                    \
        }
 
-/**
- * struct exynos_geint_data: gpio eint specific data for irq_chip callbacks.
- * @bank: pin bank from which this gpio interrupt originates.
- * @pin: pin number within the bank.
- * @eint_offset: offset to be added to the con/pend/mask register bank base.
- */
-struct exynos_geint_data {
-       struct samsung_pin_bank *bank;
-       u32                     pin;
-       u32                     eint_offset;
-};
+#define EXYNOS_PIN_BANK_EINTW(pins, reg, id, offs)     \
+       {                                               \
+               .pctl_offset    = reg,                  \
+               .nr_pins        = pins,                 \
+               .func_width     = 4,                    \
+               .pud_width      = 2,                    \
+               .drv_width      = 2,                    \
+               .eint_type      = EINT_TYPE_WKUP,       \
+               .eint_offset    = offs,                 \
+               .name           = id                    \
+       }
 
 /**
  * struct exynos_weint_data: irq specific data for all the wakeup interrupts
  * generated by the external wakeup interrupt controller.
- * @domain: irq domain representing the external wakeup interrupts
  * @irq: interrupt number within the domain.
+ * @bank: bank responsible for this interrupt
  */
 struct exynos_weint_data {
-       struct irq_domain       *domain;
-       u32                     irq;
+       unsigned int irq;
+       struct samsung_pin_bank *bank;
+};
+
+/**
+ * struct exynos_muxed_weint_data: irq specific data for muxed wakeup interrupts
+ * generated by the external wakeup interrupt controller.
+ * @nr_banks: count of banks being part of the mux
+ * @banks: array of banks being part of the mux
+ */
+struct exynos_muxed_weint_data {
+       unsigned int nr_banks;
+       struct samsung_pin_bank *banks[];
 };
index 861cd5f04d5e12ba2aa497cc39934a56b0680a7b..fc34cac8a1b054ca4cc9095cedce2afd2273e17b 100644 (file)
@@ -26,6 +26,7 @@
 #include <linux/slab.h>
 #include <linux/err.h>
 #include <linux/gpio.h>
+#include <linux/irqdomain.h>
 
 #include "core.h"
 #include "pinctrl-samsung.h"
@@ -46,6 +47,13 @@ struct pin_config {
        { "samsung,pin-pud-pdn", PINCFG_TYPE_PUD_PDN },
 };
 
+static unsigned int pin_base = 0;
+
+static inline struct samsung_pin_bank *gc_to_pin_bank(struct gpio_chip *gc)
+{
+       return container_of(gc, struct samsung_pin_bank, gpio_chip);
+}
+
 /* check if the selector is a valid pin group selector */
 static int samsung_get_group_count(struct pinctrl_dev *pctldev)
 {
@@ -250,14 +258,12 @@ static int samsung_pinmux_get_groups(struct pinctrl_dev *pctldev,
  * given a pin number that is local to a pin controller, find out the pin bank
  * and the register base of the pin bank.
  */
-static void pin_to_reg_bank(struct gpio_chip *gc, unsigned pin,
-                       void __iomem **reg, u32 *offset,
+static void pin_to_reg_bank(struct samsung_pinctrl_drv_data *drvdata,
+                       unsigned pin, void __iomem **reg, u32 *offset,
                        struct samsung_pin_bank **bank)
 {
-       struct samsung_pinctrl_drv_data *drvdata;
        struct samsung_pin_bank *b;
 
-       drvdata = dev_get_drvdata(gc->dev);
        b = drvdata->ctrl->pin_banks;
 
        while ((pin >= b->pin_base) &&
@@ -292,7 +298,7 @@ static void samsung_pinmux_setup(struct pinctrl_dev *pctldev, unsigned selector,
         * pin function number in the config register.
         */
        for (cnt = 0; cnt < drvdata->pin_groups[group].num_pins; cnt++) {
-               pin_to_reg_bank(drvdata->gc, pins[cnt] - drvdata->ctrl->base,
+               pin_to_reg_bank(drvdata, pins[cnt] - drvdata->ctrl->base,
                                &reg, &pin_offset, &bank);
                mask = (1 << bank->func_width) - 1;
                shift = pin_offset * bank->func_width;
@@ -329,10 +335,16 @@ static int samsung_pinmux_gpio_set_direction(struct pinctrl_dev *pctldev,
                struct pinctrl_gpio_range *range, unsigned offset, bool input)
 {
        struct samsung_pin_bank *bank;
+       struct samsung_pinctrl_drv_data *drvdata;
        void __iomem *reg;
        u32 data, pin_offset, mask, shift;
 
-       pin_to_reg_bank(range->gc, offset, &reg, &pin_offset, &bank);
+       bank = gc_to_pin_bank(range->gc);
+       drvdata = pinctrl_dev_get_drvdata(pctldev);
+
+       pin_offset = offset - bank->pin_base;
+       reg = drvdata->virt_base + bank->pctl_offset;
+
        mask = (1 << bank->func_width) - 1;
        shift = pin_offset * bank->func_width;
 
@@ -366,7 +378,7 @@ static int samsung_pinconf_rw(struct pinctrl_dev *pctldev, unsigned int pin,
        u32 cfg_value, cfg_reg;
 
        drvdata = pinctrl_dev_get_drvdata(pctldev);
-       pin_to_reg_bank(drvdata->gc, pin - drvdata->ctrl->base, &reg_base,
+       pin_to_reg_bank(drvdata, pin - drvdata->ctrl->base, &reg_base,
                                        &pin_offset, &bank);
 
        switch (cfg_type) {
@@ -391,6 +403,9 @@ static int samsung_pinconf_rw(struct pinctrl_dev *pctldev, unsigned int pin,
                return -EINVAL;
        }
 
+       if (!width)
+               return -EINVAL;
+
        mask = (1 << width) - 1;
        shift = pin_offset * width;
        data = readl(reg_base + cfg_reg);
@@ -463,14 +478,16 @@ static struct pinconf_ops samsung_pinconf_ops = {
 /* gpiolib gpio_set callback function */
 static void samsung_gpio_set(struct gpio_chip *gc, unsigned offset, int value)
 {
+       struct samsung_pin_bank *bank = gc_to_pin_bank(gc);
        void __iomem *reg;
-       u32 pin_offset, data;
+       u32 data;
+
+       reg = bank->drvdata->virt_base + bank->pctl_offset;
 
-       pin_to_reg_bank(gc, offset, &reg, &pin_offset, NULL);
        data = readl(reg + DAT_REG);
-       data &= ~(1 << pin_offset);
+       data &= ~(1 << offset);
        if (value)
-               data |= 1 << pin_offset;
+               data |= 1 << offset;
        writel(data, reg + DAT_REG);
 }
 
@@ -478,11 +495,13 @@ static void samsung_gpio_set(struct gpio_chip *gc, unsigned offset, int value)
 static int samsung_gpio_get(struct gpio_chip *gc, unsigned offset)
 {
        void __iomem *reg;
-       u32 pin_offset, data;
+       u32 data;
+       struct samsung_pin_bank *bank = gc_to_pin_bank(gc);
+
+       reg = bank->drvdata->virt_base + bank->pctl_offset;
 
-       pin_to_reg_bank(gc, offset, &reg, &pin_offset, NULL);
        data = readl(reg + DAT_REG);
-       data >>= pin_offset;
+       data >>= offset;
        data &= 1;
        return data;
 }
@@ -509,6 +528,23 @@ static int samsung_gpio_direction_output(struct gpio_chip *gc, unsigned offset,
        return pinctrl_gpio_direction_output(gc->base + offset);
 }
 
+/*
+ * gpiolib gpio_to_irq callback function. Creates a mapping between a GPIO pin
+ * and a virtual IRQ, if not already present.
+ */
+static int samsung_gpio_to_irq(struct gpio_chip *gc, unsigned offset)
+{
+       struct samsung_pin_bank *bank = gc_to_pin_bank(gc);
+       unsigned int virq;
+
+       if (!bank->irq_domain)
+               return -ENXIO;
+
+       virq = irq_create_mapping(bank->irq_domain, offset);
+
+       return (virq) ? : -ENXIO;
+}
+
 /*
  * Parse the pin names listed in the 'samsung,pins' property and convert it
  * into a list of gpio numbers are create a pin group from it.
@@ -597,7 +633,7 @@ static int __devinit samsung_pinctrl_parse_dt(struct platform_device *pdev,
         */
        for_each_child_of_node(dev_np, cfg_np) {
                u32 function;
-               if (of_find_property(cfg_np, "interrupt-controller", NULL))
+               if (!of_find_property(cfg_np, "samsung,pins", NULL))
                        continue;
 
                ret = samsung_pinctrl_parse_dt_pins(pdev, cfg_np,
@@ -712,12 +748,16 @@ static int __devinit samsung_pinctrl_register(struct platform_device *pdev,
                return -EINVAL;
        }
 
-       drvdata->grange.name = "samsung-pctrl-gpio-range";
-       drvdata->grange.id = 0;
-       drvdata->grange.base = drvdata->ctrl->base;
-       drvdata->grange.npins = drvdata->ctrl->nr_pins;
-       drvdata->grange.gc = drvdata->gc;
-       pinctrl_add_gpio_range(drvdata->pctl_dev, &drvdata->grange);
+       for (bank = 0; bank < drvdata->ctrl->nr_banks; ++bank) {
+               pin_bank = &drvdata->ctrl->pin_banks[bank];
+               pin_bank->grange.name = pin_bank->name;
+               pin_bank->grange.id = bank;
+               pin_bank->grange.pin_base = pin_bank->pin_base;
+               pin_bank->grange.base = pin_bank->gpio_chip.base;
+               pin_bank->grange.npins = pin_bank->gpio_chip.ngpio;
+               pin_bank->grange.gc = &pin_bank->gpio_chip;
+               pinctrl_add_gpio_range(drvdata->pctl_dev, &pin_bank->grange);
+       }
 
        ret = samsung_pinctrl_parse_dt(pdev, drvdata);
        if (ret) {
@@ -728,68 +768,117 @@ static int __devinit samsung_pinctrl_register(struct platform_device *pdev,
        return 0;
 }
 
+static const struct gpio_chip samsung_gpiolib_chip = {
+       .set = samsung_gpio_set,
+       .get = samsung_gpio_get,
+       .direction_input = samsung_gpio_direction_input,
+       .direction_output = samsung_gpio_direction_output,
+       .to_irq = samsung_gpio_to_irq,
+       .owner = THIS_MODULE,
+};
+
 /* register the gpiolib interface with the gpiolib subsystem */
 static int __devinit samsung_gpiolib_register(struct platform_device *pdev,
                                struct samsung_pinctrl_drv_data *drvdata)
 {
+       struct samsung_pin_ctrl *ctrl = drvdata->ctrl;
+       struct samsung_pin_bank *bank = ctrl->pin_banks;
        struct gpio_chip *gc;
        int ret;
-
-       gc = devm_kzalloc(&pdev->dev, sizeof(*gc), GFP_KERNEL);
-       if (!gc) {
-               dev_err(&pdev->dev, "mem alloc for gpio_chip failed\n");
-               return -ENOMEM;
-       }
-
-       drvdata->gc = gc;
-       gc->base = drvdata->ctrl->base;
-       gc->ngpio = drvdata->ctrl->nr_pins;
-       gc->dev = &pdev->dev;
-       gc->set = samsung_gpio_set;
-       gc->get = samsung_gpio_get;
-       gc->direction_input = samsung_gpio_direction_input;
-       gc->direction_output = samsung_gpio_direction_output;
-       gc->label = drvdata->ctrl->label;
-       gc->owner = THIS_MODULE;
-       ret = gpiochip_add(gc);
-       if (ret) {
-               dev_err(&pdev->dev, "failed to register gpio_chip %s, error "
-                                       "code: %d\n", gc->label, ret);
-               return ret;
+       int i;
+
+       for (i = 0; i < ctrl->nr_banks; ++i, ++bank) {
+               bank->gpio_chip = samsung_gpiolib_chip;
+
+               gc = &bank->gpio_chip;
+               gc->base = ctrl->base + bank->pin_base;
+               gc->ngpio = bank->nr_pins;
+               gc->dev = &pdev->dev;
+               gc->of_node = bank->of_node;
+               gc->label = bank->name;
+
+               ret = gpiochip_add(gc);
+               if (ret) {
+                       dev_err(&pdev->dev, "failed to register gpio_chip %s, error code: %d\n",
+                                                       gc->label, ret);
+                       goto fail;
+               }
        }
 
        return 0;
+
+fail:
+       for (--i, --bank; i >= 0; --i, --bank)
+               if (gpiochip_remove(&bank->gpio_chip))
+                       dev_err(&pdev->dev, "gpio chip %s remove failed\n",
+                                                       bank->gpio_chip.label);
+       return ret;
 }
 
 /* unregister the gpiolib interface with the gpiolib subsystem */
 static int __devinit samsung_gpiolib_unregister(struct platform_device *pdev,
                                struct samsung_pinctrl_drv_data *drvdata)
 {
-       int ret = gpiochip_remove(drvdata->gc);
-       if (ret) {
+       struct samsung_pin_ctrl *ctrl = drvdata->ctrl;
+       struct samsung_pin_bank *bank = ctrl->pin_banks;
+       int ret = 0;
+       int i;
+
+       for (i = 0; !ret && i < ctrl->nr_banks; ++i, ++bank)
+               ret = gpiochip_remove(&bank->gpio_chip);
+
+       if (ret)
                dev_err(&pdev->dev, "gpio chip remove failed\n");
-               return ret;
-       }
-       return 0;
+
+       return ret;
 }
 
 static const struct of_device_id samsung_pinctrl_dt_match[];
 
 /* retrieve the soc specific data */
 static struct samsung_pin_ctrl *samsung_pinctrl_get_soc_data(
+                               struct samsung_pinctrl_drv_data *d,
                                struct platform_device *pdev)
 {
        int id;
        const struct of_device_id *match;
-       const struct device_node *node = pdev->dev.of_node;
+       struct device_node *node = pdev->dev.of_node;
+       struct device_node *np;
+       struct samsung_pin_ctrl *ctrl;
+       struct samsung_pin_bank *bank;
+       int i;
 
-       id = of_alias_get_id(pdev->dev.of_node, "pinctrl");
+       id = of_alias_get_id(node, "pinctrl");
        if (id < 0) {
                dev_err(&pdev->dev, "failed to get alias id\n");
                return NULL;
        }
        match = of_match_node(samsung_pinctrl_dt_match, node);
-       return (struct samsung_pin_ctrl *)match->data + id;
+       ctrl = (struct samsung_pin_ctrl *)match->data + id;
+
+       bank = ctrl->pin_banks;
+       for (i = 0; i < ctrl->nr_banks; ++i, ++bank) {
+               bank->drvdata = d;
+               bank->pin_base = ctrl->nr_pins;
+               ctrl->nr_pins += bank->nr_pins;
+       }
+
+       for_each_child_of_node(node, np) {
+               if (!of_find_property(np, "gpio-controller", NULL))
+                       continue;
+               bank = ctrl->pin_banks;
+               for (i = 0; i < ctrl->nr_banks; ++i, ++bank) {
+                       if (!strcmp(bank->name, np->name)) {
+                               bank->of_node = np;
+                               break;
+                       }
+               }
+       }
+
+       ctrl->base = pin_base;
+       pin_base += ctrl->nr_pins;
+
+       return ctrl;
 }
 
 static int __devinit samsung_pinctrl_probe(struct platform_device *pdev)
@@ -805,18 +894,18 @@ static int __devinit samsung_pinctrl_probe(struct platform_device *pdev)
                return -ENODEV;
        }
 
-       ctrl = samsung_pinctrl_get_soc_data(pdev);
-       if (!ctrl) {
-               dev_err(&pdev->dev, "driver data not available\n");
-               return -EINVAL;
-       }
-
        drvdata = devm_kzalloc(dev, sizeof(*drvdata), GFP_KERNEL);
        if (!drvdata) {
                dev_err(dev, "failed to allocate memory for driver's "
                                "private data\n");
                return -ENOMEM;
        }
+
+       ctrl = samsung_pinctrl_get_soc_data(drvdata, pdev);
+       if (!ctrl) {
+               dev_err(&pdev->dev, "driver data not available\n");
+               return -EINVAL;
+       }
        drvdata->ctrl = ctrl;
        drvdata->dev = dev;
 
index b8956934cda683c8ecc99f8c8a64b1b0a27bf546..0670d9ea43fa5a45c49ed898288fc8709d57810e 100644 (file)
@@ -23,6 +23,8 @@
 #include <linux/pinctrl/consumer.h>
 #include <linux/pinctrl/machine.h>
 
+#include <linux/gpio.h>
+
 /* register offsets within a pin bank */
 #define DAT_REG                0x4
 #define PUD_REG                0x8
@@ -64,6 +66,7 @@ enum pincfg_type {
  * @EINT_TYPE_NONE: bank does not support external interrupts
  * @EINT_TYPE_GPIO: bank supportes external gpio interrupts
  * @EINT_TYPE_WKUP: bank supportes external wakeup interrupts
+ * @EINT_TYPE_WKUP_MUX: bank supports multiplexed external wakeup interrupts
  *
  * Samsung GPIO controller groups all the available pins into banks. The pins
  * in a pin bank can support external gpio interrupts or external wakeup
@@ -76,6 +79,7 @@ enum eint_type {
        EINT_TYPE_NONE,
        EINT_TYPE_GPIO,
        EINT_TYPE_WKUP,
+       EINT_TYPE_WKUP_MUX,
 };
 
 /* maximum length of a pin in pin descriptor (example: "gpa0-0") */
@@ -109,8 +113,12 @@ struct samsung_pinctrl_drv_data;
  * @conpdn_width: width of the sleep mode function selector bin field.
  * @pudpdn_width: width of the sleep mode pull up/down selector bit field.
  * @eint_type: type of the external interrupt supported by the bank.
- * @irq_base: starting controller local irq number of the bank.
  * @name: name to be prefixed for each pin in this pin bank.
+ * @of_node: OF node of the bank.
+ * @drvdata: link to controller driver data
+ * @irq_domain: IRQ domain of the bank.
+ * @gpio_chip: GPIO chip of the bank.
+ * @grange: linux gpio pin range supported by this bank.
  */
 struct samsung_pin_bank {
        u32             pctl_offset;
@@ -122,8 +130,13 @@ struct samsung_pin_bank {
        u8              conpdn_width;
        u8              pudpdn_width;
        enum eint_type  eint_type;
-       u32             irq_base;
+       u32             eint_offset;
        char            *name;
+       struct device_node *of_node;
+       struct samsung_pinctrl_drv_data *drvdata;
+       struct irq_domain *irq_domain;
+       struct gpio_chip gpio_chip;
+       struct pinctrl_gpio_range grange;
 };
 
 /**
@@ -132,8 +145,6 @@ struct samsung_pin_bank {
  * @nr_banks: number of pin banks.
  * @base: starting system wide pin number.
  * @nr_pins: number of pins supported by the controller.
- * @nr_gint: number of external gpio interrupts supported.
- * @nr_wint: number of external wakeup interrupts supported.
  * @geint_con: offset of the ext-gpio controller registers.
  * @geint_mask: offset of the ext-gpio interrupt mask registers.
  * @geint_pend: offset of the ext-gpio interrupt pending registers.
@@ -153,8 +164,6 @@ struct samsung_pin_ctrl {
 
        u32             base;
        u32             nr_pins;
-       u32             nr_gint;
-       u32             nr_wint;
 
        u32             geint_con;
        u32             geint_mask;
@@ -183,8 +192,6 @@ struct samsung_pin_ctrl {
  * @nr_groups: number of such pin groups.
  * @pmx_functions: list of pin functions available to the driver.
  * @nr_function: number of such pin functions.
- * @gc: gpio_chip instance registered with gpiolib.
- * @grange: linux gpio pin range supported by this controller.
  */
 struct samsung_pinctrl_drv_data {
        void __iomem                    *virt_base;
@@ -199,12 +206,6 @@ struct samsung_pinctrl_drv_data {
        unsigned int                    nr_groups;
        const struct samsung_pmx_func   *pmx_functions;
        unsigned int                    nr_functions;
-
-       struct irq_domain               *gpio_irqd;
-       struct irq_domain               *wkup_irqd;
-
-       struct gpio_chip                *gc;
-       struct pinctrl_gpio_range       grange;
 };
 
 /**