@@ -926,6 +926,11 @@ int gpiochip_add_data_with_key(struct gpio_chip *gc, void *data,
int base = 0;
int ret = 0;
+ /* Only allow one set() and one set_multiple(). */
+ if ((gc->set && gc->set_rv) ||
+ (gc->set_multiple && gc->set_multiple_rv))
+ return -EINVAL;
+
/*
* First: allocate and populate the internal stat container, and
* set up the struct device.
@@ -2749,11 +2754,21 @@ int gpiod_direction_input_nonotify(struct gpio_desc *desc)
static int gpiochip_set(struct gpio_chip *gc, unsigned int offset, int value)
{
+ int ret;
+
lockdep_assert_held(&gc->gpiodev->srcu);
- if (WARN_ON(unlikely(!gc->set)))
+ if (WARN_ON(unlikely(!gc->set && !gc->set_rv)))
return -EOPNOTSUPP;
+ if (gc->set_rv) {
+ ret = gc->set_rv(gc, offset, value);
+ if (ret > 0)
+ ret = -EBADE;
+
+ return ret;
+ }
+
gc->set(gc, offset, value);
return 0;
}
@@ -3475,12 +3490,21 @@ static int gpiochip_set_multiple(struct gpio_chip *gc,
unsigned long *mask, unsigned long *bits)
{
unsigned int i;
+ int ret;
lockdep_assert_held(&gc->gpiodev->srcu);
- if (WARN_ON(unlikely(!gc->set_multiple && !gc->set)))
+ if (WARN_ON(unlikely(!gc->set_multiple && !gc->set_multiple_rv)))
return -EOPNOTSUPP;
+ if (gc->set_multiple_rv) {
+ ret = gc->set_multiple_rv(gc, mask, bits);
+ if (ret > 0)
+ ret = -EBADE;
+
+ return ret;
+ }
+
if (gc->set_multiple) {
gc->set_multiple(gc, mask, bits);
return 0;
@@ -346,6 +346,10 @@ struct gpio_irq_chip {
* stores them in "bits", returns 0 on success or negative error
* @set: assigns output value for signal "offset"
* @set_multiple: assigns output values for multiple signals defined by "mask"
+ * @set_rv: assigns output value for signal "offset", returns 0 on success or
+ * negative error value
+ * @set_multiple_rv: assigns output values for multiple signals defined by
+ * "mask", returns 0 on success or negative error value
* @set_config: optional hook for all kinds of settings. Uses the same
* packed config format as generic pinconf.
* @to_irq: optional hook supporting non-static gpiod_to_irq() mappings;
@@ -441,6 +445,12 @@ struct gpio_chip {
void (*set_multiple)(struct gpio_chip *gc,
unsigned long *mask,
unsigned long *bits);
+ int (*set_rv)(struct gpio_chip *gc,
+ unsigned int offset,
+ int value);
+ int (*set_multiple_rv)(struct gpio_chip *gc,
+ unsigned long *mask,
+ unsigned long *bits);
int (*set_config)(struct gpio_chip *gc,
unsigned int offset,
unsigned long config);