root/drivers/pinctrl/spacemit/pinctrl-k1.c
// SPDX-License-Identifier: GPL-2.0
/* Copyright (c) 2024 Yixun Lan <dlan@gentoo.org> */

#include <linux/bits.h>
#include <linux/clk.h>
#include <linux/cleanup.h>
#include <linux/io.h>
#include <linux/of.h>
#include <linux/platform_device.h>
#include <linux/regmap.h>
#include <linux/seq_file.h>
#include <linux/spinlock.h>
#include <linux/mfd/syscon.h>
#include <linux/module.h>
#include <linux/mutex.h>

#include <linux/pinctrl/pinconf-generic.h>
#include <linux/pinctrl/pinconf.h>
#include <linux/pinctrl/pinctrl.h>
#include <linux/pinctrl/pinmux.h>

#include "../core.h"
#include "../pinctrl-utils.h"
#include "../pinconf.h"
#include "../pinmux.h"
#include "pinctrl-k1.h"

/*
 *     |   pull  |   drive  | schmitter | slew  |  edge  | strong |   mux  |
 * SoC | up/down | strength |  trigger  | rate  | detect |  pull  |  mode  |
 *-----+---------+----------+-----------+-------+--------+--------+--------+
 * K1  | 3 bits  |  3 bits  |   2 bits  | 1 bit | 3 bits |  1 bit | 3 bits |
 *-----+---------+----------+-----------+-------+--------+--------+--------+
 * K3  | 3 bits  |  4 bits  |   1 bits  | 1 bit | 3 bits |  1 bit | 3 bits |
 */

#define PAD_MUX                 GENMASK(2, 0)
#define PAD_STRONG_PULL         BIT(3)
#define PAD_EDGE_RISE           BIT(4)
#define PAD_EDGE_FALL           BIT(5)
#define PAD_EDGE_CLEAR          BIT(6)
#define PAD_SLEW_RATE           GENMASK(12, 11)
#define PAD_SLEW_RATE_EN        BIT(7)
#define PAD_SCHMITT_K1          GENMASK(9, 8)
#define PAD_DRIVE_K1            GENMASK(12, 10)
#define PAD_SCHMITT_K3          BIT(8)
#define PAD_DRIVE_K3            GENMASK(12, 9)
#define PAD_PULLDOWN            BIT(13)
#define PAD_PULLUP              BIT(14)
#define PAD_PULL_EN             BIT(15)

#define IO_PWR_DOMAIN_OFFSET    0x800

#define IO_PWR_DOMAIN_GPIO2_Kx  0x0c
#define IO_PWR_DOMAIN_MMC_Kx    0x1c

#define IO_PWR_DOMAIN_GPIO3_K1  0x10
#define IO_PWR_DOMAIN_QSPI_K1   0x20

#define IO_PWR_DOMAIN_GPIO1_K3  0x04
#define IO_PWR_DOMAIN_GPIO5_K3  0x10
#define IO_PWR_DOMAIN_GPIO4_K3  0x20
#define IO_PWR_DOMAIN_QSPI_K3   0x2c

#define IO_PWR_DOMAIN_V18EN     BIT(2)

#define APBC_ASFAR              0x50
#define APBC_ASSAR              0x54

#define APBC_ASFAR_AKEY         0xbaba
#define APBC_ASSAR_AKEY         0xeb10

struct spacemit_pin_drv_strength {
        u8              val;
        u32             mA;
};

struct spacemit_pinctrl_dconf {
        u64                             schmitt_mask;
        u64                             drive_mask;

        struct spacemit_pin_drv_strength *ds_1v8_tbl;
        size_t                           ds_1v8_tbl_num;
        struct spacemit_pin_drv_strength *ds_3v3_tbl;
        size_t                           ds_3v3_tbl_num;
};

struct spacemit_pin {
        u16                             pin;
        u16                             flags;
        u8                              gpiofunc;
};

struct spacemit_pinctrl {
        struct device                           *dev;
        struct pinctrl_dev                      *pctl_dev;
        const struct spacemit_pinctrl_data      *data;
        struct pinctrl_desc                     pdesc;

        struct mutex                            mutex;
        raw_spinlock_t                          lock;

        void __iomem                            *regs;

        struct regmap                           *regmap_apbc;
};

struct spacemit_pinctrl_data {
        const struct pinctrl_pin_desc   *pins;
        const struct spacemit_pin       *data;
        u16                             npins;
        unsigned int                    (*pin_to_offset)(unsigned int pin);
        unsigned int                    (*pin_to_io_pd_offset)(unsigned int pin);
        const struct spacemit_pinctrl_dconf     *dconf;
};

struct spacemit_pin_mux_config {
        const struct spacemit_pin       *pin;
        u32                             config;
};

/* map pin id to pinctrl register offset, refer MFPR definition */
static unsigned int spacemit_k1_pin_to_offset(unsigned int pin)
{
        unsigned int offset = 0;

        switch (pin) {
        case 0 ... 85:
                offset = pin + 1;
                break;
        case 86 ... 92:
                offset = pin + 37;
                break;
        case 93 ... 97:
                offset = pin + 24;
                break;
        case 98:
                offset = 93;
                break;
        case 99:
                offset = 92;
                break;
        case 100:
                offset = 91;
                break;
        case 101:
                offset = 90;
                break;
        case 102:
                offset = 95;
                break;
        case 103:
                offset = 94;
                break;
        case 104 ... 110:
                offset = pin + 6;
                break;
        case 111 ... 127:
                offset = pin + 20;
                break;
        default:
                break;
        }

        return offset << 2;
}

static unsigned int spacemit_k3_pin_to_offset(unsigned int pin)
{
        unsigned int offset = pin > 130 ? (pin + 2) : pin;

        return offset << 2;
}

static unsigned int spacemit_k1_pin_to_io_pd_offset(unsigned int pin)
{
        unsigned int offset = 0;

        switch (pin) {
        case 47 ... 52:
                offset = IO_PWR_DOMAIN_GPIO3_K1;
                break;
        case 75 ... 80:
                offset = IO_PWR_DOMAIN_GPIO2_Kx;
                break;
        case 98 ... 103:
                offset = IO_PWR_DOMAIN_QSPI_K1;
                break;
        case 104 ... 109:
                offset = IO_PWR_DOMAIN_MMC_Kx;
                break;
        }

        return offset;
}

static unsigned int spacemit_k3_pin_to_io_pd_offset(unsigned int pin)
{
        unsigned int offset = 0;

        switch (pin) {
        case 0 ... 20:
                offset = IO_PWR_DOMAIN_GPIO1_K3;
                break;
        case 21 ... 41:
                offset = IO_PWR_DOMAIN_GPIO2_Kx;
                break;
        case 76 ... 98:
                offset = IO_PWR_DOMAIN_GPIO4_K3;
                break;
        case 99 ... 127:
                offset = IO_PWR_DOMAIN_GPIO5_K3;
                break;
        case 132 ... 137:
                offset = IO_PWR_DOMAIN_MMC_Kx;
                break;
        case 138 ... 144:
                offset = IO_PWR_DOMAIN_QSPI_K3;
                break;
        }

        return offset;
}

static inline void __iomem *spacemit_pin_to_reg(struct spacemit_pinctrl *pctrl,
                                                unsigned int pin)
{
        return pctrl->regs + pctrl->data->pin_to_offset(pin);
}

static u16 spacemit_dt_get_pin(u32 value)
{
        return value >> 16;
}

static u16 spacemit_dt_get_pin_mux(u32 value)
{
        return value & GENMASK(15, 0);
}

static const struct spacemit_pin *spacemit_get_pin(struct spacemit_pinctrl *pctrl,
                                                   unsigned long pin)
{
        const struct spacemit_pin *pdata = pctrl->data->data;
        int i;

        for (i = 0; i < pctrl->data->npins; i++) {
                if (pin == pdata[i].pin)
                        return &pdata[i];
        }

        return NULL;
}

static inline enum spacemit_pin_io_type spacemit_to_pin_io_type(
        const struct spacemit_pin *pin)
{
        return K1_PIN_GET_IO_TYPE(pin->flags);
}

/* External: IO voltage via external source, can be 1.8V or 3.3V */
static const char * const io_type_desc[] = {
        "None",
        "Fixed/1V8",
        "Fixed/3V3",
        "External",
};

static void spacemit_pctrl_dbg_show(struct pinctrl_dev *pctldev,
                                    struct seq_file *seq, unsigned int pin)
{
        struct spacemit_pinctrl *pctrl = pinctrl_dev_get_drvdata(pctldev);
        const struct spacemit_pin *spin = spacemit_get_pin(pctrl, pin);
        enum spacemit_pin_io_type type = spacemit_to_pin_io_type(spin);
        void __iomem *reg;
        u32 value;

        seq_printf(seq, "offset: 0x%04x ", pctrl->data->pin_to_offset(pin));
        seq_printf(seq, "type: %s ", io_type_desc[type]);

        reg = spacemit_pin_to_reg(pctrl, pin);
        value = readl(reg);
        seq_printf(seq, "mux: %ld reg: 0x%04x", (value & PAD_MUX), value);
}

static const struct spacemit_pinctrl_dconf k1_drive_conf = {
        .drive_mask = PAD_DRIVE_K1,
        .schmitt_mask = PAD_SCHMITT_K1,
        .ds_1v8_tbl = (struct spacemit_pin_drv_strength[]) {
                { 0, 11 },
                { 2, 21 },
                { 4, 32 },
                { 6, 42 },
        },
        .ds_1v8_tbl_num = 4,
        .ds_3v3_tbl = (struct spacemit_pin_drv_strength[]) {
                { 0,  7 },
                { 2, 10 },
                { 4, 13 },
                { 6, 16 },
                { 1, 19 },
                { 3, 23 },
                { 5, 26 },
                { 7, 29 },
        },
        .ds_3v3_tbl_num = 8,
};

