Message ID | 4d34a0a70903152159y6b20bb57qfbab3f05399bd9a7@mail.gmail.com (mailing list archive) |
---|---|
State | Not Applicable |
Delegated to: | Kevin Hilman |
Headers | show |
Kim Kyuwon <chammoru@gmail.com> writes: > Hi, Kevin > > On Tue, Mar 10, 2009 at 2:21 AM, Kevin Hilman > <khilman@deeprootsystems.com> wrote: >> Kim Kyuwon <chammoru@gmail.com> writes: >> >>> Hi, Kevin Hilman. >>> >>> I'm sending this mail to tell you a few things about two recent >>> fetches that I sent. >>> >>> 1. [OMAP: GPIO: Remove enable_irq_wake() and disable_irq_wake() in >>> _set_gpio_wakeup() function] >>> I just found that you already sent the same patch in [OMAP2/3: GPIO: >>> remove recursion in IRQ wakeup path]. Sorry, I didn't know that. I >>> will cancel my patch. But can I know when your patch will be applied? >> >> I need to update the description of mine and resend after >> incorporating some review comments. >> >>> 2. [OMAP3: PM: Add the wakeup source driver] >>> Would you please review this patch? If something is unclear or need to >>> change, please let me know. I would answer with please. >> >> Yes, I will review this week. > > Can I ask again when I can get your review? :) Hi Kim, I'm sorry for the delay on reviewing your patch. I've been delaying because not only do I want to review it, I want to try it out. I will do both today. Kevin > And I'm resending the patch which is made for PM branch and added a > few trivial changes. > I really want to hear your opinion. > > Thanks & Regards, > > -- > Kyuwon > > -- > [PATCH] OMAP3: PM: Add the wakeup source driver > > Sometimes, it is necessary to find out "what does wake up my board?". > Notifying wake-up source feature may be used to blame unexpected > wake-up events which increase power consumption. And user mode > applications can act smartly according to the wake-up event to > minimize power consumption. This driver uses sysfs interface to give > information to user mode applications like: > > cat /sys/power/wakeup_irq > cat /sys/power/wakeup_event > > This driver also privides the unified GPIO wake-up source > configuration. specific GPIO settings in the board files are: > > /* Wakeup source configuration */ > static struct gpio_wake boardname_gpio_wake[] = { > { 23, IRQF_TRIGGER_RISING | IRQF_SHARED, "BT_WAKEUP", 1}, > { 24, IRQF_TRIGGER_RISING | IRQF_SHARED, "USB_DETECT", 1}, > }; > > static struct omap_wake_platform_data boardname_wake_data = { > .qpio_wakes = boardname_gpio_wake, > .gpio_wake_num = ARRAY_SIZE(boardname_gpio_wake), > }; > > static struct platform_device boardname_wakeup = { > .name = "omap-wake", > .id = -1, > .dev = { > .platform_data = &boardname_wake_data, > }, > }; > > The patch adds Kconfig options "OMAP34xx wakeup source support" under > "System type"->"TI OMAP implementations" menu. > > Signed-off-by: Kim Kyuwon <q1.kim@samsung.com> > --- > arch/arm/mach-omap2/Makefile | 1 + > arch/arm/mach-omap2/irq.c | 41 +++ > arch/arm/mach-omap2/prcm-common.h | 4 + > arch/arm/mach-omap2/prm-regbits-34xx.h | 6 + > arch/arm/mach-omap2/wake34xx.c | 474 ++++++++++++++++++++++++++++++++ > arch/arm/plat-omap/Kconfig | 9 + > arch/arm/plat-omap/include/mach/irqs.h | 1 + > arch/arm/plat-omap/include/mach/wake.h | 30 ++ > 8 files changed, 566 insertions(+), 0 deletions(-) > create mode 100644 arch/arm/mach-omap2/wake34xx.c > create mode 100644 arch/arm/plat-omap/include/mach/wake.h > > diff --git a/arch/arm/mach-omap2/Makefile b/arch/arm/mach-omap2/Makefile > index 16c6fb8..29ad0f1 100644 > --- a/arch/arm/mach-omap2/Makefile > +++ b/arch/arm/mach-omap2/Makefile > @@ -25,6 +25,7 @@ obj-$(CONFIG_ARCH_OMAP2) += pm24xx.o > obj-$(CONFIG_ARCH_OMAP24XX) += sleep24xx.o > obj-$(CONFIG_ARCH_OMAP3) += pm34xx.o sleep34xx.o cpuidle34xx.o > obj-$(CONFIG_PM_DEBUG) += pm-debug.o > +obj-$(CONFIG_OMAP_WAKE) += wake34xx.o > endif > > # SmartReflex driver > diff --git a/arch/arm/mach-omap2/irq.c b/arch/arm/mach-omap2/irq.c > index be4b596..e3a2b53 100644 > --- a/arch/arm/mach-omap2/irq.c > +++ b/arch/arm/mach-omap2/irq.c > @@ -193,6 +193,47 @@ int omap_irq_pending(void) > return 0; > } > > +/* > + * Get the first pending MPU IRQ number from 'irq_start'. > + * If none, return -1. > + */ > +int omap_get_pending_mpu_irq(unsigned int irq_start) > +{ > + struct omap_irq_bank *bank = irq_banks; > + int irq, bits_skip, bit_start; > + > + if (irq_start >= bank->nr_irqs) > + return -1; > + > + bits_skip = irq_start % IRQ_BITS_PER_REG; > + bit_start = irq_start - bits_skip; > + > + for (irq = bit_start; irq < bank->nr_irqs; irq += IRQ_BITS_PER_REG) { > + int ret, i, limit, offset = irq & (~(IRQ_BITS_PER_REG - 1)); > + > + ret = intc_bank_read_reg(bank, (INTC_PENDING_IRQ0 + offset)); > + if (!ret) > + continue; > + > + limit = IRQ_BITS_PER_REG; > + > + if (bit_start == irq) { > + ret >>= bits_skip; > + limit -= bits_skip; > + } else > + bits_skip = 0; > + > + for (i = 0; i < limit; i++) { > + if (ret & 0x1) > + return irq + i + bits_skip; > + else > + ret >>= 1; > + } > + } > + > + return -1; > +} > + > void __init omap_init_irq(void) > { > unsigned long nr_of_irqs = 0; > diff --git a/arch/arm/mach-omap2/prcm-common.h > b/arch/arm/mach-omap2/prcm-common.h > index cb1ae84..1f340aa 100644 > --- a/arch/arm/mach-omap2/prcm-common.h > +++ b/arch/arm/mach-omap2/prcm-common.h > @@ -273,6 +273,10 @@ > #define OMAP3430_ST_D2D_SHIFT 3 > #define OMAP3430_ST_D2D_MASK (1 << 3) > > +/* PM_WKST3_CORE, CM_IDLEST3_CORE shared bits */ > +#define OMAP3430_ST_USBTLL_SHIFT 2 > +#define OMAP3430_ST_USBTLL_MASK (1 << 2) > + > /* CM_FCLKEN_WKUP, CM_ICLKEN_WKUP, PM_WKEN_WKUP shared bits */ > #define OMAP3430_EN_GPIO1 (1 << 3) > #define OMAP3430_EN_GPIO1_SHIFT 3 > diff --git a/arch/arm/mach-omap2/prm-regbits-34xx.h > b/arch/arm/mach-omap2/prm-regbits-34xx.h > index cb648f9..6066032 100644 > --- a/arch/arm/mach-omap2/prm-regbits-34xx.h > +++ b/arch/arm/mach-omap2/prm-regbits-34xx.h > @@ -332,6 +332,8 @@ > /* PM_IVA2GRPSEL1_CORE specific bits */ > > /* PM_WKST1_CORE specific bits */ > +#define OMAP3430_ST_MMC3_SHIFT 30 > +#define OMAP3430_ST_MMC3_MASK (1 << 30) > > /* PM_PWSTCTRL_CORE specific bits */ > #define OMAP3430_MEM2ONSTATE_SHIFT 18 > @@ -373,6 +375,7 @@ > /* PM_IVA2GRPSEL_WKUP specific bits */ > > /* PM_WKST_WKUP specific bits */ > +#define OMAP3430_ST_IO_CHAIN (1 << 16) > #define OMAP3430_ST_IO (1 << 8) > > /* PRM_CLKSEL */ > @@ -430,6 +433,9 @@ > > /* PM_PREPWSTST_PER specific bits */ > > +/* PM_WKST_USBHOST specific bits */ > +#define OMAP3430_ST_USBHOST (1 << 0) > + > /* RM_RSTST_EMU specific bits */ > > /* PM_PWSTST_EMU specific bits */ > diff --git a/arch/arm/mach-omap2/wake34xx.c b/arch/arm/mach-omap2/wake34xx.c > new file mode 100644 > index 0000000..c352d08 > --- /dev/null > +++ b/arch/arm/mach-omap2/wake34xx.c > @@ -0,0 +1,474 @@ > +/* > + * wake34xx.c > + * > + * Copyright (c) 2009 Samsung Eletronics > + * > + * Author: Kim Kyuwon <q1.kim@samsung.com> > + * > + * This program is free software; you can redistribute it and/or modify > + * it under the terms of the GNU General Public License version 2 as > + * published by the Free Software Foundation. > + * > + */ > + > +#include <linux/kernel.h> > +#include <linux/init.h> > +#include <linux/platform_device.h> > +#include <linux/interrupt.h> > + > +#include <mach/gpio.h> > +#include <mach/wake.h> > + > +#include "prm-regbits-34xx.h" > + > +/* > + * Sometimes, it is necessary to find out "what does wake up my board?" > + * Notifying wake-up source feature may be used to blame unexpected wake-up > + * events which increase power consumption. And user mode applications can > + * act smartly according to the wake-up event to minimize power consumption. > + * This driver uses sysfs interface to give information to user mode > + * applications. > + */ > + > +#define WAKE_STR_LEN 64 > +#define WAKE_BUF_LEN 32 > + > +char wakeup_irq[WAKE_STR_LEN] = "None"; > +char wakeup_event[WAKE_STR_LEN] = "None"; > + > +struct wake_event { > + int index; > + const char *name; > +}; > + > +static struct wake_event omap3_wkup_events[] = { > + { OMAP3430_ST_IO_CHAIN, "ST_IO" }, > + { OMAP3430_ST_IO, "ST_SR2" }, > + { OMAP3430_ST_SR2_MASK, "ST_SR2" }, > + { OMAP3430_ST_SR1_MASK, "ST_SR1" }, > + { OMAP3430_ST_GPIO1_MASK, "ST_GPIO1" }, > + { OMAP3430_ST_GPT12_MASK, "ST_GPT12" }, > + { OMAP3430_ST_GPT1_MASK, "ST_GPT1" }, > +}; > + > +static struct wake_event omap3_per_events[] = { > + { OMAP3430_ST_GPIO6_MASK, "ST_GPIO6" }, > + { OMAP3430_ST_GPIO5_MASK, "ST_GPIO5" }, > + { OMAP3430_ST_GPIO4_MASK, "ST_GPIO4" }, > + { OMAP3430_ST_GPIO3_MASK, "ST_GPIO3" }, > + { OMAP3430_ST_GPIO2_MASK, "ST_GPIO2" }, > + { OMAP3430_ST_UART3_MASK, "ST_UART3" }, > + { OMAP3430_ST_GPT9_MASK, "ST_GPT9" }, > + { OMAP3430_ST_GPT8_MASK, "ST_GPT8" }, > + { OMAP3430_ST_GPT7_MASK, "ST_GPT7" }, > + { OMAP3430_ST_GPT6_MASK, "ST_GPT6" }, > + { OMAP3430_ST_GPT5_MASK, "ST_GPT5" }, > + { OMAP3430_ST_GPT4_MASK, "ST_GPT4" }, > + { OMAP3430_ST_GPT3_MASK, "ST_GPT3" }, > + { OMAP3430_ST_GPT2_MASK, "ST_GPT2" }, > + { OMAP3430_EN_MCBSP4, "EN_MCBSP4" }, > + { OMAP3430_EN_MCBSP3, "EN_MCBSP3" }, > + { OMAP3430_EN_MCBSP2, "EN_MCBSP2" }, > +}; > + > +static struct wake_event omap3_core1_events[] = { > + { OMAP3430_ST_MMC3_MASK, "ST_MMC3" }, > + { OMAP3430_ST_MMC2_MASK, "ST_MMC2" }, > + { OMAP3430_ST_MMC1_MASK, "ST_MMC1" }, > + { OMAP3430_ST_MCSPI4_MASK, "ST_MCSPI4" }, > + { OMAP3430_ST_MCSPI3_MASK, "ST_MCSPI3" }, > + { OMAP3430_ST_MCSPI2_MASK, "ST_MCSPI2" }, > + { OMAP3430_ST_MCSPI1_MASK, "ST_MCSPI1" }, > + { OMAP3430_ST_I2C3_MASK, "ST_I2C3" }, > + { OMAP3430_ST_I2C2_MASK, "ST_I2C2" }, > + { OMAP3430_ST_I2C1_MASK, "ST_I2C1" }, > + { OMAP3430_ST_UART1_MASK, "ST_UART1" }, > + { OMAP3430_ST_GPT11_MASK, "ST_GPT11" }, > + { OMAP3430_ST_GPT10_MASK, "ST_GPT10" }, > + { OMAP3430_ST_MCBSP5_MASK, "ST_MCBSP5" }, > + { OMAP3430_ST_MCBSP1_MASK, "ST_MCBSP1" }, > +}; > + > +static struct wake_event omap3es1_core1_events[] = { > + { OMAP3430ES1_ST_FSHOSTUSB_MASK, "ST_FSHOSTUSB" }, > + { OMAP3430ES1_ST_HSOTGUSB_MASK, "ST_HSOTGUSB" }, > + { OMAP3430_ST_D2D_MASK, "ST_D2D" }, > +}; > + > +static struct wake_event omap3es2_core1_events[] = { > + { OMAP3430ES2_ST_HSOTGUSB_STDBY_MASK, "ST_HSOTGUSB" }, > +}; > + > +static struct wake_event omap3_core2_events[] = { > + { OMAP3430_ST_USBTLL_MASK, "ST_USBTLL" }, > +}; > + > +static struct wake_event omap3_usbhost_events[] = { > + { OMAP3430_ST_USBHOST, "ST_USBHOST" }, > +}; > + > +static ssize_t wakeup_source_show(struct kobject *kobj, > + struct kobj_attribute *attr, char *buf); > + > +static void omap_wake_update_event(char *event) > +{ > + int len; > + > + if (wakeup_event[0]) > + len = strlen(wakeup_event) + strlen(event) + 2; > + else > + len = strlen(wakeup_event) + strlen(event); > + > + if (len > WAKE_STR_LEN - 1) { > + printk(KERN_ERR "Can't record the wakeup event: %s\n", event); > + return; > + } > + > + if (wakeup_event[0]) > + strcat(wakeup_event, ", "); > + strcat(wakeup_event, event); > +} > + > +static void omap_wake_detect_wkup(u32 wkst, char *event) > +{ > + int i; > + > + for (i = 0; i < ARRAY_SIZE(omap3_wkup_events); i++) > + if (wkst & omap3_wkup_events[i].index) { > + strncpy(event, omap3_wkup_events[i].name, > + WAKE_BUF_LEN - 1); > + return; > + } > + > + snprintf(event, WAKE_BUF_LEN, "WKUP:0x%08x", wkst); > +} > + > +static void omap_wake_detect_per(u32 wkst, char *event) > +{ > + int i; > + > + for (i = 0; i < ARRAY_SIZE(omap3_per_events); i++) > + if (wkst & omap3_per_events[i].index) { > + strncpy(event, omap3_per_events[i].name, > + WAKE_BUF_LEN - 1); > + return; > + } > + > + snprintf(event, WAKE_BUF_LEN, "PER:0x%08x", wkst); > +} > + > +static void omap_wake_detect_core1(u32 wkst, char *event) > +{ > + int i; > + > + for (i = 0; i < ARRAY_SIZE(omap3_core1_events); i++) > + if (wkst & omap3_core1_events[i].index) { > + strncpy(event, omap3_core1_events[i].name, > + WAKE_BUF_LEN - 1); > + return; > + } > + > + if (omap_rev() == OMAP3430_REV_ES1_0) { > + for (i = 0; i < ARRAY_SIZE(omap3es1_core1_events); i++) { > + if (wkst & omap3es1_core1_events[i].index) { > + strncpy(event, omap3es1_core1_events[i].name, > + WAKE_BUF_LEN - 1); > + return; > + } > + } > + } else { > + for (i = 0; i < ARRAY_SIZE(omap3es2_core1_events); i++) { > + if (wkst & omap3es2_core1_events[i].index) { > + strncpy(event, omap3es2_core1_events[i].name, > + WAKE_BUF_LEN - 1); > + return; > + } > + } > + } > + > + snprintf(event, WAKE_BUF_LEN, "CORE1:0x%08x", wkst); > +} > + > +static void omap_wake_detect_core2(u32 wkst, char *event) > +{ > + int i; > + > + for (i = 0; i < ARRAY_SIZE(omap3_core2_events); i++) > + if (wkst & omap3_core2_events[i].index) { > + strncpy(event, omap3_core2_events[i].name, > + WAKE_BUF_LEN - 1); > + return; > + } > + > + snprintf(event, WAKE_BUF_LEN, "CORE2:0x%08x", wkst); > +} > + > +static void omap_wake_detect_usbhost(u32 wkst, char *event) > +{ > + int i; > + > + for (i = 0; i < ARRAY_SIZE(omap3_usbhost_events); i++) > + if (wkst & omap3_usbhost_events[i].index) { > + strncpy(event, omap3_usbhost_events[i].name, > + WAKE_BUF_LEN - 1); > + return; > + } > + > + snprintf(event, WAKE_BUF_LEN, "USBHOST:0x%08x", wkst); > +} > + > +/* Detect wake-up events */ > +static void omap_wake_detect_wakeup(void) > +{ > + u32 wkst; > + char buf[WAKE_BUF_LEN] = {0, }; > + int irq, len, prcm_irq = 0; > + > + /* Initialize global string variables */ > + memset(wakeup_irq, 0x0, WAKE_STR_LEN); > + memset(wakeup_event, 0x0, WAKE_STR_LEN); > + > + /* IRQ */ > + irq = omap_get_pending_mpu_irq(0); > + while (irq >= 0) { > + if (irq == INT_34XX_SYS_NIRQ) > + omap_wake_update_event("sys_nirq"); > + else if (irq == INT_34XX_PRCM_MPU_IRQ) > + prcm_irq = 1; > + > + len = strlen(wakeup_irq) + > + snprintf(buf, WAKE_BUF_LEN, "%d", irq); > + if (len > WAKE_STR_LEN - 1) > + break; > + > + strcat(wakeup_irq, buf); > + > + irq = omap_get_pending_mpu_irq(irq + 1); > + if (irq >= 0) { > + len = strlen(wakeup_irq) + 2; > + if (len > WAKE_STR_LEN - 1) > + break; > + > + strcat(wakeup_irq, ", "); > + } > + } > + if (!wakeup_irq[0]) > + strncpy(wakeup_irq, "Unknown", WAKE_STR_LEN - 1); > + printk(KERN_INFO "Wake-up IRQ: %s\n", wakeup_irq); > + > + if (!prcm_irq) > + goto end_detect; > + > + /* WKUP */ > + wkst = prm_read_mod_reg(WKUP_MOD, PM_WKST); > + if (wkst) { > + omap_wake_detect_wkup(wkst, buf); > + omap_wake_update_event(buf); > + } > + > + /* PER */ > + wkst = prm_read_mod_reg(OMAP3430_PER_MOD, PM_WKST); > + if (wkst) { > + omap_wake_detect_per(wkst, buf); > + omap_wake_update_event(buf); > + } > + > + /* CORE */ > + wkst = prm_read_mod_reg(CORE_MOD, PM_WKST1); > + if (wkst) { > + omap_wake_detect_core1(wkst, buf); > + omap_wake_update_event(buf); > + } > + wkst = prm_read_mod_reg(CORE_MOD, OMAP3430ES2_PM_WKST3); > + if (wkst) { > + omap_wake_detect_core2(wkst, buf); > + omap_wake_update_event(buf); > + } > + > + /* USBHOST */ > + wkst = prm_read_mod_reg(OMAP3430ES2_USBHOST_MOD, PM_WKST); > + if (wkst) { > + omap_wake_detect_usbhost(wkst, buf); > + omap_wake_update_event(buf); > + } > + > +end_detect: > + if (!wakeup_event[0]) > + strncpy(wakeup_event, "Unknown", WAKE_STR_LEN - 1); > +} > + > +static struct kobj_attribute wakeup_irq_attr = > + __ATTR(wakeup_irq, 0644, wakeup_source_show, NULL); > + > +static struct kobj_attribute wakeup_event_attr = > + __ATTR(wakeup_event, 0644, wakeup_source_show, NULL); > + > +static ssize_t wakeup_source_show(struct kobject *kobj, > + struct kobj_attribute *attr, char *buf) > +{ > + if (attr == &wakeup_irq_attr) > + return sprintf(buf, "%s\n", wakeup_irq); > + else if (attr == &wakeup_event_attr) > + return sprintf(buf, "%s\n", wakeup_event); > + else > + return -EINVAL; > +} > + > +static irqreturn_t omap_wake_detect_gpio(int irq, void *dev_id) > +{ > + if (!strncmp(wakeup_event, "Unknown", WAKE_STR_LEN - 1)) > + strncpy(wakeup_event, dev_id, WAKE_STR_LEN - 1); > + else > + omap_wake_update_event(dev_id); > + > + return IRQ_HANDLED; > +} > + > +static int __devinit omap_wake_probe(struct platform_device *pdev) > +{ > + struct omap_wake_platform_data *pdata = pdev->dev.platform_data; > + struct gpio_wake *gw; > + int i, ret; > + > + /* > + * It may be good to configure GPIO wake-up sources in each driver. > + * Buf if the specific device driver doesn't exist, you can use > + * omap-wake driver to configure gpio wake-up sources. > + */ > + for (i = 0; i < pdata->gpio_wake_num; i++) { > + gw = pdata->qpio_wakes + i; > + > + if (gw->request) { > + ret = gpio_request(gw->gpio, gw->name); > + if (ret) { > + dev_err(&pdev->dev, "can't request gpio%d" > + ", return %d\n", gw->gpio, ret); > + goto failed_free_gpio; > + } > + } > + gpio_direction_input(gw->gpio); > + enable_irq_wake(gpio_to_irq(gw->gpio)); > + } > + > + ret = sysfs_create_file(power_kobj, &wakeup_irq_attr.attr); > + if (ret) > + dev_err(&pdev->dev, "sysfs_create_file %s failed: %d\n", > + wakeup_irq_attr.attr.name, ret); > + > + ret = sysfs_create_file(power_kobj, &wakeup_event_attr.attr); > + if (ret) > + dev_err(&pdev->dev, "sysfs_create_file %s failed: %d\n", > + wakeup_event_attr.attr.name, ret); > + > + return 0; > + > +failed_free_gpio: > + for (i--; i >= 0; i--) { > + gw = pdata->qpio_wakes + i; > + > + if (gw->request) > + gpio_free(gw->gpio); > + } > + > + return ret; > +} > + > +static int __devexit omap_wake_remove(struct platform_device *pdev) > +{ > + struct omap_wake_platform_data *pdata = pdev->dev.platform_data; > + struct gpio_wake *gw; > + int i; > + > + for (i = 0; i < pdata->gpio_wake_num; i++) { > + gw = pdata->qpio_wakes + i; > + > + if (gw->request) > + gpio_free(gw->gpio); > + > + disable_irq_wake(gpio_to_irq(gw->gpio)); > + } > + > + return 0; > +} > + > +static int omap_wake_suspend(struct platform_device *pdev, pm_message_t state) > +{ > + struct omap_wake_platform_data *pdata = pdev->dev.platform_data; > + struct gpio_wake *gw; > + int i, ret; > + > + for (i = 0; i < pdata->gpio_wake_num; i++) { > + gw = pdata->qpio_wakes + i; > + > + ret = request_irq(gpio_to_irq(gw->gpio), omap_wake_detect_gpio, > + gw->irqflag, gw->name, (void *)gw->name); > + if (ret) { > + dev_err(&pdev->dev, "can't get IRQ%d, return %d\n", > + gpio_to_irq(gw->gpio), ret); > + goto failed_free_irq; > + } > + } > + > + return 0; > + > +failed_free_irq: > + for (i--; i >= 0; i--) { > + gw = pdata->qpio_wakes + i; > + free_irq(gpio_to_irq(gw->gpio), (void *)gw->name); > + } > + > + return ret; > +} > + > +static int omap_wake_resume_early(struct platform_device *pdev) > +{ > + omap_wake_detect_wakeup(); > + > + return 0; > +} > + > +static int omap_wake_resume(struct platform_device *pdev) > +{ > + struct omap_wake_platform_data *pdata = pdev->dev.platform_data; > + struct gpio_wake *gw; > + int i; > + > + for (i = 0; i < pdata->gpio_wake_num; i++) { > + gw = pdata->qpio_wakes + i; > + > + free_irq(gpio_to_irq(gw->gpio), (void *)gw->name); > + } > + > + printk(KERN_INFO "Wake-up event: %s\n", wakeup_event); > + > + return 0; > +} > + > +static struct platform_driver omap_wake_driver = { > + .probe = omap_wake_probe, > + .remove = __devexit_p(omap_wake_remove), > + .suspend = omap_wake_suspend, > + .resume_early = omap_wake_resume_early, > + .resume = omap_wake_resume, > + .driver = { > + .name = "omap-wake", > + .owner = THIS_MODULE, > + }, > +}; > + > +static int __init omap_wake_init(void) > +{ > + return platform_driver_register(&omap_wake_driver); > +} > + > +module_init(omap_wake_init); > + > +static void __exit omap_wake_exit(void) > +{ > + platform_driver_unregister(&omap_wake_driver); > +} > +module_exit(omap_wake_exit); > + > +MODULE_AUTHOR("Kim Kyuwon <q1.kim@samsung.com>"); > +MODULE_DESCRIPTION("OMAP34xx wakeup driver"); > +MODULE_LICENSE("GPL v2"); > diff --git a/arch/arm/plat-omap/Kconfig b/arch/arm/plat-omap/Kconfig > index b8f1298..f89efaa 100644 > --- a/arch/arm/plat-omap/Kconfig > +++ b/arch/arm/plat-omap/Kconfig > @@ -184,6 +184,15 @@ config OMAP_IOMMU > Say Y here if you want to use OMAP IOMMU support for IVA2 and > Camera in OMAP3. > > +config OMAP_WAKE > + tristate "OMAP34xx wakeup source support" > + depends on ARCH_OMAP34XX && PM > + default n > + help > + Select this option if you want to know what kind of wake-up event > + wakes up your board from the low power mode. And this option > + provides the unified GPIO wake-up source configuration. > + > choice > prompt "System timer" > default OMAP_MPU_TIMER > diff --git a/arch/arm/plat-omap/include/mach/irqs.h > b/arch/arm/plat-omap/include/mach/irqs.h > index c9a5b19..d7961d4 100644 > --- a/arch/arm/plat-omap/include/mach/irqs.h > +++ b/arch/arm/plat-omap/include/mach/irqs.h > @@ -388,6 +388,7 @@ > #ifndef __ASSEMBLY__ > extern void omap_init_irq(void); > extern int omap_irq_pending(void); > +extern int omap_get_pending_mpu_irq(unsigned int irq_start); > void omap3_intc_save_context(void); > void omap3_intc_restore_context(void); > #endif > diff --git a/arch/arm/plat-omap/include/mach/wake.h > b/arch/arm/plat-omap/include/mach/wake.h > new file mode 100644 > index 0000000..713d89a > --- /dev/null > +++ b/arch/arm/plat-omap/include/mach/wake.h > @@ -0,0 +1,30 @@ > +/* > + * wake.h > + * > + * Copyright (c) 2009 Samsung Eletronics > + * > + * Author: Kim Kyuwon <q1.kim@samsung.com> > + * > + * This program is free software; you can redistribute it and/or modify > + * it under the terms of the GNU General Public License version 2 as > + * published by the Free Software Foundation. > + * > + */ > + > +#ifndef _WAKE_H_ > +#define _WAKE_H_ > + > +struct gpio_wake { > + unsigned int gpio; > + unsigned long irqflag; > + const char *name; > + int request; > +}; > + > +struct omap_wake_platform_data{ > + struct gpio_wake *qpio_wakes; > + int gpio_wake_num; > +}; > + > +#endif /* _WAKE_H_ */ > + > -- > 1.5.2.5 -- To unsubscribe from this list: send the line "unsubscribe linux-omap" in the body of a message to majordomo@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
diff --git a/arch/arm/mach-omap2/Makefile b/arch/arm/mach-omap2/Makefile index 16c6fb8..29ad0f1 100644 --- a/arch/arm/mach-omap2/Makefile +++ b/arch/arm/mach-omap2/Makefile @@ -25,6 +25,7 @@ obj-$(CONFIG_ARCH_OMAP2) += pm24xx.o obj-$(CONFIG_ARCH_OMAP24XX) += sleep24xx.o obj-$(CONFIG_ARCH_OMAP3) += pm34xx.o sleep34xx.o cpuidle34xx.o obj-$(CONFIG_PM_DEBUG) += pm-debug.o +obj-$(CONFIG_OMAP_WAKE) += wake34xx.o endif # SmartReflex driver diff --git a/arch/arm/mach-omap2/irq.c b/arch/arm/mach-omap2/irq.c index be4b596..e3a2b53 100644 --- a/arch/arm/mach-omap2/irq.c +++ b/arch/arm/mach-omap2/irq.c @@ -193,6 +193,47 @@ int omap_irq_pending(void) return 0; } +/* + * Get the first pending MPU IRQ number from 'irq_start'. + * If none, return -1. + */ +int omap_get_pending_mpu_irq(unsigned int irq_start) +{ + struct omap_irq_bank *bank = irq_banks; + int irq, bits_skip, bit_start; + + if (irq_start >= bank->nr_irqs) + return -1; + + bits_skip = irq_start % IRQ_BITS_PER_REG; + bit_start = irq_start - bits_skip; + + for (irq = bit_start; irq < bank->nr_irqs; irq += IRQ_BITS_PER_REG) { + int ret, i, limit, offset = irq & (~(IRQ_BITS_PER_REG - 1)); + + ret = intc_bank_read_reg(bank, (INTC_PENDING_IRQ0 + offset)); + if (!ret) + continue; + + limit = IRQ_BITS_PER_REG; + + if (bit_start == irq) { + ret >>= bits_skip; + limit -= bits_skip; + } else + bits_skip = 0; + + for (i = 0; i < limit; i++) { + if (ret & 0x1) + return irq + i + bits_skip; + else + ret >>= 1; + } + } + + return -1; +} + void __init omap_init_irq(void) { unsigned long nr_of_irqs = 0; diff --git a/arch/arm/mach-omap2/prcm-common.h b/arch/arm/mach-omap2/prcm-common.h index cb1ae84..1f340aa 100644 --- a/arch/arm/mach-omap2/prcm-common.h +++ b/arch/arm/mach-omap2/prcm-common.h @@ -273,6 +273,10 @@ #define OMAP3430_ST_D2D_SHIFT 3 #define OMAP3430_ST_D2D_MASK (1 << 3) +/* PM_WKST3_CORE, CM_IDLEST3_CORE shared bits */ +#define OMAP3430_ST_USBTLL_SHIFT 2 +#define OMAP3430_ST_USBTLL_MASK (1 << 2) + /* CM_FCLKEN_WKUP, CM_ICLKEN_WKUP, PM_WKEN_WKUP shared bits */ #define OMAP3430_EN_GPIO1 (1 << 3) #define OMAP3430_EN_GPIO1_SHIFT 3 diff --git a/arch/arm/mach-omap2/prm-regbits-34xx.h b/arch/arm/mach-omap2/prm-regbits-34xx.h index cb648f9..6066032 100644 --- a/arch/arm/mach-omap2/prm-regbits-34xx.h +++ b/arch/arm/mach-omap2/prm-regbits-34xx.h @@ -332,6 +332,8 @@ /* PM_IVA2GRPSEL1_CORE specific bits */ /* PM_WKST1_CORE specific bits */ +#define OMAP3430_ST_MMC3_SHIFT 30 +#define OMAP3430_ST_MMC3_MASK (1 << 30) /* PM_PWSTCTRL_CORE specific bits */ #define OMAP3430_MEM2ONSTATE_SHIFT 18 @@ -373,6 +375,7 @@ /* PM_IVA2GRPSEL_WKUP specific bits */ /* PM_WKST_WKUP specific bits */ +#define OMAP3430_ST_IO_CHAIN (1 << 16) #define OMAP3430_ST_IO (1 << 8) /* PRM_CLKSEL */ @@ -430,6 +433,9 @@ /* PM_PREPWSTST_PER specific bits */ +/* PM_WKST_USBHOST specific bits */ +#define OMAP3430_ST_USBHOST (1 << 0) + /* RM_RSTST_EMU specific bits */ /* PM_PWSTST_EMU specific bits */ diff --git a/arch/arm/mach-omap2/wake34xx.c b/arch/arm/mach-omap2/wake34xx.c new file mode 100644 index 0000000..c352d08 --- /dev/null +++ b/arch/arm/mach-omap2/wake34xx.c @@ -0,0 +1,474 @@ +/* + * wake34xx.c + * + * Copyright (c) 2009 Samsung Eletronics + * + * Author: Kim Kyuwon <q1.kim@samsung.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + */ + +#include <linux/kernel.h> +#include <linux/init.h> +#include <linux/platform_device.h> +#include <linux/interrupt.h> + +#include <mach/gpio.h> +#include <mach/wake.h> + +#include "prm-regbits-34xx.h" + +/* + * Sometimes, it is necessary to find out "what does wake up my board?" + * Notifying wake-up source feature may be used to blame unexpected wake-up + * events which increase power consumption. And user mode applications can + * act smartly according to the wake-up event to minimize power consumption. + * This driver uses sysfs interface to give information to user mode + * applications. + */ + +#define WAKE_STR_LEN 64 +#define WAKE_BUF_LEN 32 + +char wakeup_irq[WAKE_STR_LEN] = "None"; +char wakeup_event[WAKE_STR_LEN] = "None"; + +struct wake_event { + int index; + const char *name; +}; + +static struct wake_event omap3_wkup_events[] = { + { OMAP3430_ST_IO_CHAIN, "ST_IO" }, + { OMAP3430_ST_IO, "ST_SR2" }, + { OMAP3430_ST_SR2_MASK, "ST_SR2" }, + { OMAP3430_ST_SR1_MASK, "ST_SR1" }, + { OMAP3430_ST_GPIO1_MASK, "ST_GPIO1" }, + { OMAP3430_ST_GPT12_MASK, "ST_GPT12" }, + { OMAP3430_ST_GPT1_MASK, "ST_GPT1" }, +}; + +static struct wake_event omap3_per_events[] = { + { OMAP3430_ST_GPIO6_MASK, "ST_GPIO6" }, + { OMAP3430_ST_GPIO5_MASK, "ST_GPIO5" }, + { OMAP3430_ST_GPIO4_MASK, "ST_GPIO4" }, + { OMAP3430_ST_GPIO3_MASK, "ST_GPIO3" }, + { OMAP3430_ST_GPIO2_MASK, "ST_GPIO2" }, + { OMAP3430_ST_UART3_MASK, "ST_UART3" }, + { OMAP3430_ST_GPT9_MASK, "ST_GPT9" }, + { OMAP3430_ST_GPT8_MASK, "ST_GPT8" }, + { OMAP3430_ST_GPT7_MASK, "ST_GPT7" }, + { OMAP3430_ST_GPT6_MASK, "ST_GPT6" }, + { OMAP3430_ST_GPT5_MASK, "ST_GPT5" }, + { OMAP3430_ST_GPT4_MASK, "ST_GPT4" }, + { OMAP3430_ST_GPT3_MASK, "ST_GPT3" }, + { OMAP3430_ST_GPT2_MASK, "ST_GPT2" }, + { OMAP3430_EN_MCBSP4, "EN_MCBSP4" }, + { OMAP3430_EN_MCBSP3, "EN_MCBSP3" }, + { OMAP3430_EN_MCBSP2, "EN_MCBSP2" }, +}; + +static struct wake_event omap3_core1_events[] = { + { OMAP3430_ST_MMC3_MASK, "ST_MMC3" }, + { OMAP3430_ST_MMC2_MASK, "ST_MMC2" }, + { OMAP3430_ST_MMC1_MASK, "ST_MMC1" }, + { OMAP3430_ST_MCSPI4_MASK, "ST_MCSPI4" }, + { OMAP3430_ST_MCSPI3_MASK, "ST_MCSPI3" }, + { OMAP3430_ST_MCSPI2_MASK, "ST_MCSPI2" }, + { OMAP3430_ST_MCSPI1_MASK, "ST_MCSPI1" }, + { OMAP3430_ST_I2C3_MASK, "ST_I2C3" }, + { OMAP3430_ST_I2C2_MASK, "ST_I2C2" }, + { OMAP3430_ST_I2C1_MASK, "ST_I2C1" }, + { OMAP3430_ST_UART1_MASK, "ST_UART1" }, + { OMAP3430_ST_GPT11_MASK, "ST_GPT11" }, + { OMAP3430_ST_GPT10_MASK, "ST_GPT10" }, + { OMAP3430_ST_MCBSP5_MASK, "ST_MCBSP5" }, + { OMAP3430_ST_MCBSP1_MASK, "ST_MCBSP1" }, +}; + +static struct wake_event omap3es1_core1_events[] = { + { OMAP3430ES1_ST_FSHOSTUSB_MASK, "ST_FSHOSTUSB" }, + { OMAP3430ES1_ST_HSOTGUSB_MASK, "ST_HSOTGUSB" }, + { OMAP3430_ST_D2D_MASK, "ST_D2D" }, +}; + +static struct wake_event omap3es2_core1_events[] = { + { OMAP3430ES2_ST_HSOTGUSB_STDBY_MASK, "ST_HSOTGUSB" }, +}; + +static struct wake_event omap3_core2_events[] = { + { OMAP3430_ST_USBTLL_MASK, "ST_USBTLL" }, +}; + +static struct wake_event omap3_usbhost_events[] = { + { OMAP3430_ST_USBHOST, "ST_USBHOST" }, +}; + +static ssize_t wakeup_source_show(struct kobject *kobj, + struct kobj_attribute *attr, char *buf); + +static void omap_wake_update_event(char *event) +{ + int len; + + if (wakeup_event[0]) + len = strlen(wakeup_event) + strlen(event) + 2; + else + len = strlen(wakeup_event) + strlen(event); + + if (len > WAKE_STR_LEN - 1) { + printk(KERN_ERR "Can't record the wakeup event: %s\n", event); + return; + } + + if (wakeup_event[0]) + strcat(wakeup_event, ", "); + strcat(wakeup_event, event); +} + +static void omap_wake_detect_wkup(u32 wkst, char *event) +{ + int i; + + for (i = 0; i < ARRAY_SIZE(omap3_wkup_events); i++) + if (wkst & omap3_wkup_events[i].index) { + strncpy(event, omap3_wkup_events[i].name, + WAKE_BUF_LEN - 1); + return; + } + + snprintf(event, WAKE_BUF_LEN, "WKUP:0x%08x", wkst); +} + +static void omap_wake_detect_per(u32 wkst, char *event) +{ + int i; + + for (i = 0; i < ARRAY_SIZE(omap3_per_events); i++) + if (wkst & omap3_per_events[i].index) { + strncpy(event, omap3_per_events[i].name, + WAKE_BUF_LEN - 1); + return; + } + + snprintf(event, WAKE_BUF_LEN, "PER:0x%08x", wkst); +} + +static void omap_wake_detect_core1(u32 wkst, char *event) +{ + int i; + + for (i = 0; i < ARRAY_SIZE(omap3_core1_events); i++) + if (wkst & omap3_core1_events[i].index) { + strncpy(event, omap3_core1_events[i].name, + WAKE_BUF_LEN - 1); + return; + } + + if (omap_rev() == OMAP3430_REV_ES1_0) { + for (i = 0; i < ARRAY_SIZE(omap3es1_core1_events); i++) { + if (wkst & omap3es1_core1_events[i].index) { + strncpy(event, omap3es1_core1_events[i].name, + WAKE_BUF_LEN - 1); + return; + } + } + } else { + for (i = 0; i < ARRAY_SIZE(omap3es2_core1_events); i++) { + if (wkst & omap3es2_core1_events[i].index) { + strncpy(event, omap3es2_core1_events[i].name, + WAKE_BUF_LEN - 1); + return; + } + } + } + + snprintf(event, WAKE_BUF_LEN, "CORE1:0x%08x", wkst); +} + +static void omap_wake_detect_core2(u32 wkst, char *event) +{ + int i; + + for (i = 0; i < ARRAY_SIZE(omap3_core2_events); i++) + if (wkst & omap3_core2_events[i].index) { + strncpy(event, omap3_core2_events[i].name, + WAKE_BUF_LEN - 1); + return; + } + + snprintf(event, WAKE_BUF_LEN, "CORE2:0x%08x", wkst); +} + +static void omap_wake_detect_usbhost(u32 wkst, char *event) +{ + int i; + + for (i = 0; i < ARRAY_SIZE(omap3_usbhost_events); i++) + if (wkst & omap3_usbhost_events[i].index) { + strncpy(event, omap3_usbhost_events[i].name, + WAKE_BUF_LEN - 1); + return; + } + + snprintf(event, WAKE_BUF_LEN, "USBHOST:0x%08x", wkst); +} + +/* Detect wake-up events */ +static void omap_wake_detect_wakeup(void) +{ + u32 wkst; + char buf[WAKE_BUF_LEN] = {0, }; + int irq, len, prcm_irq = 0; + + /* Initialize global string variables */ + memset(wakeup_irq, 0x0, WAKE_STR_LEN); + memset(wakeup_event, 0x0, WAKE_STR_LEN); + + /* IRQ */ + irq = omap_get_pending_mpu_irq(0); + while (irq >= 0) { + if (irq == INT_34XX_SYS_NIRQ) + omap_wake_update_event("sys_nirq"); + else if (irq == INT_34XX_PRCM_MPU_IRQ) + prcm_irq = 1; + + len = strlen(wakeup_irq) + + snprintf(buf, WAKE_BUF_LEN, "%d", irq); + if (len > WAKE_STR_LEN - 1) + break; + + strcat(wakeup_irq, buf); + + irq = omap_get_pending_mpu_irq(irq + 1); + if (irq >= 0) { + len = strlen(wakeup_irq) + 2; + if (len > WAKE_STR_LEN - 1) + break; + + strcat(wakeup_irq, ", "); + } + } + if (!wakeup_irq[0]) + strncpy(wakeup_irq, "Unknown", WAKE_STR_LEN - 1); + printk(KERN_INFO "Wake-up IRQ: %s\n", wakeup_irq); + + if (!prcm_irq) + goto end_detect; + + /* WKUP */ + wkst = prm_read_mod_reg(WKUP_MOD, PM_WKST); + if (wkst) { + omap_wake_detect_wkup(wkst, buf); + omap_wake_update_event(buf); + } + + /* PER */ + wkst = prm_read_mod_reg(OMAP3430_PER_MOD, PM_WKST); + if (wkst) { + omap_wake_detect_per(wkst, buf); + omap_wake_update_event(buf); + } + + /* CORE */ + wkst = prm_read_mod_reg(CORE_MOD, PM_WKST1); + if (wkst) { + omap_wake_detect_core1(wkst, buf); + omap_wake_update_event(buf); + } + wkst = prm_read_mod_reg(CORE_MOD, OMAP3430ES2_PM_WKST3); + if (wkst) { + omap_wake_detect_core2(wkst, buf); + omap_wake_update_event(buf); + } + + /* USBHOST */ + wkst = prm_read_mod_reg(OMAP3430ES2_USBHOST_MOD, PM_WKST); + if (wkst) { + omap_wake_detect_usbhost(wkst, buf); + omap_wake_update_event(buf); + } + +end_detect: + if (!wakeup_event[0]) + strncpy(wakeup_event, "Unknown", WAKE_STR_LEN - 1); +} + +static struct kobj_attribute wakeup_irq_attr = + __ATTR(wakeup_irq, 0644, wakeup_source_show, NULL); + +static struct kobj_attribute wakeup_event_attr = + __ATTR(wakeup_event, 0644, wakeup_source_show, NULL); + +static ssize_t wakeup_source_show(struct kobject *kobj, + struct kobj_attribute *attr, char *buf) +{ + if (attr == &wakeup_irq_attr) + return sprintf(buf, "%s\n", wakeup_irq); + else if (attr == &wakeup_event_attr) + return sprintf(buf, "%s\n", wakeup_event); + else + return -EINVAL; +} + +static irqreturn_t omap_wake_detect_gpio(int irq, void *dev_id) +{ + if (!strncmp(wakeup_event, "Unknown", WAKE_STR_LEN - 1)) + strncpy(wakeup_event, dev_id, WAKE_STR_LEN - 1); + else + omap_wake_update_event(dev_id); + + return IRQ_HANDLED; +} + +static int __devinit omap_wake_probe(struct platform_device *pdev) +{ + struct omap_wake_platform_data *pdata = pdev->dev.platform_data; + struct gpio_wake *gw; + int i, ret; + + /* + * It may be good to configure GPIO wake-up sources in each driver. + * Buf if the specific device driver doesn't exist, you can use + * omap-wake driver to configure gpio wake-up sources. + */ + for (i = 0; i < pdata->gpio_wake_num; i++) { + gw = pdata->qpio_wakes + i; + + if (gw->request) { + ret = gpio_request(gw->gpio, gw->name); + if (ret) { + dev_err(&pdev->dev, "can't request gpio%d" + ", return %d\n", gw->gpio, ret); + goto failed_free_gpio; + } + } + gpio_direction_input(gw->gpio); + enable_irq_wake(gpio_to_irq(gw->gpio)); + } + + ret = sysfs_create_file(power_kobj, &wakeup_irq_attr.attr); + if (ret) + dev_err(&pdev->dev, "sysfs_create_file %s failed: %d\n", + wakeup_irq_attr.attr.name, ret); + + ret = sysfs_create_file(power_kobj, &wakeup_event_attr.attr); + if (ret) + dev_err(&pdev->dev, "sysfs_create_file %s failed: %d\n", + wakeup_event_attr.attr.name, ret); + + return 0; + +failed_free_gpio: + for (i--; i >= 0; i--) { + gw = pdata->qpio_wakes + i; + + if (gw->request) + gpio_free(gw->gpio); + } + + return ret; +} + +static int __devexit omap_wake_remove(struct platform_device *pdev) +{ + struct omap_wake_platform_data *pdata = pdev->dev.platform_data; + struct gpio_wake *gw; + int i; + + for (i = 0; i < pdata->gpio_wake_num; i++) { + gw = pdata->qpio_wakes + i; + + if (gw->request) + gpio_free(gw->gpio); + + disable_irq_wake(gpio_to_irq(gw->gpio)); + } + + return 0; +} + +static int omap_wake_suspend(struct platform_device *pdev, pm_message_t state) +{ + struct omap_wake_platform_data *pdata = pdev->dev.platform_data; + struct gpio_wake *gw; + int i, ret; + + for (i = 0; i < pdata->gpio_wake_num; i++) { + gw = pdata->qpio_wakes + i; + + ret = request_irq(gpio_to_irq(gw->gpio), omap_wake_detect_gpio, + gw->irqflag, gw->name, (void *)gw->name); + if (ret) { + dev_err(&pdev->dev, "can't get IRQ%d, return %d\n", + gpio_to_irq(gw->gpio), ret); + goto failed_free_irq; + } + } + + return 0; + +failed_free_irq: + for (i--; i >= 0; i--) { + gw = pdata->qpio_wakes + i; + free_irq(gpio_to_irq(gw->gpio), (void *)gw->name); + } + + return ret; +} + +static int omap_wake_resume_early(struct platform_device *pdev) +{ + omap_wake_detect_wakeup(); + + return 0; +} + +static int omap_wake_resume(struct platform_device *pdev) +{ + struct omap_wake_platform_data *pdata = pdev->dev.platform_data; + struct gpio_wake *gw; + int i; + + for (i = 0; i < pdata->gpio_wake_num; i++) { + gw = pdata->qpio_wakes + i; + + free_irq(gpio_to_irq(gw->gpio), (void *)gw->name); + } + + printk(KERN_INFO "Wake-up event: %s\n", wakeup_event); + + return 0; +} + +static struct platform_driver omap_wake_driver = { + .probe = omap_wake_probe, + .remove = __devexit_p(omap_wake_remove), + .suspend = omap_wake_suspend, + .resume_early = omap_wake_resume_early, + .resume = omap_wake_resume, + .driver = { + .name = "omap-wake", + .owner = THIS_MODULE, + }, +}; + +static int __init omap_wake_init(void) +{ + return platform_driver_register(&omap_wake_driver); +} + +module_init(omap_wake_init); + +static void __exit omap_wake_exit(void) +{ + platform_driver_unregister(&omap_wake_driver); +} +module_exit(omap_wake_exit); + +MODULE_AUTHOR("Kim Kyuwon <q1.kim@samsung.com>"); +MODULE_DESCRIPTION("OMAP34xx wakeup driver"); +MODULE_LICENSE("GPL v2"); diff --git a/arch/arm/plat-omap/Kconfig b/arch/arm/plat-omap/Kconfig index b8f1298..f89efaa 100644 --- a/arch/arm/plat-omap/Kconfig +++ b/arch/arm/plat-omap/Kconfig @@ -184,6 +184,15 @@ config OMAP_IOMMU Say Y here if you want to use OMAP IOMMU support for IVA2 and Camera in OMAP3. +config OMAP_WAKE + tristate "OMAP34xx wakeup source support" + depends on ARCH_OMAP34XX && PM + default n + help + Select this option if you want to know what kind of wake-up event + wakes up your board from the low power mode. And this option + provides the unified GPIO wake-up source configuration. + choice prompt "System timer" default OMAP_MPU_TIMER diff --git a/arch/arm/plat-omap/include/mach/irqs.h b/arch/arm/plat-omap/include/mach/irqs.h index c9a5b19..d7961d4 100644 --- a/arch/arm/plat-omap/include/mach/irqs.h +++ b/arch/arm/plat-omap/include/mach/irqs.h @@ -388,6 +388,7 @@ #ifndef __ASSEMBLY__ extern void omap_init_irq(void); extern int omap_irq_pending(void); +extern int omap_get_pending_mpu_irq(unsigned int irq_start); void omap3_intc_save_context(void); void omap3_intc_restore_context(void); #endif diff --git a/arch/arm/plat-omap/include/mach/wake.h b/arch/arm/plat-omap/include/mach/wake.h new file mode 100644 index 0000000..713d89a --- /dev/null +++ b/arch/arm/plat-omap/include/mach/wake.h @@ -0,0 +1,30 @@ +/* + * wake.h + * + * Copyright (c) 2009 Samsung Eletronics + * + * Author: Kim Kyuwon <q1.kim@samsung.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + */ + +#ifndef _WAKE_H_ +#define _WAKE_H_ + +struct gpio_wake { + unsigned int gpio; + unsigned long irqflag; + const char *name; + int request; +}; + +struct omap_wake_platform_data{ + struct gpio_wake *qpio_wakes; + int gpio_wake_num; +}; + +#endif /* _WAKE_H_ */ +