2012-07-07 22:56:47 +08:00
/*
2014-02-24 10:20:54 +08:00
* Copyright 2012 - 2013 Freescale Semiconductor , Inc .
2012-07-07 22:56:47 +08:00
* Copyright ( C ) 2012 Marek Vasut < marex @ denx . de >
* on behalf of DENX Software Engineering GmbH
*
* The code contained herein is licensed under the GNU General Public
* License . You may obtain a copy of the GNU General Public License
* Version 2 or later at the following locations :
*
* http : //www.opensource.org/licenses/gpl-license.html
* http : //www.gnu.org/copyleft/gpl.html
*/
# include <linux/module.h>
# include <linux/kernel.h>
# include <linux/platform_device.h>
# include <linux/clk.h>
# include <linux/usb/otg.h>
# include <linux/stmp_device.h>
# include <linux/delay.h>
# include <linux/err.h>
# include <linux/io.h>
2014-02-24 10:20:54 +08:00
# include <linux/of_device.h>
2014-02-24 10:20:57 +08:00
# include <linux/regmap.h>
# include <linux/mfd/syscon.h>
2012-07-07 22:56:47 +08:00
# define DRIVER_NAME "mxs_phy"
# define HW_USBPHY_PWD 0x00
# define HW_USBPHY_CTRL 0x30
# define HW_USBPHY_CTRL_SET 0x34
# define HW_USBPHY_CTRL_CLR 0x38
2014-02-24 10:21:02 +08:00
# define HW_USBPHY_DEBUG_SET 0x54
# define HW_USBPHY_DEBUG_CLR 0x58
2014-02-24 10:20:59 +08:00
# define HW_USBPHY_IP 0x90
# define HW_USBPHY_IP_SET 0x94
# define HW_USBPHY_IP_CLR 0x98
2012-07-07 22:56:47 +08:00
# define BM_USBPHY_CTRL_SFTRST BIT(31)
# define BM_USBPHY_CTRL_CLKGATE BIT(30)
2014-02-24 10:20:55 +08:00
# define BM_USBPHY_CTRL_ENAUTOSET_USBCLKS BIT(26)
# define BM_USBPHY_CTRL_ENAUTOCLR_USBCLKGATE BIT(25)
2014-02-24 10:21:02 +08:00
# define BM_USBPHY_CTRL_ENVBUSCHG_WKUP BIT(23)
# define BM_USBPHY_CTRL_ENIDCHG_WKUP BIT(22)
# define BM_USBPHY_CTRL_ENDPDMCHG_WKUP BIT(21)
2014-02-24 10:20:55 +08:00
# define BM_USBPHY_CTRL_ENAUTOCLR_PHY_PWD BIT(20)
# define BM_USBPHY_CTRL_ENAUTOCLR_CLKGATE BIT(19)
# define BM_USBPHY_CTRL_ENAUTO_PWRON_PLL BIT(18)
2012-07-07 22:56:47 +08:00
# define BM_USBPHY_CTRL_ENUTMILEVEL3 BIT(15)
# define BM_USBPHY_CTRL_ENUTMILEVEL2 BIT(14)
# define BM_USBPHY_CTRL_ENHOSTDISCONDETECT BIT(1)
2014-02-24 10:20:59 +08:00
# define BM_USBPHY_IP_FIX (BIT(17) | BIT(18))
2014-02-24 10:21:02 +08:00
# define BM_USBPHY_DEBUG_CLKGATE BIT(30)
/* Anatop Registers */
2014-02-24 10:21:03 +08:00
# define ANADIG_ANA_MISC0 0x150
# define ANADIG_ANA_MISC0_SET 0x154
# define ANADIG_ANA_MISC0_CLR 0x158
2014-02-24 10:21:02 +08:00
# define ANADIG_USB1_VBUS_DET_STAT 0x1c0
# define ANADIG_USB2_VBUS_DET_STAT 0x220
# define ANADIG_USB1_LOOPBACK_SET 0x1e4
# define ANADIG_USB1_LOOPBACK_CLR 0x1e8
# define ANADIG_USB2_LOOPBACK_SET 0x244
# define ANADIG_USB2_LOOPBACK_CLR 0x248
2014-02-24 10:21:03 +08:00
# define BM_ANADIG_ANA_MISC0_STOP_MODE_CONFIG BIT(12)
# define BM_ANADIG_ANA_MISC0_STOP_MODE_CONFIG_SL BIT(11)
2014-02-24 10:21:02 +08:00
# define BM_ANADIG_USB1_VBUS_DET_STAT_VBUS_VALID BIT(3)
# define BM_ANADIG_USB2_VBUS_DET_STAT_VBUS_VALID BIT(3)
# define BM_ANADIG_USB1_LOOPBACK_UTMI_DIG_TST1 BIT(2)
# define BM_ANADIG_USB1_LOOPBACK_TSTI_TX_EN BIT(5)
# define BM_ANADIG_USB2_LOOPBACK_UTMI_DIG_TST1 BIT(2)
# define BM_ANADIG_USB2_LOOPBACK_TSTI_TX_EN BIT(5)
2014-02-24 10:20:54 +08:00
# define to_mxs_phy(p) container_of((p), struct mxs_phy, phy)
/* Do disconnection between PHY and controller without vbus */
# define MXS_PHY_DISCONNECT_LINE_WITHOUT_VBUS BIT(0)
/*
* The PHY will be in messy if there is a wakeup after putting
* bus to suspend ( set portsc . suspendM ) but before setting PHY to low
* power mode ( set portsc . phcd ) .
*/
# define MXS_PHY_ABNORMAL_IN_SUSPEND BIT(1)
/*
* The SOF sends too fast after resuming , it will cause disconnection
* between host and high speed device .
*/
# define MXS_PHY_SENDING_SOF_TOO_FAST BIT(2)
2014-02-24 10:20:59 +08:00
/*
* IC has bug fixes logic , they include
* MXS_PHY_ABNORMAL_IN_SUSPEND and MXS_PHY_SENDING_SOF_TOO_FAST
* which are described at above flags , the RTL will handle it
* according to different versions .
*/
# define MXS_PHY_NEED_IP_FIX BIT(3)
2014-02-24 10:20:54 +08:00
struct mxs_phy_data {
unsigned int flags ;
} ;
static const struct mxs_phy_data imx23_phy_data = {
. flags = MXS_PHY_ABNORMAL_IN_SUSPEND | MXS_PHY_SENDING_SOF_TOO_FAST ,
} ;
static const struct mxs_phy_data imx6q_phy_data = {
. flags = MXS_PHY_SENDING_SOF_TOO_FAST |
2014-02-24 10:20:59 +08:00
MXS_PHY_DISCONNECT_LINE_WITHOUT_VBUS |
MXS_PHY_NEED_IP_FIX ,
2014-02-24 10:20:54 +08:00
} ;
static const struct mxs_phy_data imx6sl_phy_data = {
2014-02-24 10:20:59 +08:00
. flags = MXS_PHY_DISCONNECT_LINE_WITHOUT_VBUS |
MXS_PHY_NEED_IP_FIX ,
2014-02-24 10:20:54 +08:00
} ;
2014-07-28 16:57:29 +02:00
static const struct mxs_phy_data vf610_phy_data = {
. flags = MXS_PHY_DISCONNECT_LINE_WITHOUT_VBUS |
MXS_PHY_NEED_IP_FIX ,
} ;
2014-02-24 10:20:54 +08:00
static const struct of_device_id mxs_phy_dt_ids [ ] = {
{ . compatible = " fsl,imx6sl-usbphy " , . data = & imx6sl_phy_data , } ,
{ . compatible = " fsl,imx6q-usbphy " , . data = & imx6q_phy_data , } ,
{ . compatible = " fsl,imx23-usbphy " , . data = & imx23_phy_data , } ,
2014-07-28 16:57:29 +02:00
{ . compatible = " fsl,vf610-usbphy " , . data = & vf610_phy_data , } ,
2014-02-24 10:20:54 +08:00
{ /* sentinel */ }
} ;
MODULE_DEVICE_TABLE ( of , mxs_phy_dt_ids ) ;
2012-07-07 22:56:47 +08:00
struct mxs_phy {
struct usb_phy phy ;
struct clk * clk ;
2014-02-24 10:20:54 +08:00
const struct mxs_phy_data * data ;
2014-02-24 10:20:57 +08:00
struct regmap * regmap_anatop ;
2014-02-24 10:21:00 +08:00
int port_id ;
2012-07-07 22:56:47 +08:00
} ;
2014-02-24 10:21:03 +08:00
static inline bool is_imx6q_phy ( struct mxs_phy * mxs_phy )
{
return mxs_phy - > data = = & imx6q_phy_data ;
}
static inline bool is_imx6sl_phy ( struct mxs_phy * mxs_phy )
{
return mxs_phy - > data = = & imx6sl_phy_data ;
}
2014-02-24 10:21:04 +08:00
/*
* PHY needs some 32 K cycles to switch from 32 K clock to
* bus ( such as AHB / AXI , etc ) clock .
*/
static void mxs_phy_clock_switch_delay ( void )
{
usleep_range ( 300 , 400 ) ;
}
2013-07-03 16:34:13 -03:00
static int mxs_phy_hw_init ( struct mxs_phy * mxs_phy )
2012-07-07 22:56:47 +08:00
{
2013-07-03 16:34:13 -03:00
int ret ;
2012-07-07 22:56:47 +08:00
void __iomem * base = mxs_phy - > phy . io_priv ;
2013-07-03 16:34:13 -03:00
ret = stmp_reset_block ( base + HW_USBPHY_CTRL ) ;
if ( ret )
return ret ;
2012-07-07 22:56:47 +08:00
/* Power up the PHY */
2013-02-28 11:52:30 +01:00
writel ( 0 , base + HW_USBPHY_PWD ) ;
2012-07-07 22:56:47 +08:00
2014-02-24 10:20:55 +08:00
/*
* USB PHY Ctrl Setting
* - Auto clock / power on
* - Enable full / low speed support
*/
writel ( BM_USBPHY_CTRL_ENAUTOSET_USBCLKS |
BM_USBPHY_CTRL_ENAUTOCLR_USBCLKGATE |
BM_USBPHY_CTRL_ENAUTOCLR_PHY_PWD |
BM_USBPHY_CTRL_ENAUTOCLR_CLKGATE |
BM_USBPHY_CTRL_ENAUTO_PWRON_PLL |
BM_USBPHY_CTRL_ENUTMILEVEL2 |
BM_USBPHY_CTRL_ENUTMILEVEL3 ,
2013-02-28 11:52:30 +01:00
base + HW_USBPHY_CTRL_SET ) ;
2013-07-03 16:34:13 -03:00
2014-02-24 10:20:59 +08:00
if ( mxs_phy - > data - > flags & MXS_PHY_NEED_IP_FIX )
writel ( BM_USBPHY_IP_FIX , base + HW_USBPHY_IP_SET ) ;
2013-07-03 16:34:13 -03:00
return 0 ;
2012-07-07 22:56:47 +08:00
}
2014-02-24 10:21:02 +08:00
/* Return true if the vbus is there */
static bool mxs_phy_get_vbus_status ( struct mxs_phy * mxs_phy )
{
unsigned int vbus_value ;
if ( mxs_phy - > port_id = = 0 )
regmap_read ( mxs_phy - > regmap_anatop ,
ANADIG_USB1_VBUS_DET_STAT ,
& vbus_value ) ;
else if ( mxs_phy - > port_id = = 1 )
regmap_read ( mxs_phy - > regmap_anatop ,
ANADIG_USB2_VBUS_DET_STAT ,
& vbus_value ) ;
if ( vbus_value & BM_ANADIG_USB1_VBUS_DET_STAT_VBUS_VALID )
return true ;
else
return false ;
}
static void __mxs_phy_disconnect_line ( struct mxs_phy * mxs_phy , bool disconnect )
{
void __iomem * base = mxs_phy - > phy . io_priv ;
u32 reg ;
if ( disconnect )
writel_relaxed ( BM_USBPHY_DEBUG_CLKGATE ,
base + HW_USBPHY_DEBUG_CLR ) ;
if ( mxs_phy - > port_id = = 0 ) {
reg = disconnect ? ANADIG_USB1_LOOPBACK_SET
: ANADIG_USB1_LOOPBACK_CLR ;
regmap_write ( mxs_phy - > regmap_anatop , reg ,
BM_ANADIG_USB1_LOOPBACK_UTMI_DIG_TST1 |
BM_ANADIG_USB1_LOOPBACK_TSTI_TX_EN ) ;
} else if ( mxs_phy - > port_id = = 1 ) {
reg = disconnect ? ANADIG_USB2_LOOPBACK_SET
: ANADIG_USB2_LOOPBACK_CLR ;
regmap_write ( mxs_phy - > regmap_anatop , reg ,
BM_ANADIG_USB2_LOOPBACK_UTMI_DIG_TST1 |
BM_ANADIG_USB2_LOOPBACK_TSTI_TX_EN ) ;
}
if ( ! disconnect )
writel_relaxed ( BM_USBPHY_DEBUG_CLKGATE ,
base + HW_USBPHY_DEBUG_SET ) ;
/* Delay some time, and let Linestate be SE0 for controller */
if ( disconnect )
usleep_range ( 500 , 1000 ) ;
}
static void mxs_phy_disconnect_line ( struct mxs_phy * mxs_phy , bool on )
{
bool vbus_is_on = false ;
/* If the SoCs don't need to disconnect line without vbus, quit */
if ( ! ( mxs_phy - > data - > flags & MXS_PHY_DISCONNECT_LINE_WITHOUT_VBUS ) )
return ;
/* If the SoCs don't have anatop, quit */
if ( ! mxs_phy - > regmap_anatop )
return ;
vbus_is_on = mxs_phy_get_vbus_status ( mxs_phy ) ;
if ( on & & ! vbus_is_on )
__mxs_phy_disconnect_line ( mxs_phy , true ) ;
else
__mxs_phy_disconnect_line ( mxs_phy , false ) ;
}
2012-07-07 22:56:47 +08:00
static int mxs_phy_init ( struct usb_phy * phy )
{
2013-12-02 01:02:34 -02:00
int ret ;
2012-07-07 22:56:47 +08:00
struct mxs_phy * mxs_phy = to_mxs_phy ( phy ) ;
2014-02-24 10:21:04 +08:00
mxs_phy_clock_switch_delay ( ) ;
2013-12-02 01:02:34 -02:00
ret = clk_prepare_enable ( mxs_phy - > clk ) ;
if ( ret )
return ret ;
2013-07-03 16:34:13 -03:00
return mxs_phy_hw_init ( mxs_phy ) ;
2012-07-07 22:56:47 +08:00
}
static void mxs_phy_shutdown ( struct usb_phy * phy )
{
struct mxs_phy * mxs_phy = to_mxs_phy ( phy ) ;
2013-02-28 11:52:30 +01:00
writel ( BM_USBPHY_CTRL_CLKGATE ,
phy - > io_priv + HW_USBPHY_CTRL_SET ) ;
2012-07-07 22:56:47 +08:00
clk_disable_unprepare ( mxs_phy - > clk ) ;
}
2013-01-10 16:35:53 +08:00
static int mxs_phy_suspend ( struct usb_phy * x , int suspend )
{
2013-12-02 01:02:34 -02:00
int ret ;
2013-01-10 16:35:53 +08:00
struct mxs_phy * mxs_phy = to_mxs_phy ( x ) ;
if ( suspend ) {
2013-02-28 11:52:30 +01:00
writel ( 0xffffffff , x - > io_priv + HW_USBPHY_PWD ) ;
writel ( BM_USBPHY_CTRL_CLKGATE ,
x - > io_priv + HW_USBPHY_CTRL_SET ) ;
2013-01-10 16:35:53 +08:00
clk_disable_unprepare ( mxs_phy - > clk ) ;
} else {
2014-02-24 10:21:04 +08:00
mxs_phy_clock_switch_delay ( ) ;
2013-12-02 01:02:34 -02:00
ret = clk_prepare_enable ( mxs_phy - > clk ) ;
if ( ret )
return ret ;
2013-02-28 11:52:30 +01:00
writel ( BM_USBPHY_CTRL_CLKGATE ,
x - > io_priv + HW_USBPHY_CTRL_CLR ) ;
writel ( 0 , x - > io_priv + HW_USBPHY_PWD ) ;
2013-01-10 16:35:53 +08:00
}
return 0 ;
}
2014-02-24 10:21:02 +08:00
static int mxs_phy_set_wakeup ( struct usb_phy * x , bool enabled )
{
struct mxs_phy * mxs_phy = to_mxs_phy ( x ) ;
u32 value = BM_USBPHY_CTRL_ENVBUSCHG_WKUP |
BM_USBPHY_CTRL_ENDPDMCHG_WKUP |
BM_USBPHY_CTRL_ENIDCHG_WKUP ;
if ( enabled ) {
mxs_phy_disconnect_line ( mxs_phy , true ) ;
writel_relaxed ( value , x - > io_priv + HW_USBPHY_CTRL_SET ) ;
} else {
writel_relaxed ( value , x - > io_priv + HW_USBPHY_CTRL_CLR ) ;
mxs_phy_disconnect_line ( mxs_phy , false ) ;
}
return 0 ;
}
2012-11-09 09:44:44 +08:00
static int mxs_phy_on_connect ( struct usb_phy * phy ,
enum usb_device_speed speed )
2012-07-07 22:56:47 +08:00
{
2014-02-24 10:20:58 +08:00
dev_dbg ( phy - > dev , " %s device has connected \n " ,
( speed = = USB_SPEED_HIGH ) ? " HS " : " FS/LS " ) ;
2012-07-07 22:56:47 +08:00
2012-11-09 09:44:44 +08:00
if ( speed = = USB_SPEED_HIGH )
2013-02-28 11:52:30 +01:00
writel ( BM_USBPHY_CTRL_ENHOSTDISCONDETECT ,
phy - > io_priv + HW_USBPHY_CTRL_SET ) ;
2012-07-07 22:56:47 +08:00
return 0 ;
}
2012-11-09 09:44:44 +08:00
static int mxs_phy_on_disconnect ( struct usb_phy * phy ,
enum usb_device_speed speed )
2012-07-07 22:56:47 +08:00
{
2014-02-24 10:20:58 +08:00
dev_dbg ( phy - > dev , " %s device has disconnected \n " ,
( speed = = USB_SPEED_HIGH ) ? " HS " : " FS/LS " ) ;
2012-07-07 22:56:47 +08:00
2012-11-09 09:44:44 +08:00
if ( speed = = USB_SPEED_HIGH )
2013-02-28 11:52:30 +01:00
writel ( BM_USBPHY_CTRL_ENHOSTDISCONDETECT ,
phy - > io_priv + HW_USBPHY_CTRL_CLR ) ;
2012-07-07 22:56:47 +08:00
return 0 ;
}
static int mxs_phy_probe ( struct platform_device * pdev )
{
struct resource * res ;
void __iomem * base ;
struct clk * clk ;
struct mxs_phy * mxs_phy ;
2013-02-27 15:16:30 +01:00
int ret ;
2014-02-24 10:20:54 +08:00
const struct of_device_id * of_id =
of_match_device ( mxs_phy_dt_ids , & pdev - > dev ) ;
2014-02-24 10:20:57 +08:00
struct device_node * np = pdev - > dev . of_node ;
2012-07-07 22:56:47 +08:00
res = platform_get_resource ( pdev , IORESOURCE_MEM , 0 ) ;
2013-01-21 11:09:22 +01:00
base = devm_ioremap_resource ( & pdev - > dev , res ) ;
if ( IS_ERR ( base ) )
return PTR_ERR ( base ) ;
2012-07-07 22:56:47 +08:00
clk = devm_clk_get ( & pdev - > dev , NULL ) ;
if ( IS_ERR ( clk ) ) {
dev_err ( & pdev - > dev ,
" can't get the clock, err=%ld " , PTR_ERR ( clk ) ) ;
return PTR_ERR ( clk ) ;
}
mxs_phy = devm_kzalloc ( & pdev - > dev , sizeof ( * mxs_phy ) , GFP_KERNEL ) ;
if ( ! mxs_phy ) {
dev_err ( & pdev - > dev , " Failed to allocate USB PHY structure! \n " ) ;
return - ENOMEM ;
}
2014-02-24 10:20:57 +08:00
/* Some SoCs don't have anatop registers */
if ( of_get_property ( np , " fsl,anatop " , NULL ) ) {
mxs_phy - > regmap_anatop = syscon_regmap_lookup_by_phandle
( np , " fsl,anatop " ) ;
if ( IS_ERR ( mxs_phy - > regmap_anatop ) ) {
dev_dbg ( & pdev - > dev ,
" failed to find regmap for anatop \n " ) ;
return PTR_ERR ( mxs_phy - > regmap_anatop ) ;
}
}
2014-02-24 10:21:00 +08:00
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 - > port_id = ret ;
2012-07-07 22:56:47 +08:00
mxs_phy - > phy . io_priv = base ;
mxs_phy - > phy . dev = & pdev - > dev ;
mxs_phy - > phy . label = DRIVER_NAME ;
mxs_phy - > phy . init = mxs_phy_init ;
mxs_phy - > phy . shutdown = mxs_phy_shutdown ;
2013-01-10 16:35:53 +08:00
mxs_phy - > phy . set_suspend = mxs_phy_suspend ;
2012-07-07 22:56:47 +08:00
mxs_phy - > phy . notify_connect = mxs_phy_on_connect ;
mxs_phy - > phy . notify_disconnect = mxs_phy_on_disconnect ;
2013-05-15 15:03:14 +02:00
mxs_phy - > phy . type = USB_PHY_TYPE_USB2 ;
2014-02-24 10:21:02 +08:00
mxs_phy - > phy . set_wakeup = mxs_phy_set_wakeup ;
2012-07-07 22:56:47 +08:00
mxs_phy - > clk = clk ;
2014-02-24 10:20:54 +08:00
mxs_phy - > data = of_id - > data ;
2012-07-07 22:56:47 +08:00
2013-11-07 10:55:49 +08:00
platform_set_drvdata ( pdev , mxs_phy ) ;
2012-07-07 22:56:47 +08:00
2014-02-24 10:21:03 +08:00
device_set_wakeup_capable ( & pdev - > dev , true ) ;
2013-02-27 15:16:30 +01:00
ret = usb_add_phy_dev ( & mxs_phy - > phy ) ;
if ( ret )
return ret ;
2012-07-07 22:56:47 +08:00
return 0 ;
}
2012-11-19 13:26:20 -05:00
static int mxs_phy_remove ( struct platform_device * pdev )
2012-07-07 22:56:47 +08:00
{
2013-02-27 15:16:30 +01:00
struct mxs_phy * mxs_phy = platform_get_drvdata ( pdev ) ;
usb_remove_phy ( & mxs_phy - > phy ) ;
2012-07-07 22:56:47 +08:00
return 0 ;
}
2014-02-24 10:21:03 +08:00
# ifdef CONFIG_PM_SLEEP
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 ;
/* If the SoCs don't have anatop, quit */
if ( ! mxs_phy - > regmap_anatop )
return ;
if ( is_imx6q_phy ( mxs_phy ) )
regmap_write ( mxs_phy - > regmap_anatop , reg ,
BM_ANADIG_ANA_MISC0_STOP_MODE_CONFIG ) ;
else if ( is_imx6sl_phy ( mxs_phy ) )
regmap_write ( mxs_phy - > regmap_anatop ,
reg , BM_ANADIG_ANA_MISC0_STOP_MODE_CONFIG_SL ) ;
}
static int mxs_phy_system_suspend ( struct device * dev )
{
struct mxs_phy * mxs_phy = dev_get_drvdata ( dev ) ;
if ( device_may_wakeup ( dev ) )
mxs_phy_enable_ldo_in_suspend ( mxs_phy , true ) ;
return 0 ;
}
static int mxs_phy_system_resume ( struct device * dev )
{
struct mxs_phy * mxs_phy = dev_get_drvdata ( dev ) ;
if ( device_may_wakeup ( dev ) )
mxs_phy_enable_ldo_in_suspend ( mxs_phy , false ) ;
return 0 ;
}
# endif /* CONFIG_PM_SLEEP */
static SIMPLE_DEV_PM_OPS ( mxs_phy_pm , mxs_phy_system_suspend ,
mxs_phy_system_resume ) ;
2012-07-07 22:56:47 +08:00
static struct platform_driver mxs_phy_driver = {
. probe = mxs_phy_probe ,
2012-11-19 13:21:08 -05:00
. remove = mxs_phy_remove ,
2012-07-07 22:56:47 +08:00
. driver = {
. name = DRIVER_NAME ,
. owner = THIS_MODULE ,
. of_match_table = mxs_phy_dt_ids ,
2014-02-24 10:21:03 +08:00
. pm = & mxs_phy_pm ,
2012-07-07 22:56:47 +08:00
} ,
} ;
static int __init mxs_phy_module_init ( void )
{
return platform_driver_register ( & mxs_phy_driver ) ;
}
postcore_initcall ( mxs_phy_module_init ) ;
static void __exit mxs_phy_module_exit ( void )
{
platform_driver_unregister ( & mxs_phy_driver ) ;
}
module_exit ( mxs_phy_module_exit ) ;
MODULE_ALIAS ( " platform:mxs-usb-phy " ) ;
MODULE_AUTHOR ( " Marek Vasut <marex@denx.de> " ) ;
MODULE_AUTHOR ( " Richard Zhao <richard.zhao@freescale.com> " ) ;
MODULE_DESCRIPTION ( " Freescale MXS USB PHY driver " ) ;
MODULE_LICENSE ( " GPL " ) ;