[PATCH v11 02/10] pinctrl: Add RISC-V Canaan Kendryte K210 FPIOA driver

Sean Anderson seanga2 at gmail.com
Thu Jan 14 19:39:14 EST 2021


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 at linaro.org>
>>> Cc: linux-gpio at 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 at gmail.com>
>>> Signed-off-by: Damien Le Moal <damien.lemoal at 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 at wdc.com>
>>> +L:	linux-riscv at lists.infradead.org
>>> +L:	linux-gpio at 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 at wdc.com>
>>>   L:	linux-kernel at 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 at 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);
>>
> 
> 




More information about the linux-riscv mailing list