/* * 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
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;
}
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;
/* 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;
}
/* * 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
*/ staticint 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
*/ staticint aw9523_get_port_state(struct regmap *regmap, u8 pin, u8 regbit, unsignedint *state)
{
u8 reg; int dir;
dir = aw9523_get_pin_direction(regmap, pin, regbit); if (dir < 0) return dir;
/* * 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.
*/ staticvoid 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); unsignedint n = hwirq % AW9523_PINS_PER_PORT;
/* * 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.
*/ staticvoid 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); unsignedint n = hwirq % AW9523_PINS_PER_PORT;
static irqreturn_t aw9523_irq_thread_func(int irq, void *dev_id)
{ struct aw9523 *awi = (struct aw9523 *)dev_id; unsignedlong n, val = 0; unsignedlong changed_gpio; unsignedint 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);
}
/* * 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.
*/ staticvoid aw9523_irq_bus_sync_unlock(struct irq_data *d)
{ struct aw9523 *awi = gpiochip_get_data(irq_data_get_irq_chip_data(d));
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
*/ staticint _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;
}
staticint aw9523_gpio_get_multiple(struct gpio_chip *chip, unsignedlong *mask, unsignedlong *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;
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;
staticint aw9523_drive_reset_gpio(struct aw9523 *awi)
{ unsignedint 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;
}
staticint 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);
staticbool aw9523_readable_reg(struct device *dev, unsignedint reg)
{ /* All available registers (minus holes) can be read */ return !aw9523_is_reg_hole(reg);
}
/* 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);
}
/* * 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);
}
}
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.