From 0d82fb1127fb7cc8287614eb0992acb0583bc323 Mon Sep 17 00:00:00 2001 From: Sander Vanheule Date: Tue, 30 Mar 2021 19:48:43 +0200 Subject: gpio: Add Realtek Otto GPIO support Realtek MIPS SoCs (platform name Otto) have GPIO controllers with up to 64 GPIOs, divided over two banks. Each bank has a set of registers for 32 GPIOs, with support for edge-triggered interrupts. Each GPIO bank consists of four 8-bit GPIO ports (ABCD and EFGH). Most registers pack one bit per GPIO, except for the IMR register, which packs two bits per GPIO (AB-CD). Although the byte order is currently assumed to have port A..D at offset 0x0..0x3, this has been observed to be reversed on other, Lexra-based, SoCs (e.g. RTL8196E/97D/97F). Interrupt support is disabled for the fallback devicetree-compatible 'realtek,otto-gpio'. This allows for quick support of GPIO banks in which the byte order would be unknown. In this case, the port ordering in the IMR registers may not match the reversed order in the other registers (DCBA, and BA-DC or DC-BA). Signed-off-by: Sander Vanheule Reviewed-by: Linus Walleij Reviewed-by: Andy Shevchenko Signed-off-by: Bartosz Golaszewski --- drivers/gpio/Kconfig | 13 +++++++++++++ 1 file changed, 13 insertions(+) (limited to 'drivers/gpio/Kconfig') diff --git a/drivers/gpio/Kconfig b/drivers/gpio/Kconfig index e3607ec4c2e8..6fb13d6507db 100644 --- a/drivers/gpio/Kconfig +++ b/drivers/gpio/Kconfig @@ -502,6 +502,19 @@ config GPIO_RDA help Say Y here to support RDA Micro GPIO controller. +config GPIO_REALTEK_OTTO + tristate "Realtek Otto GPIO support" + depends on MACH_REALTEK_RTL + default MACH_REALTEK_RTL + select GPIO_GENERIC + select GPIOLIB_IRQCHIP + help + The GPIO controller on the Otto MIPS platform supports up to two + banks of 32 GPIOs, with edge triggered interrupts. The 32 GPIOs + are grouped in four 8-bit wide ports. + + When built as a module, the module will be called realtek_otto_gpio. + config GPIO_REG bool help -- cgit v1.2.3-59-g8ed1b From 7a81638485c1a62a87b4c391ecc9c651a4a9dc19 Mon Sep 17 00:00:00 2001 From: Jan Kiszka Date: Wed, 17 Mar 2021 17:19:27 +0200 Subject: gpio: sch: Add edge event support Add the required infrastructure to enable and report edge events of the pins to the GPIO core. The actual hook-up of the event interrupt will happen separately. Signed-off-by: Jan Kiszka Co-developed-by: Andy Shevchenko Signed-off-by: Andy Shevchenko Reviewed-by: Linus Walleij --- drivers/gpio/Kconfig | 1 + drivers/gpio/gpio-sch.c | 116 ++++++++++++++++++++++++++++++++++++++++++++---- 2 files changed, 109 insertions(+), 8 deletions(-) (limited to 'drivers/gpio/Kconfig') diff --git a/drivers/gpio/Kconfig b/drivers/gpio/Kconfig index 6fb13d6507db..ad1a325be727 100644 --- a/drivers/gpio/Kconfig +++ b/drivers/gpio/Kconfig @@ -861,6 +861,7 @@ config GPIO_IT87 config GPIO_SCH tristate "Intel SCH/TunnelCreek/Centerton/Quark X1000 GPIO" depends on (X86 || COMPILE_TEST) && PCI + select GPIOLIB_IRQCHIP select MFD_CORE select LPC_SCH help diff --git a/drivers/gpio/gpio-sch.c b/drivers/gpio/gpio-sch.c index 3a1b1adb08c6..06ab55d134b9 100644 --- a/drivers/gpio/gpio-sch.c +++ b/drivers/gpio/gpio-sch.c @@ -10,17 +10,28 @@ #include #include #include +#include #include #include #include #include +#include #define GEN 0x00 #define GIO 0x04 #define GLV 0x08 +#define GTPE 0x0c +#define GTNE 0x10 +#define GGPE 0x14 +#define GSMI 0x18 +#define GTS 0x1c + +#define CORE_BANK_OFFSET 0x00 +#define RESUME_BANK_OFFSET 0x20 struct sch_gpio { struct gpio_chip chip; + struct irq_chip irqchip; spinlock_t lock; unsigned short iobase; unsigned short resume_base; @@ -29,11 +40,11 @@ struct sch_gpio { static unsigned int sch_gpio_offset(struct sch_gpio *sch, unsigned int gpio, unsigned int reg) { - unsigned int base = 0; + unsigned int base = CORE_BANK_OFFSET; if (gpio >= sch->resume_base) { gpio -= sch->resume_base; - base += 0x20; + base = RESUME_BANK_OFFSET; } return base + reg + gpio / 8; @@ -79,10 +90,11 @@ static void sch_gpio_reg_set(struct sch_gpio *sch, unsigned int gpio, unsigned i static int sch_gpio_direction_in(struct gpio_chip *gc, unsigned int gpio_num) { struct sch_gpio *sch = gpiochip_get_data(gc); + unsigned long flags; - spin_lock(&sch->lock); + spin_lock_irqsave(&sch->lock, flags); sch_gpio_reg_set(sch, gpio_num, GIO, 1); - spin_unlock(&sch->lock); + spin_unlock_irqrestore(&sch->lock, flags); return 0; } @@ -96,20 +108,22 @@ static int sch_gpio_get(struct gpio_chip *gc, unsigned int gpio_num) static void sch_gpio_set(struct gpio_chip *gc, unsigned int gpio_num, int val) { struct sch_gpio *sch = gpiochip_get_data(gc); + unsigned long flags; - spin_lock(&sch->lock); + spin_lock_irqsave(&sch->lock, flags); sch_gpio_reg_set(sch, gpio_num, GLV, val); - spin_unlock(&sch->lock); + spin_unlock_irqrestore(&sch->lock, flags); } static int sch_gpio_direction_out(struct gpio_chip *gc, unsigned int gpio_num, int val) { struct sch_gpio *sch = gpiochip_get_data(gc); + unsigned long flags; - spin_lock(&sch->lock); + spin_lock_irqsave(&sch->lock, flags); sch_gpio_reg_set(sch, gpio_num, GIO, 0); - spin_unlock(&sch->lock); + spin_unlock_irqrestore(&sch->lock, flags); /* * according to the datasheet, writing to the level register has no @@ -144,8 +158,80 @@ static const struct gpio_chip sch_gpio_chip = { .get_direction = sch_gpio_get_direction, }; +static int sch_irq_type(struct irq_data *d, unsigned int type) +{ + struct gpio_chip *gc = irq_data_get_irq_chip_data(d); + struct sch_gpio *sch = gpiochip_get_data(gc); + irq_hw_number_t gpio_num = irqd_to_hwirq(d); + unsigned long flags; + int rising, falling; + + switch (type & IRQ_TYPE_SENSE_MASK) { + case IRQ_TYPE_EDGE_RISING: + rising = 1; + falling = 0; + break; + case IRQ_TYPE_EDGE_FALLING: + rising = 0; + falling = 1; + break; + case IRQ_TYPE_EDGE_BOTH: + rising = 1; + falling = 1; + break; + default: + return -EINVAL; + } + + spin_lock_irqsave(&sch->lock, flags); + + sch_gpio_reg_set(sch, gpio_num, GTPE, rising); + sch_gpio_reg_set(sch, gpio_num, GTNE, falling); + + irq_set_handler_locked(d, handle_edge_irq); + + spin_unlock_irqrestore(&sch->lock, flags); + + return 0; +} + +static void sch_irq_ack(struct irq_data *d) +{ + struct gpio_chip *gc = irq_data_get_irq_chip_data(d); + struct sch_gpio *sch = gpiochip_get_data(gc); + irq_hw_number_t gpio_num = irqd_to_hwirq(d); + unsigned long flags; + + spin_lock_irqsave(&sch->lock, flags); + sch_gpio_reg_set(sch, gpio_num, GTS, 1); + spin_unlock_irqrestore(&sch->lock, flags); +} + +static void sch_irq_mask_unmask(struct irq_data *d, int val) +{ + struct gpio_chip *gc = irq_data_get_irq_chip_data(d); + struct sch_gpio *sch = gpiochip_get_data(gc); + irq_hw_number_t gpio_num = irqd_to_hwirq(d); + unsigned long flags; + + spin_lock_irqsave(&sch->lock, flags); + sch_gpio_reg_set(sch, gpio_num, GGPE, val); + spin_unlock_irqrestore(&sch->lock, flags); +} + +static void sch_irq_mask(struct irq_data *d) +{ + sch_irq_mask_unmask(d, 0); +} + +static void sch_irq_unmask(struct irq_data *d) +{ + sch_irq_mask_unmask(d, 1); +} + static int sch_gpio_probe(struct platform_device *pdev) { + struct gpio_irq_chip *girq; struct sch_gpio *sch; struct resource *res; @@ -207,6 +293,20 @@ static int sch_gpio_probe(struct platform_device *pdev) platform_set_drvdata(pdev, sch); + sch->irqchip.name = "sch_gpio"; + sch->irqchip.irq_ack = sch_irq_ack; + sch->irqchip.irq_mask = sch_irq_mask; + sch->irqchip.irq_unmask = sch_irq_unmask; + sch->irqchip.irq_set_type = sch_irq_type; + + girq = &sch->chip.irq; + girq->chip = &sch->irqchip; + girq->num_parents = 0; + girq->parents = NULL; + girq->parent_handler = NULL; + girq->default_type = IRQ_TYPE_NONE; + girq->handler = handle_bad_irq; + return devm_gpiochip_add_data(&pdev->dev, &sch->chip, sch); } -- cgit v1.2.3-59-g8ed1b From fdc1f5dfb9aa890473d6f94bd224d45cf2f0443d Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Wed, 17 Mar 2021 17:19:28 +0200 Subject: gpio: sch: Hook into ACPI GPE handler to catch GPIO edge events Neither the ACPI description on Intel Minnowboard (v1) platform provides the required information to establish a generic handling nor the hardware capable of doing it. According to the data sheet the hardware can generate SCI events. Therefore, we need to hook from the driver into GPE handler of the ACPI subsystem in order to catch and report GPIO-related events. Validated on the Inlel Minnowboard (v1) platform and Intel Galileo Gen 2. Signed-off-by: Andy Shevchenko Reviewed-by: Linus Walleij --- drivers/gpio/Kconfig | 2 +- drivers/gpio/gpio-sch.c | 82 +++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 83 insertions(+), 1 deletion(-) (limited to 'drivers/gpio/Kconfig') diff --git a/drivers/gpio/Kconfig b/drivers/gpio/Kconfig index ad1a325be727..3a56a6370b6c 100644 --- a/drivers/gpio/Kconfig +++ b/drivers/gpio/Kconfig @@ -860,7 +860,7 @@ config GPIO_IT87 config GPIO_SCH tristate "Intel SCH/TunnelCreek/Centerton/Quark X1000 GPIO" - depends on (X86 || COMPILE_TEST) && PCI + depends on (X86 || COMPILE_TEST) && ACPI select GPIOLIB_IRQCHIP select MFD_CORE select LPC_SCH diff --git a/drivers/gpio/gpio-sch.c b/drivers/gpio/gpio-sch.c index 06ab55d134b9..a6f0421d6e50 100644 --- a/drivers/gpio/gpio-sch.c +++ b/drivers/gpio/gpio-sch.c @@ -7,6 +7,7 @@ */ #include +#include #include #include #include @@ -29,12 +30,22 @@ #define CORE_BANK_OFFSET 0x00 #define RESUME_BANK_OFFSET 0x20 +/* + * iLB datasheet describes GPE0BLK registers, in particular GPE0E.GPIO bit. + * Document Number: 328195-001 + */ +#define GPE0E_GPIO 14 + struct sch_gpio { struct gpio_chip chip; struct irq_chip irqchip; spinlock_t lock; unsigned short iobase; unsigned short resume_base; + + /* GPE handling */ + u32 gpe; + acpi_gpe_handler gpe_handler; }; static unsigned int sch_gpio_offset(struct sch_gpio *sch, unsigned int gpio, @@ -229,11 +240,74 @@ static void sch_irq_unmask(struct irq_data *d) sch_irq_mask_unmask(d, 1); } +static u32 sch_gpio_gpe_handler(acpi_handle gpe_device, u32 gpe, void *context) +{ + struct sch_gpio *sch = context; + struct gpio_chip *gc = &sch->chip; + unsigned long core_status, resume_status; + unsigned long pending; + unsigned long flags; + int offset; + u32 ret; + + spin_lock_irqsave(&sch->lock, flags); + + core_status = inl(sch->iobase + CORE_BANK_OFFSET + GTS); + resume_status = inl(sch->iobase + RESUME_BANK_OFFSET + GTS); + + spin_unlock_irqrestore(&sch->lock, flags); + + pending = (resume_status << sch->resume_base) | core_status; + for_each_set_bit(offset, &pending, sch->chip.ngpio) + generic_handle_irq(irq_find_mapping(gc->irq.domain, offset)); + + /* Set returning value depending on whether we handled an interrupt */ + ret = pending ? ACPI_INTERRUPT_HANDLED : ACPI_INTERRUPT_NOT_HANDLED; + + /* Acknowledge GPE to ACPICA */ + ret |= ACPI_REENABLE_GPE; + + return ret; +} + +static void sch_gpio_remove_gpe_handler(void *data) +{ + struct sch_gpio *sch = data; + + acpi_disable_gpe(NULL, sch->gpe); + acpi_remove_gpe_handler(NULL, sch->gpe, sch->gpe_handler); +} + +static int sch_gpio_install_gpe_handler(struct sch_gpio *sch) +{ + struct device *dev = sch->chip.parent; + acpi_status status; + + status = acpi_install_gpe_handler(NULL, sch->gpe, ACPI_GPE_LEVEL_TRIGGERED, + sch->gpe_handler, sch); + if (ACPI_FAILURE(status)) { + dev_err(dev, "Failed to install GPE handler for %u: %s\n", + sch->gpe, acpi_format_exception(status)); + return -ENODEV; + } + + status = acpi_enable_gpe(NULL, sch->gpe); + if (ACPI_FAILURE(status)) { + dev_err(dev, "Failed to enable GPE handler for %u: %s\n", + sch->gpe, acpi_format_exception(status)); + acpi_remove_gpe_handler(NULL, sch->gpe, sch->gpe_handler); + return -ENODEV; + } + + return devm_add_action_or_reset(dev, sch_gpio_remove_gpe_handler, sch); +} + static int sch_gpio_probe(struct platform_device *pdev) { struct gpio_irq_chip *girq; struct sch_gpio *sch; struct resource *res; + int ret; sch = devm_kzalloc(&pdev->dev, sizeof(*sch), GFP_KERNEL); if (!sch) @@ -307,6 +381,14 @@ static int sch_gpio_probe(struct platform_device *pdev) girq->default_type = IRQ_TYPE_NONE; girq->handler = handle_bad_irq; + /* GPE setup is optional */ + sch->gpe = GPE0E_GPIO; + sch->gpe_handler = sch_gpio_gpe_handler; + + ret = sch_gpio_install_gpe_handler(sch); + if (ret) + dev_warn(&pdev->dev, "Can't setup GPE, no IRQ support\n"); + return devm_gpiochip_add_data(&pdev->dev, &sch->chip, sch); } -- cgit v1.2.3-59-g8ed1b From 71cf76d451ef40ff700320069fe58ae239f6f5aa Mon Sep 17 00:00:00 2001 From: Randy Dunlap Date: Fri, 2 Apr 2021 09:17:51 -0700 Subject: gpio: sch: depends on LPC_SCH MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Since LPC_SCH provides GPIO functionality, GPIO_SCH should depend on LPC_SCH to prevent kconfig warning and build errors: WARNING: unmet direct dependencies detected for LPC_SCH Depends on [n]: HAS_IOMEM [=y] && PCI [=n] Selected by [y]: - GPIO_SCH [=y] && GPIOLIB [=y] && X86 [=y] && (X86 [=y] || COMPILE_TEST [=n]) && ACPI [=y] and ../drivers/mfd/lpc_sch.c:204:1: warning: data definition has no type or storage class module_pci_driver(lpc_sch_driver); ^~~~~~~~~~~~~~~~~ ../drivers/mfd/lpc_sch.c:204:1: error: type defaults to ‘int’ in declaration of ‘module_pci_driver’ [-Werror=implicit-int] ../drivers/mfd/lpc_sch.c:204:1: warning: parameter names (without types) in function declaration ../drivers/mfd/lpc_sch.c:197:26: warning: ‘lpc_sch_driver’ defined but not used [-Wunused-variable] static struct pci_driver lpc_sch_driver = { ^~~~~~~~~~~~~~ Fixes: 6c46215d6b62 ("gpio: sch: Hook into ACPI GPE handler to catch GPIO edge events") Signed-off-by: Randy Dunlap Cc: Linus Walleij Cc: linux-gpio@vger.kernel.org Cc: Bartosz Golaszewski Cc: Denis Turischev Signed-off-by: Andy Shevchenko --- drivers/gpio/Kconfig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/gpio/Kconfig') diff --git a/drivers/gpio/Kconfig b/drivers/gpio/Kconfig index 3a56a6370b6c..b9df2f0c05ba 100644 --- a/drivers/gpio/Kconfig +++ b/drivers/gpio/Kconfig @@ -861,9 +861,9 @@ config GPIO_IT87 config GPIO_SCH tristate "Intel SCH/TunnelCreek/Centerton/Quark X1000 GPIO" depends on (X86 || COMPILE_TEST) && ACPI + depends on LPC_SCH select GPIOLIB_IRQCHIP select MFD_CORE - select LPC_SCH help Say yes here to support GPIO interface on Intel Poulsbo SCH, Intel Tunnel Creek processor, Intel Centerton processor or -- cgit v1.2.3-59-g8ed1b From c6b4853fa25a7f0549731c141e6b2b3f29a6b473 Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Fri, 2 Apr 2021 21:21:03 +0300 Subject: gpio: sch: Drop MFD_CORE selection Since we are depended on LPC_SCH, which selects MFD_CORE, we don't need to do it ourselves. Signed-off-by: Andy Shevchenko --- drivers/gpio/Kconfig | 1 - 1 file changed, 1 deletion(-) (limited to 'drivers/gpio/Kconfig') diff --git a/drivers/gpio/Kconfig b/drivers/gpio/Kconfig index b9df2f0c05ba..39a4b8207b48 100644 --- a/drivers/gpio/Kconfig +++ b/drivers/gpio/Kconfig @@ -863,7 +863,6 @@ config GPIO_SCH depends on (X86 || COMPILE_TEST) && ACPI depends on LPC_SCH select GPIOLIB_IRQCHIP - select MFD_CORE help Say yes here to support GPIO interface on Intel Poulsbo SCH, Intel Tunnel Creek processor, Intel Centerton processor or -- cgit v1.2.3-59-g8ed1b From ba134d29e9526aa8396da355e69f55e8f9badd6d Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Fri, 2 Apr 2021 21:42:25 +0300 Subject: gpio: ich: Switch to be dependent on LPC_ICH Driver is neither dependent to PCI nor using MFD_CORE. Replace those dependency and selection by dependency on LPC_ICH. Signed-off-by: Andy Shevchenko --- drivers/gpio/Kconfig | 5 ++--- drivers/gpio/gpio-ich.c | 2 -- 2 files changed, 2 insertions(+), 5 deletions(-) (limited to 'drivers/gpio/Kconfig') diff --git a/drivers/gpio/Kconfig b/drivers/gpio/Kconfig index 39a4b8207b48..3456b418127a 100644 --- a/drivers/gpio/Kconfig +++ b/drivers/gpio/Kconfig @@ -321,9 +321,8 @@ config GPIO_HLWD config GPIO_ICH tristate "Intel ICH GPIO" - depends on PCI && X86 - select MFD_CORE - select LPC_ICH + depends on X86 + depends on LPC_ICH help Say yes here to support the GPIO functionality of a number of Intel ICH-based chipsets. Currently supported devices: ICH6, ICH7, ICH8 diff --git a/drivers/gpio/gpio-ich.c b/drivers/gpio/gpio-ich.c index de56c013a658..3b31f5e9bf40 100644 --- a/drivers/gpio/gpio-ich.c +++ b/drivers/gpio/gpio-ich.c @@ -5,13 +5,11 @@ * Copyright (C) 2010 Extreme Engineering Solutions. */ - #include #include #include #include #include -#include #include #define DRV_NAME "gpio_ich" -- cgit v1.2.3-59-g8ed1b