[PATCH v11 02/10] pinctrl: Add RISC-V Canaan Kendryte K210 FPIOA driver
Damien Le Moal
Damien.LeMoal at wdc.com
Thu Jan 14 19:17:32 EST 2021
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.
> 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);
>
--
Damien Le Moal
Western Digital Research
More information about the linux-riscv
mailing list