test: pinmux: Add test for pin muxing
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>
diff --git a/drivers/pinctrl/pinctrl-sandbox.c b/drivers/pinctrl/pinctrl-sandbox.c
index ac0119d..d27f742 100644
--- a/drivers/pinctrl/pinctrl-sandbox.c
+++ b/drivers/pinctrl/pinctrl-sandbox.c
@@ -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 @@
{ "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 @@
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 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;
+
- sandbox_pins_param[pin_selector] = 0;
- sandbox_pins_value[pin_selector] = 0;
+ 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 @@
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 @@
.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 @@
.name = "sandbox_pinctrl",
.id = UCLASS_PINCTRL,
.of_match = sandbox_pinctrl_match,
+ .priv_auto_alloc_size = sizeof(struct sandbox_pinctrl_priv),
.ops = &sandbox_pinctrl_ops,
};