All of lore.kernel.org
 help / color / mirror / Atom feed
From: Simon Glass <sjg@chromium.org>
To: u-boot@lists.denx.de
Subject: [PATCH 15/15] gpio: Add a way to read 3-way strapping pins
Date: Fri, 15 Jan 2021 07:05:00 -0700	[thread overview]
Message-ID: <20210115140500.846307-16-sjg@chromium.org> (raw)
In-Reply-To: <20210115140500.846307-1-sjg@chromium.org>

Using the internal vs. external pull resistors it is possible to get
27 different combinations from 3 strapping pins. Add an implementation
of this.

This involves updating the sandbox GPIO driver to model external and
(weaker) internal pull resistors. The get_value() method now takes account
of what is driving a pin:

   sandbox: GPIOD_EXT_DRIVEN - in which case GPIO_EXT_HIGH provides the
          value
   outside source - in which case GPIO_EXT_PULL_UP/DOWN indicates the
          external state and we work the final state using those flags and
          the internal GPIOD_PULL_UP/DOWN flags

Of course the outside source does not really exist in sandbox. We are just
modelling it for test purpose.

Signed-off-by: Simon Glass <sjg@chromium.org>
---

 arch/sandbox/include/asm/gpio.h |  5 +-
 drivers/gpio/gpio-uclass.c      | 78 ++++++++++++++++++++++++++
 drivers/gpio/sandbox.c          | 13 +++--
 include/asm-generic/gpio.h      | 37 +++++++++++++
 test/dm/gpio.c                  | 98 +++++++++++++++++++++++++++++++++
 5 files changed, 226 insertions(+), 5 deletions(-)

diff --git a/arch/sandbox/include/asm/gpio.h b/arch/sandbox/include/asm/gpio.h
index edf78cb4131..097abfb299c 100644
--- a/arch/sandbox/include/asm/gpio.h
+++ b/arch/sandbox/include/asm/gpio.h
@@ -26,8 +26,11 @@
 /* Our own private GPIO flags, which musn't conflict with GPIOD_... */
 #define GPIOD_EXT_HIGH		BIT(20)	/* external source is high (else low) */
 #define GPIOD_EXT_DRIVEN	BIT(21)	/* external source is driven */
+#define GPIOD_EXT_PULL_UP	BIT(22)	/* GPIO has external pull-up */
+#define GPIOD_EXT_PULL_DOWN	BIT(23)	/* GPIO has external pull-down */
 
-#define GPIOD_SANDBOX_MASK	GENMASK(21, 20)
+#define GPIOD_EXT_PULL		(BIT(21) | BIT(22))
+#define GPIOD_SANDBOX_MASK	GENMASK(23, 20)
 
 /**
  * Return the simulated value of a GPIO (used only in sandbox test code)
diff --git a/drivers/gpio/gpio-uclass.c b/drivers/gpio/gpio-uclass.c
index 77b40263bbd..984c07d1dfa 100644
--- a/drivers/gpio/gpio-uclass.c
+++ b/drivers/gpio/gpio-uclass.c
@@ -3,6 +3,8 @@
  * Copyright (c) 2013 Google, Inc
  */
 
+#define LOG_CATEGORY	UCLASS_GPIO
+
 #include <common.h>
 #include <dm.h>
 #include <log.h>
@@ -20,6 +22,7 @@
 #include <dm/device_compat.h>
 #include <linux/bug.h>
 #include <linux/ctype.h>
+#include <linux/delay.h>
 
 DECLARE_GLOBAL_DATA_PTR;
 
@@ -708,6 +711,21 @@ int dm_gpio_set_dir_flags(struct gpio_desc *desc, ulong flags)
 	return dm_gpio_clrset_flags(desc, 0, flags);
 }
 
+int dm_gpios_clrset_flags(struct gpio_desc *desc, int count, ulong clr,
+			  ulong set)
+{
+	int ret;
+	int i;
+
+	for (i = 0; i < count; i++) {
+		ret = dm_gpio_clrset_flags(&desc[i], clr, set);
+		if (ret)
+			return log_ret(ret);
+	}
+
+	return 0;
+}
+
 int dm_gpio_get_flags(struct gpio_desc *desc, ulong *flagsp)
 {
 	struct udevice *dev = desc->dev;
@@ -974,6 +992,66 @@ int dm_gpio_get_values_as_int(const struct gpio_desc *desc_list, int count)
 	return vector;
 }
 
