From ce0929d222f8cb18a66611642dc0661d633ce192 Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Fri, 10 Nov 2017 15:40:32 +0200 Subject: gpiolib: acpi: Add quirks field to struct acpi_gpio_mapping Some broken ACPI tables might require quirks in the OS. Introduce quirks field in struct acpi_gpio_mapping. Propagate them to struct acpi_gpio_info for further use. Signed-off-by: Andy Shevchenko Reviewed-by: Mika Westerberg Signed-off-by: Linus Walleij --- include/linux/acpi.h | 1 + 1 file changed, 1 insertion(+) (limited to 'include/linux') diff --git a/include/linux/acpi.h b/include/linux/acpi.h index dc1ebfeeb5ec..25fe77fccea0 100644 --- a/include/linux/acpi.h +++ b/include/linux/acpi.h @@ -978,6 +978,7 @@ struct acpi_gpio_mapping { const char *name; const struct acpi_gpio_params *data; unsigned int size; + unsigned int quirks; }; #if defined(CONFIG_ACPI) && defined(CONFIG_GPIOLIB) -- cgit v1.2.3 From 1b2ca32ab0b8311da84fe692522266b32ad4315e Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Fri, 10 Nov 2017 15:40:33 +0200 Subject: gpiolib: acpi: Introduce NO_RESTRICTION quirk Allow to relax IoRestriction for certain cases. One of the use case is incorrectly cooked ACPI table where interrupt pin is defined with GpioIo() macro with IoRestrictionOutputOnly. Signed-off-by: Andy Shevchenko Reviewed-by: Mika Westerberg Signed-off-by: Linus Walleij --- drivers/gpio/gpiolib-acpi.c | 13 ++++++++++--- include/linux/acpi.h | 4 ++++ 2 files changed, 14 insertions(+), 3 deletions(-) (limited to 'include/linux') diff --git a/drivers/gpio/gpiolib-acpi.c b/drivers/gpio/gpiolib-acpi.c index 711f64b9dd30..430a1475212d 100644 --- a/drivers/gpio/gpiolib-acpi.c +++ b/drivers/gpio/gpiolib-acpi.c @@ -496,11 +496,18 @@ int acpi_gpio_update_gpiod_flags(enum gpiod_flags *flags, struct acpi_gpio_info *info) { struct device *dev = &info->adev->dev; + enum gpiod_flags old = *flags; int ret; - ret = __acpi_gpio_update_gpiod_flags(flags, info->flags); - if (ret) - dev_dbg(dev, "Override GPIO initialization flags\n"); + ret = __acpi_gpio_update_gpiod_flags(&old, info->flags); + if (info->quirks & ACPI_GPIO_QUIRK_NO_IO_RESTRICTION) { + if (ret) + dev_warn(dev, FW_BUG "GPIO not in correct mode, fixing\n"); + } else { + if (ret) + dev_dbg(dev, "Override GPIO initialization flags\n"); + *flags = old; + } return ret; } diff --git a/include/linux/acpi.h b/include/linux/acpi.h index 25fe77fccea0..06b6eb775115 100644 --- a/include/linux/acpi.h +++ b/include/linux/acpi.h @@ -978,6 +978,10 @@ struct acpi_gpio_mapping { const char *name; const struct acpi_gpio_params *data; unsigned int size; + +/* Ignore IoRestriction field */ +#define ACPI_GPIO_QUIRK_NO_IO_RESTRICTION BIT(0) + unsigned int quirks; }; -- cgit v1.2.3 From 56a46b6144e7311e2bf605755a168409ef527fc4 Mon Sep 17 00:00:00 2001 From: Linus Walleij Date: Thu, 30 Nov 2017 11:03:05 +0100 Subject: gpio: Clarify that is legacy It should be clear to developers that they should not include this file in new code. Suggested-by: Arnd Bergmann Signed-off-by: Linus Walleij --- include/linux/gpio.h | 10 ++++++++++ 1 file changed, 10 insertions(+) (limited to 'include/linux') diff --git a/include/linux/gpio.h b/include/linux/gpio.h index 8ef7fc0ce0f0..91ed23468530 100644 --- a/include/linux/gpio.h +++ b/include/linux/gpio.h @@ -1,4 +1,14 @@ /* SPDX-License-Identifier: GPL-2.0 */ +/* + * + * + * This is the LEGACY GPIO bulk include file, including legacy APIs. It is + * used for GPIO drivers still referencing the global GPIO numberspace, + * and should not be included in new code. + * + * If you're implementing a GPIO driver, only include + * If you're implementing a GPIO consumer, only include + */ #ifndef __LINUX_GPIO_H #define __LINUX_GPIO_H -- cgit v1.2.3 From e10f72bf4b3e8885c1915a119141481e7fc45ca8 Mon Sep 17 00:00:00 2001 From: Andrew Jeffery Date: Thu, 30 Nov 2017 14:25:24 +1030 Subject: 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 Reviewed-by: Charles Keepax Acked-by: Rob Herring Signed-off-by: Linus Walleij --- drivers/gpio/gpiolib-of.c | 6 ++-- drivers/gpio/gpiolib-sysfs.c | 14 +++++--- drivers/gpio/gpiolib.c | 61 ++++++++++++++++++++++++++++++--- drivers/gpio/gpiolib.h | 2 +- include/dt-bindings/gpio/gpio.h | 6 ++-- include/linux/gpio/consumer.h | 8 +++++ include/linux/gpio/machine.h | 4 +-- include/linux/of_gpio.h | 2 +- include/linux/pinctrl/pinconf-generic.h | 2 ++ 9 files changed, 87 insertions(+), 18 deletions(-) (limited to 'include/linux') 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, *flags |= GPIO_OPEN_SOURCE; } - if (of_flags & OF_GPIO_SLEEP_MAY_LOSE_VALUE) - *flags |= GPIO_SLEEP_MAY_LOSE_VALUE; + if (of_flags & OF_GPIO_TRANSITORY) + *flags |= GPIO_TRANSITORY; return desc; } @@ -214,6 +214,8 @@ static struct gpio_desc *of_parse_own_gpio(struct device_node *np, if (xlate_flags & OF_GPIO_ACTIVE_LOW) *lflags |= GPIO_ACTIVE_LOW; + if (xlate_flags & OF_GPIO_TRANSITORY) + *lflags |= GPIO_TRANSITORY; if (of_property_read_bool(np, "input")) *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, status = -ENODEV; goto done; } - status = gpiod_export(desc, true); - if (status < 0) - gpiod_free(desc); - else - set_bit(FLAG_SYSFS, &desc->flags); + + status = gpiod_set_transitory(desc, false); + if (!status) { + status = gpiod_export(desc, true); + if (status < 0) + gpiod_free(desc); + else + set_bit(FLAG_SYSFS, &desc->flags); + } done: 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) if (lflags & GPIOHANDLE_REQUEST_OPEN_SOURCE) set_bit(FLAG_OPEN_SOURCE, &desc->flags); + ret = gpiod_set_transitory(desc, false); + if (ret < 0) + goto out_free_descs; + /* * Lines have to be requested explicitly for input * or output, else the line will be treated "as is". @@ -2529,6 +2533,49 @@ int gpiod_set_debounce(struct gpio_desc *desc, unsigned debounce) } EXPORT_SYMBOL_GPL(gpiod_set_debounce); +/** + * gpiod_set_transitory - Lose or retain GPIO state on suspend or reset + * @desc: descriptor of the GPIO for which to configure persistence + * @transitory: True to lose state on suspend or reset, false for persistence + * + * Returns: + * 0 on success, otherwise a negative error code. + */ +int gpiod_set_transitory(struct gpio_desc *desc, bool transitory) +{ + struct gpio_chip *chip; + unsigned long packed; + int gpio; + int rc; + + /* + * Handle FLAG_TRANSITORY first, enabling queries to gpiolib for + * persistence state. + */ + if (transitory) + set_bit(FLAG_TRANSITORY, &desc->flags); + else + clear_bit(FLAG_TRANSITORY, &desc->flags); + + /* If the driver supports it, set the persistence state now */ + chip = desc->gdev->chip; + if (!chip->set_config) + return 0; + + packed = pinconf_to_config_packed(PIN_CONFIG_PERSIST_STATE, + !transitory); + gpio = gpio_chip_hwgpio(desc); + rc = chip->set_config(chip, gpio, packed); + if (rc == -ENOTSUPP) { + dev_dbg(&desc->gdev->dev, "Persistence not supported for GPIO %d\n", + gpio); + return 0; + } + + return rc; +} +EXPORT_SYMBOL_GPL(gpiod_set_transitory); + /** * gpiod_is_active_low - test whether a GPIO is active-low or not * @desc: the gpio descriptor to test @@ -3116,8 +3163,7 @@ bool gpiochip_line_is_persistent(struct gpio_chip *chip, unsigned int offset) if (offset >= chip->ngpio) return false; - return !test_bit(FLAG_SLEEP_MAY_LOSE_VALUE, - &chip->gpiodev->descs[offset].flags); + return !test_bit(FLAG_TRANSITORY, &chip->gpiodev->descs[offset].flags); } EXPORT_SYMBOL_GPL(gpiochip_line_is_persistent); @@ -3554,8 +3600,10 @@ int gpiod_configure_flags(struct gpio_desc *desc, const char *con_id, if (lflags & GPIO_OPEN_SOURCE) set_bit(FLAG_OPEN_SOURCE, &desc->flags); - if (lflags & GPIO_SLEEP_MAY_LOSE_VALUE) - set_bit(FLAG_SLEEP_MAY_LOSE_VALUE, &desc->flags); + + status = gpiod_set_transitory(desc, (lflags & GPIO_TRANSITORY)); + if (status < 0) + return status; /* No particular flag request, return here... */ if (!(dflags & GPIOD_FLAGS_BIT_DIR_SET)) { @@ -3669,6 +3717,7 @@ struct gpio_desc *fwnode_get_named_gpiod(struct fwnode_handle *fwnode, bool active_low = false; bool single_ended = false; bool open_drain = false; + bool transitory = false; int ret; if (!fwnode) @@ -3683,6 +3732,7 @@ struct gpio_desc *fwnode_get_named_gpiod(struct fwnode_handle *fwnode, active_low = flags & OF_GPIO_ACTIVE_LOW; single_ended = flags & OF_GPIO_SINGLE_ENDED; open_drain = flags & OF_GPIO_OPEN_DRAIN; + transitory = flags & OF_GPIO_TRANSITORY; } } else if (is_acpi_node(fwnode)) { struct acpi_gpio_info info; @@ -3711,6 +3761,9 @@ struct gpio_desc *fwnode_get_named_gpiod(struct fwnode_handle *fwnode, lflags |= GPIO_OPEN_SOURCE; } + if (transitory) + lflags |= GPIO_TRANSITORY; + ret = gpiod_configure_flags(desc, propname, lflags, dflags); if (ret < 0) { 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 { #define FLAG_OPEN_SOURCE 8 /* Gpio is open source type */ #define FLAG_USED_AS_IRQ 9 /* GPIO is connected to an IRQ */ #define FLAG_IS_HOGGED 11 /* GPIO is hogged */ -#define FLAG_SLEEP_MAY_LOSE_VALUE 12 /* GPIO may lose value in sleep */ +#define FLAG_TRANSITORY 12 /* GPIO may lose value in sleep or reset */ /* Connection label */ 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 @@ #define GPIO_OPEN_DRAIN (GPIO_SINGLE_ENDED | GPIO_LINE_OPEN_DRAIN) #define GPIO_OPEN_SOURCE (GPIO_SINGLE_ENDED | GPIO_LINE_OPEN_SOURCE) -/* Bit 3 express GPIO suspend/resume persistence */ -#define GPIO_SLEEP_MAINTAIN_VALUE 0 -#define GPIO_SLEEP_MAY_LOSE_VALUE 8 +/* Bit 3 express GPIO suspend/resume and reset persistence */ +#define GPIO_PERSISTENT 0 +#define GPIO_TRANSITORY 8 #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, int *value_array); int gpiod_set_debounce(struct gpio_desc *desc, unsigned debounce); +int gpiod_set_transitory(struct gpio_desc *desc, bool transitory); int gpiod_is_active_low(const struct gpio_desc *desc); int gpiod_cansleep(const struct gpio_desc *desc); @@ -431,6 +432,13 @@ static inline int gpiod_set_debounce(struct gpio_desc *desc, unsigned debounce) return -ENOSYS; } +static inline int gpiod_set_transitory(struct gpio_desc *desc, bool transitory) +{ + /* GPIO can never have been requested */ + WARN_ON(1); + return -ENOSYS; +} + static inline int gpiod_is_active_low(const struct gpio_desc *desc) { /* 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 { GPIO_ACTIVE_LOW = (1 << 0), GPIO_OPEN_DRAIN = (1 << 1), GPIO_OPEN_SOURCE = (1 << 2), - GPIO_SLEEP_MAINTAIN_VALUE = (0 << 3), - GPIO_SLEEP_MAY_LOSE_VALUE = (1 << 3), + GPIO_PERSISTENT = (0 << 3), + GPIO_TRANSITORY = (1 << 3), }; /** 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 { OF_GPIO_ACTIVE_LOW = 0x1, OF_GPIO_SINGLE_ENDED = 0x2, OF_GPIO_OPEN_DRAIN = 0x4, - OF_GPIO_SLEEP_MAY_LOSE_VALUE = 0x8, + OF_GPIO_TRANSITORY = 0x8, }; #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 @@ * or latch delay (on outputs) this parameter (in a custom format) * specifies the clock skew or latch delay. It typically controls how * many double inverters are put in front of the line. + * @PIN_CONFIG_PERSIST_STATE: retain pin state across sleep or controller reset * @PIN_CONFIG_END: this is the last enumerator for pin configurations, if * you need to pass in custom configurations to the pin controller, use * PIN_CONFIG_END+1 as the base offset. @@ -122,6 +123,7 @@ enum pin_config_param { PIN_CONFIG_SLEEP_HARDWARE_STATE, PIN_CONFIG_SLEW_RATE, PIN_CONFIG_SKEW_DELAY, + PIN_CONFIG_PERSIST_STATE, PIN_CONFIG_END = 0x7F, PIN_CONFIG_MAX = 0xFF, }; -- cgit v1.2.3 From e0fc62a6552f3d9c21e73cc65844f9aad1892cf7 Mon Sep 17 00:00:00 2001 From: Linus Walleij Date: Tue, 26 Sep 2017 20:27:09 +0200 Subject: w1: w1-gpio: Convert to use GPIO descriptors The w1 master driver includes a complete open drain emulation reimplementation among other things. This converts the driver and all board files using it to use GPIO descriptors associated with the device to look up the GPIO wire, as well ass the optional pull-up GPIO line. When probed from the device tree, the driver will just pick descriptors and use them right off. For the two board files in the kernel, we add descriptor lookups so we do not need to keep any old platform data handling around for the GPIO lines. As the platform data is also a state container for this driver, we augment it to contain the GPIO descriptors. w1_gpio_write_bit_dir() and w1_gpio_write_bit_val() are gone since this pair was a reimplementation of open drain emulation which is now handled by gpiolib. The special "linux,open-drain" flag is a bit of mishap here: it has the same semantic as the same flags in I2C: it means that something in the platform is setting up the line as open drain behind our back. We handle this the same way as in I2C. To drive the pull-up, we need to bypass open drain emulation in gpiolib for the line, and this is done by driving it high using gpiod_set_raw_value() which has been augmented to have the semantic of overriding the open drain emulation. We also augment the documentation to reflect the way to pass GPIO descriptors from the machine. Acked-by: Evgeniy Polyakov Signed-off-by: Linus Walleij --- Documentation/w1/masters/w1-gpio | 17 +++- arch/arm/mach-ixp4xx/vulcan-setup.c | 13 +++- arch/arm/mach-pxa/raumfeld.c | 16 ++-- drivers/w1/masters/w1-gpio.c | 149 +++++++++++++++--------------------- include/linux/w1-gpio.h | 9 +-- 5 files changed, 101 insertions(+), 103 deletions(-) (limited to 'include/linux') diff --git a/Documentation/w1/masters/w1-gpio b/Documentation/w1/masters/w1-gpio index af5d3b4aa851..623961d9e83f 100644 --- a/Documentation/w1/masters/w1-gpio +++ b/Documentation/w1/masters/w1-gpio @@ -8,17 +8,27 @@ Description ----------- GPIO 1-wire bus master driver. The driver uses the GPIO API to control the -wire and the GPIO pin can be specified using platform data. +wire and the GPIO pin can be specified using GPIO machine descriptor tables. +It is also possible to define the master using device tree, see +Documentation/devicetree/bindings/w1/w1-gpio.txt Example (mach-at91) ------------------- +#include #include +static struct gpiod_lookup_table foo_w1_gpiod_table = { + .dev_id = "w1-gpio", + .table = { + GPIO_LOOKUP_IDX("at91-gpio", AT91_PIN_PB20, NULL, 0, + GPIO_ACTIVE_HIGH|GPIO_OPEN_DRAIN), + }, +}; + static struct w1_gpio_platform_data foo_w1_gpio_pdata = { - .pin = AT91_PIN_PB20, - .is_open_drain = 1, + .ext_pullup_enable_pin = -EINVAL, }; static struct platform_device foo_w1_device = { @@ -30,4 +40,5 @@ static struct platform_device foo_w1_device = { ... at91_set_GPIO_periph(foo_w1_gpio_pdata.pin, 1); at91_set_multi_drive(foo_w1_gpio_pdata.pin, 1); + gpiod_add_lookup_table(&foo_w1_gpiod_table); platform_device_register(&foo_w1_device); diff --git a/arch/arm/mach-ixp4xx/vulcan-setup.c b/arch/arm/mach-ixp4xx/vulcan-setup.c index 731fb2019ecb..2c03d2f6b647 100644 --- a/arch/arm/mach-ixp4xx/vulcan-setup.c +++ b/arch/arm/mach-ixp4xx/vulcan-setup.c @@ -16,6 +16,7 @@ #include #include #include +#include #include #include #include @@ -162,9 +163,16 @@ static struct platform_device vulcan_max6369 = { .num_resources = 1, }; +static struct gpiod_lookup_table vulcan_w1_gpiod_table = { + .dev_id = "w1-gpio", + .table = { + GPIO_LOOKUP_IDX("IXP4XX_GPIO_CHIP", 14, NULL, 0, + GPIO_ACTIVE_HIGH | GPIO_OPEN_DRAIN), + }, +}; + static struct w1_gpio_platform_data vulcan_w1_gpio_pdata = { - .pin = 14, - .ext_pullup_enable_pin = -EINVAL, + /* Intentionally left blank */ }; static struct platform_device vulcan_w1_gpio = { @@ -233,6 +241,7 @@ static void __init vulcan_init(void) IXP4XX_EXP_BUS_WR_EN | IXP4XX_EXP_BUS_BYTE_EN; + gpiod_add_lookup_table(&vulcan_w1_gpiod_table); platform_add_devices(vulcan_devices, ARRAY_SIZE(vulcan_devices)); } diff --git a/arch/arm/mach-pxa/raumfeld.c b/arch/arm/mach-pxa/raumfeld.c index 9d662fed03ec..feddca7f3540 100644 --- a/arch/arm/mach-pxa/raumfeld.c +++ b/arch/arm/mach-pxa/raumfeld.c @@ -506,11 +506,16 @@ static void w1_enable_external_pullup(int enable) msleep(100); } +static struct gpiod_lookup_table raumfeld_w1_gpiod_table = { + .dev_id = "w1-gpio", + .table = { + GPIO_LOOKUP_IDX("gpio-pxa", GPIO_ONE_WIRE, NULL, 0, + GPIO_ACTIVE_HIGH | GPIO_OPEN_DRAIN), + }, +}; + static struct w1_gpio_platform_data w1_gpio_platform_data = { - .pin = GPIO_ONE_WIRE, - .is_open_drain = 0, - .enable_external_pullup = w1_enable_external_pullup, - .ext_pullup_enable_pin = -EINVAL, + .enable_external_pullup = w1_enable_external_pullup, }; static struct platform_device raumfeld_w1_gpio_device = { @@ -523,13 +528,14 @@ static struct platform_device raumfeld_w1_gpio_device = { static void __init raumfeld_w1_init(void) { int ret = gpio_request(GPIO_W1_PULLUP_ENABLE, - "W1 external pullup enable"); + "W1 external pullup enable"); if (ret < 0) pr_warn("Unable to request GPIO_W1_PULLUP_ENABLE\n"); else gpio_direction_output(GPIO_W1_PULLUP_ENABLE, 0); + gpiod_add_lookup_table(&raumfeld_w1_gpiod_table); platform_device_register(&raumfeld_w1_gpio_device); } diff --git a/drivers/w1/masters/w1-gpio.c b/drivers/w1/masters/w1-gpio.c index a90728ceec5a..55e11bf8ebaf 100644 --- a/drivers/w1/masters/w1-gpio.c +++ b/drivers/w1/masters/w1-gpio.c @@ -13,9 +13,8 @@ #include #include #include -#include +#include #include -#include #include #include #include @@ -30,11 +29,17 @@ static u8 w1_gpio_set_pullup(void *data, int delay) pdata->pullup_duration = delay; } else { if (pdata->pullup_duration) { - gpio_direction_output(pdata->pin, 1); - + /* + * This will OVERRIDE open drain emulation and force-pull + * the line high for some time. + */ + gpiod_set_raw_value(pdata->gpiod, 1); msleep(pdata->pullup_duration); - - gpio_direction_input(pdata->pin); + /* + * This will simply set the line as input since we are doing + * open drain emulation in the GPIO library. + */ + gpiod_set_value(pdata->gpiod, 1); } pdata->pullup_duration = 0; } @@ -42,28 +47,18 @@ static u8 w1_gpio_set_pullup(void *data, int delay) return 0; } -static void w1_gpio_write_bit_dir(void *data, u8 bit) -{ - struct w1_gpio_platform_data *pdata = data; - - if (bit) - gpio_direction_input(pdata->pin); - else - gpio_direction_output(pdata->pin, 0); -} - -static void w1_gpio_write_bit_val(void *data, u8 bit) +static void w1_gpio_write_bit(void *data, u8 bit) { struct w1_gpio_platform_data *pdata = data; - gpio_set_value(pdata->pin, bit); + gpiod_set_value(pdata->gpiod, bit); } static u8 w1_gpio_read_bit(void *data) { struct w1_gpio_platform_data *pdata = data; - return gpio_get_value(pdata->pin) ? 1 : 0; + return gpiod_get_value(pdata->gpiod) ? 1 : 0; } #if defined(CONFIG_OF) @@ -74,107 +69,85 @@ static const struct of_device_id w1_gpio_dt_ids[] = { MODULE_DEVICE_TABLE(of, w1_gpio_dt_ids); #endif -static int w1_gpio_probe_dt(struct platform_device *pdev) -{ - struct w1_gpio_platform_data *pdata = dev_get_platdata(&pdev->dev); - struct device_node *np = pdev->dev.of_node; - int gpio; - - pdata = devm_kzalloc(&pdev->dev, sizeof(*pdata), GFP_KERNEL); - if (!pdata) - return -ENOMEM; - - if (of_get_property(np, "linux,open-drain", NULL)) - pdata->is_open_drain = 1; - - gpio = of_get_gpio(np, 0); - if (gpio < 0) { - if (gpio != -EPROBE_DEFER) - dev_err(&pdev->dev, - "Failed to parse gpio property for data pin (%d)\n", - gpio); - - return gpio; - } - pdata->pin = gpio; - - gpio = of_get_gpio(np, 1); - if (gpio == -EPROBE_DEFER) - return gpio; - /* ignore other errors as the pullup gpio is optional */ - pdata->ext_pullup_enable_pin = gpio; - - pdev->dev.platform_data = pdata; - - return 0; -} - static int w1_gpio_probe(struct platform_device *pdev) { struct w1_bus_master *master; struct w1_gpio_platform_data *pdata; + struct device *dev = &pdev->dev; + struct device_node *np = dev->of_node; + /* Enforce open drain mode by default */ + enum gpiod_flags gflags = GPIOD_OUT_LOW_OPEN_DRAIN; int err; if (of_have_populated_dt()) { - err = w1_gpio_probe_dt(pdev); - if (err < 0) - return err; + pdata = devm_kzalloc(&pdev->dev, sizeof(*pdata), GFP_KERNEL); + if (!pdata) + return -ENOMEM; + + /* + * This parameter means that something else than the gpiolib has + * already set the line into open drain mode, so we should just + * driver it high/low like we are in full control of the line and + * open drain will happen transparently. + */ + if (of_get_property(np, "linux,open-drain", NULL)) + gflags = GPIOD_OUT_LOW; + + pdev->dev.platform_data = pdata; } - - pdata = dev_get_platdata(&pdev->dev); + pdata = dev_get_platdata(dev); if (!pdata) { - dev_err(&pdev->dev, "No configuration data\n"); + dev_err(dev, "No configuration data\n"); return -ENXIO; } - master = devm_kzalloc(&pdev->dev, sizeof(struct w1_bus_master), + master = devm_kzalloc(dev, sizeof(struct w1_bus_master), GFP_KERNEL); if (!master) { - dev_err(&pdev->dev, "Out of memory\n"); + dev_err(dev, "Out of memory\n"); return -ENOMEM; } - err = devm_gpio_request(&pdev->dev, pdata->pin, "w1"); - if (err) { - dev_err(&pdev->dev, "gpio_request (pin) failed\n"); - return err; + pdata->gpiod = devm_gpiod_get_index(dev, NULL, 0, gflags); + if (IS_ERR(pdata->gpiod)) { + dev_err(dev, "gpio_request (pin) failed\n"); + return PTR_ERR(pdata->gpiod); } - if (gpio_is_valid(pdata->ext_pullup_enable_pin)) { - err = devm_gpio_request_one(&pdev->dev, - pdata->ext_pullup_enable_pin, GPIOF_INIT_LOW, - "w1 pullup"); - if (err < 0) { - dev_err(&pdev->dev, "gpio_request_one " - "(ext_pullup_enable_pin) failed\n"); - return err; - } + pdata->pullup_gpiod = + devm_gpiod_get_index_optional(dev, NULL, 1, GPIOD_OUT_LOW); + if (IS_ERR(pdata->pullup_gpiod)) { + dev_err(dev, "gpio_request_one " + "(ext_pullup_enable_pin) failed\n"); + return PTR_ERR(pdata->pullup_gpiod); } master->data = pdata; master->read_bit = w1_gpio_read_bit; - - if (pdata->is_open_drain) { - gpio_direction_output(pdata->pin, 1); - master->write_bit = w1_gpio_write_bit_val; - } else { - gpio_direction_input(pdata->pin); - master->write_bit = w1_gpio_write_bit_dir; + gpiod_direction_output(pdata->gpiod, 1); + master->write_bit = w1_gpio_write_bit; + + /* + * If we are using open drain emulation from the GPIO library, + * we need to use this pullup function that hammers the line + * high using a raw accessor to provide pull-up for the w1 + * line. + */ + if (gflags == GPIOD_OUT_LOW_OPEN_DRAIN) master->set_pullup = w1_gpio_set_pullup; - } err = w1_add_master_device(master); if (err) { - dev_err(&pdev->dev, "w1_add_master device failed\n"); + dev_err(dev, "w1_add_master device failed\n"); return err; } if (pdata->enable_external_pullup) pdata->enable_external_pullup(1); - if (gpio_is_valid(pdata->ext_pullup_enable_pin)) - gpio_set_value(pdata->ext_pullup_enable_pin, 1); + if (pdata->pullup_gpiod) + gpiod_set_value(pdata->pullup_gpiod, 1); platform_set_drvdata(pdev, master); @@ -189,8 +162,8 @@ static int w1_gpio_remove(struct platform_device *pdev) if (pdata->enable_external_pullup) pdata->enable_external_pullup(0); - if (gpio_is_valid(pdata->ext_pullup_enable_pin)) - gpio_set_value(pdata->ext_pullup_enable_pin, 0); + if (pdata->pullup_gpiod) + gpiod_set_value(pdata->pullup_gpiod, 0); w1_remove_master_device(master); diff --git a/include/linux/w1-gpio.h b/include/linux/w1-gpio.h index d58594a32324..78901ecd2f95 100644 --- a/include/linux/w1-gpio.h +++ b/include/linux/w1-gpio.h @@ -10,16 +10,15 @@ #ifndef _LINUX_W1_GPIO_H #define _LINUX_W1_GPIO_H +struct gpio_desc; + /** * struct w1_gpio_platform_data - Platform-dependent data for w1-gpio - * @pin: GPIO pin to use - * @is_open_drain: GPIO pin is configured as open drain */ struct w1_gpio_platform_data { - unsigned int pin; - unsigned int is_open_drain:1; + struct gpio_desc *gpiod; + struct gpio_desc *pullup_gpiod; void (*enable_external_pullup)(int enable); - unsigned int ext_pullup_enable_pin; unsigned int pullup_duration; }; -- cgit v1.2.3 From 7fda9100bb8258bbdff90f3db5079d28eb9b0013 Mon Sep 17 00:00:00 2001 From: Christophe Leroy Date: Mon, 18 Dec 2017 11:08:29 +0100 Subject: gpio: sysfs: change 'value' attribute to prealloc The GPIO 'value' attribute is time critical. A small bench with 'perf record' on the app below shows that 80% of the time spent in sysfs_kf_seq_show() is spent in memset() for zeroising the buffer. |--67.48%--sysfs_kf_seq_show | | | |--54.40%--memset | | | |--11.49%--dev_attr_show | | | | | |--10.06%--value_show | | | | | | | |--4.75%--sprintf | | | | | This patch changes the attribute type to prealloc, eliminating the need to zeroise the buffer at each read. 'perf record' gives the following result. |--42.41%--sysfs_kf_read | | | |--39.73%--dev_attr_show | | | | | |--38.23%--value_show | | | | | | | |--29.22%--sprintf | | | | | Test done with the following small app: int main(int argc, char **argv) { int fd = open(argv[1], O_RDONLY); for (;;) { int buf[512]; read(fd, buf, 512); lseek(fd, 0, SEEK_SET); } exit(0); } Signed-off-by: Christophe Leroy Signed-off-by: Linus Walleij --- drivers/gpio/gpiolib-sysfs.c | 2 +- include/linux/device.h | 3 +++ 2 files changed, 4 insertions(+), 1 deletion(-) (limited to 'include/linux') diff --git a/drivers/gpio/gpiolib-sysfs.c b/drivers/gpio/gpiolib-sysfs.c index 0bd472ffb072..3b2465bbd5e7 100644 --- a/drivers/gpio/gpiolib-sysfs.c +++ b/drivers/gpio/gpiolib-sysfs.c @@ -138,7 +138,7 @@ static ssize_t value_store(struct device *dev, return status; } -static DEVICE_ATTR_RW(value); +static DEVICE_ATTR_PREALLOC(value, S_IWUSR | S_IRUGO, value_show, value_store); static irqreturn_t gpio_sysfs_irq(int irq, void *priv) { diff --git a/include/linux/device.h b/include/linux/device.h index 9d32000725da..46ac622e5c6f 100644 --- a/include/linux/device.h +++ b/include/linux/device.h @@ -575,6 +575,9 @@ ssize_t device_store_bool(struct device *dev, struct device_attribute *attr, #define DEVICE_ATTR(_name, _mode, _show, _store) \ struct device_attribute dev_attr_##_name = __ATTR(_name, _mode, _show, _store) +#define DEVICE_ATTR_PREALLOC(_name, _mode, _show, _store) \ + struct device_attribute dev_attr_##_name = \ + __ATTR_PREALLOC(_name, _mode, _show, _store) #define DEVICE_ATTR_RW(_name) \ struct device_attribute dev_attr_##_name = __ATTR_RW(_name) #define DEVICE_ATTR_RO(_name) \ -- cgit v1.2.3 From 64ff2c8e468ceff3cd678a4fa2edfc77dadc6bfe Mon Sep 17 00:00:00 2001 From: Stephen Boyd Date: Tue, 9 Jan 2018 17:58:46 -0800 Subject: gpiolib: Export gpiochip_irqchip_irq_valid() to drivers Some pinctrl drivers can use the gpiochip irq valid information to figure out if certain gpios are exposed to the kernel for usage or not. Expose this API so we can use it in the pinmux_ops::request ops. Signed-off-by: Stephen Boyd Acked-by: Bjorn Andersson Signed-off-by: Linus Walleij --- drivers/gpio/gpiolib.c | 5 +++-- include/linux/gpio/driver.h | 3 +++ 2 files changed, 6 insertions(+), 2 deletions(-) (limited to 'include/linux') diff --git a/drivers/gpio/gpiolib.c b/drivers/gpio/gpiolib.c index 0e78a5023cb2..94a5575d1ebe 100644 --- a/drivers/gpio/gpiolib.c +++ b/drivers/gpio/gpiolib.c @@ -1501,14 +1501,15 @@ static void gpiochip_irqchip_free_valid_mask(struct gpio_chip *gpiochip) gpiochip->irq.valid_mask = NULL; } -static bool gpiochip_irqchip_irq_valid(const struct gpio_chip *gpiochip, - unsigned int offset) +bool gpiochip_irqchip_irq_valid(const struct gpio_chip *gpiochip, + unsigned int offset) { /* No mask means all valid */ if (likely(!gpiochip->irq.valid_mask)) return true; return test_bit(offset, gpiochip->irq.valid_mask); } +EXPORT_SYMBOL_GPL(gpiochip_irqchip_irq_valid); /** * gpiochip_set_cascaded_irqchip() - connects a cascaded irqchip to a gpiochip diff --git a/include/linux/gpio/driver.h b/include/linux/gpio/driver.h index 55e672592fa9..b6a05dd0d10a 100644 --- a/include/linux/gpio/driver.h +++ b/include/linux/gpio/driver.h @@ -431,6 +431,9 @@ int gpiochip_irqchip_add_key(struct gpio_chip *gpiochip, bool threaded, struct lock_class_key *lock_key); +bool gpiochip_irqchip_irq_valid(const struct gpio_chip *gpiochip, + unsigned int offset); + #ifdef CONFIG_LOCKDEP /* -- cgit v1.2.3 From 92542edc42496ac4b8f5ba0ae81ab5776db9473b Mon Sep 17 00:00:00 2001 From: Linus Walleij Date: Fri, 29 Dec 2017 22:52:02 +0100 Subject: gpio: Export devm_gpiod_get_from_of_node() for consumers We have been holding back on adding an API for fetching GPIO handles directly from device nodes, strongly preferring to get it from the spawn devices instead. The fwnode interface however already contains an API for doing this, as it is used for opaque device tree nodes or ACPI nodes for getting handles to LEDs and keys that use GPIO: those are specified as one child per LED/key in the device tree and are not individual devices. However regulators present a special problem as they already have helper functions to traverse the device tree from a regulator node and two levels down to fill in data, and as it already traverses GPIO nodes in its own way, and already holds a pointer to each regulators device tree node, it makes most sense to export an API to fetch the GPIO descriptor directly from the node. We only support the devm_* version for now, hopefully no non-devres version will be needed. Signed-off-by: Linus Walleij --- drivers/gpio/devres.c | 42 ++++++++++++++++++++++++++++++++++++++++++ drivers/gpio/gpiolib.c | 9 +++++---- drivers/gpio/gpiolib.h | 6 ++++++ include/linux/gpio/consumer.h | 17 +++++++++++++++++ 4 files changed, 70 insertions(+), 4 deletions(-) (limited to 'include/linux') diff --git a/drivers/gpio/devres.c b/drivers/gpio/devres.c index afbff155a0ba..e82cc763633c 100644 --- a/drivers/gpio/devres.c +++ b/drivers/gpio/devres.c @@ -124,6 +124,48 @@ struct gpio_desc *__must_check devm_gpiod_get_index(struct device *dev, } EXPORT_SYMBOL(devm_gpiod_get_index); +/** + * devm_gpiod_get_from_of_node() - obtain a GPIO from an OF node + * @dev: device for lifecycle management + * @node: handle of the OF node + * @propname: name of the DT property representing the GPIO + * @index: index of the GPIO to obtain for the consumer + * @dflags: GPIO initialization flags + * @label: label to attach to the requested GPIO + * + * Returns: + * On successful request the GPIO pin is configured in accordance with + * provided @dflags. + * + * In case of error an ERR_PTR() is returned. + */ +struct gpio_desc *devm_gpiod_get_from_of_node(struct device *dev, + struct device_node *node, + const char *propname, int index, + enum gpiod_flags dflags, + const char *label) +{ + struct gpio_desc **dr; + struct gpio_desc *desc; + + dr = devres_alloc(devm_gpiod_release, sizeof(struct gpio_desc *), + GFP_KERNEL); + if (!dr) + return ERR_PTR(-ENOMEM); + + desc = gpiod_get_from_of_node(node, propname, index, dflags, label); + if (IS_ERR(desc)) { + devres_free(dr); + return desc; + } + + *dr = desc; + devres_add(dev, dr); + + return desc; +} +EXPORT_SYMBOL(devm_gpiod_get_from_of_node); + /** * devm_fwnode_get_index_gpiod_from_child - get a GPIO descriptor from a * device's child node diff --git a/drivers/gpio/gpiolib.c b/drivers/gpio/gpiolib.c index 6df94492e93e..bf083bc58d30 100644 --- a/drivers/gpio/gpiolib.c +++ b/drivers/gpio/gpiolib.c @@ -3682,10 +3682,10 @@ EXPORT_SYMBOL_GPL(gpiod_get_index); * * In case of error an ERR_PTR() is returned. */ -static struct gpio_desc *gpiod_get_from_of_node(struct device_node *node, - const char *propname, int index, - enum gpiod_flags dflags, - const char *label) +struct gpio_desc *gpiod_get_from_of_node(struct device_node *node, + const char *propname, int index, + enum gpiod_flags dflags, + const char *label) { struct gpio_desc *desc = ERR_PTR(-ENODEV); unsigned long lflags = 0; @@ -3736,6 +3736,7 @@ static struct gpio_desc *gpiod_get_from_of_node(struct device_node *node, return desc; } +EXPORT_SYMBOL(gpiod_get_from_of_node); /** * fwnode_get_named_gpiod - obtain a GPIO from firmware node diff --git a/drivers/gpio/gpiolib.h b/drivers/gpio/gpiolib.h index 6e9228b94437..0ae9f991ede1 100644 --- a/drivers/gpio/gpiolib.h +++ b/drivers/gpio/gpiolib.h @@ -193,6 +193,12 @@ void gpiod_set_array_value_complex(bool raw, bool can_sleep, struct gpio_desc **desc_array, int *value_array); +/* This is just passed between gpiolib and devres */ +struct gpio_desc *gpiod_get_from_of_node(struct device_node *node, + const char *propname, int index, + enum gpiod_flags dflags, + const char *label); + extern struct spinlock gpio_lock; extern struct list_head gpio_devices; diff --git a/include/linux/gpio/consumer.h b/include/linux/gpio/consumer.h index 540b2c142493..dbd065963296 100644 --- a/include/linux/gpio/consumer.h +++ b/include/linux/gpio/consumer.h @@ -151,8 +151,14 @@ struct gpio_desc *gpio_to_desc(unsigned gpio); int desc_to_gpio(const struct gpio_desc *desc); /* Child properties interface */ +struct device_node; struct fwnode_handle; +struct gpio_desc *devm_gpiod_get_from_of_node(struct device *dev, + struct device_node *node, + const char *propname, int index, + enum gpiod_flags dflags, + const char *label); struct gpio_desc *fwnode_get_named_gpiod(struct fwnode_handle *fwnode, const char *propname, int index, enum gpiod_flags dflags, @@ -472,8 +478,19 @@ static inline int desc_to_gpio(const struct gpio_desc *desc) } /* Child properties interface */ +struct device_node; struct fwnode_handle; +static inline +struct gpio_desc *devm_gpiod_get_from_of_node(struct device *dev, + struct device_node *node, + const char *propname, int index, + enum gpiod_flags dflags, + const char *label) +{ + return ERR_PTR(-ENOSYS); +} + static inline struct gpio_desc *fwnode_get_named_gpiod(struct fwnode_handle *fwnode, const char *propname, int index, -- cgit v1.2.3