2010-12-07 17:54:03 +05:30
/* Copyright (c) 2010, Code Aurora Forum. All rights reserved.
*
* This program is free software ; you can redistribute it and / or modify
* it under the terms of the GNU General Public License version 2 and
* only version 2 as published by the Free Software Foundation .
*/
# include <linux/module.h>
# include <linux/platform_device.h>
2010-12-07 17:54:05 +05:30
# include <linux/pm_runtime.h>
2010-12-07 17:54:03 +05:30
# include <linux/usb/msm_hsusb_hw.h>
# include <linux/usb/ulpi.h>
2012-05-08 23:29:01 +03:00
# include <linux/usb/gadget.h>
2012-05-11 17:25:46 +03:00
# include <linux/usb/chipidea.h>
2010-12-07 17:54:03 +05:30
2012-05-11 17:25:46 +03:00
# include "ci.h"
2010-12-07 17:54:03 +05:30
2012-07-07 22:56:40 +08:00
# define MSM_USB_BASE (ci->hw_bank.abs)
2010-12-07 17:54:03 +05:30
2013-06-24 14:46:36 +03:00
static void ci_hdrc_msm_notify_event ( struct ci_hdrc * ci , unsigned event )
2010-12-07 17:54:03 +05:30
{
2012-07-07 22:56:40 +08:00
struct device * dev = ci - > gadget . dev . parent ;
2010-12-07 17:54:03 +05:30
switch ( event ) {
2013-06-24 14:46:36 +03:00
case CI_HDRC_CONTROLLER_RESET_EVENT :
dev_dbg ( dev , " CI_HDRC_CONTROLLER_RESET_EVENT received \n " ) ;
2010-12-07 17:54:03 +05:30
writel ( 0 , USB_AHBBURST ) ;
2015-11-06 00:04:06 -06:00
/* use AHB transactor, allow posted data writes */
writel ( 0x8 , USB_AHBMODE ) ;
2014-10-30 18:41:16 +01:00
usb_phy_init ( ci - > usb_phy ) ;
2010-12-07 17:54:03 +05:30
break ;
2013-06-24 14:46:36 +03:00
case CI_HDRC_CONTROLLER_STOPPED_EVENT :
dev_dbg ( dev , " CI_HDRC_CONTROLLER_STOPPED_EVENT received \n " ) ;
2010-12-07 17:54:03 +05:30
/*
2014-10-30 18:41:16 +01:00
* Put the phy in non - driving mode . Otherwise host
2010-12-07 17:54:03 +05:30
* may not detect soft - disconnection .
*/
2014-10-30 18:41:16 +01:00
usb_phy_notify_disconnect ( ci - > usb_phy , USB_SPEED_UNKNOWN ) ;
2010-12-07 17:54:03 +05:30
break ;
default :
2013-06-24 14:46:36 +03:00
dev_dbg ( dev , " unknown ci_hdrc event \n " ) ;
2010-12-07 17:54:03 +05:30
break ;
}
}
2013-06-24 14:46:36 +03:00
static struct ci_hdrc_platform_data ci_hdrc_msm_platdata = {
. name = " ci_hdrc_msm " ,
2014-05-04 09:24:42 +08:00
. capoffset = DEF_CAPOFFSET ,
2013-06-24 14:46:36 +03:00
. flags = CI_HDRC_REGS_SHARED |
CI_HDRC_DISABLE_STREAMING ,
2010-12-07 17:54:03 +05:30
2013-06-24 14:46:36 +03:00
. notify_event = ci_hdrc_msm_notify_event ,
2010-12-07 17:54:03 +05:30
} ;
2013-06-24 14:46:36 +03:00
static int ci_hdrc_msm_probe ( struct platform_device * pdev )
2010-12-07 17:54:03 +05:30
{
2012-05-08 23:29:01 +03:00
struct platform_device * plat_ci ;
2014-05-04 09:24:41 +08:00
struct usb_phy * phy ;
2010-12-07 17:54:03 +05:30
2013-06-24 14:46:36 +03:00
dev_dbg ( & pdev - > dev , " ci_hdrc_msm_probe \n " ) ;
2010-12-07 17:54:03 +05:30
2014-05-04 09:24:41 +08:00
/*
* OTG ( PHY ) driver takes care of PHY initialization , clock management ,
* powering up VBUS , mapping of registers address space and power
* management .
*/
phy = devm_usb_get_phy_by_phandle ( & pdev - > dev , " usb-phy " , 0 ) ;
if ( IS_ERR ( phy ) )
return PTR_ERR ( phy ) ;
2014-10-30 18:41:16 +01:00
ci_hdrc_msm_platdata . usb_phy = phy ;
2014-05-04 09:24:41 +08:00
2013-06-24 14:46:36 +03:00
plat_ci = ci_hdrc_add_device ( & pdev - > dev ,
2012-07-07 22:56:41 +08:00
pdev - > resource , pdev - > num_resources ,
2013-06-24 14:46:36 +03:00
& ci_hdrc_msm_platdata ) ;
2012-07-07 22:56:41 +08:00
if ( IS_ERR ( plat_ci ) ) {
2013-06-24 14:46:36 +03:00
dev_err ( & pdev - > dev , " ci_hdrc_add_device failed! \n " ) ;
2012-07-07 22:56:41 +08:00
return PTR_ERR ( plat_ci ) ;
2010-12-07 17:54:03 +05:30
}
2012-06-29 17:48:52 +08:00
platform_set_drvdata ( pdev , plat_ci ) ;
2016-12-28 14:56:58 -08:00
pm_runtime_set_active ( & pdev - > dev ) ;
2010-12-07 17:54:05 +05:30
pm_runtime_no_callbacks ( & pdev - > dev ) ;
pm_runtime_enable ( & pdev - > dev ) ;
2010-12-07 17:54:03 +05:30
return 0 ;
}
2013-06-24 14:46:36 +03:00
static int ci_hdrc_msm_remove ( struct platform_device * pdev )
2012-06-29 17:48:52 +08:00
{
struct platform_device * plat_ci = platform_get_drvdata ( pdev ) ;
pm_runtime_disable ( & pdev - > dev ) ;
2013-06-24 14:46:36 +03:00
ci_hdrc_remove_device ( plat_ci ) ;
2012-06-29 17:48:52 +08:00
return 0 ;
}
2014-05-04 09:24:41 +08:00
static const struct of_device_id msm_ci_dt_match [ ] = {
{ . compatible = " qcom,ci-hdrc " , } ,
{ }
} ;
MODULE_DEVICE_TABLE ( of , msm_ci_dt_match ) ;
2013-06-24 14:46:36 +03:00
static struct platform_driver ci_hdrc_msm_driver = {
. probe = ci_hdrc_msm_probe ,
. remove = ci_hdrc_msm_remove ,
2014-05-04 09:24:41 +08:00
. driver = {
. name = " msm_hsusb " ,
. of_match_table = msm_ci_dt_match ,
} ,
2010-12-07 17:54:03 +05:30
} ;
2013-06-24 14:46:36 +03:00
module_platform_driver ( ci_hdrc_msm_driver ) ;
2011-10-10 18:38:11 +02:00
2012-06-29 17:48:52 +08:00
MODULE_ALIAS ( " platform:msm_hsusb " ) ;
2013-06-24 14:46:36 +03:00
MODULE_ALIAS ( " platform:ci13xxx_msm " ) ;
2011-10-10 18:38:11 +02:00
MODULE_LICENSE ( " GPL v2 " ) ;