gpio updates for v6.10-rc1

GPIO core:
 - remove more unused legacy interfaces (after converting the last remaining
   users to better alternatives)
 - update kerneldocs
 - improve error handling and log messages in GPIO ACPI code
 - remove dead code (always true checks) from GPIOLIB
 
 New drivers:
 - add a driver for Intel Granite Rapids-D vGPIO
 
 Driver improvements:
 - use -ENOTSUPP consistently in gpio-regmap and gpio-pcie-idio-24
 - provide an ID table for gpio-cros-ec to avoid a driver name fallback check
 - add support for gpio-ranges for GPIO drivers supporting multiple GPIO banks
 - switch to using dynamic GPIO base in gpio-brcmstb
 - fix irq handling in gpio-npcm-sgpio
 - switch to memory mapped IO accessors in gpio-sch
 
 DT bindings:
 - add support for gpio-ranges to gpio-brcmstb
 - add support for a new model and the gpio-line-names property to gpio-mpfs
 
 Documentation:
 - replace leading tabs with spaces in code blocks
 - fix typos
 -----BEGIN PGP SIGNATURE-----
 
 iQIzBAABCgAdFiEEFp3rbAvDxGAT0sefEacuoBRx13IFAmZDFa4ACgkQEacuoBRx
 13IJuA//cdR+Y1xaiORhVg9gMjmeQtgP7ve6QK4p/vuwAuZJMxboc4ATPY4cBlvp
 VoMFQD8FgjbxcKRLjugS0wB/5isELzo5C+q699YKY/0R07WMBiTIt6FgS4JJ1j57
 RoAlLrZ7gxmJQyUWuk2dvvQ55MnCL4fzVCzCrQB+foWsZluyeQMnndFU7z+P96bK
 ckvNrfFlZjaTwRBVf9MVpcNUxuk+pFKMKfXCgNCvmhToOaOM3sKkFwMMZCOVRLpJ
 oCcAz6rbj+fn2x3Id2FS2R5f5GoZx31dalLnbJCY4OLgDNhjx1A7sONq+hplfO24
 LXxQgCP26myaxmCFsiKqYgYzh/1bnAeCaRjy+41+RWXy7LUil6c0yP1Z3pOlOK+h
 j32+/LS9aflneoxjXyAAQLAvMulDbIvKeWHUakPXk6bS/AR6zyL16rwfF9U3K795
 ZGAz37xuOCpAevGnRTpPz9eCWwnNFq5v8UMjvVmoMgtbJbIwP4J3cRzj6RCiBvrq
 AvveulP+oXde3vFydAf1NbjaRxf53b8vZp6DLFDqcU+76QCQwG55QqlhT4Nqm/Y4
 KASQYM4vlH+96vnCMW+p2DmN92dkoadwk5pBvEaY7q7eEC2EdAMfujUZ1VdB9OZ+
 FPZ6zAp6T2khVt4jzKFxbobV8xt3FznntEhbm4bo3Ugb2HRwD8g=
 =mBWd
 -----END PGP SIGNATURE-----

Merge tag 'gpio-updates-for-v6.10-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/brgl/linux

Pull gpio updates from Bartosz Golaszewski
 "This was a quiet release cycle for the GPIO tree and so this
  pull-request is relatively small.

  We have one new driver, some minor improvements to the GPIO core code
  and across several drivers, some DT and documentation updates but in
  general nothing stands out or is controversial. All changes have spent
  time in next with no reported issues (or ones that were quickly
  fixed).

  GPIO core:
   - remove more unused legacy interfaces (after converting the last
     remaining users to better alternatives)
   - update kerneldocs
   - improve error handling and log messages in GPIO ACPI code
   - remove dead code (always true checks) from GPIOLIB

  New drivers:
   - add a driver for Intel Granite Rapids-D vGPIO

  Driver improvements:
   - use -ENOTSUPP consistently in gpio-regmap and gpio-pcie-idio-24
   - provide an ID table for gpio-cros-ec to avoid a driver name
     fallback check
   - add support for gpio-ranges for GPIO drivers supporting multiple
     GPIO banks
   - switch to using dynamic GPIO base in gpio-brcmstb
   - fix irq handling in gpio-npcm-sgpio
   - switch to memory mapped IO accessors in gpio-sch

  DT bindings:
   - add support for gpio-ranges to gpio-brcmstb
   - add support for a new model and the gpio-line-names property to
     gpio-mpfs

  Documentation:
   - replace leading tabs with spaces in code blocks
   - fix typos"