+int dm_gpio_get_values_as_int_base3(struct gpio_desc *desc_list,
+				    int count)
+{
+	static const char tristate[] = "01z";
+	enum {
+		PULLUP,
+		PULLDOWN,
+
+		NUM_OPTIONS,
+	};
+	int vals[NUM_OPTIONS];
+	uint mask;
+	uint vector = 0;
+	int ret, i;
+
+	for (i = 0; i < NUM_OPTIONS; i++) {
+		uint flags = GPIOD_IS_IN;
+
+		flags |= (i == PULLDOWN) ? GPIOD_PULL_DOWN : GPIOD_PULL_UP;
+		ret = dm_gpios_clrset_flags(desc_list, count, GPIOD_MASK_PULL,
+					    flags);
+		if (ret)
+			return log_msg_ret("pu", ret);
+
+		/* Give the lines time to settle */
+		udelay(10);
+
+		ret = dm_gpio_get_values_as_int(desc_list, count);
+		if (ret < 0)
+			return log_msg_ret("get1", ret);
+		vals[i] = ret;
+	}
+
+	log_debug("values: %x %x, count = %d\n", vals[0], vals[1], count);
+	for (i = count - 1, mask = 1 << i; i >= 0; i--, mask >>= 1) {
+		uint pd = vals[PULLDOWN] & mask ? 1 : 0;
+		uint pu = vals[PULLUP] & mask ? 1 : 0;
+		uint digit;
+
+		/*
+		 * Get value with internal pulldown active. If this is 1 then
+		 * there is a stronger external pullup, which we call 1. If not
+		 * then call it 0.
+		 */
+		digit = pd;
+
+		/*
+		 * If the values differ then the pin is floating so we call
+		 * this a 2.
+		 */
+		if (pu != pd)
+			digit |= 2;
+		log_debug("%c ", tristate[digit]);
+		vector = 3 * vector + digit;
+	}
+	log_debug("vector=%d\n", vector);
+
+	return vector;
+}
+
 /**
  * gpio_request_tail: common work for requesting a gpio.
  *
diff --git a/drivers/gpio/sandbox.c b/drivers/gpio/sandbox.c
index b32f7ac529b..56b339f5e3c 100644
--- a/drivers/gpio/sandbox.c
+++ b/drivers/gpio/sandbox.c
@@ -19,7 +19,6 @@
 #include <dt-bindings/gpio/gpio.h>
 #include <dt-bindings/gpio/sandbox-gpio.h>
 
-
 struct gpio_state {
 	const char *label;	/* label given by requester */
 	ulong flags;		/* flags (GPIOD_...) */
@@ -81,10 +80,16 @@ int sandbox_gpio_get_value(struct udevice *dev, unsigned offset)
 	if (get_gpio_flag(dev, offset, GPIOD_IS_OUT))
 		debug("sandbox_gpio: get_value on output gpio %u\n", offset);
 
-	if (state->flags & GPIOD_EXT_DRIVEN)
+	if (state->flags & GPIOD_EXT_DRIVEN) {
 		val = state->flags & GPIOD_EXT_HIGH;
-	else
-		val = false;
+	} else {
+		if (state->flags & GPIOD_EXT_PULL_UP)
+			val = true;
+		else if (state->flags & GPIOD_EXT_PULL_DOWN)
+			val = false;
+		else
+			val = state->flags & GPIOD_PULL_UP;
+	}
 
 	return val;
 }
diff --git a/include/asm-generic/gpio.h b/include/asm-generic/gpio.h
index 4628d937259..1cf81a3fc7a 100644
--- a/include/asm-generic/gpio.h
+++ b/include/asm-generic/gpio.h
@@ -505,6 +505,28 @@ int gpio_get_values_as_int(const int *gpio_list);
  */
 int dm_gpio_get_values_as_int(const struct gpio_desc *desc_list, int count);
 
+/**
+ * dm_gpio_get_values_as_int_base3() - Create a base-3 int from a list of GPIOs
+ *
+ * This uses pull-ups/pull-downs to figure out whether a GPIO line is externally
+ * pulled down, pulled up or floating. This allows three different strap values
+ * for each pin.
+ *
+ * With this it is possible to obtain more combinations from the same number of
+ * strapping pins, when compared to dm_gpio_get_values_as_int(). The external
+ * pull resistors should be made stronger that the internal SoC pull resistors,
+ * for this to work.
+ *
+ * With 2 pins, 6 combinations are possible, compare with 4
+ * With 3 pins, 27 are possible, compared with 8
+ *
+ * @desc_list: List of GPIOs to collect
+ * @count: Number of GPIOs
+ * @return resulting integer value, or -ve on error
+ */
+int dm_gpio_get_values_as_int_base3(struct gpio_desc *desc_list,
+				    int count);
+
 /**
  * gpio_claim_vector() - claim a number of GPIOs for input
  *
@@ -722,6 +744,21 @@ int dm_gpio_clrset_flags(struct gpio_desc *desc, ulong clr, ulong set);
  */
 int dm_gpio_set_dir_flags(struct gpio_desc *desc, ulong flags);
 
