From patchwork Fri Jan 15 14:05:00 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Simon Glass X-Patchwork-Id: 1427067 X-Patchwork-Delegate: sjg@chromium.org Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Authentication-Results: ozlabs.org; spf=pass (sender SPF authorized) smtp.mailfrom=lists.denx.de (client-ip=2a01:238:438b:c500:173d:9f52:ddab:ee01; helo=phobos.denx.de; envelope-from=u-boot-bounces@lists.denx.de; receiver=) Authentication-Results: ozlabs.org; dmarc=pass (p=none dis=none) header.from=chromium.org Authentication-Results: ozlabs.org; dkim=pass (1024-bit key; unprotected) header.d=chromium.org header.i=@chromium.org header.a=rsa-sha256 header.s=google header.b=dofZver2; dkim-atps=neutral Received: from phobos.denx.de (phobos.denx.de [IPv6:2a01:238:438b:c500:173d:9f52:ddab:ee01]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (4096 bits)) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id 4DHNMG2RWsz9t0Y for ; Sat, 16 Jan 2021 01:08:41 +1100 (AEDT) Received: from h2850616.stratoserver.net (localhost [IPv6:::1]) by phobos.denx.de (Postfix) with ESMTP id A3ED0826DA; Fri, 15 Jan 2021 15:06:16 +0100 (CET) Authentication-Results: phobos.denx.de; dmarc=pass (p=none dis=none) header.from=chromium.org Authentication-Results: phobos.denx.de; spf=pass smtp.mailfrom=u-boot-bounces@lists.denx.de Authentication-Results: phobos.denx.de; dkim=pass (1024-bit key; unprotected) header.d=chromium.org header.i=@chromium.org header.b="dofZver2"; dkim-atps=neutral Received: by phobos.denx.de (Postfix, from userid 109) id 30C088267A; Fri, 15 Jan 2021 15:05:56 +0100 (CET) X-Spam-Checker-Version: SpamAssassin 3.4.2 (2018-09-13) on phobos.denx.de X-Spam-Level: X-Spam-Status: No, score=-2.2 required=5.0 tests=BAYES_00,DKIMWL_WL_HIGH, DKIM_SIGNED,DKIM_VALID,DKIM_VALID_AU,RCVD_IN_DNSWL_NONE,SPF_HELO_NONE autolearn=ham autolearn_force=no version=3.4.2 Received: from mail-io1-xd2e.google.com (mail-io1-xd2e.google.com [IPv6:2607:f8b0:4864:20::d2e]) (using TLSv1.3 with cipher TLS_AES_128_GCM_SHA256 (128/128 bits)) (No client certificate requested) by phobos.denx.de (Postfix) with ESMTPS id B1A6082656 for ; Fri, 15 Jan 2021 15:05:43 +0100 (CET) Authentication-Results: phobos.denx.de; dmarc=pass (p=none dis=none) header.from=chromium.org Authentication-Results: phobos.denx.de; spf=pass smtp.mailfrom=sjg@chromium.org Received: by mail-io1-xd2e.google.com with SMTP id z5so18224272iob.11 for ; Fri, 15 Jan 2021 06:05:43 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=chromium.org; s=google; h=from:to:cc:subject:date:message-id:in-reply-to:references :mime-version:content-transfer-encoding; bh=fEbtqSlaoOuK25ujiTcIk+6Nr/12YzWe9fF24mH7paI=; b=dofZver25XOR+rkmV/kd5lPJcpjSaWO29mBn4lFTBIaOPlXhqBEx85b9WKsZYvsP00 EBBuJtKLh/EZwQbQ3gB0cpbga9mQhEYGi0N+rEr95t+tHDGaghV6cNfSzgEIrSAmh4Wr 1a4iwBh1zbb+IQD+zf2M6FHF4usl51A7XWB5A= X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references:mime-version:content-transfer-encoding; bh=fEbtqSlaoOuK25ujiTcIk+6Nr/12YzWe9fF24mH7paI=; b=nHAtsLm0AHizZSsox5gMe5h0JtI114Xt4ngVcxrJnef9gW5yrNwbr6qe3UAx4aQWdJ bPra2+sbeqc09VffT8yqcYCwmFlikMcOwvn3c3NVwy1VNeehphHIXu1Zh7pTC4YIwvW0 vTQ1OPuATP7TVSuzBKM5wIxFf0iyfvj/htPsIv1WQGN8DSKOX5cL093ojKbIB+eab9DM /Mioc+Ul7zgYrAkqujF0WKhZEwJJ/L7ysQ9sSfm8t64JtdFh2xNiDp04EcYcLRfiREK4 20sb/JbCMkg2I5O/hAIfvbZ4s6iCfdGf5XUele7hlMZRimIviDLPYhx5PzF/zg3NEe4Y Nj7w== X-Gm-Message-State: AOAM531ZMeqt57Hmr+zQvsT98Xhh+IMM+LkNB81jnoK/QwMpc1MihGG2 3fQshBlEobfBxO6zyHVL0GpBItHXc8b0k755 X-Google-Smtp-Source: ABdhPJwz+R+0X6RiEgw+gGU+6HG6dppCeL0kNFrNv1uH+HJkyhuoc5WdL4fpvqO4JgGyxxcacXqm7A== X-Received: by 2002:a92:6b0c:: with SMTP id g12mr10785441ilc.59.1610719542059; Fri, 15 Jan 2021 06:05:42 -0800 (PST) Received: from localhost.localdomain (c-67-190-101-114.hsd1.co.comcast.net. [67.190.101.114]) by smtp.gmail.com with ESMTPSA id 1sm5664843ilv.37.2021.01.15.06.05.41 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Fri, 15 Jan 2021 06:05:41 -0800 (PST) From: Simon Glass To: U-Boot Mailing List Cc: Patrick Delaunay , Tom Rini , Simon Glass , Andy Shevchenko , Dario Binacchi , Heiko Schocher , Jean-Jacques Hiblot , Patrick Delaunay , Pratyush Yadav , Walter Lozano Subject: [PATCH 15/15] gpio: Add a way to read 3-way strapping pins Date: Fri, 15 Jan 2021 07:05:00 -0700 Message-Id: <20210115140500.846307-16-sjg@chromium.org> X-Mailer: git-send-email 2.30.0.284.gd98b1dd5eaa7-goog In-Reply-To: <20210115140500.846307-1-sjg@chromium.org> References: <20210115140500.846307-1-sjg@chromium.org> MIME-Version: 1.0 X-BeenThere: u-boot@lists.denx.de X-Mailman-Version: 2.1.34 Precedence: list List-Id: U-Boot discussion List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: u-boot-bounces@lists.denx.de Sender: "U-Boot" X-Virus-Scanned: clamav-milter 0.102.3 at phobos.denx.de X-Virus-Status: Clean 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 --- 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 #include #include @@ -20,6 +22,7 @@ #include #include #include +#include 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 #include - 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);