1164633Ssam/* 2164633Ssam * Support for the GPIO/IRQ expander chips present on several HTC phones. 3164633Ssam * These are implemented in CPLD chips present on the board. 4206358Srpaulo * 5164633Ssam * Copyright (c) 2007 Kevin O'Connor <kevin@koconnor.net> 6164633Ssam * Copyright (c) 2007 Philipp Zabel <philipp.zabel@gmail.com> 7164633Ssam * 8164633Ssam * This file may be distributed under the terms of the GNU GPL license. 9164633Ssam */ 10164633Ssam 11164633Ssam#include <linux/kernel.h> 12164633Ssam#include <linux/errno.h> 13164633Ssam#include <linux/interrupt.h> 14164633Ssam#include <linux/irq.h> 15164633Ssam#include <linux/io.h> 16164633Ssam#include <linux/spinlock.h> 17164633Ssam#include <linux/platform_data/gpio-htc-egpio.h> 18164633Ssam#include <linux/platform_device.h> 19164633Ssam#include <linux/slab.h> 20164633Ssam#include <linux/init.h> 21164633Ssam#include <linux/gpio/driver.h> 22164633Ssam 23164633Ssamstruct egpio_chip { 24164633Ssam int reg_start; 25164633Ssam int cached_values; 26164633Ssam unsigned long is_out; 27164633Ssam struct device *dev; 28164633Ssam struct gpio_chip chip; 29164633Ssam}; 30164633Ssam 31164633Ssamstruct egpio_info { 32178354Ssam spinlock_t lock; 33178354Ssam 34164633Ssam /* iomem info */ 35164633Ssam void __iomem *base_addr; 36295126Sglebius int bus_shift; /* byte shift */ 37164633Ssam int reg_shift; /* bit shift */ 38296925Sadrian int reg_mask; 39164633Ssam 40164633Ssam /* irq info */ 41164633Ssam int ack_register; 42164633Ssam int ack_write; 43257176Sglebius u16 irqs_enabled; 44164633Ssam uint irq_start; 45257241Sglebius int nirqs; 46164633Ssam uint chained_irq; 47164633Ssam 48164633Ssam /* egpio info */ 49164633Ssam struct egpio_chip *chip; 50164633Ssam int nchips; 51164633Ssam}; 52164633Ssam 53252727Sadrianstatic inline void egpio_writew(u16 value, struct egpio_info *ei, int reg) 54164633Ssam{ 55206358Srpaulo writew(value, ei->base_addr + (reg << ei->bus_shift)); 56164633Ssam} 57164633Ssam 58164633Ssamstatic inline u16 egpio_readw(struct egpio_info *ei, int reg) 59164633Ssam{ 60164633Ssam return readw(ei->base_addr + (reg << ei->bus_shift)); 61164633Ssam} 62164633Ssam 63164633Ssam/* 64206358Srpaulo * IRQs 65206358Srpaulo */ 66206358Srpaulo 67206358Srpaulostatic inline void ack_irqs(struct egpio_info *ei) 68206358Srpaulo{ 69206358Srpaulo egpio_writew(ei->ack_write, ei, ei->ack_register); 70206358Srpaulo pr_debug("EGPIO ack - write %x to base+%x\n", 71206358Srpaulo ei->ack_write, ei->ack_register << ei->bus_shift); 72206358Srpaulo} 73206358Srpaulo 74206358Srpaulostatic void egpio_ack(struct irq_data *data) 75206358Srpaulo{ 76206358Srpaulo} 77206358Srpaulo 78206358Srpaulo/* There does not appear to be a way to proactively mask interrupts 79296925Sadrian * on the egpio chip itself. So, we simply ignore interrupts that 80178354Ssam * aren't desired. */ 81178354Ssamstatic void egpio_mask(struct irq_data *data) 82178354Ssam{ 83178354Ssam struct egpio_info *ei = irq_data_get_irq_chip_data(data); 84206358Srpaulo ei->irqs_enabled &= ~(1 << (data->irq - ei->irq_start)); 85206358Srpaulo pr_debug("EGPIO mask %d %04x\n", data->irq, ei->irqs_enabled); 86206358Srpaulo} 87206358Srpaulo 88206358Srpaulostatic void egpio_unmask(struct irq_data *data) 89206358Srpaulo{ 90206358Srpaulo struct egpio_info *ei = irq_data_get_irq_chip_data(data); 91206358Srpaulo ei->irqs_enabled |= 1 << (data->irq - ei->irq_start); 92206358Srpaulo pr_debug("EGPIO unmask %d %04x\n", data->irq, ei->irqs_enabled); 93206358Srpaulo} 94206358Srpaulo 95206358Srpaulostatic struct irq_chip egpio_muxed_chip = { 96296925Sadrian .name = "htc-egpio", 97206358Srpaulo .irq_ack = egpio_ack, 98206358Srpaulo .irq_mask = egpio_mask, 99206358Srpaulo .irq_unmask = egpio_unmask, 100206358Srpaulo}; 101206358Srpaulo 102206358Srpaulostatic void egpio_handler(struct irq_desc *desc) 103178354Ssam{ 104206358Srpaulo struct egpio_info *ei = irq_desc_get_handler_data(desc); 105178354Ssam int irqpin; 106178354Ssam 107343035Savos /* Read current pins. */ 108343035Savos unsigned long readval = egpio_readw(ei, ei->ack_register); 109343035Savos pr_debug("IRQ reg: %x\n", (unsigned int)readval); 110178354Ssam /* Ack/unmask interrupts. */ 111178354Ssam ack_irqs(ei); 112178354Ssam /* Process all set pins. */ 113178354Ssam readval &= ei->irqs_enabled; 114178354Ssam for_each_set_bit(irqpin, &readval, ei->nirqs) { 115178354Ssam /* Run irq handler */ 116206358Srpaulo pr_debug("got IRQ %d\n", irqpin); 117206358Srpaulo generic_handle_irq(ei->irq_start + irqpin); 118164633Ssam } 119206358Srpaulo} 120178354Ssam 121206358Srpaulostatic inline int egpio_pos(struct egpio_info *ei, int bit) 122206358Srpaulo{ 123321724Savos return bit >> ei->reg_shift; 124283538Sadrian} 125283538Sadrian 126206419Srpaulostatic inline int egpio_bit(struct egpio_info *ei, int bit) 127206419Srpaulo{ 128206419Srpaulo return 1 << (bit & ((1 << ei->reg_shift)-1)); 129206419Srpaulo} 130206358Srpaulo 131206358Srpaulo/* 132206358Srpaulo * Input pins 133206358Srpaulo */ 134164633Ssam 135164633Ssamstatic int egpio_get(struct gpio_chip *chip, unsigned offset) 136206358Srpaulo{ 137206358Srpaulo struct egpio_chip *egpio; 138178354Ssam struct egpio_info *ei; 139283538Sadrian unsigned bit; 140321724Savos int reg; 141321724Savos int value; 142178354Ssam 143178354Ssam pr_debug("egpio_get_value(%d)\n", chip->base + offset); 144257412Sadrian 145257412Sadrian egpio = gpiochip_get_data(chip); 146257412Sadrian ei = dev_get_drvdata(egpio->dev); 147257412Sadrian bit = egpio_bit(ei, offset); 148257412Sadrian reg = egpio->reg_start + egpio_pos(ei, offset); 149257412Sadrian 150252727Sadrian if (test_bit(offset, &egpio->is_out)) { 151252727Sadrian return !!(egpio->cached_values & (1 << offset)); 152252727Sadrian } else { 153252727Sadrian value = egpio_readw(ei, reg); 154252727Sadrian pr_debug("readw(%p + %x) = %x\n", 155252727Sadrian ei->base_addr, reg << ei->bus_shift, value); 156252727Sadrian return !!(value & bit); 157252727Sadrian } 158257412Sadrian} 159257412Sadrian 160252727Sadrianstatic int egpio_direction_input(struct gpio_chip *chip, unsigned offset) 161252727Sadrian{ 162252727Sadrian struct egpio_chip *egpio; 163206358Srpaulo 164206358Srpaulo egpio = gpiochip_get_data(chip); 165164633Ssam return test_bit(offset, &egpio->is_out) ? -EINVAL : 0; 166252727Sadrian} 167206358Srpaulo 168206358Srpaulo 169206358Srpaulo/* 170252727Sadrian * Output pins 171178354Ssam */ 172343035Savos 173343035Savosstatic void egpio_set(struct gpio_chip *chip, unsigned offset, int value) 174343035Savos{ 175343035Savos unsigned long flag; 176343035Savos struct egpio_chip *egpio; 177343035Savos struct egpio_info *ei; 178207323Srpaulo int pos; 179283538Sadrian int reg; 180283538Sadrian int shift; 181207323Srpaulo 182207323Srpaulo pr_debug("egpio_set(%s, %d(%d), %d)\n", 183207323Srpaulo chip->label, offset, offset+chip->base, value); 184207323Srpaulo 185207323Srpaulo egpio = gpiochip_get_data(chip); 186207323Srpaulo ei = dev_get_drvdata(egpio->dev); 187207323Srpaulo pos = egpio_pos(ei, offset); 188178354Ssam reg = egpio->reg_start + pos; 189164633Ssam shift = pos << ei->reg_shift; 190164633Ssam 191164633Ssam pr_debug("egpio %s: reg %d = 0x%04x\n", value ? "set" : "clear", 192164633Ssam reg, (egpio->cached_values >> shift) & ei->reg_mask); 193178354Ssam 194252727Sadrian spin_lock_irqsave(&ei->lock, flag); 195252727Sadrian if (value) 196252727Sadrian egpio->cached_values |= (1 << offset); 197252727Sadrian else 198252727Sadrian egpio->cached_values &= ~(1 << offset); 199252727Sadrian egpio_writew((egpio->cached_values >> shift) & ei->reg_mask, ei, reg); 200252727Sadrian spin_unlock_irqrestore(&ei->lock, flag); 201252727Sadrian} 202252727Sadrian 203252727Sadrianstatic int egpio_direction_output(struct gpio_chip *chip, 204252727Sadrian unsigned offset, int value) 205252727Sadrian{ 206252727Sadrian struct egpio_chip *egpio; 207252727Sadrian 208252727Sadrian egpio = gpiochip_get_data(chip); 209252727Sadrian if (test_bit(offset, &egpio->is_out)) { 210252727Sadrian egpio_set(chip, offset, value); 211252727Sadrian return 0; 212252727Sadrian } else { 213252727Sadrian return -EINVAL; 214270206Sadrian } 215252727Sadrian} 216252727Sadrian 217252727Sadrianstatic int egpio_get_direction(struct gpio_chip *chip, unsigned offset) 218270206Sadrian{ 219257881Sadrian struct egpio_chip *egpio; 220270206Sadrian 221257881Sadrian egpio = gpiochip_get_data(chip); 222257881Sadrian 223252727Sadrian if (test_bit(offset, &egpio->is_out)) 224252727Sadrian return GPIO_LINE_DIRECTION_OUT; 225257881Sadrian 226252727Sadrian return GPIO_LINE_DIRECTION_IN; 227252727Sadrian} 228252727Sadrian 229252727Sadrianstatic void egpio_write_cache(struct egpio_info *ei) 230252727Sadrian{ 231252727Sadrian int i; 232252727Sadrian struct egpio_chip *egpio; 233178354Ssam int shift; 234178354Ssam 235302307Sadrian for (i = 0; i < ei->nchips; i++) { 236302307Sadrian egpio = &(ei->chip[i]); 237178354Ssam if (!egpio->is_out) 238302307Sadrian continue; 239252727Sadrian 240302307Sadrian for (shift = 0; shift < egpio->chip.ngpio; 241302307Sadrian shift += (1<<ei->reg_shift)) { 242164633Ssam 243164633Ssam int reg = egpio->reg_start + egpio_pos(ei, shift); 244206358Srpaulo 245206358Srpaulo if (!((egpio->is_out >> shift) & ei->reg_mask)) 246206358Srpaulo continue; 247283538Sadrian 248206358Srpaulo pr_debug("EGPIO: setting %x to %x, was %x\n", reg, 249206358Srpaulo (egpio->cached_values >> shift) & ei->reg_mask, 250178354Ssam egpio_readw(ei, reg)); 251178354Ssam 252178354Ssam egpio_writew((egpio->cached_values >> shift) 253164633Ssam & ei->reg_mask, ei, reg); 254178354Ssam } 255252727Sadrian } 256164633Ssam} 257178354Ssam 258178354Ssam 259252727Sadrian/* 260252727Sadrian * Setup 261252727Sadrian */ 262252727Sadrian 263252727Sadrianstatic int __init egpio_probe(struct platform_device *pdev) 264252727Sadrian{ 265252727Sadrian struct htc_egpio_platform_data *pdata = dev_get_platdata(&pdev->dev); 266252727Sadrian struct resource *res; 267302307Sadrian struct egpio_info *ei; 268302307Sadrian struct gpio_chip *chip; 269252727Sadrian unsigned int irq, irq_end; 270252727Sadrian int i; 271252727Sadrian 272252727Sadrian /* Initialize ei data structure. */ 273252727Sadrian ei = devm_kzalloc(&pdev->dev, sizeof(*ei), GFP_KERNEL); 274252727Sadrian if (!ei) 275252736Sadrian return -ENOMEM; 276252736Sadrian 277252736Sadrian spin_lock_init(&ei->lock); 278252736Sadrian 279252736Sadrian /* Find chained irq */ 280252736Sadrian res = platform_get_resource(pdev, IORESOURCE_IRQ, 0); 281252736Sadrian if (res) 282252736Sadrian ei->chained_irq = res->start; 283178354Ssam 284164633Ssam /* Map egpio chip into virtual address space. */ 285164633Ssam ei->base_addr = devm_platform_ioremap_resource(pdev, 0); 286252727Sadrian if (IS_ERR(ei->base_addr)) 287164633Ssam return PTR_ERR(ei->base_addr); 288164633Ssam 289178354Ssam if ((pdata->bus_width != 16) && (pdata->bus_width != 32)) 290302307Sadrian return -EINVAL; 291302307Sadrian 292178354Ssam ei->bus_shift = fls(pdata->bus_width - 1) - 3; 293178354Ssam pr_debug("bus_shift = %d\n", ei->bus_shift); 294252727Sadrian 295164633Ssam if ((pdata->reg_width != 8) && (pdata->reg_width != 16)) 296164633Ssam return -EINVAL; 297164633Ssam 298164633Ssam ei->reg_shift = fls(pdata->reg_width - 1); 299164633Ssam pr_debug("reg_shift = %d\n", ei->reg_shift); 300164633Ssam 301178354Ssam ei->reg_mask = (1 << pdata->reg_width) - 1; 302164633Ssam 303164633Ssam platform_set_drvdata(pdev, ei); 304164633Ssam 305164633Ssam ei->nchips = pdata->num_chips; 306164633Ssam ei->chip = devm_kcalloc(&pdev->dev, 307164633Ssam ei->nchips, sizeof(struct egpio_chip), 308164633Ssam GFP_KERNEL); 309164633Ssam if (!ei->chip) 310164633Ssam return -ENOMEM; 311164633Ssam 312178354Ssam for (i = 0; i < ei->nchips; i++) { 313302307Sadrian ei->chip[i].reg_start = pdata->chip[i].reg_start; 314302307Sadrian ei->chip[i].cached_values = pdata->chip[i].initial_values; 315178354Ssam ei->chip[i].is_out = pdata->chip[i].direction; 316178354Ssam ei->chip[i].dev = &(pdev->dev); 317252727Sadrian chip = &(ei->chip[i].chip); 318164633Ssam chip->label = devm_kasprintf(&pdev->dev, GFP_KERNEL, 319164633Ssam "htc-egpio-%d", 320164633Ssam i); 321164633Ssam if (!chip->label) 322164633Ssam return -ENOMEM; 323178354Ssam 324178354Ssam chip->parent = &pdev->dev; 325178354Ssam chip->owner = THIS_MODULE; 326178354Ssam chip->get = egpio_get; 327178354Ssam chip->set = egpio_set; 328164633Ssam chip->direction_input = egpio_direction_input; 329164633Ssam chip->direction_output = egpio_direction_output; 330164633Ssam chip->get_direction = egpio_get_direction; 331178354Ssam chip->base = pdata->chip[i].gpio_base; 332178354Ssam chip->ngpio = pdata->chip[i].num_gpios; 333178354Ssam 334164633Ssam gpiochip_add_data(chip, &ei->chip[i]); 335206358Srpaulo } 336206358Srpaulo 337178354Ssam /* Set initial pin values */ 338206358Srpaulo egpio_write_cache(ei); 339343035Savos 340252727Sadrian ei->irq_start = pdata->irq_base; 341178354Ssam ei->nirqs = pdata->num_irqs; 342178354Ssam ei->ack_register = pdata->ack_register; 343343035Savos 344343035Savos if (ei->chained_irq) { 345343035Savos /* Setup irq handlers */ 346343035Savos ei->ack_write = 0xFFFF; 347343035Savos if (pdata->invert_acks) 348343035Savos ei->ack_write = 0; 349343035Savos irq_end = ei->irq_start + ei->nirqs; 350343035Savos for (irq = ei->irq_start; irq < irq_end; irq++) { 351343035Savos irq_set_chip_and_handler(irq, &egpio_muxed_chip, 352252727Sadrian handle_simple_irq); 353252727Sadrian irq_set_chip_data(irq, ei); 354252727Sadrian irq_clear_status_flags(irq, IRQ_NOREQUEST | IRQ_NOPROBE); 355252727Sadrian } 356252727Sadrian irq_set_irq_type(ei->chained_irq, IRQ_TYPE_EDGE_RISING); 357252727Sadrian irq_set_chained_handler_and_data(ei->chained_irq, 358252727Sadrian egpio_handler, ei); 359252727Sadrian ack_irqs(ei); 360178354Ssam 361178354Ssam device_init_wakeup(&pdev->dev, 1); 362178354Ssam } 363178354Ssam 364252727Sadrian return 0; 365252727Sadrian} 366252727Sadrian 367252727Sadrian#ifdef CONFIG_PM 368252727Sadrianstatic int egpio_suspend(struct platform_device *pdev, pm_message_t state) 369252727Sadrian{ 370178354Ssam struct egpio_info *ei = platform_get_drvdata(pdev); 371178354Ssam 372178354Ssam if (ei->chained_irq && device_may_wakeup(&pdev->dev)) 373178354Ssam enable_irq_wake(ei->chained_irq); 374178354Ssam return 0; 375178354Ssam} 376178354Ssam 377178354Ssamstatic int egpio_resume(struct platform_device *pdev) 378206358Srpaulo{ 379206358Srpaulo struct egpio_info *ei = platform_get_drvdata(pdev); 380206358Srpaulo 381206358Srpaulo if (ei->chained_irq && device_may_wakeup(&pdev->dev)) 382206358Srpaulo disable_irq_wake(ei->chained_irq); 383206358Srpaulo 384206358Srpaulo /* Update registers from the cache, in case 385206358Srpaulo the CPLD was powered off during suspend */ 386206358Srpaulo egpio_write_cache(ei); 387206358Srpaulo return 0; 388206358Srpaulo} 389206358Srpaulo#else 390206358Srpaulo#define egpio_suspend NULL 391343035Savos#define egpio_resume NULL 392343035Savos#endif 393343035Savos 394206358Srpaulo 395206358Srpaulostatic struct platform_driver egpio_driver = { 396206358Srpaulo .driver = { 397206358Srpaulo .name = "htc-egpio", 398206358Srpaulo .suppress_bind_attrs = true, 399206358Srpaulo }, 400206358Srpaulo .suspend = egpio_suspend, 401206358Srpaulo .resume = egpio_resume, 402206358Srpaulo}; 403206358Srpaulo 404206358Srpaulostatic int __init egpio_init(void) 405206358Srpaulo{ 406206358Srpaulo return platform_driver_probe(&egpio_driver, egpio_probe); 407206358Srpaulo} 408206358Srpaulo/* start early for dependencies */ 409206358Srpaulosubsys_initcall(egpio_init); 410206358Srpaulo