aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/gpio/gpio-uniphier.c
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2017-11-14 20:23:44 -0500
committerLinus Torvalds <torvalds@linux-foundation.org>2017-11-14 20:23:44 -0500
commit6aa2f9441f1ef21f10c41f45e6453b135e9cd736 (patch)
tree334e67c4693eddff47a098b9afad63ca2ccfcd55 /drivers/gpio/gpio-uniphier.c
parente37e0ee0190034a059c9faea8adfb4982fb24ddd (diff)
parent24f0966c3e3f52a96e888504d60810d9df5b2d42 (diff)
Merge tag 'gpio-v4.15-1' of ssh://gitolite.kernel.org/pub/scm/linux/kernel/git/linusw/linux-gpio
Pull GPIO updates from Linus Walleij: "This is the bulk of GPIO changes for the v4.15 kernel cycle: Core: - Fix the semantics of raw GPIO to actually be raw. No inversion semantics as before, but also no open draining, and allow the raw operations to affect lines used for interrupts as the caller supposedly knows what they are doing if they are getting the big hammer. - Rewrote the __inner_function() notation calls to names that make more sense. I just find this kind of code disturbing. - Drop the .irq_base() field from the gpiochip since now all IRQs are mapped dynamically. This is nice. - Support for .get_multiple() in the core driver API. This allows us to read several GPIO lines with a single register read. This has high value for some usecases: it can be used to create oscilloscopes and signal analyzers and other things that rely on reading several lines at exactly the same instant. Also a generally nice optimization. This uses the new assign_bit() macro from the bitops lib that was ACKed by Andrew Morton and is implemented for two drivers, one of them being the generic MMIO driver so everyone using that will be able to benefit from this. - Do not allow requests of Open Drain and Open Source setting of a GPIO line simultaneously. If the hardware actually supports enabling both at the same time the electrical result would be disastrous. - A new interrupt chip core helper. This will be helpful to deal with "banked" GPIOs, which means GPIO controllers with several logical blocks of GPIO inside them. This is several gpiochips per device in the device model, in contrast to the case when there is a 1-to-1 relationship between a device and a gpiochip. New drivers: - Maxim MAX3191x industrial serializer, a very interesting piece of professional I/O hardware. - Uniphier GPIO driver. This is the GPIO block from the recent Socionext (ex Fujitsu and Panasonic) platform. - Tegra 186 driver. This is based on the new banked GPIO infrastructure. Other improvements: - Some documentation improvements. - Wakeup support for the DesignWare DWAPB GPIO controller. - Reset line support on the DesignWare DWAPB GPIO controller. - Several non-critical bug fixes and improvements for the Broadcom BRCMSTB driver. - Misc non-critical bug fixes like exotic errorpaths, removal of dead code etc. - Explicit comments on fall-through switch() statements" * tag 'gpio-v4.15-1' of ssh://gitolite.kernel.org/pub/scm/linux/kernel/git/linusw/linux-gpio: (65 commits) gpio: tegra186: Remove tegra186_gpio_lock_class gpio: rcar: Add r8a77995 (R-Car D3) support pinctrl: bcm2835: Fix some merge fallout gpio: Fix undefined lock_dep_class gpio: Automatically add lockdep keys gpio: Introduce struct gpio_irq_chip.first gpio: Disambiguate struct gpio_irq_chip.nested gpio: Add Tegra186 support gpio: Export gpiochip_irq_{map,unmap}() gpio: Implement tighter IRQ chip integration gpio: Move lock_key into struct gpio_irq_chip gpio: Move irq_valid_mask into struct gpio_irq_chip gpio: Move irq_nested into struct gpio_irq_chip gpio: Move irq_chained_parent to struct gpio_irq_chip gpio: Move irq_default_type to struct gpio_irq_chip gpio: Move irq_handler to struct gpio_irq_chip gpio: Move irqdomain into struct gpio_irq_chip gpio: Move irqchip into struct gpio_irq_chip gpio: Introduce struct gpio_irq_chip pinctrl: armada-37xx: remove unused variable ...
Diffstat (limited to 'drivers/gpio/gpio-uniphier.c')
-rw-r--r--drivers/gpio/gpio-uniphier.c508
1 files changed, 508 insertions, 0 deletions
diff --git a/drivers/gpio/gpio-uniphier.c b/drivers/gpio/gpio-uniphier.c
new file mode 100644
index 000000000000..016d7427ebfa
--- /dev/null
+++ b/drivers/gpio/gpio-uniphier.c
@@ -0,0 +1,508 @@
1/*
2 * Copyright (C) 2017 Socionext Inc.
3 * Author: Masahiro Yamada <yamada.masahiro@socionext.com>
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 as
7 * 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/bitops.h>
16#include <linux/gpio/driver.h>
17#include <linux/irq.h>
18#include <linux/irqdomain.h>
19#include <linux/module.h>
20#include <linux/of.h>
21#include <linux/of_device.h>
22#include <linux/of_irq.h>
23#include <linux/platform_device.h>
24#include <linux/spinlock.h>
25#include <dt-bindings/gpio/uniphier-gpio.h>
26
27#define UNIPHIER_GPIO_BANK_MASK \
28 GENMASK((UNIPHIER_GPIO_LINES_PER_BANK) - 1, 0)
29
30#define UNIPHIER_GPIO_IRQ_MAX_NUM 24
31
32#define UNIPHIER_GPIO_PORT_DATA 0x0 /* data */
33#define UNIPHIER_GPIO_PORT_DIR 0x4 /* direction (1:in, 0:out) */
34#define UNIPHIER_GPIO_IRQ_EN 0x90 /* irq enable */
35#define UNIPHIER_GPIO_IRQ_MODE 0x94 /* irq mode (1: both edge) */
36#define UNIPHIER_GPIO_IRQ_FLT_EN 0x98 /* noise filter enable */
37#define UNIPHIER_GPIO_IRQ_FLT_CYC 0x9c /* noise filter clock cycle */
38
39struct uniphier_gpio_priv {
40 struct gpio_chip chip;
41 struct irq_chip irq_chip;
42 struct irq_domain *domain;
43 void __iomem *regs;
44 spinlock_t lock;
45 u32 saved_vals[0];
46};
47
48static unsigned int uniphier_gpio_bank_to_reg(unsigned int bank)
49{
50 unsigned int reg;
51
52 reg = (bank + 1) * 8;
53
54 /*
55 * Unfortunately, the GPIO port registers are not contiguous because
56 * offset 0x90-0x9f is used for IRQ. Add 0x10 when crossing the region.
57 */
58 if (reg >= UNIPHIER_GPIO_IRQ_EN)
59 reg += 0x10;
60
61 return reg;
62}
63
64static void uniphier_gpio_get_bank_and_mask(unsigned int offset,
65 unsigned int *bank, u32 *mask)
66{
67 *bank = offset / UNIPHIER_GPIO_LINES_PER_BANK;
68 *mask = BIT(offset % UNIPHIER_GPIO_LINES_PER_BANK);
69}
70
71static void uniphier_gpio_reg_update(struct uniphier_gpio_priv *priv,
72 unsigned int reg, u32 mask, u32 val)
73{
74 unsigned long flags;
75 u32 tmp;
76
77 spin_lock_irqsave(&priv->lock, flags);
78 tmp = readl(priv->regs + reg);
79 tmp &= ~mask;
80 tmp |= mask & val;
81 writel(tmp, priv->regs + reg);
82 spin_unlock_irqrestore(&priv->lock, flags);
83}
84
85static void uniphier_gpio_bank_write(struct gpio_chip *chip, unsigned int bank,
86 unsigned int reg, u32 mask, u32 val)
87{
88 struct uniphier_gpio_priv *priv = gpiochip_get_data(chip);
89
90 if (!mask)
91 return;
92
93 uniphier_gpio_reg_update(priv, uniphier_gpio_bank_to_reg(bank) + reg,
94 mask, val);
95}
96
97static void uniphier_gpio_offset_write(struct gpio_chip *chip,
98 unsigned int offset, unsigned int reg,
99 int val)
100{
101 unsigned int bank;
102 u32 mask;
103
104 uniphier_gpio_get_bank_and_mask(offset, &bank, &mask);
105
106 uniphier_gpio_bank_write(chip, bank, reg, mask, val ? mask : 0);
107}
108
109static int uniphier_gpio_offset_read(struct gpio_chip *chip,
110 unsigned int offset, unsigned int reg)
111{
112 struct uniphier_gpio_priv *priv = gpiochip_get_data(chip);
113 unsigned int bank, reg_offset;
114 u32 mask;
115
116 uniphier_gpio_get_bank_and_mask(offset, &bank, &mask);
117 reg_offset = uniphier_gpio_bank_to_reg(bank) + reg;
118
119 return !!(readl(priv->regs + reg_offset) & mask);
120}
121
122static int uniphier_gpio_get_direction(struct gpio_chip *chip,
123 unsigned int offset)
124{
125 return uniphier_gpio_offset_read(chip, offset, UNIPHIER_GPIO_PORT_DIR);
126}
127
128static int uniphier_gpio_direction_input(struct gpio_chip *chip,
129 unsigned int offset)
130{
131 uniphier_gpio_offset_write(chip, offset, UNIPHIER_GPIO_PORT_DIR, 1);
132
133 return 0;
134}
135
136static int uniphier_gpio_direction_output(struct gpio_chip *chip,
137 unsigned int offset, int val)
138{
139 uniphier_gpio_offset_write(chip, offset, UNIPHIER_GPIO_PORT_DATA, val);
140 uniphier_gpio_offset_write(chip, offset, UNIPHIER_GPIO_PORT_DIR, 0);
141
142 return 0;
143}
144
145static int uniphier_gpio_get(struct gpio_chip *chip, unsigned int offset)
146{
147 return uniphier_gpio_offset_read(chip, offset, UNIPHIER_GPIO_PORT_DATA);
148}
149
150static void uniphier_gpio_set(struct gpio_chip *chip,
151 unsigned int offset, int val)
152{
153 uniphier_gpio_offset_write(chip, offset, UNIPHIER_GPIO_PORT_DATA, val);
154}
155
156static void uniphier_gpio_set_multiple(struct gpio_chip *chip,
157 unsigned long *mask, unsigned long *bits)
158{
159 unsigned int bank, shift, bank_mask, bank_bits;
160 int i;
161
162 for (i = 0; i < chip->ngpio; i += UNIPHIER_GPIO_LINES_PER_BANK) {
163 bank = i / UNIPHIER_GPIO_LINES_PER_BANK;
164 shift = i % BITS_PER_LONG;
165 bank_mask = (mask[BIT_WORD(i)] >> shift) &
166 UNIPHIER_GPIO_BANK_MASK;
167 bank_bits = bits[BIT_WORD(i)] >> shift;
168
169 uniphier_gpio_bank_write(chip, bank, UNIPHIER_GPIO_PORT_DATA,
170 bank_mask, bank_bits);
171 }
172}
173
174static int uniphier_gpio_to_irq(struct gpio_chip *chip, unsigned int offset)
175{
176 struct irq_fwspec fwspec;
177
178 if (offset < UNIPHIER_GPIO_IRQ_OFFSET)
179 return -ENXIO;
180
181 fwspec.fwnode = of_node_to_fwnode(chip->parent->of_node);
182 fwspec.param_count = 2;
183 fwspec.param[0] = offset - UNIPHIER_GPIO_IRQ_OFFSET;
184 fwspec.param[1] = IRQ_TYPE_NONE;
185
186 return irq_create_fwspec_mapping(&fwspec);
187}
188
189static void uniphier_gpio_irq_mask(struct irq_data *data)
190{
191 struct uniphier_gpio_priv *priv = data->chip_data;
192 u32 mask = BIT(data->hwirq);
193
194 uniphier_gpio_reg_update(priv, UNIPHIER_GPIO_IRQ_EN, mask, 0);
195
196 return irq_chip_mask_parent(data);
197}
198
199static void uniphier_gpio_irq_unmask(struct irq_data *data)
200{
201 struct uniphier_gpio_priv *priv = data->chip_data;
202 u32 mask = BIT(data->hwirq);
203
204 uniphier_gpio_reg_update(priv, UNIPHIER_GPIO_IRQ_EN, mask, mask);
205
206 return irq_chip_unmask_parent(data);
207}
208
209static int uniphier_gpio_irq_set_type(struct irq_data *data, unsigned int type)
210{
211 struct uniphier_gpio_priv *priv = data->chip_data;
212 u32 mask = BIT(data->hwirq);
213 u32 val = 0;
214
215 if (type == IRQ_TYPE_EDGE_BOTH) {
216 val = mask;
217 type = IRQ_TYPE_EDGE_FALLING;
218 }
219
220 uniphier_gpio_reg_update(priv, UNIPHIER_GPIO_IRQ_MODE, mask, val);
221 /* To enable both edge detection, the noise filter must be enabled. */
222 uniphier_gpio_reg_update(priv, UNIPHIER_GPIO_IRQ_FLT_EN, mask, val);
223
224 return irq_chip_set_type_parent(data, type);
225}
226
227static int uniphier_gpio_irq_get_parent_hwirq(struct uniphier_gpio_priv *priv,
228 unsigned int hwirq)
229{
230 struct device_node *np = priv->chip.parent->of_node;
231 const __be32 *range;
232 u32 base, parent_base, size;
233 int len;
234
235 range = of_get_property(np, "socionext,interrupt-ranges", &len);
236 if (!range)
237 return -EINVAL;
238
239 len /= sizeof(*range);
240
241 for (; len >= 3; len -= 3) {
242 base = be32_to_cpu(*range++);
243 parent_base = be32_to_cpu(*range++);
244 size = be32_to_cpu(*range++);
245
246 if (base <= hwirq && hwirq < base + size)
247 return hwirq - base + parent_base;
248 }
249
250 return -ENOENT;
251}
252
253static int uniphier_gpio_irq_domain_translate(struct irq_domain *domain,
254 struct irq_fwspec *fwspec,
255 unsigned long *out_hwirq,
256 unsigned int *out_type)
257{
258 if (WARN_ON(fwspec->param_count < 2))
259 return -EINVAL;
260
261 *out_hwirq = fwspec->param[0];
262 *out_type = fwspec->param[1] & IRQ_TYPE_SENSE_MASK;
263
264 return 0;
265}
266
267static int uniphier_gpio_irq_domain_alloc(struct irq_domain *domain,
268 unsigned int virq,
269 unsigned int nr_irqs, void *arg)
270{
271 struct uniphier_gpio_priv *priv = domain->host_data;
272 struct irq_fwspec parent_fwspec;
273 irq_hw_number_t hwirq;
274 unsigned int type;
275 int ret;
276
277 if (WARN_ON(nr_irqs != 1))
278 return -EINVAL;
279
280 ret = uniphier_gpio_irq_domain_translate(domain, arg, &hwirq, &type);
281 if (ret)
282 return ret;
283
284 ret = uniphier_gpio_irq_get_parent_hwirq(priv, hwirq);
285 if (ret < 0)
286 return ret;
287
288 /* parent is UniPhier AIDET */
289 parent_fwspec.fwnode = domain->parent->fwnode;
290 parent_fwspec.param_count = 2;
291 parent_fwspec.param[0] = ret;
292 parent_fwspec.param[1] = (type == IRQ_TYPE_EDGE_BOTH) ?
293 IRQ_TYPE_EDGE_FALLING : type;
294
295 ret = irq_domain_set_hwirq_and_chip(domain, virq, hwirq,
296 &priv->irq_chip, priv);
297 if (ret)
298 return ret;
299
300 return irq_domain_alloc_irqs_parent(domain, virq, 1, &parent_fwspec);
301}
302
303static int uniphier_gpio_irq_domain_activate(struct irq_domain *domain,
304 struct irq_data *data, bool early)
305{
306 struct uniphier_gpio_priv *priv = domain->host_data;
307 struct gpio_chip *chip = &priv->chip;
308
309 gpiochip_lock_as_irq(chip, data->hwirq + UNIPHIER_GPIO_IRQ_OFFSET);
310 return 0;
311}
312
313static void uniphier_gpio_irq_domain_deactivate(struct irq_domain *domain,
314 struct irq_data *data)
315{
316 struct uniphier_gpio_priv *priv = domain->host_data;
317 struct gpio_chip *chip = &priv->chip;
318
319 gpiochip_unlock_as_irq(chip, data->hwirq + UNIPHIER_GPIO_IRQ_OFFSET);
320}
321
322static const struct irq_domain_ops uniphier_gpio_irq_domain_ops = {
323 .alloc = uniphier_gpio_irq_domain_alloc,
324 .free = irq_domain_free_irqs_common,
325 .activate = uniphier_gpio_irq_domain_activate,
326 .deactivate = uniphier_gpio_irq_domain_deactivate,
327 .translate = uniphier_gpio_irq_domain_translate,
328};
329
330static void uniphier_gpio_hw_init(struct uniphier_gpio_priv *priv)
331{
332 /*
333 * Due to the hardware design, the noise filter must be enabled to
334 * detect both edge interrupts. This filter is intended to remove the
335 * noise from the irq lines. It does not work for GPIO input, so GPIO
336 * debounce is not supported. Unfortunately, the filter period is
337 * shared among all irq lines. Just choose a sensible period here.
338 */
339 writel(0xff, priv->regs + UNIPHIER_GPIO_IRQ_FLT_CYC);
340}
341
342static unsigned int uniphier_gpio_get_nbanks(unsigned int ngpio)
343{
344 return DIV_ROUND_UP(ngpio, UNIPHIER_GPIO_LINES_PER_BANK);
345}
346
347static int uniphier_gpio_probe(struct platform_device *pdev)
348{
349 struct device *dev = &pdev->dev;
350 struct device_node *parent_np;
351 struct irq_domain *parent_domain;
352 struct uniphier_gpio_priv *priv;
353 struct gpio_chip *chip;
354 struct irq_chip *irq_chip;
355 struct resource *regs;
356 unsigned int nregs;
357 u32 ngpios;
358 int ret;
359
360 parent_np = of_irq_find_parent(dev->of_node);
361 if (!parent_np)
362 return -ENXIO;
363
364 parent_domain = irq_find_host(parent_np);
365 of_node_put(parent_np);
366 if (!parent_domain)
367 return -EPROBE_DEFER;
368
369 ret = of_property_read_u32(dev->of_node, "ngpios", &ngpios);
370 if (ret)
371 return ret;
372
373 nregs = uniphier_gpio_get_nbanks(ngpios) * 2 + 3;
374 priv = devm_kzalloc(dev,
375 sizeof(*priv) + sizeof(priv->saved_vals[0]) * nregs,
376 GFP_KERNEL);
377 if (!priv)
378 return -ENOMEM;
379
380 regs = platform_get_resource(pdev, IORESOURCE_MEM, 0);
381 priv->regs = devm_ioremap_resource(dev, regs);
382 if (IS_ERR(priv->regs))
383 return PTR_ERR(priv->regs);
384
385 spin_lock_init(&priv->lock);
386
387 chip = &priv->chip;
388 chip->label = dev_name(dev);
389 chip->parent = dev;
390 chip->request = gpiochip_generic_request;
391 chip->free = gpiochip_generic_free;
392 chip->get_direction = uniphier_gpio_get_direction;
393 chip->direction_input = uniphier_gpio_direction_input;
394 chip->direction_output = uniphier_gpio_direction_output;
395 chip->get = uniphier_gpio_get;
396 chip->set = uniphier_gpio_set;
397 chip->set_multiple = uniphier_gpio_set_multiple;
398 chip->to_irq = uniphier_gpio_to_irq;
399 chip->base = -1;
400 chip->ngpio = ngpios;
401
402 irq_chip = &priv->irq_chip;
403 irq_chip->name = dev_name(dev);
404 irq_chip->irq_mask = uniphier_gpio_irq_mask;
405 irq_chip->irq_unmask = uniphier_gpio_irq_unmask;
406 irq_chip->irq_eoi = irq_chip_eoi_parent;
407 irq_chip->irq_set_affinity = irq_chip_set_affinity_parent;
408 irq_chip->irq_set_type = uniphier_gpio_irq_set_type;
409
410 uniphier_gpio_hw_init(priv);
411
412 ret = devm_gpiochip_add_data(dev, chip, priv);
413 if (ret)
414 return ret;
415
416 priv->domain = irq_domain_create_hierarchy(
417 parent_domain, 0,
418 UNIPHIER_GPIO_IRQ_MAX_NUM,
419 of_node_to_fwnode(dev->of_node),
420 &uniphier_gpio_irq_domain_ops, priv);
421 if (!priv->domain)
422 return -ENOMEM;
423
424 platform_set_drvdata(pdev, priv);
425
426 return 0;
427}
428
429static int uniphier_gpio_remove(struct platform_device *pdev)
430{
431 struct uniphier_gpio_priv *priv = platform_get_drvdata(pdev);
432
433 irq_domain_remove(priv->domain);
434
435 return 0;
436}
437
438static int __maybe_unused uniphier_gpio_suspend(struct device *dev)
439{
440 struct uniphier_gpio_priv *priv = dev_get_drvdata(dev);
441 unsigned int nbanks = uniphier_gpio_get_nbanks(priv->chip.ngpio);
442 u32 *val = priv->saved_vals;
443 unsigned int reg;
444 int i;
445
446 for (i = 0; i < nbanks; i++) {
447 reg = uniphier_gpio_bank_to_reg(i);
448
449 *val++ = readl(priv->regs + reg + UNIPHIER_GPIO_PORT_DATA);
450 *val++ = readl(priv->regs + reg + UNIPHIER_GPIO_PORT_DIR);
451 }
452
453 *val++ = readl(priv->regs + UNIPHIER_GPIO_IRQ_EN);
454 *val++ = readl(priv->regs + UNIPHIER_GPIO_IRQ_MODE);
455 *val++ = readl(priv->regs + UNIPHIER_GPIO_IRQ_FLT_EN);
456
457 return 0;
458}
459
460static int __maybe_unused uniphier_gpio_resume(struct device *dev)
461{
462 struct uniphier_gpio_priv *priv = dev_get_drvdata(dev);
463 unsigned int nbanks = uniphier_gpio_get_nbanks(priv->chip.ngpio);
464 const u32 *val = priv->saved_vals;
465 unsigned int reg;
466 int i;
467
468 for (i = 0; i < nbanks; i++) {
469 reg = uniphier_gpio_bank_to_reg(i);
470
471 writel(*val++, priv->regs + reg + UNIPHIER_GPIO_PORT_DATA);
472 writel(*val++, priv->regs + reg + UNIPHIER_GPIO_PORT_DIR);
473 }
474
475 writel(*val++, priv->regs + UNIPHIER_GPIO_IRQ_EN);
476 writel(*val++, priv->regs + UNIPHIER_GPIO_IRQ_MODE);
477 writel(*val++, priv->regs + UNIPHIER_GPIO_IRQ_FLT_EN);
478
479 uniphier_gpio_hw_init(priv);
480
481 return 0;
482}
483
484static const struct dev_pm_ops uniphier_gpio_pm_ops = {
485 SET_LATE_SYSTEM_SLEEP_PM_OPS(uniphier_gpio_suspend,
486 uniphier_gpio_resume)
487};
488
489static const struct of_device_id uniphier_gpio_match[] = {
490 { .compatible = "socionext,uniphier-gpio" },
491 { /* sentinel */ }
492};
493MODULE_DEVICE_TABLE(of, uniphier_gpio_match);
494
495static struct platform_driver uniphier_gpio_driver = {
496 .probe = uniphier_gpio_probe,
497 .remove = uniphier_gpio_remove,
498 .driver = {
499 .name = "uniphier-gpio",
500 .of_match_table = uniphier_gpio_match,
501 .pm = &uniphier_gpio_pm_ops,
502 },
503};
504module_platform_driver(uniphier_gpio_driver);
505
506MODULE_AUTHOR("Masahiro Yamada <yamada.masahiro@socionext.com>");
507MODULE_DESCRIPTION("UniPhier GPIO driver");
508MODULE_LICENSE("GPL");