| // 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/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/mutex.h> |
| #include <linux/module.h> |
| #include <linux/pinctrl/pinconf.h> |
| #include <linux/pinctrl/pinctrl.h> |
| #include <linux/pinctrl/pinmux.h> |
| #include <linux/pinctrl/pinconf-generic.h> |
| #include <linux/property.h> |
| #include <linux/regmap.h> |
| #include <linux/regulator/consumer.h> |
| #include <linux/slab.h> |
| |
| #define AW9523_MAX_FUNCS 2 |
| #define AW9523_NUM_PORTS 2 |
| #define AW9523_PINS_PER_PORT 8 |
| |
| /* |
| * HW needs at least 20uS for reset and at least 1-2uS to recover from |
| * reset, but we have to account for eventual board quirks, if any: |
| * for this reason, keep reset asserted for 50uS and wait for 20uS |
| * 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) (0x00 + AW9523_PIN_TO_PORT(pin)) |
| #define AW9523_REG_OUT_STATE(pin) (0x02 + AW9523_PIN_TO_PORT(pin)) |
| #define AW9523_REG_CONF_STATE(pin) (0x04 + AW9523_PIN_TO_PORT(pin)) |
| #define AW9523_REG_INTR_DIS(pin) (0x06 + AW9523_PIN_TO_PORT(pin)) |
| #define AW9523_REG_CHIPID 0x10 |
| #define AW9523_VAL_EXPECTED_CHIPID 0x23 |
| |
| #define AW9523_REG_GCR 0x11 |
| #define AW9523_GCR_ISEL_MASK GENMASK(0, 1) |
| #define AW9523_GCR_GPOMD_MASK BIT(4) |
| |
| #define AW9523_REG_PORT_MODE(pin) (0x12 + AW9523_PIN_TO_PORT(pin)) |
| #define AW9523_REG_SOFT_RESET 0x7f |
| #define AW9523_VAL_RESET 0x00 |
| |
| /* |
| * struct aw9523_irq - Interrupt controller structure |
| * @lock: mutex locking for the irq bus |
| * @irqchip: structure holding irqchip params |
| * @cached_gpio: stores the previous gpio status for bit comparison |
| */ |
| struct aw9523_irq { |
| struct mutex lock; |
| struct irq_chip *irqchip; |
| u16 cached_gpio; |
| }; |
| |
| /* |
| * struct aw9523_pinmux - Pin mux params |
| * @name: Name of the mux |
| * @grps: Groups of the mux |
| * @num_grps: Number of groups (sizeof array grps) |
| */ |
| struct aw9523_pinmux { |
| const char *name; |
| const char * const *grps; |
| const u8 num_grps; |
| }; |
| |
| /* |
| * 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; |
| struct regulator *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", "gpio4", "gpio5", |
| "gpio6", "gpio7", "gpio8", "gpio9", "gpio10", "gpio11", |
| "gpio12", "gpio13", "gpio14", "gpio15" |
| }; |
| |
| /* Warning: Do NOT reorder this array */ |
| static const struct aw9523_pinmux aw9523_pmx[] = { |
| { |
| .name = "pwm", |
| .grps = gpio_pwm_groups, |
| .num_grps = ARRAY_SIZE(gpio_pwm_groups), |
| }, |
| { |
| .name = "gpio", |
| .grps = gpio_pwm_groups, |
| .num_grps = 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 num_groups) |
| { |
| *groups = aw9523_pmx[sel].grps; |
| *num_groups = aw9523_pmx[sel].num_grps; |
| 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 -EOPNOTSUPP; |
| } |
| *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 -EOPNOTSUPP; |
| } |
| 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 = -EOPNOTSUPP; |
| 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 = -EOPNOTSUPP; |
| 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)); |
| unsigned int n = d->hwirq % AW9523_PINS_PER_PORT; |
| |
| regmap_update_bits(awi->regmap, |
| AW9523_REG_INTR_DIS(d->hwirq), |
| BIT(n), BIT(n)); |
| gpiochip_disable_irq(&awi->gpio, irqd_to_hwirq(d)); |
| } |
| |
| /* |
| * 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)); |
| unsigned int n = d->hwirq % AW9523_PINS_PER_PORT; |
| |
| gpiochip_enable_irq(&awi->gpio, irqd_to_hwirq(d)); |
| regmap_update_bits(awi->regmap, |
| AW9523_REG_INTR_DIS(d->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 |
| * @regmap: Regmap structure |
| * @pin: gpiolib pin number |
| * @regbit: hw pin index, used to retrieve port number |
| * @state: returned port I/O state |
| * |
| * 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 & U8_MAX; |
| 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) & U8_MAX; |
| 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 void 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 & U8_MAX; |
| mask_hi = (*mask >> 8) & U8_MAX; |
| mutex_lock(&awi->i2c_lock); |
| if (mask_hi) { |
| reg = AW9523_REG_OUT_STATE(AW9523_PINS_PER_PORT); |
| bits_hi = (*bits >> 8) & U8_MAX; |
| |
| ret = regmap_write_bits(awi->regmap, reg, mask_hi, bits_hi); |
| if (ret) { |
| dev_warn(awi->dev, "Cannot write port1 out level\n"); |
| goto out; |
| } |
| } |
| if (mask_lo) { |
| reg = AW9523_REG_OUT_STATE(0); |
| bits_lo = *bits & U8_MAX; |
| ret = regmap_write_bits(awi->regmap, reg, mask_lo, bits_lo); |
| if (ret) |
| dev_warn(awi->dev, "Cannot write port0 out level\n"); |
| } |
| out: |
| mutex_unlock(&awi->i2c_lock); |
| } |
| |
| static void 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; |
| |
| mutex_lock(&awi->i2c_lock); |
| regmap_update_bits(awi->regmap, AW9523_REG_OUT_STATE(offset), |
| BIT(regbit), value ? BIT(regbit) : 0); |
| mutex_unlock(&awi->i2c_lock); |
| } |
| |
| |
| 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 = false; |
| |
| 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; |
| struct irq_chip *irqchip; |
| int ret; |
| |
| if (!device_property_read_bool(dev, "interrupt-controller")) |
| return 0; |
| |
| irqchip = devm_kzalloc(dev, sizeof(*irqchip), GFP_KERNEL); |
| if (!irqchip) |
| return -ENOMEM; |
| |
| awi->irq = devm_kzalloc(dev, sizeof(*awi->irq), GFP_KERNEL); |
| if (!awi->irq) |
| return -ENOMEM; |
| |
| awi->irq->irqchip = irqchip; |
| 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) { |
| dev_err(dev, "Failed to request irq %d\n", irq); |
| return ret; |
| } |
| |
| 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_optional(dev, "vio"); |
| if (IS_ERR(awi->vio_vreg)) { |
| if (PTR_ERR(awi->vio_vreg) == -EPROBE_DEFER) |
| return -EPROBE_DEFER; |
| awi->vio_vreg = NULL; |
| } else { |
| ret = regulator_enable(awi->vio_vreg); |
| if (ret) |
| return ret; |
| } |
| |
| mutex_init(&awi->i2c_lock); |
| 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) |
| goto err_disable_vregs; |
| |
| 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) |
| goto err_disable_vregs; |
| |
| if (client->irq) { |
| ret = aw9523_init_irq(awi, client->irq); |
| if (ret) |
| goto err_disable_vregs; |
| } |
| |
| awi->pctl = devm_pinctrl_register(dev, pdesc, awi); |
| if (IS_ERR(awi->pctl)) { |
| ret = PTR_ERR(awi->pctl); |
| dev_err(dev, "Cannot register pinctrl: %d", ret); |
| goto err_disable_vregs; |
| } |
| |
| ret = devm_gpiochip_add_data(dev, &awi->gpio, awi); |
| if (ret) |
| goto err_disable_vregs; |
| |
| return ret; |
| |
| err_disable_vregs: |
| if (awi->vio_vreg) |
| regulator_disable(awi->vio_vreg); |
| mutex_destroy(&awi->i2c_lock); |
| return ret; |
| } |
| |
| static void aw9523_remove(struct i2c_client *client) |
| { |
| struct aw9523 *awi = i2c_get_clientdata(client); |
| int ret; |
| |
| if (!awi) |
| return; |
| |
| /* |
| * 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) { |
| regulator_disable(awi->vio_vreg); |
| } else { |
| mutex_lock(&awi->i2c_lock); |
| ret = aw9523_hw_init(awi); |
| mutex_unlock(&awi->i2c_lock); |
| if (ret) |
| return; |
| } |
| |
| mutex_destroy(&awi->i2c_lock); |
| } |
| |
| static const struct i2c_device_id aw9523_i2c_id_table[] = { |
| { "aw9523_i2c", 0 }, |
| { } |
| }; |
| 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"); |