diff mbox series

[v5,13/33] pinctrl: Add support for Kendryte K210 FPIOA

Message ID 20200228210552.615672-14-seanga2@gmail.com
State Superseded
Headers show
Series riscv: Add Sipeed Maix support | expand

Commit Message

Sean Anderson Feb. 28, 2020, 9:05 p.m. UTC
The Fully-Programmable Input/Output Array (FPIOA) device controls pin
multiplexing on the K210. The FPIOA can remap any supported function to any
multifunctional IO pin. It can also perform basic GPIO functions, such as
reading the current value of a pin.

Signed-off-by: Sean Anderson <seanga2 at gmail.com>
---

Changes in v5:
- New

 MAINTAINERS                                   |   2 +
 .../pinctrl/kendryte,k210-fpioa.txt           | 116 +++
 drivers/pinctrl/Kconfig                       |   1 +
 drivers/pinctrl/Makefile                      |   1 +
 drivers/pinctrl/kendryte/Kconfig              |   7 +
 drivers/pinctrl/kendryte/Makefile             |   1 +
 drivers/pinctrl/kendryte/pinctrl.c            | 663 ++++++++++++++++++
 drivers/pinctrl/kendryte/pinctrl.h            | 325 +++++++++
 include/dt-bindings/pinctrl/k210-pinctrl.h    |  12 +
 9 files changed, 1128 insertions(+)
 create mode 100644 doc/device-tree-bindings/pinctrl/kendryte,k210-fpioa.txt
 create mode 100644 drivers/pinctrl/kendryte/Kconfig
 create mode 100644 drivers/pinctrl/kendryte/Makefile
 create mode 100644 drivers/pinctrl/kendryte/pinctrl.c
 create mode 100644 drivers/pinctrl/kendryte/pinctrl.h
 create mode 100644 include/dt-bindings/pinctrl/k210-pinctrl.h

Comments

Rick Chen March 4, 2020, 6:47 a.m. UTC | #1
Hi Sean

> The Fully-Programmable Input/Output Array (FPIOA) device controls pin
> multiplexing on the K210. The FPIOA can remap any supported function to any
> multifunctional IO pin. It can also perform basic GPIO functions, such as
> reading the current value of a pin.
>
> Signed-off-by: Sean Anderson <seanga2 at gmail.com>
> ---
>
> Changes in v5:
> - New
>
>  MAINTAINERS                                   |   2 +
>  .../pinctrl/kendryte,k210-fpioa.txt           | 116 +++
>  drivers/pinctrl/Kconfig                       |   1 +
>  drivers/pinctrl/Makefile                      |   1 +
>  drivers/pinctrl/kendryte/Kconfig              |   7 +
>  drivers/pinctrl/kendryte/Makefile             |   1 +
>  drivers/pinctrl/kendryte/pinctrl.c            | 663 ++++++++++++++++++
>  drivers/pinctrl/kendryte/pinctrl.h            | 325 +++++++++
>  include/dt-bindings/pinctrl/k210-pinctrl.h    |  12 +
>  9 files changed, 1128 insertions(+)
>  create mode 100644 doc/device-tree-bindings/pinctrl/kendryte,k210-fpioa.txt
>  create mode 100644 drivers/pinctrl/kendryte/Kconfig
>  create mode 100644 drivers/pinctrl/kendryte/Makefile
>  create mode 100644 drivers/pinctrl/kendryte/pinctrl.c
>  create mode 100644 drivers/pinctrl/kendryte/pinctrl.h
>  create mode 100644 include/dt-bindings/pinctrl/k210-pinctrl.h
>

Please checkpatch and fix

total: 3 errors, 13 warnings, 5 checks, 1147 lines checked

Thanks
Rick


