mail archive of the barebox mailing list
 help / color / mirror / Atom feed
* [PATCH 0/4] gpio: Add gpio latch driver
@ 2022-11-07 14:45 Sascha Hauer
  2022-11-07 14:45 ` [PATCH 1/4] bitmap: Implement bitmap_*zalloc() Sascha Hauer
                   ` (3 more replies)
  0 siblings, 4 replies; 5+ messages in thread
From: Sascha Hauer @ 2022-11-07 14:45 UTC (permalink / raw)
  To: Barebox List

This adds a gpio-latch driver recently added to Linux, see
https://lore.kernel.org/lkml/20221007114647.2723457-2-s.hauer@pengutronix.de/T/

This is basically the same driver adjusted for barebox. As a preparation
we have to add some bitmap helpers needed for the driver.

Sascha Hauer (4):
  bitmap: Implement bitmap_*zalloc()
  bitops: include linux/types.h
  bitops: implement assign_bit()
  gpio: Add gpio latch driver

 drivers/gpio/Kconfig      |   6 ++
 drivers/gpio/Makefile     |   1 +
 drivers/gpio/gpio-latch.c | 195 ++++++++++++++++++++++++++++++++++++++
 include/linux/bitmap.h    |   7 ++
 include/linux/bitops.h    |  16 +++-
 lib/bitmap.c              |  10 ++
 6 files changed, 234 insertions(+), 1 deletion(-)
 create mode 100644 drivers/gpio/gpio-latch.c

-- 
2.30.2




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

* [PATCH 1/4] bitmap: Implement bitmap_*zalloc()
  2022-11-07 14:45 [PATCH 0/4] gpio: Add gpio latch driver Sascha Hauer
@ 2022-11-07 14:45 ` Sascha Hauer
  2022-11-07 14:45 ` [PATCH 2/4] bitops: include linux/types.h Sascha Hauer
                   ` (2 subsequent siblings)
  3 siblings, 0 replies; 5+ messages in thread
From: Sascha Hauer @ 2022-11-07 14:45 UTC (permalink / raw)
  To: Barebox List

Implement functions for allocating a bitmap.

Signed-off-by: Sascha Hauer <s.hauer@pengutronix.de>
---
 include/linux/bitmap.h |  7 +++++++
 lib/bitmap.c           | 10 ++++++++++
 2 files changed, 17 insertions(+)

diff --git a/include/linux/bitmap.h b/include/linux/bitmap.h
index adaf5428fe..7d06fac68d 100644
--- a/include/linux/bitmap.h
+++ b/include/linux/bitmap.h
@@ -80,6 +80,13 @@
  * contain all bit positions from 0 to 'bits' - 1.
  */
 
+/*
+ * Allocation and deallocation of bitmap.
+ * Provided in lib/bitmap.c to avoid circular dependency.
+ */
+unsigned long *bitmap_zalloc(unsigned int nbits);
+unsigned long *bitmap_xzalloc(unsigned int nbits);
+
 /*
  * lib/bitmap.c provides these functions:
  */
diff --git a/lib/bitmap.c b/lib/bitmap.c
index 5be6651941..dfc0f06b13 100644
--- a/lib/bitmap.c
+++ b/lib/bitmap.c
@@ -837,3 +837,13 @@ void bitmap_copy_le(void *dst, const unsigned long *src, int nbits)
 	}
 }
 EXPORT_SYMBOL(bitmap_copy_le);
+
+unsigned long *bitmap_zalloc(unsigned int nbits)
+{
+	return calloc(BITS_TO_LONGS(nbits), sizeof(unsigned long));
+}
+
+unsigned long *bitmap_xzalloc(unsigned int nbits)
+{
+	return xzalloc(BITS_TO_LONGS(nbits) * sizeof(unsigned long));
+}
-- 
2.30.2




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

* [PATCH 2/4] bitops: include linux/types.h
  2022-11-07 14:45 [PATCH 0/4] gpio: Add gpio latch driver Sascha Hauer
  2022-11-07 14:45 ` [PATCH 1/4] bitmap: Implement bitmap_*zalloc() Sascha Hauer
