1 From 4f339b429583965a8eb7c23474414d0730db1215 Mon Sep 17 00:00:00 2001
2 From: popcornmix <popcornmix@gmail.com>
3 Date: Wed, 8 Oct 2014 18:50:05 +0100
4 Subject: [PATCH 002/114] Add bcm2708_gpio driver
6 Signed-off-by: popcornmix <popcornmix@gmail.com>
8 bcm2708: Add extension to configure internal pulls
10 The bcm2708 gpio controller supports internal pulls to be used as pull-up,
11 pull-down or being entirely disabled. As it can be useful for a driver to
12 change the pull configuration from it's default pull-down state, add an
13 extension which allows configuring the pull per gpio.
15 Signed-off-by: Julian Scheel <julian@jusst.de>
17 bcm2708-gpio: Revert the use of pinctrl_request_gpio
19 In non-DT systems, pinctrl_request_gpio always fails causing
20 "requests probe deferral" messages. In DT systems, it isn't useful
21 because the reference counting is independent of the normal pinctrl
24 gpio: Only clear the currently occurring interrupt. Avoids losing interrupts
28 bcm2708_gpio: Avoid calling irq_unmask for all interrupts
30 When setting up the interrupts, specify that the handle_simple_irq
31 handler should be used. This leaves interrupt acknowledgement to
32 the caller, and prevents irq_unmask from being called for all
37 arch/arm/mach-bcm2708/Kconfig | 8 +
38 arch/arm/mach-bcm2708/Makefile | 1 +
39 arch/arm/mach-bcm2708/bcm2708.c | 28 ++
40 arch/arm/mach-bcm2708/bcm2708_gpio.c | 426 ++++++++++++++++++++++++++++++
41 arch/arm/mach-bcm2708/include/mach/gpio.h | 17 ++
42 include/linux/platform_data/bcm2708.h | 23 ++
43 6 files changed, 503 insertions(+)
44 create mode 100644 arch/arm/mach-bcm2708/bcm2708_gpio.c
45 create mode 100644 arch/arm/mach-bcm2708/include/mach/gpio.h
46 create mode 100644 include/linux/platform_data/bcm2708.h
48 diff --git a/arch/arm/mach-bcm2708/Kconfig b/arch/arm/mach-bcm2708/Kconfig
49 index 1f11478..9355841 100644
50 --- a/arch/arm/mach-bcm2708/Kconfig
51 +++ b/arch/arm/mach-bcm2708/Kconfig
52 @@ -9,6 +9,14 @@ config MACH_BCM2708
54 Include support for the Broadcom(R) BCM2708 platform.
57 + bool "BCM2708 gpio support"
58 + depends on MACH_BCM2708
59 + select ARCH_REQUIRE_GPIOLIB
62 + Include support for the Broadcom(R) BCM2708 gpio.
65 bool "Videocore Memory"
66 depends on MACH_BCM2708
67 diff --git a/arch/arm/mach-bcm2708/Makefile b/arch/arm/mach-bcm2708/Makefile
68 index c76f39bc..a722f3f 100644
69 --- a/arch/arm/mach-bcm2708/Makefile
70 +++ b/arch/arm/mach-bcm2708/Makefile
74 obj-$(CONFIG_MACH_BCM2708) += clock.o bcm2708.o armctrl.o vcio.o power.o dma.o
75 +obj-$(CONFIG_BCM2708_GPIO) += bcm2708_gpio.o
76 obj-$(CONFIG_BCM2708_VCMEM) += vc_mem.o
77 diff --git a/arch/arm/mach-bcm2708/bcm2708.c b/arch/arm/mach-bcm2708/bcm2708.c
78 index 9b4e709..7503649 100644
79 --- a/arch/arm/mach-bcm2708/bcm2708.c
80 +++ b/arch/arm/mach-bcm2708/bcm2708.c
81 @@ -331,6 +331,31 @@ static struct platform_device bcm2708_vcio_device = {
85 +#ifdef CONFIG_BCM2708_GPIO
86 +#define BCM_GPIO_DRIVER_NAME "bcm2708_gpio"
88 +static struct resource bcm2708_gpio_resources[] = {
89 + [0] = { /* general purpose I/O */
91 + .end = GPIO_BASE + SZ_4K - 1,
92 + .flags = IORESOURCE_MEM,
96 +static u64 gpio_dmamask = DMA_BIT_MASK(DMA_MASK_BITS_COMMON);
98 +static struct platform_device bcm2708_gpio_device = {
99 + .name = BCM_GPIO_DRIVER_NAME,
100 + .id = -1, /* only one VideoCore I/O area */
101 + .resource = bcm2708_gpio_resources,
102 + .num_resources = ARRAY_SIZE(bcm2708_gpio_resources),
104 + .dma_mask = &gpio_dmamask,
105 + .coherent_dma_mask = DMA_BIT_MASK(DMA_MASK_BITS_COMMON),
110 static struct resource bcm2708_systemtimer_resources[] = {
111 [0] = { /* system timer access */
113 @@ -473,6 +498,9 @@ void __init bcm2708_init(void)
115 bcm_register_device(&bcm2708_dmaman_device);
116 bcm_register_device(&bcm2708_vcio_device);
117 +#ifdef CONFIG_BCM2708_GPIO
118 + bcm_register_device(&bcm2708_gpio_device);
120 bcm_register_device(&bcm2708_systemtimer_device);
121 bcm_register_device(&bcm2708_fb_device);
122 bcm_register_device(&bcm2708_usb_device);
123 diff --git a/arch/arm/mach-bcm2708/bcm2708_gpio.c b/arch/arm/mach-bcm2708/bcm2708_gpio.c
125 index 0000000..c1e9254
127 +++ b/arch/arm/mach-bcm2708/bcm2708_gpio.c
130 + * linux/arch/arm/mach-bcm2708/bcm2708_gpio.c
132 + * Copyright (C) 2010 Broadcom
134 + * This program is free software; you can redistribute it and/or modify
135 + * it under the terms of the GNU General Public License version 2 as
136 + * published by the Free Software Foundation.
140 +#include <linux/spinlock.h>
141 +#include <linux/module.h>
142 +#include <linux/delay.h>
143 +#include <linux/list.h>
144 +#include <linux/io.h>
145 +#include <linux/irq.h>
146 +#include <linux/interrupt.h>
147 +#include <linux/slab.h>
148 +#include <mach/gpio.h>
149 +#include <linux/gpio.h>
150 +#include <linux/platform_device.h>
151 +#include <mach/platform.h>
152 +#include <linux/pinctrl/consumer.h>
154 +#include <linux/platform_data/bcm2708.h>
156 +#define BCM_GPIO_DRIVER_NAME "bcm2708_gpio"
157 +#define DRIVER_NAME BCM_GPIO_DRIVER_NAME
158 +#define BCM_GPIO_USE_IRQ 1
160 +#define GPIOFSEL(x) (0x00+(x)*4)
161 +#define GPIOSET(x) (0x1c+(x)*4)
162 +#define GPIOCLR(x) (0x28+(x)*4)
163 +#define GPIOLEV(x) (0x34+(x)*4)
164 +#define GPIOEDS(x) (0x40+(x)*4)
165 +#define GPIOREN(x) (0x4c+(x)*4)
166 +#define GPIOFEN(x) (0x58+(x)*4)
167 +#define GPIOHEN(x) (0x64+(x)*4)
168 +#define GPIOLEN(x) (0x70+(x)*4)
169 +#define GPIOAREN(x) (0x7c+(x)*4)
170 +#define GPIOAFEN(x) (0x88+(x)*4)
171 +#define GPIOUD(x) (0x94+(x)*4)
172 +#define GPIOUDCLK(x) (0x98+(x)*4)
174 +#define GPIO_BANKS 2
176 +enum { GPIO_FSEL_INPUT, GPIO_FSEL_OUTPUT,
177 + GPIO_FSEL_ALT5, GPIO_FSEL_ALT_4,
178 + GPIO_FSEL_ALT0, GPIO_FSEL_ALT1,
179 + GPIO_FSEL_ALT2, GPIO_FSEL_ALT3,
182 + /* Each of the two spinlocks protects a different set of hardware
183 + * regiters and data structurs. This decouples the code of the IRQ from
184 + * the GPIO code. This also makes the case of a GPIO routine call from
185 + * the IRQ code simpler.
187 +static DEFINE_SPINLOCK(lock); /* GPIO registers */
189 +struct bcm2708_gpio {
190 + struct list_head list;
191 + void __iomem *base;
192 + struct gpio_chip gc;
193 + unsigned long rising[(BCM2708_NR_GPIOS + 31) / 32];
194 + unsigned long falling[(BCM2708_NR_GPIOS + 31) / 32];
195 + unsigned long high[(BCM2708_NR_GPIOS + 31) / 32];
196 + unsigned long low[(BCM2708_NR_GPIOS + 31) / 32];
199 +static int bcm2708_set_function(struct gpio_chip *gc, unsigned offset,
202 + struct bcm2708_gpio *gpio = container_of(gc, struct bcm2708_gpio, gc);
203 + unsigned long flags;
205 + unsigned gpio_bank = offset / 10;
206 + unsigned gpio_field_offset = (offset - 10 * gpio_bank) * 3;
208 +//printk(KERN_ERR DRIVER_NAME ": bcm2708_gpio_set_function %p (%d,%d)\n", gc, offset, function);
209 + if (offset >= BCM2708_NR_GPIOS)
212 + spin_lock_irqsave(&lock, flags);
214 + gpiodir = readl(gpio->base + GPIOFSEL(gpio_bank));
215 + gpiodir &= ~(7 << gpio_field_offset);
216 + gpiodir |= function << gpio_field_offset;
217 + writel(gpiodir, gpio->base + GPIOFSEL(gpio_bank));
218 + spin_unlock_irqrestore(&lock, flags);
219 + gpiodir = readl(gpio->base + GPIOFSEL(gpio_bank));
224 +static int bcm2708_gpio_dir_in(struct gpio_chip *gc, unsigned offset)
226 + return bcm2708_set_function(gc, offset, GPIO_FSEL_INPUT);
229 +static void bcm2708_gpio_set(struct gpio_chip *gc, unsigned offset, int value);
230 +static int bcm2708_gpio_dir_out(struct gpio_chip *gc, unsigned offset,
234 + ret = bcm2708_set_function(gc, offset, GPIO_FSEL_OUTPUT);
236 + bcm2708_gpio_set(gc, offset, value);
240 +static int bcm2708_gpio_get(struct gpio_chip *gc, unsigned offset)
242 + struct bcm2708_gpio *gpio = container_of(gc, struct bcm2708_gpio, gc);
243 + unsigned gpio_bank = offset / 32;
244 + unsigned gpio_field_offset = (offset - 32 * gpio_bank);
247 + if (offset >= BCM2708_NR_GPIOS)
249 + lev = readl(gpio->base + GPIOLEV(gpio_bank));
250 +//printk(KERN_ERR DRIVER_NAME ": bcm2708_gpio_get %p (%d)=%d\n", gc, offset, 0x1 & (lev>>gpio_field_offset));
251 + return 0x1 & (lev >> gpio_field_offset);
254 +static void bcm2708_gpio_set(struct gpio_chip *gc, unsigned offset, int value)
256 + struct bcm2708_gpio *gpio = container_of(gc, struct bcm2708_gpio, gc);
257 + unsigned gpio_bank = offset / 32;
258 + unsigned gpio_field_offset = (offset - 32 * gpio_bank);
259 +//printk(KERN_ERR DRIVER_NAME ": bcm2708_gpio_set %p (%d=%d)\n", gc, offset, value);
260 + if (offset >= BCM2708_NR_GPIOS)
263 + writel(1 << gpio_field_offset, gpio->base + GPIOSET(gpio_bank));
265 + writel(1 << gpio_field_offset, gpio->base + GPIOCLR(gpio_bank));
268 +/**********************
269 + * extension to configure pullups
271 +int bcm2708_gpio_setpull(struct gpio_chip *gc, unsigned offset,
272 + bcm2708_gpio_pull_t value)
274 + struct bcm2708_gpio *gpio = container_of(gc, struct bcm2708_gpio, gc);
275 + unsigned gpio_bank = offset / 32;
276 + unsigned gpio_field_offset = (offset - 32 * gpio_bank);
278 + if (offset >= BCM2708_NR_GPIOS)
282 + case BCM2708_PULL_UP:
283 + writel(2, gpio->base + GPIOUD(0));
285 + case BCM2708_PULL_DOWN:
286 + writel(1, gpio->base + GPIOUD(0));
288 + case BCM2708_PULL_OFF:
289 + writel(0, gpio->base + GPIOUD(0));
294 + writel(1 << gpio_field_offset, gpio->base + GPIOUDCLK(gpio_bank));
296 + writel(0, gpio->base + GPIOUD(0));
297 + writel(0 << gpio_field_offset, gpio->base + GPIOUDCLK(gpio_bank));
301 +EXPORT_SYMBOL(bcm2708_gpio_setpull);
303 +/*************************************************************************************************************************
307 +#if BCM_GPIO_USE_IRQ
309 +static int bcm2708_gpio_to_irq(struct gpio_chip *chip, unsigned gpio)
311 + return gpio_to_irq(gpio);
314 +static int bcm2708_gpio_irq_set_type(struct irq_data *d, unsigned type)
316 + unsigned irq = d->irq;
317 + struct bcm2708_gpio *gpio = irq_get_chip_data(irq);
318 + unsigned gn = irq_to_gpio(irq);
319 + unsigned gb = gn / 32;
320 + unsigned go = gn % 32;
322 + gpio->rising[gb] &= ~(1 << go);
323 + gpio->falling[gb] &= ~(1 << go);
324 + gpio->high[gb] &= ~(1 << go);
325 + gpio->low[gb] &= ~(1 << go);
327 + if (type & ~(IRQ_TYPE_EDGE_FALLING | IRQ_TYPE_EDGE_RISING | IRQ_TYPE_LEVEL_LOW | IRQ_TYPE_LEVEL_HIGH))
330 + if (type & IRQ_TYPE_EDGE_RISING)
331 + gpio->rising[gb] |= (1 << go);
332 + if (type & IRQ_TYPE_EDGE_FALLING)
333 + gpio->falling[gb] |= (1 << go);
334 + if (type & IRQ_TYPE_LEVEL_HIGH)
335 + gpio->high[gb] |= (1 << go);
336 + if (type & IRQ_TYPE_LEVEL_LOW)
337 + gpio->low[gb] |= (1 << go);
341 +static void bcm2708_gpio_irq_mask(struct irq_data *d)
343 + unsigned irq = d->irq;
344 + struct bcm2708_gpio *gpio = irq_get_chip_data(irq);
345 + unsigned gn = irq_to_gpio(irq);
346 + unsigned gb = gn / 32;
347 + unsigned long rising = readl(gpio->base + GPIOREN(gb));
348 + unsigned long falling = readl(gpio->base + GPIOFEN(gb));
349 + unsigned long high = readl(gpio->base + GPIOHEN(gb));
350 + unsigned long low = readl(gpio->base + GPIOLEN(gb));
354 + writel(rising & ~(1 << gn), gpio->base + GPIOREN(gb));
355 + writel(falling & ~(1 << gn), gpio->base + GPIOFEN(gb));
356 + writel(high & ~(1 << gn), gpio->base + GPIOHEN(gb));
357 + writel(low & ~(1 << gn), gpio->base + GPIOLEN(gb));
360 +static void bcm2708_gpio_irq_unmask(struct irq_data *d)
362 + unsigned irq = d->irq;
363 + struct bcm2708_gpio *gpio = irq_get_chip_data(irq);
364 + unsigned gn = irq_to_gpio(irq);
365 + unsigned gb = gn / 32;
366 + unsigned go = gn % 32;
367 + unsigned long rising = readl(gpio->base + GPIOREN(gb));
368 + unsigned long falling = readl(gpio->base + GPIOFEN(gb));
369 + unsigned long high = readl(gpio->base + GPIOHEN(gb));
370 + unsigned long low = readl(gpio->base + GPIOLEN(gb));
372 + if (gpio->rising[gb] & (1 << go)) {
373 + writel(rising | (1 << go), gpio->base + GPIOREN(gb));
375 + writel(rising & ~(1 << go), gpio->base + GPIOREN(gb));
378 + if (gpio->falling[gb] & (1 << go)) {
379 + writel(falling | (1 << go), gpio->base + GPIOFEN(gb));
381 + writel(falling & ~(1 << go), gpio->base + GPIOFEN(gb));
384 + if (gpio->high[gb] & (1 << go)) {
385 + writel(high | (1 << go), gpio->base + GPIOHEN(gb));
387 + writel(high & ~(1 << go), gpio->base + GPIOHEN(gb));
390 + if (gpio->low[gb] & (1 << go)) {
391 + writel(low | (1 << go), gpio->base + GPIOLEN(gb));
393 + writel(low & ~(1 << go), gpio->base + GPIOLEN(gb));
397 +static struct irq_chip bcm2708_irqchip = {
399 + .irq_enable = bcm2708_gpio_irq_unmask,
400 + .irq_disable = bcm2708_gpio_irq_mask,
401 + .irq_unmask = bcm2708_gpio_irq_unmask,
402 + .irq_mask = bcm2708_gpio_irq_mask,
403 + .irq_set_type = bcm2708_gpio_irq_set_type,
406 +static irqreturn_t bcm2708_gpio_interrupt(int irq, void *dev_id)
408 + unsigned long edsr;
412 + unsigned level_bits;
413 + struct bcm2708_gpio *gpio_data = dev_id;
415 + for (bank = 0; bank < GPIO_BANKS; bank++) {
416 + edsr = readl(__io_address(GPIO_BASE) + GPIOEDS(bank));
417 + level_bits = gpio_data->high[bank] | gpio_data->low[bank];
419 + for_each_set_bit(i, &edsr, 32) {
420 + gpio = i + bank * 32;
421 + /* ack edge triggered IRQs immediately */
422 + if (!(level_bits & (1<<i)))
424 + __io_address(GPIO_BASE) + GPIOEDS(bank));
425 + generic_handle_irq(gpio_to_irq(gpio));
426 + /* ack level triggered IRQ after handling them */
427 + if (level_bits & (1<<i))
429 + __io_address(GPIO_BASE) + GPIOEDS(bank));
432 + return IRQ_HANDLED;
435 +static struct irqaction bcm2708_gpio_irq = {
436 + .name = "BCM2708 GPIO catchall handler",
437 + .flags = IRQF_DISABLED | IRQF_TIMER | IRQF_IRQPOLL,
438 + .handler = bcm2708_gpio_interrupt,
441 +static void bcm2708_gpio_irq_init(struct bcm2708_gpio *ucb)
445 + ucb->gc.to_irq = bcm2708_gpio_to_irq;
447 + for (irq = GPIO_IRQ_START; irq < (GPIO_IRQ_START + GPIO_IRQS); irq++) {
448 + irq_set_chip_data(irq, ucb);
449 + irq_set_chip_and_handler(irq, &bcm2708_irqchip,
450 + handle_simple_irq);
451 + set_irq_flags(irq, IRQF_VALID);
454 + bcm2708_gpio_irq.dev_id = ucb;
455 + setup_irq(IRQ_GPIO3, &bcm2708_gpio_irq);
460 +static void bcm2708_gpio_irq_init(struct bcm2708_gpio *ucb)
464 +#endif /* #if BCM_GPIO_USE_IRQ ***************************************************************************************************************** */
466 +static int bcm2708_gpio_probe(struct platform_device *dev)
468 + struct bcm2708_gpio *ucb;
469 + struct resource *res;
473 + printk(KERN_INFO DRIVER_NAME ": bcm2708_gpio_probe %p\n", dev);
475 + ucb = kzalloc(sizeof(*ucb), GFP_KERNEL);
477 + printk(KERN_ERR DRIVER_NAME ": failed to allocate "
478 + "mailbox memory\n");
483 + res = platform_get_resource(dev, IORESOURCE_MEM, 0);
485 + platform_set_drvdata(dev, ucb);
486 + ucb->base = __io_address(GPIO_BASE);
488 + ucb->gc.label = "bcm2708_gpio";
490 + ucb->gc.ngpio = BCM2708_NR_GPIOS;
491 + ucb->gc.owner = THIS_MODULE;
493 + ucb->gc.direction_input = bcm2708_gpio_dir_in;
494 + ucb->gc.direction_output = bcm2708_gpio_dir_out;
495 + ucb->gc.get = bcm2708_gpio_get;
496 + ucb->gc.set = bcm2708_gpio_set;
497 + ucb->gc.can_sleep = 0;
499 + for (bank = 0; bank < GPIO_BANKS; bank++) {
500 + writel(0, ucb->base + GPIOREN(bank));
501 + writel(0, ucb->base + GPIOFEN(bank));
502 + writel(0, ucb->base + GPIOHEN(bank));
503 + writel(0, ucb->base + GPIOLEN(bank));
504 + writel(0, ucb->base + GPIOAREN(bank));
505 + writel(0, ucb->base + GPIOAFEN(bank));
506 + writel(~0, ucb->base + GPIOEDS(bank));
509 + bcm2708_gpio_irq_init(ucb);
511 + err = gpiochip_add(&ucb->gc);
518 +static int bcm2708_gpio_remove(struct platform_device *dev)
521 + struct bcm2708_gpio *ucb = platform_get_drvdata(dev);
523 + printk(KERN_ERR DRIVER_NAME ": bcm2708_gpio_remove %p\n", dev);
525 + gpiochip_remove(&ucb->gc);
527 + platform_set_drvdata(dev, NULL);
533 +static struct platform_driver bcm2708_gpio_driver = {
534 + .probe = bcm2708_gpio_probe,
535 + .remove = bcm2708_gpio_remove,
537 + .name = "bcm2708_gpio"},
540 +static int __init bcm2708_gpio_init(void)
542 + return platform_driver_register(&bcm2708_gpio_driver);
545 +static void __exit bcm2708_gpio_exit(void)
547 + platform_driver_unregister(&bcm2708_gpio_driver);
550 +module_init(bcm2708_gpio_init);
551 +module_exit(bcm2708_gpio_exit);
553 +MODULE_DESCRIPTION("Broadcom BCM2708 GPIO driver");
554 +MODULE_LICENSE("GPL");
555 diff --git a/arch/arm/mach-bcm2708/include/mach/gpio.h b/arch/arm/mach-bcm2708/include/mach/gpio.h
557 index 0000000..7965a97
559 +++ b/arch/arm/mach-bcm2708/include/mach/gpio.h
562 + * arch/arm/mach-bcm2708/include/mach/gpio.h
564 + * This file is licensed under the terms of the GNU General Public
565 + * License version 2. This program is licensed "as is" without any
566 + * warranty of any kind, whether express or implied.
569 +#ifndef __ASM_ARCH_GPIO_H
570 +#define __ASM_ARCH_GPIO_H
572 +#define BCM2708_NR_GPIOS 54 // number of gpio lines
574 +#define gpio_to_irq(x) ((x) + GPIO_IRQ_START)
575 +#define irq_to_gpio(x) ((x) - GPIO_IRQ_START)
578 diff --git a/include/linux/platform_data/bcm2708.h b/include/linux/platform_data/bcm2708.h
580 index 0000000..fb69624
582 +++ b/include/linux/platform_data/bcm2708.h
585 + * include/linux/platform_data/bcm2708.h
587 + * This program is free software; you can redistribute it and/or modify
588 + * it under the terms of the GNU General Public License version 2 as
589 + * published by the Free Software Foundation.
591 + * (C) 2014 Julian Scheel <julian@jusst.de>
594 +#ifndef __BCM2708_H_
595 +#define __BCM2708_H_
601 +} bcm2708_gpio_pull_t;
603 +extern int bcm2708_gpio_setpull(struct gpio_chip *gc, unsigned offset,
604 + bcm2708_gpio_pull_t value);