> diff --git a/MAINTAINERS b/MAINTAINERS
> index 8e9e0569ba..8725bcf9af 100644
> --- a/MAINTAINERS
> +++ b/MAINTAINERS
> @@ -809,7 +809,9 @@ RISC-V KENDRYTE
>  M:     Sean Anderson <seanga2 at gmail.com>
>  S:     Maintained
>  F:     doc/device-tree-bindings/mfd/kendryte,k210-sysctl.txt
> +F:     doc/device-tree-bindings/pinctrl/kendryte,k210-fpioa.txt
>  F:     drivers/clk/kendryte/
> +F:     drivers/pinctrl/kendryte/
>  F:     include/kendryte/
>
>  RNG
> diff --git a/doc/device-tree-bindings/pinctrl/kendryte,k210-fpioa.txt b/doc/device-tree-bindings/pinctrl/kendryte,k210-fpioa.txt
> new file mode 100644
> index 0000000000..299ce65304
> --- /dev/null
> +++ b/doc/device-tree-bindings/pinctrl/kendryte,k210-fpioa.txt
> @@ -0,0 +1,116 @@
> +Kendryte K210 FPIOA
> +
> +This binding describes the Fully-Programmable Input/Output Array found on
> +Kendryte K210 SoCs. Any of the 256 functions can be mapped to any of the 48
> +pins.
> +
> +Required properties:
> +- compatible: should be "kendryte,k210-fpioa"
> +- reg: address and length of the FPIOA registers
> +- kendryte,sysctl: phandle to the "sysctl" register map node
> +- kendryte,power-offset: offset in the register map of the power bank control
> +  register (in bytes)
> +
> +Configuration nodes
> +
> +Pin configuration nodes are documented in pinctrl-bindings.txt
> +
> +Valid values for pins, groups, and function names:
> +
> +pins:
> +       "IO_X", where X is a number from 0 to 47.
> +
> +groups:
> +       A0, A1, A2, B0, B1, B2, C0, C1
> +
> +functions:
> +       JTAG_TCLK, JTAG_TDI, JTAG_TMS, JTAG_TDO, SPI0_D0, SPI0_D1, SPI0_D2,
> +       SPI0_D3, SPI0_D4, SPI0_D5, SPI0_D6, SPI0_D7, SPI0_SS0, SPI0_SS1,
> +       SPI0_SS2, SPI0_SS3, SPI0_ARB, SPI0_SCLK, UARTHS_RX, UARTHS_TX, RESV6,
> +       RESV7, CLK_SPI1, CLK_I2C1, GPIOHS0, GPIOHS1, GPIOHS2, GPIOHS3, GPIOHS4,
> +       GPIOHS5, GPIOHS6, GPIOHS7, GPIOHS8, GPIOHS9, GPIOHS10, GPIOHS11,
> +       GPIOHS12, GPIOHS13, GPIOHS14, GPIOHS15, GPIOHS16, GPIOHS17, GPIOHS18,
> +       GPIOHS19, GPIOHS20, GPIOHS21, GPIOHS22, GPIOHS23, GPIOHS24, GPIOHS25,
> +       GPIOHS26, GPIOHS27, GPIOHS28, GPIOHS29, GPIOHS30, GPIOHS31, GPIO0,
> +       GPIO1, GPIO2, GPIO3, GPIO4, GPIO5, GPIO6, GPIO7, UART1_RX, UART1_TX,
> +       UART2_RX, UART2_TX, UART3_RX, UART3_TX, SPI1_D0, SPI1_D1, SPI1_D2,
> +       SPI1_D3, SPI1_D4, SPI1_D5, SPI1_D6, SPI1_D7, SPI1_SS0, SPI1_SS1,
> +       SPI1_SS2, SPI1_SS3, SPI1_ARB, SPI1_SCLK, SPI2_D0, SPI2_SS, SPI2_SCLK,
> +       I2S0_MCLK, I2S0_SCLK, I2S0_WS, I2S0_IN_D0, I2S0_IN_D1, I2S0_IN_D2,
> +       I2S0_IN_D3, I2S0_OUT_D0, I2S0_OUT_D1, I2S0_OUT_D2, I2S0_OUT_D3,
> +       I2S1_MCLK, I2S1_SCLK, I2S1_WS, I2S1_IN_D0, I2S1_IN_D1, I2S1_IN_D2,
> +       I2S1_IN_D3, I2S1_OUT_D0, I2S1_OUT_D1, I2S1_OUT_D2, I2S1_OUT_D3,
> +       I2S2_MCLK, I2S2_SCLK, I2S2_WS, I2S2_IN_D0, I2S2_IN_D1, I2S2_IN_D2,
> +       I2S2_IN_D3, I2S2_OUT_D0, I2S2_OUT_D1, I2S2_OUT_D2, I2S2_OUT_D3, RESV0,
> +       RESV1, RESV2, RESV3, RESV4, RESV5, I2C0_SCLK, I2C0_SDA, I2C1_SCLK,
> +       I2C1_SDA, I2C2_SCLK, I2C2_SDA, DVP_XCLK, DVP_RST, DVP_PWDN, DVP_VSYNC,
> +       DVP_HREF, DVP_PCLK, DVP_D0, DVP_D1, DVP_D2, DVP_D3, DVP_D4, DVP_D5,
> +       DVP_D6, DVP_D7, SCCB_SCLK, SCCB_SDA, UART1_CTS, UART1_DSR, UART1_DCD,
> +       UART1_RI, UART1_SIR_IN, UART1_DTR, UART1_RTS, UART1_OUT2, UART1_OUT1,
> +       UART1_SIR_OUT, UART1_BAUD, UART1_RE, UART1_DE, UART1_RS485_EN,
> +       UART2_CTS, UART2_DSR, UART2_DCD, UART2_RI, UART2_SIR_IN, UART2_DTR,
> +       UART2_RTS, UART2_OUT2, UART2_OUT1, UART2_SIR_OUT, UART2_BAUD, UART2_RE,
> +       UART2_DE, UART2_RS485_EN, UART3_CTS, UART3_DSR, UART3_DCD, UART3_RI,
> +       UART3_SIR_IN, UART3_DTR, UART3_RTS, UART3_OUT2, UART3_OUT1,
> +       UART3_SIR_OUT, UART3_BAUD, UART3_RE, UART3_DE, UART3_RS485_EN,
> +       TIMER0_TOGGLE1, TIMER0_TOGGLE2, TIMER0_TOGGLE3, TIMER0_TOGGLE4,
> +       TIMER1_TOGGLE1, TIMER1_TOGGLE2, TIMER1_TOGGLE3, TIMER1_TOGGLE4,
> +       TIMER2_TOGGLE1, TIMER2_TOGGLE2, TIMER2_TOGGLE3, TIMER2_TOGGLE4,
> +       CLK_SPI2, CLK_I2C2, INTERNAL0, INTERNAL1, INTERNAL2, INTERNAL3,
> +       INTERNAL4, INTERNAL5, INTERNAL6, INTERNAL7, INTERNAL8, INTERNAL9,
> +       INTERNAL10, INTERNAL11, INTERNAL12, INTERNAL13, INTERNAL14, INTERNAL15,
> +       INTERNAL16, INTERNAL17, CONSTANT, INTERNAL18, DEBUG0, DEBUG1, DEBUG2,
> +       DEBUG3, DEBUG4, DEBUG5, DEBUG6, DEBUG7, DEBUG8, DEBUG9, DEBUG10,
> +       DEBUG11, DEBUG12, DEBUG13, DEBUG14, DEBUG15, DEBUG16, DEBUG17, DEBUG18,
> +       DEBUG19, DEBUG20, DEBUG21, DEBUG22, DEBUG23, DEBUG24, DEBUG25, DEBUG26,
> +       DEBUG27, DEBUG28, DEBUG29, DEBUG30, DEBUG31
> +
> +Valid properties include:
> +       bias-disable, bias-pull-down, bias-pull-up, drive-strength,
> +       drive-strength-ua, input-enable, input-disable, input-schmitt-enable,
> +       input-schmitt-disable, power-source, output-low, output-high,
> +       output-enable, output-disable, slew-rate
> +
> +Notes on specific properties include:
> +- bias-pull-up, -down, and -pin-default: The pull strength cannot be configured.
> +- drive-strength: There are 8 drive strength settings between 11 and 50 mA
> +- power-source: Controls the output voltage of a bank of pins. Either
> +  K210_PC_POWER_1V8 or K210_PC_POWER_3V3 may be specified. This property cannot
> +  be specified for individual pins.
> +- slew-rate: Specifying this property reduces the slew rate
> +
> +Example:
> +fpioa: pinmux at 502B0000 {
> +       compatible = "kendryte,k210-fpioa";
> +       reg = <0x502B0000 0x100>;
> +       kendryte,sysctl = <&sysctl>;
> +       kendryte,power-offset = <K210_SYSCTL_POWER_SEL>;
> +
> +       fpioa_jtag: jtag {
> +               voltage {
> +                       group = "A0";
> +                       power-source = <K210_PC_POWER_3V3>;
> +               };
> +               tck {
> +                       function = "JTAG_TCLK";
> +                       pins = "IO_0";
> +               };
> +               tdi {
> +                       function = "JTAG_TDI";
> +                       pins = "IO_1";
> +               };
> +               tms {
> +                       function = "JTAG_TMS";
> +                       pins = "IO_2";
> +               };
> +               tdo {
> +                       function = "JTAG_TDO";
> +                       pins = "IO_3";
> +               };
> +       };
> +
> +       fpioa_isp: isp {
> +               function = "GPIOHS0";
> +               pins = "IO_16";
> +       };
> +};
> diff --git a/drivers/pinctrl/Kconfig b/drivers/pinctrl/Kconfig
> index 83e39b9de3..9ec56c7735 100644
> --- a/drivers/pinctrl/Kconfig
> +++ b/drivers/pinctrl/Kconfig
> @@ -289,6 +289,7 @@ endif
>  source "drivers/pinctrl/broadcom/Kconfig"
>  source "drivers/pinctrl/exynos/Kconfig"
>  source "drivers/pinctrl/intel/Kconfig"
> +source "drivers/pinctrl/kendryte/Kconfig"
>  source "drivers/pinctrl/mediatek/Kconfig"
>  source "drivers/pinctrl/meson/Kconfig"
>  source "drivers/pinctrl/mscc/Kconfig"
> diff --git a/drivers/pinctrl/Makefile b/drivers/pinctrl/Makefile
> index 4f662c4f6d..1fe66fed3c 100644
> --- a/drivers/pinctrl/Makefile
> +++ b/drivers/pinctrl/Makefile
> @@ -17,6 +17,7 @@ obj-$(CONFIG_PINCTRL_SANDBOX) += pinctrl-sandbox.o
>  obj-$(CONFIG_PINCTRL_UNIPHIER) += uniphier/
>  obj-$(CONFIG_PINCTRL_PIC32)    += pinctrl_pic32.o
>  obj-$(CONFIG_PINCTRL_EXYNOS)   += exynos/
> +obj-$(CONFIG_PINCTRL_K210)     += kendryte/
>  obj-$(CONFIG_PINCTRL_MESON)    += meson/
>  obj-$(CONFIG_PINCTRL_MTK)      += mediatek/
>  obj-$(CONFIG_PINCTRL_MSCC)     += mscc/
> diff --git a/drivers/pinctrl/kendryte/Kconfig b/drivers/pinctrl/kendryte/Kconfig
> new file mode 100644
> index 0000000000..6fc10e9516
> --- /dev/null
> +++ b/drivers/pinctrl/kendryte/Kconfig
> @@ -0,0 +1,7 @@
> +config PINCTRL_K210
> +       bool "Kendryte K210 Fully-Programmable Input/Output Array driver"
> +       depends on DM && PINCTRL_GENERIC
> +       help
> +         Support pin multiplexing on the K210. The "FPIOA" can remap any
> +         supported function to any multifunctional IO pin. It can also perform
> +         basic GPIO functions, such as reading the current value of a pin.
> diff --git a/drivers/pinctrl/kendryte/Makefile b/drivers/pinctrl/kendryte/Makefile
> new file mode 100644
> index 0000000000..1c10d7a929
> --- /dev/null
> +++ b/drivers/pinctrl/kendryte/Makefile
> @@ -0,0 +1 @@
> +obj-y += pinctrl.o
> diff --git a/drivers/pinctrl/kendryte/pinctrl.c b/drivers/pinctrl/kendryte/pinctrl.c
> new file mode 100644
> index 0000000000..3f7de0e706
> --- /dev/null
> +++ b/drivers/pinctrl/kendryte/pinctrl.c
> @@ -0,0 +1,663 @@
> +// SPDX-License-Identifier: GPL-2.0+
> +/*
> + * Copyright (C) 2020 Sean Anderson <seanga2 at gmail.com>
> + */
> +
> +#include <common.h>
> +#include <clk.h>
> +#include <dm.h>
> +#include <dm/pinctrl.h>
> +#include <dt-bindings/pinctrl/k210-pinctrl.h>
> +#include <mapmem.h>
> +#include <regmap.h>
> +#include <syscon.h>
> +#include <asm/io.h>
> +#include <linux/err.h>
> +#include "pinctrl.h"
> +
> +struct k210_pc_priv {
> +       struct clk clk;
> +       struct k210_fpioa __iomem *fpioa; /* FPIOA register */
> +       struct regmap *sysctl; /* Sysctl regmap */
> +       u32 power_offset; /* Power bank register offset */
> +};
> +
> +#define PIN(i) [i] = "IO_" #i
> +static const char k210_pc_pin_names[][6] = {
> +       PIN(0),
> +       PIN(1),
> +       PIN(2),
> +       PIN(3),
> +       PIN(4),
> +       PIN(5),
> +       PIN(6),
> +       PIN(7),
> +       PIN(8),
> +       PIN(9),
> +       PIN(10),
> +       PIN(11),
> +       PIN(12),
> +       PIN(13),
> +       PIN(14),
> +       PIN(15),
> +       PIN(16),
> +       PIN(17),
> +       PIN(18),
> +       PIN(19),
> +       PIN(20),
> +       PIN(21),
> +       PIN(22),
> +       PIN(23),
> +       PIN(24),
> +       PIN(25),
> +       PIN(26),
> +       PIN(27),
> +       PIN(28),
> +       PIN(29),
> +       PIN(30),
> +       PIN(31),
> +       PIN(32),
> +       PIN(33),
> +       PIN(34),
> +       PIN(35),
> +       PIN(36),
> +       PIN(37),
> +       PIN(38),
> +       PIN(39),
> +       PIN(40),
> +       PIN(41),
> +       PIN(42),
> +       PIN(43),
> +       PIN(44),
> +       PIN(45),
> +       PIN(46),
> +       PIN(47),
> +};
> +#undef PIN
> +
> +static int k210_pc_get_pins_count(struct udevice *dev)
> +{
> +       return ARRAY_SIZE(k210_pc_pin_names);
> +};
> +
> +static const char *k210_pc_get_pin_name(struct udevice *dev, unsigned selector)
> +{
> +       return k210_pc_pin_names[selector];
> +}
> +
> +/* These are just power domains */
> +static const char k210_pc_group_names[][3] = {
> +       [0] = "A0",
> +       [1] = "A1",
> +       [2] = "A2",
> +       [3] = "B0",
> +       [4] = "B1",
> +       [5] = "B2",
> +       [6] = "C0",
> +       [7] = "C1",
> +};
> +
> +static int k210_pc_get_groups_count(struct udevice *dev)
> +{
> +       return ARRAY_SIZE(k210_pc_group_names);
> +}
> +
> +static const char *k210_pc_get_group_name(struct udevice *dev,
> +                                         unsigned selector)
> +{
> +       return k210_pc_group_names[selector];
> +}
> +
> +enum k210_pc_mode_id {
> +       K210_PC_DEFAULT_DISABLED,
> +       K210_PC_DEFAULT_IN,
> +       K210_PC_DEFAULT_IN_TIE,
> +       K210_PC_DEFAULT_OUT,
> +       K210_PC_DEFAULT_I2C,
> +       K210_PC_DEFAULT_SPI,
> +       K210_PC_DEFAULT_GPIO,
> +       K210_PC_DEFAULT_INT13,
> +};
> +
> +#define DEFAULT(mode) [K210_PC_DEFAULT_##mode] = K210_PC_MODE_##mode
> +static const u32 k210_pc_mode_id_to_mode[] = {
> +       [K210_PC_DEFAULT_DISABLED] = 0,
> +       DEFAULT(IN),
> +       [K210_PC_DEFAULT_IN_TIE] = K210_PC_MODE_IN,
> +       DEFAULT(OUT),
> +       DEFAULT(I2C),
> +       DEFAULT(SPI),
> +       DEFAULT(GPIO),
> +       [K210_PC_DEFAULT_INT13] = K210_PC_MODE_IN | K210_PC_PU,
> +};
> +#undef DEFAULT
> +
> +/* This saves around 2K vs having a pointer+mode */
> +struct k210_pcf_info {
> +       char name[15];
> +       u8 mode_id;
> +};
> +
> +#define FUNC(id, mode) [K210_PCF_##id] = { \
> +       .name = #id, \
> +       .mode_id = K210_PC_DEFAULT_##mode \
> +}
> +static const struct k210_pcf_info k210_pcf_infos[] = {
> +       FUNC(JTAG_TCLK,      IN),
> +       FUNC(JTAG_TDI,       IN),
> +       FUNC(JTAG_TMS,       IN),
> +       FUNC(JTAG_TDO,       OUT),
> +       FUNC(SPI0_D0,        SPI),
> +       FUNC(SPI0_D1,        SPI),
> +       FUNC(SPI0_D2,        SPI),
> +       FUNC(SPI0_D3,        SPI),
> +       FUNC(SPI0_D4,        SPI),
> +       FUNC(SPI0_D5,        SPI),
> +       FUNC(SPI0_D6,        SPI),
> +       FUNC(SPI0_D7,        SPI),
> +       FUNC(SPI0_SS0,       OUT),
> +       FUNC(SPI0_SS1,       OUT),
> +       FUNC(SPI0_SS2,       OUT),
> +       FUNC(SPI0_SS3,       OUT),
> +       FUNC(SPI0_ARB,       IN_TIE),
> +       FUNC(SPI0_SCLK,      OUT),
> +       FUNC(UARTHS_RX,      IN),
> +       FUNC(UARTHS_TX,      OUT),
> +       FUNC(RESV6,          IN),
> +       FUNC(RESV7,          IN),
> +       FUNC(CLK_SPI1,       OUT),
> +       FUNC(CLK_I2C1,       OUT),
> +       FUNC(GPIOHS0,        GPIO),
> +       FUNC(GPIOHS1,        GPIO),
> +       FUNC(GPIOHS2,        GPIO),
> +       FUNC(GPIOHS3,        GPIO),
> +       FUNC(GPIOHS4,        GPIO),
> +       FUNC(GPIOHS5,        GPIO),
> +       FUNC(GPIOHS6,        GPIO),
> +       FUNC(GPIOHS7,        GPIO),
> +       FUNC(GPIOHS8,        GPIO),
> +       FUNC(GPIOHS9,        GPIO),
> +       FUNC(GPIOHS10,       GPIO),
> +       FUNC(GPIOHS11,       GPIO),
> +       FUNC(GPIOHS12,       GPIO),
> +       FUNC(GPIOHS13,       GPIO),
> +       FUNC(GPIOHS14,       GPIO),
> +       FUNC(GPIOHS15,       GPIO),
> +       FUNC(GPIOHS16,       GPIO),
> +       FUNC(GPIOHS17,       GPIO),
> +       FUNC(GPIOHS18,       GPIO),
> +       FUNC(GPIOHS19,       GPIO),
> +       FUNC(GPIOHS20,       GPIO),
> +       FUNC(GPIOHS21,       GPIO),
> +       FUNC(GPIOHS22,       GPIO),
> +       FUNC(GPIOHS23,       GPIO),
> +       FUNC(GPIOHS24,       GPIO),
> +       FUNC(GPIOHS25,       GPIO),
> +       FUNC(GPIOHS26,       GPIO),
> +       FUNC(GPIOHS27,       GPIO),
> +       FUNC(GPIOHS28,       GPIO),
> +       FUNC(GPIOHS29,       GPIO),
> +       FUNC(GPIOHS30,       GPIO),
> +       FUNC(GPIOHS31,       GPIO),
> +       FUNC(GPIO0,          GPIO),
> +       FUNC(GPIO1,          GPIO),
> +       FUNC(GPIO2,          GPIO),
> +       FUNC(GPIO3,          GPIO),
> +       FUNC(GPIO4,          GPIO),
> +       FUNC(GPIO5,          GPIO),
> +       FUNC(GPIO6,          GPIO),
> +       FUNC(GPIO7,          GPIO),
> +       FUNC(UART1_RX,       IN),
> +       FUNC(UART1_TX,       OUT),
> +       FUNC(UART2_RX,       IN),
> +       FUNC(UART2_TX,       OUT),
> +       FUNC(UART3_RX,       IN),
> +       FUNC(UART3_TX,       OUT),
> +       FUNC(SPI1_D0,        SPI),
> +       FUNC(SPI1_D1,        SPI),
> +       FUNC(SPI1_D2,        SPI),
> +       FUNC(SPI1_D3,        SPI),
> +       FUNC(SPI1_D4,        SPI),
> +       FUNC(SPI1_D5,        SPI),
> +       FUNC(SPI1_D6,        SPI),
> +       FUNC(SPI1_D7,        SPI),
> +       FUNC(SPI1_SS0,       OUT),
> +       FUNC(SPI1_SS1,       OUT),
> +       FUNC(SPI1_SS2,       OUT),
> +       FUNC(SPI1_SS3,       OUT),
> +       FUNC(SPI1_ARB,       IN_TIE),
> +       FUNC(SPI1_SCLK,      OUT),
> +       FUNC(SPI2_D0,        SPI),
> +       FUNC(SPI2_SS,        IN),
> +       FUNC(SPI2_SCLK,      IN),
> +       FUNC(I2S0_MCLK,      OUT),
> +       FUNC(I2S0_SCLK,      OUT),
> +       FUNC(I2S0_WS,        OUT),
> +       FUNC(I2S0_IN_D0,     IN),
> +       FUNC(I2S0_IN_D1,     IN),
> +       FUNC(I2S0_IN_D2,     IN),
> +       FUNC(I2S0_IN_D3,     IN),
> +       FUNC(I2S0_OUT_D0,    OUT),
> +       FUNC(I2S0_OUT_D1,    OUT),
> +       FUNC(I2S0_OUT_D2,    OUT),
> +       FUNC(I2S0_OUT_D3,    OUT),
> +       FUNC(I2S1_MCLK,      OUT),
> +       FUNC(I2S1_SCLK,      OUT),
> +       FUNC(I2S1_WS,        OUT),
> +       FUNC(I2S1_IN_D0,     IN),
> +       FUNC(I2S1_IN_D1,     IN),
> +       FUNC(I2S1_IN_D2,     IN),
> +       FUNC(I2S1_IN_D3,     IN),
> +       FUNC(I2S1_OUT_D0,    OUT),
> +       FUNC(I2S1_OUT_D1,    OUT),
> +       FUNC(I2S1_OUT_D2,    OUT),
> +       FUNC(I2S1_OUT_D3,    OUT),
> +       FUNC(I2S2_MCLK,      OUT),
> +       FUNC(I2S2_SCLK,      OUT),
> +       FUNC(I2S2_WS,        OUT),
> +       FUNC(I2S2_IN_D0,     IN),
> +       FUNC(I2S2_IN_D1,     IN),
> +       FUNC(I2S2_IN_D2,     IN),
> +       FUNC(I2S2_IN_D3,     IN),
> +       FUNC(I2S2_OUT_D0,    OUT),
> +       FUNC(I2S2_OUT_D1,    OUT),
> +       FUNC(I2S2_OUT_D2,    OUT),
> +       FUNC(I2S2_OUT_D3,    OUT),
> +       FUNC(RESV0,          DISABLED),
> +       FUNC(RESV1,          DISABLED),
> +       FUNC(RESV2,          DISABLED),
> +       FUNC(RESV3,          DISABLED),
> +       FUNC(RESV4,          DISABLED),
> +       FUNC(RESV5,          DISABLED),
> +       FUNC(I2C0_SCLK,      I2C),
> +       FUNC(I2C0_SDA,       I2C),
> +       FUNC(I2C1_SCLK,      I2C),
> +       FUNC(I2C1_SDA,       I2C),
> +       FUNC(I2C2_SCLK,      I2C),
> +       FUNC(I2C2_SDA,       I2C),
> +       FUNC(DVP_XCLK,       OUT),
> +       FUNC(DVP_RST,        OUT),
> +       FUNC(DVP_PWDN,       OUT),
> +       FUNC(DVP_VSYNC,      IN),
> +       FUNC(DVP_HREF,       IN),
> +       FUNC(DVP_PCLK,       IN),
> +       FUNC(DVP_D0,         IN),
> +       FUNC(DVP_D1,         IN),
> +       FUNC(DVP_D2,         IN),
> +       FUNC(DVP_D3,         IN),
> +       FUNC(DVP_D4,         IN),
> +       FUNC(DVP_D5,         IN),
> +       FUNC(DVP_D6,         IN),
> +       FUNC(DVP_D7,         IN),
> +       FUNC(SCCB_SCLK,      I2C),
> +       FUNC(SCCB_SDA,       I2C),
> +       FUNC(UART1_CTS,      IN),
> +       FUNC(UART1_DSR,      IN),
> +       FUNC(UART1_DCD,      IN),
> +       FUNC(UART1_RI,       IN),
> +       FUNC(UART1_SIR_IN,   IN),
> +       FUNC(UART1_DTR,      OUT),
> +       FUNC(UART1_RTS,      OUT),
> +       FUNC(UART1_OUT2,     OUT),
> +       FUNC(UART1_OUT1,     OUT),
> +       FUNC(UART1_SIR_OUT,  OUT),
> +       FUNC(UART1_BAUD,     OUT),
> +       FUNC(UART1_RE,       OUT),
> +       FUNC(UART1_DE,       OUT),
> +       FUNC(UART1_RS485_EN, OUT),
> +       FUNC(UART2_CTS,      IN),
> +       FUNC(UART2_DSR,      IN),
> +       FUNC(UART2_DCD,      IN),
> +       FUNC(UART2_RI,       IN),
> +       FUNC(UART2_SIR_IN,   IN),
> +       FUNC(UART2_DTR,      OUT),
> +       FUNC(UART2_RTS,      OUT),
> +       FUNC(UART2_OUT2,     OUT),
> +       FUNC(UART2_OUT1,     OUT),
> +       FUNC(UART2_SIR_OUT,  OUT),
> +       FUNC(UART2_BAUD,     OUT),
> +       FUNC(UART2_RE,       OUT),
> +       FUNC(UART2_DE,       OUT),
> +       FUNC(UART2_RS485_EN, OUT),
> +       FUNC(UART3_CTS,      IN),
> +       FUNC(UART3_DSR,      IN),
> +       FUNC(UART3_DCD,      IN),
> +       FUNC(UART3_RI,       IN),
> +       FUNC(UART3_SIR_IN,   IN),
> +       FUNC(UART3_DTR,      OUT),
> +       FUNC(UART3_RTS,      OUT),
> +       FUNC(UART3_OUT2,     OUT),
> +       FUNC(UART3_OUT1,     OUT),
> +       FUNC(UART3_SIR_OUT,  OUT),
> +       FUNC(UART3_BAUD,     OUT),
> +       FUNC(UART3_RE,       OUT),
> +       FUNC(UART3_DE,       OUT),
> +       FUNC(UART3_RS485_EN, OUT),
> +       FUNC(TIMER0_TOGGLE1, OUT),
> +       FUNC(TIMER0_TOGGLE2, OUT),
> +       FUNC(TIMER0_TOGGLE3, OUT),
> +       FUNC(TIMER0_TOGGLE4, OUT),
> +       FUNC(TIMER1_TOGGLE1, OUT),
> +       FUNC(TIMER1_TOGGLE2, OUT),
> +       FUNC(TIMER1_TOGGLE3, OUT),
> +       FUNC(TIMER1_TOGGLE4, OUT),
> +       FUNC(TIMER2_TOGGLE1, OUT),
> +       FUNC(TIMER2_TOGGLE2, OUT),
> +       FUNC(TIMER2_TOGGLE3, OUT),
> +       FUNC(TIMER2_TOGGLE4, OUT),
> +       FUNC(CLK_SPI2,       OUT),
> +       FUNC(CLK_I2C2,       OUT),
> +       FUNC(INTERNAL0,      OUT),
> +       FUNC(INTERNAL1,      OUT),
> +       FUNC(INTERNAL2,      OUT),
> +       FUNC(INTERNAL3,      OUT),
> +       FUNC(INTERNAL4,      OUT),
> +       FUNC(INTERNAL5,      OUT),
> +       FUNC(INTERNAL6,      OUT),
> +       FUNC(INTERNAL7,      OUT),
> +       FUNC(INTERNAL8,      OUT),
> +       FUNC(INTERNAL9,      IN),
> +       FUNC(INTERNAL10,     IN),
> +       FUNC(INTERNAL11,     IN),
> +       FUNC(INTERNAL12,     IN),
> +       FUNC(INTERNAL13,     INT13),
> +       FUNC(INTERNAL14,     I2C),
> +       FUNC(INTERNAL15,     IN),
> +       FUNC(INTERNAL16,     IN),
> +       FUNC(INTERNAL17,     IN),
> +       FUNC(CONSTANT,       DISABLED),
> +       FUNC(INTERNAL18,     IN),
> +       FUNC(DEBUG0,         OUT),
> +       FUNC(DEBUG1,         OUT),
> +       FUNC(DEBUG2,         OUT),
> +       FUNC(DEBUG3,         OUT),
> +       FUNC(DEBUG4,         OUT),
> +       FUNC(DEBUG5,         OUT),
> +       FUNC(DEBUG6,         OUT),
> +       FUNC(DEBUG7,         OUT),
> +       FUNC(DEBUG8,         OUT),
> +       FUNC(DEBUG9,         OUT),
> +       FUNC(DEBUG10,        OUT),
> +       FUNC(DEBUG11,        OUT),
> +       FUNC(DEBUG12,        OUT),
> +       FUNC(DEBUG13,        OUT),
> +       FUNC(DEBUG14,        OUT),
> +       FUNC(DEBUG15,        OUT),
> +       FUNC(DEBUG16,        OUT),
> +       FUNC(DEBUG17,        OUT),
> +       FUNC(DEBUG18,        OUT),
> +       FUNC(DEBUG19,        OUT),
> +       FUNC(DEBUG20,        OUT),
> +       FUNC(DEBUG21,        OUT),
> +       FUNC(DEBUG22,        OUT),
> +       FUNC(DEBUG23,        OUT),
> +       FUNC(DEBUG24,        OUT),
> +       FUNC(DEBUG25,        OUT),
> +       FUNC(DEBUG26,        OUT),
> +       FUNC(DEBUG27,        OUT),
> +       FUNC(DEBUG28,        OUT),
> +       FUNC(DEBUG29,        OUT),
> +       FUNC(DEBUG30,        OUT),
> +       FUNC(DEBUG31,        OUT),
> +};
> +#undef FUNC
> +
> +int k210_pc_get_functions_count(struct udevice *dev)
> +{
> +       return ARRAY_SIZE(k210_pcf_infos);
> +}
> +
> +static const char *k210_pc_get_function_name(struct udevice *dev,
> +                                            unsigned selector)
> +{
> +       return k210_pcf_infos[selector].name;
> +}
> +
> +static int k210_pc_pinmux_set(struct udevice *dev, unsigned pin_selector,
> +                             unsigned func_selector)
> +{
> +       struct k210_pc_priv *priv = dev_get_priv(dev);
> +       const struct k210_pcf_info *info = &k210_pcf_infos[func_selector];
> +       u32 mode = k210_pc_mode_id_to_mode[info->mode_id];
> +       u32 val = func_selector | mode;
> +
> +       log_debug("setting pin %s to %s with mode %.8x\n",
> +                 k210_pc_pin_names[pin_selector], info->name, mode);
> +       writel(val, &priv->fpioa->pins[pin_selector]);
> +       return 0;
> +}
> +
> +/* Max drive strength in uA */
> +static const int k210_pc_drive_strength[] = {
> +       [0] = 11200,
> +       [1] = 16800,
> +       [2] = 22300,
> +       [3] = 27800,
> +       [4] = 33300,
> +       [5] = 38700,
> +       [6] = 44100,
> +       [7] = 49500,
> +};
> +
> +static int k210_pc_get_drive(unsigned max_strength_ua)
> +{
> +       int i;
> +
> +       for (i = K210_PC_DRIVE_MAX; i; i--)
> +               if (k210_pc_drive_strength[i] < max_strength_ua)
> +                       return i;
> +
> +       return -EINVAL;
> +}
> +
> +static int k210_pc_pinconf_set(struct udevice *dev, unsigned pin_selector,
> +                              unsigned param, unsigned argument)
> +{
> +       struct k210_pc_priv *priv = dev_get_priv(dev);
> +       u32 val = readl(&priv->fpioa->pins[pin_selector]);
> +
> +       switch (param) {
> +       case PIN_CONFIG_BIAS_DISABLE:
> +               val &= ~K210_PC_BIAS_MASK;
> +               break;
> +       case PIN_CONFIG_BIAS_PULL_DOWN:
> +               if (argument)
> +                       val |= K210_PC_PD;
> +               else
> +                       return -EINVAL;
> +               break;
> +       case PIN_CONFIG_BIAS_PULL_UP:
> +               if (argument)
> +                       val |= K210_PC_PD;
> +               else
> +                       return -EINVAL;
> +               break;
> +       case PIN_CONFIG_DRIVE_STRENGTH:
> +               argument *= 1000;
> +       case PIN_CONFIG_DRIVE_STRENGTH_UA: {
> +               int drive = k210_pc_get_drive(argument);
> +
> +               if (IS_ERR_VALUE(drive))
> +                       return drive;
> +               val &= ~K210_PC_DRIVE_MASK;
> +               val |= FIELD_PREP(K210_PC_DRIVE_MASK, drive);
> +               break;
> +       }
> +       case PIN_CONFIG_INPUT_ENABLE:
> +               if (argument)
> +                       val |= K210_PC_IE;
> +               else
> +                       val &= ~K210_PC_IE;
> +               break;
> +       case PIN_CONFIG_INPUT_SCHMITT:
> +               argument = 1;
> +       case PIN_CONFIG_INPUT_SCHMITT_ENABLE:
> +               if (argument)
> +                       val |= K210_PC_ST;
> +               else
> +                       val &= ~K210_PC_ST;
> +               break;
> +       case PIN_CONFIG_OUTPUT:
> +               k210_pc_pinmux_set(dev, pin_selector, K210_PCF_CONSTANT);
> +               val = readl(&priv->fpioa->pins[pin_selector]);
> +               val |= K210_PC_MODE_OUT;
> +
> +               if (!argument)
> +                       val |= K210_PC_DO_INV;
> +               break;
> +       case PIN_CONFIG_OUTPUT_ENABLE:
> +               if (argument)
> +                       val |= K210_PC_OE;
> +               else
> +                       val &= ~K210_PC_OE;
> +               break;
> +       case PIN_CONFIG_SLEW_RATE:
> +               if (argument)
> +                       val |= K210_PC_SL;
> +               else
> +                       val &= ~K210_PC_SL;
> +               break;
> +       default:
> +               return -EINVAL;
> +       }
> +
> +       writel(val, &priv->fpioa->pins[pin_selector]);
> +       return 0;
> +}
> +
> +static int k210_pc_pinconf_group_set(struct udevice *dev,
> +                                    unsigned group_selector, unsigned param,
> +                                    unsigned argument)
> +{
> +       struct k210_pc_priv *priv = dev_get_priv(dev);
> +
> +       if (param == PIN_CONFIG_POWER_SOURCE) {
> +               u32 bit = BIT(group_selector);
> +
> +               regmap_update_bits(priv->sysctl, priv->power_offset, bit,
> +                                  argument ? bit : 0);
> +       } else {
> +               int i, ret;
> +
> +               for (i = 0; i < 6; i++) {
> +                       ret = k210_pc_pinconf_set(dev, group_selector * 6 + i,
> +                                                 param, argument);
> +                       if (ret)
> +                               return ret;
> +               }
> +       }
> +
> +       return 0;
> +}
> +
> +static int k210_pc_get_pin_muxing(struct udevice *dev, unsigned int selector,
> +                                 char *buf, int size)
> +{
> +       struct k210_pc_priv *priv = dev_get_priv(dev);
> +       u32 val = readl(&priv->fpioa->pins[selector]);
> +       const struct k210_pcf_info *info = &k210_pcf_infos[val & K210_PCF_MASK];
> +
> +       strncpy(buf, info->name, min((size_t)size, sizeof(info->name)));
> +       return 0;
> +}
> +
> +static const struct pinconf_param k210_pc_pinconf_params[] = {
> +       { "bias-disable", PIN_CONFIG_BIAS_DISABLE, 0 },
> +       { "bias-pull-down", PIN_CONFIG_BIAS_PULL_DOWN, 1 },
> +       { "bias-pull-up", PIN_CONFIG_BIAS_PULL_UP, 1 },
> +       { "drive-strength", PIN_CONFIG_DRIVE_STRENGTH, U32_MAX },
> +       { "drive-strength-ua", PIN_CONFIG_DRIVE_STRENGTH_UA, U32_MAX },
> +       { "input-enable", PIN_CONFIG_INPUT_ENABLE, 1 },
> +       { "input-disable", PIN_CONFIG_INPUT_ENABLE, 0 },
> +       { "input-schmitt-enable", PIN_CONFIG_INPUT_SCHMITT_ENABLE, 1 },
> +       { "input-schmitt-disable", PIN_CONFIG_INPUT_SCHMITT_ENABLE, 0 },
> +       { "power-source", PIN_CONFIG_POWER_SOURCE, K210_PC_POWER_1V8 },
> +       { "output-low", PIN_CONFIG_OUTPUT, 0 },
> +       { "output-high", PIN_CONFIG_OUTPUT, 1 },
> +       { "output-enable", PIN_CONFIG_OUTPUT_ENABLE, 1 },
> +       { "output-disable", PIN_CONFIG_OUTPUT_ENABLE, 0 },
> +       { "slew-rate", PIN_CONFIG_SLEW_RATE, 1 },
> +};
> +
> +static const struct pinctrl_ops k210_pc_pinctrl_ops = {
> +       .get_pins_count = k210_pc_get_pins_count,
> +       .get_pin_name = k210_pc_get_pin_name,
> +       .get_groups_count = k210_pc_get_groups_count,
> +       .get_group_name = k210_pc_get_group_name,
> +       .get_functions_count = k210_pc_get_functions_count,
> +       .get_function_name = k210_pc_get_function_name,
> +       .pinmux_set = k210_pc_pinmux_set,
> +       .pinconf_num_params = ARRAY_SIZE(k210_pc_pinconf_params),
> +       .pinconf_params = k210_pc_pinconf_params,
> +       .pinconf_set = k210_pc_pinconf_set,
> +       .pinconf_group_set = k210_pc_pinconf_group_set,
> +       .set_state = pinctrl_generic_set_state,
> +       .get_pin_muxing = k210_pc_get_pin_muxing,
> +};
> +
> +static int k210_pc_probe(struct udevice *dev)
> +{
> +       int ret, i, j;
> +       struct k210_pc_priv *priv = dev_get_priv(dev);
> +
> +       priv->fpioa = dev_read_addr_ptr(dev);
> +       if (!priv->fpioa)
> +               return -EINVAL;
> +
> +       ret = clk_get_by_index(dev, 0, &priv->clk);
> +       if (ret)
> +               return ret;
> +
> +       ret = clk_enable(&priv->clk);
> +       if (ret && ret != -ENOSYS && ret != -ENOTSUPP)
> +               goto err;
> +
> +       priv->sysctl = syscon_regmap_lookup_by_phandle(dev, "kendryte,sysctl");
> +       if (IS_ERR(priv->sysctl)) {
> +               ret = -ENODEV;
> +               goto err;
> +       }
> +
> +       ret = dev_read_u32(dev, "kendryte,power-offset", &priv->power_offset);
> +       if (ret)
> +               goto err;
> +
> +       log_debug("fpioa = %p sysctl = %p power offset = %x\n", priv->fpioa,
> +                 (void *)priv->sysctl->ranges[0].start, priv->power_offset);
> +
> +       /* Disable all pins */
> +       for (i = 6; i < ARRAY_SIZE(k210_pc_pin_names); i++)
> +               k210_pc_pinmux_set(dev, i, K210_PCF_CONSTANT);
> +
> +       /* Init input ties */
> +       for (i = 0; i < ARRAY_SIZE(priv->fpioa->tie_en); i++) {
> +               u32 val = 0;
> +
> +               for (j = 0; j < 32; j++)
> +                       if (k210_pcf_infos[i * 32 + j].mode_id ==
> +                           K210_PC_DEFAULT_IN_TIE)
> +                               val |= BIT(j);
> +               writel(val, &priv->fpioa->tie_en[i]);
> +               writel(val, &priv->fpioa->tie_val[i]);
> +       }
> +
> +       return 0;
> +
> +err:
> +       clk_free(&priv->clk);
> +       return ret;
> +}
> +
> +static const struct udevice_id k210_pc_ids[] = {
> +       { .compatible = "kendryte,k210-fpioa" },
> +       { }
> +};
> +
> +U_BOOT_DRIVER(pinctrl_k210) = {
> +       .name = "pinctrl_k210",
> +       .id = UCLASS_PINCTRL,
> +       .of_match = k210_pc_ids,
> +       .probe = k210_pc_probe,
> +       .priv_auto_alloc_size = sizeof(struct k210_pc_priv),
> +       .ops = &k210_pc_pinctrl_ops,
> +};
> diff --git a/drivers/pinctrl/kendryte/pinctrl.h b/drivers/pinctrl/kendryte/pinctrl.h
> new file mode 100644
> index 0000000000..de434700c3
> --- /dev/null
> +++ b/drivers/pinctrl/kendryte/pinctrl.h
> @@ -0,0 +1,325 @@
> +/* SPDX-License-Identifier: GPL-2.0+ */
> +/*
> + * Copyright (C) 2020 Sean Anderson <seanga2 at gmail.com>
> + */
> +
> +#ifndef K210_PINCTRL_H
> +#define K210_PINCTRL_H
> +
> +#include <linux/bitfield.h>
> +
> +/*
> + * Full list of PinCtrl Functions from
> + * kendryte-standalone-sdk/lib/drivers/include/fpioa.h
> + */
> +#define K210_PCF_SHIFT 0
> +#define K210_PCF_MASK GENMASK(7, 0)
> +#define K210_PCF_JTAG_TCLK      0   /* JTAG Test Clock */
> +#define K210_PCF_JTAG_TDI       1   /* JTAG Test Data In */
> +#define K210_PCF_JTAG_TMS       2   /* JTAG Test Mode Select */
> +#define K210_PCF_JTAG_TDO       3   /* JTAG Test Data Out */
> +#define K210_PCF_SPI0_D0        4   /* SPI0 Data 0 */
> +#define K210_PCF_SPI0_D1        5   /* SPI0 Data 1 */
> +#define K210_PCF_SPI0_D2        6   /* SPI0 Data 2 */
> +#define K210_PCF_SPI0_D3        7   /* SPI0 Data 3 */
> +#define K210_PCF_SPI0_D4        8   /* SPI0 Data 4 */
> +#define K210_PCF_SPI0_D5        9   /* SPI0 Data 5 */
> +#define K210_PCF_SPI0_D6        10  /* SPI0 Data 6 */
> +#define K210_PCF_SPI0_D7        11  /* SPI0 Data 7 */
> +#define K210_PCF_SPI0_SS0       12  /* SPI0 Chip Select 0 */
> +#define K210_PCF_SPI0_SS1       13  /* SPI0 Chip Select 1 */
> +#define K210_PCF_SPI0_SS2       14  /* SPI0 Chip Select 2 */
> +#define K210_PCF_SPI0_SS3       15  /* SPI0 Chip Select 3 */
> +#define K210_PCF_SPI0_ARB       16  /* SPI0 Arbitration */
> +#define K210_PCF_SPI0_SCLK      17  /* SPI0 Serial Clock */
> +#define K210_PCF_UARTHS_RX      18  /* UART High speed Receiver */
> +#define K210_PCF_UARTHS_TX      19  /* UART High speed Transmitter */
> +#define K210_PCF_RESV6          20  /* Reserved function */
> +#define K210_PCF_RESV7          21  /* Reserved function */
> +#define K210_PCF_CLK_SPI1       22  /* Clock SPI1 */
> +#define K210_PCF_CLK_I2C1       23  /* Clock I2C1 */
> +#define K210_PCF_GPIOHS0        24  /* GPIO High speed 0 */
> +#define K210_PCF_GPIOHS1        25  /* GPIO High speed 1 */
> +#define K210_PCF_GPIOHS2        26  /* GPIO High speed 2 */
> +#define K210_PCF_GPIOHS3        27  /* GPIO High speed 3 */
> +#define K210_PCF_GPIOHS4        28  /* GPIO High speed 4 */
> +#define K210_PCF_GPIOHS5        29  /* GPIO High speed 5 */
> +#define K210_PCF_GPIOHS6        30  /* GPIO High speed 6 */
> +#define K210_PCF_GPIOHS7        31  /* GPIO High speed 7 */
> +#define K210_PCF_GPIOHS8        32  /* GPIO High speed 8 */
> +#define K210_PCF_GPIOHS9        33  /* GPIO High speed 9 */
> +#define K210_PCF_GPIOHS10       34  /* GPIO High speed 10 */
> +#define K210_PCF_GPIOHS11       35  /* GPIO High speed 11 */
> +#define K210_PCF_GPIOHS12       36  /* GPIO High speed 12 */
> +#define K210_PCF_GPIOHS13       37  /* GPIO High speed 13 */
> +#define K210_PCF_GPIOHS14       38  /* GPIO High speed 14 */
> +#define K210_PCF_GPIOHS15       39  /* GPIO High speed 15 */
> +#define K210_PCF_GPIOHS16       40  /* GPIO High speed 16 */
> +#define K210_PCF_GPIOHS17       41  /* GPIO High speed 17 */
> +#define K210_PCF_GPIOHS18       42  /* GPIO High speed 18 */
> +#define K210_PCF_GPIOHS19       43  /* GPIO High speed 19 */
> +#define K210_PCF_GPIOHS20       44  /* GPIO High speed 20 */
> +#define K210_PCF_GPIOHS21       45  /* GPIO High speed 21 */
> +#define K210_PCF_GPIOHS22       46  /* GPIO High speed 22 */
> +#define K210_PCF_GPIOHS23       47  /* GPIO High speed 23 */
> +#define K210_PCF_GPIOHS24       48  /* GPIO High speed 24 */
> +#define K210_PCF_GPIOHS25       49  /* GPIO High speed 25 */
> +#define K210_PCF_GPIOHS26       50  /* GPIO High speed 26 */
> +#define K210_PCF_GPIOHS27       51  /* GPIO High speed 27 */
> +#define K210_PCF_GPIOHS28       52  /* GPIO High speed 28 */
> +#define K210_PCF_GPIOHS29       53  /* GPIO High speed 29 */
> +#define K210_PCF_GPIOHS30       54  /* GPIO High speed 30 */
> +#define K210_PCF_GPIOHS31       55  /* GPIO High speed 31 */
> +#define K210_PCF_GPIO0          56  /* GPIO pin 0 */
> +#define K210_PCF_GPIO1          57  /* GPIO pin 1 */
> +#define K210_PCF_GPIO2          58  /* GPIO pin 2 */
> +#define K210_PCF_GPIO3          59  /* GPIO pin 3 */
> +#define K210_PCF_GPIO4          60  /* GPIO pin 4 */
> +#define K210_PCF_GPIO5          61  /* GPIO pin 5 */
> +#define K210_PCF_GPIO6          62  /* GPIO pin 6 */
> +#define K210_PCF_GPIO7          63  /* GPIO pin 7 */
> +#define K210_PCF_UART1_RX       64  /* UART1 Receiver */
> +#define K210_PCF_UART1_TX       65  /* UART1 Transmitter */
> +#define K210_PCF_UART2_RX       66  /* UART2 Receiver */
> +#define K210_PCF_UART2_TX       67  /* UART2 Transmitter */
> +#define K210_PCF_UART3_RX       68  /* UART3 Receiver */
> +#define K210_PCF_UART3_TX       69  /* UART3 Transmitter */
> +#define K210_PCF_SPI1_D0        70  /* SPI1 Data 0 */
> +#define K210_PCF_SPI1_D1        71  /* SPI1 Data 1 */
> +#define K210_PCF_SPI1_D2        72  /* SPI1 Data 2 */
> +#define K210_PCF_SPI1_D3        73  /* SPI1 Data 3 */
> +#define K210_PCF_SPI1_D4        74  /* SPI1 Data 4 */
> +#define K210_PCF_SPI1_D5        75  /* SPI1 Data 5 */
> +#define K210_PCF_SPI1_D6        76  /* SPI1 Data 6 */
> +#define K210_PCF_SPI1_D7        77  /* SPI1 Data 7 */
> +#define K210_PCF_SPI1_SS0       78  /* SPI1 Chip Select 0 */
> +#define K210_PCF_SPI1_SS1       79  /* SPI1 Chip Select 1 */
> +#define K210_PCF_SPI1_SS2       80  /* SPI1 Chip Select 2 */
> +#define K210_PCF_SPI1_SS3       81  /* SPI1 Chip Select 3 */
> +#define K210_PCF_SPI1_ARB       82  /* SPI1 Arbitration */
> +#define K210_PCF_SPI1_SCLK      83  /* SPI1 Serial Clock */
> +#define K210_PCF_SPI2_D0        84  /* SPI2 Data 0 */
> +#define K210_PCF_SPI2_SS        85  /* SPI2 Select */
> +#define K210_PCF_SPI2_SCLK      86  /* SPI2 Serial Clock */
> +#define K210_PCF_I2S0_MCLK      87  /* I2S0 Master Clock */
> +#define K210_PCF_I2S0_SCLK      88  /* I2S0 Serial Clock(BCLK) */
> +#define K210_PCF_I2S0_WS        89  /* I2S0 Word Select(LRCLK) */
> +#define K210_PCF_I2S0_IN_D0     90  /* I2S0 Serial Data Input 0 */
> +#define K210_PCF_I2S0_IN_D1     91  /* I2S0 Serial Data Input 1 */
> +#define K210_PCF_I2S0_IN_D2     92  /* I2S0 Serial Data Input 2 */
> +#define K210_PCF_I2S0_IN_D3     93  /* I2S0 Serial Data Input 3 */
> +#define K210_PCF_I2S0_OUT_D0    94  /* I2S0 Serial Data Output 0 */
> +#define K210_PCF_I2S0_OUT_D1    95  /* I2S0 Serial Data Output 1 */
> +#define K210_PCF_I2S0_OUT_D2    96  /* I2S0 Serial Data Output 2 */
> +#define K210_PCF_I2S0_OUT_D3    97  /* I2S0 Serial Data Output 3 */
> +#define K210_PCF_I2S1_MCLK      98  /* I2S1 Master Clock */
> +#define K210_PCF_I2S1_SCLK      99  /* I2S1 Serial Clock(BCLK) */
> +#define K210_PCF_I2S1_WS        100 /* I2S1 Word Select(LRCLK) */
> +#define K210_PCF_I2S1_IN_D0     101 /* I2S1 Serial Data Input 0 */
> +#define K210_PCF_I2S1_IN_D1     102 /* I2S1 Serial Data Input 1 */
> +#define K210_PCF_I2S1_IN_D2     103 /* I2S1 Serial Data Input 2 */
> +#define K210_PCF_I2S1_IN_D3     104 /* I2S1 Serial Data Input 3 */
> +#define K210_PCF_I2S1_OUT_D0    105 /* I2S1 Serial Data Output 0 */
> +#define K210_PCF_I2S1_OUT_D1    106 /* I2S1 Serial Data Output 1 */
> +#define K210_PCF_I2S1_OUT_D2    107 /* I2S1 Serial Data Output 2 */
> +#define K210_PCF_I2S1_OUT_D3    108 /* I2S1 Serial Data Output 3 */
> +#define K210_PCF_I2S2_MCLK      109 /* I2S2 Master Clock */
> +#define K210_PCF_I2S2_SCLK      110 /* I2S2 Serial Clock(BCLK) */
> +#define K210_PCF_I2S2_WS        111 /* I2S2 Word Select(LRCLK) */
> +#define K210_PCF_I2S2_IN_D0     112 /* I2S2 Serial Data Input 0 */
> +#define K210_PCF_I2S2_IN_D1     113 /* I2S2 Serial Data Input 1 */
> +#define K210_PCF_I2S2_IN_D2     114 /* I2S2 Serial Data Input 2 */
> +#define K210_PCF_I2S2_IN_D3     115 /* I2S2 Serial Data Input 3 */
> +#define K210_PCF_I2S2_OUT_D0    116 /* I2S2 Serial Data Output 0 */
> +#define K210_PCF_I2S2_OUT_D1    117 /* I2S2 Serial Data Output 1 */
> +#define K210_PCF_I2S2_OUT_D2    118 /* I2S2 Serial Data Output 2 */
> +#define K210_PCF_I2S2_OUT_D3    119 /* I2S2 Serial Data Output 3 */
> +#define K210_PCF_RESV0          120 /* Reserved function */
> +#define K210_PCF_RESV1          121 /* Reserved function */
> +#define K210_PCF_RESV2          122 /* Reserved function */
> +#define K210_PCF_RESV3          123 /* Reserved function */
> +#define K210_PCF_RESV4          124 /* Reserved function */
> +#define K210_PCF_RESV5          125 /* Reserved function */
> +#define K210_PCF_I2C0_SCLK      126 /* I2C0 Serial Clock */
> +#define K210_PCF_I2C0_SDA       127 /* I2C0 Serial Data */
> +#define K210_PCF_I2C1_SCLK      128 /* I2C1 Serial Clock */
> +#define K210_PCF_I2C1_SDA       129 /* I2C1 Serial Data */
> +#define K210_PCF_I2C2_SCLK      130 /* I2C2 Serial Clock */
> +#define K210_PCF_I2C2_SDA       131 /* I2C2 Serial Data */
> +#define K210_PCF_DVP_XCLK       132 /* DVP System Clock */
> +#define K210_PCF_DVP_RST        133 /* DVP System Reset */
> +#define K210_PCF_DVP_PWDN       134 /* DVP Power Down Mode */
> +#define K210_PCF_DVP_VSYNC      135 /* DVP Vertical Sync */
> +#define K210_PCF_DVP_HREF       136 /* DVP Horizontal Reference output */
> +#define K210_PCF_DVP_PCLK       137 /* Pixel Clock */
> +#define K210_PCF_DVP_D0         138 /* Data Bit 0 */
> +#define K210_PCF_DVP_D1         139 /* Data Bit 1 */
> +#define K210_PCF_DVP_D2         140 /* Data Bit 2 */
> +#define K210_PCF_DVP_D3         141 /* Data Bit 3 */
> +#define K210_PCF_DVP_D4         142 /* Data Bit 4 */
> +#define K210_PCF_DVP_D5         143 /* Data Bit 5 */
> +#define K210_PCF_DVP_D6         144 /* Data Bit 6 */
> +#define K210_PCF_DVP_D7         145 /* Data Bit 7 */
> +#define K210_PCF_SCCB_SCLK      146 /* Serial Camera Control Bus Clock */
> +#define K210_PCF_SCCB_SDA       147 /* Serial Camera Control Bus Data */
> +#define K210_PCF_UART1_CTS      148 /* UART1 Clear To Send */
> +#define K210_PCF_UART1_DSR      149 /* UART1 Data Set Ready */
> +#define K210_PCF_UART1_DCD      150 /* UART1 Data Carrier Detect */
> +#define K210_PCF_UART1_RI       151 /* UART1 Ring Indicator */
> +#define K210_PCF_UART1_SIR_IN   152 /* UART1 Serial Infrared Input */
> +#define K210_PCF_UART1_DTR      153 /* UART1 Data Terminal Ready */
> +#define K210_PCF_UART1_RTS      154 /* UART1 Request To Send */
> +#define K210_PCF_UART1_OUT2     155 /* UART1 User-designated Output 2 */
> +#define K210_PCF_UART1_OUT1     156 /* UART1 User-designated Output 1 */
> +#define K210_PCF_UART1_SIR_OUT  157 /* UART1 Serial Infrared Output */
> +#define K210_PCF_UART1_BAUD     158 /* UART1 Transmit Clock Output */
> +#define K210_PCF_UART1_RE       159 /* UART1 Receiver Output Enable */
> +#define K210_PCF_UART1_DE       160 /* UART1 Driver Output Enable */
> +#define K210_PCF_UART1_RS485_EN 161 /* UART1 RS485 Enable */
> +#define K210_PCF_UART2_CTS      162 /* UART2 Clear To Send */
> +#define K210_PCF_UART2_DSR      163 /* UART2 Data Set Ready */
> +#define K210_PCF_UART2_DCD      164 /* UART2 Data Carrier Detect */
> +#define K210_PCF_UART2_RI       165 /* UART2 Ring Indicator */
> +#define K210_PCF_UART2_SIR_IN   166 /* UART2 Serial Infrared Input */
> +#define K210_PCF_UART2_DTR      167 /* UART2 Data Terminal Ready */
> +#define K210_PCF_UART2_RTS      168 /* UART2 Request To Send */
> +#define K210_PCF_UART2_OUT2     169 /* UART2 User-designated Output 2 */
> +#define K210_PCF_UART2_OUT1     170 /* UART2 User-designated Output 1 */
> +#define K210_PCF_UART2_SIR_OUT  171 /* UART2 Serial Infrared Output */
> +#define K210_PCF_UART2_BAUD     172 /* UART2 Transmit Clock Output */
> +#define K210_PCF_UART2_RE       173 /* UART2 Receiver Output Enable */
> +#define K210_PCF_UART2_DE       174 /* UART2 Driver Output Enable */
> +#define K210_PCF_UART2_RS485_EN 175 /* UART2 RS485 Enable */
> +#define K210_PCF_UART3_CTS      176 /* UART3 Clear To Send */
> +#define K210_PCF_UART3_DSR      177 /* UART3 Data Set Ready */
> +#define K210_PCF_UART3_DCD      178 /* UART3 Data Carrier Detect */
> +#define K210_PCF_UART3_RI       179 /* UART3 Ring Indicator */
> +#define K210_PCF_UART3_SIR_IN   180 /* UART3 Serial Infrared Input */
> +#define K210_PCF_UART3_DTR      181 /* UART3 Data Terminal Ready */
> +#define K210_PCF_UART3_RTS      182 /* UART3 Request To Send */
> +#define K210_PCF_UART3_OUT2     183 /* UART3 User-designated Output 2 */
> +#define K210_PCF_UART3_OUT1     184 /* UART3 User-designated Output 1 */
> +#define K210_PCF_UART3_SIR_OUT  185 /* UART3 Serial Infrared Output */
> +#define K210_PCF_UART3_BAUD     186 /* UART3 Transmit Clock Output */
> +#define K210_PCF_UART3_RE       187 /* UART3 Receiver Output Enable */
> +#define K210_PCF_UART3_DE       188 /* UART3 Driver Output Enable */
> +#define K210_PCF_UART3_RS485_EN 189 /* UART3 RS485 Enable */
> +#define K210_PCF_TIMER0_TOGGLE1 190 /* TIMER0 Toggle Output 1 */
> +#define K210_PCF_TIMER0_TOGGLE2 191 /* TIMER0 Toggle Output 2 */
> +#define K210_PCF_TIMER0_TOGGLE3 192 /* TIMER0 Toggle Output 3 */
> +#define K210_PCF_TIMER0_TOGGLE4 193 /* TIMER0 Toggle Output 4 */
> +#define K210_PCF_TIMER1_TOGGLE1 194 /* TIMER1 Toggle Output 1 */
> +#define K210_PCF_TIMER1_TOGGLE2 195 /* TIMER1 Toggle Output 2 */
> +#define K210_PCF_TIMER1_TOGGLE3 196 /* TIMER1 Toggle Output 3 */
> +#define K210_PCF_TIMER1_TOGGLE4 197 /* TIMER1 Toggle Output 4 */
> +#define K210_PCF_TIMER2_TOGGLE1 198 /* TIMER2 Toggle Output 1 */
> +#define K210_PCF_TIMER2_TOGGLE2 199 /* TIMER2 Toggle Output 2 */
> +#define K210_PCF_TIMER2_TOGGLE3 200 /* TIMER2 Toggle Output 3 */
> +#define K210_PCF_TIMER2_TOGGLE4 201 /* TIMER2 Toggle Output 4 */
> +#define K210_PCF_CLK_SPI2       202 /* Clock SPI2 */
> +#define K210_PCF_CLK_I2C2       203 /* Clock I2C2 */
> +#define K210_PCF_INTERNAL0      204 /* Internal function signal 0 */
> +#define K210_PCF_INTERNAL1      205 /* Internal function signal 1 */
> +#define K210_PCF_INTERNAL2      206 /* Internal function signal 2 */
> +#define K210_PCF_INTERNAL3      207 /* Internal function signal 3 */
> +#define K210_PCF_INTERNAL4      208 /* Internal function signal 4 */
> +#define K210_PCF_INTERNAL5      209 /* Internal function signal 5 */
> +#define K210_PCF_INTERNAL6      210 /* Internal function signal 6 */
> +#define K210_PCF_INTERNAL7      211 /* Internal function signal 7 */
> +#define K210_PCF_INTERNAL8      212 /* Internal function signal 8 */
> +#define K210_PCF_INTERNAL9      213 /* Internal function signal 9 */
> +#define K210_PCF_INTERNAL10     214 /* Internal function signal 10 */
> +#define K210_PCF_INTERNAL11     215 /* Internal function signal 11 */
> +#define K210_PCF_INTERNAL12     216 /* Internal function signal 12 */
> +#define K210_PCF_INTERNAL13     217 /* Internal function signal 13 */
> +#define K210_PCF_INTERNAL14     218 /* Internal function signal 14 */
> +#define K210_PCF_INTERNAL15     219 /* Internal function signal 15 */
> +#define K210_PCF_INTERNAL16     220 /* Internal function signal 16 */
> +#define K210_PCF_INTERNAL17     221 /* Internal function signal 17 */
> +#define K210_PCF_CONSTANT       222 /* Constant function */
> +#define K210_PCF_INTERNAL18     223 /* Internal function signal 18 */
> +#define K210_PCF_DEBUG0         224 /* Debug function 0 */
> +#define K210_PCF_DEBUG1         225 /* Debug function 1 */
> +#define K210_PCF_DEBUG2         226 /* Debug function 2 */
> +#define K210_PCF_DEBUG3         227 /* Debug function 3 */
> +#define K210_PCF_DEBUG4         228 /* Debug function 4 */
> +#define K210_PCF_DEBUG5         229 /* Debug function 5 */
> +#define K210_PCF_DEBUG6         230 /* Debug function 6 */
> +#define K210_PCF_DEBUG7         231 /* Debug function 7 */
> +#define K210_PCF_DEBUG8         232 /* Debug function 8 */
> +#define K210_PCF_DEBUG9         233 /* Debug function 9 */
> +#define K210_PCF_DEBUG10        234 /* Debug function 10 */
> +#define K210_PCF_DEBUG11        235 /* Debug function 11 */
> +#define K210_PCF_DEBUG12        236 /* Debug function 12 */
> +#define K210_PCF_DEBUG13        237 /* Debug function 13 */
> +#define K210_PCF_DEBUG14        238 /* Debug function 14 */
> +#define K210_PCF_DEBUG15        239 /* Debug function 15 */
> +#define K210_PCF_DEBUG16        240 /* Debug function 16 */
> +#define K210_PCF_DEBUG17        241 /* Debug function 17 */
> +#define K210_PCF_DEBUG18        242 /* Debug function 18 */
> +#define K210_PCF_DEBUG19        243 /* Debug function 19 */
> +#define K210_PCF_DEBUG20        244 /* Debug function 20 */
> +#define K210_PCF_DEBUG21        245 /* Debug function 21 */
> +#define K210_PCF_DEBUG22        246 /* Debug function 22 */
> +#define K210_PCF_DEBUG23        247 /* Debug function 23 */
> +#define K210_PCF_DEBUG24        248 /* Debug function 24 */
> +#define K210_PCF_DEBUG25        249 /* Debug function 25 */
> +#define K210_PCF_DEBUG26        250 /* Debug function 26 */
> +#define K210_PCF_DEBUG27        251 /* Debug function 27 */
> +#define K210_PCF_DEBUG28        252 /* Debug function 28 */
> +#define K210_PCF_DEBUG29        253 /* Debug function 29 */
> +#define K210_PCF_DEBUG30        254 /* Debug function 30 */
> +#define K210_PCF_DEBUG31        255 /* Debug function 31 */
> +
> +/*
> + * The K210 only implements 8 drive levels, even though there is register space
> + * for 16
> + */
> +#define K210_PC_DRIVE_SHIFT 8
> +#define K210_PC_DRIVE_MASK GENMASK(11, 8)
> +#define K210_PC_DRIVE_0 (0 << K210_PC_DRIVE_SHIFT)
> +#define K210_PC_DRIVE_1 (1 << K210_PC_DRIVE_SHIFT)
> +#define K210_PC_DRIVE_2 (2 << K210_PC_DRIVE_SHIFT)
> +#define K210_PC_DRIVE_3 (3 << K210_PC_DRIVE_SHIFT)
> +#define K210_PC_DRIVE_4 (4 << K210_PC_DRIVE_SHIFT)
> +#define K210_PC_DRIVE_5 (5 << K210_PC_DRIVE_SHIFT)
> +#define K210_PC_DRIVE_6 (6 << K210_PC_DRIVE_SHIFT)
> +#define K210_PC_DRIVE_7 (7 << K210_PC_DRIVE_SHIFT)
> +#define K210_PC_DRIVE_MAX 7
> +
> +#define K210_PC_MODE_MASK GENMASK(23, 12)
> +/*
> + * output enabled == PC_OE & (PC_OE_INV ^ FUNCTION_OE) where FUNCTION_OE is a
> + * physical signal from the function
> + */
> +#define K210_PC_OE       BIT(12) /* Output Enable */
> +#define K210_PC_OE_INV   BIT(13) /* INVert function-controlled Output Enable */
> +#define K210_PC_DO_OE    BIT(14) /* set Data Out to the Output Enable signal */
> +#define K210_PC_DO_INV   BIT(15) /* INVert final Data Output */
> +#define K210_PC_PU       BIT(16) /* Pull Up */
> +#define K210_PC_PD       BIT(17) /* Pull Down */
> +/* Strong pull up not implemented on K210 */
> +#define K210_PC_SL       BIT(19) /* reduce SLew rate to prevent overshoot */
> +/* Same semantics as OE above */
> +#define K210_PC_IE       BIT(20) /* Input Enable */
> +#define K210_PC_IE_INV   BIT(21) /* INVert function-controlled Input Enable */
> +#define K210_PC_DI_INV   BIT(22) /* INVert Data Input */
> +#define K210_PC_ST       BIT(23) /* Schmitt Trigger */
> +#define K210_PC_DI       BIT(31) /* raw Data Input */
> +#define K210_PC_BIAS_MASK (K210_PC_PU & K210_PC_PD)
> +
> +#define K210_PC_MODE_IN   (K210_PC_IE | K210_PC_ST)
> +#define K210_PC_MODE_OUT  (K210_PC_DRIVE_7 | K210_PC_OE)
> +#define K210_PC_MODE_I2C  (K210_PC_MODE_IN | K210_PC_IE_INV | K210_PC_SL | \
> +                          K210_PC_OE | K210_PC_OE_INV | K210_PC_PU)
> +#define K210_PC_MODE_SPI  (K210_PC_MODE_IN | K210_PC_IE_INV | \
> +                          K210_PC_MODE_OUT | K210_PC_OE_INV)
> +#define K210_PC_MODE_GPIO (K210_PC_MODE_IN | K210_PC_MODE_OUT)
> +
> +struct k210_fpioa {
> +       u32 pins[48];
> +       u32 tie_en[8];
> +       u32 tie_val[8];
> +};
> +
> +#endif /* K210_PINCTRL_H */
> diff --git a/include/dt-bindings/pinctrl/k210-pinctrl.h b/include/dt-bindings/pinctrl/k210-pinctrl.h
> new file mode 100644
> index 0000000000..6d44ea765b
> --- /dev/null
> +++ b/include/dt-bindings/pinctrl/k210-pinctrl.h
> @@ -0,0 +1,12 @@
> +/* SPDX-License-Identifier: GPL-2.0+ */
> +/*
> + * Copyright (C) 2020 Sean Anderson <seanga2 at gmail.com>
> + */
> +
> +#ifndef DT_K210_PINCTRL_H
> +#define DT_K210_PINCTRL_H
> +
> +#define K210_PC_POWER_3V3 0
> +#define K210_PC_POWER_1V8 1
> +
> +#endif /* DT_K210_PINCTRL_H */
> --
> 2.25.0
>
Sean Anderson March 4, 2020, 3 p.m. UTC | #2
On 3/4/20 1:47 AM, Rick Chen wrote:
> Hi Sean
> 
>> The Fully-Programmable Input/Output Array (FPIOA) device controls pin
>> multiplexing on the K210. The FPIOA can remap any supported function to any
>> multifunctional IO pin. It can also perform basic GPIO functions, such as
>> reading the current value of a pin.
>>
>> Signed-off-by: Sean Anderson <seanga2 at gmail.com>
>> ---
>>
>> Changes in v5:
>> - New
>>
>>  MAINTAINERS                                   |   2 +
>>  .../pinctrl/kendryte,k210-fpioa.txt           | 116 +++
>>  drivers/pinctrl/Kconfig                       |   1 +
>>  drivers/pinctrl/Makefile                      |   1 +
>>  drivers/pinctrl/kendryte/Kconfig              |   7 +
>>  drivers/pinctrl/kendryte/Makefile             |   1 +
>>  drivers/pinctrl/kendryte/pinctrl.c            | 663 ++++++++++++++++++
>>  drivers/pinctrl/kendryte/pinctrl.h            | 325 +++++++++
>>  include/dt-bindings/pinctrl/k210-pinctrl.h    |  12 +
>>  9 files changed, 1128 insertions(+)
>>  create mode 100644 doc/device-tree-bindings/pinctrl/kendryte,k210-fpioa.txt
>>  create mode 100644 drivers/pinctrl/kendryte/Kconfig
>>  create mode 100644 drivers/pinctrl/kendryte/Makefile
>>  create mode 100644 drivers/pinctrl/kendryte/pinctrl.c
>>  create mode 100644 drivers/pinctrl/kendryte/pinctrl.h
>>  create mode 100644 include/dt-bindings/pinctrl/k210-pinctrl.h
>>
> 
> Please checkpatch and fix
> 
> total: 3 errors, 13 warnings, 5 checks, 1147 lines checked
> 
> Thanks
> Rick

