All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH v11 02/10] pinctrl: Add RISC-V Canaan Kendryte K210 FPIOA driver
@ 2021-01-12  1:03 ` Damien Le Moal
  0 siblings, 0 replies; 24+ messages in thread
From: Damien Le Moal @ 2021-01-12  1:03 UTC (permalink / raw)
  To: Palmer Dabbelt, linux-riscv, Linus Walleij, linux-gpio; +Cc: Sean Anderson

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
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);
-- 
2.29.2


^ permalink raw reply related	[flat|nested] 24+ messages in thread

* [PATCH v11 02/10] pinctrl: Add RISC-V Canaan Kendryte K210 FPIOA driver
@ 2021-01-12  1:03 ` Damien Le Moal
  0 siblings, 0 replies; 24+ messages in thread
From: Damien Le Moal @ 2021-01-12  1:03 UTC (permalink / raw)
  To: Palmer Dabbelt, linux-riscv, Linus Walleij, linux-gpio; +Cc: Sean Anderson

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
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);
-- 
2.29.2


_______________________________________________
linux-riscv mailing list
linux-riscv@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-riscv

^ permalink raw reply related	[flat|nested] 24+ messages in thread

* Re: [PATCH v11 02/10] pinctrl: Add RISC-V Canaan Kendryte K210 FPIOA driver
  2021-01-12  1:03 ` Damien Le Moal
@ 2021-01-18 13:33   ` Linus Walleij
  -1 siblings, 0 replies; 24+ messages in thread
From: Linus Walleij @ 2021-01-18 13:33 UTC (permalink / raw)
  To: Damien Le Moal
  Cc: Palmer Dabbelt, linux-riscv, open list:GPIO SUBSYSTEM, Sean Anderson

Hi Damien,

this looks all right to me.
Reviewed-by: Linus Walleij <linus.walleij@linaro.org>

Shall I apply just this one patch to the pinctrl tree?

I think the line that touches arch/*/Kconfig should be dropped
then, that better go to the SoC tree.

Yours,
Linus Walleij

^ permalink raw reply	[flat|nested] 24+ messages in thread

* Re: [PATCH v11 02/10] pinctrl: Add RISC-V Canaan Kendryte K210 FPIOA driver
@ 2021-01-18 13:33   ` Linus Walleij
  0 siblings, 0 replies; 24+ messages in thread
From: Linus Walleij @ 2021-01-18 13:33 UTC (permalink / raw)
  To: Damien Le Moal
  Cc: open list:GPIO SUBSYSTEM, linux-riscv, Palmer Dabbelt, Sean Anderson

Hi Damien,

this looks all right to me.
Reviewed-by: Linus Walleij <linus.walleij@linaro.org>

Shall I apply just this one patch to the pinctrl tree?

I think the line that touches arch/*/Kconfig should be dropped
then, that better go to the SoC tree.

Yours,
Linus Walleij

_______________________________________________
linux-riscv mailing list
linux-riscv@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-riscv

^ permalink raw reply	[flat|nested] 24+ messages in thread

* Re: [PATCH v11 02/10] pinctrl: Add RISC-V Canaan Kendryte K210 FPIOA driver
  2021-01-18 13:33   ` Linus Walleij
@ 2021-01-19  0:06     ` Damien Le Moal
  -1 siblings, 0 replies; 24+ messages in thread
From: Damien Le Moal @ 2021-01-19  0:06 UTC (permalink / raw)
  To: Linus Walleij
  Cc: Palmer Dabbelt, linux-riscv, open list:GPIO SUBSYSTEM, Sean Anderson

On 2021/01/18 22:33, Linus Walleij wrote:
> Hi Damien,
> 
> this looks all right to me.
> Reviewed-by: Linus Walleij <linus.walleij@linaro.org>

Thanks !

> 
> Shall I apply just this one patch to the pinctrl tree?
> 
> I think the line that touches arch/*/Kconfig should be dropped
> then, that better go to the SoC tree.

Good point. I can send a v14 series that does that. Or simpler, if that is OK
with you and Palmer, Palmer could may be take the patch through the riscv tree ?

> 
> Yours,
> Linus Walleij
> 


-- 
Damien Le Moal
Western Digital Research

^ permalink raw reply	[flat|nested] 24+ messages in thread

* Re: [PATCH v11 02/10] pinctrl: Add RISC-V Canaan Kendryte K210 FPIOA driver
@ 2021-01-19  0:06     ` Damien Le Moal
  0 siblings, 0 replies; 24+ messages in thread
From: Damien Le Moal @ 2021-01-19  0:06 UTC (permalink / raw)
  To: Linus Walleij
  Cc: open list:GPIO SUBSYSTEM, linux-riscv, Palmer Dabbelt, Sean Anderson

On 2021/01/18 22:33, Linus Walleij wrote:
> Hi Damien,
> 
> this looks all right to me.
> Reviewed-by: Linus Walleij <linus.walleij@linaro.org>

Thanks !

> 
> Shall I apply just this one patch to the pinctrl tree?
> 
> I think the line that touches arch/*/Kconfig should be dropped
> then, that better go to the SoC tree.

Good point. I can send a v14 series that does that. Or simpler, if that is OK
with you and Palmer, Palmer could may be take the patch through the riscv tree ?

> 
> Yours,
> Linus Walleij
> 


-- 
Damien Le Moal
Western Digital Research

_______________________________________________
linux-riscv mailing list
linux-riscv@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-riscv

^ permalink raw reply	[flat|nested] 24+ messages in thread

* Re: [PATCH v11 02/10] pinctrl: Add RISC-V Canaan Kendryte K210 FPIOA driver
  2021-01-18 13:33   ` Linus Walleij
@ 2021-01-20 18:21     ` Palmer Dabbelt
  -1 siblings, 0 replies; 24+ messages in thread
