cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

phy-mxs-usb.c (24379B)


      1// SPDX-License-Identifier: GPL-2.0+
      2/*
      3 * Copyright 2012-2014 Freescale Semiconductor, Inc.
      4 * Copyright (C) 2012 Marek Vasut <marex@denx.de>
      5 * on behalf of DENX Software Engineering GmbH
      6 */
      7
      8#include <linux/module.h>
      9#include <linux/kernel.h>
     10#include <linux/platform_device.h>
     11#include <linux/clk.h>
     12#include <linux/usb/otg.h>
     13#include <linux/stmp_device.h>
     14#include <linux/delay.h>
     15#include <linux/err.h>
     16#include <linux/io.h>
     17#include <linux/of_device.h>
     18#include <linux/regmap.h>
     19#include <linux/mfd/syscon.h>
     20#include <linux/iopoll.h>
     21
     22#define DRIVER_NAME "mxs_phy"
     23
     24/* Register Macro */
     25#define HW_USBPHY_PWD				0x00
     26#define HW_USBPHY_TX				0x10
     27#define HW_USBPHY_CTRL				0x30
     28#define HW_USBPHY_CTRL_SET			0x34
     29#define HW_USBPHY_CTRL_CLR			0x38
     30
     31#define HW_USBPHY_DEBUG_SET			0x54
     32#define HW_USBPHY_DEBUG_CLR			0x58
     33
     34#define HW_USBPHY_IP				0x90
     35#define HW_USBPHY_IP_SET			0x94
     36#define HW_USBPHY_IP_CLR			0x98
     37
     38#define GM_USBPHY_TX_TXCAL45DP(x)            (((x) & 0xf) << 16)
     39#define GM_USBPHY_TX_TXCAL45DN(x)            (((x) & 0xf) << 8)
     40#define GM_USBPHY_TX_D_CAL(x)                (((x) & 0xf) << 0)
     41
     42/* imx7ulp */
     43#define HW_USBPHY_PLL_SIC			0xa0
     44#define HW_USBPHY_PLL_SIC_SET			0xa4
     45#define HW_USBPHY_PLL_SIC_CLR			0xa8
     46
     47#define BM_USBPHY_CTRL_SFTRST			BIT(31)
     48#define BM_USBPHY_CTRL_CLKGATE			BIT(30)
     49#define BM_USBPHY_CTRL_OTG_ID_VALUE		BIT(27)
     50#define BM_USBPHY_CTRL_ENAUTOSET_USBCLKS	BIT(26)
     51#define BM_USBPHY_CTRL_ENAUTOCLR_USBCLKGATE	BIT(25)
     52#define BM_USBPHY_CTRL_ENVBUSCHG_WKUP		BIT(23)
     53#define BM_USBPHY_CTRL_ENIDCHG_WKUP		BIT(22)
     54#define BM_USBPHY_CTRL_ENDPDMCHG_WKUP		BIT(21)
     55#define BM_USBPHY_CTRL_ENAUTOCLR_PHY_PWD	BIT(20)
     56#define BM_USBPHY_CTRL_ENAUTOCLR_CLKGATE	BIT(19)
     57#define BM_USBPHY_CTRL_ENAUTO_PWRON_PLL		BIT(18)
     58#define BM_USBPHY_CTRL_ENUTMILEVEL3		BIT(15)
     59#define BM_USBPHY_CTRL_ENUTMILEVEL2		BIT(14)
     60#define BM_USBPHY_CTRL_ENHOSTDISCONDETECT	BIT(1)
     61
     62#define BM_USBPHY_IP_FIX                       (BIT(17) | BIT(18))
     63
     64#define BM_USBPHY_DEBUG_CLKGATE			BIT(30)
     65/* imx7ulp */
     66#define BM_USBPHY_PLL_LOCK			BIT(31)
     67#define BM_USBPHY_PLL_REG_ENABLE		BIT(21)
     68#define BM_USBPHY_PLL_BYPASS			BIT(16)
     69#define BM_USBPHY_PLL_POWER			BIT(12)
     70#define BM_USBPHY_PLL_EN_USB_CLKS		BIT(6)
     71
     72/* Anatop Registers */
     73#define ANADIG_ANA_MISC0			0x150
     74#define ANADIG_ANA_MISC0_SET			0x154
     75#define ANADIG_ANA_MISC0_CLR			0x158
     76
     77#define ANADIG_USB1_CHRG_DETECT_SET		0x1b4
     78#define ANADIG_USB1_CHRG_DETECT_CLR		0x1b8
     79#define ANADIG_USB2_CHRG_DETECT_SET		0x214
     80#define ANADIG_USB1_CHRG_DETECT_EN_B		BIT(20)
     81#define ANADIG_USB1_CHRG_DETECT_CHK_CHRG_B	BIT(19)
     82#define ANADIG_USB1_CHRG_DETECT_CHK_CONTACT	BIT(18)
     83
     84#define ANADIG_USB1_VBUS_DET_STAT		0x1c0
     85#define ANADIG_USB1_VBUS_DET_STAT_VBUS_VALID	BIT(3)
     86
     87#define ANADIG_USB1_CHRG_DET_STAT		0x1d0
     88#define ANADIG_USB1_CHRG_DET_STAT_DM_STATE	BIT(2)
     89#define ANADIG_USB1_CHRG_DET_STAT_CHRG_DETECTED	BIT(1)
     90#define ANADIG_USB1_CHRG_DET_STAT_PLUG_CONTACT	BIT(0)
     91
     92#define ANADIG_USB2_VBUS_DET_STAT		0x220
     93
     94#define ANADIG_USB1_LOOPBACK_SET		0x1e4
     95#define ANADIG_USB1_LOOPBACK_CLR		0x1e8
     96#define ANADIG_USB1_LOOPBACK_UTMI_TESTSTART	BIT(0)
     97
     98#define ANADIG_USB2_LOOPBACK_SET		0x244
     99#define ANADIG_USB2_LOOPBACK_CLR		0x248
    100
    101#define ANADIG_USB1_MISC			0x1f0
    102#define ANADIG_USB2_MISC			0x250
    103
    104#define BM_ANADIG_ANA_MISC0_STOP_MODE_CONFIG	BIT(12)
    105#define BM_ANADIG_ANA_MISC0_STOP_MODE_CONFIG_SL BIT(11)
    106
    107#define BM_ANADIG_USB1_VBUS_DET_STAT_VBUS_VALID	BIT(3)
    108#define BM_ANADIG_USB2_VBUS_DET_STAT_VBUS_VALID	BIT(3)
    109
    110#define BM_ANADIG_USB1_LOOPBACK_UTMI_DIG_TST1	BIT(2)
    111#define BM_ANADIG_USB1_LOOPBACK_TSTI_TX_EN	BIT(5)
    112#define BM_ANADIG_USB2_LOOPBACK_UTMI_DIG_TST1	BIT(2)
    113#define BM_ANADIG_USB2_LOOPBACK_TSTI_TX_EN	BIT(5)
    114
    115#define BM_ANADIG_USB1_MISC_RX_VPIN_FS		BIT(29)
    116#define BM_ANADIG_USB1_MISC_RX_VMIN_FS		BIT(28)
    117#define BM_ANADIG_USB2_MISC_RX_VPIN_FS		BIT(29)
    118#define BM_ANADIG_USB2_MISC_RX_VMIN_FS		BIT(28)
    119
    120#define to_mxs_phy(p) container_of((p), struct mxs_phy, phy)
    121
    122/* Do disconnection between PHY and controller without vbus */
    123#define MXS_PHY_DISCONNECT_LINE_WITHOUT_VBUS	BIT(0)
    124
    125/*
    126 * The PHY will be in messy if there is a wakeup after putting
    127 * bus to suspend (set portsc.suspendM) but before setting PHY to low
    128 * power mode (set portsc.phcd).
    129 */
    130#define MXS_PHY_ABNORMAL_IN_SUSPEND		BIT(1)
    131
    132/*
    133 * The SOF sends too fast after resuming, it will cause disconnection
    134 * between host and high speed device.
    135 */
    136#define MXS_PHY_SENDING_SOF_TOO_FAST		BIT(2)
    137
    138/*
    139 * IC has bug fixes logic, they include
    140 * MXS_PHY_ABNORMAL_IN_SUSPEND and MXS_PHY_SENDING_SOF_TOO_FAST
    141 * which are described at above flags, the RTL will handle it
    142 * according to different versions.
    143 */
    144#define MXS_PHY_NEED_IP_FIX			BIT(3)
    145
    146/* Minimum and maximum values for device tree entries */
    147#define MXS_PHY_TX_CAL45_MIN			30
    148#define MXS_PHY_TX_CAL45_MAX			55
    149#define MXS_PHY_TX_D_CAL_MIN			79
    150#define MXS_PHY_TX_D_CAL_MAX			119
    151
    152struct mxs_phy_data {
    153	unsigned int flags;
    154};
    155
    156static const struct mxs_phy_data imx23_phy_data = {
    157	.flags = MXS_PHY_ABNORMAL_IN_SUSPEND | MXS_PHY_SENDING_SOF_TOO_FAST,
    158};
    159
    160static const struct mxs_phy_data imx6q_phy_data = {
    161	.flags = MXS_PHY_SENDING_SOF_TOO_FAST |
    162		MXS_PHY_DISCONNECT_LINE_WITHOUT_VBUS |
    163		MXS_PHY_NEED_IP_FIX,
    164};
    165
    166static const struct mxs_phy_data imx6sl_phy_data = {
    167	.flags = MXS_PHY_DISCONNECT_LINE_WITHOUT_VBUS |
    168		MXS_PHY_NEED_IP_FIX,
    169};
    170
    171static const struct mxs_phy_data vf610_phy_data = {
    172	.flags = MXS_PHY_DISCONNECT_LINE_WITHOUT_VBUS |
    173		MXS_PHY_NEED_IP_FIX,
    174};
    175
    176static const struct mxs_phy_data imx6sx_phy_data = {
    177	.flags = MXS_PHY_DISCONNECT_LINE_WITHOUT_VBUS,
    178};
    179
    180static const struct mxs_phy_data imx6ul_phy_data = {
    181	.flags = MXS_PHY_DISCONNECT_LINE_WITHOUT_VBUS,
    182};
    183
    184static const struct mxs_phy_data imx7ulp_phy_data = {
    185};
    186
    187static const struct of_device_id mxs_phy_dt_ids[] = {
    188	{ .compatible = "fsl,imx6sx-usbphy", .data = &imx6sx_phy_data, },
    189	{ .compatible = "fsl,imx6sl-usbphy", .data = &imx6sl_phy_data, },
    190	{ .compatible = "fsl,imx6q-usbphy", .data = &imx6q_phy_data, },
    191	{ .compatible = "fsl,imx23-usbphy", .data = &imx23_phy_data, },
    192	{ .compatible = "fsl,vf610-usbphy", .data = &vf610_phy_data, },
    193	{ .compatible = "fsl,imx6ul-usbphy", .data = &imx6ul_phy_data, },
    194	{ .compatible = "fsl,imx7ulp-usbphy", .data = &imx7ulp_phy_data, },
    195	{ /* sentinel */ }
    196};
    197MODULE_DEVICE_TABLE(of, mxs_phy_dt_ids);
    198
    199struct mxs_phy {
    200	struct usb_phy phy;
    201	struct clk *clk;
    202	const struct mxs_phy_data *data;
    203	struct regmap *regmap_anatop;
    204	int port_id;
    205	u32 tx_reg_set;
    206	u32 tx_reg_mask;
    207};
    208
    209static inline bool is_imx6q_phy(struct mxs_phy *mxs_phy)
    210{
    211	return mxs_phy->data == &imx6q_phy_data;
    212}
    213
    214static inline bool is_imx6sl_phy(struct mxs_phy *mxs_phy)
    215{
    216	return mxs_phy->data == &imx6sl_phy_data;
    217}
    218
    219static inline bool is_imx7ulp_phy(struct mxs_phy *mxs_phy)
    220{
    221	return mxs_phy->data == &imx7ulp_phy_data;
    222}
    223
    224/*
    225 * PHY needs some 32K cycles to switch from 32K clock to
    226 * bus (such as AHB/AXI, etc) clock.
    227 */
    228static void mxs_phy_clock_switch_delay(void)
    229{
    230	usleep_range(300, 400);
    231}
    232
    233static void mxs_phy_tx_init(struct mxs_phy *mxs_phy)
    234{
    235	void __iomem *base = mxs_phy->phy.io_priv;
    236	u32 phytx;
    237
    238	/* Update TX register if there is anything to write */
    239	if (mxs_phy->tx_reg_mask) {
    240		phytx = readl(base + HW_USBPHY_TX);
    241		phytx &= ~mxs_phy->tx_reg_mask;
    242		phytx |= mxs_phy->tx_reg_set;
    243		writel(phytx, base + HW_USBPHY_TX);
    244	}
    245}
    246
    247static int mxs_phy_pll_enable(void __iomem *base, bool enable)
    248{
    249	int ret = 0;
    250
    251	if (enable) {
    252		u32 value;
    253
    254		writel(BM_USBPHY_PLL_REG_ENABLE, base + HW_USBPHY_PLL_SIC_SET);
    255		writel(BM_USBPHY_PLL_BYPASS, base + HW_USBPHY_PLL_SIC_CLR);
    256		writel(BM_USBPHY_PLL_POWER, base + HW_USBPHY_PLL_SIC_SET);
    257		ret = readl_poll_timeout(base + HW_USBPHY_PLL_SIC,
    258			value, (value & BM_USBPHY_PLL_LOCK) != 0,
    259			100, 10000);
    260		if (ret)
    261			return ret;
    262
    263		writel(BM_USBPHY_PLL_EN_USB_CLKS, base +
    264				HW_USBPHY_PLL_SIC_SET);
    265	} else {
    266		writel(BM_USBPHY_PLL_EN_USB_CLKS, base +
    267				HW_USBPHY_PLL_SIC_CLR);
    268		writel(BM_USBPHY_PLL_POWER, base + HW_USBPHY_PLL_SIC_CLR);
    269		writel(BM_USBPHY_PLL_BYPASS, base + HW_USBPHY_PLL_SIC_SET);
    270		writel(BM_USBPHY_PLL_REG_ENABLE, base + HW_USBPHY_PLL_SIC_CLR);
    271	}
    272
    273	return ret;
    274}
    275
    276static int mxs_phy_hw_init(struct mxs_phy *mxs_phy)
    277{
    278	int ret;
    279	void __iomem *base = mxs_phy->phy.io_priv;
    280
    281	if (is_imx7ulp_phy(mxs_phy)) {
    282		ret = mxs_phy_pll_enable(base, true);
    283		if (ret)
    284			return ret;
    285	}
    286
    287	ret = stmp_reset_block(base + HW_USBPHY_CTRL);
    288	if (ret)
    289		goto disable_pll;
    290
    291	/* Power up the PHY */
    292	writel(0, base + HW_USBPHY_PWD);
    293
    294	/*
    295	 * USB PHY Ctrl Setting
    296	 * - Auto clock/power on
    297	 * - Enable full/low speed support
    298	 */
    299	writel(BM_USBPHY_CTRL_ENAUTOSET_USBCLKS |
    300		BM_USBPHY_CTRL_ENAUTOCLR_USBCLKGATE |
    301		BM_USBPHY_CTRL_ENAUTOCLR_PHY_PWD |
    302		BM_USBPHY_CTRL_ENAUTOCLR_CLKGATE |
    303		BM_USBPHY_CTRL_ENAUTO_PWRON_PLL |
    304		BM_USBPHY_CTRL_ENUTMILEVEL2 |
    305		BM_USBPHY_CTRL_ENUTMILEVEL3,
    306	       base + HW_USBPHY_CTRL_SET);
    307
    308	if (mxs_phy->data->flags & MXS_PHY_NEED_IP_FIX)
    309		writel(BM_USBPHY_IP_FIX, base + HW_USBPHY_IP_SET);
    310
    311	if (mxs_phy->regmap_anatop) {
    312		unsigned int reg = mxs_phy->port_id ?
    313			ANADIG_USB1_CHRG_DETECT_SET :
    314			ANADIG_USB2_CHRG_DETECT_SET;
    315		/*
    316		 * The external charger detector needs to be disabled,
    317		 * or the signal at DP will be poor
    318		 */
    319		regmap_write(mxs_phy->regmap_anatop, reg,
    320			     ANADIG_USB1_CHRG_DETECT_EN_B |
    321			     ANADIG_USB1_CHRG_DETECT_CHK_CHRG_B);
    322	}
    323
    324	mxs_phy_tx_init(mxs_phy);
    325
    326	return 0;
    327
    328disable_pll:
    329	if (is_imx7ulp_phy(mxs_phy))
    330		mxs_phy_pll_enable(base, false);
    331	return ret;
    332}
    333
    334/* Return true if the vbus is there */
    335static bool mxs_phy_get_vbus_status(struct mxs_phy *mxs_phy)
    336{
    337	unsigned int vbus_value = 0;
    338
    339	if (!mxs_phy->regmap_anatop)
    340		return false;
    341
    342	if (mxs_phy->port_id == 0)
    343		regmap_read(mxs_phy->regmap_anatop,
    344			ANADIG_USB1_VBUS_DET_STAT,
    345			&vbus_value);
    346	else if (mxs_phy->port_id == 1)
    347		regmap_read(mxs_phy->regmap_anatop,
    348			ANADIG_USB2_VBUS_DET_STAT,
    349			&vbus_value);
    350
    351	if (vbus_value & BM_ANADIG_USB1_VBUS_DET_STAT_VBUS_VALID)
    352		return true;
    353	else
    354		return false;
    355}
    356
    357static void __mxs_phy_disconnect_line(struct mxs_phy *mxs_phy, bool disconnect)
    358{
    359	void __iomem *base = mxs_phy->phy.io_priv;
    360	u32 reg;
    361
    362	if (disconnect)
    363		writel_relaxed(BM_USBPHY_DEBUG_CLKGATE,
    364			base + HW_USBPHY_DEBUG_CLR);
    365
    366	if (mxs_phy->port_id == 0) {
    367		reg = disconnect ? ANADIG_USB1_LOOPBACK_SET
    368			: ANADIG_USB1_LOOPBACK_CLR;
    369		regmap_write(mxs_phy->regmap_anatop, reg,
    370			BM_ANADIG_USB1_LOOPBACK_UTMI_DIG_TST1 |
    371			BM_ANADIG_USB1_LOOPBACK_TSTI_TX_EN);
    372	} else if (mxs_phy->port_id == 1) {
    373		reg = disconnect ? ANADIG_USB2_LOOPBACK_SET
    374			: ANADIG_USB2_LOOPBACK_CLR;
    375		regmap_write(mxs_phy->regmap_anatop, reg,
    376			BM_ANADIG_USB2_LOOPBACK_UTMI_DIG_TST1 |
    377			BM_ANADIG_USB2_LOOPBACK_TSTI_TX_EN);
    378	}
    379
    380	if (!disconnect)
    381		writel_relaxed(BM_USBPHY_DEBUG_CLKGATE,
    382			base + HW_USBPHY_DEBUG_SET);
    383
    384	/* Delay some time, and let Linestate be SE0 for controller */
    385	if (disconnect)
    386		usleep_range(500, 1000);
    387}
    388
    389static bool mxs_phy_is_otg_host(struct mxs_phy *mxs_phy)
    390{
    391	void __iomem *base = mxs_phy->phy.io_priv;
    392	u32 phyctrl = readl(base + HW_USBPHY_CTRL);
    393
    394	if (IS_ENABLED(CONFIG_USB_OTG) &&
    395			!(phyctrl & BM_USBPHY_CTRL_OTG_ID_VALUE))
    396		return true;
    397
    398	return false;
    399}
    400
    401static void mxs_phy_disconnect_line(struct mxs_phy *mxs_phy, bool on)
    402{
    403	bool vbus_is_on = false;
    404
    405	/* If the SoCs don't need to disconnect line without vbus, quit */
    406	if (!(mxs_phy->data->flags & MXS_PHY_DISCONNECT_LINE_WITHOUT_VBUS))
    407		return;
    408
    409	/* If the SoCs don't have anatop, quit */
    410	if (!mxs_phy->regmap_anatop)
    411		return;
    412
    413	vbus_is_on = mxs_phy_get_vbus_status(mxs_phy);
    414
    415	if (on && !vbus_is_on && !mxs_phy_is_otg_host(mxs_phy))
    416		__mxs_phy_disconnect_line(mxs_phy, true);
    417	else
    418		__mxs_phy_disconnect_line(mxs_phy, false);
    419
    420}
    421
    422static int mxs_phy_init(struct usb_phy *phy)
    423{
    424	int ret;
    425	struct mxs_phy *mxs_phy = to_mxs_phy(phy);
    426
    427	mxs_phy_clock_switch_delay();
    428	ret = clk_prepare_enable(mxs_phy->clk);
    429	if (ret)
    430		return ret;
    431
    432	return mxs_phy_hw_init(mxs_phy);
    433}
    434
    435static void mxs_phy_shutdown(struct usb_phy *phy)
    436{
    437	struct mxs_phy *mxs_phy = to_mxs_phy(phy);
    438	u32 value = BM_USBPHY_CTRL_ENVBUSCHG_WKUP |
    439			BM_USBPHY_CTRL_ENDPDMCHG_WKUP |
    440			BM_USBPHY_CTRL_ENIDCHG_WKUP |
    441			BM_USBPHY_CTRL_ENAUTOSET_USBCLKS |
    442			BM_USBPHY_CTRL_ENAUTOCLR_USBCLKGATE |
    443			BM_USBPHY_CTRL_ENAUTOCLR_PHY_PWD |
    444			BM_USBPHY_CTRL_ENAUTOCLR_CLKGATE |
    445			BM_USBPHY_CTRL_ENAUTO_PWRON_PLL;
    446
    447	writel(value, phy->io_priv + HW_USBPHY_CTRL_CLR);
    448	writel(0xffffffff, phy->io_priv + HW_USBPHY_PWD);
    449
    450	writel(BM_USBPHY_CTRL_CLKGATE,
    451	       phy->io_priv + HW_USBPHY_CTRL_SET);
    452
    453	if (is_imx7ulp_phy(mxs_phy))
    454		mxs_phy_pll_enable(phy->io_priv, false);
    455
    456	clk_disable_unprepare(mxs_phy->clk);
    457}
    458
    459static bool mxs_phy_is_low_speed_connection(struct mxs_phy *mxs_phy)
    460{
    461	unsigned int line_state;
    462	/* bit definition is the same for all controllers */
    463	unsigned int dp_bit = BM_ANADIG_USB1_MISC_RX_VPIN_FS,
    464		     dm_bit = BM_ANADIG_USB1_MISC_RX_VMIN_FS;
    465	unsigned int reg = ANADIG_USB1_MISC;
    466
    467	/* If the SoCs don't have anatop, quit */
    468	if (!mxs_phy->regmap_anatop)
    469		return false;
    470
    471	if (mxs_phy->port_id == 0)
    472		reg = ANADIG_USB1_MISC;
    473	else if (mxs_phy->port_id == 1)
    474		reg = ANADIG_USB2_MISC;
    475
    476	regmap_read(mxs_phy->regmap_anatop, reg, &line_state);
    477
    478	if ((line_state & (dp_bit | dm_bit)) ==  dm_bit)
    479		return true;
    480	else
    481		return false;
    482}
    483
    484static int mxs_phy_suspend(struct usb_phy *x, int suspend)
    485{
    486	int ret;
    487	struct mxs_phy *mxs_phy = to_mxs_phy(x);
    488	bool low_speed_connection, vbus_is_on;
    489
    490	low_speed_connection = mxs_phy_is_low_speed_connection(mxs_phy);
    491	vbus_is_on = mxs_phy_get_vbus_status(mxs_phy);
    492
    493	if (suspend) {
    494		/*
    495		 * FIXME: Do not power down RXPWD1PT1 bit for low speed
    496		 * connect. The low speed connection will have problem at
    497		 * very rare cases during usb suspend and resume process.
    498		 */
    499		if (low_speed_connection & vbus_is_on) {
    500			/*
    501			 * If value to be set as pwd value is not 0xffffffff,
    502			 * several 32Khz cycles are needed.
    503			 */
    504			mxs_phy_clock_switch_delay();
    505			writel(0xffbfffff, x->io_priv + HW_USBPHY_PWD);
    506		} else {
    507			writel(0xffffffff, x->io_priv + HW_USBPHY_PWD);
    508		}
    509		writel(BM_USBPHY_CTRL_CLKGATE,
    510		       x->io_priv + HW_USBPHY_CTRL_SET);
    511		clk_disable_unprepare(mxs_phy->clk);
    512	} else {
    513		mxs_phy_clock_switch_delay();
    514		ret = clk_prepare_enable(mxs_phy->clk);
    515		if (ret)
    516			return ret;
    517		writel(BM_USBPHY_CTRL_CLKGATE,
    518		       x->io_priv + HW_USBPHY_CTRL_CLR);
    519		writel(0, x->io_priv + HW_USBPHY_PWD);
    520	}
    521
    522	return 0;
    523}
    524
    525static int mxs_phy_set_wakeup(struct usb_phy *x, bool enabled)
    526{
    527	struct mxs_phy *mxs_phy = to_mxs_phy(x);
    528	u32 value = BM_USBPHY_CTRL_ENVBUSCHG_WKUP |
    529			BM_USBPHY_CTRL_ENDPDMCHG_WKUP |
    530				BM_USBPHY_CTRL_ENIDCHG_WKUP;
    531	if (enabled) {
    532		mxs_phy_disconnect_line(mxs_phy, true);
    533		writel_relaxed(value, x->io_priv + HW_USBPHY_CTRL_SET);
    534	} else {
    535		writel_relaxed(value, x->io_priv + HW_USBPHY_CTRL_CLR);
    536		mxs_phy_disconnect_line(mxs_phy, false);
    537	}
    538
    539	return 0;
    540}
    541
    542static int mxs_phy_on_connect(struct usb_phy *phy,
    543		enum usb_device_speed speed)
    544{
    545	dev_dbg(phy->dev, "%s device has connected\n",
    546		(speed == USB_SPEED_HIGH) ? "HS" : "FS/LS");
    547
    548	if (speed == USB_SPEED_HIGH)
    549		writel(BM_USBPHY_CTRL_ENHOSTDISCONDETECT,
    550		       phy->io_priv + HW_USBPHY_CTRL_SET);
    551
    552	return 0;
    553}
    554
    555static int mxs_phy_on_disconnect(struct usb_phy *phy,
    556		enum usb_device_speed speed)
    557{
    558	dev_dbg(phy->dev, "%s device has disconnected\n",
    559		(speed == USB_SPEED_HIGH) ? "HS" : "FS/LS");
    560
    561	/* Sometimes, the speed is not high speed when the error occurs */
    562	if (readl(phy->io_priv + HW_USBPHY_CTRL) &
    563			BM_USBPHY_CTRL_ENHOSTDISCONDETECT)
    564		writel(BM_USBPHY_CTRL_ENHOSTDISCONDETECT,
    565		       phy->io_priv + HW_USBPHY_CTRL_CLR);
    566
    567	return 0;
    568}
    569
    570#define MXS_USB_CHARGER_DATA_CONTACT_TIMEOUT	100
    571static int mxs_charger_data_contact_detect(struct mxs_phy *x)
    572{
    573	struct regmap *regmap = x->regmap_anatop;
    574	int i, stable_contact_count = 0;
    575	u32 val;
    576
    577	/* Check if vbus is valid */
    578	regmap_read(regmap, ANADIG_USB1_VBUS_DET_STAT, &val);
    579	if (!(val & ANADIG_USB1_VBUS_DET_STAT_VBUS_VALID)) {
    580		dev_err(x->phy.dev, "vbus is not valid\n");
    581		return -EINVAL;
    582	}
    583
    584	/* Enable charger detector */
    585	regmap_write(regmap, ANADIG_USB1_CHRG_DETECT_CLR,
    586				ANADIG_USB1_CHRG_DETECT_EN_B);
    587	/*
    588	 * - Do not check whether a charger is connected to the USB port
    589	 * - Check whether the USB plug has been in contact with each other
    590	 */
    591	regmap_write(regmap, ANADIG_USB1_CHRG_DETECT_SET,
    592			ANADIG_USB1_CHRG_DETECT_CHK_CONTACT |
    593			ANADIG_USB1_CHRG_DETECT_CHK_CHRG_B);
    594
    595	/* Check if plug is connected */
    596	for (i = 0; i < MXS_USB_CHARGER_DATA_CONTACT_TIMEOUT; i++) {
    597		regmap_read(regmap, ANADIG_USB1_CHRG_DET_STAT, &val);
    598		if (val & ANADIG_USB1_CHRG_DET_STAT_PLUG_CONTACT) {
    599			stable_contact_count++;
    600			if (stable_contact_count > 5)
    601				/* Data pin makes contact */
    602				break;
    603			else
    604				usleep_range(5000, 10000);
    605		} else {
    606			stable_contact_count = 0;
    607			usleep_range(5000, 6000);
    608		}
    609	}
    610
    611	if (i == MXS_USB_CHARGER_DATA_CONTACT_TIMEOUT) {
    612		dev_err(x->phy.dev,
    613			"Data pin can't make good contact.\n");
    614		/* Disable charger detector */
    615		regmap_write(regmap, ANADIG_USB1_CHRG_DETECT_SET,
    616				ANADIG_USB1_CHRG_DETECT_EN_B |
    617				ANADIG_USB1_CHRG_DETECT_CHK_CHRG_B);
    618		return -ENXIO;
    619	}
    620
    621	return 0;
    622}
    623
    624static enum usb_charger_type mxs_charger_primary_detection(struct mxs_phy *x)
    625{
    626	struct regmap *regmap = x->regmap_anatop;
    627	enum usb_charger_type chgr_type = UNKNOWN_TYPE;
    628	u32 val;
    629
    630	/*
    631	 * - Do check whether a charger is connected to the USB port
    632	 * - Do not Check whether the USB plug has been in contact with
    633	 *   each other
    634	 */
    635	regmap_write(regmap, ANADIG_USB1_CHRG_DETECT_CLR,
    636			ANADIG_USB1_CHRG_DETECT_CHK_CONTACT |
    637			ANADIG_USB1_CHRG_DETECT_CHK_CHRG_B);
    638
    639	msleep(100);
    640
    641	/* Check if it is a charger */
    642	regmap_read(regmap, ANADIG_USB1_CHRG_DET_STAT, &val);
    643	if (!(val & ANADIG_USB1_CHRG_DET_STAT_CHRG_DETECTED)) {
    644		chgr_type = SDP_TYPE;
    645		dev_dbg(x->phy.dev, "It is a standard downstream port\n");
    646	}
    647
    648	/* Disable charger detector */
    649	regmap_write(regmap, ANADIG_USB1_CHRG_DETECT_SET,
    650			ANADIG_USB1_CHRG_DETECT_EN_B |
    651			ANADIG_USB1_CHRG_DETECT_CHK_CHRG_B);
    652
    653	return chgr_type;
    654}
    655
    656/*
    657 * It must be called after DP is pulled up, which is used to
    658 * differentiate DCP and CDP.
    659 */
    660static enum usb_charger_type mxs_charger_secondary_detection(struct mxs_phy *x)
    661{
    662	struct regmap *regmap = x->regmap_anatop;
    663	int val;
    664
    665	msleep(80);
    666
    667	regmap_read(regmap, ANADIG_USB1_CHRG_DET_STAT, &val);
    668	if (val & ANADIG_USB1_CHRG_DET_STAT_DM_STATE) {
    669		dev_dbg(x->phy.dev, "It is a dedicate charging port\n");
    670		return DCP_TYPE;
    671	} else {
    672		dev_dbg(x->phy.dev, "It is a charging downstream port\n");
    673		return CDP_TYPE;
    674	}
    675}
    676
    677static enum usb_charger_type mxs_phy_charger_detect(struct usb_phy *phy)
    678{
    679	struct mxs_phy *mxs_phy = to_mxs_phy(phy);
    680	struct regmap *regmap = mxs_phy->regmap_anatop;
    681	void __iomem *base = phy->io_priv;
    682	enum usb_charger_type chgr_type = UNKNOWN_TYPE;
    683
    684	if (!regmap)
    685		return UNKNOWN_TYPE;
    686
    687	if (mxs_charger_data_contact_detect(mxs_phy))
    688		return chgr_type;
    689
    690	chgr_type = mxs_charger_primary_detection(mxs_phy);
    691
    692	if (chgr_type != SDP_TYPE) {
    693		/* Pull up DP via test */
    694		writel_relaxed(BM_USBPHY_DEBUG_CLKGATE,
    695				base + HW_USBPHY_DEBUG_CLR);
    696		regmap_write(regmap, ANADIG_USB1_LOOPBACK_SET,
    697				ANADIG_USB1_LOOPBACK_UTMI_TESTSTART);
    698
    699		chgr_type = mxs_charger_secondary_detection(mxs_phy);
    700
    701		/* Stop the test */
    702		regmap_write(regmap, ANADIG_USB1_LOOPBACK_CLR,
    703				ANADIG_USB1_LOOPBACK_UTMI_TESTSTART);
    704		writel_relaxed(BM_USBPHY_DEBUG_CLKGATE,
    705				base + HW_USBPHY_DEBUG_SET);
    706	}
    707
    708	return chgr_type;
    709}
    710
    711static int mxs_phy_probe(struct platform_device *pdev)
    712{
    713	void __iomem *base;
    714	struct clk *clk;
    715	struct mxs_phy *mxs_phy;
    716	int ret;
    717	struct device_node *np = pdev->dev.of_node;
    718	u32 val;
    719
    720	base = devm_platform_ioremap_resource(pdev, 0);
    721	if (IS_ERR(base))
    722		return PTR_ERR(base);
    723
    724	clk = devm_clk_get(&pdev->dev, NULL);
    725	if (IS_ERR(clk)) {
    726		dev_err(&pdev->dev,
    727			"can't get the clock, err=%ld", PTR_ERR(clk));
    728		return PTR_ERR(clk);
    729	}
    730
    731	mxs_phy = devm_kzalloc(&pdev->dev, sizeof(*mxs_phy), GFP_KERNEL);
    732	if (!mxs_phy)
    733		return -ENOMEM;
    734
    735	/* Some SoCs don't have anatop registers */
    736	if (of_get_property(np, "fsl,anatop", NULL)) {
    737		mxs_phy->regmap_anatop = syscon_regmap_lookup_by_phandle
    738			(np, "fsl,anatop");
    739		if (IS_ERR(mxs_phy->regmap_anatop)) {
    740			dev_dbg(&pdev->dev,
    741				"failed to find regmap for anatop\n");
    742			return PTR_ERR(mxs_phy->regmap_anatop);
    743		}
    744	}
    745
    746	/* Precompute which bits of the TX register are to be updated, if any */
    747	if (!of_property_read_u32(np, "fsl,tx-cal-45-dn-ohms", &val) &&
    748	    val >= MXS_PHY_TX_CAL45_MIN && val <= MXS_PHY_TX_CAL45_MAX) {
    749		/* Scale to a 4-bit value */
    750		val = (MXS_PHY_TX_CAL45_MAX - val) * 0xF
    751			/ (MXS_PHY_TX_CAL45_MAX - MXS_PHY_TX_CAL45_MIN);
    752		mxs_phy->tx_reg_mask |= GM_USBPHY_TX_TXCAL45DN(~0);
    753		mxs_phy->tx_reg_set  |= GM_USBPHY_TX_TXCAL45DN(val);
    754	}
    755
    756	if (!of_property_read_u32(np, "fsl,tx-cal-45-dp-ohms", &val) &&
    757	    val >= MXS_PHY_TX_CAL45_MIN && val <= MXS_PHY_TX_CAL45_MAX) {
    758		/* Scale to a 4-bit value. */
    759		val = (MXS_PHY_TX_CAL45_MAX - val) * 0xF
    760			/ (MXS_PHY_TX_CAL45_MAX - MXS_PHY_TX_CAL45_MIN);
    761		mxs_phy->tx_reg_mask |= GM_USBPHY_TX_TXCAL45DP(~0);
    762		mxs_phy->tx_reg_set  |= GM_USBPHY_TX_TXCAL45DP(val);
    763	}
    764
    765	if (!of_property_read_u32(np, "fsl,tx-d-cal", &val) &&
    766	    val >= MXS_PHY_TX_D_CAL_MIN && val <= MXS_PHY_TX_D_CAL_MAX) {
    767		/* Scale to a 4-bit value.  Round up the values and heavily
    768		 * weight the rounding by adding 2/3 of the denominator.
    769		 */
    770		val = ((MXS_PHY_TX_D_CAL_MAX - val) * 0xF
    771			+ (MXS_PHY_TX_D_CAL_MAX - MXS_PHY_TX_D_CAL_MIN) * 2/3)
    772			/ (MXS_PHY_TX_D_CAL_MAX - MXS_PHY_TX_D_CAL_MIN);
    773		mxs_phy->tx_reg_mask |= GM_USBPHY_TX_D_CAL(~0);
    774		mxs_phy->tx_reg_set  |= GM_USBPHY_TX_D_CAL(val);
    775	}
    776
    777	ret = of_alias_get_id(np, "usbphy");
    778	if (ret < 0)
    779		dev_dbg(&pdev->dev, "failed to get alias id, errno %d\n", ret);
    780	mxs_phy->port_id = ret;
    781
    782	mxs_phy->phy.io_priv		= base;
    783	mxs_phy->phy.dev		= &pdev->dev;
    784	mxs_phy->phy.label		= DRIVER_NAME;
    785	mxs_phy->phy.init		= mxs_phy_init;
    786	mxs_phy->phy.shutdown		= mxs_phy_shutdown;
    787	mxs_phy->phy.set_suspend	= mxs_phy_suspend;
    788	mxs_phy->phy.notify_connect	= mxs_phy_on_connect;
    789	mxs_phy->phy.notify_disconnect	= mxs_phy_on_disconnect;
    790	mxs_phy->phy.type		= USB_PHY_TYPE_USB2;
    791	mxs_phy->phy.set_wakeup		= mxs_phy_set_wakeup;
    792	mxs_phy->phy.charger_detect	= mxs_phy_charger_detect;
    793
    794	mxs_phy->clk = clk;
    795	mxs_phy->data = of_device_get_match_data(&pdev->dev);
    796
    797	platform_set_drvdata(pdev, mxs_phy);
    798
    799	device_set_wakeup_capable(&pdev->dev, true);
    800
    801	return usb_add_phy_dev(&mxs_phy->phy);
    802}
    803
    804static int mxs_phy_remove(struct platform_device *pdev)
    805{
    806	struct mxs_phy *mxs_phy = platform_get_drvdata(pdev);
    807
    808	usb_remove_phy(&mxs_phy->phy);
    809
    810	return 0;
    811}
    812
    813#ifdef CONFIG_PM_SLEEP
    814static void mxs_phy_enable_ldo_in_suspend(struct mxs_phy *mxs_phy, bool on)
    815{
    816	unsigned int reg = on ? ANADIG_ANA_MISC0_SET : ANADIG_ANA_MISC0_CLR;
    817
    818	/* If the SoCs don't have anatop, quit */
    819	if (!mxs_phy->regmap_anatop)
    820		return;
    821
    822	if (is_imx6q_phy(mxs_phy))
    823		regmap_write(mxs_phy->regmap_anatop, reg,
    824			BM_ANADIG_ANA_MISC0_STOP_MODE_CONFIG);
    825	else if (is_imx6sl_phy(mxs_phy))
    826		regmap_write(mxs_phy->regmap_anatop,
    827			reg, BM_ANADIG_ANA_MISC0_STOP_MODE_CONFIG_SL);
    828}
    829
    830static int mxs_phy_system_suspend(struct device *dev)
    831{
    832	struct mxs_phy *mxs_phy = dev_get_drvdata(dev);
    833
    834	if (device_may_wakeup(dev))
    835		mxs_phy_enable_ldo_in_suspend(mxs_phy, true);
    836
    837	return 0;
    838}
    839
    840static int mxs_phy_system_resume(struct device *dev)
    841{
    842	struct mxs_phy *mxs_phy = dev_get_drvdata(dev);
    843
    844	if (device_may_wakeup(dev))
    845		mxs_phy_enable_ldo_in_suspend(mxs_phy, false);
    846
    847	return 0;
    848}
    849#endif /* CONFIG_PM_SLEEP */
    850
    851static SIMPLE_DEV_PM_OPS(mxs_phy_pm, mxs_phy_system_suspend,
    852		mxs_phy_system_resume);
    853
    854static struct platform_driver mxs_phy_driver = {
    855	.probe = mxs_phy_probe,
    856	.remove = mxs_phy_remove,
    857	.driver = {
    858		.name = DRIVER_NAME,
    859		.of_match_table = mxs_phy_dt_ids,
    860		.pm = &mxs_phy_pm,
    861	 },
    862};
    863
    864static int __init mxs_phy_module_init(void)
    865{
    866	return platform_driver_register(&mxs_phy_driver);
    867}
    868postcore_initcall(mxs_phy_module_init);
    869
    870static void __exit mxs_phy_module_exit(void)
    871{
    872	platform_driver_unregister(&mxs_phy_driver);
    873}
    874module_exit(mxs_phy_module_exit);
    875
    876MODULE_ALIAS("platform:mxs-usb-phy");
    877MODULE_AUTHOR("Marek Vasut <marex@denx.de>");
    878MODULE_AUTHOR("Richard Zhao <richard.zhao@freescale.com>");
    879MODULE_DESCRIPTION("Freescale MXS USB PHY driver");
    880MODULE_LICENSE("GPL");