pinctrl: Add SpacemiT K1-X pinctrl drivers 36/316536/1
authorMichal Wilczynski <m.wilczynski@samsung.com>
Thu, 22 Aug 2024 07:39:33 +0000 (09:39 +0200)
committerMichal Wilczynski <m.wilczynski@samsung.com>
Thu, 22 Aug 2024 11:53:38 +0000 (13:53 +0200)
Add custom SpacemiT K1-X pinctrl drivers. Ported from the vendor kernel [1].

[1] - https://github.com/BPI-SINOVOIP/pi-linux.git

Change-Id: Ie7537d93bca98ce0ffcf366d49b1dc4fee490cd1
Signed-off-by: Michal Wilczynski <m.wilczynski@samsung.com>
drivers/pinctrl/Kconfig
drivers/pinctrl/Makefile
drivers/pinctrl/spacemit-pmic-pinctrl.c [new file with mode: 0644]
drivers/pinctrl/spacemit/Kconfig [new file with mode: 0755]
drivers/pinctrl/spacemit/Makefile [new file with mode: 0755]
drivers/pinctrl/spacemit/pinctrl-spacemit.c [new file with mode: 0755]
drivers/pinctrl/spacemit/pinctrl-spacemit.h [new file with mode: 0755]
include/dt-bindings/pinctrl/k1-x-pinctrl.h [new file with mode: 0644]

index 7dfb7190580efaa47bcc8a68f73a642e23270f6f..95282fa1aeafbbfcc7d5d91ff7a18efe4fb4bfd7 100644 (file)
@@ -403,6 +403,17 @@ config PINCTRL_RK805
        help
          This selects the pinctrl driver for RK805.
 
+config PINCTRL_SPACEMIT_PMIC
+       tristate "Pinctrl and GPIO driver for Spacemit PMIC"
+       depends on MFD_SPACEMIT_PMIC
+       select GPIOLIB
+       select PINMUX
+       select GENERIC_PINCTRL_GROUPS
+       select GENERIC_PINMUX_FUNCTIONS
+       select GENERIC_PINCONF
+       help
+         This selects the pinctrl driver for spacemit pmic.
+
 config PINCTRL_ROCKCHIP
        tristate "Rockchip gpio and pinctrl driver"
        depends on ARCH_ROCKCHIP || COMPILE_TEST
@@ -533,5 +544,6 @@ source "drivers/pinctrl/ti/Kconfig"
 source "drivers/pinctrl/uniphier/Kconfig"
 source "drivers/pinctrl/visconti/Kconfig"
 source "drivers/pinctrl/vt8500/Kconfig"
+source "drivers/pinctrl/spacemit/Kconfig"
 
 endif
index dd6cda27029492812122d2712336237cebc234f3..7394096d2b7eab72ea00ca098b5b7dbe144f8683 100644 (file)
@@ -79,3 +79,5 @@ obj-y                         += ti/
 obj-$(CONFIG_PINCTRL_UNIPHIER) += uniphier/
 obj-$(CONFIG_PINCTRL_VISCONTI) += visconti/
 obj-$(CONFIG_ARCH_VT8500)      += vt8500/
