162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * Copyright (C) 2011-2012 Avionic Design GmbH 462306a36Sopenharmony_ci */ 562306a36Sopenharmony_ci 662306a36Sopenharmony_ci#include <linux/gpio/driver.h> 762306a36Sopenharmony_ci#include <linux/i2c.h> 862306a36Sopenharmony_ci#include <linux/interrupt.h> 962306a36Sopenharmony_ci#include <linux/mod_devicetable.h> 1062306a36Sopenharmony_ci#include <linux/module.h> 1162306a36Sopenharmony_ci#include <linux/property.h> 1262306a36Sopenharmony_ci#include <linux/seq_file.h> 1362306a36Sopenharmony_ci#include <linux/slab.h> 1462306a36Sopenharmony_ci 1562306a36Sopenharmony_ci#define GPIO_DDR(gpio) (0x00 << (gpio)->reg_shift) 1662306a36Sopenharmony_ci#define GPIO_PLR(gpio) (0x01 << (gpio)->reg_shift) 1762306a36Sopenharmony_ci#define GPIO_IER(gpio) (0x02 << (gpio)->reg_shift) 1862306a36Sopenharmony_ci#define GPIO_ISR(gpio) (0x03 << (gpio)->reg_shift) 1962306a36Sopenharmony_ci#define GPIO_PTR(gpio) (0x04 << (gpio)->reg_shift) 2062306a36Sopenharmony_ci 2162306a36Sopenharmony_cistruct adnp { 2262306a36Sopenharmony_ci struct i2c_client *client; 2362306a36Sopenharmony_ci struct gpio_chip gpio; 2462306a36Sopenharmony_ci unsigned int reg_shift; 2562306a36Sopenharmony_ci 2662306a36Sopenharmony_ci struct mutex i2c_lock; 2762306a36Sopenharmony_ci struct mutex irq_lock; 2862306a36Sopenharmony_ci 2962306a36Sopenharmony_ci u8 *irq_enable; 3062306a36Sopenharmony_ci u8 *irq_level; 3162306a36Sopenharmony_ci u8 *irq_rise; 3262306a36Sopenharmony_ci u8 *irq_fall; 3362306a36Sopenharmony_ci u8 *irq_high; 3462306a36Sopenharmony_ci u8 *irq_low; 3562306a36Sopenharmony_ci}; 3662306a36Sopenharmony_ci 3762306a36Sopenharmony_cistatic int adnp_read(struct adnp *adnp, unsigned offset, uint8_t *value) 3862306a36Sopenharmony_ci{ 3962306a36Sopenharmony_ci int err; 4062306a36Sopenharmony_ci 4162306a36Sopenharmony_ci err = i2c_smbus_read_byte_data(adnp->client, offset); 4262306a36Sopenharmony_ci if (err < 0) { 4362306a36Sopenharmony_ci dev_err(adnp->gpio.parent, "%s failed: %d\n", 4462306a36Sopenharmony_ci "i2c_smbus_read_byte_data()", err); 4562306a36Sopenharmony_ci return err; 4662306a36Sopenharmony_ci } 4762306a36Sopenharmony_ci 4862306a36Sopenharmony_ci *value = err; 4962306a36Sopenharmony_ci return 0; 5062306a36Sopenharmony_ci} 5162306a36Sopenharmony_ci 5262306a36Sopenharmony_cistatic int adnp_write(struct adnp *adnp, unsigned offset, uint8_t value) 5362306a36Sopenharmony_ci{ 5462306a36Sopenharmony_ci int err; 5562306a36Sopenharmony_ci 5662306a36Sopenharmony_ci err = i2c_smbus_write_byte_data(adnp->client, offset, value); 5762306a36Sopenharmony_ci if (err < 0) { 5862306a36Sopenharmony_ci dev_err(adnp->gpio.parent, "%s failed: %d\n", 5962306a36Sopenharmony_ci "i2c_smbus_write_byte_data()", err); 6062306a36Sopenharmony_ci return err; 6162306a36Sopenharmony_ci } 6262306a36Sopenharmony_ci 6362306a36Sopenharmony_ci return 0; 6462306a36Sopenharmony_ci} 6562306a36Sopenharmony_ci 6662306a36Sopenharmony_cistatic int adnp_gpio_get(struct gpio_chip *chip, unsigned offset) 6762306a36Sopenharmony_ci{ 6862306a36Sopenharmony_ci struct adnp *adnp = gpiochip_get_data(chip); 6962306a36Sopenharmony_ci unsigned int reg = offset >> adnp->reg_shift; 7062306a36Sopenharmony_ci unsigned int pos = offset & 7; 7162306a36Sopenharmony_ci u8 value; 7262306a36Sopenharmony_ci int err; 7362306a36Sopenharmony_ci 7462306a36Sopenharmony_ci err = adnp_read(adnp, GPIO_PLR(adnp) + reg, &value); 7562306a36Sopenharmony_ci if (err < 0) 7662306a36Sopenharmony_ci return err; 7762306a36Sopenharmony_ci 7862306a36Sopenharmony_ci return (value & BIT(pos)) ? 1 : 0; 7962306a36Sopenharmony_ci} 8062306a36Sopenharmony_ci 8162306a36Sopenharmony_cistatic void __adnp_gpio_set(struct adnp *adnp, unsigned offset, int value) 8262306a36Sopenharmony_ci{ 8362306a36Sopenharmony_ci unsigned int reg = offset >> adnp->reg_shift; 8462306a36Sopenharmony_ci unsigned int pos = offset & 7; 8562306a36Sopenharmony_ci int err; 8662306a36Sopenharmony_ci u8 val; 8762306a36Sopenharmony_ci 8862306a36Sopenharmony_ci err = adnp_read(adnp, GPIO_PLR(adnp) + reg, &val); 8962306a36Sopenharmony_ci if (err < 0) 9062306a36Sopenharmony_ci return; 9162306a36Sopenharmony_ci 9262306a36Sopenharmony_ci if (value) 9362306a36Sopenharmony_ci val |= BIT(pos); 9462306a36Sopenharmony_ci else 9562306a36Sopenharmony_ci val &= ~BIT(pos); 9662306a36Sopenharmony_ci 9762306a36Sopenharmony_ci adnp_write(adnp, GPIO_PLR(adnp) + reg, val); 9862306a36Sopenharmony_ci} 9962306a36Sopenharmony_ci 10062306a36Sopenharmony_cistatic void adnp_gpio_set(struct gpio_chip *chip, unsigned offset, int value) 10162306a36Sopenharmony_ci{ 10262306a36Sopenharmony_ci struct adnp *adnp = gpiochip_get_data(chip); 10362306a36Sopenharmony_ci 10462306a36Sopenharmony_ci mutex_lock(&adnp->i2c_lock); 10562306a36Sopenharmony_ci __adnp_gpio_set(adnp, offset, value); 10662306a36Sopenharmony_ci mutex_unlock(&adnp->i2c_lock); 10762306a36Sopenharmony_ci} 10862306a36Sopenharmony_ci 10962306a36Sopenharmony_cistatic int adnp_gpio_direction_input(struct gpio_chip *chip, unsigned offset) 11062306a36Sopenharmony_ci{ 11162306a36Sopenharmony_ci struct adnp *adnp = gpiochip_get_data(chip); 11262306a36Sopenharmony_ci unsigned int reg = offset >> adnp->reg_shift; 11362306a36Sopenharmony_ci unsigned int pos = offset & 7; 11462306a36Sopenharmony_ci u8 value; 11562306a36Sopenharmony_ci int err; 11662306a36Sopenharmony_ci 11762306a36Sopenharmony_ci mutex_lock(&adnp->i2c_lock); 11862306a36Sopenharmony_ci 11962306a36Sopenharmony_ci err = adnp_read(adnp, GPIO_DDR(adnp) + reg, &value); 12062306a36Sopenharmony_ci if (err < 0) 12162306a36Sopenharmony_ci goto out; 12262306a36Sopenharmony_ci 12362306a36Sopenharmony_ci value &= ~BIT(pos); 12462306a36Sopenharmony_ci 12562306a36Sopenharmony_ci err = adnp_write(adnp, GPIO_DDR(adnp) + reg, value); 12662306a36Sopenharmony_ci if (err < 0) 12762306a36Sopenharmony_ci goto out; 12862306a36Sopenharmony_ci 12962306a36Sopenharmony_ci err = adnp_read(adnp, GPIO_DDR(adnp) + reg, &value); 13062306a36Sopenharmony_ci if (err < 0) 13162306a36Sopenharmony_ci goto out; 13262306a36Sopenharmony_ci 13362306a36Sopenharmony_ci if (value & BIT(pos)) { 13462306a36Sopenharmony_ci err = -EPERM; 13562306a36Sopenharmony_ci goto out; 13662306a36Sopenharmony_ci } 13762306a36Sopenharmony_ci 13862306a36Sopenharmony_ci err = 0; 13962306a36Sopenharmony_ci 14062306a36Sopenharmony_ciout: 14162306a36Sopenharmony_ci mutex_unlock(&adnp->i2c_lock); 14262306a36Sopenharmony_ci return err; 14362306a36Sopenharmony_ci} 14462306a36Sopenharmony_ci 14562306a36Sopenharmony_cistatic int adnp_gpio_direction_output(struct gpio_chip *chip, unsigned offset, 14662306a36Sopenharmony_ci int value) 14762306a36Sopenharmony_ci{ 14862306a36Sopenharmony_ci struct adnp *adnp = gpiochip_get_data(chip); 14962306a36Sopenharmony_ci unsigned int reg = offset >> adnp->reg_shift; 15062306a36Sopenharmony_ci unsigned int pos = offset & 7; 15162306a36Sopenharmony_ci int err; 15262306a36Sopenharmony_ci u8 val; 15362306a36Sopenharmony_ci 15462306a36Sopenharmony_ci mutex_lock(&adnp->i2c_lock); 15562306a36Sopenharmony_ci 15662306a36Sopenharmony_ci err = adnp_read(adnp, GPIO_DDR(adnp) + reg, &val); 15762306a36Sopenharmony_ci if (err < 0) 15862306a36Sopenharmony_ci goto out; 15962306a36Sopenharmony_ci 16062306a36Sopenharmony_ci val |= BIT(pos); 16162306a36Sopenharmony_ci 16262306a36Sopenharmony_ci err = adnp_write(adnp, GPIO_DDR(adnp) + reg, val); 16362306a36Sopenharmony_ci if (err < 0) 16462306a36Sopenharmony_ci goto out; 16562306a36Sopenharmony_ci 16662306a36Sopenharmony_ci err = adnp_read(adnp, GPIO_DDR(adnp) + reg, &val); 16762306a36Sopenharmony_ci if (err < 0) 16862306a36Sopenharmony_ci goto out; 16962306a36Sopenharmony_ci 17062306a36Sopenharmony_ci if (!(val & BIT(pos))) { 17162306a36Sopenharmony_ci err = -EPERM; 17262306a36Sopenharmony_ci goto out; 17362306a36Sopenharmony_ci } 17462306a36Sopenharmony_ci 17562306a36Sopenharmony_ci __adnp_gpio_set(adnp, offset, value); 17662306a36Sopenharmony_ci err = 0; 17762306a36Sopenharmony_ci 17862306a36Sopenharmony_ciout: 17962306a36Sopenharmony_ci mutex_unlock(&adnp->i2c_lock); 18062306a36Sopenharmony_ci return err; 18162306a36Sopenharmony_ci} 18262306a36Sopenharmony_ci 18362306a36Sopenharmony_cistatic void adnp_gpio_dbg_show(struct seq_file *s, struct gpio_chip *chip) 18462306a36Sopenharmony_ci{ 18562306a36Sopenharmony_ci struct adnp *adnp = gpiochip_get_data(chip); 18662306a36Sopenharmony_ci unsigned int num_regs = 1 << adnp->reg_shift, i, j; 18762306a36Sopenharmony_ci int err; 18862306a36Sopenharmony_ci 18962306a36Sopenharmony_ci for (i = 0; i < num_regs; i++) { 19062306a36Sopenharmony_ci u8 ddr, plr, ier, isr; 19162306a36Sopenharmony_ci 19262306a36Sopenharmony_ci mutex_lock(&adnp->i2c_lock); 19362306a36Sopenharmony_ci 19462306a36Sopenharmony_ci err = adnp_read(adnp, GPIO_DDR(adnp) + i, &ddr); 19562306a36Sopenharmony_ci if (err < 0) 19662306a36Sopenharmony_ci goto unlock; 19762306a36Sopenharmony_ci 19862306a36Sopenharmony_ci err = adnp_read(adnp, GPIO_PLR(adnp) + i, &plr); 19962306a36Sopenharmony_ci if (err < 0) 20062306a36Sopenharmony_ci goto unlock; 20162306a36Sopenharmony_ci 20262306a36Sopenharmony_ci err = adnp_read(adnp, GPIO_IER(adnp) + i, &ier); 20362306a36Sopenharmony_ci if (err < 0) 20462306a36Sopenharmony_ci goto unlock; 20562306a36Sopenharmony_ci 20662306a36Sopenharmony_ci err = adnp_read(adnp, GPIO_ISR(adnp) + i, &isr); 20762306a36Sopenharmony_ci if (err < 0) 20862306a36Sopenharmony_ci goto unlock; 20962306a36Sopenharmony_ci 21062306a36Sopenharmony_ci mutex_unlock(&adnp->i2c_lock); 21162306a36Sopenharmony_ci 21262306a36Sopenharmony_ci for (j = 0; j < 8; j++) { 21362306a36Sopenharmony_ci unsigned int bit = (i << adnp->reg_shift) + j; 21462306a36Sopenharmony_ci const char *direction = "input "; 21562306a36Sopenharmony_ci const char *level = "low "; 21662306a36Sopenharmony_ci const char *interrupt = "disabled"; 21762306a36Sopenharmony_ci const char *pending = ""; 21862306a36Sopenharmony_ci 21962306a36Sopenharmony_ci if (ddr & BIT(j)) 22062306a36Sopenharmony_ci direction = "output"; 22162306a36Sopenharmony_ci 22262306a36Sopenharmony_ci if (plr & BIT(j)) 22362306a36Sopenharmony_ci level = "high"; 22462306a36Sopenharmony_ci 22562306a36Sopenharmony_ci if (ier & BIT(j)) 22662306a36Sopenharmony_ci interrupt = "enabled "; 22762306a36Sopenharmony_ci 22862306a36Sopenharmony_ci if (isr & BIT(j)) 22962306a36Sopenharmony_ci pending = "pending"; 23062306a36Sopenharmony_ci 23162306a36Sopenharmony_ci seq_printf(s, "%2u: %s %s IRQ %s %s\n", bit, 23262306a36Sopenharmony_ci direction, level, interrupt, pending); 23362306a36Sopenharmony_ci } 23462306a36Sopenharmony_ci } 23562306a36Sopenharmony_ci 23662306a36Sopenharmony_ci return; 23762306a36Sopenharmony_ci 23862306a36Sopenharmony_ciunlock: 23962306a36Sopenharmony_ci mutex_unlock(&adnp->i2c_lock); 24062306a36Sopenharmony_ci} 24162306a36Sopenharmony_ci 24262306a36Sopenharmony_cistatic irqreturn_t adnp_irq(int irq, void *data) 24362306a36Sopenharmony_ci{ 24462306a36Sopenharmony_ci struct adnp *adnp = data; 24562306a36Sopenharmony_ci unsigned int num_regs, i; 24662306a36Sopenharmony_ci 24762306a36Sopenharmony_ci num_regs = 1 << adnp->reg_shift; 24862306a36Sopenharmony_ci 24962306a36Sopenharmony_ci for (i = 0; i < num_regs; i++) { 25062306a36Sopenharmony_ci unsigned int base = i << adnp->reg_shift, bit; 25162306a36Sopenharmony_ci u8 changed, level, isr, ier; 25262306a36Sopenharmony_ci unsigned long pending; 25362306a36Sopenharmony_ci int err; 25462306a36Sopenharmony_ci 25562306a36Sopenharmony_ci mutex_lock(&adnp->i2c_lock); 25662306a36Sopenharmony_ci 25762306a36Sopenharmony_ci err = adnp_read(adnp, GPIO_PLR(adnp) + i, &level); 25862306a36Sopenharmony_ci if (err < 0) { 25962306a36Sopenharmony_ci mutex_unlock(&adnp->i2c_lock); 26062306a36Sopenharmony_ci continue; 26162306a36Sopenharmony_ci } 26262306a36Sopenharmony_ci 26362306a36Sopenharmony_ci err = adnp_read(adnp, GPIO_ISR(adnp) + i, &isr); 26462306a36Sopenharmony_ci if (err < 0) { 26562306a36Sopenharmony_ci mutex_unlock(&adnp->i2c_lock); 26662306a36Sopenharmony_ci continue; 26762306a36Sopenharmony_ci } 26862306a36Sopenharmony_ci 26962306a36Sopenharmony_ci err = adnp_read(adnp, GPIO_IER(adnp) + i, &ier); 27062306a36Sopenharmony_ci if (err < 0) { 27162306a36Sopenharmony_ci mutex_unlock(&adnp->i2c_lock); 27262306a36Sopenharmony_ci continue; 27362306a36Sopenharmony_ci } 27462306a36Sopenharmony_ci 27562306a36Sopenharmony_ci mutex_unlock(&adnp->i2c_lock); 27662306a36Sopenharmony_ci 27762306a36Sopenharmony_ci /* determine pins that changed levels */ 27862306a36Sopenharmony_ci changed = level ^ adnp->irq_level[i]; 27962306a36Sopenharmony_ci 28062306a36Sopenharmony_ci /* compute edge-triggered interrupts */ 28162306a36Sopenharmony_ci pending = changed & ((adnp->irq_fall[i] & ~level) | 28262306a36Sopenharmony_ci (adnp->irq_rise[i] & level)); 28362306a36Sopenharmony_ci 28462306a36Sopenharmony_ci /* add in level-triggered interrupts */ 28562306a36Sopenharmony_ci pending |= (adnp->irq_high[i] & level) | 28662306a36Sopenharmony_ci (adnp->irq_low[i] & ~level); 28762306a36Sopenharmony_ci 28862306a36Sopenharmony_ci /* mask out non-pending and disabled interrupts */ 28962306a36Sopenharmony_ci pending &= isr & ier; 29062306a36Sopenharmony_ci 29162306a36Sopenharmony_ci for_each_set_bit(bit, &pending, 8) { 29262306a36Sopenharmony_ci unsigned int child_irq; 29362306a36Sopenharmony_ci child_irq = irq_find_mapping(adnp->gpio.irq.domain, 29462306a36Sopenharmony_ci base + bit); 29562306a36Sopenharmony_ci handle_nested_irq(child_irq); 29662306a36Sopenharmony_ci } 29762306a36Sopenharmony_ci } 29862306a36Sopenharmony_ci 29962306a36Sopenharmony_ci return IRQ_HANDLED; 30062306a36Sopenharmony_ci} 30162306a36Sopenharmony_ci 30262306a36Sopenharmony_cistatic void adnp_irq_mask(struct irq_data *d) 30362306a36Sopenharmony_ci{ 30462306a36Sopenharmony_ci struct gpio_chip *gc = irq_data_get_irq_chip_data(d); 30562306a36Sopenharmony_ci struct adnp *adnp = gpiochip_get_data(gc); 30662306a36Sopenharmony_ci unsigned int reg = d->hwirq >> adnp->reg_shift; 30762306a36Sopenharmony_ci unsigned int pos = d->hwirq & 7; 30862306a36Sopenharmony_ci 30962306a36Sopenharmony_ci adnp->irq_enable[reg] &= ~BIT(pos); 31062306a36Sopenharmony_ci gpiochip_disable_irq(gc, irqd_to_hwirq(d)); 31162306a36Sopenharmony_ci} 31262306a36Sopenharmony_ci 31362306a36Sopenharmony_cistatic void adnp_irq_unmask(struct irq_data *d) 31462306a36Sopenharmony_ci{ 31562306a36Sopenharmony_ci struct gpio_chip *gc = irq_data_get_irq_chip_data(d); 31662306a36Sopenharmony_ci struct adnp *adnp = gpiochip_get_data(gc); 31762306a36Sopenharmony_ci unsigned int reg = d->hwirq >> adnp->reg_shift; 31862306a36Sopenharmony_ci unsigned int pos = d->hwirq & 7; 31962306a36Sopenharmony_ci 32062306a36Sopenharmony_ci gpiochip_enable_irq(gc, irqd_to_hwirq(d)); 32162306a36Sopenharmony_ci adnp->irq_enable[reg] |= BIT(pos); 32262306a36Sopenharmony_ci} 32362306a36Sopenharmony_ci 32462306a36Sopenharmony_cistatic int adnp_irq_set_type(struct irq_data *d, unsigned int type) 32562306a36Sopenharmony_ci{ 32662306a36Sopenharmony_ci struct gpio_chip *gc = irq_data_get_irq_chip_data(d); 32762306a36Sopenharmony_ci struct adnp *adnp = gpiochip_get_data(gc); 32862306a36Sopenharmony_ci unsigned int reg = d->hwirq >> adnp->reg_shift; 32962306a36Sopenharmony_ci unsigned int pos = d->hwirq & 7; 33062306a36Sopenharmony_ci 33162306a36Sopenharmony_ci if (type & IRQ_TYPE_EDGE_RISING) 33262306a36Sopenharmony_ci adnp->irq_rise[reg] |= BIT(pos); 33362306a36Sopenharmony_ci else 33462306a36Sopenharmony_ci adnp->irq_rise[reg] &= ~BIT(pos); 33562306a36Sopenharmony_ci 33662306a36Sopenharmony_ci if (type & IRQ_TYPE_EDGE_FALLING) 33762306a36Sopenharmony_ci adnp->irq_fall[reg] |= BIT(pos); 33862306a36Sopenharmony_ci else 33962306a36Sopenharmony_ci adnp->irq_fall[reg] &= ~BIT(pos); 34062306a36Sopenharmony_ci 34162306a36Sopenharmony_ci if (type & IRQ_TYPE_LEVEL_HIGH) 34262306a36Sopenharmony_ci adnp->irq_high[reg] |= BIT(pos); 34362306a36Sopenharmony_ci else 34462306a36Sopenharmony_ci adnp->irq_high[reg] &= ~BIT(pos); 34562306a36Sopenharmony_ci 34662306a36Sopenharmony_ci if (type & IRQ_TYPE_LEVEL_LOW) 34762306a36Sopenharmony_ci adnp->irq_low[reg] |= BIT(pos); 34862306a36Sopenharmony_ci else 34962306a36Sopenharmony_ci adnp->irq_low[reg] &= ~BIT(pos); 35062306a36Sopenharmony_ci 35162306a36Sopenharmony_ci return 0; 35262306a36Sopenharmony_ci} 35362306a36Sopenharmony_ci 35462306a36Sopenharmony_cistatic void adnp_irq_bus_lock(struct irq_data *d) 35562306a36Sopenharmony_ci{ 35662306a36Sopenharmony_ci struct gpio_chip *gc = irq_data_get_irq_chip_data(d); 35762306a36Sopenharmony_ci struct adnp *adnp = gpiochip_get_data(gc); 35862306a36Sopenharmony_ci 35962306a36Sopenharmony_ci mutex_lock(&adnp->irq_lock); 36062306a36Sopenharmony_ci} 36162306a36Sopenharmony_ci 36262306a36Sopenharmony_cistatic void adnp_irq_bus_unlock(struct irq_data *d) 36362306a36Sopenharmony_ci{ 36462306a36Sopenharmony_ci struct gpio_chip *gc = irq_data_get_irq_chip_data(d); 36562306a36Sopenharmony_ci struct adnp *adnp = gpiochip_get_data(gc); 36662306a36Sopenharmony_ci unsigned int num_regs = 1 << adnp->reg_shift, i; 36762306a36Sopenharmony_ci 36862306a36Sopenharmony_ci mutex_lock(&adnp->i2c_lock); 36962306a36Sopenharmony_ci 37062306a36Sopenharmony_ci for (i = 0; i < num_regs; i++) 37162306a36Sopenharmony_ci adnp_write(adnp, GPIO_IER(adnp) + i, adnp->irq_enable[i]); 37262306a36Sopenharmony_ci 37362306a36Sopenharmony_ci mutex_unlock(&adnp->i2c_lock); 37462306a36Sopenharmony_ci mutex_unlock(&adnp->irq_lock); 37562306a36Sopenharmony_ci} 37662306a36Sopenharmony_ci 37762306a36Sopenharmony_cistatic const struct irq_chip adnp_irq_chip = { 37862306a36Sopenharmony_ci .name = "gpio-adnp", 37962306a36Sopenharmony_ci .irq_mask = adnp_irq_mask, 38062306a36Sopenharmony_ci .irq_unmask = adnp_irq_unmask, 38162306a36Sopenharmony_ci .irq_set_type = adnp_irq_set_type, 38262306a36Sopenharmony_ci .irq_bus_lock = adnp_irq_bus_lock, 38362306a36Sopenharmony_ci .irq_bus_sync_unlock = adnp_irq_bus_unlock, 38462306a36Sopenharmony_ci .flags = IRQCHIP_IMMUTABLE, 38562306a36Sopenharmony_ci GPIOCHIP_IRQ_RESOURCE_HELPERS, 38662306a36Sopenharmony_ci}; 38762306a36Sopenharmony_ci 38862306a36Sopenharmony_cistatic int adnp_irq_setup(struct adnp *adnp) 38962306a36Sopenharmony_ci{ 39062306a36Sopenharmony_ci unsigned int num_regs = 1 << adnp->reg_shift, i; 39162306a36Sopenharmony_ci struct gpio_chip *chip = &adnp->gpio; 39262306a36Sopenharmony_ci int err; 39362306a36Sopenharmony_ci 39462306a36Sopenharmony_ci mutex_init(&adnp->irq_lock); 39562306a36Sopenharmony_ci 39662306a36Sopenharmony_ci /* 39762306a36Sopenharmony_ci * Allocate memory to keep track of the current level and trigger 39862306a36Sopenharmony_ci * modes of the interrupts. To avoid multiple allocations, a single 39962306a36Sopenharmony_ci * large buffer is allocated and pointers are setup to point at the 40062306a36Sopenharmony_ci * corresponding offsets. For consistency, the layout of the buffer 40162306a36Sopenharmony_ci * is chosen to match the register layout of the hardware in that 40262306a36Sopenharmony_ci * each segment contains the corresponding bits for all interrupts. 40362306a36Sopenharmony_ci */ 40462306a36Sopenharmony_ci adnp->irq_enable = devm_kcalloc(chip->parent, num_regs, 6, 40562306a36Sopenharmony_ci GFP_KERNEL); 40662306a36Sopenharmony_ci if (!adnp->irq_enable) 40762306a36Sopenharmony_ci return -ENOMEM; 40862306a36Sopenharmony_ci 40962306a36Sopenharmony_ci adnp->irq_level = adnp->irq_enable + (num_regs * 1); 41062306a36Sopenharmony_ci adnp->irq_rise = adnp->irq_enable + (num_regs * 2); 41162306a36Sopenharmony_ci adnp->irq_fall = adnp->irq_enable + (num_regs * 3); 41262306a36Sopenharmony_ci adnp->irq_high = adnp->irq_enable + (num_regs * 4); 41362306a36Sopenharmony_ci adnp->irq_low = adnp->irq_enable + (num_regs * 5); 41462306a36Sopenharmony_ci 41562306a36Sopenharmony_ci for (i = 0; i < num_regs; i++) { 41662306a36Sopenharmony_ci /* 41762306a36Sopenharmony_ci * Read the initial level of all pins to allow the emulation 41862306a36Sopenharmony_ci * of edge triggered interrupts. 41962306a36Sopenharmony_ci */ 42062306a36Sopenharmony_ci err = adnp_read(adnp, GPIO_PLR(adnp) + i, &adnp->irq_level[i]); 42162306a36Sopenharmony_ci if (err < 0) 42262306a36Sopenharmony_ci return err; 42362306a36Sopenharmony_ci 42462306a36Sopenharmony_ci /* disable all interrupts */ 42562306a36Sopenharmony_ci err = adnp_write(adnp, GPIO_IER(adnp) + i, 0); 42662306a36Sopenharmony_ci if (err < 0) 42762306a36Sopenharmony_ci return err; 42862306a36Sopenharmony_ci 42962306a36Sopenharmony_ci adnp->irq_enable[i] = 0x00; 43062306a36Sopenharmony_ci } 43162306a36Sopenharmony_ci 43262306a36Sopenharmony_ci err = devm_request_threaded_irq(chip->parent, adnp->client->irq, 43362306a36Sopenharmony_ci NULL, adnp_irq, 43462306a36Sopenharmony_ci IRQF_TRIGGER_RISING | IRQF_ONESHOT, 43562306a36Sopenharmony_ci dev_name(chip->parent), adnp); 43662306a36Sopenharmony_ci if (err != 0) { 43762306a36Sopenharmony_ci dev_err(chip->parent, "can't request IRQ#%d: %d\n", 43862306a36Sopenharmony_ci adnp->client->irq, err); 43962306a36Sopenharmony_ci return err; 44062306a36Sopenharmony_ci } 44162306a36Sopenharmony_ci 44262306a36Sopenharmony_ci return 0; 44362306a36Sopenharmony_ci} 44462306a36Sopenharmony_ci 44562306a36Sopenharmony_cistatic int adnp_gpio_setup(struct adnp *adnp, unsigned int num_gpios, 44662306a36Sopenharmony_ci bool is_irq_controller) 44762306a36Sopenharmony_ci{ 44862306a36Sopenharmony_ci struct gpio_chip *chip = &adnp->gpio; 44962306a36Sopenharmony_ci int err; 45062306a36Sopenharmony_ci 45162306a36Sopenharmony_ci adnp->reg_shift = get_count_order(num_gpios) - 3; 45262306a36Sopenharmony_ci 45362306a36Sopenharmony_ci chip->direction_input = adnp_gpio_direction_input; 45462306a36Sopenharmony_ci chip->direction_output = adnp_gpio_direction_output; 45562306a36Sopenharmony_ci chip->get = adnp_gpio_get; 45662306a36Sopenharmony_ci chip->set = adnp_gpio_set; 45762306a36Sopenharmony_ci chip->can_sleep = true; 45862306a36Sopenharmony_ci 45962306a36Sopenharmony_ci if (IS_ENABLED(CONFIG_DEBUG_FS)) 46062306a36Sopenharmony_ci chip->dbg_show = adnp_gpio_dbg_show; 46162306a36Sopenharmony_ci 46262306a36Sopenharmony_ci chip->base = -1; 46362306a36Sopenharmony_ci chip->ngpio = num_gpios; 46462306a36Sopenharmony_ci chip->label = adnp->client->name; 46562306a36Sopenharmony_ci chip->parent = &adnp->client->dev; 46662306a36Sopenharmony_ci chip->owner = THIS_MODULE; 46762306a36Sopenharmony_ci 46862306a36Sopenharmony_ci if (is_irq_controller) { 46962306a36Sopenharmony_ci struct gpio_irq_chip *girq; 47062306a36Sopenharmony_ci 47162306a36Sopenharmony_ci err = adnp_irq_setup(adnp); 47262306a36Sopenharmony_ci if (err) 47362306a36Sopenharmony_ci return err; 47462306a36Sopenharmony_ci 47562306a36Sopenharmony_ci girq = &chip->irq; 47662306a36Sopenharmony_ci gpio_irq_chip_set_chip(girq, &adnp_irq_chip); 47762306a36Sopenharmony_ci 47862306a36Sopenharmony_ci /* This will let us handle the parent IRQ in the driver */ 47962306a36Sopenharmony_ci girq->parent_handler = NULL; 48062306a36Sopenharmony_ci girq->num_parents = 0; 48162306a36Sopenharmony_ci girq->parents = NULL; 48262306a36Sopenharmony_ci girq->default_type = IRQ_TYPE_NONE; 48362306a36Sopenharmony_ci girq->handler = handle_simple_irq; 48462306a36Sopenharmony_ci girq->threaded = true; 48562306a36Sopenharmony_ci } 48662306a36Sopenharmony_ci 48762306a36Sopenharmony_ci err = devm_gpiochip_add_data(&adnp->client->dev, chip, adnp); 48862306a36Sopenharmony_ci if (err) 48962306a36Sopenharmony_ci return err; 49062306a36Sopenharmony_ci 49162306a36Sopenharmony_ci return 0; 49262306a36Sopenharmony_ci} 49362306a36Sopenharmony_ci 49462306a36Sopenharmony_cistatic int adnp_i2c_probe(struct i2c_client *client) 49562306a36Sopenharmony_ci{ 49662306a36Sopenharmony_ci struct device *dev = &client->dev; 49762306a36Sopenharmony_ci struct adnp *adnp; 49862306a36Sopenharmony_ci u32 num_gpios; 49962306a36Sopenharmony_ci int err; 50062306a36Sopenharmony_ci 50162306a36Sopenharmony_ci err = device_property_read_u32(dev, "nr-gpios", &num_gpios); 50262306a36Sopenharmony_ci if (err < 0) 50362306a36Sopenharmony_ci return err; 50462306a36Sopenharmony_ci 50562306a36Sopenharmony_ci adnp = devm_kzalloc(&client->dev, sizeof(*adnp), GFP_KERNEL); 50662306a36Sopenharmony_ci if (!adnp) 50762306a36Sopenharmony_ci return -ENOMEM; 50862306a36Sopenharmony_ci 50962306a36Sopenharmony_ci mutex_init(&adnp->i2c_lock); 51062306a36Sopenharmony_ci adnp->client = client; 51162306a36Sopenharmony_ci 51262306a36Sopenharmony_ci err = adnp_gpio_setup(adnp, num_gpios, device_property_read_bool(dev, "interrupt-controller")); 51362306a36Sopenharmony_ci if (err) 51462306a36Sopenharmony_ci return err; 51562306a36Sopenharmony_ci 51662306a36Sopenharmony_ci i2c_set_clientdata(client, adnp); 51762306a36Sopenharmony_ci 51862306a36Sopenharmony_ci return 0; 51962306a36Sopenharmony_ci} 52062306a36Sopenharmony_ci 52162306a36Sopenharmony_cistatic const struct i2c_device_id adnp_i2c_id[] = { 52262306a36Sopenharmony_ci { "gpio-adnp" }, 52362306a36Sopenharmony_ci { }, 52462306a36Sopenharmony_ci}; 52562306a36Sopenharmony_ciMODULE_DEVICE_TABLE(i2c, adnp_i2c_id); 52662306a36Sopenharmony_ci 52762306a36Sopenharmony_cistatic const struct of_device_id adnp_of_match[] = { 52862306a36Sopenharmony_ci { .compatible = "ad,gpio-adnp", }, 52962306a36Sopenharmony_ci { }, 53062306a36Sopenharmony_ci}; 53162306a36Sopenharmony_ciMODULE_DEVICE_TABLE(of, adnp_of_match); 53262306a36Sopenharmony_ci 53362306a36Sopenharmony_cistatic struct i2c_driver adnp_i2c_driver = { 53462306a36Sopenharmony_ci .driver = { 53562306a36Sopenharmony_ci .name = "gpio-adnp", 53662306a36Sopenharmony_ci .of_match_table = adnp_of_match, 53762306a36Sopenharmony_ci }, 53862306a36Sopenharmony_ci .probe = adnp_i2c_probe, 53962306a36Sopenharmony_ci .id_table = adnp_i2c_id, 54062306a36Sopenharmony_ci}; 54162306a36Sopenharmony_cimodule_i2c_driver(adnp_i2c_driver); 54262306a36Sopenharmony_ci 54362306a36Sopenharmony_ciMODULE_DESCRIPTION("Avionic Design N-bit GPIO expander"); 54462306a36Sopenharmony_ciMODULE_AUTHOR("Thierry Reding <thierry.reding@avionic-design.de>"); 54562306a36Sopenharmony_ciMODULE_LICENSE("GPL"); 546