+/**
+ * dm_gpios_clrset_flags() - Sets flags for a set of GPIOs
+ *
+ * This clears and sets flags individually for each GPIO.
+ *
+ * @desc:	List of GPIOs to update
+ * @count:	Number of GPIOs in the list
+ * @clr:	Flags to clear (GPIOD_...), e.g. GPIOD_MASK_DIR if you are
+ *		changing the direction
+ * @set:	Flags to set (GPIOD_...)
+ * @return 0 if OK, -ve on error
+ */
+int dm_gpios_clrset_flags(struct gpio_desc *desc, int count, ulong clr,
+			  ulong set);
+
 /**
  * dm_gpio_get_flags() - Get direction flags
  *
diff --git a/test/dm/gpio.c b/test/dm/gpio.c
index eaf78e9aed8..726c1b6c44f 100644
--- a/test/dm/gpio.c
+++ b/test/dm/gpio.c
@@ -673,3 +673,101 @@ static int dm_test_clrset_flags_invert(struct unit_test_state *uts)
 	return 0;
 }
 DM_TEST(dm_test_clrset_flags_invert, UT_TESTF_SCAN_PDATA | UT_TESTF_SCAN_FDT);
+
+static int set_gpios(struct unit_test_state *uts, struct gpio_desc *desc,
+		     int count, uint value)
+{
+	int i;
+
+	for (i = 0; i < count; i++) {
+		const uint mask = 1 << i;
+
+		ut_assertok(sandbox_gpio_set_value(desc[i].dev, desc[i].offset,
+						   value & mask));
+	}
+
+	return 0;
+}
+
+/* Check that an active-low GPIO works as expected */
+static int dm_test_gpio_get_values_as_int(struct unit_test_state *uts)
+{
+	const int gpio_count = 3;
+	struct gpio_desc desc[gpio_count];
+	struct udevice *dev;
+
+	ut_assertok(uclass_get_device(UCLASS_TEST_FDT, 0, &dev));
+	ut_asserteq_str("a-test", dev->name);
+
+	ut_asserteq(3, gpio_request_list_by_name(dev, "test-gpios", desc,
+						 gpio_count, GPIOD_IS_IN));
+	ut_assertok(set_gpios(uts, desc, gpio_count, 0));
+	ut_asserteq(0, dm_gpio_get_values_as_int(desc, gpio_count));
+
+	ut_assertok(set_gpios(uts, desc, gpio_count, 5));
+	ut_asserteq(5, dm_gpio_get_values_as_int(desc, gpio_count));
+
+	ut_assertok(set_gpios(uts, desc, gpio_count, 7));
+	ut_asserteq(7, dm_gpio_get_values_as_int(desc, gpio_count));
+
+	return 0;
+}
+DM_TEST(dm_test_gpio_get_values_as_int,
+	UT_TESTF_SCAN_PDATA | UT_TESTF_SCAN_FDT);
+
+/* Check that an active-low GPIO works as expected */
+static int dm_test_gpio_get_values_as_int_base3(struct unit_test_state *uts)
+{
+	const int gpio_count = 3;
+	struct gpio_desc desc[gpio_count];
+	struct udevice *dev;
+
+	ut_assertok(uclass_get_device(UCLASS_TEST_FDT, 0, &dev));
+	ut_asserteq_str("a-test", dev->name);
+
+	ut_asserteq(3, gpio_request_list_by_name(dev, "test-gpios", desc,
+						 gpio_count, GPIOD_IS_IN));
+
+	/*
+	 * First test the sandbox GPIO driver works as expected. The external
+	 * pull resistor should be stronger than the internal one.
+	 */
+	sandbox_gpio_set_flags(desc[0].dev, desc[0].offset,
+			       GPIOD_IS_IN | GPIOD_EXT_PULL_UP | GPIOD_PULL_UP);
+	ut_asserteq(1, dm_gpio_get_value(desc));
+
+	sandbox_gpio_set_flags(desc[0].dev, desc[0].offset, GPIOD_IS_IN |
+			       GPIOD_EXT_PULL_DOWN | GPIOD_PULL_UP);
+	ut_asserteq(0, dm_gpio_get_value(desc));
+
+	sandbox_gpio_set_flags(desc[0].dev, desc[0].offset,
+			       GPIOD_IS_IN | GPIOD_PULL_UP);
+	ut_asserteq(1, dm_gpio_get_value(desc));
+
+	sandbox_gpio_set_flags(desc[0].dev, desc[0].offset, GPIOD_PULL_DOWN);
+	ut_asserteq(0, dm_gpio_get_value(desc));
+
+	/*
+	 * Set up pins: pull-up (1), pull-down (0) and floating (2). This should
+	 * result in digits 2 0 1, i.e. 2 * 9 + 1 * 3 = 19
+	 */
+	sandbox_gpio_set_flags(desc[0].dev, desc[0].offset, GPIOD_EXT_PULL_UP);
+	sandbox_gpio_set_flags(desc[1].dev, desc[1].offset,
+			       GPIOD_EXT_PULL_DOWN);
+	sandbox_gpio_set_flags(desc[2].dev, desc[2].offset, 0);
+	ut_asserteq(19, dm_gpio_get_values_as_int_base3(desc, gpio_count));
+
+	/*
+	 * Set up pins: floating (2), pull-up (1) and pull-down (0). This should
+	 * result in digits 0 1 2, i.e. 1 * 3 + 2 = 5
+	 */
+	sandbox_gpio_set_flags(desc[0].dev, desc[0].offset, 0);
+	sandbox_gpio_set_flags(desc[1].dev, desc[1].offset, GPIOD_EXT_PULL_UP);
+	sandbox_gpio_set_flags(desc[2].dev, desc[2].offset,
+			       GPIOD_EXT_PULL_DOWN);
+	ut_asserteq(5, dm_gpio_get_values_as_int_base3(desc, gpio_count));
+
+	return 0;
+}
+DM_TEST(dm_test_gpio_get_values_as_int_base3,
+	UT_TESTF_SCAN_PDATA | UT_TESTF_SCAN_FDT);
-- 
2.30.0.284.gd98b1dd5eaa7-goog

  parent reply	other threads:[~2021-01-15 14:05 UTC|newest]

