Message ID | 20210112005848.199951-3-damien.lemoal@wdc.com (mailing list archive) |
---|---|
State | New, archived |
Headers | show |
Series | RISC-V Kendryte K210 support improvements | expand |
On Mon, 11 Jan 2021 16:58:40 PST (-0800), Damien Le Moal wrote: > Add the pinctrl-k210.c pinctrl driver for the Canaan Kendryte K210 > field programmable IO array (FPIOA) to allow configuring the SoC pin > functions. The K210 has 48 programmable pins which can take any of 256 > possible functions. > > This patch is inspired from the k210 pinctrl driver for the u-boot > project and contains many direct contributions from Sean Anderson. > > The MAINTAINERS file is updated, adding the entry "CANAAN/KENDRYTE K210 > SOC FPIOA DRIVER" with myself listed as maintainer for this driver. > > Cc: Linus Walleij <linus.walleij@linaro.org> > Cc: linux-gpio@vger.kernel.org IDK if something's screwed up on my end, but I don't see these CCs locally. Lore does have it in the GPIO list, though, so maybe it made it. Either way, if I'm going to take this through the RISC-V tree then I'd much prefer to have at least an Ack. I'd also be happy to have it go through the GPIO tree, as this is largely stand-alone -- the DT bindings are on riscv/for-next, but I'd be happy to split them out into a shared tag or just put them in through your tree if that's easier. > Signed-off-by: Sean Anderson <seanga2@gmail.com> > Signed-off-by: Damien Le Moal <damien.lemoal@wdc.com> > --- > MAINTAINERS | 7 + > arch/riscv/Kconfig.socs | 1 + > drivers/pinctrl/Kconfig | 13 + > drivers/pinctrl/Makefile | 1 + > drivers/pinctrl/pinctrl-k210.c | 985 +++++++++++++++++++++++++++++++++ > 5 files changed, 1007 insertions(+) > create mode 100644 drivers/pinctrl/pinctrl-k210.c > > diff --git a/MAINTAINERS b/MAINTAINERS > index 637b79eba693..1a7a1e4092e2 100644 > --- a/MAINTAINERS > +++ b/MAINTAINERS > @@ -3860,6 +3860,13 @@ W: https://github.com/Cascoda/ca8210-linux.git > F: Documentation/devicetree/bindings/net/ieee802154/ca8210.txt > F: drivers/net/ieee802154/ca8210.c > > +CANAAN/KENDRYTE K210 SOC FPIOA DRIVER > +M: Damien Le Moal <damien.lemoal@wdc.com> > +L: linux-riscv@lists.infradead.org > +L: linux-gpio@vger.kernel.org (pinctrl driver) > +F: Documentation/devicetree/bindings/pinctrl/canaan,k210-fpioa.yaml > +F: drivers/pinctrl/pinctrl-k210.c > + > CANAAN/KENDRYTE K210 SOC RESET CONTROLLER DRIVER > M: Damien Le Moal <damien.lemoal@wdc.com> > L: linux-kernel@vger.kernel.org > diff --git a/arch/riscv/Kconfig.socs b/arch/riscv/Kconfig.socs > index 57e53219c500..6402746c68f3 100644 > --- a/arch/riscv/Kconfig.socs > +++ b/arch/riscv/Kconfig.socs > @@ -30,6 +30,7 @@ config SOC_CANAAN > select SERIAL_SIFIVE_CONSOLE if TTY > select SIFIVE_PLIC > select ARCH_HAS_RESET_CONTROLLER > + select PINCTRL > help > This enables support for Canaan Kendryte K210 SoC platform hardware. > > diff --git a/drivers/pinctrl/Kconfig b/drivers/pinctrl/Kconfig > index d4b2f2e2ed75..cd437e3cc255 100644 > --- a/drivers/pinctrl/Kconfig > +++ b/drivers/pinctrl/Kconfig > @@ -394,6 +394,19 @@ config PINCTRL_MICROCHIP_SGPIO > connect control signals from SFP modules and to act as an > LED controller. > > +config PINCTRL_K210 > + bool "Pinctrl driver for the Canaan Kendryte K210 SoC" > + depends on RISCV && SOC_CANAAN && OF > + select GENERIC_PINMUX_FUNCTIONS > + select GENERIC_PINCONF > + select GPIOLIB > + select OF_GPIO > + select REGMAP_MMIO > + default SOC_CANAAN > + help > + Add support for the Canaan Kendryte K210 RISC-V SOC Field > + Programmable IO Array (FPIOA) controller. > + > source "drivers/pinctrl/actions/Kconfig" > source "drivers/pinctrl/aspeed/Kconfig" > source "drivers/pinctrl/bcm/Kconfig" > diff --git a/drivers/pinctrl/Makefile b/drivers/pinctrl/Makefile > index 5bb9bb6cc3ce..152c8fe51726 100644 > --- a/drivers/pinctrl/Makefile > +++ b/drivers/pinctrl/Makefile > @@ -48,6 +48,7 @@ obj-$(CONFIG_PINCTRL_RK805) += pinctrl-rk805.o > obj-$(CONFIG_PINCTRL_OCELOT) += pinctrl-ocelot.o > obj-$(CONFIG_PINCTRL_MICROCHIP_SGPIO) += pinctrl-microchip-sgpio.o > obj-$(CONFIG_PINCTRL_EQUILIBRIUM) += pinctrl-equilibrium.o > +obj-$(CONFIG_PINCTRL_K210) += pinctrl-k210.o > > obj-y += actions/ > obj-$(CONFIG_ARCH_ASPEED) += aspeed/ > diff --git a/drivers/pinctrl/pinctrl-k210.c b/drivers/pinctrl/pinctrl-k210.c > new file mode 100644 > index 000000000000..8a733cf77ba0 > --- /dev/null > +++ b/drivers/pinctrl/pinctrl-k210.c > @@ -0,0 +1,985 @@ > +// SPDX-License-Identifier: GPL-2.0-or-later > +/* > + * Copyright (C) 2020 Sean Anderson <seanga2@gmail.com> > + * Copyright (c) 2020 Western Digital Corporation or its affiliates. > + */ > +#include <linux/io.h> > +#include <linux/of_device.h> > +#include <linux/clk.h> > +#include <linux/mfd/syscon.h> > +#include <linux/platform_device.h> > +#include <linux/bitfield.h> > +#include <linux/regmap.h> > +#include <linux/slab.h> > +#include <linux/pinctrl/pinctrl.h> > +#include <linux/pinctrl/pinmux.h> > +#include <linux/pinctrl/pinconf.h> > +#include <linux/pinctrl/pinconf-generic.h> > +#include <linux/io.h> > + > +#include <dt-bindings/pinctrl/k210-fpioa.h> > + > +#include "core.h" > +#include "pinconf.h" > +#include "pinctrl-utils.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 Output Enable */ > +#define K210_PC_DO_OE BIT(14) /* set Data Out to Output Enable sig */ > +#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 */ > +/* Same semantics as OE above */ > +#define K210_PC_IE BIT(20) /* Input Enable */ > +#define K210_PC_IE_INV BIT(21) /* INVert 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_SL | \ > + K210_PC_OE | K210_PC_PU) > +#define K210_PC_MODE_SCCB (K210_PC_MODE_I2C | \ > + K210_PC_OE_INV | K210_PC_IE_INV) > +#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) > + > +/* > + * struct k210_fpioa: Kendryte K210 FPIOA memory mapped registers > + * @pins: 48 32-bits IO pin registers > + * @tie_en: 256 (one per function) input tie enable bits > + * @tie_val: 256 (one per function) input tie value bits > + */ > +struct k210_fpioa { > + u32 pins[48]; > + u32 tie_en[8]; > + u32 tie_val[8]; > +}; > + > +struct k210_fpioa_data { > + > + struct device *dev; > + struct pinctrl_dev *pctl; > + > + struct k210_fpioa __iomem *fpioa; > + struct regmap *sysctl_map; > + u32 power_offset; > + struct clk *clk; > + struct clk *pclk; > +}; > + > +#define K210_PIN_NAME(i) ("IO_" #i) > +#define K210_PIN(i) [(i)] = PINCTRL_PIN((i), K210_PIN_NAME(i)) > + > +static const struct pinctrl_pin_desc k210_pins[] = { > + K210_PIN(0), K210_PIN(1), K210_PIN(2), > + K210_PIN(3), K210_PIN(4), K210_PIN(5), > + K210_PIN(6), K210_PIN(7), K210_PIN(8), > + K210_PIN(9), K210_PIN(10), K210_PIN(11), > + K210_PIN(12), K210_PIN(13), K210_PIN(14), > + K210_PIN(15), K210_PIN(16), K210_PIN(17), > + K210_PIN(18), K210_PIN(19), K210_PIN(20), > + K210_PIN(21), K210_PIN(22), K210_PIN(23), > + K210_PIN(24), K210_PIN(25), K210_PIN(26), > + K210_PIN(27), K210_PIN(28), K210_PIN(29), > + K210_PIN(30), K210_PIN(31), K210_PIN(32), > + K210_PIN(33), K210_PIN(34), K210_PIN(35), > + K210_PIN(36), K210_PIN(37), K210_PIN(38), > + K210_PIN(39), K210_PIN(40), K210_PIN(41), > + K210_PIN(42), K210_PIN(43), K210_PIN(44), > + K210_PIN(45), K210_PIN(46), K210_PIN(47) > +}; > + > +#define K210_NPINS ARRAY_SIZE(k210_pins) > + > +/* > + * Pin groups: each of the 48 programmable pins is a group. > + * To this are added 8 power domain groups, which for the purposes of > + * the pin subsystem, contain no pins. The power domain groups only exist > + * to set the power level. The id should never be used (since there are > + * no pins 48-55). > + */ > +static const char *const k210_group_names[] = { > + /* The first 48 groups are for pins, one each */ > + K210_PIN_NAME(0), K210_PIN_NAME(1), K210_PIN_NAME(2), > + K210_PIN_NAME(3), K210_PIN_NAME(4), K210_PIN_NAME(5), > + K210_PIN_NAME(6), K210_PIN_NAME(7), K210_PIN_NAME(8), > + K210_PIN_NAME(9), K210_PIN_NAME(10), K210_PIN_NAME(11), > + K210_PIN_NAME(12), K210_PIN_NAME(13), K210_PIN_NAME(14), > + K210_PIN_NAME(15), K210_PIN_NAME(16), K210_PIN_NAME(17), > + K210_PIN_NAME(18), K210_PIN_NAME(19), K210_PIN_NAME(20), > + K210_PIN_NAME(21), K210_PIN_NAME(22), K210_PIN_NAME(23), > + K210_PIN_NAME(24), K210_PIN_NAME(25), K210_PIN_NAME(26), > + K210_PIN_NAME(27), K210_PIN_NAME(28), K210_PIN_NAME(29), > + K210_PIN_NAME(30), K210_PIN_NAME(31), K210_PIN_NAME(32), > + K210_PIN_NAME(33), K210_PIN_NAME(34), K210_PIN_NAME(35), > + K210_PIN_NAME(36), K210_PIN_NAME(37), K210_PIN_NAME(38), > + K210_PIN_NAME(39), K210_PIN_NAME(40), K210_PIN_NAME(41), > + K210_PIN_NAME(42), K210_PIN_NAME(43), K210_PIN_NAME(44), > + K210_PIN_NAME(45), K210_PIN_NAME(46), K210_PIN_NAME(47), > + [48] = "A0", [49] = "A1", [50] = "A2", > + [51] = "B3", [52] = "B4", [53] = "B5", > + [54] = "C6", [55] = "C7" > +}; > + > +#define K210_NGROUPS ARRAY_SIZE(k210_group_names) > + > +enum k210_pinctrl_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_SCCB, > + K210_PC_DEFAULT_SPI, > + K210_PC_DEFAULT_GPIO, > + K210_PC_DEFAULT_INT13, > +}; > + > +#define K210_PC_DEFAULT(mode) \ > + [K210_PC_DEFAULT_##mode] = K210_PC_MODE_##mode > + > +static const u32 k210_pinconf_mode_id_to_mode[] = { > + [K210_PC_DEFAULT_DISABLED] = 0, > + K210_PC_DEFAULT(IN), > + [K210_PC_DEFAULT_IN_TIE] = K210_PC_MODE_IN, > + K210_PC_DEFAULT(OUT), > + K210_PC_DEFAULT(I2C), > + K210_PC_DEFAULT(SCCB), > + K210_PC_DEFAULT(SPI), > + K210_PC_DEFAULT(GPIO), > + [K210_PC_DEFAULT_INT13] = K210_PC_MODE_IN | K210_PC_PU, > +}; > + > +#undef DEFAULT > + > +/* > + * Pin functions configuration information. > + */ > +struct k210_pcf_info { > + char name[15]; > + u8 mode_id; > +}; > + > +#define K210_FUNC(id, mode) \ > + [K210_PCF_##id] = { \ > + .name = #id, \ > + .mode_id = K210_PC_DEFAULT_##mode \ > + } > + > +static const struct k210_pcf_info k210_pcf_infos[] = { > + K210_FUNC(JTAG_TCLK, IN), > + K210_FUNC(JTAG_TDI, IN), > + K210_FUNC(JTAG_TMS, IN), > + K210_FUNC(JTAG_TDO, OUT), > + K210_FUNC(SPI0_D0, SPI), > + K210_FUNC(SPI0_D1, SPI), > + K210_FUNC(SPI0_D2, SPI), > + K210_FUNC(SPI0_D3, SPI), > + K210_FUNC(SPI0_D4, SPI), > + K210_FUNC(SPI0_D5, SPI), > + K210_FUNC(SPI0_D6, SPI), > + K210_FUNC(SPI0_D7, SPI), > + K210_FUNC(SPI0_SS0, OUT), > + K210_FUNC(SPI0_SS1, OUT), > + K210_FUNC(SPI0_SS2, OUT), > + K210_FUNC(SPI0_SS3, OUT), > + K210_FUNC(SPI0_ARB, IN_TIE), > + K210_FUNC(SPI0_SCLK, OUT), > + K210_FUNC(UARTHS_RX, IN), > + K210_FUNC(UARTHS_TX, OUT), > + K210_FUNC(RESV6, IN), > + K210_FUNC(RESV7, IN), > + K210_FUNC(CLK_SPI1, OUT), > + K210_FUNC(CLK_I2C1, OUT), > + K210_FUNC(GPIOHS0, GPIO), > + K210_FUNC(GPIOHS1, GPIO), > + K210_FUNC(GPIOHS2, GPIO), > + K210_FUNC(GPIOHS3, GPIO), > + K210_FUNC(GPIOHS4, GPIO), > + K210_FUNC(GPIOHS5, GPIO), > + K210_FUNC(GPIOHS6, GPIO), > + K210_FUNC(GPIOHS7, GPIO), > + K210_FUNC(GPIOHS8, GPIO), > + K210_FUNC(GPIOHS9, GPIO), > + K210_FUNC(GPIOHS10, GPIO), > + K210_FUNC(GPIOHS11, GPIO), > + K210_FUNC(GPIOHS12, GPIO), > + K210_FUNC(GPIOHS13, GPIO), > + K210_FUNC(GPIOHS14, GPIO), > + K210_FUNC(GPIOHS15, GPIO), > + K210_FUNC(GPIOHS16, GPIO), > + K210_FUNC(GPIOHS17, GPIO), > + K210_FUNC(GPIOHS18, GPIO), > + K210_FUNC(GPIOHS19, GPIO), > + K210_FUNC(GPIOHS20, GPIO), > + K210_FUNC(GPIOHS21, GPIO), > + K210_FUNC(GPIOHS22, GPIO), > + K210_FUNC(GPIOHS23, GPIO), > + K210_FUNC(GPIOHS24, GPIO), > + K210_FUNC(GPIOHS25, GPIO), > + K210_FUNC(GPIOHS26, GPIO), > + K210_FUNC(GPIOHS27, GPIO), > + K210_FUNC(GPIOHS28, GPIO), > + K210_FUNC(GPIOHS29, GPIO), > + K210_FUNC(GPIOHS30, GPIO), > + K210_FUNC(GPIOHS31, GPIO), > + K210_FUNC(GPIO0, GPIO), > + K210_FUNC(GPIO1, GPIO), > + K210_FUNC(GPIO2, GPIO), > + K210_FUNC(GPIO3, GPIO), > + K210_FUNC(GPIO4, GPIO), > + K210_FUNC(GPIO5, GPIO), > + K210_FUNC(GPIO6, GPIO), > + K210_FUNC(GPIO7, GPIO), > + K210_FUNC(UART1_RX, IN), > + K210_FUNC(UART1_TX, OUT), > + K210_FUNC(UART2_RX, IN), > + K210_FUNC(UART2_TX, OUT), > + K210_FUNC(UART3_RX, IN), > + K210_FUNC(UART3_TX, OUT), > + K210_FUNC(SPI1_D0, SPI), > + K210_FUNC(SPI1_D1, SPI), > + K210_FUNC(SPI1_D2, SPI), > + K210_FUNC(SPI1_D3, SPI), > + K210_FUNC(SPI1_D4, SPI), > + K210_FUNC(SPI1_D5, SPI), > + K210_FUNC(SPI1_D6, SPI), > + K210_FUNC(SPI1_D7, SPI), > + K210_FUNC(SPI1_SS0, OUT), > + K210_FUNC(SPI1_SS1, OUT), > + K210_FUNC(SPI1_SS2, OUT), > + K210_FUNC(SPI1_SS3, OUT), > + K210_FUNC(SPI1_ARB, IN_TIE), > + K210_FUNC(SPI1_SCLK, OUT), > + K210_FUNC(SPI2_D0, SPI), > + K210_FUNC(SPI2_SS, IN), > + K210_FUNC(SPI2_SCLK, IN), > + K210_FUNC(I2S0_MCLK, OUT), > + K210_FUNC(I2S0_SCLK, OUT), > + K210_FUNC(I2S0_WS, OUT), > + K210_FUNC(I2S0_IN_D0, IN), > + K210_FUNC(I2S0_IN_D1, IN), > + K210_FUNC(I2S0_IN_D2, IN), > + K210_FUNC(I2S0_IN_D3, IN), > + K210_FUNC(I2S0_OUT_D0, OUT), > + K210_FUNC(I2S0_OUT_D1, OUT), > + K210_FUNC(I2S0_OUT_D2, OUT), > + K210_FUNC(I2S0_OUT_D3, OUT), > + K210_FUNC(I2S1_MCLK, OUT), > + K210_FUNC(I2S1_SCLK, OUT), > + K210_FUNC(I2S1_WS, OUT), > + K210_FUNC(I2S1_IN_D0, IN), > + K210_FUNC(I2S1_IN_D1, IN), > + K210_FUNC(I2S1_IN_D2, IN), > + K210_FUNC(I2S1_IN_D3, IN), > + K210_FUNC(I2S1_OUT_D0, OUT), > + K210_FUNC(I2S1_OUT_D1, OUT), > + K210_FUNC(I2S1_OUT_D2, OUT), > + K210_FUNC(I2S1_OUT_D3, OUT), > + K210_FUNC(I2S2_MCLK, OUT), > + K210_FUNC(I2S2_SCLK, OUT), > + K210_FUNC(I2S2_WS, OUT), > + K210_FUNC(I2S2_IN_D0, IN), > + K210_FUNC(I2S2_IN_D1, IN), > + K210_FUNC(I2S2_IN_D2, IN), > + K210_FUNC(I2S2_IN_D3, IN), > + K210_FUNC(I2S2_OUT_D0, OUT), > + K210_FUNC(I2S2_OUT_D1, OUT), > + K210_FUNC(I2S2_OUT_D2, OUT), > + K210_FUNC(I2S2_OUT_D3, OUT), > + K210_FUNC(RESV0, DISABLED), > + K210_FUNC(RESV1, DISABLED), > + K210_FUNC(RESV2, DISABLED), > + K210_FUNC(RESV3, DISABLED), > + K210_FUNC(RESV4, DISABLED), > + K210_FUNC(RESV5, DISABLED), > + K210_FUNC(I2C0_SCLK, I2C), > + K210_FUNC(I2C0_SDA, I2C), > + K210_FUNC(I2C1_SCLK, I2C), > + K210_FUNC(I2C1_SDA, I2C), > + K210_FUNC(I2C2_SCLK, I2C), > + K210_FUNC(I2C2_SDA, I2C), > + K210_FUNC(DVP_XCLK, OUT), > + K210_FUNC(DVP_RST, OUT), > + K210_FUNC(DVP_PWDN, OUT), > + K210_FUNC(DVP_VSYNC, IN), > + K210_FUNC(DVP_HSYNC, IN), > + K210_FUNC(DVP_PCLK, IN), > + K210_FUNC(DVP_D0, IN), > + K210_FUNC(DVP_D1, IN), > + K210_FUNC(DVP_D2, IN), > + K210_FUNC(DVP_D3, IN), > + K210_FUNC(DVP_D4, IN), > + K210_FUNC(DVP_D5, IN), > + K210_FUNC(DVP_D6, IN), > + K210_FUNC(DVP_D7, IN), > + K210_FUNC(SCCB_SCLK, SCCB), > + K210_FUNC(SCCB_SDA, SCCB), > + K210_FUNC(UART1_CTS, IN), > + K210_FUNC(UART1_DSR, IN), > + K210_FUNC(UART1_DCD, IN), > + K210_FUNC(UART1_RI, IN), > + K210_FUNC(UART1_SIR_IN, IN), > + K210_FUNC(UART1_DTR, OUT), > + K210_FUNC(UART1_RTS, OUT), > + K210_FUNC(UART1_OUT2, OUT), > + K210_FUNC(UART1_OUT1, OUT), > + K210_FUNC(UART1_SIR_OUT, OUT), > + K210_FUNC(UART1_BAUD, OUT), > + K210_FUNC(UART1_RE, OUT), > + K210_FUNC(UART1_DE, OUT), > + K210_FUNC(UART1_RS485_EN, OUT), > + K210_FUNC(UART2_CTS, IN), > + K210_FUNC(UART2_DSR, IN), > + K210_FUNC(UART2_DCD, IN), > + K210_FUNC(UART2_RI, IN), > + K210_FUNC(UART2_SIR_IN, IN), > + K210_FUNC(UART2_DTR, OUT), > + K210_FUNC(UART2_RTS, OUT), > + K210_FUNC(UART2_OUT2, OUT), > + K210_FUNC(UART2_OUT1, OUT), > + K210_FUNC(UART2_SIR_OUT, OUT), > + K210_FUNC(UART2_BAUD, OUT), > + K210_FUNC(UART2_RE, OUT), > + K210_FUNC(UART2_DE, OUT), > + K210_FUNC(UART2_RS485_EN, OUT), > + K210_FUNC(UART3_CTS, IN), > + K210_FUNC(UART3_DSR, IN), > + K210_FUNC(UART3_DCD, IN), > + K210_FUNC(UART3_RI, IN), > + K210_FUNC(UART3_SIR_IN, IN), > + K210_FUNC(UART3_DTR, OUT), > + K210_FUNC(UART3_RTS, OUT), > + K210_FUNC(UART3_OUT2, OUT), > + K210_FUNC(UART3_OUT1, OUT), > + K210_FUNC(UART3_SIR_OUT, OUT), > + K210_FUNC(UART3_BAUD, OUT), > + K210_FUNC(UART3_RE, OUT), > + K210_FUNC(UART3_DE, OUT), > + K210_FUNC(UART3_RS485_EN, OUT), > + K210_FUNC(TIMER0_TOGGLE1, OUT), > + K210_FUNC(TIMER0_TOGGLE2, OUT), > + K210_FUNC(TIMER0_TOGGLE3, OUT), > + K210_FUNC(TIMER0_TOGGLE4, OUT), > + K210_FUNC(TIMER1_TOGGLE1, OUT), > + K210_FUNC(TIMER1_TOGGLE2, OUT), > + K210_FUNC(TIMER1_TOGGLE3, OUT), > + K210_FUNC(TIMER1_TOGGLE4, OUT), > + K210_FUNC(TIMER2_TOGGLE1, OUT), > + K210_FUNC(TIMER2_TOGGLE2, OUT), > + K210_FUNC(TIMER2_TOGGLE3, OUT), > + K210_FUNC(TIMER2_TOGGLE4, OUT), > + K210_FUNC(CLK_SPI2, OUT), > + K210_FUNC(CLK_I2C2, OUT), > + K210_FUNC(INTERNAL0, OUT), > + K210_FUNC(INTERNAL1, OUT), > + K210_FUNC(INTERNAL2, OUT), > + K210_FUNC(INTERNAL3, OUT), > + K210_FUNC(INTERNAL4, OUT), > + K210_FUNC(INTERNAL5, OUT), > + K210_FUNC(INTERNAL6, OUT), > + K210_FUNC(INTERNAL7, OUT), > + K210_FUNC(INTERNAL8, OUT), > + K210_FUNC(INTERNAL9, IN), > + K210_FUNC(INTERNAL10, IN), > + K210_FUNC(INTERNAL11, IN), > + K210_FUNC(INTERNAL12, IN), > + K210_FUNC(INTERNAL13, INT13), > + K210_FUNC(INTERNAL14, I2C), > + K210_FUNC(INTERNAL15, IN), > + K210_FUNC(INTERNAL16, IN), > + K210_FUNC(INTERNAL17, IN), > + K210_FUNC(CONSTANT, DISABLED), > + K210_FUNC(INTERNAL18, IN), > + K210_FUNC(DEBUG0, OUT), > + K210_FUNC(DEBUG1, OUT), > + K210_FUNC(DEBUG2, OUT), > + K210_FUNC(DEBUG3, OUT), > + K210_FUNC(DEBUG4, OUT), > + K210_FUNC(DEBUG5, OUT), > + K210_FUNC(DEBUG6, OUT), > + K210_FUNC(DEBUG7, OUT), > + K210_FUNC(DEBUG8, OUT), > + K210_FUNC(DEBUG9, OUT), > + K210_FUNC(DEBUG10, OUT), > + K210_FUNC(DEBUG11, OUT), > + K210_FUNC(DEBUG12, OUT), > + K210_FUNC(DEBUG13, OUT), > + K210_FUNC(DEBUG14, OUT), > + K210_FUNC(DEBUG15, OUT), > + K210_FUNC(DEBUG16, OUT), > + K210_FUNC(DEBUG17, OUT), > + K210_FUNC(DEBUG18, OUT), > + K210_FUNC(DEBUG19, OUT), > + K210_FUNC(DEBUG20, OUT), > + K210_FUNC(DEBUG21, OUT), > + K210_FUNC(DEBUG22, OUT), > + K210_FUNC(DEBUG23, OUT), > + K210_FUNC(DEBUG24, OUT), > + K210_FUNC(DEBUG25, OUT), > + K210_FUNC(DEBUG26, OUT), > + K210_FUNC(DEBUG27, OUT), > + K210_FUNC(DEBUG28, OUT), > + K210_FUNC(DEBUG29, OUT), > + K210_FUNC(DEBUG30, OUT), > + K210_FUNC(DEBUG31, OUT), > +}; > + > +#define PIN_CONFIG_OUTPUT_INVERT (PIN_CONFIG_END + 1) > +#define PIN_CONFIG_INPUT_INVERT (PIN_CONFIG_END + 2) > + > +static const struct pinconf_generic_params k210_pinconf_custom_params[] = { > + { "output-polarity-invert", PIN_CONFIG_OUTPUT_INVERT, 1 }, > + { "input-polarity-invert", PIN_CONFIG_INPUT_INVERT, 1 }, > +}; > + > +/* > + * Max drive strength in uA. > + */ > +static const int k210_pinconf_drive_strength[] = { > + [0] = 11200, > + [1] = 16800, > + [2] = 22300, > + [3] = 27800, > + [4] = 33300, > + [5] = 38700, > + [6] = 44100, > + [7] = 49500, > +}; > + > +static int k210_pinconf_get_drive(unsigned int max_strength_ua) > +{ > + int i; > + > + for (i = K210_PC_DRIVE_MAX; i; i--) { > + if (k210_pinconf_drive_strength[i] <= max_strength_ua) > + return i; > + } > + > + return -EINVAL; > +} > + > +static void k210_pinmux_set_pin_function(struct pinctrl_dev *pctldev, > + u32 pin, u32 func) > +{ > + struct k210_fpioa_data *pdata = pinctrl_dev_get_drvdata(pctldev); > + const struct k210_pcf_info *info = &k210_pcf_infos[func]; > + u32 mode = k210_pinconf_mode_id_to_mode[info->mode_id]; > + u32 val = func | mode; > + > + dev_dbg(pdata->dev, "set pin %u function %s (%u) -> 0x%08x\n", > + pin, info->name, func, val); > + > + writel(val, &pdata->fpioa->pins[pin]); > +} > + > +static int k210_pinconf_set_param(struct pinctrl_dev *pctldev, > + unsigned int pin, > + unsigned int param, unsigned int arg) > +{ > + struct k210_fpioa_data *pdata = pinctrl_dev_get_drvdata(pctldev); > + u32 val = readl(&pdata->fpioa->pins[pin]); > + int drive; > + > + dev_dbg(pdata->dev, "set pin %u param %u, arg 0x%x\n", > + pin, param, arg); > + > + switch (param) { > + case PIN_CONFIG_BIAS_DISABLE: > + val &= ~K210_PC_BIAS_MASK; > + break; > + case PIN_CONFIG_BIAS_PULL_DOWN: > + if (!arg) > + return -EINVAL; > + val |= K210_PC_PD; > + break; > + case PIN_CONFIG_BIAS_PULL_UP: > + if (!arg) > + return -EINVAL; > + val |= K210_PC_PD; > + break; > + case PIN_CONFIG_DRIVE_STRENGTH: > + arg *= 1000; > + fallthrough; > + case PIN_CONFIG_DRIVE_STRENGTH_UA: > + drive = k210_pinconf_get_drive(arg); > + if (drive < 0) > + return drive; > + val &= ~K210_PC_DRIVE_MASK; > + val |= FIELD_PREP(K210_PC_DRIVE_MASK, drive); > + break; > + case PIN_CONFIG_INPUT_ENABLE: > + if (arg) > + val |= K210_PC_IE; > + else > + val &= ~K210_PC_IE; > + break; > + case PIN_CONFIG_INPUT_SCHMITT_ENABLE: > + if (arg) > + val |= K210_PC_ST; > + else > + val &= ~K210_PC_ST; > + break; > + case PIN_CONFIG_OUTPUT: > + k210_pinmux_set_pin_function(pctldev, pin, K210_PCF_CONSTANT); > + val = readl(&pdata->fpioa->pins[pin]); > + val |= K210_PC_MODE_OUT; > + if (!arg) > + val |= K210_PC_DO_INV; > + break; > + case PIN_CONFIG_OUTPUT_ENABLE: > + if (arg) > + val |= K210_PC_OE; > + else > + val &= ~K210_PC_OE; > + break; > + case PIN_CONFIG_SLEW_RATE: > + if (arg) > + val |= K210_PC_SL; > + else > + val &= ~K210_PC_SL; > + break; > + case PIN_CONFIG_OUTPUT_INVERT: > + if (arg) > + val |= K210_PC_DO_INV; > + else > + val &= ~K210_PC_DO_INV; > + break; > + case PIN_CONFIG_INPUT_INVERT: > + if (arg) > + val |= K210_PC_DI_INV; > + else > + val &= ~K210_PC_DI_INV; > + break; > + default: > + return -EINVAL; > + } > + > + writel(val, &pdata->fpioa->pins[pin]); > + > + return 0; > +} > + > +static int k210_pinconf_set(struct pinctrl_dev *pctldev, unsigned int pin, > + unsigned long *configs, unsigned int num_configs) > +{ > + unsigned int param, arg; > + int i, ret; > + > + if (WARN_ON(pin >= K210_NPINS)) > + return -EINVAL; > + > + for (i = 0; i < num_configs; i++) { > + param = pinconf_to_config_param(configs[i]); > + arg = pinconf_to_config_argument(configs[i]); > + ret = k210_pinconf_set_param(pctldev, pin, param, arg); > + if (ret) > + return ret; > + } > + > + return 0; > +} > + > +static void k210_pinconf_dbg_show(struct pinctrl_dev *pctldev, > + struct seq_file *s, unsigned int pin) > +{ > + struct k210_fpioa_data *pdata = pinctrl_dev_get_drvdata(pctldev); > + > + seq_printf(s, "%#x", readl(&pdata->fpioa->pins[pin])); > +} > + > +static int k210_pinconf_group_set(struct pinctrl_dev *pctldev, > + unsigned int selector, unsigned long *configs, > + unsigned int num_configs) > +{ > + struct k210_fpioa_data *pdata = pinctrl_dev_get_drvdata(pctldev); > + unsigned int param, arg; > + u32 bit; > + int i; > + > + /* Pins should be configured with pinmux, not groups*/ > + if (selector < K210_NPINS) > + return -EINVAL; > + > + /* Otherwise it's a power domain */ > + for (i = 0; i < num_configs; i++) { > + param = pinconf_to_config_param(configs[i]); > + if (param != PIN_CONFIG_POWER_SOURCE) > + return -EINVAL; > + > + arg = pinconf_to_config_argument(configs[i]); > + bit = BIT(selector - K210_NPINS); > + regmap_update_bits(pdata->sysctl_map, > + pdata->power_offset, > + bit, arg ? bit : 0); > + } > + > + return 0; > +} > + > +static void k210_pinconf_group_dbg_show(struct pinctrl_dev *pctldev, > + struct seq_file *s, > + unsigned int selector) > +{ > + struct k210_fpioa_data *pdata = pinctrl_dev_get_drvdata(pctldev); > + int ret; > + u32 val; > + > + if (selector < K210_NPINS) > + return k210_pinconf_dbg_show(pctldev, s, selector); > + > + ret = regmap_read(pdata->sysctl_map, pdata->power_offset, &val); > + if (ret) { > + dev_err(pdata->dev, "Failed to read power reg\n"); > + return; > + } > + > + seq_printf(s, "%s: %s V", k210_group_names[selector], > + val & BIT(selector - K210_NPINS) ? "1.8" : "3.3"); > +} > + > +static const struct pinconf_ops k210_pinconf_ops = { > + .is_generic = true, > + .pin_config_set = k210_pinconf_set, > + .pin_config_group_set = k210_pinconf_group_set, > + .pin_config_dbg_show = k210_pinconf_dbg_show, > + .pin_config_group_dbg_show = k210_pinconf_group_dbg_show, > +}; > + > +static int k210_pinmux_get_function_count(struct pinctrl_dev *pctldev) > +{ > + return ARRAY_SIZE(k210_pcf_infos); > +} > + > +static const char *k210_pinmux_get_function_name(struct pinctrl_dev *pctldev, > + unsigned int selector) > +{ > + return k210_pcf_infos[selector].name; > +} > + > +static int k210_pinmux_get_function_groups(struct pinctrl_dev *pctldev, > + unsigned int selector, > + const char * const **groups, > + unsigned int * const num_groups) > +{ > + /* Any function can be mapped to any pin */ > + *groups = k210_group_names; > + *num_groups = K210_NPINS; > + > + return 0; > +} > + > +static int k210_pinmux_set_mux(struct pinctrl_dev *pctldev, > + unsigned int function, > + unsigned int group) > +{ > + /* Can't mux power domains */ > + if (group >= K210_NPINS) > + return -EINVAL; > + > + k210_pinmux_set_pin_function(pctldev, group, function); > + > + return 0; > +} > + > +static const struct pinmux_ops k210_pinmux_ops = { > + .get_functions_count = k210_pinmux_get_function_count, > + .get_function_name = k210_pinmux_get_function_name, > + .get_function_groups = k210_pinmux_get_function_groups, > + .set_mux = k210_pinmux_set_mux, > + .strict = true, > +}; > + > +static int k210_pinctrl_get_groups_count(struct pinctrl_dev *pctldev) > +{ > + return K210_NGROUPS; > +} > + > +static const char *k210_pinctrl_get_group_name(struct pinctrl_dev *pctldev, > + unsigned int group) > +{ > + return k210_group_names[group]; > +} > + > +static int k210_pinctrl_get_group_pins(struct pinctrl_dev *pctldev, > + unsigned int group, > + const unsigned int **pins, > + unsigned int *npins) > +{ > + if (group >= K210_NPINS) { > + *pins = NULL; > + *npins = 0; > + return 0; > + } > + > + *pins = &k210_pins[group].number; > + *npins = 1; > + > + return 0; > +} > + > +static void k210_pinctrl_pin_dbg_show(struct pinctrl_dev *pctldev, > + struct seq_file *s, unsigned int offset) > +{ > + seq_printf(s, "%s", dev_name(pctldev->dev)); > +} > + > +static int k210_pinctrl_dt_subnode_to_map(struct pinctrl_dev *pctldev, > + struct device_node *np, > + struct pinctrl_map **map, > + unsigned int *reserved_maps, > + unsigned int *num_maps) > +{ > + struct property *prop; > + const __be32 *p; > + int ret, pinmux_groups; > + u32 pinmux_group; > + unsigned long *configs = NULL; > + unsigned int num_configs = 0; > + unsigned int reserve = 0; > + > + ret = of_property_count_strings(np, "groups"); > + if (!ret) > + return pinconf_generic_dt_subnode_to_map(pctldev, np, map, > + reserved_maps, num_maps, > + PIN_MAP_TYPE_CONFIGS_GROUP); > + > + pinmux_groups = of_property_count_u32_elems(np, "pinmux"); > + if (pinmux_groups <= 0) { > + /* Ignore this node */ > + return 0; > + } > + > + ret = pinconf_generic_parse_dt_config(np, pctldev, &configs, > + &num_configs); > + if (ret < 0) { > + dev_err(pctldev->dev, "%pOF: could not parse node property\n", > + np); > + return ret; > + } > + > + reserve = pinmux_groups * (1 + num_configs); > + ret = pinctrl_utils_reserve_map(pctldev, map, reserved_maps, num_maps, > + reserve); > + if (ret < 0) > + goto exit; > + > + of_property_for_each_u32(np, "pinmux", prop, p, pinmux_group) { > + const char *group_name, *func_name; > + u32 pin = FIELD_GET(K210_PG_PIN, pinmux_group); > + u32 func = FIELD_GET(K210_PG_FUNC, pinmux_group); > + > + if (pin >= K210_NPINS) { > + ret = -EINVAL; > + goto exit; > + } > + > + group_name = k210_group_names[pin]; > + func_name = k210_pcf_infos[func].name; > + > + dev_dbg(pctldev->dev, "Pinmux %s: pin %u func %s\n", > + np->name, pin, func_name); > + > + ret = pinctrl_utils_add_map_mux(pctldev, map, reserved_maps, > + num_maps, group_name, > + func_name); > + if (ret < 0) { > + dev_err(pctldev->dev, "%pOF add mux map failed %d\n", > + np, ret); > + goto exit; > + } > + > + if (num_configs) { > + ret = pinctrl_utils_add_map_configs(pctldev, map, > + reserved_maps, num_maps, group_name, > + configs, num_configs, > + PIN_MAP_TYPE_CONFIGS_PIN); > + if (ret < 0) { > + dev_err(pctldev->dev, > + "%pOF add configs map failed %d\n", > + np, ret); > + goto exit; > + } > + } > + } > + > + ret = 0; > + > +exit: > + kfree(configs); > + return ret; > +} > + > +static int k210_pinctrl_dt_node_to_map(struct pinctrl_dev *pctldev, > + struct device_node *np_config, > + struct pinctrl_map **map, > + unsigned int *num_maps) > +{ > + unsigned int reserved_maps; > + struct device_node *np; > + int ret; > + > + reserved_maps = 0; > + *map = NULL; > + *num_maps = 0; > + > + ret = k210_pinctrl_dt_subnode_to_map(pctldev, np_config, map, > + &reserved_maps, num_maps); > + if (ret < 0) > + goto err; > + > + for_each_available_child_of_node(np_config, np) { > + ret = k210_pinctrl_dt_subnode_to_map(pctldev, np, map, > + &reserved_maps, num_maps); > + if (ret < 0) > + goto err; > + } > + return 0; > + > +err: > + pinctrl_utils_free_map(pctldev, *map, *num_maps); > + return ret; > +} > + > + > +static const struct pinctrl_ops k210_pinctrl_ops = { > + .get_groups_count = k210_pinctrl_get_groups_count, > + .get_group_name = k210_pinctrl_get_group_name, > + .get_group_pins = k210_pinctrl_get_group_pins, > + .pin_dbg_show = k210_pinctrl_pin_dbg_show, > + .dt_node_to_map = k210_pinctrl_dt_node_to_map, > + .dt_free_map = pinconf_generic_dt_free_map, > +}; > + > +static struct pinctrl_desc k210_pinctrl_desc = { > + .name = "k210-pinctrl", > + .pins = k210_pins, > + .npins = K210_NPINS, > + .pctlops = &k210_pinctrl_ops, > + .pmxops = &k210_pinmux_ops, > + .confops = &k210_pinconf_ops, > + .custom_params = k210_pinconf_custom_params, > + .num_custom_params = ARRAY_SIZE(k210_pinconf_custom_params), > +}; > + > +static void k210_fpioa_init_ties(struct k210_fpioa_data *pdata) > +{ > + struct k210_fpioa __iomem *fpioa = pdata->fpioa; > + u32 val; > + int i, j; > + > + dev_dbg(pdata->dev, "Init pin ties\n"); > + > + /* Init pin functions input ties */ > + for (i = 0; i < ARRAY_SIZE(fpioa->tie_en); i++) { > + val = 0; > + for (j = 0; j < 32; j++) { > + if (k210_pcf_infos[i * 32 + j].mode_id == > + K210_PC_DEFAULT_IN_TIE) { > + dev_dbg(pdata->dev, > + "tie_en function %d (%s)\n", > + i * 32 + j, > + k210_pcf_infos[i * 32 + j].name); > + val |= BIT(j); > + } > + } > + > + /* Set value before enable */ > + writel(val, &fpioa->tie_val[i]); > + writel(val, &fpioa->tie_en[i]); > + } > +} > + > +static int k210_fpioa_probe(struct platform_device *pdev) > +{ > + struct device *dev = &pdev->dev; > + struct device_node *np = dev->of_node; > + struct k210_fpioa_data *pdata; > + int ret; > + > + dev_info(dev, "K210 FPIOA pin controller\n"); > + > + pdata = devm_kzalloc(dev, sizeof(*pdata), GFP_KERNEL); > + if (!pdata) > + return -ENOMEM; > + > + pdata->dev = dev; > + platform_set_drvdata(pdev, pdata); > + > + pdata->fpioa = devm_platform_ioremap_resource(pdev, 0); > + if (IS_ERR(pdata->fpioa)) > + return PTR_ERR(pdata->fpioa); > + > + pdata->clk = devm_clk_get(dev, "ref"); > + if (IS_ERR(pdata->clk)) > + return PTR_ERR(pdata->clk); > + > + ret = clk_prepare_enable(pdata->clk); > + if (ret) > + return ret; > + > + pdata->pclk = devm_clk_get_optional(dev, "pclk"); > + if (!IS_ERR(pdata->pclk)) > + clk_prepare_enable(pdata->pclk); > + > + pdata->sysctl_map = > + syscon_regmap_lookup_by_phandle_args(np, > + "canaan,k210-sysctl-power", > + 1, &pdata->power_offset); > + if (IS_ERR(pdata->sysctl_map)) > + return PTR_ERR(pdata->sysctl_map); > + > + k210_fpioa_init_ties(pdata); > + > + pdata->pctl = pinctrl_register(&k210_pinctrl_desc, dev, (void *)pdata); > + if (IS_ERR(pdata->pctl)) > + return PTR_ERR(pdata->pctl); > + > + return 0; > +} > + > +static const struct of_device_id k210_fpioa_dt_ids[] = { > + { .compatible = "canaan,k210-fpioa" }, > + { /* sentinel */ }, > +}; > + > +static struct platform_driver k210_fpioa_driver = { > + .probe = k210_fpioa_probe, > + .driver = { > + .name = "k210-fpioa", > + .of_match_table = k210_fpioa_dt_ids, > + }, > +}; > +builtin_platform_driver(k210_fpioa_driver);
On 2021/01/15 8:32, Palmer Dabbelt wrote: > On Mon, 11 Jan 2021 16:58:40 PST (-0800), Damien Le Moal wrote: >> Add the pinctrl-k210.c pinctrl driver for the Canaan Kendryte K210 >> field programmable IO array (FPIOA) to allow configuring the SoC pin >> functions. The K210 has 48 programmable pins which can take any of 256 >> possible functions. >> >> This patch is inspired from the k210 pinctrl driver for the u-boot >> project and contains many direct contributions from Sean Anderson. >> >> The MAINTAINERS file is updated, adding the entry "CANAAN/KENDRYTE K210 >> SOC FPIOA DRIVER" with myself listed as maintainer for this driver. >> >> Cc: Linus Walleij <linus.walleij@linaro.org> >> Cc: linux-gpio@vger.kernel.org > > IDK if something's screwed up on my end, but I don't see these CCs locally. It's me who messed up my git-send-email command. I can't get it to send a patch series using only the CC per patch instead of coalescing all the CC references and sending all patches to everyone, which I would like to avoid. Still digging the option usage to figure that one out. I was doing --dry-run tests but the patches still were sent... Anyway, I sent this and the clock driver patch separately to the gpio and clk lists. > Lore does have it in the GPIO list, though, so maybe it made it. Either way, > if I'm going to take this through the RISC-V tree then I'd much prefer to have > at least an Ack. I'd also be happy to have it go through the GPIO tree, as > this is largely stand-alone -- the DT bindings are on riscv/for-next, but I'd > be happy to split them out into a shared tag or just put them in through your > tree if that's easier. Yes, I think this one can go through the gpio tree. Linus, Could you review this patch please ? > >> Signed-off-by: Sean Anderson <seanga2@gmail.com> >> Signed-off-by: Damien Le Moal <damien.lemoal@wdc.com> >> --- >> MAINTAINERS | 7 + >> arch/riscv/Kconfig.socs | 1 + >> drivers/pinctrl/Kconfig | 13 + >> drivers/pinctrl/Makefile | 1 + >> drivers/pinctrl/pinctrl-k210.c | 985 +++++++++++++++++++++++++++++++++ >> 5 files changed, 1007 insertions(+) >> create mode 100644 drivers/pinctrl/pinctrl-k210.c >> >> diff --git a/MAINTAINERS b/MAINTAINERS >> index 637b79eba693..1a7a1e4092e2 100644 >> --- a/MAINTAINERS >> +++ b/MAINTAINERS >> @@ -3860,6 +3860,13 @@ W: https://github.com/Cascoda/ca8210-linux.git >> F: Documentation/devicetree/bindings/net/ieee802154/ca8210.txt >> F: drivers/net/ieee802154/ca8210.c >> >> +CANAAN/KENDRYTE K210 SOC FPIOA DRIVER >> +M: Damien Le Moal <damien.lemoal@wdc.com> >> +L: linux-riscv@lists.infradead.org >> +L: linux-gpio@vger.kernel.org (pinctrl driver) >> +F: Documentation/devicetree/bindings/pinctrl/canaan,k210-fpioa.yaml >> +F: drivers/pinctrl/pinctrl-k210.c >> + >> CANAAN/KENDRYTE K210 SOC RESET CONTROLLER DRIVER >> M: Damien Le Moal <damien.lemoal@wdc.com> >> L: linux-kernel@vger.kernel.org >> diff --git a/arch/riscv/Kconfig.socs b/arch/riscv/Kconfig.socs >> index 57e53219c500..6402746c68f3 100644 >> --- a/arch/riscv/Kconfig.socs >> +++ b/arch/riscv/Kconfig.socs >> @@ -30,6 +30,7 @@ config SOC_CANAAN >> select SERIAL_SIFIVE_CONSOLE if TTY >> select SIFIVE_PLIC >> select ARCH_HAS_RESET_CONTROLLER >> + select PINCTRL >> help >> This enables support for Canaan Kendryte K210 SoC platform hardware. >> >> diff --git a/drivers/pinctrl/Kconfig b/drivers/pinctrl/Kconfig >> index d4b2f2e2ed75..cd437e3cc255 100644 >> --- a/drivers/pinctrl/Kconfig >> +++ b/drivers/pinctrl/Kconfig >> @@ -394,6 +394,19 @@ config PINCTRL_MICROCHIP_SGPIO >> connect control signals from SFP modules and to act as an >> LED controller. >> >> +config PINCTRL_K210 >> + bool "Pinctrl driver for the Canaan Kendryte K210 SoC" >> + depends on RISCV && SOC_CANAAN && OF >> + select GENERIC_PINMUX_FUNCTIONS >> + select GENERIC_PINCONF >> + select GPIOLIB >> + select OF_GPIO >> + select REGMAP_MMIO >> + default SOC_CANAAN >> + help >> + Add support for the Canaan Kendryte K210 RISC-V SOC Field >> + Programmable IO Array (FPIOA) controller. >> + >> source "drivers/pinctrl/actions/Kconfig" >> source "drivers/pinctrl/aspeed/Kconfig" >> source "drivers/pinctrl/bcm/Kconfig" >> diff --git a/drivers/pinctrl/Makefile b/drivers/pinctrl/Makefile >> index 5bb9bb6cc3ce..152c8fe51726 100644 >> --- a/drivers/pinctrl/Makefile >> +++ b/drivers/pinctrl/Makefile >> @@ -48,6 +48,7 @@ obj-$(CONFIG_PINCTRL_RK805) += pinctrl-rk805.o >> obj-$(CONFIG_PINCTRL_OCELOT) += pinctrl-ocelot.o >> obj-$(CONFIG_PINCTRL_MICROCHIP_SGPIO) += pinctrl-microchip-sgpio.o >> obj-$(CONFIG_PINCTRL_EQUILIBRIUM) += pinctrl-equilibrium.o >> +obj-$(CONFIG_PINCTRL_K210) += pinctrl-k210.o >> >> obj-y += actions/ >> obj-$(CONFIG_ARCH_ASPEED) += aspeed/ >> diff --git a/drivers/pinctrl/pinctrl-k210.c b/drivers/pinctrl/pinctrl-k210.c >> new file mode 100644 >> index 000000000000..8a733cf77ba0 >> --- /dev/null >> +++ b/drivers/pinctrl/pinctrl-k210.c >> @@ -0,0 +1,985 @@ >> +// SPDX-License-Identifier: GPL-2.0-or-later >> +/* >> + * Copyright (C) 2020 Sean Anderson <seanga2@gmail.com> >> + * Copyright (c) 2020 Western Digital Corporation or its affiliates. >> + */ >> +#include <linux/io.h> >> +#include <linux/of_device.h> >> +#include <linux/clk.h> >> +#include <linux/mfd/syscon.h> >> +#include <linux/platform_device.h> >> +#include <linux/bitfield.h> >> +#include <linux/regmap.h> >> +#include <linux/slab.h> >> +#include <linux/pinctrl/pinctrl.h> >> +#include <linux/pinctrl/pinmux.h> >> +#include <linux/pinctrl/pinconf.h> >> +#include <linux/pinctrl/pinconf-generic.h> >> +#include <linux/io.h> >> + >> +#include <dt-bindings/pinctrl/k210-fpioa.h> >> + >> +#include "core.h" >> +#include "pinconf.h" >> +#include "pinctrl-utils.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 Output Enable */ >> +#define K210_PC_DO_OE BIT(14) /* set Data Out to Output Enable sig */ >> +#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 */ >> +/* Same semantics as OE above */ >> +#define K210_PC_IE BIT(20) /* Input Enable */ >> +#define K210_PC_IE_INV BIT(21) /* INVert 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_SL | \ >> + K210_PC_OE | K210_PC_PU) >> +#define K210_PC_MODE_SCCB (K210_PC_MODE_I2C | \ >> + K210_PC_OE_INV | K210_PC_IE_INV) >> +#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) >> + >> +/* >> + * struct k210_fpioa: Kendryte K210 FPIOA memory mapped registers >> + * @pins: 48 32-bits IO pin registers >> + * @tie_en: 256 (one per function) input tie enable bits >> + * @tie_val: 256 (one per function) input tie value bits >> + */ >> +struct k210_fpioa { >> + u32 pins[48]; >> + u32 tie_en[8]; >> + u32 tie_val[8]; >> +}; >> + >> +struct k210_fpioa_data { >> + >> + struct device *dev; >> + struct pinctrl_dev *pctl; >> + >> + struct k210_fpioa __iomem *fpioa; >> + struct regmap *sysctl_map; >> + u32 power_offset; >> + struct clk *clk; >> + struct clk *pclk; >> +}; >> + >> +#define K210_PIN_NAME(i) ("IO_" #i) >> +#define K210_PIN(i) [(i)] = PINCTRL_PIN((i), K210_PIN_NAME(i)) >> + >> +static const struct pinctrl_pin_desc k210_pins[] = { >> + K210_PIN(0), K210_PIN(1), K210_PIN(2), >> + K210_PIN(3), K210_PIN(4), K210_PIN(5), >> + K210_PIN(6), K210_PIN(7), K210_PIN(8), >> + K210_PIN(9), K210_PIN(10), K210_PIN(11), >> + K210_PIN(12), K210_PIN(13), K210_PIN(14), >> + K210_PIN(15), K210_PIN(16), K210_PIN(17), >> + K210_PIN(18), K210_PIN(19), K210_PIN(20), >> + K210_PIN(21), K210_PIN(22), K210_PIN(23), >> + K210_PIN(24), K210_PIN(25), K210_PIN(26), >> + K210_PIN(27), K210_PIN(28), K210_PIN(29), >> + K210_PIN(30), K210_PIN(31), K210_PIN(32), >> + K210_PIN(33), K210_PIN(34), K210_PIN(35), >> + K210_PIN(36), K210_PIN(37), K210_PIN(38), >> + K210_PIN(39), K210_PIN(40), K210_PIN(41), >> + K210_PIN(42), K210_PIN(43), K210_PIN(44), >> + K210_PIN(45), K210_PIN(46), K210_PIN(47) >> +}; >> + >> +#define K210_NPINS ARRAY_SIZE(k210_pins) >> + >> +/* >> + * Pin groups: each of the 48 programmable pins is a group. >> + * To this are added 8 power domain groups, which for the purposes of >> + * the pin subsystem, contain no pins. The power domain groups only exist >> + * to set the power level. The id should never be used (since there are >> + * no pins 48-55). >> + */ >> +static const char *const k210_group_names[] = { >> + /* The first 48 groups are for pins, one each */ >> + K210_PIN_NAME(0), K210_PIN_NAME(1), K210_PIN_NAME(2), >> + K210_PIN_NAME(3), K210_PIN_NAME(4), K210_PIN_NAME(5), >> + K210_PIN_NAME(6), K210_PIN_NAME(7), K210_PIN_NAME(8), >> + K210_PIN_NAME(9), K210_PIN_NAME(10), K210_PIN_NAME(11), >> + K210_PIN_NAME(12), K210_PIN_NAME(13), K210_PIN_NAME(14), >> + K210_PIN_NAME(15), K210_PIN_NAME(16), K210_PIN_NAME(17), >> + K210_PIN_NAME(18), K210_PIN_NAME(19), K210_PIN_NAME(20), >> + K210_PIN_NAME(21), K210_PIN_NAME(22), K210_PIN_NAME(23), >> + K210_PIN_NAME(24), K210_PIN_NAME(25), K210_PIN_NAME(26), >> + K210_PIN_NAME(27), K210_PIN_NAME(28), K210_PIN_NAME(29), >> + K210_PIN_NAME(30), K210_PIN_NAME(31), K210_PIN_NAME(32), >> + K210_PIN_NAME(33), K210_PIN_NAME(34), K210_PIN_NAME(35), >> + K210_PIN_NAME(36), K210_PIN_NAME(37), K210_PIN_NAME(38), >> + K210_PIN_NAME(39), K210_PIN_NAME(40), K210_PIN_NAME(41), >> + K210_PIN_NAME(42), K210_PIN_NAME(43), K210_PIN_NAME(44), >> + K210_PIN_NAME(45), K210_PIN_NAME(46), K210_PIN_NAME(47), >> + [48] = "A0", [49] = "A1", [50] = "A2", >> + [51] = "B3", [52] = "B4", [53] = "B5", >> + [54] = "C6", [55] = "C7" >> +}; >> + >> +#define K210_NGROUPS ARRAY_SIZE(k210_group_names) >> + >> +enum k210_pinctrl_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_SCCB, >> + K210_PC_DEFAULT_SPI, >> + K210_PC_DEFAULT_GPIO, >> + K210_PC_DEFAULT_INT13, >> +}; >> + >> +#define K210_PC_DEFAULT(mode) \ >> + [K210_PC_DEFAULT_##mode] = K210_PC_MODE_##mode >> + >> +static const u32 k210_pinconf_mode_id_to_mode[] = { >> + [K210_PC_DEFAULT_DISABLED] = 0, >> + K210_PC_DEFAULT(IN), >> + [K210_PC_DEFAULT_IN_TIE] = K210_PC_MODE_IN, >> + K210_PC_DEFAULT(OUT), >> + K210_PC_DEFAULT(I2C), >> + K210_PC_DEFAULT(SCCB), >> + K210_PC_DEFAULT(SPI), >> + K210_PC_DEFAULT(GPIO), >> + [K210_PC_DEFAULT_INT13] = K210_PC_MODE_IN | K210_PC_PU, >> +}; >> + >> +#undef DEFAULT >> + >> +/* >> + * Pin functions configuration information. >> + */ >> +struct k210_pcf_info { >> + char name[15]; >> + u8 mode_id; >> +}; >> + >> +#define K210_FUNC(id, mode) \ >> + [K210_PCF_##id] = { \ >> + .name = #id, \ >> + .mode_id = K210_PC_DEFAULT_##mode \ >> + } >> + >> +static const struct k210_pcf_info k210_pcf_infos[] = { >> + K210_FUNC(JTAG_TCLK, IN), >> + K210_FUNC(JTAG_TDI, IN), >> + K210_FUNC(JTAG_TMS, IN), >> + K210_FUNC(JTAG_TDO, OUT), >> + K210_FUNC(SPI0_D0, SPI), >> + K210_FUNC(SPI0_D1, SPI), >> + K210_FUNC(SPI0_D2, SPI), >> + K210_FUNC(SPI0_D3, SPI), >> + K210_FUNC(SPI0_D4, SPI), >> + K210_FUNC(SPI0_D5, SPI), >> + K210_FUNC(SPI0_D6, SPI), >> + K210_FUNC(SPI0_D7, SPI), >> + K210_FUNC(SPI0_SS0, OUT), >> + K210_FUNC(SPI0_SS1, OUT), >> + K210_FUNC(SPI0_SS2, OUT), >> + K210_FUNC(SPI0_SS3, OUT), >> + K210_FUNC(SPI0_ARB, IN_TIE), >> + K210_FUNC(SPI0_SCLK, OUT), >> + K210_FUNC(UARTHS_RX, IN), >> + K210_FUNC(UARTHS_TX, OUT), >> + K210_FUNC(RESV6, IN), >> + K210_FUNC(RESV7, IN), >> + K210_FUNC(CLK_SPI1, OUT), >> + K210_FUNC(CLK_I2C1, OUT), >> + K210_FUNC(GPIOHS0, GPIO), >> + K210_FUNC(GPIOHS1, GPIO), >> + K210_FUNC(GPIOHS2, GPIO), >> + K210_FUNC(GPIOHS3, GPIO), >> + K210_FUNC(GPIOHS4, GPIO), >> + K210_FUNC(GPIOHS5, GPIO), >> + K210_FUNC(GPIOHS6, GPIO), >> + K210_FUNC(GPIOHS7, GPIO), >> + K210_FUNC(GPIOHS8, GPIO), >> + K210_FUNC(GPIOHS9, GPIO), >> + K210_FUNC(GPIOHS10, GPIO), >> + K210_FUNC(GPIOHS11, GPIO), >> + K210_FUNC(GPIOHS12, GPIO), >> + K210_FUNC(GPIOHS13, GPIO), >> + K210_FUNC(GPIOHS14, GPIO), >> + K210_FUNC(GPIOHS15, GPIO), >> + K210_FUNC(GPIOHS16, GPIO), >> + K210_FUNC(GPIOHS17, GPIO), >> + K210_FUNC(GPIOHS18, GPIO), >> + K210_FUNC(GPIOHS19, GPIO), >> + K210_FUNC(GPIOHS20, GPIO), >> + K210_FUNC(GPIOHS21, GPIO), >> + K210_FUNC(GPIOHS22, GPIO), >> + K210_FUNC(GPIOHS23, GPIO), >> + K210_FUNC(GPIOHS24, GPIO), >> + K210_FUNC(GPIOHS25, GPIO), >> + K210_FUNC(GPIOHS26, GPIO), >> + K210_FUNC(GPIOHS27, GPIO), >> + K210_FUNC(GPIOHS28, GPIO), >> + K210_FUNC(GPIOHS29, GPIO), >> + K210_FUNC(GPIOHS30, GPIO), >> + K210_FUNC(GPIOHS31, GPIO), >> + K210_FUNC(GPIO0, GPIO), >> + K210_FUNC(GPIO1, GPIO), >> + K210_FUNC(GPIO2, GPIO), >> + K210_FUNC(GPIO3, GPIO), >> + K210_FUNC(GPIO4, GPIO), >> + K210_FUNC(GPIO5, GPIO), >> + K210_FUNC(GPIO6, GPIO), >> + K210_FUNC(GPIO7, GPIO), >> + K210_FUNC(UART1_RX, IN), >> + K210_FUNC(UART1_TX, OUT), >> + K210_FUNC(UART2_RX, IN), >> + K210_FUNC(UART2_TX, OUT), >> + K210_FUNC(UART3_RX, IN), >> + K210_FUNC(UART3_TX, OUT), >> + K210_FUNC(SPI1_D0, SPI), >> + K210_FUNC(SPI1_D1, SPI), >> + K210_FUNC(SPI1_D2, SPI), >> + K210_FUNC(SPI1_D3, SPI), >> + K210_FUNC(SPI1_D4, SPI), >> + K210_FUNC(SPI1_D5, SPI), >> + K210_FUNC(SPI1_D6, SPI), >> + K210_FUNC(SPI1_D7, SPI), >> + K210_FUNC(SPI1_SS0, OUT), >> + K210_FUNC(SPI1_SS1, OUT), >> + K210_FUNC(SPI1_SS2, OUT), >> + K210_FUNC(SPI1_SS3, OUT), >> + K210_FUNC(SPI1_ARB, IN_TIE), >> + K210_FUNC(SPI1_SCLK, OUT), >> + K210_FUNC(SPI2_D0, SPI), >> + K210_FUNC(SPI2_SS, IN), >> + K210_FUNC(SPI2_SCLK, IN), >> + K210_FUNC(I2S0_MCLK, OUT), >> + K210_FUNC(I2S0_SCLK, OUT), >> + K210_FUNC(I2S0_WS, OUT), >> + K210_FUNC(I2S0_IN_D0, IN), >> + K210_FUNC(I2S0_IN_D1, IN), >> + K210_FUNC(I2S0_IN_D2, IN), >> + K210_FUNC(I2S0_IN_D3, IN), >> + K210_FUNC(I2S0_OUT_D0, OUT), >> + K210_FUNC(I2S0_OUT_D1, OUT), >> + K210_FUNC(I2S0_OUT_D2, OUT), >> + K210_FUNC(I2S0_OUT_D3, OUT), >> + K210_FUNC(I2S1_MCLK, OUT), >> + K210_FUNC(I2S1_SCLK, OUT), >> + K210_FUNC(I2S1_WS, OUT), >> + K210_FUNC(I2S1_IN_D0, IN), >> + K210_FUNC(I2S1_IN_D1, IN), >> + K210_FUNC(I2S1_IN_D2, IN), >> + K210_FUNC(I2S1_IN_D3, IN), >> + K210_FUNC(I2S1_OUT_D0, OUT), >> + K210_FUNC(I2S1_OUT_D1, OUT), >> + K210_FUNC(I2S1_OUT_D2, OUT), >> + K210_FUNC(I2S1_OUT_D3, OUT), >> + K210_FUNC(I2S2_MCLK, OUT), >> + K210_FUNC(I2S2_SCLK, OUT), >> + K210_FUNC(I2S2_WS, OUT), >> + K210_FUNC(I2S2_IN_D0, IN), >> + K210_FUNC(I2S2_IN_D1, IN), >> + K210_FUNC(I2S2_IN_D2, IN), >> + K210_FUNC(I2S2_IN_D3, IN), >> + K210_FUNC(I2S2_OUT_D0, OUT), >> + K210_FUNC(I2S2_OUT_D1, OUT), >> + K210_FUNC(I2S2_OUT_D2, OUT), >> + K210_FUNC(I2S2_OUT_D3, OUT), >> + K210_FUNC(RESV0, DISABLED), >> + K210_FUNC(RESV1, DISABLED), >> + K210_FUNC(RESV2, DISABLED), >> + K210_FUNC(RESV3, DISABLED), >> + K210_FUNC(RESV4, DISABLED), >> + K210_FUNC(RESV5, DISABLED), >> + K210_FUNC(I2C0_SCLK, I2C), >> + K210_FUNC(I2C0_SDA, I2C), >> + K210_FUNC(I2C1_SCLK, I2C), >> + K210_FUNC(I2C1_SDA, I2C), >> + K210_FUNC(I2C2_SCLK, I2C), >> + K210_FUNC(I2C2_SDA, I2C), >> + K210_FUNC(DVP_XCLK, OUT), >> + K210_FUNC(DVP_RST, OUT), >> + K210_FUNC(DVP_PWDN, OUT), >> + K210_FUNC(DVP_VSYNC, IN), >> + K210_FUNC(DVP_HSYNC, IN), >> + K210_FUNC(DVP_PCLK, IN), >> + K210_FUNC(DVP_D0, IN), >> + K210_FUNC(DVP_D1, IN), >> + K210_FUNC(DVP_D2, IN), >> + K210_FUNC(DVP_D3, IN), >> + K210_FUNC(DVP_D4, IN), >> + K210_FUNC(DVP_D5, IN), >> + K210_FUNC(DVP_D6, IN), >> + K210_FUNC(DVP_D7, IN), >> + K210_FUNC(SCCB_SCLK, SCCB), >> + K210_FUNC(SCCB_SDA, SCCB), >> + K210_FUNC(UART1_CTS, IN), >> + K210_FUNC(UART1_DSR, IN), >> + K210_FUNC(UART1_DCD, IN), >> + K210_FUNC(UART1_RI, IN), >> + K210_FUNC(UART1_SIR_IN, IN), >> + K210_FUNC(UART1_DTR, OUT), >> + K210_FUNC(UART1_RTS, OUT), >> + K210_FUNC(UART1_OUT2, OUT), >> + K210_FUNC(UART1_OUT1, OUT), >> + K210_FUNC(UART1_SIR_OUT, OUT), >> + K210_FUNC(UART1_BAUD, OUT), >> + K210_FUNC(UART1_RE, OUT), >> + K210_FUNC(UART1_DE, OUT), >> + K210_FUNC(UART1_RS485_EN, OUT), >> + K210_FUNC(UART2_CTS, IN), >> + K210_FUNC(UART2_DSR, IN), >> + K210_FUNC(UART2_DCD, IN), >> + K210_FUNC(UART2_RI, IN), >> + K210_FUNC(UART2_SIR_IN, IN), >> + K210_FUNC(UART2_DTR, OUT), >> + K210_FUNC(UART2_RTS, OUT), >> + K210_FUNC(UART2_OUT2, OUT), >> + K210_FUNC(UART2_OUT1, OUT), >> + K210_FUNC(UART2_SIR_OUT, OUT), >> + K210_FUNC(UART2_BAUD, OUT), >> + K210_FUNC(UART2_RE, OUT), >> + K210_FUNC(UART2_DE, OUT), >> + K210_FUNC(UART2_RS485_EN, OUT), >> + K210_FUNC(UART3_CTS, IN), >> + K210_FUNC(UART3_DSR, IN), >> + K210_FUNC(UART3_DCD, IN), >> + K210_FUNC(UART3_RI, IN), >> + K210_FUNC(UART3_SIR_IN, IN), >> + K210_FUNC(UART3_DTR, OUT), >> + K210_FUNC(UART3_RTS, OUT), >> + K210_FUNC(UART3_OUT2, OUT), >> + K210_FUNC(UART3_OUT1, OUT), >> + K210_FUNC(UART3_SIR_OUT, OUT), >> + K210_FUNC(UART3_BAUD, OUT), >> + K210_FUNC(UART3_RE, OUT), >> + K210_FUNC(UART3_DE, OUT), >> + K210_FUNC(UART3_RS485_EN, OUT), >> + K210_FUNC(TIMER0_TOGGLE1, OUT), >> + K210_FUNC(TIMER0_TOGGLE2, OUT), >> + K210_FUNC(TIMER0_TOGGLE3, OUT), >> + K210_FUNC(TIMER0_TOGGLE4, OUT), >> + K210_FUNC(TIMER1_TOGGLE1, OUT), >> + K210_FUNC(TIMER1_TOGGLE2, OUT), >> + K210_FUNC(TIMER1_TOGGLE3, OUT), >> + K210_FUNC(TIMER1_TOGGLE4, OUT), >> + K210_FUNC(TIMER2_TOGGLE1, OUT), >> + K210_FUNC(TIMER2_TOGGLE2, OUT), >> + K210_FUNC(TIMER2_TOGGLE3, OUT), >> + K210_FUNC(TIMER2_TOGGLE4, OUT), >> + K210_FUNC(CLK_SPI2, OUT), >> + K210_FUNC(CLK_I2C2, OUT), >> + K210_FUNC(INTERNAL0, OUT), >> + K210_FUNC(INTERNAL1, OUT), >> + K210_FUNC(INTERNAL2, OUT), >> + K210_FUNC(INTERNAL3, OUT), >> + K210_FUNC(INTERNAL4, OUT), >> + K210_FUNC(INTERNAL5, OUT), >> + K210_FUNC(INTERNAL6, OUT), >> + K210_FUNC(INTERNAL7, OUT), >> + K210_FUNC(INTERNAL8, OUT), >> + K210_FUNC(INTERNAL9, IN), >> + K210_FUNC(INTERNAL10, IN), >> + K210_FUNC(INTERNAL11, IN), >> + K210_FUNC(INTERNAL12, IN), >> + K210_FUNC(INTERNAL13, INT13), >> + K210_FUNC(INTERNAL14, I2C), >> + K210_FUNC(INTERNAL15, IN), >> + K210_FUNC(INTERNAL16, IN), >> + K210_FUNC(INTERNAL17, IN), >> + K210_FUNC(CONSTANT, DISABLED), >> + K210_FUNC(INTERNAL18, IN), >> + K210_FUNC(DEBUG0, OUT), >> + K210_FUNC(DEBUG1, OUT), >> + K210_FUNC(DEBUG2, OUT), >> + K210_FUNC(DEBUG3, OUT), >> + K210_FUNC(DEBUG4, OUT), >> + K210_FUNC(DEBUG5, OUT), >> + K210_FUNC(DEBUG6, OUT), >> + K210_FUNC(DEBUG7, OUT), >> + K210_FUNC(DEBUG8, OUT), >> + K210_FUNC(DEBUG9, OUT), >> + K210_FUNC(DEBUG10, OUT), >> + K210_FUNC(DEBUG11, OUT), >> + K210_FUNC(DEBUG12, OUT), >> + K210_FUNC(DEBUG13, OUT), >> + K210_FUNC(DEBUG14, OUT), >> + K210_FUNC(DEBUG15, OUT), >> + K210_FUNC(DEBUG16, OUT), >> + K210_FUNC(DEBUG17, OUT), >> + K210_FUNC(DEBUG18, OUT), >> + K210_FUNC(DEBUG19, OUT), >> + K210_FUNC(DEBUG20, OUT), >> + K210_FUNC(DEBUG21, OUT), >> + K210_FUNC(DEBUG22, OUT), >> + K210_FUNC(DEBUG23, OUT), >> + K210_FUNC(DEBUG24, OUT), >> + K210_FUNC(DEBUG25, OUT), >> + K210_FUNC(DEBUG26, OUT), >> + K210_FUNC(DEBUG27, OUT), >> + K210_FUNC(DEBUG28, OUT), >> + K210_FUNC(DEBUG29, OUT), >> + K210_FUNC(DEBUG30, OUT), >> + K210_FUNC(DEBUG31, OUT), >> +}; >> + >> +#define PIN_CONFIG_OUTPUT_INVERT (PIN_CONFIG_END + 1) >> +#define PIN_CONFIG_INPUT_INVERT (PIN_CONFIG_END + 2) >> + >> +static const struct pinconf_generic_params k210_pinconf_custom_params[] = { >> + { "output-polarity-invert", PIN_CONFIG_OUTPUT_INVERT, 1 }, >> + { "input-polarity-invert", PIN_CONFIG_INPUT_INVERT, 1 }, >> +}; >> + >> +/* >> + * Max drive strength in uA. >> + */ >> +static const int k210_pinconf_drive_strength[] = { >> + [0] = 11200, >> + [1] = 16800, >> + [2] = 22300, >> + [3] = 27800, >> + [4] = 33300, >> + [5] = 38700, >> + [6] = 44100, >> + [7] = 49500, >> +}; >> + >> +static int k210_pinconf_get_drive(unsigned int max_strength_ua) >> +{ >> + int i; >> + >> + for (i = K210_PC_DRIVE_MAX; i; i--) { >> + if (k210_pinconf_drive_strength[i] <= max_strength_ua) >> + return i; >> + } >> + >> + return -EINVAL; >> +} >> + >> +static void k210_pinmux_set_pin_function(struct pinctrl_dev *pctldev, >> + u32 pin, u32 func) >> +{ >> + struct k210_fpioa_data *pdata = pinctrl_dev_get_drvdata(pctldev); >> + const struct k210_pcf_info *info = &k210_pcf_infos[func]; >> + u32 mode = k210_pinconf_mode_id_to_mode[info->mode_id]; >> + u32 val = func | mode; >> + >> + dev_dbg(pdata->dev, "set pin %u function %s (%u) -> 0x%08x\n", >> + pin, info->name, func, val); >> + >> + writel(val, &pdata->fpioa->pins[pin]); >> +} >> + >> +static int k210_pinconf_set_param(struct pinctrl_dev *pctldev, >> + unsigned int pin, >> + unsigned int param, unsigned int arg) >> +{ >> + struct k210_fpioa_data *pdata = pinctrl_dev_get_drvdata(pctldev); >> + u32 val = readl(&pdata->fpioa->pins[pin]); >> + int drive; >> + >> + dev_dbg(pdata->dev, "set pin %u param %u, arg 0x%x\n", >> + pin, param, arg); >> + >> + switch (param) { >> + case PIN_CONFIG_BIAS_DISABLE: >> + val &= ~K210_PC_BIAS_MASK; >> + break; >> + case PIN_CONFIG_BIAS_PULL_DOWN: >> + if (!arg) >> + return -EINVAL; >> + val |= K210_PC_PD; >> + break; >> + case PIN_CONFIG_BIAS_PULL_UP: >> + if (!arg) >> + return -EINVAL; >> + val |= K210_PC_PD; >> + break; >> + case PIN_CONFIG_DRIVE_STRENGTH: >> + arg *= 1000; >> + fallthrough; >> + case PIN_CONFIG_DRIVE_STRENGTH_UA: >> + drive = k210_pinconf_get_drive(arg); >> + if (drive < 0) >> + return drive; >> + val &= ~K210_PC_DRIVE_MASK; >> + val |= FIELD_PREP(K210_PC_DRIVE_MASK, drive); >> + break; >> + case PIN_CONFIG_INPUT_ENABLE: >> + if (arg) >> + val |= K210_PC_IE; >> + else >> + val &= ~K210_PC_IE; >> + break; >> + case PIN_CONFIG_INPUT_SCHMITT_ENABLE: >> + if (arg) >> + val |= K210_PC_ST; >> + else >> + val &= ~K210_PC_ST; >> + break; >> + case PIN_CONFIG_OUTPUT: >> + k210_pinmux_set_pin_function(pctldev, pin, K210_PCF_CONSTANT); >> + val = readl(&pdata->fpioa->pins[pin]); >> + val |= K210_PC_MODE_OUT; >> + if (!arg) >> + val |= K210_PC_DO_INV; >> + break; >> + case PIN_CONFIG_OUTPUT_ENABLE: >> + if (arg) >> + val |= K210_PC_OE; >> + else >> + val &= ~K210_PC_OE; >> + break; >> + case PIN_CONFIG_SLEW_RATE: >> + if (arg) >> + val |= K210_PC_SL; >> + else >> + val &= ~K210_PC_SL; >> + break; >> + case PIN_CONFIG_OUTPUT_INVERT: >> + if (arg) >> + val |= K210_PC_DO_INV; >> + else >> + val &= ~K210_PC_DO_INV; >> + break; >> + case PIN_CONFIG_INPUT_INVERT: >> + if (arg) >> + val |= K210_PC_DI_INV; >> + else >> + val &= ~K210_PC_DI_INV; >> + break; >> + default: >> + return -EINVAL; >> + } >> + >> + writel(val, &pdata->fpioa->pins[pin]); >> + >> + return 0; >> +} >> + >> +static int k210_pinconf_set(struct pinctrl_dev *pctldev, unsigned int pin, >> + unsigned long *configs, unsigned int num_configs) >> +{ >> + unsigned int param, arg; >> + int i, ret; >> + >> + if (WARN_ON(pin >= K210_NPINS)) >> + return -EINVAL; >> + >> + for (i = 0; i < num_configs; i++) { >> + param = pinconf_to_config_param(configs[i]); >> + arg = pinconf_to_config_argument(configs[i]); >> + ret = k210_pinconf_set_param(pctldev, pin, param, arg); >> + if (ret) >> + return ret; >> + } >> + >> + return 0; >> +} >> + >> +static void k210_pinconf_dbg_show(struct pinctrl_dev *pctldev, >> + struct seq_file *s, unsigned int pin) >> +{ >> + struct k210_fpioa_data *pdata = pinctrl_dev_get_drvdata(pctldev); >> + >> + seq_printf(s, "%#x", readl(&pdata->fpioa->pins[pin])); >> +} >> + >> +static int k210_pinconf_group_set(struct pinctrl_dev *pctldev, >> + unsigned int selector, unsigned long *configs, >> + unsigned int num_configs) >> +{ >> + struct k210_fpioa_data *pdata = pinctrl_dev_get_drvdata(pctldev); >> + unsigned int param, arg; >> + u32 bit; >> + int i; >> + >> + /* Pins should be configured with pinmux, not groups*/ >> + if (selector < K210_NPINS) >> + return -EINVAL; >> + >> + /* Otherwise it's a power domain */ >> + for (i = 0; i < num_configs; i++) { >> + param = pinconf_to_config_param(configs[i]); >> + if (param != PIN_CONFIG_POWER_SOURCE) >> + return -EINVAL; >> + >> + arg = pinconf_to_config_argument(configs[i]); >> + bit = BIT(selector - K210_NPINS); >> + regmap_update_bits(pdata->sysctl_map, >> + pdata->power_offset, >> + bit, arg ? bit : 0); >> + } >> + >> + return 0; >> +} >> + >> +static void k210_pinconf_group_dbg_show(struct pinctrl_dev *pctldev, >> + struct seq_file *s, >> + unsigned int selector) >> +{ >> + struct k210_fpioa_data *pdata = pinctrl_dev_get_drvdata(pctldev); >> + int ret; >> + u32 val; >> + >> + if (selector < K210_NPINS) >> + return k210_pinconf_dbg_show(pctldev, s, selector); >> + >> + ret = regmap_read(pdata->sysctl_map, pdata->power_offset, &val); >> + if (ret) { >> + dev_err(pdata->dev, "Failed to read power reg\n"); >> + return; >> + } >> + >> + seq_printf(s, "%s: %s V", k210_group_names[selector], >> + val & BIT(selector - K210_NPINS) ? "1.8" : "3.3"); >> +} >> + >> +static const struct pinconf_ops k210_pinconf_ops = { >> + .is_generic = true, >> + .pin_config_set = k210_pinconf_set, >> + .pin_config_group_set = k210_pinconf_group_set, >> + .pin_config_dbg_show = k210_pinconf_dbg_show, >> + .pin_config_group_dbg_show = k210_pinconf_group_dbg_show, >> +}; >> + >> +static int k210_pinmux_get_function_count(struct pinctrl_dev *pctldev) >> +{ >> + return ARRAY_SIZE(k210_pcf_infos); >> +} >> + >> +static const char *k210_pinmux_get_function_name(struct pinctrl_dev *pctldev, >> + unsigned int selector) >> +{ >> + return k210_pcf_infos[selector].name; >> +} >> + >> +static int k210_pinmux_get_function_groups(struct pinctrl_dev *pctldev, >> + unsigned int selector, >> + const char * const **groups, >> + unsigned int * const num_groups) >> +{ >> + /* Any function can be mapped to any pin */ >> + *groups = k210_group_names; >> + *num_groups = K210_NPINS; >> + >> + return 0; >> +} >> + >> +static int k210_pinmux_set_mux(struct pinctrl_dev *pctldev, >> + unsigned int function, >> + unsigned int group) >> +{ >> + /* Can't mux power domains */ >> + if (group >= K210_NPINS) >> + return -EINVAL; >> + >> + k210_pinmux_set_pin_function(pctldev, group, function); >> + >> + return 0; >> +} >> + >> +static const struct pinmux_ops k210_pinmux_ops = { >> + .get_functions_count = k210_pinmux_get_function_count, >> + .get_function_name = k210_pinmux_get_function_name, >> + .get_function_groups = k210_pinmux_get_function_groups, >> + .set_mux = k210_pinmux_set_mux, >> + .strict = true, >> +}; >> + >> +static int k210_pinctrl_get_groups_count(struct pinctrl_dev *pctldev) >> +{ >> + return K210_NGROUPS; >> +} >> + >> +static const char *k210_pinctrl_get_group_name(struct pinctrl_dev *pctldev, >> + unsigned int group) >> +{ >> + return k210_group_names[group]; >> +} >> + >> +static int k210_pinctrl_get_group_pins(struct pinctrl_dev *pctldev, >> + unsigned int group, >> + const unsigned int **pins, >> + unsigned int *npins) >> +{ >> + if (group >= K210_NPINS) { >> + *pins = NULL; >> + *npins = 0; >> + return 0; >> + } >> + >> + *pins = &k210_pins[group].number; >> + *npins = 1; >> + >> + return 0; >> +} >> + >> +static void k210_pinctrl_pin_dbg_show(struct pinctrl_dev *pctldev, >> + struct seq_file *s, unsigned int offset) >> +{ >> + seq_printf(s, "%s", dev_name(pctldev->dev)); >> +} >> + >> +static int k210_pinctrl_dt_subnode_to_map(struct pinctrl_dev *pctldev, >> + struct device_node *np, >> + struct pinctrl_map **map, >> + unsigned int *reserved_maps, >> + unsigned int *num_maps) >> +{ >> + struct property *prop; >> + const __be32 *p; >> + int ret, pinmux_groups; >> + u32 pinmux_group; >> + unsigned long *configs = NULL; >> + unsigned int num_configs = 0; >> + unsigned int reserve = 0; >> + >> + ret = of_property_count_strings(np, "groups"); >> + if (!ret) >> + return pinconf_generic_dt_subnode_to_map(pctldev, np, map, >> + reserved_maps, num_maps, >> + PIN_MAP_TYPE_CONFIGS_GROUP); >> + >> + pinmux_groups = of_property_count_u32_elems(np, "pinmux"); >> + if (pinmux_groups <= 0) { >> + /* Ignore this node */ >> + return 0; >> + } >> + >> + ret = pinconf_generic_parse_dt_config(np, pctldev, &configs, >> + &num_configs); >> + if (ret < 0) { >> + dev_err(pctldev->dev, "%pOF: could not parse node property\n", >> + np); >> + return ret; >> + } >> + >> + reserve = pinmux_groups * (1 + num_configs); >> + ret = pinctrl_utils_reserve_map(pctldev, map, reserved_maps, num_maps, >> + reserve); >> + if (ret < 0) >> + goto exit; >> + >> + of_property_for_each_u32(np, "pinmux", prop, p, pinmux_group) { >> + const char *group_name, *func_name; >> + u32 pin = FIELD_GET(K210_PG_PIN, pinmux_group); >> + u32 func = FIELD_GET(K210_PG_FUNC, pinmux_group); >> + >> + if (pin >= K210_NPINS) { >> + ret = -EINVAL; >> + goto exit; >> + } >> + >> + group_name = k210_group_names[pin]; >> + func_name = k210_pcf_infos[func].name; >> + >> + dev_dbg(pctldev->dev, "Pinmux %s: pin %u func %s\n", >> + np->name, pin, func_name); >> + >> + ret = pinctrl_utils_add_map_mux(pctldev, map, reserved_maps, >> + num_maps, group_name, >> + func_name); >> + if (ret < 0) { >> + dev_err(pctldev->dev, "%pOF add mux map failed %d\n", >> + np, ret); >> + goto exit; >> + } >> + >> + if (num_configs) { >> + ret = pinctrl_utils_add_map_configs(pctldev, map, >> + reserved_maps, num_maps, group_name, >> + configs, num_configs, >> + PIN_MAP_TYPE_CONFIGS_PIN); >> + if (ret < 0) { >> + dev_err(pctldev->dev, >> + "%pOF add configs map failed %d\n", >> + np, ret); >> + goto exit; >> + } >> + } >> + } >> + >> + ret = 0; >> + >> +exit: >> + kfree(configs); >> + return ret; >> +} >> + >> +static int k210_pinctrl_dt_node_to_map(struct pinctrl_dev *pctldev, >> + struct device_node *np_config, >> + struct pinctrl_map **map, >> + unsigned int *num_maps) >> +{ >> + unsigned int reserved_maps; >> + struct device_node *np; >> + int ret; >> + >> + reserved_maps = 0; >> + *map = NULL; >> + *num_maps = 0; >> + >> + ret = k210_pinctrl_dt_subnode_to_map(pctldev, np_config, map, >> + &reserved_maps, num_maps); >> + if (ret < 0) >> + goto err; >> + >> + for_each_available_child_of_node(np_config, np) { >> + ret = k210_pinctrl_dt_subnode_to_map(pctldev, np, map, >> + &reserved_maps, num_maps); >> + if (ret < 0) >> + goto err; >> + } >> + return 0; >> + >> +err: >> + pinctrl_utils_free_map(pctldev, *map, *num_maps); >> + return ret; >> +} >> + >> + >> +static const struct pinctrl_ops k210_pinctrl_ops = { >> + .get_groups_count = k210_pinctrl_get_groups_count, >> + .get_group_name = k210_pinctrl_get_group_name, >> + .get_group_pins = k210_pinctrl_get_group_pins, >> + .pin_dbg_show = k210_pinctrl_pin_dbg_show, >> + .dt_node_to_map = k210_pinctrl_dt_node_to_map, >> + .dt_free_map = pinconf_generic_dt_free_map, >> +}; >> + >> +static struct pinctrl_desc k210_pinctrl_desc = { >> + .name = "k210-pinctrl", >> + .pins = k210_pins, >> + .npins = K210_NPINS, >> + .pctlops = &k210_pinctrl_ops, >> + .pmxops = &k210_pinmux_ops, >> + .confops = &k210_pinconf_ops, >> + .custom_params = k210_pinconf_custom_params, >> + .num_custom_params = ARRAY_SIZE(k210_pinconf_custom_params), >> +}; >> + >> +static void k210_fpioa_init_ties(struct k210_fpioa_data *pdata) >> +{ >> + struct k210_fpioa __iomem *fpioa = pdata->fpioa; >> + u32 val; >> + int i, j; >> + >> + dev_dbg(pdata->dev, "Init pin ties\n"); >> + >> + /* Init pin functions input ties */ >> + for (i = 0; i < ARRAY_SIZE(fpioa->tie_en); i++) { >> + val = 0; >> + for (j = 0; j < 32; j++) { >> + if (k210_pcf_infos[i * 32 + j].mode_id == >> + K210_PC_DEFAULT_IN_TIE) { >> + dev_dbg(pdata->dev, >> + "tie_en function %d (%s)\n", >> + i * 32 + j, >> + k210_pcf_infos[i * 32 + j].name); >> + val |= BIT(j); >> + } >> + } >> + >> + /* Set value before enable */ >> + writel(val, &fpioa->tie_val[i]); >> + writel(val, &fpioa->tie_en[i]); >> + } >> +} >> + >> +static int k210_fpioa_probe(struct platform_device *pdev) >> +{ >> + struct device *dev = &pdev->dev; >> + struct device_node *np = dev->of_node; >> + struct k210_fpioa_data *pdata; >> + int ret; >> + >> + dev_info(dev, "K210 FPIOA pin controller\n"); >> + >> + pdata = devm_kzalloc(dev, sizeof(*pdata), GFP_KERNEL); >> + if (!pdata) >> + return -ENOMEM; >> + >> + pdata->dev = dev; >> + platform_set_drvdata(pdev, pdata); >> + >> + pdata->fpioa = devm_platform_ioremap_resource(pdev, 0); >> + if (IS_ERR(pdata->fpioa)) >> + return PTR_ERR(pdata->fpioa); >> + >> + pdata->clk = devm_clk_get(dev, "ref"); >> + if (IS_ERR(pdata->clk)) >> + return PTR_ERR(pdata->clk); >> + >> + ret = clk_prepare_enable(pdata->clk); >> + if (ret) >> + return ret; >> + >> + pdata->pclk = devm_clk_get_optional(dev, "pclk"); >> + if (!IS_ERR(pdata->pclk)) >> + clk_prepare_enable(pdata->pclk); >> + >> + pdata->sysctl_map = >> + syscon_regmap_lookup_by_phandle_args(np, >> + "canaan,k210-sysctl-power", >> + 1, &pdata->power_offset); >> + if (IS_ERR(pdata->sysctl_map)) >> + return PTR_ERR(pdata->sysctl_map); >> + >> + k210_fpioa_init_ties(pdata); >> + >> + pdata->pctl = pinctrl_register(&k210_pinctrl_desc, dev, (void *)pdata); >> + if (IS_ERR(pdata->pctl)) >> + return PTR_ERR(pdata->pctl); >> + >> + return 0; >> +} >> + >> +static const struct of_device_id k210_fpioa_dt_ids[] = { >> + { .compatible = "canaan,k210-fpioa" }, >> + { /* sentinel */ }, >> +}; >> + >> +static struct platform_driver k210_fpioa_driver = { >> + .probe = k210_fpioa_probe, >> + .driver = { >> + .name = "k210-fpioa", >> + .of_match_table = k210_fpioa_dt_ids, >> + }, >> +}; >> +builtin_platform_driver(k210_fpioa_driver); >
On 1/14/21 7:17 PM, Damien Le Moal wrote: > On 2021/01/15 8:32, Palmer Dabbelt wrote: >> On Mon, 11 Jan 2021 16:58:40 PST (-0800), Damien Le Moal wrote: >>> Add the pinctrl-k210.c pinctrl driver for the Canaan Kendryte K210 >>> field programmable IO array (FPIOA) to allow configuring the SoC pin >>> functions. The K210 has 48 programmable pins which can take any of 256 >>> possible functions. >>> >>> This patch is inspired from the k210 pinctrl driver for the u-boot >>> project and contains many direct contributions from Sean Anderson. >>> >>> The MAINTAINERS file is updated, adding the entry "CANAAN/KENDRYTE K210 >>> SOC FPIOA DRIVER" with myself listed as maintainer for this driver. >>> >>> Cc: Linus Walleij <linus.walleij@linaro.org> >>> Cc: linux-gpio@vger.kernel.org >> >> IDK if something's screwed up on my end, but I don't see these CCs locally. > > It's me who messed up my git-send-email command. I can't get it to send a patch > series using only the CC per patch instead of coalescing all the CC references > and sending all patches to everyone, which I would like to avoid. Still digging > the option usage to figure that one out. I was doing --dry-run tests but the > patches still were sent... Anyway, I sent this and the clock driver patch > separately to the gpio and clk lists. There's always u-boot's patman. I find it very helpful for CC-ing relevant people and managing changelogs. https://gitlab.denx.de/u-boot/u-boot/blob/master/tools/patman/README --Sean > >> Lore does have it in the GPIO list, though, so maybe it made it. Either way, >> if I'm going to take this through the RISC-V tree then I'd much prefer to have >> at least an Ack. I'd also be happy to have it go through the GPIO tree, as >> this is largely stand-alone -- the DT bindings are on riscv/for-next, but I'd >> be happy to split them out into a shared tag or just put them in through your >> tree if that's easier. > > Yes, I think this one can go through the gpio tree. > > Linus, > > Could you review this patch please ? > >> >>> Signed-off-by: Sean Anderson <seanga2@gmail.com> >>> Signed-off-by: Damien Le Moal <damien.lemoal@wdc.com> >>> --- >>> MAINTAINERS | 7 + >>> arch/riscv/Kconfig.socs | 1 + >>> drivers/pinctrl/Kconfig | 13 + >>> drivers/pinctrl/Makefile | 1 + >>> drivers/pinctrl/pinctrl-k210.c | 985 +++++++++++++++++++++++++++++++++ >>> 5 files changed, 1007 insertions(+) >>> create mode 100644 drivers/pinctrl/pinctrl-k210.c >>> >>> diff --git a/MAINTAINERS b/MAINTAINERS >>> index 637b79eba693..1a7a1e4092e2 100644 >>> --- a/MAINTAINERS >>> +++ b/MAINTAINERS >>> @@ -3860,6 +3860,13 @@ W: https://github.com/Cascoda/ca8210-linux.git >>> F: Documentation/devicetree/bindings/net/ieee802154/ca8210.txt >>> F: drivers/net/ieee802154/ca8210.c >>> >>> +CANAAN/KENDRYTE K210 SOC FPIOA DRIVER >>> +M: Damien Le Moal <damien.lemoal@wdc.com> >>> +L: linux-riscv@lists.infradead.org >>> +L: linux-gpio@vger.kernel.org (pinctrl driver) >>> +F: Documentation/devicetree/bindings/pinctrl/canaan,k210-fpioa.yaml >>> +F: drivers/pinctrl/pinctrl-k210.c >>> + >>> CANAAN/KENDRYTE K210 SOC RESET CONTROLLER DRIVER >>> M: Damien Le Moal <damien.lemoal@wdc.com> >>> L: linux-kernel@vger.kernel.org >>> diff --git a/arch/riscv/Kconfig.socs b/arch/riscv/Kconfig.socs >>> index 57e53219c500..6402746c68f3 100644 >>> --- a/arch/riscv/Kconfig.socs >>> +++ b/arch/riscv/Kconfig.socs >>> @@ -30,6 +30,7 @@ config SOC_CANAAN >>> select SERIAL_SIFIVE_CONSOLE if TTY >>> select SIFIVE_PLIC >>> select ARCH_HAS_RESET_CONTROLLER >>> + select PINCTRL >>> help >>> This enables support for Canaan Kendryte K210 SoC platform hardware. >>> >>> diff --git a/drivers/pinctrl/Kconfig b/drivers/pinctrl/Kconfig >>> index d4b2f2e2ed75..cd437e3cc255 100644 >>> --- a/drivers/pinctrl/Kconfig >>> +++ b/drivers/pinctrl/Kconfig >>> @@ -394,6 +394,19 @@ config PINCTRL_MICROCHIP_SGPIO >>> connect control signals from SFP modules and to act as an >>> LED controller. >>> >>> +config PINCTRL_K210 >>> + bool "Pinctrl driver for the Canaan Kendryte K210 SoC" >>> + depends on RISCV && SOC_CANAAN && OF >>> + select GENERIC_PINMUX_FUNCTIONS >>> + select GENERIC_PINCONF >>> + select GPIOLIB >>> + select OF_GPIO >>> + select REGMAP_MMIO >>> + default SOC_CANAAN >>> + help >>> + Add support for the Canaan Kendryte K210 RISC-V SOC Field >>> + Programmable IO Array (FPIOA) controller. >>> + >>> source "drivers/pinctrl/actions/Kconfig" >>> source "drivers/pinctrl/aspeed/Kconfig" >>> source "drivers/pinctrl/bcm/Kconfig" >>> diff --git a/drivers/pinctrl/Makefile b/drivers/pinctrl/Makefile >>> index 5bb9bb6cc3ce..152c8fe51726 100644 >>> --- a/drivers/pinctrl/Makefile >>> +++ b/drivers/pinctrl/Makefile >>> @@ -48,6 +48,7 @@ obj-$(CONFIG_PINCTRL_RK805) += pinctrl-rk805.o >>> obj-$(CONFIG_PINCTRL_OCELOT) += pinctrl-ocelot.o >>> obj-$(CONFIG_PINCTRL_MICROCHIP_SGPIO) += pinctrl-microchip-sgpio.o >>> obj-$(CONFIG_PINCTRL_EQUILIBRIUM) += pinctrl-equilibrium.o >>> +obj-$(CONFIG_PINCTRL_K210) += pinctrl-k210.o >>> >>> obj-y += actions/ >>> obj-$(CONFIG_ARCH_ASPEED) += aspeed/ >>> diff --git a/drivers/pinctrl/pinctrl-k210.c b/drivers/pinctrl/pinctrl-k210.c >>> new file mode 100644 >>> index 000000000000..8a733cf77ba0 >>> --- /dev/null >>> +++ b/drivers/pinctrl/pinctrl-k210.c >>> @@ -0,0 +1,985 @@ >>> +// SPDX-License-Identifier: GPL-2.0-or-later >>> +/* >>> + * Copyright (C) 2020 Sean Anderson <seanga2@gmail.com> >>> + * Copyright (c) 2020 Western Digital Corporation or its affiliates. >>> + */ >>> +#include <linux/io.h> >>> +#include <linux/of_device.h> >>> +#include <linux/clk.h> >>> +#include <linux/mfd/syscon.h> >>> +#include <linux/platform_device.h> >>> +#include <linux/bitfield.h> >>> +#include <linux/regmap.h> >>> +#include <linux/slab.h> >>> +#include <linux/pinctrl/pinctrl.h> >>> +#include <linux/pinctrl/pinmux.h> >>> +#include <linux/pinctrl/pinconf.h> >>> +#include <linux/pinctrl/pinconf-generic.h> >>> +#include <linux/io.h> >>> + >>> +#include <dt-bindings/pinctrl/k210-fpioa.h> >>> + >>> +#include "core.h" >>> +#include "pinconf.h" >>> +#include "pinctrl-utils.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 Output Enable */ >>> +#define K210_PC_DO_OE BIT(14) /* set Data Out to Output Enable sig */ >>> +#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 */ >>> +/* Same semantics as OE above */ >>> +#define K210_PC_IE BIT(20) /* Input Enable */ >>> +#define K210_PC_IE_INV BIT(21) /* INVert 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_SL | \ >>> + K210_PC_OE | K210_PC_PU) >>> +#define K210_PC_MODE_SCCB (K210_PC_MODE_I2C | \ >>> + K210_PC_OE_INV | K210_PC_IE_INV) >>> +#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) >>> + >>> +/* >>> + * struct k210_fpioa: Kendryte K210 FPIOA memory mapped registers >>> + * @pins: 48 32-bits IO pin registers >>> + * @tie_en: 256 (one per function) input tie enable bits >>> + * @tie_val: 256 (one per function) input tie value bits >>> + */ >>> +struct k210_fpioa { >>> + u32 pins[48]; >>> + u32 tie_en[8]; >>> + u32 tie_val[8]; >>> +}; >>> + >>> +struct k210_fpioa_data { >>> + >>> + struct device *dev; >>> + struct pinctrl_dev *pctl; >>> + >>> + struct k210_fpioa __iomem *fpioa; >>> + struct regmap *sysctl_map; >>> + u32 power_offset; >>> + struct clk *clk; >>> + struct clk *pclk; >>> +}; >>> + >>> +#define K210_PIN_NAME(i) ("IO_" #i) >>> +#define K210_PIN(i) [(i)] = PINCTRL_PIN((i), K210_PIN_NAME(i)) >>> + >>> +static const struct pinctrl_pin_desc k210_pins[] = { >>> + K210_PIN(0), K210_PIN(1), K210_PIN(2), >>> + K210_PIN(3), K210_PIN(4), K210_PIN(5), >>> + K210_PIN(6), K210_PIN(7), K210_PIN(8), >>> + K210_PIN(9), K210_PIN(10), K210_PIN(11), >>> + K210_PIN(12), K210_PIN(13), K210_PIN(14), >>> + K210_PIN(15), K210_PIN(16), K210_PIN(17), >>> + K210_PIN(18), K210_PIN(19), K210_PIN(20), >>> + K210_PIN(21), K210_PIN(22), K210_PIN(23), >>> + K210_PIN(24), K210_PIN(25), K210_PIN(26), >>> + K210_PIN(27), K210_PIN(28), K210_PIN(29), >>> + K210_PIN(30), K210_PIN(31), K210_PIN(32), >>> + K210_PIN(33), K210_PIN(34), K210_PIN(35), >>> + K210_PIN(36), K210_PIN(37), K210_PIN(38), >>> + K210_PIN(39), K210_PIN(40), K210_PIN(41), >>> + K210_PIN(42), K210_PIN(43), K210_PIN(44), >>> + K210_PIN(45), K210_PIN(46), K210_PIN(47) >>> +}; >>> + >>> +#define K210_NPINS ARRAY_SIZE(k210_pins) >>> + >>> +/* >>> + * Pin groups: each of the 48 programmable pins is a group. >>> + * To this are added 8 power domain groups, which for the purposes of >>> + * the pin subsystem, contain no pins. The power domain groups only exist >>> + * to set the power level. The id should never be used (since there are >>> + * no pins 48-55). >>> + */ >>> +static const char *const k210_group_names[] = { >>> + /* The first 48 groups are for pins, one each */ >>> + K210_PIN_NAME(0), K210_PIN_NAME(1), K210_PIN_NAME(2), >>> + K210_PIN_NAME(3), K210_PIN_NAME(4), K210_PIN_NAME(5), >>> + K210_PIN_NAME(6), K210_PIN_NAME(7), K210_PIN_NAME(8), >>> + K210_PIN_NAME(9), K210_PIN_NAME(10), K210_PIN_NAME(11), >>> + K210_PIN_NAME(12), K210_PIN_NAME(13), K210_PIN_NAME(14), >>> + K210_PIN_NAME(15), K210_PIN_NAME(16), K210_PIN_NAME(17), >>> + K210_PIN_NAME(18), K210_PIN_NAME(19), K210_PIN_NAME(20), >>> + K210_PIN_NAME(21), K210_PIN_NAME(22), K210_PIN_NAME(23), >>> + K210_PIN_NAME(24), K210_PIN_NAME(25), K210_PIN_NAME(26), >>> + K210_PIN_NAME(27), K210_PIN_NAME(28), K210_PIN_NAME(29), >>> + K210_PIN_NAME(30), K210_PIN_NAME(31), K210_PIN_NAME(32), >>> + K210_PIN_NAME(33), K210_PIN_NAME(34), K210_PIN_NAME(35), >>> + K210_PIN_NAME(36), K210_PIN_NAME(37), K210_PIN_NAME(38), >>> + K210_PIN_NAME(39), K210_PIN_NAME(40), K210_PIN_NAME(41), >>> + K210_PIN_NAME(42), K210_PIN_NAME(43), K210_PIN_NAME(44), >>> + K210_PIN_NAME(45), K210_PIN_NAME(46), K210_PIN_NAME(47), >>> + [48] = "A0", [49] = "A1", [50] = "A2", >>> + [51] = "B3", [52] = "B4", [53] = "B5", >>> + [54] = "C6", [55] = "C7" >>> +}; >>> + >>> +#define K210_NGROUPS ARRAY_SIZE(k210_group_names) >>> + >>> +enum k210_pinctrl_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_SCCB, >>> + K210_PC_DEFAULT_SPI, >>> + K210_PC_DEFAULT_GPIO, >>> + K210_PC_DEFAULT_INT13, >>> +}; >>> + >>> +#define K210_PC_DEFAULT(mode) \ >>> + [K210_PC_DEFAULT_##mode] = K210_PC_MODE_##mode >>> + >>> +static const u32 k210_pinconf_mode_id_to_mode[] = { >>> + [K210_PC_DEFAULT_DISABLED] = 0, >>> + K210_PC_DEFAULT(IN), >>> + [K210_PC_DEFAULT_IN_TIE] = K210_PC_MODE_IN, >>> + K210_PC_DEFAULT(OUT), >>> + K210_PC_DEFAULT(I2C), >>> + K210_PC_DEFAULT(SCCB), >>> + K210_PC_DEFAULT(SPI), >>> + K210_PC_DEFAULT(GPIO), >>> + [K210_PC_DEFAULT_INT13] = K210_PC_MODE_IN | K210_PC_PU, >>> +}; >>> + >>> +#undef DEFAULT >>> + >>> +/* >>> + * Pin functions configuration information. >>> + */ >>> +struct k210_pcf_info { >>> + char name[15]; >>> + u8 mode_id; >>> +}; >>> + >>> +#define K210_FUNC(id, mode) \ >>> + [K210_PCF_##id] = { \ >>> + .name = #id, \ >>> + .mode_id = K210_PC_DEFAULT_##mode \ >>> + } >>> + >>> +static const struct k210_pcf_info k210_pcf_infos[] = { >>> + K210_FUNC(JTAG_TCLK, IN), >>> + K210_FUNC(JTAG_TDI, IN), >>> + K210_FUNC(JTAG_TMS, IN), >>> + K210_FUNC(JTAG_TDO, OUT), >>> + K210_FUNC(SPI0_D0, SPI), >>> + K210_FUNC(SPI0_D1, SPI), >>> + K210_FUNC(SPI0_D2, SPI), >>> + K210_FUNC(SPI0_D3, SPI), >>> + K210_FUNC(SPI0_D4, SPI), >>> + K210_FUNC(SPI0_D5, SPI), >>> + K210_FUNC(SPI0_D6, SPI), >>> + K210_FUNC(SPI0_D7, SPI), >>> + K210_FUNC(SPI0_SS0, OUT), >>> + K210_FUNC(SPI0_SS1, OUT), >>> + K210_FUNC(SPI0_SS2, OUT), >>> + K210_FUNC(SPI0_SS3, OUT), >>> + K210_FUNC(SPI0_ARB, IN_TIE), >>> + K210_FUNC(SPI0_SCLK, OUT), >>> + K210_FUNC(UARTHS_RX, IN), >>> + K210_FUNC(UARTHS_TX, OUT), >>> + K210_FUNC(RESV6, IN), >>> + K210_FUNC(RESV7, IN), >>> + K210_FUNC(CLK_SPI1, OUT), >>> + K210_FUNC(CLK_I2C1, OUT), >>> + K210_FUNC(GPIOHS0, GPIO), >>> + K210_FUNC(GPIOHS1, GPIO), >>> + K210_FUNC(GPIOHS2, GPIO), >>> + K210_FUNC(GPIOHS3, GPIO), >>> + K210_FUNC(GPIOHS4, GPIO), >>> + K210_FUNC(GPIOHS5, GPIO), >>> + K210_FUNC(GPIOHS6, GPIO), >>> + K210_FUNC(GPIOHS7, GPIO), >>> + K210_FUNC(GPIOHS8, GPIO), >>> + K210_FUNC(GPIOHS9, GPIO), >>> + K210_FUNC(GPIOHS10, GPIO), >>> + K210_FUNC(GPIOHS11, GPIO), >>> + K210_FUNC(GPIOHS12, GPIO), >>> + K210_FUNC(GPIOHS13, GPIO), >>> + K210_FUNC(GPIOHS14, GPIO), >>> + K210_FUNC(GPIOHS15, GPIO), >>> + K210_FUNC(GPIOHS16, GPIO), >>> + K210_FUNC(GPIOHS17, GPIO), >>> + K210_FUNC(GPIOHS18, GPIO), >>> + K210_FUNC(GPIOHS19, GPIO), >>> + K210_FUNC(GPIOHS20, GPIO), >>> + K210_FUNC(GPIOHS21, GPIO), >>> + K210_FUNC(GPIOHS22, GPIO), >>> + K210_FUNC(GPIOHS23, GPIO), >>> + K210_FUNC(GPIOHS24, GPIO), >>> + K210_FUNC(GPIOHS25, GPIO), >>> + K210_FUNC(GPIOHS26, GPIO), >>> + K210_FUNC(GPIOHS27, GPIO), >>> + K210_FUNC(GPIOHS28, GPIO), >>> + K210_FUNC(GPIOHS29, GPIO), >>> + K210_FUNC(GPIOHS30, GPIO), >>> + K210_FUNC(GPIOHS31, GPIO), >>> + K210_FUNC(GPIO0, GPIO), >>> + K210_FUNC(GPIO1, GPIO), >>> + K210_FUNC(GPIO2, GPIO), >>> + K210_FUNC(GPIO3, GPIO), >>> + K210_FUNC(GPIO4, GPIO), >>> + K210_FUNC(GPIO5, GPIO), >>> + K210_FUNC(GPIO6, GPIO), >>> + K210_FUNC(GPIO7, GPIO), >>> + K210_FUNC(UART1_RX, IN), >>> + K210_FUNC(UART1_TX, OUT), >>> + K210_FUNC(UART2_RX, IN), >>> + K210_FUNC(UART2_TX, OUT), >>> + K210_FUNC(UART3_RX, IN), >>> + K210_FUNC(UART3_TX, OUT), >>> + K210_FUNC(SPI1_D0, SPI), >>> + K210_FUNC(SPI1_D1, SPI), >>> + K210_FUNC(SPI1_D2, SPI), >>> + K210_FUNC(SPI1_D3, SPI), >>> + K210_FUNC(SPI1_D4, SPI), >>> + K210_FUNC(SPI1_D5, SPI), >>> + K210_FUNC(SPI1_D6, SPI), >>> + K210_FUNC(SPI1_D7, SPI), >>> + K210_FUNC(SPI1_SS0, OUT), >>> + K210_FUNC(SPI1_SS1, OUT), >>> + K210_FUNC(SPI1_SS2, OUT), >>> + K210_FUNC(SPI1_SS3, OUT), >>> + K210_FUNC(SPI1_ARB, IN_TIE), >>> + K210_FUNC(SPI1_SCLK, OUT), >>> + K210_FUNC(SPI2_D0, SPI), >>> + K210_FUNC(SPI2_SS, IN), >>> + K210_FUNC(SPI2_SCLK, IN), >>> + K210_FUNC(I2S0_MCLK, OUT), >>> + K210_FUNC(I2S0_SCLK, OUT), >>> + K210_FUNC(I2S0_WS, OUT), >>> + K210_FUNC(I2S0_IN_D0, IN), >>> + K210_FUNC(I2S0_IN_D1, IN), >>> + K210_FUNC(I2S0_IN_D2, IN), >>> + K210_FUNC(I2S0_IN_D3, IN), >>> + K210_FUNC(I2S0_OUT_D0, OUT), >>> + K210_FUNC(I2S0_OUT_D1, OUT), >>> + K210_FUNC(I2S0_OUT_D2, OUT), >>> + K210_FUNC(I2S0_OUT_D3, OUT), >>> + K210_FUNC(I2S1_MCLK, OUT), >>> + K210_FUNC(I2S1_SCLK, OUT), >>> + K210_FUNC(I2S1_WS, OUT), >>> + K210_FUNC(I2S1_IN_D0, IN), >>> + K210_FUNC(I2S1_IN_D1, IN), >>> + K210_FUNC(I2S1_IN_D2, IN), >>> + K210_FUNC(I2S1_IN_D3, IN), >>> + K210_FUNC(I2S1_OUT_D0, OUT), >>> + K210_FUNC(I2S1_OUT_D1, OUT), >>> + K210_FUNC(I2S1_OUT_D2, OUT), >>> + K210_FUNC(I2S1_OUT_D3, OUT), >>> + K210_FUNC(I2S2_MCLK, OUT), >>> + K210_FUNC(I2S2_SCLK, OUT), >>> + K210_FUNC(I2S2_WS, OUT), >>> + K210_FUNC(I2S2_IN_D0, IN), >>> + K210_FUNC(I2S2_IN_D1, IN), >>> + K210_FUNC(I2S2_IN_D2, IN), >>> + K210_FUNC(I2S2_IN_D3, IN), >>> + K210_FUNC(I2S2_OUT_D0, OUT), >>> + K210_FUNC(I2S2_OUT_D1, OUT), >>> + K210_FUNC(I2S2_OUT_D2, OUT), >>> + K210_FUNC(I2S2_OUT_D3, OUT), >>> + K210_FUNC(RESV0, DISABLED), >>> + K210_FUNC(RESV1, DISABLED), >>> + K210_FUNC(RESV2, DISABLED), >>> + K210_FUNC(RESV3, DISABLED), >>> + K210_FUNC(RESV4, DISABLED), >>> + K210_FUNC(RESV5, DISABLED), >>> + K210_FUNC(I2C0_SCLK, I2C), >>> + K210_FUNC(I2C0_SDA, I2C), >>> + K210_FUNC(I2C1_SCLK, I2C), >>> + K210_FUNC(I2C1_SDA, I2C), >>> + K210_FUNC(I2C2_SCLK, I2C), >>> + K210_FUNC(I2C2_SDA, I2C), >>> + K210_FUNC(DVP_XCLK, OUT), >>> + K210_FUNC(DVP_RST, OUT), >>> + K210_FUNC(DVP_PWDN, OUT), >>> + K210_FUNC(DVP_VSYNC, IN), >>> + K210_FUNC(DVP_HSYNC, IN), >>> + K210_FUNC(DVP_PCLK, IN), >>> + K210_FUNC(DVP_D0, IN), >>> + K210_FUNC(DVP_D1, IN), >>> + K210_FUNC(DVP_D2, IN), >>> + K210_FUNC(DVP_D3, IN), >>> + K210_FUNC(DVP_D4, IN), >>> + K210_FUNC(DVP_D5, IN), >>> + K210_FUNC(DVP_D6, IN), >>> + K210_FUNC(DVP_D7, IN), >>> + K210_FUNC(SCCB_SCLK, SCCB), >>> + K210_FUNC(SCCB_SDA, SCCB), >>> + K210_FUNC(UART1_CTS, IN), >>> + K210_FUNC(UART1_DSR, IN), >>> + K210_FUNC(UART1_DCD, IN), >>> + K210_FUNC(UART1_RI, IN), >>> + K210_FUNC(UART1_SIR_IN, IN), >>> + K210_FUNC(UART1_DTR, OUT), >>> + K210_FUNC(UART1_RTS, OUT), >>> + K210_FUNC(UART1_OUT2, OUT), >>> + K210_FUNC(UART1_OUT1, OUT), >>> + K210_FUNC(UART1_SIR_OUT, OUT), >>> + K210_FUNC(UART1_BAUD, OUT), >>> + K210_FUNC(UART1_RE, OUT), >>> + K210_FUNC(UART1_DE, OUT), >>> + K210_FUNC(UART1_RS485_EN, OUT), >>> + K210_FUNC(UART2_CTS, IN), >>> + K210_FUNC(UART2_DSR, IN), >>> + K210_FUNC(UART2_DCD, IN), >>> + K210_FUNC(UART2_RI, IN), >>> + K210_FUNC(UART2_SIR_IN, IN), >>> + K210_FUNC(UART2_DTR, OUT), >>> + K210_FUNC(UART2_RTS, OUT), >>> + K210_FUNC(UART2_OUT2, OUT), >>> + K210_FUNC(UART2_OUT1, OUT), >>> + K210_FUNC(UART2_SIR_OUT, OUT), >>> + K210_FUNC(UART2_BAUD, OUT), >>> + K210_FUNC(UART2_RE, OUT), >>> + K210_FUNC(UART2_DE, OUT), >>> + K210_FUNC(UART2_RS485_EN, OUT), >>> + K210_FUNC(UART3_CTS, IN), >>> + K210_FUNC(UART3_DSR, IN), >>> + K210_FUNC(UART3_DCD, IN), >>> + K210_FUNC(UART3_RI, IN), >>> + K210_FUNC(UART3_SIR_IN, IN), >>> + K210_FUNC(UART3_DTR, OUT), >>> + K210_FUNC(UART3_RTS, OUT), >>> + K210_FUNC(UART3_OUT2, OUT), >>> + K210_FUNC(UART3_OUT1, OUT), >>> + K210_FUNC(UART3_SIR_OUT, OUT), >>> + K210_FUNC(UART3_BAUD, OUT), >>> + K210_FUNC(UART3_RE, OUT), >>> + K210_FUNC(UART3_DE, OUT), >>> + K210_FUNC(UART3_RS485_EN, OUT), >>> + K210_FUNC(TIMER0_TOGGLE1, OUT), >>> + K210_FUNC(TIMER0_TOGGLE2, OUT), >>> + K210_FUNC(TIMER0_TOGGLE3, OUT), >>> + K210_FUNC(TIMER0_TOGGLE4, OUT), >>> + K210_FUNC(TIMER1_TOGGLE1, OUT), >>> + K210_FUNC(TIMER1_TOGGLE2, OUT), >>> + K210_FUNC(TIMER1_TOGGLE3, OUT), >>> + K210_FUNC(TIMER1_TOGGLE4, OUT), >>> + K210_FUNC(TIMER2_TOGGLE1, OUT), >>> + K210_FUNC(TIMER2_TOGGLE2, OUT), >>> + K210_FUNC(TIMER2_TOGGLE3, OUT), >>> + K210_FUNC(TIMER2_TOGGLE4, OUT), >>> + K210_FUNC(CLK_SPI2, OUT), >>> + K210_FUNC(CLK_I2C2, OUT), >>> + K210_FUNC(INTERNAL0, OUT), >>> + K210_FUNC(INTERNAL1, OUT), >>> + K210_FUNC(INTERNAL2, OUT), >>> + K210_FUNC(INTERNAL3, OUT), >>> + K210_FUNC(INTERNAL4, OUT), >>> + K210_FUNC(INTERNAL5, OUT), >>> + K210_FUNC(INTERNAL6, OUT), >>> + K210_FUNC(INTERNAL7, OUT), >>> + K210_FUNC(INTERNAL8, OUT), >>> + K210_FUNC(INTERNAL9, IN), >>> + K210_FUNC(INTERNAL10, IN), >>> + K210_FUNC(INTERNAL11, IN), >>> + K210_FUNC(INTERNAL12, IN), >>> + K210_FUNC(INTERNAL13, INT13), >>> + K210_FUNC(INTERNAL14, I2C), >>> + K210_FUNC(INTERNAL15, IN), >>> + K210_FUNC(INTERNAL16, IN), >>> + K210_FUNC(INTERNAL17, IN), >>> + K210_FUNC(CONSTANT, DISABLED), >>> + K210_FUNC(INTERNAL18, IN), >>> + K210_FUNC(DEBUG0, OUT), >>> + K210_FUNC(DEBUG1, OUT), >>> + K210_FUNC(DEBUG2, OUT), >>> + K210_FUNC(DEBUG3, OUT), >>> + K210_FUNC(DEBUG4, OUT), >>> + K210_FUNC(DEBUG5, OUT), >>> + K210_FUNC(DEBUG6, OUT), >>> + K210_FUNC(DEBUG7, OUT), >>> + K210_FUNC(DEBUG8, OUT), >>> + K210_FUNC(DEBUG9, OUT), >>> + K210_FUNC(DEBUG10, OUT), >>> + K210_FUNC(DEBUG11, OUT), >>> + K210_FUNC(DEBUG12, OUT), >>> + K210_FUNC(DEBUG13, OUT), >>> + K210_FUNC(DEBUG14, OUT), >>> + K210_FUNC(DEBUG15, OUT), >>> + K210_FUNC(DEBUG16, OUT), >>> + K210_FUNC(DEBUG17, OUT), >>> + K210_FUNC(DEBUG18, OUT), >>> + K210_FUNC(DEBUG19, OUT), >>> + K210_FUNC(DEBUG20, OUT), >>> + K210_FUNC(DEBUG21, OUT), >>> + K210_FUNC(DEBUG22, OUT), >>> + K210_FUNC(DEBUG23, OUT), >>> + K210_FUNC(DEBUG24, OUT), >>> + K210_FUNC(DEBUG25, OUT), >>> + K210_FUNC(DEBUG26, OUT), >>> + K210_FUNC(DEBUG27, OUT), >>> + K210_FUNC(DEBUG28, OUT), >>> + K210_FUNC(DEBUG29, OUT), >>> + K210_FUNC(DEBUG30, OUT), >>> + K210_FUNC(DEBUG31, OUT), >>> +}; >>> + >>> +#define PIN_CONFIG_OUTPUT_INVERT (PIN_CONFIG_END + 1) >>> +#define PIN_CONFIG_INPUT_INVERT (PIN_CONFIG_END + 2) >>> + >>> +static const struct pinconf_generic_params k210_pinconf_custom_params[] = { >>> + { "output-polarity-invert", PIN_CONFIG_OUTPUT_INVERT, 1 }, >>> + { "input-polarity-invert", PIN_CONFIG_INPUT_INVERT, 1 }, >>> +}; >>> + >>> +/* >>> + * Max drive strength in uA. >>> + */ >>> +static const int k210_pinconf_drive_strength[] = { >>> + [0] = 11200, >>> + [1] = 16800, >>> + [2] = 22300, >>> + [3] = 27800, >>> + [4] = 33300, >>> + [5] = 38700, >>> + [6] = 44100, >>> + [7] = 49500, >>> +}; >>> + >>> +static int k210_pinconf_get_drive(unsigned int max_strength_ua) >>> +{ >>> + int i; >>> + >>> + for (i = K210_PC_DRIVE_MAX; i; i--) { >>> + if (k210_pinconf_drive_strength[i] <= max_strength_ua) >>> + return i; >>> + } >>> + >>> + return -EINVAL; >>> +} >>> + >>> +static void k210_pinmux_set_pin_function(struct pinctrl_dev *pctldev, >>> + u32 pin, u32 func) >>> +{ >>> + struct k210_fpioa_data *pdata = pinctrl_dev_get_drvdata(pctldev); >>> + const struct k210_pcf_info *info = &k210_pcf_infos[func]; >>> + u32 mode = k210_pinconf_mode_id_to_mode[info->mode_id]; >>> + u32 val = func | mode; >>> + >>> + dev_dbg(pdata->dev, "set pin %u function %s (%u) -> 0x%08x\n", >>> + pin, info->name, func, val); >>> + >>> + writel(val, &pdata->fpioa->pins[pin]); >>> +} >>> + >>> +static int k210_pinconf_set_param(struct pinctrl_dev *pctldev, >>> + unsigned int pin, >>> + unsigned int param, unsigned int arg) >>> +{ >>> + struct k210_fpioa_data *pdata = pinctrl_dev_get_drvdata(pctldev); >>> + u32 val = readl(&pdata->fpioa->pins[pin]); >>> + int drive; >>> + >>> + dev_dbg(pdata->dev, "set pin %u param %u, arg 0x%x\n", >>> + pin, param, arg); >>> + >>> + switch (param) { >>> + case PIN_CONFIG_BIAS_DISABLE: >>> + val &= ~K210_PC_BIAS_MASK; >>> + break; >>> + case PIN_CONFIG_BIAS_PULL_DOWN: >>> + if (!arg) >>> + return -EINVAL; >>> + val |= K210_PC_PD; >>> + break; >>> + case PIN_CONFIG_BIAS_PULL_UP: >>> + if (!arg) >>> + return -EINVAL; >>> + val |= K210_PC_PD; >>> + break; >>> + case PIN_CONFIG_DRIVE_STRENGTH: >>> + arg *= 1000; >>> + fallthrough; >>> + case PIN_CONFIG_DRIVE_STRENGTH_UA: >>> + drive = k210_pinconf_get_drive(arg); >>> + if (drive < 0) >>> + return drive; >>> + val &= ~K210_PC_DRIVE_MASK; >>> + val |= FIELD_PREP(K210_PC_DRIVE_MASK, drive); >>> + break; >>> + case PIN_CONFIG_INPUT_ENABLE: >>> + if (arg) >>> + val |= K210_PC_IE; >>> + else >>> + val &= ~K210_PC_IE; >>> + break; >>> + case PIN_CONFIG_INPUT_SCHMITT_ENABLE: >>> + if (arg) >>> + val |= K210_PC_ST; >>> + else >>> + val &= ~K210_PC_ST; >>> + break; >>> + case PIN_CONFIG_OUTPUT: >>> + k210_pinmux_set_pin_function(pctldev, pin, K210_PCF_CONSTANT); >>> + val = readl(&pdata->fpioa->pins[pin]); >>> + val |= K210_PC_MODE_OUT; >>> + if (!arg) >>> + val |= K210_PC_DO_INV; >>> + break; >>> + case PIN_CONFIG_OUTPUT_ENABLE: >>> + if (arg) >>> + val |= K210_PC_OE; >>> + else >>> + val &= ~K210_PC_OE; >>> + break; >>> + case PIN_CONFIG_SLEW_RATE: >>> + if (arg) >>> + val |= K210_PC_SL; >>> + else >>> + val &= ~K210_PC_SL; >>> + break; >>> + case PIN_CONFIG_OUTPUT_INVERT: >>> + if (arg) >>> + val |= K210_PC_DO_INV; >>> + else >>> + val &= ~K210_PC_DO_INV; >>> + break; >>> + case PIN_CONFIG_INPUT_INVERT: >>> + if (arg) >>> + val |= K210_PC_DI_INV; >>> + else >>> + val &= ~K210_PC_DI_INV; >>> + break; >>> + default: >>> + return -EINVAL; >>> + } >>> + >>> + writel(val, &pdata->fpioa->pins[pin]); >>> + >>> + return 0; >>> +} >>> + >>> +static int k210_pinconf_set(struct pinctrl_dev *pctldev, unsigned int pin, >>> + unsigned long *configs, unsigned int num_configs) >>> +{ >>> + unsigned int param, arg; >>> + int i, ret; >>> + >>> + if (WARN_ON(pin >= K210_NPINS)) >>> + return -EINVAL; >>> + >>> + for (i = 0; i < num_configs; i++) { >>> + param = pinconf_to_config_param(configs[i]); >>> + arg = pinconf_to_config_argument(configs[i]); >>> + ret = k210_pinconf_set_param(pctldev, pin, param, arg); >>> + if (ret) >>> + return ret; >>> + } >>> + >>> + return 0; >>> +} >>> + >>> +static void k210_pinconf_dbg_show(struct pinctrl_dev *pctldev, >>> + struct seq_file *s, unsigned int pin) >>> +{ >>> + struct k210_fpioa_data *pdata = pinctrl_dev_get_drvdata(pctldev); >>> + >>> + seq_printf(s, "%#x", readl(&pdata->fpioa->pins[pin])); >>> +} >>> + >>> +static int k210_pinconf_group_set(struct pinctrl_dev *pctldev, >>> + unsigned int selector, unsigned long *configs, >>> + unsigned int num_configs) >>> +{ >>> + struct k210_fpioa_data *pdata = pinctrl_dev_get_drvdata(pctldev); >>> + unsigned int param, arg; >>> + u32 bit; >>> + int i; >>> + >>> + /* Pins should be configured with pinmux, not groups*/ >>> + if (selector < K210_NPINS) >>> + return -EINVAL; >>> + >>> + /* Otherwise it's a power domain */ >>> + for (i = 0; i < num_configs; i++) { >>> + param = pinconf_to_config_param(configs[i]); >>> + if (param != PIN_CONFIG_POWER_SOURCE) >>> + return -EINVAL; >>> + >>> + arg = pinconf_to_config_argument(configs[i]); >>> + bit = BIT(selector - K210_NPINS); >>> + regmap_update_bits(pdata->sysctl_map, >>> + pdata->power_offset, >>> + bit, arg ? bit : 0); >>> + } >>> + >>> + return 0; >>> +} >>> + >>> +static void k210_pinconf_group_dbg_show(struct pinctrl_dev *pctldev, >>> + struct seq_file *s, >>> + unsigned int selector) >>> +{ >>> + struct k210_fpioa_data *pdata = pinctrl_dev_get_drvdata(pctldev); >>> + int ret; >>> + u32 val; >>> + >>> + if (selector < K210_NPINS) >>> + return k210_pinconf_dbg_show(pctldev, s, selector); >>> + >>> + ret = regmap_read(pdata->sysctl_map, pdata->power_offset, &val); >>> + if (ret) { >>> + dev_err(pdata->dev, "Failed to read power reg\n"); >>> + return; >>> + } >>> + >>> + seq_printf(s, "%s: %s V", k210_group_names[selector], >>> + val & BIT(selector - K210_NPINS) ? "1.8" : "3.3"); >>> +} >>> + >>> +static const struct pinconf_ops k210_pinconf_ops = { >>> + .is_generic = true, >>> + .pin_config_set = k210_pinconf_set, >>> + .pin_config_group_set = k210_pinconf_group_set, >>> + .pin_config_dbg_show = k210_pinconf_dbg_show, >>> + .pin_config_group_dbg_show = k210_pinconf_group_dbg_show, >>> +}; >>> + >>> +static int k210_pinmux_get_function_count(struct pinctrl_dev *pctldev) >>> +{ >>> + return ARRAY_SIZE(k210_pcf_infos); >>> +} >>> + >>> +static const char *k210_pinmux_get_function_name(struct pinctrl_dev *pctldev, >>> + unsigned int selector) >>> +{ >>> + return k210_pcf_infos[selector].name; >>> +} >>> + >>> +static int k210_pinmux_get_function_groups(struct pinctrl_dev *pctldev, >>> + unsigned int selector, >>> + const char * const **groups, >>> + unsigned int * const num_groups) >>> +{ >>> + /* Any function can be mapped to any pin */ >>> + *groups = k210_group_names; >>> + *num_groups = K210_NPINS; >>> + >>> + return 0; >>> +} >>> + >>> +static int k210_pinmux_set_mux(struct pinctrl_dev *pctldev, >>> + unsigned int function, >>> + unsigned int group) >>> +{ >>> + /* Can't mux power domains */ >>> + if (group >= K210_NPINS) >>> + return -EINVAL; >>> + >>> + k210_pinmux_set_pin_function(pctldev, group, function); >>> + >>> + return 0; >>> +} >>> + >>> +static const struct pinmux_ops k210_pinmux_ops = { >>> + .get_functions_count = k210_pinmux_get_function_count, >>> + .get_function_name = k210_pinmux_get_function_name, >>> + .get_function_groups = k210_pinmux_get_function_groups, >>> + .set_mux = k210_pinmux_set_mux, >>> + .strict = true, >>> +}; >>> + >>> +static int k210_pinctrl_get_groups_count(struct pinctrl_dev *pctldev) >>> +{ >>> + return K210_NGROUPS; >>> +} >>> + >>> +static const char *k210_pinctrl_get_group_name(struct pinctrl_dev *pctldev, >>> + unsigned int group) >>> +{ >>> + return k210_group_names[group]; >>> +} >>> + >>> +static int k210_pinctrl_get_group_pins(struct pinctrl_dev *pctldev, >>> + unsigned int group, >>> + const unsigned int **pins, >>> + unsigned int *npins) >>> +{ >>> + if (group >= K210_NPINS) { >>> + *pins = NULL; >>> + *npins = 0; >>> + return 0; >>> + } >>> + >>> + *pins = &k210_pins[group].number; >>> + *npins = 1; >>> + >>> + return 0; >>> +} >>> + >>> +static void k210_pinctrl_pin_dbg_show(struct pinctrl_dev *pctldev, >>> + struct seq_file *s, unsigned int offset) >>> +{ >>> + seq_printf(s, "%s", dev_name(pctldev->dev)); >>> +} >>> + >>> +static int k210_pinctrl_dt_subnode_to_map(struct pinctrl_dev *pctldev, >>> + struct device_node *np, >>> + struct pinctrl_map **map, >>> + unsigned int *reserved_maps, >>> + unsigned int *num_maps) >>> +{ >>> + struct property *prop; >>> + const __be32 *p; >>> + int ret, pinmux_groups; >>> + u32 pinmux_group; >>> + unsigned long *configs = NULL; >>> + unsigned int num_configs = 0; >>> + unsigned int reserve = 0; >>> + >>> + ret = of_property_count_strings(np, "groups"); >>> + if (!ret) >>> + return pinconf_generic_dt_subnode_to_map(pctldev, np, map, >>> + reserved_maps, num_maps, >>> + PIN_MAP_TYPE_CONFIGS_GROUP); >>> + >>> + pinmux_groups = of_property_count_u32_elems(np, "pinmux"); >>> + if (pinmux_groups <= 0) { >>> + /* Ignore this node */ >>> + return 0; >>> + } >>> + >>> + ret = pinconf_generic_parse_dt_config(np, pctldev, &configs, >>> + &num_configs); >>> + if (ret < 0) { >>> + dev_err(pctldev->dev, "%pOF: could not parse node property\n", >>> + np); >>> + return ret; >>> + } >>> + >>> + reserve = pinmux_groups * (1 + num_configs); >>> + ret = pinctrl_utils_reserve_map(pctldev, map, reserved_maps, num_maps, >>> + reserve); >>> + if (ret < 0) >>> + goto exit; >>> + >>> + of_property_for_each_u32(np, "pinmux", prop, p, pinmux_group) { >>> + const char *group_name, *func_name; >>> + u32 pin = FIELD_GET(K210_PG_PIN, pinmux_group); >>> + u32 func = FIELD_GET(K210_PG_FUNC, pinmux_group); >>> + >>> + if (pin >= K210_NPINS) { >>> + ret = -EINVAL; >>> + goto exit; >>> + } >>> + >>> + group_name = k210_group_names[pin]; >>> + func_name = k210_pcf_infos[func].name; >>> + >>> + dev_dbg(pctldev->dev, "Pinmux %s: pin %u func %s\n", >>> + np->name, pin, func_name); >>> + >>> + ret = pinctrl_utils_add_map_mux(pctldev, map, reserved_maps, >>> + num_maps, group_name, >>> + func_name); >>> + if (ret < 0) { >>> + dev_err(pctldev->dev, "%pOF add mux map failed %d\n", >>> + np, ret); >>> + goto exit; >>> + } >>> + >>> + if (num_configs) { >>> + ret = pinctrl_utils_add_map_configs(pctldev, map, >>> + reserved_maps, num_maps, group_name, >>> + configs, num_configs, >>> + PIN_MAP_TYPE_CONFIGS_PIN); >>> + if (ret < 0) { >>> + dev_err(pctldev->dev, >>> + "%pOF add configs map failed %d\n", >>> + np, ret); >>> + goto exit; >>> + } >>> + } >>> + } >>> + >>> + ret = 0; >>> + >>> +exit: >>> + kfree(configs); >>> + return ret; >>> +} >>> + >>> +static int k210_pinctrl_dt_node_to_map(struct pinctrl_dev *pctldev, >>> + struct device_node *np_config, >>> + struct pinctrl_map **map, >>> + unsigned int *num_maps) >>> +{ >>> + unsigned int reserved_maps; >>> + struct device_node *np; >>> + int ret; >>> + >>> + reserved_maps = 0; >>> + *map = NULL; >>> + *num_maps = 0; >>> + >>> + ret = k210_pinctrl_dt_subnode_to_map(pctldev, np_config, map, >>> + &reserved_maps, num_maps); >>> + if (ret < 0) >>> + goto err; >>> + >>> + for_each_available_child_of_node(np_config, np) { >>> + ret = k210_pinctrl_dt_subnode_to_map(pctldev, np, map, >>> + &reserved_maps, num_maps); >>> + if (ret < 0) >>> + goto err; >>> + } >>> + return 0; >>> + >>> +err: >>> + pinctrl_utils_free_map(pctldev, *map, *num_maps); >>> + return ret; >>> +} >>> + >>> + >>> +static const struct pinctrl_ops k210_pinctrl_ops = { >>> + .get_groups_count = k210_pinctrl_get_groups_count, >>> + .get_group_name = k210_pinctrl_get_group_name, >>> + .get_group_pins = k210_pinctrl_get_group_pins, >>> + .pin_dbg_show = k210_pinctrl_pin_dbg_show, >>> + .dt_node_to_map = k210_pinctrl_dt_node_to_map, >>> + .dt_free_map = pinconf_generic_dt_free_map, >>> +}; >>> + >>> +static struct pinctrl_desc k210_pinctrl_desc = { >>> + .name = "k210-pinctrl", >>> + .pins = k210_pins, >>> + .npins = K210_NPINS, >>> + .pctlops = &k210_pinctrl_ops, >>> + .pmxops = &k210_pinmux_ops, >>> + .confops = &k210_pinconf_ops, >>> + .custom_params = k210_pinconf_custom_params, >>> + .num_custom_params = ARRAY_SIZE(k210_pinconf_custom_params), >>> +}; >>> + >>> +static void k210_fpioa_init_ties(struct k210_fpioa_data *pdata) >>> +{ >>> + struct k210_fpioa __iomem *fpioa = pdata->fpioa; >>> + u32 val; >>> + int i, j; >>> + >>> + dev_dbg(pdata->dev, "Init pin ties\n"); >>> + >>> + /* Init pin functions input ties */ >>> + for (i = 0; i < ARRAY_SIZE(fpioa->tie_en); i++) { >>> + val = 0; >>> + for (j = 0; j < 32; j++) { >>> + if (k210_pcf_infos[i * 32 + j].mode_id == >>> + K210_PC_DEFAULT_IN_TIE) { >>> + dev_dbg(pdata->dev, >>> + "tie_en function %d (%s)\n", >>> + i * 32 + j, >>> + k210_pcf_infos[i * 32 + j].name); >>> + val |= BIT(j); >>> + } >>> + } >>> + >>> + /* Set value before enable */ >>> + writel(val, &fpioa->tie_val[i]); >>> + writel(val, &fpioa->tie_en[i]); >>> + } >>> +} >>> + >>> +static int k210_fpioa_probe(struct platform_device *pdev) >>> +{ >>> + struct device *dev = &pdev->dev; >>> + struct device_node *np = dev->of_node; >>> + struct k210_fpioa_data *pdata; >>> + int ret; >>> + >>> + dev_info(dev, "K210 FPIOA pin controller\n"); >>> + >>> + pdata = devm_kzalloc(dev, sizeof(*pdata), GFP_KERNEL); >>> + if (!pdata) >>> + return -ENOMEM; >>> + >>> + pdata->dev = dev; >>> + platform_set_drvdata(pdev, pdata); >>> + >>> + pdata->fpioa = devm_platform_ioremap_resource(pdev, 0); >>> + if (IS_ERR(pdata->fpioa)) >>> + return PTR_ERR(pdata->fpioa); >>> + >>> + pdata->clk = devm_clk_get(dev, "ref"); >>> + if (IS_ERR(pdata->clk)) >>> + return PTR_ERR(pdata->clk); >>> + >>> + ret = clk_prepare_enable(pdata->clk); >>> + if (ret) >>> + return ret; >>> + >>> + pdata->pclk = devm_clk_get_optional(dev, "pclk"); >>> + if (!IS_ERR(pdata->pclk)) >>> + clk_prepare_enable(pdata->pclk); >>> + >>> + pdata->sysctl_map = >>> + syscon_regmap_lookup_by_phandle_args(np, >>> + "canaan,k210-sysctl-power", >>> + 1, &pdata->power_offset); >>> + if (IS_ERR(pdata->sysctl_map)) >>> + return PTR_ERR(pdata->sysctl_map); >>> + >>> + k210_fpioa_init_ties(pdata); >>> + >>> + pdata->pctl = pinctrl_register(&k210_pinctrl_desc, dev, (void *)pdata); >>> + if (IS_ERR(pdata->pctl)) >>> + return PTR_ERR(pdata->pctl); >>> + >>> + return 0; >>> +} >>> + >>> +static const struct of_device_id k210_fpioa_dt_ids[] = { >>> + { .compatible = "canaan,k210-fpioa" }, >>> + { /* sentinel */ }, >>> +}; >>> + >>> +static struct platform_driver k210_fpioa_driver = { >>> + .probe = k210_fpioa_probe, >>> + .driver = { >>> + .name = "k210-fpioa", >>> + .of_match_table = k210_fpioa_dt_ids, >>> + }, >>> +}; >>> +builtin_platform_driver(k210_fpioa_driver); >> > >
diff --git a/MAINTAINERS b/MAINTAINERS index 637b79eba693..1a7a1e4092e2 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -3860,6 +3860,13 @@ W: https://github.com/Cascoda/ca8210-linux.git F: Documentation/devicetree/bindings/net/ieee802154/ca8210.txt F: drivers/net/ieee802154/ca8210.c +CANAAN/KENDRYTE K210 SOC FPIOA DRIVER +M: Damien Le Moal <damien.lemoal@wdc.com> +L: linux-riscv@lists.infradead.org +L: linux-gpio@vger.kernel.org (pinctrl driver) +F: Documentation/devicetree/bindings/pinctrl/canaan,k210-fpioa.yaml +F: drivers/pinctrl/pinctrl-k210.c + CANAAN/KENDRYTE K210 SOC RESET CONTROLLER DRIVER M: Damien Le Moal <damien.lemoal@wdc.com> L: linux-kernel@vger.kernel.org diff --git a/arch/riscv/Kconfig.socs b/arch/riscv/Kconfig.socs index 57e53219c500..6402746c68f3 100644 --- a/arch/riscv/Kconfig.socs +++ b/arch/riscv/Kconfig.socs @@ -30,6 +30,7 @@ config SOC_CANAAN select SERIAL_SIFIVE_CONSOLE if TTY select SIFIVE_PLIC select ARCH_HAS_RESET_CONTROLLER + select PINCTRL help This enables support for Canaan Kendryte K210 SoC platform hardware. diff --git a/drivers/pinctrl/Kconfig b/drivers/pinctrl/Kconfig index d4b2f2e2ed75..cd437e3cc255 100644 --- a/drivers/pinctrl/Kconfig +++ b/drivers/pinctrl/Kconfig @@ -394,6 +394,19 @@ config PINCTRL_MICROCHIP_SGPIO connect control signals from SFP modules and to act as an LED controller. +config PINCTRL_K210 + bool "Pinctrl driver for the Canaan Kendryte K210 SoC" + depends on RISCV && SOC_CANAAN && OF + select GENERIC_PINMUX_FUNCTIONS + select GENERIC_PINCONF + select GPIOLIB + select OF_GPIO + select REGMAP_MMIO + default SOC_CANAAN + help + Add support for the Canaan Kendryte K210 RISC-V SOC Field + Programmable IO Array (FPIOA) controller. + source "drivers/pinctrl/actions/Kconfig" source "drivers/pinctrl/aspeed/Kconfig" source "drivers/pinctrl/bcm/Kconfig" diff --git a/drivers/pinctrl/Makefile b/drivers/pinctrl/Makefile index 5bb9bb6cc3ce..152c8fe51726 100644 --- a/drivers/pinctrl/Makefile +++ b/drivers/pinctrl/Makefile @@ -48,6 +48,7 @@ obj-$(CONFIG_PINCTRL_RK805) += pinctrl-rk805.o obj-$(CONFIG_PINCTRL_OCELOT) += pinctrl-ocelot.o obj-$(CONFIG_PINCTRL_MICROCHIP_SGPIO) += pinctrl-microchip-sgpio.o obj-$(CONFIG_PINCTRL_EQUILIBRIUM) += pinctrl-equilibrium.o +obj-$(CONFIG_PINCTRL_K210) += pinctrl-k210.o obj-y += actions/ obj-$(CONFIG_ARCH_ASPEED) += aspeed/ diff --git a/drivers/pinctrl/pinctrl-k210.c b/drivers/pinctrl/pinctrl-k210.c new file mode 100644 index 000000000000..8a733cf77ba0 --- /dev/null +++ b/drivers/pinctrl/pinctrl-k210.c @@ -0,0 +1,985 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Copyright (C) 2020 Sean Anderson <seanga2@gmail.com> + * Copyright (c) 2020 Western Digital Corporation or its affiliates. + */ +#include <linux/io.h> +#include <linux/of_device.h> +#include <linux/clk.h> +#include <linux/mfd/syscon.h> +#include <linux/platform_device.h> +#include <linux/bitfield.h> +#include <linux/regmap.h> +#include <linux/slab.h> +#include <linux/pinctrl/pinctrl.h> +#include <linux/pinctrl/pinmux.h> +#include <linux/pinctrl/pinconf.h> +#include <linux/pinctrl/pinconf-generic.h> +#include <linux/io.h> + +#include <dt-bindings/pinctrl/k210-fpioa.h> + +#include "core.h" +#include "pinconf.h" +#include "pinctrl-utils.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 Output Enable */ +#define K210_PC_DO_OE BIT(14) /* set Data Out to Output Enable sig */ +#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 */ +/* Same semantics as OE above */ +#define K210_PC_IE BIT(20) /* Input Enable */ +#define K210_PC_IE_INV BIT(21) /* INVert 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_SL | \ + K210_PC_OE | K210_PC_PU) +#define K210_PC_MODE_SCCB (K210_PC_MODE_I2C | \ + K210_PC_OE_INV | K210_PC_IE_INV) +#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) + +/* + * struct k210_fpioa: Kendryte K210 FPIOA memory mapped registers + * @pins: 48 32-bits IO pin registers + * @tie_en: 256 (one per function) input tie enable bits + * @tie_val: 256 (one per function) input tie value bits + */ +struct k210_fpioa { + u32 pins[48]; + u32 tie_en[8]; + u32 tie_val[8]; +}; + +struct k210_fpioa_data { + + struct device *dev; + struct pinctrl_dev *pctl; + + struct k210_fpioa __iomem *fpioa; + struct regmap *sysctl_map; + u32 power_offset; + struct clk *clk; + struct clk *pclk; +}; + +#define K210_PIN_NAME(i) ("IO_" #i) +#define K210_PIN(i) [(i)] = PINCTRL_PIN((i), K210_PIN_NAME(i)) + +static const struct pinctrl_pin_desc k210_pins[] = { + K210_PIN(0), K210_PIN(1), K210_PIN(2), + K210_PIN(3), K210_PIN(4), K210_PIN(5), + K210_PIN(6), K210_PIN(7), K210_PIN(8), + K210_PIN(9), K210_PIN(10), K210_PIN(11), + K210_PIN(12), K210_PIN(13), K210_PIN(14), + K210_PIN(15), K210_PIN(16), K210_PIN(17), + K210_PIN(18), K210_PIN(19), K210_PIN(20), + K210_PIN(21), K210_PIN(22), K210_PIN(23), + K210_PIN(24), K210_PIN(25), K210_PIN(26), + K210_PIN(27), K210_PIN(28), K210_PIN(29), + K210_PIN(30), K210_PIN(31), K210_PIN(32), + K210_PIN(33), K210_PIN(34), K210_PIN(35), + K210_PIN(36), K210_PIN(37), K210_PIN(38), + K210_PIN(39), K210_PIN(40), K210_PIN(41), + K210_PIN(42), K210_PIN(43), K210_PIN(44), + K210_PIN(45), K210_PIN(46), K210_PIN(47) +}; + +#define K210_NPINS ARRAY_SIZE(k210_pins) + +/* + * Pin groups: each of the 48 programmable pins is a group. + * To this are added 8 power domain groups, which for the purposes of + * the pin subsystem, contain no pins. The power domain groups only exist + * to set the power level. The id should never be used (since there are + * no pins 48-55). + */ +static const char *const k210_group_names[] = { + /* The first 48 groups are for pins, one each */ + K210_PIN_NAME(0), K210_PIN_NAME(1), K210_PIN_NAME(2), + K210_PIN_NAME(3), K210_PIN_NAME(4), K210_PIN_NAME(5), + K210_PIN_NAME(6), K210_PIN_NAME(7), K210_PIN_NAME(8), + K210_PIN_NAME(9), K210_PIN_NAME(10), K210_PIN_NAME(11), + K210_PIN_NAME(12), K210_PIN_NAME(13), K210_PIN_NAME(14), + K210_PIN_NAME(15), K210_PIN_NAME(16), K210_PIN_NAME(17), + K210_PIN_NAME(18), K210_PIN_NAME(19), K210_PIN_NAME(20), + K210_PIN_NAME(21), K210_PIN_NAME(22), K210_PIN_NAME(23), + K210_PIN_NAME(24), K210_PIN_NAME(25), K210_PIN_NAME(26), + K210_PIN_NAME(27), K210_PIN_NAME(28), K210_PIN_NAME(29), + K210_PIN_NAME(30), K210_PIN_NAME(31), K210_PIN_NAME(32), + K210_PIN_NAME(33), K210_PIN_NAME(34), K210_PIN_NAME(35), + K210_PIN_NAME(36), K210_PIN_NAME(37), K210_PIN_NAME(38), + K210_PIN_NAME(39), K210_PIN_NAME(40), K210_PIN_NAME(41), + K210_PIN_NAME(42), K210_PIN_NAME(43), K210_PIN_NAME(44), + K210_PIN_NAME(45), K210_PIN_NAME(46), K210_PIN_NAME(47), + [48] = "A0", [49] = "A1", [50] = "A2", + [51] = "B3", [52] = "B4", [53] = "B5", + [54] = "C6", [55] = "C7" +}; + +#define K210_NGROUPS ARRAY_SIZE(k210_group_names) + +enum k210_pinctrl_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_SCCB, + K210_PC_DEFAULT_SPI, + K210_PC_DEFAULT_GPIO, + K210_PC_DEFAULT_INT13, +}; + +#define K210_PC_DEFAULT(mode) \ + [K210_PC_DEFAULT_##mode] = K210_PC_MODE_##mode + +static const u32 k210_pinconf_mode_id_to_mode[] = { + [K210_PC_DEFAULT_DISABLED] = 0, + K210_PC_DEFAULT(IN), + [K210_PC_DEFAULT_IN_TIE] = K210_PC_MODE_IN, + K210_PC_DEFAULT(OUT), + K210_PC_DEFAULT(I2C), + K210_PC_DEFAULT(SCCB), + K210_PC_DEFAULT(SPI), + K210_PC_DEFAULT(GPIO), + [K210_PC_DEFAULT_INT13] = K210_PC_MODE_IN | K210_PC_PU, +}; + +#undef DEFAULT + +/* + * Pin functions configuration information. + */ +struct k210_pcf_info { + char name[15]; + u8 mode_id; +}; + +#define K210_FUNC(id, mode) \ + [K210_PCF_##id] = { \ + .name = #id, \ + .mode_id = K210_PC_DEFAULT_##mode \ + } + +static const struct k210_pcf_info k210_pcf_infos[] = { + K210_FUNC(JTAG_TCLK, IN), + K210_FUNC(JTAG_TDI, IN), + K210_FUNC(JTAG_TMS, IN), + K210_FUNC(JTAG_TDO, OUT), + K210_FUNC(SPI0_D0, SPI), + K210_FUNC(SPI0_D1, SPI), + K210_FUNC(SPI0_D2, SPI), + K210_FUNC(SPI0_D3, SPI), + K210_FUNC(SPI0_D4, SPI), + K210_FUNC(SPI0_D5, SPI), + K210_FUNC(SPI0_D6, SPI), + K210_FUNC(SPI0_D7, SPI), + K210_FUNC(SPI0_SS0, OUT), + K210_FUNC(SPI0_SS1, OUT), + K210_FUNC(SPI0_SS2, OUT), + K210_FUNC(SPI0_SS3, OUT), + K210_FUNC(SPI0_ARB, IN_TIE), + K210_FUNC(SPI0_SCLK, OUT), + K210_FUNC(UARTHS_RX, IN), + K210_FUNC(UARTHS_TX, OUT), + K210_FUNC(RESV6, IN), + K210_FUNC(RESV7, IN), + K210_FUNC(CLK_SPI1, OUT), + K210_FUNC(CLK_I2C1, OUT), + K210_FUNC(GPIOHS0, GPIO), + K210_FUNC(GPIOHS1, GPIO), + K210_FUNC(GPIOHS2, GPIO), + K210_FUNC(GPIOHS3, GPIO), + K210_FUNC(GPIOHS4, GPIO), + K210_FUNC(GPIOHS5, GPIO), + K210_FUNC(GPIOHS6, GPIO), + K210_FUNC(GPIOHS7, GPIO), + K210_FUNC(GPIOHS8, GPIO), + K210_FUNC(GPIOHS9, GPIO), + K210_FUNC(GPIOHS10, GPIO), + K210_FUNC(GPIOHS11, GPIO), + K210_FUNC(GPIOHS12, GPIO), + K210_FUNC(GPIOHS13, GPIO), + K210_FUNC(GPIOHS14, GPIO), + K210_FUNC(GPIOHS15, GPIO), + K210_FUNC(GPIOHS16, GPIO), + K210_FUNC(GPIOHS17, GPIO), + K210_FUNC(GPIOHS18, GPIO), + K210_FUNC(GPIOHS19, GPIO), + K210_FUNC(GPIOHS20, GPIO), + K210_FUNC(GPIOHS21, GPIO), + K210_FUNC(GPIOHS22, GPIO), + K210_FUNC(GPIOHS23, GPIO), + K210_FUNC(GPIOHS24, GPIO), + K210_FUNC(GPIOHS25, GPIO), + K210_FUNC(GPIOHS26, GPIO), + K210_FUNC(GPIOHS27, GPIO), + K210_FUNC(GPIOHS28, GPIO), + K210_FUNC(GPIOHS29, GPIO), + K210_FUNC(GPIOHS30, GPIO), + K210_FUNC(GPIOHS31, GPIO), + K210_FUNC(GPIO0, GPIO), + K210_FUNC(GPIO1, GPIO), + K210_FUNC(GPIO2, GPIO), + K210_FUNC(GPIO3, GPIO), + K210_FUNC(GPIO4, GPIO), + K210_FUNC(GPIO5, GPIO), + K210_FUNC(GPIO6, GPIO), + K210_FUNC(GPIO7, GPIO), + K210_FUNC(UART1_RX, IN), + K210_FUNC(UART1_TX, OUT), + K210_FUNC(UART2_RX, IN), + K210_FUNC(UART2_TX, OUT), + K210_FUNC(UART3_RX, IN), + K210_FUNC(UART3_TX, OUT), + K210_FUNC(SPI1_D0, SPI), + K210_FUNC(SPI1_D1, SPI), + K210_FUNC(SPI1_D2, SPI), + K210_FUNC(SPI1_D3, SPI), + K210_FUNC(SPI1_D4, SPI), + K210_FUNC(SPI1_D5, SPI), + K210_FUNC(SPI1_D6, SPI), + K210_FUNC(SPI1_D7, SPI), + K210_FUNC(SPI1_SS0, OUT), + K210_FUNC(SPI1_SS1, OUT), + K210_FUNC(SPI1_SS2, OUT), + K210_FUNC(SPI1_SS3, OUT), + K210_FUNC(SPI1_ARB, IN_TIE), + K210_FUNC(SPI1_SCLK, OUT), + K210_FUNC(SPI2_D0, SPI), + K210_FUNC(SPI2_SS, IN), + K210_FUNC(SPI2_SCLK, IN), + K210_FUNC(I2S0_MCLK, OUT), + K210_FUNC(I2S0_SCLK, OUT), + K210_FUNC(I2S0_WS, OUT), + K210_FUNC(I2S0_IN_D0, IN), + K210_FUNC(I2S0_IN_D1, IN), + K210_FUNC(I2S0_IN_D2, IN), + K210_FUNC(I2S0_IN_D3, IN), + K210_FUNC(I2S0_OUT_D0, OUT), + K210_FUNC(I2S0_OUT_D1, OUT), + K210_FUNC(I2S0_OUT_D2, OUT), + K210_FUNC(I2S0_OUT_D3, OUT), + K210_FUNC(I2S1_MCLK, OUT), + K210_FUNC(I2S1_SCLK, OUT), + K210_FUNC(I2S1_WS, OUT), + K210_FUNC(I2S1_IN_D0, IN), + K210_FUNC(I2S1_IN_D1, IN), + K210_FUNC(I2S1_IN_D2, IN), + K210_FUNC(I2S1_IN_D3, IN), + K210_FUNC(I2S1_OUT_D0, OUT), + K210_FUNC(I2S1_OUT_D1, OUT), + K210_FUNC(I2S1_OUT_D2, OUT), + K210_FUNC(I2S1_OUT_D3, OUT), + K210_FUNC(I2S2_MCLK, OUT), + K210_FUNC(I2S2_SCLK, OUT), + K210_FUNC(I2S2_WS, OUT), + K210_FUNC(I2S2_IN_D0, IN), + K210_FUNC(I2S2_IN_D1, IN), + K210_FUNC(I2S2_IN_D2, IN), + K210_FUNC(I2S2_IN_D3, IN), + K210_FUNC(I2S2_OUT_D0, OUT), + K210_FUNC(I2S2_OUT_D1, OUT), + K210_FUNC(I2S2_OUT_D2, OUT), + K210_FUNC(I2S2_OUT_D3, OUT), + K210_FUNC(RESV0, DISABLED), + K210_FUNC(RESV1, DISABLED), + K210_FUNC(RESV2, DISABLED), + K210_FUNC(RESV3, DISABLED), + K210_FUNC(RESV4, DISABLED), + K210_FUNC(RESV5, DISABLED), + K210_FUNC(I2C0_SCLK, I2C), + K210_FUNC(I2C0_SDA, I2C), + K210_FUNC(I2C1_SCLK, I2C), + K210_FUNC(I2C1_SDA, I2C), + K210_FUNC(I2C2_SCLK, I2C), + K210_FUNC(I2C2_SDA, I2C), + K210_FUNC(DVP_XCLK, OUT), + K210_FUNC(DVP_RST, OUT), + K210_FUNC(DVP_PWDN, OUT), + K210_FUNC(DVP_VSYNC, IN), + K210_FUNC(DVP_HSYNC, IN), + K210_FUNC(DVP_PCLK, IN), + K210_FUNC(DVP_D0, IN), + K210_FUNC(DVP_D1, IN), + K210_FUNC(DVP_D2, IN), + K210_FUNC(DVP_D3, IN), + K210_FUNC(DVP_D4, IN), + K210_FUNC(DVP_D5, IN), + K210_FUNC(DVP_D6, IN), + K210_FUNC(DVP_D7, IN), + K210_FUNC(SCCB_SCLK, SCCB), + K210_FUNC(SCCB_SDA, SCCB), + K210_FUNC(UART1_CTS, IN), + K210_FUNC(UART1_DSR, IN), + K210_FUNC(UART1_DCD, IN), + K210_FUNC(UART1_RI, IN), + K210_FUNC(UART1_SIR_IN, IN), + K210_FUNC(UART1_DTR, OUT), + K210_FUNC(UART1_RTS, OUT), + K210_FUNC(UART1_OUT2, OUT), + K210_FUNC(UART1_OUT1, OUT), + K210_FUNC(UART1_SIR_OUT, OUT), + K210_FUNC(UART1_BAUD, OUT), + K210_FUNC(UART1_RE, OUT), + K210_FUNC(UART1_DE, OUT), + K210_FUNC(UART1_RS485_EN, OUT), + K210_FUNC(UART2_CTS, IN), + K210_FUNC(UART2_DSR, IN), + K210_FUNC(UART2_DCD, IN), + K210_FUNC(UART2_RI, IN), + K210_FUNC(UART2_SIR_IN, IN), + K210_FUNC(UART2_DTR, OUT), + K210_FUNC(UART2_RTS, OUT), + K210_FUNC(UART2_OUT2, OUT), + K210_FUNC(UART2_OUT1, OUT), + K210_FUNC(UART2_SIR_OUT, OUT), + K210_FUNC(UART2_BAUD, OUT), + K210_FUNC(UART2_RE, OUT), + K210_FUNC(UART2_DE, OUT), + K210_FUNC(UART2_RS485_EN, OUT), + K210_FUNC(UART3_CTS, IN), + K210_FUNC(UART3_DSR, IN), + K210_FUNC(UART3_DCD, IN), + K210_FUNC(UART3_RI, IN), + K210_FUNC(UART3_SIR_IN, IN), + K210_FUNC(UART3_DTR, OUT), + K210_FUNC(UART3_RTS, OUT), + K210_FUNC(UART3_OUT2, OUT), + K210_FUNC(UART3_OUT1, OUT), + K210_FUNC(UART3_SIR_OUT, OUT), + K210_FUNC(UART3_BAUD, OUT), + K210_FUNC(UART3_RE, OUT), + K210_FUNC(UART3_DE, OUT), + K210_FUNC(UART3_RS485_EN, OUT), + K210_FUNC(TIMER0_TOGGLE1, OUT), + K210_FUNC(TIMER0_TOGGLE2, OUT), + K210_FUNC(TIMER0_TOGGLE3, OUT), + K210_FUNC(TIMER0_TOGGLE4, OUT), + K210_FUNC(TIMER1_TOGGLE1, OUT), + K210_FUNC(TIMER1_TOGGLE2, OUT), + K210_FUNC(TIMER1_TOGGLE3, OUT), + K210_FUNC(TIMER1_TOGGLE4, OUT), + K210_FUNC(TIMER2_TOGGLE1, OUT), + K210_FUNC(TIMER2_TOGGLE2, OUT), + K210_FUNC(TIMER2_TOGGLE3, OUT), + K210_FUNC(TIMER2_TOGGLE4, OUT), + K210_FUNC(CLK_SPI2, OUT), + K210_FUNC(CLK_I2C2, OUT), + K210_FUNC(INTERNAL0, OUT), + K210_FUNC(INTERNAL1, OUT), + K210_FUNC(INTERNAL2, OUT), + K210_FUNC(INTERNAL3, OUT), + K210_FUNC(INTERNAL4, OUT), + K210_FUNC(INTERNAL5, OUT), + K210_FUNC(INTERNAL6, OUT), + K210_FUNC(INTERNAL7, OUT), + K210_FUNC(INTERNAL8, OUT), + K210_FUNC(INTERNAL9, IN), + K210_FUNC(INTERNAL10, IN), + K210_FUNC(INTERNAL11, IN), + K210_FUNC(INTERNAL12, IN), + K210_FUNC(INTERNAL13, INT13), + K210_FUNC(INTERNAL14, I2C), + K210_FUNC(INTERNAL15, IN), + K210_FUNC(INTERNAL16, IN), + K210_FUNC(INTERNAL17, IN), + K210_FUNC(CONSTANT, DISABLED), + K210_FUNC(INTERNAL18, IN), + K210_FUNC(DEBUG0, OUT), + K210_FUNC(DEBUG1, OUT), + K210_FUNC(DEBUG2, OUT), + K210_FUNC(DEBUG3, OUT), + K210_FUNC(DEBUG4, OUT), + K210_FUNC(DEBUG5, OUT), + K210_FUNC(DEBUG6, OUT), + K210_FUNC(DEBUG7, OUT), + K210_FUNC(DEBUG8, OUT), + K210_FUNC(DEBUG9, OUT), + K210_FUNC(DEBUG10, OUT), + K210_FUNC(DEBUG11, OUT), + K210_FUNC(DEBUG12, OUT), + K210_FUNC(DEBUG13, OUT), + K210_FUNC(DEBUG14, OUT), + K210_FUNC(DEBUG15, OUT), + K210_FUNC(DEBUG16, OUT), + K210_FUNC(DEBUG17, OUT), + K210_FUNC(DEBUG18, OUT), + K210_FUNC(DEBUG19, OUT), + K210_FUNC(DEBUG20, OUT), + K210_FUNC(DEBUG21, OUT), + K210_FUNC(DEBUG22, OUT), + K210_FUNC(DEBUG23, OUT), + K210_FUNC(DEBUG24, OUT), + K210_FUNC(DEBUG25, OUT), + K210_FUNC(DEBUG26, OUT), + K210_FUNC(DEBUG27, OUT), + K210_FUNC(DEBUG28, OUT), + K210_FUNC(DEBUG29, OUT), + K210_FUNC(DEBUG30, OUT), + K210_FUNC(DEBUG31, OUT), +}; + +#define PIN_CONFIG_OUTPUT_INVERT (PIN_CONFIG_END + 1) +#define PIN_CONFIG_INPUT_INVERT (PIN_CONFIG_END + 2) + +static const struct pinconf_generic_params k210_pinconf_custom_params[] = { + { "output-polarity-invert", PIN_CONFIG_OUTPUT_INVERT, 1 }, + { "input-polarity-invert", PIN_CONFIG_INPUT_INVERT, 1 }, +}; + +/* + * Max drive strength in uA. + */ +static const int k210_pinconf_drive_strength[] = { + [0] = 11200, + [1] = 16800, + [2] = 22300, + [3] = 27800, + [4] = 33300, + [5] = 38700, + [6] = 44100, + [7] = 49500, +}; + +static int k210_pinconf_get_drive(unsigned int max_strength_ua) +{ + int i; + + for (i = K210_PC_DRIVE_MAX; i; i--) { + if (k210_pinconf_drive_strength[i] <= max_strength_ua) + return i; + } + + return -EINVAL; +} + +static void k210_pinmux_set_pin_function(struct pinctrl_dev *pctldev, + u32 pin, u32 func) +{ + struct k210_fpioa_data *pdata = pinctrl_dev_get_drvdata(pctldev); + const struct k210_pcf_info *info = &k210_pcf_infos[func]; + u32 mode = k210_pinconf_mode_id_to_mode[info->mode_id]; + u32 val = func | mode; + + dev_dbg(pdata->dev, "set pin %u function %s (%u) -> 0x%08x\n", + pin, info->name, func, val); + + writel(val, &pdata->fpioa->pins[pin]); +} + +static int k210_pinconf_set_param(struct pinctrl_dev *pctldev, + unsigned int pin, + unsigned int param, unsigned int arg) +{ + struct k210_fpioa_data *pdata = pinctrl_dev_get_drvdata(pctldev); + u32 val = readl(&pdata->fpioa->pins[pin]); + int drive; + + dev_dbg(pdata->dev, "set pin %u param %u, arg 0x%x\n", + pin, param, arg); + + switch (param) { + case PIN_CONFIG_BIAS_DISABLE: + val &= ~K210_PC_BIAS_MASK; + break; + case PIN_CONFIG_BIAS_PULL_DOWN: + if (!arg) + return -EINVAL; + val |= K210_PC_PD; + break; + case PIN_CONFIG_BIAS_PULL_UP: + if (!arg) + return -EINVAL; + val |= K210_PC_PD; + break; + case PIN_CONFIG_DRIVE_STRENGTH: + arg *= 1000; + fallthrough; + case PIN_CONFIG_DRIVE_STRENGTH_UA: + drive = k210_pinconf_get_drive(arg); + if (drive < 0) + return drive; + val &= ~K210_PC_DRIVE_MASK; + val |= FIELD_PREP(K210_PC_DRIVE_MASK, drive); + break; + case PIN_CONFIG_INPUT_ENABLE: + if (arg) + val |= K210_PC_IE; + else + val &= ~K210_PC_IE; + break; + case PIN_CONFIG_INPUT_SCHMITT_ENABLE: + if (arg) + val |= K210_PC_ST; + else + val &= ~K210_PC_ST; + break; + case PIN_CONFIG_OUTPUT: + k210_pinmux_set_pin_function(pctldev, pin, K210_PCF_CONSTANT); + val = readl(&pdata->fpioa->pins[pin]); + val |= K210_PC_MODE_OUT; + if (!arg) + val |= K210_PC_DO_INV; + break; + case PIN_CONFIG_OUTPUT_ENABLE: + if (arg) + val |= K210_PC_OE; + else + val &= ~K210_PC_OE; + break; + case PIN_CONFIG_SLEW_RATE: + if (arg) + val |= K210_PC_SL; + else + val &= ~K210_PC_SL; + break; + case PIN_CONFIG_OUTPUT_INVERT: + if (arg) + val |= K210_PC_DO_INV; + else + val &= ~K210_PC_DO_INV; + break; + case PIN_CONFIG_INPUT_INVERT: + if (arg) + val |= K210_PC_DI_INV; + else + val &= ~K210_PC_DI_INV; + break; + default: + return -EINVAL; + } + + writel(val, &pdata->fpioa->pins[pin]); + + return 0; +} + +static int k210_pinconf_set(struct pinctrl_dev *pctldev, unsigned int pin, + unsigned long *configs, unsigned int num_configs) +{ + unsigned int param, arg; + int i, ret; + + if (WARN_ON(pin >= K210_NPINS)) + return -EINVAL; + + for (i = 0; i < num_configs; i++) { + param = pinconf_to_config_param(configs[i]); + arg = pinconf_to_config_argument(configs[i]); + ret = k210_pinconf_set_param(pctldev, pin, param, arg); + if (ret) + return ret; + } + + return 0; +} + +static void k210_pinconf_dbg_show(struct pinctrl_dev *pctldev, + struct seq_file *s, unsigned int pin) +{ + struct k210_fpioa_data *pdata = pinctrl_dev_get_drvdata(pctldev); + + seq_printf(s, "%#x", readl(&pdata->fpioa->pins[pin])); +} + +static int k210_pinconf_group_set(struct pinctrl_dev *pctldev, + unsigned int selector, unsigned long *configs, + unsigned int num_configs) +{ + struct k210_fpioa_data *pdata = pinctrl_dev_get_drvdata(pctldev); + unsigned int param, arg; + u32 bit; + int i; + + /* Pins should be configured with pinmux, not groups*/ + if (selector < K210_NPINS) + return -EINVAL; + + /* Otherwise it's a power domain */ + for (i = 0; i < num_configs; i++) { + param = pinconf_to_config_param(configs[i]); + if (param != PIN_CONFIG_POWER_SOURCE) + return -EINVAL; + + arg = pinconf_to_config_argument(configs[i]); + bit = BIT(selector - K210_NPINS); + regmap_update_bits(pdata->sysctl_map, + pdata->power_offset, + bit, arg ? bit : 0); + } + + return 0; +} + +static void k210_pinconf_group_dbg_show(struct pinctrl_dev *pctldev, + struct seq_file *s, + unsigned int selector) +{ + struct k210_fpioa_data *pdata = pinctrl_dev_get_drvdata(pctldev); + int ret; + u32 val; + + if (selector < K210_NPINS) + return k210_pinconf_dbg_show(pctldev, s, selector); + + ret = regmap_read(pdata->sysctl_map, pdata->power_offset, &val); + if (ret) { + dev_err(pdata->dev, "Failed to read power reg\n"); + return; + } + + seq_printf(s, "%s: %s V", k210_group_names[selector], + val & BIT(selector - K210_NPINS) ? "1.8" : "3.3"); +} + +static const struct pinconf_ops k210_pinconf_ops = { + .is_generic = true, + .pin_config_set = k210_pinconf_set, + .pin_config_group_set = k210_pinconf_group_set, + .pin_config_dbg_show = k210_pinconf_dbg_show, + .pin_config_group_dbg_show = k210_pinconf_group_dbg_show, +}; + +static int k210_pinmux_get_function_count(struct pinctrl_dev *pctldev) +{ + return ARRAY_SIZE(k210_pcf_infos); +} + +static const char *k210_pinmux_get_function_name(struct pinctrl_dev *pctldev, + unsigned int selector) +{ + return k210_pcf_infos[selector].name; +} + +static int k210_pinmux_get_function_groups(struct pinctrl_dev *pctldev, + unsigned int selector, + const char * const **groups, + unsigned int * const num_groups) +{ + /* Any function can be mapped to any pin */ + *groups = k210_group_names; + *num_groups = K210_NPINS; + + return 0; +} + +static int k210_pinmux_set_mux(struct pinctrl_dev *pctldev, + unsigned int function, + unsigned int group) +{ + /* Can't mux power domains */ + if (group >= K210_NPINS) + return -EINVAL; + + k210_pinmux_set_pin_function(pctldev, group, function); + + return 0; +} + +static const struct pinmux_ops k210_pinmux_ops = { + .get_functions_count = k210_pinmux_get_function_count, + .get_function_name = k210_pinmux_get_function_name, + .get_function_groups = k210_pinmux_get_function_groups, + .set_mux = k210_pinmux_set_mux, + .strict = true, +}; + +static int k210_pinctrl_get_groups_count(struct pinctrl_dev *pctldev) +{ + return K210_NGROUPS; +} + +static const char *k210_pinctrl_get_group_name(struct pinctrl_dev *pctldev, + unsigned int group) +{ + return k210_group_names[group]; +} + +static int k210_pinctrl_get_group_pins(struct pinctrl_dev *pctldev, + unsigned int group, + const unsigned int **pins, + unsigned int *npins) +{ + if (group >= K210_NPINS) { + *pins = NULL; + *npins = 0; + return 0; + } + + *pins = &k210_pins[group].number; + *npins = 1; + + return 0; +} + +static void k210_pinctrl_pin_dbg_show(struct pinctrl_dev *pctldev, + struct seq_file *s, unsigned int offset) +{ + seq_printf(s, "%s", dev_name(pctldev->dev)); +} + +static int k210_pinctrl_dt_subnode_to_map(struct pinctrl_dev *pctldev, + struct device_node *np, + struct pinctrl_map **map, + unsigned int *reserved_maps, + unsigned int *num_maps) +{ + struct property *prop; + const __be32 *p; + int ret, pinmux_groups; + u32 pinmux_group; + unsigned long *configs = NULL; + unsigned int num_configs = 0; + unsigned int reserve = 0; + + ret = of_property_count_strings(np, "groups"); + if (!ret) + return pinconf_generic_dt_subnode_to_map(pctldev, np, map, + reserved_maps, num_maps, + PIN_MAP_TYPE_CONFIGS_GROUP); + + pinmux_groups = of_property_count_u32_elems(np, "pinmux"); + if (pinmux_groups <= 0) { + /* Ignore this node */ + return 0; + } + + ret = pinconf_generic_parse_dt_config(np, pctldev, &configs, + &num_configs); + if (ret < 0) { + dev_err(pctldev->dev, "%pOF: could not parse node property\n", + np); + return ret; + } + + reserve = pinmux_groups * (1 + num_configs); + ret = pinctrl_utils_reserve_map(pctldev, map, reserved_maps, num_maps, + reserve); + if (ret < 0) + goto exit; + + of_property_for_each_u32(np, "pinmux", prop, p, pinmux_group) { + const char *group_name, *func_name; + u32 pin = FIELD_GET(K210_PG_PIN, pinmux_group); + u32 func = FIELD_GET(K210_PG_FUNC, pinmux_group); + + if (pin >= K210_NPINS) { + ret = -EINVAL; + goto exit; + } + + group_name = k210_group_names[pin]; + func_name = k210_pcf_infos[func].name; + + dev_dbg(pctldev->dev, "Pinmux %s: pin %u func %s\n", + np->name, pin, func_name); + + ret = pinctrl_utils_add_map_mux(pctldev, map, reserved_maps, + num_maps, group_name, + func_name); + if (ret < 0) { + dev_err(pctldev->dev, "%pOF add mux map failed %d\n", + np, ret); + goto exit; + } + + if (num_configs) { + ret = pinctrl_utils_add_map_configs(pctldev, map, + reserved_maps, num_maps, group_name, + configs, num_configs, + PIN_MAP_TYPE_CONFIGS_PIN); + if (ret < 0) { + dev_err(pctldev->dev, + "%pOF add configs map failed %d\n", + np, ret); + goto exit; + } + } + } + + ret = 0; + +exit: + kfree(configs); + return ret; +} + +static int k210_pinctrl_dt_node_to_map(struct pinctrl_dev *pctldev, + struct device_node *np_config, + struct pinctrl_map **map, + unsigned int *num_maps) +{ + unsigned int reserved_maps; + struct device_node *np; + int ret; + + reserved_maps = 0; + *map = NULL; + *num_maps = 0; + + ret = k210_pinctrl_dt_subnode_to_map(pctldev, np_config, map, + &reserved_maps, num_maps); + if (ret < 0) + goto err; + + for_each_available_child_of_node(np_config, np) { + ret = k210_pinctrl_dt_subnode_to_map(pctldev, np, map, + &reserved_maps, num_maps); + if (ret < 0) + goto err; + } + return 0; + +err: + pinctrl_utils_free_map(pctldev, *map, *num_maps); + return ret; +} + + +static const struct pinctrl_ops k210_pinctrl_ops = { + .get_groups_count = k210_pinctrl_get_groups_count, + .get_group_name = k210_pinctrl_get_group_name, + .get_group_pins = k210_pinctrl_get_group_pins, + .pin_dbg_show = k210_pinctrl_pin_dbg_show, + .dt_node_to_map = k210_pinctrl_dt_node_to_map, + .dt_free_map = pinconf_generic_dt_free_map, +}; + +static struct pinctrl_desc k210_pinctrl_desc = { + .name = "k210-pinctrl", + .pins = k210_pins, + .npins = K210_NPINS, + .pctlops = &k210_pinctrl_ops, + .pmxops = &k210_pinmux_ops, + .confops = &k210_pinconf_ops, + .custom_params = k210_pinconf_custom_params, + .num_custom_params = ARRAY_SIZE(k210_pinconf_custom_params), +}; + +static void k210_fpioa_init_ties(struct k210_fpioa_data *pdata) +{ + struct k210_fpioa __iomem *fpioa = pdata->fpioa; + u32 val; + int i, j; + + dev_dbg(pdata->dev, "Init pin ties\n"); + + /* Init pin functions input ties */ + for (i = 0; i < ARRAY_SIZE(fpioa->tie_en); i++) { + val = 0; + for (j = 0; j < 32; j++) { + if (k210_pcf_infos[i * 32 + j].mode_id == + K210_PC_DEFAULT_IN_TIE) { + dev_dbg(pdata->dev, + "tie_en function %d (%s)\n", + i * 32 + j, + k210_pcf_infos[i * 32 + j].name); + val |= BIT(j); + } + } + + /* Set value before enable */ + writel(val, &fpioa->tie_val[i]); + writel(val, &fpioa->tie_en[i]); + } +} + +static int k210_fpioa_probe(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + struct device_node *np = dev->of_node; + struct k210_fpioa_data *pdata; + int ret; + + dev_info(dev, "K210 FPIOA pin controller\n"); + + pdata = devm_kzalloc(dev, sizeof(*pdata), GFP_KERNEL); + if (!pdata) + return -ENOMEM; + + pdata->dev = dev; + platform_set_drvdata(pdev, pdata); + + pdata->fpioa = devm_platform_ioremap_resource(pdev, 0); + if (IS_ERR(pdata->fpioa)) + return PTR_ERR(pdata->fpioa); + + pdata->clk = devm_clk_get(dev, "ref"); + if (IS_ERR(pdata->clk)) + return PTR_ERR(pdata->clk); + + ret = clk_prepare_enable(pdata->clk); + if (ret) + return ret; + + pdata->pclk = devm_clk_get_optional(dev, "pclk"); + if (!IS_ERR(pdata->pclk)) + clk_prepare_enable(pdata->pclk); + + pdata->sysctl_map = + syscon_regmap_lookup_by_phandle_args(np, + "canaan,k210-sysctl-power", + 1, &pdata->power_offset); + if (IS_ERR(pdata->sysctl_map)) + return PTR_ERR(pdata->sysctl_map); + + k210_fpioa_init_ties(pdata); + + pdata->pctl = pinctrl_register(&k210_pinctrl_desc, dev, (void *)pdata); + if (IS_ERR(pdata->pctl)) + return PTR_ERR(pdata->pctl); + + return 0; +} + +static const struct of_device_id k210_fpioa_dt_ids[] = { + { .compatible = "canaan,k210-fpioa" }, + { /* sentinel */ }, +}; + +static struct platform_driver k210_fpioa_driver = { + .probe = k210_fpioa_probe, + .driver = { + .name = "k210-fpioa", + .of_match_table = k210_fpioa_dt_ids, + }, +}; +builtin_platform_driver(k210_fpioa_driver);