1*9c26df9bSWilliam Breathitt Gray /* 2*9c26df9bSWilliam Breathitt Gray * GPIO driver for the WinSystems WS16C48 3*9c26df9bSWilliam Breathitt Gray * Copyright (C) 2016 William Breathitt Gray 4*9c26df9bSWilliam Breathitt Gray * 5*9c26df9bSWilliam Breathitt Gray * This program is free software; you can redistribute it and/or modify 6*9c26df9bSWilliam Breathitt Gray * it under the terms of the GNU General Public License, version 2, as 7*9c26df9bSWilliam Breathitt Gray * published by the Free Software Foundation. 8*9c26df9bSWilliam Breathitt Gray * 9*9c26df9bSWilliam Breathitt Gray * This program is distributed in the hope that it will be useful, but 10*9c26df9bSWilliam Breathitt Gray * WITHOUT ANY WARRANTY; without even the implied warranty of 11*9c26df9bSWilliam Breathitt Gray * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 12*9c26df9bSWilliam Breathitt Gray * General Public License for more details. 13*9c26df9bSWilliam Breathitt Gray */ 14*9c26df9bSWilliam Breathitt Gray #include <linux/bitops.h> 15*9c26df9bSWilliam Breathitt Gray #include <linux/device.h> 16*9c26df9bSWilliam Breathitt Gray #include <linux/errno.h> 17*9c26df9bSWilliam Breathitt Gray #include <linux/gpio/driver.h> 18*9c26df9bSWilliam Breathitt Gray #include <linux/io.h> 19*9c26df9bSWilliam Breathitt Gray #include <linux/ioport.h> 20*9c26df9bSWilliam Breathitt Gray #include <linux/interrupt.h> 21*9c26df9bSWilliam Breathitt Gray #include <linux/irqdesc.h> 22*9c26df9bSWilliam Breathitt Gray #include <linux/kernel.h> 23*9c26df9bSWilliam Breathitt Gray #include <linux/module.h> 24*9c26df9bSWilliam Breathitt Gray #include <linux/moduleparam.h> 25*9c26df9bSWilliam Breathitt Gray #include <linux/platform_device.h> 26*9c26df9bSWilliam Breathitt Gray #include <linux/spinlock.h> 27*9c26df9bSWilliam Breathitt Gray 28*9c26df9bSWilliam Breathitt Gray static unsigned ws16c48_base; 29*9c26df9bSWilliam Breathitt Gray module_param(ws16c48_base, uint, 0); 30*9c26df9bSWilliam Breathitt Gray MODULE_PARM_DESC(ws16c48_base, "WinSystems WS16C48 base address"); 31*9c26df9bSWilliam Breathitt Gray static unsigned ws16c48_irq; 32*9c26df9bSWilliam Breathitt Gray module_param(ws16c48_irq, uint, 0); 33*9c26df9bSWilliam Breathitt Gray MODULE_PARM_DESC(ws16c48_irq, "WinSystems WS16C48 interrupt line number"); 34*9c26df9bSWilliam Breathitt Gray 35*9c26df9bSWilliam Breathitt Gray /** 36*9c26df9bSWilliam Breathitt Gray * struct ws16c48_gpio - GPIO device private data structure 37*9c26df9bSWilliam Breathitt Gray * @chip: instance of the gpio_chip 38*9c26df9bSWilliam Breathitt Gray * @io_state: bit I/O state (whether bit is set to input or output) 39*9c26df9bSWilliam Breathitt Gray * @out_state: output bits state 40*9c26df9bSWilliam Breathitt Gray * @lock: synchronization lock to prevent I/O race conditions 41*9c26df9bSWilliam Breathitt Gray * @irq_mask: I/O bits affected by interrupts 42*9c26df9bSWilliam Breathitt Gray * @flow_mask: IRQ flow type mask for the respective I/O bits 43*9c26df9bSWilliam Breathitt Gray * @base: base port address of the GPIO device 44*9c26df9bSWilliam Breathitt Gray * @extent: extent of port address region of the GPIO device 45*9c26df9bSWilliam Breathitt Gray * @irq: Interrupt line number 46*9c26df9bSWilliam Breathitt Gray */ 47*9c26df9bSWilliam Breathitt Gray struct ws16c48_gpio { 48*9c26df9bSWilliam Breathitt Gray struct gpio_chip chip; 49*9c26df9bSWilliam Breathitt Gray unsigned char io_state[6]; 50*9c26df9bSWilliam Breathitt Gray unsigned char out_state[6]; 51*9c26df9bSWilliam Breathitt Gray spinlock_t lock; 52*9c26df9bSWilliam Breathitt Gray unsigned long irq_mask; 53*9c26df9bSWilliam Breathitt Gray unsigned long flow_mask; 54*9c26df9bSWilliam Breathitt Gray unsigned base; 55*9c26df9bSWilliam Breathitt Gray unsigned extent; 56*9c26df9bSWilliam Breathitt Gray unsigned irq; 57*9c26df9bSWilliam Breathitt Gray }; 58*9c26df9bSWilliam Breathitt Gray 59*9c26df9bSWilliam Breathitt Gray static int ws16c48_gpio_get_direction(struct gpio_chip *chip, unsigned offset) 60*9c26df9bSWilliam Breathitt Gray { 61*9c26df9bSWilliam Breathitt Gray struct ws16c48_gpio *const ws16c48gpio = gpiochip_get_data(chip); 62*9c26df9bSWilliam Breathitt Gray const unsigned port = offset / 8; 63*9c26df9bSWilliam Breathitt Gray const unsigned mask = BIT(offset % 8); 64*9c26df9bSWilliam Breathitt Gray 65*9c26df9bSWilliam Breathitt Gray return !!(ws16c48gpio->io_state[port] & mask); 66*9c26df9bSWilliam Breathitt Gray } 67*9c26df9bSWilliam Breathitt Gray 68*9c26df9bSWilliam Breathitt Gray static int ws16c48_gpio_direction_input(struct gpio_chip *chip, unsigned offset) 69*9c26df9bSWilliam Breathitt Gray { 70*9c26df9bSWilliam Breathitt Gray struct ws16c48_gpio *const ws16c48gpio = gpiochip_get_data(chip); 71*9c26df9bSWilliam Breathitt Gray const unsigned port = offset / 8; 72*9c26df9bSWilliam Breathitt Gray const unsigned mask = BIT(offset % 8); 73*9c26df9bSWilliam Breathitt Gray unsigned long flags; 74*9c26df9bSWilliam Breathitt Gray 75*9c26df9bSWilliam Breathitt Gray spin_lock_irqsave(&ws16c48gpio->lock, flags); 76*9c26df9bSWilliam Breathitt Gray 77*9c26df9bSWilliam Breathitt Gray ws16c48gpio->io_state[port] |= mask; 78*9c26df9bSWilliam Breathitt Gray ws16c48gpio->out_state[port] &= ~mask; 79*9c26df9bSWilliam Breathitt Gray outb(ws16c48gpio->out_state[port], ws16c48gpio->base + port); 80*9c26df9bSWilliam Breathitt Gray 81*9c26df9bSWilliam Breathitt Gray spin_unlock_irqrestore(&ws16c48gpio->lock, flags); 82*9c26df9bSWilliam Breathitt Gray 83*9c26df9bSWilliam Breathitt Gray return 0; 84*9c26df9bSWilliam Breathitt Gray } 85*9c26df9bSWilliam Breathitt Gray 86*9c26df9bSWilliam Breathitt Gray static int ws16c48_gpio_direction_output(struct gpio_chip *chip, 87*9c26df9bSWilliam Breathitt Gray unsigned offset, int value) 88*9c26df9bSWilliam Breathitt Gray { 89*9c26df9bSWilliam Breathitt Gray struct ws16c48_gpio *const ws16c48gpio = gpiochip_get_data(chip); 90*9c26df9bSWilliam Breathitt Gray const unsigned port = offset / 8; 91*9c26df9bSWilliam Breathitt Gray const unsigned mask = BIT(offset % 8); 92*9c26df9bSWilliam Breathitt Gray unsigned long flags; 93*9c26df9bSWilliam Breathitt Gray 94*9c26df9bSWilliam Breathitt Gray spin_lock_irqsave(&ws16c48gpio->lock, flags); 95*9c26df9bSWilliam Breathitt Gray 96*9c26df9bSWilliam Breathitt Gray ws16c48gpio->io_state[port] &= ~mask; 97*9c26df9bSWilliam Breathitt Gray if (value) 98*9c26df9bSWilliam Breathitt Gray ws16c48gpio->out_state[port] |= mask; 99*9c26df9bSWilliam Breathitt Gray else 100*9c26df9bSWilliam Breathitt Gray ws16c48gpio->out_state[port] &= ~mask; 101*9c26df9bSWilliam Breathitt Gray outb(ws16c48gpio->out_state[port], ws16c48gpio->base + port); 102*9c26df9bSWilliam Breathitt Gray 103*9c26df9bSWilliam Breathitt Gray spin_unlock_irqrestore(&ws16c48gpio->lock, flags); 104*9c26df9bSWilliam Breathitt Gray 105*9c26df9bSWilliam Breathitt Gray return 0; 106*9c26df9bSWilliam Breathitt Gray } 107*9c26df9bSWilliam Breathitt Gray 108*9c26df9bSWilliam Breathitt Gray static int ws16c48_gpio_get(struct gpio_chip *chip, unsigned offset) 109*9c26df9bSWilliam Breathitt Gray { 110*9c26df9bSWilliam Breathitt Gray struct ws16c48_gpio *const ws16c48gpio = gpiochip_get_data(chip); 111*9c26df9bSWilliam Breathitt Gray const unsigned port = offset / 8; 112*9c26df9bSWilliam Breathitt Gray const unsigned mask = BIT(offset % 8); 113*9c26df9bSWilliam Breathitt Gray unsigned long flags; 114*9c26df9bSWilliam Breathitt Gray unsigned port_state; 115*9c26df9bSWilliam Breathitt Gray 116*9c26df9bSWilliam Breathitt Gray spin_lock_irqsave(&ws16c48gpio->lock, flags); 117*9c26df9bSWilliam Breathitt Gray 118*9c26df9bSWilliam Breathitt Gray /* ensure that GPIO is set for input */ 119*9c26df9bSWilliam Breathitt Gray if (!(ws16c48gpio->io_state[port] & mask)) { 120*9c26df9bSWilliam Breathitt Gray spin_unlock_irqrestore(&ws16c48gpio->lock, flags); 121*9c26df9bSWilliam Breathitt Gray return -EINVAL; 122*9c26df9bSWilliam Breathitt Gray } 123*9c26df9bSWilliam Breathitt Gray 124*9c26df9bSWilliam Breathitt Gray port_state = inb(ws16c48gpio->base + port); 125*9c26df9bSWilliam Breathitt Gray 126*9c26df9bSWilliam Breathitt Gray spin_unlock_irqrestore(&ws16c48gpio->lock, flags); 127*9c26df9bSWilliam Breathitt Gray 128*9c26df9bSWilliam Breathitt Gray return !!(port_state & mask); 129*9c26df9bSWilliam Breathitt Gray } 130*9c26df9bSWilliam Breathitt Gray 131*9c26df9bSWilliam Breathitt Gray static void ws16c48_gpio_set(struct gpio_chip *chip, unsigned offset, int value) 132*9c26df9bSWilliam Breathitt Gray { 133*9c26df9bSWilliam Breathitt Gray struct ws16c48_gpio *const ws16c48gpio = gpiochip_get_data(chip); 134*9c26df9bSWilliam Breathitt Gray const unsigned port = offset / 8; 135*9c26df9bSWilliam Breathitt Gray const unsigned mask = BIT(offset % 8); 136*9c26df9bSWilliam Breathitt Gray unsigned long flags; 137*9c26df9bSWilliam Breathitt Gray 138*9c26df9bSWilliam Breathitt Gray spin_lock_irqsave(&ws16c48gpio->lock, flags); 139*9c26df9bSWilliam Breathitt Gray 140*9c26df9bSWilliam Breathitt Gray /* ensure that GPIO is set for output */ 141*9c26df9bSWilliam Breathitt Gray if (ws16c48gpio->io_state[port] & mask) { 142*9c26df9bSWilliam Breathitt Gray spin_unlock_irqrestore(&ws16c48gpio->lock, flags); 143*9c26df9bSWilliam Breathitt Gray return; 144*9c26df9bSWilliam Breathitt Gray } 145*9c26df9bSWilliam Breathitt Gray 146*9c26df9bSWilliam Breathitt Gray if (value) 147*9c26df9bSWilliam Breathitt Gray ws16c48gpio->out_state[port] |= mask; 148*9c26df9bSWilliam Breathitt Gray else 149*9c26df9bSWilliam Breathitt Gray ws16c48gpio->out_state[port] &= ~mask; 150*9c26df9bSWilliam Breathitt Gray outb(ws16c48gpio->out_state[port], ws16c48gpio->base + port); 151*9c26df9bSWilliam Breathitt Gray 152*9c26df9bSWilliam Breathitt Gray spin_unlock_irqrestore(&ws16c48gpio->lock, flags); 153*9c26df9bSWilliam Breathitt Gray } 154*9c26df9bSWilliam Breathitt Gray 155*9c26df9bSWilliam Breathitt Gray static void ws16c48_irq_ack(struct irq_data *data) 156*9c26df9bSWilliam Breathitt Gray { 157*9c26df9bSWilliam Breathitt Gray struct gpio_chip *chip = irq_data_get_irq_chip_data(data); 158*9c26df9bSWilliam Breathitt Gray struct ws16c48_gpio *const ws16c48gpio = gpiochip_get_data(chip); 159*9c26df9bSWilliam Breathitt Gray const unsigned long offset = irqd_to_hwirq(data); 160*9c26df9bSWilliam Breathitt Gray const unsigned port = offset / 8; 161*9c26df9bSWilliam Breathitt Gray const unsigned mask = BIT(offset % 8); 162*9c26df9bSWilliam Breathitt Gray unsigned long flags; 163*9c26df9bSWilliam Breathitt Gray unsigned port_state; 164*9c26df9bSWilliam Breathitt Gray 165*9c26df9bSWilliam Breathitt Gray /* only the first 3 ports support interrupts */ 166*9c26df9bSWilliam Breathitt Gray if (port > 2) 167*9c26df9bSWilliam Breathitt Gray return; 168*9c26df9bSWilliam Breathitt Gray 169*9c26df9bSWilliam Breathitt Gray spin_lock_irqsave(&ws16c48gpio->lock, flags); 170*9c26df9bSWilliam Breathitt Gray 171*9c26df9bSWilliam Breathitt Gray port_state = ws16c48gpio->irq_mask >> (8*port); 172*9c26df9bSWilliam Breathitt Gray 173*9c26df9bSWilliam Breathitt Gray outb(0x80, ws16c48gpio->base + 7); 174*9c26df9bSWilliam Breathitt Gray outb(port_state & ~mask, ws16c48gpio->base + 8 + port); 175*9c26df9bSWilliam Breathitt Gray outb(port_state | mask, ws16c48gpio->base + 8 + port); 176*9c26df9bSWilliam Breathitt Gray outb(0xC0, ws16c48gpio->base + 7); 177*9c26df9bSWilliam Breathitt Gray 178*9c26df9bSWilliam Breathitt Gray spin_unlock_irqrestore(&ws16c48gpio->lock, flags); 179*9c26df9bSWilliam Breathitt Gray } 180*9c26df9bSWilliam Breathitt Gray 181*9c26df9bSWilliam Breathitt Gray static void ws16c48_irq_mask(struct irq_data *data) 182*9c26df9bSWilliam Breathitt Gray { 183*9c26df9bSWilliam Breathitt Gray struct gpio_chip *chip = irq_data_get_irq_chip_data(data); 184*9c26df9bSWilliam Breathitt Gray struct ws16c48_gpio *const ws16c48gpio = gpiochip_get_data(chip); 185*9c26df9bSWilliam Breathitt Gray const unsigned long offset = irqd_to_hwirq(data); 186*9c26df9bSWilliam Breathitt Gray const unsigned long mask = BIT(offset); 187*9c26df9bSWilliam Breathitt Gray const unsigned port = offset / 8; 188*9c26df9bSWilliam Breathitt Gray unsigned long flags; 189*9c26df9bSWilliam Breathitt Gray 190*9c26df9bSWilliam Breathitt Gray /* only the first 3 ports support interrupts */ 191*9c26df9bSWilliam Breathitt Gray if (port > 2) 192*9c26df9bSWilliam Breathitt Gray return; 193*9c26df9bSWilliam Breathitt Gray 194*9c26df9bSWilliam Breathitt Gray spin_lock_irqsave(&ws16c48gpio->lock, flags); 195*9c26df9bSWilliam Breathitt Gray 196*9c26df9bSWilliam Breathitt Gray ws16c48gpio->irq_mask &= ~mask; 197*9c26df9bSWilliam Breathitt Gray 198*9c26df9bSWilliam Breathitt Gray outb(0x80, ws16c48gpio->base + 7); 199*9c26df9bSWilliam Breathitt Gray outb(ws16c48gpio->irq_mask >> (8*port), ws16c48gpio->base + 8 + port); 200*9c26df9bSWilliam Breathitt Gray outb(0xC0, ws16c48gpio->base + 7); 201*9c26df9bSWilliam Breathitt Gray 202*9c26df9bSWilliam Breathitt Gray spin_unlock_irqrestore(&ws16c48gpio->lock, flags); 203*9c26df9bSWilliam Breathitt Gray } 204*9c26df9bSWilliam Breathitt Gray 205*9c26df9bSWilliam Breathitt Gray static void ws16c48_irq_unmask(struct irq_data *data) 206*9c26df9bSWilliam Breathitt Gray { 207*9c26df9bSWilliam Breathitt Gray struct gpio_chip *chip = irq_data_get_irq_chip_data(data); 208*9c26df9bSWilliam Breathitt Gray struct ws16c48_gpio *const ws16c48gpio = gpiochip_get_data(chip); 209*9c26df9bSWilliam Breathitt Gray const unsigned long offset = irqd_to_hwirq(data); 210*9c26df9bSWilliam Breathitt Gray const unsigned long mask = BIT(offset); 211*9c26df9bSWilliam Breathitt Gray const unsigned port = offset / 8; 212*9c26df9bSWilliam Breathitt Gray unsigned long flags; 213*9c26df9bSWilliam Breathitt Gray 214*9c26df9bSWilliam Breathitt Gray /* only the first 3 ports support interrupts */ 215*9c26df9bSWilliam Breathitt Gray if (port > 2) 216*9c26df9bSWilliam Breathitt Gray return; 217*9c26df9bSWilliam Breathitt Gray 218*9c26df9bSWilliam Breathitt Gray spin_lock_irqsave(&ws16c48gpio->lock, flags); 219*9c26df9bSWilliam Breathitt Gray 220*9c26df9bSWilliam Breathitt Gray ws16c48gpio->irq_mask |= mask; 221*9c26df9bSWilliam Breathitt Gray 222*9c26df9bSWilliam Breathitt Gray outb(0x80, ws16c48gpio->base + 7); 223*9c26df9bSWilliam Breathitt Gray outb(ws16c48gpio->irq_mask >> (8*port), ws16c48gpio->base + 8 + port); 224*9c26df9bSWilliam Breathitt Gray outb(0xC0, ws16c48gpio->base + 7); 225*9c26df9bSWilliam Breathitt Gray 226*9c26df9bSWilliam Breathitt Gray spin_unlock_irqrestore(&ws16c48gpio->lock, flags); 227*9c26df9bSWilliam Breathitt Gray } 228*9c26df9bSWilliam Breathitt Gray 229*9c26df9bSWilliam Breathitt Gray static int ws16c48_irq_set_type(struct irq_data *data, unsigned flow_type) 230*9c26df9bSWilliam Breathitt Gray { 231*9c26df9bSWilliam Breathitt Gray struct gpio_chip *chip = irq_data_get_irq_chip_data(data); 232*9c26df9bSWilliam Breathitt Gray struct ws16c48_gpio *const ws16c48gpio = gpiochip_get_data(chip); 233*9c26df9bSWilliam Breathitt Gray const unsigned long offset = irqd_to_hwirq(data); 234*9c26df9bSWilliam Breathitt Gray const unsigned long mask = BIT(offset); 235*9c26df9bSWilliam Breathitt Gray const unsigned port = offset / 8; 236*9c26df9bSWilliam Breathitt Gray unsigned long flags; 237*9c26df9bSWilliam Breathitt Gray 238*9c26df9bSWilliam Breathitt Gray /* only the first 3 ports support interrupts */ 239*9c26df9bSWilliam Breathitt Gray if (port > 2) 240*9c26df9bSWilliam Breathitt Gray return -EINVAL; 241*9c26df9bSWilliam Breathitt Gray 242*9c26df9bSWilliam Breathitt Gray spin_lock_irqsave(&ws16c48gpio->lock, flags); 243*9c26df9bSWilliam Breathitt Gray 244*9c26df9bSWilliam Breathitt Gray switch (flow_type) { 245*9c26df9bSWilliam Breathitt Gray case IRQ_TYPE_NONE: 246*9c26df9bSWilliam Breathitt Gray break; 247*9c26df9bSWilliam Breathitt Gray case IRQ_TYPE_EDGE_RISING: 248*9c26df9bSWilliam Breathitt Gray ws16c48gpio->flow_mask |= mask; 249*9c26df9bSWilliam Breathitt Gray break; 250*9c26df9bSWilliam Breathitt Gray case IRQ_TYPE_EDGE_FALLING: 251*9c26df9bSWilliam Breathitt Gray ws16c48gpio->flow_mask &= ~mask; 252*9c26df9bSWilliam Breathitt Gray break; 253*9c26df9bSWilliam Breathitt Gray default: 254*9c26df9bSWilliam Breathitt Gray spin_unlock_irqrestore(&ws16c48gpio->lock, flags); 255*9c26df9bSWilliam Breathitt Gray return -EINVAL; 256*9c26df9bSWilliam Breathitt Gray } 257*9c26df9bSWilliam Breathitt Gray 258*9c26df9bSWilliam Breathitt Gray outb(0x40, ws16c48gpio->base + 7); 259*9c26df9bSWilliam Breathitt Gray outb(ws16c48gpio->flow_mask >> (8*port), ws16c48gpio->base + 8 + port); 260*9c26df9bSWilliam Breathitt Gray outb(0xC0, ws16c48gpio->base + 7); 261*9c26df9bSWilliam Breathitt Gray 262*9c26df9bSWilliam Breathitt Gray spin_unlock_irqrestore(&ws16c48gpio->lock, flags); 263*9c26df9bSWilliam Breathitt Gray 264*9c26df9bSWilliam Breathitt Gray return 0; 265*9c26df9bSWilliam Breathitt Gray } 266*9c26df9bSWilliam Breathitt Gray 267*9c26df9bSWilliam Breathitt Gray static struct irq_chip ws16c48_irqchip = { 268*9c26df9bSWilliam Breathitt Gray .name = "ws16c48", 269*9c26df9bSWilliam Breathitt Gray .irq_ack = ws16c48_irq_ack, 270*9c26df9bSWilliam Breathitt Gray .irq_mask = ws16c48_irq_mask, 271*9c26df9bSWilliam Breathitt Gray .irq_unmask = ws16c48_irq_unmask, 272*9c26df9bSWilliam Breathitt Gray .irq_set_type = ws16c48_irq_set_type 273*9c26df9bSWilliam Breathitt Gray }; 274*9c26df9bSWilliam Breathitt Gray 275*9c26df9bSWilliam Breathitt Gray static irqreturn_t ws16c48_irq_handler(int irq, void *dev_id) 276*9c26df9bSWilliam Breathitt Gray { 277*9c26df9bSWilliam Breathitt Gray struct ws16c48_gpio *const ws16c48gpio = dev_id; 278*9c26df9bSWilliam Breathitt Gray struct gpio_chip *const chip = &ws16c48gpio->chip; 279*9c26df9bSWilliam Breathitt Gray unsigned long int_pending; 280*9c26df9bSWilliam Breathitt Gray unsigned long port; 281*9c26df9bSWilliam Breathitt Gray unsigned long int_id; 282*9c26df9bSWilliam Breathitt Gray unsigned long gpio; 283*9c26df9bSWilliam Breathitt Gray 284*9c26df9bSWilliam Breathitt Gray int_pending = inb(ws16c48gpio->base + 6) & 0x7; 285*9c26df9bSWilliam Breathitt Gray if (!int_pending) 286*9c26df9bSWilliam Breathitt Gray return IRQ_NONE; 287*9c26df9bSWilliam Breathitt Gray 288*9c26df9bSWilliam Breathitt Gray /* loop until all pending interrupts are handled */ 289*9c26df9bSWilliam Breathitt Gray do { 290*9c26df9bSWilliam Breathitt Gray for_each_set_bit(port, &int_pending, 3) { 291*9c26df9bSWilliam Breathitt Gray int_id = inb(ws16c48gpio->base + 8 + port); 292*9c26df9bSWilliam Breathitt Gray for_each_set_bit(gpio, &int_id, 8) 293*9c26df9bSWilliam Breathitt Gray generic_handle_irq(irq_find_mapping( 294*9c26df9bSWilliam Breathitt Gray chip->irqdomain, gpio + 8*port)); 295*9c26df9bSWilliam Breathitt Gray } 296*9c26df9bSWilliam Breathitt Gray 297*9c26df9bSWilliam Breathitt Gray int_pending = inb(ws16c48gpio->base + 6) & 0x7; 298*9c26df9bSWilliam Breathitt Gray } while (int_pending); 299*9c26df9bSWilliam Breathitt Gray 300*9c26df9bSWilliam Breathitt Gray return IRQ_HANDLED; 301*9c26df9bSWilliam Breathitt Gray } 302*9c26df9bSWilliam Breathitt Gray 303*9c26df9bSWilliam Breathitt Gray static int __init ws16c48_probe(struct platform_device *pdev) 304*9c26df9bSWilliam Breathitt Gray { 305*9c26df9bSWilliam Breathitt Gray struct device *dev = &pdev->dev; 306*9c26df9bSWilliam Breathitt Gray struct ws16c48_gpio *ws16c48gpio; 307*9c26df9bSWilliam Breathitt Gray const unsigned base = ws16c48_base; 308*9c26df9bSWilliam Breathitt Gray const unsigned extent = 16; 309*9c26df9bSWilliam Breathitt Gray const char *const name = dev_name(dev); 310*9c26df9bSWilliam Breathitt Gray int err; 311*9c26df9bSWilliam Breathitt Gray const unsigned irq = ws16c48_irq; 312*9c26df9bSWilliam Breathitt Gray 313*9c26df9bSWilliam Breathitt Gray ws16c48gpio = devm_kzalloc(dev, sizeof(*ws16c48gpio), GFP_KERNEL); 314*9c26df9bSWilliam Breathitt Gray if (!ws16c48gpio) 315*9c26df9bSWilliam Breathitt Gray return -ENOMEM; 316*9c26df9bSWilliam Breathitt Gray 317*9c26df9bSWilliam Breathitt Gray if (!request_region(base, extent, name)) { 318*9c26df9bSWilliam Breathitt Gray dev_err(dev, "Unable to lock %s port addresses (0x%X-0x%X)\n", 319*9c26df9bSWilliam Breathitt Gray name, base, base + extent); 320*9c26df9bSWilliam Breathitt Gray err = -EBUSY; 321*9c26df9bSWilliam Breathitt Gray goto err_lock_io_port; 322*9c26df9bSWilliam Breathitt Gray } 323*9c26df9bSWilliam Breathitt Gray 324*9c26df9bSWilliam Breathitt Gray ws16c48gpio->chip.label = name; 325*9c26df9bSWilliam Breathitt Gray ws16c48gpio->chip.parent = dev; 326*9c26df9bSWilliam Breathitt Gray ws16c48gpio->chip.owner = THIS_MODULE; 327*9c26df9bSWilliam Breathitt Gray ws16c48gpio->chip.base = -1; 328*9c26df9bSWilliam Breathitt Gray ws16c48gpio->chip.ngpio = 48; 329*9c26df9bSWilliam Breathitt Gray ws16c48gpio->chip.get_direction = ws16c48_gpio_get_direction; 330*9c26df9bSWilliam Breathitt Gray ws16c48gpio->chip.direction_input = ws16c48_gpio_direction_input; 331*9c26df9bSWilliam Breathitt Gray ws16c48gpio->chip.direction_output = ws16c48_gpio_direction_output; 332*9c26df9bSWilliam Breathitt Gray ws16c48gpio->chip.get = ws16c48_gpio_get; 333*9c26df9bSWilliam Breathitt Gray ws16c48gpio->chip.set = ws16c48_gpio_set; 334*9c26df9bSWilliam Breathitt Gray ws16c48gpio->base = base; 335*9c26df9bSWilliam Breathitt Gray ws16c48gpio->extent = extent; 336*9c26df9bSWilliam Breathitt Gray ws16c48gpio->irq = irq; 337*9c26df9bSWilliam Breathitt Gray 338*9c26df9bSWilliam Breathitt Gray spin_lock_init(&ws16c48gpio->lock); 339*9c26df9bSWilliam Breathitt Gray 340*9c26df9bSWilliam Breathitt Gray dev_set_drvdata(dev, ws16c48gpio); 341*9c26df9bSWilliam Breathitt Gray 342*9c26df9bSWilliam Breathitt Gray err = gpiochip_add_data(&ws16c48gpio->chip, ws16c48gpio); 343*9c26df9bSWilliam Breathitt Gray if (err) { 344*9c26df9bSWilliam Breathitt Gray dev_err(dev, "GPIO registering failed (%d)\n", err); 345*9c26df9bSWilliam Breathitt Gray goto err_gpio_register; 346*9c26df9bSWilliam Breathitt Gray } 347*9c26df9bSWilliam Breathitt Gray 348*9c26df9bSWilliam Breathitt Gray /* Disable IRQ by default */ 349*9c26df9bSWilliam Breathitt Gray outb(0x80, base + 7); 350*9c26df9bSWilliam Breathitt Gray outb(0, base + 8); 351*9c26df9bSWilliam Breathitt Gray outb(0, base + 9); 352*9c26df9bSWilliam Breathitt Gray outb(0, base + 10); 353*9c26df9bSWilliam Breathitt Gray outb(0xC0, base + 7); 354*9c26df9bSWilliam Breathitt Gray 355*9c26df9bSWilliam Breathitt Gray err = gpiochip_irqchip_add(&ws16c48gpio->chip, &ws16c48_irqchip, 0, 356*9c26df9bSWilliam Breathitt Gray handle_edge_irq, IRQ_TYPE_NONE); 357*9c26df9bSWilliam Breathitt Gray if (err) { 358*9c26df9bSWilliam Breathitt Gray dev_err(dev, "Could not add irqchip (%d)\n", err); 359*9c26df9bSWilliam Breathitt Gray goto err_gpiochip_irqchip_add; 360*9c26df9bSWilliam Breathitt Gray } 361*9c26df9bSWilliam Breathitt Gray 362*9c26df9bSWilliam Breathitt Gray err = request_irq(irq, ws16c48_irq_handler, IRQF_SHARED, name, 363*9c26df9bSWilliam Breathitt Gray ws16c48gpio); 364*9c26df9bSWilliam Breathitt Gray if (err) { 365*9c26df9bSWilliam Breathitt Gray dev_err(dev, "IRQ handler registering failed (%d)\n", err); 366*9c26df9bSWilliam Breathitt Gray goto err_request_irq; 367*9c26df9bSWilliam Breathitt Gray } 368*9c26df9bSWilliam Breathitt Gray 369*9c26df9bSWilliam Breathitt Gray return 0; 370*9c26df9bSWilliam Breathitt Gray 371*9c26df9bSWilliam Breathitt Gray err_request_irq: 372*9c26df9bSWilliam Breathitt Gray err_gpiochip_irqchip_add: 373*9c26df9bSWilliam Breathitt Gray gpiochip_remove(&ws16c48gpio->chip); 374*9c26df9bSWilliam Breathitt Gray err_gpio_register: 375*9c26df9bSWilliam Breathitt Gray release_region(base, extent); 376*9c26df9bSWilliam Breathitt Gray err_lock_io_port: 377*9c26df9bSWilliam Breathitt Gray return err; 378*9c26df9bSWilliam Breathitt Gray } 379*9c26df9bSWilliam Breathitt Gray 380*9c26df9bSWilliam Breathitt Gray static int ws16c48_remove(struct platform_device *pdev) 381*9c26df9bSWilliam Breathitt Gray { 382*9c26df9bSWilliam Breathitt Gray struct ws16c48_gpio *const ws16c48gpio = platform_get_drvdata(pdev); 383*9c26df9bSWilliam Breathitt Gray 384*9c26df9bSWilliam Breathitt Gray free_irq(ws16c48gpio->irq, ws16c48gpio); 385*9c26df9bSWilliam Breathitt Gray gpiochip_remove(&ws16c48gpio->chip); 386*9c26df9bSWilliam Breathitt Gray release_region(ws16c48gpio->base, ws16c48gpio->extent); 387*9c26df9bSWilliam Breathitt Gray 388*9c26df9bSWilliam Breathitt Gray return 0; 389*9c26df9bSWilliam Breathitt Gray } 390*9c26df9bSWilliam Breathitt Gray 391*9c26df9bSWilliam Breathitt Gray static struct platform_device *ws16c48_device; 392*9c26df9bSWilliam Breathitt Gray 393*9c26df9bSWilliam Breathitt Gray static struct platform_driver ws16c48_driver = { 394*9c26df9bSWilliam Breathitt Gray .driver = { 395*9c26df9bSWilliam Breathitt Gray .name = "ws16c48" 396*9c26df9bSWilliam Breathitt Gray }, 397*9c26df9bSWilliam Breathitt Gray .remove = ws16c48_remove 398*9c26df9bSWilliam Breathitt Gray }; 399*9c26df9bSWilliam Breathitt Gray 400*9c26df9bSWilliam Breathitt Gray static void __exit ws16c48_exit(void) 401*9c26df9bSWilliam Breathitt Gray { 402*9c26df9bSWilliam Breathitt Gray platform_device_unregister(ws16c48_device); 403*9c26df9bSWilliam Breathitt Gray platform_driver_unregister(&ws16c48_driver); 404*9c26df9bSWilliam Breathitt Gray } 405*9c26df9bSWilliam Breathitt Gray 406*9c26df9bSWilliam Breathitt Gray static int __init ws16c48_init(void) 407*9c26df9bSWilliam Breathitt Gray { 408*9c26df9bSWilliam Breathitt Gray int err; 409*9c26df9bSWilliam Breathitt Gray 410*9c26df9bSWilliam Breathitt Gray ws16c48_device = platform_device_alloc(ws16c48_driver.driver.name, -1); 411*9c26df9bSWilliam Breathitt Gray if (!ws16c48_device) 412*9c26df9bSWilliam Breathitt Gray return -ENOMEM; 413*9c26df9bSWilliam Breathitt Gray 414*9c26df9bSWilliam Breathitt Gray err = platform_device_add(ws16c48_device); 415*9c26df9bSWilliam Breathitt Gray if (err) 416*9c26df9bSWilliam Breathitt Gray goto err_platform_device; 417*9c26df9bSWilliam Breathitt Gray 418*9c26df9bSWilliam Breathitt Gray err = platform_driver_probe(&ws16c48_driver, ws16c48_probe); 419*9c26df9bSWilliam Breathitt Gray if (err) 420*9c26df9bSWilliam Breathitt Gray goto err_platform_driver; 421*9c26df9bSWilliam Breathitt Gray 422*9c26df9bSWilliam Breathitt Gray return 0; 423*9c26df9bSWilliam Breathitt Gray 424*9c26df9bSWilliam Breathitt Gray err_platform_driver: 425*9c26df9bSWilliam Breathitt Gray platform_device_del(ws16c48_device); 426*9c26df9bSWilliam Breathitt Gray err_platform_device: 427*9c26df9bSWilliam Breathitt Gray platform_device_put(ws16c48_device); 428*9c26df9bSWilliam Breathitt Gray return err; 429*9c26df9bSWilliam Breathitt Gray } 430*9c26df9bSWilliam Breathitt Gray 431*9c26df9bSWilliam Breathitt Gray module_init(ws16c48_init); 432*9c26df9bSWilliam Breathitt Gray module_exit(ws16c48_exit); 433*9c26df9bSWilliam Breathitt Gray 434*9c26df9bSWilliam Breathitt Gray MODULE_AUTHOR("William Breathitt Gray <vilhelm.gray@gmail.com>"); 435*9c26df9bSWilliam Breathitt Gray MODULE_DESCRIPTION("WinSystems WS16C48 GPIO driver"); 436*9c26df9bSWilliam Breathitt Gray MODULE_LICENSE("GPL"); 437