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

[ARM] 4947/1: htc-egpio, a driver for GPIO/IRQ expanders with fixed input/output pins

implemented in CPLD chips on several HTC devices.

The original driver was written by Kevin O'Connor, I have adapted it to
use gpiolib and made the bus/register widths configurable.

Signed-off-by: Philipp Zabel <philipp.zabel@gmail.com>
Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>

authored by

Philipp Zabel and committed by
Russell King
a1635b8f e6816f34

+507
+8
drivers/mfd/Kconfig
··· 22 22 This driver supports the ASIC3 multifunction chip found on many 23 23 PDAs (mainly iPAQ and HTC based ones) 24 24 25 + config HTC_EGPIO 26 + bool "HTC EGPIO support" 27 + depends on GENERIC_HARDIRQS && HAVE_GPIO_LIB 28 + help 29 + This driver supports the CPLD egpio chip present on 30 + several HTC phones. It provides basic support for input 31 + pins, output pins, and irqs. 32 + 25 33 endmenu 26 34 27 35 menu "Multimedia Capabilities Port drivers"
+2
drivers/mfd/Makefile
··· 5 5 obj-$(CONFIG_MFD_SM501) += sm501.o 6 6 obj-$(CONFIG_MFD_ASIC3) += asic3.o 7 7 8 + obj-$(CONFIG_HTC_EGPIO) += htc-egpio.o 9 + 8 10 obj-$(CONFIG_MCP) += mcp-core.o 9 11 obj-$(CONFIG_MCP_SA11X0) += mcp-sa11x0.o 10 12 obj-$(CONFIG_MCP_UCB1200) += ucb1x00-core.o
+440
drivers/mfd/htc-egpio.c
··· 1 + /* 2 + * Support for the GPIO/IRQ expander chips present on several HTC phones. 3 + * These are implemented in CPLD chips present on the board. 4 + * 5 + * Copyright (c) 2007 Kevin O'Connor <kevin@koconnor.net> 6 + * Copyright (c) 2007 Philipp Zabel <philipp.zabel@gmail.com> 7 + * 8 + * This file may be distributed under the terms of the GNU GPL license. 9 + */ 10 + 11 + #include <linux/kernel.h> 12 + #include <linux/errno.h> 13 + #include <linux/interrupt.h> 14 + #include <linux/irq.h> 15 + #include <linux/io.h> 16 + #include <linux/spinlock.h> 17 + #include <linux/platform_device.h> 18 + #include <linux/module.h> 19 + #include <linux/mfd/htc-egpio.h> 20 + 21 + struct egpio_chip { 22 + int reg_start; 23 + int cached_values; 24 + unsigned long is_out; 25 + struct device *dev; 26 + struct gpio_chip chip; 27 + }; 28 + 29 + struct egpio_info { 30 + spinlock_t lock; 31 + 32 + /* iomem info */ 33 + void __iomem *base_addr; 34 + int bus_shift; /* byte shift */ 35 + int reg_shift; /* bit shift */ 36 + int reg_mask; 37 + 38 + /* irq info */ 39 + int ack_register; 40 + int ack_write; 41 + u16 irqs_enabled; 42 + uint irq_start; 43 + int nirqs; 44 + uint chained_irq; 45 + 46 + /* egpio info */ 47 + struct egpio_chip *chip; 48 + int nchips; 49 + }; 50 + 51 + static inline void egpio_writew(u16 value, struct egpio_info *ei, int reg) 52 + { 53 + writew(value, ei->base_addr + (reg << ei->bus_shift)); 54 + } 55 + 56 + static inline u16 egpio_readw(struct egpio_info *ei, int reg) 57 + { 58 + return readw(ei->base_addr + (reg << ei->bus_shift)); 59 + } 60 + 61 + /* 62 + * IRQs 63 + */ 64 + 65 + static inline void ack_irqs(struct egpio_info *ei) 66 + { 67 + egpio_writew(ei->ack_write, ei, ei->ack_register); 68 + pr_debug("EGPIO ack - write %x to base+%x\n", 69 + ei->ack_write, ei->ack_register << ei->bus_shift); 70 + } 71 + 72 + static void egpio_ack(unsigned int irq) 73 + { 74 + } 75 + 76 + /* There does not appear to be a way to proactively mask interrupts 77 + * on the egpio chip itself. So, we simply ignore interrupts that 78 + * aren't desired. */ 79 + static void egpio_mask(unsigned int irq) 80 + { 81 + struct egpio_info *ei = get_irq_chip_data(irq); 82 + ei->irqs_enabled &= ~(1 << (irq - ei->irq_start)); 83 + pr_debug("EGPIO mask %d %04x\n", irq, ei->irqs_enabled); 84 + } 85 + static void egpio_unmask(unsigned int irq) 86 + { 87 + struct egpio_info *ei = get_irq_chip_data(irq); 88 + ei->irqs_enabled |= 1 << (irq - ei->irq_start); 89 + pr_debug("EGPIO unmask %d %04x\n", irq, ei->irqs_enabled); 90 + } 91 + 92 + static struct irq_chip egpio_muxed_chip = { 93 + .name = "htc-egpio", 94 + .ack = egpio_ack, 95 + .mask = egpio_mask, 96 + .unmask = egpio_unmask, 97 + }; 98 + 99 + static void egpio_handler(unsigned int irq, struct irq_desc *desc) 100 + { 101 + struct egpio_info *ei = get_irq_data(irq); 102 + int irqpin; 103 + 104 + /* Read current pins. */ 105 + unsigned long readval = egpio_readw(ei, ei->ack_register); 106 + pr_debug("IRQ reg: %x\n", (unsigned int)readval); 107 + /* Ack/unmask interrupts. */ 108 + ack_irqs(ei); 109 + /* Process all set pins. */ 110 + readval &= ei->irqs_enabled; 111 + for_each_bit(irqpin, &readval, ei->nirqs) { 112 + /* Run irq handler */ 113 + pr_debug("got IRQ %d\n", irqpin); 114 + irq = ei->irq_start + irqpin; 115 + desc = &irq_desc[irq]; 116 + desc->handle_irq(irq, desc); 117 + } 118 + } 119 + 120 + int htc_egpio_get_wakeup_irq(struct device *dev) 121 + { 122 + struct egpio_info *ei = dev_get_drvdata(dev); 123 + 124 + /* Read current pins. */ 125 + u16 readval = egpio_readw(ei, ei->ack_register); 126 + /* Ack/unmask interrupts. */ 127 + ack_irqs(ei); 128 + /* Return first set pin. */ 129 + readval &= ei->irqs_enabled; 130 + return ei->irq_start + ffs(readval) - 1; 131 + } 132 + EXPORT_SYMBOL(htc_egpio_get_wakeup_irq); 133 + 134 + static inline int egpio_pos(struct egpio_info *ei, int bit) 135 + { 136 + return bit >> ei->reg_shift; 137 + } 138 + 139 + static inline int egpio_bit(struct egpio_info *ei, int bit) 140 + { 141 + return 1 << (bit & ((1 << ei->reg_shift)-1)); 142 + } 143 + 144 + /* 145 + * Input pins 146 + */ 147 + 148 + static int egpio_get(struct gpio_chip *chip, unsigned offset) 149 + { 150 + struct egpio_chip *egpio; 151 + struct egpio_info *ei; 152 + unsigned bit; 153 + int reg; 154 + int value; 155 + 156 + pr_debug("egpio_get_value(%d)\n", chip->base + offset); 157 + 158 + egpio = container_of(chip, struct egpio_chip, chip); 159 + ei = dev_get_drvdata(egpio->dev); 160 + bit = egpio_bit(ei, offset); 161 + reg = egpio->reg_start + egpio_pos(ei, offset); 162 + 163 + value = egpio_readw(ei, reg); 164 + pr_debug("readw(%p + %x) = %x\n", 165 + ei->base_addr, reg << ei->bus_shift, value); 166 + return value & bit; 167 + } 168 + 169 + static int egpio_direction_input(struct gpio_chip *chip, unsigned offset) 170 + { 171 + struct egpio_chip *egpio; 172 + 173 + egpio = container_of(chip, struct egpio_chip, chip); 174 + return test_bit(offset, &egpio->is_out) ? -EINVAL : 0; 175 + } 176 + 177 + 178 + /* 179 + * Output pins 180 + */ 181 + 182 + static void egpio_set(struct gpio_chip *chip, unsigned offset, int value) 183 + { 184 + unsigned long flag; 185 + struct egpio_chip *egpio; 186 + struct egpio_info *ei; 187 + unsigned bit; 188 + int pos; 189 + int reg; 190 + int shift; 191 + 192 + pr_debug("egpio_set(%s, %d(%d), %d)\n", 193 + chip->label, offset, offset+chip->base, value); 194 + 195 + egpio = container_of(chip, struct egpio_chip, chip); 196 + ei = dev_get_drvdata(egpio->dev); 197 + bit = egpio_bit(ei, offset); 198 + pos = egpio_pos(ei, offset); 199 + reg = egpio->reg_start + pos; 200 + shift = pos << ei->reg_shift; 201 + 202 + pr_debug("egpio %s: reg %d = 0x%04x\n", value ? "set" : "clear", 203 + reg, (egpio->cached_values >> shift) & ei->reg_mask); 204 + 205 + spin_lock_irqsave(&ei->lock, flag); 206 + if (value) 207 + egpio->cached_values |= (1 << offset); 208 + else 209 + egpio->cached_values &= ~(1 << offset); 210 + egpio_writew((egpio->cached_values >> shift) & ei->reg_mask, ei, reg); 211 + spin_unlock_irqrestore(&ei->lock, flag); 212 + } 213 + 214 + static int egpio_direction_output(struct gpio_chip *chip, 215 + unsigned offset, int value) 216 + { 217 + struct egpio_chip *egpio; 218 + 219 + egpio = container_of(chip, struct egpio_chip, chip); 220 + if (test_bit(offset, &egpio->is_out)) { 221 + egpio_set(chip, offset, value); 222 + return 0; 223 + } else { 224 + return -EINVAL; 225 + } 226 + } 227 + 228 + static void egpio_write_cache(struct egpio_info *ei) 229 + { 230 + int i; 231 + struct egpio_chip *egpio; 232 + int shift; 233 + 234 + for (i = 0; i < ei->nchips; i++) { 235 + egpio = &(ei->chip[i]); 236 + if (!egpio->is_out) 237 + continue; 238 + 239 + for (shift = 0; shift < egpio->chip.ngpio; 240 + shift += (1<<ei->reg_shift)) { 241 + 242 + int reg = egpio->reg_start + egpio_pos(ei, shift); 243 + 244 + if (!((egpio->is_out >> shift) & ei->reg_mask)) 245 + continue; 246 + 247 + pr_debug("EGPIO: setting %x to %x, was %x\n", reg, 248 + (egpio->cached_values >> shift) & ei->reg_mask, 249 + egpio_readw(ei, reg)); 250 + 251 + egpio_writew((egpio->cached_values >> shift) 252 + & ei->reg_mask, ei, reg); 253 + } 254 + } 255 + } 256 + 257 + 258 + /* 259 + * Setup 260 + */ 261 + 262 + static int __init egpio_probe(struct platform_device *pdev) 263 + { 264 + struct htc_egpio_platform_data *pdata = pdev->dev.platform_data; 265 + struct resource *res; 266 + struct egpio_info *ei; 267 + struct gpio_chip *chip; 268 + unsigned int irq, irq_end; 269 + int i; 270 + int ret; 271 + 272 + /* Initialize ei data structure. */ 273 + ei = kzalloc(sizeof(*ei), GFP_KERNEL); 274 + if (!ei) 275 + return -ENOMEM; 276 + 277 + spin_lock_init(&ei->lock); 278 + 279 + /* Find chained irq */ 280 + ret = -EINVAL; 281 + res = platform_get_resource(pdev, IORESOURCE_IRQ, 0); 282 + if (res) 283 + ei->chained_irq = res->start; 284 + 285 + /* Map egpio chip into virtual address space. */ 286 + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); 287 + if (!res) 288 + goto fail; 289 + ei->base_addr = ioremap_nocache(res->start, res->end - res->start); 290 + if (!ei->base_addr) 291 + goto fail; 292 + pr_debug("EGPIO phys=%08x virt=%p\n", res->start, ei->base_addr); 293 + 294 + if ((pdata->bus_width != 16) && (pdata->bus_width != 32)) 295 + goto fail; 296 + ei->bus_shift = fls(pdata->bus_width - 1) - 3; 297 + pr_debug("bus_shift = %d\n", ei->bus_shift); 298 + 299 + if ((pdata->reg_width != 8) && (pdata->reg_width != 16)) 300 + goto fail; 301 + ei->reg_shift = fls(pdata->reg_width - 1); 302 + pr_debug("reg_shift = %d\n", ei->reg_shift); 303 + 304 + ei->reg_mask = (1 << pdata->reg_width) - 1; 305 + 306 + platform_set_drvdata(pdev, ei); 307 + 308 + ei->nchips = pdata->num_chips; 309 + ei->chip = kzalloc(sizeof(struct egpio_chip) * ei->nchips, GFP_KERNEL); 310 + if (!ei) { 311 + ret = -ENOMEM; 312 + goto fail; 313 + } 314 + for (i = 0; i < ei->nchips; i++) { 315 + ei->chip[i].reg_start = pdata->chip[i].reg_start; 316 + ei->chip[i].cached_values = pdata->chip[i].initial_values; 317 + ei->chip[i].is_out = pdata->chip[i].direction; 318 + ei->chip[i].dev = &(pdev->dev); 319 + chip = &(ei->chip[i].chip); 320 + chip->label = "htc-egpio"; 321 + chip->get = egpio_get; 322 + chip->set = egpio_set; 323 + chip->direction_input = egpio_direction_input; 324 + chip->direction_output = egpio_direction_output; 325 + chip->base = pdata->chip[i].gpio_base; 326 + chip->ngpio = pdata->chip[i].num_gpios; 327 + 328 + gpiochip_add(chip); 329 + } 330 + 331 + /* Set initial pin values */ 332 + egpio_write_cache(ei); 333 + 334 + ei->irq_start = pdata->irq_base; 335 + ei->nirqs = pdata->num_irqs; 336 + ei->ack_register = pdata->ack_register; 337 + 338 + if (ei->chained_irq) { 339 + /* Setup irq handlers */ 340 + ei->ack_write = 0xFFFF; 341 + if (pdata->invert_acks) 342 + ei->ack_write = 0; 343 + irq_end = ei->irq_start + ei->nirqs; 344 + for (irq = ei->irq_start; irq < irq_end; irq++) { 345 + set_irq_chip(irq, &egpio_muxed_chip); 346 + set_irq_chip_data(irq, ei); 347 + set_irq_handler(irq, handle_simple_irq); 348 + set_irq_flags(irq, IRQF_VALID | IRQF_PROBE); 349 + } 350 + set_irq_type(ei->chained_irq, IRQ_TYPE_EDGE_RISING); 351 + set_irq_data(ei->chained_irq, ei); 352 + set_irq_chained_handler(ei->chained_irq, egpio_handler); 353 + ack_irqs(ei); 354 + 355 + device_init_wakeup(&pdev->dev, 1); 356 + } 357 + 358 + return 0; 359 + 360 + fail: 361 + printk(KERN_ERR "EGPIO failed to setup\n"); 362 + kfree(ei); 363 + return ret; 364 + } 365 + 366 + static int __exit egpio_remove(struct platform_device *pdev) 367 + { 368 + struct egpio_info *ei = platform_get_drvdata(pdev); 369 + unsigned int irq, irq_end; 370 + 371 + if (ei->chained_irq) { 372 + irq_end = ei->irq_start + ei->nirqs; 373 + for (irq = ei->irq_start; irq < irq_end; irq++) { 374 + set_irq_chip(irq, NULL); 375 + set_irq_handler(irq, NULL); 376 + set_irq_flags(irq, 0); 377 + } 378 + set_irq_chained_handler(ei->chained_irq, NULL); 379 + device_init_wakeup(&pdev->dev, 0); 380 + } 381 + iounmap(ei->base_addr); 382 + kfree(ei->chip); 383 + kfree(ei); 384 + 385 + return 0; 386 + } 387 + 388 + #ifdef CONFIG_PM 389 + static int egpio_suspend(struct platform_device *pdev, pm_message_t state) 390 + { 391 + struct egpio_info *ei = platform_get_drvdata(pdev); 392 + 393 + if (ei->chained_irq && device_may_wakeup(&pdev->dev)) 394 + enable_irq_wake(ei->chained_irq); 395 + return 0; 396 + } 397 + 398 + static int egpio_resume(struct platform_device *pdev) 399 + { 400 + struct egpio_info *ei = platform_get_drvdata(pdev); 401 + 402 + if (ei->chained_irq && device_may_wakeup(&pdev->dev)) 403 + disable_irq_wake(ei->chained_irq); 404 + 405 + /* Update registers from the cache, in case 406 + the CPLD was powered off during suspend */ 407 + egpio_write_cache(ei); 408 + return 0; 409 + } 410 + #else 411 + #define egpio_suspend NULL 412 + #define egpio_resume NULL 413 + #endif 414 + 415 + 416 + static struct platform_driver egpio_driver = { 417 + .driver = { 418 + .name = "htc-egpio", 419 + }, 420 + .remove = __exit_p(egpio_remove), 421 + .suspend = egpio_suspend, 422 + .resume = egpio_resume, 423 + }; 424 + 425 + static int __init egpio_init(void) 426 + { 427 + return platform_driver_probe(&egpio_driver, egpio_probe); 428 + } 429 + 430 + static void __exit egpio_exit(void) 431 + { 432 + platform_driver_unregister(&egpio_driver); 433 + } 434 + 435 + /* start early for dependencies */ 436 + subsys_initcall(egpio_init); 437 + module_exit(egpio_exit) 438 + 439 + MODULE_LICENSE("GPL"); 440 + MODULE_AUTHOR("Kevin O'Connor <kevin@koconnor.net>");
+57
include/linux/mfd/htc-egpio.h
··· 1 + /* 2 + * HTC simple EGPIO irq and gpio extender 3 + */ 4 + 5 + #ifndef __HTC_EGPIO_H__ 6 + #define __HTC_EGPIO_H__ 7 + 8 + #include <linux/gpio.h> 9 + 10 + /* Descriptive values for all-in or all-out htc_egpio_chip descriptors. */ 11 + #define HTC_EGPIO_OUTPUT (~0) 12 + #define HTC_EGPIO_INPUT 0 13 + 14 + /** 15 + * struct htc_egpio_chip - descriptor to create gpio_chip for register range 16 + * @reg_start: index of first register 17 + * @gpio_base: gpio number of first pin in this register range 18 + * @num_gpios: number of gpios in this register range, max BITS_PER_LONG 19 + * (number of registers = DIV_ROUND_UP(num_gpios, reg_width)) 20 + * @direction: bitfield, '0' = input, '1' = output, 21 + */ 22 + struct htc_egpio_chip { 23 + int reg_start; 24 + int gpio_base; 25 + int num_gpios; 26 + unsigned long direction; 27 + unsigned long initial_values; 28 + }; 29 + 30 + /** 31 + * struct htc_egpio_platform_data - description provided by the arch 32 + * @irq_base: beginning of available IRQs (eg, IRQ_BOARD_START) 33 + * @num_irqs: number of irqs 34 + * @reg_width: number of bits per register, either 8 or 16 bit 35 + * @bus_width: alignment of the registers, either 16 or 32 bit 36 + * @invert_acks: set if chip requires writing '0' to ack an irq, instead of '1' 37 + * @ack_register: location of the irq/ack register 38 + * @chip: pointer to array of htc_egpio_chip descriptors 39 + * @num_chips: number of egpio chip descriptors 40 + */ 41 + struct htc_egpio_platform_data { 42 + int bus_width; 43 + int reg_width; 44 + 45 + int irq_base; 46 + int num_irqs; 47 + int invert_acks; 48 + int ack_register; 49 + 50 + struct htc_egpio_chip *chip; 51 + int num_chips; 52 + }; 53 + 54 + /* Determine the wakeup irq, to be called during early resume */ 55 + extern int htc_egpio_get_wakeup_irq(struct device *dev); 56 + 57 + #endif