summaryrefslogtreecommitdiffstats
path: root/drivers/gpio
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2013-05-07 13:57:51 -0400
committerLinus Torvalds <torvalds@linux-foundation.org>2013-05-07 13:57:51 -0400
commita8c4b90e670be3b01e9395c7310639c8109fc77e (patch)
tree272f7988aeeaf930efd594f66c1a41a7d28ecd74 /drivers/gpio
parenteac84105cddf8686440aaa9fbcb58093e37e4180 (diff)
parent9251c6c0dc929d8eec6751c12ef312597f84e147 (diff)
Merge tag 'soc-for-linus-2' of git://git.kernel.org/pub/scm/linux/kernel/git/arm/arm-soc
Pull ARM SoC platform updates (part 2) from Arnd Bergmann: "These patches are all for Renesas shmobile, and depend on the earlier pinctrl updates. Remarkably, this adds support for three new SoCs: r8a73a4, r8a73a4 and r8a7778. The bulk of the code added for these is for pinctrl (using the new subsystem) and for clocks (not yet using the common clock subsystem). The latter will have to get converted in one of the upcoming releases, but shmobile is not ready for that yet. The series also contains Renesas shmobile board changes, adding one board file for each of the three new SoCs. These boards are using a mix of classic and device-tree based probing, as there is still a lot of infrastructure in shmobile that has not been converted to DT yet. Once those are resolved to the degree that no board specific setup code is needed, they can get folded into the respective SoC setup files." * tag 'soc-for-linus-2' of git://git.kernel.org/pub/scm/linux/kernel/git/arm/arm-soc: (78 commits) ARM: shmobile: use r8a7790 timer setup code on Lager ARM: shmobile: force enable of r8a7790 arch timer ARM: shmobile: Add second I/O range for r8a7790 PFC ARM: shmobile: bockw: enable network settings on bootargs ARM: shmobile: bockw: add SMSC ethernet support ARM: shmobile: R8A7778: add Ether support ARM: shmobile: bockw: enable SMSC ethernet on defconfig ARM: shmobile: r8a7778: add r8a7778_init_irq_extpin() ARM: shmobile: r8a7778: remove pointless PLATFORM_INFO() ARM: shmobile: mackerel: clean up MMCIF vs. SDHI1 selection ARM: shmobile: mackerel: add interrupt names for SDHI0 ARM: shmobile: mackerel: switch SDHI and MMCIF interfaces to slot-gpio ARM: shmobile: mackerel: remove OCR masks, where regulators are used ARM: shmobile: mackerel: SDHI resources do not have to be numbered ARM: shmobile: Initial r8a7790 Lager board support ARM: shmobile: APE6EVM LAN9220 support ARM: shmobile: APE6EVM PFC support ARM: shmobile: APE6EVM base support ARM: shmobile: kzm9g-reference: add ethernet support ARM: shmobile: add R-Car M1A Bock-W platform support ...
Diffstat (limited to 'drivers/gpio')
-rw-r--r--drivers/gpio/Kconfig6
-rw-r--r--drivers/gpio/Makefile1
-rw-r--r--drivers/gpio/gpio-rcar.c396
3 files changed, 403 insertions, 0 deletions
diff --git a/drivers/gpio/Kconfig b/drivers/gpio/Kconfig
index ff7f0c87745a..c22eed9481e3 100644
--- a/drivers/gpio/Kconfig
+++ b/drivers/gpio/Kconfig
@@ -204,6 +204,12 @@ config GPIO_PXA
204 help 204 help
205 Say yes here to support the PXA GPIO device 205 Say yes here to support the PXA GPIO device
206 206
207config GPIO_RCAR
208 tristate "Renesas R-Car GPIO"
209 depends on ARM
210 help
211 Say yes here to support GPIO on Renesas R-Car SoCs.
212
207config GPIO_SPEAR_SPICS 213config GPIO_SPEAR_SPICS
208 bool "ST SPEAr13xx SPI Chip Select as GPIO support" 214 bool "ST SPEAr13xx SPI Chip Select as GPIO support"
209 depends on PLAT_SPEAR 215 depends on PLAT_SPEAR
diff --git a/drivers/gpio/Makefile b/drivers/gpio/Makefile
index 6aab73d577d1..0cb2d656ad16 100644
--- a/drivers/gpio/Makefile
+++ b/drivers/gpio/Makefile
@@ -58,6 +58,7 @@ obj-$(CONFIG_GPIO_PL061) += gpio-pl061.o
58obj-$(CONFIG_GPIO_PXA) += gpio-pxa.o 58obj-$(CONFIG_GPIO_PXA) += gpio-pxa.o
59obj-$(CONFIG_GPIO_RC5T583) += gpio-rc5t583.o 59obj-$(CONFIG_GPIO_RC5T583) += gpio-rc5t583.o
60obj-$(CONFIG_GPIO_RDC321X) += gpio-rdc321x.o 60obj-$(CONFIG_GPIO_RDC321X) += gpio-rdc321x.o
61obj-$(CONFIG_GPIO_RCAR) += gpio-rcar.o
61obj-$(CONFIG_PLAT_SAMSUNG) += gpio-samsung.o 62obj-$(CONFIG_PLAT_SAMSUNG) += gpio-samsung.o
62obj-$(CONFIG_ARCH_SA1100) += gpio-sa1100.o 63obj-$(CONFIG_ARCH_SA1100) += gpio-sa1100.o
63obj-$(CONFIG_GPIO_SCH) += gpio-sch.o 64obj-$(CONFIG_GPIO_SCH) += gpio-sch.o
diff --git a/drivers/gpio/gpio-rcar.c b/drivers/gpio/gpio-rcar.c
new file mode 100644
index 000000000000..b4ca450947b8
--- /dev/null
+++ b/drivers/gpio/gpio-rcar.c
@@ -0,0 +1,396 @@
1/*
2 * Renesas R-Car GPIO Support
3 *
4 * Copyright (C) 2013 Magnus Damm
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 */
15
16#include <linux/err.h>
17#include <linux/gpio.h>
18#include <linux/init.h>
19#include <linux/interrupt.h>
20#include <linux/io.h>
21#include <linux/ioport.h>
22#include <linux/irq.h>
23#include <linux/irqdomain.h>
24#include <linux/module.h>
25#include <linux/pinctrl/consumer.h>
26#include <linux/platform_data/gpio-rcar.h>
27#include <linux/platform_device.h>
28#include <linux/spinlock.h>
29#include <linux/slab.h>
30
31struct gpio_rcar_priv {
32 void __iomem *base;
33 spinlock_t lock;
34 struct gpio_rcar_config config;
35 struct platform_device *pdev;
36 struct gpio_chip gpio_chip;
37 struct irq_chip irq_chip;
38 struct irq_domain *irq_domain;
39};
40
41#define IOINTSEL 0x00
42#define INOUTSEL 0x04
43#define OUTDT 0x08
44#define INDT 0x0c
45#define INTDT 0x10
46#define INTCLR 0x14
47#define INTMSK 0x18
48#define MSKCLR 0x1c
49#define POSNEG 0x20
50#define EDGLEVEL 0x24
51#define FILONOFF 0x28
52
53static inline u32 gpio_rcar_read(struct gpio_rcar_priv *p, int offs)
54{
55 return ioread32(p->base + offs);
56}
57
58static inline void gpio_rcar_write(struct gpio_rcar_priv *p, int offs,
59 u32 value)
60{
61 iowrite32(value, p->base + offs);
62}
63
64static void gpio_rcar_modify_bit(struct gpio_rcar_priv *p, int offs,
65 int bit, bool value)
66{
67 u32 tmp = gpio_rcar_read(p, offs);
68
69 if (value)
70 tmp |= BIT(bit);
71 else
72 tmp &= ~BIT(bit);
73
74 gpio_rcar_write(p, offs, tmp);
75}
76
77static void gpio_rcar_irq_disable(struct irq_data *d)
78{
79 struct gpio_rcar_priv *p = irq_data_get_irq_chip_data(d);
80
81 gpio_rcar_write(p, INTMSK, ~BIT(irqd_to_hwirq(d)));
82}
83
84static void gpio_rcar_irq_enable(struct irq_data *d)
85{
86 struct gpio_rcar_priv *p = irq_data_get_irq_chip_data(d);
87
88 gpio_rcar_write(p, MSKCLR, BIT(irqd_to_hwirq(d)));
89}
90
91static void gpio_rcar_config_interrupt_input_mode(struct gpio_rcar_priv *p,
92 unsigned int hwirq,
93 bool active_high_rising_edge,
94 bool level_trigger)
95{
96 unsigned long flags;
97
98 /* follow steps in the GPIO documentation for
99 * "Setting Edge-Sensitive Interrupt Input Mode" and
100 * "Setting Level-Sensitive Interrupt Input Mode"
101 */
102
103 spin_lock_irqsave(&p->lock, flags);
104
105 /* Configure postive or negative logic in POSNEG */
106 gpio_rcar_modify_bit(p, POSNEG, hwirq, !active_high_rising_edge);
107
108 /* Configure edge or level trigger in EDGLEVEL */
109 gpio_rcar_modify_bit(p, EDGLEVEL, hwirq, !level_trigger);
110
111 /* Select "Interrupt Input Mode" in IOINTSEL */
112 gpio_rcar_modify_bit(p, IOINTSEL, hwirq, true);
113
114 /* Write INTCLR in case of edge trigger */
115 if (!level_trigger)
116 gpio_rcar_write(p, INTCLR, BIT(hwirq));
117
118 spin_unlock_irqrestore(&p->lock, flags);
119}
120
121static int gpio_rcar_irq_set_type(struct irq_data *d, unsigned int type)
122{
123 struct gpio_rcar_priv *p = irq_data_get_irq_chip_data(d);
124 unsigned int hwirq = irqd_to_hwirq(d);
125
126 dev_dbg(&p->pdev->dev, "sense irq = %d, type = %d\n", hwirq, type);
127
128 switch (type & IRQ_TYPE_SENSE_MASK) {
129 case IRQ_TYPE_LEVEL_HIGH:
130 gpio_rcar_config_interrupt_input_mode(p, hwirq, true, true);
131 break;
132 case IRQ_TYPE_LEVEL_LOW:
133 gpio_rcar_config_interrupt_input_mode(p, hwirq, false, true);
134 break;
135 case IRQ_TYPE_EDGE_RISING:
136 gpio_rcar_config_interrupt_input_mode(p, hwirq, true, false);
137 break;
138 case IRQ_TYPE_EDGE_FALLING:
139 gpio_rcar_config_interrupt_input_mode(p, hwirq, false, false);
140 break;
141 default:
142 return -EINVAL;
143 }
144 return 0;
145}
146
147static irqreturn_t gpio_rcar_irq_handler(int irq, void *dev_id)
148{
149 struct gpio_rcar_priv *p = dev_id;
150 u32 pending;
151 unsigned int offset, irqs_handled = 0;
152
153 while ((pending = gpio_rcar_read(p, INTDT))) {
154 offset = __ffs(pending);
155 gpio_rcar_write(p, INTCLR, BIT(offset));
156 generic_handle_irq(irq_find_mapping(p->irq_domain, offset));
157 irqs_handled++;
158 }
159
160 return irqs_handled ? IRQ_HANDLED : IRQ_NONE;
161}
162
163static inline struct gpio_rcar_priv *gpio_to_priv(struct gpio_chip *chip)
164{
165 return container_of(chip, struct gpio_rcar_priv, gpio_chip);
166}
167
168static void gpio_rcar_config_general_input_output_mode(struct gpio_chip *chip,
169 unsigned int gpio,
170 bool output)
171{
172 struct gpio_rcar_priv *p = gpio_to_priv(chip);
173 unsigned long flags;
174
175 /* follow steps in the GPIO documentation for
176 * "Setting General Output Mode" and
177 * "Setting General Input Mode"
178 */
179
180 spin_lock_irqsave(&p->lock, flags);
181
182 /* Configure postive logic in POSNEG */
183 gpio_rcar_modify_bit(p, POSNEG, gpio, false);
184
185 /* Select "General Input/Output Mode" in IOINTSEL */
186 gpio_rcar_modify_bit(p, IOINTSEL, gpio, false);
187
188 /* Select Input Mode or Output Mode in INOUTSEL */
189 gpio_rcar_modify_bit(p, INOUTSEL, gpio, output);
190
191 spin_unlock_irqrestore(&p->lock, flags);
192}
193
194static int gpio_rcar_request(struct gpio_chip *chip, unsigned offset)
195{
196 return pinctrl_request_gpio(chip->base + offset);
197}
198
199static void gpio_rcar_free(struct gpio_chip *chip, unsigned offset)
200{
201 pinctrl_free_gpio(chip->base + offset);
202
203 /* Set the GPIO as an input to ensure that the next GPIO request won't
204 * drive the GPIO pin as an output.
205 */
206 gpio_rcar_config_general_input_output_mode(chip, offset, false);
207}
208
209static int gpio_rcar_direction_input(struct gpio_chip *chip, unsigned offset)
210{
211 gpio_rcar_config_general_input_output_mode(chip, offset, false);
212 return 0;
213}
214
215static int gpio_rcar_get(struct gpio_chip *chip, unsigned offset)
216{
217 return (int)(gpio_rcar_read(gpio_to_priv(chip), INDT) & BIT(offset));
218}
219
220static void gpio_rcar_set(struct gpio_chip *chip, unsigned offset, int value)
221{
222 struct gpio_rcar_priv *p = gpio_to_priv(chip);
223 unsigned long flags;
224
225 spin_lock_irqsave(&p->lock, flags);
226 gpio_rcar_modify_bit(p, OUTDT, offset, value);
227 spin_unlock_irqrestore(&p->lock, flags);
228}
229
230static int gpio_rcar_direction_output(struct gpio_chip *chip, unsigned offset,
231 int value)
232{
233 /* write GPIO value to output before selecting output mode of pin */
234 gpio_rcar_set(chip, offset, value);
235 gpio_rcar_config_general_input_output_mode(chip, offset, true);
236 return 0;
237}
238
239static int gpio_rcar_to_irq(struct gpio_chip *chip, unsigned offset)
240{
241 return irq_create_mapping(gpio_to_priv(chip)->irq_domain, offset);
242}
243
244static int gpio_rcar_irq_domain_map(struct irq_domain *h, unsigned int virq,
245 irq_hw_number_t hw)
246{
247 struct gpio_rcar_priv *p = h->host_data;
248
249 dev_dbg(&p->pdev->dev, "map hw irq = %d, virq = %d\n", (int)hw, virq);
250
251 irq_set_chip_data(virq, h->host_data);
252 irq_set_chip_and_handler(virq, &p->irq_chip, handle_level_irq);
253 set_irq_flags(virq, IRQF_VALID); /* kill me now */
254 return 0;
255}
256
257static struct irq_domain_ops gpio_rcar_irq_domain_ops = {
258 .map = gpio_rcar_irq_domain_map,
259};
260
261static int gpio_rcar_probe(struct platform_device *pdev)
262{
263 struct gpio_rcar_config *pdata = pdev->dev.platform_data;
264 struct gpio_rcar_priv *p;
265 struct resource *io, *irq;
266 struct gpio_chip *gpio_chip;
267 struct irq_chip *irq_chip;
268 const char *name = dev_name(&pdev->dev);
269 int ret;
270
271 p = devm_kzalloc(&pdev->dev, sizeof(*p), GFP_KERNEL);
272 if (!p) {
273 dev_err(&pdev->dev, "failed to allocate driver data\n");
274 ret = -ENOMEM;
275 goto err0;
276 }
277
278 /* deal with driver instance configuration */
279 if (pdata)
280 p->config = *pdata;
281
282 p->pdev = pdev;
283 platform_set_drvdata(pdev, p);
284 spin_lock_init(&p->lock);
285
286 io = platform_get_resource(pdev, IORESOURCE_MEM, 0);
287 irq = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
288
289 if (!io || !irq) {
290 dev_err(&pdev->dev, "missing IRQ or IOMEM\n");
291 ret = -EINVAL;
292 goto err0;
293 }
294
295 p->base = devm_ioremap_nocache(&pdev->dev, io->start,
296 resource_size(io));
297 if (!p->base) {
298 dev_err(&pdev->dev, "failed to remap I/O memory\n");
299 ret = -ENXIO;
300 goto err0;
301 }
302
303 gpio_chip = &p->gpio_chip;
304 gpio_chip->request = gpio_rcar_request;
305 gpio_chip->free = gpio_rcar_free;
306 gpio_chip->direction_input = gpio_rcar_direction_input;
307 gpio_chip->get = gpio_rcar_get;
308 gpio_chip->direction_output = gpio_rcar_direction_output;
309 gpio_chip->set = gpio_rcar_set;
310 gpio_chip->to_irq = gpio_rcar_to_irq;
311 gpio_chip->label = name;
312 gpio_chip->owner = THIS_MODULE;
313 gpio_chip->base = p->config.gpio_base;
314 gpio_chip->ngpio = p->config.number_of_pins;
315
316 irq_chip = &p->irq_chip;
317 irq_chip->name = name;
318 irq_chip->irq_mask = gpio_rcar_irq_disable;
319 irq_chip->irq_unmask = gpio_rcar_irq_enable;
320 irq_chip->irq_enable = gpio_rcar_irq_enable;
321 irq_chip->irq_disable = gpio_rcar_irq_disable;
322 irq_chip->irq_set_type = gpio_rcar_irq_set_type;
323 irq_chip->flags = IRQCHIP_SKIP_SET_WAKE | IRQCHIP_SET_TYPE_MASKED;
324
325 p->irq_domain = irq_domain_add_simple(pdev->dev.of_node,
326 p->config.number_of_pins,
327 p->config.irq_base,
328 &gpio_rcar_irq_domain_ops, p);
329 if (!p->irq_domain) {
330 ret = -ENXIO;
331 dev_err(&pdev->dev, "cannot initialize irq domain\n");
332 goto err1;
333 }
334
335 if (devm_request_irq(&pdev->dev, irq->start,
336 gpio_rcar_irq_handler, 0, name, p)) {
337 dev_err(&pdev->dev, "failed to request IRQ\n");
338 ret = -ENOENT;
339 goto err1;
340 }
341
342 ret = gpiochip_add(gpio_chip);
343 if (ret) {
344 dev_err(&pdev->dev, "failed to add GPIO controller\n");
345 goto err1;
346 }
347
348 dev_info(&pdev->dev, "driving %d GPIOs\n", p->config.number_of_pins);
349
350 /* warn in case of mismatch if irq base is specified */
351 if (p->config.irq_base) {
352 ret = irq_find_mapping(p->irq_domain, 0);
353 if (p->config.irq_base != ret)
354 dev_warn(&pdev->dev, "irq base mismatch (%u/%u)\n",
355 p->config.irq_base, ret);
356 }
357
358 ret = gpiochip_add_pin_range(gpio_chip, p->config.pctl_name, 0,
359 gpio_chip->base, gpio_chip->ngpio);
360 if (ret < 0)
361 dev_warn(&pdev->dev, "failed to add pin range\n");
362
363 return 0;
364
365err1:
366 irq_domain_remove(p->irq_domain);
367err0:
368 return ret;
369}
370
371static int gpio_rcar_remove(struct platform_device *pdev)
372{
373 struct gpio_rcar_priv *p = platform_get_drvdata(pdev);
374 int ret;
375
376 ret = gpiochip_remove(&p->gpio_chip);
377 if (ret)
378 return ret;
379
380 irq_domain_remove(p->irq_domain);
381 return 0;
382}
383
384static struct platform_driver gpio_rcar_device_driver = {
385 .probe = gpio_rcar_probe,
386 .remove = gpio_rcar_remove,
387 .driver = {
388 .name = "gpio_rcar",
389 }
390};
391
392module_platform_driver(gpio_rcar_device_driver);
393
394MODULE_AUTHOR("Magnus Damm");
395MODULE_DESCRIPTION("Renesas R-Car GPIO Driver");
396MODULE_LICENSE("GPL v2");