static const struct spacemit_pinctrl_dconf k3_drive_conf = {
        .drive_mask = PAD_DRIVE_K3,
        .schmitt_mask = PAD_SCHMITT_K3,
        .ds_1v8_tbl = (struct spacemit_pin_drv_strength[]) {
                { 0,  2 },
                { 1,  4 },
                { 2,  6 },
                { 3,  7 },
                { 4,  9 },
                { 5,  11 },
                { 6,  13 },
                { 7,  14 },
                { 8,  21 },
                { 9,  23 },
                { 10, 25 },
                { 11, 26 },
                { 12, 28 },
                { 13, 30 },
                { 14, 31 },
                { 15, 33 },
        },
        .ds_1v8_tbl_num = 16,
        .ds_3v3_tbl = (struct spacemit_pin_drv_strength[]) {
                { 0,  3 },
                { 1,  5 },
                { 2,  7 },
                { 3,  9 },
                { 4,  11 },
                { 5,  13 },
                { 6,  15 },
                { 7,  17 },
                { 8,  25 },
                { 9,  27 },
                { 10, 29 },
                { 11, 31 },
                { 12, 33 },
                { 13, 35 },
                { 14, 37 },
                { 15, 38 },
        },
        .ds_3v3_tbl_num = 16,
};

static inline u8 spacemit_get_ds_value(struct spacemit_pin_drv_strength *tbl,
                                       u32 num, u32 mA)
{
        int i;

        for (i = 0; i < num; i++)
                if (mA <= tbl[i].mA)
                        return tbl[i].val;

        return tbl[num - 1].val;
}

static inline u32 spacemit_get_ds_mA(struct spacemit_pin_drv_strength *tbl,
                                     u32 num, u32 val)
{
        int i;

        for (i = 0; i < num; i++)
                if (val == tbl[i].val)
                        return tbl[i].mA;

        return 0;
}

static inline u8 spacemit_get_driver_strength(enum spacemit_pin_io_type type,
                                              const struct spacemit_pinctrl_dconf *dconf,
                                              u32 mA)
{
        switch (type) {
        case IO_TYPE_1V8:
                return spacemit_get_ds_value(dconf->ds_1v8_tbl,
                                             dconf->ds_1v8_tbl_num,
                                             mA);
        case IO_TYPE_3V3:
                return spacemit_get_ds_value(dconf->ds_3v3_tbl,
                                             dconf->ds_3v3_tbl_num,
                                             mA);
        default:
                return 0;
        }
}

static inline u32 spacemit_get_drive_strength_mA(enum spacemit_pin_io_type type,
                                                 const struct spacemit_pinctrl_dconf *dconf,
                                                 u32 value)
{
        switch (type) {
        case IO_TYPE_1V8:
                return spacemit_get_ds_mA(dconf->ds_1v8_tbl,
                                          dconf->ds_1v8_tbl_num,
                                          value);
        case IO_TYPE_3V3:
                return spacemit_get_ds_mA(dconf->ds_3v3_tbl,
                                          dconf->ds_3v3_tbl_num,
                                          value);
        default:
                return 0;
        }
}

static int spacemit_pctrl_check_power(struct pinctrl_dev *pctldev,
                                      struct device_node *dn,
                                      struct spacemit_pin_mux_config *pinmuxs,
                                      int num_pins, const char *grpname)
{
        struct spacemit_pinctrl *pctrl = pinctrl_dev_get_drvdata(pctldev);
        struct device *dev = pctrl->dev;
        enum spacemit_pin_io_type type;
        u32 power = 0, i;

        of_property_read_u32(dn, "power-source", &power);

        for (i = 0; i < num_pins; i++) {
                type = spacemit_to_pin_io_type(pinmuxs[i].pin);

                if (type != IO_TYPE_EXTERNAL)
                        continue;

                switch (power) {
                case PIN_POWER_STATE_1V8:
                case PIN_POWER_STATE_3V3:
                        break;
                default:
                        dev_err(dev, "group %s has unsupported power\n",
                                grpname);
                        return -ENOTSUPP;
                }
        }

        return 0;
}

static void spacemit_set_io_pwr_domain(struct spacemit_pinctrl *pctrl,
                                      const struct spacemit_pin *spin,
                                      const enum spacemit_pin_io_type type)
{
        u32 offset, val = 0;

        if (!pctrl->regmap_apbc)
                return;

        offset = pctrl->data->pin_to_io_pd_offset(spin->pin);

        /* Other bits are reserved so don't need to save them */
        if (type == IO_TYPE_1V8)
                val = IO_PWR_DOMAIN_V18EN;

        /*
         * IO power domain registers are protected and cannot be accessed
         * directly. Before performing any read or write to the IO power
         * domain registers, an explicit unlock sequence must be issued
         * via the AIB Secure Access Register (ASAR).
         *
         * The unlock sequence allows exactly one subsequent access to the
         * IO power domain registers. After that access completes, the ASAR
         * keys are automatically cleared, and the registers become locked
         * again.
         *
         * This mechanism ensures that IO power domain configuration is
         * performed intentionally, as incorrect voltage settings may
         * result in functional failures or hardware damage.
         */
        regmap_write(pctrl->regmap_apbc, APBC_ASFAR, APBC_ASFAR_AKEY);
        regmap_write(pctrl->regmap_apbc, APBC_ASSAR, APBC_ASSAR_AKEY);

        writel_relaxed(val, pctrl->regs + IO_PWR_DOMAIN_OFFSET + offset);
}

static int spacemit_pctrl_dt_node_to_map(struct pinctrl_dev *pctldev,
                                         struct device_node *np,
                                         struct pinctrl_map **maps,
                                         unsigned int *num_maps)
{
        struct spacemit_pinctrl *pctrl = pinctrl_dev_get_drvdata(pctldev);
        struct device *dev = pctrl->dev;
        struct device_node *child;
        struct pinctrl_map *map;
        const char **grpnames;
        const char *grpname;
        int ngroups = 0;
        int nmaps = 0;
        int ret;

        for_each_available_child_of_node(np, child)
                ngroups += 1;

        grpnames = devm_kcalloc(dev, ngroups, sizeof(*grpnames), GFP_KERNEL);
        if (!grpnames)
                return -ENOMEM;

        map = kzalloc_objs(*map, ngroups * 2);
        if (!map)
                return -ENOMEM;

        ngroups = 0;
        guard(mutex)(&pctrl->mutex);
        for_each_available_child_of_node_scoped(np, child) {
                struct spacemit_pin_mux_config *pinmuxs;
                unsigned int config, *pins;
                int i, npins;

                npins = of_property_count_u32_elems(child, "pinmux");

                if (npins < 1) {
                        dev_err(dev, "invalid pinctrl group %pOFn.%pOFn\n",
                                np, child);
                        return -EINVAL;
                }

                grpname = devm_kasprintf(dev, GFP_KERNEL, "%pOFn.%pOFn",
                                         np, child);
                if (!grpname)
                        return -ENOMEM;

                grpnames[ngroups++] = grpname;

                pins = devm_kcalloc(dev, npins, sizeof(*pins), GFP_KERNEL);
                if (!pins)
                        return -ENOMEM;

                pinmuxs = devm_kcalloc(dev, npins, sizeof(*pinmuxs), GFP_KERNEL);
                if (!pinmuxs)
                        return -ENOMEM;

                for (i = 0; i < npins; i++) {
                        ret = of_property_read_u32_index(child, "pinmux",
                                                         i, &config);

                        if (ret)
                                return -EINVAL;

                        pins[i] = spacemit_dt_get_pin(config);
                        pinmuxs[i].config = config;
                        pinmuxs[i].pin = spacemit_get_pin(pctrl, pins[i]);

                        if (!pinmuxs[i].pin)
                                return dev_err_probe(dev, -ENODEV, "failed to get pin %d\n", pins[i]);
                }

                ret = spacemit_pctrl_check_power(pctldev, child, pinmuxs,
                                                 npins, grpname);
                if (ret < 0)
                        return ret;

                map[nmaps].type = PIN_MAP_TYPE_MUX_GROUP;
                map[nmaps].data.mux.function = np->name;
                map[nmaps].data.mux.group = grpname;
                nmaps += 1;

                ret = pinctrl_generic_add_group(pctldev, grpname,
                                                pins, npins, pinmuxs);
                if (ret < 0)
                        return dev_err_probe(dev, ret, "failed to add group %s: %d\n", grpname, ret);

                ret = pinconf_generic_parse_dt_config(child, pctldev,
                                                      &map[nmaps].data.configs.configs,
                                                      &map[nmaps].data.configs.num_configs);
                if (ret)
                        return dev_err_probe(dev, ret, "failed to parse pin config of group %s\n",
                                grpname);

                if (map[nmaps].data.configs.num_configs == 0)
                        continue;

                map[nmaps].type = PIN_MAP_TYPE_CONFIGS_GROUP;
                map[nmaps].data.configs.group_or_pin = grpname;
                nmaps += 1;
        }

        ret = pinmux_generic_add_function(pctldev, np->name,
                                          grpnames, ngroups, NULL);
        if (ret < 0) {
                pinctrl_utils_free_map(pctldev, map, nmaps);
                return dev_err_probe(dev, ret, "error adding function %s\n", np->name);
        }

        *maps = map;
        *num_maps = nmaps;

        return 0;
}