From: Palmer Dabbelt @ 2021-01-20 18:21 UTC (permalink / raw)
  To: linus.walleij; +Cc: Damien Le Moal, linux-riscv, linux-gpio, seanga2

On Mon, 18 Jan 2021 05:33:05 PST (-0800), linus.walleij@linaro.org wrote:
> Hi Damien,
>
> this looks all right to me.
> Reviewed-by: Linus Walleij <linus.walleij@linaro.org>
>
> Shall I apply just this one patch to the pinctrl tree?

That's fine with me.  The DT bindings are in riscv/for-next, maybe it's best to
take those as well and I'll drop them?  I don't generally like to drop stuff
from for-next, but that's probably better than having everything all mixed up.

https://git.kernel.org/pub/scm/linux/kernel/git/riscv/linux.git/commit/?h=for-next&id=ed3137edb31b86702511e7ad12b4abe8686b6805

> I think the line that touches arch/*/Kconfig should be dropped
> then, that better go to the SoC tree.

I'm OK with you taking them along with my Ack, but if you don't want to that's
fine.  Just LMK

Acked-by: Palmer Dabbelt <palmerdabbelt@google.com>

> Yours,
> Linus Walleij

Thanks!

^ permalink raw reply	[flat|nested] 24+ messages in thread

* Re: [PATCH v11 02/10] pinctrl: Add RISC-V Canaan Kendryte K210 FPIOA driver
@ 2021-01-20 18:21     ` Palmer Dabbelt
  0 siblings, 0 replies; 24+ messages in thread
From: Palmer Dabbelt @ 2021-01-20 18:21 UTC (permalink / raw)
  To: linus.walleij; +Cc: linux-gpio, Damien Le Moal, linux-riscv, seanga2

On Mon, 18 Jan 2021 05:33:05 PST (-0800), linus.walleij@linaro.org wrote:
> Hi Damien,
>
> this looks all right to me.
> Reviewed-by: Linus Walleij <linus.walleij@linaro.org>
>
> Shall I apply just this one patch to the pinctrl tree?

That's fine with me.  The DT bindings are in riscv/for-next, maybe it's best to
take those as well and I'll drop them?  I don't generally like to drop stuff
from for-next, but that's probably better than having everything all mixed up.

https://git.kernel.org/pub/scm/linux/kernel/git/riscv/linux.git/commit/?h=for-next&id=ed3137edb31b86702511e7ad12b4abe8686b6805

> I think the line that touches arch/*/Kconfig should be dropped
> then, that better go to the SoC tree.

I'm OK with you taking them along with my Ack, but if you don't want to that's
fine.  Just LMK

Acked-by: Palmer Dabbelt <palmerdabbelt@google.com>

> Yours,
> Linus Walleij

Thanks!

_______________________________________________
linux-riscv mailing list
linux-riscv@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-riscv

^ permalink raw reply	[flat|nested] 24+ messages in thread

* Re: [PATCH v11 02/10] pinctrl: Add RISC-V Canaan Kendryte K210 FPIOA driver
  2021-01-20 18:21     ` Palmer Dabbelt
@ 2021-01-21  0:15       ` Damien Le Moal
  -1 siblings, 0 replies; 24+ messages in thread
From: Damien Le Moal @ 2021-01-21  0:15 UTC (permalink / raw)
  To: Palmer Dabbelt, linus.walleij; +Cc: linux-riscv, linux-gpio, seanga2

On 2021/01/21 3:21, Palmer Dabbelt wrote:
> On Mon, 18 Jan 2021 05:33:05 PST (-0800), linus.walleij@linaro.org wrote:
>> Hi Damien,
>>
>> this looks all right to me.
>> Reviewed-by: Linus Walleij <linus.walleij@linaro.org>
>>
>> Shall I apply just this one patch to the pinctrl tree?
> 
> That's fine with me.  The DT bindings are in riscv/for-next, maybe it's best to
> take those as well and I'll drop them?  I don't generally like to drop stuff
> from for-next, but that's probably better than having everything all mixed up.
> 
> https://git.kernel.org/pub/scm/linux/kernel/git/riscv/linux.git/commit/?h=for-next&id=ed3137edb31b86702511e7ad12b4abe8686b6805
> 
>> I think the line that touches arch/*/Kconfig should be dropped
>> then, that better go to the SoC tree.
> 
> I'm OK with you taking them along with my Ack, but if you don't want to that's
> fine.  Just LMK
> 
> Acked-by: Palmer Dabbelt <palmerdabbelt@google.com>

Linus,

Please let me know which way you want to proceed. If you want to take the patch,
I will resend without the Kconfig change and move that change to another patch.

Thanks !

> 
>> Yours,
>> Linus Walleij
> 
> Thanks!
> 


-- 
Damien Le Moal
Western Digital Research

^ permalink raw reply	[flat|nested] 24+ messages in thread

* Re: [PATCH v11 02/10] pinctrl: Add RISC-V Canaan Kendryte K210 FPIOA driver
@ 2021-01-21  0:15       ` Damien Le Moal
  0 siblings, 0 replies; 24+ messages in thread
From: Damien Le Moal @ 2021-01-21  0:15 UTC (permalink / raw)
  To: Palmer Dabbelt, linus.walleij; +Cc: linux-gpio, linux-riscv, seanga2

On 2021/01/21 3:21, Palmer Dabbelt wrote:
> On Mon, 18 Jan 2021 05:33:05 PST (-0800), linus.walleij@linaro.org wrote:
>> Hi Damien,
>>
>> this looks all right to me.
>> Reviewed-by: Linus Walleij <linus.walleij@linaro.org>
>>
>> Shall I apply just this one patch to the pinctrl tree?
> 
> That's fine with me.  The DT bindings are in riscv/for-next, maybe it's best to
> take those as well and I'll drop them?  I don't generally like to drop stuff
> from for-next, but that's probably better than having everything all mixed up.
> 
> https://git.kernel.org/pub/scm/linux/kernel/git/riscv/linux.git/commit/?h=for-next&id=ed3137edb31b86702511e7ad12b4abe8686b6805
> 
>> I think the line that touches arch/*/Kconfig should be dropped
>> then, that better go to the SoC tree.
> 
> I'm OK with you taking them along with my Ack, but if you don't want to that's
> fine.  Just LMK
> 
> Acked-by: Palmer Dabbelt <palmerdabbelt@google.com>

