test: pinmux: Add test for pin muxing
authorSean Anderson <seanga2@gmail.com>
Mon, 14 Sep 2020 15:01:57 +0000 (11:01 -0400)
committerTom Rini <trini@konsulko.com>
Thu, 8 Oct 2020 15:42:36 +0000 (11:42 -0400)
This extends the pinctrl-sandbox driver to support pin muxing, and adds a
test for that behaviour. The test is done in C and not python (like the
existing tests for the pinctrl uclass) because it needs to call
pinctrl_select_state.  Another option could be to add a command that
invokes pinctrl_select_state and then test everything in
test/py/tests/test_pinmux.py.

The pinctrl-sandbox driver now mimics the way that many pinmux devices
work.  There are two groups of pins which are muxed together, as well as
four pins which are muxed individually. I have tried to test all normal
paths. However, very few error cases are explicitly checked for.

Signed-off-by: Sean Anderson <seanga2@gmail.com>
Reviewed-by: Simon Glass <sjg@chromium.org>
MAINTAINERS
arch/sandbox/dts/test.dts
drivers/pinctrl/pinctrl-sandbox.c
include/dt-bindings/pinctrl/sandbox-pinmux.h [new file with mode: 0644]
test/dm/Makefile
test/dm/pinmux.c [new file with mode: 0644]
test/py/tests/test_pinmux.py

index ed5e354..2e53294 100644 (file)
@@ -960,6 +960,7 @@ M:  Simon Glass <sjg@chromium.org>
 S:     Maintained
 F:     arch/sandbox/
 F:     doc/arch/sandbox.rst
+F:     include/dt-bindings/*/sandbox*.h
 
 SH
 M:     Marek Vasut <marek.vasut+renesas@gmail.com>
index cc37280..6ea1073 100644 (file)
@@ -2,6 +2,7 @@
 
 #include <dt-bindings/gpio/gpio.h>
 #include <dt-bindings/gpio/sandbox-gpio.h>
+#include <dt-bindings/pinctrl/sandbox-pinmux.h>
 
 / {
        model = "sandbox";
        pinctrl {
                compatible = "sandbox,pinctrl";
 
-               pinctrl-names = "default";
-               pinctrl-0 = <&gpios>;
+               pinctrl-names = "default", "alternate";
+               pinctrl-0 = <&pinctrl_gpios>, <&pinctrl_i2s>;
+               pinctrl-1 = <&pinctrl_spi>, <&pinctrl_i2c>;
 
-               gpios: gpios {
+               pinctrl_gpios: gpios {
                        gpio0 {
-                               pins = "GPIO0";
+                               pins = "P5";
+                               function = "GPIO";
                                bias-pull-up;
                                input-disable;
                        };
                        gpio1 {
-                               pins = "GPIO1";
+                               pins = "P6";
+                               function = "GPIO";
                                output-high;
                                drive-open-drain;
                        };
                        gpio2 {
-                               pins = "GPIO2";
+                               pinmux = <SANDBOX_PINMUX(7, SANDBOX_PINMUX_GPIO)>;
                                bias-pull-down;
                                input-enable;
                        };
                        gpio3 {
-                               pins = "GPIO3";
+                               pinmux = <SANDBOX_PINMUX(8, SANDBOX_PINMUX_GPIO)>;
                                bias-disable;
                        };
                };
+
+               pinctrl_i2c: i2c {
+                       groups {
+                               groups = "I2C_UART";
+                               function = "I2C";
+                       };
+
+                       pins {
+                               pins = "P0", "P1";
+                               drive-open-drain;
+                       };
+               };
+
+               pinctrl_i2s: i2s {
+                       groups = "SPI_I2S";
+                       function = "I2S";
+               };
+
+               pinctrl_spi: spi {
+                       groups = "SPI_I2S";
+                       function = "SPI";
+
+                       cs {
+                               pinmux = <SANDBOX_PINMUX(5, SANDBOX_PINMUX_CS)>,
+                                        <SANDBOX_PINMUX(6, SANDBOX_PINMUX_CS)>;
+                       };
+               };
        };
 
        hwspinlock@0 {
index ac0119d..d27f742 100644 (file)
@@ -1,57 +1,70 @@
 // SPDX-License-Identifier: GPL-2.0+
 /*
- * Copyright (C) 2015  Masahiro Yamada <yamada.masahiro@socionext.com>
+ * Copyright (C) 2020 Sean Anderson <seanga2@gmail.com>
+ * Copyright (C) 2015 Masahiro Yamada <yamada.masahiro@socionext.com>
  */
 
