[U-Boot] [PATCH 4/6] pinctrl: armada-37xx: Add gpio support

Stefan Roese sr at denx.de
Tue May 23 04:59:48 UTC 2017


From: Gregory CLEMENT <gregory.clement at free-electrons.com>

GPIO management is pretty simple and is part of the same IP than the pin
controller for the Armada 37xx SoCs.  This patch adds the GPIO support to
the pinctrl-armada-37xx.c file, it also allows sharing common functions
between the gpio and the pinctrl drivers.

Ported to U-Boot based on the Linux version by Stefan Roese.

Signed-off-by: Gregory CLEMENT <gregory.clement at free-electrons.com>
Signed-off-by: Stefan Roese <sr at denx.de>
Cc: Gregory CLEMENT <gregory.clement at free-electrons.com>
Cc: Konstantin Porotchkin <kostap at marvell.com>
Cc: Nadav Haklai <nadavh at marvell.com>
---
 drivers/pinctrl/mvebu/pinctrl-armada-37xx.c | 162 ++++++++++++++++++++++++++++
 1 file changed, 162 insertions(+)

diff --git a/drivers/pinctrl/mvebu/pinctrl-armada-37xx.c b/drivers/pinctrl/mvebu/pinctrl-armada-37xx.c
index 6a31d98937..630cedf2d6 100644
--- a/drivers/pinctrl/mvebu/pinctrl-armada-37xx.c
+++ b/drivers/pinctrl/mvebu/pinctrl-armada-37xx.c
@@ -20,17 +20,22 @@
 #include <common.h>
 #include <config.h>
 #include <dm.h>
+#include <dm/device-internal.h>
+#include <dm/lists.h>
 #include <dm/pinctrl.h>
 #include <dm/root.h>
 #include <errno.h>
 #include <fdtdec.h>
 #include <regmap.h>
+#include <asm/gpio.h>
 #include <asm/system.h>
 #include <asm/io.h>
 
 DECLARE_GLOBAL_DATA_PTR;
 
 #define OUTPUT_EN	0x0
+#define INPUT_VAL	0x10
+#define OUTPUT_VAL	0x18
 #define OUTPUT_CTL	0x20
 #define SELECTION	0x30
 
@@ -189,6 +194,16 @@ const struct armada_37xx_pin_data armada_37xx_pin_sb = {
 	.ngroups = ARRAY_SIZE(armada_37xx_sb_groups),
 };
 
+static inline void armada_37xx_update_reg(unsigned int *reg,
+					  unsigned int offset)
+{
+	/* We never have more than 2 registers */
+	if (offset >= GPIO_PER_REG) {
+		offset -= GPIO_PER_REG;
+		*reg += sizeof(u32);
+	}
+}
+
 static int armada_37xx_get_func_reg(struct armada_37xx_pin_group *grp,
 				    const char *func)
 {
@@ -399,6 +414,149 @@ static int armada_37xx_fill_func(struct armada_37xx_pinctrl *info)
 	return 0;
 }
 