Linus,

Please let me know which way you want to proceed. If you want to take the patch,
I will resend without the Kconfig change and move that change to another patch.

Thanks !

> 
>> Yours,
>> Linus Walleij
> 
> Thanks!
> 


-- 
Damien Le Moal
Western Digital Research

_______________________________________________
linux-riscv mailing list
linux-riscv@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-riscv

^ permalink raw reply	[flat|nested] 24+ messages in thread

* Re: [PATCH v11 02/10] pinctrl: Add RISC-V Canaan Kendryte K210 FPIOA driver
  2021-01-21  0:15       ` Damien Le Moal
@ 2021-01-21  8:25         ` Linus Walleij
  -1 siblings, 0 replies; 24+ messages in thread
From: Linus Walleij @ 2021-01-21  8:25 UTC (permalink / raw)
  To: Damien Le Moal; +Cc: Palmer Dabbelt, linux-riscv, linux-gpio, seanga2

On Thu, Jan 21, 2021 at 1:15 AM Damien Le Moal <Damien.LeMoal@wdc.com> wrote:
> On 2021/01/21 3:21, Palmer Dabbelt wrote:
> > On Mon, 18 Jan 2021 05:33:05 PST (-0800), linus.walleij@linaro.org wrote:
> >> Hi Damien,
> >>
> >> this looks all right to me.
> >> Reviewed-by: Linus Walleij <linus.walleij@linaro.org>
> >>
> >> Shall I apply just this one patch to the pinctrl tree?
> >
> > That's fine with me.  The DT bindings are in riscv/for-next, maybe it's best to
> > take those as well and I'll drop them?  I don't generally like to drop stuff
> > from for-next, but that's probably better than having everything all mixed up.
> >
> > https://git.kernel.org/pub/scm/linux/kernel/git/riscv/linux.git/commit/?h=for-next&id=ed3137edb31b86702511e7ad12b4abe8686b6805
> >
> >> I think the line that touches arch/*/Kconfig should be dropped
> >> then, that better go to the SoC tree.
> >
> > I'm OK with you taking them along with my Ack, but if you don't want to that's
> > fine.  Just LMK
> >
> > Acked-by: Palmer Dabbelt <palmerdabbelt@google.com>
>
> Linus,
>
> Please let me know which way you want to proceed. If you want to take the patch,
> I will resend without the Kconfig change and move that change to another patch.

It's fine to proceed as is, since Palmer already applied the bindings to
his tree, just apply the pinctrl driver there as well. I don't see any
risk of collisions in the tree.

Yours,
Linus Walleij

^ permalink raw reply	[flat|nested] 24+ messages in thread

* Re: [PATCH v11 02/10] pinctrl: Add RISC-V Canaan Kendryte K210 FPIOA driver
@ 2021-01-21  8:25         ` Linus Walleij
  0 siblings, 0 replies; 24+ messages in thread
From: Linus Walleij @ 2021-01-21  8:25 UTC (permalink / raw)
  To: Damien Le Moal; +Cc: linux-gpio, linux-riscv, Palmer Dabbelt, seanga2

On Thu, Jan 21, 2021 at 1:15 AM Damien Le Moal <Damien.LeMoal@wdc.com> wrote:
> On 2021/01/21 3:21, Palmer Dabbelt wrote:
> > On Mon, 18 Jan 2021 05:33:05 PST (-0800), linus.walleij@linaro.org wrote:
> >> Hi Damien,
> >>
> >> this looks all right to me.
> >> Reviewed-by: Linus Walleij <linus.walleij@linaro.org>
> >>
> >> Shall I apply just this one patch to the pinctrl tree?
> >
> > That's fine with me.  The DT bindings are in riscv/for-next, maybe it's best to
> > take those as well and I'll drop them?  I don't generally like to drop stuff
> > from for-next, but that's probably better than having everything all mixed up.
> >
> > https://git.kernel.org/pub/scm/linux/kernel/git/riscv/linux.git/commit/?h=for-next&id=ed3137edb31b86702511e7ad12b4abe8686b6805
> >
> >> I think the line that touches arch/*/Kconfig should be dropped
> >> then, that better go to the SoC tree.
> >
> > I'm OK with you taking them along with my Ack, but if you don't want to that's
> > fine.  Just LMK
> >
> > Acked-by: Palmer Dabbelt <palmerdabbelt@google.com>
>
> Linus,
>
> Please let me know which way you want to proceed. If you want to take the patch,
> I will resend without the Kconfig change and move that change to another patch.

It's fine to proceed as is, since Palmer already applied the bindings to
his tree, just apply the pinctrl driver there as well. I don't see any
risk of collisions in the tree.

Yours,
Linus Walleij

_______________________________________________
linux-riscv mailing list
linux-riscv@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-riscv

^ permalink raw reply	[flat|nested] 24+ messages in thread

* Re: [PATCH v11 02/10] pinctrl: Add RISC-V Canaan Kendryte K210 FPIOA driver
  2021-01-21  8:25         ` Linus Walleij
@ 2021-01-21  8:32           ` Damien Le Moal
  -1 siblings, 0 replies; 24+ messages in thread