-/* #define DEBUG */
-
 #include <common.h>
 #include <dm.h>
-#include <log.h>
 #include <dm/pinctrl.h>
+#include <dt-bindings/pinctrl/sandbox-pinmux.h>
+#include <log.h>
 #include <linux/bitops.h>
 
+/*
+ * This driver emulates a pin controller with the following rules:
+ * - The pinctrl config for each pin must be set individually
+ * - The first three pins (P0-P2) must be muxed as a group
+ * - The next two pins (P3-P4) must be muxed as a group
+ * - The last four pins (P5-P8) must be muxed individually
+ */
+
 static const char * const sandbox_pins[] = {
-       "SCL",
-       "SDA",
-       "TX",
-       "RX",
-       "W1",
-       "GPIO0",
-       "GPIO1",
-       "GPIO2",
-       "GPIO3",
+#define PIN(x) \
+       [x] = "P" #x
+       PIN(0),
+       PIN(1),
+       PIN(2),
+       PIN(3),
+       PIN(4),
+       PIN(5),
+       PIN(6),
+       PIN(7),
+       PIN(8),
+#undef PIN
 };
 
-static const char * const sandbox_pins_muxing[] = {
-       "I2C SCL",
-       "I2C SDA",
-       "Uart TX",
-       "Uart RX",
-       "1-wire gpio",
-       "gpio",
-       "gpio",
-       "gpio",
-       "gpio",
+static const char * const sandbox_pins_muxing[][2] = {
+       { "UART TX", "I2C SCL" },
+       { "UART RX", "I2C SDA" },
+       { "SPI SCLK", "I2S SCK" },
+       { "SPI MOSI", "I2S SD" },
+       { "SPI MISO", "I2S WS" },
+       { "GPIO0", "SPI CS0" },
+       { "GPIO1", "SPI CS1" },
+       { "GPIO2", "PWM0" },
+       { "GPIO3", "PWM1" },
 };
 
+#define SANDBOX_GROUP_I2C_UART 0
+#define SANDBOX_GROUP_SPI_I2S 1
+
 static const char * const sandbox_groups[] = {
-       "i2c",
-       "serial_a",
-       "serial_b",
-       "spi",
-       "w1",
+       [SANDBOX_GROUP_I2C_UART] = "I2C_UART",
+       [SANDBOX_GROUP_SPI_I2S] = "SPI_I2S",
 };
 
 static const char * const sandbox_functions[] = {
-       "i2c",
-       "serial",
-       "spi",
-       "w1",
-       "gpio",
-       "gpio",
-       "gpio",
-       "gpio",
+#define FUNC(id) \
+       [SANDBOX_PINMUX_##id] = #id
+       FUNC(UART),
+       FUNC(I2C),
+       FUNC(SPI),
+       FUNC(I2S),
+       FUNC(GPIO),
+       FUNC(CS),
+       FUNC(PWM),
+#undef FUNC
 };
 
 static const struct pinconf_param sandbox_conf_params[] = {
@@ -68,9 +81,12 @@ static const struct pinconf_param sandbox_conf_params[] = {
        { "input-disable", PIN_CONFIG_INPUT_ENABLE, 0 },
 };
 
-/* bitfield used to save param and value of each pin/selector */
-static unsigned int sandbox_pins_param[ARRAY_SIZE(sandbox_pins)];
-static unsigned int sandbox_pins_value[ARRAY_SIZE(sandbox_pins)];
+/* Bitfield used to save param and value of each pin/selector */
+struct sandbox_pinctrl_priv {
+       unsigned int mux;
+       unsigned int pins_param[ARRAY_SIZE(sandbox_pins)];
+       unsigned int pins_value[ARRAY_SIZE(sandbox_pins)];
+};
 
 static int sandbox_get_pins_count(struct udevice *dev)
 {
@@ -87,16 +103,18 @@ static int sandbox_get_pin_muxing(struct udevice *dev,
                                  char *buf, int size)
 {
        const struct pinconf_param *p;
+       struct sandbox_pinctrl_priv *priv = dev_get_priv(dev);
        int i;
 
-       snprintf(buf, size, "%s", sandbox_pins_muxing[selector]);
+       snprintf(buf, size, "%s",
+                sandbox_pins_muxing[selector][!!(priv->mux & BIT(selector))]);
 
-       if (sandbox_pins_param[selector]) {
+       if (priv->pins_param[selector]) {
                for (i = 0, p = sandbox_conf_params;
                     i < ARRAY_SIZE(sandbox_conf_params);
                     i++, p++) {
-                       if ((sandbox_pins_param[selector] & BIT(p->param)) &&
-                           (!!(sandbox_pins_value[selector] & BIT(p->param)) ==
+                       if ((priv->pins_param[selector] & BIT(p->param)) &&
+                           (!!(priv->pins_value[selector] & BIT(p->param)) ==
                             p->default_value)) {
                                strncat(buf, " ", size);
                                strncat(buf, p->property, size);
@@ -133,12 +151,32 @@ static const char *sandbox_get_function_name(struct udevice *dev,
 static int sandbox_pinmux_set(struct udevice *dev, unsigned pin_selector,
                              unsigned func_selector)
 {
+       int mux;
+       struct sandbox_pinctrl_priv *priv = dev_get_priv(dev);
+
        debug("sandbox pinmux: pin = %d (%s), function = %d (%s)\n",
              pin_selector, sandbox_get_pin_name(dev, pin_selector),
              func_selector, sandbox_get_function_name(dev, func_selector));
 
-       sandbox_pins_param[pin_selector] = 0;
-       sandbox_pins_value[pin_selector] = 0;
+       if (pin_selector < 5)
+               return -EINVAL;
+
+       switch (func_selector) {
+       case SANDBOX_PINMUX_GPIO:
+               mux = 0;
+               break;
+       case SANDBOX_PINMUX_CS:
+       case SANDBOX_PINMUX_PWM:
+               mux = BIT(pin_selector);
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       priv->mux &= ~BIT(pin_selector);
+       priv->mux |= mux;
+       priv->pins_param[pin_selector] = 0;
+       priv->pins_value[pin_selector] = 0;
 
        return 0;
 }
@@ -147,25 +185,75 @@ static int sandbox_pinmux_group_set(struct udevice *dev,
                                    unsigned group_selector,
                                    unsigned func_selector)
 {
+       bool mux;
+       int i, group_start, group_end;
+       struct sandbox_pinctrl_priv *priv = dev_get_priv(dev);
+       unsigned int mask;
+
        debug("sandbox pinmux: group = %d (%s), function = %d (%s)\n",
              group_selector, sandbox_get_group_name(dev, group_selector),
              func_selector, sandbox_get_function_name(dev, func_selector));
 
+       if (group_selector == SANDBOX_GROUP_I2C_UART) {
+               group_start = 0;
+               group_end = 1;
+
+               if (func_selector == SANDBOX_PINMUX_UART)
+                       mux = false;
+               else if (func_selector == SANDBOX_PINMUX_I2C)
+                       mux = true;
+               else
+                       return -EINVAL;
+       } else if (group_selector == SANDBOX_GROUP_SPI_I2S) {
+               group_start = 2;
+               group_end = 4;
+
+               if (func_selector == SANDBOX_PINMUX_SPI)
+                       mux = false;
+               else if (func_selector == SANDBOX_PINMUX_I2S)
+                       mux = true;
+               else
+                       return -EINVAL;
+       } else {
+               return -EINVAL;
+       }
+
+       mask = GENMASK(group_end, group_start);
+       priv->mux &= ~mask;
+       priv->mux |= mux ? mask : 0;
+
+       for (i = group_start; i < group_end; i++) {
+               priv->pins_param[i] = 0;
+               priv->pins_value[i] = 0;
+       }
+
        return 0;
 }
 
+static int sandbox_pinmux_property_set(struct udevice *dev, u32 pinmux_group)
+{
+       int ret;
+       unsigned pin_selector = pinmux_group & 0xFFFF;
+       unsigned func_selector = pinmux_group >> 16;
+
+       ret = sandbox_pinmux_set(dev, pin_selector, func_selector);
+       return ret ? ret : pin_selector;
+}
+
 static int sandbox_pinconf_set(struct udevice *dev, unsigned pin_selector,
                               unsigned param, unsigned argument)
 {
+       struct sandbox_pinctrl_priv *priv = dev_get_priv(dev);
+
        debug("sandbox pinconf: pin = %d (%s), param = %d, arg = %d\n",
              pin_selector, sandbox_get_pin_name(dev, pin_selector),
              param, argument);
 
-       sandbox_pins_param[pin_selector] |= BIT(param);
+       priv->pins_param[pin_selector] |= BIT(param);
        if (argument)
-               sandbox_pins_value[pin_selector] |= BIT(param);
+               priv->pins_value[pin_selector] |= BIT(param);
        else
-               sandbox_pins_value[pin_selector] &= ~BIT(param);
+               priv->pins_value[pin_selector] &= ~BIT(param);
 
        return 0;
 }
@@ -191,6 +279,7 @@ const struct pinctrl_ops sandbox_pinctrl_ops = {
        .get_function_name = sandbox_get_function_name,
        .pinmux_set = sandbox_pinmux_set,
        .pinmux_group_set = sandbox_pinmux_group_set,
+       .pinmux_property_set = sandbox_pinmux_property_set,
        .pinconf_num_params = ARRAY_SIZE(sandbox_conf_params),
        .pinconf_params = sandbox_conf_params,
        .pinconf_set = sandbox_pinconf_set,
@@ -207,5 +296,6 @@ U_BOOT_DRIVER(sandbox_pinctrl) = {
        .name = "sandbox_pinctrl",
        .id = UCLASS_PINCTRL,
        .of_match = sandbox_pinctrl_match,
+       .priv_auto_alloc_size = sizeof(struct sandbox_pinctrl_priv),
        .ops = &sandbox_pinctrl_ops,
 };
diff --git a/include/dt-bindings/pinctrl/sandbox-pinmux.h b/include/dt-bindings/pinctrl/sandbox-pinmux.h
new file mode 100644 (file)
index 0000000..891af07
--- /dev/null
@@ -0,0 +1,19 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Copyright (C) 2020 Sean Anderson <seanga2@gmail.com>
+ */
+
+#ifndef SANDBOX_PINMUX_H
+#define SANDBOX_PINMUX_H
+
+#define SANDBOX_PINMUX_UART 0
+#define SANDBOX_PINMUX_I2C  1
+#define SANDBOX_PINMUX_SPI  2
+#define SANDBOX_PINMUX_I2S  3
+#define SANDBOX_PINMUX_GPIO 4
+#define SANDBOX_PINMUX_CS   5
+#define SANDBOX_PINMUX_PWM  6
+
+#define SANDBOX_PINMUX(pin, func) ((func) << 16 | (pin))
+
+#endif /* SANDBOX_PINMUX_H */
index 70ba1b6..e2b0798 100644 (file)
@@ -81,4 +81,7 @@ obj-$(CONFIG_CLK_K210_SET_RATE) += k210_pll.o
 obj-$(CONFIG_SIMPLE_PM_BUS) += simple-pm-bus.o
 obj-$(CONFIG_RESET_SYSCON) += syscon-reset.o
 obj-$(CONFIG_SCMI_FIRMWARE) += scmi.o
+ifneq ($(CONFIG_PINMUX),)
+obj-$(CONFIG_PINCONF) += pinmux.o
+endif
 endif
diff --git a/test/dm/pinmux.c b/test/dm/pinmux.c
new file mode 100644 (file)
index 0000000..047184d
--- /dev/null
@@ -0,0 +1,57 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright (C) 2020 Sean Anderson <seanga2@gmail.com>
+ */
+
+#include <common.h>
+#include <dm.h>
+#include <dm/pinctrl.h>
+#include <dm/test.h>
+#include <test/ut.h>
+
+static int dm_test_pinmux(struct unit_test_state *uts)
+{
+       char buf[64];
+       struct udevice *dev;
+
+#define test_muxing(selector, expected) do { \
+       ut_assertok(pinctrl_get_pin_muxing(dev, selector, buf, sizeof(buf))); \
+       ut_asserteq_str(expected, (char *)&buf); \
+} while (0)
+
+       ut_assertok(uclass_get_device_by_name(UCLASS_PINCTRL, "pinctrl", &dev));
+       test_muxing(0, "UART TX.");
+       test_muxing(1, "UART RX.");
+       test_muxing(2, "I2S SCK.");
+       test_muxing(3, "I2S SD.");
+       test_muxing(4, "I2S WS.");
+       test_muxing(5, "GPIO0 bias-pull-up input-disable.");
+       test_muxing(6, "GPIO1 drive-open-drain.");
+       test_muxing(7, "GPIO2 bias-pull-down input-enable.");
+       test_muxing(8, "GPIO3 bias-disable.");
+
+       ut_assertok(pinctrl_select_state(dev, "alternate"));
+       test_muxing(0, "I2C SCL drive-open-drain.");
+       test_muxing(1, "I2C SDA drive-open-drain.");
+       test_muxing(2, "SPI SCLK.");
+       test_muxing(3, "SPI MOSI.");
+       test_muxing(4, "SPI MISO.");
+       test_muxing(5, "SPI CS0.");
+       test_muxing(6, "SPI CS1.");
+       test_muxing(7, "GPIO2 bias-pull-down input-enable.");
+       test_muxing(8, "GPIO3 bias-disable.");
+
+       ut_assertok(pinctrl_select_state(dev, "0"));
+       test_muxing(0, "I2C SCL drive-open-drain.");
+       test_muxing(1, "I2C SDA drive-open-drain.");
+       test_muxing(2, "I2S SCK.");
+       test_muxing(3, "I2S SD.");
+       test_muxing(4, "I2S WS.");
+       test_muxing(5, "GPIO0 bias-pull-up input-disable.");
+       test_muxing(6, "GPIO1 drive-open-drain.");
+       test_muxing(7, "GPIO2 bias-pull-down input-enable.");
+       test_muxing(8, "GPIO3 bias-disable.");
+
+       return 0;
+}
+DM_TEST(dm_test_pinmux, UT_TESTF_SCAN_FDT);
index 4e6df99..0cbbae0 100644 (file)
@@ -28,15 +28,15 @@ def test_pinmux_status_all(u_boot_console):
     assert ('a6        : gpio output .' in output)
 
     assert ('pinctrl:' in output)
-    assert ('SCL       : I2C SCL.' in output)
-    assert ('SDA       : I2C SDA.' in output)
-    assert ('TX        : Uart TX.' in output)
-    assert ('RX        : Uart RX.' in output)
-    assert ('W1        : 1-wire gpio.' in output)
-    assert ('GPIO0     : gpio bias-pull-up input-disable.' in output)
-    assert ('GPIO1     : gpio drive-open-drain.' in output)
-    assert ('GPIO2     : gpio bias-pull-down input-enable.' in output)
-    assert ('GPIO3     : gpio bias-disable.' in output)
+    assert ('P0        : UART TX.' in output)
+    assert ('P1        : UART RX.' in output)
+    assert ('P2        : I2S SCK.' in output)
+    assert ('P3        : I2S SD.' in output)
+    assert ('P4        : I2S WS.' in output)
+    assert ('P5        : GPIO0 bias-pull-up input-disable.' in output)
+    assert ('P6        : GPIO1 drive-open-drain.' in output)
+    assert ('P7        : GPIO2 bias-pull-down input-enable.' in output)
+    assert ('P8        : GPIO3 bias-disable.' in output)
 
 @pytest.mark.buildconfigspec('cmd_pinmux')
 @pytest.mark.boardspec('sandbox')
@@ -73,12 +73,12 @@ def test_pinmux_status(u_boot_console):
     assert (not 'pinctrl-gpio:' in output)
     assert (not 'pinctrl:' in output)
 
-    assert ('SCL       : I2C SCL.' in output)
-    assert ('SDA       : I2C SDA.' in output)
-    assert ('TX        : Uart TX.' in output)
-    assert ('RX        : Uart RX.' in output)
-    assert ('W1        : 1-wire gpio.' in output)
-    assert ('GPIO0     : gpio bias-pull-up input-disable.' in output)
-    assert ('GPIO1     : gpio drive-open-drain.' in output)
-    assert ('GPIO2     : gpio bias-pull-down input-enable.' in output)
-    assert ('GPIO3     : gpio bias-disable.' in output)
+    assert ('P0        : UART TX.' in output)
+    assert ('P1        : UART RX.' in output)
+    assert ('P2        : I2S SCK.' in output)
+    assert ('P3        : I2S SD.' in output)
+    assert ('P4        : I2S WS.' in output)
+    assert ('P5        : GPIO0 bias-pull-up input-disable.' in output)
+    assert ('P6        : GPIO1 drive-open-drain.' in output)
+    assert ('P7        : GPIO2 bias-pull-down input-enable.' in output)
+    assert ('P8        : GPIO3 bias-disable.' in output)