* tag 'gpio-updates-for-v6.10-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/brgl/linux: (30 commits)
  gpio: nuvoton: Fix sgpio irq handle error
  gpiolib: Discourage to use formatting strings in line names
  gpio: brcmstb: add support for gpio-ranges
  gpio: of: support gpio-ranges for multiple gpiochip devices
  dt-bindings: gpio: brcmstb: add gpio-ranges
  gpio: Add Intel Granite Rapids-D vGPIO driver
  gpio: brcmstb: Use dynamic GPIO base numbers
  gpiolib: acpi: Set label for IRQ only lines
  gpiolib: acpi: Add fwnode name to the GPIO interrupt label
  gpiolib: Get rid of never false gpio_is_valid() calls
  gpiolib: acpi: Pass con_id instead of property into acpi_dev_gpio_irq_get_by()
  gpiolib: acpi: Move acpi_can_fallback_to_crs() out of __acpi_find_gpio()
  gpiolib: acpi: Simplify error handling in __acpi_find_gpio()
  gpiolib: acpi: Extract __acpi_find_gpio() helper
  gpio: sch: Utilise temporary variable for struct device
  gpio: sch: Switch to memory mapped IO accessors
  gpio: regmap: Use -ENOTSUPP consistently
  gpio: pcie-idio-24: Use -ENOTSUPP consistently
  Documentation: gpio: Replace leading TABs by spaces in code blocks
  gpiolib: acpi: Check for errors first in acpi_find_gpio()
  ...
This commit is contained in:
Linus Torvalds 2024-05-14 15:07:07 -07:00
commit ce952d8f0e
31 changed files with 622 additions and 235 deletions

View File

@ -62,6 +62,8 @@ properties:
interrupt-controller: true
gpio-ranges: true
wakeup-source:
type: boolean
description: >
@ -88,6 +90,7 @@ examples:
interrupt-parent = <&irq0_intc>;
interrupts = <0x6>;
brcm,gpio-bank-widths = <32 32 32 24>;
gpio-ranges = <&pinctrl 0 0 120>;
};
upg_gio_aon: gpio@f04172c0 {

View File

@ -14,6 +14,7 @@ properties:
items:
- enum:
- microchip,mpfs-gpio
- microchip,coregpio-rtl-v3
reg:
maxItems: 1
@ -43,6 +44,7 @@ properties:
default: 32
gpio-controller: true
gpio-line-names: true
patternProperties:
"^.+-hog(-[0-9]+)?$":
@ -62,12 +64,21 @@ patternProperties:
- gpio-hog
- gpios
allOf:
- if:
properties:
compatible:
contains:
const: microchip,mpfs-gpio
then:
required:
- interrupts
- "#interrupt-cells"
- interrupt-controller
required:
- compatible
- reg
- interrupts
- "#interrupt-cells"
- interrupt-controller
- "#gpio-cells"
- gpio-controller
- clocks

View File

@ -7,7 +7,7 @@ This document serves as a guide for writers of GPIO chip drivers.
Each GPIO controller driver needs to include the following header, which defines
the structures used to define a GPIO driver::
#include <linux/gpio/driver.h>
#include <linux/gpio/driver.h>
Internal Representation of GPIOs
@ -144,7 +144,7 @@ is not open, it will present a high-impedance (tristate) to the external rail::
in ----|| |/
||--+ in ----|
| |\
GND GND
GND GND
This configuration is normally used as a way to achieve one of two things:
@ -550,10 +550,10 @@ the interrupt separately and go with it:
struct my_gpio *g;
struct gpio_irq_chip *girq;
ret = devm_request_threaded_irq(dev, irq, NULL,
irq_thread_fn, IRQF_ONESHOT, "my-chip", g);
ret = devm_request_threaded_irq(dev, irq, NULL, irq_thread_fn,
IRQF_ONESHOT, "my-chip", g);
if (ret < 0)
return ret;
return ret;
/* Get a pointer to the gpio_irq_chip */
girq = &g->gc.irq;
@ -681,12 +681,12 @@ certain operations and keep track of usage inside of the gpiolib subsystem.
Input GPIOs can be used as IRQ signals. When this happens, a driver is requested
to mark the GPIO as being used as an IRQ::
int gpiochip_lock_as_irq(struct gpio_chip *chip, unsigned int offset)
int gpiochip_lock_as_irq(struct gpio_chip *chip, unsigned int offset)
This will prevent the use of non-irq related GPIO APIs until the GPIO IRQ lock
is released::
void gpiochip_unlock_as_irq(struct gpio_chip *chip, unsigned int offset)
void gpiochip_unlock_as_irq(struct gpio_chip *chip, unsigned int offset)
When implementing an irqchip inside a GPIO driver, these two functions should
typically be called in the .startup() and .shutdown() callbacks from the
@ -708,12 +708,12 @@ When a GPIO is used as an IRQ signal, then gpiolib also needs to know if
the IRQ is enabled or disabled. In order to inform gpiolib about this,
the irqchip driver should call::
void gpiochip_disable_irq(struct gpio_chip *chip, unsigned int offset)
void gpiochip_disable_irq(struct gpio_chip *chip, unsigned int offset)
This allows drivers to drive the GPIO as an output while the IRQ is
disabled. When the IRQ is enabled again, a driver should call::
void gpiochip_enable_irq(struct gpio_chip *chip, unsigned int offset)
void gpiochip_enable_irq(struct gpio_chip *chip, unsigned int offset)
When implementing an irqchip inside a GPIO driver, these two functions should
typically be called in the .irq_disable() and .irq_enable() callbacks from the
@ -763,12 +763,12 @@ Sometimes it is useful to allow a GPIO chip driver to request its own GPIO
descriptors through the gpiolib API. A GPIO driver can use the following
functions to request and free descriptors::
struct gpio_desc *gpiochip_request_own_desc(struct gpio_desc *desc,
u16 hwnum,
const char *label,
enum gpiod_flags flags)
struct gpio_desc *gpiochip_request_own_desc(struct gpio_desc *desc,
u16 hwnum,
const char *label,
enum gpiod_flags flags)
void gpiochip_free_own_desc(struct gpio_desc *desc)
void gpiochip_free_own_desc(struct gpio_desc *desc)
Descriptors requested with gpiochip_request_own_desc() must be released with
gpiochip_free_own_desc().

View File

@ -225,8 +225,6 @@ setup or driver probe/teardown code, so this is an easy constraint.)::
gpio_request()
## gpio_request_one()
## gpio_request_array()
## gpio_free_array()
gpio_free()
@ -295,14 +293,6 @@ are claimed, three additional calls are defined::
*/
int gpio_request_one(unsigned gpio, unsigned long flags, const char *label);
/* request multiple GPIOs in a single call
*/
int gpio_request_array(struct gpio *array, size_t num);
/* release multiple GPIOs in a single call
*/
void gpio_free_array(struct gpio *array, size_t num);
where 'flags' is currently defined to specify the following properties:
* GPIOF_DIR_IN - to configure direction as input
@ -341,12 +331,6 @@ A typical example of usage::
if (err)
...
err = gpio_request_array(leds_gpios, ARRAY_SIZE(leds_gpios));
if (err)
...
gpio_free_array(leds_gpios, ARRAY_SIZE(leds_gpios));
GPIOs mapped to IRQs
--------------------