From: Damien Le Moal @ 2021-01-21  8:32 UTC (permalink / raw)
  To: Linus Walleij; +Cc: Palmer Dabbelt, linux-riscv, linux-gpio, seanga2

On 2021/01/21 17:25, Linus Walleij wrote:
> On Thu, Jan 21, 2021 at 1:15 AM Damien Le Moal <Damien.LeMoal@wdc.com> wrote:
>> On 2021/01/21 3:21, Palmer Dabbelt wrote:
>>> On Mon, 18 Jan 2021 05:33:05 PST (-0800), linus.walleij@linaro.org wrote:
>>>> Hi Damien,
>>>>
>>>> this looks all right to me.
>>>> Reviewed-by: Linus Walleij <linus.walleij@linaro.org>
>>>>
>>>> Shall I apply just this one patch to the pinctrl tree?
>>>
>>> That's fine with me.  The DT bindings are in riscv/for-next, maybe it's best to
>>> take those as well and I'll drop them?  I don't generally like to drop stuff
>>> from for-next, but that's probably better than having everything all mixed up.
>>>
>>> https://git.kernel.org/pub/scm/linux/kernel/git/riscv/linux.git/commit/?h=for-next&id=ed3137edb31b86702511e7ad12b4abe8686b6805
>>>
>>>> I think the line that touches arch/*/Kconfig should be dropped
>>>> then, that better go to the SoC tree.
>>>
>>> I'm OK with you taking them along with my Ack, but if you don't want to that's
>>> fine.  Just LMK
>>>
>>> Acked-by: Palmer Dabbelt <palmerdabbelt@google.com>
>>
>> Linus,
>>
>> Please let me know which way you want to proceed. If you want to take the patch,
>> I will resend without the Kconfig change and move that change to another patch.
> 
> It's fine to proceed as is, since Palmer already applied the bindings to
> his tree, just apply the pinctrl driver there as well. I don't see any
> risk of collisions in the tree.

Sounds good. Thanks !

> 
> Yours,
> Linus Walleij
> 


-- 
Damien Le Moal
Western Digital Research

^ permalink raw reply	[flat|nested] 24+ messages in thread

* Re: [PATCH v11 02/10] pinctrl: Add RISC-V Canaan Kendryte K210 FPIOA driver
@ 2021-01-21  8:32           ` Damien Le Moal
  0 siblings, 0 replies; 24+ messages in thread
From: Damien Le Moal @ 2021-01-21  8:32 UTC (permalink / raw)
  To: Linus Walleij; +Cc: linux-gpio, linux-riscv, Palmer Dabbelt, seanga2

On 2021/01/21 17:25, Linus Walleij wrote:
> On Thu, Jan 21, 2021 at 1:15 AM Damien Le Moal <Damien.LeMoal@wdc.com> wrote:
>> On 2021/01/21 3:21, Palmer Dabbelt wrote:
>>> On Mon, 18 Jan 2021 05:33:05 PST (-0800), linus.walleij@linaro.org wrote:
>>>> Hi Damien,
>>>>
>>>> this looks all right to me.
>>>> Reviewed-by: Linus Walleij <linus.walleij@linaro.org>
>>>>
>>>> Shall I apply just this one patch to the pinctrl tree?
>>>
>>> That's fine with me.  The DT bindings are in riscv/for-next, maybe it's best to
>>> take those as well and I'll drop them?  I don't generally like to drop stuff
>>> from for-next, but that's probably better than having everything all mixed up.
>>>
>>> https://git.kernel.org/pub/scm/linux/kernel/git/riscv/linux.git/commit/?h=for-next&id=ed3137edb31b86702511e7ad12b4abe8686b6805
>>>
>>>> I think the line that touches arch/*/Kconfig should be dropped
>>>> then, that better go to the SoC tree.
>>>
>>> I'm OK with you taking them along with my Ack, but if you don't want to that's
>>> fine.  Just LMK
>>>
>>> Acked-by: Palmer Dabbelt <palmerdabbelt@google.com>
>>
>> Linus,
>>
>> Please let me know which way you want to proceed. If you want to take the patch,
>> I will resend without the Kconfig change and move that change to another patch.
> 
> It's fine to proceed as is, since Palmer already applied the bindings to
> his tree, just apply the pinctrl driver there as well. I don't see any
> risk of collisions in the tree.

Sounds good. Thanks !

> 
> Yours,
> Linus Walleij
> 


-- 
Damien Le Moal
Western Digital Research

_______________________________________________
linux-riscv mailing list
linux-riscv@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-riscv

^ permalink raw reply	[flat|nested] 24+ messages in thread

* Re: [PATCH v11 02/10] pinctrl: Add RISC-V Canaan Kendryte K210 FPIOA driver
  2021-01-21  8:32           ` Damien Le Moal
@ 2021-01-23  4:15             ` Palmer Dabbelt
  -1 siblings, 0 replies; 24+ messages in thread
From: Palmer Dabbelt @ 2021-01-23  4:15 UTC (permalink / raw)
  To: Damien Le Moal; +Cc: linus.walleij, linux-riscv, linux-gpio, seanga2

