From f8b410e3695a86686f4075b997bc53c8a178e4e2 Mon Sep 17 00:00:00 2001 From: Linus Walleij Date: Fri, 27 Sep 2019 13:48:33 +0200 Subject: gpio: aspeed-sgpio: Rename and add Kconfig/Makefile This renames the "gpio-aspeed" driver to conform with other GPIO drivers as "gpio-aspeed-sgpio.c". All GPIO drivers should start with the string "gpio-" no special exceptions. Also the Kconfig and Makefile entries should normally go with the driver but I missed this in my review, sorry for mistake. "CONFIG_GPIO_ASPEED_SGPIO" is used to activate this driver. Cc: Hongwei Zhang Fixes: 7db47faae79b ("gpio: aspeed: Add SGPIO driver") Signed-off-by: Linus Walleij Acked-by: Andrew Jeffery Link: https://lore.kernel.org/r/20190927114833.12551-1-linus.walleij@linaro.org --- drivers/gpio/Kconfig | 8 + drivers/gpio/Makefile | 1 + drivers/gpio/gpio-aspeed-sgpio.c | 533 +++++++++++++++++++++++++++++++++++++++ drivers/gpio/sgpio-aspeed.c | 533 --------------------------------------- 4 files changed, 542 insertions(+), 533 deletions(-) create mode 100644 drivers/gpio/gpio-aspeed-sgpio.c delete mode 100644 drivers/gpio/sgpio-aspeed.c diff --git a/drivers/gpio/Kconfig b/drivers/gpio/Kconfig index 38e096e6925f..7138290cdd36 100644 --- a/drivers/gpio/Kconfig +++ b/drivers/gpio/Kconfig @@ -120,6 +120,14 @@ config GPIO_ASPEED help Say Y here to support Aspeed AST2400 and AST2500 GPIO controllers. +config GPIO_ASPEED_SGPIO + bool "Aspeed SGPIO support" + depends on (ARCH_ASPEED || COMPILE_TEST) && OF_GPIO + select GPIO_GENERIC + select GPIOLIB_IRQCHIP + help + Say Y here to support Aspeed AST2500 SGPIO functionality. + config GPIO_ATH79 tristate "Atheros AR71XX/AR724X/AR913X GPIO support" default y if ATH79 diff --git a/drivers/gpio/Makefile b/drivers/gpio/Makefile index d2fd19c15bae..e4599f90f702 100644 --- a/drivers/gpio/Makefile +++ b/drivers/gpio/Makefile @@ -32,6 +32,7 @@ obj-$(CONFIG_GPIO_AMD_FCH) += gpio-amd-fch.o obj-$(CONFIG_GPIO_AMDPT) += gpio-amdpt.o obj-$(CONFIG_GPIO_ARIZONA) += gpio-arizona.o obj-$(CONFIG_GPIO_ASPEED) += gpio-aspeed.o +obj-$(CONFIG_GPIO_ASPEED_SGPIO) += gpio-aspeed-sgpio.o obj-$(CONFIG_GPIO_ATH79) += gpio-ath79.o obj-$(CONFIG_GPIO_BCM_KONA) += gpio-bcm-kona.o obj-$(CONFIG_GPIO_BD70528) += gpio-bd70528.o diff --git a/drivers/gpio/gpio-aspeed-sgpio.c b/drivers/gpio/gpio-aspeed-sgpio.c new file mode 100644 index 000000000000..7e99860ca447 --- /dev/null +++ b/drivers/gpio/gpio-aspeed-sgpio.c @@ -0,0 +1,533 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Copyright 2019 American Megatrends International LLC. + * + * Author: Karthikeyan Mani + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define MAX_NR_SGPIO 80 + +#define ASPEED_SGPIO_CTRL 0x54 + +#define ASPEED_SGPIO_PINS_MASK GENMASK(9, 6) +#define ASPEED_SGPIO_CLK_DIV_MASK GENMASK(31, 16) +#define ASPEED_SGPIO_ENABLE BIT(0) + +struct aspeed_sgpio { + struct gpio_chip chip; + struct clk *pclk; + spinlock_t lock; + void __iomem *base; + uint32_t dir_in[3]; + int irq; +}; + +struct aspeed_sgpio_bank { + uint16_t val_regs; + uint16_t rdata_reg; + uint16_t irq_regs; + const char names[4][3]; +}; + +/* + * Note: The "value" register returns the input value when the GPIO is + * configured as an input. + * + * The "rdata" register returns the output value when the GPIO is + * configured as an output. + */ +static const struct aspeed_sgpio_bank aspeed_sgpio_banks[] = { + { + .val_regs = 0x0000, + .rdata_reg = 0x0070, + .irq_regs = 0x0004, + .names = { "A", "B", "C", "D" }, + }, + { + .val_regs = 0x001C, + .rdata_reg = 0x0074, + .irq_regs = 0x0020, + .names = { "E", "F", "G", "H" }, + }, + { + .val_regs = 0x0038, + .rdata_reg = 0x0078, + .irq_regs = 0x003C, + .names = { "I", "J" }, + }, +}; + +enum aspeed_sgpio_reg { + reg_val, + reg_rdata, + reg_irq_enable, + reg_irq_type0, + reg_irq_type1, + reg_irq_type2, + reg_irq_status, +}; + +#define GPIO_VAL_VALUE 0x00 +#define GPIO_IRQ_ENABLE 0x00 +#define GPIO_IRQ_TYPE0 0x04 +#define GPIO_IRQ_TYPE1 0x08 +#define GPIO_IRQ_TYPE2 0x0C +#define GPIO_IRQ_STATUS 0x10 + +static void __iomem *bank_reg(struct aspeed_sgpio *gpio, + const struct aspeed_sgpio_bank *bank, + const enum aspeed_sgpio_reg reg) +{ + switch (reg) { + case reg_val: + return gpio->base + bank->val_regs + GPIO_VAL_VALUE; + case reg_rdata: + return gpio->base + bank->rdata_reg; + case reg_irq_enable: + return gpio->base + bank->irq_regs + GPIO_IRQ_ENABLE; + case reg_irq_type0: + return gpio->base + bank->irq_regs + GPIO_IRQ_TYPE0; + case reg_irq_type1: + return gpio->base + bank->irq_regs + GPIO_IRQ_TYPE1; + case reg_irq_type2: + return gpio->base + bank->irq_regs + GPIO_IRQ_TYPE2; + case reg_irq_status: + return gpio->base + bank->irq_regs + GPIO_IRQ_STATUS; + default: + /* acturally if code runs to here, it's an error case */ + BUG_ON(1); + } +} + +#define GPIO_BANK(x) ((x) >> 5) +#define GPIO_OFFSET(x) ((x) & 0x1f) +#define GPIO_BIT(x) BIT(GPIO_OFFSET(x)) + +static const struct aspeed_sgpio_bank *to_bank(unsigned int offset) +{ + unsigned int bank = GPIO_BANK(offset); + + WARN_ON(bank >= ARRAY_SIZE(aspeed_sgpio_banks)); + return &aspeed_sgpio_banks[bank]; +} + +static int aspeed_sgpio_get(struct gpio_chip *gc, unsigned int offset) +{ + struct aspeed_sgpio *gpio = gpiochip_get_data(gc); + const struct aspeed_sgpio_bank *bank = to_bank(offset); + unsigned long flags; + enum aspeed_sgpio_reg reg; + bool is_input; + int rc = 0; + + spin_lock_irqsave(&gpio->lock, flags); + + is_input = gpio->dir_in[GPIO_BANK(offset)] & GPIO_BIT(offset); + reg = is_input ? reg_val : reg_rdata; + rc = !!(ioread32(bank_reg(gpio, bank, reg)) & GPIO_BIT(offset)); + + spin_unlock_irqrestore(&gpio->lock, flags); + + return rc; +} + +static void sgpio_set_value(struct gpio_chip *gc, unsigned int offset, int val) +{ + struct aspeed_sgpio *gpio = gpiochip_get_data(gc); + const struct aspeed_sgpio_bank *bank = to_bank(offset); + void __iomem *addr; + u32 reg = 0; + + addr = bank_reg(gpio, bank, reg_val); + reg = ioread32(addr); + + if (val) + reg |= GPIO_BIT(offset); + else + reg &= ~GPIO_BIT(offset); + + iowrite32(reg, addr); +} + +static void aspeed_sgpio_set(struct gpio_chip *gc, unsigned int offset, int val) +{ + struct aspeed_sgpio *gpio = gpiochip_get_data(gc); + unsigned long flags; + + spin_lock_irqsave(&gpio->lock, flags); + + sgpio_set_value(gc, offset, val); + + spin_unlock_irqrestore(&gpio->lock, flags); +} + +static int aspeed_sgpio_dir_in(struct gpio_chip *gc, unsigned int offset) +{ + struct aspeed_sgpio *gpio = gpiochip_get_data(gc); + unsigned long flags; + + spin_lock_irqsave(&gpio->lock, flags); + gpio->dir_in[GPIO_BANK(offset)] |= GPIO_BIT(offset); + spin_unlock_irqrestore(&gpio->lock, flags); + + return 0; +} + +static int aspeed_sgpio_dir_out(struct gpio_chip *gc, unsigned int offset, int val) +{ + struct aspeed_sgpio *gpio = gpiochip_get_data(gc); + unsigned long flags; + + spin_lock_irqsave(&gpio->lock, flags); + + gpio->dir_in[GPIO_BANK(offset)] &= ~GPIO_BIT(offset); + sgpio_set_value(gc, offset, val); + + spin_unlock_irqrestore(&gpio->lock, flags); + + return 0; +} + +static int aspeed_sgpio_get_direction(struct gpio_chip *gc, unsigned int offset) +{ + int dir_status; + struct aspeed_sgpio *gpio = gpiochip_get_data(gc); + unsigned long flags; + + spin_lock_irqsave(&gpio->lock, flags); + dir_status = gpio->dir_in[GPIO_BANK(offset)] & GPIO_BIT(offset); + spin_unlock_irqrestore(&gpio->lock, flags); + + return dir_status; + +} + +static void irqd_to_aspeed_sgpio_data(struct irq_data *d, + struct aspeed_sgpio **gpio, + const struct aspeed_sgpio_bank **bank, + u32 *bit, int *offset) +{ + struct aspeed_sgpio *internal; + + *offset = irqd_to_hwirq(d); + internal = irq_data_get_irq_chip_data(d); + WARN_ON(!internal); + + *gpio = internal; + *bank = to_bank(*offset); + *bit = GPIO_BIT(*offset); +} + +static void aspeed_sgpio_irq_ack(struct irq_data *d) +{ + const struct aspeed_sgpio_bank *bank; + struct aspeed_sgpio *gpio; + unsigned long flags; + void __iomem *status_addr; + int offset; + u32 bit; + + irqd_to_aspeed_sgpio_data(d, &gpio, &bank, &bit, &offset); + + status_addr = bank_reg(gpio, bank, reg_irq_status); + + spin_lock_irqsave(&gpio->lock, flags); + + iowrite32(bit, status_addr); + + spin_unlock_irqrestore(&gpio->lock, flags); +} + +static void aspeed_sgpio_irq_set_mask(struct irq_data *d, bool set) +{ + const struct aspeed_sgpio_bank *bank; + struct aspeed_sgpio *gpio; + unsigned long flags; + u32 reg, bit; + void __iomem *addr; + int offset; + + irqd_to_aspeed_sgpio_data(d, &gpio, &bank, &bit, &offset); + addr = bank_reg(gpio, bank, reg_irq_enable); + + spin_lock_irqsave(&gpio->lock, flags); + + reg = ioread32(addr); + if (set) + reg |= bit; + else + reg &= ~bit; + + iowrite32(reg, addr); + + spin_unlock_irqrestore(&gpio->lock, flags); +} + +static void aspeed_sgpio_irq_mask(struct irq_data *d) +{ + aspeed_sgpio_irq_set_mask(d, false); +} + +static void aspeed_sgpio_irq_unmask(struct irq_data *d) +{ + aspeed_sgpio_irq_set_mask(d, true); +} + +static int aspeed_sgpio_set_type(struct irq_data *d, unsigned int type) +{ + u32 type0 = 0; + u32 type1 = 0; + u32 type2 = 0; + u32 bit, reg; + const struct aspeed_sgpio_bank *bank; + irq_flow_handler_t handler; + struct aspeed_sgpio *gpio; + unsigned long flags; + void __iomem *addr; + int offset; + + irqd_to_aspeed_sgpio_data(d, &gpio, &bank, &bit, &offset); + + switch (type & IRQ_TYPE_SENSE_MASK) { + case IRQ_TYPE_EDGE_BOTH: + type2 |= bit; + /* fall through */ + case IRQ_TYPE_EDGE_RISING: + type0 |= bit; + /* fall through */ + case IRQ_TYPE_EDGE_FALLING: + handler = handle_edge_irq; + break; + case IRQ_TYPE_LEVEL_HIGH: + type0 |= bit; + /* fall through */ + case IRQ_TYPE_LEVEL_LOW: + type1 |= bit; + handler = handle_level_irq; + break; + default: + return -EINVAL; + } + + spin_lock_irqsave(&gpio->lock, flags); + + addr = bank_reg(gpio, bank, reg_irq_type0); + reg = ioread32(addr); + reg = (reg & ~bit) | type0; + iowrite32(reg, addr); + + addr = bank_reg(gpio, bank, reg_irq_type1); + reg = ioread32(addr); + reg = (reg & ~bit) | type1; + iowrite32(reg, addr); + + addr = bank_reg(gpio, bank, reg_irq_type2); + reg = ioread32(addr); + reg = (reg & ~bit) | type2; + iowrite32(reg, addr); + + spin_unlock_irqrestore(&gpio->lock, flags); + + irq_set_handler_locked(d, handler); + + return 0; +} + +static void aspeed_sgpio_irq_handler(struct irq_desc *desc) +{ + struct gpio_chip *gc = irq_desc_get_handler_data(desc); + struct irq_chip *ic = irq_desc_get_chip(desc); + struct aspeed_sgpio *data = gpiochip_get_data(gc); + unsigned int i, p, girq; + unsigned long reg; + + chained_irq_enter(ic, desc); + + for (i = 0; i < ARRAY_SIZE(aspeed_sgpio_banks); i++) { + const struct aspeed_sgpio_bank *bank = &aspeed_sgpio_banks[i]; + + reg = ioread32(bank_reg(data, bank, reg_irq_status)); + + for_each_set_bit(p, ®, 32) { + girq = irq_find_mapping(gc->irq.domain, i * 32 + p); + generic_handle_irq(girq); + } + + } + + chained_irq_exit(ic, desc); +} + +static struct irq_chip aspeed_sgpio_irqchip = { + .name = "aspeed-sgpio", + .irq_ack = aspeed_sgpio_irq_ack, + .irq_mask = aspeed_sgpio_irq_mask, + .irq_unmask = aspeed_sgpio_irq_unmask, + .irq_set_type = aspeed_sgpio_set_type, +}; + +static int aspeed_sgpio_setup_irqs(struct aspeed_sgpio *gpio, + struct platform_device *pdev) +{ + int rc, i; + const struct aspeed_sgpio_bank *bank; + struct gpio_irq_chip *irq; + + rc = platform_get_irq(pdev, 0); + if (rc < 0) + return rc; + + gpio->irq = rc; + + /* Disable IRQ and clear Interrupt status registers for all SPGIO Pins. */ + for (i = 0; i < ARRAY_SIZE(aspeed_sgpio_banks); i++) { + bank = &aspeed_sgpio_banks[i]; + /* disable irq enable bits */ + iowrite32(0x00000000, bank_reg(gpio, bank, reg_irq_enable)); + /* clear status bits */ + iowrite32(0xffffffff, bank_reg(gpio, bank, reg_irq_status)); + } + + irq = &gpio->chip.irq; + irq->chip = &aspeed_sgpio_irqchip; + irq->handler = handle_bad_irq; + irq->default_type = IRQ_TYPE_NONE; + irq->parent_handler = aspeed_sgpio_irq_handler; + irq->parent_handler_data = gpio; + irq->parents = &gpio->irq; + irq->num_parents = 1; + + /* set IRQ settings and Enable Interrupt */ + for (i = 0; i < ARRAY_SIZE(aspeed_sgpio_banks); i++) { + bank = &aspeed_sgpio_banks[i]; + /* set falling or level-low irq */ + iowrite32(0x00000000, bank_reg(gpio, bank, reg_irq_type0)); + /* trigger type is edge */ + iowrite32(0x00000000, bank_reg(gpio, bank, reg_irq_type1)); + /* dual edge trigger mode. */ + iowrite32(0xffffffff, bank_reg(gpio, bank, reg_irq_type2)); + /* enable irq */ + iowrite32(0xffffffff, bank_reg(gpio, bank, reg_irq_enable)); + } + + return 0; +} + +static const struct of_device_id aspeed_sgpio_of_table[] = { + { .compatible = "aspeed,ast2400-sgpio" }, + { .compatible = "aspeed,ast2500-sgpio" }, + {} +}; + +MODULE_DEVICE_TABLE(of, aspeed_sgpio_of_table); + +static int __init aspeed_sgpio_probe(struct platform_device *pdev) +{ + struct aspeed_sgpio *gpio; + u32 nr_gpios, sgpio_freq, sgpio_clk_div; + int rc; + unsigned long apb_freq; + + gpio = devm_kzalloc(&pdev->dev, sizeof(*gpio), GFP_KERNEL); + if (!gpio) + return -ENOMEM; + + gpio->base = devm_platform_ioremap_resource(pdev, 0); + if (IS_ERR(gpio->base)) + return PTR_ERR(gpio->base); + + rc = of_property_read_u32(pdev->dev.of_node, "ngpios", &nr_gpios); + if (rc < 0) { + dev_err(&pdev->dev, "Could not read ngpios property\n"); + return -EINVAL; + } else if (nr_gpios > MAX_NR_SGPIO) { + dev_err(&pdev->dev, "Number of GPIOs exceeds the maximum of %d: %d\n", + MAX_NR_SGPIO, nr_gpios); + return -EINVAL; + } + + rc = of_property_read_u32(pdev->dev.of_node, "bus-frequency", &sgpio_freq); + if (rc < 0) { + dev_err(&pdev->dev, "Could not read bus-frequency property\n"); + return -EINVAL; + } + + gpio->pclk = devm_clk_get(&pdev->dev, NULL); + if (IS_ERR(gpio->pclk)) { + dev_err(&pdev->dev, "devm_clk_get failed\n"); + return PTR_ERR(gpio->pclk); + } + + apb_freq = clk_get_rate(gpio->pclk); + + /* + * From the datasheet, + * SGPIO period = 1/PCLK * 2 * (GPIO254[31:16] + 1) + * period = 2 * (GPIO254[31:16] + 1) / PCLK + * frequency = 1 / (2 * (GPIO254[31:16] + 1) / PCLK) + * frequency = PCLK / (2 * (GPIO254[31:16] + 1)) + * frequency * 2 * (GPIO254[31:16] + 1) = PCLK + * GPIO254[31:16] = PCLK / (frequency * 2) - 1 + */ + if (sgpio_freq == 0) + return -EINVAL; + + sgpio_clk_div = (apb_freq / (sgpio_freq * 2)) - 1; + + if (sgpio_clk_div > (1 << 16) - 1) + return -EINVAL; + + iowrite32(FIELD_PREP(ASPEED_SGPIO_CLK_DIV_MASK, sgpio_clk_div) | + FIELD_PREP(ASPEED_SGPIO_PINS_MASK, (nr_gpios / 8)) | + ASPEED_SGPIO_ENABLE, + gpio->base + ASPEED_SGPIO_CTRL); + + spin_lock_init(&gpio->lock); + + gpio->chip.parent = &pdev->dev; + gpio->chip.ngpio = nr_gpios; + gpio->chip.direction_input = aspeed_sgpio_dir_in; + gpio->chip.direction_output = aspeed_sgpio_dir_out; + gpio->chip.get_direction = aspeed_sgpio_get_direction; + gpio->chip.request = NULL; + gpio->chip.free = NULL; + gpio->chip.get = aspeed_sgpio_get; + gpio->chip.set = aspeed_sgpio_set; + gpio->chip.set_config = NULL; + gpio->chip.label = dev_name(&pdev->dev); + gpio->chip.base = -1; + + /* set all SGPIO pins as input (1). */ + memset(gpio->dir_in, 0xff, sizeof(gpio->dir_in)); + + aspeed_sgpio_setup_irqs(gpio, pdev); + + rc = devm_gpiochip_add_data(&pdev->dev, &gpio->chip, gpio); + if (rc < 0) + return rc; + + return 0; +} + +static struct platform_driver aspeed_sgpio_driver = { + .driver = { + .name = KBUILD_MODNAME, + .of_match_table = aspeed_sgpio_of_table, + }, +}; + +module_platform_driver_probe(aspeed_sgpio_driver, aspeed_sgpio_probe); +MODULE_DESCRIPTION("Aspeed Serial GPIO Driver"); +MODULE_LICENSE("GPL"); diff --git a/drivers/gpio/sgpio-aspeed.c b/drivers/gpio/sgpio-aspeed.c deleted file mode 100644 index 7e99860ca447..000000000000 --- a/drivers/gpio/sgpio-aspeed.c +++ /dev/null @@ -1,533 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-or-later -/* - * Copyright 2019 American Megatrends International LLC. - * - * Author: Karthikeyan Mani - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#define MAX_NR_SGPIO 80 - -#define ASPEED_SGPIO_CTRL 0x54 - -#define ASPEED_SGPIO_PINS_MASK GENMASK(9, 6) -#define ASPEED_SGPIO_CLK_DIV_MASK GENMASK(31, 16) -#define ASPEED_SGPIO_ENABLE BIT(0) - -struct aspeed_sgpio { - struct gpio_chip chip; - struct clk *pclk; - spinlock_t lock; - void __iomem *base; - uint32_t dir_in[3]; - int irq; -}; - -struct aspeed_sgpio_bank { - uint16_t val_regs; - uint16_t rdata_reg; - uint16_t irq_regs; - const char names[4][3]; -}; - -/* - * Note: The "value" register returns the input value when the GPIO is - * configured as an input. - * - * The "rdata" register returns the output value when the GPIO is - * configured as an output. - */ -static const struct aspeed_sgpio_bank aspeed_sgpio_banks[] = { - { - .val_regs = 0x0000, - .rdata_reg = 0x0070, - .irq_regs = 0x0004, - .names = { "A", "B", "C", "D" }, - }, - { - .val_regs = 0x001C, - .rdata_reg = 0x0074, - .irq_regs = 0x0020, - .names = { "E", "F", "G", "H" }, - }, - { - .val_regs = 0x0038, - .rdata_reg = 0x0078, - .irq_regs = 0x003C, - .names = { "I", "J" }, - }, -}; - -enum aspeed_sgpio_reg { - reg_val, - reg_rdata, - reg_irq_enable, - reg_irq_type0, - reg_irq_type1, - reg_irq_type2, - reg_irq_status, -}; - -#define GPIO_VAL_VALUE 0x00 -#define GPIO_IRQ_ENABLE 0x00 -#define GPIO_IRQ_TYPE0 0x04 -#define GPIO_IRQ_TYPE1 0x08 -#define GPIO_IRQ_TYPE2 0x0C -#define GPIO_IRQ_STATUS 0x10 - -static void __iomem *bank_reg(struct aspeed_sgpio *gpio, - const struct aspeed_sgpio_bank *bank, - const enum aspeed_sgpio_reg reg) -{ - switch (reg) { - case reg_val: - return gpio->base + bank->val_regs + GPIO_VAL_VALUE; - case reg_rdata: - return gpio->base + bank->rdata_reg; - case reg_irq_enable: - return gpio->base + bank->irq_regs + GPIO_IRQ_ENABLE; - case reg_irq_type0: - return gpio->base + bank->irq_regs + GPIO_IRQ_TYPE0; - case reg_irq_type1: - return gpio->base + bank->irq_regs + GPIO_IRQ_TYPE1; - case reg_irq_type2: - return gpio->base + bank->irq_regs + GPIO_IRQ_TYPE2; - case reg_irq_status: - return gpio->base + bank->irq_regs + GPIO_IRQ_STATUS; - default: - /* acturally if code runs to here, it's an error case */ - BUG_ON(1); - } -} - -#define GPIO_BANK(x) ((x) >> 5) -#define GPIO_OFFSET(x) ((x) & 0x1f) -#define GPIO_BIT(x) BIT(GPIO_OFFSET(x)) - -static const struct aspeed_sgpio_bank *to_bank(unsigned int offset) -{ - unsigned int bank = GPIO_BANK(offset); - - WARN_ON(bank >= ARRAY_SIZE(aspeed_sgpio_banks)); - return &aspeed_sgpio_banks[bank]; -} - -static int aspeed_sgpio_get(struct gpio_chip *gc, unsigned int offset) -{ - struct aspeed_sgpio *gpio = gpiochip_get_data(gc); - const struct aspeed_sgpio_bank *bank = to_bank(offset); - unsigned long flags; - enum aspeed_sgpio_reg reg; - bool is_input; - int rc = 0; - - spin_lock_irqsave(&gpio->lock, flags); - - is_input = gpio->dir_in[GPIO_BANK(offset)] & GPIO_BIT(offset); - reg = is_input ? reg_val : reg_rdata; - rc = !!(ioread32(bank_reg(gpio, bank, reg)) & GPIO_BIT(offset)); - - spin_unlock_irqrestore(&gpio->lock, flags); - - return rc; -} - -static void sgpio_set_value(struct gpio_chip *gc, unsigned int offset, int val) -{ - struct aspeed_sgpio *gpio = gpiochip_get_data(gc); - const struct aspeed_sgpio_bank *bank = to_bank(offset); - void __iomem *addr; - u32 reg = 0; - - addr = bank_reg(gpio, bank, reg_val); - reg = ioread32(addr); - - if (val) - reg |= GPIO_BIT(offset); - else - reg &= ~GPIO_BIT(offset); - - iowrite32(reg, addr); -} - -static void aspeed_sgpio_set(struct gpio_chip *gc, unsigned int offset, int val) -{ - struct aspeed_sgpio *gpio = gpiochip_get_data(gc); - unsigned long flags; - - spin_lock_irqsave(&gpio->lock, flags); - - sgpio_set_value(gc, offset, val); - - spin_unlock_irqrestore(&gpio->lock, flags); -} - -static int aspeed_sgpio_dir_in(struct gpio_chip *gc, unsigned int offset) -{ - struct aspeed_sgpio *gpio = gpiochip_get_data(gc); - unsigned long flags; - - spin_lock_irqsave(&gpio->lock, flags); - gpio->dir_in[GPIO_BANK(offset)] |= GPIO_BIT(offset); - spin_unlock_irqrestore(&gpio->lock, flags); - - return 0; -} - -static int aspeed_sgpio_dir_out(struct gpio_chip *gc, unsigned int offset, int val) -{ - struct aspeed_sgpio *gpio = gpiochip_get_data(gc); - unsigned long flags; - - spin_lock_irqsave(&gpio->lock, flags); - - gpio->dir_in[GPIO_BANK(offset)] &= ~GPIO_BIT(offset); - sgpio_set_value(gc, offset, val); - - spin_unlock_irqrestore(&gpio->lock, flags); - - return 0; -} - -static int aspeed_sgpio_get_direction(struct gpio_chip *gc, unsigned int offset) -{ - int dir_status; - struct aspeed_sgpio *gpio = gpiochip_get_data(gc); - unsigned long flags; - - spin_lock_irqsave(&gpio->lock, flags); - dir_status = gpio->dir_in[GPIO_BANK(offset)] & GPIO_BIT(offset); - spin_unlock_irqrestore(&gpio->lock, flags); - - return dir_status; - -} - -static void irqd_to_aspeed_sgpio_data(struct irq_data *d, - struct aspeed_sgpio **gpio, - const struct aspeed_sgpio_bank **bank, - u32 *bit, int *offset) -{ - struct aspeed_sgpio *internal; - - *offset = irqd_to_hwirq(d); - internal = irq_data_get_irq_chip_data(d); - WARN_ON(!internal); - - *gpio = internal; - *bank = to_bank(*offset); - *bit = GPIO_BIT(*offset); -} - -static void aspeed_sgpio_irq_ack(struct irq_data *d) -{ - const struct aspeed_sgpio_bank *bank; - struct aspeed_sgpio *gpio; - unsigned long flags; - void __iomem *status_addr; - int offset; - u32 bit; - - irqd_to_aspeed_sgpio_data(d, &gpio, &bank, &bit, &offset); - - status_addr = bank_reg(gpio, bank, reg_irq_status); - - spin_lock_irqsave(&gpio->lock, flags); - - iowrite32(bit, status_addr); - - spin_unlock_irqrestore(&gpio->lock, flags); -} - -static void aspeed_sgpio_irq_set_mask(struct irq_data *d, bool set) -{ - const struct aspeed_sgpio_bank *bank; - struct aspeed_sgpio *gpio; - unsigned long flags; - u32 reg, bit; - void __iomem *addr; - int offset; - - irqd_to_aspeed_sgpio_data(d, &gpio, &bank, &bit, &offset); - addr = bank_reg(gpio, bank, reg_irq_enable); - - spin_lock_irqsave(&gpio->lock, flags); - - reg = ioread32(addr); - if (set) - reg |= bit; - else - reg &= ~bit; - - iowrite32(reg, addr); - - spin_unlock_irqrestore(&gpio->lock, flags); -} - -static void aspeed_sgpio_irq_mask(struct irq_data *d) -{ - aspeed_sgpio_irq_set_mask(d, false); -} - -static void aspeed_sgpio_irq_unmask(struct irq_data *d) -{ - aspeed_sgpio_irq_set_mask(d, true); -} - -static int aspeed_sgpio_set_type(struct irq_data *d, unsigned int type) -{ - u32 type0 = 0; - u32 type1 = 0; - u32 type2 = 0; - u32 bit, reg; - const struct aspeed_sgpio_bank *bank; - irq_flow_handler_t handler; - struct aspeed_sgpio *gpio; - unsigned long flags; - void __iomem *addr; - int offset; - - irqd_to_aspeed_sgpio_data(d, &gpio, &bank, &bit, &offset); - - switch (type & IRQ_TYPE_SENSE_MASK) { - case IRQ_TYPE_EDGE_BOTH: - type2 |= bit; - /* fall through */ - case IRQ_TYPE_EDGE_RISING: - type0 |= bit; - /* fall through */ - case IRQ_TYPE_EDGE_FALLING: - handler = handle_edge_irq; - break; - case IRQ_TYPE_LEVEL_HIGH: - type0 |= bit; - /* fall through */ - case IRQ_TYPE_LEVEL_LOW: - type1 |= bit; - handler = handle_level_irq; - break; - default: - return -EINVAL; - } - - spin_lock_irqsave(&gpio->lock, flags); - - addr = bank_reg(gpio, bank, reg_irq_type0); - reg = ioread32(addr); - reg = (reg & ~bit) | type0; - iowrite32(reg, addr); - - addr = bank_reg(gpio, bank, reg_irq_type1); - reg = ioread32(addr); - reg = (reg & ~bit) | type1; - iowrite32(reg, addr); - - addr = bank_reg(gpio, bank, reg_irq_type2); - reg = ioread32(addr); - reg = (reg & ~bit) | type2; - iowrite32(reg, addr); - - spin_unlock_irqrestore(&gpio->lock, flags); - - irq_set_handler_locked(d, handler); - - return 0; -} - -static void aspeed_sgpio_irq_handler(struct irq_desc *desc) -{ - struct gpio_chip *gc = irq_desc_get_handler_data(desc); - struct irq_chip *ic = irq_desc_get_chip(desc); - struct aspeed_sgpio *data = gpiochip_get_data(gc); - unsigned int i, p, girq; - unsigned long reg; - - chained_irq_enter(ic, desc); - - for (i = 0; i < ARRAY_SIZE(aspeed_sgpio_banks); i++) { - const struct aspeed_sgpio_bank *bank = &aspeed_sgpio_banks[i]; - - reg = ioread32(bank_reg(data, bank, reg_irq_status)); - - for_each_set_bit(p, ®, 32) { - girq = irq_find_mapping(gc->irq.domain, i * 32 + p); - generic_handle_irq(girq); - } - - } - - chained_irq_exit(ic, desc); -} - -static struct irq_chip aspeed_sgpio_irqchip = { - .name = "aspeed-sgpio", - .irq_ack = aspeed_sgpio_irq_ack, - .irq_mask = aspeed_sgpio_irq_mask, - .irq_unmask = aspeed_sgpio_irq_unmask, - .irq_set_type = aspeed_sgpio_set_type, -}; - -static int aspeed_sgpio_setup_irqs(struct aspeed_sgpio *gpio, - struct platform_device *pdev) -{ - int rc, i; - const struct aspeed_sgpio_bank *bank; - struct gpio_irq_chip *irq; - - rc = platform_get_irq(pdev, 0); - if (rc < 0) - return rc; - - gpio->irq = rc; - - /* Disable IRQ and clear Interrupt status registers for all SPGIO Pins. */ - for (i = 0; i < ARRAY_SIZE(aspeed_sgpio_banks); i++) { - bank = &aspeed_sgpio_banks[i]; - /* disable irq enable bits */ - iowrite32(0x00000000, bank_reg(gpio, bank, reg_irq_enable)); - /* clear status bits */ - iowrite32(0xffffffff, bank_reg(gpio, bank, reg_irq_status)); - } - - irq = &gpio->chip.irq; - irq->chip = &aspeed_sgpio_irqchip; - irq->handler = handle_bad_irq; - irq->default_type = IRQ_TYPE_NONE; - irq->parent_handler = aspeed_sgpio_irq_handler; - irq->parent_handler_data = gpio; - irq->parents = &gpio->irq; - irq->num_parents = 1; - - /* set IRQ settings and Enable Interrupt */ - for (i = 0; i < ARRAY_SIZE(aspeed_sgpio_banks); i++) { - bank = &aspeed_sgpio_banks[i]; - /* set falling or level-low irq */ - iowrite32(0x00000000, bank_reg(gpio, bank, reg_irq_type0)); - /* trigger type is edge */ - iowrite32(0x00000000, bank_reg(gpio, bank, reg_irq_type1)); - /* dual edge trigger mode. */ - iowrite32(0xffffffff, bank_reg(gpio, bank, reg_irq_type2)); - /* enable irq */ - iowrite32(0xffffffff, bank_reg(gpio, bank, reg_irq_enable)); - } - - return 0; -} - -static const struct of_device_id aspeed_sgpio_of_table[] = { - { .compatible = "aspeed,ast2400-sgpio" }, - { .compatible = "aspeed,ast2500-sgpio" }, - {} -}; - -MODULE_DEVICE_TABLE(of, aspeed_sgpio_of_table); - -static int __init aspeed_sgpio_probe(struct platform_device *pdev) -{ - struct aspeed_sgpio *gpio; - u32 nr_gpios, sgpio_freq, sgpio_clk_div; - int rc; - unsigned long apb_freq; - - gpio = devm_kzalloc(&pdev->dev, sizeof(*gpio), GFP_KERNEL); - if (!gpio) - return -ENOMEM; - - gpio->base = devm_platform_ioremap_resource(pdev, 0); - if (IS_ERR(gpio->base)) - return PTR_ERR(gpio->base); - - rc = of_property_read_u32(pdev->dev.of_node, "ngpios", &nr_gpios); - if (rc < 0) { - dev_err(&pdev->dev, "Could not read ngpios property\n"); - return -EINVAL; - } else if (nr_gpios > MAX_NR_SGPIO) { - dev_err(&pdev->dev, "Number of GPIOs exceeds the maximum of %d: %d\n", - MAX_NR_SGPIO, nr_gpios); - return -EINVAL; - } - - rc = of_property_read_u32(pdev->dev.of_node, "bus-frequency", &sgpio_freq); - if (rc < 0) { - dev_err(&pdev->dev, "Could not read bus-frequency property\n"); - return -EINVAL; - } - - gpio->pclk = devm_clk_get(&pdev->dev, NULL); - if (IS_ERR(gpio->pclk)) { - dev_err(&pdev->dev, "devm_clk_get failed\n"); - return PTR_ERR(gpio->pclk); - } - - apb_freq = clk_get_rate(gpio->pclk); - - /* - * From the datasheet, - * SGPIO period = 1/PCLK * 2 * (GPIO254[31:16] + 1) - * period = 2 * (GPIO254[31:16] + 1) / PCLK - * frequency = 1 / (2 * (GPIO254[31:16] + 1) / PCLK) - * frequency = PCLK / (2 * (GPIO254[31:16] + 1)) - * frequency * 2 * (GPIO254[31:16] + 1) = PCLK - * GPIO254[31:16] = PCLK / (frequency * 2) - 1 - */ - if (sgpio_freq == 0) - return -EINVAL; - - sgpio_clk_div = (apb_freq / (sgpio_freq * 2)) - 1; - - if (sgpio_clk_div > (1 << 16) - 1) - return -EINVAL; - - iowrite32(FIELD_PREP(ASPEED_SGPIO_CLK_DIV_MASK, sgpio_clk_div) | - FIELD_PREP(ASPEED_SGPIO_PINS_MASK, (nr_gpios / 8)) | - ASPEED_SGPIO_ENABLE, - gpio->base + ASPEED_SGPIO_CTRL); - - spin_lock_init(&gpio->lock); - - gpio->chip.parent = &pdev->dev; - gpio->chip.ngpio = nr_gpios; - gpio->chip.direction_input = aspeed_sgpio_dir_in; - gpio->chip.direction_output = aspeed_sgpio_dir_out; - gpio->chip.get_direction = aspeed_sgpio_get_direction; - gpio->chip.request = NULL; - gpio->chip.free = NULL; - gpio->chip.get = aspeed_sgpio_get; - gpio->chip.set = aspeed_sgpio_set; - gpio->chip.set_config = NULL; - gpio->chip.label = dev_name(&pdev->dev); - gpio->chip.base = -1; - - /* set all SGPIO pins as input (1). */ - memset(gpio->dir_in, 0xff, sizeof(gpio->dir_in)); - - aspeed_sgpio_setup_irqs(gpio, pdev); - - rc = devm_gpiochip_add_data(&pdev->dev, &gpio->chip, gpio); - if (rc < 0) - return rc; - - return 0; -} - -static struct platform_driver aspeed_sgpio_driver = { - .driver = { - .name = KBUILD_MODNAME, - .of_match_table = aspeed_sgpio_of_table, - }, -}; - -module_platform_driver_probe(aspeed_sgpio_driver, aspeed_sgpio_probe); -MODULE_DESCRIPTION("Aspeed Serial GPIO Driver"); -MODULE_LICENSE("GPL"); -- cgit From 2d2f116d69c127099553afe0d87cf9c0bbe2759e Mon Sep 17 00:00:00 2001 From: Dmitry Torokhov Date: Thu, 12 Sep 2019 20:22:38 -0700 Subject: gpiolib: introduce devm_fwnode_gpiod_get_index() devm_fwnode_get_index_gpiod_from_child() is too long, besides the fwnode in question does not have to be a child of device node. Let's rename it to devm_fwnode_gpiod_get_index() and keep the old name for compatibility for now. Also let's add a devm_fwnode_gpiod_get() wrapper as majority of the callers need a single GPIO. Reviewed-by: Andy Shevchenko Signed-off-by: Dmitry Torokhov Reviewed-by: Mika Westerberg Link: https://lore.kernel.org/r/20190913032240.50333-2-dmitry.torokhov@gmail.com Signed-off-by: Linus Walleij --- drivers/gpio/gpiolib-devres.c | 19 +++++++++---------- include/linux/gpio/consumer.h | 41 +++++++++++++++++++++++++++++++---------- 2 files changed, 40 insertions(+), 20 deletions(-) diff --git a/drivers/gpio/gpiolib-devres.c b/drivers/gpio/gpiolib-devres.c index 98e3c20d9730..9a0475c87f95 100644 --- a/drivers/gpio/gpiolib-devres.c +++ b/drivers/gpio/gpiolib-devres.c @@ -185,12 +185,11 @@ struct gpio_desc *devm_gpiod_get_from_of_node(struct device *dev, EXPORT_SYMBOL_GPL(devm_gpiod_get_from_of_node); /** - * devm_fwnode_get_index_gpiod_from_child - get a GPIO descriptor from a - * device's child node + * devm_fwnode_gpiod_get_index - get a GPIO descriptor from a given node * @dev: GPIO consumer + * @fwnode: firmware node containing GPIO reference * @con_id: function within the GPIO consumer * @index: index of the GPIO to obtain in the consumer - * @child: firmware node (child of @dev) * @flags: GPIO initialization flags * @label: label to attach to the requested GPIO * @@ -200,11 +199,11 @@ EXPORT_SYMBOL_GPL(devm_gpiod_get_from_of_node); * On successful request the GPIO pin is configured in accordance with * provided @flags. */ -struct gpio_desc *devm_fwnode_get_index_gpiod_from_child(struct device *dev, - const char *con_id, int index, - struct fwnode_handle *child, - enum gpiod_flags flags, - const char *label) +struct gpio_desc *devm_fwnode_gpiod_get_index(struct device *dev, + struct fwnode_handle *fwnode, + const char *con_id, int index, + enum gpiod_flags flags, + const char *label) { char prop_name[32]; /* 32 is max size of property name */ struct gpio_desc **dr; @@ -224,7 +223,7 @@ struct gpio_desc *devm_fwnode_get_index_gpiod_from_child(struct device *dev, snprintf(prop_name, sizeof(prop_name), "%s", gpio_suffixes[i]); - desc = fwnode_get_named_gpiod(child, prop_name, index, flags, + desc = fwnode_get_named_gpiod(fwnode, prop_name, index, flags, label); if (!IS_ERR(desc) || (PTR_ERR(desc) != -ENOENT)) break; @@ -239,7 +238,7 @@ struct gpio_desc *devm_fwnode_get_index_gpiod_from_child(struct device *dev, return desc; } -EXPORT_SYMBOL_GPL(devm_fwnode_get_index_gpiod_from_child); +EXPORT_SYMBOL_GPL(devm_fwnode_gpiod_get_index); /** * devm_gpiod_get_index_optional - Resource-managed gpiod_get_index_optional() diff --git a/include/linux/gpio/consumer.h b/include/linux/gpio/consumer.h index b70af921c614..dc0ddcd30515 100644 --- a/include/linux/gpio/consumer.h +++ b/include/linux/gpio/consumer.h @@ -176,11 +176,11 @@ struct gpio_desc *fwnode_get_named_gpiod(struct fwnode_handle *fwnode, const char *propname, int index, enum gpiod_flags dflags, const char *label); -struct gpio_desc *devm_fwnode_get_index_gpiod_from_child(struct device *dev, - const char *con_id, int index, - struct fwnode_handle *child, - enum gpiod_flags flags, - const char *label); +struct gpio_desc *devm_fwnode_gpiod_get_index(struct device *dev, + struct fwnode_handle *child, + const char *con_id, int index, + enum gpiod_flags flags, + const char *label); #else /* CONFIG_GPIOLIB */ @@ -531,6 +531,29 @@ struct gpio_desc *fwnode_get_named_gpiod(struct fwnode_handle *fwnode, return ERR_PTR(-ENOSYS); } +static inline +struct gpio_desc *devm_fwnode_gpiod_get_index(struct device *dev, + struct fwnode_handle *fwnode, + const char *con_id, int index, + enum gpiod_flags flags, + const char *label) +{ + return ERR_PTR(-ENOSYS); +} + +#endif /* CONFIG_GPIOLIB */ + +static inline +struct gpio_desc *devm_fwnode_gpiod_get(struct device *dev, + struct fwnode_handle *fwnode, + const char *con_id, + enum gpiod_flags flags, + const char *label) +{ + return devm_fwnode_gpiod_get_index(dev, fwnode, con_id, 0, + flags, label); +} + static inline struct gpio_desc *devm_fwnode_get_index_gpiod_from_child(struct device *dev, const char *con_id, int index, @@ -538,11 +561,10 @@ struct gpio_desc *devm_fwnode_get_index_gpiod_from_child(struct device *dev, enum gpiod_flags flags, const char *label) { - return ERR_PTR(-ENOSYS); + return devm_fwnode_gpiod_get_index(dev, child, con_id, index, + flags, label); } -#endif /* CONFIG_GPIOLIB */ - static inline struct gpio_desc *devm_fwnode_get_gpiod_from_child(struct device *dev, const char *con_id, @@ -550,8 +572,7 @@ struct gpio_desc *devm_fwnode_get_gpiod_from_child(struct device *dev, enum gpiod_flags flags, const char *label) { - return devm_fwnode_get_index_gpiod_from_child(dev, con_id, 0, child, - flags, label); + return devm_fwnode_gpiod_get_index(dev, child, con_id, 0, flags, label); } #if IS_ENABLED(CONFIG_GPIOLIB) && IS_ENABLED(CONFIG_OF_GPIO) -- cgit From 13949fa9daa91a60c7cfef40755f7611cc2cf653 Mon Sep 17 00:00:00 2001 From: Dmitry Torokhov Date: Thu, 12 Sep 2019 20:22:39 -0700 Subject: gpiolib: introduce fwnode_gpiod_get_index() This introduces fwnode_gpiod_get_index() that iterates through common gpio suffixes when trying to locate a GPIO within a given firmware node. We also switch devm_fwnode_gpiod_get_index() to call fwnode_gpiod_get_index() instead of iterating through GPIO suffixes on its own. Reviewed-by: Andy Shevchenko Signed-off-by: Dmitry Torokhov Link: https://lore.kernel.org/r/20190913032240.50333-3-dmitry.torokhov@gmail.com Reviewed-by: Mika Westerberg Signed-off-by: Linus Walleij --- drivers/gpio/gpiolib-devres.c | 16 +-------------- drivers/gpio/gpiolib.c | 48 +++++++++++++++++++++++++++++++++++++++++++ include/linux/gpio/consumer.h | 13 ++++++++++++ 3 files changed, 62 insertions(+), 15 deletions(-) diff --git a/drivers/gpio/gpiolib-devres.c b/drivers/gpio/gpiolib-devres.c index 9a0475c87f95..4421be09b960 100644 --- a/drivers/gpio/gpiolib-devres.c +++ b/drivers/gpio/gpiolib-devres.c @@ -205,29 +205,15 @@ struct gpio_desc *devm_fwnode_gpiod_get_index(struct device *dev, enum gpiod_flags flags, const char *label) { - char prop_name[32]; /* 32 is max size of property name */ struct gpio_desc **dr; struct gpio_desc *desc; - unsigned int i; dr = devres_alloc(devm_gpiod_release, sizeof(struct gpio_desc *), GFP_KERNEL); if (!dr) return ERR_PTR(-ENOMEM); - for (i = 0; i < ARRAY_SIZE(gpio_suffixes); i++) { - if (con_id) - snprintf(prop_name, sizeof(prop_name), "%s-%s", - con_id, gpio_suffixes[i]); - else - snprintf(prop_name, sizeof(prop_name), "%s", - gpio_suffixes[i]); - - desc = fwnode_get_named_gpiod(fwnode, prop_name, index, flags, - label); - if (!IS_ERR(desc) || (PTR_ERR(desc) != -ENOENT)) - break; - } + desc = fwnode_gpiod_get_index(fwnode, con_id, index, flags, label); if (IS_ERR(desc)) { devres_free(dr); return desc; diff --git a/drivers/gpio/gpiolib.c b/drivers/gpio/gpiolib.c index bdbc1649eafa..2342deaace17 100644 --- a/drivers/gpio/gpiolib.c +++ b/drivers/gpio/gpiolib.c @@ -4324,6 +4324,54 @@ static int platform_gpio_count(struct device *dev, const char *con_id) return count; } +/** + * fwnode_gpiod_get_index - obtain a GPIO from firmware node + * @fwnode: handle of the firmware node + * @con_id: function within the GPIO consumer + * @index: index of the GPIO to obtain for the consumer + * @flags: GPIO initialization flags + * @label: label to attach to the requested GPIO + * + * This function can be used for drivers that get their configuration + * from opaque firmware. + * + * The function properly finds the corresponding GPIO using whatever is the + * underlying firmware interface and then makes sure that the GPIO + * descriptor is requested before it is returned to the caller. + * + * Returns: + * On successful request the GPIO pin is configured in accordance with + * provided @flags. + * + * In case of error an ERR_PTR() is returned. + */ +struct gpio_desc *fwnode_gpiod_get_index(struct fwnode_handle *fwnode, + const char *con_id, int index, + enum gpiod_flags flags, + const char *label) +{ + struct gpio_desc *desc; + char prop_name[32]; /* 32 is max size of property name */ + unsigned int i; + + for (i = 0; i < ARRAY_SIZE(gpio_suffixes); i++) { + if (con_id) + snprintf(prop_name, sizeof(prop_name), "%s-%s", + con_id, gpio_suffixes[i]); + else + snprintf(prop_name, sizeof(prop_name), "%s", + gpio_suffixes[i]); + + desc = fwnode_get_named_gpiod(fwnode, prop_name, index, flags, + label); + if (!IS_ERR(desc) || (PTR_ERR(desc) != -ENOENT)) + break; + } + + return desc; +} +EXPORT_SYMBOL_GPL(fwnode_gpiod_get_index); + /** * gpiod_count - return the number of GPIOs associated with a device / function * or -ENOENT if no GPIO has been assigned to the requested function diff --git a/include/linux/gpio/consumer.h b/include/linux/gpio/consumer.h index dc0ddcd30515..5215fdba6b9a 100644 --- a/include/linux/gpio/consumer.h +++ b/include/linux/gpio/consumer.h @@ -176,6 +176,10 @@ struct gpio_desc *fwnode_get_named_gpiod(struct fwnode_handle *fwnode, const char *propname, int index, enum gpiod_flags dflags, const char *label); +struct gpio_desc *fwnode_gpiod_get_index(struct fwnode_handle *fwnode, + const char *con_id, int index, + enum gpiod_flags flags, + const char *label); struct gpio_desc *devm_fwnode_gpiod_get_index(struct device *dev, struct fwnode_handle *child, const char *con_id, int index, @@ -531,6 +535,15 @@ struct gpio_desc *fwnode_get_named_gpiod(struct fwnode_handle *fwnode, return ERR_PTR(-ENOSYS); } +static inline +struct gpio_desc *fwnode_gpiod_get_index(struct fwnode_handle *fwnode, + const char *con_id, int index, + enum gpiod_flags flags, + const char *label) +{ + return ERR_PTR(-ENOSYS); +} + static inline struct gpio_desc *devm_fwnode_gpiod_get_index(struct device *dev, struct fwnode_handle *fwnode, -- cgit From 704355db127e4bcc96c40fa3eeff5450f1a14d13 Mon Sep 17 00:00:00 2001 From: Thierry Reding Date: Wed, 2 Oct 2019 14:28:24 +0200 Subject: gpio: max77620: Do not allocate IRQs upfront regmap_add_irq_chip() will try to allocate all of the IRQ descriptors upfront if passed a non-zero irq_base parameter. However, the intention is to allocate IRQ descriptors on an as-needed basis if possible. Pass 0 instead of -1 to fix that use-case. Signed-off-by: Thierry Reding Link: https://lore.kernel.org/r/20191002122825.3948322-2-thierry.reding@gmail.com Signed-off-by: Linus Walleij --- drivers/gpio/gpio-max77620.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpio/gpio-max77620.c b/drivers/gpio/gpio-max77620.c index 47d05e357e61..3094fad151b4 100644 --- a/drivers/gpio/gpio-max77620.c +++ b/drivers/gpio/gpio-max77620.c @@ -304,7 +304,7 @@ static int max77620_gpio_probe(struct platform_device *pdev) } ret = devm_regmap_add_irq_chip(&pdev->dev, chip->rmap, gpio_irq, - IRQF_ONESHOT, -1, + IRQF_ONESHOT, 0, &max77620_gpio_irq_chip, &chip->gpio_irq_data); if (ret < 0) { -- cgit From ab3dd9cc24d4d49739cec0c7763e473ddd22f9c1 Mon Sep 17 00:00:00 2001 From: Timo Alho Date: Wed, 2 Oct 2019 14:28:25 +0200 Subject: gpio: max77620: Fix interrupt handling The interrupt-related register fields on the MAX77620 GPIO controller share registers with GPIO related fields. If the IRQ chip is implemented with regmap-irq, this causes the IRQ controller code to overwrite fields previously configured by the GPIO controller code. Two examples where this causes problems are the NVIDIA Jetson TX1 and Jetson TX2 boards, where some of the GPIOs are used to enable vital power regulators. The MAX77620 GPIO controller also provides the USB OTG ID pin. If configured as an interrupt, this causes some of the regulators to be powered off. Signed-off-by: Timo Alho Signed-off-by: Thierry Reding Link: https://lore.kernel.org/r/20191002122825.3948322-3-thierry.reding@gmail.com Signed-off-by: Linus Walleij --- drivers/gpio/gpio-max77620.c | 231 ++++++++++++++++++++++--------------------- 1 file changed, 117 insertions(+), 114 deletions(-) diff --git a/drivers/gpio/gpio-max77620.c b/drivers/gpio/gpio-max77620.c index 3094fad151b4..3ece63ae6f93 100644 --- a/drivers/gpio/gpio-max77620.c +++ b/drivers/gpio/gpio-max77620.c @@ -18,109 +18,115 @@ struct max77620_gpio { struct gpio_chip gpio_chip; struct regmap *rmap; struct device *dev; + struct mutex buslock; /* irq_bus_lock */ + unsigned int irq_type[8]; + bool irq_enabled[8]; }; -static const struct regmap_irq max77620_gpio_irqs[] = { - [0] = { - .reg_offset = 0, - .mask = MAX77620_IRQ_LVL2_GPIO_EDGE0, - .type = { - .type_rising_val = MAX77620_CNFG_GPIO_INT_RISING, - .type_falling_val = MAX77620_CNFG_GPIO_INT_FALLING, - .type_reg_mask = MAX77620_CNFG_GPIO_INT_MASK, - .type_reg_offset = 0, - .types_supported = IRQ_TYPE_EDGE_BOTH, - }, - }, - [1] = { - .reg_offset = 0, - .mask = MAX77620_IRQ_LVL2_GPIO_EDGE1, - .type = { - .type_rising_val = MAX77620_CNFG_GPIO_INT_RISING, - .type_falling_val = MAX77620_CNFG_GPIO_INT_FALLING, - .type_reg_mask = MAX77620_CNFG_GPIO_INT_MASK, - .type_reg_offset = 1, - .types_supported = IRQ_TYPE_EDGE_BOTH, - }, - }, - [2] = { - .reg_offset = 0, - .mask = MAX77620_IRQ_LVL2_GPIO_EDGE2, - .type = { - .type_rising_val = MAX77620_CNFG_GPIO_INT_RISING, - .type_falling_val = MAX77620_CNFG_GPIO_INT_FALLING, - .type_reg_mask = MAX77620_CNFG_GPIO_INT_MASK, - .type_reg_offset = 2, - .types_supported = IRQ_TYPE_EDGE_BOTH, - }, - }, - [3] = { - .reg_offset = 0, - .mask = MAX77620_IRQ_LVL2_GPIO_EDGE3, - .type = { - .type_rising_val = MAX77620_CNFG_GPIO_INT_RISING, - .type_falling_val = MAX77620_CNFG_GPIO_INT_FALLING, - .type_reg_mask = MAX77620_CNFG_GPIO_INT_MASK, - .type_reg_offset = 3, - .types_supported = IRQ_TYPE_EDGE_BOTH, - }, - }, - [4] = { - .reg_offset = 0, - .mask = MAX77620_IRQ_LVL2_GPIO_EDGE4, - .type = { - .type_rising_val = MAX77620_CNFG_GPIO_INT_RISING, - .type_falling_val = MAX77620_CNFG_GPIO_INT_FALLING, - .type_reg_mask = MAX77620_CNFG_GPIO_INT_MASK, - .type_reg_offset = 4, - .types_supported = IRQ_TYPE_EDGE_BOTH, - }, - }, - [5] = { - .reg_offset = 0, - .mask = MAX77620_IRQ_LVL2_GPIO_EDGE5, - .type = { - .type_rising_val = MAX77620_CNFG_GPIO_INT_RISING, - .type_falling_val = MAX77620_CNFG_GPIO_INT_FALLING, - .type_reg_mask = MAX77620_CNFG_GPIO_INT_MASK, - .type_reg_offset = 5, - .types_supported = IRQ_TYPE_EDGE_BOTH, - }, - }, - [6] = { - .reg_offset = 0, - .mask = MAX77620_IRQ_LVL2_GPIO_EDGE6, - .type = { - .type_rising_val = MAX77620_CNFG_GPIO_INT_RISING, - .type_falling_val = MAX77620_CNFG_GPIO_INT_FALLING, - .type_reg_mask = MAX77620_CNFG_GPIO_INT_MASK, - .type_reg_offset = 6, - .types_supported = IRQ_TYPE_EDGE_BOTH, - }, - }, - [7] = { - .reg_offset = 0, - .mask = MAX77620_IRQ_LVL2_GPIO_EDGE7, - .type = { - .type_rising_val = MAX77620_CNFG_GPIO_INT_RISING, - .type_falling_val = MAX77620_CNFG_GPIO_INT_FALLING, - .type_reg_mask = MAX77620_CNFG_GPIO_INT_MASK, - .type_reg_offset = 7, - .types_supported = IRQ_TYPE_EDGE_BOTH, - }, - }, -}; +static irqreturn_t max77620_gpio_irqhandler(int irq, void *data) +{ + struct max77620_gpio *gpio = data; + unsigned int value, offset; + unsigned long pending; + int err; + + err = regmap_read(gpio->rmap, MAX77620_REG_IRQ_LVL2_GPIO, &value); + if (err < 0) { + dev_err(gpio->dev, "REG_IRQ_LVL2_GPIO read failed: %d\n", err); + return IRQ_NONE; + } + + pending = value; + + for_each_set_bit(offset, &pending, 8) { + unsigned int virq; + + virq = irq_find_mapping(gpio->gpio_chip.irq.domain, offset); + handle_nested_irq(virq); + } + + return IRQ_HANDLED; +} + +static void max77620_gpio_irq_mask(struct irq_data *data) +{ + struct gpio_chip *chip = irq_data_get_irq_chip_data(data); + struct max77620_gpio *gpio = gpiochip_get_data(chip); + + gpio->irq_enabled[data->hwirq] = false; +} -static const struct regmap_irq_chip max77620_gpio_irq_chip = { - .name = "max77620-gpio", - .irqs = max77620_gpio_irqs, - .num_irqs = ARRAY_SIZE(max77620_gpio_irqs), - .num_regs = 1, - .num_type_reg = 8, - .irq_reg_stride = 1, - .type_reg_stride = 1, - .status_base = MAX77620_REG_IRQ_LVL2_GPIO, - .type_base = MAX77620_REG_GPIO0, +static void max77620_gpio_irq_unmask(struct irq_data *data) +{ + struct gpio_chip *chip = irq_data_get_irq_chip_data(data); + struct max77620_gpio *gpio = gpiochip_get_data(chip); + + gpio->irq_enabled[data->hwirq] = true; +} + +static int max77620_gpio_set_irq_type(struct irq_data *data, unsigned int type) +{ + struct gpio_chip *chip = irq_data_get_irq_chip_data(data); + struct max77620_gpio *gpio = gpiochip_get_data(chip); + unsigned int irq_type; + + switch (type) { + case IRQ_TYPE_EDGE_RISING: + irq_type = MAX77620_CNFG_GPIO_INT_RISING; + break; + + case IRQ_TYPE_EDGE_FALLING: + irq_type = MAX77620_CNFG_GPIO_INT_FALLING; + break; + + case IRQ_TYPE_EDGE_BOTH: + irq_type = MAX77620_CNFG_GPIO_INT_RISING | + MAX77620_CNFG_GPIO_INT_FALLING; + break; + + default: + return -EINVAL; + } + + gpio->irq_type[data->hwirq] = irq_type; + + return 0; +} + +static void max77620_gpio_bus_lock(struct irq_data *data) +{ + struct gpio_chip *chip = irq_data_get_irq_chip_data(data); + struct max77620_gpio *gpio = gpiochip_get_data(chip); + + mutex_lock(&gpio->buslock); +} + +static void max77620_gpio_bus_sync_unlock(struct irq_data *data) +{ + struct gpio_chip *chip = irq_data_get_irq_chip_data(data); + struct max77620_gpio *gpio = gpiochip_get_data(chip); + unsigned int value, offset = data->hwirq; + int err; + + value = gpio->irq_enabled[offset] ? gpio->irq_type[offset] : 0; + + err = regmap_update_bits(gpio->rmap, GPIO_REG_ADDR(offset), + MAX77620_CNFG_GPIO_INT_MASK, value); + if (err < 0) + dev_err(chip->parent, "failed to update interrupt mask: %d\n", + err); + + mutex_unlock(&gpio->buslock); +} + +static struct irq_chip max77620_gpio_irqchip = { + .name = "max77620-gpio", + .irq_mask = max77620_gpio_irq_mask, + .irq_unmask = max77620_gpio_irq_unmask, + .irq_set_type = max77620_gpio_set_irq_type, + .irq_bus_lock = max77620_gpio_bus_lock, + .irq_bus_sync_unlock = max77620_gpio_bus_sync_unlock, + .flags = IRQCHIP_MASK_ON_SUSPEND, }; static int max77620_gpio_dir_input(struct gpio_chip *gc, unsigned int offset) @@ -254,14 +260,6 @@ static int max77620_gpio_set_config(struct gpio_chip *gc, unsigned int offset, return -ENOTSUPP; } -static int max77620_gpio_to_irq(struct gpio_chip *gc, unsigned int offset) -{ - struct max77620_gpio *mgpio = gpiochip_get_data(gc); - struct max77620_chip *chip = dev_get_drvdata(mgpio->dev->parent); - - return regmap_irq_get_virq(chip->gpio_irq_data, offset); -} - static int max77620_gpio_probe(struct platform_device *pdev) { struct max77620_chip *chip = dev_get_drvdata(pdev->dev.parent); @@ -287,7 +285,6 @@ static int max77620_gpio_probe(struct platform_device *pdev) mgpio->gpio_chip.direction_output = max77620_gpio_dir_output; mgpio->gpio_chip.set = max77620_gpio_set; mgpio->gpio_chip.set_config = max77620_gpio_set_config; - mgpio->gpio_chip.to_irq = max77620_gpio_to_irq; mgpio->gpio_chip.ngpio = MAX77620_GPIO_NR; mgpio->gpio_chip.can_sleep = 1; mgpio->gpio_chip.base = -1; @@ -303,15 +300,21 @@ static int max77620_gpio_probe(struct platform_device *pdev) return ret; } - ret = devm_regmap_add_irq_chip(&pdev->dev, chip->rmap, gpio_irq, - IRQF_ONESHOT, 0, - &max77620_gpio_irq_chip, - &chip->gpio_irq_data); + mutex_init(&mgpio->buslock); + + gpiochip_irqchip_add_nested(&mgpio->gpio_chip, &max77620_gpio_irqchip, + 0, handle_edge_irq, IRQ_TYPE_NONE); + + ret = request_threaded_irq(gpio_irq, NULL, max77620_gpio_irqhandler, + IRQF_ONESHOT, "max77620-gpio", mgpio); if (ret < 0) { - dev_err(&pdev->dev, "Failed to add gpio irq_chip %d\n", ret); + dev_err(&pdev->dev, "failed to request IRQ: %d\n", ret); return ret; } + gpiochip_set_nested_irqchip(&mgpio->gpio_chip, &max77620_gpio_irqchip, + gpio_irq); + return 0; } -- cgit From 2a36550567307b881ce570a81189682ae1c9d08d Mon Sep 17 00:00:00 2001 From: Thierry Reding Date: Wed, 2 Oct 2019 16:45:02 +0200 Subject: gpio: tegra186: Implement wake event support The GPIO controller doesn't have any controls to enable the system to wake up from low power states based on activity on GPIO pins. An extra hardware block that is part of the power management controller (PMC) contains these controls. In order for the GPIO controller to be able to cooperate with the PMC, obtain a reference to the PMC's IRQ domain and make it a parent to the GPIO controller's IRQ domain. This way the PMC gets an opportunity to program the additional registers required to enable wakeup sources on suspend. Based on additional work by Bitan Biswas . Signed-off-by: Thierry Reding Link: https://lore.kernel.org/r/20191002144502.156393-2-thierry.reding@gmail.com Signed-off-by: Linus Walleij --- drivers/gpio/Kconfig | 1 + drivers/gpio/gpio-tegra186.c | 97 ++++++++++++++++++++++++++++++++++++-------- 2 files changed, 80 insertions(+), 18 deletions(-) diff --git a/drivers/gpio/Kconfig b/drivers/gpio/Kconfig index 7138290cdd36..7365cf150ae5 100644 --- a/drivers/gpio/Kconfig +++ b/drivers/gpio/Kconfig @@ -539,6 +539,7 @@ config GPIO_TEGRA186 depends on ARCH_TEGRA_186_SOC || COMPILE_TEST depends on OF_GPIO select GPIOLIB_IRQCHIP + select IRQ_DOMAIN_HIERARCHY help Say yes here to support GPIO pins on NVIDIA Tegra186 SoCs. diff --git a/drivers/gpio/gpio-tegra186.c b/drivers/gpio/gpio-tegra186.c index a9058fda187e..8a2a69178925 100644 --- a/drivers/gpio/gpio-tegra186.c +++ b/drivers/gpio/gpio-tegra186.c @@ -53,6 +53,7 @@ struct tegra_gpio_soc { const struct tegra_gpio_port *ports; unsigned int num_ports; const char *name; + unsigned int instance; }; struct tegra_gpio { @@ -327,7 +328,7 @@ static int tegra186_irq_set_type(struct irq_data *data, unsigned int type) else irq_set_handler_locked(data, handle_edge_irq); - return 0; + return irq_chip_set_type_parent(data, type); } static void tegra186_gpio_irq(struct irq_desc *desc) @@ -367,39 +368,80 @@ skip: chained_irq_exit(chip, desc); } -static int tegra186_gpio_irq_domain_xlate(struct irq_domain *domain, - struct device_node *np, - const u32 *spec, unsigned int size, - unsigned long *hwirq, - unsigned int *type) +static int tegra186_gpio_irq_domain_translate(struct irq_domain *domain, + struct irq_fwspec *fwspec, + unsigned long *hwirq, + unsigned int *type) { struct tegra_gpio *gpio = gpiochip_get_data(domain->host_data); unsigned int port, pin, i, offset = 0; - if (size < 2) + if (WARN_ON(gpio->gpio.of_gpio_n_cells < 2)) + return -EINVAL; + + if (WARN_ON(fwspec->param_count < gpio->gpio.of_gpio_n_cells)) return -EINVAL; - port = spec[0] / 8; - pin = spec[0] % 8; + port = fwspec->param[0] / 8; + pin = fwspec->param[0] % 8; - if (port >= gpio->soc->num_ports) { - dev_err(gpio->gpio.parent, "invalid port number: %u\n", port); + if (port >= gpio->soc->num_ports) return -EINVAL; - } for (i = 0; i < port; i++) offset += gpio->soc->ports[i].pins; - *type = spec[1] & IRQ_TYPE_SENSE_MASK; + *type = fwspec->param[1] & IRQ_TYPE_SENSE_MASK; *hwirq = offset + pin; return 0; } -static const struct irq_domain_ops tegra186_gpio_irq_domain_ops = { - .map = gpiochip_irq_map, - .unmap = gpiochip_irq_unmap, - .xlate = tegra186_gpio_irq_domain_xlate, +static void tegra186_gpio_populate_parent_fwspec(struct gpio_chip *chip, + struct irq_fwspec *fwspec, + unsigned int parent_hwirq, + unsigned int parent_type) +{ + struct tegra_gpio *gpio = gpiochip_get_data(chip); + + fwspec->param_count = 3; + fwspec->param[0] = gpio->soc->instance; + fwspec->param[1] = parent_hwirq; + fwspec->param[2] = parent_type; +} + +static int tegra186_gpio_child_to_parent_hwirq(struct gpio_chip *chip, + unsigned int hwirq, + unsigned int type, + unsigned int *parent_hwirq, + unsigned int *parent_type) +{ + *parent_hwirq = chip->irq.child_offset_to_irq(chip, hwirq); + *parent_type = type; + + return 0; +} + +static unsigned int tegra186_gpio_child_offset_to_irq(struct gpio_chip *chip, + unsigned int offset) +{ + struct tegra_gpio *gpio = gpiochip_get_data(chip); + unsigned int i; + + for (i = 0; i < gpio->soc->num_ports; i++) { + if (offset < gpio->soc->ports[i].pins) + break; + + offset -= gpio->soc->ports[i].pins; + } + + return offset + i * 8; +} + +static const struct of_device_id tegra186_pmc_of_match[] = { + { .compatible = "nvidia,tegra186-pmc" }, + { .compatible = "nvidia,tegra194-pmc" }, + { /* sentinel */ } }; static int tegra186_gpio_probe(struct platform_device *pdev) @@ -407,6 +449,7 @@ static int tegra186_gpio_probe(struct platform_device *pdev) unsigned int i, j, offset; struct gpio_irq_chip *irq; struct tegra_gpio *gpio; + struct device_node *np; struct resource *res; char **names; int err; @@ -487,10 +530,15 @@ static int tegra186_gpio_probe(struct platform_device *pdev) gpio->intc.irq_mask = tegra186_irq_mask; gpio->intc.irq_unmask = tegra186_irq_unmask; gpio->intc.irq_set_type = tegra186_irq_set_type; + gpio->intc.irq_set_wake = irq_chip_set_wake_parent; irq = &gpio->gpio.irq; irq->chip = &gpio->intc; - irq->domain_ops = &tegra186_gpio_irq_domain_ops; + irq->fwnode = of_node_to_fwnode(pdev->dev.of_node); + irq->child_to_parent_hwirq = tegra186_gpio_child_to_parent_hwirq; + irq->populate_parent_fwspec = tegra186_gpio_populate_parent_fwspec; + irq->child_offset_to_irq = tegra186_gpio_child_offset_to_irq; + irq->child_irq_domain_ops.translate = tegra186_gpio_irq_domain_translate; irq->handler = handle_simple_irq; irq->default_type = IRQ_TYPE_NONE; irq->parent_handler = tegra186_gpio_irq; @@ -498,6 +546,15 @@ static int tegra186_gpio_probe(struct platform_device *pdev) irq->num_parents = gpio->num_irq; irq->parents = gpio->irq; + np = of_find_matching_node(NULL, tegra186_pmc_of_match); + if (np) { + irq->parent_domain = irq_find_host(np); + of_node_put(np); + + if (!irq->parent_domain) + return -EPROBE_DEFER; + } + irq->map = devm_kcalloc(&pdev->dev, gpio->gpio.ngpio, sizeof(*irq->map), GFP_KERNEL); if (!irq->map) @@ -564,6 +621,7 @@ static const struct tegra_gpio_soc tegra186_main_soc = { .num_ports = ARRAY_SIZE(tegra186_main_ports), .ports = tegra186_main_ports, .name = "tegra186-gpio", + .instance = 0, }; #define TEGRA186_AON_GPIO_PORT(port, base, count, controller) \ @@ -589,6 +647,7 @@ static const struct tegra_gpio_soc tegra186_aon_soc = { .num_ports = ARRAY_SIZE(tegra186_aon_ports), .ports = tegra186_aon_ports, .name = "tegra186-gpio-aon", + .instance = 1, }; #define TEGRA194_MAIN_GPIO_PORT(port, base, count, controller) \ @@ -634,6 +693,7 @@ static const struct tegra_gpio_soc tegra194_main_soc = { .num_ports = ARRAY_SIZE(tegra194_main_ports), .ports = tegra194_main_ports, .name = "tegra194-gpio", + .instance = 0, }; #define TEGRA194_AON_GPIO_PORT(port, base, count, controller) \ @@ -656,6 +716,7 @@ static const struct tegra_gpio_soc tegra194_aon_soc = { .num_ports = ARRAY_SIZE(tegra194_aon_ports), .ports = tegra194_aon_ports, .name = "tegra194-gpio-aon", + .instance = 1, }; static const struct of_device_id tegra186_gpio_of_match[] = { -- cgit From 8c550e94b8835170593169a45b5ba30d3fc72a70 Mon Sep 17 00:00:00 2001 From: Drew Fustini Date: Sat, 21 Sep 2019 12:25:23 +0200 Subject: gpio: expose pull-up/pull-down line flags to userspace Add pull-up/pull-down flags to the gpio line get and set ioctl() calls. Use cases include a push button that does not have an external resistor. Addition use cases described by Limor Fried (ladyada) of Adafruit in this PR for Adafruit_Blinka Python lib: https://github.com/adafruit/Adafruit_Blinka/pull/59 Signed-off-by: Drew Fustini Link: https://lore.kernel.org/r/20190921102522.8970-1-drew@pdp7.com Signed-off-by: Linus Walleij --- drivers/gpio/gpiolib.c | 12 ++++++++++++ include/uapi/linux/gpio.h | 4 ++++ 2 files changed, 16 insertions(+) diff --git a/drivers/gpio/gpiolib.c b/drivers/gpio/gpiolib.c index 2342deaace17..921f76d2f5c4 100644 --- a/drivers/gpio/gpiolib.c +++ b/drivers/gpio/gpiolib.c @@ -421,6 +421,8 @@ struct linehandle_state { (GPIOHANDLE_REQUEST_INPUT | \ GPIOHANDLE_REQUEST_OUTPUT | \ GPIOHANDLE_REQUEST_ACTIVE_LOW | \ + GPIOHANDLE_REQUEST_PULL_UP | \ + GPIOHANDLE_REQUEST_PULL_DOWN | \ GPIOHANDLE_REQUEST_OPEN_DRAIN | \ GPIOHANDLE_REQUEST_OPEN_SOURCE) @@ -592,6 +594,10 @@ static int linehandle_create(struct gpio_device *gdev, void __user *ip) set_bit(FLAG_OPEN_DRAIN, &desc->flags); if (lflags & GPIOHANDLE_REQUEST_OPEN_SOURCE) set_bit(FLAG_OPEN_SOURCE, &desc->flags); + if (lflags & GPIOHANDLE_REQUEST_PULL_DOWN) + set_bit(FLAG_PULL_DOWN, &desc->flags); + if (lflags & GPIOHANDLE_REQUEST_PULL_UP) + set_bit(FLAG_PULL_UP, &desc->flags); ret = gpiod_set_transitory(desc, false); if (ret < 0) @@ -1097,6 +1103,10 @@ static long gpio_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) if (test_bit(FLAG_OPEN_SOURCE, &desc->flags)) lineinfo.flags |= (GPIOLINE_FLAG_OPEN_SOURCE | GPIOLINE_FLAG_IS_OUT); + if (test_bit(FLAG_PULL_DOWN, &desc->flags)) + lineinfo.flags |= GPIOLINE_FLAG_PULL_DOWN; + if (test_bit(FLAG_PULL_UP, &desc->flags)) + lineinfo.flags |= GPIOLINE_FLAG_PULL_UP; if (copy_to_user(ip, &lineinfo, sizeof(lineinfo))) return -EFAULT; @@ -2770,6 +2780,8 @@ static bool gpiod_free_commit(struct gpio_desc *desc) clear_bit(FLAG_REQUESTED, &desc->flags); clear_bit(FLAG_OPEN_DRAIN, &desc->flags); clear_bit(FLAG_OPEN_SOURCE, &desc->flags); + clear_bit(FLAG_PULL_UP, &desc->flags); + clear_bit(FLAG_PULL_DOWN, &desc->flags); clear_bit(FLAG_IS_HOGGED, &desc->flags); ret = true; } diff --git a/include/uapi/linux/gpio.h b/include/uapi/linux/gpio.h index 4ebfe0ac6c5b..c2d1f7d908d6 100644 --- a/include/uapi/linux/gpio.h +++ b/include/uapi/linux/gpio.h @@ -33,6 +33,8 @@ struct gpiochip_info { #define GPIOLINE_FLAG_ACTIVE_LOW (1UL << 2) #define GPIOLINE_FLAG_OPEN_DRAIN (1UL << 3) #define GPIOLINE_FLAG_OPEN_SOURCE (1UL << 4) +#define GPIOLINE_FLAG_PULL_UP (1UL << 5) +#define GPIOLINE_FLAG_PULL_DOWN (1UL << 6) /** * struct gpioline_info - Information about a certain GPIO line @@ -62,6 +64,8 @@ struct gpioline_info { #define GPIOHANDLE_REQUEST_ACTIVE_LOW (1UL << 2) #define GPIOHANDLE_REQUEST_OPEN_DRAIN (1UL << 3) #define GPIOHANDLE_REQUEST_OPEN_SOURCE (1UL << 4) +#define GPIOHANDLE_REQUEST_PULL_UP (1UL << 5) +#define GPIOHANDLE_REQUEST_PULL_DOWN (1UL << 6) /** * struct gpiohandle_request - Information about a GPIO handle request -- cgit From 14e8c535ff684876d1be9dae475fe666b97c04a9 Mon Sep 17 00:00:00 2001 From: Randy Dunlap Date: Tue, 8 Oct 2019 13:40:21 -0700 Subject: gpio: fix kernel-doc for of_gpio_need_valid_mask() Fix kernel-doc for of_gpio_need_valid_mask(). Fixes this warning and uses correct Return: format. ../drivers/gpio/gpiolib-of.c:92: warning: Excess function parameter 'dev' description in 'of_gpio_need_valid_mask' Fixes: f626d6dfb709 ("gpio: of: Break out OF-only code") Signed-off-by: Randy Dunlap Cc: Linus Walleij Cc: Bartosz Golaszewski Cc: linux-gpio@vger.kernel.org Link: https://lore.kernel.org/r/6c5d22c8-6e27-3314-9c46-701d932b11a6@infradead.org Signed-off-by: Linus Walleij --- drivers/gpio/gpiolib-of.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/drivers/gpio/gpiolib-of.c b/drivers/gpio/gpiolib-of.c index 1eea2c6c2e1d..3f50c433b7b1 100644 --- a/drivers/gpio/gpiolib-of.c +++ b/drivers/gpio/gpiolib-of.c @@ -84,8 +84,9 @@ static struct gpio_desc *of_xlate_and_get_gpiod_flags(struct gpio_chip *chip, /** * of_gpio_need_valid_mask() - figure out if the OF GPIO driver needs * to set the .valid_mask - * @dev: the device for the GPIO provider - * @return: true if the valid mask needs to be set + * @gc: the target gpio_chip + * + * Return: true if the valid mask needs to be set */ bool of_gpio_need_valid_mask(const struct gpio_chip *gc) { -- cgit From 5f07224e0fae2a7d475eb21a79ee5a08251d9c44 Mon Sep 17 00:00:00 2001 From: Jonathan Neuschäfer Date: Fri, 4 Oct 2019 18:40:55 +0200 Subject: docs: driver-api: Move bt8xxgpio to the gpio directory MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Let's declutter Documentation/driver-api a bit. Signed-off-by: Jonathan Neuschäfer Link: https://lore.kernel.org/r/20191004164059.10397-1-j.neuschaefer@gmx.net Signed-off-by: Linus Walleij --- Documentation/driver-api/bt8xxgpio.rst | 62 ----------------------------- Documentation/driver-api/gpio/bt8xxgpio.rst | 62 +++++++++++++++++++++++++++++ Documentation/driver-api/gpio/index.rst | 1 + Documentation/driver-api/index.rst | 1 - drivers/gpio/Kconfig | 2 +- 5 files changed, 64 insertions(+), 64 deletions(-) delete mode 100644 Documentation/driver-api/bt8xxgpio.rst create mode 100644 Documentation/driver-api/gpio/bt8xxgpio.rst diff --git a/Documentation/driver-api/bt8xxgpio.rst b/Documentation/driver-api/bt8xxgpio.rst deleted file mode 100644 index a845feb074de..000000000000 --- a/Documentation/driver-api/bt8xxgpio.rst +++ /dev/null @@ -1,62 +0,0 @@ -=================================================================== -A driver for a selfmade cheap BT8xx based PCI GPIO-card (bt8xxgpio) -=================================================================== - -For advanced documentation, see http://www.bu3sch.de/btgpio.php - -A generic digital 24-port PCI GPIO card can be built out of an ordinary -Brooktree bt848, bt849, bt878 or bt879 based analog TV tuner card. The -Brooktree chip is used in old analog Hauppauge WinTV PCI cards. You can easily -find them used for low prices on the net. - -The bt8xx chip does have 24 digital GPIO ports. -These ports are accessible via 24 pins on the SMD chip package. - - -How to physically access the GPIO pins -====================================== - -The are several ways to access these pins. One might unsolder the whole chip -and put it on a custom PCI board, or one might only unsolder each individual -GPIO pin and solder that to some tiny wire. As the chip package really is tiny -there are some advanced soldering skills needed in any case. - -The physical pinouts are drawn in the following ASCII art. -The GPIO pins are marked with G00-G23:: - - G G G G G G G G G G G G G G G G G G - 0 0 0 0 0 0 0 0 0 0 1 1 1 1 1 1 1 1 - 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 - | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | - --------------------------------------------------------------------------- - --| ^ ^ |-- - --| pin 86 pin 67 |-- - --| |-- - --| pin 61 > |-- G18 - --| |-- G19 - --| |-- G20 - --| |-- G21 - --| |-- G22 - --| pin 56 > |-- G23 - --| |-- - --| Brooktree 878/879 |-- - --| |-- - --| |-- - --| |-- - --| |-- - --| |-- - --| |-- - --| |-- - --| |-- - --| |-- - --| |-- - --| |-- - --| |-- - --| |-- - --| O |-- - --| |-- - --------------------------------------------------------------------------- - | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | - ^ - This is pin 1 - diff --git a/Documentation/driver-api/gpio/bt8xxgpio.rst b/Documentation/driver-api/gpio/bt8xxgpio.rst new file mode 100644 index 000000000000..a845feb074de --- /dev/null +++ b/Documentation/driver-api/gpio/bt8xxgpio.rst @@ -0,0 +1,62 @@ +=================================================================== +A driver for a selfmade cheap BT8xx based PCI GPIO-card (bt8xxgpio) +=================================================================== + +For advanced documentation, see http://www.bu3sch.de/btgpio.php + +A generic digital 24-port PCI GPIO card can be built out of an ordinary +Brooktree bt848, bt849, bt878 or bt879 based analog TV tuner card. The +Brooktree chip is used in old analog Hauppauge WinTV PCI cards. You can easily +find them used for low prices on the net. + +The bt8xx chip does have 24 digital GPIO ports. +These ports are accessible via 24 pins on the SMD chip package. + + +How to physically access the GPIO pins +====================================== + +The are several ways to access these pins. One might unsolder the whole chip +and put it on a custom PCI board, or one might only unsolder each individual +GPIO pin and solder that to some tiny wire. As the chip package really is tiny +there are some advanced soldering skills needed in any case. + +The physical pinouts are drawn in the following ASCII art. +The GPIO pins are marked with G00-G23:: + + G G G G G G G G G G G G G G G G G G + 0 0 0 0 0 0 0 0 0 0 1 1 1 1 1 1 1 1 + 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 + | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | + --------------------------------------------------------------------------- + --| ^ ^ |-- + --| pin 86 pin 67 |-- + --| |-- + --| pin 61 > |-- G18 + --| |-- G19 + --| |-- G20 + --| |-- G21 + --| |-- G22 + --| pin 56 > |-- G23 + --| |-- + --| Brooktree 878/879 |-- + --| |-- + --| |-- + --| |-- + --| |-- + --| |-- + --| |-- + --| |-- + --| |-- + --| |-- + --| |-- + --| |-- + --| |-- + --| |-- + --| O |-- + --| |-- + --------------------------------------------------------------------------- + | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | + ^ + This is pin 1 + diff --git a/Documentation/driver-api/gpio/index.rst b/Documentation/driver-api/gpio/index.rst index c5b8467f9104..5b61032aa4ea 100644 --- a/Documentation/driver-api/gpio/index.rst +++ b/Documentation/driver-api/gpio/index.rst @@ -13,6 +13,7 @@ Contents: board drivers-on-gpio legacy + bt8xxgpio Core ==== diff --git a/Documentation/driver-api/index.rst b/Documentation/driver-api/index.rst index 38e638abe3eb..2b3b6949381e 100644 --- a/Documentation/driver-api/index.rst +++ b/Documentation/driver-api/index.rst @@ -69,7 +69,6 @@ available subsections can be seen below. fpga/index acpi/index backlight/lp855x-driver.rst - bt8xxgpio connector console dcdbas diff --git a/drivers/gpio/Kconfig b/drivers/gpio/Kconfig index 7365cf150ae5..088a8a0f8add 100644 --- a/drivers/gpio/Kconfig +++ b/drivers/gpio/Kconfig @@ -1329,7 +1329,7 @@ config GPIO_BT8XX The card needs to be physically altered for using it as a GPIO card. For more information on how to build a GPIO card from a BT8xx TV card, see the documentation file at - Documentation/driver-api/bt8xxgpio.rst + Documentation/driver-api/gpio/bt8xxgpio.rst If unsure, say N. -- cgit From 95873fba06ae39e4042647dec9c1138c0109ce7b Mon Sep 17 00:00:00 2001 From: Jonathan Neuschäfer Date: Fri, 4 Oct 2019 18:40:56 +0200 Subject: docs: driver-api: bt8xxgpio: Revive dead link MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit www.bu3sch.de has been unusable for several years, but the same information is available on bues.ch. Signed-off-by: Jonathan Neuschäfer Link: https://lore.kernel.org/r/20191004164059.10397-2-j.neuschaefer@gmx.net Acked-by: Michael Büsch Reviewed-by: Mauro Carvalho Chehab Signed-off-by: Linus Walleij --- Documentation/driver-api/gpio/bt8xxgpio.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Documentation/driver-api/gpio/bt8xxgpio.rst b/Documentation/driver-api/gpio/bt8xxgpio.rst index a845feb074de..d7e75f1234e7 100644 --- a/Documentation/driver-api/gpio/bt8xxgpio.rst +++ b/Documentation/driver-api/gpio/bt8xxgpio.rst @@ -2,7 +2,7 @@ A driver for a selfmade cheap BT8xx based PCI GPIO-card (bt8xxgpio) =================================================================== -For advanced documentation, see http://www.bu3sch.de/btgpio.php +For advanced documentation, see https://bues.ch/cms/unmaintained/btgpio.html A generic digital 24-port PCI GPIO card can be built out of an ordinary Brooktree bt848, bt849, bt878 or bt879 based analog TV tuner card. The -- cgit From 698b8eeaed7287970fc2b6d322618850fd1b1e6c Mon Sep 17 00:00:00 2001 From: Song Hui Date: Fri, 11 Oct 2019 08:56:43 +0800 Subject: gpio/mpc8xxx: change irq handler from chained to normal More than one gpio controllers can share one interrupt, change the driver to request shared irq. While this will work, it will mess up userspace accounting of the number of interrupts per second in tools such as vmstat. The reason is that for every GPIO interrupt, /proc/interrupts records the count against GIC interrupt 68 or 69, as well as the GPIO itself. So, for every GPIO interrupt, the total number of interrupts that the system has seen increments by two. Signed-off-by: Laurentiu Tudor Signed-off-by: Alex Marginean Signed-off-by: Song Hui Link: https://lore.kernel.org/r/20191011005643.41007-1-hui.song_1@nxp.com Signed-off-by: Linus Walleij --- drivers/gpio/gpio-mpc8xxx.c | 30 +++++++++++++++++++----------- 1 file changed, 19 insertions(+), 11 deletions(-) diff --git a/drivers/gpio/gpio-mpc8xxx.c b/drivers/gpio/gpio-mpc8xxx.c index 16a47de29c94..58ff37219fce 100644 --- a/drivers/gpio/gpio-mpc8xxx.c +++ b/drivers/gpio/gpio-mpc8xxx.c @@ -22,6 +22,7 @@ #include #include #include +#include #define MPC8XXX_GPIO_PINS 32 @@ -127,20 +128,19 @@ static int mpc8xxx_gpio_to_irq(struct gpio_chip *gc, unsigned offset) return -ENXIO; } -static void mpc8xxx_gpio_irq_cascade(struct irq_desc *desc) +static irqreturn_t mpc8xxx_gpio_irq_cascade(int irq, void *data) { - struct mpc8xxx_gpio_chip *mpc8xxx_gc = irq_desc_get_handler_data(desc); - struct irq_chip *chip = irq_desc_get_chip(desc); + struct mpc8xxx_gpio_chip *mpc8xxx_gc = data; struct gpio_chip *gc = &mpc8xxx_gc->gc; - unsigned int mask; + unsigned long mask; + int i; mask = gc->read_reg(mpc8xxx_gc->regs + GPIO_IER) & gc->read_reg(mpc8xxx_gc->regs + GPIO_IMR); - if (mask) - generic_handle_irq(irq_linear_revmap(mpc8xxx_gc->irq, - 32 - ffs(mask))); - if (chip->irq_eoi) - chip->irq_eoi(&desc->irq_data); + for_each_set_bit(i, &mask, 32) + generic_handle_irq(irq_linear_revmap(mpc8xxx_gc->irq, 31 - i)); + + return IRQ_HANDLED; } static void mpc8xxx_irq_unmask(struct irq_data *d) @@ -409,8 +409,16 @@ static int mpc8xxx_probe(struct platform_device *pdev) if (devtype->gpio_dir_in_init) devtype->gpio_dir_in_init(gc); - irq_set_chained_handler_and_data(mpc8xxx_gc->irqn, - mpc8xxx_gpio_irq_cascade, mpc8xxx_gc); + ret = devm_request_irq(&pdev->dev, mpc8xxx_gc->irqn, + mpc8xxx_gpio_irq_cascade, + IRQF_NO_THREAD | IRQF_SHARED, "gpio-cascade", + mpc8xxx_gc); + if (ret) { + dev_err(&pdev->dev, "%s: failed to devm_request_irq(%d), ret = %d\n", + np->full_name, mpc8xxx_gc->irqn, ret); + goto err; + } + return 0; err: iounmap(mpc8xxx_gc->regs); -- cgit From 4a6a6f5c4aeedb72db871d60bfcca89835f317aa Mon Sep 17 00:00:00 2001 From: Shuah Khan Date: Thu, 26 Sep 2019 19:16:41 -0600 Subject: tools: gpio: Use !building_out_of_srctree to determine srctree make TARGETS=gpio kselftest fails with: Makefile:23: tools/build/Makefile.include: No such file or directory When the gpio tool make is invoked from tools Makefile, srctree is cleared and the current logic check for srctree equals to empty string to determine srctree location from CURDIR. When the build in invoked from selftests/gpio Makefile, the srctree is set to "." and the same logic used for srctree equals to empty is needed to determine srctree. Check building_out_of_srctree undefined as the condition for both cases to fix "make TARGETS=gpio kselftest" build failure. Cc: stable@vger.kernel.org Signed-off-by: Shuah Khan Signed-off-by: Bartosz Golaszewski --- tools/gpio/Makefile | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/tools/gpio/Makefile b/tools/gpio/Makefile index 6ecdd1067826..1178d302757e 100644 --- a/tools/gpio/Makefile +++ b/tools/gpio/Makefile @@ -3,7 +3,11 @@ include ../scripts/Makefile.include bindir ?= /usr/bin -ifeq ($(srctree),) +# This will work when gpio is built in tools env. where srctree +# isn't set and when invoked from selftests build, where srctree +# is set to ".". building_out_of_srctree is undefined for in srctree +# builds +ifndef building_out_of_srctree srctree := $(patsubst %/,%,$(dir $(CURDIR))) srctree := $(patsubst %/,%,$(dir $(srctree))) endif -- cgit From 8a99358a1d8e4987f9b2b9cbb5e31a44f9c4c674 Mon Sep 17 00:00:00 2001 From: Linus Walleij Date: Fri, 4 Jan 2019 23:27:02 +0100 Subject: ata: ahci-imx: Covert to use GPIO descriptor This converts the i.MX AHCI driver to use a GPIO descriptor instead of parsing the device tree by itself. This driver is quite obviously device tree only, and the GPIO line is treated as optional, so let's keep it as optional. None of the device trees in the kernel use this GPIO facility today, so it is hard to test. Cc: Egor Starkov Cc: Richard Zhu Signed-off-by: Linus Walleij --- drivers/ata/ahci_imx.c | 25 ++++++++----------------- 1 file changed, 8 insertions(+), 17 deletions(-) diff --git a/drivers/ata/ahci_imx.c b/drivers/ata/ahci_imx.c index bfc617cc8ac5..948d2c6557f3 100644 --- a/drivers/ata/ahci_imx.c +++ b/drivers/ata/ahci_imx.c @@ -11,8 +11,8 @@ #include #include #include +#include #include -#include #include #include #include @@ -100,7 +100,7 @@ struct imx_ahci_priv { struct clk *phy_pclk0; struct clk *phy_pclk1; void __iomem *phy_base; - int clkreq_gpio; + struct gpio_desc *clkreq_gpiod; struct regmap *gpr; bool no_device; bool first_time; @@ -980,7 +980,6 @@ static struct scsi_host_template ahci_platform_sht = { static int imx8_sata_probe(struct device *dev, struct imx_ahci_priv *imxpriv) { - int ret; struct resource *phy_res; struct platform_device *pdev = imxpriv->ahci_pdev; struct device_node *np = dev->of_node; @@ -1033,20 +1032,12 @@ static int imx8_sata_probe(struct device *dev, struct imx_ahci_priv *imxpriv) } /* Fetch GPIO, then enable the external OSC */ - imxpriv->clkreq_gpio = of_get_named_gpio(np, "clkreq-gpio", 0); - if (gpio_is_valid(imxpriv->clkreq_gpio)) { - ret = devm_gpio_request_one(dev, imxpriv->clkreq_gpio, - GPIOF_OUT_INIT_LOW, - "SATA CLKREQ"); - if (ret == -EBUSY) { - dev_info(dev, "clkreq had been initialized.\n"); - } else if (ret) { - dev_err(dev, "%d unable to get clkreq.\n", ret); - return ret; - } - } else if (imxpriv->clkreq_gpio == -EPROBE_DEFER) { - return imxpriv->clkreq_gpio; - } + imxpriv->clkreq_gpiod = devm_gpiod_get_optional(dev, "clkreq", + GPIOD_OUT_LOW | GPIOD_FLAGS_BIT_NONEXCLUSIVE); + if (IS_ERR(imxpriv->clkreq_gpiod)) + return PTR_ERR(imxpriv->clkreq_gpiod); + if (imxpriv->clkreq_gpiod) + gpiod_set_consumer_name(imxpriv->clkreq_gpiod, "SATA CLKREQ"); return 0; } -- cgit From 69e00e2d8d313a8e3b7d8397384d94aa014be6b1 Mon Sep 17 00:00:00 2001 From: Manivannan Sadhasivam Date: Mon, 21 Oct 2019 12:14:10 +0530 Subject: dt-bindings: gpio: Add devicetree binding for RDA Micro GPIO controller Add YAML devicetree binding for RDA Micro GPIO controller. Signed-off-by: Manivannan Sadhasivam Link: https://lore.kernel.org/r/20191021064413.19840-2-manivannan.sadhasivam@linaro.org Signed-off-by: Linus Walleij --- .../devicetree/bindings/gpio/gpio-rda.yaml | 50 ++++++++++++++++++++++ 1 file changed, 50 insertions(+) create mode 100644 Documentation/devicetree/bindings/gpio/gpio-rda.yaml diff --git a/Documentation/devicetree/bindings/gpio/gpio-rda.yaml b/Documentation/devicetree/bindings/gpio/gpio-rda.yaml new file mode 100644 index 000000000000..6ece555f074f --- /dev/null +++ b/Documentation/devicetree/bindings/gpio/gpio-rda.yaml @@ -0,0 +1,50 @@ +# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/gpio/gpio-rda.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: RDA Micro GPIO controller + +maintainers: + - Manivannan Sadhasivam + +properties: + compatible: + const: rda,8810pl-gpio + + reg: + maxItems: 1 + + gpio-controller: true + + "#gpio-cells": + const: 2 + + ngpios: + description: + Number of available gpios in a bank. + minimum: 1 + maximum: 32 + + interrupt-controller: true + + "#interrupt-cells": + const: 2 + + interrupts: + maxItems: 1 + +required: + - compatible + - reg + - gpio-controller + - "#gpio-cells" + - ngpios + - interrupt-controller + - "#interrupt-cells" + - interrupts + +additionalProperties: false + +... -- cgit From d57eb825e0dc6f0b5be78251d69cbf1bdd1db622 Mon Sep 17 00:00:00 2001 From: Manivannan Sadhasivam Date: Mon, 21 Oct 2019 12:14:12 +0530 Subject: gpio: Add RDA Micro GPIO controller support Add support for GPIO controller from RDA Micro. This GPIO controller is an in house IP, developed by RDA Micro (now Unisoc) for the use in RDA88* series of SoCs. There are multiple GPIO ports present in all SoCs, each capable of addressing 32 GPIOs. But only first 8 pins have the interrupt capability. Signed-off-by: Manivannan Sadhasivam Link: https://lore.kernel.org/r/20191021064413.19840-4-manivannan.sadhasivam@linaro.org Reviewed-by: Bartosz Golaszewski Signed-off-by: Linus Walleij --- drivers/gpio/Kconfig | 9 ++ drivers/gpio/Makefile | 1 + drivers/gpio/gpio-rda.c | 294 ++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 304 insertions(+) create mode 100644 drivers/gpio/gpio-rda.c diff --git a/drivers/gpio/Kconfig b/drivers/gpio/Kconfig index 088a8a0f8add..8ec1f041c98d 100644 --- a/drivers/gpio/Kconfig +++ b/drivers/gpio/Kconfig @@ -443,6 +443,15 @@ config GPIO_RCAR help Say yes here to support GPIO on Renesas R-Car SoCs. +config GPIO_RDA + bool "RDA Micro GPIO controller support" + depends on ARCH_RDA || COMPILE_TEST + depends on OF_GPIO + select GPIO_GENERIC + select GPIOLIB_IRQCHIP + help + Say Y here to support RDA Micro GPIO controller. + config GPIO_REG bool help diff --git a/drivers/gpio/Makefile b/drivers/gpio/Makefile index e4599f90f702..84e05701f500 100644 --- a/drivers/gpio/Makefile +++ b/drivers/gpio/Makefile @@ -116,6 +116,7 @@ obj-$(CONFIG_GPIO_PXA) += gpio-pxa.o obj-$(CONFIG_GPIO_RASPBERRYPI_EXP) += gpio-raspberrypi-exp.o obj-$(CONFIG_GPIO_RC5T583) += gpio-rc5t583.o obj-$(CONFIG_GPIO_RCAR) += gpio-rcar.o +obj-$(CONFIG_GPIO_RDA) += gpio-rda.o obj-$(CONFIG_GPIO_RDC321X) += gpio-rdc321x.o obj-$(CONFIG_GPIO_REG) += gpio-reg.o obj-$(CONFIG_ARCH_SA1100) += gpio-sa1100.o diff --git a/drivers/gpio/gpio-rda.c b/drivers/gpio/gpio-rda.c new file mode 100644 index 000000000000..28dcbb58b76b --- /dev/null +++ b/drivers/gpio/gpio-rda.c @@ -0,0 +1,294 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * RDA Micro GPIO driver + * + * Copyright (C) 2012 RDA Micro Inc. + * Copyright (C) 2019 Manivannan Sadhasivam + */ + +#include +#include +#include +#include +#include +#include + +#define RDA_GPIO_OEN_VAL 0x00 +#define RDA_GPIO_OEN_SET_OUT 0x04 +#define RDA_GPIO_OEN_SET_IN 0x08 +#define RDA_GPIO_VAL 0x0c +#define RDA_GPIO_SET 0x10 +#define RDA_GPIO_CLR 0x14 +#define RDA_GPIO_INT_CTRL_SET 0x18 +#define RDA_GPIO_INT_CTRL_CLR 0x1c +#define RDA_GPIO_INT_CLR 0x20 +#define RDA_GPIO_INT_STATUS 0x24 + +#define RDA_GPIO_IRQ_RISE_SHIFT 0 +#define RDA_GPIO_IRQ_FALL_SHIFT 8 +#define RDA_GPIO_DEBOUCE_SHIFT 16 +#define RDA_GPIO_LEVEL_SHIFT 24 + +#define RDA_GPIO_IRQ_MASK 0xff + +/* Each bank consists of 32 GPIOs */ +#define RDA_GPIO_BANK_NR 32 + +struct rda_gpio { + struct gpio_chip chip; + void __iomem *base; + spinlock_t lock; + struct irq_chip irq_chip; + int irq; +}; + +static inline void rda_gpio_update(struct gpio_chip *chip, unsigned int offset, + u16 reg, int val) +{ + struct rda_gpio *rda_gpio = gpiochip_get_data(chip); + void __iomem *base = rda_gpio->base; + unsigned long flags; + u32 tmp; + + spin_lock_irqsave(&rda_gpio->lock, flags); + tmp = readl_relaxed(base + reg); + + if (val) + tmp |= BIT(offset); + else + tmp &= ~BIT(offset); + + writel_relaxed(tmp, base + reg); + spin_unlock_irqrestore(&rda_gpio->lock, flags); +} + +static void rda_gpio_irq_mask(struct irq_data *data) +{ + struct gpio_chip *chip = irq_data_get_irq_chip_data(data); + struct rda_gpio *rda_gpio = gpiochip_get_data(chip); + void __iomem *base = rda_gpio->base; + u32 offset = irqd_to_hwirq(data); + u32 value; + + value = BIT(offset) << RDA_GPIO_IRQ_RISE_SHIFT; + value |= BIT(offset) << RDA_GPIO_IRQ_FALL_SHIFT; + + writel_relaxed(value, base + RDA_GPIO_INT_CTRL_CLR); +} + +static void rda_gpio_irq_ack(struct irq_data *data) +{ + struct gpio_chip *chip = irq_data_get_irq_chip_data(data); + u32 offset = irqd_to_hwirq(data); + + rda_gpio_update(chip, offset, RDA_GPIO_INT_CLR, 1); +} + +static int rda_gpio_set_irq(struct gpio_chip *chip, u32 offset, + unsigned int flow_type) +{ + struct rda_gpio *rda_gpio = gpiochip_get_data(chip); + void __iomem *base = rda_gpio->base; + u32 value; + + switch (flow_type) { + case IRQ_TYPE_EDGE_RISING: + /* Set rising edge trigger */ + value = BIT(offset) << RDA_GPIO_IRQ_RISE_SHIFT; + writel_relaxed(value, base + RDA_GPIO_INT_CTRL_SET); + + /* Switch to edge trigger interrupt */ + value = BIT(offset) << RDA_GPIO_LEVEL_SHIFT; + writel_relaxed(value, base + RDA_GPIO_INT_CTRL_CLR); + break; + + case IRQ_TYPE_EDGE_FALLING: + /* Set falling edge trigger */ + value = BIT(offset) << RDA_GPIO_IRQ_FALL_SHIFT; + writel_relaxed(value, base + RDA_GPIO_INT_CTRL_SET); + + /* Switch to edge trigger interrupt */ + value = BIT(offset) << RDA_GPIO_LEVEL_SHIFT; + writel_relaxed(value, base + RDA_GPIO_INT_CTRL_CLR); + break; + + case IRQ_TYPE_EDGE_BOTH: + /* Set both edge trigger */ + value = BIT(offset) << RDA_GPIO_IRQ_RISE_SHIFT; + value |= BIT(offset) << RDA_GPIO_IRQ_FALL_SHIFT; + writel_relaxed(value, base + RDA_GPIO_INT_CTRL_SET); + + /* Switch to edge trigger interrupt */ + value = BIT(offset) << RDA_GPIO_LEVEL_SHIFT; + writel_relaxed(value, base + RDA_GPIO_INT_CTRL_CLR); + break; + + case IRQ_TYPE_LEVEL_HIGH: + /* Set high level trigger */ + value = BIT(offset) << RDA_GPIO_IRQ_RISE_SHIFT; + + /* Switch to level trigger interrupt */ + value |= BIT(offset) << RDA_GPIO_LEVEL_SHIFT; + writel_relaxed(value, base + RDA_GPIO_INT_CTRL_SET); + break; + + case IRQ_TYPE_LEVEL_LOW: + /* Set low level trigger */ + value = BIT(offset) << RDA_GPIO_IRQ_FALL_SHIFT; + + /* Switch to level trigger interrupt */ + value |= BIT(offset) << RDA_GPIO_LEVEL_SHIFT; + writel_relaxed(value, base + RDA_GPIO_INT_CTRL_SET); + break; + + default: + return -EINVAL; + } + + return 0; +} + +static void rda_gpio_irq_unmask(struct irq_data *data) +{ + struct gpio_chip *chip = irq_data_get_irq_chip_data(data); + u32 offset = irqd_to_hwirq(data); + u32 trigger = irqd_get_trigger_type(data); + + rda_gpio_set_irq(chip, offset, trigger); +} + +static int rda_gpio_irq_set_type(struct irq_data *data, unsigned int flow_type) +{ + struct gpio_chip *chip = irq_data_get_irq_chip_data(data); + u32 offset = irqd_to_hwirq(data); + int ret; + + ret = rda_gpio_set_irq(chip, offset, flow_type); + if (ret) + return ret; + + if (flow_type & (IRQ_TYPE_LEVEL_LOW | IRQ_TYPE_LEVEL_HIGH)) + irq_set_handler_locked(data, handle_level_irq); + else if (flow_type & (IRQ_TYPE_EDGE_FALLING | IRQ_TYPE_EDGE_RISING)) + irq_set_handler_locked(data, handle_edge_irq); + + return 0; +} + +static void rda_gpio_irq_handler(struct irq_desc *desc) +{ + struct gpio_chip *chip = irq_desc_get_handler_data(desc); + struct irq_chip *ic = irq_desc_get_chip(desc); + struct rda_gpio *rda_gpio = gpiochip_get_data(chip); + unsigned long status; + u32 n, girq; + + chained_irq_enter(ic, desc); + + status = readl_relaxed(rda_gpio->base + RDA_GPIO_INT_STATUS); + /* Only lower 8 bits are capable of generating interrupts */ + status &= RDA_GPIO_IRQ_MASK; + + for_each_set_bit(n, &status, RDA_GPIO_BANK_NR) { + girq = irq_find_mapping(chip->irq.domain, n); + generic_handle_irq(girq); + } + + chained_irq_exit(ic, desc); +} + +static int rda_gpio_probe(struct platform_device *pdev) +{ + struct device_node *np = pdev->dev.of_node; + struct device *dev = &pdev->dev; + struct gpio_irq_chip *girq; + struct rda_gpio *rda_gpio; + u32 ngpios; + int ret; + + rda_gpio = devm_kzalloc(dev, sizeof(*rda_gpio), GFP_KERNEL); + if (!rda_gpio) + return -ENOMEM; + + ret = device_property_read_u32(dev, "ngpios", &ngpios); + if (ret < 0) + return ret; + + /* + * Not all ports have interrupt capability. For instance, on + * RDA8810PL, GPIOC doesn't support interrupt. So we must handle + * those also. + */ + rda_gpio->irq = platform_get_irq(pdev, 0); + + rda_gpio->base = devm_platform_ioremap_resource(pdev, 0); + if (IS_ERR(rda_gpio->base)) + return PTR_ERR(rda_gpio->base); + + spin_lock_init(&rda_gpio->lock); + + ret = bgpio_init(&rda_gpio->chip, dev, 4, + rda_gpio->base + RDA_GPIO_VAL, + rda_gpio->base + RDA_GPIO_SET, + rda_gpio->base + RDA_GPIO_CLR, + rda_gpio->base + RDA_GPIO_OEN_SET_OUT, + rda_gpio->base + RDA_GPIO_OEN_SET_IN, + BGPIOF_READ_OUTPUT_REG_SET); + if (ret) { + dev_err(dev, "bgpio_init failed\n"); + return ret; + } + + rda_gpio->chip.label = dev_name(dev); + rda_gpio->chip.ngpio = ngpios; + rda_gpio->chip.base = -1; + rda_gpio->chip.parent = dev; + rda_gpio->chip.of_node = np; + + if (rda_gpio->irq >= 0) { + rda_gpio->irq_chip.name = "rda-gpio", + rda_gpio->irq_chip.irq_ack = rda_gpio_irq_ack, + rda_gpio->irq_chip.irq_mask = rda_gpio_irq_mask, + rda_gpio->irq_chip.irq_unmask = rda_gpio_irq_unmask, + rda_gpio->irq_chip.irq_set_type = rda_gpio_irq_set_type, + rda_gpio->irq_chip.flags = IRQCHIP_SKIP_SET_WAKE, + + girq = &rda_gpio->chip.irq; + girq->chip = &rda_gpio->irq_chip; + girq->handler = handle_bad_irq; + girq->default_type = IRQ_TYPE_NONE; + girq->parent_handler = rda_gpio_irq_handler; + girq->parent_handler_data = rda_gpio; + girq->num_parents = 1; + girq->parents = devm_kcalloc(dev, 1, + sizeof(*girq->parents), + GFP_KERNEL); + if (!girq->parents) + return -ENOMEM; + girq->parents[0] = rda_gpio->irq; + } + + platform_set_drvdata(pdev, rda_gpio); + + return devm_gpiochip_add_data(dev, &rda_gpio->chip, rda_gpio); +} + +static const struct of_device_id rda_gpio_of_match[] = { + { .compatible = "rda,8810pl-gpio", }, + { /* sentinel */ } +}; +MODULE_DEVICE_TABLE(of, rda_gpio_of_match); + +static struct platform_driver rda_gpio_driver = { + .probe = rda_gpio_probe, + .driver = { + .name = "rda-gpio", + .of_match_table = rda_gpio_of_match, + }, +}; + +module_platform_driver_probe(rda_gpio_driver, rda_gpio_probe); + +MODULE_DESCRIPTION("RDA Micro GPIO driver"); +MODULE_AUTHOR("Manivannan Sadhasivam "); +MODULE_LICENSE("GPL v2"); -- cgit From 921d6c32b6f86c48e06667ce2f8c50ca45bfa212 Mon Sep 17 00:00:00 2001 From: Manivannan Sadhasivam Date: Mon, 21 Oct 2019 12:14:13 +0530 Subject: MAINTAINERS: Add entry for RDA Micro GPIO driver and binding Add MAINTAINERS entry for RDA Micro GPIO driver and devicetree binding. Signed-off-by: Manivannan Sadhasivam Link: https://lore.kernel.org/r/20191021064413.19840-5-manivannan.sadhasivam@linaro.org Signed-off-by: Linus Walleij --- MAINTAINERS | 2 ++ 1 file changed, 2 insertions(+) diff --git a/MAINTAINERS b/MAINTAINERS index 296de2b51c83..d33ad83c5718 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -2150,9 +2150,11 @@ L: linux-unisoc@lists.infradead.org (moderated for non-subscribers) S: Maintained F: arch/arm/boot/dts/rda8810pl-* F: drivers/clocksource/timer-rda.c +F: drivers/gpio/gpio-rda.c F: drivers/irqchip/irq-rda-intc.c F: drivers/tty/serial/rda-uart.c F: Documentation/devicetree/bindings/arm/rda.yaml +F: Documentation/devicetree/bindings/gpio/gpio-rda.yaml F: Documentation/devicetree/bindings/interrupt-controller/rda,8810pl-intc.txt F: Documentation/devicetree/bindings/serial/rda,8810pl-uart.txt F: Documentation/devicetree/bindings/timer/rda,8810pl-timer.txt -- cgit From 1dfc462a54386d8467ff427ef900f553e2e470e3 Mon Sep 17 00:00:00 2001 From: Chris Packham Date: Tue, 29 Oct 2019 09:05:55 +1300 Subject: dt-bindings: gpio: brcm: Add bindings for xgs-iproc This GPIO controller is present on a number of Broadcom switch ASICs with integrated SoCs. It is similar to the nsp-gpio and iproc-gpio blocks but different enough to require a separate driver. Signed-off-by: Chris Packham Reviewed-by: Rob Herring Link: https://lore.kernel.org/r/20191028200555.27524-1-chris.packham@alliedtelesis.co.nz Acked-by: Scott Branden Signed-off-by: Linus Walleij --- .../bindings/gpio/brcm,xgs-iproc-gpio.yaml | 70 ++++++++++++++++++++++ 1 file changed, 70 insertions(+) create mode 100644 Documentation/devicetree/bindings/gpio/brcm,xgs-iproc-gpio.yaml diff --git a/Documentation/devicetree/bindings/gpio/brcm,xgs-iproc-gpio.yaml b/Documentation/devicetree/bindings/gpio/brcm,xgs-iproc-gpio.yaml new file mode 100644 index 000000000000..64e279a4bc10 --- /dev/null +++ b/Documentation/devicetree/bindings/gpio/brcm,xgs-iproc-gpio.yaml @@ -0,0 +1,70 @@ +# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/gpio/brcm,xgs-iproc-gpio.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Broadcom XGS iProc GPIO controller + +maintainers: + - Chris Packham + +description: | + This controller is the Chip Common A GPIO present on a number of Broadcom + switch ASICs with integrated SoCs. + +properties: + compatible: + const: brcm,iproc-gpio-cca + + reg: + items: + - description: the I/O address containing the GPIO controller + registers. + - description: the I/O address containing the Chip Common A interrupt + registers. + + gpio-controller: true + + '#gpio-cells': + const: 2 + + ngpios: + minimum: 0 + maximum: 32 + + interrupt-controller: true + + '#interrupt-cells': + const: 2 + + interrupts: + maxItems: 1 + +required: + - compatible + - reg + - "#gpio-cells" + - gpio-controller + +dependencies: + interrupt-controller: [ interrupts ] + +examples: + - | + #include + #include + gpio@18000060 { + compatible = "brcm,iproc-gpio-cca"; + #gpio-cells = <2>; + reg = <0x18000060 0x50>, + <0x18000000 0x50>; + ngpios = <12>; + gpio-controller; + interrupt-controller; + #interrupt-cells = <2>; + interrupts = ; + }; + + +... -- cgit From 6a41b6c5fc20abced88fa0eed42ae5e5cb70b280 Mon Sep 17 00:00:00 2001 From: Chris Packham Date: Fri, 25 Oct 2019 09:27:03 +1300 Subject: gpio: Add xgs-iproc driver This driver supports the Chip Common A GPIO controller present on a number of Broadcom switch ASICs with integrated SoCs. The controller is similar to the pinctrl-nsp-gpio and pinctrl-iproc-gpio blocks but different enough that a separate driver is required. This has been ported from Broadcom's XLDK 5.0.3 retaining only the CCA support (pinctrl-iproc-gpio covers CCB). Signed-off-by: Chris Packham Link: https://lore.kernel.org/r/20191024202703.8017-3-chris.packham@alliedtelesis.co.nz Acked-by: Scott Branden Signed-off-by: Linus Walleij --- drivers/gpio/Kconfig | 9 ++ drivers/gpio/Makefile | 1 + drivers/gpio/gpio-xgs-iproc.c | 321 ++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 331 insertions(+) create mode 100644 drivers/gpio/gpio-xgs-iproc.c diff --git a/drivers/gpio/Kconfig b/drivers/gpio/Kconfig index 8ec1f041c98d..e9516393c971 100644 --- a/drivers/gpio/Kconfig +++ b/drivers/gpio/Kconfig @@ -155,6 +155,15 @@ config GPIO_BCM_KONA help Turn on GPIO support for Broadcom "Kona" chips. +config GPIO_BCM_XGS_IPROC + tristate "BRCM XGS iProc GPIO support" + depends on OF_GPIO && (ARCH_BCM_IPROC || COMPILE_TEST) + select GPIO_GENERIC + select GPIOLIB_IRQCHIP + default ARCH_BCM_IPROC + help + Say yes here to enable GPIO support for Broadcom XGS iProc SoCs. + config GPIO_BRCMSTB tristate "BRCMSTB GPIO support" default y if (ARCH_BRCMSTB || BMIPS_GENERIC) diff --git a/drivers/gpio/Makefile b/drivers/gpio/Makefile index 84e05701f500..34eb8b2b12dd 100644 --- a/drivers/gpio/Makefile +++ b/drivers/gpio/Makefile @@ -35,6 +35,7 @@ obj-$(CONFIG_GPIO_ASPEED) += gpio-aspeed.o obj-$(CONFIG_GPIO_ASPEED_SGPIO) += gpio-aspeed-sgpio.o obj-$(CONFIG_GPIO_ATH79) += gpio-ath79.o obj-$(CONFIG_GPIO_BCM_KONA) += gpio-bcm-kona.o +obj-$(CONFIG_GPIO_BCM_XGS_IPROC) += gpio-xgs-iproc.o obj-$(CONFIG_GPIO_BD70528) += gpio-bd70528.o obj-$(CONFIG_GPIO_BD9571MWV) += gpio-bd9571mwv.o obj-$(CONFIG_GPIO_BRCMSTB) += gpio-brcmstb.o diff --git a/drivers/gpio/gpio-xgs-iproc.c b/drivers/gpio/gpio-xgs-iproc.c new file mode 100644 index 000000000000..a3fdd95cc9e6 --- /dev/null +++ b/drivers/gpio/gpio-xgs-iproc.c @@ -0,0 +1,321 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (C) 2017 Broadcom + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define IPROC_CCA_INT_F_GPIOINT BIT(0) +#define IPROC_CCA_INT_STS 0x20 +#define IPROC_CCA_INT_MASK 0x24 + +#define IPROC_GPIO_CCA_DIN 0x0 +#define IPROC_GPIO_CCA_DOUT 0x4 +#define IPROC_GPIO_CCA_OUT_EN 0x8 +#define IPROC_GPIO_CCA_INT_LEVEL 0x10 +#define IPROC_GPIO_CCA_INT_LEVEL_MASK 0x14 +#define IPROC_GPIO_CCA_INT_EVENT 0x18 +#define IPROC_GPIO_CCA_INT_EVENT_MASK 0x1C +#define IPROC_GPIO_CCA_INT_EDGE 0x24 + +struct iproc_gpio_chip { + struct irq_chip irqchip; + struct gpio_chip gc; + spinlock_t lock; + struct device *dev; + void __iomem *base; + void __iomem *intr; +}; + +static inline struct iproc_gpio_chip * +to_iproc_gpio(struct gpio_chip *gc) +{ + return container_of(gc, struct iproc_gpio_chip, gc); +} + +static void iproc_gpio_irq_ack(struct irq_data *d) +{ + struct gpio_chip *gc = irq_data_get_irq_chip_data(d); + struct iproc_gpio_chip *chip = to_iproc_gpio(gc); + int pin = d->hwirq; + unsigned long flags; + u32 irq = d->irq; + u32 irq_type, event_status = 0; + + spin_lock_irqsave(&chip->lock, flags); + irq_type = irq_get_trigger_type(irq); + if (irq_type & IRQ_TYPE_EDGE_BOTH) { + event_status |= BIT(pin); + writel_relaxed(event_status, + chip->base + IPROC_GPIO_CCA_INT_EVENT); + } + spin_unlock_irqrestore(&chip->lock, flags); +} + +static void iproc_gpio_irq_unmask(struct irq_data *d) +{ + struct gpio_chip *gc = irq_data_get_irq_chip_data(d); + struct iproc_gpio_chip *chip = to_iproc_gpio(gc); + int pin = d->hwirq; + unsigned long flags; + u32 irq = d->irq; + u32 int_mask, irq_type, event_mask; + + spin_lock_irqsave(&chip->lock, flags); + irq_type = irq_get_trigger_type(irq); + event_mask = readl_relaxed(chip->base + IPROC_GPIO_CCA_INT_EVENT_MASK); + int_mask = readl_relaxed(chip->base + IPROC_GPIO_CCA_INT_LEVEL_MASK); + + if (irq_type & IRQ_TYPE_EDGE_BOTH) { + event_mask |= 1 << pin; + writel_relaxed(event_mask, + chip->base + IPROC_GPIO_CCA_INT_EVENT_MASK); + } else { + int_mask |= 1 << pin; + writel_relaxed(int_mask, + chip->base + IPROC_GPIO_CCA_INT_LEVEL_MASK); + } + spin_unlock_irqrestore(&chip->lock, flags); +} + +static void iproc_gpio_irq_mask(struct irq_data *d) +{ + struct gpio_chip *gc = irq_data_get_irq_chip_data(d); + struct iproc_gpio_chip *chip = to_iproc_gpio(gc); + int pin = d->hwirq; + unsigned long flags; + u32 irq = d->irq; + u32 irq_type, int_mask, event_mask; + + spin_lock_irqsave(&chip->lock, flags); + irq_type = irq_get_trigger_type(irq); + event_mask = readl_relaxed(chip->base + IPROC_GPIO_CCA_INT_EVENT_MASK); + int_mask = readl_relaxed(chip->base + IPROC_GPIO_CCA_INT_LEVEL_MASK); + + if (irq_type & IRQ_TYPE_EDGE_BOTH) { + event_mask &= ~BIT(pin); + writel_relaxed(event_mask, + chip->base + IPROC_GPIO_CCA_INT_EVENT_MASK); + } else { + int_mask &= ~BIT(pin); + writel_relaxed(int_mask, + chip->base + IPROC_GPIO_CCA_INT_LEVEL_MASK); + } + spin_unlock_irqrestore(&chip->lock, flags); +} + +static int iproc_gpio_irq_set_type(struct irq_data *d, u32 type) +{ + struct gpio_chip *gc = irq_data_get_irq_chip_data(d); + struct iproc_gpio_chip *chip = to_iproc_gpio(gc); + int pin = d->hwirq; + unsigned long flags; + u32 irq = d->irq; + u32 event_pol, int_pol; + int ret = 0; + + spin_lock_irqsave(&chip->lock, flags); + switch (type & IRQ_TYPE_SENSE_MASK) { + case IRQ_TYPE_EDGE_RISING: + event_pol = readl_relaxed(chip->base + IPROC_GPIO_CCA_INT_EDGE); + event_pol &= ~BIT(pin); + writel_relaxed(event_pol, chip->base + IPROC_GPIO_CCA_INT_EDGE); + break; + case IRQ_TYPE_EDGE_FALLING: + event_pol = readl_relaxed(chip->base + IPROC_GPIO_CCA_INT_EDGE); + event_pol |= BIT(pin); + writel_relaxed(event_pol, chip->base + IPROC_GPIO_CCA_INT_EDGE); + break; + case IRQ_TYPE_LEVEL_HIGH: + int_pol = readl_relaxed(chip->base + IPROC_GPIO_CCA_INT_LEVEL); + int_pol &= ~BIT(pin); + writel_relaxed(int_pol, chip->base + IPROC_GPIO_CCA_INT_LEVEL); + break; + case IRQ_TYPE_LEVEL_LOW: + int_pol = readl_relaxed(chip->base + IPROC_GPIO_CCA_INT_LEVEL); + int_pol |= BIT(pin); + writel_relaxed(int_pol, chip->base + IPROC_GPIO_CCA_INT_LEVEL); + break; + default: + /* should not come here */ + ret = -EINVAL; + goto out_unlock; + } + + if (type & IRQ_TYPE_LEVEL_MASK) + irq_set_handler_locked(irq_get_irq_data(irq), handle_level_irq); + else if (type & IRQ_TYPE_EDGE_BOTH) + irq_set_handler_locked(irq_get_irq_data(irq), handle_edge_irq); + +out_unlock: + spin_unlock_irqrestore(&chip->lock, flags); + + return ret; +} + +static irqreturn_t iproc_gpio_irq_handler(int irq, void *data) +{ + struct gpio_chip *gc = (struct gpio_chip *)data; + struct iproc_gpio_chip *chip = to_iproc_gpio(gc); + int bit; + unsigned long int_bits = 0; + u32 int_status; + + /* go through the entire GPIOs and handle all interrupts */ + int_status = readl_relaxed(chip->intr + IPROC_CCA_INT_STS); + if (int_status & IPROC_CCA_INT_F_GPIOINT) { + u32 event, level; + + /* Get level and edge interrupts */ + event = + readl_relaxed(chip->base + IPROC_GPIO_CCA_INT_EVENT_MASK); + event &= readl_relaxed(chip->base + IPROC_GPIO_CCA_INT_EVENT); + level = readl_relaxed(chip->base + IPROC_GPIO_CCA_DIN); + level ^= readl_relaxed(chip->base + IPROC_GPIO_CCA_INT_LEVEL); + level &= + readl_relaxed(chip->base + IPROC_GPIO_CCA_INT_LEVEL_MASK); + int_bits = level | event; + + for_each_set_bit(bit, &int_bits, gc->ngpio) + generic_handle_irq(irq_linear_revmap(gc->irq.domain, bit)); + } + + return int_bits ? IRQ_HANDLED : IRQ_NONE; +} + +static int iproc_gpio_probe(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + struct device_node *dn = pdev->dev.of_node; + struct iproc_gpio_chip *chip; + u32 num_gpios; + int irq, ret; + + chip = devm_kzalloc(dev, sizeof(*chip), GFP_KERNEL); + if (!chip) + return -ENOMEM; + + chip->dev = dev; + platform_set_drvdata(pdev, chip); + spin_lock_init(&chip->lock); + + chip->base = devm_platform_ioremap_resource(pdev, 0); + if (IS_ERR(chip->base)) + return PTR_ERR(chip->base); + + ret = bgpio_init(&chip->gc, dev, 4, + chip->base + IPROC_GPIO_CCA_DIN, + chip->base + IPROC_GPIO_CCA_DOUT, + NULL, + chip->base + IPROC_GPIO_CCA_OUT_EN, + NULL, + 0); + if (ret) { + dev_err(dev, "unable to init GPIO chip\n"); + return ret; + } + + chip->gc.label = dev_name(dev); + if (of_property_read_u32(dn, "ngpios", &num_gpios)) + chip->gc.ngpio = num_gpios; + + irq = platform_get_irq(pdev, 0); + if (irq > 0) { + struct gpio_irq_chip *girq; + struct irq_chip *irqc; + u32 val; + + irqc = &chip->irqchip; + irqc->name = dev_name(dev); + irqc->irq_ack = iproc_gpio_irq_ack; + irqc->irq_mask = iproc_gpio_irq_mask; + irqc->irq_unmask = iproc_gpio_irq_unmask; + irqc->irq_set_type = iproc_gpio_irq_set_type; + + chip->intr = devm_platform_ioremap_resource(pdev, 1); + if (IS_ERR(chip->intr)) + return PTR_ERR(chip->intr); + + /* Enable GPIO interrupts for CCA GPIO */ + val = readl_relaxed(chip->intr + IPROC_CCA_INT_MASK); + val |= IPROC_CCA_INT_F_GPIOINT; + writel_relaxed(val, chip->intr + IPROC_CCA_INT_MASK); + + /* + * Directly request the irq here instead of passing + * a flow-handler to gpiochip_set_chained_irqchip, + * because the irq is shared. + */ + ret = devm_request_irq(dev, irq, iproc_gpio_irq_handler, + IRQF_SHARED, chip->gc.label, &chip->gc); + if (ret) { + dev_err(dev, "Fail to request IRQ%d: %d\n", irq, ret); + return ret; + } + + girq = &chip->gc.irq; + girq->chip = irqc; + /* This will let us handle the parent IRQ in the driver */ + girq->parent_handler = NULL; + girq->num_parents = 0; + girq->parents = NULL; + girq->default_type = IRQ_TYPE_NONE; + girq->handler = handle_simple_irq; + } + + ret = devm_gpiochip_add_data(dev, &chip->gc, chip); + if (ret) { + dev_err(dev, "unable to add GPIO chip\n"); + return ret; + } + + return 0; +} + +static int __exit iproc_gpio_remove(struct platform_device *pdev) +{ + struct iproc_gpio_chip *chip; + + chip = platform_get_drvdata(pdev); + if (!chip) + return -ENODEV; + + if (chip->intr) { + u32 val; + + val = readl_relaxed(chip->intr + IPROC_CCA_INT_MASK); + val &= ~IPROC_CCA_INT_F_GPIOINT; + writel_relaxed(val, chip->intr + IPROC_CCA_INT_MASK); + } + + return 0; +} + +static const struct of_device_id bcm_iproc_gpio_of_match[] __initconst = { + { .compatible = "brcm,iproc-gpio-cca" }, + {} +}; +MODULE_DEVICE_TABLE(of, bcm_iproc_gpio_of_match); + +static struct platform_driver bcm_iproc_gpio_driver = { + .driver = { + .name = "iproc-xgs-gpio", + .owner = THIS_MODULE, + .of_match_table = bcm_iproc_gpio_of_match, + }, + .probe = iproc_gpio_probe, + .remove = iproc_gpio_remove, +}; + +module_platform_driver(bcm_iproc_gpio_driver); + +MODULE_DESCRIPTION("XGS IPROC GPIO driver"); +MODULE_LICENSE("GPL v2"); -- cgit From 806766af3909258ccab74265e33ce8afd21af952 Mon Sep 17 00:00:00 2001 From: Linus Walleij Date: Sun, 3 Nov 2019 23:38:39 +0100 Subject: Revert "gpio: merrifield: Move hardware initialization to callback" This reverts commit 4c87540940cbc7ddbe9674087919c605fd5c2ef1. This revert is a prerequisite for the later revert of commit 8f86a5b4ad679e4836733b47414226074eee4e4d. Reported-by: Hans de Goede Acked-by: Andy Shevchenko Signed-off-by: Linus Walleij --- drivers/gpio/gpio-merrifield.c | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/drivers/gpio/gpio-merrifield.c b/drivers/gpio/gpio-merrifield.c index 2f1e9da81c1e..9596024c9161 100644 --- a/drivers/gpio/gpio-merrifield.c +++ b/drivers/gpio/gpio-merrifield.c @@ -362,9 +362,8 @@ static void mrfld_irq_handler(struct irq_desc *desc) chained_irq_exit(irqchip, desc); } -static int mrfld_irq_init_hw(struct gpio_chip *chip) +static void mrfld_irq_init_hw(struct mrfld_gpio *priv) { - struct mrfld_gpio *priv = gpiochip_get_data(chip); void __iomem *reg; unsigned int base; @@ -376,8 +375,6 @@ static int mrfld_irq_init_hw(struct gpio_chip *chip) reg = gpio_reg(&priv->chip, base, GFER); writel(0, reg); } - - return 0; } static const char *mrfld_gpio_get_pinctrl_dev_name(struct mrfld_gpio *priv) @@ -450,7 +447,6 @@ static int mrfld_gpio_probe(struct pci_dev *pdev, const struct pci_device_id *id girq = &priv->chip.irq; girq->chip = &mrfld_irqchip; - girq->init_hw = mrfld_irq_init_hw; girq->parent_handler = mrfld_irq_handler; girq->num_parents = 1; girq->parents = devm_kcalloc(&pdev->dev, girq->num_parents, @@ -463,6 +459,8 @@ static int mrfld_gpio_probe(struct pci_dev *pdev, const struct pci_device_id *id girq->default_type = IRQ_TYPE_NONE; girq->handler = handle_bad_irq; + mrfld_irq_init_hw(priv); + pci_set_drvdata(pdev, priv); retval = devm_gpiochip_add_data(&pdev->dev, &priv->chip, priv); if (retval) { -- cgit From 52c75f56703e1c40a2bc3f64a140602112dfa302 Mon Sep 17 00:00:00 2001 From: Linus Walleij Date: Sun, 3 Nov 2019 23:40:48 +0100 Subject: Revert "gpio: merrifield: Restore use of irq_base" This reverts commit 6658f87f219427ee776c498e07c878eb5cad1be2. This revert is a prerequisite for the later revert of commit 8f86a5b4ad679e4836733b47414226074eee4e4d. Reported-by: Hans de Goede Acked-by: Andy Shevchenko Signed-off-by: Linus Walleij --- drivers/gpio/gpio-merrifield.c | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/gpio/gpio-merrifield.c b/drivers/gpio/gpio-merrifield.c index 9596024c9161..4f27ddfe1e2f 100644 --- a/drivers/gpio/gpio-merrifield.c +++ b/drivers/gpio/gpio-merrifield.c @@ -455,7 +455,6 @@ static int mrfld_gpio_probe(struct pci_dev *pdev, const struct pci_device_id *id if (!girq->parents) return -ENOMEM; girq->parents[0] = pdev->irq; - girq->first = irq_base; girq->default_type = IRQ_TYPE_NONE; girq->handler = handle_bad_irq; -- cgit From 1173c3c28abfc3d7b7665db502280ba9322320e6 Mon Sep 17 00:00:00 2001 From: Linus Walleij Date: Sun, 3 Nov 2019 23:41:11 +0100 Subject: Revert "gpio: merrifield: Pass irqchip when adding gpiochip" This reverts commit 8f86a5b4ad679e4836733b47414226074eee4e4d. It has been established that this causes a boot regression on both Baytrail and Cherrytrail SoCs, and we can't have that in the final kernel release, so we need to revert it. Reported-by: Hans de Goede Acked-by: Andy Shevchenko Signed-off-by: Linus Walleij --- drivers/gpio/gpio-merrifield.c | 28 ++++++++++++---------------- 1 file changed, 12 insertions(+), 16 deletions(-) diff --git a/drivers/gpio/gpio-merrifield.c b/drivers/gpio/gpio-merrifield.c index 4f27ddfe1e2f..3302125e5265 100644 --- a/drivers/gpio/gpio-merrifield.c +++ b/drivers/gpio/gpio-merrifield.c @@ -397,7 +397,6 @@ static int mrfld_gpio_probe(struct pci_dev *pdev, const struct pci_device_id *id { const struct mrfld_gpio_pinrange *range; const char *pinctrl_dev_name; - struct gpio_irq_chip *girq; struct mrfld_gpio *priv; u32 gpio_base, irq_base; void __iomem *base; @@ -445,21 +444,6 @@ static int mrfld_gpio_probe(struct pci_dev *pdev, const struct pci_device_id *id raw_spin_lock_init(&priv->lock); - girq = &priv->chip.irq; - girq->chip = &mrfld_irqchip; - girq->parent_handler = mrfld_irq_handler; - girq->num_parents = 1; - girq->parents = devm_kcalloc(&pdev->dev, girq->num_parents, - sizeof(*girq->parents), - GFP_KERNEL); - if (!girq->parents) - return -ENOMEM; - girq->parents[0] = pdev->irq; - girq->default_type = IRQ_TYPE_NONE; - girq->handler = handle_bad_irq; - - mrfld_irq_init_hw(priv); - pci_set_drvdata(pdev, priv); retval = devm_gpiochip_add_data(&pdev->dev, &priv->chip, priv); if (retval) { @@ -481,6 +465,18 @@ static int mrfld_gpio_probe(struct pci_dev *pdev, const struct pci_device_id *id } } + retval = gpiochip_irqchip_add(&priv->chip, &mrfld_irqchip, irq_base, + handle_bad_irq, IRQ_TYPE_NONE); + if (retval) { + dev_err(&pdev->dev, "could not connect irqchip to gpiochip\n"); + return retval; + } + + mrfld_irq_init_hw(priv); + + gpiochip_set_chained_irqchip(&priv->chip, &mrfld_irqchip, pdev->irq, + mrfld_irq_handler); + return 0; } -- cgit From 504369cd6d2ce34c1225063071ac7e0a5a4d5e30 Mon Sep 17 00:00:00 2001 From: Linus Walleij Date: Wed, 30 Oct 2019 13:29:14 +0100 Subject: gpiolib: Switch order of valid mask and hw init The GPIO irqchip needs to initialize the valid mask before initializing the IRQ hardware, because sometimes the latter require the former to be executed first. Cc: Andy Shevchenko Cc: Mika Westerberg Reported-by: Hans de Goede Link: https://lore.kernel.org/r/20191030122914.967-1-linus.walleij@linaro.org Acked-by: Hans de Goede Reviewed-by: Mika Westerberg Reviewed-by: Andy Shevchenko Signed-off-by: Linus Walleij --- drivers/gpio/gpiolib.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/gpio/gpiolib.c b/drivers/gpio/gpiolib.c index 9afbc0612126..e865c889ba8d 100644 --- a/drivers/gpio/gpiolib.c +++ b/drivers/gpio/gpiolib.c @@ -1411,11 +1411,11 @@ int gpiochip_add_data_with_key(struct gpio_chip *chip, void *data, machine_gpiochip_add(chip); - ret = gpiochip_irqchip_init_hw(chip); + ret = gpiochip_irqchip_init_valid_mask(chip); if (ret) goto err_remove_acpi_chip; - ret = gpiochip_irqchip_init_valid_mask(chip); + ret = gpiochip_irqchip_init_hw(chip); if (ret) goto err_remove_acpi_chip; -- cgit From 5d682fa3d8943c19a632ebeaf70e8b9e41c78a5b Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Tue, 5 Nov 2019 12:49:15 +0000 Subject: gpio: xgs-iproc: Fix section mismatch on device tree match table The table of devicetree identifiers is annotated as __initconst indicating that it can be discarded after kernel boot but it is referenced from the driver struct which has no init annotation leading to a linker warning: WARNING: vmlinux.o(.data+0x82d58): Section mismatch in reference from the variable bcm_iproc_gpio_driver to the variable .init.rodata:bcm_iproc_gpio_of_match The variable bcm_iproc_gpio_driver references the variable __initconst bcm_iproc_gpio_of_match Since drivers can be probed after init the lack of annotation on the driver struct is correct so remove the annotation from the match table. Fixes: 6a41b6c5fc20 ("gpio: Add xgs-iproc driver") Signed-off-by: Mark Brown Reviewed-by: Chris Packham Reviewed-by: Yoshihiro Shimoda Tested-by: Yoshihiro Shimoda Signed-off-by: Linus Walleij --- drivers/gpio/gpio-xgs-iproc.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpio/gpio-xgs-iproc.c b/drivers/gpio/gpio-xgs-iproc.c index a3fdd95cc9e6..bb183f584d92 100644 --- a/drivers/gpio/gpio-xgs-iproc.c +++ b/drivers/gpio/gpio-xgs-iproc.c @@ -299,7 +299,7 @@ static int __exit iproc_gpio_remove(struct platform_device *pdev) return 0; } -static const struct of_device_id bcm_iproc_gpio_of_match[] __initconst = { +static const struct of_device_id bcm_iproc_gpio_of_match[] = { { .compatible = "brcm,iproc-gpio-cca" }, {} }; -- cgit From 9208b1e77d6e8e9776f34f46ef4079ecac9c3c25 Mon Sep 17 00:00:00 2001 From: Matti Vaittinen Date: Wed, 6 Nov 2019 10:51:47 +0200 Subject: gpio: Add definition for GPIO direction At least for me it is difficult to remember the meaning of GPIO direction values. Define GPIO_LINE_DIRECTION_IN and GPIO_LINE_DIRECTION_OUT so that occasional GPIO contributors would not need to always check the meaning of hard coded values 1 and 0. Signed-off-by: Matti Vaittinen Signed-off-by: Linus Walleij --- include/linux/gpio/driver.h | 3 +++ 1 file changed, 3 insertions(+) diff --git a/include/linux/gpio/driver.h b/include/linux/gpio/driver.h index 5dd9c982e2cb..cc9ade4552d9 100644 --- a/include/linux/gpio/driver.h +++ b/include/linux/gpio/driver.h @@ -22,6 +22,9 @@ enum gpio_lookup_flags; struct gpio_chip; +#define GPIO_LINE_DIRECTION_IN 1 +#define GPIO_LINE_DIRECTION_OUT 0 + /** * struct gpio_irq_chip - GPIO interrupt controller */ -- cgit From e42615ec233b30dfaf117b108d4cb49455b4df1d Mon Sep 17 00:00:00 2001 From: Matti Vaittinen Date: Wed, 6 Nov 2019 10:54:12 +0200 Subject: gpio: Use new GPIO_LINE_DIRECTION It's hard for occasional GPIO code reader/writer to know if values 0/1 equal to IN or OUT. Use defined GPIO_LINE_DIRECTION_IN and GPIO_LINE_DIRECTION_OUT to help them out. NOTE - for gpio-amd-fch and gpio-bd9571mwv: This commit also changes the return value for direction get to equal 1 for direction INPUT. Prior this commit these drivers might have returned some other positive value but 1 for INPUT. Signed-off-by: Matti Vaittinen Acked-by: Scott Branden Reviewed-by: Grygorii Strashko Reviewed-by: Michal Simek Reviewed-by: Geert Uytterhoeven Acked-by: Andy Shevchenko Acked-by: William Breathitt Gray Acked-by: Kuppuswamy Sathyanarayanan Signed-off-by: Linus Walleij --- drivers/gpio/gpio-104-dio-48e.c | 5 ++++- drivers/gpio/gpio-104-idi-48.c | 2 +- drivers/gpio/gpio-104-idio-16.c | 4 ++-- drivers/gpio/gpio-74xx-mmio.c | 5 ++++- drivers/gpio/gpio-amd-fch.c | 2 +- drivers/gpio/gpio-aspeed.c | 7 +++---- drivers/gpio/gpio-bcm-kona.c | 6 +++--- drivers/gpio/gpio-bd70528.c | 8 +++++--- drivers/gpio/gpio-bd9571mwv.c | 4 +++- drivers/gpio/gpio-dln2.c | 6 +++--- drivers/gpio/gpio-exar.c | 5 ++++- drivers/gpio/gpio-f7188x.c | 5 ++++- drivers/gpio/gpio-gpio-mm.c | 5 ++++- drivers/gpio/gpio-htc-egpio.c | 5 ++++- drivers/gpio/gpio-ich.c | 5 ++++- drivers/gpio/gpio-kempld.c | 5 ++++- drivers/gpio/gpio-lp873x.c | 2 +- drivers/gpio/gpio-lp87565.c | 5 ++++- drivers/gpio/gpio-madera.c | 5 ++++- drivers/gpio/gpio-max3191x.c | 2 +- drivers/gpio/gpio-merrifield.c | 5 ++++- drivers/gpio/gpio-mmio.c | 21 +++++++++++++++------ drivers/gpio/gpio-mockup.c | 11 +++-------- drivers/gpio/gpio-moxtet.c | 4 ++-- drivers/gpio/gpio-mvebu.c | 5 ++++- drivers/gpio/gpio-mxs.c | 5 ++++- drivers/gpio/gpio-omap.c | 6 ++++-- drivers/gpio/gpio-pca953x.c | 5 ++++- drivers/gpio/gpio-pci-idio-16.c | 4 ++-- drivers/gpio/gpio-pcie-idio-24.c | 9 ++++++--- drivers/gpio/gpio-pisosr.c | 2 +- drivers/gpio/gpio-pl061.c | 5 ++++- drivers/gpio/gpio-raspberrypi-exp.c | 5 ++++- drivers/gpio/gpio-rcar.c | 5 ++++- drivers/gpio/gpio-reg.c | 3 ++- drivers/gpio/gpio-sa1100.c | 5 ++++- drivers/gpio/gpio-sama5d2-piobu.c | 7 ++++--- drivers/gpio/gpio-sch.c | 5 ++++- drivers/gpio/gpio-sch311x.c | 5 ++++- drivers/gpio/gpio-siox.c | 4 ++-- drivers/gpio/gpio-stmpe.c | 5 ++++- drivers/gpio/gpio-tc3589x.c | 5 ++++- drivers/gpio/gpio-tegra.c | 5 ++++- drivers/gpio/gpio-tegra186.c | 4 ++-- drivers/gpio/gpio-thunderx.c | 5 ++++- drivers/gpio/gpio-tpic2810.c | 2 +- drivers/gpio/gpio-tps65086.c | 2 +- drivers/gpio/gpio-tps65912.c | 4 ++-- drivers/gpio/gpio-tps68470.c | 6 +++--- drivers/gpio/gpio-tqmx86.c | 5 ++++- drivers/gpio/gpio-ts4900.c | 5 ++++- drivers/gpio/gpio-twl4030.c | 10 +++++----- drivers/gpio/gpio-twl6040.c | 3 +-- drivers/gpio/gpio-uniphier.c | 5 ++++- drivers/gpio/gpio-wcove.c | 7 +++++-- drivers/gpio/gpio-ws16c48.c | 5 ++++- drivers/gpio/gpio-xgene.c | 5 ++++- drivers/gpio/gpio-xra1403.c | 5 ++++- drivers/gpio/gpio-xtensa.c | 4 ++-- drivers/gpio/gpio-zynq.c | 7 +++++-- 60 files changed, 211 insertions(+), 102 deletions(-) diff --git a/drivers/gpio/gpio-104-dio-48e.c b/drivers/gpio/gpio-104-dio-48e.c index a44fa8af5b0d..400c09b905f8 100644 --- a/drivers/gpio/gpio-104-dio-48e.c +++ b/drivers/gpio/gpio-104-dio-48e.c @@ -59,7 +59,10 @@ static int dio48e_gpio_get_direction(struct gpio_chip *chip, unsigned offset) const unsigned port = offset / 8; const unsigned mask = BIT(offset % 8); - return !!(dio48egpio->io_state[port] & mask); + if (dio48egpio->io_state[port] & mask) + return GPIO_LINE_DIRECTION_IN; + + return GPIO_LINE_DIRECTION_OUT; } static int dio48e_gpio_direction_input(struct gpio_chip *chip, unsigned offset) diff --git a/drivers/gpio/gpio-104-idi-48.c b/drivers/gpio/gpio-104-idi-48.c index 79dead61e776..c50329ab493a 100644 --- a/drivers/gpio/gpio-104-idi-48.c +++ b/drivers/gpio/gpio-104-idi-48.c @@ -53,7 +53,7 @@ struct idi_48_gpio { static int idi_48_gpio_get_direction(struct gpio_chip *chip, unsigned offset) { - return 1; + return GPIO_LINE_DIRECTION_IN; } static int idi_48_gpio_direction_input(struct gpio_chip *chip, unsigned offset) diff --git a/drivers/gpio/gpio-104-idio-16.c b/drivers/gpio/gpio-104-idio-16.c index 8d2f51cd9d91..5752d9dab148 100644 --- a/drivers/gpio/gpio-104-idio-16.c +++ b/drivers/gpio/gpio-104-idio-16.c @@ -51,9 +51,9 @@ struct idio_16_gpio { static int idio_16_gpio_get_direction(struct gpio_chip *chip, unsigned offset) { if (offset > 15) - return 1; + return GPIO_LINE_DIRECTION_IN; - return 0; + return GPIO_LINE_DIRECTION_OUT; } static int idio_16_gpio_direction_input(struct gpio_chip *chip, unsigned offset) diff --git a/drivers/gpio/gpio-74xx-mmio.c b/drivers/gpio/gpio-74xx-mmio.c index 83a2286d93f6..173e06758e6c 100644 --- a/drivers/gpio/gpio-74xx-mmio.c +++ b/drivers/gpio/gpio-74xx-mmio.c @@ -77,7 +77,10 @@ static int mmio_74xx_get_direction(struct gpio_chip *gc, unsigned offset) { struct mmio_74xx_gpio_priv *priv = gpiochip_get_data(gc); - return !(priv->flags & MMIO_74XX_DIR_OUT); + if (priv->flags & MMIO_74XX_DIR_OUT) + return GPIO_LINE_DIRECTION_OUT; + + return GPIO_LINE_DIRECTION_IN; } static int mmio_74xx_dir_in(struct gpio_chip *gc, unsigned int gpio) diff --git a/drivers/gpio/gpio-amd-fch.c b/drivers/gpio/gpio-amd-fch.c index 181df1581df5..4e44ba4d7423 100644 --- a/drivers/gpio/gpio-amd-fch.c +++ b/drivers/gpio/gpio-amd-fch.c @@ -92,7 +92,7 @@ static int amd_fch_gpio_get_direction(struct gpio_chip *gc, unsigned int gpio) ret = (readl_relaxed(ptr) & AMD_FCH_GPIO_FLAG_DIRECTION); spin_unlock_irqrestore(&priv->lock, flags); - return ret; + return ret ? GPIO_LINE_DIRECTION_IN : GPIO_LINE_DIRECTION_OUT; } static void amd_fch_gpio_set(struct gpio_chip *gc, diff --git a/drivers/gpio/gpio-aspeed.c b/drivers/gpio/gpio-aspeed.c index 09e53c5f3b0a..f1037b61f763 100644 --- a/drivers/gpio/gpio-aspeed.c +++ b/drivers/gpio/gpio-aspeed.c @@ -487,10 +487,10 @@ static int aspeed_gpio_get_direction(struct gpio_chip *gc, unsigned int offset) u32 val; if (!have_input(gpio, offset)) - return 0; + return GPIO_LINE_DIRECTION_OUT; if (!have_output(gpio, offset)) - return 1; + return GPIO_LINE_DIRECTION_IN; spin_lock_irqsave(&gpio->lock, flags); @@ -498,8 +498,7 @@ static int aspeed_gpio_get_direction(struct gpio_chip *gc, unsigned int offset) spin_unlock_irqrestore(&gpio->lock, flags); - return !val; - + return val ? GPIO_LINE_DIRECTION_OUT : GPIO_LINE_DIRECTION_IN; } static inline int irqd_to_aspeed_gpio_data(struct irq_data *d, diff --git a/drivers/gpio/gpio-bcm-kona.c b/drivers/gpio/gpio-bcm-kona.c index 9fa6d3a967d2..4122683eb1f9 100644 --- a/drivers/gpio/gpio-bcm-kona.c +++ b/drivers/gpio/gpio-bcm-kona.c @@ -127,7 +127,7 @@ static int bcm_kona_gpio_get_dir(struct gpio_chip *chip, unsigned gpio) u32 val; val = readl(reg_base + GPIO_CONTROL(gpio)) & GPIO_GPCTR0_IOTR_MASK; - return !!val; + return val ? GPIO_LINE_DIRECTION_IN : GPIO_LINE_DIRECTION_OUT; } static void bcm_kona_gpio_set(struct gpio_chip *chip, unsigned gpio, int value) @@ -144,7 +144,7 @@ static void bcm_kona_gpio_set(struct gpio_chip *chip, unsigned gpio, int value) raw_spin_lock_irqsave(&kona_gpio->lock, flags); /* this function only applies to output pin */ - if (bcm_kona_gpio_get_dir(chip, gpio) == 1) + if (bcm_kona_gpio_get_dir(chip, gpio) == GPIO_LINE_DIRECTION_IN) goto out; reg_offset = value ? GPIO_OUT_SET(bank_id) : GPIO_OUT_CLEAR(bank_id); @@ -170,7 +170,7 @@ static int bcm_kona_gpio_get(struct gpio_chip *chip, unsigned gpio) reg_base = kona_gpio->reg_base; raw_spin_lock_irqsave(&kona_gpio->lock, flags); - if (bcm_kona_gpio_get_dir(chip, gpio) == 1) + if (bcm_kona_gpio_get_dir(chip, gpio) == GPIO_LINE_DIRECTION_IN) reg_offset = GPIO_IN_STATUS(bank_id); else reg_offset = GPIO_OUT_STATUS(bank_id); diff --git a/drivers/gpio/gpio-bd70528.c b/drivers/gpio/gpio-bd70528.c index 0c1ead12d883..734be6b752d0 100644 --- a/drivers/gpio/gpio-bd70528.c +++ b/drivers/gpio/gpio-bd70528.c @@ -54,8 +54,10 @@ static int bd70528_get_direction(struct gpio_chip *chip, unsigned int offset) dev_err(bdgpio->chip.dev, "Could not read gpio direction\n"); return ret; } + if (val & BD70528_GPIO_OUT_EN_MASK) + return GPIO_LINE_DIRECTION_OUT; - return !(val & BD70528_GPIO_OUT_EN_MASK); + return GPIO_LINE_DIRECTION_IN; } static int bd70528_gpio_set_config(struct gpio_chip *chip, unsigned int offset, @@ -166,9 +168,9 @@ static int bd70528_gpio_get(struct gpio_chip *chip, unsigned int offset) * locking would make no sense. */ ret = bd70528_get_direction(chip, offset); - if (ret == 0) + if (ret == GPIO_LINE_DIRECTION_OUT) ret = bd70528_gpio_get_o(bdgpio, offset); - else if (ret == 1) + else if (ret == GPIO_LINE_DIRECTION_IN) ret = bd70528_gpio_get_i(bdgpio, offset); else dev_err(bdgpio->chip.dev, "failed to read GPIO direction\n"); diff --git a/drivers/gpio/gpio-bd9571mwv.c b/drivers/gpio/gpio-bd9571mwv.c index 5224a946e8ab..c0abc9c6851b 100644 --- a/drivers/gpio/gpio-bd9571mwv.c +++ b/drivers/gpio/gpio-bd9571mwv.c @@ -37,8 +37,10 @@ static int bd9571mwv_gpio_get_direction(struct gpio_chip *chip, ret = regmap_read(gpio->bd->regmap, BD9571MWV_GPIO_DIR, &val); if (ret < 0) return ret; + if (val & BIT(offset)) + return GPIO_LINE_DIRECTION_IN; - return val & BIT(offset); + return GPIO_LINE_DIRECTION_OUT; } static int bd9571mwv_gpio_direction_input(struct gpio_chip *chip, diff --git a/drivers/gpio/gpio-dln2.c b/drivers/gpio/gpio-dln2.c index 8a33c2fc174d..26b40c8b8a12 100644 --- a/drivers/gpio/gpio-dln2.c +++ b/drivers/gpio/gpio-dln2.c @@ -200,9 +200,9 @@ static int dln2_gpio_get_direction(struct gpio_chip *chip, unsigned offset) struct dln2_gpio *dln2 = gpiochip_get_data(chip); if (test_bit(offset, dln2->output_enabled)) - return 0; + return GPIO_LINE_DIRECTION_OUT; - return 1; + return GPIO_LINE_DIRECTION_IN; } static int dln2_gpio_get(struct gpio_chip *chip, unsigned int offset) @@ -214,7 +214,7 @@ static int dln2_gpio_get(struct gpio_chip *chip, unsigned int offset) if (dir < 0) return dir; - if (dir == 1) + if (dir == GPIO_LINE_DIRECTION_IN) return dln2_gpio_pin_get_in_val(dln2, offset); return dln2_gpio_pin_get_out_val(dln2, offset); diff --git a/drivers/gpio/gpio-exar.c b/drivers/gpio/gpio-exar.c index fae327d5b06e..da1ef0b1c291 100644 --- a/drivers/gpio/gpio-exar.c +++ b/drivers/gpio/gpio-exar.c @@ -77,7 +77,10 @@ static int exar_get_direction(struct gpio_chip *chip, unsigned int offset) EXAR_OFFSET_MPIOSEL_HI : EXAR_OFFSET_MPIOSEL_LO; unsigned int bit = (offset + exar_gpio->first_pin) % 8; - return !!(exar_get(chip, addr) & BIT(bit)); + if (exar_get(chip, addr) & BIT(bit)) + return GPIO_LINE_DIRECTION_IN; + + return GPIO_LINE_DIRECTION_OUT; } static int exar_get_value(struct gpio_chip *chip, unsigned int offset) diff --git a/drivers/gpio/gpio-f7188x.c b/drivers/gpio/gpio-f7188x.c index fdc639f856f1..cadd02993539 100644 --- a/drivers/gpio/gpio-f7188x.c +++ b/drivers/gpio/gpio-f7188x.c @@ -250,7 +250,10 @@ static int f7188x_gpio_get_direction(struct gpio_chip *chip, unsigned offset) superio_exit(sio->addr); - return !(dir & 1 << offset); + if (dir & 1 << offset) + return GPIO_LINE_DIRECTION_OUT; + + return GPIO_LINE_DIRECTION_IN; } static int f7188x_gpio_direction_in(struct gpio_chip *chip, unsigned offset) diff --git a/drivers/gpio/gpio-gpio-mm.c b/drivers/gpio/gpio-gpio-mm.c index 78a1db24e931..c22d6f94129c 100644 --- a/drivers/gpio/gpio-gpio-mm.c +++ b/drivers/gpio/gpio-gpio-mm.c @@ -52,7 +52,10 @@ static int gpiomm_gpio_get_direction(struct gpio_chip *chip, const unsigned int port = offset / 8; const unsigned int mask = BIT(offset % 8); - return !!(gpiommgpio->io_state[port] & mask); + if (gpiommgpio->io_state[port] & mask) + return GPIO_LINE_DIRECTION_IN; + + return GPIO_LINE_DIRECTION_OUT; } static int gpiomm_gpio_direction_input(struct gpio_chip *chip, diff --git a/drivers/gpio/gpio-htc-egpio.c b/drivers/gpio/gpio-htc-egpio.c index 8aa23d70b1e6..a40bd56673fe 100644 --- a/drivers/gpio/gpio-htc-egpio.c +++ b/drivers/gpio/gpio-htc-egpio.c @@ -220,7 +220,10 @@ static int egpio_get_direction(struct gpio_chip *chip, unsigned offset) egpio = gpiochip_get_data(chip); - return !test_bit(offset, &egpio->is_out); + if (test_bit(offset, &egpio->is_out)) + return GPIO_LINE_DIRECTION_OUT; + + return GPIO_LINE_DIRECTION_IN; } static void egpio_write_cache(struct egpio_info *ei) diff --git a/drivers/gpio/gpio-ich.c b/drivers/gpio/gpio-ich.c index 90bf7742f9b0..2f086d0aa1f4 100644 --- a/drivers/gpio/gpio-ich.c +++ b/drivers/gpio/gpio-ich.c @@ -159,7 +159,10 @@ static bool ichx_gpio_check_available(struct gpio_chip *gpio, unsigned nr) static int ichx_gpio_get_direction(struct gpio_chip *gpio, unsigned nr) { - return ichx_read_bit(GPIO_IO_SEL, nr); + if (ichx_read_bit(GPIO_IO_SEL, nr)) + return GPIO_LINE_DIRECTION_IN; + + return GPIO_LINE_DIRECTION_OUT; } static int ichx_gpio_direction_input(struct gpio_chip *gpio, unsigned nr) diff --git a/drivers/gpio/gpio-kempld.c b/drivers/gpio/gpio-kempld.c index ef51638f3f75..4ea15f08e0f4 100644 --- a/drivers/gpio/gpio-kempld.c +++ b/drivers/gpio/gpio-kempld.c @@ -104,7 +104,10 @@ static int kempld_gpio_get_direction(struct gpio_chip *chip, unsigned offset) struct kempld_gpio_data *gpio = gpiochip_get_data(chip); struct kempld_device_data *pld = gpio->pld; - return !kempld_gpio_get_bit(pld, KEMPLD_GPIO_DIR_NUM(offset), offset); + if (kempld_gpio_get_bit(pld, KEMPLD_GPIO_DIR_NUM(offset), offset)) + return GPIO_LINE_DIRECTION_OUT; + + return GPIO_LINE_DIRECTION_IN; } static int kempld_gpio_pincount(struct kempld_device_data *pld) diff --git a/drivers/gpio/gpio-lp873x.c b/drivers/gpio/gpio-lp873x.c index 801995dd9b26..70fad87ff2db 100644 --- a/drivers/gpio/gpio-lp873x.c +++ b/drivers/gpio/gpio-lp873x.c @@ -33,7 +33,7 @@ static int lp873x_gpio_get_direction(struct gpio_chip *chip, unsigned int offset) { /* This device is output only */ - return 0; + return GPIO_LINE_DIRECTION_OUT; } static int lp873x_gpio_direction_input(struct gpio_chip *chip, diff --git a/drivers/gpio/gpio-lp87565.c b/drivers/gpio/gpio-lp87565.c index a121c8f10610..e1244520cf7d 100644 --- a/drivers/gpio/gpio-lp87565.c +++ b/drivers/gpio/gpio-lp87565.c @@ -57,7 +57,10 @@ static int lp87565_gpio_get_direction(struct gpio_chip *chip, if (ret < 0) return ret; - return !(val & BIT(offset)); + if (val & BIT(offset)) + return GPIO_LINE_DIRECTION_OUT; + + return GPIO_LINE_DIRECTION_IN; } static int lp87565_gpio_direction_input(struct gpio_chip *chip, diff --git a/drivers/gpio/gpio-madera.c b/drivers/gpio/gpio-madera.c index 7086f8b5388f..8f38303fcbc4 100644 --- a/drivers/gpio/gpio-madera.c +++ b/drivers/gpio/gpio-madera.c @@ -34,7 +34,10 @@ static int madera_gpio_get_direction(struct gpio_chip *chip, if (ret < 0) return ret; - return !!(val & MADERA_GP1_DIR_MASK); + if (val & MADERA_GP1_DIR_MASK) + return GPIO_LINE_DIRECTION_IN; + + return GPIO_LINE_DIRECTION_OUT; } static int madera_gpio_direction_in(struct gpio_chip *chip, unsigned int offset) diff --git a/drivers/gpio/gpio-max3191x.c b/drivers/gpio/gpio-max3191x.c index 4b4b2ceb82fc..0696d5a21431 100644 --- a/drivers/gpio/gpio-max3191x.c +++ b/drivers/gpio/gpio-max3191x.c @@ -94,7 +94,7 @@ DECLARE_CRC8_TABLE(max3191x_crc8); static int max3191x_get_direction(struct gpio_chip *gpio, unsigned int offset) { - return 1; /* always in */ + return GPIO_LINE_DIRECTION_IN; /* always in */ } static int max3191x_direction_input(struct gpio_chip *gpio, unsigned int offset) diff --git a/drivers/gpio/gpio-merrifield.c b/drivers/gpio/gpio-merrifield.c index 2f1e9da81c1e..d4fa6e9560f3 100644 --- a/drivers/gpio/gpio-merrifield.c +++ b/drivers/gpio/gpio-merrifield.c @@ -162,7 +162,10 @@ static int mrfld_gpio_get_direction(struct gpio_chip *chip, unsigned int offset) { void __iomem *gpdr = gpio_reg(chip, offset, GPDR); - return !(readl(gpdr) & BIT(offset % 32)); + if (readl(gpdr) & BIT(offset % 32)) + return GPIO_LINE_DIRECTION_OUT; + + return GPIO_LINE_DIRECTION_IN; } static int mrfld_gpio_set_debounce(struct gpio_chip *chip, unsigned int offset, diff --git a/drivers/gpio/gpio-mmio.c b/drivers/gpio/gpio-mmio.c index 6f904c874678..cd07c948649f 100644 --- a/drivers/gpio/gpio-mmio.c +++ b/drivers/gpio/gpio-mmio.c @@ -370,15 +370,24 @@ static int bgpio_dir_in(struct gpio_chip *gc, unsigned int gpio) static int bgpio_get_dir(struct gpio_chip *gc, unsigned int gpio) { /* Return 0 if output, 1 if input */ - if (gc->bgpio_dir_unreadable) - return !(gc->bgpio_dir & bgpio_line2mask(gc, gpio)); - if (gc->reg_dir_out) - return !(gc->read_reg(gc->reg_dir_out) & bgpio_line2mask(gc, gpio)); + if (gc->bgpio_dir_unreadable) { + if (gc->bgpio_dir & bgpio_line2mask(gc, gpio)) + return GPIO_LINE_DIRECTION_OUT; + return GPIO_LINE_DIRECTION_IN; + } + + if (gc->reg_dir_out) { + if (gc->read_reg(gc->reg_dir_out) & bgpio_line2mask(gc, gpio)) + return GPIO_LINE_DIRECTION_OUT; + return GPIO_LINE_DIRECTION_IN; + } + if (gc->reg_dir_in) - return !!(gc->read_reg(gc->reg_dir_in) & bgpio_line2mask(gc, gpio)); + if (!(gc->read_reg(gc->reg_dir_in) & bgpio_line2mask(gc, gpio))) + return GPIO_LINE_DIRECTION_OUT; /* This should not happen */ - return 1; + return GPIO_LINE_DIRECTION_IN; } static int bgpio_dir_out(struct gpio_chip *gc, unsigned int gpio, int val) diff --git a/drivers/gpio/gpio-mockup.c b/drivers/gpio/gpio-mockup.c index 213aedc97dc2..47c172b2f5ad 100644 --- a/drivers/gpio/gpio-mockup.c +++ b/drivers/gpio/gpio-mockup.c @@ -34,14 +34,9 @@ #define gpio_mockup_err(...) pr_err(GPIO_MOCKUP_NAME ": " __VA_ARGS__) -enum { - GPIO_MOCKUP_DIR_IN = 0, - GPIO_MOCKUP_DIR_OUT = 1, -}; - /* * struct gpio_pin_status - structure describing a GPIO status - * @dir: Configures direction of gpio as "in" or "out", 0=in, 1=out + * @dir: Configures direction of gpio as "in" or "out" * @value: Configures status of the gpio as 0(low) or 1(high) */ struct gpio_mockup_line_status { @@ -152,7 +147,7 @@ static int gpio_mockup_dirout(struct gpio_chip *gc, struct gpio_mockup_chip *chip = gpiochip_get_data(gc); mutex_lock(&chip->lock); - chip->lines[offset].dir = GPIO_MOCKUP_DIR_OUT; + chip->lines[offset].dir = GPIO_LINE_DIRECTION_OUT; __gpio_mockup_set(chip, offset, value); mutex_unlock(&chip->lock); @@ -164,7 +159,7 @@ static int gpio_mockup_dirin(struct gpio_chip *gc, unsigned int offset) struct gpio_mockup_chip *chip = gpiochip_get_data(gc); mutex_lock(&chip->lock); - chip->lines[offset].dir = GPIO_MOCKUP_DIR_IN; + chip->lines[offset].dir = GPIO_LINE_DIRECTION_IN; mutex_unlock(&chip->lock); return 0; diff --git a/drivers/gpio/gpio-moxtet.c b/drivers/gpio/gpio-moxtet.c index 3fd729994a38..8299909318f4 100644 --- a/drivers/gpio/gpio-moxtet.c +++ b/drivers/gpio/gpio-moxtet.c @@ -78,9 +78,9 @@ static int moxtet_gpio_get_direction(struct gpio_chip *gc, unsigned int offset) /* All lines are hard wired to be either input or output, not both. */ if (chip->desc->in_mask & BIT(offset)) - return 1; + return GPIO_LINE_DIRECTION_IN; else if (chip->desc->out_mask & BIT(offset)) - return 0; + return GPIO_LINE_DIRECTION_OUT; else return -EINVAL; } diff --git a/drivers/gpio/gpio-mvebu.c b/drivers/gpio/gpio-mvebu.c index 6c0687694341..9b2adf0ef880 100644 --- a/drivers/gpio/gpio-mvebu.c +++ b/drivers/gpio/gpio-mvebu.c @@ -384,7 +384,10 @@ static int mvebu_gpio_get_direction(struct gpio_chip *chip, unsigned int pin) regmap_read(mvchip->regs, GPIO_IO_CONF_OFF + mvchip->offset, &u); - return !!(u & BIT(pin)); + if (u & BIT(pin)) + return GPIO_LINE_DIRECTION_IN; + + return GPIO_LINE_DIRECTION_OUT; } static int mvebu_gpio_to_irq(struct gpio_chip *chip, unsigned int pin) diff --git a/drivers/gpio/gpio-mxs.c b/drivers/gpio/gpio-mxs.c index 5e5437a2c607..c4a314c68555 100644 --- a/drivers/gpio/gpio-mxs.c +++ b/drivers/gpio/gpio-mxs.c @@ -248,7 +248,10 @@ static int mxs_gpio_get_direction(struct gpio_chip *gc, unsigned offset) u32 dir; dir = readl(port->base + PINCTRL_DOE(port)); - return !(dir & mask); + if (dir & mask) + return GPIO_LINE_DIRECTION_OUT; + + return GPIO_LINE_DIRECTION_IN; } static const struct platform_device_id mxs_gpio_ids[] = { diff --git a/drivers/gpio/gpio-omap.c b/drivers/gpio/gpio-omap.c index d0f27084a942..3bd8adaeed9e 100644 --- a/drivers/gpio/gpio-omap.c +++ b/drivers/gpio/gpio-omap.c @@ -805,8 +805,10 @@ static int omap_gpio_get_direction(struct gpio_chip *chip, unsigned offset) { struct gpio_bank *bank = gpiochip_get_data(chip); - return !!(readl_relaxed(bank->base + bank->regs->direction) & - BIT(offset)); + if (readl_relaxed(bank->base + bank->regs->direction) & BIT(offset)) + return GPIO_LINE_DIRECTION_IN; + + return GPIO_LINE_DIRECTION_OUT; } static int omap_gpio_input(struct gpio_chip *chip, unsigned offset) diff --git a/drivers/gpio/gpio-pca953x.c b/drivers/gpio/gpio-pca953x.c index de5d1383f28d..82122c3c688a 100644 --- a/drivers/gpio/gpio-pca953x.c +++ b/drivers/gpio/gpio-pca953x.c @@ -449,7 +449,10 @@ static int pca953x_gpio_get_direction(struct gpio_chip *gc, unsigned off) if (ret < 0) return ret; - return !!(reg_val & bit); + if (reg_val & bit) + return GPIO_LINE_DIRECTION_IN; + + return GPIO_LINE_DIRECTION_OUT; } static void pca953x_gpio_set_multiple(struct gpio_chip *gc, diff --git a/drivers/gpio/gpio-pci-idio-16.c b/drivers/gpio/gpio-pci-idio-16.c index 5aa136a6a3e0..df51dd08bdfe 100644 --- a/drivers/gpio/gpio-pci-idio-16.c +++ b/drivers/gpio/gpio-pci-idio-16.c @@ -61,9 +61,9 @@ static int idio_16_gpio_get_direction(struct gpio_chip *chip, unsigned int offset) { if (offset > 15) - return 1; + return GPIO_LINE_DIRECTION_IN; - return 0; + return GPIO_LINE_DIRECTION_OUT; } static int idio_16_gpio_direction_input(struct gpio_chip *chip, diff --git a/drivers/gpio/gpio-pcie-idio-24.c b/drivers/gpio/gpio-pcie-idio-24.c index 52f1647a46fd..44c1e4fc489f 100644 --- a/drivers/gpio/gpio-pcie-idio-24.c +++ b/drivers/gpio/gpio-pcie-idio-24.c @@ -104,15 +104,18 @@ static int idio_24_gpio_get_direction(struct gpio_chip *chip, /* FET Outputs */ if (offset < 24) - return 0; + return GPIO_LINE_DIRECTION_OUT; /* Isolated Inputs */ if (offset < 48) - return 1; + return GPIO_LINE_DIRECTION_IN; /* TTL/CMOS I/O */ /* OUT MODE = 1 when TTL/CMOS Output Mode is set */ - return !(ioread8(&idio24gpio->reg->ctl) & out_mode_mask); + if (ioread8(&idio24gpio->reg->ctl) & out_mode_mask) + return GPIO_LINE_DIRECTION_OUT; + + return GPIO_LINE_DIRECTION_IN; } static int idio_24_gpio_direction_input(struct gpio_chip *chip, diff --git a/drivers/gpio/gpio-pisosr.c b/drivers/gpio/gpio-pisosr.c index f809a5a8e9eb..1331b2a94679 100644 --- a/drivers/gpio/gpio-pisosr.c +++ b/drivers/gpio/gpio-pisosr.c @@ -65,7 +65,7 @@ static int pisosr_gpio_get_direction(struct gpio_chip *chip, unsigned offset) { /* This device always input */ - return 1; + return GPIO_LINE_DIRECTION_IN; } static int pisosr_gpio_direction_input(struct gpio_chip *chip, diff --git a/drivers/gpio/gpio-pl061.c b/drivers/gpio/gpio-pl061.c index 722ce5cf861e..5df7782e348f 100644 --- a/drivers/gpio/gpio-pl061.c +++ b/drivers/gpio/gpio-pl061.c @@ -63,7 +63,10 @@ static int pl061_get_direction(struct gpio_chip *gc, unsigned offset) { struct pl061 *pl061 = gpiochip_get_data(gc); - return !(readb(pl061->base + GPIODIR) & BIT(offset)); + if (readb(pl061->base + GPIODIR) & BIT(offset)) + return GPIO_LINE_DIRECTION_OUT; + + return GPIO_LINE_DIRECTION_IN; } static int pl061_direction_input(struct gpio_chip *gc, unsigned offset) diff --git a/drivers/gpio/gpio-raspberrypi-exp.c b/drivers/gpio/gpio-raspberrypi-exp.c index b77ea16ffa03..bb100e0124e6 100644 --- a/drivers/gpio/gpio-raspberrypi-exp.c +++ b/drivers/gpio/gpio-raspberrypi-exp.c @@ -147,7 +147,10 @@ static int rpi_exp_gpio_get_direction(struct gpio_chip *gc, unsigned int off) get.gpio); return ret ? ret : -EIO; } - return !get.direction; + if (get.direction) + return GPIO_LINE_DIRECTION_OUT; + + return GPIO_LINE_DIRECTION_IN; } static int rpi_exp_gpio_get(struct gpio_chip *gc, unsigned int off) diff --git a/drivers/gpio/gpio-rcar.c b/drivers/gpio/gpio-rcar.c index 187984d26f47..d7e6e68c25af 100644 --- a/drivers/gpio/gpio-rcar.c +++ b/drivers/gpio/gpio-rcar.c @@ -279,7 +279,10 @@ static int gpio_rcar_get_direction(struct gpio_chip *chip, unsigned int offset) { struct gpio_rcar_priv *p = gpiochip_get_data(chip); - return !(gpio_rcar_read(p, INOUTSEL) & BIT(offset)); + if (gpio_rcar_read(p, INOUTSEL) & BIT(offset)) + return GPIO_LINE_DIRECTION_OUT; + + return GPIO_LINE_DIRECTION_IN; } static int gpio_rcar_direction_input(struct gpio_chip *chip, unsigned offset) diff --git a/drivers/gpio/gpio-reg.c b/drivers/gpio/gpio-reg.c index fdc7a9d5b382..d35169bde25a 100644 --- a/drivers/gpio/gpio-reg.c +++ b/drivers/gpio/gpio-reg.c @@ -26,7 +26,8 @@ static int gpio_reg_get_direction(struct gpio_chip *gc, unsigned offset) { struct gpio_reg *r = to_gpio_reg(gc); - return r->direction & BIT(offset) ? 1 : 0; + return r->direction & BIT(offset) ? GPIO_LINE_DIRECTION_IN : + GPIO_LINE_DIRECTION_OUT; } static int gpio_reg_direction_output(struct gpio_chip *gc, unsigned offset, diff --git a/drivers/gpio/gpio-sa1100.c b/drivers/gpio/gpio-sa1100.c index 46b7cf23fb0f..edff5e81489f 100644 --- a/drivers/gpio/gpio-sa1100.c +++ b/drivers/gpio/gpio-sa1100.c @@ -53,7 +53,10 @@ static int sa1100_get_direction(struct gpio_chip *chip, unsigned offset) { void __iomem *gpdr = sa1100_gpio_chip(chip)->membase + R_GPDR; - return !(readl_relaxed(gpdr) & BIT(offset)); + if (readl_relaxed(gpdr) & BIT(offset)) + return GPIO_LINE_DIRECTION_OUT; + + return GPIO_LINE_DIRECTION_IN; } static int sa1100_direction_input(struct gpio_chip *chip, unsigned offset) diff --git a/drivers/gpio/gpio-sama5d2-piobu.c b/drivers/gpio/gpio-sama5d2-piobu.c index 7d718557092e..b04c561f3280 100644 --- a/drivers/gpio/gpio-sama5d2-piobu.c +++ b/drivers/gpio/gpio-sama5d2-piobu.c @@ -119,7 +119,8 @@ static int sama5d2_piobu_get_direction(struct gpio_chip *chip, if (ret < 0) return ret; - return (ret == PIOBU_IN) ? 1 : 0; + return (ret == PIOBU_IN) ? GPIO_LINE_DIRECTION_IN : + GPIO_LINE_DIRECTION_OUT; } /** @@ -154,9 +155,9 @@ static int sama5d2_piobu_get(struct gpio_chip *chip, unsigned int pin) /* if pin is input, read value from PDS else read from SOD */ int ret = sama5d2_piobu_get_direction(chip, pin); - if (ret == 1) + if (ret == GPIO_LINE_DIRECTION_IN) ret = sama5d2_piobu_read_value(chip, pin, PIOBU_PDS); - else if (!ret) + else if (ret == GPIO_LINE_DIRECTION_OUT) ret = sama5d2_piobu_read_value(chip, pin, PIOBU_SOD); if (ret < 0) diff --git a/drivers/gpio/gpio-sch.c b/drivers/gpio/gpio-sch.c index fb143f28c386..c65f35b68202 100644 --- a/drivers/gpio/gpio-sch.c +++ b/drivers/gpio/gpio-sch.c @@ -127,7 +127,10 @@ static int sch_gpio_get_direction(struct gpio_chip *gc, unsigned gpio_num) { struct sch_gpio *sch = gpiochip_get_data(gc); - return sch_gpio_reg_get(sch, gpio_num, GIO); + if (sch_gpio_reg_get(sch, gpio_num, GIO)) + return GPIO_LINE_DIRECTION_IN; + + return GPIO_LINE_DIRECTION_OUT; } static const struct gpio_chip sch_gpio_chip = { diff --git a/drivers/gpio/gpio-sch311x.c b/drivers/gpio/gpio-sch311x.c index 8ecf336c9af4..da01e1cad7cb 100644 --- a/drivers/gpio/gpio-sch311x.c +++ b/drivers/gpio/gpio-sch311x.c @@ -228,7 +228,10 @@ static int sch311x_gpio_get_direction(struct gpio_chip *chip, unsigned offset) data = inb(block->runtime_reg + block->config_regs[offset]); spin_unlock(&block->lock); - return !!(data & SCH311X_GPIO_CONF_DIR); + if (data & SCH311X_GPIO_CONF_DIR) + return GPIO_LINE_DIRECTION_IN; + + return GPIO_LINE_DIRECTION_OUT; } static int sch311x_gpio_set_config(struct gpio_chip *chip, unsigned offset, diff --git a/drivers/gpio/gpio-siox.c b/drivers/gpio/gpio-siox.c index 006a7e6a75f2..311f66757b92 100644 --- a/drivers/gpio/gpio-siox.c +++ b/drivers/gpio/gpio-siox.c @@ -203,9 +203,9 @@ static int gpio_siox_direction_output(struct gpio_chip *chip, static int gpio_siox_get_direction(struct gpio_chip *chip, unsigned int offset) { if (offset < 12) - return 1; /* input */ + return GPIO_LINE_DIRECTION_IN; else - return 0; /* output */ + return GPIO_LINE_DIRECTION_OUT; } static int gpio_siox_probe(struct siox_device *sdevice) diff --git a/drivers/gpio/gpio-stmpe.c b/drivers/gpio/gpio-stmpe.c index 994d542daf53..542706a852e6 100644 --- a/drivers/gpio/gpio-stmpe.c +++ b/drivers/gpio/gpio-stmpe.c @@ -84,7 +84,10 @@ static int stmpe_gpio_get_direction(struct gpio_chip *chip, if (ret < 0) return ret; - return !(ret & mask); + if (ret & mask) + return GPIO_LINE_DIRECTION_OUT; + + return GPIO_LINE_DIRECTION_IN; } static int stmpe_gpio_direction_output(struct gpio_chip *chip, diff --git a/drivers/gpio/gpio-tc3589x.c b/drivers/gpio/gpio-tc3589x.c index 75b1135b383a..6be0684cfa49 100644 --- a/drivers/gpio/gpio-tc3589x.c +++ b/drivers/gpio/gpio-tc3589x.c @@ -97,7 +97,10 @@ static int tc3589x_gpio_get_direction(struct gpio_chip *chip, if (ret < 0) return ret; - return !(ret & BIT(pos)); + if (ret & BIT(pos)) + return GPIO_LINE_DIRECTION_OUT; + + return GPIO_LINE_DIRECTION_IN; } static int tc3589x_gpio_set_config(struct gpio_chip *chip, unsigned int offset, diff --git a/drivers/gpio/gpio-tegra.c b/drivers/gpio/gpio-tegra.c index 8a01d3694b28..6fdfe4c5303e 100644 --- a/drivers/gpio/gpio-tegra.c +++ b/drivers/gpio/gpio-tegra.c @@ -215,7 +215,10 @@ static int tegra_gpio_get_direction(struct gpio_chip *chip, oe = tegra_gpio_readl(tgi, GPIO_OE(tgi, offset)); - return !(oe & pin_mask); + if (oe & pin_mask) + return GPIO_LINE_DIRECTION_OUT; + + return GPIO_LINE_DIRECTION_IN; } static int tegra_gpio_set_debounce(struct gpio_chip *chip, unsigned int offset, diff --git a/drivers/gpio/gpio-tegra186.c b/drivers/gpio/gpio-tegra186.c index 8a2a69178925..57185b96c110 100644 --- a/drivers/gpio/gpio-tegra186.c +++ b/drivers/gpio/gpio-tegra186.c @@ -111,9 +111,9 @@ static int tegra186_gpio_get_direction(struct gpio_chip *chip, value = readl(base + TEGRA186_GPIO_ENABLE_CONFIG); if (value & TEGRA186_GPIO_ENABLE_CONFIG_OUT) - return 0; + return GPIO_LINE_DIRECTION_OUT; - return 1; + return GPIO_LINE_DIRECTION_IN; } static int tegra186_gpio_direction_input(struct gpio_chip *chip, diff --git a/drivers/gpio/gpio-thunderx.c b/drivers/gpio/gpio-thunderx.c index ddad5c7ea617..d08d86a22b1f 100644 --- a/drivers/gpio/gpio-thunderx.c +++ b/drivers/gpio/gpio-thunderx.c @@ -169,7 +169,10 @@ static int thunderx_gpio_get_direction(struct gpio_chip *chip, unsigned int line bit_cfg = readq(txgpio->register_base + bit_cfg_reg(line)); - return !(bit_cfg & GPIO_BIT_CFG_TX_OE); + if (bit_cfg & GPIO_BIT_CFG_TX_OE) + return GPIO_LINE_DIRECTION_OUT; + + return GPIO_LINE_DIRECTION_IN; } static int thunderx_gpio_set_config(struct gpio_chip *chip, diff --git a/drivers/gpio/gpio-tpic2810.c b/drivers/gpio/gpio-tpic2810.c index c8b34d787eed..99d5a84a9129 100644 --- a/drivers/gpio/gpio-tpic2810.c +++ b/drivers/gpio/gpio-tpic2810.c @@ -39,7 +39,7 @@ static int tpic2810_get_direction(struct gpio_chip *chip, unsigned offset) { /* This device always output */ - return 0; + return GPIO_LINE_DIRECTION_OUT; } static int tpic2810_direction_input(struct gpio_chip *chip, diff --git a/drivers/gpio/gpio-tps65086.c b/drivers/gpio/gpio-tps65086.c index 2eea98ff4ea3..1e9d8262d0ff 100644 --- a/drivers/gpio/gpio-tps65086.c +++ b/drivers/gpio/gpio-tps65086.c @@ -21,7 +21,7 @@ static int tps65086_gpio_get_direction(struct gpio_chip *chip, unsigned offset) { /* This device is output only */ - return 0; + return GPIO_LINE_DIRECTION_OUT; } static int tps65086_gpio_direction_input(struct gpio_chip *chip, diff --git a/drivers/gpio/gpio-tps65912.c b/drivers/gpio/gpio-tps65912.c index 3ad68bd78282..510d9ed9fd2a 100644 --- a/drivers/gpio/gpio-tps65912.c +++ b/drivers/gpio/gpio-tps65912.c @@ -32,9 +32,9 @@ static int tps65912_gpio_get_direction(struct gpio_chip *gc, return ret; if (val & GPIO_CFG_MASK) - return 0; + return GPIO_LINE_DIRECTION_OUT; else - return 1; + return GPIO_LINE_DIRECTION_IN; } static int tps65912_gpio_direction_input(struct gpio_chip *gc, unsigned offset) diff --git a/drivers/gpio/gpio-tps68470.c b/drivers/gpio/gpio-tps68470.c index aff6e504c666..f7f5f770e0fb 100644 --- a/drivers/gpio/gpio-tps68470.c +++ b/drivers/gpio/gpio-tps68470.c @@ -47,7 +47,6 @@ static int tps68470_gpio_get(struct gpio_chip *gc, unsigned int offset) return !!(val & BIT(offset)); } -/* Return 0 if output, 1 if input */ static int tps68470_gpio_get_direction(struct gpio_chip *gc, unsigned int offset) { @@ -57,7 +56,7 @@ static int tps68470_gpio_get_direction(struct gpio_chip *gc, /* rest are always outputs */ if (offset >= TPS68470_N_REGULAR_GPIO) - return 0; + return GPIO_LINE_DIRECTION_OUT; ret = regmap_read(regmap, TPS68470_GPIO_CTL_REG_A(offset), &val); if (ret) { @@ -67,7 +66,8 @@ static int tps68470_gpio_get_direction(struct gpio_chip *gc, } val &= TPS68470_GPIO_MODE_MASK; - return val >= TPS68470_GPIO_MODE_OUT_CMOS ? 0 : 1; + return val >= TPS68470_GPIO_MODE_OUT_CMOS ? GPIO_LINE_DIRECTION_OUT : + GPIO_LINE_DIRECTION_IN; } static void tps68470_gpio_set(struct gpio_chip *gc, unsigned int offset, diff --git a/drivers/gpio/gpio-tqmx86.c b/drivers/gpio/gpio-tqmx86.c index a3109bcaa0ac..5022e0ad0fae 100644 --- a/drivers/gpio/gpio-tqmx86.c +++ b/drivers/gpio/gpio-tqmx86.c @@ -101,7 +101,10 @@ static int tqmx86_gpio_direction_output(struct gpio_chip *chip, static int tqmx86_gpio_get_direction(struct gpio_chip *chip, unsigned int offset) { - return !!(TQMX86_DIR_INPUT_MASK & BIT(offset)); + if (TQMX86_DIR_INPUT_MASK & BIT(offset)) + return GPIO_LINE_DIRECTION_IN; + + return GPIO_LINE_DIRECTION_OUT; } static void tqmx86_gpio_irq_mask(struct irq_data *data) diff --git a/drivers/gpio/gpio-ts4900.c b/drivers/gpio/gpio-ts4900.c index 1da8d0586329..d885032cf814 100644 --- a/drivers/gpio/gpio-ts4900.c +++ b/drivers/gpio/gpio-ts4900.c @@ -44,7 +44,10 @@ static int ts4900_gpio_get_direction(struct gpio_chip *chip, regmap_read(priv->regmap, offset, ®); - return !(reg & TS4900_GPIO_OE); + if (reg & TS4900_GPIO_OE) + return GPIO_LINE_DIRECTION_OUT; + + return GPIO_LINE_DIRECTION_IN; } static int ts4900_gpio_direction_input(struct gpio_chip *chip, diff --git a/drivers/gpio/gpio-twl4030.c b/drivers/gpio/gpio-twl4030.c index fbfb648d3502..de249726230e 100644 --- a/drivers/gpio/gpio-twl4030.c +++ b/drivers/gpio/gpio-twl4030.c @@ -165,10 +165,10 @@ static int twl4030_get_gpio_direction(int gpio) if (ret < 0) return ret; - /* 1 = output, but gpiolib semantics are inverse so invert */ - ret = !(ret & d_msk); + if (ret & d_msk) + return GPIO_LINE_DIRECTION_OUT; - return ret; + return GPIO_LINE_DIRECTION_IN; } static int twl4030_set_gpio_dataout(int gpio, int enable) @@ -380,10 +380,10 @@ static int twl_get_direction(struct gpio_chip *chip, unsigned offset) { struct gpio_twl4030_priv *priv = gpiochip_get_data(chip); /* - * Default 0 = output + * Default GPIO_LINE_DIRECTION_OUT * LED GPIOs >= TWL4030_GPIO_MAX are always output */ - int ret = 0; + int ret = GPIO_LINE_DIRECTION_OUT; mutex_lock(&priv->mutex); if (offset < TWL4030_GPIO_MAX) { diff --git a/drivers/gpio/gpio-twl6040.c b/drivers/gpio/gpio-twl6040.c index c845b2ff1f43..648fb418d775 100644 --- a/drivers/gpio/gpio-twl6040.c +++ b/drivers/gpio/gpio-twl6040.c @@ -34,8 +34,7 @@ static int twl6040gpo_get(struct gpio_chip *chip, unsigned offset) static int twl6040gpo_get_direction(struct gpio_chip *chip, unsigned offset) { - /* This means "out" */ - return 0; + return GPIO_LINE_DIRECTION_OUT; } static int twl6040gpo_direction_out(struct gpio_chip *chip, unsigned offset, diff --git a/drivers/gpio/gpio-uniphier.c b/drivers/gpio/gpio-uniphier.c index 93cdcc41e9fb..bd203e8fa58e 100644 --- a/drivers/gpio/gpio-uniphier.c +++ b/drivers/gpio/gpio-uniphier.c @@ -113,7 +113,10 @@ static int uniphier_gpio_offset_read(struct gpio_chip *chip, static int uniphier_gpio_get_direction(struct gpio_chip *chip, unsigned int offset) { - return uniphier_gpio_offset_read(chip, offset, UNIPHIER_GPIO_PORT_DIR); + if (uniphier_gpio_offset_read(chip, offset, UNIPHIER_GPIO_PORT_DIR)) + return GPIO_LINE_DIRECTION_IN; + + return GPIO_LINE_DIRECTION_OUT; } static int uniphier_gpio_direction_input(struct gpio_chip *chip, diff --git a/drivers/gpio/gpio-wcove.c b/drivers/gpio/gpio-wcove.c index 444fe9e7f04a..8b481b3c1ebe 100644 --- a/drivers/gpio/gpio-wcove.c +++ b/drivers/gpio/gpio-wcove.c @@ -170,13 +170,16 @@ static int wcove_gpio_get_direction(struct gpio_chip *chip, unsigned int gpio) int ret, reg = to_reg(gpio, CTRL_OUT); if (reg < 0) - return 0; + return GPIO_LINE_DIRECTION_OUT; ret = regmap_read(wg->regmap, reg, &val); if (ret) return ret; - return !(val & CTLO_DIR_OUT); + if (val & CTLO_DIR_OUT) + return GPIO_LINE_DIRECTION_OUT; + + return GPIO_LINE_DIRECTION_IN; } static int wcove_gpio_get(struct gpio_chip *chip, unsigned int gpio) diff --git a/drivers/gpio/gpio-ws16c48.c b/drivers/gpio/gpio-ws16c48.c index e0ef66b6a237..fe456bea81f6 100644 --- a/drivers/gpio/gpio-ws16c48.c +++ b/drivers/gpio/gpio-ws16c48.c @@ -56,7 +56,10 @@ static int ws16c48_gpio_get_direction(struct gpio_chip *chip, unsigned offset) const unsigned port = offset / 8; const unsigned mask = BIT(offset % 8); - return !!(ws16c48gpio->io_state[port] & mask); + if (ws16c48gpio->io_state[port] & mask) + return GPIO_LINE_DIRECTION_IN; + + return GPIO_LINE_DIRECTION_OUT; } static int ws16c48_gpio_direction_input(struct gpio_chip *chip, unsigned offset) diff --git a/drivers/gpio/gpio-xgene.c b/drivers/gpio/gpio-xgene.c index a6e66ac18e1f..532b0df8a1f2 100644 --- a/drivers/gpio/gpio-xgene.c +++ b/drivers/gpio/gpio-xgene.c @@ -80,7 +80,10 @@ static int xgene_gpio_get_direction(struct gpio_chip *gc, unsigned int offset) bank_offset = GPIO_SET_DR_OFFSET + GPIO_BANK_OFFSET(offset); bit_offset = GPIO_BIT_OFFSET(offset); - return !!(ioread32(chip->base + bank_offset) & BIT(bit_offset)); + if (ioread32(chip->base + bank_offset) & BIT(bit_offset)) + return GPIO_LINE_DIRECTION_IN; + + return GPIO_LINE_DIRECTION_OUT; } static int xgene_gpio_dir_in(struct gpio_chip *gc, unsigned int offset) diff --git a/drivers/gpio/gpio-xra1403.c b/drivers/gpio/gpio-xra1403.c index 05f1998c11a4..31b5072b2df0 100644 --- a/drivers/gpio/gpio-xra1403.c +++ b/drivers/gpio/gpio-xra1403.c @@ -83,7 +83,10 @@ static int xra1403_get_direction(struct gpio_chip *chip, unsigned int offset) if (ret) return ret; - return !!(val & BIT(offset % 8)); + if (val & BIT(offset % 8)) + return GPIO_LINE_DIRECTION_IN; + + return GPIO_LINE_DIRECTION_OUT; } static int xra1403_get(struct gpio_chip *chip, unsigned int offset) diff --git a/drivers/gpio/gpio-xtensa.c b/drivers/gpio/gpio-xtensa.c index 43d3fa5f511a..08d7c3b32038 100644 --- a/drivers/gpio/gpio-xtensa.c +++ b/drivers/gpio/gpio-xtensa.c @@ -72,7 +72,7 @@ static inline void disable_cp(unsigned long flags, unsigned long cpenable) static int xtensa_impwire_get_direction(struct gpio_chip *gc, unsigned offset) { - return 1; /* input only */ + return GPIO_LINE_DIRECTION_IN; /* input only */ } static int xtensa_impwire_get_value(struct gpio_chip *gc, unsigned offset) @@ -95,7 +95,7 @@ static void xtensa_impwire_set_value(struct gpio_chip *gc, unsigned offset, static int xtensa_expstate_get_direction(struct gpio_chip *gc, unsigned offset) { - return 0; /* output only */ + return GPIO_LINE_DIRECTION_OUT; /* output only */ } static int xtensa_expstate_get_value(struct gpio_chip *gc, unsigned offset) diff --git a/drivers/gpio/gpio-zynq.c b/drivers/gpio/gpio-zynq.c index cd475ff4bcad..4c3f6370eab4 100644 --- a/drivers/gpio/gpio-zynq.c +++ b/drivers/gpio/gpio-zynq.c @@ -360,7 +360,7 @@ static int zynq_gpio_dir_out(struct gpio_chip *chip, unsigned int pin, * * This function returns the direction of the specified GPIO. * - * Return: 0 for output, 1 for input + * Return: GPIO_LINE_DIRECTION_OUT or GPIO_LINE_DIRECTION_IN */ static int zynq_gpio_get_direction(struct gpio_chip *chip, unsigned int pin) { @@ -372,7 +372,10 @@ static int zynq_gpio_get_direction(struct gpio_chip *chip, unsigned int pin) reg = readl_relaxed(gpio->base_addr + ZYNQ_GPIO_DIRM_OFFSET(bank_num)); - return !(reg & BIT(bank_pin_num)); + if (reg & BIT(bank_pin_num)) + return GPIO_LINE_DIRECTION_OUT; + + return GPIO_LINE_DIRECTION_IN; } /** -- cgit From 2f4133bb5f14f49a99acf0cc55b84996dbfb4dff Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Tue, 5 Nov 2019 20:06:54 +0200 Subject: gpiolib: No need to call gpiochip_remove_pin_ranges() twice of_gpiochip_add(), when fails, calls gpiochip_remove_pin_ranges(). ADD: gpiochip_add_data_with_key() -> of_gpiochip_add() -> (ERROR path) gpiochip_remove_pin_ranges() At the same time of_gpiochip_remove() calls exactly the above mentioned function unconditionally and so does gpiochip_remove(). REMOVE: gpiochip_remove() -> gpiochip_remove_pin_ranges() of_gpiochip_remove() -> gpiochip_remove_pin_ranges() Since gpiochip_remove() calls gpiochip_remove_pin_ranges() unconditionally, we have duplicate call to the same function when it's not necessary. Move gpiochip_remove_pin_ranges() from of_gpiochip_add() to gpiochip_add() to avoid duplicate calls and be consistent with the explicit call in gpiochip_remove(). Fixes: e93fa3f24353 ("gpiolib: remove duplicate pin range code") Depends-on: f7299d441a4d ("gpio: of: Fix of_gpiochip_add() error path") Cc: Geert Uytterhoeven Signed-off-by: Andy Shevchenko Signed-off-by: Linus Walleij --- drivers/gpio/gpiolib-of.c | 5 +---- drivers/gpio/gpiolib.c | 3 ++- 2 files changed, 3 insertions(+), 5 deletions(-) diff --git a/drivers/gpio/gpiolib-of.c b/drivers/gpio/gpiolib-of.c index 0380a1d6b660..bd06743a5d7c 100644 --- a/drivers/gpio/gpiolib-of.c +++ b/drivers/gpio/gpiolib-of.c @@ -885,16 +885,13 @@ int of_gpiochip_add(struct gpio_chip *chip) of_node_get(chip->of_node); ret = of_gpiochip_scan_gpios(chip); - if (ret) { + if (ret) of_node_put(chip->of_node); - gpiochip_remove_pin_ranges(chip); - } return ret; } void of_gpiochip_remove(struct gpio_chip *chip) { - gpiochip_remove_pin_ranges(chip); of_node_put(chip->of_node); } diff --git a/drivers/gpio/gpiolib.c b/drivers/gpio/gpiolib.c index e865c889ba8d..618d71f0540b 100644 --- a/drivers/gpio/gpiolib.c +++ b/drivers/gpio/gpiolib.c @@ -1448,6 +1448,7 @@ err_remove_of_chip: gpiochip_free_hogs(chip); of_gpiochip_remove(chip); err_free_gpiochip_mask: + gpiochip_remove_pin_ranges(chip); gpiochip_free_valid_mask(chip); err_remove_from_list: spin_lock_irqsave(&gpio_lock, flags); @@ -1503,8 +1504,8 @@ void gpiochip_remove(struct gpio_chip *chip) gdev->chip = NULL; gpiochip_irqchip_remove(chip); acpi_gpiochip_remove(chip); - gpiochip_remove_pin_ranges(chip); of_gpiochip_remove(chip); + gpiochip_remove_pin_ranges(chip); gpiochip_free_valid_mask(chip); /* * We accept no more calls into the driver from this point, so -- cgit From 70d97e099bb426ecb3ad4bf31e88dbf2ef4b2e4c Mon Sep 17 00:00:00 2001 From: Linus Walleij Date: Fri, 8 Nov 2019 13:37:54 +0100 Subject: Revert "gpio: expose pull-up/pull-down line flags to userspace" This reverts commit 8c550e94b8835170593169a45b5ba30d3fc72a70. This was prematurely applied and we need to back it out to merge a better version of the development track for this feature. Signed-off-by: Linus Walleij --- drivers/gpio/gpiolib.c | 12 ------------ include/uapi/linux/gpio.h | 4 ---- 2 files changed, 16 deletions(-) diff --git a/drivers/gpio/gpiolib.c b/drivers/gpio/gpiolib.c index 618d71f0540b..731d732cdc2b 100644 --- a/drivers/gpio/gpiolib.c +++ b/drivers/gpio/gpiolib.c @@ -422,8 +422,6 @@ struct linehandle_state { (GPIOHANDLE_REQUEST_INPUT | \ GPIOHANDLE_REQUEST_OUTPUT | \ GPIOHANDLE_REQUEST_ACTIVE_LOW | \ - GPIOHANDLE_REQUEST_PULL_UP | \ - GPIOHANDLE_REQUEST_PULL_DOWN | \ GPIOHANDLE_REQUEST_OPEN_DRAIN | \ GPIOHANDLE_REQUEST_OPEN_SOURCE) @@ -595,10 +593,6 @@ static int linehandle_create(struct gpio_device *gdev, void __user *ip) set_bit(FLAG_OPEN_DRAIN, &desc->flags); if (lflags & GPIOHANDLE_REQUEST_OPEN_SOURCE) set_bit(FLAG_OPEN_SOURCE, &desc->flags); - if (lflags & GPIOHANDLE_REQUEST_PULL_DOWN) - set_bit(FLAG_PULL_DOWN, &desc->flags); - if (lflags & GPIOHANDLE_REQUEST_PULL_UP) - set_bit(FLAG_PULL_UP, &desc->flags); ret = gpiod_set_transitory(desc, false); if (ret < 0) @@ -1098,10 +1092,6 @@ static long gpio_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) if (test_bit(FLAG_OPEN_SOURCE, &desc->flags)) lineinfo.flags |= (GPIOLINE_FLAG_OPEN_SOURCE | GPIOLINE_FLAG_IS_OUT); - if (test_bit(FLAG_PULL_DOWN, &desc->flags)) - lineinfo.flags |= GPIOLINE_FLAG_PULL_DOWN; - if (test_bit(FLAG_PULL_UP, &desc->flags)) - lineinfo.flags |= GPIOLINE_FLAG_PULL_UP; if (copy_to_user(ip, &lineinfo, sizeof(lineinfo))) return -EFAULT; @@ -2795,8 +2785,6 @@ static bool gpiod_free_commit(struct gpio_desc *desc) clear_bit(FLAG_REQUESTED, &desc->flags); clear_bit(FLAG_OPEN_DRAIN, &desc->flags); clear_bit(FLAG_OPEN_SOURCE, &desc->flags); - clear_bit(FLAG_PULL_UP, &desc->flags); - clear_bit(FLAG_PULL_DOWN, &desc->flags); clear_bit(FLAG_IS_HOGGED, &desc->flags); ret = true; } diff --git a/include/uapi/linux/gpio.h b/include/uapi/linux/gpio.h index c2d1f7d908d6..4ebfe0ac6c5b 100644 --- a/include/uapi/linux/gpio.h +++ b/include/uapi/linux/gpio.h @@ -33,8 +33,6 @@ struct gpiochip_info { #define GPIOLINE_FLAG_ACTIVE_LOW (1UL << 2) #define GPIOLINE_FLAG_OPEN_DRAIN (1UL << 3) #define GPIOLINE_FLAG_OPEN_SOURCE (1UL << 4) -#define GPIOLINE_FLAG_PULL_UP (1UL << 5) -#define GPIOLINE_FLAG_PULL_DOWN (1UL << 6) /** * struct gpioline_info - Information about a certain GPIO line @@ -64,8 +62,6 @@ struct gpioline_info { #define GPIOHANDLE_REQUEST_ACTIVE_LOW (1UL << 2) #define GPIOHANDLE_REQUEST_OPEN_DRAIN (1UL << 3) #define GPIOHANDLE_REQUEST_OPEN_SOURCE (1UL << 4) -#define GPIOHANDLE_REQUEST_PULL_UP (1UL << 5) -#define GPIOHANDLE_REQUEST_PULL_DOWN (1UL << 6) /** * struct gpiohandle_request - Information about a GPIO handle request -- cgit