@ 2022-11-07 14:45 ` Sascha Hauer
  2022-11-07 14:45 ` [PATCH 3/4] bitops: implement assign_bit() Sascha Hauer
  2022-11-07 14:45 ` [PATCH 4/4] gpio: Add gpio latch driver Sascha Hauer
  3 siblings, 0 replies; 5+ messages in thread
From: Sascha Hauer @ 2022-11-07 14:45 UTC (permalink / raw)
  To: Barebox List

linux/types.h includes asm/types.h. linux/types.h declares 'bool' we
need in the next patch, so include the former rather than the latter.

Signed-off-by: Sascha Hauer <s.hauer@pengutronix.de>
---
 include/linux/bitops.h | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/include/linux/bitops.h b/include/linux/bitops.h
index 645fd2e6f6..84161e43a3 100644
--- a/include/linux/bitops.h
+++ b/include/linux/bitops.h
@@ -2,7 +2,7 @@
 
 #ifndef _LINUX_BITOPS_H
 #define _LINUX_BITOPS_H
-#include <asm/types.h>
+#include <linux/types.h>
 
 #ifdef	__KERNEL__
 #define BIT(nr)			(1UL << (nr))
-- 
2.30.2




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

* [PATCH 3/4] bitops: implement assign_bit()
  2022-11-07 14:45 [PATCH 0/4] gpio: Add gpio latch driver Sascha Hauer
  2022-11-07 14:45 ` [PATCH 1/4] bitmap: Implement bitmap_*zalloc() Sascha Hauer
  2022-11-07 14:45 ` [PATCH 2/4] bitops: include linux/types.h Sascha Hauer
@ 2022-11-07 14:45 ` Sascha Hauer
  2022-11-07 14:45 ` [PATCH 4/4] gpio: Add gpio latch driver Sascha Hauer
  3 siblings, 0 replies; 5+ messages in thread
From: Sascha Hauer @ 2022-11-07 14:45 UTC (permalink / raw)
  To: Barebox List

assign_bit() is a useful shortcut to if (foo) set_bit(); else clear_bit();

Signed-off-by: Sascha Hauer <s.hauer@pengutronix.de>
---
 include/linux/bitops.h | 14 ++++++++++++++
 1 file changed, 14 insertions(+)

diff --git a/include/linux/bitops.h b/include/linux/bitops.h
index 84161e43a3..eb5ff37f2f 100644
--- a/include/linux/bitops.h
+++ b/include/linux/bitops.h
@@ -194,6 +194,20 @@ static inline unsigned long __ffs64(u64 word)
 	return __ffs((unsigned long)word);
 }
 
+/**
+ * assign_bit - Assign value to a bit in memory
+ * @nr: the bit to set
+ * @addr: the address to start counting from
+ * @value: the value to assign
+ */
+static inline void assign_bit(long nr, volatile unsigned long *addr, bool value)
+{
+	if (value)
+		set_bit(nr, addr);
+	else
+		clear_bit(nr, addr);
+}
+
 #ifdef __KERNEL__
 
 #ifndef set_mask_bits
-- 
2.30.2




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

* [PATCH 4/4] gpio: Add gpio latch driver
  2022-11-07 14:45 [PATCH 0/4] gpio: Add gpio latch driver Sascha Hauer
                   ` (2 preceding siblings ...)
  2022-11-07 14:45 ` [PATCH 3/4] bitops: implement assign_bit() Sascha Hauer
@ 2022-11-07 14:45 ` Sascha Hauer
  3 siblings, 0 replies; 5+ messages in thread
From: Sascha Hauer @ 2022-11-07 14:45 UTC (permalink / raw)
  To: Barebox List

This driver implements a GPIO multiplexer based on latches connected to
other GPIOs. A set of data GPIOs is connected to the data input of
multiple latches. The clock input of each latch is driven by another
set of GPIOs. With two 8-bit latches 10 GPIOs can be multiplexed into
16 GPIOs. GPOs might be a better term as in fact the multiplexed pins
are output only.

Signed-off-by: Sascha Hauer <s.hauer@pengutronix.de>
---
 drivers/gpio/Kconfig      |   6 ++
 drivers/gpio/Makefile     |   1 +
 drivers/gpio/gpio-latch.c | 195 ++++++++++++++++++++++++++++++++++++++
 3 files changed, 202 insertions(+)
 create mode 100644 drivers/gpio/gpio-latch.c

diff --git a/drivers/gpio/Kconfig b/drivers/gpio/Kconfig
index ab75fe4ed9..dd2b56d256 100644
--- a/drivers/gpio/Kconfig
+++ b/drivers/gpio/Kconfig
@@ -205,6 +205,12 @@ config GPIO_ZYNQ
 	help
 	  Say yes here to support Xilinx Zynq GPIO controller.
 
+config GPIO_LATCH
+	tristate "GPIO latch driver"
+	help
+	  Say yes here to enable a driver for GPIO multiplexers based on latches
+	  connected to other GPIOs.
+
 endmenu
 
 endif
diff --git a/drivers/gpio/Makefile b/drivers/gpio/Makefile
index fcb6a232e0..90ab0a8b28 100644
--- a/drivers/gpio/Makefile
+++ b/drivers/gpio/Makefile
@@ -28,3 +28,4 @@ obj-$(CONFIG_GPIO_RASPBERRYPI_EXP) += gpio-raspberrypi-exp.o
 obj-$(CONFIG_GPIO_SIFIVE)	+= gpio-sifive.o
 obj-$(CONFIG_GPIO_STARFIVE)	+= gpio-starfive-vic.o
 obj-$(CONFIG_GPIO_ZYNQ)		+= gpio-zynq.o