On Thu, 21 Jan 2021 00:32:38 PST (-0800), Damien Le Moal wrote:
>> On 2021/01/21 17:25, Linus Walleij wrote:
>> On Thu, Jan 21, 2021 at 1:15 AM Damien Le Moal <Damien.LeMoal@wdc.com> wrote:
>>> On 2021/01/21 3:21, Palmer Dabbelt wrote:
>>>> On Mon, 18 Jan 2021 05:33:05 PST (-0800), linus.walleij@linaro.org wrote:
>>>>> Hi Damien,
>>>>>
>>>>> this looks all right to me.
>>>>> Reviewed-by: Linus Walleij <linus.walleij@linaro.org>
>>>>>
>>>>> Shall I apply just this one patch to the pinctrl tree?
>>>>
>>>> That's fine with me.  The DT bindings are in riscv/for-next, maybe it's best to
>>>> take those as well and I'll drop them?  I don't generally like to drop stuff
>>>> from for-next, but that's probably better than having everything all mixed up.
>>>>
>>>> https://git.kernel.org/pub/scm/linux/kernel/git/riscv/linux.git/commit/?h=for-next&id=ed3137edb31b86702511e7ad12b4abe8686b6805
>>>>
>>>>> I think the line that touches arch/*/Kconfig should be dropped
>>>>> then, that better go to the SoC tree.
>>>>
>>>> I'm OK with you taking them along with my Ack, but if you don't want to that's
>>>> fine.  Just LMK
>>>>
>>>> Acked-by: Palmer Dabbelt <palmerdabbelt@google.com>
>>>
>>> Linus,
>>>
>>> Please let me know which way you want to proceed. If you want to take the patch,
>>> I will resend without the Kconfig change and move that change to another patch.
>> 
>> It's fine to proceed as is, since Palmer already applied the bindings to
>> his tree, just apply the pinctrl driver there as well. I don't see any
>> risk of collisions in the tree.
>
> Sounds good. Thanks !

I don't see an actual Ack here, but I'm OK taking it.  IIRC there were some
issues with the DT stuff as well, I don't remember if they got resolved or if I
should be expecting a v14.

>
>> 
>> Yours,
>> Linus Walleij
>> 


-- 
Damien Le Moal
Western Digital Research


^ permalink raw reply	[flat|nested] 24+ messages in thread

* Re: [PATCH v11 02/10] pinctrl: Add RISC-V Canaan Kendryte K210 FPIOA driver
@ 2021-01-23  4:15             ` Palmer Dabbelt
  0 siblings, 0 replies; 24+ messages in thread
From: Palmer Dabbelt @ 2021-01-23  4:15 UTC (permalink / raw)
  To: Damien Le Moal; +Cc: linux-gpio, linus.walleij, linux-riscv, seanga2

On Thu, 21 Jan 2021 00:32:38 PST (-0800), Damien Le Moal wrote:
>> On 2021/01/21 17:25, Linus Walleij wrote:
>> On Thu, Jan 21, 2021 at 1:15 AM Damien Le Moal <Damien.LeMoal@wdc.com> wrote:
>>> On 2021/01/21 3:21, Palmer Dabbelt wrote:
>>>> On Mon, 18 Jan 2021 05:33:05 PST (-0800), linus.walleij@linaro.org wrote:
>>>>> Hi Damien,
>>>>>
>>>>> this looks all right to me.
>>>>> Reviewed-by: Linus Walleij <linus.walleij@linaro.org>
>>>>>
>>>>> Shall I apply just this one patch to the pinctrl tree?
>>>>
>>>> That's fine with me.  The DT bindings are in riscv/for-next, maybe it's best to
>>>> take those as well and I'll drop them?  I don't generally like to drop stuff
>>>> from for-next, but that's probably better than having everything all mixed up.
>>>>
>>>> https://git.kernel.org/pub/scm/linux/kernel/git/riscv/linux.git/commit/?h=for-next&id=ed3137edb31b86702511e7ad12b4abe8686b6805
>>>>
>>>>> I think the line that touches arch/*/Kconfig should be dropped
>>>>> then, that better go to the SoC tree.
>>>>
>>>> I'm OK with you taking them along with my Ack, but if you don't want to that's
>>>> fine.  Just LMK
>>>>
>>>> Acked-by: Palmer Dabbelt <palmerdabbelt@google.com>
>>>
>>> Linus,
>>>
>>> Please let me know which way you want to proceed. If you want to take the patch,
>>> I will resend without the Kconfig change and move that change to another patch.
>> 
>> It's fine to proceed as is, since Palmer already applied the bindings to
>> his tree, just apply the pinctrl driver there as well. I don't see any
>> risk of collisions in the tree.
>
> Sounds good. Thanks !

I don't see an actual Ack here, but I'm OK taking it.  IIRC there were some
issues with the DT stuff as well, I don't remember if they got resolved or if I
should be expecting a v14.

>
>> 
>> Yours,
>> Linus Walleij
>> 


-- 
Damien Le Moal
Western Digital Research


_______________________________________________
linux-riscv mailing list
linux-riscv@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-riscv

^ permalink raw reply	[flat|nested] 24+ messages in thread

* Re: [PATCH v11 02/10] pinctrl: Add RISC-V Canaan Kendryte K210 FPIOA driver
  2021-01-23  4:15             ` Palmer Dabbelt
@ 2021-01-23  6:19               ` Damien Le Moal
  -1 siblings, 0 replies; 24+ messages in thread
From: Damien Le Moal @ 2021-01-23  6:19 UTC (permalink / raw)
  To: Palmer Dabbelt; +Cc: linus.walleij, linux-riscv, linux-gpio, seanga2