Here is the output of checkpatch.

drivers/pinctrl/kendryte/pinctrl.c:25: error: space prohibited before open square bracket '['

This is from using macros in the style

#define FOO(x) [FOO_##x] = {\
	...
}

I think this is more elegant than putting the [] on a separate line,
but it can of course be changed.

drivers/pinctrl/kendryte/pinctrl.c:76: check: Please use a blank line after function/struct/union/enum declarations

This is from using "local" macros, e.g.

#define FOO(x) FOO_##x
enum foo {
	FOO(bar),
	FOO(baz)
};
#undef FOO

I think keeping the undefinition of FOO close to where it is last used
aids readability. This can of course be changed (perhaps by moving the
(un)definition inside the enum).

drivers/pinctrl/kendryte/pinctrl.c:83: warning: Prefer 'unsigned int' to bare use of 'unsigned'
drivers/pinctrl/kendryte/pinctrl.c:106: warning: Prefer 'unsigned int' to bare use of 'unsigned'

All these warnings are due to following the function definitions as
defined in pinctrl_ops.

drivers/pinctrl/kendryte/pinctrl.c:122: error: space prohibited before open square bracket '['
drivers/pinctrl/kendryte/pinctrl.c:133: check: Please use a blank line after function/struct/union/enum declarations
drivers/pinctrl/kendryte/pinctrl.c:141: error: space prohibited before open square bracket '['
drivers/pinctrl/kendryte/pinctrl.c:145: check: Please use a blank line after function/struct/union/enum declarations
drivers/pinctrl/kendryte/pinctrl.c:403: check: Please use a blank line after function/struct/union/enum declarations
drivers/pinctrl/kendryte/pinctrl.c:411: warning: Prefer 'unsigned int' to bare use of 'unsigned'
drivers/pinctrl/kendryte/pinctrl.c:416: warning: Prefer 'unsigned int' to bare use of 'unsigned'
drivers/pinctrl/kendryte/pinctrl.c:417: warning: Prefer 'unsigned int' to bare use of 'unsigned'
drivers/pinctrl/kendryte/pinctrl.c:442: warning: Prefer 'unsigned int' to bare use of 'unsigned'
drivers/pinctrl/kendryte/pinctrl.c:453: warning: Prefer 'unsigned int' to bare use of 'unsigned'
drivers/pinctrl/kendryte/pinctrl.c:454: warning: Prefer 'unsigned int' to bare use of 'unsigned'
drivers/pinctrl/kendryte/pinctrl.c:454: warning: Prefer 'unsigned int' to bare use of 'unsigned'
drivers/pinctrl/kendryte/pinctrl.c:529: warning: Prefer 'unsigned int' to bare use of 'unsigned'
drivers/pinctrl/kendryte/pinctrl.c:529: warning: Prefer 'unsigned int' to bare use of 'unsigned'
drivers/pinctrl/kendryte/pinctrl.c:530: warning: Prefer 'unsigned int' to bare use of 'unsigned'
drivers/pinctrl/kendryte/pinctrl.c:612: warning: ENOSYS means 'invalid syscall nr' and nothing else
drivers/pinctrl/kendryte/pinctrl.h:281: check: Prefer using the BIT macro

