summaryrefslogtreecommitdiff
path: root/arch/arm/mach-imx/gpcv2.c
diff options
context:
space:
mode:
Diffstat (limited to 'arch/arm/mach-imx/gpcv2.c')
-rw-r--r--arch/arm/mach-imx/gpcv2.c73
1 files changed, 70 insertions, 3 deletions
diff --git a/arch/arm/mach-imx/gpcv2.c b/arch/arm/mach-imx/gpcv2.c
index d52578d6a1e1..0e2502430cdf 100644
--- a/arch/arm/mach-imx/gpcv2.c
+++ b/arch/arm/mach-imx/gpcv2.c
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2015 Freescale Semiconductor, Inc.
+ * Copyright (C) 2015-2016 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
@@ -115,7 +115,24 @@ static u32 gpcv2_saved_imrs_m4[IMR_NUM];
static u32 gpcv2_mf_irqs[IMR_NUM];
static u32 gpcv2_mf_request_on[IMR_NUM];
static DEFINE_SPINLOCK(gpcv2_lock);
-static struct notifier_block nb_mipi, nb_pcie;
+static struct notifier_block nb_mipi, nb_pcie, nb_usb_hsic;
+
+void imx_gpcv2_add_m4_wake_up_irq(u32 hwirq, bool enable)
+{
+ unsigned int idx = hwirq / 32;
+ unsigned long flags;
+ u32 mask;
+
+ /* Sanity check for SPI irq */
+ if (hwirq < 32)
+ return;
+
+ mask = 1 << hwirq % 32;
+ spin_lock_irqsave(&gpcv2_lock, flags);
+ gpcv2_wake_irqs[idx] = enable ? gpcv2_wake_irqs[idx] | mask :
+ gpcv2_wake_irqs[idx] & ~mask;
+ spin_unlock_irqrestore(&gpcv2_lock, flags);
+}
static int imx_gpcv2_irq_set_wake(struct irq_data *d, unsigned int on)
{
@@ -700,6 +717,41 @@ static struct irq_domain_ops imx_gpcv2_domain_ops = {
.free = irq_domain_free_irqs_common,
};
+static int imx_usb_hsic_regulator_notify(struct notifier_block *nb,
+ unsigned long event,
+ void *ignored)
+{
+ u32 val = 0;
+
+ val = readl_relaxed(gpc_base + GPC_PGC_CPU_MAPPING);
+ writel_relaxed(val | BIT(6), gpc_base + GPC_PGC_CPU_MAPPING);
+
+ switch (event) {
+ case REGULATOR_EVENT_PRE_DO_ENABLE:
+ val = readl_relaxed(gpc_base + GPC_PU_PGC_SW_PUP_REQ);
+ writel_relaxed(val | BIT(4), gpc_base + GPC_PU_PGC_SW_PUP_REQ);
+ while (readl_relaxed(gpc_base + GPC_PU_PGC_SW_PUP_REQ) & BIT(4))
+ ;
+ break;
+ case REGULATOR_EVENT_PRE_DO_DISABLE:
+ /* only disable phy need to set PGC bit, enable does NOT need */
+ imx_gpcv2_set_m_core_pgc(true, GPC_PGC_USB_HSIC_PHY);
+ val = readl_relaxed(gpc_base + GPC_PU_PGC_SW_PDN_REQ);
+ writel_relaxed(val | BIT(4), gpc_base + GPC_PU_PGC_SW_PDN_REQ);
+ while (readl_relaxed(gpc_base + GPC_PU_PGC_SW_PDN_REQ) & BIT(4))
+ ;
+ imx_gpcv2_set_m_core_pgc(false, GPC_PGC_USB_HSIC_PHY);
+ break;
+ default:
+ break;
+ }
+
+ val = readl_relaxed(gpc_base + GPC_PGC_CPU_MAPPING);
+ writel_relaxed(val & ~BIT(6), gpc_base + GPC_PGC_CPU_MAPPING);
+
+ return NOTIFY_OK;
+}
+
static int imx_mipi_regulator_notify(struct notifier_block *nb,
unsigned long event,
void *ignored)
@@ -901,7 +953,7 @@ void __init imx_gpcv2_check_dt(void)
static int imx_gpcv2_probe(struct platform_device *pdev)
{
int ret;
- struct regulator *mipi_reg, *pcie_reg;
+ struct regulator *mipi_reg, *pcie_reg, *usb_hsic_reg;
if (cpu_is_imx7d()) {
mipi_reg = devm_regulator_get(&pdev->dev, "mipi-phy");
@@ -935,6 +987,21 @@ static int imx_gpcv2_probe(struct platform_device *pdev)
"pcie regulator notifier request failed\n");
return ret;
}
+
+ usb_hsic_reg = devm_regulator_get(&pdev->dev, "vcc");
+ if (IS_ERR(usb_hsic_reg)) {
+ ret = PTR_ERR(usb_hsic_reg);
+ dev_err(&pdev->dev, "usb hsic regulator not ready.\n");
+ return ret;
+ }
+ nb_usb_hsic.notifier_call = &imx_usb_hsic_regulator_notify;
+
+ ret = regulator_register_notifier(usb_hsic_reg, &nb_usb_hsic);
+ if (ret) {
+ dev_err(&pdev->dev,
+ "usb hsic regulator notifier request failed\n");
+ return ret;
+ }
}
return 0;
}