Thread overview: 34+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2021-01-15 14:04 [PATCH 00/15] gpio: Update and simplify the uclass API Simon Glass
2021-01-15 14:04 ` [PATCH 01/15] gpio: Disable functions not used with of-platdata Simon Glass
2021-01-18 21:17   ` Pratyush Yadav
2021-01-21  8:59   ` Patrick DELAUNAY
2021-01-15 14:04 ` [PATCH 02/15] dm: gpio: Rename set_dir_flags() method to update_flags() Simon Glass
2021-01-18 21:39   ` Pratyush Yadav
2021-01-21  9:01   ` Patrick DELAUNAY
2021-01-15 14:04 ` [PATCH 03/15] dm: gpio: Rename get_dir_flags() method to get_flags() Simon Glass
2021-01-18 21:54   ` Pratyush Yadav
2021-01-21  9:02   ` Patrick DELAUNAY
2021-01-15 14:04 ` [PATCH 04/15] gpio: Rename dm_gpio_get_dir_flags() to dm_gpio_get_flags() Simon Glass
2021-01-18 21:57   ` Pratyush Yadav
2021-01-21  9:05   ` Patrick DELAUNAY
2021-01-15 14:04 ` [PATCH 05/15] gpio: Drop dm_gpio_set_dir() Simon Glass
2021-01-21  9:06   ` Patrick DELAUNAY
2021-01-15 14:04 ` [PATCH 06/15] gpio: sandbox: Rename GPIO dir_flags to flags Simon Glass
2021-01-21  9:14   ` Patrick DELAUNAY
2021-01-15 14:04 ` [PATCH 07/15] gpio: sandbox: Use a separate flag for the value Simon Glass
2021-01-21  9:33   ` Patrick DELAUNAY
2021-01-15 14:04 ` [PATCH 08/15] gpio: sandbox: Fully separate pin value from output value Simon Glass
2021-01-21  9:39   ` Patrick DELAUNAY
2021-01-15 14:04 ` [PATCH 09/15] gpio: sandbox: Make sandbox_gpio_set_flags() set all flags Simon Glass
2021-01-21  9:43   ` Patrick DELAUNAY
2021-01-15 14:04 ` [PATCH 10/15] dm: gpio: Add a way to update flags Simon Glass
2021-01-21 10:07   ` Patrick DELAUNAY
2021-01-15 14:04 ` [PATCH 11/15] gpio: Replace direction_input() and direction_output() Simon Glass
2021-01-21 10:12   ` Patrick DELAUNAY
2021-01-15 14:04 ` [PATCH 12/15] gpio: Use an 'ops' variable everywhere Simon Glass
2021-01-21 10:13   ` Patrick DELAUNAY
2021-01-15 14:04 ` [PATCH 13/15] gpio: x86: Drop the deprecated methods in intel_gpio Simon Glass
2021-01-15 14:04 ` [PATCH 14/15] gpio: sandbox: Track whether a GPIO is driven Simon Glass
2021-01-21 10:19   ` Patrick DELAUNAY
2021-01-15 14:05 ` Simon Glass [this message]
2021-01-21 10:52   ` [PATCH 15/15] gpio: Add a way to read 3-way strapping pins Patrick DELAUNAY

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=20210115140500.846307-16-sjg@chromium.org \
    --to=sjg@chromium.org \
    --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.