// 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[] = {
{ "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)
{
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);
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;
}
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;
}
.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,
.name = "sandbox_pinctrl",
.id = UCLASS_PINCTRL,
.of_match = sandbox_pinctrl_match,
+ .priv_auto_alloc_size = sizeof(struct sandbox_pinctrl_priv),
.ops = &sandbox_pinctrl_ops,
};
--- /dev/null
+// 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);
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')
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)