mirror of
https://github.com/AuxXxilium/linux_dsm_epyc7002.git
synced 2024-11-24 13:00:54 +07:00
gpio: updates for v5.2 (part 1)
- batch of improvements for the vf610 driver which shrink the code and make use of resource managed helpers - support for a new variant of pca953x - make gpio-mockup buildable on systems without IOMEM - make gpio-74x164 more flexible by using generic device properties plus minor improvements - new driver for Mellanox BlueField - fixes for wakeup GPIOs in gpio-omap - use devm_platform_ioremap_resource() in gpio-mxc - a couple improvements of kernel docs for ACPI code - don't WARN() in gpiod_put() on optional GPIOs -----BEGIN PGP SIGNATURE----- iQIzBAABCAAdFiEEFp3rbAvDxGAT0sefEacuoBRx13IFAlyrR7kACgkQEacuoBRx 13KSJg/+NCSqM0OBMylRdNwfwQvpHj7Fp/6IRVVSpIetaVafPcPJ7TJtHeSBCE9X F9Cqpe9UlqLuBI+LXIIYLdsltirmhFfAUkhQvpFlUj4w9YyKojbISCgswUPMwFJ8 JM6uiZaCHrHD7Q6m0znwmOJsCm/OOMhrjPWFrRTZNZOGl86eB/FifPvlWW/+GIkv RutHf+qiC7TkIpZO/mn4RIKwCOamFZvqUGTxasBU3+xwFrVlRW1ER8oWvSUjI8io OLNY25lgr8zfVCeBL9RDGTrS2R6HDt3ibkNO1mZfsADIKQxhl/U9UopIupCKA1we 4tID5qLLm320vTVS+kUmrroKL7mNc7u9J7fo7AcrR03dn9697bBogrxTobCuw39r Alpm1SjsftfWyEIyNC+w+pvB7l8iLxFa7WeTTW4W+JSmrOMGp8xuCGAo1jNm/2CL ljs4BXYvhDgVMQwvgFm9B3r7Lyo4K83pbnScu2BGhWvmotXxQ37jL8GRM6EZFY3E rcZOiqqE6GlUXuO0hwiBqJsMzRLBHsHlX7yS7sajOx3tTyIOhLkDGt20YVsj1gVP I0438QZ4MeAiWnIpxMDjntPxPX92TwAP90sYX9ix0bJ12NbIQb+105TKYJnHj2eL LEEVrN4AUkSA7WFXPEAAxKEG9Z0dhagDtxsW+ZNwS4SvLEVl/Kc= =mSS+ -----END PGP SIGNATURE----- Merge tag 'gpio-v5.2-updates-for-linus-part1' of git://git.kernel.org/pub/scm/linux/kernel/git/brgl/linux into devel gpio: updates for v5.2 (part 1) - batch of improvements for the vf610 driver which shrink the code and make use of resource managed helpers - support for a new variant of pca953x - make gpio-mockup buildable on systems without IOMEM - make gpio-74x164 more flexible by using generic device properties plus minor improvements - new driver for Mellanox BlueField - fixes for wakeup GPIOs in gpio-omap - use devm_platform_ioremap_resource() in gpio-mxc - a couple improvements of kernel docs for ACPI code - don't WARN() in gpiod_put() on optional GPIOs
This commit is contained in:
commit
4779a066e7
@ -30,6 +30,7 @@ Required properties:
|
|||||||
ti,tca6424
|
ti,tca6424
|
||||||
ti,tca9539
|
ti,tca9539
|
||||||
ti,tca9554
|
ti,tca9554
|
||||||
|
onnn,cat9554
|
||||||
onnn,pca9654
|
onnn,pca9654
|
||||||
exar,xra1202
|
exar,xra1202
|
||||||
- gpio-controller: if used as gpio expander.
|
- gpio-controller: if used as gpio expander.
|
||||||
|
@ -330,20 +330,6 @@ config GPIO_MM_LANTIQ
|
|||||||
(EBU) found on Lantiq SoCs. The gpios are output only as they are
|
(EBU) found on Lantiq SoCs. The gpios are output only as they are
|
||||||
created by attaching a 16bit latch to the bus.
|
created by attaching a 16bit latch to the bus.
|
||||||
|
|
||||||
config GPIO_MOCKUP
|
|
||||||
tristate "GPIO Testing Driver"
|
|
||||||
depends on GPIOLIB && SYSFS
|
|
||||||
select GPIO_SYSFS
|
|
||||||
select GPIOLIB_IRQCHIP
|
|
||||||
select IRQ_SIM
|
|
||||||
help
|
|
||||||
This enables GPIO Testing driver, which provides a way to test GPIO
|
|
||||||
subsystem through sysfs(or char device) and debugfs. GPIO_SYSFS
|
|
||||||
must be selected for this test.
|
|
||||||
User could use it through the script in
|
|
||||||
tools/testing/selftests/gpio/gpio-mockup.sh. Reference the usage in
|
|
||||||
it.
|
|
||||||
|
|
||||||
config GPIO_MPC5200
|
config GPIO_MPC5200
|
||||||
def_bool y
|
def_bool y
|
||||||
depends on PPC_MPC52xx
|
depends on PPC_MPC52xx
|
||||||
@ -1316,6 +1302,13 @@ config GPIO_MERRIFIELD
|
|||||||
help
|
help
|
||||||
Say Y here to support Intel Merrifield GPIO.
|
Say Y here to support Intel Merrifield GPIO.
|
||||||
|
|
||||||
|
config GPIO_MLXBF
|
||||||
|
tristate "Mellanox BlueField SoC GPIO"
|
||||||
|
depends on (MELLANOX_PLATFORM && ARM64 && ACPI) || (64BIT && COMPILE_TEST)
|
||||||
|
select GPIO_GENERIC
|
||||||
|
help
|
||||||
|
Say Y here if you want GPIO support on Mellanox BlueField SoC.
|
||||||
|
|
||||||
config GPIO_ML_IOH
|
config GPIO_ML_IOH
|
||||||
tristate "OKI SEMICONDUCTOR ML7213 IOH GPIO support"
|
tristate "OKI SEMICONDUCTOR ML7213 IOH GPIO support"
|
||||||
depends on X86 || COMPILE_TEST
|
depends on X86 || COMPILE_TEST
|
||||||
@ -1442,4 +1435,16 @@ config GPIO_VIPERBOARD
|
|||||||
|
|
||||||
endmenu
|
endmenu
|
||||||
|
|
||||||
|
config GPIO_MOCKUP
|
||||||
|
tristate "GPIO Testing Driver"
|
||||||
|
depends on GPIOLIB
|
||||||
|
select IRQ_SIM
|
||||||
|
help
|
||||||
|
This enables GPIO Testing driver, which provides a way to test GPIO
|
||||||
|
subsystem through sysfs(or char device) and debugfs. GPIO_SYSFS
|
||||||
|
must be selected for this test.
|
||||||
|
User could use it through the script in
|
||||||
|
tools/testing/selftests/gpio/gpio-mockup.sh. Reference the usage in
|
||||||
|
it.
|
||||||
|
|
||||||
endif
|
endif
|
||||||
|
@ -85,6 +85,7 @@ obj-$(CONFIG_GPIO_MENZ127) += gpio-menz127.o
|
|||||||
obj-$(CONFIG_GPIO_MERRIFIELD) += gpio-merrifield.o
|
obj-$(CONFIG_GPIO_MERRIFIELD) += gpio-merrifield.o
|
||||||
obj-$(CONFIG_GPIO_MC33880) += gpio-mc33880.o
|
obj-$(CONFIG_GPIO_MC33880) += gpio-mc33880.o
|
||||||
obj-$(CONFIG_GPIO_MC9S08DZ60) += gpio-mc9s08dz60.o
|
obj-$(CONFIG_GPIO_MC9S08DZ60) += gpio-mc9s08dz60.o
|
||||||
|
obj-$(CONFIG_GPIO_MLXBF) += gpio-mlxbf.o
|
||||||
obj-$(CONFIG_GPIO_ML_IOH) += gpio-ml-ioh.o
|
obj-$(CONFIG_GPIO_ML_IOH) += gpio-ml-ioh.o
|
||||||
obj-$(CONFIG_GPIO_MM_LANTIQ) += gpio-mm-lantiq.o
|
obj-$(CONFIG_GPIO_MM_LANTIQ) += gpio-mm-lantiq.o
|
||||||
obj-$(CONFIG_GPIO_MOCKUP) += gpio-mockup.o
|
obj-$(CONFIG_GPIO_MOCKUP) += gpio-mockup.o
|
||||||
|
@ -1,21 +1,18 @@
|
|||||||
|
// SPDX-License-Identifier: GPL-2.0-only
|
||||||
/*
|
/*
|
||||||
* 74Hx164 - Generic serial-in/parallel-out 8-bits shift register GPIO driver
|
* 74Hx164 - Generic serial-in/parallel-out 8-bits shift register GPIO driver
|
||||||
*
|
*
|
||||||
* Copyright (C) 2010 Gabor Juhos <juhosg@openwrt.org>
|
* Copyright (C) 2010 Gabor Juhos <juhosg@openwrt.org>
|
||||||
* Copyright (C) 2010 Miguel Gaio <miguel.gaio@efixo.com>
|
* Copyright (C) 2010 Miguel Gaio <miguel.gaio@efixo.com>
|
||||||
*
|
|
||||||
* This program is free software; you can redistribute it and/or modify
|
|
||||||
* it under the terms of the GNU General Public License version 2 as
|
|
||||||
* published by the Free Software Foundation.
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include <linux/init.h>
|
|
||||||
#include <linux/mutex.h>
|
|
||||||
#include <linux/spi/spi.h>
|
|
||||||
#include <linux/gpio/driver.h>
|
|
||||||
#include <linux/gpio/consumer.h>
|
#include <linux/gpio/consumer.h>
|
||||||
#include <linux/slab.h>
|
#include <linux/gpio/driver.h>
|
||||||
#include <linux/module.h>
|
#include <linux/module.h>
|
||||||
|
#include <linux/mutex.h>
|
||||||
|
#include <linux/property.h>
|
||||||
|
#include <linux/slab.h>
|
||||||
|
#include <linux/spi/spi.h>
|
||||||
|
|
||||||
#define GEN_74X164_NUMBER_GPIOS 8
|
#define GEN_74X164_NUMBER_GPIOS 8
|
||||||
|
|
||||||
@ -116,10 +113,9 @@ static int gen_74x164_probe(struct spi_device *spi)
|
|||||||
if (ret < 0)
|
if (ret < 0)
|
||||||
return ret;
|
return ret;
|
||||||
|
|
||||||
if (of_property_read_u32(spi->dev.of_node, "registers-number",
|
ret = device_property_read_u32(&spi->dev, "registers-number", &nregs);
|
||||||
&nregs)) {
|
if (ret) {
|
||||||
dev_err(&spi->dev,
|
dev_err(&spi->dev, "Missing 'registers-number' property.\n");
|
||||||
"Missing registers-number property in the DT.\n");
|
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
152
drivers/gpio/gpio-mlxbf.c
Normal file
152
drivers/gpio/gpio-mlxbf.c
Normal file
@ -0,0 +1,152 @@
|
|||||||
|
// SPDX-License-Identifier: GPL-2.0
|
||||||
|
|
||||||
|
#include <linux/acpi.h>
|
||||||
|
#include <linux/bitops.h>
|
||||||
|
#include <linux/device.h>
|
||||||
|
#include <linux/gpio/driver.h>
|
||||||
|
#include <linux/io.h>
|
||||||
|
#include <linux/kernel.h>
|
||||||
|
#include <linux/module.h>
|
||||||
|
#include <linux/platform_device.h>
|
||||||
|
#include <linux/pm.h>
|
||||||
|
#include <linux/resource.h>
|
||||||
|
#include <linux/types.h>
|
||||||
|
|
||||||
|
/* Number of pins on BlueField */
|
||||||
|
#define MLXBF_GPIO_NR 54
|
||||||
|
|
||||||
|
/* Pad Electrical Controls. */
|
||||||
|
#define MLXBF_GPIO_PAD_CONTROL_FIRST_WORD 0x0700
|
||||||
|
#define MLXBF_GPIO_PAD_CONTROL_1_FIRST_WORD 0x0708
|
||||||
|
#define MLXBF_GPIO_PAD_CONTROL_2_FIRST_WORD 0x0710
|
||||||
|
#define MLXBF_GPIO_PAD_CONTROL_3_FIRST_WORD 0x0718
|
||||||
|
|
||||||
|
#define MLXBF_GPIO_PIN_DIR_I 0x1040
|
||||||
|
#define MLXBF_GPIO_PIN_DIR_O 0x1048
|
||||||
|
#define MLXBF_GPIO_PIN_STATE 0x1000
|
||||||
|
#define MLXBF_GPIO_SCRATCHPAD 0x20
|
||||||
|
|
||||||
|
#ifdef CONFIG_PM
|
||||||
|
struct mlxbf_gpio_context_save_regs {
|
||||||
|
u64 scratchpad;
|
||||||
|
u64 pad_control[MLXBF_GPIO_NR];
|
||||||
|
u64 pin_dir_i;
|
||||||
|
u64 pin_dir_o;
|
||||||
|
};
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* Device state structure. */
|
||||||
|
struct mlxbf_gpio_state {
|
||||||
|
struct gpio_chip gc;
|
||||||
|
|
||||||
|
/* Memory Address */
|
||||||
|
void __iomem *base;
|
||||||
|
|
||||||
|
#ifdef CONFIG_PM
|
||||||
|
struct mlxbf_gpio_context_save_regs csave_regs;
|
||||||
|
#endif
|
||||||
|
};
|
||||||
|
|
||||||
|
static int mlxbf_gpio_probe(struct platform_device *pdev)
|
||||||
|
{
|
||||||
|
struct mlxbf_gpio_state *gs;
|
||||||
|
struct device *dev = &pdev->dev;
|
||||||
|
struct gpio_chip *gc;
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
gs = devm_kzalloc(&pdev->dev, sizeof(*gs), GFP_KERNEL);
|
||||||
|
if (!gs)
|
||||||
|
return -ENOMEM;
|
||||||
|
|
||||||
|
gs->base = devm_platform_ioremap_resource(pdev, 0);
|
||||||
|
if (IS_ERR(gs->base))
|
||||||
|
return PTR_ERR(gs->base);
|
||||||
|
|
||||||
|
gc = &gs->gc;
|
||||||
|
ret = bgpio_init(gc, dev, 8,
|
||||||
|
gs->base + MLXBF_GPIO_PIN_STATE,
|
||||||
|
NULL,
|
||||||
|
NULL,
|
||||||
|
gs->base + MLXBF_GPIO_PIN_DIR_O,
|
||||||
|
gs->base + MLXBF_GPIO_PIN_DIR_I,
|
||||||
|
0);
|
||||||
|
if (ret)
|
||||||
|
return -ENODEV;
|
||||||
|
|
||||||
|
gc->owner = THIS_MODULE;
|
||||||
|
gc->ngpio = MLXBF_GPIO_NR;
|
||||||
|
|
||||||
|
ret = devm_gpiochip_add_data(dev, &gs->gc, gs);
|
||||||
|
if (ret) {
|
||||||
|
dev_err(&pdev->dev, "Failed adding memory mapped gpiochip\n");
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
platform_set_drvdata(pdev, gs);
|
||||||
|
dev_info(&pdev->dev, "registered Mellanox BlueField GPIO");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef CONFIG_PM
|
||||||
|
static int mlxbf_gpio_suspend(struct platform_device *pdev, pm_message_t state)
|
||||||
|
{
|
||||||
|
struct mlxbf_gpio_state *gs = platform_get_drvdata(pdev);
|
||||||
|
|
||||||
|
gs->csave_regs.scratchpad = readq(gs->base + MLXBF_GPIO_SCRATCHPAD);
|
||||||
|
gs->csave_regs.pad_control[0] =
|
||||||
|
readq(gs->base + MLXBF_GPIO_PAD_CONTROL_FIRST_WORD);
|
||||||
|
gs->csave_regs.pad_control[1] =
|
||||||
|
readq(gs->base + MLXBF_GPIO_PAD_CONTROL_1_FIRST_WORD);
|
||||||
|
gs->csave_regs.pad_control[2] =
|
||||||
|
readq(gs->base + MLXBF_GPIO_PAD_CONTROL_2_FIRST_WORD);
|
||||||
|
gs->csave_regs.pad_control[3] =
|
||||||
|
readq(gs->base + MLXBF_GPIO_PAD_CONTROL_3_FIRST_WORD);
|
||||||
|
gs->csave_regs.pin_dir_i = readq(gs->base + MLXBF_GPIO_PIN_DIR_I);
|
||||||
|
gs->csave_regs.pin_dir_o = readq(gs->base + MLXBF_GPIO_PIN_DIR_O);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int mlxbf_gpio_resume(struct platform_device *pdev)
|
||||||
|
{
|
||||||
|
struct mlxbf_gpio_state *gs = platform_get_drvdata(pdev);
|
||||||
|
|
||||||
|
writeq(gs->csave_regs.scratchpad, gs->base + MLXBF_GPIO_SCRATCHPAD);
|
||||||
|
writeq(gs->csave_regs.pad_control[0],
|
||||||
|
gs->base + MLXBF_GPIO_PAD_CONTROL_FIRST_WORD);
|
||||||
|
writeq(gs->csave_regs.pad_control[1],
|
||||||
|
gs->base + MLXBF_GPIO_PAD_CONTROL_1_FIRST_WORD);
|
||||||
|
writeq(gs->csave_regs.pad_control[2],
|
||||||
|
gs->base + MLXBF_GPIO_PAD_CONTROL_2_FIRST_WORD);
|
||||||
|
writeq(gs->csave_regs.pad_control[3],
|
||||||
|
gs->base + MLXBF_GPIO_PAD_CONTROL_3_FIRST_WORD);
|
||||||
|
writeq(gs->csave_regs.pin_dir_i, gs->base + MLXBF_GPIO_PIN_DIR_I);
|
||||||
|
writeq(gs->csave_regs.pin_dir_o, gs->base + MLXBF_GPIO_PIN_DIR_O);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
static const struct acpi_device_id mlxbf_gpio_acpi_match[] = {
|
||||||
|
{ "MLNXBF02", 0 },
|
||||||
|
{}
|
||||||
|
};
|
||||||
|
MODULE_DEVICE_TABLE(acpi, mlxbf_gpio_acpi_match);
|
||||||
|
|
||||||
|
static struct platform_driver mlxbf_gpio_driver = {
|
||||||
|
.driver = {
|
||||||
|
.name = "mlxbf_gpio",
|
||||||
|
.acpi_match_table = ACPI_PTR(mlxbf_gpio_acpi_match),
|
||||||
|
},
|
||||||
|
.probe = mlxbf_gpio_probe,
|
||||||
|
#ifdef CONFIG_PM
|
||||||
|
.suspend = mlxbf_gpio_suspend,
|
||||||
|
.resume = mlxbf_gpio_resume,
|
||||||
|
#endif
|
||||||
|
};
|
||||||
|
|
||||||
|
module_platform_driver(mlxbf_gpio_driver);
|
||||||
|
|
||||||
|
MODULE_DESCRIPTION("Mellanox BlueField GPIO Driver");
|
||||||
|
MODULE_AUTHOR("Mellanox Technologies");
|
||||||
|
MODULE_LICENSE("GPL");
|
@ -83,7 +83,6 @@ struct gpio_bank {
|
|||||||
int stride;
|
int stride;
|
||||||
u32 width;
|
u32 width;
|
||||||
int context_loss_count;
|
int context_loss_count;
|
||||||
bool workaround_enabled;
|
|
||||||
u32 quirks;
|
u32 quirks;
|
||||||
|
|
||||||
void (*set_dataout)(struct gpio_bank *bank, unsigned gpio, int enable);
|
void (*set_dataout)(struct gpio_bank *bank, unsigned gpio, int enable);
|
||||||
@ -353,6 +352,22 @@ static void omap_clear_gpio_debounce(struct gpio_bank *bank, unsigned offset)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Off mode wake-up capable GPIOs in bank(s) that are in the wakeup domain.
|
||||||
|
* See TRM section for GPIO for "Wake-Up Generation" for the list of GPIOs
|
||||||
|
* in wakeup domain. If bank->non_wakeup_gpios is not configured, assume none
|
||||||
|
* are capable waking up the system from off mode.
|
||||||
|
*/
|
||||||
|
static bool omap_gpio_is_off_wakeup_capable(struct gpio_bank *bank, u32 gpio_mask)
|
||||||
|
{
|
||||||
|
u32 no_wake = bank->non_wakeup_gpios;
|
||||||
|
|
||||||
|
if (no_wake)
|
||||||
|
return !!(~no_wake & gpio_mask);
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
static inline void omap_set_gpio_trigger(struct gpio_bank *bank, int gpio,
|
static inline void omap_set_gpio_trigger(struct gpio_bank *bank, int gpio,
|
||||||
unsigned trigger)
|
unsigned trigger)
|
||||||
{
|
{
|
||||||
@ -384,13 +399,7 @@ static inline void omap_set_gpio_trigger(struct gpio_bank *bank, int gpio,
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* This part needs to be executed always for OMAP{34xx, 44xx} */
|
/* This part needs to be executed always for OMAP{34xx, 44xx} */
|
||||||
if (!bank->regs->irqctrl) {
|
if (!bank->regs->irqctrl && !omap_gpio_is_off_wakeup_capable(bank, gpio)) {
|
||||||
/* On omap24xx proceed only when valid GPIO bit is set */
|
|
||||||
if (bank->non_wakeup_gpios) {
|
|
||||||
if (!(bank->non_wakeup_gpios & gpio_bit))
|
|
||||||
goto exit;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Log the edge gpio and manually trigger the IRQ
|
* Log the edge gpio and manually trigger the IRQ
|
||||||
* after resume if the input level changes
|
* after resume if the input level changes
|
||||||
@ -403,7 +412,6 @@ static inline void omap_set_gpio_trigger(struct gpio_bank *bank, int gpio,
|
|||||||
bank->enabled_non_wakeup_gpios &= ~gpio_bit;
|
bank->enabled_non_wakeup_gpios &= ~gpio_bit;
|
||||||
}
|
}
|
||||||
|
|
||||||
exit:
|
|
||||||
bank->level_mask =
|
bank->level_mask =
|
||||||
readl_relaxed(bank->base + bank->regs->leveldetect0) |
|
readl_relaxed(bank->base + bank->regs->leveldetect0) |
|
||||||
readl_relaxed(bank->base + bank->regs->leveldetect1);
|
readl_relaxed(bank->base + bank->regs->leveldetect1);
|
||||||
@ -1311,7 +1319,10 @@ static void omap_gpio_restore_context(struct gpio_bank *bank)
|
|||||||
static void omap_gpio_idle(struct gpio_bank *bank, bool may_lose_context)
|
static void omap_gpio_idle(struct gpio_bank *bank, bool may_lose_context)
|
||||||
{
|
{
|
||||||
struct device *dev = bank->chip.parent;
|
struct device *dev = bank->chip.parent;
|
||||||
u32 l1 = 0, l2 = 0;
|
void __iomem *base = bank->base;
|
||||||
|
u32 nowake;
|
||||||
|
|
||||||
|
bank->saved_datain = readl_relaxed(base + bank->regs->datain);
|
||||||
|
|
||||||
if (bank->funcs.idle_enable_level_quirk)
|
if (bank->funcs.idle_enable_level_quirk)
|
||||||
bank->funcs.idle_enable_level_quirk(bank);
|
bank->funcs.idle_enable_level_quirk(bank);
|
||||||
@ -1323,22 +1334,15 @@ static void omap_gpio_idle(struct gpio_bank *bank, bool may_lose_context)
|
|||||||
goto update_gpio_context_count;
|
goto update_gpio_context_count;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* If going to OFF, remove triggering for all
|
* If going to OFF, remove triggering for all wkup domain
|
||||||
* non-wakeup GPIOs. Otherwise spurious IRQs will be
|
* non-wakeup GPIOs. Otherwise spurious IRQs will be
|
||||||
* generated. See OMAP2420 Errata item 1.101.
|
* generated. See OMAP2420 Errata item 1.101.
|
||||||
*/
|
*/
|
||||||
bank->saved_datain = readl_relaxed(bank->base +
|
if (!bank->loses_context && bank->enabled_non_wakeup_gpios) {
|
||||||
bank->regs->datain);
|
nowake = bank->enabled_non_wakeup_gpios;
|
||||||
l1 = bank->context.fallingdetect;
|
omap_gpio_rmw(base, bank->regs->fallingdetect, nowake, ~nowake);
|
||||||
l2 = bank->context.risingdetect;
|
omap_gpio_rmw(base, bank->regs->risingdetect, nowake, ~nowake);
|
||||||
|
}
|
||||||
l1 &= ~bank->enabled_non_wakeup_gpios;
|
|
||||||
l2 &= ~bank->enabled_non_wakeup_gpios;
|
|
||||||
|
|
||||||
writel_relaxed(l1, bank->base + bank->regs->fallingdetect);
|
|
||||||
writel_relaxed(l2, bank->base + bank->regs->risingdetect);
|
|
||||||
|
|
||||||
bank->workaround_enabled = true;
|
|
||||||
|
|
||||||
update_gpio_context_count:
|
update_gpio_context_count:
|
||||||
if (bank->get_context_loss_count)
|
if (bank->get_context_loss_count)
|
||||||
@ -1383,11 +1387,14 @@ static void omap_gpio_unidle(struct gpio_bank *bank)
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
/* Restore changes done for OMAP2420 errata 1.101 */
|
||||||
|
writel_relaxed(bank->context.fallingdetect,
|
||||||
|
bank->base + bank->regs->fallingdetect);
|
||||||
|
writel_relaxed(bank->context.risingdetect,
|
||||||
|
bank->base + bank->regs->risingdetect);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!bank->workaround_enabled)
|
|
||||||
return;
|
|
||||||
|
|
||||||
l = readl_relaxed(bank->base + bank->regs->datain);
|
l = readl_relaxed(bank->base + bank->regs->datain);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -1437,8 +1444,6 @@ static void omap_gpio_unidle(struct gpio_bank *bank)
|
|||||||
writel_relaxed(old0, bank->base + bank->regs->leveldetect0);
|
writel_relaxed(old0, bank->base + bank->regs->leveldetect0);
|
||||||
writel_relaxed(old1, bank->base + bank->regs->leveldetect1);
|
writel_relaxed(old1, bank->base + bank->regs->leveldetect1);
|
||||||
}
|
}
|
||||||
|
|
||||||
bank->workaround_enabled = false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static int gpio_omap_cpu_notifier(struct notifier_block *nb,
|
static int gpio_omap_cpu_notifier(struct notifier_block *nb,
|
||||||
|
@ -1178,6 +1178,7 @@ static const struct of_device_id pca953x_dt_ids[] = {
|
|||||||
{ .compatible = "ti,tca6416", .data = OF_953X(16, PCA_INT), },
|
{ .compatible = "ti,tca6416", .data = OF_953X(16, PCA_INT), },
|
||||||
{ .compatible = "ti,tca6424", .data = OF_953X(24, PCA_INT), },
|
{ .compatible = "ti,tca6424", .data = OF_953X(24, PCA_INT), },
|
||||||
|
|
||||||
|
{ .compatible = "onnn,cat9554", .data = OF_953X( 8, PCA_INT), },
|
||||||
{ .compatible = "onnn,pca9654", .data = OF_953X( 8, PCA_INT), },
|
{ .compatible = "onnn,pca9654", .data = OF_953X( 8, PCA_INT), },
|
||||||
|
|
||||||
{ .compatible = "exar,xra1202", .data = OF_953X( 8, 0), },
|
{ .compatible = "exar,xra1202", .data = OF_953X( 8, 0), },
|
||||||
|
@ -29,6 +29,7 @@ struct fsl_gpio_soc_data {
|
|||||||
|
|
||||||
struct vf610_gpio_port {
|
struct vf610_gpio_port {
|
||||||
struct gpio_chip gc;
|
struct gpio_chip gc;
|
||||||
|
struct irq_chip ic;
|
||||||
void __iomem *base;
|
void __iomem *base;
|
||||||
void __iomem *gpio_base;
|
void __iomem *gpio_base;
|
||||||
const struct fsl_gpio_soc_data *sdata;
|
const struct fsl_gpio_soc_data *sdata;
|
||||||
@ -60,8 +61,6 @@ struct vf610_gpio_port {
|
|||||||
#define PORT_INT_EITHER_EDGE 0xb
|
#define PORT_INT_EITHER_EDGE 0xb
|
||||||
#define PORT_INT_LOGIC_ONE 0xc
|
#define PORT_INT_LOGIC_ONE 0xc
|
||||||
|
|
||||||
static struct irq_chip vf610_gpio_irq_chip;
|
|
||||||
|
|
||||||
static const struct fsl_gpio_soc_data imx_data = {
|
static const struct fsl_gpio_soc_data imx_data = {
|
||||||
.have_paddr = true,
|
.have_paddr = true,
|
||||||
};
|
};
|
||||||
@ -86,28 +85,24 @@ static int vf610_gpio_get(struct gpio_chip *gc, unsigned int gpio)
|
|||||||
{
|
{
|
||||||
struct vf610_gpio_port *port = gpiochip_get_data(gc);
|
struct vf610_gpio_port *port = gpiochip_get_data(gc);
|
||||||
unsigned long mask = BIT(gpio);
|
unsigned long mask = BIT(gpio);
|
||||||
void __iomem *addr;
|
unsigned long offset = GPIO_PDIR;
|
||||||
|
|
||||||
if (port->sdata && port->sdata->have_paddr) {
|
if (port->sdata && port->sdata->have_paddr) {
|
||||||
mask &= vf610_gpio_readl(port->gpio_base + GPIO_PDDR);
|
mask &= vf610_gpio_readl(port->gpio_base + GPIO_PDDR);
|
||||||
addr = mask ? port->gpio_base + GPIO_PDOR :
|
if (mask)
|
||||||
port->gpio_base + GPIO_PDIR;
|
offset = GPIO_PDOR;
|
||||||
return !!(vf610_gpio_readl(addr) & BIT(gpio));
|
|
||||||
} else {
|
|
||||||
return !!(vf610_gpio_readl(port->gpio_base + GPIO_PDIR)
|
|
||||||
& BIT(gpio));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return !!(vf610_gpio_readl(port->gpio_base + offset) & BIT(gpio));
|
||||||
}
|
}
|
||||||
|
|
||||||
static void vf610_gpio_set(struct gpio_chip *gc, unsigned int gpio, int val)
|
static void vf610_gpio_set(struct gpio_chip *gc, unsigned int gpio, int val)
|
||||||
{
|
{
|
||||||
struct vf610_gpio_port *port = gpiochip_get_data(gc);
|
struct vf610_gpio_port *port = gpiochip_get_data(gc);
|
||||||
unsigned long mask = BIT(gpio);
|
unsigned long mask = BIT(gpio);
|
||||||
|
unsigned long offset = val ? GPIO_PSOR : GPIO_PCOR;
|
||||||
|
|
||||||
if (val)
|
vf610_gpio_writel(mask, port->gpio_base + offset);
|
||||||
vf610_gpio_writel(mask, port->gpio_base + GPIO_PSOR);
|
|
||||||
else
|
|
||||||
vf610_gpio_writel(mask, port->gpio_base + GPIO_PCOR);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static int vf610_gpio_direction_input(struct gpio_chip *chip, unsigned gpio)
|
static int vf610_gpio_direction_input(struct gpio_chip *chip, unsigned gpio)
|
||||||
@ -237,14 +232,10 @@ static int vf610_gpio_irq_set_wake(struct irq_data *d, u32 enable)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static struct irq_chip vf610_gpio_irq_chip = {
|
static void vf610_gpio_disable_clk(void *data)
|
||||||
.name = "gpio-vf610",
|
{
|
||||||
.irq_ack = vf610_gpio_irq_ack,
|
clk_disable_unprepare(data);
|
||||||
.irq_mask = vf610_gpio_irq_mask,
|
}
|
||||||
.irq_unmask = vf610_gpio_irq_unmask,
|
|
||||||
.irq_set_type = vf610_gpio_irq_set_type,
|
|
||||||
.irq_set_wake = vf610_gpio_irq_set_wake,
|
|
||||||
};
|
|
||||||
|
|
||||||
static int vf610_gpio_probe(struct platform_device *pdev)
|
static int vf610_gpio_probe(struct platform_device *pdev)
|
||||||
{
|
{
|
||||||
@ -252,10 +243,11 @@ static int vf610_gpio_probe(struct platform_device *pdev)
|
|||||||
struct device_node *np = dev->of_node;
|
struct device_node *np = dev->of_node;
|
||||||
struct vf610_gpio_port *port;
|
struct vf610_gpio_port *port;
|
||||||
struct gpio_chip *gc;
|
struct gpio_chip *gc;
|
||||||
|
struct irq_chip *ic;
|
||||||
int i;
|
int i;
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
port = devm_kzalloc(&pdev->dev, sizeof(*port), GFP_KERNEL);
|
port = devm_kzalloc(dev, sizeof(*port), GFP_KERNEL);
|
||||||
if (!port)
|
if (!port)
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
|
|
||||||
@ -272,11 +264,15 @@ static int vf610_gpio_probe(struct platform_device *pdev)
|
|||||||
if (port->irq < 0)
|
if (port->irq < 0)
|
||||||
return port->irq;
|
return port->irq;
|
||||||
|
|
||||||
port->clk_port = devm_clk_get(&pdev->dev, "port");
|
port->clk_port = devm_clk_get(dev, "port");
|
||||||
if (!IS_ERR(port->clk_port)) {
|
if (!IS_ERR(port->clk_port)) {
|
||||||
ret = clk_prepare_enable(port->clk_port);
|
ret = clk_prepare_enable(port->clk_port);
|
||||||
if (ret)
|
if (ret)
|
||||||
return ret;
|
return ret;
|
||||||
|
ret = devm_add_action_or_reset(dev, vf610_gpio_disable_clk,
|
||||||
|
port->clk_port);
|
||||||
|
if (ret)
|
||||||
|
return ret;
|
||||||
} else if (port->clk_port == ERR_PTR(-EPROBE_DEFER)) {
|
} else if (port->clk_port == ERR_PTR(-EPROBE_DEFER)) {
|
||||||
/*
|
/*
|
||||||
* Percolate deferrals, for anything else,
|
* Percolate deferrals, for anything else,
|
||||||
@ -285,20 +281,19 @@ static int vf610_gpio_probe(struct platform_device *pdev)
|
|||||||
return PTR_ERR(port->clk_port);
|
return PTR_ERR(port->clk_port);
|
||||||
}
|
}
|
||||||
|
|
||||||
port->clk_gpio = devm_clk_get(&pdev->dev, "gpio");
|
port->clk_gpio = devm_clk_get(dev, "gpio");
|
||||||
if (!IS_ERR(port->clk_gpio)) {
|
if (!IS_ERR(port->clk_gpio)) {
|
||||||
ret = clk_prepare_enable(port->clk_gpio);
|
ret = clk_prepare_enable(port->clk_gpio);
|
||||||
if (ret) {
|
if (ret)
|
||||||
clk_disable_unprepare(port->clk_port);
|
return ret;
|
||||||
|
ret = devm_add_action_or_reset(dev, vf610_gpio_disable_clk,
|
||||||
|
port->clk_gpio);
|
||||||
|
if (ret)
|
||||||
return ret;
|
return ret;
|
||||||
}
|
|
||||||
} else if (port->clk_gpio == ERR_PTR(-EPROBE_DEFER)) {
|
} else if (port->clk_gpio == ERR_PTR(-EPROBE_DEFER)) {
|
||||||
clk_disable_unprepare(port->clk_port);
|
|
||||||
return PTR_ERR(port->clk_gpio);
|
return PTR_ERR(port->clk_gpio);
|
||||||
}
|
}
|
||||||
|
|
||||||
platform_set_drvdata(pdev, port);
|
|
||||||
|
|
||||||
gc = &port->gc;
|
gc = &port->gc;
|
||||||
gc->of_node = np;
|
gc->of_node = np;
|
||||||
gc->parent = dev;
|
gc->parent = dev;
|
||||||
@ -313,7 +308,15 @@ static int vf610_gpio_probe(struct platform_device *pdev)
|
|||||||
gc->direction_output = vf610_gpio_direction_output;
|
gc->direction_output = vf610_gpio_direction_output;
|
||||||
gc->set = vf610_gpio_set;
|
gc->set = vf610_gpio_set;
|
||||||
|
|
||||||
ret = gpiochip_add_data(gc, port);
|
ic = &port->ic;
|
||||||
|
ic->name = "gpio-vf610";
|
||||||
|
ic->irq_ack = vf610_gpio_irq_ack;
|
||||||
|
ic->irq_mask = vf610_gpio_irq_mask;
|
||||||
|
ic->irq_unmask = vf610_gpio_irq_unmask;
|
||||||
|
ic->irq_set_type = vf610_gpio_irq_set_type;
|
||||||
|
ic->irq_set_wake = vf610_gpio_irq_set_wake;
|
||||||
|
|
||||||
|
ret = devm_gpiochip_add_data(dev, gc, port);
|
||||||
if (ret < 0)
|
if (ret < 0)
|
||||||
return ret;
|
return ret;
|
||||||
|
|
||||||
@ -324,39 +327,23 @@ static int vf610_gpio_probe(struct platform_device *pdev)
|
|||||||
/* Clear the interrupt status register for all GPIO's */
|
/* Clear the interrupt status register for all GPIO's */
|
||||||
vf610_gpio_writel(~0, port->base + PORT_ISFR);
|
vf610_gpio_writel(~0, port->base + PORT_ISFR);
|
||||||
|
|
||||||
ret = gpiochip_irqchip_add(gc, &vf610_gpio_irq_chip, 0,
|
ret = gpiochip_irqchip_add(gc, ic, 0, handle_edge_irq, IRQ_TYPE_NONE);
|
||||||
handle_edge_irq, IRQ_TYPE_NONE);
|
|
||||||
if (ret) {
|
if (ret) {
|
||||||
dev_err(dev, "failed to add irqchip\n");
|
dev_err(dev, "failed to add irqchip\n");
|
||||||
gpiochip_remove(gc);
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
gpiochip_set_chained_irqchip(gc, &vf610_gpio_irq_chip, port->irq,
|
gpiochip_set_chained_irqchip(gc, ic, port->irq,
|
||||||
vf610_gpio_irq_handler);
|
vf610_gpio_irq_handler);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int vf610_gpio_remove(struct platform_device *pdev)
|
|
||||||
{
|
|
||||||
struct vf610_gpio_port *port = platform_get_drvdata(pdev);
|
|
||||||
|
|
||||||
gpiochip_remove(&port->gc);
|
|
||||||
if (!IS_ERR(port->clk_port))
|
|
||||||
clk_disable_unprepare(port->clk_port);
|
|
||||||
if (!IS_ERR(port->clk_gpio))
|
|
||||||
clk_disable_unprepare(port->clk_gpio);
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static struct platform_driver vf610_gpio_driver = {
|
static struct platform_driver vf610_gpio_driver = {
|
||||||
.driver = {
|
.driver = {
|
||||||
.name = "gpio-vf610",
|
.name = "gpio-vf610",
|
||||||
.of_match_table = vf610_gpio_dt_ids,
|
.of_match_table = vf610_gpio_dt_ids,
|
||||||
},
|
},
|
||||||
.probe = vf610_gpio_probe,
|
.probe = vf610_gpio_probe,
|
||||||
.remove = vf610_gpio_remove,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
builtin_platform_driver(vf610_gpio_driver);
|
builtin_platform_driver(vf610_gpio_driver);
|
||||||
|
@ -24,13 +24,13 @@
|
|||||||
*
|
*
|
||||||
* @node: list-entry of the events list of the struct acpi_gpio_chip
|
* @node: list-entry of the events list of the struct acpi_gpio_chip
|
||||||
* @handle: handle of ACPI method to execute when the IRQ triggers
|
* @handle: handle of ACPI method to execute when the IRQ triggers
|
||||||
* @handler: irq_handler to pass to request_irq when requesting the IRQ
|
* @handler: handler function to pass to request_irq() when requesting the IRQ
|
||||||
* @pin: GPIO pin number on the gpio_chip
|
* @pin: GPIO pin number on the struct gpio_chip
|
||||||
* @irq: Linux IRQ number for the event, for request_ / free_irq
|
* @irq: Linux IRQ number for the event, for request_irq() / free_irq()
|
||||||
* @irqflags: flags to pass to request_irq when requesting the IRQ
|
* @irqflags: flags to pass to request_irq() when requesting the IRQ
|
||||||
* @irq_is_wake: If the ACPI flags indicate the IRQ is a wakeup source
|
* @irq_is_wake: If the ACPI flags indicate the IRQ is a wakeup source
|
||||||
* @irq_requested:True if request_irq has been done
|
* @irq_requested:True if request_irq() has been done
|
||||||
* @desc: gpio_desc for the GPIO pin for this event
|
* @desc: struct gpio_desc for the GPIO pin for this event
|
||||||
*/
|
*/
|
||||||
struct acpi_gpio_event {
|
struct acpi_gpio_event {
|
||||||
struct list_head node;
|
struct list_head node;
|
||||||
@ -65,10 +65,10 @@ struct acpi_gpio_chip {
|
|||||||
};
|
};
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* For gpiochips which call acpi_gpiochip_request_interrupts() before late_init
|
* For GPIO chips which call acpi_gpiochip_request_interrupts() before late_init
|
||||||
* (so builtin drivers) we register the ACPI GpioInt IRQ handlers from a
|
* (so builtin drivers) we register the ACPI GpioInt IRQ handlers from a
|
||||||
* late_initcall_sync handler, so that other builtin drivers can register their
|
* late_initcall_sync() handler, so that other builtin drivers can register their
|
||||||
* OpRegions before the event handlers can run. This list contains gpiochips
|
* OpRegions before the event handlers can run. This list contains GPIO chips
|
||||||
* for which the acpi_gpiochip_request_irqs() call has been deferred.
|
* for which the acpi_gpiochip_request_irqs() call has been deferred.
|
||||||
*/
|
*/
|
||||||
static DEFINE_MUTEX(acpi_gpio_deferred_req_irqs_lock);
|
static DEFINE_MUTEX(acpi_gpio_deferred_req_irqs_lock);
|
||||||
@ -90,7 +90,7 @@ static int acpi_gpiochip_find(struct gpio_chip *gc, void *data)
|
|||||||
*
|
*
|
||||||
* Return: GPIO descriptor to use with Linux generic GPIO API, or ERR_PTR
|
* Return: GPIO descriptor to use with Linux generic GPIO API, or ERR_PTR
|
||||||
* error value. Specifically returns %-EPROBE_DEFER if the referenced GPIO
|
* error value. Specifically returns %-EPROBE_DEFER if the referenced GPIO
|
||||||
* controller does not have gpiochip registered at the moment. This is to
|
* controller does not have GPIO chip registered at the moment. This is to
|
||||||
* support probe deferral.
|
* support probe deferral.
|
||||||
*/
|
*/
|
||||||
static struct gpio_desc *acpi_get_gpiod(char *path, int pin)
|
static struct gpio_desc *acpi_get_gpiod(char *path, int pin)
|
||||||
@ -287,9 +287,9 @@ static acpi_status acpi_gpiochip_alloc_event(struct acpi_resource *ares,
|
|||||||
*
|
*
|
||||||
* ACPI5 platforms can use GPIO signaled ACPI events. These GPIO interrupts are
|
* ACPI5 platforms can use GPIO signaled ACPI events. These GPIO interrupts are
|
||||||
* handled by ACPI event methods which need to be called from the GPIO
|
* handled by ACPI event methods which need to be called from the GPIO
|
||||||
* chip's interrupt handler. acpi_gpiochip_request_interrupts finds out which
|
* chip's interrupt handler. acpi_gpiochip_request_interrupts() finds out which
|
||||||
* gpio pins have acpi event methods and assigns interrupt handlers that calls
|
* GPIO pins have ACPI event methods and assigns interrupt handlers that calls
|
||||||
* the acpi event methods for those pins.
|
* the ACPI event methods for those pins.
|
||||||
*/
|
*/
|
||||||
void acpi_gpiochip_request_interrupts(struct gpio_chip *chip)
|
void acpi_gpiochip_request_interrupts(struct gpio_chip *chip)
|
||||||
{
|
{
|
||||||
@ -653,7 +653,7 @@ static int acpi_gpio_property_lookup(struct fwnode_handle *fwnode,
|
|||||||
* that case @index is used to select the GPIO entry in the property value
|
* that case @index is used to select the GPIO entry in the property value
|
||||||
* (in case of multiple).
|
* (in case of multiple).
|
||||||
*
|
*
|
||||||
* If the GPIO cannot be translated or there is an error an ERR_PTR is
|
* If the GPIO cannot be translated or there is an error, an ERR_PTR is
|
||||||
* returned.
|
* returned.
|
||||||
*
|
*
|
||||||
* Note: if the GPIO resource has multiple entries in the pin list, this
|
* Note: if the GPIO resource has multiple entries in the pin list, this
|
||||||
@ -751,10 +751,13 @@ struct gpio_desc *acpi_find_gpio(struct device *dev,
|
|||||||
* @index: index of GpioIo/GpioInt resource (starting from %0)
|
* @index: index of GpioIo/GpioInt resource (starting from %0)
|
||||||
* @info: info pointer to fill in (optional)
|
* @info: info pointer to fill in (optional)
|
||||||
*
|
*
|
||||||
* If @fwnode is an ACPI device object, call %acpi_get_gpiod_by_index() for it.
|
* If @fwnode is an ACPI device object, call acpi_get_gpiod_by_index() for it.
|
||||||
* Otherwise (ie. it is a data-only non-device object), use the property-based
|
* Otherwise (i.e. it is a data-only non-device object), use the property-based
|
||||||
* GPIO lookup to get to the GPIO resource with the relevant information and use
|
* GPIO lookup to get to the GPIO resource with the relevant information and use
|
||||||
* that to obtain the GPIO descriptor to return.
|
* that to obtain the GPIO descriptor to return.
|
||||||
|
*
|
||||||
|
* If the GPIO cannot be translated or there is an error an ERR_PTR is
|
||||||
|
* returned.
|
||||||
*/
|
*/
|
||||||
struct gpio_desc *acpi_node_get_gpiod(struct fwnode_handle *fwnode,
|
struct gpio_desc *acpi_node_get_gpiod(struct fwnode_handle *fwnode,
|
||||||
const char *propname, int index,
|
const char *propname, int index,
|
||||||
@ -1158,11 +1161,13 @@ static int acpi_find_gpio_count(struct acpi_resource *ares, void *data)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* acpi_gpio_count - return the number of GPIOs associated with a
|
* acpi_gpio_count - count the GPIOs associated with a device / function
|
||||||
* device / function or -ENOENT if no GPIO has been
|
* @dev: GPIO consumer, can be %NULL for system-global GPIOs
|
||||||
* assigned to the requested function.
|
|
||||||
* @dev: GPIO consumer, can be NULL for system-global GPIOs
|
|
||||||
* @con_id: function within the GPIO consumer
|
* @con_id: function within the GPIO consumer
|
||||||
|
*
|
||||||
|
* Return:
|
||||||
|
* The number of GPIOs associated with a device / function or %-ENOENT,
|
||||||
|
* if no GPIO has been assigned to the requested function.
|
||||||
*/
|
*/
|
||||||
int acpi_gpio_count(struct device *dev, const char *con_id)
|
int acpi_gpio_count(struct device *dev, const char *con_id)
|
||||||
{
|
{
|
||||||
|
@ -4626,7 +4626,8 @@ EXPORT_SYMBOL_GPL(gpiod_get_array_optional);
|
|||||||
*/
|
*/
|
||||||
void gpiod_put(struct gpio_desc *desc)
|
void gpiod_put(struct gpio_desc *desc)
|
||||||
{
|
{
|
||||||
gpiod_free(desc);
|
if (desc)
|
||||||
|
gpiod_free(desc);
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL_GPL(gpiod_put);
|
EXPORT_SYMBOL_GPL(gpiod_put);
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user