18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only
28c2ecf20Sopenharmony_ci/*
38c2ecf20Sopenharmony_ci * Copyright (C) 2011-2012 Avionic Design GmbH
48c2ecf20Sopenharmony_ci */
58c2ecf20Sopenharmony_ci
68c2ecf20Sopenharmony_ci#include <linux/gpio/driver.h>
78c2ecf20Sopenharmony_ci#include <linux/i2c.h>
88c2ecf20Sopenharmony_ci#include <linux/interrupt.h>
98c2ecf20Sopenharmony_ci#include <linux/module.h>
108c2ecf20Sopenharmony_ci#include <linux/of_irq.h>
118c2ecf20Sopenharmony_ci#include <linux/seq_file.h>
128c2ecf20Sopenharmony_ci#include <linux/slab.h>
138c2ecf20Sopenharmony_ci
148c2ecf20Sopenharmony_ci#define GPIO_DDR(gpio) (0x00 << (gpio)->reg_shift)
158c2ecf20Sopenharmony_ci#define GPIO_PLR(gpio) (0x01 << (gpio)->reg_shift)
168c2ecf20Sopenharmony_ci#define GPIO_IER(gpio) (0x02 << (gpio)->reg_shift)
178c2ecf20Sopenharmony_ci#define GPIO_ISR(gpio) (0x03 << (gpio)->reg_shift)
188c2ecf20Sopenharmony_ci#define GPIO_PTR(gpio) (0x04 << (gpio)->reg_shift)
198c2ecf20Sopenharmony_ci
208c2ecf20Sopenharmony_cistruct adnp {
218c2ecf20Sopenharmony_ci	struct i2c_client *client;
228c2ecf20Sopenharmony_ci	struct gpio_chip gpio;
238c2ecf20Sopenharmony_ci	unsigned int reg_shift;
248c2ecf20Sopenharmony_ci
258c2ecf20Sopenharmony_ci	struct mutex i2c_lock;
268c2ecf20Sopenharmony_ci	struct mutex irq_lock;
278c2ecf20Sopenharmony_ci
288c2ecf20Sopenharmony_ci	u8 *irq_enable;
298c2ecf20Sopenharmony_ci	u8 *irq_level;
308c2ecf20Sopenharmony_ci	u8 *irq_rise;
318c2ecf20Sopenharmony_ci	u8 *irq_fall;
328c2ecf20Sopenharmony_ci	u8 *irq_high;
338c2ecf20Sopenharmony_ci	u8 *irq_low;
348c2ecf20Sopenharmony_ci};
358c2ecf20Sopenharmony_ci
368c2ecf20Sopenharmony_cistatic int adnp_read(struct adnp *adnp, unsigned offset, uint8_t *value)
378c2ecf20Sopenharmony_ci{
388c2ecf20Sopenharmony_ci	int err;
398c2ecf20Sopenharmony_ci
408c2ecf20Sopenharmony_ci	err = i2c_smbus_read_byte_data(adnp->client, offset);
418c2ecf20Sopenharmony_ci	if (err < 0) {
428c2ecf20Sopenharmony_ci		dev_err(adnp->gpio.parent, "%s failed: %d\n",
438c2ecf20Sopenharmony_ci			"i2c_smbus_read_byte_data()", err);
448c2ecf20Sopenharmony_ci		return err;
458c2ecf20Sopenharmony_ci	}
468c2ecf20Sopenharmony_ci
478c2ecf20Sopenharmony_ci	*value = err;
488c2ecf20Sopenharmony_ci	return 0;
498c2ecf20Sopenharmony_ci}
508c2ecf20Sopenharmony_ci
518c2ecf20Sopenharmony_cistatic int adnp_write(struct adnp *adnp, unsigned offset, uint8_t value)
528c2ecf20Sopenharmony_ci{
538c2ecf20Sopenharmony_ci	int err;
548c2ecf20Sopenharmony_ci
558c2ecf20Sopenharmony_ci	err = i2c_smbus_write_byte_data(adnp->client, offset, value);
568c2ecf20Sopenharmony_ci	if (err < 0) {
578c2ecf20Sopenharmony_ci		dev_err(adnp->gpio.parent, "%s failed: %d\n",
588c2ecf20Sopenharmony_ci			"i2c_smbus_write_byte_data()", err);
598c2ecf20Sopenharmony_ci		return err;
608c2ecf20Sopenharmony_ci	}
618c2ecf20Sopenharmony_ci
628c2ecf20Sopenharmony_ci	return 0;
638c2ecf20Sopenharmony_ci}
648c2ecf20Sopenharmony_ci
658c2ecf20Sopenharmony_cistatic int adnp_gpio_get(struct gpio_chip *chip, unsigned offset)
668c2ecf20Sopenharmony_ci{
678c2ecf20Sopenharmony_ci	struct adnp *adnp = gpiochip_get_data(chip);
688c2ecf20Sopenharmony_ci	unsigned int reg = offset >> adnp->reg_shift;
698c2ecf20Sopenharmony_ci	unsigned int pos = offset & 7;
708c2ecf20Sopenharmony_ci	u8 value;
718c2ecf20Sopenharmony_ci	int err;
728c2ecf20Sopenharmony_ci
738c2ecf20Sopenharmony_ci	err = adnp_read(adnp, GPIO_PLR(adnp) + reg, &value);
748c2ecf20Sopenharmony_ci	if (err < 0)
758c2ecf20Sopenharmony_ci		return err;
768c2ecf20Sopenharmony_ci
778c2ecf20Sopenharmony_ci	return (value & BIT(pos)) ? 1 : 0;
788c2ecf20Sopenharmony_ci}
798c2ecf20Sopenharmony_ci
808c2ecf20Sopenharmony_cistatic void __adnp_gpio_set(struct adnp *adnp, unsigned offset, int value)
818c2ecf20Sopenharmony_ci{
828c2ecf20Sopenharmony_ci	unsigned int reg = offset >> adnp->reg_shift;
838c2ecf20Sopenharmony_ci	unsigned int pos = offset & 7;
848c2ecf20Sopenharmony_ci	int err;
858c2ecf20Sopenharmony_ci	u8 val;
868c2ecf20Sopenharmony_ci
878c2ecf20Sopenharmony_ci	err = adnp_read(adnp, GPIO_PLR(adnp) + reg, &val);
888c2ecf20Sopenharmony_ci	if (err < 0)
898c2ecf20Sopenharmony_ci		return;
908c2ecf20Sopenharmony_ci
918c2ecf20Sopenharmony_ci	if (value)
928c2ecf20Sopenharmony_ci		val |= BIT(pos);
938c2ecf20Sopenharmony_ci	else
948c2ecf20Sopenharmony_ci		val &= ~BIT(pos);
958c2ecf20Sopenharmony_ci
968c2ecf20Sopenharmony_ci	adnp_write(adnp, GPIO_PLR(adnp) + reg, val);
978c2ecf20Sopenharmony_ci}
988c2ecf20Sopenharmony_ci
998c2ecf20Sopenharmony_cistatic void adnp_gpio_set(struct gpio_chip *chip, unsigned offset, int value)
1008c2ecf20Sopenharmony_ci{
1018c2ecf20Sopenharmony_ci	struct adnp *adnp = gpiochip_get_data(chip);
1028c2ecf20Sopenharmony_ci
1038c2ecf20Sopenharmony_ci	mutex_lock(&adnp->i2c_lock);
1048c2ecf20Sopenharmony_ci	__adnp_gpio_set(adnp, offset, value);
1058c2ecf20Sopenharmony_ci	mutex_unlock(&adnp->i2c_lock);
1068c2ecf20Sopenharmony_ci}
1078c2ecf20Sopenharmony_ci
1088c2ecf20Sopenharmony_cistatic int adnp_gpio_direction_input(struct gpio_chip *chip, unsigned offset)
1098c2ecf20Sopenharmony_ci{
1108c2ecf20Sopenharmony_ci	struct adnp *adnp = gpiochip_get_data(chip);
1118c2ecf20Sopenharmony_ci	unsigned int reg = offset >> adnp->reg_shift;
1128c2ecf20Sopenharmony_ci	unsigned int pos = offset & 7;
1138c2ecf20Sopenharmony_ci	u8 value;
1148c2ecf20Sopenharmony_ci	int err;
1158c2ecf20Sopenharmony_ci
1168c2ecf20Sopenharmony_ci	mutex_lock(&adnp->i2c_lock);
1178c2ecf20Sopenharmony_ci
1188c2ecf20Sopenharmony_ci	err = adnp_read(adnp, GPIO_DDR(adnp) + reg, &value);
1198c2ecf20Sopenharmony_ci	if (err < 0)
1208c2ecf20Sopenharmony_ci		goto out;
1218c2ecf20Sopenharmony_ci
1228c2ecf20Sopenharmony_ci	value &= ~BIT(pos);
1238c2ecf20Sopenharmony_ci
1248c2ecf20Sopenharmony_ci	err = adnp_write(adnp, GPIO_DDR(adnp) + reg, value);
1258c2ecf20Sopenharmony_ci	if (err < 0)
1268c2ecf20Sopenharmony_ci		goto out;
1278c2ecf20Sopenharmony_ci
1288c2ecf20Sopenharmony_ci	err = adnp_read(adnp, GPIO_DDR(adnp) + reg, &value);
1298c2ecf20Sopenharmony_ci	if (err < 0)
1308c2ecf20Sopenharmony_ci		goto out;
1318c2ecf20Sopenharmony_ci
1328c2ecf20Sopenharmony_ci	if (value & BIT(pos)) {
1338c2ecf20Sopenharmony_ci		err = -EPERM;
1348c2ecf20Sopenharmony_ci		goto out;
1358c2ecf20Sopenharmony_ci	}
1368c2ecf20Sopenharmony_ci
1378c2ecf20Sopenharmony_ci	err = 0;
1388c2ecf20Sopenharmony_ci
1398c2ecf20Sopenharmony_ciout:
1408c2ecf20Sopenharmony_ci	mutex_unlock(&adnp->i2c_lock);
1418c2ecf20Sopenharmony_ci	return err;
1428c2ecf20Sopenharmony_ci}
1438c2ecf20Sopenharmony_ci
1448c2ecf20Sopenharmony_cistatic int adnp_gpio_direction_output(struct gpio_chip *chip, unsigned offset,
1458c2ecf20Sopenharmony_ci				      int value)
1468c2ecf20Sopenharmony_ci{
1478c2ecf20Sopenharmony_ci	struct adnp *adnp = gpiochip_get_data(chip);
1488c2ecf20Sopenharmony_ci	unsigned int reg = offset >> adnp->reg_shift;
1498c2ecf20Sopenharmony_ci	unsigned int pos = offset & 7;
1508c2ecf20Sopenharmony_ci	int err;
1518c2ecf20Sopenharmony_ci	u8 val;
1528c2ecf20Sopenharmony_ci
1538c2ecf20Sopenharmony_ci	mutex_lock(&adnp->i2c_lock);
1548c2ecf20Sopenharmony_ci
1558c2ecf20Sopenharmony_ci	err = adnp_read(adnp, GPIO_DDR(adnp) + reg, &val);
1568c2ecf20Sopenharmony_ci	if (err < 0)
1578c2ecf20Sopenharmony_ci		goto out;
1588c2ecf20Sopenharmony_ci
1598c2ecf20Sopenharmony_ci	val |= BIT(pos);
1608c2ecf20Sopenharmony_ci
1618c2ecf20Sopenharmony_ci	err = adnp_write(adnp, GPIO_DDR(adnp) + reg, val);
1628c2ecf20Sopenharmony_ci	if (err < 0)
1638c2ecf20Sopenharmony_ci		goto out;
1648c2ecf20Sopenharmony_ci
1658c2ecf20Sopenharmony_ci	err = adnp_read(adnp, GPIO_DDR(adnp) + reg, &val);
1668c2ecf20Sopenharmony_ci	if (err < 0)
1678c2ecf20Sopenharmony_ci		goto out;
1688c2ecf20Sopenharmony_ci
1698c2ecf20Sopenharmony_ci	if (!(val & BIT(pos))) {
1708c2ecf20Sopenharmony_ci		err = -EPERM;
1718c2ecf20Sopenharmony_ci		goto out;
1728c2ecf20Sopenharmony_ci	}
1738c2ecf20Sopenharmony_ci
1748c2ecf20Sopenharmony_ci	__adnp_gpio_set(adnp, offset, value);
1758c2ecf20Sopenharmony_ci	err = 0;
1768c2ecf20Sopenharmony_ci
1778c2ecf20Sopenharmony_ciout:
1788c2ecf20Sopenharmony_ci	mutex_unlock(&adnp->i2c_lock);
1798c2ecf20Sopenharmony_ci	return err;
1808c2ecf20Sopenharmony_ci}
1818c2ecf20Sopenharmony_ci
1828c2ecf20Sopenharmony_cistatic void adnp_gpio_dbg_show(struct seq_file *s, struct gpio_chip *chip)
1838c2ecf20Sopenharmony_ci{
1848c2ecf20Sopenharmony_ci	struct adnp *adnp = gpiochip_get_data(chip);
1858c2ecf20Sopenharmony_ci	unsigned int num_regs = 1 << adnp->reg_shift, i, j;
1868c2ecf20Sopenharmony_ci	int err;
1878c2ecf20Sopenharmony_ci
1888c2ecf20Sopenharmony_ci	for (i = 0; i < num_regs; i++) {
1898c2ecf20Sopenharmony_ci		u8 ddr, plr, ier, isr;
1908c2ecf20Sopenharmony_ci
1918c2ecf20Sopenharmony_ci		mutex_lock(&adnp->i2c_lock);
1928c2ecf20Sopenharmony_ci
1938c2ecf20Sopenharmony_ci		err = adnp_read(adnp, GPIO_DDR(adnp) + i, &ddr);
1948c2ecf20Sopenharmony_ci		if (err < 0)
1958c2ecf20Sopenharmony_ci			goto unlock;
1968c2ecf20Sopenharmony_ci
1978c2ecf20Sopenharmony_ci		err = adnp_read(adnp, GPIO_PLR(adnp) + i, &plr);
1988c2ecf20Sopenharmony_ci		if (err < 0)
1998c2ecf20Sopenharmony_ci			goto unlock;
2008c2ecf20Sopenharmony_ci
2018c2ecf20Sopenharmony_ci		err = adnp_read(adnp, GPIO_IER(adnp) + i, &ier);
2028c2ecf20Sopenharmony_ci		if (err < 0)
2038c2ecf20Sopenharmony_ci			goto unlock;
2048c2ecf20Sopenharmony_ci
2058c2ecf20Sopenharmony_ci		err = adnp_read(adnp, GPIO_ISR(adnp) + i, &isr);
2068c2ecf20Sopenharmony_ci		if (err < 0)
2078c2ecf20Sopenharmony_ci			goto unlock;
2088c2ecf20Sopenharmony_ci
2098c2ecf20Sopenharmony_ci		mutex_unlock(&adnp->i2c_lock);
2108c2ecf20Sopenharmony_ci
2118c2ecf20Sopenharmony_ci		for (j = 0; j < 8; j++) {
2128c2ecf20Sopenharmony_ci			unsigned int bit = (i << adnp->reg_shift) + j;
2138c2ecf20Sopenharmony_ci			const char *direction = "input ";
2148c2ecf20Sopenharmony_ci			const char *level = "low ";
2158c2ecf20Sopenharmony_ci			const char *interrupt = "disabled";
2168c2ecf20Sopenharmony_ci			const char *pending = "";
2178c2ecf20Sopenharmony_ci
2188c2ecf20Sopenharmony_ci			if (ddr & BIT(j))
2198c2ecf20Sopenharmony_ci				direction = "output";
2208c2ecf20Sopenharmony_ci
2218c2ecf20Sopenharmony_ci			if (plr & BIT(j))
2228c2ecf20Sopenharmony_ci				level = "high";
2238c2ecf20Sopenharmony_ci
2248c2ecf20Sopenharmony_ci			if (ier & BIT(j))
2258c2ecf20Sopenharmony_ci				interrupt = "enabled ";
2268c2ecf20Sopenharmony_ci
2278c2ecf20Sopenharmony_ci			if (isr & BIT(j))
2288c2ecf20Sopenharmony_ci				pending = "pending";
2298c2ecf20Sopenharmony_ci
2308c2ecf20Sopenharmony_ci			seq_printf(s, "%2u: %s %s IRQ %s %s\n", bit,
2318c2ecf20Sopenharmony_ci				   direction, level, interrupt, pending);
2328c2ecf20Sopenharmony_ci		}
2338c2ecf20Sopenharmony_ci	}
2348c2ecf20Sopenharmony_ci
2358c2ecf20Sopenharmony_ci	return;
2368c2ecf20Sopenharmony_ci
2378c2ecf20Sopenharmony_ciunlock:
2388c2ecf20Sopenharmony_ci	mutex_unlock(&adnp->i2c_lock);
2398c2ecf20Sopenharmony_ci}
2408c2ecf20Sopenharmony_ci
2418c2ecf20Sopenharmony_cistatic irqreturn_t adnp_irq(int irq, void *data)
2428c2ecf20Sopenharmony_ci{
2438c2ecf20Sopenharmony_ci	struct adnp *adnp = data;
2448c2ecf20Sopenharmony_ci	unsigned int num_regs, i;
2458c2ecf20Sopenharmony_ci
2468c2ecf20Sopenharmony_ci	num_regs = 1 << adnp->reg_shift;
2478c2ecf20Sopenharmony_ci
2488c2ecf20Sopenharmony_ci	for (i = 0; i < num_regs; i++) {
2498c2ecf20Sopenharmony_ci		unsigned int base = i << adnp->reg_shift, bit;
2508c2ecf20Sopenharmony_ci		u8 changed, level, isr, ier;
2518c2ecf20Sopenharmony_ci		unsigned long pending;
2528c2ecf20Sopenharmony_ci		int err;
2538c2ecf20Sopenharmony_ci
2548c2ecf20Sopenharmony_ci		mutex_lock(&adnp->i2c_lock);
2558c2ecf20Sopenharmony_ci
2568c2ecf20Sopenharmony_ci		err = adnp_read(adnp, GPIO_PLR(adnp) + i, &level);
2578c2ecf20Sopenharmony_ci		if (err < 0) {
2588c2ecf20Sopenharmony_ci			mutex_unlock(&adnp->i2c_lock);
2598c2ecf20Sopenharmony_ci			continue;
2608c2ecf20Sopenharmony_ci		}
2618c2ecf20Sopenharmony_ci
2628c2ecf20Sopenharmony_ci		err = adnp_read(adnp, GPIO_ISR(adnp) + i, &isr);
2638c2ecf20Sopenharmony_ci		if (err < 0) {
2648c2ecf20Sopenharmony_ci			mutex_unlock(&adnp->i2c_lock);
2658c2ecf20Sopenharmony_ci			continue;
2668c2ecf20Sopenharmony_ci		}
2678c2ecf20Sopenharmony_ci
2688c2ecf20Sopenharmony_ci		err = adnp_read(adnp, GPIO_IER(adnp) + i, &ier);
2698c2ecf20Sopenharmony_ci		if (err < 0) {
2708c2ecf20Sopenharmony_ci			mutex_unlock(&adnp->i2c_lock);
2718c2ecf20Sopenharmony_ci			continue;
2728c2ecf20Sopenharmony_ci		}
2738c2ecf20Sopenharmony_ci
2748c2ecf20Sopenharmony_ci		mutex_unlock(&adnp->i2c_lock);
2758c2ecf20Sopenharmony_ci
2768c2ecf20Sopenharmony_ci		/* determine pins that changed levels */
2778c2ecf20Sopenharmony_ci		changed = level ^ adnp->irq_level[i];
2788c2ecf20Sopenharmony_ci
2798c2ecf20Sopenharmony_ci		/* compute edge-triggered interrupts */
2808c2ecf20Sopenharmony_ci		pending = changed & ((adnp->irq_fall[i] & ~level) |
2818c2ecf20Sopenharmony_ci				     (adnp->irq_rise[i] & level));
2828c2ecf20Sopenharmony_ci
2838c2ecf20Sopenharmony_ci		/* add in level-triggered interrupts */
2848c2ecf20Sopenharmony_ci		pending |= (adnp->irq_high[i] & level) |
2858c2ecf20Sopenharmony_ci			   (adnp->irq_low[i] & ~level);
2868c2ecf20Sopenharmony_ci
2878c2ecf20Sopenharmony_ci		/* mask out non-pending and disabled interrupts */
2888c2ecf20Sopenharmony_ci		pending &= isr & ier;
2898c2ecf20Sopenharmony_ci
2908c2ecf20Sopenharmony_ci		for_each_set_bit(bit, &pending, 8) {
2918c2ecf20Sopenharmony_ci			unsigned int child_irq;
2928c2ecf20Sopenharmony_ci			child_irq = irq_find_mapping(adnp->gpio.irq.domain,
2938c2ecf20Sopenharmony_ci						     base + bit);
2948c2ecf20Sopenharmony_ci			handle_nested_irq(child_irq);
2958c2ecf20Sopenharmony_ci		}
2968c2ecf20Sopenharmony_ci	}
2978c2ecf20Sopenharmony_ci
2988c2ecf20Sopenharmony_ci	return IRQ_HANDLED;
2998c2ecf20Sopenharmony_ci}
3008c2ecf20Sopenharmony_ci
3018c2ecf20Sopenharmony_cistatic void adnp_irq_mask(struct irq_data *d)
3028c2ecf20Sopenharmony_ci{
3038c2ecf20Sopenharmony_ci	struct gpio_chip *gc = irq_data_get_irq_chip_data(d);
3048c2ecf20Sopenharmony_ci	struct adnp *adnp = gpiochip_get_data(gc);
3058c2ecf20Sopenharmony_ci	unsigned int reg = d->hwirq >> adnp->reg_shift;
3068c2ecf20Sopenharmony_ci	unsigned int pos = d->hwirq & 7;
3078c2ecf20Sopenharmony_ci
3088c2ecf20Sopenharmony_ci	adnp->irq_enable[reg] &= ~BIT(pos);
3098c2ecf20Sopenharmony_ci}
3108c2ecf20Sopenharmony_ci
3118c2ecf20Sopenharmony_cistatic void adnp_irq_unmask(struct irq_data *d)
3128c2ecf20Sopenharmony_ci{
3138c2ecf20Sopenharmony_ci	struct gpio_chip *gc = irq_data_get_irq_chip_data(d);
3148c2ecf20Sopenharmony_ci	struct adnp *adnp = gpiochip_get_data(gc);
3158c2ecf20Sopenharmony_ci	unsigned int reg = d->hwirq >> adnp->reg_shift;
3168c2ecf20Sopenharmony_ci	unsigned int pos = d->hwirq & 7;
3178c2ecf20Sopenharmony_ci
3188c2ecf20Sopenharmony_ci	adnp->irq_enable[reg] |= BIT(pos);
3198c2ecf20Sopenharmony_ci}
3208c2ecf20Sopenharmony_ci
3218c2ecf20Sopenharmony_cistatic int adnp_irq_set_type(struct irq_data *d, unsigned int type)
3228c2ecf20Sopenharmony_ci{
3238c2ecf20Sopenharmony_ci	struct gpio_chip *gc = irq_data_get_irq_chip_data(d);
3248c2ecf20Sopenharmony_ci	struct adnp *adnp = gpiochip_get_data(gc);
3258c2ecf20Sopenharmony_ci	unsigned int reg = d->hwirq >> adnp->reg_shift;
3268c2ecf20Sopenharmony_ci	unsigned int pos = d->hwirq & 7;
3278c2ecf20Sopenharmony_ci
3288c2ecf20Sopenharmony_ci	if (type & IRQ_TYPE_EDGE_RISING)
3298c2ecf20Sopenharmony_ci		adnp->irq_rise[reg] |= BIT(pos);
3308c2ecf20Sopenharmony_ci	else
3318c2ecf20Sopenharmony_ci		adnp->irq_rise[reg] &= ~BIT(pos);
3328c2ecf20Sopenharmony_ci
3338c2ecf20Sopenharmony_ci	if (type & IRQ_TYPE_EDGE_FALLING)
3348c2ecf20Sopenharmony_ci		adnp->irq_fall[reg] |= BIT(pos);
3358c2ecf20Sopenharmony_ci	else
3368c2ecf20Sopenharmony_ci		adnp->irq_fall[reg] &= ~BIT(pos);
3378c2ecf20Sopenharmony_ci
3388c2ecf20Sopenharmony_ci	if (type & IRQ_TYPE_LEVEL_HIGH)
3398c2ecf20Sopenharmony_ci		adnp->irq_high[reg] |= BIT(pos);
3408c2ecf20Sopenharmony_ci	else
3418c2ecf20Sopenharmony_ci		adnp->irq_high[reg] &= ~BIT(pos);
3428c2ecf20Sopenharmony_ci
3438c2ecf20Sopenharmony_ci	if (type & IRQ_TYPE_LEVEL_LOW)
3448c2ecf20Sopenharmony_ci		adnp->irq_low[reg] |= BIT(pos);
3458c2ecf20Sopenharmony_ci	else
3468c2ecf20Sopenharmony_ci		adnp->irq_low[reg] &= ~BIT(pos);
3478c2ecf20Sopenharmony_ci
3488c2ecf20Sopenharmony_ci	return 0;
3498c2ecf20Sopenharmony_ci}
3508c2ecf20Sopenharmony_ci
3518c2ecf20Sopenharmony_cistatic void adnp_irq_bus_lock(struct irq_data *d)
3528c2ecf20Sopenharmony_ci{
3538c2ecf20Sopenharmony_ci	struct gpio_chip *gc = irq_data_get_irq_chip_data(d);
3548c2ecf20Sopenharmony_ci	struct adnp *adnp = gpiochip_get_data(gc);
3558c2ecf20Sopenharmony_ci
3568c2ecf20Sopenharmony_ci	mutex_lock(&adnp->irq_lock);
3578c2ecf20Sopenharmony_ci}
3588c2ecf20Sopenharmony_ci
3598c2ecf20Sopenharmony_cistatic void adnp_irq_bus_unlock(struct irq_data *d)
3608c2ecf20Sopenharmony_ci{
3618c2ecf20Sopenharmony_ci	struct gpio_chip *gc = irq_data_get_irq_chip_data(d);
3628c2ecf20Sopenharmony_ci	struct adnp *adnp = gpiochip_get_data(gc);
3638c2ecf20Sopenharmony_ci	unsigned int num_regs = 1 << adnp->reg_shift, i;
3648c2ecf20Sopenharmony_ci
3658c2ecf20Sopenharmony_ci	mutex_lock(&adnp->i2c_lock);
3668c2ecf20Sopenharmony_ci
3678c2ecf20Sopenharmony_ci	for (i = 0; i < num_regs; i++)
3688c2ecf20Sopenharmony_ci		adnp_write(adnp, GPIO_IER(adnp) + i, adnp->irq_enable[i]);
3698c2ecf20Sopenharmony_ci
3708c2ecf20Sopenharmony_ci	mutex_unlock(&adnp->i2c_lock);
3718c2ecf20Sopenharmony_ci	mutex_unlock(&adnp->irq_lock);
3728c2ecf20Sopenharmony_ci}
3738c2ecf20Sopenharmony_ci
3748c2ecf20Sopenharmony_cistatic struct irq_chip adnp_irq_chip = {
3758c2ecf20Sopenharmony_ci	.name = "gpio-adnp",
3768c2ecf20Sopenharmony_ci	.irq_mask = adnp_irq_mask,
3778c2ecf20Sopenharmony_ci	.irq_unmask = adnp_irq_unmask,
3788c2ecf20Sopenharmony_ci	.irq_set_type = adnp_irq_set_type,
3798c2ecf20Sopenharmony_ci	.irq_bus_lock = adnp_irq_bus_lock,
3808c2ecf20Sopenharmony_ci	.irq_bus_sync_unlock = adnp_irq_bus_unlock,
3818c2ecf20Sopenharmony_ci};
3828c2ecf20Sopenharmony_ci
3838c2ecf20Sopenharmony_cistatic int adnp_irq_setup(struct adnp *adnp)
3848c2ecf20Sopenharmony_ci{
3858c2ecf20Sopenharmony_ci	unsigned int num_regs = 1 << adnp->reg_shift, i;
3868c2ecf20Sopenharmony_ci	struct gpio_chip *chip = &adnp->gpio;
3878c2ecf20Sopenharmony_ci	int err;
3888c2ecf20Sopenharmony_ci
3898c2ecf20Sopenharmony_ci	mutex_init(&adnp->irq_lock);
3908c2ecf20Sopenharmony_ci
3918c2ecf20Sopenharmony_ci	/*
3928c2ecf20Sopenharmony_ci	 * Allocate memory to keep track of the current level and trigger
3938c2ecf20Sopenharmony_ci	 * modes of the interrupts. To avoid multiple allocations, a single
3948c2ecf20Sopenharmony_ci	 * large buffer is allocated and pointers are setup to point at the
3958c2ecf20Sopenharmony_ci	 * corresponding offsets. For consistency, the layout of the buffer
3968c2ecf20Sopenharmony_ci	 * is chosen to match the register layout of the hardware in that
3978c2ecf20Sopenharmony_ci	 * each segment contains the corresponding bits for all interrupts.
3988c2ecf20Sopenharmony_ci	 */
3998c2ecf20Sopenharmony_ci	adnp->irq_enable = devm_kcalloc(chip->parent, num_regs, 6,
4008c2ecf20Sopenharmony_ci					GFP_KERNEL);
4018c2ecf20Sopenharmony_ci	if (!adnp->irq_enable)
4028c2ecf20Sopenharmony_ci		return -ENOMEM;
4038c2ecf20Sopenharmony_ci
4048c2ecf20Sopenharmony_ci	adnp->irq_level = adnp->irq_enable + (num_regs * 1);
4058c2ecf20Sopenharmony_ci	adnp->irq_rise = adnp->irq_enable + (num_regs * 2);
4068c2ecf20Sopenharmony_ci	adnp->irq_fall = adnp->irq_enable + (num_regs * 3);
4078c2ecf20Sopenharmony_ci	adnp->irq_high = adnp->irq_enable + (num_regs * 4);
4088c2ecf20Sopenharmony_ci	adnp->irq_low = adnp->irq_enable + (num_regs * 5);
4098c2ecf20Sopenharmony_ci
4108c2ecf20Sopenharmony_ci	for (i = 0; i < num_regs; i++) {
4118c2ecf20Sopenharmony_ci		/*
4128c2ecf20Sopenharmony_ci		 * Read the initial level of all pins to allow the emulation
4138c2ecf20Sopenharmony_ci		 * of edge triggered interrupts.
4148c2ecf20Sopenharmony_ci		 */
4158c2ecf20Sopenharmony_ci		err = adnp_read(adnp, GPIO_PLR(adnp) + i, &adnp->irq_level[i]);
4168c2ecf20Sopenharmony_ci		if (err < 0)
4178c2ecf20Sopenharmony_ci			return err;
4188c2ecf20Sopenharmony_ci
4198c2ecf20Sopenharmony_ci		/* disable all interrupts */
4208c2ecf20Sopenharmony_ci		err = adnp_write(adnp, GPIO_IER(adnp) + i, 0);
4218c2ecf20Sopenharmony_ci		if (err < 0)
4228c2ecf20Sopenharmony_ci			return err;
4238c2ecf20Sopenharmony_ci
4248c2ecf20Sopenharmony_ci		adnp->irq_enable[i] = 0x00;
4258c2ecf20Sopenharmony_ci	}
4268c2ecf20Sopenharmony_ci
4278c2ecf20Sopenharmony_ci	err = devm_request_threaded_irq(chip->parent, adnp->client->irq,
4288c2ecf20Sopenharmony_ci					NULL, adnp_irq,
4298c2ecf20Sopenharmony_ci					IRQF_TRIGGER_RISING | IRQF_ONESHOT,
4308c2ecf20Sopenharmony_ci					dev_name(chip->parent), adnp);
4318c2ecf20Sopenharmony_ci	if (err != 0) {
4328c2ecf20Sopenharmony_ci		dev_err(chip->parent, "can't request IRQ#%d: %d\n",
4338c2ecf20Sopenharmony_ci			adnp->client->irq, err);
4348c2ecf20Sopenharmony_ci		return err;
4358c2ecf20Sopenharmony_ci	}
4368c2ecf20Sopenharmony_ci
4378c2ecf20Sopenharmony_ci	return 0;
4388c2ecf20Sopenharmony_ci}
4398c2ecf20Sopenharmony_ci
4408c2ecf20Sopenharmony_cistatic int adnp_gpio_setup(struct adnp *adnp, unsigned int num_gpios,
4418c2ecf20Sopenharmony_ci			   bool is_irq_controller)
4428c2ecf20Sopenharmony_ci{
4438c2ecf20Sopenharmony_ci	struct gpio_chip *chip = &adnp->gpio;
4448c2ecf20Sopenharmony_ci	int err;
4458c2ecf20Sopenharmony_ci
4468c2ecf20Sopenharmony_ci	adnp->reg_shift = get_count_order(num_gpios) - 3;
4478c2ecf20Sopenharmony_ci
4488c2ecf20Sopenharmony_ci	chip->direction_input = adnp_gpio_direction_input;
4498c2ecf20Sopenharmony_ci	chip->direction_output = adnp_gpio_direction_output;
4508c2ecf20Sopenharmony_ci	chip->get = adnp_gpio_get;
4518c2ecf20Sopenharmony_ci	chip->set = adnp_gpio_set;
4528c2ecf20Sopenharmony_ci	chip->can_sleep = true;
4538c2ecf20Sopenharmony_ci
4548c2ecf20Sopenharmony_ci	if (IS_ENABLED(CONFIG_DEBUG_FS))
4558c2ecf20Sopenharmony_ci		chip->dbg_show = adnp_gpio_dbg_show;
4568c2ecf20Sopenharmony_ci
4578c2ecf20Sopenharmony_ci	chip->base = -1;
4588c2ecf20Sopenharmony_ci	chip->ngpio = num_gpios;
4598c2ecf20Sopenharmony_ci	chip->label = adnp->client->name;
4608c2ecf20Sopenharmony_ci	chip->parent = &adnp->client->dev;
4618c2ecf20Sopenharmony_ci	chip->of_node = chip->parent->of_node;
4628c2ecf20Sopenharmony_ci	chip->owner = THIS_MODULE;
4638c2ecf20Sopenharmony_ci
4648c2ecf20Sopenharmony_ci	if (is_irq_controller) {
4658c2ecf20Sopenharmony_ci		struct gpio_irq_chip *girq;
4668c2ecf20Sopenharmony_ci
4678c2ecf20Sopenharmony_ci		err = adnp_irq_setup(adnp);
4688c2ecf20Sopenharmony_ci		if (err)
4698c2ecf20Sopenharmony_ci			return err;
4708c2ecf20Sopenharmony_ci
4718c2ecf20Sopenharmony_ci		girq = &chip->irq;
4728c2ecf20Sopenharmony_ci		girq->chip = &adnp_irq_chip;
4738c2ecf20Sopenharmony_ci		/* This will let us handle the parent IRQ in the driver */
4748c2ecf20Sopenharmony_ci		girq->parent_handler = NULL;
4758c2ecf20Sopenharmony_ci		girq->num_parents = 0;
4768c2ecf20Sopenharmony_ci		girq->parents = NULL;
4778c2ecf20Sopenharmony_ci		girq->default_type = IRQ_TYPE_NONE;
4788c2ecf20Sopenharmony_ci		girq->handler = handle_simple_irq;
4798c2ecf20Sopenharmony_ci		girq->threaded = true;
4808c2ecf20Sopenharmony_ci	}
4818c2ecf20Sopenharmony_ci
4828c2ecf20Sopenharmony_ci	err = devm_gpiochip_add_data(&adnp->client->dev, chip, adnp);
4838c2ecf20Sopenharmony_ci	if (err)
4848c2ecf20Sopenharmony_ci		return err;
4858c2ecf20Sopenharmony_ci
4868c2ecf20Sopenharmony_ci	return 0;
4878c2ecf20Sopenharmony_ci}
4888c2ecf20Sopenharmony_ci
4898c2ecf20Sopenharmony_cistatic int adnp_i2c_probe(struct i2c_client *client,
4908c2ecf20Sopenharmony_ci				    const struct i2c_device_id *id)
4918c2ecf20Sopenharmony_ci{
4928c2ecf20Sopenharmony_ci	struct device_node *np = client->dev.of_node;
4938c2ecf20Sopenharmony_ci	struct adnp *adnp;
4948c2ecf20Sopenharmony_ci	u32 num_gpios;
4958c2ecf20Sopenharmony_ci	int err;
4968c2ecf20Sopenharmony_ci
4978c2ecf20Sopenharmony_ci	err = of_property_read_u32(np, "nr-gpios", &num_gpios);
4988c2ecf20Sopenharmony_ci	if (err < 0)
4998c2ecf20Sopenharmony_ci		return err;
5008c2ecf20Sopenharmony_ci
5018c2ecf20Sopenharmony_ci	client->irq = irq_of_parse_and_map(np, 0);
5028c2ecf20Sopenharmony_ci	if (!client->irq)
5038c2ecf20Sopenharmony_ci		return -EPROBE_DEFER;
5048c2ecf20Sopenharmony_ci
5058c2ecf20Sopenharmony_ci	adnp = devm_kzalloc(&client->dev, sizeof(*adnp), GFP_KERNEL);
5068c2ecf20Sopenharmony_ci	if (!adnp)
5078c2ecf20Sopenharmony_ci		return -ENOMEM;
5088c2ecf20Sopenharmony_ci
5098c2ecf20Sopenharmony_ci	mutex_init(&adnp->i2c_lock);
5108c2ecf20Sopenharmony_ci	adnp->client = client;
5118c2ecf20Sopenharmony_ci
5128c2ecf20Sopenharmony_ci	err = adnp_gpio_setup(adnp, num_gpios,
5138c2ecf20Sopenharmony_ci			of_property_read_bool(np, "interrupt-controller"));
5148c2ecf20Sopenharmony_ci	if (err)
5158c2ecf20Sopenharmony_ci		return err;
5168c2ecf20Sopenharmony_ci
5178c2ecf20Sopenharmony_ci	i2c_set_clientdata(client, adnp);
5188c2ecf20Sopenharmony_ci
5198c2ecf20Sopenharmony_ci	return 0;
5208c2ecf20Sopenharmony_ci}
5218c2ecf20Sopenharmony_ci
5228c2ecf20Sopenharmony_cistatic const struct i2c_device_id adnp_i2c_id[] = {
5238c2ecf20Sopenharmony_ci	{ "gpio-adnp" },
5248c2ecf20Sopenharmony_ci	{ },
5258c2ecf20Sopenharmony_ci};
5268c2ecf20Sopenharmony_ciMODULE_DEVICE_TABLE(i2c, adnp_i2c_id);
5278c2ecf20Sopenharmony_ci
5288c2ecf20Sopenharmony_cistatic const struct of_device_id adnp_of_match[] = {
5298c2ecf20Sopenharmony_ci	{ .compatible = "ad,gpio-adnp", },
5308c2ecf20Sopenharmony_ci	{ },
5318c2ecf20Sopenharmony_ci};
5328c2ecf20Sopenharmony_ciMODULE_DEVICE_TABLE(of, adnp_of_match);
5338c2ecf20Sopenharmony_ci
5348c2ecf20Sopenharmony_cistatic struct i2c_driver adnp_i2c_driver = {
5358c2ecf20Sopenharmony_ci	.driver = {
5368c2ecf20Sopenharmony_ci		.name = "gpio-adnp",
5378c2ecf20Sopenharmony_ci		.of_match_table = adnp_of_match,
5388c2ecf20Sopenharmony_ci	},
5398c2ecf20Sopenharmony_ci	.probe = adnp_i2c_probe,
5408c2ecf20Sopenharmony_ci	.id_table = adnp_i2c_id,
5418c2ecf20Sopenharmony_ci};
5428c2ecf20Sopenharmony_cimodule_i2c_driver(adnp_i2c_driver);
5438c2ecf20Sopenharmony_ci
5448c2ecf20Sopenharmony_ciMODULE_DESCRIPTION("Avionic Design N-bit GPIO expander");
5458c2ecf20Sopenharmony_ciMODULE_AUTHOR("Thierry Reding <thierry.reding@avionic-design.de>");
5468c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL");
547