--- /dev/null
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Xilinx pinctrl driver for ZynqMP
+ *
+ * Author(s): Ashok Reddy Soma <ashok.reddy.soma@xilinx.com>
+ * Michal Simek <michal.simek@xilinx.com>
+ *
+ * Copyright (C) 2021 Xilinx, Inc. All rights reserved.
+ */
+
+#include <common.h>
+#include <dm.h>
+#include <errno.h>
+#include <malloc.h>
+#include <zynqmp_firmware.h>
+#include <asm/arch/sys_proto.h>
+#include <asm/io.h>
+#include <dm/device_compat.h>
+#include <dm/pinctrl.h>
+#include <linux/compat.h>
+#include <dt-bindings/pinctrl/pinctrl-zynqmp.h>
+
+#define PINCTRL_GET_FUNC_GROUPS_RESP_LEN 12
+#define PINCTRL_GET_PIN_GROUPS_RESP_LEN 12
+#define NUM_GROUPS_PER_RESP 6
+#define NA_GROUP -1
+#define RESERVED_GROUP -2
+#define MAX_GROUP_PIN 50
+#define MAX_PIN_GROUPS 50
+#define MAX_GROUP_NAME_LEN 32
+#define MAX_FUNC_NAME_LEN 16
+
+#define DRIVE_STRENGTH_2MA 2
+#define DRIVE_STRENGTH_4MA 4
+#define DRIVE_STRENGTH_8MA 8
+#define DRIVE_STRENGTH_12MA 12
+
+/*
+ * This driver works with very simple configuration that has the same name
+ * for group and function. This way it is compatible with the Linux Kernel
+ * driver.
+ */
+struct zynqmp_pinctrl_priv {
+ u32 npins;
+ u32 nfuncs;
+ u32 ngroups;
+ struct zynqmp_pmux_function *funcs;
+ struct zynqmp_pctrl_group *groups;
+};
+
+/**
+ * struct zynqmp_pinctrl_config - pinconfig parameters
+ * @slew: Slew rate slow or fast
+ * @bias: Bias enabled or disabled
+ * @pull_ctrl: Pull control pull up or pull down
+ * @input_type: CMOS or Schmitt
+ * @drive_strength: Drive strength 2mA/4mA/8mA/12mA
+ * @volt_sts: Voltage status 1.8V or 3.3V
+ * @tri_state: Tristate enabled or disabled
+ *
+ * This structure holds information about pin control config
+ * option that can be set for each pin.
+ */
+struct zynqmp_pinctrl_config {
+ u32 slew;
+ u32 bias;
+ u32 pull_ctrl;
+ u32 input_type;
+ u32 drive_strength;
+ u32 volt_sts;
+ u32 tri_state;
+};
+
+/**
+ * enum zynqmp_pin_config_param - possible pin configuration parameters
+ * @PIN_CONFIG_IOSTANDARD: if the pin can select an IO standard,
+ * the argument to this parameter (on a
+ * custom format) tells the driver which
+ * alternative IO standard to use
+ * @PIN_CONFIG_SCHMITTCMOS: this parameter (on a custom format) allows
+ * to select schmitt or cmos input for MIO pins
+ */
+enum zynqmp_pin_config_param {
+ PIN_CONFIG_IOSTANDARD = PIN_CONFIG_END + 1,
+ PIN_CONFIG_SCHMITTCMOS,
+};
+
+/**
+ * struct zynqmp_pmux_function - a pinmux function
+ * @name: Name of the pinmux function
+ * @groups: List of pingroups for this function
+ * @ngroups: Number of entries in @groups
+ *
+ * This structure holds information about pin control function
+ * and function group names supporting that function.
+ */
+struct zynqmp_pmux_function {
+ char name[MAX_FUNC_NAME_LEN];
+ const char * const *groups;
+ unsigned int ngroups;
+};
+
+/**
+ * struct zynqmp_pctrl_group - Pin control group info
+ * @name: Group name
+ * @pins: Group pin numbers
+ * @npins: Number of pins in group
+ */
+struct zynqmp_pctrl_group {
+ const char *name;
+ unsigned int pins[MAX_GROUP_PIN];
+ unsigned int npins;
+};
+
+static char pin_name[PINNAME_SIZE];
+
+/**
+ * zynqmp_pm_query_data() - Get query data from firmware
+ * @qid: Value of enum pm_query_id
+ * @arg1: Argument 1
+ * @arg2: Argument 2
+ * @out: Returned output value
+ *
+ * Return: Returns status, either success or error+reason
+ */
+static int zynqmp_pm_query_data(enum pm_query_id qid, u32 arg1, u32 arg2, u32 *out)
+{
+ int ret;
+ u32 ret_payload[PAYLOAD_ARG_CNT];
+
+ ret = xilinx_pm_request(PM_QUERY_DATA, qid, arg1, arg2, 0, ret_payload);
+ if (ret)
+ return ret;
+
+ *out = ret_payload[1];
+
+ return ret;
+}
+
+static int zynqmp_pm_pinctrl_get_config(const u32 pin, const u32 param, u32 *value)
+{
+ int ret;
+ u32 ret_payload[PAYLOAD_ARG_CNT];
+
+ /* Get config for the pin */
+ ret = xilinx_pm_request(PM_PINCTRL_CONFIG_PARAM_GET, pin, param, 0, 0, ret_payload);
+ if (ret) {
+ printf("%s failed\n", __func__);
+ return ret;
+ }
+
+ *value = ret_payload[1];
+
+ return ret;
+}
+
+static int zynqmp_pm_pinctrl_set_config(const u32 pin, const u32 param, u32 value)
+{
+ int ret;
+
+ /* Request the pin first */
+ ret = xilinx_pm_request(PM_PINCTRL_REQUEST, pin, 0, 0, 0, NULL);
+ if (ret) {
+ printf("%s: pin request failed\n", __func__);
+ return ret;
+ }
+
+ /* Set config for the pin */
+ ret = xilinx_pm_request(PM_PINCTRL_CONFIG_PARAM_SET, pin, param, value, 0, NULL);
+ if (ret) {
+ printf("%s failed\n", __func__);
+ return ret;
+ }
+
+ return ret;
+}
+
+static int zynqmp_pinctrl_get_function_groups(u32 fid, u32 index, u16 *groups)
+{
+ int ret;
+ u32 ret_payload[PAYLOAD_ARG_CNT];
+
+ ret = xilinx_pm_request(PM_QUERY_DATA, PM_QID_PINCTRL_GET_FUNCTION_GROUPS,
+ fid, index, 0, ret_payload);
+ if (ret) {
+ printf("%s failed\n", __func__);
+ return ret;
+ }
+
+ memcpy(groups, &ret_payload[1], PINCTRL_GET_FUNC_GROUPS_RESP_LEN);
+
+ return ret;
+}
+
+static int zynqmp_pinctrl_prepare_func_groups(u32 fid,
+ struct zynqmp_pmux_function *func,
+ struct zynqmp_pctrl_group *groups)
+{
+ const char **fgroups;
+ char name[MAX_GROUP_NAME_LEN];
+ u16 resp[NUM_GROUPS_PER_RESP] = {0};
+ int ret, index, i;
+
+ fgroups = kcalloc(func->ngroups, sizeof(*fgroups), GFP_KERNEL);
+ if (!fgroups)
+ return -ENOMEM;
+
+ for (index = 0; index < func->ngroups; index += NUM_GROUPS_PER_RESP) {
+ ret = zynqmp_pinctrl_get_function_groups(fid, index, resp);
+ if (ret)
+ return ret;
+
+ for (i = 0; i < NUM_GROUPS_PER_RESP; i++) {
+ if (resp[i] == (u16)NA_GROUP)
+ goto done;
+ if (resp[i] == (u16)RESERVED_GROUP)
+ continue;
+
+ snprintf(name, MAX_GROUP_NAME_LEN, "%s_%d_grp",
+ func->name, index + i);
+ fgroups[index + i] = strdup(name);
+
+ snprintf(name, MAX_GROUP_NAME_LEN, "%s_%d_grp",
+ func->name, index + i);
+ groups[resp[i]].name = strdup(name);
+ }
+ }
+done:
+ func->groups = fgroups;
+
+ return ret;
+}
+
+static int zynqmp_pinctrl_get_pin_groups(u32 pin, u32 index, u16 *groups)
+{
+ int ret;
+ u32 ret_payload[PAYLOAD_ARG_CNT];
+
+ ret = xilinx_pm_request(PM_QUERY_DATA, PM_QID_PINCTRL_GET_PIN_GROUPS,
+ pin, index, 0, ret_payload);
+ if (ret) {
+ printf("%s failed to get pin groups\n", __func__);
+ return ret;
+ }
+
+ memcpy(groups, &ret_payload[1], PINCTRL_GET_PIN_GROUPS_RESP_LEN);
+
+ return ret;
+}
+
+static void zynqmp_pinctrl_group_add_pin(struct zynqmp_pctrl_group *group,
+ unsigned int pin)
+{
+ group->pins[group->npins++] = pin;
+}
+
+static int zynqmp_pinctrl_create_pin_groups(struct zynqmp_pctrl_group *groups,
+ unsigned int pin)
+{
+ u16 resp[NUM_GROUPS_PER_RESP] = {0};
+ int ret, i, index = 0;
+
+ do {
+ ret = zynqmp_pinctrl_get_pin_groups(pin, index, resp);
+ if (ret)
+ return ret;
+
+ for (i = 0; i < NUM_GROUPS_PER_RESP; i++) {
+ if (resp[i] == (u16)NA_GROUP)
+ goto done;
+ if (resp[i] == (u16)RESERVED_GROUP)
+ continue;
+ zynqmp_pinctrl_group_add_pin(&groups[resp[i]], pin);
+ }
+ index += NUM_GROUPS_PER_RESP;
+ } while (index <= MAX_PIN_GROUPS);
+
+done:
+ return ret;
+}
+
+static int zynqmp_pinctrl_probe(struct udevice *dev)
+{
+ struct zynqmp_pinctrl_priv *priv = dev_get_priv(dev);
+ int ret, i;
+ u32 pin;
+ u32 ret_payload[PAYLOAD_ARG_CNT];
+
+ /* Get number of pins first */
+ ret = zynqmp_pm_query_data(PM_QID_PINCTRL_GET_NUM_PINS, 0, 0, &priv->npins);
+ if (ret) {
+ printf("%s failed to get no of pins\n", __func__);
+ return ret;
+ }
+
+ /* Get number of functions available */
+ ret = zynqmp_pm_query_data(PM_QID_PINCTRL_GET_NUM_FUNCTIONS, 0, 0, &priv->nfuncs);
+ if (ret) {
+ printf("%s failed to get no of functions\n", __func__);
+ return ret;
+ }
+
+ /* Allocating structures for functions and its groups */
+ priv->funcs = kzalloc(sizeof(*priv->funcs) * priv->nfuncs, GFP_KERNEL);
+ if (!priv->funcs)
+ return -ENOMEM;
+
+ for (i = 0; i < priv->nfuncs; i++) {
+ /* Get function name for the function and fill */
+ xilinx_pm_request(PM_QUERY_DATA, PM_QID_PINCTRL_GET_FUNCTION_NAME,
+ i, 0, 0, ret_payload);
+
+ memcpy((void *)priv->funcs[i].name, ret_payload, MAX_FUNC_NAME_LEN);
+
+ /* And fill number of groups available for certain function */
+ xilinx_pm_request(PM_QUERY_DATA, PM_QID_PINCTRL_GET_NUM_FUNCTION_GROUPS,
+ i, 0, 0, ret_payload);
+
+ priv->funcs[i].ngroups = ret_payload[1];
+ priv->ngroups += priv->funcs[i].ngroups;
+ }
+
+ /* Prepare all groups */
+ priv->groups = kzalloc(sizeof(*priv->groups) * priv->ngroups,
+ GFP_KERNEL);
+ if (!priv->groups)
+ return -ENOMEM;
+
+ for (i = 0; i < priv->nfuncs; i++) {
+ ret = zynqmp_pinctrl_prepare_func_groups(i, &priv->funcs[i],
+ priv->groups);
+ if (ret) {
+ printf("Failed to prepare_func_groups\n");
+ return ret;
+ }
+ }
+
+ for (pin = 0; pin < priv->npins; pin++) {
+ ret = zynqmp_pinctrl_create_pin_groups(priv->groups, pin);
+ if (ret)
+ return ret;
+ }
+
+ return 0;
+}
+
+static int zynqmp_pinctrl_get_functions_count(struct udevice *dev)
+{
+ struct zynqmp_pinctrl_priv *priv = dev_get_priv(dev);
+
+ return priv->nfuncs;
+}
+
+static const char *zynqmp_pinctrl_get_function_name(struct udevice *dev,
+ unsigned int selector)
+{
+ struct zynqmp_pinctrl_priv *priv = dev_get_priv(dev);
+
+ return priv->funcs[selector].name;
+}
+
+static int zynqmp_pinmux_set(struct udevice *dev, unsigned int selector,
+ unsigned int func_selector)
+{
+ int ret;
+
+ /* Request the pin first */
+ ret = xilinx_pm_request(PM_PINCTRL_REQUEST, selector, 0, 0, 0, NULL);
+ if (ret) {
+ printf("%s: pin request failed\n", __func__);
+ return ret;
+ }
+
+ /* Set the pin function */
+ ret = xilinx_pm_request(PM_PINCTRL_SET_FUNCTION, selector, func_selector,
+ 0, 0, NULL);
+ if (ret) {
+ printf("%s: Failed to set pinmux function\n", __func__);
+ return ret;
+ }
+
+ return 0;
+}
+
+static int zynqmp_pinmux_group_set(struct udevice *dev, unsigned int selector,
+ unsigned int func_selector)
+{
+ int i;
+ struct zynqmp_pinctrl_priv *priv = dev_get_priv(dev);
+ const struct zynqmp_pctrl_group *pgrp = &priv->groups[selector];
+
+ for (i = 0; i < pgrp->npins; i++)
+ zynqmp_pinmux_set(dev, pgrp->pins[i], func_selector);
+
+ return 0;
+}
+
+static int zynqmp_pinconf_set(struct udevice *dev, unsigned int pin,
+ unsigned int param, unsigned int arg)
+{
+ int ret = 0;
+ unsigned int value;
+
+ switch (param) {
+ case PIN_CONFIG_SLEW_RATE:
+ param = PM_PINCTRL_CONFIG_SLEW_RATE;
+ ret = zynqmp_pm_pinctrl_set_config(pin, param, arg);
+ break;
+ case PIN_CONFIG_BIAS_PULL_UP:
+ param = PM_PINCTRL_CONFIG_PULL_CTRL;
+ arg = PM_PINCTRL_BIAS_PULL_UP;
+ ret = zynqmp_pm_pinctrl_set_config(pin, param, arg);
+ break;
+ case PIN_CONFIG_BIAS_PULL_DOWN:
+ param = PM_PINCTRL_CONFIG_PULL_CTRL;
+ arg = PM_PINCTRL_BIAS_PULL_DOWN;
+ ret = zynqmp_pm_pinctrl_set_config(pin, param, arg);
+ break;
+ case PIN_CONFIG_BIAS_DISABLE:
+ param = PM_PINCTRL_CONFIG_BIAS_STATUS;
+ arg = PM_PINCTRL_BIAS_DISABLE;
+ ret = zynqmp_pm_pinctrl_set_config(pin, param, arg);
+ break;
+ case PIN_CONFIG_SCHMITTCMOS:
+ param = PM_PINCTRL_CONFIG_SCHMITT_CMOS;
+ ret = zynqmp_pm_pinctrl_set_config(pin, param, arg);
+ break;
+ case PIN_CONFIG_INPUT_SCHMITT_ENABLE:
+ param = PM_PINCTRL_CONFIG_SCHMITT_CMOS;
+ ret = zynqmp_pm_pinctrl_set_config(pin, param, arg);
+ break;
+ case PIN_CONFIG_DRIVE_STRENGTH:
+ switch (arg) {
+ case DRIVE_STRENGTH_2MA:
+ value = PM_PINCTRL_DRIVE_STRENGTH_2MA;
+ break;
+ case DRIVE_STRENGTH_4MA:
+ value = PM_PINCTRL_DRIVE_STRENGTH_4MA;
+ break;
+ case DRIVE_STRENGTH_8MA:
+ value = PM_PINCTRL_DRIVE_STRENGTH_8MA;
+ break;
+ case DRIVE_STRENGTH_12MA:
+ value = PM_PINCTRL_DRIVE_STRENGTH_12MA;
+ break;
+ default:
+ /* Invalid drive strength */
+ dev_warn(dev, "Invalid drive strength for pin %d\n", pin);
+ return -EINVAL;
+ }
+
+ param = PM_PINCTRL_CONFIG_DRIVE_STRENGTH;
+ ret = zynqmp_pm_pinctrl_set_config(pin, param, value);
+ break;
+ case PIN_CONFIG_IOSTANDARD:
+ param = PM_PINCTRL_CONFIG_VOLTAGE_STATUS;
+ ret = zynqmp_pm_pinctrl_get_config(pin, param, &value);
+ if (arg != value)
+ dev_warn(dev, "Invalid IO Standard requested for pin %d\n",
+ pin);
+ break;
+ case PIN_CONFIG_POWER_SOURCE:
+ param = PM_PINCTRL_CONFIG_VOLTAGE_STATUS;
+ ret = zynqmp_pm_pinctrl_get_config(pin, param, &value);
+ if (arg != value)
+ dev_warn(dev, "Invalid IO Standard requested for pin %d\n",
+ pin);
+ break;
+ case PIN_CONFIG_BIAS_HIGH_IMPEDANCE:
+ case PIN_CONFIG_LOW_POWER_MODE:
+ /*
+ * This cases are mentioned in dts but configurable
+ * registers are unknown. So falling through to ignore
+ * boot time warnings as of now.
+ */
+ ret = 0;
+ break;
+ default:
+ dev_warn(dev, "unsupported configuration parameter '%u'\n",
+ param);
+ ret = -ENOTSUPP;
+ break;
+ }
+
+ return ret;
+}
+
+static int zynqmp_pinconf_group_set(struct udevice *dev,
+ unsigned int group_selector,
+ unsigned int param, unsigned int arg)
+{
+ int i;
+ struct zynqmp_pinctrl_priv *priv = dev_get_priv(dev);
+ const struct zynqmp_pctrl_group *pgrp = &priv->groups[group_selector];
+
+ for (i = 0; i < pgrp->npins; i++)
+ zynqmp_pinconf_set(dev, pgrp->pins[i], param, arg);
+
+ return 0;
+}
+
+static int zynqmp_pinctrl_get_pins_count(struct udevice *dev)
+{
+ struct zynqmp_pinctrl_priv *priv = dev_get_priv(dev);
+
+ return priv->npins;
+}
+
+static const char *zynqmp_pinctrl_get_pin_name(struct udevice *dev,
+ unsigned int selector)
+{
+ snprintf(pin_name, PINNAME_SIZE, "MIO%d", selector);
+
+ return pin_name;
+}
+
+static int zynqmp_pinctrl_get_pin_muxing(struct udevice *dev,
+ unsigned int selector,
+ char *buf,
+ int size)
+{
+ struct zynqmp_pinctrl_config pinmux;
+
+ zynqmp_pm_pinctrl_get_config(selector, PM_PINCTRL_CONFIG_SLEW_RATE,
+ &pinmux.slew);
+ zynqmp_pm_pinctrl_get_config(selector, PM_PINCTRL_CONFIG_BIAS_STATUS,
+ &pinmux.bias);
+ zynqmp_pm_pinctrl_get_config(selector, PM_PINCTRL_CONFIG_PULL_CTRL,
+ &pinmux.pull_ctrl);
+ zynqmp_pm_pinctrl_get_config(selector, PM_PINCTRL_CONFIG_SCHMITT_CMOS,
+ &pinmux.input_type);
+ zynqmp_pm_pinctrl_get_config(selector, PM_PINCTRL_CONFIG_DRIVE_STRENGTH,
+ &pinmux.drive_strength);
+ zynqmp_pm_pinctrl_get_config(selector, PM_PINCTRL_CONFIG_VOLTAGE_STATUS,
+ &pinmux.volt_sts);
+
+ switch (pinmux.drive_strength) {
+ case PM_PINCTRL_DRIVE_STRENGTH_2MA:
+ pinmux.drive_strength = DRIVE_STRENGTH_2MA;
+ break;
+ case PM_PINCTRL_DRIVE_STRENGTH_4MA:
+ pinmux.drive_strength = DRIVE_STRENGTH_4MA;
+ break;
+ case PM_PINCTRL_DRIVE_STRENGTH_8MA:
+ pinmux.drive_strength = DRIVE_STRENGTH_8MA;
+ break;
+ case PM_PINCTRL_DRIVE_STRENGTH_12MA:
+ pinmux.drive_strength = DRIVE_STRENGTH_12MA;
+ break;
+ default:
+ /* Invalid drive strength */
+ dev_warn(dev, "Invalid drive strength\n");
+ return -EINVAL;
+ }
+
+ snprintf(buf, size, "slew:%s\tbias:%s\tpull:%s\tinput:%s\tdrive:%dmA\tvolt:%s",
+ pinmux.slew ? "slow" : "fast",
+ pinmux.bias ? "enabled" : "disabled",
+ pinmux.pull_ctrl ? "up" : "down",
+ pinmux.input_type ? "schmitt" : "cmos",
+ pinmux.drive_strength,
+ pinmux.volt_sts ? "1.8" : "3.3");
+
+ return 0;
+}
+
+static int zynqmp_pinctrl_get_groups_count(struct udevice *dev)
+{
+ struct zynqmp_pinctrl_priv *priv = dev_get_priv(dev);
+
+ return priv->ngroups;
+}
+
+static const char *zynqmp_pinctrl_get_group_name(struct udevice *dev,
+ unsigned int selector)
+{
+ struct zynqmp_pinctrl_priv *priv = dev_get_priv(dev);
+
+ return priv->groups[selector].name;
+}
+
+static const struct pinconf_param zynqmp_conf_params[] = {
+ { "bias-bus-hold", PIN_CONFIG_BIAS_BUS_HOLD, 0 },
+ { "bias-disable", PIN_CONFIG_BIAS_DISABLE, 0 },
+ { "bias-high-impedance", PIN_CONFIG_BIAS_HIGH_IMPEDANCE, 0 },
+ { "bias-pull-up", PIN_CONFIG_BIAS_PULL_UP, 1 },
+ { "bias-pull-pin-default", PIN_CONFIG_BIAS_PULL_PIN_DEFAULT, 1 },
+ { "bias-pull-down", PIN_CONFIG_BIAS_PULL_DOWN, 1 },
+ { "drive-open-drain", PIN_CONFIG_DRIVE_OPEN_DRAIN, 0 },
+ { "drive-open-source", PIN_CONFIG_DRIVE_OPEN_SOURCE, 0 },
+ { "drive-push-pull", PIN_CONFIG_DRIVE_PUSH_PULL, 0 },
+ { "drive-strength", PIN_CONFIG_DRIVE_STRENGTH, 0 },
+ { "drive-strength-microamp", PIN_CONFIG_DRIVE_STRENGTH_UA, 0 },
+ { "input-debounce", PIN_CONFIG_INPUT_DEBOUNCE, 0 },
+ { "input-disable", PIN_CONFIG_INPUT_ENABLE, 0 },
+ { "input-enable", PIN_CONFIG_INPUT_ENABLE, 1 },
+ { "input-schmitt", PIN_CONFIG_INPUT_SCHMITT, 0 },
+ { "input-schmitt-disable", PIN_CONFIG_INPUT_SCHMITT_ENABLE, 0 },
+ { "input-schmitt-enable", PIN_CONFIG_INPUT_SCHMITT_ENABLE, 1 },
+ { "low-power-disable", PIN_CONFIG_LOW_POWER_MODE, 0 },
+ { "low-power-enable", PIN_CONFIG_LOW_POWER_MODE, 1 },
+ { "output-disable", PIN_CONFIG_OUTPUT_ENABLE, 0 },
+ { "output-enable", PIN_CONFIG_OUTPUT_ENABLE, 1 },
+ { "output-high", PIN_CONFIG_OUTPUT, 1, },
+ { "output-low", PIN_CONFIG_OUTPUT, 0, },
+ { "power-source", PIN_CONFIG_POWER_SOURCE, 0 },
+ { "sleep-hardware-state", PIN_CONFIG_SLEEP_HARDWARE_STATE, 0 },
+ { "slew-rate", PIN_CONFIG_SLEW_RATE, 0 },
+ { "skew-delay", PIN_CONFIG_SKEW_DELAY, 0 },
+ /* zynqmp specific */
+ {"io-standard", PIN_CONFIG_IOSTANDARD, IO_STANDARD_LVCMOS18},
+ {"schmitt-cmos", PIN_CONFIG_SCHMITTCMOS, PM_PINCTRL_INPUT_TYPE_SCHMITT},
+};
+
+static struct pinctrl_ops zynqmp_pinctrl_ops = {
+ .get_pins_count = zynqmp_pinctrl_get_pins_count,
+ .get_pin_name = zynqmp_pinctrl_get_pin_name,
+ .get_pin_muxing = zynqmp_pinctrl_get_pin_muxing,
+ .set_state = pinctrl_generic_set_state,
+ .get_groups_count = zynqmp_pinctrl_get_groups_count,
+ .get_group_name = zynqmp_pinctrl_get_group_name,
+ .get_functions_count = zynqmp_pinctrl_get_functions_count,
+ .get_function_name = zynqmp_pinctrl_get_function_name,
+ .pinmux_group_set = zynqmp_pinmux_group_set,
+ .pinmux_set = zynqmp_pinmux_set,
+ .pinconf_params = zynqmp_conf_params,
+ .pinconf_group_set = zynqmp_pinconf_group_set,
+ .pinconf_set = zynqmp_pinconf_set,
+ .pinconf_num_params = ARRAY_SIZE(zynqmp_conf_params),
+};
+
+static const struct udevice_id zynqmp_pinctrl_ids[] = {
+ { .compatible = "xlnx,zynqmp-pinctrl" },
+ { }
+};
+
+U_BOOT_DRIVER(pinctrl_zynqmp) = {
+ .name = "zynqmp-pinctrl",
+ .id = UCLASS_PINCTRL,
+ .of_match = zynqmp_pinctrl_ids,
+ .priv_auto = sizeof(struct zynqmp_pinctrl_priv),
+ .ops = &zynqmp_pinctrl_ops,
+ .probe = zynqmp_pinctrl_probe,
+};