2017-11-03 13:28:30 +03:00
// SPDX-License-Identifier: GPL-2.0
2016-10-19 05:28:23 +03:00
/*
* Copyright ( C ) 2016 MediaTek Inc .
*
* Author : Chunfeng Yun < chunfeng . yun @ mediatek . com >
*/
# include <linux/clk.h>
# include <linux/dma-mapping.h>
# include <linux/iopoll.h>
# include <linux/kernel.h>
# include <linux/module.h>
# include <linux/of_address.h>
# include <linux/of_irq.h>
# include <linux/platform_device.h>
# include "mtu3.h"
2016-10-19 05:28:25 +03:00
# include "mtu3_dr.h"
2019-03-21 05:53:46 +03:00
# include "mtu3_debug.h"
2016-10-19 05:28:23 +03:00
/* u2-port0 should be powered on and enabled; */
2016-10-19 05:28:25 +03:00
int ssusb_check_clocks ( struct ssusb_mtk * ssusb , u32 ex_clks )
2016-10-19 05:28:23 +03:00
{
2016-10-19 05:28:25 +03:00
void __iomem * ibase = ssusb - > ippc_base ;
2016-10-19 05:28:23 +03:00
u32 value , check_val ;
int ret ;
check_val = ex_clks | SSUSB_SYS125_RST_B_STS | SSUSB_SYSPLL_STABLE |
SSUSB_REF_RST_B_STS ;
ret = readl_poll_timeout ( ibase + U3D_SSUSB_IP_PW_STS1 , value ,
( check_val = = ( value & check_val ) ) , 100 , 20000 ) ;
if ( ret ) {
2016-10-19 05:28:25 +03:00
dev_err ( ssusb - > dev , " clks of sts1 are not stable! \n " ) ;
2016-10-19 05:28:23 +03:00
return ret ;
}
ret = readl_poll_timeout ( ibase + U3D_SSUSB_IP_PW_STS2 , value ,
( value & SSUSB_U2_MAC_SYS_RST_B_STS ) , 100 , 10000 ) ;
if ( ret ) {
2016-10-19 05:28:25 +03:00
dev_err ( ssusb - > dev , " mac2 clock is not stable \n " ) ;
2016-10-19 05:28:23 +03:00
return ret ;
}
return 0 ;
}
2016-10-19 05:28:25 +03:00
static int ssusb_phy_init ( struct ssusb_mtk * ssusb )
{
int i ;
int ret ;
for ( i = 0 ; i < ssusb - > num_phys ; i + + ) {
ret = phy_init ( ssusb - > phys [ i ] ) ;
if ( ret )
goto exit_phy ;
}
return 0 ;
exit_phy :
for ( ; i > 0 ; i - - )
phy_exit ( ssusb - > phys [ i - 1 ] ) ;
return ret ;
}
static int ssusb_phy_exit ( struct ssusb_mtk * ssusb )
{
int i ;
for ( i = 0 ; i < ssusb - > num_phys ; i + + )
phy_exit ( ssusb - > phys [ i ] ) ;
return 0 ;
}
static int ssusb_phy_power_on ( struct ssusb_mtk * ssusb )
{
int i ;
int ret ;
for ( i = 0 ; i < ssusb - > num_phys ; i + + ) {
ret = phy_power_on ( ssusb - > phys [ i ] ) ;
if ( ret )
goto power_off_phy ;
}
return 0 ;
power_off_phy :
for ( ; i > 0 ; i - - )
phy_power_off ( ssusb - > phys [ i - 1 ] ) ;
return ret ;
}
static void ssusb_phy_power_off ( struct ssusb_mtk * ssusb )
{
unsigned int i ;
for ( i = 0 ; i < ssusb - > num_phys ; i + + )
phy_power_off ( ssusb - > phys [ i ] ) ;
}
2017-10-13 12:10:40 +03:00
static int ssusb_clks_enable ( struct ssusb_mtk * ssusb )
2016-10-19 05:28:23 +03:00
{
2017-10-13 12:10:40 +03:00
int ret ;
2016-10-19 05:28:23 +03:00
2016-10-19 05:28:25 +03:00
ret = clk_prepare_enable ( ssusb - > sys_clk ) ;
2016-10-19 05:28:23 +03:00
if ( ret ) {
2016-10-19 05:28:25 +03:00
dev_err ( ssusb - > dev , " failed to enable sys_clk \n " ) ;
2017-01-18 09:08:23 +03:00
goto sys_clk_err ;
}
ret = clk_prepare_enable ( ssusb - > ref_clk ) ;
if ( ret ) {
dev_err ( ssusb - > dev , " failed to enable ref_clk \n " ) ;
goto ref_clk_err ;
2016-10-19 05:28:23 +03:00
}
2017-10-13 12:10:40 +03:00
ret = clk_prepare_enable ( ssusb - > mcu_clk ) ;
if ( ret ) {
dev_err ( ssusb - > dev , " failed to enable mcu_clk \n " ) ;
goto mcu_clk_err ;
}
ret = clk_prepare_enable ( ssusb - > dma_clk ) ;
if ( ret ) {
dev_err ( ssusb - > dev , " failed to enable dma_clk \n " ) ;
goto dma_clk_err ;
}
return 0 ;
dma_clk_err :
clk_disable_unprepare ( ssusb - > mcu_clk ) ;
mcu_clk_err :
clk_disable_unprepare ( ssusb - > ref_clk ) ;
ref_clk_err :
clk_disable_unprepare ( ssusb - > sys_clk ) ;
sys_clk_err :
return ret ;
}
static void ssusb_clks_disable ( struct ssusb_mtk * ssusb )
{
clk_disable_unprepare ( ssusb - > dma_clk ) ;
clk_disable_unprepare ( ssusb - > mcu_clk ) ;
clk_disable_unprepare ( ssusb - > ref_clk ) ;
clk_disable_unprepare ( ssusb - > sys_clk ) ;
}
static int ssusb_rscs_init ( struct ssusb_mtk * ssusb )
{
int ret = 0 ;
ret = regulator_enable ( ssusb - > vusb33 ) ;
if ( ret ) {
dev_err ( ssusb - > dev , " failed to enable vusb33 \n " ) ;
goto vusb33_err ;
}
ret = ssusb_clks_enable ( ssusb ) ;
if ( ret )
goto clks_err ;
2016-10-19 05:28:25 +03:00
ret = ssusb_phy_init ( ssusb ) ;
2016-10-19 05:28:23 +03:00
if ( ret ) {
2016-10-19 05:28:25 +03:00
dev_err ( ssusb - > dev , " failed to init phy \n " ) ;
2016-10-19 05:28:23 +03:00
goto phy_init_err ;
}
2016-10-19 05:28:25 +03:00
ret = ssusb_phy_power_on ( ssusb ) ;
2016-10-19 05:28:23 +03:00
if ( ret ) {
2016-10-19 05:28:25 +03:00
dev_err ( ssusb - > dev , " failed to power on phy \n " ) ;
2016-10-19 05:28:23 +03:00
goto phy_err ;
}
return 0 ;
phy_err :
2016-10-19 05:28:25 +03:00
ssusb_phy_exit ( ssusb ) ;
2016-10-19 05:28:23 +03:00
phy_init_err :
2017-10-13 12:10:40 +03:00
ssusb_clks_disable ( ssusb ) ;
clks_err :
2016-10-19 05:28:25 +03:00
regulator_disable ( ssusb - > vusb33 ) ;
2016-10-19 05:28:23 +03:00
vusb33_err :
return ret ;
}
2016-10-19 05:28:25 +03:00
static void ssusb_rscs_exit ( struct ssusb_mtk * ssusb )
2016-10-19 05:28:23 +03:00
{
2017-10-13 12:10:40 +03:00
ssusb_clks_disable ( ssusb ) ;
2016-10-19 05:28:25 +03:00
regulator_disable ( ssusb - > vusb33 ) ;
ssusb_phy_power_off ( ssusb ) ;
ssusb_phy_exit ( ssusb ) ;
2016-10-19 05:28:23 +03:00
}
2016-10-19 05:28:25 +03:00
static void ssusb_ip_sw_reset ( struct ssusb_mtk * ssusb )
2016-10-19 05:28:23 +03:00
{
2016-10-19 05:28:25 +03:00
/* reset whole ip (xhci & u3d) */
mtu3_setbits ( ssusb - > ippc_base , U3D_SSUSB_IP_PW_CTRL0 , SSUSB_IP_SW_RST ) ;
2016-10-19 05:28:23 +03:00
udelay ( 1 ) ;
2016-10-19 05:28:25 +03:00
mtu3_clrbits ( ssusb - > ippc_base , U3D_SSUSB_IP_PW_CTRL0 , SSUSB_IP_SW_RST ) ;
2018-11-29 06:16:27 +03:00
/*
* device ip may be powered on in firmware / BROM stage before entering
* kernel stage ;
* power down device ip , otherwise ip - sleep will fail when working as
* host only mode
*/
mtu3_setbits ( ssusb - > ippc_base , U3D_SSUSB_IP_PW_CTRL2 , SSUSB_IP_DEV_PDN ) ;
2016-10-19 05:28:23 +03:00
}
2016-10-19 05:28:25 +03:00
static int get_ssusb_rscs ( struct platform_device * pdev , struct ssusb_mtk * ssusb )
2016-10-19 05:28:23 +03:00
{
struct device_node * node = pdev - > dev . of_node ;
2016-10-19 05:28:26 +03:00
struct otg_switch_mtk * otg_sx = & ssusb - > otg_switch ;
2016-10-19 05:28:23 +03:00
struct device * dev = & pdev - > dev ;
struct resource * res ;
2016-10-19 05:28:25 +03:00
int i ;
int ret ;
2016-10-19 05:28:23 +03:00
2019-03-21 05:53:46 +03:00
ssusb - > vusb33 = devm_regulator_get ( dev , " vusb33 " ) ;
2017-01-18 09:08:22 +03:00
if ( IS_ERR ( ssusb - > vusb33 ) ) {
dev_err ( dev , " failed to get vusb33 \n " ) ;
return PTR_ERR ( ssusb - > vusb33 ) ;
}
ssusb - > sys_clk = devm_clk_get ( dev , " sys_ck " ) ;
if ( IS_ERR ( ssusb - > sys_clk ) ) {
dev_err ( dev , " failed to get sys clock \n " ) ;
return PTR_ERR ( ssusb - > sys_clk ) ;
}
2019-04-17 11:28:21 +03:00
ssusb - > ref_clk = devm_clk_get_optional ( dev , " ref_ck " ) ;
2017-10-13 12:10:40 +03:00
if ( IS_ERR ( ssusb - > ref_clk ) )
return PTR_ERR ( ssusb - > ref_clk ) ;
2017-02-07 09:13:32 +03:00
2019-04-17 11:28:21 +03:00
ssusb - > mcu_clk = devm_clk_get_optional ( dev , " mcu_ck " ) ;
2017-10-13 12:10:40 +03:00
if ( IS_ERR ( ssusb - > mcu_clk ) )
return PTR_ERR ( ssusb - > mcu_clk ) ;
2019-04-17 11:28:21 +03:00
ssusb - > dma_clk = devm_clk_get_optional ( dev , " dma_ck " ) ;
2017-10-13 12:10:40 +03:00
if ( IS_ERR ( ssusb - > dma_clk ) )
return PTR_ERR ( ssusb - > dma_clk ) ;
2017-01-18 09:08:23 +03:00
2016-10-19 05:28:25 +03:00
ssusb - > num_phys = of_count_phandle_with_args ( node ,
" phys " , " #phy-cells " ) ;
if ( ssusb - > num_phys > 0 ) {
ssusb - > phys = devm_kcalloc ( dev , ssusb - > num_phys ,
sizeof ( * ssusb - > phys ) , GFP_KERNEL ) ;
if ( ! ssusb - > phys )
return - ENOMEM ;
} else {
ssusb - > num_phys = 0 ;
2016-10-19 05:28:23 +03:00
}
2016-10-19 05:28:25 +03:00
for ( i = 0 ; i < ssusb - > num_phys ; i + + ) {
ssusb - > phys [ i ] = devm_of_phy_get_by_index ( dev , node , i ) ;
if ( IS_ERR ( ssusb - > phys [ i ] ) ) {
dev_err ( dev , " failed to get phy-%d \n " , i ) ;
return PTR_ERR ( ssusb - > phys [ i ] ) ;
}
2016-10-19 05:28:23 +03:00
}
res = platform_get_resource_byname ( pdev , IORESOURCE_MEM , " ippc " ) ;
2016-10-19 05:28:25 +03:00
ssusb - > ippc_base = devm_ioremap_resource ( dev , res ) ;
2017-02-05 19:25:38 +03:00
if ( IS_ERR ( ssusb - > ippc_base ) )
2016-10-19 05:28:25 +03:00
return PTR_ERR ( ssusb - > ippc_base ) ;
2016-10-19 05:28:23 +03:00
2016-10-19 05:28:25 +03:00
ssusb - > dr_mode = usb_get_dr_mode ( dev ) ;
2017-10-13 12:10:45 +03:00
if ( ssusb - > dr_mode = = USB_DR_MODE_UNKNOWN )
ssusb - > dr_mode = USB_DR_MODE_OTG ;
2016-10-19 05:28:23 +03:00
2016-10-19 05:28:25 +03:00
if ( ssusb - > dr_mode = = USB_DR_MODE_PERIPHERAL )
2019-03-21 05:53:40 +03:00
goto out ;
2016-10-19 05:28:25 +03:00
/* if host role is supported */
ret = ssusb_wakeup_of_property_parse ( ssusb , node ) ;
2018-01-03 11:53:18 +03:00
if ( ret ) {
dev_err ( dev , " failed to parse uwk property \n " ) ;
2016-10-19 05:28:25 +03:00
return ret ;
2018-01-03 11:53:18 +03:00
}
2016-10-19 05:28:25 +03:00
2017-10-13 12:10:38 +03:00
/* optional property, ignore the error if it does not exist */
of_property_read_u32 ( node , " mediatek,u3p-dis-msk " ,
& ssusb - > u3p_dis_msk ) ;
2019-03-21 05:53:42 +03:00
otg_sx - > vbus = devm_regulator_get ( dev , " vbus " ) ;
if ( IS_ERR ( otg_sx - > vbus ) ) {
2016-10-19 05:28:26 +03:00
dev_err ( dev , " failed to get vbus \n " ) ;
2019-03-21 05:53:42 +03:00
return PTR_ERR ( otg_sx - > vbus ) ;
2016-10-19 05:28:26 +03:00
}
2017-10-13 12:10:44 +03:00
if ( ssusb - > dr_mode = = USB_DR_MODE_HOST )
2019-03-21 05:53:40 +03:00
goto out ;
2017-10-13 12:10:44 +03:00
/* if dual-role mode is supported */
2016-10-19 05:28:26 +03:00
otg_sx - > is_u3_drd = of_property_read_bool ( node , " mediatek,usb3-drd " ) ;
otg_sx - > manual_drd_enabled =
of_property_read_bool ( node , " enable-manual-drd " ) ;
2019-08-29 12:22:38 +03:00
otg_sx - > role_sw_used = of_property_read_bool ( node , " usb-role-switch " ) ;
2016-10-19 05:28:26 +03:00
2019-08-29 12:22:38 +03:00
if ( ! otg_sx - > role_sw_used & & of_property_read_bool ( node , " extcon " ) ) {
2016-10-19 05:28:26 +03:00
otg_sx - > edev = extcon_get_edev_by_phandle ( ssusb - > dev , 0 ) ;
if ( IS_ERR ( otg_sx - > edev ) ) {
dev_err ( ssusb - > dev , " couldn't get extcon device \n " ) ;
2018-01-03 11:53:17 +03:00
return PTR_ERR ( otg_sx - > edev ) ;
2016-10-19 05:28:26 +03:00
}
}
2019-03-21 05:53:40 +03:00
out :
2017-10-13 12:10:42 +03:00
dev_info ( dev , " dr_mode: %d, is_u3_dr: %d, u3p_dis_msk: %x, drd: %s \n " ,
ssusb - > dr_mode , otg_sx - > is_u3_drd , ssusb - > u3p_dis_msk ,
otg_sx - > manual_drd_enabled ? " manual " : " auto " ) ;
2016-10-19 05:28:26 +03:00
2016-10-19 05:28:23 +03:00
return 0 ;
}
static int mtu3_probe ( struct platform_device * pdev )
{
2016-10-19 05:28:25 +03:00
struct device_node * node = pdev - > dev . of_node ;
2016-10-19 05:28:23 +03:00
struct device * dev = & pdev - > dev ;
2016-10-19 05:28:25 +03:00
struct ssusb_mtk * ssusb ;
2016-10-19 05:28:23 +03:00
int ret = - ENOMEM ;
/* all elements are set to ZERO as default value */
2016-10-19 05:28:25 +03:00
ssusb = devm_kzalloc ( dev , sizeof ( * ssusb ) , GFP_KERNEL ) ;
if ( ! ssusb )
2016-10-19 05:28:23 +03:00
return - ENOMEM ;
ret = dma_set_mask_and_coherent ( dev , DMA_BIT_MASK ( 32 ) ) ;
if ( ret ) {
dev_err ( dev , " No suitable DMA config available \n " ) ;
return - ENOTSUPP ;
}
2016-10-19 05:28:25 +03:00
platform_set_drvdata ( pdev , ssusb ) ;
ssusb - > dev = dev ;
2016-10-19 05:28:23 +03:00
2016-10-19 05:28:25 +03:00
ret = get_ssusb_rscs ( pdev , ssusb ) ;
2016-10-19 05:28:23 +03:00
if ( ret )
return ret ;
2019-03-21 05:53:46 +03:00
ssusb_debugfs_create_root ( ssusb ) ;
2016-10-19 05:28:23 +03:00
/* enable power domain */
pm_runtime_enable ( dev ) ;
pm_runtime_get_sync ( dev ) ;
device_enable_async_suspend ( dev ) ;
2016-10-19 05:28:25 +03:00
ret = ssusb_rscs_init ( ssusb ) ;
2016-10-19 05:28:23 +03:00
if ( ret )
goto comm_init_err ;
2016-10-19 05:28:25 +03:00
ssusb_ip_sw_reset ( ssusb ) ;
if ( IS_ENABLED ( CONFIG_USB_MTU3_HOST ) )
ssusb - > dr_mode = USB_DR_MODE_HOST ;
else if ( IS_ENABLED ( CONFIG_USB_MTU3_GADGET ) )
ssusb - > dr_mode = USB_DR_MODE_PERIPHERAL ;
/* default as host */
ssusb - > is_host = ! ( ssusb - > dr_mode = = USB_DR_MODE_PERIPHERAL ) ;
switch ( ssusb - > dr_mode ) {
case USB_DR_MODE_PERIPHERAL :
ret = ssusb_gadget_init ( ssusb ) ;
if ( ret ) {
dev_err ( dev , " failed to initialize gadget \n " ) ;
goto comm_exit ;
}
break ;
case USB_DR_MODE_HOST :
ret = ssusb_host_init ( ssusb , node ) ;
if ( ret ) {
dev_err ( dev , " failed to initialize host \n " ) ;
goto comm_exit ;
}
break ;
2016-10-19 05:28:26 +03:00
case USB_DR_MODE_OTG :
ret = ssusb_gadget_init ( ssusb ) ;
if ( ret ) {
dev_err ( dev , " failed to initialize gadget \n " ) ;
goto comm_exit ;
}
ret = ssusb_host_init ( ssusb , node ) ;
if ( ret ) {
dev_err ( dev , " failed to initialize host \n " ) ;
goto gadget_exit ;
}
2019-03-21 05:53:39 +03:00
ret = ssusb_otg_switch_init ( ssusb ) ;
if ( ret ) {
dev_err ( dev , " failed to initialize switch \n " ) ;
goto host_exit ;
}
2016-10-19 05:28:26 +03:00
break ;
2016-10-19 05:28:25 +03:00
default :
dev_err ( dev , " unsupported mode: %d \n " , ssusb - > dr_mode ) ;
ret = - EINVAL ;
2016-10-19 05:28:23 +03:00
goto comm_exit ;
}
return 0 ;
2019-03-21 05:53:39 +03:00
host_exit :
ssusb_host_exit ( ssusb ) ;
2016-10-19 05:28:26 +03:00
gadget_exit :
ssusb_gadget_exit ( ssusb ) ;
2016-10-19 05:28:23 +03:00
comm_exit :
2016-10-19 05:28:25 +03:00
ssusb_rscs_exit ( ssusb ) ;
2016-10-19 05:28:23 +03:00
comm_init_err :
pm_runtime_put_sync ( dev ) ;
pm_runtime_disable ( dev ) ;
2019-03-21 05:53:46 +03:00
ssusb_debugfs_remove_root ( ssusb ) ;
2016-10-19 05:28:23 +03:00
return ret ;
}
static int mtu3_remove ( struct platform_device * pdev )
{
2016-10-19 05:28:25 +03:00
struct ssusb_mtk * ssusb = platform_get_drvdata ( pdev ) ;
switch ( ssusb - > dr_mode ) {
case USB_DR_MODE_PERIPHERAL :
ssusb_gadget_exit ( ssusb ) ;
break ;
case USB_DR_MODE_HOST :
ssusb_host_exit ( ssusb ) ;
break ;
2016-10-19 05:28:26 +03:00
case USB_DR_MODE_OTG :
ssusb_otg_switch_exit ( ssusb ) ;
ssusb_gadget_exit ( ssusb ) ;
ssusb_host_exit ( ssusb ) ;
break ;
2016-10-19 05:28:25 +03:00
default :
return - EINVAL ;
}
2016-10-19 05:28:23 +03:00
2016-10-19 05:28:25 +03:00
ssusb_rscs_exit ( ssusb ) ;
2016-10-19 05:28:23 +03:00
pm_runtime_put_sync ( & pdev - > dev ) ;
pm_runtime_disable ( & pdev - > dev ) ;
2019-03-21 05:53:46 +03:00
ssusb_debugfs_remove_root ( ssusb ) ;
2016-10-19 05:28:23 +03:00
return 0 ;
}
2016-10-19 05:28:25 +03:00
/*
* when support dual - role mode , we reject suspend when
* it works as device mode ;
*/
static int __maybe_unused mtu3_suspend ( struct device * dev )
{
2018-04-19 17:06:25 +03:00
struct ssusb_mtk * ssusb = dev_get_drvdata ( dev ) ;
2016-10-19 05:28:25 +03:00
dev_dbg ( dev , " %s \n " , __func__ ) ;
/* REVISIT: disconnect it for only device mode? */
if ( ! ssusb - > is_host )
return 0 ;
ssusb_host_disable ( ssusb , true ) ;
ssusb_phy_power_off ( ssusb ) ;
2017-10-13 12:10:40 +03:00
ssusb_clks_disable ( ssusb ) ;
2018-01-03 11:53:18 +03:00
ssusb_wakeup_set ( ssusb , true ) ;
2016-10-19 05:28:25 +03:00
return 0 ;
}
static int __maybe_unused mtu3_resume ( struct device * dev )
{
2018-04-19 17:06:25 +03:00
struct ssusb_mtk * ssusb = dev_get_drvdata ( dev ) ;
2017-06-09 15:03:31 +03:00
int ret ;
2016-10-19 05:28:25 +03:00
dev_dbg ( dev , " %s \n " , __func__ ) ;
if ( ! ssusb - > is_host )
return 0 ;
2018-01-03 11:53:18 +03:00
ssusb_wakeup_set ( ssusb , false ) ;
2017-10-13 12:10:40 +03:00
ret = ssusb_clks_enable ( ssusb ) ;
2017-06-09 15:03:31 +03:00
if ( ret )
2017-10-13 12:10:40 +03:00
goto clks_err ;
2017-06-09 15:03:31 +03:00
ret = ssusb_phy_power_on ( ssusb ) ;
if ( ret )
2017-10-13 12:10:40 +03:00
goto phy_err ;
2017-06-09 15:03:31 +03:00
2016-10-19 05:28:25 +03:00
ssusb_host_enable ( ssusb ) ;
return 0 ;
2017-06-09 15:03:31 +03:00
2017-10-13 12:10:40 +03:00
phy_err :
ssusb_clks_disable ( ssusb ) ;
clks_err :
2017-06-09 15:03:31 +03:00
return ret ;
2016-10-19 05:28:25 +03:00
}
static const struct dev_pm_ops mtu3_pm_ops = {
SET_SYSTEM_SLEEP_PM_OPS ( mtu3_suspend , mtu3_resume )
} ;
# define DEV_PM_OPS (IS_ENABLED(CONFIG_PM) ? &mtu3_pm_ops : NULL)
2016-10-19 05:28:23 +03:00
# ifdef CONFIG_OF
static const struct of_device_id mtu3_of_match [ ] = {
{ . compatible = " mediatek,mt8173-mtu3 " , } ,
2017-08-08 08:42:49 +03:00
{ . compatible = " mediatek,mtu3 " , } ,
2016-10-19 05:28:23 +03:00
{ } ,
} ;
MODULE_DEVICE_TABLE ( of , mtu3_of_match ) ;
# endif
static struct platform_driver mtu3_driver = {
. probe = mtu3_probe ,
. remove = mtu3_remove ,
. driver = {
. name = MTU3_DRIVER_NAME ,
2016-10-19 05:28:25 +03:00
. pm = DEV_PM_OPS ,
2016-10-19 05:28:23 +03:00
. of_match_table = of_match_ptr ( mtu3_of_match ) ,
} ,
} ;
module_platform_driver ( mtu3_driver ) ;
MODULE_AUTHOR ( " Chunfeng Yun <chunfeng.yun@mediatek.com> " ) ;
MODULE_LICENSE ( " GPL v2 " ) ;
MODULE_DESCRIPTION ( " MediaTek USB3 DRD Controller Driver " ) ;