+obj-$(CONFIG_GPIO_LATCH)	+= gpio-latch.o
diff --git a/drivers/gpio/gpio-latch.c b/drivers/gpio/gpio-latch.c
new file mode 100644
index 0000000000..2a89f22401
--- /dev/null
+++ b/drivers/gpio/gpio-latch.c
@@ -0,0 +1,195 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * GPIO latch driver
+ *
+ *  Copyright (C) 2022 Sascha Hauer <s.hauer@pengutronix.de>
+ *
+ * This driver implements a GPIO (or better GPO as there is no input)
+ * multiplexer based on latches like this:
+ *
+ * CLK0 ----------------------.        ,--------.
+ * CLK1 -------------------.  `--------|>    #0 |
+ *                         |           |        |
+ * OUT0 ----------------+--|-----------|D0    Q0|-----|<
+ * OUT1 --------------+-|--|-----------|D1    Q1|-----|<
+ * OUT2 ------------+-|-|--|-----------|D2    Q2|-----|<
+ * OUT3 ----------+-|-|-|--|-----------|D3    Q3|-----|<
+ * OUT4 --------+-|-|-|-|--|-----------|D4    Q4|-----|<
+ * OUT5 ------+-|-|-|-|-|--|-----------|D5    Q5|-----|<
+ * OUT6 ----+-|-|-|-|-|-|--|-----------|D6    Q6|-----|<
+ * OUT7 --+-|-|-|-|-|-|-|--|-----------|D7    Q7|-----|<
+ *        | | | | | | | |  |           `--------'
+ *        | | | | | | | |  |
+ *        | | | | | | | |  |           ,--------.
+ *        | | | | | | | |  `-----------|>    #1 |
+ *        | | | | | | | |              |        |
+ *        | | | | | | | `--------------|D0    Q0|-----|<
+ *        | | | | | | `----------------|D1    Q1|-----|<
+ *        | | | | | `------------------|D2    Q2|-----|<
+ *        | | | | `--------------------|D3    Q3|-----|<
+ *        | | | `----------------------|D4    Q4|-----|<
+ *        | | `------------------------|D5    Q5|-----|<
+ *        | `--------------------------|D6    Q6|-----|<
+ *        `----------------------------|D7    Q7|-----|<
+ *                                     `--------'
+ *
+ * The above is just an example. The actual number of number of latches and
+ * the number of inputs per latch is derived from the number of GPIOs given
+ * in the corresponding device tree properties.
+ */
+
+#include <common.h>
+#include <errno.h>
+#include <io.h>
+#include <of.h>
+#include <gpio.h>
+#include <init.h>
+#include <of_gpio.h>
+#include <linux/bitmap.h>
+
+struct gpio_latch_priv {
+	struct gpio_chip gc;
+	int *clk_gpios;
+	int *latched_gpios;
+	int n_latched_gpios;
+	unsigned int setup_duration_ns;
+	unsigned int clock_duration_ns;
+	unsigned long *shadow;
+};
+
+static int gpio_latch_get_direction(struct gpio_chip *gc, unsigned int offset)
+{
+	return 0;
+}
+
+static void gpio_latch_set(struct gpio_chip *gc, unsigned int offset, int val)
+{
+	struct gpio_latch_priv *priv = container_of(gc, struct gpio_latch_priv, gc);
+	int latch = offset / priv->n_latched_gpios;
+	int i;
+
+	assign_bit(offset, priv->shadow, val);
+
+	for (i = 0; i < priv->n_latched_gpios; i++)
+		gpio_set_value(priv->latched_gpios[i],
+			       test_bit(latch * priv->n_latched_gpios + i, priv->shadow));
+
+	ndelay(priv->setup_duration_ns);
+	gpio_set_value(priv->clk_gpios[latch], 1);
+	ndelay(priv->clock_duration_ns);
+	gpio_set_value(priv->clk_gpios[latch], 0);
+}
+static int gpio_latch_direction_output(struct gpio_chip *gc, unsigned gpio, int val)
+{
+	gpio_latch_set(gc, gpio, val);
+
+	return 0;
+}
+
+#define DURATION_NS_MAX 5000
+
+static struct gpio_ops gpio_latch_gpio_ops = {
+	.direction_output = gpio_latch_direction_output,
+	.set = gpio_latch_set,
+	.get_direction = gpio_latch_get_direction,
+};
+
+static int gpio_latch_probe(struct device_d *dev)
+{
+	struct gpio_latch_priv *priv;
+	int n_latches, i, ret;
+	struct device_node *np = dev->device_node;
+	enum of_gpio_flags flags;
+
+	priv = xzalloc(sizeof(*priv));
+
+	n_latches = of_gpio_named_count(np, "clk-gpios");
+	if (n_latches < 0) {
+		dev_err(dev, "invalid or missing clk-gpios");
+		ret = -EINVAL;
+		goto err_gpio;
+	}
+
+	priv->n_latched_gpios = of_gpio_named_count(np, "latched-gpios");
+	if (priv->n_latched_gpios < 0) {
+		dev_err(dev, "invalid or missing latched-gpios");
+		ret = -EINVAL;
+		goto err_gpio;
+	}
+
+	priv->clk_gpios = xzalloc(sizeof(int) * n_latches);
+	priv->latched_gpios = xzalloc(sizeof(int) * priv->n_latched_gpios);
+
+	for (i = 0; i < n_latches; i++) {
+		priv->clk_gpios[i] = of_get_named_gpio_flags(np, "clk-gpios",
+								i, &flags);
+		ret = gpio_request_one(priv->clk_gpios[i],
+				       flags & OF_GPIO_ACTIVE_LOW ? GPIOF_ACTIVE_LOW : 0,
+				       dev_name(dev));
+		if (ret) {
+			dev_err(dev, "Cannot request gpio %d: %s\n", priv->clk_gpios[i],
+				strerror(-ret));
+			goto err_gpio;
+		}
+
+		gpio_direction_output(priv->clk_gpios[i], 0);
+	}
+
+	for (i = 0; i < priv->n_latched_gpios; i++) {
+		priv->latched_gpios[i] = of_get_named_gpio_flags(np, "latched-gpios",
+							      i, &flags);
+		ret = gpio_request_one(priv->latched_gpios[i],
+				       flags & OF_GPIO_ACTIVE_LOW ? GPIOF_ACTIVE_LOW : 0,
+				       dev_name(dev));
+		if (ret) {
+			dev_err(dev, "Cannot request gpio %d: %s\n", priv->latched_gpios[i],
+				strerror(-ret));
+			goto err_gpio;
+		}
+	}
+
+	priv->shadow = bitmap_zalloc(n_latches * priv->n_latched_gpios);
+
+	of_property_read_u32(np, "setup-duration-ns", &priv->setup_duration_ns);
+	if (priv->setup_duration_ns > DURATION_NS_MAX) {
+		dev_warn(dev, "setup-duration-ns too high, limit to %d\n",
+			 DURATION_NS_MAX);
+		priv->setup_duration_ns = DURATION_NS_MAX;
+	}
+
+	of_property_read_u32(np, "clock-duration-ns", &priv->clock_duration_ns);
+	if (priv->clock_duration_ns > DURATION_NS_MAX) {
+		dev_warn(dev, "clock-duration-ns too high, limit to %d\n",
+			 DURATION_NS_MAX);
+		priv->clock_duration_ns = DURATION_NS_MAX;
+	}
+
+	priv->gc.ops = &gpio_latch_gpio_ops;
+	priv->gc.ngpio = n_latches * priv->n_latched_gpios;
+	priv->gc.base = -1;
+	priv->gc.dev = dev;
+
+	return gpiochip_add(&priv->gc);
+
+err_gpio:
+	return ret;
+}
+
+static const struct of_device_id gpio_latch_ids[] = {
+	{
+		.compatible	= "gpio-latch",
+	}, {
+		/* sentinel */
+	}
+};
+
+static struct driver_d gpio_latch_driver = {
+	.name = "gpio-latch",
+	.probe = gpio_latch_probe,
+	.of_compatible = DRV_OF_COMPAT(gpio_latch_ids),
+};
+device_platform_driver(gpio_latch_driver);
+
+MODULE_LICENSE("GPL v2");
+MODULE_AUTHOR("Sascha Hauer <s.hauer@pengutronix.de>");
+MODULE_DESCRIPTION("GPIO latch driver");
-- 
2.30.2




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

end of thread, other threads:[~2022-11-07 15:02 UTC | newest]

Thread overview: 5+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2022-11-07 14:45 [PATCH 0/4] gpio: Add gpio latch driver Sascha Hauer
2022-11-07 14:45 ` [PATCH 1/4] bitmap: Implement bitmap_*zalloc() Sascha Hauer
2022-11-07 14:45 ` [PATCH 2/4] bitops: include linux/types.h Sascha Hauer
2022-11-07 14:45 ` [PATCH 3/4] bitops: implement assign_bit() Sascha Hauer
2022-11-07 14:45 ` [PATCH 4/4] gpio: Add gpio latch driver Sascha Hauer

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