Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

gpio: add GPIO driver for the Timberdale FPGA

A GPIO driver for the Timberdale FPGA found on the Intel Atom board
Russellville.

The GPIO driver also has an IRQ-chip to support interrupts on the pins.

Signed-off-by: Richard Röjfors <richard.rojfors@mocean-labs.com>
Cc: David Brownell <david-b@pacbell.net>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

authored by

Richard Röjfors and committed by
Linus Torvalds
35570ac6 4efec627

+386
+6
drivers/gpio/Kconfig
··· 206 206 help 207 207 Say Y here to support Intel Moorestown platform GPIO. 208 208 209 + config GPIO_TIMBERDALE 210 + bool "Support for timberdale GPIO IP" 211 + depends on MFD_TIMBERDALE && GPIOLIB && HAS_IOMEM 212 + ---help--- 213 + Add support for the GPIO IP in the timberdale FPGA. 214 + 209 215 comment "SPI GPIO expanders:" 210 216 211 217 config GPIO_MAX7301
+1
drivers/gpio/Makefile
··· 13 13 obj-$(CONFIG_GPIO_PCA953X) += pca953x.o 14 14 obj-$(CONFIG_GPIO_PCF857X) += pcf857x.o 15 15 obj-$(CONFIG_GPIO_PL061) += pl061.o 16 + obj-$(CONFIG_GPIO_TIMBERDALE) += timbgpio.o 16 17 obj-$(CONFIG_GPIO_TWL4030) += twl4030-gpio.o 17 18 obj-$(CONFIG_GPIO_UCB1400) += ucb1400_gpio.o 18 19 obj-$(CONFIG_GPIO_XILINX) += xilinx_gpio.o
+342
drivers/gpio/timbgpio.c
··· 1 + /* 2 + * timbgpio.c timberdale FPGA GPIO driver 3 + * Copyright (c) 2009 Intel Corporation 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 + * You should have received a copy of the GNU General Public License 15 + * along with this program; if not, write to the Free Software 16 + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. 17 + */ 18 + 19 + /* Supports: 20 + * Timberdale FPGA GPIO 21 + */ 22 + 23 + #include <linux/module.h> 24 + #include <linux/gpio.h> 25 + #include <linux/platform_device.h> 26 + #include <linux/io.h> 27 + #include <linux/timb_gpio.h> 28 + #include <linux/interrupt.h> 29 + 30 + #define DRIVER_NAME "timb-gpio" 31 + 32 + #define TGPIOVAL 0x00 33 + #define TGPIODIR 0x04 34 + #define TGPIO_IER 0x08 35 + #define TGPIO_ISR 0x0c 36 + #define TGPIO_IPR 0x10 37 + #define TGPIO_ICR 0x14 38 + #define TGPIO_FLR 0x18 39 + #define TGPIO_LVR 0x1c 40 + 41 + struct timbgpio { 42 + void __iomem *membase; 43 + spinlock_t lock; /* mutual exclusion */ 44 + struct gpio_chip gpio; 45 + int irq_base; 46 + }; 47 + 48 + static int timbgpio_update_bit(struct gpio_chip *gpio, unsigned index, 49 + unsigned offset, bool enabled) 50 + { 51 + struct timbgpio *tgpio = container_of(gpio, struct timbgpio, gpio); 52 + u32 reg; 53 + 54 + spin_lock(&tgpio->lock); 55 + reg = ioread32(tgpio->membase + offset); 56 + 57 + if (enabled) 58 + reg |= (1 << index); 59 + else 60 + reg &= ~(1 << index); 61 + 62 + iowrite32(reg, tgpio->membase + offset); 63 + spin_unlock(&tgpio->lock); 64 + 65 + return 0; 66 + } 67 + 68 + static int timbgpio_gpio_direction_input(struct gpio_chip *gpio, unsigned nr) 69 + { 70 + return timbgpio_update_bit(gpio, nr, TGPIODIR, true); 71 + } 72 + 73 + static int timbgpio_gpio_get(struct gpio_chip *gpio, unsigned nr) 74 + { 75 + struct timbgpio *tgpio = container_of(gpio, struct timbgpio, gpio); 76 + u32 value; 77 + 78 + value = ioread32(tgpio->membase + TGPIOVAL); 79 + return (value & (1 << nr)) ? 1 : 0; 80 + } 81 + 82 + static int timbgpio_gpio_direction_output(struct gpio_chip *gpio, 83 + unsigned nr, int val) 84 + { 85 + return timbgpio_update_bit(gpio, nr, TGPIODIR, false); 86 + } 87 + 88 + static void timbgpio_gpio_set(struct gpio_chip *gpio, 89 + unsigned nr, int val) 90 + { 91 + timbgpio_update_bit(gpio, nr, TGPIOVAL, val != 0); 92 + } 93 + 94 + static int timbgpio_to_irq(struct gpio_chip *gpio, unsigned offset) 95 + { 96 + struct timbgpio *tgpio = container_of(gpio, struct timbgpio, gpio); 97 + 98 + if (tgpio->irq_base <= 0) 99 + return -EINVAL; 100 + 101 + return tgpio->irq_base + offset; 102 + } 103 + 104 + /* 105 + * GPIO IRQ 106 + */ 107 + static void timbgpio_irq_disable(unsigned irq) 108 + { 109 + struct timbgpio *tgpio = get_irq_chip_data(irq); 110 + int offset = irq - tgpio->irq_base; 111 + 112 + timbgpio_update_bit(&tgpio->gpio, offset, TGPIO_IER, 0); 113 + } 114 + 115 + static void timbgpio_irq_enable(unsigned irq) 116 + { 117 + struct timbgpio *tgpio = get_irq_chip_data(irq); 118 + int offset = irq - tgpio->irq_base; 119 + 120 + timbgpio_update_bit(&tgpio->gpio, offset, TGPIO_IER, 1); 121 + } 122 + 123 + static int timbgpio_irq_type(unsigned irq, unsigned trigger) 124 + { 125 + struct timbgpio *tgpio = get_irq_chip_data(irq); 126 + int offset = irq - tgpio->irq_base; 127 + unsigned long flags; 128 + u32 lvr, flr; 129 + 130 + if (offset < 0 || offset > tgpio->gpio.ngpio) 131 + return -EINVAL; 132 + 133 + spin_lock_irqsave(&tgpio->lock, flags); 134 + 135 + lvr = ioread32(tgpio->membase + TGPIO_LVR); 136 + flr = ioread32(tgpio->membase + TGPIO_FLR); 137 + 138 + if (trigger & (IRQ_TYPE_LEVEL_HIGH | IRQ_TYPE_LEVEL_LOW)) { 139 + flr &= ~(1 << offset); 140 + if (trigger & IRQ_TYPE_LEVEL_HIGH) 141 + lvr |= 1 << offset; 142 + else 143 + lvr &= ~(1 << offset); 144 + } 145 + 146 + if ((trigger & IRQ_TYPE_EDGE_BOTH) == IRQ_TYPE_EDGE_BOTH) 147 + return -EINVAL; 148 + else { 149 + flr |= 1 << offset; 150 + /* opposite compared to the datasheet, but it mirrors the 151 + * reality 152 + */ 153 + if (trigger & IRQ_TYPE_EDGE_FALLING) 154 + lvr |= 1 << offset; 155 + else 156 + lvr &= ~(1 << offset); 157 + } 158 + 159 + iowrite32(lvr, tgpio->membase + TGPIO_LVR); 160 + iowrite32(flr, tgpio->membase + TGPIO_FLR); 161 + iowrite32(1 << offset, tgpio->membase + TGPIO_ICR); 162 + spin_unlock_irqrestore(&tgpio->lock, flags); 163 + 164 + return 0; 165 + } 166 + 167 + static void timbgpio_irq(unsigned int irq, struct irq_desc *desc) 168 + { 169 + struct timbgpio *tgpio = get_irq_data(irq); 170 + unsigned long ipr; 171 + int offset; 172 + 173 + desc->chip->ack(irq); 174 + ipr = ioread32(tgpio->membase + TGPIO_IPR); 175 + iowrite32(ipr, tgpio->membase + TGPIO_ICR); 176 + 177 + for_each_bit(offset, &ipr, tgpio->gpio.ngpio) 178 + generic_handle_irq(timbgpio_to_irq(&tgpio->gpio, offset)); 179 + } 180 + 181 + static struct irq_chip timbgpio_irqchip = { 182 + .name = "GPIO", 183 + .enable = timbgpio_irq_enable, 184 + .disable = timbgpio_irq_disable, 185 + .set_type = timbgpio_irq_type, 186 + }; 187 + 188 + static int __devinit timbgpio_probe(struct platform_device *pdev) 189 + { 190 + int err, i; 191 + struct gpio_chip *gc; 192 + struct timbgpio *tgpio; 193 + struct resource *iomem; 194 + struct timbgpio_platform_data *pdata = pdev->dev.platform_data; 195 + int irq = platform_get_irq(pdev, 0); 196 + 197 + if (!pdata || pdata->nr_pins > 32) { 198 + err = -EINVAL; 199 + goto err_mem; 200 + } 201 + 202 + iomem = platform_get_resource(pdev, IORESOURCE_MEM, 0); 203 + if (!iomem) { 204 + err = -EINVAL; 205 + goto err_mem; 206 + } 207 + 208 + tgpio = kzalloc(sizeof(*tgpio), GFP_KERNEL); 209 + if (!tgpio) { 210 + err = -EINVAL; 211 + goto err_mem; 212 + } 213 + tgpio->irq_base = pdata->irq_base; 214 + 215 + spin_lock_init(&tgpio->lock); 216 + 217 + if (!request_mem_region(iomem->start, resource_size(iomem), 218 + DRIVER_NAME)) { 219 + err = -EBUSY; 220 + goto err_request; 221 + } 222 + 223 + tgpio->membase = ioremap(iomem->start, resource_size(iomem)); 224 + if (!tgpio->membase) { 225 + err = -ENOMEM; 226 + goto err_ioremap; 227 + } 228 + 229 + gc = &tgpio->gpio; 230 + 231 + gc->label = dev_name(&pdev->dev); 232 + gc->owner = THIS_MODULE; 233 + gc->dev = &pdev->dev; 234 + gc->direction_input = timbgpio_gpio_direction_input; 235 + gc->get = timbgpio_gpio_get; 236 + gc->direction_output = timbgpio_gpio_direction_output; 237 + gc->set = timbgpio_gpio_set; 238 + gc->to_irq = (irq >= 0 && tgpio->irq_base > 0) ? timbgpio_to_irq : NULL; 239 + gc->dbg_show = NULL; 240 + gc->base = pdata->gpio_base; 241 + gc->ngpio = pdata->nr_pins; 242 + gc->can_sleep = 0; 243 + 244 + err = gpiochip_add(gc); 245 + if (err) 246 + goto err_chipadd; 247 + 248 + platform_set_drvdata(pdev, tgpio); 249 + 250 + /* make sure to disable interrupts */ 251 + iowrite32(0x0, tgpio->membase + TGPIO_IER); 252 + 253 + if (irq < 0 || tgpio->irq_base <= 0) 254 + return 0; 255 + 256 + for (i = 0; i < pdata->nr_pins; i++) { 257 + set_irq_chip_and_handler_name(tgpio->irq_base + i, 258 + &timbgpio_irqchip, handle_simple_irq, "mux"); 259 + set_irq_chip_data(tgpio->irq_base + i, tgpio); 260 + #ifdef CONFIG_ARM 261 + set_irq_flags(tgpio->irq_base + i, IRQF_VALID | IRQF_PROBE); 262 + #endif 263 + } 264 + 265 + set_irq_data(irq, tgpio); 266 + set_irq_chained_handler(irq, timbgpio_irq); 267 + 268 + return 0; 269 + 270 + err_chipadd: 271 + iounmap(tgpio->membase); 272 + err_ioremap: 273 + release_mem_region(iomem->start, resource_size(iomem)); 274 + err_request: 275 + kfree(tgpio); 276 + err_mem: 277 + printk(KERN_ERR DRIVER_NAME": Failed to register GPIOs: %d\n", err); 278 + 279 + return err; 280 + } 281 + 282 + static int __devexit timbgpio_remove(struct platform_device *pdev) 283 + { 284 + int err; 285 + struct timbgpio_platform_data *pdata = pdev->dev.platform_data; 286 + struct timbgpio *tgpio = platform_get_drvdata(pdev); 287 + struct resource *iomem = platform_get_resource(pdev, IORESOURCE_MEM, 0); 288 + int irq = platform_get_irq(pdev, 0); 289 + 290 + if (irq >= 0 && tgpio->irq_base > 0) { 291 + int i; 292 + for (i = 0; i < pdata->nr_pins; i++) { 293 + set_irq_chip(tgpio->irq_base + i, NULL); 294 + set_irq_chip_data(tgpio->irq_base + i, NULL); 295 + } 296 + 297 + set_irq_handler(irq, NULL); 298 + set_irq_data(irq, NULL); 299 + } 300 + 301 + err = gpiochip_remove(&tgpio->gpio); 302 + if (err) 303 + printk(KERN_ERR DRIVER_NAME": failed to remove gpio_chip\n"); 304 + 305 + iounmap(tgpio->membase); 306 + release_mem_region(iomem->start, resource_size(iomem)); 307 + kfree(tgpio); 308 + 309 + platform_set_drvdata(pdev, NULL); 310 + 311 + return 0; 312 + } 313 + 314 + static struct platform_driver timbgpio_platform_driver = { 315 + .driver = { 316 + .name = DRIVER_NAME, 317 + .owner = THIS_MODULE, 318 + }, 319 + .probe = timbgpio_probe, 320 + .remove = timbgpio_remove, 321 + }; 322 + 323 + /*--------------------------------------------------------------------------*/ 324 + 325 + static int __init timbgpio_init(void) 326 + { 327 + return platform_driver_register(&timbgpio_platform_driver); 328 + } 329 + 330 + static void __exit timbgpio_exit(void) 331 + { 332 + platform_driver_unregister(&timbgpio_platform_driver); 333 + } 334 + 335 + module_init(timbgpio_init); 336 + module_exit(timbgpio_exit); 337 + 338 + MODULE_DESCRIPTION("Timberdale GPIO driver"); 339 + MODULE_LICENSE("GPL v2"); 340 + MODULE_AUTHOR("Mocean Laboratories"); 341 + MODULE_ALIAS("platform:"DRIVER_NAME); 342 +
+37
include/linux/timb_gpio.h
··· 1 + /* 2 + * timb_gpio.h timberdale FPGA GPIO driver, platform data definition 3 + * Copyright (c) 2009 Intel Corporation 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 + * You should have received a copy of the GNU General Public License 15 + * along with this program; if not, write to the Free Software 16 + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. 17 + */ 18 + 19 + #ifndef _LINUX_TIMB_GPIO_H 20 + #define _LINUX_TIMB_GPIO_H 21 + 22 + /** 23 + * struct timbgpio_platform_data - Platform data of the Timberdale GPIO driver 24 + * @gpio_base The number of the first GPIO pin, set to -1 for 25 + * dynamic number allocation. 26 + * @nr_pins Number of pins that is supported by the hardware (1-32) 27 + * @irq_base If IRQ is supported by the hardware, this is the base 28 + * number of IRQ:s. One IRQ per pin will be used. Set to 29 + * -1 if IRQ:s is not supported. 30 + */ 31 + struct timbgpio_platform_data { 32 + int gpio_base; 33 + int nr_pins; 34 + int irq_base; 35 + }; 36 + 37 + #endif