// SPDX-License-Identifier: GPL-2.0-only
/*
* Awinic AW9523B i2c pin controller driver
* Copyright ( c ) 2020 , AngeloGioacchino Del Regno < angelogioacchino . delregno @ somainline . org >
*/
#include <linux/bitfield.h>
#include <linux/errno.h>
#include <linux/gpio/consumer.h>
#include <linux/gpio/driver.h>
#include <linux/i2c.h>
#include <linux/init.h>
#include <linux/interrupt.h>
#include <linux/irq.h>
#include <linux/module.h>
#include <linux/mutex.h>
#include <linux/property.h>
#include <linux/regmap.h>
#include <linux/regulator/consumer.h>
#include <linux/slab.h>
#include <linux/pinctrl/pinconf-generic.h>
#include <linux/pinctrl/pinconf.h>
#include <linux/pinctrl/pinctrl.h>
#include <linux/pinctrl/pinmux.h>
#define AW9523_MAX_FUNCS 2
#define AW9523_NUM_PORTS 2
#define AW9523_PINS_PER_PORT 8
/*
* HW needs at least 20 uS for reset and at least 1 - 2 uS to recover from
* reset , but we have to account for eventual board quirks , if any :
* for this reason , keep reset asserted for 50 uS and wait for 20 uS
* to recover from the reset .
*/
#define AW9523_HW_RESET_US 50
#define AW9523_HW_RESET_RECOVERY_US 20
/* Port 0: P0_0...P0_7 - Port 1: P1_0...P1_7 */
#define AW9523_PIN_TO_PORT(pin) (pin >> 3 )
#define AW9523_REG_IN_STATE(pin) (0 x00 + AW9523_PIN_TO_PORT(pin))
#define AW9523_REG_OUT_STATE(pin) (0 x02 + AW9523_PIN_TO_PORT(pin))
#define AW9523_REG_CONF_STATE(pin) (0 x04 + AW9523_PIN_TO_PORT(pin))
#define AW9523_REG_INTR_DIS(pin) (0 x06 + AW9523_PIN_TO_PORT(pin))
#define AW9523_REG_CHIPID 0 x10
#define AW9523_VAL_EXPECTED_CHIPID 0 x23
#define AW9523_REG_GCR 0 x11
#define AW9523_GCR_ISEL_MASK GENMASK(0 , 1 )
#define AW9523_GCR_GPOMD_MASK BIT(4 )
#define AW9523_REG_PORT_MODE(pin) (0 x12 + AW9523_PIN_TO_PORT(pin))
#define AW9523_REG_SOFT_RESET 0 x7f
#define AW9523_VAL_RESET 0 x00
/*
* struct aw9523_irq - Interrupt controller structure
* @ lock : mutex locking for the irq bus
* @ cached_gpio : stores the previous gpio status for bit comparison
*/
struct aw9523_irq {
struct mutex lock;
u16 cached_gpio;
};
/*
* struct aw9523 - Main driver structure
* @ dev : device handle
* @ regmap : regmap handle for current device
* @ i2c_lock : Mutex lock for i2c operations
* @ reset_gpio : Hardware reset ( RSTN ) signal GPIO
* @ vio_vreg : VCC regulator ( Optional )
* @ pctl : pinctrl handle for current device
* @ gpio : structure holding gpiochip params
* @ irq : Interrupt controller structure
*/
struct aw9523 {
struct device *dev;
struct regmap *regmap;
struct mutex i2c_lock;
struct gpio_desc *reset_gpio;
int vio_vreg;
struct pinctrl_dev *pctl;
struct gpio_chip gpio;
struct aw9523_irq *irq;
};
static const struct pinctrl_pin_desc aw9523_pins[] = {
/* Port 0 */
PINCTRL_PIN(0 , "gpio0" ),
PINCTRL_PIN(1 , "gpio1" ),
PINCTRL_PIN(2 , "gpio2" ),
PINCTRL_PIN(3 , "gpio3" ),
PINCTRL_PIN(4 , "gpio4" ),
PINCTRL_PIN(5 , "gpio5" ),
PINCTRL_PIN(6 , "gpio6" ),
PINCTRL_PIN(7 , "gpio7" ),
/* Port 1 */
PINCTRL_PIN(8 , "gpio8" ),
PINCTRL_PIN(9 , "gpio9" ),
PINCTRL_PIN(10 , "gpio10" ),
PINCTRL_PIN(11 , "gpio11" ),
PINCTRL_PIN(12 , "gpio12" ),
PINCTRL_PIN(13 , "gpio13" ),
PINCTRL_PIN(14 , "gpio14" ),
PINCTRL_PIN(15 , "gpio15" ),
};
static int aw9523_pinctrl_get_groups_count(struct pinctrl_dev *pctldev)
{
return ARRAY_SIZE(aw9523_pins);
}
static const char *aw9523_pinctrl_get_group_name(struct pinctrl_dev *pctldev,
unsigned int selector)
{
return aw9523_pins[selector].name;
}
static int aw9523_pinctrl_get_group_pins(struct pinctrl_dev *pctldev,
unsigned int selector,
const unsigned int **pins,
unsigned int *num_pins)
{
*pins = &aw9523_pins[selector].number;
*num_pins = 1 ;
return 0 ;
}
static const struct pinctrl_ops aw9523_pinctrl_ops = {
.get_groups_count = aw9523_pinctrl_get_groups_count,
.get_group_pins = aw9523_pinctrl_get_group_pins,
.get_group_name = aw9523_pinctrl_get_group_name,
.dt_node_to_map = pinconf_generic_dt_node_to_map_pin,
.dt_free_map = pinconf_generic_dt_free_map,
};
static const char * const gpio_pwm_groups[] = {
"gpio0" , "gpio1" , "gpio2" , "gpio3" , /* 0-3 */
"gpio4" , "gpio5" , "gpio6" , "gpio7" , /* 4-7 */
"gpio8" , "gpio9" , "gpio10" , "gpio11" , /* 8-11 */
"gpio12" , "gpio13" , "gpio14" , "gpio15" , /* 11-15 */
};
/* Warning: Do NOT reorder this array */
static const struct pinfunction aw9523_pmx[] = {
PINCTRL_PINFUNCTION("pwm" , gpio_pwm_groups, ARRAY_SIZE(gpio_pwm_groups)),
PINCTRL_PINFUNCTION("gpio" , gpio_pwm_groups, ARRAY_SIZE(gpio_pwm_groups)),
};
static int aw9523_pmx_get_funcs_count(struct pinctrl_dev *pctl)
{
return ARRAY_SIZE(aw9523_pmx);
}
static const char *aw9523_pmx_get_fname(struct pinctrl_dev *pctl,
unsigned int sel)
{
return aw9523_pmx[sel].name;
}
static int aw9523_pmx_get_groups(struct pinctrl_dev *pctl, unsigned int sel,
const char * const **groups,
unsigned int * const ngroups)
{
*groups = aw9523_pmx[sel].groups;
*ngroups = aw9523_pmx[sel].ngroups;
return 0 ;
}
static int aw9523_pmx_set_mux(struct pinctrl_dev *pctl, unsigned int fsel,
unsigned int grp)
{
struct aw9523 *awi = pinctrl_dev_get_drvdata(pctl);
int ret, pin = aw9523_pins[grp].number % AW9523_PINS_PER_PORT;
if (fsel >= ARRAY_SIZE(aw9523_pmx))
return -EINVAL;
/*
* This maps directly to the aw9523_pmx array : programming a
* high bit means " gpio " and a low bit means " pwm " .
*/
mutex_lock(&awi->i2c_lock);
ret = regmap_update_bits(awi->regmap, AW9523_REG_PORT_MODE(pin),
BIT(pin), (fsel ? BIT(pin) : 0 ));
mutex_unlock(&awi->i2c_lock);
return ret;
}
static const struct pinmux_ops aw9523_pinmux_ops = {
.get_functions_count = aw9523_pmx_get_funcs_count,
.get_function_name = aw9523_pmx_get_fname,
.get_function_groups = aw9523_pmx_get_groups,
.set_mux = aw9523_pmx_set_mux,
};
static int aw9523_pcfg_param_to_reg(enum pin_config_param pcp, int pin, u8 *r)
{
u8 reg;
switch (pcp) {
case PIN_CONFIG_BIAS_PULL_PIN_DEFAULT:
case PIN_CONFIG_BIAS_PULL_DOWN:
case PIN_CONFIG_BIAS_PULL_UP:
reg = AW9523_REG_IN_STATE(pin);
break ;
case PIN_CONFIG_DRIVE_OPEN_DRAIN:
case PIN_CONFIG_DRIVE_PUSH_PULL:
reg = AW9523_REG_GCR;
break ;
case PIN_CONFIG_INPUT_ENABLE:
case PIN_CONFIG_OUTPUT_ENABLE:
reg = AW9523_REG_CONF_STATE(pin);
break ;
case PIN_CONFIG_OUTPUT:
reg = AW9523_REG_OUT_STATE(pin);
break ;
default :
return -ENOTSUPP;
}
*r = reg;
return 0 ;
}
static int aw9523_pconf_get(struct pinctrl_dev *pctldev, unsigned int pin,
unsigned long *config)
{
struct aw9523 *awi = pinctrl_dev_get_drvdata(pctldev);
enum pin_config_param param = pinconf_to_config_param(*config);
int regbit = pin % AW9523_PINS_PER_PORT;
unsigned int val;
u8 reg;
int rc;
rc = aw9523_pcfg_param_to_reg(param, pin, ®);
if (rc)
return rc;
mutex_lock(&awi->i2c_lock);
rc = regmap_read(awi->regmap, reg, &val);
mutex_unlock(&awi->i2c_lock);
if (rc)
return rc;
switch (param) {
case PIN_CONFIG_BIAS_PULL_UP:
case PIN_CONFIG_INPUT_ENABLE:
case PIN_CONFIG_OUTPUT:
val &= BIT(regbit);
break ;
case PIN_CONFIG_BIAS_PULL_DOWN:
case PIN_CONFIG_OUTPUT_ENABLE:
val &= BIT(regbit);
val = !val;
break ;
case PIN_CONFIG_DRIVE_OPEN_DRAIN:
if (pin >= AW9523_PINS_PER_PORT)
val = 0 ;
else
val = !FIELD_GET(AW9523_GCR_GPOMD_MASK, val);
break ;
case PIN_CONFIG_DRIVE_PUSH_PULL:
if (pin >= AW9523_PINS_PER_PORT)
val = 1 ;
else
val = FIELD_GET(AW9523_GCR_GPOMD_MASK, val);
break ;
default :
return -ENOTSUPP;
}
if (val < 1 )
return -EINVAL;
*config = pinconf_to_config_packed(param, !!val);
return rc;
}
static int aw9523_pconf_set(struct pinctrl_dev *pctldev, unsigned int pin,
unsigned long *configs, unsigned int num_configs)
{
struct aw9523 *awi = pinctrl_dev_get_drvdata(pctldev);
enum pin_config_param param;
int regbit = pin % AW9523_PINS_PER_PORT;
u32 arg;
u8 reg;
unsigned int mask, val;
int i, rc;
mutex_lock(&awi->i2c_lock);
for (i = 0 ; i < num_configs; i++) {
param = pinconf_to_config_param(configs[i]);
arg = pinconf_to_config_argument(configs[i]);
rc = aw9523_pcfg_param_to_reg(param, pin, ®);
if (rc)
goto end;
switch (param) {
case PIN_CONFIG_OUTPUT:
/* First, enable pin output */
rc = regmap_update_bits(awi->regmap,
AW9523_REG_CONF_STATE(pin),
BIT(regbit), 0 );
if (rc)
goto end;
/* Then, fall through to config output level */
fallthrough;
case PIN_CONFIG_OUTPUT_ENABLE:
arg = !arg;
fallthrough;
case PIN_CONFIG_BIAS_PULL_PIN_DEFAULT:
case PIN_CONFIG_BIAS_PULL_DOWN:
case PIN_CONFIG_BIAS_PULL_UP:
case PIN_CONFIG_INPUT_ENABLE:
mask = BIT(regbit);
val = arg ? BIT(regbit) : 0 ;
break ;
case PIN_CONFIG_DRIVE_OPEN_DRAIN:
/* Open-Drain is supported only on port 0 */
if (pin >= AW9523_PINS_PER_PORT) {
rc = -ENOTSUPP;
goto end;
}
mask = AW9523_GCR_GPOMD_MASK;
val = 0 ;
break ;
case PIN_CONFIG_DRIVE_PUSH_PULL:
/* Port 1 is always Push-Pull */
if (pin >= AW9523_PINS_PER_PORT) {
mask = 0 ;
val = 0 ;
continue ;
}
mask = AW9523_GCR_GPOMD_MASK;
val = AW9523_GCR_GPOMD_MASK;
break ;
default :
rc = -ENOTSUPP;
goto end;
}
rc = regmap_update_bits(awi->regmap, reg, mask, val);
if (rc)
goto end;
}
end:
mutex_unlock(&awi->i2c_lock);
return rc;
}
static const struct pinconf_ops aw9523_pinconf_ops = {
.pin_config_get = aw9523_pconf_get,
.pin_config_set = aw9523_pconf_set,
.is_generic = true ,
};
/*
* aw9523_get_pin_direction - Get pin direction
* @ regmap : Regmap structure
* @ pin : gpiolib pin number
* @ n : pin index in port register
*
* Return : Pin direction for success or negative number for error
*/
static int aw9523_get_pin_direction(struct regmap *regmap, u8 pin, u8 n)
{
int ret;
ret = regmap_test_bits(regmap, AW9523_REG_CONF_STATE(pin), BIT(n));
if (ret < 0 )
return ret;
return ret ? GPIO_LINE_DIRECTION_IN : GPIO_LINE_DIRECTION_OUT;
}
/*
* aw9523_get_port_state - Get input or output state for entire port
* @ regmap : Regmap structure
* @ pin : gpiolib pin number
* @ regbit : hw pin index , used to retrieve port number
* @ state : returned port state
*
* Return : Zero for success or negative number for error
*/
static int aw9523_get_port_state(struct regmap *regmap, u8 pin, u8 regbit,
unsigned int *state)
{
u8 reg;
int dir;
dir = aw9523_get_pin_direction(regmap, pin, regbit);
if (dir < 0 )
return dir;
if (dir == GPIO_LINE_DIRECTION_IN)
reg = AW9523_REG_IN_STATE(pin);
else
reg = AW9523_REG_OUT_STATE(pin);
return regmap_read(regmap, reg, state);
}
static int aw9523_gpio_irq_type(struct irq_data *d, unsigned int type)
{
switch (type) {
case IRQ_TYPE_NONE:
case IRQ_TYPE_EDGE_BOTH:
return 0 ;
default :
return -EINVAL;
};
}
/*
* aw9523_irq_mask - Mask interrupt
* @ d : irq data
*
* Sets which interrupt to mask in the bitmap ;
* The interrupt will be masked when unlocking the irq bus .
*/
static void aw9523_irq_mask(struct irq_data *d)
{
struct aw9523 *awi = gpiochip_get_data(irq_data_get_irq_chip_data(d));
irq_hw_number_t hwirq = irqd_to_hwirq(d);
unsigned int n = hwirq % AW9523_PINS_PER_PORT;
regmap_update_bits(awi->regmap, AW9523_REG_INTR_DIS(hwirq),
BIT(n), BIT(n));
gpiochip_disable_irq(&awi->gpio, hwirq);
}
/*
* aw9523_irq_unmask - Unmask interrupt
* @ d : irq data
*
* Sets which interrupt to unmask in the bitmap ;
* The interrupt will be masked when unlocking the irq bus .
*/
static void aw9523_irq_unmask(struct irq_data *d)
{
struct aw9523 *awi = gpiochip_get_data(irq_data_get_irq_chip_data(d));
irq_hw_number_t hwirq = irqd_to_hwirq(d);
unsigned int n = hwirq % AW9523_PINS_PER_PORT;
gpiochip_enable_irq(&awi->gpio, hwirq);
regmap_update_bits(awi->regmap, AW9523_REG_INTR_DIS(hwirq),
BIT(n), 0 );
}
static irqreturn_t aw9523_irq_thread_func(int irq, void *dev_id)
{
struct aw9523 *awi = (struct aw9523 *)dev_id;
unsigned long n, val = 0 ;
unsigned long changed_gpio;
unsigned int tmp, port_pin, i, ret;
for (i = 0 ; i < AW9523_NUM_PORTS; i++) {
port_pin = i * AW9523_PINS_PER_PORT;
ret = regmap_read(awi->regmap,
AW9523_REG_IN_STATE(port_pin),
&tmp);
if (ret)
return ret;
val |= (u8)tmp << (i * 8 );
}
/* Handle GPIO input release interrupt as well */
changed_gpio = awi->irq->cached_gpio ^ val;
awi->irq->cached_gpio = val;
/*
* To avoid up to four * slow * i2c reads from any driver hooked
* up to our interrupts , just check for the irq_find_mapping
* result : if the interrupt is not mapped , then we don ' t want
* to care about it .
*/
for_each_set_bit(n, &changed_gpio, awi->gpio.ngpio) {
tmp = irq_find_mapping(awi->gpio.irq.domain, n);
if (tmp <= 0 )
continue ;
handle_nested_irq(tmp);
}
return IRQ_HANDLED;
}
/*
* aw9523_irq_bus_lock - Grab lock for interrupt operation
* @ d : irq data
*/
static void aw9523_irq_bus_lock(struct irq_data *d)
{
struct aw9523 *awi = gpiochip_get_data(irq_data_get_irq_chip_data(d));
mutex_lock(&awi->irq->lock);
regcache_cache_only(awi->regmap, true );
}
/*
* aw9523_irq_bus_sync_unlock - Synchronize state and unlock
* @ d : irq data
*
* Writes the interrupt mask bits ( found in the bit map ) to the
* hardware , then unlocks the bus .
*/
static void aw9523_irq_bus_sync_unlock(struct irq_data *d)
{
struct aw9523 *awi = gpiochip_get_data(irq_data_get_irq_chip_data(d));
regcache_cache_only(awi->regmap, false );
regcache_sync(awi->regmap);
mutex_unlock(&awi->irq->lock);
}
static int aw9523_gpio_get_direction(struct gpio_chip *chip,
unsigned int offset)
{
struct aw9523 *awi = gpiochip_get_data(chip);
u8 regbit = offset % AW9523_PINS_PER_PORT;
int ret;
mutex_lock(&awi->i2c_lock);
ret = aw9523_get_pin_direction(awi->regmap, offset, regbit);
mutex_unlock(&awi->i2c_lock);
return ret;
}
static int aw9523_gpio_get(struct gpio_chip *chip, unsigned int offset)
{
struct aw9523 *awi = gpiochip_get_data(chip);
u8 regbit = offset % AW9523_PINS_PER_PORT;
unsigned int val;
int ret;
mutex_lock(&awi->i2c_lock);
ret = aw9523_get_port_state(awi->regmap, offset, regbit, &val);
mutex_unlock(&awi->i2c_lock);
if (ret)
return ret;
return !!(val & BIT(regbit));
}
/**
* _ aw9523_gpio_get_multiple - Get I / O state for an entire port
* @ awi : Controller data
* @ regbit : hw pin index , used to retrieve port number
* @ state : returned port I / O state
* @ mask : lines to read values for
*
* Return : Zero for success or negative number for error
*/
static int _aw9523_gpio_get_multiple(struct aw9523 *awi, u8 regbit,
u8 *state, u8 mask)
{
u32 dir_in, val;
u8 m;
int ret;
/* Registers are 8-bits wide */
ret = regmap_read(awi->regmap, AW9523_REG_CONF_STATE(regbit), &dir_in);
if (ret)
return ret;
*state = 0 ;
m = mask & dir_in;
if (m) {
ret = regmap_read(awi->regmap, AW9523_REG_IN_STATE(regbit),
&val);
if (ret)
return ret;
*state |= (u8)val & m;
}
m = mask & ~dir_in;
if (m) {
ret = regmap_read(awi->regmap, AW9523_REG_OUT_STATE(regbit),
&val);
if (ret)
return ret;
*state |= (u8)val & m;
}
return 0 ;
}
static int aw9523_gpio_get_multiple(struct gpio_chip *chip,
unsigned long *mask,
unsigned long *bits)
{
struct aw9523 *awi = gpiochip_get_data(chip);
u8 m, state = 0 ;
int ret;
mutex_lock(&awi->i2c_lock);
/* Port 0 (gpio 0-7) */
m = *mask;
if (m) {
ret = _aw9523_gpio_get_multiple(awi, 0 , &state, m);
if (ret)
goto out;
}
*bits = state;
/* Port 1 (gpio 8-15) */
m = *mask >> 8 ;
if (m) {
ret = _aw9523_gpio_get_multiple(awi, AW9523_PINS_PER_PORT,
&state, m);
if (ret)
goto out;
*bits |= (state << 8 );
}
out:
mutex_unlock(&awi->i2c_lock);
return ret;
}
static int aw9523_gpio_set_multiple(struct gpio_chip *chip,
unsigned long *mask,
unsigned long *bits)
{
struct aw9523 *awi = gpiochip_get_data(chip);
u8 mask_lo, mask_hi, bits_lo, bits_hi;
unsigned int reg;
int ret = 0 ;
mask_lo = *mask;
mask_hi = *mask >> 8 ;
bits_lo = *bits;
bits_hi = *bits >> 8 ;
mutex_lock(&awi->i2c_lock);
if (mask_hi) {
reg = AW9523_REG_OUT_STATE(AW9523_PINS_PER_PORT);
ret = regmap_write_bits(awi->regmap, reg, mask_hi, bits_hi);
if (ret)
goto out;
}
if (mask_lo) {
reg = AW9523_REG_OUT_STATE(0 );
ret = regmap_write_bits(awi->regmap, reg, mask_lo, bits_lo);
if (ret)
goto out;
}
out:
mutex_unlock(&awi->i2c_lock);
return ret;
}
static int aw9523_gpio_set(struct gpio_chip *chip, unsigned int offset,
int value)
{
struct aw9523 *awi = gpiochip_get_data(chip);
u8 regbit = offset % AW9523_PINS_PER_PORT;
int ret;
mutex_lock(&awi->i2c_lock);
ret = regmap_update_bits(awi->regmap, AW9523_REG_OUT_STATE(offset),
BIT(regbit), value ? BIT(regbit) : 0 );
mutex_unlock(&awi->i2c_lock);
return ret;
}
static int aw9523_direction_input(struct gpio_chip *chip, unsigned int offset)
{
struct aw9523 *awi = gpiochip_get_data(chip);
u8 regbit = offset % AW9523_PINS_PER_PORT;
int ret;
mutex_lock(&awi->i2c_lock);
ret = regmap_update_bits(awi->regmap, AW9523_REG_CONF_STATE(offset),
BIT(regbit), BIT(regbit));
mutex_unlock(&awi->i2c_lock);
return ret;
}
static int aw9523_direction_output(struct gpio_chip *chip,
unsigned int offset, int value)
{
struct aw9523 *awi = gpiochip_get_data(chip);
u8 regbit = offset % AW9523_PINS_PER_PORT;
int ret;
mutex_lock(&awi->i2c_lock);
ret = regmap_update_bits(awi->regmap, AW9523_REG_OUT_STATE(offset),
BIT(regbit), value ? BIT(regbit) : 0 );
if (ret)
goto end;
ret = regmap_update_bits(awi->regmap, AW9523_REG_CONF_STATE(offset),
BIT(regbit), 0 );
end:
mutex_unlock(&awi->i2c_lock);
return ret;
}
static int aw9523_drive_reset_gpio(struct aw9523 *awi)
{
unsigned int chip_id;
int ret;
/*
* If the chip is already configured for any reason , then we
* will probably succeed in sending the soft reset signal to
* the hardware through I2C : this operation takes less time
* compared to a full HW reset and it gives the same results .
*/
ret = regmap_write(awi->regmap, AW9523_REG_SOFT_RESET, 0 );
if (ret == 0 )
goto done;
dev_dbg(awi->dev, "Cannot execute soft reset: trying hard reset\n" );
ret = gpiod_direction_output(awi->reset_gpio, 0 );
if (ret)
return ret;
/* The reset pulse has to be longer than 20uS due to deglitch */
usleep_range(AW9523_HW_RESET_US, AW9523_HW_RESET_US + 1 );
ret = gpiod_direction_output(awi->reset_gpio, 1 );
if (ret)
return ret;
done:
/* The HW needs at least 1uS to reliably recover after reset */
usleep_range(AW9523_HW_RESET_RECOVERY_US,
AW9523_HW_RESET_RECOVERY_US + 1 );
/* Check the ChipID */
ret = regmap_read(awi->regmap, AW9523_REG_CHIPID, &chip_id);
if (ret) {
dev_err(awi->dev, "Cannot read Chip ID: %d\n" , ret);
return ret;
}
if (chip_id != AW9523_VAL_EXPECTED_CHIPID) {
dev_err(awi->dev, "Bad ChipID; read 0x%x, expected 0x%x\n" ,
chip_id, AW9523_VAL_EXPECTED_CHIPID);
return -EINVAL;
}
return 0 ;
}
static int aw9523_hw_reset(struct aw9523 *awi)
{
int ret, max_retries = 2 ;
/* Sometimes the chip needs more than one reset cycle */
do {
ret = aw9523_drive_reset_gpio(awi);
if (ret == 0 )
break ;
max_retries--;
} while (max_retries);
return ret;
}
static int aw9523_init_gpiochip(struct aw9523 *awi, unsigned int npins)
{
struct device *dev = awi->dev;
struct gpio_chip *gc = &awi->gpio;
gc->label = devm_kstrdup(dev, dev_name(dev), GFP_KERNEL);
if (!gc->label)
return -ENOMEM;
gc->base = -1 ;
gc->ngpio = npins;
gc->get_direction = aw9523_gpio_get_direction;
gc->direction_input = aw9523_direction_input;
gc->direction_output = aw9523_direction_output;
gc->get = aw9523_gpio_get;
gc->get_multiple = aw9523_gpio_get_multiple;
gc->set = aw9523_gpio_set;
gc->set_multiple = aw9523_gpio_set_multiple;
gc->set_config = gpiochip_generic_config;
gc->parent = dev;
gc->owner = THIS_MODULE;
gc->can_sleep = true ;
return 0 ;
}
static const struct irq_chip aw9523_irq_chip = {
.name = "aw9523" ,
.irq_mask = aw9523_irq_mask,
.irq_unmask = aw9523_irq_unmask,
.irq_bus_lock = aw9523_irq_bus_lock,
.irq_bus_sync_unlock = aw9523_irq_bus_sync_unlock,
.irq_set_type = aw9523_gpio_irq_type,
.flags = IRQCHIP_IMMUTABLE,
GPIOCHIP_IRQ_RESOURCE_HELPERS,
};
static int aw9523_init_irq(struct aw9523 *awi, int irq)
{
struct device *dev = awi->dev;
struct gpio_irq_chip *girq;
int ret;
if (!device_property_read_bool(dev, "interrupt-controller" ))
return 0 ;
awi->irq = devm_kzalloc(dev, sizeof (*awi->irq), GFP_KERNEL);
if (!awi->irq)
return -ENOMEM;
mutex_init(&awi->irq->lock);
ret = devm_request_threaded_irq(dev, irq, NULL, aw9523_irq_thread_func,
IRQF_ONESHOT, dev_name(dev), awi);
if (ret)
return dev_err_probe(dev, ret, "Failed to request irq %d\n" , irq);
girq = &awi->gpio.irq;
gpio_irq_chip_set_chip(girq, &aw9523_irq_chip);
girq->parent_handler = NULL;
girq->num_parents = 0 ;
girq->parents = NULL;
girq->default_type = IRQ_TYPE_EDGE_BOTH;
girq->handler = handle_simple_irq;
girq->threaded = true ;
return 0 ;
}
static bool aw9523_is_reg_hole(unsigned int reg)
{
return (reg > AW9523_REG_PORT_MODE(AW9523_PINS_PER_PORT) &&
reg < AW9523_REG_SOFT_RESET) ||
(reg > AW9523_REG_INTR_DIS(AW9523_PINS_PER_PORT) &&
reg < AW9523_REG_CHIPID);
}
static bool aw9523_readable_reg(struct device *dev, unsigned int reg)
{
/* All available registers (minus holes) can be read */
return !aw9523_is_reg_hole(reg);
}
static bool aw9523_volatile_reg(struct device *dev, unsigned int reg)
{
return aw9523_is_reg_hole(reg) ||
reg == AW9523_REG_IN_STATE(0 ) ||
reg == AW9523_REG_IN_STATE(AW9523_PINS_PER_PORT) ||
reg == AW9523_REG_CHIPID ||
reg == AW9523_REG_SOFT_RESET;
}
static bool aw9523_writeable_reg(struct device *dev, unsigned int reg)
{
return !aw9523_is_reg_hole(reg) && reg != AW9523_REG_CHIPID;
}
static bool aw9523_precious_reg(struct device *dev, unsigned int reg)
{
/* Reading AW9523_REG_IN_STATE clears interrupt status */
return aw9523_is_reg_hole(reg) ||
reg == AW9523_REG_IN_STATE(0 ) ||
reg == AW9523_REG_IN_STATE(AW9523_PINS_PER_PORT);
}
static const struct regmap_config aw9523_regmap = {
.reg_bits = 8 ,
.val_bits = 8 ,
.reg_stride = 1 ,
.precious_reg = aw9523_precious_reg,
.readable_reg = aw9523_readable_reg,
.volatile_reg = aw9523_volatile_reg,
.writeable_reg = aw9523_writeable_reg,
.cache_type = REGCACHE_FLAT,
.disable_locking = true ,
.num_reg_defaults_raw = AW9523_REG_SOFT_RESET,
};
static int aw9523_hw_init(struct aw9523 *awi)
{
u8 p1_pin = AW9523_PINS_PER_PORT;
unsigned int val;
int ret;
/* No register caching during initialization */
regcache_cache_bypass(awi->regmap, true );
/* Bring up the chip */
ret = aw9523_hw_reset(awi);
if (ret) {
dev_err(awi->dev, "HW Reset failed: %d\n" , ret);
return ret;
}
/*
* This is the expected chip and it is running : it ' s time to
* set a safe default configuration in case the user doesn ' t
* configure ( all of the available ) pins in this chip .
* P . S . : The writes order doesn ' t matter .
*/
/* Set all pins as GPIO */
ret = regmap_write(awi->regmap, AW9523_REG_PORT_MODE(0 ), U8_MAX);
if (ret)
return ret;
ret = regmap_write(awi->regmap, AW9523_REG_PORT_MODE(p1_pin), U8_MAX);
if (ret)
return ret;
/* Set Open-Drain mode on Port 0 (Port 1 is always P-P) */
ret = regmap_write(awi->regmap, AW9523_REG_GCR, 0 );
if (ret)
return ret;
/* Set all pins as inputs */
ret = regmap_write(awi->regmap, AW9523_REG_CONF_STATE(0 ), U8_MAX);
if (ret)
return ret;
ret = regmap_write(awi->regmap, AW9523_REG_CONF_STATE(p1_pin), U8_MAX);
if (ret)
return ret;
/* Disable all interrupts to avoid unreasoned wakeups */
ret = regmap_write(awi->regmap, AW9523_REG_INTR_DIS(0 ), U8_MAX);
if (ret)
return ret;
ret = regmap_write(awi->regmap, AW9523_REG_INTR_DIS(p1_pin), U8_MAX);
if (ret)
return ret;
/* Clear setup-generated interrupts by performing a port state read */
ret = aw9523_get_port_state(awi->regmap, 0 , 0 , &val);
if (ret)
return ret;
ret = aw9523_get_port_state(awi->regmap, p1_pin, 0 , &val);
if (ret)
return ret;
/* Everything went fine: activate and reinitialize register cache */
regcache_cache_bypass(awi->regmap, false );
return regmap_reinit_cache(awi->regmap, &aw9523_regmap);
}
static int aw9523_probe(struct i2c_client *client)
{
struct device *dev = &client->dev;
struct pinctrl_desc *pdesc;
struct aw9523 *awi;
int ret;
awi = devm_kzalloc(dev, sizeof (*awi), GFP_KERNEL);
if (!awi)
return -ENOMEM;
i2c_set_clientdata(client, awi);
awi->dev = dev;
awi->reset_gpio = devm_gpiod_get(dev, "reset" , GPIOD_OUT_HIGH);
if (IS_ERR(awi->reset_gpio))
return PTR_ERR(awi->reset_gpio);
gpiod_set_consumer_name(awi->reset_gpio, "aw9523 reset" );
awi->regmap = devm_regmap_init_i2c(client, &aw9523_regmap);
if (IS_ERR(awi->regmap))
return PTR_ERR(awi->regmap);
awi->vio_vreg = devm_regulator_get_enable_optional(dev, "vio" );
if (awi->vio_vreg && awi->vio_vreg != -ENODEV)
return awi->vio_vreg;
ret = devm_mutex_init(dev, &awi->i2c_lock);
if (ret)
return ret;
lockdep_set_subclass(&awi->i2c_lock, i2c_adapter_depth(client->adapter));
pdesc = devm_kzalloc(dev, sizeof (*pdesc), GFP_KERNEL);
if (!pdesc)
return -ENOMEM;
ret = aw9523_hw_init(awi);
if (ret)
return ret;
pdesc->name = dev_name(dev);
pdesc->owner = THIS_MODULE;
pdesc->pctlops = &aw9523_pinctrl_ops;
pdesc->pmxops = &aw9523_pinmux_ops;
pdesc->confops = &aw9523_pinconf_ops;
pdesc->pins = aw9523_pins;
pdesc->npins = ARRAY_SIZE(aw9523_pins);
ret = aw9523_init_gpiochip(awi, pdesc->npins);
if (ret)
return ret;
if (client->irq) {
ret = aw9523_init_irq(awi, client->irq);
if (ret)
return ret;
}
awi->pctl = devm_pinctrl_register(dev, pdesc, awi);
if (IS_ERR(awi->pctl))
return dev_err_probe(dev, PTR_ERR(awi->pctl),
"Cannot register pinctrl" );
return devm_gpiochip_add_data(dev, &awi->gpio, awi);
}
static void aw9523_remove(struct i2c_client *client)
{
struct aw9523 *awi = i2c_get_clientdata(client);
/*
* If the chip VIO is connected to a regulator that we can turn
* off , life is easy . . . otherwise , reinitialize the chip and
* set the pins to hardware defaults before removing the driver
* to leave it in a clean , safe and predictable state .
*/
if (awi->vio_vreg == -ENODEV) {
mutex_lock(&awi->i2c_lock);
aw9523_hw_init(awi);
mutex_unlock(&awi->i2c_lock);
}
}
static const struct i2c_device_id aw9523_i2c_id_table[] = {
{ "aw9523_i2c" },
{ }
};
MODULE_DEVICE_TABLE(i2c, aw9523_i2c_id_table);
static const struct of_device_id of_aw9523_i2c_match[] = {
{ .compatible = "awinic,aw9523-pinctrl" , },
{ }
};
MODULE_DEVICE_TABLE(of, of_aw9523_i2c_match);
static struct i2c_driver aw9523_driver = {
.driver = {
.name = "aw9523-pinctrl" ,
.of_match_table = of_aw9523_i2c_match,
},
.probe = aw9523_probe,
.remove = aw9523_remove,
.id_table = aw9523_i2c_id_table,
};
module_i2c_driver(aw9523_driver);
MODULE_DESCRIPTION("Awinic AW9523 I2C GPIO Expander driver" );
MODULE_AUTHOR("AngeloGioacchino Del Regno <angelogioacchino.delregno@somainline.org>" );
MODULE_LICENSE("GPL v2" );
Messung V0.5 in Prozent C=96 H=95 G=95
¤ Dauer der Verarbeitung: 0.21 Sekunden
(vorverarbeitet am 2026-09-28)
¤
*© Formatika GbR, Deutschland