diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2014-08-07 20:20:53 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2014-08-07 20:20:53 -0400 |
commit | e0b8b78651350e8dcf9cc60a959ccbcfc5bc3061 (patch) | |
tree | 87cf0ed233021bb5c7486b35c2e34f1ea98b81c2 /drivers/pinctrl/qcom/pinctrl-msm.c | |
parent | 54c72d5987ff9f3cf59529d5d4f5cf19eae3f695 (diff) | |
parent | e1ee5c578fb1fa24b7ccaf1a11237a2bd70b6f9a (diff) |
Merge tag 'pinctrl-v3.17-1' of git://git.kernel.org/pub/scm/linux/kernel/git/linusw/linux-pinctrl
Pull pinctrl updates from Linus Walleij:
"This is the bulk pin control changes for the v3.17 merge development
cycle:
- get rid of the .disable() callback from the driver callback vtable.
This callback was abused and counterintuitive since a pin or group
of pins can be said to always be in some setting, and never really
disabled. We now only enable a certain muxing, and move between
some certain muxings, we never "disable" a mux setting
- some janitorial moving the MSM, Samsung and Nomadik and drivers to
their own subdirectories for a clearer view in the subsystem. This
will continue
- kill off the use of the return value from gpiochip_remove(), this
will be done in parallel in the GPIO subsystem and hopefully not
trigger too many unchecked return value warnings before we get rid
of this altogether
- a huge set of changes and improvements to the Allwinner sunxi
drivers especially for their latest A23 and A31 SoCs, and some
ground work for the new sun8i platform family
- a large set of Rockchip driver improvements adding support for the
RK3288 SoC
- advances in migration of older Freescale platforms to pin control,
especially i.MX1
- Samsung and Exynos improvements
- support for the Qualcomm MSM8960 SoC
- use the gpiolib irqchip helpers for the ST SPEAr and Intel Baytrail
drivers
- a bunch of nice janitorial work done with cppcheck"
* tag 'pinctrl-v3.17-1' of git://git.kernel.org/pub/scm/linux/kernel/git/linusw/linux-pinctrl: (61 commits)
pinctrl: baytrail: Convert to use gpiolib irqchip
pinctrl: sunxi: number gpio ranges starting from 0
pinctrl: sunxi: use gpiolib API to mark a GPIO used as an IRQ
pinctrl: rockchip: add drive-strength control for rk3288
pinctrl: rockchip: add separate type for rk3288
pinctrl: rockchip: set is_generic in pinconf_ops
pinctrl: msm: drop negativity check on unsigned value
pinctrl: remove all usage of gpio_remove ret val in driver/pinctl
pinctrl: qcom: Make muxing of gpio function explicit
pinctrl: nomadik: move all Nomadik drivers to subdir
pinctrl: samsung: Group all drivers in a sub-dir
sh-pfc: sh73a0: Introduce the use of devm_regulator_register
sh-pfc: Add renesas,pfc-r8a7791 to binding documentation
pinctrl: msm: move all qualcomm drivers to subdir
pinctrl: msm: Add msm8960 definitions
pinctrl: samsung: Allow pin value to be initialized using pinfunc
pinctrl: samsung: Allow grouping multiple pinmux/pinconf nodes
pinctrl: exynos: Consolidate irq_chips of GPIO and WKUP EINTs
pinctrl: samsung: Handle GPIO request and free using pinctrl helpers
pinctrl: samsung: Decouple direction setting from pinctrl
...
Diffstat (limited to 'drivers/pinctrl/qcom/pinctrl-msm.c')
-rw-r--r-- | drivers/pinctrl/qcom/pinctrl-msm.c | 919 |
1 files changed, 919 insertions, 0 deletions
diff --git a/drivers/pinctrl/qcom/pinctrl-msm.c b/drivers/pinctrl/qcom/pinctrl-msm.c new file mode 100644 index 000000000000..2738108caff2 --- /dev/null +++ b/drivers/pinctrl/qcom/pinctrl-msm.c | |||
@@ -0,0 +1,919 @@ | |||
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/io.h> | ||
17 | #include <linux/module.h> | ||
18 | #include <linux/of.h> | ||
19 | #include <linux/platform_device.h> | ||
20 | #include <linux/pinctrl/machine.h> | ||
21 | #include <linux/pinctrl/pinctrl.h> | ||
22 | #include <linux/pinctrl/pinmux.h> | ||
23 | #include <linux/pinctrl/pinconf.h> | ||
24 | #include <linux/pinctrl/pinconf-generic.h> | ||
25 | #include <linux/slab.h> | ||
26 | #include <linux/gpio.h> | ||
27 | #include <linux/interrupt.h> | ||
28 | #include <linux/spinlock.h> | ||
29 | |||
30 | #include "../core.h" | ||
31 | #include "../pinconf.h" | ||
32 | #include "pinctrl-msm.h" | ||
33 | #include "../pinctrl-utils.h" | ||
34 | |||
35 | #define MAX_NR_GPIO 300 | ||
36 | |||
37 | /** | ||
38 | * struct msm_pinctrl - state for a pinctrl-msm device | ||
39 | * @dev: device handle. | ||
40 | * @pctrl: pinctrl handle. | ||
41 | * @chip: gpiochip handle. | ||
42 | * @irq: parent irq for the TLMM irq_chip. | ||
43 | * @lock: Spinlock to protect register resources as well | ||
44 | * as msm_pinctrl data structures. | ||
45 | * @enabled_irqs: Bitmap of currently enabled irqs. | ||
46 | * @dual_edge_irqs: Bitmap of irqs that need sw emulated dual edge | ||
47 | * detection. | ||
48 | * @soc; Reference to soc_data of platform specific data. | ||
49 | * @regs: Base address for the TLMM register map. | ||
50 | */ | ||
51 | struct msm_pinctrl { | ||
52 | struct device *dev; | ||
53 | struct pinctrl_dev *pctrl; | ||
54 | struct gpio_chip chip; | ||
55 | int irq; | ||
56 | |||
57 | spinlock_t lock; | ||
58 | |||
59 | DECLARE_BITMAP(dual_edge_irqs, MAX_NR_GPIO); | ||
60 | DECLARE_BITMAP(enabled_irqs, MAX_NR_GPIO); | ||
61 | |||
62 | const struct msm_pinctrl_soc_data *soc; | ||
63 | void __iomem *regs; | ||
64 | }; | ||
65 | |||
66 | static inline struct msm_pinctrl *to_msm_pinctrl(struct gpio_chip *gc) | ||
67 | { | ||
68 | return container_of(gc, struct msm_pinctrl, chip); | ||
69 | } | ||
70 | |||
71 | static int msm_get_groups_count(struct pinctrl_dev *pctldev) | ||
72 | { | ||
73 | struct msm_pinctrl *pctrl = pinctrl_dev_get_drvdata(pctldev); | ||
74 | |||
75 | return pctrl->soc->ngroups; | ||
76 | } | ||
77 | |||
78 | static const char *msm_get_group_name(struct pinctrl_dev *pctldev, | ||
79 | unsigned group) | ||
80 | { | ||
81 | struct msm_pinctrl *pctrl = pinctrl_dev_get_drvdata(pctldev); | ||
82 | |||
83 | return pctrl->soc->groups[group].name; | ||
84 | } | ||
85 | |||
86 | static int msm_get_group_pins(struct pinctrl_dev *pctldev, | ||
87 | unsigned group, | ||
88 | const unsigned **pins, | ||
89 | unsigned *num_pins) | ||
90 | { | ||
91 | struct msm_pinctrl *pctrl = pinctrl_dev_get_drvdata(pctldev); | ||
92 | |||
93 | *pins = pctrl->soc->groups[group].pins; | ||
94 | *num_pins = pctrl->soc->groups[group].npins; | ||
95 | return 0; | ||
96 | } | ||
97 | |||
98 | static const struct pinctrl_ops msm_pinctrl_ops = { | ||
99 | .get_groups_count = msm_get_groups_count, | ||
100 | .get_group_name = msm_get_group_name, | ||
101 | .get_group_pins = msm_get_group_pins, | ||
102 | .dt_node_to_map = pinconf_generic_dt_node_to_map_group, | ||
103 | .dt_free_map = pinctrl_utils_dt_free_map, | ||
104 | }; | ||
105 | |||
106 | static int msm_get_functions_count(struct pinctrl_dev *pctldev) | ||
107 | { | ||
108 | struct msm_pinctrl *pctrl = pinctrl_dev_get_drvdata(pctldev); | ||
109 | |||
110 | return pctrl->soc->nfunctions; | ||
111 | } | ||
112 | |||
113 | static const char *msm_get_function_name(struct pinctrl_dev *pctldev, | ||
114 | unsigned function) | ||
115 | { | ||
116 | struct msm_pinctrl *pctrl = pinctrl_dev_get_drvdata(pctldev); | ||
117 | |||
118 | return pctrl->soc->functions[function].name; | ||
119 | } | ||
120 | |||
121 | static int msm_get_function_groups(struct pinctrl_dev *pctldev, | ||
122 | unsigned function, | ||
123 | const char * const **groups, | ||
124 | unsigned * const num_groups) | ||
125 | { | ||
126 | struct msm_pinctrl *pctrl = pinctrl_dev_get_drvdata(pctldev); | ||
127 | |||
128 | *groups = pctrl->soc->functions[function].groups; | ||
129 | *num_groups = pctrl->soc->functions[function].ngroups; | ||
130 | return 0; | ||
131 | } | ||
132 | |||
133 | static int msm_pinmux_enable(struct pinctrl_dev *pctldev, | ||
134 | unsigned function, | ||
135 | unsigned group) | ||
136 | { | ||
137 | struct msm_pinctrl *pctrl = pinctrl_dev_get_drvdata(pctldev); | ||
138 | const struct msm_pingroup *g; | ||
139 | unsigned long flags; | ||
140 | u32 val; | ||
141 | int i; | ||
142 | |||
143 | g = &pctrl->soc->groups[group]; | ||
144 | |||
145 | for (i = 0; i < g->nfuncs; i++) { | ||
146 | if (g->funcs[i] == function) | ||
147 | break; | ||
148 | } | ||
149 | |||
150 | if (WARN_ON(i == g->nfuncs)) | ||
151 | return -EINVAL; | ||
152 | |||
153 | spin_lock_irqsave(&pctrl->lock, flags); | ||
154 | |||
155 | val = readl(pctrl->regs + g->ctl_reg); | ||
156 | val &= ~(0x7 << g->mux_bit); | ||
157 | val |= i << g->mux_bit; | ||
158 | writel(val, pctrl->regs + g->ctl_reg); | ||
159 | |||
160 | spin_unlock_irqrestore(&pctrl->lock, flags); | ||
161 | |||
162 | return 0; | ||
163 | } | ||
164 | |||
165 | static const struct pinmux_ops msm_pinmux_ops = { | ||
166 | .get_functions_count = msm_get_functions_count, | ||
167 | .get_function_name = msm_get_function_name, | ||
168 | .get_function_groups = msm_get_function_groups, | ||
169 | .enable = msm_pinmux_enable, | ||
170 | }; | ||
171 | |||
172 | static int msm_config_reg(struct msm_pinctrl *pctrl, | ||
173 | const struct msm_pingroup *g, | ||
174 | unsigned param, | ||
175 | unsigned *mask, | ||
176 | unsigned *bit) | ||
177 | { | ||
178 | switch (param) { | ||
179 | case PIN_CONFIG_BIAS_DISABLE: | ||
180 | case PIN_CONFIG_BIAS_PULL_DOWN: | ||
181 | case PIN_CONFIG_BIAS_BUS_HOLD: | ||
182 | case PIN_CONFIG_BIAS_PULL_UP: | ||
183 | *bit = g->pull_bit; | ||
184 | *mask = 3; | ||
185 | break; | ||
186 | case PIN_CONFIG_DRIVE_STRENGTH: | ||
187 | *bit = g->drv_bit; | ||
188 | *mask = 7; | ||
189 | break; | ||
190 | case PIN_CONFIG_OUTPUT: | ||
191 | *bit = g->oe_bit; | ||
192 | *mask = 1; | ||
193 | break; | ||
194 | default: | ||
195 | dev_err(pctrl->dev, "Invalid config param %04x\n", param); | ||
196 | return -ENOTSUPP; | ||
197 | } | ||
198 | |||
199 | return 0; | ||
200 | } | ||
201 | |||
202 | static int msm_config_get(struct pinctrl_dev *pctldev, | ||
203 | unsigned int pin, | ||
204 | unsigned long *config) | ||
205 | { | ||
206 | dev_err(pctldev->dev, "pin_config_set op not supported\n"); | ||
207 | return -ENOTSUPP; | ||
208 | } | ||
209 | |||
210 | static int msm_config_set(struct pinctrl_dev *pctldev, unsigned int pin, | ||
211 | unsigned long *configs, unsigned num_configs) | ||
212 | { | ||
213 | dev_err(pctldev->dev, "pin_config_set op not supported\n"); | ||
214 | return -ENOTSUPP; | ||
215 | } | ||
216 | |||
217 | #define MSM_NO_PULL 0 | ||
218 | #define MSM_PULL_DOWN 1 | ||
219 | #define MSM_KEEPER 2 | ||
220 | #define MSM_PULL_UP 3 | ||
221 | |||
222 | static unsigned msm_regval_to_drive(u32 val) | ||
223 | { | ||
224 | return (val + 1) * 2; | ||
225 | } | ||
226 | |||
227 | static int msm_config_group_get(struct pinctrl_dev *pctldev, | ||
228 | unsigned int group, | ||
229 | unsigned long *config) | ||
230 | { | ||
231 | const struct msm_pingroup *g; | ||
232 | struct msm_pinctrl *pctrl = pinctrl_dev_get_drvdata(pctldev); | ||
233 | unsigned param = pinconf_to_config_param(*config); | ||
234 | unsigned mask; | ||
235 | unsigned arg; | ||
236 | unsigned bit; | ||
237 | int ret; | ||
238 | u32 val; | ||
239 | |||
240 | g = &pctrl->soc->groups[group]; | ||
241 | |||
242 | ret = msm_config_reg(pctrl, g, param, &mask, &bit); | ||
243 | if (ret < 0) | ||
244 | return ret; | ||
245 | |||
246 | val = readl(pctrl->regs + g->ctl_reg); | ||
247 | arg = (val >> bit) & mask; | ||
248 | |||
249 | /* Convert register value to pinconf value */ | ||
250 | switch (param) { | ||
251 | case PIN_CONFIG_BIAS_DISABLE: | ||
252 | arg = arg == MSM_NO_PULL; | ||
253 | break; | ||
254 | case PIN_CONFIG_BIAS_PULL_DOWN: | ||
255 | arg = arg == MSM_PULL_DOWN; | ||
256 | break; | ||
257 | case PIN_CONFIG_BIAS_BUS_HOLD: | ||
258 | arg = arg == MSM_KEEPER; | ||
259 | break; | ||
260 | case PIN_CONFIG_BIAS_PULL_UP: | ||
261 | arg = arg == MSM_PULL_UP; | ||
262 | break; | ||
263 | case PIN_CONFIG_DRIVE_STRENGTH: | ||
264 | arg = msm_regval_to_drive(arg); | ||
265 | break; | ||
266 | case PIN_CONFIG_OUTPUT: | ||
267 | /* Pin is not output */ | ||
268 | if (!arg) | ||
269 | return -EINVAL; | ||
270 | |||
271 | val = readl(pctrl->regs + g->io_reg); | ||
272 | arg = !!(val & BIT(g->in_bit)); | ||
273 | break; | ||
274 | default: | ||
275 | dev_err(pctrl->dev, "Unsupported config parameter: %x\n", | ||
276 | param); | ||
277 | return -EINVAL; | ||
278 | } | ||
279 | |||
280 | *config = pinconf_to_config_packed(param, arg); | ||
281 | |||
282 | return 0; | ||
283 | } | ||
284 | |||
285 | static int msm_config_group_set(struct pinctrl_dev *pctldev, | ||
286 | unsigned group, | ||
287 | unsigned long *configs, | ||
288 | unsigned num_configs) | ||
289 | { | ||
290 | const struct msm_pingroup *g; | ||
291 | struct msm_pinctrl *pctrl = pinctrl_dev_get_drvdata(pctldev); | ||
292 | unsigned long flags; | ||
293 | unsigned param; | ||
294 | unsigned mask; | ||
295 | unsigned arg; | ||
296 | unsigned bit; | ||
297 | int ret; | ||
298 | u32 val; | ||
299 | int i; | ||
300 | |||
301 | g = &pctrl->soc->groups[group]; | ||
302 | |||
303 | for (i = 0; i < num_configs; i++) { | ||
304 | param = pinconf_to_config_param(configs[i]); | ||
305 | arg = pinconf_to_config_argument(configs[i]); | ||
306 | |||
307 | ret = msm_config_reg(pctrl, g, param, &mask, &bit); | ||
308 | if (ret < 0) | ||
309 | return ret; | ||
310 | |||
311 | /* Convert pinconf values to register values */ | ||
312 | switch (param) { | ||
313 | case PIN_CONFIG_BIAS_DISABLE: | ||
314 | arg = MSM_NO_PULL; | ||
315 | break; | ||
316 | case PIN_CONFIG_BIAS_PULL_DOWN: | ||
317 | arg = MSM_PULL_DOWN; | ||
318 | break; | ||
319 | case PIN_CONFIG_BIAS_BUS_HOLD: | ||
320 | arg = MSM_KEEPER; | ||
321 | break; | ||
322 | case PIN_CONFIG_BIAS_PULL_UP: | ||
323 | arg = MSM_PULL_UP; | ||
324 | break; | ||
325 | case PIN_CONFIG_DRIVE_STRENGTH: | ||
326 | /* Check for invalid values */ | ||
327 | if (arg > 16 || arg < 2 || (arg % 2) != 0) | ||
328 | arg = -1; | ||
329 | else | ||
330 | arg = (arg / 2) - 1; | ||
331 | break; | ||
332 | case PIN_CONFIG_OUTPUT: | ||
333 | /* set output value */ | ||
334 | spin_lock_irqsave(&pctrl->lock, flags); | ||
335 | val = readl(pctrl->regs + g->io_reg); | ||
336 | if (arg) | ||
337 | val |= BIT(g->out_bit); | ||
338 | else | ||
339 | val &= ~BIT(g->out_bit); | ||
340 | writel(val, pctrl->regs + g->io_reg); | ||
341 | spin_unlock_irqrestore(&pctrl->lock, flags); | ||
342 | |||
343 | /* enable output */ | ||
344 | arg = 1; | ||
345 | break; | ||
346 | default: | ||
347 | dev_err(pctrl->dev, "Unsupported config parameter: %x\n", | ||
348 | param); | ||
349 | return -EINVAL; | ||
350 | } | ||
351 | |||
352 | /* Range-check user-supplied value */ | ||
353 | if (arg & ~mask) { | ||
354 | dev_err(pctrl->dev, "config %x: %x is invalid\n", param, arg); | ||
355 | return -EINVAL; | ||
356 | } | ||
357 | |||
358 | spin_lock_irqsave(&pctrl->lock, flags); | ||
359 | val = readl(pctrl->regs + g->ctl_reg); | ||
360 | val &= ~(mask << bit); | ||
361 | val |= arg << bit; | ||
362 | writel(val, pctrl->regs + g->ctl_reg); | ||
363 | spin_unlock_irqrestore(&pctrl->lock, flags); | ||
364 | } | ||
365 | |||
366 | return 0; | ||
367 | } | ||
368 | |||
369 | static const struct pinconf_ops msm_pinconf_ops = { | ||
370 | .pin_config_get = msm_config_get, | ||
371 | .pin_config_set = msm_config_set, | ||
372 | .pin_config_group_get = msm_config_group_get, | ||
373 | .pin_config_group_set = msm_config_group_set, | ||
374 | }; | ||
375 | |||
376 | static struct pinctrl_desc msm_pinctrl_desc = { | ||
377 | .pctlops = &msm_pinctrl_ops, | ||
378 | .pmxops = &msm_pinmux_ops, | ||
379 | .confops = &msm_pinconf_ops, | ||
380 | .owner = THIS_MODULE, | ||
381 | }; | ||
382 | |||
383 | static int msm_gpio_direction_input(struct gpio_chip *chip, unsigned offset) | ||
384 | { | ||
385 | const struct msm_pingroup *g; | ||
386 | struct msm_pinctrl *pctrl = container_of(chip, struct msm_pinctrl, chip); | ||
387 | unsigned long flags; | ||
388 | u32 val; | ||
389 | |||
390 | g = &pctrl->soc->groups[offset]; | ||
391 | |||
392 | spin_lock_irqsave(&pctrl->lock, flags); | ||
393 | |||
394 | val = readl(pctrl->regs + g->ctl_reg); | ||
395 | val &= ~BIT(g->oe_bit); | ||
396 | writel(val, pctrl->regs + g->ctl_reg); | ||
397 | |||
398 | spin_unlock_irqrestore(&pctrl->lock, flags); | ||
399 | |||
400 | return 0; | ||
401 | } | ||
402 | |||
403 | static int msm_gpio_direction_output(struct gpio_chip *chip, unsigned offset, int value) | ||
404 | { | ||
405 | const struct msm_pingroup *g; | ||
406 | struct msm_pinctrl *pctrl = container_of(chip, struct msm_pinctrl, chip); | ||
407 | unsigned long flags; | ||
408 | u32 val; | ||
409 | |||
410 | g = &pctrl->soc->groups[offset]; | ||
411 | |||
412 | spin_lock_irqsave(&pctrl->lock, flags); | ||
413 | |||
414 | val = readl(pctrl->regs + g->io_reg); | ||
415 | if (value) | ||
416 | val |= BIT(g->out_bit); | ||
417 | else | ||
418 | val &= ~BIT(g->out_bit); | ||
419 | writel(val, pctrl->regs + g->io_reg); | ||
420 | |||
421 | val = readl(pctrl->regs + g->ctl_reg); | ||
422 | val |= BIT(g->oe_bit); | ||
423 | writel(val, pctrl->regs + g->ctl_reg); | ||
424 | |||
425 | spin_unlock_irqrestore(&pctrl->lock, flags); | ||
426 | |||
427 | return 0; | ||
428 | } | ||
429 | |||
430 | static int msm_gpio_get(struct gpio_chip *chip, unsigned offset) | ||
431 | { | ||
432 | const struct msm_pingroup *g; | ||
433 | struct msm_pinctrl *pctrl = container_of(chip, struct msm_pinctrl, chip); | ||
434 | u32 val; | ||
435 | |||
436 | g = &pctrl->soc->groups[offset]; | ||
437 | |||
438 | val = readl(pctrl->regs + g->io_reg); | ||
439 | return !!(val & BIT(g->in_bit)); | ||
440 | } | ||
441 | |||
442 | static void msm_gpio_set(struct gpio_chip *chip, unsigned offset, int value) | ||
443 | { | ||
444 | const struct msm_pingroup *g; | ||
445 | struct msm_pinctrl *pctrl = container_of(chip, struct msm_pinctrl, chip); | ||
446 | unsigned long flags; | ||
447 | u32 val; | ||
448 | |||
449 | g = &pctrl->soc->groups[offset]; | ||
450 | |||
451 | spin_lock_irqsave(&pctrl->lock, flags); | ||
452 | |||
453 | val = readl(pctrl->regs + g->io_reg); | ||
454 | if (value) | ||
455 | val |= BIT(g->out_bit); | ||
456 | else | ||
457 | val &= ~BIT(g->out_bit); | ||
458 | writel(val, pctrl->regs + g->io_reg); | ||
459 | |||
460 | spin_unlock_irqrestore(&pctrl->lock, flags); | ||
461 | } | ||
462 | |||
463 | static int msm_gpio_request(struct gpio_chip *chip, unsigned offset) | ||
464 | { | ||
465 | int gpio = chip->base + offset; | ||
466 | return pinctrl_request_gpio(gpio); | ||
467 | } | ||
468 | |||
469 | static void msm_gpio_free(struct gpio_chip *chip, unsigned offset) | ||
470 | { | ||
471 | int gpio = chip->base + offset; | ||
472 | return pinctrl_free_gpio(gpio); | ||
473 | } | ||
474 | |||
475 | #ifdef CONFIG_DEBUG_FS | ||
476 | #include <linux/seq_file.h> | ||
477 | |||
478 | static void msm_gpio_dbg_show_one(struct seq_file *s, | ||
479 | struct pinctrl_dev *pctldev, | ||
480 | struct gpio_chip *chip, | ||
481 | unsigned offset, | ||
482 | unsigned gpio) | ||
483 | { | ||
484 | const struct msm_pingroup *g; | ||
485 | struct msm_pinctrl *pctrl = container_of(chip, struct msm_pinctrl, chip); | ||
486 | unsigned func; | ||
487 | int is_out; | ||
488 | int drive; | ||
489 | int pull; | ||
490 | u32 ctl_reg; | ||
491 | |||
492 | static const char * const pulls[] = { | ||
493 | "no pull", | ||
494 | "pull down", | ||
495 | "keeper", | ||
496 | "pull up" | ||
497 | }; | ||
498 | |||
499 | g = &pctrl->soc->groups[offset]; | ||
500 | ctl_reg = readl(pctrl->regs + g->ctl_reg); | ||
501 | |||
502 | is_out = !!(ctl_reg & BIT(g->oe_bit)); | ||
503 | func = (ctl_reg >> g->mux_bit) & 7; | ||
504 | drive = (ctl_reg >> g->drv_bit) & 7; | ||
505 | pull = (ctl_reg >> g->pull_bit) & 3; | ||
506 | |||
507 | seq_printf(s, " %-8s: %-3s %d", g->name, is_out ? "out" : "in", func); | ||
508 | seq_printf(s, " %dmA", msm_regval_to_drive(drive)); | ||
509 | seq_printf(s, " %s", pulls[pull]); | ||
510 | } | ||
511 | |||
512 | static void msm_gpio_dbg_show(struct seq_file *s, struct gpio_chip *chip) | ||
513 | { | ||
514 | unsigned gpio = chip->base; | ||
515 | unsigned i; | ||
516 | |||
517 | for (i = 0; i < chip->ngpio; i++, gpio++) { | ||
518 | msm_gpio_dbg_show_one(s, NULL, chip, i, gpio); | ||
519 | seq_puts(s, "\n"); | ||
520 | } | ||
521 | } | ||
522 | |||
523 | #else | ||
524 | #define msm_gpio_dbg_show NULL | ||
525 | #endif | ||
526 | |||
527 | static struct gpio_chip msm_gpio_template = { | ||
528 | .direction_input = msm_gpio_direction_input, | ||
529 | .direction_output = msm_gpio_direction_output, | ||
530 | .get = msm_gpio_get, | ||
531 | .set = msm_gpio_set, | ||
532 | .request = msm_gpio_request, | ||
533 | .free = msm_gpio_free, | ||
534 | .dbg_show = msm_gpio_dbg_show, | ||
535 | }; | ||
536 | |||
537 | /* For dual-edge interrupts in software, since some hardware has no | ||
538 | * such support: | ||
539 | * | ||
540 | * At appropriate moments, this function may be called to flip the polarity | ||
541 | * settings of both-edge irq lines to try and catch the next edge. | ||
542 | * | ||
543 | * The attempt is considered successful if: | ||
544 | * - the status bit goes high, indicating that an edge was caught, or | ||
545 | * - the input value of the gpio doesn't change during the attempt. | ||
546 | * If the value changes twice during the process, that would cause the first | ||
547 | * test to fail but would force the second, as two opposite | ||
548 | * transitions would cause a detection no matter the polarity setting. | ||
549 | * | ||
550 | * The do-loop tries to sledge-hammer closed the timing hole between | ||
551 | * the initial value-read and the polarity-write - if the line value changes | ||
552 | * during that window, an interrupt is lost, the new polarity setting is | ||
553 | * incorrect, and the first success test will fail, causing a retry. | ||
554 | * | ||
555 | * Algorithm comes from Google's msmgpio driver. | ||
556 | */ | ||
557 | static void msm_gpio_update_dual_edge_pos(struct msm_pinctrl *pctrl, | ||
558 | const struct msm_pingroup *g, | ||
559 | struct irq_data *d) | ||
560 | { | ||
561 | int loop_limit = 100; | ||
562 | unsigned val, val2, intstat; | ||
563 | unsigned pol; | ||
564 | |||
565 | do { | ||
566 | val = readl(pctrl->regs + g->io_reg) & BIT(g->in_bit); | ||
567 | |||
568 | pol = readl(pctrl->regs + g->intr_cfg_reg); | ||
569 | pol ^= BIT(g->intr_polarity_bit); | ||
570 | writel(pol, pctrl->regs + g->intr_cfg_reg); | ||
571 | |||
572 | val2 = readl(pctrl->regs + g->io_reg) & BIT(g->in_bit); | ||
573 | intstat = readl(pctrl->regs + g->intr_status_reg); | ||
574 | if (intstat || (val == val2)) | ||
575 | return; | ||
576 | } while (loop_limit-- > 0); | ||
577 | dev_err(pctrl->dev, "dual-edge irq failed to stabilize, %#08x != %#08x\n", | ||
578 | val, val2); | ||
579 | } | ||
580 | |||
581 | static void msm_gpio_irq_mask(struct irq_data *d) | ||
582 | { | ||
583 | struct gpio_chip *gc = irq_data_get_irq_chip_data(d); | ||
584 | struct msm_pinctrl *pctrl = to_msm_pinctrl(gc); | ||
585 | const struct msm_pingroup *g; | ||
586 | unsigned long flags; | ||
587 | u32 val; | ||
588 | |||
589 | g = &pctrl->soc->groups[d->hwirq]; | ||
590 | |||
591 | spin_lock_irqsave(&pctrl->lock, flags); | ||
592 | |||
593 | val = readl(pctrl->regs + g->intr_cfg_reg); | ||
594 | val &= ~BIT(g->intr_enable_bit); | ||
595 | writel(val, pctrl->regs + g->intr_cfg_reg); | ||
596 | |||
597 | clear_bit(d->hwirq, pctrl->enabled_irqs); | ||
598 | |||
599 | spin_unlock_irqrestore(&pctrl->lock, flags); | ||
600 | } | ||
601 | |||
602 | static void msm_gpio_irq_unmask(struct irq_data *d) | ||
603 | { | ||
604 | struct gpio_chip *gc = irq_data_get_irq_chip_data(d); | ||
605 | struct msm_pinctrl *pctrl = to_msm_pinctrl(gc); | ||
606 | const struct msm_pingroup *g; | ||
607 | unsigned long flags; | ||
608 | u32 val; | ||
609 | |||
610 | g = &pctrl->soc->groups[d->hwirq]; | ||
611 | |||
612 | spin_lock_irqsave(&pctrl->lock, flags); | ||
613 | |||
614 | val = readl(pctrl->regs + g->intr_status_reg); | ||
615 | val &= ~BIT(g->intr_status_bit); | ||
616 | writel(val, pctrl->regs + g->intr_status_reg); | ||
617 | |||
618 | val = readl(pctrl->regs + g->intr_cfg_reg); | ||
619 | val |= BIT(g->intr_enable_bit); | ||
620 | writel(val, pctrl->regs + g->intr_cfg_reg); | ||
621 | |||
622 | set_bit(d->hwirq, pctrl->enabled_irqs); | ||
623 | |||
624 | spin_unlock_irqrestore(&pctrl->lock, flags); | ||
625 | } | ||
626 | |||
627 | static void msm_gpio_irq_ack(struct irq_data *d) | ||
628 | { | ||
629 | struct gpio_chip *gc = irq_data_get_irq_chip_data(d); | ||
630 | struct msm_pinctrl *pctrl = to_msm_pinctrl(gc); | ||
631 | const struct msm_pingroup *g; | ||
632 | unsigned long flags; | ||
633 | u32 val; | ||
634 | |||
635 | g = &pctrl->soc->groups[d->hwirq]; | ||
636 | |||
637 | spin_lock_irqsave(&pctrl->lock, flags); | ||
638 | |||
639 | val = readl(pctrl->regs + g->intr_status_reg); | ||
640 | if (g->intr_ack_high) | ||
641 | val |= BIT(g->intr_status_bit); | ||
642 | else | ||
643 | val &= ~BIT(g->intr_status_bit); | ||
644 | writel(val, pctrl->regs + g->intr_status_reg); | ||
645 | |||
646 | if (test_bit(d->hwirq, pctrl->dual_edge_irqs)) | ||
647 | msm_gpio_update_dual_edge_pos(pctrl, g, d); | ||
648 | |||
649 | spin_unlock_irqrestore(&pctrl->lock, flags); | ||
650 | } | ||
651 | |||
652 | #define INTR_TARGET_PROC_APPS 4 | ||
653 | |||
654 | static int msm_gpio_irq_set_type(struct irq_data *d, unsigned int type) | ||
655 | { | ||
656 | struct gpio_chip *gc = irq_data_get_irq_chip_data(d); | ||
657 | struct msm_pinctrl *pctrl = to_msm_pinctrl(gc); | ||
658 | const struct msm_pingroup *g; | ||
659 | unsigned long flags; | ||
660 | u32 val; | ||
661 | |||
662 | g = &pctrl->soc->groups[d->hwirq]; | ||
663 | |||
664 | spin_lock_irqsave(&pctrl->lock, flags); | ||
665 | |||
666 | /* | ||
667 | * For hw without possibility of detecting both edges | ||
668 | */ | ||
669 | if (g->intr_detection_width == 1 && type == IRQ_TYPE_EDGE_BOTH) | ||
670 | set_bit(d->hwirq, pctrl->dual_edge_irqs); | ||
671 | else | ||
672 | clear_bit(d->hwirq, pctrl->dual_edge_irqs); | ||
673 | |||
674 | /* Route interrupts to application cpu */ | ||
675 | val = readl(pctrl->regs + g->intr_target_reg); | ||
676 | val &= ~(7 << g->intr_target_bit); | ||
677 | val |= INTR_TARGET_PROC_APPS << g->intr_target_bit; | ||
678 | writel(val, pctrl->regs + g->intr_target_reg); | ||
679 | |||
680 | /* Update configuration for gpio. | ||
681 | * RAW_STATUS_EN is left on for all gpio irqs. Due to the | ||
682 | * internal circuitry of TLMM, toggling the RAW_STATUS | ||
683 | * could cause the INTR_STATUS to be set for EDGE interrupts. | ||
684 | */ | ||
685 | val = readl(pctrl->regs + g->intr_cfg_reg); | ||
686 | val |= BIT(g->intr_raw_status_bit); | ||
687 | if (g->intr_detection_width == 2) { | ||
688 | val &= ~(3 << g->intr_detection_bit); | ||
689 | val &= ~(1 << g->intr_polarity_bit); | ||
690 | switch (type) { | ||
691 | case IRQ_TYPE_EDGE_RISING: | ||
692 | val |= 1 << g->intr_detection_bit; | ||
693 | val |= BIT(g->intr_polarity_bit); | ||
694 | break; | ||
695 | case IRQ_TYPE_EDGE_FALLING: | ||
696 | val |= 2 << g->intr_detection_bit; | ||
697 | val |= BIT(g->intr_polarity_bit); | ||
698 | break; | ||
699 | case IRQ_TYPE_EDGE_BOTH: | ||
700 | val |= 3 << g->intr_detection_bit; | ||
701 | val |= BIT(g->intr_polarity_bit); | ||
702 | break; | ||
703 | case IRQ_TYPE_LEVEL_LOW: | ||
704 | break; | ||
705 | case IRQ_TYPE_LEVEL_HIGH: | ||
706 | val |= BIT(g->intr_polarity_bit); | ||
707 | break; | ||
708 | } | ||
709 | } else if (g->intr_detection_width == 1) { | ||
710 | val &= ~(1 << g->intr_detection_bit); | ||
711 | val &= ~(1 << g->intr_polarity_bit); | ||
712 | switch (type) { | ||
713 | case IRQ_TYPE_EDGE_RISING: | ||
714 | val |= BIT(g->intr_detection_bit); | ||
715 | val |= BIT(g->intr_polarity_bit); | ||
716 | break; | ||
717 | case IRQ_TYPE_EDGE_FALLING: | ||
718 | val |= BIT(g->intr_detection_bit); | ||
719 | break; | ||
720 | case IRQ_TYPE_EDGE_BOTH: | ||
721 | val |= BIT(g->intr_detection_bit); | ||
722 | val |= BIT(g->intr_polarity_bit); | ||
723 | break; | ||
724 | case IRQ_TYPE_LEVEL_LOW: | ||
725 | break; | ||
726 | case IRQ_TYPE_LEVEL_HIGH: | ||
727 | val |= BIT(g->intr_polarity_bit); | ||
728 | break; | ||
729 | } | ||
730 | } else { | ||
731 | BUG(); | ||
732 | } | ||
733 | writel(val, pctrl->regs + g->intr_cfg_reg); | ||
734 | |||
735 | if (test_bit(d->hwirq, pctrl->dual_edge_irqs)) | ||
736 | msm_gpio_update_dual_edge_pos(pctrl, g, d); | ||
737 | |||
738 | spin_unlock_irqrestore(&pctrl->lock, flags); | ||
739 | |||
740 | if (type & (IRQ_TYPE_LEVEL_LOW | IRQ_TYPE_LEVEL_HIGH)) | ||
741 | __irq_set_handler_locked(d->irq, handle_level_irq); | ||
742 | else if (type & (IRQ_TYPE_EDGE_FALLING | IRQ_TYPE_EDGE_RISING)) | ||
743 | __irq_set_handler_locked(d->irq, handle_edge_irq); | ||
744 | |||
745 | return 0; | ||
746 | } | ||
747 | |||
748 | static int msm_gpio_irq_set_wake(struct irq_data *d, unsigned int on) | ||
749 | { | ||
750 | struct gpio_chip *gc = irq_data_get_irq_chip_data(d); | ||
751 | struct msm_pinctrl *pctrl = to_msm_pinctrl(gc); | ||
752 | unsigned long flags; | ||
753 | |||
754 | spin_lock_irqsave(&pctrl->lock, flags); | ||
755 | |||
756 | irq_set_irq_wake(pctrl->irq, on); | ||
757 | |||
758 | spin_unlock_irqrestore(&pctrl->lock, flags); | ||
759 | |||
760 | return 0; | ||
761 | } | ||
762 | |||
763 | static struct irq_chip msm_gpio_irq_chip = { | ||
764 | .name = "msmgpio", | ||
765 | .irq_mask = msm_gpio_irq_mask, | ||
766 | .irq_unmask = msm_gpio_irq_unmask, | ||
767 | .irq_ack = msm_gpio_irq_ack, | ||
768 | .irq_set_type = msm_gpio_irq_set_type, | ||
769 | .irq_set_wake = msm_gpio_irq_set_wake, | ||
770 | }; | ||
771 | |||
772 | static void msm_gpio_irq_handler(unsigned int irq, struct irq_desc *desc) | ||
773 | { | ||
774 | struct gpio_chip *gc = irq_desc_get_handler_data(desc); | ||
775 | const struct msm_pingroup *g; | ||
776 | struct msm_pinctrl *pctrl = to_msm_pinctrl(gc); | ||
777 | struct irq_chip *chip = irq_get_chip(irq); | ||
778 | int irq_pin; | ||
779 | int handled = 0; | ||
780 | u32 val; | ||
781 | int i; | ||
782 | |||
783 | chained_irq_enter(chip, desc); | ||
784 | |||
785 | /* | ||
786 | * Each pin has it's own IRQ status register, so use | ||
787 | * enabled_irq bitmap to limit the number of reads. | ||
788 | */ | ||
789 | for_each_set_bit(i, pctrl->enabled_irqs, pctrl->chip.ngpio) { | ||
790 | g = &pctrl->soc->groups[i]; | ||
791 | val = readl(pctrl->regs + g->intr_status_reg); | ||
792 | if (val & BIT(g->intr_status_bit)) { | ||
793 | irq_pin = irq_find_mapping(gc->irqdomain, i); | ||
794 | generic_handle_irq(irq_pin); | ||
795 | handled++; | ||
796 | } | ||
797 | } | ||
798 | |||
799 | /* No interrupts were flagged */ | ||
800 | if (handled == 0) | ||
801 | handle_bad_irq(irq, desc); | ||
802 | |||
803 | chained_irq_exit(chip, desc); | ||
804 | } | ||
805 | |||
806 | static int msm_gpio_init(struct msm_pinctrl *pctrl) | ||
807 | { | ||
808 | struct gpio_chip *chip; | ||
809 | int ret; | ||
810 | unsigned ngpio = pctrl->soc->ngpios; | ||
811 | |||
812 | if (WARN_ON(ngpio > MAX_NR_GPIO)) | ||
813 | return -EINVAL; | ||
814 | |||
815 | chip = &pctrl->chip; | ||
816 | chip->base = 0; | ||
817 | chip->ngpio = ngpio; | ||
818 | chip->label = dev_name(pctrl->dev); | ||
819 | chip->dev = pctrl->dev; | ||
820 | chip->owner = THIS_MODULE; | ||
821 | chip->of_node = pctrl->dev->of_node; | ||
822 | |||
823 | ret = gpiochip_add(&pctrl->chip); | ||
824 | if (ret) { | ||
825 | dev_err(pctrl->dev, "Failed register gpiochip\n"); | ||
826 | return ret; | ||
827 | } | ||
828 | |||
829 | ret = gpiochip_add_pin_range(&pctrl->chip, dev_name(pctrl->dev), 0, 0, chip->ngpio); | ||
830 | if (ret) { | ||
831 | dev_err(pctrl->dev, "Failed to add pin range\n"); | ||
832 | return ret; | ||
833 | } | ||
834 | |||
835 | ret = gpiochip_irqchip_add(chip, | ||
836 | &msm_gpio_irq_chip, | ||
837 | 0, | ||
838 | handle_edge_irq, | ||
839 | IRQ_TYPE_NONE); | ||
840 | if (ret) { | ||
841 | dev_err(pctrl->dev, "Failed to add irqchip to gpiochip\n"); | ||
842 | return -ENOSYS; | ||
843 | } | ||
844 | |||
845 | gpiochip_set_chained_irqchip(chip, &msm_gpio_irq_chip, pctrl->irq, | ||
846 | msm_gpio_irq_handler); | ||
847 | |||
848 | return 0; | ||
849 | } | ||
850 | |||
851 | int msm_pinctrl_probe(struct platform_device *pdev, | ||
852 | const struct msm_pinctrl_soc_data *soc_data) | ||
853 | { | ||
854 | struct msm_pinctrl *pctrl; | ||
855 | struct resource *res; | ||
856 | int ret; | ||
857 | |||
858 | pctrl = devm_kzalloc(&pdev->dev, sizeof(*pctrl), GFP_KERNEL); | ||
859 | if (!pctrl) { | ||
860 | dev_err(&pdev->dev, "Can't allocate msm_pinctrl\n"); | ||
861 | return -ENOMEM; | ||
862 | } | ||
863 | pctrl->dev = &pdev->dev; | ||
864 | pctrl->soc = soc_data; | ||
865 | pctrl->chip = msm_gpio_template; | ||
866 | |||
867 | spin_lock_init(&pctrl->lock); | ||
868 | |||
869 | res = platform_get_resource(pdev, IORESOURCE_MEM, 0); | ||
870 | pctrl->regs = devm_ioremap_resource(&pdev->dev, res); | ||
871 | if (IS_ERR(pctrl->regs)) | ||
872 | return PTR_ERR(pctrl->regs); | ||
873 | |||
874 | pctrl->irq = platform_get_irq(pdev, 0); | ||
875 | if (pctrl->irq < 0) { | ||
876 | dev_err(&pdev->dev, "No interrupt defined for msmgpio\n"); | ||
877 | return pctrl->irq; | ||
878 | } | ||
879 | |||
880 | msm_pinctrl_desc.name = dev_name(&pdev->dev); | ||
881 | msm_pinctrl_desc.pins = pctrl->soc->pins; | ||
882 | msm_pinctrl_desc.npins = pctrl->soc->npins; | ||
883 | pctrl->pctrl = pinctrl_register(&msm_pinctrl_desc, &pdev->dev, pctrl); | ||
884 | if (!pctrl->pctrl) { | ||
885 | dev_err(&pdev->dev, "Couldn't register pinctrl driver\n"); | ||
886 | return -ENODEV; | ||
887 | } | ||
888 | |||
889 | ret = msm_gpio_init(pctrl); | ||
890 | if (ret) { | ||
891 | pinctrl_unregister(pctrl->pctrl); | ||
892 | return ret; | ||
893 | } | ||
894 | |||
895 | platform_set_drvdata(pdev, pctrl); | ||
896 | |||
897 | dev_dbg(&pdev->dev, "Probed Qualcomm pinctrl driver\n"); | ||
898 | |||
899 | return 0; | ||
900 | } | ||
901 | EXPORT_SYMBOL(msm_pinctrl_probe); | ||
902 | |||
903 | int msm_pinctrl_remove(struct platform_device *pdev) | ||
904 | { | ||
905 | struct msm_pinctrl *pctrl = platform_get_drvdata(pdev); | ||
906 | int ret; | ||
907 | |||
908 | ret = gpiochip_remove(&pctrl->chip); | ||
909 | if (ret) { | ||
910 | dev_err(&pdev->dev, "Failed to remove gpiochip\n"); | ||
911 | return ret; | ||
912 | } | ||
913 | |||
914 | pinctrl_unregister(pctrl->pctrl); | ||
915 | |||
916 | return 0; | ||
917 | } | ||
918 | EXPORT_SYMBOL(msm_pinctrl_remove); | ||
919 | |||