aboutsummaryrefslogtreecommitdiffstats
path: root/arch/arm/mach-omap2/omap-wakeupgen.c
diff options
context:
space:
mode:
Diffstat (limited to 'arch/arm/mach-omap2/omap-wakeupgen.c')
-rw-r--r--arch/arm/mach-omap2/omap-wakeupgen.c128
1 files changed, 98 insertions, 30 deletions
diff --git a/arch/arm/mach-omap2/omap-wakeupgen.c b/arch/arm/mach-omap2/omap-wakeupgen.c
index f961c46453b9..3b56722dfd8a 100644
--- a/arch/arm/mach-omap2/omap-wakeupgen.c
+++ b/arch/arm/mach-omap2/omap-wakeupgen.c
@@ -20,11 +20,12 @@
20#include <linux/init.h> 20#include <linux/init.h>
21#include <linux/io.h> 21#include <linux/io.h>
22#include <linux/irq.h> 22#include <linux/irq.h>
23#include <linux/irqdomain.h>
24#include <linux/of_address.h>
23#include <linux/platform_device.h> 25#include <linux/platform_device.h>
24#include <linux/cpu.h> 26#include <linux/cpu.h>
25#include <linux/notifier.h> 27#include <linux/notifier.h>
26#include <linux/cpu_pm.h> 28#include <linux/cpu_pm.h>
27#include <linux/irqchip/arm-gic.h>
28 29
29#include "omap-wakeupgen.h" 30#include "omap-wakeupgen.h"
30#include "omap-secure.h" 31#include "omap-secure.h"
@@ -78,29 +79,12 @@ static inline void sar_writel(u32 val, u32 offset, u8 idx)
78 79
79static inline int _wakeupgen_get_irq_info(u32 irq, u32 *bit_posn, u8 *reg_index) 80static inline int _wakeupgen_get_irq_info(u32 irq, u32 *bit_posn, u8 *reg_index)
80{ 81{
81 unsigned int spi_irq;
82
83 /*
84 * PPIs and SGIs are not supported.
85 */
86 if (irq < OMAP44XX_IRQ_GIC_START)
87 return -EINVAL;
88
89 /*
90 * Subtract the GIC offset.
91 */
92 spi_irq = irq - OMAP44XX_IRQ_GIC_START;
93 if (spi_irq > MAX_IRQS) {
94 pr_err("omap wakeupGen: Invalid IRQ%d\n", irq);
95 return -EINVAL;
96 }
97
98 /* 82 /*
99 * Each WakeupGen register controls 32 interrupt. 83 * Each WakeupGen register controls 32 interrupt.
100 * i.e. 1 bit per SPI IRQ 84 * i.e. 1 bit per SPI IRQ
101 */ 85 */
102 *reg_index = spi_irq >> 5; 86 *reg_index = irq >> 5;
103 *bit_posn = spi_irq %= 32; 87 *bit_posn = irq %= 32;
104 88
105 return 0; 89 return 0;
106} 90}
@@ -141,6 +125,7 @@ static void wakeupgen_mask(struct irq_data *d)
141 raw_spin_lock_irqsave(&wakeupgen_lock, flags); 125 raw_spin_lock_irqsave(&wakeupgen_lock, flags);
142 _wakeupgen_clear(d->hwirq, irq_target_cpu[d->hwirq]); 126 _wakeupgen_clear(d->hwirq, irq_target_cpu[d->hwirq]);
143 raw_spin_unlock_irqrestore(&wakeupgen_lock, flags); 127 raw_spin_unlock_irqrestore(&wakeupgen_lock, flags);
128 irq_chip_mask_parent(d);
144} 129}
145 130
146/* 131/*
@@ -153,6 +138,7 @@ static void wakeupgen_unmask(struct irq_data *d)
153 raw_spin_lock_irqsave(&wakeupgen_lock, flags); 138 raw_spin_lock_irqsave(&wakeupgen_lock, flags);
154 _wakeupgen_set(d->hwirq, irq_target_cpu[d->hwirq]); 139 _wakeupgen_set(d->hwirq, irq_target_cpu[d->hwirq]);
155 raw_spin_unlock_irqrestore(&wakeupgen_lock, flags); 140 raw_spin_unlock_irqrestore(&wakeupgen_lock, flags);
141 irq_chip_unmask_parent(d);
156} 142}
157 143
158#ifdef CONFIG_HOTPLUG_CPU 144#ifdef CONFIG_HOTPLUG_CPU
@@ -400,15 +386,91 @@ int omap_secure_apis_support(void)
400 return omap_secure_apis; 386 return omap_secure_apis;
401} 387}
402 388
389static struct irq_chip wakeupgen_chip = {
390 .name = "WUGEN",
391 .irq_eoi = irq_chip_eoi_parent,
392 .irq_mask = wakeupgen_mask,
393 .irq_unmask = wakeupgen_unmask,
394 .irq_retrigger = irq_chip_retrigger_hierarchy,
395 .flags = IRQCHIP_SKIP_SET_WAKE | IRQCHIP_MASK_ON_SUSPEND,
396#ifdef CONFIG_SMP
397 .irq_set_affinity = irq_chip_set_affinity_parent,
398#endif
399};
400
401static int wakeupgen_domain_xlate(struct irq_domain *domain,
402 struct device_node *controller,
403 const u32 *intspec,
404 unsigned int intsize,
405 unsigned long *out_hwirq,
406 unsigned int *out_type)
407{
408 if (domain->of_node != controller)
409 return -EINVAL; /* Shouldn't happen, really... */
410 if (intsize != 3)
411 return -EINVAL; /* Not GIC compliant */
412 if (intspec[0] != 0)
413 return -EINVAL; /* No PPI should point to this domain */
414
415 *out_hwirq = intspec[1];
416 *out_type = intspec[2];
417 return 0;
418}
419
420static int wakeupgen_domain_alloc(struct irq_domain *domain,
421 unsigned int virq,
422 unsigned int nr_irqs, void *data)
423{
424 struct of_phandle_args *args = data;
425 struct of_phandle_args parent_args;
426 irq_hw_number_t hwirq;
427 int i;
428
429 if (args->args_count != 3)
430 return -EINVAL; /* Not GIC compliant */
431 if (args->args[0] != 0)
432 return -EINVAL; /* No PPI should point to this domain */
433
434 hwirq = args->args[1];
435 if (hwirq >= MAX_IRQS)
436 return -EINVAL; /* Can't deal with this */
437
438 for (i = 0; i < nr_irqs; i++)
439 irq_domain_set_hwirq_and_chip(domain, virq + i, hwirq + i,
440 &wakeupgen_chip, NULL);
441
442 parent_args = *args;
443 parent_args.np = domain->parent->of_node;
444 return irq_domain_alloc_irqs_parent(domain, virq, nr_irqs, &parent_args);
445}
446
447static struct irq_domain_ops wakeupgen_domain_ops = {
448 .xlate = wakeupgen_domain_xlate,
449 .alloc = wakeupgen_domain_alloc,
450 .free = irq_domain_free_irqs_common,
451};
452
403/* 453/*
404 * Initialise the wakeupgen module. 454 * Initialise the wakeupgen module.
405 */ 455 */
406int __init omap_wakeupgen_init(void) 456static int __init wakeupgen_init(struct device_node *node,
457 struct device_node *parent)
407{ 458{
459 struct irq_domain *parent_domain, *domain;
408 int i; 460 int i;
409 unsigned int boot_cpu = smp_processor_id(); 461 unsigned int boot_cpu = smp_processor_id();
410 u32 val; 462 u32 val;
411 463
464 if (!parent) {
465 pr_err("%s: no parent, giving up\n", node->full_name);
466 return -ENODEV;
467 }
468
469 parent_domain = irq_find_host(parent);
470 if (!parent_domain) {
471 pr_err("%s: unable to obtain parent domain\n", node->full_name);
472 return -ENXIO;
473 }
412 /* Not supported on OMAP4 ES1.0 silicon */ 474 /* Not supported on OMAP4 ES1.0 silicon */
413 if (omap_rev() == OMAP4430_REV_ES1_0) { 475 if (omap_rev() == OMAP4430_REV_ES1_0) {
414 WARN(1, "WakeupGen: Not supported on OMAP4430 ES1.0\n"); 476 WARN(1, "WakeupGen: Not supported on OMAP4430 ES1.0\n");
@@ -416,7 +478,7 @@ int __init omap_wakeupgen_init(void)
416 } 478 }
417 479
418 /* Static mapping, never released */ 480 /* Static mapping, never released */
419 wakeupgen_base = ioremap(OMAP_WKUPGEN_BASE, SZ_4K); 481 wakeupgen_base = of_iomap(node, 0);
420 if (WARN_ON(!wakeupgen_base)) 482 if (WARN_ON(!wakeupgen_base))
421 return -ENOMEM; 483 return -ENOMEM;
422 484
@@ -429,6 +491,14 @@ int __init omap_wakeupgen_init(void)
429 max_irqs = AM43XX_IRQS; 491 max_irqs = AM43XX_IRQS;
430 } 492 }
431 493
494 domain = irq_domain_add_hierarchy(parent_domain, 0, max_irqs,
495 node, &wakeupgen_domain_ops,
496 NULL);
497 if (!domain) {
498 iounmap(wakeupgen_base);
499 return -ENOMEM;
500 }
501
432 /* Clear all IRQ bitmasks at wakeupGen level */ 502 /* Clear all IRQ bitmasks at wakeupGen level */
433 for (i = 0; i < irq_banks; i++) { 503 for (i = 0; i < irq_banks; i++) {
434 wakeupgen_writel(0, i, CPU0_ID); 504 wakeupgen_writel(0, i, CPU0_ID);
@@ -437,14 +507,6 @@ int __init omap_wakeupgen_init(void)
437 } 507 }
438 508
439 /* 509 /*
440 * Override GIC architecture specific functions to add
441 * OMAP WakeupGen interrupt controller along with GIC
442 */
443 gic_arch_extn.irq_mask = wakeupgen_mask;
444 gic_arch_extn.irq_unmask = wakeupgen_unmask;
445 gic_arch_extn.flags = IRQCHIP_MASK_ON_SUSPEND | IRQCHIP_SKIP_SET_WAKE;
446
447 /*
448 * FIXME: Add support to set_smp_affinity() once the core 510 * FIXME: Add support to set_smp_affinity() once the core
449 * GIC code has necessary hooks in place. 511 * GIC code has necessary hooks in place.
450 */ 512 */
@@ -474,3 +536,9 @@ int __init omap_wakeupgen_init(void)
474 536
475 return 0; 537 return 0;
476} 538}
539
540/*
541 * We cannot use the IRQCHIP_DECLARE macro that lives in
542 * drivers/irqchip, so we're forced to roll our own. Not very nice.
543 */
544OF_DECLARE_2(irqchip, ti_wakeupgen, "ti,omap4-wugen-mpu", wakeupgen_init);