static const struct pinctrl_ops spacemit_pctrl_ops = {
        .get_groups_count       = pinctrl_generic_get_group_count,
        .get_group_name         = pinctrl_generic_get_group_name,
        .get_group_pins         = pinctrl_generic_get_group_pins,
        .pin_dbg_show           = spacemit_pctrl_dbg_show,
        .dt_node_to_map         = spacemit_pctrl_dt_node_to_map,
        .dt_free_map            = pinctrl_utils_free_map,
};

static int spacemit_pmx_set_mux(struct pinctrl_dev *pctldev,
                                unsigned int fsel, unsigned int gsel)
{
        struct spacemit_pinctrl *pctrl = pinctrl_dev_get_drvdata(pctldev);
        const struct group_desc *group;
        const struct spacemit_pin_mux_config *configs;
        unsigned int i, mux;
        void __iomem *reg;

        group = pinctrl_generic_get_group(pctldev, gsel);
        if (!group)
                return -EINVAL;

        configs = group->data;

        for (i = 0; i < group->grp.npins; i++) {
                const struct spacemit_pin *spin = configs[i].pin;
                u32 value = configs[i].config;

                reg = spacemit_pin_to_reg(pctrl, spin->pin);
                mux = spacemit_dt_get_pin_mux(value);

                guard(raw_spinlock_irqsave)(&pctrl->lock);
                value = readl_relaxed(reg) & ~PAD_MUX;
                writel_relaxed(mux | value, reg);
        }

        return 0;
}

static int spacemit_request_gpio(struct pinctrl_dev *pctldev,
                                 struct pinctrl_gpio_range *range,
                                 unsigned int pin)
{
        struct spacemit_pinctrl *pctrl = pinctrl_dev_get_drvdata(pctldev);
        const struct spacemit_pin *spin = spacemit_get_pin(pctrl, pin);
        void __iomem *reg;

        reg = spacemit_pin_to_reg(pctrl, pin);
        guard(raw_spinlock_irqsave)(&pctrl->lock);
        writel_relaxed(spin->gpiofunc, reg);

        return 0;
}

static const struct pinmux_ops spacemit_pmx_ops = {
        .get_functions_count    = pinmux_generic_get_function_count,
        .get_function_name      = pinmux_generic_get_function_name,
        .get_function_groups    = pinmux_generic_get_function_groups,
        .set_mux                = spacemit_pmx_set_mux,
        .gpio_request_enable    = spacemit_request_gpio,
        .strict                 = true,
};

static int spacemit_pinconf_get(struct pinctrl_dev *pctldev,
                                unsigned int pin, unsigned long *config)
{
        struct spacemit_pinctrl *pctrl = pinctrl_dev_get_drvdata(pctldev);
        int param = pinconf_to_config_param(*config);
        u32 value, arg = 0;

        if (!pin)
                return -EINVAL;

        value = readl(spacemit_pin_to_reg(pctrl, pin));

        switch (param) {
        case PIN_CONFIG_SLEW_RATE:
                if (FIELD_GET(PAD_SLEW_RATE_EN, value))
                        arg = FIELD_GET(PAD_SLEW_RATE, value) + 2;
                else
                        arg = 0;
                break;
        default:
                return -EINVAL;
        }

        *config = pinconf_to_config_packed(param, arg);

        return 0;
}

#define ENABLE_DRV_STRENGTH     BIT(1)
#define ENABLE_SLEW_RATE        BIT(2)
static int spacemit_pinconf_generate_config(struct spacemit_pinctrl *pctrl,
                                            const struct spacemit_pin *spin,
                                            const struct spacemit_pinctrl_dconf *dconf,
                                            unsigned long *configs,
                                            unsigned int num_configs,
                                            u32 *value)
{
        enum spacemit_pin_io_type type;
        int i, param;
        u32 v = 0, voltage = 0, arg, val;
        u32 flag = 0, drv_strength, slew_rate;

        if (!spin)
                return -EINVAL;

        for (i = 0; i < num_configs; i++) {
                param = pinconf_to_config_param(configs[i]);
                arg = pinconf_to_config_argument(configs[i]);

                switch (param) {
                case PIN_CONFIG_BIAS_DISABLE:
                        v &= ~(PAD_PULL_EN | PAD_PULLDOWN | PAD_PULLUP);
                        v &= ~PAD_STRONG_PULL;
                        break;
                case PIN_CONFIG_BIAS_PULL_DOWN:
                        v &= ~(PAD_PULLUP | PAD_STRONG_PULL);
                        v |= (PAD_PULL_EN | PAD_PULLDOWN);
                        break;
                case PIN_CONFIG_BIAS_PULL_UP:
                        v &= ~PAD_PULLDOWN;
                        v |= (PAD_PULL_EN | PAD_PULLUP);

                        if (arg == 1)
                                v |= PAD_STRONG_PULL;
                        break;
                case PIN_CONFIG_DRIVE_STRENGTH:
                        flag |= ENABLE_DRV_STRENGTH;
                        drv_strength = arg;
                        break;
                case PIN_CONFIG_INPUT_SCHMITT:
                        v &= ~dconf->schmitt_mask;
                        v |= (arg << __ffs(dconf->schmitt_mask)) & dconf->schmitt_mask;
                        break;
                case PIN_CONFIG_POWER_SOURCE:
                        voltage = arg;
                        break;
                case PIN_CONFIG_SLEW_RATE:
                        if (arg) {
                                flag |= ENABLE_SLEW_RATE;
                                v |= PAD_SLEW_RATE_EN;
                                slew_rate = arg;
                        } else {
                                v &= ~PAD_SLEW_RATE_EN;
                        }
                        break;
                default:
                        return -EINVAL;
                }
        }

        if (flag & ENABLE_DRV_STRENGTH) {
                type = spacemit_to_pin_io_type(spin);

                /* fix external io type */
                if (type == IO_TYPE_EXTERNAL) {
                        switch (voltage) {
                        case 1800:
                                type = IO_TYPE_1V8;
                                break;
                        case 3300:
                                type = IO_TYPE_3V3;
                                break;
                        default:
                                return -EINVAL;
                        }
                        spacemit_set_io_pwr_domain(pctrl, spin, type);
                }

                val = spacemit_get_driver_strength(type, dconf, drv_strength);

                v &= ~dconf->drive_mask;
                v |= (val << __ffs(dconf->drive_mask)) & dconf->drive_mask;
        }

        if (flag & ENABLE_SLEW_RATE) {
                /* check, driver strength & slew rate */
                if (flag & ENABLE_DRV_STRENGTH) {
                        val = FIELD_GET(PAD_SLEW_RATE, v) + 2;
                        if (slew_rate > 1 && slew_rate != val) {
                                pr_err("slew rate conflict with drive strength\n");
                                return -EINVAL;
                        }
                } else {
                        v &= ~PAD_SLEW_RATE;
                        slew_rate = slew_rate > 1 ? (slew_rate - 2) : 0;
                        v |= FIELD_PREP(PAD_SLEW_RATE, slew_rate);
                }
        }

        *value = v;

        return 0;
}

static int spacemit_pin_set_config(struct spacemit_pinctrl *pctrl,
                                   unsigned int pin, u32 value)
{
        const struct spacemit_pin *spin = spacemit_get_pin(pctrl, pin);
        void __iomem *reg;
        unsigned int mux;

        if (!pin)
                return -EINVAL;

        reg = spacemit_pin_to_reg(pctrl, spin->pin);

        guard(raw_spinlock_irqsave)(&pctrl->lock);
        mux = readl_relaxed(reg) & PAD_MUX;
        writel_relaxed(mux | value, reg);

        return 0;
}

static int spacemit_pinconf_set(struct pinctrl_dev *pctldev,
                                unsigned int pin, unsigned long *configs,
                                unsigned int num_configs)
{
        struct spacemit_pinctrl *pctrl = pinctrl_dev_get_drvdata(pctldev);
        const struct spacemit_pin *spin = spacemit_get_pin(pctrl, pin);
        u32 value;

        if (spacemit_pinconf_generate_config(pctrl, spin, pctrl->data->dconf,
                                             configs, num_configs, &value))
                return -EINVAL;

        return spacemit_pin_set_config(pctrl, pin, value);
}

static int spacemit_pinconf_group_set(struct pinctrl_dev *pctldev,
                                      unsigned int gsel,
                                      unsigned long *configs,
                                      unsigned int num_configs)
{
        struct spacemit_pinctrl *pctrl = pinctrl_dev_get_drvdata(pctldev);
        const struct spacemit_pin *spin;
        const struct group_desc *group;
        u32 value;
        int i;

        group = pinctrl_generic_get_group(pctldev, gsel);
        if (!group)
                return -EINVAL;

        spin = spacemit_get_pin(pctrl, group->grp.pins[0]);
        if (spacemit_pinconf_generate_config(pctrl, spin, pctrl->data->dconf,
                                             configs, num_configs, &value))
                return -EINVAL;

        for (i = 0; i < group->grp.npins; i++)
                spacemit_pin_set_config(pctrl, group->grp.pins[i], value);

        return 0;
}

