xref: /openbmc/linux/drivers/phy/tegra/xusb.c (revision 3dd6e0fa)
12025cf9eSThomas Gleixner // SPDX-License-Identifier: GPL-2.0-only
253d2a715SThierry Reding /*
377bfa0fcSJim Lin  * Copyright (c) 2014-2022, NVIDIA CORPORATION.  All rights reserved.
453d2a715SThierry Reding  */
553d2a715SThierry Reding 
653d2a715SThierry Reding #include <linux/delay.h>
753d2a715SThierry Reding #include <linux/io.h>
853d2a715SThierry Reding #include <linux/mailbox_client.h>
953d2a715SThierry Reding #include <linux/module.h>
1053d2a715SThierry Reding #include <linux/of.h>
117559e757SRob Herring #include <linux/of_platform.h>
1253d2a715SThierry Reding #include <linux/phy/phy.h>
130674b440SBaoyou Xie #include <linux/phy/tegra/xusb.h>
1453d2a715SThierry Reding #include <linux/platform_device.h>
1553d2a715SThierry Reding #include <linux/regulator/consumer.h>
1653d2a715SThierry Reding #include <linux/reset.h>
1753d2a715SThierry Reding #include <linux/slab.h>
1853d2a715SThierry Reding #include <linux/workqueue.h>
1953d2a715SThierry Reding 
2053d2a715SThierry Reding #include <soc/tegra/fuse.h>
2153d2a715SThierry Reding 
2253d2a715SThierry Reding #include "xusb.h"
2353d2a715SThierry Reding 
tegra_xusb_pad_of_xlate(struct device * dev,struct of_phandle_args * args)2453d2a715SThierry Reding static struct phy *tegra_xusb_pad_of_xlate(struct device *dev,
2553d2a715SThierry Reding 					   struct of_phandle_args *args)
2653d2a715SThierry Reding {
2753d2a715SThierry Reding 	struct tegra_xusb_pad *pad = dev_get_drvdata(dev);
2853d2a715SThierry Reding 	struct phy *phy = NULL;
2953d2a715SThierry Reding 	unsigned int i;
3053d2a715SThierry Reding 
3153d2a715SThierry Reding 	if (args->args_count != 0)
3253d2a715SThierry Reding 		return ERR_PTR(-EINVAL);
3353d2a715SThierry Reding 
3453d2a715SThierry Reding 	for (i = 0; i < pad->soc->num_lanes; i++) {
3553d2a715SThierry Reding 		if (!pad->lanes[i])
3653d2a715SThierry Reding 			continue;
3753d2a715SThierry Reding 
3853d2a715SThierry Reding 		if (pad->lanes[i]->dev.of_node == args->np) {
3953d2a715SThierry Reding 			phy = pad->lanes[i];
4053d2a715SThierry Reding 			break;
4153d2a715SThierry Reding 		}
4253d2a715SThierry Reding 	}
4353d2a715SThierry Reding 
4453d2a715SThierry Reding 	if (phy == NULL)
4553d2a715SThierry Reding 		phy = ERR_PTR(-ENODEV);
4653d2a715SThierry Reding 
4753d2a715SThierry Reding 	return phy;
4853d2a715SThierry Reding }
4953d2a715SThierry Reding 
5053d2a715SThierry Reding static const struct of_device_id tegra_xusb_padctl_of_match[] = {
5153d2a715SThierry Reding #if defined(CONFIG_ARCH_TEGRA_124_SOC) || defined(CONFIG_ARCH_TEGRA_132_SOC)
5253d2a715SThierry Reding 	{
5353d2a715SThierry Reding 		.compatible = "nvidia,tegra124-xusb-padctl",
5453d2a715SThierry Reding 		.data = &tegra124_xusb_padctl_soc,
5553d2a715SThierry Reding 	},
5653d2a715SThierry Reding #endif
5753d2a715SThierry Reding #if defined(CONFIG_ARCH_TEGRA_210_SOC)
5853d2a715SThierry Reding 	{
5953d2a715SThierry Reding 		.compatible = "nvidia,tegra210-xusb-padctl",
6053d2a715SThierry Reding 		.data = &tegra210_xusb_padctl_soc,
6153d2a715SThierry Reding 	},
6253d2a715SThierry Reding #endif
63bbf71168SJC Kuo #if defined(CONFIG_ARCH_TEGRA_186_SOC)
64bbf71168SJC Kuo 	{
65bbf71168SJC Kuo 		.compatible = "nvidia,tegra186-xusb-padctl",
66bbf71168SJC Kuo 		.data = &tegra186_xusb_padctl_soc,
67bbf71168SJC Kuo 	},
68bbf71168SJC Kuo #endif
691ef535c6SJC Kuo #if defined(CONFIG_ARCH_TEGRA_194_SOC)
701ef535c6SJC Kuo 	{
711ef535c6SJC Kuo 		.compatible = "nvidia,tegra194-xusb-padctl",
721ef535c6SJC Kuo 		.data = &tegra194_xusb_padctl_soc,
731ef535c6SJC Kuo 	},
741ef535c6SJC Kuo #endif
755c7f94f8SSing-Han Chen #if defined(CONFIG_ARCH_TEGRA_234_SOC)
765c7f94f8SSing-Han Chen 	{
775c7f94f8SSing-Han Chen 		.compatible = "nvidia,tegra234-xusb-padctl",
785c7f94f8SSing-Han Chen 		.data = &tegra234_xusb_padctl_soc,
795c7f94f8SSing-Han Chen 	},
805c7f94f8SSing-Han Chen #endif
8153d2a715SThierry Reding 	{ }
8253d2a715SThierry Reding };
8353d2a715SThierry Reding MODULE_DEVICE_TABLE(of, tegra_xusb_padctl_of_match);
8453d2a715SThierry Reding 
8553d2a715SThierry Reding static struct device_node *
tegra_xusb_find_pad_node(struct tegra_xusb_padctl * padctl,const char * name)8653d2a715SThierry Reding tegra_xusb_find_pad_node(struct tegra_xusb_padctl *padctl, const char *name)
8753d2a715SThierry Reding {
8804604673SJohan Hovold 	struct device_node *pads, *np;
8953d2a715SThierry Reding 
9004604673SJohan Hovold 	pads = of_get_child_by_name(padctl->dev->of_node, "pads");
9104604673SJohan Hovold 	if (!pads)
9204604673SJohan Hovold 		return NULL;
9304604673SJohan Hovold 
9404604673SJohan Hovold 	np = of_get_child_by_name(pads, name);
9504604673SJohan Hovold 	of_node_put(pads);
9653d2a715SThierry Reding 
9753d2a715SThierry Reding 	return np;
9853d2a715SThierry Reding }
9953d2a715SThierry Reding 
10053d2a715SThierry Reding static struct device_node *
tegra_xusb_pad_find_phy_node(struct tegra_xusb_pad * pad,unsigned int index)10153d2a715SThierry Reding tegra_xusb_pad_find_phy_node(struct tegra_xusb_pad *pad, unsigned int index)
10253d2a715SThierry Reding {
10304604673SJohan Hovold 	struct device_node *np, *lanes;
10453d2a715SThierry Reding 
10504604673SJohan Hovold 	lanes = of_get_child_by_name(pad->dev.of_node, "lanes");
10604604673SJohan Hovold 	if (!lanes)
10753d2a715SThierry Reding 		return NULL;
10853d2a715SThierry Reding 
10904604673SJohan Hovold 	np = of_get_child_by_name(lanes, pad->soc->lanes[index].name);
11004604673SJohan Hovold 	of_node_put(lanes);
11104604673SJohan Hovold 
11204604673SJohan Hovold 	return np;
11353d2a715SThierry Reding }
11453d2a715SThierry Reding 
tegra_xusb_lane_parse_dt(struct tegra_xusb_lane * lane,struct device_node * np)11553d2a715SThierry Reding int tegra_xusb_lane_parse_dt(struct tegra_xusb_lane *lane,
11653d2a715SThierry Reding 			     struct device_node *np)
11753d2a715SThierry Reding {
11853d2a715SThierry Reding 	struct device *dev = &lane->pad->dev;
11953d2a715SThierry Reding 	const char *function;
12053d2a715SThierry Reding 	int err;
12153d2a715SThierry Reding 
12253d2a715SThierry Reding 	err = of_property_read_string(np, "nvidia,function", &function);
12353d2a715SThierry Reding 	if (err < 0)
12453d2a715SThierry Reding 		return err;
12553d2a715SThierry Reding 
126f9e8d0f7SAndy Shevchenko 	err = match_string(lane->soc->funcs, lane->soc->num_funcs, function);
12753d2a715SThierry Reding 	if (err < 0) {
128ac9ba7dcSRob Herring 		dev_err(dev, "invalid function \"%s\" for lane \"%pOFn\"\n",
129ac9ba7dcSRob Herring 			function, np);
13053d2a715SThierry Reding 		return err;
13153d2a715SThierry Reding 	}
13253d2a715SThierry Reding 
13353d2a715SThierry Reding 	lane->function = err;
13453d2a715SThierry Reding 
13553d2a715SThierry Reding 	return 0;
13653d2a715SThierry Reding }
13753d2a715SThierry Reding 
tegra_xusb_lane_destroy(struct phy * phy)13853d2a715SThierry Reding static void tegra_xusb_lane_destroy(struct phy *phy)
13953d2a715SThierry Reding {
14053d2a715SThierry Reding 	if (phy) {
14153d2a715SThierry Reding 		struct tegra_xusb_lane *lane = phy_get_drvdata(phy);
14253d2a715SThierry Reding 
14353d2a715SThierry Reding 		lane->pad->ops->remove(lane);
14453d2a715SThierry Reding 		phy_destroy(phy);
14553d2a715SThierry Reding 	}
14653d2a715SThierry Reding }
14753d2a715SThierry Reding 
tegra_xusb_pad_release(struct device * dev)14853d2a715SThierry Reding static void tegra_xusb_pad_release(struct device *dev)
14953d2a715SThierry Reding {
15053d2a715SThierry Reding 	struct tegra_xusb_pad *pad = to_tegra_xusb_pad(dev);
15153d2a715SThierry Reding 
15253d2a715SThierry Reding 	pad->soc->ops->remove(pad);
15353d2a715SThierry Reding }
15453d2a715SThierry Reding 
15586f1a6e6SRikard Falkeborn static const struct device_type tegra_xusb_pad_type = {
15653d2a715SThierry Reding 	.release = tegra_xusb_pad_release,
15753d2a715SThierry Reding };
15853d2a715SThierry Reding 
tegra_xusb_pad_init(struct tegra_xusb_pad * pad,struct tegra_xusb_padctl * padctl,struct device_node * np)15953d2a715SThierry Reding int tegra_xusb_pad_init(struct tegra_xusb_pad *pad,
16053d2a715SThierry Reding 			struct tegra_xusb_padctl *padctl,
16153d2a715SThierry Reding 			struct device_node *np)
16253d2a715SThierry Reding {
16353d2a715SThierry Reding 	int err;
16453d2a715SThierry Reding 
16553d2a715SThierry Reding 	device_initialize(&pad->dev);
16653d2a715SThierry Reding 	INIT_LIST_HEAD(&pad->list);
16753d2a715SThierry Reding 	pad->dev.parent = padctl->dev;
16853d2a715SThierry Reding 	pad->dev.type = &tegra_xusb_pad_type;
16953d2a715SThierry Reding 	pad->dev.of_node = np;
17053d2a715SThierry Reding 	pad->padctl = padctl;
17153d2a715SThierry Reding 
17253d2a715SThierry Reding 	err = dev_set_name(&pad->dev, "%s", pad->soc->name);
17353d2a715SThierry Reding 	if (err < 0)
17453d2a715SThierry Reding 		goto unregister;
17553d2a715SThierry Reding 
17653d2a715SThierry Reding 	err = device_add(&pad->dev);
17753d2a715SThierry Reding 	if (err < 0)
17853d2a715SThierry Reding 		goto unregister;
17953d2a715SThierry Reding 
18053d2a715SThierry Reding 	return 0;
18153d2a715SThierry Reding 
18253d2a715SThierry Reding unregister:
18353d2a715SThierry Reding 	device_unregister(&pad->dev);
18453d2a715SThierry Reding 	return err;
18553d2a715SThierry Reding }
18653d2a715SThierry Reding 
tegra_xusb_pad_register(struct tegra_xusb_pad * pad,const struct phy_ops * ops)18753d2a715SThierry Reding int tegra_xusb_pad_register(struct tegra_xusb_pad *pad,
18853d2a715SThierry Reding 			    const struct phy_ops *ops)
18953d2a715SThierry Reding {
19053d2a715SThierry Reding 	struct device_node *children;
19153d2a715SThierry Reding 	struct phy *lane;
19253d2a715SThierry Reding 	unsigned int i;
19353d2a715SThierry Reding 	int err;
19453d2a715SThierry Reding 
19504604673SJohan Hovold 	children = of_get_child_by_name(pad->dev.of_node, "lanes");
19653d2a715SThierry Reding 	if (!children)
19753d2a715SThierry Reding 		return -ENODEV;
19853d2a715SThierry Reding 
19953d2a715SThierry Reding 	pad->lanes = devm_kcalloc(&pad->dev, pad->soc->num_lanes, sizeof(lane),
20053d2a715SThierry Reding 				  GFP_KERNEL);
20153d2a715SThierry Reding 	if (!pad->lanes) {
20253d2a715SThierry Reding 		of_node_put(children);
20353d2a715SThierry Reding 		return -ENOMEM;
20453d2a715SThierry Reding 	}
20553d2a715SThierry Reding 
20653d2a715SThierry Reding 	for (i = 0; i < pad->soc->num_lanes; i++) {
20753d2a715SThierry Reding 		struct device_node *np = tegra_xusb_pad_find_phy_node(pad, i);
20853d2a715SThierry Reding 		struct tegra_xusb_lane *lane;
20953d2a715SThierry Reding 
21053d2a715SThierry Reding 		/* skip disabled lanes */
21153d2a715SThierry Reding 		if (!np || !of_device_is_available(np)) {
21253d2a715SThierry Reding 			of_node_put(np);
21353d2a715SThierry Reding 			continue;
21453d2a715SThierry Reding 		}
21553d2a715SThierry Reding 
21653d2a715SThierry Reding 		pad->lanes[i] = phy_create(&pad->dev, np, ops);
21753d2a715SThierry Reding 		if (IS_ERR(pad->lanes[i])) {
21853d2a715SThierry Reding 			err = PTR_ERR(pad->lanes[i]);
21953d2a715SThierry Reding 			of_node_put(np);
22053d2a715SThierry Reding 			goto remove;
22153d2a715SThierry Reding 		}
22253d2a715SThierry Reding 
22353d2a715SThierry Reding 		lane = pad->ops->probe(pad, np, i);
22453d2a715SThierry Reding 		if (IS_ERR(lane)) {
22553d2a715SThierry Reding 			phy_destroy(pad->lanes[i]);
22653d2a715SThierry Reding 			err = PTR_ERR(lane);
22753d2a715SThierry Reding 			goto remove;
22853d2a715SThierry Reding 		}
22953d2a715SThierry Reding 
23053d2a715SThierry Reding 		list_add_tail(&lane->list, &pad->padctl->lanes);
23153d2a715SThierry Reding 		phy_set_drvdata(pad->lanes[i], lane);
23253d2a715SThierry Reding 	}
23353d2a715SThierry Reding 
23453d2a715SThierry Reding 	pad->provider = of_phy_provider_register_full(&pad->dev, children,
23553d2a715SThierry Reding 						      tegra_xusb_pad_of_xlate);
23653d2a715SThierry Reding 	if (IS_ERR(pad->provider)) {
23753d2a715SThierry Reding 		err = PTR_ERR(pad->provider);
23853d2a715SThierry Reding 		goto remove;
23953d2a715SThierry Reding 	}
24053d2a715SThierry Reding 
24153d2a715SThierry Reding 	return 0;
24253d2a715SThierry Reding 
24353d2a715SThierry Reding remove:
24453d2a715SThierry Reding 	while (i--)
24553d2a715SThierry Reding 		tegra_xusb_lane_destroy(pad->lanes[i]);
24653d2a715SThierry Reding 
24753d2a715SThierry Reding 	of_node_put(children);
24853d2a715SThierry Reding 
24953d2a715SThierry Reding 	return err;
25053d2a715SThierry Reding }
25153d2a715SThierry Reding 
tegra_xusb_pad_unregister(struct tegra_xusb_pad * pad)25253d2a715SThierry Reding void tegra_xusb_pad_unregister(struct tegra_xusb_pad *pad)
25353d2a715SThierry Reding {
25453d2a715SThierry Reding 	unsigned int i = pad->soc->num_lanes;
25553d2a715SThierry Reding 
25653d2a715SThierry Reding 	of_phy_provider_unregister(pad->provider);
25753d2a715SThierry Reding 
25853d2a715SThierry Reding 	while (i--)
25953d2a715SThierry Reding 		tegra_xusb_lane_destroy(pad->lanes[i]);
26053d2a715SThierry Reding 
26153d2a715SThierry Reding 	device_unregister(&pad->dev);
26253d2a715SThierry Reding }
26353d2a715SThierry Reding 
26453d2a715SThierry Reding static struct tegra_xusb_pad *
tegra_xusb_pad_create(struct tegra_xusb_padctl * padctl,const struct tegra_xusb_pad_soc * soc)26553d2a715SThierry Reding tegra_xusb_pad_create(struct tegra_xusb_padctl *padctl,
26653d2a715SThierry Reding 		      const struct tegra_xusb_pad_soc *soc)
26753d2a715SThierry Reding {
26853d2a715SThierry Reding 	struct tegra_xusb_pad *pad;
26953d2a715SThierry Reding 	struct device_node *np;
27053d2a715SThierry Reding 	int err;
27153d2a715SThierry Reding 
27253d2a715SThierry Reding 	np = tegra_xusb_find_pad_node(padctl, soc->name);
27353d2a715SThierry Reding 	if (!np || !of_device_is_available(np))
27453d2a715SThierry Reding 		return NULL;
27553d2a715SThierry Reding 
27653d2a715SThierry Reding 	pad = soc->ops->probe(padctl, soc, np);
27753d2a715SThierry Reding 	if (IS_ERR(pad)) {
27853d2a715SThierry Reding 		err = PTR_ERR(pad);
27953d2a715SThierry Reding 		dev_err(padctl->dev, "failed to create pad %s: %d\n",
28053d2a715SThierry Reding 			soc->name, err);
28153d2a715SThierry Reding 		return ERR_PTR(err);
28253d2a715SThierry Reding 	}
28353d2a715SThierry Reding 
28453d2a715SThierry Reding 	/* XXX move this into ->probe() to avoid string comparison */
28553d2a715SThierry Reding 	if (strcmp(soc->name, "pcie") == 0)
28653d2a715SThierry Reding 		padctl->pcie = pad;
28753d2a715SThierry Reding 
28853d2a715SThierry Reding 	if (strcmp(soc->name, "sata") == 0)
28953d2a715SThierry Reding 		padctl->sata = pad;
29053d2a715SThierry Reding 
29153d2a715SThierry Reding 	if (strcmp(soc->name, "usb2") == 0)
29253d2a715SThierry Reding 		padctl->usb2 = pad;
29353d2a715SThierry Reding 
29453d2a715SThierry Reding 	if (strcmp(soc->name, "ulpi") == 0)
29553d2a715SThierry Reding 		padctl->ulpi = pad;
29653d2a715SThierry Reding 
29753d2a715SThierry Reding 	if (strcmp(soc->name, "hsic") == 0)
29853d2a715SThierry Reding 		padctl->hsic = pad;
29953d2a715SThierry Reding 
30053d2a715SThierry Reding 	return pad;
30153d2a715SThierry Reding }
30253d2a715SThierry Reding 
__tegra_xusb_remove_pads(struct tegra_xusb_padctl * padctl)30353d2a715SThierry Reding static void __tegra_xusb_remove_pads(struct tegra_xusb_padctl *padctl)
30453d2a715SThierry Reding {
30553d2a715SThierry Reding 	struct tegra_xusb_pad *pad, *tmp;
30653d2a715SThierry Reding 
30753d2a715SThierry Reding 	list_for_each_entry_safe_reverse(pad, tmp, &padctl->pads, list) {
30853d2a715SThierry Reding 		list_del(&pad->list);
30953d2a715SThierry Reding 		tegra_xusb_pad_unregister(pad);
31053d2a715SThierry Reding 	}
31153d2a715SThierry Reding }
31253d2a715SThierry Reding 
tegra_xusb_remove_pads(struct tegra_xusb_padctl * padctl)31353d2a715SThierry Reding static void tegra_xusb_remove_pads(struct tegra_xusb_padctl *padctl)
31453d2a715SThierry Reding {
31553d2a715SThierry Reding 	mutex_lock(&padctl->lock);
31653d2a715SThierry Reding 	__tegra_xusb_remove_pads(padctl);
31753d2a715SThierry Reding 	mutex_unlock(&padctl->lock);
31853d2a715SThierry Reding }
31953d2a715SThierry Reding 
tegra_xusb_lane_program(struct tegra_xusb_lane * lane)32053d2a715SThierry Reding static void tegra_xusb_lane_program(struct tegra_xusb_lane *lane)
32153d2a715SThierry Reding {
32253d2a715SThierry Reding 	struct tegra_xusb_padctl *padctl = lane->pad->padctl;
32353d2a715SThierry Reding 	const struct tegra_xusb_lane_soc *soc = lane->soc;
32453d2a715SThierry Reding 	u32 value;
32553d2a715SThierry Reding 
3263cffa081SJC Kuo 	/* skip single function lanes */
3273cffa081SJC Kuo 	if (soc->num_funcs < 2)
3283cffa081SJC Kuo 		return;
3293cffa081SJC Kuo 
330c339605cSJC Kuo 	if (lane->pad->ops->iddq_enable)
331c339605cSJC Kuo 		lane->pad->ops->iddq_enable(lane);
332c339605cSJC Kuo 
33353d2a715SThierry Reding 	/* choose function */
33453d2a715SThierry Reding 	value = padctl_readl(padctl, soc->offset);
33553d2a715SThierry Reding 	value &= ~(soc->mask << soc->shift);
33653d2a715SThierry Reding 	value |= lane->function << soc->shift;
33753d2a715SThierry Reding 	padctl_writel(padctl, value, soc->offset);
338c339605cSJC Kuo 
339c339605cSJC Kuo 	if (lane->pad->ops->iddq_disable)
340c339605cSJC Kuo 		lane->pad->ops->iddq_disable(lane);
34153d2a715SThierry Reding }
34253d2a715SThierry Reding 
tegra_xusb_pad_program(struct tegra_xusb_pad * pad)34353d2a715SThierry Reding static void tegra_xusb_pad_program(struct tegra_xusb_pad *pad)
34453d2a715SThierry Reding {
34553d2a715SThierry Reding 	unsigned int i;
34653d2a715SThierry Reding 
34753d2a715SThierry Reding 	for (i = 0; i < pad->soc->num_lanes; i++) {
34853d2a715SThierry Reding 		struct tegra_xusb_lane *lane;
34953d2a715SThierry Reding 
35053d2a715SThierry Reding 		if (pad->lanes[i]) {
35153d2a715SThierry Reding 			lane = phy_get_drvdata(pad->lanes[i]);
35253d2a715SThierry Reding 			tegra_xusb_lane_program(lane);
35353d2a715SThierry Reding 		}
35453d2a715SThierry Reding 	}
35553d2a715SThierry Reding }
35653d2a715SThierry Reding 
tegra_xusb_setup_pads(struct tegra_xusb_padctl * padctl)35753d2a715SThierry Reding static int tegra_xusb_setup_pads(struct tegra_xusb_padctl *padctl)
35853d2a715SThierry Reding {
35953d2a715SThierry Reding 	struct tegra_xusb_pad *pad;
36053d2a715SThierry Reding 	unsigned int i;
36153d2a715SThierry Reding 
36253d2a715SThierry Reding 	mutex_lock(&padctl->lock);
36353d2a715SThierry Reding 
36453d2a715SThierry Reding 	for (i = 0; i < padctl->soc->num_pads; i++) {
36553d2a715SThierry Reding 		const struct tegra_xusb_pad_soc *soc = padctl->soc->pads[i];
36653d2a715SThierry Reding 		int err;
36753d2a715SThierry Reding 
36853d2a715SThierry Reding 		pad = tegra_xusb_pad_create(padctl, soc);
36953d2a715SThierry Reding 		if (IS_ERR(pad)) {
37053d2a715SThierry Reding 			err = PTR_ERR(pad);
37153d2a715SThierry Reding 			dev_err(padctl->dev, "failed to create pad %s: %d\n",
37253d2a715SThierry Reding 				soc->name, err);
37353d2a715SThierry Reding 			__tegra_xusb_remove_pads(padctl);
37453d2a715SThierry Reding 			mutex_unlock(&padctl->lock);
37553d2a715SThierry Reding 			return err;
37653d2a715SThierry Reding 		}
37753d2a715SThierry Reding 
37853d2a715SThierry Reding 		if (!pad)
37953d2a715SThierry Reding 			continue;
38053d2a715SThierry Reding 
38153d2a715SThierry Reding 		list_add_tail(&pad->list, &padctl->pads);
38253d2a715SThierry Reding 	}
38353d2a715SThierry Reding 
38453d2a715SThierry Reding 	list_for_each_entry(pad, &padctl->pads, list)
38553d2a715SThierry Reding 		tegra_xusb_pad_program(pad);
38653d2a715SThierry Reding 
38753d2a715SThierry Reding 	mutex_unlock(&padctl->lock);
38853d2a715SThierry Reding 	return 0;
38953d2a715SThierry Reding }
39053d2a715SThierry Reding 
tegra_xusb_lane_check(struct tegra_xusb_lane * lane,const char * function)39123d5ec3fSJC Kuo bool tegra_xusb_lane_check(struct tegra_xusb_lane *lane,
39253d2a715SThierry Reding 				  const char *function)
39353d2a715SThierry Reding {
39453d2a715SThierry Reding 	const char *func = lane->soc->funcs[lane->function];
39553d2a715SThierry Reding 
39653d2a715SThierry Reding 	return strcmp(function, func) == 0;
39753d2a715SThierry Reding }
39853d2a715SThierry Reding 
tegra_xusb_find_lane(struct tegra_xusb_padctl * padctl,const char * type,unsigned int index)39953d2a715SThierry Reding struct tegra_xusb_lane *tegra_xusb_find_lane(struct tegra_xusb_padctl *padctl,
40053d2a715SThierry Reding 					     const char *type,
40153d2a715SThierry Reding 					     unsigned int index)
40253d2a715SThierry Reding {
40353d2a715SThierry Reding 	struct tegra_xusb_lane *lane, *hit = ERR_PTR(-ENODEV);
40453d2a715SThierry Reding 	char *name;
40553d2a715SThierry Reding 
40653d2a715SThierry Reding 	name = kasprintf(GFP_KERNEL, "%s-%u", type, index);
40753d2a715SThierry Reding 	if (!name)
40853d2a715SThierry Reding 		return ERR_PTR(-ENOMEM);
40953d2a715SThierry Reding 
41053d2a715SThierry Reding 	list_for_each_entry(lane, &padctl->lanes, list) {
41153d2a715SThierry Reding 		if (strcmp(lane->soc->name, name) == 0) {
41253d2a715SThierry Reding 			hit = lane;
41353d2a715SThierry Reding 			break;
41453d2a715SThierry Reding 		}
41553d2a715SThierry Reding 	}
41653d2a715SThierry Reding 
41753d2a715SThierry Reding 	kfree(name);
41853d2a715SThierry Reding 	return hit;
41953d2a715SThierry Reding }
42053d2a715SThierry Reding 
42153d2a715SThierry Reding struct tegra_xusb_lane *
tegra_xusb_port_find_lane(struct tegra_xusb_port * port,const struct tegra_xusb_lane_map * map,const char * function)42253d2a715SThierry Reding tegra_xusb_port_find_lane(struct tegra_xusb_port *port,
42353d2a715SThierry Reding 			  const struct tegra_xusb_lane_map *map,
42453d2a715SThierry Reding 			  const char *function)
42553d2a715SThierry Reding {
42653d2a715SThierry Reding 	struct tegra_xusb_lane *lane, *match = ERR_PTR(-ENODEV);
42753d2a715SThierry Reding 
428a0dd6773SColin Ian King 	for (; map->type; map++) {
42953d2a715SThierry Reding 		if (port->index != map->port)
43053d2a715SThierry Reding 			continue;
43153d2a715SThierry Reding 
43253d2a715SThierry Reding 		lane = tegra_xusb_find_lane(port->padctl, map->type,
43353d2a715SThierry Reding 					    map->index);
43453d2a715SThierry Reding 		if (IS_ERR(lane))
43553d2a715SThierry Reding 			continue;
43653d2a715SThierry Reding 
43753d2a715SThierry Reding 		if (!tegra_xusb_lane_check(lane, function))
43853d2a715SThierry Reding 			continue;
43953d2a715SThierry Reding 
44053d2a715SThierry Reding 		if (!IS_ERR(match))
44153d2a715SThierry Reding 			dev_err(&port->dev, "conflicting match: %s-%u / %s\n",
44253d2a715SThierry Reding 				map->type, map->index, match->soc->name);
44353d2a715SThierry Reding 		else
44453d2a715SThierry Reding 			match = lane;
44553d2a715SThierry Reding 	}
44653d2a715SThierry Reding 
44753d2a715SThierry Reding 	return match;
44853d2a715SThierry Reding }
44953d2a715SThierry Reding 
45053d2a715SThierry Reding static struct device_node *
tegra_xusb_find_port_node(struct tegra_xusb_padctl * padctl,const char * type,unsigned int index)45153d2a715SThierry Reding tegra_xusb_find_port_node(struct tegra_xusb_padctl *padctl, const char *type,
45253d2a715SThierry Reding 			  unsigned int index)
45353d2a715SThierry Reding {
45404604673SJohan Hovold 	struct device_node *ports, *np;
45553d2a715SThierry Reding 	char *name;
45653d2a715SThierry Reding 
45704604673SJohan Hovold 	ports = of_get_child_by_name(padctl->dev->of_node, "ports");
45804604673SJohan Hovold 	if (!ports)
45904604673SJohan Hovold 		return NULL;
46004604673SJohan Hovold 
46153d2a715SThierry Reding 	name = kasprintf(GFP_KERNEL, "%s-%u", type, index);
46204604673SJohan Hovold 	if (!name) {
46304604673SJohan Hovold 		of_node_put(ports);
464045a31b9SMiaoqian Lin 		return NULL;
46553d2a715SThierry Reding 	}
46604604673SJohan Hovold 	np = of_get_child_by_name(ports, name);
46704604673SJohan Hovold 	kfree(name);
46804604673SJohan Hovold 	of_node_put(ports);
46953d2a715SThierry Reding 
47053d2a715SThierry Reding 	return np;
47153d2a715SThierry Reding }
47253d2a715SThierry Reding 
47353d2a715SThierry Reding struct tegra_xusb_port *
tegra_xusb_find_port(struct tegra_xusb_padctl * padctl,const char * type,unsigned int index)47453d2a715SThierry Reding tegra_xusb_find_port(struct tegra_xusb_padctl *padctl, const char *type,
47553d2a715SThierry Reding 		     unsigned int index)
47653d2a715SThierry Reding {
47753d2a715SThierry Reding 	struct tegra_xusb_port *port;
47853d2a715SThierry Reding 	struct device_node *np;
47953d2a715SThierry Reding 
48053d2a715SThierry Reding 	np = tegra_xusb_find_port_node(padctl, type, index);
48153d2a715SThierry Reding 	if (!np)
48253d2a715SThierry Reding 		return NULL;
48353d2a715SThierry Reding 
48453d2a715SThierry Reding 	list_for_each_entry(port, &padctl->ports, list) {
48553d2a715SThierry Reding 		if (np == port->dev.of_node) {
48653d2a715SThierry Reding 			of_node_put(np);
48753d2a715SThierry Reding 			return port;
48853d2a715SThierry Reding 		}
48953d2a715SThierry Reding 	}
49053d2a715SThierry Reding 
49153d2a715SThierry Reding 	of_node_put(np);
49253d2a715SThierry Reding 
49353d2a715SThierry Reding 	return NULL;
49453d2a715SThierry Reding }
49553d2a715SThierry Reding 
49653d2a715SThierry Reding struct tegra_xusb_usb2_port *
tegra_xusb_find_usb2_port(struct tegra_xusb_padctl * padctl,unsigned int index)49753d2a715SThierry Reding tegra_xusb_find_usb2_port(struct tegra_xusb_padctl *padctl, unsigned int index)
49853d2a715SThierry Reding {
49953d2a715SThierry Reding 	struct tegra_xusb_port *port;
50053d2a715SThierry Reding 
50153d2a715SThierry Reding 	port = tegra_xusb_find_port(padctl, "usb2", index);
50253d2a715SThierry Reding 	if (port)
50353d2a715SThierry Reding 		return to_usb2_port(port);
50453d2a715SThierry Reding 
50553d2a715SThierry Reding 	return NULL;
50653d2a715SThierry Reding }
50753d2a715SThierry Reding 
50853d2a715SThierry Reding struct tegra_xusb_usb3_port *
tegra_xusb_find_usb3_port(struct tegra_xusb_padctl * padctl,unsigned int index)50953d2a715SThierry Reding tegra_xusb_find_usb3_port(struct tegra_xusb_padctl *padctl, unsigned int index)
51053d2a715SThierry Reding {
51153d2a715SThierry Reding 	struct tegra_xusb_port *port;
51253d2a715SThierry Reding 
51353d2a715SThierry Reding 	port = tegra_xusb_find_port(padctl, "usb3", index);
51453d2a715SThierry Reding 	if (port)
51553d2a715SThierry Reding 		return to_usb3_port(port);
51653d2a715SThierry Reding 
51753d2a715SThierry Reding 	return NULL;
51853d2a715SThierry Reding }
51953d2a715SThierry Reding 
tegra_xusb_port_release(struct device * dev)52053d2a715SThierry Reding static void tegra_xusb_port_release(struct device *dev)
52153d2a715SThierry Reding {
522e78fdbadSThierry Reding 	struct tegra_xusb_port *port = to_tegra_xusb_port(dev);
523e78fdbadSThierry Reding 
524e78fdbadSThierry Reding 	if (port->ops->release)
525e78fdbadSThierry Reding 		port->ops->release(port);
52653d2a715SThierry Reding }
52753d2a715SThierry Reding 
52886f1a6e6SRikard Falkeborn static const struct device_type tegra_xusb_port_type = {
52953d2a715SThierry Reding 	.release = tegra_xusb_port_release,
53053d2a715SThierry Reding };
53153d2a715SThierry Reding 
tegra_xusb_port_init(struct tegra_xusb_port * port,struct tegra_xusb_padctl * padctl,struct device_node * np,const char * name,unsigned int index)53253d2a715SThierry Reding static int tegra_xusb_port_init(struct tegra_xusb_port *port,
53353d2a715SThierry Reding 				struct tegra_xusb_padctl *padctl,
53453d2a715SThierry Reding 				struct device_node *np,
53553d2a715SThierry Reding 				const char *name,
53653d2a715SThierry Reding 				unsigned int index)
53753d2a715SThierry Reding {
53853d2a715SThierry Reding 	int err;
53953d2a715SThierry Reding 
54053d2a715SThierry Reding 	INIT_LIST_HEAD(&port->list);
54153d2a715SThierry Reding 	port->padctl = padctl;
54253d2a715SThierry Reding 	port->index = index;
54353d2a715SThierry Reding 
54453d2a715SThierry Reding 	device_initialize(&port->dev);
54553d2a715SThierry Reding 	port->dev.type = &tegra_xusb_port_type;
54653d2a715SThierry Reding 	port->dev.of_node = of_node_get(np);
54753d2a715SThierry Reding 	port->dev.parent = padctl->dev;
54853d2a715SThierry Reding 
54953d2a715SThierry Reding 	err = dev_set_name(&port->dev, "%s-%u", name, index);
55053d2a715SThierry Reding 	if (err < 0)
55153d2a715SThierry Reding 		goto unregister;
55253d2a715SThierry Reding 
55353d2a715SThierry Reding 	err = device_add(&port->dev);
55453d2a715SThierry Reding 	if (err < 0)
55553d2a715SThierry Reding 		goto unregister;
55653d2a715SThierry Reding 
55753d2a715SThierry Reding 	return 0;
55853d2a715SThierry Reding 
55953d2a715SThierry Reding unregister:
56053d2a715SThierry Reding 	device_unregister(&port->dev);
56153d2a715SThierry Reding 	return err;
56253d2a715SThierry Reding }
56353d2a715SThierry Reding 
tegra_xusb_port_unregister(struct tegra_xusb_port * port)56453d2a715SThierry Reding static void tegra_xusb_port_unregister(struct tegra_xusb_port *port)
56553d2a715SThierry Reding {
566f67213ceSNagarjuna Kristam 	if (!IS_ERR_OR_NULL(port->usb_role_sw)) {
567f67213ceSNagarjuna Kristam 		of_platform_depopulate(&port->dev);
568f67213ceSNagarjuna Kristam 		usb_role_switch_unregister(port->usb_role_sw);
569e8f7d2f4SNagarjuna Kristam 		cancel_work_sync(&port->usb_phy_work);
570e8f7d2f4SNagarjuna Kristam 		usb_remove_phy(&port->usb_phy);
571c0c2fcb1SEJ Hsu 		port->usb_phy.dev->driver = NULL;
572f67213ceSNagarjuna Kristam 	}
573f67213ceSNagarjuna Kristam 
5742f8da84dSThierry Reding 	if (port->ops->remove)
5752f8da84dSThierry Reding 		port->ops->remove(port);
5762f8da84dSThierry Reding 
57753d2a715SThierry Reding 	device_unregister(&port->dev);
57853d2a715SThierry Reding }
57953d2a715SThierry Reding 
5805311a7b8SThierry Reding static const char *const modes[] = {
5815311a7b8SThierry Reding 	[USB_DR_MODE_UNKNOWN] = "",
5825311a7b8SThierry Reding 	[USB_DR_MODE_HOST] = "host",
5835311a7b8SThierry Reding 	[USB_DR_MODE_PERIPHERAL] = "peripheral",
5845311a7b8SThierry Reding 	[USB_DR_MODE_OTG] = "otg",
5855311a7b8SThierry Reding };
5865311a7b8SThierry Reding 
587f67213ceSNagarjuna Kristam static const char * const usb_roles[] = {
588f67213ceSNagarjuna Kristam 	[USB_ROLE_NONE]		= "none",
589f67213ceSNagarjuna Kristam 	[USB_ROLE_HOST]		= "host",
590f67213ceSNagarjuna Kristam 	[USB_ROLE_DEVICE]	= "device",
591f67213ceSNagarjuna Kristam };
592f67213ceSNagarjuna Kristam 
to_usb_phy_event(enum usb_role role)593e8f7d2f4SNagarjuna Kristam static enum usb_phy_events to_usb_phy_event(enum usb_role role)
594e8f7d2f4SNagarjuna Kristam {
595e8f7d2f4SNagarjuna Kristam 	switch (role) {
596e8f7d2f4SNagarjuna Kristam 	case USB_ROLE_DEVICE:
597e8f7d2f4SNagarjuna Kristam 		return USB_EVENT_VBUS;
598e8f7d2f4SNagarjuna Kristam 
599e8f7d2f4SNagarjuna Kristam 	case USB_ROLE_HOST:
600e8f7d2f4SNagarjuna Kristam 		return USB_EVENT_ID;
601e8f7d2f4SNagarjuna Kristam 
602e8f7d2f4SNagarjuna Kristam 	default:
603e8f7d2f4SNagarjuna Kristam 		return USB_EVENT_NONE;
604e8f7d2f4SNagarjuna Kristam 	}
605e8f7d2f4SNagarjuna Kristam }
606e8f7d2f4SNagarjuna Kristam 
tegra_xusb_usb_phy_work(struct work_struct * work)607e8f7d2f4SNagarjuna Kristam static void tegra_xusb_usb_phy_work(struct work_struct *work)
608e8f7d2f4SNagarjuna Kristam {
609e8f7d2f4SNagarjuna Kristam 	struct tegra_xusb_port *port = container_of(work,
610e8f7d2f4SNagarjuna Kristam 						    struct tegra_xusb_port,
611e8f7d2f4SNagarjuna Kristam 						    usb_phy_work);
612e8f7d2f4SNagarjuna Kristam 	enum usb_role role = usb_role_switch_get_role(port->usb_role_sw);
613e8f7d2f4SNagarjuna Kristam 
614e8f7d2f4SNagarjuna Kristam 	usb_phy_set_event(&port->usb_phy, to_usb_phy_event(role));
615e8f7d2f4SNagarjuna Kristam 
616e8f7d2f4SNagarjuna Kristam 	dev_dbg(&port->dev, "%s(): calling notifier for role %s\n", __func__,
617e8f7d2f4SNagarjuna Kristam 		usb_roles[role]);
618e8f7d2f4SNagarjuna Kristam 
619e8f7d2f4SNagarjuna Kristam 	atomic_notifier_call_chain(&port->usb_phy.notifier, 0, &port->usb_phy);
620e8f7d2f4SNagarjuna Kristam }
621e8f7d2f4SNagarjuna Kristam 
tegra_xusb_role_sw_set(struct usb_role_switch * sw,enum usb_role role)622f67213ceSNagarjuna Kristam static int tegra_xusb_role_sw_set(struct usb_role_switch *sw,
623f67213ceSNagarjuna Kristam 				  enum usb_role role)
624f67213ceSNagarjuna Kristam {
625f67213ceSNagarjuna Kristam 	struct tegra_xusb_port *port = usb_role_switch_get_drvdata(sw);
626f67213ceSNagarjuna Kristam 
627f67213ceSNagarjuna Kristam 	dev_dbg(&port->dev, "%s(): role %s\n", __func__, usb_roles[role]);
628f67213ceSNagarjuna Kristam 
629e8f7d2f4SNagarjuna Kristam 	schedule_work(&port->usb_phy_work);
630e8f7d2f4SNagarjuna Kristam 
631f67213ceSNagarjuna Kristam 	return 0;
632f67213ceSNagarjuna Kristam }
633f67213ceSNagarjuna Kristam 
tegra_xusb_set_peripheral(struct usb_otg * otg,struct usb_gadget * gadget)634e8f7d2f4SNagarjuna Kristam static int tegra_xusb_set_peripheral(struct usb_otg *otg,
635e8f7d2f4SNagarjuna Kristam 				     struct usb_gadget *gadget)
636e8f7d2f4SNagarjuna Kristam {
637e8f7d2f4SNagarjuna Kristam 	struct tegra_xusb_port *port = container_of(otg->usb_phy,
638e8f7d2f4SNagarjuna Kristam 						    struct tegra_xusb_port,
639e8f7d2f4SNagarjuna Kristam 						    usb_phy);
640e8f7d2f4SNagarjuna Kristam 
641e8f7d2f4SNagarjuna Kristam 	if (gadget != NULL)
642e8f7d2f4SNagarjuna Kristam 		schedule_work(&port->usb_phy_work);
643e8f7d2f4SNagarjuna Kristam 
644e8f7d2f4SNagarjuna Kristam 	return 0;
645e8f7d2f4SNagarjuna Kristam }
646e8f7d2f4SNagarjuna Kristam 
tegra_xusb_set_host(struct usb_otg * otg,struct usb_bus * host)647e8f7d2f4SNagarjuna Kristam static int tegra_xusb_set_host(struct usb_otg *otg, struct usb_bus *host)
648e8f7d2f4SNagarjuna Kristam {
649e8f7d2f4SNagarjuna Kristam 	struct tegra_xusb_port *port = container_of(otg->usb_phy,
650e8f7d2f4SNagarjuna Kristam 						    struct tegra_xusb_port,
651e8f7d2f4SNagarjuna Kristam 						    usb_phy);
652e8f7d2f4SNagarjuna Kristam 
653e8f7d2f4SNagarjuna Kristam 	if (host != NULL)
654e8f7d2f4SNagarjuna Kristam 		schedule_work(&port->usb_phy_work);
655e8f7d2f4SNagarjuna Kristam 
656e8f7d2f4SNagarjuna Kristam 	return 0;
657e8f7d2f4SNagarjuna Kristam }
658e8f7d2f4SNagarjuna Kristam 
659e8f7d2f4SNagarjuna Kristam 
tegra_xusb_setup_usb_role_switch(struct tegra_xusb_port * port)660f67213ceSNagarjuna Kristam static int tegra_xusb_setup_usb_role_switch(struct tegra_xusb_port *port)
661f67213ceSNagarjuna Kristam {
662e8f7d2f4SNagarjuna Kristam 	struct tegra_xusb_lane *lane;
663f67213ceSNagarjuna Kristam 	struct usb_role_switch_desc role_sx_desc = {
664f67213ceSNagarjuna Kristam 		.fwnode = dev_fwnode(&port->dev),
665f67213ceSNagarjuna Kristam 		.set = tegra_xusb_role_sw_set,
66603b756d2SWayne Chang 		.allow_userspace_control = true,
667f67213ceSNagarjuna Kristam 	};
668f67213ceSNagarjuna Kristam 	int err = 0;
669f67213ceSNagarjuna Kristam 
670f67213ceSNagarjuna Kristam 	/*
671f67213ceSNagarjuna Kristam 	 * USB role switch driver needs parent driver owner info. This is a
672f67213ceSNagarjuna Kristam 	 * suboptimal solution. TODO: Need to revisit this in a follow-up patch
673f67213ceSNagarjuna Kristam 	 * where an optimal solution is possible with changes to USB role
674f67213ceSNagarjuna Kristam 	 * switch driver.
675f67213ceSNagarjuna Kristam 	 */
676f67213ceSNagarjuna Kristam 	port->dev.driver = devm_kzalloc(&port->dev,
677f67213ceSNagarjuna Kristam 					sizeof(struct device_driver),
678f67213ceSNagarjuna Kristam 					GFP_KERNEL);
67944faada0SClaudiu Beznea 	if (!port->dev.driver)
68044faada0SClaudiu Beznea 		return -ENOMEM;
68144faada0SClaudiu Beznea 
682f67213ceSNagarjuna Kristam 	port->dev.driver->owner	 = THIS_MODULE;
683f67213ceSNagarjuna Kristam 
684f67213ceSNagarjuna Kristam 	port->usb_role_sw = usb_role_switch_register(&port->dev,
685f67213ceSNagarjuna Kristam 						     &role_sx_desc);
686f67213ceSNagarjuna Kristam 	if (IS_ERR(port->usb_role_sw)) {
687f67213ceSNagarjuna Kristam 		err = PTR_ERR(port->usb_role_sw);
688f67213ceSNagarjuna Kristam 		dev_err(&port->dev, "failed to register USB role switch: %d",
689f67213ceSNagarjuna Kristam 			err);
690f67213ceSNagarjuna Kristam 		return err;
691f67213ceSNagarjuna Kristam 	}
692f67213ceSNagarjuna Kristam 
693e8f7d2f4SNagarjuna Kristam 	INIT_WORK(&port->usb_phy_work, tegra_xusb_usb_phy_work);
694f67213ceSNagarjuna Kristam 	usb_role_switch_set_drvdata(port->usb_role_sw, port);
695f67213ceSNagarjuna Kristam 
696e8f7d2f4SNagarjuna Kristam 	port->usb_phy.otg = devm_kzalloc(&port->dev, sizeof(struct usb_otg),
697e8f7d2f4SNagarjuna Kristam 					 GFP_KERNEL);
698e8f7d2f4SNagarjuna Kristam 	if (!port->usb_phy.otg)
699e8f7d2f4SNagarjuna Kristam 		return -ENOMEM;
700e8f7d2f4SNagarjuna Kristam 
701e8f7d2f4SNagarjuna Kristam 	lane = tegra_xusb_find_lane(port->padctl, "usb2", port->index);
702e8f7d2f4SNagarjuna Kristam 
703e8f7d2f4SNagarjuna Kristam 	/*
704e8f7d2f4SNagarjuna Kristam 	 * Assign phy dev to usb-phy dev. Host/device drivers can use phy
705e8f7d2f4SNagarjuna Kristam 	 * reference to retrieve usb-phy details.
706e8f7d2f4SNagarjuna Kristam 	 */
707e8f7d2f4SNagarjuna Kristam 	port->usb_phy.dev = &lane->pad->lanes[port->index]->dev;
7084ea0bf2aSJC Kuo 	port->usb_phy.dev->driver = port->dev.driver;
709e8f7d2f4SNagarjuna Kristam 	port->usb_phy.otg->usb_phy = &port->usb_phy;
710e8f7d2f4SNagarjuna Kristam 	port->usb_phy.otg->set_peripheral = tegra_xusb_set_peripheral;
711e8f7d2f4SNagarjuna Kristam 	port->usb_phy.otg->set_host = tegra_xusb_set_host;
712e8f7d2f4SNagarjuna Kristam 
713e8f7d2f4SNagarjuna Kristam 	err = usb_add_phy_dev(&port->usb_phy);
714e8f7d2f4SNagarjuna Kristam 	if (err < 0) {
715e8f7d2f4SNagarjuna Kristam 		dev_err(&port->dev, "Failed to add USB PHY: %d\n", err);
716e8f7d2f4SNagarjuna Kristam 		return err;
717e8f7d2f4SNagarjuna Kristam 	}
718e8f7d2f4SNagarjuna Kristam 
719f67213ceSNagarjuna Kristam 	/* populate connector entry */
720f67213ceSNagarjuna Kristam 	of_platform_populate(port->dev.of_node, NULL, NULL, &port->dev);
721f67213ceSNagarjuna Kristam 
722f67213ceSNagarjuna Kristam 	return err;
723f67213ceSNagarjuna Kristam }
724f67213ceSNagarjuna Kristam 
tegra_xusb_parse_usb_role_default_mode(struct tegra_xusb_port * port)7253cde1ef6SHaotien Hsu static void tegra_xusb_parse_usb_role_default_mode(struct tegra_xusb_port *port)
7263cde1ef6SHaotien Hsu {
7273cde1ef6SHaotien Hsu 	enum usb_role role = USB_ROLE_NONE;
7283cde1ef6SHaotien Hsu 	enum usb_dr_mode mode = usb_get_role_switch_default_mode(&port->dev);
7293cde1ef6SHaotien Hsu 
7303cde1ef6SHaotien Hsu 	if (mode == USB_DR_MODE_HOST)
7313cde1ef6SHaotien Hsu 		role = USB_ROLE_HOST;
7323cde1ef6SHaotien Hsu 	else if (mode == USB_DR_MODE_PERIPHERAL)
7333cde1ef6SHaotien Hsu 		role = USB_ROLE_DEVICE;
7343cde1ef6SHaotien Hsu 
7353cde1ef6SHaotien Hsu 	if (role != USB_ROLE_NONE) {
7363cde1ef6SHaotien Hsu 		usb_role_switch_set_role(port->usb_role_sw, role);
7373cde1ef6SHaotien Hsu 		dev_dbg(&port->dev, "usb role default mode is %s", modes[mode]);
7383cde1ef6SHaotien Hsu 	}
7393cde1ef6SHaotien Hsu }
7403cde1ef6SHaotien Hsu 
tegra_xusb_usb2_port_parse_dt(struct tegra_xusb_usb2_port * usb2)74153d2a715SThierry Reding static int tegra_xusb_usb2_port_parse_dt(struct tegra_xusb_usb2_port *usb2)
74253d2a715SThierry Reding {
74353d2a715SThierry Reding 	struct tegra_xusb_port *port = &usb2->base;
74453d2a715SThierry Reding 	struct device_node *np = port->dev.of_node;
7455311a7b8SThierry Reding 	const char *mode;
746f67213ceSNagarjuna Kristam 	int err;
74753d2a715SThierry Reding 
74853d2a715SThierry Reding 	usb2->internal = of_property_read_bool(np, "nvidia,internal");
74953d2a715SThierry Reding 
7505311a7b8SThierry Reding 	if (!of_property_read_string(np, "mode", &mode)) {
7515311a7b8SThierry Reding 		int err = match_string(modes, ARRAY_SIZE(modes), mode);
7525311a7b8SThierry Reding 		if (err < 0) {
7535311a7b8SThierry Reding 			dev_err(&port->dev, "invalid value %s for \"mode\"\n",
7545311a7b8SThierry Reding 				mode);
7555311a7b8SThierry Reding 			usb2->mode = USB_DR_MODE_UNKNOWN;
7565311a7b8SThierry Reding 		} else {
7575311a7b8SThierry Reding 			usb2->mode = err;
7585311a7b8SThierry Reding 		}
7595311a7b8SThierry Reding 	} else {
7605311a7b8SThierry Reding 		usb2->mode = USB_DR_MODE_HOST;
7615311a7b8SThierry Reding 	}
7625311a7b8SThierry Reding 
763f67213ceSNagarjuna Kristam 	/* usb-role-switch property is mandatory for OTG/Peripheral modes */
764f67213ceSNagarjuna Kristam 	if (usb2->mode == USB_DR_MODE_PERIPHERAL ||
765f67213ceSNagarjuna Kristam 	    usb2->mode == USB_DR_MODE_OTG) {
766f67213ceSNagarjuna Kristam 		if (of_property_read_bool(np, "usb-role-switch")) {
767f67213ceSNagarjuna Kristam 			err = tegra_xusb_setup_usb_role_switch(port);
768f67213ceSNagarjuna Kristam 			if (err < 0)
769f67213ceSNagarjuna Kristam 				return err;
7703cde1ef6SHaotien Hsu 			tegra_xusb_parse_usb_role_default_mode(port);
771f67213ceSNagarjuna Kristam 		} else {
772f67213ceSNagarjuna Kristam 			dev_err(&port->dev, "usb-role-switch not found for %s mode",
773f67213ceSNagarjuna Kristam 				modes[usb2->mode]);
774f67213ceSNagarjuna Kristam 			return -EINVAL;
775f67213ceSNagarjuna Kristam 		}
776f67213ceSNagarjuna Kristam 	}
777f67213ceSNagarjuna Kristam 
7782f8da84dSThierry Reding 	usb2->supply = regulator_get(&port->dev, "vbus");
779045ef311SVivek Gautam 	return PTR_ERR_OR_ZERO(usb2->supply);
78053d2a715SThierry Reding }
78153d2a715SThierry Reding 
tegra_xusb_add_usb2_port(struct tegra_xusb_padctl * padctl,unsigned int index)78253d2a715SThierry Reding static int tegra_xusb_add_usb2_port(struct tegra_xusb_padctl *padctl,
78353d2a715SThierry Reding 				    unsigned int index)
78453d2a715SThierry Reding {
78553d2a715SThierry Reding 	struct tegra_xusb_usb2_port *usb2;
78653d2a715SThierry Reding 	struct device_node *np;
78753d2a715SThierry Reding 	int err = 0;
78853d2a715SThierry Reding 
78953d2a715SThierry Reding 	/*
79053d2a715SThierry Reding 	 * USB2 ports don't require additional properties, but if the port is
79153d2a715SThierry Reding 	 * marked as disabled there is no reason to register it.
79253d2a715SThierry Reding 	 */
79353d2a715SThierry Reding 	np = tegra_xusb_find_port_node(padctl, "usb2", index);
79453d2a715SThierry Reding 	if (!np || !of_device_is_available(np))
79553d2a715SThierry Reding 		goto out;
79653d2a715SThierry Reding 
797e78fdbadSThierry Reding 	usb2 = kzalloc(sizeof(*usb2), GFP_KERNEL);
79853d2a715SThierry Reding 	if (!usb2) {
79953d2a715SThierry Reding 		err = -ENOMEM;
80053d2a715SThierry Reding 		goto out;
80153d2a715SThierry Reding 	}
80253d2a715SThierry Reding 
80353d2a715SThierry Reding 	err = tegra_xusb_port_init(&usb2->base, padctl, np, "usb2", index);
80453d2a715SThierry Reding 	if (err < 0)
80553d2a715SThierry Reding 		goto out;
80653d2a715SThierry Reding 
80753d2a715SThierry Reding 	usb2->base.ops = padctl->soc->ports.usb2.ops;
80853d2a715SThierry Reding 
80953d2a715SThierry Reding 	usb2->base.lane = usb2->base.ops->map(&usb2->base);
81053d2a715SThierry Reding 	if (IS_ERR(usb2->base.lane)) {
81153d2a715SThierry Reding 		err = PTR_ERR(usb2->base.lane);
812e0248540SGaosheng Cui 		tegra_xusb_port_unregister(&usb2->base);
81353d2a715SThierry Reding 		goto out;
81453d2a715SThierry Reding 	}
81553d2a715SThierry Reding 
81653d2a715SThierry Reding 	err = tegra_xusb_usb2_port_parse_dt(usb2);
81753d2a715SThierry Reding 	if (err < 0) {
81853d2a715SThierry Reding 		tegra_xusb_port_unregister(&usb2->base);
81953d2a715SThierry Reding 		goto out;
82053d2a715SThierry Reding 	}
82153d2a715SThierry Reding 
82253d2a715SThierry Reding 	list_add_tail(&usb2->base.list, &padctl->ports);
82353d2a715SThierry Reding 
82453d2a715SThierry Reding out:
82553d2a715SThierry Reding 	of_node_put(np);
82653d2a715SThierry Reding 	return err;
82753d2a715SThierry Reding }
82853d2a715SThierry Reding 
tegra_xusb_usb2_port_release(struct tegra_xusb_port * port)829e78fdbadSThierry Reding void tegra_xusb_usb2_port_release(struct tegra_xusb_port *port)
830e78fdbadSThierry Reding {
831e78fdbadSThierry Reding 	struct tegra_xusb_usb2_port *usb2 = to_usb2_port(port);
832e78fdbadSThierry Reding 
833e78fdbadSThierry Reding 	kfree(usb2);
834e78fdbadSThierry Reding }
835e78fdbadSThierry Reding 
tegra_xusb_usb2_port_remove(struct tegra_xusb_port * port)8362f8da84dSThierry Reding void tegra_xusb_usb2_port_remove(struct tegra_xusb_port *port)
8372f8da84dSThierry Reding {
8382f8da84dSThierry Reding 	struct tegra_xusb_usb2_port *usb2 = to_usb2_port(port);
8392f8da84dSThierry Reding 
8402f8da84dSThierry Reding 	regulator_put(usb2->supply);
8412f8da84dSThierry Reding }
8422f8da84dSThierry Reding 
tegra_xusb_ulpi_port_parse_dt(struct tegra_xusb_ulpi_port * ulpi)84353d2a715SThierry Reding static int tegra_xusb_ulpi_port_parse_dt(struct tegra_xusb_ulpi_port *ulpi)
84453d2a715SThierry Reding {
84553d2a715SThierry Reding 	struct tegra_xusb_port *port = &ulpi->base;
84653d2a715SThierry Reding 	struct device_node *np = port->dev.of_node;
84753d2a715SThierry Reding 
84853d2a715SThierry Reding 	ulpi->internal = of_property_read_bool(np, "nvidia,internal");
84953d2a715SThierry Reding 
85053d2a715SThierry Reding 	return 0;
85153d2a715SThierry Reding }
85253d2a715SThierry Reding 
tegra_xusb_add_ulpi_port(struct tegra_xusb_padctl * padctl,unsigned int index)85353d2a715SThierry Reding static int tegra_xusb_add_ulpi_port(struct tegra_xusb_padctl *padctl,
85453d2a715SThierry Reding 				    unsigned int index)
85553d2a715SThierry Reding {
85653d2a715SThierry Reding 	struct tegra_xusb_ulpi_port *ulpi;
85753d2a715SThierry Reding 	struct device_node *np;
85853d2a715SThierry Reding 	int err = 0;
85953d2a715SThierry Reding 
86053d2a715SThierry Reding 	np = tegra_xusb_find_port_node(padctl, "ulpi", index);
86153d2a715SThierry Reding 	if (!np || !of_device_is_available(np))
86253d2a715SThierry Reding 		goto out;
86353d2a715SThierry Reding 
864e78fdbadSThierry Reding 	ulpi = kzalloc(sizeof(*ulpi), GFP_KERNEL);
86553d2a715SThierry Reding 	if (!ulpi) {
86653d2a715SThierry Reding 		err = -ENOMEM;
86753d2a715SThierry Reding 		goto out;
86853d2a715SThierry Reding 	}
86953d2a715SThierry Reding 
87053d2a715SThierry Reding 	err = tegra_xusb_port_init(&ulpi->base, padctl, np, "ulpi", index);
87153d2a715SThierry Reding 	if (err < 0)
87253d2a715SThierry Reding 		goto out;
87353d2a715SThierry Reding 
87453d2a715SThierry Reding 	ulpi->base.ops = padctl->soc->ports.ulpi.ops;
87553d2a715SThierry Reding 
87653d2a715SThierry Reding 	ulpi->base.lane = ulpi->base.ops->map(&ulpi->base);
87753d2a715SThierry Reding 	if (IS_ERR(ulpi->base.lane)) {
87853d2a715SThierry Reding 		err = PTR_ERR(ulpi->base.lane);
879e0248540SGaosheng Cui 		tegra_xusb_port_unregister(&ulpi->base);
88053d2a715SThierry Reding 		goto out;
88153d2a715SThierry Reding 	}
88253d2a715SThierry Reding 
88353d2a715SThierry Reding 	err = tegra_xusb_ulpi_port_parse_dt(ulpi);
88453d2a715SThierry Reding 	if (err < 0) {
88553d2a715SThierry Reding 		tegra_xusb_port_unregister(&ulpi->base);
88653d2a715SThierry Reding 		goto out;
88753d2a715SThierry Reding 	}
88853d2a715SThierry Reding 
88953d2a715SThierry Reding 	list_add_tail(&ulpi->base.list, &padctl->ports);
89053d2a715SThierry Reding 
89153d2a715SThierry Reding out:
89253d2a715SThierry Reding 	of_node_put(np);
89353d2a715SThierry Reding 	return err;
89453d2a715SThierry Reding }
89553d2a715SThierry Reding 
tegra_xusb_ulpi_port_release(struct tegra_xusb_port * port)896e78fdbadSThierry Reding void tegra_xusb_ulpi_port_release(struct tegra_xusb_port *port)
897e78fdbadSThierry Reding {
898e78fdbadSThierry Reding 	struct tegra_xusb_ulpi_port *ulpi = to_ulpi_port(port);
899e78fdbadSThierry Reding 
900e78fdbadSThierry Reding 	kfree(ulpi);
901e78fdbadSThierry Reding }
902e78fdbadSThierry Reding 
tegra_xusb_hsic_port_parse_dt(struct tegra_xusb_hsic_port * hsic)90353d2a715SThierry Reding static int tegra_xusb_hsic_port_parse_dt(struct tegra_xusb_hsic_port *hsic)
90453d2a715SThierry Reding {
90553d2a715SThierry Reding 	/* XXX */
90653d2a715SThierry Reding 	return 0;
90753d2a715SThierry Reding }
90853d2a715SThierry Reding 
tegra_xusb_add_hsic_port(struct tegra_xusb_padctl * padctl,unsigned int index)90953d2a715SThierry Reding static int tegra_xusb_add_hsic_port(struct tegra_xusb_padctl *padctl,
91053d2a715SThierry Reding 				    unsigned int index)
91153d2a715SThierry Reding {
91253d2a715SThierry Reding 	struct tegra_xusb_hsic_port *hsic;
91353d2a715SThierry Reding 	struct device_node *np;
91453d2a715SThierry Reding 	int err = 0;
91553d2a715SThierry Reding 
91653d2a715SThierry Reding 	np = tegra_xusb_find_port_node(padctl, "hsic", index);
91753d2a715SThierry Reding 	if (!np || !of_device_is_available(np))
91853d2a715SThierry Reding 		goto out;
91953d2a715SThierry Reding 
920e78fdbadSThierry Reding 	hsic = kzalloc(sizeof(*hsic), GFP_KERNEL);
92153d2a715SThierry Reding 	if (!hsic) {
92253d2a715SThierry Reding 		err = -ENOMEM;
92353d2a715SThierry Reding 		goto out;
92453d2a715SThierry Reding 	}
92553d2a715SThierry Reding 
92653d2a715SThierry Reding 	err = tegra_xusb_port_init(&hsic->base, padctl, np, "hsic", index);
92753d2a715SThierry Reding 	if (err < 0)
92853d2a715SThierry Reding 		goto out;
92953d2a715SThierry Reding 
93053d2a715SThierry Reding 	hsic->base.ops = padctl->soc->ports.hsic.ops;
93153d2a715SThierry Reding 
93253d2a715SThierry Reding 	hsic->base.lane = hsic->base.ops->map(&hsic->base);
93353d2a715SThierry Reding 	if (IS_ERR(hsic->base.lane)) {
93453d2a715SThierry Reding 		err = PTR_ERR(hsic->base.lane);
93553d2a715SThierry Reding 		goto out;
93653d2a715SThierry Reding 	}
93753d2a715SThierry Reding 
93853d2a715SThierry Reding 	err = tegra_xusb_hsic_port_parse_dt(hsic);
93953d2a715SThierry Reding 	if (err < 0) {
94053d2a715SThierry Reding 		tegra_xusb_port_unregister(&hsic->base);
94153d2a715SThierry Reding 		goto out;
94253d2a715SThierry Reding 	}
94353d2a715SThierry Reding 
94453d2a715SThierry Reding 	list_add_tail(&hsic->base.list, &padctl->ports);
94553d2a715SThierry Reding 
94653d2a715SThierry Reding out:
94753d2a715SThierry Reding 	of_node_put(np);
94853d2a715SThierry Reding 	return err;
94953d2a715SThierry Reding }
95053d2a715SThierry Reding 
tegra_xusb_hsic_port_release(struct tegra_xusb_port * port)951e78fdbadSThierry Reding void tegra_xusb_hsic_port_release(struct tegra_xusb_port *port)
952e78fdbadSThierry Reding {
953e78fdbadSThierry Reding 	struct tegra_xusb_hsic_port *hsic = to_hsic_port(port);
954e78fdbadSThierry Reding 
955e78fdbadSThierry Reding 	kfree(hsic);
956e78fdbadSThierry Reding }
957e78fdbadSThierry Reding 
tegra_xusb_usb3_port_parse_dt(struct tegra_xusb_usb3_port * usb3)95853d2a715SThierry Reding static int tegra_xusb_usb3_port_parse_dt(struct tegra_xusb_usb3_port *usb3)
95953d2a715SThierry Reding {
96053d2a715SThierry Reding 	struct tegra_xusb_port *port = &usb3->base;
96153d2a715SThierry Reding 	struct device_node *np = port->dev.of_node;
9621ef535c6SJC Kuo 	enum usb_device_speed maximum_speed;
96353d2a715SThierry Reding 	u32 value;
96453d2a715SThierry Reding 	int err;
96553d2a715SThierry Reding 
96653d2a715SThierry Reding 	err = of_property_read_u32(np, "nvidia,usb2-companion", &value);
96753d2a715SThierry Reding 	if (err < 0) {
96853d2a715SThierry Reding 		dev_err(&port->dev, "failed to read port: %d\n", err);
96953d2a715SThierry Reding 		return err;
97053d2a715SThierry Reding 	}
97153d2a715SThierry Reding 
97253d2a715SThierry Reding 	usb3->port = value;
97353d2a715SThierry Reding 
97453d2a715SThierry Reding 	usb3->internal = of_property_read_bool(np, "nvidia,internal");
97553d2a715SThierry Reding 
9761ef535c6SJC Kuo 	if (device_property_present(&port->dev, "maximum-speed")) {
9771ef535c6SJC Kuo 		maximum_speed =  usb_get_maximum_speed(&port->dev);
9781ef535c6SJC Kuo 		if (maximum_speed == USB_SPEED_SUPER)
9791ef535c6SJC Kuo 			usb3->disable_gen2 = true;
9801ef535c6SJC Kuo 		else if (maximum_speed == USB_SPEED_SUPER_PLUS)
9811ef535c6SJC Kuo 			usb3->disable_gen2 = false;
9821ef535c6SJC Kuo 		else
9831ef535c6SJC Kuo 			return -EINVAL;
9841ef535c6SJC Kuo 	}
9851ef535c6SJC Kuo 
9862428787fSWayne Chang 	return 0;
98753d2a715SThierry Reding }
98853d2a715SThierry Reding 
tegra_xusb_add_usb3_port(struct tegra_xusb_padctl * padctl,unsigned int index)98953d2a715SThierry Reding static int tegra_xusb_add_usb3_port(struct tegra_xusb_padctl *padctl,
99053d2a715SThierry Reding 				    unsigned int index)
99153d2a715SThierry Reding {
99253d2a715SThierry Reding 	struct tegra_xusb_usb3_port *usb3;
99353d2a715SThierry Reding 	struct device_node *np;
99453d2a715SThierry Reding 	int err = 0;
99553d2a715SThierry Reding 
99653d2a715SThierry Reding 	/*
99753d2a715SThierry Reding 	 * If there is no supplemental configuration in the device tree the
99853d2a715SThierry Reding 	 * port is unusable. But it is valid to configure only a single port,
99953d2a715SThierry Reding 	 * hence return 0 instead of an error to allow ports to be optional.
100053d2a715SThierry Reding 	 */
100153d2a715SThierry Reding 	np = tegra_xusb_find_port_node(padctl, "usb3", index);
100253d2a715SThierry Reding 	if (!np || !of_device_is_available(np))
100353d2a715SThierry Reding 		goto out;
100453d2a715SThierry Reding 
1005e78fdbadSThierry Reding 	usb3 = kzalloc(sizeof(*usb3), GFP_KERNEL);
100653d2a715SThierry Reding 	if (!usb3) {
100753d2a715SThierry Reding 		err = -ENOMEM;
100853d2a715SThierry Reding 		goto out;
100953d2a715SThierry Reding 	}
101053d2a715SThierry Reding 
101153d2a715SThierry Reding 	err = tegra_xusb_port_init(&usb3->base, padctl, np, "usb3", index);
101253d2a715SThierry Reding 	if (err < 0)
101353d2a715SThierry Reding 		goto out;
101453d2a715SThierry Reding 
101553d2a715SThierry Reding 	usb3->base.ops = padctl->soc->ports.usb3.ops;
101653d2a715SThierry Reding 
101753d2a715SThierry Reding 	usb3->base.lane = usb3->base.ops->map(&usb3->base);
101853d2a715SThierry Reding 	if (IS_ERR(usb3->base.lane)) {
101953d2a715SThierry Reding 		err = PTR_ERR(usb3->base.lane);
102053d2a715SThierry Reding 		goto out;
102153d2a715SThierry Reding 	}
102253d2a715SThierry Reding 
102353d2a715SThierry Reding 	err = tegra_xusb_usb3_port_parse_dt(usb3);
102453d2a715SThierry Reding 	if (err < 0) {
102553d2a715SThierry Reding 		tegra_xusb_port_unregister(&usb3->base);
102653d2a715SThierry Reding 		goto out;
102753d2a715SThierry Reding 	}
102853d2a715SThierry Reding 
102953d2a715SThierry Reding 	list_add_tail(&usb3->base.list, &padctl->ports);
103053d2a715SThierry Reding 
103153d2a715SThierry Reding out:
103253d2a715SThierry Reding 	of_node_put(np);
103353d2a715SThierry Reding 	return err;
103453d2a715SThierry Reding }
103553d2a715SThierry Reding 
tegra_xusb_usb3_port_release(struct tegra_xusb_port * port)1036e78fdbadSThierry Reding void tegra_xusb_usb3_port_release(struct tegra_xusb_port *port)
1037e78fdbadSThierry Reding {
1038e78fdbadSThierry Reding 	struct tegra_xusb_usb3_port *usb3 = to_usb3_port(port);
1039e78fdbadSThierry Reding 
1040e78fdbadSThierry Reding 	kfree(usb3);
1041e78fdbadSThierry Reding }
1042e78fdbadSThierry Reding 
__tegra_xusb_remove_ports(struct tegra_xusb_padctl * padctl)104353d2a715SThierry Reding static void __tegra_xusb_remove_ports(struct tegra_xusb_padctl *padctl)
104453d2a715SThierry Reding {
104553d2a715SThierry Reding 	struct tegra_xusb_port *port, *tmp;
104653d2a715SThierry Reding 
104753d2a715SThierry Reding 	list_for_each_entry_safe_reverse(port, tmp, &padctl->ports, list) {
104853d2a715SThierry Reding 		list_del(&port->list);
104953d2a715SThierry Reding 		tegra_xusb_port_unregister(port);
105053d2a715SThierry Reding 	}
105153d2a715SThierry Reding }
105253d2a715SThierry Reding 
tegra_xusb_find_unused_usb3_port(struct tegra_xusb_padctl * padctl)1053a5be28c3SNagarjuna Kristam static int tegra_xusb_find_unused_usb3_port(struct tegra_xusb_padctl *padctl)
1054a5be28c3SNagarjuna Kristam {
1055a5be28c3SNagarjuna Kristam 	struct device_node *np;
1056a5be28c3SNagarjuna Kristam 	unsigned int i;
1057a5be28c3SNagarjuna Kristam 
1058a5be28c3SNagarjuna Kristam 	for (i = 0; i < padctl->soc->ports.usb3.count; i++) {
1059a5be28c3SNagarjuna Kristam 		np = tegra_xusb_find_port_node(padctl, "usb3", i);
1060a5be28c3SNagarjuna Kristam 		if (!np || !of_device_is_available(np))
1061a5be28c3SNagarjuna Kristam 			return i;
1062a5be28c3SNagarjuna Kristam 	}
1063a5be28c3SNagarjuna Kristam 
1064a5be28c3SNagarjuna Kristam 	return -ENODEV;
1065a5be28c3SNagarjuna Kristam }
1066a5be28c3SNagarjuna Kristam 
tegra_xusb_port_is_companion(struct tegra_xusb_usb2_port * usb2)1067a5be28c3SNagarjuna Kristam static bool tegra_xusb_port_is_companion(struct tegra_xusb_usb2_port *usb2)
1068a5be28c3SNagarjuna Kristam {
1069a5be28c3SNagarjuna Kristam 	unsigned int i;
1070a5be28c3SNagarjuna Kristam 	struct tegra_xusb_usb3_port *usb3;
1071a5be28c3SNagarjuna Kristam 	struct tegra_xusb_padctl *padctl = usb2->base.padctl;
1072a5be28c3SNagarjuna Kristam 
1073a5be28c3SNagarjuna Kristam 	for (i = 0; i < padctl->soc->ports.usb3.count; i++) {
1074a5be28c3SNagarjuna Kristam 		usb3 = tegra_xusb_find_usb3_port(padctl, i);
1075a5be28c3SNagarjuna Kristam 		if (usb3 && usb3->port == usb2->base.index)
1076a5be28c3SNagarjuna Kristam 			return true;
1077a5be28c3SNagarjuna Kristam 	}
1078a5be28c3SNagarjuna Kristam 
1079a5be28c3SNagarjuna Kristam 	return false;
1080a5be28c3SNagarjuna Kristam }
1081a5be28c3SNagarjuna Kristam 
tegra_xusb_update_usb3_fake_port(struct tegra_xusb_usb2_port * usb2)1082a5be28c3SNagarjuna Kristam static int tegra_xusb_update_usb3_fake_port(struct tegra_xusb_usb2_port *usb2)
1083a5be28c3SNagarjuna Kristam {
1084a5be28c3SNagarjuna Kristam 	int fake;
1085a5be28c3SNagarjuna Kristam 
1086a5be28c3SNagarjuna Kristam 	/* Disable usb3_port_fake usage by default and assign if needed */
1087a5be28c3SNagarjuna Kristam 	usb2->usb3_port_fake = -1;
1088a5be28c3SNagarjuna Kristam 
1089a5be28c3SNagarjuna Kristam 	if ((usb2->mode == USB_DR_MODE_OTG ||
1090a5be28c3SNagarjuna Kristam 	     usb2->mode == USB_DR_MODE_PERIPHERAL) &&
1091a5be28c3SNagarjuna Kristam 		!tegra_xusb_port_is_companion(usb2)) {
1092a5be28c3SNagarjuna Kristam 		fake = tegra_xusb_find_unused_usb3_port(usb2->base.padctl);
1093a5be28c3SNagarjuna Kristam 		if (fake < 0) {
1094a5be28c3SNagarjuna Kristam 			dev_err(&usb2->base.dev, "no unused USB3 ports available\n");
1095a5be28c3SNagarjuna Kristam 			return -ENODEV;
1096a5be28c3SNagarjuna Kristam 		}
1097a5be28c3SNagarjuna Kristam 
1098a5be28c3SNagarjuna Kristam 		dev_dbg(&usb2->base.dev, "Found unused usb3 port: %d\n", fake);
1099a5be28c3SNagarjuna Kristam 		usb2->usb3_port_fake = fake;
1100a5be28c3SNagarjuna Kristam 	}
1101a5be28c3SNagarjuna Kristam 
1102a5be28c3SNagarjuna Kristam 	return 0;
1103a5be28c3SNagarjuna Kristam }
1104a5be28c3SNagarjuna Kristam 
tegra_xusb_setup_ports(struct tegra_xusb_padctl * padctl)110553d2a715SThierry Reding static int tegra_xusb_setup_ports(struct tegra_xusb_padctl *padctl)
110653d2a715SThierry Reding {
110753d2a715SThierry Reding 	struct tegra_xusb_port *port;
1108a5be28c3SNagarjuna Kristam 	struct tegra_xusb_usb2_port *usb2;
110953d2a715SThierry Reding 	unsigned int i;
111053d2a715SThierry Reding 	int err = 0;
111153d2a715SThierry Reding 
111253d2a715SThierry Reding 	mutex_lock(&padctl->lock);
111353d2a715SThierry Reding 
111453d2a715SThierry Reding 	for (i = 0; i < padctl->soc->ports.usb2.count; i++) {
111553d2a715SThierry Reding 		err = tegra_xusb_add_usb2_port(padctl, i);
111653d2a715SThierry Reding 		if (err < 0)
111753d2a715SThierry Reding 			goto remove_ports;
111853d2a715SThierry Reding 	}
111953d2a715SThierry Reding 
112053d2a715SThierry Reding 	for (i = 0; i < padctl->soc->ports.ulpi.count; i++) {
112153d2a715SThierry Reding 		err = tegra_xusb_add_ulpi_port(padctl, i);
112253d2a715SThierry Reding 		if (err < 0)
112353d2a715SThierry Reding 			goto remove_ports;
112453d2a715SThierry Reding 	}
112553d2a715SThierry Reding 
112653d2a715SThierry Reding 	for (i = 0; i < padctl->soc->ports.hsic.count; i++) {
112753d2a715SThierry Reding 		err = tegra_xusb_add_hsic_port(padctl, i);
112853d2a715SThierry Reding 		if (err < 0)
112953d2a715SThierry Reding 			goto remove_ports;
113053d2a715SThierry Reding 	}
113153d2a715SThierry Reding 
113253d2a715SThierry Reding 	for (i = 0; i < padctl->soc->ports.usb3.count; i++) {
113353d2a715SThierry Reding 		err = tegra_xusb_add_usb3_port(padctl, i);
113453d2a715SThierry Reding 		if (err < 0)
113553d2a715SThierry Reding 			goto remove_ports;
113653d2a715SThierry Reding 	}
113753d2a715SThierry Reding 
1138a5be28c3SNagarjuna Kristam 	if (padctl->soc->need_fake_usb3_port) {
1139a5be28c3SNagarjuna Kristam 		for (i = 0; i < padctl->soc->ports.usb2.count; i++) {
1140a5be28c3SNagarjuna Kristam 			usb2 = tegra_xusb_find_usb2_port(padctl, i);
1141a5be28c3SNagarjuna Kristam 			if (!usb2)
1142a5be28c3SNagarjuna Kristam 				continue;
1143a5be28c3SNagarjuna Kristam 
1144a5be28c3SNagarjuna Kristam 			err = tegra_xusb_update_usb3_fake_port(usb2);
1145a5be28c3SNagarjuna Kristam 			if (err < 0)
1146a5be28c3SNagarjuna Kristam 				goto remove_ports;
1147a5be28c3SNagarjuna Kristam 		}
1148a5be28c3SNagarjuna Kristam 	}
1149a5be28c3SNagarjuna Kristam 
115053d2a715SThierry Reding 	list_for_each_entry(port, &padctl->ports, list) {
115153d2a715SThierry Reding 		err = port->ops->enable(port);
115253d2a715SThierry Reding 		if (err < 0)
115353d2a715SThierry Reding 			dev_err(padctl->dev, "failed to enable port %s: %d\n",
115453d2a715SThierry Reding 				dev_name(&port->dev), err);
115553d2a715SThierry Reding 	}
115653d2a715SThierry Reding 
115753d2a715SThierry Reding 	goto unlock;
115853d2a715SThierry Reding 
115953d2a715SThierry Reding remove_ports:
116053d2a715SThierry Reding 	__tegra_xusb_remove_ports(padctl);
116153d2a715SThierry Reding unlock:
116253d2a715SThierry Reding 	mutex_unlock(&padctl->lock);
116353d2a715SThierry Reding 	return err;
116453d2a715SThierry Reding }
116553d2a715SThierry Reding 
tegra_xusb_remove_ports(struct tegra_xusb_padctl * padctl)116653d2a715SThierry Reding static void tegra_xusb_remove_ports(struct tegra_xusb_padctl *padctl)
116753d2a715SThierry Reding {
116853d2a715SThierry Reding 	mutex_lock(&padctl->lock);
116953d2a715SThierry Reding 	__tegra_xusb_remove_ports(padctl);
117053d2a715SThierry Reding 	mutex_unlock(&padctl->lock);
117153d2a715SThierry Reding }
117253d2a715SThierry Reding 
tegra_xusb_padctl_probe(struct platform_device * pdev)117353d2a715SThierry Reding static int tegra_xusb_padctl_probe(struct platform_device *pdev)
117453d2a715SThierry Reding {
117504604673SJohan Hovold 	struct device_node *np = pdev->dev.of_node;
117653d2a715SThierry Reding 	const struct tegra_xusb_padctl_soc *soc;
117753d2a715SThierry Reding 	struct tegra_xusb_padctl *padctl;
117853d2a715SThierry Reding 	const struct of_device_id *match;
117953d2a715SThierry Reding 	int err;
118053d2a715SThierry Reding 
118153d2a715SThierry Reding 	/* for backwards compatibility with old device trees */
118204604673SJohan Hovold 	np = of_get_child_by_name(np, "pads");
118353d2a715SThierry Reding 	if (!np) {
118453d2a715SThierry Reding 		dev_warn(&pdev->dev, "deprecated DT, using legacy driver\n");
118553d2a715SThierry Reding 		return tegra_xusb_padctl_legacy_probe(pdev);
118653d2a715SThierry Reding 	}
118753d2a715SThierry Reding 
118853d2a715SThierry Reding 	of_node_put(np);
118953d2a715SThierry Reding 
119053d2a715SThierry Reding 	match = of_match_node(tegra_xusb_padctl_of_match, pdev->dev.of_node);
119153d2a715SThierry Reding 	soc = match->data;
119253d2a715SThierry Reding 
119353d2a715SThierry Reding 	padctl = soc->ops->probe(&pdev->dev, soc);
119453d2a715SThierry Reding 	if (IS_ERR(padctl))
119553d2a715SThierry Reding 		return PTR_ERR(padctl);
119653d2a715SThierry Reding 
119753d2a715SThierry Reding 	platform_set_drvdata(pdev, padctl);
119853d2a715SThierry Reding 	INIT_LIST_HEAD(&padctl->ports);
119953d2a715SThierry Reding 	INIT_LIST_HEAD(&padctl->lanes);
120053d2a715SThierry Reding 	INIT_LIST_HEAD(&padctl->pads);
120153d2a715SThierry Reding 	mutex_init(&padctl->lock);
120253d2a715SThierry Reding 
12039ab4212bSChunfeng Yun 	padctl->regs = devm_platform_ioremap_resource(pdev, 0);
120453d2a715SThierry Reding 	if (IS_ERR(padctl->regs)) {
120553d2a715SThierry Reding 		err = PTR_ERR(padctl->regs);
120653d2a715SThierry Reding 		goto remove;
120753d2a715SThierry Reding 	}
120853d2a715SThierry Reding 
120953d2a715SThierry Reding 	padctl->rst = devm_reset_control_get(&pdev->dev, NULL);
121053d2a715SThierry Reding 	if (IS_ERR(padctl->rst)) {
121153d2a715SThierry Reding 		err = PTR_ERR(padctl->rst);
121253d2a715SThierry Reding 		goto remove;
121353d2a715SThierry Reding 	}
121453d2a715SThierry Reding 
1215a630d54dSThierry Reding 	padctl->supplies = devm_kcalloc(&pdev->dev, padctl->soc->num_supplies,
1216a630d54dSThierry Reding 					sizeof(*padctl->supplies), GFP_KERNEL);
1217a630d54dSThierry Reding 	if (!padctl->supplies) {
1218a630d54dSThierry Reding 		err = -ENOMEM;
1219a630d54dSThierry Reding 		goto remove;
1220a630d54dSThierry Reding 	}
1221a630d54dSThierry Reding 
122264d5989cSBartosz Golaszewski 	regulator_bulk_set_supply_names(padctl->supplies,
122364d5989cSBartosz Golaszewski 					padctl->soc->supply_names,
122464d5989cSBartosz Golaszewski 					padctl->soc->num_supplies);
1225a630d54dSThierry Reding 
1226a630d54dSThierry Reding 	err = devm_regulator_bulk_get(&pdev->dev, padctl->soc->num_supplies,
1227a630d54dSThierry Reding 				      padctl->supplies);
1228a630d54dSThierry Reding 	if (err < 0) {
122950c0133cSJon Hunter 		dev_err_probe(&pdev->dev, err, "failed to get regulators\n");
1230a630d54dSThierry Reding 		goto remove;
1231a630d54dSThierry Reding 	}
1232a630d54dSThierry Reding 
123353d2a715SThierry Reding 	err = reset_control_deassert(padctl->rst);
123453d2a715SThierry Reding 	if (err < 0)
123553d2a715SThierry Reding 		goto remove;
123653d2a715SThierry Reding 
1237a630d54dSThierry Reding 	err = regulator_bulk_enable(padctl->soc->num_supplies,
1238a630d54dSThierry Reding 				    padctl->supplies);
1239a630d54dSThierry Reding 	if (err < 0) {
1240a630d54dSThierry Reding 		dev_err(&pdev->dev, "failed to enable supplies: %d\n", err);
1241a630d54dSThierry Reding 		goto reset;
1242a630d54dSThierry Reding 	}
1243a630d54dSThierry Reding 
124453d2a715SThierry Reding 	err = tegra_xusb_setup_pads(padctl);
124553d2a715SThierry Reding 	if (err < 0) {
124653d2a715SThierry Reding 		dev_err(&pdev->dev, "failed to setup pads: %d\n", err);
1247a630d54dSThierry Reding 		goto power_down;
124853d2a715SThierry Reding 	}
124953d2a715SThierry Reding 
125053d2a715SThierry Reding 	err = tegra_xusb_setup_ports(padctl);
125153d2a715SThierry Reding 	if (err) {
125256283564SThierry Reding 		const char *level = KERN_ERR;
125356283564SThierry Reding 
125456283564SThierry Reding 		if (err == -EPROBE_DEFER)
125556283564SThierry Reding 			level = KERN_DEBUG;
125656283564SThierry Reding 
125756283564SThierry Reding 		dev_printk(level, &pdev->dev,
125856283564SThierry Reding 			   dev_fmt("failed to setup XUSB ports: %d\n"), err);
125953d2a715SThierry Reding 		goto remove_pads;
126053d2a715SThierry Reding 	}
126153d2a715SThierry Reding 
126253d2a715SThierry Reding 	return 0;
126353d2a715SThierry Reding 
126453d2a715SThierry Reding remove_pads:
126553d2a715SThierry Reding 	tegra_xusb_remove_pads(padctl);
1266a630d54dSThierry Reding power_down:
1267a630d54dSThierry Reding 	regulator_bulk_disable(padctl->soc->num_supplies, padctl->supplies);
126853d2a715SThierry Reding reset:
126953d2a715SThierry Reding 	reset_control_assert(padctl->rst);
127053d2a715SThierry Reding remove:
1271eb9c4dd9SMarc Zyngier 	platform_set_drvdata(pdev, NULL);
127253d2a715SThierry Reding 	soc->ops->remove(padctl);
127353d2a715SThierry Reding 	return err;
127453d2a715SThierry Reding }
127553d2a715SThierry Reding 
tegra_xusb_padctl_remove(struct platform_device * pdev)127680460691SUwe Kleine-König static void tegra_xusb_padctl_remove(struct platform_device *pdev)
127753d2a715SThierry Reding {
127853d2a715SThierry Reding 	struct tegra_xusb_padctl *padctl = platform_get_drvdata(pdev);
127953d2a715SThierry Reding 	int err;
128053d2a715SThierry Reding 
128153d2a715SThierry Reding 	tegra_xusb_remove_ports(padctl);
128253d2a715SThierry Reding 	tegra_xusb_remove_pads(padctl);
128353d2a715SThierry Reding 
1284a630d54dSThierry Reding 	err = regulator_bulk_disable(padctl->soc->num_supplies,
1285a630d54dSThierry Reding 				     padctl->supplies);
1286a630d54dSThierry Reding 	if (err < 0)
1287a630d54dSThierry Reding 		dev_err(&pdev->dev, "failed to disable supplies: %d\n", err);
1288a630d54dSThierry Reding 
128953d2a715SThierry Reding 	err = reset_control_assert(padctl->rst);
129053d2a715SThierry Reding 	if (err < 0)
129153d2a715SThierry Reding 		dev_err(&pdev->dev, "failed to assert reset: %d\n", err);
129253d2a715SThierry Reding 
129353d2a715SThierry Reding 	padctl->soc->ops->remove(padctl);
129453d2a715SThierry Reding }
129553d2a715SThierry Reding 
tegra_xusb_padctl_suspend_noirq(struct device * dev)1296c1302e8cSArnd Bergmann static __maybe_unused int tegra_xusb_padctl_suspend_noirq(struct device *dev)
1297c545a905SJC Kuo {
1298c545a905SJC Kuo 	struct tegra_xusb_padctl *padctl = dev_get_drvdata(dev);
1299c545a905SJC Kuo 
1300c545a905SJC Kuo 	if (padctl->soc && padctl->soc->ops && padctl->soc->ops->suspend_noirq)
1301c545a905SJC Kuo 		return padctl->soc->ops->suspend_noirq(padctl);
1302c545a905SJC Kuo 
1303c545a905SJC Kuo 	return 0;
1304c545a905SJC Kuo }
1305c545a905SJC Kuo 
tegra_xusb_padctl_resume_noirq(struct device * dev)1306c1302e8cSArnd Bergmann static __maybe_unused int tegra_xusb_padctl_resume_noirq(struct device *dev)
1307c545a905SJC Kuo {
1308c545a905SJC Kuo 	struct tegra_xusb_padctl *padctl = dev_get_drvdata(dev);
1309c545a905SJC Kuo 
1310c545a905SJC Kuo 	if (padctl->soc && padctl->soc->ops && padctl->soc->ops->resume_noirq)
1311c545a905SJC Kuo 		return padctl->soc->ops->resume_noirq(padctl);
1312c545a905SJC Kuo 
1313c545a905SJC Kuo 	return 0;
1314c545a905SJC Kuo }
1315c545a905SJC Kuo 
1316c545a905SJC Kuo static const struct dev_pm_ops tegra_xusb_padctl_pm_ops = {
1317c545a905SJC Kuo 	SET_NOIRQ_SYSTEM_SLEEP_PM_OPS(tegra_xusb_padctl_suspend_noirq,
1318c545a905SJC Kuo 				      tegra_xusb_padctl_resume_noirq)
1319c545a905SJC Kuo };
1320c545a905SJC Kuo 
132153d2a715SThierry Reding static struct platform_driver tegra_xusb_padctl_driver = {
132253d2a715SThierry Reding 	.driver = {
132353d2a715SThierry Reding 		.name = "tegra-xusb-padctl",
132453d2a715SThierry Reding 		.of_match_table = tegra_xusb_padctl_of_match,
1325c545a905SJC Kuo 		.pm = &tegra_xusb_padctl_pm_ops,
132653d2a715SThierry Reding 	},
132753d2a715SThierry Reding 	.probe = tegra_xusb_padctl_probe,
132880460691SUwe Kleine-König 	.remove_new = tegra_xusb_padctl_remove,
132953d2a715SThierry Reding };
133053d2a715SThierry Reding module_platform_driver(tegra_xusb_padctl_driver);
133153d2a715SThierry Reding 
tegra_xusb_padctl_get(struct device * dev)133253d2a715SThierry Reding struct tegra_xusb_padctl *tegra_xusb_padctl_get(struct device *dev)
133353d2a715SThierry Reding {
133453d2a715SThierry Reding 	struct tegra_xusb_padctl *padctl;
133553d2a715SThierry Reding 	struct platform_device *pdev;
133653d2a715SThierry Reding 	struct device_node *np;
133753d2a715SThierry Reding 
133853d2a715SThierry Reding 	np = of_parse_phandle(dev->of_node, "nvidia,xusb-padctl", 0);
133953d2a715SThierry Reding 	if (!np)
134053d2a715SThierry Reding 		return ERR_PTR(-EINVAL);
134153d2a715SThierry Reding 
134253d2a715SThierry Reding 	/*
134353d2a715SThierry Reding 	 * This is slightly ugly. A better implementation would be to keep a
134453d2a715SThierry Reding 	 * registry of pad controllers, but since there will almost certainly
134553d2a715SThierry Reding 	 * only ever be one per SoC that would be a little overkill.
134653d2a715SThierry Reding 	 */
134753d2a715SThierry Reding 	pdev = of_find_device_by_node(np);
134853d2a715SThierry Reding 	if (!pdev) {
134953d2a715SThierry Reding 		of_node_put(np);
135053d2a715SThierry Reding 		return ERR_PTR(-ENODEV);
135153d2a715SThierry Reding 	}
135253d2a715SThierry Reding 
135353d2a715SThierry Reding 	of_node_put(np);
135453d2a715SThierry Reding 
135553d2a715SThierry Reding 	padctl = platform_get_drvdata(pdev);
135653d2a715SThierry Reding 	if (!padctl) {
135753d2a715SThierry Reding 		put_device(&pdev->dev);
135853d2a715SThierry Reding 		return ERR_PTR(-EPROBE_DEFER);
135953d2a715SThierry Reding 	}
136053d2a715SThierry Reding 
136153d2a715SThierry Reding 	return padctl;
136253d2a715SThierry Reding }
136353d2a715SThierry Reding EXPORT_SYMBOL_GPL(tegra_xusb_padctl_get);
136453d2a715SThierry Reding 
tegra_xusb_padctl_put(struct tegra_xusb_padctl * padctl)136553d2a715SThierry Reding void tegra_xusb_padctl_put(struct tegra_xusb_padctl *padctl)
136653d2a715SThierry Reding {
136753d2a715SThierry Reding 	if (padctl)
136853d2a715SThierry Reding 		put_device(padctl->dev);
136953d2a715SThierry Reding }
137053d2a715SThierry Reding EXPORT_SYMBOL_GPL(tegra_xusb_padctl_put);
137153d2a715SThierry Reding 
tegra_xusb_padctl_usb3_save_context(struct tegra_xusb_padctl * padctl,unsigned int port)137253d2a715SThierry Reding int tegra_xusb_padctl_usb3_save_context(struct tegra_xusb_padctl *padctl,
137353d2a715SThierry Reding 					unsigned int port)
137453d2a715SThierry Reding {
137553d2a715SThierry Reding 	if (padctl->soc->ops->usb3_save_context)
137653d2a715SThierry Reding 		return padctl->soc->ops->usb3_save_context(padctl, port);
137753d2a715SThierry Reding 
137853d2a715SThierry Reding 	return -ENOSYS;
137953d2a715SThierry Reding }
138053d2a715SThierry Reding EXPORT_SYMBOL_GPL(tegra_xusb_padctl_usb3_save_context);
138153d2a715SThierry Reding 
tegra_xusb_padctl_hsic_set_idle(struct tegra_xusb_padctl * padctl,unsigned int port,bool idle)138253d2a715SThierry Reding int tegra_xusb_padctl_hsic_set_idle(struct tegra_xusb_padctl *padctl,
138353d2a715SThierry Reding 				    unsigned int port, bool idle)
138453d2a715SThierry Reding {
138553d2a715SThierry Reding 	if (padctl->soc->ops->hsic_set_idle)
138653d2a715SThierry Reding 		return padctl->soc->ops->hsic_set_idle(padctl, port, idle);
138753d2a715SThierry Reding 
138853d2a715SThierry Reding 	return -ENOSYS;
138953d2a715SThierry Reding }
139053d2a715SThierry Reding EXPORT_SYMBOL_GPL(tegra_xusb_padctl_hsic_set_idle);
139153d2a715SThierry Reding 
tegra_xusb_padctl_enable_phy_sleepwalk(struct tegra_xusb_padctl * padctl,struct phy * phy,enum usb_device_speed speed)1392c545a905SJC Kuo int tegra_xusb_padctl_enable_phy_sleepwalk(struct tegra_xusb_padctl *padctl, struct phy *phy,
1393c545a905SJC Kuo 					   enum usb_device_speed speed)
1394c545a905SJC Kuo {
1395c545a905SJC Kuo 	struct tegra_xusb_lane *lane = phy_get_drvdata(phy);
1396c545a905SJC Kuo 
1397c545a905SJC Kuo 	if (lane->pad->ops->enable_phy_sleepwalk)
1398c545a905SJC Kuo 		return lane->pad->ops->enable_phy_sleepwalk(lane, speed);
1399c545a905SJC Kuo 
1400c545a905SJC Kuo 	return -EOPNOTSUPP;
1401c545a905SJC Kuo }
1402c545a905SJC Kuo EXPORT_SYMBOL_GPL(tegra_xusb_padctl_enable_phy_sleepwalk);
1403c545a905SJC Kuo 
tegra_xusb_padctl_disable_phy_sleepwalk(struct tegra_xusb_padctl * padctl,struct phy * phy)1404c545a905SJC Kuo int tegra_xusb_padctl_disable_phy_sleepwalk(struct tegra_xusb_padctl *padctl, struct phy *phy)
1405c545a905SJC Kuo {
1406c545a905SJC Kuo 	struct tegra_xusb_lane *lane = phy_get_drvdata(phy);
1407c545a905SJC Kuo 
1408c545a905SJC Kuo 	if (lane->pad->ops->disable_phy_sleepwalk)
1409c545a905SJC Kuo 		return lane->pad->ops->disable_phy_sleepwalk(lane);
1410c545a905SJC Kuo 
1411c545a905SJC Kuo 	return -EOPNOTSUPP;
1412c545a905SJC Kuo }
1413c545a905SJC Kuo EXPORT_SYMBOL_GPL(tegra_xusb_padctl_disable_phy_sleepwalk);
1414c545a905SJC Kuo 
tegra_xusb_padctl_enable_phy_wake(struct tegra_xusb_padctl * padctl,struct phy * phy)1415c545a905SJC Kuo int tegra_xusb_padctl_enable_phy_wake(struct tegra_xusb_padctl *padctl, struct phy *phy)
1416c545a905SJC Kuo {
1417c545a905SJC Kuo 	struct tegra_xusb_lane *lane = phy_get_drvdata(phy);
1418c545a905SJC Kuo 
1419c545a905SJC Kuo 	if (lane->pad->ops->enable_phy_wake)
1420c545a905SJC Kuo 		return lane->pad->ops->enable_phy_wake(lane);
1421c545a905SJC Kuo 
1422c545a905SJC Kuo 	return -EOPNOTSUPP;
1423c545a905SJC Kuo }
1424c545a905SJC Kuo EXPORT_SYMBOL_GPL(tegra_xusb_padctl_enable_phy_wake);
1425c545a905SJC Kuo 
tegra_xusb_padctl_disable_phy_wake(struct tegra_xusb_padctl * padctl,struct phy * phy)1426c545a905SJC Kuo int tegra_xusb_padctl_disable_phy_wake(struct tegra_xusb_padctl *padctl, struct phy *phy)
1427c545a905SJC Kuo {
1428c545a905SJC Kuo 	struct tegra_xusb_lane *lane = phy_get_drvdata(phy);
1429c545a905SJC Kuo 
1430c545a905SJC Kuo 	if (lane->pad->ops->disable_phy_wake)
1431c545a905SJC Kuo 		return lane->pad->ops->disable_phy_wake(lane);
1432c545a905SJC Kuo 
1433c545a905SJC Kuo 	return -EOPNOTSUPP;
1434c545a905SJC Kuo }
1435c545a905SJC Kuo EXPORT_SYMBOL_GPL(tegra_xusb_padctl_disable_phy_wake);
1436c545a905SJC Kuo 
tegra_xusb_padctl_remote_wake_detected(struct tegra_xusb_padctl * padctl,struct phy * phy)1437c545a905SJC Kuo bool tegra_xusb_padctl_remote_wake_detected(struct tegra_xusb_padctl *padctl, struct phy *phy)
1438c545a905SJC Kuo {
1439c545a905SJC Kuo 	struct tegra_xusb_lane *lane = phy_get_drvdata(phy);
1440c545a905SJC Kuo 
1441c545a905SJC Kuo 	if (lane->pad->ops->remote_wake_detected)
1442c545a905SJC Kuo 		return lane->pad->ops->remote_wake_detected(lane);
1443c545a905SJC Kuo 
1444c545a905SJC Kuo 	return false;
1445c545a905SJC Kuo }
1446c545a905SJC Kuo EXPORT_SYMBOL_GPL(tegra_xusb_padctl_remote_wake_detected);
1447c545a905SJC Kuo 
tegra_xusb_padctl_usb3_set_lfps_detect(struct tegra_xusb_padctl * padctl,unsigned int port,bool enable)144853d2a715SThierry Reding int tegra_xusb_padctl_usb3_set_lfps_detect(struct tegra_xusb_padctl *padctl,
144953d2a715SThierry Reding 					   unsigned int port, bool enable)
145053d2a715SThierry Reding {
145153d2a715SThierry Reding 	if (padctl->soc->ops->usb3_set_lfps_detect)
145253d2a715SThierry Reding 		return padctl->soc->ops->usb3_set_lfps_detect(padctl, port,
145353d2a715SThierry Reding 							      enable);
145453d2a715SThierry Reding 
145553d2a715SThierry Reding 	return -ENOSYS;
145653d2a715SThierry Reding }
145753d2a715SThierry Reding EXPORT_SYMBOL_GPL(tegra_xusb_padctl_usb3_set_lfps_detect);
145853d2a715SThierry Reding 
tegra_xusb_padctl_set_vbus_override(struct tegra_xusb_padctl * padctl,bool val)145990767cdfSNagarjuna Kristam int tegra_xusb_padctl_set_vbus_override(struct tegra_xusb_padctl *padctl,
146090767cdfSNagarjuna Kristam 							bool val)
146190767cdfSNagarjuna Kristam {
146290767cdfSNagarjuna Kristam 	if (padctl->soc->ops->vbus_override)
146390767cdfSNagarjuna Kristam 		return padctl->soc->ops->vbus_override(padctl, val);
146490767cdfSNagarjuna Kristam 
146590767cdfSNagarjuna Kristam 	return -ENOTSUPP;
146690767cdfSNagarjuna Kristam }
146790767cdfSNagarjuna Kristam EXPORT_SYMBOL_GPL(tegra_xusb_padctl_set_vbus_override);
146890767cdfSNagarjuna Kristam 
tegra_phy_xusb_utmi_port_reset(struct phy * phy)146990767cdfSNagarjuna Kristam int tegra_phy_xusb_utmi_port_reset(struct phy *phy)
147090767cdfSNagarjuna Kristam {
147190767cdfSNagarjuna Kristam 	struct tegra_xusb_lane *lane = phy_get_drvdata(phy);
147290767cdfSNagarjuna Kristam 	struct tegra_xusb_padctl *padctl = lane->pad->padctl;
147390767cdfSNagarjuna Kristam 
147490767cdfSNagarjuna Kristam 	if (padctl->soc->ops->utmi_port_reset)
147590767cdfSNagarjuna Kristam 		return padctl->soc->ops->utmi_port_reset(phy);
147690767cdfSNagarjuna Kristam 
147790767cdfSNagarjuna Kristam 	return -ENOTSUPP;
147890767cdfSNagarjuna Kristam }
147990767cdfSNagarjuna Kristam EXPORT_SYMBOL_GPL(tegra_phy_xusb_utmi_port_reset);
148090767cdfSNagarjuna Kristam 
tegra_phy_xusb_utmi_pad_power_on(struct phy * phy)148177bfa0fcSJim Lin void tegra_phy_xusb_utmi_pad_power_on(struct phy *phy)
148277bfa0fcSJim Lin {
14832a4ea83bSJon Hunter 	struct tegra_xusb_lane *lane;
14842a4ea83bSJon Hunter 	struct tegra_xusb_padctl *padctl;
14852a4ea83bSJon Hunter 
14862a4ea83bSJon Hunter 	if (!phy)
14872a4ea83bSJon Hunter 		return;
14882a4ea83bSJon Hunter 
14892a4ea83bSJon Hunter 	lane = phy_get_drvdata(phy);
14902a4ea83bSJon Hunter 	padctl = lane->pad->padctl;
149177bfa0fcSJim Lin 
149277bfa0fcSJim Lin 	if (padctl->soc->ops->utmi_pad_power_on)
149377bfa0fcSJim Lin 		padctl->soc->ops->utmi_pad_power_on(phy);
149477bfa0fcSJim Lin }
149577bfa0fcSJim Lin EXPORT_SYMBOL_GPL(tegra_phy_xusb_utmi_pad_power_on);
149677bfa0fcSJim Lin 
tegra_phy_xusb_utmi_pad_power_down(struct phy * phy)149777bfa0fcSJim Lin void tegra_phy_xusb_utmi_pad_power_down(struct phy *phy)
149877bfa0fcSJim Lin {
14992a4ea83bSJon Hunter 	struct tegra_xusb_lane *lane;
15002a4ea83bSJon Hunter 	struct tegra_xusb_padctl *padctl;
15012a4ea83bSJon Hunter 
15022a4ea83bSJon Hunter 	if (!phy)
15032a4ea83bSJon Hunter 		return;
15042a4ea83bSJon Hunter 
15052a4ea83bSJon Hunter 	lane = phy_get_drvdata(phy);
15062a4ea83bSJon Hunter 	padctl = lane->pad->padctl;
150777bfa0fcSJim Lin 
150877bfa0fcSJim Lin 	if (padctl->soc->ops->utmi_pad_power_down)
150977bfa0fcSJim Lin 		padctl->soc->ops->utmi_pad_power_down(phy);
151077bfa0fcSJim Lin }
151177bfa0fcSJim Lin EXPORT_SYMBOL_GPL(tegra_phy_xusb_utmi_pad_power_down);
151277bfa0fcSJim Lin 
tegra_xusb_padctl_get_usb3_companion(struct tegra_xusb_padctl * padctl,unsigned int port)15135a40fc4bSNagarjuna Kristam int tegra_xusb_padctl_get_usb3_companion(struct tegra_xusb_padctl *padctl,
15145a40fc4bSNagarjuna Kristam 				    unsigned int port)
15155a40fc4bSNagarjuna Kristam {
15165a40fc4bSNagarjuna Kristam 	struct tegra_xusb_usb2_port *usb2;
15175a40fc4bSNagarjuna Kristam 	struct tegra_xusb_usb3_port *usb3;
15185a40fc4bSNagarjuna Kristam 	int i;
15195a40fc4bSNagarjuna Kristam 
15205a40fc4bSNagarjuna Kristam 	usb2 = tegra_xusb_find_usb2_port(padctl, port);
15215a40fc4bSNagarjuna Kristam 	if (!usb2)
15225a40fc4bSNagarjuna Kristam 		return -EINVAL;
15235a40fc4bSNagarjuna Kristam 
15245a40fc4bSNagarjuna Kristam 	for (i = 0; i < padctl->soc->ports.usb3.count; i++) {
15255a40fc4bSNagarjuna Kristam 		usb3 = tegra_xusb_find_usb3_port(padctl, i);
15265a40fc4bSNagarjuna Kristam 		if (usb3 && usb3->port == usb2->base.index)
15275a40fc4bSNagarjuna Kristam 			return usb3->base.index;
15285a40fc4bSNagarjuna Kristam 	}
15295a40fc4bSNagarjuna Kristam 
15305a40fc4bSNagarjuna Kristam 	return -ENODEV;
15315a40fc4bSNagarjuna Kristam }
15325a40fc4bSNagarjuna Kristam EXPORT_SYMBOL_GPL(tegra_xusb_padctl_get_usb3_companion);
15335a40fc4bSNagarjuna Kristam 
tegra_xusb_padctl_get_port_number(struct phy * phy)15343dd6e0faSWayne Chang int tegra_xusb_padctl_get_port_number(struct phy *phy)
15353dd6e0faSWayne Chang {
15363dd6e0faSWayne Chang 	struct tegra_xusb_lane *lane;
15373dd6e0faSWayne Chang 
15383dd6e0faSWayne Chang 	if (!phy)
15393dd6e0faSWayne Chang 		return -ENODEV;
15403dd6e0faSWayne Chang 
15413dd6e0faSWayne Chang 	lane = phy_get_drvdata(phy);
15423dd6e0faSWayne Chang 
15433dd6e0faSWayne Chang 	return lane->index;
15443dd6e0faSWayne Chang }
15453dd6e0faSWayne Chang EXPORT_SYMBOL_GPL(tegra_xusb_padctl_get_port_number);
15463dd6e0faSWayne Chang 
154753d2a715SThierry Reding MODULE_AUTHOR("Thierry Reding <treding@nvidia.com>");
154853d2a715SThierry Reding MODULE_DESCRIPTION("Tegra XUSB Pad Controller driver");
154953d2a715SThierry Reding MODULE_LICENSE("GPL v2");
1550