From 96dc19fd03303ae1b9292d1f73aa8de597f4a183 Mon Sep 17 00:00:00 2001 From: Paul Walmsley Date: Fri, 16 Dec 2011 14:36:57 -0700 Subject: ARM: OMAP2+: mux: add wakeup-capable hwmod mux entries to dynamic list omap_hwmod_mux() currently only iterates through the dynamic pad list. This list currently only consists of pads with the OMAP_DEVICE_MUX_REMUX flag set. Subsequent patches in this series will cause hwmod mux entries with the OMAP_DEVICE_MUX_WAKEUP flag set to be changed dynamically, to control hwmod I/O ring wakeup. For this to work correctly, hwmod mux entries with the OMAP_DEVICE_MUX_WAKEUP flag set must also be added to the dynamic pad list. So this patch modifies omap_hwmod_mux_init() to do so. Signed-off-by: Paul Walmsley Cc: Tony Lindgren Cc: Tero Kristo Cc: Govindraj R Acked-by: Tony Lindgren --- arch/arm/mach-omap2/mux.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) (limited to 'arch/arm/mach-omap2/mux.c') diff --git a/arch/arm/mach-omap2/mux.c b/arch/arm/mach-omap2/mux.c index 655e9480eb98..a474c81355ec 100644 --- a/arch/arm/mach-omap2/mux.c +++ b/arch/arm/mach-omap2/mux.c @@ -306,7 +306,8 @@ omap_hwmod_mux_init(struct omap_device_pad *bpads, int nr_pads) pad->idle = bpad->idle; pad->off = bpad->off; - if (pad->flags & OMAP_DEVICE_PAD_REMUX) + if (pad->flags & + (OMAP_DEVICE_PAD_REMUX | OMAP_DEVICE_PAD_WAKEUP)) nr_pads_dynamic++; pr_debug("%s: Initialized %s\n", __func__, pad->name); @@ -331,7 +332,8 @@ omap_hwmod_mux_init(struct omap_device_pad *bpads, int nr_pads) for (i = 0; i < hmux->nr_pads; i++) { struct omap_device_pad *pad = &hmux->pads[i]; - if (pad->flags & OMAP_DEVICE_PAD_REMUX) { + if (pad->flags & + (OMAP_DEVICE_PAD_REMUX | OMAP_DEVICE_PAD_WAKEUP)) { pr_debug("%s: pad %s tagged dynamic\n", __func__, pad->name); hmux->pads_dynamic[nr_pads_dynamic] = pad; -- cgit v1.2.3 From 13a3fe52f7525d7b327f1f6766826fe9668bd749 Mon Sep 17 00:00:00 2001 From: Tero Kristo Date: Fri, 16 Dec 2011 14:36:59 -0700 Subject: 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 Cc: Govindraj.R Tested-by: Kevin Hilman Reviewed-by: Kevin Hilman Acked-by: Tony Lindgren [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 --- arch/arm/mach-omap2/mux.c | 83 ++++++++++++++++++++++++++++ arch/arm/plat-omap/include/plat/omap_hwmod.h | 1 + 2 files changed, 84 insertions(+) (limited to 'arch/arm/mach-omap2/mux.c') 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 @@ #include #include #include +#include +#include #include @@ -39,6 +41,7 @@ #include "control.h" #include "mux.h" +#include "prm.h" #define OMAP_MUX_BASE_OFFSET 0x30 /* Offset from CTRL_BASE */ #define OMAP_MUX_BASE_SZ 0x5ca @@ -353,6 +356,78 @@ err1: return NULL; } +/** + * omap_hwmod_mux_scan_wakeups - omap hwmod scan wakeup pads + * @hmux: Pads for a hwmod + * @mpu_irqs: MPU irq array for a hwmod + * + * Scans the wakeup status of pads for a single hwmod. If an irq + * array is defined for this mux, the parser will call the registered + * ISRs for corresponding pads, otherwise the parser will stop at the + * first wakeup active pad and return. Returns true if there is a + * pending and non-served wakeup event for the mux, otherwise false. + */ +static bool omap_hwmod_mux_scan_wakeups(struct omap_hwmod_mux_info *hmux, + struct omap_hwmod_irq_info *mpu_irqs) +{ + int i, irq; + unsigned int val; + u32 handled_irqs = 0; + + for (i = 0; i < hmux->nr_pads_dynamic; i++) { + struct omap_device_pad *pad = hmux->pads_dynamic[i]; + + if (!(pad->flags & OMAP_DEVICE_PAD_WAKEUP) || + !(pad->idle & OMAP_WAKEUP_EN)) + continue; + + val = omap_mux_read(pad->partition, pad->mux->reg_offset); + if (!(val & OMAP_WAKEUP_EVENT)) + continue; + + if (!hmux->irqs) + return true; + + irq = hmux->irqs[i]; + /* make sure we only handle each irq once */ + if (handled_irqs & 1 << irq) + continue; + + handled_irqs |= 1 << irq; + + generic_handle_irq(mpu_irqs[irq].irq); + } + + return false; +} + +/** + * _omap_hwmod_mux_handle_irq - Process wakeup events for a single hwmod + * + * Checks a single hwmod for every wakeup capable pad to see if there is an + * active wakeup event. If this is the case, call the corresponding ISR. + */ +static int _omap_hwmod_mux_handle_irq(struct omap_hwmod *oh, void *data) +{ + if (!oh->mux || !oh->mux->enabled) + return 0; + if (omap_hwmod_mux_scan_wakeups(oh->mux, oh->mpu_irqs)) + generic_handle_irq(oh->mpu_irqs[0].irq); + return 0; +} + +/** + * omap_hwmod_mux_handle_irq - Process pad wakeup irqs. + * + * Calls a function for each registered omap_hwmod to check + * pad wakeup statuses. + */ +static irqreturn_t omap_hwmod_mux_handle_irq(int irq, void *unused) +{ + omap_hwmod_for_each(_omap_hwmod_mux_handle_irq, NULL); + return IRQ_HANDLED; +} + /* Assumes the calling function takes care of locking */ void omap_hwmod_mux(struct omap_hwmod_mux_info *hmux, u8 state) { @@ -717,6 +792,7 @@ static void __init omap_mux_free_names(struct omap_mux *m) static int __init omap_mux_late_init(void) { struct omap_mux_partition *partition; + int ret; list_for_each_entry(partition, &mux_partitions, node) { struct omap_mux_entry *e, *tmp; @@ -737,6 +813,13 @@ static int __init omap_mux_late_init(void) } } + ret = request_irq(omap_prcm_event_to_irq("io"), + omap_hwmod_mux_handle_irq, IRQF_SHARED | IRQF_NO_SUSPEND, + "hwmod_io", omap_mux_late_init); + + if (ret) + pr_warning("mux: Failed to setup hwmod io irq %d\n", ret); + omap_mux_dbg_init(); return 0; diff --git a/arch/arm/plat-omap/include/plat/omap_hwmod.h b/arch/arm/plat-omap/include/plat/omap_hwmod.h index 8b372ede17c1..f7054926f4e7 100644 --- a/arch/arm/plat-omap/include/plat/omap_hwmod.h +++ b/arch/arm/plat-omap/include/plat/omap_hwmod.h @@ -97,6 +97,7 @@ struct omap_hwmod_mux_info { struct omap_device_pad *pads; int nr_pads_dynamic; struct omap_device_pad **pads_dynamic; + int *irqs; bool enabled; }; -- cgit v1.2.3 From 27d8d3bf06c574b8bc88d1cf50ed3e3b2c40935b Mon Sep 17 00:00:00 2001 From: Russell King Date: Tue, 7 Feb 2012 10:18:34 +0000 Subject: ARM: omap: fix section mismatch warning in mux.c WARNING: arch/arm/mach-omap2/built-in.o(.text+0x15a4): Section mismatch in reference from the function omap_mux_init_signals() to the function .init.text:omap_mux_init_signal() The function omap_mux_init_signals() references the function __init omap_mux_init_signal(). This is often because omap_mux_init_signals lacks a __init annotation or the annotation of omap_mux_init_signal is wrong. Acked-by: Tony Lindgren Signed-off-by: Russell King --- arch/arm/mach-omap2/mux.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'arch/arm/mach-omap2/mux.c') diff --git a/arch/arm/mach-omap2/mux.c b/arch/arm/mach-omap2/mux.c index e1cc75d1a57a..f26b2faa1694 100644 --- a/arch/arm/mach-omap2/mux.c +++ b/arch/arm/mach-omap2/mux.c @@ -1094,8 +1094,8 @@ static void omap_mux_init_package(struct omap_mux *superset, omap_mux_package_init_balls(package_balls, superset); } -static void omap_mux_init_signals(struct omap_mux_partition *partition, - struct omap_board_mux *board_mux) +static void __init omap_mux_init_signals(struct omap_mux_partition *partition, + struct omap_board_mux *board_mux) { omap_mux_set_cmdline_signals(); omap_mux_write_array(partition, board_mux); @@ -1109,8 +1109,8 @@ static void omap_mux_init_package(struct omap_mux *superset, { } -static void omap_mux_init_signals(struct omap_mux_partition *partition, - struct omap_board_mux *board_mux) +static void __init omap_mux_init_signals(struct omap_mux_partition *partition, + struct omap_board_mux *board_mux) { } -- cgit v1.2.3 From 8930b4e3c31cf67140e6281879b28feac8381e29 Mon Sep 17 00:00:00 2001 From: Russell King Date: Tue, 7 Feb 2012 10:51:39 +0000 Subject: ARM: omap: fix section mismatch warnings in mux.c caused by hsmmc.c The previous commit causes new section mismatch warnings: WARNING: arch/arm/mach-omap2/built-in.o(.text+0xdb30): Section mismatch in reference from the function omap_init_hsmmc() to the function .init.text:omap_mux_init_gpio() The function omap_init_hsmmc() references the function __init omap_mux_init_gpio(). This is often because omap_init_hsmmc lacks a __init annotation or the annotation of omap_mux_init_gpio is wrong. WARNING: arch/arm/mach-omap2/built-in.o(.text+0xdb4c): Section mismatch in reference from the function omap_init_hsmmc() to the function .init.text:omap_mux_init_gpio() The function omap_init_hsmmc() references the function __init omap_mux_init_gpio(). This is often because omap_init_hsmmc lacks a __init annotation or the annotation of omap_mux_init_gpio is wrong. WARNING: arch/arm/mach-omap2/built-in.o(.text+0xdb60): Section mismatch in reference from the function omap_init_hsmmc() to the function .init.text:omap_mux_init_signal() The function omap_init_hsmmc() references the function __init omap_mux_init_signal(). This is often because omap_init_hsmmc lacks a __init annotation or the annotation of omap_mux_init_signal is wrong. WARNING: arch/arm/mach-omap2/built-in.o(.text+0xdb6c): Section mismatch in reference from the function omap_init_hsmmc() to the function .init.text:omap_mux_init_signal() The function omap_init_hsmmc() references the function __init omap_mux_init_signal(). This is often because omap_init_hsmmc lacks a __init annotation or the annotation of omap_mux_init_signal is wrong. WARNING: arch/arm/mach-omap2/built-in.o(.text+0xdb78): Section mismatch in reference from the function omap_init_hsmmc() to the function .init.text:omap_mux_init_signal() The function omap_init_hsmmc() references the function __init omap_mux_init_signal(). This is often because omap_init_hsmmc lacks a __init annotation or the annotation of omap_mux_init_signal is wrong. WARNING: arch/arm/mach-omap2/built-in.o(.text+0xdb90): Section mismatch in reference from the function omap_init_hsmmc() to the function .init.text:omap_mux_init_signal() The function omap_init_hsmmc() references the function __init omap_mux_init_signal(). This is often because omap_init_hsmmc lacks a __init annotation or the annotation of omap_mux_init_signal is wrong. WARNING: arch/arm/mach-omap2/built-in.o(.text+0xdb9c): Section mismatch in reference from the function omap_init_hsmmc() to the function .init.text:omap_mux_init_signal() The function omap_init_hsmmc() references the function __init omap_mux_init_signal(). This is often because omap_init_hsmmc lacks a __init annotation or the annotation of omap_mux_init_signal is wrong. WARNING: arch/arm/mach-omap2/built-in.o(.text+0xdba8): Section mismatch in reference from the function omap_init_hsmmc() to the function .init.text:omap_mux_init_signal() The function omap_init_hsmmc() references the function __init omap_mux_init_signal(). This is often because omap_init_hsmmc lacks a __init annotation or the annotation of omap_mux_init_signal is wrong. WARNING: arch/arm/mach-omap2/built-in.o(.text+0xdbc0): Section mismatch in reference from the function omap_init_hsmmc() to the function .init.text:omap_mux_init_signal() The function omap_init_hsmmc() references the function __init omap_mux_init_signal(). This is often because omap_init_hsmmc lacks a __init annotation or the annotation of omap_mux_init_signal is wrong. WARNING: arch/arm/mach-omap2/built-in.o(.text+0xdbcc): Section mismatch in reference from the function omap_init_hsmmc() to the function .init.text:omap_mux_init_signal() The function omap_init_hsmmc() references the function __init omap_mux_init_signal(). This is often because omap_init_hsmmc lacks a __init annotation or the annotation of omap_mux_init_signal is wrong. WARNING: arch/arm/mach-omap2/built-in.o(.text+0xdbd8): Section mismatch in reference from the function omap_init_hsmmc() to the function .init.text:omap_mux_init_signal() The function omap_init_hsmmc() references the function __init omap_mux_init_signal(). This is often because omap_init_hsmmc lacks a __init annotation or the annotation of omap_mux_init_signal is wrong. WARNING: arch/arm/mach-omap2/built-in.o(.text+0xdbf8): Section mismatch in reference from the function omap_init_hsmmc() to the function .init.text:omap_mux_init_signal() The function omap_init_hsmmc() references the function __init omap_mux_init_signal(). This is often because omap_init_hsmmc lacks a __init annotation or the annotation of omap_mux_init_signal is wrong. WARNING: arch/arm/mach-omap2/built-in.o(.text+0xdc04): Section mismatch in reference from the function omap_init_hsmmc() to the function .init.text:omap_mux_init_signal() The function omap_init_hsmmc() references the function __init omap_mux_init_signal(). This is often because omap_init_hsmmc lacks a __init annotation or the annotation of omap_mux_init_signal is wrong. WARNING: arch/arm/mach-omap2/built-in.o(.text+0xdc10): Section mismatch in reference from the function omap_init_hsmmc() to the function .init.text:omap_mux_init_signal() The function omap_init_hsmmc() references the function __init omap_mux_init_signal(). This is often because omap_init_hsmmc lacks a __init annotation or the annotation of omap_mux_init_signal is wrong. WARNING: arch/arm/mach-omap2/built-in.o(.text+0xdc28): Section mismatch in reference from the function omap_init_hsmmc() to the function .init.text:omap_mux_init_signal() The function omap_init_hsmmc() references the function __init omap_mux_init_signal(). This is often because omap_init_hsmmc lacks a __init annotation or the annotation of omap_mux_init_signal is wrong. WARNING: arch/arm/mach-omap2/built-in.o(.text+0xdc34): Section mismatch in reference from the function omap_init_hsmmc() to the function .init.text:omap_mux_init_signal() The function omap_init_hsmmc() references the function __init omap_mux_init_signal(). This is often because omap_init_hsmmc lacks a __init annotation or the annotation of omap_mux_init_signal is wrong. WARNING: arch/arm/mach-omap2/built-in.o(.text+0xdc40): Section mismatch in reference from the function omap_init_hsmmc() to the function .init.text:omap_mux_init_signal() The function omap_init_hsmmc() references the function __init omap_mux_init_signal(). This is often because omap_init_hsmmc lacks a __init annotation or the annotation of omap_mux_init_signal is wrong. WARNING: arch/arm/mach-omap2/built-in.o(.text+0xdc58): Section mismatch in reference from the function omap_init_hsmmc() to the function .init.text:omap_mux_init_signal() The function omap_init_hsmmc() references the function __init omap_mux_init_signal(). This is often because omap_init_hsmmc lacks a __init annotation or the annotation of omap_mux_init_signal is wrong. WARNING: arch/arm/mach-omap2/built-in.o(.text+0xdc64): Section mismatch in reference from the function omap_init_hsmmc() to the function .init.text:omap_mux_init_signal() The function omap_init_hsmmc() references the function __init omap_mux_init_signal(). This is often because omap_init_hsmmc lacks a __init annotation or the annotation of omap_mux_init_signal is wrong. WARNING: arch/arm/mach-omap2/built-in.o(.text+0xdc70): Section mismatch in reference from the function omap_init_hsmmc() to the function .init.text:omap_mux_init_signal() The function omap_init_hsmmc() references the function __init omap_mux_init_signal(). This is often because omap_init_hsmmc lacks a __init annotation or the annotation of omap_mux_init_signal is wrong. WARNING: arch/arm/mach-omap2/built-in.o(.text+0xdc7c): Section mismatch in reference from the function omap_init_hsmmc() to the function .init.text:omap_mux_init_signal() The function omap_init_hsmmc() references the function __init omap_mux_init_signal(). This is often because omap_init_hsmmc lacks a __init annotation or the annotation of omap_mux_init_signal is wrong. Again, as for omap2_hsmmc_init(), these functions are callable at runtime via the gpio-twl4030.c driver, and so these can't be marked __init. Acked-by: Tony Lindgren Signed-off-by: Russell King --- arch/arm/mach-omap2/mux.c | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) (limited to 'arch/arm/mach-omap2/mux.c') diff --git a/arch/arm/mach-omap2/mux.c b/arch/arm/mach-omap2/mux.c index f26b2faa1694..fb8bc9fa43b1 100644 --- a/arch/arm/mach-omap2/mux.c +++ b/arch/arm/mach-omap2/mux.c @@ -100,8 +100,8 @@ void omap_mux_write_array(struct omap_mux_partition *partition, static char *omap_mux_options; -static int __init _omap_mux_init_gpio(struct omap_mux_partition *partition, - int gpio, int val) +static int _omap_mux_init_gpio(struct omap_mux_partition *partition, + int gpio, int val) { struct omap_mux_entry *e; struct omap_mux *gpio_mux = NULL; @@ -145,7 +145,7 @@ static int __init _omap_mux_init_gpio(struct omap_mux_partition *partition, return 0; } -int __init omap_mux_init_gpio(int gpio, int val) +int omap_mux_init_gpio(int gpio, int val) { struct omap_mux_partition *partition; int ret; @@ -159,9 +159,9 @@ int __init omap_mux_init_gpio(int gpio, int val) return -ENODEV; } -static int __init _omap_mux_get_by_name(struct omap_mux_partition *partition, - const char *muxname, - struct omap_mux **found_mux) +static int _omap_mux_get_by_name(struct omap_mux_partition *partition, + const char *muxname, + struct omap_mux **found_mux) { struct omap_mux *mux = NULL; struct omap_mux_entry *e; @@ -240,7 +240,7 @@ omap_mux_get_by_name(const char *muxname, return -ENODEV; } -int __init omap_mux_init_signal(const char *muxname, int val) +int omap_mux_init_signal(const char *muxname, int val) { struct omap_mux_partition *partition = NULL; struct omap_mux *mux = NULL; -- cgit v1.2.3 From 97899e555b76ce64222303bc8d46fda9d49eb14b Mon Sep 17 00:00:00 2001 From: Tony Lindgren Date: Mon, 20 Feb 2012 09:43:28 -0800 Subject: ARM: OMAP: Fix kernel panic with HSMMC when twl4030_gpio is a module On some omaps twl4030_gpio has a callback to try to initialize the MMC controller. If twl4030_gpio is compiled as a module, bad things can happen because the callback function starts calling functions that are supposed to be marked __init: Kernel panic - not syncing: Attempted to kill the idle task! twl4030_gpio twl4030_gpio: can't dispatch IRQs from modules gpiochip_add: registered GPIOs 192 to 209 on device: twl4030 Unable to handle kernel paging request at virtual address b82a4c74 ... Additionally if this does not fail, warnings are produced about trying to register the MMC multiple times. Fix this by removing __init from omap_mux_get_by_name, and add checks if omap2_hsmmc_init() is getting called more than once. Note that this will get fixed properly later on by splitting omap2_hsmmc_init into two functions. Reported-by: Russell King Signed-off-by: Tony Lindgren --- arch/arm/mach-omap2/hsmmc.c | 6 ++++++ arch/arm/mach-omap2/mux.c | 2 +- 2 files changed, 7 insertions(+), 1 deletion(-) (limited to 'arch/arm/mach-omap2/mux.c') diff --git a/arch/arm/mach-omap2/hsmmc.c b/arch/arm/mach-omap2/hsmmc.c index b40c28895298..19dd1657245c 100644 --- a/arch/arm/mach-omap2/hsmmc.c +++ b/arch/arm/mach-omap2/hsmmc.c @@ -428,6 +428,7 @@ static int omap_hsmmc_pdata_init(struct omap2_hsmmc_info *c, return 0; } +static int omap_hsmmc_done; #define MAX_OMAP_MMC_HWMOD_NAME_LEN 16 void omap_init_hsmmc(struct omap2_hsmmc_info *hsmmcinfo, int ctrl_nr) @@ -491,6 +492,11 @@ void omap2_hsmmc_init(struct omap2_hsmmc_info *controllers) { u32 reg; + if (omap_hsmmc_done) + return; + + omap_hsmmc_done = 1; + if (!cpu_is_omap44xx()) { if (cpu_is_omap2430()) { control_pbias_offset = OMAP243X_CONTROL_PBIAS_LITE; diff --git a/arch/arm/mach-omap2/mux.c b/arch/arm/mach-omap2/mux.c index fb8bc9fa43b1..611a0e3d54ca 100644 --- a/arch/arm/mach-omap2/mux.c +++ b/arch/arm/mach-omap2/mux.c @@ -218,7 +218,7 @@ static int _omap_mux_get_by_name(struct omap_mux_partition *partition, return -ENODEV; } -static int __init +static int omap_mux_get_by_name(const char *muxname, struct omap_mux_partition **found_partition, struct omap_mux **found_mux) -- cgit v1.2.3