On 2021/01/23 13:15, Palmer Dabbelt wrote:
> On Thu, 21 Jan 2021 00:32:38 PST (-0800), Damien Le Moal wrote:
>>> On 2021/01/21 17:25, Linus Walleij wrote:
>>> On Thu, Jan 21, 2021 at 1:15 AM Damien Le Moal <Damien.LeMoal@wdc.com> wrote:
>>>> On 2021/01/21 3:21, Palmer Dabbelt wrote:
>>>>> On Mon, 18 Jan 2021 05:33:05 PST (-0800), linus.walleij@linaro.org wrote:
>>>>>> Hi Damien,
>>>>>>
>>>>>> this looks all right to me.
>>>>>> Reviewed-by: Linus Walleij <linus.walleij@linaro.org>
>>>>>>
>>>>>> Shall I apply just this one patch to the pinctrl tree?
>>>>>
>>>>> That's fine with me.  The DT bindings are in riscv/for-next, maybe it's best to
>>>>> take those as well and I'll drop them?  I don't generally like to drop stuff
>>>>> from for-next, but that's probably better than having everything all mixed up.
>>>>>
>>>>> https://git.kernel.org/pub/scm/linux/kernel/git/riscv/linux.git/commit/?h=for-next&id=ed3137edb31b86702511e7ad12b4abe8686b6805
>>>>>
>>>>>> I think the line that touches arch/*/Kconfig should be dropped
>>>>>> then, that better go to the SoC tree.
>>>>>
>>>>> I'm OK with you taking them along with my Ack, but if you don't want to that's
>>>>> fine.  Just LMK
>>>>>
>>>>> Acked-by: Palmer Dabbelt <palmerdabbelt@google.com>
>>>>
>>>> Linus,
>>>>
>>>> Please let me know which way you want to proceed. If you want to take the patch,
>>>> I will resend without the Kconfig change and move that change to another patch.
>>>
>>> It's fine to proceed as is, since Palmer already applied the bindings to
>>> his tree, just apply the pinctrl driver there as well. I don't see any
>>> risk of collisions in the tree.
>>
>> Sounds good. Thanks !
> 
> I don't see an actual Ack here, but I'm OK taking it.  IIRC there were some
> issues with the DT stuff as well, I don't remember if they got resolved or if I
> should be expecting a v14.

Palmer,

Linus sent a reviewed-by tag (see above).

For the dt-bindings problems, the v13 that I sent already addresses all make
dtbs_check warning and also addresses Rob's comments. The v13 dt-bindings
patches need review, as well as the clk driver patch. Will ping Stephen about
that one.
I will send a v14 only if there are more comments that need to be addressed.



-- 
Damien Le Moal
Western Digital Research

^ permalink raw reply	[flat|nested] 24+ messages in thread

* Re: [PATCH v11 02/10] pinctrl: Add RISC-V Canaan Kendryte K210 FPIOA driver
@ 2021-01-23  6:19               ` Damien Le Moal
  0 siblings, 0 replies; 24+ messages in thread
From: Damien Le Moal @ 2021-01-23  6:19 UTC (permalink / raw)
  To: Palmer Dabbelt; +Cc: linux-gpio, linus.walleij, linux-riscv, seanga2

On 2021/01/23 13:15, Palmer Dabbelt wrote:
> On Thu, 21 Jan 2021 00:32:38 PST (-0800), Damien Le Moal wrote:
>>> On 2021/01/21 17:25, Linus Walleij wrote:
>>> On Thu, Jan 21, 2021 at 1:15 AM Damien Le Moal <Damien.LeMoal@wdc.com> wrote:
>>>> On 2021/01/21 3:21, Palmer Dabbelt wrote:
>>>>> On Mon, 18 Jan 2021 05:33:05 PST (-0800), linus.walleij@linaro.org wrote:
>>>>>> Hi Damien,
>>>>>>
>>>>>> this looks all right to me.
>>>>>> Reviewed-by: Linus Walleij <linus.walleij@linaro.org>
>>>>>>
>>>>>> Shall I apply just this one patch to the pinctrl tree?
>>>>>
>>>>> That's fine with me.  The DT bindings are in riscv/for-next, maybe it's best to
>>>>> take those as well and I'll drop them?  I don't generally like to drop stuff
>>>>> from for-next, but that's probably better than having everything all mixed up.
>>>>>
>>>>> https://git.kernel.org/pub/scm/linux/kernel/git/riscv/linux.git/commit/?h=for-next&id=ed3137edb31b86702511e7ad12b4abe8686b6805
>>>>>
>>>>>> I think the line that touches arch/*/Kconfig should be dropped
>>>>>> then, that better go to the SoC tree.
>>>>>
>>>>> I'm OK with you taking them along with my Ack, but if you don't want to that's
>>>>> fine.  Just LMK
>>>>>
>>>>> Acked-by: Palmer Dabbelt <palmerdabbelt@google.com>
>>>>
>>>> Linus,
>>>>
>>>> Please let me know which way you want to proceed. If you want to take the patch,
>>>> I will resend without the Kconfig change and move that change to another patch.
>>>
>>> It's fine to proceed as is, since Palmer already applied the bindings to
>>> his tree, just apply the pinctrl driver there as well. I don't see any
>>> risk of collisions in the tree.
>>
>> Sounds good. Thanks !
> 
> I don't see an actual Ack here, but I'm OK taking it.  IIRC there were some
> issues with the DT stuff as well, I don't remember if they got resolved or if I
> should be expecting a v14.

Palmer,

Linus sent a reviewed-by tag (see above).

For the dt-bindings problems, the v13 that I sent already addresses all make
dtbs_check warning and also addresses Rob's comments. The v13 dt-bindings
patches need review, as well as the clk driver patch. Will ping Stephen about
that one.
I will send a v14 only if there are more comments that need to be addressed.



-- 
Damien Le Moal
Western Digital Research

_______________________________________________
linux-riscv mailing list
linux-riscv@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-riscv

^ permalink raw reply	[flat|nested] 24+ messages in thread

* Re: [PATCH v11 02/10] pinctrl: Add RISC-V Canaan Kendryte K210 FPIOA driver
  2021-01-23  6:19               ` Damien Le Moal
@ 2021-01-27  5:46                 ` Palmer Dabbelt
  -1 siblings, 0 replies; 24+ messages in thread
From: Palmer Dabbelt @ 2021-01-27  5:46 UTC (permalink / raw)
  To: Damien Le Moal; +Cc: linus.walleij, linux-riscv, linux-gpio, seanga2

