diff options
author | Bjorn Andersson <bjorn.andersson@sonymobile.com> | 2013-12-05 21:10:03 -0500 |
---|---|---|
committer | Linus Walleij <linus.walleij@linaro.org> | 2013-12-06 08:58:33 -0500 |
commit | f365be0925729508fd8e62f8bdb504ef896cb6e0 (patch) | |
tree | e77df7f6e3f6a168d4a2a7f115b538ad0024f5e1 /drivers/pinctrl | |
parent | a4d8d6da4820230a2e0e977fda44ced9345c41d4 (diff) |
pinctrl: Add Qualcomm TLMM driver
This adds a pinctrl, pinmux, pinconf and gpiolib driver for the
Qualcomm TLMM block.
Signed-off-by: Bjorn Andersson <bjorn.andersson@sonymobile.com>
Signed-off-by: Linus Walleij <linus.walleij@linaro.org>
Diffstat (limited to 'drivers/pinctrl')
-rw-r--r-- | drivers/pinctrl/Kconfig | 6 | ||||
-rw-r--r-- | drivers/pinctrl/Makefile | 1 | ||||
-rw-r--r-- | drivers/pinctrl/pinctrl-msm.c | 1028 | ||||
-rw-r--r-- | drivers/pinctrl/pinctrl-msm.h | 122 |
4 files changed, 1157 insertions, 0 deletions
diff --git a/drivers/pinctrl/Kconfig b/drivers/pinctrl/Kconfig index 5e4418f4282b..f5a7d7c0c1ee 100644 --- a/drivers/pinctrl/Kconfig +++ b/drivers/pinctrl/Kconfig | |||
@@ -203,6 +203,12 @@ config PINCTRL_IMX28 | |||
203 | bool | 203 | bool |
204 | select PINCTRL_MXS | 204 | select PINCTRL_MXS |
205 | 205 | ||
206 | config PINCTRL_MSM | ||
207 | bool | ||
208 | select PINMUX | ||
209 | select PINCONF | ||
210 | select GENERIC_PINCONF | ||
211 | |||
206 | config PINCTRL_NOMADIK | 212 | config PINCTRL_NOMADIK |
207 | bool "Nomadik pin controller driver" | 213 | bool "Nomadik pin controller driver" |
208 | depends on ARCH_U8500 || ARCH_NOMADIK | 214 | depends on ARCH_U8500 || ARCH_NOMADIK |
diff --git a/drivers/pinctrl/Makefile b/drivers/pinctrl/Makefile index dcb01a4ef653..4eed91ff0676 100644 --- a/drivers/pinctrl/Makefile +++ b/drivers/pinctrl/Makefile | |||
@@ -36,6 +36,7 @@ obj-$(CONFIG_PINCTRL_MXS) += pinctrl-mxs.o | |||
36 | obj-$(CONFIG_PINCTRL_IMX23) += pinctrl-imx23.o | 36 | obj-$(CONFIG_PINCTRL_IMX23) += pinctrl-imx23.o |
37 | obj-$(CONFIG_PINCTRL_IMX25) += pinctrl-imx25.o | 37 | obj-$(CONFIG_PINCTRL_IMX25) += pinctrl-imx25.o |
38 | obj-$(CONFIG_PINCTRL_IMX28) += pinctrl-imx28.o | 38 | obj-$(CONFIG_PINCTRL_IMX28) += pinctrl-imx28.o |
39 | obj-$(CONFIG_PINCTRL_MSM) += pinctrl-msm.o | ||
39 | obj-$(CONFIG_PINCTRL_NOMADIK) += pinctrl-nomadik.o | 40 | obj-$(CONFIG_PINCTRL_NOMADIK) += pinctrl-nomadik.o |
40 | obj-$(CONFIG_PINCTRL_STN8815) += pinctrl-nomadik-stn8815.o | 41 | obj-$(CONFIG_PINCTRL_STN8815) += pinctrl-nomadik-stn8815.o |
41 | obj-$(CONFIG_PINCTRL_DB8500) += pinctrl-nomadik-db8500.o | 42 | obj-$(CONFIG_PINCTRL_DB8500) += pinctrl-nomadik-db8500.o |
diff --git a/drivers/pinctrl/pinctrl-msm.c b/drivers/pinctrl/pinctrl-msm.c new file mode 100644 index 000000000000..28b90aba708d --- /dev/null +++ b/drivers/pinctrl/pinctrl-msm.c | |||
@@ -0,0 +1,1028 @@ | |||
1 | /* | ||
2 | * Copyright (c) 2013, Sony Mobile Communications AB. | ||
3 | * Copyright (c) 2013, The Linux Foundation. All rights reserved. | ||
4 | * | ||
5 | * This program is free software; you can redistribute it and/or modify | ||
6 | * it under the terms of the GNU General Public License version 2 and | ||
7 | * only version 2 as published by the Free Software Foundation. | ||
8 | * | ||
9 | * This program is distributed in the hope that it will be useful, | ||
10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
12 | * GNU General Public License for more details. | ||
13 | */ | ||
14 | |||
15 | #include <linux/err.h> | ||
16 | #include <linux/irqdomain.h> | ||
17 | #include <linux/io.h> | ||
18 | #include <linux/module.h> | ||
19 | #include <linux/of.h> | ||
20 | #include <linux/platform_device.h> | ||
21 | #include <linux/pinctrl/machine.h> | ||
22 | #include <linux/pinctrl/pinctrl.h> | ||
23 | #include <linux/pinctrl/pinmux.h> | ||
24 | #include <linux/pinctrl/pinconf.h> | ||
25 | #include <linux/pinctrl/pinconf-generic.h> | ||
26 | #include <linux/slab.h> | ||
27 | #include <linux/gpio.h> | ||
28 | #include <linux/interrupt.h> | ||
29 | #include <linux/irq.h> | ||
30 | #include <linux/irqchip/chained_irq.h> | ||
31 | #include <linux/of_irq.h> | ||
32 | #include <linux/spinlock.h> | ||
33 | |||
34 | #include "core.h" | ||
35 | #include "pinconf.h" | ||
36 | #include "pinctrl-msm.h" | ||
37 | #include "pinctrl-utils.h" | ||
38 | |||
39 | /** | ||
40 | * struct msm_pinctrl - state for a pinctrl-msm device | ||
41 | * @dev: device handle. | ||
42 | * @pctrl: pinctrl handle. | ||
43 | * @domain: irqdomain handle. | ||
44 | * @chip: gpiochip handle. | ||
45 | * @irq: parent irq for the TLMM irq_chip. | ||
46 | * @lock: Spinlock to protect register resources as well | ||
47 | * as msm_pinctrl data structures. | ||
48 | * @enabled_irqs: Bitmap of currently enabled irqs. | ||
49 | * @dual_edge_irqs: Bitmap of irqs that need sw emulated dual edge | ||
50 | * detection. | ||
51 | * @wake_irqs: Bitmap of irqs with requested as wakeup source. | ||
52 | * @soc; Reference to soc_data of platform specific data. | ||
53 | * @regs: Base address for the TLMM register map. | ||
54 | */ | ||
55 | struct msm_pinctrl { | ||
56 | struct device *dev; | ||
57 | struct pinctrl_dev *pctrl; | ||
58 | struct irq_domain *domain; | ||
59 | struct gpio_chip chip; | ||
60 | unsigned irq; | ||
61 | |||
62 | spinlock_t lock; | ||
63 | |||
64 | unsigned long *enabled_irqs; | ||
65 | unsigned long *dual_edge_irqs; | ||
66 | unsigned long *wake_irqs; | ||
67 | |||
68 | const struct msm_pinctrl_soc_data *soc; | ||
69 | void __iomem *regs; | ||
70 | }; | ||
71 | |||
72 | static int msm_get_groups_count(struct pinctrl_dev *pctldev) | ||
73 | { | ||
74 | struct msm_pinctrl *pctrl = pinctrl_dev_get_drvdata(pctldev); | ||
75 | |||
76 | return pctrl->soc->ngroups; | ||
77 | } | ||
78 | |||
79 | static const char *msm_get_group_name(struct pinctrl_dev *pctldev, | ||
80 | unsigned group) | ||
81 | { | ||
82 | struct msm_pinctrl *pctrl = pinctrl_dev_get_drvdata(pctldev); | ||
83 | |||
84 | return pctrl->soc->groups[group].name; | ||
85 | } | ||
86 | |||
87 | static int msm_get_group_pins(struct pinctrl_dev *pctldev, | ||
88 | unsigned group, | ||
89 | const unsigned **pins, | ||
90 | unsigned *num_pins) | ||
91 | { | ||
92 | struct msm_pinctrl *pctrl = pinctrl_dev_get_drvdata(pctldev); | ||
93 | |||
94 | *pins = pctrl->soc->groups[group].pins; | ||
95 | *num_pins = pctrl->soc->groups[group].npins; | ||
96 | return 0; | ||
97 | } | ||
98 | |||
99 | static struct pinctrl_ops msm_pinctrl_ops = { | ||
100 | .get_groups_count = msm_get_groups_count, | ||
101 | .get_group_name = msm_get_group_name, | ||
102 | .get_group_pins = msm_get_group_pins, | ||
103 | .dt_node_to_map = pinconf_generic_dt_node_to_map_group, | ||
104 | .dt_free_map = pinctrl_utils_dt_free_map, | ||
105 | }; | ||
106 | |||
107 | static int msm_get_functions_count(struct pinctrl_dev *pctldev) | ||
108 | { | ||
109 | struct msm_pinctrl *pctrl = pinctrl_dev_get_drvdata(pctldev); | ||
110 | |||
111 | return pctrl->soc->nfunctions; | ||
112 | } | ||
113 | |||
114 | static const char *msm_get_function_name(struct pinctrl_dev *pctldev, | ||
115 | unsigned function) | ||
116 | { | ||
117 | struct msm_pinctrl *pctrl = pinctrl_dev_get_drvdata(pctldev); | ||
118 | |||
119 | return pctrl->soc->functions[function].name; | ||
120 | } | ||
121 | |||
122 | static int msm_get_function_groups(struct pinctrl_dev *pctldev, | ||
123 | unsigned function, | ||
124 | const char * const **groups, | ||
125 | unsigned * const num_groups) | ||
126 | { | ||
127 | struct msm_pinctrl *pctrl = pinctrl_dev_get_drvdata(pctldev); | ||
128 | |||
129 | *groups = pctrl->soc->functions[function].groups; | ||
130 | *num_groups = pctrl->soc->functions[function].ngroups; | ||
131 | return 0; | ||
132 | } | ||
133 | |||
134 | static int msm_pinmux_enable(struct pinctrl_dev *pctldev, | ||
135 | unsigned function, | ||
136 | unsigned group) | ||
137 | { | ||
138 | struct msm_pinctrl *pctrl = pinctrl_dev_get_drvdata(pctldev); | ||
139 | const struct msm_pingroup *g; | ||
140 | unsigned long flags; | ||
141 | u32 val; | ||
142 | int i; | ||
143 | |||
144 | g = &pctrl->soc->groups[group]; | ||
145 | |||
146 | if (WARN_ON(g->mux_bit < 0)) | ||
147 | return -EINVAL; | ||
148 | |||
149 | for (i = 0; i < ARRAY_SIZE(g->funcs); i++) { | ||
150 | if (g->funcs[i] == function) | ||
151 | break; | ||
152 | } | ||
153 | |||
154 | if (WARN_ON(i == ARRAY_SIZE(g->funcs))) | ||
155 | return -EINVAL; | ||
156 | |||
157 | spin_lock_irqsave(&pctrl->lock, flags); | ||
158 | |||
159 | val = readl(pctrl->regs + g->ctl_reg); | ||
160 | val &= ~(0x7 << g->mux_bit); | ||
161 | val |= i << g->mux_bit; | ||
162 | writel(val, pctrl->regs + g->ctl_reg); | ||
163 | |||
164 | spin_unlock_irqrestore(&pctrl->lock, flags); | ||
165 | |||
166 | return 0; | ||
167 | } | ||
168 | |||
169 | static void msm_pinmux_disable(struct pinctrl_dev *pctldev, | ||
170 | unsigned function, | ||
171 | unsigned group) | ||
172 | { | ||
173 | struct msm_pinctrl *pctrl = pinctrl_dev_get_drvdata(pctldev); | ||
174 | const struct msm_pingroup *g; | ||
175 | unsigned long flags; | ||
176 | u32 val; | ||
177 | |||
178 | g = &pctrl->soc->groups[group]; | ||
179 | |||
180 | if (WARN_ON(g->mux_bit < 0)) | ||
181 | return; | ||
182 | |||
183 | spin_lock_irqsave(&pctrl->lock, flags); | ||
184 | |||
185 | /* Clear the mux bits to select gpio mode */ | ||
186 | val = readl(pctrl->regs + g->ctl_reg); | ||
187 | val &= ~(0x7 << g->mux_bit); | ||
188 | writel(val, pctrl->regs + g->ctl_reg); | ||
189 | |||
190 | spin_unlock_irqrestore(&pctrl->lock, flags); | ||
191 | } | ||
192 | |||
193 | static struct pinmux_ops msm_pinmux_ops = { | ||
194 | .get_functions_count = msm_get_functions_count, | ||
195 | .get_function_name = msm_get_function_name, | ||
196 | .get_function_groups = msm_get_function_groups, | ||
197 | .enable = msm_pinmux_enable, | ||
198 | .disable = msm_pinmux_disable, | ||
199 | }; | ||
200 | |||
201 | static int msm_config_reg(struct msm_pinctrl *pctrl, | ||
202 | const struct msm_pingroup *g, | ||
203 | unsigned param, | ||
204 | unsigned *reg, | ||
205 | unsigned *mask, | ||
206 | unsigned *bit) | ||
207 | { | ||
208 | switch (param) { | ||
209 | case PIN_CONFIG_BIAS_DISABLE: | ||
210 | *reg = g->ctl_reg; | ||
211 | *bit = g->pull_bit; | ||
212 | *mask = 3; | ||
213 | break; | ||
214 | case PIN_CONFIG_BIAS_PULL_DOWN: | ||
215 | *reg = g->ctl_reg; | ||
216 | *bit = g->pull_bit; | ||
217 | *mask = 3; | ||
218 | break; | ||
219 | case PIN_CONFIG_BIAS_PULL_UP: | ||
220 | *reg = g->ctl_reg; | ||
221 | *bit = g->pull_bit; | ||
222 | *mask = 3; | ||
223 | break; | ||
224 | case PIN_CONFIG_DRIVE_STRENGTH: | ||
225 | *reg = g->ctl_reg; | ||
226 | *bit = g->drv_bit; | ||
227 | *mask = 7; | ||
228 | break; | ||
229 | default: | ||
230 | dev_err(pctrl->dev, "Invalid config param %04x\n", param); | ||
231 | return -ENOTSUPP; | ||
232 | } | ||
233 | |||
234 | if (*reg < 0) { | ||
235 | dev_err(pctrl->dev, "Config param %04x not supported on group %s\n", | ||
236 | param, g->name); | ||
237 | return -ENOTSUPP; | ||
238 | } | ||
239 | |||
240 | return 0; | ||
241 | } | ||
242 | |||
243 | static int msm_config_get(struct pinctrl_dev *pctldev, | ||
244 | unsigned int pin, | ||
245 | unsigned long *config) | ||
246 | { | ||
247 | dev_err(pctldev->dev, "pin_config_set op not supported\n"); | ||
248 | return -ENOTSUPP; | ||
249 | } | ||
250 | |||
251 | static int msm_config_set(struct pinctrl_dev *pctldev, unsigned int pin, | ||
252 | unsigned long *configs, unsigned num_configs) | ||
253 | { | ||
254 | dev_err(pctldev->dev, "pin_config_set op not supported\n"); | ||
255 | return -ENOTSUPP; | ||
256 | } | ||
257 | |||
258 | #define MSM_NO_PULL 0 | ||
259 | #define MSM_PULL_DOWN 1 | ||
260 | #define MSM_PULL_UP 3 | ||
261 | |||
262 | static const unsigned msm_regval_to_drive[] = { 2, 4, 6, 8, 10, 12, 14, 16 }; | ||
263 | static const unsigned msm_drive_to_regval[] = { -1, -1, 0, -1, 1, -1, 2, -1, 3, -1, 4, -1, 5, -1, 6, -1, 7 }; | ||
264 | |||
265 | static int msm_config_group_get(struct pinctrl_dev *pctldev, | ||
266 | unsigned int group, | ||
267 | unsigned long *config) | ||
268 | { | ||
269 | const struct msm_pingroup *g; | ||
270 | struct msm_pinctrl *pctrl = pinctrl_dev_get_drvdata(pctldev); | ||
271 | unsigned param = pinconf_to_config_param(*config); | ||
272 | unsigned mask; | ||
273 | unsigned arg; | ||
274 | unsigned bit; | ||
275 | unsigned reg; | ||
276 | int ret; | ||
277 | u32 val; | ||
278 | |||
279 | g = &pctrl->soc->groups[group]; | ||
280 | |||
281 | ret = msm_config_reg(pctrl, g, param, ®, &mask, &bit); | ||
282 | if (ret < 0) | ||
283 | return ret; | ||
284 | |||
285 | val = readl(pctrl->regs + reg); | ||
286 | arg = (val >> bit) & mask; | ||
287 | |||
288 | /* Convert register value to pinconf value */ | ||
289 | switch (param) { | ||
290 | case PIN_CONFIG_BIAS_DISABLE: | ||
291 | arg = arg == MSM_NO_PULL; | ||
292 | break; | ||
293 | case PIN_CONFIG_BIAS_PULL_DOWN: | ||
294 | arg = arg == MSM_PULL_DOWN; | ||
295 | break; | ||
296 | case PIN_CONFIG_BIAS_PULL_UP: | ||
297 | arg = arg == MSM_PULL_UP; | ||
298 | break; | ||
299 | case PIN_CONFIG_DRIVE_STRENGTH: | ||
300 | arg = msm_regval_to_drive[arg]; | ||
301 | break; | ||
302 | default: | ||
303 | dev_err(pctrl->dev, "Unsupported config parameter: %x\n", | ||
304 | param); | ||
305 | return -EINVAL; | ||
306 | } | ||
307 | |||
308 | *config = pinconf_to_config_packed(param, arg); | ||
309 | |||
310 | return 0; | ||
311 | } | ||
312 | |||
313 | static int msm_config_group_set(struct pinctrl_dev *pctldev, | ||
314 | unsigned group, | ||
315 | unsigned long *configs, | ||
316 | unsigned num_configs) | ||
317 | { | ||
318 | const struct msm_pingroup *g; | ||
319 | struct msm_pinctrl *pctrl = pinctrl_dev_get_drvdata(pctldev); | ||
320 | unsigned long flags; | ||
321 | unsigned param; | ||
322 | unsigned mask; | ||
323 | unsigned arg; | ||
324 | unsigned bit; | ||
325 | unsigned reg; | ||
326 | int ret; | ||
327 | u32 val; | ||
328 | int i; | ||
329 | |||
330 | g = &pctrl->soc->groups[group]; | ||
331 | |||
332 | for (i = 0; i < num_configs; i++) { | ||
333 | param = pinconf_to_config_param(configs[i]); | ||
334 | arg = pinconf_to_config_argument(configs[i]); | ||
335 | |||
336 | ret = msm_config_reg(pctrl, g, param, ®, &mask, &bit); | ||
337 | if (ret < 0) | ||
338 | return ret; | ||
339 | |||
340 | /* Convert pinconf values to register values */ | ||
341 | switch (param) { | ||
342 | case PIN_CONFIG_BIAS_DISABLE: | ||
343 | arg = MSM_NO_PULL; | ||
344 | break; | ||
345 | case PIN_CONFIG_BIAS_PULL_DOWN: | ||
346 | arg = MSM_PULL_DOWN; | ||
347 | break; | ||
348 | case PIN_CONFIG_BIAS_PULL_UP: | ||
349 | arg = MSM_PULL_UP; | ||
350 | break; | ||
351 | case PIN_CONFIG_DRIVE_STRENGTH: | ||
352 | /* Check for invalid values */ | ||
353 | if (arg > ARRAY_SIZE(msm_drive_to_regval)) | ||
354 | arg = -1; | ||
355 | else | ||
356 | arg = msm_drive_to_regval[arg]; | ||
357 | break; | ||
358 | default: | ||
359 | dev_err(pctrl->dev, "Unsupported config parameter: %x\n", | ||
360 | param); | ||
361 | return -EINVAL; | ||
362 | } | ||
363 | |||
364 | /* Range-check user-supplied value */ | ||
365 | if (arg & ~mask) { | ||
366 | dev_err(pctrl->dev, "config %x: %x is invalid\n", param, arg); | ||
367 | return -EINVAL; | ||
368 | } | ||
369 | |||
370 | spin_lock_irqsave(&pctrl->lock, flags); | ||
371 | val = readl(pctrl->regs + reg); | ||
372 | val &= ~(mask << bit); | ||
373 | val |= arg << bit; | ||
374 | writel(val, pctrl->regs + reg); | ||
375 | spin_unlock_irqrestore(&pctrl->lock, flags); | ||
376 | } | ||
377 | |||
378 | return 0; | ||
379 | } | ||
380 | |||
381 | static struct pinconf_ops msm_pinconf_ops = { | ||
382 | .pin_config_get = msm_config_get, | ||
383 | .pin_config_set = msm_config_set, | ||
384 | .pin_config_group_get = msm_config_group_get, | ||
385 | .pin_config_group_set = msm_config_group_set, | ||
386 | }; | ||
387 | |||
388 | static struct pinctrl_desc msm_pinctrl_desc = { | ||
389 | .pctlops = &msm_pinctrl_ops, | ||
390 | .pmxops = &msm_pinmux_ops, | ||
391 | .confops = &msm_pinconf_ops, | ||
392 | .owner = THIS_MODULE, | ||
393 | }; | ||
394 | |||
395 | static int msm_gpio_direction_input(struct gpio_chip *chip, unsigned offset) | ||
396 | { | ||
397 | const struct msm_pingroup *g; | ||
398 | struct msm_pinctrl *pctrl = container_of(chip, struct msm_pinctrl, chip); | ||
399 | unsigned long flags; | ||
400 | u32 val; | ||
401 | |||
402 | if (WARN_ON(offset >= pctrl->soc->ngroups)) | ||
403 | return -EINVAL; | ||
404 | |||
405 | g = &pctrl->soc->groups[offset]; | ||
406 | |||
407 | if (WARN_ON(g->oe_bit < 0)) | ||
408 | return -EINVAL; | ||
409 | |||
410 | spin_lock_irqsave(&pctrl->lock, flags); | ||
411 | |||
412 | val = readl(pctrl->regs + g->ctl_reg); | ||
413 | val &= ~BIT(g->oe_bit); | ||
414 | writel(val, pctrl->regs + g->ctl_reg); | ||
415 | |||
416 | spin_unlock_irqrestore(&pctrl->lock, flags); | ||
417 | |||
418 | return 0; | ||
419 | } | ||
420 | |||
421 | static int msm_gpio_direction_output(struct gpio_chip *chip, unsigned offset, int value) | ||
422 | { | ||
423 | const struct msm_pingroup *g; | ||
424 | struct msm_pinctrl *pctrl = container_of(chip, struct msm_pinctrl, chip); | ||
425 | unsigned long flags; | ||
426 | u32 val; | ||
427 | |||
428 | if (WARN_ON(offset >= pctrl->soc->ngroups)) | ||
429 | return -EINVAL; | ||
430 | |||
431 | g = &pctrl->soc->groups[offset]; | ||
432 | |||
433 | if (WARN_ON(g->oe_bit < 0)) | ||
434 | return -EINVAL; | ||
435 | |||
436 | spin_lock_irqsave(&pctrl->lock, flags); | ||
437 | |||
438 | writel(value ? BIT(g->out_bit) : 0, pctrl->regs + g->io_reg); | ||
439 | |||
440 | val = readl(pctrl->regs + g->ctl_reg); | ||
441 | val |= BIT(g->oe_bit); | ||
442 | writel(val, pctrl->regs + g->ctl_reg); | ||
443 | |||
444 | spin_unlock_irqrestore(&pctrl->lock, flags); | ||
445 | |||
446 | return 0; | ||
447 | } | ||
448 | |||
449 | static int msm_gpio_get(struct gpio_chip *chip, unsigned offset) | ||
450 | { | ||
451 | const struct msm_pingroup *g; | ||
452 | struct msm_pinctrl *pctrl = container_of(chip, struct msm_pinctrl, chip); | ||
453 | u32 val; | ||
454 | |||
455 | if (WARN_ON(offset >= pctrl->soc->ngroups)) | ||
456 | return -EINVAL; | ||
457 | |||
458 | g = &pctrl->soc->groups[offset]; | ||
459 | |||
460 | val = readl(pctrl->regs + g->io_reg); | ||
461 | return !!(val & BIT(g->in_bit)); | ||
462 | } | ||
463 | |||
464 | static void msm_gpio_set(struct gpio_chip *chip, unsigned offset, int value) | ||
465 | { | ||
466 | const struct msm_pingroup *g; | ||
467 | struct msm_pinctrl *pctrl = container_of(chip, struct msm_pinctrl, chip); | ||
468 | unsigned long flags; | ||
469 | u32 val; | ||
470 | |||
471 | if (WARN_ON(offset >= pctrl->soc->ngroups)) | ||
472 | return; | ||
473 | |||
474 | g = &pctrl->soc->groups[offset]; | ||
475 | |||
476 | spin_lock_irqsave(&pctrl->lock, flags); | ||
477 | |||
478 | val = readl(pctrl->regs + g->io_reg); | ||
479 | val |= BIT(g->out_bit); | ||
480 | writel(val, pctrl->regs + g->io_reg); | ||
481 | |||
482 | spin_unlock_irqrestore(&pctrl->lock, flags); | ||
483 | } | ||
484 | |||
485 | static int msm_gpio_to_irq(struct gpio_chip *chip, unsigned offset) | ||
486 | { | ||
487 | struct msm_pinctrl *pctrl = container_of(chip, struct msm_pinctrl, chip); | ||
488 | |||
489 | return irq_find_mapping(pctrl->domain, offset); | ||
490 | } | ||
491 | |||
492 | static int msm_gpio_request(struct gpio_chip *chip, unsigned offset) | ||
493 | { | ||
494 | int gpio = chip->base + offset; | ||
495 | return pinctrl_request_gpio(gpio); | ||
496 | } | ||
497 | |||
498 | static void msm_gpio_free(struct gpio_chip *chip, unsigned offset) | ||
499 | { | ||
500 | int gpio = chip->base + offset; | ||
501 | return pinctrl_free_gpio(gpio); | ||
502 | } | ||
503 | |||
504 | #ifdef CONFIG_DEBUG_FS | ||
505 | #include <linux/seq_file.h> | ||
506 | |||
507 | static void msm_gpio_dbg_show_one(struct seq_file *s, | ||
508 | struct pinctrl_dev *pctldev, | ||
509 | struct gpio_chip *chip, | ||
510 | unsigned offset, | ||
511 | unsigned gpio) | ||
512 | { | ||
513 | const struct msm_pingroup *g; | ||
514 | struct msm_pinctrl *pctrl = container_of(chip, struct msm_pinctrl, chip); | ||
515 | unsigned func; | ||
516 | int is_out; | ||
517 | int drive; | ||
518 | int pull; | ||
519 | u32 ctl_reg; | ||
520 | |||
521 | const char *pulls[] = { | ||
522 | "no pull", | ||
523 | "pull down", | ||
524 | "keeper", | ||
525 | "pull up" | ||
526 | }; | ||
527 | |||
528 | g = &pctrl->soc->groups[offset]; | ||
529 | ctl_reg = readl(pctrl->regs + g->ctl_reg); | ||
530 | |||
531 | is_out = !!(ctl_reg & BIT(g->oe_bit)); | ||
532 | func = (ctl_reg >> g->mux_bit) & 7; | ||
533 | drive = (ctl_reg >> g->drv_bit) & 7; | ||
534 | pull = (ctl_reg >> g->pull_bit) & 3; | ||
535 | |||
536 | seq_printf(s, " %-8s: %-3s %d", g->name, is_out ? "out" : "in", func); | ||
537 | seq_printf(s, " %dmA", msm_regval_to_drive[drive]); | ||
538 | seq_printf(s, " %s", pulls[pull]); | ||
539 | } | ||
540 | |||
541 | static void msm_gpio_dbg_show(struct seq_file *s, struct gpio_chip *chip) | ||
542 | { | ||
543 | unsigned gpio = chip->base; | ||
544 | unsigned i; | ||
545 | |||
546 | for (i = 0; i < chip->ngpio; i++, gpio++) { | ||
547 | msm_gpio_dbg_show_one(s, NULL, chip, i, gpio); | ||
548 | seq_printf(s, "\n"); | ||
549 | } | ||
550 | } | ||
551 | |||
552 | #else | ||
553 | #define msm_gpio_dbg_show NULL | ||
554 | #endif | ||
555 | |||
556 | static struct gpio_chip msm_gpio_template = { | ||
557 | .direction_input = msm_gpio_direction_input, | ||
558 | .direction_output = msm_gpio_direction_output, | ||
559 | .get = msm_gpio_get, | ||
560 | .set = msm_gpio_set, | ||
561 | .to_irq = msm_gpio_to_irq, | ||
562 | .request = msm_gpio_request, | ||
563 | .free = msm_gpio_free, | ||
564 | .dbg_show = msm_gpio_dbg_show, | ||
565 | }; | ||
566 | |||
567 | /* For dual-edge interrupts in software, since some hardware has no | ||
568 | * such support: | ||
569 | * | ||
570 | * At appropriate moments, this function may be called to flip the polarity | ||
571 | * settings of both-edge irq lines to try and catch the next edge. | ||
572 | * | ||
573 | * The attempt is considered successful if: | ||
574 | * - the status bit goes high, indicating that an edge was caught, or | ||
575 | * - the input value of the gpio doesn't change during the attempt. | ||
576 | * If the value changes twice during the process, that would cause the first | ||
577 | * test to fail but would force the second, as two opposite | ||
578 | * transitions would cause a detection no matter the polarity setting. | ||
579 | * | ||
580 | * The do-loop tries to sledge-hammer closed the timing hole between | ||
581 | * the initial value-read and the polarity-write - if the line value changes | ||
582 | * during that window, an interrupt is lost, the new polarity setting is | ||
583 | * incorrect, and the first success test will fail, causing a retry. | ||
584 | * | ||
585 | * Algorithm comes from Google's msmgpio driver. | ||
586 | */ | ||
587 | static void msm_gpio_update_dual_edge_pos(struct msm_pinctrl *pctrl, | ||
588 | const struct msm_pingroup *g, | ||
589 | struct irq_data *d) | ||
590 | { | ||
591 | int loop_limit = 100; | ||
592 | unsigned val, val2, intstat; | ||
593 | unsigned pol; | ||
594 | |||
595 | do { | ||
596 | val = readl(pctrl->regs + g->io_reg) & BIT(g->in_bit); | ||
597 | |||
598 | pol = readl(pctrl->regs + g->intr_cfg_reg); | ||
599 | pol ^= BIT(g->intr_polarity_bit); | ||
600 | writel(pol, pctrl->regs + g->intr_cfg_reg); | ||
601 | |||
602 | val2 = readl(pctrl->regs + g->io_reg) & BIT(g->in_bit); | ||
603 | intstat = readl(pctrl->regs + g->intr_status_reg); | ||
604 | if (intstat || (val == val2)) | ||
605 | return; | ||
606 | } while (loop_limit-- > 0); | ||
607 | dev_err(pctrl->dev, "dual-edge irq failed to stabilize, %#08x != %#08x\n", | ||
608 | val, val2); | ||
609 | } | ||
610 | |||
611 | static void msm_gpio_irq_mask(struct irq_data *d) | ||
612 | { | ||
613 | const struct msm_pingroup *g; | ||
614 | struct msm_pinctrl *pctrl; | ||
615 | unsigned long flags; | ||
616 | u32 val; | ||
617 | |||
618 | pctrl = irq_data_get_irq_chip_data(d); | ||
619 | if (!pctrl) | ||
620 | return; | ||
621 | |||
622 | if (WARN_ON(d->hwirq >= pctrl->soc->ngroups)) | ||
623 | return; | ||
624 | |||
625 | g = &pctrl->soc->groups[d->hwirq]; | ||
626 | |||
627 | spin_lock_irqsave(&pctrl->lock, flags); | ||
628 | |||
629 | val = readl(pctrl->regs + g->intr_cfg_reg); | ||
630 | val &= ~BIT(g->intr_enable_bit); | ||
631 | writel(val, pctrl->regs + g->intr_cfg_reg); | ||
632 | |||
633 | clear_bit(d->hwirq, pctrl->enabled_irqs); | ||
634 | |||
635 | spin_unlock_irqrestore(&pctrl->lock, flags); | ||
636 | } | ||
637 | |||
638 | static void msm_gpio_irq_unmask(struct irq_data *d) | ||
639 | { | ||
640 | const struct msm_pingroup *g; | ||
641 | struct msm_pinctrl *pctrl; | ||
642 | unsigned long flags; | ||
643 | u32 val; | ||
644 | |||
645 | pctrl = irq_data_get_irq_chip_data(d); | ||
646 | if (!pctrl) | ||
647 | return; | ||
648 | |||
649 | if (WARN_ON(d->hwirq >= pctrl->soc->ngroups)) | ||
650 | return; | ||
651 | |||
652 | g = &pctrl->soc->groups[d->hwirq]; | ||
653 | |||
654 | spin_lock_irqsave(&pctrl->lock, flags); | ||
655 | |||
656 | val = readl(pctrl->regs + g->intr_status_reg); | ||
657 | val &= ~BIT(g->intr_status_bit); | ||
658 | writel(val, pctrl->regs + g->intr_status_reg); | ||
659 | |||
660 | val = readl(pctrl->regs + g->intr_cfg_reg); | ||
661 | val |= BIT(g->intr_enable_bit); | ||
662 | writel(val, pctrl->regs + g->intr_cfg_reg); | ||
663 | |||
664 | set_bit(d->hwirq, pctrl->enabled_irqs); | ||
665 | |||
666 | spin_unlock_irqrestore(&pctrl->lock, flags); | ||
667 | } | ||
668 | |||
669 | static void msm_gpio_irq_ack(struct irq_data *d) | ||
670 | { | ||
671 | const struct msm_pingroup *g; | ||
672 | struct msm_pinctrl *pctrl; | ||
673 | unsigned long flags; | ||
674 | u32 val; | ||
675 | |||
676 | pctrl = irq_data_get_irq_chip_data(d); | ||
677 | if (!pctrl) | ||
678 | return; | ||
679 | |||
680 | if (WARN_ON(d->hwirq >= pctrl->soc->ngroups)) | ||
681 | return; | ||
682 | |||
683 | g = &pctrl->soc->groups[d->hwirq]; | ||
684 | |||
685 | spin_lock_irqsave(&pctrl->lock, flags); | ||
686 | |||
687 | val = readl(pctrl->regs + g->intr_status_reg); | ||
688 | val &= ~BIT(g->intr_status_bit); | ||
689 | writel(val, pctrl->regs + g->intr_status_reg); | ||
690 | |||
691 | if (test_bit(d->hwirq, pctrl->dual_edge_irqs)) | ||
692 | msm_gpio_update_dual_edge_pos(pctrl, g, d); | ||
693 | |||
694 | spin_unlock_irqrestore(&pctrl->lock, flags); | ||
695 | } | ||
696 | |||
697 | #define INTR_TARGET_PROC_APPS 4 | ||
698 | |||
699 | static int msm_gpio_irq_set_type(struct irq_data *d, unsigned int type) | ||
700 | { | ||
701 | const struct msm_pingroup *g; | ||
702 | struct msm_pinctrl *pctrl; | ||
703 | unsigned long flags; | ||
704 | u32 val; | ||
705 | |||
706 | pctrl = irq_data_get_irq_chip_data(d); | ||
707 | if (!pctrl) | ||
708 | return -EINVAL; | ||
709 | |||
710 | if (WARN_ON(d->hwirq >= pctrl->soc->ngroups)) | ||
711 | return -EINVAL; | ||
712 | |||
713 | g = &pctrl->soc->groups[d->hwirq]; | ||
714 | |||
715 | spin_lock_irqsave(&pctrl->lock, flags); | ||
716 | |||
717 | /* | ||
718 | * For hw without possibility of detecting both edges | ||
719 | */ | ||
720 | if (g->intr_detection_width == 1 && type == IRQ_TYPE_EDGE_BOTH) | ||
721 | set_bit(d->hwirq, pctrl->dual_edge_irqs); | ||
722 | else | ||
723 | clear_bit(d->hwirq, pctrl->dual_edge_irqs); | ||
724 | |||
725 | /* Route interrupts to application cpu */ | ||
726 | val = readl(pctrl->regs + g->intr_target_reg); | ||
727 | val &= ~(7 << g->intr_target_bit); | ||
728 | val |= INTR_TARGET_PROC_APPS << g->intr_target_bit; | ||
729 | writel(val, pctrl->regs + g->intr_target_reg); | ||
730 | |||
731 | /* Update configuration for gpio. | ||
732 | * RAW_STATUS_EN is left on for all gpio irqs. Due to the | ||
733 | * internal circuitry of TLMM, toggling the RAW_STATUS | ||
734 | * could cause the INTR_STATUS to be set for EDGE interrupts. | ||
735 | */ | ||
736 | val = readl(pctrl->regs + g->intr_cfg_reg); | ||
737 | val |= BIT(g->intr_raw_status_bit); | ||
738 | if (g->intr_detection_width == 2) { | ||
739 | val &= ~(3 << g->intr_detection_bit); | ||
740 | val &= ~(1 << g->intr_polarity_bit); | ||
741 | switch (type) { | ||
742 | case IRQ_TYPE_EDGE_RISING: | ||
743 | val |= 1 << g->intr_detection_bit; | ||
744 | val |= BIT(g->intr_polarity_bit); | ||
745 | break; | ||
746 | case IRQ_TYPE_EDGE_FALLING: | ||
747 | val |= 2 << g->intr_detection_bit; | ||
748 | val |= BIT(g->intr_polarity_bit); | ||
749 | break; | ||
750 | case IRQ_TYPE_EDGE_BOTH: | ||
751 | val |= 3 << g->intr_detection_bit; | ||
752 | val |= BIT(g->intr_polarity_bit); | ||
753 | break; | ||
754 | case IRQ_TYPE_LEVEL_LOW: | ||
755 | break; | ||
756 | case IRQ_TYPE_LEVEL_HIGH: | ||
757 | val |= BIT(g->intr_polarity_bit); | ||
758 | break; | ||
759 | } | ||
760 | } else if (g->intr_detection_width == 1) { | ||
761 | val &= ~(1 << g->intr_detection_bit); | ||
762 | val &= ~(1 << g->intr_polarity_bit); | ||
763 | switch (type) { | ||
764 | case IRQ_TYPE_EDGE_RISING: | ||
765 | val |= BIT(g->intr_detection_bit); | ||
766 | val |= BIT(g->intr_polarity_bit); | ||
767 | break; | ||
768 | case IRQ_TYPE_EDGE_FALLING: | ||
769 | val |= BIT(g->intr_detection_bit); | ||
770 | break; | ||
771 | case IRQ_TYPE_EDGE_BOTH: | ||
772 | val |= BIT(g->intr_detection_bit); | ||
773 | break; | ||
774 | case IRQ_TYPE_LEVEL_LOW: | ||
775 | break; | ||
776 | case IRQ_TYPE_LEVEL_HIGH: | ||
777 | val |= BIT(g->intr_polarity_bit); | ||
778 | break; | ||
779 | } | ||
780 | } else { | ||
781 | BUG(); | ||
782 | } | ||
783 | writel(val, pctrl->regs + g->intr_cfg_reg); | ||
784 | |||
785 | if (test_bit(d->hwirq, pctrl->dual_edge_irqs)) | ||
786 | msm_gpio_update_dual_edge_pos(pctrl, g, d); | ||
787 | |||
788 | spin_unlock_irqrestore(&pctrl->lock, flags); | ||
789 | |||
790 | if (type & (IRQ_TYPE_LEVEL_LOW | IRQ_TYPE_LEVEL_HIGH)) | ||
791 | __irq_set_handler_locked(d->irq, handle_level_irq); | ||
792 | else if (type & (IRQ_TYPE_EDGE_FALLING | IRQ_TYPE_EDGE_RISING)) | ||
793 | __irq_set_handler_locked(d->irq, handle_edge_irq); | ||
794 | |||
795 | return 0; | ||
796 | } | ||
797 | |||
798 | static int msm_gpio_irq_set_wake(struct irq_data *d, unsigned int on) | ||
799 | { | ||
800 | struct msm_pinctrl *pctrl; | ||
801 | unsigned long flags; | ||
802 | unsigned ngpio; | ||
803 | |||
804 | pctrl = irq_data_get_irq_chip_data(d); | ||
805 | if (!pctrl) | ||
806 | return -EINVAL; | ||
807 | |||
808 | ngpio = pctrl->chip.ngpio; | ||
809 | |||
810 | spin_lock_irqsave(&pctrl->lock, flags); | ||
811 | |||
812 | if (on) { | ||
813 | if (bitmap_empty(pctrl->wake_irqs, ngpio)) | ||
814 | enable_irq_wake(pctrl->irq); | ||
815 | set_bit(d->hwirq, pctrl->wake_irqs); | ||
816 | } else { | ||
817 | clear_bit(d->hwirq, pctrl->wake_irqs); | ||
818 | if (bitmap_empty(pctrl->wake_irqs, ngpio)) | ||
819 | disable_irq_wake(pctrl->irq); | ||
820 | } | ||
821 | |||
822 | spin_unlock_irqrestore(&pctrl->lock, flags); | ||
823 | |||
824 | return 0; | ||
825 | } | ||
826 | |||
827 | static unsigned int msm_gpio_irq_startup(struct irq_data *d) | ||
828 | { | ||
829 | struct msm_pinctrl *pctrl = irq_data_get_irq_chip_data(d); | ||
830 | |||
831 | if (gpio_lock_as_irq(&pctrl->chip, d->hwirq)) { | ||
832 | dev_err(pctrl->dev, "unable to lock HW IRQ %lu for IRQ\n", | ||
833 | d->hwirq); | ||
834 | } | ||
835 | msm_gpio_irq_unmask(d); | ||
836 | return 0; | ||
837 | } | ||
838 | |||
839 | static void msm_gpio_irq_shutdown(struct irq_data *d) | ||
840 | { | ||
841 | struct msm_pinctrl *pctrl = irq_data_get_irq_chip_data(d); | ||
842 | |||
843 | msm_gpio_irq_mask(d); | ||
844 | gpio_unlock_as_irq(&pctrl->chip, d->hwirq); | ||
845 | } | ||
846 | |||
847 | static struct irq_chip msm_gpio_irq_chip = { | ||
848 | .name = "msmgpio", | ||
849 | .irq_mask = msm_gpio_irq_mask, | ||
850 | .irq_unmask = msm_gpio_irq_unmask, | ||
851 | .irq_ack = msm_gpio_irq_ack, | ||
852 | .irq_set_type = msm_gpio_irq_set_type, | ||
853 | .irq_set_wake = msm_gpio_irq_set_wake, | ||
854 | .irq_startup = msm_gpio_irq_startup, | ||
855 | .irq_shutdown = msm_gpio_irq_shutdown, | ||
856 | }; | ||
857 | |||
858 | static void msm_gpio_irq_handler(unsigned int irq, struct irq_desc *desc) | ||
859 | { | ||
860 | const struct msm_pingroup *g; | ||
861 | struct msm_pinctrl *pctrl = irq_desc_get_handler_data(desc); | ||
862 | struct irq_chip *chip = irq_get_chip(irq); | ||
863 | int irq_pin; | ||
864 | int handled = 0; | ||
865 | u32 val; | ||
866 | int i; | ||
867 | |||
868 | chained_irq_enter(chip, desc); | ||
869 | |||
870 | /* | ||
871 | * Each pin have it's own IRQ status register, so use | ||
872 | * enabled_irq bitmap to limit the number of reads. | ||
873 | */ | ||
874 | for_each_set_bit(i, pctrl->enabled_irqs, pctrl->chip.ngpio) { | ||
875 | g = &pctrl->soc->groups[i]; | ||
876 | val = readl(pctrl->regs + g->intr_status_reg); | ||
877 | if (val & BIT(g->intr_status_bit)) { | ||
878 | irq_pin = irq_find_mapping(pctrl->domain, i); | ||
879 | generic_handle_irq(irq_pin); | ||
880 | handled++; | ||
881 | } | ||
882 | } | ||
883 | |||
884 | /* No interrutps where flagged */ | ||
885 | if (handled == 0) | ||
886 | handle_bad_irq(irq, desc); | ||
887 | |||
888 | chained_irq_exit(chip, desc); | ||
889 | } | ||
890 | |||
891 | static int msm_gpio_init(struct msm_pinctrl *pctrl) | ||
892 | { | ||
893 | struct gpio_chip *chip; | ||
894 | int irq; | ||
895 | int ret; | ||
896 | int i; | ||
897 | int r; | ||
898 | |||
899 | chip = &pctrl->chip; | ||
900 | chip->base = 0; | ||
901 | chip->ngpio = pctrl->soc->ngpios; | ||
902 | chip->label = dev_name(pctrl->dev); | ||
903 | chip->dev = pctrl->dev; | ||
904 | chip->owner = THIS_MODULE; | ||
905 | chip->of_node = pctrl->dev->of_node; | ||
906 | |||
907 | pctrl->enabled_irqs = devm_kzalloc(pctrl->dev, | ||
908 | sizeof(unsigned long) * BITS_TO_LONGS(chip->ngpio), | ||
909 | GFP_KERNEL); | ||
910 | if (!pctrl->enabled_irqs) { | ||
911 | dev_err(pctrl->dev, "Failed to allocate enabled_irqs bitmap\n"); | ||
912 | return -ENOMEM; | ||
913 | } | ||
914 | |||
915 | pctrl->dual_edge_irqs = devm_kzalloc(pctrl->dev, | ||
916 | sizeof(unsigned long) * BITS_TO_LONGS(chip->ngpio), | ||
917 | GFP_KERNEL); | ||
918 | if (!pctrl->dual_edge_irqs) { | ||
919 | dev_err(pctrl->dev, "Failed to allocate dual_edge_irqs bitmap\n"); | ||
920 | return -ENOMEM; | ||
921 | } | ||
922 | |||
923 | pctrl->wake_irqs = devm_kzalloc(pctrl->dev, | ||
924 | sizeof(unsigned long) * BITS_TO_LONGS(chip->ngpio), | ||
925 | GFP_KERNEL); | ||
926 | if (!pctrl->wake_irqs) { | ||
927 | dev_err(pctrl->dev, "Failed to allocate wake_irqs bitmap\n"); | ||
928 | return -ENOMEM; | ||
929 | } | ||
930 | |||
931 | ret = gpiochip_add(&pctrl->chip); | ||
932 | if (ret) { | ||
933 | dev_err(pctrl->dev, "Failed register gpiochip\n"); | ||
934 | return ret; | ||
935 | } | ||
936 | |||
937 | ret = gpiochip_add_pin_range(&pctrl->chip, dev_name(pctrl->dev), 0, 0, chip->ngpio); | ||
938 | if (ret) { | ||
939 | dev_err(pctrl->dev, "Failed to add pin range\n"); | ||
940 | return ret; | ||
941 | } | ||
942 | |||
943 | pctrl->domain = irq_domain_add_linear(pctrl->dev->of_node, chip->ngpio, | ||
944 | &irq_domain_simple_ops, NULL); | ||
945 | if (!pctrl->domain) { | ||
946 | dev_err(pctrl->dev, "Failed to register irq domain\n"); | ||
947 | r = gpiochip_remove(&pctrl->chip); | ||
948 | return -ENOSYS; | ||
949 | } | ||
950 | |||
951 | for (i = 0; i < chip->ngpio; i++) { | ||
952 | irq = irq_create_mapping(pctrl->domain, i); | ||
953 | irq_set_chip_and_handler(irq, &msm_gpio_irq_chip, handle_edge_irq); | ||
954 | irq_set_chip_data(irq, pctrl); | ||
955 | } | ||
956 | |||
957 | irq_set_handler_data(pctrl->irq, pctrl); | ||
958 | irq_set_chained_handler(pctrl->irq, msm_gpio_irq_handler); | ||
959 | |||
960 | return 0; | ||
961 | } | ||
962 | |||
963 | int msm_pinctrl_probe(struct platform_device *pdev, | ||
964 | const struct msm_pinctrl_soc_data *soc_data) | ||
965 | { | ||
966 | struct msm_pinctrl *pctrl; | ||
967 | struct resource *res; | ||
968 | int ret; | ||
969 | |||
970 | pctrl = devm_kzalloc(&pdev->dev, sizeof(*pctrl), GFP_KERNEL); | ||
971 | if (!pctrl) { | ||
972 | dev_err(&pdev->dev, "Can't allocate msm_pinctrl\n"); | ||
973 | return -ENOMEM; | ||
974 | } | ||
975 | pctrl->dev = &pdev->dev; | ||
976 | pctrl->soc = soc_data; | ||
977 | pctrl->chip = msm_gpio_template; | ||
978 | |||
979 | spin_lock_init(&pctrl->lock); | ||
980 | |||
981 | res = platform_get_resource(pdev, IORESOURCE_MEM, 0); | ||
982 | pctrl->regs = devm_ioremap_resource(&pdev->dev, res); | ||
983 | if (IS_ERR(pctrl->regs)) | ||
984 | return PTR_ERR(pctrl->regs); | ||
985 | |||
986 | pctrl->irq = irq_of_parse_and_map(pdev->dev.of_node, 0); | ||
987 | if (pctrl->irq < 0) { | ||
988 | dev_err(&pdev->dev, "No interrupt defined for msmgpio\n"); | ||
989 | return pctrl->irq; | ||
990 | } | ||
991 | |||
992 | msm_pinctrl_desc.name = dev_name(&pdev->dev); | ||
993 | msm_pinctrl_desc.pins = pctrl->soc->pins; | ||
994 | msm_pinctrl_desc.npins = pctrl->soc->npins; | ||
995 | pctrl->pctrl = pinctrl_register(&msm_pinctrl_desc, &pdev->dev, pctrl); | ||
996 | if (!pctrl->pctrl) { | ||
997 | dev_err(&pdev->dev, "Couldn't register pinctrl driver\n"); | ||
998 | return -ENODEV; | ||
999 | } | ||
1000 | |||
1001 | ret = msm_gpio_init(pctrl); | ||
1002 | if (ret) { | ||
1003 | pinctrl_unregister(pctrl->pctrl); | ||
1004 | return ret; | ||
1005 | } | ||
1006 | |||
1007 | platform_set_drvdata(pdev, pctrl); | ||
1008 | |||
1009 | dev_dbg(&pdev->dev, "Probed Qualcomm pinctrl driver\n"); | ||
1010 | |||
1011 | return 0; | ||
1012 | } | ||
1013 | EXPORT_SYMBOL(msm_pinctrl_probe); | ||
1014 | |||
1015 | int msm_pinctrl_remove(struct platform_device *pdev) | ||
1016 | { | ||
1017 | struct msm_pinctrl *pctrl = platform_get_drvdata(pdev); | ||
1018 | int ret; | ||
1019 | |||
1020 | irq_set_chained_handler(pctrl->irq, NULL); | ||
1021 | irq_domain_remove(pctrl->domain); | ||
1022 | ret = gpiochip_remove(&pctrl->chip); | ||
1023 | pinctrl_unregister(pctrl->pctrl); | ||
1024 | |||
1025 | return 0; | ||
1026 | } | ||
1027 | EXPORT_SYMBOL(msm_pinctrl_remove); | ||
1028 | |||
diff --git a/drivers/pinctrl/pinctrl-msm.h b/drivers/pinctrl/pinctrl-msm.h new file mode 100644 index 000000000000..206e782e2daa --- /dev/null +++ b/drivers/pinctrl/pinctrl-msm.h | |||
@@ -0,0 +1,122 @@ | |||
1 | /* | ||
2 | * Copyright (c) 2013, Sony Mobile Communications AB. | ||
3 | * | ||
4 | * This program is free software; you can redistribute it and/or modify | ||
5 | * it under the terms of the GNU General Public License version 2 and | ||
6 | * only version 2 as published by the Free Software Foundation. | ||
7 | * | ||
8 | * This program is distributed in the hope that it will be useful, | ||
9 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
10 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
11 | * GNU General Public License for more details. | ||
12 | */ | ||
13 | #ifndef __PINCTRL_MSM_H__ | ||
14 | #define __PINCTRL_MSM_H__ | ||
15 | |||
16 | #include <linux/pinctrl/pinctrl.h> | ||
17 | #include <linux/pinctrl/pinmux.h> | ||
18 | #include <linux/pinctrl/pinconf.h> | ||
19 | #include <linux/pinctrl/machine.h> | ||
20 | |||
21 | /** | ||
22 | * struct msm_function - a pinmux function | ||
23 | * @name: Name of the pinmux function. | ||
24 | * @groups: List of pingroups for this function. | ||
25 | * @ngroups: Number of entries in @groups. | ||
26 | */ | ||
27 | struct msm_function { | ||
28 | const char *name; | ||
29 | const char * const *groups; | ||
30 | unsigned ngroups; | ||
31 | }; | ||
32 | |||
33 | /** | ||
34 | * struct msm_pingroup - Qualcomm pingroup definition | ||
35 | * @name: Name of the pingroup. | ||
36 | * @pins: A list of pins assigned to this pingroup. | ||
37 | * @npins: Number of entries in @pins. | ||
38 | * @funcs: A list of pinmux functions that can be selected for | ||
39 | * this group. The index of the selected function is used | ||
40 | * for programming the function selector. | ||
41 | * Entries should be indices into the groups list of the | ||
42 | * struct msm_pinctrl_soc_data. | ||
43 | * @ctl_reg: Offset of the register holding control bits for this group. | ||
44 | * @io_reg: Offset of the register holding input/output bits for this group. | ||
45 | * @intr_cfg_reg: Offset of the register holding interrupt configuration bits. | ||
46 | * @intr_status_reg: Offset of the register holding the status bits for this group. | ||
47 | * @intr_target_reg: Offset of the register specifying routing of the interrupts | ||
48 | * from this group. | ||
49 | * @mux_bit: Offset in @ctl_reg for the pinmux function selection. | ||
50 | * @pull_bit: Offset in @ctl_reg for the bias configuration. | ||
51 | * @drv_bit: Offset in @ctl_reg for the drive strength configuration. | ||
52 | * @oe_bit: Offset in @ctl_reg for controlling output enable. | ||
53 | * @in_bit: Offset in @io_reg for the input bit value. | ||
54 | * @out_bit: Offset in @io_reg for the output bit value. | ||
55 | * @intr_enable_bit: Offset in @intr_cfg_reg for enabling the interrupt for this group. | ||
56 | * @intr_status_bit: Offset in @intr_status_reg for reading and acking the interrupt | ||
57 | * status. | ||
58 | * @intr_target_bit: Offset in @intr_target_reg for configuring the interrupt routing. | ||
59 | * @intr_raw_status_bit: Offset in @intr_cfg_reg for the raw status bit. | ||
60 | * @intr_polarity_bit: Offset in @intr_cfg_reg for specifying polarity of the interrupt. | ||
61 | * @intr_detection_bit: Offset in @intr_cfg_reg for specifying interrupt type. | ||
62 | * @intr_detection_width: Number of bits used for specifying interrupt type, | ||
63 | * Should be 2 for SoCs that can detect both edges in hardware, | ||
64 | * otherwise 1. | ||
65 | */ | ||
66 | struct msm_pingroup { | ||
67 | const char *name; | ||
68 | const unsigned *pins; | ||
69 | unsigned npins; | ||
70 | |||
71 | unsigned funcs[8]; | ||
72 | |||
73 | s16 ctl_reg; | ||
74 | s16 io_reg; | ||
75 | s16 intr_cfg_reg; | ||
76 | s16 intr_status_reg; | ||
77 | s16 intr_target_reg; | ||
78 | |||
79 | unsigned mux_bit:5; | ||
80 | |||
81 | unsigned pull_bit:5; | ||
82 | unsigned drv_bit:5; | ||
83 | |||
84 | unsigned oe_bit:5; | ||
85 | unsigned in_bit:5; | ||
86 | unsigned out_bit:5; | ||
87 | |||
88 | unsigned intr_enable_bit:5; | ||
89 | unsigned intr_status_bit:5; | ||
90 | |||
91 | unsigned intr_target_bit:5; | ||
92 | unsigned intr_raw_status_bit:5; | ||
93 | unsigned intr_polarity_bit:5; | ||
94 | unsigned intr_detection_bit:5; | ||
95 | unsigned intr_detection_width:5; | ||
96 | }; | ||
97 | |||
98 | /** | ||
99 | * struct msm_pinctrl_soc_data - Qualcomm pin controller driver configuration | ||
100 | * @pins: An array describing all pins the pin controller affects. | ||
101 | * @npins: The number of entries in @pins. | ||
102 | * @functions: An array describing all mux functions the SoC supports. | ||
103 | * @nfunctions: The number of entries in @functions. | ||
104 | * @groups: An array describing all pin groups the pin SoC supports. | ||
105 | * @ngroups: The numbmer of entries in @groups. | ||
106 | * @ngpio: The number of pingroups the driver should expose as GPIOs. | ||
107 | */ | ||
108 | struct msm_pinctrl_soc_data { | ||
109 | const struct pinctrl_pin_desc *pins; | ||
110 | unsigned npins; | ||
111 | const struct msm_function *functions; | ||
112 | unsigned nfunctions; | ||
113 | const struct msm_pingroup *groups; | ||
114 | unsigned ngroups; | ||
115 | unsigned ngpios; | ||
116 | }; | ||
117 | |||
118 | int msm_pinctrl_probe(struct platform_device *pdev, | ||
119 | const struct msm_pinctrl_soc_data *soc_data); | ||
120 | int msm_pinctrl_remove(struct platform_device *pdev); | ||
121 | |||
122 | #endif | ||