+static int armada_37xx_gpio_get(struct udevice *dev, unsigned int offset)
+{
+	struct armada_37xx_pinctrl *info = dev_get_priv(dev->parent);
+	unsigned int reg = INPUT_VAL;
+	unsigned int val, mask;
+
+	armada_37xx_update_reg(&reg, offset);
+	mask = BIT(offset);
+
+	val = readl(info->base + reg);
+
+	return (val & mask) != 0;
+}
+
+static int armada_37xx_gpio_set(struct udevice *dev, unsigned int offset,
+				int value)
+{
+	struct armada_37xx_pinctrl *info = dev_get_priv(dev->parent);
+	unsigned int reg = OUTPUT_VAL;
+	unsigned int mask, val;
+
+	armada_37xx_update_reg(&reg, offset);
+	mask = BIT(offset);
+	val = value ? mask : 0;
+
+	clrsetbits_le32(info->base + reg, mask, val);
+
+	return 0;
+}
+
+static int armada_37xx_gpio_get_direction(struct udevice *dev,
+					  unsigned int offset)
+{
+	struct armada_37xx_pinctrl *info = dev_get_priv(dev->parent);
+	unsigned int reg = OUTPUT_EN;
+	unsigned int val, mask;
+
+	armada_37xx_update_reg(&reg, offset);
+	mask = BIT(offset);
+	val = readl(info->base + reg);
+
+	if (val & mask)
+		return GPIOF_OUTPUT;
+	else
+		return GPIOF_INPUT;
+}
+
+static int armada_37xx_gpio_direction_input(struct udevice *dev,
+					    unsigned int offset)
+{
+	struct armada_37xx_pinctrl *info = dev_get_priv(dev->parent);
+	unsigned int reg = OUTPUT_EN;
+	unsigned int mask;
+
+	armada_37xx_update_reg(&reg, offset);
+	mask = BIT(offset);
+
+	clrbits_le32(info->base + reg, mask);
+
+	return 0;
+}
+
+static int armada_37xx_gpio_direction_output(struct udevice *dev,
+					     unsigned int offset, int value)
+{
+	struct armada_37xx_pinctrl *info = dev_get_priv(dev->parent);
+	unsigned int reg = OUTPUT_EN;
+	unsigned int mask;
+
+	armada_37xx_update_reg(&reg, offset);
+	mask = BIT(offset);
+
+	setbits_le32(info->base + reg, mask);
+
+	/* And set the requested value */
+	return armada_37xx_gpio_set(dev, offset, value);
+}
+
+static int armada_37xx_gpio_probe(struct udevice *dev)
+{
+	struct armada_37xx_pinctrl *info = dev_get_priv(dev->parent);
+	struct gpio_dev_priv *uc_priv;
+
+	uc_priv = dev_get_uclass_priv(dev);
+	uc_priv->bank_name = info->data->name;
+	uc_priv->gpio_count = info->data->nr_pins;
+
+	return 0;
+}
+
+static const struct dm_gpio_ops armada_37xx_gpio_ops = {
+	.set_value = armada_37xx_gpio_set,
+	.get_value = armada_37xx_gpio_get,
+	.get_function = armada_37xx_gpio_get_direction,
+	.direction_input = armada_37xx_gpio_direction_input,
+	.direction_output = armada_37xx_gpio_direction_output,
+};
+
+static struct driver armada_37xx_gpio_driver = {
+	.name	= "armada-37xx-gpio",
+	.id	= UCLASS_GPIO,
+	.probe	= armada_37xx_gpio_probe,
+	.ops	= &armada_37xx_gpio_ops,
+};
+
+static int armada_37xx_gpiochip_register(struct udevice *parent,
+					 struct armada_37xx_pinctrl *info)
+{
+	const void *blob = gd->fdt_blob;
+	int node = dev_of_offset(parent);
+	struct uclass_driver *drv;
+	struct udevice *dev;
+	int ret = -ENODEV;
+	int subnode;
+	char *name;
+
+	/* Lookup GPIO driver */
+	drv = lists_uclass_lookup(UCLASS_GPIO);
+	if (!drv) {
+		puts("Cannot find GPIO driver\n");
+		return -ENOENT;
+	}
+
+	fdt_for_each_subnode(subnode, blob, node) {
+		if (!fdtdec_get_bool(blob, subnode, "gpio-controller")) {
+			ret = 0;
+			break;
+		}
+	};
+	if (ret)
+		return ret;
+
+	name = calloc(1, 32);
+	sprintf(name, "armada-37xx-gpio");
+
+	/* Create child device UCLASS_GPIO and bind it */
+	device_bind(parent, &armada_37xx_gpio_driver, name, NULL, subnode,
+		    &dev);
+	dev_set_of_offset(dev, subnode);
+
+	return 0;
+}
+
 const struct pinctrl_ops armada_37xx_pinctrl_ops  = {
 	.get_groups_count = armada_37xx_pmx_get_groups_count,
 	.get_group_name = armada_37xx_pmx_get_group_name,
@@ -444,6 +602,10 @@ int armada_37xx_pinctrl_probe(struct udevice *dev)
 	if (ret)
 		return ret;
 
+	ret = armada_37xx_gpiochip_register(dev, info);
+	if (ret)
+		return ret;
+
 	return 0;
 }
 
-- 
2.12.3



More information about the U-Boot mailing list