summaryrefslogtreecommitdiffstats
path: root/drivers/gpio
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/gpio')
-rw-r--r--drivers/gpio/Kconfig94
-rw-r--r--drivers/gpio/Makefile9
-rw-r--r--drivers/gpio/gpio-74164.c25
-rw-r--r--drivers/gpio/gpio-74xx-mmio.c166
-rw-r--r--drivers/gpio/gpio-ath79.c27
-rw-r--r--drivers/gpio/gpio-clps711x.c24
-rw-r--r--drivers/gpio/gpio-davinci.c100
-rw-r--r--drivers/gpio/gpio-digic.c29
-rw-r--r--drivers/gpio/gpio-dw.c35
-rw-r--r--drivers/gpio/gpio-generic.c473
-rw-r--r--drivers/gpio/gpio-imx.c37
-rw-r--r--drivers/gpio/gpio-intel.c198
-rw-r--r--drivers/gpio/gpio-jz4740.c29
-rw-r--r--drivers/gpio/gpio-latch.c196
-rw-r--r--drivers/gpio/gpio-libftdi1.c29
-rw-r--r--drivers/gpio/gpio-malta-fpga-i2c.c30
-rw-r--r--drivers/gpio/gpio-mpc8xxx.c32
-rw-r--r--drivers/gpio/gpio-mxs.c26
-rw-r--r--drivers/gpio/gpio-omap.c47
-rw-r--r--drivers/gpio/gpio-orion.c32
-rw-r--r--drivers/gpio/gpio-pca953x.c58
-rw-r--r--drivers/gpio/gpio-pcf857x.c23
-rw-r--r--drivers/gpio/gpio-pl061.c20
-rw-r--r--drivers/gpio/gpio-raspberrypi-exp.c273
-rw-r--r--drivers/gpio/gpio-rockchip.c211
-rw-r--r--drivers/gpio/gpio-sifive.c88
-rw-r--r--drivers/gpio/gpio-starfive-vic.c178
-rw-r--r--drivers/gpio/gpio-stmpe.c27
-rw-r--r--drivers/gpio/gpio-sx150x.c19
-rw-r--r--drivers/gpio/gpio-tegra.c30
-rw-r--r--drivers/gpio/gpio-vf610.c137
-rw-r--r--drivers/gpio/gpio-zynq.c437
-rw-r--r--drivers/gpio/gpiolib.c960
33 files changed, 3311 insertions, 788 deletions
diff --git a/drivers/gpio/Kconfig b/drivers/gpio/Kconfig
index 0f924d135f..d9bb68e06b 100644
--- a/drivers/gpio/Kconfig
+++ b/drivers/gpio/Kconfig
@@ -1,3 +1,4 @@
+# SPDX-License-Identifier: GPL-2.0-only
config GPIOLIB
bool
select GENERIC_GPIO
@@ -11,7 +12,7 @@ config GPIO_GENERIC
config GPIO_DIGIC
bool "GPIO support for Canon DIGIC"
- depends on ARCH_DIGIC
+ depends on ARCH_DIGIC || COMPILE_TEST
config GPIO_74164
bool "Generic SPI attached shift register"
@@ -21,17 +22,31 @@ config GPIO_74164
shift registers. This driver can be used to provide access
to more gpio outputs.
+config GPIO_74XX_MMIO
+ tristate "GPIO driver for 74xx-ICs with MMIO access"
+ depends on OFDEVICE
+ select GPIO_GENERIC
+ help
+ Say yes here to support GPIO functionality for 74xx-compatible ICs
+ with MMIO access. Compatible models include:
+ 1 bit: 741G125 (Input), 741G74 (Output)
+ 2 bits: 742G125 (Input), 7474 (Output)
+ 4 bits: 74125 (Input), 74175 (Output)
+ 6 bits: 74365 (Input), 74174 (Output)
+ 8 bits: 74244 (Input), 74273 (Output)
+ 16 bits: 741624 (Input), 7416374 (Output)
+
config GPIO_CLPS711X
bool "GPIO support for CLPS711X"
- depends on ARCH_CLPS711X
+ depends on ARCH_CLPS711X || COMPILE_TEST
select GPIO_GENERIC
help
Say yes here to enable the GPIO driver for the CLPS711X CPUs
config GPIO_DAVINCI
bool "TI Davinci/Keystone GPIO support"
- default y if ARCH_DAVINCI
- depends on ARM && ARCH_DAVINCI
+ default y if ARCH_DAVINCI || ARCH_K3
+ depends on (ARM && (ARCH_DAVINCI || ARCH_K3)) || COMPILE_TEST
help
Say yes here to enable GPIO support for TI Davinci/Keystone SoCs.
@@ -43,23 +58,27 @@ config GPIO_GENERIC_PLATFORM
GPIO controllers
config GPIO_IMX
- def_bool ARCH_IMX
+ bool "i.MX GPIO controller" if COMPILE_TEST
+ default y if ARCH_IMX
config GPIO_VF610
- def_bool ARCH_VF610
+ bool "VF610 GPIO controller" if COMPILE_TEST
+ depends on ARCH_IMX || ARCH_VF610 || COMPILE_TEST
+ default y if ARCH_VF610 || ARCH_IMX93
config GPIO_MXS
- def_bool ARCH_MXS
+ bool "MXS GPIO controller" if COMPILE_TEST
+ default y if ARCH_MXS
config GPIO_JZ4740
bool "GPIO support for Ingenic SoCs"
- depends on MACH_MIPS_XBURST
+ depends on MACH_MIPS_XBURST || COMPILE_TEST
help
Say yes here to enable the GPIO driver for the Ingenic SoCs.
config GPIO_MALTA_FPGA_I2C
bool "Malta CBUS FPGA I2C GPIO"
- depends on MACH_MIPS_MALTA
+ depends on MACH_MIPS_MALTA || COMPILE_TEST
help
Support access to the CBUS FPGA I2C lines through the gpio library.
@@ -69,18 +88,19 @@ config GPIO_MALTA_FPGA_I2C
config GPIO_MPC8XXX
bool "MPC512x/MPC8xxx/QorIQ GPIO support"
- depends on ARCH_LAYERSCAPE
+ depends on ARCH_LAYERSCAPE || COMPILE_TEST
select GPIO_GENERIC
help
Say Y here if you're going to use hardware that connects to the
MPC512x/831x/834x/837x/8572/8610/QorIQ GPIOs.
config GPIO_OMAP
- def_bool ARCH_OMAP
+ bool "OMAP GPIO controller" if COMPILE_TEST
+ default y if ARCH_OMAP
config GPIO_ORION
bool "GPIO support for Marvell Orion/MVEBU SoCs"
- depends on ARCH_MVEBU
+ depends on ARCH_MVEBU || COMPILE_TEST
help
Say yes here to add the driver for the GPIO controller
found on Marvell Orion and MVEBU SoCs (Armada 370/XP,
@@ -129,13 +149,27 @@ config GPIO_PL061
help
Say yes here to support the PrimeCell PL061 GPIO device
+config GPIO_RASPBERRYPI_EXP
+ bool "Raspberry Pi 3 GPIO Expander"
+ depends on ARCH_BCM283X
+ help
+ Turn on GPIO support for the expander on Raspberry Pi 3 boards, using
+ the firmware mailbox to communicate with VideoCore on BCM283x chips.
+
+config GPIO_ROCKCHIP
+ bool "Rockchip GPIO support"
+ depends on ARCH_ROCKCHIP
+ help
+ Say yes here to include the driver for the GPIO controller found on
+ Rockchip SoCs.
+
config GPIO_STMPE
depends on MFD_STMPE
bool "STMPE GPIO Expander"
config GPIO_TEGRA
bool "GPIO support for the Tegra SoCs"
- depends on ARCH_TEGRA
+ depends on ARCH_TEGRA || COMPILE_TEST
help
Say yes here to include the driver for the GPIO controller found on the
Tegra line of SoCs.
@@ -153,10 +187,44 @@ config GPIO_SX150X
Say Y here to build support for the Semtec Sx150x I2C GPIO
expander chip.
+config GPIO_SIFIVE
+ bool "SiFive GPIO support"
+ depends on OF_GPIO
+ select GPIO_GENERIC
+ help
+ Say yes here to support the GPIO device on SiFive SoCs.
+
+config GPIO_STARFIVE
+ bool "StarFive GPIO support"
+ depends on SOC_STARFIVE || CROSS_COMPILE
+ depends on OF_GPIO
+ select GPIO_GENERIC
+ help
+ Say yes here to support the GPIO device on StarFive SoCs.
+
config GPIO_LIBFTDI1
bool "libftdi1 driver"
depends on SANDBOX
+config GPIO_ZYNQ
+ tristate "Xilinx Zynq GPIO support"
+ depends on ARCH_ZYNQ || ARCH_ZYNQMP || CROSS_COMPILE
+ depends on OFDEVICE
+ help
+ Say yes here to support Xilinx Zynq GPIO controller.
+
+config GPIO_LATCH
+ tristate "GPIO latch driver"
+ help
+ Say yes here to enable a driver for GPIO multiplexers based on latches
+ connected to other GPIOs.
+
+config GPIO_INTEL
+ bool "Intel GPIO driver"
+ depends on X86 || COMPILE_TEST
+ help
+ Say Y here to build support for the Intel GPIO driver.
+
endmenu
endif
diff --git a/drivers/gpio/Makefile b/drivers/gpio/Makefile
index bc5c500e4d..b0575ccf8c 100644
--- a/drivers/gpio/Makefile
+++ b/drivers/gpio/Makefile
@@ -1,6 +1,8 @@
+# SPDX-License-Identifier: GPL-2.0-only
obj-$(CONFIG_GPIOLIB) += gpiolib.o
obj-$(CONFIG_GPIO_74164) += gpio-74164.o
+obj-$(CONFIG_GPIO_74XX_MMIO) += gpio-74xx-mmio.o
obj-$(CONFIG_MACH_MIPS_ATH79) += gpio-ath79.o
obj-$(CONFIG_GPIO_DAVINCI) += gpio-davinci.o
obj-$(CONFIG_GPIO_CLPS711X) += gpio-clps711x.o
@@ -18,7 +20,14 @@ obj-$(CONFIG_GPIO_PCA953X) += gpio-pca953x.o
obj-$(CONFIG_GPIO_PCF857X) += gpio-pcf857x.o
obj-$(CONFIG_GPIO_PL061) += gpio-pl061.o
obj-$(CONFIG_GPIO_STMPE) += gpio-stmpe.o
+obj-$(CONFIG_GPIO_ROCKCHIP) += gpio-rockchip.o
obj-$(CONFIG_GPIO_TEGRA) += gpio-tegra.o
obj-$(CONFIG_GPIO_DESIGNWARE) += gpio-dw.o
obj-$(CONFIG_GPIO_SX150X) += gpio-sx150x.o
obj-$(CONFIG_GPIO_VF610) += gpio-vf610.o
+obj-$(CONFIG_GPIO_RASPBERRYPI_EXP) += gpio-raspberrypi-exp.o
+obj-$(CONFIG_GPIO_SIFIVE) += gpio-sifive.o
+obj-$(CONFIG_GPIO_STARFIVE) += gpio-starfive-vic.o
+obj-$(CONFIG_GPIO_ZYNQ) += gpio-zynq.o
+obj-$(CONFIG_GPIO_LATCH) += gpio-latch.o
+obj-$(CONFIG_GPIO_INTEL) += gpio-intel.o
diff --git a/drivers/gpio/gpio-74164.c b/drivers/gpio/gpio-74164.c
index e4d413b689..fb96e281b2 100644
--- a/drivers/gpio/gpio-74164.c
+++ b/drivers/gpio/gpio-74164.c
@@ -1,16 +1,13 @@
+// SPDX-License-Identifier: GPL-2.0-only
+// SPDX-FileCopyrightText: 2010 Gabor Juhos <juhosg@openwrt.org>
+// SPDX-FileCopyrightText: 2010 Miguel Gaio <miguel.gaio@efixo.com>
+
/*
* Generic serial-in/parallel-out 8-bits shift register GPIO driver
* e.g. for 74x164
*
- * Sebastian Hesselbarth <sebastian.hesselbarth@gmail.com>
- *
- * Based on Linux 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.
+ * Created by Sebastian Hesselbarth <sebastian.hesselbarth@gmail.com>
+ * based on the Linux driver for this hardware.
*/
#include <common.h>
@@ -97,16 +94,16 @@ static struct platform_device_id gpio_74164_ids[] = {
{ }
};
-static int gpio_74164_probe(struct device_d *dev)
+static int gpio_74164_probe(struct device *dev)
{
struct spi_device *spi = (struct spi_device *)dev->type_data;
struct gpio_74164 *priv;
u32 num_regs = 1;
dev->id = DEVICE_ID_DYNAMIC;
- if (IS_ENABLED(CONFIG_OFDEVICE) && dev->device_node) {
- dev->id = of_alias_get_id(dev->device_node, "gpio");
- of_property_read_u32(dev->device_node, "registers-number",
+ if (IS_ENABLED(CONFIG_OFDEVICE) && dev->of_node) {
+ dev->id = of_alias_get_id(dev->of_node, "gpio");
+ of_property_read_u32(dev->of_node, "registers-number",
&num_regs);
}
@@ -124,7 +121,7 @@ static int gpio_74164_probe(struct device_d *dev)
return gpiochip_add(&priv->chip);
}
-static struct driver_d gpio_74164_driver = {
+static struct driver gpio_74164_driver = {
.name = "gpio-74164",
.probe = gpio_74164_probe,
.id_table = gpio_74164_ids,
diff --git a/drivers/gpio/gpio-74xx-mmio.c b/drivers/gpio/gpio-74xx-mmio.c
new file mode 100644
index 0000000000..513d071c79
--- /dev/null
+++ b/drivers/gpio/gpio-74xx-mmio.c
@@ -0,0 +1,166 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * 74xx MMIO GPIO driver
+ *
+ * Copyright (C) 2014 Alexander Shiyan <shc_work@mail.ru>
+ *
+ * Ported to barebox from linux-v5.4-rc6
+ * Copyright (C) 2019-2021 Antony Pavlov <antonynpavlov@gmail.com>
+ *
+ */
+
+#include <common.h>
+#include <driver.h>
+#include <errno.h>
+#include <gpio.h>
+#include <init.h>
+#include <io.h>
+#include <malloc.h>
+#include <of_device.h>
+
+#include <linux/err.h>
+#include <linux/basic_mmio_gpio.h>
+
+#define MMIO_74XX_DIR_IN (0 << 8)
+#define MMIO_74XX_DIR_OUT (1 << 8)
+#define MMIO_74XX_BIT_CNT(x) ((x) & 0xff)
+
+struct mmio_74xx_gpio_priv {
+ struct bgpio_chip bgc;
+ unsigned int flags;
+};
+
+static const struct of_device_id mmio_74xx_gpio_ids[] = {
+ {
+ .compatible = "ti,741g125",
+ .data = (const void *)(MMIO_74XX_DIR_IN | 1),
+ },
+ {
+ .compatible = "ti,742g125",
+ .data = (const void *)(MMIO_74XX_DIR_IN | 2),
+ },
+ {
+ .compatible = "ti,74125",
+ .data = (const void *)(MMIO_74XX_DIR_IN | 4),
+ },
+ {
+ .compatible = "ti,74365",
+ .data = (const void *)(MMIO_74XX_DIR_IN | 6),
+ },
+ {
+ .compatible = "ti,74244",
+ .data = (const void *)(MMIO_74XX_DIR_IN | 8),
+ },
+ {
+ .compatible = "ti,741624",
+ .data = (const void *)(MMIO_74XX_DIR_IN | 16),
+ },
+ {
+ .compatible = "ti,741g74",
+ .data = (const void *)(MMIO_74XX_DIR_OUT | 1),
+ },
+ {
+ .compatible = "ti,7474",
+ .data = (const void *)(MMIO_74XX_DIR_OUT | 2),
+ },
+ {
+ .compatible = "ti,74175",
+ .data = (const void *)(MMIO_74XX_DIR_OUT | 4),
+ },
+ {
+ .compatible = "ti,74174",
+ .data = (const void *)(MMIO_74XX_DIR_OUT | 6),
+ },
+ {
+ .compatible = "ti,74273",
+ .data = (const void *)(MMIO_74XX_DIR_OUT | 8),
+ },
+ {
+ .compatible = "ti,7416374",
+ .data = (const void *)(MMIO_74XX_DIR_OUT | 16),
+ },
+ { }
+};
+MODULE_DEVICE_TABLE(of, mmio_74xx_gpio_ids);
+
+static inline
+struct mmio_74xx_gpio_priv *to_mmio_74xx_gpio_priv(struct gpio_chip *gc)
+{
+ struct bgpio_chip *bgc =
+ container_of(gc, struct bgpio_chip, gc);
+
+ return container_of(bgc, struct mmio_74xx_gpio_priv, bgc);
+}
+
+static int mmio_74xx_get_direction(struct gpio_chip *gc, unsigned int offset)
+{
+ struct mmio_74xx_gpio_priv *priv = to_mmio_74xx_gpio_priv(gc);
+
+ if (priv->flags & MMIO_74XX_DIR_OUT)
+ return GPIOF_DIR_OUT;
+
+ return GPIOF_DIR_IN;
+}
+
+static int mmio_74xx_dir_in(struct gpio_chip *gc, unsigned int gpio)
+{
+ struct mmio_74xx_gpio_priv *priv = to_mmio_74xx_gpio_priv(gc);
+
+ return (priv->flags & MMIO_74XX_DIR_OUT) ? -ENOTSUPP : 0;
+}
+
+static int mmio_74xx_dir_out(struct gpio_chip *gc, unsigned int gpio, int val)
+{
+ struct mmio_74xx_gpio_priv *priv = to_mmio_74xx_gpio_priv(gc);
+
+ if (priv->flags & MMIO_74XX_DIR_OUT) {
+ gc->ops->set(gc, gpio, val);
+ return 0;
+ }
+
+ return -ENOTSUPP;
+}
+
+static int mmio_74xx_gpio_probe(struct device *dev)
+{
+ struct mmio_74xx_gpio_priv *priv;
+ void __iomem *dat;
+ int err;
+ struct gpio_chip *gc;
+
+ priv = xzalloc(sizeof(*priv));
+
+ priv->flags = (uintptr_t)of_device_get_match_data(dev);
+
+ dat = dev_request_mem_region(dev, 0);
+ if (IS_ERR(dat))
+ return PTR_ERR(dat);
+
+ err = bgpio_init(&priv->bgc, dev,
+ DIV_ROUND_UP(MMIO_74XX_BIT_CNT(priv->flags), 8),
+ dat, NULL, NULL, NULL, NULL, 0);
+ if (err)
+ return err;
+
+ gc = &priv->bgc.gc;
+ gc->ops->direction_input = mmio_74xx_dir_in;
+ gc->ops->direction_output = mmio_74xx_dir_out;
+ gc->ops->get_direction = mmio_74xx_get_direction;
+ gc->ngpio = MMIO_74XX_BIT_CNT(priv->flags);
+
+ dev->priv = priv;
+
+ return gpiochip_add(gc);
+}
+
+static struct driver mmio_74xx_gpio_driver = {
+ .name = "74xx-mmio-gpio",
+ .of_compatible = DRV_OF_COMPAT(mmio_74xx_gpio_ids),
+ .probe = mmio_74xx_gpio_probe,
+};
+
+coredevice_platform_driver(mmio_74xx_gpio_driver);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Alexander Shiyan <shc_work@mail.ru>");
+MODULE_DESCRIPTION("74xx MMIO GPIO driver");
diff --git a/drivers/gpio/gpio-ath79.c b/drivers/gpio/gpio-ath79.c
index d08d743b54..b32e9552ce 100644
--- a/drivers/gpio/gpio-ath79.c
+++ b/drivers/gpio/gpio-ath79.c
@@ -1,16 +1,14 @@
+// SPDX-License-Identifier: GPL-2.0-only
+// SPDX-FileCopyrightText: 2010-2011 Jaiganesh Narayanan <jnarayanan@atheros.com>
+// SPDX-FileCopyrightText: 2008-2011 Gabor Juhos <juhosg@openwrt.org>
+// SPDX-FileCopyrightText: 2008 Imre Kaloz <kaloz@openwrt.org>
+// SPDX-FileCopyrightText: 2015 Antony Pavlov <antonynpavlov@gmail.com>
+
/*
* Atheros AR71XX/AR724X/AR913X GPIO API support
*
- * Copyright (C) 2010-2011 Jaiganesh Narayanan <jnarayanan@atheros.com>
- * Copyright (C) 2008-2011 Gabor Juhos <juhosg@openwrt.org>
- * Copyright (C) 2008 Imre Kaloz <kaloz@openwrt.org>
- * Copyright (C) 2015 Antony Pavlov <antonynpavlov@gmail.com>
- *
* Parts of this file are based on Atheros' 2.6.15/2.6.31 BSP
*
- * 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 <common.h>
@@ -104,11 +102,12 @@ static const struct of_device_id ath79_gpio_of_match[] = {
{ .compatible = "qca,ar7100-gpio" },
{},
};
+MODULE_DEVICE_TABLE(of, ath79_gpio_of_match);
-static int ath79_gpio_probe(struct device_d *dev)
+static int ath79_gpio_probe(struct device *dev)
{
struct resource *iores;
- struct device_node *np = dev->device_node;
+ struct device_node *np = dev->of_node;
int err;
if (!np) {
@@ -145,14 +144,10 @@ static int ath79_gpio_probe(struct device_d *dev)
return 0;
}
-static struct driver_d ath79_gpio_driver = {
+static struct driver ath79_gpio_driver = {
.name = "ath79-gpio",
.probe = ath79_gpio_probe,
.of_compatible = DRV_OF_COMPAT(ath79_gpio_of_match),
};
-static int ath79_gpio_init(void)
-{
- return platform_driver_register(&ath79_gpio_driver);
-}
-coredevice_initcall(ath79_gpio_init);
+coredevice_platform_driver(ath79_gpio_driver);
diff --git a/drivers/gpio/gpio-clps711x.c b/drivers/gpio/gpio-clps711x.c
index 44f40c36e4..a59bdd212a 100644
--- a/drivers/gpio/gpio-clps711x.c
+++ b/drivers/gpio/gpio-clps711x.c
@@ -1,4 +1,4 @@
-// SPDX-License-Identifier: GPL-2.0+
+// SPDX-License-Identifier: GPL-2.0-or-later
/* Author: Alexander Shiyan <shc_work@mail.ru> */
#include <init.h>
@@ -7,16 +7,13 @@
#include <linux/err.h>
#include <linux/basic_mmio_gpio.h>
-static int clps711x_gpio_probe(struct device_d *dev)
+static int clps711x_gpio_probe(struct device *dev)
{
struct resource *iores;
- int err, id = dev->id;
+ int err, id = of_alias_get_id(dev->of_node, "gpio");
void __iomem *dat, *dir = NULL, *dir_inv = NULL;
struct bgpio_chip *bgc;
- if (dev->device_node)
- id = of_alias_get_id(dev->device_node, "gpio");
-
if (id < 0 || id > 4)
return -ENODEV;
@@ -25,17 +22,15 @@ static int clps711x_gpio_probe(struct device_d *dev)
return PTR_ERR(iores);
dat = IOMEM(iores->start);
+ iores = dev_request_mem_resource(dev, 1);
+ if (IS_ERR(iores))
+ return PTR_ERR(iores);
+
switch (id) {
case 3:
- iores = dev_request_mem_resource(dev, 1);
- if (IS_ERR(iores))
- return PTR_ERR(iores);
dir_inv = IOMEM(iores->start);
break;
default:
- iores = dev_request_mem_resource(dev, 1);
- if (IS_ERR(iores))
- return PTR_ERR(iores);
dir = IOMEM(iores->start);
break;
}
@@ -64,12 +59,13 @@ out_err:
return err;
}
-static struct of_device_id __maybe_unused clps711x_gpio_dt_ids[] = {
+static const struct of_device_id __maybe_unused clps711x_gpio_dt_ids[] = {
{ .compatible = "cirrus,ep7209-gpio", },
{ /* sentinel */ }
};
+MODULE_DEVICE_TABLE(of, clps711x_gpio_dt_ids);
-static struct driver_d clps711x_gpio_driver = {
+static struct driver clps711x_gpio_driver = {
.name = "clps711x-gpio",
.probe = clps711x_gpio_probe,
.of_compatible = DRV_OF_COMPAT(clps711x_gpio_dt_ids),
diff --git a/drivers/gpio/gpio-davinci.c b/drivers/gpio/gpio-davinci.c
index 7c060a09b1..831da2fc7f 100644
--- a/drivers/gpio/gpio-davinci.c
+++ b/drivers/gpio/gpio-davinci.c
@@ -1,14 +1,10 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+// SPDX-FileCopyrightText: 2006-2007 David Brownell
+// SPDX-FileCopyrightText: 2007 MontaVista Software, Inc. <source@mvista.com>
+// SPDX-FileCopyrightText: 2014 Antony Pavlov <antonynpavlov@gmail.com>
+
/*
* TI DaVinci GPIO Support
- *
- * Copyright (c) 2006-2007 David Brownell
- * Copyright (c) 2007, MontaVista Software, Inc. <source@mvista.com>
- * Copyright (c) 2014 Antony Pavlov <antonynpavlov@gmail.com>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
*/
#include <common.h>
@@ -17,9 +13,6 @@
#include <io.h>
#include <linux/err.h>
-#define readl_relaxed readl
-#define writel_relaxed writel
-
struct davinci_gpio_regs {
u32 dir;
u32 out_data;
@@ -37,40 +30,42 @@ struct davinci_gpio_controller {
struct gpio_chip chip;
/* Serialize access to GPIO registers */
void __iomem *regs;
- void __iomem *set_data;
- void __iomem *clr_data;
- void __iomem *in_data;
};
#define chip2controller(chip) \
container_of(chip, struct davinci_gpio_controller, chip)
-static struct davinci_gpio_regs __iomem *gpio2regs(void __iomem *gpio_base,
- unsigned gpio)
+static struct davinci_gpio_regs __iomem *gpio2regs(struct davinci_gpio_controller *d,
+ unsigned gpio)
{
void __iomem *ptr;
if (gpio < 32 * 1)
- ptr = gpio_base + 0x10;
+ ptr = d->regs + 0x10;
else if (gpio < 32 * 2)
- ptr = gpio_base + 0x38;
+ ptr = d->regs + 0x38;
else if (gpio < 32 * 3)
- ptr = gpio_base + 0x60;
+ ptr = d->regs + 0x60;
else if (gpio < 32 * 4)
- ptr = gpio_base + 0x88;
+ ptr = d->regs + 0x88;
else if (gpio < 32 * 5)
- ptr = gpio_base + 0xb0;
+ ptr = d->regs + 0xb0;
else
ptr = NULL;
return ptr;
}
+static inline u32 __gpio_mask(unsigned gpio)
+{
+ return 1 << (gpio % 32);
+}
+
static int davinci_get_direction(struct gpio_chip *chip, unsigned offset)
{
struct davinci_gpio_controller *d = chip2controller(chip);
- struct davinci_gpio_regs __iomem *g = d->regs;
+ struct davinci_gpio_regs __iomem *g = gpio2regs(d, offset);
- return ((readl_relaxed(&g->dir)) & (1 << offset)) ?
+ return ((readl_relaxed(&g->dir)) & __gpio_mask(offset)) ?
GPIOF_DIR_IN : GPIOF_DIR_OUT;
}
@@ -78,9 +73,9 @@ static inline int __davinci_direction(struct gpio_chip *chip,
unsigned offset, bool out, int value)
{
struct davinci_gpio_controller *d = chip2controller(chip);
- struct davinci_gpio_regs __iomem *g = d->regs;
+ struct davinci_gpio_regs __iomem *g = gpio2regs(d, offset);
u32 temp;
- u32 mask = 1 << offset;
+ u32 mask = __gpio_mask(offset);
temp = readl_relaxed(&g->dir);
if (out) {
@@ -115,9 +110,9 @@ davinci_direction_out(struct gpio_chip *chip, unsigned offset, int value)
static int davinci_gpio_get(struct gpio_chip *chip, unsigned offset)
{
struct davinci_gpio_controller *d = chip2controller(chip);
- struct davinci_gpio_regs __iomem *g = d->regs;
+ struct davinci_gpio_regs __iomem *g = gpio2regs(d, offset);
- return ((1 << offset) & readl_relaxed(&g->in_data)) ? 1 : 0;
+ return (__gpio_mask(offset) & readl_relaxed(&g->in_data)) ? 1 : 0;
}
/*
@@ -127,9 +122,9 @@ static void
davinci_gpio_set(struct gpio_chip *chip, unsigned offset, int value)
{
struct davinci_gpio_controller *d = chip2controller(chip);
- struct davinci_gpio_regs __iomem *g = d->regs;
+ struct davinci_gpio_regs __iomem *g = gpio2regs(d, offset);
- writel_relaxed((1 << offset), value ? &g->set_data : &g->clr_data);
+ writel_relaxed(__gpio_mask(offset), value ? &g->set_data : &g->clr_data);
}
static struct gpio_ops davinci_gpio_ops = {
@@ -140,17 +135,17 @@ static struct gpio_ops davinci_gpio_ops = {
.set = davinci_gpio_set,
};
-static int davinci_gpio_probe(struct device_d *dev)
+static int davinci_gpio_probe(struct device *dev)
{
struct resource *iores;
void __iomem *gpio_base;
int ret;
u32 val;
- int i, base;
unsigned ngpio;
struct davinci_gpio_controller *chips;
+ struct gpio_chip *gc;
- ret = of_property_read_u32(dev->device_node, "ti,ngpio", &val);
+ ret = of_property_read_u32(dev->of_node, "ti,ngpio", &val);
if (ret) {
dev_err(dev, "could not read 'ti,ngpio' property\n");
return -EINVAL;
@@ -161,7 +156,7 @@ static int davinci_gpio_probe(struct device_d *dev)
if (WARN_ON(ARCH_NR_GPIOS < ngpio))
ngpio = ARCH_NR_GPIOS;
- chips = xzalloc((ngpio / 32 + 1) * sizeof(*chips));
+ chips = xzalloc(sizeof(*chips));
iores = dev_request_mem_resource(dev, 0);
if (IS_ERR(iores)) {
@@ -170,44 +165,31 @@ static int davinci_gpio_probe(struct device_d *dev)
}
gpio_base = IOMEM(iores->start);
- for (i = 0, base = 0; base < ngpio; i++, base += 32) {
- struct davinci_gpio_regs __iomem *regs;
- struct gpio_chip *gc;
-
- gc = &chips[i].chip;
- gc->ops = &davinci_gpio_ops;
-
- gc->dev = dev;
- gc->base = base;
- gc->ngpio = ngpio - base;
- if (gc->ngpio > 32)
- gc->ngpio = 32;
+ gc = &chips->chip;
+ gc->ops = &davinci_gpio_ops;
+ gc->dev = dev;
+ gc->ngpio = ngpio;
+ gc->base = -1;
- regs = gpio2regs(gpio_base, base);
- chips[i].regs = regs;
- chips[i].set_data = &regs->set_data;
- chips[i].clr_data = &regs->clr_data;
- chips[i].in_data = &regs->in_data;
+ chips->regs = gpio_base;
- gpiochip_add(gc);
- }
+ gpiochip_add(gc);
return 0;
}
static struct of_device_id davinci_gpio_ids[] = {
+ { .compatible = "ti,keystone-gpio", },
+ { .compatible = "ti,am654-gpio", },
{ .compatible = "ti,dm6441-gpio", },
{ /* sentinel */ },
};
+MODULE_DEVICE_TABLE(of, davinci_gpio_ids);
-static struct driver_d davinci_gpio_driver = {
+static struct driver davinci_gpio_driver = {
.name = "davinci_gpio",
.probe = davinci_gpio_probe,
.of_compatible = DRV_OF_COMPAT(davinci_gpio_ids),
};
-static int davinci_gpio_drv_reg(void)
-{
- return platform_driver_register(&davinci_gpio_driver);
-}
-coredevice_initcall(davinci_gpio_drv_reg);
+coredevice_platform_driver(davinci_gpio_driver);
diff --git a/drivers/gpio/gpio-digic.c b/drivers/gpio/gpio-digic.c
index 714e3b4a1d..7e2db85efe 100644
--- a/drivers/gpio/gpio-digic.c
+++ b/drivers/gpio/gpio-digic.c
@@ -1,19 +1,5 @@
-/*
- * Copyright (C) 2013 Antony Pavlov <antonynpavlov@gmail.com>
- *
- * This file is part of barebox.
- * See file CREDITS for list of people who contributed to this project.
- *
- * 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.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- */
+// SPDX-License-Identifier: GPL-2.0-only
+// SPDX-FileCopyrightText: 2013 Antony Pavlov <antonynpavlov@gmail.com>
#include <common.h>
#include <malloc.h>
@@ -120,7 +106,7 @@ static struct gpio_ops digic_gpio_ops = {
.set = digic_gpio_set_value,
};
-static int digic_gpio_probe(struct device_d *dev)
+static int digic_gpio_probe(struct device *dev)
{
struct resource *iores;
struct digic_gpio_chip *chip;
@@ -170,15 +156,12 @@ static __maybe_unused struct of_device_id digic_gpio_dt_ids[] = {
/* sentinel */
}
};
+MODULE_DEVICE_TABLE(of, digic_gpio_dt_ids);
-static struct driver_d digic_gpio_driver = {
+static struct driver digic_gpio_driver = {
.name = "digic-gpio",
.probe = digic_gpio_probe,
.of_compatible = DRV_OF_COMPAT(digic_gpio_dt_ids),
};
-static int digic_gpio_init(void)
-{
- return platform_driver_register(&digic_gpio_driver);
-}
-coredevice_initcall(digic_gpio_init);
+coredevice_platform_driver(digic_gpio_driver);
diff --git a/drivers/gpio/gpio-dw.c b/drivers/gpio/gpio-dw.c
index b81e6a75c5..e6eba6b423 100644
--- a/drivers/gpio/gpio-dw.c
+++ b/drivers/gpio/gpio-dw.c
@@ -1,20 +1,8 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+// SPDX-FileCopyrightText: 2012 Altera
+
/*
* Designware GPIO support functions
- *
- * Copyright (C) 2012 Altera
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include <common.h>
@@ -116,7 +104,7 @@ static struct gpio_ops dw_gpio_ops = {
.set = dw_gpio_set,
};
-static int dw_gpio_add_port(struct device_d *dev, struct device_node *node,
+static int dw_gpio_add_port(struct device *dev, struct device_node *node,
struct dw_gpio *parent)
{
struct dw_gpio_instance *chip;
@@ -150,7 +138,7 @@ static int dw_gpio_add_port(struct device_d *dev, struct device_node *node,
return -ENODEV;
}
- chip->chip.dev->device_node = node;
+ chip->chip.dev->of_node = node;
ret = gpiochip_add(&chip->chip);
if (ret)
@@ -162,7 +150,7 @@ static int dw_gpio_add_port(struct device_d *dev, struct device_node *node,
return 0;
}
-static int dw_gpio_probe(struct device_d *dev)
+static int dw_gpio_probe(struct device *dev)
{
struct resource *iores;
struct dw_gpio *gpio;
@@ -175,7 +163,7 @@ static int dw_gpio_probe(struct device_d *dev)
return PTR_ERR(iores);
gpio->regs = IOMEM(iores->start);
- for_each_child_of_node(dev->device_node, node)
+ for_each_child_of_node(dev->of_node, node)
dw_gpio_add_port(dev, node, gpio);
return 0;
@@ -188,15 +176,12 @@ static __maybe_unused struct of_device_id dwgpio_match[] = {
/* sentinel */
},
};
+MODULE_DEVICE_TABLE(of, dwgpio_match);
-static struct driver_d dwgpio_driver = {
+static struct driver dwgpio_driver = {
.name = "dw-apb-gpio",
.probe = dw_gpio_probe,
.of_compatible = DRV_OF_COMPAT(dwgpio_match),
};
-static int __init dwgpio_init(void)
-{
- return platform_driver_register(&dwgpio_driver);
-}
-postcore_initcall(dwgpio_init);
+postcore_platform_driver(dwgpio_driver);
diff --git a/drivers/gpio/gpio-generic.c b/drivers/gpio/gpio-generic.c
index e4c4f39b62..1902c83960 100644
--- a/drivers/gpio/gpio-generic.c
+++ b/drivers/gpio/gpio-generic.c
@@ -1,74 +1,123 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+// SPDX-FileCopyrightText: 2008 MontaVista Software, Inc.
+// SPDX-FileCopyrightText: 2008,2010 Anton Vorontsov <cbouatmailru@gmail.com>
+
/*
- * Generic driver for memory-mapped GPIO controllers.
- *
- * Based on linux driver by:
- * Copyright 2008 MontaVista Software, Inc.
- * Copyright 2008,2010 Anton Vorontsov <cbouatmailru@gmail.com>
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License as published by the
- * Free Software Foundation; either version 2 of the License, or (at your
- * option) any later version.
+ * Generic driver for memory-mapped GPIO controllers, based on the Linux driver.
*/
#include <init.h>
-#include <malloc.h>
#include <linux/err.h>
+#include <linux/bug.h>
+#include <linux/kernel.h>
+#include <linux/compiler.h>
+#include <linux/types.h>
+#include <errno.h>
#include <linux/log2.h>
-#include <linux/err.h>
+#include <linux/ioport.h>
+#include <io.h>
#include <linux/basic_mmio_gpio.h>
+#include <linux/slab.h>
+#include <linux/bitops.h>
+#include <driver.h>
+#include <of.h>
+#include <of_device.h>
-static void bgpio_write8(void __iomem *reg, unsigned int data)
+static void bgpio_write8(void __iomem *reg, unsigned long data)
{
writeb(data, reg);
}
-static unsigned int bgpio_read8(void __iomem *reg)
+static unsigned long bgpio_read8(void __iomem *reg)
{
return readb(reg);
}
-static void bgpio_write16(void __iomem *reg, unsigned int data)
+static void bgpio_write16(void __iomem *reg, unsigned long data)
{
writew(data, reg);
}
-static unsigned int bgpio_read16(void __iomem *reg)
+static unsigned long bgpio_read16(void __iomem *reg)
{
return readw(reg);
}
-static void bgpio_write32(void __iomem *reg, unsigned int data)
+static void bgpio_write32(void __iomem *reg, unsigned long data)
{
writel(data, reg);
}
-static unsigned int bgpio_read32(void __iomem *reg)
+static unsigned long bgpio_read32(void __iomem *reg)
{
return readl(reg);
}
-static unsigned int bgpio_pin2mask(struct bgpio_chip *bgc, unsigned int pin)
+#if BITS_PER_LONG >= 64
+static void bgpio_write64(void __iomem *reg, unsigned long data)
+{
+ writeq(data, reg);
+}
+
+static unsigned long bgpio_read64(void __iomem *reg)
+{
+ return readq(reg);
+}
+#endif /* BITS_PER_LONG >= 64 */
+
+static void bgpio_write16be(void __iomem *reg, unsigned long data)
+{
+ iowrite16be(data, reg);
+}
+
+static unsigned long bgpio_read16be(void __iomem *reg)
{
- return 1 << pin;
+ return ioread16be(reg);
}
-static unsigned int bgpio_pin2mask_be(struct bgpio_chip *bgc, unsigned int pin)
+static void bgpio_write32be(void __iomem *reg, unsigned long data)
{
- return 1 << (bgc->bits - 1 - pin);
+ iowrite32be(data, reg);
+}
+
+static unsigned long bgpio_read32be(void __iomem *reg)
+{
+ return ioread32be(reg);
+}
+
+static unsigned long bgpio_line2mask(struct bgpio_chip *bgc, unsigned int line)
+{
+ if (bgc->be_bits)
+ return BIT(bgc->bits - 1 - line);
+ return BIT(line);
+}
+
+static int bgpio_get_set(struct gpio_chip *gc, unsigned int gpio)
+{
+ struct bgpio_chip *bgc = to_bgpio_chip(gc);
+ unsigned long pinmask = bgpio_line2mask(bgc, gpio);
+ bool dir = !!(bgc->dir & pinmask);
+
+ if (dir)
+ return !!(bgc->read_reg(bgc->reg_set) & pinmask);
+ else
+ return !!(bgc->read_reg(bgc->reg_dat) & pinmask);
}
static int bgpio_get(struct gpio_chip *gc, unsigned int gpio)
{
struct bgpio_chip *bgc = to_bgpio_chip(gc);
+ return !!(bgc->read_reg(bgc->reg_dat) & bgpio_line2mask(bgc, gpio));
+}
- return bgc->read_reg(bgc->reg_dat) & bgc->pin2mask(bgc, gpio);
+static void bgpio_set_none(struct gpio_chip *gc, unsigned int gpio, int val)
+{
}
static void bgpio_set(struct gpio_chip *gc, unsigned int gpio, int val)
{
struct bgpio_chip *bgc = to_bgpio_chip(gc);
- unsigned int mask = bgc->pin2mask(bgc, gpio);
+ unsigned long mask = bgpio_line2mask(bgc, gpio);
if (val)
bgc->data |= mask;
@@ -82,7 +131,7 @@ static void bgpio_set_with_clear(struct gpio_chip *gc, unsigned int gpio,
int val)
{
struct bgpio_chip *bgc = to_bgpio_chip(gc);
- unsigned int mask = bgc->pin2mask(bgc, gpio);
+ unsigned long mask = bgpio_line2mask(bgc, gpio);
if (val)
bgc->write_reg(bgc->reg_set, mask);
@@ -93,7 +142,7 @@ static void bgpio_set_with_clear(struct gpio_chip *gc, unsigned int gpio,
static void bgpio_set_set(struct gpio_chip *gc, unsigned int gpio, int val)
{
struct bgpio_chip *bgc = to_bgpio_chip(gc);
- unsigned int mask = bgc->pin2mask(bgc, gpio);
+ unsigned long mask = bgpio_line2mask(bgc, gpio);
if (val)
bgc->data |= mask;
@@ -108,6 +157,12 @@ static int bgpio_simple_dir_in(struct gpio_chip *gc, unsigned int gpio)
return 0;
}
+static int bgpio_dir_out_err(struct gpio_chip *gc, unsigned int gpio,
+ int val)
+{
+ return -EINVAL;
+}
+
static int bgpio_simple_dir_out(struct gpio_chip *gc, unsigned int gpio,
int val)
{
@@ -120,69 +175,115 @@ static int bgpio_dir_in(struct gpio_chip *gc, unsigned int gpio)
{
struct bgpio_chip *bgc = to_bgpio_chip(gc);
- bgc->dir &= ~bgc->pin2mask(bgc, gpio);
- bgc->write_reg(bgc->reg_dir, bgc->dir);
+ bgc->dir &= ~bgpio_line2mask(bgc, gpio);
+
+ if (bgc->reg_dir_in)
+ bgc->write_reg(bgc->reg_dir_in, ~bgc->dir);
+ if (bgc->reg_dir_out)
+ bgc->write_reg(bgc->reg_dir_out, bgc->dir);
return 0;
}
-static int bgpio_dir_out(struct gpio_chip *gc, unsigned int gpio, int val)
+static int bgpio_get_dir(struct gpio_chip *gc, unsigned int gpio)
{
struct bgpio_chip *bgc = to_bgpio_chip(gc);
- gc->ops->set(gc, gpio, val);
+ /* Return 0 if output, 1 if input */
+ if (bgc->dir_unreadable) {
+ if (bgc->dir & bgpio_line2mask(bgc, gpio))
+ return GPIOF_DIR_OUT;
+ return GPIOF_DIR_IN;
+ }
- bgc->dir |= bgc->pin2mask(bgc, gpio);
- bgc->write_reg(bgc->reg_dir, bgc->dir);
+ if (bgc->reg_dir_out) {
+ if (bgc->read_reg(bgc->reg_dir_out) & bgpio_line2mask(bgc, gpio))
+ return GPIOF_DIR_OUT;
+ return GPIOF_DIR_IN;
+ }
- return 0;
+ if (bgc->reg_dir_in)
+ if (!(bgc->read_reg(bgc->reg_dir_in) & bgpio_line2mask(bgc, gpio)))
+ return GPIOF_DIR_OUT;
+
+ return GPIOF_DIR_IN;
}
-static int bgpio_dir_in_inv(struct gpio_chip *gc, unsigned int gpio)
+static void bgpio_dir_out(struct bgpio_chip *bgc, unsigned int gpio, int val)
{
- struct bgpio_chip *bgc = to_bgpio_chip(gc);
-
- bgc->dir |= bgc->pin2mask(bgc, gpio);
- bgc->write_reg(bgc->reg_dir, bgc->dir);
+ bgc->dir |= bgpio_line2mask(bgc, gpio);
- return 0;
+ if (bgc->reg_dir_in)
+ bgc->write_reg(bgc->reg_dir_in, ~bgc->dir);
+ if (bgc->reg_dir_out)
+ bgc->write_reg(bgc->reg_dir_out, bgc->dir);
}
-static int bgpio_dir_out_inv(struct gpio_chip *gc, unsigned int gpio, int val)
+static int bgpio_dir_out_dir_first(struct gpio_chip *gc, unsigned int gpio,
+ int val)
{
struct bgpio_chip *bgc = to_bgpio_chip(gc);
+ bgpio_dir_out(bgc, gpio, val);
gc->ops->set(gc, gpio, val);
+ return 0;
+}
- bgc->dir &= ~bgc->pin2mask(bgc, gpio);
- bgc->write_reg(bgc->reg_dir, bgc->dir);
+static int bgpio_dir_out_val_first(struct gpio_chip *gc, unsigned int gpio,
+ int val)
+{
+ struct bgpio_chip *bgc = to_bgpio_chip(gc);
+ gc->ops->set(gc, gpio, val);
+ bgpio_dir_out(bgc, gpio, val);
return 0;
}
-static int bgpio_setup_accessors(struct device_d *dev, struct bgpio_chip *bgc,
- bool be)
+static int bgpio_setup_accessors(struct device *dev,
+ struct bgpio_chip *bgc,
+ bool byte_be)
{
+
switch (bgc->bits) {
case 8:
bgc->read_reg = bgpio_read8;
bgc->write_reg = bgpio_write8;
break;
case 16:
- bgc->read_reg = bgpio_read16;
- bgc->write_reg = bgpio_write16;
+ if (byte_be) {
+ bgc->read_reg = bgpio_read16be;
+ bgc->write_reg = bgpio_write16be;
+ } else {
+ bgc->read_reg = bgpio_read16;
+ bgc->write_reg = bgpio_write16;
+ }
break;
case 32:
- bgc->read_reg = bgpio_read32;
- bgc->write_reg = bgpio_write32;
+ if (byte_be) {
+ bgc->read_reg = bgpio_read32be;
+ bgc->write_reg = bgpio_write32be;
+ } else {
+ bgc->read_reg = bgpio_read32;
+ bgc->write_reg = bgpio_write32;
+ }
+ break;
+#if BITS_PER_LONG >= 64
+ case 64:
+ if (byte_be) {
+ dev_err(dev,
+ "64 bit big endian byte order unsupported\n");
+ return -EINVAL;
+ } else {
+ bgc->read_reg = bgpio_read64;
+ bgc->write_reg = bgpio_write64;
+ }
break;
+#endif /* BITS_PER_LONG >= 64 */
default:
- dev_err(dev, "Unsupported data width %u bits\n", bgc->bits);
+ dev_err(dev, "unsupported data width %u bits\n", bgc->bits);
return -EINVAL;
}
- bgc->pin2mask = be ? bgpio_pin2mask_be : bgpio_pin2mask;
-
return 0;
}
@@ -193,7 +294,7 @@ static int bgpio_setup_accessors(struct device_d *dev, struct bgpio_chip *bgc,
* - single input/output register resource (named "dat").
* - set/clear pair (named "set" and "clr").
* - single output register resource and single input resource ("set" and
- * dat").
+ * dat").
*
* For the single output register, this drives a 1 by setting a bit and a zero
* by clearing a bit. For the set clr pair, this drives a 1 by setting a bit
@@ -211,126 +312,214 @@ static int bgpio_setup_accessors(struct device_d *dev, struct bgpio_chip *bgc,
static int bgpio_setup_io(struct bgpio_chip *bgc,
void __iomem *dat,
void __iomem *set,
- void __iomem *clr)
+ void __iomem *clr,
+ unsigned long flags)
{
- if (!dat)
- return -EINVAL;
+ struct gpio_ops *ops = bgc->gc.ops;
bgc->reg_dat = dat;
+ if (!bgc->reg_dat)
+ return -EINVAL;
if (set && clr) {
bgc->reg_set = set;
bgc->reg_clr = clr;
- bgc->gc.ops->set = bgpio_set_with_clear;
+ ops->set = bgpio_set_with_clear;
} else if (set && !clr) {
bgc->reg_set = set;
- bgc->gc.ops->set = bgpio_set_set;
- } else
- bgc->gc.ops->set = bgpio_set;
+ ops->set = bgpio_set_set;
+ } else if (flags & BGPIOF_NO_OUTPUT) {
+ ops->set = bgpio_set_none;
+ } else {
+ ops->set = bgpio_set;
+ }
- bgc->gc.ops->get = bgpio_get;
+ if (!(flags & BGPIOF_UNREADABLE_REG_SET) && (flags & BGPIOF_READ_OUTPUT_REG_SET))
+ ops->get = bgpio_get_set;
+ else
+ ops->get = bgpio_get;
return 0;
}
static int bgpio_setup_direction(struct bgpio_chip *bgc,
void __iomem *dirout,
- void __iomem *dirin)
+ void __iomem *dirin,
+ unsigned long flags)
{
- if (dirout && dirin)
- return -EINVAL;
-
- if (dirout) {
- bgc->reg_dir = dirout;
- bgc->gc.ops->direction_output = bgpio_dir_out;
- bgc->gc.ops->direction_input = bgpio_dir_in;
- } else if (dirin) {
- bgc->reg_dir = dirin;
- bgc->gc.ops->direction_output = bgpio_dir_out_inv;
- bgc->gc.ops->direction_input = bgpio_dir_in_inv;
+ struct gpio_ops *ops = bgc->gc.ops;
+
+ if (dirout || dirin) {
+ bgc->reg_dir_out = dirout;
+ bgc->reg_dir_in = dirin;
+ if (flags & BGPIOF_NO_SET_ON_INPUT)
+ ops->direction_output = bgpio_dir_out_dir_first;
+ else
+ ops->direction_output = bgpio_dir_out_val_first;
+ ops->direction_input = bgpio_dir_in;
+ ops->get_direction = bgpio_get_dir;
} else {
- bgc->gc.ops->direction_output = bgpio_simple_dir_out;
- bgc->gc.ops->direction_input = bgpio_simple_dir_in;
+ if (flags & BGPIOF_NO_OUTPUT)
+ ops->direction_output = bgpio_dir_out_err;
+ else
+ ops->direction_output = bgpio_simple_dir_out;
+ ops->direction_input = bgpio_simple_dir_in;
}
return 0;
}
-int bgpio_init(struct bgpio_chip *bgc, struct device_d *dev,
+static int bgpio_request(struct gpio_chip *chip, unsigned gpio_pin)
+{
+ if (gpio_pin < chip->ngpio)
+ return 0;
+
+ return -EINVAL;
+}
+
+/**
+ * bgpio_init() - Initialize generic GPIO accessor functions
+ * @bgc: the GPIO chip to set up
+ * @dev: the parent device of the new GPIO chip (compulsory)
+ * @sz: the size (width) of the MMIO registers in bytes, typically 1, 2 or 4
+ * @dat: MMIO address for the register to READ the value of the GPIO lines, it
+ * is expected that a 1 in the corresponding bit in this register means the
+ * line is asserted
+ * @set: MMIO address for the register to SET the value of the GPIO lines, it is
+ * expected that we write the line with 1 in this register to drive the GPIO line
+ * high.
+ * @clr: MMIO address for the register to CLEAR the value of the GPIO lines, it is
+ * expected that we write the line with 1 in this register to drive the GPIO line
+ * low. It is allowed to leave this address as NULL, in that case the SET register
+ * will be assumed to also clear the GPIO lines, by actively writing the line
+ * with 0.
+ * @dirout: MMIO address for the register to set the line as OUTPUT. It is assumed
+ * that setting a line to 1 in this register will turn that line into an
+ * output line. Conversely, setting the line to 0 will turn that line into
+ * an input.
+ * @dirin: MMIO address for the register to set this line as INPUT. It is assumed
+ * that setting a line to 1 in this register will turn that line into an
+ * input line. Conversely, setting the line to 0 will turn that line into
+ * an output.
+ * @flags: Different flags that will affect the behaviour of the device, such as
+ * endianness etc.
+ */
+int bgpio_init(struct bgpio_chip *bgc, struct device *dev,
unsigned int sz, void __iomem *dat, void __iomem *set,
void __iomem *clr, void __iomem *dirout, void __iomem *dirin,
unsigned long flags)
{
+ struct gpio_ops *ops = &bgc->ops;
int ret;
- if ((sz > 4) || !is_power_of_2(sz))
+ if (!is_power_of_2(sz))
return -EINVAL;
bgc->bits = sz * 8;
- bgc->gc.ngpio = bgc->bits;
+ if (bgc->bits > BITS_PER_LONG)
+ return -EINVAL;
+
bgc->gc.base = -1;
+ bgc->gc.ngpio = bgc->bits;
bgc->gc.dev = dev;
- bgc->gc.ops = &bgc->ops;
+ bgc->gc.ops = ops;
+ ops->request = bgpio_request;
+ bgc->be_bits = !!(flags & BGPIOF_BIG_ENDIAN);
- ret = bgpio_setup_io(bgc, dat, set, clr);
+ ret = bgpio_setup_io(bgc, dat, set, clr, flags);
if (ret)
return ret;
- ret = bgpio_setup_accessors(dev, bgc, flags & BGPIOF_BIG_ENDIAN);
+ ret = bgpio_setup_accessors(dev, bgc, flags & BGPIOF_BIG_ENDIAN_BYTE_ORDER);
if (ret)
return ret;
- ret = bgpio_setup_direction(bgc, dirout, dirin);
+ ret = bgpio_setup_direction(bgc, dirout, dirin, flags);
if (ret)
return ret;
bgc->data = bgc->read_reg(bgc->reg_dat);
-
- if (bgc->gc.ops->set == bgpio_set_set && !(flags &
- BGPIOF_UNREADABLE_REG_SET))
+ if (ops->set == bgpio_set_set &&
+ !(flags & BGPIOF_UNREADABLE_REG_SET))
bgc->data = bgc->read_reg(bgc->reg_set);
- if (bgc->reg_dir && !(flags & BGPIOF_UNREADABLE_REG_DIR))
- bgc->dir = bgc->read_reg(bgc->reg_dir);
+ if (flags & BGPIOF_UNREADABLE_REG_DIR)
+ bgc->dir_unreadable = true;
+
+ /*
+ * Inspect hardware to find initial direction setting.
+ */
+ if ((bgc->reg_dir_out || bgc->reg_dir_in) &&
+ !(flags & BGPIOF_UNREADABLE_REG_DIR)) {
+ if (bgc->reg_dir_out)
+ bgc->dir = bgc->read_reg(bgc->reg_dir_out);
+ else if (bgc->reg_dir_in)
+ bgc->dir = ~bgc->read_reg(bgc->reg_dir_in);
+ /*
+ * If we have two direction registers, synchronise
+ * input setting to output setting, the library
+ * can not handle a line being input and output at
+ * the same time.
+ */
+ if (bgc->reg_dir_out && bgc->reg_dir_in)
+ bgc->write_reg(bgc->reg_dir_in, ~bgc->dir);
+ }
return ret;
}
+EXPORT_SYMBOL_GPL(bgpio_init);
void bgpio_remove(struct bgpio_chip *bgc)
{
gpiochip_remove(&bgc->gc);
free(bgc);
}
+EXPORT_SYMBOL_GPL(bgpio_remove);
#ifdef CONFIG_GPIO_GENERIC_PLATFORM
-static void __iomem *bgpio_map(struct device_d *dev, const char *name,
- resource_size_t sane_sz, int *err)
+static void __iomem *bgpio_map(struct device *dev,
+ const char *name,
+ resource_size_t sane_sz)
{
struct resource *r;
- struct resource *ret;
-
- *err = 0;
+ resource_size_t sz;
- r = dev_get_resource_by_name(dev, IORESOURCE_MEM, name);
+ r = dev_request_mem_resource_by_name(dev, name);
if (IS_ERR(r))
return NULL;
- if (resource_size(r) != sane_sz) {
- *err = -EINVAL;
- return NULL;
- }
+ sz = resource_size(r);
+ if (sz != sane_sz)
+ return IOMEM_ERR_PTR(-EINVAL);
- ret = request_iomem_region(dev_name(dev), r->start, r->end);
- if (IS_ERR(ret)) {
- *err = PTR_ERR(ret);
+ return IOMEM(r->start);
+}
+
+static const struct of_device_id bgpio_of_match[];
+
+static struct bgpio_pdata *bgpio_parse_dt(struct device *dev,
+ unsigned long *flags)
+{
+ struct bgpio_pdata *pdata;
+
+ if (!of_match_device(bgpio_of_match, dev))
return NULL;
- }
- return IOMEM(ret->start);
+ pdata = xzalloc(sizeof(struct bgpio_pdata));
+
+ pdata->base = -1;
+
+ if (of_device_is_big_endian(dev->of_node))
+ *flags |= BGPIOF_BIG_ENDIAN_BYTE_ORDER;
+
+ if (of_property_read_bool(dev->of_node, "no-output"))
+ *flags |= BGPIOF_NO_OUTPUT;
+
+ return pdata;
}
-static int bgpio_dev_probe(struct device_d *dev)
+static int bgpio_dev_probe(struct device *dev)
{
struct resource *r;
void __iomem *dat;
@@ -342,35 +531,37 @@ static int bgpio_dev_probe(struct device_d *dev)
unsigned long flags = 0;
int err;
struct bgpio_chip *bgc;
- struct bgpio_pdata *pdata = dev->platform_data;
+ struct bgpio_pdata *pdata;
+
+ pdata = bgpio_parse_dt(dev, &flags);
+ if (IS_ERR(pdata))
+ return PTR_ERR(pdata);
r = dev_get_resource_by_name(dev, IORESOURCE_MEM, "dat");
- if (IS_ERR(r))
- return PTR_ERR(r);
+ if (!r)
+ return -EINVAL;
sz = resource_size(r);
- dat = bgpio_map(dev, "dat", sz, &err);
- if (!dat)
- return err ? err : -EINVAL;
+ dat = bgpio_map(dev, "dat", sz);
+ if (IS_ERR(dat))
+ return PTR_ERR(dat);
- set = bgpio_map(dev, "set", sz, &err);
- if (err)
- return err;
+ set = bgpio_map(dev, "set", sz);
+ if (IS_ERR(set))
+ return PTR_ERR(set);
- clr = bgpio_map(dev, "clr", sz, &err);
- if (err)
- return err;
+ clr = bgpio_map(dev, "clr", sz);
+ if (IS_ERR(clr))
+ return PTR_ERR(clr);
- dirout = bgpio_map(dev, "dirout", sz, &err);
- if (err)
- return err;
+ dirout = bgpio_map(dev, "dirout", sz);
+ if (IS_ERR(dirout))
+ return PTR_ERR(dirout);
- dirin = bgpio_map(dev, "dirin", sz, &err);
- if (err)
- return err;
-
- dev_get_drvdata(dev, (const void **)&flags);
+ dirin = bgpio_map(dev, "dirin", sz);
+ if (IS_ERR(dirin))
+ return PTR_ERR(dirin);
bgc = xzalloc(sizeof(struct bgpio_chip));
@@ -378,57 +569,47 @@ static int bgpio_dev_probe(struct device_d *dev)
if (err)
return err;
- if (pdata) {
- bgc->gc.base = pdata->base;
- if (pdata->ngpio > 0)
- bgc->gc.ngpio = pdata->ngpio;
- }
+ bgc->gc.base = pdata->base;
+ bgc->gc.dev = dev;
+ bgc->gc.ops = &bgc->ops;
+ if (pdata->ngpio > 0)
+ bgc->gc.ngpio = pdata->ngpio;
dev->priv = bgc;
return gpiochip_add(&bgc->gc);
}
-static void bgpio_dev_remove(struct device_d *dev)
+static void bgpio_dev_remove(struct device *dev)
{
struct bgpio_chip *bgc = dev->priv;
bgpio_remove(bgc);
}
-static struct platform_device_id bgpio_id_table[] = {
+static const struct of_device_id bgpio_of_match[] = {
{
- .name = "basic-mmio-gpio",
- .driver_data = 0,
+ .compatible = "wd,mbl-gpio",
},
{
- .name = "basic-mmio-gpio-be",
- .driver_data = BGPIOF_BIG_ENDIAN,
+ .compatible = "brcm,bcm6345-gpio"
},
- { }
-};
-
-static struct of_device_id __maybe_unused bgpio_of_match[] = {
{
- .compatible = "wd,mbl-gpio",
+ .compatible = "ni,169445-nand-gpio"
}, {
/* sentinel */
}
};
+MODULE_DEVICE_TABLE(of, bgpio_of_match);
-static struct driver_d bgpio_driver = {
+static struct driver bgpio_driver = {
.name = "basic-mmio-gpio",
- .id_table = bgpio_id_table,
- .of_compatible = DRV_OF_COMPAT(bgpio_of_match),
+ .of_compatible = bgpio_of_match,
.probe = bgpio_dev_probe,
.remove = bgpio_dev_remove,
};
-static int bgpio_register(void)
-{
- return platform_driver_register(&bgpio_driver);
-}
-coredevice_initcall(bgpio_register);
+coredevice_platform_driver(bgpio_driver);
#endif
diff --git a/drivers/gpio/gpio-imx.c b/drivers/gpio/gpio-imx.c
index 2827e11e73..49c5555b98 100644
--- a/drivers/gpio/gpio-imx.c
+++ b/drivers/gpio/gpio-imx.c
@@ -1,23 +1,10 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+// SPDX-FileCopyrightText: 2004 Sascha Hauer, Synertronixx GmbH
+
/*
- * arch/arm/mach-imx/gpio.c
- *
- * author: Sascha Hauer
- * Created: april 20th, 2004
- * Copyright: Synertronixx GmbH
- *
- * Common code for i.MX machines
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
+ * arch/arm/mach-imx/gpio.c
*
+ * Common code for i.MX machines
*/
#include <common.h>
@@ -130,7 +117,7 @@ static struct gpio_ops imx_gpio_ops = {
.get_direction = imx_get_direction,
};
-static int imx_gpio_probe(struct device_d *dev)
+static int imx_gpio_probe(struct device *dev)
{
struct resource *iores;
struct imx_gpio_chip *imxgpio;
@@ -148,7 +135,7 @@ static int imx_gpio_probe(struct device_d *dev)
imxgpio->base = IOMEM(iores->start);
imxgpio->chip.ops = &imx_gpio_ops;
if (dev->id < 0) {
- imxgpio->chip.base = of_alias_get_id(dev->device_node, "gpio");
+ imxgpio->chip.base = of_alias_get_id(dev->of_node, "gpio");
if (imxgpio->chip.base < 0)
return imxgpio->chip.base;
imxgpio->chip.base *= 32;
@@ -197,6 +184,7 @@ static __maybe_unused struct of_device_id imx_gpio_dt_ids[] = {
/* sentinel */
}
};
+MODULE_DEVICE_TABLE(of, imx_gpio_dt_ids);
static struct platform_device_id imx_gpio_ids[] = {
{
@@ -210,16 +198,11 @@ static struct platform_device_id imx_gpio_ids[] = {
},
};
-static struct driver_d imx_gpio_driver = {
+static struct driver imx_gpio_driver = {
.name = "imx-gpio",
.probe = imx_gpio_probe,
.of_compatible = DRV_OF_COMPAT(imx_gpio_dt_ids),
.id_table = imx_gpio_ids,
};
-static int imx_gpio_add(void)
-{
- platform_driver_register(&imx_gpio_driver);
- return 0;
-}
-postcore_initcall(imx_gpio_add);
+postcore_platform_driver(imx_gpio_driver);
diff --git a/drivers/gpio/gpio-intel.c b/drivers/gpio/gpio-intel.c
new file mode 100644
index 0000000000..ebec220f46
--- /dev/null
+++ b/drivers/gpio/gpio-intel.c
@@ -0,0 +1,198 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+// SPDX-FileCopyrightText: 2004 Tomas Marek, Elrest Solutions Company s.r.o.
+
+/*
+ * Based on the Linux kernel v6.8 drivers/pinctrl/intel/pinctrl-intel.c.
+ */
+
+#include <common.h>
+#include <errno.h>
+#include <io.h>
+#include <gpio.h>
+
+#include <platform_data/gpio-intel.h>
+
+#define PADBAR 0x00c
+
+/* Offset from pad_regs */
+#define PADCFG0 0x000
+#define PADCFG0_RXEVCFG_MASK GENMASK(26, 25)
+#define PADCFG0_RXEVCFG_LEVEL (0 << 25)
+#define PADCFG0_RXEVCFG_EDGE (1 << 25)
+#define PADCFG0_RXEVCFG_DISABLED (2 << 25)
+#define PADCFG0_RXEVCFG_EDGE_BOTH (3 << 25)
+#define PADCFG0_PREGFRXSEL BIT(24)
+#define PADCFG0_RXINV BIT(23)
+#define PADCFG0_GPIROUTIOXAPIC BIT(20)
+#define PADCFG0_GPIROUTSCI BIT(19)
+#define PADCFG0_GPIROUTSMI BIT(18)
+#define PADCFG0_GPIROUTNMI BIT(17)
+#define PADCFG0_PMODE_SHIFT 10
+#define PADCFG0_PMODE_MASK GENMASK(13, 10)
+#define PADCFG0_PMODE_GPIO 0
+#define PADCFG0_GPIORXDIS BIT(9)
+#define PADCFG0_GPIOTXDIS BIT(8)
+#define PADCFG0_GPIORXSTATE BIT(1)
+#define PADCFG0_GPIOTXSTATE BIT(0)
+
+struct intel_gpio_chip {
+ struct gpio_chip chip;
+ void __iomem *community_pad_base;
+};
+
+static inline struct intel_gpio_chip *to_intel_gpio(struct gpio_chip *gc)
+{
+ return container_of(gc, struct intel_gpio_chip, chip);
+}
+
+static void __iomem *intel_gpio_padcfg0_reg(const struct intel_gpio_chip *chip,
+ const unsigned int gpio)
+{
+ const u32 pad_cfg_offset = 16;
+
+ return chip->community_pad_base + pad_cfg_offset * gpio;
+}
+
+static u32 intel_gpio_padcfg0_value(const struct intel_gpio_chip *chip,
+ const unsigned int gpio)
+{
+ return readl(intel_gpio_padcfg0_reg(chip, gpio));
+}
+
+static void intel_gpio_padcfg0_write(const struct intel_gpio_chip *chip,
+ const unsigned int gpio, u32 value)
+{
+ writel(value, intel_gpio_padcfg0_reg(chip, gpio));
+}
+
+static void intel_gpio_set_value(struct gpio_chip *gc, unsigned int gpio,
+ int value)
+{
+ struct intel_gpio_chip *chip = to_intel_gpio(gc);
+ u32 padcfg0;
+
+ padcfg0 = intel_gpio_padcfg0_value(chip, gpio);
+ if (value)
+ padcfg0 |= PADCFG0_GPIOTXSTATE;
+ else
+ padcfg0 &= ~PADCFG0_GPIOTXSTATE;
+ intel_gpio_padcfg0_write(chip, gpio, padcfg0);
+}
+
+static int intel_gpio_get_value(struct gpio_chip *gc, unsigned int gpio)
+{
+ struct intel_gpio_chip *chip = to_intel_gpio(gc);
+ u32 padcfg0;
+
+ padcfg0 = intel_gpio_padcfg0_value(chip, gpio);
+ if (!(padcfg0 & PADCFG0_GPIOTXDIS))
+ return !!(padcfg0 & PADCFG0_GPIOTXSTATE);
+
+ return !!(padcfg0 & PADCFG0_GPIORXSTATE);
+}
+
+static int intel_gpio_get_direction(struct gpio_chip *gc, unsigned int gpio)
+{
+ struct intel_gpio_chip *chip = to_intel_gpio(gc);
+ u32 padcfg0;
+
+ padcfg0 = intel_gpio_padcfg0_value(chip, gpio);
+
+ if (padcfg0 & PADCFG0_PMODE_MASK)
+ return -EINVAL;
+
+ if (padcfg0 & PADCFG0_GPIOTXDIS)
+ return GPIOF_DIR_IN;
+
+ return GPIOF_DIR_OUT;
+}
+
+static int intel_gpio_direction_input(struct gpio_chip *gc, unsigned int gpio)
+{
+ struct intel_gpio_chip *chip = to_intel_gpio(gc);
+ u32 padcfg0;
+
+ padcfg0 = intel_gpio_padcfg0_value(chip, gpio);
+ padcfg0 &= ~PADCFG0_GPIORXDIS;
+ padcfg0 |= PADCFG0_GPIOTXDIS;
+ intel_gpio_padcfg0_write(chip, gpio, padcfg0);
+
+ return 0;
+}
+
+static int intel_gpio_direction_output(struct gpio_chip *gc, unsigned int gpio,
+ int value)
+{
+ struct intel_gpio_chip *chip = to_intel_gpio(gc);
+ u32 padcfg0;
+
+ padcfg0 = intel_gpio_padcfg0_value(chip, gpio);
+ padcfg0 &= ~PADCFG0_GPIOTXDIS;
+ padcfg0 |= PADCFG0_GPIORXDIS;
+ if (value)
+ padcfg0 |= PADCFG0_GPIOTXSTATE;
+ else
+ padcfg0 &= ~PADCFG0_GPIOTXSTATE;
+ intel_gpio_padcfg0_write(chip, gpio, padcfg0);
+
+ return 0;
+}
+
+static struct gpio_ops intel_gpio_ops = {
+ .direction_input = intel_gpio_direction_input,
+ .direction_output = intel_gpio_direction_output,
+ .get_direction = intel_gpio_get_direction,
+ .get = intel_gpio_get_value,
+ .set = intel_gpio_set_value,
+};
+
+static int intel_gpio_probe(struct device *dev)
+{
+ const struct gpio_intel_platform_data *pdata;
+ struct intel_gpio_chip *intel_gpio;
+ void __iomem *community_pad_base;
+ void __iomem *community_base;
+ struct resource *iores;
+ int ret;
+
+ pdata = (struct gpio_intel_platform_data *)dev->platform_data;
+ if (!pdata) {
+ dev_err(dev, "Configuration missing!\n");
+ return -EINVAL;
+ }
+
+ iores = dev_request_mem_resource(dev, 0);
+ if (IS_ERR(iores)) {
+ dev_err(dev, "Memory resource request failed: %ld\n",
+ PTR_ERR(iores));
+ return PTR_ERR(iores);
+ }
+
+ intel_gpio = xzalloc(sizeof(*intel_gpio));
+
+ intel_gpio->chip.ops = &intel_gpio_ops;
+ intel_gpio->chip.ngpio = pdata->ngpios;
+ intel_gpio->chip.dev = dev;
+
+ community_base = IOMEM(iores->start);
+ community_pad_base = IOMEM(community_base + readl(community_base + PADBAR));
+
+ intel_gpio->community_pad_base = community_pad_base;
+
+ ret = gpiochip_add(&intel_gpio->chip);
+
+ if (ret) {
+ dev_err(dev, "Couldn't add gpiochip: %pe\n", ERR_PTR(ret));
+ kfree(intel_gpio);
+ return ret;
+ }
+
+ return 0;
+}
+
+static struct driver_d intel_gpio_driver = {
+ .name = "intel-gpio",
+ .probe = intel_gpio_probe,
+};
+
+coredevice_platform_driver(intel_gpio_driver);
diff --git a/drivers/gpio/gpio-jz4740.c b/drivers/gpio/gpio-jz4740.c
index 87e0716b06..911f9f2470 100644
--- a/drivers/gpio/gpio-jz4740.c
+++ b/drivers/gpio/gpio-jz4740.c
@@ -1,19 +1,9 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+// SPDX-FileCopyrightText: 2013,2014 Antony Pavlov <antonynpavlov@gmail.com>
+// SPDX-FileCopyrightText: 2009-2010 Lars-Peter Clausen <lars@metafoo.de>
+
/*
- * Copyright (C) 2013, 2014 Antony Pavlov <antonynpavlov@gmail.com>
- *
* Based on Linux JZ4740 platform GPIO support:
- * Copyright (C) 2009-2010, Lars-Peter Clausen <lars@metafoo.de>
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License as
- * published by the Free Software Foundation; either version 2 of
- * the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
*/
#include <common.h>
@@ -88,7 +78,7 @@ static struct gpio_ops jz4740_gpio_ops = {
.set = jz4740_gpio_set_value,
};
-static int jz4740_gpio_probe(struct device_d *dev)
+static int jz4740_gpio_probe(struct device *dev)
{
struct resource *iores;
void __iomem *base;
@@ -129,15 +119,12 @@ static __maybe_unused struct of_device_id jz4740_gpio_dt_ids[] = {
/* sentinel */
},
};
+MODULE_DEVICE_TABLE(of, jz4740_gpio_dt_ids);
-static struct driver_d jz4740_gpio_driver = {
+static struct driver jz4740_gpio_driver = {
.name = "jz4740-gpio",
.probe = jz4740_gpio_probe,
.of_compatible = DRV_OF_COMPAT(jz4740_gpio_dt_ids),
};
-static int jz4740_gpio_init(void)
-{
- return platform_driver_register(&jz4740_gpio_driver);
-}
-coredevice_initcall(jz4740_gpio_init);
+coredevice_platform_driver(jz4740_gpio_driver);
diff --git a/drivers/gpio/gpio-latch.c b/drivers/gpio/gpio-latch.c
new file mode 100644
index 0000000000..9a1a87250e
--- /dev/null
+++ b/drivers/gpio/gpio-latch.c
@@ -0,0 +1,196 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * GPIO latch driver
+ *
+ * Copyright (C) 2022 Sascha Hauer <s.hauer@pengutronix.de>
+ *
+ * This driver implements a GPIO (or better GPO as there is no input)
+ * multiplexer based on latches like this:
+ *
+ * CLK0 ----------------------. ,--------.
+ * CLK1 -------------------. `--------|> #0 |
+ * | | |
+ * OUT0 ----------------+--|-----------|D0 Q0|-----|<
+ * OUT1 --------------+-|--|-----------|D1 Q1|-----|<
+ * OUT2 ------------+-|-|--|-----------|D2 Q2|-----|<
+ * OUT3 ----------+-|-|-|--|-----------|D3 Q3|-----|<
+ * OUT4 --------+-|-|-|-|--|-----------|D4 Q4|-----|<
+ * OUT5 ------+-|-|-|-|-|--|-----------|D5 Q5|-----|<
+ * OUT6 ----+-|-|-|-|-|-|--|-----------|D6 Q6|-----|<
+ * OUT7 --+-|-|-|-|-|-|-|--|-----------|D7 Q7|-----|<
+ * | | | | | | | | | `--------'
+ * | | | | | | | | |
+ * | | | | | | | | | ,--------.
+ * | | | | | | | | `-----------|> #1 |
+ * | | | | | | | | | |
+ * | | | | | | | `--------------|D0 Q0|-----|<
+ * | | | | | | `----------------|D1 Q1|-----|<
+ * | | | | | `------------------|D2 Q2|-----|<
+ * | | | | `--------------------|D3 Q3|-----|<
+ * | | | `----------------------|D4 Q4|-----|<
+ * | | `------------------------|D5 Q5|-----|<
+ * | `--------------------------|D6 Q6|-----|<
+ * `----------------------------|D7 Q7|-----|<
+ * `--------'
+ *
+ * The above is just an example. The actual number of number of latches and
+ * the number of inputs per latch is derived from the number of GPIOs given
+ * in the corresponding device tree properties.
+ */
+
+#include <common.h>
+#include <errno.h>
+#include <io.h>
+#include <of.h>
+#include <gpio.h>
+#include <init.h>
+#include <of_gpio.h>
+#include <linux/bitmap.h>
+
+struct gpio_latch_priv {
+ struct gpio_chip gc;
+ int *clk_gpios;
+ int *latched_gpios;
+ int n_latched_gpios;
+ unsigned int setup_duration_ns;
+ unsigned int clock_duration_ns;
+ unsigned long *shadow;
+};
+
+static int gpio_latch_get_direction(struct gpio_chip *gc, unsigned int offset)
+{
+ return 0;
+}
+
+static void gpio_latch_set(struct gpio_chip *gc, unsigned int offset, int val)
+{
+ struct gpio_latch_priv *priv = container_of(gc, struct gpio_latch_priv, gc);
+ int latch = offset / priv->n_latched_gpios;
+ int i;
+
+ assign_bit(offset, priv->shadow, val);
+
+ for (i = 0; i < priv->n_latched_gpios; i++)
+ gpio_set_value(priv->latched_gpios[i],
+ test_bit(latch * priv->n_latched_gpios + i, priv->shadow));
+
+ ndelay(priv->setup_duration_ns);
+ gpio_set_value(priv->clk_gpios[latch], 1);
+ ndelay(priv->clock_duration_ns);
+ gpio_set_value(priv->clk_gpios[latch], 0);
+}
+static int gpio_latch_direction_output(struct gpio_chip *gc, unsigned gpio, int val)
+{
+ gpio_latch_set(gc, gpio, val);
+
+ return 0;
+}
+
+#define DURATION_NS_MAX 5000
+
+static struct gpio_ops gpio_latch_gpio_ops = {
+ .direction_output = gpio_latch_direction_output,
+ .set = gpio_latch_set,
+ .get_direction = gpio_latch_get_direction,
+};
+
+static int gpio_latch_probe(struct device *dev)
+{
+ struct gpio_latch_priv *priv;
+ int n_latches, i, ret;
+ struct device_node *np = dev->of_node;
+ enum of_gpio_flags flags;
+
+ priv = xzalloc(sizeof(*priv));
+
+ n_latches = of_gpio_named_count(np, "clk-gpios");
+ if (n_latches < 0) {
+ dev_err(dev, "invalid or missing clk-gpios");
+ ret = -EINVAL;
+ goto err_gpio;
+ }
+
+ priv->n_latched_gpios = of_gpio_named_count(np, "latched-gpios");
+ if (priv->n_latched_gpios < 0) {
+ dev_err(dev, "invalid or missing latched-gpios");
+ ret = -EINVAL;
+ goto err_gpio;
+ }
+
+ priv->clk_gpios = xzalloc(sizeof(int) * n_latches);
+ priv->latched_gpios = xzalloc(sizeof(int) * priv->n_latched_gpios);
+
+ for (i = 0; i < n_latches; i++) {
+ priv->clk_gpios[i] = of_get_named_gpio_flags(np, "clk-gpios",
+ i, &flags);
+ ret = gpio_request_one(priv->clk_gpios[i],
+ flags & OF_GPIO_ACTIVE_LOW ? GPIOF_ACTIVE_LOW : 0,
+ dev_name(dev));
+ if (ret) {
+ dev_err(dev, "Cannot request gpio %d: %s\n", priv->clk_gpios[i],
+ strerror(-ret));
+ goto err_gpio;
+ }
+
+ gpio_direction_output(priv->clk_gpios[i], 0);
+ }
+
+ for (i = 0; i < priv->n_latched_gpios; i++) {
+ priv->latched_gpios[i] = of_get_named_gpio_flags(np, "latched-gpios",
+ i, &flags);
+ ret = gpio_request_one(priv->latched_gpios[i],
+ flags & OF_GPIO_ACTIVE_LOW ? GPIOF_ACTIVE_LOW : 0,
+ dev_name(dev));
+ if (ret) {
+ dev_err(dev, "Cannot request gpio %d: %s\n", priv->latched_gpios[i],
+ strerror(-ret));
+ goto err_gpio;
+ }
+ }
+
+ priv->shadow = bitmap_zalloc(n_latches * priv->n_latched_gpios);
+
+ of_property_read_u32(np, "setup-duration-ns", &priv->setup_duration_ns);
+ if (priv->setup_duration_ns > DURATION_NS_MAX) {
+ dev_warn(dev, "setup-duration-ns too high, limit to %d\n",
+ DURATION_NS_MAX);
+ priv->setup_duration_ns = DURATION_NS_MAX;
+ }
+
+ of_property_read_u32(np, "clock-duration-ns", &priv->clock_duration_ns);
+ if (priv->clock_duration_ns > DURATION_NS_MAX) {
+ dev_warn(dev, "clock-duration-ns too high, limit to %d\n",
+ DURATION_NS_MAX);
+ priv->clock_duration_ns = DURATION_NS_MAX;
+ }
+
+ priv->gc.ops = &gpio_latch_gpio_ops;
+ priv->gc.ngpio = n_latches * priv->n_latched_gpios;
+ priv->gc.base = -1;
+ priv->gc.dev = dev;
+
+ return gpiochip_add(&priv->gc);
+
+err_gpio:
+ return ret;
+}
+
+static const struct of_device_id gpio_latch_ids[] = {
+ {
+ .compatible = "gpio-latch",
+ }, {
+ /* sentinel */
+ }
+};
+MODULE_DEVICE_TABLE(of, gpio_latch_ids);
+
+static struct driver gpio_latch_driver = {
+ .name = "gpio-latch",
+ .probe = gpio_latch_probe,
+ .of_compatible = DRV_OF_COMPAT(gpio_latch_ids),
+};
+device_platform_driver(gpio_latch_driver);
+
+MODULE_LICENSE("GPL v2");
+MODULE_AUTHOR("Sascha Hauer <s.hauer@pengutronix.de>");
+MODULE_DESCRIPTION("GPIO latch driver");
diff --git a/drivers/gpio/gpio-libftdi1.c b/drivers/gpio/gpio-libftdi1.c
index cd36b08ca6..b7c94b573d 100644
--- a/drivers/gpio/gpio-libftdi1.c
+++ b/drivers/gpio/gpio-libftdi1.c
@@ -1,18 +1,8 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+// SPDX-FileCopyrightText: 2016,2017 Antony Pavlov <antonynpavlov@gmail.com>
+
/*
* libftdi1 sandbox barebox GPIO driver
- *
- * Copyright (C) 2016, 2017 Antony Pavlov <antonynpavlov@gmail.com>
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License as
- * published by the Free Software Foundation; either version 2 of
- * the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
*/
#include <common.h>
@@ -76,7 +66,7 @@ static struct gpio_ops libftdi1_gpio_ops = {
.set = libftdi1_gpio_set_value,
};
-static int libftdi1_gpio_probe(struct device_d *dev)
+static int libftdi1_gpio_probe(struct device *dev)
{
struct libftdi1_gpio_chip *gpio;
struct ft2232_bitbang *ftbb;
@@ -84,13 +74,13 @@ static int libftdi1_gpio_probe(struct device_d *dev)
uint32_t id_vendor, id_product;
const char *i_serial_number = NULL;
- of_property_read_u32(dev->device_node, "usb,id_vendor",
+ of_property_read_u32(dev->of_node, "usb,id_vendor",
&id_vendor);
- of_property_read_u32(dev->device_node, "usb,id_product",
+ of_property_read_u32(dev->of_node, "usb,id_product",
&id_product);
- of_property_read_string(dev->device_node, "usb,i_serial_number",
+ of_property_read_string(dev->of_node, "usb,i_serial_number",
&i_serial_number);
ftbb = barebox_libftdi1_open(id_vendor, id_product,
@@ -122,13 +112,14 @@ static __maybe_unused const struct of_device_id libftdi1_gpio_dt_ids[] = {
/* sentinel */
},
};
+MODULE_DEVICE_TABLE(of, libftdi1_gpio_dt_ids);
-static void libftdi1_gpio_remove(struct device_d *dev)
+static void libftdi1_gpio_remove(struct device *dev)
{
barebox_libftdi1_close();
}
-static struct driver_d libftdi1_gpio_driver = {
+static struct driver libftdi1_gpio_driver = {
.name = "libftdi1-gpio",
.probe = libftdi1_gpio_probe,
.remove = libftdi1_gpio_remove,
diff --git a/drivers/gpio/gpio-malta-fpga-i2c.c b/drivers/gpio/gpio-malta-fpga-i2c.c
index 0188e51af2..d0e454015c 100644
--- a/drivers/gpio/gpio-malta-fpga-i2c.c
+++ b/drivers/gpio/gpio-malta-fpga-i2c.c
@@ -1,20 +1,5 @@
-/*
- * Copyright (C) 2014 Antony Pavlov <antonynpavlov@gmail.com>
- *
- * This file is part of barebox.
- * See file CREDITS for list of people who contributed to this project.
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License as
- * published by the Free Software Foundation; either version 2 of
- * the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- */
+// SPDX-License-Identifier: GPL-2.0-or-later
+// SPDX-FileCopyrightText: 2014 Antony Pavlov <antonynpavlov@gmail.com>
#include <common.h>
#include <init.h>
@@ -131,7 +116,7 @@ static struct gpio_ops malta_i2c_gpio_ops = {
.set = malta_i2c_gpio_set_value,
};
-static int malta_i2c_gpio_probe(struct device_d *dev)
+static int malta_i2c_gpio_probe(struct device *dev)
{
struct resource *iores;
void __iomem *gpio_base;
@@ -174,15 +159,12 @@ static __maybe_unused struct of_device_id malta_i2c_gpio_dt_ids[] = {
/* sentinel */
},
};
+MODULE_DEVICE_TABLE(of, malta_i2c_gpio_dt_ids);
-static struct driver_d malta_i2c_gpio_driver = {
+static struct driver malta_i2c_gpio_driver = {
.name = "malta-fpga-i2c-gpio",
.probe = malta_i2c_gpio_probe,
.of_compatible = DRV_OF_COMPAT(malta_i2c_gpio_dt_ids),
};
-static int malta_i2c_gpio_driver_init(void)
-{
- return platform_driver_register(&malta_i2c_gpio_driver);
-}
-coredevice_initcall(malta_i2c_gpio_driver_init);
+coredevice_platform_driver(malta_i2c_gpio_driver);
diff --git a/drivers/gpio/gpio-mpc8xxx.c b/drivers/gpio/gpio-mpc8xxx.c
index 979f92ad30..bf855958a3 100644
--- a/drivers/gpio/gpio-mpc8xxx.c
+++ b/drivers/gpio/gpio-mpc8xxx.c
@@ -1,12 +1,9 @@
+// SPDX-License-Identifier: GPL-2.0-only
+// SPDX-FileCopyrightText: 2008 Peter Korsgaard <jacmet@sunsite.dk>
+// SPDX-FileCopyrightText: 2016 Freescale Semiconductor Inc.
+
/*
* GPIOs on MPC512x/8349/8572/8610/QorIQ and compatible
- *
- * Copyright (C) 2008 Peter Korsgaard <jacmet@sunsite.dk>
- * Copyright (C) 2016 Freescale Semiconductor Inc.
- *
- * This file is licensed under the terms of the GNU General Public License
- * version 2. This program is licensed "as is" without any warranty of any
- * kind, whether express or implied.
*/
#include <common.h>
@@ -37,7 +34,7 @@ struct mpc8xxx_gpio_devtype {
int (*gpio_get)(struct bgpio_chip *, unsigned int);
};
-static int mpc8xxx_probe(struct device_d *dev)
+static int mpc8xxx_probe(struct device *dev)
{
struct device_node *np;
struct resource *iores;
@@ -47,8 +44,8 @@ static int mpc8xxx_probe(struct device_d *dev)
mpc8xxx_gc = xzalloc(sizeof(*mpc8xxx_gc));
- if (dev->device_node) {
- np = dev->device_node;
+ if (dev->of_node) {
+ np = dev->of_node;
} else {
dev_err(dev, "no device_node\n");
return -ENODEV;
@@ -68,7 +65,8 @@ static int mpc8xxx_probe(struct device_d *dev)
ret = bgpio_init(bgc, dev, 4,
mpc8xxx_gc->regs + GPIO_DAT,
NULL, NULL,
- mpc8xxx_gc->regs + GPIO_DIR, NULL, 0);
+ mpc8xxx_gc->regs + GPIO_DIR, NULL,
+ BGPIOF_BIG_ENDIAN);
if (ret)
goto err;
dev_dbg(dev, "GPIO registers are LITTLE endian\n");
@@ -77,7 +75,8 @@ static int mpc8xxx_probe(struct device_d *dev)
mpc8xxx_gc->regs + GPIO_DAT,
NULL, NULL,
mpc8xxx_gc->regs + GPIO_DIR, NULL,
- BGPIOF_BIG_ENDIAN);
+ BGPIOF_BIG_ENDIAN
+ | BGPIOF_BIG_ENDIAN_BYTE_ORDER);
if (ret)
goto err;
dev_dbg(dev, "GPIO registers are BIG endian\n");
@@ -108,15 +107,12 @@ static __maybe_unused struct of_device_id mpc8xxx_gpio_ids[] = {
/* sentinel */
},
};
+MODULE_DEVICE_TABLE(of, mpc8xxx_gpio_ids);
-static struct driver_d mpc8xxx_driver = {
+static struct driver mpc8xxx_driver = {
.name = "mpc8xxx-gpio",
.probe = mpc8xxx_probe,
.of_compatible = DRV_OF_COMPAT(mpc8xxx_gpio_ids),
};
-static int __init mpc8xxx_init(void)
-{
- return platform_driver_register(&mpc8xxx_driver);
-}
-postcore_initcall(mpc8xxx_init);
+postcore_platform_driver(mpc8xxx_driver);
diff --git a/drivers/gpio/gpio-mxs.c b/drivers/gpio/gpio-mxs.c
index ef78873ad2..770acb61c8 100644
--- a/drivers/gpio/gpio-mxs.c
+++ b/drivers/gpio/gpio-mxs.c
@@ -1,15 +1,7 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+
/*
* Freescale MXS gpio support
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
*/
#include <common.h>
@@ -106,7 +98,7 @@ static struct gpio_ops mxs_gpio_ops = {
.get_direction = mxs_get_direction,
};
-static int mxs_gpio_probe(struct device_d *dev)
+static int mxs_gpio_probe(struct device *dev)
{
struct mxs_gpio_chip *mxsgpio;
struct mxs_gpio_regs *regs;
@@ -119,7 +111,7 @@ static int mxs_gpio_probe(struct device_d *dev)
mxsgpio = xzalloc(sizeof(*mxsgpio));
mxsgpio->chip.ops = &mxs_gpio_ops;
if (dev->id < 0) {
- id = of_alias_get_id(dev->device_node, "gpio");
+ id = of_alias_get_id(dev->of_node, "gpio");
if (id < 0)
return id;
mxsgpio->base = dev_get_mem_region(dev->parent, 0);
@@ -158,6 +150,7 @@ static __maybe_unused struct of_device_id mxs_gpio_dt_ids[] = {
/* sentinel */
}
};
+MODULE_DEVICE_TABLE(of, mxs_gpio_dt_ids);
static struct platform_device_id mxs_gpio_ids[] = {
{
@@ -171,16 +164,11 @@ static struct platform_device_id mxs_gpio_ids[] = {
},
};
-static struct driver_d mxs_gpio_driver = {
+static struct driver mxs_gpio_driver = {
.name = "gpio-mxs",
.probe = mxs_gpio_probe,
.of_compatible = DRV_OF_COMPAT(mxs_gpio_dt_ids),
.id_table = mxs_gpio_ids,
};
-static int mxs_gpio_add(void)
-{
- platform_driver_register(&mxs_gpio_driver);
- return 0;
-}
-postcore_initcall(mxs_gpio_add);
+postcore_platform_driver(mxs_gpio_driver);
diff --git a/drivers/gpio/gpio-omap.c b/drivers/gpio/gpio-omap.c
index b00766a6aa..3fcb7387e3 100644
--- a/drivers/gpio/gpio-omap.c
+++ b/drivers/gpio/gpio-omap.c
@@ -1,35 +1,11 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+// SPDX-FileCopyrightText: 2009 Wind River Systems, Inc. (Tom Rix <Tom.Rix@windriver.com>)
+// SPDX-FileCopyrightText: 2003-2005 Nokia Corporation (Juha Yrjölä <juha.yrjola@nokia.com>)
+
/*
- * Copyright (c) 2009 Wind River Systems, Inc.
- * Tom Rix <Tom.Rix@windriver.com>
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License as
- * published by the Free Software Foundation; either version 2 of
- * the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- *
- * This work is derived from the linux 2.6.27 kernel source
- * To fetch, use the kernel repository
- * git://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux-2.6.git
- * Use the v2.6.27 tag.
- *
- * Below is the original's header including its copyright
- *
- * linux/arch/arm/plat-omap/gpio.c
- *
* Support functions for OMAP GPIO
*
- * Copyright (C) 2003-2005 Nokia Corporation
- * Written by Juha Yrjölä <juha.yrjola@nokia.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.
+ * This work is derived from the omap GPIO driver in Linux 2.6.27.
*/
#include <common.h>
#include <io.h>
@@ -139,7 +115,7 @@ static struct gpio_ops omap_gpio_ops = {
.set = omap_gpio_set_value,
};
-static int omap_gpio_probe(struct device_d *dev)
+static int omap_gpio_probe(struct device *dev)
{
struct resource *iores;
struct omap_gpio_chip *omapgpio;
@@ -158,7 +134,7 @@ static int omap_gpio_probe(struct device_d *dev)
omapgpio->chip.ops = &omap_gpio_ops;
if (dev->id < 0) {
- omapgpio->chip.base = of_alias_get_id(dev->device_node, "gpio");
+ omapgpio->chip.base = of_alias_get_id(dev->of_node, "gpio");
if (omapgpio->chip.base < 0)
return omapgpio->chip.base;
omapgpio->chip.base *= 32;
@@ -185,15 +161,12 @@ static __maybe_unused struct of_device_id omap_gpio_dt_ids[] = {
}, {
}
};
+MODULE_DEVICE_TABLE(of, omap_gpio_dt_ids);
-static struct driver_d omap_gpio_driver = {
+static struct driver omap_gpio_driver = {
.name = "omap-gpio",
.probe = omap_gpio_probe,
.of_compatible = DRV_OF_COMPAT(omap_gpio_dt_ids),
};
-static int omap_gpio_add(void)
-{
- return platform_driver_register(&omap_gpio_driver);
-}
-coredevice_initcall(omap_gpio_add);
+coredevice_platform_driver(omap_gpio_driver);
diff --git a/drivers/gpio/gpio-orion.c b/drivers/gpio/gpio-orion.c
index 63ef966edf..0a1b50069b 100644
--- a/drivers/gpio/gpio-orion.c
+++ b/drivers/gpio/gpio-orion.c
@@ -1,18 +1,9 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+
/*
* Marvell Orion/MVEBU SoC GPIO driver
*
* Sebastian Hesselbarth <sebastian.hesselbarth@gmail.com>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
*/
#include <common.h>
@@ -87,14 +78,11 @@ static struct gpio_ops orion_gpio_ops = {
.set = orion_gpio_set_value,
};
-static int orion_gpio_probe(struct device_d *dev)
+static int orion_gpio_probe(struct device *dev)
{
struct resource *iores;
struct orion_gpio_chip *gpio;
-
- dev->id = of_alias_get_id(dev->device_node, "gpio");
- if (dev->id < 0)
- return dev->id;
+ int id;
gpio = xzalloc(sizeof(*gpio));
iores = dev_request_mem_resource(dev, 0);
@@ -105,9 +93,14 @@ static int orion_gpio_probe(struct device_d *dev)
gpio->regs = IOMEM(iores->start);
gpio->chip.dev = dev;
gpio->chip.ops = &orion_gpio_ops;
- gpio->chip.base = dev->id * 32;
+
+ id = of_alias_get_id(dev->of_node, "gpio");
+ if (id < 0)
+ return id;
+
+ gpio->chip.base = id * 32;
gpio->chip.ngpio = 32;
- of_property_read_u32(dev->device_node, "ngpios", &gpio->chip.ngpio);
+ of_property_read_u32(dev->of_node, "ngpios", &gpio->chip.ngpio);
gpiochip_add(&gpio->chip);
@@ -120,8 +113,9 @@ static struct of_device_id orion_gpio_dt_ids[] = {
{ .compatible = "marvell,orion-gpio", },
{ }
};
+MODULE_DEVICE_TABLE(of, orion_gpio_dt_ids);
-static struct driver_d orion_gpio_driver = {
+static struct driver orion_gpio_driver = {
.name = "orion-gpio",
.probe = orion_gpio_probe,
.of_compatible = DRV_OF_COMPAT(orion_gpio_dt_ids),
diff --git a/drivers/gpio/gpio-pca953x.c b/drivers/gpio/gpio-pca953x.c
index 98a7a6c97c..e303f6b21f 100644
--- a/drivers/gpio/gpio-pca953x.c
+++ b/drivers/gpio/gpio-pca953x.c
@@ -1,21 +1,19 @@
+// SPDX-License-Identifier: GPL-2.0-only
+// SPDX-FileCopyrightText: 2005 Ben Gardner <bgardner@wabtec.com>
+// SPDX-FileCopyrightText: 2007 Marvell International Ltd.
+
/*
* PCA953x 4/8/16/24/40 bit I/O ports
*
* This code was ported from linux-3.15 kernel by Antony Pavlov.
- *
- * Copyright (C) 2005 Ben Gardner <bgardner@wabtec.com>
- * Copyright (C) 2007 Marvell International Ltd.
- *
* Derived from drivers/i2c/chips/pca9539.c
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; version 2 of the License.
*/
#include <common.h>
#include <malloc.h>
#include <driver.h>
+#include <linux/gpio/consumer.h>
+#include <regulator.h>
#include <xfuncs.h>
#include <errno.h>
#include <i2c/i2c.h>
@@ -41,6 +39,8 @@
#define PCA_GPIO_MASK 0x00FF
#define PCA_INT 0x0100
+#define PCA_PCAL 0x0200
+#define PCA_LATCH_INT (PCA_PCAL | PCA_INT)
#define PCA953X_TYPE 0x1000
#define PCA957X_TYPE 0x2000
@@ -60,6 +60,8 @@ static struct platform_device_id pca953x_id[] = {
{ "pca9575", 16 | PCA957X_TYPE | PCA_INT, },
{ "pca9698", 40 | PCA953X_TYPE, },
+ { "pcal6408", 8 | PCA953X_TYPE | PCA_LATCH_INT, },
+
{ "max7310", 8 | PCA953X_TYPE, },
{ "max7312", 16 | PCA953X_TYPE | PCA_INT, },
{ "max7313", 16 | PCA953X_TYPE | PCA_INT, },
@@ -410,12 +412,14 @@ out:
return ret;
}
-static int pca953x_probe(struct device_d *dev)
+static int pca953x_probe(struct device *dev)
{
struct i2c_client *client = to_i2c_client(dev);
unsigned long driver_data;
struct pca953x_platform_data *pdata;
struct pca953x_chip *chip;
+ struct regulator *reg;
+ struct gpio_desc *reset_gpio;
int ret;
u32 invert = 0;
@@ -439,6 +443,20 @@ static int pca953x_probe(struct device_d *dev)
chip->client = client;
+ reset_gpio = gpiod_get_optional(dev, "reset", GPIOD_OUT_LOW);
+ if (IS_ERR(reset_gpio))
+ dev_warn(dev, "Failed to get 'reset' GPIO (ignored)\n");
+
+ reg = regulator_get(dev, "vcc");
+ if (IS_ERR(reg)) {
+ dev_warn(dev, "Failed to get 'vcc' regulator (ignored).\n");
+ reg = NULL;
+ }
+
+ ret = regulator_enable(reg);
+ if (ret)
+ return dev_err_probe(dev, ret, "failed to enable register\n");
+
chip->chip_type = driver_data & (PCA953X_TYPE | PCA957X_TYPE);
/* initialize cached registers from their original values.
@@ -457,6 +475,8 @@ static int pca953x_probe(struct device_d *dev)
if (ret)
return ret;
+ slice_depends_on(gpiochip_slice(&chip->gpio_chip), i2c_client_slice(client));
+
if (pdata && pdata->setup) {
ret = pdata->setup(client, chip->gpio_chip.base,
chip->gpio_chip.ngpio, pdata->context);
@@ -472,7 +492,10 @@ static int pca953x_probe(struct device_d *dev)
#define OF_957X(__nrgpio, __int) (void *)(__nrgpio | PCA957X_TYPE | __int)
static const struct of_device_id pca953x_dt_ids[] = {
+ { .compatible = "nxp,pca6408", .data = OF_953X(8, PCA_INT), },
+ { .compatible = "nxp,pca6416", .data = OF_953X(16, PCA_INT), },
{ .compatible = "nxp,pca9505", .data = OF_953X(40, PCA_INT), },
+ { .compatible = "nxp,pca9506", .data = OF_953X(40, PCA_INT), },
{ .compatible = "nxp,pca9534", .data = OF_953X( 8, PCA_INT), },
{ .compatible = "nxp,pca9535", .data = OF_953X(16, PCA_INT), },
{ .compatible = "nxp,pca9536", .data = OF_953X( 4, 0), },
@@ -487,21 +510,36 @@ static const struct of_device_id pca953x_dt_ids[] = {
{ .compatible = "nxp,pca9575", .data = OF_957X(16, PCA_INT), },
{ .compatible = "nxp,pca9698", .data = OF_953X(40, 0), },
+ { .compatible = "nxp,pcal6408", .data = OF_953X(8, PCA_LATCH_INT), },
+ { .compatible = "nxp,pcal6416", .data = OF_953X(16, PCA_LATCH_INT), },
+ { .compatible = "nxp,pcal6524", .data = OF_953X(24, PCA_LATCH_INT), },
+ { .compatible = "nxp,pcal9535", .data = OF_953X(16, PCA_LATCH_INT), },
+ { .compatible = "nxp,pcal9554b", .data = OF_953X( 8, PCA_LATCH_INT), },
+ { .compatible = "nxp,pcal9555a", .data = OF_953X(16, PCA_LATCH_INT), },
+
{ .compatible = "maxim,max7310", .data = OF_953X( 8, 0), },
{ .compatible = "maxim,max7312", .data = OF_953X(16, PCA_INT), },
{ .compatible = "maxim,max7313", .data = OF_953X(16, PCA_INT), },
{ .compatible = "maxim,max7315", .data = OF_953X( 8, PCA_INT), },
+ { .compatible = "maxim,max7318", .data = OF_953X(16, PCA_INT), },
{ .compatible = "ti,pca6107", .data = OF_953X( 8, PCA_INT), },
+ { .compatible = "ti,pca9536", .data = OF_953X( 4, 0), },
{ .compatible = "ti,tca6408", .data = OF_953X( 8, PCA_INT), },
{ .compatible = "ti,tca6416", .data = OF_953X(16, PCA_INT), },
{ .compatible = "ti,tca6424", .data = OF_953X(24, PCA_INT), },
+ { .compatible = "ti,tca9539", .data = OF_953X(16, PCA_INT), },
+
+ { .compatible = "onnn,cat9554", .data = OF_953X( 8, PCA_INT), },
+ { .compatible = "onnn,pca9654", .data = OF_953X( 8, PCA_INT), },
+ { .compatible = "onnn,pca9655", .data = OF_953X(16, PCA_INT), },
{ .compatible = "exar,xra1202", .data = OF_953X( 8, 0), },
{ }
};
+MODULE_DEVICE_TABLE(of, pca953x_dt_ids);
-static struct driver_d pca953x_driver = {
+static struct driver pca953x_driver = {
.name = "pca953x",
.probe = pca953x_probe,
.of_compatible = DRV_OF_COMPAT(pca953x_dt_ids),
diff --git a/drivers/gpio/gpio-pcf857x.c b/drivers/gpio/gpio-pcf857x.c
index 6c1c0ac352..52c3a6d00a 100644
--- a/drivers/gpio/gpio-pcf857x.c
+++ b/drivers/gpio/gpio-pcf857x.c
@@ -1,14 +1,10 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+// SPDX-FileCopyrightText: 2007 David Brownell
+
/*
* Driver for pcf857x, pca857x, and pca967x I2C GPIO expanders
*
* This code was ported from linux-5.1 kernel by Michael Grzeschik.
- *
- * Copyright (C) 2007 David Brownell
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
*/
#include <common.h>
@@ -149,10 +145,10 @@ static struct gpio_ops pcf857x_gpio_ops = {
.set = pcf857x_set,
};
-static int pcf857x_probe(struct device_d *dev)
+static int pcf857x_probe(struct device *dev)
{
struct i2c_client *client = to_i2c_client(dev);
- struct device_node *np = dev->device_node;
+ struct device_node *np = dev->of_node;
struct pcf857x *gpio;
unsigned long driver_data;
unsigned int n_latch = 0;
@@ -223,11 +219,7 @@ static int pcf857x_probe(struct device_d *dev)
*/
gpio->out = ~n_latch;
- ret = gpiochip_add(&gpio->chip);
- if (ret)
- return ret;
-
- return ret;
+ return gpiochip_add(&gpio->chip);
}
static const struct of_device_id pcf857x_dt_ids[] = {
@@ -246,8 +238,9 @@ static const struct of_device_id pcf857x_dt_ids[] = {
{ .compatible = "maxim,max7329", .data = (void *)8 },
{ }
};
+MODULE_DEVICE_TABLE(of, pcf857x_dt_ids);
-static struct driver_d pcf857x_driver = {
+static struct driver pcf857x_driver = {
.name = "pcf857x",
.probe = pcf857x_probe,
.of_compatible = DRV_OF_COMPAT(pcf857x_dt_ids),
diff --git a/drivers/gpio/gpio-pl061.c b/drivers/gpio/gpio-pl061.c
index f34aba9da9..8dd9ca3bd5 100644
--- a/drivers/gpio/gpio-pl061.c
+++ b/drivers/gpio/gpio-pl061.c
@@ -1,10 +1,7 @@
+// SPDX-License-Identifier: GPL-2.0-only
+// SPDX-FileCopyrightText: 2008,2009 Provigent Ltd.
+
/*
- * Copyright (C) 2008, 2009 Provigent Ltd.
- *
- * 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.
- *
* Driver for the ARM PrimeCell(tm) General Purpose Input/Output (PL061)
*
* Data sheet: ARM DDI 0190B, September 2000
@@ -87,7 +84,18 @@ static void pl061_set_value(struct gpio_chip *gc, unsigned offset, int value)
writeb(!!value << offset, chip->base + (1 << (offset + 2)));
}
+static int pl061_get_direction(struct gpio_chip *gc, unsigned offset)
+{
+ struct pl061_gpio *chip = container_of(gc, struct pl061_gpio, gc);
+
+ if (readb(chip->base + GPIODIR) & (1 << offset))
+ return GPIOF_DIR_OUT;
+
+ return GPIOF_DIR_IN;
+}
+
static struct gpio_ops pl061_gpio_ops = {
+ .get_direction = pl061_get_direction,
.direction_input = pl061_direction_input,
.direction_output = pl061_direction_output,
.get = pl061_get_value,
diff --git a/drivers/gpio/gpio-raspberrypi-exp.c b/drivers/gpio/gpio-raspberrypi-exp.c
new file mode 100644
index 0000000000..a021253489
--- /dev/null
+++ b/drivers/gpio/gpio-raspberrypi-exp.c
@@ -0,0 +1,273 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Raspberry Pi 3 expander GPIO driver
+ *
+ * Uses the firmware mailbox service to communicate with the
+ * GPIO expander on the VPU.
+ *
+ * Copyright (C) 2017 Raspberry Pi Trading Ltd.
+ */
+
+#include <common.h>
+#include <gpio.h>
+#include <init.h>
+#include <mach/bcm283x/mbox.h>
+
+#define NUM_GPIO 8
+
+#define RPI_EXP_GPIO_BASE 128
+
+#define RPI_EXP_GPIO_DIR_IN 0
+#define RPI_EXP_GPIO_DIR_OUT 1
+
+struct rpi_exp_gpio {
+ struct gpio_chip gc;
+ struct rpi_firmware *fw;
+};
+
+/* VC4 firmware mailbox interface data structures */
+struct gpio_set_config {
+ struct bcm2835_mbox_hdr hdr; /* buf_size, code */
+ struct bcm2835_mbox_tag_hdr tag_hdr; /* tag, val_buf_size, val_len */
+ union {
+ struct {
+ u32 gpio;
+ u32 direction;
+ u32 polarity;
+ u32 term_en;
+ u32 term_pull_up;
+ u32 state;
+ } req;
+ } body;
+ u32 end_tag;
+};
+
+struct gpio_get_config {
+ struct bcm2835_mbox_hdr hdr;
+ struct bcm2835_mbox_tag_hdr tag_hdr;
+ union {
+ struct {
+ u32 gpio;
+ u32 direction;
+ u32 polarity;
+ u32 term_en;
+ u32 term_pull_up;
+ } req;
+ } body;
+ u32 end_tag;
+};
+
+struct gpio_get_set_state {
+ struct bcm2835_mbox_hdr hdr;
+ struct bcm2835_mbox_tag_hdr tag_hdr;
+ union {
+ struct {
+ u32 gpio;
+ u32 state;
+ } req;
+ } body;
+ u32 end_tag;
+};
+
+static inline struct rpi_exp_gpio *to_rpi_gpio(struct gpio_chip *gc)
+{
+ return container_of(gc, struct rpi_exp_gpio, gc);
+}
+
+static int rpi_exp_gpio_get_polarity(struct gpio_chip *gc, unsigned int off)
+{
+ struct rpi_exp_gpio *gpio;
+ int ret;
+ BCM2835_MBOX_STACK_ALIGN(struct gpio_get_config, get);
+ BCM2835_MBOX_INIT_HDR(get);
+ BCM2835_MBOX_INIT_TAG(get, GET_GPIO_CONFIG);
+
+ gpio = to_rpi_gpio(gc);
+
+ get->body.req.gpio = off + RPI_EXP_GPIO_BASE; /* GPIO to update */
+
+ ret = bcm2835_mbox_call_prop(BCM2835_MBOX_PROP_CHAN, &get->hdr);
+ if (ret || get->body.req.gpio != 0) {
+ dev_err(gc->dev, "Failed to get GPIO %u config (%d %x)\n",
+ off, ret, get->body.req.gpio);
+ return ret ? ret : -EIO;
+ }
+ return get->body.req.polarity;
+}
+
+static int rpi_exp_gpio_dir_in(struct gpio_chip *gc, unsigned int off)
+{
+ struct rpi_exp_gpio *gpio;
+ int ret;
+ BCM2835_MBOX_STACK_ALIGN(struct gpio_set_config, set_in);
+ BCM2835_MBOX_INIT_HDR(set_in);
+ BCM2835_MBOX_INIT_TAG(set_in, SET_GPIO_CONFIG);
+
+ gpio = to_rpi_gpio(gc);
+
+ set_in->body.req.gpio = off + RPI_EXP_GPIO_BASE; /* GPIO to update */
+ set_in->body.req.direction = RPI_EXP_GPIO_DIR_IN;
+ set_in->body.req.term_en = 0; /* termination disabled */
+ set_in->body.req.term_pull_up = 0; /* n/a as termination disabled */
+ set_in->body.req.state = 0; /* n/a as configured as an input */
+
+ ret = rpi_exp_gpio_get_polarity(gc, off);
+ if (ret < 0)
+ return ret;
+
+ set_in->body.req.polarity = ret; /* Retain existing setting */
+
+ ret = bcm2835_mbox_call_prop(BCM2835_MBOX_PROP_CHAN, &set_in->hdr);
+ if (ret || set_in->body.req.gpio != 0) {
+ dev_err(gc->dev, "Failed to set GPIO %u to input (%d %x)\n",
+ off, ret, set_in->body.req.gpio);
+ return ret ? ret : -EIO;
+ }
+
+ return 0;
+}
+
+static int rpi_exp_gpio_dir_out(struct gpio_chip *gc, unsigned int off, int val)
+{
+ struct rpi_exp_gpio *gpio;
+ int ret;
+ BCM2835_MBOX_STACK_ALIGN(struct gpio_set_config, set_out);
+ BCM2835_MBOX_INIT_HDR(set_out);
+ BCM2835_MBOX_INIT_TAG(set_out, SET_GPIO_CONFIG);
+
+ gpio = to_rpi_gpio(gc);
+
+ set_out->body.req.gpio = off + RPI_EXP_GPIO_BASE; /* GPIO to update */
+ set_out->body.req.direction = RPI_EXP_GPIO_DIR_OUT;
+ set_out->body.req.term_en = 0; /* n/a as an output */
+ set_out->body.req.term_pull_up = 0; /* n/a as termination disabled */
+ set_out->body.req.state = val; /* Output state */
+
+ ret = rpi_exp_gpio_get_polarity(gc, off);
+ if (ret < 0)
+ return ret;
+ set_out->body.req.polarity = ret; /* Retain existing setting */
+
+ ret = bcm2835_mbox_call_prop(BCM2835_MBOX_PROP_CHAN, &set_out->hdr);
+ if (ret || set_out->body.req.gpio != 0) {
+ dev_err(gc->dev, "Failed to set GPIO %u to output (%d %x)\n",
+ off, ret, set_out->body.req.gpio);
+ return ret ? ret : -EIO;
+ }
+ return 0;
+}
+
+static int rpi_exp_gpio_get_direction(struct gpio_chip *gc, unsigned int off)
+{
+ struct rpi_exp_gpio *gpio;
+ int ret;
+ BCM2835_MBOX_STACK_ALIGN(struct gpio_get_config, get);
+ BCM2835_MBOX_INIT_HDR(get);
+ BCM2835_MBOX_INIT_TAG(get, GET_GPIO_CONFIG);
+
+ gpio = to_rpi_gpio(gc);
+
+ get->body.req.gpio = off + RPI_EXP_GPIO_BASE; /* GPIO to update */
+
+ ret = bcm2835_mbox_call_prop(BCM2835_MBOX_PROP_CHAN, &get->hdr);
+ if (ret || get->body.req.gpio != 0) {
+ dev_err(gc->dev,
+ "Failed to get GPIO %u config (%d %x)\n", off, ret,
+ get->body.req.gpio);
+ return ret ? ret : -EIO;
+ }
+ if (get->body.req.direction)
+ return GPIOF_DIR_OUT;
+
+ return GPIOF_DIR_IN;
+}
+
+static int rpi_exp_gpio_get(struct gpio_chip *gc, unsigned int off)
+{
+ struct rpi_exp_gpio *gpio;
+ int ret;
+ BCM2835_MBOX_STACK_ALIGN(struct gpio_get_set_state, get);
+ BCM2835_MBOX_INIT_HDR(get);
+ BCM2835_MBOX_INIT_TAG(get, GET_GPIO_STATE);
+
+ gpio = to_rpi_gpio(gc);
+
+ get->body.req.gpio = off + RPI_EXP_GPIO_BASE; /* GPIO to update */
+ get->body.req.state = 0; /* storage for returned value */
+
+ ret = bcm2835_mbox_call_prop(BCM2835_MBOX_PROP_CHAN, &get->hdr);
+ if (ret || get->body.req.gpio != 0) {
+ dev_err(gc->dev,
+ "Failed to get GPIO %u state (%d %x)\n", off, ret,
+ get->body.req.gpio);
+ return ret ? ret : -EIO;
+ }
+ return !!get->body.req.state;
+}
+
+static void rpi_exp_gpio_set(struct gpio_chip *gc, unsigned int off, int val)
+{
+ struct rpi_exp_gpio *gpio;
+ int ret;
+ BCM2835_MBOX_STACK_ALIGN(struct gpio_get_set_state, set);
+ BCM2835_MBOX_INIT_HDR(set);
+ BCM2835_MBOX_INIT_TAG(set, SET_GPIO_STATE);
+
+ gpio = to_rpi_gpio(gc);
+
+ set->body.req.gpio = off + RPI_EXP_GPIO_BASE; /* GPIO to update */
+ set->body.req.state = val; /* Output state */
+
+ ret = bcm2835_mbox_call_prop(BCM2835_MBOX_PROP_CHAN, &set->hdr);
+ if (ret || set->body.req.gpio != 0)
+ dev_err(gc->dev,
+ "Failed to set GPIO %u state (%d %x)\n", off, ret,
+ set->body.req.gpio);
+}
+
+static struct gpio_ops rpi_exp_gpio_ops = {
+ .direction_input = rpi_exp_gpio_dir_in,
+ .direction_output = rpi_exp_gpio_dir_out,
+ .get_direction = rpi_exp_gpio_get_direction,
+ .get = rpi_exp_gpio_get,
+ .set = rpi_exp_gpio_set,
+};
+
+static int rpi_exp_gpio_probe(struct device *dev)
+{
+ struct rpi_exp_gpio *rpi_gpio;
+ int ret;
+
+ rpi_gpio = xzalloc(sizeof(*rpi_gpio));
+
+ rpi_gpio->gc.dev = dev;
+ rpi_gpio->gc.base = -1;
+ rpi_gpio->gc.ngpio = NUM_GPIO;
+ rpi_gpio->gc.ops = &rpi_exp_gpio_ops;
+
+ ret = gpiochip_add(&rpi_gpio->gc);
+ if (ret)
+ return ret;
+
+ dev_dbg(dev, "probed gpiochip with %d gpios, base %d\n",
+ rpi_gpio->gc.ngpio, rpi_gpio->gc.base);
+
+ return 0;
+}
+
+static __maybe_unused struct of_device_id rpi_exp_gpio_ids[] = {
+ {
+ .compatible = "raspberrypi,firmware-gpio",
+ }, {
+ /* sentinel */
+ },
+};
+MODULE_DEVICE_TABLE(of, rpi_exp_gpio_ids);
+
+static struct driver rpi_exp_gpio_driver = {
+ .name = "rpi-exp-gpio",
+ .probe = rpi_exp_gpio_probe,
+ .of_compatible = DRV_OF_COMPAT(rpi_exp_gpio_ids),
+};
+
+device_platform_driver(rpi_exp_gpio_driver);
diff --git a/drivers/gpio/gpio-rockchip.c b/drivers/gpio/gpio-rockchip.c
new file mode 100644
index 0000000000..2c13e97b97
--- /dev/null
+++ b/drivers/gpio/gpio-rockchip.c
@@ -0,0 +1,211 @@
+// SPDX-License-Identifier: GPL-2.0-only
+
+#include <common.h>
+#include <errno.h>
+#include <io.h>
+#include <of.h>
+#include <gpio.h>
+#include <init.h>
+#include <linux/clk.h>
+#include <linux/basic_mmio_gpio.h>
+#include <mach/rockchip/rockchip.h>
+
+#define GPIO_TYPE_V1 (0) /* GPIO Version ID reserved */
+#define GPIO_TYPE_V2 (0x01000C2B) /* GPIO Version ID 0x01000C2B */
+#define GPIO_TYPE_V2_1 (0x0101157C) /* GPIO Version ID 0x0101157C */
+
+struct rockchip_gpiochip {
+ struct device *dev;
+ void __iomem *reg_base;
+ struct clk *clk;
+ struct bgpio_chip bgpio_chip;
+};
+
+/* GPIO registers */
+enum {
+ RK_GPIO_SWPORT_DR = 0x00,
+ RK_GPIO_SWPORT_DDR = 0x04,
+ RK_GPIO_EXT_PORT = 0x50,
+};
+
+/* GPIO registers */
+enum {
+ RK_GPIOV2_DR_L = 0x00,
+ RK_GPIOV2_DR_H = 0x04,
+ RK_GPIOV2_DDR_L = 0x08,
+ RK_GPIOV2_DDR_H = 0x0c,
+ RK_GPIOV2_EXT_PORT = 0x70,
+};
+
+static struct rockchip_gpiochip *gc_to_rockchip_pinctrl(struct gpio_chip *gc)
+{
+ struct bgpio_chip *bgc = to_bgpio_chip(gc);
+
+ return container_of(bgc, struct rockchip_gpiochip, bgpio_chip);
+}
+
+static int rockchip_gpiov2_direction_input(struct gpio_chip *gc, unsigned int gpio)
+{
+ struct rockchip_gpiochip *rgc = gc_to_rockchip_pinctrl(gc);
+ u32 mask;
+
+ mask = 1 << (16 + (gpio % 16));
+
+ if (gpio < 16)
+ writel(mask, rgc->reg_base + RK_GPIOV2_DDR_L);
+ else
+ writel(mask, rgc->reg_base + RK_GPIOV2_DDR_H);
+
+ return 0;
+}
+
+static int rockchip_gpiov2_get_direction(struct gpio_chip *gc, unsigned int gpio)
+{
+ struct rockchip_gpiochip *rgc = gc_to_rockchip_pinctrl(gc);
+ u32 r;
+
+ if (gpio < 16)
+ r = readl(rgc->reg_base + RK_GPIOV2_DDR_L);
+ else
+ r = readl(rgc->reg_base + RK_GPIOV2_DDR_H);
+
+ return r & BIT(gpio % 16) ? GPIOF_DIR_OUT : GPIOF_DIR_IN;
+}
+
+static void rockchip_gpiov2_set_value(struct gpio_chip *gc, unsigned int gpio,
+ int val)
+{
+ struct rockchip_gpiochip *rgc = gc_to_rockchip_pinctrl(gc);
+ u32 mask, vval = 0;
+
+ mask = 1 << (16 + (gpio % 16));
+ if (val)
+ vval = 1 << (gpio % 16);
+
+ if (gpio < 16)
+ writel(mask | vval, rgc->reg_base + RK_GPIOV2_DR_L);
+ else
+ writel(mask | vval, rgc->reg_base + RK_GPIOV2_DR_H);
+}
+
+static int rockchip_gpiov2_direction_output(struct gpio_chip *gc,
+ unsigned int gpio, int val)
+{
+ struct rockchip_gpiochip *rgc = gc_to_rockchip_pinctrl(gc);
+ u32 mask, out, vval = 0;
+
+ mask = 1 << (16 + (gpio % 16));
+ out = 1 << (gpio % 16);
+ if (val)
+ vval = 1 << (gpio % 16);
+
+ if (gpio < 16) {
+ writel(mask | vval, rgc->reg_base + RK_GPIOV2_DR_L);
+ writel(mask | out, rgc->reg_base + RK_GPIOV2_DDR_L);
+ } else {
+ writel(mask | vval, rgc->reg_base + RK_GPIOV2_DR_H);
+ writel(mask | out, rgc->reg_base + RK_GPIOV2_DDR_H);
+ }
+
+ return 0;
+}
+
+static int rockchip_gpiov2_get_value(struct gpio_chip *gc, unsigned int gpio)
+{
+ struct rockchip_gpiochip *rgc = gc_to_rockchip_pinctrl(gc);
+ u32 mask, r;
+
+ mask = 1 << (gpio % 32);
+ r = readl(rgc->reg_base + RK_GPIOV2_EXT_PORT);
+
+ return r & mask ? 1 : 0;
+}
+
+static struct gpio_ops rockchip_gpio_ops = {
+ .direction_input = rockchip_gpiov2_direction_input,
+ .direction_output = rockchip_gpiov2_direction_output,
+ .get = rockchip_gpiov2_get_value,
+ .set = rockchip_gpiov2_set_value,
+ .get_direction = rockchip_gpiov2_get_direction,
+};
+
+static int rockchip_gpio_probe(struct device *dev)
+{
+ struct rockchip_gpiochip *rgc;
+ struct gpio_chip *gpio;
+ struct resource *res;
+ void __iomem *reg_base;
+ u32 id, gpio_type;
+ int ret;
+
+ rgc = xzalloc(sizeof(*rgc));
+ gpio = &rgc->bgpio_chip.gc;
+
+ res = dev_request_mem_resource(dev, 0);
+ if (IS_ERR(res))
+ return PTR_ERR(res);
+
+ rgc->reg_base = IOMEM(res->start);
+
+ rgc->clk = clk_get(dev, NULL);
+
+ if (IS_ERR(rgc->clk))
+ return PTR_ERR(rgc->clk);
+
+ ret = clk_enable(rgc->clk);
+ if (ret)
+ return ret;
+
+ reg_base = rgc->reg_base;
+
+ id = readl(reg_base + 0x78);
+ if (id == GPIO_TYPE_V2 || id == GPIO_TYPE_V2_1)
+ gpio_type = GPIO_TYPE_V2;
+ else
+ gpio_type = GPIO_TYPE_V1;
+
+ if (gpio_type >= GPIO_TYPE_V2) {
+ gpio->ngpio = 32;
+ gpio->dev = dev;
+ gpio->ops = &rockchip_gpio_ops;
+ gpio->base = of_alias_get_id(dev->of_node, "gpio");
+ if (gpio->base < 0)
+ return -EINVAL;
+ gpio->base *= 32;
+ } else {
+ ret = bgpio_init(&rgc->bgpio_chip, dev, 4,
+ reg_base + RK_GPIO_EXT_PORT,
+ reg_base + RK_GPIO_SWPORT_DR, NULL,
+ reg_base + RK_GPIO_SWPORT_DDR, NULL, 0);
+ if (ret)
+ return ret;
+ }
+
+ ret = gpiochip_add(&rgc->bgpio_chip.gc);
+ if (ret) {
+ dev_err(dev, "failed to register gpio_chip:: %d\n", ret);
+ return ret;
+ }
+
+ dev_dbg(dev, "registered GPIOv%d-compatible bank\n",
+ gpio_type == GPIO_TYPE_V1 ? 1 : 2);
+
+ return 0;
+}
+
+static struct of_device_id rockchip_gpio_dt_match[] = {
+ {
+ .compatible = "rockchip,gpio-bank",
+ }, {
+ /* sentinel */
+ }
+};
+MODULE_DEVICE_TABLE(of, rockchip_gpio_dt_match);
+
+static struct driver rockchip_gpio_driver = {
+ .name = "rockchip-gpio",
+ .probe = rockchip_gpio_probe,
+ .of_compatible = DRV_OF_COMPAT(rockchip_gpio_dt_match),
+};
+
+core_platform_driver(rockchip_gpio_driver);
diff --git a/drivers/gpio/gpio-sifive.c b/drivers/gpio/gpio-sifive.c
new file mode 100644
index 0000000000..58934fdfa7
--- /dev/null
+++ b/drivers/gpio/gpio-sifive.c
@@ -0,0 +1,88 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Copyright (C) 2019 SiFive
+ */
+
+#include <linux/basic_mmio_gpio.h>
+#include <linux/printk.h>
+#include <driver.h>
+#include <errno.h>
+
+#define SIFIVE_GPIO_INPUT_VAL 0x00
+#define SIFIVE_GPIO_INPUT_EN 0x04
+#define SIFIVE_GPIO_OUTPUT_EN 0x08
+#define SIFIVE_GPIO_OUTPUT_VAL 0x0C
+#define SIFIVE_GPIO_RISE_IE 0x18
+#define SIFIVE_GPIO_FALL_IE 0x20
+#define SIFIVE_GPIO_HIGH_IE 0x28
+#define SIFIVE_GPIO_LOW_IE 0x30
+
+#define SIFIVE_GPIO_MAX 32
+
+static int __of_irq_count(struct device_node *np)
+{
+ unsigned npins = 0;
+
+ of_get_property(np, "interrupts", &npins);
+
+ return npins / sizeof(__be32);
+}
+
+static int sifive_gpio_probe(struct device *dev)
+{
+ struct bgpio_chip *bgc;
+ struct resource *res;
+ void __iomem *base;
+ int ret, ngpio;
+
+ bgc = xzalloc(sizeof(*bgc));
+
+ res = dev_request_mem_resource(dev, 0);
+ if (IS_ERR(res)) {
+ dev_err(dev, "failed to request device memory\n");
+ return PTR_ERR(res);
+ }
+ base = IOMEM(res->start);
+
+ ngpio = __of_irq_count(dev->of_node);
+ if (ngpio > SIFIVE_GPIO_MAX) {
+ dev_err(dev, "Too many GPIO interrupts (max=%d)\n",
+ SIFIVE_GPIO_MAX);
+ return -ENXIO;
+ }
+
+ ret = bgpio_init(bgc, dev, 4,
+ base + SIFIVE_GPIO_INPUT_VAL,
+ base + SIFIVE_GPIO_OUTPUT_VAL,
+ NULL,
+ base + SIFIVE_GPIO_OUTPUT_EN,
+ base + SIFIVE_GPIO_INPUT_EN,
+ 0);
+ if (ret) {
+ dev_err(dev, "unable to init generic GPIO\n");
+ return ret;
+ }
+
+ /* Disable all GPIO interrupts */
+ writel(0, base + SIFIVE_GPIO_RISE_IE);
+ writel(0, base + SIFIVE_GPIO_FALL_IE);
+ writel(0, base + SIFIVE_GPIO_HIGH_IE);
+ writel(0, base + SIFIVE_GPIO_LOW_IE);
+
+ bgc->gc.ngpio = ngpio;
+ return gpiochip_add(&bgc->gc);
+}
+
+static const struct of_device_id sifive_gpio_match[] = {
+ { .compatible = "sifive,gpio0" },
+ { .compatible = "sifive,fu540-c000-gpio" },
+ { },
+};
+MODULE_DEVICE_TABLE(of, sifive_gpio_match);
+
+static struct driver sifive_gpio_driver = {
+ .name = "sifive_gpio",
+ .of_compatible = sifive_gpio_match,
+ .probe = sifive_gpio_probe,
+};
+postcore_platform_driver(sifive_gpio_driver);
diff --git a/drivers/gpio/gpio-starfive-vic.c b/drivers/gpio/gpio-starfive-vic.c
new file mode 100644
index 0000000000..399219a3a0
--- /dev/null
+++ b/drivers/gpio/gpio-starfive-vic.c
@@ -0,0 +1,178 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * COPYRIGHT 2020 Shanghai StarFive Technology Co., Ltd.
+ */
+
+#include <linux/basic_mmio_gpio.h>
+#include <linux/reset.h>
+#include <linux/clk.h>
+#include <linux/printk.h>
+#include <driver.h>
+#include <errno.h>
+#include <pinctrl.h>
+
+#define GPIO_EN 0x0
+#define GPIO_IS_LOW 0x10
+#define GPIO_IS_HIGH 0x14
+#define GPIO_IBE_LOW 0x18
+#define GPIO_IBE_HIGH 0x1c
+#define GPIO_IEV_LOW 0x20
+#define GPIO_IEV_HIGH 0x24
+#define GPIO_IE_LOW 0x28
+#define GPIO_IE_HIGH 0x2c
+#define GPIO_IC_LOW 0x30
+#define GPIO_IC_HIGH 0x34
+//read only
+#define GPIO_RIS_LOW 0x38
+#define GPIO_RIS_HIGH 0x3c
+#define GPIO_MIS_LOW 0x40
+#define GPIO_MIS_HIGH 0x44
+#define GPIO_DIN_LOW 0x48
+#define GPIO_DIN_HIGH 0x4c
+
+#define GPIO_DOUT_X_REG 0x50
+#define GPIO_DOEN_X_REG 0x54
+
+#define MAX_GPIO 64
+
+struct starfive_gpio {
+ void __iomem *base;
+ struct gpio_chip gc;
+};
+
+#define to_starfive_gpio(gc) container_of(gc, struct starfive_gpio, gc)
+
+static int starfive_direction_input(struct gpio_chip *gc, unsigned offset)
+{
+ struct starfive_gpio *chip = to_starfive_gpio(gc);
+
+ if (offset >= gc->ngpio)
+ return -EINVAL;
+
+ writel(0x1, chip->base + GPIO_DOEN_X_REG + offset * 8);
+
+ return 0;
+}
+
+static int starfive_direction_output(struct gpio_chip *gc, unsigned offset, int value)
+{
+ struct starfive_gpio *chip = to_starfive_gpio(gc);
+
+ if (offset >= gc->ngpio)
+ return -EINVAL;
+ writel(0x0, chip->base + GPIO_DOEN_X_REG + offset * 8);
+ writel(value, chip->base + GPIO_DOUT_X_REG + offset * 8);
+
+ return 0;
+}
+
+static int starfive_get_direction(struct gpio_chip *gc, unsigned offset)
+{
+ struct starfive_gpio *chip = to_starfive_gpio(gc);
+
+ if (offset >= gc->ngpio)
+ return -EINVAL;
+
+ return readl(chip->base + GPIO_DOEN_X_REG + offset * 8) & 0x1;
+}
+
+static int starfive_get_value(struct gpio_chip *gc, unsigned offset)
+{
+ struct starfive_gpio *chip = to_starfive_gpio(gc);
+ int value;
+
+ if (offset >= gc->ngpio)
+ return -EINVAL;
+
+ if(offset < 32){
+ value = readl(chip->base + GPIO_DIN_LOW);
+ return (value >> offset) & 0x1;
+ } else {
+ value = readl(chip->base + GPIO_DIN_HIGH);
+ return (value >> (offset - 32)) & 0x1;
+ }
+}
+
+static void starfive_set_value(struct gpio_chip *gc, unsigned offset, int value)
+{
+ struct starfive_gpio *chip = to_starfive_gpio(gc);
+
+ if (offset >= gc->ngpio)
+ return;
+
+ writel(value, chip->base + GPIO_DOUT_X_REG + offset * 8);
+}
+
+static struct gpio_ops starfive_gpio_ops = {
+ .direction_input = starfive_direction_input,
+ .direction_output = starfive_direction_output,
+ .get_direction = starfive_get_direction,
+ .get = starfive_get_value,
+ .set = starfive_set_value,
+};
+
+static int starfive_gpio_probe(struct device *dev)
+{
+ struct starfive_gpio *chip;
+ struct resource *res;
+ struct clk *clk;
+ int ret;
+
+ clk = clk_get(dev, NULL);
+ if (IS_ERR(clk))
+ return PTR_ERR(clk);
+
+ clk_enable(clk);
+
+ ret = device_reset(dev);
+ if (ret)
+ return ret;
+
+ ret = pinctrl_single_probe(dev);
+ if (ret)
+ return ret;
+
+ res = dev_get_resource(dev, IORESOURCE_MEM, 0);
+ if (IS_ERR(res))
+ return PTR_ERR(res);
+
+ chip = xzalloc(sizeof(*chip));
+ chip->base = IOMEM(res->start);
+
+ chip->gc.base = -1;
+ chip->gc.ngpio = MAX_GPIO;
+ chip->gc.dev = dev;
+ chip->gc.ops = &starfive_gpio_ops;
+
+ /* Disable all GPIO interrupts */
+ iowrite32(0, chip->base + GPIO_IE_HIGH);
+ iowrite32(0, chip->base + GPIO_IE_LOW);
+
+ ret = gpiochip_add(&chip->gc);
+ if (ret) {
+ dev_err(dev, "could not add gpiochip\n");
+ gpiochip_remove(&chip->gc);
+ return ret;
+ }
+
+ writel(1, chip->base + GPIO_EN);
+
+ return 0;
+}
+
+static const struct of_device_id starfive_gpio_match[] = {
+ { .compatible = "starfive,gpio0", },
+ { },
+};
+MODULE_DEVICE_TABLE(of, starfive_gpio_match);
+
+static struct driver starfive_gpio_driver = {
+ .probe = starfive_gpio_probe,
+ .name = "starfive_gpio",
+ .of_compatible = starfive_gpio_match,
+};
+postcore_platform_driver(starfive_gpio_driver);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Huan Feng <huan.feng@starfivetech.com>");
+MODULE_DESCRIPTION("Starfive VIC GPIO generator driver");
diff --git a/drivers/gpio/gpio-stmpe.c b/drivers/gpio/gpio-stmpe.c
index d7e64045b4..b736f66c7e 100644
--- a/drivers/gpio/gpio-stmpe.c
+++ b/drivers/gpio/gpio-stmpe.c
@@ -1,18 +1,5 @@
-/*
- * Copyright (C) 2012 Pengutronix
- * Steffen Trumtrar <s.trumtrar@pengutronix.de>
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License as
- * published by the Free Software Foundation; either version 2 of
- * the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- */
+// SPDX-License-Identifier: GPL-2.0-or-later
+// SPDX-FileCopyrightText: 2012 Steffen Trumtrar <s.trumtrar@pengutronix.de>, Pengutronix
#include <common.h>
#include <errno.h>
@@ -118,7 +105,7 @@ static struct gpio_ops stmpe_gpio_ops = {
.set = stmpe_gpio_set_value,
};
-static int stmpe_gpio_probe(struct device_d *dev)
+static int stmpe_gpio_probe(struct device *dev)
{
struct stmpe_gpio_chip *stmpegpio;
struct stmpe_client_info *ci;
@@ -149,13 +136,9 @@ static int stmpe_gpio_probe(struct device_d *dev)
return 0;
}
-static struct driver_d stmpe_gpio_driver = {
+static struct driver stmpe_gpio_driver = {
.name = "stmpe-gpio",
.probe = stmpe_gpio_probe,
};
-static int stmpe_gpio_add(void)
-{
- return platform_driver_register(&stmpe_gpio_driver);
-}
-coredevice_initcall(stmpe_gpio_add);
+coredevice_platform_driver(stmpe_gpio_driver);
diff --git a/drivers/gpio/gpio-sx150x.c b/drivers/gpio/gpio-sx150x.c
index 76535187b0..ff7e86d644 100644
--- a/drivers/gpio/gpio-sx150x.c
+++ b/drivers/gpio/gpio-sx150x.c
@@ -1,19 +1,16 @@
+// SPDX-License-Identifier: GPL-2.0-only
+// SPDX-FileCopyrightText: 2016 BayLibre, SAS (Neil Armstrong <narmstrong@baylibre.com>)
+// SPDX-FileCopyrightText: 2010 Code Aurora Forum
+
/*
* Driver for SX150x I2C GPIO expanders
*
* This code was ported from linux-4.9 kernel driver by
* Andrey Smirnov <andrew.smirnov@gmail.com>.
*
- * Orginal code with it's copyright info can be found in
- * drivers/pinctrl/pinctrl-sx150x.c
- *
* Note: That although linux driver was converted from being a GPIO
* subsystem to Pinctrl subsytem driver, due to Barebox's lack of
* similar provisions this driver is still a GPIO driver.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; version 2 of the License.
*/
#include <common.h>
@@ -22,7 +19,7 @@
#include <xfuncs.h>
#include <errno.h>
#include <i2c/i2c.h>
-#include <regmap.h>
+#include <linux/regmap.h>
#include <gpio.h>
#include <of_device.h>
@@ -45,7 +42,6 @@ struct sx150x_device_data {
};
struct sx150x_gpio {
- struct device *dev;
struct i2c_client *client;
struct gpio_chip gpio;
struct regmap *regmap;
@@ -231,7 +227,7 @@ static struct gpio_ops sx150x_gpio_ops = {
.set = sx150x_gpio_set,
};
-static int sx150x_probe(struct device_d *dev)
+static int sx150x_probe(struct device *dev)
{
struct i2c_client *client = to_i2c_client(dev);
struct sx150x_gpio *sx150x;
@@ -259,8 +255,9 @@ static __maybe_unused struct of_device_id sx150x_dt_ids[] = {
{ .compatible = "semtech,sx1503q", .data = &sx1503q_device_data, },
{ }
};
+MODULE_DEVICE_TABLE(of, sx150x_dt_ids);
-static struct driver_d sx150x_driver = {
+static struct driver sx150x_driver = {
.name = "sx150x",
.probe = sx150x_probe,
.of_compatible = sx150x_dt_ids,
diff --git a/drivers/gpio/gpio-tegra.c b/drivers/gpio/gpio-tegra.c
index 56808b57e4..693432a8c9 100644
--- a/drivers/gpio/gpio-tegra.c
+++ b/drivers/gpio/gpio-tegra.c
@@ -1,19 +1,6 @@
-/* *
- * Copyright (C) 2010 Erik Gilling <konkers@google.com>, Google, Inc
- * Copyright (C) 2013 Lucas Stach <l.stach@pengutronix.de>
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms and conditions of the GNU General Public License,
- * version 2, as published by the Free Software Foundation.
- *
- * This program is distributed in the hope it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
- * more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- */
+// SPDX-License-Identifier: GPL-2.0-only
+// SPDX-FileCopyrightText: 2010 Erik Gilling <konkers@google.com>, Google, Inc
+// SPDX-FileCopyrightText: 2013 Lucas Stach <l.stach@pengutronix.de>
#include <common.h>
#include <gpio.h>
@@ -138,7 +125,7 @@ static struct gpio_chip tegra_gpio_chip = {
.base = 0,
};
-static int tegra_gpio_probe(struct device_d *dev)
+static int tegra_gpio_probe(struct device *dev)
{
struct resource *iores;
int i, j, ret;
@@ -194,15 +181,12 @@ static __maybe_unused struct of_device_id tegra_gpio_dt_ids[] = {
/* sentinel */
},
};
+MODULE_DEVICE_TABLE(of, tegra_gpio_dt_ids);
-static struct driver_d tegra_gpio_driver = {
+static struct driver tegra_gpio_driver = {
.name = "tegra-gpio",
.of_compatible = DRV_OF_COMPAT(tegra_gpio_dt_ids),
.probe = tegra_gpio_probe,
};
-static int __init tegra_gpio_init(void)
-{
- return platform_driver_register(&tegra_gpio_driver);
-}
-coredevice_initcall(tegra_gpio_init);
+coredevice_platform_driver(tegra_gpio_driver);
diff --git a/drivers/gpio/gpio-vf610.c b/drivers/gpio/gpio-vf610.c
index ab35310fbe..7c535c2e5e 100644
--- a/drivers/gpio/gpio-vf610.c
+++ b/drivers/gpio/gpio-vf610.c
@@ -1,18 +1,8 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+// SPDX-FileCopyrightText: 2014 Toradex AG (Stefan Agner <stefan@agner.ch>)
+
/*
* vf610 GPIO support through PORT and GPIO module
- *
- * Copyright (c) 2014 Toradex AG.
- *
- * Author: Stefan Agner <stefan@agner.ch>.
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
*/
#include <common.h>
@@ -31,6 +21,8 @@ struct vf610_gpio_port {
struct gpio_chip chip;
void __iomem *gpio_base;
unsigned int pinctrl_base;
+ bool have_paddr;
+ bool need_pinctrl;
};
#define GPIO_PDOR 0x00
@@ -38,19 +30,46 @@ struct vf610_gpio_port {
#define GPIO_PCOR 0x08
#define GPIO_PTOR 0x0c
#define GPIO_PDIR 0x10
+#define GPIO_PDDR 0x14
+
+struct fsl_gpio_soc_data {
+ /* SoCs has a Port Data Direction Register (PDDR) */
+ bool have_paddr;
+ bool need_pinctrl;
+};
+
+static const struct fsl_gpio_soc_data vf610_data = {
+ .need_pinctrl = true,
+};
+
+static const struct fsl_gpio_soc_data imx_data = {
+ .have_paddr = true,
+};
static const struct of_device_id vf610_gpio_dt_ids[] = {
- { .compatible = "fsl,vf610-gpio" },
+ { .compatible = "fsl,vf610-gpio", .data = &vf610_data, },
+ { .compatible = "fsl,imx7ulp-gpio", .data = &imx_data, },
+ { .compatible = "fsl,imx8ulp-gpio", .data = &imx_data, },
+ { .compatible = "fsl,imx93-gpio", .data = &imx_data, },
{ /* sentinel */ }
};
+MODULE_DEVICE_TABLE(of, vf610_gpio_dt_ids);
static int vf610_gpio_get_value(struct gpio_chip *chip, unsigned int gpio)
{
struct vf610_gpio_port *port =
container_of(chip, struct vf610_gpio_port, chip);
+ unsigned long mask = BIT(gpio);
+ unsigned long offset = GPIO_PDIR;
- return !!(readl(port->gpio_base + GPIO_PDIR) & BIT(gpio));
+ if (port->have_paddr) {
+ mask &= readl(port->gpio_base + GPIO_PDDR);
+ if (mask)
+ offset = GPIO_PDOR;
+ }
+
+ return !!(readl(port->gpio_base + offset) & BIT(gpio));
}
static void vf610_gpio_set_value(struct gpio_chip *chip,
@@ -67,8 +86,19 @@ static int vf610_gpio_direction_input(struct gpio_chip *chip, unsigned gpio)
{
struct vf610_gpio_port *port =
container_of(chip, struct vf610_gpio_port, chip);
+ unsigned long mask = BIT(gpio);
+ u32 val;
- return pinctrl_gpio_direction_input(port->pinctrl_base + gpio);
+ if (port->have_paddr) {
+ val = readl(port->gpio_base + GPIO_PDDR);
+ val &= ~mask;
+ writel(val, port->gpio_base + GPIO_PDDR);
+ }
+
+ if (port->need_pinctrl)
+ return pinctrl_gpio_direction_input(port->pinctrl_base + gpio);
+
+ return 0;
}
static int vf610_gpio_direction_output(struct gpio_chip *chip, unsigned gpio,
@@ -76,18 +106,41 @@ static int vf610_gpio_direction_output(struct gpio_chip *chip, unsigned gpio,
{
struct vf610_gpio_port *port =
container_of(chip, struct vf610_gpio_port, chip);
+ unsigned long mask = BIT(gpio);
+ u32 val;
vf610_gpio_set_value(chip, gpio, value);
- return pinctrl_gpio_direction_output(port->pinctrl_base + gpio);
+ if (port->have_paddr) {
+ val = readl(port->gpio_base + GPIO_PDDR);
+ val |= mask;
+ writel(val, port->gpio_base + GPIO_PDDR);
+ }
+
+ if (port->need_pinctrl)
+ return pinctrl_gpio_direction_output(port->pinctrl_base + gpio);
+
+ return 0;
}
static int vf610_gpio_get_direction(struct gpio_chip *chip, unsigned gpio)
{
struct vf610_gpio_port *port =
container_of(chip, struct vf610_gpio_port, chip);
+ u32 val;
+
+ if (port->have_paddr) {
+ val = readl(port->gpio_base + GPIO_PDDR);
+ if (val & BIT(gpio))
+ return GPIOF_DIR_OUT;
+ else
+ return GPIOF_DIR_IN;
+ }
- return pinctrl_gpio_get_direction(port->pinctrl_base + gpio);
+ if (port->need_pinctrl)
+ return pinctrl_gpio_get_direction(port->pinctrl_base + gpio);
+
+ return 0;
}
static struct gpio_ops vf610_gpio_ops = {
@@ -98,38 +151,56 @@ static struct gpio_ops vf610_gpio_ops = {
.get_direction = vf610_gpio_get_direction,
};
-static int vf610_gpio_probe(struct device_d *dev)
+static int vf610_gpio_probe(struct device *dev)
{
int ret, size;
struct resource *iores;
struct vf610_gpio_port *port;
const __be32 *gpio_ranges;
+ struct fsl_gpio_soc_data *devtype;
+
+ ret = dev_get_drvdata(dev, (const void **)&devtype);
+ if (ret)
+ return ret;
port = xzalloc(sizeof(*port));
- gpio_ranges = of_get_property(dev->device_node, "gpio-ranges", &size);
+ gpio_ranges = of_get_property(dev->of_node, "gpio-ranges", &size);
if (!gpio_ranges) {
- dev_err(dev, "Couldn't read 'gpio-ranges' propery of %s\n",
- dev->device_node->full_name);
+ dev_err(dev, "Couldn't read 'gpio-ranges' propery of %pOF\n",
+ dev->of_node);
ret = -EINVAL;
goto free_port;
}
+ port->have_paddr = devtype->have_paddr;
+ port->need_pinctrl = devtype->need_pinctrl;
+
port->pinctrl_base = be32_to_cpu(gpio_ranges[PINCTRL_BASE]);
- port->chip.ngpio = be32_to_cpu(gpio_ranges[COUNT]);
+ port->chip.ngpio = 32;
+ /*
+ * Some old bindings have two register ranges. When we have two ranges
+ * the GPIO base is in the second range. With only one range the GPIO
+ * base is at offset 0x40.
+ */
iores = dev_request_mem_resource(dev, 1);
if (IS_ERR(iores)) {
- ret = PTR_ERR(iores);
- dev_dbg(dev, "Failed to request memory resource\n");
- goto free_port;
+ iores = dev_request_mem_resource(dev, 0);
+ if (IS_ERR(iores)) {
+ ret = PTR_ERR(iores);
+ dev_dbg(dev, "Failed to request memory resource\n");
+ goto free_port;
+ } else {
+ port->gpio_base = IOMEM(iores->start) + 0x40;
+ }
+ } else {
+ port->gpio_base = IOMEM(iores->start);
}
- port->gpio_base = IOMEM(iores->start);
-
port->chip.ops = &vf610_gpio_ops;
if (dev->id < 0) {
- port->chip.base = of_alias_get_id(dev->device_node, "gpio");
+ port->chip.base = of_alias_get_id(dev->of_node, "gpio");
if (port->chip.base < 0) {
ret = port->chip.base;
dev_dbg(dev, "Failed to get GPIO alias\n");
@@ -150,14 +221,10 @@ free_port:
return ret;
}
-static struct driver_d vf610_gpio_driver = {
+static struct driver vf610_gpio_driver = {
.name = "gpio-vf610",
.probe = vf610_gpio_probe,
.of_compatible = DRV_OF_COMPAT(vf610_gpio_dt_ids),
};
-static int __init gpio_vf610_init(void)
-{
- return platform_driver_register(&vf610_gpio_driver);
-}
-postcore_initcall(gpio_vf610_init);
+postcore_platform_driver(vf610_gpio_driver);
diff --git a/drivers/gpio/gpio-zynq.c b/drivers/gpio/gpio-zynq.c
new file mode 100644
index 0000000000..1358182547
--- /dev/null
+++ b/drivers/gpio/gpio-zynq.c
@@ -0,0 +1,437 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Xilinx Zynq GPIO device driver
+ *
+ * Copyright (C) 2009 - 2014 Xilinx, Inc.
+ *
+ * Based on the Linux kernel driver (drivers/gpio/gpio-zynq.c).
+ */
+
+#include <common.h>
+#include <errno.h>
+#include <gpio.h>
+#include <init.h>
+#include <io.h>
+#include <of.h>
+
+/* Maximum banks */
+#define ZYNQ_GPIO_MAX_BANK 4
+#define ZYNQMP_GPIO_MAX_BANK 6
+
+#define ZYNQ_GPIO_BANK0_NGPIO 32
+#define ZYNQ_GPIO_BANK1_NGPIO 22
+#define ZYNQ_GPIO_BANK2_NGPIO 32
+#define ZYNQ_GPIO_BANK3_NGPIO 32
+
+#define ZYNQMP_GPIO_BANK0_NGPIO 26
+#define ZYNQMP_GPIO_BANK1_NGPIO 26
+#define ZYNQMP_GPIO_BANK2_NGPIO 26
+#define ZYNQMP_GPIO_BANK3_NGPIO 32
+#define ZYNQMP_GPIO_BANK4_NGPIO 32
+#define ZYNQMP_GPIO_BANK5_NGPIO 32
+
+#define ZYNQ_GPIO_NR_GPIOS 118
+#define ZYNQMP_GPIO_NR_GPIOS 174
+
+#define ZYNQ_GPIO_BANK0_PIN_MIN(str) 0
+#define ZYNQ_GPIO_BANK0_PIN_MAX(str) \
+ (ZYNQ_GPIO_BANK0_PIN_MIN(str) + ZYNQ##str##_GPIO_BANK0_NGPIO - 1)
+#define ZYNQ_GPIO_BANK1_PIN_MIN(str) (ZYNQ_GPIO_BANK0_PIN_MAX(str) + 1)
+#define ZYNQ_GPIO_BANK1_PIN_MAX(str) \
+ (ZYNQ_GPIO_BANK1_PIN_MIN(str) + ZYNQ##str##_GPIO_BANK1_NGPIO - 1)
+#define ZYNQ_GPIO_BANK2_PIN_MIN(str) (ZYNQ_GPIO_BANK1_PIN_MAX(str) + 1)
+#define ZYNQ_GPIO_BANK2_PIN_MAX(str) \
+ (ZYNQ_GPIO_BANK2_PIN_MIN(str) + ZYNQ##str##_GPIO_BANK2_NGPIO - 1)
+#define ZYNQ_GPIO_BANK3_PIN_MIN(str) (ZYNQ_GPIO_BANK2_PIN_MAX(str) + 1)
+#define ZYNQ_GPIO_BANK3_PIN_MAX(str) \
+ (ZYNQ_GPIO_BANK3_PIN_MIN(str) + ZYNQ##str##_GPIO_BANK3_NGPIO - 1)
+#define ZYNQ_GPIO_BANK4_PIN_MIN(str) (ZYNQ_GPIO_BANK3_PIN_MAX(str) + 1)
+#define ZYNQ_GPIO_BANK4_PIN_MAX(str) \
+ (ZYNQ_GPIO_BANK4_PIN_MIN(str) + ZYNQ##str##_GPIO_BANK4_NGPIO - 1)
+#define ZYNQ_GPIO_BANK5_PIN_MIN(str) (ZYNQ_GPIO_BANK4_PIN_MAX(str) + 1)
+#define ZYNQ_GPIO_BANK5_PIN_MAX(str) \
+ (ZYNQ_GPIO_BANK5_PIN_MIN(str) + ZYNQ##str##_GPIO_BANK5_NGPIO - 1)
+
+/* Register offsets for the GPIO device */
+/* LSW Mask & Data -WO */
+#define ZYNQ_GPIO_DATA_LSW_OFFSET(BANK) (0x000 + (8 * BANK))
+/* MSW Mask & Data -WO */
+#define ZYNQ_GPIO_DATA_MSW_OFFSET(BANK) (0x004 + (8 * BANK))
+/* Data Register-RW */
+#define ZYNQ_GPIO_DATA_OFFSET(BANK) (0x040 + (4 * BANK))
+#define ZYNQ_GPIO_DATA_RO_OFFSET(BANK) (0x060 + (4 * BANK))
+/* Direction mode reg-RW */
+#define ZYNQ_GPIO_DIRM_OFFSET(BANK) (0x204 + (0x40 * BANK))
+/* Output enable reg-RW */
+#define ZYNQ_GPIO_OUTEN_OFFSET(BANK) (0x208 + (0x40 * BANK))
+/* Interrupt mask reg-RO */
+#define ZYNQ_GPIO_INTMASK_OFFSET(BANK) (0x20C + (0x40 * BANK))
+/* Interrupt enable reg-WO */
+#define ZYNQ_GPIO_INTEN_OFFSET(BANK) (0x210 + (0x40 * BANK))
+/* Interrupt disable reg-WO */
+#define ZYNQ_GPIO_INTDIS_OFFSET(BANK) (0x214 + (0x40 * BANK))
+/* Interrupt status reg-RO */
+#define ZYNQ_GPIO_INTSTS_OFFSET(BANK) (0x218 + (0x40 * BANK))
+/* Interrupt type reg-RW */
+#define ZYNQ_GPIO_INTTYPE_OFFSET(BANK) (0x21C + (0x40 * BANK))
+/* Interrupt polarity reg-RW */
+#define ZYNQ_GPIO_INTPOL_OFFSET(BANK) (0x220 + (0x40 * BANK))
+/* Interrupt on any, reg-RW */
+#define ZYNQ_GPIO_INTANY_OFFSET(BANK) (0x224 + (0x40 * BANK))
+
+/* Disable all interrupts mask */
+#define ZYNQ_GPIO_IXR_DISABLE_ALL 0xFFFFFFFF
+
+/* Mid pin number of a bank */
+#define ZYNQ_GPIO_MID_PIN_NUM 16
+
+/* GPIO upper 16 bit mask */
+#define ZYNQ_GPIO_UPPER_MASK 0xFFFF0000
+
+/* set to differentiate zynq from zynqmp, 0=zynqmp, 1=zynq */
+#define ZYNQ_GPIO_QUIRK_IS_ZYNQ BIT(0)
+#define GPIO_QUIRK_DATA_RO_BUG BIT(1)
+
+/**
+ * struct zynq_gpio - GPIO device private data structure
+ * @chip: instance of the gpio_chip
+ * @base_addr: base address of the GPIO device
+ * @p_data: pointer to platform data
+ */
+struct zynq_gpio {
+ struct gpio_chip chip;
+ void __iomem *base_addr;
+ const struct zynq_platform_data *p_data;
+};
+
+/**
+ * struct zynq_platform_data - Zynq GPIO platform data structure
+ * @quirks: Flags is used to identify the platform
+ * @ngpio: max number of gpio pins
+ * @max_bank: maximum number of gpio banks
+ * @bank_min: this array represents bank's min pin
+ * @bank_max: this array represents bank's max pin
+ */
+struct zynq_platform_data {
+ u32 quirks;
+ u16 ngpio;
+ int max_bank;
+ int bank_min[ZYNQMP_GPIO_MAX_BANK];
+ int bank_max[ZYNQMP_GPIO_MAX_BANK];
+};
+
+/**
+ * zynq_gpio_is_zynq - Test if HW is Zynq or ZynqMP
+ * @gpio: Pointer to driver data struct
+ *
+ * Return: 0 if ZynqMP, 1 if Zynq.
+ */
+static int zynq_gpio_is_zynq(struct zynq_gpio *gpio)
+{
+ return !!(gpio->p_data->quirks & ZYNQ_GPIO_QUIRK_IS_ZYNQ);
+}
+
+/**
+ * gpio_data_ro_bug - Test if HW bug exists or not
+ * @gpio: Pointer to driver data struct
+ *
+ * Return: 0 if bug does not exist, 1 if bug exists.
+ */
+static int gpio_data_ro_bug(struct zynq_gpio *gpio)
+{
+ return !!(gpio->p_data->quirks & GPIO_QUIRK_DATA_RO_BUG);
+}
+
+/**
+ * zynq_gpio_get_bank_pin - Get the bank number and pin number within that bank
+ * for a given pin in the GPIO device
+ * @pin_num: gpio pin number within the device
+ * @bank_num: an output parameter used to return the bank number of the gpio
+ * pin
+ * @bank_pin_num: an output parameter used to return pin number within a bank
+ * for the given gpio pin
+ * @gpio: gpio device data structure
+ *
+ * Returns the bank number and pin offset within the bank.
+ */
+static int zynq_gpio_get_bank_pin(unsigned int pin_num, unsigned int *bank_num,
+ unsigned int *bank_pin_num,
+ struct zynq_gpio *gpio)
+{
+ int bank;
+
+ for (bank = 0; bank < gpio->p_data->max_bank; bank++) {
+ if ((pin_num >= gpio->p_data->bank_min[bank]) &&
+ (pin_num <= gpio->p_data->bank_max[bank])) {
+ *bank_num = bank;
+ *bank_pin_num = pin_num - gpio->p_data->bank_min[bank];
+ return 0;
+ }
+ }
+
+ *bank_num = 0;
+ *bank_pin_num = 0;
+ return -ENODEV;
+}
+
+/**
+ * zynq_gpio_get_value - Get the state of the specified pin of GPIO device
+ * @chip: gpio_chip instance to be worked on
+ * @pin: gpio pin number within the device
+ *
+ * This function reads the state of the specified pin of the GPIO device.
+ *
+ * Return: 0 if the pin is low, 1 if pin is high.
+ */
+static int zynq_gpio_get_value(struct gpio_chip *chip, unsigned int pin)
+{
+ u32 data;
+ unsigned int bank_num, bank_pin_num;
+ struct zynq_gpio *gpio = container_of(chip, struct zynq_gpio, chip);
+
+ if (zynq_gpio_get_bank_pin(pin, &bank_num, &bank_pin_num, gpio) < 0)
+ return -EINVAL;
+
+ if (gpio_data_ro_bug(gpio)) {
+ if (zynq_gpio_is_zynq(gpio)) {
+ if (bank_num <= 1) {
+ data = readl_relaxed(
+ gpio->base_addr +
+ ZYNQ_GPIO_DATA_RO_OFFSET(bank_num));
+ } else {
+ data = readl_relaxed(
+ gpio->base_addr +
+ ZYNQ_GPIO_DATA_OFFSET(bank_num));
+ }
+ } else {
+ if (bank_num <= 2) {
+ data = readl_relaxed(
+ gpio->base_addr +
+ ZYNQ_GPIO_DATA_RO_OFFSET(bank_num));
+ } else {
+ data = readl_relaxed(
+ gpio->base_addr +
+ ZYNQ_GPIO_DATA_OFFSET(bank_num));
+ }
+ }
+ } else {
+ data = readl_relaxed(gpio->base_addr +
+ ZYNQ_GPIO_DATA_RO_OFFSET(bank_num));
+ }
+ return (data >> bank_pin_num) & 1;
+}
+
+/**
+ * zynq_gpio_set_value - Modify the state of the pin with specified value
+ * @chip: gpio_chip instance to be worked on
+ * @pin: gpio pin number within the device
+ * @state: value used to modify the state of the specified pin
+ *
+ * This function calculates the register offset (i.e to lower 16 bits or
+ * upper 16 bits) based on the given pin number and sets the state of a
+ * gpio pin to the specified value. The state is either 0 or non-zero.
+ */
+static void zynq_gpio_set_value(struct gpio_chip *chip, unsigned int pin,
+ int state)
+{
+ unsigned int reg_offset, bank_num, bank_pin_num;
+ struct zynq_gpio *gpio = container_of(chip, struct zynq_gpio, chip);
+
+ if (zynq_gpio_get_bank_pin(pin, &bank_num, &bank_pin_num, gpio) < 0)
+ return;
+
+ if (bank_pin_num >= ZYNQ_GPIO_MID_PIN_NUM) {
+ bank_pin_num -= ZYNQ_GPIO_MID_PIN_NUM;
+ reg_offset = ZYNQ_GPIO_DATA_MSW_OFFSET(bank_num);
+ } else {
+ reg_offset = ZYNQ_GPIO_DATA_LSW_OFFSET(bank_num);
+ }
+
+ /*
+ * get the 32 bit value to be written to the mask/data register where
+ * the upper 16 bits is the mask and lower 16 bits is the data
+ */
+ state = !!state;
+ state = ~(1 << (bank_pin_num + ZYNQ_GPIO_MID_PIN_NUM)) &
+ ((state << bank_pin_num) | ZYNQ_GPIO_UPPER_MASK);
+
+ writel_relaxed(state, gpio->base_addr + reg_offset);
+}
+
+/**
+ * zynq_gpio_dir_in - Set the direction of the specified GPIO pin as input
+ * @chip: gpio_chip instance to be worked on
+ * @pin: gpio pin number within the device
+ *
+ * This function uses the read-modify-write sequence to set the direction of
+ * the gpio pin as input.
+ *
+ * Return: 0 always
+ */
+static int zynq_gpio_dir_in(struct gpio_chip *chip, unsigned int pin)
+{
+ u32 reg;
+ unsigned int bank_num, bank_pin_num;
+ struct zynq_gpio *gpio = container_of(chip, struct zynq_gpio, chip);
+
+ if (zynq_gpio_get_bank_pin(pin, &bank_num, &bank_pin_num, gpio) < 0)
+ return -EINVAL;
+ /*
+ * On zynq bank 0 pins 7 and 8 are special and cannot be used
+ * as inputs.
+ */
+ if (zynq_gpio_is_zynq(gpio) && bank_num == 0 &&
+ (bank_pin_num == 7 || bank_pin_num == 8))
+ return -EINVAL;
+
+ /* clear the bit in direction mode reg to set the pin as input */
+ reg = readl_relaxed(gpio->base_addr + ZYNQ_GPIO_DIRM_OFFSET(bank_num));
+ reg &= ~BIT(bank_pin_num);
+ writel_relaxed(reg, gpio->base_addr + ZYNQ_GPIO_DIRM_OFFSET(bank_num));
+
+ return 0;
+}
+
+/**
+ * zynq_gpio_dir_out - Set the direction of the specified GPIO pin as output
+ * @chip: gpio_chip instance to be worked on
+ * @pin: gpio pin number within the device
+ * @state: value to be written to specified pin
+ *
+ * This function sets the direction of specified GPIO pin as output, configures
+ * the Output Enable register for the pin and uses zynq_gpio_set to set
+ * the state of the pin to the value specified.
+ *
+ * Return: 0 always
+ */
+static int zynq_gpio_dir_out(struct gpio_chip *chip, unsigned int pin,
+ int state)
+{
+ u32 reg;
+ unsigned int bank_num, bank_pin_num;
+ struct zynq_gpio *gpio = container_of(chip, struct zynq_gpio, chip);
+
+ if (zynq_gpio_get_bank_pin(pin, &bank_num, &bank_pin_num, gpio) < 0)
+ return -EINVAL;
+
+ /* set the GPIO pin as output */
+ reg = readl_relaxed(gpio->base_addr + ZYNQ_GPIO_DIRM_OFFSET(bank_num));
+ reg |= BIT(bank_pin_num);
+ writel_relaxed(reg, gpio->base_addr + ZYNQ_GPIO_DIRM_OFFSET(bank_num));
+
+ /* configure the output enable reg for the pin */
+ reg = readl_relaxed(gpio->base_addr + ZYNQ_GPIO_OUTEN_OFFSET(bank_num));
+ reg |= BIT(bank_pin_num);
+ writel_relaxed(reg, gpio->base_addr + ZYNQ_GPIO_OUTEN_OFFSET(bank_num));
+
+ /* set the state of the pin */
+ zynq_gpio_set_value(chip, pin, state);
+ return 0;
+}
+
+/**
+ * zynq_gpio_get_direction - Read the direction of the specified GPIO pin
+ * @chip: gpio_chip instance to be worked on
+ * @pin: gpio pin number within the device
+ *
+ * This function returns the direction of the specified GPIO.
+ *
+ * Return: 0 for output, 1 for input
+ */
+static int zynq_gpio_get_direction(struct gpio_chip *chip, unsigned int pin)
+{
+ u32 reg;
+ unsigned int bank_num, bank_pin_num;
+ struct zynq_gpio *gpio = container_of(chip, struct zynq_gpio, chip);
+
+ if (zynq_gpio_get_bank_pin(pin, &bank_num, &bank_pin_num, gpio) < 0)
+ return -EINVAL;
+
+ reg = readl_relaxed(gpio->base_addr + ZYNQ_GPIO_DIRM_OFFSET(bank_num));
+
+ return !(reg & BIT(bank_pin_num));
+}
+
+static struct gpio_ops zynq_gpio_ops = {
+ .direction_input = zynq_gpio_dir_in,
+ .direction_output = zynq_gpio_dir_out,
+ .get = zynq_gpio_get_value,
+ .set = zynq_gpio_set_value,
+ .get_direction = zynq_gpio_get_direction,
+};
+
+static int zynqmp_gpio_probe(struct device *dev)
+{
+ struct resource *iores;
+ struct zynq_gpio *gpio;
+ const struct zynq_platform_data *p_data;
+ int ret;
+
+ gpio = xzalloc(sizeof(*gpio));
+ p_data = device_get_match_data(dev);
+ iores = dev_request_mem_resource(dev, 0);
+ if (IS_ERR(iores)) {
+ ret = PTR_ERR(iores);
+ goto free_gpio;
+ }
+
+ gpio->base_addr = IOMEM(iores->start);
+ gpio->chip.base = of_alias_get_id(dev->of_node, "gpio");
+ gpio->chip.ops = &zynq_gpio_ops;
+ gpio->chip.ngpio = p_data->ngpio;
+ gpio->chip.dev = dev;
+ gpio->p_data = p_data;
+
+ return gpiochip_add(&gpio->chip);
+
+free_gpio:
+ kfree(gpio);
+ return ret;
+}
+
+static const struct zynq_platform_data zynqmp_gpio_def = {
+ .quirks = GPIO_QUIRK_DATA_RO_BUG,
+ .ngpio = ZYNQMP_GPIO_NR_GPIOS,
+ .max_bank = ZYNQMP_GPIO_MAX_BANK,
+ .bank_min[0] = ZYNQ_GPIO_BANK0_PIN_MIN(MP),
+ .bank_max[0] = ZYNQ_GPIO_BANK0_PIN_MAX(MP),
+ .bank_min[1] = ZYNQ_GPIO_BANK1_PIN_MIN(MP),
+ .bank_max[1] = ZYNQ_GPIO_BANK1_PIN_MAX(MP),
+ .bank_min[2] = ZYNQ_GPIO_BANK2_PIN_MIN(MP),
+ .bank_max[2] = ZYNQ_GPIO_BANK2_PIN_MAX(MP),
+ .bank_min[3] = ZYNQ_GPIO_BANK3_PIN_MIN(MP),
+ .bank_max[3] = ZYNQ_GPIO_BANK3_PIN_MAX(MP),
+ .bank_min[4] = ZYNQ_GPIO_BANK4_PIN_MIN(MP),
+ .bank_max[4] = ZYNQ_GPIO_BANK4_PIN_MAX(MP),
+ .bank_min[5] = ZYNQ_GPIO_BANK5_PIN_MIN(MP),
+ .bank_max[5] = ZYNQ_GPIO_BANK5_PIN_MAX(MP),
+};
+
+static const struct zynq_platform_data zynq_gpio_def = {
+ .quirks = ZYNQ_GPIO_QUIRK_IS_ZYNQ | GPIO_QUIRK_DATA_RO_BUG,
+ .ngpio = ZYNQ_GPIO_NR_GPIOS,
+ .max_bank = ZYNQ_GPIO_MAX_BANK,
+ .bank_min[0] = ZYNQ_GPIO_BANK0_PIN_MIN(),
+ .bank_max[0] = ZYNQ_GPIO_BANK0_PIN_MAX(),
+ .bank_min[1] = ZYNQ_GPIO_BANK1_PIN_MIN(),
+ .bank_max[1] = ZYNQ_GPIO_BANK1_PIN_MAX(),
+ .bank_min[2] = ZYNQ_GPIO_BANK2_PIN_MIN(),
+ .bank_max[2] = ZYNQ_GPIO_BANK2_PIN_MAX(),
+ .bank_min[3] = ZYNQ_GPIO_BANK3_PIN_MIN(),
+ .bank_max[3] = ZYNQ_GPIO_BANK3_PIN_MAX(),
+};
+
+static const struct of_device_id zynq_gpio_of_match[] = {
+ { .compatible = "xlnx,zynq-gpio-1.0", .data = &zynq_gpio_def },
+ { .compatible = "xlnx,zynqmp-gpio-1.0", .data = &zynqmp_gpio_def },
+ { /* end of table */ }
+};
+MODULE_DEVICE_TABLE(of, zynq_gpio_of_match);
+
+static struct driver zynqmp_gpio_driver = {
+ .name = "zynqmp-gpio",
+ .of_compatible = zynq_gpio_of_match,
+ .probe = zynqmp_gpio_probe,
+};
+
+postcore_platform_driver(zynqmp_gpio_driver);
diff --git a/drivers/gpio/gpiolib.c b/drivers/gpio/gpiolib.c
index f96009896a..a70e13eafc 100644
--- a/drivers/gpio/gpiolib.c
+++ b/drivers/gpio/gpiolib.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0-only
#define pr_fmt(fmt) "gpiolib: " fmt
#include <init.h>
@@ -6,37 +7,70 @@
#include <complete.h>
#include <gpio.h>
#include <of_gpio.h>
+#include <linux/gpio/consumer.h>
+#include <linux/overflow.h>
#include <errno.h>
#include <malloc.h>
static LIST_HEAD(chip_list);
-struct gpio_info {
+struct gpio_desc {
struct gpio_chip *chip;
bool requested;
bool active_low;
char *label;
+ const char *name;
};
-static struct gpio_info *gpio_desc;
+/*
+ * This descriptor validation needs to be inserted verbatim into each
+ * function taking a descriptor, so we need to use a preprocessor
+ * macro to avoid endless duplication. If the desc is NULL it is an
+ * optional GPIO and calls should just bail out.
+ */
+static int validate_desc(const struct gpio_desc *desc, const char *func)
+{
+ if (!desc)
+ return 0;
+ if (IS_ERR(desc)) {
+ pr_warn("%s: invalid GPIO (errorpointer)\n", func);
+ return PTR_ERR(desc);
+ }
+
+ return 1;
+}
+
+#define VALIDATE_DESC(desc) do { \
+ int __valid = validate_desc(desc, __func__); \
+ if (__valid <= 0) \
+ return __valid; \
+ } while (0)
+
+#define VALIDATE_DESC_VOID(desc) do { \
+ int __valid = validate_desc(desc, __func__); \
+ if (__valid <= 0) \
+ return; \
+ } while (0)
+
+static struct gpio_desc *gpio_desc;
static int gpio_desc_alloc(void)
{
- gpio_desc = xzalloc(sizeof(struct gpio_info) * ARCH_NR_GPIOS);
+ gpio_desc = xzalloc(sizeof(struct gpio_desc) * ARCH_NR_GPIOS);
return 0;
}
pure_initcall(gpio_desc_alloc);
-static int gpio_ensure_requested(struct gpio_info *gi, int gpio)
+static int gpio_ensure_requested(struct gpio_desc *desc, int gpio)
{
- if (gi->requested)
+ if (desc->requested)
return 0;
return gpio_request(gpio, "gpio");
}
-static struct gpio_info *gpio_to_desc(unsigned gpio)
+static struct gpio_desc *gpio_to_desc(unsigned gpio)
{
if (gpio_is_valid(gpio))
if (gpio_desc[gpio].chip)
@@ -47,46 +81,46 @@ static struct gpio_info *gpio_to_desc(unsigned gpio)
return NULL;
}
-static int gpio_adjust_value(struct gpio_info *gi,
+static unsigned gpiodesc_chip_offset(const struct gpio_desc *desc)
+{
+ return (desc - gpio_desc) - desc->chip->base;
+}
+
+static int gpio_adjust_value(const struct gpio_desc *desc,
int value)
{
if (value < 0)
return value;
- return !!value ^ gi->active_low;
+ return !!value ^ desc->active_low;
}
-int gpio_request(unsigned gpio, const char *label)
+static int gpiodesc_request(struct gpio_desc *desc, const char *label)
{
- struct gpio_info *gi = gpio_to_desc(gpio);
int ret;
- if (!gi) {
- ret = -ENODEV;
- goto done;
- }
-
- if (gi->requested) {
+ if (desc->requested) {
ret = -EBUSY;
goto done;
}
ret = 0;
- if (gi->chip->ops->request) {
- ret = gi->chip->ops->request(gi->chip, gpio - gi->chip->base);
+ if (desc->chip->ops->request) {
+ ret = desc->chip->ops->request(desc->chip,
+ gpiodesc_chip_offset(desc));
if (ret)
goto done;
}
- gi->requested = true;
- gi->active_low = false;
- gi->label = xstrdup(label);
+ desc->requested = true;
+ desc->active_low = false;
+ desc->label = xstrdup(label);
done:
if (ret)
- pr_err("_gpio_request: gpio-%d (%s) status %d\n",
- gpio, label ? : "?", ret);
+ pr_err("_gpio_request: gpio-%td (%s) status %d\n",
+ desc - gpio_desc, label ? : "?", ret);
return ret;
}
@@ -96,7 +130,7 @@ int gpio_find_by_label(const char *label)
int i;
for (i = 0; i < ARCH_NR_GPIOS; i++) {
- struct gpio_info *info = &gpio_desc[i];
+ struct gpio_desc *info = &gpio_desc[i];
if (!info->requested || !info->chip || !info->label)
continue;
@@ -108,225 +142,460 @@ int gpio_find_by_label(const char *label)
return -ENOENT;
}
-void gpio_free(unsigned gpio)
+int gpio_find_by_name(const char *name)
{
- struct gpio_info *gi = gpio_to_desc(gpio);
+ int i;
- if (!gi)
- return;
+ for (i = 0; i < ARCH_NR_GPIOS; i++) {
+ struct gpio_desc *info = &gpio_desc[i];
- if (!gi->requested)
- return;
+ if (!info->chip || !info->name)
+ continue;
- if (gi->chip->ops->free)
- gi->chip->ops->free(gi->chip, gpio - gi->chip->base);
+ if (!strcmp(info->name, name))
+ return i;
+ }
- gi->requested = false;
- gi->active_low = false;
- free(gi->label);
- gi->label = NULL;
+ return -ENOENT;
}
-/**
- * gpio_request_one - request a single GPIO with initial configuration
- * @gpio: the GPIO number
- * @flags: GPIO configuration as specified by GPIOF_*
- * @label: a literal description string of this GPIO
- */
-int gpio_request_one(unsigned gpio, unsigned long flags, const char *label)
+int gpio_request(unsigned gpio, const char *label)
{
- int err;
- struct gpio_info *gi = gpio_to_desc(gpio);
+ struct gpio_desc *desc = gpio_to_desc(gpio);
- /*
- * Not all of the flags below are mulit-bit, but, for the sake
- * of consistency, the code is written as if all of them were.
- */
- const bool active_low = (flags & GPIOF_ACTIVE_LOW) == GPIOF_ACTIVE_LOW;
- const bool dir_in = (flags & GPIOF_DIR_IN) == GPIOF_DIR_IN;
- const bool logical = (flags & GPIOF_LOGICAL) == GPIOF_LOGICAL;
- const bool init_active = (flags & GPIOF_INIT_ACTIVE) == GPIOF_INIT_ACTIVE;
- const bool init_high = (flags & GPIOF_INIT_HIGH) == GPIOF_INIT_HIGH;
+ if (!desc) {
+ pr_err("_gpio_request: gpio-%d (%s) status %d\n",
+ gpio, label ? : "?", -ENODEV);
+ return -ENODEV;
+ }
- err = gpio_request(gpio, label);
- if (err)
- return err;
+ return gpiodesc_request(desc, label);
+}
- gi->active_low = active_low;
+bool gpiod_slice_acquired(struct gpio_desc *desc)
+{
+ if (!desc)
+ return false;
- if (dir_in)
- err = gpio_direction_input(gpio);
- else if (logical)
- err = gpio_direction_active(gpio, init_active);
- else
- err = gpio_direction_output(gpio, init_high);
+ return slice_acquired(&desc->chip->slice);
+}
- if (err)
- gpio_free(gpio);
+bool gpio_slice_acquired(unsigned gpio)
+{
+ struct gpio_desc *desc = gpio_to_desc(gpio);
- return err;
+ return gpiod_slice_acquired(desc);
+}
+
+static void gpiodesc_free(struct gpio_desc *desc)
+{
+ if (!desc->requested)
+ return;
+
+ if (desc->chip->ops->free)
+ desc->chip->ops->free(desc->chip, gpiodesc_chip_offset(desc));
+
+ desc->requested = false;
+ desc->active_low = false;
+ free(desc->label);
+ desc->label = NULL;
+}
+
+void gpio_free(unsigned gpio)
+{
+ struct gpio_desc *desc = gpio_to_desc(gpio);
+
+ gpiodesc_free(desc);
}
-EXPORT_SYMBOL_GPL(gpio_request_one);
/**
- * gpio_request_array - request multiple GPIOs in a single call
- * @array: array of the 'struct gpio'
- * @num: how many GPIOs in the array
+ * gpiod_put - dispose of a GPIO descriptor
+ * @desc: GPIO descriptor to dispose of
+ *
+ * No descriptor can be used after gpiod_put() has been called on it.
*/
-int gpio_request_array(const struct gpio *array, size_t num)
+void gpiod_put(struct gpio_desc *desc)
{
- int i, err;
+ if (!desc)
+ return;
- for (i = 0; i < num; i++, array++) {
- err = gpio_request_one(array->gpio, array->flags, array->label);
- if (err)
- goto err_free;
- }
- return 0;
+ gpiodesc_free(desc);
+}
+EXPORT_SYMBOL(gpiod_put);
-err_free:
- while (i--)
- gpio_free((--array)->gpio);
- return err;
+/**
+ * gpiod_put_array - dispose of multiple GPIO descriptors
+ * @descs: struct gpio_descs containing an array of descriptors
+ */
+void gpiod_put_array(struct gpio_descs *descs)
+{
+ unsigned int i;
+
+ for (i = 0; i < descs->ndescs; i++)
+ gpiod_put(descs->desc[i]);
+
+ kfree(descs);
}
-EXPORT_SYMBOL_GPL(gpio_request_array);
+EXPORT_SYMBOL_GPL(gpiod_put_array);
/**
- * gpio_free_array - release multiple GPIOs in a single call
- * @array: array of the 'struct gpio'
- * @num: how many GPIOs in the array
+ * gpiod_set_raw_value() - assign a gpio's raw value
+ * @desc: gpio whose value will be assigned
+ * @value: value to assign
+ *
+ * Set the raw value of the GPIO, i.e. the value of its physical line without
+ * regard for its ACTIVE_LOW status.
*/
-void gpio_free_array(const struct gpio *array, size_t num)
+void gpiod_set_raw_value(struct gpio_desc *desc, int value)
{
- while (num--)
- gpio_free((array++)->gpio);
+ VALIDATE_DESC_VOID(desc);
+
+ if (desc->chip->ops->set)
+ desc->chip->ops->set(desc->chip, gpiodesc_chip_offset(desc), value);
}
-EXPORT_SYMBOL_GPL(gpio_free_array);
+EXPORT_SYMBOL(gpiod_set_raw_value);
void gpio_set_value(unsigned gpio, int value)
{
- struct gpio_info *gi = gpio_to_desc(gpio);
+ struct gpio_desc *desc = gpio_to_desc(gpio);
- if (!gi)
+ if (!desc)
return;
- if (gpio_ensure_requested(gi, gpio))
+ if (gpio_ensure_requested(desc, gpio))
return;
- if (gi->chip->ops->set)
- gi->chip->ops->set(gi->chip, gpio - gi->chip->base, value);
+ gpiod_set_raw_value(desc, value);
}
EXPORT_SYMBOL(gpio_set_value);
+/**
+ * gpiod_set_value() - assign a gpio's value
+ * @desc: gpio whose value will be assigned
+ * @value: value to assign
+ *
+ * Set the logical value of the GPIO, i.e. taking its ACTIVE_LOW,
+ * OPEN_DRAIN and OPEN_SOURCE flags into account.
+ */
+void gpiod_set_value(struct gpio_desc *desc, int value)
+{
+ VALIDATE_DESC_VOID(desc);
+ gpiod_set_raw_value(desc, gpio_adjust_value(desc, value));
+}
+EXPORT_SYMBOL_GPL(gpiod_set_value);
+
void gpio_set_active(unsigned gpio, bool value)
{
- struct gpio_info *gi = gpio_to_desc(gpio);
+ struct gpio_desc *desc = gpio_to_desc(gpio);
- if (!gi)
+ if (!desc)
return;
- gpio_set_value(gpio, gpio_adjust_value(gi, value));
+ gpiod_set_value(desc, value);
}
EXPORT_SYMBOL(gpio_set_active);
+/**
+ * gpiod_get_raw_value() - return a gpio's raw value
+ * @desc: gpio whose value will be returned
+ *
+ * Return the GPIO's raw value, i.e. the value of the physical line disregarding
+ * its ACTIVE_LOW status, or negative errno on failure.
+ */
+int gpiod_get_raw_value(const struct gpio_desc *desc)
+{
+ VALIDATE_DESC(desc);
+
+ if (!desc->chip->ops->get)
+ return -ENOSYS;
+
+ return desc->chip->ops->get(desc->chip, gpiodesc_chip_offset(desc));
+}
+EXPORT_SYMBOL_GPL(gpiod_get_raw_value);
+
int gpio_get_value(unsigned gpio)
{
- struct gpio_info *gi = gpio_to_desc(gpio);
+ struct gpio_desc *desc = gpio_to_desc(gpio);
int ret;
- if (!gi)
+ if (!desc)
return -ENODEV;
- ret = gpio_ensure_requested(gi, gpio);
+ ret = gpio_ensure_requested(desc, gpio);
if (ret)
return ret;
- if (!gi->chip->ops->get)
- return -ENOSYS;
- return gi->chip->ops->get(gi->chip, gpio - gi->chip->base);
+ return gpiod_get_raw_value(desc);
}
EXPORT_SYMBOL(gpio_get_value);
+/**
+ * gpiod_get_value() - return a gpio's value
+ * @desc: gpio whose value will be returned
+ *
+ * Return the GPIO's logical value, i.e. taking the ACTIVE_LOW status into
+ * account, or negative errno on failure.
+ */
+int gpiod_get_value(const struct gpio_desc *desc)
+{
+ VALIDATE_DESC(desc);
+
+ return gpio_adjust_value(desc, gpiod_get_raw_value(desc));
+}
+EXPORT_SYMBOL_GPL(gpiod_get_value);
+
int gpio_is_active(unsigned gpio)
{
- struct gpio_info *gi = gpio_to_desc(gpio);
+ struct gpio_desc *desc = gpio_to_desc(gpio);
- if (!gi)
+ if (!desc)
return -ENODEV;
- return gpio_adjust_value(gi, gpio_get_value(gpio));
+ return gpiod_get_value(desc);
}
EXPORT_SYMBOL(gpio_is_active);
+/**
+ * gpiod_direction_output_raw - set the GPIO direction to output
+ * @desc: GPIO to set to output
+ * @value: initial output value of the GPIO
+ *
+ * Set the direction of the passed GPIO to output, such as gpiod_set_value() can
+ * be called safely on it. The initial value of the output must be specified
+ * as raw value on the physical line without regard for the ACTIVE_LOW status.
+ *
+ * Return 0 in case of success, else an error code.
+ */
+int gpiod_direction_output_raw(struct gpio_desc *desc, int value)
+{
+ VALIDATE_DESC(desc);
+
+ if (!desc->chip->ops->direction_output)
+ return -ENOSYS;
+
+ return desc->chip->ops->direction_output(desc->chip,
+ gpiodesc_chip_offset(desc), value);
+}
+EXPORT_SYMBOL(gpiod_direction_output_raw);
+
int gpio_direction_output(unsigned gpio, int value)
{
- struct gpio_info *gi = gpio_to_desc(gpio);
+ struct gpio_desc *desc = gpio_to_desc(gpio);
int ret;
- if (!gi)
+ if (!desc)
return -ENODEV;
- ret = gpio_ensure_requested(gi, gpio);
+ ret = gpio_ensure_requested(desc, gpio);
if (ret)
return ret;
- if (!gi->chip->ops->direction_output)
- return -ENOSYS;
- return gi->chip->ops->direction_output(gi->chip, gpio - gi->chip->base,
- value);
+ return gpiod_direction_output_raw(desc, value);
}
EXPORT_SYMBOL(gpio_direction_output);
+/**
+ * gpiod_direction_output - set the GPIO direction to output
+ * @desc: GPIO to set to output
+ * @value: initial output value of the GPIO
+ *
+ * Set the direction of the passed GPIO to output, such as gpiod_set_value() can
+ * be called safely on it. The initial value of the output must be specified
+ * as the logical value of the GPIO, i.e. taking its ACTIVE_LOW status into
+ * account.
+ *
+ * Return 0 in case of success, else an error code.
+ */
+int gpiod_direction_output(struct gpio_desc *desc, int value)
+{
+ VALIDATE_DESC(desc);
+
+ return gpiod_direction_output_raw(desc, gpio_adjust_value(desc, value));
+}
+
int gpio_direction_active(unsigned gpio, bool value)
{
- struct gpio_info *gi = gpio_to_desc(gpio);
+ struct gpio_desc *desc = gpio_to_desc(gpio);
- if (!gi)
+ if (!desc)
return -ENODEV;
- return gpio_direction_output(gpio, gpio_adjust_value(gi, value));
+ return gpiod_direction_output(desc, value);
}
EXPORT_SYMBOL(gpio_direction_active);
+/**
+ * gpiod_direction_input - set the GPIO direction to input
+ * @desc: GPIO to set to input
+ *
+ * Set the direction of the passed GPIO to input, such as gpiod_get_value() can
+ * be called safely on it.
+ *
+ * Return 0 in case of success, else an error code.
+ */
+int gpiod_direction_input(struct gpio_desc *desc)
+{
+ VALIDATE_DESC(desc);
+
+ if (!desc->chip->ops->direction_input)
+ return -ENOSYS;
+
+ return desc->chip->ops->direction_input(desc->chip,
+ gpiodesc_chip_offset(desc));
+}
+EXPORT_SYMBOL(gpiod_direction_input);
+
int gpio_direction_input(unsigned gpio)
{
- struct gpio_info *gi = gpio_to_desc(gpio);
+ struct gpio_desc *desc = gpio_to_desc(gpio);
int ret;
- if (!gi)
+ if (!desc)
return -ENODEV;
- ret = gpio_ensure_requested(gi, gpio);
+ ret = gpio_ensure_requested(desc, gpio);
if (ret)
return ret;
- if (!gi->chip->ops->direction_input)
- return -ENOSYS;
- return gi->chip->ops->direction_input(gi->chip, gpio - gi->chip->base);
+ return gpiod_direction_input(desc);
}
EXPORT_SYMBOL(gpio_direction_input);
-static int gpiochip_find_base(int start, int ngpio)
+static int gpiodesc_request_one(struct gpio_desc *desc, unsigned long flags,
+ const char *label)
+{
+ int err;
+
+ /*
+ * Not all of the flags below are mulit-bit, but, for the sake
+ * of consistency, the code is written as if all of them were.
+ */
+ const bool active_low = (flags & GPIOF_ACTIVE_LOW) == GPIOF_ACTIVE_LOW;
+ const bool dir_in = (flags & GPIOF_DIR_IN) == GPIOF_DIR_IN;
+ const bool logical = (flags & GPIOF_LOGICAL) == GPIOF_LOGICAL;
+ const bool init_active = (flags & GPIOF_INIT_ACTIVE) == GPIOF_INIT_ACTIVE;
+ const bool init_high = (flags & GPIOF_INIT_HIGH) == GPIOF_INIT_HIGH;
+
+ err = gpiodesc_request(desc, label);
+ if (err)
+ return err;
+
+ desc->active_low = active_low;
+
+ if (dir_in)
+ err = gpiod_direction_input(desc);
+ else if (logical)
+ err = gpiod_direction_output(desc, init_active);
+ else
+ err = gpiod_direction_output_raw(desc, init_high);
+
+ if (err)
+ gpiodesc_free(desc);
+
+ return err;
+}
+
+/**
+ * gpio_request_one - request a single GPIO with initial configuration
+ * @gpio: the GPIO number
+ * @flags: GPIO configuration as specified by GPIOF_*
+ * @label: a literal description string of this GPIO
+ */
+int gpio_request_one(unsigned gpio, unsigned long flags, const char *label)
+{
+ struct gpio_desc *desc = gpio_to_desc(gpio);
+
+ if (!desc)
+ return -ENODEV;
+
+ return gpiodesc_request_one(desc, flags, label);
+}
+EXPORT_SYMBOL_GPL(gpio_request_one);
+
+/**
+ * gpio_request_array - request multiple GPIOs in a single call
+ * @array: array of the 'struct gpio'
+ * @num: how many GPIOs in the array
+ */
+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
+ */
+void gpio_free_array(const struct gpio *array, size_t num)
+{
+ while (num--)
+ gpio_free((array++)->gpio);
+}
+EXPORT_SYMBOL_GPL(gpio_free_array);
+
+int gpio_array_to_id(const struct gpio *array, size_t num, u32 *val)
+{
+ u32 id = 0;
+ int ret, i;
+
+ if (num > 32)
+ return -EOVERFLOW;
+
+ ret = gpio_request_array(array, num);
+ if (ret)
+ return ret;
+
+ /* Wait until logic level will be stable */
+ udelay(5);
+ for (i = 0; i < num; i++) {
+ ret = gpio_is_active(array[i].gpio);
+ if (ret < 0)
+ goto free_array;
+ if (ret)
+ id |= 1UL << i;
+ }
+
+ *val = id;
+ ret = 0;
+
+free_array:
+ gpio_free_array(array, num);
+ return ret;
+}
+EXPORT_SYMBOL(gpio_array_to_id);
+
+static int gpiochip_find_base(int ngpio)
{
int i;
int spare = 0;
int base = -ENOSPC;
- if (start < 0)
- start = 0;
-
- for (i = start; i < ARCH_NR_GPIOS; i++) {
+ for (i = ARCH_NR_GPIOS - 1; i >= 0; i--) {
struct gpio_chip *chip = gpio_desc[i].chip;
if (!chip) {
spare++;
if (spare == ngpio) {
- base = i + 1 - ngpio;
+ base = i;
break;
}
} else {
spare = 0;
- i += chip->ngpio - 1;
+ i -= chip->ngpio - 1;
}
}
@@ -335,10 +604,12 @@ static int gpiochip_find_base(int start, int ngpio)
return base;
}
+#ifdef CONFIG_OF_GPIO
+
static int of_hog_gpio(struct device_node *np, struct gpio_chip *chip,
unsigned int idx)
{
- struct device_node *chip_np = chip->dev->device_node;
+ struct device_node *chip_np = chip->dev->of_node;
unsigned long flags = 0;
u32 gpio_cells, gpio_num, gpio_flags;
int ret, gpio;
@@ -412,10 +683,7 @@ static int of_gpiochip_scan_hogs(struct gpio_chip *chip)
struct device_node *np;
int ret, i;
- if (!IS_ENABLED(CONFIG_OFDEVICE) || !chip->dev->device_node)
- return 0;
-
- for_each_available_child_of_node(chip->dev->device_node, np) {
+ for_each_available_child_of_node(chip->dev->of_node, np) {
if (!of_property_read_bool(np, "gpio-hog"))
continue;
@@ -434,25 +702,340 @@ static int of_gpiochip_scan_hogs(struct gpio_chip *chip)
return 0;
}
-int gpiochip_add(struct gpio_chip *chip)
+/*
+ * of_gpiochip_set_names - Set GPIO line names using OF properties
+ * @chip: GPIO chip whose lines should be named, if possible
+ *
+ * Looks for device property "gpio-line-names" and if it exists assigns
+ * GPIO line names for the chip. The memory allocated for the assigned
+ * names belong to the underlying firmware node and should not be released
+ * by the caller.
+ */
+static int of_gpiochip_set_names(struct gpio_chip *chip)
+{
+ struct device_node *np = dev_of_node(chip->dev);
+ const char **names;
+ int ret, i, count;
+
+ count = of_property_count_strings(np, "gpio-line-names");
+ if (count < 0)
+ return 0;
+
+ names = kcalloc(count, sizeof(*names), GFP_KERNEL);
+ if (!names)
+ return -ENOMEM;
+
+ ret = of_property_read_string_array(np, "gpio-line-names",
+ names, count);
+ if (ret < 0) {
+ kfree(names);
+ return ret;
+ }
+
+ /*
+ * Since property 'gpio-line-names' cannot contains gaps, we
+ * have to be sure we only assign those pins that really exists
+ * since chip->ngpio can be less.
+ */
+ if (count > chip->ngpio)
+ count = chip->ngpio;
+
+ for (i = 0; i < count; i++) {
+ /*
+ * Allow overriding "fixed" names provided by the GPIO
+ * provider. The "fixed" names are more often than not
+ * generic and less informative than the names given in
+ * device properties.
+ */
+ if (names[i] && names[i][0])
+ gpio_desc[chip->base + i].name = names[i];
+ }
+
+ free(names);
+
+ return 0;
+}
+
+/**
+ * of_gpio_simple_xlate - translate gpiospec to the GPIO number and flags
+ * @gc: pointer to the gpio_chip structure
+ * @gpiospec: GPIO specifier as found in the device tree
+ * @flags: a flags pointer to fill in
+ *
+ * This is simple translation function, suitable for the most 1:1 mapped
+ * GPIO chips. This function performs only one sanity check: whether GPIO
+ * is less than ngpios (that is specified in the gpio_chip).
+ */
+static int of_gpio_simple_xlate(struct gpio_chip *gc,
+ const struct of_phandle_args *gpiospec,
+ u32 *flags)
+{
+ /*
+ * We're discouraging gpio_cells < 2, since that way you'll have to
+ * write your own xlate function (that will have to retrieve the GPIO
+ * number and the flags from a single gpio cell -- this is possible,
+ * but not recommended).
+ */
+ if (WARN_ON(gc->of_gpio_n_cells < 2))
+ return -EINVAL;
+
+ if (WARN_ON(gpiospec->args_count < gc->of_gpio_n_cells))
+ return -EINVAL;
+
+ if (gpiospec->args[0] >= gc->ngpio)
+ return -EINVAL;
+
+ if (flags)
+ *flags = gpiospec->args[1];
+
+ return gc->base + gpiospec->args[0];
+}
+
+static int of_gpiochip_add(struct gpio_chip *chip)
+{
+ struct device_node *np;
+ int ret;
+
+ np = dev_of_node(chip->dev);
+ if (!np)
+ return 0;
+
+ if (!chip->ops->of_xlate)
+ chip->ops->of_xlate = of_gpio_simple_xlate;
+
+ /*
+ * Separate check since the 'struct gpio_ops' is always the same for
+ * every 'struct gpio_chip' of the same instance (e.g. 'struct
+ * imx_gpio_chip').
+ */
+ if (chip->ops->of_xlate == of_gpio_simple_xlate)
+ chip->of_gpio_n_cells = 2;
+
+ if (chip->of_gpio_n_cells > MAX_PHANDLE_ARGS)
+ return -EINVAL;
+
+ ret = of_gpiochip_set_names(chip);
+ if (ret)
+ return ret;
+
+ return of_gpiochip_scan_hogs(chip);
+}
+#else
+static int of_gpiochip_add(struct gpio_chip *chip)
+{
+ return 0;
+}
+#endif
+
+#ifdef CONFIG_OFDEVICE
+static const char *gpio_suffixes[] = {
+ "gpios",
+ "gpio",
+};
+
+static struct property *of_find_gpio_property(struct device_node *np,
+ const char *_con_id)
+{
+ struct property *pp = NULL;
+ char *con_id;
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(gpio_suffixes); i++) {
+ if (_con_id)
+ con_id = basprintf("%s-%s", _con_id, gpio_suffixes[i]);
+ else
+ con_id = basprintf("%s", gpio_suffixes[i]);
+
+ if (!con_id)
+ return ERR_PTR(-ENOMEM);
+
+ pp = of_find_property(np, con_id, NULL);
+ free(con_id);
+
+ if (pp)
+ return pp;
+ }
+
+ return NULL;
+}
+
+/* Linux compatibility helper: Get a GPIO descriptor from device tree */
+struct gpio_desc *dev_gpiod_get_index(struct device *dev,
+ struct device_node *np,
+ const char *con_id, int index,
+ enum gpiod_flags flags,
+ const char *label)
+{
+ struct gpio_desc *desc = NULL;
+ enum of_gpio_flags of_flags;
+ struct property *pp;
+ char *buf = NULL;
+ int gpio;
+ int ret;
+
+ if (!np)
+ return ERR_PTR(-ENODEV);
+
+ pp = of_find_gpio_property(np, con_id);
+ if (!pp)
+ return ERR_PTR(-ENOENT);
+
+ gpio = of_get_named_gpio_flags(dev->device_node, pp->name,
+ index, &of_flags);
+ if (!gpio_is_valid(gpio))
+ return ERR_PTR(gpio < 0 ? gpio : -EINVAL);
+
+ desc = gpio_to_desc(gpio);
+
+ if (of_flags & OF_GPIO_ACTIVE_LOW)
+ flags |= GPIOF_ACTIVE_LOW;
+
+ buf = NULL;
+
+ if (!label) {
+ if (con_id)
+ label = buf = basprintf("%s-%s", dev_name(dev), con_id);
+ else
+ label = dev_name(dev);
+ }
+
+ ret = gpiodesc_request_one(desc, flags, label);
+ free(buf);
+
+ return ret ? ERR_PTR(ret): desc;
+}
+
+/**
+ * gpiod_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
+ * @_con_id: function within the GPIO consumer
+ */
+int gpiod_count(struct device *dev, const char *con_id)
+{
+ struct device_node *np = dev_of_node(dev);
+ struct property *pp;
+
+ if (!np)
+ return -ENODEV;
+
+ pp = of_find_gpio_property(np, con_id);
+ if (!pp)
+ return -ENOENT;
+
+ return of_gpio_named_count(np, pp->name);
+}
+EXPORT_SYMBOL_GPL(gpiod_count);
+
+/**
+ * gpiod_get_array - obtain multiple GPIOs from a multi-index GPIO function
+ * @dev: GPIO consumer, can be NULL for system-global GPIOs
+ * @con_id: function within the GPIO consumer
+ * @flags: optional GPIO initialization flags
+ *
+ * This function acquires all the GPIOs defined under a given function.
+ *
+ * Return a struct gpio_descs containing an array of descriptors, -ENOENT if
+ * no GPIO has been assigned to the requested function, or another IS_ERR()
+ * code if an error occurred while trying to acquire the GPIOs.
+ */
+struct gpio_descs *__must_check gpiod_get_array(struct device *dev,
+ const char *con_id,
+ enum gpiod_flags flags)
+{
+ struct gpio_desc *desc;
+ struct gpio_descs *descs;
+ int count;
+
+ count = gpiod_count(dev, con_id);
+ if (count < 0)
+ return ERR_PTR(count);
+
+ descs = kzalloc(struct_size(descs, desc, count), GFP_KERNEL);
+ if (!descs)
+ return ERR_PTR(-ENOMEM);
+
+ for (descs->ndescs = 0; descs->ndescs < count; descs->ndescs++) {
+ desc = dev_gpiod_get_index(dev, dev_of_node(dev), con_id,
+ descs->ndescs, flags, NULL);
+ if (IS_ERR(desc)) {
+ gpiod_put_array(descs);
+ return ERR_CAST(desc);
+ }
+
+ descs->desc[descs->ndescs] = desc;
+ }
+
+ return descs;
+}
+EXPORT_SYMBOL_GPL(gpiod_get_array);
+
+#endif
+
+static int gpiod_set_array_value_complex(bool raw,
+ unsigned int array_size,
+ struct gpio_desc **desc_array,
+ struct gpio_array *array_info,
+ unsigned long *value_bitmap)
+{
+ int i;
+
+ BUG_ON(array_info != NULL);
+
+ for (i = 0; i < array_size; i++)
+ gpiod_set_value(desc_array[i], test_bit(i, value_bitmap));
+
+ return 0;
+}
+
+/**
+ * gpiod_set_array_value() - assign values to an array of GPIOs
+ * @array_size: number of elements in the descriptor array / value bitmap
+ * @desc_array: array of GPIO descriptors whose values will be assigned
+ * @array_info: information on applicability of fast bitmap processing path
+ * @value_bitmap: bitmap of values to assign
+ *
+ * Set the logical values of the GPIOs, i.e. taking their ACTIVE_LOW status
+ * into account. NOTE: This function has no special handling for GPIOs
+ * in the same bank that could've been set atomically: GPIO sequencing
+ * is not guaranteed to always remain in the same order.
+ */
+int gpiod_set_array_value(unsigned int array_size,
+ struct gpio_desc **desc_array,
+ struct gpio_array *array_info,
+ unsigned long *value_bitmap)
{
- int base, i;
+ if (!desc_array)
+ return -EINVAL;
+ return gpiod_set_array_value_complex(false, array_size,
+ desc_array, array_info,
+ value_bitmap);
+}
+EXPORT_SYMBOL_GPL(gpiod_set_array_value);
- base = gpiochip_find_base(chip->base, chip->ngpio);
- if (base < 0)
- return base;
+int gpiochip_add(struct gpio_chip *chip)
+{
+ int i;
- if (chip->base >= 0 && chip->base != base)
- return -EBUSY;
+ if (chip->base >= 0) {
+ for (i = 0; i < chip->ngpio; i++) {
+ if (gpio_desc[chip->base + i].chip)
+ return -EBUSY;
+ }
+ } else {
+ chip->base = gpiochip_find_base(chip->ngpio);
+ if (chip->base < 0)
+ return -ENOSPC;
+ }
- chip->base = base;
+ slice_init(&chip->slice, dev_name(chip->dev));
list_add_tail(&chip->list, &chip_list);
for (i = chip->base; i < chip->base + chip->ngpio; i++)
gpio_desc[i].chip = chip;
- return of_gpiochip_scan_hogs(chip);
+ return of_gpiochip_add(chip);
}
void gpiochip_remove(struct gpio_chip *chip)
@@ -460,61 +1043,93 @@ void gpiochip_remove(struct gpio_chip *chip)
list_del(&chip->list);
}
-int gpio_get_num(struct device_d *dev, int gpio)
+struct gpio_chip *gpio_get_chip_by_dev(struct device *dev)
{
struct gpio_chip *chip;
- if (!dev)
- return -ENODEV;
-
list_for_each_entry(chip, &chip_list, list) {
if (chip->dev == dev)
- return chip->base + gpio;
+ return chip;
}
- return -EPROBE_DEFER;
+ return NULL;
+}
+
+int gpio_get_num(struct device *dev, int gpio)
+{
+ struct gpio_chip *chip;
+
+ if (!dev)
+ return -ENODEV;
+
+ chip = gpio_get_chip_by_dev(dev);
+ if (!chip)
+ return -EPROBE_DEFER;
+
+ return chip->base + gpio;
}
struct gpio_chip *gpio_get_chip(int gpio)
{
- struct gpio_info *gi = gpio_to_desc(gpio);
+ struct gpio_desc *desc = gpio_to_desc(gpio);
- return gi ? gi->chip : NULL;
+ return desc ? desc->chip : NULL;
}
#ifdef CONFIG_CMD_GPIO
static int do_gpiolib(int argc, char *argv[])
{
+ struct gpio_chip *chip = NULL;
int i;
+ if (argc > 2)
+ return COMMAND_ERROR_USAGE;
+
+ if (argc > 1) {
+ struct device *dev;
+
+ dev = find_device(argv[1]);
+ if (!dev)
+ return -ENODEV;
+
+ chip = gpio_get_chip_by_dev(dev);
+ if (!chip)
+ return -EINVAL;
+ }
+
for (i = 0; i < ARCH_NR_GPIOS; i++) {
- struct gpio_info *gi = &gpio_desc[i];
+ struct gpio_desc *desc = &gpio_desc[i];
int val = -1, dir = -1;
+ int idx;
+
+ if (!desc->chip)
+ continue;
- if (!gi->chip)
+ if (chip && chip != desc->chip)
continue;
/* print chip information and header on first gpio */
- if (gi->chip->base == i) {
+ if (desc->chip->base == i) {
printf("\nGPIOs %u-%u, chip %s:\n",
- gi->chip->base,
- gi->chip->base + gi->chip->ngpio - 1,
- gi->chip->dev->name);
- printf("%*cdir val requested label\n", 13, ' ');
+ desc->chip->base,
+ desc->chip->base + desc->chip->ngpio - 1,
+ dev_name(desc->chip->dev));
+ printf(" %-3s %-3s %-9s %-20s %-20s\n", "dir", "val", "requested", "name", "label");
}
- if (gi->chip->ops->get_direction)
- dir = gi->chip->ops->get_direction(gi->chip,
- i - gi->chip->base);
- if (gi->chip->ops->get)
- val = gi->chip->ops->get(gi->chip,
- i - gi->chip->base);
-
- printf(" GPIO %*d: %*s %*s %*s %s\n", 4, i,
- 3, (dir < 0) ? "unk" : ((dir == GPIOF_DIR_IN) ? "in" : "out"),
- 3, (val < 0) ? "unk" : ((val == 0) ? "lo" : "hi"),
- 12, gi->requested ? (gi->active_low ? "active low" : "true") : "false",
- (gi->requested && gi->label) ? gi->label : "");
+ idx = i - desc->chip->base;
+
+ if (desc->chip->ops->get_direction)
+ dir = desc->chip->ops->get_direction(desc->chip, idx);
+ if (desc->chip->ops->get)
+ val = desc->chip->ops->get(desc->chip, idx);
+
+ printf(" GPIO %4d: %-3s %-3s %-9s %-20s %-20s\n", chip ? idx : i,
+ (dir < 0) ? "unk" : ((dir == GPIOF_DIR_IN) ? "in" : "out"),
+ (val < 0) ? "unk" : ((val == 0) ? "lo" : "hi"),
+ desc->requested ? (desc->active_low ? "active low" : "true") : "false",
+ desc->name ? desc->name : "",
+ desc->label ? desc->label : "");
}
return 0;
@@ -523,6 +1138,7 @@ static int do_gpiolib(int argc, char *argv[])
BAREBOX_CMD_START(gpioinfo)
.cmd = do_gpiolib,
BAREBOX_CMD_DESC("list registered GPIOs")
+ BAREBOX_CMD_OPTS("[CONTROLLER]")
BAREBOX_CMD_GROUP(CMD_GRP_INFO)
BAREBOX_CMD_COMPLETE(empty_complete)
BAREBOX_CMD_END