All of lore.kernel.org
 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 an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.