pinctrl: tegra: add XUSB pad controller
This is a combined pincontrol/PHY driver for the SerDes lanes on Tegra K1. Signed-off-by: Lucas Stach <dev@lynxeye.de> Signed-off-by: Sascha Hauer <s.hauer@pengutronix.de>
This commit is contained in:
parent
3e41e7561a
commit
d712ce1824
|
@ -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
|
||||
|
|
|
@ -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/
|
||||
|
|
|
@ -0,0 +1,519 @@
|
|||
/*
|
||||
* Copyright (C) 2014 Lucas Stach <l.stach@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);
|
Loading…
Reference in New Issue