staticvoid sx150x_irq_set_sense(struct sx150x_pinctrl *pctl, unsignedint line, unsignedint sense)
{ /* * Every interrupt line is represented by two bits shifted * proportionally to the line number
*/ constunsignedint n = line * 2; constunsignedint mask = ~((SX150X_IRQ_TYPE_EDGE_RISING |
SX150X_IRQ_TYPE_EDGE_FALLING) << n);
pctl->irq.sense &= mask;
pctl->irq.sense |= sense << n;
}
if (sx150x_pin_is_oscio(pctl, pin)) { switch (param) { case PIN_CONFIG_DRIVE_PUSH_PULL: case PIN_CONFIG_OUTPUT:
ret = regmap_read(pctl->regmap,
pctl->data->pri.x789.reg_clock,
&data); if (ret < 0) return ret;
switch (param) { case PIN_CONFIG_BIAS_PULL_DOWN:
ret = regmap_read(pctl->regmap,
pctl->data->reg_pulldn,
&data);
data &= BIT(pin);
if (ret < 0) return ret;
if (!ret) return -EINVAL;
arg = 1; break;
case PIN_CONFIG_BIAS_PULL_UP:
ret = regmap_read(pctl->regmap,
pctl->data->reg_pullup,
&data);
data &= BIT(pin);
if (ret < 0) return ret;
if (!ret) return -EINVAL;
arg = 1; break;
case PIN_CONFIG_DRIVE_OPEN_DRAIN: if (pctl->data->model != SX150X_789) return -ENOTSUPP;
ret = regmap_read(pctl->regmap,
pctl->data->pri.x789.reg_drain,
&data);
data &= BIT(pin);
if (ret < 0) return ret;
if (!data) return -EINVAL;
arg = 1; break;
case PIN_CONFIG_DRIVE_PUSH_PULL: if (pctl->data->model != SX150X_789)
arg = true; else {
ret = regmap_read(pctl->regmap,
pctl->data->pri.x789.reg_drain,
&data);
data &= BIT(pin);
if (ret < 0) return ret;
if (data) return -EINVAL;
arg = 1;
} break;
case PIN_CONFIG_OUTPUT:
ret = sx150x_gpio_get_direction(&pctl->gpio, pin); if (ret < 0) return ret;
if (ret == GPIO_LINE_DIRECTION_IN) return -EINVAL;
ret = sx150x_gpio_get(&pctl->gpio, pin); if (ret < 0) return ret;
for (i = 0; i < num_configs; i++) {
param = pinconf_to_config_param(configs[i]);
arg = pinconf_to_config_argument(configs[i]);
if (sx150x_pin_is_oscio(pctl, pin)) { if (param == PIN_CONFIG_OUTPUT) {
ret = sx150x_gpio_direction_output(&pctl->gpio,
pin, arg); if (ret < 0) return ret;
continue;
} else return -ENOTSUPP;
}
switch (param) { case PIN_CONFIG_BIAS_PULL_PIN_DEFAULT: case PIN_CONFIG_BIAS_DISABLE:
ret = regmap_write_bits(pctl->regmap,
pctl->data->reg_pulldn,
BIT(pin), 0); if (ret < 0) return ret;
ret = regmap_write_bits(pctl->regmap,
pctl->data->reg_pullup,
BIT(pin), 0); if (ret < 0) return ret;
break;
case PIN_CONFIG_BIAS_PULL_UP:
ret = regmap_write_bits(pctl->regmap,
pctl->data->reg_pullup,
BIT(pin), BIT(pin)); if (ret < 0) return ret;
break;
case PIN_CONFIG_BIAS_PULL_DOWN:
ret = regmap_write_bits(pctl->regmap,
pctl->data->reg_pulldn,
BIT(pin), BIT(pin)); if (ret < 0) return ret;
break;
case PIN_CONFIG_DRIVE_OPEN_DRAIN: if (pctl->data->model != SX150X_789 ||
sx150x_pin_is_oscio(pctl, pin)) return -ENOTSUPP;
ret = regmap_write_bits(pctl->regmap,
pctl->data->pri.x789.reg_drain,
BIT(pin), BIT(pin)); if (ret < 0) return ret;
break;
case PIN_CONFIG_DRIVE_PUSH_PULL: if (pctl->data->model != SX150X_789 ||
sx150x_pin_is_oscio(pctl, pin)) return 0;
ret = regmap_write_bits(pctl->regmap,
pctl->data->pri.x789.reg_drain,
BIT(pin), 0); if (ret < 0) return ret;
break;
case PIN_CONFIG_OUTPUT:
ret = sx150x_gpio_direction_output(&pctl->gpio,
pin, arg); if (ret < 0) return ret;
break;
default: return -ENOTSUPP;
}
} /* for each config */
switch (pctl->data->model) { case SX150X_789:
reg = pctl->data->pri.x789.reg_misc;
value = SX150X_789_REG_MISC_AUTOCLEAR_OFF; break; case SX150X_456:
reg = pctl->data->pri.x456.reg_advanced;
value = 0x00;
/* * Only SX1506 has RegAdvanced, SX1504/5 are expected * to initialize this offset to zero
*/ if (!reg) return 0; break; case SX150X_123:
reg = pctl->data->pri.x123.reg_advanced;
value = 0x00; break; default:
WARN(1, "Unknown chip model %d\n", pctl->data->model); return -EINVAL;
}
/* * Whereas SX1509 presents RegSense in a simple layout as such: * reg [ f f e e d d c c ] * reg + 1 [ b b a a 9 9 8 8 ] * reg + 2 [ 7 7 6 6 5 5 4 4 ] * reg + 3 [ 3 3 2 2 1 1 0 0 ] * * SX1503 and SX1506 deviate from that data layout, instead storing * their contents as follows: * * reg [ f f e e d d c c ] * reg + 1 [ 7 7 6 6 5 5 4 4 ] * reg + 2 [ b b a a 9 9 8 8 ] * reg + 3 [ 3 3 2 2 1 1 0 0 ] * * so, taking that into account, we swap two * inner bytes of a 4-byte result
*/
if (reg == data->reg_sense &&
data->ngpios == 16 &&
(data->model == SX150X_123 ||
data->model == SX150X_456)) {
a = val & 0x00ff0000;
b = val & 0x0000ff00;
val &= 0xff0000ff;
val |= b << 8;
val |= a >> 8;
}
return val;
}
/* * In order to mask the differences between 16 and 8 bit expander * devices we set up a sligthly ficticious regmap that pretends to be * a set of 32-bit (to accommodate RegSenseLow/RegSenseHigh * pair/quartet) registers and transparently reconstructs those * registers via multiple I2C/SMBus reads * * This way the rest of the driver code, interfacing with the chip via * regmap API, can work assuming that each GPIO pin is represented by * a group of bits at an offset proportional to GPIO number within a * given register.
*/ staticint sx150x_regmap_reg_read(void *context, unsignedint reg, unsignedint *result)
{ int ret, n; struct sx150x_pinctrl *pctl = context; struct i2c_client *i2c = pctl->client; constint width = sx150x_regmap_reg_width(pctl, reg); unsignedint idx, val;
/* * There are four potential cases covered by this function: * * 1) 8-pin chip, single configuration bit register * * This is trivial the code below just needs to read: * reg [ 7 6 5 4 3 2 1 0 ] * * 2) 8-pin chip, double configuration bit register (RegSense) * * The read will be done as follows: * reg [ 7 7 6 6 5 5 4 4 ] * reg + 1 [ 3 3 2 2 1 1 0 0 ] * * 3) 16-pin chip, single configuration bit register * * The read will be done as follows: * reg [ f e d c b a 9 8 ] * reg + 1 [ 7 6 5 4 3 2 1 0 ] * * 4) 16-pin chip, double configuration bit register (RegSense) * * The read will be done as follows: * reg [ f f e e d d c c ] * reg + 1 [ b b a a 9 9 8 8 ] * reg + 2 [ 7 7 6 6 5 5 4 4 ] * reg + 3 [ 3 3 2 2 1 1 0 0 ]
*/
for (n = width, val = 0, idx = reg; n > 0; n -= 8, idx++) {
val <<= 8;
ret = i2c_smbus_read_byte_data(i2c, idx); if (ret < 0) return ret;
/* * Setting multiple pins is not safe when all pins are not * handled by the same regmap register. The oscio pin (present * on the SX150X_789 chips) lives in its own register, so * would require locking that is not in place at this time.
*/ if (pctl->data->model != SX150X_789)
pctl->gpio.set_multiple = sx150x_gpio_set_multiple;
/* Add Interrupt support if an irq is specified */ if (client->irq > 0) { struct gpio_irq_chip *girq;
pctl->irq.masked = ~0;
pctl->irq.sense = 0; /* * Because sx150x_irq_threaded_fn invokes all of the * nested interrupt handlers via handle_nested_irq, * any "handler" assigned to struct gpio_irq_chip * below is going to be ignored, so the choice of the * function does not matter that much. * * We set it to handle_bad_irq to avoid confusion, * plus it will be instantly noticeable if it is ever * called (should not happen)
*/
girq = &pctl->gpio.irq;
gpio_irq_chip_set_chip(girq, &sx150x_irq_chip); /* This will let us handle the parent IRQ in the driver */
girq->parent_handler = NULL;
girq->num_parents = 0;
girq->parents = NULL;
girq->default_type = IRQ_TYPE_NONE;
girq->handler = handle_bad_irq;
girq->threaded = true;
ret = devm_request_threaded_irq(dev, client->irq, NULL,
sx150x_irq_thread_fn,
IRQF_ONESHOT | IRQF_SHARED |
IRQF_TRIGGER_FALLING,
client->name, pctl); if (ret < 0) return ret;
}
ret = devm_gpiochip_add_data(dev, &pctl->gpio, pctl); if (ret) return ret;
/* * Pin control functions need to be enabled AFTER registering the * GPIO chip because sx150x_pinconf_set() calls * sx150x_gpio_direction_output().
*/
ret = pinctrl_enable(pctl->pctldev); if (ret) {
dev_err(dev, "Failed to enable pinctrl device\n"); return ret;
}
ret = gpiochip_add_pin_range(&pctl->gpio, dev_name(dev),
0, 0, pctl->data->npins); if (ret) return ret;
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.