static void spacemit_pinconf_dbg_pull(struct seq_file *seq, unsigned int value)
{
        u32 normal, strong;

        if (!FIELD_GET(PAD_PULL_EN, value)) {
                seq_puts(seq, ", bias pull disabled");
                return;
        }

        if (FIELD_GET(PAD_PULLDOWN, value))
                seq_puts(seq, ", bias pull down");

        normal = FIELD_GET(PAD_PULLUP, value);
        strong = FIELD_GET(PAD_STRONG_PULL, value);

        if (normal && strong)
                seq_puts(seq, ", bias strong pull up");
        else if (normal)
                seq_puts(seq, ", bias normal pull up");
}

static void spacemit_pinconf_dbg_show(struct pinctrl_dev *pctldev,
                                      struct seq_file *seq, unsigned int pin)
{
        struct spacemit_pinctrl *pctrl = pinctrl_dev_get_drvdata(pctldev);
        const struct spacemit_pinctrl_dconf *dconf = pctrl->data->dconf;
        const struct spacemit_pin *spin = spacemit_get_pin(pctrl, pin);
        enum spacemit_pin_io_type type = spacemit_to_pin_io_type(spin);
        void __iomem *reg = spacemit_pin_to_reg(pctrl, pin);
        u32 value, tmp, mA;

        value = readl(reg);
        spacemit_pinconf_dbg_pull(seq, value);

        seq_printf(seq, ", io type (%s)", io_type_desc[type]);

        tmp = (value & dconf->drive_mask) >> __ffs(dconf->drive_mask);
        if (type == IO_TYPE_1V8 || type == IO_TYPE_3V3) {
                mA = spacemit_get_drive_strength_mA(type, dconf, tmp);
                seq_printf(seq, ", drive strength (%d mA)", mA);
        }

        /* drive strength depend on power source, so show all values */
        if (type == IO_TYPE_EXTERNAL)
                seq_printf(seq, ", drive strength (%d or %d mA)",
                           spacemit_get_drive_strength_mA(IO_TYPE_1V8, dconf, tmp),
                           spacemit_get_drive_strength_mA(IO_TYPE_3V3, dconf, tmp));

        seq_printf(seq, ", register (0x%04x)", value);
}

static const struct pinconf_ops spacemit_pinconf_ops = {
        .pin_config_get                 = spacemit_pinconf_get,
        .pin_config_set                 = spacemit_pinconf_set,
        .pin_config_group_set           = spacemit_pinconf_group_set,
        .pin_config_dbg_show            = spacemit_pinconf_dbg_show,
        .is_generic                     = true,
};

static int spacemit_pinctrl_probe(struct platform_device *pdev)
{
        struct device_node *np = pdev->dev.of_node;
        struct device *dev = &pdev->dev;
        struct spacemit_pinctrl *pctrl;
        struct clk *func_clk, *bus_clk;
        const struct spacemit_pinctrl_data *pctrl_data;
        int ret;

        pctrl_data = device_get_match_data(dev);
        if (!pctrl_data)
                return -ENODEV;

        if (pctrl_data->npins == 0)
                return dev_err_probe(dev, -EINVAL, "invalid pin data\n");

        pctrl = devm_kzalloc(dev, sizeof(*pctrl), GFP_KERNEL);
        if (!pctrl)
                return -ENOMEM;

        pctrl->regs = devm_platform_ioremap_resource(pdev, 0);
        if (IS_ERR(pctrl->regs))
                return PTR_ERR(pctrl->regs);

        pctrl->regmap_apbc = syscon_regmap_lookup_by_phandle(np, "spacemit,apbc");
        if (IS_ERR(pctrl->regmap_apbc)) {
                dev_warn(dev, "no syscon found, disable power voltage switch functionality\n");
                pctrl->regmap_apbc = NULL;
        }

        func_clk = devm_clk_get_enabled(dev, "func");
        if (IS_ERR(func_clk))
                return dev_err_probe(dev, PTR_ERR(func_clk), "failed to get func clock\n");

        bus_clk = devm_clk_get_enabled(dev, "bus");
        if (IS_ERR(bus_clk))
                return dev_err_probe(dev, PTR_ERR(bus_clk), "failed to get bus clock\n");

        pctrl->pdesc.name = dev_name(dev);
        pctrl->pdesc.pins = pctrl_data->pins;
        pctrl->pdesc.npins = pctrl_data->npins;
        pctrl->pdesc.pctlops = &spacemit_pctrl_ops;
        pctrl->pdesc.pmxops = &spacemit_pmx_ops;
        pctrl->pdesc.confops = &spacemit_pinconf_ops;
        pctrl->pdesc.owner = THIS_MODULE;

        pctrl->data = pctrl_data;
        pctrl->dev = dev;
        raw_spin_lock_init(&pctrl->lock);

        ret = devm_mutex_init(dev, &pctrl->mutex);
        if (ret)
                return ret;

        platform_set_drvdata(pdev, pctrl);

        ret = devm_pinctrl_register_and_init(dev, &pctrl->pdesc,
                                             pctrl, &pctrl->pctl_dev);
        if (ret)
                return dev_err_probe(dev, ret,
                                     "fail to register pinctrl driver\n");

        return pinctrl_enable(pctrl->pctl_dev);
}

static const struct pinctrl_pin_desc k1_pin_desc[] = {
        PINCTRL_PIN(0, "GPIO_00"),
        PINCTRL_PIN(1, "GPIO_01"),
        PINCTRL_PIN(2, "GPIO_02"),
        PINCTRL_PIN(3, "GPIO_03"),
        PINCTRL_PIN(4, "GPIO_04"),
        PINCTRL_PIN(5, "GPIO_05"),
        PINCTRL_PIN(6, "GPIO_06"),
        PINCTRL_PIN(7, "GPIO_07"),
        PINCTRL_PIN(8, "GPIO_08"),
        PINCTRL_PIN(9, "GPIO_09"),
        PINCTRL_PIN(10, "GPIO_10"),
        PINCTRL_PIN(11, "GPIO_11"),
        PINCTRL_PIN(12, "GPIO_12"),
        PINCTRL_PIN(13, "GPIO_13"),
        PINCTRL_PIN(14, "GPIO_14"),
        PINCTRL_PIN(15, "GPIO_15"),
        PINCTRL_PIN(16, "GPIO_16"),
        PINCTRL_PIN(17, "GPIO_17"),
        PINCTRL_PIN(18, "GPIO_18"),
        PINCTRL_PIN(19, "GPIO_19"),
        PINCTRL_PIN(20, "GPIO_20"),
        PINCTRL_PIN(21, "GPIO_21"),
        PINCTRL_PIN(22, "GPIO_22"),
        PINCTRL_PIN(23, "GPIO_23"),
        PINCTRL_PIN(24, "GPIO_24"),
        PINCTRL_PIN(25, "GPIO_25"),
        PINCTRL_PIN(26, "GPIO_26"),
        PINCTRL_PIN(27, "GPIO_27"),
        PINCTRL_PIN(28, "GPIO_28"),
        PINCTRL_PIN(29, "GPIO_29"),
        PINCTRL_PIN(30, "GPIO_30"),
        PINCTRL_PIN(31, "GPIO_31"),
        PINCTRL_PIN(32, "GPIO_32"),
        PINCTRL_PIN(33, "GPIO_33"),
        PINCTRL_PIN(34, "GPIO_34"),
        PINCTRL_PIN(35, "GPIO_35"),
        PINCTRL_PIN(36, "GPIO_36"),
        PINCTRL_PIN(37, "GPIO_37"),
        PINCTRL_PIN(38, "GPIO_38"),
        PINCTRL_PIN(39, "GPIO_39"),
        PINCTRL_PIN(40, "GPIO_40"),
        PINCTRL_PIN(41, "GPIO_41"),
        PINCTRL_PIN(42, "GPIO_42"),
        PINCTRL_PIN(43, "GPIO_43"),
        PINCTRL_PIN(44, "GPIO_44"),
        PINCTRL_PIN(45, "GPIO_45"),
        PINCTRL_PIN(46, "GPIO_46"),
        PINCTRL_PIN(47, "GPIO_47"),
        PINCTRL_PIN(48, "GPIO_48"),
        PINCTRL_PIN(49, "GPIO_49"),
        PINCTRL_PIN(50, "GPIO_50"),
        PINCTRL_PIN(51, "GPIO_51"),
        PINCTRL_PIN(52, "GPIO_52"),
        PINCTRL_PIN(53, "GPIO_53"),
        PINCTRL_PIN(54, "GPIO_54"),
        PINCTRL_PIN(55, "GPIO_55"),
        PINCTRL_PIN(56, "GPIO_56"),
        PINCTRL_PIN(57, "GPIO_57"),
        PINCTRL_PIN(58, "GPIO_58"),
        PINCTRL_PIN(59, "GPIO_59"),
        PINCTRL_PIN(60, "GPIO_60"),
        PINCTRL_PIN(61, "GPIO_61"),
        PINCTRL_PIN(62, "GPIO_62"),
        PINCTRL_PIN(63, "GPIO_63"),
        PINCTRL_PIN(64, "GPIO_64"),
        PINCTRL_PIN(65, "GPIO_65"),
        PINCTRL_PIN(66, "GPIO_66"),
        PINCTRL_PIN(67, "GPIO_67"),
        PINCTRL_PIN(68, "GPIO_68"),
        PINCTRL_PIN(69, "GPIO_69"),
        PINCTRL_PIN(70, "GPIO_70/PRI_TDI"),
        PINCTRL_PIN(71, "GPIO_71/PRI_TMS"),
        PINCTRL_PIN(72, "GPIO_72/PRI_TCK"),
        PINCTRL_PIN(73, "GPIO_73/PRI_TDO"),
        PINCTRL_PIN(74, "GPIO_74"),
        PINCTRL_PIN(75, "GPIO_75"),
        PINCTRL_PIN(76, "GPIO_76"),
        PINCTRL_PIN(77, "GPIO_77"),
        PINCTRL_PIN(78, "GPIO_78"),
        PINCTRL_PIN(79, "GPIO_79"),
        PINCTRL_PIN(80, "GPIO_80"),
        PINCTRL_PIN(81, "GPIO_81"),
        PINCTRL_PIN(82, "GPIO_82"),
        PINCTRL_PIN(83, "GPIO_83"),
        PINCTRL_PIN(84, "GPIO_84"),
        PINCTRL_PIN(85, "GPIO_85"),
        PINCTRL_PIN(86, "GPIO_86"),
        PINCTRL_PIN(87, "GPIO_87"),
        PINCTRL_PIN(88, "GPIO_88"),
        PINCTRL_PIN(89, "GPIO_89"),
        PINCTRL_PIN(90, "GPIO_90"),
        PINCTRL_PIN(91, "GPIO_91"),
        PINCTRL_PIN(92, "GPIO_92"),
        PINCTRL_PIN(93, "GPIO_93/PWR_SCL"),
        PINCTRL_PIN(94, "GPIO_94/PWR_SDA"),
        PINCTRL_PIN(95, "GPIO_95/VCX0_EN"),
        PINCTRL_PIN(96, "GPIO_96/DVL0"),
        PINCTRL_PIN(97, "GPIO_97/DVL1"),
        PINCTRL_PIN(98,  "GPIO_98/QSPI_DAT3"),
        PINCTRL_PIN(99,  "GPIO_99/QSPI_DAT2"),
        PINCTRL_PIN(100, "GPIO_100/QSPI_DAT1"),
        PINCTRL_PIN(101, "GPIO_101/QSPI_DAT0"),
        PINCTRL_PIN(102, "GPIO_102/QSPI_CLK"),
        PINCTRL_PIN(103, "GPIO_103/QSPI_CS1"),
        PINCTRL_PIN(104, "GPIO_104/MMC1_DAT3"),
        PINCTRL_PIN(105, "GPIO_105/MMC1_DAT2"),
        PINCTRL_PIN(106, "GPIO_106/MMC1_DAT1"),
        PINCTRL_PIN(107, "GPIO_107/MMC1_DAT0"),
        PINCTRL_PIN(108, "GPIO_108/MMC1_CMD"),
        PINCTRL_PIN(109, "GPIO_109/MMC1_CLK"),
        PINCTRL_PIN(110, "GPIO_110"),
        PINCTRL_PIN(111, "GPIO_111"),
        PINCTRL_PIN(112, "GPIO_112"),
        PINCTRL_PIN(113, "GPIO_113"),
        PINCTRL_PIN(114, "GPIO_114"),
        PINCTRL_PIN(115, "GPIO_115"),
        PINCTRL_PIN(116, "GPIO_116"),
        PINCTRL_PIN(117, "GPIO_117"),
        PINCTRL_PIN(118, "GPIO_118"),
        PINCTRL_PIN(119, "GPIO_119"),
        PINCTRL_PIN(120, "GPIO_120"),
        PINCTRL_PIN(121, "GPIO_121"),
        PINCTRL_PIN(122, "GPIO_122"),
        PINCTRL_PIN(123, "GPIO_123"),
        PINCTRL_PIN(124, "GPIO_124"),
        PINCTRL_PIN(125, "GPIO_125"),
        PINCTRL_PIN(126, "GPIO_126"),
        PINCTRL_PIN(127, "GPIO_127"),
};

