diff options
Diffstat (limited to 'drivers/gpio')
-rw-r--r-- | drivers/gpio/Kconfig | 27 | ||||
-rw-r--r-- | drivers/gpio/Makefile | 1 | ||||
-rw-r--r-- | drivers/gpio/gpio-brcmstb.c | 21 | ||||
-rw-r--r-- | drivers/gpio/gpio-cros-ec.c | 8 | ||||
-rw-r--r-- | drivers/gpio/gpio-graniterapids.c | 385 | ||||
-rw-r--r-- | drivers/gpio/gpio-gw-pld.c | 1 | ||||
-rw-r--r-- | drivers/gpio/gpio-mc33880.c | 1 | ||||
-rw-r--r-- | drivers/gpio/gpio-pca953x.c | 2 | ||||
-rw-r--r-- | drivers/gpio/gpio-pcf857x.c | 1 | ||||
-rw-r--r-- | drivers/gpio/gpio-pcie-idio-24.c | 2 | ||||
-rw-r--r-- | drivers/gpio/gpio-pl061.c | 1 | ||||
-rw-r--r-- | drivers/gpio/gpio-regmap.c | 4 | ||||
-rw-r--r-- | drivers/gpio/gpio-sch.c | 35 | ||||
-rw-r--r-- | drivers/gpio/gpio-virtio.c | 1 | ||||
-rw-r--r-- | drivers/gpio/gpiolib-acpi.c | 69 | ||||
-rw-r--r-- | drivers/gpio/gpiolib-legacy.c | 49 | ||||
-rw-r--r-- | drivers/gpio/gpiolib-of.c | 23 | ||||
-rw-r--r-- | drivers/gpio/gpiolib-swnode.c | 44 | ||||
-rw-r--r-- | drivers/gpio/gpiolib-sysfs.c | 2 | ||||
-rw-r--r-- | drivers/gpio/gpiolib.c | 26 | ||||
-rw-r--r-- | drivers/gpio/gpiolib.h | 2 |
21 files changed, 587 insertions, 118 deletions
diff --git a/drivers/gpio/Kconfig b/drivers/gpio/Kconfig index cbfcfefdb5..1c28a48915 100644 --- a/drivers/gpio/Kconfig +++ b/drivers/gpio/Kconfig @@ -103,6 +103,15 @@ config GPIO_REGMAP select REGMAP tristate +config GPIO_SWNODE_UNDEFINED + bool + help + This adds a special place holder for software nodes to contain an + undefined GPIO reference, this is primarily used by SPI to allow a + list of GPIO chip selects to mark a certain chip select as being + controlled the SPI device's internal chip select mechanism and not + a GPIO. + # put drivers in the right section, in alphabetical order # This symbol is selected by both I2C and SPI expanders @@ -312,6 +321,24 @@ config GPIO_GENERIC_PLATFORM help Say yes here to support basic platform_device memory-mapped GPIO controllers. +config GPIO_GRANITERAPIDS + tristate "Intel Granite Rapids-D vGPIO support" + depends on X86 || COMPILE_TEST + select GPIOLIB_IRQCHIP + help + Select this to enable virtual GPIO support on platforms with the + following SoCs: + + - Intel Granite Rapids-D + + The driver enables basic GPIO functionality and implements interrupt + support. The virtual GPIO driver controls GPIO lines via a firmware + interface. The physical GPIO pins reside on device that is external + from the main SoC package, such as a BMC or a CPLD. + + To compile this driver as a module, choose M here: the module will + be called gpio-graniterapids. + config GPIO_GRGPIO tristate "Aeroflex Gaisler GRGPIO support" depends on OF_GPIO diff --git a/drivers/gpio/Makefile b/drivers/gpio/Makefile index fdd28c58d8..e2a5301378 100644 --- a/drivers/gpio/Makefile +++ b/drivers/gpio/Makefile @@ -66,6 +66,7 @@ obj-$(CONFIG_GPIO_FTGPIO010) += gpio-ftgpio010.o obj-$(CONFIG_GPIO_FXL6408) += gpio-fxl6408.o obj-$(CONFIG_GPIO_GE_FPGA) += gpio-ge.o obj-$(CONFIG_GPIO_GPIO_MM) += gpio-gpio-mm.o +obj-$(CONFIG_GPIO_GRANITERAPIDS) += gpio-graniterapids.o obj-$(CONFIG_GPIO_GRGPIO) += gpio-grgpio.o obj-$(CONFIG_GPIO_GW_PLD) += gpio-gw-pld.o obj-$(CONFIG_GPIO_HISI) += gpio-hisi.o diff --git a/drivers/gpio/gpio-brcmstb.c b/drivers/gpio/gpio-brcmstb.c index a789af4a5c..8dce78ea71 100644 --- a/drivers/gpio/gpio-brcmstb.c +++ b/drivers/gpio/gpio-brcmstb.c @@ -50,7 +50,6 @@ struct brcmstb_gpio_priv { struct irq_domain *irq_domain; struct irq_chip irq_chip; int parent_irq; - int gpio_base; int num_gpios; int parent_wake_irq; }; @@ -92,7 +91,7 @@ brcmstb_gpio_get_active_irqs(struct brcmstb_gpio_bank *bank) static int brcmstb_gpio_hwirq_to_offset(irq_hw_number_t hwirq, struct brcmstb_gpio_bank *bank) { - return hwirq - (bank->gc.base - bank->parent_priv->gpio_base); + return hwirq - bank->gc.offset; } static void brcmstb_gpio_set_imask(struct brcmstb_gpio_bank *bank, @@ -118,7 +117,7 @@ static int brcmstb_gpio_to_irq(struct gpio_chip *gc, unsigned offset) { struct brcmstb_gpio_priv *priv = brcmstb_gpio_gc_to_priv(gc); /* gc_offset is relative to this gpio_chip; want real offset */ - int hwirq = offset + (gc->base - priv->gpio_base); + int hwirq = offset + gc->offset; if (hwirq >= priv->num_gpios) return -ENXIO; @@ -263,7 +262,7 @@ static void brcmstb_gpio_irq_bank_handler(struct brcmstb_gpio_bank *bank) { struct brcmstb_gpio_priv *priv = bank->parent_priv; struct irq_domain *domain = priv->irq_domain; - int hwbase = bank->gc.base - priv->gpio_base; + int hwbase = bank->gc.offset; unsigned long status; while ((status = brcmstb_gpio_get_active_irqs(bank))) { @@ -412,7 +411,7 @@ static int brcmstb_gpio_of_xlate(struct gpio_chip *gc, if (WARN_ON(gpiospec->args_count < gc->of_gpio_n_cells)) return -EINVAL; - offset = gpiospec->args[0] - (gc->base - priv->gpio_base); + offset = gpiospec->args[0] - bank->gc.offset; if (offset >= gc->ngpio || offset < 0) return -EINVAL; @@ -596,8 +595,8 @@ static int brcmstb_gpio_probe(struct platform_device *pdev) const __be32 *p; u32 bank_width; int num_banks = 0; + int num_gpios = 0; int err; - static int gpio_base; unsigned long flags = 0; bool need_wakeup_event = false; @@ -611,7 +610,6 @@ static int brcmstb_gpio_probe(struct platform_device *pdev) if (IS_ERR(reg_base)) return PTR_ERR(reg_base); - priv->gpio_base = gpio_base; priv->reg_base = reg_base; priv->pdev = pdev; @@ -651,7 +649,7 @@ static int brcmstb_gpio_probe(struct platform_device *pdev) dev_dbg(dev, "Width 0 found: Empty bank @ %d\n", num_banks); num_banks++; - gpio_base += MAX_GPIO_PER_BANK; + num_gpios += MAX_GPIO_PER_BANK; continue; } @@ -691,12 +689,13 @@ static int brcmstb_gpio_probe(struct platform_device *pdev) err = -ENOMEM; goto fail; } - gc->base = gpio_base; gc->of_gpio_n_cells = 2; gc->of_xlate = brcmstb_gpio_of_xlate; /* not all ngpio lines are valid, will use bank width later */ gc->ngpio = MAX_GPIO_PER_BANK; gc->offset = bank->id * MAX_GPIO_PER_BANK; + gc->request = gpiochip_generic_request; + gc->free = gpiochip_generic_free; if (priv->parent_irq > 0) gc->to_irq = brcmstb_gpio_to_irq; @@ -713,7 +712,7 @@ static int brcmstb_gpio_probe(struct platform_device *pdev) bank->id); goto fail; } - gpio_base += gc->ngpio; + num_gpios += gc->ngpio; dev_dbg(dev, "bank=%d, base=%d, ngpio=%d, width=%d\n", bank->id, gc->base, gc->ngpio, bank->width); @@ -724,7 +723,7 @@ static int brcmstb_gpio_probe(struct platform_device *pdev) num_banks++; } - priv->num_gpios = gpio_base - priv->gpio_base; + priv->num_gpios = num_gpios; if (priv->parent_irq > 0) { err = brcmstb_gpio_irq_setup(pdev, priv); if (err) diff --git a/drivers/gpio/gpio-cros-ec.c b/drivers/gpio/gpio-cros-ec.c index 842e1c0604..0c09bb54dc 100644 --- a/drivers/gpio/gpio-cros-ec.c +++ b/drivers/gpio/gpio-cros-ec.c @@ -12,6 +12,7 @@ #include <linux/errno.h> #include <linux/gpio/driver.h> #include <linux/kernel.h> +#include <linux/mod_devicetable.h> #include <linux/module.h> #include <linux/platform_data/cros_ec_commands.h> #include <linux/platform_data/cros_ec_proto.h> @@ -197,11 +198,18 @@ static int cros_ec_gpio_probe(struct platform_device *pdev) return devm_gpiochip_add_data(dev, gc, cros_ec); } +static const struct platform_device_id cros_ec_gpio_id[] = { + { "cros-ec-gpio", 0 }, + {} +}; +MODULE_DEVICE_TABLE(platform, cros_ec_gpio_id); + static struct platform_driver cros_ec_gpio_driver = { .probe = cros_ec_gpio_probe, .driver = { .name = "cros-ec-gpio", }, + .id_table = cros_ec_gpio_id, }; module_platform_driver(cros_ec_gpio_driver); diff --git a/drivers/gpio/gpio-graniterapids.c b/drivers/gpio/gpio-graniterapids.c new file mode 100644 index 0000000000..f2e911a3d2 --- /dev/null +++ b/drivers/gpio/gpio-graniterapids.c @@ -0,0 +1,385 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Intel Granite Rapids-D vGPIO driver + * + * Copyright (c) 2024, Intel Corporation. + * + * Author: Aapo Vienamo <aapo.vienamo@linux.intel.com> + */ + +#include <linux/array_size.h> +#include <linux/bitfield.h> +#include <linux/bitmap.h> +#include <linux/cleanup.h> +#include <linux/device.h> +#include <linux/err.h> +#include <linux/gfp_types.h> +#include <linux/interrupt.h> +#include <linux/io.h> +#include <linux/irq.h> +#include <linux/math.h> +#include <linux/mod_devicetable.h> +#include <linux/module.h> +#include <linux/overflow.h> +#include <linux/platform_device.h> +#include <linux/pm.h> +#include <linux/spinlock.h> +#include <linux/types.h> + +#include <linux/gpio/driver.h> + +#define GNR_NUM_PINS 128 +#define GNR_PINS_PER_REG 32 +#define GNR_NUM_REGS DIV_ROUND_UP(GNR_NUM_PINS, GNR_PINS_PER_REG) + +#define GNR_CFG_BAR 0x00 +#define GNR_CFG_LOCK_OFFSET 0x04 +#define GNR_GPI_STATUS_OFFSET 0x20 +#define GNR_GPI_ENABLE_OFFSET 0x24 + +#define GNR_CFG_DW_RX_MASK GENMASK(25, 22) +#define GNR_CFG_DW_RX_DISABLE FIELD_PREP(GNR_CFG_DW_RX_MASK, 2) +#define GNR_CFG_DW_RX_EDGE FIELD_PREP(GNR_CFG_DW_RX_MASK, 1) +#define GNR_CFG_DW_RX_LEVEL FIELD_PREP(GNR_CFG_DW_RX_MASK, 0) +#define GNR_CFG_DW_RXDIS BIT(4) +#define GNR_CFG_DW_TXDIS BIT(3) +#define GNR_CFG_DW_RXSTATE BIT(1) +#define GNR_CFG_DW_TXSTATE BIT(0) + +/** + * struct gnr_gpio - Intel Granite Rapids-D vGPIO driver state + * @gc: GPIO controller interface + * @reg_base: base address of the GPIO registers + * @ro_bitmap: bitmap of read-only pins + * @lock: guard the registers + * @pad_backup: backup of the register state for suspend + */ +struct gnr_gpio { + struct gpio_chip gc; + void __iomem *reg_base; + DECLARE_BITMAP(ro_bitmap, GNR_NUM_PINS); + raw_spinlock_t lock; + u32 pad_backup[]; +}; + +static void __iomem *gnr_gpio_get_padcfg_addr(const struct gnr_gpio *priv, + unsigned int gpio) +{ + return priv->reg_base + gpio * sizeof(u32); +} + +static int gnr_gpio_configure_line(struct gpio_chip *gc, unsigned int gpio, + u32 clear_mask, u32 set_mask) +{ + struct gnr_gpio *priv = gpiochip_get_data(gc); + void __iomem *addr = gnr_gpio_get_padcfg_addr(priv, gpio); + u32 dw; + + if (test_bit(gpio, priv->ro_bitmap)) + return -EACCES; + + guard(raw_spinlock_irqsave)(&priv->lock); + + dw = readl(addr); + dw &= ~clear_mask; + dw |= set_mask; + writel(dw, addr); + + return 0; +} + +static int gnr_gpio_get(struct gpio_chip *gc, unsigned int gpio) +{ + const struct gnr_gpio *priv = gpiochip_get_data(gc); + u32 dw; + + dw = readl(gnr_gpio_get_padcfg_addr(priv, gpio)); + + return !!(dw & GNR_CFG_DW_RXSTATE); +} + +static void gnr_gpio_set(struct gpio_chip *gc, unsigned int gpio, int value) +{ + u32 clear = 0; + u32 set = 0; + + if (value) + set = GNR_CFG_DW_TXSTATE; + else + clear = GNR_CFG_DW_TXSTATE; + + gnr_gpio_configure_line(gc, gpio, clear, set); +} + +static int gnr_gpio_get_direction(struct gpio_chip *gc, unsigned int gpio) +{ + struct gnr_gpio *priv = gpiochip_get_data(gc); + u32 dw; + + dw = readl(gnr_gpio_get_padcfg_addr(priv, gpio)); + + if (dw & GNR_CFG_DW_TXDIS) + return GPIO_LINE_DIRECTION_IN; + + return GPIO_LINE_DIRECTION_OUT; +} + +static int gnr_gpio_direction_input(struct gpio_chip *gc, unsigned int gpio) +{ + return gnr_gpio_configure_line(gc, gpio, GNR_CFG_DW_RXDIS, 0); +} + +static int gnr_gpio_direction_output(struct gpio_chip *gc, unsigned int gpio, int value) +{ + u32 clear = GNR_CFG_DW_TXDIS; + u32 set = value ? GNR_CFG_DW_TXSTATE : 0; + + return gnr_gpio_configure_line(gc, gpio, clear, set); +} + +static const struct gpio_chip gnr_gpio_chip = { + .owner = THIS_MODULE, + .get = gnr_gpio_get, + .set = gnr_gpio_set, + .get_direction = gnr_gpio_get_direction, + .direction_input = gnr_gpio_direction_input, + .direction_output = gnr_gpio_direction_output, +}; + +static void __iomem *gnr_gpio_get_reg_addr(const struct gnr_gpio *priv, + unsigned int base, + unsigned int gpio) +{ + return priv->reg_base + base + gpio * sizeof(u32); +} + +static void gnr_gpio_irq_ack(struct irq_data *d) +{ + struct gpio_chip *gc = irq_data_get_irq_chip_data(d); + struct gnr_gpio *priv = gpiochip_get_data(gc); + irq_hw_number_t gpio = irqd_to_hwirq(d); + unsigned int reg_idx = gpio / GNR_PINS_PER_REG; + unsigned int bit_idx = gpio % GNR_PINS_PER_REG; + void __iomem *addr = gnr_gpio_get_reg_addr(priv, GNR_GPI_STATUS_OFFSET, reg_idx); + u32 reg; + + guard(raw_spinlock_irqsave)(&priv->lock); + + reg = readl(addr); + reg &= ~BIT(bit_idx); + writel(reg, addr); +} + +static void gnr_gpio_irq_mask_unmask(struct gpio_chip *gc, unsigned long gpio, bool mask) +{ + struct gnr_gpio *priv = gpiochip_get_data(gc); + unsigned int reg_idx = gpio / GNR_PINS_PER_REG; + unsigned int bit_idx = gpio % GNR_PINS_PER_REG; + void __iomem *addr = gnr_gpio_get_reg_addr(priv, GNR_GPI_ENABLE_OFFSET, reg_idx); + u32 reg; + + guard(raw_spinlock_irqsave)(&priv->lock); + + reg = readl(addr); + if (mask) + reg &= ~BIT(bit_idx); + else + reg |= BIT(bit_idx); + writel(reg, addr); +} + +static void gnr_gpio_irq_mask(struct irq_data *d) +{ + struct gpio_chip *gc = irq_data_get_irq_chip_data(d); + irq_hw_number_t hwirq = irqd_to_hwirq(d); + + gnr_gpio_irq_mask_unmask(gc, hwirq, true); + gpiochip_disable_irq(gc, hwirq); +} + +static void gnr_gpio_irq_unmask(struct irq_data *d) +{ + struct gpio_chip *gc = irq_data_get_irq_chip_data(d); + irq_hw_number_t hwirq = irqd_to_hwirq(d); + + gpiochip_enable_irq(gc, hwirq); + gnr_gpio_irq_mask_unmask(gc, hwirq, false); +} + +static int gnr_gpio_irq_set_type(struct irq_data *d, unsigned int type) +{ + struct gpio_chip *gc = irq_data_get_irq_chip_data(d); + irq_hw_number_t pin = irqd_to_hwirq(d); + u32 mask = GNR_CFG_DW_RX_MASK; + u32 set; + + /* Falling edge and level low triggers not supported by the GPIO controller */ + switch (type) { + case IRQ_TYPE_NONE: + set = GNR_CFG_DW_RX_DISABLE; + break; + case IRQ_TYPE_EDGE_RISING: + set = GNR_CFG_DW_RX_EDGE; + irq_set_handler_locked(d, handle_edge_irq); + break; + case IRQ_TYPE_LEVEL_HIGH: + set = GNR_CFG_DW_RX_LEVEL; + irq_set_handler_locked(d, handle_level_irq); + break; + default: + return -EINVAL; + } + + return gnr_gpio_configure_line(gc, pin, mask, set); +} + +static const struct irq_chip gnr_gpio_irq_chip = { + .irq_ack = gnr_gpio_irq_ack, + .irq_mask = gnr_gpio_irq_mask, + .irq_unmask = gnr_gpio_irq_unmask, + .irq_set_type = gnr_gpio_irq_set_type, + .flags = IRQCHIP_IMMUTABLE, + GPIOCHIP_IRQ_RESOURCE_HELPERS, +}; + +static void gnr_gpio_init_pin_ro_bits(struct device *dev, + const void __iomem *cfg_lock_base, + unsigned long *ro_bitmap) +{ + u32 tmp[GNR_NUM_REGS]; + + memcpy_fromio(tmp, cfg_lock_base, sizeof(tmp)); + bitmap_from_arr32(ro_bitmap, tmp, GNR_NUM_PINS); +} + +static irqreturn_t gnr_gpio_irq(int irq, void *data) +{ + struct gnr_gpio *priv = data; + unsigned int handled = 0; + + for (unsigned int i = 0; i < GNR_NUM_REGS; i++) { + const void __iomem *reg = priv->reg_base + i * sizeof(u32); + unsigned long pending; + unsigned long enabled; + unsigned int bit_idx; + + scoped_guard(raw_spinlock, &priv->lock) { + pending = readl(reg + GNR_GPI_STATUS_OFFSET); + enabled = readl(reg + GNR_GPI_ENABLE_OFFSET); + } + + /* Only enabled interrupts */ + pending &= enabled; + + for_each_set_bit(bit_idx, &pending, GNR_PINS_PER_REG) { + unsigned int hwirq = i * GNR_PINS_PER_REG + bit_idx; + + generic_handle_domain_irq(priv->gc.irq.domain, hwirq); + } + + handled += pending ? 1 : 0; + + } + return IRQ_RETVAL(handled); +} + +static int gnr_gpio_probe(struct platform_device *pdev) +{ + size_t num_backup_pins = IS_ENABLED(CONFIG_PM_SLEEP) ? GNR_NUM_PINS : 0; + struct device *dev = &pdev->dev; + struct gpio_irq_chip *girq; + struct gnr_gpio *priv; + void __iomem *regs; + int irq, ret; + + priv = devm_kzalloc(dev, struct_size(priv, pad_backup, num_backup_pins), GFP_KERNEL); + if (!priv) + return -ENOMEM; + + raw_spin_lock_init(&priv->lock); + + regs = devm_platform_ioremap_resource(pdev, 0); + if (IS_ERR(regs)) + return PTR_ERR(regs); + + irq = platform_get_irq(pdev, 0); + if (irq < 0) + return irq; + + ret = devm_request_irq(dev, irq, gnr_gpio_irq, IRQF_SHARED | IRQF_NO_THREAD, + dev_name(dev), priv); + if (ret) + return dev_err_probe(dev, ret, "failed to request interrupt\n"); + + priv->reg_base = regs + readl(regs + GNR_CFG_BAR); + + gnr_gpio_init_pin_ro_bits(dev, priv->reg_base + GNR_CFG_LOCK_OFFSET, + priv->ro_bitmap); + + priv->gc = gnr_gpio_chip; + priv->gc.label = dev_name(dev); + priv->gc.parent = dev; + priv->gc.ngpio = GNR_NUM_PINS; + priv->gc.base = -1; + + girq = &priv->gc.irq; + gpio_irq_chip_set_chip(girq, &gnr_gpio_irq_chip); + girq->chip->name = dev_name(dev); + girq->parent_handler = NULL; + girq->num_parents = 0; + girq->parents = NULL; + girq->default_type = IRQ_TYPE_NONE; + girq->handler = handle_bad_irq; + + platform_set_drvdata(pdev, priv); + + return devm_gpiochip_add_data(dev, &priv->gc, priv); +} + +static int gnr_gpio_suspend(struct device *dev) +{ + struct gnr_gpio *priv = dev_get_drvdata(dev); + unsigned int i; + + guard(raw_spinlock_irqsave)(&priv->lock); + + for_each_clear_bit(i, priv->ro_bitmap, priv->gc.ngpio) + priv->pad_backup[i] = readl(gnr_gpio_get_padcfg_addr(priv, i)); + + return 0; +} + +static int gnr_gpio_resume(struct device *dev) +{ + struct gnr_gpio *priv = dev_get_drvdata(dev); + unsigned int i; + + guard(raw_spinlock_irqsave)(&priv->lock); + + for_each_clear_bit(i, priv->ro_bitmap, priv->gc.ngpio) + writel(priv->pad_backup[i], gnr_gpio_get_padcfg_addr(priv, i)); + + return 0; +} + +static DEFINE_SIMPLE_DEV_PM_OPS(gnr_gpio_pm_ops, gnr_gpio_suspend, gnr_gpio_resume); + +static const struct acpi_device_id gnr_gpio_acpi_match[] = { + { "INTC1109" }, + {} +}; +MODULE_DEVICE_TABLE(acpi, gnr_gpio_acpi_match); + +static struct platform_driver gnr_gpio_driver = { + .driver = { + .name = "gpio-graniterapids", + .pm = pm_sleep_ptr(&gnr_gpio_pm_ops), + .acpi_match_table = gnr_gpio_acpi_match, + }, + .probe = gnr_gpio_probe, +}; +module_platform_driver(gnr_gpio_driver); + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Aapo Vienamo <aapo.vienamo@linux.intel.com>"); +MODULE_DESCRIPTION("Intel Granite Rapids-D vGPIO driver"); diff --git a/drivers/gpio/gpio-gw-pld.c b/drivers/gpio/gpio-gw-pld.c index 899335da93..7e29a2d8de 100644 --- a/drivers/gpio/gpio-gw-pld.c +++ b/drivers/gpio/gpio-gw-pld.c @@ -130,5 +130,6 @@ static struct i2c_driver gw_pld_driver = { }; module_i2c_driver(gw_pld_driver); +MODULE_DESCRIPTION("Gateworks I2C PLD GPIO expander"); MODULE_LICENSE("GPL"); MODULE_AUTHOR("Linus Walleij <linus.walleij@linaro.org>"); diff --git a/drivers/gpio/gpio-mc33880.c b/drivers/gpio/gpio-mc33880.c index cd9b16dbe1..94f6fefc01 100644 --- a/drivers/gpio/gpio-mc33880.c +++ b/drivers/gpio/gpio-mc33880.c @@ -168,5 +168,6 @@ static void __exit mc33880_exit(void) module_exit(mc33880_exit); MODULE_AUTHOR("Mocean Laboratories <info@mocean-labs.com>"); +MODULE_DESCRIPTION("MC33880 high-side/low-side switch GPIO driver"); MODULE_LICENSE("GPL v2"); diff --git a/drivers/gpio/gpio-pca953x.c b/drivers/gpio/gpio-pca953x.c index f2f40393e3..732a696474 100644 --- a/drivers/gpio/gpio-pca953x.c +++ b/drivers/gpio/gpio-pca953x.c @@ -144,7 +144,7 @@ static int pca953x_acpi_get_irq(struct device *dev) if (ret) dev_warn(dev, "can't add GPIO ACPI mapping\n"); - ret = acpi_dev_gpio_irq_get_by(ACPI_COMPANION(dev), "irq-gpios", 0); + ret = acpi_dev_gpio_irq_get_by(ACPI_COMPANION(dev), "irq", 0); if (ret < 0) return ret; diff --git a/drivers/gpio/gpio-pcf857x.c b/drivers/gpio/gpio-pcf857x.c index 53b69abe67..7c57eaeb0a 100644 --- a/drivers/gpio/gpio-pcf857x.c +++ b/drivers/gpio/gpio-pcf857x.c @@ -438,5 +438,6 @@ static void __exit pcf857x_exit(void) } module_exit(pcf857x_exit); +MODULE_DESCRIPTION("Driver for pcf857x, pca857x, and pca967x I2C GPIO expanders"); MODULE_LICENSE("GPL"); MODULE_AUTHOR("David Brownell"); diff --git a/drivers/gpio/gpio-pcie-idio-24.c b/drivers/gpio/gpio-pcie-idio-24.c index 2efd1b1a08..7f7f95ad43 100644 --- a/drivers/gpio/gpio-pcie-idio-24.c +++ b/drivers/gpio/gpio-pcie-idio-24.c @@ -267,7 +267,7 @@ static int idio_24_reg_mask_xlate(struct gpio_regmap *const gpio, const unsigned case IDIO_24_CONTROL_REG: /* We can only set direction for TTL/CMOS lines */ if (offset < 48) - return -EOPNOTSUPP; + return -ENOTSUPP; *reg = IDIO_24_CONTROL_REG; *mask = CONTROL_REG_OUT_MODE; diff --git a/drivers/gpio/gpio-pl061.c b/drivers/gpio/gpio-pl061.c index 9fc1f3dd41..a211a02d4b 100644 --- a/drivers/gpio/gpio-pl061.c +++ b/drivers/gpio/gpio-pl061.c @@ -438,4 +438,5 @@ static struct amba_driver pl061_gpio_driver = { }; module_amba_driver(pl061_gpio_driver); +MODULE_DESCRIPTION("Driver for the ARM PrimeCell(tm) General Purpose Input/Output (PL061)"); MODULE_LICENSE("GPL v2"); diff --git a/drivers/gpio/gpio-regmap.c b/drivers/gpio/gpio-regmap.c index c08c8e5288..71684dee2c 100644 --- a/drivers/gpio/gpio-regmap.c +++ b/drivers/gpio/gpio-regmap.c @@ -129,7 +129,7 @@ static int gpio_regmap_get_direction(struct gpio_chip *chip, base = gpio_regmap_addr(gpio->reg_dir_in_base); invert = 1; } else { - return -EOPNOTSUPP; + return -ENOTSUPP; } ret = gpio->reg_mask_xlate(gpio, base, offset, ®, &mask); @@ -160,7 +160,7 @@ static int gpio_regmap_set_direction(struct gpio_chip *chip, base = gpio_regmap_addr(gpio->reg_dir_in_base); invert = 1; } else { - return -EOPNOTSUPP; + return -ENOTSUPP; } ret = gpio->reg_mask_xlate(gpio, base, offset, ®, &mask); diff --git a/drivers/gpio/gpio-sch.c b/drivers/gpio/gpio-sch.c index e48392074e..ff0341b122 100644 --- a/drivers/gpio/gpio-sch.c +++ b/drivers/gpio/gpio-sch.c @@ -38,8 +38,8 @@ struct sch_gpio { struct gpio_chip chip; + void __iomem *regs; spinlock_t lock; - unsigned short iobase; unsigned short resume_base; /* GPE handling */ @@ -75,7 +75,7 @@ static int sch_gpio_reg_get(struct sch_gpio *sch, unsigned int gpio, unsigned in offset = sch_gpio_offset(sch, gpio, reg); bit = sch_gpio_bit(sch, gpio); - reg_val = !!(inb(sch->iobase + offset) & BIT(bit)); + reg_val = !!(ioread8(sch->regs + offset) & BIT(bit)); return reg_val; } @@ -89,12 +89,14 @@ static void sch_gpio_reg_set(struct sch_gpio *sch, unsigned int gpio, unsigned i offset = sch_gpio_offset(sch, gpio, reg); bit = sch_gpio_bit(sch, gpio); - reg_val = inb(sch->iobase + offset); + reg_val = ioread8(sch->regs + offset); if (val) - outb(reg_val | BIT(bit), sch->iobase + offset); + reg_val |= BIT(bit); else - outb((reg_val & ~BIT(bit)), sch->iobase + offset); + reg_val &= ~BIT(bit); + + iowrite8(reg_val, sch->regs + offset); } static int sch_gpio_direction_in(struct gpio_chip *gc, unsigned int gpio_num) @@ -267,8 +269,8 @@ static u32 sch_gpio_gpe_handler(acpi_handle gpe_device, u32 gpe, void *context) spin_lock_irqsave(&sch->lock, flags); - core_status = inl(sch->iobase + CORE_BANK_OFFSET + GTS); - resume_status = inl(sch->iobase + RESUME_BANK_OFFSET + GTS); + core_status = ioread32(sch->regs + CORE_BANK_OFFSET + GTS); + resume_status = ioread32(sch->regs + RESUME_BANK_OFFSET + GTS); spin_unlock_irqrestore(&sch->lock, flags); @@ -319,12 +321,14 @@ static int sch_gpio_install_gpe_handler(struct sch_gpio *sch) static int sch_gpio_probe(struct platform_device *pdev) { + struct device *dev = &pdev->dev; struct gpio_irq_chip *girq; struct sch_gpio *sch; struct resource *res; + void __iomem *regs; int ret; - sch = devm_kzalloc(&pdev->dev, sizeof(*sch), GFP_KERNEL); + sch = devm_kzalloc(dev, sizeof(*sch), GFP_KERNEL); if (!sch) return -ENOMEM; @@ -332,15 +336,16 @@ static int sch_gpio_probe(struct platform_device *pdev) if (!res) return -EBUSY; - if (!devm_request_region(&pdev->dev, res->start, resource_size(res), - pdev->name)) + regs = devm_ioport_map(dev, res->start, resource_size(res)); + if (!regs) return -EBUSY; + sch->regs = regs; + spin_lock_init(&sch->lock); - sch->iobase = res->start; sch->chip = sch_gpio_chip; - sch->chip.label = dev_name(&pdev->dev); - sch->chip.parent = &pdev->dev; + sch->chip.label = dev_name(dev); + sch->chip.parent = dev; switch (pdev->id) { case PCI_DEVICE_ID_INTEL_SCH_LPC: @@ -394,9 +399,9 @@ static int sch_gpio_probe(struct platform_device *pdev) ret = sch_gpio_install_gpe_handler(sch); if (ret) - dev_warn(&pdev->dev, "Can't setup GPE, no IRQ support\n"); + dev_warn(dev, "Can't setup GPE, no IRQ support\n"); - return devm_gpiochip_add_data(&pdev->dev, &sch->chip, sch); + return devm_gpiochip_add_data(dev, &sch->chip, sch); } static struct platform_driver sch_gpio_driver = { diff --git a/drivers/gpio/gpio-virtio.c b/drivers/gpio/gpio-virtio.c index fcc5e8c089..9fae8e396c 100644 --- a/drivers/gpio/gpio-virtio.c +++ b/drivers/gpio/gpio-virtio.c @@ -653,7 +653,6 @@ static struct virtio_driver virtio_gpio_driver = { .remove = virtio_gpio_remove, .driver = { .name = KBUILD_MODNAME, - .owner = THIS_MODULE, }, }; module_virtio_driver(virtio_gpio_driver); diff --git a/drivers/gpio/gpiolib-acpi.c b/drivers/gpio/gpiolib-acpi.c index c1e190d3ea..bb063b81ce 100644 --- a/drivers/gpio/gpiolib-acpi.c +++ b/drivers/gpio/gpiolib-acpi.c @@ -890,9 +890,6 @@ static struct gpio_desc *acpi_get_gpiod_by_index(struct acpi_device *adev, struct acpi_gpio_lookup lookup; int ret; - if (!adev) - return ERR_PTR(-ENODEV); - memset(&lookup, 0, sizeof(lookup)); lookup.index = index; @@ -958,6 +955,10 @@ static struct gpio_desc *acpi_get_gpiod_from_data(struct fwnode_handle *fwnode, static bool acpi_can_fallback_to_crs(struct acpi_device *adev, const char *con_id) { + /* If there is no ACPI device, there is no _CRS to fall back to */ + if (!adev) + return false; + /* Never allow fallback if the device has properties */ if (acpi_dev_has_props(adev) || adev->driver_gpios) return false; @@ -965,14 +966,11 @@ static bool acpi_can_fallback_to_crs(struct acpi_device *adev, return con_id == NULL; } -struct gpio_desc *acpi_find_gpio(struct fwnode_handle *fwnode, - const char *con_id, - unsigned int idx, - enum gpiod_flags *dflags, - unsigned long *lookupflags) +static struct gpio_desc * +__acpi_find_gpio(struct fwnode_handle *fwnode, const char *con_id, unsigned int idx, + bool can_fallback, struct acpi_gpio_info *info) { struct acpi_device *adev = to_acpi_device_node(fwnode); - struct acpi_gpio_info info; struct gpio_desc *desc; char propname[32]; int i; @@ -989,25 +987,38 @@ struct gpio_desc *acpi_find_gpio(struct fwnode_handle *fwnode, if (adev) desc = acpi_get_gpiod_by_index(adev, - propname, idx, &info); + propname, idx, info); else desc = acpi_get_gpiod_from_data(fwnode, - propname, idx, &info); - if (!IS_ERR(desc)) - break; + propname, idx, info); if (PTR_ERR(desc) == -EPROBE_DEFER) return ERR_CAST(desc); + + if (!IS_ERR(desc)) + return desc; } /* Then from plain _CRS GPIOs */ - if (IS_ERR(desc)) { - if (!adev || !acpi_can_fallback_to_crs(adev, con_id)) - return ERR_PTR(-ENOENT); + if (can_fallback) + return acpi_get_gpiod_by_index(adev, NULL, idx, info); - desc = acpi_get_gpiod_by_index(adev, NULL, idx, &info); - if (IS_ERR(desc)) - return desc; - } + return ERR_PTR(-ENOENT); +} + +struct gpio_desc *acpi_find_gpio(struct fwnode_handle *fwnode, + const char *con_id, + unsigned int idx, + enum gpiod_flags *dflags, + unsigned long *lookupflags) +{ + struct acpi_device *adev = to_acpi_device_node(fwnode); + bool can_fallback = acpi_can_fallback_to_crs(adev, con_id); + struct acpi_gpio_info info; + struct gpio_desc *desc; + + desc = __acpi_find_gpio(fwnode, con_id, idx, can_fallback, &info); + if (IS_ERR(desc)) + return desc; if (info.gpioint && (*dflags == GPIOD_OUT_LOW || *dflags == GPIOD_OUT_HIGH)) { @@ -1023,7 +1034,7 @@ struct gpio_desc *acpi_find_gpio(struct fwnode_handle *fwnode, /** * acpi_dev_gpio_irq_wake_get_by() - Find GpioInt and translate it to Linux IRQ number * @adev: pointer to a ACPI device to get IRQ from - * @name: optional name of GpioInt resource + * @con_id: optional name of GpioInt resource * @index: index of GpioInt resource (starting from %0) * @wake_capable: Set to true if the IRQ is wake capable * @@ -1034,17 +1045,18 @@ struct gpio_desc *acpi_find_gpio(struct fwnode_handle *fwnode, * The function is idempotent, though each time it runs it will configure GPIO * pin direction according to the flags in GpioInt resource. * - * The function takes optional @name parameter. If the resource has a property - * name, then only those will be taken into account. + * The function takes optional @con_id parameter. If the resource has + * a @con_id in a property, then only those will be taken into account. * * The GPIO is considered wake capable if the GpioInt resource specifies * SharedAndWake or ExclusiveAndWake. * * Return: Linux IRQ number (> %0) on success, negative errno on failure. */ -int acpi_dev_gpio_irq_wake_get_by(struct acpi_device *adev, const char *name, int index, +int acpi_dev_gpio_irq_wake_get_by(struct acpi_device *adev, const char *con_id, int index, bool *wake_capable) { + struct fwnode_handle *fwnode = acpi_fwnode_handle(adev); int idx, i; unsigned int irq_flags; int ret; @@ -1053,9 +1065,8 @@ int acpi_dev_gpio_irq_wake_get_by(struct acpi_device *adev, const char *name, in struct acpi_gpio_info info; struct gpio_desc *desc; - desc = acpi_get_gpiod_by_index(adev, name, i, &info); - /* Ignore -EPROBE_DEFER, it only matters if idx matches */ + desc = __acpi_find_gpio(fwnode, con_id, i, true, &info); if (IS_ERR(desc) && PTR_ERR(desc) != -EPROBE_DEFER) return PTR_ERR(desc); @@ -1075,7 +1086,11 @@ int acpi_dev_gpio_irq_wake_get_by(struct acpi_device *adev, const char *name, in acpi_gpio_update_gpiod_flags(&dflags, &info); acpi_gpio_update_gpiod_lookup_flags(&lflags, &info); - snprintf(label, sizeof(label), "GpioInt() %d", index); + snprintf(label, sizeof(label), "%pfwP GpioInt(%d)", fwnode, index); + ret = gpiod_set_consumer_name(desc, con_id ?: label); + if (ret) + return ret; + ret = gpiod_configure_flags(desc, label, lflags, dflags); if (ret < 0) return ret; diff --git a/drivers/gpio/gpiolib-legacy.c b/drivers/gpio/gpiolib-legacy.c index b138682fec..5a9911ae91 100644 --- a/drivers/gpio/gpiolib-legacy.c +++ b/drivers/gpio/gpiolib-legacy.c @@ -28,10 +28,9 @@ int gpio_request_one(unsigned gpio, unsigned long flags, const char *label) struct gpio_desc *desc; int err; - desc = gpio_to_desc(gpio); - /* Compatibility: assume unavailable "valid" GPIOs will appear later */ - if (!desc && gpio_is_valid(gpio)) + desc = gpio_to_desc(gpio); + if (!desc) return -EPROBE_DEFER; err = gpiod_request(desc, label); @@ -63,51 +62,13 @@ EXPORT_SYMBOL_GPL(gpio_request_one); */ int gpio_request(unsigned gpio, const char *label) { - struct gpio_desc *desc = gpio_to_desc(gpio); + struct gpio_desc *desc; /* Compatibility: assume unavailable "valid" GPIOs will appear later */ - if (!desc && gpio_is_valid(gpio)) + desc = gpio_to_desc(gpio); + if (!desc) return -EPROBE_DEFER; return gpiod_request(desc, label); } EXPORT_SYMBOL_GPL(gpio_request); - -/** - * gpio_request_array - request multiple GPIOs in a single call - * @array: array of the 'struct gpio' - * @num: how many GPIOs in the array - * - * **DEPRECATED** This function is deprecated and must not be used in new code. - */ -int gpio_request_array(const struct gpio *array, size_t num) -{ - int i, err; - - for (i = 0; i < num; i++, array++) { - err = gpio_request_one(array->gpio, array->flags, array->label); - if (err) - goto err_free; - } - return 0; - -err_free: - while (i--) - gpio_free((--array)->gpio); - return err; -} -EXPORT_SYMBOL_GPL(gpio_request_array); - -/** - * gpio_free_array - release multiple GPIOs in a single call - * @array: array of the 'struct gpio' - * @num: how many GPIOs in the array - * - * **DEPRECATED** This function is deprecated and must not be used in new code. - */ -void gpio_free_array(const struct gpio *array, size_t num) -{ - while (num--) - gpio_free((array++)->gpio); -} -EXPORT_SYMBOL_GPL(gpio_free_array); diff --git a/drivers/gpio/gpiolib-of.c b/drivers/gpio/gpiolib-of.c index 5c44422001..89d5e64cf6 100644 --- a/drivers/gpio/gpiolib-of.c +++ b/drivers/gpio/gpiolib-of.c @@ -1055,7 +1055,7 @@ static int of_gpiochip_add_pin_range(struct gpio_chip *chip) struct of_phandle_args pinspec; struct pinctrl_dev *pctldev; struct device_node *np; - int index = 0, ret; + int index = 0, ret, trim; const char *name; static const char group_names_propname[] = "gpio-ranges-group-names"; struct property *group_names; @@ -1077,7 +1077,14 @@ static int of_gpiochip_add_pin_range(struct gpio_chip *chip) if (!pctldev) return -EPROBE_DEFER; + /* Ignore ranges outside of this GPIO chip */ + if (pinspec.args[0] >= (chip->offset + chip->ngpio)) + continue; + if (pinspec.args[0] + pinspec.args[2] <= chip->offset) + continue; + if (pinspec.args[2]) { + /* npins != 0: linear range */ if (group_names) { of_property_read_string_index(np, group_names_propname, @@ -1088,7 +1095,19 @@ static int of_gpiochip_add_pin_range(struct gpio_chip *chip) break; } } - /* npins != 0: linear range */ + + /* Trim the range to fit this GPIO chip */ + if (chip->offset > pinspec.args[0]) { + trim = chip->offset - pinspec.args[0]; + pinspec.args[2] -= trim; + pinspec.args[1] += trim; + pinspec.args[0] = 0; + } else { + pinspec.args[0] -= chip->offset; + } + if ((pinspec.args[0] + pinspec.args[2]) > chip->ngpio) + pinspec.args[2] = chip->ngpio - pinspec.args[0]; + ret = gpiochip_add_pin_range(chip, pinctrl_dev_get_devname(pctldev), pinspec.args[0], diff --git a/drivers/gpio/gpiolib-swnode.c b/drivers/gpio/gpiolib-swnode.c index fa52bdb1a2..cec1ab878a 100644 --- a/drivers/gpio/gpiolib-swnode.c +++ b/drivers/gpio/gpiolib-swnode.c @@ -4,8 +4,13 @@ * * Copyright 2022 Google LLC */ + +#define pr_fmt(fmt) "gpiolib: swnode: " fmt + #include <linux/err.h> #include <linux/errno.h> +#include <linux/export.h> +#include <linux/init.h> #include <linux/kernel.h> #include <linux/printk.h> #include <linux/property.h> @@ -17,6 +22,8 @@ #include "gpiolib.h" #include "gpiolib-swnode.h" +#define GPIOLIB_SWNODE_UNDEFINED_NAME "swnode-gpio-undefined" + static void swnode_format_propname(const char *con_id, char *propname, size_t max_size) { @@ -40,6 +47,14 @@ static struct gpio_device *swnode_get_gpio_device(struct fwnode_handle *fwnode) if (!gdev_node || !gdev_node->name) return ERR_PTR(-EINVAL); + /* + * Check for a special node that identifies undefined GPIOs, this is + * primarily used as a key for internal chip selects in SPI bindings. + */ + if (IS_ENABLED(CONFIG_GPIO_SWNODE_UNDEFINED) && + !strcmp(gdev_node->name, GPIOLIB_SWNODE_UNDEFINED_NAME)) + return ERR_PTR(-ENOENT); + gdev = gpio_device_find_by_label(gdev_node->name); return gdev ?: ERR_PTR(-EPROBE_DEFER); } @@ -121,3 +136,32 @@ int swnode_gpio_count(const struct fwnode_handle *fwnode, const char *con_id) return count ?: -ENOENT; } + +#if IS_ENABLED(CONFIG_GPIO_SWNODE_UNDEFINED) +/* + * A special node that identifies undefined GPIOs, this is primarily used as + * a key for internal chip selects in SPI bindings. + */ +const struct software_node swnode_gpio_undefined = { + .name = GPIOLIB_SWNODE_UNDEFINED_NAME, +}; +EXPORT_SYMBOL_NS_GPL(swnode_gpio_undefined, GPIO_SWNODE); + +static int __init swnode_gpio_init(void) +{ + int ret; + + ret = software_node_register(&swnode_gpio_undefined); + if (ret < 0) + pr_err("failed to register swnode: %d\n", ret); + + return ret; +} +subsys_initcall(swnode_gpio_init); + +static void __exit swnode_gpio_cleanup(void) +{ + software_node_unregister(&swnode_gpio_undefined); +} +__exitcall(swnode_gpio_cleanup); +#endif diff --git a/drivers/gpio/gpiolib-sysfs.c b/drivers/gpio/gpiolib-sysfs.c index 6853ecd98b..26202586fd 100644 --- a/drivers/gpio/gpiolib-sysfs.c +++ b/drivers/gpio/gpiolib-sysfs.c @@ -412,7 +412,7 @@ static ssize_t base_show(struct device *dev, { const struct gpio_device *gdev = dev_get_drvdata(dev); - return sysfs_emit(buf, "%d\n", gdev->base); + return sysfs_emit(buf, "%u\n", gdev->base); } static DEVICE_ATTR_RO(base); diff --git a/drivers/gpio/gpiolib.c b/drivers/gpio/gpiolib.c index fa50db0c36..fa62367ee9 100644 --- a/drivers/gpio/gpiolib.c +++ b/drivers/gpio/gpiolib.c @@ -164,9 +164,6 @@ struct gpio_desc *gpio_to_desc(unsigned gpio) } } - if (!gpio_is_valid(gpio)) - pr_warn("invalid GPIO %d\n", gpio); - return NULL; } EXPORT_SYMBOL_GPL(gpio_to_desc); @@ -311,10 +308,10 @@ struct gpio_chip *gpio_device_get_chip(struct gpio_device *gdev) EXPORT_SYMBOL_GPL(gpio_device_get_chip); /* dynamic allocation of GPIOs, e.g. on a hotplugged device */ -static int gpiochip_find_base_unlocked(int ngpio) +static int gpiochip_find_base_unlocked(u16 ngpio) { + unsigned int base = GPIO_DYNAMIC_BASE; struct gpio_device *gdev; - int base = GPIO_DYNAMIC_BASE; list_for_each_entry_srcu(gdev, &gpio_devices, list, lockdep_is_held(&gpio_devices_lock)) { @@ -325,9 +322,11 @@ static int gpiochip_find_base_unlocked(int ngpio) base = gdev->base + gdev->ngpio; if (base < GPIO_DYNAMIC_BASE) base = GPIO_DYNAMIC_BASE; + if (base > GPIO_DYNAMIC_MAX - ngpio) + break; } - if (gpio_is_valid(base)) { + if (base <= GPIO_DYNAMIC_MAX - ngpio) { pr_debug("%s: found new base at %d\n", __func__, base); return base; } else { @@ -379,7 +378,10 @@ int gpiod_get_direction(struct gpio_desc *desc) if (ret < 0) return ret; - /* GPIOF_DIR_IN or other positive, otherwise GPIOF_DIR_OUT */ + /* + * GPIO_LINE_DIRECTION_IN or other positive, + * otherwise GPIO_LINE_DIRECTION_OUT. + */ if (ret > 0) ret = 1; @@ -760,7 +762,7 @@ static int gpiochip_setup_dev(struct gpio_device *gdev) if (ret) goto err_remove_device; - dev_dbg(&gdev->dev, "registered GPIOs %d to %d on %s\n", gdev->base, + dev_dbg(&gdev->dev, "registered GPIOs %u to %u on %s\n", gdev->base, gdev->base + gdev->ngpio - 1, gdev->label); return 0; @@ -4254,7 +4256,7 @@ struct gpio_desc *gpiod_find_and_request(struct device *consumer, ret = gpiod_configure_flags(desc, con_id, lookupflags, flags); if (ret < 0) { gpiod_put(desc); - dev_dbg(consumer, "setup of GPIO %s failed\n", name); + dev_err(consumer, "setup of GPIO %s failed: %d\n", name, ret); return ERR_PTR(ret); } @@ -4802,14 +4804,14 @@ static void gpiolib_dbg_show(struct seq_file *s, struct gpio_device *gdev) value = gpio_chip_get_value(gc, desc); is_irq = test_bit(FLAG_USED_AS_IRQ, &desc->flags); active_low = test_bit(FLAG_ACTIVE_LOW, &desc->flags); - seq_printf(s, " gpio-%-3d (%-20.20s|%-20.20s) %s %s %s%s\n", + seq_printf(s, " gpio-%-3u (%-20.20s|%-20.20s) %s %s %s%s\n", gpio, desc->name ?: "", gpiod_get_label(desc), is_out ? "out" : "in ", value >= 0 ? (value ? "hi" : "lo") : "? ", is_irq ? "IRQ " : "", active_low ? "ACTIVE LOW" : ""); } else if (desc->name) { - seq_printf(s, " gpio-%-3d (%-20.20s)\n", gpio, desc->name); + seq_printf(s, " gpio-%-3u (%-20.20s)\n", gpio, desc->name); } gpio++; @@ -4881,7 +4883,7 @@ static int gpiolib_seq_show(struct seq_file *s, void *v) return 0; } - seq_printf(s, "%s%s: GPIOs %d-%d", priv->newline ? "\n" : "", + seq_printf(s, "%s%s: GPIOs %u-%u", priv->newline ? "\n" : "", dev_name(&gdev->dev), gdev->base, gdev->base + gdev->ngpio - 1); parent = gc->parent; diff --git a/drivers/gpio/gpiolib.h b/drivers/gpio/gpiolib.h index 8e0e211ebf..48e086c2f4 100644 --- a/drivers/gpio/gpiolib.h +++ b/drivers/gpio/gpiolib.h @@ -63,7 +63,7 @@ struct gpio_device { struct gpio_chip __rcu *chip; struct gpio_desc *descs; struct srcu_struct desc_srcu; - int base; + unsigned int base; u16 ngpio; bool can_sleep; const char *label; |