On Fri, 22 Jan 2021 22:19:51 PST (-0800), Damien Le Moal wrote:
> On 2021/01/23 13:15, Palmer Dabbelt wrote:
>> On Thu, 21 Jan 2021 00:32:38 PST (-0800), Damien Le Moal wrote:
>>>> On 2021/01/21 17:25, Linus Walleij wrote:
>>>> On Thu, Jan 21, 2021 at 1:15 AM Damien Le Moal <Damien.LeMoal@wdc.com> wrote:
>>>>> On 2021/01/21 3:21, Palmer Dabbelt wrote:
>>>>>> On Mon, 18 Jan 2021 05:33:05 PST (-0800), linus.walleij@linaro.org wrote:
>>>>>>> Hi Damien,
>>>>>>>
>>>>>>> this looks all right to me.
>>>>>>> Reviewed-by: Linus Walleij <linus.walleij@linaro.org>
>>>>>>>
>>>>>>> Shall I apply just this one patch to the pinctrl tree?
>>>>>>
>>>>>> That's fine with me.  The DT bindings are in riscv/for-next, maybe it's best to
>>>>>> take those as well and I'll drop them?  I don't generally like to drop stuff
>>>>>> from for-next, but that's probably better than having everything all mixed up.
>>>>>>
>>>>>> https://git.kernel.org/pub/scm/linux/kernel/git/riscv/linux.git/commit/?h=for-next&id=ed3137edb31b86702511e7ad12b4abe8686b6805
>>>>>>
>>>>>>> I think the line that touches arch/*/Kconfig should be dropped
>>>>>>> then, that better go to the SoC tree.
>>>>>>
>>>>>> I'm OK with you taking them along with my Ack, but if you don't want to that's
>>>>>> fine.  Just LMK
>>>>>>
>>>>>> Acked-by: Palmer Dabbelt <palmerdabbelt@google.com>
>>>>>
>>>>> Linus,
>>>>>
>>>>> Please let me know which way you want to proceed. If you want to take the patch,
>>>>> I will resend without the Kconfig change and move that change to another patch.
>>>>
>>>> It's fine to proceed as is, since Palmer already applied the bindings to
>>>> his tree, just apply the pinctrl driver there as well. I don't see any
>>>> risk of collisions in the tree.
>>>
>>> Sounds good. Thanks !
>> 
>> I don't see an actual Ack here, but I'm OK taking it.  IIRC there were some
>> issues with the DT stuff as well, I don't remember if they got resolved or if I
>> should be expecting a v14.
>
> Palmer,
> 
> Linus sent a reviewed-by tag (see above).
> 
> For the dt-bindings problems, the v13 that I sent already addresses all make
> dtbs_check warning and also addresses Rob's comments. The v13 dt-bindings
> patches need review, as well as the clk driver patch. Will ping Stephen about
> that one.
> I will send a v14 only if there are more comments that need to be addressed.

Ah, thanks.  This is on for-next.  I'll look at the rest, but probably not
tonight as it's a bit late here.

^ permalink raw reply	[flat|nested] 24+ messages in thread

* Re: [PATCH v11 02/10] pinctrl: Add RISC-V Canaan Kendryte K210 FPIOA driver
@ 2021-01-27  5:46                 ` Palmer Dabbelt
  0 siblings, 0 replies; 24+ messages in thread
From: Palmer Dabbelt @ 2021-01-27  5:46 UTC (permalink / raw)
  To: Damien Le Moal; +Cc: linux-gpio, linus.walleij, linux-riscv, seanga2

On Fri, 22 Jan 2021 22:19:51 PST (-0800), Damien Le Moal wrote:
> On 2021/01/23 13:15, Palmer Dabbelt wrote:
>> On Thu, 21 Jan 2021 00:32:38 PST (-0800), Damien Le Moal wrote:
>>>> On 2021/01/21 17:25, Linus Walleij wrote:
>>>> On Thu, Jan 21, 2021 at 1:15 AM Damien Le Moal <Damien.LeMoal@wdc.com> wrote:
>>>>> On 2021/01/21 3:21, Palmer Dabbelt wrote:
>>>>>> On Mon, 18 Jan 2021 05:33:05 PST (-0800), linus.walleij@linaro.org wrote:
>>>>>>> Hi Damien,
>>>>>>>
>>>>>>> this looks all right to me.
>>>>>>> Reviewed-by: Linus Walleij <linus.walleij@linaro.org>
>>>>>>>
>>>>>>> Shall I apply just this one patch to the pinctrl tree?
>>>>>>
>>>>>> That's fine with me.  The DT bindings are in riscv/for-next, maybe it's best to
>>>>>> take those as well and I'll drop them?  I don't generally like to drop stuff
>>>>>> from for-next, but that's probably better than having everything all mixed up.
>>>>>>
>>>>>> https://git.kernel.org/pub/scm/linux/kernel/git/riscv/linux.git/commit/?h=for-next&id=ed3137edb31b86702511e7ad12b4abe8686b6805
>>>>>>
>>>>>>> I think the line that touches arch/*/Kconfig should be dropped
>>>>>>> then, that better go to the SoC tree.
>>>>>>
>>>>>> I'm OK with you taking them along with my Ack, but if you don't want to that's
>>>>>> fine.  Just LMK
>>>>>>
>>>>>> Acked-by: Palmer Dabbelt <palmerdabbelt@google.com>
>>>>>
>>>>> Linus,
>>>>>
>>>>> Please let me know which way you want to proceed. If you want to take the patch,
>>>>> I will resend without the Kconfig change and move that change to another patch.
>>>>
>>>> It's fine to proceed as is, since Palmer already applied the bindings to
>>>> his tree, just apply the pinctrl driver there as well. I don't see any
>>>> risk of collisions in the tree.
>>>
>>> Sounds good. Thanks !
>> 
>> I don't see an actual Ack here, but I'm OK taking it.  IIRC there were some
>> issues with the DT stuff as well, I don't remember if they got resolved or if I
>> should be expecting a v14.
>
> Palmer,
> 
> Linus sent a reviewed-by tag (see above).
> 
> For the dt-bindings problems, the v13 that I sent already addresses all make
> dtbs_check warning and also addresses Rob's comments. The v13 dt-bindings
> patches need review, as well as the clk driver patch. Will ping Stephen about
> that one.
> I will send a v14 only if there are more comments that need to be addressed.

