mail archive of the barebox mailing list
 help / color / mirror / Atom feed
* [PATCH 1/5] gpiolib: add Linux-like gpiod_get() helper
@ 2021-04-10 10:35 Ahmad Fatoum
  2021-04-10 10:35 ` [PATCH 2/5] sound: gpio-beeper: simplify using new gpiod_get helper Ahmad Fatoum
                   ` (4 more replies)
  0 siblings, 5 replies; 7+ messages in thread
From: Ahmad Fatoum @ 2021-04-10 10:35 UTC (permalink / raw)
  To: barebox; +Cc: Ahmad Fatoum

Many Linux drivers use [devm_]gpiod_get to get appropriately configured
GPIO descriptors out with little code. Make porting such Linux code
easier by providing a semi-compatible gpiod_get function. Main
differences:

 - It returns a gpio index, so it can be passed to any gpio_ function
 - It's device-tree only, so it should only be used from drivers
   that themselves probe from device tree.

Signed-off-by: Ahmad Fatoum <ahmad@a3f.at>
---
 drivers/gpio/gpiolib.c | 43 ++++++++++++++++++++++++++++++++++++++++++
 include/gpiod.h        | 26 +++++++++++++++++++++++++
 2 files changed, 69 insertions(+)
 create mode 100644 include/gpiod.h

diff --git a/drivers/gpio/gpiolib.c b/drivers/gpio/gpiolib.c
index 6088cadd8a18..7b7261d01f24 100644
--- a/drivers/gpio/gpiolib.c
+++ b/drivers/gpio/gpiolib.c
@@ -6,6 +6,7 @@
 #include <complete.h>
 #include <gpio.h>
 #include <of_gpio.h>
+#include <gpiod.h>
 #include <errno.h>
 #include <malloc.h>
 
@@ -554,6 +555,48 @@ static int of_gpiochip_scan_hogs(struct gpio_chip *chip)
 	return 0;
 }
 
