[PATCH 12/13] pinctrl: tegra: add XUSB pad controller

Lucas Stach dev at lynxeye.de
Sun Nov 2 12:13:54 PST 2014


This is a combined pincontrol/PHY driver for
the SerDes lanes on Tegra K1.

Signed-off-by: Lucas Stach <dev at lynxeye.de>
---
 drivers/pinctrl/Kconfig              |   8 +
 drivers/pinctrl/Makefile             |   1 +
 drivers/pinctrl/pinctrl-tegra-xusb.c | 519 +++++++++++++++++++++++++++++++++++
 3 files changed, 528 insertions(+)
 create mode 100644 drivers/pinctrl/pinctrl-tegra-xusb.c

diff --git a/drivers/pinctrl/Kconfig b/drivers/pinctrl/Kconfig
index 770fb2d..4cbc167 100644
--- a/drivers/pinctrl/Kconfig
+++ b/drivers/pinctrl/Kconfig
@@ -60,6 +60,14 @@ config PINCTRL_TEGRA30
 	help
 	  The pinmux controller found on the Tegra 30+ line of SoCs.
 
+config PINCTRL_TEGRA_XUSB
+	bool
+	default y if ARCH_TEGRA_124_SOC
+	select GENERIC_PHY
+	help
+	  The pinmux controller found on the Tegra 124 line of SoCs used for
+	  the SerDes lanes.
+
 source drivers/pinctrl/mvebu/Kconfig
 
 endif
diff --git a/drivers/pinctrl/Makefile b/drivers/pinctrl/Makefile
index 3ea8649..724e6d7 100644
--- a/drivers/pinctrl/Makefile
+++ b/drivers/pinctrl/Makefile
@@ -7,5 +7,6 @@ obj-$(CONFIG_PINCTRL_ROCKCHIP) += pinctrl-rockchip.o
 obj-$(CONFIG_PINCTRL_SINGLE) += pinctrl-single.o
 obj-$(CONFIG_PINCTRL_TEGRA20) += pinctrl-tegra20.o
 obj-$(CONFIG_PINCTRL_TEGRA30) += pinctrl-tegra30.o
+obj-$(CONFIG_PINCTRL_TEGRA_XUSB) += pinctrl-tegra-xusb.o
 
 obj-$(CONFIG_ARCH_MVEBU) += mvebu/
