diff options
| author | Olof Johansson <olof@lixom.net> | 2012-11-21 10:18:54 -0800 |
|---|---|---|
| committer | Olof Johansson <olof@lixom.net> | 2012-11-21 10:18:54 -0800 |
| commit | 41739b60b3c00e0591d1a413276ddfa0d0b1ea89 (patch) | |
| tree | 9d94865a3ace7e1f2d6f892c0fe03ffc896cafd1 | |
| parent | 24e93941f26e28b2f884d30dc8bfb4c7c5d905d1 (diff) | |
| parent | 4a991b410cd7940c48f261e854e8698923e23fd2 (diff) | |
Merge branch 'samsung/pinctrl' into next/soc
From Kukjin Kim:
Here is Samsung DT for v3.8 and this is including DT for EXYNOS4X12
SoC, SMDK4412 board, pinctrl for exynos4x12, TMU, MFC, SATA and SATA
PHY.
As I commented on [4/7], this branch merged pinctrl/samsung to support
pinctrl for exynos4x12 without useless merge conflicts.
* samsung/pinctrl:
pinctrl: samsung: Update error check for unsigned variables
pinctrl: samsung: Add support for EXYNOS4X12
Documentation: Update samsung-pinctrl device tree bindings documentation
pinctrl: samsung: Add GPIO to IRQ translation
pinctrl: exynos: Set pin function to EINT in irq_set_type of wake-up EINT
pinctrl: samsung: Use per-bank IRQ domain for wake-up interrupts
pinctrl: samsung: Use one GPIO chip per pin bank
pinctrl: exynos: Use one IRQ domain per pin bank
pinctrl: samsung: Include bank-specific eint offset in bank struct
pinctrl: samsung: Hold pointer to driver data in bank struct
pinctrl: samsung: Match pin banks with their device nodes
ARM: dts: exynos4210-pinctrl: Add nodes for pin banks
pinctrl: samsung: Distinguish between pin group and bank nodes
pinctrl: samsung: Remove static pin enumerations
pinctrl: samsung: Assing pin numbers dynamically
pinctrl: samsung: Do not pass gpio_chip to pin_to_reg_bank
pinctrl: samsung: Detect and handle unsupported configuration types
| -rw-r--r-- | Documentation/devicetree/bindings/pinctrl/samsung-pinctrl.txt | 119 | ||||
| -rw-r--r-- | arch/arm/boot/dts/exynos4210-pinctrl.dtsi | 278 | ||||
| -rw-r--r-- | arch/arm/boot/dts/exynos4210.dtsi | 241 | ||||
| -rw-r--r-- | drivers/pinctrl/pinctrl-exynos.c | 477 | ||||
| -rw-r--r-- | drivers/pinctrl/pinctrl-exynos.h | 170 | ||||
| -rw-r--r-- | drivers/pinctrl/pinctrl-samsung.c | 207 | ||||
| -rw-r--r-- | drivers/pinctrl/pinctrl-samsung.h | 30 |
7 files changed, 856 insertions, 666 deletions
diff --git a/Documentation/devicetree/bindings/pinctrl/samsung-pinctrl.txt b/Documentation/devicetree/bindings/pinctrl/samsung-pinctrl.txt index 03dee50532f5..e97a27856b21 100644 --- a/Documentation/devicetree/bindings/pinctrl/samsung-pinctrl.txt +++ b/Documentation/devicetree/bindings/pinctrl/samsung-pinctrl.txt @@ -8,13 +8,20 @@ on-chip controllers onto these pads. Required Properties: - compatible: should be one of the following. - "samsung,pinctrl-exynos4210": for Exynos4210 compatible pin-controller. + - "samsung,pinctrl-exynos4x12": for Exynos4x12 compatible pin-controller. - "samsung,pinctrl-exynos5250": for Exynos5250 compatible pin-controller. - 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 +79,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 +109,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 +125,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 +189,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 +232,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 +258,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); } diff --git a/arch/arm/boot/dts/exynos4210-pinctrl.dtsi b/arch/arm/boot/dts/exynos4210-pinctrl.dtsi index b12cf272ad0d..6a4a1a04221c 100644 --- a/arch/arm/boot/dts/exynos4210-pinctrl.dtsi +++ b/arch/arm/boot/dts/exynos4210-pinctrl.dtsi @@ -16,6 +16,134 @@ / { 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>; @@ -205,6 +333,151 @@ }; 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>; @@ -438,6 +711,11 @@ }; 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"; diff --git a/arch/arm/boot/dts/exynos4210.dtsi b/arch/arm/boot/dts/exynos4210.dtsi index 214c557eda7f..d877dbe7ac0e 100644 --- a/arch/arm/boot/dts/exynos4210.dtsi +++ b/arch/arm/boot/dts/exynos4210.dtsi @@ -46,27 +46,17 @@ 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>; }; }; @@ -74,233 +64,4 @@ 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>; - }; - }; }; diff --git a/drivers/pinctrl/pinctrl-exynos.c b/drivers/pinctrl/pinctrl-exynos.c index 21362f48d370..19fab68a9fbf 100644 --- a/drivers/pinctrl/pinctrl-exynos.c +++ b/drivers/pinctrl/pinctrl-exynos.c @@ -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; - - eint_data = exynos_get_eint_data(hw, d); - if (!eint_data) - return -EINVAL; + struct samsung_pin_bank *b = h->host_data; - 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); |