This is from the line

#define K210_PC_DRIVE_1 (1 << K210_PC_DRIVE_SHIFT)

Where there are several succeeding and preceding lines which have
different values instead of 1.

--Sean
diff mbox series

Patch

diff --git a/MAINTAINERS b/MAINTAINERS
index 8e9e0569ba..8725bcf9af 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -809,7 +809,9 @@  RISC-V KENDRYTE
 M:	Sean Anderson <seanga2 at gmail.com>
 S:	Maintained
 F:	doc/device-tree-bindings/mfd/kendryte,k210-sysctl.txt
+F:	doc/device-tree-bindings/pinctrl/kendryte,k210-fpioa.txt
 F:	drivers/clk/kendryte/
+F:	drivers/pinctrl/kendryte/
 F:	include/kendryte/
 
 RNG
diff --git a/doc/device-tree-bindings/pinctrl/kendryte,k210-fpioa.txt b/doc/device-tree-bindings/pinctrl/kendryte,k210-fpioa.txt
new file mode 100644
index 0000000000..299ce65304
--- /dev/null
+++ b/doc/device-tree-bindings/pinctrl/kendryte,k210-fpioa.txt
@@ -0,0 +1,116 @@ 
+Kendryte K210 FPIOA
+
+This binding describes the Fully-Programmable Input/Output Array found on
+Kendryte K210 SoCs. Any of the 256 functions can be mapped to any of the 48
+pins.
+
+Required properties:
+- compatible: should be "kendryte,k210-fpioa"
+- reg: address and length of the FPIOA registers
+- kendryte,sysctl: phandle to the "sysctl" register map node
+- kendryte,power-offset: offset in the register map of the power bank control
+  register (in bytes)
+
+Configuration nodes
+
+Pin configuration nodes are documented in pinctrl-bindings.txt
+
+Valid values for pins, groups, and function names:
+
+pins:
+	"IO_X", where X is a number from 0 to 47.
+
+groups:
+	A0, A1, A2, B0, B1, B2, C0, C1
+
+functions:
+	JTAG_TCLK, JTAG_TDI, JTAG_TMS, JTAG_TDO, SPI0_D0, SPI0_D1, SPI0_D2,
+	SPI0_D3, SPI0_D4, SPI0_D5, SPI0_D6, SPI0_D7, SPI0_SS0, SPI0_SS1,
+	SPI0_SS2, SPI0_SS3, SPI0_ARB, SPI0_SCLK, UARTHS_RX, UARTHS_TX, RESV6,
+	RESV7, CLK_SPI1, CLK_I2C1, GPIOHS0, GPIOHS1, GPIOHS2, GPIOHS3, GPIOHS4,
+	GPIOHS5, GPIOHS6, GPIOHS7, GPIOHS8, GPIOHS9, GPIOHS10, GPIOHS11,
+	GPIOHS12, GPIOHS13, GPIOHS14, GPIOHS15, GPIOHS16, GPIOHS17, GPIOHS18,
+	GPIOHS19, GPIOHS20, GPIOHS21, GPIOHS22, GPIOHS23, GPIOHS24, GPIOHS25,
+	GPIOHS26, GPIOHS27, GPIOHS28, GPIOHS29, GPIOHS30, GPIOHS31, GPIO0,
+	GPIO1, GPIO2, GPIO3, GPIO4, GPIO5, GPIO6, GPIO7, UART1_RX, UART1_TX,
+	UART2_RX, UART2_TX, UART3_RX, UART3_TX, SPI1_D0, SPI1_D1, SPI1_D2,
+	SPI1_D3, SPI1_D4, SPI1_D5, SPI1_D6, SPI1_D7, SPI1_SS0, SPI1_SS1,
+	SPI1_SS2, SPI1_SS3, SPI1_ARB, SPI1_SCLK, SPI2_D0, SPI2_SS, SPI2_SCLK,
+	I2S0_MCLK, I2S0_SCLK, I2S0_WS, I2S0_IN_D0, I2S0_IN_D1, I2S0_IN_D2,
+	I2S0_IN_D3, I2S0_OUT_D0, I2S0_OUT_D1, I2S0_OUT_D2, I2S0_OUT_D3,
+	I2S1_MCLK, I2S1_SCLK, I2S1_WS, I2S1_IN_D0, I2S1_IN_D1, I2S1_IN_D2,
+	I2S1_IN_D3, I2S1_OUT_D0, I2S1_OUT_D1, I2S1_OUT_D2, I2S1_OUT_D3,
+	I2S2_MCLK, I2S2_SCLK, I2S2_WS, I2S2_IN_D0, I2S2_IN_D1, I2S2_IN_D2,
+	I2S2_IN_D3, I2S2_OUT_D0, I2S2_OUT_D1, I2S2_OUT_D2, I2S2_OUT_D3, RESV0,
+	RESV1, RESV2, RESV3, RESV4, RESV5, I2C0_SCLK, I2C0_SDA, I2C1_SCLK,
+	I2C1_SDA, I2C2_SCLK, I2C2_SDA, DVP_XCLK, DVP_RST, DVP_PWDN, DVP_VSYNC,
+	DVP_HREF, DVP_PCLK, DVP_D0, DVP_D1, DVP_D2, DVP_D3, DVP_D4, DVP_D5,
+	DVP_D6, DVP_D7, SCCB_SCLK, SCCB_SDA, UART1_CTS, UART1_DSR, UART1_DCD,
+	UART1_RI, UART1_SIR_IN, UART1_DTR, UART1_RTS, UART1_OUT2, UART1_OUT1,
+	UART1_SIR_OUT, UART1_BAUD, UART1_RE, UART1_DE, UART1_RS485_EN,
+	UART2_CTS, UART2_DSR, UART2_DCD, UART2_RI, UART2_SIR_IN, UART2_DTR,
+	UART2_RTS, UART2_OUT2, UART2_OUT1, UART2_SIR_OUT, UART2_BAUD, UART2_RE,
+	UART2_DE, UART2_RS485_EN, UART3_CTS, UART3_DSR, UART3_DCD, UART3_RI,
+	UART3_SIR_IN, UART3_DTR, UART3_RTS, UART3_OUT2, UART3_OUT1,
+	UART3_SIR_OUT, UART3_BAUD, UART3_RE, UART3_DE, UART3_RS485_EN,
+	TIMER0_TOGGLE1, TIMER0_TOGGLE2, TIMER0_TOGGLE3, TIMER0_TOGGLE4,
+	TIMER1_TOGGLE1, TIMER1_TOGGLE2, TIMER1_TOGGLE3, TIMER1_TOGGLE4,
+	TIMER2_TOGGLE1, TIMER2_TOGGLE2, TIMER2_TOGGLE3, TIMER2_TOGGLE4,
+	CLK_SPI2, CLK_I2C2, INTERNAL0, INTERNAL1, INTERNAL2, INTERNAL3,
+	INTERNAL4, INTERNAL5, INTERNAL6, INTERNAL7, INTERNAL8, INTERNAL9,
+	INTERNAL10, INTERNAL11, INTERNAL12, INTERNAL13, INTERNAL14, INTERNAL15,
+	INTERNAL16, INTERNAL17, CONSTANT, INTERNAL18, DEBUG0, DEBUG1, DEBUG2,
+	DEBUG3, DEBUG4, DEBUG5, DEBUG6, DEBUG7, DEBUG8, DEBUG9, DEBUG10,
+	DEBUG11, DEBUG12, DEBUG13, DEBUG14, DEBUG15, DEBUG16, DEBUG17, DEBUG18,
+	DEBUG19, DEBUG20, DEBUG21, DEBUG22, DEBUG23, DEBUG24, DEBUG25, DEBUG26,
+	DEBUG27, DEBUG28, DEBUG29, DEBUG30, DEBUG31
+
+Valid properties include:
+	bias-disable, bias-pull-down, bias-pull-up, drive-strength,
+	drive-strength-ua, input-enable, input-disable, input-schmitt-enable,
+	input-schmitt-disable, power-source, output-low, output-high,
+	output-enable, output-disable, slew-rate
+
+Notes on specific properties include:
+- bias-pull-up, -down, and -pin-default: The pull strength cannot be configured.
+- drive-strength: There are 8 drive strength settings between 11 and 50 mA
+- power-source: Controls the output voltage of a bank of pins. Either
+  K210_PC_POWER_1V8 or K210_PC_POWER_3V3 may be specified. This property cannot
+  be specified for individual pins.
+- slew-rate: Specifying this property reduces the slew rate
+
+Example:
+fpioa: pinmux at 502B0000 {
+	compatible = "kendryte,k210-fpioa";
+	reg = <0x502B0000 0x100>;
+	kendryte,sysctl = <&sysctl>;
+	kendryte,power-offset = <K210_SYSCTL_POWER_SEL>;
+
+	fpioa_jtag: jtag {
+		voltage {
+			group = "A0";
+			power-source = <K210_PC_POWER_3V3>;
+		};
+		tck {
+			function = "JTAG_TCLK";
+			pins = "IO_0";
+		};
+		tdi {
+			function = "JTAG_TDI";
+			pins = "IO_1";
+		};
+		tms {
+			function = "JTAG_TMS";
+			pins = "IO_2";
+		};
+		tdo {
+			function = "JTAG_TDO";
+			pins = "IO_3";
+		};
+	};
+
+	fpioa_isp: isp {
+		function = "GPIOHS0";
+		pins = "IO_16";
+	};
+};
diff --git a/drivers/pinctrl/Kconfig b/drivers/pinctrl/Kconfig
index 83e39b9de3..9ec56c7735 100644
--- a/drivers/pinctrl/Kconfig
+++ b/drivers/pinctrl/Kconfig
@@ -289,6 +289,7 @@  endif
 source "drivers/pinctrl/broadcom/Kconfig"
 source "drivers/pinctrl/exynos/Kconfig"
 source "drivers/pinctrl/intel/Kconfig"