diff --git a/drivers/pinctrl/pinctrl-tegra-xusb.c b/drivers/pinctrl/pinctrl-tegra-xusb.c
new file mode 100644
index 0000000..05cdecb
--- /dev/null
+++ b/drivers/pinctrl/pinctrl-tegra-xusb.c
@@ -0,0 +1,519 @@
+/*
+ * Copyright (C) 2014 Lucas Stach <l.stach at pengutronix.de>
+ *
+ * Partly based on code
+ * Copyright (C) 2014, NVIDIA CORPORATION.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <common.h>
+#include <clock.h>
+#include <init.h>
+#include <io.h>
+#include <malloc.h>
+#include <pinctrl.h>
+#include <linux/err.h>
+#include <linux/reset.h>
+#include <linux/phy/phy.h>
+
+#include <dt-bindings/pinctrl/pinctrl-tegra-xusb.h>
+
+#define XUSB_PADCTL_ELPG_PROGRAM 0x01c
+#define XUSB_PADCTL_ELPG_PROGRAM_AUX_MUX_LP0_VCORE_DOWN (1 << 26)
+#define XUSB_PADCTL_ELPG_PROGRAM_AUX_MUX_LP0_CLAMP_EN_EARLY (1 << 25)
+#define XUSB_PADCTL_ELPG_PROGRAM_AUX_MUX_LP0_CLAMP_EN (1 << 24)
+
+#define XUSB_PADCTL_IOPHY_PLL_P0_CTL1 0x040
+#define XUSB_PADCTL_IOPHY_PLL_P0_CTL1_PLL0_LOCKDET (1 << 19)
+#define XUSB_PADCTL_IOPHY_PLL_P0_CTL1_REFCLK_SEL_MASK (0xf << 12)
+#define XUSB_PADCTL_IOPHY_PLL_P0_CTL1_PLL_RST (1 << 1)
+
+#define XUSB_PADCTL_IOPHY_PLL_P0_CTL2 0x044
+#define XUSB_PADCTL_IOPHY_PLL_P0_CTL2_REFCLKBUF_EN (1 << 6)
+#define XUSB_PADCTL_IOPHY_PLL_P0_CTL2_TXCLKREF_EN (1 << 5)
+#define XUSB_PADCTL_IOPHY_PLL_P0_CTL2_TXCLKREF_SEL (1 << 4)
+
+#define XUSB_PADCTL_IOPHY_PLL_S0_CTL1 0x138
+#define XUSB_PADCTL_IOPHY_PLL_S0_CTL1_PLL1_LOCKDET (1 << 27)
+#define XUSB_PADCTL_IOPHY_PLL_S0_CTL1_PLL1_MODE (1 << 24)
+#define XUSB_PADCTL_IOPHY_PLL_S0_CTL1_PLL_PWR_OVRD (1 << 3)
+#define XUSB_PADCTL_IOPHY_PLL_S0_CTL1_PLL_RST (1 << 1)
+#define XUSB_PADCTL_IOPHY_PLL_S0_CTL1_PLL_IDDQ (1 << 0)
+
+#define XUSB_PADCTL_IOPHY_MISC_PAD_S0_CTL1 0x148
+#define XUSB_PADCTL_IOPHY_MISC_PAD_S0_CTL1_IDDQ_OVRD (1 << 1)
+#define XUSB_PADCTL_IOPHY_MISC_PAD_S0_CTL1_IDDQ (1 << 0)
+
+struct tegra_xusb_padctl_soc {
+	const struct tegra_xusb_padctl_lane *lanes;
+	unsigned int num_lanes;
+};
+
+struct tegra_xusb_padctl_lane {
+	const char *name;
+
+	unsigned int offset;
+	unsigned int shift;
+	unsigned int mask;
+	unsigned int iddq;
+
+	const char **funcs;
+	unsigned int num_funcs;
+};
+
+struct tegra_xusb_padctl {
+	struct device_d *dev;
+	void __iomem *regs;
+	struct reset_control *rst;
+
+	const struct tegra_xusb_padctl_soc *soc;
+	struct pinctrl_device pinctrl;
+
+	struct phy_provider *provider;
+	struct phy *phys[2];
+
+	unsigned int enable;
+};
+
+static inline void padctl_writel(struct tegra_xusb_padctl *padctl, u32 value,
+				 unsigned long offset)
+{
+	writel(value, padctl->regs + offset);
+}
+
+static inline u32 padctl_readl(struct tegra_xusb_padctl *padctl,
+			       unsigned long offset)
+{
+	return readl(padctl->regs + offset);
+}
+
+static int tegra_xusb_padctl_enable(struct tegra_xusb_padctl *padctl)
+{
+	u32 value;
+
+	if (padctl->enable++ > 0)
+		return 0;
+
+	value = padctl_readl(padctl, XUSB_PADCTL_ELPG_PROGRAM);
+	value &= ~XUSB_PADCTL_ELPG_PROGRAM_AUX_MUX_LP0_CLAMP_EN;
+	padctl_writel(padctl, value, XUSB_PADCTL_ELPG_PROGRAM);
+
+	udelay(100);
+
+	value = padctl_readl(padctl, XUSB_PADCTL_ELPG_PROGRAM);
+	value &= ~XUSB_PADCTL_ELPG_PROGRAM_AUX_MUX_LP0_CLAMP_EN_EARLY;
+	padctl_writel(padctl, value, XUSB_PADCTL_ELPG_PROGRAM);
+
+	udelay(100);
+
+	value = padctl_readl(padctl, XUSB_PADCTL_ELPG_PROGRAM);
+	value &= ~XUSB_PADCTL_ELPG_PROGRAM_AUX_MUX_LP0_VCORE_DOWN;
+	padctl_writel(padctl, value, XUSB_PADCTL_ELPG_PROGRAM);
+
+	return 0;
+}
+
+static int tegra_xusb_padctl_disable(struct tegra_xusb_padctl *padctl)
+{
+	u32 value;
+
+	if (WARN_ON(padctl->enable == 0))
+		return 0;
+
+	if (--padctl->enable > 0)
+		return 0;
+
+	value = padctl_readl(padctl, XUSB_PADCTL_ELPG_PROGRAM);
+	value |= XUSB_PADCTL_ELPG_PROGRAM_AUX_MUX_LP0_VCORE_DOWN;
+	padctl_writel(padctl, value, XUSB_PADCTL_ELPG_PROGRAM);
+
+	udelay(100);
+
+	value = padctl_readl(padctl, XUSB_PADCTL_ELPG_PROGRAM);
+	value |= XUSB_PADCTL_ELPG_PROGRAM_AUX_MUX_LP0_CLAMP_EN_EARLY;
+	padctl_writel(padctl, value, XUSB_PADCTL_ELPG_PROGRAM);
+
+	udelay(100);
+
+	value = padctl_readl(padctl, XUSB_PADCTL_ELPG_PROGRAM);
+	value |= XUSB_PADCTL_ELPG_PROGRAM_AUX_MUX_LP0_CLAMP_EN;
+	padctl_writel(padctl, value, XUSB_PADCTL_ELPG_PROGRAM);
+
+	return 0;
+}
+
+static int tegra_xusb_phy_init(struct phy *phy)
+{
+	struct tegra_xusb_padctl *padctl = phy_get_drvdata(phy);
+
+	return tegra_xusb_padctl_enable(padctl);
+}
+
+static int tegra_xusb_phy_exit(struct phy *phy)
+{
+	struct tegra_xusb_padctl *padctl = phy_get_drvdata(phy);
+
+	return tegra_xusb_padctl_disable(padctl);
+}
+
+static int pcie_phy_power_on(struct phy *phy)
+{
+	struct tegra_xusb_padctl *padctl = phy_get_drvdata(phy);
+	int err;
+	u32 value;
+
+	value = padctl_readl(padctl, XUSB_PADCTL_IOPHY_PLL_P0_CTL1);
+	value &= ~XUSB_PADCTL_IOPHY_PLL_P0_CTL1_REFCLK_SEL_MASK;
+	padctl_writel(padctl, value, XUSB_PADCTL_IOPHY_PLL_P0_CTL1);
+
+	value = padctl_readl(padctl, XUSB_PADCTL_IOPHY_PLL_P0_CTL2);
+	value |= XUSB_PADCTL_IOPHY_PLL_P0_CTL2_REFCLKBUF_EN |
+		 XUSB_PADCTL_IOPHY_PLL_P0_CTL2_TXCLKREF_EN |
+		 XUSB_PADCTL_IOPHY_PLL_P0_CTL2_TXCLKREF_SEL;
+	padctl_writel(padctl, value, XUSB_PADCTL_IOPHY_PLL_P0_CTL2);
+
+	value = padctl_readl(padctl, XUSB_PADCTL_IOPHY_PLL_P0_CTL1);
+	value |= XUSB_PADCTL_IOPHY_PLL_P0_CTL1_PLL_RST;
+	padctl_writel(padctl, value, XUSB_PADCTL_IOPHY_PLL_P0_CTL1);
+
+	err = wait_on_timeout(50 * MSECOND,
+			padctl_readl(padctl, XUSB_PADCTL_IOPHY_PLL_P0_CTL1) &
+			XUSB_PADCTL_IOPHY_PLL_P0_CTL1_PLL0_LOCKDET);
+
+	return err;
+}
+
+static int pcie_phy_power_off(struct phy *phy)
+{
+	struct tegra_xusb_padctl *padctl = phy_get_drvdata(phy);
+	u32 value;
+
+	value = padctl_readl(padctl, XUSB_PADCTL_IOPHY_PLL_P0_CTL1);
+	value &= ~XUSB_PADCTL_IOPHY_PLL_P0_CTL1_PLL_RST;
+	padctl_writel(padctl, value, XUSB_PADCTL_IOPHY_PLL_P0_CTL1);
+
+	return 0;
+}
+
+static const struct phy_ops pcie_phy_ops = {
+
+	.init = tegra_xusb_phy_init,
+	.exit = tegra_xusb_phy_exit,
+	.power_on = pcie_phy_power_on,
+	.power_off = pcie_phy_power_off,
+};
+
+static int sata_phy_power_on(struct phy *phy)
+{
+	struct tegra_xusb_padctl *padctl = phy_get_drvdata(phy);
+	int err;
+	u32 value;
+
+	value = padctl_readl(padctl, XUSB_PADCTL_IOPHY_MISC_PAD_S0_CTL1);
+	value &= ~XUSB_PADCTL_IOPHY_MISC_PAD_S0_CTL1_IDDQ_OVRD;
+	value &= ~XUSB_PADCTL_IOPHY_MISC_PAD_S0_CTL1_IDDQ;
+	padctl_writel(padctl, value, XUSB_PADCTL_IOPHY_MISC_PAD_S0_CTL1);
+
+	value = padctl_readl(padctl, XUSB_PADCTL_IOPHY_PLL_S0_CTL1);
+	value &= ~XUSB_PADCTL_IOPHY_PLL_S0_CTL1_PLL_PWR_OVRD;
+	value &= ~XUSB_PADCTL_IOPHY_PLL_S0_CTL1_PLL_IDDQ;
+	padctl_writel(padctl, value, XUSB_PADCTL_IOPHY_PLL_S0_CTL1);
+
+	value = padctl_readl(padctl, XUSB_PADCTL_IOPHY_PLL_S0_CTL1);
+	value |= XUSB_PADCTL_IOPHY_PLL_S0_CTL1_PLL1_MODE;
+	padctl_writel(padctl, value, XUSB_PADCTL_IOPHY_PLL_S0_CTL1);
+
+	value = padctl_readl(padctl, XUSB_PADCTL_IOPHY_PLL_S0_CTL1);
+	value |= XUSB_PADCTL_IOPHY_PLL_S0_CTL1_PLL_RST;
+	padctl_writel(padctl, value, XUSB_PADCTL_IOPHY_PLL_S0_CTL1);
+
+	err = wait_on_timeout(50 * MSECOND,
+			padctl_readl(padctl, XUSB_PADCTL_IOPHY_PLL_S0_CTL1) &
+			XUSB_PADCTL_IOPHY_PLL_S0_CTL1_PLL1_LOCKDET);
+
+	return err;
+}
+
+static int sata_phy_power_off(struct phy *phy)
+{
+	struct tegra_xusb_padctl *padctl = phy_get_drvdata(phy);
+	u32 value;
+
+	value = padctl_readl(padctl, XUSB_PADCTL_IOPHY_PLL_S0_CTL1);
+	value &= ~XUSB_PADCTL_IOPHY_PLL_S0_CTL1_PLL_RST;
+	padctl_writel(padctl, value, XUSB_PADCTL_IOPHY_PLL_S0_CTL1);
+
+	value = padctl_readl(padctl, XUSB_PADCTL_IOPHY_PLL_S0_CTL1);
+	value &= ~XUSB_PADCTL_IOPHY_PLL_S0_CTL1_PLL1_MODE;
+	padctl_writel(padctl, value, XUSB_PADCTL_IOPHY_PLL_S0_CTL1);
+
+	value = padctl_readl(padctl, XUSB_PADCTL_IOPHY_PLL_S0_CTL1);
+	value |= XUSB_PADCTL_IOPHY_PLL_S0_CTL1_PLL_PWR_OVRD;
+	value |= XUSB_PADCTL_IOPHY_PLL_S0_CTL1_PLL_IDDQ;
+	padctl_writel(padctl, value, XUSB_PADCTL_IOPHY_PLL_S0_CTL1);
+
+	value = padctl_readl(padctl, XUSB_PADCTL_IOPHY_MISC_PAD_S0_CTL1);
+	value |= ~XUSB_PADCTL_IOPHY_MISC_PAD_S0_CTL1_IDDQ_OVRD;
+	value |= ~XUSB_PADCTL_IOPHY_MISC_PAD_S0_CTL1_IDDQ;
+	padctl_writel(padctl, value, XUSB_PADCTL_IOPHY_MISC_PAD_S0_CTL1);
+
+	return 0;
+}
+
+static const struct phy_ops sata_phy_ops = {
+
+	.init = tegra_xusb_phy_init,
+	.exit = tegra_xusb_phy_exit,
+	.power_on = sata_phy_power_on,
+	.power_off = sata_phy_power_off,
+};
+
+static struct phy *tegra_xusb_padctl_xlate(struct device_d *dev,
+					   struct of_phandle_args *args)
+{
+	struct tegra_xusb_padctl *padctl = dev->priv;
+	unsigned int index = args->args[0];
+
+	if (args->args_count <= 0)
+		return ERR_PTR(-EINVAL);
+
+	if (index >= ARRAY_SIZE(padctl->phys))
+		return ERR_PTR(-EINVAL);
+
+	return padctl->phys[index];
+}
+
+static int pinctrl_tegra_xusb_set_state(struct pinctrl_device *pdev,
+					struct device_node *np)
+{
+	struct tegra_xusb_padctl *padctl =
+			container_of(pdev, struct tegra_xusb_padctl, pinctrl);
+	struct device_node *childnode;
+	int iddq = -1, i, j, k;
+	const char *lanes, *func = NULL;
+	const struct tegra_xusb_padctl_lane *lane = NULL;
+	u32 val;
+
+	/*
+	 * At first look if the node we are pointed at has children,
+	 * which we may want to visit.
+	 */
+	list_for_each_entry(childnode, &np->children, parent_list)
+		pinctrl_tegra_xusb_set_state(pdev, childnode);
+
+	/* read relevant state from devicetree */
+	of_property_read_string(np, "nvidia,function", &func);
+	of_property_read_u32_array(np, "nvidia,iddq", &iddq, 1);
+
+	/* iterate over all lanes referenced in the dt node */
+	for (i = 0; ; i++) {
+		if (of_property_read_string_index(np, "nvidia,lanes", i, &lanes))
+			break;
+
+		for (j = 0; j < padctl->soc->num_lanes; j++) {
+			if (!strcmp(lanes, padctl->soc->lanes[j].name)) {
+				lane = &padctl->soc->lanes[j];
+				break;
+			}
+		}
+		/* if no matching lane is found */
+		if (j == padctl->soc->num_lanes) {
+			/* nothing matching found, warn and bail out */
+			dev_warn(padctl->pinctrl.dev,
+				 "invalid lane %s referenced in node %s\n",
+				 lanes, np->name);
+			continue;
+		}
+
+		if (func) {
+			for (k = 0; k < lane->num_funcs; k++) {
+				if (!strcmp(func, lane->funcs[k]))
+					break;
+			}
+			if (k < lane->num_funcs) {
+				val = padctl_readl(padctl, lane->offset);
+				val &= ~(lane->mask << lane->shift);
+				val |= k << lane->shift;
+				padctl_writel(padctl, val, lane->offset);
+			} else {
+				dev_warn(padctl->pinctrl.dev,
+					 "invalid function %s for lane %s in node %s\n",
+					 func, lane->name, np->name);
+			}
+		}
+
+		if (iddq >= 0) {
+			if (lane->iddq) {
+				val = padctl_readl(padctl, lane->offset);
+				if (iddq)
+					val &= ~BIT(lane->iddq);
+				else
+					val |= BIT(lane->iddq);
+				padctl_writel(padctl, val, lane->offset);
+			} else {
+				dev_warn(padctl->pinctrl.dev,
+					 "invalid iddq setting for lane %s in node %s\n",
+					 lane->name, np->name);
+			}
+		}
+	}
+
+	return 0;
+}
+
+static struct pinctrl_ops pinctrl_tegra_xusb_ops = {
+	.set_state = pinctrl_tegra_xusb_set_state,
+};
+
+static int pinctrl_tegra_xusb_probe(struct device_d *dev)
+{
+	struct tegra_xusb_padctl *padctl;
+	struct phy *phy;
+	int err;
+
+	padctl = xzalloc(sizeof(*padctl));
+
+	dev->priv = padctl;
+	padctl->dev = dev;
+
+	dev_get_drvdata(dev, (unsigned long *)&padctl->soc);
+
+	padctl->regs = dev_request_mem_region(dev, 0);
+	if (IS_ERR(padctl->regs)) {
+		dev_err(dev, "Could not get iomem region\n");
+		return PTR_ERR(padctl->regs);
+	}
+
+	padctl->rst = reset_control_get(dev, NULL);
+	if (IS_ERR(padctl->rst))
+		return PTR_ERR(padctl->rst);
+
+	err = reset_control_deassert(padctl->rst);
+	if (err < 0)
+		return err;
+
+	padctl->pinctrl.dev = dev;
+	padctl->pinctrl.ops = &pinctrl_tegra_xusb_ops;
+
+	err = pinctrl_register(&padctl->pinctrl);
+	if (err) {
+		dev_err(dev, "failed to register pincontrol\n");
+		err = -ENODEV;
+		goto reset;
+	}
+
+	phy = phy_create(dev, NULL, &pcie_phy_ops, NULL);
+	if (IS_ERR(phy)) {
+		err = PTR_ERR(phy);
+		goto unregister;
+	}
+
+	padctl->phys[TEGRA_XUSB_PADCTL_PCIE] = phy;
+	phy_set_drvdata(phy, padctl);
+
+	phy = phy_create(dev, NULL, &sata_phy_ops, NULL);
+	if (IS_ERR(phy)) {
+		err = PTR_ERR(phy);
+		goto unregister;
+	}
+
+	padctl->phys[TEGRA_XUSB_PADCTL_SATA] = phy;
+	phy_set_drvdata(phy, padctl);
+
+	padctl->provider = of_phy_provider_register(dev, tegra_xusb_padctl_xlate);
+	if (IS_ERR(padctl->provider)) {
+		err = PTR_ERR(padctl->provider);
+		dev_err(dev, "failed to register PHYs: %d\n", err);
+		goto unregister;
+	}
+
+	return 0;
+
+unregister:
+	pinctrl_unregister(&padctl->pinctrl);
+reset:
+	reset_control_assert(padctl->rst);
+	return err;
+}
+
+static const char *tegra124_otg_functions[] = {
+	"snps",
+	"xusb",
+	"uart",
+	"rsvd",
+};
+
+static const char *tegra124_usb_functions[] = {
+	"snps",
+	"xusb",
+};
+
+static const char *tegra124_pci_functions[] = {
+	"pcie",
+	"usb3",
+	"sata",
+	"rsvd",
+};
+
+#define TEGRA124_LANE(_name, _offs, _shift, _mask, _iddq, _funcs, _num)	\
+	{								\
+		.name = _name,						\
+		.offset = _offs,					\
+		.shift = _shift,					\
+		.mask = _mask,						\
+		.iddq = _iddq,						\
+		.num_funcs = _num,					\
+		.funcs = tegra124_##_funcs##_functions,			\
+	}
+
+static const struct tegra_xusb_padctl_lane tegra124_lanes[] = {
+	TEGRA124_LANE("otg-0",  0x004,  0, 0x3, 0, otg, 4),
+	TEGRA124_LANE("otg-1",  0x004,  2, 0x3, 0, otg, 4),
+	TEGRA124_LANE("otg-2",  0x004,  4, 0x3, 0, otg, 4),
+	TEGRA124_LANE("ulpi-0", 0x004, 12, 0x1, 0, usb, 2),
+	TEGRA124_LANE("hsic-0", 0x004, 14, 0x1, 0, usb, 2),
+	TEGRA124_LANE("hsic-1", 0x004, 15, 0x1, 0, usb, 2),
+	TEGRA124_LANE("pcie-0", 0x134, 16, 0x3, 1, pci, 4),
+	TEGRA124_LANE("pcie-1", 0x134, 18, 0x3, 2, pci, 4),
+	TEGRA124_LANE("pcie-2", 0x134, 20, 0x3, 3, pci, 4),
+	TEGRA124_LANE("pcie-3", 0x134, 22, 0x3, 4, pci, 4),
+	TEGRA124_LANE("pcie-4", 0x134, 24, 0x3, 5, pci, 4),
+	TEGRA124_LANE("sata-0", 0x134, 26, 0x3, 6, pci, 4),
+};
+
+static const struct tegra_xusb_padctl_soc tegra124_soc = {
+	.num_lanes = ARRAY_SIZE(tegra124_lanes),
+	.lanes = tegra124_lanes,
+};
+
+static __maybe_unused struct of_device_id pinctrl_tegra_xusb_dt_ids[] = {
+	{
+		.compatible = "nvidia,tegra124-xusb-padctl",
+		.data = (unsigned long)&tegra124_soc,
+	}, {
+		/* sentinel */
+	}
+};
+
+static struct driver_d pinctrl_tegra_xusb_driver = {
+	.name		= "pinctrl-tegra-xusb",
+	.probe		= pinctrl_tegra_xusb_probe,
+	.of_compatible	= DRV_OF_COMPAT(pinctrl_tegra_xusb_dt_ids),
+};
+
+static int pinctrl_tegra_xusb_init(void)
+{
+	return platform_driver_register(&pinctrl_tegra_xusb_driver);
+}
+postcore_initcall(pinctrl_tegra_xusb_init);
-- 
1.9.3




More information about the barebox mailing list