static const struct spacemit_pin k1_pin_data[ARRAY_SIZE(k1_pin_desc)] = {
        K1_FUNC_PIN(0, 0, IO_TYPE_1V8),
        K1_FUNC_PIN(1, 0, IO_TYPE_1V8),
        K1_FUNC_PIN(2, 0, IO_TYPE_1V8),
        K1_FUNC_PIN(3, 0, IO_TYPE_1V8),
        K1_FUNC_PIN(4, 0, IO_TYPE_1V8),
        K1_FUNC_PIN(5, 0, IO_TYPE_1V8),
        K1_FUNC_PIN(6, 0, IO_TYPE_1V8),
        K1_FUNC_PIN(7, 0, IO_TYPE_1V8),
        K1_FUNC_PIN(8, 0, IO_TYPE_1V8),
        K1_FUNC_PIN(9, 0, IO_TYPE_1V8),
        K1_FUNC_PIN(10, 0, IO_TYPE_1V8),
        K1_FUNC_PIN(11, 0, IO_TYPE_1V8),
        K1_FUNC_PIN(12, 0, IO_TYPE_1V8),
        K1_FUNC_PIN(13, 0, IO_TYPE_1V8),
        K1_FUNC_PIN(14, 0, IO_TYPE_1V8),
        K1_FUNC_PIN(15, 0, IO_TYPE_1V8),
        K1_FUNC_PIN(16, 0, IO_TYPE_1V8),
        K1_FUNC_PIN(17, 0, IO_TYPE_1V8),
        K1_FUNC_PIN(18, 0, IO_TYPE_1V8),
        K1_FUNC_PIN(19, 0, IO_TYPE_1V8),
        K1_FUNC_PIN(20, 0, IO_TYPE_1V8),
        K1_FUNC_PIN(21, 0, IO_TYPE_1V8),
        K1_FUNC_PIN(22, 0, IO_TYPE_1V8),
        K1_FUNC_PIN(23, 0, IO_TYPE_1V8),
        K1_FUNC_PIN(24, 0, IO_TYPE_1V8),
        K1_FUNC_PIN(25, 0, IO_TYPE_1V8),
        K1_FUNC_PIN(26, 0, IO_TYPE_1V8),
        K1_FUNC_PIN(27, 0, IO_TYPE_1V8),
        K1_FUNC_PIN(28, 0, IO_TYPE_1V8),
        K1_FUNC_PIN(29, 0, IO_TYPE_1V8),
        K1_FUNC_PIN(30, 0, IO_TYPE_1V8),
        K1_FUNC_PIN(31, 0, IO_TYPE_1V8),
        K1_FUNC_PIN(32, 0, IO_TYPE_1V8),
        K1_FUNC_PIN(33, 0, IO_TYPE_1V8),
        K1_FUNC_PIN(34, 0, IO_TYPE_1V8),
        K1_FUNC_PIN(35, 0, IO_TYPE_1V8),
        K1_FUNC_PIN(36, 0, IO_TYPE_1V8),
        K1_FUNC_PIN(37, 0, IO_TYPE_1V8),
        K1_FUNC_PIN(38, 0, IO_TYPE_1V8),
        K1_FUNC_PIN(39, 0, IO_TYPE_1V8),
        K1_FUNC_PIN(40, 0, IO_TYPE_1V8),
        K1_FUNC_PIN(41, 0, IO_TYPE_1V8),
        K1_FUNC_PIN(42, 0, IO_TYPE_1V8),
        K1_FUNC_PIN(43, 0, IO_TYPE_1V8),
        K1_FUNC_PIN(44, 0, IO_TYPE_1V8),
        K1_FUNC_PIN(45, 0, IO_TYPE_1V8),
        K1_FUNC_PIN(46, 0, IO_TYPE_1V8),
        K1_FUNC_PIN(47, 0, IO_TYPE_EXTERNAL),
        K1_FUNC_PIN(48, 0, IO_TYPE_EXTERNAL),
        K1_FUNC_PIN(49, 0, IO_TYPE_EXTERNAL),
        K1_FUNC_PIN(50, 0, IO_TYPE_EXTERNAL),
        K1_FUNC_PIN(51, 0, IO_TYPE_EXTERNAL),
        K1_FUNC_PIN(52, 0, IO_TYPE_EXTERNAL),
        K1_FUNC_PIN(53, 0, IO_TYPE_1V8),
        K1_FUNC_PIN(54, 0, IO_TYPE_1V8),
        K1_FUNC_PIN(55, 0, IO_TYPE_1V8),
        K1_FUNC_PIN(56, 0, IO_TYPE_1V8),
        K1_FUNC_PIN(57, 0, IO_TYPE_1V8),
        K1_FUNC_PIN(58, 0, IO_TYPE_1V8),
        K1_FUNC_PIN(59, 0, IO_TYPE_1V8),
        K1_FUNC_PIN(60, 0, IO_TYPE_1V8),
        K1_FUNC_PIN(61, 0, IO_TYPE_1V8),
        K1_FUNC_PIN(62, 0, IO_TYPE_1V8),
        K1_FUNC_PIN(63, 0, IO_TYPE_1V8),
        K1_FUNC_PIN(64, 0, IO_TYPE_1V8),
        K1_FUNC_PIN(65, 0, IO_TYPE_1V8),
        K1_FUNC_PIN(66, 0, IO_TYPE_1V8),
        K1_FUNC_PIN(67, 0, IO_TYPE_1V8),
        K1_FUNC_PIN(68, 0, IO_TYPE_1V8),
        K1_FUNC_PIN(69, 0, IO_TYPE_1V8),
        K1_FUNC_PIN(70, 1, IO_TYPE_1V8),
        K1_FUNC_PIN(71, 1, IO_TYPE_1V8),
        K1_FUNC_PIN(72, 1, IO_TYPE_1V8),
        K1_FUNC_PIN(73, 1, IO_TYPE_1V8),
        K1_FUNC_PIN(74, 0, IO_TYPE_1V8),
        K1_FUNC_PIN(75, 0, IO_TYPE_EXTERNAL),
        K1_FUNC_PIN(76, 0, IO_TYPE_EXTERNAL),
        K1_FUNC_PIN(77, 0, IO_TYPE_EXTERNAL),
        K1_FUNC_PIN(78, 0, IO_TYPE_EXTERNAL),
        K1_FUNC_PIN(79, 0, IO_TYPE_EXTERNAL),
        K1_FUNC_PIN(80, 0, IO_TYPE_EXTERNAL),
        K1_FUNC_PIN(81, 0, IO_TYPE_1V8),
        K1_FUNC_PIN(82, 0, IO_TYPE_1V8),
        K1_FUNC_PIN(83, 0, IO_TYPE_1V8),
        K1_FUNC_PIN(84, 0, IO_TYPE_1V8),
        K1_FUNC_PIN(85, 0, IO_TYPE_1V8),
        K1_FUNC_PIN(86, 0, IO_TYPE_1V8),
        K1_FUNC_PIN(87, 0, IO_TYPE_1V8),
        K1_FUNC_PIN(88, 0, IO_TYPE_1V8),
        K1_FUNC_PIN(89, 0, IO_TYPE_1V8),
        K1_FUNC_PIN(90, 0, IO_TYPE_1V8),
        K1_FUNC_PIN(91, 0, IO_TYPE_1V8),
        K1_FUNC_PIN(92, 0, IO_TYPE_1V8),
        K1_FUNC_PIN(93, 1, IO_TYPE_1V8),
        K1_FUNC_PIN(94, 1, IO_TYPE_1V8),
        K1_FUNC_PIN(95, 1, IO_TYPE_1V8),
        K1_FUNC_PIN(96, 1, IO_TYPE_1V8),
        K1_FUNC_PIN(97, 1, IO_TYPE_1V8),
        K1_FUNC_PIN(98, 1, IO_TYPE_EXTERNAL),
        K1_FUNC_PIN(99, 1, IO_TYPE_EXTERNAL),
        K1_FUNC_PIN(100, 1, IO_TYPE_EXTERNAL),
        K1_FUNC_PIN(101, 1, IO_TYPE_EXTERNAL),
        K1_FUNC_PIN(102, 1, IO_TYPE_EXTERNAL),
        K1_FUNC_PIN(103, 1, IO_TYPE_EXTERNAL),
        K1_FUNC_PIN(104, 4, IO_TYPE_EXTERNAL),
        K1_FUNC_PIN(105, 4, IO_TYPE_EXTERNAL),
        K1_FUNC_PIN(106, 4, IO_TYPE_EXTERNAL),
        K1_FUNC_PIN(107, 4, IO_TYPE_EXTERNAL),
        K1_FUNC_PIN(108, 4, IO_TYPE_EXTERNAL),
        K1_FUNC_PIN(109, 4, IO_TYPE_EXTERNAL),
        K1_FUNC_PIN(110, 0, IO_TYPE_1V8),
        K1_FUNC_PIN(111, 0, IO_TYPE_1V8),
        K1_FUNC_PIN(112, 0, IO_TYPE_1V8),
        K1_FUNC_PIN(113, 0, IO_TYPE_1V8),
        K1_FUNC_PIN(114, 0, IO_TYPE_1V8),
        K1_FUNC_PIN(115, 0, IO_TYPE_1V8),
        K1_FUNC_PIN(116, 0, IO_TYPE_1V8),
        K1_FUNC_PIN(117, 0, IO_TYPE_1V8),
        K1_FUNC_PIN(118, 0, IO_TYPE_1V8),
        K1_FUNC_PIN(119, 0, IO_TYPE_1V8),
        K1_FUNC_PIN(120, 0, IO_TYPE_1V8),
        K1_FUNC_PIN(121, 0, IO_TYPE_1V8),
        K1_FUNC_PIN(122, 0, IO_TYPE_1V8),
        K1_FUNC_PIN(123, 0, IO_TYPE_1V8),
        K1_FUNC_PIN(124, 0, IO_TYPE_1V8),
        K1_FUNC_PIN(125, 0, IO_TYPE_1V8),
        K1_FUNC_PIN(126, 0, IO_TYPE_1V8),
        K1_FUNC_PIN(127, 0, IO_TYPE_1V8),
};

