gpio-pl061.c revision b2888095feb3c651cba5904b0227622e82777b34
1/* 2 * Copyright (C) 2008, 2009 Provigent Ltd. 3 * 4 * This program is free software; you can redistribute it and/or modify 5 * it under the terms of the GNU General Public License version 2 as 6 * published by the Free Software Foundation. 7 * 8 * Driver for the ARM PrimeCell(tm) General Purpose Input/Output (PL061) 9 * 10 * Data sheet: ARM DDI 0190B, September 2000 11 */ 12#include <linux/spinlock.h> 13#include <linux/errno.h> 14#include <linux/module.h> 15#include <linux/list.h> 16#include <linux/io.h> 17#include <linux/ioport.h> 18#include <linux/irq.h> 19#include <linux/bitops.h> 20#include <linux/workqueue.h> 21#include <linux/gpio.h> 22#include <linux/device.h> 23#include <linux/amba/bus.h> 24#include <linux/amba/pl061.h> 25#include <linux/slab.h> 26 27#define GPIODIR 0x400 28#define GPIOIS 0x404 29#define GPIOIBE 0x408 30#define GPIOIEV 0x40C 31#define GPIOIE 0x410 32#define GPIORIS 0x414 33#define GPIOMIS 0x418 34#define GPIOIC 0x41C 35 36#define PL061_GPIO_NR 8 37 38struct pl061_gpio { 39 /* We use a list of pl061_gpio structs for each trigger IRQ in the main 40 * interrupts controller of the system. We need this to support systems 41 * in which more that one PL061s are connected to the same IRQ. The ISR 42 * interates through this list to find the source of the interrupt. 43 */ 44 struct list_head list; 45 46 /* Each of the two spinlocks protects a different set of hardware 47 * regiters and data structurs. This decouples the code of the IRQ from 48 * the GPIO code. This also makes the case of a GPIO routine call from 49 * the IRQ code simpler. 50 */ 51 spinlock_t lock; /* GPIO registers */ 52 spinlock_t irq_lock; /* IRQ registers */ 53 54 void __iomem *base; 55 unsigned irq_base; 56 struct gpio_chip gc; 57}; 58 59static int pl061_direction_input(struct gpio_chip *gc, unsigned offset) 60{ 61 struct pl061_gpio *chip = container_of(gc, struct pl061_gpio, gc); 62 unsigned long flags; 63 unsigned char gpiodir; 64 65 if (offset >= gc->ngpio) 66 return -EINVAL; 67 68 spin_lock_irqsave(&chip->lock, flags); 69 gpiodir = readb(chip->base + GPIODIR); 70 gpiodir &= ~(1 << offset); 71 writeb(gpiodir, chip->base + GPIODIR); 72 spin_unlock_irqrestore(&chip->lock, flags); 73 74 return 0; 75} 76 77static int pl061_direction_output(struct gpio_chip *gc, unsigned offset, 78 int value) 79{ 80 struct pl061_gpio *chip = container_of(gc, struct pl061_gpio, gc); 81 unsigned long flags; 82 unsigned char gpiodir; 83 84 if (offset >= gc->ngpio) 85 return -EINVAL; 86 87 spin_lock_irqsave(&chip->lock, flags); 88 writeb(!!value << offset, chip->base + (1 << (offset + 2))); 89 gpiodir = readb(chip->base + GPIODIR); 90 gpiodir |= 1 << offset; 91 writeb(gpiodir, chip->base + GPIODIR); 92 93 /* 94 * gpio value is set again, because pl061 doesn't allow to set value of 95 * a gpio pin before configuring it in OUT mode. 96 */ 97 writeb(!!value << offset, chip->base + (1 << (offset + 2))); 98 spin_unlock_irqrestore(&chip->lock, flags); 99 100 return 0; 101} 102 103static int pl061_get_value(struct gpio_chip *gc, unsigned offset) 104{ 105 struct pl061_gpio *chip = container_of(gc, struct pl061_gpio, gc); 106 107 return !!readb(chip->base + (1 << (offset + 2))); 108} 109 110static void pl061_set_value(struct gpio_chip *gc, unsigned offset, int value) 111{ 112 struct pl061_gpio *chip = container_of(gc, struct pl061_gpio, gc); 113 114 writeb(!!value << offset, chip->base + (1 << (offset + 2))); 115} 116 117static int pl061_to_irq(struct gpio_chip *gc, unsigned offset) 118{ 119 struct pl061_gpio *chip = container_of(gc, struct pl061_gpio, gc); 120 121 if (chip->irq_base == NO_IRQ) 122 return -EINVAL; 123 124 return chip->irq_base + offset; 125} 126 127/* 128 * PL061 GPIO IRQ 129 */ 130static void pl061_irq_disable(struct irq_data *d) 131{ 132 struct pl061_gpio *chip = irq_data_get_irq_chip_data(d); 133 int offset = d->irq - chip->irq_base; 134 unsigned long flags; 135 u8 gpioie; 136 137 spin_lock_irqsave(&chip->irq_lock, flags); 138 gpioie = readb(chip->base + GPIOIE); 139 gpioie &= ~(1 << offset); 140 writeb(gpioie, chip->base + GPIOIE); 141 spin_unlock_irqrestore(&chip->irq_lock, flags); 142} 143 144static void pl061_irq_enable(struct irq_data *d) 145{ 146 struct pl061_gpio *chip = irq_data_get_irq_chip_data(d); 147 int offset = d->irq - chip->irq_base; 148 unsigned long flags; 149 u8 gpioie; 150 151 spin_lock_irqsave(&chip->irq_lock, flags); 152 gpioie = readb(chip->base + GPIOIE); 153 gpioie |= 1 << offset; 154 writeb(gpioie, chip->base + GPIOIE); 155 spin_unlock_irqrestore(&chip->irq_lock, flags); 156} 157 158static int pl061_irq_type(struct irq_data *d, unsigned trigger) 159{ 160 struct pl061_gpio *chip = irq_data_get_irq_chip_data(d); 161 int offset = d->irq - chip->irq_base; 162 unsigned long flags; 163 u8 gpiois, gpioibe, gpioiev; 164 165 if (offset < 0 || offset >= PL061_GPIO_NR) 166 return -EINVAL; 167 168 spin_lock_irqsave(&chip->irq_lock, flags); 169 170 gpioiev = readb(chip->base + GPIOIEV); 171 172 gpiois = readb(chip->base + GPIOIS); 173 if (trigger & (IRQ_TYPE_LEVEL_HIGH | IRQ_TYPE_LEVEL_LOW)) { 174 gpiois |= 1 << offset; 175 if (trigger & IRQ_TYPE_LEVEL_HIGH) 176 gpioiev |= 1 << offset; 177 else 178 gpioiev &= ~(1 << offset); 179 } else 180 gpiois &= ~(1 << offset); 181 writeb(gpiois, chip->base + GPIOIS); 182 183 gpioibe = readb(chip->base + GPIOIBE); 184 if ((trigger & IRQ_TYPE_EDGE_BOTH) == IRQ_TYPE_EDGE_BOTH) 185 gpioibe |= 1 << offset; 186 else { 187 gpioibe &= ~(1 << offset); 188 if (trigger & IRQ_TYPE_EDGE_RISING) 189 gpioiev |= 1 << offset; 190 else if (trigger & IRQ_TYPE_EDGE_FALLING) 191 gpioiev &= ~(1 << offset); 192 } 193 writeb(gpioibe, chip->base + GPIOIBE); 194 195 writeb(gpioiev, chip->base + GPIOIEV); 196 197 spin_unlock_irqrestore(&chip->irq_lock, flags); 198 199 return 0; 200} 201 202static struct irq_chip pl061_irqchip = { 203 .name = "GPIO", 204 .irq_enable = pl061_irq_enable, 205 .irq_disable = pl061_irq_disable, 206 .irq_set_type = pl061_irq_type, 207}; 208 209static void pl061_irq_handler(unsigned irq, struct irq_desc *desc) 210{ 211 struct list_head *chip_list = irq_get_handler_data(irq); 212 struct list_head *ptr; 213 struct pl061_gpio *chip; 214 215 desc->irq_data.chip->irq_ack(&desc->irq_data); 216 list_for_each(ptr, chip_list) { 217 unsigned long pending; 218 int offset; 219 220 chip = list_entry(ptr, struct pl061_gpio, list); 221 pending = readb(chip->base + GPIOMIS); 222 writeb(pending, chip->base + GPIOIC); 223 224 if (pending == 0) 225 continue; 226 227 for_each_set_bit(offset, &pending, PL061_GPIO_NR) 228 generic_handle_irq(pl061_to_irq(&chip->gc, offset)); 229 } 230 desc->irq_data.chip->irq_unmask(&desc->irq_data); 231} 232 233static int pl061_probe(struct amba_device *dev, const struct amba_id *id) 234{ 235 struct pl061_platform_data *pdata; 236 struct pl061_gpio *chip; 237 struct list_head *chip_list; 238 int ret, irq, i; 239 static DECLARE_BITMAP(init_irq, NR_IRQS); 240 241 chip = kzalloc(sizeof(*chip), GFP_KERNEL); 242 if (chip == NULL) 243 return -ENOMEM; 244 245 pdata = dev->dev.platform_data; 246 if (pdata) { 247 chip->gc.base = pdata->gpio_base; 248 chip->irq_base = pdata->irq_base; 249 } else if (dev->dev.of_node) { 250 chip->gc.base = -1; 251 chip->irq_base = NO_IRQ; 252 } else { 253 ret = -ENODEV; 254 goto free_mem; 255 } 256 257 if (!request_mem_region(dev->res.start, 258 resource_size(&dev->res), "pl061")) { 259 ret = -EBUSY; 260 goto free_mem; 261 } 262 263 chip->base = ioremap(dev->res.start, resource_size(&dev->res)); 264 if (chip->base == NULL) { 265 ret = -ENOMEM; 266 goto release_region; 267 } 268 269 spin_lock_init(&chip->lock); 270 spin_lock_init(&chip->irq_lock); 271 INIT_LIST_HEAD(&chip->list); 272 273 chip->gc.direction_input = pl061_direction_input; 274 chip->gc.direction_output = pl061_direction_output; 275 chip->gc.get = pl061_get_value; 276 chip->gc.set = pl061_set_value; 277 chip->gc.to_irq = pl061_to_irq; 278 chip->gc.ngpio = PL061_GPIO_NR; 279 chip->gc.label = dev_name(&dev->dev); 280 chip->gc.dev = &dev->dev; 281 chip->gc.owner = THIS_MODULE; 282 283 ret = gpiochip_add(&chip->gc); 284 if (ret) 285 goto iounmap; 286 287 /* 288 * irq_chip support 289 */ 290 291 if (chip->irq_base == NO_IRQ) 292 return 0; 293 294 writeb(0, chip->base + GPIOIE); /* disable irqs */ 295 irq = dev->irq[0]; 296 if (irq < 0) { 297 ret = -ENODEV; 298 goto iounmap; 299 } 300 irq_set_chained_handler(irq, pl061_irq_handler); 301 if (!test_and_set_bit(irq, init_irq)) { /* list initialized? */ 302 chip_list = kmalloc(sizeof(*chip_list), GFP_KERNEL); 303 if (chip_list == NULL) { 304 clear_bit(irq, init_irq); 305 ret = -ENOMEM; 306 goto iounmap; 307 } 308 INIT_LIST_HEAD(chip_list); 309 irq_set_handler_data(irq, chip_list); 310 } else 311 chip_list = irq_get_handler_data(irq); 312 list_add(&chip->list, chip_list); 313 314 for (i = 0; i < PL061_GPIO_NR; i++) { 315 if (pdata) { 316 if (pdata->directions & (1 << i)) 317 pl061_direction_output(&chip->gc, i, 318 pdata->values & (1 << i)); 319 else 320 pl061_direction_input(&chip->gc, i); 321 } 322 323 irq_set_chip_and_handler(i + chip->irq_base, &pl061_irqchip, 324 handle_simple_irq); 325 set_irq_flags(i+chip->irq_base, IRQF_VALID); 326 irq_set_chip_data(i + chip->irq_base, chip); 327 } 328 329 return 0; 330 331iounmap: 332 iounmap(chip->base); 333release_region: 334 release_mem_region(dev->res.start, resource_size(&dev->res)); 335free_mem: 336 kfree(chip); 337 338 return ret; 339} 340 341static struct amba_id pl061_ids[] = { 342 { 343 .id = 0x00041061, 344 .mask = 0x000fffff, 345 }, 346 { 0, 0 }, 347}; 348 349static struct amba_driver pl061_gpio_driver = { 350 .drv = { 351 .name = "pl061_gpio", 352 }, 353 .id_table = pl061_ids, 354 .probe = pl061_probe, 355}; 356 357static int __init pl061_gpio_init(void) 358{ 359 return amba_driver_register(&pl061_gpio_driver); 360} 361subsys_initcall(pl061_gpio_init); 362 363MODULE_AUTHOR("Baruch Siach <baruch@tkos.co.il>"); 364MODULE_DESCRIPTION("PL061 GPIO driver"); 365MODULE_LICENSE("GPL"); 366