mirror of
https://github.com/torvalds/linux.git
synced 2026-05-27 00:22:00 +02:00
intel-gpio for v6.10-1
* New driver for vGPIO controller on Intel Granite Rapids-D * Update ACPI GPIO library to unify the IRQ code path * Better GPIO IRQ line labeling for ACPI * Switched Intel SCH driver to use "mapped" I/O accessors The following is an automated git shortlog grouped by driver: Add Intel Granite Rapids-D vGPIO driver: - Add Intel Granite Rapids-D vGPIO driver crystalcove: - Use -ENOTSUPP consistently gpiolib: - acpi: Set label for IRQ only lines - acpi: Add fwnode name to the GPIO interrupt label - acpi: Pass con_id instead of property into acpi_dev_gpio_irq_get_by() - acpi: Move acpi_can_fallback_to_crs() out of __acpi_find_gpio() - acpi: Simplify error handling in __acpi_find_gpio() - acpi: Extract __acpi_find_gpio() helper - acpi: Check for errors first in acpi_find_gpio() - acpi: Remove never true check in acpi_get_gpiod_by_index() sch: - Utilise temporary variable for struct device - Switch to memory mapped IO accessors wcove: - Use -ENOTSUPP consistently -----BEGIN PGP SIGNATURE----- iQIzBAABCgAdFiEEqaflIX74DDDzMJJtb7wzTHR8rCgFAmY4lK4ACgkQb7wzTHR8 rCjo8Q//YaGaR/0ZEh9s8pz5lLNz7MiyW3pDrABrRqd68yR4GhQcyHiUaybIrVtf ayNoyLn7u9On/j8bVPhru3fYWNGazg0q4KnMJu4BgkNsCCP6KWERHKzVHLuXg52Y zQiUsOWxlESYNlIhl0COy/o87dTPxQ3omnthMUDYUEvxuUv6aNIC0uCpXmSNm0+/ L9bZo7z6AiZMOeU7+XnoGuzWt2OeQjpR3liHo2zgR8ftPIp+iqjiRrA39+adXl7l LVro6F76p/xxNfGEzB4qxpz1jwHSkEhhFtcd13+t/CHXAm34BcAMbm1xJN1yHNmU e42CQ2gAOZo8F88iW4z56Wr446Uw0knf17Fe91Xd1CpqMdW0Hp9arta7awPoxh0R kHx5T71UkilX6+/CwREL7hiolvnNCO/q7djq/XeO//xPT67N0EU5mKZF/1yQiLWz NrJpNCRiQq2ZaHhOA0eS/4+iokpkLE0baeXsQhWrIjvFXfif8J82GiSgce1RzbHO v0yGeUHRJvY54zdXMKzCXEw+bgOyJZPmk4tZwq9XCkBcCrjxmR4cUtPCkv7B7QWN aSaeFh4AAQoSal8jMey/et+nctFZyO87aK8Enze9kzv/9FIc5837yXfz1qfjffPd E1m4RYh5t8DgC+msBjwbr1jcOM6FJ5KyEXXZf5CgAEzL5Bespm4= =33sC -----END PGP SIGNATURE----- Merge tag 'intel-gpio-v6.10-1' of git://git.kernel.org/pub/scm/linux/kernel/git/andy/linux-gpio-intel into gpio/for-next intel-gpio for v6.10-1 * New driver for vGPIO controller on Intel Granite Rapids-D * Update ACPI GPIO library to unify the IRQ code path * Better GPIO IRQ line labeling for ACPI * Switched Intel SCH driver to use "mapped" I/O accessors The following is an automated git shortlog grouped by driver: Add Intel Granite Rapids-D vGPIO driver: - Add Intel Granite Rapids-D vGPIO driver crystalcove: - Use -ENOTSUPP consistently gpiolib: - acpi: Set label for IRQ only lines - acpi: Add fwnode name to the GPIO interrupt label - acpi: Pass con_id instead of property into acpi_dev_gpio_irq_get_by() - acpi: Move acpi_can_fallback_to_crs() out of __acpi_find_gpio() - acpi: Simplify error handling in __acpi_find_gpio() - acpi: Extract __acpi_find_gpio() helper - acpi: Check for errors first in acpi_find_gpio() - acpi: Remove never true check in acpi_get_gpiod_by_index() sch: - Utilise temporary variable for struct device - Switch to memory mapped IO accessors wcove: - Use -ENOTSUPP consistently
This commit is contained in:
commit
68a25c3671
|
|
@ -10895,6 +10895,7 @@ L: linux-gpio@vger.kernel.org
|
|||
S: Supported
|
||||
T: git git://git.kernel.org/pub/scm/linux/kernel/git/andy/linux-gpio-intel.git
|
||||
F: drivers/gpio/gpio-elkhartlake.c
|
||||
F: drivers/gpio/gpio-graniterapids.c
|
||||
F: drivers/gpio/gpio-ich.c
|
||||
F: drivers/gpio/gpio-merrifield.c
|
||||
F: drivers/gpio/gpio-ml-ioh.c
|
||||
|
|
|
|||
|
|
@ -312,6 +312,24 @@ config GPIO_GENERIC_PLATFORM
|
|||
help
|
||||
Say yes here to support basic platform_device memory-mapped GPIO controllers.
|
||||
|
||||
config GPIO_GRANITERAPIDS
|
||||
tristate "Intel Granite Rapids-D vGPIO support"
|
||||
depends on X86 || COMPILE_TEST
|
||||
select GPIOLIB_IRQCHIP
|
||||
help
|
||||
Select this to enable virtual GPIO support on platforms with the
|
||||
following SoCs:
|
||||
|
||||
- Intel Granite Rapids-D
|
||||
|
||||
The driver enables basic GPIO functionality and implements interrupt
|
||||
support. The virtual GPIO driver controls GPIO lines via a firmware
|
||||
interface. The physical GPIO pins reside on device that is external
|
||||
from the main SoC package, such as a BMC or a CPLD.
|
||||
|
||||
To compile this driver as a module, choose M here: the module will
|
||||
be called gpio-graniterapids.
|
||||
|
||||
config GPIO_GRGPIO
|
||||
tristate "Aeroflex Gaisler GRGPIO support"
|
||||
depends on OF_GPIO
|
||||
|
|
|
|||
|
|
@ -66,6 +66,7 @@ obj-$(CONFIG_GPIO_FTGPIO010) += gpio-ftgpio010.o
|
|||
obj-$(CONFIG_GPIO_FXL6408) += gpio-fxl6408.o
|
||||
obj-$(CONFIG_GPIO_GE_FPGA) += gpio-ge.o
|
||||
obj-$(CONFIG_GPIO_GPIO_MM) += gpio-gpio-mm.o
|
||||
obj-$(CONFIG_GPIO_GRANITERAPIDS) += gpio-graniterapids.o
|
||||
obj-$(CONFIG_GPIO_GRGPIO) += gpio-grgpio.o
|
||||
obj-$(CONFIG_GPIO_GW_PLD) += gpio-gw-pld.o
|
||||
obj-$(CONFIG_GPIO_HISI) += gpio-hisi.o
|
||||
|
|
|
|||
|
|
@ -92,7 +92,7 @@ static inline int to_reg(int gpio, enum ctrl_register reg_type)
|
|||
case 0x5e:
|
||||
return GPIOPANELCTL;
|
||||
default:
|
||||
return -EOPNOTSUPP;
|
||||
return -ENOTSUPP;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
383
drivers/gpio/gpio-graniterapids.c
Normal file
383
drivers/gpio/gpio-graniterapids.c
Normal file
|
|
@ -0,0 +1,383 @@
|
|||
// SPDX-License-Identifier: GPL-2.0-only
|
||||
/*
|
||||
* Intel Granite Rapids-D vGPIO driver
|
||||
*
|
||||
* Copyright (c) 2024, Intel Corporation.
|
||||
*
|
||||
* Author: Aapo Vienamo <aapo.vienamo@linux.intel.com>
|
||||
*/
|
||||
|
||||
#include <linux/array_size.h>
|
||||
#include <linux/bitfield.h>
|
||||
#include <linux/bitmap.h>
|
||||
#include <linux/cleanup.h>
|
||||
#include <linux/device.h>
|
||||
#include <linux/err.h>
|
||||
#include <linux/gfp_types.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/io.h>
|
||||
#include <linux/irq.h>
|
||||
#include <linux/math.h>
|
||||
#include <linux/mod_devicetable.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/overflow.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/pm.h>
|
||||
#include <linux/spinlock.h>
|
||||
#include <linux/types.h>
|
||||
|
||||
#include <linux/gpio/driver.h>
|
||||
|
||||
#define GNR_NUM_PINS 128
|
||||
#define GNR_PINS_PER_REG 32
|
||||
#define GNR_NUM_REGS DIV_ROUND_UP(GNR_NUM_PINS, GNR_PINS_PER_REG)
|
||||
|
||||
#define GNR_CFG_BAR 0x00
|
||||
#define GNR_CFG_LOCK_OFFSET 0x04
|
||||
#define GNR_GPI_STATUS_OFFSET 0x20
|
||||
#define GNR_GPI_ENABLE_OFFSET 0x24
|
||||
|
||||
#define GNR_CFG_DW_RX_MASK GENMASK(25, 22)
|
||||
#define GNR_CFG_DW_RX_DISABLE FIELD_PREP(GNR_CFG_DW_RX_MASK, 2)
|
||||
#define GNR_CFG_DW_RX_EDGE FIELD_PREP(GNR_CFG_DW_RX_MASK, 1)
|
||||
#define GNR_CFG_DW_RX_LEVEL FIELD_PREP(GNR_CFG_DW_RX_MASK, 0)
|
||||
#define GNR_CFG_DW_RXDIS BIT(4)
|
||||
#define GNR_CFG_DW_TXDIS BIT(3)
|
||||
#define GNR_CFG_DW_RXSTATE BIT(1)
|
||||
#define GNR_CFG_DW_TXSTATE BIT(0)
|
||||
|
||||
/**
|
||||
* struct gnr_gpio - Intel Granite Rapids-D vGPIO driver state
|
||||
* @gc: GPIO controller interface
|
||||
* @reg_base: base address of the GPIO registers
|
||||
* @ro_bitmap: bitmap of read-only pins
|
||||
* @lock: guard the registers
|
||||
* @pad_backup: backup of the register state for suspend
|
||||
*/
|
||||
struct gnr_gpio {
|
||||
struct gpio_chip gc;
|
||||
void __iomem *reg_base;
|
||||
DECLARE_BITMAP(ro_bitmap, GNR_NUM_PINS);
|
||||
raw_spinlock_t lock;
|
||||
u32 pad_backup[];
|
||||
};
|
||||
|
||||
static void __iomem *gnr_gpio_get_padcfg_addr(const struct gnr_gpio *priv,
|
||||
unsigned int gpio)
|
||||
{
|
||||
return priv->reg_base + gpio * sizeof(u32);
|
||||
}
|
||||
|
||||
static int gnr_gpio_configure_line(struct gpio_chip *gc, unsigned int gpio,
|
||||
u32 clear_mask, u32 set_mask)
|
||||
{
|
||||
struct gnr_gpio *priv = gpiochip_get_data(gc);
|
||||
void __iomem *addr = gnr_gpio_get_padcfg_addr(priv, gpio);
|
||||
u32 dw;
|
||||
|
||||
if (test_bit(gpio, priv->ro_bitmap))
|
||||
return -EACCES;
|
||||
|
||||
guard(raw_spinlock_irqsave)(&priv->lock);
|
||||
|
||||
dw = readl(addr);
|
||||
dw &= ~clear_mask;
|
||||
dw |= set_mask;
|
||||
writel(dw, addr);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int gnr_gpio_get(struct gpio_chip *gc, unsigned int gpio)
|
||||
{
|
||||
const struct gnr_gpio *priv = gpiochip_get_data(gc);
|
||||
u32 dw;
|
||||
|
||||
dw = readl(gnr_gpio_get_padcfg_addr(priv, gpio));
|
||||
|
||||
return !!(dw & GNR_CFG_DW_RXSTATE);
|
||||
}
|
||||
|
||||
static void gnr_gpio_set(struct gpio_chip *gc, unsigned int gpio, int value)
|
||||
{
|
||||
u32 clear = 0;
|
||||
u32 set = 0;
|
||||
|
||||
if (value)
|
||||
set = GNR_CFG_DW_TXSTATE;
|
||||
else
|
||||
clear = GNR_CFG_DW_TXSTATE;
|
||||
|
||||
gnr_gpio_configure_line(gc, gpio, clear, set);
|
||||
}
|
||||
|
||||
static int gnr_gpio_get_direction(struct gpio_chip *gc, unsigned int gpio)
|
||||
{
|
||||
struct gnr_gpio *priv = gpiochip_get_data(gc);
|
||||
u32 dw;
|
||||
|
||||
dw = readl(gnr_gpio_get_padcfg_addr(priv, gpio));
|
||||
|
||||
if (dw & GNR_CFG_DW_TXDIS)
|
||||
return GPIO_LINE_DIRECTION_IN;
|
||||
|
||||
return GPIO_LINE_DIRECTION_OUT;
|
||||
}
|
||||
|
||||
static int gnr_gpio_direction_input(struct gpio_chip *gc, unsigned int gpio)
|
||||
{
|
||||
return gnr_gpio_configure_line(gc, gpio, GNR_CFG_DW_RXDIS, 0);
|
||||
}
|
||||
|
||||
static int gnr_gpio_direction_output(struct gpio_chip *gc, unsigned int gpio, int value)
|
||||
{
|
||||
u32 clear = GNR_CFG_DW_TXDIS;
|
||||
u32 set = value ? GNR_CFG_DW_TXSTATE : 0;
|
||||
|
||||
return gnr_gpio_configure_line(gc, gpio, clear, set);
|
||||
}
|
||||
|
||||
static const struct gpio_chip gnr_gpio_chip = {
|
||||
.owner = THIS_MODULE,
|
||||
.get = gnr_gpio_get,
|
||||
.set = gnr_gpio_set,
|
||||
.get_direction = gnr_gpio_get_direction,
|
||||
.direction_input = gnr_gpio_direction_input,
|
||||
.direction_output = gnr_gpio_direction_output,
|
||||
};
|
||||
|
||||
static void __iomem *gnr_gpio_get_reg_addr(const struct gnr_gpio *priv,
|
||||
unsigned int base,
|
||||
unsigned int gpio)
|
||||
{
|
||||
return priv->reg_base + base + gpio * sizeof(u32);
|
||||
}
|
||||
|
||||
static void gnr_gpio_irq_ack(struct irq_data *d)
|
||||
{
|
||||
struct gpio_chip *gc = irq_data_get_irq_chip_data(d);
|
||||
struct gnr_gpio *priv = gpiochip_get_data(gc);
|
||||
irq_hw_number_t gpio = irqd_to_hwirq(d);
|
||||
unsigned int reg_idx = gpio / GNR_PINS_PER_REG;
|
||||
unsigned int bit_idx = gpio % GNR_PINS_PER_REG;
|
||||
void __iomem *addr = gnr_gpio_get_reg_addr(priv, GNR_GPI_STATUS_OFFSET, reg_idx);
|
||||
u32 reg;
|
||||
|
||||
guard(raw_spinlock_irqsave)(&priv->lock);
|
||||
|
||||
reg = readl(addr);
|
||||
reg &= ~BIT(bit_idx);
|
||||
writel(reg, addr);
|
||||
}
|
||||
|
||||
static void gnr_gpio_irq_mask_unmask(struct gpio_chip *gc, unsigned long gpio, bool mask)
|
||||
{
|
||||
struct gnr_gpio *priv = gpiochip_get_data(gc);
|
||||
unsigned int reg_idx = gpio / GNR_PINS_PER_REG;
|
||||
unsigned int bit_idx = gpio % GNR_PINS_PER_REG;
|
||||
void __iomem *addr = gnr_gpio_get_reg_addr(priv, GNR_GPI_ENABLE_OFFSET, reg_idx);
|
||||
u32 reg;
|
||||
|
||||
guard(raw_spinlock_irqsave)(&priv->lock);
|
||||
|
||||
reg = readl(addr);
|
||||
if (mask)
|
||||
reg &= ~BIT(bit_idx);
|
||||
else
|
||||
reg |= BIT(bit_idx);
|
||||
writel(reg, addr);
|
||||
}
|
||||
|
||||
static void gnr_gpio_irq_mask(struct irq_data *d)
|
||||
{
|
||||
struct gpio_chip *gc = irq_data_get_irq_chip_data(d);
|
||||
irq_hw_number_t hwirq = irqd_to_hwirq(d);
|
||||
|
||||
gnr_gpio_irq_mask_unmask(gc, hwirq, true);
|
||||
gpiochip_disable_irq(gc, hwirq);
|
||||
}
|
||||
|
||||
static void gnr_gpio_irq_unmask(struct irq_data *d)
|
||||
{
|
||||
struct gpio_chip *gc = irq_data_get_irq_chip_data(d);
|
||||
irq_hw_number_t hwirq = irqd_to_hwirq(d);
|
||||
|
||||
gpiochip_enable_irq(gc, hwirq);
|
||||
gnr_gpio_irq_mask_unmask(gc, hwirq, false);
|
||||
}
|
||||
|
||||
static int gnr_gpio_irq_set_type(struct irq_data *d, unsigned int type)
|
||||
{
|
||||
struct gpio_chip *gc = irq_data_get_irq_chip_data(d);
|
||||
irq_hw_number_t pin = irqd_to_hwirq(d);
|
||||
u32 mask = GNR_CFG_DW_RX_MASK;
|
||||
u32 set;
|
||||
|
||||
/* Falling edge and level low triggers not supported by the GPIO controller */
|
||||
switch (type) {
|
||||
case IRQ_TYPE_NONE:
|
||||
set = GNR_CFG_DW_RX_DISABLE;
|
||||
break;
|
||||
case IRQ_TYPE_EDGE_RISING:
|
||||
set = GNR_CFG_DW_RX_EDGE;
|
||||
irq_set_handler_locked(d, handle_edge_irq);
|
||||
break;
|
||||
case IRQ_TYPE_LEVEL_HIGH:
|
||||
set = GNR_CFG_DW_RX_LEVEL;
|
||||
irq_set_handler_locked(d, handle_level_irq);
|
||||
break;
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
return gnr_gpio_configure_line(gc, pin, mask, set);
|
||||
}
|
||||
|
||||
static const struct irq_chip gnr_gpio_irq_chip = {
|
||||
.irq_ack = gnr_gpio_irq_ack,
|
||||
.irq_mask = gnr_gpio_irq_mask,
|
||||
.irq_unmask = gnr_gpio_irq_unmask,
|
||||
.irq_set_type = gnr_gpio_irq_set_type,
|
||||
.flags = IRQCHIP_IMMUTABLE,
|
||||
GPIOCHIP_IRQ_RESOURCE_HELPERS,
|
||||
};
|
||||
|
||||
static void gnr_gpio_init_pin_ro_bits(struct device *dev,
|
||||
const void __iomem *cfg_lock_base,
|
||||
unsigned long *ro_bitmap)
|
||||
{
|
||||
u32 tmp[GNR_NUM_REGS];
|
||||
|
||||
memcpy_fromio(tmp, cfg_lock_base, sizeof(tmp));
|
||||
bitmap_from_arr32(ro_bitmap, tmp, GNR_NUM_PINS);
|
||||
}
|
||||
|
||||
static irqreturn_t gnr_gpio_irq(int irq, void *data)
|
||||
{
|
||||
struct gnr_gpio *priv = data;
|
||||
unsigned int handled = 0;
|
||||
|
||||
for (unsigned int i = 0; i < GNR_NUM_REGS; i++) {
|
||||
const void __iomem *reg = priv->reg_base + i * sizeof(u32);
|
||||
unsigned long pending;
|
||||
unsigned long enabled;
|
||||
unsigned int bit_idx;
|
||||
|
||||
scoped_guard(raw_spinlock, &priv->lock) {
|
||||
pending = readl(reg + GNR_GPI_STATUS_OFFSET);
|
||||
enabled = readl(reg + GNR_GPI_ENABLE_OFFSET);
|
||||
}
|
||||
|
||||
/* Only enabled interrupts */
|
||||
pending &= enabled;
|
||||
|
||||
for_each_set_bit(bit_idx, &pending, GNR_PINS_PER_REG) {
|
||||
unsigned int hwirq = i * GNR_PINS_PER_REG + bit_idx;
|
||||
|
||||
generic_handle_domain_irq(priv->gc.irq.domain, hwirq);
|
||||
}
|
||||
|
||||
handled += pending ? 1 : 0;
|
||||
|
||||
}
|
||||
return IRQ_RETVAL(handled);
|
||||
}
|
||||
|
||||
static int gnr_gpio_probe(struct platform_device *pdev)
|
||||
{
|
||||
size_t num_backup_pins = IS_ENABLED(CONFIG_PM_SLEEP) ? GNR_NUM_PINS : 0;
|
||||
struct device *dev = &pdev->dev;
|
||||
struct gpio_irq_chip *girq;
|
||||
struct gnr_gpio *priv;
|
||||
void __iomem *regs;
|
||||
int irq, ret;
|
||||
|
||||
priv = devm_kzalloc(dev, struct_size(priv, pad_backup, num_backup_pins), GFP_KERNEL);
|
||||
if (!priv)
|
||||
return -ENOMEM;
|
||||
|
||||
regs = devm_platform_ioremap_resource(pdev, 0);
|
||||
if (IS_ERR(regs))
|
||||
return PTR_ERR(regs);
|
||||
|
||||
irq = platform_get_irq(pdev, 0);
|
||||
if (irq < 0)
|
||||
return irq;
|
||||
|
||||
ret = devm_request_irq(dev, irq, gnr_gpio_irq, IRQF_SHARED | IRQF_NO_THREAD,
|
||||
dev_name(dev), priv);
|
||||
if (ret)
|
||||
return dev_err_probe(dev, ret, "failed to request interrupt\n");
|
||||
|
||||
priv->reg_base = regs + readl(regs + GNR_CFG_BAR);
|
||||
|
||||
gnr_gpio_init_pin_ro_bits(dev, priv->reg_base + GNR_CFG_LOCK_OFFSET,
|
||||
priv->ro_bitmap);
|
||||
|
||||
priv->gc = gnr_gpio_chip;
|
||||
priv->gc.label = dev_name(dev);
|
||||
priv->gc.parent = dev;
|
||||
priv->gc.ngpio = GNR_NUM_PINS;
|
||||
priv->gc.base = -1;
|
||||
|
||||
girq = &priv->gc.irq;
|
||||
gpio_irq_chip_set_chip(girq, &gnr_gpio_irq_chip);
|
||||
girq->chip->name = dev_name(dev);
|
||||
girq->parent_handler = NULL;
|
||||
girq->num_parents = 0;
|
||||
girq->parents = NULL;
|
||||
girq->default_type = IRQ_TYPE_NONE;
|
||||
girq->handler = handle_bad_irq;
|
||||
|
||||
platform_set_drvdata(pdev, priv);
|
||||
|
||||
return devm_gpiochip_add_data(dev, &priv->gc, priv);
|
||||
}
|
||||
|
||||
static int gnr_gpio_suspend(struct device *dev)
|
||||
{
|
||||
struct gnr_gpio *priv = dev_get_drvdata(dev);
|
||||
unsigned int i;
|
||||
|
||||
guard(raw_spinlock_irqsave)(&priv->lock);
|
||||
|
||||
for_each_clear_bit(i, priv->ro_bitmap, priv->gc.ngpio)
|
||||
priv->pad_backup[i] = readl(gnr_gpio_get_padcfg_addr(priv, i));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int gnr_gpio_resume(struct device *dev)
|
||||
{
|
||||
struct gnr_gpio *priv = dev_get_drvdata(dev);
|
||||
unsigned int i;
|
||||
|
||||
guard(raw_spinlock_irqsave)(&priv->lock);
|
||||
|
||||
for_each_clear_bit(i, priv->ro_bitmap, priv->gc.ngpio)
|
||||
writel(priv->pad_backup[i], gnr_gpio_get_padcfg_addr(priv, i));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static DEFINE_SIMPLE_DEV_PM_OPS(gnr_gpio_pm_ops, gnr_gpio_suspend, gnr_gpio_resume);
|
||||
|
||||
static const struct acpi_device_id gnr_gpio_acpi_match[] = {
|
||||
{ "INTC1109" },
|
||||
{}
|
||||
};
|
||||
MODULE_DEVICE_TABLE(acpi, gnr_gpio_acpi_match);
|
||||
|
||||
static struct platform_driver gnr_gpio_driver = {
|
||||
.driver = {
|
||||
.name = "gpio-graniterapids",
|
||||
.pm = pm_sleep_ptr(&gnr_gpio_pm_ops),
|
||||
.acpi_match_table = gnr_gpio_acpi_match,
|
||||
},
|
||||
.probe = gnr_gpio_probe,
|
||||
};
|
||||
module_platform_driver(gnr_gpio_driver);
|
||||
|
||||
MODULE_LICENSE("GPL");
|
||||
MODULE_AUTHOR("Aapo Vienamo <aapo.vienamo@linux.intel.com>");
|
||||
MODULE_DESCRIPTION("Intel Granite Rapids-D vGPIO driver");
|
||||
|
|
@ -144,7 +144,7 @@ static int pca953x_acpi_get_irq(struct device *dev)
|
|||
if (ret)
|
||||
dev_warn(dev, "can't add GPIO ACPI mapping\n");
|
||||
|
||||
ret = acpi_dev_gpio_irq_get_by(ACPI_COMPANION(dev), "irq-gpios", 0);
|
||||
ret = acpi_dev_gpio_irq_get_by(ACPI_COMPANION(dev), "irq", 0);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
|
|
|
|||
|
|
@ -38,8 +38,8 @@
|
|||
|
||||
struct sch_gpio {
|
||||
struct gpio_chip chip;
|
||||
void __iomem *regs;
|
||||
spinlock_t lock;
|
||||
unsigned short iobase;
|
||||
unsigned short resume_base;
|
||||
|
||||
/* GPE handling */
|
||||
|
|
@ -75,7 +75,7 @@ static int sch_gpio_reg_get(struct sch_gpio *sch, unsigned int gpio, unsigned in
|
|||
offset = sch_gpio_offset(sch, gpio, reg);
|
||||
bit = sch_gpio_bit(sch, gpio);
|
||||
|
||||
reg_val = !!(inb(sch->iobase + offset) & BIT(bit));
|
||||
reg_val = !!(ioread8(sch->regs + offset) & BIT(bit));
|
||||
|
||||
return reg_val;
|
||||
}
|
||||
|
|
@ -89,12 +89,14 @@ static void sch_gpio_reg_set(struct sch_gpio *sch, unsigned int gpio, unsigned i
|
|||
offset = sch_gpio_offset(sch, gpio, reg);
|
||||
bit = sch_gpio_bit(sch, gpio);
|
||||
|
||||
reg_val = inb(sch->iobase + offset);
|
||||
reg_val = ioread8(sch->regs + offset);
|
||||
|
||||
if (val)
|
||||
outb(reg_val | BIT(bit), sch->iobase + offset);
|
||||
reg_val |= BIT(bit);
|
||||
else
|
||||
outb((reg_val & ~BIT(bit)), sch->iobase + offset);
|
||||
reg_val &= ~BIT(bit);
|
||||
|
||||
iowrite8(reg_val, sch->regs + offset);
|
||||
}
|
||||
|
||||
static int sch_gpio_direction_in(struct gpio_chip *gc, unsigned int gpio_num)
|
||||
|
|
@ -267,8 +269,8 @@ static u32 sch_gpio_gpe_handler(acpi_handle gpe_device, u32 gpe, void *context)
|
|||
|
||||
spin_lock_irqsave(&sch->lock, flags);
|
||||
|
||||
core_status = inl(sch->iobase + CORE_BANK_OFFSET + GTS);
|
||||
resume_status = inl(sch->iobase + RESUME_BANK_OFFSET + GTS);
|
||||
core_status = ioread32(sch->regs + CORE_BANK_OFFSET + GTS);
|
||||
resume_status = ioread32(sch->regs + RESUME_BANK_OFFSET + GTS);
|
||||
|
||||
spin_unlock_irqrestore(&sch->lock, flags);
|
||||
|
||||
|
|
@ -319,12 +321,14 @@ static int sch_gpio_install_gpe_handler(struct sch_gpio *sch)
|
|||
|
||||
static int sch_gpio_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct device *dev = &pdev->dev;
|
||||
struct gpio_irq_chip *girq;
|
||||
struct sch_gpio *sch;
|
||||
struct resource *res;
|
||||
void __iomem *regs;
|
||||
int ret;
|
||||
|
||||
sch = devm_kzalloc(&pdev->dev, sizeof(*sch), GFP_KERNEL);
|
||||
sch = devm_kzalloc(dev, sizeof(*sch), GFP_KERNEL);
|
||||
if (!sch)
|
||||
return -ENOMEM;
|
||||
|
||||
|
|
@ -332,15 +336,16 @@ static int sch_gpio_probe(struct platform_device *pdev)
|
|||
if (!res)
|
||||
return -EBUSY;
|
||||
|
||||
if (!devm_request_region(&pdev->dev, res->start, resource_size(res),
|
||||
pdev->name))
|
||||
regs = devm_ioport_map(dev, res->start, resource_size(res));
|
||||
if (!regs)
|
||||
return -EBUSY;
|
||||
|
||||
sch->regs = regs;
|
||||
|
||||
spin_lock_init(&sch->lock);
|
||||
sch->iobase = res->start;
|
||||
sch->chip = sch_gpio_chip;
|
||||
sch->chip.label = dev_name(&pdev->dev);
|
||||
sch->chip.parent = &pdev->dev;
|
||||
sch->chip.label = dev_name(dev);
|
||||
sch->chip.parent = dev;
|
||||
|
||||
switch (pdev->id) {
|
||||
case PCI_DEVICE_ID_INTEL_SCH_LPC:
|
||||
|
|
@ -394,9 +399,9 @@ static int sch_gpio_probe(struct platform_device *pdev)
|
|||
|
||||
ret = sch_gpio_install_gpe_handler(sch);
|
||||
if (ret)
|
||||
dev_warn(&pdev->dev, "Can't setup GPE, no IRQ support\n");
|
||||
dev_warn(dev, "Can't setup GPE, no IRQ support\n");
|
||||
|
||||
return devm_gpiochip_add_data(&pdev->dev, &sch->chip, sch);
|
||||
return devm_gpiochip_add_data(dev, &sch->chip, sch);
|
||||
}
|
||||
|
||||
static struct platform_driver sch_gpio_driver = {
|
||||
|
|
|
|||
|
|
@ -104,7 +104,7 @@ static inline int to_reg(int gpio, enum ctrl_register type)
|
|||
unsigned int reg = type == CTRL_IN ? GPIO_IN_CTRL_BASE : GPIO_OUT_CTRL_BASE;
|
||||
|
||||
if (gpio >= WCOVE_GPIO_NUM)
|
||||
return -EOPNOTSUPP;
|
||||
return -ENOTSUPP;
|
||||
|
||||
return reg + gpio;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -873,9 +873,6 @@ static struct gpio_desc *acpi_get_gpiod_by_index(struct acpi_device *adev,
|
|||
struct acpi_gpio_lookup lookup;
|
||||
int ret;
|
||||
|
||||
if (!adev)
|
||||
return ERR_PTR(-ENODEV);
|
||||
|
||||
memset(&lookup, 0, sizeof(lookup));
|
||||
lookup.index = index;
|
||||
|
||||
|
|
@ -948,14 +945,11 @@ static bool acpi_can_fallback_to_crs(struct acpi_device *adev,
|
|||
return con_id == NULL;
|
||||
}
|
||||
|
||||
struct gpio_desc *acpi_find_gpio(struct fwnode_handle *fwnode,
|
||||
const char *con_id,
|
||||
unsigned int idx,
|
||||
enum gpiod_flags *dflags,
|
||||
unsigned long *lookupflags)
|
||||
static struct gpio_desc *
|
||||
__acpi_find_gpio(struct fwnode_handle *fwnode, const char *con_id, unsigned int idx,
|
||||
bool can_fallback, struct acpi_gpio_info *info)
|
||||
{
|
||||
struct acpi_device *adev = to_acpi_device_node(fwnode);
|
||||
struct acpi_gpio_info info;
|
||||
struct gpio_desc *desc;
|
||||
char propname[32];
|
||||
int i;
|
||||
|
|
@ -972,25 +966,38 @@ struct gpio_desc *acpi_find_gpio(struct fwnode_handle *fwnode,
|
|||
|
||||
if (adev)
|
||||
desc = acpi_get_gpiod_by_index(adev,
|
||||
propname, idx, &info);
|
||||
propname, idx, info);
|
||||
else
|
||||
desc = acpi_get_gpiod_from_data(fwnode,
|
||||
propname, idx, &info);
|
||||
if (!IS_ERR(desc))
|
||||
break;
|
||||
propname, idx, info);
|
||||
if (PTR_ERR(desc) == -EPROBE_DEFER)
|
||||
return ERR_CAST(desc);
|
||||
|
||||
if (!IS_ERR(desc))
|
||||
return desc;
|
||||
}
|
||||
|
||||
/* Then from plain _CRS GPIOs */
|
||||
if (IS_ERR(desc)) {
|
||||
if (!adev || !acpi_can_fallback_to_crs(adev, con_id))
|
||||
return ERR_PTR(-ENOENT);
|
||||
if (!adev || !can_fallback)
|
||||
return ERR_PTR(-ENOENT);
|
||||
|
||||
desc = acpi_get_gpiod_by_index(adev, NULL, idx, &info);
|
||||
if (IS_ERR(desc))
|
||||
return desc;
|
||||
}
|
||||
return acpi_get_gpiod_by_index(adev, NULL, idx, info);
|
||||
}
|
||||
|
||||
struct gpio_desc *acpi_find_gpio(struct fwnode_handle *fwnode,
|
||||
const char *con_id,
|
||||
unsigned int idx,
|
||||
enum gpiod_flags *dflags,
|
||||
unsigned long *lookupflags)
|
||||
{
|
||||
struct acpi_device *adev = to_acpi_device_node(fwnode);
|
||||
bool can_fallback = acpi_can_fallback_to_crs(adev, con_id);
|
||||
struct acpi_gpio_info info;
|
||||
struct gpio_desc *desc;
|
||||
|
||||
desc = __acpi_find_gpio(fwnode, con_id, idx, can_fallback, &info);
|
||||
if (IS_ERR(desc))
|
||||
return desc;
|
||||
|
||||
if (info.gpioint &&
|
||||
(*dflags == GPIOD_OUT_LOW || *dflags == GPIOD_OUT_HIGH)) {
|
||||
|
|
@ -1006,7 +1013,7 @@ struct gpio_desc *acpi_find_gpio(struct fwnode_handle *fwnode,
|
|||
/**
|
||||
* acpi_dev_gpio_irq_wake_get_by() - Find GpioInt and translate it to Linux IRQ number
|
||||
* @adev: pointer to a ACPI device to get IRQ from
|
||||
* @name: optional name of GpioInt resource
|
||||
* @con_id: optional name of GpioInt resource
|
||||
* @index: index of GpioInt resource (starting from %0)
|
||||
* @wake_capable: Set to true if the IRQ is wake capable
|
||||
*
|
||||
|
|
@ -1017,17 +1024,18 @@ struct gpio_desc *acpi_find_gpio(struct fwnode_handle *fwnode,
|
|||
* The function is idempotent, though each time it runs it will configure GPIO
|
||||
* pin direction according to the flags in GpioInt resource.
|
||||
*
|
||||
* The function takes optional @name parameter. If the resource has a property
|
||||
* name, then only those will be taken into account.
|
||||
* The function takes optional @con_id parameter. If the resource has
|
||||
* a @con_id in a property, then only those will be taken into account.
|
||||
*
|
||||
* The GPIO is considered wake capable if the GpioInt resource specifies
|
||||
* SharedAndWake or ExclusiveAndWake.
|
||||
*
|
||||
* Return: Linux IRQ number (> %0) on success, negative errno on failure.
|
||||
*/
|
||||
int acpi_dev_gpio_irq_wake_get_by(struct acpi_device *adev, const char *name, int index,
|
||||
int acpi_dev_gpio_irq_wake_get_by(struct acpi_device *adev, const char *con_id, int index,
|
||||
bool *wake_capable)
|
||||
{
|
||||
struct fwnode_handle *fwnode = acpi_fwnode_handle(adev);
|
||||
int idx, i;
|
||||
unsigned int irq_flags;
|
||||
int ret;
|
||||
|
|
@ -1036,9 +1044,8 @@ int acpi_dev_gpio_irq_wake_get_by(struct acpi_device *adev, const char *name, in
|
|||
struct acpi_gpio_info info;
|
||||
struct gpio_desc *desc;
|
||||
|
||||
desc = acpi_get_gpiod_by_index(adev, name, i, &info);
|
||||
|
||||
/* Ignore -EPROBE_DEFER, it only matters if idx matches */
|
||||
desc = __acpi_find_gpio(fwnode, con_id, i, true, &info);
|
||||
if (IS_ERR(desc) && PTR_ERR(desc) != -EPROBE_DEFER)
|
||||
return PTR_ERR(desc);
|
||||
|
||||
|
|
@ -1058,7 +1065,11 @@ int acpi_dev_gpio_irq_wake_get_by(struct acpi_device *adev, const char *name, in
|
|||
acpi_gpio_update_gpiod_flags(&dflags, &info);
|
||||
acpi_gpio_update_gpiod_lookup_flags(&lflags, &info);
|
||||
|
||||
snprintf(label, sizeof(label), "GpioInt() %d", index);
|
||||
snprintf(label, sizeof(label), "%pfwP GpioInt(%d)", fwnode, index);
|
||||
ret = gpiod_set_consumer_name(desc, con_id ?: label);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = gpiod_configure_flags(desc, label, lflags, dflags);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
|
|
|||
|
|
@ -435,7 +435,7 @@ static int mlxbf_gige_probe(struct platform_device *pdev)
|
|||
priv->rx_irq = platform_get_irq(pdev, MLXBF_GIGE_RECEIVE_PKT_INTR_IDX);
|
||||
priv->llu_plu_irq = platform_get_irq(pdev, MLXBF_GIGE_LLU_PLU_INTR_IDX);
|
||||
|
||||
phy_irq = acpi_dev_gpio_irq_get_by(ACPI_COMPANION(&pdev->dev), "phy-gpios", 0);
|
||||
phy_irq = acpi_dev_gpio_irq_get_by(ACPI_COMPANION(&pdev->dev), "phy", 0);
|
||||
if (phy_irq < 0) {
|
||||
dev_err(&pdev->dev, "Error getting PHY irq. Use polling instead");
|
||||
phy_irq = PHY_POLL;
|
||||
|
|
|
|||
|
|
@ -95,7 +95,7 @@ static int cy8c95x0_acpi_get_irq(struct device *dev)
|
|||
if (ret)
|
||||
dev_warn(dev, "can't add GPIO ACPI mapping\n");
|
||||
|
||||
ret = acpi_dev_gpio_irq_get_by(ACPI_COMPANION(dev), "irq-gpios", 0);
|
||||
ret = acpi_dev_gpio_irq_get_by(ACPI_COMPANION(dev), "irq", 0);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
|
|
|
|||
|
|
@ -1233,7 +1233,7 @@ bool acpi_gpio_get_irq_resource(struct acpi_resource *ares,
|
|||
struct acpi_resource_gpio **agpio);
|
||||
bool acpi_gpio_get_io_resource(struct acpi_resource *ares,
|
||||
struct acpi_resource_gpio **agpio);
|
||||
int acpi_dev_gpio_irq_wake_get_by(struct acpi_device *adev, const char *name, int index,
|
||||
int acpi_dev_gpio_irq_wake_get_by(struct acpi_device *adev, const char *con_id, int index,
|
||||
bool *wake_capable);
|
||||
#else
|
||||
static inline bool acpi_gpio_get_irq_resource(struct acpi_resource *ares,
|
||||
|
|
@ -1246,7 +1246,7 @@ static inline bool acpi_gpio_get_io_resource(struct acpi_resource *ares,
|
|||
{
|
||||
return false;
|
||||
}
|
||||
static inline int acpi_dev_gpio_irq_wake_get_by(struct acpi_device *adev, const char *name,
|
||||
static inline int acpi_dev_gpio_irq_wake_get_by(struct acpi_device *adev, const char *con_id,
|
||||
int index, bool *wake_capable)
|
||||
{
|
||||
return -ENXIO;
|
||||
|
|
@ -1259,10 +1259,10 @@ static inline int acpi_dev_gpio_irq_wake_get(struct acpi_device *adev, int index
|
|||
return acpi_dev_gpio_irq_wake_get_by(adev, NULL, index, wake_capable);
|
||||
}
|
||||
|
||||
static inline int acpi_dev_gpio_irq_get_by(struct acpi_device *adev, const char *name,
|
||||
static inline int acpi_dev_gpio_irq_get_by(struct acpi_device *adev, const char *con_id,
|
||||
int index)
|
||||
{
|
||||
return acpi_dev_gpio_irq_wake_get_by(adev, name, index, NULL);
|
||||
return acpi_dev_gpio_irq_wake_get_by(adev, con_id, index, NULL);
|
||||
}
|
||||
|
||||
static inline int acpi_dev_gpio_irq_get(struct acpi_device *adev, int index)
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user