View File

@ -208,8 +208,6 @@ GPIO 值的命令需要等待其信息排到队首才发送命令,再获得其
gpio_request()
## gpio_request_one()
## gpio_request_array()
## gpio_free_array()
gpio_free()
@ -272,14 +270,6 @@ gpio_request()前将这类细节配置好,例如使用引脚控制子系统的
*/
int gpio_request_one(unsigned gpio, unsigned long flags, const char *label);
/* 在单个函数中申请多个 GPIO
*/
int gpio_request_array(struct gpio *array, size_t num);
/* 在单个函数中释放多个 GPIO
*/
void gpio_free_array(struct gpio *array, size_t num);
这里 'flags' 当前定义可指定以下属性:
* GPIOF_DIR_IN - 配置方向为输入
@ -317,12 +307,6 @@ gpio_request()前将这类细节配置好,例如使用引脚控制子系统的
if (err)
...
err = gpio_request_array(leds_gpios, ARRAY_SIZE(leds_gpios));
if (err)
...
gpio_free_array(leds_gpios, ARRAY_SIZE(leds_gpios));
GPIO 映射到 IRQ
----------------

View File

@ -215,13 +215,10 @@ GPIO 值的命令需要等待其信息排到隊首才發送命令,再獲得其
gpio_request()
## gpio_request_one()
## gpio_request_array()
## gpio_free_array()
gpio_free()
聲明和釋放 GPIO
----------------------------
爲了有助於捕獲系統配置錯誤,定義了兩個函數。
@ -278,14 +275,6 @@ gpio_request()前將這類細節配置好,例如使用 pinctrl 子系統的映
*/
int gpio_request_one(unsigned gpio, unsigned long flags, const char *label);
/* 在單個函數中申請多個 GPIO
*/
int gpio_request_array(struct gpio *array, size_t num);
/* 在單個函數中釋放多個 GPIO
*/
void gpio_free_array(struct gpio *array, size_t num);
這裡 'flags' 當前定義可指定以下屬性:
* GPIOF_DIR_IN - 配置方向爲輸入
@ -323,12 +312,6 @@ gpio_request()前將這類細節配置好,例如使用 pinctrl 子系統的映
if (err)
...
err = gpio_request_array(leds_gpios, ARRAY_SIZE(leds_gpios));
if (err)
...
gpio_free_array(leds_gpios, ARRAY_SIZE(leds_gpios));
GPIO 映射到 IRQ
--------------------

View File

