diff options
Diffstat (limited to 'arch/arm/mach-imx/gpcv2.c')
-rw-r--r-- | arch/arm/mach-imx/gpcv2.c | 73 |
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; } |