diff options
author | Linus Walleij <linus.walleij@linaro.org> | 2020-01-23 15:44:29 +0100 |
---|---|---|
committer | Linus Walleij <linus.walleij@linaro.org> | 2020-01-23 15:44:29 +0100 |
commit | a1dd4bfb145e88bdc8374a506409f95916bae368 (patch) | |
tree | 703909c8ece9e6016fa55067abae2af6a5decca4 /drivers/gpio | |
parent | 783e998653b430a159f83552fa263f57bf8e2055 (diff) | |
parent | cd0a32371db73d0b50536a7ca4f036abddff0d1d (diff) |
Merge tag 'intel-pinctrl-v5.6-1' of git://git.kernel.org/pub/scm/linux/kernel/git/pinctrl/intel into devel
intel-pinctrl for v5.6-1
* Tiger Lake appears to have _HID enumeration, thus driver has been updated
* Coffee Lake-S has the same IP as Sunrisepoint, thus ID has been added
* Baytrail has got more clean ups and bug fixes, such as direct IRQ handling
* Lynxpoint GPIO has been converted to true pin control driver
* The common driver now uses IRQ chip enumeration via GPIO chip
The following is an automated git shortlog grouped by driver:
baytrail:
- Replace WARN with dev_info_once when setting direct-irq pin to output
- Do not clear IRQ flags on direct-irq enabled pins
- Reuse struct intel_pinctrl in the driver
- Use local variable to keep device pointer
- Keep pointer to struct device instead of its container
- Use GPIO direction definitions
- Move IRQ valid mask initialization to a dedicated callback
- Group GPIO IRQ chip initialization
- Allocate IRQ chip dynamic
cherryview:
- Use GPIO direction definitions
intel:
- Pass irqchip when adding gpiochip
- Add GPIO <-> pin mapping ranges via callback
- Share struct intel_pinctrl for wider use
- Use GPIO direction definitions
lynxpoint:
- Update summary in the driver
- Switch to pin control API
- Add GPIO <-> pin mapping ranges via callback
- Implement ->pin_dbg_show()
- Add pin control operations
- Reuse struct intel_pinctrl in the driver
- Add pin control data structures
- Implement intel_gpio_get_direction callback
- Implement ->irq_ack() callback
- Move ownership check to IRQ chip
- Move lp_irq_type() closer to IRQ related routines
- Move ->remove closer to ->probe()
- Extract lp_gpio_acpi_use() for future use
- Convert unsigned to unsigned int
- Switch to memory mapped IO accessors
- Keep pointer to struct device instead of its container
- Relax GPIO request rules
- Assume 2 bits for mode selector
- Use standard pattern for memory allocation
- Use %pR to print IO resource
- Drop useless assignment
- Correct amount of pins
- Use raw_spinlock for locking
- Move GPIO driver to pin controller folder
sunrisepoint:
- Add Coffee Lake-S ACPI ID
- Add missing Interrupt Status register offset
tigerlake:
- Tiger Lake uses _HID enumeration
Diffstat (limited to 'drivers/gpio')
-rw-r--r-- | drivers/gpio/Kconfig | 8 | ||||
-rw-r--r-- | drivers/gpio/Makefile | 1 | ||||
-rw-r--r-- | drivers/gpio/gpio-lynxpoint.c | 471 |
3 files changed, 0 insertions, 480 deletions
diff --git a/drivers/gpio/Kconfig b/drivers/gpio/Kconfig index 8adffd42f8cb..6923142fd874 100644 --- a/drivers/gpio/Kconfig +++ b/drivers/gpio/Kconfig @@ -335,14 +335,6 @@ config GPIO_LPC32XX Select this option to enable GPIO driver for NXP LPC32XX devices. -config GPIO_LYNXPOINT - tristate "Intel Lynxpoint GPIO support" - depends on ACPI && X86 - select GPIOLIB_IRQCHIP - help - driver for GPIO functionality on Intel Lynxpoint PCH chipset - Requires ACPI device enumeration code to set up a platform device. - config GPIO_MB86S7X tristate "GPIO support for Fujitsu MB86S7x Platforms" help diff --git a/drivers/gpio/Makefile b/drivers/gpio/Makefile index 34eb8b2b12dd..55b2b645391e 100644 --- a/drivers/gpio/Makefile +++ b/drivers/gpio/Makefile @@ -76,7 +76,6 @@ obj-$(CONFIG_GPIO_LP873X) += gpio-lp873x.o obj-$(CONFIG_GPIO_LP87565) += gpio-lp87565.o obj-$(CONFIG_GPIO_LPC18XX) += gpio-lpc18xx.o obj-$(CONFIG_GPIO_LPC32XX) += gpio-lpc32xx.o -obj-$(CONFIG_GPIO_LYNXPOINT) += gpio-lynxpoint.o obj-$(CONFIG_GPIO_MADERA) += gpio-madera.o obj-$(CONFIG_GPIO_MAX3191X) += gpio-max3191x.o obj-$(CONFIG_GPIO_MAX7300) += gpio-max7300.o diff --git a/drivers/gpio/gpio-lynxpoint.c b/drivers/gpio/gpio-lynxpoint.c deleted file mode 100644 index 490ce7bae25e..000000000000 --- a/drivers/gpio/gpio-lynxpoint.c +++ /dev/null @@ -1,471 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 -/* - * GPIO controller driver for Intel Lynxpoint PCH chipset> - * Copyright (c) 2012, Intel Corporation. - * - * Author: Mathias Nyman <mathias.nyman@linux.intel.com> - */ - -#include <linux/acpi.h> -#include <linux/bitops.h> -#include <linux/gpio/driver.h> -#include <linux/interrupt.h> -#include <linux/io.h> -#include <linux/kernel.h> -#include <linux/module.h> -#include <linux/platform_device.h> -#include <linux/pm_runtime.h> -#include <linux/slab.h> -#include <linux/types.h> - -/* LynxPoint chipset has support for 94 gpio pins */ - -#define LP_NUM_GPIO 94 - -/* Bitmapped register offsets */ -#define LP_ACPI_OWNED 0x00 /* Bitmap, set by bios, 0: pin reserved for ACPI */ -#define LP_GC 0x7C /* set APIC IRQ to IRQ14 or IRQ15 for all pins */ -#define LP_INT_STAT 0x80 -#define LP_INT_ENABLE 0x90 - -/* Each pin has two 32 bit config registers, starting at 0x100 */ -#define LP_CONFIG1 0x100 -#define LP_CONFIG2 0x104 - -/* LP_CONFIG1 reg bits */ -#define OUT_LVL_BIT BIT(31) -#define IN_LVL_BIT BIT(30) -#define TRIG_SEL_BIT BIT(4) /* 0: Edge, 1: Level */ -#define INT_INV_BIT BIT(3) /* Invert interrupt triggering */ -#define DIR_BIT BIT(2) /* 0: Output, 1: Input */ -#define USE_SEL_BIT BIT(0) /* 0: Native, 1: GPIO */ - -/* LP_CONFIG2 reg bits */ -#define GPINDIS_BIT BIT(2) /* disable input sensing */ -#define GPIWP_BIT (BIT(0) | BIT(1)) /* weak pull options */ - -struct lp_gpio { - struct gpio_chip chip; - struct platform_device *pdev; - spinlock_t lock; - unsigned long reg_base; -}; - -/* - * Lynxpoint gpios are controlled through both bitmapped registers and - * per gpio specific registers. The bitmapped registers are in chunks of - * 3 x 32bit registers to cover all 94 gpios - * - * per gpio specific registers consist of two 32bit registers per gpio - * (LP_CONFIG1 and LP_CONFIG2), with 94 gpios there's a total of - * 188 config registers. - * - * A simplified view of the register layout look like this: - * - * LP_ACPI_OWNED[31:0] gpio ownerships for gpios 0-31 (bitmapped registers) - * LP_ACPI_OWNED[63:32] gpio ownerships for gpios 32-63 - * LP_ACPI_OWNED[94:64] gpio ownerships for gpios 63-94 - * ... - * LP_INT_ENABLE[31:0] ... - * LP_INT_ENABLE[63:31] ... - * LP_INT_ENABLE[94:64] ... - * LP0_CONFIG1 (gpio 0) config1 reg for gpio 0 (per gpio registers) - * LP0_CONFIG2 (gpio 0) config2 reg for gpio 0 - * LP1_CONFIG1 (gpio 1) config1 reg for gpio 1 - * LP1_CONFIG2 (gpio 1) config2 reg for gpio 1 - * LP2_CONFIG1 (gpio 2) ... - * LP2_CONFIG2 (gpio 2) ... - * ... - * LP94_CONFIG1 (gpio 94) ... - * LP94_CONFIG2 (gpio 94) ... - */ - -static unsigned long lp_gpio_reg(struct gpio_chip *chip, unsigned offset, - int reg) -{ - struct lp_gpio *lg = gpiochip_get_data(chip); - int reg_offset; - - if (reg == LP_CONFIG1 || reg == LP_CONFIG2) - /* per gpio specific config registers */ - reg_offset = offset * 8; - else - /* bitmapped registers */ - reg_offset = (offset / 32) * 4; - - return lg->reg_base + reg + reg_offset; -} - -static int lp_gpio_request(struct gpio_chip *chip, unsigned offset) -{ - struct lp_gpio *lg = gpiochip_get_data(chip); - unsigned long reg = lp_gpio_reg(chip, offset, LP_CONFIG1); - unsigned long conf2 = lp_gpio_reg(chip, offset, LP_CONFIG2); - unsigned long acpi_use = lp_gpio_reg(chip, offset, LP_ACPI_OWNED); - - pm_runtime_get(&lg->pdev->dev); /* should we put if failed */ - - /* Fail if BIOS reserved pin for ACPI use */ - if (!(inl(acpi_use) & BIT(offset % 32))) { - dev_err(&lg->pdev->dev, "gpio %d reserved for ACPI\n", offset); - return -EBUSY; - } - /* Fail if pin is in alternate function mode (not GPIO mode) */ - if (!(inl(reg) & USE_SEL_BIT)) - return -ENODEV; - - /* enable input sensing */ - outl(inl(conf2) & ~GPINDIS_BIT, conf2); - - - return 0; -} - -static void lp_gpio_free(struct gpio_chip *chip, unsigned offset) -{ - struct lp_gpio *lg = gpiochip_get_data(chip); - unsigned long conf2 = lp_gpio_reg(chip, offset, LP_CONFIG2); - - /* disable input sensing */ - outl(inl(conf2) | GPINDIS_BIT, conf2); - - pm_runtime_put(&lg->pdev->dev); -} - -static int lp_irq_type(struct irq_data *d, unsigned type) -{ - struct gpio_chip *gc = irq_data_get_irq_chip_data(d); - struct lp_gpio *lg = gpiochip_get_data(gc); - u32 hwirq = irqd_to_hwirq(d); - unsigned long flags; - u32 value; - unsigned long reg = lp_gpio_reg(&lg->chip, hwirq, LP_CONFIG1); - - if (hwirq >= lg->chip.ngpio) - return -EINVAL; - - spin_lock_irqsave(&lg->lock, flags); - value = inl(reg); - - /* set both TRIG_SEL and INV bits to 0 for rising edge */ - if (type & IRQ_TYPE_EDGE_RISING) - value &= ~(TRIG_SEL_BIT | INT_INV_BIT); - - /* TRIG_SEL bit 0, INV bit 1 for falling edge */ - if (type & IRQ_TYPE_EDGE_FALLING) - value = (value | INT_INV_BIT) & ~TRIG_SEL_BIT; - - /* TRIG_SEL bit 1, INV bit 0 for level low */ - if (type & IRQ_TYPE_LEVEL_LOW) - value = (value | TRIG_SEL_BIT) & ~INT_INV_BIT; - - /* TRIG_SEL bit 1, INV bit 1 for level high */ - if (type & IRQ_TYPE_LEVEL_HIGH) - value |= TRIG_SEL_BIT | INT_INV_BIT; - - outl(value, reg); - - if (type & IRQ_TYPE_EDGE_BOTH) - irq_set_handler_locked(d, handle_edge_irq); - else if (type & IRQ_TYPE_LEVEL_MASK) - irq_set_handler_locked(d, handle_level_irq); - - spin_unlock_irqrestore(&lg->lock, flags); - - return 0; -} - -static int lp_gpio_get(struct gpio_chip *chip, unsigned offset) -{ - unsigned long reg = lp_gpio_reg(chip, offset, LP_CONFIG1); - return !!(inl(reg) & IN_LVL_BIT); -} - -static void lp_gpio_set(struct gpio_chip *chip, unsigned offset, int value) -{ - struct lp_gpio *lg = gpiochip_get_data(chip); - unsigned long reg = lp_gpio_reg(chip, offset, LP_CONFIG1); - unsigned long flags; - - spin_lock_irqsave(&lg->lock, flags); - - if (value) - outl(inl(reg) | OUT_LVL_BIT, reg); - else - outl(inl(reg) & ~OUT_LVL_BIT, reg); - - spin_unlock_irqrestore(&lg->lock, flags); -} - -static int lp_gpio_direction_input(struct gpio_chip *chip, unsigned offset) -{ - struct lp_gpio *lg = gpiochip_get_data(chip); - unsigned long reg = lp_gpio_reg(chip, offset, LP_CONFIG1); - unsigned long flags; - - spin_lock_irqsave(&lg->lock, flags); - outl(inl(reg) | DIR_BIT, reg); - spin_unlock_irqrestore(&lg->lock, flags); - - return 0; -} - -static int lp_gpio_direction_output(struct gpio_chip *chip, - unsigned offset, int value) -{ - struct lp_gpio *lg = gpiochip_get_data(chip); - unsigned long reg = lp_gpio_reg(chip, offset, LP_CONFIG1); - unsigned long flags; - - lp_gpio_set(chip, offset, value); - - spin_lock_irqsave(&lg->lock, flags); - outl(inl(reg) & ~DIR_BIT, reg); - spin_unlock_irqrestore(&lg->lock, flags); - - return 0; -} - -static void lp_gpio_irq_handler(struct irq_desc *desc) -{ - struct irq_data *data = irq_desc_get_irq_data(desc); - struct gpio_chip *gc = irq_desc_get_handler_data(desc); - struct lp_gpio *lg = gpiochip_get_data(gc); - struct irq_chip *chip = irq_data_get_irq_chip(data); - unsigned long reg, ena, pending; - u32 base, pin; - - /* check from GPIO controller which pin triggered the interrupt */ - for (base = 0; base < lg->chip.ngpio; base += 32) { - reg = lp_gpio_reg(&lg->chip, base, LP_INT_STAT); - ena = lp_gpio_reg(&lg->chip, base, LP_INT_ENABLE); - - /* Only interrupts that are enabled */ - pending = inl(reg) & inl(ena); - - for_each_set_bit(pin, &pending, 32) { - unsigned irq; - - /* Clear before handling so we don't lose an edge */ - outl(BIT(pin), reg); - - irq = irq_find_mapping(lg->chip.irq.domain, base + pin); - generic_handle_irq(irq); - } - } - chip->irq_eoi(data); -} - -static void lp_irq_unmask(struct irq_data *d) -{ -} - -static void lp_irq_mask(struct irq_data *d) -{ -} - -static void lp_irq_enable(struct irq_data *d) -{ - struct gpio_chip *gc = irq_data_get_irq_chip_data(d); - struct lp_gpio *lg = gpiochip_get_data(gc); - u32 hwirq = irqd_to_hwirq(d); - unsigned long reg = lp_gpio_reg(&lg->chip, hwirq, LP_INT_ENABLE); - unsigned long flags; - - spin_lock_irqsave(&lg->lock, flags); - outl(inl(reg) | BIT(hwirq % 32), reg); - spin_unlock_irqrestore(&lg->lock, flags); -} - -static void lp_irq_disable(struct irq_data *d) -{ - struct gpio_chip *gc = irq_data_get_irq_chip_data(d); - struct lp_gpio *lg = gpiochip_get_data(gc); - u32 hwirq = irqd_to_hwirq(d); - unsigned long reg = lp_gpio_reg(&lg->chip, hwirq, LP_INT_ENABLE); - unsigned long flags; - - spin_lock_irqsave(&lg->lock, flags); - outl(inl(reg) & ~BIT(hwirq % 32), reg); - spin_unlock_irqrestore(&lg->lock, flags); -} - -static struct irq_chip lp_irqchip = { - .name = "LP-GPIO", - .irq_mask = lp_irq_mask, - .irq_unmask = lp_irq_unmask, - .irq_enable = lp_irq_enable, - .irq_disable = lp_irq_disable, - .irq_set_type = lp_irq_type, - .flags = IRQCHIP_SKIP_SET_WAKE, -}; - -static int lp_gpio_irq_init_hw(struct gpio_chip *chip) -{ - struct lp_gpio *lg = gpiochip_get_data(chip); - unsigned long reg; - unsigned base; - - for (base = 0; base < lg->chip.ngpio; base += 32) { - /* disable gpio pin interrupts */ - reg = lp_gpio_reg(&lg->chip, base, LP_INT_ENABLE); - outl(0, reg); - /* Clear interrupt status register */ - reg = lp_gpio_reg(&lg->chip, base, LP_INT_STAT); - outl(0xffffffff, reg); - } - - return 0; -} - -static int lp_gpio_probe(struct platform_device *pdev) -{ - struct lp_gpio *lg; - struct gpio_chip *gc; - struct resource *io_rc, *irq_rc; - struct device *dev = &pdev->dev; - unsigned long reg_len; - int ret = -ENODEV; - - lg = devm_kzalloc(dev, sizeof(struct lp_gpio), GFP_KERNEL); - if (!lg) - return -ENOMEM; - - lg->pdev = pdev; - platform_set_drvdata(pdev, lg); - - io_rc = platform_get_resource(pdev, IORESOURCE_IO, 0); - irq_rc = platform_get_resource(pdev, IORESOURCE_IRQ, 0); - - if (!io_rc) { - dev_err(dev, "missing IO resources\n"); - return -EINVAL; - } - - lg->reg_base = io_rc->start; - reg_len = resource_size(io_rc); - - if (!devm_request_region(dev, lg->reg_base, reg_len, "lp-gpio")) { - dev_err(dev, "failed requesting IO region 0x%x\n", - (unsigned int)lg->reg_base); - return -EBUSY; - } - - spin_lock_init(&lg->lock); - - gc = &lg->chip; - gc->label = dev_name(dev); - gc->owner = THIS_MODULE; - gc->request = lp_gpio_request; - gc->free = lp_gpio_free; - gc->direction_input = lp_gpio_direction_input; - gc->direction_output = lp_gpio_direction_output; - gc->get = lp_gpio_get; - gc->set = lp_gpio_set; - gc->base = -1; - gc->ngpio = LP_NUM_GPIO; - gc->can_sleep = false; - gc->parent = dev; - - /* set up interrupts */ - if (irq_rc && irq_rc->start) { - struct gpio_irq_chip *girq; - - girq = &gc->irq; - girq->chip = &lp_irqchip; - girq->init_hw = lp_gpio_irq_init_hw; - girq->parent_handler = lp_gpio_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] = (unsigned)irq_rc->start; - girq->default_type = IRQ_TYPE_NONE; - girq->handler = handle_bad_irq; - } - - ret = devm_gpiochip_add_data(dev, gc, lg); - if (ret) { - dev_err(dev, "failed adding lp-gpio chip\n"); - return ret; - } - - pm_runtime_enable(dev); - - return 0; -} - -static int lp_gpio_runtime_suspend(struct device *dev) -{ - return 0; -} - -static int lp_gpio_runtime_resume(struct device *dev) -{ - return 0; -} - -static int lp_gpio_resume(struct device *dev) -{ - struct lp_gpio *lg = dev_get_drvdata(dev); - unsigned long reg; - int i; - - /* on some hardware suspend clears input sensing, re-enable it here */ - for (i = 0; i < lg->chip.ngpio; i++) { - if (gpiochip_is_requested(&lg->chip, i) != NULL) { - reg = lp_gpio_reg(&lg->chip, i, LP_CONFIG2); - outl(inl(reg) & ~GPINDIS_BIT, reg); - } - } - return 0; -} - -static const struct dev_pm_ops lp_gpio_pm_ops = { - .runtime_suspend = lp_gpio_runtime_suspend, - .runtime_resume = lp_gpio_runtime_resume, - .resume = lp_gpio_resume, -}; - -static const struct acpi_device_id lynxpoint_gpio_acpi_match[] = { - { "INT33C7", 0 }, - { "INT3437", 0 }, - { } -}; -MODULE_DEVICE_TABLE(acpi, lynxpoint_gpio_acpi_match); - -static int lp_gpio_remove(struct platform_device *pdev) -{ - pm_runtime_disable(&pdev->dev); - return 0; -} - -static struct platform_driver lp_gpio_driver = { - .probe = lp_gpio_probe, - .remove = lp_gpio_remove, - .driver = { - .name = "lp_gpio", - .pm = &lp_gpio_pm_ops, - .acpi_match_table = ACPI_PTR(lynxpoint_gpio_acpi_match), - }, -}; - -static int __init lp_gpio_init(void) -{ - return platform_driver_register(&lp_gpio_driver); -} - -static void __exit lp_gpio_exit(void) -{ - platform_driver_unregister(&lp_gpio_driver); -} - -subsys_initcall(lp_gpio_init); -module_exit(lp_gpio_exit); - -MODULE_AUTHOR("Mathias Nyman (Intel)"); -MODULE_DESCRIPTION("GPIO interface for Intel Lynxpoint"); -MODULE_LICENSE("GPL v2"); -MODULE_ALIAS("platform:lp_gpio"); |