@ -81,7 +81,7 @@ Only one event clock flag, ``GPIO_V2_LINE_FLAG_EVENT_CLOCK_xxx``, may be set.
If none are set then the event clock defaults to ``CLOCK_MONOTONIC``.
The ``GPIO_V2_LINE_FLAG_EVENT_CLOCK_HTE`` flag requires supporting hardware
and a kernel with ``CONFIG_HTE`` set. Requesting HTE from a device that
doesn't support it is an error (**EOPNOTSUP**).
doesn't support it is an error (**EOPNOTSUPP**).
The :c:type:`debounce_period_us<gpio_v2_line_attribute>` attribute may only
be applied to lines with ``GPIO_V2_LINE_FLAG_INPUT`` set. When set, debounce

View File

@ -10936,6 +10936,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

View File

@ -35,18 +35,20 @@
static int spitz_last_ac_status;
static struct gpio spitz_charger_gpios[] = {
{ SPITZ_GPIO_KEY_INT, GPIOF_IN, "Keyboard Interrupt" },
{ SPITZ_GPIO_SYNC, GPIOF_IN, "Sync" },
{ SPITZ_GPIO_AC_IN, GPIOF_IN, "Charger Detection" },
{ SPITZ_GPIO_ADC_TEMP_ON, GPIOF_OUT_INIT_LOW, "ADC Temp On" },
{ SPITZ_GPIO_JK_B, GPIOF_OUT_INIT_LOW, "JK B" },
{ SPITZ_GPIO_CHRG_ON, GPIOF_OUT_INIT_LOW, "Charger On" },
};
static void spitz_charger_init(void)
{
gpio_request_array(ARRAY_AND_SIZE(spitz_charger_gpios));
gpio_request(SPITZ_GPIO_KEY_INT, "Keyboard Interrupt");
gpio_direction_input(SPITZ_GPIO_KEY_INT);
gpio_request(SPITZ_GPIO_SYNC, "Sync");
gpio_direction_input(SPITZ_GPIO_SYNC);
gpio_request(SPITZ_GPIO_AC_IN, "Charger Detection");
gpio_direction_input(SPITZ_GPIO_AC_IN);
gpio_request(SPITZ_GPIO_ADC_TEMP_ON, "ADC Temp On");
gpio_direction_output(SPITZ_GPIO_ADC_TEMP_ON, 0);
gpio_request(SPITZ_GPIO_JK_B, "JK B");
gpio_direction_output(SPITZ_GPIO_JK_B, 0);
gpio_request(SPITZ_GPIO_CHRG_ON, "Charger On");
gpio_direction_output(SPITZ_GPIO_CHRG_ON, 0);
}
static void spitz_measure_temp(int on)

View File

