18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0+ 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * Copyright 2012 Freescale Semiconductor, Inc. 48c2ecf20Sopenharmony_ci */ 58c2ecf20Sopenharmony_ci 68c2ecf20Sopenharmony_ci#include <linux/module.h> 78c2ecf20Sopenharmony_ci#include <linux/of_platform.h> 88c2ecf20Sopenharmony_ci#include <linux/err.h> 98c2ecf20Sopenharmony_ci#include <linux/io.h> 108c2ecf20Sopenharmony_ci#include <linux/delay.h> 118c2ecf20Sopenharmony_ci#include <linux/usb/otg.h> 128c2ecf20Sopenharmony_ci 138c2ecf20Sopenharmony_ci#include "ci_hdrc_imx.h" 148c2ecf20Sopenharmony_ci 158c2ecf20Sopenharmony_ci#define MX25_USB_PHY_CTRL_OFFSET 0x08 168c2ecf20Sopenharmony_ci#define MX25_BM_EXTERNAL_VBUS_DIVIDER BIT(23) 178c2ecf20Sopenharmony_ci 188c2ecf20Sopenharmony_ci#define MX25_EHCI_INTERFACE_SINGLE_UNI (2 << 0) 198c2ecf20Sopenharmony_ci#define MX25_EHCI_INTERFACE_DIFF_UNI (0 << 0) 208c2ecf20Sopenharmony_ci#define MX25_EHCI_INTERFACE_MASK (0xf) 218c2ecf20Sopenharmony_ci 228c2ecf20Sopenharmony_ci#define MX25_OTG_SIC_SHIFT 29 238c2ecf20Sopenharmony_ci#define MX25_OTG_SIC_MASK (0x3 << MX25_OTG_SIC_SHIFT) 248c2ecf20Sopenharmony_ci#define MX25_OTG_PM_BIT BIT(24) 258c2ecf20Sopenharmony_ci#define MX25_OTG_PP_BIT BIT(11) 268c2ecf20Sopenharmony_ci#define MX25_OTG_OCPOL_BIT BIT(3) 278c2ecf20Sopenharmony_ci 288c2ecf20Sopenharmony_ci#define MX25_H1_SIC_SHIFT 21 298c2ecf20Sopenharmony_ci#define MX25_H1_SIC_MASK (0x3 << MX25_H1_SIC_SHIFT) 308c2ecf20Sopenharmony_ci#define MX25_H1_PP_BIT BIT(18) 318c2ecf20Sopenharmony_ci#define MX25_H1_PM_BIT BIT(16) 328c2ecf20Sopenharmony_ci#define MX25_H1_IPPUE_UP_BIT BIT(7) 338c2ecf20Sopenharmony_ci#define MX25_H1_IPPUE_DOWN_BIT BIT(6) 348c2ecf20Sopenharmony_ci#define MX25_H1_TLL_BIT BIT(5) 358c2ecf20Sopenharmony_ci#define MX25_H1_USBTE_BIT BIT(4) 368c2ecf20Sopenharmony_ci#define MX25_H1_OCPOL_BIT BIT(2) 378c2ecf20Sopenharmony_ci 388c2ecf20Sopenharmony_ci#define MX27_H1_PM_BIT BIT(8) 398c2ecf20Sopenharmony_ci#define MX27_H2_PM_BIT BIT(16) 408c2ecf20Sopenharmony_ci#define MX27_OTG_PM_BIT BIT(24) 418c2ecf20Sopenharmony_ci 428c2ecf20Sopenharmony_ci#define MX53_USB_OTG_PHY_CTRL_0_OFFSET 0x08 438c2ecf20Sopenharmony_ci#define MX53_USB_OTG_PHY_CTRL_1_OFFSET 0x0c 448c2ecf20Sopenharmony_ci#define MX53_USB_CTRL_1_OFFSET 0x10 458c2ecf20Sopenharmony_ci#define MX53_USB_CTRL_1_H2_XCVR_CLK_SEL_MASK (0x11 << 2) 468c2ecf20Sopenharmony_ci#define MX53_USB_CTRL_1_H2_XCVR_CLK_SEL_ULPI BIT(2) 478c2ecf20Sopenharmony_ci#define MX53_USB_CTRL_1_H3_XCVR_CLK_SEL_MASK (0x11 << 6) 488c2ecf20Sopenharmony_ci#define MX53_USB_CTRL_1_H3_XCVR_CLK_SEL_ULPI BIT(6) 498c2ecf20Sopenharmony_ci#define MX53_USB_UH2_CTRL_OFFSET 0x14 508c2ecf20Sopenharmony_ci#define MX53_USB_UH3_CTRL_OFFSET 0x18 518c2ecf20Sopenharmony_ci#define MX53_USB_CLKONOFF_CTRL_OFFSET 0x24 528c2ecf20Sopenharmony_ci#define MX53_USB_CLKONOFF_CTRL_H2_INT60CKOFF BIT(21) 538c2ecf20Sopenharmony_ci#define MX53_USB_CLKONOFF_CTRL_H3_INT60CKOFF BIT(22) 548c2ecf20Sopenharmony_ci#define MX53_BM_OVER_CUR_DIS_H1 BIT(5) 558c2ecf20Sopenharmony_ci#define MX53_BM_OVER_CUR_DIS_OTG BIT(8) 568c2ecf20Sopenharmony_ci#define MX53_BM_OVER_CUR_DIS_UHx BIT(30) 578c2ecf20Sopenharmony_ci#define MX53_USB_CTRL_1_UH2_ULPI_EN BIT(26) 588c2ecf20Sopenharmony_ci#define MX53_USB_CTRL_1_UH3_ULPI_EN BIT(27) 598c2ecf20Sopenharmony_ci#define MX53_USB_UHx_CTRL_WAKE_UP_EN BIT(7) 608c2ecf20Sopenharmony_ci#define MX53_USB_UHx_CTRL_ULPI_INT_EN BIT(8) 618c2ecf20Sopenharmony_ci#define MX53_USB_PHYCTRL1_PLLDIV_MASK 0x3 628c2ecf20Sopenharmony_ci#define MX53_USB_PLL_DIV_24_MHZ 0x01 638c2ecf20Sopenharmony_ci 648c2ecf20Sopenharmony_ci#define MX6_BM_NON_BURST_SETTING BIT(1) 658c2ecf20Sopenharmony_ci#define MX6_BM_OVER_CUR_DIS BIT(7) 668c2ecf20Sopenharmony_ci#define MX6_BM_OVER_CUR_POLARITY BIT(8) 678c2ecf20Sopenharmony_ci#define MX6_BM_PWR_POLARITY BIT(9) 688c2ecf20Sopenharmony_ci#define MX6_BM_WAKEUP_ENABLE BIT(10) 698c2ecf20Sopenharmony_ci#define MX6_BM_UTMI_ON_CLOCK BIT(13) 708c2ecf20Sopenharmony_ci#define MX6_BM_ID_WAKEUP BIT(16) 718c2ecf20Sopenharmony_ci#define MX6_BM_VBUS_WAKEUP BIT(17) 728c2ecf20Sopenharmony_ci#define MX6SX_BM_DPDM_WAKEUP_EN BIT(29) 738c2ecf20Sopenharmony_ci#define MX6_BM_WAKEUP_INTR BIT(31) 748c2ecf20Sopenharmony_ci 758c2ecf20Sopenharmony_ci#define MX6_USB_HSIC_CTRL_OFFSET 0x10 768c2ecf20Sopenharmony_ci/* Send resume signal without 480Mhz PHY clock */ 778c2ecf20Sopenharmony_ci#define MX6SX_BM_HSIC_AUTO_RESUME BIT(23) 788c2ecf20Sopenharmony_ci/* set before portsc.suspendM = 1 */ 798c2ecf20Sopenharmony_ci#define MX6_BM_HSIC_DEV_CONN BIT(21) 808c2ecf20Sopenharmony_ci/* HSIC enable */ 818c2ecf20Sopenharmony_ci#define MX6_BM_HSIC_EN BIT(12) 828c2ecf20Sopenharmony_ci/* Force HSIC module 480M clock on, even when in Host is in suspend mode */ 838c2ecf20Sopenharmony_ci#define MX6_BM_HSIC_CLK_ON BIT(11) 848c2ecf20Sopenharmony_ci 858c2ecf20Sopenharmony_ci#define MX6_USB_OTG1_PHY_CTRL 0x18 868c2ecf20Sopenharmony_ci/* For imx6dql, it is host-only controller, for later imx6, it is otg's */ 878c2ecf20Sopenharmony_ci#define MX6_USB_OTG2_PHY_CTRL 0x1c 888c2ecf20Sopenharmony_ci#define MX6SX_USB_VBUS_WAKEUP_SOURCE(v) (v << 8) 898c2ecf20Sopenharmony_ci#define MX6SX_USB_VBUS_WAKEUP_SOURCE_VBUS MX6SX_USB_VBUS_WAKEUP_SOURCE(0) 908c2ecf20Sopenharmony_ci#define MX6SX_USB_VBUS_WAKEUP_SOURCE_AVALID MX6SX_USB_VBUS_WAKEUP_SOURCE(1) 918c2ecf20Sopenharmony_ci#define MX6SX_USB_VBUS_WAKEUP_SOURCE_BVALID MX6SX_USB_VBUS_WAKEUP_SOURCE(2) 928c2ecf20Sopenharmony_ci#define MX6SX_USB_VBUS_WAKEUP_SOURCE_SESS_END MX6SX_USB_VBUS_WAKEUP_SOURCE(3) 938c2ecf20Sopenharmony_ci 948c2ecf20Sopenharmony_ci#define VF610_OVER_CUR_DIS BIT(7) 958c2ecf20Sopenharmony_ci 968c2ecf20Sopenharmony_ci#define MX7D_USBNC_USB_CTRL2 0x4 978c2ecf20Sopenharmony_ci#define MX7D_USB_VBUS_WAKEUP_SOURCE_MASK 0x3 988c2ecf20Sopenharmony_ci#define MX7D_USB_VBUS_WAKEUP_SOURCE(v) (v << 0) 998c2ecf20Sopenharmony_ci#define MX7D_USB_VBUS_WAKEUP_SOURCE_VBUS MX7D_USB_VBUS_WAKEUP_SOURCE(0) 1008c2ecf20Sopenharmony_ci#define MX7D_USB_VBUS_WAKEUP_SOURCE_AVALID MX7D_USB_VBUS_WAKEUP_SOURCE(1) 1018c2ecf20Sopenharmony_ci#define MX7D_USB_VBUS_WAKEUP_SOURCE_BVALID MX7D_USB_VBUS_WAKEUP_SOURCE(2) 1028c2ecf20Sopenharmony_ci#define MX7D_USB_VBUS_WAKEUP_SOURCE_SESS_END MX7D_USB_VBUS_WAKEUP_SOURCE(3) 1038c2ecf20Sopenharmony_ci#define MX7D_USBNC_AUTO_RESUME BIT(2) 1048c2ecf20Sopenharmony_ci/* The default DM/DP value is pull-down */ 1058c2ecf20Sopenharmony_ci#define MX7D_USBNC_USB_CTRL2_OPMODE(v) (v << 6) 1068c2ecf20Sopenharmony_ci#define MX7D_USBNC_USB_CTRL2_OPMODE_NON_DRIVING MX7D_USBNC_USB_CTRL2_OPMODE(1) 1078c2ecf20Sopenharmony_ci#define MX7D_USBNC_USB_CTRL2_OPMODE_OVERRIDE_MASK (BIT(7) | BIT(6)) 1088c2ecf20Sopenharmony_ci#define MX7D_USBNC_USB_CTRL2_OPMODE_OVERRIDE_EN BIT(8) 1098c2ecf20Sopenharmony_ci#define MX7D_USBNC_USB_CTRL2_DP_OVERRIDE_VAL BIT(12) 1108c2ecf20Sopenharmony_ci#define MX7D_USBNC_USB_CTRL2_DP_OVERRIDE_EN BIT(13) 1118c2ecf20Sopenharmony_ci#define MX7D_USBNC_USB_CTRL2_DM_OVERRIDE_VAL BIT(14) 1128c2ecf20Sopenharmony_ci#define MX7D_USBNC_USB_CTRL2_DM_OVERRIDE_EN BIT(15) 1138c2ecf20Sopenharmony_ci#define MX7D_USBNC_USB_CTRL2_DP_DM_MASK (BIT(12) | BIT(13) | \ 1148c2ecf20Sopenharmony_ci BIT(14) | BIT(15)) 1158c2ecf20Sopenharmony_ci 1168c2ecf20Sopenharmony_ci#define MX7D_USB_OTG_PHY_CFG1 0x30 1178c2ecf20Sopenharmony_ci#define MX7D_USB_OTG_PHY_CFG2_CHRG_CHRGSEL BIT(0) 1188c2ecf20Sopenharmony_ci#define MX7D_USB_OTG_PHY_CFG2_CHRG_VDATDETENB0 BIT(1) 1198c2ecf20Sopenharmony_ci#define MX7D_USB_OTG_PHY_CFG2_CHRG_VDATSRCENB0 BIT(2) 1208c2ecf20Sopenharmony_ci#define MX7D_USB_OTG_PHY_CFG2_CHRG_DCDENB BIT(3) 1218c2ecf20Sopenharmony_ci#define MX7D_USB_OTG_PHY_CFG2_DRVVBUS0 BIT(16) 1228c2ecf20Sopenharmony_ci 1238c2ecf20Sopenharmony_ci#define MX7D_USB_OTG_PHY_CFG2 0x34 1248c2ecf20Sopenharmony_ci 1258c2ecf20Sopenharmony_ci#define MX7D_USB_OTG_PHY_STATUS 0x3c 1268c2ecf20Sopenharmony_ci#define MX7D_USB_OTG_PHY_STATUS_LINE_STATE0 BIT(0) 1278c2ecf20Sopenharmony_ci#define MX7D_USB_OTG_PHY_STATUS_LINE_STATE1 BIT(1) 1288c2ecf20Sopenharmony_ci#define MX7D_USB_OTG_PHY_STATUS_VBUS_VLD BIT(3) 1298c2ecf20Sopenharmony_ci#define MX7D_USB_OTG_PHY_STATUS_CHRGDET BIT(29) 1308c2ecf20Sopenharmony_ci 1318c2ecf20Sopenharmony_ci#define MX7D_USB_OTG_PHY_CFG1 0x30 1328c2ecf20Sopenharmony_ci#define TXPREEMPAMPTUNE0_BIT 28 1338c2ecf20Sopenharmony_ci#define TXPREEMPAMPTUNE0_MASK (3 << 28) 1348c2ecf20Sopenharmony_ci#define TXVREFTUNE0_BIT 20 1358c2ecf20Sopenharmony_ci#define TXVREFTUNE0_MASK (0xf << 20) 1368c2ecf20Sopenharmony_ci 1378c2ecf20Sopenharmony_ci#define MX6_USB_OTG_WAKEUP_BITS (MX6_BM_WAKEUP_ENABLE | MX6_BM_VBUS_WAKEUP | \ 1388c2ecf20Sopenharmony_ci MX6_BM_ID_WAKEUP | MX6SX_BM_DPDM_WAKEUP_EN) 1398c2ecf20Sopenharmony_ci 1408c2ecf20Sopenharmony_cistruct usbmisc_ops { 1418c2ecf20Sopenharmony_ci /* It's called once when probe a usb device */ 1428c2ecf20Sopenharmony_ci int (*init)(struct imx_usbmisc_data *data); 1438c2ecf20Sopenharmony_ci /* It's called once after adding a usb device */ 1448c2ecf20Sopenharmony_ci int (*post)(struct imx_usbmisc_data *data); 1458c2ecf20Sopenharmony_ci /* It's called when we need to enable/disable usb wakeup */ 1468c2ecf20Sopenharmony_ci int (*set_wakeup)(struct imx_usbmisc_data *data, bool enabled); 1478c2ecf20Sopenharmony_ci /* It's called before setting portsc.suspendM */ 1488c2ecf20Sopenharmony_ci int (*hsic_set_connect)(struct imx_usbmisc_data *data); 1498c2ecf20Sopenharmony_ci /* It's called during suspend/resume */ 1508c2ecf20Sopenharmony_ci int (*hsic_set_clk)(struct imx_usbmisc_data *data, bool enabled); 1518c2ecf20Sopenharmony_ci /* usb charger detection */ 1528c2ecf20Sopenharmony_ci int (*charger_detection)(struct imx_usbmisc_data *data); 1538c2ecf20Sopenharmony_ci}; 1548c2ecf20Sopenharmony_ci 1558c2ecf20Sopenharmony_cistruct imx_usbmisc { 1568c2ecf20Sopenharmony_ci void __iomem *base; 1578c2ecf20Sopenharmony_ci spinlock_t lock; 1588c2ecf20Sopenharmony_ci const struct usbmisc_ops *ops; 1598c2ecf20Sopenharmony_ci}; 1608c2ecf20Sopenharmony_ci 1618c2ecf20Sopenharmony_cistatic inline bool is_imx53_usbmisc(struct imx_usbmisc_data *data); 1628c2ecf20Sopenharmony_ci 1638c2ecf20Sopenharmony_cistatic int usbmisc_imx25_init(struct imx_usbmisc_data *data) 1648c2ecf20Sopenharmony_ci{ 1658c2ecf20Sopenharmony_ci struct imx_usbmisc *usbmisc = dev_get_drvdata(data->dev); 1668c2ecf20Sopenharmony_ci unsigned long flags; 1678c2ecf20Sopenharmony_ci u32 val = 0; 1688c2ecf20Sopenharmony_ci 1698c2ecf20Sopenharmony_ci if (data->index > 1) 1708c2ecf20Sopenharmony_ci return -EINVAL; 1718c2ecf20Sopenharmony_ci 1728c2ecf20Sopenharmony_ci spin_lock_irqsave(&usbmisc->lock, flags); 1738c2ecf20Sopenharmony_ci switch (data->index) { 1748c2ecf20Sopenharmony_ci case 0: 1758c2ecf20Sopenharmony_ci val = readl(usbmisc->base); 1768c2ecf20Sopenharmony_ci val &= ~(MX25_OTG_SIC_MASK | MX25_OTG_PP_BIT); 1778c2ecf20Sopenharmony_ci val |= (MX25_EHCI_INTERFACE_DIFF_UNI & MX25_EHCI_INTERFACE_MASK) << MX25_OTG_SIC_SHIFT; 1788c2ecf20Sopenharmony_ci val |= (MX25_OTG_PM_BIT | MX25_OTG_OCPOL_BIT); 1798c2ecf20Sopenharmony_ci 1808c2ecf20Sopenharmony_ci /* 1818c2ecf20Sopenharmony_ci * If the polarity is not configured assume active high for 1828c2ecf20Sopenharmony_ci * historical reasons. 1838c2ecf20Sopenharmony_ci */ 1848c2ecf20Sopenharmony_ci if (data->oc_pol_configured && data->oc_pol_active_low) 1858c2ecf20Sopenharmony_ci val &= ~MX25_OTG_OCPOL_BIT; 1868c2ecf20Sopenharmony_ci 1878c2ecf20Sopenharmony_ci writel(val, usbmisc->base); 1888c2ecf20Sopenharmony_ci break; 1898c2ecf20Sopenharmony_ci case 1: 1908c2ecf20Sopenharmony_ci val = readl(usbmisc->base); 1918c2ecf20Sopenharmony_ci val &= ~(MX25_H1_SIC_MASK | MX25_H1_PP_BIT | MX25_H1_IPPUE_UP_BIT); 1928c2ecf20Sopenharmony_ci val |= (MX25_EHCI_INTERFACE_SINGLE_UNI & MX25_EHCI_INTERFACE_MASK) << MX25_H1_SIC_SHIFT; 1938c2ecf20Sopenharmony_ci val |= (MX25_H1_PM_BIT | MX25_H1_OCPOL_BIT | MX25_H1_TLL_BIT | 1948c2ecf20Sopenharmony_ci MX25_H1_USBTE_BIT | MX25_H1_IPPUE_DOWN_BIT); 1958c2ecf20Sopenharmony_ci 1968c2ecf20Sopenharmony_ci /* 1978c2ecf20Sopenharmony_ci * If the polarity is not configured assume active high for 1988c2ecf20Sopenharmony_ci * historical reasons. 1998c2ecf20Sopenharmony_ci */ 2008c2ecf20Sopenharmony_ci if (data->oc_pol_configured && data->oc_pol_active_low) 2018c2ecf20Sopenharmony_ci val &= ~MX25_H1_OCPOL_BIT; 2028c2ecf20Sopenharmony_ci 2038c2ecf20Sopenharmony_ci writel(val, usbmisc->base); 2048c2ecf20Sopenharmony_ci 2058c2ecf20Sopenharmony_ci break; 2068c2ecf20Sopenharmony_ci } 2078c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&usbmisc->lock, flags); 2088c2ecf20Sopenharmony_ci 2098c2ecf20Sopenharmony_ci return 0; 2108c2ecf20Sopenharmony_ci} 2118c2ecf20Sopenharmony_ci 2128c2ecf20Sopenharmony_cistatic int usbmisc_imx25_post(struct imx_usbmisc_data *data) 2138c2ecf20Sopenharmony_ci{ 2148c2ecf20Sopenharmony_ci struct imx_usbmisc *usbmisc = dev_get_drvdata(data->dev); 2158c2ecf20Sopenharmony_ci void __iomem *reg; 2168c2ecf20Sopenharmony_ci unsigned long flags; 2178c2ecf20Sopenharmony_ci u32 val; 2188c2ecf20Sopenharmony_ci 2198c2ecf20Sopenharmony_ci if (data->index > 2) 2208c2ecf20Sopenharmony_ci return -EINVAL; 2218c2ecf20Sopenharmony_ci 2228c2ecf20Sopenharmony_ci if (data->index) 2238c2ecf20Sopenharmony_ci return 0; 2248c2ecf20Sopenharmony_ci 2258c2ecf20Sopenharmony_ci spin_lock_irqsave(&usbmisc->lock, flags); 2268c2ecf20Sopenharmony_ci reg = usbmisc->base + MX25_USB_PHY_CTRL_OFFSET; 2278c2ecf20Sopenharmony_ci val = readl(reg); 2288c2ecf20Sopenharmony_ci 2298c2ecf20Sopenharmony_ci if (data->evdo) 2308c2ecf20Sopenharmony_ci val |= MX25_BM_EXTERNAL_VBUS_DIVIDER; 2318c2ecf20Sopenharmony_ci else 2328c2ecf20Sopenharmony_ci val &= ~MX25_BM_EXTERNAL_VBUS_DIVIDER; 2338c2ecf20Sopenharmony_ci 2348c2ecf20Sopenharmony_ci writel(val, reg); 2358c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&usbmisc->lock, flags); 2368c2ecf20Sopenharmony_ci usleep_range(5000, 10000); /* needed to stabilize voltage */ 2378c2ecf20Sopenharmony_ci 2388c2ecf20Sopenharmony_ci return 0; 2398c2ecf20Sopenharmony_ci} 2408c2ecf20Sopenharmony_ci 2418c2ecf20Sopenharmony_cistatic int usbmisc_imx27_init(struct imx_usbmisc_data *data) 2428c2ecf20Sopenharmony_ci{ 2438c2ecf20Sopenharmony_ci struct imx_usbmisc *usbmisc = dev_get_drvdata(data->dev); 2448c2ecf20Sopenharmony_ci unsigned long flags; 2458c2ecf20Sopenharmony_ci u32 val; 2468c2ecf20Sopenharmony_ci 2478c2ecf20Sopenharmony_ci switch (data->index) { 2488c2ecf20Sopenharmony_ci case 0: 2498c2ecf20Sopenharmony_ci val = MX27_OTG_PM_BIT; 2508c2ecf20Sopenharmony_ci break; 2518c2ecf20Sopenharmony_ci case 1: 2528c2ecf20Sopenharmony_ci val = MX27_H1_PM_BIT; 2538c2ecf20Sopenharmony_ci break; 2548c2ecf20Sopenharmony_ci case 2: 2558c2ecf20Sopenharmony_ci val = MX27_H2_PM_BIT; 2568c2ecf20Sopenharmony_ci break; 2578c2ecf20Sopenharmony_ci default: 2588c2ecf20Sopenharmony_ci return -EINVAL; 2598c2ecf20Sopenharmony_ci } 2608c2ecf20Sopenharmony_ci 2618c2ecf20Sopenharmony_ci spin_lock_irqsave(&usbmisc->lock, flags); 2628c2ecf20Sopenharmony_ci if (data->disable_oc) 2638c2ecf20Sopenharmony_ci val = readl(usbmisc->base) | val; 2648c2ecf20Sopenharmony_ci else 2658c2ecf20Sopenharmony_ci val = readl(usbmisc->base) & ~val; 2668c2ecf20Sopenharmony_ci writel(val, usbmisc->base); 2678c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&usbmisc->lock, flags); 2688c2ecf20Sopenharmony_ci 2698c2ecf20Sopenharmony_ci return 0; 2708c2ecf20Sopenharmony_ci} 2718c2ecf20Sopenharmony_ci 2728c2ecf20Sopenharmony_cistatic int usbmisc_imx53_init(struct imx_usbmisc_data *data) 2738c2ecf20Sopenharmony_ci{ 2748c2ecf20Sopenharmony_ci struct imx_usbmisc *usbmisc = dev_get_drvdata(data->dev); 2758c2ecf20Sopenharmony_ci void __iomem *reg = NULL; 2768c2ecf20Sopenharmony_ci unsigned long flags; 2778c2ecf20Sopenharmony_ci u32 val = 0; 2788c2ecf20Sopenharmony_ci 2798c2ecf20Sopenharmony_ci if (data->index > 3) 2808c2ecf20Sopenharmony_ci return -EINVAL; 2818c2ecf20Sopenharmony_ci 2828c2ecf20Sopenharmony_ci /* Select a 24 MHz reference clock for the PHY */ 2838c2ecf20Sopenharmony_ci val = readl(usbmisc->base + MX53_USB_OTG_PHY_CTRL_1_OFFSET); 2848c2ecf20Sopenharmony_ci val &= ~MX53_USB_PHYCTRL1_PLLDIV_MASK; 2858c2ecf20Sopenharmony_ci val |= MX53_USB_PLL_DIV_24_MHZ; 2868c2ecf20Sopenharmony_ci writel(val, usbmisc->base + MX53_USB_OTG_PHY_CTRL_1_OFFSET); 2878c2ecf20Sopenharmony_ci 2888c2ecf20Sopenharmony_ci spin_lock_irqsave(&usbmisc->lock, flags); 2898c2ecf20Sopenharmony_ci 2908c2ecf20Sopenharmony_ci switch (data->index) { 2918c2ecf20Sopenharmony_ci case 0: 2928c2ecf20Sopenharmony_ci if (data->disable_oc) { 2938c2ecf20Sopenharmony_ci reg = usbmisc->base + MX53_USB_OTG_PHY_CTRL_0_OFFSET; 2948c2ecf20Sopenharmony_ci val = readl(reg) | MX53_BM_OVER_CUR_DIS_OTG; 2958c2ecf20Sopenharmony_ci writel(val, reg); 2968c2ecf20Sopenharmony_ci } 2978c2ecf20Sopenharmony_ci break; 2988c2ecf20Sopenharmony_ci case 1: 2998c2ecf20Sopenharmony_ci if (data->disable_oc) { 3008c2ecf20Sopenharmony_ci reg = usbmisc->base + MX53_USB_OTG_PHY_CTRL_0_OFFSET; 3018c2ecf20Sopenharmony_ci val = readl(reg) | MX53_BM_OVER_CUR_DIS_H1; 3028c2ecf20Sopenharmony_ci writel(val, reg); 3038c2ecf20Sopenharmony_ci } 3048c2ecf20Sopenharmony_ci break; 3058c2ecf20Sopenharmony_ci case 2: 3068c2ecf20Sopenharmony_ci if (data->ulpi) { 3078c2ecf20Sopenharmony_ci /* set USBH2 into ULPI-mode. */ 3088c2ecf20Sopenharmony_ci reg = usbmisc->base + MX53_USB_CTRL_1_OFFSET; 3098c2ecf20Sopenharmony_ci val = readl(reg) | MX53_USB_CTRL_1_UH2_ULPI_EN; 3108c2ecf20Sopenharmony_ci /* select ULPI clock */ 3118c2ecf20Sopenharmony_ci val &= ~MX53_USB_CTRL_1_H2_XCVR_CLK_SEL_MASK; 3128c2ecf20Sopenharmony_ci val |= MX53_USB_CTRL_1_H2_XCVR_CLK_SEL_ULPI; 3138c2ecf20Sopenharmony_ci writel(val, reg); 3148c2ecf20Sopenharmony_ci /* Set interrupt wake up enable */ 3158c2ecf20Sopenharmony_ci reg = usbmisc->base + MX53_USB_UH2_CTRL_OFFSET; 3168c2ecf20Sopenharmony_ci val = readl(reg) | MX53_USB_UHx_CTRL_WAKE_UP_EN 3178c2ecf20Sopenharmony_ci | MX53_USB_UHx_CTRL_ULPI_INT_EN; 3188c2ecf20Sopenharmony_ci writel(val, reg); 3198c2ecf20Sopenharmony_ci if (is_imx53_usbmisc(data)) { 3208c2ecf20Sopenharmony_ci /* Disable internal 60Mhz clock */ 3218c2ecf20Sopenharmony_ci reg = usbmisc->base + 3228c2ecf20Sopenharmony_ci MX53_USB_CLKONOFF_CTRL_OFFSET; 3238c2ecf20Sopenharmony_ci val = readl(reg) | 3248c2ecf20Sopenharmony_ci MX53_USB_CLKONOFF_CTRL_H2_INT60CKOFF; 3258c2ecf20Sopenharmony_ci writel(val, reg); 3268c2ecf20Sopenharmony_ci } 3278c2ecf20Sopenharmony_ci 3288c2ecf20Sopenharmony_ci } 3298c2ecf20Sopenharmony_ci if (data->disable_oc) { 3308c2ecf20Sopenharmony_ci reg = usbmisc->base + MX53_USB_UH2_CTRL_OFFSET; 3318c2ecf20Sopenharmony_ci val = readl(reg) | MX53_BM_OVER_CUR_DIS_UHx; 3328c2ecf20Sopenharmony_ci writel(val, reg); 3338c2ecf20Sopenharmony_ci } 3348c2ecf20Sopenharmony_ci break; 3358c2ecf20Sopenharmony_ci case 3: 3368c2ecf20Sopenharmony_ci if (data->ulpi) { 3378c2ecf20Sopenharmony_ci /* set USBH3 into ULPI-mode. */ 3388c2ecf20Sopenharmony_ci reg = usbmisc->base + MX53_USB_CTRL_1_OFFSET; 3398c2ecf20Sopenharmony_ci val = readl(reg) | MX53_USB_CTRL_1_UH3_ULPI_EN; 3408c2ecf20Sopenharmony_ci /* select ULPI clock */ 3418c2ecf20Sopenharmony_ci val &= ~MX53_USB_CTRL_1_H3_XCVR_CLK_SEL_MASK; 3428c2ecf20Sopenharmony_ci val |= MX53_USB_CTRL_1_H3_XCVR_CLK_SEL_ULPI; 3438c2ecf20Sopenharmony_ci writel(val, reg); 3448c2ecf20Sopenharmony_ci /* Set interrupt wake up enable */ 3458c2ecf20Sopenharmony_ci reg = usbmisc->base + MX53_USB_UH3_CTRL_OFFSET; 3468c2ecf20Sopenharmony_ci val = readl(reg) | MX53_USB_UHx_CTRL_WAKE_UP_EN 3478c2ecf20Sopenharmony_ci | MX53_USB_UHx_CTRL_ULPI_INT_EN; 3488c2ecf20Sopenharmony_ci writel(val, reg); 3498c2ecf20Sopenharmony_ci 3508c2ecf20Sopenharmony_ci if (is_imx53_usbmisc(data)) { 3518c2ecf20Sopenharmony_ci /* Disable internal 60Mhz clock */ 3528c2ecf20Sopenharmony_ci reg = usbmisc->base + 3538c2ecf20Sopenharmony_ci MX53_USB_CLKONOFF_CTRL_OFFSET; 3548c2ecf20Sopenharmony_ci val = readl(reg) | 3558c2ecf20Sopenharmony_ci MX53_USB_CLKONOFF_CTRL_H3_INT60CKOFF; 3568c2ecf20Sopenharmony_ci writel(val, reg); 3578c2ecf20Sopenharmony_ci } 3588c2ecf20Sopenharmony_ci } 3598c2ecf20Sopenharmony_ci if (data->disable_oc) { 3608c2ecf20Sopenharmony_ci reg = usbmisc->base + MX53_USB_UH3_CTRL_OFFSET; 3618c2ecf20Sopenharmony_ci val = readl(reg) | MX53_BM_OVER_CUR_DIS_UHx; 3628c2ecf20Sopenharmony_ci writel(val, reg); 3638c2ecf20Sopenharmony_ci } 3648c2ecf20Sopenharmony_ci break; 3658c2ecf20Sopenharmony_ci } 3668c2ecf20Sopenharmony_ci 3678c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&usbmisc->lock, flags); 3688c2ecf20Sopenharmony_ci 3698c2ecf20Sopenharmony_ci return 0; 3708c2ecf20Sopenharmony_ci} 3718c2ecf20Sopenharmony_ci 3728c2ecf20Sopenharmony_cistatic u32 usbmisc_wakeup_setting(struct imx_usbmisc_data *data) 3738c2ecf20Sopenharmony_ci{ 3748c2ecf20Sopenharmony_ci u32 wakeup_setting = MX6_USB_OTG_WAKEUP_BITS; 3758c2ecf20Sopenharmony_ci 3768c2ecf20Sopenharmony_ci if (data->ext_id || data->available_role != USB_DR_MODE_OTG) 3778c2ecf20Sopenharmony_ci wakeup_setting &= ~MX6_BM_ID_WAKEUP; 3788c2ecf20Sopenharmony_ci 3798c2ecf20Sopenharmony_ci if (data->ext_vbus || data->available_role == USB_DR_MODE_HOST) 3808c2ecf20Sopenharmony_ci wakeup_setting &= ~MX6_BM_VBUS_WAKEUP; 3818c2ecf20Sopenharmony_ci 3828c2ecf20Sopenharmony_ci return wakeup_setting; 3838c2ecf20Sopenharmony_ci} 3848c2ecf20Sopenharmony_ci 3858c2ecf20Sopenharmony_cistatic int usbmisc_imx6q_set_wakeup 3868c2ecf20Sopenharmony_ci (struct imx_usbmisc_data *data, bool enabled) 3878c2ecf20Sopenharmony_ci{ 3888c2ecf20Sopenharmony_ci struct imx_usbmisc *usbmisc = dev_get_drvdata(data->dev); 3898c2ecf20Sopenharmony_ci unsigned long flags; 3908c2ecf20Sopenharmony_ci u32 val; 3918c2ecf20Sopenharmony_ci int ret = 0; 3928c2ecf20Sopenharmony_ci 3938c2ecf20Sopenharmony_ci if (data->index > 3) 3948c2ecf20Sopenharmony_ci return -EINVAL; 3958c2ecf20Sopenharmony_ci 3968c2ecf20Sopenharmony_ci spin_lock_irqsave(&usbmisc->lock, flags); 3978c2ecf20Sopenharmony_ci val = readl(usbmisc->base + data->index * 4); 3988c2ecf20Sopenharmony_ci if (enabled) { 3998c2ecf20Sopenharmony_ci val &= ~MX6_USB_OTG_WAKEUP_BITS; 4008c2ecf20Sopenharmony_ci val |= usbmisc_wakeup_setting(data); 4018c2ecf20Sopenharmony_ci } else { 4028c2ecf20Sopenharmony_ci if (val & MX6_BM_WAKEUP_INTR) 4038c2ecf20Sopenharmony_ci pr_debug("wakeup int at ci_hdrc.%d\n", data->index); 4048c2ecf20Sopenharmony_ci val &= ~MX6_USB_OTG_WAKEUP_BITS; 4058c2ecf20Sopenharmony_ci } 4068c2ecf20Sopenharmony_ci writel(val, usbmisc->base + data->index * 4); 4078c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&usbmisc->lock, flags); 4088c2ecf20Sopenharmony_ci 4098c2ecf20Sopenharmony_ci return ret; 4108c2ecf20Sopenharmony_ci} 4118c2ecf20Sopenharmony_ci 4128c2ecf20Sopenharmony_cistatic int usbmisc_imx6q_init(struct imx_usbmisc_data *data) 4138c2ecf20Sopenharmony_ci{ 4148c2ecf20Sopenharmony_ci struct imx_usbmisc *usbmisc = dev_get_drvdata(data->dev); 4158c2ecf20Sopenharmony_ci unsigned long flags; 4168c2ecf20Sopenharmony_ci u32 reg; 4178c2ecf20Sopenharmony_ci 4188c2ecf20Sopenharmony_ci if (data->index > 3) 4198c2ecf20Sopenharmony_ci return -EINVAL; 4208c2ecf20Sopenharmony_ci 4218c2ecf20Sopenharmony_ci spin_lock_irqsave(&usbmisc->lock, flags); 4228c2ecf20Sopenharmony_ci 4238c2ecf20Sopenharmony_ci reg = readl(usbmisc->base + data->index * 4); 4248c2ecf20Sopenharmony_ci if (data->disable_oc) { 4258c2ecf20Sopenharmony_ci reg |= MX6_BM_OVER_CUR_DIS; 4268c2ecf20Sopenharmony_ci } else { 4278c2ecf20Sopenharmony_ci reg &= ~MX6_BM_OVER_CUR_DIS; 4288c2ecf20Sopenharmony_ci 4298c2ecf20Sopenharmony_ci /* 4308c2ecf20Sopenharmony_ci * If the polarity is not configured keep it as setup by the 4318c2ecf20Sopenharmony_ci * bootloader. 4328c2ecf20Sopenharmony_ci */ 4338c2ecf20Sopenharmony_ci if (data->oc_pol_configured && data->oc_pol_active_low) 4348c2ecf20Sopenharmony_ci reg |= MX6_BM_OVER_CUR_POLARITY; 4358c2ecf20Sopenharmony_ci else if (data->oc_pol_configured) 4368c2ecf20Sopenharmony_ci reg &= ~MX6_BM_OVER_CUR_POLARITY; 4378c2ecf20Sopenharmony_ci } 4388c2ecf20Sopenharmony_ci /* If the polarity is not set keep it as setup by the bootlader */ 4398c2ecf20Sopenharmony_ci if (data->pwr_pol == 1) 4408c2ecf20Sopenharmony_ci reg |= MX6_BM_PWR_POLARITY; 4418c2ecf20Sopenharmony_ci writel(reg, usbmisc->base + data->index * 4); 4428c2ecf20Sopenharmony_ci 4438c2ecf20Sopenharmony_ci /* SoC non-burst setting */ 4448c2ecf20Sopenharmony_ci reg = readl(usbmisc->base + data->index * 4); 4458c2ecf20Sopenharmony_ci writel(reg | MX6_BM_NON_BURST_SETTING, 4468c2ecf20Sopenharmony_ci usbmisc->base + data->index * 4); 4478c2ecf20Sopenharmony_ci 4488c2ecf20Sopenharmony_ci /* For HSIC controller */ 4498c2ecf20Sopenharmony_ci if (data->hsic) { 4508c2ecf20Sopenharmony_ci reg = readl(usbmisc->base + data->index * 4); 4518c2ecf20Sopenharmony_ci writel(reg | MX6_BM_UTMI_ON_CLOCK, 4528c2ecf20Sopenharmony_ci usbmisc->base + data->index * 4); 4538c2ecf20Sopenharmony_ci reg = readl(usbmisc->base + MX6_USB_HSIC_CTRL_OFFSET 4548c2ecf20Sopenharmony_ci + (data->index - 2) * 4); 4558c2ecf20Sopenharmony_ci reg |= MX6_BM_HSIC_EN | MX6_BM_HSIC_CLK_ON; 4568c2ecf20Sopenharmony_ci writel(reg, usbmisc->base + MX6_USB_HSIC_CTRL_OFFSET 4578c2ecf20Sopenharmony_ci + (data->index - 2) * 4); 4588c2ecf20Sopenharmony_ci } 4598c2ecf20Sopenharmony_ci 4608c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&usbmisc->lock, flags); 4618c2ecf20Sopenharmony_ci 4628c2ecf20Sopenharmony_ci usbmisc_imx6q_set_wakeup(data, false); 4638c2ecf20Sopenharmony_ci 4648c2ecf20Sopenharmony_ci return 0; 4658c2ecf20Sopenharmony_ci} 4668c2ecf20Sopenharmony_ci 4678c2ecf20Sopenharmony_cistatic int usbmisc_imx6_hsic_get_reg_offset(struct imx_usbmisc_data *data) 4688c2ecf20Sopenharmony_ci{ 4698c2ecf20Sopenharmony_ci int offset, ret = 0; 4708c2ecf20Sopenharmony_ci 4718c2ecf20Sopenharmony_ci if (data->index == 2 || data->index == 3) { 4728c2ecf20Sopenharmony_ci offset = (data->index - 2) * 4; 4738c2ecf20Sopenharmony_ci } else if (data->index == 0) { 4748c2ecf20Sopenharmony_ci /* 4758c2ecf20Sopenharmony_ci * For SoCs like i.MX7D and later, each USB controller has 4768c2ecf20Sopenharmony_ci * its own non-core register region. For SoCs before i.MX7D, 4778c2ecf20Sopenharmony_ci * the first two USB controllers are non-HSIC controllers. 4788c2ecf20Sopenharmony_ci */ 4798c2ecf20Sopenharmony_ci offset = 0; 4808c2ecf20Sopenharmony_ci } else { 4818c2ecf20Sopenharmony_ci dev_err(data->dev, "index is error for usbmisc\n"); 4828c2ecf20Sopenharmony_ci ret = -EINVAL; 4838c2ecf20Sopenharmony_ci } 4848c2ecf20Sopenharmony_ci 4858c2ecf20Sopenharmony_ci return ret ? ret : offset; 4868c2ecf20Sopenharmony_ci} 4878c2ecf20Sopenharmony_ci 4888c2ecf20Sopenharmony_cistatic int usbmisc_imx6_hsic_set_connect(struct imx_usbmisc_data *data) 4898c2ecf20Sopenharmony_ci{ 4908c2ecf20Sopenharmony_ci unsigned long flags; 4918c2ecf20Sopenharmony_ci u32 val; 4928c2ecf20Sopenharmony_ci struct imx_usbmisc *usbmisc = dev_get_drvdata(data->dev); 4938c2ecf20Sopenharmony_ci int offset; 4948c2ecf20Sopenharmony_ci 4958c2ecf20Sopenharmony_ci spin_lock_irqsave(&usbmisc->lock, flags); 4968c2ecf20Sopenharmony_ci offset = usbmisc_imx6_hsic_get_reg_offset(data); 4978c2ecf20Sopenharmony_ci if (offset < 0) { 4988c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&usbmisc->lock, flags); 4998c2ecf20Sopenharmony_ci return offset; 5008c2ecf20Sopenharmony_ci } 5018c2ecf20Sopenharmony_ci 5028c2ecf20Sopenharmony_ci val = readl(usbmisc->base + MX6_USB_HSIC_CTRL_OFFSET + offset); 5038c2ecf20Sopenharmony_ci if (!(val & MX6_BM_HSIC_DEV_CONN)) 5048c2ecf20Sopenharmony_ci writel(val | MX6_BM_HSIC_DEV_CONN, 5058c2ecf20Sopenharmony_ci usbmisc->base + MX6_USB_HSIC_CTRL_OFFSET + offset); 5068c2ecf20Sopenharmony_ci 5078c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&usbmisc->lock, flags); 5088c2ecf20Sopenharmony_ci 5098c2ecf20Sopenharmony_ci return 0; 5108c2ecf20Sopenharmony_ci} 5118c2ecf20Sopenharmony_ci 5128c2ecf20Sopenharmony_cistatic int usbmisc_imx6_hsic_set_clk(struct imx_usbmisc_data *data, bool on) 5138c2ecf20Sopenharmony_ci{ 5148c2ecf20Sopenharmony_ci unsigned long flags; 5158c2ecf20Sopenharmony_ci u32 val; 5168c2ecf20Sopenharmony_ci struct imx_usbmisc *usbmisc = dev_get_drvdata(data->dev); 5178c2ecf20Sopenharmony_ci int offset; 5188c2ecf20Sopenharmony_ci 5198c2ecf20Sopenharmony_ci spin_lock_irqsave(&usbmisc->lock, flags); 5208c2ecf20Sopenharmony_ci offset = usbmisc_imx6_hsic_get_reg_offset(data); 5218c2ecf20Sopenharmony_ci if (offset < 0) { 5228c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&usbmisc->lock, flags); 5238c2ecf20Sopenharmony_ci return offset; 5248c2ecf20Sopenharmony_ci } 5258c2ecf20Sopenharmony_ci 5268c2ecf20Sopenharmony_ci val = readl(usbmisc->base + MX6_USB_HSIC_CTRL_OFFSET + offset); 5278c2ecf20Sopenharmony_ci val |= MX6_BM_HSIC_EN | MX6_BM_HSIC_CLK_ON; 5288c2ecf20Sopenharmony_ci if (on) 5298c2ecf20Sopenharmony_ci val |= MX6_BM_HSIC_CLK_ON; 5308c2ecf20Sopenharmony_ci else 5318c2ecf20Sopenharmony_ci val &= ~MX6_BM_HSIC_CLK_ON; 5328c2ecf20Sopenharmony_ci 5338c2ecf20Sopenharmony_ci writel(val, usbmisc->base + MX6_USB_HSIC_CTRL_OFFSET + offset); 5348c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&usbmisc->lock, flags); 5358c2ecf20Sopenharmony_ci 5368c2ecf20Sopenharmony_ci return 0; 5378c2ecf20Sopenharmony_ci} 5388c2ecf20Sopenharmony_ci 5398c2ecf20Sopenharmony_ci 5408c2ecf20Sopenharmony_cistatic int usbmisc_imx6sx_init(struct imx_usbmisc_data *data) 5418c2ecf20Sopenharmony_ci{ 5428c2ecf20Sopenharmony_ci void __iomem *reg = NULL; 5438c2ecf20Sopenharmony_ci unsigned long flags; 5448c2ecf20Sopenharmony_ci struct imx_usbmisc *usbmisc = dev_get_drvdata(data->dev); 5458c2ecf20Sopenharmony_ci u32 val; 5468c2ecf20Sopenharmony_ci 5478c2ecf20Sopenharmony_ci usbmisc_imx6q_init(data); 5488c2ecf20Sopenharmony_ci 5498c2ecf20Sopenharmony_ci if (data->index == 0 || data->index == 1) { 5508c2ecf20Sopenharmony_ci reg = usbmisc->base + MX6_USB_OTG1_PHY_CTRL + data->index * 4; 5518c2ecf20Sopenharmony_ci spin_lock_irqsave(&usbmisc->lock, flags); 5528c2ecf20Sopenharmony_ci /* Set vbus wakeup source as bvalid */ 5538c2ecf20Sopenharmony_ci val = readl(reg); 5548c2ecf20Sopenharmony_ci writel(val | MX6SX_USB_VBUS_WAKEUP_SOURCE_BVALID, reg); 5558c2ecf20Sopenharmony_ci /* 5568c2ecf20Sopenharmony_ci * Disable dp/dm wakeup in device mode when vbus is 5578c2ecf20Sopenharmony_ci * not there. 5588c2ecf20Sopenharmony_ci */ 5598c2ecf20Sopenharmony_ci val = readl(usbmisc->base + data->index * 4); 5608c2ecf20Sopenharmony_ci writel(val & ~MX6SX_BM_DPDM_WAKEUP_EN, 5618c2ecf20Sopenharmony_ci usbmisc->base + data->index * 4); 5628c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&usbmisc->lock, flags); 5638c2ecf20Sopenharmony_ci } 5648c2ecf20Sopenharmony_ci 5658c2ecf20Sopenharmony_ci /* For HSIC controller */ 5668c2ecf20Sopenharmony_ci if (data->hsic) { 5678c2ecf20Sopenharmony_ci val = readl(usbmisc->base + MX6_USB_HSIC_CTRL_OFFSET); 5688c2ecf20Sopenharmony_ci val |= MX6SX_BM_HSIC_AUTO_RESUME; 5698c2ecf20Sopenharmony_ci writel(val, usbmisc->base + MX6_USB_HSIC_CTRL_OFFSET); 5708c2ecf20Sopenharmony_ci } 5718c2ecf20Sopenharmony_ci 5728c2ecf20Sopenharmony_ci return 0; 5738c2ecf20Sopenharmony_ci} 5748c2ecf20Sopenharmony_ci 5758c2ecf20Sopenharmony_cistatic int usbmisc_vf610_init(struct imx_usbmisc_data *data) 5768c2ecf20Sopenharmony_ci{ 5778c2ecf20Sopenharmony_ci struct imx_usbmisc *usbmisc = dev_get_drvdata(data->dev); 5788c2ecf20Sopenharmony_ci u32 reg; 5798c2ecf20Sopenharmony_ci 5808c2ecf20Sopenharmony_ci /* 5818c2ecf20Sopenharmony_ci * Vybrid only has one misc register set, but in two different 5828c2ecf20Sopenharmony_ci * areas. These is reflected in two instances of this driver. 5838c2ecf20Sopenharmony_ci */ 5848c2ecf20Sopenharmony_ci if (data->index >= 1) 5858c2ecf20Sopenharmony_ci return -EINVAL; 5868c2ecf20Sopenharmony_ci 5878c2ecf20Sopenharmony_ci if (data->disable_oc) { 5888c2ecf20Sopenharmony_ci reg = readl(usbmisc->base); 5898c2ecf20Sopenharmony_ci writel(reg | VF610_OVER_CUR_DIS, usbmisc->base); 5908c2ecf20Sopenharmony_ci } 5918c2ecf20Sopenharmony_ci 5928c2ecf20Sopenharmony_ci return 0; 5938c2ecf20Sopenharmony_ci} 5948c2ecf20Sopenharmony_ci 5958c2ecf20Sopenharmony_cistatic int usbmisc_imx7d_set_wakeup 5968c2ecf20Sopenharmony_ci (struct imx_usbmisc_data *data, bool enabled) 5978c2ecf20Sopenharmony_ci{ 5988c2ecf20Sopenharmony_ci struct imx_usbmisc *usbmisc = dev_get_drvdata(data->dev); 5998c2ecf20Sopenharmony_ci unsigned long flags; 6008c2ecf20Sopenharmony_ci u32 val; 6018c2ecf20Sopenharmony_ci 6028c2ecf20Sopenharmony_ci spin_lock_irqsave(&usbmisc->lock, flags); 6038c2ecf20Sopenharmony_ci val = readl(usbmisc->base); 6048c2ecf20Sopenharmony_ci if (enabled) { 6058c2ecf20Sopenharmony_ci val &= ~MX6_USB_OTG_WAKEUP_BITS; 6068c2ecf20Sopenharmony_ci val |= usbmisc_wakeup_setting(data); 6078c2ecf20Sopenharmony_ci writel(val, usbmisc->base); 6088c2ecf20Sopenharmony_ci } else { 6098c2ecf20Sopenharmony_ci if (val & MX6_BM_WAKEUP_INTR) 6108c2ecf20Sopenharmony_ci dev_dbg(data->dev, "wakeup int\n"); 6118c2ecf20Sopenharmony_ci writel(val & ~MX6_USB_OTG_WAKEUP_BITS, usbmisc->base); 6128c2ecf20Sopenharmony_ci } 6138c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&usbmisc->lock, flags); 6148c2ecf20Sopenharmony_ci 6158c2ecf20Sopenharmony_ci return 0; 6168c2ecf20Sopenharmony_ci} 6178c2ecf20Sopenharmony_ci 6188c2ecf20Sopenharmony_cistatic int usbmisc_imx7d_init(struct imx_usbmisc_data *data) 6198c2ecf20Sopenharmony_ci{ 6208c2ecf20Sopenharmony_ci struct imx_usbmisc *usbmisc = dev_get_drvdata(data->dev); 6218c2ecf20Sopenharmony_ci unsigned long flags; 6228c2ecf20Sopenharmony_ci u32 reg; 6238c2ecf20Sopenharmony_ci 6248c2ecf20Sopenharmony_ci if (data->index >= 1) 6258c2ecf20Sopenharmony_ci return -EINVAL; 6268c2ecf20Sopenharmony_ci 6278c2ecf20Sopenharmony_ci spin_lock_irqsave(&usbmisc->lock, flags); 6288c2ecf20Sopenharmony_ci reg = readl(usbmisc->base); 6298c2ecf20Sopenharmony_ci if (data->disable_oc) { 6308c2ecf20Sopenharmony_ci reg |= MX6_BM_OVER_CUR_DIS; 6318c2ecf20Sopenharmony_ci } else { 6328c2ecf20Sopenharmony_ci reg &= ~MX6_BM_OVER_CUR_DIS; 6338c2ecf20Sopenharmony_ci 6348c2ecf20Sopenharmony_ci /* 6358c2ecf20Sopenharmony_ci * If the polarity is not configured keep it as setup by the 6368c2ecf20Sopenharmony_ci * bootloader. 6378c2ecf20Sopenharmony_ci */ 6388c2ecf20Sopenharmony_ci if (data->oc_pol_configured && data->oc_pol_active_low) 6398c2ecf20Sopenharmony_ci reg |= MX6_BM_OVER_CUR_POLARITY; 6408c2ecf20Sopenharmony_ci else if (data->oc_pol_configured) 6418c2ecf20Sopenharmony_ci reg &= ~MX6_BM_OVER_CUR_POLARITY; 6428c2ecf20Sopenharmony_ci } 6438c2ecf20Sopenharmony_ci /* If the polarity is not set keep it as setup by the bootlader */ 6448c2ecf20Sopenharmony_ci if (data->pwr_pol == 1) 6458c2ecf20Sopenharmony_ci reg |= MX6_BM_PWR_POLARITY; 6468c2ecf20Sopenharmony_ci writel(reg, usbmisc->base); 6478c2ecf20Sopenharmony_ci 6488c2ecf20Sopenharmony_ci /* SoC non-burst setting */ 6498c2ecf20Sopenharmony_ci reg = readl(usbmisc->base); 6508c2ecf20Sopenharmony_ci writel(reg | MX6_BM_NON_BURST_SETTING, usbmisc->base); 6518c2ecf20Sopenharmony_ci 6528c2ecf20Sopenharmony_ci if (!data->hsic) { 6538c2ecf20Sopenharmony_ci reg = readl(usbmisc->base + MX7D_USBNC_USB_CTRL2); 6548c2ecf20Sopenharmony_ci reg &= ~MX7D_USB_VBUS_WAKEUP_SOURCE_MASK; 6558c2ecf20Sopenharmony_ci writel(reg | MX7D_USB_VBUS_WAKEUP_SOURCE_BVALID 6568c2ecf20Sopenharmony_ci | MX7D_USBNC_AUTO_RESUME, 6578c2ecf20Sopenharmony_ci usbmisc->base + MX7D_USBNC_USB_CTRL2); 6588c2ecf20Sopenharmony_ci /* PHY tuning for signal quality */ 6598c2ecf20Sopenharmony_ci reg = readl(usbmisc->base + MX7D_USB_OTG_PHY_CFG1); 6608c2ecf20Sopenharmony_ci if (data->emp_curr_control >= 0 && 6618c2ecf20Sopenharmony_ci data->emp_curr_control <= 6628c2ecf20Sopenharmony_ci (TXPREEMPAMPTUNE0_MASK >> TXPREEMPAMPTUNE0_BIT)) { 6638c2ecf20Sopenharmony_ci reg &= ~TXPREEMPAMPTUNE0_MASK; 6648c2ecf20Sopenharmony_ci reg |= (data->emp_curr_control << TXPREEMPAMPTUNE0_BIT); 6658c2ecf20Sopenharmony_ci } 6668c2ecf20Sopenharmony_ci 6678c2ecf20Sopenharmony_ci if (data->dc_vol_level_adjust >= 0 && 6688c2ecf20Sopenharmony_ci data->dc_vol_level_adjust <= 6698c2ecf20Sopenharmony_ci (TXVREFTUNE0_MASK >> TXVREFTUNE0_BIT)) { 6708c2ecf20Sopenharmony_ci reg &= ~TXVREFTUNE0_MASK; 6718c2ecf20Sopenharmony_ci reg |= (data->dc_vol_level_adjust << TXVREFTUNE0_BIT); 6728c2ecf20Sopenharmony_ci } 6738c2ecf20Sopenharmony_ci 6748c2ecf20Sopenharmony_ci writel(reg, usbmisc->base + MX7D_USB_OTG_PHY_CFG1); 6758c2ecf20Sopenharmony_ci } 6768c2ecf20Sopenharmony_ci 6778c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&usbmisc->lock, flags); 6788c2ecf20Sopenharmony_ci 6798c2ecf20Sopenharmony_ci usbmisc_imx7d_set_wakeup(data, false); 6808c2ecf20Sopenharmony_ci 6818c2ecf20Sopenharmony_ci return 0; 6828c2ecf20Sopenharmony_ci} 6838c2ecf20Sopenharmony_ci 6848c2ecf20Sopenharmony_cistatic int imx7d_charger_secondary_detection(struct imx_usbmisc_data *data) 6858c2ecf20Sopenharmony_ci{ 6868c2ecf20Sopenharmony_ci struct imx_usbmisc *usbmisc = dev_get_drvdata(data->dev); 6878c2ecf20Sopenharmony_ci struct usb_phy *usb_phy = data->usb_phy; 6888c2ecf20Sopenharmony_ci int val; 6898c2ecf20Sopenharmony_ci unsigned long flags; 6908c2ecf20Sopenharmony_ci 6918c2ecf20Sopenharmony_ci /* Clear VDATSRCENB0 to disable VDP_SRC and IDM_SNK required by BC 1.2 spec */ 6928c2ecf20Sopenharmony_ci spin_lock_irqsave(&usbmisc->lock, flags); 6938c2ecf20Sopenharmony_ci val = readl(usbmisc->base + MX7D_USB_OTG_PHY_CFG2); 6948c2ecf20Sopenharmony_ci val &= ~MX7D_USB_OTG_PHY_CFG2_CHRG_VDATSRCENB0; 6958c2ecf20Sopenharmony_ci writel(val, usbmisc->base + MX7D_USB_OTG_PHY_CFG2); 6968c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&usbmisc->lock, flags); 6978c2ecf20Sopenharmony_ci 6988c2ecf20Sopenharmony_ci /* TVDMSRC_DIS */ 6998c2ecf20Sopenharmony_ci msleep(20); 7008c2ecf20Sopenharmony_ci 7018c2ecf20Sopenharmony_ci /* VDM_SRC is connected to D- and IDP_SINK is connected to D+ */ 7028c2ecf20Sopenharmony_ci spin_lock_irqsave(&usbmisc->lock, flags); 7038c2ecf20Sopenharmony_ci val = readl(usbmisc->base + MX7D_USB_OTG_PHY_CFG2); 7048c2ecf20Sopenharmony_ci writel(val | MX7D_USB_OTG_PHY_CFG2_CHRG_VDATSRCENB0 | 7058c2ecf20Sopenharmony_ci MX7D_USB_OTG_PHY_CFG2_CHRG_VDATDETENB0 | 7068c2ecf20Sopenharmony_ci MX7D_USB_OTG_PHY_CFG2_CHRG_CHRGSEL, 7078c2ecf20Sopenharmony_ci usbmisc->base + MX7D_USB_OTG_PHY_CFG2); 7088c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&usbmisc->lock, flags); 7098c2ecf20Sopenharmony_ci 7108c2ecf20Sopenharmony_ci /* TVDMSRC_ON */ 7118c2ecf20Sopenharmony_ci msleep(40); 7128c2ecf20Sopenharmony_ci 7138c2ecf20Sopenharmony_ci /* 7148c2ecf20Sopenharmony_ci * Per BC 1.2, check voltage of D+: 7158c2ecf20Sopenharmony_ci * DCP: if greater than VDAT_REF; 7168c2ecf20Sopenharmony_ci * CDP: if less than VDAT_REF. 7178c2ecf20Sopenharmony_ci */ 7188c2ecf20Sopenharmony_ci val = readl(usbmisc->base + MX7D_USB_OTG_PHY_STATUS); 7198c2ecf20Sopenharmony_ci if (val & MX7D_USB_OTG_PHY_STATUS_CHRGDET) { 7208c2ecf20Sopenharmony_ci dev_dbg(data->dev, "It is a dedicate charging port\n"); 7218c2ecf20Sopenharmony_ci usb_phy->chg_type = DCP_TYPE; 7228c2ecf20Sopenharmony_ci } else { 7238c2ecf20Sopenharmony_ci dev_dbg(data->dev, "It is a charging downstream port\n"); 7248c2ecf20Sopenharmony_ci usb_phy->chg_type = CDP_TYPE; 7258c2ecf20Sopenharmony_ci } 7268c2ecf20Sopenharmony_ci 7278c2ecf20Sopenharmony_ci return 0; 7288c2ecf20Sopenharmony_ci} 7298c2ecf20Sopenharmony_ci 7308c2ecf20Sopenharmony_cistatic void imx7_disable_charger_detector(struct imx_usbmisc_data *data) 7318c2ecf20Sopenharmony_ci{ 7328c2ecf20Sopenharmony_ci struct imx_usbmisc *usbmisc = dev_get_drvdata(data->dev); 7338c2ecf20Sopenharmony_ci unsigned long flags; 7348c2ecf20Sopenharmony_ci u32 val; 7358c2ecf20Sopenharmony_ci 7368c2ecf20Sopenharmony_ci spin_lock_irqsave(&usbmisc->lock, flags); 7378c2ecf20Sopenharmony_ci val = readl(usbmisc->base + MX7D_USB_OTG_PHY_CFG2); 7388c2ecf20Sopenharmony_ci val &= ~(MX7D_USB_OTG_PHY_CFG2_CHRG_DCDENB | 7398c2ecf20Sopenharmony_ci MX7D_USB_OTG_PHY_CFG2_CHRG_VDATSRCENB0 | 7408c2ecf20Sopenharmony_ci MX7D_USB_OTG_PHY_CFG2_CHRG_VDATDETENB0 | 7418c2ecf20Sopenharmony_ci MX7D_USB_OTG_PHY_CFG2_CHRG_CHRGSEL); 7428c2ecf20Sopenharmony_ci writel(val, usbmisc->base + MX7D_USB_OTG_PHY_CFG2); 7438c2ecf20Sopenharmony_ci 7448c2ecf20Sopenharmony_ci /* Set OPMODE to be 2'b00 and disable its override */ 7458c2ecf20Sopenharmony_ci val = readl(usbmisc->base + MX7D_USBNC_USB_CTRL2); 7468c2ecf20Sopenharmony_ci val &= ~MX7D_USBNC_USB_CTRL2_OPMODE_OVERRIDE_MASK; 7478c2ecf20Sopenharmony_ci writel(val, usbmisc->base + MX7D_USBNC_USB_CTRL2); 7488c2ecf20Sopenharmony_ci 7498c2ecf20Sopenharmony_ci val = readl(usbmisc->base + MX7D_USBNC_USB_CTRL2); 7508c2ecf20Sopenharmony_ci writel(val & ~MX7D_USBNC_USB_CTRL2_OPMODE_OVERRIDE_EN, 7518c2ecf20Sopenharmony_ci usbmisc->base + MX7D_USBNC_USB_CTRL2); 7528c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&usbmisc->lock, flags); 7538c2ecf20Sopenharmony_ci} 7548c2ecf20Sopenharmony_ci 7558c2ecf20Sopenharmony_cistatic int imx7d_charger_data_contact_detect(struct imx_usbmisc_data *data) 7568c2ecf20Sopenharmony_ci{ 7578c2ecf20Sopenharmony_ci struct imx_usbmisc *usbmisc = dev_get_drvdata(data->dev); 7588c2ecf20Sopenharmony_ci unsigned long flags; 7598c2ecf20Sopenharmony_ci u32 val; 7608c2ecf20Sopenharmony_ci int i, data_pin_contact_count = 0; 7618c2ecf20Sopenharmony_ci 7628c2ecf20Sopenharmony_ci /* Enable Data Contact Detect (DCD) per the USB BC 1.2 */ 7638c2ecf20Sopenharmony_ci spin_lock_irqsave(&usbmisc->lock, flags); 7648c2ecf20Sopenharmony_ci val = readl(usbmisc->base + MX7D_USB_OTG_PHY_CFG2); 7658c2ecf20Sopenharmony_ci writel(val | MX7D_USB_OTG_PHY_CFG2_CHRG_DCDENB, 7668c2ecf20Sopenharmony_ci usbmisc->base + MX7D_USB_OTG_PHY_CFG2); 7678c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&usbmisc->lock, flags); 7688c2ecf20Sopenharmony_ci 7698c2ecf20Sopenharmony_ci for (i = 0; i < 100; i = i + 1) { 7708c2ecf20Sopenharmony_ci val = readl(usbmisc->base + MX7D_USB_OTG_PHY_STATUS); 7718c2ecf20Sopenharmony_ci if (!(val & MX7D_USB_OTG_PHY_STATUS_LINE_STATE0)) { 7728c2ecf20Sopenharmony_ci if (data_pin_contact_count++ > 5) 7738c2ecf20Sopenharmony_ci /* Data pin makes contact */ 7748c2ecf20Sopenharmony_ci break; 7758c2ecf20Sopenharmony_ci usleep_range(5000, 10000); 7768c2ecf20Sopenharmony_ci } else { 7778c2ecf20Sopenharmony_ci data_pin_contact_count = 0; 7788c2ecf20Sopenharmony_ci usleep_range(5000, 6000); 7798c2ecf20Sopenharmony_ci } 7808c2ecf20Sopenharmony_ci } 7818c2ecf20Sopenharmony_ci 7828c2ecf20Sopenharmony_ci /* Disable DCD after finished data contact check */ 7838c2ecf20Sopenharmony_ci spin_lock_irqsave(&usbmisc->lock, flags); 7848c2ecf20Sopenharmony_ci val = readl(usbmisc->base + MX7D_USB_OTG_PHY_CFG2); 7858c2ecf20Sopenharmony_ci writel(val & ~MX7D_USB_OTG_PHY_CFG2_CHRG_DCDENB, 7868c2ecf20Sopenharmony_ci usbmisc->base + MX7D_USB_OTG_PHY_CFG2); 7878c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&usbmisc->lock, flags); 7888c2ecf20Sopenharmony_ci 7898c2ecf20Sopenharmony_ci if (i == 100) { 7908c2ecf20Sopenharmony_ci dev_err(data->dev, 7918c2ecf20Sopenharmony_ci "VBUS is coming from a dedicated power supply.\n"); 7928c2ecf20Sopenharmony_ci return -ENXIO; 7938c2ecf20Sopenharmony_ci } 7948c2ecf20Sopenharmony_ci 7958c2ecf20Sopenharmony_ci return 0; 7968c2ecf20Sopenharmony_ci} 7978c2ecf20Sopenharmony_ci 7988c2ecf20Sopenharmony_cistatic int imx7d_charger_primary_detection(struct imx_usbmisc_data *data) 7998c2ecf20Sopenharmony_ci{ 8008c2ecf20Sopenharmony_ci struct imx_usbmisc *usbmisc = dev_get_drvdata(data->dev); 8018c2ecf20Sopenharmony_ci struct usb_phy *usb_phy = data->usb_phy; 8028c2ecf20Sopenharmony_ci unsigned long flags; 8038c2ecf20Sopenharmony_ci u32 val; 8048c2ecf20Sopenharmony_ci 8058c2ecf20Sopenharmony_ci /* VDP_SRC is connected to D+ and IDM_SINK is connected to D- */ 8068c2ecf20Sopenharmony_ci spin_lock_irqsave(&usbmisc->lock, flags); 8078c2ecf20Sopenharmony_ci val = readl(usbmisc->base + MX7D_USB_OTG_PHY_CFG2); 8088c2ecf20Sopenharmony_ci val &= ~MX7D_USB_OTG_PHY_CFG2_CHRG_CHRGSEL; 8098c2ecf20Sopenharmony_ci writel(val | MX7D_USB_OTG_PHY_CFG2_CHRG_VDATSRCENB0 | 8108c2ecf20Sopenharmony_ci MX7D_USB_OTG_PHY_CFG2_CHRG_VDATDETENB0, 8118c2ecf20Sopenharmony_ci usbmisc->base + MX7D_USB_OTG_PHY_CFG2); 8128c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&usbmisc->lock, flags); 8138c2ecf20Sopenharmony_ci 8148c2ecf20Sopenharmony_ci /* TVDPSRC_ON */ 8158c2ecf20Sopenharmony_ci msleep(40); 8168c2ecf20Sopenharmony_ci 8178c2ecf20Sopenharmony_ci /* Check if D- is less than VDAT_REF to determine an SDP per BC 1.2 */ 8188c2ecf20Sopenharmony_ci val = readl(usbmisc->base + MX7D_USB_OTG_PHY_STATUS); 8198c2ecf20Sopenharmony_ci if (!(val & MX7D_USB_OTG_PHY_STATUS_CHRGDET)) { 8208c2ecf20Sopenharmony_ci dev_dbg(data->dev, "It is a standard downstream port\n"); 8218c2ecf20Sopenharmony_ci usb_phy->chg_type = SDP_TYPE; 8228c2ecf20Sopenharmony_ci } 8238c2ecf20Sopenharmony_ci 8248c2ecf20Sopenharmony_ci return 0; 8258c2ecf20Sopenharmony_ci} 8268c2ecf20Sopenharmony_ci 8278c2ecf20Sopenharmony_ci/* 8288c2ecf20Sopenharmony_ci * Whole charger detection process: 8298c2ecf20Sopenharmony_ci * 1. OPMODE override to be non-driving 8308c2ecf20Sopenharmony_ci * 2. Data contact check 8318c2ecf20Sopenharmony_ci * 3. Primary detection 8328c2ecf20Sopenharmony_ci * 4. Secondary detection 8338c2ecf20Sopenharmony_ci * 5. Disable charger detection 8348c2ecf20Sopenharmony_ci */ 8358c2ecf20Sopenharmony_cistatic int imx7d_charger_detection(struct imx_usbmisc_data *data) 8368c2ecf20Sopenharmony_ci{ 8378c2ecf20Sopenharmony_ci struct imx_usbmisc *usbmisc = dev_get_drvdata(data->dev); 8388c2ecf20Sopenharmony_ci struct usb_phy *usb_phy = data->usb_phy; 8398c2ecf20Sopenharmony_ci unsigned long flags; 8408c2ecf20Sopenharmony_ci u32 val; 8418c2ecf20Sopenharmony_ci int ret; 8428c2ecf20Sopenharmony_ci 8438c2ecf20Sopenharmony_ci /* Check if vbus is valid */ 8448c2ecf20Sopenharmony_ci val = readl(usbmisc->base + MX7D_USB_OTG_PHY_STATUS); 8458c2ecf20Sopenharmony_ci if (!(val & MX7D_USB_OTG_PHY_STATUS_VBUS_VLD)) { 8468c2ecf20Sopenharmony_ci dev_err(data->dev, "vbus is error\n"); 8478c2ecf20Sopenharmony_ci return -EINVAL; 8488c2ecf20Sopenharmony_ci } 8498c2ecf20Sopenharmony_ci 8508c2ecf20Sopenharmony_ci /* 8518c2ecf20Sopenharmony_ci * Keep OPMODE to be non-driving mode during the whole 8528c2ecf20Sopenharmony_ci * charger detection process. 8538c2ecf20Sopenharmony_ci */ 8548c2ecf20Sopenharmony_ci spin_lock_irqsave(&usbmisc->lock, flags); 8558c2ecf20Sopenharmony_ci val = readl(usbmisc->base + MX7D_USBNC_USB_CTRL2); 8568c2ecf20Sopenharmony_ci val &= ~MX7D_USBNC_USB_CTRL2_OPMODE_OVERRIDE_MASK; 8578c2ecf20Sopenharmony_ci val |= MX7D_USBNC_USB_CTRL2_OPMODE_NON_DRIVING; 8588c2ecf20Sopenharmony_ci writel(val, usbmisc->base + MX7D_USBNC_USB_CTRL2); 8598c2ecf20Sopenharmony_ci 8608c2ecf20Sopenharmony_ci val = readl(usbmisc->base + MX7D_USBNC_USB_CTRL2); 8618c2ecf20Sopenharmony_ci writel(val | MX7D_USBNC_USB_CTRL2_OPMODE_OVERRIDE_EN, 8628c2ecf20Sopenharmony_ci usbmisc->base + MX7D_USBNC_USB_CTRL2); 8638c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&usbmisc->lock, flags); 8648c2ecf20Sopenharmony_ci 8658c2ecf20Sopenharmony_ci ret = imx7d_charger_data_contact_detect(data); 8668c2ecf20Sopenharmony_ci if (ret) 8678c2ecf20Sopenharmony_ci return ret; 8688c2ecf20Sopenharmony_ci 8698c2ecf20Sopenharmony_ci ret = imx7d_charger_primary_detection(data); 8708c2ecf20Sopenharmony_ci if (!ret && usb_phy->chg_type != SDP_TYPE) 8718c2ecf20Sopenharmony_ci ret = imx7d_charger_secondary_detection(data); 8728c2ecf20Sopenharmony_ci 8738c2ecf20Sopenharmony_ci imx7_disable_charger_detector(data); 8748c2ecf20Sopenharmony_ci 8758c2ecf20Sopenharmony_ci return ret; 8768c2ecf20Sopenharmony_ci} 8778c2ecf20Sopenharmony_ci 8788c2ecf20Sopenharmony_cistatic int usbmisc_imx7ulp_init(struct imx_usbmisc_data *data) 8798c2ecf20Sopenharmony_ci{ 8808c2ecf20Sopenharmony_ci struct imx_usbmisc *usbmisc = dev_get_drvdata(data->dev); 8818c2ecf20Sopenharmony_ci unsigned long flags; 8828c2ecf20Sopenharmony_ci u32 reg; 8838c2ecf20Sopenharmony_ci 8848c2ecf20Sopenharmony_ci if (data->index >= 1) 8858c2ecf20Sopenharmony_ci return -EINVAL; 8868c2ecf20Sopenharmony_ci 8878c2ecf20Sopenharmony_ci spin_lock_irqsave(&usbmisc->lock, flags); 8888c2ecf20Sopenharmony_ci reg = readl(usbmisc->base); 8898c2ecf20Sopenharmony_ci if (data->disable_oc) { 8908c2ecf20Sopenharmony_ci reg |= MX6_BM_OVER_CUR_DIS; 8918c2ecf20Sopenharmony_ci } else { 8928c2ecf20Sopenharmony_ci reg &= ~MX6_BM_OVER_CUR_DIS; 8938c2ecf20Sopenharmony_ci 8948c2ecf20Sopenharmony_ci /* 8958c2ecf20Sopenharmony_ci * If the polarity is not configured keep it as setup by the 8968c2ecf20Sopenharmony_ci * bootloader. 8978c2ecf20Sopenharmony_ci */ 8988c2ecf20Sopenharmony_ci if (data->oc_pol_configured && data->oc_pol_active_low) 8998c2ecf20Sopenharmony_ci reg |= MX6_BM_OVER_CUR_POLARITY; 9008c2ecf20Sopenharmony_ci else if (data->oc_pol_configured) 9018c2ecf20Sopenharmony_ci reg &= ~MX6_BM_OVER_CUR_POLARITY; 9028c2ecf20Sopenharmony_ci } 9038c2ecf20Sopenharmony_ci /* If the polarity is not set keep it as setup by the bootlader */ 9048c2ecf20Sopenharmony_ci if (data->pwr_pol == 1) 9058c2ecf20Sopenharmony_ci reg |= MX6_BM_PWR_POLARITY; 9068c2ecf20Sopenharmony_ci 9078c2ecf20Sopenharmony_ci writel(reg, usbmisc->base); 9088c2ecf20Sopenharmony_ci 9098c2ecf20Sopenharmony_ci /* SoC non-burst setting */ 9108c2ecf20Sopenharmony_ci reg = readl(usbmisc->base); 9118c2ecf20Sopenharmony_ci writel(reg | MX6_BM_NON_BURST_SETTING, usbmisc->base); 9128c2ecf20Sopenharmony_ci 9138c2ecf20Sopenharmony_ci if (data->hsic) { 9148c2ecf20Sopenharmony_ci reg = readl(usbmisc->base); 9158c2ecf20Sopenharmony_ci writel(reg | MX6_BM_UTMI_ON_CLOCK, usbmisc->base); 9168c2ecf20Sopenharmony_ci 9178c2ecf20Sopenharmony_ci reg = readl(usbmisc->base + MX6_USB_HSIC_CTRL_OFFSET); 9188c2ecf20Sopenharmony_ci reg |= MX6_BM_HSIC_EN | MX6_BM_HSIC_CLK_ON; 9198c2ecf20Sopenharmony_ci writel(reg, usbmisc->base + MX6_USB_HSIC_CTRL_OFFSET); 9208c2ecf20Sopenharmony_ci 9218c2ecf20Sopenharmony_ci /* 9228c2ecf20Sopenharmony_ci * For non-HSIC controller, the autoresume is enabled 9238c2ecf20Sopenharmony_ci * at MXS PHY driver (usbphy_ctrl bit18). 9248c2ecf20Sopenharmony_ci */ 9258c2ecf20Sopenharmony_ci reg = readl(usbmisc->base + MX7D_USBNC_USB_CTRL2); 9268c2ecf20Sopenharmony_ci writel(reg | MX7D_USBNC_AUTO_RESUME, 9278c2ecf20Sopenharmony_ci usbmisc->base + MX7D_USBNC_USB_CTRL2); 9288c2ecf20Sopenharmony_ci } else { 9298c2ecf20Sopenharmony_ci reg = readl(usbmisc->base + MX7D_USBNC_USB_CTRL2); 9308c2ecf20Sopenharmony_ci reg &= ~MX7D_USB_VBUS_WAKEUP_SOURCE_MASK; 9318c2ecf20Sopenharmony_ci writel(reg | MX7D_USB_VBUS_WAKEUP_SOURCE_BVALID, 9328c2ecf20Sopenharmony_ci usbmisc->base + MX7D_USBNC_USB_CTRL2); 9338c2ecf20Sopenharmony_ci } 9348c2ecf20Sopenharmony_ci 9358c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&usbmisc->lock, flags); 9368c2ecf20Sopenharmony_ci 9378c2ecf20Sopenharmony_ci usbmisc_imx7d_set_wakeup(data, false); 9388c2ecf20Sopenharmony_ci 9398c2ecf20Sopenharmony_ci return 0; 9408c2ecf20Sopenharmony_ci} 9418c2ecf20Sopenharmony_ci 9428c2ecf20Sopenharmony_cistatic const struct usbmisc_ops imx25_usbmisc_ops = { 9438c2ecf20Sopenharmony_ci .init = usbmisc_imx25_init, 9448c2ecf20Sopenharmony_ci .post = usbmisc_imx25_post, 9458c2ecf20Sopenharmony_ci}; 9468c2ecf20Sopenharmony_ci 9478c2ecf20Sopenharmony_cistatic const struct usbmisc_ops imx27_usbmisc_ops = { 9488c2ecf20Sopenharmony_ci .init = usbmisc_imx27_init, 9498c2ecf20Sopenharmony_ci}; 9508c2ecf20Sopenharmony_ci 9518c2ecf20Sopenharmony_cistatic const struct usbmisc_ops imx51_usbmisc_ops = { 9528c2ecf20Sopenharmony_ci .init = usbmisc_imx53_init, 9538c2ecf20Sopenharmony_ci}; 9548c2ecf20Sopenharmony_ci 9558c2ecf20Sopenharmony_cistatic const struct usbmisc_ops imx53_usbmisc_ops = { 9568c2ecf20Sopenharmony_ci .init = usbmisc_imx53_init, 9578c2ecf20Sopenharmony_ci}; 9588c2ecf20Sopenharmony_ci 9598c2ecf20Sopenharmony_cistatic const struct usbmisc_ops imx6q_usbmisc_ops = { 9608c2ecf20Sopenharmony_ci .set_wakeup = usbmisc_imx6q_set_wakeup, 9618c2ecf20Sopenharmony_ci .init = usbmisc_imx6q_init, 9628c2ecf20Sopenharmony_ci .hsic_set_connect = usbmisc_imx6_hsic_set_connect, 9638c2ecf20Sopenharmony_ci .hsic_set_clk = usbmisc_imx6_hsic_set_clk, 9648c2ecf20Sopenharmony_ci}; 9658c2ecf20Sopenharmony_ci 9668c2ecf20Sopenharmony_cistatic const struct usbmisc_ops vf610_usbmisc_ops = { 9678c2ecf20Sopenharmony_ci .init = usbmisc_vf610_init, 9688c2ecf20Sopenharmony_ci}; 9698c2ecf20Sopenharmony_ci 9708c2ecf20Sopenharmony_cistatic const struct usbmisc_ops imx6sx_usbmisc_ops = { 9718c2ecf20Sopenharmony_ci .set_wakeup = usbmisc_imx6q_set_wakeup, 9728c2ecf20Sopenharmony_ci .init = usbmisc_imx6sx_init, 9738c2ecf20Sopenharmony_ci .hsic_set_connect = usbmisc_imx6_hsic_set_connect, 9748c2ecf20Sopenharmony_ci .hsic_set_clk = usbmisc_imx6_hsic_set_clk, 9758c2ecf20Sopenharmony_ci}; 9768c2ecf20Sopenharmony_ci 9778c2ecf20Sopenharmony_cistatic const struct usbmisc_ops imx7d_usbmisc_ops = { 9788c2ecf20Sopenharmony_ci .init = usbmisc_imx7d_init, 9798c2ecf20Sopenharmony_ci .set_wakeup = usbmisc_imx7d_set_wakeup, 9808c2ecf20Sopenharmony_ci .charger_detection = imx7d_charger_detection, 9818c2ecf20Sopenharmony_ci}; 9828c2ecf20Sopenharmony_ci 9838c2ecf20Sopenharmony_cistatic const struct usbmisc_ops imx7ulp_usbmisc_ops = { 9848c2ecf20Sopenharmony_ci .init = usbmisc_imx7ulp_init, 9858c2ecf20Sopenharmony_ci .set_wakeup = usbmisc_imx7d_set_wakeup, 9868c2ecf20Sopenharmony_ci .hsic_set_connect = usbmisc_imx6_hsic_set_connect, 9878c2ecf20Sopenharmony_ci .hsic_set_clk = usbmisc_imx6_hsic_set_clk, 9888c2ecf20Sopenharmony_ci}; 9898c2ecf20Sopenharmony_ci 9908c2ecf20Sopenharmony_cistatic inline bool is_imx53_usbmisc(struct imx_usbmisc_data *data) 9918c2ecf20Sopenharmony_ci{ 9928c2ecf20Sopenharmony_ci struct imx_usbmisc *usbmisc = dev_get_drvdata(data->dev); 9938c2ecf20Sopenharmony_ci 9948c2ecf20Sopenharmony_ci return usbmisc->ops == &imx53_usbmisc_ops; 9958c2ecf20Sopenharmony_ci} 9968c2ecf20Sopenharmony_ci 9978c2ecf20Sopenharmony_ciint imx_usbmisc_init(struct imx_usbmisc_data *data) 9988c2ecf20Sopenharmony_ci{ 9998c2ecf20Sopenharmony_ci struct imx_usbmisc *usbmisc; 10008c2ecf20Sopenharmony_ci 10018c2ecf20Sopenharmony_ci if (!data) 10028c2ecf20Sopenharmony_ci return 0; 10038c2ecf20Sopenharmony_ci 10048c2ecf20Sopenharmony_ci usbmisc = dev_get_drvdata(data->dev); 10058c2ecf20Sopenharmony_ci if (!usbmisc->ops->init) 10068c2ecf20Sopenharmony_ci return 0; 10078c2ecf20Sopenharmony_ci return usbmisc->ops->init(data); 10088c2ecf20Sopenharmony_ci} 10098c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(imx_usbmisc_init); 10108c2ecf20Sopenharmony_ci 10118c2ecf20Sopenharmony_ciint imx_usbmisc_init_post(struct imx_usbmisc_data *data) 10128c2ecf20Sopenharmony_ci{ 10138c2ecf20Sopenharmony_ci struct imx_usbmisc *usbmisc; 10148c2ecf20Sopenharmony_ci 10158c2ecf20Sopenharmony_ci if (!data) 10168c2ecf20Sopenharmony_ci return 0; 10178c2ecf20Sopenharmony_ci 10188c2ecf20Sopenharmony_ci usbmisc = dev_get_drvdata(data->dev); 10198c2ecf20Sopenharmony_ci if (!usbmisc->ops->post) 10208c2ecf20Sopenharmony_ci return 0; 10218c2ecf20Sopenharmony_ci return usbmisc->ops->post(data); 10228c2ecf20Sopenharmony_ci} 10238c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(imx_usbmisc_init_post); 10248c2ecf20Sopenharmony_ci 10258c2ecf20Sopenharmony_ciint imx_usbmisc_set_wakeup(struct imx_usbmisc_data *data, bool enabled) 10268c2ecf20Sopenharmony_ci{ 10278c2ecf20Sopenharmony_ci struct imx_usbmisc *usbmisc; 10288c2ecf20Sopenharmony_ci 10298c2ecf20Sopenharmony_ci if (!data) 10308c2ecf20Sopenharmony_ci return 0; 10318c2ecf20Sopenharmony_ci 10328c2ecf20Sopenharmony_ci usbmisc = dev_get_drvdata(data->dev); 10338c2ecf20Sopenharmony_ci if (!usbmisc->ops->set_wakeup) 10348c2ecf20Sopenharmony_ci return 0; 10358c2ecf20Sopenharmony_ci return usbmisc->ops->set_wakeup(data, enabled); 10368c2ecf20Sopenharmony_ci} 10378c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(imx_usbmisc_set_wakeup); 10388c2ecf20Sopenharmony_ci 10398c2ecf20Sopenharmony_ciint imx_usbmisc_hsic_set_connect(struct imx_usbmisc_data *data) 10408c2ecf20Sopenharmony_ci{ 10418c2ecf20Sopenharmony_ci struct imx_usbmisc *usbmisc; 10428c2ecf20Sopenharmony_ci 10438c2ecf20Sopenharmony_ci if (!data) 10448c2ecf20Sopenharmony_ci return 0; 10458c2ecf20Sopenharmony_ci 10468c2ecf20Sopenharmony_ci usbmisc = dev_get_drvdata(data->dev); 10478c2ecf20Sopenharmony_ci if (!usbmisc->ops->hsic_set_connect || !data->hsic) 10488c2ecf20Sopenharmony_ci return 0; 10498c2ecf20Sopenharmony_ci return usbmisc->ops->hsic_set_connect(data); 10508c2ecf20Sopenharmony_ci} 10518c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(imx_usbmisc_hsic_set_connect); 10528c2ecf20Sopenharmony_ci 10538c2ecf20Sopenharmony_ciint imx_usbmisc_hsic_set_clk(struct imx_usbmisc_data *data, bool on) 10548c2ecf20Sopenharmony_ci{ 10558c2ecf20Sopenharmony_ci struct imx_usbmisc *usbmisc; 10568c2ecf20Sopenharmony_ci 10578c2ecf20Sopenharmony_ci if (!data) 10588c2ecf20Sopenharmony_ci return 0; 10598c2ecf20Sopenharmony_ci 10608c2ecf20Sopenharmony_ci usbmisc = dev_get_drvdata(data->dev); 10618c2ecf20Sopenharmony_ci if (!usbmisc->ops->hsic_set_clk || !data->hsic) 10628c2ecf20Sopenharmony_ci return 0; 10638c2ecf20Sopenharmony_ci return usbmisc->ops->hsic_set_clk(data, on); 10648c2ecf20Sopenharmony_ci} 10658c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(imx_usbmisc_hsic_set_clk); 10668c2ecf20Sopenharmony_ci 10678c2ecf20Sopenharmony_ciint imx_usbmisc_charger_detection(struct imx_usbmisc_data *data, bool connect) 10688c2ecf20Sopenharmony_ci{ 10698c2ecf20Sopenharmony_ci struct imx_usbmisc *usbmisc; 10708c2ecf20Sopenharmony_ci struct usb_phy *usb_phy; 10718c2ecf20Sopenharmony_ci int ret = 0; 10728c2ecf20Sopenharmony_ci 10738c2ecf20Sopenharmony_ci if (!data) 10748c2ecf20Sopenharmony_ci return -EINVAL; 10758c2ecf20Sopenharmony_ci 10768c2ecf20Sopenharmony_ci usbmisc = dev_get_drvdata(data->dev); 10778c2ecf20Sopenharmony_ci usb_phy = data->usb_phy; 10788c2ecf20Sopenharmony_ci if (!usbmisc->ops->charger_detection) 10798c2ecf20Sopenharmony_ci return -ENOTSUPP; 10808c2ecf20Sopenharmony_ci 10818c2ecf20Sopenharmony_ci if (connect) { 10828c2ecf20Sopenharmony_ci ret = usbmisc->ops->charger_detection(data); 10838c2ecf20Sopenharmony_ci if (ret) { 10848c2ecf20Sopenharmony_ci dev_err(data->dev, 10858c2ecf20Sopenharmony_ci "Error occurs during detection: %d\n", 10868c2ecf20Sopenharmony_ci ret); 10878c2ecf20Sopenharmony_ci usb_phy->chg_state = USB_CHARGER_ABSENT; 10888c2ecf20Sopenharmony_ci } else { 10898c2ecf20Sopenharmony_ci usb_phy->chg_state = USB_CHARGER_PRESENT; 10908c2ecf20Sopenharmony_ci } 10918c2ecf20Sopenharmony_ci } else { 10928c2ecf20Sopenharmony_ci usb_phy->chg_state = USB_CHARGER_ABSENT; 10938c2ecf20Sopenharmony_ci usb_phy->chg_type = UNKNOWN_TYPE; 10948c2ecf20Sopenharmony_ci } 10958c2ecf20Sopenharmony_ci return ret; 10968c2ecf20Sopenharmony_ci} 10978c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(imx_usbmisc_charger_detection); 10988c2ecf20Sopenharmony_ci 10998c2ecf20Sopenharmony_cistatic const struct of_device_id usbmisc_imx_dt_ids[] = { 11008c2ecf20Sopenharmony_ci { 11018c2ecf20Sopenharmony_ci .compatible = "fsl,imx25-usbmisc", 11028c2ecf20Sopenharmony_ci .data = &imx25_usbmisc_ops, 11038c2ecf20Sopenharmony_ci }, 11048c2ecf20Sopenharmony_ci { 11058c2ecf20Sopenharmony_ci .compatible = "fsl,imx35-usbmisc", 11068c2ecf20Sopenharmony_ci .data = &imx25_usbmisc_ops, 11078c2ecf20Sopenharmony_ci }, 11088c2ecf20Sopenharmony_ci { 11098c2ecf20Sopenharmony_ci .compatible = "fsl,imx27-usbmisc", 11108c2ecf20Sopenharmony_ci .data = &imx27_usbmisc_ops, 11118c2ecf20Sopenharmony_ci }, 11128c2ecf20Sopenharmony_ci { 11138c2ecf20Sopenharmony_ci .compatible = "fsl,imx51-usbmisc", 11148c2ecf20Sopenharmony_ci .data = &imx51_usbmisc_ops, 11158c2ecf20Sopenharmony_ci }, 11168c2ecf20Sopenharmony_ci { 11178c2ecf20Sopenharmony_ci .compatible = "fsl,imx53-usbmisc", 11188c2ecf20Sopenharmony_ci .data = &imx53_usbmisc_ops, 11198c2ecf20Sopenharmony_ci }, 11208c2ecf20Sopenharmony_ci { 11218c2ecf20Sopenharmony_ci .compatible = "fsl,imx6q-usbmisc", 11228c2ecf20Sopenharmony_ci .data = &imx6q_usbmisc_ops, 11238c2ecf20Sopenharmony_ci }, 11248c2ecf20Sopenharmony_ci { 11258c2ecf20Sopenharmony_ci .compatible = "fsl,vf610-usbmisc", 11268c2ecf20Sopenharmony_ci .data = &vf610_usbmisc_ops, 11278c2ecf20Sopenharmony_ci }, 11288c2ecf20Sopenharmony_ci { 11298c2ecf20Sopenharmony_ci .compatible = "fsl,imx6sx-usbmisc", 11308c2ecf20Sopenharmony_ci .data = &imx6sx_usbmisc_ops, 11318c2ecf20Sopenharmony_ci }, 11328c2ecf20Sopenharmony_ci { 11338c2ecf20Sopenharmony_ci .compatible = "fsl,imx6ul-usbmisc", 11348c2ecf20Sopenharmony_ci .data = &imx6sx_usbmisc_ops, 11358c2ecf20Sopenharmony_ci }, 11368c2ecf20Sopenharmony_ci { 11378c2ecf20Sopenharmony_ci .compatible = "fsl,imx7d-usbmisc", 11388c2ecf20Sopenharmony_ci .data = &imx7d_usbmisc_ops, 11398c2ecf20Sopenharmony_ci }, 11408c2ecf20Sopenharmony_ci { 11418c2ecf20Sopenharmony_ci .compatible = "fsl,imx7ulp-usbmisc", 11428c2ecf20Sopenharmony_ci .data = &imx7ulp_usbmisc_ops, 11438c2ecf20Sopenharmony_ci }, 11448c2ecf20Sopenharmony_ci { /* sentinel */ } 11458c2ecf20Sopenharmony_ci}; 11468c2ecf20Sopenharmony_ciMODULE_DEVICE_TABLE(of, usbmisc_imx_dt_ids); 11478c2ecf20Sopenharmony_ci 11488c2ecf20Sopenharmony_cistatic int usbmisc_imx_probe(struct platform_device *pdev) 11498c2ecf20Sopenharmony_ci{ 11508c2ecf20Sopenharmony_ci struct imx_usbmisc *data; 11518c2ecf20Sopenharmony_ci const struct of_device_id *of_id; 11528c2ecf20Sopenharmony_ci 11538c2ecf20Sopenharmony_ci of_id = of_match_device(usbmisc_imx_dt_ids, &pdev->dev); 11548c2ecf20Sopenharmony_ci if (!of_id) 11558c2ecf20Sopenharmony_ci return -ENODEV; 11568c2ecf20Sopenharmony_ci 11578c2ecf20Sopenharmony_ci data = devm_kzalloc(&pdev->dev, sizeof(*data), GFP_KERNEL); 11588c2ecf20Sopenharmony_ci if (!data) 11598c2ecf20Sopenharmony_ci return -ENOMEM; 11608c2ecf20Sopenharmony_ci 11618c2ecf20Sopenharmony_ci spin_lock_init(&data->lock); 11628c2ecf20Sopenharmony_ci 11638c2ecf20Sopenharmony_ci data->base = devm_platform_ioremap_resource(pdev, 0); 11648c2ecf20Sopenharmony_ci if (IS_ERR(data->base)) 11658c2ecf20Sopenharmony_ci return PTR_ERR(data->base); 11668c2ecf20Sopenharmony_ci 11678c2ecf20Sopenharmony_ci data->ops = (const struct usbmisc_ops *)of_id->data; 11688c2ecf20Sopenharmony_ci platform_set_drvdata(pdev, data); 11698c2ecf20Sopenharmony_ci 11708c2ecf20Sopenharmony_ci return 0; 11718c2ecf20Sopenharmony_ci} 11728c2ecf20Sopenharmony_ci 11738c2ecf20Sopenharmony_cistatic int usbmisc_imx_remove(struct platform_device *pdev) 11748c2ecf20Sopenharmony_ci{ 11758c2ecf20Sopenharmony_ci return 0; 11768c2ecf20Sopenharmony_ci} 11778c2ecf20Sopenharmony_ci 11788c2ecf20Sopenharmony_cistatic struct platform_driver usbmisc_imx_driver = { 11798c2ecf20Sopenharmony_ci .probe = usbmisc_imx_probe, 11808c2ecf20Sopenharmony_ci .remove = usbmisc_imx_remove, 11818c2ecf20Sopenharmony_ci .driver = { 11828c2ecf20Sopenharmony_ci .name = "usbmisc_imx", 11838c2ecf20Sopenharmony_ci .of_match_table = usbmisc_imx_dt_ids, 11848c2ecf20Sopenharmony_ci }, 11858c2ecf20Sopenharmony_ci}; 11868c2ecf20Sopenharmony_ci 11878c2ecf20Sopenharmony_cimodule_platform_driver(usbmisc_imx_driver); 11888c2ecf20Sopenharmony_ci 11898c2ecf20Sopenharmony_ciMODULE_ALIAS("platform:usbmisc-imx"); 11908c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL"); 11918c2ecf20Sopenharmony_ciMODULE_DESCRIPTION("driver for imx usb non-core registers"); 11928c2ecf20Sopenharmony_ciMODULE_AUTHOR("Richard Zhao <richard.zhao@freescale.com>"); 1193