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