@ -20,16 +20,6 @@
#include "generic.h"
/*
* helper for sa1100fb
*/
static struct gpio h3600_lcd_gpio[] = {
{ H3XXX_EGPIO_LCD_ON, GPIOF_OUT_INIT_LOW, "LCD power" },
{ H3600_EGPIO_LCD_PCI, GPIOF_OUT_INIT_LOW, "LCD control" },
{ H3600_EGPIO_LCD_5V_ON, GPIOF_OUT_INIT_LOW, "LCD 5v" },
{ H3600_EGPIO_LVDD_ON, GPIOF_OUT_INIT_LOW, "LCD 9v/-6.5v" },
};
static bool h3600_lcd_request(void)
{
static bool h3600_lcd_ok;
@ -38,7 +28,42 @@ static bool h3600_lcd_request(void)
if (h3600_lcd_ok)
return true;
rc = gpio_request_array(h3600_lcd_gpio, ARRAY_SIZE(h3600_lcd_gpio));
rc = gpio_request(H3XXX_EGPIO_LCD_ON, "LCD power");
if (rc)
goto out;
rc = gpio_direction_output(H3XXX_EGPIO_LCD_ON, 0);
if (rc)
goto out_free_on;
rc = gpio_request(H3600_EGPIO_LCD_PCI, "LCD control");
if (rc)
goto out_free_on;
rc = gpio_direction_output(H3600_EGPIO_LCD_PCI, 0);
if (rc)
goto out_free_pci;
rc = gpio_request(H3600_EGPIO_LCD_5V_ON, "LCD 5v");
if (rc)
goto out_free_pci;
rc = gpio_direction_output(H3600_EGPIO_LCD_5V_ON, 0);
if (rc)
goto out_free_5v_on;
rc = gpio_request(H3600_EGPIO_LVDD_ON, "LCD 9v/-6.5v");
if (rc)
goto out_free_5v_on;
rc = gpio_direction_output(H3600_EGPIO_LVDD_ON, 0);
if (rc)
goto out_free_lvdd_on;
goto out;
out_free_lvdd_on:
gpio_free(H3600_EGPIO_LVDD_ON);
out_free_5v_on:
gpio_free(H3600_EGPIO_LCD_5V_ON);
out_free_pci:
gpio_free(H3600_EGPIO_LCD_PCI);
out_free_on:
gpio_free(H3XXX_EGPIO_LCD_ON);
out:
if (rc)
pr_err("%s: can't request GPIOs\n", __func__);
else

View File

@ -321,6 +321,24 @@ config GPIO_GENERIC_PLATFORM
help
Say yes here to support basic platform_device memory-mapped GPIO controllers.
config GPIO_GRANITERAPIDS
tristate "Intel Granite Rapids-D vGPIO support"
depends on X86 || COMPILE_TEST
select GPIOLIB_IRQCHIP
help
Select this to enable virtual GPIO support on platforms with the
following SoCs:
- Intel Granite Rapids-D
The driver enables basic GPIO functionality and implements interrupt
support. The virtual GPIO driver controls GPIO lines via a firmware
interface. The physical GPIO pins reside on device that is external
from the main SoC package, such as a BMC or a CPLD.
To compile this driver as a module, choose M here: the module will
be called gpio-graniterapids.
config GPIO_GRGPIO
tristate "Aeroflex Gaisler GRGPIO support"
depends on OF_GPIO

View File

@ -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

View File

@ -50,7 +50,6 @@ struct brcmstb_gpio_priv {
struct irq_domain *irq_domain;
struct irq_chip irq_chip;
int parent_irq;
int gpio_base;
int num_gpios;
int parent_wake_irq;
};
@ -92,7 +91,7 @@ brcmstb_gpio_get_active_irqs(struct brcmstb_gpio_bank *bank)
static int brcmstb_gpio_hwirq_to_offset(irq_hw_number_t hwirq,
struct brcmstb_gpio_bank *bank)
{
return hwirq - (bank->gc.base - bank->parent_priv->gpio_base);
return hwirq - bank->gc.offset;
}
static void brcmstb_gpio_set_imask(struct brcmstb_gpio_bank *bank,
@ -118,7 +117,7 @@ static int brcmstb_gpio_to_irq(struct gpio_chip *gc, unsigned offset)
{
struct brcmstb_gpio_priv *priv = brcmstb_gpio_gc_to_priv(gc);
/* gc_offset is relative to this gpio_chip; want real offset */
int hwirq = offset + (gc->base - priv->gpio_base);
int hwirq = offset + gc->offset;
if (hwirq >= priv->num_gpios)
return -ENXIO;
@ -263,7 +262,7 @@ static void brcmstb_gpio_irq_bank_handler(struct brcmstb_gpio_bank *bank)
{
struct brcmstb_gpio_priv *priv = bank->parent_priv;
struct irq_domain *domain = priv->irq_domain;
int hwbase = bank->gc.base - priv->gpio_base;
int hwbase = bank->gc.offset;
unsigned long status;
while ((status = brcmstb_gpio_get_active_irqs(bank))) {
@ -412,7 +411,7 @@ static int brcmstb_gpio_of_xlate(struct gpio_chip *gc,
if (WARN_ON(gpiospec->args_count < gc->of_gpio_n_cells))
return -EINVAL;
offset = gpiospec->args[0] - (gc->base - priv->gpio_base);
offset = gpiospec->args[0] - bank->gc.offset;
if (offset >= gc->ngpio || offset < 0)
return -EINVAL;
@ -596,8 +595,8 @@ static int brcmstb_gpio_probe(struct platform_device *pdev)
const __be32 *p;
u32 bank_width;
int num_banks = 0;
int num_gpios = 0;
int err;
static int gpio_base;
unsigned long flags = 0;
bool need_wakeup_event = false;
@ -611,7 +610,6 @@ static int brcmstb_gpio_probe(struct platform_device *pdev)
if (IS_ERR(reg_base))
return PTR_ERR(reg_base);
priv->gpio_base = gpio_base;
priv->reg_base = reg_base;
priv->pdev = pdev;
@ -651,7 +649,7 @@ static int brcmstb_gpio_probe(struct platform_device *pdev)
dev_dbg(dev, "Width 0 found: Empty bank @ %d\n",
num_banks);
num_banks++;
gpio_base += MAX_GPIO_PER_BANK;
num_gpios += MAX_GPIO_PER_BANK;
continue;
}
@ -691,12 +689,13 @@ static int brcmstb_gpio_probe(struct platform_device *pdev)
err = -ENOMEM;
goto fail;
}
gc->base = gpio_base;
gc->of_gpio_n_cells = 2;
gc->of_xlate = brcmstb_gpio_of_xlate;
/* not all ngpio lines are valid, will use bank width later */
gc->ngpio = MAX_GPIO_PER_BANK;
gc->offset = bank->id * MAX_GPIO_PER_BANK;
gc->request = gpiochip_generic_request;
gc->free = gpiochip_generic_free;
if (priv->parent_irq > 0)
gc->to_irq = brcmstb_gpio_to_irq;
@ -713,7 +712,7 @@ static int brcmstb_gpio_probe(struct platform_device *pdev)
bank->id);
goto fail;
}
gpio_base += gc->ngpio;
num_gpios += gc->ngpio;
dev_dbg(dev, "bank=%d, base=%d, ngpio=%d, width=%d\n", bank->id,
gc->base, gc->ngpio, bank->width);
@ -724,7 +723,7 @@ static int brcmstb_gpio_probe(struct platform_device *pdev)
num_banks++;
}
priv->num_gpios = gpio_base - priv->gpio_base;
priv->num_gpios = num_gpios;
if (priv->parent_irq > 0) {
err = brcmstb_gpio_irq_setup(pdev, priv);
if (err)

View File

@ -12,6 +12,7 @@
#include <linux/errno.h>
#include <linux/gpio/driver.h>
#include <linux/kernel.h>
#include <linux/mod_devicetable.h>
#include <linux/module.h>
#include <linux/platform_data/cros_ec_commands.h>
#include <linux/platform_data/cros_ec_proto.h>
@ -197,11 +198,18 @@ static int cros_ec_gpio_probe(struct platform_device *pdev)
return devm_gpiochip_add_data(dev, gc, cros_ec);
}
static const struct platform_device_id cros_ec_gpio_id[] = {
{ "cros-ec-gpio", 0 },
{}
};
MODULE_DEVICE_TABLE(platform, cros_ec_gpio_id);
static struct platform_driver cros_ec_gpio_driver = {
.probe = cros_ec_gpio_probe,
.driver = {
.name = "cros-ec-gpio",
},
.id_table = cros_ec_gpio_id,
};
module_platform_driver(cros_ec_gpio_driver);

View 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");

View File

@ -434,7 +434,7 @@ static void npcm_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 npcm_sgpio *gpio = gpiochip_get_data(gc);
unsigned int i, j, girq;
unsigned int i, j;
unsigned long reg;
chained_irq_enter(ic, desc);
@ -443,11 +443,9 @@ static void npcm_sgpio_irq_handler(struct irq_desc *desc)
const struct npcm_sgpio_bank *bank = &npcm_sgpio_banks[i];
reg = ioread8(bank_reg(gpio, bank, EVENT_STS));
for_each_set_bit(j, &reg, 8) {
girq = irq_find_mapping(gc->irq.domain,
i * 8 + gpio->nout_sgpio + j);
generic_handle_domain_irq(gc->irq.domain, girq);
}
for_each_set_bit(j, &reg, 8)
generic_handle_domain_irq(gc->irq.domain,
i * 8 + gpio->nout_sgpio + j);
}
chained_irq_exit(ic, desc);