static const struct spacemit_pinctrl_data k1_pinctrl_data = {
        .pins = k1_pin_desc,
        .data = k1_pin_data,
        .npins = ARRAY_SIZE(k1_pin_desc),
        .pin_to_offset = spacemit_k1_pin_to_offset,
        .pin_to_io_pd_offset = spacemit_k1_pin_to_io_pd_offset,
        .dconf = &k1_drive_conf,
};

static const struct pinctrl_pin_desc k3_pin_desc[] = {
        PINCTRL_PIN(0, "GPIO_00"),
        PINCTRL_PIN(1, "GPIO_01"),
        PINCTRL_PIN(2, "GPIO_02"),
        PINCTRL_PIN(3, "GPIO_03"),
        PINCTRL_PIN(4, "GPIO_04"),
        PINCTRL_PIN(5, "GPIO_05"),
        PINCTRL_PIN(6, "GPIO_06"),
        PINCTRL_PIN(7, "GPIO_07"),
        PINCTRL_PIN(8, "GPIO_08"),
        PINCTRL_PIN(9, "GPIO_09"),
        PINCTRL_PIN(10, "GPIO_10"),
        PINCTRL_PIN(11, "GPIO_11"),
        PINCTRL_PIN(12, "GPIO_12"),
        PINCTRL_PIN(13, "GPIO_13"),
        PINCTRL_PIN(14, "GPIO_14"),
        PINCTRL_PIN(15, "GPIO_15"),
        PINCTRL_PIN(16, "GPIO_16"),
        PINCTRL_PIN(17, "GPIO_17"),
        PINCTRL_PIN(18, "GPIO_18"),
        PINCTRL_PIN(19, "GPIO_19"),
        PINCTRL_PIN(20, "GPIO_20"),
        PINCTRL_PIN(21, "GPIO_21"),
        PINCTRL_PIN(22, "GPIO_22"),
        PINCTRL_PIN(23, "GPIO_23"),
        PINCTRL_PIN(24, "GPIO_24"),
        PINCTRL_PIN(25, "GPIO_25"),
        PINCTRL_PIN(26, "GPIO_26"),
        PINCTRL_PIN(27, "GPIO_27"),
        PINCTRL_PIN(28, "GPIO_28"),
        PINCTRL_PIN(29, "GPIO_29"),
        PINCTRL_PIN(30, "GPIO_30"),
        PINCTRL_PIN(31, "GPIO_31"),
        PINCTRL_PIN(32, "GPIO_32"),
        PINCTRL_PIN(33, "GPIO_33"),
        PINCTRL_PIN(34, "GPIO_34"),
        PINCTRL_PIN(35, "GPIO_35"),
        PINCTRL_PIN(36, "GPIO_36"),
        PINCTRL_PIN(37, "GPIO_37"),
        PINCTRL_PIN(38, "GPIO_38"),
        PINCTRL_PIN(39, "GPIO_39"),
        PINCTRL_PIN(40, "GPIO_40"),
        PINCTRL_PIN(41, "GPIO_41"),
        PINCTRL_PIN(42, "GPIO_42"),
        PINCTRL_PIN(43, "GPIO_43"),
        PINCTRL_PIN(44, "GPIO_44"),
        PINCTRL_PIN(45, "GPIO_45"),
        PINCTRL_PIN(46, "GPIO_46"),
        PINCTRL_PIN(47, "GPIO_47"),
        PINCTRL_PIN(48, "GPIO_48"),
        PINCTRL_PIN(49, "GPIO_49"),
        PINCTRL_PIN(50, "GPIO_50"),
        PINCTRL_PIN(51, "GPIO_51"),
        PINCTRL_PIN(52, "GPIO_52"),
        PINCTRL_PIN(53, "GPIO_53"),
        PINCTRL_PIN(54, "GPIO_54"),
        PINCTRL_PIN(55, "GPIO_55"),
        PINCTRL_PIN(56, "GPIO_56"),
        PINCTRL_PIN(57, "GPIO_57"),
        PINCTRL_PIN(58, "GPIO_58"),
        PINCTRL_PIN(59, "GPIO_59"),
        PINCTRL_PIN(60, "GPIO_60"),
        PINCTRL_PIN(61, "GPIO_61"),
        PINCTRL_PIN(62, "GPIO_62"),
        PINCTRL_PIN(63, "GPIO_63"),
        PINCTRL_PIN(64, "GPIO_64"),
        PINCTRL_PIN(65, "GPIO_65"),
        PINCTRL_PIN(66, "GPIO_66"),
        PINCTRL_PIN(67, "GPIO_67"),
        PINCTRL_PIN(68, "GPIO_68"),
        PINCTRL_PIN(69, "GPIO_69"),
        PINCTRL_PIN(70, "GPIO_70"),
        PINCTRL_PIN(71, "GPIO_71"),
        PINCTRL_PIN(72, "GPIO_72"),
        PINCTRL_PIN(73, "GPIO_73"),
        PINCTRL_PIN(74, "GPIO_74"),
        PINCTRL_PIN(75, "GPIO_75"),
        PINCTRL_PIN(76, "GPIO_76"),
        PINCTRL_PIN(77, "GPIO_77"),
        PINCTRL_PIN(78, "GPIO_78"),
        PINCTRL_PIN(79, "GPIO_79"),
        PINCTRL_PIN(80, "GPIO_80"),
        PINCTRL_PIN(81, "GPIO_81"),
        PINCTRL_PIN(82, "GPIO_82"),
        PINCTRL_PIN(83, "GPIO_83"),
        PINCTRL_PIN(84, "GPIO_84"),
        PINCTRL_PIN(85, "GPIO_85"),
        PINCTRL_PIN(86, "GPIO_86"),
        PINCTRL_PIN(87, "GPIO_87"),
        PINCTRL_PIN(88, "GPIO_88"),
        PINCTRL_PIN(89, "GPIO_89"),
        PINCTRL_PIN(90, "GPIO_90"),
        PINCTRL_PIN(91, "GPIO_91"),
        PINCTRL_PIN(92, "GPIO_92"),
        PINCTRL_PIN(93, "GPIO_93"),
        PINCTRL_PIN(94, "GPIO_94"),
        PINCTRL_PIN(95, "GPIO_95"),
        PINCTRL_PIN(96, "GPIO_96"),
        PINCTRL_PIN(97, "GPIO_97"),
        PINCTRL_PIN(98,  "GPIO_98"),
        PINCTRL_PIN(99,  "GPIO_99"),
        PINCTRL_PIN(100, "GPIO_100"),
        PINCTRL_PIN(101, "GPIO_101"),
        PINCTRL_PIN(102, "GPIO_102"),
        PINCTRL_PIN(103, "GPIO_103"),
        PINCTRL_PIN(104, "GPIO_104"),
        PINCTRL_PIN(105, "GPIO_105"),
        PINCTRL_PIN(106, "GPIO_106"),
        PINCTRL_PIN(107, "GPIO_107"),
        PINCTRL_PIN(108, "GPIO_108"),
        PINCTRL_PIN(109, "GPIO_109"),
        PINCTRL_PIN(110, "GPIO_110"),
        PINCTRL_PIN(111, "GPIO_111"),
        PINCTRL_PIN(112, "GPIO_112"),
        PINCTRL_PIN(113, "GPIO_113"),
        PINCTRL_PIN(114, "GPIO_114"),
        PINCTRL_PIN(115, "GPIO_115"),
        PINCTRL_PIN(116, "GPIO_116"),
        PINCTRL_PIN(117, "GPIO_117"),
        PINCTRL_PIN(118, "GPIO_118"),
        PINCTRL_PIN(119, "GPIO_119"),
        PINCTRL_PIN(120, "GPIO_120"),
        PINCTRL_PIN(121, "GPIO_121"),
        PINCTRL_PIN(122, "GPIO_122"),
        PINCTRL_PIN(123, "GPIO_123"),
        PINCTRL_PIN(124, "GPIO_124"),
        PINCTRL_PIN(125, "GPIO_125"),
        PINCTRL_PIN(126, "GPIO_126"),
        PINCTRL_PIN(127, "GPIO_127"),
        PINCTRL_PIN(128, "PWR_SCL"),
        PINCTRL_PIN(129, "PWR_SDA"),
        PINCTRL_PIN(130, "VCXO_EN"),
        PINCTRL_PIN(131, "PMIC_INT_N"),
        PINCTRL_PIN(132, "MMC1_DAT3"),
        PINCTRL_PIN(133, "MMC1_DAT2"),
        PINCTRL_PIN(134, "MMC1_DAT1"),
        PINCTRL_PIN(135, "MMC1_DAT0"),
        PINCTRL_PIN(136, "MMC1_CMD"),
        PINCTRL_PIN(137, "MMC1_CLK"),
        PINCTRL_PIN(138, "QSPI_DAT0"),
        PINCTRL_PIN(139, "QSPI_DAT1"),
        PINCTRL_PIN(140, "QSPI_DAT2"),
        PINCTRL_PIN(141, "QSPI_DAT3"),
        PINCTRL_PIN(142, "QSPI_CS0"),
        PINCTRL_PIN(143, "QSPI_CS1"),
        PINCTRL_PIN(144, "QSPI_CLK"),
        PINCTRL_PIN(145, "PRI_TDI"),
        PINCTRL_PIN(146, "PRI_TMS"),
        PINCTRL_PIN(147, "PRI_TCK"),
        PINCTRL_PIN(148, "PRI_TDO"),
        PINCTRL_PIN(149, "PWR_SSP_SCLK"),
        PINCTRL_PIN(150, "PWR_SSP_FRM"),
        PINCTRL_PIN(151, "PWR_SSP_TXD"),
        PINCTRL_PIN(152, "PWR_SSP_RXD"),
};

