public inbox for u-boot@lists.denx.de
 help / color / mirror / Atom feed
From: Stefan Roese <sr@denx.de>
To: u-boot@lists.denx.de
Subject: [U-Boot] [PATCH 4/6] pinctrl: armada-37xx: Add gpio support
Date: Tue, 23 May 2017 06:59:48 +0200	[thread overview]
Message-ID: <20170523045950.7020-4-sr@denx.de> (raw)
In-Reply-To: <20170523045950.7020-1-sr@denx.de>

From: Gregory CLEMENT <gregory.clement@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@free-electrons.com>
Signed-off-by: Stefan Roese <sr@denx.de>
Cc: Gregory CLEMENT <gregory.clement@free-electrons.com>
Cc: Konstantin Porotchkin <kostap@marvell.com>
Cc: Nadav Haklai <nadavh@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

  parent reply	other threads:[~2017-05-23  4:59 UTC|newest]

Thread overview: 7+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2017-05-23  4:59 [U-Boot] [PATCH 1/6] arm64: mvebu: Add pinctrl nodes for Armada 3700 Stefan Roese
2017-05-23  4:59 ` [U-Boot] [PATCH 2/6] arm64: mvebu: armada37xx: add pinctrl definition Stefan Roese
2017-05-23  4:59 ` [U-Boot] [PATCH 3/6] pinctrl: armada-37xx: Add pin controller support for Armada 37xx Stefan Roese
2017-05-23  4:59 ` Stefan Roese [this message]
2017-05-23  4:59 ` [U-Boot] [PATCH 5/6] pinctrl: mvebu: Enable support for the Armada 37xx pinctrl driver Stefan Roese
2017-05-23  4:59 ` [U-Boot] [PATCH 6/6] arm64: mvebu_db-88f3720_defconfig: Enable PINCTRL and GPIO support Stefan Roese
2017-05-31  8:59 ` [U-Boot] [PATCH 1/6] arm64: mvebu: Add pinctrl nodes for Armada 3700 Stefan Roese

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20170523045950.7020-4-sr@denx.de \
    --to=sr@denx.de \
    --cc=u-boot@lists.denx.de \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox