Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

gpio: gpiolib: Generalise state persistence beyond sleep

General support for state persistence is added to gpiolib with the
introduction of a new pinconf parameter to propagate the request to
hardware. The existing persistence support for sleep is adapted to
include hardware support if the GPIO driver provides it. Persistence
continues to be enabled by default; in-kernel consumers can opt out, but
userspace (currently) does not have a choice.

The *_SLEEP_MAY_LOSE_VALUE and *_SLEEP_MAINTAIN_VALUE symbols are
renamed, dropping the SLEEP prefix to reflect that the concept is no
longer sleep-specific. I feel that renaming to just *_MAY_LOSE_VALUE
could initially be misinterpreted, so I've further changed the symbols
to *_TRANSITORY and *_PERSISTENT to address this.

The sysfs interface is modified only to keep consistency with the
chardev interface in enforcing persistence for userspace exports.

Signed-off-by: Andrew Jeffery <andrew@aj.id.au>
Reviewed-by: Charles Keepax <ckeepax@opensource.cirrus.com>
Acked-by: Rob Herring <robh@kernel.org>
Signed-off-by: Linus Walleij <linus.walleij@linaro.org>

authored by

Andrew Jeffery and committed by
Linus Walleij
e10f72bf e2843cb6

+87 -18
+4 -2
drivers/gpio/gpiolib-of.c
··· 153 153 *flags |= GPIO_OPEN_SOURCE; 154 154 } 155 155 156 - if (of_flags & OF_GPIO_SLEEP_MAY_LOSE_VALUE) 157 - *flags |= GPIO_SLEEP_MAY_LOSE_VALUE; 156 + if (of_flags & OF_GPIO_TRANSITORY) 157 + *flags |= GPIO_TRANSITORY; 158 158 159 159 return desc; 160 160 } ··· 214 214 215 215 if (xlate_flags & OF_GPIO_ACTIVE_LOW) 216 216 *lflags |= GPIO_ACTIVE_LOW; 217 + if (xlate_flags & OF_GPIO_TRANSITORY) 218 + *lflags |= GPIO_TRANSITORY; 217 219 218 220 if (of_property_read_bool(np, "input")) 219 221 *dflags |= GPIOD_IN;
+9 -5
drivers/gpio/gpiolib-sysfs.c
··· 474 474 status = -ENODEV; 475 475 goto done; 476 476 } 477 - status = gpiod_export(desc, true); 478 - if (status < 0) 479 - gpiod_free(desc); 480 - else 481 - set_bit(FLAG_SYSFS, &desc->flags); 477 + 478 + status = gpiod_set_transitory(desc, false); 479 + if (!status) { 480 + status = gpiod_export(desc, true); 481 + if (status < 0) 482 + gpiod_free(desc); 483 + else 484 + set_bit(FLAG_SYSFS, &desc->flags); 485 + } 482 486 483 487 done: 484 488 if (status)
+57 -4
drivers/gpio/gpiolib.c
··· 514 514 if (lflags & GPIOHANDLE_REQUEST_OPEN_SOURCE) 515 515 set_bit(FLAG_OPEN_SOURCE, &desc->flags); 516 516 517 + ret = gpiod_set_transitory(desc, false); 518 + if (ret < 0) 519 + goto out_free_descs; 520 + 517 521 /* 518 522 * Lines have to be requested explicitly for input 519 523 * or output, else the line will be treated "as is". ··· 2534 2530 EXPORT_SYMBOL_GPL(gpiod_set_debounce); 2535 2531 2536 2532 /** 2533 + * gpiod_set_transitory - Lose or retain GPIO state on suspend or reset 2534 + * @desc: descriptor of the GPIO for which to configure persistence 2535 + * @transitory: True to lose state on suspend or reset, false for persistence 2536 + * 2537 + * Returns: 2538 + * 0 on success, otherwise a negative error code. 2539 + */ 2540 + int gpiod_set_transitory(struct gpio_desc *desc, bool transitory) 2541 + { 2542 + struct gpio_chip *chip; 2543 + unsigned long packed; 2544 + int gpio; 2545 + int rc; 2546 + 2547 + /* 2548 + * Handle FLAG_TRANSITORY first, enabling queries to gpiolib for 2549 + * persistence state. 2550 + */ 2551 + if (transitory) 2552 + set_bit(FLAG_TRANSITORY, &desc->flags); 2553 + else 2554 + clear_bit(FLAG_TRANSITORY, &desc->flags); 2555 + 2556 + /* If the driver supports it, set the persistence state now */ 2557 + chip = desc->gdev->chip; 2558 + if (!chip->set_config) 2559 + return 0; 2560 + 2561 + packed = pinconf_to_config_packed(PIN_CONFIG_PERSIST_STATE, 2562 + !transitory); 2563 + gpio = gpio_chip_hwgpio(desc); 2564 + rc = chip->set_config(chip, gpio, packed); 2565 + if (rc == -ENOTSUPP) { 2566 + dev_dbg(&desc->gdev->dev, "Persistence not supported for GPIO %d\n", 2567 + gpio); 2568 + return 0; 2569 + } 2570 + 2571 + return rc; 2572 + } 2573 + EXPORT_SYMBOL_GPL(gpiod_set_transitory); 2574 + 2575 + /** 2537 2576 * gpiod_is_active_low - test whether a GPIO is active-low or not 2538 2577 * @desc: the gpio descriptor to test 2539 2578 * ··· 3163 3116 if (offset >= chip->ngpio) 3164 3117 return false; 3165 3118 3166 - return !test_bit(FLAG_SLEEP_MAY_LOSE_VALUE, 3167 - &chip->gpiodev->descs[offset].flags); 3119 + return !test_bit(FLAG_TRANSITORY, &chip->gpiodev->descs[offset].flags); 3168 3120 } 3169 3121 EXPORT_SYMBOL_GPL(gpiochip_line_is_persistent); 3170 3122 ··· 3600 3554 3601 3555 if (lflags & GPIO_OPEN_SOURCE) 3602 3556 set_bit(FLAG_OPEN_SOURCE, &desc->flags); 3603 - if (lflags & GPIO_SLEEP_MAY_LOSE_VALUE) 3604 - set_bit(FLAG_SLEEP_MAY_LOSE_VALUE, &desc->flags); 3557 + 3558 + status = gpiod_set_transitory(desc, (lflags & GPIO_TRANSITORY)); 3559 + if (status < 0) 3560 + return status; 3605 3561 3606 3562 /* No particular flag request, return here... */ 3607 3563 if (!(dflags & GPIOD_FLAGS_BIT_DIR_SET)) { ··· 3717 3669 bool active_low = false; 3718 3670 bool single_ended = false; 3719 3671 bool open_drain = false; 3672 + bool transitory = false; 3720 3673 int ret; 3721 3674 3722 3675 if (!fwnode) ··· 3732 3683 active_low = flags & OF_GPIO_ACTIVE_LOW; 3733 3684 single_ended = flags & OF_GPIO_SINGLE_ENDED; 3734 3685 open_drain = flags & OF_GPIO_OPEN_DRAIN; 3686 + transitory = flags & OF_GPIO_TRANSITORY; 3735 3687 } 3736 3688 } else if (is_acpi_node(fwnode)) { 3737 3689 struct acpi_gpio_info info; ··· 3760 3710 else 3761 3711 lflags |= GPIO_OPEN_SOURCE; 3762 3712 } 3713 + 3714 + if (transitory) 3715 + lflags |= GPIO_TRANSITORY; 3763 3716 3764 3717 ret = gpiod_configure_flags(desc, propname, lflags, dflags); 3765 3718 if (ret < 0) {
+1 -1
drivers/gpio/gpiolib.h
··· 209 209 #define FLAG_OPEN_SOURCE 8 /* Gpio is open source type */ 210 210 #define FLAG_USED_AS_IRQ 9 /* GPIO is connected to an IRQ */ 211 211 #define FLAG_IS_HOGGED 11 /* GPIO is hogged */ 212 - #define FLAG_SLEEP_MAY_LOSE_VALUE 12 /* GPIO may lose value in sleep */ 212 + #define FLAG_TRANSITORY 12 /* GPIO may lose value in sleep or reset */ 213 213 214 214 /* Connection label */ 215 215 const char *label;
+3 -3
include/dt-bindings/gpio/gpio.h
··· 29 29 #define GPIO_OPEN_DRAIN (GPIO_SINGLE_ENDED | GPIO_LINE_OPEN_DRAIN) 30 30 #define GPIO_OPEN_SOURCE (GPIO_SINGLE_ENDED | GPIO_LINE_OPEN_SOURCE) 31 31 32 - /* Bit 3 express GPIO suspend/resume persistence */ 33 - #define GPIO_SLEEP_MAINTAIN_VALUE 0 34 - #define GPIO_SLEEP_MAY_LOSE_VALUE 8 32 + /* Bit 3 express GPIO suspend/resume and reset persistence */ 33 + #define GPIO_PERSISTENT 0 34 + #define GPIO_TRANSITORY 8 35 35 36 36 #endif
+8
include/linux/gpio/consumer.h
··· 139 139 int *value_array); 140 140 141 141 int gpiod_set_debounce(struct gpio_desc *desc, unsigned debounce); 142 + int gpiod_set_transitory(struct gpio_desc *desc, bool transitory); 142 143 143 144 int gpiod_is_active_low(const struct gpio_desc *desc); 144 145 int gpiod_cansleep(const struct gpio_desc *desc); ··· 426 425 } 427 426 428 427 static inline int gpiod_set_debounce(struct gpio_desc *desc, unsigned debounce) 428 + { 429 + /* GPIO can never have been requested */ 430 + WARN_ON(1); 431 + return -ENOSYS; 432 + } 433 + 434 + static inline int gpiod_set_transitory(struct gpio_desc *desc, bool transitory) 429 435 { 430 436 /* GPIO can never have been requested */ 431 437 WARN_ON(1);
+2 -2
include/linux/gpio/machine.h
··· 10 10 GPIO_ACTIVE_LOW = (1 << 0), 11 11 GPIO_OPEN_DRAIN = (1 << 1), 12 12 GPIO_OPEN_SOURCE = (1 << 2), 13 - GPIO_SLEEP_MAINTAIN_VALUE = (0 << 3), 14 - GPIO_SLEEP_MAY_LOSE_VALUE = (1 << 3), 13 + GPIO_PERSISTENT = (0 << 3), 14 + GPIO_TRANSITORY = (1 << 3), 15 15 }; 16 16 17 17 /**
+1 -1
include/linux/of_gpio.h
··· 31 31 OF_GPIO_ACTIVE_LOW = 0x1, 32 32 OF_GPIO_SINGLE_ENDED = 0x2, 33 33 OF_GPIO_OPEN_DRAIN = 0x4, 34 - OF_GPIO_SLEEP_MAY_LOSE_VALUE = 0x8, 34 + OF_GPIO_TRANSITORY = 0x8, 35 35 }; 36 36 37 37 #ifdef CONFIG_OF_GPIO
+2
include/linux/pinctrl/pinconf-generic.h
··· 94 94 * or latch delay (on outputs) this parameter (in a custom format) 95 95 * specifies the clock skew or latch delay. It typically controls how 96 96 * many double inverters are put in front of the line. 97 + * @PIN_CONFIG_PERSIST_STATE: retain pin state across sleep or controller reset 97 98 * @PIN_CONFIG_END: this is the last enumerator for pin configurations, if 98 99 * you need to pass in custom configurations to the pin controller, use 99 100 * PIN_CONFIG_END+1 as the base offset. ··· 123 122 PIN_CONFIG_SLEEP_HARDWARE_STATE, 124 123 PIN_CONFIG_SLEW_RATE, 125 124 PIN_CONFIG_SKEW_DELAY, 125 + PIN_CONFIG_PERSIST_STATE, 126 126 PIN_CONFIG_END = 0x7F, 127 127 PIN_CONFIG_MAX = 0xFF, 128 128 };