@ -1,6 +1,7 @@
// SPDX-License-Identifier: GPL-2.0+
/*
* Copyright 2012-2014 Freescale Semiconductor, Inc.
* Copyright 2012-2016 Freescale Semiconductor, Inc.
* Copyright 2017 NXP
* Copyright (C) 2012 Marek Vasut <marex@denx.de>
* on behalf of DENX Software Engineering GmbH
*/
@ -18,6 +19,7 @@
# include <linux/regmap.h>
# include <linux/mfd/syscon.h>
# include <linux/iopoll.h>
# include <linux/regulator/consumer.h>
# define DRIVER_NAME "mxs_phy"
@ -70,6 +72,12 @@
# define BM_USBPHY_PLL_EN_USB_CLKS BIT(6)
/* Anatop Registers */
# define ANADIG_PLL_USB2 0x20
# define ANADIG_PLL_USB2_SET 0x24
# define ANADIG_PLL_USB2_CLR 0x28
# define ANADIG_REG_1P1_SET 0x114
# define ANADIG_REG_1P1_CLR 0x118
# define ANADIG_ANA_MISC0 0x150
# define ANADIG_ANA_MISC0_SET 0x154
# define ANADIG_ANA_MISC0_CLR 0x158
@ -117,6 +125,42 @@
# define BM_ANADIG_USB2_MISC_RX_VPIN_FS BIT(29)
# define BM_ANADIG_USB2_MISC_RX_VMIN_FS BIT(28)
/* System Integration Module (SIM) Registers */
# define SIM_GPR1 0x30
# define USB_PHY_VLLS_WAKEUP_EN BIT(0)
# define BM_ANADIG_REG_1P1_ENABLE_WEAK_LINREG BIT(18)
# define BM_ANADIG_REG_1P1_TRACK_VDD_SOC_CAP BIT(19)
# define BM_ANADIG_PLL_USB2_HOLD_RING_OFF BIT(11)
/* DCD module, the offset is 0x800 */
# define DCD_CONTROL 0x800
# define DCD_CLOCK (DCD_CONTROL + 0x4)
# define DCD_STATUS (DCD_CONTROL + 0x8)
# define DCD_CONTROL_SR BIT(25)
# define DCD_CONTROL_START BIT(24)
# define DCD_CONTROL_BC12 BIT(17)
# define DCD_CONTROL_IE BIT(16)
# define DCD_CONTROL_IF BIT(8)
# define DCD_CONTROL_IACK BIT(0)
# define DCD_CLOCK_MHZ BIT(0)
# define DCD_STATUS_ACTIVE BIT(22)
# define DCD_STATUS_TO BIT(21)
# define DCD_STATUS_ERR BIT(20)
# define DCD_STATUS_SEQ_STAT (BIT(18) | BIT(19))
# define DCD_CHG_PORT BIT(19)
# define DCD_CHG_DET (BIT(18) | BIT(19))
# define DCD_CHG_DPIN BIT(18)
# define DCD_STATUS_SEQ_RES (BIT(16) | BIT(17))
# define DCD_SDP_PORT BIT(16)
# define DCD_CDP_PORT BIT(17)
# define DCD_DCP_PORT (BIT(16) | BIT(17))
# define to_mxs_phy(p) container_of((p), struct mxs_phy, phy)
/* Do disconnection between PHY and controller without vbus */
@ -149,6 +193,19 @@
# define MXS_PHY_TX_D_CAL_MIN 79
# define MXS_PHY_TX_D_CAL_MAX 119
/*
* At some versions, the PHY2's clock is controlled by hardware directly,
* eg, according to PHY's suspend status. In these PHYs, we only need to
* open the clock at the initialization and close it at its shutdown routine.
* It will be benefit for remote wakeup case which needs to send resume
* signal as soon as possible, and in this case, the resume signal can be sent
* out without software interfere.
*/
# define MXS_PHY_HARDWARE_CONTROL_PHY2_CLK BIT(4)
/* The MXS PHYs which have DCD module for charger detection */
# define MXS_PHY_HAS_DCD BIT(5)
struct mxs_phy_data {
unsigned int flags ;
} ;
@ -160,12 +217,14 @@ static const struct mxs_phy_data imx23_phy_data = {
static const struct mxs_phy_data imx6q_phy_data = {
. flags = MXS_PHY_SENDING_SOF_TOO_FAST |
MXS_PHY_DISCONNECT_LINE_WITHOUT_VBUS |
MXS_PHY_NEED_IP_FIX ,
MXS_PHY_NEED_IP_FIX |
MXS_PHY_HARDWARE_CONTROL_PHY2_CLK ,
} ;
static const struct mxs_phy_data imx6sl_phy_data = {
. flags = MXS_PHY_DISCONNECT_LINE_WITHOUT_VBUS |
MXS_PHY_NEED_IP_FIX ,
MXS_PHY_NEED_IP_FIX |
MXS_PHY_HARDWARE_CONTROL_PHY2_CLK ,
} ;
static const struct mxs_phy_data vf610_phy_data = {
@ -174,14 +233,17 @@ static const struct mxs_phy_data vf610_phy_data = {
} ;
static const struct mxs_phy_data imx6sx_phy_data = {
. flags = MXS_PHY_DISCONNECT_LINE_WITHOUT_VBUS ,
. flags = MXS_PHY_DISCONNECT_LINE_WITHOUT_VBUS |
MXS_PHY_HARDWARE_CONTROL_PHY2_CLK ,
} ;
static const struct mxs_phy_data imx6ul_phy_data = {
. flags = MXS_PHY_DISCONNECT_LINE_WITHOUT_VBUS ,
. flags = MXS_PHY_DISCONNECT_LINE_WITHOUT_VBUS |
MXS_PHY_HARDWARE_CONTROL_PHY2_CLK ,
} ;
static const struct mxs_phy_data imx7ulp_phy_data = {
. flags = MXS_PHY_HAS_DCD ,
} ;
static const struct of_device_id mxs_phy_dt_ids [ ] = {
@ -201,9 +263,14 @@ struct mxs_phy {
struct clk * clk ;
const struct mxs_phy_data * data ;
struct regmap * regmap_anatop ;
struct regmap * regmap_sim ;
int port_id ;
u32 tx_reg_set ;
u32 tx_reg_mask ;
struct regulator * phy_3p0 ;
bool hardware_control_phy2_clk ;
enum usb_current_mode mode ;
unsigned long clk_rate ;
} ;
static inline bool is_imx6q_phy ( struct mxs_phy * mxs_phy )
@ -221,6 +288,11 @@ static inline bool is_imx7ulp_phy(struct mxs_phy *mxs_phy)
return mxs_phy - > data = = & imx7ulp_phy_data ;
}
static inline bool is_imx6ul_phy ( struct mxs_phy * mxs_phy )
{
return mxs_phy - > data = = & imx6ul_phy_data ;
}
/*
* PHY needs some 32K cycles to switch from 32K clock to
* bus (such as AHB/AXI, etc) clock.
@ -288,6 +360,16 @@ static int mxs_phy_hw_init(struct mxs_phy *mxs_phy)
if ( ret )
goto disable_pll ;
if ( mxs_phy - > phy_3p0 ) {
ret = regulator_enable ( mxs_phy - > phy_3p0 ) ;
if ( ret ) {
dev_err ( mxs_phy - > phy . dev ,
" Failed to enable 3p0 regulator, ret=%d \n " ,
ret ) ;
return ret ;
}
}
/* Power up the PHY */
writel ( 0 , base + HW_USBPHY_PWD ) ;
@ -386,21 +468,10 @@ static void __mxs_phy_disconnect_line(struct mxs_phy *mxs_phy, bool disconnect)
usleep_range ( 500 , 1000 ) ;
}
static bool mxs_phy_is_otg_host ( struct mxs_phy * mxs_phy )
{
void __iomem * base = mxs_phy - > phy . io_priv ;
u32 phyctrl = readl ( base + HW_USBPHY_CTRL ) ;
if ( IS_ENABLED ( CONFIG_USB_OTG ) & &
! ( phyctrl & BM_USBPHY_CTRL_OTG_ID_VALUE ) )
return true ;
return false ;
}
static void mxs_phy_disconnect_line ( struct mxs_phy * mxs_phy , bool on )
{
bool vbus_is_on = false ;
enum usb_phy_events last_event = mxs_phy - > phy . last_event ;
/* If the SoCs don't need to disconnect line without vbus, quit */
if ( ! ( mxs_phy - > data - > flags & MXS_PHY_DISCONNECT_LINE_WITHOUT_VBUS ) )
@ -412,7 +483,8 @@ static void mxs_phy_disconnect_line(struct mxs_phy *mxs_phy, bool on)
vbus_is_on = mxs_phy_get_vbus_status ( mxs_phy ) ;
if ( on & & ! vbus_is_on & & ! mxs_phy_is_otg_host ( mxs_phy ) )
if ( on & & ( ( ! vbus_is_on & & mxs_phy- > mode ! = CUR_USB_MODE_HOST ) | |
( last_event = = USB_EVENT_VBUS ) ) )
__mxs_phy_disconnect_line ( mxs_phy , true ) ;
else
__mxs_phy_disconnect_line ( mxs_phy , false ) ;
@ -453,6 +525,9 @@ static void mxs_phy_shutdown(struct usb_phy *phy)
if ( is_imx7ulp_phy ( mxs_phy ) )
mxs_phy_pll_enable ( phy - > io_priv , false ) ;
if ( mxs_phy - > phy_3p0 )
regulator_disable ( mxs_phy - > phy_3p0 ) ;
clk_disable_unprepare ( mxs_phy - > clk ) ;
}
@ -506,14 +581,49 @@ static int mxs_phy_suspend(struct usb_phy *x, int suspend)
} else {
writel ( 0xffffffff , x - > io_priv + HW_USBPHY_PWD ) ;
}
/*
* USB2 PLL use ring VCO, when the PLL power up, the ring
* VCO’ s supply also ramp up. There is a possibility that
* the ring VCO start oscillation at multi nodes in this
* phase, especially for VCO which has many stages, then
* the multiwave will be kept until PLL power down. the bit
* hold_ring_off can force the VCO in one determined state
* to avoid the multiwave issue when VCO supply start ramp
* up.
*/
if ( mxs_phy - > port_id = = 1 & & mxs_phy - > regmap_anatop )
regmap_write ( mxs_phy - > regmap_anatop ,
ANADIG_PLL_USB2_SET ,
BM_ANADIG_PLL_USB2_HOLD_RING_OFF ) ;
writel ( BM_USBPHY_CTRL_CLKGATE ,
x - > io_priv + HW_USBPHY_CTRL_SET ) ;
clk_disable_unprepare ( mxs_phy - > clk ) ;
if ( ! ( mxs_phy - > port_id = = 1 & &
mxs_phy - > hardware_control_phy2_clk ) )
clk_disable_unprepare ( mxs_phy - > clk ) ;
} else {
mxs_phy_clock_switch_delay ( ) ;
ret = clk_prepare_enable ( mxs_phy - > clk ) ;
if ( ret )
return ret ;
if ( ! ( mxs_phy - > port_id = = 1 & &
mxs_phy - > hardware_control_phy2_clk ) ) {
ret = clk_prepare_enable ( mxs_phy - > clk ) ;
if ( ret )
return ret ;
}
/*
* Per IC design's requirement, hold_ring_off bit can be
* cleared 25us after PLL power up and 25us before any USB
* TX/RX.
*/
if ( mxs_phy - > port_id = = 1 & & mxs_phy - > regmap_anatop ) {
udelay ( 25 ) ;
regmap_write ( mxs_phy - > regmap_anatop ,
ANADIG_PLL_USB2_CLR ,
BM_ANADIG_PLL_USB2_HOLD_RING_OFF ) ;
udelay ( 25 ) ;
}
writel ( BM_USBPHY_CTRL_CLKGATE ,
x - > io_priv + HW_USBPHY_CTRL_CLR ) ;
writel ( 0 , x - > io_priv + HW_USBPHY_PWD ) ;
@ -708,6 +818,169 @@ static enum usb_charger_type mxs_phy_charger_detect(struct usb_phy *phy)
return chgr_type ;
}
static int mxs_phy_on_suspend ( struct usb_phy * phy ,
enum usb_device_speed speed )
{
struct mxs_phy * mxs_phy = to_mxs_phy ( phy ) ;
dev_dbg ( phy - > dev , " %s device has suspended \n " ,
( speed = = USB_SPEED_HIGH ) ? " HS " : " FS/LS " ) ;
/* delay 4ms to wait bus entering idle */
usleep_range ( 4000 , 5000 ) ;
if ( mxs_phy - > data - > flags & MXS_PHY_ABNORMAL_IN_SUSPEND ) {
writel_relaxed ( 0xffffffff , phy - > io_priv + HW_USBPHY_PWD ) ;
writel_relaxed ( 0 , phy - > io_priv + HW_USBPHY_PWD ) ;
}
if ( speed = = USB_SPEED_HIGH )
writel_relaxed ( BM_USBPHY_CTRL_ENHOSTDISCONDETECT ,
phy - > io_priv + HW_USBPHY_CTRL_CLR ) ;
return 0 ;
}
/*
* The resume signal must be finished here.
*/
static int mxs_phy_on_resume ( struct usb_phy * phy ,
enum usb_device_speed speed )
{
dev_dbg ( phy - > dev , " %s device has resumed \n " ,
( speed = = USB_SPEED_HIGH ) ? " HS " : " FS/LS " ) ;
if ( speed = = USB_SPEED_HIGH ) {
/* Make sure the device has switched to High-Speed mode */
udelay ( 500 ) ;
writel_relaxed ( BM_USBPHY_CTRL_ENHOSTDISCONDETECT ,
phy - > io_priv + HW_USBPHY_CTRL_SET ) ;
}
return 0 ;
}
/*
* Set the usb current role for phy.
*/
static int mxs_phy_set_mode ( struct usb_phy * phy ,
enum usb_current_mode mode )
{
struct mxs_phy * mxs_phy = to_mxs_phy ( phy ) ;
mxs_phy - > mode = mode ;
return 0 ;
}
static int mxs_phy_dcd_start ( struct mxs_phy * mxs_phy )
{
void __iomem * base = mxs_phy - > phy . io_priv ;
u32 value ;
value = readl ( base + DCD_CONTROL ) ;
writel ( value | DCD_CONTROL_SR , base + DCD_CONTROL ) ;
if ( ! mxs_phy - > clk_rate )
return - EINVAL ;
value = readl ( base + DCD_CONTROL ) ;
writel ( ( ( mxs_phy - > clk_rate / 1000000 ) < < 2 ) | DCD_CLOCK_MHZ ,
base + DCD_CLOCK ) ;
value = readl ( base + DCD_CONTROL ) ;
value & = ~ DCD_CONTROL_IE ;
writel ( value | DCD_CONTROL_BC12 , base + DCD_CONTROL ) ;
value = readl ( base + DCD_CONTROL ) ;
writel ( value | DCD_CONTROL_START , base + DCD_CONTROL ) ;
return 0 ;
}
# define DCD_CHARGING_DURTION 1000 /* One second according to BC 1.2 */
static enum usb_charger_type mxs_phy_dcd_flow ( struct usb_phy * phy )
{
struct mxs_phy * mxs_phy = to_mxs_phy ( phy ) ;
void __iomem * base = mxs_phy - > phy . io_priv ;
u32 value ;
int i = 0 ;
enum usb_charger_type chgr_type ;
if ( mxs_phy_dcd_start ( mxs_phy ) )
return UNKNOWN_TYPE ;
while ( i + + < = ( DCD_CHARGING_DURTION / 50 ) ) {
value = readl ( base + DCD_CONTROL ) ;
if ( value & DCD_CONTROL_IF ) {
value = readl ( base + DCD_STATUS ) ;
if ( value & DCD_STATUS_ACTIVE ) {
dev_err ( phy - > dev , " still detecting \n " ) ;
chgr_type = UNKNOWN_TYPE ;
break ;
}
if ( value & DCD_STATUS_TO ) {
dev_err ( phy - > dev , " detect timeout \n " ) ;
chgr_type = UNKNOWN_TYPE ;
break ;
}
if ( value & DCD_STATUS_ERR ) {
dev_err ( phy - > dev , " detect error \n " ) ;
chgr_type = UNKNOWN_TYPE ;
break ;
}
if ( ( value & DCD_STATUS_SEQ_STAT ) < = DCD_CHG_DPIN ) {
dev_err ( phy - > dev , " error occurs \n " ) ;
chgr_type = UNKNOWN_TYPE ;
break ;
}
/* SDP */
if ( ( ( value & DCD_STATUS_SEQ_STAT ) = = DCD_CHG_PORT ) & &
( ( value & DCD_STATUS_SEQ_RES )
= = DCD_SDP_PORT ) ) {
dev_dbg ( phy - > dev , " SDP \n " ) ;
chgr_type = SDP_TYPE ;
break ;
}
if ( ( value & DCD_STATUS_SEQ_STAT ) = = DCD_CHG_DET ) {
if ( ( value & DCD_STATUS_SEQ_RES ) = =
DCD_CDP_PORT ) {
dev_dbg ( phy - > dev , " CDP \n " ) ;
chgr_type = CDP_TYPE ;
break ;
}
if ( ( value & DCD_STATUS_SEQ_RES ) = =
DCD_DCP_PORT ) {
dev_dbg ( phy - > dev , " DCP \n " ) ;
chgr_type = DCP_TYPE ;
break ;
}
}
dev_err ( phy - > dev , " unknown error occurs \n " ) ;
chgr_type = UNKNOWN_TYPE ;
break ;
}
msleep ( 50 ) ;
}
if ( i > 20 ) {
dev_err ( phy - > dev , " charger detecting timeout \n " ) ;
chgr_type = UNKNOWN_TYPE ;
}
/* disable dcd module */
readl ( base + DCD_STATUS ) ;
writel ( DCD_CONTROL_IACK , base + DCD_CONTROL ) ;
writel ( DCD_CONTROL_SR , base + DCD_CONTROL ) ;
return chgr_type ;
}
static int mxs_phy_probe ( struct platform_device * pdev )
{
struct resource * res ;
@ -739,6 +1012,7 @@ static int mxs_phy_probe(struct platform_device *pdev)
if ( ! mxs_phy )
return - ENOMEM ;
mxs_phy - > clk_rate = clk_get_rate ( clk ) ;
/* Some SoCs don't have anatop registers */
if ( of_get_property ( np , " fsl,anatop " , NULL ) ) {
mxs_phy - > regmap_anatop = syscon_regmap_lookup_by_phandle
@ -750,6 +1024,17 @@ static int mxs_phy_probe(struct platform_device *pdev)
}
}
/* Currently, only imx7ulp has SIM module */
if ( of_get_property ( np , " nxp,sim " , NULL ) ) {
mxs_phy - > regmap_sim = syscon_regmap_lookup_by_phandle
( np , " nxp,sim " ) ;
if ( IS_ERR ( mxs_phy - > regmap_sim ) ) {
dev_dbg ( & pdev - > dev ,
" failed to find regmap for sim \n " ) ;
return PTR_ERR ( mxs_phy - > regmap_sim ) ;
}
}
/* Precompute which bits of the TX register are to be updated, if any */
if ( ! of_property_read_u32 ( np , " fsl,tx-cal-45-dn-ohms " , & val ) & &
val > = MXS_PHY_TX_CAL45_MIN & & val < = MXS_PHY_TX_CAL45_MAX ) {
@ -784,6 +1069,8 @@ static int mxs_phy_probe(struct platform_device *pdev)
ret = of_alias_get_id ( np , " usbphy " ) ;
if ( ret < 0 )
dev_dbg ( & pdev - > dev , " failed to get alias id, errno %d \n " , ret ) ;
mxs_phy - > clk = clk ;
mxs_phy - > data = of_id - > data ;
mxs_phy - > port_id = ret ;
mxs_phy - > phy . io_priv = base ;
@ -796,10 +1083,33 @@ static int mxs_phy_probe(struct platform_device *pdev)
mxs_phy - > phy . notify_disconnect = mxs_phy_on_disconnect ;
mxs_phy - > phy . type = USB_PHY_TYPE_USB2 ;
mxs_phy - > phy . set_wakeup = mxs_phy_set_wakeup ;
mxs_phy - > phy . charger_detect = mxs_phy_charger_detect ;
if ( mxs_phy - > data - > flags & MXS_PHY_HAS_DCD )
mxs_phy - > phy . charger_detect = mxs_phy_dcd_flow ;
else
mxs_phy - > phy . charger_detect = mxs_phy_charger_detect ;
mxs_phy - > clk = clk ;
mxs_phy - > data = of_id - > data ;
mxs_phy - > phy . set_mode = mxs_phy_set_mode ;
if ( mxs_phy - > data - > flags & MXS_PHY_SENDING_SOF_TOO_FAST ) {
mxs_phy - > phy . notify_suspend = mxs_phy_on_suspend ;
mxs_phy - > phy . notify_resume = mxs_phy_on_resume ;
}
mxs_phy - > phy_3p0 = devm_regulator_get ( & pdev - > dev , " phy-3p0 " ) ;
if ( PTR_ERR ( mxs_phy - > phy_3p0 ) = = - EPROBE_DEFER ) {
return - EPROBE_DEFER ;
} else if ( PTR_ERR ( mxs_phy - > phy_3p0 ) = = - ENODEV ) {
/* not exist */
mxs_phy - > phy_3p0 = NULL ;
} else if ( IS_ERR ( mxs_phy - > phy_3p0 ) ) {
dev_err ( & pdev - > dev , " Getting regulator error: %ld \n " ,
PTR_ERR ( mxs_phy - > phy_3p0 ) ) ;
return PTR_ERR ( mxs_phy - > phy_3p0 ) ;
}
if ( mxs_phy - > phy_3p0 )
regulator_set_voltage ( mxs_phy - > phy_3p0 , 3200000 , 3200000 ) ;
if ( mxs_phy - > data - > flags & MXS_PHY_HARDWARE_CONTROL_PHY2_CLK )
mxs_phy - > hardware_control_phy2_clk = true ;
platform_set_drvdata ( pdev , mxs_phy ) ;
@ -818,28 +1128,58 @@ static int mxs_phy_remove(struct platform_device *pdev)
}
# ifdef CONFIG_PM_SLEEP
static void mxs_phy_wakeup_enable ( struct mxs_phy * mxs_phy , bool on )
{
u32 mask = USB_PHY_VLLS_WAKEUP_EN ;
/* If the SoCs don't have SIM, quit */
if ( ! mxs_phy - > regmap_sim )
return ;
if ( on ) {
regmap_update_bits ( mxs_phy - > regmap_sim , SIM_GPR1 , mask , mask ) ;
udelay ( 500 ) ;
} else {
regmap_update_bits ( mxs_phy - > regmap_sim , SIM_GPR1 , mask , 0 ) ;
}
}
static void mxs_phy_enable_ldo_in_suspend ( struct mxs_phy * mxs_phy , bool on )
{
unsigned int reg = on ? ANADIG_ANA_MISC0_SET : ANADIG_ANA_MISC0_CLR ;
unsigned int reg ;
u32 value ;
/* If the SoCs don't have anatop, quit */
if ( ! mxs_phy - > regmap_anatop )
return ;
if ( is_imx6q_phy ( mxs_phy ) )
if ( is_imx6q_phy ( mxs_phy ) ) {
reg = on ? ANADIG_ANA_MISC0_SET : ANADIG_ANA_MISC0_CLR ;
regmap_write ( mxs_phy - > regmap_anatop , reg ,
BM_ANADIG_ANA_MISC0_STOP_MODE_CONFIG ) ;
else if ( is_imx6sl_phy ( mxs_phy ) )
} else if ( is_imx6sl_phy ( mxs_phy ) ) {
reg = on ? ANADIG_ANA_MISC0_SET : ANADIG_ANA_MISC0_CLR ;
regmap_write ( mxs_phy - > regmap_anatop ,
reg , BM_ANADIG_ANA_MISC0_STOP_MODE_CONFIG_SL ) ;
} else if ( is_imx6ul_phy ( mxs_phy ) ) {
reg = on ? ANADIG_REG_1P1_SET : ANADIG_REG_1P1_CLR ;
value = BM_ANADIG_REG_1P1_ENABLE_WEAK_LINREG |
BM_ANADIG_REG_1P1_TRACK_VDD_SOC_CAP ;
if ( mxs_phy_get_vbus_status ( mxs_phy ) & & on )
regmap_write ( mxs_phy - > regmap_anatop , reg , value ) ;
else if ( ! on )
regmap_write ( mxs_phy - > regmap_anatop , reg , value ) ;
}
}
static int mxs_phy_system_suspend ( struct device * dev )
{
struct mxs_phy * mxs_phy = dev_get_drvdata ( dev ) ;
if ( device_may_wakeup ( dev ) )
if ( device_may_wakeup ( dev ) ) {
mxs_phy_enable_ldo_in_suspend ( mxs_phy , true ) ;
mxs_phy_wakeup_enable ( mxs_phy , true ) ;
}
return 0 ;
}
@ -848,8 +1188,10 @@ static int mxs_phy_system_resume(struct device *dev)
{
struct mxs_phy * mxs_phy = dev_get_drvdata ( dev ) ;
if ( device_may_wakeup ( dev ) )
if ( device_may_wakeup ( dev ) ) {
mxs_phy_enable_ldo_in_suspend ( mxs_phy , false ) ;
mxs_phy_wakeup_enable ( mxs_phy , false ) ;
}
return 0 ;
}