+source "drivers/pinctrl/kendryte/Kconfig"
 source "drivers/pinctrl/mediatek/Kconfig"
 source "drivers/pinctrl/meson/Kconfig"
 source "drivers/pinctrl/mscc/Kconfig"
diff --git a/drivers/pinctrl/Makefile b/drivers/pinctrl/Makefile
index 4f662c4f6d..1fe66fed3c 100644
--- a/drivers/pinctrl/Makefile
+++ b/drivers/pinctrl/Makefile
@@ -17,6 +17,7 @@  obj-$(CONFIG_PINCTRL_SANDBOX)	+= pinctrl-sandbox.o
 obj-$(CONFIG_PINCTRL_UNIPHIER)	+= uniphier/
 obj-$(CONFIG_PINCTRL_PIC32)	+= pinctrl_pic32.o
 obj-$(CONFIG_PINCTRL_EXYNOS)	+= exynos/
+obj-$(CONFIG_PINCTRL_K210)	+= kendryte/
 obj-$(CONFIG_PINCTRL_MESON)	+= meson/
 obj-$(CONFIG_PINCTRL_MTK)	+= mediatek/
 obj-$(CONFIG_PINCTRL_MSCC)	+= mscc/
diff --git a/drivers/pinctrl/kendryte/Kconfig b/drivers/pinctrl/kendryte/Kconfig
new file mode 100644
index 0000000000..6fc10e9516
--- /dev/null
+++ b/drivers/pinctrl/kendryte/Kconfig
@@ -0,0 +1,7 @@ 
+config PINCTRL_K210
+	bool "Kendryte K210 Fully-Programmable Input/Output Array driver"
+	depends on DM && PINCTRL_GENERIC
+	help
+	  Support pin multiplexing on the K210. The "FPIOA" can remap any
+	  supported function to any multifunctional IO pin. It can also perform
+	  basic GPIO functions, such as reading the current value of a pin.
diff --git a/drivers/pinctrl/kendryte/Makefile b/drivers/pinctrl/kendryte/Makefile
new file mode 100644
index 0000000000..1c10d7a929
--- /dev/null
+++ b/drivers/pinctrl/kendryte/Makefile
@@ -0,0 +1 @@ 
+obj-y += pinctrl.o
diff --git a/drivers/pinctrl/kendryte/pinctrl.c b/drivers/pinctrl/kendryte/pinctrl.c
new file mode 100644
index 0000000000..3f7de0e706
--- /dev/null
+++ b/drivers/pinctrl/kendryte/pinctrl.c
@@ -0,0 +1,663 @@ 
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright (C) 2020 Sean Anderson <seanga2 at gmail.com>
+ */
+
+#include <common.h>
+#include <clk.h>
+#include <dm.h>
+#include <dm/pinctrl.h>
+#include <dt-bindings/pinctrl/k210-pinctrl.h>
+#include <mapmem.h>
+#include <regmap.h>
+#include <syscon.h>
+#include <asm/io.h>
+#include <linux/err.h>
+#include "pinctrl.h"
+
+struct k210_pc_priv {
+	struct clk clk;
+	struct k210_fpioa __iomem *fpioa; /* FPIOA register */
+	struct regmap *sysctl; /* Sysctl regmap */
+	u32 power_offset; /* Power bank register offset */
+};
+
+#define PIN(i) [i] = "IO_" #i
+static const char k210_pc_pin_names[][6] = {
+	PIN(0),
+	PIN(1),
+	PIN(2),
+	PIN(3),
+	PIN(4),
+	PIN(5),
+	PIN(6),
+	PIN(7),
+	PIN(8),
+	PIN(9),
+	PIN(10),
+	PIN(11),
+	PIN(12),
+	PIN(13),
+	PIN(14),
+	PIN(15),
+	PIN(16),
+	PIN(17),
+	PIN(18),
+	PIN(19),
+	PIN(20),
+	PIN(21),
+	PIN(22),
+	PIN(23),
+	PIN(24),
+	PIN(25),
+	PIN(26),
+	PIN(27),
+	PIN(28),
+	PIN(29),
+	PIN(30),
+	PIN(31),
+	PIN(32),
+	PIN(33),
+	PIN(34),
+	PIN(35),
+	PIN(36),
+	PIN(37),
+	PIN(38),
+	PIN(39),
+	PIN(40),
+	PIN(41),
+	PIN(42),
+	PIN(43),
+	PIN(44),
+	PIN(45),
+	PIN(46),
+	PIN(47),
+};
+#undef PIN
+
+static int k210_pc_get_pins_count(struct udevice *dev)
+{
+	return ARRAY_SIZE(k210_pc_pin_names);
+};
+
+static const char *k210_pc_get_pin_name(struct udevice *dev, unsigned selector)
+{
+	return k210_pc_pin_names[selector];
+}
+
+/* These are just power domains */
+static const char k210_pc_group_names[][3] = {
+	[0] = "A0",
+	[1] = "A1",
+	[2] = "A2",
+	[3] = "B0",
+	[4] = "B1",
+	[5] = "B2",
+	[6] = "C0",
+	[7] = "C1",
+};
+
+static int k210_pc_get_groups_count(struct udevice *dev)
+{
+	return ARRAY_SIZE(k210_pc_group_names);
+}
+
+static const char *k210_pc_get_group_name(struct udevice *dev,
+					  unsigned selector)
+{
+	return k210_pc_group_names[selector];
+}
+
+enum k210_pc_mode_id {
+	K210_PC_DEFAULT_DISABLED,
+	K210_PC_DEFAULT_IN,
+	K210_PC_DEFAULT_IN_TIE,
+	K210_PC_DEFAULT_OUT,
+	K210_PC_DEFAULT_I2C,
+	K210_PC_DEFAULT_SPI,
+	K210_PC_DEFAULT_GPIO,
+	K210_PC_DEFAULT_INT13,
+};
+
+#define DEFAULT(mode) [K210_PC_DEFAULT_##mode] = K210_PC_MODE_##mode
+static const u32 k210_pc_mode_id_to_mode[] = {
+	[K210_PC_DEFAULT_DISABLED] = 0,
+	DEFAULT(IN),
+	[K210_PC_DEFAULT_IN_TIE] = K210_PC_MODE_IN,
+	DEFAULT(OUT),
+	DEFAULT(I2C),
+	DEFAULT(SPI),
+	DEFAULT(GPIO),
+	[K210_PC_DEFAULT_INT13] = K210_PC_MODE_IN | K210_PC_PU,
+};
+#undef DEFAULT
+
+/* This saves around 2K vs having a pointer+mode */
+struct k210_pcf_info {
+	char name[15];
+	u8 mode_id;
+};
+
+#define FUNC(id, mode) [K210_PCF_##id] = { \
+	.name = #id, \
+	.mode_id = K210_PC_DEFAULT_##mode \
+}
+static const struct k210_pcf_info k210_pcf_infos[] = {
+	FUNC(JTAG_TCLK,      IN),
+	FUNC(JTAG_TDI,       IN),
+	FUNC(JTAG_TMS,       IN),
+	FUNC(JTAG_TDO,       OUT),
+	FUNC(SPI0_D0,        SPI),
+	FUNC(SPI0_D1,        SPI),
+	FUNC(SPI0_D2,        SPI),
+	FUNC(SPI0_D3,        SPI),
+	FUNC(SPI0_D4,        SPI),
+	FUNC(SPI0_D5,        SPI),
+	FUNC(SPI0_D6,        SPI),
+	FUNC(SPI0_D7,        SPI),
+	FUNC(SPI0_SS0,       OUT),
+	FUNC(SPI0_SS1,       OUT),
+	FUNC(SPI0_SS2,       OUT),
+	FUNC(SPI0_SS3,       OUT),
+	FUNC(SPI0_ARB,       IN_TIE),
+	FUNC(SPI0_SCLK,      OUT),
+	FUNC(UARTHS_RX,      IN),
+	FUNC(UARTHS_TX,      OUT),
+	FUNC(RESV6,          IN),
+	FUNC(RESV7,          IN),
+	FUNC(CLK_SPI1,       OUT),
+	FUNC(CLK_I2C1,       OUT),
+	FUNC(GPIOHS0,        GPIO),
+	FUNC(GPIOHS1,        GPIO),
+	FUNC(GPIOHS2,        GPIO),
+	FUNC(GPIOHS3,        GPIO),
+	FUNC(GPIOHS4,        GPIO),
+	FUNC(GPIOHS5,        GPIO),
+	FUNC(GPIOHS6,        GPIO),
+	FUNC(GPIOHS7,        GPIO),
+	FUNC(GPIOHS8,        GPIO),
+	FUNC(GPIOHS9,        GPIO),
+	FUNC(GPIOHS10,       GPIO),
+	FUNC(GPIOHS11,       GPIO),
+	FUNC(GPIOHS12,       GPIO),
+	FUNC(GPIOHS13,       GPIO),
+	FUNC(GPIOHS14,       GPIO),
+	FUNC(GPIOHS15,       GPIO),
+	FUNC(GPIOHS16,       GPIO),
+	FUNC(GPIOHS17,       GPIO),
+	FUNC(GPIOHS18,       GPIO),
+	FUNC(GPIOHS19,       GPIO),
+	FUNC(GPIOHS20,       GPIO),
+	FUNC(GPIOHS21,       GPIO),
+	FUNC(GPIOHS22,       GPIO),
+	FUNC(GPIOHS23,       GPIO),
+	FUNC(GPIOHS24,       GPIO),
+	FUNC(GPIOHS25,       GPIO),
+	FUNC(GPIOHS26,       GPIO),
+	FUNC(GPIOHS27,       GPIO),
+	FUNC(GPIOHS28,       GPIO),
+	FUNC(GPIOHS29,       GPIO),
+	FUNC(GPIOHS30,       GPIO),
+	FUNC(GPIOHS31,       GPIO),
+	FUNC(GPIO0,          GPIO),
+	FUNC(GPIO1,          GPIO),
+	FUNC(GPIO2,          GPIO),
+	FUNC(GPIO3,          GPIO),
+	FUNC(GPIO4,          GPIO),
+	FUNC(GPIO5,          GPIO),
+	FUNC(GPIO6,          GPIO),
+	FUNC(GPIO7,          GPIO),
+	FUNC(UART1_RX,       IN),
+	FUNC(UART1_TX,       OUT),
+	FUNC(UART2_RX,       IN),
+	FUNC(UART2_TX,       OUT),
+	FUNC(UART3_RX,       IN),
+	FUNC(UART3_TX,       OUT),
+	FUNC(SPI1_D0,        SPI),
+	FUNC(SPI1_D1,        SPI),
+	FUNC(SPI1_D2,        SPI),
+	FUNC(SPI1_D3,        SPI),
+	FUNC(SPI1_D4,        SPI),
+	FUNC(SPI1_D5,        SPI),
+	FUNC(SPI1_D6,        SPI),
+	FUNC(SPI1_D7,        SPI),
+	FUNC(SPI1_SS0,       OUT),
+	FUNC(SPI1_SS1,       OUT),
+	FUNC(SPI1_SS2,       OUT),
+	FUNC(SPI1_SS3,       OUT),
+	FUNC(SPI1_ARB,       IN_TIE),
+	FUNC(SPI1_SCLK,      OUT),
+	FUNC(SPI2_D0,        SPI),
+	FUNC(SPI2_SS,        IN),
+	FUNC(SPI2_SCLK,      IN),
+	FUNC(I2S0_MCLK,      OUT),
+	FUNC(I2S0_SCLK,      OUT),
+	FUNC(I2S0_WS,        OUT),
+	FUNC(I2S0_IN_D0,     IN),
+	FUNC(I2S0_IN_D1,     IN),
+	FUNC(I2S0_IN_D2,     IN),
+	FUNC(I2S0_IN_D3,     IN),
+	FUNC(I2S0_OUT_D0,    OUT),
+	FUNC(I2S0_OUT_D1,    OUT),
+	FUNC(I2S0_OUT_D2,    OUT),
+	FUNC(I2S0_OUT_D3,    OUT),
+	FUNC(I2S1_MCLK,      OUT),
+	FUNC(I2S1_SCLK,      OUT),
+	FUNC(I2S1_WS,        OUT),
+	FUNC(I2S1_IN_D0,     IN),
+	FUNC(I2S1_IN_D1,     IN),
+	FUNC(I2S1_IN_D2,     IN),
+	FUNC(I2S1_IN_D3,     IN),
+	FUNC(I2S1_OUT_D0,    OUT),
+	FUNC(I2S1_OUT_D1,    OUT),
+	FUNC(I2S1_OUT_D2,    OUT),
+	FUNC(I2S1_OUT_D3,    OUT),
+	FUNC(I2S2_MCLK,      OUT),
+	FUNC(I2S2_SCLK,      OUT),
+	FUNC(I2S2_WS,        OUT),
+	FUNC(I2S2_IN_D0,     IN),
+	FUNC(I2S2_IN_D1,     IN),
+	FUNC(I2S2_IN_D2,     IN),
+	FUNC(I2S2_IN_D3,     IN),
+	FUNC(I2S2_OUT_D0,    OUT),
+	FUNC(I2S2_OUT_D1,    OUT),
+	FUNC(I2S2_OUT_D2,    OUT),
+	FUNC(I2S2_OUT_D3,    OUT),
+	FUNC(RESV0,          DISABLED),
+	FUNC(RESV1,          DISABLED),
+	FUNC(RESV2,          DISABLED),
+	FUNC(RESV3,          DISABLED),
+	FUNC(RESV4,          DISABLED),
+	FUNC(RESV5,          DISABLED),
+	FUNC(I2C0_SCLK,      I2C),
+	FUNC(I2C0_SDA,       I2C),
+	FUNC(I2C1_SCLK,      I2C),
+	FUNC(I2C1_SDA,       I2C),
+	FUNC(I2C2_SCLK,      I2C),
+	FUNC(I2C2_SDA,       I2C),
+	FUNC(DVP_XCLK,       OUT),
+	FUNC(DVP_RST,        OUT),
+	FUNC(DVP_PWDN,       OUT),
+	FUNC(DVP_VSYNC,      IN),
+	FUNC(DVP_HREF,       IN),
+	FUNC(DVP_PCLK,       IN),
+	FUNC(DVP_D0,         IN),
+	FUNC(DVP_D1,         IN),
+	FUNC(DVP_D2,         IN),
+	FUNC(DVP_D3,         IN),
+	FUNC(DVP_D4,         IN),
+	FUNC(DVP_D5,         IN),
+	FUNC(DVP_D6,         IN),
+	FUNC(DVP_D7,         IN),
+	FUNC(SCCB_SCLK,      I2C),
+	FUNC(SCCB_SDA,       I2C),
+	FUNC(UART1_CTS,      IN),
+	FUNC(UART1_DSR,      IN),
+	FUNC(UART1_DCD,      IN),
+	FUNC(UART1_RI,       IN),
+	FUNC(UART1_SIR_IN,   IN),
+	FUNC(UART1_DTR,      OUT),
+	FUNC(UART1_RTS,      OUT),
+	FUNC(UART1_OUT2,     OUT),
+	FUNC(UART1_OUT1,     OUT),
+	FUNC(UART1_SIR_OUT,  OUT),
+	FUNC(UART1_BAUD,     OUT),
+	FUNC(UART1_RE,       OUT),
+	FUNC(UART1_DE,       OUT),
+	FUNC(UART1_RS485_EN, OUT),
+	FUNC(UART2_CTS,      IN),
+	FUNC(UART2_DSR,      IN),
+	FUNC(UART2_DCD,      IN),
+	FUNC(UART2_RI,       IN),
+	FUNC(UART2_SIR_IN,   IN),
+	FUNC(UART2_DTR,      OUT),
+	FUNC(UART2_RTS,      OUT),
+	FUNC(UART2_OUT2,     OUT),
+	FUNC(UART2_OUT1,     OUT),
+	FUNC(UART2_SIR_OUT,  OUT),
+	FUNC(UART2_BAUD,     OUT),
+	FUNC(UART2_RE,       OUT),
+	FUNC(UART2_DE,       OUT),
+	FUNC(UART2_RS485_EN, OUT),
+	FUNC(UART3_CTS,      IN),
+	FUNC(UART3_DSR,      IN),
+	FUNC(UART3_DCD,      IN),
+	FUNC(UART3_RI,       IN),
+	FUNC(UART3_SIR_IN,   IN),
+	FUNC(UART3_DTR,      OUT),
+	FUNC(UART3_RTS,      OUT),
+	FUNC(UART3_OUT2,     OUT),
+	FUNC(UART3_OUT1,     OUT),
+	FUNC(UART3_SIR_OUT,  OUT),
+	FUNC(UART3_BAUD,     OUT),
+	FUNC(UART3_RE,       OUT),
+	FUNC(UART3_DE,       OUT),
+	FUNC(UART3_RS485_EN, OUT),
+	FUNC(TIMER0_TOGGLE1, OUT),
+	FUNC(TIMER0_TOGGLE2, OUT),
+	FUNC(TIMER0_TOGGLE3, OUT),
+	FUNC(TIMER0_TOGGLE4, OUT),
+	FUNC(TIMER1_TOGGLE1, OUT),
+	FUNC(TIMER1_TOGGLE2, OUT),
+	FUNC(TIMER1_TOGGLE3, OUT),
+	FUNC(TIMER1_TOGGLE4, OUT),
+	FUNC(TIMER2_TOGGLE1, OUT),
+	FUNC(TIMER2_TOGGLE2, OUT),
+	FUNC(TIMER2_TOGGLE3, OUT),
+	FUNC(TIMER2_TOGGLE4, OUT),
+	FUNC(CLK_SPI2,       OUT),
+	FUNC(CLK_I2C2,       OUT),
+	FUNC(INTERNAL0,      OUT),
+	FUNC(INTERNAL1,      OUT),
+	FUNC(INTERNAL2,      OUT),
+	FUNC(INTERNAL3,      OUT),
+	FUNC(INTERNAL4,      OUT),
+	FUNC(INTERNAL5,      OUT),
+	FUNC(INTERNAL6,      OUT),
+	FUNC(INTERNAL7,      OUT),
+	FUNC(INTERNAL8,      OUT),
+	FUNC(INTERNAL9,      IN),
+	FUNC(INTERNAL10,     IN),
+	FUNC(INTERNAL11,     IN),
+	FUNC(INTERNAL12,     IN),
+	FUNC(INTERNAL13,     INT13),
+	FUNC(INTERNAL14,     I2C),
+	FUNC(INTERNAL15,     IN),
+	FUNC(INTERNAL16,     IN),
+	FUNC(INTERNAL17,     IN),
+	FUNC(CONSTANT,       DISABLED),
+	FUNC(INTERNAL18,     IN),
+	FUNC(DEBUG0,         OUT),
+	FUNC(DEBUG1,         OUT),
+	FUNC(DEBUG2,         OUT),
+	FUNC(DEBUG3,         OUT),
+	FUNC(DEBUG4,         OUT),
+	FUNC(DEBUG5,         OUT),
+	FUNC(DEBUG6,         OUT),
+	FUNC(DEBUG7,         OUT),
+	FUNC(DEBUG8,         OUT),
+	FUNC(DEBUG9,         OUT),
+	FUNC(DEBUG10,        OUT),
+	FUNC(DEBUG11,        OUT),
+	FUNC(DEBUG12,        OUT),
+	FUNC(DEBUG13,        OUT),
+	FUNC(DEBUG14,        OUT),
+	FUNC(DEBUG15,        OUT),
+	FUNC(DEBUG16,        OUT),
+	FUNC(DEBUG17,        OUT),
+	FUNC(DEBUG18,        OUT),
+	FUNC(DEBUG19,        OUT),
+	FUNC(DEBUG20,        OUT),
+	FUNC(DEBUG21,        OUT),
+	FUNC(DEBUG22,        OUT),
+	FUNC(DEBUG23,        OUT),
+	FUNC(DEBUG24,        OUT),
+	FUNC(DEBUG25,        OUT),
+	FUNC(DEBUG26,        OUT),
+	FUNC(DEBUG27,        OUT),
+	FUNC(DEBUG28,        OUT),
+	FUNC(DEBUG29,        OUT),
+	FUNC(DEBUG30,        OUT),
+	FUNC(DEBUG31,        OUT),
+};
+#undef FUNC
+
+int k210_pc_get_functions_count(struct udevice *dev)
+{
+	return ARRAY_SIZE(k210_pcf_infos);
+}
+
+static const char *k210_pc_get_function_name(struct udevice *dev,
+					     unsigned selector)
+{
+	return k210_pcf_infos[selector].name;
+}
+
+static int k210_pc_pinmux_set(struct udevice *dev, unsigned pin_selector,
+			      unsigned func_selector)
+{
+	struct k210_pc_priv *priv = dev_get_priv(dev);
+	const struct k210_pcf_info *info = &k210_pcf_infos[func_selector];
+	u32 mode = k210_pc_mode_id_to_mode[info->mode_id];
+	u32 val = func_selector | mode;
+
+	log_debug("setting pin %s to %s with mode %.8x\n",
+		  k210_pc_pin_names[pin_selector], info->name, mode);
+	writel(val, &priv->fpioa->pins[pin_selector]);
+	return 0;
+}
+
+/* Max drive strength in uA */
+static const int k210_pc_drive_strength[] = {
+	[0] = 11200,
+	[1] = 16800,
+	[2] = 22300,
+	[3] = 27800,
+	[4] = 33300,
+	[5] = 38700,
+	[6] = 44100,
+	[7] = 49500,
+};
+
+static int k210_pc_get_drive(unsigned max_strength_ua)
+{
+	int i;
+
+	for (i = K210_PC_DRIVE_MAX; i; i--)
+		if (k210_pc_drive_strength[i] < max_strength_ua)
+			return i;
+
+	return -EINVAL;
+}
+
+static int k210_pc_pinconf_set(struct udevice *dev, unsigned pin_selector,
+			       unsigned param, unsigned argument)
+{
+	struct k210_pc_priv *priv = dev_get_priv(dev);
+	u32 val = readl(&priv->fpioa->pins[pin_selector]);
+
+	switch (param) {
+	case PIN_CONFIG_BIAS_DISABLE:
+		val &= ~K210_PC_BIAS_MASK;
+		break;
+	case PIN_CONFIG_BIAS_PULL_DOWN:
+		if (argument)
+			val |= K210_PC_PD;
+		else
+			return -EINVAL;
+		break;
+	case PIN_CONFIG_BIAS_PULL_UP:
+		if (argument)
+			val |= K210_PC_PD;
+		else
+			return -EINVAL;
+		break;
+	case PIN_CONFIG_DRIVE_STRENGTH:
+		argument *= 1000;
+	case PIN_CONFIG_DRIVE_STRENGTH_UA: {
+		int drive = k210_pc_get_drive(argument);
+
+		if (IS_ERR_VALUE(drive))
+			return drive;
+		val &= ~K210_PC_DRIVE_MASK;
+		val |= FIELD_PREP(K210_PC_DRIVE_MASK, drive);
+		break;
+	}
+	case PIN_CONFIG_INPUT_ENABLE:
+		if (argument)
+			val |= K210_PC_IE;
+		else
+			val &= ~K210_PC_IE;
+		break;
+	case PIN_CONFIG_INPUT_SCHMITT:
+		argument = 1;
+	case PIN_CONFIG_INPUT_SCHMITT_ENABLE:
+		if (argument)
+			val |= K210_PC_ST;
+		else
+			val &= ~K210_PC_ST;
+		break;
+	case PIN_CONFIG_OUTPUT:
+		k210_pc_pinmux_set(dev, pin_selector, K210_PCF_CONSTANT);
+		val = readl(&priv->fpioa->pins[pin_selector]);
+		val |= K210_PC_MODE_OUT;
+
+		if (!argument)
+			val |= K210_PC_DO_INV;
+		break;
+	case PIN_CONFIG_OUTPUT_ENABLE:
+		if (argument)
+			val |= K210_PC_OE;
+		else
+			val &= ~K210_PC_OE;
+		break;
+	case PIN_CONFIG_SLEW_RATE:
+		if (argument)
+			val |= K210_PC_SL;
+		else
+			val &= ~K210_PC_SL;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	writel(val, &priv->fpioa->pins[pin_selector]);
+	return 0;
+}
+
+static int k210_pc_pinconf_group_set(struct udevice *dev,
+				     unsigned group_selector, unsigned param,
+				     unsigned argument)
+{
+	struct k210_pc_priv *priv = dev_get_priv(dev);
+
+	if (param == PIN_CONFIG_POWER_SOURCE) {
+		u32 bit = BIT(group_selector);
+
+		regmap_update_bits(priv->sysctl, priv->power_offset, bit,
+				   argument ? bit : 0);
+	} else {
+		int i, ret;
+
+		for (i = 0; i < 6; i++) {
+			ret = k210_pc_pinconf_set(dev, group_selector * 6 + i,
+						  param, argument);
+			if (ret)
+				return ret;
+		}
+	}
+
+	return 0;
+}
+
+static int k210_pc_get_pin_muxing(struct udevice *dev, unsigned int selector,
+				  char *buf, int size)
+{
+	struct k210_pc_priv *priv = dev_get_priv(dev);
+	u32 val = readl(&priv->fpioa->pins[selector]);
+	const struct k210_pcf_info *info = &k210_pcf_infos[val & K210_PCF_MASK];
+
+	strncpy(buf, info->name, min((size_t)size, sizeof(info->name)));
+	return 0;
+}
+
+static const struct pinconf_param k210_pc_pinconf_params[] = {
+	{ "bias-disable", PIN_CONFIG_BIAS_DISABLE, 0 },
+	{ "bias-pull-down", PIN_CONFIG_BIAS_PULL_DOWN, 1 },
+	{ "bias-pull-up", PIN_CONFIG_BIAS_PULL_UP, 1 },
+	{ "drive-strength", PIN_CONFIG_DRIVE_STRENGTH, U32_MAX },
+	{ "drive-strength-ua", PIN_CONFIG_DRIVE_STRENGTH_UA, U32_MAX },
+	{ "input-enable", PIN_CONFIG_INPUT_ENABLE, 1 },
+	{ "input-disable", PIN_CONFIG_INPUT_ENABLE, 0 },
+	{ "input-schmitt-enable", PIN_CONFIG_INPUT_SCHMITT_ENABLE, 1 },
+	{ "input-schmitt-disable", PIN_CONFIG_INPUT_SCHMITT_ENABLE, 0 },
+	{ "power-source", PIN_CONFIG_POWER_SOURCE, K210_PC_POWER_1V8 },
+	{ "output-low", PIN_CONFIG_OUTPUT, 0 },
+	{ "output-high", PIN_CONFIG_OUTPUT, 1 },
+	{ "output-enable", PIN_CONFIG_OUTPUT_ENABLE, 1 },
+	{ "output-disable", PIN_CONFIG_OUTPUT_ENABLE, 0 },
+	{ "slew-rate", PIN_CONFIG_SLEW_RATE, 1 },
+};
+
+static const struct pinctrl_ops k210_pc_pinctrl_ops = {
+	.get_pins_count = k210_pc_get_pins_count,
+	.get_pin_name = k210_pc_get_pin_name,
+	.get_groups_count = k210_pc_get_groups_count,
+	.get_group_name = k210_pc_get_group_name,
+	.get_functions_count = k210_pc_get_functions_count,
+	.get_function_name = k210_pc_get_function_name,
+	.pinmux_set = k210_pc_pinmux_set,
+	.pinconf_num_params = ARRAY_SIZE(k210_pc_pinconf_params),
+	.pinconf_params = k210_pc_pinconf_params,
+	.pinconf_set = k210_pc_pinconf_set,
+	.pinconf_group_set = k210_pc_pinconf_group_set,
+	.set_state = pinctrl_generic_set_state,
+	.get_pin_muxing = k210_pc_get_pin_muxing,
+};
+
+static int k210_pc_probe(struct udevice *dev)
+{
+	int ret, i, j;
+	struct k210_pc_priv *priv = dev_get_priv(dev);
+
+	priv->fpioa = dev_read_addr_ptr(dev);
+	if (!priv->fpioa)
+		return -EINVAL;
+
+	ret = clk_get_by_index(dev, 0, &priv->clk);
+	if (ret)
+		return ret;
+
+	ret = clk_enable(&priv->clk);
+	if (ret && ret != -ENOSYS && ret != -ENOTSUPP)
+		goto err;
+
+	priv->sysctl = syscon_regmap_lookup_by_phandle(dev, "kendryte,sysctl");
+	if (IS_ERR(priv->sysctl)) {
+		ret = -ENODEV;
+		goto err;
+	}
+
+	ret = dev_read_u32(dev, "kendryte,power-offset", &priv->power_offset);
+	if (ret)
+		goto err;
+
+	log_debug("fpioa = %p sysctl = %p power offset = %x\n", priv->fpioa,
+		  (void *)priv->sysctl->ranges[0].start, priv->power_offset);
+
+	/* Disable all pins */
+	for (i = 6; i < ARRAY_SIZE(k210_pc_pin_names); i++)
+		k210_pc_pinmux_set(dev, i, K210_PCF_CONSTANT);
+
+	/* Init input ties */
+	for (i = 0; i < ARRAY_SIZE(priv->fpioa->tie_en); i++) {
+		u32 val = 0;
+
+		for (j = 0; j < 32; j++)
+			if (k210_pcf_infos[i * 32 + j].mode_id ==
+			    K210_PC_DEFAULT_IN_TIE)
+				val |= BIT(j);
+		writel(val, &priv->fpioa->tie_en[i]);
+		writel(val, &priv->fpioa->tie_val[i]);
+	}
+
+	return 0;
+
+err:
+	clk_free(&priv->clk);
+	return ret;
+}
+
+static const struct udevice_id k210_pc_ids[] = {
+	{ .compatible = "kendryte,k210-fpioa" },
+	{ }
+};
+
+U_BOOT_DRIVER(pinctrl_k210) = {
+	.name = "pinctrl_k210",
+	.id = UCLASS_PINCTRL,
+	.of_match = k210_pc_ids,
+	.probe = k210_pc_probe,
+	.priv_auto_alloc_size = sizeof(struct k210_pc_priv),
+	.ops = &k210_pc_pinctrl_ops,
+};
diff --git a/drivers/pinctrl/kendryte/pinctrl.h b/drivers/pinctrl/kendryte/pinctrl.h
new file mode 100644
index 0000000000..de434700c3
--- /dev/null
+++ b/drivers/pinctrl/kendryte/pinctrl.h
@@ -0,0 +1,325 @@ 
+/* SPDX-License-Identifier: GPL-2.0+ */
+/*
+ * Copyright (C) 2020 Sean Anderson <seanga2 at gmail.com>
+ */
+
+#ifndef K210_PINCTRL_H
+#define K210_PINCTRL_H
+
+#include <linux/bitfield.h>
+
+/*
+ * Full list of PinCtrl Functions from
+ * kendryte-standalone-sdk/lib/drivers/include/fpioa.h
+ */
+#define K210_PCF_SHIFT 0
+#define K210_PCF_MASK GENMASK(7, 0)
+#define K210_PCF_JTAG_TCLK      0   /* JTAG Test Clock */
+#define K210_PCF_JTAG_TDI       1   /* JTAG Test Data In */
+#define K210_PCF_JTAG_TMS       2   /* JTAG Test Mode Select */
+#define K210_PCF_JTAG_TDO       3   /* JTAG Test Data Out */
+#define K210_PCF_SPI0_D0        4   /* SPI0 Data 0 */
+#define K210_PCF_SPI0_D1        5   /* SPI0 Data 1 */
+#define K210_PCF_SPI0_D2        6   /* SPI0 Data 2 */
+#define K210_PCF_SPI0_D3        7   /* SPI0 Data 3 */
+#define K210_PCF_SPI0_D4        8   /* SPI0 Data 4 */
+#define K210_PCF_SPI0_D5        9   /* SPI0 Data 5 */
+#define K210_PCF_SPI0_D6        10  /* SPI0 Data 6 */
+#define K210_PCF_SPI0_D7        11  /* SPI0 Data 7 */
+#define K210_PCF_SPI0_SS0       12  /* SPI0 Chip Select 0 */
+#define K210_PCF_SPI0_SS1       13  /* SPI0 Chip Select 1 */
+#define K210_PCF_SPI0_SS2       14  /* SPI0 Chip Select 2 */
+#define K210_PCF_SPI0_SS3       15  /* SPI0 Chip Select 3 */
+#define K210_PCF_SPI0_ARB       16  /* SPI0 Arbitration */
+#define K210_PCF_SPI0_SCLK      17  /* SPI0 Serial Clock */
+#define K210_PCF_UARTHS_RX      18  /* UART High speed Receiver */
+#define K210_PCF_UARTHS_TX      19  /* UART High speed Transmitter */
+#define K210_PCF_RESV6          20  /* Reserved function */
+#define K210_PCF_RESV7          21  /* Reserved function */
+#define K210_PCF_CLK_SPI1       22  /* Clock SPI1 */
+#define K210_PCF_CLK_I2C1       23  /* Clock I2C1 */
+#define K210_PCF_GPIOHS0        24  /* GPIO High speed 0 */
+#define K210_PCF_GPIOHS1        25  /* GPIO High speed 1 */
+#define K210_PCF_GPIOHS2        26  /* GPIO High speed 2 */
+#define K210_PCF_GPIOHS3        27  /* GPIO High speed 3 */
+#define K210_PCF_GPIOHS4        28  /* GPIO High speed 4 */
+#define K210_PCF_GPIOHS5        29  /* GPIO High speed 5 */
+#define K210_PCF_GPIOHS6        30  /* GPIO High speed 6 */
+#define K210_PCF_GPIOHS7        31  /* GPIO High speed 7 */
+#define K210_PCF_GPIOHS8        32  /* GPIO High speed 8 */
+#define K210_PCF_GPIOHS9        33  /* GPIO High speed 9 */
+#define K210_PCF_GPIOHS10       34  /* GPIO High speed 10 */
+#define K210_PCF_GPIOHS11       35  /* GPIO High speed 11 */
+#define K210_PCF_GPIOHS12       36  /* GPIO High speed 12 */
+#define K210_PCF_GPIOHS13       37  /* GPIO High speed 13 */
+#define K210_PCF_GPIOHS14       38  /* GPIO High speed 14 */
+#define K210_PCF_GPIOHS15       39  /* GPIO High speed 15 */
+#define K210_PCF_GPIOHS16       40  /* GPIO High speed 16 */
+#define K210_PCF_GPIOHS17       41  /* GPIO High speed 17 */
+#define K210_PCF_GPIOHS18       42  /* GPIO High speed 18 */
+#define K210_PCF_GPIOHS19       43  /* GPIO High speed 19 */
+#define K210_PCF_GPIOHS20       44  /* GPIO High speed 20 */
+#define K210_PCF_GPIOHS21       45  /* GPIO High speed 21 */
+#define K210_PCF_GPIOHS22       46  /* GPIO High speed 22 */
+#define K210_PCF_GPIOHS23       47  /* GPIO High speed 23 */
+#define K210_PCF_GPIOHS24       48  /* GPIO High speed 24 */
+#define K210_PCF_GPIOHS25       49  /* GPIO High speed 25 */
+#define K210_PCF_GPIOHS26       50  /* GPIO High speed 26 */
+#define K210_PCF_GPIOHS27       51  /* GPIO High speed 27 */
+#define K210_PCF_GPIOHS28       52  /* GPIO High speed 28 */
+#define K210_PCF_GPIOHS29       53  /* GPIO High speed 29 */
+#define K210_PCF_GPIOHS30       54  /* GPIO High speed 30 */
+#define K210_PCF_GPIOHS31       55  /* GPIO High speed 31 */
+#define K210_PCF_GPIO0          56  /* GPIO pin 0 */
+#define K210_PCF_GPIO1          57  /* GPIO pin 1 */
+#define K210_PCF_GPIO2          58  /* GPIO pin 2 */
+#define K210_PCF_GPIO3          59  /* GPIO pin 3 */
+#define K210_PCF_GPIO4          60  /* GPIO pin 4 */
+#define K210_PCF_GPIO5          61  /* GPIO pin 5 */
+#define K210_PCF_GPIO6          62  /* GPIO pin 6 */
+#define K210_PCF_GPIO7          63  /* GPIO pin 7 */
+#define K210_PCF_UART1_RX       64  /* UART1 Receiver */
+#define K210_PCF_UART1_TX       65  /* UART1 Transmitter */
+#define K210_PCF_UART2_RX       66  /* UART2 Receiver */
+#define K210_PCF_UART2_TX       67  /* UART2 Transmitter */
+#define K210_PCF_UART3_RX       68  /* UART3 Receiver */
+#define K210_PCF_UART3_TX       69  /* UART3 Transmitter */
+#define K210_PCF_SPI1_D0        70  /* SPI1 Data 0 */
+#define K210_PCF_SPI1_D1        71  /* SPI1 Data 1 */
+#define K210_PCF_SPI1_D2        72  /* SPI1 Data 2 */
+#define K210_PCF_SPI1_D3        73  /* SPI1 Data 3 */
+#define K210_PCF_SPI1_D4        74  /* SPI1 Data 4 */
+#define K210_PCF_SPI1_D5        75  /* SPI1 Data 5 */
+#define K210_PCF_SPI1_D6        76  /* SPI1 Data 6 */
+#define K210_PCF_SPI1_D7        77  /* SPI1 Data 7 */
+#define K210_PCF_SPI1_SS0       78  /* SPI1 Chip Select 0 */
+#define K210_PCF_SPI1_SS1       79  /* SPI1 Chip Select 1 */
+#define K210_PCF_SPI1_SS2       80  /* SPI1 Chip Select 2 */
+#define K210_PCF_SPI1_SS3       81  /* SPI1 Chip Select 3 */
+#define K210_PCF_SPI1_ARB       82  /* SPI1 Arbitration */
+#define K210_PCF_SPI1_SCLK      83  /* SPI1 Serial Clock */
+#define K210_PCF_SPI2_D0        84  /* SPI2 Data 0 */
+#define K210_PCF_SPI2_SS        85  /* SPI2 Select */
+#define K210_PCF_SPI2_SCLK      86  /* SPI2 Serial Clock */
+#define K210_PCF_I2S0_MCLK      87  /* I2S0 Master Clock */
+#define K210_PCF_I2S0_SCLK      88  /* I2S0 Serial Clock(BCLK) */
+#define K210_PCF_I2S0_WS        89  /* I2S0 Word Select(LRCLK) */
+#define K210_PCF_I2S0_IN_D0     90  /* I2S0 Serial Data Input 0 */
+#define K210_PCF_I2S0_IN_D1     91  /* I2S0 Serial Data Input 1 */
+#define K210_PCF_I2S0_IN_D2     92  /* I2S0 Serial Data Input 2 */
+#define K210_PCF_I2S0_IN_D3     93  /* I2S0 Serial Data Input 3 */
+#define K210_PCF_I2S0_OUT_D0    94  /* I2S0 Serial Data Output 0 */
+#define K210_PCF_I2S0_OUT_D1    95  /* I2S0 Serial Data Output 1 */
+#define K210_PCF_I2S0_OUT_D2    96  /* I2S0 Serial Data Output 2 */
+#define K210_PCF_I2S0_OUT_D3    97  /* I2S0 Serial Data Output 3 */
+#define K210_PCF_I2S1_MCLK      98  /* I2S1 Master Clock */
+#define K210_PCF_I2S1_SCLK      99  /* I2S1 Serial Clock(BCLK) */
+#define K210_PCF_I2S1_WS        100 /* I2S1 Word Select(LRCLK) */
+#define K210_PCF_I2S1_IN_D0     101 /* I2S1 Serial Data Input 0 */
+#define K210_PCF_I2S1_IN_D1     102 /* I2S1 Serial Data Input 1 */
+#define K210_PCF_I2S1_IN_D2     103 /* I2S1 Serial Data Input 2 */
+#define K210_PCF_I2S1_IN_D3     104 /* I2S1 Serial Data Input 3 */
+#define K210_PCF_I2S1_OUT_D0    105 /* I2S1 Serial Data Output 0 */
+#define K210_PCF_I2S1_OUT_D1    106 /* I2S1 Serial Data Output 1 */
+#define K210_PCF_I2S1_OUT_D2    107 /* I2S1 Serial Data Output 2 */
+#define K210_PCF_I2S1_OUT_D3    108 /* I2S1 Serial Data Output 3 */
+#define K210_PCF_I2S2_MCLK      109 /* I2S2 Master Clock */
+#define K210_PCF_I2S2_SCLK      110 /* I2S2 Serial Clock(BCLK) */
+#define K210_PCF_I2S2_WS        111 /* I2S2 Word Select(LRCLK) */
+#define K210_PCF_I2S2_IN_D0     112 /* I2S2 Serial Data Input 0 */
+#define K210_PCF_I2S2_IN_D1     113 /* I2S2 Serial Data Input 1 */
+#define K210_PCF_I2S2_IN_D2     114 /* I2S2 Serial Data Input 2 */
+#define K210_PCF_I2S2_IN_D3     115 /* I2S2 Serial Data Input 3 */
+#define K210_PCF_I2S2_OUT_D0    116 /* I2S2 Serial Data Output 0 */
+#define K210_PCF_I2S2_OUT_D1    117 /* I2S2 Serial Data Output 1 */
+#define K210_PCF_I2S2_OUT_D2    118 /* I2S2 Serial Data Output 2 */
+#define K210_PCF_I2S2_OUT_D3    119 /* I2S2 Serial Data Output 3 */
+#define K210_PCF_RESV0          120 /* Reserved function */
+#define K210_PCF_RESV1          121 /* Reserved function */
+#define K210_PCF_RESV2          122 /* Reserved function */
+#define K210_PCF_RESV3          123 /* Reserved function */
+#define K210_PCF_RESV4          124 /* Reserved function */
+#define K210_PCF_RESV5          125 /* Reserved function */
+#define K210_PCF_I2C0_SCLK      126 /* I2C0 Serial Clock */
+#define K210_PCF_I2C0_SDA       127 /* I2C0 Serial Data */
+#define K210_PCF_I2C1_SCLK      128 /* I2C1 Serial Clock */
+#define K210_PCF_I2C1_SDA       129 /* I2C1 Serial Data */
+#define K210_PCF_I2C2_SCLK      130 /* I2C2 Serial Clock */
+#define K210_PCF_I2C2_SDA       131 /* I2C2 Serial Data */
+#define K210_PCF_DVP_XCLK       132 /* DVP System Clock */
+#define K210_PCF_DVP_RST        133 /* DVP System Reset */
+#define K210_PCF_DVP_PWDN       134 /* DVP Power Down Mode */
+#define K210_PCF_DVP_VSYNC      135 /* DVP Vertical Sync */
+#define K210_PCF_DVP_HREF       136 /* DVP Horizontal Reference output */
+#define K210_PCF_DVP_PCLK       137 /* Pixel Clock */
+#define K210_PCF_DVP_D0         138 /* Data Bit 0 */
+#define K210_PCF_DVP_D1         139 /* Data Bit 1 */
+#define K210_PCF_DVP_D2         140 /* Data Bit 2 */
+#define K210_PCF_DVP_D3         141 /* Data Bit 3 */
+#define K210_PCF_DVP_D4         142 /* Data Bit 4 */
+#define K210_PCF_DVP_D5         143 /* Data Bit 5 */
+#define K210_PCF_DVP_D6         144 /* Data Bit 6 */
+#define K210_PCF_DVP_D7         145 /* Data Bit 7 */
+#define K210_PCF_SCCB_SCLK      146 /* Serial Camera Control Bus Clock */
+#define K210_PCF_SCCB_SDA       147 /* Serial Camera Control Bus Data */
+#define K210_PCF_UART1_CTS      148 /* UART1 Clear To Send */
+#define K210_PCF_UART1_DSR      149 /* UART1 Data Set Ready */
+#define K210_PCF_UART1_DCD      150 /* UART1 Data Carrier Detect */
+#define K210_PCF_UART1_RI       151 /* UART1 Ring Indicator */
+#define K210_PCF_UART1_SIR_IN   152 /* UART1 Serial Infrared Input */
+#define K210_PCF_UART1_DTR      153 /* UART1 Data Terminal Ready */
+#define K210_PCF_UART1_RTS      154 /* UART1 Request To Send */
+#define K210_PCF_UART1_OUT2     155 /* UART1 User-designated Output 2 */
+#define K210_PCF_UART1_OUT1     156 /* UART1 User-designated Output 1 */
+#define K210_PCF_UART1_SIR_OUT  157 /* UART1 Serial Infrared Output */
+#define K210_PCF_UART1_BAUD     158 /* UART1 Transmit Clock Output */
+#define K210_PCF_UART1_RE       159 /* UART1 Receiver Output Enable */
+#define K210_PCF_UART1_DE       160 /* UART1 Driver Output Enable */
+#define K210_PCF_UART1_RS485_EN 161 /* UART1 RS485 Enable */
+#define K210_PCF_UART2_CTS      162 /* UART2 Clear To Send */
+#define K210_PCF_UART2_DSR      163 /* UART2 Data Set Ready */
+#define K210_PCF_UART2_DCD      164 /* UART2 Data Carrier Detect */
+#define K210_PCF_UART2_RI       165 /* UART2 Ring Indicator */
+#define K210_PCF_UART2_SIR_IN   166 /* UART2 Serial Infrared Input */
+#define K210_PCF_UART2_DTR      167 /* UART2 Data Terminal Ready */
+#define K210_PCF_UART2_RTS      168 /* UART2 Request To Send */
+#define K210_PCF_UART2_OUT2     169 /* UART2 User-designated Output 2 */
+#define K210_PCF_UART2_OUT1     170 /* UART2 User-designated Output 1 */
+#define K210_PCF_UART2_SIR_OUT  171 /* UART2 Serial Infrared Output */
+#define K210_PCF_UART2_BAUD     172 /* UART2 Transmit Clock Output */
+#define K210_PCF_UART2_RE       173 /* UART2 Receiver Output Enable */
+#define K210_PCF_UART2_DE       174 /* UART2 Driver Output Enable */
+#define K210_PCF_UART2_RS485_EN 175 /* UART2 RS485 Enable */
+#define K210_PCF_UART3_CTS      176 /* UART3 Clear To Send */
+#define K210_PCF_UART3_DSR      177 /* UART3 Data Set Ready */
+#define K210_PCF_UART3_DCD      178 /* UART3 Data Carrier Detect */
+#define K210_PCF_UART3_RI       179 /* UART3 Ring Indicator */
+#define K210_PCF_UART3_SIR_IN   180 /* UART3 Serial Infrared Input */
+#define K210_PCF_UART3_DTR      181 /* UART3 Data Terminal Ready */
+#define K210_PCF_UART3_RTS      182 /* UART3 Request To Send */
+#define K210_PCF_UART3_OUT2     183 /* UART3 User-designated Output 2 */
+#define K210_PCF_UART3_OUT1     184 /* UART3 User-designated Output 1 */
+#define K210_PCF_UART3_SIR_OUT  185 /* UART3 Serial Infrared Output */
+#define K210_PCF_UART3_BAUD     186 /* UART3 Transmit Clock Output */
+#define K210_PCF_UART3_RE       187 /* UART3 Receiver Output Enable */
+#define K210_PCF_UART3_DE       188 /* UART3 Driver Output Enable */
+#define K210_PCF_UART3_RS485_EN 189 /* UART3 RS485 Enable */
+#define K210_PCF_TIMER0_TOGGLE1 190 /* TIMER0 Toggle Output 1 */
+#define K210_PCF_TIMER0_TOGGLE2 191 /* TIMER0 Toggle Output 2 */
+#define K210_PCF_TIMER0_TOGGLE3 192 /* TIMER0 Toggle Output 3 */
+#define K210_PCF_TIMER0_TOGGLE4 193 /* TIMER0 Toggle Output 4 */
+#define K210_PCF_TIMER1_TOGGLE1 194 /* TIMER1 Toggle Output 1 */
+#define K210_PCF_TIMER1_TOGGLE2 195 /* TIMER1 Toggle Output 2 */
+#define K210_PCF_TIMER1_TOGGLE3 196 /* TIMER1 Toggle Output 3 */
+#define K210_PCF_TIMER1_TOGGLE4 197 /* TIMER1 Toggle Output 4 */
+#define K210_PCF_TIMER2_TOGGLE1 198 /* TIMER2 Toggle Output 1 */
+#define K210_PCF_TIMER2_TOGGLE2 199 /* TIMER2 Toggle Output 2 */
+#define K210_PCF_TIMER2_TOGGLE3 200 /* TIMER2 Toggle Output 3 */
+#define K210_PCF_TIMER2_TOGGLE4 201 /* TIMER2 Toggle Output 4 */
+#define K210_PCF_CLK_SPI2       202 /* Clock SPI2 */
+#define K210_PCF_CLK_I2C2       203 /* Clock I2C2 */
+#define K210_PCF_INTERNAL0      204 /* Internal function signal 0 */
+#define K210_PCF_INTERNAL1      205 /* Internal function signal 1 */
+#define K210_PCF_INTERNAL2      206 /* Internal function signal 2 */
+#define K210_PCF_INTERNAL3      207 /* Internal function signal 3 */
+#define K210_PCF_INTERNAL4      208 /* Internal function signal 4 */
+#define K210_PCF_INTERNAL5      209 /* Internal function signal 5 */
+#define K210_PCF_INTERNAL6      210 /* Internal function signal 6 */
+#define K210_PCF_INTERNAL7      211 /* Internal function signal 7 */
+#define K210_PCF_INTERNAL8      212 /* Internal function signal 8 */
+#define K210_PCF_INTERNAL9      213 /* Internal function signal 9 */
+#define K210_PCF_INTERNAL10     214 /* Internal function signal 10 */
+#define K210_PCF_INTERNAL11     215 /* Internal function signal 11 */
+#define K210_PCF_INTERNAL12     216 /* Internal function signal 12 */
+#define K210_PCF_INTERNAL13     217 /* Internal function signal 13 */
+#define K210_PCF_INTERNAL14     218 /* Internal function signal 14 */
+#define K210_PCF_INTERNAL15     219 /* Internal function signal 15 */
+#define K210_PCF_INTERNAL16     220 /* Internal function signal 16 */
+#define K210_PCF_INTERNAL17     221 /* Internal function signal 17 */
+#define K210_PCF_CONSTANT       222 /* Constant function */
+#define K210_PCF_INTERNAL18     223 /* Internal function signal 18 */
+#define K210_PCF_DEBUG0         224 /* Debug function 0 */
+#define K210_PCF_DEBUG1         225 /* Debug function 1 */
+#define K210_PCF_DEBUG2         226 /* Debug function 2 */
+#define K210_PCF_DEBUG3         227 /* Debug function 3 */
+#define K210_PCF_DEBUG4         228 /* Debug function 4 */
+#define K210_PCF_DEBUG5         229 /* Debug function 5 */
+#define K210_PCF_DEBUG6         230 /* Debug function 6 */
+#define K210_PCF_DEBUG7         231 /* Debug function 7 */
+#define K210_PCF_DEBUG8         232 /* Debug function 8 */
+#define K210_PCF_DEBUG9         233 /* Debug function 9 */
+#define K210_PCF_DEBUG10        234 /* Debug function 10 */
+#define K210_PCF_DEBUG11        235 /* Debug function 11 */
+#define K210_PCF_DEBUG12        236 /* Debug function 12 */
+#define K210_PCF_DEBUG13        237 /* Debug function 13 */
+#define K210_PCF_DEBUG14        238 /* Debug function 14 */
+#define K210_PCF_DEBUG15        239 /* Debug function 15 */
+#define K210_PCF_DEBUG16        240 /* Debug function 16 */
+#define K210_PCF_DEBUG17        241 /* Debug function 17 */
+#define K210_PCF_DEBUG18        242 /* Debug function 18 */
+#define K210_PCF_DEBUG19        243 /* Debug function 19 */
+#define K210_PCF_DEBUG20        244 /* Debug function 20 */
+#define K210_PCF_DEBUG21        245 /* Debug function 21 */
+#define K210_PCF_DEBUG22        246 /* Debug function 22 */
+#define K210_PCF_DEBUG23        247 /* Debug function 23 */
+#define K210_PCF_DEBUG24        248 /* Debug function 24 */
+#define K210_PCF_DEBUG25        249 /* Debug function 25 */
+#define K210_PCF_DEBUG26        250 /* Debug function 26 */
+#define K210_PCF_DEBUG27        251 /* Debug function 27 */
+#define K210_PCF_DEBUG28        252 /* Debug function 28 */
+#define K210_PCF_DEBUG29        253 /* Debug function 29 */
+#define K210_PCF_DEBUG30        254 /* Debug function 30 */
+#define K210_PCF_DEBUG31        255 /* Debug function 31 */
+
+/*
+ * The K210 only implements 8 drive levels, even though there is register space
+ * for 16
+ */
+#define K210_PC_DRIVE_SHIFT 8
+#define K210_PC_DRIVE_MASK GENMASK(11, 8)
+#define K210_PC_DRIVE_0 (0 << K210_PC_DRIVE_SHIFT)
+#define K210_PC_DRIVE_1 (1 << K210_PC_DRIVE_SHIFT)
+#define K210_PC_DRIVE_2 (2 << K210_PC_DRIVE_SHIFT)
+#define K210_PC_DRIVE_3 (3 << K210_PC_DRIVE_SHIFT)
+#define K210_PC_DRIVE_4 (4 << K210_PC_DRIVE_SHIFT)
+#define K210_PC_DRIVE_5 (5 << K210_PC_DRIVE_SHIFT)
+#define K210_PC_DRIVE_6 (6 << K210_PC_DRIVE_SHIFT)
+#define K210_PC_DRIVE_7 (7 << K210_PC_DRIVE_SHIFT)
+#define K210_PC_DRIVE_MAX 7
+
+#define K210_PC_MODE_MASK GENMASK(23, 12)
+/*
+ * output enabled == PC_OE & (PC_OE_INV ^ FUNCTION_OE) where FUNCTION_OE is a
+ * physical signal from the function
+ */
+#define K210_PC_OE       BIT(12) /* Output Enable */
+#define K210_PC_OE_INV   BIT(13) /* INVert function-controlled Output Enable */
+#define K210_PC_DO_OE    BIT(14) /* set Data Out to the Output Enable signal */
+#define K210_PC_DO_INV   BIT(15) /* INVert final Data Output */
+#define K210_PC_PU       BIT(16) /* Pull Up */
+#define K210_PC_PD       BIT(17) /* Pull Down */
+/* Strong pull up not implemented on K210 */
+#define K210_PC_SL       BIT(19) /* reduce SLew rate to prevent overshoot */
+/* Same semantics as OE above */
+#define K210_PC_IE       BIT(20) /* Input Enable */
+#define K210_PC_IE_INV   BIT(21) /* INVert function-controlled Input Enable */
+#define K210_PC_DI_INV   BIT(22) /* INVert Data Input */
+#define K210_PC_ST       BIT(23) /* Schmitt Trigger */
+#define K210_PC_DI       BIT(31) /* raw Data Input */
+#define K210_PC_BIAS_MASK (K210_PC_PU & K210_PC_PD)
+
+#define K210_PC_MODE_IN   (K210_PC_IE | K210_PC_ST)
+#define K210_PC_MODE_OUT  (K210_PC_DRIVE_7 | K210_PC_OE)
+#define K210_PC_MODE_I2C  (K210_PC_MODE_IN | K210_PC_IE_INV | K210_PC_SL | \
+			   K210_PC_OE | K210_PC_OE_INV | K210_PC_PU)
+#define K210_PC_MODE_SPI  (K210_PC_MODE_IN | K210_PC_IE_INV | \
+			   K210_PC_MODE_OUT | K210_PC_OE_INV)
+#define K210_PC_MODE_GPIO (K210_PC_MODE_IN | K210_PC_MODE_OUT)
+
+struct k210_fpioa {
+	u32 pins[48];
+	u32 tie_en[8];
+	u32 tie_val[8];
+};
+
+#endif /* K210_PINCTRL_H */
diff --git a/include/dt-bindings/pinctrl/k210-pinctrl.h b/include/dt-bindings/pinctrl/k210-pinctrl.h
new file mode 100644
index 0000000000..6d44ea765b
--- /dev/null
+++ b/include/dt-bindings/pinctrl/k210-pinctrl.h
@@ -0,0 +1,12 @@ 
+/* SPDX-License-Identifier: GPL-2.0+ */
+/*
+ * Copyright (C) 2020 Sean Anderson <seanga2 at gmail.com>
+ */
+
+#ifndef DT_K210_PINCTRL_H
+#define DT_K210_PINCTRL_H
+
+#define K210_PC_POWER_3V3 0
+#define K210_PC_POWER_1V8 1
+
+#endif /* DT_K210_PINCTRL_H */