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 212c05a0f2SWilliam Breathitt Gray #define WS16C48_EXTENT 10 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]; 30*c95671a3SWilliam Breathitt Gray static unsigned int num_irq; 31*c95671a3SWilliam 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; 2692c05a0f2SWilliam Breathitt Gray port_state = ws16c48gpio->irq_mask >> (8 * port); 2709c26df9bSWilliam Breathitt Gray 2712c05a0f2SWilliam Breathitt Gray /* Select Register Page 2; Unlock all I/O ports */ 2722c05a0f2SWilliam Breathitt Gray iowrite8(0x80, &ws16c48gpio->reg->page_lock); 2732c05a0f2SWilliam Breathitt Gray 2742c05a0f2SWilliam Breathitt Gray /* Disable interrupt */ 2752c05a0f2SWilliam Breathitt Gray iowrite8(port_state, ws16c48gpio->reg->pol_enab_int_id + port); 2762c05a0f2SWilliam Breathitt Gray 2772c05a0f2SWilliam Breathitt Gray /* Select Register Page 3; Unlock all I/O ports */ 2782c05a0f2SWilliam Breathitt Gray iowrite8(0xC0, &ws16c48gpio->reg->page_lock); 2799c26df9bSWilliam Breathitt Gray 280a0a584f0SJulia Cartwright raw_spin_unlock_irqrestore(&ws16c48gpio->lock, flags); 2819c26df9bSWilliam Breathitt Gray } 2829c26df9bSWilliam Breathitt Gray 2839c26df9bSWilliam Breathitt Gray static void ws16c48_irq_unmask(struct irq_data *data) 2849c26df9bSWilliam Breathitt Gray { 2859c26df9bSWilliam Breathitt Gray struct gpio_chip *chip = irq_data_get_irq_chip_data(data); 2869c26df9bSWilliam Breathitt Gray struct ws16c48_gpio *const ws16c48gpio = gpiochip_get_data(chip); 2879c26df9bSWilliam Breathitt Gray const unsigned long offset = irqd_to_hwirq(data); 2889c26df9bSWilliam Breathitt Gray const unsigned long mask = BIT(offset); 2899c26df9bSWilliam Breathitt Gray const unsigned port = offset / 8; 2909c26df9bSWilliam Breathitt Gray unsigned long flags; 2912c05a0f2SWilliam Breathitt Gray unsigned long port_state; 2929c26df9bSWilliam Breathitt Gray 2939c26df9bSWilliam Breathitt Gray /* only the first 3 ports support interrupts */ 2949c26df9bSWilliam Breathitt Gray if (port > 2) 2959c26df9bSWilliam Breathitt Gray return; 2969c26df9bSWilliam Breathitt Gray 297a0a584f0SJulia Cartwright raw_spin_lock_irqsave(&ws16c48gpio->lock, flags); 2989c26df9bSWilliam Breathitt Gray 2999c26df9bSWilliam Breathitt Gray ws16c48gpio->irq_mask |= mask; 3002c05a0f2SWilliam Breathitt Gray port_state = ws16c48gpio->irq_mask >> (8 * port); 3019c26df9bSWilliam Breathitt Gray 3022c05a0f2SWilliam Breathitt Gray /* Select Register Page 2; Unlock all I/O ports */ 3032c05a0f2SWilliam Breathitt Gray iowrite8(0x80, &ws16c48gpio->reg->page_lock); 3042c05a0f2SWilliam Breathitt Gray 3052c05a0f2SWilliam Breathitt Gray /* Enable interrupt */ 3062c05a0f2SWilliam Breathitt Gray iowrite8(port_state, ws16c48gpio->reg->pol_enab_int_id + port); 3072c05a0f2SWilliam Breathitt Gray 3082c05a0f2SWilliam Breathitt Gray /* Select Register Page 3; Unlock all I/O ports */ 3092c05a0f2SWilliam Breathitt Gray iowrite8(0xC0, &ws16c48gpio->reg->page_lock); 3109c26df9bSWilliam Breathitt Gray 311a0a584f0SJulia Cartwright raw_spin_unlock_irqrestore(&ws16c48gpio->lock, flags); 3129c26df9bSWilliam Breathitt Gray } 3139c26df9bSWilliam Breathitt Gray 3149c26df9bSWilliam Breathitt Gray static int ws16c48_irq_set_type(struct irq_data *data, unsigned flow_type) 3159c26df9bSWilliam Breathitt Gray { 3169c26df9bSWilliam Breathitt Gray struct gpio_chip *chip = irq_data_get_irq_chip_data(data); 3179c26df9bSWilliam Breathitt Gray struct ws16c48_gpio *const ws16c48gpio = gpiochip_get_data(chip); 3189c26df9bSWilliam Breathitt Gray const unsigned long offset = irqd_to_hwirq(data); 3199c26df9bSWilliam Breathitt Gray const unsigned long mask = BIT(offset); 3209c26df9bSWilliam Breathitt Gray const unsigned port = offset / 8; 3219c26df9bSWilliam Breathitt Gray unsigned long flags; 3222c05a0f2SWilliam Breathitt Gray unsigned long port_state; 3239c26df9bSWilliam Breathitt Gray 3249c26df9bSWilliam Breathitt Gray /* only the first 3 ports support interrupts */ 3259c26df9bSWilliam Breathitt Gray if (port > 2) 3269c26df9bSWilliam Breathitt Gray return -EINVAL; 3279c26df9bSWilliam Breathitt Gray 328a0a584f0SJulia Cartwright raw_spin_lock_irqsave(&ws16c48gpio->lock, flags); 3299c26df9bSWilliam Breathitt Gray 3309c26df9bSWilliam Breathitt Gray switch (flow_type) { 3319c26df9bSWilliam Breathitt Gray case IRQ_TYPE_NONE: 3329c26df9bSWilliam Breathitt Gray break; 3339c26df9bSWilliam Breathitt Gray case IRQ_TYPE_EDGE_RISING: 3349c26df9bSWilliam Breathitt Gray ws16c48gpio->flow_mask |= mask; 3359c26df9bSWilliam Breathitt Gray break; 3369c26df9bSWilliam Breathitt Gray case IRQ_TYPE_EDGE_FALLING: 3379c26df9bSWilliam Breathitt Gray ws16c48gpio->flow_mask &= ~mask; 3389c26df9bSWilliam Breathitt Gray break; 3399c26df9bSWilliam Breathitt Gray default: 340a0a584f0SJulia Cartwright raw_spin_unlock_irqrestore(&ws16c48gpio->lock, flags); 3419c26df9bSWilliam Breathitt Gray return -EINVAL; 3429c26df9bSWilliam Breathitt Gray } 3439c26df9bSWilliam Breathitt Gray 3442c05a0f2SWilliam Breathitt Gray port_state = ws16c48gpio->flow_mask >> (8 * port); 3452c05a0f2SWilliam Breathitt Gray 3462c05a0f2SWilliam Breathitt Gray /* Select Register Page 1; Unlock all I/O ports */ 3472c05a0f2SWilliam Breathitt Gray iowrite8(0x40, &ws16c48gpio->reg->page_lock); 3482c05a0f2SWilliam Breathitt Gray 3492c05a0f2SWilliam Breathitt Gray /* Set interrupt polarity */ 3502c05a0f2SWilliam Breathitt Gray iowrite8(port_state, ws16c48gpio->reg->pol_enab_int_id + port); 3512c05a0f2SWilliam Breathitt Gray 3522c05a0f2SWilliam Breathitt Gray /* Select Register Page 3; Unlock all I/O ports */ 3532c05a0f2SWilliam Breathitt Gray iowrite8(0xC0, &ws16c48gpio->reg->page_lock); 3549c26df9bSWilliam Breathitt Gray 355a0a584f0SJulia Cartwright raw_spin_unlock_irqrestore(&ws16c48gpio->lock, flags); 3569c26df9bSWilliam Breathitt Gray 3579c26df9bSWilliam Breathitt Gray return 0; 3589c26df9bSWilliam Breathitt Gray } 3599c26df9bSWilliam Breathitt Gray 3609c26df9bSWilliam Breathitt Gray static struct irq_chip ws16c48_irqchip = { 3619c26df9bSWilliam Breathitt Gray .name = "ws16c48", 3629c26df9bSWilliam Breathitt Gray .irq_ack = ws16c48_irq_ack, 3639c26df9bSWilliam Breathitt Gray .irq_mask = ws16c48_irq_mask, 3649c26df9bSWilliam Breathitt Gray .irq_unmask = ws16c48_irq_unmask, 3659c26df9bSWilliam Breathitt Gray .irq_set_type = ws16c48_irq_set_type 3669c26df9bSWilliam Breathitt Gray }; 3679c26df9bSWilliam Breathitt Gray 3689c26df9bSWilliam Breathitt Gray static irqreturn_t ws16c48_irq_handler(int irq, void *dev_id) 3699c26df9bSWilliam Breathitt Gray { 3709c26df9bSWilliam Breathitt Gray struct ws16c48_gpio *const ws16c48gpio = dev_id; 3719c26df9bSWilliam Breathitt Gray struct gpio_chip *const chip = &ws16c48gpio->chip; 3722c05a0f2SWilliam Breathitt Gray struct ws16c48_reg __iomem *const reg = ws16c48gpio->reg; 3739c26df9bSWilliam Breathitt Gray unsigned long int_pending; 3749c26df9bSWilliam Breathitt Gray unsigned long port; 3759c26df9bSWilliam Breathitt Gray unsigned long int_id; 3769c26df9bSWilliam Breathitt Gray unsigned long gpio; 3779c26df9bSWilliam Breathitt Gray 3782c05a0f2SWilliam Breathitt Gray int_pending = ioread8(®->int_pending) & 0x7; 3799c26df9bSWilliam Breathitt Gray if (!int_pending) 3809c26df9bSWilliam Breathitt Gray return IRQ_NONE; 3819c26df9bSWilliam Breathitt Gray 3829c26df9bSWilliam Breathitt Gray /* loop until all pending interrupts are handled */ 3839c26df9bSWilliam Breathitt Gray do { 3849c26df9bSWilliam Breathitt Gray for_each_set_bit(port, &int_pending, 3) { 3852c05a0f2SWilliam Breathitt Gray int_id = ioread8(reg->pol_enab_int_id + port); 3869c26df9bSWilliam Breathitt Gray for_each_set_bit(gpio, &int_id, 8) 387dbd1c54fSMarc Zyngier generic_handle_domain_irq(chip->irq.domain, 388dbd1c54fSMarc Zyngier gpio + 8*port); 3899c26df9bSWilliam Breathitt Gray } 3909c26df9bSWilliam Breathitt Gray 3912c05a0f2SWilliam Breathitt Gray int_pending = ioread8(®->int_pending) & 0x7; 3929c26df9bSWilliam Breathitt Gray } while (int_pending); 3939c26df9bSWilliam Breathitt Gray 3949c26df9bSWilliam Breathitt Gray return IRQ_HANDLED; 3959c26df9bSWilliam Breathitt Gray } 3969c26df9bSWilliam Breathitt Gray 3975238f60fSWilliam Breathitt Gray #define WS16C48_NGPIO 48 3985238f60fSWilliam Breathitt Gray static const char *ws16c48_names[WS16C48_NGPIO] = { 3995238f60fSWilliam Breathitt Gray "Port 0 Bit 0", "Port 0 Bit 1", "Port 0 Bit 2", "Port 0 Bit 3", 4005238f60fSWilliam Breathitt Gray "Port 0 Bit 4", "Port 0 Bit 5", "Port 0 Bit 6", "Port 0 Bit 7", 4015238f60fSWilliam Breathitt Gray "Port 1 Bit 0", "Port 1 Bit 1", "Port 1 Bit 2", "Port 1 Bit 3", 4025238f60fSWilliam Breathitt Gray "Port 1 Bit 4", "Port 1 Bit 5", "Port 1 Bit 6", "Port 1 Bit 7", 4035238f60fSWilliam Breathitt Gray "Port 2 Bit 0", "Port 2 Bit 1", "Port 2 Bit 2", "Port 2 Bit 3", 4045238f60fSWilliam Breathitt Gray "Port 2 Bit 4", "Port 2 Bit 5", "Port 2 Bit 6", "Port 2 Bit 7", 4055238f60fSWilliam Breathitt Gray "Port 3 Bit 0", "Port 3 Bit 1", "Port 3 Bit 2", "Port 3 Bit 3", 4065238f60fSWilliam Breathitt Gray "Port 3 Bit 4", "Port 3 Bit 5", "Port 3 Bit 6", "Port 3 Bit 7", 4075238f60fSWilliam Breathitt Gray "Port 4 Bit 0", "Port 4 Bit 1", "Port 4 Bit 2", "Port 4 Bit 3", 4085238f60fSWilliam Breathitt Gray "Port 4 Bit 4", "Port 4 Bit 5", "Port 4 Bit 6", "Port 4 Bit 7", 4095238f60fSWilliam Breathitt Gray "Port 5 Bit 0", "Port 5 Bit 1", "Port 5 Bit 2", "Port 5 Bit 3", 4105238f60fSWilliam Breathitt Gray "Port 5 Bit 4", "Port 5 Bit 5", "Port 5 Bit 6", "Port 5 Bit 7" 4115238f60fSWilliam Breathitt Gray }; 4125238f60fSWilliam Breathitt Gray 413fceb7ab3SLinus Walleij static int ws16c48_irq_init_hw(struct gpio_chip *gc) 414fceb7ab3SLinus Walleij { 415fceb7ab3SLinus Walleij struct ws16c48_gpio *const ws16c48gpio = gpiochip_get_data(gc); 416fceb7ab3SLinus Walleij 4172c05a0f2SWilliam Breathitt Gray /* Select Register Page 2; Unlock all I/O ports */ 4182c05a0f2SWilliam Breathitt Gray iowrite8(0x80, &ws16c48gpio->reg->page_lock); 4192c05a0f2SWilliam Breathitt Gray 4202c05a0f2SWilliam Breathitt Gray /* Disable interrupts for all lines */ 4212c05a0f2SWilliam Breathitt Gray iowrite8(0, &ws16c48gpio->reg->pol_enab_int_id[0]); 4222c05a0f2SWilliam Breathitt Gray iowrite8(0, &ws16c48gpio->reg->pol_enab_int_id[1]); 4232c05a0f2SWilliam Breathitt Gray iowrite8(0, &ws16c48gpio->reg->pol_enab_int_id[2]); 4242c05a0f2SWilliam Breathitt Gray 4252c05a0f2SWilliam Breathitt Gray /* Select Register Page 3; Unlock all I/O ports */ 4262c05a0f2SWilliam Breathitt Gray iowrite8(0xC0, &ws16c48gpio->reg->page_lock); 427fceb7ab3SLinus Walleij 428fceb7ab3SLinus Walleij return 0; 429fceb7ab3SLinus Walleij } 430fceb7ab3SLinus Walleij 431cc736607SWilliam Breathitt Gray static int ws16c48_probe(struct device *dev, unsigned int id) 4329c26df9bSWilliam Breathitt Gray { 4339c26df9bSWilliam Breathitt Gray struct ws16c48_gpio *ws16c48gpio; 4349c26df9bSWilliam Breathitt Gray const char *const name = dev_name(dev); 435fceb7ab3SLinus Walleij struct gpio_irq_chip *girq; 4369c26df9bSWilliam Breathitt Gray int err; 4379c26df9bSWilliam Breathitt Gray 4389c26df9bSWilliam Breathitt Gray ws16c48gpio = devm_kzalloc(dev, sizeof(*ws16c48gpio), GFP_KERNEL); 4399c26df9bSWilliam Breathitt Gray if (!ws16c48gpio) 4409c26df9bSWilliam Breathitt Gray return -ENOMEM; 4419c26df9bSWilliam Breathitt Gray 442cc736607SWilliam Breathitt Gray if (!devm_request_region(dev, base[id], WS16C48_EXTENT, name)) { 443148ad68bSWilliam Breathitt Gray dev_err(dev, "Unable to lock port addresses (0x%X-0x%X)\n", 444cc736607SWilliam Breathitt Gray base[id], base[id] + WS16C48_EXTENT); 445148ad68bSWilliam Breathitt Gray return -EBUSY; 4469c26df9bSWilliam Breathitt Gray } 4479c26df9bSWilliam Breathitt Gray 4482c05a0f2SWilliam Breathitt Gray ws16c48gpio->reg = devm_ioport_map(dev, base[id], WS16C48_EXTENT); 4492c05a0f2SWilliam Breathitt Gray if (!ws16c48gpio->reg) 4505561a2b0SWilliam Breathitt Gray return -ENOMEM; 4515561a2b0SWilliam Breathitt Gray 4529c26df9bSWilliam Breathitt Gray ws16c48gpio->chip.label = name; 4539c26df9bSWilliam Breathitt Gray ws16c48gpio->chip.parent = dev; 4549c26df9bSWilliam Breathitt Gray ws16c48gpio->chip.owner = THIS_MODULE; 4559c26df9bSWilliam Breathitt Gray ws16c48gpio->chip.base = -1; 4565238f60fSWilliam Breathitt Gray ws16c48gpio->chip.ngpio = WS16C48_NGPIO; 4575238f60fSWilliam Breathitt Gray ws16c48gpio->chip.names = ws16c48_names; 4589c26df9bSWilliam Breathitt Gray ws16c48gpio->chip.get_direction = ws16c48_gpio_get_direction; 4599c26df9bSWilliam Breathitt Gray ws16c48gpio->chip.direction_input = ws16c48_gpio_direction_input; 4609c26df9bSWilliam Breathitt Gray ws16c48gpio->chip.direction_output = ws16c48_gpio_direction_output; 4619c26df9bSWilliam Breathitt Gray ws16c48gpio->chip.get = ws16c48_gpio_get; 462a8ff510dSWilliam Breathitt Gray ws16c48gpio->chip.get_multiple = ws16c48_gpio_get_multiple; 4639c26df9bSWilliam Breathitt Gray ws16c48gpio->chip.set = ws16c48_gpio_set; 46499c8ac95SWilliam Breathitt Gray ws16c48gpio->chip.set_multiple = ws16c48_gpio_set_multiple; 4659c26df9bSWilliam Breathitt Gray 466fceb7ab3SLinus Walleij girq = &ws16c48gpio->chip.irq; 467fceb7ab3SLinus Walleij girq->chip = &ws16c48_irqchip; 468fceb7ab3SLinus Walleij /* This will let us handle the parent IRQ in the driver */ 469fceb7ab3SLinus Walleij girq->parent_handler = NULL; 470fceb7ab3SLinus Walleij girq->num_parents = 0; 471fceb7ab3SLinus Walleij girq->parents = NULL; 472fceb7ab3SLinus Walleij girq->default_type = IRQ_TYPE_NONE; 473fceb7ab3SLinus Walleij girq->handler = handle_edge_irq; 474fceb7ab3SLinus Walleij girq->init_hw = ws16c48_irq_init_hw; 475fceb7ab3SLinus Walleij 476a0a584f0SJulia Cartwright raw_spin_lock_init(&ws16c48gpio->lock); 4779c26df9bSWilliam Breathitt Gray 478b4cad1bcSWilliam Breathitt Gray err = devm_gpiochip_add_data(dev, &ws16c48gpio->chip, ws16c48gpio); 4799c26df9bSWilliam Breathitt Gray if (err) { 4809c26df9bSWilliam Breathitt Gray dev_err(dev, "GPIO registering failed (%d)\n", err); 481148ad68bSWilliam Breathitt Gray return err; 4829c26df9bSWilliam Breathitt Gray } 4839c26df9bSWilliam Breathitt Gray 484b4cad1bcSWilliam Breathitt Gray err = devm_request_irq(dev, irq[id], ws16c48_irq_handler, IRQF_SHARED, 485b4cad1bcSWilliam Breathitt Gray name, ws16c48gpio); 486b4cad1bcSWilliam Breathitt Gray if (err) { 487b4cad1bcSWilliam Breathitt Gray dev_err(dev, "IRQ handler registering failed (%d)\n", err); 488b4cad1bcSWilliam Breathitt Gray return err; 489b4cad1bcSWilliam Breathitt Gray } 4909c26df9bSWilliam Breathitt Gray 4919c26df9bSWilliam Breathitt Gray return 0; 4929c26df9bSWilliam Breathitt Gray } 4939c26df9bSWilliam Breathitt Gray 494cc736607SWilliam Breathitt Gray static struct isa_driver ws16c48_driver = { 495cc736607SWilliam Breathitt Gray .probe = ws16c48_probe, 4969c26df9bSWilliam Breathitt Gray .driver = { 4979c26df9bSWilliam Breathitt Gray .name = "ws16c48" 4989c26df9bSWilliam Breathitt Gray }, 4999c26df9bSWilliam Breathitt Gray }; 5009c26df9bSWilliam Breathitt Gray 501*c95671a3SWilliam Breathitt Gray module_isa_driver_with_irq(ws16c48_driver, num_ws16c48, num_irq); 5029c26df9bSWilliam Breathitt Gray 5039c26df9bSWilliam Breathitt Gray MODULE_AUTHOR("William Breathitt Gray <vilhelm.gray@gmail.com>"); 5049c26df9bSWilliam Breathitt Gray MODULE_DESCRIPTION("WinSystems WS16C48 GPIO driver"); 50522aeddb5SWilliam Breathitt Gray MODULE_LICENSE("GPL v2"); 506