static const struct spacemit_pin k3_pin_data[ARRAY_SIZE(k3_pin_desc)] = {
        /* GPIO1 bank */
        K1_FUNC_PIN(0, 0, IO_TYPE_EXTERNAL),
        K1_FUNC_PIN(1, 0, IO_TYPE_EXTERNAL),
        K1_FUNC_PIN(2, 0, IO_TYPE_EXTERNAL),
        K1_FUNC_PIN(3, 0, IO_TYPE_EXTERNAL),
        K1_FUNC_PIN(4, 0, IO_TYPE_EXTERNAL),
        K1_FUNC_PIN(5, 0, IO_TYPE_EXTERNAL),
        K1_FUNC_PIN(6, 0, IO_TYPE_EXTERNAL),
        K1_FUNC_PIN(7, 0, IO_TYPE_EXTERNAL),
        K1_FUNC_PIN(8, 0, IO_TYPE_EXTERNAL),
        K1_FUNC_PIN(9, 0, IO_TYPE_EXTERNAL),
        K1_FUNC_PIN(10, 0, IO_TYPE_EXTERNAL),
        K1_FUNC_PIN(11, 0, IO_TYPE_EXTERNAL),
        K1_FUNC_PIN(12, 0, IO_TYPE_EXTERNAL),
        K1_FUNC_PIN(13, 0, IO_TYPE_EXTERNAL),
        K1_FUNC_PIN(14, 0, IO_TYPE_EXTERNAL),
        K1_FUNC_PIN(15, 0, IO_TYPE_EXTERNAL),
        K1_FUNC_PIN(16, 0, IO_TYPE_EXTERNAL),
        K1_FUNC_PIN(17, 0, IO_TYPE_EXTERNAL),
        K1_FUNC_PIN(18, 0, IO_TYPE_EXTERNAL),
        K1_FUNC_PIN(19, 0, IO_TYPE_EXTERNAL),
        K1_FUNC_PIN(20, 0, IO_TYPE_EXTERNAL),

        /* GPIO2 bank */
        K1_FUNC_PIN(21, 0, IO_TYPE_EXTERNAL),
        K1_FUNC_PIN(22, 0, IO_TYPE_EXTERNAL),
        K1_FUNC_PIN(23, 0, IO_TYPE_EXTERNAL),
        K1_FUNC_PIN(24, 0, IO_TYPE_EXTERNAL),
        K1_FUNC_PIN(25, 0, IO_TYPE_EXTERNAL),
        K1_FUNC_PIN(26, 0, IO_TYPE_EXTERNAL),
        K1_FUNC_PIN(27, 0, IO_TYPE_EXTERNAL),
        K1_FUNC_PIN(28, 0, IO_TYPE_EXTERNAL),
        K1_FUNC_PIN(29, 0, IO_TYPE_EXTERNAL),
        K1_FUNC_PIN(30, 0, IO_TYPE_EXTERNAL),
        K1_FUNC_PIN(31, 0, IO_TYPE_EXTERNAL),
        K1_FUNC_PIN(32, 0, IO_TYPE_EXTERNAL),
        K1_FUNC_PIN(33, 0, IO_TYPE_EXTERNAL),
        K1_FUNC_PIN(34, 0, IO_TYPE_EXTERNAL),
        K1_FUNC_PIN(35, 0, IO_TYPE_EXTERNAL),
        K1_FUNC_PIN(36, 0, IO_TYPE_EXTERNAL),
        K1_FUNC_PIN(37, 0, IO_TYPE_EXTERNAL),
        K1_FUNC_PIN(38, 0, IO_TYPE_EXTERNAL),
        K1_FUNC_PIN(39, 0, IO_TYPE_EXTERNAL),
        K1_FUNC_PIN(40, 0, IO_TYPE_EXTERNAL),
        K1_FUNC_PIN(41, 0, IO_TYPE_EXTERNAL),

        /* GPIO3 bank */
        K1_FUNC_PIN(42, 0, IO_TYPE_1V8),
        K1_FUNC_PIN(43, 0, IO_TYPE_1V8),
        K1_FUNC_PIN(44, 0, IO_TYPE_1V8),
        K1_FUNC_PIN(45, 0, IO_TYPE_1V8),
        K1_FUNC_PIN(46, 0, IO_TYPE_1V8),
        K1_FUNC_PIN(47, 0, IO_TYPE_1V8),
        K1_FUNC_PIN(48, 0, IO_TYPE_1V8),
        K1_FUNC_PIN(49, 0, IO_TYPE_1V8),
        K1_FUNC_PIN(50, 0, IO_TYPE_1V8),
        K1_FUNC_PIN(51, 0, IO_TYPE_1V8),
        K1_FUNC_PIN(52, 0, IO_TYPE_1V8),
        K1_FUNC_PIN(53, 0, IO_TYPE_1V8),
        K1_FUNC_PIN(54, 0, IO_TYPE_1V8),
        K1_FUNC_PIN(55, 0, IO_TYPE_1V8),
        K1_FUNC_PIN(56, 0, IO_TYPE_1V8),
        K1_FUNC_PIN(57, 0, IO_TYPE_1V8),
        K1_FUNC_PIN(58, 0, IO_TYPE_1V8),
        K1_FUNC_PIN(59, 0, IO_TYPE_1V8),
        K1_FUNC_PIN(60, 0, IO_TYPE_1V8),
        K1_FUNC_PIN(61, 0, IO_TYPE_1V8),
        K1_FUNC_PIN(62, 0, IO_TYPE_1V8),
        K1_FUNC_PIN(63, 0, IO_TYPE_1V8),
        K1_FUNC_PIN(64, 0, IO_TYPE_1V8),
        K1_FUNC_PIN(65, 0, IO_TYPE_1V8),
        K1_FUNC_PIN(66, 0, IO_TYPE_1V8),
        K1_FUNC_PIN(67, 0, IO_TYPE_1V8),
        K1_FUNC_PIN(68, 0, IO_TYPE_1V8),
        K1_FUNC_PIN(69, 0, IO_TYPE_1V8),
        K1_FUNC_PIN(70, 0, IO_TYPE_1V8),
        K1_FUNC_PIN(71, 0, IO_TYPE_1V8),
        K1_FUNC_PIN(72, 0, IO_TYPE_1V8),
        K1_FUNC_PIN(73, 0, IO_TYPE_1V8),
        K1_FUNC_PIN(74, 0, IO_TYPE_1V8),
        K1_FUNC_PIN(75, 0, IO_TYPE_1V8),

        /* GPIO4 bank */
        K1_FUNC_PIN(76, 0, IO_TYPE_EXTERNAL),
        K1_FUNC_PIN(77, 0, IO_TYPE_EXTERNAL),
        K1_FUNC_PIN(78, 0, IO_TYPE_EXTERNAL),
        K1_FUNC_PIN(79, 0, IO_TYPE_EXTERNAL),
        K1_FUNC_PIN(80, 0, IO_TYPE_EXTERNAL),
        K1_FUNC_PIN(81, 0, IO_TYPE_EXTERNAL),
        K1_FUNC_PIN(82, 0, IO_TYPE_EXTERNAL),
        K1_FUNC_PIN(83, 0, IO_TYPE_EXTERNAL),
        K1_FUNC_PIN(84, 0, IO_TYPE_EXTERNAL),
        K1_FUNC_PIN(85, 0, IO_TYPE_EXTERNAL),
        K1_FUNC_PIN(86, 0, IO_TYPE_EXTERNAL),
        K1_FUNC_PIN(87, 0, IO_TYPE_EXTERNAL),
        K1_FUNC_PIN(88, 0, IO_TYPE_EXTERNAL),
        K1_FUNC_PIN(89, 0, IO_TYPE_EXTERNAL),
        K1_FUNC_PIN(90, 0, IO_TYPE_EXTERNAL),
        K1_FUNC_PIN(91, 0, IO_TYPE_EXTERNAL),
        K1_FUNC_PIN(92, 0, IO_TYPE_EXTERNAL),
        K1_FUNC_PIN(93, 0, IO_TYPE_EXTERNAL),
        K1_FUNC_PIN(94, 0, IO_TYPE_EXTERNAL),
        K1_FUNC_PIN(95, 0, IO_TYPE_EXTERNAL),
        K1_FUNC_PIN(96, 0, IO_TYPE_EXTERNAL),
        K1_FUNC_PIN(97, 0, IO_TYPE_EXTERNAL),
        K1_FUNC_PIN(98, 0, IO_TYPE_EXTERNAL),

        /* GPIO5 bank */
        K1_FUNC_PIN(99, 0, IO_TYPE_EXTERNAL),
        K1_FUNC_PIN(100, 0, IO_TYPE_EXTERNAL),
        K1_FUNC_PIN(101, 0, IO_TYPE_EXTERNAL),
        K1_FUNC_PIN(102, 0, IO_TYPE_EXTERNAL),
        K1_FUNC_PIN(103, 0, IO_TYPE_EXTERNAL),
        K1_FUNC_PIN(104, 0, IO_TYPE_EXTERNAL),
        K1_FUNC_PIN(105, 0, IO_TYPE_EXTERNAL),
        K1_FUNC_PIN(106, 0, IO_TYPE_EXTERNAL),
        K1_FUNC_PIN(107, 0, IO_TYPE_EXTERNAL),
        K1_FUNC_PIN(108, 0, IO_TYPE_EXTERNAL),
        K1_FUNC_PIN(109, 0, IO_TYPE_EXTERNAL),
        K1_FUNC_PIN(110, 0, IO_TYPE_EXTERNAL),
        K1_FUNC_PIN(111, 0, IO_TYPE_EXTERNAL),
        K1_FUNC_PIN(112, 0, IO_TYPE_EXTERNAL),
        K1_FUNC_PIN(113, 0, IO_TYPE_EXTERNAL),
        K1_FUNC_PIN(114, 0, IO_TYPE_EXTERNAL),
        K1_FUNC_PIN(115, 0, IO_TYPE_EXTERNAL),
        K1_FUNC_PIN(116, 0, IO_TYPE_EXTERNAL),
        K1_FUNC_PIN(117, 0, IO_TYPE_EXTERNAL),
        K1_FUNC_PIN(118, 0, IO_TYPE_EXTERNAL),
        K1_FUNC_PIN(119, 0, IO_TYPE_EXTERNAL),
        K1_FUNC_PIN(120, 0, IO_TYPE_EXTERNAL),
        K1_FUNC_PIN(121, 0, IO_TYPE_EXTERNAL),
        K1_FUNC_PIN(122, 0, IO_TYPE_EXTERNAL),
        K1_FUNC_PIN(123, 0, IO_TYPE_EXTERNAL),
        K1_FUNC_PIN(124, 0, IO_TYPE_EXTERNAL),
        K1_FUNC_PIN(125, 0, IO_TYPE_EXTERNAL),
        K1_FUNC_PIN(126, 0, IO_TYPE_EXTERNAL),
        K1_FUNC_PIN(127, 0, IO_TYPE_EXTERNAL),

        /* PMIC */
        K1_FUNC_PIN(128, 0, IO_TYPE_1V8),
        K1_FUNC_PIN(129, 0, IO_TYPE_1V8),
        K1_FUNC_PIN(130, 0, IO_TYPE_1V8),
        K1_FUNC_PIN(131, 0, IO_TYPE_1V8),

        /* SD/MMC1 */
        K1_FUNC_PIN(132, 1, IO_TYPE_EXTERNAL),
        K1_FUNC_PIN(133, 1, IO_TYPE_EXTERNAL),
        K1_FUNC_PIN(134, 1, IO_TYPE_EXTERNAL),
        K1_FUNC_PIN(135, 1, IO_TYPE_EXTERNAL),
        K1_FUNC_PIN(136, 1, IO_TYPE_EXTERNAL),
        K1_FUNC_PIN(137, 1, IO_TYPE_EXTERNAL),

        /* QSPI */
        K1_FUNC_PIN(138, 1, IO_TYPE_EXTERNAL),
        K1_FUNC_PIN(139, 1, IO_TYPE_EXTERNAL),
        K1_FUNC_PIN(140, 1, IO_TYPE_EXTERNAL),
        K1_FUNC_PIN(141, 1, IO_TYPE_EXTERNAL),
        K1_FUNC_PIN(142, 1, IO_TYPE_EXTERNAL),
        K1_FUNC_PIN(143, 1, IO_TYPE_EXTERNAL),
        K1_FUNC_PIN(144, 1, IO_TYPE_EXTERNAL),

        /* PMIC */
        K1_FUNC_PIN(145, 1, IO_TYPE_1V8),
        K1_FUNC_PIN(146, 1, IO_TYPE_1V8),
        K1_FUNC_PIN(147, 1, IO_TYPE_1V8),
        K1_FUNC_PIN(148, 1, IO_TYPE_1V8),
        K1_FUNC_PIN(149, 1, IO_TYPE_1V8),
        K1_FUNC_PIN(150, 1, IO_TYPE_1V8),
        K1_FUNC_PIN(151, 1, IO_TYPE_1V8),
        K1_FUNC_PIN(152, 1, IO_TYPE_1V8),
};

