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 <sean...@gmail.com>
---

Changes in v3:
- Add dt-bindings/pinctrl/sandbox-pinmux.h to patch

Changes in v2:
- New

 arch/sandbox/dts/test.dts                    |  45 +++++-
 drivers/pinctrl/pinctrl-sandbox.c            | 155 ++++++++++++++-----
 include/dt-bindings/pinctrl/sandbox-pinmux.h |  19 +++
 test/dm/Makefile                             |   3 +
 test/py/tests/test_pinmux.py                 |  36 ++---
 5 files changed, 197 insertions(+), 61 deletions(-)
 create mode 100644 include/dt-bindings/pinctrl/sandbox-pinmux.h

diff --git a/arch/sandbox/dts/test.dts b/arch/sandbox/dts/test.dts
index f5b685f7fe..36736f374d 100644
--- a/arch/sandbox/dts/test.dts
+++ b/arch/sandbox/dts/test.dts
@@ -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";
@@ -967,30 +968,60 @@
        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 {
diff --git a/drivers/pinctrl/pinctrl-sandbox.c 
b/drivers/pinctrl/pinctrl-sandbox.c
index ac0119d198..9aa13fbd55 100644
--- a/drivers/pinctrl/pinctrl-sandbox.c
+++ b/drivers/pinctrl/pinctrl-sandbox.c
@@ -3,55 +3,67 @@
  * Copyright (C) 2015  Masahiro Yamada <yamada.masah...@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[] = {
@@ -69,6 +81,7 @@ static const struct pinconf_param sandbox_conf_params[] = {
 };
 
 /* bitfield used to save param and value of each pin/selector */
+static unsigned int sandbox_mux;
 static unsigned int sandbox_pins_param[ARRAY_SIZE(sandbox_pins)];
 static unsigned int sandbox_pins_value[ARRAY_SIZE(sandbox_pins)];
 
@@ -89,7 +102,8 @@ static int sandbox_get_pin_muxing(struct udevice *dev,
        const struct pinconf_param *p;
        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]) {
                for (i = 0, p = sandbox_conf_params;
@@ -133,10 +147,30 @@ 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));
 
+       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;
+       }
+
+       sandbox_mux &= ~BIT(pin_selector);
+       sandbox_mux |= mux;
        sandbox_pins_param[pin_selector] = 0;
        sandbox_pins_value[pin_selector] = 0;
 
@@ -147,13 +181,61 @@ 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->param[i] = 0;
+               priv->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)
 {
@@ -191,6 +273,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,
diff --git a/include/dt-bindings/pinctrl/sandbox-pinmux.h 
b/include/dt-bindings/pinctrl/sandbox-pinmux.h
new file mode 100644
index 0000000000..891af072e5
--- /dev/null
+++ b/include/dt-bindings/pinctrl/sandbox-pinmux.h
@@ -0,0 +1,19 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Copyright (C) 2020 Sean Anderson <sean...@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 */
diff --git a/test/dm/Makefile b/test/dm/Makefile
index 0d1c66fa1e..9e273ee02d 100644
--- a/test/dm/Makefile
+++ b/test/dm/Makefile
@@ -76,4 +76,7 @@ obj-$(CONFIG_DM_RNG) += rng.o
 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
+ifneq ($(CONFIG_PINMUX),)
+obj-$(CONFIG_PINCONF) += pinmux.o
+endif
 endif
diff --git a/test/py/tests/test_pinmux.py b/test/py/tests/test_pinmux.py
index 4e6df992a4..0cbbae000c 100644
--- a/test/py/tests/test_pinmux.py
+++ b/test/py/tests/test_pinmux.py
@@ -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)
-- 
2.26.2

Reply via email to