Ah, thanks.  This is on for-next.  I'll look at the rest, but probably not
tonight as it's a bit late here.

_______________________________________________
linux-riscv mailing list
linux-riscv@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-riscv

^ permalink raw reply	[flat|nested] 24+ messages in thread

* Re: [PATCH v11 02/10] pinctrl: Add RISC-V Canaan Kendryte K210 FPIOA driver
  2021-01-15  0:17     ` Damien Le Moal
@ 2021-01-15  0:39       ` Sean Anderson
  0 siblings, 0 replies; 24+ messages in thread
From: Sean Anderson @ 2021-01-15  0:39 UTC (permalink / raw)
  To: Damien Le Moal, Palmer Dabbelt, linus.walleij; +Cc: linux-riscv

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);
>>
> 
> 


_______________________________________________
linux-riscv mailing list
linux-riscv@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-riscv

^ permalink raw reply	[flat|nested] 24+ messages in thread

* Re: [PATCH v11 02/10] pinctrl: Add RISC-V Canaan Kendryte K210 FPIOA driver
  2021-01-14 23:32   ` Palmer Dabbelt
@ 2021-01-15  0:17     ` Damien Le Moal
  2021-01-15  0:39       ` Sean Anderson
  0 siblings, 1 reply; 24+ messages in thread
From: Damien Le Moal @ 2021-01-15  0:17 UTC (permalink / raw)
  To: Palmer Dabbelt, linus.walleij; +Cc: linux-riscv, seanga2

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);
> 


-- 
Damien Le Moal
Western Digital Research

_______________________________________________
linux-riscv mailing list
linux-riscv@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-riscv

^ permalink raw reply	[flat|nested] 24+ messages in thread

* Re: [PATCH v11 02/10] pinctrl: Add RISC-V Canaan Kendryte K210 FPIOA driver
  2021-01-12  0:58 ` [PATCH v11 02/10] pinctrl: Add RISC-V Canaan Kendryte K210 FPIOA driver Damien Le Moal
@ 2021-01-14 23:32   ` Palmer Dabbelt
  2021-01-15  0:17     ` Damien Le Moal
  0 siblings, 1 reply; 24+ messages in thread
From: Palmer Dabbelt @ 2021-01-14 23:32 UTC (permalink / raw)
  To: linus.walleij; +Cc: Damien Le Moal, linux-riscv, seanga2

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);

_______________________________________________
linux-riscv mailing list
linux-riscv@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-riscv

^ permalink raw reply	[flat|nested] 24+ messages in thread

* [PATCH v11 02/10] pinctrl: Add RISC-V Canaan Kendryte K210 FPIOA driver
  2021-01-12  0:58 [PATCH v11 00/10] RISC-V Kendryte K210 support improvements Damien Le Moal
@ 2021-01-12  0:58 ` Damien Le Moal
  2021-01-14 23:32   ` Palmer Dabbelt
  0 siblings, 1 reply; 24+ messages in thread
From: Damien Le Moal @ 2021-01-12  0:58 UTC (permalink / raw)
  To: Palmer Dabbelt, linux-riscv; +Cc: Sean Anderson

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
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);
-- 
2.29.2


_______________________________________________
linux-riscv mailing list
linux-riscv@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-riscv

^ permalink raw reply related	[flat|nested] 24+ messages in thread

end of thread, other threads:[~2021-01-27  6:05 UTC | newest]

Thread overview: 24+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2021-01-12  1:03 [PATCH v11 02/10] pinctrl: Add RISC-V Canaan Kendryte K210 FPIOA driver Damien Le Moal
2021-01-12  1:03 ` Damien Le Moal
2021-01-18 13:33 ` Linus Walleij
2021-01-18 13:33   ` Linus Walleij
2021-01-19  0:06   ` Damien Le Moal
2021-01-19  0:06     ` Damien Le Moal
2021-01-20 18:21   ` Palmer Dabbelt
2021-01-20 18:21     ` Palmer Dabbelt
2021-01-21  0:15     ` Damien Le Moal
2021-01-21  0:15       ` Damien Le Moal
2021-01-21  8:25       ` Linus Walleij
2021-01-21  8:25         ` Linus Walleij
2021-01-21  8:32         ` Damien Le Moal
2021-01-21  8:32           ` Damien Le Moal
2021-01-23  4:15           ` Palmer Dabbelt
2021-01-23  4:15             ` Palmer Dabbelt
2021-01-23  6:19             ` Damien Le Moal
2021-01-23  6:19               ` Damien Le Moal
2021-01-27  5:46               ` Palmer Dabbelt
2021-01-27  5:46                 ` Palmer Dabbelt
  -- strict thread matches above, loose matches on Subject: below --
2021-01-12  0:58 [PATCH v11 00/10] RISC-V Kendryte K210 support improvements Damien Le Moal
2021-01-12  0:58 ` [PATCH v11 02/10] pinctrl: Add RISC-V Canaan Kendryte K210 FPIOA driver Damien Le Moal
2021-01-14 23:32   ` Palmer Dabbelt
2021-01-15  0:17     ` Damien Le Moal
2021-01-15  0:39       ` Sean Anderson

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.