diff options
author | Tero Kristo <t-kristo@ti.com> | 2011-12-16 16:36:59 -0500 |
---|---|---|
committer | Paul Walmsley <paul@pwsan.com> | 2011-12-16 16:36:59 -0500 |
commit | 13a3fe52f7525d7b327f1f6766826fe9668bd749 (patch) | |
tree | 94cf7f68f443474771e6fb183d7febbdce50e046 /arch/arm/mach-omap2/mux.c | |
parent | 91285b6fa296657d92dc2225100fb94aee869bf2 (diff) |
ARM: OMAP2+: mux: add support for PAD wakeup interrupts
OMAP mux now parses active wakeup events from pad registers and calls
corresponding hwmod ISRs once a wakeup is detected. This is
accomplished by registering an interrupt handler for PRCM IO event,
which is raised every time the HW detects wakeups.
[paul@pwsan.com: This patch is a merge of Govindraj R's "ARM: OMAP2+:
hwmod: Add API to check IO PAD wakeup status" patch, Tero Kristo's
"ARM: OMAP2+: mux: add support for PAD wakeup interrupts" patch, and
part of Tero's "ARM: OMAP: mux: add support for selecting mpu_irq for
each wakeup pad" patch.]
Signed-off-by: Tero Kristo <t-kristo@ti.com>
Cc: Govindraj.R <govindraj.raja@ti.com>
Tested-by: Kevin Hilman <khilman@ti.com>
Reviewed-by: Kevin Hilman <khilman@ti.com>
Acked-by: Tony Lindgren <tony@atomide.com>
[paul@pwsan.com: reduced indentation level; renamed omap_hwmod function;
improved function documentation; modified to iterate only through dynamic
pads; modified to skip pads where idle mode doesn't enable wakeups; split
patches]
Signed-off-by: Paul Walmsley <paul@pwsan.com>
Diffstat (limited to 'arch/arm/mach-omap2/mux.c')
-rw-r--r-- | arch/arm/mach-omap2/mux.c | 83 |
1 files changed, 83 insertions, 0 deletions
diff --git a/arch/arm/mach-omap2/mux.c b/arch/arm/mach-omap2/mux.c index a474c81355ec..e1cc75d1a57a 100644 --- a/arch/arm/mach-omap2/mux.c +++ b/arch/arm/mach-omap2/mux.c | |||
@@ -32,6 +32,8 @@ | |||
32 | #include <linux/debugfs.h> | 32 | #include <linux/debugfs.h> |
33 | #include <linux/seq_file.h> | 33 | #include <linux/seq_file.h> |
34 | #include <linux/uaccess.h> | 34 | #include <linux/uaccess.h> |
35 | #include <linux/irq.h> | ||
36 | #include <linux/interrupt.h> | ||
35 | 37 | ||
36 | #include <asm/system.h> | 38 | #include <asm/system.h> |
37 | 39 | ||
@@ -39,6 +41,7 @@ | |||
39 | 41 | ||
40 | #include "control.h" | 42 | #include "control.h" |
41 | #include "mux.h" | 43 | #include "mux.h" |
44 | #include "prm.h" | ||
42 | 45 | ||
43 | #define OMAP_MUX_BASE_OFFSET 0x30 /* Offset from CTRL_BASE */ | 46 | #define OMAP_MUX_BASE_OFFSET 0x30 /* Offset from CTRL_BASE */ |
44 | #define OMAP_MUX_BASE_SZ 0x5ca | 47 | #define OMAP_MUX_BASE_SZ 0x5ca |
@@ -353,6 +356,78 @@ err1: | |||
353 | return NULL; | 356 | return NULL; |
354 | } | 357 | } |
355 | 358 | ||
359 | /** | ||
360 | * omap_hwmod_mux_scan_wakeups - omap hwmod scan wakeup pads | ||
361 | * @hmux: Pads for a hwmod | ||
362 | * @mpu_irqs: MPU irq array for a hwmod | ||
363 | * | ||
364 | * Scans the wakeup status of pads for a single hwmod. If an irq | ||
365 | * array is defined for this mux, the parser will call the registered | ||
366 | * ISRs for corresponding pads, otherwise the parser will stop at the | ||
367 | * first wakeup active pad and return. Returns true if there is a | ||
368 | * pending and non-served wakeup event for the mux, otherwise false. | ||
369 | */ | ||
370 | static bool omap_hwmod_mux_scan_wakeups(struct omap_hwmod_mux_info *hmux, | ||
371 | struct omap_hwmod_irq_info *mpu_irqs) | ||
372 | { | ||
373 | int i, irq; | ||
374 | unsigned int val; | ||
375 | u32 handled_irqs = 0; | ||
376 | |||
377 | for (i = 0; i < hmux->nr_pads_dynamic; i++) { | ||
378 | struct omap_device_pad *pad = hmux->pads_dynamic[i]; | ||
379 | |||
380 | if (!(pad->flags & OMAP_DEVICE_PAD_WAKEUP) || | ||
381 | !(pad->idle & OMAP_WAKEUP_EN)) | ||
382 | continue; | ||
383 | |||
384 | val = omap_mux_read(pad->partition, pad->mux->reg_offset); | ||
385 | if (!(val & OMAP_WAKEUP_EVENT)) | ||
386 | continue; | ||
387 | |||
388 | if (!hmux->irqs) | ||
389 | return true; | ||
390 | |||
391 | irq = hmux->irqs[i]; | ||
392 | /* make sure we only handle each irq once */ | ||
393 | if (handled_irqs & 1 << irq) | ||
394 | continue; | ||
395 | |||
396 | handled_irqs |= 1 << irq; | ||
397 | |||
398 | generic_handle_irq(mpu_irqs[irq].irq); | ||
399 | } | ||
400 | |||
401 | return false; | ||
402 | } | ||
403 | |||
404 | /** | ||
405 | * _omap_hwmod_mux_handle_irq - Process wakeup events for a single hwmod | ||
406 | * | ||
407 | * Checks a single hwmod for every wakeup capable pad to see if there is an | ||
408 | * active wakeup event. If this is the case, call the corresponding ISR. | ||
409 | */ | ||
410 | static int _omap_hwmod_mux_handle_irq(struct omap_hwmod *oh, void *data) | ||
411 | { | ||
412 | if (!oh->mux || !oh->mux->enabled) | ||
413 | return 0; | ||
414 | if (omap_hwmod_mux_scan_wakeups(oh->mux, oh->mpu_irqs)) | ||
415 | generic_handle_irq(oh->mpu_irqs[0].irq); | ||
416 | return 0; | ||
417 | } | ||
418 | |||
419 | /** | ||
420 | * omap_hwmod_mux_handle_irq - Process pad wakeup irqs. | ||
421 | * | ||
422 | * Calls a function for each registered omap_hwmod to check | ||
423 | * pad wakeup statuses. | ||
424 | */ | ||
425 | static irqreturn_t omap_hwmod_mux_handle_irq(int irq, void *unused) | ||
426 | { | ||
427 | omap_hwmod_for_each(_omap_hwmod_mux_handle_irq, NULL); | ||
428 | return IRQ_HANDLED; | ||
429 | } | ||
430 | |||
356 | /* Assumes the calling function takes care of locking */ | 431 | /* Assumes the calling function takes care of locking */ |
357 | void omap_hwmod_mux(struct omap_hwmod_mux_info *hmux, u8 state) | 432 | void omap_hwmod_mux(struct omap_hwmod_mux_info *hmux, u8 state) |
358 | { | 433 | { |
@@ -717,6 +792,7 @@ static void __init omap_mux_free_names(struct omap_mux *m) | |||
717 | static int __init omap_mux_late_init(void) | 792 | static int __init omap_mux_late_init(void) |
718 | { | 793 | { |
719 | struct omap_mux_partition *partition; | 794 | struct omap_mux_partition *partition; |
795 | int ret; | ||
720 | 796 | ||
721 | list_for_each_entry(partition, &mux_partitions, node) { | 797 | list_for_each_entry(partition, &mux_partitions, node) { |
722 | struct omap_mux_entry *e, *tmp; | 798 | struct omap_mux_entry *e, *tmp; |
@@ -737,6 +813,13 @@ static int __init omap_mux_late_init(void) | |||
737 | } | 813 | } |
738 | } | 814 | } |
739 | 815 | ||
816 | ret = request_irq(omap_prcm_event_to_irq("io"), | ||
817 | omap_hwmod_mux_handle_irq, IRQF_SHARED | IRQF_NO_SUSPEND, | ||
818 | "hwmod_io", omap_mux_late_init); | ||
819 | |||
820 | if (ret) | ||
821 | pr_warning("mux: Failed to setup hwmod io irq %d\n", ret); | ||
822 | |||
740 | omap_mux_dbg_init(); | 823 | omap_mux_dbg_init(); |
741 | 824 | ||
742 | return 0; | 825 | return 0; |