static const struct spacemit_pinctrl_data k3_pinctrl_data = {
        .pins = k3_pin_desc,
        .data = k3_pin_data,
        .npins = ARRAY_SIZE(k3_pin_desc),
        .pin_to_offset = spacemit_k3_pin_to_offset,
        .pin_to_io_pd_offset = spacemit_k3_pin_to_io_pd_offset,
        .dconf = &k3_drive_conf,
};

static const struct of_device_id k1_pinctrl_ids[] = {
        { .compatible = "spacemit,k1-pinctrl", .data = &k1_pinctrl_data },
        { .compatible = "spacemit,k3-pinctrl", .data = &k3_pinctrl_data },
        { /* sentinel */ }
};
MODULE_DEVICE_TABLE(of, k1_pinctrl_ids);

static struct platform_driver k1_pinctrl_driver = {
        .probe  = spacemit_pinctrl_probe,
        .driver = {
                .name                   = "k1-pinctrl",
                .suppress_bind_attrs    = true,
                .of_match_table         = k1_pinctrl_ids,
        },
};
builtin_platform_driver(k1_pinctrl_driver);

MODULE_AUTHOR("Yixun Lan <dlan@gentoo.org>");
MODULE_DESCRIPTION("Pinctrl driver for the SpacemiT K1/K3 SoC");
MODULE_LICENSE("GPL");