Linux Audio

Check our new training course

Loading...
Note: File does not exist in v3.1.
  1/*
  2 * Copyright 2011 Freescale Semiconductor, Inc.
  3 * Copyright 2011 Linaro Ltd.
  4 *
  5 * The code contained herein is licensed under the GNU General Public
  6 * License. You may obtain a copy of the GNU General Public License
  7 * Version 2 or later at the following locations:
  8 *
  9 * http://www.opensource.org/licenses/gpl-license.html
 10 * http://www.gnu.org/copyleft/gpl.html
 11 */
 12
 13#include <linux/io.h>
 14#include <linux/irq.h>
 15#include <linux/of.h>
 16#include <linux/of_address.h>
 17#include <linux/of_irq.h>
 18#include <asm/hardware/gic.h>
 19
 20#define GPC_IMR1		0x008
 21#define GPC_PGC_CPU_PDN		0x2a0
 22
 23#define IMR_NUM			4
 24
 25static void __iomem *gpc_base;
 26static u32 gpc_wake_irqs[IMR_NUM];
 27static u32 gpc_saved_imrs[IMR_NUM];
 28
 29void imx_gpc_pre_suspend(void)
 30{
 31	void __iomem *reg_imr1 = gpc_base + GPC_IMR1;
 32	int i;
 33
 34	/* Tell GPC to power off ARM core when suspend */
 35	writel_relaxed(0x1, gpc_base + GPC_PGC_CPU_PDN);
 36
 37	for (i = 0; i < IMR_NUM; i++) {
 38		gpc_saved_imrs[i] = readl_relaxed(reg_imr1 + i * 4);
 39		writel_relaxed(~gpc_wake_irqs[i], reg_imr1 + i * 4);
 40	}
 41}
 42
 43void imx_gpc_post_resume(void)
 44{
 45	void __iomem *reg_imr1 = gpc_base + GPC_IMR1;
 46	int i;
 47
 48	/* Keep ARM core powered on for other low-power modes */
 49	writel_relaxed(0x0, gpc_base + GPC_PGC_CPU_PDN);
 50
 51	for (i = 0; i < IMR_NUM; i++)
 52		writel_relaxed(gpc_saved_imrs[i], reg_imr1 + i * 4);
 53}
 54
 55static int imx_gpc_irq_set_wake(struct irq_data *d, unsigned int on)
 56{
 57	unsigned int idx = d->irq / 32 - 1;
 58	u32 mask;
 59
 60	/* Sanity check for SPI irq */
 61	if (d->irq < 32)
 62		return -EINVAL;
 63
 64	mask = 1 << d->irq % 32;
 65	gpc_wake_irqs[idx] = on ? gpc_wake_irqs[idx] | mask :
 66				  gpc_wake_irqs[idx] & ~mask;
 67
 68	return 0;
 69}
 70
 71static void imx_gpc_irq_unmask(struct irq_data *d)
 72{
 73	void __iomem *reg;
 74	u32 val;
 75
 76	/* Sanity check for SPI irq */
 77	if (d->irq < 32)
 78		return;
 79
 80	reg = gpc_base + GPC_IMR1 + (d->irq / 32 - 1) * 4;
 81	val = readl_relaxed(reg);
 82	val &= ~(1 << d->irq % 32);
 83	writel_relaxed(val, reg);
 84}
 85
 86static void imx_gpc_irq_mask(struct irq_data *d)
 87{
 88	void __iomem *reg;
 89	u32 val;
 90
 91	/* Sanity check for SPI irq */
 92	if (d->irq < 32)
 93		return;
 94
 95	reg = gpc_base + GPC_IMR1 + (d->irq / 32 - 1) * 4;
 96	val = readl_relaxed(reg);
 97	val |= 1 << (d->irq % 32);
 98	writel_relaxed(val, reg);
 99}
100
101void __init imx_gpc_init(void)
102{
103	struct device_node *np;
104
105	np = of_find_compatible_node(NULL, NULL, "fsl,imx6q-gpc");
106	gpc_base = of_iomap(np, 0);
107	WARN_ON(!gpc_base);
108
109	/* Register GPC as the secondary interrupt controller behind GIC */
110	gic_arch_extn.irq_mask = imx_gpc_irq_mask;
111	gic_arch_extn.irq_unmask = imx_gpc_irq_unmask;
112	gic_arch_extn.irq_set_wake = imx_gpc_irq_set_wake;
113}