2017-11-03 11:28:30 +01:00
// SPDX-License-Identifier: GPL-2.0
2015-11-18 13:15:20 -06:00
/**
* dwc3 - of - simple . c - OF glue layer for simple integrations
*
* Copyright ( c ) 2015 Texas Instruments Incorporated - http : //www.ti.com
*
* Author : Felipe Balbi < balbi @ ti . com >
*
* This is a combination of the old dwc3 - qcom . c by Ivan T . Ivanov
* < iivanov @ mm - sol . com > and the original patch adding support for Xilinx ' SoC
* by Subbaraya Sundeep Bhatta < subbaraya . sundeep . bhatta @ xilinx . com >
*/
# include <linux/module.h>
# include <linux/kernel.h>
# include <linux/slab.h>
# include <linux/platform_device.h>
# include <linux/dma-mapping.h>
# include <linux/clk.h>
# include <linux/of.h>
# include <linux/of_platform.h>
# include <linux/pm_runtime.h>
2017-10-19 13:47:43 +02:00
# include <linux/reset.h>
2015-11-18 13:15:20 -06:00
struct dwc3_of_simple {
struct device * dev ;
2019-03-27 19:24:06 +00:00
struct clk_bulk_data * clks ;
2015-11-18 13:15:20 -06:00
int num_clocks ;
2017-10-19 13:47:43 +02:00
struct reset_control * resets ;
2018-07-16 12:25:47 +02:00
bool need_reset ;
2015-11-18 13:15:20 -06:00
} ;
2016-09-12 21:20:22 +03:00
static int dwc3_of_simple_probe ( struct platform_device * pdev )
{
struct dwc3_of_simple * simple ;
struct device * dev = & pdev - > dev ;
struct device_node * np = dev - > of_node ;
int ret ;
simple = devm_kzalloc ( dev , sizeof ( * simple ) , GFP_KERNEL ) ;
if ( ! simple )
return - ENOMEM ;
platform_set_drvdata ( pdev , simple ) ;
simple - > dev = dev ;
2018-07-16 12:25:47 +02:00
/*
* Some controllers need to toggle the usb3 - otg reset before trying to
* initialize the PHY , otherwise the PHY times out .
*/
if ( of_device_is_compatible ( np , " rockchip,rk3399-dwc3 " ) )
simple - > need_reset = true ;
2020-04-16 14:19:08 +02:00
simple - > resets = of_reset_control_array_get ( np , false , true ,
2019-02-21 16:25:54 +01:00
true ) ;
2017-10-19 13:47:43 +02:00
if ( IS_ERR ( simple - > resets ) ) {
ret = PTR_ERR ( simple - > resets ) ;
dev_err ( dev , " failed to get device resets, err=%d \n " , ret ) ;
return ret ;
}
2020-04-16 14:19:08 +02:00
ret = reset_control_deassert ( simple - > resets ) ;
if ( ret )
goto err_resetc_put ;
2017-10-19 13:47:43 +02:00
2019-03-27 19:24:06 +00:00
ret = clk_bulk_get_all ( simple - > dev , & simple - > clks ) ;
if ( ret < 0 )
goto err_resetc_assert ;
simple - > num_clocks = ret ;
ret = clk_bulk_prepare_enable ( simple - > num_clocks , simple - > clks ) ;
2016-09-12 21:20:22 +03:00
if ( ret )
2017-10-19 13:47:43 +02:00
goto err_resetc_assert ;
2016-09-12 21:20:22 +03:00
2015-11-18 13:15:20 -06:00
ret = of_platform_populate ( np , NULL , NULL , dev ) ;
2019-03-27 19:24:06 +00:00
if ( ret )
goto err_clk_put ;
2015-11-18 13:15:20 -06:00
pm_runtime_set_active ( dev ) ;
pm_runtime_enable ( dev ) ;
pm_runtime_get_sync ( dev ) ;
return 0 ;
2017-10-19 13:47:43 +02:00
2019-03-27 19:24:06 +00:00
err_clk_put :
clk_bulk_disable_unprepare ( simple - > num_clocks , simple - > clks ) ;
clk_bulk_put_all ( simple - > num_clocks , simple - > clks ) ;
2017-10-19 13:47:43 +02:00
err_resetc_assert :
2020-04-16 14:19:08 +02:00
reset_control_assert ( simple - > resets ) ;
2017-10-19 13:47:43 +02:00
err_resetc_put :
reset_control_put ( simple - > resets ) ;
return ret ;
2015-11-18 13:15:20 -06:00
}
2019-10-29 12:56:11 +02:00
static void __dwc3_of_simple_teardown ( struct dwc3_of_simple * simple )
2015-11-18 13:15:20 -06:00
{
2019-10-29 12:56:11 +02:00
of_platform_depopulate ( simple - > dev ) ;
2017-07-19 17:59:06 +02:00
2019-03-27 19:24:06 +00:00
clk_bulk_disable_unprepare ( simple - > num_clocks , simple - > clks ) ;
clk_bulk_put_all ( simple - > num_clocks , simple - > clks ) ;
2017-12-18 16:14:36 +01:00
simple - > num_clocks = 0 ;
2015-11-18 13:15:20 -06:00
2020-04-16 14:19:08 +02:00
reset_control_assert ( simple - > resets ) ;
2018-02-11 22:15:16 +01:00
2017-10-19 13:47:43 +02:00
reset_control_put ( simple - > resets ) ;
2019-10-29 12:56:11 +02:00
pm_runtime_disable ( simple - > dev ) ;
pm_runtime_put_noidle ( simple - > dev ) ;
pm_runtime_set_suspended ( simple - > dev ) ;
}
static int dwc3_of_simple_remove ( struct platform_device * pdev )
{
struct dwc3_of_simple * simple = platform_get_drvdata ( pdev ) ;
__dwc3_of_simple_teardown ( simple ) ;
2015-11-18 13:15:20 -06:00
return 0 ;
}
2019-10-29 12:56:11 +02:00
static void dwc3_of_simple_shutdown ( struct platform_device * pdev )
{
struct dwc3_of_simple * simple = platform_get_drvdata ( pdev ) ;
__dwc3_of_simple_teardown ( simple ) ;
}
2018-08-13 23:56:55 +02:00
static int __maybe_unused dwc3_of_simple_runtime_suspend ( struct device * dev )
2015-11-18 13:15:20 -06:00
{
struct dwc3_of_simple * simple = dev_get_drvdata ( dev ) ;
2019-03-27 19:24:06 +00:00
clk_bulk_disable ( simple - > num_clocks , simple - > clks ) ;
2015-11-18 13:15:20 -06:00
return 0 ;
}
2018-08-13 23:56:55 +02:00
static int __maybe_unused dwc3_of_simple_runtime_resume ( struct device * dev )
2015-11-18 13:15:20 -06:00
{
struct dwc3_of_simple * simple = dev_get_drvdata ( dev ) ;
2019-03-27 19:24:06 +00:00
return clk_bulk_enable ( simple - > num_clocks , simple - > clks ) ;
2015-11-18 13:15:20 -06:00
}
2018-07-16 12:25:47 +02:00
2018-08-13 23:56:55 +02:00
static int __maybe_unused dwc3_of_simple_suspend ( struct device * dev )
2018-07-16 12:25:47 +02:00
{
struct dwc3_of_simple * simple = dev_get_drvdata ( dev ) ;
if ( simple - > need_reset )
reset_control_assert ( simple - > resets ) ;
return 0 ;
}
2018-08-13 23:56:55 +02:00
static int __maybe_unused dwc3_of_simple_resume ( struct device * dev )
2018-07-16 12:25:47 +02:00
{
struct dwc3_of_simple * simple = dev_get_drvdata ( dev ) ;
if ( simple - > need_reset )
reset_control_deassert ( simple - > resets ) ;
return 0 ;
}
2015-11-18 13:15:20 -06:00
static const struct dev_pm_ops dwc3_of_simple_dev_pm_ops = {
2018-07-16 12:25:47 +02:00
SET_SYSTEM_SLEEP_PM_OPS ( dwc3_of_simple_suspend , dwc3_of_simple_resume )
2015-11-18 13:15:20 -06:00
SET_RUNTIME_PM_OPS ( dwc3_of_simple_runtime_suspend ,
dwc3_of_simple_runtime_resume , NULL )
} ;
static const struct of_device_id of_dwc3_simple_match [ ] = {
2016-08-16 22:44:36 +08:00
{ . compatible = " rockchip,rk3399-dwc3 " } ,
2015-11-18 13:15:20 -06:00
{ . compatible = " xlnx,zynqmp-dwc3 " } ,
2016-09-12 21:24:58 +03:00
{ . compatible = " cavium,octeon-7130-usb-uctl " } ,
2017-08-30 19:03:52 +08:00
{ . compatible = " sprd,sc9860-dwc3 " } ,
2018-05-07 23:18:15 +08:00
{ . compatible = " allwinner,sun50i-h6-dwc3 " } ,
2015-11-18 13:15:20 -06:00
{ /* Sentinel */ }
} ;
MODULE_DEVICE_TABLE ( of , of_dwc3_simple_match ) ;
static struct platform_driver dwc3_of_simple_driver = {
. probe = dwc3_of_simple_probe ,
. remove = dwc3_of_simple_remove ,
2019-10-29 12:56:11 +02:00
. shutdown = dwc3_of_simple_shutdown ,
2015-11-18 13:15:20 -06:00
. driver = {
. name = " dwc3-of-simple " ,
. of_match_table = of_dwc3_simple_match ,
2017-12-07 13:40:24 +09:00
. pm = & dwc3_of_simple_dev_pm_ops ,
2015-11-18 13:15:20 -06:00
} ,
} ;
module_platform_driver ( dwc3_of_simple_driver ) ;
MODULE_LICENSE ( " GPL v2 " ) ;
MODULE_DESCRIPTION ( " DesignWare USB3 OF Simple Glue Layer " ) ;
MODULE_AUTHOR ( " Felipe Balbi <balbi@ti.com> " ) ;