2012-09-12 14:58:05 +03:00
/*
* Copyright 2012 Freescale Semiconductor , Inc .
*
* 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/of_platform.h>
# include <linux/err.h>
# include <linux/io.h>
2013-03-30 12:54:01 +02:00
# include <linux/delay.h>
2012-09-12 14:58:05 +03:00
2013-06-24 14:46:36 +03:00
# include "ci_hdrc_imx.h"
2012-09-12 14:58:05 +03:00
2013-03-30 12:54:01 +02:00
# define MX25_USB_PHY_CTRL_OFFSET 0x08
# define MX25_BM_EXTERNAL_VBUS_DIVIDER BIT(23)
2014-04-23 15:56:36 +08:00
# define MX25_EHCI_INTERFACE_SINGLE_UNI (2 << 0)
# define MX25_EHCI_INTERFACE_DIFF_UNI (0 << 0)
# define MX25_EHCI_INTERFACE_MASK (0xf)
# define MX25_OTG_SIC_SHIFT 29
# define MX25_OTG_SIC_MASK (0x3 << MX25_OTG_SIC_SHIFT)
# define MX25_OTG_PM_BIT BIT(24)
# define MX25_OTG_PP_BIT BIT(11)
# define MX25_OTG_OCPOL_BIT BIT(3)
# define MX25_H1_SIC_SHIFT 21
# define MX25_H1_SIC_MASK (0x3 << MX25_H1_SIC_SHIFT)
# define MX25_H1_PP_BIT BIT(18)
# define MX25_H1_PM_BIT BIT(16)
# define MX25_H1_IPPUE_UP_BIT BIT(7)
# define MX25_H1_IPPUE_DOWN_BIT BIT(6)
# define MX25_H1_TLL_BIT BIT(5)
# define MX25_H1_USBTE_BIT BIT(4)
# define MX25_H1_OCPOL_BIT BIT(2)
2013-12-06 16:35:14 +08:00
# define MX27_H1_PM_BIT BIT(8)
# define MX27_H2_PM_BIT BIT(16)
# define MX27_OTG_PM_BIT BIT(24)
2013-03-30 12:54:00 +02:00
# define MX53_USB_OTG_PHY_CTRL_0_OFFSET 0x08
2014-05-04 09:24:39 +08:00
# define MX53_USB_OTG_PHY_CTRL_1_OFFSET 0x0c
2016-09-26 13:14:19 +02:00
# define MX53_USB_CTRL_1_OFFSET 0x10
# define MX53_USB_CTRL_1_H2_XCVR_CLK_SEL_MASK (0x11 << 2)
# define MX53_USB_CTRL_1_H2_XCVR_CLK_SEL_ULPI BIT(2)
# define MX53_USB_CTRL_1_H3_XCVR_CLK_SEL_MASK (0x11 << 6)
# define MX53_USB_CTRL_1_H3_XCVR_CLK_SEL_ULPI BIT(6)
2013-03-30 12:54:00 +02:00
# define MX53_USB_UH2_CTRL_OFFSET 0x14
# define MX53_USB_UH3_CTRL_OFFSET 0x18
2016-09-26 13:14:20 +02:00
# define MX53_USB_CLKONOFF_CTRL_OFFSET 0x24
# define MX53_USB_CLKONOFF_CTRL_H2_INT60CKOFF BIT(21)
# define MX53_USB_CLKONOFF_CTRL_H3_INT60CKOFF BIT(22)
2013-03-30 12:54:00 +02:00
# define MX53_BM_OVER_CUR_DIS_H1 BIT(5)
# define MX53_BM_OVER_CUR_DIS_OTG BIT(8)
# define MX53_BM_OVER_CUR_DIS_UHx BIT(30)
2016-09-26 13:14:19 +02:00
# define MX53_USB_CTRL_1_UH2_ULPI_EN BIT(26)
# define MX53_USB_CTRL_1_UH3_ULPI_EN BIT(27)
# define MX53_USB_UHx_CTRL_WAKE_UP_EN BIT(7)
# define MX53_USB_UHx_CTRL_ULPI_INT_EN BIT(8)
2014-05-04 09:24:39 +08:00
# define MX53_USB_PHYCTRL1_PLLDIV_MASK 0x3
# define MX53_USB_PLL_DIV_24_MHZ 0x01
2013-03-30 12:54:00 +02:00
2014-11-05 14:58:32 +08:00
# define MX6_BM_NON_BURST_SETTING BIT(1)
2013-03-30 12:53:59 +02:00
# define MX6_BM_OVER_CUR_DIS BIT(7)
2016-07-20 16:02:42 +08:00
# define MX6_BM_OVER_CUR_POLARITY BIT(8)
2015-02-11 12:44:46 +08:00
# define MX6_BM_WAKEUP_ENABLE BIT(10)
# define MX6_BM_ID_WAKEUP BIT(16)
# define MX6_BM_VBUS_WAKEUP BIT(17)
2015-02-11 12:44:53 +08:00
# define MX6SX_BM_DPDM_WAKEUP_EN BIT(29)
2015-02-11 12:44:46 +08:00
# define MX6_BM_WAKEUP_INTR BIT(31)
2015-02-11 12:44:53 +08:00
# define MX6_USB_OTG1_PHY_CTRL 0x18
/* For imx6dql, it is host-only controller, for later imx6, it is otg's */
# define MX6_USB_OTG2_PHY_CTRL 0x1c
# define MX6SX_USB_VBUS_WAKEUP_SOURCE(v) (v << 8)
# define MX6SX_USB_VBUS_WAKEUP_SOURCE_VBUS MX6SX_USB_VBUS_WAKEUP_SOURCE(0)
# define MX6SX_USB_VBUS_WAKEUP_SOURCE_AVALID MX6SX_USB_VBUS_WAKEUP_SOURCE(1)
# define MX6SX_USB_VBUS_WAKEUP_SOURCE_BVALID MX6SX_USB_VBUS_WAKEUP_SOURCE(2)
# define MX6SX_USB_VBUS_WAKEUP_SOURCE_SESS_END MX6SX_USB_VBUS_WAKEUP_SOURCE(3)
2012-09-12 14:58:05 +03:00
2014-09-22 08:14:15 +08:00
# define VF610_OVER_CUR_DIS BIT(7)
2015-09-09 16:33:02 +08:00
# define MX7D_USBNC_USB_CTRL2 0x4
# define MX7D_USB_VBUS_WAKEUP_SOURCE_MASK 0x3
# define MX7D_USB_VBUS_WAKEUP_SOURCE(v) (v << 0)
# define MX7D_USB_VBUS_WAKEUP_SOURCE_VBUS MX7D_USB_VBUS_WAKEUP_SOURCE(0)
# define MX7D_USB_VBUS_WAKEUP_SOURCE_AVALID MX7D_USB_VBUS_WAKEUP_SOURCE(1)
# define MX7D_USB_VBUS_WAKEUP_SOURCE_BVALID MX7D_USB_VBUS_WAKEUP_SOURCE(2)
# define MX7D_USB_VBUS_WAKEUP_SOURCE_SESS_END MX7D_USB_VBUS_WAKEUP_SOURCE(3)
2013-08-14 12:44:16 +03:00
struct usbmisc_ops {
/* It's called once when probe a usb device */
int ( * init ) ( struct imx_usbmisc_data * data ) ;
/* It's called once after adding a usb device */
int ( * post ) ( struct imx_usbmisc_data * data ) ;
2015-02-11 12:44:46 +08:00
/* It's called when we need to enable/disable usb wakeup */
int ( * set_wakeup ) ( struct imx_usbmisc_data * data , bool enabled ) ;
2013-08-14 12:44:16 +03:00
} ;
2013-03-30 12:53:56 +02:00
struct imx_usbmisc {
2012-09-12 14:58:05 +03:00
void __iomem * base ;
spinlock_t lock ;
2013-03-30 12:53:59 +02:00
const struct usbmisc_ops * ops ;
2012-09-12 14:58:05 +03:00
} ;
2014-04-23 15:56:36 +08:00
static int usbmisc_imx25_init ( struct imx_usbmisc_data * data )
{
2014-09-22 08:14:15 +08:00
struct imx_usbmisc * usbmisc = dev_get_drvdata ( data - > dev ) ;
2014-04-23 15:56:36 +08:00
unsigned long flags ;
u32 val = 0 ;
if ( data - > index > 1 )
return - EINVAL ;
spin_lock_irqsave ( & usbmisc - > lock , flags ) ;
switch ( data - > index ) {
case 0 :
val = readl ( usbmisc - > base ) ;
val & = ~ ( MX25_OTG_SIC_MASK | MX25_OTG_PP_BIT ) ;
val | = ( MX25_EHCI_INTERFACE_DIFF_UNI & MX25_EHCI_INTERFACE_MASK ) < < MX25_OTG_SIC_SHIFT ;
val | = ( MX25_OTG_PM_BIT | MX25_OTG_OCPOL_BIT ) ;
writel ( val , usbmisc - > base ) ;
break ;
case 1 :
val = readl ( usbmisc - > base ) ;
val & = ~ ( MX25_H1_SIC_MASK | MX25_H1_PP_BIT | MX25_H1_IPPUE_UP_BIT ) ;
val | = ( MX25_EHCI_INTERFACE_SINGLE_UNI & MX25_EHCI_INTERFACE_MASK ) < < MX25_H1_SIC_SHIFT ;
val | = ( MX25_H1_PM_BIT | MX25_H1_OCPOL_BIT | MX25_H1_TLL_BIT |
MX25_H1_USBTE_BIT | MX25_H1_IPPUE_DOWN_BIT ) ;
writel ( val , usbmisc - > base ) ;
break ;
}
spin_unlock_irqrestore ( & usbmisc - > lock , flags ) ;
return 0 ;
}
2013-08-14 12:44:16 +03:00
static int usbmisc_imx25_post ( struct imx_usbmisc_data * data )
2013-03-30 12:54:01 +02:00
{
2014-09-22 08:14:15 +08:00
struct imx_usbmisc * usbmisc = dev_get_drvdata ( data - > dev ) ;
2013-03-30 12:54:01 +02:00
void __iomem * reg ;
unsigned long flags ;
u32 val ;
2013-08-14 12:44:16 +03:00
if ( data - > index > 2 )
return - EINVAL ;
2013-03-30 12:54:01 +02:00
2013-08-14 12:44:16 +03:00
if ( data - > evdo ) {
2013-03-30 12:54:01 +02:00
spin_lock_irqsave ( & usbmisc - > lock , flags ) ;
2014-11-26 13:44:25 +08:00
reg = usbmisc - > base + MX25_USB_PHY_CTRL_OFFSET ;
2013-03-30 12:54:01 +02:00
val = readl ( reg ) ;
writel ( val | MX25_BM_EXTERNAL_VBUS_DIVIDER , reg ) ;
spin_unlock_irqrestore ( & usbmisc - > lock , flags ) ;
usleep_range ( 5000 , 10000 ) ; /* needed to stabilize voltage */
}
return 0 ;
}
2013-12-06 16:35:14 +08:00
static int usbmisc_imx27_init ( struct imx_usbmisc_data * data )
{
2014-09-22 08:14:15 +08:00
struct imx_usbmisc * usbmisc = dev_get_drvdata ( data - > dev ) ;
2013-12-06 16:35:14 +08:00
unsigned long flags ;
u32 val ;
switch ( data - > index ) {
case 0 :
val = MX27_OTG_PM_BIT ;
break ;
case 1 :
val = MX27_H1_PM_BIT ;
break ;
case 2 :
val = MX27_H2_PM_BIT ;
break ;
default :
return - EINVAL ;
2015-05-09 12:15:24 -03:00
}
2013-12-06 16:35:14 +08:00
spin_lock_irqsave ( & usbmisc - > lock , flags ) ;
if ( data - > disable_oc )
val = readl ( usbmisc - > base ) | val ;
else
val = readl ( usbmisc - > base ) & ~ val ;
writel ( val , usbmisc - > base ) ;
spin_unlock_irqrestore ( & usbmisc - > lock , flags ) ;
return 0 ;
}
2013-08-14 12:44:16 +03:00
static int usbmisc_imx53_init ( struct imx_usbmisc_data * data )
2013-03-30 12:54:00 +02:00
{
2014-09-22 08:14:15 +08:00
struct imx_usbmisc * usbmisc = dev_get_drvdata ( data - > dev ) ;
2013-03-30 12:54:00 +02:00
void __iomem * reg = NULL ;
unsigned long flags ;
u32 val = 0 ;
2013-08-14 12:44:16 +03:00
if ( data - > index > 3 )
return - EINVAL ;
2013-03-30 12:54:00 +02:00
2014-05-04 09:24:39 +08:00
/* Select a 24 MHz reference clock for the PHY */
2014-11-26 13:44:26 +08:00
val = readl ( usbmisc - > base + MX53_USB_OTG_PHY_CTRL_1_OFFSET ) ;
2014-05-04 09:24:39 +08:00
val & = ~ MX53_USB_PHYCTRL1_PLLDIV_MASK ;
val | = MX53_USB_PLL_DIV_24_MHZ ;
writel ( val , usbmisc - > base + MX53_USB_OTG_PHY_CTRL_1_OFFSET ) ;
2016-09-26 13:14:19 +02:00
spin_lock_irqsave ( & usbmisc - > lock , flags ) ;
switch ( data - > index ) {
case 0 :
if ( data - > disable_oc ) {
2013-03-30 12:54:00 +02:00
reg = usbmisc - > base + MX53_USB_OTG_PHY_CTRL_0_OFFSET ;
val = readl ( reg ) | MX53_BM_OVER_CUR_DIS_OTG ;
2016-09-26 13:14:19 +02:00
writel ( val , reg ) ;
}
break ;
case 1 :
if ( data - > disable_oc ) {
2013-03-30 12:54:00 +02:00
reg = usbmisc - > base + MX53_USB_OTG_PHY_CTRL_0_OFFSET ;
val = readl ( reg ) | MX53_BM_OVER_CUR_DIS_H1 ;
2016-09-26 13:14:19 +02:00
writel ( val , reg ) ;
}
break ;
case 2 :
if ( data - > ulpi ) {
/* set USBH2 into ULPI-mode. */
reg = usbmisc - > base + MX53_USB_CTRL_1_OFFSET ;
val = readl ( reg ) | MX53_USB_CTRL_1_UH2_ULPI_EN ;
/* select ULPI clock */
val & = ~ MX53_USB_CTRL_1_H2_XCVR_CLK_SEL_MASK ;
val | = MX53_USB_CTRL_1_H2_XCVR_CLK_SEL_ULPI ;
writel ( val , reg ) ;
/* Set interrupt wake up enable */
reg = usbmisc - > base + MX53_USB_UH2_CTRL_OFFSET ;
val = readl ( reg ) | MX53_USB_UHx_CTRL_WAKE_UP_EN
| MX53_USB_UHx_CTRL_ULPI_INT_EN ;
writel ( val , reg ) ;
2016-09-26 13:14:20 +02:00
/* Disable internal 60Mhz clock */
reg = usbmisc - > base + MX53_USB_CLKONOFF_CTRL_OFFSET ;
val = readl ( reg ) | MX53_USB_CLKONOFF_CTRL_H2_INT60CKOFF ;
writel ( val , reg ) ;
2016-09-26 13:14:19 +02:00
}
if ( data - > disable_oc ) {
2013-03-30 12:54:00 +02:00
reg = usbmisc - > base + MX53_USB_UH2_CTRL_OFFSET ;
val = readl ( reg ) | MX53_BM_OVER_CUR_DIS_UHx ;
2016-09-26 13:14:19 +02:00
writel ( val , reg ) ;
}
break ;
case 3 :
if ( data - > ulpi ) {
/* set USBH3 into ULPI-mode. */
reg = usbmisc - > base + MX53_USB_CTRL_1_OFFSET ;
val = readl ( reg ) | MX53_USB_CTRL_1_UH3_ULPI_EN ;
/* select ULPI clock */
val & = ~ MX53_USB_CTRL_1_H3_XCVR_CLK_SEL_MASK ;
val | = MX53_USB_CTRL_1_H3_XCVR_CLK_SEL_ULPI ;
writel ( val , reg ) ;
/* Set interrupt wake up enable */
2013-03-30 12:54:00 +02:00
reg = usbmisc - > base + MX53_USB_UH3_CTRL_OFFSET ;
2016-09-26 13:14:19 +02:00
val = readl ( reg ) | MX53_USB_UHx_CTRL_WAKE_UP_EN
| MX53_USB_UHx_CTRL_ULPI_INT_EN ;
writel ( val , reg ) ;
2016-09-26 13:14:20 +02:00
/* Disable internal 60Mhz clock */
reg = usbmisc - > base + MX53_USB_CLKONOFF_CTRL_OFFSET ;
val = readl ( reg ) | MX53_USB_CLKONOFF_CTRL_H3_INT60CKOFF ;
writel ( val , reg ) ;
2013-03-30 12:54:00 +02:00
}
2016-09-26 13:14:19 +02:00
if ( data - > disable_oc ) {
reg = usbmisc - > base + MX53_USB_UH3_CTRL_OFFSET ;
val = readl ( reg ) | MX53_BM_OVER_CUR_DIS_UHx ;
2013-03-30 12:54:00 +02:00
writel ( val , reg ) ;
2016-09-26 13:14:19 +02:00
}
break ;
2013-03-30 12:54:00 +02:00
}
2016-09-26 13:14:19 +02:00
spin_unlock_irqrestore ( & usbmisc - > lock , flags ) ;
2013-03-30 12:54:00 +02:00
return 0 ;
}
2015-02-11 12:44:46 +08:00
static int usbmisc_imx6q_set_wakeup
( struct imx_usbmisc_data * data , bool enabled )
{
struct imx_usbmisc * usbmisc = dev_get_drvdata ( data - > dev ) ;
unsigned long flags ;
u32 val ;
u32 wakeup_setting = ( MX6_BM_WAKEUP_ENABLE |
MX6_BM_VBUS_WAKEUP | MX6_BM_ID_WAKEUP ) ;
int ret = 0 ;
if ( data - > index > 3 )
return - EINVAL ;
spin_lock_irqsave ( & usbmisc - > lock , flags ) ;
val = readl ( usbmisc - > base + data - > index * 4 ) ;
if ( enabled ) {
val | = wakeup_setting ;
writel ( val , usbmisc - > base + data - > index * 4 ) ;
} else {
if ( val & MX6_BM_WAKEUP_INTR )
pr_debug ( " wakeup int at ci_hdrc.%d \n " , data - > index ) ;
val & = ~ wakeup_setting ;
writel ( val , usbmisc - > base + data - > index * 4 ) ;
}
spin_unlock_irqrestore ( & usbmisc - > lock , flags ) ;
return ret ;
}
2013-08-14 12:44:16 +03:00
static int usbmisc_imx6q_init ( struct imx_usbmisc_data * data )
2012-09-12 14:58:05 +03:00
{
2014-09-22 08:14:15 +08:00
struct imx_usbmisc * usbmisc = dev_get_drvdata ( data - > dev ) ;
2012-09-12 14:58:05 +03:00
unsigned long flags ;
u32 reg ;
2013-08-14 12:44:16 +03:00
if ( data - > index > 3 )
return - EINVAL ;
2012-09-12 14:58:05 +03:00
2014-11-05 14:58:32 +08:00
spin_lock_irqsave ( & usbmisc - > lock , flags ) ;
2016-07-20 16:02:42 +08:00
reg = readl ( usbmisc - > base + data - > index * 4 ) ;
2013-08-14 12:44:16 +03:00
if ( data - > disable_oc ) {
2016-07-20 16:02:42 +08:00
reg | = MX6_BM_OVER_CUR_DIS ;
} else if ( data - > oc_polarity = = 1 ) {
/* High active */
reg & = ~ ( MX6_BM_OVER_CUR_DIS | MX6_BM_OVER_CUR_POLARITY ) ;
2012-09-12 14:58:05 +03:00
}
2016-07-20 16:02:42 +08:00
writel ( reg , usbmisc - > base + data - > index * 4 ) ;
2012-09-12 14:58:05 +03:00
2014-11-05 14:58:32 +08:00
/* SoC non-burst setting */
reg = readl ( usbmisc - > base + data - > index * 4 ) ;
writel ( reg | MX6_BM_NON_BURST_SETTING ,
usbmisc - > base + data - > index * 4 ) ;
spin_unlock_irqrestore ( & usbmisc - > lock , flags ) ;
2015-02-11 12:44:46 +08:00
usbmisc_imx6q_set_wakeup ( data , false ) ;
2012-09-12 14:58:05 +03:00
return 0 ;
}
2015-02-11 12:44:53 +08:00
static int usbmisc_imx6sx_init ( struct imx_usbmisc_data * data )
{
void __iomem * reg = NULL ;
unsigned long flags ;
struct imx_usbmisc * usbmisc = dev_get_drvdata ( data - > dev ) ;
u32 val ;
usbmisc_imx6q_init ( data ) ;
if ( data - > index = = 0 | | data - > index = = 1 ) {
reg = usbmisc - > base + MX6_USB_OTG1_PHY_CTRL + data - > index * 4 ;
spin_lock_irqsave ( & usbmisc - > lock , flags ) ;
/* Set vbus wakeup source as bvalid */
val = readl ( reg ) ;
writel ( val | MX6SX_USB_VBUS_WAKEUP_SOURCE_BVALID , reg ) ;
/*
* Disable dp / dm wakeup in device mode when vbus is
* not there .
*/
val = readl ( usbmisc - > base + data - > index * 4 ) ;
writel ( val & ~ MX6SX_BM_DPDM_WAKEUP_EN ,
usbmisc - > base + data - > index * 4 ) ;
spin_unlock_irqrestore ( & usbmisc - > lock , flags ) ;
}
2015-03-25 07:23:52 +01:00
return 0 ;
2015-02-11 12:44:53 +08:00
}
2014-09-22 08:14:15 +08:00
static int usbmisc_vf610_init ( struct imx_usbmisc_data * data )
{
struct imx_usbmisc * usbmisc = dev_get_drvdata ( data - > dev ) ;
u32 reg ;
/*
* Vybrid only has one misc register set , but in two different
* areas . These is reflected in two instances of this driver .
*/
if ( data - > index > = 1 )
return - EINVAL ;
if ( data - > disable_oc ) {
reg = readl ( usbmisc - > base ) ;
writel ( reg | VF610_OVER_CUR_DIS , usbmisc - > base ) ;
}
return 0 ;
}
2015-09-09 16:33:02 +08:00
static int usbmisc_imx7d_set_wakeup
( struct imx_usbmisc_data * data , bool enabled )
{
struct imx_usbmisc * usbmisc = dev_get_drvdata ( data - > dev ) ;
unsigned long flags ;
u32 val ;
u32 wakeup_setting = ( MX6_BM_WAKEUP_ENABLE |
MX6_BM_VBUS_WAKEUP | MX6_BM_ID_WAKEUP ) ;
spin_lock_irqsave ( & usbmisc - > lock , flags ) ;
val = readl ( usbmisc - > base ) ;
if ( enabled ) {
writel ( val | wakeup_setting , usbmisc - > base ) ;
} else {
if ( val & MX6_BM_WAKEUP_INTR )
dev_dbg ( data - > dev , " wakeup int \n " ) ;
writel ( val & ~ wakeup_setting , usbmisc - > base ) ;
}
spin_unlock_irqrestore ( & usbmisc - > lock , flags ) ;
return 0 ;
}
static int usbmisc_imx7d_init ( struct imx_usbmisc_data * data )
{
struct imx_usbmisc * usbmisc = dev_get_drvdata ( data - > dev ) ;
unsigned long flags ;
u32 reg ;
if ( data - > index > = 1 )
return - EINVAL ;
spin_lock_irqsave ( & usbmisc - > lock , flags ) ;
2016-07-20 16:02:42 +08:00
reg = readl ( usbmisc - > base ) ;
2015-09-09 16:33:02 +08:00
if ( data - > disable_oc ) {
2016-07-20 16:02:42 +08:00
reg | = MX6_BM_OVER_CUR_DIS ;
} else if ( data - > oc_polarity = = 1 ) {
/* High active */
reg & = ~ ( MX6_BM_OVER_CUR_DIS | MX6_BM_OVER_CUR_POLARITY ) ;
2015-09-09 16:33:02 +08:00
}
2016-07-20 16:02:42 +08:00
writel ( reg , usbmisc - > base ) ;
2015-09-09 16:33:02 +08:00
reg = readl ( usbmisc - > base + MX7D_USBNC_USB_CTRL2 ) ;
reg & = ~ MX7D_USB_VBUS_WAKEUP_SOURCE_MASK ;
writel ( reg | MX7D_USB_VBUS_WAKEUP_SOURCE_BVALID ,
usbmisc - > base + MX7D_USBNC_USB_CTRL2 ) ;
spin_unlock_irqrestore ( & usbmisc - > lock , flags ) ;
usbmisc_imx7d_set_wakeup ( data , false ) ;
return 0 ;
}
2013-03-30 12:54:01 +02:00
static const struct usbmisc_ops imx25_usbmisc_ops = {
2014-04-23 15:56:36 +08:00
. init = usbmisc_imx25_init ,
2013-03-30 12:54:01 +02:00
. post = usbmisc_imx25_post ,
} ;
2013-12-06 16:35:14 +08:00
static const struct usbmisc_ops imx27_usbmisc_ops = {
. init = usbmisc_imx27_init ,
} ;
2013-03-30 12:54:00 +02:00
static const struct usbmisc_ops imx53_usbmisc_ops = {
. init = usbmisc_imx53_init ,
} ;
2012-09-12 14:58:05 +03:00
static const struct usbmisc_ops imx6q_usbmisc_ops = {
2015-02-11 12:44:46 +08:00
. set_wakeup = usbmisc_imx6q_set_wakeup ,
2012-09-12 14:58:05 +03:00
. init = usbmisc_imx6q_init ,
} ;
2014-09-22 08:14:15 +08:00
static const struct usbmisc_ops vf610_usbmisc_ops = {
. init = usbmisc_vf610_init ,
} ;
2015-02-11 12:44:53 +08:00
static const struct usbmisc_ops imx6sx_usbmisc_ops = {
. set_wakeup = usbmisc_imx6q_set_wakeup ,
. init = usbmisc_imx6sx_init ,
} ;
2015-09-09 16:33:02 +08:00
static const struct usbmisc_ops imx7d_usbmisc_ops = {
. init = usbmisc_imx7d_init ,
. set_wakeup = usbmisc_imx7d_set_wakeup ,
} ;
2013-08-14 12:44:16 +03:00
int imx_usbmisc_init ( struct imx_usbmisc_data * data )
{
2015-02-11 12:44:44 +08:00
struct imx_usbmisc * usbmisc ;
if ( ! data )
return 0 ;
2014-09-22 08:14:15 +08:00
2015-02-11 12:44:44 +08:00
usbmisc = dev_get_drvdata ( data - > dev ) ;
2013-08-14 12:44:16 +03:00
if ( ! usbmisc - > ops - > init )
return 0 ;
return usbmisc - > ops - > init ( data ) ;
}
EXPORT_SYMBOL_GPL ( imx_usbmisc_init ) ;
int imx_usbmisc_init_post ( struct imx_usbmisc_data * data )
{
2015-02-11 12:44:44 +08:00
struct imx_usbmisc * usbmisc ;
if ( ! data )
return 0 ;
2014-09-22 08:14:15 +08:00
2015-02-11 12:44:44 +08:00
usbmisc = dev_get_drvdata ( data - > dev ) ;
2013-08-14 12:44:16 +03:00
if ( ! usbmisc - > ops - > post )
return 0 ;
return usbmisc - > ops - > post ( data ) ;
}
EXPORT_SYMBOL_GPL ( imx_usbmisc_init_post ) ;
2015-02-11 12:44:46 +08:00
int imx_usbmisc_set_wakeup ( struct imx_usbmisc_data * data , bool enabled )
{
struct imx_usbmisc * usbmisc ;
if ( ! data )
return 0 ;
usbmisc = dev_get_drvdata ( data - > dev ) ;
if ( ! usbmisc - > ops - > set_wakeup )
return 0 ;
return usbmisc - > ops - > set_wakeup ( data , enabled ) ;
}
EXPORT_SYMBOL_GPL ( imx_usbmisc_set_wakeup ) ;
2013-03-30 12:53:56 +02:00
static const struct of_device_id usbmisc_imx_dt_ids [ ] = {
2013-03-30 12:54:01 +02:00
{
. compatible = " fsl,imx25-usbmisc " ,
. data = & imx25_usbmisc_ops ,
} ,
2014-04-23 15:56:36 +08:00
{
. compatible = " fsl,imx35-usbmisc " ,
. data = & imx25_usbmisc_ops ,
} ,
2013-12-06 16:35:14 +08:00
{
. compatible = " fsl,imx27-usbmisc " ,
. data = & imx27_usbmisc_ops ,
} ,
2013-12-06 16:35:15 +08:00
{
. compatible = " fsl,imx51-usbmisc " ,
. data = & imx53_usbmisc_ops ,
} ,
2013-03-30 12:54:00 +02:00
{
. compatible = " fsl,imx53-usbmisc " ,
. data = & imx53_usbmisc_ops ,
} ,
2013-03-30 12:53:59 +02:00
{
. compatible = " fsl,imx6q-usbmisc " ,
. data = & imx6q_usbmisc_ops ,
} ,
2014-09-22 08:14:15 +08:00
{
. compatible = " fsl,vf610-usbmisc " ,
. data = & vf610_usbmisc_ops ,
} ,
2015-02-11 12:44:53 +08:00
{
. compatible = " fsl,imx6sx-usbmisc " ,
. data = & imx6sx_usbmisc_ops ,
} ,
2015-09-16 15:52:32 +08:00
{
. compatible = " fsl,imx6ul-usbmisc " ,
. data = & imx6sx_usbmisc_ops ,
} ,
2016-07-20 16:02:42 +08:00
{
. compatible = " fsl,imx7d-usbmisc " ,
. data = & imx7d_usbmisc_ops ,
} ,
2012-09-12 14:58:05 +03:00
{ /* sentinel */ }
} ;
2013-06-20 23:33:25 +02:00
MODULE_DEVICE_TABLE ( of , usbmisc_imx_dt_ids ) ;
2012-09-12 14:58:05 +03:00
2013-03-30 12:53:56 +02:00
static int usbmisc_imx_probe ( struct platform_device * pdev )
2012-09-12 14:58:05 +03:00
{
struct resource * res ;
2013-03-30 12:53:56 +02:00
struct imx_usbmisc * data ;
2015-11-12 08:43:33 +01:00
const struct of_device_id * of_id ;
of_id = of_match_device ( usbmisc_imx_dt_ids , & pdev - > dev ) ;
if ( ! of_id )
return - ENODEV ;
2012-09-12 14:58:05 +03:00
data = devm_kzalloc ( & pdev - > dev , sizeof ( * data ) , GFP_KERNEL ) ;
if ( ! data )
return - ENOMEM ;
spin_lock_init ( & data - > lock ) ;
res = platform_get_resource ( pdev , IORESOURCE_MEM , 0 ) ;
2013-01-21 11:09:22 +01:00
data - > base = devm_ioremap_resource ( & pdev - > dev , res ) ;
if ( IS_ERR ( data - > base ) )
return PTR_ERR ( data - > base ) ;
2012-09-12 14:58:05 +03:00
2015-11-12 08:43:33 +01:00
data - > ops = ( const struct usbmisc_ops * ) of_id - > data ;
2014-09-22 08:14:15 +08:00
platform_set_drvdata ( pdev , data ) ;
2012-09-12 14:58:05 +03:00
return 0 ;
}
2013-03-30 12:53:56 +02:00
static int usbmisc_imx_remove ( struct platform_device * pdev )
2012-09-12 14:58:05 +03:00
{
return 0 ;
}
2013-03-30 12:53:56 +02:00
static struct platform_driver usbmisc_imx_driver = {
. probe = usbmisc_imx_probe ,
. remove = usbmisc_imx_remove ,
2012-09-12 14:58:05 +03:00
. driver = {
2013-03-30 12:53:56 +02:00
. name = " usbmisc_imx " ,
. of_match_table = usbmisc_imx_dt_ids ,
2012-09-12 14:58:05 +03:00
} ,
} ;
2013-06-13 17:59:59 +03:00
module_platform_driver ( usbmisc_imx_driver ) ;
2012-09-12 14:58:05 +03:00
2013-03-30 12:53:56 +02:00
MODULE_ALIAS ( " platform:usbmisc-imx " ) ;
2012-09-12 14:58:05 +03:00
MODULE_LICENSE ( " GPL v2 " ) ;
2013-03-30 12:53:56 +02:00
MODULE_DESCRIPTION ( " driver for imx usb non-core registers " ) ;
2012-09-12 14:58:05 +03:00
MODULE_AUTHOR ( " Richard Zhao <richard.zhao@freescale.com> " ) ;