162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * Copyright (C) ST-Ericsson SA 2010 462306a36Sopenharmony_ci * 562306a36Sopenharmony_ci * Author: Rabin Vincent <rabin.vincent@stericsson.com> for ST-Ericsson 662306a36Sopenharmony_ci */ 762306a36Sopenharmony_ci 862306a36Sopenharmony_ci#include <linux/init.h> 962306a36Sopenharmony_ci#include <linux/platform_device.h> 1062306a36Sopenharmony_ci#include <linux/slab.h> 1162306a36Sopenharmony_ci#include <linux/gpio/driver.h> 1262306a36Sopenharmony_ci#include <linux/interrupt.h> 1362306a36Sopenharmony_ci#include <linux/of.h> 1462306a36Sopenharmony_ci#include <linux/mfd/stmpe.h> 1562306a36Sopenharmony_ci#include <linux/seq_file.h> 1662306a36Sopenharmony_ci#include <linux/bitops.h> 1762306a36Sopenharmony_ci 1862306a36Sopenharmony_ci/* 1962306a36Sopenharmony_ci * These registers are modified under the irq bus lock and cached to avoid 2062306a36Sopenharmony_ci * unnecessary writes in bus_sync_unlock. 2162306a36Sopenharmony_ci */ 2262306a36Sopenharmony_cienum { REG_RE, REG_FE, REG_IE }; 2362306a36Sopenharmony_ci 2462306a36Sopenharmony_cienum { LSB, CSB, MSB }; 2562306a36Sopenharmony_ci 2662306a36Sopenharmony_ci#define CACHE_NR_REGS 3 2762306a36Sopenharmony_ci/* No variant has more than 24 GPIOs */ 2862306a36Sopenharmony_ci#define CACHE_NR_BANKS (24 / 8) 2962306a36Sopenharmony_ci 3062306a36Sopenharmony_cistruct stmpe_gpio { 3162306a36Sopenharmony_ci struct gpio_chip chip; 3262306a36Sopenharmony_ci struct stmpe *stmpe; 3362306a36Sopenharmony_ci struct device *dev; 3462306a36Sopenharmony_ci struct mutex irq_lock; 3562306a36Sopenharmony_ci u32 norequest_mask; 3662306a36Sopenharmony_ci /* Caches of interrupt control registers for bus_lock */ 3762306a36Sopenharmony_ci u8 regs[CACHE_NR_REGS][CACHE_NR_BANKS]; 3862306a36Sopenharmony_ci u8 oldregs[CACHE_NR_REGS][CACHE_NR_BANKS]; 3962306a36Sopenharmony_ci}; 4062306a36Sopenharmony_ci 4162306a36Sopenharmony_cistatic int stmpe_gpio_get(struct gpio_chip *chip, unsigned offset) 4262306a36Sopenharmony_ci{ 4362306a36Sopenharmony_ci struct stmpe_gpio *stmpe_gpio = gpiochip_get_data(chip); 4462306a36Sopenharmony_ci struct stmpe *stmpe = stmpe_gpio->stmpe; 4562306a36Sopenharmony_ci u8 reg = stmpe->regs[STMPE_IDX_GPMR_LSB + (offset / 8)]; 4662306a36Sopenharmony_ci u8 mask = BIT(offset % 8); 4762306a36Sopenharmony_ci int ret; 4862306a36Sopenharmony_ci 4962306a36Sopenharmony_ci ret = stmpe_reg_read(stmpe, reg); 5062306a36Sopenharmony_ci if (ret < 0) 5162306a36Sopenharmony_ci return ret; 5262306a36Sopenharmony_ci 5362306a36Sopenharmony_ci return !!(ret & mask); 5462306a36Sopenharmony_ci} 5562306a36Sopenharmony_ci 5662306a36Sopenharmony_cistatic void stmpe_gpio_set(struct gpio_chip *chip, unsigned offset, int val) 5762306a36Sopenharmony_ci{ 5862306a36Sopenharmony_ci struct stmpe_gpio *stmpe_gpio = gpiochip_get_data(chip); 5962306a36Sopenharmony_ci struct stmpe *stmpe = stmpe_gpio->stmpe; 6062306a36Sopenharmony_ci int which = val ? STMPE_IDX_GPSR_LSB : STMPE_IDX_GPCR_LSB; 6162306a36Sopenharmony_ci u8 reg = stmpe->regs[which + (offset / 8)]; 6262306a36Sopenharmony_ci u8 mask = BIT(offset % 8); 6362306a36Sopenharmony_ci 6462306a36Sopenharmony_ci /* 6562306a36Sopenharmony_ci * Some variants have single register for gpio set/clear functionality. 6662306a36Sopenharmony_ci * For them we need to write 0 to clear and 1 to set. 6762306a36Sopenharmony_ci */ 6862306a36Sopenharmony_ci if (stmpe->regs[STMPE_IDX_GPSR_LSB] == stmpe->regs[STMPE_IDX_GPCR_LSB]) 6962306a36Sopenharmony_ci stmpe_set_bits(stmpe, reg, mask, val ? mask : 0); 7062306a36Sopenharmony_ci else 7162306a36Sopenharmony_ci stmpe_reg_write(stmpe, reg, mask); 7262306a36Sopenharmony_ci} 7362306a36Sopenharmony_ci 7462306a36Sopenharmony_cistatic int stmpe_gpio_get_direction(struct gpio_chip *chip, 7562306a36Sopenharmony_ci unsigned offset) 7662306a36Sopenharmony_ci{ 7762306a36Sopenharmony_ci struct stmpe_gpio *stmpe_gpio = gpiochip_get_data(chip); 7862306a36Sopenharmony_ci struct stmpe *stmpe = stmpe_gpio->stmpe; 7962306a36Sopenharmony_ci u8 reg = stmpe->regs[STMPE_IDX_GPDR_LSB] - (offset / 8); 8062306a36Sopenharmony_ci u8 mask = BIT(offset % 8); 8162306a36Sopenharmony_ci int ret; 8262306a36Sopenharmony_ci 8362306a36Sopenharmony_ci ret = stmpe_reg_read(stmpe, reg); 8462306a36Sopenharmony_ci if (ret < 0) 8562306a36Sopenharmony_ci return ret; 8662306a36Sopenharmony_ci 8762306a36Sopenharmony_ci if (ret & mask) 8862306a36Sopenharmony_ci return GPIO_LINE_DIRECTION_OUT; 8962306a36Sopenharmony_ci 9062306a36Sopenharmony_ci return GPIO_LINE_DIRECTION_IN; 9162306a36Sopenharmony_ci} 9262306a36Sopenharmony_ci 9362306a36Sopenharmony_cistatic int stmpe_gpio_direction_output(struct gpio_chip *chip, 9462306a36Sopenharmony_ci unsigned offset, int val) 9562306a36Sopenharmony_ci{ 9662306a36Sopenharmony_ci struct stmpe_gpio *stmpe_gpio = gpiochip_get_data(chip); 9762306a36Sopenharmony_ci struct stmpe *stmpe = stmpe_gpio->stmpe; 9862306a36Sopenharmony_ci u8 reg = stmpe->regs[STMPE_IDX_GPDR_LSB + (offset / 8)]; 9962306a36Sopenharmony_ci u8 mask = BIT(offset % 8); 10062306a36Sopenharmony_ci 10162306a36Sopenharmony_ci stmpe_gpio_set(chip, offset, val); 10262306a36Sopenharmony_ci 10362306a36Sopenharmony_ci return stmpe_set_bits(stmpe, reg, mask, mask); 10462306a36Sopenharmony_ci} 10562306a36Sopenharmony_ci 10662306a36Sopenharmony_cistatic int stmpe_gpio_direction_input(struct gpio_chip *chip, 10762306a36Sopenharmony_ci unsigned offset) 10862306a36Sopenharmony_ci{ 10962306a36Sopenharmony_ci struct stmpe_gpio *stmpe_gpio = gpiochip_get_data(chip); 11062306a36Sopenharmony_ci struct stmpe *stmpe = stmpe_gpio->stmpe; 11162306a36Sopenharmony_ci u8 reg = stmpe->regs[STMPE_IDX_GPDR_LSB + (offset / 8)]; 11262306a36Sopenharmony_ci u8 mask = BIT(offset % 8); 11362306a36Sopenharmony_ci 11462306a36Sopenharmony_ci return stmpe_set_bits(stmpe, reg, mask, 0); 11562306a36Sopenharmony_ci} 11662306a36Sopenharmony_ci 11762306a36Sopenharmony_cistatic int stmpe_gpio_request(struct gpio_chip *chip, unsigned offset) 11862306a36Sopenharmony_ci{ 11962306a36Sopenharmony_ci struct stmpe_gpio *stmpe_gpio = gpiochip_get_data(chip); 12062306a36Sopenharmony_ci struct stmpe *stmpe = stmpe_gpio->stmpe; 12162306a36Sopenharmony_ci 12262306a36Sopenharmony_ci if (stmpe_gpio->norequest_mask & BIT(offset)) 12362306a36Sopenharmony_ci return -EINVAL; 12462306a36Sopenharmony_ci 12562306a36Sopenharmony_ci return stmpe_set_altfunc(stmpe, BIT(offset), STMPE_BLOCK_GPIO); 12662306a36Sopenharmony_ci} 12762306a36Sopenharmony_ci 12862306a36Sopenharmony_cistatic const struct gpio_chip template_chip = { 12962306a36Sopenharmony_ci .label = "stmpe", 13062306a36Sopenharmony_ci .owner = THIS_MODULE, 13162306a36Sopenharmony_ci .get_direction = stmpe_gpio_get_direction, 13262306a36Sopenharmony_ci .direction_input = stmpe_gpio_direction_input, 13362306a36Sopenharmony_ci .get = stmpe_gpio_get, 13462306a36Sopenharmony_ci .direction_output = stmpe_gpio_direction_output, 13562306a36Sopenharmony_ci .set = stmpe_gpio_set, 13662306a36Sopenharmony_ci .request = stmpe_gpio_request, 13762306a36Sopenharmony_ci .can_sleep = true, 13862306a36Sopenharmony_ci}; 13962306a36Sopenharmony_ci 14062306a36Sopenharmony_cistatic int stmpe_gpio_irq_set_type(struct irq_data *d, unsigned int type) 14162306a36Sopenharmony_ci{ 14262306a36Sopenharmony_ci struct gpio_chip *gc = irq_data_get_irq_chip_data(d); 14362306a36Sopenharmony_ci struct stmpe_gpio *stmpe_gpio = gpiochip_get_data(gc); 14462306a36Sopenharmony_ci int offset = d->hwirq; 14562306a36Sopenharmony_ci int regoffset = offset / 8; 14662306a36Sopenharmony_ci int mask = BIT(offset % 8); 14762306a36Sopenharmony_ci 14862306a36Sopenharmony_ci if (type & IRQ_TYPE_LEVEL_LOW || type & IRQ_TYPE_LEVEL_HIGH) 14962306a36Sopenharmony_ci return -EINVAL; 15062306a36Sopenharmony_ci 15162306a36Sopenharmony_ci /* STMPE801 and STMPE 1600 don't have RE and FE registers */ 15262306a36Sopenharmony_ci if (stmpe_gpio->stmpe->partnum == STMPE801 || 15362306a36Sopenharmony_ci stmpe_gpio->stmpe->partnum == STMPE1600) 15462306a36Sopenharmony_ci return 0; 15562306a36Sopenharmony_ci 15662306a36Sopenharmony_ci if (type & IRQ_TYPE_EDGE_RISING) 15762306a36Sopenharmony_ci stmpe_gpio->regs[REG_RE][regoffset] |= mask; 15862306a36Sopenharmony_ci else 15962306a36Sopenharmony_ci stmpe_gpio->regs[REG_RE][regoffset] &= ~mask; 16062306a36Sopenharmony_ci 16162306a36Sopenharmony_ci if (type & IRQ_TYPE_EDGE_FALLING) 16262306a36Sopenharmony_ci stmpe_gpio->regs[REG_FE][regoffset] |= mask; 16362306a36Sopenharmony_ci else 16462306a36Sopenharmony_ci stmpe_gpio->regs[REG_FE][regoffset] &= ~mask; 16562306a36Sopenharmony_ci 16662306a36Sopenharmony_ci return 0; 16762306a36Sopenharmony_ci} 16862306a36Sopenharmony_ci 16962306a36Sopenharmony_cistatic void stmpe_gpio_irq_lock(struct irq_data *d) 17062306a36Sopenharmony_ci{ 17162306a36Sopenharmony_ci struct gpio_chip *gc = irq_data_get_irq_chip_data(d); 17262306a36Sopenharmony_ci struct stmpe_gpio *stmpe_gpio = gpiochip_get_data(gc); 17362306a36Sopenharmony_ci 17462306a36Sopenharmony_ci mutex_lock(&stmpe_gpio->irq_lock); 17562306a36Sopenharmony_ci} 17662306a36Sopenharmony_ci 17762306a36Sopenharmony_cistatic void stmpe_gpio_irq_sync_unlock(struct irq_data *d) 17862306a36Sopenharmony_ci{ 17962306a36Sopenharmony_ci struct gpio_chip *gc = irq_data_get_irq_chip_data(d); 18062306a36Sopenharmony_ci struct stmpe_gpio *stmpe_gpio = gpiochip_get_data(gc); 18162306a36Sopenharmony_ci struct stmpe *stmpe = stmpe_gpio->stmpe; 18262306a36Sopenharmony_ci int num_banks = DIV_ROUND_UP(stmpe->num_gpios, 8); 18362306a36Sopenharmony_ci static const u8 regmap[CACHE_NR_REGS][CACHE_NR_BANKS] = { 18462306a36Sopenharmony_ci [REG_RE][LSB] = STMPE_IDX_GPRER_LSB, 18562306a36Sopenharmony_ci [REG_RE][CSB] = STMPE_IDX_GPRER_CSB, 18662306a36Sopenharmony_ci [REG_RE][MSB] = STMPE_IDX_GPRER_MSB, 18762306a36Sopenharmony_ci [REG_FE][LSB] = STMPE_IDX_GPFER_LSB, 18862306a36Sopenharmony_ci [REG_FE][CSB] = STMPE_IDX_GPFER_CSB, 18962306a36Sopenharmony_ci [REG_FE][MSB] = STMPE_IDX_GPFER_MSB, 19062306a36Sopenharmony_ci [REG_IE][LSB] = STMPE_IDX_IEGPIOR_LSB, 19162306a36Sopenharmony_ci [REG_IE][CSB] = STMPE_IDX_IEGPIOR_CSB, 19262306a36Sopenharmony_ci [REG_IE][MSB] = STMPE_IDX_IEGPIOR_MSB, 19362306a36Sopenharmony_ci }; 19462306a36Sopenharmony_ci int i, j; 19562306a36Sopenharmony_ci 19662306a36Sopenharmony_ci /* 19762306a36Sopenharmony_ci * STMPE1600: to be able to get IRQ from pins, 19862306a36Sopenharmony_ci * a read must be done on GPMR register, or a write in 19962306a36Sopenharmony_ci * GPSR or GPCR registers 20062306a36Sopenharmony_ci */ 20162306a36Sopenharmony_ci if (stmpe->partnum == STMPE1600) { 20262306a36Sopenharmony_ci stmpe_reg_read(stmpe, stmpe->regs[STMPE_IDX_GPMR_LSB]); 20362306a36Sopenharmony_ci stmpe_reg_read(stmpe, stmpe->regs[STMPE_IDX_GPMR_CSB]); 20462306a36Sopenharmony_ci } 20562306a36Sopenharmony_ci 20662306a36Sopenharmony_ci for (i = 0; i < CACHE_NR_REGS; i++) { 20762306a36Sopenharmony_ci /* STMPE801 and STMPE1600 don't have RE and FE registers */ 20862306a36Sopenharmony_ci if ((stmpe->partnum == STMPE801 || 20962306a36Sopenharmony_ci stmpe->partnum == STMPE1600) && 21062306a36Sopenharmony_ci (i != REG_IE)) 21162306a36Sopenharmony_ci continue; 21262306a36Sopenharmony_ci 21362306a36Sopenharmony_ci for (j = 0; j < num_banks; j++) { 21462306a36Sopenharmony_ci u8 old = stmpe_gpio->oldregs[i][j]; 21562306a36Sopenharmony_ci u8 new = stmpe_gpio->regs[i][j]; 21662306a36Sopenharmony_ci 21762306a36Sopenharmony_ci if (new == old) 21862306a36Sopenharmony_ci continue; 21962306a36Sopenharmony_ci 22062306a36Sopenharmony_ci stmpe_gpio->oldregs[i][j] = new; 22162306a36Sopenharmony_ci stmpe_reg_write(stmpe, stmpe->regs[regmap[i][j]], new); 22262306a36Sopenharmony_ci } 22362306a36Sopenharmony_ci } 22462306a36Sopenharmony_ci 22562306a36Sopenharmony_ci mutex_unlock(&stmpe_gpio->irq_lock); 22662306a36Sopenharmony_ci} 22762306a36Sopenharmony_ci 22862306a36Sopenharmony_cistatic void stmpe_gpio_irq_mask(struct irq_data *d) 22962306a36Sopenharmony_ci{ 23062306a36Sopenharmony_ci struct gpio_chip *gc = irq_data_get_irq_chip_data(d); 23162306a36Sopenharmony_ci struct stmpe_gpio *stmpe_gpio = gpiochip_get_data(gc); 23262306a36Sopenharmony_ci int offset = d->hwirq; 23362306a36Sopenharmony_ci int regoffset = offset / 8; 23462306a36Sopenharmony_ci int mask = BIT(offset % 8); 23562306a36Sopenharmony_ci 23662306a36Sopenharmony_ci stmpe_gpio->regs[REG_IE][regoffset] &= ~mask; 23762306a36Sopenharmony_ci gpiochip_disable_irq(gc, offset); 23862306a36Sopenharmony_ci} 23962306a36Sopenharmony_ci 24062306a36Sopenharmony_cistatic void stmpe_gpio_irq_unmask(struct irq_data *d) 24162306a36Sopenharmony_ci{ 24262306a36Sopenharmony_ci struct gpio_chip *gc = irq_data_get_irq_chip_data(d); 24362306a36Sopenharmony_ci struct stmpe_gpio *stmpe_gpio = gpiochip_get_data(gc); 24462306a36Sopenharmony_ci int offset = d->hwirq; 24562306a36Sopenharmony_ci int regoffset = offset / 8; 24662306a36Sopenharmony_ci int mask = BIT(offset % 8); 24762306a36Sopenharmony_ci 24862306a36Sopenharmony_ci gpiochip_enable_irq(gc, offset); 24962306a36Sopenharmony_ci stmpe_gpio->regs[REG_IE][regoffset] |= mask; 25062306a36Sopenharmony_ci} 25162306a36Sopenharmony_ci 25262306a36Sopenharmony_cistatic void stmpe_dbg_show_one(struct seq_file *s, 25362306a36Sopenharmony_ci struct gpio_chip *gc, 25462306a36Sopenharmony_ci unsigned offset, unsigned gpio) 25562306a36Sopenharmony_ci{ 25662306a36Sopenharmony_ci struct stmpe_gpio *stmpe_gpio = gpiochip_get_data(gc); 25762306a36Sopenharmony_ci struct stmpe *stmpe = stmpe_gpio->stmpe; 25862306a36Sopenharmony_ci const char *label = gpiochip_is_requested(gc, offset); 25962306a36Sopenharmony_ci bool val = !!stmpe_gpio_get(gc, offset); 26062306a36Sopenharmony_ci u8 bank = offset / 8; 26162306a36Sopenharmony_ci u8 dir_reg = stmpe->regs[STMPE_IDX_GPDR_LSB + bank]; 26262306a36Sopenharmony_ci u8 mask = BIT(offset % 8); 26362306a36Sopenharmony_ci int ret; 26462306a36Sopenharmony_ci u8 dir; 26562306a36Sopenharmony_ci 26662306a36Sopenharmony_ci ret = stmpe_reg_read(stmpe, dir_reg); 26762306a36Sopenharmony_ci if (ret < 0) 26862306a36Sopenharmony_ci return; 26962306a36Sopenharmony_ci dir = !!(ret & mask); 27062306a36Sopenharmony_ci 27162306a36Sopenharmony_ci if (dir) { 27262306a36Sopenharmony_ci seq_printf(s, " gpio-%-3d (%-20.20s) out %s", 27362306a36Sopenharmony_ci gpio, label ?: "(none)", 27462306a36Sopenharmony_ci val ? "hi" : "lo"); 27562306a36Sopenharmony_ci } else { 27662306a36Sopenharmony_ci u8 edge_det_reg; 27762306a36Sopenharmony_ci u8 rise_reg; 27862306a36Sopenharmony_ci u8 fall_reg; 27962306a36Sopenharmony_ci u8 irqen_reg; 28062306a36Sopenharmony_ci 28162306a36Sopenharmony_ci static const char * const edge_det_values[] = { 28262306a36Sopenharmony_ci "edge-inactive", 28362306a36Sopenharmony_ci "edge-asserted", 28462306a36Sopenharmony_ci "not-supported" 28562306a36Sopenharmony_ci }; 28662306a36Sopenharmony_ci static const char * const rise_values[] = { 28762306a36Sopenharmony_ci "no-rising-edge-detection", 28862306a36Sopenharmony_ci "rising-edge-detection", 28962306a36Sopenharmony_ci "not-supported" 29062306a36Sopenharmony_ci }; 29162306a36Sopenharmony_ci static const char * const fall_values[] = { 29262306a36Sopenharmony_ci "no-falling-edge-detection", 29362306a36Sopenharmony_ci "falling-edge-detection", 29462306a36Sopenharmony_ci "not-supported" 29562306a36Sopenharmony_ci }; 29662306a36Sopenharmony_ci #define NOT_SUPPORTED_IDX 2 29762306a36Sopenharmony_ci u8 edge_det = NOT_SUPPORTED_IDX; 29862306a36Sopenharmony_ci u8 rise = NOT_SUPPORTED_IDX; 29962306a36Sopenharmony_ci u8 fall = NOT_SUPPORTED_IDX; 30062306a36Sopenharmony_ci bool irqen; 30162306a36Sopenharmony_ci 30262306a36Sopenharmony_ci switch (stmpe->partnum) { 30362306a36Sopenharmony_ci case STMPE610: 30462306a36Sopenharmony_ci case STMPE811: 30562306a36Sopenharmony_ci case STMPE1601: 30662306a36Sopenharmony_ci case STMPE2401: 30762306a36Sopenharmony_ci case STMPE2403: 30862306a36Sopenharmony_ci edge_det_reg = stmpe->regs[STMPE_IDX_GPEDR_LSB + bank]; 30962306a36Sopenharmony_ci ret = stmpe_reg_read(stmpe, edge_det_reg); 31062306a36Sopenharmony_ci if (ret < 0) 31162306a36Sopenharmony_ci return; 31262306a36Sopenharmony_ci edge_det = !!(ret & mask); 31362306a36Sopenharmony_ci fallthrough; 31462306a36Sopenharmony_ci case STMPE1801: 31562306a36Sopenharmony_ci rise_reg = stmpe->regs[STMPE_IDX_GPRER_LSB + bank]; 31662306a36Sopenharmony_ci fall_reg = stmpe->regs[STMPE_IDX_GPFER_LSB + bank]; 31762306a36Sopenharmony_ci 31862306a36Sopenharmony_ci ret = stmpe_reg_read(stmpe, rise_reg); 31962306a36Sopenharmony_ci if (ret < 0) 32062306a36Sopenharmony_ci return; 32162306a36Sopenharmony_ci rise = !!(ret & mask); 32262306a36Sopenharmony_ci ret = stmpe_reg_read(stmpe, fall_reg); 32362306a36Sopenharmony_ci if (ret < 0) 32462306a36Sopenharmony_ci return; 32562306a36Sopenharmony_ci fall = !!(ret & mask); 32662306a36Sopenharmony_ci fallthrough; 32762306a36Sopenharmony_ci case STMPE801: 32862306a36Sopenharmony_ci case STMPE1600: 32962306a36Sopenharmony_ci irqen_reg = stmpe->regs[STMPE_IDX_IEGPIOR_LSB + bank]; 33062306a36Sopenharmony_ci break; 33162306a36Sopenharmony_ci 33262306a36Sopenharmony_ci default: 33362306a36Sopenharmony_ci return; 33462306a36Sopenharmony_ci } 33562306a36Sopenharmony_ci 33662306a36Sopenharmony_ci ret = stmpe_reg_read(stmpe, irqen_reg); 33762306a36Sopenharmony_ci if (ret < 0) 33862306a36Sopenharmony_ci return; 33962306a36Sopenharmony_ci irqen = !!(ret & mask); 34062306a36Sopenharmony_ci 34162306a36Sopenharmony_ci seq_printf(s, " gpio-%-3d (%-20.20s) in %s %13s %13s %25s %25s", 34262306a36Sopenharmony_ci gpio, label ?: "(none)", 34362306a36Sopenharmony_ci val ? "hi" : "lo", 34462306a36Sopenharmony_ci edge_det_values[edge_det], 34562306a36Sopenharmony_ci irqen ? "IRQ-enabled" : "IRQ-disabled", 34662306a36Sopenharmony_ci rise_values[rise], 34762306a36Sopenharmony_ci fall_values[fall]); 34862306a36Sopenharmony_ci } 34962306a36Sopenharmony_ci} 35062306a36Sopenharmony_ci 35162306a36Sopenharmony_cistatic void stmpe_dbg_show(struct seq_file *s, struct gpio_chip *gc) 35262306a36Sopenharmony_ci{ 35362306a36Sopenharmony_ci unsigned i; 35462306a36Sopenharmony_ci unsigned gpio = gc->base; 35562306a36Sopenharmony_ci 35662306a36Sopenharmony_ci for (i = 0; i < gc->ngpio; i++, gpio++) { 35762306a36Sopenharmony_ci stmpe_dbg_show_one(s, gc, i, gpio); 35862306a36Sopenharmony_ci seq_putc(s, '\n'); 35962306a36Sopenharmony_ci } 36062306a36Sopenharmony_ci} 36162306a36Sopenharmony_ci 36262306a36Sopenharmony_cistatic const struct irq_chip stmpe_gpio_irq_chip = { 36362306a36Sopenharmony_ci .name = "stmpe-gpio", 36462306a36Sopenharmony_ci .irq_bus_lock = stmpe_gpio_irq_lock, 36562306a36Sopenharmony_ci .irq_bus_sync_unlock = stmpe_gpio_irq_sync_unlock, 36662306a36Sopenharmony_ci .irq_mask = stmpe_gpio_irq_mask, 36762306a36Sopenharmony_ci .irq_unmask = stmpe_gpio_irq_unmask, 36862306a36Sopenharmony_ci .irq_set_type = stmpe_gpio_irq_set_type, 36962306a36Sopenharmony_ci .flags = IRQCHIP_IMMUTABLE, 37062306a36Sopenharmony_ci GPIOCHIP_IRQ_RESOURCE_HELPERS, 37162306a36Sopenharmony_ci}; 37262306a36Sopenharmony_ci 37362306a36Sopenharmony_ci#define MAX_GPIOS 24 37462306a36Sopenharmony_ci 37562306a36Sopenharmony_cistatic irqreturn_t stmpe_gpio_irq(int irq, void *dev) 37662306a36Sopenharmony_ci{ 37762306a36Sopenharmony_ci struct stmpe_gpio *stmpe_gpio = dev; 37862306a36Sopenharmony_ci struct stmpe *stmpe = stmpe_gpio->stmpe; 37962306a36Sopenharmony_ci u8 statmsbreg; 38062306a36Sopenharmony_ci int num_banks = DIV_ROUND_UP(stmpe->num_gpios, 8); 38162306a36Sopenharmony_ci u8 status[DIV_ROUND_UP(MAX_GPIOS, 8)]; 38262306a36Sopenharmony_ci int ret; 38362306a36Sopenharmony_ci int i; 38462306a36Sopenharmony_ci 38562306a36Sopenharmony_ci /* 38662306a36Sopenharmony_ci * the stmpe_block_read() call below, imposes to set statmsbreg 38762306a36Sopenharmony_ci * with the register located at the lowest address. As STMPE1600 38862306a36Sopenharmony_ci * variant is the only one which respect registers address's order 38962306a36Sopenharmony_ci * (LSB regs located at lowest address than MSB ones) whereas all 39062306a36Sopenharmony_ci * the others have a registers layout with MSB located before the 39162306a36Sopenharmony_ci * LSB regs. 39262306a36Sopenharmony_ci */ 39362306a36Sopenharmony_ci if (stmpe->partnum == STMPE1600) 39462306a36Sopenharmony_ci statmsbreg = stmpe->regs[STMPE_IDX_ISGPIOR_LSB]; 39562306a36Sopenharmony_ci else 39662306a36Sopenharmony_ci statmsbreg = stmpe->regs[STMPE_IDX_ISGPIOR_MSB]; 39762306a36Sopenharmony_ci 39862306a36Sopenharmony_ci ret = stmpe_block_read(stmpe, statmsbreg, num_banks, status); 39962306a36Sopenharmony_ci if (ret < 0) 40062306a36Sopenharmony_ci return IRQ_NONE; 40162306a36Sopenharmony_ci 40262306a36Sopenharmony_ci for (i = 0; i < num_banks; i++) { 40362306a36Sopenharmony_ci int bank = (stmpe_gpio->stmpe->partnum == STMPE1600) ? i : 40462306a36Sopenharmony_ci num_banks - i - 1; 40562306a36Sopenharmony_ci unsigned int enabled = stmpe_gpio->regs[REG_IE][bank]; 40662306a36Sopenharmony_ci unsigned int stat = status[i]; 40762306a36Sopenharmony_ci 40862306a36Sopenharmony_ci stat &= enabled; 40962306a36Sopenharmony_ci if (!stat) 41062306a36Sopenharmony_ci continue; 41162306a36Sopenharmony_ci 41262306a36Sopenharmony_ci while (stat) { 41362306a36Sopenharmony_ci int bit = __ffs(stat); 41462306a36Sopenharmony_ci int line = bank * 8 + bit; 41562306a36Sopenharmony_ci int child_irq = irq_find_mapping(stmpe_gpio->chip.irq.domain, 41662306a36Sopenharmony_ci line); 41762306a36Sopenharmony_ci 41862306a36Sopenharmony_ci handle_nested_irq(child_irq); 41962306a36Sopenharmony_ci stat &= ~BIT(bit); 42062306a36Sopenharmony_ci } 42162306a36Sopenharmony_ci 42262306a36Sopenharmony_ci /* 42362306a36Sopenharmony_ci * interrupt status register write has no effect on 42462306a36Sopenharmony_ci * 801/1801/1600, bits are cleared when read. 42562306a36Sopenharmony_ci * Edge detect register is not present on 801/1600/1801 42662306a36Sopenharmony_ci */ 42762306a36Sopenharmony_ci if (stmpe->partnum != STMPE801 && stmpe->partnum != STMPE1600 && 42862306a36Sopenharmony_ci stmpe->partnum != STMPE1801) { 42962306a36Sopenharmony_ci stmpe_reg_write(stmpe, statmsbreg + i, status[i]); 43062306a36Sopenharmony_ci stmpe_reg_write(stmpe, 43162306a36Sopenharmony_ci stmpe->regs[STMPE_IDX_GPEDR_MSB] + i, 43262306a36Sopenharmony_ci status[i]); 43362306a36Sopenharmony_ci } 43462306a36Sopenharmony_ci } 43562306a36Sopenharmony_ci 43662306a36Sopenharmony_ci return IRQ_HANDLED; 43762306a36Sopenharmony_ci} 43862306a36Sopenharmony_ci 43962306a36Sopenharmony_cistatic void stmpe_init_irq_valid_mask(struct gpio_chip *gc, 44062306a36Sopenharmony_ci unsigned long *valid_mask, 44162306a36Sopenharmony_ci unsigned int ngpios) 44262306a36Sopenharmony_ci{ 44362306a36Sopenharmony_ci struct stmpe_gpio *stmpe_gpio = gpiochip_get_data(gc); 44462306a36Sopenharmony_ci int i; 44562306a36Sopenharmony_ci 44662306a36Sopenharmony_ci if (!stmpe_gpio->norequest_mask) 44762306a36Sopenharmony_ci return; 44862306a36Sopenharmony_ci 44962306a36Sopenharmony_ci /* Forbid unused lines to be mapped as IRQs */ 45062306a36Sopenharmony_ci for (i = 0; i < sizeof(u32); i++) { 45162306a36Sopenharmony_ci if (stmpe_gpio->norequest_mask & BIT(i)) 45262306a36Sopenharmony_ci clear_bit(i, valid_mask); 45362306a36Sopenharmony_ci } 45462306a36Sopenharmony_ci} 45562306a36Sopenharmony_ci 45662306a36Sopenharmony_cistatic void stmpe_gpio_disable(void *stmpe) 45762306a36Sopenharmony_ci{ 45862306a36Sopenharmony_ci stmpe_disable(stmpe, STMPE_BLOCK_GPIO); 45962306a36Sopenharmony_ci} 46062306a36Sopenharmony_ci 46162306a36Sopenharmony_cistatic int stmpe_gpio_probe(struct platform_device *pdev) 46262306a36Sopenharmony_ci{ 46362306a36Sopenharmony_ci struct stmpe *stmpe = dev_get_drvdata(pdev->dev.parent); 46462306a36Sopenharmony_ci struct device_node *np = pdev->dev.of_node; 46562306a36Sopenharmony_ci struct stmpe_gpio *stmpe_gpio; 46662306a36Sopenharmony_ci int ret, irq; 46762306a36Sopenharmony_ci 46862306a36Sopenharmony_ci if (stmpe->num_gpios > MAX_GPIOS) { 46962306a36Sopenharmony_ci dev_err(&pdev->dev, "Need to increase maximum GPIO number\n"); 47062306a36Sopenharmony_ci return -EINVAL; 47162306a36Sopenharmony_ci } 47262306a36Sopenharmony_ci 47362306a36Sopenharmony_ci stmpe_gpio = devm_kzalloc(&pdev->dev, sizeof(*stmpe_gpio), GFP_KERNEL); 47462306a36Sopenharmony_ci if (!stmpe_gpio) 47562306a36Sopenharmony_ci return -ENOMEM; 47662306a36Sopenharmony_ci 47762306a36Sopenharmony_ci mutex_init(&stmpe_gpio->irq_lock); 47862306a36Sopenharmony_ci 47962306a36Sopenharmony_ci stmpe_gpio->dev = &pdev->dev; 48062306a36Sopenharmony_ci stmpe_gpio->stmpe = stmpe; 48162306a36Sopenharmony_ci stmpe_gpio->chip = template_chip; 48262306a36Sopenharmony_ci stmpe_gpio->chip.ngpio = stmpe->num_gpios; 48362306a36Sopenharmony_ci stmpe_gpio->chip.parent = &pdev->dev; 48462306a36Sopenharmony_ci stmpe_gpio->chip.base = -1; 48562306a36Sopenharmony_ci 48662306a36Sopenharmony_ci if (IS_ENABLED(CONFIG_DEBUG_FS)) 48762306a36Sopenharmony_ci stmpe_gpio->chip.dbg_show = stmpe_dbg_show; 48862306a36Sopenharmony_ci 48962306a36Sopenharmony_ci of_property_read_u32(np, "st,norequest-mask", 49062306a36Sopenharmony_ci &stmpe_gpio->norequest_mask); 49162306a36Sopenharmony_ci 49262306a36Sopenharmony_ci irq = platform_get_irq(pdev, 0); 49362306a36Sopenharmony_ci if (irq < 0) 49462306a36Sopenharmony_ci dev_info(&pdev->dev, 49562306a36Sopenharmony_ci "device configured in no-irq mode: " 49662306a36Sopenharmony_ci "irqs are not available\n"); 49762306a36Sopenharmony_ci 49862306a36Sopenharmony_ci ret = stmpe_enable(stmpe, STMPE_BLOCK_GPIO); 49962306a36Sopenharmony_ci if (ret) 50062306a36Sopenharmony_ci return ret; 50162306a36Sopenharmony_ci 50262306a36Sopenharmony_ci ret = devm_add_action_or_reset(&pdev->dev, stmpe_gpio_disable, stmpe); 50362306a36Sopenharmony_ci if (ret) 50462306a36Sopenharmony_ci return ret; 50562306a36Sopenharmony_ci 50662306a36Sopenharmony_ci if (irq > 0) { 50762306a36Sopenharmony_ci struct gpio_irq_chip *girq; 50862306a36Sopenharmony_ci 50962306a36Sopenharmony_ci ret = devm_request_threaded_irq(&pdev->dev, irq, NULL, 51062306a36Sopenharmony_ci stmpe_gpio_irq, IRQF_ONESHOT, 51162306a36Sopenharmony_ci "stmpe-gpio", stmpe_gpio); 51262306a36Sopenharmony_ci if (ret) { 51362306a36Sopenharmony_ci dev_err(&pdev->dev, "unable to get irq: %d\n", ret); 51462306a36Sopenharmony_ci return ret; 51562306a36Sopenharmony_ci } 51662306a36Sopenharmony_ci 51762306a36Sopenharmony_ci girq = &stmpe_gpio->chip.irq; 51862306a36Sopenharmony_ci gpio_irq_chip_set_chip(girq, &stmpe_gpio_irq_chip); 51962306a36Sopenharmony_ci /* This will let us handle the parent IRQ in the driver */ 52062306a36Sopenharmony_ci girq->parent_handler = NULL; 52162306a36Sopenharmony_ci girq->num_parents = 0; 52262306a36Sopenharmony_ci girq->parents = NULL; 52362306a36Sopenharmony_ci girq->default_type = IRQ_TYPE_NONE; 52462306a36Sopenharmony_ci girq->handler = handle_simple_irq; 52562306a36Sopenharmony_ci girq->threaded = true; 52662306a36Sopenharmony_ci girq->init_valid_mask = stmpe_init_irq_valid_mask; 52762306a36Sopenharmony_ci } 52862306a36Sopenharmony_ci 52962306a36Sopenharmony_ci return devm_gpiochip_add_data(&pdev->dev, &stmpe_gpio->chip, stmpe_gpio); 53062306a36Sopenharmony_ci} 53162306a36Sopenharmony_ci 53262306a36Sopenharmony_cistatic struct platform_driver stmpe_gpio_driver = { 53362306a36Sopenharmony_ci .driver = { 53462306a36Sopenharmony_ci .suppress_bind_attrs = true, 53562306a36Sopenharmony_ci .name = "stmpe-gpio", 53662306a36Sopenharmony_ci }, 53762306a36Sopenharmony_ci .probe = stmpe_gpio_probe, 53862306a36Sopenharmony_ci}; 53962306a36Sopenharmony_ci 54062306a36Sopenharmony_cistatic int __init stmpe_gpio_init(void) 54162306a36Sopenharmony_ci{ 54262306a36Sopenharmony_ci return platform_driver_register(&stmpe_gpio_driver); 54362306a36Sopenharmony_ci} 54462306a36Sopenharmony_cisubsys_initcall(stmpe_gpio_init); 545