dm: gpio: Add of-platdata support

Add support for accessing GPIOs using of-plata. This uses the same
mechanism as for clocks, but allows use of the xlate() method so that
the driver can interpret the parameters.

Update the condition for GPIO_HOG so that it is not built into SPL,
since it needs SPL_OF_REAL which is not enabled in sandbox_spl.

Signed-off-by: Simon Glass <sjg@chromium.org>
diff --git a/drivers/gpio/Makefile b/drivers/gpio/Makefile
index 58f4704..1891748 100644
--- a/drivers/gpio/Makefile
+++ b/drivers/gpio/Makefile
@@ -33,7 +33,7 @@
 obj-$(CONFIG_RCAR_GPIO)		+= gpio-rcar.o
 obj-$(CONFIG_RZA1_GPIO)		+= gpio-rza1.o
 obj-$(CONFIG_S5P)		+= s5p_gpio.o
-obj-$(CONFIG_SANDBOX_GPIO)	+= sandbox.o
+obj-$(CONFIG_SANDBOX_GPIO)	+= sandbox.o sandbox_test.o
 obj-$(CONFIG_TEGRA_GPIO)	+= tegra_gpio.o
 obj-$(CONFIG_TEGRA186_GPIO)	+= tegra186_gpio.o
 obj-$(CONFIG_DA8XX_GPIO)	+= da8xx_gpio.o
@@ -62,7 +62,7 @@
 obj-$(CONFIG_MVEBU_GPIO)	+= mvebu_gpio.o
 obj-$(CONFIG_MSM_GPIO)		+= msm_gpio.o
 obj-$(CONFIG_$(SPL_)PCF8575_GPIO)	+= pcf8575_gpio.o
-obj-$(CONFIG_PM8916_GPIO)	+= pm8916_gpio.o
+obj-$(CONFIG_$(SPL_TPL_)PM8916_GPIO)	+= pm8916_gpio.o
 obj-$(CONFIG_MT7620_GPIO)	+= mt7620_gpio.o
 obj-$(CONFIG_MT7621_GPIO)	+= mt7621_gpio.o
 obj-$(CONFIG_MSCC_SGPIO)	+= mscc_sgpio.o
diff --git a/drivers/gpio/gpio-uclass.c b/drivers/gpio/gpio-uclass.c
index e0d3ae6..bb2f232 100644
--- a/drivers/gpio/gpio-uclass.c
+++ b/drivers/gpio/gpio-uclass.c
@@ -7,6 +7,7 @@
 
 #include <common.h>
 #include <dm.h>
+#include <dt-structs.h>
 #include <log.h>
 #include <dm/devres.h>
 #include <dm/device_compat.h>
@@ -231,7 +232,7 @@
 		return gpio_xlate_offs_flags(desc->dev, desc, args);
 }
 
-#if defined(CONFIG_GPIO_HOG)
+#if CONFIG_IS_ENABLED(GPIO_HOG)
 
 struct gpio_hog_priv {
 	struct gpio_desc gpiod;
@@ -1226,6 +1227,27 @@
 }
 #endif /* OF_PLATDATA */
 
+#if CONFIG_IS_ENABLED(OF_PLATDATA)
+int gpio_request_by_phandle(struct udevice *dev,
+			    const struct phandle_2_arg *cells,
+			    struct gpio_desc *desc, int flags)
+{
+	struct ofnode_phandle_args args;
+	struct udevice *gpio_dev;
+	const int index = 0;
+	int ret;
+
+	ret = device_get_by_ofplat_idx(cells->idx, &gpio_dev);
+	if (ret)
+		return ret;
+	args.args[0] = cells->arg[0];
+	args.args[1] = cells->arg[1];
+
+	return gpio_request_tail(ret, NULL, &args, NULL, index, desc, flags,
+				 index > 0, gpio_dev);
+}
+#endif
+
 int dm_gpio_free(struct udevice *dev, struct gpio_desc *desc)
 {
 	/* For now, we don't do any checking of dev */
@@ -1430,7 +1452,7 @@
 	}
 #endif
 
-	if (IS_ENABLED(CONFIG_GPIO_HOG)) {
+	if (CONFIG_IS_ENABLED(OF_REAL) && IS_ENABLED(CONFIG_GPIO_HOG)) {
 		dev_for_each_subnode(node, dev) {
 			if (ofnode_read_bool(node, "gpio-hog")) {
 				const char *name = ofnode_get_name(node);
diff --git a/drivers/gpio/sandbox.c b/drivers/gpio/sandbox.c
index d008fdd..106b2a7 100644
--- a/drivers/gpio/sandbox.c
+++ b/drivers/gpio/sandbox.c
@@ -323,11 +323,13 @@
 
 static int sandbox_gpio_of_to_plat(struct udevice *dev)
 {
-	struct gpio_dev_priv *uc_priv = dev_get_uclass_priv(dev);
+	if (CONFIG_IS_ENABLED(OF_REAL)) {
+		struct gpio_dev_priv *uc_priv = dev_get_uclass_priv(dev);
 
-	uc_priv->gpio_count = dev_read_u32_default(dev, "sandbox,gpio-count",
-						   0);
-	uc_priv->bank_name = dev_read_string(dev, "gpio-bank-name");
+		uc_priv->gpio_count =
+			dev_read_u32_default(dev, "sandbox,gpio-count", 0);
+		uc_priv->bank_name = dev_read_string(dev, "gpio-bank-name");
+	}
 
 	return 0;
 }
@@ -371,6 +373,8 @@
 
 DM_DRIVER_ALIAS(sandbox_gpio, sandbox_gpio_alias)
 
+#if CONFIG_IS_ENABLED(PINCTRL)
+
 /* pincontrol: used only to check GPIO pin configuration (pinmux command) */
 
 struct sb_pinctrl_priv {
@@ -579,3 +583,5 @@
 	.priv_auto	= sizeof(struct sb_pinctrl_priv),
 	ACPI_OPS_PTR(&pinctrl_sandbox_acpi_ops)
 };
+
+#endif /* PINCTRL */
diff --git a/drivers/gpio/sandbox_test.c b/drivers/gpio/sandbox_test.c
new file mode 100644
index 0000000..c76e199
--- /dev/null
+++ b/drivers/gpio/sandbox_test.c
@@ -0,0 +1,21 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Sandbox driver for testing GPIOs with of-platdata
+ *
+ * Copyright 2021 Google LLC
+ */
+
+#include <common.h>
+#include <dm.h>
+#include <asm-generic/gpio.h>
+
+static const struct udevice_id sandbox_gpio_test_ids[] = {
+	{ .compatible = "sandbox,gpio-test" },
+	{ }
+};
+
+U_BOOT_DRIVER(sandbox_gpio_test) = {
+	.name = "sandbox_gpio_test",
+	.id = UCLASS_MISC,
+	.of_match = sandbox_gpio_test_ids,
+};