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,tca9539
|
||||
ti,tca9554
|
||||
onnn,cat9554
|
||||
onnn,pca9654
|
||||
exar,xra1202
|
||||
- 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
|
||||
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
|
||||
def_bool y
|
||||
depends on PPC_MPC52xx
|
||||
|
@ -1316,6 +1302,13 @@ config GPIO_MERRIFIELD
|
|||
help
|
||||
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
|
||||
tristate "OKI SEMICONDUCTOR ML7213 IOH GPIO support"
|
||||
depends on X86 || COMPILE_TEST
|
||||
|
@ -1442,4 +1435,16 @@ config GPIO_VIPERBOARD
|
|||
|
||||
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
|
||||
|
|
|
@ -85,6 +85,7 @@ obj-$(CONFIG_GPIO_MENZ127) += gpio-menz127.o
|
|||
obj-$(CONFIG_GPIO_MERRIFIELD) += gpio-merrifield.o
|
||||
obj-$(CONFIG_GPIO_MC33880) += gpio-mc33880.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_MM_LANTIQ) += gpio-mm-lantiq.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
|
||||
*
|
||||
* Copyright (C) 2010 Gabor Juhos <juhosg@openwrt.org>
|
||||
* 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/slab.h>
|
||||
#include <linux/gpio/driver.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
|
||||
|
||||
|
@ -116,10 +113,9 @@ static int gen_74x164_probe(struct spi_device *spi)
|
|||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
if (of_property_read_u32(spi->dev.of_node, "registers-number",
|
||||
&nregs)) {
|
||||
dev_err(&spi->dev,
|
||||
"Missing registers-number property in the DT.\n");
|
||||
ret = device_property_read_u32(&spi->dev, "registers-number", &nregs);
|
||||
if (ret) {
|
||||
dev_err(&spi->dev, "Missing 'registers-number' property.\n");
|
||||
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;
|
||||
u32 width;
|
||||
int context_loss_count;
|
||||
bool workaround_enabled;
|
||||
u32 quirks;
|
||||
|
||||
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,
|
||||
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} */
|
||||
if (!bank->regs->irqctrl) {
|
||||
/* On omap24xx proceed only when valid GPIO bit is set */
|
||||
if (bank->non_wakeup_gpios) {
|
||||
if (!(bank->non_wakeup_gpios & gpio_bit))
|
||||
goto exit;
|
||||
}
|
||||
|
||||
if (!bank->regs->irqctrl && !omap_gpio_is_off_wakeup_capable(bank, gpio)) {
|
||||
/*
|
||||
* Log the edge gpio and manually trigger the IRQ
|
||||
* 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;
|
||||
}
|
||||
|
||||
exit:
|
||||
bank->level_mask =
|
||||
readl_relaxed(bank->base + bank->regs->leveldetect0) |
|
||||
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)
|
||||
{
|
||||
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)
|
||||
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;
|
||||
|
||||
/*
|
||||
* 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
|
||||
* generated. See OMAP2420 Errata item 1.101.
|
||||
*/
|
||||
bank->saved_datain = readl_relaxed(bank->base +
|
||||
bank->regs->datain);
|
||||
l1 = bank->context.fallingdetect;
|
||||
l2 = bank->context.risingdetect;
|
||||
|
||||
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;
|
||||
if (!bank->loses_context && bank->enabled_non_wakeup_gpios) {
|
||||
nowake = bank->enabled_non_wakeup_gpios;
|
||||
omap_gpio_rmw(base, bank->regs->fallingdetect, nowake, ~nowake);
|
||||
omap_gpio_rmw(base, bank->regs->risingdetect, nowake, ~nowake);
|
||||
}
|
||||
|
||||
update_gpio_context_count:
|
||||
if (bank->get_context_loss_count)
|
||||
|
@ -1383,11 +1387,14 @@ static void omap_gpio_unidle(struct gpio_bank *bank)
|
|||
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);
|
||||
|
||||
/*
|
||||
|
@ -1437,8 +1444,6 @@ static void omap_gpio_unidle(struct gpio_bank *bank)
|
|||
writel_relaxed(old0, bank->base + bank->regs->leveldetect0);
|
||||
writel_relaxed(old1, bank->base + bank->regs->leveldetect1);
|
||||
}
|
||||
|
||||
bank->workaround_enabled = false;
|
||||
}
|
||||
|
||||
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,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 = "exar,xra1202", .data = OF_953X( 8, 0), },
|
||||
|
|
|
@ -29,6 +29,7 @@ struct fsl_gpio_soc_data {
|
|||
|
||||
struct vf610_gpio_port {
|
||||
struct gpio_chip gc;
|
||||
struct irq_chip ic;
|
||||
void __iomem *base;
|
||||
void __iomem *gpio_base;
|
||||
const struct fsl_gpio_soc_data *sdata;
|
||||
|
@ -60,8 +61,6 @@ struct vf610_gpio_port {
|
|||
#define PORT_INT_EITHER_EDGE 0xb
|
||||
#define PORT_INT_LOGIC_ONE 0xc
|
||||
|
||||
static struct irq_chip vf610_gpio_irq_chip;
|
||||
|
||||
static const struct fsl_gpio_soc_data imx_data = {
|
||||
.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);
|
||||
unsigned long mask = BIT(gpio);
|
||||
void __iomem *addr;
|
||||
unsigned long offset = GPIO_PDIR;
|
||||
|
||||
if (port->sdata && port->sdata->have_paddr) {
|
||||
mask &= vf610_gpio_readl(port->gpio_base + GPIO_PDDR);
|
||||
addr = mask ? port->gpio_base + GPIO_PDOR :
|
||||
port->gpio_base + GPIO_PDIR;
|
||||
return !!(vf610_gpio_readl(addr) & BIT(gpio));
|
||||
} else {
|
||||
return !!(vf610_gpio_readl(port->gpio_base + GPIO_PDIR)
|
||||
& BIT(gpio));
|
||||
if (mask)
|
||||
offset = GPIO_PDOR;
|
||||
}
|
||||
|
||||
return !!(vf610_gpio_readl(port->gpio_base + offset) & BIT(gpio));
|
||||
}
|
||||
|
||||
static void vf610_gpio_set(struct gpio_chip *gc, unsigned int gpio, int val)
|
||||
{
|
||||
struct vf610_gpio_port *port = gpiochip_get_data(gc);
|
||||
unsigned long mask = BIT(gpio);
|
||||
unsigned long offset = val ? GPIO_PSOR : GPIO_PCOR;
|
||||
|
||||
if (val)
|
||||
vf610_gpio_writel(mask, port->gpio_base + GPIO_PSOR);
|
||||
else
|
||||
vf610_gpio_writel(mask, port->gpio_base + GPIO_PCOR);
|
||||
vf610_gpio_writel(mask, port->gpio_base + offset);
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
static struct irq_chip vf610_gpio_irq_chip = {
|
||||
.name = "gpio-vf610",
|
||||
.irq_ack = vf610_gpio_irq_ack,
|
||||
.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 void vf610_gpio_disable_clk(void *data)
|
||||
{
|
||||
clk_disable_unprepare(data);
|
||||
}
|
||||
|
||||
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 vf610_gpio_port *port;
|
||||
struct gpio_chip *gc;
|
||||
struct irq_chip *ic;
|
||||
int i;
|
||||
int ret;
|
||||
|
||||
port = devm_kzalloc(&pdev->dev, sizeof(*port), GFP_KERNEL);
|
||||
port = devm_kzalloc(dev, sizeof(*port), GFP_KERNEL);
|
||||
if (!port)
|
||||
return -ENOMEM;
|
||||
|
||||
|
@ -272,11 +264,15 @@ static int vf610_gpio_probe(struct platform_device *pdev)
|
|||
if (port->irq < 0)
|
||||
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)) {
|
||||
ret = clk_prepare_enable(port->clk_port);
|
||||
if (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)) {
|
||||
/*
|
||||
* Percolate deferrals, for anything else,
|
||||
|
@ -285,20 +281,19 @@ static int vf610_gpio_probe(struct platform_device *pdev)
|
|||
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)) {
|
||||
ret = clk_prepare_enable(port->clk_gpio);
|
||||
if (ret) {
|
||||
clk_disable_unprepare(port->clk_port);
|
||||
if (ret)
|
||||
return ret;
|
||||
ret = devm_add_action_or_reset(dev, vf610_gpio_disable_clk,
|
||||
port->clk_gpio);
|
||||
if (ret)
|
||||
return ret;
|
||||
}
|
||||
} else if (port->clk_gpio == ERR_PTR(-EPROBE_DEFER)) {
|
||||
clk_disable_unprepare(port->clk_port);
|
||||
return PTR_ERR(port->clk_gpio);
|
||||
}
|
||||
|
||||
platform_set_drvdata(pdev, port);
|
||||
|
||||
gc = &port->gc;
|
||||
gc->of_node = np;
|
||||
gc->parent = dev;
|
||||
|
@ -313,7 +308,15 @@ static int vf610_gpio_probe(struct platform_device *pdev)
|
|||
gc->direction_output = vf610_gpio_direction_output;
|
||||
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)
|
||||
return ret;
|
||||
|
||||
|
@ -324,39 +327,23 @@ static int vf610_gpio_probe(struct platform_device *pdev)
|
|||
/* Clear the interrupt status register for all GPIO's */
|
||||
vf610_gpio_writel(~0, port->base + PORT_ISFR);
|
||||
|
||||
ret = gpiochip_irqchip_add(gc, &vf610_gpio_irq_chip, 0,
|
||||
handle_edge_irq, IRQ_TYPE_NONE);
|
||||
ret = gpiochip_irqchip_add(gc, ic, 0, handle_edge_irq, IRQ_TYPE_NONE);
|
||||
if (ret) {
|
||||
dev_err(dev, "failed to add irqchip\n");
|
||||
gpiochip_remove(gc);
|
||||
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);
|
||||
|
||||
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 = {
|
||||
.driver = {
|
||||
.name = "gpio-vf610",
|
||||
.of_match_table = vf610_gpio_dt_ids,
|
||||
},
|
||||
.probe = vf610_gpio_probe,
|
||||
.remove = vf610_gpio_remove,
|
||||
};
|
||||
|
||||
builtin_platform_driver(vf610_gpio_driver);
|
||||
|
|
|
@ -24,13 +24,13 @@
|
|||
*
|
||||
* @node: list-entry of the events list of the struct acpi_gpio_chip
|
||||
* @handle: handle of ACPI method to execute when the IRQ triggers
|
||||
* @handler: irq_handler to pass to request_irq when requesting the IRQ
|
||||
* @pin: GPIO pin number on the gpio_chip
|
||||
* @irq: Linux IRQ number for the event, for request_ / free_irq
|
||||
* @irqflags: flags 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 struct gpio_chip
|
||||
* @irq: Linux IRQ number for the event, for request_irq() / free_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_requested:True if request_irq has been done
|
||||
* @desc: gpio_desc for the GPIO pin for this event
|
||||
* @irq_requested:True if request_irq() has been done
|
||||
* @desc: struct gpio_desc for the GPIO pin for this event
|
||||
*/
|
||||
struct acpi_gpio_event {
|
||||
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
|
||||
* late_initcall_sync handler, so that other builtin drivers can register their
|
||||
* OpRegions before the event handlers can run. This list contains gpiochips
|
||||
* late_initcall_sync() handler, so that other builtin drivers can register their
|
||||
* OpRegions before the event handlers can run. This list contains GPIO chips
|
||||
* for which the acpi_gpiochip_request_irqs() call has been deferred.
|
||||
*/
|
||||
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
|
||||
* 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.
|
||||
*/
|
||||
static struct gpio_desc *acpi_get_gpiod(char *path, int pin)
|
||||
|
@ -287,9 +287,9 @@ fail_free_desc:
|
|||
*
|
||||
* 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
|
||||
* chip's interrupt handler. acpi_gpiochip_request_interrupts finds out which
|
||||
* gpio pins have acpi event methods and assigns interrupt handlers that calls
|
||||
* the acpi event methods for those pins.
|
||||
* chip's interrupt handler. acpi_gpiochip_request_interrupts() finds out which
|
||||
* GPIO pins have ACPI event methods and assigns interrupt handlers that calls
|
||||
* the ACPI event methods for those pins.
|
||||
*/
|
||||
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
|
||||
* (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.
|
||||
*
|
||||
* 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)
|
||||
* @info: info pointer to fill in (optional)
|
||||
*
|
||||
* 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
|
||||
* If @fwnode is an ACPI device object, call acpi_get_gpiod_by_index() for it.
|
||||
* 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
|
||||
* 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,
|
||||
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
|
||||
* device / function or -ENOENT if no GPIO has been
|
||||
* assigned to the requested function.
|
||||
* @dev: GPIO consumer, can be NULL for system-global GPIOs
|
||||
* acpi_gpio_count - count the GPIOs associated with a device / function
|
||||
* @dev: GPIO consumer, can be %NULL for system-global GPIOs
|
||||
* @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)
|
||||
{
|
||||
|
|
|
@ -4626,7 +4626,8 @@ EXPORT_SYMBOL_GPL(gpiod_get_array_optional);
|
|||
*/
|
||||
void gpiod_put(struct gpio_desc *desc)
|
||||
{
|
||||
gpiod_free(desc);
|
||||
if (desc)
|
||||
gpiod_free(desc);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(gpiod_put);
|
||||
|
||||
|
|
Loading…
Reference in a new issue