2017-11-03 13:28:30 +03:00
// SPDX-License-Identifier: GPL-2.0
2014-11-26 08:44:36 +03:00
/*
* Copyright ( C ) 2014 Marvell Technology Group Ltd .
*
* Antoine Tenart < antoine . tenart @ free - electrons . com >
*/
# include <linux/clk.h>
# include <linux/dma-mapping.h>
# include <linux/module.h>
# include <linux/of.h>
2015-08-31 17:49:51 +03:00
# include <linux/of_platform.h>
2014-11-26 08:44:36 +03:00
# include <linux/phy/phy.h>
# include <linux/platform_device.h>
# include <linux/usb/chipidea.h>
# include <linux/usb/hcd.h>
# include <linux/usb/ulpi.h>
# include "ci.h"
struct ci_hdrc_usb2_priv {
struct platform_device * ci_pdev ;
struct clk * clk ;
} ;
2015-05-29 19:38:45 +03:00
static const struct ci_hdrc_platform_data ci_default_pdata = {
2014-11-26 08:44:36 +03:00
. capoffset = DEF_CAPOFFSET ,
. flags = CI_HDRC_DISABLE_STREAMING ,
} ;
2015-08-31 17:49:51 +03:00
static struct ci_hdrc_platform_data ci_zynq_pdata = {
. capoffset = DEF_CAPOFFSET ,
} ;
static const struct of_device_id ci_hdrc_usb2_of_match [ ] = {
{ . compatible = " chipidea,usb2 " } ,
{ . compatible = " xlnx,zynq-usb-2.20a " , . data = & ci_zynq_pdata } ,
{ }
} ;
MODULE_DEVICE_TABLE ( of , ci_hdrc_usb2_of_match ) ;
2014-11-26 08:44:36 +03:00
static int ci_hdrc_usb2_probe ( struct platform_device * pdev )
{
struct device * dev = & pdev - > dev ;
struct ci_hdrc_usb2_priv * priv ;
struct ci_hdrc_platform_data * ci_pdata = dev_get_platdata ( dev ) ;
int ret ;
2015-08-31 17:49:51 +03:00
const struct of_device_id * match ;
2014-11-26 08:44:36 +03:00
2015-05-29 19:38:45 +03:00
if ( ! ci_pdata ) {
ci_pdata = devm_kmalloc ( dev , sizeof ( * ci_pdata ) , GFP_KERNEL ) ;
2017-08-25 08:22:53 +03:00
if ( ! ci_pdata )
return - ENOMEM ;
2015-05-29 19:38:45 +03:00
* ci_pdata = ci_default_pdata ; /* struct copy */
}
2014-11-26 08:44:36 +03:00
2015-08-31 17:49:51 +03:00
match = of_match_device ( ci_hdrc_usb2_of_match , & pdev - > dev ) ;
if ( match & & match - > data ) {
/* struct copy */
* ci_pdata = * ( struct ci_hdrc_platform_data * ) match - > data ;
}
2014-11-26 08:44:36 +03:00
priv = devm_kzalloc ( dev , sizeof ( * priv ) , GFP_KERNEL ) ;
if ( ! priv )
return - ENOMEM ;
priv - > clk = devm_clk_get ( dev , NULL ) ;
if ( ! IS_ERR ( priv - > clk ) ) {
ret = clk_prepare_enable ( priv - > clk ) ;
if ( ret ) {
dev_err ( dev , " failed to enable the clock: %d \n " , ret ) ;
return ret ;
}
}
ci_pdata - > name = dev_name ( dev ) ;
priv - > ci_pdev = ci_hdrc_add_device ( dev , pdev - > resource ,
pdev - > num_resources , ci_pdata ) ;
if ( IS_ERR ( priv - > ci_pdev ) ) {
ret = PTR_ERR ( priv - > ci_pdev ) ;
if ( ret ! = - EPROBE_DEFER )
dev_err ( dev ,
" failed to register ci_hdrc platform device: %d \n " ,
ret ) ;
goto clk_err ;
}
platform_set_drvdata ( pdev , priv ) ;
pm_runtime_no_callbacks ( dev ) ;
pm_runtime_enable ( dev ) ;
return 0 ;
clk_err :
if ( ! IS_ERR ( priv - > clk ) )
clk_disable_unprepare ( priv - > clk ) ;
return ret ;
}
static int ci_hdrc_usb2_remove ( struct platform_device * pdev )
{
struct ci_hdrc_usb2_priv * priv = platform_get_drvdata ( pdev ) ;
pm_runtime_disable ( & pdev - > dev ) ;
ci_hdrc_remove_device ( priv - > ci_pdev ) ;
clk_disable_unprepare ( priv - > clk ) ;
return 0 ;
}
static struct platform_driver ci_hdrc_usb2_driver = {
. probe = ci_hdrc_usb2_probe ,
. remove = ci_hdrc_usb2_remove ,
. driver = {
. name = " chipidea-usb2 " ,
. of_match_table = of_match_ptr ( ci_hdrc_usb2_of_match ) ,
} ,
} ;
module_platform_driver ( ci_hdrc_usb2_driver ) ;
MODULE_DESCRIPTION ( " ChipIdea HDRC USB2 binding for ci13xxx " ) ;
MODULE_AUTHOR ( " Antoine Tenart <antoine.tenart@free-electrons.com> " ) ;
MODULE_LICENSE ( " GPL " ) ;