diff options
Diffstat (limited to 'drivers/pinctrl/pinctrl-msm.c')
-rw-r--r-- | drivers/pinctrl/pinctrl-msm.c | 990 |
1 files changed, 990 insertions, 0 deletions
diff --git a/drivers/pinctrl/pinctrl-msm.c b/drivers/pinctrl/pinctrl-msm.c new file mode 100644 index 000000000000..ef2bf3126da6 --- /dev/null +++ b/drivers/pinctrl/pinctrl-msm.c | |||
@@ -0,0 +1,990 @@ | |||
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 | #define MAX_NR_GPIO 300 | ||
40 | |||
41 | /** | ||
42 | * struct msm_pinctrl - state for a pinctrl-msm device | ||
43 | * @dev: device handle. | ||
44 | * @pctrl: pinctrl handle. | ||
45 | * @domain: irqdomain handle. | ||
46 | * @chip: gpiochip handle. | ||
47 | * @irq: parent irq for the TLMM irq_chip. | ||
48 | * @lock: Spinlock to protect register resources as well | ||
49 | * as msm_pinctrl data structures. | ||
50 | * @enabled_irqs: Bitmap of currently enabled irqs. | ||
51 | * @dual_edge_irqs: Bitmap of irqs that need sw emulated dual edge | ||
52 | * detection. | ||
53 | * @wake_irqs: Bitmap of irqs with requested as wakeup source. | ||
54 | * @soc; Reference to soc_data of platform specific data. | ||
55 | * @regs: Base address for the TLMM register map. | ||
56 | */ | ||
57 | struct msm_pinctrl { | ||
58 | struct device *dev; | ||
59 | struct pinctrl_dev *pctrl; | ||
60 | struct irq_domain *domain; | ||
61 | struct gpio_chip chip; | ||
62 | int irq; | ||
63 | |||
64 | spinlock_t lock; | ||
65 | |||
66 | DECLARE_BITMAP(dual_edge_irqs, MAX_NR_GPIO); | ||
67 | DECLARE_BITMAP(enabled_irqs, MAX_NR_GPIO); | ||
68 | DECLARE_BITMAP(wake_irqs, MAX_NR_GPIO); | ||
69 | |||
70 | const struct msm_pinctrl_soc_data *soc; | ||
71 | void __iomem *regs; | ||
72 | }; | ||
73 | |||
74 | static int msm_get_groups_count(struct pinctrl_dev *pctldev) | ||
75 | { | ||
76 | struct msm_pinctrl *pctrl = pinctrl_dev_get_drvdata(pctldev); | ||
77 | |||
78 | return pctrl->soc->ngroups; | ||
79 | } | ||
80 | |||
81 | static const char *msm_get_group_name(struct pinctrl_dev *pctldev, | ||
82 | unsigned group) | ||
83 | { | ||
84 | struct msm_pinctrl *pctrl = pinctrl_dev_get_drvdata(pctldev); | ||
85 | |||
86 | return pctrl->soc->groups[group].name; | ||
87 | } | ||
88 | |||
89 | static int msm_get_group_pins(struct pinctrl_dev *pctldev, | ||
90 | unsigned group, | ||
91 | const unsigned **pins, | ||
92 | unsigned *num_pins) | ||
93 | { | ||
94 | struct msm_pinctrl *pctrl = pinctrl_dev_get_drvdata(pctldev); | ||
95 | |||
96 | *pins = pctrl->soc->groups[group].pins; | ||
97 | *num_pins = pctrl->soc->groups[group].npins; | ||
98 | return 0; | ||
99 | } | ||
100 | |||
101 | static const struct pinctrl_ops msm_pinctrl_ops = { | ||
102 | .get_groups_count = msm_get_groups_count, | ||
103 | .get_group_name = msm_get_group_name, | ||
104 | .get_group_pins = msm_get_group_pins, | ||
105 | .dt_node_to_map = pinconf_generic_dt_node_to_map_group, | ||
106 | .dt_free_map = pinctrl_utils_dt_free_map, | ||
107 | }; | ||
108 | |||
109 | static int msm_get_functions_count(struct pinctrl_dev *pctldev) | ||
110 | { | ||
111 | struct msm_pinctrl *pctrl = pinctrl_dev_get_drvdata(pctldev); | ||
112 | |||
113 | return pctrl->soc->nfunctions; | ||
114 | } | ||
115 | |||
116 | static const char *msm_get_function_name(struct pinctrl_dev *pctldev, | ||
117 | unsigned function) | ||
118 | { | ||
119 | struct msm_pinctrl *pctrl = pinctrl_dev_get_drvdata(pctldev); | ||
120 | |||
121 | return pctrl->soc->functions[function].name; | ||
122 | } | ||
123 | |||
124 | static int msm_get_function_groups(struct pinctrl_dev *pctldev, | ||
125 | unsigned function, | ||
126 | const char * const **groups, | ||
127 | unsigned * const num_groups) | ||
128 | { | ||
129 | struct msm_pinctrl *pctrl = pinctrl_dev_get_drvdata(pctldev); | ||
130 | |||
131 | *groups = pctrl->soc->functions[function].groups; | ||
132 | *num_groups = pctrl->soc->functions[function].ngroups; | ||
133 | return 0; | ||
134 | } | ||
135 | |||
136 | static int msm_pinmux_enable(struct pinctrl_dev *pctldev, | ||
137 | unsigned function, | ||
138 | unsigned group) | ||
139 | { | ||
140 | struct msm_pinctrl *pctrl = pinctrl_dev_get_drvdata(pctldev); | ||
141 | const struct msm_pingroup *g; | ||
142 | unsigned long flags; | ||
143 | u32 val; | ||
144 | int i; | ||
145 | |||
146 | g = &pctrl->soc->groups[group]; | ||
147 | |||
148 | if (WARN_ON(g->mux_bit < 0)) | ||
149 | return -EINVAL; | ||
150 | |||
151 | for (i = 0; i < ARRAY_SIZE(g->funcs); i++) { | ||
152 | if (g->funcs[i] == function) | ||
153 | break; | ||
154 | } | ||
155 | |||
156 | if (WARN_ON(i == ARRAY_SIZE(g->funcs))) | ||
157 | return -EINVAL; | ||
158 | |||
159 | spin_lock_irqsave(&pctrl->lock, flags); | ||
160 | |||
161 | val = readl(pctrl->regs + g->ctl_reg); | ||
162 | val &= ~(0x7 << g->mux_bit); | ||
163 | val |= i << g->mux_bit; | ||
164 | writel(val, pctrl->regs + g->ctl_reg); | ||
165 | |||
166 | spin_unlock_irqrestore(&pctrl->lock, flags); | ||
167 | |||
168 | return 0; | ||
169 | } | ||
170 | |||
171 | static void msm_pinmux_disable(struct pinctrl_dev *pctldev, | ||
172 | unsigned function, | ||
173 | unsigned group) | ||
174 | { | ||
175 | struct msm_pinctrl *pctrl = pinctrl_dev_get_drvdata(pctldev); | ||
176 | const struct msm_pingroup *g; | ||
177 | unsigned long flags; | ||
178 | u32 val; | ||
179 | |||
180 | g = &pctrl->soc->groups[group]; | ||
181 | |||
182 | if (WARN_ON(g->mux_bit < 0)) | ||
183 | return; | ||
184 | |||
185 | spin_lock_irqsave(&pctrl->lock, flags); | ||
186 | |||
187 | /* Clear the mux bits to select gpio mode */ | ||
188 | val = readl(pctrl->regs + g->ctl_reg); | ||
189 | val &= ~(0x7 << g->mux_bit); | ||
190 | writel(val, pctrl->regs + g->ctl_reg); | ||
191 | |||
192 | spin_unlock_irqrestore(&pctrl->lock, flags); | ||
193 | } | ||
194 | |||
195 | static const struct pinmux_ops msm_pinmux_ops = { | ||
196 | .get_functions_count = msm_get_functions_count, | ||
197 | .get_function_name = msm_get_function_name, | ||
198 | .get_function_groups = msm_get_function_groups, | ||
199 | .enable = msm_pinmux_enable, | ||
200 | .disable = msm_pinmux_disable, | ||
201 | }; | ||
202 | |||
203 | static int msm_config_reg(struct msm_pinctrl *pctrl, | ||
204 | const struct msm_pingroup *g, | ||
205 | unsigned param, | ||
206 | s16 *reg, | ||
207 | unsigned *mask, | ||
208 | unsigned *bit) | ||
209 | { | ||
210 | switch (param) { | ||
211 | case PIN_CONFIG_BIAS_DISABLE: | ||
212 | *reg = g->ctl_reg; | ||
213 | *bit = g->pull_bit; | ||
214 | *mask = 3; | ||
215 | break; | ||
216 | case PIN_CONFIG_BIAS_PULL_DOWN: | ||
217 | *reg = g->ctl_reg; | ||
218 | *bit = g->pull_bit; | ||
219 | *mask = 3; | ||
220 | break; | ||
221 | case PIN_CONFIG_BIAS_PULL_UP: | ||
222 | *reg = g->ctl_reg; | ||
223 | *bit = g->pull_bit; | ||
224 | *mask = 3; | ||
225 | break; | ||
226 | case PIN_CONFIG_DRIVE_STRENGTH: | ||
227 | *reg = g->ctl_reg; | ||
228 | *bit = g->drv_bit; | ||
229 | *mask = 7; | ||
230 | break; | ||
231 | default: | ||
232 | dev_err(pctrl->dev, "Invalid config param %04x\n", param); | ||
233 | return -ENOTSUPP; | ||
234 | } | ||
235 | |||
236 | if (*reg < 0) { | ||
237 | dev_err(pctrl->dev, "Config param %04x not supported on group %s\n", | ||
238 | param, g->name); | ||
239 | return -ENOTSUPP; | ||
240 | } | ||
241 | |||
242 | return 0; | ||
243 | } | ||
244 | |||
245 | static int msm_config_get(struct pinctrl_dev *pctldev, | ||
246 | unsigned int pin, | ||
247 | unsigned long *config) | ||
248 | { | ||
249 | dev_err(pctldev->dev, "pin_config_set op not supported\n"); | ||
250 | return -ENOTSUPP; | ||
251 | } | ||
252 | |||
253 | static int msm_config_set(struct pinctrl_dev *pctldev, unsigned int pin, | ||
254 | unsigned long *configs, unsigned num_configs) | ||
255 | { | ||
256 | dev_err(pctldev->dev, "pin_config_set op not supported\n"); | ||
257 | return -ENOTSUPP; | ||
258 | } | ||
259 | |||
260 | #define MSM_NO_PULL 0 | ||
261 | #define MSM_PULL_DOWN 1 | ||
262 | #define MSM_PULL_UP 3 | ||
263 | |||
264 | static const unsigned msm_regval_to_drive[] = { 2, 4, 6, 8, 10, 12, 14, 16 }; | ||
265 | static const unsigned msm_drive_to_regval[] = { -1, -1, 0, -1, 1, -1, 2, -1, 3, -1, 4, -1, 5, -1, 6, -1, 7 }; | ||
266 | |||
267 | static int msm_config_group_get(struct pinctrl_dev *pctldev, | ||
268 | unsigned int group, | ||
269 | unsigned long *config) | ||
270 | { | ||
271 | const struct msm_pingroup *g; | ||
272 | struct msm_pinctrl *pctrl = pinctrl_dev_get_drvdata(pctldev); | ||
273 | unsigned param = pinconf_to_config_param(*config); | ||
274 | unsigned mask; | ||
275 | unsigned arg; | ||
276 | unsigned bit; | ||
277 | s16 reg; | ||
278 | int ret; | ||
279 | u32 val; | ||
280 | |||
281 | g = &pctrl->soc->groups[group]; | ||
282 | |||
283 | ret = msm_config_reg(pctrl, g, param, ®, &mask, &bit); | ||
284 | if (ret < 0) | ||
285 | return ret; | ||
286 | |||
287 | val = readl(pctrl->regs + reg); | ||
288 | arg = (val >> bit) & mask; | ||
289 | |||
290 | /* Convert register value to pinconf value */ | ||
291 | switch (param) { | ||
292 | case PIN_CONFIG_BIAS_DISABLE: | ||
293 | arg = arg == MSM_NO_PULL; | ||
294 | break; | ||
295 | case PIN_CONFIG_BIAS_PULL_DOWN: | ||
296 | arg = arg == MSM_PULL_DOWN; | ||
297 | break; | ||
298 | case PIN_CONFIG_BIAS_PULL_UP: | ||
299 | arg = arg == MSM_PULL_UP; | ||
300 | break; | ||
301 | case PIN_CONFIG_DRIVE_STRENGTH: | ||
302 | arg = msm_regval_to_drive[arg]; | ||
303 | break; | ||
304 | default: | ||
305 | dev_err(pctrl->dev, "Unsupported config parameter: %x\n", | ||
306 | param); | ||
307 | return -EINVAL; | ||
308 | } | ||
309 | |||
310 | *config = pinconf_to_config_packed(param, arg); | ||
311 | |||
312 | return 0; | ||
313 | } | ||
314 | |||
315 | static int msm_config_group_set(struct pinctrl_dev *pctldev, | ||
316 | unsigned group, | ||
317 | unsigned long *configs, | ||
318 | unsigned num_configs) | ||
319 | { | ||
320 | const struct msm_pingroup *g; | ||
321 | struct msm_pinctrl *pctrl = pinctrl_dev_get_drvdata(pctldev); | ||
322 | unsigned long flags; | ||
323 | unsigned param; | ||
324 | unsigned mask; | ||
325 | unsigned arg; | ||
326 | unsigned bit; | ||
327 | s16 reg; | ||
328 | int ret; | ||
329 | u32 val; | ||
330 | int i; | ||
331 | |||
332 | g = &pctrl->soc->groups[group]; | ||
333 | |||
334 | for (i = 0; i < num_configs; i++) { | ||
335 | param = pinconf_to_config_param(configs[i]); | ||
336 | arg = pinconf_to_config_argument(configs[i]); | ||
337 | |||
338 | ret = msm_config_reg(pctrl, g, param, ®, &mask, &bit); | ||
339 | if (ret < 0) | ||
340 | return ret; | ||
341 | |||
342 | /* Convert pinconf values to register values */ | ||
343 | switch (param) { | ||
344 | case PIN_CONFIG_BIAS_DISABLE: | ||
345 | arg = MSM_NO_PULL; | ||
346 | break; | ||
347 | case PIN_CONFIG_BIAS_PULL_DOWN: | ||
348 | arg = MSM_PULL_DOWN; | ||
349 | break; | ||
350 | case PIN_CONFIG_BIAS_PULL_UP: | ||
351 | arg = MSM_PULL_UP; | ||
352 | break; | ||
353 | case PIN_CONFIG_DRIVE_STRENGTH: | ||
354 | /* Check for invalid values */ | ||
355 | if (arg >= ARRAY_SIZE(msm_drive_to_regval)) | ||
356 | arg = -1; | ||
357 | else | ||
358 | arg = msm_drive_to_regval[arg]; | ||
359 | break; | ||
360 | default: | ||
361 | dev_err(pctrl->dev, "Unsupported config parameter: %x\n", | ||
362 | param); | ||
363 | return -EINVAL; | ||
364 | } | ||
365 | |||
366 | /* Range-check user-supplied value */ | ||
367 | if (arg & ~mask) { | ||
368 | dev_err(pctrl->dev, "config %x: %x is invalid\n", param, arg); | ||
369 | return -EINVAL; | ||
370 | } | ||
371 | |||
372 | spin_lock_irqsave(&pctrl->lock, flags); | ||
373 | val = readl(pctrl->regs + reg); | ||
374 | val &= ~(mask << bit); | ||
375 | val |= arg << bit; | ||
376 | writel(val, pctrl->regs + reg); | ||
377 | spin_unlock_irqrestore(&pctrl->lock, flags); | ||
378 | } | ||
379 | |||
380 | return 0; | ||
381 | } | ||
382 | |||
383 | static const struct pinconf_ops msm_pinconf_ops = { | ||
384 | .pin_config_get = msm_config_get, | ||
385 | .pin_config_set = msm_config_set, | ||
386 | .pin_config_group_get = msm_config_group_get, | ||
387 | .pin_config_group_set = msm_config_group_set, | ||
388 | }; | ||
389 | |||
390 | static struct pinctrl_desc msm_pinctrl_desc = { | ||
391 | .pctlops = &msm_pinctrl_ops, | ||
392 | .pmxops = &msm_pinmux_ops, | ||
393 | .confops = &msm_pinconf_ops, | ||
394 | .owner = THIS_MODULE, | ||
395 | }; | ||
396 | |||
397 | static int msm_gpio_direction_input(struct gpio_chip *chip, unsigned offset) | ||
398 | { | ||
399 | const struct msm_pingroup *g; | ||
400 | struct msm_pinctrl *pctrl = container_of(chip, struct msm_pinctrl, chip); | ||
401 | unsigned long flags; | ||
402 | u32 val; | ||
403 | |||
404 | g = &pctrl->soc->groups[offset]; | ||
405 | if (WARN_ON(g->io_reg < 0)) | ||
406 | return -EINVAL; | ||
407 | |||
408 | spin_lock_irqsave(&pctrl->lock, flags); | ||
409 | |||
410 | val = readl(pctrl->regs + g->ctl_reg); | ||
411 | val &= ~BIT(g->oe_bit); | ||
412 | writel(val, pctrl->regs + g->ctl_reg); | ||
413 | |||
414 | spin_unlock_irqrestore(&pctrl->lock, flags); | ||
415 | |||
416 | return 0; | ||
417 | } | ||
418 | |||
419 | static int msm_gpio_direction_output(struct gpio_chip *chip, unsigned offset, int value) | ||
420 | { | ||
421 | const struct msm_pingroup *g; | ||
422 | struct msm_pinctrl *pctrl = container_of(chip, struct msm_pinctrl, chip); | ||
423 | unsigned long flags; | ||
424 | u32 val; | ||
425 | |||
426 | g = &pctrl->soc->groups[offset]; | ||
427 | if (WARN_ON(g->io_reg < 0)) | ||
428 | return -EINVAL; | ||
429 | |||
430 | spin_lock_irqsave(&pctrl->lock, flags); | ||
431 | |||
432 | val = readl(pctrl->regs + g->io_reg); | ||
433 | if (value) | ||
434 | val |= BIT(g->out_bit); | ||
435 | else | ||
436 | val &= ~BIT(g->out_bit); | ||
437 | writel(val, pctrl->regs + g->io_reg); | ||
438 | |||
439 | val = readl(pctrl->regs + g->ctl_reg); | ||
440 | val |= BIT(g->oe_bit); | ||
441 | writel(val, pctrl->regs + g->ctl_reg); | ||
442 | |||
443 | spin_unlock_irqrestore(&pctrl->lock, flags); | ||
444 | |||
445 | return 0; | ||
446 | } | ||
447 | |||
448 | static int msm_gpio_get(struct gpio_chip *chip, unsigned offset) | ||
449 | { | ||
450 | const struct msm_pingroup *g; | ||
451 | struct msm_pinctrl *pctrl = container_of(chip, struct msm_pinctrl, chip); | ||
452 | u32 val; | ||
453 | |||
454 | g = &pctrl->soc->groups[offset]; | ||
455 | if (WARN_ON(g->io_reg < 0)) | ||
456 | return -EINVAL; | ||
457 | |||
458 | val = readl(pctrl->regs + g->io_reg); | ||
459 | return !!(val & BIT(g->in_bit)); | ||
460 | } | ||
461 | |||
462 | static void msm_gpio_set(struct gpio_chip *chip, unsigned offset, int value) | ||
463 | { | ||
464 | const struct msm_pingroup *g; | ||
465 | struct msm_pinctrl *pctrl = container_of(chip, struct msm_pinctrl, chip); | ||
466 | unsigned long flags; | ||
467 | u32 val; | ||
468 | |||
469 | g = &pctrl->soc->groups[offset]; | ||
470 | if (WARN_ON(g->io_reg < 0)) | ||
471 | return; | ||
472 | |||
473 | spin_lock_irqsave(&pctrl->lock, flags); | ||
474 | |||
475 | val = readl(pctrl->regs + g->io_reg); | ||
476 | if (value) | ||
477 | val |= BIT(g->out_bit); | ||
478 | else | ||
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 | static const char * const 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_puts(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 | g = &pctrl->soc->groups[d->hwirq]; | ||
620 | if (WARN_ON(g->intr_cfg_reg < 0)) | ||
621 | return; | ||
622 | |||
623 | spin_lock_irqsave(&pctrl->lock, flags); | ||
624 | |||
625 | val = readl(pctrl->regs + g->intr_cfg_reg); | ||
626 | val &= ~BIT(g->intr_enable_bit); | ||
627 | writel(val, pctrl->regs + g->intr_cfg_reg); | ||
628 | |||
629 | clear_bit(d->hwirq, pctrl->enabled_irqs); | ||
630 | |||
631 | spin_unlock_irqrestore(&pctrl->lock, flags); | ||
632 | } | ||
633 | |||
634 | static void msm_gpio_irq_unmask(struct irq_data *d) | ||
635 | { | ||
636 | const struct msm_pingroup *g; | ||
637 | struct msm_pinctrl *pctrl; | ||
638 | unsigned long flags; | ||
639 | u32 val; | ||
640 | |||
641 | pctrl = irq_data_get_irq_chip_data(d); | ||
642 | g = &pctrl->soc->groups[d->hwirq]; | ||
643 | if (WARN_ON(g->intr_status_reg < 0)) | ||
644 | return; | ||
645 | |||
646 | spin_lock_irqsave(&pctrl->lock, flags); | ||
647 | |||
648 | val = readl(pctrl->regs + g->intr_status_reg); | ||
649 | val &= ~BIT(g->intr_status_bit); | ||
650 | writel(val, pctrl->regs + g->intr_status_reg); | ||
651 | |||
652 | val = readl(pctrl->regs + g->intr_cfg_reg); | ||
653 | val |= BIT(g->intr_enable_bit); | ||
654 | writel(val, pctrl->regs + g->intr_cfg_reg); | ||
655 | |||
656 | set_bit(d->hwirq, pctrl->enabled_irqs); | ||
657 | |||
658 | spin_unlock_irqrestore(&pctrl->lock, flags); | ||
659 | } | ||
660 | |||
661 | static void msm_gpio_irq_ack(struct irq_data *d) | ||
662 | { | ||
663 | const struct msm_pingroup *g; | ||
664 | struct msm_pinctrl *pctrl; | ||
665 | unsigned long flags; | ||
666 | u32 val; | ||
667 | |||
668 | pctrl = irq_data_get_irq_chip_data(d); | ||
669 | g = &pctrl->soc->groups[d->hwirq]; | ||
670 | if (WARN_ON(g->intr_status_reg < 0)) | ||
671 | return; | ||
672 | |||
673 | spin_lock_irqsave(&pctrl->lock, flags); | ||
674 | |||
675 | val = readl(pctrl->regs + g->intr_status_reg); | ||
676 | val &= ~BIT(g->intr_status_bit); | ||
677 | writel(val, pctrl->regs + g->intr_status_reg); | ||
678 | |||
679 | if (test_bit(d->hwirq, pctrl->dual_edge_irqs)) | ||
680 | msm_gpio_update_dual_edge_pos(pctrl, g, d); | ||
681 | |||
682 | spin_unlock_irqrestore(&pctrl->lock, flags); | ||
683 | } | ||
684 | |||
685 | #define INTR_TARGET_PROC_APPS 4 | ||
686 | |||
687 | static int msm_gpio_irq_set_type(struct irq_data *d, unsigned int type) | ||
688 | { | ||
689 | const struct msm_pingroup *g; | ||
690 | struct msm_pinctrl *pctrl; | ||
691 | unsigned long flags; | ||
692 | u32 val; | ||
693 | |||
694 | pctrl = irq_data_get_irq_chip_data(d); | ||
695 | g = &pctrl->soc->groups[d->hwirq]; | ||
696 | if (WARN_ON(g->intr_cfg_reg < 0)) | ||
697 | return -EINVAL; | ||
698 | |||
699 | spin_lock_irqsave(&pctrl->lock, flags); | ||
700 | |||
701 | /* | ||
702 | * For hw without possibility of detecting both edges | ||
703 | */ | ||
704 | if (g->intr_detection_width == 1 && type == IRQ_TYPE_EDGE_BOTH) | ||
705 | set_bit(d->hwirq, pctrl->dual_edge_irqs); | ||
706 | else | ||
707 | clear_bit(d->hwirq, pctrl->dual_edge_irqs); | ||
708 | |||
709 | /* Route interrupts to application cpu */ | ||
710 | val = readl(pctrl->regs + g->intr_target_reg); | ||
711 | val &= ~(7 << g->intr_target_bit); | ||
712 | val |= INTR_TARGET_PROC_APPS << g->intr_target_bit; | ||
713 | writel(val, pctrl->regs + g->intr_target_reg); | ||
714 | |||
715 | /* Update configuration for gpio. | ||
716 | * RAW_STATUS_EN is left on for all gpio irqs. Due to the | ||
717 | * internal circuitry of TLMM, toggling the RAW_STATUS | ||
718 | * could cause the INTR_STATUS to be set for EDGE interrupts. | ||
719 | */ | ||
720 | val = readl(pctrl->regs + g->intr_cfg_reg); | ||
721 | val |= BIT(g->intr_raw_status_bit); | ||
722 | if (g->intr_detection_width == 2) { | ||
723 | val &= ~(3 << g->intr_detection_bit); | ||
724 | val &= ~(1 << g->intr_polarity_bit); | ||
725 | switch (type) { | ||
726 | case IRQ_TYPE_EDGE_RISING: | ||
727 | val |= 1 << g->intr_detection_bit; | ||
728 | val |= BIT(g->intr_polarity_bit); | ||
729 | break; | ||
730 | case IRQ_TYPE_EDGE_FALLING: | ||
731 | val |= 2 << g->intr_detection_bit; | ||
732 | val |= BIT(g->intr_polarity_bit); | ||
733 | break; | ||
734 | case IRQ_TYPE_EDGE_BOTH: | ||
735 | val |= 3 << g->intr_detection_bit; | ||
736 | val |= BIT(g->intr_polarity_bit); | ||
737 | break; | ||
738 | case IRQ_TYPE_LEVEL_LOW: | ||
739 | break; | ||
740 | case IRQ_TYPE_LEVEL_HIGH: | ||
741 | val |= BIT(g->intr_polarity_bit); | ||
742 | break; | ||
743 | } | ||
744 | } else if (g->intr_detection_width == 1) { | ||
745 | val &= ~(1 << g->intr_detection_bit); | ||
746 | val &= ~(1 << g->intr_polarity_bit); | ||
747 | switch (type) { | ||
748 | case IRQ_TYPE_EDGE_RISING: | ||
749 | val |= BIT(g->intr_detection_bit); | ||
750 | val |= BIT(g->intr_polarity_bit); | ||
751 | break; | ||
752 | case IRQ_TYPE_EDGE_FALLING: | ||
753 | val |= BIT(g->intr_detection_bit); | ||
754 | break; | ||
755 | case IRQ_TYPE_EDGE_BOTH: | ||
756 | val |= BIT(g->intr_detection_bit); | ||
757 | break; | ||
758 | case IRQ_TYPE_LEVEL_LOW: | ||
759 | break; | ||
760 | case IRQ_TYPE_LEVEL_HIGH: | ||
761 | val |= BIT(g->intr_polarity_bit); | ||
762 | break; | ||
763 | } | ||
764 | } else { | ||
765 | BUG(); | ||
766 | } | ||
767 | writel(val, pctrl->regs + g->intr_cfg_reg); | ||
768 | |||
769 | if (test_bit(d->hwirq, pctrl->dual_edge_irqs)) | ||
770 | msm_gpio_update_dual_edge_pos(pctrl, g, d); | ||
771 | |||
772 | spin_unlock_irqrestore(&pctrl->lock, flags); | ||
773 | |||
774 | if (type & (IRQ_TYPE_LEVEL_LOW | IRQ_TYPE_LEVEL_HIGH)) | ||
775 | __irq_set_handler_locked(d->irq, handle_level_irq); | ||
776 | else if (type & (IRQ_TYPE_EDGE_FALLING | IRQ_TYPE_EDGE_RISING)) | ||
777 | __irq_set_handler_locked(d->irq, handle_edge_irq); | ||
778 | |||
779 | return 0; | ||
780 | } | ||
781 | |||
782 | static int msm_gpio_irq_set_wake(struct irq_data *d, unsigned int on) | ||
783 | { | ||
784 | struct msm_pinctrl *pctrl; | ||
785 | unsigned long flags; | ||
786 | unsigned ngpio; | ||
787 | |||
788 | pctrl = irq_data_get_irq_chip_data(d); | ||
789 | ngpio = pctrl->chip.ngpio; | ||
790 | |||
791 | spin_lock_irqsave(&pctrl->lock, flags); | ||
792 | |||
793 | if (on) { | ||
794 | if (bitmap_empty(pctrl->wake_irqs, ngpio)) | ||
795 | enable_irq_wake(pctrl->irq); | ||
796 | set_bit(d->hwirq, pctrl->wake_irqs); | ||
797 | } else { | ||
798 | clear_bit(d->hwirq, pctrl->wake_irqs); | ||
799 | if (bitmap_empty(pctrl->wake_irqs, ngpio)) | ||
800 | disable_irq_wake(pctrl->irq); | ||
801 | } | ||
802 | |||
803 | spin_unlock_irqrestore(&pctrl->lock, flags); | ||
804 | |||
805 | return 0; | ||
806 | } | ||
807 | |||
808 | static unsigned int msm_gpio_irq_startup(struct irq_data *d) | ||
809 | { | ||
810 | struct msm_pinctrl *pctrl = irq_data_get_irq_chip_data(d); | ||
811 | |||
812 | if (gpio_lock_as_irq(&pctrl->chip, d->hwirq)) { | ||
813 | dev_err(pctrl->dev, "unable to lock HW IRQ %lu for IRQ\n", | ||
814 | d->hwirq); | ||
815 | } | ||
816 | msm_gpio_irq_unmask(d); | ||
817 | return 0; | ||
818 | } | ||
819 | |||
820 | static void msm_gpio_irq_shutdown(struct irq_data *d) | ||
821 | { | ||
822 | struct msm_pinctrl *pctrl = irq_data_get_irq_chip_data(d); | ||
823 | |||
824 | msm_gpio_irq_mask(d); | ||
825 | gpio_unlock_as_irq(&pctrl->chip, d->hwirq); | ||
826 | } | ||
827 | |||
828 | static struct irq_chip msm_gpio_irq_chip = { | ||
829 | .name = "msmgpio", | ||
830 | .irq_mask = msm_gpio_irq_mask, | ||
831 | .irq_unmask = msm_gpio_irq_unmask, | ||
832 | .irq_ack = msm_gpio_irq_ack, | ||
833 | .irq_set_type = msm_gpio_irq_set_type, | ||
834 | .irq_set_wake = msm_gpio_irq_set_wake, | ||
835 | .irq_startup = msm_gpio_irq_startup, | ||
836 | .irq_shutdown = msm_gpio_irq_shutdown, | ||
837 | }; | ||
838 | |||
839 | static void msm_gpio_irq_handler(unsigned int irq, struct irq_desc *desc) | ||
840 | { | ||
841 | const struct msm_pingroup *g; | ||
842 | struct msm_pinctrl *pctrl = irq_desc_get_handler_data(desc); | ||
843 | struct irq_chip *chip = irq_get_chip(irq); | ||
844 | int irq_pin; | ||
845 | int handled = 0; | ||
846 | u32 val; | ||
847 | int i; | ||
848 | |||
849 | chained_irq_enter(chip, desc); | ||
850 | |||
851 | /* | ||
852 | * Each pin has it's own IRQ status register, so use | ||
853 | * enabled_irq bitmap to limit the number of reads. | ||
854 | */ | ||
855 | for_each_set_bit(i, pctrl->enabled_irqs, pctrl->chip.ngpio) { | ||
856 | g = &pctrl->soc->groups[i]; | ||
857 | val = readl(pctrl->regs + g->intr_status_reg); | ||
858 | if (val & BIT(g->intr_status_bit)) { | ||
859 | irq_pin = irq_find_mapping(pctrl->domain, i); | ||
860 | generic_handle_irq(irq_pin); | ||
861 | handled++; | ||
862 | } | ||
863 | } | ||
864 | |||
865 | /* No interrupts were flagged */ | ||
866 | if (handled == 0) | ||
867 | handle_bad_irq(irq, desc); | ||
868 | |||
869 | chained_irq_exit(chip, desc); | ||
870 | } | ||
871 | |||
872 | static int msm_gpio_init(struct msm_pinctrl *pctrl) | ||
873 | { | ||
874 | struct gpio_chip *chip; | ||
875 | int irq; | ||
876 | int ret; | ||
877 | int i; | ||
878 | int r; | ||
879 | |||
880 | chip = &pctrl->chip; | ||
881 | chip->base = 0; | ||
882 | chip->ngpio = pctrl->soc->ngpios; | ||
883 | chip->label = dev_name(pctrl->dev); | ||
884 | chip->dev = pctrl->dev; | ||
885 | chip->owner = THIS_MODULE; | ||
886 | chip->of_node = pctrl->dev->of_node; | ||
887 | |||
888 | ret = gpiochip_add(&pctrl->chip); | ||
889 | if (ret) { | ||
890 | dev_err(pctrl->dev, "Failed register gpiochip\n"); | ||
891 | return ret; | ||
892 | } | ||
893 | |||
894 | ret = gpiochip_add_pin_range(&pctrl->chip, dev_name(pctrl->dev), 0, 0, chip->ngpio); | ||
895 | if (ret) { | ||
896 | dev_err(pctrl->dev, "Failed to add pin range\n"); | ||
897 | return ret; | ||
898 | } | ||
899 | |||
900 | pctrl->domain = irq_domain_add_linear(pctrl->dev->of_node, chip->ngpio, | ||
901 | &irq_domain_simple_ops, NULL); | ||
902 | if (!pctrl->domain) { | ||
903 | dev_err(pctrl->dev, "Failed to register irq domain\n"); | ||
904 | r = gpiochip_remove(&pctrl->chip); | ||
905 | return -ENOSYS; | ||
906 | } | ||
907 | |||
908 | for (i = 0; i < chip->ngpio; i++) { | ||
909 | irq = irq_create_mapping(pctrl->domain, i); | ||
910 | irq_set_chip_and_handler(irq, &msm_gpio_irq_chip, handle_edge_irq); | ||
911 | irq_set_chip_data(irq, pctrl); | ||
912 | } | ||
913 | |||
914 | irq_set_handler_data(pctrl->irq, pctrl); | ||
915 | irq_set_chained_handler(pctrl->irq, msm_gpio_irq_handler); | ||
916 | |||
917 | return 0; | ||
918 | } | ||
919 | |||
920 | int msm_pinctrl_probe(struct platform_device *pdev, | ||
921 | const struct msm_pinctrl_soc_data *soc_data) | ||
922 | { | ||
923 | struct msm_pinctrl *pctrl; | ||
924 | struct resource *res; | ||
925 | int ret; | ||
926 | |||
927 | pctrl = devm_kzalloc(&pdev->dev, sizeof(*pctrl), GFP_KERNEL); | ||
928 | if (!pctrl) { | ||
929 | dev_err(&pdev->dev, "Can't allocate msm_pinctrl\n"); | ||
930 | return -ENOMEM; | ||
931 | } | ||
932 | pctrl->dev = &pdev->dev; | ||
933 | pctrl->soc = soc_data; | ||
934 | pctrl->chip = msm_gpio_template; | ||
935 | |||
936 | spin_lock_init(&pctrl->lock); | ||
937 | |||
938 | res = platform_get_resource(pdev, IORESOURCE_MEM, 0); | ||
939 | pctrl->regs = devm_ioremap_resource(&pdev->dev, res); | ||
940 | if (IS_ERR(pctrl->regs)) | ||
941 | return PTR_ERR(pctrl->regs); | ||
942 | |||
943 | pctrl->irq = platform_get_irq(pdev, 0); | ||
944 | if (pctrl->irq < 0) { | ||
945 | dev_err(&pdev->dev, "No interrupt defined for msmgpio\n"); | ||
946 | return pctrl->irq; | ||
947 | } | ||
948 | |||
949 | msm_pinctrl_desc.name = dev_name(&pdev->dev); | ||
950 | msm_pinctrl_desc.pins = pctrl->soc->pins; | ||
951 | msm_pinctrl_desc.npins = pctrl->soc->npins; | ||
952 | pctrl->pctrl = pinctrl_register(&msm_pinctrl_desc, &pdev->dev, pctrl); | ||
953 | if (!pctrl->pctrl) { | ||
954 | dev_err(&pdev->dev, "Couldn't register pinctrl driver\n"); | ||
955 | return -ENODEV; | ||
956 | } | ||
957 | |||
958 | ret = msm_gpio_init(pctrl); | ||
959 | if (ret) { | ||
960 | pinctrl_unregister(pctrl->pctrl); | ||
961 | return ret; | ||
962 | } | ||
963 | |||
964 | platform_set_drvdata(pdev, pctrl); | ||
965 | |||
966 | dev_dbg(&pdev->dev, "Probed Qualcomm pinctrl driver\n"); | ||
967 | |||
968 | return 0; | ||
969 | } | ||
970 | EXPORT_SYMBOL(msm_pinctrl_probe); | ||
971 | |||
972 | int msm_pinctrl_remove(struct platform_device *pdev) | ||
973 | { | ||
974 | struct msm_pinctrl *pctrl = platform_get_drvdata(pdev); | ||
975 | int ret; | ||
976 | |||
977 | ret = gpiochip_remove(&pctrl->chip); | ||
978 | if (ret) { | ||
979 | dev_err(&pdev->dev, "Failed to remove gpiochip\n"); | ||
980 | return ret; | ||
981 | } | ||
982 | |||
983 | irq_set_chained_handler(pctrl->irq, NULL); | ||
984 | irq_domain_remove(pctrl->domain); | ||
985 | pinctrl_unregister(pctrl->pctrl); | ||
986 | |||
987 | return 0; | ||
988 | } | ||
989 | EXPORT_SYMBOL(msm_pinctrl_remove); | ||
990 | |||