View File

@ -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;

View File

@ -267,7 +267,7 @@ static int idio_24_reg_mask_xlate(struct gpio_regmap *const gpio, const unsigned
case IDIO_24_CONTROL_REG:
/* We can only set direction for TTL/CMOS lines */
if (offset < 48)
return -EOPNOTSUPP;
return -ENOTSUPP;
*reg = IDIO_24_CONTROL_REG;
*mask = CONTROL_REG_OUT_MODE;

View File

@ -129,7 +129,7 @@ static int gpio_regmap_get_direction(struct gpio_chip *chip,
base = gpio_regmap_addr(gpio->reg_dir_in_base);
invert = 1;
} else {
return -EOPNOTSUPP;
return -ENOTSUPP;
}
ret = gpio->reg_mask_xlate(gpio, base, offset, &reg, &mask);
@ -160,7 +160,7 @@ static int gpio_regmap_set_direction(struct gpio_chip *chip,
base = gpio_regmap_addr(gpio->reg_dir_in_base);
invert = 1;
} else {
return -EOPNOTSUPP;
return -ENOTSUPP;
}
ret = gpio->reg_mask_xlate(gpio, base, offset, &reg, &mask);

View File

@ -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 = {

View File

@ -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;

View File

@ -28,10 +28,9 @@ int gpio_request_one(unsigned gpio, unsigned long flags, const char *label)
struct gpio_desc *desc;
int err;
desc = gpio_to_desc(gpio);
/* Compatibility: assume unavailable "valid" GPIOs will appear later */
if (!desc && gpio_is_valid(gpio))
desc = gpio_to_desc(gpio);
if (!desc)
return -EPROBE_DEFER;
err = gpiod_request(desc, label);
@ -63,51 +62,13 @@ EXPORT_SYMBOL_GPL(gpio_request_one);
*/
int gpio_request(unsigned gpio, const char *label)
{
struct gpio_desc *desc = gpio_to_desc(gpio);
struct gpio_desc *desc;
/* Compatibility: assume unavailable "valid" GPIOs will appear later */
if (!desc && gpio_is_valid(gpio))
desc = gpio_to_desc(gpio);
if (!desc)
return -EPROBE_DEFER;
return gpiod_request(desc, label);
}
EXPORT_SYMBOL_GPL(gpio_request);
/**
* gpio_request_array - request multiple GPIOs in a single call
* @array: array of the 'struct gpio'
* @num: how many GPIOs in the array
*
* **DEPRECATED** This function is deprecated and must not be used in new code.
*/
int gpio_request_array(const struct gpio *array, size_t num)
{
int i, err;
for (i = 0; i < num; i++, array++) {
err = gpio_request_one(array->gpio, array->flags, array->label);
if (err)
goto err_free;
}
return 0;
err_free:
while (i--)
gpio_free((--array)->gpio);
return err;
}
EXPORT_SYMBOL_GPL(gpio_request_array);
/**
* gpio_free_array - release multiple GPIOs in a single call
* @array: array of the 'struct gpio'
* @num: how many GPIOs in the array
*
* **DEPRECATED** This function is deprecated and must not be used in new code.
*/
void gpio_free_array(const struct gpio *array, size_t num)
{
while (num--)
gpio_free((array++)->gpio);
}
EXPORT_SYMBOL_GPL(gpio_free_array);

View File

@ -1037,7 +1037,7 @@ static int of_gpiochip_add_pin_range(struct gpio_chip *chip)
struct of_phandle_args pinspec;
struct pinctrl_dev *pctldev;
struct device_node *np;
int index = 0, ret;
int index = 0, ret, trim;
const char *name;
static const char group_names_propname[] = "gpio-ranges-group-names";
struct property *group_names;
@ -1059,7 +1059,14 @@ static int of_gpiochip_add_pin_range(struct gpio_chip *chip)
if (!pctldev)
return -EPROBE_DEFER;
/* Ignore ranges outside of this GPIO chip */
if (pinspec.args[0] >= (chip->offset + chip->ngpio))
continue;
if (pinspec.args[0] + pinspec.args[2] <= chip->offset)
continue;
if (pinspec.args[2]) {
/* npins != 0: linear range */
if (group_names) {
of_property_read_string_index(np,
group_names_propname,
@ -1070,7 +1077,19 @@ static int of_gpiochip_add_pin_range(struct gpio_chip *chip)
break;
}
}
/* npins != 0: linear range */
/* Trim the range to fit this GPIO chip */
if (chip->offset > pinspec.args[0]) {
trim = chip->offset - pinspec.args[0];
pinspec.args[2] -= trim;
pinspec.args[1] += trim;
pinspec.args[0] = 0;
} else {
pinspec.args[0] -= chip->offset;
}
if ((pinspec.args[0] + pinspec.args[2]) > chip->ngpio)
pinspec.args[2] = chip->ngpio - pinspec.args[0];
ret = gpiochip_add_pin_range(chip,
pinctrl_dev_get_devname(pctldev),
pinspec.args[0],

View File

@ -412,7 +412,7 @@ static ssize_t base_show(struct device *dev,
{
const struct gpio_device *gdev = dev_get_drvdata(dev);
return sysfs_emit(buf, "%d\n", gdev->base);
return sysfs_emit(buf, "%u\n", gdev->base);
}
static DEVICE_ATTR_RO(base);

View File

@ -164,9 +164,6 @@ struct gpio_desc *gpio_to_desc(unsigned gpio)
}
}
if (!gpio_is_valid(gpio))
pr_warn("invalid GPIO %d\n", gpio);
return NULL;
}
EXPORT_SYMBOL_GPL(gpio_to_desc);
@ -311,10 +308,10 @@ struct gpio_chip *gpio_device_get_chip(struct gpio_device *gdev)
EXPORT_SYMBOL_GPL(gpio_device_get_chip);
/* dynamic allocation of GPIOs, e.g. on a hotplugged device */
static int gpiochip_find_base_unlocked(int ngpio)
static int gpiochip_find_base_unlocked(u16 ngpio)
{
unsigned int base = GPIO_DYNAMIC_BASE;
struct gpio_device *gdev;
int base = GPIO_DYNAMIC_BASE;
list_for_each_entry_srcu(gdev, &gpio_devices, list,
lockdep_is_held(&gpio_devices_lock)) {
@ -325,9 +322,11 @@ static int gpiochip_find_base_unlocked(int ngpio)
base = gdev->base + gdev->ngpio;
if (base < GPIO_DYNAMIC_BASE)
base = GPIO_DYNAMIC_BASE;
if (base > GPIO_DYNAMIC_MAX - ngpio)
break;
}
if (gpio_is_valid(base)) {
if (base <= GPIO_DYNAMIC_MAX - ngpio) {
pr_debug("%s: found new base at %d\n", __func__, base);
return base;
} else {
@ -379,7 +378,10 @@ int gpiod_get_direction(struct gpio_desc *desc)
if (ret < 0)
return ret;
/* GPIOF_DIR_IN or other positive, otherwise GPIOF_DIR_OUT */
/*
* GPIO_LINE_DIRECTION_IN or other positive,
* otherwise GPIO_LINE_DIRECTION_OUT.
*/
if (ret > 0)
ret = 1;
@ -760,7 +762,7 @@ static int gpiochip_setup_dev(struct gpio_device *gdev)
if (ret)
goto err_remove_device;
dev_dbg(&gdev->dev, "registered GPIOs %d to %d on %s\n", gdev->base,
dev_dbg(&gdev->dev, "registered GPIOs %u to %u on %s\n", gdev->base,
gdev->base + gdev->ngpio - 1, gdev->label);
return 0;
@ -4254,7 +4256,7 @@ struct gpio_desc *gpiod_find_and_request(struct device *consumer,
ret = gpiod_configure_flags(desc, con_id, lookupflags, flags);
if (ret < 0) {
gpiod_put(desc);
dev_dbg(consumer, "setup of GPIO %s failed\n", name);
dev_err(consumer, "setup of GPIO %s failed: %d\n", name, ret);
return ERR_PTR(ret);
}
@ -4802,14 +4804,14 @@ static void gpiolib_dbg_show(struct seq_file *s, struct gpio_device *gdev)
value = gpio_chip_get_value(gc, desc);
is_irq = test_bit(FLAG_USED_AS_IRQ, &desc->flags);
active_low = test_bit(FLAG_ACTIVE_LOW, &desc->flags);
seq_printf(s, " gpio-%-3d (%-20.20s|%-20.20s) %s %s %s%s\n",
seq_printf(s, " gpio-%-3u (%-20.20s|%-20.20s) %s %s %s%s\n",
gpio, desc->name ?: "", gpiod_get_label(desc),
is_out ? "out" : "in ",
value >= 0 ? (value ? "hi" : "lo") : "? ",
is_irq ? "IRQ " : "",
active_low ? "ACTIVE LOW" : "");
} else if (desc->name) {
seq_printf(s, " gpio-%-3d (%-20.20s)\n", gpio, desc->name);
seq_printf(s, " gpio-%-3u (%-20.20s)\n", gpio, desc->name);
}
gpio++;
@ -4881,7 +4883,7 @@ static int gpiolib_seq_show(struct seq_file *s, void *v)
return 0;
}
seq_printf(s, "%s%s: GPIOs %d-%d", priv->newline ? "\n" : "",
seq_printf(s, "%s%s: GPIOs %u-%u", priv->newline ? "\n" : "",
dev_name(&gdev->dev),
gdev->base, gdev->base + gdev->ngpio - 1);
parent = gc->parent;

View File

@ -63,7 +63,7 @@ struct gpio_device {
struct gpio_chip __rcu *chip;
struct gpio_desc *descs;
struct srcu_struct desc_srcu;
int base;
unsigned int base;
u16 ngpio;
bool can_sleep;
const char *label;

View File

@ -436,7 +436,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;

View File

@ -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;

View File

@ -1232,7 +1232,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,
@ -1245,7 +1245,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;
@ -1258,10 +1258,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)

View File

@ -74,6 +74,12 @@ static inline bool gpio_is_valid(int number)
* Until they are all fixed, leave 0-512 space for them.
*/
#define GPIO_DYNAMIC_BASE 512
/*
* Define the maximum of the possible GPIO in the global numberspace.
* While the GPIO base and numbers are positive, we limit it with signed
* maximum as a lot of code is using negative values for special cases.
*/
#define GPIO_DYNAMIC_MAX INT_MAX
/* Always use the library code for GPIO management calls,
* or when sleeping may be involved.
@ -114,8 +120,6 @@ static inline int gpio_to_irq(unsigned gpio)
}
int gpio_request_one(unsigned gpio, unsigned long flags, const char *label);
int gpio_request_array(const struct gpio *array, size_t num);
void gpio_free_array(const struct gpio *array, size_t num);
/* CONFIG_GPIOLIB: bindings for managed devices that want to request gpios */
@ -146,11 +150,6 @@ static inline int gpio_request_one(unsigned gpio,
return -ENOSYS;
}
static inline int gpio_request_array(const struct gpio *array, size_t num)
{
return -ENOSYS;
}
static inline void gpio_free(unsigned gpio)
{
might_sleep();
@ -159,14 +158,6 @@ static inline void gpio_free(unsigned gpio)
WARN_ON(1);
}
static inline void gpio_free_array(const struct gpio *array, size_t num)
{
might_sleep();
/* GPIO can never have been requested */
WARN_ON(1);
}
static inline int gpio_direction_input(unsigned gpio)
{
return -ENOSYS;

View File

@ -376,9 +376,7 @@ struct gpio_irq_chip {
* @names: if set, must be an array of strings to use as alternative
* names for the GPIOs in this chip. Any entry in the array
* may be NULL if there is no alias for the GPIO, however the
* array must be @ngpio entries long. A name can include a single printk
* format specifier for an unsigned int. It is substituted by the actual
* number of the gpio.
* array must be @ngpio entries long.
* @can_sleep: flag must be set iff get()/set() methods sleep, as they
* must while accessing GPIO expander chips over I2C or SPI. This
* implies that if the chip supports IRQs, these IRQs need to be threaded