+obj-$(CONFIG_ARCH_SPACEMIT)      += spacemit/
+obj-$(CONFIG_PINCTRL_SPACEMIT_PMIC)    += spacemit-pmic-pinctrl.o
\ No newline at end of file
diff --git a/drivers/pinctrl/spacemit-pmic-pinctrl.c b/drivers/pinctrl/spacemit-pmic-pinctrl.c
new file mode 100644 (file)
index 0000000..2758936
--- /dev/null
@@ -0,0 +1,403 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Pinctrl driver for Spacemit PMIC
+ *
+ * Copyright (c) 2023, SPACEMIT Co., Ltd
+ *
+ */
+
+#include <linux/pinctrl/consumer.h>
+#include <linux/pinctrl/machine.h>
+#include <linux/pinctrl/pinctrl.h>
+#include <linux/pinctrl/pinconf-generic.h>
+#include <linux/pinctrl/pinconf.h>
+#include <linux/pinctrl/pinmux.h>
+#include <linux/gpio/driver.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/pm.h>
+#include <linux/property.h>
+#include <linux/regmap.h>
+#include <linux/slab.h>
+#include <linux/mfd/spacemit/spacemit_pmic.h>
+
+#include "core.h"
+#include "pinctrl-utils.h"
+#include "pinmux.h"
+
+SPM8821_PINMUX_DESC;
+SPM8821_PINFUNC_DESC;
+SPM8821_PIN_CINFIG_DESC;
+SPM8821_PINCTRL_MATCH_DATA;
+
+struct spacemit_pctl {
+       struct gpio_chip        chip;
+       struct regmap           *regmap;
+       struct pinctrl_dev      *pctldev;
+       struct device           *dev;
+       struct pinctrl_desc pinctrl_desc;
+       int funcdesc_nums, confdesc_nums;
+       const struct pin_func_desc *func_desc;
+       const struct pin_config_desc *config_desc;
+       const char *name;
+};
+
+static const struct pinctrl_ops spacemit_gpio_pinctrl_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,
+       .dt_node_to_map = pinconf_generic_dt_node_to_map_group,
+       .dt_free_map = pinconf_generic_dt_free_map,
+};
+
+static int spacemit_gpio_pinmux_set(struct pinctrl_dev *pctldev,
+                             unsigned int function, unsigned int group)
+{
+       int i, ret;
+       struct spacemit_pctl *pctl = pinctrl_dev_get_drvdata(pctldev);
+       const char *funcname = pinmux_generic_get_function_name(pctldev, function);
+
+       /* get the target desc */
+       for (i = 0; i < pctl->funcdesc_nums; ++i) {
+               if (strcmp(funcname, pctl->func_desc[i].name) == 0 && group ==
+                               pctl->func_desc[i].pin_id) {
+                       /* set the first */
+                       ret = regmap_update_bits(pctl->regmap,
+                                       pctl->func_desc[i].func_reg,
+                                       pctl->func_desc[i].func_mask,
+                                       pctl->func_desc[i].en_val
+                                       << (ffs(pctl->func_desc[i].func_mask) - 1));
+                       if (ret) {
+                               dev_err(pctl->dev, "set PIN%d, function:%s, failed\n", group, funcname);
+                               return ret;
+                       }
+
+                       /* set the next if it have */
+                       if (pctl->func_desc[i].ha_sub) {
+                               ret = regmap_update_bits(pctl->regmap,
+                                       pctl->func_desc[i].sub_reg,
+                                       pctl->func_desc[i].sub_mask,
+                                       pctl->func_desc[i].sube_val
+                                       << (ffs(pctl->func_desc[i].sub_mask) - 1));
+                               if (ret) {
+                                       dev_err(pctl->dev, "set PIN%d, function:%s, failed\n", group, funcname);
+                                       return ret;
+                               }
+                       }
+
+                       break;
+               }
+       }
+
+       if (i >= pctl->funcdesc_nums) {
+               dev_err(pctl->dev, "Unsupported PIN%d, function:%s\n", group, funcname);
+               return -EINVAL;
+       }
+
+       return 0;
+}
+
+static int spacemit_pmx_gpio_set_direction(struct pinctrl_dev *pctldev,
+                                        struct pinctrl_gpio_range *range,
+                                        unsigned int offset, bool input)
+{
+       int ret;
+       struct spacemit_pctl *pctl = pinctrl_dev_get_drvdata(pctldev);
+
+       if (strcmp(pctl->name, "spm8821") == 0)
+               /* when input == true, it means that we should set this pin
+                * as gpioin, so we should pass function(0) to set_mux
+                */
+               ret = spacemit_gpio_pinmux_set(pctldev, !input, offset);
+       else
+               return -EINVAL;
+
+       return ret;
+}
+
+static const struct pinmux_ops spacemit_gpio_pinmux_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_gpio_pinmux_set,
+       .gpio_set_direction = spacemit_pmx_gpio_set_direction,
+       .strict = true,
+};
+
+static int spacemit_gpio_get(struct gpio_chip *chip, unsigned int offset)
+{
+       int ret;
+       unsigned int val;
+       struct spacemit_pctl *pctl = gpiochip_get_data(chip);
+
+       ret = regmap_read(pctl->regmap, pctl->config_desc[offset].input.reg, &val);
+       if (ret) {
+               dev_err(pctl->dev, "get PIN%d, direction failed\n", offset);
+               return ret;
+       }
+
+       val = val & pctl->config_desc[offset].input.msk;
+       val >>= ffs(pctl->config_desc[offset].input.msk) - 1;
+
+       return val;
+}
+
+static int spacemit_gpio_get_direction(struct gpio_chip *chip,
+                                    unsigned int offset)
+{
+       int i, ret;
+       unsigned int val, direction = 0;
+       struct spacemit_pctl *pctl = gpiochip_get_data(chip);
+
+       /* read the function set register */
+       for (i = 0; i < pctl->funcdesc_nums; ++i) {
+               if (offset == pctl->func_desc[i].pin_id) {
+                       ret = regmap_read(pctl->regmap, pctl->func_desc[i].func_reg, &val);
+                       if (ret) {
+                               dev_err(pctl->dev, "get PIN%d, direction failed\n", offset);
+                               return ret;
+                       }
+
+                       direction = val & pctl->func_desc[i].func_mask;
+                       direction >>= ffs(pctl->func_desc[i].func_mask) - 1;
+
+                       break;
+               }
+       }
+
+       if (strcmp(pctl->name, "spm8821") == 0)
+               return !direction;
+       else
+               return -EINVAL;
+}
+
+static void spacemit_gpio_set(struct gpio_chip *chip, unsigned int offset,
+                           int value)
+{
+       int ret;
+       struct spacemit_pctl *pctl = gpiochip_get_data(chip);
+
+       ret = regmap_update_bits(pctl->regmap,
+                       pctl->config_desc[offset].output.reg,
+                       pctl->config_desc[offset].output.msk,
+                       value ? pctl->config_desc[offset].output.msk : 0);
+       if (ret)
+               dev_err(pctl->dev, "set PIN%d, val:%d, failed\n", offset, value);
+}
+
+static int spacemit_gpio_input(struct gpio_chip *chip, unsigned int offset)
+{
+       /* set the gpio input */
+       return pinctrl_gpio_direction_input(chip->base + offset);
+}
+
+static int spacemit_gpio_output(struct gpio_chip *chip, unsigned int offset,
+                             int value)
+{
+       /* set the gpio output */
+       return pinctrl_gpio_direction_input(chip->base + offset);
+}
+
+static int spacemit_pin_conf_get(struct pinctrl_dev *pctldev, unsigned int pin,
+                              unsigned long *config)
+{
+       /* Do nothing by now */
+       return 0;
+}
+
+static int spacemit_pin_conf_set(struct pinctrl_dev *pctldev, unsigned int pin,
+                              unsigned long *configs, unsigned int num_configs)
+{
+       unsigned int reg, msk, ret;
+       struct spacemit_pctl *pctl = pinctrl_dev_get_drvdata(pctldev);
+
+       while (num_configs) {
+               switch (pinconf_to_config_param(*configs)) {
+               case PIN_CONFIG_BIAS_DISABLE:
+               case PIN_CONFIG_BIAS_PULL_DOWN:
+               case PIN_CONFIG_BIAS_PULL_UP:
+                       reg = pctl->config_desc[pin].pup.reg;
+                       msk = pctl->config_desc[pin].pup.msk;
+                       break;
+               case PIN_CONFIG_DRIVE_OPEN_DRAIN:
+               case PIN_CONFIG_DRIVE_PUSH_PULL:
+               case PIN_CONFIG_DRIVE_OPEN_SOURCE:
+                       reg = pctl->config_desc[pin].od.reg;
+                       msk = pctl->config_desc[pin].od.msk;
+                       break;
+               case PIN_CONFIG_INPUT_DEBOUNCE:
+                       reg = pctl->config_desc[pin].deb.reg;
+                       msk = pctl->config_desc[pin].deb.timemsk;
+                       break;
+               case PIN_CONFIG_INPUT_SCHMITT_ENABLE:
+                       reg = pctl->config_desc[pin].deb.reg;
+                       msk = pctl->config_desc[pin].deb.en.msk;
+                       break;
+               case PIN_CONFIG_OUTPUT:
+                       reg = pctl->config_desc[pin].output.reg;
+                       msk = pctl->config_desc[pin].output.msk;
+                       break;
+               default:
+                       return -ENOTSUPP;
+               }
+
+               ret = regmap_update_bits(pctl->regmap, reg, msk,
+                               pinconf_to_config_argument(*configs)
+                               << (ffs(msk) - 1));
+               if (ret) {
+                       dev_err(pctl->dev, "set reg:%x, msk:%x failed\n", reg, msk);
+                       return -EINVAL;
+               }
+               ++configs;
+               --num_configs;
+       }
+
+       return 0;
+}
+
+static int spacemit_pconf_group_set(struct pinctrl_dev *pctldev, unsigned group,
+                                unsigned long *configs, unsigned num_configs)
+{
+       return spacemit_pin_conf_set(pctldev, group, configs, num_configs);
+}
+
+static int spacemit_pconf_group_get(struct pinctrl_dev *pctldev,
+                                unsigned group,
+                                unsigned long *config)
+{
+       return spacemit_pin_conf_get(pctldev, group, config);
+}
+
+static const struct pinconf_ops spacemit_gpio_pinconf_ops = {
+       .is_generic = true,
+       .pin_config_get = spacemit_pin_conf_get,
+       .pin_config_set = spacemit_pin_conf_set,
+       .pin_config_group_get   = spacemit_pconf_group_get,
+       .pin_config_group_set   = spacemit_pconf_group_set,
+};
+
+static const struct of_device_id spacemit_pmic_pinctrl_of_match[] = {
+       { .compatible = "pmic,pinctrl,spm8821", .data = (void *)&spm8821_pinctrl_match_data },
+       { },
+};
+MODULE_DEVICE_TABLE(of, spacemit_pmic_pinctrl_of_match);
+
+static int spacemit_pmic_pinctrl_probe(struct platform_device *pdev)
+{
+       int i, res;
+       struct spacemit_pctl *pctl;
+       unsigned int npins;
+       const char **pin_names;
+       unsigned int *pin_nums;
+       struct pinctrl_pin_desc *pins;
+       const struct of_device_id *of_id;
+       struct spacemit_pmic *pmic = dev_get_drvdata(pdev->dev.parent);
+       struct pinctrl_match_data *match_data;
+
+       of_id = of_match_device(spacemit_pmic_pinctrl_of_match, &pdev->dev);
+       if (!of_id) {
+               pr_err("Unable to match OF ID\n");
+               return -ENODEV;
+       }
+
+       match_data = (struct pinctrl_match_data *)of_id->data;
+
+       pctl = devm_kzalloc(&pdev->dev, sizeof(*pctl), GFP_KERNEL);
+       if (!pctl)
+               return -ENOMEM;
+
+       pctl->name = match_data->name;
+       pctl->dev = &pdev->dev;
+       pctl->regmap = pmic->regmap;
+       pctl->func_desc = match_data->pinfunc_desc;
+       pctl->funcdesc_nums = match_data->nr_pin_fuc_desc;
+       pctl->config_desc = match_data->pinconf_desc;
+       pctl->confdesc_nums = match_data->nr_pin_conf_desc;
+       dev_set_drvdata(&pdev->dev, pctl);
+
+       if (of_property_read_u32(pdev->dev.of_node, "spacemit,npins", &npins))
+               return dev_err_probe(&pdev->dev, -EINVAL,
+                                    "spacemit,npins property not found\n");
+
+       pins = devm_kmalloc_array(&pdev->dev, npins, sizeof(pins[0]),
+                                 GFP_KERNEL);
+       pin_names = devm_kmalloc_array(&pdev->dev, npins, sizeof(pin_names[0]),
+                                      GFP_KERNEL);
+       pin_nums = devm_kmalloc_array(&pdev->dev, npins, sizeof(pin_nums[0]),
+                                     GFP_KERNEL);
+       if (!pins || !pin_names || !pin_nums)
+               return -ENOMEM;
+
+       for (i = 0; i < npins; i++) {
+               pins[i].number = i;
+               pins[i].name = devm_kasprintf(&pdev->dev, GFP_KERNEL, "PIN%u", i);
+               pins[i].drv_data = pctl;
+               pin_names[i] = pins[i].name;
+               pin_nums[i] = i;
+       }
+
+       pctl->pinctrl_desc.name = dev_name(pctl->dev);
+       pctl->pinctrl_desc.pins = pins;
+       pctl->pinctrl_desc.npins = npins;
+       pctl->pinctrl_desc.pctlops = &spacemit_gpio_pinctrl_ops;
+       pctl->pinctrl_desc.pmxops = &spacemit_gpio_pinmux_ops;
+       pctl->pinctrl_desc.confops = &spacemit_gpio_pinconf_ops;
+
+       pctl->pctldev = devm_pinctrl_register(&pdev->dev, &pctl->pinctrl_desc, pctl);
+       if (IS_ERR(pctl->pctldev))
+               return dev_err_probe(&pdev->dev, PTR_ERR(pctl->pctldev),
+                                    "Failed to register pinctrl device.\n");
+
+       for (i = 0; i < npins; i++) {
+               res = pinctrl_generic_add_group(pctl->pctldev, pins[i].name,
+                                               pin_nums + i, 1, pctl);
+               if (res < 0)
+                       return dev_err_probe(pctl->dev, res,
+                                            "Failed to register group");
+       }
+
+       for (i = 0; i < match_data->nr_pin_mux; ++i) {
+               res = pinmux_generic_add_function(pctl->pctldev, match_data->pinmux_funcs[i],
+                                                 pin_names, npins, pctl);
+               if (res < 0)
+                       return dev_err_probe(pctl->dev, res,
+                                            "Failed to register function.");
+       }
+
+       pctl->chip.base                 = -1;
+       pctl->chip.can_sleep            = true;
+       pctl->chip.request              = gpiochip_generic_request;
+       pctl->chip.free                 = gpiochip_generic_free;
+       pctl->chip.parent               = &pdev->dev;
+       pctl->chip.label                = dev_name(&pdev->dev);
+       pctl->chip.owner                = THIS_MODULE;
+       pctl->chip.get                  = spacemit_gpio_get;
+       pctl->chip.get_direction        = spacemit_gpio_get_direction;
+       pctl->chip.set                  = spacemit_gpio_set;
+       pctl->chip.direction_input      = spacemit_gpio_input;
+       pctl->chip.direction_output     = spacemit_gpio_output;
+
+       pctl->chip.ngpio = pctl->pinctrl_desc.npins;
+
+       res = devm_gpiochip_add_data(&pdev->dev, &pctl->chip, pctl);
+       if (res) {
+               dev_err(&pdev->dev, "Failed to register GPIO chip\n");
+               return res;
+       }
+
+       return 0;
+}
+
+static struct platform_driver spacemit_pmic_pinctrl_driver = {
+       .probe = spacemit_pmic_pinctrl_probe,
+       .driver = {
+               .name = "spacemit-pmic-pinctrl",
+               .of_match_table = spacemit_pmic_pinctrl_of_match,
+       },
+};
+module_platform_driver(spacemit_pmic_pinctrl_driver);
+
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/pinctrl/spacemit/Kconfig b/drivers/pinctrl/spacemit/Kconfig
new file mode 100755 (executable)
index 0000000..21ac696
--- /dev/null
@@ -0,0 +1,15 @@
+# SPDX-License-Identifier: GPL-2.0-only
+config PINCTRL_SPACEMIT
+       tristate
+       depends on OF
+       select GENERIC_PINCTRL_GROUPS
+       select GENERIC_PINMUX_FUNCTIONS
+       select GENERIC_PINCONF
+
+config PINCTRL_K1PRO
+       bool "Spacemit K1PRO pinctrl driver"
+       depends on OF
+       depends on SOC_SPACEMIT_K1_FPGA
+       select PINCTRL_SPACEMIT
+       help
+         Say Y here to enable the k1-pro pinctrl driver
diff --git a/drivers/pinctrl/spacemit/Makefile b/drivers/pinctrl/spacemit/Makefile
new file mode 100755 (executable)
index 0000000..0395ca4
--- /dev/null
@@ -0,0 +1,2 @@
+obj-$(CONFIG_PINCTRL_SPACEMIT) += pinctrl-spacemit.o
+obj-$(CONFIG_PINCTRL_K1PRO)    += pinctrl-k1pro.o
\ No newline at end of file
diff --git a/drivers/pinctrl/spacemit/pinctrl-spacemit.c b/drivers/pinctrl/spacemit/pinctrl-spacemit.c
new file mode 100755 (executable)
index 0000000..cd3770d
--- /dev/null
@@ -0,0 +1,582 @@
+// SPDX-License-Identifier: GPL-2.0+
+//
+// Copyright (c) 2023, spacemit Corporation.
+#include <linux/err.h>
+#include <linux/init.h>
+#include <linux/io.h>
+#include <linux/of.h>
+#include <linux/of_address.h>
+#include <linux/pinctrl/machine.h>
+#include <linux/pinctrl/pinconf.h>
+#include <linux/pinctrl/pinctrl.h>
+#include <linux/pinctrl/pinmux.h>
+#include <linux/platform_device.h>
+#include <linux/slab.h>
+#include <linux/reset.h>
+#include "../core.h"
+#include "pinctrl-spacemit.h"
+
+struct spacemit_pinctrl_data {
+       struct device *dev;
+       struct pinctrl_dev *pctl;
+       void __iomem *base;
+       struct reset_control *rstc;
+       struct spacemit_pinctrl_soc_data *soc;
+};
+
+static int spacemit_get_groups_count(struct pinctrl_dev *pctldev)
+{
+       struct spacemit_pinctrl_data *d = pinctrl_dev_get_drvdata(pctldev);
+
+       return d->soc->ngroups;
+}
+
+static const char *spacemit_get_group_name(struct pinctrl_dev *pctldev,
+                                       unsigned group)
+{
+       struct spacemit_pinctrl_data *d = pinctrl_dev_get_drvdata(pctldev);
+
+       if (group >= d->soc->ngroups)
+               return NULL;
+
+       return d->soc->groups[group].name;
+}
+
+static int spacemit_get_group_pins(struct pinctrl_dev *pctldev, unsigned group,
+                               const unsigned **pins, unsigned *num_pins)
+{
+       struct spacemit_pinctrl_data *d = pinctrl_dev_get_drvdata(pctldev);
+
+       if (group >= d->soc->ngroups)
+               return -EINVAL;
+
+       *pins = d->soc->groups[group].pin_ids;
+       *num_pins = d->soc->groups[group].npins;
+
+       return 0;
+}
+
+static void spacemit_pin_dbg_show(struct pinctrl_dev *pctldev, struct seq_file *s,
+                               unsigned offset)
+{
+       seq_printf(s, " %s", dev_name(pctldev->dev));
+}
+
+static int spacemit_dt_node_to_map(struct pinctrl_dev *pctldev,
+                               struct device_node *np,
+                               struct pinctrl_map **map, unsigned *num_maps)
+{
+       struct spacemit_pinctrl_data *d = pinctrl_dev_get_drvdata(pctldev);
+       const struct spacemit_group *grp;
+       struct pinctrl_map *new_map;
+       struct device_node *parent;
+       int map_num = 1;
+       int i, j;
+
+       /*
+        * first find the group of this node and check if we need create
+        * config maps for pins
+        */
+       grp = NULL;
+       for (i = 0; i < d->soc->ngroups; i++) {
+               if (!strcmp(d->soc->groups[i].name, np->name)) {
+                       grp = &d->soc->groups[i];
+                       break;
+               }
+       }
+       if (!grp) {
+               dev_err(d->dev, "unable to find group for node %s\n",
+                       np->name);
+               return -EINVAL;
+       }
+
+       for (i = 0; i < grp->npins; i++)
+               map_num++;
+
+       new_map = kmalloc_array(map_num, sizeof(struct pinctrl_map),
+                               GFP_KERNEL);
+       if (!new_map)
+               return -ENOMEM;
+
+       *map = new_map;
+       *num_maps = map_num;
+
+       /* create mux map */
+       parent = of_get_parent(np);
+       if (!parent) {
+               kfree(new_map);
+               return -EINVAL;
+       }
+       new_map[0].type = PIN_MAP_TYPE_MUX_GROUP;
+       new_map[0].data.mux.function = np->name;
+       new_map[0].data.mux.group = np->name;
+       of_node_put(parent);
+
+       /* create config map */
+       new_map++;
+       for (i = j = 0; i < grp->npins; i++) {
+               new_map[j].type = PIN_MAP_TYPE_CONFIGS_PIN;
+               new_map[j].data.configs.group_or_pin =
+                       pin_get_name(pctldev, grp->pins[i].pin_id);
+               new_map[j].data.configs.configs = &grp->pins[i].config;
+               new_map[j].data.configs.num_configs = 1;
+               j++;
+       }
+
+       dev_dbg(pctldev->dev, "maps: function %s group %s num %d\n",
+               (*map)->data.mux.function, (*map)->data.mux.group, map_num);
+
+       return 0;
+}
+
+static void spacemit_dt_free_map(struct pinctrl_dev *pctldev,
+                               struct pinctrl_map *map, unsigned num_maps)
+{
+       u32 i;
+
+       for (i = 0; i < num_maps; i++) {
+               if (map[i].type == PIN_MAP_TYPE_MUX_GROUP)
+                       kfree(map[i].data.mux.group);
+               if (map[i].type == PIN_MAP_TYPE_CONFIGS_PIN)
+                       kfree(map[i].data.configs.configs);
+       }
+
+       kfree(map);
+}
+
+static const struct pinctrl_ops spacemit_pinctrl_ops = {
+       .get_groups_count = spacemit_get_groups_count,
+       .get_group_name = spacemit_get_group_name,
+       .get_group_pins = spacemit_get_group_pins,
+       .pin_dbg_show = spacemit_pin_dbg_show,
+       .dt_node_to_map = spacemit_dt_node_to_map,
+       .dt_free_map = spacemit_dt_free_map,
+};
+
+static int spacemit_pinctrl_get_funcs_count(struct pinctrl_dev *pctldev)
+{
+       struct spacemit_pinctrl_data *d = pinctrl_dev_get_drvdata(pctldev);
+
+       return d->soc->nfunctions;
+}
+
+static const char *spacemit_pinctrl_get_func_name(struct pinctrl_dev *pctldev,
+                                               unsigned function)
+{
+       struct spacemit_pinctrl_data *d = pinctrl_dev_get_drvdata(pctldev);
+
+       return d->soc->functions[function].name;
+}
+
+static int spacemit_pinctrl_get_func_groups(struct pinctrl_dev *pctldev,
+                                       unsigned group,
+                                       const char * const **groups,
+                                       unsigned * const num_groups)
+{
+       struct spacemit_pinctrl_data *d = pinctrl_dev_get_drvdata(pctldev);
+
+       *groups = d->soc->functions[group].groups;
+       *num_groups = d->soc->functions[group].ngroups;
+
+       return 0;
+}
+
+static void spacemit_pinctrl_rmwl(u32 value, u32 mask, u8 shift, void __iomem *reg)
+{
+       u32 tmp;
+
+       tmp = readl(reg);
+       tmp &= ~(mask << shift);
+       tmp |= value << shift;
+       writel(tmp, reg);
+}
+
+static int spacemit_pinctrl_set_mux(struct pinctrl_dev *pctldev, unsigned selector,
+                               unsigned group)
+{
+       struct spacemit_pinctrl_data *d = pinctrl_dev_get_drvdata(pctldev);
+       struct spacemit_group *g = &d->soc->groups[group];
+       void __iomem *reg;
+       u8 bank, shift, width;
+       u16 offset;
+       u32 i;
+
+       for (i = 0; i < g->npins; i++) {
+               bank = PINID_TO_BANK(g->pin_ids[i]);
+               offset = PINID_TO_PIN(g->pin_ids[i]);
+               reg = d->base + d->soc->regs->cfg;
+               reg += bank * d->soc->regs->reg_len + offset * 4;
+               shift = d->soc->pinconf->fs_shift;
+               width = d->soc->pinconf->fs_width;
+
+               dev_dbg(d->dev, "set mux: bank %d 0ffset %d val 0x%lx\n",
+                       bank, offset, g->pins[i].muxsel);
+
+               spacemit_pinctrl_rmwl(g->pins[i].muxsel, GENMASK((width-1),0), shift, reg);
+       }
+
+       return 0;
+}
+
+static const struct pinmux_ops spacemit_pinmux_ops = {
+       .get_functions_count = spacemit_pinctrl_get_funcs_count,
+       .get_function_name = spacemit_pinctrl_get_func_name,
+       .get_function_groups = spacemit_pinctrl_get_func_groups,
+       .set_mux = spacemit_pinctrl_set_mux,
+};
+
+static int spacemit_pinconf_get(struct pinctrl_dev *pctldev,
+                       unsigned pin, unsigned long *config)
+{
+       struct spacemit_pinctrl_data *d = pinctrl_dev_get_drvdata(pctldev);
+       u8 bank;
+       u16 offset = 0;
+       u64 reg = 0;
+
+       bank = PINID_TO_BANK(pin);
+       offset = PINID_TO_PIN(pin);
+       reg = (u64)(d->base + d->soc->regs->cfg);
+       reg += bank * d->soc->regs->reg_len + offset * 4;
+
+       *config = readl((void *)reg);
+       return 0;
+}
+
+static int spacemit_pinconf_set(struct pinctrl_dev *pctldev,
+                       unsigned pin, unsigned long *configs,
+                       unsigned num_configs)
+{
+       struct spacemit_pinctrl_data *d = pinctrl_dev_get_drvdata(pctldev);
+       struct spacemit_pinctrl_soc_data *soc = d->soc;
+       const struct spacemit_regs *regs = soc->regs;
+       const struct spacemit_pin_conf *pin_conf = soc->pinconf;
+       int i;
+       u8 bank;
+       u32 od, pull_en, pull, ds, st, rte;
+       u16 offset = 0;
+       u64 reg = 0;
+
+       dev_dbg(d->dev, "pinconf set pin %s\n",
+               pin_get_name(pctldev, pin));
+
+       bank = PINID_TO_BANK(pin);
+       offset = PINID_TO_PIN(pin);
+       reg = (u64)(d->base + regs->cfg);
+       reg += bank * regs->reg_len + offset * 4;
+
+       for (i = 0; i < num_configs; i++) {
+               volatile long config;
+
+               config = readl((void *)reg);
+
+               od = OD_DIS << pin_conf->od_shift;
+               pull_en = PE_EN << pin_conf->pe_shift;
+               pull = CONFIG_TO_PULL(configs[i]) << pin_conf->pull_shift;
+               ds = CONFIG_TO_DS(configs[i]) << pin_conf->ds_shift;
+               st = ST_DIS << pin_conf->st_shift;
+               rte = RTE_EN << pin_conf->rte_shift;
+
+               config |= (od | pull_en | pull | ds | st | rte);
+               writel(config, (void *)reg);
+               dev_dbg(d->dev, "write: bank %d 0ffset %d val 0x%lx\n",
+                       bank, offset, config);
+       } /* for each config */
+
+       return 0;
+}
+
+static void spacemit_pinconf_dbg_show(struct pinctrl_dev *pctldev,
+                               struct seq_file *s, unsigned pin)
+{
+       struct spacemit_pinctrl_data *d = pinctrl_dev_get_drvdata(pctldev);
+       u8 bank;
+       u16 offset = 0;
+       u64 reg = 0;
+
+       bank = PINID_TO_BANK(pin);
+       offset = PINID_TO_PIN(pin);
+       reg = (u64)(d->base + d->soc->regs->cfg);
+       reg += bank * d->soc->regs->reg_len + offset * 4;
+
+       seq_printf(s, "0x%lx", readl((void *)reg));
+}
+
+static void spacemit_pinconf_group_dbg_show(struct pinctrl_dev *pctldev,
+                                       struct seq_file *s, unsigned group)
+{
+       struct spacemit_pinctrl_data *d = pinctrl_dev_get_drvdata(pctldev);
+       struct spacemit_group *grp;
+       unsigned long config;
+       const char *name;
+       int i, ret;
+
+       if (group > d->soc->ngroups)
+               return;
+
+       seq_puts(s, "\n");
+       grp = &d->soc->groups[group];
+       for (i = 0; i < grp->npins; i++) {
+               struct spacemit_pin *pin = &grp->pins[i];
+
+               name = pin_get_name(pctldev, pin->pin_id);
+               ret = spacemit_pinconf_get(pctldev, pin->pin_id, &config);
+               if (ret)
+                       return;
+               seq_printf(s, "%s: 0x%lx", name, config);
+       }
+}
+
+static const struct pinconf_ops spacemit_pinconf_ops = {
+       .pin_config_get = spacemit_pinconf_get,
+       .pin_config_set = spacemit_pinconf_set,
+       .pin_config_dbg_show = spacemit_pinconf_dbg_show,
+       .pin_config_group_dbg_show = spacemit_pinconf_group_dbg_show,
+};
+
+static struct pinctrl_desc spacemit_pinctrl_desc = {
+       .pctlops = &spacemit_pinctrl_ops,
+       .pmxops = &spacemit_pinmux_ops,
+       .confops = &spacemit_pinconf_ops,
+       .owner = THIS_MODULE,
+};
+
+static const char *get_pin_name_from_soc(struct spacemit_pinctrl_soc_data *soc,
+                                       const unsigned int pin_id)
+{
+       int i;
+
+       for (i = 0; i < soc->npins; i++) {
+               if (soc->pins[i].number == pin_id)
+                       return soc->pins[i].name;
+       }
+
+       return NULL;
+}
+
+static int spacemit_pinctrl_parse_groups(struct device_node *np,
+                                       struct spacemit_group *grp,
+                                       struct spacemit_pinctrl_data *d,
+                                       u32 index)
+{
+       int size, i;
+       const __be32 *list;
+
+       dev_dbg(d->dev, "group(%d): %s\n", index, np->name);
+
+       /* Initialise group */
+       grp->name = np->name;
+
+       /*
+        * the binding format is spacemit,pins = <PIN MUX CONFIG>,
+        * do sanity check and calculate pins number
+        */
+       list = of_get_property(np, "spacemit,pins", &size);
+       if (!list) {
+               dev_err(d->dev, "no spacemit,pins property in node %s\n",
+                       np->full_name);
+               return -EINVAL;
+       }
+
+       if (!size || size % SPACEMIT_PIN_SIZE) {
+               dev_err(d->dev, "Invalid spacemit,pins property in node %s\n",
+                       np->full_name);
+               return -EINVAL;
+       }
+
+       grp->npins = size / SPACEMIT_PIN_SIZE;
+       grp->pins = devm_kcalloc(d->dev, grp->npins,
+                               sizeof(struct spacemit_pin), GFP_KERNEL);
+       grp->pin_ids = devm_kcalloc(d->dev, grp->npins,
+                                       sizeof(unsigned int), GFP_KERNEL);
+       if (!grp->pins || !grp->pin_ids)
+               return -ENOMEM;
+
+       for (i = 0; i < grp->npins; i++) {
+               struct spacemit_pin *pin = &grp->pins[i];
+               u8 pull_val, driver_strength;
+
+               pin->pin_id = be32_to_cpu(*list++);
+               pin->muxsel = be32_to_cpu(*list++) & 0xF;
+               pull_val = be32_to_cpu(*list++) & 0x1;
+               driver_strength =  be32_to_cpu(*list++) & 0xF;
+               pin->config = (pull_val << PULL_SHIFT) | (driver_strength << DS_SHIFT);
+               grp->pin_ids[i] = grp->pins[i].pin_id;
+
+               dev_dbg(d->dev, "%s: 0x%04x 0x%04lx",
+                       get_pin_name_from_soc(d->soc, pin->pin_id), pin->muxsel, pin->config);
+       }
+
+       return 0;
+}
+
+static int spacemit_pinctrl_parse_functions(struct device_node *np,
+                                       struct spacemit_pinctrl_data *d)
+{
+       struct spacemit_pinctrl_soc_data *soc = d->soc;
+       struct device_node *child;
+       struct spacemit_function *f;
+       u32 i = 0, idxf = 0, idxg = 0;
+       const char *fn, *fnull = "";
+       int ret;
+
+       /* Count groups for each function */
+       fn = fnull;
+       f = &soc->functions[idxf];
+       for_each_child_of_node(np, child) {
+               if (strcmp(fn, child->name)) {
+                       struct device_node *child2;
+
+                       /*
+                        * This reference is dropped by
+                        * of_get_next_child(np, * child)
+                        */
+                       of_node_get(child);
+
+                       /*
+                        * The logic parsing the functions from dt currently
+                        * doesn't handle if functions with the same name are
+                        * not grouped together. Only the first contiguous
+                        * cluster is usable for each function name. This is a
+                        * bug that is not trivial to fix, but at least warn
+                        * about it.
+                        */
+                       for (child2 = of_get_next_child(np, child);
+                               child2 != NULL;
+                               child2 = of_get_next_child(np, child2)) {
+                               if (!strcmp(child2->name, fn))
+                                       dev_warn(d->dev,
+                                               "function nodes must be grouped by name (failed for: %s)",
+                                               fn);
+                       }
+
+                       f = &soc->functions[idxf++];
+                       f->name = fn = child->name;
+               }
+               f->ngroups++;
+               dev_dbg(d->dev, "function(%d): %s\n", idxf-1, f->name);
+       }
+
+       /* Get groups for each function */
+       idxf = 0;
+       fn = fnull;
+       for_each_child_of_node(np, child) {
+               if (strcmp(fn, child->name)) {
+                       f = &soc->functions[idxf++];
+                       f->groups = devm_kcalloc(d->dev,
+                                               f->ngroups,
+                                               sizeof(*f->groups),
+                                               GFP_KERNEL);
+                       if (!f->groups) {
+                               of_node_put(child);
+                               return -ENOMEM;
+                       }
+                       fn = child->name;
+                       i = 0;
+               }
+
+               f->groups[i] = child->name;
+               ret = spacemit_pinctrl_parse_groups(child, &soc->groups[idxg++], d, i++);
+               if (ret) {
+                       of_node_put(child);
+                       return ret;
+               }
+       }
+
+       return 0;
+}
+
+static int spacemit_pinctrl_probe_dt(struct platform_device *pdev,
+                               struct spacemit_pinctrl_data *d)
+{
+       struct spacemit_pinctrl_soc_data *soc = d->soc;
+       struct device_node *np = pdev->dev.of_node;
+       struct device_node *child;
+       const char *fn, *fnull = "";
+
+       if (!np)
+               return -ENODEV;
+
+       /* Count total functions and groups */
+       fn = fnull;
+       for_each_child_of_node(np, child) {
+               soc->ngroups++;
+               if (strcmp(fn, child->name)) {
+                       fn = child->name;
+                       soc->nfunctions++;
+               }
+       }
+
+       if (soc->nfunctions <= 0) {
+               dev_err(&pdev->dev, "It has no functions\n");
+               return -EINVAL;
+       }
+
+       soc->functions = devm_kcalloc(&pdev->dev, soc->nfunctions,
+                                       sizeof(struct spacemit_function),
+                                       GFP_KERNEL);
+       if (!soc->functions)
+               return -ENOMEM;
+
+       soc->groups = devm_kcalloc(&pdev->dev, soc->ngroups,
+                                       sizeof(struct spacemit_group),
+                                       GFP_KERNEL);
+       if (!soc->groups)
+               return -ENOMEM;
+
+       spacemit_pinctrl_parse_functions(np, d);
+
+       return 0;
+}
+
+int spacemit_pinctrl_probe(struct platform_device *pdev,
+                       struct spacemit_pinctrl_soc_data *soc)
+{
+       struct spacemit_pinctrl_data *d;
+       struct resource *res;
+       int ret;
+
+       d = devm_kzalloc(&pdev->dev, sizeof(*d), GFP_KERNEL);
+       if (!d)
+               return -ENOMEM;
+
+       d->dev = &pdev->dev;
+       d->soc = soc;
+
+       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+       d->base = devm_ioremap(&pdev->dev, res->start, resource_size(res));
+       if (!d->base)
+               return -EADDRNOTAVAIL;
+
+       spacemit_pinctrl_desc.pins = d->soc->pins;
+       spacemit_pinctrl_desc.npins = d->soc->npins;
+       spacemit_pinctrl_desc.name = dev_name(&pdev->dev);
+
+       platform_set_drvdata(pdev, d);
+
+       d->rstc = devm_reset_control_get_optional_exclusive(&pdev->dev, NULL);
+       if (IS_ERR(d->rstc)) {
+               ret = PTR_ERR(d->rstc);
+               dev_err(&pdev->dev, "failed to get reset.\n");
+               goto err;
+       }
+       reset_control_deassert(d->rstc);
+
+       ret = spacemit_pinctrl_probe_dt(pdev, d);
+       if (ret) {
+               dev_err(&pdev->dev, "dt probe failed: %d\n", ret);
+               goto err;
+       }
+
+       d->pctl = pinctrl_register(&spacemit_pinctrl_desc, &pdev->dev, d);
+       if (IS_ERR(d->pctl)) {
+               dev_err(&pdev->dev, "Couldn't register spacemit pinctrl driver\n");
+               ret = PTR_ERR(d->pctl);
+               goto err;
+       }
+
+       return 0;
+
+err:
+       iounmap(d->base);
+       return ret;
+}
\ No newline at end of file
diff --git a/drivers/pinctrl/spacemit/pinctrl-spacemit.h b/drivers/pinctrl/spacemit/pinctrl-spacemit.h
new file mode 100755 (executable)
index 0000000..f937ab5
--- /dev/null
@@ -0,0 +1,104 @@
+/* SPDX-License-Identifier: GPL-2.0+ */
+/*
+ * Copyright (c) 2023, spacemit Corporation.
+ */
+
+#ifndef __PINCTRL_SPACEMIT_H
+#define __PINCTRL_SPACEMIT_H
+
+#include <linux/platform_device.h>
+#include <linux/pinctrl/pinctrl.h>
+
+#define SPACEMIT_PINCTRL_PIN(pin)      PINCTRL_PIN(pin, #pin)
+
+#define PINID_TO_BANK(p)       ((p) >> 5)
+#define PINID_TO_PIN(p)                ((p) % 32)
+
+/*
+ * pin config bit field definitions
+ * config format
+ * 0-3  driver_strength
+ * 4    pull
+ *
+ * od: open drain
+ * pe:  pull enable
+ * st: schmit trigger
+ * rte:        retention signal bus
+ *
+ * MSB of each field is presence bit for the config.
+ */
+#define OD_EN          1
+#define OD_DIS         0
+#define PE_EN          1
+#define PE_DIS         0
+#define ST_EN          1
+#define ST_DIS         0
+#define RTE_EN         1
+#define RTE_DIS                0
+
+#define DS_SHIFT       0
+#define PULL_SHIFT  4
+
+#define CONFIG_TO_DS(c)                ((c) >> DS_SHIFT & 0xf)
+#define CONFIG_TO_PULL(c)      ((c) >> PULL_SHIFT & 0x1)
+
+struct spacemit_function {
+       const char *name;
+       const char **groups;
+       unsigned ngroups;
+};
+
+/*
+ * Each pin represented in spacemit,pins consists:
+ * - u32 PIN_FUNC_ID
+ * - u32 pin muxsel
+ * - u32 pin pull_up/down
+ * - u32 pin driving strength
+ */
+#define SPACEMIT_PIN_SIZE 16
+
+struct spacemit_pin {
+       unsigned int pin_id;
+       u8 muxsel;
+       u8 pull;
+       unsigned long config;
+};
+
+struct spacemit_group {
+       const char *name;
+       unsigned npins;
+       unsigned *pin_ids;
+       struct spacemit_pin *pins;
+};
+
+struct spacemit_regs {
+       u16 cfg;
+       u16 reg_len;
+};
+
+struct spacemit_pin_conf {
+       u8  fs_shift;
+       u8  fs_width;
+       u8  od_shift;
+       u8  pe_shift;
+       u8  pull_shift;
+       u8  ds_shift;
+       u8  st_shift;
+       u8  rte_shift;
+};
+
+struct spacemit_pinctrl_soc_data {
+       const struct spacemit_regs *regs;
+       const struct spacemit_pin_conf *pinconf;
+       const struct pinctrl_pin_desc *pins;
+       unsigned npins;
+       struct spacemit_function *functions;
+       unsigned nfunctions;
+       struct spacemit_group *groups;
+       unsigned ngroups;
+};
+
+int spacemit_pinctrl_probe(struct platform_device *pdev,
+                               struct spacemit_pinctrl_soc_data *soc);
+
+#endif /* __PINCTRL_SPACEMIT_H */
diff --git a/include/dt-bindings/pinctrl/k1-x-pinctrl.h b/include/dt-bindings/pinctrl/k1-x-pinctrl.h
new file mode 100644 (file)
index 0000000..90d0ec2
--- /dev/null
@@ -0,0 +1,198 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+
+#ifndef __DT_BINDINGS_K1X_PINCTRL_H
+#define __DT_BINDINGS_K1X_PINCTRL_H
+
+/* pin offset */
+#define PINID(x)       ((x) + 1)
+
+#define GPIO_00  PINID(0)
+#define GPIO_01  PINID(1)
+#define GPIO_02  PINID(2)
+#define GPIO_03  PINID(3)
+#define GPIO_04  PINID(4)
+#define GPIO_05  PINID(5)
+#define GPIO_06  PINID(6)
+#define GPIO_07  PINID(7)
+#define GPIO_08  PINID(8)
+#define GPIO_09  PINID(9)
+#define GPIO_10  PINID(10)
+#define GPIO_11  PINID(11)
+#define GPIO_12  PINID(12)
+#define GPIO_13  PINID(13)
+#define GPIO_14  PINID(14)
+#define GPIO_15  PINID(15)
+#define GPIO_16  PINID(16)
+#define GPIO_17  PINID(17)
+#define GPIO_18  PINID(18)
+#define GPIO_19  PINID(19)
+#define GPIO_20  PINID(20)
+#define GPIO_21  PINID(21)
+#define GPIO_22  PINID(22)
+#define GPIO_23  PINID(23)
+#define GPIO_24  PINID(24)
+#define GPIO_25  PINID(25)
+#define GPIO_26  PINID(26)
+#define GPIO_27  PINID(27)
+#define GPIO_28  PINID(28)
+#define GPIO_29  PINID(29)
+#define GPIO_30  PINID(30)
+#define GPIO_31  PINID(31)
+
+#define GPIO_32  PINID(32)
+#define GPIO_33  PINID(33)
+#define GPIO_34  PINID(34)
+#define GPIO_35  PINID(35)
+#define GPIO_36  PINID(36)
+#define GPIO_37  PINID(37)
+#define GPIO_38  PINID(38)
+#define GPIO_39  PINID(39)
+#define GPIO_40  PINID(40)
+#define GPIO_41  PINID(41)
+#define GPIO_42  PINID(42)
+#define GPIO_43  PINID(43)
+#define GPIO_44  PINID(44)
+#define GPIO_45  PINID(45)
+#define GPIO_46  PINID(46)
+#define GPIO_47  PINID(47)
+#define GPIO_48  PINID(48)
+#define GPIO_49  PINID(49)
+#define GPIO_50  PINID(50)
+#define GPIO_51  PINID(51)
+#define GPIO_52  PINID(52)
+#define GPIO_53  PINID(53)
+#define GPIO_54  PINID(54)
+#define GPIO_55  PINID(55)
+#define GPIO_56  PINID(56)
+#define GPIO_57  PINID(57)
+#define GPIO_58  PINID(58)
+#define GPIO_59  PINID(59)
+#define GPIO_60  PINID(60)
+#define GPIO_61  PINID(61)
+#define GPIO_62  PINID(62)
+#define GPIO_63  PINID(63)
+
+#define GPIO_64  PINID(64)
+#define GPIO_65  PINID(65)
+#define GPIO_66  PINID(66)
+#define GPIO_67  PINID(67)
+#define GPIO_68  PINID(68)
+#define GPIO_69  PINID(69)
+#define PRI_TDI  PINID(70)
+#define PRI_TMS  PINID(71)
+#define PRI_TCK  PINID(72)
+#define PRI_TDO  PINID(73)
+#define GPIO_74  PINID(74)
+#define GPIO_75  PINID(75)
+#define GPIO_76  PINID(76)
+#define GPIO_77  PINID(77)
+#define GPIO_78  PINID(78)
+#define GPIO_79  PINID(79)
+#define GPIO_80  PINID(80)
+#define GPIO_81  PINID(81)
+#define GPIO_82  PINID(82)
+#define GPIO_83  PINID(83)
+#define GPIO_84  PINID(84)
+#define GPIO_85  PINID(85)
+
+#define QSPI_DAT0   PINID(89)
+#define QSPI_DAT1   PINID(90)
+#define QSPI_DAT2   PINID(91)
+#define QSPI_DAT3   PINID(92)
+#define QSPI_CSI    PINID(93)
+#define QSPI_CLK    PINID(94)
+
+#define MMC1_DAT3   PINID(109)
+#define MMC1_DAT2   PINID(110)
+#define MMC1_DAT1   PINID(111)
+#define MMC1_DAT0   PINID(112)
+#define MMC1_CMD    PINID(113)
+#define MMC1_CLK    PINID(114)
+#define GPIO_110    PINID(115)
+#define PWR_SCL     PINID(116)
+#define PWR_SDA     PINID(117)
+#define VCXO_EN     PINID(118)
+#define DVL0        PINID(119)
+#define DVL1        PINID(120)
+#define PMIC_INT_N  PINID(121)
+#define GPIO_86     PINID(122)
+#define GPIO_87     PINID(123)
+#define GPIO_88     PINID(124)
+#define GPIO_89     PINID(125)
+#define GPIO_90     PINID(126)
+#define GPIO_91     PINID(127)
+#define GPIO_92     PINID(128)
+
+#define GPIO_111    PINID(130)
+#define GPIO_112    PINID(131)
+#define GPIO_113    PINID(132)
+#define GPIO_114    PINID(133)
+#define GPIO_115    PINID(134)
+#define GPIO_116    PINID(135)
+#define GPIO_117    PINID(136)
+#define GPIO_118    PINID(137)
+#define GPIO_119    PINID(138)
+#define GPIO_120    PINID(139)
+#define GPIO_121    PINID(140)
+#define GPIO_122    PINID(141)
+#define GPIO_123    PINID(142)
+#define GPIO_124    PINID(143)
+#define GPIO_125    PINID(144)
+#define GPIO_126    PINID(145)
+#define GPIO_127    PINID(146)
+
+/* pin mux */
+#define MUX_MODE0       0
+#define MUX_MODE1       1
+#define MUX_MODE2       2
+#define MUX_MODE3       3
+#define MUX_MODE4       4
+#define MUX_MODE5       5
+#define MUX_MODE6       6
+#define MUX_MODE7       7
+
+/* strong pull resistor */
+#define SPU_EN          (1 << 3)
+
+/* edge detect */
+#define EDGE_NONE       (1 << 6)
+#define EDGE_RISE       (1 << 4)
+#define EDGE_FALL       (1 << 5)
+#define EDGE_BOTH       (3 << 4)
+
+/* slew rate output control */
+#define SLE_EN          (1 << 7)
+
+/* schmitter trigger input threshhold */
+#define ST00            (0 << 8)
+#define ST01            (1 << 8)
+#define ST02            (2 << 8)
+#define ST03            (3 << 8)
+
+/* driver strength*/
+#define PAD_1V8_DS0     (0 << 11)
+#define PAD_1V8_DS1     (1 << 11)
+#define PAD_1V8_DS2     (2 << 11)
+#define PAD_1V8_DS3     (3 << 11)
+
+/*
+ * notice: !!!
+ * ds2 ---> bit10, ds1 ----> bit12, ds0 ----> bit11
+*/
+#define PAD_3V_DS0      (0 << 10)     /* bit[12:10] 000 */
+#define PAD_3V_DS1      (2 << 10)     /* bit[12:10] 010 */
+#define PAD_3V_DS2      (4 << 10)     /* bit[12:10] 100 */
+#define PAD_3V_DS3      (6 << 10)     /* bit[12:10] 110 */
+#define PAD_3V_DS4      (1 << 10)     /* bit[12:10] 001 */
+#define PAD_3V_DS5      (3 << 10)     /* bit[12:10] 011 */
+#define PAD_3V_DS6      (5 << 10)     /* bit[12:10] 101 */
+#define PAD_3V_DS7      (7 << 10)     /* bit[12:10] 111 */
+
+/* pull up/down */
+#define PULL_DIS        (0 << 13)     /* bit[15:13] 000 */
+#define PULL_UP         (6 << 13)     /* bit[15:13] 110 */
+#define PULL_DOWN       (5 << 13)     /* bit[15:13] 101 */
+
+#define K1X_PADCONF(pinid, conf, mux)  ((pinid) * 4) (conf) (mux)
+
+#endif /* __DT_BINDINGS_K1PRO_PINCTRL_H */