diff options
author | Sebastian Hesselbarth <sebastian.hesselbarth@gmail.com> | 2012-09-13 11:41:43 -0400 |
---|---|---|
committer | Jason Cooper <jason@lakedaemon.net> | 2012-09-22 10:50:14 -0400 |
commit | 7e8d941567c99a03390154a7bb116d1b03db82b3 (patch) | |
tree | 069e6d14c5af258c02cef3658d0be38bc8de2f6d | |
parent | 5b40baee4a39d96d4d6a48a2b2383982912c429b (diff) |
pinctrl: mvebu: pinctrl driver core
This patch adds a pinctrl driver core for Marvell SoCs plus DT
binding documentation. This core driver will be used by SoC family
specific drivers, i.e. Armada XP, Armada 370, Dove, Kirkwood, aso.
Signed-off-by: Sebastian Hesselbarth <sebastian.hesselbarth@gmail.com>
Signed-off-by: Thomas Petazzoni <thomas.petazzoni@free-electrons.com>
Acked-by: Thomas Petazzoni <thomas.petazzoni@free-electrons.com>
Tested-by: Thomas Petazzoni <thomas.petazzoni@free-electrons.com>
Reviewed-by: Stephen Warren <swarren@wwwdotorg.org>
Signed-off-by: Jason Cooper <jason@lakedaemon.net>
Conflicts:
arch/arm/Kconfig
-rw-r--r-- | Documentation/devicetree/bindings/pinctrl/marvell,mvebu-pinctrl.txt | 46 | ||||
-rw-r--r-- | arch/arm/Kconfig | 1 | ||||
-rw-r--r-- | drivers/pinctrl/Kconfig | 6 | ||||
-rw-r--r-- | drivers/pinctrl/Makefile | 1 | ||||
-rw-r--r-- | drivers/pinctrl/pinctrl-mvebu.c | 754 | ||||
-rw-r--r-- | drivers/pinctrl/pinctrl-mvebu.h | 192 |
6 files changed, 1000 insertions, 0 deletions
diff --git a/Documentation/devicetree/bindings/pinctrl/marvell,mvebu-pinctrl.txt b/Documentation/devicetree/bindings/pinctrl/marvell,mvebu-pinctrl.txt new file mode 100644 index 000000000000..0a26c3aa4e6d --- /dev/null +++ b/Documentation/devicetree/bindings/pinctrl/marvell,mvebu-pinctrl.txt | |||
@@ -0,0 +1,46 @@ | |||
1 | * Marvell SoC pinctrl core driver for mpp | ||
2 | |||
3 | The pinctrl driver enables Marvell SoCs to configure the multi-purpose pins | ||
4 | (mpp) to a specific function. For each SoC family there is a SoC specific | ||
5 | driver using this core driver. | ||
6 | |||
7 | Please refer to pinctrl-bindings.txt in this directory for details of the | ||
8 | common pinctrl bindings used by client devices, including the meaning of the | ||
9 | phrase "pin configuration node". | ||
10 | |||
11 | A Marvell SoC pin configuration node is a node of a group of pins which can | ||
12 | be used for a specific device or function. Each node requires one or more | ||
13 | mpp pins or group of pins and a mpp function common to all pins. | ||
14 | |||
15 | Required properties for pinctrl driver: | ||
16 | - compatible: "marvell,<soc>-pinctrl" | ||
17 | Please refer to each marvell,<soc>-pinctrl.txt binding doc for supported SoCs. | ||
18 | |||
19 | Required properties for pin configuration node: | ||
20 | - marvell,pins: string array of mpp pins or group of pins to be muxed. | ||
21 | - marvell,function: string representing a function to mux to for all | ||
22 | marvell,pins given in this pin configuration node. The function has to be | ||
23 | common for all marvell,pins. Please refer to marvell,<soc>-pinctrl.txt for | ||
24 | valid pin/pin group names and available function names for each SoC. | ||
25 | |||
26 | Examples: | ||
27 | |||
28 | uart1: serial@12100 { | ||
29 | compatible = "ns16550a"; | ||
30 | reg = <0x12100 0x100>; | ||
31 | reg-shift = <2>; | ||
32 | interrupts = <7>; | ||
33 | |||
34 | pinctrl-0 = <&pmx_uart1_sw>; | ||
35 | pinctrl-names = "default"; | ||
36 | }; | ||
37 | |||
38 | pinctrl: pinctrl@d0200 { | ||
39 | compatible = "marvell,dove-pinctrl"; | ||
40 | reg = <0xd0200 0x20>; | ||
41 | |||
42 | pmx_uart1_sw: pmx-uart1-sw { | ||
43 | marvell,pins = "mpp_uart1"; | ||
44 | marvell,function = "uart1"; | ||
45 | }; | ||
46 | }; | ||
diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig index a4eab57bee2f..4b307249dcb3 100644 --- a/arch/arm/Kconfig +++ b/arch/arm/Kconfig | |||
@@ -568,6 +568,7 @@ config ARCH_MVEBU | |||
568 | select IRQ_DOMAIN | 568 | select IRQ_DOMAIN |
569 | select COMMON_CLK | 569 | select COMMON_CLK |
570 | select PLAT_ORION | 570 | select PLAT_ORION |
571 | select PINCTRL | ||
571 | help | 572 | help |
572 | Support for the Marvell SoC Family with device tree support | 573 | Support for the Marvell SoC Family with device tree support |
573 | 574 | ||
diff --git a/drivers/pinctrl/Kconfig b/drivers/pinctrl/Kconfig index 54e3588bef62..20bfdc35936b 100644 --- a/drivers/pinctrl/Kconfig +++ b/drivers/pinctrl/Kconfig | |||
@@ -145,6 +145,12 @@ 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_MVEBU | ||
149 | bool | ||
150 | depends on ARCH_MVEBU | ||
151 | select PINMUX | ||
152 | select PINCONF | ||
153 | |||
148 | source "drivers/pinctrl/spear/Kconfig" | 154 | source "drivers/pinctrl/spear/Kconfig" |
149 | 155 | ||
150 | endmenu | 156 | endmenu |
diff --git a/drivers/pinctrl/Makefile b/drivers/pinctrl/Makefile index f40b1f81ff2c..007ed32c152e 100644 --- a/drivers/pinctrl/Makefile +++ b/drivers/pinctrl/Makefile | |||
@@ -29,5 +29,6 @@ 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_MVEBU) += pinctrl-mvebu.o | ||
32 | 33 | ||
33 | obj-$(CONFIG_PLAT_SPEAR) += spear/ | 34 | obj-$(CONFIG_PLAT_SPEAR) += spear/ |
diff --git a/drivers/pinctrl/pinctrl-mvebu.c b/drivers/pinctrl/pinctrl-mvebu.c new file mode 100644 index 000000000000..8e6266c6249a --- /dev/null +++ b/drivers/pinctrl/pinctrl-mvebu.c | |||
@@ -0,0 +1,754 @@ | |||
1 | /* | ||
2 | * Marvell MVEBU pinctrl core driver | ||
3 | * | ||
4 | * Authors: Sebastian Hesselbarth <sebastian.hesselbarth@gmail.com> | ||
5 | * Thomas Petazzoni <thomas.petazzoni@free-electrons.com> | ||
6 | * | ||
7 | * This program is free software; you can redistribute it and/or modify | ||
8 | * it under the terms of the GNU General Public License as published by | ||
9 | * the Free Software Foundation; either version 2 of the License, or | ||
10 | * (at your option) any later version. | ||
11 | */ | ||
12 | |||
13 | #include <linux/platform_device.h> | ||
14 | #include <linux/module.h> | ||
15 | #include <linux/slab.h> | ||
16 | #include <linux/io.h> | ||
17 | #include <linux/of.h> | ||
18 | #include <linux/of_address.h> | ||
19 | #include <linux/of_platform.h> | ||
20 | #include <linux/err.h> | ||
21 | #include <linux/gpio.h> | ||
22 | #include <linux/pinctrl/machine.h> | ||
23 | #include <linux/pinctrl/pinconf.h> | ||
24 | #include <linux/pinctrl/pinctrl.h> | ||
25 | #include <linux/pinctrl/pinmux.h> | ||
26 | |||
27 | #include "core.h" | ||
28 | #include "pinctrl-mvebu.h" | ||
29 | |||
30 | #define MPPS_PER_REG 8 | ||
31 | #define MPP_BITS 4 | ||
32 | #define MPP_MASK 0xf | ||
33 | |||
34 | struct mvebu_pinctrl_function { | ||
35 | const char *name; | ||
36 | const char **groups; | ||
37 | unsigned num_groups; | ||
38 | }; | ||
39 | |||
40 | struct mvebu_pinctrl_group { | ||
41 | const char *name; | ||
42 | struct mvebu_mpp_ctrl *ctrl; | ||
43 | struct mvebu_mpp_ctrl_setting *settings; | ||
44 | unsigned num_settings; | ||
45 | unsigned gid; | ||
46 | unsigned *pins; | ||
47 | unsigned npins; | ||
48 | }; | ||
49 | |||
50 | struct mvebu_pinctrl { | ||
51 | struct device *dev; | ||
52 | struct pinctrl_dev *pctldev; | ||
53 | struct pinctrl_desc desc; | ||
54 | void __iomem *base; | ||
55 | struct mvebu_pinctrl_group *groups; | ||
56 | unsigned num_groups; | ||
57 | struct mvebu_pinctrl_function *functions; | ||
58 | unsigned num_functions; | ||
59 | u8 variant; | ||
60 | }; | ||
61 | |||
62 | static struct mvebu_pinctrl_group *mvebu_pinctrl_find_group_by_pid( | ||
63 | struct mvebu_pinctrl *pctl, unsigned pid) | ||
64 | { | ||
65 | unsigned n; | ||
66 | for (n = 0; n < pctl->num_groups; n++) { | ||
67 | if (pid >= pctl->groups[n].pins[0] && | ||
68 | pid < pctl->groups[n].pins[0] + | ||
69 | pctl->groups[n].npins) | ||
70 | return &pctl->groups[n]; | ||
71 | } | ||
72 | return NULL; | ||
73 | } | ||
74 | |||
75 | static struct mvebu_pinctrl_group *mvebu_pinctrl_find_group_by_name( | ||
76 | struct mvebu_pinctrl *pctl, const char *name) | ||
77 | { | ||
78 | unsigned n; | ||
79 | for (n = 0; n < pctl->num_groups; n++) { | ||
80 | if (strcmp(name, pctl->groups[n].name) == 0) | ||
81 | return &pctl->groups[n]; | ||
82 | } | ||
83 | return NULL; | ||
84 | } | ||
85 | |||
86 | static struct mvebu_mpp_ctrl_setting *mvebu_pinctrl_find_setting_by_val( | ||
87 | struct mvebu_pinctrl *pctl, struct mvebu_pinctrl_group *grp, | ||
88 | unsigned long config) | ||
89 | { | ||
90 | unsigned n; | ||
91 | for (n = 0; n < grp->num_settings; n++) { | ||
92 | if (config == grp->settings[n].val) { | ||
93 | if (!pctl->variant || (pctl->variant & | ||
94 | grp->settings[n].variant)) | ||
95 | return &grp->settings[n]; | ||
96 | } | ||
97 | } | ||
98 | return NULL; | ||
99 | } | ||
100 | |||
101 | static struct mvebu_mpp_ctrl_setting *mvebu_pinctrl_find_setting_by_name( | ||
102 | struct mvebu_pinctrl *pctl, struct mvebu_pinctrl_group *grp, | ||
103 | const char *name) | ||
104 | { | ||
105 | unsigned n; | ||
106 | for (n = 0; n < grp->num_settings; n++) { | ||
107 | if (strcmp(name, grp->settings[n].name) == 0) { | ||
108 | if (!pctl->variant || (pctl->variant & | ||
109 | grp->settings[n].variant)) | ||
110 | return &grp->settings[n]; | ||
111 | } | ||
112 | } | ||
113 | return NULL; | ||
114 | } | ||
115 | |||
116 | static struct mvebu_mpp_ctrl_setting *mvebu_pinctrl_find_gpio_setting( | ||
117 | struct mvebu_pinctrl *pctl, struct mvebu_pinctrl_group *grp) | ||
118 | { | ||
119 | unsigned n; | ||
120 | for (n = 0; n < grp->num_settings; n++) { | ||
121 | if (grp->settings[n].flags & | ||
122 | (MVEBU_SETTING_GPO | MVEBU_SETTING_GPI)) { | ||
123 | if (!pctl->variant || (pctl->variant & | ||
124 | grp->settings[n].variant)) | ||
125 | return &grp->settings[n]; | ||
126 | } | ||
127 | } | ||
128 | return NULL; | ||
129 | } | ||
130 | |||
131 | static struct mvebu_pinctrl_function *mvebu_pinctrl_find_function_by_name( | ||
132 | struct mvebu_pinctrl *pctl, const char *name) | ||
133 | { | ||
134 | unsigned n; | ||
135 | for (n = 0; n < pctl->num_functions; n++) { | ||
136 | if (strcmp(name, pctl->functions[n].name) == 0) | ||
137 | return &pctl->functions[n]; | ||
138 | } | ||
139 | return NULL; | ||
140 | } | ||
141 | |||
142 | /* | ||
143 | * Common mpp pin configuration registers on MVEBU are | ||
144 | * registers of eight 4-bit values for each mpp setting. | ||
145 | * Register offset and bit mask are calculated accordingly below. | ||
146 | */ | ||
147 | static int mvebu_common_mpp_get(struct mvebu_pinctrl *pctl, | ||
148 | struct mvebu_pinctrl_group *grp, | ||
149 | unsigned long *config) | ||
150 | { | ||
151 | unsigned pin = grp->gid; | ||
152 | unsigned off = (pin / MPPS_PER_REG) * MPP_BITS; | ||
153 | unsigned shift = (pin % MPPS_PER_REG) * MPP_BITS; | ||
154 | |||
155 | *config = readl(pctl->base + off); | ||
156 | *config >>= shift; | ||
157 | *config &= MPP_MASK; | ||
158 | |||
159 | return 0; | ||
160 | } | ||
161 | |||
162 | static int mvebu_common_mpp_set(struct mvebu_pinctrl *pctl, | ||
163 | struct mvebu_pinctrl_group *grp, | ||
164 | unsigned long config) | ||
165 | { | ||
166 | unsigned pin = grp->gid; | ||
167 | unsigned off = (pin / MPPS_PER_REG) * MPP_BITS; | ||
168 | unsigned shift = (pin % MPPS_PER_REG) * MPP_BITS; | ||
169 | unsigned long reg; | ||
170 | |||
171 | reg = readl(pctl->base + off); | ||
172 | reg &= ~(MPP_MASK << shift); | ||
173 | reg |= (config << shift); | ||
174 | writel(reg, pctl->base + off); | ||
175 | |||
176 | return 0; | ||
177 | } | ||
178 | |||
179 | static int mvebu_pinconf_group_get(struct pinctrl_dev *pctldev, | ||
180 | unsigned gid, unsigned long *config) | ||
181 | { | ||
182 | struct mvebu_pinctrl *pctl = pinctrl_dev_get_drvdata(pctldev); | ||
183 | struct mvebu_pinctrl_group *grp = &pctl->groups[gid]; | ||
184 | |||
185 | if (!grp->ctrl) | ||
186 | return -EINVAL; | ||
187 | |||
188 | if (grp->ctrl->mpp_get) | ||
189 | return grp->ctrl->mpp_get(grp->ctrl, config); | ||
190 | |||
191 | return mvebu_common_mpp_get(pctl, grp, config); | ||
192 | } | ||
193 | |||
194 | static int mvebu_pinconf_group_set(struct pinctrl_dev *pctldev, | ||
195 | unsigned gid, unsigned long config) | ||
196 | { | ||
197 | struct mvebu_pinctrl *pctl = pinctrl_dev_get_drvdata(pctldev); | ||
198 | struct mvebu_pinctrl_group *grp = &pctl->groups[gid]; | ||
199 | |||
200 | if (!grp->ctrl) | ||
201 | return -EINVAL; | ||
202 | |||
203 | if (grp->ctrl->mpp_set) | ||
204 | return grp->ctrl->mpp_set(grp->ctrl, config); | ||
205 | |||
206 | return mvebu_common_mpp_set(pctl, grp, config); | ||
207 | } | ||
208 | |||
209 | static void mvebu_pinconf_group_dbg_show(struct pinctrl_dev *pctldev, | ||
210 | struct seq_file *s, unsigned gid) | ||
211 | { | ||
212 | struct mvebu_pinctrl *pctl = pinctrl_dev_get_drvdata(pctldev); | ||
213 | struct mvebu_pinctrl_group *grp = &pctl->groups[gid]; | ||
214 | struct mvebu_mpp_ctrl_setting *curr; | ||
215 | unsigned long config; | ||
216 | unsigned n; | ||
217 | |||
218 | if (mvebu_pinconf_group_get(pctldev, gid, &config)) | ||
219 | return; | ||
220 | |||
221 | curr = mvebu_pinctrl_find_setting_by_val(pctl, grp, config); | ||
222 | |||
223 | if (curr) { | ||
224 | seq_printf(s, "current: %s", curr->name); | ||
225 | if (curr->subname) | ||
226 | seq_printf(s, "(%s)", curr->subname); | ||
227 | if (curr->flags & (MVEBU_SETTING_GPO | MVEBU_SETTING_GPI)) { | ||
228 | seq_printf(s, "("); | ||
229 | if (curr->flags & MVEBU_SETTING_GPI) | ||
230 | seq_printf(s, "i"); | ||
231 | if (curr->flags & MVEBU_SETTING_GPO) | ||
232 | seq_printf(s, "o"); | ||
233 | seq_printf(s, ")"); | ||
234 | } | ||
235 | } else | ||
236 | seq_printf(s, "current: UNKNOWN"); | ||
237 | |||
238 | if (grp->num_settings > 1) { | ||
239 | seq_printf(s, ", available = ["); | ||
240 | for (n = 0; n < grp->num_settings; n++) { | ||
241 | if (curr == &grp->settings[n]) | ||
242 | continue; | ||
243 | |||
244 | /* skip unsupported settings for this variant */ | ||
245 | if (pctl->variant && | ||
246 | !(pctl->variant & grp->settings[n].variant)) | ||
247 | continue; | ||
248 | |||
249 | seq_printf(s, " %s", grp->settings[n].name); | ||
250 | if (grp->settings[n].subname) | ||
251 | seq_printf(s, "(%s)", grp->settings[n].subname); | ||
252 | if (grp->settings[n].flags & | ||
253 | (MVEBU_SETTING_GPO | MVEBU_SETTING_GPI)) { | ||
254 | seq_printf(s, "("); | ||
255 | if (grp->settings[n].flags & MVEBU_SETTING_GPI) | ||
256 | seq_printf(s, "i"); | ||
257 | if (grp->settings[n].flags & MVEBU_SETTING_GPO) | ||
258 | seq_printf(s, "o"); | ||
259 | seq_printf(s, ")"); | ||
260 | } | ||
261 | } | ||
262 | seq_printf(s, " ]"); | ||
263 | } | ||
264 | return; | ||
265 | } | ||
266 | |||
267 | static struct pinconf_ops mvebu_pinconf_ops = { | ||
268 | .pin_config_group_get = mvebu_pinconf_group_get, | ||
269 | .pin_config_group_set = mvebu_pinconf_group_set, | ||
270 | .pin_config_group_dbg_show = mvebu_pinconf_group_dbg_show, | ||
271 | }; | ||
272 | |||
273 | static int mvebu_pinmux_get_funcs_count(struct pinctrl_dev *pctldev) | ||
274 | { | ||
275 | struct mvebu_pinctrl *pctl = pinctrl_dev_get_drvdata(pctldev); | ||
276 | |||
277 | return pctl->num_functions; | ||
278 | } | ||
279 | |||
280 | static const char *mvebu_pinmux_get_func_name(struct pinctrl_dev *pctldev, | ||
281 | unsigned fid) | ||
282 | { | ||
283 | struct mvebu_pinctrl *pctl = pinctrl_dev_get_drvdata(pctldev); | ||
284 | |||
285 | return pctl->functions[fid].name; | ||
286 | } | ||
287 | |||
288 | static int mvebu_pinmux_get_groups(struct pinctrl_dev *pctldev, unsigned fid, | ||
289 | const char * const **groups, | ||
290 | unsigned * const num_groups) | ||
291 | { | ||
292 | struct mvebu_pinctrl *pctl = pinctrl_dev_get_drvdata(pctldev); | ||
293 | |||
294 | *groups = pctl->functions[fid].groups; | ||
295 | *num_groups = pctl->functions[fid].num_groups; | ||
296 | return 0; | ||
297 | } | ||
298 | |||
299 | static int mvebu_pinmux_enable(struct pinctrl_dev *pctldev, unsigned fid, | ||
300 | unsigned gid) | ||
301 | { | ||
302 | struct mvebu_pinctrl *pctl = pinctrl_dev_get_drvdata(pctldev); | ||
303 | struct mvebu_pinctrl_function *func = &pctl->functions[fid]; | ||
304 | struct mvebu_pinctrl_group *grp = &pctl->groups[gid]; | ||
305 | struct mvebu_mpp_ctrl_setting *setting; | ||
306 | int ret; | ||
307 | |||
308 | setting = mvebu_pinctrl_find_setting_by_name(pctl, grp, | ||
309 | func->name); | ||
310 | if (!setting) { | ||
311 | dev_err(pctl->dev, | ||
312 | "unable to find setting %s in group %s\n", | ||
313 | func->name, func->groups[gid]); | ||
314 | return -EINVAL; | ||
315 | } | ||
316 | |||
317 | ret = mvebu_pinconf_group_set(pctldev, grp->gid, setting->val); | ||
318 | if (ret) { | ||
319 | dev_err(pctl->dev, "cannot set group %s to %s\n", | ||
320 | func->groups[gid], func->name); | ||
321 | return ret; | ||
322 | } | ||
323 | |||
324 | return 0; | ||
325 | } | ||
326 | |||
327 | static int mvebu_pinmux_gpio_request_enable(struct pinctrl_dev *pctldev, | ||
328 | struct pinctrl_gpio_range *range, unsigned offset) | ||
329 | { | ||
330 | struct mvebu_pinctrl *pctl = pinctrl_dev_get_drvdata(pctldev); | ||
331 | struct mvebu_pinctrl_group *grp; | ||
332 | struct mvebu_mpp_ctrl_setting *setting; | ||
333 | |||
334 | grp = mvebu_pinctrl_find_group_by_pid(pctl, offset); | ||
335 | if (!grp) | ||
336 | return -EINVAL; | ||
337 | |||
338 | if (grp->ctrl->mpp_gpio_req) | ||
339 | return grp->ctrl->mpp_gpio_req(grp->ctrl, offset); | ||
340 | |||
341 | setting = mvebu_pinctrl_find_gpio_setting(pctl, grp); | ||
342 | if (!setting) | ||
343 | return -ENOTSUPP; | ||
344 | |||
345 | return mvebu_pinconf_group_set(pctldev, grp->gid, setting->val); | ||
346 | } | ||
347 | |||
348 | static int mvebu_pinmux_gpio_set_direction(struct pinctrl_dev *pctldev, | ||
349 | struct pinctrl_gpio_range *range, unsigned offset, bool input) | ||
350 | { | ||
351 | struct mvebu_pinctrl *pctl = pinctrl_dev_get_drvdata(pctldev); | ||
352 | struct mvebu_pinctrl_group *grp; | ||
353 | struct mvebu_mpp_ctrl_setting *setting; | ||
354 | |||
355 | grp = mvebu_pinctrl_find_group_by_pid(pctl, offset); | ||
356 | if (!grp) | ||
357 | return -EINVAL; | ||
358 | |||
359 | if (grp->ctrl->mpp_gpio_dir) | ||
360 | return grp->ctrl->mpp_gpio_dir(grp->ctrl, offset, input); | ||
361 | |||
362 | setting = mvebu_pinctrl_find_gpio_setting(pctl, grp); | ||
363 | if (!setting) | ||
364 | return -ENOTSUPP; | ||
365 | |||
366 | if ((input && (setting->flags & MVEBU_SETTING_GPI)) || | ||
367 | (!input && (setting->flags & MVEBU_SETTING_GPO))) | ||
368 | return 0; | ||
369 | |||
370 | return -ENOTSUPP; | ||
371 | } | ||
372 | |||
373 | static struct pinmux_ops mvebu_pinmux_ops = { | ||
374 | .get_functions_count = mvebu_pinmux_get_funcs_count, | ||
375 | .get_function_name = mvebu_pinmux_get_func_name, | ||
376 | .get_function_groups = mvebu_pinmux_get_groups, | ||
377 | .gpio_request_enable = mvebu_pinmux_gpio_request_enable, | ||
378 | .gpio_set_direction = mvebu_pinmux_gpio_set_direction, | ||
379 | .enable = mvebu_pinmux_enable, | ||
380 | }; | ||
381 | |||
382 | static int mvebu_pinctrl_get_groups_count(struct pinctrl_dev *pctldev) | ||
383 | { | ||
384 | struct mvebu_pinctrl *pctl = pinctrl_dev_get_drvdata(pctldev); | ||
385 | return pctl->num_groups; | ||
386 | } | ||
387 | |||
388 | static const char *mvebu_pinctrl_get_group_name(struct pinctrl_dev *pctldev, | ||
389 | unsigned gid) | ||
390 | { | ||
391 | struct mvebu_pinctrl *pctl = pinctrl_dev_get_drvdata(pctldev); | ||
392 | return pctl->groups[gid].name; | ||
393 | } | ||
394 | |||
395 | static int mvebu_pinctrl_get_group_pins(struct pinctrl_dev *pctldev, | ||
396 | unsigned gid, const unsigned **pins, | ||
397 | unsigned *num_pins) | ||
398 | { | ||
399 | struct mvebu_pinctrl *pctl = pinctrl_dev_get_drvdata(pctldev); | ||
400 | *pins = pctl->groups[gid].pins; | ||
401 | *num_pins = pctl->groups[gid].npins; | ||
402 | return 0; | ||
403 | } | ||
404 | |||
405 | static int mvebu_pinctrl_dt_node_to_map(struct pinctrl_dev *pctldev, | ||
406 | struct device_node *np, | ||
407 | struct pinctrl_map **map, | ||
408 | unsigned *num_maps) | ||
409 | { | ||
410 | struct mvebu_pinctrl *pctl = pinctrl_dev_get_drvdata(pctldev); | ||
411 | struct property *prop; | ||
412 | const char *function; | ||
413 | const char *group; | ||
414 | int ret, nmaps, n; | ||
415 | |||
416 | *map = NULL; | ||
417 | *num_maps = 0; | ||
418 | |||
419 | ret = of_property_read_string(np, "marvell,function", &function); | ||
420 | if (ret) { | ||
421 | dev_err(pctl->dev, | ||
422 | "missing marvell,function in node %s\n", np->name); | ||
423 | return 0; | ||
424 | } | ||
425 | |||
426 | nmaps = of_property_count_strings(np, "marvell,pins"); | ||
427 | if (nmaps < 0) { | ||
428 | dev_err(pctl->dev, | ||
429 | "missing marvell,pins in node %s\n", np->name); | ||
430 | return 0; | ||
431 | } | ||
432 | |||
433 | *map = kmalloc(nmaps * sizeof(struct pinctrl_map), GFP_KERNEL); | ||
434 | if (map == NULL) { | ||
435 | dev_err(pctl->dev, | ||
436 | "cannot allocate pinctrl_map memory for %s\n", | ||
437 | np->name); | ||
438 | return -ENOMEM; | ||
439 | } | ||
440 | |||
441 | n = 0; | ||
442 | of_property_for_each_string(np, "marvell,pins", prop, group) { | ||
443 | struct mvebu_pinctrl_group *grp = | ||
444 | mvebu_pinctrl_find_group_by_name(pctl, group); | ||
445 | |||
446 | if (!grp) { | ||
447 | dev_err(pctl->dev, "unknown pin %s", group); | ||
448 | continue; | ||
449 | } | ||
450 | |||
451 | if (!mvebu_pinctrl_find_setting_by_name(pctl, grp, function)) { | ||
452 | dev_err(pctl->dev, "unsupported function %s on pin %s", | ||
453 | function, group); | ||
454 | continue; | ||
455 | } | ||
456 | |||
457 | (*map)[n].type = PIN_MAP_TYPE_MUX_GROUP; | ||
458 | (*map)[n].data.mux.group = group; | ||
459 | (*map)[n].data.mux.function = function; | ||
460 | n++; | ||
461 | } | ||
462 | |||
463 | *num_maps = nmaps; | ||
464 | |||
465 | return 0; | ||
466 | } | ||
467 | |||
468 | static void mvebu_pinctrl_dt_free_map(struct pinctrl_dev *pctldev, | ||
469 | struct pinctrl_map *map, unsigned num_maps) | ||
470 | { | ||
471 | kfree(map); | ||
472 | } | ||
473 | |||
474 | static struct pinctrl_ops mvebu_pinctrl_ops = { | ||
475 | .get_groups_count = mvebu_pinctrl_get_groups_count, | ||
476 | .get_group_name = mvebu_pinctrl_get_group_name, | ||
477 | .get_group_pins = mvebu_pinctrl_get_group_pins, | ||
478 | .dt_node_to_map = mvebu_pinctrl_dt_node_to_map, | ||
479 | .dt_free_map = mvebu_pinctrl_dt_free_map, | ||
480 | }; | ||
481 | |||
482 | static int __devinit _add_function(struct mvebu_pinctrl_function *funcs, | ||
483 | const char *name) | ||
484 | { | ||
485 | while (funcs->num_groups) { | ||
486 | /* function already there */ | ||
487 | if (strcmp(funcs->name, name) == 0) { | ||
488 | funcs->num_groups++; | ||
489 | return -EEXIST; | ||
490 | } | ||
491 | funcs++; | ||
492 | } | ||
493 | funcs->name = name; | ||
494 | funcs->num_groups = 1; | ||
495 | return 0; | ||
496 | } | ||
497 | |||
498 | static int __devinit mvebu_pinctrl_build_functions(struct platform_device *pdev, | ||
499 | struct mvebu_pinctrl *pctl) | ||
500 | { | ||
501 | struct mvebu_pinctrl_function *funcs; | ||
502 | int num = 0; | ||
503 | int n, s; | ||
504 | |||
505 | /* we allocate functions for number of pins and hope | ||
506 | * there are less unique functions than pins available */ | ||
507 | funcs = devm_kzalloc(&pdev->dev, pctl->desc.npins * | ||
508 | sizeof(struct mvebu_pinctrl_function), GFP_KERNEL); | ||
509 | if (!funcs) | ||
510 | return -ENOMEM; | ||
511 | |||
512 | for (n = 0; n < pctl->num_groups; n++) { | ||
513 | struct mvebu_pinctrl_group *grp = &pctl->groups[n]; | ||
514 | for (s = 0; s < grp->num_settings; s++) { | ||
515 | /* skip unsupported settings on this variant */ | ||
516 | if (pctl->variant && | ||
517 | !(pctl->variant & grp->settings[s].variant)) | ||
518 | continue; | ||
519 | |||
520 | /* check for unique functions and count groups */ | ||
521 | if (_add_function(funcs, grp->settings[s].name)) | ||
522 | continue; | ||
523 | |||
524 | num++; | ||
525 | } | ||
526 | } | ||
527 | |||
528 | /* with the number of unique functions and it's groups known, | ||
529 | reallocate functions and assign group names */ | ||
530 | funcs = krealloc(funcs, num * sizeof(struct mvebu_pinctrl_function), | ||
531 | GFP_KERNEL); | ||
532 | if (!funcs) | ||
533 | return -ENOMEM; | ||
534 | |||
535 | pctl->num_functions = num; | ||
536 | pctl->functions = funcs; | ||
537 | |||
538 | for (n = 0; n < pctl->num_groups; n++) { | ||
539 | struct mvebu_pinctrl_group *grp = &pctl->groups[n]; | ||
540 | for (s = 0; s < grp->num_settings; s++) { | ||
541 | struct mvebu_pinctrl_function *f; | ||
542 | const char **groups; | ||
543 | |||
544 | /* skip unsupported settings on this variant */ | ||
545 | if (pctl->variant && | ||
546 | !(pctl->variant & grp->settings[s].variant)) | ||
547 | continue; | ||
548 | |||
549 | f = mvebu_pinctrl_find_function_by_name(pctl, | ||
550 | grp->settings[s].name); | ||
551 | |||
552 | /* allocate group name array if not done already */ | ||
553 | if (!f->groups) { | ||
554 | f->groups = devm_kzalloc(&pdev->dev, | ||
555 | f->num_groups * sizeof(char *), | ||
556 | GFP_KERNEL); | ||
557 | if (!f->groups) | ||
558 | return -ENOMEM; | ||
559 | } | ||
560 | |||
561 | /* find next free group name and assign current name */ | ||
562 | groups = f->groups; | ||
563 | while (*groups) | ||
564 | groups++; | ||
565 | *groups = grp->name; | ||
566 | } | ||
567 | } | ||
568 | |||
569 | return 0; | ||
570 | } | ||
571 | |||
572 | int __devinit mvebu_pinctrl_probe(struct platform_device *pdev) | ||
573 | { | ||
574 | struct mvebu_pinctrl_soc_info *soc = dev_get_platdata(&pdev->dev); | ||
575 | struct device_node *np = pdev->dev.of_node; | ||
576 | struct mvebu_pinctrl *pctl; | ||
577 | void __iomem *base; | ||
578 | struct pinctrl_pin_desc *pdesc; | ||
579 | unsigned gid, n, k; | ||
580 | int ret; | ||
581 | |||
582 | if (!soc || !soc->controls || !soc->modes) { | ||
583 | dev_err(&pdev->dev, "wrong pinctrl soc info\n"); | ||
584 | return -EINVAL; | ||
585 | } | ||
586 | |||
587 | base = of_iomap(np, 0); | ||
588 | if (!base) { | ||
589 | dev_err(&pdev->dev, "unable to get base address\n"); | ||
590 | return -ENODEV; | ||
591 | } | ||
592 | |||
593 | pctl = devm_kzalloc(&pdev->dev, sizeof(struct mvebu_pinctrl), | ||
594 | GFP_KERNEL); | ||
595 | if (!pctl) { | ||
596 | dev_err(&pdev->dev, "unable to alloc driver\n"); | ||
597 | return -ENOMEM; | ||
598 | } | ||
599 | |||
600 | pctl->desc.name = dev_name(&pdev->dev); | ||
601 | pctl->desc.owner = THIS_MODULE; | ||
602 | pctl->desc.pctlops = &mvebu_pinctrl_ops; | ||
603 | pctl->desc.pmxops = &mvebu_pinmux_ops; | ||
604 | pctl->desc.confops = &mvebu_pinconf_ops; | ||
605 | pctl->variant = soc->variant; | ||
606 | pctl->base = base; | ||
607 | pctl->dev = &pdev->dev; | ||
608 | platform_set_drvdata(pdev, pctl); | ||
609 | |||
610 | /* count controls and create names for mvebu generic | ||
611 | register controls; also does sanity checks */ | ||
612 | pctl->num_groups = 0; | ||
613 | pctl->desc.npins = 0; | ||
614 | for (n = 0; n < soc->ncontrols; n++) { | ||
615 | struct mvebu_mpp_ctrl *ctrl = &soc->controls[n]; | ||
616 | char *names; | ||
617 | |||
618 | pctl->desc.npins += ctrl->npins; | ||
619 | /* initial control pins */ | ||
620 | for (k = 0; k < ctrl->npins; k++) | ||
621 | ctrl->pins[k] = ctrl->pid + k; | ||
622 | |||
623 | /* special soc specific control */ | ||
624 | if (ctrl->mpp_get || ctrl->mpp_set) { | ||
625 | if (!ctrl->name || !ctrl->mpp_set || !ctrl->mpp_set) { | ||
626 | dev_err(&pdev->dev, "wrong soc control info\n"); | ||
627 | return -EINVAL; | ||
628 | } | ||
629 | pctl->num_groups += 1; | ||
630 | continue; | ||
631 | } | ||
632 | |||
633 | /* generic mvebu register control */ | ||
634 | names = devm_kzalloc(&pdev->dev, ctrl->npins * 8, GFP_KERNEL); | ||
635 | if (!names) { | ||
636 | dev_err(&pdev->dev, "failed to alloc mpp names\n"); | ||
637 | return -ENOMEM; | ||
638 | } | ||
639 | for (k = 0; k < ctrl->npins; k++) | ||
640 | sprintf(names + 8*k, "mpp%d", ctrl->pid+k); | ||
641 | ctrl->name = names; | ||
642 | pctl->num_groups += ctrl->npins; | ||
643 | } | ||
644 | |||
645 | pdesc = devm_kzalloc(&pdev->dev, pctl->desc.npins * | ||
646 | sizeof(struct pinctrl_pin_desc), GFP_KERNEL); | ||
647 | if (!pdesc) { | ||
648 | dev_err(&pdev->dev, "failed to alloc pinctrl pins\n"); | ||
649 | return -ENOMEM; | ||
650 | } | ||
651 | |||
652 | for (n = 0; n < pctl->desc.npins; n++) | ||
653 | pdesc[n].number = n; | ||
654 | pctl->desc.pins = pdesc; | ||
655 | |||
656 | pctl->groups = devm_kzalloc(&pdev->dev, pctl->num_groups * | ||
657 | sizeof(struct mvebu_pinctrl_group), GFP_KERNEL); | ||
658 | if (!pctl->groups) { | ||
659 | dev_err(&pdev->dev, "failed to alloc pinctrl groups\n"); | ||
660 | return -ENOMEM; | ||
661 | } | ||
662 | |||
663 | /* assign mpp controls to groups */ | ||
664 | gid = 0; | ||
665 | for (n = 0; n < soc->ncontrols; n++) { | ||
666 | struct mvebu_mpp_ctrl *ctrl = &soc->controls[n]; | ||
667 | pctl->groups[gid].gid = gid; | ||
668 | pctl->groups[gid].ctrl = ctrl; | ||
669 | pctl->groups[gid].name = ctrl->name; | ||
670 | pctl->groups[gid].pins = ctrl->pins; | ||
671 | pctl->groups[gid].npins = ctrl->npins; | ||
672 | |||
673 | /* generic mvebu register control maps to a number of groups */ | ||
674 | if (!ctrl->mpp_get && !ctrl->mpp_set) { | ||
675 | pctl->groups[gid].npins = 1; | ||
676 | |||
677 | for (k = 1; k < ctrl->npins; k++) { | ||
678 | gid++; | ||
679 | pctl->groups[gid].gid = gid; | ||
680 | pctl->groups[gid].ctrl = ctrl; | ||
681 | pctl->groups[gid].name = &ctrl->name[8*k]; | ||
682 | pctl->groups[gid].pins = &ctrl->pins[k]; | ||
683 | pctl->groups[gid].npins = 1; | ||
684 | } | ||
685 | } | ||
686 | gid++; | ||
687 | } | ||
688 | |||
689 | /* assign mpp modes to groups */ | ||
690 | for (n = 0; n < soc->nmodes; n++) { | ||
691 | struct mvebu_mpp_mode *mode = &soc->modes[n]; | ||
692 | struct mvebu_pinctrl_group *grp = | ||
693 | mvebu_pinctrl_find_group_by_pid(pctl, mode->pid); | ||
694 | unsigned num_settings; | ||
695 | |||
696 | if (!grp) { | ||
697 | dev_warn(&pdev->dev, "unknown pinctrl group %d\n", | ||
698 | mode->pid); | ||
699 | continue; | ||
700 | } | ||
701 | |||
702 | for (num_settings = 0; ;) { | ||
703 | struct mvebu_mpp_ctrl_setting *set = | ||
704 | &mode->settings[num_settings]; | ||
705 | |||
706 | if (!set->name) | ||
707 | break; | ||
708 | num_settings++; | ||
709 | |||
710 | /* skip unsupported settings for this variant */ | ||
711 | if (pctl->variant && !(pctl->variant & set->variant)) | ||
712 | continue; | ||
713 | |||
714 | /* find gpio/gpo/gpi settings */ | ||
715 | if (strcmp(set->name, "gpio") == 0) | ||
716 | set->flags = MVEBU_SETTING_GPI | | ||
717 | MVEBU_SETTING_GPO; | ||
718 | else if (strcmp(set->name, "gpo") == 0) | ||
719 | set->flags = MVEBU_SETTING_GPO; | ||
720 | else if (strcmp(set->name, "gpi") == 0) | ||
721 | set->flags = MVEBU_SETTING_GPI; | ||
722 | } | ||
723 | |||
724 | grp->settings = mode->settings; | ||
725 | grp->num_settings = num_settings; | ||
726 | } | ||
727 | |||
728 | ret = mvebu_pinctrl_build_functions(pdev, pctl); | ||
729 | if (ret) { | ||
730 | dev_err(&pdev->dev, "unable to build functions\n"); | ||
731 | return ret; | ||
732 | } | ||
733 | |||
734 | pctl->pctldev = pinctrl_register(&pctl->desc, &pdev->dev, pctl); | ||
735 | if (!pctl->pctldev) { | ||
736 | dev_err(&pdev->dev, "unable to register pinctrl driver\n"); | ||
737 | return -EINVAL; | ||
738 | } | ||
739 | |||
740 | dev_info(&pdev->dev, "registered pinctrl driver\n"); | ||
741 | |||
742 | /* register gpio ranges */ | ||
743 | for (n = 0; n < soc->ngpioranges; n++) | ||
744 | pinctrl_add_gpio_range(pctl->pctldev, &soc->gpioranges[n]); | ||
745 | |||
746 | return 0; | ||
747 | } | ||
748 | |||
749 | int __devexit mvebu_pinctrl_remove(struct platform_device *pdev) | ||
750 | { | ||
751 | struct mvebu_pinctrl *pctl = platform_get_drvdata(pdev); | ||
752 | pinctrl_unregister(pctl->pctldev); | ||
753 | return 0; | ||
754 | } | ||
diff --git a/drivers/pinctrl/pinctrl-mvebu.h b/drivers/pinctrl/pinctrl-mvebu.h new file mode 100644 index 000000000000..90bd3beee860 --- /dev/null +++ b/drivers/pinctrl/pinctrl-mvebu.h | |||
@@ -0,0 +1,192 @@ | |||
1 | /* | ||
2 | * Marvell MVEBU pinctrl driver | ||
3 | * | ||
4 | * Authors: Sebastian Hesselbarth <sebastian.hesselbarth@gmail.com> | ||
5 | * Thomas Petazzoni <thomas.petazzoni@free-electrons.com> | ||
6 | * | ||
7 | * This program is free software; you can redistribute it and/or modify | ||
8 | * it under the terms of the GNU General Public License as published by | ||
9 | * the Free Software Foundation; either version 2 of the License, or | ||
10 | * (at your option) any later version. | ||
11 | */ | ||
12 | |||
13 | #ifndef __PINCTRL_MVEBU_H__ | ||
14 | #define __PINCTRL_MVEBU_H__ | ||
15 | |||
16 | /** | ||
17 | * struct mvebu_mpp_ctrl - describe a mpp control | ||
18 | * @name: name of the control group | ||
19 | * @pid: first pin id handled by this control | ||
20 | * @npins: number of pins controlled by this control | ||
21 | * @mpp_get: (optional) special function to get mpp setting | ||
22 | * @mpp_set: (optional) special function to set mpp setting | ||
23 | * @mpp_gpio_req: (optional) special function to request gpio | ||
24 | * @mpp_gpio_dir: (optional) special function to set gpio direction | ||
25 | * | ||
26 | * A mpp_ctrl describes a muxable unit, e.g. pin, group of pins, or | ||
27 | * internal function, inside the SoC. Each muxable unit can be switched | ||
28 | * between two or more different settings, e.g. assign mpp pin 13 to | ||
29 | * uart1 or sata. | ||
30 | * | ||
31 | * If optional mpp_get/_set functions are set these are used to get/set | ||
32 | * a specific mode. Otherwise it is assumed that the mpp control is based | ||
33 | * on 4-bit groups in subsequent registers. The optional mpp_gpio_req/_dir | ||
34 | * functions can be used to allow pin settings with varying gpio pins. | ||
35 | */ | ||
36 | struct mvebu_mpp_ctrl { | ||
37 | const char *name; | ||
38 | u8 pid; | ||
39 | u8 npins; | ||
40 | unsigned *pins; | ||
41 | int (*mpp_get)(struct mvebu_mpp_ctrl *ctrl, unsigned long *config); | ||
42 | int (*mpp_set)(struct mvebu_mpp_ctrl *ctrl, unsigned long config); | ||
43 | int (*mpp_gpio_req)(struct mvebu_mpp_ctrl *ctrl, u8 pid); | ||
44 | int (*mpp_gpio_dir)(struct mvebu_mpp_ctrl *ctrl, u8 pid, bool input); | ||
45 | }; | ||
46 | |||
47 | /** | ||
48 | * struct mvebu_mpp_ctrl_setting - describe a mpp ctrl setting | ||
49 | * @val: ctrl setting value | ||
50 | * @name: ctrl setting name, e.g. uart2, spi0 - unique per mpp_mode | ||
51 | * @subname: (optional) additional ctrl setting name, e.g. rts, cts | ||
52 | * @variant: (optional) variant identifier mask | ||
53 | * @flags: (private) flags to store gpi/gpo/gpio capabilities | ||
54 | * | ||
55 | * A ctrl_setting describes a specific internal mux function that a mpp pin | ||
56 | * can be switched to. The value (val) will be written in the corresponding | ||
57 | * register for common mpp pin configuration registers on MVEBU. SoC specific | ||
58 | * mpp_get/_set function may use val to distinguish between different settings. | ||
59 | * | ||
60 | * The name will be used to switch to this setting in DT description, e.g. | ||
61 | * marvell,function = "uart2". subname is only for debugging purposes. | ||
62 | * | ||
63 | * If name is one of "gpi", "gpo", "gpio" gpio capabilities are | ||
64 | * parsed during initialization and stored in flags. | ||
65 | * | ||
66 | * The variant can be used to combine different revisions of one SoC to a | ||
67 | * common pinctrl driver. It is matched (AND) with variant of soc_info to | ||
68 | * determine if a setting is available on the current SoC revision. | ||
69 | */ | ||
70 | struct mvebu_mpp_ctrl_setting { | ||
71 | u8 val; | ||
72 | const char *name; | ||
73 | const char *subname; | ||
74 | u8 variant; | ||
75 | u8 flags; | ||
76 | #define MVEBU_SETTING_GPO (1 << 0) | ||
77 | #define MVEBU_SETTING_GPI (1 << 1) | ||
78 | }; | ||
79 | |||
80 | /** | ||
81 | * struct mvebu_mpp_mode - link ctrl and settings | ||
82 | * @pid: first pin id handled by this mode | ||
83 | * @settings: list of settings available for this mode | ||
84 | * | ||
85 | * A mode connects all available settings with the corresponding mpp_ctrl | ||
86 | * given by pid. | ||
87 | */ | ||
88 | struct mvebu_mpp_mode { | ||
89 | u8 pid; | ||
90 | struct mvebu_mpp_ctrl_setting *settings; | ||
91 | }; | ||
92 | |||
93 | /** | ||
94 | * struct mvebu_pinctrl_soc_info - SoC specific info passed to pinctrl-mvebu | ||
95 | * @variant: variant mask of soc_info | ||
96 | * @controls: list of available mvebu_mpp_ctrls | ||
97 | * @ncontrols: number of available mvebu_mpp_ctrls | ||
98 | * @modes: list of available mvebu_mpp_modes | ||
99 | * @nmodes: number of available mvebu_mpp_modes | ||
100 | * @gpioranges: list of pinctrl_gpio_ranges | ||
101 | * @ngpioranges: number of available pinctrl_gpio_ranges | ||
102 | * | ||
103 | * This struct describes all pinctrl related information for a specific SoC. | ||
104 | * If variant is unequal 0 it will be matched (AND) with variant of each | ||
105 | * setting and allows to distinguish between different revisions of one SoC. | ||
106 | */ | ||
107 | struct mvebu_pinctrl_soc_info { | ||
108 | u8 variant; | ||
109 | struct mvebu_mpp_ctrl *controls; | ||
110 | int ncontrols; | ||
111 | struct mvebu_mpp_mode *modes; | ||
112 | int nmodes; | ||
113 | struct pinctrl_gpio_range *gpioranges; | ||
114 | int ngpioranges; | ||
115 | }; | ||
116 | |||
117 | #define MPP_REG_CTRL(_idl, _idh) \ | ||
118 | { \ | ||
119 | .name = NULL, \ | ||
120 | .pid = _idl, \ | ||
121 | .npins = _idh - _idl + 1, \ | ||
122 | .pins = (unsigned[_idh - _idl + 1]) { }, \ | ||
123 | .mpp_get = NULL, \ | ||
124 | .mpp_set = NULL, \ | ||
125 | .mpp_gpio_req = NULL, \ | ||
126 | .mpp_gpio_dir = NULL, \ | ||
127 | } | ||
128 | |||
129 | #define MPP_FUNC_CTRL(_idl, _idh, _name, _func) \ | ||
130 | { \ | ||
131 | .name = _name, \ | ||
132 | .pid = _idl, \ | ||
133 | .npins = _idh - _idl + 1, \ | ||
134 | .pins = (unsigned[_idh - _idl + 1]) { }, \ | ||
135 | .mpp_get = _func ## _get, \ | ||
136 | .mpp_set = _func ## _set, \ | ||
137 | .mpp_gpio_req = NULL, \ | ||
138 | .mpp_gpio_dir = NULL, \ | ||
139 | } | ||
140 | |||
141 | #define MPP_FUNC_GPIO_CTRL(_idl, _idh, _name, _func) \ | ||
142 | { \ | ||
143 | .name = _name, \ | ||
144 | .pid = _idl, \ | ||
145 | .npins = _idh - _idl + 1, \ | ||
146 | .pins = (unsigned[_idh - _idl + 1]) { }, \ | ||
147 | .mpp_get = _func ## _get, \ | ||
148 | .mpp_set = _func ## _set, \ | ||
149 | .mpp_gpio_req = _func ## _gpio_req, \ | ||
150 | .mpp_gpio_dir = _func ## _gpio_dir, \ | ||
151 | } | ||
152 | |||
153 | #define _MPP_VAR_FUNCTION(_val, _name, _subname, _mask) \ | ||
154 | { \ | ||
155 | .val = _val, \ | ||
156 | .name = _name, \ | ||
157 | .subname = _subname, \ | ||
158 | .variant = _mask, \ | ||
159 | .flags = 0, \ | ||
160 | } | ||
161 | |||
162 | #if defined(CONFIG_DEBUG_FS) | ||
163 | #define MPP_VAR_FUNCTION(_val, _name, _subname, _mask) \ | ||
164 | _MPP_VAR_FUNCTION(_val, _name, _subname, _mask) | ||
165 | #else | ||
166 | #define MPP_VAR_FUNCTION(_val, _name, _subname, _mask) \ | ||
167 | _MPP_VAR_FUNCTION(_val, _name, NULL, _mask) | ||
168 | #endif | ||
169 | |||
170 | #define MPP_FUNCTION(_val, _name, _subname) \ | ||
171 | MPP_VAR_FUNCTION(_val, _name, _subname, (u8)-1) | ||
172 | |||
173 | #define MPP_MODE(_id, ...) \ | ||
174 | { \ | ||
175 | .pid = _id, \ | ||
176 | .settings = (struct mvebu_mpp_ctrl_setting[]){ \ | ||
177 | __VA_ARGS__, { } }, \ | ||
178 | } | ||
179 | |||
180 | #define MPP_GPIO_RANGE(_id, _pinbase, _gpiobase, _npins) \ | ||
181 | { \ | ||
182 | .name = "mvebu-gpio", \ | ||
183 | .id = _id, \ | ||
184 | .pin_base = _pinbase, \ | ||
185 | .base = _gpiobase, \ | ||
186 | .npins = _npins, \ | ||
187 | } | ||
188 | |||
189 | int mvebu_pinctrl_probe(struct platform_device *pdev); | ||
190 | int mvebu_pinctrl_remove(struct platform_device *pdev); | ||
191 | |||
192 | #endif | ||