diff options
Diffstat (limited to 'drivers/pinctrl')
-rw-r--r-- | drivers/pinctrl/Kconfig | 7 | ||||
-rw-r--r-- | drivers/pinctrl/Makefile | 1 | ||||
-rw-r--r-- | drivers/pinctrl/pinctrl-kendryte.c | 737 |
3 files changed, 745 insertions, 0 deletions
diff --git a/drivers/pinctrl/Kconfig b/drivers/pinctrl/Kconfig index 048583f39b..77fb851114 100644 --- a/drivers/pinctrl/Kconfig +++ b/drivers/pinctrl/Kconfig @@ -291,6 +291,13 @@ config ASPEED_AST2500_PINCTRL uses Generic Pinctrl framework and is compatible with the Linux driver, i.e. it uses the same device tree configuration. +config PINCTRL_K210 + bool "Kendryte K210 Fully-Programmable Input/Output Array driver" + depends on DM && PINCTRL_GENERIC + help + Support pin multiplexing on the K210. The "FPIOA" can remap any + supported function to any multifunctional IO pin. It can also perform + basic GPIO functions, such as reading the current value of a pin. endif source "drivers/pinctrl/broadcom/Kconfig" diff --git a/drivers/pinctrl/Makefile b/drivers/pinctrl/Makefile index 507dd3a926..05b71f2f13 100644 --- a/drivers/pinctrl/Makefile +++ b/drivers/pinctrl/Makefile @@ -17,6 +17,7 @@ obj-$(CONFIG_PINCTRL_SANDBOX) += pinctrl-sandbox.o obj-$(CONFIG_PINCTRL_UNIPHIER) += uniphier/ obj-$(CONFIG_PINCTRL_PIC32) += pinctrl_pic32.o obj-$(CONFIG_PINCTRL_EXYNOS) += exynos/ +obj-$(CONFIG_PINCTRL_K210) += pinctrl-kendryte.o obj-$(CONFIG_PINCTRL_MESON) += meson/ obj-$(CONFIG_PINCTRL_MTK) += mediatek/ obj-$(CONFIG_PINCTRL_MSCC) += mscc/ diff --git a/drivers/pinctrl/pinctrl-kendryte.c b/drivers/pinctrl/pinctrl-kendryte.c new file mode 100644 index 0000000000..5ad049d955 --- /dev/null +++ b/drivers/pinctrl/pinctrl-kendryte.c @@ -0,0 +1,737 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Copyright (C) 2020 Sean Anderson <seanga2@gmail.com> + */ + +#include <common.h> +#include <clk.h> +#include <dm.h> +#include <dm/pinctrl.h> +#include <dt-bindings/pinctrl/k210-pinctrl.h> +#include <mapmem.h> +#include <regmap.h> +#include <syscon.h> +#include <asm/io.h> +#include <linux/err.h> +#include <linux/bitfield.h> +#include <linux/bitops.h> + +/* + * The K210 only implements 8 drive levels, even though there is register space + * for 16 + */ +#define K210_PC_DRIVE_MASK GENMASK(11, 8) +#define K210_PC_DRIVE_SHIFT 8 +#define K210_PC_DRIVE_0 (0 << K210_PC_DRIVE_SHIFT) +#define K210_PC_DRIVE_1 (1 << K210_PC_DRIVE_SHIFT) +#define K210_PC_DRIVE_2 (2 << K210_PC_DRIVE_SHIFT) +#define K210_PC_DRIVE_3 (3 << K210_PC_DRIVE_SHIFT) +#define K210_PC_DRIVE_4 (4 << K210_PC_DRIVE_SHIFT) +#define K210_PC_DRIVE_5 (5 << K210_PC_DRIVE_SHIFT) +#define K210_PC_DRIVE_6 (6 << K210_PC_DRIVE_SHIFT) +#define K210_PC_DRIVE_7 (7 << K210_PC_DRIVE_SHIFT) +#define K210_PC_DRIVE_MAX 7 + +#define K210_PC_MODE_MASK GENMASK(23, 12) +/* + * output enabled == PC_OE & (PC_OE_INV ^ FUNCTION_OE) where FUNCTION_OE is a + * physical signal from the function + */ +#define K210_PC_OE BIT(12) /* Output Enable */ +#define K210_PC_OE_INV BIT(13) /* INVert function-controlled Output Enable */ +#define K210_PC_DO_OE BIT(14) /* set Data Out to the Output Enable signal */ +#define K210_PC_DO_INV BIT(15) /* INVert final Data Output */ +#define K210_PC_PU BIT(16) /* Pull Up */ +#define K210_PC_PD BIT(17) /* Pull Down */ +/* Strong pull up not implemented on K210 */ +#define K210_PC_SL BIT(19) /* reduce SLew rate to prevent overshoot */ +/* Same semantics as OE above */ +#define K210_PC_IE BIT(20) /* Input Enable */ +#define K210_PC_IE_INV BIT(21) /* INVert function-controlled Input Enable */ +#define K210_PC_DI_INV BIT(22) /* INVert Data Input */ +#define K210_PC_ST BIT(23) /* Schmitt Trigger */ +#define K210_PC_DI BIT(31) /* raw Data Input */ +#define K210_PC_BIAS_MASK (K210_PC_PU & K210_PC_PD) + +#define K210_PC_MODE_IN (K210_PC_IE | K210_PC_ST) +#define K210_PC_MODE_OUT (K210_PC_DRIVE_7 | K210_PC_OE) +#define K210_PC_MODE_I2C (K210_PC_MODE_IN | K210_PC_IE_INV | K210_PC_SL | \ + K210_PC_OE | K210_PC_OE_INV | K210_PC_PU) +#define K210_PC_MODE_SPI (K210_PC_MODE_IN | K210_PC_IE_INV | \ + K210_PC_MODE_OUT | K210_PC_OE_INV) +#define K210_PC_MODE_GPIO (K210_PC_MODE_IN | K210_PC_MODE_OUT) + +#define K210_PG_FUNC GENMASK(7, 0) +#define K210_PG_DO BIT(8) +#define K210_PG_PIN GENMASK(22, 16) + +#define PIN_CONFIG_OUTPUT_INVERT (PIN_CONFIG_END + 1) +#define PIN_CONFIG_INPUT_INVERT (PIN_CONFIG_END + 2) + +struct k210_fpioa { + u32 pins[48]; + u32 tie_en[8]; + u32 tie_val[8]; +}; + +struct k210_pc_priv { + struct clk clk; + struct k210_fpioa __iomem *fpioa; /* FPIOA register */ + struct regmap *sysctl; /* Sysctl regmap */ + u32 power_offset; /* Power bank register offset */ +}; + +#ifdef CONFIG_CMD_PINMUX +static const char k210_pc_pin_names[][6] = { +#define PIN(i) \ + [i] = "IO_" #i + PIN(0), + PIN(1), + PIN(2), + PIN(3), + PIN(4), + PIN(5), + PIN(6), + PIN(7), + PIN(8), + PIN(9), + PIN(10), + PIN(11), + PIN(12), + PIN(13), + PIN(14), + PIN(15), + PIN(16), + PIN(17), + PIN(18), + PIN(19), + PIN(20), + PIN(21), + PIN(22), + PIN(23), + PIN(24), + PIN(25), + PIN(26), + PIN(27), + PIN(28), + PIN(29), + PIN(30), + PIN(31), + PIN(32), + PIN(33), + PIN(34), + PIN(35), + PIN(36), + PIN(37), + PIN(38), + PIN(39), + PIN(40), + PIN(41), + PIN(42), + PIN(43), + PIN(44), + PIN(45), + PIN(46), + PIN(47), +#undef PIN +}; + +static int k210_pc_get_pins_count(struct udevice *dev) +{ + return ARRAY_SIZE(k210_pc_pin_names); +}; + +static const char *k210_pc_get_pin_name(struct udevice *dev, unsigned selector) +{ + return k210_pc_pin_names[selector]; +} +#endif /* CONFIG_CMD_PINMUX */ + +/* These are just power domains */ +static const char k210_pc_group_names[][3] = { + [0] = "A0", + [1] = "A1", + [2] = "A2", + [3] = "B0", + [4] = "B1", + [5] = "B2", + [6] = "C0", + [7] = "C1", +}; + +static int k210_pc_get_groups_count(struct udevice *dev) +{ + return ARRAY_SIZE(k210_pc_group_names); +} + +static const char *k210_pc_get_group_name(struct udevice *dev, + unsigned selector) +{ + return k210_pc_group_names[selector]; +} + +enum k210_pc_mode_id { + K210_PC_DEFAULT_DISABLED, + K210_PC_DEFAULT_IN, + K210_PC_DEFAULT_IN_TIE, + K210_PC_DEFAULT_OUT, + K210_PC_DEFAULT_I2C, + K210_PC_DEFAULT_SPI, + K210_PC_DEFAULT_GPIO, + K210_PC_DEFAULT_INT13, +}; + +static const u32 k210_pc_mode_id_to_mode[] = { +#define DEFAULT(mode) \ + [K210_PC_DEFAULT_##mode] = K210_PC_MODE_##mode + [K210_PC_DEFAULT_DISABLED] = 0, + DEFAULT(IN), + [K210_PC_DEFAULT_IN_TIE] = K210_PC_MODE_IN, + DEFAULT(OUT), + DEFAULT(I2C), + DEFAULT(SPI), + DEFAULT(GPIO), + [K210_PC_DEFAULT_INT13] = K210_PC_MODE_IN | K210_PC_PU, +#undef DEFAULT +}; + +/* This saves around 2K vs having a pointer+mode */ +struct k210_pcf_info { +#ifdef CONFIG_CMD_PINMUX + char name[15]; +#endif + u8 mode_id; +}; + +static const struct k210_pcf_info k210_pcf_infos[] = { +#ifdef CONFIG_CMD_PINMUX +#define FUNC(id, mode) \ + [K210_PCF_##id] = { \ + .name = #id, \ + .mode_id = K210_PC_DEFAULT_##mode \ + } +#else +#define FUNC(id, mode) \ + [K210_PCF_##id] = { \ + .mode_id = K210_PC_DEFAULT_##mode \ + } +#endif + FUNC(JTAG_TCLK, IN), + FUNC(JTAG_TDI, IN), + FUNC(JTAG_TMS, IN), + FUNC(JTAG_TDO, OUT), + FUNC(SPI0_D0, SPI), + FUNC(SPI0_D1, SPI), + FUNC(SPI0_D2, SPI), + FUNC(SPI0_D3, SPI), + FUNC(SPI0_D4, SPI), + FUNC(SPI0_D5, SPI), + FUNC(SPI0_D6, SPI), + FUNC(SPI0_D7, SPI), + FUNC(SPI0_SS0, OUT), + FUNC(SPI0_SS1, OUT), + FUNC(SPI0_SS2, OUT), + FUNC(SPI0_SS3, OUT), + FUNC(SPI0_ARB, IN_TIE), + FUNC(SPI0_SCLK, OUT), + FUNC(UARTHS_RX, IN), + FUNC(UARTHS_TX, OUT), + FUNC(RESV6, IN), + FUNC(RESV7, IN), + FUNC(CLK_SPI1, OUT), + FUNC(CLK_I2C1, OUT), + FUNC(GPIOHS0, GPIO), + FUNC(GPIOHS1, GPIO), + FUNC(GPIOHS2, GPIO), + FUNC(GPIOHS3, GPIO), + FUNC(GPIOHS4, GPIO), + FUNC(GPIOHS5, GPIO), + FUNC(GPIOHS6, GPIO), + FUNC(GPIOHS7, GPIO), + FUNC(GPIOHS8, GPIO), + FUNC(GPIOHS9, GPIO), + FUNC(GPIOHS10, GPIO), + FUNC(GPIOHS11, GPIO), + FUNC(GPIOHS12, GPIO), + FUNC(GPIOHS13, GPIO), + FUNC(GPIOHS14, GPIO), + FUNC(GPIOHS15, GPIO), + FUNC(GPIOHS16, GPIO), + FUNC(GPIOHS17, GPIO), + FUNC(GPIOHS18, GPIO), + FUNC(GPIOHS19, GPIO), + FUNC(GPIOHS20, GPIO), + FUNC(GPIOHS21, GPIO), + FUNC(GPIOHS22, GPIO), + FUNC(GPIOHS23, GPIO), + FUNC(GPIOHS24, GPIO), + FUNC(GPIOHS25, GPIO), + FUNC(GPIOHS26, GPIO), + FUNC(GPIOHS27, GPIO), + FUNC(GPIOHS28, GPIO), + FUNC(GPIOHS29, GPIO), + FUNC(GPIOHS30, GPIO), + FUNC(GPIOHS31, GPIO), + FUNC(GPIO0, GPIO), + FUNC(GPIO1, GPIO), + FUNC(GPIO2, GPIO), + FUNC(GPIO3, GPIO), + FUNC(GPIO4, GPIO), + FUNC(GPIO5, GPIO), + FUNC(GPIO6, GPIO), + FUNC(GPIO7, GPIO), + FUNC(UART1_RX, IN), + FUNC(UART1_TX, OUT), + FUNC(UART2_RX, IN), + FUNC(UART2_TX, OUT), + FUNC(UART3_RX, IN), + FUNC(UART3_TX, OUT), + FUNC(SPI1_D0, SPI), + FUNC(SPI1_D1, SPI), + FUNC(SPI1_D2, SPI), + FUNC(SPI1_D3, SPI), + FUNC(SPI1_D4, SPI), + FUNC(SPI1_D5, SPI), + FUNC(SPI1_D6, SPI), + FUNC(SPI1_D7, SPI), + FUNC(SPI1_SS0, OUT), + FUNC(SPI1_SS1, OUT), + FUNC(SPI1_SS2, OUT), + FUNC(SPI1_SS3, OUT), + FUNC(SPI1_ARB, IN_TIE), + FUNC(SPI1_SCLK, OUT), + FUNC(SPI2_D0, SPI), + FUNC(SPI2_SS, IN), + FUNC(SPI2_SCLK, IN), + FUNC(I2S0_MCLK, OUT), + FUNC(I2S0_SCLK, OUT), + FUNC(I2S0_WS, OUT), + FUNC(I2S0_IN_D0, IN), + FUNC(I2S0_IN_D1, IN), + FUNC(I2S0_IN_D2, IN), + FUNC(I2S0_IN_D3, IN), + FUNC(I2S0_OUT_D0, OUT), + FUNC(I2S0_OUT_D1, OUT), + FUNC(I2S0_OUT_D2, OUT), + FUNC(I2S0_OUT_D3, OUT), + FUNC(I2S1_MCLK, OUT), + FUNC(I2S1_SCLK, OUT), + FUNC(I2S1_WS, OUT), + FUNC(I2S1_IN_D0, IN), + FUNC(I2S1_IN_D1, IN), + FUNC(I2S1_IN_D2, IN), + FUNC(I2S1_IN_D3, IN), + FUNC(I2S1_OUT_D0, OUT), + FUNC(I2S1_OUT_D1, OUT), + FUNC(I2S1_OUT_D2, OUT), + FUNC(I2S1_OUT_D3, OUT), + FUNC(I2S2_MCLK, OUT), + FUNC(I2S2_SCLK, OUT), + FUNC(I2S2_WS, OUT), + FUNC(I2S2_IN_D0, IN), + FUNC(I2S2_IN_D1, IN), + FUNC(I2S2_IN_D2, IN), + FUNC(I2S2_IN_D3, IN), + FUNC(I2S2_OUT_D0, OUT), + FUNC(I2S2_OUT_D1, OUT), + FUNC(I2S2_OUT_D2, OUT), + FUNC(I2S2_OUT_D3, OUT), + FUNC(RESV0, DISABLED), + FUNC(RESV1, DISABLED), + FUNC(RESV2, DISABLED), + FUNC(RESV3, DISABLED), + FUNC(RESV4, DISABLED), + FUNC(RESV5, DISABLED), + FUNC(I2C0_SCLK, I2C), + FUNC(I2C0_SDA, I2C), + FUNC(I2C1_SCLK, I2C), + FUNC(I2C1_SDA, I2C), + FUNC(I2C2_SCLK, I2C), + FUNC(I2C2_SDA, I2C), + FUNC(DVP_XCLK, OUT), + FUNC(DVP_RST, OUT), + FUNC(DVP_PWDN, OUT), + FUNC(DVP_VSYNC, IN), + FUNC(DVP_HSYNC, IN), + FUNC(DVP_PCLK, IN), + FUNC(DVP_D0, IN), + FUNC(DVP_D1, IN), + FUNC(DVP_D2, IN), + FUNC(DVP_D3, IN), + FUNC(DVP_D4, IN), + FUNC(DVP_D5, IN), + FUNC(DVP_D6, IN), + FUNC(DVP_D7, IN), + FUNC(SCCB_SCLK, I2C), + FUNC(SCCB_SDA, I2C), + FUNC(UART1_CTS, IN), + FUNC(UART1_DSR, IN), + FUNC(UART1_DCD, IN), + FUNC(UART1_RI, IN), + FUNC(UART1_SIR_IN, IN), + FUNC(UART1_DTR, OUT), + FUNC(UART1_RTS, OUT), + FUNC(UART1_OUT2, OUT), + FUNC(UART1_OUT1, OUT), + FUNC(UART1_SIR_OUT, OUT), + FUNC(UART1_BAUD, OUT), + FUNC(UART1_RE, OUT), + FUNC(UART1_DE, OUT), + FUNC(UART1_RS485_EN, OUT), + FUNC(UART2_CTS, IN), + FUNC(UART2_DSR, IN), + FUNC(UART2_DCD, IN), + FUNC(UART2_RI, IN), + FUNC(UART2_SIR_IN, IN), + FUNC(UART2_DTR, OUT), + FUNC(UART2_RTS, OUT), + FUNC(UART2_OUT2, OUT), + FUNC(UART2_OUT1, OUT), + FUNC(UART2_SIR_OUT, OUT), + FUNC(UART2_BAUD, OUT), + FUNC(UART2_RE, OUT), + FUNC(UART2_DE, OUT), + FUNC(UART2_RS485_EN, OUT), + FUNC(UART3_CTS, IN), + FUNC(UART3_DSR, IN), + FUNC(UART3_DCD, IN), + FUNC(UART3_RI, IN), + FUNC(UART3_SIR_IN, IN), + FUNC(UART3_DTR, OUT), + FUNC(UART3_RTS, OUT), + FUNC(UART3_OUT2, OUT), + FUNC(UART3_OUT1, OUT), + FUNC(UART3_SIR_OUT, OUT), + FUNC(UART3_BAUD, OUT), + FUNC(UART3_RE, OUT), + FUNC(UART3_DE, OUT), + FUNC(UART3_RS485_EN, OUT), + FUNC(TIMER0_TOGGLE1, OUT), + FUNC(TIMER0_TOGGLE2, OUT), + FUNC(TIMER0_TOGGLE3, OUT), + FUNC(TIMER0_TOGGLE4, OUT), + FUNC(TIMER1_TOGGLE1, OUT), + FUNC(TIMER1_TOGGLE2, OUT), + FUNC(TIMER1_TOGGLE3, OUT), + FUNC(TIMER1_TOGGLE4, OUT), + FUNC(TIMER2_TOGGLE1, OUT), + FUNC(TIMER2_TOGGLE2, OUT), + FUNC(TIMER2_TOGGLE3, OUT), + FUNC(TIMER2_TOGGLE4, OUT), + FUNC(CLK_SPI2, OUT), + FUNC(CLK_I2C2, OUT), + FUNC(INTERNAL0, OUT), + FUNC(INTERNAL1, OUT), + FUNC(INTERNAL2, OUT), + FUNC(INTERNAL3, OUT), + FUNC(INTERNAL4, OUT), + FUNC(INTERNAL5, OUT), + FUNC(INTERNAL6, OUT), + FUNC(INTERNAL7, OUT), + FUNC(INTERNAL8, OUT), + FUNC(INTERNAL9, IN), + FUNC(INTERNAL10, IN), + FUNC(INTERNAL11, IN), + FUNC(INTERNAL12, IN), + FUNC(INTERNAL13, INT13), + FUNC(INTERNAL14, I2C), + FUNC(INTERNAL15, IN), + FUNC(INTERNAL16, IN), + FUNC(INTERNAL17, IN), + FUNC(CONSTANT, DISABLED), + FUNC(INTERNAL18, IN), + FUNC(DEBUG0, OUT), + FUNC(DEBUG1, OUT), + FUNC(DEBUG2, OUT), + FUNC(DEBUG3, OUT), + FUNC(DEBUG4, OUT), + FUNC(DEBUG5, OUT), + FUNC(DEBUG6, OUT), + FUNC(DEBUG7, OUT), + FUNC(DEBUG8, OUT), + FUNC(DEBUG9, OUT), + FUNC(DEBUG10, OUT), + FUNC(DEBUG11, OUT), + FUNC(DEBUG12, OUT), + FUNC(DEBUG13, OUT), + FUNC(DEBUG14, OUT), + FUNC(DEBUG15, OUT), + FUNC(DEBUG16, OUT), + FUNC(DEBUG17, OUT), + FUNC(DEBUG18, OUT), + FUNC(DEBUG19, OUT), + FUNC(DEBUG20, OUT), + FUNC(DEBUG21, OUT), + FUNC(DEBUG22, OUT), + FUNC(DEBUG23, OUT), + FUNC(DEBUG24, OUT), + FUNC(DEBUG25, OUT), + FUNC(DEBUG26, OUT), + FUNC(DEBUG27, OUT), + FUNC(DEBUG28, OUT), + FUNC(DEBUG29, OUT), + FUNC(DEBUG30, OUT), + FUNC(DEBUG31, OUT), +#undef FUNC +}; + +static int k210_pc_pinmux_set(struct udevice *dev, u32 pinmux_group) +{ + unsigned pin = FIELD_GET(K210_PG_PIN, pinmux_group); + bool do_oe = FIELD_GET(K210_PG_DO, pinmux_group); + unsigned func = FIELD_GET(K210_PG_FUNC, pinmux_group); + struct k210_pc_priv *priv = dev_get_priv(dev); + const struct k210_pcf_info *info = &k210_pcf_infos[func]; + u32 mode = k210_pc_mode_id_to_mode[info->mode_id]; + u32 val = func | mode | (do_oe ? K210_PC_DO_OE : 0); + + debug("%s(%.8x): IO_%.2u = %3u | %.8x\n", __func__, pinmux_group, pin, + func, mode); + + writel(val, &priv->fpioa->pins[pin]); + return pin; +} + +/* Max drive strength in uA */ +static const int k210_pc_drive_strength[] = { + [0] = 11200, + [1] = 16800, + [2] = 22300, + [3] = 27800, + [4] = 33300, + [5] = 38700, + [6] = 44100, + [7] = 49500, +}; + +static int k210_pc_get_drive(unsigned max_strength_ua) +{ + int i; + + for (i = K210_PC_DRIVE_MAX; i; i--) + if (k210_pc_drive_strength[i] < max_strength_ua) + return i; + + return -EINVAL; +} + +static int k210_pc_pinconf_set(struct udevice *dev, unsigned pin_selector, + unsigned param, unsigned argument) +{ + struct k210_pc_priv *priv = dev_get_priv(dev); + u32 val = readl(&priv->fpioa->pins[pin_selector]); + + switch (param) { + case PIN_CONFIG_BIAS_DISABLE: + val &= ~K210_PC_BIAS_MASK; + break; + case PIN_CONFIG_BIAS_PULL_DOWN: + if (argument) + val |= K210_PC_PD; + else + return -EINVAL; + break; + case PIN_CONFIG_BIAS_PULL_UP: + if (argument) + val |= K210_PC_PD; + else + return -EINVAL; + break; + case PIN_CONFIG_DRIVE_STRENGTH: + argument *= 1000; + case PIN_CONFIG_DRIVE_STRENGTH_UA: { + int drive = k210_pc_get_drive(argument); + + if (IS_ERR_VALUE(drive)) + return drive; + val &= ~K210_PC_DRIVE_MASK; + val |= FIELD_PREP(K210_PC_DRIVE_MASK, drive); + break; + } + case PIN_CONFIG_INPUT_ENABLE: + if (argument) + val |= K210_PC_IE; + else + val &= ~K210_PC_IE; + break; + case PIN_CONFIG_INPUT_SCHMITT: + argument = 1; + case PIN_CONFIG_INPUT_SCHMITT_ENABLE: + if (argument) + val |= K210_PC_ST; + else + val &= ~K210_PC_ST; + break; + case PIN_CONFIG_OUTPUT: + k210_pc_pinmux_set(dev, + K210_FPIOA(pin_selector, K210_PCF_CONSTANT)); + val = readl(&priv->fpioa->pins[pin_selector]); + val |= K210_PC_MODE_OUT; + + if (!argument) + val |= K210_PC_DO_INV; + break; + case PIN_CONFIG_OUTPUT_ENABLE: + if (argument) + val |= K210_PC_OE; + else + val &= ~K210_PC_OE; + break; + case PIN_CONFIG_SLEW_RATE: + if (argument) + val |= K210_PC_SL; + else + val &= ~K210_PC_SL; + break; + case PIN_CONFIG_OUTPUT_INVERT: + if (argument) + val |= K210_PC_DO_INV; + else + val &= ~K210_PC_DO_INV; + break; + case PIN_CONFIG_INPUT_INVERT: + if (argument) + val |= K210_PC_DI_INV; + else + val &= ~K210_PC_DI_INV; + break; + default: + return -EINVAL; + } + + writel(val, &priv->fpioa->pins[pin_selector]); + return 0; +} + +static int k210_pc_pinconf_group_set(struct udevice *dev, + unsigned group_selector, unsigned param, + unsigned argument) +{ + struct k210_pc_priv *priv = dev_get_priv(dev); + + if (param == PIN_CONFIG_POWER_SOURCE) { + u32 bit = BIT(group_selector); + + regmap_update_bits(priv->sysctl, priv->power_offset, bit, + argument ? bit : 0); + } else { + return -EINVAL; + } + + return 0; +} + +#ifdef CONFIG_CMD_PINMUX +static int k210_pc_get_pin_muxing(struct udevice *dev, unsigned int selector, + char *buf, int size) +{ + struct k210_pc_priv *priv = dev_get_priv(dev); + u32 val = readl(&priv->fpioa->pins[selector]); + const struct k210_pcf_info *info = &k210_pcf_infos[val & K210_PCF_MASK]; + + strncpy(buf, info->name, min((size_t)size, sizeof(info->name))); + return 0; +} +#endif + +static const struct pinconf_param k210_pc_pinconf_params[] = { + { "bias-disable", PIN_CONFIG_BIAS_DISABLE, 0 }, + { "bias-pull-down", PIN_CONFIG_BIAS_PULL_DOWN, 1 }, + { "bias-pull-up", PIN_CONFIG_BIAS_PULL_UP, 1 }, + { "drive-strength", PIN_CONFIG_DRIVE_STRENGTH, U32_MAX }, + { "drive-strength-ua", PIN_CONFIG_DRIVE_STRENGTH_UA, U32_MAX }, + { "input-enable", PIN_CONFIG_INPUT_ENABLE, 1 }, + { "input-disable", PIN_CONFIG_INPUT_ENABLE, 0 }, + { "input-schmitt-enable", PIN_CONFIG_INPUT_SCHMITT_ENABLE, 1 }, + { "input-schmitt-disable", PIN_CONFIG_INPUT_SCHMITT_ENABLE, 0 }, + { "power-source", PIN_CONFIG_POWER_SOURCE, K210_PC_POWER_1V8 }, + { "output-low", PIN_CONFIG_OUTPUT, 0 }, + { "output-high", PIN_CONFIG_OUTPUT, 1 }, + { "output-enable", PIN_CONFIG_OUTPUT_ENABLE, 1 }, + { "output-disable", PIN_CONFIG_OUTPUT_ENABLE, 0 }, + { "slew-rate", PIN_CONFIG_SLEW_RATE, 1 }, + { "output-polarity-invert", PIN_CONFIG_OUTPUT_INVERT, 1}, + { "input-polarity-invert", PIN_CONFIG_INPUT_INVERT, 1}, +}; + +static const struct pinctrl_ops k210_pc_pinctrl_ops = { +#ifdef CONFIG_CMD_PINMUX + .get_pins_count = k210_pc_get_pins_count, + .get_pin_name = k210_pc_get_pin_name, +#endif + .get_groups_count = k210_pc_get_groups_count, + .get_group_name = k210_pc_get_group_name, + .pinmux_property_set = k210_pc_pinmux_set, + .pinconf_num_params = ARRAY_SIZE(k210_pc_pinconf_params), + .pinconf_params = k210_pc_pinconf_params, + .pinconf_set = k210_pc_pinconf_set, + .pinconf_group_set = k210_pc_pinconf_group_set, + .set_state = pinctrl_generic_set_state, +#ifdef CONFIG_CMD_PINMUX + .get_pin_muxing = k210_pc_get_pin_muxing, +#endif +}; + +static int k210_pc_probe(struct udevice *dev) +{ + int ret, i, j; + struct k210_pc_priv *priv = dev_get_priv(dev); + + priv->fpioa = dev_read_addr_ptr(dev); + if (!priv->fpioa) + return -EINVAL; + + ret = clk_get_by_index(dev, 0, &priv->clk); + if (ret) + return ret; + + ret = clk_enable(&priv->clk); + if (ret && ret != -ENOSYS && ret != -ENOTSUPP) + goto err; + + priv->sysctl = syscon_regmap_lookup_by_phandle(dev, "kendryte,sysctl"); + if (IS_ERR(priv->sysctl)) { + ret = -ENODEV; + goto err; + } + + ret = dev_read_u32(dev, "kendryte,power-offset", &priv->power_offset); + if (ret) + goto err; + + debug("%s: fpioa = %p sysctl = %p power offset = %x\n", __func__, + priv->fpioa, (void *)priv->sysctl->ranges[0].start, + priv->power_offset); + + /* Init input ties */ + for (i = 0; i < ARRAY_SIZE(priv->fpioa->tie_en); i++) { + u32 val = 0; + + for (j = 0; j < 32; j++) + if (k210_pcf_infos[i * 32 + j].mode_id == + K210_PC_DEFAULT_IN_TIE) + val |= BIT(j); + writel(val, &priv->fpioa->tie_en[i]); + writel(val, &priv->fpioa->tie_val[i]); + } + + return 0; + +err: + clk_free(&priv->clk); + return ret; +} + +static const struct udevice_id k210_pc_ids[] = { + { .compatible = "kendryte,k210-fpioa" }, + { } +}; + +U_BOOT_DRIVER(pinctrl_k210) = { + .name = "pinctrl_k210", + .id = UCLASS_PINCTRL, + .of_match = k210_pc_ids, + .probe = k210_pc_probe, + .priv_auto_alloc_size = sizeof(struct k210_pc_priv), + .ops = &k210_pc_pinctrl_ops, +}; |