summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAndrew Jeffery <andrew@aj.id.au>2017-11-29 22:55:24 -0500
committerLinus Walleij <linus.walleij@linaro.org>2017-12-02 16:42:34 -0500
commite10f72bf4b3e8885c1915a119141481e7fc45ca8 (patch)
tree12f85b22ea1e17f9bb38f9cbb61a62da2abe44cd
parente2843cb6cd6ba433d18d87e3e922b6e49ecccf01 (diff)
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>
-rw-r--r--drivers/gpio/gpiolib-of.c6
-rw-r--r--drivers/gpio/gpiolib-sysfs.c14
-rw-r--r--drivers/gpio/gpiolib.c61
-rw-r--r--drivers/gpio/gpiolib.h2
-rw-r--r--include/dt-bindings/gpio/gpio.h6
-rw-r--r--include/linux/gpio/consumer.h8
-rw-r--r--include/linux/gpio/machine.h4
-rw-r--r--include/linux/of_gpio.h2
-rw-r--r--include/linux/pinctrl/pinconf-generic.h2
9 files changed, 87 insertions, 18 deletions
diff --git a/drivers/gpio/gpiolib-of.c b/drivers/gpio/gpiolib-of.c
index e0d59e61b52f..4a2b8d3397c7 100644
--- a/drivers/gpio/gpiolib-of.c
+++ b/drivers/gpio/gpiolib-of.c
@@ -153,8 +153,8 @@ struct gpio_desc *of_find_gpio(struct device *dev, const char *con_id,
153 *flags |= GPIO_OPEN_SOURCE; 153 *flags |= GPIO_OPEN_SOURCE;
154 } 154 }
155 155
156 if (of_flags & OF_GPIO_SLEEP_MAY_LOSE_VALUE) 156 if (of_flags & OF_GPIO_TRANSITORY)
157 *flags |= GPIO_SLEEP_MAY_LOSE_VALUE; 157 *flags |= GPIO_TRANSITORY;
158 158
159 return desc; 159 return desc;
160} 160}
@@ -214,6 +214,8 @@ static struct gpio_desc *of_parse_own_gpio(struct device_node *np,
214 214
215 if (xlate_flags & OF_GPIO_ACTIVE_LOW) 215 if (xlate_flags & OF_GPIO_ACTIVE_LOW)
216 *lflags |= GPIO_ACTIVE_LOW; 216 *lflags |= GPIO_ACTIVE_LOW;
217 if (xlate_flags & OF_GPIO_TRANSITORY)
218 *lflags |= GPIO_TRANSITORY;
217 219
218 if (of_property_read_bool(np, "input")) 220 if (of_property_read_bool(np, "input"))
219 *dflags |= GPIOD_IN; 221 *dflags |= GPIOD_IN;
diff --git a/drivers/gpio/gpiolib-sysfs.c b/drivers/gpio/gpiolib-sysfs.c
index 3f454eaf2101..0bd472ffb072 100644
--- a/drivers/gpio/gpiolib-sysfs.c
+++ b/drivers/gpio/gpiolib-sysfs.c
@@ -474,11 +474,15 @@ static ssize_t export_store(struct class *class,
474 status = -ENODEV; 474 status = -ENODEV;
475 goto done; 475 goto done;
476 } 476 }
477 status = gpiod_export(desc, true); 477
478 if (status < 0) 478 status = gpiod_set_transitory(desc, false);
479 gpiod_free(desc); 479 if (!status) {
480 else 480 status = gpiod_export(desc, true);
481 set_bit(FLAG_SYSFS, &desc->flags); 481 if (status < 0)
482 gpiod_free(desc);
483 else
484 set_bit(FLAG_SYSFS, &desc->flags);
485 }
482 486
483done: 487done:
484 if (status) 488 if (status)
diff --git a/drivers/gpio/gpiolib.c b/drivers/gpio/gpiolib.c
index ec0fd95bbf35..56eec094184c 100644
--- a/drivers/gpio/gpiolib.c
+++ b/drivers/gpio/gpiolib.c
@@ -514,6 +514,10 @@ static int linehandle_create(struct gpio_device *gdev, void __user *ip)
514 if (lflags & GPIOHANDLE_REQUEST_OPEN_SOURCE) 514 if (lflags & GPIOHANDLE_REQUEST_OPEN_SOURCE)
515 set_bit(FLAG_OPEN_SOURCE, &desc->flags); 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 * Lines have to be requested explicitly for input 522 * Lines have to be requested explicitly for input
519 * or output, else the line will be treated "as is". 523 * or output, else the line will be treated "as is".
@@ -2530,6 +2534,49 @@ int gpiod_set_debounce(struct gpio_desc *desc, unsigned debounce)
2530EXPORT_SYMBOL_GPL(gpiod_set_debounce); 2534EXPORT_SYMBOL_GPL(gpiod_set_debounce);
2531 2535
2532/** 2536/**
2537 * gpiod_set_transitory - Lose or retain GPIO state on suspend or reset
2538 * @desc: descriptor of the GPIO for which to configure persistence
2539 * @transitory: True to lose state on suspend or reset, false for persistence
2540 *
2541 * Returns:
2542 * 0 on success, otherwise a negative error code.
2543 */
2544int gpiod_set_transitory(struct gpio_desc *desc, bool transitory)
2545{
2546 struct gpio_chip *chip;
2547 unsigned long packed;
2548 int gpio;
2549 int rc;
2550
2551 /*
2552 * Handle FLAG_TRANSITORY first, enabling queries to gpiolib for
2553 * persistence state.
2554 */
2555 if (transitory)
2556 set_bit(FLAG_TRANSITORY, &desc->flags);
2557 else
2558 clear_bit(FLAG_TRANSITORY, &desc->flags);
2559
2560 /* If the driver supports it, set the persistence state now */
2561 chip = desc->gdev->chip;
2562 if (!chip->set_config)
2563 return 0;
2564
2565 packed = pinconf_to_config_packed(PIN_CONFIG_PERSIST_STATE,
2566 !transitory);
2567 gpio = gpio_chip_hwgpio(desc);
2568 rc = chip->set_config(chip, gpio, packed);
2569 if (rc == -ENOTSUPP) {
2570 dev_dbg(&desc->gdev->dev, "Persistence not supported for GPIO %d\n",
2571 gpio);
2572 return 0;
2573 }
2574
2575 return rc;
2576}
2577EXPORT_SYMBOL_GPL(gpiod_set_transitory);
2578
2579/**
2533 * gpiod_is_active_low - test whether a GPIO is active-low or not 2580 * gpiod_is_active_low - test whether a GPIO is active-low or not
2534 * @desc: the gpio descriptor to test 2581 * @desc: the gpio descriptor to test
2535 * 2582 *
@@ -3116,8 +3163,7 @@ bool gpiochip_line_is_persistent(struct gpio_chip *chip, unsigned int offset)
3116 if (offset >= chip->ngpio) 3163 if (offset >= chip->ngpio)
3117 return false; 3164 return false;
3118 3165
3119 return !test_bit(FLAG_SLEEP_MAY_LOSE_VALUE, 3166 return !test_bit(FLAG_TRANSITORY, &chip->gpiodev->descs[offset].flags);
3120 &chip->gpiodev->descs[offset].flags);
3121} 3167}
3122EXPORT_SYMBOL_GPL(gpiochip_line_is_persistent); 3168EXPORT_SYMBOL_GPL(gpiochip_line_is_persistent);
3123 3169
@@ -3554,8 +3600,10 @@ int gpiod_configure_flags(struct gpio_desc *desc, const char *con_id,
3554 3600
3555 if (lflags & GPIO_OPEN_SOURCE) 3601 if (lflags & GPIO_OPEN_SOURCE)
3556 set_bit(FLAG_OPEN_SOURCE, &desc->flags); 3602 set_bit(FLAG_OPEN_SOURCE, &desc->flags);
3557 if (lflags & GPIO_SLEEP_MAY_LOSE_VALUE) 3603
3558 set_bit(FLAG_SLEEP_MAY_LOSE_VALUE, &desc->flags); 3604 status = gpiod_set_transitory(desc, (lflags & GPIO_TRANSITORY));
3605 if (status < 0)
3606 return status;
3559 3607
3560 /* No particular flag request, return here... */ 3608 /* No particular flag request, return here... */
3561 if (!(dflags & GPIOD_FLAGS_BIT_DIR_SET)) { 3609 if (!(dflags & GPIOD_FLAGS_BIT_DIR_SET)) {
@@ -3669,6 +3717,7 @@ struct gpio_desc *fwnode_get_named_gpiod(struct fwnode_handle *fwnode,
3669 bool active_low = false; 3717 bool active_low = false;
3670 bool single_ended = false; 3718 bool single_ended = false;
3671 bool open_drain = false; 3719 bool open_drain = false;
3720 bool transitory = false;
3672 int ret; 3721 int ret;
3673 3722
3674 if (!fwnode) 3723 if (!fwnode)
@@ -3683,6 +3732,7 @@ struct gpio_desc *fwnode_get_named_gpiod(struct fwnode_handle *fwnode,
3683 active_low = flags & OF_GPIO_ACTIVE_LOW; 3732 active_low = flags & OF_GPIO_ACTIVE_LOW;
3684 single_ended = flags & OF_GPIO_SINGLE_ENDED; 3733 single_ended = flags & OF_GPIO_SINGLE_ENDED;
3685 open_drain = flags & OF_GPIO_OPEN_DRAIN; 3734 open_drain = flags & OF_GPIO_OPEN_DRAIN;
3735 transitory = flags & OF_GPIO_TRANSITORY;
3686 } 3736 }
3687 } else if (is_acpi_node(fwnode)) { 3737 } else if (is_acpi_node(fwnode)) {
3688 struct acpi_gpio_info info; 3738 struct acpi_gpio_info info;
@@ -3711,6 +3761,9 @@ struct gpio_desc *fwnode_get_named_gpiod(struct fwnode_handle *fwnode,
3711 lflags |= GPIO_OPEN_SOURCE; 3761 lflags |= GPIO_OPEN_SOURCE;
3712 } 3762 }
3713 3763
3764 if (transitory)
3765 lflags |= GPIO_TRANSITORY;
3766
3714 ret = gpiod_configure_flags(desc, propname, lflags, dflags); 3767 ret = gpiod_configure_flags(desc, propname, lflags, dflags);
3715 if (ret < 0) { 3768 if (ret < 0) {
3716 gpiod_put(desc); 3769 gpiod_put(desc);
diff --git a/drivers/gpio/gpiolib.h b/drivers/gpio/gpiolib.h
index cd4622863fe1..5e1f7cc6eeb6 100644
--- a/drivers/gpio/gpiolib.h
+++ b/drivers/gpio/gpiolib.h
@@ -209,7 +209,7 @@ struct gpio_desc {
209#define FLAG_OPEN_SOURCE 8 /* Gpio is open source type */ 209#define FLAG_OPEN_SOURCE 8 /* Gpio is open source type */
210#define FLAG_USED_AS_IRQ 9 /* GPIO is connected to an IRQ */ 210#define FLAG_USED_AS_IRQ 9 /* GPIO is connected to an IRQ */
211#define FLAG_IS_HOGGED 11 /* GPIO is hogged */ 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 /* Connection label */ 214 /* Connection label */
215 const char *label; 215 const char *label;
diff --git a/include/dt-bindings/gpio/gpio.h b/include/dt-bindings/gpio/gpio.h
index dd549ff04295..2cc10ae4bbb7 100644
--- a/include/dt-bindings/gpio/gpio.h
+++ b/include/dt-bindings/gpio/gpio.h
@@ -29,8 +29,8 @@
29#define GPIO_OPEN_DRAIN (GPIO_SINGLE_ENDED | GPIO_LINE_OPEN_DRAIN) 29#define GPIO_OPEN_DRAIN (GPIO_SINGLE_ENDED | GPIO_LINE_OPEN_DRAIN)
30#define GPIO_OPEN_SOURCE (GPIO_SINGLE_ENDED | GPIO_LINE_OPEN_SOURCE) 30#define GPIO_OPEN_SOURCE (GPIO_SINGLE_ENDED | GPIO_LINE_OPEN_SOURCE)
31 31
32/* Bit 3 express GPIO suspend/resume persistence */ 32/* Bit 3 express GPIO suspend/resume and reset persistence */
33#define GPIO_SLEEP_MAINTAIN_VALUE 0 33#define GPIO_PERSISTENT 0
34#define GPIO_SLEEP_MAY_LOSE_VALUE 8 34#define GPIO_TRANSITORY 8
35 35
36#endif 36#endif
diff --git a/include/linux/gpio/consumer.h b/include/linux/gpio/consumer.h
index 7447d85dbe2f..540b2c142493 100644
--- a/include/linux/gpio/consumer.h
+++ b/include/linux/gpio/consumer.h
@@ -139,6 +139,7 @@ void gpiod_set_raw_array_value_cansleep(unsigned int array_size,
139 int *value_array); 139 int *value_array);
140 140
141int gpiod_set_debounce(struct gpio_desc *desc, unsigned debounce); 141int gpiod_set_debounce(struct gpio_desc *desc, unsigned debounce);
142int gpiod_set_transitory(struct gpio_desc *desc, bool transitory);
142 143
143int gpiod_is_active_low(const struct gpio_desc *desc); 144int gpiod_is_active_low(const struct gpio_desc *desc);
144int gpiod_cansleep(const struct gpio_desc *desc); 145int gpiod_cansleep(const struct gpio_desc *desc);
@@ -431,6 +432,13 @@ static inline int gpiod_set_debounce(struct gpio_desc *desc, unsigned debounce)
431 return -ENOSYS; 432 return -ENOSYS;
432} 433}
433 434
435static inline int gpiod_set_transitory(struct gpio_desc *desc, bool transitory)
436{
437 /* GPIO can never have been requested */
438 WARN_ON(1);
439 return -ENOSYS;
440}
441
434static inline int gpiod_is_active_low(const struct gpio_desc *desc) 442static inline int gpiod_is_active_low(const struct gpio_desc *desc)
435{ 443{
436 /* GPIO can never have been requested */ 444 /* GPIO can never have been requested */
diff --git a/include/linux/gpio/machine.h b/include/linux/gpio/machine.h
index 846be7c69a52..b2f2dc638463 100644
--- a/include/linux/gpio/machine.h
+++ b/include/linux/gpio/machine.h
@@ -10,8 +10,8 @@ enum gpio_lookup_flags {
10 GPIO_ACTIVE_LOW = (1 << 0), 10 GPIO_ACTIVE_LOW = (1 << 0),
11 GPIO_OPEN_DRAIN = (1 << 1), 11 GPIO_OPEN_DRAIN = (1 << 1),
12 GPIO_OPEN_SOURCE = (1 << 2), 12 GPIO_OPEN_SOURCE = (1 << 2),
13 GPIO_SLEEP_MAINTAIN_VALUE = (0 << 3), 13 GPIO_PERSISTENT = (0 << 3),
14 GPIO_SLEEP_MAY_LOSE_VALUE = (1 << 3), 14 GPIO_TRANSITORY = (1 << 3),
15}; 15};
16 16
17/** 17/**
diff --git a/include/linux/of_gpio.h b/include/linux/of_gpio.h
index 1fe205582111..18a7f03e1182 100644
--- a/include/linux/of_gpio.h
+++ b/include/linux/of_gpio.h
@@ -31,7 +31,7 @@ enum of_gpio_flags {
31 OF_GPIO_ACTIVE_LOW = 0x1, 31 OF_GPIO_ACTIVE_LOW = 0x1,
32 OF_GPIO_SINGLE_ENDED = 0x2, 32 OF_GPIO_SINGLE_ENDED = 0x2,
33 OF_GPIO_OPEN_DRAIN = 0x4, 33 OF_GPIO_OPEN_DRAIN = 0x4,
34 OF_GPIO_SLEEP_MAY_LOSE_VALUE = 0x8, 34 OF_GPIO_TRANSITORY = 0x8,
35}; 35};
36 36
37#ifdef CONFIG_OF_GPIO 37#ifdef CONFIG_OF_GPIO
diff --git a/include/linux/pinctrl/pinconf-generic.h b/include/linux/pinctrl/pinconf-generic.h
index ec6dadcc1fde..6c0680641108 100644
--- a/include/linux/pinctrl/pinconf-generic.h
+++ b/include/linux/pinctrl/pinconf-generic.h
@@ -94,6 +94,7 @@
94 * or latch delay (on outputs) this parameter (in a custom format) 94 * or latch delay (on outputs) this parameter (in a custom format)
95 * specifies the clock skew or latch delay. It typically controls how 95 * specifies the clock skew or latch delay. It typically controls how
96 * many double inverters are put in front of the line. 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 * @PIN_CONFIG_END: this is the last enumerator for pin configurations, if 98 * @PIN_CONFIG_END: this is the last enumerator for pin configurations, if
98 * you need to pass in custom configurations to the pin controller, use 99 * you need to pass in custom configurations to the pin controller, use
99 * PIN_CONFIG_END+1 as the base offset. 100 * PIN_CONFIG_END+1 as the base offset.
@@ -122,6 +123,7 @@ enum pin_config_param {
122 PIN_CONFIG_SLEEP_HARDWARE_STATE, 123 PIN_CONFIG_SLEEP_HARDWARE_STATE,
123 PIN_CONFIG_SLEW_RATE, 124 PIN_CONFIG_SLEW_RATE,
124 PIN_CONFIG_SKEW_DELAY, 125 PIN_CONFIG_SKEW_DELAY,
126 PIN_CONFIG_PERSIST_STATE,
125 PIN_CONFIG_END = 0x7F, 127 PIN_CONFIG_END = 0x7F,
126 PIN_CONFIG_MAX = 0xFF, 128 PIN_CONFIG_MAX = 0xFF,
127}; 129};