+/* Linux compatibility helper: Get a GPIO descriptor from device tree */
+int gpiod_get(struct device_d *dev, const char *_con_id, enum gpiod_flags flags)
+{
+	struct device_node *np = dev->device_node;
+	enum of_gpio_flags of_flags;
+	const char *con_id = "gpios", *label = dev_name(dev);
+	char *buf = NULL;
+	int gpio;
+	int ret;
+
+	if (!IS_ENABLED(CONFIG_OFDEVICE) || !dev->device_node)
+		return -ENODEV;
+
+	if (_con_id) {
+		con_id = buf = basprintf("%s-gpios", _con_id);
+		if (!buf)
+			return -ENOMEM;
+	}
+
+	gpio = of_get_named_gpio_flags(np, con_id, 0, &of_flags);
+	free(buf);
+
+	if (!gpio_is_valid(gpio))
+		return gpio < 0 ? gpio : -EINVAL;
+
+	if (of_flags & OF_GPIO_ACTIVE_LOW)
+		flags |= GPIOF_ACTIVE_LOW;
+
+	buf = NULL;
+
+	if (_con_id) {
+		label = buf = basprintf("%s-%s", dev_name(dev), _con_id);
+		if (!label)
+			return -ENOMEM;
+	}
+
+	ret = gpio_request_one(gpio, flags, label);
+	free(buf);
+
+	return ret ?: gpio;
+}
+
 int gpiochip_add(struct gpio_chip *chip)
 {
 	int base, i;
diff --git a/include/gpiod.h b/include/gpiod.h
new file mode 100644
index 000000000000..c8b2cd47a3cb
--- /dev/null
+++ b/include/gpiod.h
@@ -0,0 +1,26 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+#ifndef __GPIOD_H_
+#define __GPIOD_H_
+
+#include <gpio.h>
+#include <of_gpio.h>
+
+/**
+ * Optional flags that can be passed to one of gpiod_* to configure direction
+ * and output value. These values cannot be OR'd.
+ */
+enum gpiod_flags {
+	GPIOD_ASIS	= 0,
+	GPIOD_IN	= GPIOF_IN,
+	/*
+	 * To change this later to a different logic level (i.e. taking
+	 * active low into account), use gpio_direction_active()
+	 */
+	GPIOD_OUT_LOW	= GPIOF_OUT_INIT_INACTIVE,
+	GPIOD_OUT_HIGH	= GPIOF_OUT_INIT_ACTIVE,
+};
+
+/* returned gpio descriptor can be passed to any normal gpio_* function */
+int gpiod_get(struct device_d *dev, const char *_con_id, enum gpiod_flags flags);
+
+#endif
-- 
2.30.0


_______________________________________________
barebox mailing list
barebox@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/barebox


^ permalink raw reply	[flat|nested] 7+ messages in thread

* [PATCH 2/5] sound: gpio-beeper: simplify using new gpiod_get helper
  2021-04-10 10:35 [PATCH 1/5] gpiolib: add Linux-like gpiod_get() helper Ahmad Fatoum
@ 2021-04-10 10:35 ` Ahmad Fatoum
  2021-04-10 10:35 ` [PATCH 3/5] power: reset: add GPIO poweroff driver Ahmad Fatoum
                   ` (3 subsequent siblings)
  4 siblings, 0 replies; 7+ messages in thread
From: Ahmad Fatoum @ 2021-04-10 10:35 UTC (permalink / raw)
  To: barebox; +Cc: Ahmad Fatoum

the new gpid_get helper allows us to remove the manual
active state setting. Make use of this.

This also fixes an issue where the initial state of the beeper
was on, not off.

Signed-off-by: Ahmad Fatoum <ahmad@a3f.at>
---
 drivers/sound/gpio-beeper.c | 20 +++++---------------
 1 file changed, 5 insertions(+), 15 deletions(-)

diff --git a/drivers/sound/gpio-beeper.c b/drivers/sound/gpio-beeper.c
index 86fd4a4ee67c..300998d6079b 100644
--- a/drivers/sound/gpio-beeper.c
+++ b/drivers/sound/gpio-beeper.c
@@ -7,8 +7,7 @@
 #include <regulator.h>
 #include <sound.h>
 #include <of.h>
-#include <gpio.h>
-#include <of_gpio.h>
+#include <gpiod.h>
 
 struct gpio_beeper {
 	int gpio;
@@ -28,21 +27,12 @@ static int gpio_beeper_probe(struct device_d *dev)
 	struct device_node *np = dev->device_node;
 	struct gpio_beeper *beeper;
 	struct sound_card *card;
-	enum of_gpio_flags of_flags;
-	unsigned long gpio_flags = GPIOF_OUT_INIT_ACTIVE;
-	int ret, gpio;
+	int gpio;
 
-	gpio = of_get_named_gpio_flags(np, "gpios", 0, &of_flags);
-	if (!gpio_is_valid(gpio))
+	gpio = gpiod_get(dev, NULL, GPIOD_OUT_LOW);
+	if (gpio < 0) {
+		dev_err(dev, "failed to request gpio: %pe\n", ERR_PTR(gpio));
 		return gpio;
-
-	if (of_flags & OF_GPIO_ACTIVE_LOW)
-		gpio_flags |= GPIOF_ACTIVE_LOW;
-
-	ret = gpio_request_one(gpio, gpio_flags, "gpio-beeper");
-	if (ret) {
-		dev_err(dev, "failed to request gpio %d: %d\n", gpio, ret);
-		return ret;
 	}
 
 	beeper = xzalloc(sizeof(*beeper));
-- 
2.30.0


_______________________________________________
barebox mailing list
barebox@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/barebox


^ permalink raw reply	[flat|nested] 7+ messages in thread

* [PATCH 3/5] power: reset: add GPIO poweroff driver
  2021-04-10 10:35 [PATCH 1/5] gpiolib: add Linux-like gpiod_get() helper Ahmad Fatoum
  2021-04-10 10:35 ` [PATCH 2/5] sound: gpio-beeper: simplify using new gpiod_get helper Ahmad Fatoum
@ 2021-04-10 10:35 ` Ahmad Fatoum
  2021-04-10 10:35 ` [PATCH 4/5] power: reset: add GPIO restart driver Ahmad Fatoum
                   ` (2 subsequent siblings)
  4 siblings, 0 replies; 7+ messages in thread
From: Ahmad Fatoum @ 2021-04-10 10:35 UTC (permalink / raw)
  To: barebox; +Cc: Ahmad Fatoum

This is a straight port from Linux v5.11.

Signed-off-by: Ahmad Fatoum <ahmad@a3f.at>
---
 drivers/power/reset/Kconfig         |  8 +++
 drivers/power/reset/Makefile        |  1 +
 drivers/power/reset/gpio-poweroff.c | 93 +++++++++++++++++++++++++++++
 3 files changed, 102 insertions(+)
 create mode 100644 drivers/power/reset/gpio-poweroff.c

diff --git a/drivers/power/reset/Kconfig b/drivers/power/reset/Kconfig
index e60037a6e637..cadcc0b13f2f 100644
--- a/drivers/power/reset/Kconfig
+++ b/drivers/power/reset/Kconfig
@@ -28,3 +28,11 @@ config POWER_RESET_SYSCON_POWEROFF
 	select MFD_SYSCON
 	help
 	  Poweroff support for generic SYSCON mapped register poweroff.
+
+config POWER_RESET_GPIO
+	bool "GPIO power-off driver"
+	depends on OF_GPIO
+	help
+	  This driver supports turning off your board via a GPIO line.
+	  If your board needs a GPIO high/low to power down, say Y and
+	  create a binding in your devicetree.
diff --git a/drivers/power/reset/Makefile b/drivers/power/reset/Makefile
index a490dce87333..438c85970028 100644
--- a/drivers/power/reset/Makefile
+++ b/drivers/power/reset/Makefile
@@ -3,3 +3,4 @@ obj-$(CONFIG_REBOOT_MODE) += reboot-mode.o
 obj-$(CONFIG_SYSCON_REBOOT_MODE) += syscon-reboot-mode.o
 obj-$(CONFIG_POWER_RESET_SYSCON) += syscon-reboot.o
 obj-$(CONFIG_POWER_RESET_SYSCON_POWEROFF) += syscon-poweroff.o
+obj-$(CONFIG_POWER_RESET_GPIO) += gpio-poweroff.o
diff --git a/drivers/power/reset/gpio-poweroff.c b/drivers/power/reset/gpio-poweroff.c
new file mode 100644
index 000000000000..45b0d274e729
--- /dev/null
+++ b/drivers/power/reset/gpio-poweroff.c
@@ -0,0 +1,93 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Toggles a GPIO pin to power down a device
+ *
+ * Jamie Lentin <jm@lentin.co.uk>
+ * Andrew Lunn <andrew@lunn.ch>
+ *
+ * Copyright (C) 2012 Jamie Lentin
+ */
+#include <common.h>
+#include <driver.h>
+#include <poweroff.h>
+#include <gpiod.h>
+
+#define DEFAULT_TIMEOUT_MS 3000
+/*
+ * Hold configuration here, cannot be more than one instance of the driver
+ * since pm_power_off itself is global.
+ */
+static int reset_gpio;
+static u32 timeout = DEFAULT_TIMEOUT_MS;
+static u32 active_delay = 100;
+static u32 inactive_delay = 100;
+
+static void gpio_poweroff_do_poweroff(struct poweroff_handler *handler)
+{
+	/* drive it active, also inactive->active edge */
+	gpio_direction_active(reset_gpio, true);
+	mdelay(active_delay);
+
+	/* drive inactive, also active->inactive edge */
+	gpio_set_active(reset_gpio, false);
+	mdelay(inactive_delay);
+
+	/* drive it active, also inactive->active edge */
+	gpio_set_active(reset_gpio, true);
+
+	/* give it some time */
+	mdelay(timeout);
+
+	WARN_ON(1);
+}
+
+static struct poweroff_handler handler;
+
+static int gpio_poweroff_probe(struct device_d *dev)
+{
+	struct device_node *np = dev->device_node;
+	bool input = false;
+	enum gpiod_flags flags;
+
+	if (handler.poweroff != NULL) {
+		dev_err(dev, "%s: pm_power_off function already registered\n", __func__);
+		return -EBUSY;
+	}
+
+	input = of_property_read_bool(np, "input");
+	if (input)
+		flags = GPIOD_IN;
+	else
+		flags = GPIOD_OUT_LOW;
+
+	of_property_read_u32(np, "active-delay-ms", &active_delay);
+	of_property_read_u32(np, "inactive-delay-ms", &inactive_delay);
+	of_property_read_u32(np, "timeout-ms", &timeout);
+
+	reset_gpio = gpiod_get(dev, NULL, flags);
+	if (reset_gpio < 0)
+		return reset_gpio;
+
+	handler.name = "gpio-poweroff";
+	handler.poweroff = gpio_poweroff_do_poweroff;
+	handler.priority = 129;
+
+	return poweroff_handler_register(&handler);
+}
+
+static const struct of_device_id of_gpio_poweroff_match[] = {
+	{ .compatible = "gpio-poweroff", },
+	{},
+};
+
+static struct driver_d gpio_poweroff_driver = {
+	.name = "poweroff-gpio",
+	.of_compatible = of_gpio_poweroff_match,
+	.probe = gpio_poweroff_probe,
+};
+device_platform_driver(gpio_poweroff_driver);
+
+MODULE_AUTHOR("Jamie Lentin <jm@lentin.co.uk>");
+MODULE_DESCRIPTION("GPIO poweroff driver");
+MODULE_LICENSE("GPL v2");
+MODULE_ALIAS("platform:poweroff-gpio");
-- 
2.30.0


_______________________________________________
barebox mailing list
barebox@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/barebox


^ permalink raw reply	[flat|nested] 7+ messages in thread

* [PATCH 4/5] power: reset: add GPIO restart driver
  2021-04-10 10:35 [PATCH 1/5] gpiolib: add Linux-like gpiod_get() helper Ahmad Fatoum
  2021-04-10 10:35 ` [PATCH 2/5] sound: gpio-beeper: simplify using new gpiod_get helper Ahmad Fatoum
  2021-04-10 10:35 ` [PATCH 3/5] power: reset: add GPIO poweroff driver Ahmad Fatoum
@ 2021-04-10 10:35 ` Ahmad Fatoum
  2021-04-12 12:14   ` Lars Pedersen
  2021-04-10 10:35 ` [PATCH 5/5] watchdog: add GPIO watchdog driver Ahmad Fatoum
  2021-04-13  6:12 ` [PATCH 1/5] gpiolib: add Linux-like gpiod_get() helper Sascha Hauer
  4 siblings, 1 reply; 7+ messages in thread
From: Ahmad Fatoum @ 2021-04-10 10:35 UTC (permalink / raw)
  To: barebox; +Cc: Ahmad Fatoum

This is a straight port from Linux v5.11.

Signed-off-by: Ahmad Fatoum <ahmad@a3f.at>
---
 drivers/power/reset/Kconfig        |  8 +++
 drivers/power/reset/Makefile       |  1 +
 drivers/power/reset/gpio-restart.c | 99 ++++++++++++++++++++++++++++++
 3 files changed, 108 insertions(+)
 create mode 100644 drivers/power/reset/gpio-restart.c

diff --git a/drivers/power/reset/Kconfig b/drivers/power/reset/Kconfig
index cadcc0b13f2f..dec1482ccd0c 100644
--- a/drivers/power/reset/Kconfig
+++ b/drivers/power/reset/Kconfig
@@ -36,3 +36,11 @@ config POWER_RESET_GPIO
 	  This driver supports turning off your board via a GPIO line.
 	  If your board needs a GPIO high/low to power down, say Y and
 	  create a binding in your devicetree.
+
+config POWER_RESET_GPIO_RESTART
+	bool "GPIO restart driver"
+	depends on OF_GPIO
+	help
+	  This driver supports restarting your board via a GPIO line.
+	  If your board needs a GPIO high/low to restart, say Y and
+	  create a binding in your devicetree.
diff --git a/drivers/power/reset/Makefile b/drivers/power/reset/Makefile
index 438c85970028..33d29d2d9546 100644
--- a/drivers/power/reset/Makefile
+++ b/drivers/power/reset/Makefile
@@ -4,3 +4,4 @@ obj-$(CONFIG_SYSCON_REBOOT_MODE) += syscon-reboot-mode.o
 obj-$(CONFIG_POWER_RESET_SYSCON) += syscon-reboot.o
 obj-$(CONFIG_POWER_RESET_SYSCON_POWEROFF) += syscon-poweroff.o
 obj-$(CONFIG_POWER_RESET_GPIO) += gpio-poweroff.o
+obj-$(CONFIG_POWER_RESET_GPIO_RESTART) += gpio-restart.o
diff --git a/drivers/power/reset/gpio-restart.c b/drivers/power/reset/gpio-restart.c
new file mode 100644
index 000000000000..72c690a3cf4c
--- /dev/null
+++ b/drivers/power/reset/gpio-restart.c
@@ -0,0 +1,99 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Toggles a GPIO pin to restart a device
+ *
+ * Copyright (C) 2014 Google, Inc.
+ *
+ * Based on the gpio-poweroff driver.
+ */
+#include <common.h>
+#include <driver.h>
+#include <restart.h>
+#include <gpiod.h>
+
+struct gpio_restart {
+	int reset_gpio;
+	struct restart_handler restart_handler;
+	u32 active_delay_ms;
+	u32 inactive_delay_ms;
+	u32 wait_delay_ms;
+};
+
+static void __noreturn gpio_restart_handle(struct restart_handler *this)
+{
+	struct gpio_restart *gpio_restart =
+		container_of(this, struct gpio_restart, restart_handler);
+
+	/* drive it active, also inactive->active edge */
+	gpio_direction_active(gpio_restart->reset_gpio, true);
+	mdelay(gpio_restart->active_delay_ms);
+
+	/* drive inactive, also active->inactive edge */
+	gpio_set_active(gpio_restart->reset_gpio, false);
+	mdelay(gpio_restart->inactive_delay_ms);
+
+	/* drive it active, also inactive->active edge */
+	gpio_set_active(gpio_restart->reset_gpio, true);
+
+	/* give it some time */
+	mdelay(gpio_restart->wait_delay_ms);
+
+	mdelay(1000);
+
+	panic("Unable to restart system\n");
+}
+
+static int gpio_restart_probe(struct device_d *dev)
+{
+	struct device_node *np = dev->device_node;
+	struct gpio_restart *gpio_restart;
+	bool open_source = false;
+	u32 property;
+	int ret;
+
+	gpio_restart = xzalloc(sizeof(*gpio_restart));
+
+	open_source = of_property_read_bool(np, "open-source");
+
+	gpio_restart->reset_gpio = gpiod_get(dev, NULL,
+			open_source ? GPIOD_IN : GPIOD_OUT_LOW);
+	ret = gpio_restart->reset_gpio;
+	if (ret < 0) {
+		if (ret != -EPROBE_DEFER)
+			dev_err(dev, "Could not get reset GPIO\n");
+		return ret;
+	}
+
+	gpio_restart->restart_handler.restart = gpio_restart_handle;
+	gpio_restart->restart_handler.name = "gpio-restart";
+	gpio_restart->restart_handler.priority = 129;
+	gpio_restart->active_delay_ms = 100;
+	gpio_restart->inactive_delay_ms = 100;
+	gpio_restart->wait_delay_ms = 3000;
+
+	ret = of_property_read_u32(dev->device_node, "priority", &property);
+	if (!ret)
+		gpio_restart->restart_handler.priority = property;
+
+	of_property_read_u32(np, "active-delay", &gpio_restart->active_delay_ms);
+	of_property_read_u32(np, "inactive-delay", &gpio_restart->inactive_delay_ms);
+	of_property_read_u32(np, "wait-delay", &gpio_restart->wait_delay_ms);
+
+	return restart_handler_register(&gpio_restart->restart_handler);
+}
+
+static const struct of_device_id of_gpio_restart_match[] = {
+	{ .compatible = "gpio-restart", },
+	{},
+};
+
+static struct driver_d gpio_restart_driver = {
+	.name = "restart-gpio",
+	.of_compatible = of_gpio_restart_match,
+	.probe = gpio_restart_probe,
+};
+device_platform_driver(gpio_restart_driver);
+
+MODULE_AUTHOR("David Riley <davidriley@chromium.org>");
+MODULE_DESCRIPTION("GPIO restart driver");
+MODULE_LICENSE("GPL");
-- 
2.30.0


_______________________________________________
barebox mailing list
barebox@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/barebox


^ permalink raw reply	[flat|nested] 7+ messages in thread

* [PATCH 5/5] watchdog: add GPIO watchdog driver
  2021-04-10 10:35 [PATCH 1/5] gpiolib: add Linux-like gpiod_get() helper Ahmad Fatoum
                   ` (2 preceding siblings ...)
  2021-04-10 10:35 ` [PATCH 4/5] power: reset: add GPIO restart driver Ahmad Fatoum
@ 2021-04-10 10:35 ` Ahmad Fatoum
  2021-04-13  6:12 ` [PATCH 1/5] gpiolib: add Linux-like gpiod_get() helper Sascha Hauer
  4 siblings, 0 replies; 7+ messages in thread
From: Ahmad Fatoum @ 2021-04-10 10:35 UTC (permalink / raw)
  To: barebox; +Cc: Ahmad Fatoum

This is a straight port from Linux v5.11.

Signed-off-by: Ahmad Fatoum <ahmad@a3f.at>
---
 drivers/watchdog/Kconfig    |   7 ++
 drivers/watchdog/Makefile   |   1 +
 drivers/watchdog/gpio_wdt.c | 142 ++++++++++++++++++++++++++++++++++++
 3 files changed, 150 insertions(+)
 create mode 100644 drivers/watchdog/gpio_wdt.c

diff --git a/drivers/watchdog/Kconfig b/drivers/watchdog/Kconfig
index 8750a97d8c50..fb4ea7ffac3c 100644
--- a/drivers/watchdog/Kconfig
+++ b/drivers/watchdog/Kconfig
@@ -117,6 +117,13 @@ config F71808E_WDT
 	  F71862FG, F71868, F71869, F71882FG, F71889FG, F81865 and F81866
 	  Super I/O controllers.
 
+config GPIO_WATCHDOG
+	tristate "Watchdog device controlled through GPIO-line"
+	depends on OF_GPIO
+	help
+	  If you say yes here you get support for watchdog device
+	  controlled through GPIO-line.
+
 config ITCO_WDT
 	bool "Intel TCO Timer/Watchdog"
 	depends on X86
diff --git a/drivers/watchdog/Makefile b/drivers/watchdog/Makefile
index b55c58cf3cb3..9edb73512903 100644
--- a/drivers/watchdog/Makefile
+++ b/drivers/watchdog/Makefile
@@ -17,3 +17,4 @@ obj-$(CONFIG_STM32_IWDG_WATCHDOG) += stm32_iwdg.o
 obj-$(CONFIG_STPMIC1_WATCHDOG) += stpmic1_wdt.o
 obj-$(CONFIG_F71808E_WDT) += f71808e_wdt.o
 obj-$(CONFIG_ITCO_WDT) += itco_wdt.o
+obj-$(CONFIG_GPIO_WATCHDOG)	+= gpio_wdt.o
diff --git a/drivers/watchdog/gpio_wdt.c b/drivers/watchdog/gpio_wdt.c
new file mode 100644
index 000000000000..4de49dcee38a
--- /dev/null
+++ b/drivers/watchdog/gpio_wdt.c
@@ -0,0 +1,142 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Driver for watchdog device controlled through GPIO-line
+ *
+ * Author: 2013, Alexander Shiyan <shc_work@mail.ru>
+ */
+
+#include <common.h>
+#include <driver.h>
+#include <watchdog.h>
+#include <superio.h>
+#include <gpiod.h>
+
+enum {
+	HW_ALGO_TOGGLE,
+	HW_ALGO_LEVEL,
+};
+
+struct gpio_wdt_priv {
+	int		gpio;
+	bool		state;
+	bool		started;
+	unsigned int	hw_algo;
+	struct watchdog	wdd;
+};
+
+static inline struct gpio_wdt_priv *to_gpio_wdt_priv(struct watchdog *wdd)
+{
+	return container_of(wdd, struct gpio_wdt_priv, wdd);
+}
+
+static void gpio_wdt_disable(struct gpio_wdt_priv *priv)
+{
+	/* Eternal ping */
+	gpio_set_active(priv->gpio, 1);
+
+	/* Put GPIO back to tristate */
+	if (priv->hw_algo == HW_ALGO_TOGGLE)
+		gpio_direction_input(priv->gpio);
+
+	priv->started = false;
+}
+
+static void gpio_wdt_ping(struct gpio_wdt_priv *priv)
+{
+	switch (priv->hw_algo) {
+	case HW_ALGO_TOGGLE:
+		/* Toggle output pin */
+		priv->state = !priv->state;
+		gpio_set_active(priv->gpio, priv->state);
+		break;
+	case HW_ALGO_LEVEL:
+		/* Pulse */
+		gpio_set_active(priv->gpio, true);
+		udelay(1);
+		gpio_set_active(priv->gpio, false);
+		break;
+	}
+}
+
+static void gpio_wdt_start(struct gpio_wdt_priv *priv)
+{
+	priv->state = false;
+	gpio_direction_active(priv->gpio, priv->state);
+	priv->started = true;
+}
+
+static int gpio_wdt_set_timeout(struct watchdog *wdd, unsigned int new_timeout)
+{
+	struct gpio_wdt_priv *priv = to_gpio_wdt_priv(wdd);
+
+	if (!new_timeout) {
+		gpio_wdt_disable(priv);
+		return 0;
+	}
+
+	if (!priv->started)
+		gpio_wdt_start(priv);
+
+	gpio_wdt_ping(priv);
+	return 0;
+}
+
+static int gpio_wdt_probe(struct device_d *dev)
+{
+	struct device_node *np = dev->device_node;
+	struct gpio_wdt_priv *priv;
+	enum gpiod_flags gflags;
+	unsigned int hw_margin;
+	const char *algo;
+	int ret;
+
+	priv = xzalloc(sizeof(*priv));
+
+	ret = of_property_read_u32(np, "hw_margin_ms", &hw_margin);
+	if (ret)
+		return ret;
+
+	/* Autoping is fixed at one ping every 500 ms. Round it up to a second */
+	if (hw_margin < 1000)
+		return -EINVAL;
+
+	ret = of_property_read_string(np, "hw_algo", &algo);
+	if (ret)
+		return ret;
+	if (!strcmp(algo, "toggle")) {
+		priv->hw_algo = HW_ALGO_TOGGLE;
+		gflags = GPIOD_IN;
+	} else if (!strcmp(algo, "level")) {
+		priv->hw_algo = HW_ALGO_LEVEL;
+		gflags = GPIOD_OUT_LOW;
+	} else {
+		return -EINVAL;
+	}
+
+	priv->gpio = gpiod_get(dev, NULL, gflags);
+	if (priv->gpio < 0)
+		return priv->gpio;
+
+	priv->wdd.hwdev		= dev;
+	priv->wdd.timeout_max	= hw_margin / 1000;
+	priv->wdd.priority	= 129;
+	priv->wdd.set_timeout	= gpio_wdt_set_timeout;
+
+	return watchdog_register(&priv->wdd);
+}
+
+static const struct of_device_id gpio_wdt_dt_ids[] = {
+	{ .compatible = "linux,wdt-gpio", },
+	{ }
+};
+
+static struct driver_d gpio_wdt_driver = {
+	.name		= "gpio-wdt",
+	.of_compatible	= gpio_wdt_dt_ids,
+	.probe	= gpio_wdt_probe,
+};
+device_platform_driver(gpio_wdt_driver);
+
+MODULE_AUTHOR("Alexander Shiyan <shc_work@mail.ru>");
+MODULE_DESCRIPTION("GPIO Watchdog");
+MODULE_LICENSE("GPL");
-- 
2.30.0


_______________________________________________
barebox mailing list
barebox@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/barebox


^ permalink raw reply	[flat|nested] 7+ messages in thread

* Re: [PATCH 4/5] power: reset: add GPIO restart driver
  2021-04-10 10:35 ` [PATCH 4/5] power: reset: add GPIO restart driver Ahmad Fatoum
@ 2021-04-12 12:14   ` Lars Pedersen
  0 siblings, 0 replies; 7+ messages in thread
From: Lars Pedersen @ 2021-04-12 12:14 UTC (permalink / raw)
  To: Ahmad Fatoum; +Cc: barebox

On Sat, 10 Apr 2021 at 12:37, Ahmad Fatoum <ahmad@a3f.at> wrote:
>
> This is a straight port from Linux v5.11.
>
> Signed-off-by: Ahmad Fatoum <ahmad@a3f.at>
Tested-by: Lars Pedersen <lapeddk@gmail.com>

Tested on imx7-tqma7 platform.

> ---
>  drivers/power/reset/Kconfig        |  8 +++
>  drivers/power/reset/Makefile       |  1 +
>  drivers/power/reset/gpio-restart.c | 99 ++++++++++++++++++++++++++++++
>  3 files changed, 108 insertions(+)
>  create mode 100644 drivers/power/reset/gpio-restart.c
>
> diff --git a/drivers/power/reset/Kconfig b/drivers/power/reset/Kconfig
> index cadcc0b13f2f..dec1482ccd0c 100644
> --- a/drivers/power/reset/Kconfig
> +++ b/drivers/power/reset/Kconfig
> @@ -36,3 +36,11 @@ config POWER_RESET_GPIO
>           This driver supports turning off your board via a GPIO line.
>           If your board needs a GPIO high/low to power down, say Y and
>           create a binding in your devicetree.
> +
> +config POWER_RESET_GPIO_RESTART
> +       bool "GPIO restart driver"
> +       depends on OF_GPIO
> +       help
> +         This driver supports restarting your board via a GPIO line.
> +         If your board needs a GPIO high/low to restart, say Y and
> +         create a binding in your devicetree.
> diff --git a/drivers/power/reset/Makefile b/drivers/power/reset/Makefile
> index 438c85970028..33d29d2d9546 100644
> --- a/drivers/power/reset/Makefile
> +++ b/drivers/power/reset/Makefile
> @@ -4,3 +4,4 @@ obj-$(CONFIG_SYSCON_REBOOT_MODE) += syscon-reboot-mode.o
>  obj-$(CONFIG_POWER_RESET_SYSCON) += syscon-reboot.o
>  obj-$(CONFIG_POWER_RESET_SYSCON_POWEROFF) += syscon-poweroff.o
>  obj-$(CONFIG_POWER_RESET_GPIO) += gpio-poweroff.o
> +obj-$(CONFIG_POWER_RESET_GPIO_RESTART) += gpio-restart.o
> diff --git a/drivers/power/reset/gpio-restart.c b/drivers/power/reset/gpio-restart.c
> new file mode 100644
> index 000000000000..72c690a3cf4c
> --- /dev/null
> +++ b/drivers/power/reset/gpio-restart.c
> @@ -0,0 +1,99 @@
> +// SPDX-License-Identifier: GPL-2.0-only
> +/*
> + * Toggles a GPIO pin to restart a device
> + *
> + * Copyright (C) 2014 Google, Inc.
> + *
> + * Based on the gpio-poweroff driver.
> + */
> +#include <common.h>
> +#include <driver.h>
> +#include <restart.h>
> +#include <gpiod.h>
> +
> +struct gpio_restart {
> +       int reset_gpio;
> +       struct restart_handler restart_handler;
> +       u32 active_delay_ms;
> +       u32 inactive_delay_ms;
> +       u32 wait_delay_ms;
> +};
> +
> +static void __noreturn gpio_restart_handle(struct restart_handler *this)
> +{
> +       struct gpio_restart *gpio_restart =
> +               container_of(this, struct gpio_restart, restart_handler);
> +
> +       /* drive it active, also inactive->active edge */
> +       gpio_direction_active(gpio_restart->reset_gpio, true);
> +       mdelay(gpio_restart->active_delay_ms);
> +
> +       /* drive inactive, also active->inactive edge */
> +       gpio_set_active(gpio_restart->reset_gpio, false);
> +       mdelay(gpio_restart->inactive_delay_ms);
> +
> +       /* drive it active, also inactive->active edge */
> +       gpio_set_active(gpio_restart->reset_gpio, true);
> +
> +       /* give it some time */
> +       mdelay(gpio_restart->wait_delay_ms);
> +
> +       mdelay(1000);
> +
> +       panic("Unable to restart system\n");
> +}
> +
> +static int gpio_restart_probe(struct device_d *dev)
> +{
> +       struct device_node *np = dev->device_node;
> +       struct gpio_restart *gpio_restart;
> +       bool open_source = false;
> +       u32 property;
> +       int ret;
> +
> +       gpio_restart = xzalloc(sizeof(*gpio_restart));
> +
> +       open_source = of_property_read_bool(np, "open-source");
> +
> +       gpio_restart->reset_gpio = gpiod_get(dev, NULL,
> +                       open_source ? GPIOD_IN : GPIOD_OUT_LOW);
> +       ret = gpio_restart->reset_gpio;
> +       if (ret < 0) {
> +               if (ret != -EPROBE_DEFER)
> +                       dev_err(dev, "Could not get reset GPIO\n");
> +               return ret;
> +       }
> +
> +       gpio_restart->restart_handler.restart = gpio_restart_handle;
> +       gpio_restart->restart_handler.name = "gpio-restart";
> +       gpio_restart->restart_handler.priority = 129;
> +       gpio_restart->active_delay_ms = 100;
> +       gpio_restart->inactive_delay_ms = 100;
> +       gpio_restart->wait_delay_ms = 3000;
> +
> +       ret = of_property_read_u32(dev->device_node, "priority", &property);
> +       if (!ret)
> +               gpio_restart->restart_handler.priority = property;
> +
> +       of_property_read_u32(np, "active-delay", &gpio_restart->active_delay_ms);
> +       of_property_read_u32(np, "inactive-delay", &gpio_restart->inactive_delay_ms);
> +       of_property_read_u32(np, "wait-delay", &gpio_restart->wait_delay_ms);
> +
> +       return restart_handler_register(&gpio_restart->restart_handler);
> +}
> +
> +static const struct of_device_id of_gpio_restart_match[] = {
> +       { .compatible = "gpio-restart", },
> +       {},
> +};
> +
> +static struct driver_d gpio_restart_driver = {
> +       .name = "restart-gpio",
> +       .of_compatible = of_gpio_restart_match,
> +       .probe = gpio_restart_probe,
> +};
> +device_platform_driver(gpio_restart_driver);
> +
> +MODULE_AUTHOR("David Riley <davidriley@chromium.org>");
> +MODULE_DESCRIPTION("GPIO restart driver");
> +MODULE_LICENSE("GPL");
> --
> 2.30.0
>
>
> _______________________________________________
> barebox mailing list
> barebox@lists.infradead.org
> http://lists.infradead.org/mailman/listinfo/barebox

_______________________________________________
barebox mailing list
barebox@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/barebox


^ permalink raw reply	[flat|nested] 7+ messages in thread

* Re: [PATCH 1/5] gpiolib: add Linux-like gpiod_get() helper
  2021-04-10 10:35 [PATCH 1/5] gpiolib: add Linux-like gpiod_get() helper Ahmad Fatoum
                   ` (3 preceding siblings ...)
  2021-04-10 10:35 ` [PATCH 5/5] watchdog: add GPIO watchdog driver Ahmad Fatoum
@ 2021-04-13  6:12 ` Sascha Hauer
  4 siblings, 0 replies; 7+ messages in thread
From: Sascha Hauer @ 2021-04-13  6:12 UTC (permalink / raw)
  To: Ahmad Fatoum; +Cc: barebox

On Sat, Apr 10, 2021 at 12:35:07PM +0200, Ahmad Fatoum wrote:
> Many Linux drivers use [devm_]gpiod_get to get appropriately configured
> GPIO descriptors out with little code. Make porting such Linux code
> easier by providing a semi-compatible gpiod_get function. Main
> differences:
> 
>  - It returns a gpio index, so it can be passed to any gpio_ function
>  - It's device-tree only, so it should only be used from drivers
>    that themselves probe from device tree.
> 
> Signed-off-by: Ahmad Fatoum <ahmad@a3f.at>
> ---
>  drivers/gpio/gpiolib.c | 43 ++++++++++++++++++++++++++++++++++++++++++
>  include/gpiod.h        | 26 +++++++++++++++++++++++++
>  2 files changed, 69 insertions(+)
>  create mode 100644 include/gpiod.h

Applied, thanks

Sascha

> 
> diff --git a/drivers/gpio/gpiolib.c b/drivers/gpio/gpiolib.c
> index 6088cadd8a18..7b7261d01f24 100644
> --- a/drivers/gpio/gpiolib.c
> +++ b/drivers/gpio/gpiolib.c
> @@ -6,6 +6,7 @@
>  #include <complete.h>
>  #include <gpio.h>
>  #include <of_gpio.h>
> +#include <gpiod.h>
>  #include <errno.h>
>  #include <malloc.h>
>  
> @@ -554,6 +555,48 @@ static int of_gpiochip_scan_hogs(struct gpio_chip *chip)
>  	return 0;
>  }
>  
> +/* Linux compatibility helper: Get a GPIO descriptor from device tree */
> +int gpiod_get(struct device_d *dev, const char *_con_id, enum gpiod_flags flags)
> +{
> +	struct device_node *np = dev->device_node;
> +	enum of_gpio_flags of_flags;
> +	const char *con_id = "gpios", *label = dev_name(dev);
> +	char *buf = NULL;
> +	int gpio;
> +	int ret;
> +
> +	if (!IS_ENABLED(CONFIG_OFDEVICE) || !dev->device_node)
> +		return -ENODEV;
> +
> +	if (_con_id) {
> +		con_id = buf = basprintf("%s-gpios", _con_id);
> +		if (!buf)
> +			return -ENOMEM;
> +	}
> +
> +	gpio = of_get_named_gpio_flags(np, con_id, 0, &of_flags);
> +	free(buf);
> +
> +	if (!gpio_is_valid(gpio))
> +		return gpio < 0 ? gpio : -EINVAL;
> +
> +	if (of_flags & OF_GPIO_ACTIVE_LOW)
> +		flags |= GPIOF_ACTIVE_LOW;
> +
> +	buf = NULL;
> +
> +	if (_con_id) {
> +		label = buf = basprintf("%s-%s", dev_name(dev), _con_id);
> +		if (!label)
> +			return -ENOMEM;
> +	}
> +
> +	ret = gpio_request_one(gpio, flags, label);
> +	free(buf);
> +
> +	return ret ?: gpio;
> +}
> +
>  int gpiochip_add(struct gpio_chip *chip)
>  {
>  	int base, i;
> diff --git a/include/gpiod.h b/include/gpiod.h
> new file mode 100644
> index 000000000000..c8b2cd47a3cb
> --- /dev/null
> +++ b/include/gpiod.h
> @@ -0,0 +1,26 @@
> +/* SPDX-License-Identifier: GPL-2.0 */
> +#ifndef __GPIOD_H_
> +#define __GPIOD_H_
> +
> +#include <gpio.h>
> +#include <of_gpio.h>
> +
> +/**
> + * Optional flags that can be passed to one of gpiod_* to configure direction
> + * and output value. These values cannot be OR'd.
> + */
> +enum gpiod_flags {
> +	GPIOD_ASIS	= 0,
> +	GPIOD_IN	= GPIOF_IN,
> +	/*
> +	 * To change this later to a different logic level (i.e. taking
> +	 * active low into account), use gpio_direction_active()
> +	 */
> +	GPIOD_OUT_LOW	= GPIOF_OUT_INIT_INACTIVE,
> +	GPIOD_OUT_HIGH	= GPIOF_OUT_INIT_ACTIVE,
> +};
> +
> +/* returned gpio descriptor can be passed to any normal gpio_* function */
> +int gpiod_get(struct device_d *dev, const char *_con_id, enum gpiod_flags flags);
> +
> +#endif
> -- 
> 2.30.0
> 
> 
> _______________________________________________
> barebox mailing list
> barebox@lists.infradead.org
> http://lists.infradead.org/mailman/listinfo/barebox
> 

-- 
Pengutronix e.K.                           |                             |
Steuerwalder Str. 21                       | http://www.pengutronix.de/  |
31137 Hildesheim, Germany                  | Phone: +49-5121-206917-0    |
Amtsgericht Hildesheim, HRA 2686           | Fax:   +49-5121-206917-5555 |

_______________________________________________
barebox mailing list
barebox@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/barebox


^ permalink raw reply	[flat|nested] 7+ messages in thread

end of thread, other threads:[~2021-04-13  6:16 UTC | newest]

Thread overview: 7+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2021-04-10 10:35 [PATCH 1/5] gpiolib: add Linux-like gpiod_get() helper Ahmad Fatoum
2021-04-10 10:35 ` [PATCH 2/5] sound: gpio-beeper: simplify using new gpiod_get helper Ahmad Fatoum
2021-04-10 10:35 ` [PATCH 3/5] power: reset: add GPIO poweroff driver Ahmad Fatoum
2021-04-10 10:35 ` [PATCH 4/5] power: reset: add GPIO restart driver Ahmad Fatoum
2021-04-12 12:14   ` Lars Pedersen
2021-04-10 10:35 ` [PATCH 5/5] watchdog: add GPIO watchdog driver Ahmad Fatoum
2021-04-13  6:12 ` [PATCH 1/5] gpiolib: add Linux-like gpiod_get() helper Sascha Hauer

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox