diff options
author | Olof Johansson <olof@lixom.net> | 2012-09-20 19:41:32 -0400 |
---|---|---|
committer | Olof Johansson <olof@lixom.net> | 2012-09-20 19:41:32 -0400 |
commit | 827cbe71886bc82125212630a52c5fe94b284330 (patch) | |
tree | a1f81706789fd8bbc5ace65e0bec4df7a603f272 | |
parent | 1ef3f756b069469621a47ded867e71c97e1b483f (diff) | |
parent | 011527b45f8e3092e1f3192e5aea94187a6ca269 (diff) |
Merge branch 'next/pinctrl-samsung' of git://git.kernel.org/pub/scm/linux/kernel/git/kgene/linux-samsung into next/drivers
From Kukjin Kim:
This branch is for supporting pinctrl for Samsung EXYNOS. Now this can
support EXYNOS4210 and other EXYNOS SoCs such as EXYNOS4X12 will be
supported next time.
* 'next/pinctrl-samsung' of git://git.kernel.org/pub/scm/linux/kernel/git/kgene/linux-samsung:
ARM: EXYNOS: Enable pinctrl driver support for EXYNOS4 device tree enabled platform
ARM: dts: Add pinctrl node entries for SAMSUNG EXYNOS4210 SoC
ARM: EXYNOS: skip wakeup interrupt setup if pinctrl driver is used
gpio: exynos4: skip gpiolib registration if pinctrl driver is used
pinctrl: add exynos4210 specific extensions for samsung pinctrl driver
pinctrl: add samsung pinctrl and gpiolib driver
-rw-r--r-- | Documentation/devicetree/bindings/pinctrl/samsung-pinctrl.txt | 196 | ||||
-rw-r--r-- | arch/arm/boot/dts/exynos4210-pinctrl.dtsi | 457 | ||||
-rw-r--r-- | arch/arm/boot/dts/exynos4210.dtsi | 37 | ||||
-rw-r--r-- | arch/arm/mach-exynos/Kconfig | 2 | ||||
-rw-r--r-- | arch/arm/mach-exynos/common.c | 26 | ||||
-rw-r--r-- | drivers/gpio/gpio-samsung.c | 21 | ||||
-rw-r--r-- | drivers/pinctrl/Kconfig | 9 | ||||
-rw-r--r-- | drivers/pinctrl/Makefile | 2 | ||||
-rw-r--r-- | drivers/pinctrl/pinctrl-exynos.c | 560 | ||||
-rw-r--r-- | drivers/pinctrl/pinctrl-exynos.h | 217 | ||||
-rw-r--r-- | drivers/pinctrl/pinctrl-samsung.c | 888 | ||||
-rw-r--r-- | drivers/pinctrl/pinctrl-samsung.h | 239 |
12 files changed, 2654 insertions, 0 deletions
diff --git a/Documentation/devicetree/bindings/pinctrl/samsung-pinctrl.txt b/Documentation/devicetree/bindings/pinctrl/samsung-pinctrl.txt new file mode 100644 index 000000000000..03dee50532f5 --- /dev/null +++ b/Documentation/devicetree/bindings/pinctrl/samsung-pinctrl.txt | |||
@@ -0,0 +1,196 @@ | |||
1 | Samsung GPIO and Pin Mux/Config controller | ||
2 | |||
3 | Samsung's ARM based SoC's integrates a GPIO and Pin mux/config hardware | ||
4 | controller. It controls the input/output settings on the available pads/pins | ||
5 | and also provides ability to multiplex and configure the output of various | ||
6 | on-chip controllers onto these pads. | ||
7 | |||
8 | Required Properties: | ||
9 | - compatible: should be one of the following. | ||
10 | - "samsung,pinctrl-exynos4210": for Exynos4210 compatible pin-controller. | ||
11 | - "samsung,pinctrl-exynos5250": for Exynos5250 compatible pin-controller. | ||
12 | |||
13 | - reg: Base address of the pin controller hardware module and length of | ||
14 | the address space it occupies. | ||
15 | |||
16 | - interrupts: interrupt specifier for the controller. The format and value of | ||
17 | the interrupt specifier depends on the interrupt parent for the controller. | ||
18 | |||
19 | - Pin mux/config groups as child nodes: The pin mux (selecting pin function | ||
20 | mode) and pin config (pull up/down, driver strength) settings are represented | ||
21 | as child nodes of the pin-controller node. There should be atleast one | ||
22 | child node and there is no limit on the count of these child nodes. | ||
23 | |||
24 | The child node should contain a list of pin(s) on which a particular pin | ||
25 | function selection or pin configuration (or both) have to applied. This | ||
26 | list of pins is specified using the property name "samsung,pins". There | ||
27 | should be atleast one pin specfied for this property and there is no upper | ||
28 | limit on the count of pins that can be specified. The pins are specified | ||
29 | using pin names which are derived from the hardware manual of the SoC. As | ||
30 | an example, the pins in GPA0 bank of the pin controller can be represented | ||
31 | as "gpa0-0", "gpa0-1", "gpa0-2" and so on. The names should be in lower case. | ||
32 | The format of the pin names should be (as per the hardware manual) | ||
33 | "[pin bank name]-[pin number within the bank]". | ||
34 | |||
35 | The pin function selection that should be applied on the pins listed in the | ||
36 | child node is specified using the "samsung,pin-function" property. The value | ||
37 | of this property that should be applied to each of the pins listed in the | ||
38 | "samsung,pins" property should be picked from the hardware manual of the SoC | ||
39 | for the specified pin group. This property is optional in the child node if | ||
40 | no specific function selection is desired for the pins listed in the child | ||
41 | node. The value of this property is used as-is to program the pin-controller | ||
42 | function selector register of the pin-bank. | ||
43 | |||
44 | The child node can also optionally specify one or more of the pin | ||
45 | configuration that should be applied on all the pins listed in the | ||
46 | "samsung,pins" property of the child node. The following pin configuration | ||
47 | properties are supported. | ||
48 | |||
49 | - samsung,pin-pud: Pull up/down configuration. | ||
50 | - samsung,pin-drv: Drive strength configuration. | ||
51 | - samsung,pin-pud-pdn: Pull up/down configuration in power down mode. | ||
52 | - samsung,pin-drv-pdn: Drive strength configuration in power down mode. | ||
53 | |||
54 | The values specified by these config properties should be derived from the | ||
55 | hardware manual and these values are programmed as-is into the pin | ||
56 | pull up/down and driver strength register of the pin-controller. | ||
57 | |||
58 | Note: A child should include atleast a pin function selection property or | ||
59 | pin configuration property (one or more) or both. | ||
60 | |||
61 | The client nodes that require a particular pin function selection and/or | ||
62 | pin configuration should use the bindings listed in the "pinctrl-bindings.txt" | ||
63 | file. | ||
64 | |||
65 | External GPIO and Wakeup Interrupts: | ||
66 | |||
67 | The controller supports two types of external interrupts over gpio. The first | ||
68 | is the external gpio interrupt and second is the external wakeup interrupts. | ||
69 | The difference between the two is that the external wakeup interrupts can be | ||
70 | used as system wakeup events. | ||
71 | |||
72 | A. External GPIO Interrupts: For supporting external gpio interrupts, the | ||
73 | following properties should be specified in the pin-controller device node. | ||
74 | |||
75 | - interrupt-controller: identifies the controller node as interrupt-parent. | ||
76 | - #interrupt-cells: the value of this property should be 2. | ||
77 | - First Cell: represents the external gpio interrupt number local to the | ||
78 | external gpio interrupt space of the controller. | ||
79 | - Second Cell: flags to identify the type of the interrupt | ||
80 | - 1 = rising edge triggered | ||
81 | - 2 = falling edge triggered | ||
82 | - 3 = rising and falling edge triggered | ||
83 | - 4 = high level triggered | ||
84 | - 8 = low level triggered | ||
85 | |||
86 | B. External Wakeup Interrupts: For supporting external wakeup interrupts, a | ||
87 | child node representing the external wakeup interrupt controller should be | ||
88 | included in the pin-controller device node. This child node should include | ||
89 | the following properties. | ||
90 | |||
91 | - compatible: identifies the type of the external wakeup interrupt controller | ||
92 | The possible values are: | ||
93 | - samsung,exynos4210-wakeup-eint: represents wakeup interrupt controller | ||
94 | found on Samsung Exynos4210 SoC. | ||
95 | - interrupt-parent: phandle of the interrupt parent to which the external | ||
96 | wakeup interrupts are forwarded to. | ||
97 | - interrupt-controller: identifies the node as interrupt-parent. | ||
98 | - #interrupt-cells: the value of this property should be 2 | ||
99 | - First Cell: represents the external wakeup interrupt number local to | ||
100 | the external wakeup interrupt space of the controller. | ||
101 | - Second Cell: flags to identify the type of the interrupt | ||
102 | - 1 = rising edge triggered | ||
103 | - 2 = falling edge triggered | ||
104 | - 3 = rising and falling edge triggered | ||
105 | - 4 = high level triggered | ||
106 | - 8 = low level triggered | ||
107 | |||
108 | Aliases: | ||
109 | |||
110 | All the pin controller nodes should be represented in the aliases node using | ||
111 | the following format 'pinctrl{n}' where n is a unique number for the alias. | ||
112 | |||
113 | Example 1: A pin-controller node with pin groups. | ||
114 | |||
115 | pinctrl_0: pinctrl@11400000 { | ||
116 | compatible = "samsung,pinctrl-exynos4210"; | ||
117 | reg = <0x11400000 0x1000>; | ||
118 | interrupts = <0 47 0>; | ||
119 | |||
120 | uart0_data: uart0-data { | ||
121 | samsung,pins = "gpa0-0", "gpa0-1"; | ||
122 | samsung,pin-function = <2>; | ||
123 | samsung,pin-pud = <0>; | ||
124 | samsung,pin-drv = <0>; | ||
125 | }; | ||
126 | |||
127 | uart0_fctl: uart0-fctl { | ||
128 | samsung,pins = "gpa0-2", "gpa0-3"; | ||
129 | samsung,pin-function = <2>; | ||
130 | samsung,pin-pud = <0>; | ||
131 | samsung,pin-drv = <0>; | ||
132 | }; | ||
133 | |||
134 | uart1_data: uart1-data { | ||
135 | samsung,pins = "gpa0-4", "gpa0-5"; | ||
136 | samsung,pin-function = <2>; | ||
137 | samsung,pin-pud = <0>; | ||
138 | samsung,pin-drv = <0>; | ||
139 | }; | ||
140 | |||
141 | uart1_fctl: uart1-fctl { | ||
142 | samsung,pins = "gpa0-6", "gpa0-7"; | ||
143 | samsung,pin-function = <2>; | ||
144 | samsung,pin-pud = <0>; | ||
145 | samsung,pin-drv = <0>; | ||
146 | }; | ||
147 | |||
148 | i2c2_bus: i2c2-bus { | ||
149 | samsung,pins = "gpa0-6", "gpa0-7"; | ||
150 | samsung,pin-function = <3>; | ||
151 | samsung,pin-pud = <3>; | ||
152 | samsung,pin-drv = <0>; | ||
153 | }; | ||
154 | }; | ||
155 | |||
156 | Example 2: A pin-controller node with external wakeup interrupt controller node. | ||
157 | |||
158 | pinctrl_1: pinctrl@11000000 { | ||
159 | compatible = "samsung,pinctrl-exynos4210"; | ||
160 | reg = <0x11000000 0x1000>; | ||
161 | interrupts = <0 46 0>; | ||
162 | interrupt-controller; | ||
163 | #interrupt-cells = <2>; | ||
164 | |||
165 | wakup_eint: wakeup-interrupt-controller { | ||
166 | compatible = "samsung,exynos4210-wakeup-eint"; | ||
167 | interrupt-parent = <&gic>; | ||
168 | interrupt-controller; | ||
169 | #interrupt-cells = <2>; | ||
170 | interrupts = <0 16 0>, <0 17 0>, <0 18 0>, <0 19 0>, | ||
171 | <0 20 0>, <0 21 0>, <0 22 0>, <0 23 0>, | ||
172 | <0 24 0>, <0 25 0>, <0 26 0>, <0 27 0>, | ||
173 | <0 28 0>, <0 29 0>, <0 30 0>, <0 31 0>, | ||
174 | <0 32 0>; | ||
175 | }; | ||
176 | }; | ||
177 | |||
178 | Example 3: A uart client node that supports 'default' and 'flow-control' states. | ||
179 | |||
180 | uart@13800000 { | ||
181 | compatible = "samsung,exynos4210-uart"; | ||
182 | reg = <0x13800000 0x100>; | ||
183 | interrupts = <0 52 0>; | ||
184 | pinctrl-names = "default", "flow-control; | ||
185 | pinctrl-0 = <&uart0_data>; | ||
186 | pinctrl-1 = <&uart0_data &uart0_fctl>; | ||
187 | }; | ||
188 | |||
189 | Example 4: Set up the default pin state for uart controller. | ||
190 | |||
191 | static int s3c24xx_serial_probe(struct platform_device *pdev) { | ||
192 | struct pinctrl *pinctrl; | ||
193 | ... | ||
194 | ... | ||
195 | pinctrl = devm_pinctrl_get_select_default(&pdev->dev); | ||
196 | } | ||
diff --git a/arch/arm/boot/dts/exynos4210-pinctrl.dtsi b/arch/arm/boot/dts/exynos4210-pinctrl.dtsi new file mode 100644 index 000000000000..b12cf272ad0d --- /dev/null +++ b/arch/arm/boot/dts/exynos4210-pinctrl.dtsi | |||
@@ -0,0 +1,457 @@ | |||
1 | /* | ||
2 | * Samsung's Exynos4210 SoC pin-mux and pin-config device tree source | ||
3 | * | ||
4 | * Copyright (c) 2011-2012 Samsung Electronics Co., Ltd. | ||
5 | * http://www.samsung.com | ||
6 | * Copyright (c) 2011-2012 Linaro Ltd. | ||
7 | * www.linaro.org | ||
8 | * | ||
9 | * Samsung's Exynos4210 SoC pin-mux and pin-config optiosn are listed as device | ||
10 | * tree nodes are listed in this file. | ||
11 | * | ||
12 | * This program is free software; you can redistribute it and/or modify | ||
13 | * it under the terms of the GNU General Public License version 2 as | ||
14 | * published by the Free Software Foundation. | ||
15 | */ | ||
16 | |||
17 | / { | ||
18 | pinctrl@11400000 { | ||
19 | uart0_data: uart0-data { | ||
20 | samsung,pins = "gpa0-0", "gpa0-1"; | ||
21 | samsung,pin-function = <0x2>; | ||
22 | samsung,pin-pud = <0>; | ||
23 | samsung,pin-drv = <0>; | ||
24 | }; | ||
25 | |||
26 | uart0_fctl: uart0-fctl { | ||
27 | samsung,pins = "gpa0-2", "gpa0-3"; | ||
28 | samsung,pin-function = <2>; | ||
29 | samsung,pin-pud = <0>; | ||
30 | samsung,pin-drv = <0>; | ||
31 | }; | ||
32 | |||
33 | uart1_data: uart1-data { | ||
34 | samsung,pins = "gpa0-4", "gpa0-5"; | ||
35 | samsung,pin-function = <2>; | ||
36 | samsung,pin-pud = <0>; | ||
37 | samsung,pin-drv = <0>; | ||
38 | }; | ||
39 | |||
40 | uart1_fctl: uart1-fctl { | ||
41 | samsung,pins = "gpa0-6", "gpa0-7"; | ||
42 | samsung,pin-function = <2>; | ||
43 | samsung,pin-pud = <0>; | ||
44 | samsung,pin-drv = <0>; | ||
45 | }; | ||
46 | |||
47 | i2c2_bus: i2c2-bus { | ||
48 | samsung,pins = "gpa0-6", "gpa0-7"; | ||
49 | samsung,pin-function = <3>; | ||
50 | samsung,pin-pud = <3>; | ||
51 | samsung,pin-drv = <0>; | ||
52 | }; | ||
53 | |||
54 | uart2_data: uart2-data { | ||
55 | samsung,pins = "gpa1-0", "gpa1-1"; | ||
56 | samsung,pin-function = <2>; | ||
57 | samsung,pin-pud = <0>; | ||
58 | samsung,pin-drv = <0>; | ||
59 | }; | ||
60 | |||
61 | uart2_fctl: uart2-fctl { | ||
62 | samsung,pins = "gpa1-2", "gpa1-3"; | ||
63 | samsung,pin-function = <2>; | ||
64 | samsung,pin-pud = <0>; | ||
65 | samsung,pin-drv = <0>; | ||
66 | }; | ||
67 | |||
68 | uart_audio_a: uart-audio-a { | ||
69 | samsung,pins = "gpa1-0", "gpa1-1"; | ||
70 | samsung,pin-function = <4>; | ||
71 | samsung,pin-pud = <0>; | ||
72 | samsung,pin-drv = <0>; | ||
73 | }; | ||
74 | |||
75 | i2c3_bus: i2c3-bus { | ||
76 | samsung,pins = "gpa1-2", "gpa1-3"; | ||
77 | samsung,pin-function = <3>; | ||
78 | samsung,pin-pud = <3>; | ||
79 | samsung,pin-drv = <0>; | ||
80 | }; | ||
81 | |||
82 | uart3_data: uart3-data { | ||
83 | samsung,pins = "gpa1-4", "gpa1-5"; | ||
84 | samsung,pin-function = <2>; | ||
85 | samsung,pin-pud = <0>; | ||
86 | samsung,pin-drv = <0>; | ||
87 | }; | ||
88 | |||
89 | uart_audio_b: uart-audio-b { | ||
90 | samsung,pins = "gpa1-4", "gpa1-5"; | ||
91 | samsung,pin-function = <4>; | ||
92 | samsung,pin-pud = <0>; | ||
93 | samsung,pin-drv = <0>; | ||
94 | }; | ||
95 | |||
96 | spi0_bus: spi0-bus { | ||
97 | samsung,pins = "gpb-0", "gpb-2", "gpb-3"; | ||
98 | samsung,pin-function = <2>; | ||
99 | samsung,pin-pud = <3>; | ||
100 | samsung,pin-drv = <0>; | ||
101 | }; | ||
102 | |||
103 | i2c4_bus: i2c4-bus { | ||
104 | samsung,pins = "gpb-2", "gpb-3"; | ||
105 | samsung,pin-function = <3>; | ||
106 | samsung,pin-pud = <3>; | ||
107 | samsung,pin-drv = <0>; | ||
108 | }; | ||
109 | |||
110 | spi1_bus: spi1-bus { | ||
111 | samsung,pins = "gpb-4", "gpb-6", "gpb-7"; | ||
112 | samsung,pin-function = <2>; | ||
113 | samsung,pin-pud = <3>; | ||
114 | samsung,pin-drv = <0>; | ||
115 | }; | ||
116 | |||
117 | i2c5_bus: i2c5-bus { | ||
118 | samsung,pins = "gpb-6", "gpb-7"; | ||
119 | samsung,pin-function = <3>; | ||
120 | samsung,pin-pud = <3>; | ||
121 | samsung,pin-drv = <0>; | ||
122 | }; | ||
123 | |||
124 | i2s1_bus: i2s1-bus { | ||
125 | samsung,pins = "gpc0-0", "gpc0-1", "gpc0-2", "gpc0-3", | ||
126 | "gpc0-4"; | ||
127 | samsung,pin-function = <2>; | ||
128 | samsung,pin-pud = <0>; | ||
129 | samsung,pin-drv = <0>; | ||
130 | }; | ||
131 | |||
132 | pcm1_bus: pcm1-bus { | ||
133 | samsung,pins = "gpc0-0", "gpc0-1", "gpc0-2", "gpc0-3", | ||
134 | "gpc0-4"; | ||
135 | samsung,pin-function = <3>; | ||
136 | samsung,pin-pud = <0>; | ||
137 | samsung,pin-drv = <0>; | ||
138 | }; | ||
139 | |||
140 | ac97_bus: ac97-bus { | ||
141 | samsung,pins = "gpc0-0", "gpc0-1", "gpc0-2", "gpc0-3", | ||
142 | "gpc0-4"; | ||
143 | samsung,pin-function = <4>; | ||
144 | samsung,pin-pud = <0>; | ||
145 | samsung,pin-drv = <0>; | ||
146 | }; | ||
147 | |||
148 | i2s2_bus: i2s2-bus { | ||
149 | samsung,pins = "gpc1-0", "gpc1-1", "gpc1-2", "gpc1-3", | ||
150 | "gpc1-4"; | ||
151 | samsung,pin-function = <2>; | ||
152 | samsung,pin-pud = <0>; | ||
153 | samsung,pin-drv = <0>; | ||
154 | }; | ||
155 | |||
156 | pcm2_bus: pcm2-bus { | ||
157 | samsung,pins = "gpc1-0", "gpc1-1", "gpc1-2", "gpc1-3", | ||
158 | "gpc1-4"; | ||
159 | samsung,pin-function = <3>; | ||
160 | samsung,pin-pud = <0>; | ||
161 | samsung,pin-drv = <0>; | ||
162 | }; | ||
163 | |||
164 | spdif_bus: spdif-bus { | ||
165 | samsung,pins = "gpc1-0", "gpc1-1"; | ||
166 | samsung,pin-function = <4>; | ||
167 | samsung,pin-pud = <0>; | ||
168 | samsung,pin-drv = <0>; | ||
169 | }; | ||
170 | |||
171 | i2c6_bus: i2c6-bus { | ||
172 | samsung,pins = "gpc1-3", "gpc1-4"; | ||
173 | samsung,pin-function = <4>; | ||
174 | samsung,pin-pud = <3>; | ||
175 | samsung,pin-drv = <0>; | ||
176 | }; | ||
177 | |||
178 | spi2_bus: spi2-bus { | ||
179 | samsung,pins = "gpc1-1", "gpc1-2", "gpc1-3", "gpc1-4"; | ||
180 | samsung,pin-function = <5>; | ||
181 | samsung,pin-pud = <3>; | ||
182 | samsung,pin-drv = <0>; | ||
183 | }; | ||
184 | |||
185 | i2c7_bus: i2c7-bus { | ||
186 | samsung,pins = "gpd0-2", "gpd0-3"; | ||
187 | samsung,pin-function = <3>; | ||
188 | samsung,pin-pud = <3>; | ||
189 | samsung,pin-drv = <0>; | ||
190 | }; | ||
191 | |||
192 | i2c0_bus: i2c0-bus { | ||
193 | samsung,pins = "gpd1-0", "gpd1-1"; | ||
194 | samsung,pin-function = <2>; | ||
195 | samsung,pin-pud = <3>; | ||
196 | samsung,pin-drv = <0>; | ||
197 | }; | ||
198 | |||
199 | i2c1_bus: i2c1-bus { | ||
200 | samsung,pins = "gpd1-2", "gpd1-3"; | ||
201 | samsung,pin-function = <2>; | ||
202 | samsung,pin-pud = <3>; | ||
203 | samsung,pin-drv = <0>; | ||
204 | }; | ||
205 | }; | ||
206 | |||
207 | pinctrl@11000000 { | ||
208 | sd0_clk: sd0-clk { | ||
209 | samsung,pins = "gpk0-0"; | ||
210 | samsung,pin-function = <2>; | ||
211 | samsung,pin-pud = <0>; | ||
212 | samsung,pin-drv = <0>; | ||
213 | }; | ||
214 | |||
215 | sd0_cmd: sd0-cmd { | ||
216 | samsung,pins = "gpk0-1"; | ||
217 | samsung,pin-function = <2>; | ||
218 | samsung,pin-pud = <0>; | ||
219 | samsung,pin-drv = <0>; | ||
220 | }; | ||
221 | |||
222 | sd0_cd: sd0-cd { | ||
223 | samsung,pins = "gpk0-2"; | ||
224 | samsung,pin-function = <2>; | ||
225 | samsung,pin-pud = <3>; | ||
226 | samsung,pin-drv = <0>; | ||
227 | }; | ||
228 | |||
229 | sd0_bus1: sd0-bus-width1 { | ||
230 | samsung,pins = "gpk0-3"; | ||
231 | samsung,pin-function = <2>; | ||
232 | samsung,pin-pud = <3>; | ||
233 | samsung,pin-drv = <0>; | ||
234 | }; | ||
235 | |||
236 | sd0_bus4: sd0-bus-width4 { | ||
237 | samsung,pins = "gpk0-3", "gpk0-4", "gpk0-5", "gpk0-6"; | ||
238 | samsung,pin-function = <2>; | ||
239 | samsung,pin-pud = <3>; | ||
240 | samsung,pin-drv = <0>; | ||
241 | }; | ||
242 | |||
243 | sd0_bus8: sd0-bus-width8 { | ||
244 | samsung,pins = "gpk1-3", "gpk1-4", "gpk1-5", "gpk1-6"; | ||
245 | samsung,pin-function = <3>; | ||
246 | samsung,pin-pud = <3>; | ||
247 | samsung,pin-drv = <0>; | ||
248 | }; | ||
249 | |||
250 | sd4_clk: sd4-clk { | ||
251 | samsung,pins = "gpk0-0"; | ||
252 | samsung,pin-function = <3>; | ||
253 | samsung,pin-pud = <0>; | ||
254 | samsung,pin-drv = <0>; | ||
255 | }; | ||
256 | |||
257 | sd4_cmd: sd4-cmd { | ||
258 | samsung,pins = "gpk0-1"; | ||
259 | samsung,pin-function = <3>; | ||
260 | samsung,pin-pud = <0>; | ||
261 | samsung,pin-drv = <0>; | ||
262 | }; | ||
263 | |||
264 | sd4_cd: sd4-cd { | ||
265 | samsung,pins = "gpk0-2"; | ||
266 | samsung,pin-function = <3>; | ||
267 | samsung,pin-pud = <3>; | ||
268 | samsung,pin-drv = <0>; | ||
269 | }; | ||
270 | |||
271 | sd4_bus1: sd4-bus-width1 { | ||
272 | samsung,pins = "gpk0-3"; | ||
273 | samsung,pin-function = <3>; | ||
274 | samsung,pin-pud = <3>; | ||
275 | samsung,pin-drv = <0>; | ||
276 | }; | ||
277 | |||
278 | sd4_bus4: sd4-bus-width4 { | ||
279 | samsung,pins = "gpk0-3", "gpk0-4", "gpk0-5", "gpk0-6"; | ||
280 | samsung,pin-function = <3>; | ||
281 | samsung,pin-pud = <3>; | ||
282 | samsung,pin-drv = <0>; | ||
283 | }; | ||
284 | |||
285 | sd4_bus8: sd4-bus-width8 { | ||
286 | samsung,pins = "gpk1-3", "gpk1-4", "gpk1-5", "gpk1-6"; | ||
287 | samsung,pin-function = <3>; | ||
288 | samsung,pin-pud = <4>; | ||
289 | samsung,pin-drv = <0>; | ||
290 | }; | ||
291 | |||
292 | sd1_clk: sd1-clk { | ||
293 | samsung,pins = "gpk1-0"; | ||
294 | samsung,pin-function = <2>; | ||
295 | samsung,pin-pud = <0>; | ||
296 | samsung,pin-drv = <0>; | ||
297 | }; | ||
298 | |||
299 | sd1_cmd: sd1-cmd { | ||
300 | samsung,pins = "gpk1-1"; | ||
301 | samsung,pin-function = <2>; | ||
302 | samsung,pin-pud = <0>; | ||
303 | samsung,pin-drv = <0>; | ||
304 | }; | ||
305 | |||
306 | sd1_cd: sd1-cd { | ||
307 | samsung,pins = "gpk1-2"; | ||
308 | samsung,pin-function = <2>; | ||
309 | samsung,pin-pud = <3>; | ||
310 | samsung,pin-drv = <0>; | ||
311 | }; | ||
312 | |||
313 | sd1_bus1: sd1-bus-width1 { | ||
314 | samsung,pins = "gpk1-3"; | ||
315 | samsung,pin-function = <2>; | ||
316 | samsung,pin-pud = <3>; | ||
317 | samsung,pin-drv = <0>; | ||
318 | }; | ||
319 | |||
320 | sd1_bus4: sd1-bus-width4 { | ||
321 | samsung,pins = "gpk1-3", "gpk1-4", "gpk1-5", "gpk1-6"; | ||
322 | samsung,pin-function = <2>; | ||
323 | samsung,pin-pud = <3>; | ||
324 | samsung,pin-drv = <0>; | ||
325 | }; | ||
326 | |||
327 | sd2_clk: sd2-clk { | ||
328 | samsung,pins = "gpk2-0"; | ||
329 | samsung,pin-function = <2>; | ||
330 | samsung,pin-pud = <0>; | ||
331 | samsung,pin-drv = <0>; | ||
332 | }; | ||
333 | |||
334 | sd2_cmd: sd2-cmd { | ||
335 | samsung,pins = "gpk2-1"; | ||
336 | samsung,pin-function = <2>; | ||
337 | samsung,pin-pud = <0>; | ||
338 | samsung,pin-drv = <0>; | ||
339 | }; | ||
340 | |||
341 | sd2_cd: sd2-cd { | ||
342 | samsung,pins = "gpk2-2"; | ||
343 | samsung,pin-function = <2>; | ||
344 | samsung,pin-pud = <3>; | ||
345 | samsung,pin-drv = <0>; | ||
346 | }; | ||
347 | |||
348 | sd2_bus1: sd2-bus-width1 { | ||
349 | samsung,pins = "gpk2-3"; | ||
350 | samsung,pin-function = <2>; | ||
351 | samsung,pin-pud = <3>; | ||
352 | samsung,pin-drv = <0>; | ||
353 | }; | ||
354 | |||
355 | sd2_bus4: sd2-bus-width4 { | ||
356 | samsung,pins = "gpk2-3", "gpk2-4", "gpk2-5", "gpk2-6"; | ||
357 | samsung,pin-function = <2>; | ||
358 | samsung,pin-pud = <3>; | ||
359 | samsung,pin-drv = <0>; | ||
360 | }; | ||
361 | |||
362 | sd2_bus8: sd2-bus-width8 { | ||
363 | samsung,pins = "gpk3-3", "gpk3-4", "gpk3-5", "gpk3-6"; | ||
364 | samsung,pin-function = <3>; | ||
365 | samsung,pin-pud = <3>; | ||
366 | samsung,pin-drv = <0>; | ||
367 | }; | ||
368 | |||
369 | sd3_clk: sd3-clk { | ||
370 | samsung,pins = "gpk3-0"; | ||
371 | samsung,pin-function = <2>; | ||
372 | samsung,pin-pud = <0>; | ||
373 | samsung,pin-drv = <0>; | ||
374 | }; | ||
375 | |||
376 | sd3_cmd: sd3-cmd { | ||
377 | samsung,pins = "gpk3-1"; | ||
378 | samsung,pin-function = <2>; | ||
379 | samsung,pin-pud = <0>; | ||
380 | samsung,pin-drv = <0>; | ||
381 | }; | ||
382 | |||
383 | sd3_cd: sd3-cd { | ||
384 | samsung,pins = "gpk3-2"; | ||
385 | samsung,pin-function = <2>; | ||
386 | samsung,pin-pud = <3>; | ||
387 | samsung,pin-drv = <0>; | ||
388 | }; | ||
389 | |||
390 | sd3_bus1: sd3-bus-width1 { | ||
391 | samsung,pins = "gpk3-3"; | ||
392 | samsung,pin-function = <2>; | ||
393 | samsung,pin-pud = <3>; | ||
394 | samsung,pin-drv = <0>; | ||
395 | }; | ||
396 | |||
397 | sd3_bus4: sd3-bus-width4 { | ||
398 | samsung,pins = "gpk3-3", "gpk3-4", "gpk3-5", "gpk3-6"; | ||
399 | samsung,pin-function = <2>; | ||
400 | samsung,pin-pud = <3>; | ||
401 | samsung,pin-drv = <0>; | ||
402 | }; | ||
403 | |||
404 | eint0: ext-int0 { | ||
405 | samsung,pins = "gpx0-0"; | ||
406 | samsung,pin-function = <0xf>; | ||
407 | samsung,pin-pud = <0>; | ||
408 | samsung,pin-drv = <0>; | ||
409 | }; | ||
410 | |||
411 | eint8: ext-int8 { | ||
412 | samsung,pins = "gpx1-0"; | ||
413 | samsung,pin-function = <0xf>; | ||
414 | samsung,pin-pud = <0>; | ||
415 | samsung,pin-drv = <0>; | ||
416 | }; | ||
417 | |||
418 | eint15: ext-int15 { | ||
419 | samsung,pins = "gpx1-7"; | ||
420 | samsung,pin-function = <0xf>; | ||
421 | samsung,pin-pud = <0>; | ||
422 | samsung,pin-drv = <0>; | ||
423 | }; | ||
424 | |||
425 | eint16: ext-int16 { | ||
426 | samsung,pins = "gpx2-0"; | ||
427 | samsung,pin-function = <0xf>; | ||
428 | samsung,pin-pud = <0>; | ||
429 | samsung,pin-drv = <0>; | ||
430 | }; | ||
431 | |||
432 | eint31: ext-int31 { | ||
433 | samsung,pins = "gpx3-7"; | ||
434 | samsung,pin-function = <0xf>; | ||
435 | samsung,pin-pud = <0>; | ||
436 | samsung,pin-drv = <0>; | ||
437 | }; | ||
438 | }; | ||
439 | |||
440 | pinctrl@03860000 { | ||
441 | i2s0_bus: i2s0-bus { | ||
442 | samsung,pins = "gpz-0", "gpz-1", "gpz-2", "gpz-3", | ||
443 | "gpz-4", "gpz-5", "gpz-6"; | ||
444 | samsung,pin-function = <0x2>; | ||
445 | samsung,pin-pud = <0>; | ||
446 | samsung,pin-drv = <0>; | ||
447 | }; | ||
448 | |||
449 | pcm0_bus: pcm0-bus { | ||
450 | samsung,pins = "gpz-0", "gpz-1", "gpz-2", "gpz-3", | ||
451 | "gpz-4"; | ||
452 | samsung,pin-function = <0x3>; | ||
453 | samsung,pin-pud = <0>; | ||
454 | samsung,pin-drv = <0>; | ||
455 | }; | ||
456 | }; | ||
457 | }; | ||
diff --git a/arch/arm/boot/dts/exynos4210.dtsi b/arch/arm/boot/dts/exynos4210.dtsi index 02891fe876e4..a4bd0c9a206e 100644 --- a/arch/arm/boot/dts/exynos4210.dtsi +++ b/arch/arm/boot/dts/exynos4210.dtsi | |||
@@ -20,6 +20,7 @@ | |||
20 | */ | 20 | */ |
21 | 21 | ||
22 | /include/ "skeleton.dtsi" | 22 | /include/ "skeleton.dtsi" |
23 | /include/ "exynos4210-pinctrl.dtsi" | ||
23 | 24 | ||
24 | / { | 25 | / { |
25 | compatible = "samsung,exynos4210"; | 26 | compatible = "samsung,exynos4210"; |
@@ -29,6 +30,9 @@ | |||
29 | spi0 = &spi_0; | 30 | spi0 = &spi_0; |
30 | spi1 = &spi_1; | 31 | spi1 = &spi_1; |
31 | spi2 = &spi_2; | 32 | spi2 = &spi_2; |
33 | pinctrl0 = &pinctrl_0; | ||
34 | pinctrl1 = &pinctrl_1; | ||
35 | pinctrl2 = &pinctrl_2; | ||
32 | }; | 36 | }; |
33 | 37 | ||
34 | gic:interrupt-controller@10490000 { | 38 | gic:interrupt-controller@10490000 { |
@@ -50,6 +54,39 @@ | |||
50 | <0 12 0>, <0 13 0>, <0 14 0>, <0 15 0>; | 54 | <0 12 0>, <0 13 0>, <0 14 0>, <0 15 0>; |
51 | }; | 55 | }; |
52 | 56 | ||
57 | pinctrl_0: pinctrl@11400000 { | ||
58 | compatible = "samsung,pinctrl-exynos4210"; | ||
59 | reg = <0x11400000 0x1000>; | ||
60 | interrupts = <0 47 0>; | ||
61 | interrupt-controller; | ||
62 | #interrupt-cells = <2>; | ||
63 | }; | ||
64 | |||
65 | pinctrl_1: pinctrl@11000000 { | ||
66 | compatible = "samsung,pinctrl-exynos4210"; | ||
67 | reg = <0x11000000 0x1000>; | ||
68 | interrupts = <0 46 0>; | ||
69 | interrupt-controller; | ||
70 | #interrupt-cells = <2>; | ||
71 | |||
72 | wakup_eint: wakeup-interrupt-controller { | ||
73 | compatible = "samsung,exynos4210-wakeup-eint"; | ||
74 | interrupt-parent = <&gic>; | ||
75 | interrupt-controller; | ||
76 | #interrupt-cells = <2>; | ||
77 | interrupts = <0 16 0>, <0 17 0>, <0 18 0>, <0 19 0>, | ||
78 | <0 20 0>, <0 21 0>, <0 22 0>, <0 23 0>, | ||
79 | <0 24 0>, <0 25 0>, <0 26 0>, <0 27 0>, | ||
80 | <0 28 0>, <0 29 0>, <0 30 0>, <0 31 0>, | ||
81 | <0 32 0>; | ||
82 | }; | ||
83 | }; | ||
84 | |||
85 | pinctrl_2: pinctrl@03860000 { | ||
86 | compatible = "samsung,pinctrl-exynos4210"; | ||
87 | reg = <0x03860000 0x1000>; | ||
88 | }; | ||
89 | |||
53 | watchdog@10060000 { | 90 | watchdog@10060000 { |
54 | compatible = "samsung,s3c2410-wdt"; | 91 | compatible = "samsung,s3c2410-wdt"; |
55 | reg = <0x10060000 0x100>; | 92 | reg = <0x10060000 0x100>; |
diff --git a/arch/arm/mach-exynos/Kconfig b/arch/arm/mach-exynos/Kconfig index b5b4c8c9db11..195b50eb1e57 100644 --- a/arch/arm/mach-exynos/Kconfig +++ b/arch/arm/mach-exynos/Kconfig | |||
@@ -405,6 +405,8 @@ config MACH_EXYNOS4_DT | |||
405 | select USE_OF | 405 | select USE_OF |
406 | select ARM_AMBA | 406 | select ARM_AMBA |
407 | select HAVE_SAMSUNG_KEYPAD if INPUT_KEYBOARD | 407 | select HAVE_SAMSUNG_KEYPAD if INPUT_KEYBOARD |
408 | select PINCTRL | ||
409 | select PINCTRL_EXYNOS4 | ||
408 | help | 410 | help |
409 | Machine support for Samsung Exynos4 machine with device tree enabled. | 411 | Machine support for Samsung Exynos4 machine with device tree enabled. |
410 | Select this if a fdt blob is available for the Exynos4 SoC based board. | 412 | Select this if a fdt blob is available for the Exynos4 SoC based board. |
diff --git a/arch/arm/mach-exynos/common.c b/arch/arm/mach-exynos/common.c index 4eb39cdf75ea..715b690e5009 100644 --- a/arch/arm/mach-exynos/common.c +++ b/arch/arm/mach-exynos/common.c | |||
@@ -980,6 +980,32 @@ static int __init exynos_init_irq_eint(void) | |||
980 | { | 980 | { |
981 | int irq; | 981 | int irq; |
982 | 982 | ||
983 | #ifdef CONFIG_PINCTRL_SAMSUNG | ||
984 | /* | ||
985 | * The Samsung pinctrl driver provides an integrated gpio/pinmux/pinconf | ||
986 | * functionality along with support for external gpio and wakeup | ||
987 | * interrupts. If the samsung pinctrl driver is enabled and includes | ||
988 | * the wakeup interrupt support, then the setting up external wakeup | ||
989 | * interrupts here can be skipped. This check here is temporary to | ||
990 | * allow exynos4 platforms that do not use Samsung pinctrl driver to | ||
991 | * co-exist with platforms that do. When all of the Samsung Exynos4 | ||
992 | * platforms switch over to using the pinctrl driver, the wakeup | ||
993 | * interrupt support code here can be completely removed. | ||
994 | */ | ||
995 | struct device_node *pctrl_np, *wkup_np; | ||
996 | const char *pctrl_compat = "samsung,pinctrl-exynos4210"; | ||
997 | const char *wkup_compat = "samsung,exynos4210-wakeup-eint"; | ||
998 | |||
999 | for_each_compatible_node(pctrl_np, NULL, pctrl_compat) { | ||
1000 | if (of_device_is_available(pctrl_np)) { | ||
1001 | wkup_np = of_find_compatible_node(pctrl_np, NULL, | ||
1002 | wkup_compat); | ||
1003 | if (wkup_np) | ||
1004 | return -ENODEV; | ||
1005 | } | ||
1006 | } | ||
1007 | #endif | ||
1008 | |||
983 | if (soc_is_exynos5250()) | 1009 | if (soc_is_exynos5250()) |
984 | exynos_eint_base = ioremap(EXYNOS5_PA_GPIO1, SZ_4K); | 1010 | exynos_eint_base = ioremap(EXYNOS5_PA_GPIO1, SZ_4K); |
985 | else | 1011 | else |
diff --git a/drivers/gpio/gpio-samsung.c b/drivers/gpio/gpio-samsung.c index ba126cc04073..41ab7f66cdf9 100644 --- a/drivers/gpio/gpio-samsung.c +++ b/drivers/gpio/gpio-samsung.c | |||
@@ -2734,6 +2734,27 @@ static __init void exynos4_gpiolib_init(void) | |||
2734 | int group = 0; | 2734 | int group = 0; |
2735 | void __iomem *gpx_base; | 2735 | void __iomem *gpx_base; |
2736 | 2736 | ||
2737 | #ifdef CONFIG_PINCTRL_SAMSUNG | ||
2738 | /* | ||
2739 | * This gpio driver includes support for device tree support and | ||
2740 | * there are platforms using it. In order to maintain | ||
2741 | * compatibility with those platforms, and to allow non-dt | ||
2742 | * Exynos4210 platforms to use this gpiolib support, a check | ||
2743 | * is added to find out if there is a active pin-controller | ||
2744 | * driver support available. If it is available, this gpiolib | ||
2745 | * support is ignored and the gpiolib support available in | ||
2746 | * pin-controller driver is used. This is a temporary check and | ||
2747 | * will go away when all of the Exynos4210 platforms have | ||
2748 | * switched to using device tree and the pin-ctrl driver. | ||
2749 | */ | ||
2750 | struct device_node *pctrl_np; | ||
2751 | const char *pctrl_compat = "samsung,pinctrl-exynos4210"; | ||
2752 | pctrl_np = of_find_compatible_node(NULL, NULL, pctrl_compat); | ||
2753 | if (pctrl_np) | ||
2754 | if (of_device_is_available(pctrl_np)) | ||
2755 | return; | ||
2756 | #endif | ||
2757 | |||
2737 | /* gpio part1 */ | 2758 | /* gpio part1 */ |
2738 | gpio_base1 = ioremap(EXYNOS4_PA_GPIO1, SZ_4K); | 2759 | gpio_base1 = ioremap(EXYNOS4_PA_GPIO1, SZ_4K); |
2739 | if (gpio_base1 == NULL) { | 2760 | if (gpio_base1 == NULL) { |
diff --git a/drivers/pinctrl/Kconfig b/drivers/pinctrl/Kconfig index 54e3588bef62..34e94c7f68ca 100644 --- a/drivers/pinctrl/Kconfig +++ b/drivers/pinctrl/Kconfig | |||
@@ -145,6 +145,15 @@ config PINCTRL_COH901 | |||
145 | COH 901 335 and COH 901 571/3. They contain 3, 5 or 7 | 145 | COH 901 335 and COH 901 571/3. They contain 3, 5 or 7 |
146 | ports of 8 GPIO pins each. | 146 | ports of 8 GPIO pins each. |
147 | 147 | ||
148 | config PINCTRL_SAMSUNG | ||
149 | bool "Samsung pinctrl driver" | ||
150 | select PINMUX | ||
151 | select PINCONF | ||
152 | |||
153 | config PINCTRL_EXYNOS4 | ||
154 | bool "Pinctrl driver data for Exynos4 SoC" | ||
155 | select PINCTRL_SAMSUNG | ||
156 | |||
148 | source "drivers/pinctrl/spear/Kconfig" | 157 | source "drivers/pinctrl/spear/Kconfig" |
149 | 158 | ||
150 | endmenu | 159 | endmenu |
diff --git a/drivers/pinctrl/Makefile b/drivers/pinctrl/Makefile index f40b1f81ff2c..6a88113e11d9 100644 --- a/drivers/pinctrl/Makefile +++ b/drivers/pinctrl/Makefile | |||
@@ -29,5 +29,7 @@ obj-$(CONFIG_PINCTRL_TEGRA20) += pinctrl-tegra20.o | |||
29 | obj-$(CONFIG_PINCTRL_TEGRA30) += pinctrl-tegra30.o | 29 | obj-$(CONFIG_PINCTRL_TEGRA30) += pinctrl-tegra30.o |
30 | obj-$(CONFIG_PINCTRL_U300) += pinctrl-u300.o | 30 | obj-$(CONFIG_PINCTRL_U300) += pinctrl-u300.o |
31 | obj-$(CONFIG_PINCTRL_COH901) += pinctrl-coh901.o | 31 | obj-$(CONFIG_PINCTRL_COH901) += pinctrl-coh901.o |
32 | obj-$(CONFIG_PINCTRL_SAMSUNG) += pinctrl-samsung.o | ||
33 | obj-$(CONFIG_PINCTRL_EXYNOS4) += pinctrl-exynos.o | ||
32 | 34 | ||
33 | obj-$(CONFIG_PLAT_SPEAR) += spear/ | 35 | obj-$(CONFIG_PLAT_SPEAR) += spear/ |
diff --git a/drivers/pinctrl/pinctrl-exynos.c b/drivers/pinctrl/pinctrl-exynos.c new file mode 100644 index 000000000000..447818d9851b --- /dev/null +++ b/drivers/pinctrl/pinctrl-exynos.c | |||
@@ -0,0 +1,560 @@ | |||
1 | /* | ||
2 | * Exynos specific support for Samsung pinctrl/gpiolib driver with eint support. | ||
3 | * | ||
4 | * Copyright (c) 2012 Samsung Electronics Co., Ltd. | ||
5 | * http://www.samsung.com | ||
6 | * Copyright (c) 2012 Linaro Ltd | ||
7 | * http://www.linaro.org | ||
8 | * | ||
9 | * Author: Thomas Abraham <thomas.ab@samsung.com> | ||
10 | * | ||
11 | * This program is free software; you can redistribute it and/or modify | ||
12 | * it under the terms of the GNU General Public License as published by | ||
13 | * the Free Software Foundation; either version 2 of the License, or | ||
14 | * (at your option) any later version. | ||
15 | * | ||
16 | * This file contains the Samsung Exynos specific information required by the | ||
17 | * the Samsung pinctrl/gpiolib driver. It also includes the implementation of | ||
18 | * external gpio and wakeup interrupt support. | ||
19 | */ | ||
20 | |||
21 | #include <linux/module.h> | ||
22 | #include <linux/device.h> | ||
23 | #include <linux/interrupt.h> | ||
24 | #include <linux/irqdomain.h> | ||
25 | #include <linux/irq.h> | ||
26 | #include <linux/of_irq.h> | ||
27 | #include <linux/io.h> | ||
28 | #include <linux/slab.h> | ||
29 | #include <linux/err.h> | ||
30 | |||
31 | #include <asm/mach/irq.h> | ||
32 | |||
33 | #include "pinctrl-samsung.h" | ||
34 | #include "pinctrl-exynos.h" | ||
35 | |||
36 | /* list of external wakeup controllers supported */ | ||
37 | static const struct of_device_id exynos_wkup_irq_ids[] = { | ||
38 | { .compatible = "samsung,exynos4210-wakeup-eint", }, | ||
39 | }; | ||
40 | |||
41 | static void exynos_gpio_irq_unmask(struct irq_data *irqd) | ||
42 | { | ||
43 | struct samsung_pinctrl_drv_data *d = irqd->domain->host_data; | ||
44 | struct exynos_geint_data *edata = irq_data_get_irq_handler_data(irqd); | ||
45 | unsigned long reg_mask = d->ctrl->geint_mask + edata->eint_offset; | ||
46 | unsigned long mask; | ||
47 | |||
48 | mask = readl(d->virt_base + reg_mask); | ||
49 | mask &= ~(1 << edata->pin); | ||
50 | writel(mask, d->virt_base + reg_mask); | ||
51 | } | ||
52 | |||
53 | static void exynos_gpio_irq_mask(struct irq_data *irqd) | ||
54 | { | ||
55 | struct samsung_pinctrl_drv_data *d = irqd->domain->host_data; | ||
56 | struct exynos_geint_data *edata = irq_data_get_irq_handler_data(irqd); | ||
57 | unsigned long reg_mask = d->ctrl->geint_mask + edata->eint_offset; | ||
58 | unsigned long mask; | ||
59 | |||
60 | mask = readl(d->virt_base + reg_mask); | ||
61 | mask |= ~(1 << edata->pin); | ||
62 | writel(mask, d->virt_base + reg_mask); | ||
63 | } | ||
64 | |||
65 | static void exynos_gpio_irq_ack(struct irq_data *irqd) | ||
66 | { | ||
67 | struct samsung_pinctrl_drv_data *d = irqd->domain->host_data; | ||
68 | struct exynos_geint_data *edata = irq_data_get_irq_handler_data(irqd); | ||
69 | unsigned long reg_pend = d->ctrl->geint_pend + edata->eint_offset; | ||
70 | |||
71 | writel(1 << edata->pin, d->virt_base + reg_pend); | ||
72 | } | ||
73 | |||
74 | static int exynos_gpio_irq_set_type(struct irq_data *irqd, unsigned int type) | ||
75 | { | ||
76 | struct samsung_pinctrl_drv_data *d = irqd->domain->host_data; | ||
77 | struct samsung_pin_ctrl *ctrl = d->ctrl; | ||
78 | struct exynos_geint_data *edata = irq_data_get_irq_handler_data(irqd); | ||
79 | unsigned int shift = EXYNOS_EINT_CON_LEN * edata->pin; | ||
80 | unsigned int con, trig_type; | ||
81 | unsigned long reg_con = ctrl->geint_con + edata->eint_offset; | ||
82 | |||
83 | switch (type) { | ||
84 | case IRQ_TYPE_EDGE_RISING: | ||
85 | trig_type = EXYNOS_EINT_EDGE_RISING; | ||
86 | break; | ||
87 | case IRQ_TYPE_EDGE_FALLING: | ||
88 | trig_type = EXYNOS_EINT_EDGE_FALLING; | ||
89 | break; | ||
90 | case IRQ_TYPE_EDGE_BOTH: | ||
91 | trig_type = EXYNOS_EINT_EDGE_BOTH; | ||
92 | break; | ||
93 | case IRQ_TYPE_LEVEL_HIGH: | ||
94 | trig_type = EXYNOS_EINT_LEVEL_HIGH; | ||
95 | break; | ||
96 | case IRQ_TYPE_LEVEL_LOW: | ||
97 | trig_type = EXYNOS_EINT_LEVEL_LOW; | ||
98 | break; | ||
99 | default: | ||
100 | pr_err("unsupported external interrupt type\n"); | ||
101 | return -EINVAL; | ||
102 | } | ||
103 | |||
104 | if (type & IRQ_TYPE_EDGE_BOTH) | ||
105 | __irq_set_handler_locked(irqd->irq, handle_edge_irq); | ||
106 | else | ||
107 | __irq_set_handler_locked(irqd->irq, handle_level_irq); | ||
108 | |||
109 | con = readl(d->virt_base + reg_con); | ||
110 | con &= ~(EXYNOS_EINT_CON_MASK << shift); | ||
111 | con |= trig_type << shift; | ||
112 | writel(con, d->virt_base + reg_con); | ||
113 | return 0; | ||
114 | } | ||
115 | |||
116 | /* | ||
117 | * irq_chip for gpio interrupts. | ||
118 | */ | ||
119 | static struct irq_chip exynos_gpio_irq_chip = { | ||
120 | .name = "exynos_gpio_irq_chip", | ||
121 | .irq_unmask = exynos_gpio_irq_unmask, | ||
122 | .irq_mask = exynos_gpio_irq_mask, | ||
123 | .irq_ack = exynos_gpio_irq_ack, | ||
124 | .irq_set_type = exynos_gpio_irq_set_type, | ||
125 | }; | ||
126 | |||
127 | /* | ||
128 | * given a controller-local external gpio interrupt number, prepare the handler | ||
129 | * data for it. | ||
130 | */ | ||
131 | static struct exynos_geint_data *exynos_get_eint_data(irq_hw_number_t hw, | ||
132 | struct samsung_pinctrl_drv_data *d) | ||
133 | { | ||
134 | struct samsung_pin_bank *bank = d->ctrl->pin_banks; | ||
135 | struct exynos_geint_data *eint_data; | ||
136 | unsigned int nr_banks = d->ctrl->nr_banks, idx; | ||
137 | unsigned int irq_base = 0, eint_offset = 0; | ||
138 | |||
139 | if (hw >= d->ctrl->nr_gint) { | ||
140 | dev_err(d->dev, "unsupported ext-gpio interrupt\n"); | ||
141 | return NULL; | ||
142 | } | ||
143 | |||
144 | for (idx = 0; idx < nr_banks; idx++, bank++) { | ||
145 | if (bank->eint_type != EINT_TYPE_GPIO) | ||
146 | continue; | ||
147 | if ((hw >= irq_base) && (hw < (irq_base + bank->nr_pins))) | ||
148 | break; | ||
149 | irq_base += bank->nr_pins; | ||
150 | eint_offset += 4; | ||
151 | } | ||
152 | |||
153 | if (idx == nr_banks) { | ||
154 | dev_err(d->dev, "pin bank not found for ext-gpio interrupt\n"); | ||
155 | return NULL; | ||
156 | } | ||
157 | |||
158 | eint_data = devm_kzalloc(d->dev, sizeof(*eint_data), GFP_KERNEL); | ||
159 | if (!eint_data) { | ||
160 | dev_err(d->dev, "no memory for eint-gpio data\n"); | ||
161 | return NULL; | ||
162 | } | ||
163 | |||
164 | eint_data->bank = bank; | ||
165 | eint_data->pin = hw - irq_base; | ||
166 | eint_data->eint_offset = eint_offset; | ||
167 | return eint_data; | ||
168 | } | ||
169 | |||
170 | static int exynos_gpio_irq_map(struct irq_domain *h, unsigned int virq, | ||
171 | irq_hw_number_t hw) | ||
172 | { | ||
173 | struct samsung_pinctrl_drv_data *d = h->host_data; | ||
174 | struct exynos_geint_data *eint_data; | ||
175 | |||
176 | eint_data = exynos_get_eint_data(hw, d); | ||
177 | if (!eint_data) | ||
178 | return -EINVAL; | ||
179 | |||
180 | irq_set_handler_data(virq, eint_data); | ||
181 | irq_set_chip_data(virq, h->host_data); | ||
182 | irq_set_chip_and_handler(virq, &exynos_gpio_irq_chip, | ||
183 | handle_level_irq); | ||
184 | set_irq_flags(virq, IRQF_VALID); | ||
185 | return 0; | ||
186 | } | ||
187 | |||
188 | static void exynos_gpio_irq_unmap(struct irq_domain *h, unsigned int virq) | ||
189 | { | ||
190 | struct samsung_pinctrl_drv_data *d = h->host_data; | ||
191 | struct exynos_geint_data *eint_data; | ||
192 | |||
193 | eint_data = irq_get_handler_data(virq); | ||
194 | devm_kfree(d->dev, eint_data); | ||
195 | } | ||
196 | |||
197 | /* | ||
198 | * irq domain callbacks for external gpio interrupt controller. | ||
199 | */ | ||
200 | static const struct irq_domain_ops exynos_gpio_irqd_ops = { | ||
201 | .map = exynos_gpio_irq_map, | ||
202 | .unmap = exynos_gpio_irq_unmap, | ||
203 | .xlate = irq_domain_xlate_twocell, | ||
204 | }; | ||
205 | |||
206 | static irqreturn_t exynos_eint_gpio_irq(int irq, void *data) | ||
207 | { | ||
208 | struct samsung_pinctrl_drv_data *d = data; | ||
209 | struct samsung_pin_ctrl *ctrl = d->ctrl; | ||
210 | struct samsung_pin_bank *bank = ctrl->pin_banks; | ||
211 | unsigned int svc, group, pin, virq; | ||
212 | |||
213 | svc = readl(d->virt_base + ctrl->svc); | ||
214 | group = EXYNOS_SVC_GROUP(svc); | ||
215 | pin = svc & EXYNOS_SVC_NUM_MASK; | ||
216 | |||
217 | if (!group) | ||
218 | return IRQ_HANDLED; | ||
219 | bank += (group - 1); | ||
220 | |||
221 | virq = irq_linear_revmap(d->gpio_irqd, bank->irq_base + pin); | ||
222 | if (!virq) | ||
223 | return IRQ_NONE; | ||
224 | generic_handle_irq(virq); | ||
225 | return IRQ_HANDLED; | ||
226 | } | ||
227 | |||
228 | /* | ||
229 | * exynos_eint_gpio_init() - setup handling of external gpio interrupts. | ||
230 | * @d: driver data of samsung pinctrl driver. | ||
231 | */ | ||
232 | static int exynos_eint_gpio_init(struct samsung_pinctrl_drv_data *d) | ||
233 | { | ||
234 | struct device *dev = d->dev; | ||
235 | unsigned int ret; | ||
236 | |||
237 | if (!d->irq) { | ||
238 | dev_err(dev, "irq number not available\n"); | ||
239 | return -EINVAL; | ||
240 | } | ||
241 | |||
242 | ret = devm_request_irq(dev, d->irq, exynos_eint_gpio_irq, | ||
243 | 0, dev_name(dev), d); | ||
244 | if (ret) { | ||
245 | dev_err(dev, "irq request failed\n"); | ||
246 | return -ENXIO; | ||
247 | } | ||
248 | |||
249 | d->gpio_irqd = irq_domain_add_linear(dev->of_node, d->ctrl->nr_gint, | ||
250 | &exynos_gpio_irqd_ops, d); | ||
251 | if (!d->gpio_irqd) { | ||
252 | dev_err(dev, "gpio irq domain allocation failed\n"); | ||
253 | return -ENXIO; | ||
254 | } | ||
255 | |||
256 | return 0; | ||
257 | } | ||
258 | |||
259 | static void exynos_wkup_irq_unmask(struct irq_data *irqd) | ||
260 | { | ||
261 | struct samsung_pinctrl_drv_data *d = irq_data_get_irq_chip_data(irqd); | ||
262 | unsigned int bank = irqd->hwirq / EXYNOS_EINT_MAX_PER_BANK; | ||
263 | unsigned int pin = irqd->hwirq & (EXYNOS_EINT_MAX_PER_BANK - 1); | ||
264 | unsigned long reg_mask = d->ctrl->weint_mask + (bank << 2); | ||
265 | unsigned long mask; | ||
266 | |||
267 | mask = readl(d->virt_base + reg_mask); | ||
268 | mask &= ~(1 << pin); | ||
269 | writel(mask, d->virt_base + reg_mask); | ||
270 | } | ||
271 | |||
272 | static void exynos_wkup_irq_mask(struct irq_data *irqd) | ||
273 | { | ||
274 | struct samsung_pinctrl_drv_data *d = irq_data_get_irq_chip_data(irqd); | ||
275 | unsigned int bank = irqd->hwirq / EXYNOS_EINT_MAX_PER_BANK; | ||
276 | unsigned int pin = irqd->hwirq & (EXYNOS_EINT_MAX_PER_BANK - 1); | ||
277 | unsigned long reg_mask = d->ctrl->weint_mask + (bank << 2); | ||
278 | unsigned long mask; | ||
279 | |||
280 | mask = readl(d->virt_base + reg_mask); | ||
281 | mask &= ~(1 << pin); | ||
282 | writel(mask, d->virt_base + reg_mask); | ||
283 | } | ||
284 | |||
285 | static void exynos_wkup_irq_ack(struct irq_data *irqd) | ||
286 | { | ||
287 | struct samsung_pinctrl_drv_data *d = irq_data_get_irq_chip_data(irqd); | ||
288 | unsigned int bank = irqd->hwirq / EXYNOS_EINT_MAX_PER_BANK; | ||
289 | unsigned int pin = irqd->hwirq & (EXYNOS_EINT_MAX_PER_BANK - 1); | ||
290 | unsigned long pend = d->ctrl->weint_pend + (bank << 2); | ||
291 | |||
292 | writel(1 << pin, d->virt_base + pend); | ||
293 | } | ||
294 | |||
295 | static int exynos_wkup_irq_set_type(struct irq_data *irqd, unsigned int type) | ||
296 | { | ||
297 | struct samsung_pinctrl_drv_data *d = irq_data_get_irq_chip_data(irqd); | ||
298 | unsigned int bank = irqd->hwirq / EXYNOS_EINT_MAX_PER_BANK; | ||
299 | unsigned int pin = irqd->hwirq & (EXYNOS_EINT_MAX_PER_BANK - 1); | ||
300 | unsigned long reg_con = d->ctrl->weint_con + (bank << 2); | ||
301 | unsigned long shift = EXYNOS_EINT_CON_LEN * pin; | ||
302 | unsigned long con, trig_type; | ||
303 | |||
304 | switch (type) { | ||
305 | case IRQ_TYPE_EDGE_RISING: | ||
306 | trig_type = EXYNOS_EINT_EDGE_RISING; | ||
307 | break; | ||
308 | case IRQ_TYPE_EDGE_FALLING: | ||
309 | trig_type = EXYNOS_EINT_EDGE_FALLING; | ||
310 | break; | ||
311 | case IRQ_TYPE_EDGE_BOTH: | ||
312 | trig_type = EXYNOS_EINT_EDGE_BOTH; | ||
313 | break; | ||
314 | case IRQ_TYPE_LEVEL_HIGH: | ||
315 | trig_type = EXYNOS_EINT_LEVEL_HIGH; | ||
316 | break; | ||
317 | case IRQ_TYPE_LEVEL_LOW: | ||
318 | trig_type = EXYNOS_EINT_LEVEL_LOW; | ||
319 | break; | ||
320 | default: | ||
321 | pr_err("unsupported external interrupt type\n"); | ||
322 | return -EINVAL; | ||
323 | } | ||
324 | |||
325 | if (type & IRQ_TYPE_EDGE_BOTH) | ||
326 | __irq_set_handler_locked(irqd->irq, handle_edge_irq); | ||
327 | else | ||
328 | __irq_set_handler_locked(irqd->irq, handle_level_irq); | ||
329 | |||
330 | con = readl(d->virt_base + reg_con); | ||
331 | con &= ~(EXYNOS_EINT_CON_MASK << shift); | ||
332 | con |= trig_type << shift; | ||
333 | writel(con, d->virt_base + reg_con); | ||
334 | return 0; | ||
335 | } | ||
336 | |||
337 | /* | ||
338 | * irq_chip for wakeup interrupts | ||
339 | */ | ||
340 | static struct irq_chip exynos_wkup_irq_chip = { | ||
341 | .name = "exynos_wkup_irq_chip", | ||
342 | .irq_unmask = exynos_wkup_irq_unmask, | ||
343 | .irq_mask = exynos_wkup_irq_mask, | ||
344 | .irq_ack = exynos_wkup_irq_ack, | ||
345 | .irq_set_type = exynos_wkup_irq_set_type, | ||
346 | }; | ||
347 | |||
348 | /* interrupt handler for wakeup interrupts 0..15 */ | ||
349 | static void exynos_irq_eint0_15(unsigned int irq, struct irq_desc *desc) | ||
350 | { | ||
351 | struct exynos_weint_data *eintd = irq_get_handler_data(irq); | ||
352 | struct irq_chip *chip = irq_get_chip(irq); | ||
353 | int eint_irq; | ||
354 | |||
355 | chained_irq_enter(chip, desc); | ||
356 | chip->irq_mask(&desc->irq_data); | ||
357 | |||
358 | if (chip->irq_ack) | ||
359 | chip->irq_ack(&desc->irq_data); | ||
360 | |||
361 | eint_irq = irq_linear_revmap(eintd->domain, eintd->irq); | ||
362 | generic_handle_irq(eint_irq); | ||
363 | chip->irq_unmask(&desc->irq_data); | ||
364 | chained_irq_exit(chip, desc); | ||
365 | } | ||
366 | |||
367 | static void exynos_irq_demux_eint(int irq_base, unsigned long pend, | ||
368 | struct irq_domain *domain) | ||
369 | { | ||
370 | unsigned int irq; | ||
371 | |||
372 | while (pend) { | ||
373 | irq = fls(pend) - 1; | ||
374 | generic_handle_irq(irq_find_mapping(domain, irq_base + irq)); | ||
375 | pend &= ~(1 << irq); | ||
376 | } | ||
377 | } | ||
378 | |||
379 | /* interrupt handler for wakeup interrupt 16 */ | ||
380 | static void exynos_irq_demux_eint16_31(unsigned int irq, struct irq_desc *desc) | ||
381 | { | ||
382 | struct irq_chip *chip = irq_get_chip(irq); | ||
383 | struct exynos_weint_data *eintd = irq_get_handler_data(irq); | ||
384 | struct samsung_pinctrl_drv_data *d = eintd->domain->host_data; | ||
385 | unsigned long pend; | ||
386 | |||
387 | chained_irq_enter(chip, desc); | ||
388 | pend = readl(d->virt_base + d->ctrl->weint_pend + 0x8); | ||
389 | exynos_irq_demux_eint(16, pend, eintd->domain); | ||
390 | pend = readl(d->virt_base + d->ctrl->weint_pend + 0xC); | ||
391 | exynos_irq_demux_eint(24, pend, eintd->domain); | ||
392 | chained_irq_exit(chip, desc); | ||
393 | } | ||
394 | |||
395 | static int exynos_wkup_irq_map(struct irq_domain *h, unsigned int virq, | ||
396 | irq_hw_number_t hw) | ||
397 | { | ||
398 | irq_set_chip_and_handler(virq, &exynos_wkup_irq_chip, handle_level_irq); | ||
399 | irq_set_chip_data(virq, h->host_data); | ||
400 | set_irq_flags(virq, IRQF_VALID); | ||
401 | return 0; | ||
402 | } | ||
403 | |||
404 | /* | ||
405 | * irq domain callbacks for external wakeup interrupt controller. | ||
406 | */ | ||
407 | static const struct irq_domain_ops exynos_wkup_irqd_ops = { | ||
408 | .map = exynos_wkup_irq_map, | ||
409 | .xlate = irq_domain_xlate_twocell, | ||
410 | }; | ||
411 | |||
412 | /* | ||
413 | * exynos_eint_wkup_init() - setup handling of external wakeup interrupts. | ||
414 | * @d: driver data of samsung pinctrl driver. | ||
415 | */ | ||
416 | static int exynos_eint_wkup_init(struct samsung_pinctrl_drv_data *d) | ||
417 | { | ||
418 | struct device *dev = d->dev; | ||
419 | struct device_node *wkup_np; | ||
420 | struct exynos_weint_data *weint_data; | ||
421 | int idx, irq; | ||
422 | |||
423 | wkup_np = of_find_matching_node(dev->of_node, exynos_wkup_irq_ids); | ||
424 | if (!wkup_np) { | ||
425 | dev_err(dev, "wakeup controller node not found\n"); | ||
426 | return -ENODEV; | ||
427 | } | ||
428 | |||
429 | d->wkup_irqd = irq_domain_add_linear(wkup_np, d->ctrl->nr_wint, | ||
430 | &exynos_wkup_irqd_ops, d); | ||
431 | if (!d->gpio_irqd) { | ||
432 | dev_err(dev, "wakeup irq domain allocation failed\n"); | ||
433 | return -ENXIO; | ||
434 | } | ||
435 | |||
436 | weint_data = devm_kzalloc(dev, sizeof(*weint_data) * 17, GFP_KERNEL); | ||
437 | if (!weint_data) { | ||
438 | dev_err(dev, "could not allocate memory for weint_data\n"); | ||
439 | return -ENOMEM; | ||
440 | } | ||
441 | |||
442 | irq = irq_of_parse_and_map(wkup_np, 16); | ||
443 | if (irq) { | ||
444 | weint_data[16].domain = d->wkup_irqd; | ||
445 | irq_set_chained_handler(irq, exynos_irq_demux_eint16_31); | ||
446 | irq_set_handler_data(irq, &weint_data[16]); | ||
447 | } else { | ||
448 | dev_err(dev, "irq number for EINT16-32 not found\n"); | ||
449 | } | ||
450 | |||
451 | for (idx = 0; idx < 16; idx++) { | ||
452 | weint_data[idx].domain = d->wkup_irqd; | ||
453 | weint_data[idx].irq = idx; | ||
454 | |||
455 | irq = irq_of_parse_and_map(wkup_np, idx); | ||
456 | if (irq) { | ||
457 | irq_set_handler_data(irq, &weint_data[idx]); | ||
458 | irq_set_chained_handler(irq, exynos_irq_eint0_15); | ||
459 | } else { | ||
460 | dev_err(dev, "irq number for eint-%x not found\n", idx); | ||
461 | } | ||
462 | } | ||
463 | return 0; | ||
464 | } | ||
465 | |||
466 | /* pin banks of exynos4210 pin-controller 0 */ | ||
467 | static struct samsung_pin_bank exynos4210_pin_banks0[] = { | ||
468 | EXYNOS_PIN_BANK_EINTG(0x000, EXYNOS4210_GPIO_A0, "gpa0"), | ||
469 | EXYNOS_PIN_BANK_EINTG(0x020, EXYNOS4210_GPIO_A1, "gpa1"), | ||
470 | EXYNOS_PIN_BANK_EINTG(0x040, EXYNOS4210_GPIO_B, "gpb"), | ||
471 | EXYNOS_PIN_BANK_EINTG(0x060, EXYNOS4210_GPIO_C0, "gpc0"), | ||
472 | EXYNOS_PIN_BANK_EINTG(0x080, EXYNOS4210_GPIO_C1, "gpc1"), | ||
473 | EXYNOS_PIN_BANK_EINTG(0x0A0, EXYNOS4210_GPIO_D0, "gpd0"), | ||
474 | EXYNOS_PIN_BANK_EINTG(0x0C0, EXYNOS4210_GPIO_D1, "gpd1"), | ||
475 | EXYNOS_PIN_BANK_EINTG(0x0E0, EXYNOS4210_GPIO_E0, "gpe0"), | ||
476 | EXYNOS_PIN_BANK_EINTG(0x100, EXYNOS4210_GPIO_E1, "gpe1"), | ||
477 | EXYNOS_PIN_BANK_EINTG(0x120, EXYNOS4210_GPIO_E2, "gpe2"), | ||
478 | EXYNOS_PIN_BANK_EINTG(0x140, EXYNOS4210_GPIO_E3, "gpe3"), | ||
479 | EXYNOS_PIN_BANK_EINTG(0x160, EXYNOS4210_GPIO_E4, "gpe4"), | ||
480 | EXYNOS_PIN_BANK_EINTG(0x180, EXYNOS4210_GPIO_F0, "gpf0"), | ||
481 | EXYNOS_PIN_BANK_EINTG(0x1A0, EXYNOS4210_GPIO_F1, "gpf1"), | ||
482 | EXYNOS_PIN_BANK_EINTG(0x1C0, EXYNOS4210_GPIO_F2, "gpf2"), | ||
483 | EXYNOS_PIN_BANK_EINTG(0x1E0, EXYNOS4210_GPIO_F3, "gpf3"), | ||
484 | }; | ||
485 | |||
486 | /* pin banks of exynos4210 pin-controller 1 */ | ||
487 | static struct samsung_pin_bank exynos4210_pin_banks1[] = { | ||
488 | EXYNOS_PIN_BANK_EINTG(0x000, EXYNOS4210_GPIO_J0, "gpj0"), | ||
489 | EXYNOS_PIN_BANK_EINTG(0x020, EXYNOS4210_GPIO_J1, "gpj1"), | ||
490 | EXYNOS_PIN_BANK_EINTG(0x040, EXYNOS4210_GPIO_K0, "gpk0"), | ||
491 | EXYNOS_PIN_BANK_EINTG(0x060, EXYNOS4210_GPIO_K1, "gpk1"), | ||
492 | EXYNOS_PIN_BANK_EINTG(0x080, EXYNOS4210_GPIO_K2, "gpk2"), | ||
493 | EXYNOS_PIN_BANK_EINTG(0x0A0, EXYNOS4210_GPIO_K3, "gpk3"), | ||
494 | EXYNOS_PIN_BANK_EINTG(0x0C0, EXYNOS4210_GPIO_L0, "gpl0"), | ||
495 | EXYNOS_PIN_BANK_EINTG(0x0E0, EXYNOS4210_GPIO_L1, "gpl1"), | ||
496 | EXYNOS_PIN_BANK_EINTG(0x100, EXYNOS4210_GPIO_L2, "gpl2"), | ||
497 | EXYNOS_PIN_BANK_EINTN(0x120, EXYNOS4210_GPIO_Y0, "gpy0"), | ||
498 | EXYNOS_PIN_BANK_EINTN(0x140, EXYNOS4210_GPIO_Y1, "gpy1"), | ||
499 | EXYNOS_PIN_BANK_EINTN(0x160, EXYNOS4210_GPIO_Y2, "gpy2"), | ||
500 | EXYNOS_PIN_BANK_EINTN(0x180, EXYNOS4210_GPIO_Y3, "gpy3"), | ||
501 | EXYNOS_PIN_BANK_EINTN(0x1A0, EXYNOS4210_GPIO_Y4, "gpy4"), | ||
502 | EXYNOS_PIN_BANK_EINTN(0x1C0, EXYNOS4210_GPIO_Y5, "gpy5"), | ||
503 | EXYNOS_PIN_BANK_EINTN(0x1E0, EXYNOS4210_GPIO_Y6, "gpy6"), | ||
504 | EXYNOS_PIN_BANK_EINTN(0xC00, EXYNOS4210_GPIO_X0, "gpx0"), | ||
505 | EXYNOS_PIN_BANK_EINTN(0xC20, EXYNOS4210_GPIO_X1, "gpx1"), | ||
506 | EXYNOS_PIN_BANK_EINTN(0xC40, EXYNOS4210_GPIO_X2, "gpx2"), | ||
507 | EXYNOS_PIN_BANK_EINTN(0xC60, EXYNOS4210_GPIO_X3, "gpx3"), | ||
508 | }; | ||
509 | |||
510 | /* pin banks of exynos4210 pin-controller 2 */ | ||
511 | static struct samsung_pin_bank exynos4210_pin_banks2[] = { | ||
512 | EXYNOS_PIN_BANK_EINTN(0x000, EXYNOS4210_GPIO_Z, "gpz"), | ||
513 | }; | ||
514 | |||
515 | /* | ||
516 | * Samsung pinctrl driver data for Exynos4210 SoC. Exynos4210 SoC includes | ||
517 | * three gpio/pin-mux/pinconfig controllers. | ||
518 | */ | ||
519 | struct samsung_pin_ctrl exynos4210_pin_ctrl[] = { | ||
520 | { | ||
521 | /* pin-controller instance 0 data */ | ||
522 | .pin_banks = exynos4210_pin_banks0, | ||
523 | .nr_banks = ARRAY_SIZE(exynos4210_pin_banks0), | ||
524 | .base = EXYNOS4210_GPIO_A0_START, | ||
525 | .nr_pins = EXYNOS4210_GPIOA_NR_PINS, | ||
526 | .nr_gint = EXYNOS4210_GPIOA_NR_GINT, | ||
527 | .geint_con = EXYNOS_GPIO_ECON_OFFSET, | ||
528 | .geint_mask = EXYNOS_GPIO_EMASK_OFFSET, | ||
529 | .geint_pend = EXYNOS_GPIO_EPEND_OFFSET, | ||
530 | .svc = EXYNOS_SVC_OFFSET, | ||
531 | .eint_gpio_init = exynos_eint_gpio_init, | ||
532 | .label = "exynos4210-gpio-ctrl0", | ||
533 | }, { | ||
534 | /* pin-controller instance 1 data */ | ||
535 | .pin_banks = exynos4210_pin_banks1, | ||
536 | .nr_banks = ARRAY_SIZE(exynos4210_pin_banks1), | ||
537 | .base = EXYNOS4210_GPIOA_NR_PINS, | ||
538 | .nr_pins = EXYNOS4210_GPIOB_NR_PINS, | ||
539 | .nr_gint = EXYNOS4210_GPIOB_NR_GINT, | ||
540 | .nr_wint = 32, | ||
541 | .geint_con = EXYNOS_GPIO_ECON_OFFSET, | ||
542 | .geint_mask = EXYNOS_GPIO_EMASK_OFFSET, | ||
543 | .geint_pend = EXYNOS_GPIO_EPEND_OFFSET, | ||
544 | .weint_con = EXYNOS_WKUP_ECON_OFFSET, | ||
545 | .weint_mask = EXYNOS_WKUP_EMASK_OFFSET, | ||
546 | .weint_pend = EXYNOS_WKUP_EPEND_OFFSET, | ||
547 | .svc = EXYNOS_SVC_OFFSET, | ||
548 | .eint_gpio_init = exynos_eint_gpio_init, | ||
549 | .eint_wkup_init = exynos_eint_wkup_init, | ||
550 | .label = "exynos4210-gpio-ctrl1", | ||
551 | }, { | ||
552 | /* pin-controller instance 2 data */ | ||
553 | .pin_banks = exynos4210_pin_banks2, | ||
554 | .nr_banks = ARRAY_SIZE(exynos4210_pin_banks2), | ||
555 | .base = EXYNOS4210_GPIOA_NR_PINS + | ||
556 | EXYNOS4210_GPIOB_NR_PINS, | ||
557 | .nr_pins = EXYNOS4210_GPIOC_NR_PINS, | ||
558 | .label = "exynos4210-gpio-ctrl2", | ||
559 | }, | ||
560 | }; | ||
diff --git a/drivers/pinctrl/pinctrl-exynos.h b/drivers/pinctrl/pinctrl-exynos.h new file mode 100644 index 000000000000..5f27ba974a3a --- /dev/null +++ b/drivers/pinctrl/pinctrl-exynos.h | |||
@@ -0,0 +1,217 @@ | |||
1 | /* | ||
2 | * Exynos specific definitions for Samsung pinctrl and gpiolib driver. | ||
3 | * | ||
4 | * Copyright (c) 2012 Samsung Electronics Co., Ltd. | ||
5 | * http://www.samsung.com | ||
6 | * Copyright (c) 2012 Linaro Ltd | ||
7 | * http://www.linaro.org | ||
8 | * | ||
9 | * This file contains the Exynos specific definitions for the Samsung | ||
10 | * pinctrl/gpiolib interface drivers. | ||
11 | * | ||
12 | * Author: Thomas Abraham <thomas.ab@samsung.com> | ||
13 | * | ||
14 | * This program is free software; you can redistribute it and/or modify | ||
15 | * it under the terms of the GNU General Public License as published by | ||
16 | * the Free Software Foundation; either version 2 of the License, or | ||
17 | * (at your option) any later version. | ||
18 | */ | ||
19 | |||
20 | #define EXYNOS_GPIO_START(__gpio) ((__gpio##_START) + (__gpio##_NR)) | ||
21 | |||
22 | #define EXYNOS4210_GPIO_A0_NR (8) | ||
23 | #define EXYNOS4210_GPIO_A1_NR (6) | ||
24 | #define EXYNOS4210_GPIO_B_NR (8) | ||
25 | #define EXYNOS4210_GPIO_C0_NR (5) | ||
26 | #define EXYNOS4210_GPIO_C1_NR (5) | ||
27 | #define EXYNOS4210_GPIO_D0_NR (4) | ||
28 | #define EXYNOS4210_GPIO_D1_NR (4) | ||
29 | #define EXYNOS4210_GPIO_E0_NR (5) | ||
30 | #define EXYNOS4210_GPIO_E1_NR (8) | ||
31 | #define EXYNOS4210_GPIO_E2_NR (6) | ||
32 | #define EXYNOS4210_GPIO_E3_NR (8) | ||
33 | #define EXYNOS4210_GPIO_E4_NR (8) | ||
34 | #define EXYNOS4210_GPIO_F0_NR (8) | ||
35 | #define EXYNOS4210_GPIO_F1_NR (8) | ||
36 | #define EXYNOS4210_GPIO_F2_NR (8) | ||
37 | #define EXYNOS4210_GPIO_F3_NR (6) | ||
38 | #define EXYNOS4210_GPIO_J0_NR (8) | ||
39 | #define EXYNOS4210_GPIO_J1_NR (5) | ||
40 | #define EXYNOS4210_GPIO_K0_NR (7) | ||
41 | #define EXYNOS4210_GPIO_K1_NR (7) | ||
42 | #define EXYNOS4210_GPIO_K2_NR (7) | ||
43 | #define EXYNOS4210_GPIO_K3_NR (7) | ||
44 | #define EXYNOS4210_GPIO_L0_NR (8) | ||
45 | #define EXYNOS4210_GPIO_L1_NR (3) | ||
46 | #define EXYNOS4210_GPIO_L2_NR (8) | ||
47 | #define EXYNOS4210_GPIO_Y0_NR (6) | ||
48 | #define EXYNOS4210_GPIO_Y1_NR (4) | ||
49 | #define EXYNOS4210_GPIO_Y2_NR (6) | ||
50 | #define EXYNOS4210_GPIO_Y3_NR (8) | ||
51 | #define EXYNOS4210_GPIO_Y4_NR (8) | ||
52 | #define EXYNOS4210_GPIO_Y5_NR (8) | ||
53 | #define EXYNOS4210_GPIO_Y6_NR (8) | ||
54 | #define EXYNOS4210_GPIO_X0_NR (8) | ||
55 | #define EXYNOS4210_GPIO_X1_NR (8) | ||
56 | #define EXYNOS4210_GPIO_X2_NR (8) | ||
57 | #define EXYNOS4210_GPIO_X3_NR (8) | ||
58 | #define EXYNOS4210_GPIO_Z_NR (7) | ||
59 | |||
60 | enum exynos4210_gpio_xa_start { | ||
61 | EXYNOS4210_GPIO_A0_START = 0, | ||
62 | EXYNOS4210_GPIO_A1_START = EXYNOS_GPIO_START(EXYNOS4210_GPIO_A0), | ||
63 | EXYNOS4210_GPIO_B_START = EXYNOS_GPIO_START(EXYNOS4210_GPIO_A1), | ||
64 | EXYNOS4210_GPIO_C0_START = EXYNOS_GPIO_START(EXYNOS4210_GPIO_B), | ||
65 | EXYNOS4210_GPIO_C1_START = EXYNOS_GPIO_START(EXYNOS4210_GPIO_C0), | ||
66 | EXYNOS4210_GPIO_D0_START = EXYNOS_GPIO_START(EXYNOS4210_GPIO_C1), | ||
67 | EXYNOS4210_GPIO_D1_START = EXYNOS_GPIO_START(EXYNOS4210_GPIO_D0), | ||
68 | EXYNOS4210_GPIO_E0_START = EXYNOS_GPIO_START(EXYNOS4210_GPIO_D1), | ||
69 | EXYNOS4210_GPIO_E1_START = EXYNOS_GPIO_START(EXYNOS4210_GPIO_E0), | ||
70 | EXYNOS4210_GPIO_E2_START = EXYNOS_GPIO_START(EXYNOS4210_GPIO_E1), | ||
71 | EXYNOS4210_GPIO_E3_START = EXYNOS_GPIO_START(EXYNOS4210_GPIO_E2), | ||
72 | EXYNOS4210_GPIO_E4_START = EXYNOS_GPIO_START(EXYNOS4210_GPIO_E3), | ||
73 | EXYNOS4210_GPIO_F0_START = EXYNOS_GPIO_START(EXYNOS4210_GPIO_E4), | ||
74 | EXYNOS4210_GPIO_F1_START = EXYNOS_GPIO_START(EXYNOS4210_GPIO_F0), | ||
75 | EXYNOS4210_GPIO_F2_START = EXYNOS_GPIO_START(EXYNOS4210_GPIO_F1), | ||
76 | EXYNOS4210_GPIO_F3_START = EXYNOS_GPIO_START(EXYNOS4210_GPIO_F2), | ||
77 | }; | ||
78 | |||
79 | enum exynos4210_gpio_xb_start { | ||
80 | EXYNOS4210_GPIO_J0_START = 0, | ||
81 | EXYNOS4210_GPIO_J1_START = EXYNOS_GPIO_START(EXYNOS4210_GPIO_J0), | ||
82 | EXYNOS4210_GPIO_K0_START = EXYNOS_GPIO_START(EXYNOS4210_GPIO_J1), | ||
83 | EXYNOS4210_GPIO_K1_START = EXYNOS_GPIO_START(EXYNOS4210_GPIO_K0), | ||
84 | EXYNOS4210_GPIO_K2_START = EXYNOS_GPIO_START(EXYNOS4210_GPIO_K1), | ||
85 | EXYNOS4210_GPIO_K3_START = EXYNOS_GPIO_START(EXYNOS4210_GPIO_K2), | ||
86 | EXYNOS4210_GPIO_L0_START = EXYNOS_GPIO_START(EXYNOS4210_GPIO_K3), | ||
87 | EXYNOS4210_GPIO_L1_START = EXYNOS_GPIO_START(EXYNOS4210_GPIO_L0), | ||
88 | EXYNOS4210_GPIO_L2_START = EXYNOS_GPIO_START(EXYNOS4210_GPIO_L1), | ||
89 | EXYNOS4210_GPIO_Y0_START = EXYNOS_GPIO_START(EXYNOS4210_GPIO_L2), | ||
90 | EXYNOS4210_GPIO_Y1_START = EXYNOS_GPIO_START(EXYNOS4210_GPIO_Y0), | ||
91 | EXYNOS4210_GPIO_Y2_START = EXYNOS_GPIO_START(EXYNOS4210_GPIO_Y1), | ||
92 | EXYNOS4210_GPIO_Y3_START = EXYNOS_GPIO_START(EXYNOS4210_GPIO_Y2), | ||
93 | EXYNOS4210_GPIO_Y4_START = EXYNOS_GPIO_START(EXYNOS4210_GPIO_Y3), | ||
94 | EXYNOS4210_GPIO_Y5_START = EXYNOS_GPIO_START(EXYNOS4210_GPIO_Y4), | ||
95 | EXYNOS4210_GPIO_Y6_START = EXYNOS_GPIO_START(EXYNOS4210_GPIO_Y5), | ||
96 | EXYNOS4210_GPIO_X0_START = EXYNOS_GPIO_START(EXYNOS4210_GPIO_Y6), | ||
97 | EXYNOS4210_GPIO_X1_START = EXYNOS_GPIO_START(EXYNOS4210_GPIO_X0), | ||
98 | EXYNOS4210_GPIO_X2_START = EXYNOS_GPIO_START(EXYNOS4210_GPIO_X1), | ||
99 | EXYNOS4210_GPIO_X3_START = EXYNOS_GPIO_START(EXYNOS4210_GPIO_X2), | ||
100 | }; | ||
101 | |||
102 | enum exynos4210_gpio_xc_start { | ||
103 | EXYNOS4210_GPIO_Z_START = 0, | ||
104 | }; | ||
105 | |||
106 | #define EXYNOS4210_GPIO_A0_IRQ EXYNOS4210_GPIO_A0_START | ||
107 | #define EXYNOS4210_GPIO_A1_IRQ EXYNOS4210_GPIO_A1_START | ||
108 | #define EXYNOS4210_GPIO_B_IRQ EXYNOS4210_GPIO_B_START | ||
109 | #define EXYNOS4210_GPIO_C0_IRQ EXYNOS4210_GPIO_C0_START | ||
110 | #define EXYNOS4210_GPIO_C1_IRQ EXYNOS4210_GPIO_C1_START | ||
111 | #define EXYNOS4210_GPIO_D0_IRQ EXYNOS4210_GPIO_D0_START | ||
112 | #define EXYNOS4210_GPIO_D1_IRQ EXYNOS4210_GPIO_D1_START | ||
113 | #define EXYNOS4210_GPIO_E0_IRQ EXYNOS4210_GPIO_E0_START | ||
114 | #define EXYNOS4210_GPIO_E1_IRQ EXYNOS4210_GPIO_E1_START | ||
115 | #define EXYNOS4210_GPIO_E2_IRQ EXYNOS4210_GPIO_E2_START | ||
116 | #define EXYNOS4210_GPIO_E3_IRQ EXYNOS4210_GPIO_E3_START | ||
117 | #define EXYNOS4210_GPIO_E4_IRQ EXYNOS4210_GPIO_E4_START | ||
118 | #define EXYNOS4210_GPIO_F0_IRQ EXYNOS4210_GPIO_F0_START | ||
119 | #define EXYNOS4210_GPIO_F1_IRQ EXYNOS4210_GPIO_F1_START | ||
120 | #define EXYNOS4210_GPIO_F2_IRQ EXYNOS4210_GPIO_F2_START | ||
121 | #define EXYNOS4210_GPIO_F3_IRQ EXYNOS4210_GPIO_F3_START | ||
122 | #define EXYNOS4210_GPIO_J0_IRQ EXYNOS4210_GPIO_J0_START | ||
123 | #define EXYNOS4210_GPIO_J1_IRQ EXYNOS4210_GPIO_J1_START | ||
124 | #define EXYNOS4210_GPIO_K0_IRQ EXYNOS4210_GPIO_K0_START | ||
125 | #define EXYNOS4210_GPIO_K1_IRQ EXYNOS4210_GPIO_K1_START | ||
126 | #define EXYNOS4210_GPIO_K2_IRQ EXYNOS4210_GPIO_K2_START | ||
127 | #define EXYNOS4210_GPIO_K3_IRQ EXYNOS4210_GPIO_K3_START | ||
128 | #define EXYNOS4210_GPIO_L0_IRQ EXYNOS4210_GPIO_L0_START | ||
129 | #define EXYNOS4210_GPIO_L1_IRQ EXYNOS4210_GPIO_L1_START | ||
130 | #define EXYNOS4210_GPIO_L2_IRQ EXYNOS4210_GPIO_L2_START | ||
131 | #define EXYNOS4210_GPIO_Z_IRQ EXYNOS4210_GPIO_Z_START | ||
132 | |||
133 | #define EXYNOS4210_GPIOA_NR_PINS EXYNOS_GPIO_START(EXYNOS4210_GPIO_F3) | ||
134 | #define EXYNOS4210_GPIOA_NR_GINT EXYNOS_GPIO_START(EXYNOS4210_GPIO_F3) | ||
135 | #define EXYNOS4210_GPIOB_NR_PINS EXYNOS_GPIO_START(EXYNOS4210_GPIO_X3) | ||
136 | #define EXYNOS4210_GPIOB_NR_GINT EXYNOS_GPIO_START(EXYNOS4210_GPIO_L2) | ||
137 | #define EXYNOS4210_GPIOC_NR_PINS EXYNOS_GPIO_START(EXYNOS4210_GPIO_Z) | ||
138 | |||
139 | /* External GPIO and wakeup interrupt related definitions */ | ||
140 | #define EXYNOS_GPIO_ECON_OFFSET 0x700 | ||
141 | #define EXYNOS_GPIO_EMASK_OFFSET 0x900 | ||
142 | #define EXYNOS_GPIO_EPEND_OFFSET 0xA00 | ||
143 | #define EXYNOS_WKUP_ECON_OFFSET 0xE00 | ||
144 | #define EXYNOS_WKUP_EMASK_OFFSET 0xF00 | ||
145 | #define EXYNOS_WKUP_EPEND_OFFSET 0xF40 | ||
146 | #define EXYNOS_SVC_OFFSET 0xB08 | ||
147 | |||
148 | /* helpers to access interrupt service register */ | ||
149 | #define EXYNOS_SVC_GROUP_SHIFT 3 | ||
150 | #define EXYNOS_SVC_GROUP_MASK 0x1f | ||
151 | #define EXYNOS_SVC_NUM_MASK 7 | ||
152 | #define EXYNOS_SVC_GROUP(x) ((x >> EXYNOS_SVC_GROUP_SHIFT) & \ | ||
153 | EXYNOS_SVC_GROUP_MASK) | ||
154 | |||
155 | /* Exynos specific external interrupt trigger types */ | ||
156 | #define EXYNOS_EINT_LEVEL_LOW 0 | ||
157 | #define EXYNOS_EINT_LEVEL_HIGH 1 | ||
158 | #define EXYNOS_EINT_EDGE_FALLING 2 | ||
159 | #define EXYNOS_EINT_EDGE_RISING 3 | ||
160 | #define EXYNOS_EINT_EDGE_BOTH 4 | ||
161 | #define EXYNOS_EINT_CON_MASK 0xF | ||
162 | #define EXYNOS_EINT_CON_LEN 4 | ||
163 | |||
164 | #define EXYNOS_EINT_MAX_PER_BANK 8 | ||
165 | #define EXYNOS_EINT_NR_WKUP_EINT | ||
166 | |||
167 | #define EXYNOS_PIN_BANK_EINTN(reg, __gpio, id) \ | ||
168 | { \ | ||
169 | .pctl_offset = reg, \ | ||
170 | .pin_base = (__gpio##_START), \ | ||
171 | .nr_pins = (__gpio##_NR), \ | ||
172 | .func_width = 4, \ | ||
173 | .pud_width = 2, \ | ||
174 | .drv_width = 2, \ | ||
175 | .conpdn_width = 2, \ | ||
176 | .pudpdn_width = 2, \ | ||
177 | .eint_type = EINT_TYPE_NONE, \ | ||
178 | .name = id \ | ||
179 | } | ||
180 | |||
181 | #define EXYNOS_PIN_BANK_EINTG(reg, __gpio, id) \ | ||
182 | { \ | ||
183 | .pctl_offset = reg, \ | ||
184 | .pin_base = (__gpio##_START), \ | ||
185 | .nr_pins = (__gpio##_NR), \ | ||
186 | .func_width = 4, \ | ||
187 | .pud_width = 2, \ | ||
188 | .drv_width = 2, \ | ||
189 | .conpdn_width = 2, \ | ||
190 | .pudpdn_width = 2, \ | ||
191 | .eint_type = EINT_TYPE_GPIO, \ | ||
192 | .irq_base = (__gpio##_IRQ), \ | ||
193 | .name = id \ | ||
194 | } | ||
195 | |||
196 | /** | ||
197 | * struct exynos_geint_data: gpio eint specific data for irq_chip callbacks. | ||
198 | * @bank: pin bank from which this gpio interrupt originates. | ||
199 | * @pin: pin number within the bank. | ||
200 | * @eint_offset: offset to be added to the con/pend/mask register bank base. | ||
201 | */ | ||
202 | struct exynos_geint_data { | ||
203 | struct samsung_pin_bank *bank; | ||
204 | u32 pin; | ||
205 | u32 eint_offset; | ||
206 | }; | ||
207 | |||
208 | /** | ||
209 | * struct exynos_weint_data: irq specific data for all the wakeup interrupts | ||
210 | * generated by the external wakeup interrupt controller. | ||
211 | * @domain: irq domain representing the external wakeup interrupts | ||
212 | * @irq: interrupt number within the domain. | ||
213 | */ | ||
214 | struct exynos_weint_data { | ||
215 | struct irq_domain *domain; | ||
216 | u32 irq; | ||
217 | }; | ||
diff --git a/drivers/pinctrl/pinctrl-samsung.c b/drivers/pinctrl/pinctrl-samsung.c new file mode 100644 index 000000000000..8a24223d5334 --- /dev/null +++ b/drivers/pinctrl/pinctrl-samsung.c | |||
@@ -0,0 +1,888 @@ | |||
1 | /* | ||
2 | * pin-controller/pin-mux/pin-config/gpio-driver for Samsung's SoC's. | ||
3 | * | ||
4 | * Copyright (c) 2012 Samsung Electronics Co., Ltd. | ||
5 | * http://www.samsung.com | ||
6 | * Copyright (c) 2012 Linaro Ltd | ||
7 | * http://www.linaro.org | ||
8 | * | ||
9 | * Author: Thomas Abraham <thomas.ab@samsung.com> | ||
10 | * | ||
11 | * This program is free software; you can redistribute it and/or modify | ||
12 | * it under the terms of the GNU General Public License as published by | ||
13 | * the Free Software Foundation; either version 2 of the License, or | ||
14 | * (at your option) any later version. | ||
15 | * | ||
16 | * This driver implements the Samsung pinctrl driver. It supports setting up of | ||
17 | * pinmux and pinconf configurations. The gpiolib interface is also included. | ||
18 | * External interrupt (gpio and wakeup) support are not included in this driver | ||
19 | * but provides extensions to which platform specific implementation of the gpio | ||
20 | * and wakeup interrupts can be hooked to. | ||
21 | */ | ||
22 | |||
23 | #include <linux/module.h> | ||
24 | #include <linux/platform_device.h> | ||
25 | #include <linux/io.h> | ||
26 | #include <linux/slab.h> | ||
27 | #include <linux/err.h> | ||
28 | #include <linux/gpio.h> | ||
29 | |||
30 | #include "core.h" | ||
31 | #include "pinctrl-samsung.h" | ||
32 | |||
33 | #define GROUP_SUFFIX "-grp" | ||
34 | #define GSUFFIX_LEN sizeof(GROUP_SUFFIX) | ||
35 | #define FUNCTION_SUFFIX "-mux" | ||
36 | #define FSUFFIX_LEN sizeof(FUNCTION_SUFFIX) | ||
37 | |||
38 | /* list of all possible config options supported */ | ||
39 | struct pin_config { | ||
40 | char *prop_cfg; | ||
41 | unsigned int cfg_type; | ||
42 | } pcfgs[] = { | ||
43 | { "samsung,pin-pud", PINCFG_TYPE_PUD }, | ||
44 | { "samsung,pin-drv", PINCFG_TYPE_DRV }, | ||
45 | { "samsung,pin-con-pdn", PINCFG_TYPE_CON_PDN }, | ||
46 | { "samsung,pin-pud-pdn", PINCFG_TYPE_PUD_PDN }, | ||
47 | }; | ||
48 | |||
49 | /* check if the selector is a valid pin group selector */ | ||
50 | static int samsung_get_group_count(struct pinctrl_dev *pctldev) | ||
51 | { | ||
52 | struct samsung_pinctrl_drv_data *drvdata; | ||
53 | |||
54 | drvdata = pinctrl_dev_get_drvdata(pctldev); | ||
55 | return drvdata->nr_groups; | ||
56 | } | ||
57 | |||
58 | /* return the name of the group selected by the group selector */ | ||
59 | static const char *samsung_get_group_name(struct pinctrl_dev *pctldev, | ||
60 | unsigned selector) | ||
61 | { | ||
62 | struct samsung_pinctrl_drv_data *drvdata; | ||
63 | |||
64 | drvdata = pinctrl_dev_get_drvdata(pctldev); | ||
65 | return drvdata->pin_groups[selector].name; | ||
66 | } | ||
67 | |||
68 | /* return the pin numbers associated with the specified group */ | ||
69 | static int samsung_get_group_pins(struct pinctrl_dev *pctldev, | ||
70 | unsigned selector, const unsigned **pins, unsigned *num_pins) | ||
71 | { | ||
72 | struct samsung_pinctrl_drv_data *drvdata; | ||
73 | |||
74 | drvdata = pinctrl_dev_get_drvdata(pctldev); | ||
75 | *pins = drvdata->pin_groups[selector].pins; | ||
76 | *num_pins = drvdata->pin_groups[selector].num_pins; | ||
77 | return 0; | ||
78 | } | ||
79 | |||
80 | /* create pinctrl_map entries by parsing device tree nodes */ | ||
81 | static int samsung_dt_node_to_map(struct pinctrl_dev *pctldev, | ||
82 | struct device_node *np, struct pinctrl_map **maps, | ||
83 | unsigned *nmaps) | ||
84 | { | ||
85 | struct device *dev = pctldev->dev; | ||
86 | struct pinctrl_map *map; | ||
87 | unsigned long *cfg = NULL; | ||
88 | char *gname, *fname; | ||
89 | int cfg_cnt = 0, map_cnt = 0, idx = 0; | ||
90 | |||
91 | /* count the number of config options specfied in the node */ | ||
92 | for (idx = 0; idx < ARRAY_SIZE(pcfgs); idx++) { | ||
93 | if (of_find_property(np, pcfgs[idx].prop_cfg, NULL)) | ||
94 | cfg_cnt++; | ||
95 | } | ||
96 | |||
97 | /* | ||
98 | * Find out the number of map entries to create. All the config options | ||
99 | * can be accomadated into a single config map entry. | ||
100 | */ | ||
101 | if (cfg_cnt) | ||
102 | map_cnt = 1; | ||
103 | if (of_find_property(np, "samsung,pin-function", NULL)) | ||
104 | map_cnt++; | ||
105 | if (!map_cnt) { | ||
106 | dev_err(dev, "node %s does not have either config or function " | ||
107 | "configurations\n", np->name); | ||
108 | return -EINVAL; | ||
109 | } | ||
110 | |||
111 | /* Allocate memory for pin-map entries */ | ||
112 | map = kzalloc(sizeof(*map) * map_cnt, GFP_KERNEL); | ||
113 | if (!map) { | ||
114 | dev_err(dev, "could not alloc memory for pin-maps\n"); | ||
115 | return -ENOMEM; | ||
116 | } | ||
117 | *nmaps = 0; | ||
118 | |||
119 | /* | ||
120 | * Allocate memory for pin group name. The pin group name is derived | ||
121 | * from the node name from which these map entries are be created. | ||
122 | */ | ||
123 | gname = kzalloc(strlen(np->name) + GSUFFIX_LEN, GFP_KERNEL); | ||
124 | if (!gname) { | ||
125 | dev_err(dev, "failed to alloc memory for group name\n"); | ||
126 | goto free_map; | ||
127 | } | ||
128 | sprintf(gname, "%s%s", np->name, GROUP_SUFFIX); | ||
129 | |||
130 | /* | ||
131 | * don't have config options? then skip over to creating function | ||
132 | * map entries. | ||
133 | */ | ||
134 | if (!cfg_cnt) | ||
135 | goto skip_cfgs; | ||
136 | |||
137 | /* Allocate memory for config entries */ | ||
138 | cfg = kzalloc(sizeof(*cfg) * cfg_cnt, GFP_KERNEL); | ||
139 | if (!cfg) { | ||
140 | dev_err(dev, "failed to alloc memory for configs\n"); | ||
141 | goto free_gname; | ||
142 | } | ||
143 | |||
144 | /* Prepare a list of config settings */ | ||
145 | for (idx = 0, cfg_cnt = 0; idx < ARRAY_SIZE(pcfgs); idx++) { | ||
146 | u32 value; | ||
147 | if (!of_property_read_u32(np, pcfgs[idx].prop_cfg, &value)) | ||
148 | cfg[cfg_cnt++] = | ||
149 | PINCFG_PACK(pcfgs[idx].cfg_type, value); | ||
150 | } | ||
151 | |||
152 | /* create the config map entry */ | ||
153 | map[*nmaps].data.configs.group_or_pin = gname; | ||
154 | map[*nmaps].data.configs.configs = cfg; | ||
155 | map[*nmaps].data.configs.num_configs = cfg_cnt; | ||
156 | map[*nmaps].type = PIN_MAP_TYPE_CONFIGS_GROUP; | ||
157 | *nmaps += 1; | ||
158 | |||
159 | skip_cfgs: | ||
160 | /* create the function map entry */ | ||
161 | if (of_find_property(np, "samsung,pin-function", NULL)) { | ||
162 | fname = kzalloc(strlen(np->name) + FSUFFIX_LEN, GFP_KERNEL); | ||
163 | if (!fname) { | ||
164 | dev_err(dev, "failed to alloc memory for func name\n"); | ||
165 | goto free_cfg; | ||
166 | } | ||
167 | sprintf(fname, "%s%s", np->name, FUNCTION_SUFFIX); | ||
168 | |||
169 | map[*nmaps].data.mux.group = gname; | ||
170 | map[*nmaps].data.mux.function = fname; | ||
171 | map[*nmaps].type = PIN_MAP_TYPE_MUX_GROUP; | ||
172 | *nmaps += 1; | ||
173 | } | ||
174 | |||
175 | *maps = map; | ||
176 | return 0; | ||
177 | |||
178 | free_cfg: | ||
179 | kfree(cfg); | ||
180 | free_gname: | ||
181 | kfree(gname); | ||
182 | free_map: | ||
183 | kfree(map); | ||
184 | return -ENOMEM; | ||
185 | } | ||
186 | |||
187 | /* free the memory allocated to hold the pin-map table */ | ||
188 | static void samsung_dt_free_map(struct pinctrl_dev *pctldev, | ||
189 | struct pinctrl_map *map, unsigned num_maps) | ||
190 | { | ||
191 | int idx; | ||
192 | |||
193 | for (idx = 0; idx < num_maps; idx++) { | ||
194 | if (map[idx].type == PIN_MAP_TYPE_MUX_GROUP) { | ||
195 | kfree(map[idx].data.mux.function); | ||
196 | if (!idx) | ||
197 | kfree(map[idx].data.mux.group); | ||
198 | } else if (map->type == PIN_MAP_TYPE_CONFIGS_GROUP) { | ||
199 | kfree(map[idx].data.configs.configs); | ||
200 | if (!idx) | ||
201 | kfree(map[idx].data.configs.group_or_pin); | ||
202 | } | ||
203 | }; | ||
204 | |||
205 | kfree(map); | ||
206 | } | ||
207 | |||
208 | /* list of pinctrl callbacks for the pinctrl core */ | ||
209 | static struct pinctrl_ops samsung_pctrl_ops = { | ||
210 | .get_groups_count = samsung_get_group_count, | ||
211 | .get_group_name = samsung_get_group_name, | ||
212 | .get_group_pins = samsung_get_group_pins, | ||
213 | .dt_node_to_map = samsung_dt_node_to_map, | ||
214 | .dt_free_map = samsung_dt_free_map, | ||
215 | }; | ||
216 | |||
217 | /* check if the selector is a valid pin function selector */ | ||
218 | static int samsung_get_functions_count(struct pinctrl_dev *pctldev) | ||
219 | { | ||
220 | struct samsung_pinctrl_drv_data *drvdata; | ||
221 | |||
222 | drvdata = pinctrl_dev_get_drvdata(pctldev); | ||
223 | return drvdata->nr_functions; | ||
224 | } | ||
225 | |||
226 | /* return the name of the pin function specified */ | ||
227 | static const char *samsung_pinmux_get_fname(struct pinctrl_dev *pctldev, | ||
228 | unsigned selector) | ||
229 | { | ||
230 | struct samsung_pinctrl_drv_data *drvdata; | ||
231 | |||
232 | drvdata = pinctrl_dev_get_drvdata(pctldev); | ||
233 | return drvdata->pmx_functions[selector].name; | ||
234 | } | ||
235 | |||
236 | /* return the groups associated for the specified function selector */ | ||
237 | static int samsung_pinmux_get_groups(struct pinctrl_dev *pctldev, | ||
238 | unsigned selector, const char * const **groups, | ||
239 | unsigned * const num_groups) | ||
240 | { | ||
241 | struct samsung_pinctrl_drv_data *drvdata; | ||
242 | |||
243 | drvdata = pinctrl_dev_get_drvdata(pctldev); | ||
244 | *groups = drvdata->pmx_functions[selector].groups; | ||
245 | *num_groups = drvdata->pmx_functions[selector].num_groups; | ||
246 | return 0; | ||
247 | } | ||
248 | |||
249 | /* | ||
250 | * given a pin number that is local to a pin controller, find out the pin bank | ||
251 | * and the register base of the pin bank. | ||
252 | */ | ||
253 | static void pin_to_reg_bank(struct gpio_chip *gc, unsigned pin, | ||
254 | void __iomem **reg, u32 *offset, | ||
255 | struct samsung_pin_bank **bank) | ||
256 | { | ||
257 | struct samsung_pinctrl_drv_data *drvdata; | ||
258 | struct samsung_pin_bank *b; | ||
259 | |||
260 | drvdata = dev_get_drvdata(gc->dev); | ||
261 | b = drvdata->ctrl->pin_banks; | ||
262 | |||
263 | while ((pin >= b->pin_base) && | ||
264 | ((b->pin_base + b->nr_pins - 1) < pin)) | ||
265 | b++; | ||
266 | |||
267 | *reg = drvdata->virt_base + b->pctl_offset; | ||
268 | *offset = pin - b->pin_base; | ||
269 | if (bank) | ||
270 | *bank = b; | ||
271 | |||
272 | /* some banks have two config registers in a single bank */ | ||
273 | if (*offset * b->func_width > BITS_PER_LONG) | ||
274 | *reg += 4; | ||
275 | } | ||
276 | |||
277 | /* enable or disable a pinmux function */ | ||
278 | static void samsung_pinmux_setup(struct pinctrl_dev *pctldev, unsigned selector, | ||
279 | unsigned group, bool enable) | ||
280 | { | ||
281 | struct samsung_pinctrl_drv_data *drvdata; | ||
282 | const unsigned int *pins; | ||
283 | struct samsung_pin_bank *bank; | ||
284 | void __iomem *reg; | ||
285 | u32 mask, shift, data, pin_offset, cnt; | ||
286 | |||
287 | drvdata = pinctrl_dev_get_drvdata(pctldev); | ||
288 | pins = drvdata->pin_groups[group].pins; | ||
289 | |||
290 | /* | ||
291 | * for each pin in the pin group selected, program the correspoding pin | ||
292 | * pin function number in the config register. | ||
293 | */ | ||
294 | for (cnt = 0; cnt < drvdata->pin_groups[group].num_pins; cnt++) { | ||
295 | pin_to_reg_bank(drvdata->gc, pins[cnt] - drvdata->ctrl->base, | ||
296 | ®, &pin_offset, &bank); | ||
297 | mask = (1 << bank->func_width) - 1; | ||
298 | shift = pin_offset * bank->func_width; | ||
299 | |||
300 | data = readl(reg); | ||
301 | data &= ~(mask << shift); | ||
302 | if (enable) | ||
303 | data |= drvdata->pin_groups[group].func << shift; | ||
304 | writel(data, reg); | ||
305 | } | ||
306 | } | ||
307 | |||
308 | /* enable a specified pinmux by writing to registers */ | ||
309 | static int samsung_pinmux_enable(struct pinctrl_dev *pctldev, unsigned selector, | ||
310 | unsigned group) | ||
311 | { | ||
312 | samsung_pinmux_setup(pctldev, selector, group, true); | ||
313 | return 0; | ||
314 | } | ||
315 | |||
316 | /* disable a specified pinmux by writing to registers */ | ||
317 | static void samsung_pinmux_disable(struct pinctrl_dev *pctldev, | ||
318 | unsigned selector, unsigned group) | ||
319 | { | ||
320 | samsung_pinmux_setup(pctldev, selector, group, false); | ||
321 | } | ||
322 | |||
323 | /* | ||
324 | * The calls to gpio_direction_output() and gpio_direction_input() | ||
325 | * leads to this function call (via the pinctrl_gpio_direction_{input|output}() | ||
326 | * function called from the gpiolib interface). | ||
327 | */ | ||
328 | static int samsung_pinmux_gpio_set_direction(struct pinctrl_dev *pctldev, | ||
329 | struct pinctrl_gpio_range *range, unsigned offset, bool input) | ||
330 | { | ||
331 | struct samsung_pin_bank *bank; | ||
332 | void __iomem *reg; | ||
333 | u32 data, pin_offset, mask, shift; | ||
334 | |||
335 | pin_to_reg_bank(range->gc, offset, ®, &pin_offset, &bank); | ||
336 | mask = (1 << bank->func_width) - 1; | ||
337 | shift = pin_offset * bank->func_width; | ||
338 | |||
339 | data = readl(reg); | ||
340 | data &= ~(mask << shift); | ||
341 | if (!input) | ||
342 | data |= FUNC_OUTPUT << shift; | ||
343 | writel(data, reg); | ||
344 | return 0; | ||
345 | } | ||
346 | |||
347 | /* list of pinmux callbacks for the pinmux vertical in pinctrl core */ | ||
348 | static struct pinmux_ops samsung_pinmux_ops = { | ||
349 | .get_functions_count = samsung_get_functions_count, | ||
350 | .get_function_name = samsung_pinmux_get_fname, | ||
351 | .get_function_groups = samsung_pinmux_get_groups, | ||
352 | .enable = samsung_pinmux_enable, | ||
353 | .disable = samsung_pinmux_disable, | ||
354 | .gpio_set_direction = samsung_pinmux_gpio_set_direction, | ||
355 | }; | ||
356 | |||
357 | /* set or get the pin config settings for a specified pin */ | ||
358 | static int samsung_pinconf_rw(struct pinctrl_dev *pctldev, unsigned int pin, | ||
359 | unsigned long *config, bool set) | ||
360 | { | ||
361 | struct samsung_pinctrl_drv_data *drvdata; | ||
362 | struct samsung_pin_bank *bank; | ||
363 | void __iomem *reg_base; | ||
364 | enum pincfg_type cfg_type = PINCFG_UNPACK_TYPE(*config); | ||
365 | u32 data, width, pin_offset, mask, shift; | ||
366 | u32 cfg_value, cfg_reg; | ||
367 | |||
368 | drvdata = pinctrl_dev_get_drvdata(pctldev); | ||
369 | pin_to_reg_bank(drvdata->gc, pin - drvdata->ctrl->base, ®_base, | ||
370 | &pin_offset, &bank); | ||
371 | |||
372 | switch (cfg_type) { | ||
373 | case PINCFG_TYPE_PUD: | ||
374 | width = bank->pud_width; | ||
375 | cfg_reg = PUD_REG; | ||
376 | break; | ||
377 | case PINCFG_TYPE_DRV: | ||
378 | width = bank->drv_width; | ||
379 | cfg_reg = DRV_REG; | ||
380 | break; | ||
381 | case PINCFG_TYPE_CON_PDN: | ||
382 | width = bank->conpdn_width; | ||
383 | cfg_reg = CONPDN_REG; | ||
384 | break; | ||
385 | case PINCFG_TYPE_PUD_PDN: | ||
386 | width = bank->pudpdn_width; | ||
387 | cfg_reg = PUDPDN_REG; | ||
388 | break; | ||
389 | default: | ||
390 | WARN_ON(1); | ||
391 | return -EINVAL; | ||
392 | } | ||
393 | |||
394 | mask = (1 << width) - 1; | ||
395 | shift = pin_offset * width; | ||
396 | data = readl(reg_base + cfg_reg); | ||
397 | |||
398 | if (set) { | ||
399 | cfg_value = PINCFG_UNPACK_VALUE(*config); | ||
400 | data &= ~(mask << shift); | ||
401 | data |= (cfg_value << shift); | ||
402 | writel(data, reg_base + cfg_reg); | ||
403 | } else { | ||
404 | data >>= shift; | ||
405 | data &= mask; | ||
406 | *config = PINCFG_PACK(cfg_type, data); | ||
407 | } | ||
408 | return 0; | ||
409 | } | ||
410 | |||
411 | /* set the pin config settings for a specified pin */ | ||
412 | static int samsung_pinconf_set(struct pinctrl_dev *pctldev, unsigned int pin, | ||
413 | unsigned long config) | ||
414 | { | ||
415 | return samsung_pinconf_rw(pctldev, pin, &config, true); | ||
416 | } | ||
417 | |||
418 | /* get the pin config settings for a specified pin */ | ||
419 | static int samsung_pinconf_get(struct pinctrl_dev *pctldev, unsigned int pin, | ||
420 | unsigned long *config) | ||
421 | { | ||
422 | return samsung_pinconf_rw(pctldev, pin, config, false); | ||
423 | } | ||
424 | |||
425 | /* set the pin config settings for a specified pin group */ | ||
426 | static int samsung_pinconf_group_set(struct pinctrl_dev *pctldev, | ||
427 | unsigned group, unsigned long config) | ||
428 | { | ||
429 | struct samsung_pinctrl_drv_data *drvdata; | ||
430 | const unsigned int *pins; | ||
431 | unsigned int cnt; | ||
432 | |||
433 | drvdata = pinctrl_dev_get_drvdata(pctldev); | ||
434 | pins = drvdata->pin_groups[group].pins; | ||
435 | |||
436 | for (cnt = 0; cnt < drvdata->pin_groups[group].num_pins; cnt++) | ||
437 | samsung_pinconf_set(pctldev, pins[cnt], config); | ||
438 | |||
439 | return 0; | ||
440 | } | ||
441 | |||
442 | /* get the pin config settings for a specified pin group */ | ||
443 | static int samsung_pinconf_group_get(struct pinctrl_dev *pctldev, | ||
444 | unsigned int group, unsigned long *config) | ||
445 | { | ||
446 | struct samsung_pinctrl_drv_data *drvdata; | ||
447 | const unsigned int *pins; | ||
448 | |||
449 | drvdata = pinctrl_dev_get_drvdata(pctldev); | ||
450 | pins = drvdata->pin_groups[group].pins; | ||
451 | samsung_pinconf_get(pctldev, pins[0], config); | ||
452 | return 0; | ||
453 | } | ||
454 | |||
455 | /* list of pinconfig callbacks for pinconfig vertical in the pinctrl code */ | ||
456 | static struct pinconf_ops samsung_pinconf_ops = { | ||
457 | .pin_config_get = samsung_pinconf_get, | ||
458 | .pin_config_set = samsung_pinconf_set, | ||
459 | .pin_config_group_get = samsung_pinconf_group_get, | ||
460 | .pin_config_group_set = samsung_pinconf_group_set, | ||
461 | }; | ||
462 | |||
463 | /* gpiolib gpio_set callback function */ | ||
464 | static void samsung_gpio_set(struct gpio_chip *gc, unsigned offset, int value) | ||
465 | { | ||
466 | void __iomem *reg; | ||
467 | u32 pin_offset, data; | ||
468 | |||
469 | pin_to_reg_bank(gc, offset, ®, &pin_offset, NULL); | ||
470 | data = readl(reg + DAT_REG); | ||
471 | data &= ~(1 << pin_offset); | ||
472 | if (value) | ||
473 | data |= 1 << pin_offset; | ||
474 | writel(data, reg + DAT_REG); | ||
475 | } | ||
476 | |||
477 | /* gpiolib gpio_get callback function */ | ||
478 | static int samsung_gpio_get(struct gpio_chip *gc, unsigned offset) | ||
479 | { | ||
480 | void __iomem *reg; | ||
481 | u32 pin_offset, data; | ||
482 | |||
483 | pin_to_reg_bank(gc, offset, ®, &pin_offset, NULL); | ||
484 | data = readl(reg + DAT_REG); | ||
485 | data >>= pin_offset; | ||
486 | data &= 1; | ||
487 | return data; | ||
488 | } | ||
489 | |||
490 | /* | ||
491 | * gpiolib gpio_direction_input callback function. The setting of the pin | ||
492 | * mux function as 'gpio input' will be handled by the pinctrl susbsystem | ||
493 | * interface. | ||
494 | */ | ||
495 | static int samsung_gpio_direction_input(struct gpio_chip *gc, unsigned offset) | ||
496 | { | ||
497 | return pinctrl_gpio_direction_input(gc->base + offset); | ||
498 | } | ||
499 | |||
500 | /* | ||
501 | * gpiolib gpio_direction_output callback function. The setting of the pin | ||
502 | * mux function as 'gpio output' will be handled by the pinctrl susbsystem | ||
503 | * interface. | ||
504 | */ | ||
505 | static int samsung_gpio_direction_output(struct gpio_chip *gc, unsigned offset, | ||
506 | int value) | ||
507 | { | ||
508 | samsung_gpio_set(gc, offset, value); | ||
509 | return pinctrl_gpio_direction_output(gc->base + offset); | ||
510 | } | ||
511 | |||
512 | /* | ||
513 | * Parse the pin names listed in the 'samsung,pins' property and convert it | ||
514 | * into a list of gpio numbers are create a pin group from it. | ||
515 | */ | ||
516 | static int __init samsung_pinctrl_parse_dt_pins(struct platform_device *pdev, | ||
517 | struct device_node *cfg_np, struct pinctrl_desc *pctl, | ||
518 | unsigned int **pin_list, unsigned int *npins) | ||
519 | { | ||
520 | struct device *dev = &pdev->dev; | ||
521 | struct property *prop; | ||
522 | struct pinctrl_pin_desc const *pdesc = pctl->pins; | ||
523 | unsigned int idx = 0, cnt; | ||
524 | const char *pin_name; | ||
525 | |||
526 | *npins = of_property_count_strings(cfg_np, "samsung,pins"); | ||
527 | if (*npins < 0) { | ||
528 | dev_err(dev, "invalid pin list in %s node", cfg_np->name); | ||
529 | return -EINVAL; | ||
530 | } | ||
531 | |||
532 | *pin_list = devm_kzalloc(dev, *npins * sizeof(**pin_list), GFP_KERNEL); | ||
533 | if (!*pin_list) { | ||
534 | dev_err(dev, "failed to allocate memory for pin list\n"); | ||
535 | return -ENOMEM; | ||
536 | } | ||
537 | |||
538 | of_property_for_each_string(cfg_np, "samsung,pins", prop, pin_name) { | ||
539 | for (cnt = 0; cnt < pctl->npins; cnt++) { | ||
540 | if (pdesc[cnt].name) { | ||
541 | if (!strcmp(pin_name, pdesc[cnt].name)) { | ||
542 | (*pin_list)[idx++] = pdesc[cnt].number; | ||
543 | break; | ||
544 | } | ||
545 | } | ||
546 | } | ||
547 | if (cnt == pctl->npins) { | ||
548 | dev_err(dev, "pin %s not valid in %s node\n", | ||
549 | pin_name, cfg_np->name); | ||
550 | devm_kfree(dev, *pin_list); | ||
551 | return -EINVAL; | ||
552 | } | ||
553 | } | ||
554 | |||
555 | return 0; | ||
556 | } | ||
557 | |||
558 | /* | ||
559 | * Parse the information about all the available pin groups and pin functions | ||
560 | * from device node of the pin-controller. A pin group is formed with all | ||
561 | * the pins listed in the "samsung,pins" property. | ||
562 | */ | ||
563 | static int __init samsung_pinctrl_parse_dt(struct platform_device *pdev, | ||
564 | struct samsung_pinctrl_drv_data *drvdata) | ||
565 | { | ||
566 | struct device *dev = &pdev->dev; | ||
567 | struct device_node *dev_np = dev->of_node; | ||
568 | struct device_node *cfg_np; | ||
569 | struct samsung_pin_group *groups, *grp; | ||
570 | struct samsung_pmx_func *functions, *func; | ||
571 | unsigned *pin_list; | ||
572 | unsigned int npins, grp_cnt, func_idx = 0; | ||
573 | char *gname, *fname; | ||
574 | int ret; | ||
575 | |||
576 | grp_cnt = of_get_child_count(dev_np); | ||
577 | if (!grp_cnt) | ||
578 | return -EINVAL; | ||
579 | |||
580 | groups = devm_kzalloc(dev, grp_cnt * sizeof(*groups), GFP_KERNEL); | ||
581 | if (!groups) { | ||
582 | dev_err(dev, "failed allocate memory for ping group list\n"); | ||
583 | return -EINVAL; | ||
584 | } | ||
585 | grp = groups; | ||
586 | |||
587 | functions = devm_kzalloc(dev, grp_cnt * sizeof(*functions), GFP_KERNEL); | ||
588 | if (!functions) { | ||
589 | dev_err(dev, "failed to allocate memory for function list\n"); | ||
590 | return -EINVAL; | ||
591 | } | ||
592 | func = functions; | ||
593 | |||
594 | /* | ||
595 | * Iterate over all the child nodes of the pin controller node | ||
596 | * and create pin groups and pin function lists. | ||
597 | */ | ||
598 | for_each_child_of_node(dev_np, cfg_np) { | ||
599 | u32 function; | ||
600 | if (of_find_property(cfg_np, "interrupt-controller", NULL)) | ||
601 | continue; | ||
602 | |||
603 | ret = samsung_pinctrl_parse_dt_pins(pdev, cfg_np, | ||
604 | &drvdata->pctl, &pin_list, &npins); | ||
605 | if (ret) | ||
606 | return ret; | ||
607 | |||
608 | /* derive pin group name from the node name */ | ||
609 | gname = devm_kzalloc(dev, strlen(cfg_np->name) + GSUFFIX_LEN, | ||
610 | GFP_KERNEL); | ||
611 | if (!gname) { | ||
612 | dev_err(dev, "failed to alloc memory for group name\n"); | ||
613 | return -ENOMEM; | ||
614 | } | ||
615 | sprintf(gname, "%s%s", cfg_np->name, GROUP_SUFFIX); | ||
616 | |||
617 | grp->name = gname; | ||
618 | grp->pins = pin_list; | ||
619 | grp->num_pins = npins; | ||
620 | of_property_read_u32(cfg_np, "samsung,pin-function", &function); | ||
621 | grp->func = function; | ||
622 | grp++; | ||
623 | |||
624 | if (!of_find_property(cfg_np, "samsung,pin-function", NULL)) | ||
625 | continue; | ||
626 | |||
627 | /* derive function name from the node name */ | ||
628 | fname = devm_kzalloc(dev, strlen(cfg_np->name) + FSUFFIX_LEN, | ||
629 | GFP_KERNEL); | ||
630 | if (!fname) { | ||
631 | dev_err(dev, "failed to alloc memory for func name\n"); | ||
632 | return -ENOMEM; | ||
633 | } | ||
634 | sprintf(fname, "%s%s", cfg_np->name, FUNCTION_SUFFIX); | ||
635 | |||
636 | func->name = fname; | ||
637 | func->groups = devm_kzalloc(dev, sizeof(char *), GFP_KERNEL); | ||
638 | if (!func->groups) { | ||
639 | dev_err(dev, "failed to alloc memory for group list " | ||
640 | "in pin function"); | ||
641 | return -ENOMEM; | ||
642 | } | ||
643 | func->groups[0] = gname; | ||
644 | func->num_groups = 1; | ||
645 | func++; | ||
646 | func_idx++; | ||
647 | } | ||
648 | |||
649 | drvdata->pin_groups = groups; | ||
650 | drvdata->nr_groups = grp_cnt; | ||
651 | drvdata->pmx_functions = functions; | ||
652 | drvdata->nr_functions = func_idx; | ||
653 | |||
654 | return 0; | ||
655 | } | ||
656 | |||
657 | /* register the pinctrl interface with the pinctrl subsystem */ | ||
658 | static int __init samsung_pinctrl_register(struct platform_device *pdev, | ||
659 | struct samsung_pinctrl_drv_data *drvdata) | ||
660 | { | ||
661 | struct pinctrl_desc *ctrldesc = &drvdata->pctl; | ||
662 | struct pinctrl_pin_desc *pindesc, *pdesc; | ||
663 | struct samsung_pin_bank *pin_bank; | ||
664 | char *pin_names; | ||
665 | int pin, bank, ret; | ||
666 | |||
667 | ctrldesc->name = "samsung-pinctrl"; | ||
668 | ctrldesc->owner = THIS_MODULE; | ||
669 | ctrldesc->pctlops = &samsung_pctrl_ops; | ||
670 | ctrldesc->pmxops = &samsung_pinmux_ops; | ||
671 | ctrldesc->confops = &samsung_pinconf_ops; | ||
672 | |||
673 | pindesc = devm_kzalloc(&pdev->dev, sizeof(*pindesc) * | ||
674 | drvdata->ctrl->nr_pins, GFP_KERNEL); | ||
675 | if (!pindesc) { | ||
676 | dev_err(&pdev->dev, "mem alloc for pin descriptors failed\n"); | ||
677 | return -ENOMEM; | ||
678 | } | ||
679 | ctrldesc->pins = pindesc; | ||
680 | ctrldesc->npins = drvdata->ctrl->nr_pins; | ||
681 | ctrldesc->npins = drvdata->ctrl->nr_pins; | ||
682 | |||
683 | /* dynamically populate the pin number and pin name for pindesc */ | ||
684 | for (pin = 0, pdesc = pindesc; pin < ctrldesc->npins; pin++, pdesc++) | ||
685 | pdesc->number = pin + drvdata->ctrl->base; | ||
686 | |||
687 | /* | ||
688 | * allocate space for storing the dynamically generated names for all | ||
689 | * the pins which belong to this pin-controller. | ||
690 | */ | ||
691 | pin_names = devm_kzalloc(&pdev->dev, sizeof(char) * PIN_NAME_LENGTH * | ||
692 | drvdata->ctrl->nr_pins, GFP_KERNEL); | ||
693 | if (!pin_names) { | ||
694 | dev_err(&pdev->dev, "mem alloc for pin names failed\n"); | ||
695 | return -ENOMEM; | ||
696 | } | ||
697 | |||
698 | /* for each pin, the name of the pin is pin-bank name + pin number */ | ||
699 | for (bank = 0; bank < drvdata->ctrl->nr_banks; bank++) { | ||
700 | pin_bank = &drvdata->ctrl->pin_banks[bank]; | ||
701 | for (pin = 0; pin < pin_bank->nr_pins; pin++) { | ||
702 | sprintf(pin_names, "%s-%d", pin_bank->name, pin); | ||
703 | pdesc = pindesc + pin_bank->pin_base + pin; | ||
704 | pdesc->name = pin_names; | ||
705 | pin_names += PIN_NAME_LENGTH; | ||
706 | } | ||
707 | } | ||
708 | |||
709 | drvdata->pctl_dev = pinctrl_register(ctrldesc, &pdev->dev, drvdata); | ||
710 | if (!drvdata->pctl_dev) { | ||
711 | dev_err(&pdev->dev, "could not register pinctrl driver\n"); | ||
712 | return -EINVAL; | ||
713 | } | ||
714 | |||
715 | drvdata->grange.name = "samsung-pctrl-gpio-range"; | ||
716 | drvdata->grange.id = 0; | ||
717 | drvdata->grange.base = drvdata->ctrl->base; | ||
718 | drvdata->grange.npins = drvdata->ctrl->nr_pins; | ||
719 | drvdata->grange.gc = drvdata->gc; | ||
720 | pinctrl_add_gpio_range(drvdata->pctl_dev, &drvdata->grange); | ||
721 | |||
722 | ret = samsung_pinctrl_parse_dt(pdev, drvdata); | ||
723 | if (ret) { | ||
724 | pinctrl_unregister(drvdata->pctl_dev); | ||
725 | return ret; | ||
726 | } | ||
727 | |||
728 | return 0; | ||
729 | } | ||
730 | |||
731 | /* register the gpiolib interface with the gpiolib subsystem */ | ||
732 | static int __init samsung_gpiolib_register(struct platform_device *pdev, | ||
733 | struct samsung_pinctrl_drv_data *drvdata) | ||
734 | { | ||
735 | struct gpio_chip *gc; | ||
736 | int ret; | ||
737 | |||
738 | gc = devm_kzalloc(&pdev->dev, sizeof(*gc), GFP_KERNEL); | ||
739 | if (!gc) { | ||
740 | dev_err(&pdev->dev, "mem alloc for gpio_chip failed\n"); | ||
741 | return -ENOMEM; | ||
742 | } | ||
743 | |||
744 | drvdata->gc = gc; | ||
745 | gc->base = drvdata->ctrl->base; | ||
746 | gc->ngpio = drvdata->ctrl->nr_pins; | ||
747 | gc->dev = &pdev->dev; | ||
748 | gc->set = samsung_gpio_set; | ||
749 | gc->get = samsung_gpio_get; | ||
750 | gc->direction_input = samsung_gpio_direction_input; | ||
751 | gc->direction_output = samsung_gpio_direction_output; | ||
752 | gc->label = drvdata->ctrl->label; | ||
753 | gc->owner = THIS_MODULE; | ||
754 | ret = gpiochip_add(gc); | ||
755 | if (ret) { | ||
756 | dev_err(&pdev->dev, "failed to register gpio_chip %s, error " | ||
757 | "code: %d\n", gc->label, ret); | ||
758 | return ret; | ||
759 | } | ||
760 | |||
761 | return 0; | ||
762 | } | ||
763 | |||
764 | /* unregister the gpiolib interface with the gpiolib subsystem */ | ||
765 | static int __init samsung_gpiolib_unregister(struct platform_device *pdev, | ||
766 | struct samsung_pinctrl_drv_data *drvdata) | ||
767 | { | ||
768 | int ret = gpiochip_remove(drvdata->gc); | ||
769 | if (ret) { | ||
770 | dev_err(&pdev->dev, "gpio chip remove failed\n"); | ||
771 | return ret; | ||
772 | } | ||
773 | return 0; | ||
774 | } | ||
775 | |||
776 | static const struct of_device_id samsung_pinctrl_dt_match[]; | ||
777 | |||
778 | /* retrieve the soc specific data */ | ||
779 | static inline struct samsung_pin_ctrl *samsung_pinctrl_get_soc_data( | ||
780 | struct platform_device *pdev) | ||
781 | { | ||
782 | int id; | ||
783 | const struct of_device_id *match; | ||
784 | const struct device_node *node = pdev->dev.of_node; | ||
785 | |||
786 | id = of_alias_get_id(pdev->dev.of_node, "pinctrl"); | ||
787 | if (id < 0) { | ||
788 | dev_err(&pdev->dev, "failed to get alias id\n"); | ||
789 | return NULL; | ||
790 | } | ||
791 | match = of_match_node(samsung_pinctrl_dt_match, node); | ||
792 | return (struct samsung_pin_ctrl *)match->data + id; | ||
793 | } | ||
794 | |||
795 | static int __devinit samsung_pinctrl_probe(struct platform_device *pdev) | ||
796 | { | ||
797 | struct samsung_pinctrl_drv_data *drvdata; | ||
798 | struct device *dev = &pdev->dev; | ||
799 | struct samsung_pin_ctrl *ctrl; | ||
800 | struct resource *res; | ||
801 | int ret; | ||
802 | |||
803 | if (!dev->of_node) { | ||
804 | dev_err(dev, "device tree node not found\n"); | ||
805 | return -ENODEV; | ||
806 | } | ||
807 | |||
808 | ctrl = samsung_pinctrl_get_soc_data(pdev); | ||
809 | if (!ctrl) { | ||
810 | dev_err(&pdev->dev, "driver data not available\n"); | ||
811 | return -EINVAL; | ||
812 | } | ||
813 | |||
814 | drvdata = devm_kzalloc(dev, sizeof(*drvdata), GFP_KERNEL); | ||
815 | if (!drvdata) { | ||
816 | dev_err(dev, "failed to allocate memory for driver's " | ||
817 | "private data\n"); | ||
818 | return -ENOMEM; | ||
819 | } | ||
820 | drvdata->ctrl = ctrl; | ||
821 | drvdata->dev = dev; | ||
822 | |||
823 | res = platform_get_resource(pdev, IORESOURCE_MEM, 0); | ||
824 | if (!res) { | ||
825 | dev_err(dev, "cannot find IO resource\n"); | ||
826 | return -ENOENT; | ||
827 | } | ||
828 | |||
829 | drvdata->virt_base = devm_request_and_ioremap(&pdev->dev, res); | ||
830 | if (!drvdata->virt_base) { | ||
831 | dev_err(dev, "ioremap failed\n"); | ||
832 | return -ENODEV; | ||
833 | } | ||
834 | |||
835 | res = platform_get_resource(pdev, IORESOURCE_IRQ, 0); | ||
836 | if (res) | ||
837 | drvdata->irq = res->start; | ||
838 | |||
839 | ret = samsung_gpiolib_register(pdev, drvdata); | ||
840 | if (ret) | ||
841 | return ret; | ||
842 | |||
843 | ret = samsung_pinctrl_register(pdev, drvdata); | ||
844 | if (ret) { | ||
845 | samsung_gpiolib_unregister(pdev, drvdata); | ||
846 | return ret; | ||
847 | } | ||
848 | |||
849 | if (ctrl->eint_gpio_init) | ||
850 | ctrl->eint_gpio_init(drvdata); | ||
851 | if (ctrl->eint_wkup_init) | ||
852 | ctrl->eint_wkup_init(drvdata); | ||
853 | |||
854 | platform_set_drvdata(pdev, drvdata); | ||
855 | return 0; | ||
856 | } | ||
857 | |||
858 | static const struct of_device_id samsung_pinctrl_dt_match[] = { | ||
859 | { .compatible = "samsung,pinctrl-exynos4210", | ||
860 | .data = (void *)exynos4210_pin_ctrl }, | ||
861 | {}, | ||
862 | }; | ||
863 | MODULE_DEVICE_TABLE(of, samsung_pinctrl_dt_match); | ||
864 | |||
865 | static struct platform_driver samsung_pinctrl_driver = { | ||
866 | .probe = samsung_pinctrl_probe, | ||
867 | .driver = { | ||
868 | .name = "samsung-pinctrl", | ||
869 | .owner = THIS_MODULE, | ||
870 | .of_match_table = of_match_ptr(samsung_pinctrl_dt_match), | ||
871 | }, | ||
872 | }; | ||
873 | |||
874 | static int __init samsung_pinctrl_drv_register(void) | ||
875 | { | ||
876 | return platform_driver_register(&samsung_pinctrl_driver); | ||
877 | } | ||
878 | postcore_initcall(samsung_pinctrl_drv_register); | ||
879 | |||
880 | static void __exit samsung_pinctrl_drv_unregister(void) | ||
881 | { | ||
882 | platform_driver_unregister(&samsung_pinctrl_driver); | ||
883 | } | ||
884 | module_exit(samsung_pinctrl_drv_unregister); | ||
885 | |||
886 | MODULE_AUTHOR("Thomas Abraham <thomas.ab@samsung.com>"); | ||
887 | MODULE_DESCRIPTION("Samsung pinctrl driver"); | ||
888 | MODULE_LICENSE("GPL v2"); | ||
diff --git a/drivers/pinctrl/pinctrl-samsung.h b/drivers/pinctrl/pinctrl-samsung.h new file mode 100644 index 000000000000..b8956934cda6 --- /dev/null +++ b/drivers/pinctrl/pinctrl-samsung.h | |||
@@ -0,0 +1,239 @@ | |||
1 | /* | ||
2 | * pin-controller/pin-mux/pin-config/gpio-driver for Samsung's SoC's. | ||
3 | * | ||
4 | * Copyright (c) 2012 Samsung Electronics Co., Ltd. | ||
5 | * http://www.samsung.com | ||
6 | * Copyright (c) 2012 Linaro Ltd | ||
7 | * http://www.linaro.org | ||
8 | * | ||
9 | * Author: Thomas Abraham <thomas.ab@samsung.com> | ||
10 | * | ||
11 | * This program is free software; you can redistribute it and/or modify | ||
12 | * it under the terms of the GNU General Public License as published by | ||
13 | * the Free Software Foundation; either version 2 of the License, or | ||
14 | * (at your option) any later version. | ||
15 | */ | ||
16 | |||
17 | #ifndef __PINCTRL_SAMSUNG_H | ||
18 | #define __PINCTRL_SAMSUNG_H | ||
19 | |||
20 | #include <linux/pinctrl/pinctrl.h> | ||
21 | #include <linux/pinctrl/pinmux.h> | ||
22 | #include <linux/pinctrl/pinconf.h> | ||
23 | #include <linux/pinctrl/consumer.h> | ||
24 | #include <linux/pinctrl/machine.h> | ||
25 | |||
26 | /* register offsets within a pin bank */ | ||
27 | #define DAT_REG 0x4 | ||
28 | #define PUD_REG 0x8 | ||
29 | #define DRV_REG 0xC | ||
30 | #define CONPDN_REG 0x10 | ||
31 | #define PUDPDN_REG 0x14 | ||
32 | |||
33 | /* pinmux function number for pin as gpio output line */ | ||
34 | #define FUNC_OUTPUT 0x1 | ||
35 | |||
36 | /** | ||
37 | * enum pincfg_type - possible pin configuration types supported. | ||
38 | * @PINCFG_TYPE_PUD: Pull up/down configuration. | ||
39 | * @PINCFG_TYPE_DRV: Drive strength configuration. | ||
40 | * @PINCFG_TYPE_CON_PDN: Pin function in power down mode. | ||
41 | * @PINCFG_TYPE_PUD_PDN: Pull up/down configuration in power down mode. | ||
42 | */ | ||
43 | enum pincfg_type { | ||
44 | PINCFG_TYPE_PUD, | ||
45 | PINCFG_TYPE_DRV, | ||
46 | PINCFG_TYPE_CON_PDN, | ||
47 | PINCFG_TYPE_PUD_PDN, | ||
48 | }; | ||
49 | |||
50 | /* | ||
51 | * pin configuration (pull up/down and drive strength) type and its value are | ||
52 | * packed together into a 16-bits. The upper 8-bits represent the configuration | ||
53 | * type and the lower 8-bits hold the value of the configuration type. | ||
54 | */ | ||
55 | #define PINCFG_TYPE_MASK 0xFF | ||
56 | #define PINCFG_VALUE_SHIFT 8 | ||
57 | #define PINCFG_VALUE_MASK (0xFF << PINCFG_VALUE_SHIFT) | ||
58 | #define PINCFG_PACK(type, value) (((value) << PINCFG_VALUE_SHIFT) | type) | ||
59 | #define PINCFG_UNPACK_TYPE(cfg) ((cfg) & PINCFG_TYPE_MASK) | ||
60 | #define PINCFG_UNPACK_VALUE(cfg) (((cfg) & PINCFG_VALUE_MASK) >> \ | ||
61 | PINCFG_VALUE_SHIFT) | ||
62 | /** | ||
63 | * enum eint_type - possible external interrupt types. | ||
64 | * @EINT_TYPE_NONE: bank does not support external interrupts | ||
65 | * @EINT_TYPE_GPIO: bank supportes external gpio interrupts | ||
66 | * @EINT_TYPE_WKUP: bank supportes external wakeup interrupts | ||
67 | * | ||
68 | * Samsung GPIO controller groups all the available pins into banks. The pins | ||
69 | * in a pin bank can support external gpio interrupts or external wakeup | ||
70 | * interrupts or no interrupts at all. From a software perspective, the only | ||
71 | * difference between external gpio and external wakeup interrupts is that | ||
72 | * the wakeup interrupts can additionally wakeup the system if it is in | ||
73 | * suspended state. | ||
74 | */ | ||
75 | enum eint_type { | ||
76 | EINT_TYPE_NONE, | ||
77 | EINT_TYPE_GPIO, | ||
78 | EINT_TYPE_WKUP, | ||
79 | }; | ||
80 | |||
81 | /* maximum length of a pin in pin descriptor (example: "gpa0-0") */ | ||
82 | #define PIN_NAME_LENGTH 10 | ||
83 | |||
84 | #define PIN_GROUP(n, p, f) \ | ||
85 | { \ | ||
86 | .name = n, \ | ||
87 | .pins = p, \ | ||
88 | .num_pins = ARRAY_SIZE(p), \ | ||
89 | .func = f \ | ||
90 | } | ||
91 | |||
92 | #define PMX_FUNC(n, g) \ | ||
93 | { \ | ||
94 | .name = n, \ | ||
95 | .groups = g, \ | ||
96 | .num_groups = ARRAY_SIZE(g), \ | ||
97 | } | ||
98 | |||
99 | struct samsung_pinctrl_drv_data; | ||
100 | |||
101 | /** | ||
102 | * struct samsung_pin_bank: represent a controller pin-bank. | ||
103 | * @reg_offset: starting offset of the pin-bank registers. | ||
104 | * @pin_base: starting pin number of the bank. | ||
105 | * @nr_pins: number of pins included in this bank. | ||
106 | * @func_width: width of the function selector bit field. | ||
107 | * @pud_width: width of the pin pull up/down selector bit field. | ||
108 | * @drv_width: width of the pin driver strength selector bit field. | ||
109 | * @conpdn_width: width of the sleep mode function selector bin field. | ||
110 | * @pudpdn_width: width of the sleep mode pull up/down selector bit field. | ||
111 | * @eint_type: type of the external interrupt supported by the bank. | ||
112 | * @irq_base: starting controller local irq number of the bank. | ||
113 | * @name: name to be prefixed for each pin in this pin bank. | ||
114 | */ | ||
115 | struct samsung_pin_bank { | ||
116 | u32 pctl_offset; | ||
117 | u32 pin_base; | ||
118 | u8 nr_pins; | ||
119 | u8 func_width; | ||
120 | u8 pud_width; | ||
121 | u8 drv_width; | ||
122 | u8 conpdn_width; | ||
123 | u8 pudpdn_width; | ||
124 | enum eint_type eint_type; | ||
125 | u32 irq_base; | ||
126 | char *name; | ||
127 | }; | ||
128 | |||
129 | /** | ||
130 | * struct samsung_pin_ctrl: represent a pin controller. | ||
131 | * @pin_banks: list of pin banks included in this controller. | ||
132 | * @nr_banks: number of pin banks. | ||
133 | * @base: starting system wide pin number. | ||
134 | * @nr_pins: number of pins supported by the controller. | ||
135 | * @nr_gint: number of external gpio interrupts supported. | ||
136 | * @nr_wint: number of external wakeup interrupts supported. | ||
137 | * @geint_con: offset of the ext-gpio controller registers. | ||
138 | * @geint_mask: offset of the ext-gpio interrupt mask registers. | ||
139 | * @geint_pend: offset of the ext-gpio interrupt pending registers. | ||
140 | * @weint_con: offset of the ext-wakeup controller registers. | ||
141 | * @weint_mask: offset of the ext-wakeup interrupt mask registers. | ||
142 | * @weint_pend: offset of the ext-wakeup interrupt pending registers. | ||
143 | * @svc: offset of the interrupt service register. | ||
144 | * @eint_gpio_init: platform specific callback to setup the external gpio | ||
145 | * interrupts for the controller. | ||
146 | * @eint_wkup_init: platform specific callback to setup the external wakeup | ||
147 | * interrupts for the controller. | ||
148 | * @label: for debug information. | ||
149 | */ | ||
150 | struct samsung_pin_ctrl { | ||
151 | struct samsung_pin_bank *pin_banks; | ||
152 | u32 nr_banks; | ||
153 | |||
154 | u32 base; | ||
155 | u32 nr_pins; | ||
156 | u32 nr_gint; | ||
157 | u32 nr_wint; | ||
158 | |||
159 | u32 geint_con; | ||
160 | u32 geint_mask; | ||
161 | u32 geint_pend; | ||
162 | |||
163 | u32 weint_con; | ||
164 | u32 weint_mask; | ||
165 | u32 weint_pend; | ||
166 | |||
167 | u32 svc; | ||
168 | |||
169 | int (*eint_gpio_init)(struct samsung_pinctrl_drv_data *); | ||
170 | int (*eint_wkup_init)(struct samsung_pinctrl_drv_data *); | ||
171 | char *label; | ||
172 | }; | ||
173 | |||
174 | /** | ||
175 | * struct samsung_pinctrl_drv_data: wrapper for holding driver data together. | ||
176 | * @virt_base: register base address of the controller. | ||
177 | * @dev: device instance representing the controller. | ||
178 | * @irq: interrpt number used by the controller to notify gpio interrupts. | ||
179 | * @ctrl: pin controller instance managed by the driver. | ||
180 | * @pctl: pin controller descriptor registered with the pinctrl subsystem. | ||
181 | * @pctl_dev: cookie representing pinctrl device instance. | ||
182 | * @pin_groups: list of pin groups available to the driver. | ||
183 | * @nr_groups: number of such pin groups. | ||
184 | * @pmx_functions: list of pin functions available to the driver. | ||
185 | * @nr_function: number of such pin functions. | ||
186 | * @gc: gpio_chip instance registered with gpiolib. | ||
187 | * @grange: linux gpio pin range supported by this controller. | ||
188 | */ | ||
189 | struct samsung_pinctrl_drv_data { | ||
190 | void __iomem *virt_base; | ||
191 | struct device *dev; | ||
192 | int irq; | ||
193 | |||
194 | struct samsung_pin_ctrl *ctrl; | ||
195 | struct pinctrl_desc pctl; | ||
196 | struct pinctrl_dev *pctl_dev; | ||
197 | |||
198 | const struct samsung_pin_group *pin_groups; | ||
199 | unsigned int nr_groups; | ||
200 | const struct samsung_pmx_func *pmx_functions; | ||
201 | unsigned int nr_functions; | ||
202 | |||
203 | struct irq_domain *gpio_irqd; | ||
204 | struct irq_domain *wkup_irqd; | ||
205 | |||
206 | struct gpio_chip *gc; | ||
207 | struct pinctrl_gpio_range grange; | ||
208 | }; | ||
209 | |||
210 | /** | ||
211 | * struct samsung_pin_group: represent group of pins of a pinmux function. | ||
212 | * @name: name of the pin group, used to lookup the group. | ||
213 | * @pins: the pins included in this group. | ||
214 | * @num_pins: number of pins included in this group. | ||
215 | * @func: the function number to be programmed when selected. | ||
216 | */ | ||
217 | struct samsung_pin_group { | ||
218 | const char *name; | ||
219 | const unsigned int *pins; | ||
220 | u8 num_pins; | ||
221 | u8 func; | ||
222 | }; | ||
223 | |||
224 | /** | ||
225 | * struct samsung_pmx_func: represent a pin function. | ||
226 | * @name: name of the pin function, used to lookup the function. | ||
227 | * @groups: one or more names of pin groups that provide this function. | ||
228 | * @num_groups: number of groups included in @groups. | ||
229 | */ | ||
230 | struct samsung_pmx_func { | ||
231 | const char *name; | ||
232 | const char **groups; | ||
233 | u8 num_groups; | ||
234 | }; | ||
235 | |||
236 | /* list of all exported SoC specific data */ | ||
237 | extern struct samsung_pin_ctrl exynos4210_pin_ctrl[]; | ||
238 | |||
239 | #endif /* __PINCTRL_SAMSUNG_H */ | ||