18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0
28c2ecf20Sopenharmony_ci/*
38c2ecf20Sopenharmony_ci * Copyright (c) 2016-2019, NVIDIA CORPORATION.  All rights reserved.
48c2ecf20Sopenharmony_ci */
58c2ecf20Sopenharmony_ci
68c2ecf20Sopenharmony_ci#include <linux/delay.h>
78c2ecf20Sopenharmony_ci#include <linux/io.h>
88c2ecf20Sopenharmony_ci#include <linux/module.h>
98c2ecf20Sopenharmony_ci#include <linux/of.h>
108c2ecf20Sopenharmony_ci#include <linux/phy/phy.h>
118c2ecf20Sopenharmony_ci#include <linux/regulator/consumer.h>
128c2ecf20Sopenharmony_ci#include <linux/platform_device.h>
138c2ecf20Sopenharmony_ci#include <linux/clk.h>
148c2ecf20Sopenharmony_ci#include <linux/slab.h>
158c2ecf20Sopenharmony_ci
168c2ecf20Sopenharmony_ci#include <soc/tegra/fuse.h>
178c2ecf20Sopenharmony_ci
188c2ecf20Sopenharmony_ci#include "xusb.h"
198c2ecf20Sopenharmony_ci
208c2ecf20Sopenharmony_ci/* FUSE USB_CALIB registers */
218c2ecf20Sopenharmony_ci#define HS_CURR_LEVEL_PADX_SHIFT(x)	((x) ? (11 + (x - 1) * 6) : 0)
228c2ecf20Sopenharmony_ci#define HS_CURR_LEVEL_PAD_MASK		0x3f
238c2ecf20Sopenharmony_ci#define HS_TERM_RANGE_ADJ_SHIFT		7
248c2ecf20Sopenharmony_ci#define HS_TERM_RANGE_ADJ_MASK		0xf
258c2ecf20Sopenharmony_ci#define HS_SQUELCH_SHIFT		29
268c2ecf20Sopenharmony_ci#define HS_SQUELCH_MASK			0x7
278c2ecf20Sopenharmony_ci
288c2ecf20Sopenharmony_ci#define RPD_CTRL_SHIFT			0
298c2ecf20Sopenharmony_ci#define RPD_CTRL_MASK			0x1f
308c2ecf20Sopenharmony_ci
318c2ecf20Sopenharmony_ci/* XUSB PADCTL registers */
328c2ecf20Sopenharmony_ci#define XUSB_PADCTL_USB2_PAD_MUX	0x4
338c2ecf20Sopenharmony_ci#define  USB2_PORT_SHIFT(x)		((x) * 2)
348c2ecf20Sopenharmony_ci#define  USB2_PORT_MASK			0x3
358c2ecf20Sopenharmony_ci#define   PORT_XUSB			1
368c2ecf20Sopenharmony_ci#define  HSIC_PORT_SHIFT(x)		((x) + 20)
378c2ecf20Sopenharmony_ci#define  HSIC_PORT_MASK			0x1
388c2ecf20Sopenharmony_ci#define   PORT_HSIC			0
398c2ecf20Sopenharmony_ci
408c2ecf20Sopenharmony_ci#define XUSB_PADCTL_USB2_PORT_CAP	0x8
418c2ecf20Sopenharmony_ci#define XUSB_PADCTL_SS_PORT_CAP		0xc
428c2ecf20Sopenharmony_ci#define  PORTX_CAP_SHIFT(x)		((x) * 4)
438c2ecf20Sopenharmony_ci#define  PORT_CAP_MASK			0x3
448c2ecf20Sopenharmony_ci#define   PORT_CAP_DISABLED		0x0
458c2ecf20Sopenharmony_ci#define   PORT_CAP_HOST			0x1
468c2ecf20Sopenharmony_ci#define   PORT_CAP_DEVICE		0x2
478c2ecf20Sopenharmony_ci#define   PORT_CAP_OTG			0x3
488c2ecf20Sopenharmony_ci
498c2ecf20Sopenharmony_ci#define XUSB_PADCTL_ELPG_PROGRAM		0x20
508c2ecf20Sopenharmony_ci#define  USB2_PORT_WAKE_INTERRUPT_ENABLE(x)		BIT(x)
518c2ecf20Sopenharmony_ci#define  USB2_PORT_WAKEUP_EVENT(x)			BIT((x) +  7)
528c2ecf20Sopenharmony_ci#define  SS_PORT_WAKE_INTERRUPT_ENABLE(x)		BIT((x) + 14)
538c2ecf20Sopenharmony_ci#define  SS_PORT_WAKEUP_EVENT(x)			BIT((x) + 21)
548c2ecf20Sopenharmony_ci#define  USB2_HSIC_PORT_WAKE_INTERRUPT_ENABLE(x)	BIT((x) + 28)
558c2ecf20Sopenharmony_ci#define  USB2_HSIC_PORT_WAKEUP_EVENT(x)			BIT((x) + 30)
568c2ecf20Sopenharmony_ci#define  ALL_WAKE_EVENTS						\
578c2ecf20Sopenharmony_ci	(USB2_PORT_WAKEUP_EVENT(0) | USB2_PORT_WAKEUP_EVENT(1) |	\
588c2ecf20Sopenharmony_ci	USB2_PORT_WAKEUP_EVENT(2) | SS_PORT_WAKEUP_EVENT(0) |		\
598c2ecf20Sopenharmony_ci	SS_PORT_WAKEUP_EVENT(1) | SS_PORT_WAKEUP_EVENT(2) |		\
608c2ecf20Sopenharmony_ci	USB2_HSIC_PORT_WAKEUP_EVENT(0))
618c2ecf20Sopenharmony_ci
628c2ecf20Sopenharmony_ci#define XUSB_PADCTL_ELPG_PROGRAM_1		0x24
638c2ecf20Sopenharmony_ci#define  SSPX_ELPG_CLAMP_EN(x)			BIT(0 + (x) * 3)
648c2ecf20Sopenharmony_ci#define  SSPX_ELPG_CLAMP_EN_EARLY(x)		BIT(1 + (x) * 3)
658c2ecf20Sopenharmony_ci#define  SSPX_ELPG_VCORE_DOWN(x)		BIT(2 + (x) * 3)
668c2ecf20Sopenharmony_ci#define XUSB_PADCTL_SS_PORT_CFG			0x2c
678c2ecf20Sopenharmony_ci#define   PORTX_SPEED_SUPPORT_SHIFT(x)		((x) * 4)
688c2ecf20Sopenharmony_ci#define   PORTX_SPEED_SUPPORT_MASK		(0x3)
698c2ecf20Sopenharmony_ci#define     PORT_SPEED_SUPPORT_GEN1		(0x0)
708c2ecf20Sopenharmony_ci
718c2ecf20Sopenharmony_ci#define XUSB_PADCTL_USB2_OTG_PADX_CTL0(x)	(0x88 + (x) * 0x40)
728c2ecf20Sopenharmony_ci#define  HS_CURR_LEVEL(x)			((x) & 0x3f)
738c2ecf20Sopenharmony_ci#define  TERM_SEL				BIT(25)
748c2ecf20Sopenharmony_ci#define  USB2_OTG_PD				BIT(26)
758c2ecf20Sopenharmony_ci#define  USB2_OTG_PD2				BIT(27)
768c2ecf20Sopenharmony_ci#define  USB2_OTG_PD2_OVRD_EN			BIT(28)
778c2ecf20Sopenharmony_ci#define  USB2_OTG_PD_ZI				BIT(29)
788c2ecf20Sopenharmony_ci
798c2ecf20Sopenharmony_ci#define XUSB_PADCTL_USB2_OTG_PADX_CTL1(x)	(0x8c + (x) * 0x40)
808c2ecf20Sopenharmony_ci#define  USB2_OTG_PD_DR				BIT(2)
818c2ecf20Sopenharmony_ci#define  TERM_RANGE_ADJ(x)			(((x) & 0xf) << 3)
828c2ecf20Sopenharmony_ci#define  RPD_CTRL(x)				(((x) & 0x1f) << 26)
838c2ecf20Sopenharmony_ci
848c2ecf20Sopenharmony_ci#define XUSB_PADCTL_USB2_BIAS_PAD_CTL0		0x284
858c2ecf20Sopenharmony_ci#define  BIAS_PAD_PD				BIT(11)
868c2ecf20Sopenharmony_ci#define  HS_SQUELCH_LEVEL(x)			(((x) & 0x7) << 0)
878c2ecf20Sopenharmony_ci
888c2ecf20Sopenharmony_ci#define XUSB_PADCTL_USB2_BIAS_PAD_CTL1		0x288
898c2ecf20Sopenharmony_ci#define  USB2_TRK_START_TIMER(x)		(((x) & 0x7f) << 12)
908c2ecf20Sopenharmony_ci#define  USB2_TRK_DONE_RESET_TIMER(x)		(((x) & 0x7f) << 19)
918c2ecf20Sopenharmony_ci#define  USB2_PD_TRK				BIT(26)
928c2ecf20Sopenharmony_ci
938c2ecf20Sopenharmony_ci#define XUSB_PADCTL_HSIC_PADX_CTL0(x)		(0x300 + (x) * 0x20)
948c2ecf20Sopenharmony_ci#define  HSIC_PD_TX_DATA0			BIT(1)
958c2ecf20Sopenharmony_ci#define  HSIC_PD_TX_STROBE			BIT(3)
968c2ecf20Sopenharmony_ci#define  HSIC_PD_RX_DATA0			BIT(4)
978c2ecf20Sopenharmony_ci#define  HSIC_PD_RX_STROBE			BIT(6)
988c2ecf20Sopenharmony_ci#define  HSIC_PD_ZI_DATA0			BIT(7)
998c2ecf20Sopenharmony_ci#define  HSIC_PD_ZI_STROBE			BIT(9)
1008c2ecf20Sopenharmony_ci#define  HSIC_RPD_DATA0				BIT(13)
1018c2ecf20Sopenharmony_ci#define  HSIC_RPD_STROBE			BIT(15)
1028c2ecf20Sopenharmony_ci#define  HSIC_RPU_DATA0				BIT(16)
1038c2ecf20Sopenharmony_ci#define  HSIC_RPU_STROBE			BIT(18)
1048c2ecf20Sopenharmony_ci
1058c2ecf20Sopenharmony_ci#define XUSB_PADCTL_HSIC_PAD_TRK_CTL0		0x340
1068c2ecf20Sopenharmony_ci#define  HSIC_TRK_START_TIMER(x)		(((x) & 0x7f) << 5)
1078c2ecf20Sopenharmony_ci#define  HSIC_TRK_DONE_RESET_TIMER(x)		(((x) & 0x7f) << 12)
1088c2ecf20Sopenharmony_ci#define  HSIC_PD_TRK				BIT(19)
1098c2ecf20Sopenharmony_ci
1108c2ecf20Sopenharmony_ci#define USB2_VBUS_ID				0x360
1118c2ecf20Sopenharmony_ci#define  VBUS_OVERRIDE				BIT(14)
1128c2ecf20Sopenharmony_ci#define  ID_OVERRIDE(x)				(((x) & 0xf) << 18)
1138c2ecf20Sopenharmony_ci#define  ID_OVERRIDE_FLOATING			ID_OVERRIDE(8)
1148c2ecf20Sopenharmony_ci#define  ID_OVERRIDE_GROUNDED			ID_OVERRIDE(0)
1158c2ecf20Sopenharmony_ci
1168c2ecf20Sopenharmony_ci#define TEGRA186_LANE(_name, _offset, _shift, _mask, _type)		\
1178c2ecf20Sopenharmony_ci	{								\
1188c2ecf20Sopenharmony_ci		.name = _name,						\
1198c2ecf20Sopenharmony_ci		.offset = _offset,					\
1208c2ecf20Sopenharmony_ci		.shift = _shift,					\
1218c2ecf20Sopenharmony_ci		.mask = _mask,						\
1228c2ecf20Sopenharmony_ci		.num_funcs = ARRAY_SIZE(tegra186_##_type##_functions),	\
1238c2ecf20Sopenharmony_ci		.funcs = tegra186_##_type##_functions,			\
1248c2ecf20Sopenharmony_ci	}
1258c2ecf20Sopenharmony_ci
1268c2ecf20Sopenharmony_cistruct tegra_xusb_fuse_calibration {
1278c2ecf20Sopenharmony_ci	u32 *hs_curr_level;
1288c2ecf20Sopenharmony_ci	u32 hs_squelch;
1298c2ecf20Sopenharmony_ci	u32 hs_term_range_adj;
1308c2ecf20Sopenharmony_ci	u32 rpd_ctrl;
1318c2ecf20Sopenharmony_ci};
1328c2ecf20Sopenharmony_ci
1338c2ecf20Sopenharmony_cistruct tegra186_xusb_padctl {
1348c2ecf20Sopenharmony_ci	struct tegra_xusb_padctl base;
1358c2ecf20Sopenharmony_ci
1368c2ecf20Sopenharmony_ci	struct tegra_xusb_fuse_calibration calib;
1378c2ecf20Sopenharmony_ci
1388c2ecf20Sopenharmony_ci	/* UTMI bias and tracking */
1398c2ecf20Sopenharmony_ci	struct clk *usb2_trk_clk;
1408c2ecf20Sopenharmony_ci	unsigned int bias_pad_enable;
1418c2ecf20Sopenharmony_ci};
1428c2ecf20Sopenharmony_ci
1438c2ecf20Sopenharmony_cistatic inline struct tegra186_xusb_padctl *
1448c2ecf20Sopenharmony_cito_tegra186_xusb_padctl(struct tegra_xusb_padctl *padctl)
1458c2ecf20Sopenharmony_ci{
1468c2ecf20Sopenharmony_ci	return container_of(padctl, struct tegra186_xusb_padctl, base);
1478c2ecf20Sopenharmony_ci}
1488c2ecf20Sopenharmony_ci
1498c2ecf20Sopenharmony_ci/* USB 2.0 UTMI PHY support */
1508c2ecf20Sopenharmony_cistatic struct tegra_xusb_lane *
1518c2ecf20Sopenharmony_citegra186_usb2_lane_probe(struct tegra_xusb_pad *pad, struct device_node *np,
1528c2ecf20Sopenharmony_ci			 unsigned int index)
1538c2ecf20Sopenharmony_ci{
1548c2ecf20Sopenharmony_ci	struct tegra_xusb_usb2_lane *usb2;
1558c2ecf20Sopenharmony_ci	int err;
1568c2ecf20Sopenharmony_ci
1578c2ecf20Sopenharmony_ci	usb2 = kzalloc(sizeof(*usb2), GFP_KERNEL);
1588c2ecf20Sopenharmony_ci	if (!usb2)
1598c2ecf20Sopenharmony_ci		return ERR_PTR(-ENOMEM);
1608c2ecf20Sopenharmony_ci
1618c2ecf20Sopenharmony_ci	INIT_LIST_HEAD(&usb2->base.list);
1628c2ecf20Sopenharmony_ci	usb2->base.soc = &pad->soc->lanes[index];
1638c2ecf20Sopenharmony_ci	usb2->base.index = index;
1648c2ecf20Sopenharmony_ci	usb2->base.pad = pad;
1658c2ecf20Sopenharmony_ci	usb2->base.np = np;
1668c2ecf20Sopenharmony_ci
1678c2ecf20Sopenharmony_ci	err = tegra_xusb_lane_parse_dt(&usb2->base, np);
1688c2ecf20Sopenharmony_ci	if (err < 0) {
1698c2ecf20Sopenharmony_ci		kfree(usb2);
1708c2ecf20Sopenharmony_ci		return ERR_PTR(err);
1718c2ecf20Sopenharmony_ci	}
1728c2ecf20Sopenharmony_ci
1738c2ecf20Sopenharmony_ci	return &usb2->base;
1748c2ecf20Sopenharmony_ci}
1758c2ecf20Sopenharmony_ci
1768c2ecf20Sopenharmony_cistatic void tegra186_usb2_lane_remove(struct tegra_xusb_lane *lane)
1778c2ecf20Sopenharmony_ci{
1788c2ecf20Sopenharmony_ci	struct tegra_xusb_usb2_lane *usb2 = to_usb2_lane(lane);
1798c2ecf20Sopenharmony_ci
1808c2ecf20Sopenharmony_ci	kfree(usb2);
1818c2ecf20Sopenharmony_ci}
1828c2ecf20Sopenharmony_ci
1838c2ecf20Sopenharmony_cistatic const struct tegra_xusb_lane_ops tegra186_usb2_lane_ops = {
1848c2ecf20Sopenharmony_ci	.probe = tegra186_usb2_lane_probe,
1858c2ecf20Sopenharmony_ci	.remove = tegra186_usb2_lane_remove,
1868c2ecf20Sopenharmony_ci};
1878c2ecf20Sopenharmony_ci
1888c2ecf20Sopenharmony_cistatic void tegra186_utmi_bias_pad_power_on(struct tegra_xusb_padctl *padctl)
1898c2ecf20Sopenharmony_ci{
1908c2ecf20Sopenharmony_ci	struct tegra186_xusb_padctl *priv = to_tegra186_xusb_padctl(padctl);
1918c2ecf20Sopenharmony_ci	struct device *dev = padctl->dev;
1928c2ecf20Sopenharmony_ci	u32 value;
1938c2ecf20Sopenharmony_ci	int err;
1948c2ecf20Sopenharmony_ci
1958c2ecf20Sopenharmony_ci	mutex_lock(&padctl->lock);
1968c2ecf20Sopenharmony_ci
1978c2ecf20Sopenharmony_ci	if (priv->bias_pad_enable++ > 0) {
1988c2ecf20Sopenharmony_ci		mutex_unlock(&padctl->lock);
1998c2ecf20Sopenharmony_ci		return;
2008c2ecf20Sopenharmony_ci	}
2018c2ecf20Sopenharmony_ci
2028c2ecf20Sopenharmony_ci	err = clk_prepare_enable(priv->usb2_trk_clk);
2038c2ecf20Sopenharmony_ci	if (err < 0)
2048c2ecf20Sopenharmony_ci		dev_warn(dev, "failed to enable USB2 trk clock: %d\n", err);
2058c2ecf20Sopenharmony_ci
2068c2ecf20Sopenharmony_ci	value = padctl_readl(padctl, XUSB_PADCTL_USB2_BIAS_PAD_CTL1);
2078c2ecf20Sopenharmony_ci	value &= ~USB2_TRK_START_TIMER(~0);
2088c2ecf20Sopenharmony_ci	value |= USB2_TRK_START_TIMER(0x1e);
2098c2ecf20Sopenharmony_ci	value &= ~USB2_TRK_DONE_RESET_TIMER(~0);
2108c2ecf20Sopenharmony_ci	value |= USB2_TRK_DONE_RESET_TIMER(0xa);
2118c2ecf20Sopenharmony_ci	padctl_writel(padctl, value, XUSB_PADCTL_USB2_BIAS_PAD_CTL1);
2128c2ecf20Sopenharmony_ci
2138c2ecf20Sopenharmony_ci	value = padctl_readl(padctl, XUSB_PADCTL_USB2_BIAS_PAD_CTL0);
2148c2ecf20Sopenharmony_ci	value &= ~BIAS_PAD_PD;
2158c2ecf20Sopenharmony_ci	value &= ~HS_SQUELCH_LEVEL(~0);
2168c2ecf20Sopenharmony_ci	value |= HS_SQUELCH_LEVEL(priv->calib.hs_squelch);
2178c2ecf20Sopenharmony_ci	padctl_writel(padctl, value, XUSB_PADCTL_USB2_BIAS_PAD_CTL0);
2188c2ecf20Sopenharmony_ci
2198c2ecf20Sopenharmony_ci	udelay(1);
2208c2ecf20Sopenharmony_ci
2218c2ecf20Sopenharmony_ci	value = padctl_readl(padctl, XUSB_PADCTL_USB2_BIAS_PAD_CTL1);
2228c2ecf20Sopenharmony_ci	value &= ~USB2_PD_TRK;
2238c2ecf20Sopenharmony_ci	padctl_writel(padctl, value, XUSB_PADCTL_USB2_BIAS_PAD_CTL1);
2248c2ecf20Sopenharmony_ci
2258c2ecf20Sopenharmony_ci	mutex_unlock(&padctl->lock);
2268c2ecf20Sopenharmony_ci}
2278c2ecf20Sopenharmony_ci
2288c2ecf20Sopenharmony_cistatic void tegra186_utmi_bias_pad_power_off(struct tegra_xusb_padctl *padctl)
2298c2ecf20Sopenharmony_ci{
2308c2ecf20Sopenharmony_ci	struct tegra186_xusb_padctl *priv = to_tegra186_xusb_padctl(padctl);
2318c2ecf20Sopenharmony_ci	u32 value;
2328c2ecf20Sopenharmony_ci
2338c2ecf20Sopenharmony_ci	mutex_lock(&padctl->lock);
2348c2ecf20Sopenharmony_ci
2358c2ecf20Sopenharmony_ci	if (WARN_ON(priv->bias_pad_enable == 0)) {
2368c2ecf20Sopenharmony_ci		mutex_unlock(&padctl->lock);
2378c2ecf20Sopenharmony_ci		return;
2388c2ecf20Sopenharmony_ci	}
2398c2ecf20Sopenharmony_ci
2408c2ecf20Sopenharmony_ci	if (--priv->bias_pad_enable > 0) {
2418c2ecf20Sopenharmony_ci		mutex_unlock(&padctl->lock);
2428c2ecf20Sopenharmony_ci		return;
2438c2ecf20Sopenharmony_ci	}
2448c2ecf20Sopenharmony_ci
2458c2ecf20Sopenharmony_ci	value = padctl_readl(padctl, XUSB_PADCTL_USB2_BIAS_PAD_CTL1);
2468c2ecf20Sopenharmony_ci	value |= USB2_PD_TRK;
2478c2ecf20Sopenharmony_ci	padctl_writel(padctl, value, XUSB_PADCTL_USB2_BIAS_PAD_CTL1);
2488c2ecf20Sopenharmony_ci
2498c2ecf20Sopenharmony_ci	clk_disable_unprepare(priv->usb2_trk_clk);
2508c2ecf20Sopenharmony_ci
2518c2ecf20Sopenharmony_ci	mutex_unlock(&padctl->lock);
2528c2ecf20Sopenharmony_ci}
2538c2ecf20Sopenharmony_ci
2548c2ecf20Sopenharmony_cistatic void tegra_phy_xusb_utmi_pad_power_on(struct phy *phy)
2558c2ecf20Sopenharmony_ci{
2568c2ecf20Sopenharmony_ci	struct tegra_xusb_lane *lane = phy_get_drvdata(phy);
2578c2ecf20Sopenharmony_ci	struct tegra_xusb_padctl *padctl = lane->pad->padctl;
2588c2ecf20Sopenharmony_ci	struct tegra_xusb_usb2_port *port;
2598c2ecf20Sopenharmony_ci	struct device *dev = padctl->dev;
2608c2ecf20Sopenharmony_ci	unsigned int index = lane->index;
2618c2ecf20Sopenharmony_ci	u32 value;
2628c2ecf20Sopenharmony_ci
2638c2ecf20Sopenharmony_ci	if (!phy)
2648c2ecf20Sopenharmony_ci		return;
2658c2ecf20Sopenharmony_ci
2668c2ecf20Sopenharmony_ci	port = tegra_xusb_find_usb2_port(padctl, index);
2678c2ecf20Sopenharmony_ci	if (!port) {
2688c2ecf20Sopenharmony_ci		dev_err(dev, "no port found for USB2 lane %u\n", index);
2698c2ecf20Sopenharmony_ci		return;
2708c2ecf20Sopenharmony_ci	}
2718c2ecf20Sopenharmony_ci
2728c2ecf20Sopenharmony_ci	tegra186_utmi_bias_pad_power_on(padctl);
2738c2ecf20Sopenharmony_ci
2748c2ecf20Sopenharmony_ci	udelay(2);
2758c2ecf20Sopenharmony_ci
2768c2ecf20Sopenharmony_ci	value = padctl_readl(padctl, XUSB_PADCTL_USB2_OTG_PADX_CTL0(index));
2778c2ecf20Sopenharmony_ci	value &= ~USB2_OTG_PD;
2788c2ecf20Sopenharmony_ci	padctl_writel(padctl, value, XUSB_PADCTL_USB2_OTG_PADX_CTL0(index));
2798c2ecf20Sopenharmony_ci
2808c2ecf20Sopenharmony_ci	value = padctl_readl(padctl, XUSB_PADCTL_USB2_OTG_PADX_CTL1(index));
2818c2ecf20Sopenharmony_ci	value &= ~USB2_OTG_PD_DR;
2828c2ecf20Sopenharmony_ci	padctl_writel(padctl, value, XUSB_PADCTL_USB2_OTG_PADX_CTL1(index));
2838c2ecf20Sopenharmony_ci}
2848c2ecf20Sopenharmony_ci
2858c2ecf20Sopenharmony_cistatic void tegra_phy_xusb_utmi_pad_power_down(struct phy *phy)
2868c2ecf20Sopenharmony_ci{
2878c2ecf20Sopenharmony_ci	struct tegra_xusb_lane *lane = phy_get_drvdata(phy);
2888c2ecf20Sopenharmony_ci	struct tegra_xusb_padctl *padctl = lane->pad->padctl;
2898c2ecf20Sopenharmony_ci	unsigned int index = lane->index;
2908c2ecf20Sopenharmony_ci	u32 value;
2918c2ecf20Sopenharmony_ci
2928c2ecf20Sopenharmony_ci	if (!phy)
2938c2ecf20Sopenharmony_ci		return;
2948c2ecf20Sopenharmony_ci
2958c2ecf20Sopenharmony_ci	value = padctl_readl(padctl, XUSB_PADCTL_USB2_OTG_PADX_CTL0(index));
2968c2ecf20Sopenharmony_ci	value |= USB2_OTG_PD;
2978c2ecf20Sopenharmony_ci	padctl_writel(padctl, value, XUSB_PADCTL_USB2_OTG_PADX_CTL0(index));
2988c2ecf20Sopenharmony_ci
2998c2ecf20Sopenharmony_ci	value = padctl_readl(padctl, XUSB_PADCTL_USB2_OTG_PADX_CTL1(index));
3008c2ecf20Sopenharmony_ci	value |= USB2_OTG_PD_DR;
3018c2ecf20Sopenharmony_ci	padctl_writel(padctl, value, XUSB_PADCTL_USB2_OTG_PADX_CTL1(index));
3028c2ecf20Sopenharmony_ci
3038c2ecf20Sopenharmony_ci	udelay(2);
3048c2ecf20Sopenharmony_ci
3058c2ecf20Sopenharmony_ci	tegra186_utmi_bias_pad_power_off(padctl);
3068c2ecf20Sopenharmony_ci}
3078c2ecf20Sopenharmony_ci
3088c2ecf20Sopenharmony_cistatic int tegra186_xusb_padctl_vbus_override(struct tegra_xusb_padctl *padctl,
3098c2ecf20Sopenharmony_ci					       bool status)
3108c2ecf20Sopenharmony_ci{
3118c2ecf20Sopenharmony_ci	u32 value;
3128c2ecf20Sopenharmony_ci
3138c2ecf20Sopenharmony_ci	dev_dbg(padctl->dev, "%s vbus override\n", status ? "set" : "clear");
3148c2ecf20Sopenharmony_ci
3158c2ecf20Sopenharmony_ci	value = padctl_readl(padctl, USB2_VBUS_ID);
3168c2ecf20Sopenharmony_ci
3178c2ecf20Sopenharmony_ci	if (status) {
3188c2ecf20Sopenharmony_ci		value |= VBUS_OVERRIDE;
3198c2ecf20Sopenharmony_ci		value &= ~ID_OVERRIDE(~0);
3208c2ecf20Sopenharmony_ci		value |= ID_OVERRIDE_FLOATING;
3218c2ecf20Sopenharmony_ci	} else {
3228c2ecf20Sopenharmony_ci		value &= ~VBUS_OVERRIDE;
3238c2ecf20Sopenharmony_ci	}
3248c2ecf20Sopenharmony_ci
3258c2ecf20Sopenharmony_ci	padctl_writel(padctl, value, USB2_VBUS_ID);
3268c2ecf20Sopenharmony_ci
3278c2ecf20Sopenharmony_ci	return 0;
3288c2ecf20Sopenharmony_ci}
3298c2ecf20Sopenharmony_ci
3308c2ecf20Sopenharmony_cistatic int tegra186_xusb_padctl_id_override(struct tegra_xusb_padctl *padctl,
3318c2ecf20Sopenharmony_ci					    bool status)
3328c2ecf20Sopenharmony_ci{
3338c2ecf20Sopenharmony_ci	u32 value;
3348c2ecf20Sopenharmony_ci
3358c2ecf20Sopenharmony_ci	dev_dbg(padctl->dev, "%s id override\n", status ? "set" : "clear");
3368c2ecf20Sopenharmony_ci
3378c2ecf20Sopenharmony_ci	value = padctl_readl(padctl, USB2_VBUS_ID);
3388c2ecf20Sopenharmony_ci
3398c2ecf20Sopenharmony_ci	if (status) {
3408c2ecf20Sopenharmony_ci		if (value & VBUS_OVERRIDE) {
3418c2ecf20Sopenharmony_ci			value &= ~VBUS_OVERRIDE;
3428c2ecf20Sopenharmony_ci			padctl_writel(padctl, value, USB2_VBUS_ID);
3438c2ecf20Sopenharmony_ci			usleep_range(1000, 2000);
3448c2ecf20Sopenharmony_ci
3458c2ecf20Sopenharmony_ci			value = padctl_readl(padctl, USB2_VBUS_ID);
3468c2ecf20Sopenharmony_ci		}
3478c2ecf20Sopenharmony_ci
3488c2ecf20Sopenharmony_ci		value &= ~ID_OVERRIDE(~0);
3498c2ecf20Sopenharmony_ci		value |= ID_OVERRIDE_GROUNDED;
3508c2ecf20Sopenharmony_ci	} else {
3518c2ecf20Sopenharmony_ci		value &= ~ID_OVERRIDE(~0);
3528c2ecf20Sopenharmony_ci		value |= ID_OVERRIDE_FLOATING;
3538c2ecf20Sopenharmony_ci	}
3548c2ecf20Sopenharmony_ci
3558c2ecf20Sopenharmony_ci	padctl_writel(padctl, value, USB2_VBUS_ID);
3568c2ecf20Sopenharmony_ci
3578c2ecf20Sopenharmony_ci	return 0;
3588c2ecf20Sopenharmony_ci}
3598c2ecf20Sopenharmony_ci
3608c2ecf20Sopenharmony_cistatic int tegra186_utmi_phy_set_mode(struct phy *phy, enum phy_mode mode,
3618c2ecf20Sopenharmony_ci				      int submode)
3628c2ecf20Sopenharmony_ci{
3638c2ecf20Sopenharmony_ci	struct tegra_xusb_lane *lane = phy_get_drvdata(phy);
3648c2ecf20Sopenharmony_ci	struct tegra_xusb_padctl *padctl = lane->pad->padctl;
3658c2ecf20Sopenharmony_ci	struct tegra_xusb_usb2_port *port = tegra_xusb_find_usb2_port(padctl,
3668c2ecf20Sopenharmony_ci								lane->index);
3678c2ecf20Sopenharmony_ci	int err = 0;
3688c2ecf20Sopenharmony_ci
3698c2ecf20Sopenharmony_ci	mutex_lock(&padctl->lock);
3708c2ecf20Sopenharmony_ci
3718c2ecf20Sopenharmony_ci	dev_dbg(&port->base.dev, "%s: mode %d", __func__, mode);
3728c2ecf20Sopenharmony_ci
3738c2ecf20Sopenharmony_ci	if (mode == PHY_MODE_USB_OTG) {
3748c2ecf20Sopenharmony_ci		if (submode == USB_ROLE_HOST) {
3758c2ecf20Sopenharmony_ci			tegra186_xusb_padctl_id_override(padctl, true);
3768c2ecf20Sopenharmony_ci
3778c2ecf20Sopenharmony_ci			err = regulator_enable(port->supply);
3788c2ecf20Sopenharmony_ci		} else if (submode == USB_ROLE_DEVICE) {
3798c2ecf20Sopenharmony_ci			tegra186_xusb_padctl_vbus_override(padctl, true);
3808c2ecf20Sopenharmony_ci		} else if (submode == USB_ROLE_NONE) {
3818c2ecf20Sopenharmony_ci			/*
3828c2ecf20Sopenharmony_ci			 * When port is peripheral only or role transitions to
3838c2ecf20Sopenharmony_ci			 * USB_ROLE_NONE from USB_ROLE_DEVICE, regulator is not
3848c2ecf20Sopenharmony_ci			 * enabled.
3858c2ecf20Sopenharmony_ci			 */
3868c2ecf20Sopenharmony_ci			if (regulator_is_enabled(port->supply))
3878c2ecf20Sopenharmony_ci				regulator_disable(port->supply);
3888c2ecf20Sopenharmony_ci
3898c2ecf20Sopenharmony_ci			tegra186_xusb_padctl_id_override(padctl, false);
3908c2ecf20Sopenharmony_ci			tegra186_xusb_padctl_vbus_override(padctl, false);
3918c2ecf20Sopenharmony_ci		}
3928c2ecf20Sopenharmony_ci	}
3938c2ecf20Sopenharmony_ci
3948c2ecf20Sopenharmony_ci	mutex_unlock(&padctl->lock);
3958c2ecf20Sopenharmony_ci
3968c2ecf20Sopenharmony_ci	return err;
3978c2ecf20Sopenharmony_ci}
3988c2ecf20Sopenharmony_ci
3998c2ecf20Sopenharmony_cistatic int tegra186_utmi_phy_power_on(struct phy *phy)
4008c2ecf20Sopenharmony_ci{
4018c2ecf20Sopenharmony_ci	struct tegra_xusb_lane *lane = phy_get_drvdata(phy);
4028c2ecf20Sopenharmony_ci	struct tegra_xusb_usb2_lane *usb2 = to_usb2_lane(lane);
4038c2ecf20Sopenharmony_ci	struct tegra_xusb_padctl *padctl = lane->pad->padctl;
4048c2ecf20Sopenharmony_ci	struct tegra186_xusb_padctl *priv = to_tegra186_xusb_padctl(padctl);
4058c2ecf20Sopenharmony_ci	struct tegra_xusb_usb2_port *port;
4068c2ecf20Sopenharmony_ci	unsigned int index = lane->index;
4078c2ecf20Sopenharmony_ci	struct device *dev = padctl->dev;
4088c2ecf20Sopenharmony_ci	u32 value;
4098c2ecf20Sopenharmony_ci
4108c2ecf20Sopenharmony_ci	port = tegra_xusb_find_usb2_port(padctl, index);
4118c2ecf20Sopenharmony_ci	if (!port) {
4128c2ecf20Sopenharmony_ci		dev_err(dev, "no port found for USB2 lane %u\n", index);
4138c2ecf20Sopenharmony_ci		return -ENODEV;
4148c2ecf20Sopenharmony_ci	}
4158c2ecf20Sopenharmony_ci
4168c2ecf20Sopenharmony_ci	value = padctl_readl(padctl, XUSB_PADCTL_USB2_PAD_MUX);
4178c2ecf20Sopenharmony_ci	value &= ~(USB2_PORT_MASK << USB2_PORT_SHIFT(index));
4188c2ecf20Sopenharmony_ci	value |= (PORT_XUSB << USB2_PORT_SHIFT(index));
4198c2ecf20Sopenharmony_ci	padctl_writel(padctl, value, XUSB_PADCTL_USB2_PAD_MUX);
4208c2ecf20Sopenharmony_ci
4218c2ecf20Sopenharmony_ci	value = padctl_readl(padctl, XUSB_PADCTL_USB2_PORT_CAP);
4228c2ecf20Sopenharmony_ci	value &= ~(PORT_CAP_MASK << PORTX_CAP_SHIFT(index));
4238c2ecf20Sopenharmony_ci
4248c2ecf20Sopenharmony_ci	if (port->mode == USB_DR_MODE_UNKNOWN)
4258c2ecf20Sopenharmony_ci		value |= (PORT_CAP_DISABLED << PORTX_CAP_SHIFT(index));
4268c2ecf20Sopenharmony_ci	else if (port->mode == USB_DR_MODE_PERIPHERAL)
4278c2ecf20Sopenharmony_ci		value |= (PORT_CAP_DEVICE << PORTX_CAP_SHIFT(index));
4288c2ecf20Sopenharmony_ci	else if (port->mode == USB_DR_MODE_HOST)
4298c2ecf20Sopenharmony_ci		value |= (PORT_CAP_HOST << PORTX_CAP_SHIFT(index));
4308c2ecf20Sopenharmony_ci	else if (port->mode == USB_DR_MODE_OTG)
4318c2ecf20Sopenharmony_ci		value |= (PORT_CAP_OTG << PORTX_CAP_SHIFT(index));
4328c2ecf20Sopenharmony_ci
4338c2ecf20Sopenharmony_ci	padctl_writel(padctl, value, XUSB_PADCTL_USB2_PORT_CAP);
4348c2ecf20Sopenharmony_ci
4358c2ecf20Sopenharmony_ci	value = padctl_readl(padctl, XUSB_PADCTL_USB2_OTG_PADX_CTL0(index));
4368c2ecf20Sopenharmony_ci	value &= ~USB2_OTG_PD_ZI;
4378c2ecf20Sopenharmony_ci	value |= TERM_SEL;
4388c2ecf20Sopenharmony_ci	value &= ~HS_CURR_LEVEL(~0);
4398c2ecf20Sopenharmony_ci
4408c2ecf20Sopenharmony_ci	if (usb2->hs_curr_level_offset) {
4418c2ecf20Sopenharmony_ci		int hs_current_level;
4428c2ecf20Sopenharmony_ci
4438c2ecf20Sopenharmony_ci		hs_current_level = (int)priv->calib.hs_curr_level[index] +
4448c2ecf20Sopenharmony_ci						usb2->hs_curr_level_offset;
4458c2ecf20Sopenharmony_ci
4468c2ecf20Sopenharmony_ci		if (hs_current_level < 0)
4478c2ecf20Sopenharmony_ci			hs_current_level = 0;
4488c2ecf20Sopenharmony_ci		if (hs_current_level > 0x3f)
4498c2ecf20Sopenharmony_ci			hs_current_level = 0x3f;
4508c2ecf20Sopenharmony_ci
4518c2ecf20Sopenharmony_ci		value |= HS_CURR_LEVEL(hs_current_level);
4528c2ecf20Sopenharmony_ci	} else {
4538c2ecf20Sopenharmony_ci		value |= HS_CURR_LEVEL(priv->calib.hs_curr_level[index]);
4548c2ecf20Sopenharmony_ci	}
4558c2ecf20Sopenharmony_ci
4568c2ecf20Sopenharmony_ci	padctl_writel(padctl, value, XUSB_PADCTL_USB2_OTG_PADX_CTL0(index));
4578c2ecf20Sopenharmony_ci
4588c2ecf20Sopenharmony_ci	value = padctl_readl(padctl, XUSB_PADCTL_USB2_OTG_PADX_CTL1(index));
4598c2ecf20Sopenharmony_ci	value &= ~TERM_RANGE_ADJ(~0);
4608c2ecf20Sopenharmony_ci	value |= TERM_RANGE_ADJ(priv->calib.hs_term_range_adj);
4618c2ecf20Sopenharmony_ci	value &= ~RPD_CTRL(~0);
4628c2ecf20Sopenharmony_ci	value |= RPD_CTRL(priv->calib.rpd_ctrl);
4638c2ecf20Sopenharmony_ci	padctl_writel(padctl, value, XUSB_PADCTL_USB2_OTG_PADX_CTL1(index));
4648c2ecf20Sopenharmony_ci
4658c2ecf20Sopenharmony_ci	/* TODO: pad power saving */
4668c2ecf20Sopenharmony_ci	tegra_phy_xusb_utmi_pad_power_on(phy);
4678c2ecf20Sopenharmony_ci	return 0;
4688c2ecf20Sopenharmony_ci}
4698c2ecf20Sopenharmony_ci
4708c2ecf20Sopenharmony_cistatic int tegra186_utmi_phy_power_off(struct phy *phy)
4718c2ecf20Sopenharmony_ci{
4728c2ecf20Sopenharmony_ci	/* TODO: pad power saving */
4738c2ecf20Sopenharmony_ci	tegra_phy_xusb_utmi_pad_power_down(phy);
4748c2ecf20Sopenharmony_ci
4758c2ecf20Sopenharmony_ci	return 0;
4768c2ecf20Sopenharmony_ci}
4778c2ecf20Sopenharmony_ci
4788c2ecf20Sopenharmony_cistatic int tegra186_utmi_phy_init(struct phy *phy)
4798c2ecf20Sopenharmony_ci{
4808c2ecf20Sopenharmony_ci	struct tegra_xusb_lane *lane = phy_get_drvdata(phy);
4818c2ecf20Sopenharmony_ci	struct tegra_xusb_padctl *padctl = lane->pad->padctl;
4828c2ecf20Sopenharmony_ci	struct tegra_xusb_usb2_port *port;
4838c2ecf20Sopenharmony_ci	unsigned int index = lane->index;
4848c2ecf20Sopenharmony_ci	struct device *dev = padctl->dev;
4858c2ecf20Sopenharmony_ci	int err;
4868c2ecf20Sopenharmony_ci
4878c2ecf20Sopenharmony_ci	port = tegra_xusb_find_usb2_port(padctl, index);
4888c2ecf20Sopenharmony_ci	if (!port) {
4898c2ecf20Sopenharmony_ci		dev_err(dev, "no port found for USB2 lane %u\n", index);
4908c2ecf20Sopenharmony_ci		return -ENODEV;
4918c2ecf20Sopenharmony_ci	}
4928c2ecf20Sopenharmony_ci
4938c2ecf20Sopenharmony_ci	if (port->supply && port->mode == USB_DR_MODE_HOST) {
4948c2ecf20Sopenharmony_ci		err = regulator_enable(port->supply);
4958c2ecf20Sopenharmony_ci		if (err) {
4968c2ecf20Sopenharmony_ci			dev_err(dev, "failed to enable port %u VBUS: %d\n",
4978c2ecf20Sopenharmony_ci				index, err);
4988c2ecf20Sopenharmony_ci			return err;
4998c2ecf20Sopenharmony_ci		}
5008c2ecf20Sopenharmony_ci	}
5018c2ecf20Sopenharmony_ci
5028c2ecf20Sopenharmony_ci	return 0;
5038c2ecf20Sopenharmony_ci}
5048c2ecf20Sopenharmony_ci
5058c2ecf20Sopenharmony_cistatic int tegra186_utmi_phy_exit(struct phy *phy)
5068c2ecf20Sopenharmony_ci{
5078c2ecf20Sopenharmony_ci	struct tegra_xusb_lane *lane = phy_get_drvdata(phy);
5088c2ecf20Sopenharmony_ci	struct tegra_xusb_padctl *padctl = lane->pad->padctl;
5098c2ecf20Sopenharmony_ci	struct tegra_xusb_usb2_port *port;
5108c2ecf20Sopenharmony_ci	unsigned int index = lane->index;
5118c2ecf20Sopenharmony_ci	struct device *dev = padctl->dev;
5128c2ecf20Sopenharmony_ci	int err;
5138c2ecf20Sopenharmony_ci
5148c2ecf20Sopenharmony_ci	port = tegra_xusb_find_usb2_port(padctl, index);
5158c2ecf20Sopenharmony_ci	if (!port) {
5168c2ecf20Sopenharmony_ci		dev_err(dev, "no port found for USB2 lane %u\n", index);
5178c2ecf20Sopenharmony_ci		return -ENODEV;
5188c2ecf20Sopenharmony_ci	}
5198c2ecf20Sopenharmony_ci
5208c2ecf20Sopenharmony_ci	if (port->supply && port->mode == USB_DR_MODE_HOST) {
5218c2ecf20Sopenharmony_ci		err = regulator_disable(port->supply);
5228c2ecf20Sopenharmony_ci		if (err) {
5238c2ecf20Sopenharmony_ci			dev_err(dev, "failed to disable port %u VBUS: %d\n",
5248c2ecf20Sopenharmony_ci				index, err);
5258c2ecf20Sopenharmony_ci			return err;
5268c2ecf20Sopenharmony_ci		}
5278c2ecf20Sopenharmony_ci	}
5288c2ecf20Sopenharmony_ci
5298c2ecf20Sopenharmony_ci	return 0;
5308c2ecf20Sopenharmony_ci}
5318c2ecf20Sopenharmony_ci
5328c2ecf20Sopenharmony_cistatic const struct phy_ops utmi_phy_ops = {
5338c2ecf20Sopenharmony_ci	.init = tegra186_utmi_phy_init,
5348c2ecf20Sopenharmony_ci	.exit = tegra186_utmi_phy_exit,
5358c2ecf20Sopenharmony_ci	.power_on = tegra186_utmi_phy_power_on,
5368c2ecf20Sopenharmony_ci	.power_off = tegra186_utmi_phy_power_off,
5378c2ecf20Sopenharmony_ci	.set_mode = tegra186_utmi_phy_set_mode,
5388c2ecf20Sopenharmony_ci	.owner = THIS_MODULE,
5398c2ecf20Sopenharmony_ci};
5408c2ecf20Sopenharmony_ci
5418c2ecf20Sopenharmony_cistatic struct tegra_xusb_pad *
5428c2ecf20Sopenharmony_citegra186_usb2_pad_probe(struct tegra_xusb_padctl *padctl,
5438c2ecf20Sopenharmony_ci			const struct tegra_xusb_pad_soc *soc,
5448c2ecf20Sopenharmony_ci			struct device_node *np)
5458c2ecf20Sopenharmony_ci{
5468c2ecf20Sopenharmony_ci	struct tegra186_xusb_padctl *priv = to_tegra186_xusb_padctl(padctl);
5478c2ecf20Sopenharmony_ci	struct tegra_xusb_usb2_pad *usb2;
5488c2ecf20Sopenharmony_ci	struct tegra_xusb_pad *pad;
5498c2ecf20Sopenharmony_ci	int err;
5508c2ecf20Sopenharmony_ci
5518c2ecf20Sopenharmony_ci	usb2 = kzalloc(sizeof(*usb2), GFP_KERNEL);
5528c2ecf20Sopenharmony_ci	if (!usb2)
5538c2ecf20Sopenharmony_ci		return ERR_PTR(-ENOMEM);
5548c2ecf20Sopenharmony_ci
5558c2ecf20Sopenharmony_ci	pad = &usb2->base;
5568c2ecf20Sopenharmony_ci	pad->ops = &tegra186_usb2_lane_ops;
5578c2ecf20Sopenharmony_ci	pad->soc = soc;
5588c2ecf20Sopenharmony_ci
5598c2ecf20Sopenharmony_ci	err = tegra_xusb_pad_init(pad, padctl, np);
5608c2ecf20Sopenharmony_ci	if (err < 0) {
5618c2ecf20Sopenharmony_ci		kfree(usb2);
5628c2ecf20Sopenharmony_ci		goto out;
5638c2ecf20Sopenharmony_ci	}
5648c2ecf20Sopenharmony_ci
5658c2ecf20Sopenharmony_ci	priv->usb2_trk_clk = devm_clk_get(&pad->dev, "trk");
5668c2ecf20Sopenharmony_ci	if (IS_ERR(priv->usb2_trk_clk)) {
5678c2ecf20Sopenharmony_ci		err = PTR_ERR(priv->usb2_trk_clk);
5688c2ecf20Sopenharmony_ci		dev_dbg(&pad->dev, "failed to get usb2 trk clock: %d\n", err);
5698c2ecf20Sopenharmony_ci		goto unregister;
5708c2ecf20Sopenharmony_ci	}
5718c2ecf20Sopenharmony_ci
5728c2ecf20Sopenharmony_ci	err = tegra_xusb_pad_register(pad, &utmi_phy_ops);
5738c2ecf20Sopenharmony_ci	if (err < 0)
5748c2ecf20Sopenharmony_ci		goto unregister;
5758c2ecf20Sopenharmony_ci
5768c2ecf20Sopenharmony_ci	dev_set_drvdata(&pad->dev, pad);
5778c2ecf20Sopenharmony_ci
5788c2ecf20Sopenharmony_ci	return pad;
5798c2ecf20Sopenharmony_ci
5808c2ecf20Sopenharmony_ciunregister:
5818c2ecf20Sopenharmony_ci	device_unregister(&pad->dev);
5828c2ecf20Sopenharmony_ciout:
5838c2ecf20Sopenharmony_ci	return ERR_PTR(err);
5848c2ecf20Sopenharmony_ci}
5858c2ecf20Sopenharmony_ci
5868c2ecf20Sopenharmony_cistatic void tegra186_usb2_pad_remove(struct tegra_xusb_pad *pad)
5878c2ecf20Sopenharmony_ci{
5888c2ecf20Sopenharmony_ci	struct tegra_xusb_usb2_pad *usb2 = to_usb2_pad(pad);
5898c2ecf20Sopenharmony_ci
5908c2ecf20Sopenharmony_ci	kfree(usb2);
5918c2ecf20Sopenharmony_ci}
5928c2ecf20Sopenharmony_ci
5938c2ecf20Sopenharmony_cistatic const struct tegra_xusb_pad_ops tegra186_usb2_pad_ops = {
5948c2ecf20Sopenharmony_ci	.probe = tegra186_usb2_pad_probe,
5958c2ecf20Sopenharmony_ci	.remove = tegra186_usb2_pad_remove,
5968c2ecf20Sopenharmony_ci};
5978c2ecf20Sopenharmony_ci
5988c2ecf20Sopenharmony_cistatic const char * const tegra186_usb2_functions[] = {
5998c2ecf20Sopenharmony_ci	"xusb",
6008c2ecf20Sopenharmony_ci};
6018c2ecf20Sopenharmony_ci
6028c2ecf20Sopenharmony_cistatic int tegra186_usb2_port_enable(struct tegra_xusb_port *port)
6038c2ecf20Sopenharmony_ci{
6048c2ecf20Sopenharmony_ci	return 0;
6058c2ecf20Sopenharmony_ci}
6068c2ecf20Sopenharmony_ci
6078c2ecf20Sopenharmony_cistatic void tegra186_usb2_port_disable(struct tegra_xusb_port *port)
6088c2ecf20Sopenharmony_ci{
6098c2ecf20Sopenharmony_ci}
6108c2ecf20Sopenharmony_ci
6118c2ecf20Sopenharmony_cistatic struct tegra_xusb_lane *
6128c2ecf20Sopenharmony_citegra186_usb2_port_map(struct tegra_xusb_port *port)
6138c2ecf20Sopenharmony_ci{
6148c2ecf20Sopenharmony_ci	return tegra_xusb_find_lane(port->padctl, "usb2", port->index);
6158c2ecf20Sopenharmony_ci}
6168c2ecf20Sopenharmony_ci
6178c2ecf20Sopenharmony_cistatic const struct tegra_xusb_port_ops tegra186_usb2_port_ops = {
6188c2ecf20Sopenharmony_ci	.release = tegra_xusb_usb2_port_release,
6198c2ecf20Sopenharmony_ci	.remove = tegra_xusb_usb2_port_remove,
6208c2ecf20Sopenharmony_ci	.enable = tegra186_usb2_port_enable,
6218c2ecf20Sopenharmony_ci	.disable = tegra186_usb2_port_disable,
6228c2ecf20Sopenharmony_ci	.map = tegra186_usb2_port_map,
6238c2ecf20Sopenharmony_ci};
6248c2ecf20Sopenharmony_ci
6258c2ecf20Sopenharmony_ci/* SuperSpeed PHY support */
6268c2ecf20Sopenharmony_cistatic struct tegra_xusb_lane *
6278c2ecf20Sopenharmony_citegra186_usb3_lane_probe(struct tegra_xusb_pad *pad, struct device_node *np,
6288c2ecf20Sopenharmony_ci			 unsigned int index)
6298c2ecf20Sopenharmony_ci{
6308c2ecf20Sopenharmony_ci	struct tegra_xusb_usb3_lane *usb3;
6318c2ecf20Sopenharmony_ci	int err;
6328c2ecf20Sopenharmony_ci
6338c2ecf20Sopenharmony_ci	usb3 = kzalloc(sizeof(*usb3), GFP_KERNEL);
6348c2ecf20Sopenharmony_ci	if (!usb3)
6358c2ecf20Sopenharmony_ci		return ERR_PTR(-ENOMEM);
6368c2ecf20Sopenharmony_ci
6378c2ecf20Sopenharmony_ci	INIT_LIST_HEAD(&usb3->base.list);
6388c2ecf20Sopenharmony_ci	usb3->base.soc = &pad->soc->lanes[index];
6398c2ecf20Sopenharmony_ci	usb3->base.index = index;
6408c2ecf20Sopenharmony_ci	usb3->base.pad = pad;
6418c2ecf20Sopenharmony_ci	usb3->base.np = np;
6428c2ecf20Sopenharmony_ci
6438c2ecf20Sopenharmony_ci	err = tegra_xusb_lane_parse_dt(&usb3->base, np);
6448c2ecf20Sopenharmony_ci	if (err < 0) {
6458c2ecf20Sopenharmony_ci		kfree(usb3);
6468c2ecf20Sopenharmony_ci		return ERR_PTR(err);
6478c2ecf20Sopenharmony_ci	}
6488c2ecf20Sopenharmony_ci
6498c2ecf20Sopenharmony_ci	return &usb3->base;
6508c2ecf20Sopenharmony_ci}
6518c2ecf20Sopenharmony_ci
6528c2ecf20Sopenharmony_cistatic void tegra186_usb3_lane_remove(struct tegra_xusb_lane *lane)
6538c2ecf20Sopenharmony_ci{
6548c2ecf20Sopenharmony_ci	struct tegra_xusb_usb3_lane *usb3 = to_usb3_lane(lane);
6558c2ecf20Sopenharmony_ci
6568c2ecf20Sopenharmony_ci	kfree(usb3);
6578c2ecf20Sopenharmony_ci}
6588c2ecf20Sopenharmony_ci
6598c2ecf20Sopenharmony_cistatic const struct tegra_xusb_lane_ops tegra186_usb3_lane_ops = {
6608c2ecf20Sopenharmony_ci	.probe = tegra186_usb3_lane_probe,
6618c2ecf20Sopenharmony_ci	.remove = tegra186_usb3_lane_remove,
6628c2ecf20Sopenharmony_ci};
6638c2ecf20Sopenharmony_cistatic int tegra186_usb3_port_enable(struct tegra_xusb_port *port)
6648c2ecf20Sopenharmony_ci{
6658c2ecf20Sopenharmony_ci	return 0;
6668c2ecf20Sopenharmony_ci}
6678c2ecf20Sopenharmony_ci
6688c2ecf20Sopenharmony_cistatic void tegra186_usb3_port_disable(struct tegra_xusb_port *port)
6698c2ecf20Sopenharmony_ci{
6708c2ecf20Sopenharmony_ci}
6718c2ecf20Sopenharmony_ci
6728c2ecf20Sopenharmony_cistatic struct tegra_xusb_lane *
6738c2ecf20Sopenharmony_citegra186_usb3_port_map(struct tegra_xusb_port *port)
6748c2ecf20Sopenharmony_ci{
6758c2ecf20Sopenharmony_ci	return tegra_xusb_find_lane(port->padctl, "usb3", port->index);
6768c2ecf20Sopenharmony_ci}
6778c2ecf20Sopenharmony_ci
6788c2ecf20Sopenharmony_cistatic const struct tegra_xusb_port_ops tegra186_usb3_port_ops = {
6798c2ecf20Sopenharmony_ci	.release = tegra_xusb_usb3_port_release,
6808c2ecf20Sopenharmony_ci	.remove = tegra_xusb_usb3_port_remove,
6818c2ecf20Sopenharmony_ci	.enable = tegra186_usb3_port_enable,
6828c2ecf20Sopenharmony_ci	.disable = tegra186_usb3_port_disable,
6838c2ecf20Sopenharmony_ci	.map = tegra186_usb3_port_map,
6848c2ecf20Sopenharmony_ci};
6858c2ecf20Sopenharmony_ci
6868c2ecf20Sopenharmony_cistatic int tegra186_usb3_phy_power_on(struct phy *phy)
6878c2ecf20Sopenharmony_ci{
6888c2ecf20Sopenharmony_ci	struct tegra_xusb_lane *lane = phy_get_drvdata(phy);
6898c2ecf20Sopenharmony_ci	struct tegra_xusb_padctl *padctl = lane->pad->padctl;
6908c2ecf20Sopenharmony_ci	struct tegra_xusb_usb3_port *port;
6918c2ecf20Sopenharmony_ci	struct tegra_xusb_usb2_port *usb2;
6928c2ecf20Sopenharmony_ci	unsigned int index = lane->index;
6938c2ecf20Sopenharmony_ci	struct device *dev = padctl->dev;
6948c2ecf20Sopenharmony_ci	u32 value;
6958c2ecf20Sopenharmony_ci
6968c2ecf20Sopenharmony_ci	port = tegra_xusb_find_usb3_port(padctl, index);
6978c2ecf20Sopenharmony_ci	if (!port) {
6988c2ecf20Sopenharmony_ci		dev_err(dev, "no port found for USB3 lane %u\n", index);
6998c2ecf20Sopenharmony_ci		return -ENODEV;
7008c2ecf20Sopenharmony_ci	}
7018c2ecf20Sopenharmony_ci
7028c2ecf20Sopenharmony_ci	usb2 = tegra_xusb_find_usb2_port(padctl, port->port);
7038c2ecf20Sopenharmony_ci	if (!usb2) {
7048c2ecf20Sopenharmony_ci		dev_err(dev, "no companion port found for USB3 lane %u\n",
7058c2ecf20Sopenharmony_ci			index);
7068c2ecf20Sopenharmony_ci		return -ENODEV;
7078c2ecf20Sopenharmony_ci	}
7088c2ecf20Sopenharmony_ci
7098c2ecf20Sopenharmony_ci	mutex_lock(&padctl->lock);
7108c2ecf20Sopenharmony_ci
7118c2ecf20Sopenharmony_ci	value = padctl_readl(padctl, XUSB_PADCTL_SS_PORT_CAP);
7128c2ecf20Sopenharmony_ci	value &= ~(PORT_CAP_MASK << PORTX_CAP_SHIFT(index));
7138c2ecf20Sopenharmony_ci
7148c2ecf20Sopenharmony_ci	if (usb2->mode == USB_DR_MODE_UNKNOWN)
7158c2ecf20Sopenharmony_ci		value |= (PORT_CAP_DISABLED << PORTX_CAP_SHIFT(index));
7168c2ecf20Sopenharmony_ci	else if (usb2->mode == USB_DR_MODE_PERIPHERAL)
7178c2ecf20Sopenharmony_ci		value |= (PORT_CAP_DEVICE << PORTX_CAP_SHIFT(index));
7188c2ecf20Sopenharmony_ci	else if (usb2->mode == USB_DR_MODE_HOST)
7198c2ecf20Sopenharmony_ci		value |= (PORT_CAP_HOST << PORTX_CAP_SHIFT(index));
7208c2ecf20Sopenharmony_ci	else if (usb2->mode == USB_DR_MODE_OTG)
7218c2ecf20Sopenharmony_ci		value |= (PORT_CAP_OTG << PORTX_CAP_SHIFT(index));
7228c2ecf20Sopenharmony_ci
7238c2ecf20Sopenharmony_ci	padctl_writel(padctl, value, XUSB_PADCTL_SS_PORT_CAP);
7248c2ecf20Sopenharmony_ci
7258c2ecf20Sopenharmony_ci	if (padctl->soc->supports_gen2 && port->disable_gen2) {
7268c2ecf20Sopenharmony_ci		value = padctl_readl(padctl, XUSB_PADCTL_SS_PORT_CFG);
7278c2ecf20Sopenharmony_ci		value &= ~(PORTX_SPEED_SUPPORT_MASK <<
7288c2ecf20Sopenharmony_ci			PORTX_SPEED_SUPPORT_SHIFT(index));
7298c2ecf20Sopenharmony_ci		value |= (PORT_SPEED_SUPPORT_GEN1 <<
7308c2ecf20Sopenharmony_ci			PORTX_SPEED_SUPPORT_SHIFT(index));
7318c2ecf20Sopenharmony_ci		padctl_writel(padctl, value, XUSB_PADCTL_SS_PORT_CFG);
7328c2ecf20Sopenharmony_ci	}
7338c2ecf20Sopenharmony_ci
7348c2ecf20Sopenharmony_ci	value = padctl_readl(padctl, XUSB_PADCTL_ELPG_PROGRAM_1);
7358c2ecf20Sopenharmony_ci	value &= ~SSPX_ELPG_VCORE_DOWN(index);
7368c2ecf20Sopenharmony_ci	padctl_writel(padctl, value, XUSB_PADCTL_ELPG_PROGRAM_1);
7378c2ecf20Sopenharmony_ci
7388c2ecf20Sopenharmony_ci	usleep_range(100, 200);
7398c2ecf20Sopenharmony_ci
7408c2ecf20Sopenharmony_ci	value = padctl_readl(padctl, XUSB_PADCTL_ELPG_PROGRAM_1);
7418c2ecf20Sopenharmony_ci	value &= ~SSPX_ELPG_CLAMP_EN_EARLY(index);
7428c2ecf20Sopenharmony_ci	padctl_writel(padctl, value, XUSB_PADCTL_ELPG_PROGRAM_1);
7438c2ecf20Sopenharmony_ci
7448c2ecf20Sopenharmony_ci	usleep_range(100, 200);
7458c2ecf20Sopenharmony_ci
7468c2ecf20Sopenharmony_ci	value = padctl_readl(padctl, XUSB_PADCTL_ELPG_PROGRAM_1);
7478c2ecf20Sopenharmony_ci	value &= ~SSPX_ELPG_CLAMP_EN(index);
7488c2ecf20Sopenharmony_ci	padctl_writel(padctl, value, XUSB_PADCTL_ELPG_PROGRAM_1);
7498c2ecf20Sopenharmony_ci
7508c2ecf20Sopenharmony_ci	mutex_unlock(&padctl->lock);
7518c2ecf20Sopenharmony_ci
7528c2ecf20Sopenharmony_ci	return 0;
7538c2ecf20Sopenharmony_ci}
7548c2ecf20Sopenharmony_ci
7558c2ecf20Sopenharmony_cistatic int tegra186_usb3_phy_power_off(struct phy *phy)
7568c2ecf20Sopenharmony_ci{
7578c2ecf20Sopenharmony_ci	struct tegra_xusb_lane *lane = phy_get_drvdata(phy);
7588c2ecf20Sopenharmony_ci	struct tegra_xusb_padctl *padctl = lane->pad->padctl;
7598c2ecf20Sopenharmony_ci	struct tegra_xusb_usb3_port *port;
7608c2ecf20Sopenharmony_ci	unsigned int index = lane->index;
7618c2ecf20Sopenharmony_ci	struct device *dev = padctl->dev;
7628c2ecf20Sopenharmony_ci	u32 value;
7638c2ecf20Sopenharmony_ci
7648c2ecf20Sopenharmony_ci	port = tegra_xusb_find_usb3_port(padctl, index);
7658c2ecf20Sopenharmony_ci	if (!port) {
7668c2ecf20Sopenharmony_ci		dev_err(dev, "no port found for USB3 lane %u\n", index);
7678c2ecf20Sopenharmony_ci		return -ENODEV;
7688c2ecf20Sopenharmony_ci	}
7698c2ecf20Sopenharmony_ci
7708c2ecf20Sopenharmony_ci	mutex_lock(&padctl->lock);
7718c2ecf20Sopenharmony_ci
7728c2ecf20Sopenharmony_ci	value = padctl_readl(padctl, XUSB_PADCTL_ELPG_PROGRAM_1);
7738c2ecf20Sopenharmony_ci	value |= SSPX_ELPG_CLAMP_EN_EARLY(index);
7748c2ecf20Sopenharmony_ci	padctl_writel(padctl, value, XUSB_PADCTL_ELPG_PROGRAM_1);
7758c2ecf20Sopenharmony_ci
7768c2ecf20Sopenharmony_ci	usleep_range(100, 200);
7778c2ecf20Sopenharmony_ci
7788c2ecf20Sopenharmony_ci	value = padctl_readl(padctl, XUSB_PADCTL_ELPG_PROGRAM_1);
7798c2ecf20Sopenharmony_ci	value |= SSPX_ELPG_CLAMP_EN(index);
7808c2ecf20Sopenharmony_ci	padctl_writel(padctl, value, XUSB_PADCTL_ELPG_PROGRAM_1);
7818c2ecf20Sopenharmony_ci
7828c2ecf20Sopenharmony_ci	usleep_range(250, 350);
7838c2ecf20Sopenharmony_ci
7848c2ecf20Sopenharmony_ci	value = padctl_readl(padctl, XUSB_PADCTL_ELPG_PROGRAM_1);
7858c2ecf20Sopenharmony_ci	value |= SSPX_ELPG_VCORE_DOWN(index);
7868c2ecf20Sopenharmony_ci	padctl_writel(padctl, value, XUSB_PADCTL_ELPG_PROGRAM_1);
7878c2ecf20Sopenharmony_ci
7888c2ecf20Sopenharmony_ci	mutex_unlock(&padctl->lock);
7898c2ecf20Sopenharmony_ci
7908c2ecf20Sopenharmony_ci	return 0;
7918c2ecf20Sopenharmony_ci}
7928c2ecf20Sopenharmony_ci
7938c2ecf20Sopenharmony_cistatic int tegra186_usb3_phy_init(struct phy *phy)
7948c2ecf20Sopenharmony_ci{
7958c2ecf20Sopenharmony_ci	return 0;
7968c2ecf20Sopenharmony_ci}
7978c2ecf20Sopenharmony_ci
7988c2ecf20Sopenharmony_cistatic int tegra186_usb3_phy_exit(struct phy *phy)
7998c2ecf20Sopenharmony_ci{
8008c2ecf20Sopenharmony_ci	return 0;
8018c2ecf20Sopenharmony_ci}
8028c2ecf20Sopenharmony_ci
8038c2ecf20Sopenharmony_cistatic const struct phy_ops usb3_phy_ops = {
8048c2ecf20Sopenharmony_ci	.init = tegra186_usb3_phy_init,
8058c2ecf20Sopenharmony_ci	.exit = tegra186_usb3_phy_exit,
8068c2ecf20Sopenharmony_ci	.power_on = tegra186_usb3_phy_power_on,
8078c2ecf20Sopenharmony_ci	.power_off = tegra186_usb3_phy_power_off,
8088c2ecf20Sopenharmony_ci	.owner = THIS_MODULE,
8098c2ecf20Sopenharmony_ci};
8108c2ecf20Sopenharmony_ci
8118c2ecf20Sopenharmony_cistatic struct tegra_xusb_pad *
8128c2ecf20Sopenharmony_citegra186_usb3_pad_probe(struct tegra_xusb_padctl *padctl,
8138c2ecf20Sopenharmony_ci			const struct tegra_xusb_pad_soc *soc,
8148c2ecf20Sopenharmony_ci			struct device_node *np)
8158c2ecf20Sopenharmony_ci{
8168c2ecf20Sopenharmony_ci	struct tegra_xusb_usb3_pad *usb3;
8178c2ecf20Sopenharmony_ci	struct tegra_xusb_pad *pad;
8188c2ecf20Sopenharmony_ci	int err;
8198c2ecf20Sopenharmony_ci
8208c2ecf20Sopenharmony_ci	usb3 = kzalloc(sizeof(*usb3), GFP_KERNEL);
8218c2ecf20Sopenharmony_ci	if (!usb3)
8228c2ecf20Sopenharmony_ci		return ERR_PTR(-ENOMEM);
8238c2ecf20Sopenharmony_ci
8248c2ecf20Sopenharmony_ci	pad = &usb3->base;
8258c2ecf20Sopenharmony_ci	pad->ops = &tegra186_usb3_lane_ops;
8268c2ecf20Sopenharmony_ci	pad->soc = soc;
8278c2ecf20Sopenharmony_ci
8288c2ecf20Sopenharmony_ci	err = tegra_xusb_pad_init(pad, padctl, np);
8298c2ecf20Sopenharmony_ci	if (err < 0) {
8308c2ecf20Sopenharmony_ci		kfree(usb3);
8318c2ecf20Sopenharmony_ci		goto out;
8328c2ecf20Sopenharmony_ci	}
8338c2ecf20Sopenharmony_ci
8348c2ecf20Sopenharmony_ci	err = tegra_xusb_pad_register(pad, &usb3_phy_ops);
8358c2ecf20Sopenharmony_ci	if (err < 0)
8368c2ecf20Sopenharmony_ci		goto unregister;
8378c2ecf20Sopenharmony_ci
8388c2ecf20Sopenharmony_ci	dev_set_drvdata(&pad->dev, pad);
8398c2ecf20Sopenharmony_ci
8408c2ecf20Sopenharmony_ci	return pad;
8418c2ecf20Sopenharmony_ci
8428c2ecf20Sopenharmony_ciunregister:
8438c2ecf20Sopenharmony_ci	device_unregister(&pad->dev);
8448c2ecf20Sopenharmony_ciout:
8458c2ecf20Sopenharmony_ci	return ERR_PTR(err);
8468c2ecf20Sopenharmony_ci}
8478c2ecf20Sopenharmony_ci
8488c2ecf20Sopenharmony_cistatic void tegra186_usb3_pad_remove(struct tegra_xusb_pad *pad)
8498c2ecf20Sopenharmony_ci{
8508c2ecf20Sopenharmony_ci	struct tegra_xusb_usb2_pad *usb2 = to_usb2_pad(pad);
8518c2ecf20Sopenharmony_ci
8528c2ecf20Sopenharmony_ci	kfree(usb2);
8538c2ecf20Sopenharmony_ci}
8548c2ecf20Sopenharmony_ci
8558c2ecf20Sopenharmony_cistatic const struct tegra_xusb_pad_ops tegra186_usb3_pad_ops = {
8568c2ecf20Sopenharmony_ci	.probe = tegra186_usb3_pad_probe,
8578c2ecf20Sopenharmony_ci	.remove = tegra186_usb3_pad_remove,
8588c2ecf20Sopenharmony_ci};
8598c2ecf20Sopenharmony_ci
8608c2ecf20Sopenharmony_cistatic const char * const tegra186_usb3_functions[] = {
8618c2ecf20Sopenharmony_ci	"xusb",
8628c2ecf20Sopenharmony_ci};
8638c2ecf20Sopenharmony_ci
8648c2ecf20Sopenharmony_cistatic int
8658c2ecf20Sopenharmony_citegra186_xusb_read_fuse_calibration(struct tegra186_xusb_padctl *padctl)
8668c2ecf20Sopenharmony_ci{
8678c2ecf20Sopenharmony_ci	struct device *dev = padctl->base.dev;
8688c2ecf20Sopenharmony_ci	unsigned int i, count;
8698c2ecf20Sopenharmony_ci	u32 value, *level;
8708c2ecf20Sopenharmony_ci	int err;
8718c2ecf20Sopenharmony_ci
8728c2ecf20Sopenharmony_ci	count = padctl->base.soc->ports.usb2.count;
8738c2ecf20Sopenharmony_ci
8748c2ecf20Sopenharmony_ci	level = devm_kcalloc(dev, count, sizeof(u32), GFP_KERNEL);
8758c2ecf20Sopenharmony_ci	if (!level)
8768c2ecf20Sopenharmony_ci		return -ENOMEM;
8778c2ecf20Sopenharmony_ci
8788c2ecf20Sopenharmony_ci	err = tegra_fuse_readl(TEGRA_FUSE_SKU_CALIB_0, &value);
8798c2ecf20Sopenharmony_ci	if (err) {
8808c2ecf20Sopenharmony_ci		if (err != -EPROBE_DEFER)
8818c2ecf20Sopenharmony_ci			dev_err(dev, "failed to read calibration fuse: %d\n",
8828c2ecf20Sopenharmony_ci				err);
8838c2ecf20Sopenharmony_ci		return err;
8848c2ecf20Sopenharmony_ci	}
8858c2ecf20Sopenharmony_ci
8868c2ecf20Sopenharmony_ci	dev_dbg(dev, "FUSE_USB_CALIB_0 %#x\n", value);
8878c2ecf20Sopenharmony_ci
8888c2ecf20Sopenharmony_ci	for (i = 0; i < count; i++)
8898c2ecf20Sopenharmony_ci		level[i] = (value >> HS_CURR_LEVEL_PADX_SHIFT(i)) &
8908c2ecf20Sopenharmony_ci				HS_CURR_LEVEL_PAD_MASK;
8918c2ecf20Sopenharmony_ci
8928c2ecf20Sopenharmony_ci	padctl->calib.hs_curr_level = level;
8938c2ecf20Sopenharmony_ci
8948c2ecf20Sopenharmony_ci	padctl->calib.hs_squelch = (value >> HS_SQUELCH_SHIFT) &
8958c2ecf20Sopenharmony_ci					HS_SQUELCH_MASK;
8968c2ecf20Sopenharmony_ci	padctl->calib.hs_term_range_adj = (value >> HS_TERM_RANGE_ADJ_SHIFT) &
8978c2ecf20Sopenharmony_ci						HS_TERM_RANGE_ADJ_MASK;
8988c2ecf20Sopenharmony_ci
8998c2ecf20Sopenharmony_ci	err = tegra_fuse_readl(TEGRA_FUSE_USB_CALIB_EXT_0, &value);
9008c2ecf20Sopenharmony_ci	if (err) {
9018c2ecf20Sopenharmony_ci		dev_err(dev, "failed to read calibration fuse: %d\n", err);
9028c2ecf20Sopenharmony_ci		return err;
9038c2ecf20Sopenharmony_ci	}
9048c2ecf20Sopenharmony_ci
9058c2ecf20Sopenharmony_ci	dev_dbg(dev, "FUSE_USB_CALIB_EXT_0 %#x\n", value);
9068c2ecf20Sopenharmony_ci
9078c2ecf20Sopenharmony_ci	padctl->calib.rpd_ctrl = (value >> RPD_CTRL_SHIFT) & RPD_CTRL_MASK;
9088c2ecf20Sopenharmony_ci
9098c2ecf20Sopenharmony_ci	return 0;
9108c2ecf20Sopenharmony_ci}
9118c2ecf20Sopenharmony_ci
9128c2ecf20Sopenharmony_cistatic struct tegra_xusb_padctl *
9138c2ecf20Sopenharmony_citegra186_xusb_padctl_probe(struct device *dev,
9148c2ecf20Sopenharmony_ci			   const struct tegra_xusb_padctl_soc *soc)
9158c2ecf20Sopenharmony_ci{
9168c2ecf20Sopenharmony_ci	struct tegra186_xusb_padctl *priv;
9178c2ecf20Sopenharmony_ci	int err;
9188c2ecf20Sopenharmony_ci
9198c2ecf20Sopenharmony_ci	priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
9208c2ecf20Sopenharmony_ci	if (!priv)
9218c2ecf20Sopenharmony_ci		return ERR_PTR(-ENOMEM);
9228c2ecf20Sopenharmony_ci
9238c2ecf20Sopenharmony_ci	priv->base.dev = dev;
9248c2ecf20Sopenharmony_ci	priv->base.soc = soc;
9258c2ecf20Sopenharmony_ci
9268c2ecf20Sopenharmony_ci	err = tegra186_xusb_read_fuse_calibration(priv);
9278c2ecf20Sopenharmony_ci	if (err < 0)
9288c2ecf20Sopenharmony_ci		return ERR_PTR(err);
9298c2ecf20Sopenharmony_ci
9308c2ecf20Sopenharmony_ci	return &priv->base;
9318c2ecf20Sopenharmony_ci}
9328c2ecf20Sopenharmony_ci
9338c2ecf20Sopenharmony_cistatic void tegra186_xusb_padctl_remove(struct tegra_xusb_padctl *padctl)
9348c2ecf20Sopenharmony_ci{
9358c2ecf20Sopenharmony_ci}
9368c2ecf20Sopenharmony_ci
9378c2ecf20Sopenharmony_cistatic const struct tegra_xusb_padctl_ops tegra186_xusb_padctl_ops = {
9388c2ecf20Sopenharmony_ci	.probe = tegra186_xusb_padctl_probe,
9398c2ecf20Sopenharmony_ci	.remove = tegra186_xusb_padctl_remove,
9408c2ecf20Sopenharmony_ci	.vbus_override = tegra186_xusb_padctl_vbus_override,
9418c2ecf20Sopenharmony_ci};
9428c2ecf20Sopenharmony_ci
9438c2ecf20Sopenharmony_ci#if IS_ENABLED(CONFIG_ARCH_TEGRA_186_SOC)
9448c2ecf20Sopenharmony_cistatic const char * const tegra186_xusb_padctl_supply_names[] = {
9458c2ecf20Sopenharmony_ci	"avdd-pll-erefeut",
9468c2ecf20Sopenharmony_ci	"avdd-usb",
9478c2ecf20Sopenharmony_ci	"vclamp-usb",
9488c2ecf20Sopenharmony_ci	"vddio-hsic",
9498c2ecf20Sopenharmony_ci};
9508c2ecf20Sopenharmony_ci
9518c2ecf20Sopenharmony_cistatic const struct tegra_xusb_lane_soc tegra186_usb2_lanes[] = {
9528c2ecf20Sopenharmony_ci	TEGRA186_LANE("usb2-0", 0,  0, 0, usb2),
9538c2ecf20Sopenharmony_ci	TEGRA186_LANE("usb2-1", 0,  0, 0, usb2),
9548c2ecf20Sopenharmony_ci	TEGRA186_LANE("usb2-2", 0,  0, 0, usb2),
9558c2ecf20Sopenharmony_ci};
9568c2ecf20Sopenharmony_ci
9578c2ecf20Sopenharmony_cistatic const struct tegra_xusb_pad_soc tegra186_usb2_pad = {
9588c2ecf20Sopenharmony_ci	.name = "usb2",
9598c2ecf20Sopenharmony_ci	.num_lanes = ARRAY_SIZE(tegra186_usb2_lanes),
9608c2ecf20Sopenharmony_ci	.lanes = tegra186_usb2_lanes,
9618c2ecf20Sopenharmony_ci	.ops = &tegra186_usb2_pad_ops,
9628c2ecf20Sopenharmony_ci};
9638c2ecf20Sopenharmony_ci
9648c2ecf20Sopenharmony_cistatic const struct tegra_xusb_lane_soc tegra186_usb3_lanes[] = {
9658c2ecf20Sopenharmony_ci	TEGRA186_LANE("usb3-0", 0,  0, 0, usb3),
9668c2ecf20Sopenharmony_ci	TEGRA186_LANE("usb3-1", 0,  0, 0, usb3),
9678c2ecf20Sopenharmony_ci	TEGRA186_LANE("usb3-2", 0,  0, 0, usb3),
9688c2ecf20Sopenharmony_ci};
9698c2ecf20Sopenharmony_ci
9708c2ecf20Sopenharmony_cistatic const struct tegra_xusb_pad_soc tegra186_usb3_pad = {
9718c2ecf20Sopenharmony_ci	.name = "usb3",
9728c2ecf20Sopenharmony_ci	.num_lanes = ARRAY_SIZE(tegra186_usb3_lanes),
9738c2ecf20Sopenharmony_ci	.lanes = tegra186_usb3_lanes,
9748c2ecf20Sopenharmony_ci	.ops = &tegra186_usb3_pad_ops,
9758c2ecf20Sopenharmony_ci};
9768c2ecf20Sopenharmony_ci
9778c2ecf20Sopenharmony_cistatic const struct tegra_xusb_pad_soc * const tegra186_pads[] = {
9788c2ecf20Sopenharmony_ci	&tegra186_usb2_pad,
9798c2ecf20Sopenharmony_ci	&tegra186_usb3_pad,
9808c2ecf20Sopenharmony_ci#if 0 /* TODO implement */
9818c2ecf20Sopenharmony_ci	&tegra186_hsic_pad,
9828c2ecf20Sopenharmony_ci#endif
9838c2ecf20Sopenharmony_ci};
9848c2ecf20Sopenharmony_ci
9858c2ecf20Sopenharmony_ciconst struct tegra_xusb_padctl_soc tegra186_xusb_padctl_soc = {
9868c2ecf20Sopenharmony_ci	.num_pads = ARRAY_SIZE(tegra186_pads),
9878c2ecf20Sopenharmony_ci	.pads = tegra186_pads,
9888c2ecf20Sopenharmony_ci	.ports = {
9898c2ecf20Sopenharmony_ci		.usb2 = {
9908c2ecf20Sopenharmony_ci			.ops = &tegra186_usb2_port_ops,
9918c2ecf20Sopenharmony_ci			.count = 3,
9928c2ecf20Sopenharmony_ci		},
9938c2ecf20Sopenharmony_ci#if 0 /* TODO implement */
9948c2ecf20Sopenharmony_ci		.hsic = {
9958c2ecf20Sopenharmony_ci			.ops = &tegra186_hsic_port_ops,
9968c2ecf20Sopenharmony_ci			.count = 1,
9978c2ecf20Sopenharmony_ci		},
9988c2ecf20Sopenharmony_ci#endif
9998c2ecf20Sopenharmony_ci		.usb3 = {
10008c2ecf20Sopenharmony_ci			.ops = &tegra186_usb3_port_ops,
10018c2ecf20Sopenharmony_ci			.count = 3,
10028c2ecf20Sopenharmony_ci		},
10038c2ecf20Sopenharmony_ci	},
10048c2ecf20Sopenharmony_ci	.ops = &tegra186_xusb_padctl_ops,
10058c2ecf20Sopenharmony_ci	.supply_names = tegra186_xusb_padctl_supply_names,
10068c2ecf20Sopenharmony_ci	.num_supplies = ARRAY_SIZE(tegra186_xusb_padctl_supply_names),
10078c2ecf20Sopenharmony_ci};
10088c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(tegra186_xusb_padctl_soc);
10098c2ecf20Sopenharmony_ci#endif
10108c2ecf20Sopenharmony_ci
10118c2ecf20Sopenharmony_ci#if IS_ENABLED(CONFIG_ARCH_TEGRA_194_SOC)
10128c2ecf20Sopenharmony_cistatic const char * const tegra194_xusb_padctl_supply_names[] = {
10138c2ecf20Sopenharmony_ci	"avdd-usb",
10148c2ecf20Sopenharmony_ci	"vclamp-usb",
10158c2ecf20Sopenharmony_ci};
10168c2ecf20Sopenharmony_ci
10178c2ecf20Sopenharmony_cistatic const struct tegra_xusb_lane_soc tegra194_usb2_lanes[] = {
10188c2ecf20Sopenharmony_ci	TEGRA186_LANE("usb2-0", 0,  0, 0, usb2),
10198c2ecf20Sopenharmony_ci	TEGRA186_LANE("usb2-1", 0,  0, 0, usb2),
10208c2ecf20Sopenharmony_ci	TEGRA186_LANE("usb2-2", 0,  0, 0, usb2),
10218c2ecf20Sopenharmony_ci	TEGRA186_LANE("usb2-3", 0,  0, 0, usb2),
10228c2ecf20Sopenharmony_ci};
10238c2ecf20Sopenharmony_ci
10248c2ecf20Sopenharmony_cistatic const struct tegra_xusb_pad_soc tegra194_usb2_pad = {
10258c2ecf20Sopenharmony_ci	.name = "usb2",
10268c2ecf20Sopenharmony_ci	.num_lanes = ARRAY_SIZE(tegra194_usb2_lanes),
10278c2ecf20Sopenharmony_ci	.lanes = tegra194_usb2_lanes,
10288c2ecf20Sopenharmony_ci	.ops = &tegra186_usb2_pad_ops,
10298c2ecf20Sopenharmony_ci};
10308c2ecf20Sopenharmony_ci
10318c2ecf20Sopenharmony_cistatic const struct tegra_xusb_lane_soc tegra194_usb3_lanes[] = {
10328c2ecf20Sopenharmony_ci	TEGRA186_LANE("usb3-0", 0,  0, 0, usb3),
10338c2ecf20Sopenharmony_ci	TEGRA186_LANE("usb3-1", 0,  0, 0, usb3),
10348c2ecf20Sopenharmony_ci	TEGRA186_LANE("usb3-2", 0,  0, 0, usb3),
10358c2ecf20Sopenharmony_ci	TEGRA186_LANE("usb3-3", 0,  0, 0, usb3),
10368c2ecf20Sopenharmony_ci};
10378c2ecf20Sopenharmony_ci
10388c2ecf20Sopenharmony_cistatic const struct tegra_xusb_pad_soc tegra194_usb3_pad = {
10398c2ecf20Sopenharmony_ci	.name = "usb3",
10408c2ecf20Sopenharmony_ci	.num_lanes = ARRAY_SIZE(tegra194_usb3_lanes),
10418c2ecf20Sopenharmony_ci	.lanes = tegra194_usb3_lanes,
10428c2ecf20Sopenharmony_ci	.ops = &tegra186_usb3_pad_ops,
10438c2ecf20Sopenharmony_ci};
10448c2ecf20Sopenharmony_ci
10458c2ecf20Sopenharmony_cistatic const struct tegra_xusb_pad_soc * const tegra194_pads[] = {
10468c2ecf20Sopenharmony_ci	&tegra194_usb2_pad,
10478c2ecf20Sopenharmony_ci	&tegra194_usb3_pad,
10488c2ecf20Sopenharmony_ci};
10498c2ecf20Sopenharmony_ci
10508c2ecf20Sopenharmony_ciconst struct tegra_xusb_padctl_soc tegra194_xusb_padctl_soc = {
10518c2ecf20Sopenharmony_ci	.num_pads = ARRAY_SIZE(tegra194_pads),
10528c2ecf20Sopenharmony_ci	.pads = tegra194_pads,
10538c2ecf20Sopenharmony_ci	.ports = {
10548c2ecf20Sopenharmony_ci		.usb2 = {
10558c2ecf20Sopenharmony_ci			.ops = &tegra186_usb2_port_ops,
10568c2ecf20Sopenharmony_ci			.count = 4,
10578c2ecf20Sopenharmony_ci		},
10588c2ecf20Sopenharmony_ci		.usb3 = {
10598c2ecf20Sopenharmony_ci			.ops = &tegra186_usb3_port_ops,
10608c2ecf20Sopenharmony_ci			.count = 4,
10618c2ecf20Sopenharmony_ci		},
10628c2ecf20Sopenharmony_ci	},
10638c2ecf20Sopenharmony_ci	.ops = &tegra186_xusb_padctl_ops,
10648c2ecf20Sopenharmony_ci	.supply_names = tegra194_xusb_padctl_supply_names,
10658c2ecf20Sopenharmony_ci	.num_supplies = ARRAY_SIZE(tegra194_xusb_padctl_supply_names),
10668c2ecf20Sopenharmony_ci	.supports_gen2 = true,
10678c2ecf20Sopenharmony_ci};
10688c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(tegra194_xusb_padctl_soc);
10698c2ecf20Sopenharmony_ci#endif
10708c2ecf20Sopenharmony_ci
10718c2ecf20Sopenharmony_ciMODULE_AUTHOR("JC Kuo <jckuo@nvidia.com>");
10728c2ecf20Sopenharmony_ciMODULE_DESCRIPTION("NVIDIA Tegra186 XUSB Pad Controller driver");
10738c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL v2");
1074