11802d0beSThomas Gleixner // SPDX-License-Identifier: GPL-2.0-only 29c26df9bSWilliam Breathitt Gray /* 39c26df9bSWilliam Breathitt Gray * GPIO driver for the WinSystems WS16C48 49c26df9bSWilliam Breathitt Gray * Copyright (C) 2016 William Breathitt Gray 59c26df9bSWilliam Breathitt Gray */ 6a8ff510dSWilliam Breathitt Gray #include <linux/bitmap.h> 79c26df9bSWilliam Breathitt Gray #include <linux/device.h> 89c26df9bSWilliam Breathitt Gray #include <linux/errno.h> 99c26df9bSWilliam Breathitt Gray #include <linux/gpio/driver.h> 109c26df9bSWilliam Breathitt Gray #include <linux/io.h> 119c26df9bSWilliam Breathitt Gray #include <linux/ioport.h> 129c26df9bSWilliam Breathitt Gray #include <linux/interrupt.h> 139c26df9bSWilliam Breathitt Gray #include <linux/irqdesc.h> 14cc736607SWilliam Breathitt Gray #include <linux/isa.h> 159c26df9bSWilliam Breathitt Gray #include <linux/kernel.h> 169c26df9bSWilliam Breathitt Gray #include <linux/module.h> 179c26df9bSWilliam Breathitt Gray #include <linux/moduleparam.h> 189c26df9bSWilliam Breathitt Gray #include <linux/spinlock.h> 192c05a0f2SWilliam Breathitt Gray #include <linux/types.h> 209c26df9bSWilliam Breathitt Gray 21*33f83d13SWilliam Breathitt Gray #define WS16C48_EXTENT 11 22cc736607SWilliam Breathitt Gray #define MAX_NUM_WS16C48 max_num_isa_dev(WS16C48_EXTENT) 23cc736607SWilliam Breathitt Gray 24cc736607SWilliam Breathitt Gray static unsigned int base[MAX_NUM_WS16C48]; 25cc736607SWilliam Breathitt Gray static unsigned int num_ws16c48; 26d759f906SDavid Howells module_param_hw_array(base, uint, ioport, &num_ws16c48, 0); 27cc736607SWilliam Breathitt Gray MODULE_PARM_DESC(base, "WinSystems WS16C48 base addresses"); 28cc736607SWilliam Breathitt Gray 29cc736607SWilliam Breathitt Gray static unsigned int irq[MAX_NUM_WS16C48]; 30c95671a3SWilliam Breathitt Gray static unsigned int num_irq; 31c95671a3SWilliam Breathitt Gray module_param_hw_array(irq, uint, irq, &num_irq, 0); 32cc736607SWilliam Breathitt Gray MODULE_PARM_DESC(irq, "WinSystems WS16C48 interrupt line numbers"); 339c26df9bSWilliam Breathitt Gray 349c26df9bSWilliam Breathitt Gray /** 352c05a0f2SWilliam Breathitt Gray * struct ws16c48_reg - device register structure 362c05a0f2SWilliam Breathitt Gray * @port: Port 0 through 5 I/O 372c05a0f2SWilliam Breathitt Gray * @int_pending: Interrupt Pending 382c05a0f2SWilliam Breathitt Gray * @page_lock: Register page (Bits 7-6) and I/O port lock (Bits 5-0) 392c05a0f2SWilliam Breathitt Gray * @pol_enab_int_id: Interrupt polarity, enable, and ID 402c05a0f2SWilliam Breathitt Gray */ 412c05a0f2SWilliam Breathitt Gray struct ws16c48_reg { 422c05a0f2SWilliam Breathitt Gray u8 port[6]; 432c05a0f2SWilliam Breathitt Gray u8 int_pending; 442c05a0f2SWilliam Breathitt Gray u8 page_lock; 452c05a0f2SWilliam Breathitt Gray u8 pol_enab_int_id[3]; 462c05a0f2SWilliam Breathitt Gray }; 472c05a0f2SWilliam Breathitt Gray 482c05a0f2SWilliam Breathitt Gray /** 499c26df9bSWilliam Breathitt Gray * struct ws16c48_gpio - GPIO device private data structure 509c26df9bSWilliam Breathitt Gray * @chip: instance of the gpio_chip 519c26df9bSWilliam Breathitt Gray * @io_state: bit I/O state (whether bit is set to input or output) 529c26df9bSWilliam Breathitt Gray * @out_state: output bits state 539c26df9bSWilliam Breathitt Gray * @lock: synchronization lock to prevent I/O race conditions 549c26df9bSWilliam Breathitt Gray * @irq_mask: I/O bits affected by interrupts 559c26df9bSWilliam Breathitt Gray * @flow_mask: IRQ flow type mask for the respective I/O bits 562c05a0f2SWilliam Breathitt Gray * @reg: I/O address offset for the device registers 579c26df9bSWilliam Breathitt Gray */ 589c26df9bSWilliam Breathitt Gray struct ws16c48_gpio { 599c26df9bSWilliam Breathitt Gray struct gpio_chip chip; 609c26df9bSWilliam Breathitt Gray unsigned char io_state[6]; 619c26df9bSWilliam Breathitt Gray unsigned char out_state[6]; 62a0a584f0SJulia Cartwright raw_spinlock_t lock; 639c26df9bSWilliam Breathitt Gray unsigned long irq_mask; 649c26df9bSWilliam Breathitt Gray unsigned long flow_mask; 652c05a0f2SWilliam Breathitt Gray struct ws16c48_reg __iomem *reg; 669c26df9bSWilliam Breathitt Gray }; 679c26df9bSWilliam Breathitt Gray 689c26df9bSWilliam Breathitt Gray static int ws16c48_gpio_get_direction(struct gpio_chip *chip, unsigned offset) 699c26df9bSWilliam Breathitt Gray { 709c26df9bSWilliam Breathitt Gray struct ws16c48_gpio *const ws16c48gpio = gpiochip_get_data(chip); 719c26df9bSWilliam Breathitt Gray const unsigned port = offset / 8; 729c26df9bSWilliam Breathitt Gray const unsigned mask = BIT(offset % 8); 739c26df9bSWilliam Breathitt Gray 74e42615ecSMatti Vaittinen if (ws16c48gpio->io_state[port] & mask) 75e42615ecSMatti Vaittinen return GPIO_LINE_DIRECTION_IN; 76e42615ecSMatti Vaittinen 77e42615ecSMatti Vaittinen return GPIO_LINE_DIRECTION_OUT; 789c26df9bSWilliam Breathitt Gray } 799c26df9bSWilliam Breathitt Gray 809c26df9bSWilliam Breathitt Gray static int ws16c48_gpio_direction_input(struct gpio_chip *chip, unsigned offset) 819c26df9bSWilliam Breathitt Gray { 829c26df9bSWilliam Breathitt Gray struct ws16c48_gpio *const ws16c48gpio = gpiochip_get_data(chip); 839c26df9bSWilliam Breathitt Gray const unsigned port = offset / 8; 849c26df9bSWilliam Breathitt Gray const unsigned mask = BIT(offset % 8); 859c26df9bSWilliam Breathitt Gray unsigned long flags; 869c26df9bSWilliam Breathitt Gray 87a0a584f0SJulia Cartwright raw_spin_lock_irqsave(&ws16c48gpio->lock, flags); 889c26df9bSWilliam Breathitt Gray 899c26df9bSWilliam Breathitt Gray ws16c48gpio->io_state[port] |= mask; 909c26df9bSWilliam Breathitt Gray ws16c48gpio->out_state[port] &= ~mask; 912c05a0f2SWilliam Breathitt Gray iowrite8(ws16c48gpio->out_state[port], ws16c48gpio->reg->port + port); 929c26df9bSWilliam Breathitt Gray 93a0a584f0SJulia Cartwright raw_spin_unlock_irqrestore(&ws16c48gpio->lock, flags); 949c26df9bSWilliam Breathitt Gray 959c26df9bSWilliam Breathitt Gray return 0; 969c26df9bSWilliam Breathitt Gray } 979c26df9bSWilliam Breathitt Gray 989c26df9bSWilliam Breathitt Gray static int ws16c48_gpio_direction_output(struct gpio_chip *chip, 999c26df9bSWilliam Breathitt Gray unsigned offset, int value) 1009c26df9bSWilliam Breathitt Gray { 1019c26df9bSWilliam Breathitt Gray struct ws16c48_gpio *const ws16c48gpio = gpiochip_get_data(chip); 1029c26df9bSWilliam Breathitt Gray const unsigned port = offset / 8; 1039c26df9bSWilliam Breathitt Gray const unsigned mask = BIT(offset % 8); 1049c26df9bSWilliam Breathitt Gray unsigned long flags; 1059c26df9bSWilliam Breathitt Gray 106a0a584f0SJulia Cartwright raw_spin_lock_irqsave(&ws16c48gpio->lock, flags); 1079c26df9bSWilliam Breathitt Gray 1089c26df9bSWilliam Breathitt Gray ws16c48gpio->io_state[port] &= ~mask; 1099c26df9bSWilliam Breathitt Gray if (value) 1109c26df9bSWilliam Breathitt Gray ws16c48gpio->out_state[port] |= mask; 1119c26df9bSWilliam Breathitt Gray else 1129c26df9bSWilliam Breathitt Gray ws16c48gpio->out_state[port] &= ~mask; 1132c05a0f2SWilliam Breathitt Gray iowrite8(ws16c48gpio->out_state[port], ws16c48gpio->reg->port + port); 1149c26df9bSWilliam Breathitt Gray 115a0a584f0SJulia Cartwright raw_spin_unlock_irqrestore(&ws16c48gpio->lock, flags); 1169c26df9bSWilliam Breathitt Gray 1179c26df9bSWilliam Breathitt Gray return 0; 1189c26df9bSWilliam Breathitt Gray } 1199c26df9bSWilliam Breathitt Gray 1209c26df9bSWilliam Breathitt Gray static int ws16c48_gpio_get(struct gpio_chip *chip, unsigned offset) 1219c26df9bSWilliam Breathitt Gray { 1229c26df9bSWilliam Breathitt Gray struct ws16c48_gpio *const ws16c48gpio = gpiochip_get_data(chip); 1239c26df9bSWilliam Breathitt Gray const unsigned port = offset / 8; 1249c26df9bSWilliam Breathitt Gray const unsigned mask = BIT(offset % 8); 1259c26df9bSWilliam Breathitt Gray unsigned long flags; 1269c26df9bSWilliam Breathitt Gray unsigned port_state; 1279c26df9bSWilliam Breathitt Gray 128a0a584f0SJulia Cartwright raw_spin_lock_irqsave(&ws16c48gpio->lock, flags); 1299c26df9bSWilliam Breathitt Gray 1309c26df9bSWilliam Breathitt Gray /* ensure that GPIO is set for input */ 1319c26df9bSWilliam Breathitt Gray if (!(ws16c48gpio->io_state[port] & mask)) { 132a0a584f0SJulia Cartwright raw_spin_unlock_irqrestore(&ws16c48gpio->lock, flags); 1339c26df9bSWilliam Breathitt Gray return -EINVAL; 1349c26df9bSWilliam Breathitt Gray } 1359c26df9bSWilliam Breathitt Gray 1362c05a0f2SWilliam Breathitt Gray port_state = ioread8(ws16c48gpio->reg->port + port); 1379c26df9bSWilliam Breathitt Gray 138a0a584f0SJulia Cartwright raw_spin_unlock_irqrestore(&ws16c48gpio->lock, flags); 1399c26df9bSWilliam Breathitt Gray 1409c26df9bSWilliam Breathitt Gray return !!(port_state & mask); 1419c26df9bSWilliam Breathitt Gray } 1429c26df9bSWilliam Breathitt Gray 143a8ff510dSWilliam Breathitt Gray static int ws16c48_gpio_get_multiple(struct gpio_chip *chip, 144a8ff510dSWilliam Breathitt Gray unsigned long *mask, unsigned long *bits) 145a8ff510dSWilliam Breathitt Gray { 146a8ff510dSWilliam Breathitt Gray struct ws16c48_gpio *const ws16c48gpio = gpiochip_get_data(chip); 147acebb82fSWilliam Breathitt Gray unsigned long offset; 148acebb82fSWilliam Breathitt Gray unsigned long gpio_mask; 1492c05a0f2SWilliam Breathitt Gray size_t index; 1502c05a0f2SWilliam Breathitt Gray u8 __iomem *port_addr; 151a8ff510dSWilliam Breathitt Gray unsigned long port_state; 152a8ff510dSWilliam Breathitt Gray 153a8ff510dSWilliam Breathitt Gray /* clear bits array to a clean slate */ 154a8ff510dSWilliam Breathitt Gray bitmap_zero(bits, chip->ngpio); 155a8ff510dSWilliam Breathitt Gray 156acebb82fSWilliam Breathitt Gray for_each_set_clump8(offset, gpio_mask, mask, chip->ngpio) { 1572c05a0f2SWilliam Breathitt Gray index = offset / 8; 1582c05a0f2SWilliam Breathitt Gray port_addr = ws16c48gpio->reg->port + index; 1595561a2b0SWilliam Breathitt Gray port_state = ioread8(port_addr) & gpio_mask; 160a8ff510dSWilliam Breathitt Gray 161acebb82fSWilliam Breathitt Gray bitmap_set_value8(bits, port_state, offset); 162a8ff510dSWilliam Breathitt Gray } 163a8ff510dSWilliam Breathitt Gray 164a8ff510dSWilliam Breathitt Gray return 0; 165a8ff510dSWilliam Breathitt Gray } 166a8ff510dSWilliam Breathitt Gray 1679c26df9bSWilliam Breathitt Gray static void ws16c48_gpio_set(struct gpio_chip *chip, unsigned offset, int value) 1689c26df9bSWilliam Breathitt Gray { 1699c26df9bSWilliam Breathitt Gray struct ws16c48_gpio *const ws16c48gpio = gpiochip_get_data(chip); 1709c26df9bSWilliam Breathitt Gray const unsigned port = offset / 8; 1719c26df9bSWilliam Breathitt Gray const unsigned mask = BIT(offset % 8); 1729c26df9bSWilliam Breathitt Gray unsigned long flags; 1739c26df9bSWilliam Breathitt Gray 174a0a584f0SJulia Cartwright raw_spin_lock_irqsave(&ws16c48gpio->lock, flags); 1759c26df9bSWilliam Breathitt Gray 1769c26df9bSWilliam Breathitt Gray /* ensure that GPIO is set for output */ 1779c26df9bSWilliam Breathitt Gray if (ws16c48gpio->io_state[port] & mask) { 178a0a584f0SJulia Cartwright raw_spin_unlock_irqrestore(&ws16c48gpio->lock, flags); 1799c26df9bSWilliam Breathitt Gray return; 1809c26df9bSWilliam Breathitt Gray } 1819c26df9bSWilliam Breathitt Gray 1829c26df9bSWilliam Breathitt Gray if (value) 1839c26df9bSWilliam Breathitt Gray ws16c48gpio->out_state[port] |= mask; 1849c26df9bSWilliam Breathitt Gray else 1859c26df9bSWilliam Breathitt Gray ws16c48gpio->out_state[port] &= ~mask; 1862c05a0f2SWilliam Breathitt Gray iowrite8(ws16c48gpio->out_state[port], ws16c48gpio->reg->port + port); 1879c26df9bSWilliam Breathitt Gray 188a0a584f0SJulia Cartwright raw_spin_unlock_irqrestore(&ws16c48gpio->lock, flags); 1899c26df9bSWilliam Breathitt Gray } 1909c26df9bSWilliam Breathitt Gray 19199c8ac95SWilliam Breathitt Gray static void ws16c48_gpio_set_multiple(struct gpio_chip *chip, 19299c8ac95SWilliam Breathitt Gray unsigned long *mask, unsigned long *bits) 19399c8ac95SWilliam Breathitt Gray { 19499c8ac95SWilliam Breathitt Gray struct ws16c48_gpio *const ws16c48gpio = gpiochip_get_data(chip); 195acebb82fSWilliam Breathitt Gray unsigned long offset; 196acebb82fSWilliam Breathitt Gray unsigned long gpio_mask; 197acebb82fSWilliam Breathitt Gray size_t index; 1982c05a0f2SWilliam Breathitt Gray u8 __iomem *port_addr; 199acebb82fSWilliam Breathitt Gray unsigned long bitmask; 20099c8ac95SWilliam Breathitt Gray unsigned long flags; 20199c8ac95SWilliam Breathitt Gray 202acebb82fSWilliam Breathitt Gray for_each_set_clump8(offset, gpio_mask, mask, chip->ngpio) { 203acebb82fSWilliam Breathitt Gray index = offset / 8; 2042c05a0f2SWilliam Breathitt Gray port_addr = ws16c48gpio->reg->port + index; 20599c8ac95SWilliam Breathitt Gray 20699c8ac95SWilliam Breathitt Gray /* mask out GPIO configured for input */ 207acebb82fSWilliam Breathitt Gray gpio_mask &= ~ws16c48gpio->io_state[index]; 208acebb82fSWilliam Breathitt Gray bitmask = bitmap_get_value8(bits, offset) & gpio_mask; 20999c8ac95SWilliam Breathitt Gray 210a0a584f0SJulia Cartwright raw_spin_lock_irqsave(&ws16c48gpio->lock, flags); 21199c8ac95SWilliam Breathitt Gray 21299c8ac95SWilliam Breathitt Gray /* update output state data and set device gpio register */ 213acebb82fSWilliam Breathitt Gray ws16c48gpio->out_state[index] &= ~gpio_mask; 214acebb82fSWilliam Breathitt Gray ws16c48gpio->out_state[index] |= bitmask; 2155561a2b0SWilliam Breathitt Gray iowrite8(ws16c48gpio->out_state[index], port_addr); 21699c8ac95SWilliam Breathitt Gray 217a0a584f0SJulia Cartwright raw_spin_unlock_irqrestore(&ws16c48gpio->lock, flags); 21899c8ac95SWilliam Breathitt Gray } 21999c8ac95SWilliam Breathitt Gray } 22099c8ac95SWilliam Breathitt Gray 2219c26df9bSWilliam Breathitt Gray static void ws16c48_irq_ack(struct irq_data *data) 2229c26df9bSWilliam Breathitt Gray { 2239c26df9bSWilliam Breathitt Gray struct gpio_chip *chip = irq_data_get_irq_chip_data(data); 2249c26df9bSWilliam Breathitt Gray struct ws16c48_gpio *const ws16c48gpio = gpiochip_get_data(chip); 2259c26df9bSWilliam Breathitt Gray const unsigned long offset = irqd_to_hwirq(data); 2269c26df9bSWilliam Breathitt Gray const unsigned port = offset / 8; 2279c26df9bSWilliam Breathitt Gray const unsigned mask = BIT(offset % 8); 2289c26df9bSWilliam Breathitt Gray unsigned long flags; 2299c26df9bSWilliam Breathitt Gray unsigned port_state; 2309c26df9bSWilliam Breathitt Gray 2319c26df9bSWilliam Breathitt Gray /* only the first 3 ports support interrupts */ 2329c26df9bSWilliam Breathitt Gray if (port > 2) 2339c26df9bSWilliam Breathitt Gray return; 2349c26df9bSWilliam Breathitt Gray 235a0a584f0SJulia Cartwright raw_spin_lock_irqsave(&ws16c48gpio->lock, flags); 2369c26df9bSWilliam Breathitt Gray 2379c26df9bSWilliam Breathitt Gray port_state = ws16c48gpio->irq_mask >> (8*port); 2389c26df9bSWilliam Breathitt Gray 2392c05a0f2SWilliam Breathitt Gray /* Select Register Page 2; Unlock all I/O ports */ 2402c05a0f2SWilliam Breathitt Gray iowrite8(0x80, &ws16c48gpio->reg->page_lock); 2412c05a0f2SWilliam Breathitt Gray 2422c05a0f2SWilliam Breathitt Gray /* Clear pending interrupt */ 2432c05a0f2SWilliam Breathitt Gray iowrite8(port_state & ~mask, ws16c48gpio->reg->pol_enab_int_id + port); 2442c05a0f2SWilliam Breathitt Gray iowrite8(port_state | mask, ws16c48gpio->reg->pol_enab_int_id + port); 2452c05a0f2SWilliam Breathitt Gray 2462c05a0f2SWilliam Breathitt Gray /* Select Register Page 3; Unlock all I/O ports */ 2472c05a0f2SWilliam Breathitt Gray iowrite8(0xC0, &ws16c48gpio->reg->page_lock); 2489c26df9bSWilliam Breathitt Gray 249a0a584f0SJulia Cartwright raw_spin_unlock_irqrestore(&ws16c48gpio->lock, flags); 2509c26df9bSWilliam Breathitt Gray } 2519c26df9bSWilliam Breathitt Gray 2529c26df9bSWilliam Breathitt Gray static void ws16c48_irq_mask(struct irq_data *data) 2539c26df9bSWilliam Breathitt Gray { 2549c26df9bSWilliam Breathitt Gray struct gpio_chip *chip = irq_data_get_irq_chip_data(data); 2559c26df9bSWilliam Breathitt Gray struct ws16c48_gpio *const ws16c48gpio = gpiochip_get_data(chip); 2569c26df9bSWilliam Breathitt Gray const unsigned long offset = irqd_to_hwirq(data); 2579c26df9bSWilliam Breathitt Gray const unsigned long mask = BIT(offset); 2589c26df9bSWilliam Breathitt Gray const unsigned port = offset / 8; 2599c26df9bSWilliam Breathitt Gray unsigned long flags; 2602c05a0f2SWilliam Breathitt Gray unsigned long port_state; 2619c26df9bSWilliam Breathitt Gray 2629c26df9bSWilliam Breathitt Gray /* only the first 3 ports support interrupts */ 2639c26df9bSWilliam Breathitt Gray if (port > 2) 2649c26df9bSWilliam Breathitt Gray return; 2659c26df9bSWilliam Breathitt Gray 266a0a584f0SJulia Cartwright raw_spin_lock_irqsave(&ws16c48gpio->lock, flags); 2679c26df9bSWilliam Breathitt Gray 2689c26df9bSWilliam Breathitt Gray ws16c48gpio->irq_mask &= ~mask; 26968903817SWilliam Breathitt Gray gpiochip_disable_irq(chip, offset); 2702c05a0f2SWilliam Breathitt Gray port_state = ws16c48gpio->irq_mask >> (8 * port); 2719c26df9bSWilliam Breathitt Gray 2722c05a0f2SWilliam Breathitt Gray /* Select Register Page 2; Unlock all I/O ports */ 2732c05a0f2SWilliam Breathitt Gray iowrite8(0x80, &ws16c48gpio->reg->page_lock); 2742c05a0f2SWilliam Breathitt Gray 2752c05a0f2SWilliam Breathitt Gray /* Disable interrupt */ 2762c05a0f2SWilliam Breathitt Gray iowrite8(port_state, ws16c48gpio->reg->pol_enab_int_id + port); 2772c05a0f2SWilliam Breathitt Gray 2782c05a0f2SWilliam Breathitt Gray /* Select Register Page 3; Unlock all I/O ports */ 2792c05a0f2SWilliam Breathitt Gray iowrite8(0xC0, &ws16c48gpio->reg->page_lock); 2809c26df9bSWilliam Breathitt Gray 281a0a584f0SJulia Cartwright raw_spin_unlock_irqrestore(&ws16c48gpio->lock, flags); 2829c26df9bSWilliam Breathitt Gray } 2839c26df9bSWilliam Breathitt Gray 2849c26df9bSWilliam Breathitt Gray static void ws16c48_irq_unmask(struct irq_data *data) 2859c26df9bSWilliam Breathitt Gray { 2869c26df9bSWilliam Breathitt Gray struct gpio_chip *chip = irq_data_get_irq_chip_data(data); 2879c26df9bSWilliam Breathitt Gray struct ws16c48_gpio *const ws16c48gpio = gpiochip_get_data(chip); 2889c26df9bSWilliam Breathitt Gray const unsigned long offset = irqd_to_hwirq(data); 2899c26df9bSWilliam Breathitt Gray const unsigned long mask = BIT(offset); 2909c26df9bSWilliam Breathitt Gray const unsigned port = offset / 8; 2919c26df9bSWilliam Breathitt Gray unsigned long flags; 2922c05a0f2SWilliam Breathitt Gray unsigned long port_state; 2939c26df9bSWilliam Breathitt Gray 2949c26df9bSWilliam Breathitt Gray /* only the first 3 ports support interrupts */ 2959c26df9bSWilliam Breathitt Gray if (port > 2) 2969c26df9bSWilliam Breathitt Gray return; 2979c26df9bSWilliam Breathitt Gray 298a0a584f0SJulia Cartwright raw_spin_lock_irqsave(&ws16c48gpio->lock, flags); 2999c26df9bSWilliam Breathitt Gray 30068903817SWilliam Breathitt Gray gpiochip_enable_irq(chip, offset); 3019c26df9bSWilliam Breathitt Gray ws16c48gpio->irq_mask |= mask; 3022c05a0f2SWilliam Breathitt Gray port_state = ws16c48gpio->irq_mask >> (8 * port); 3039c26df9bSWilliam Breathitt Gray 3042c05a0f2SWilliam Breathitt Gray /* Select Register Page 2; Unlock all I/O ports */ 3052c05a0f2SWilliam Breathitt Gray iowrite8(0x80, &ws16c48gpio->reg->page_lock); 3062c05a0f2SWilliam Breathitt Gray 3072c05a0f2SWilliam Breathitt Gray /* Enable interrupt */ 3082c05a0f2SWilliam Breathitt Gray iowrite8(port_state, ws16c48gpio->reg->pol_enab_int_id + port); 3092c05a0f2SWilliam Breathitt Gray 3102c05a0f2SWilliam Breathitt Gray /* Select Register Page 3; Unlock all I/O ports */ 3112c05a0f2SWilliam Breathitt Gray iowrite8(0xC0, &ws16c48gpio->reg->page_lock); 3129c26df9bSWilliam Breathitt Gray 313a0a584f0SJulia Cartwright raw_spin_unlock_irqrestore(&ws16c48gpio->lock, flags); 3149c26df9bSWilliam Breathitt Gray } 3159c26df9bSWilliam Breathitt Gray 3169c26df9bSWilliam Breathitt Gray static int ws16c48_irq_set_type(struct irq_data *data, unsigned flow_type) 3179c26df9bSWilliam Breathitt Gray { 3189c26df9bSWilliam Breathitt Gray struct gpio_chip *chip = irq_data_get_irq_chip_data(data); 3199c26df9bSWilliam Breathitt Gray struct ws16c48_gpio *const ws16c48gpio = gpiochip_get_data(chip); 3209c26df9bSWilliam Breathitt Gray const unsigned long offset = irqd_to_hwirq(data); 3219c26df9bSWilliam Breathitt Gray const unsigned long mask = BIT(offset); 3229c26df9bSWilliam Breathitt Gray const unsigned port = offset / 8; 3239c26df9bSWilliam Breathitt Gray unsigned long flags; 3242c05a0f2SWilliam Breathitt Gray unsigned long port_state; 3259c26df9bSWilliam Breathitt Gray 3269c26df9bSWilliam Breathitt Gray /* only the first 3 ports support interrupts */ 3279c26df9bSWilliam Breathitt Gray if (port > 2) 3289c26df9bSWilliam Breathitt Gray return -EINVAL; 3299c26df9bSWilliam Breathitt Gray 330a0a584f0SJulia Cartwright raw_spin_lock_irqsave(&ws16c48gpio->lock, flags); 3319c26df9bSWilliam Breathitt Gray 3329c26df9bSWilliam Breathitt Gray switch (flow_type) { 3339c26df9bSWilliam Breathitt Gray case IRQ_TYPE_NONE: 3349c26df9bSWilliam Breathitt Gray break; 3359c26df9bSWilliam Breathitt Gray case IRQ_TYPE_EDGE_RISING: 3369c26df9bSWilliam Breathitt Gray ws16c48gpio->flow_mask |= mask; 3379c26df9bSWilliam Breathitt Gray break; 3389c26df9bSWilliam Breathitt Gray case IRQ_TYPE_EDGE_FALLING: 3399c26df9bSWilliam Breathitt Gray ws16c48gpio->flow_mask &= ~mask; 3409c26df9bSWilliam Breathitt Gray break; 3419c26df9bSWilliam Breathitt Gray default: 342a0a584f0SJulia Cartwright raw_spin_unlock_irqrestore(&ws16c48gpio->lock, flags); 3439c26df9bSWilliam Breathitt Gray return -EINVAL; 3449c26df9bSWilliam Breathitt Gray } 3459c26df9bSWilliam Breathitt Gray 3462c05a0f2SWilliam Breathitt Gray port_state = ws16c48gpio->flow_mask >> (8 * port); 3472c05a0f2SWilliam Breathitt Gray 3482c05a0f2SWilliam Breathitt Gray /* Select Register Page 1; Unlock all I/O ports */ 3492c05a0f2SWilliam Breathitt Gray iowrite8(0x40, &ws16c48gpio->reg->page_lock); 3502c05a0f2SWilliam Breathitt Gray 3512c05a0f2SWilliam Breathitt Gray /* Set interrupt polarity */ 3522c05a0f2SWilliam Breathitt Gray iowrite8(port_state, ws16c48gpio->reg->pol_enab_int_id + port); 3532c05a0f2SWilliam Breathitt Gray 3542c05a0f2SWilliam Breathitt Gray /* Select Register Page 3; Unlock all I/O ports */ 3552c05a0f2SWilliam Breathitt Gray iowrite8(0xC0, &ws16c48gpio->reg->page_lock); 3569c26df9bSWilliam Breathitt Gray 357a0a584f0SJulia Cartwright raw_spin_unlock_irqrestore(&ws16c48gpio->lock, flags); 3589c26df9bSWilliam Breathitt Gray 3599c26df9bSWilliam Breathitt Gray return 0; 3609c26df9bSWilliam Breathitt Gray } 3619c26df9bSWilliam Breathitt Gray 36268903817SWilliam Breathitt Gray static const struct irq_chip ws16c48_irqchip = { 3639c26df9bSWilliam Breathitt Gray .name = "ws16c48", 3649c26df9bSWilliam Breathitt Gray .irq_ack = ws16c48_irq_ack, 3659c26df9bSWilliam Breathitt Gray .irq_mask = ws16c48_irq_mask, 3669c26df9bSWilliam Breathitt Gray .irq_unmask = ws16c48_irq_unmask, 36768903817SWilliam Breathitt Gray .irq_set_type = ws16c48_irq_set_type, 36868903817SWilliam Breathitt Gray .flags = IRQCHIP_IMMUTABLE, 36968903817SWilliam Breathitt Gray GPIOCHIP_IRQ_RESOURCE_HELPERS, 3709c26df9bSWilliam Breathitt Gray }; 3719c26df9bSWilliam Breathitt Gray 3729c26df9bSWilliam Breathitt Gray static irqreturn_t ws16c48_irq_handler(int irq, void *dev_id) 3739c26df9bSWilliam Breathitt Gray { 3749c26df9bSWilliam Breathitt Gray struct ws16c48_gpio *const ws16c48gpio = dev_id; 3759c26df9bSWilliam Breathitt Gray struct gpio_chip *const chip = &ws16c48gpio->chip; 3762c05a0f2SWilliam Breathitt Gray struct ws16c48_reg __iomem *const reg = ws16c48gpio->reg; 3779c26df9bSWilliam Breathitt Gray unsigned long int_pending; 3789c26df9bSWilliam Breathitt Gray unsigned long port; 3799c26df9bSWilliam Breathitt Gray unsigned long int_id; 3809c26df9bSWilliam Breathitt Gray unsigned long gpio; 3819c26df9bSWilliam Breathitt Gray 3822c05a0f2SWilliam Breathitt Gray int_pending = ioread8(®->int_pending) & 0x7; 3839c26df9bSWilliam Breathitt Gray if (!int_pending) 3849c26df9bSWilliam Breathitt Gray return IRQ_NONE; 3859c26df9bSWilliam Breathitt Gray 3869c26df9bSWilliam Breathitt Gray /* loop until all pending interrupts are handled */ 3879c26df9bSWilliam Breathitt Gray do { 3889c26df9bSWilliam Breathitt Gray for_each_set_bit(port, &int_pending, 3) { 3892c05a0f2SWilliam Breathitt Gray int_id = ioread8(reg->pol_enab_int_id + port); 3909c26df9bSWilliam Breathitt Gray for_each_set_bit(gpio, &int_id, 8) 391dbd1c54fSMarc Zyngier generic_handle_domain_irq(chip->irq.domain, 392dbd1c54fSMarc Zyngier gpio + 8*port); 3939c26df9bSWilliam Breathitt Gray } 3949c26df9bSWilliam Breathitt Gray 3952c05a0f2SWilliam Breathitt Gray int_pending = ioread8(®->int_pending) & 0x7; 3969c26df9bSWilliam Breathitt Gray } while (int_pending); 3979c26df9bSWilliam Breathitt Gray 3989c26df9bSWilliam Breathitt Gray return IRQ_HANDLED; 3999c26df9bSWilliam Breathitt Gray } 4009c26df9bSWilliam Breathitt Gray 4015238f60fSWilliam Breathitt Gray #define WS16C48_NGPIO 48 4025238f60fSWilliam Breathitt Gray static const char *ws16c48_names[WS16C48_NGPIO] = { 4035238f60fSWilliam Breathitt Gray "Port 0 Bit 0", "Port 0 Bit 1", "Port 0 Bit 2", "Port 0 Bit 3", 4045238f60fSWilliam Breathitt Gray "Port 0 Bit 4", "Port 0 Bit 5", "Port 0 Bit 6", "Port 0 Bit 7", 4055238f60fSWilliam Breathitt Gray "Port 1 Bit 0", "Port 1 Bit 1", "Port 1 Bit 2", "Port 1 Bit 3", 4065238f60fSWilliam Breathitt Gray "Port 1 Bit 4", "Port 1 Bit 5", "Port 1 Bit 6", "Port 1 Bit 7", 4075238f60fSWilliam Breathitt Gray "Port 2 Bit 0", "Port 2 Bit 1", "Port 2 Bit 2", "Port 2 Bit 3", 4085238f60fSWilliam Breathitt Gray "Port 2 Bit 4", "Port 2 Bit 5", "Port 2 Bit 6", "Port 2 Bit 7", 4095238f60fSWilliam Breathitt Gray "Port 3 Bit 0", "Port 3 Bit 1", "Port 3 Bit 2", "Port 3 Bit 3", 4105238f60fSWilliam Breathitt Gray "Port 3 Bit 4", "Port 3 Bit 5", "Port 3 Bit 6", "Port 3 Bit 7", 4115238f60fSWilliam Breathitt Gray "Port 4 Bit 0", "Port 4 Bit 1", "Port 4 Bit 2", "Port 4 Bit 3", 4125238f60fSWilliam Breathitt Gray "Port 4 Bit 4", "Port 4 Bit 5", "Port 4 Bit 6", "Port 4 Bit 7", 4135238f60fSWilliam Breathitt Gray "Port 5 Bit 0", "Port 5 Bit 1", "Port 5 Bit 2", "Port 5 Bit 3", 4145238f60fSWilliam Breathitt Gray "Port 5 Bit 4", "Port 5 Bit 5", "Port 5 Bit 6", "Port 5 Bit 7" 4155238f60fSWilliam Breathitt Gray }; 4165238f60fSWilliam Breathitt Gray 417fceb7ab3SLinus Walleij static int ws16c48_irq_init_hw(struct gpio_chip *gc) 418fceb7ab3SLinus Walleij { 419fceb7ab3SLinus Walleij struct ws16c48_gpio *const ws16c48gpio = gpiochip_get_data(gc); 420fceb7ab3SLinus Walleij 4212c05a0f2SWilliam Breathitt Gray /* Select Register Page 2; Unlock all I/O ports */ 4222c05a0f2SWilliam Breathitt Gray iowrite8(0x80, &ws16c48gpio->reg->page_lock); 4232c05a0f2SWilliam Breathitt Gray 4242c05a0f2SWilliam Breathitt Gray /* Disable interrupts for all lines */ 4252c05a0f2SWilliam Breathitt Gray iowrite8(0, &ws16c48gpio->reg->pol_enab_int_id[0]); 4262c05a0f2SWilliam Breathitt Gray iowrite8(0, &ws16c48gpio->reg->pol_enab_int_id[1]); 4272c05a0f2SWilliam Breathitt Gray iowrite8(0, &ws16c48gpio->reg->pol_enab_int_id[2]); 4282c05a0f2SWilliam Breathitt Gray 4292c05a0f2SWilliam Breathitt Gray /* Select Register Page 3; Unlock all I/O ports */ 4302c05a0f2SWilliam Breathitt Gray iowrite8(0xC0, &ws16c48gpio->reg->page_lock); 431fceb7ab3SLinus Walleij 432fceb7ab3SLinus Walleij return 0; 433fceb7ab3SLinus Walleij } 434fceb7ab3SLinus Walleij 435cc736607SWilliam Breathitt Gray static int ws16c48_probe(struct device *dev, unsigned int id) 4369c26df9bSWilliam Breathitt Gray { 4379c26df9bSWilliam Breathitt Gray struct ws16c48_gpio *ws16c48gpio; 4389c26df9bSWilliam Breathitt Gray const char *const name = dev_name(dev); 439fceb7ab3SLinus Walleij struct gpio_irq_chip *girq; 4409c26df9bSWilliam Breathitt Gray int err; 4419c26df9bSWilliam Breathitt Gray 4429c26df9bSWilliam Breathitt Gray ws16c48gpio = devm_kzalloc(dev, sizeof(*ws16c48gpio), GFP_KERNEL); 4439c26df9bSWilliam Breathitt Gray if (!ws16c48gpio) 4449c26df9bSWilliam Breathitt Gray return -ENOMEM; 4459c26df9bSWilliam Breathitt Gray 446cc736607SWilliam Breathitt Gray if (!devm_request_region(dev, base[id], WS16C48_EXTENT, name)) { 447148ad68bSWilliam Breathitt Gray dev_err(dev, "Unable to lock port addresses (0x%X-0x%X)\n", 448cc736607SWilliam Breathitt Gray base[id], base[id] + WS16C48_EXTENT); 449148ad68bSWilliam Breathitt Gray return -EBUSY; 4509c26df9bSWilliam Breathitt Gray } 4519c26df9bSWilliam Breathitt Gray 4522c05a0f2SWilliam Breathitt Gray ws16c48gpio->reg = devm_ioport_map(dev, base[id], WS16C48_EXTENT); 4532c05a0f2SWilliam Breathitt Gray if (!ws16c48gpio->reg) 4545561a2b0SWilliam Breathitt Gray return -ENOMEM; 4555561a2b0SWilliam Breathitt Gray 4569c26df9bSWilliam Breathitt Gray ws16c48gpio->chip.label = name; 4579c26df9bSWilliam Breathitt Gray ws16c48gpio->chip.parent = dev; 4589c26df9bSWilliam Breathitt Gray ws16c48gpio->chip.owner = THIS_MODULE; 4599c26df9bSWilliam Breathitt Gray ws16c48gpio->chip.base = -1; 4605238f60fSWilliam Breathitt Gray ws16c48gpio->chip.ngpio = WS16C48_NGPIO; 4615238f60fSWilliam Breathitt Gray ws16c48gpio->chip.names = ws16c48_names; 4629c26df9bSWilliam Breathitt Gray ws16c48gpio->chip.get_direction = ws16c48_gpio_get_direction; 4639c26df9bSWilliam Breathitt Gray ws16c48gpio->chip.direction_input = ws16c48_gpio_direction_input; 4649c26df9bSWilliam Breathitt Gray ws16c48gpio->chip.direction_output = ws16c48_gpio_direction_output; 4659c26df9bSWilliam Breathitt Gray ws16c48gpio->chip.get = ws16c48_gpio_get; 466a8ff510dSWilliam Breathitt Gray ws16c48gpio->chip.get_multiple = ws16c48_gpio_get_multiple; 4679c26df9bSWilliam Breathitt Gray ws16c48gpio->chip.set = ws16c48_gpio_set; 46899c8ac95SWilliam Breathitt Gray ws16c48gpio->chip.set_multiple = ws16c48_gpio_set_multiple; 4699c26df9bSWilliam Breathitt Gray 470fceb7ab3SLinus Walleij girq = &ws16c48gpio->chip.irq; 47168903817SWilliam Breathitt Gray gpio_irq_chip_set_chip(girq, &ws16c48_irqchip); 472fceb7ab3SLinus Walleij /* This will let us handle the parent IRQ in the driver */ 473fceb7ab3SLinus Walleij girq->parent_handler = NULL; 474fceb7ab3SLinus Walleij girq->num_parents = 0; 475fceb7ab3SLinus Walleij girq->parents = NULL; 476fceb7ab3SLinus Walleij girq->default_type = IRQ_TYPE_NONE; 477fceb7ab3SLinus Walleij girq->handler = handle_edge_irq; 478fceb7ab3SLinus Walleij girq->init_hw = ws16c48_irq_init_hw; 479fceb7ab3SLinus Walleij 480a0a584f0SJulia Cartwright raw_spin_lock_init(&ws16c48gpio->lock); 4819c26df9bSWilliam Breathitt Gray 482b4cad1bcSWilliam Breathitt Gray err = devm_gpiochip_add_data(dev, &ws16c48gpio->chip, ws16c48gpio); 4839c26df9bSWilliam Breathitt Gray if (err) { 4849c26df9bSWilliam Breathitt Gray dev_err(dev, "GPIO registering failed (%d)\n", err); 485148ad68bSWilliam Breathitt Gray return err; 4869c26df9bSWilliam Breathitt Gray } 4879c26df9bSWilliam Breathitt Gray 488b4cad1bcSWilliam Breathitt Gray err = devm_request_irq(dev, irq[id], ws16c48_irq_handler, IRQF_SHARED, 489b4cad1bcSWilliam Breathitt Gray name, ws16c48gpio); 490b4cad1bcSWilliam Breathitt Gray if (err) { 491b4cad1bcSWilliam Breathitt Gray dev_err(dev, "IRQ handler registering failed (%d)\n", err); 492b4cad1bcSWilliam Breathitt Gray return err; 493b4cad1bcSWilliam Breathitt Gray } 4949c26df9bSWilliam Breathitt Gray 4959c26df9bSWilliam Breathitt Gray return 0; 4969c26df9bSWilliam Breathitt Gray } 4979c26df9bSWilliam Breathitt Gray 498cc736607SWilliam Breathitt Gray static struct isa_driver ws16c48_driver = { 499cc736607SWilliam Breathitt Gray .probe = ws16c48_probe, 5009c26df9bSWilliam Breathitt Gray .driver = { 5019c26df9bSWilliam Breathitt Gray .name = "ws16c48" 5029c26df9bSWilliam Breathitt Gray }, 5039c26df9bSWilliam Breathitt Gray }; 5049c26df9bSWilliam Breathitt Gray 505c95671a3SWilliam Breathitt Gray module_isa_driver_with_irq(ws16c48_driver, num_ws16c48, num_irq); 5069c26df9bSWilliam Breathitt Gray 5079c26df9bSWilliam Breathitt Gray MODULE_AUTHOR("William Breathitt Gray <vilhelm.gray@gmail.com>"); 5089c26df9bSWilliam Breathitt Gray MODULE_DESCRIPTION("WinSystems WS16C48 GPIO driver"); 50922aeddb5SWilliam Breathitt Gray MODULE_LICENSE("GPL v2"); 510