* OMAP3: PM: Add the wakeup source driver, v4
@ 2009-05-05 9:13 Kim Kyuwon
2009-05-14 4:49 ` Kim Kyuwon
0 siblings, 1 reply; 4+ messages in thread
From: Kim Kyuwon @ 2009-05-05 9:13 UTC (permalink / raw)
To: OMAP; +Cc: Kevin Hilman, Kyungmin Park, Paul Walmsley
Sometimes, it is necessary to find out "what does wake up my board from suspend?". 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 from Suspend-to-RAM state to minimize power consumption. Note that this driver can't inform wake-up events from idle state. This driver uses sysfs interface to give information to user mode applications like:
cat /sys/power/omap_resume_irq
cat /sys/power/omap_resume_event
This driver also provides the I/O pad wake-up source configuration. Specific GPIO settings in the board file are:
/* I/O pad wakeup source configuration */
static struct iopad_wake boardname_iopad_wake[] = {
{
.mux_index = AE7_34XX_GPIO24,
.alias = "KEY_PWRON",
},
{
.mux_index = ETK_D9_GPIO23,
.alias = "USB_DETECT",
},
};
static struct omap_wake_platform_data boardname_wake_data = {
.iopad_wakes = boardname_iopad_wake,
.iopad_wake_num = ARRAY_SIZE(boardname_iopad_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 | 21 ++-
arch/arm/mach-omap2/omapdev-common.h | 3 +
arch/arm/mach-omap2/omapdev3xxx.h | 63 +++++
arch/arm/mach-omap2/pm34xx.c | 13 +
arch/arm/mach-omap2/prcm-common.h | 4 +
arch/arm/mach-omap2/prm-regbits-34xx.h | 5 +
arch/arm/mach-omap2/wake34xx.c | 409 +++++++++++++++++++++++++++++
arch/arm/plat-omap/Kconfig | 9 +
arch/arm/plat-omap/include/mach/irqs.h | 4 +
arch/arm/plat-omap/include/mach/mux.h | 3 +
arch/arm/plat-omap/include/mach/omapdev.h | 3 +
arch/arm/plat-omap/include/mach/wake.h | 52 ++++
arch/arm/plat-omap/mux.c | 25 ++-
14 files changed, 605 insertions(+), 10 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 c58bab4..cfc5a13 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_OMAP3_WAKE) += wake34xx.o
endif
# SmartReflex driver
diff --git a/arch/arm/mach-omap2/irq.c b/arch/arm/mach-omap2/irq.c
index 700fc3d..18ac725 100644
--- a/arch/arm/mach-omap2/irq.c
+++ b/arch/arm/mach-omap2/irq.c
@@ -33,9 +33,6 @@
#define INTC_MIR_SET0 0x008c
#define INTC_PENDING_IRQ0 0x0098
-/* Number of IRQ state bits in each MIR register */
-#define IRQ_BITS_PER_REG 32
-
/*
* OMAP2 has a number of different interrupt controllers, each interrupt
* controller is identified as its own "bank". Register definitions are
@@ -193,6 +190,24 @@ int omap_irq_pending(void)
return 0;
}
+void omap_get_pending_irqs(u32 *pending_irqs, unsigned len)
+{
+ int i, j = 0;
+
+ for (i = 0; i < ARRAY_SIZE(irq_banks); i++) {
+ struct omap_irq_bank *bank = irq_banks + i;
+ int irq;
+
+ for (irq = 0; irq < bank->nr_irqs && j < len;
+ irq += IRQ_BITS_PER_REG) {
+ int offset = irq & (~(IRQ_BITS_PER_REG - 1));
+
+ pending_irqs[j++] = intc_bank_read_reg(bank,
+ (INTC_PENDING_IRQ0 + offset));
+ }
+ }
+}
+
void __init omap_init_irq(void)
{
unsigned long nr_of_irqs = 0;
diff --git a/arch/arm/mach-omap2/omapdev-common.h b/arch/arm/mach-omap2/omapdev-common.h
index a2d4855..57b9b0b 100644
--- a/arch/arm/mach-omap2/omapdev-common.h
+++ b/arch/arm/mach-omap2/omapdev-common.h
@@ -228,10 +228,13 @@ static struct omapdev *omapdevs[] = {
&hsmmc2_3xxx_omapdev,
&mcspi3_3xxx_omapdev,
&gptimer1_3xxx_omapdev,
+ &gptimer12_3xxx_omapdev,
&prm_3xxx_omapdev,
&cm_3xxx_omapdev,
&omap_32ksynct_3xxx_omapdev,
&gpio1_3xxx_omapdev,
+ &io_3xxx_omapdev,
+ &io_chain_3xxx_omapdev,
&wdtimer2_3xxx_omapdev,
&wdtimer1_3xxx_omapdev,
&rng_3xxx_omapdev,
diff --git a/arch/arm/mach-omap2/omapdev3xxx.h b/arch/arm/mach-omap2/omapdev3xxx.h
index dce87df..9091a88 100644
--- a/arch/arm/mach-omap2/omapdev3xxx.h
+++ b/arch/arm/mach-omap2/omapdev3xxx.h
@@ -19,6 +19,8 @@
#include <mach/cpu.h>
#include <mach/omapdev.h>
+#include "prm-regbits-34xx.h"
+
#ifdef CONFIG_ARCH_OMAP3
/* 3xxx data from the 34xx ES2 TRM Rev F */
@@ -146,6 +148,7 @@ static struct omapdev sdma_3xxx_omapdev = {
static struct omapdev i2c1_3xxx_omapdev = {
.name = "i2c1_omapdev",
.pwrdm = { .name = "core_pwrdm" },
+ .wkst_mask = OMAP3430_ST_I2C1_MASK,
.pdev_name = "i2c_omap",
.pdev_id = 1,
.omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP3430),
@@ -154,6 +157,7 @@ static struct omapdev i2c1_3xxx_omapdev = {
static struct omapdev i2c2_3xxx_omapdev = {
.name = "i2c2_omapdev",
.pwrdm = { .name = "core_pwrdm" },
+ .wkst_mask = OMAP3430_ST_I2C2_MASK,
.pdev_name = "i2c_omap",
.pdev_id = 2,
.omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP3430),
@@ -162,6 +166,7 @@ static struct omapdev i2c2_3xxx_omapdev = {
static struct omapdev uart1_3xxx_omapdev = {
.name = "uart1_omapdev",
.pwrdm = { .name = "core_pwrdm" },
+ .wkst_mask = OMAP3430_ST_UART1_MASK,
.pdev_name = "serial8250",
.pdev_id = PLAT8250_DEV_PLATFORM,
.omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP3430),
@@ -170,6 +175,7 @@ static struct omapdev uart1_3xxx_omapdev = {
static struct omapdev uart2_3xxx_omapdev = {
.name = "uart2_omapdev",
.pwrdm = { .name = "core_pwrdm" },
+ .wkst_mask = OMAP3430_ST_UART2_MASK,
.pdev_name = "serial8250",
.pdev_id = PLAT8250_DEV_PLATFORM,
.omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP3430),
@@ -178,6 +184,7 @@ static struct omapdev uart2_3xxx_omapdev = {
static struct omapdev mcbsp1_3xxx_omapdev = {
.name = "mcbsp1_omapdev",
.pwrdm = { .name = "core_pwrdm" },
+ .wkst_mask = OMAP3430_ST_MCBSP1_MASK,
.pdev_name = "omap-mcbsp",
.pdev_id = 1,
.omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP3430),
@@ -186,12 +193,14 @@ static struct omapdev mcbsp1_3xxx_omapdev = {
static struct omapdev gptimer10_3xxx_omapdev = {
.name = "gptimer10_omapdev",
.pwrdm = { .name = "core_pwrdm" },
+ .wkst_mask = OMAP3430_ST_GPT10_MASK,
.omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP3430),
};
static struct omapdev gptimer11_3xxx_omapdev = {
.name = "gptimer11_omapdev",
.pwrdm = { .name = "core_pwrdm" },
+ .wkst_mask = OMAP3430_ST_GPT11_MASK,
.omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP3430),
};
@@ -206,6 +215,7 @@ static struct omapdev mailbox_3xxx_omapdev = {
static struct omapdev mcspi1_3xxx_omapdev = {
.name = "mcspi1_omapdev",
.pwrdm = { .name = "core_pwrdm" },
+ .wkst_mask = OMAP3430_ST_MCSPI1_MASK,
.pdev_name = "omap2_mcspi",
.pdev_id = 1,
.omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP3430),
@@ -214,6 +224,7 @@ static struct omapdev mcspi1_3xxx_omapdev = {
static struct omapdev mcspi2_3xxx_omapdev = {
.name = "mcspi2_omapdev",
.pwrdm = { .name = "core_pwrdm" },
+ .wkst_mask = OMAP3430_ST_MCSPI2_MASK,
.pdev_name = "omap2_mcspi",
.pdev_id = 2,
.omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP3430),
@@ -242,6 +253,7 @@ static struct omapdev mspro_3xxx_omapdev = {
static struct omapdev mcbsp5_3xxx_omapdev = {
.name = "mcbsp5_omapdev",
.pwrdm = { .name = "core_pwrdm" },
+ .wkst_mask = OMAP3430_ST_MCBSP5_MASK,
.pdev_name = "omap-mcbsp",
.pdev_id = 5,
.omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP3430),
@@ -250,6 +262,7 @@ static struct omapdev mcbsp5_3xxx_omapdev = {
static struct omapdev hsmmc1_3xxx_omapdev = {
.name = "hsmmc1_omapdev",
.pwrdm = { .name = "core_pwrdm" },
+ .wkst_mask = OMAP3430_ST_MMC1_MASK,
.pdev_name = "mmci-omap",
.pdev_id = 0,
.omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP3430),
@@ -258,6 +271,7 @@ static struct omapdev hsmmc1_3xxx_omapdev = {
static struct omapdev hsmmc2_3xxx_omapdev = {
.name = "hsmmc2_omapdev",
.pwrdm = { .name = "core_pwrdm" },
+ .wkst_mask = OMAP3430_ST_MMC2_MASK,
.pdev_name = "mmci-omap",
.pdev_id = 1,
.omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP3430),
@@ -266,6 +280,7 @@ static struct omapdev hsmmc2_3xxx_omapdev = {
static struct omapdev mcspi3_3xxx_omapdev = {
.name = "mcspi3_omapdev",
.pwrdm = { .name = "core_pwrdm" },
+ .wkst_mask = OMAP3430_ST_MCSPI3_MASK,
.pdev_name = "omap2_mcspi",
.pdev_id = 3,
.omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP3430),
@@ -278,6 +293,14 @@ static struct omapdev mcspi3_3xxx_omapdev = {
static struct omapdev gptimer1_3xxx_omapdev = {
.name = "gptimer1_omapdev",
.pwrdm = { .name = "wkup_pwrdm" },
+ .wkst_mask = OMAP3430_ST_GPT1_MASK,
+ .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP3430),
+};
+
+static struct omapdev gptimer12_3xxx_omapdev = {
+ .name = "gptimer12_omapdev",
+ .pwrdm = { .name = "wkup_pwrdm" },
+ .wkst_mask = OMAP3430_ST_GPT12_MASK,
.omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP3430),
};
@@ -302,9 +325,24 @@ static struct omapdev omap_32ksynct_3xxx_omapdev = {
static struct omapdev gpio1_3xxx_omapdev = {
.name = "gpio1_omapdev",
.pwrdm = { .name = "wkup_pwrdm" },
+ .wkst_mask = OMAP3430_ST_GPIO1_MASK,
+ .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP3430),
+};
+
+static struct omapdev io_3xxx_omapdev = {
+ .name = "io_omapdev",
+ .pwrdm = { .name = "wkup_pwrdm" },
+ .wkst_mask = OMAP3430_ST_IO,
.omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP3430),
};
+static struct omapdev io_chain_3xxx_omapdev = {
+ .name = "io_chain_omapdev",
+ .pwrdm = { .name = "wkup_pwrdm" },
+ .wkst_mask = OMAP3430_ST_IO_CHAIN,
+ .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP3430ES3_1),
+};
+
/* aka the "omap wdtimer" on 2430 or the "mpu wdtimer" on 3430 */
static struct omapdev wdtimer2_3xxx_omapdev = {
.name = "wdtimer2_omapdev",
@@ -425,6 +463,7 @@ static struct omapdev control_3xxx_omapdev = {
static struct omapdev i2c3_3xxx_omapdev = {
.name = "i2c3_omapdev",
.pwrdm = { .name = "core_pwrdm" },
+ .wkst_mask = OMAP3430_ST_I2C3_MASK,
.pdev_name = "i2c_omap",
.pdev_id = 3,
.omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP3430),
@@ -433,6 +472,7 @@ static struct omapdev i2c3_3xxx_omapdev = {
static struct omapdev hsmmc3_3xxx_omapdev = {
.name = "hsmmc3_omapdev",
.pwrdm = { .name = "core_pwrdm" },
+ .wkst_mask = OMAP3430ES2_ST_MMC3_MASK,
.pdev_name = "mmci-omap",
.pdev_id = 2,
.omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP3430ES2),
@@ -441,6 +481,7 @@ static struct omapdev hsmmc3_3xxx_omapdev = {
static struct omapdev mcspi4_3xxx_omapdev = {
.name = "mcspi4_omapdev",
.pwrdm = { .name = "core_pwrdm" },
+ .wkst_mask = OMAP3430_ST_MCSPI4_MASK,
.pdev_name = "omap2_mcspi",
.pdev_id = 4,
.omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP3430),
@@ -461,12 +502,14 @@ static struct omapdev sr2_3xxx_omapdev = {
static struct omapdev usbhost_es1_3xxx_omapdev = {
.name = "usbhost_omapdev",
.pwrdm = { .name = "core_pwrdm" },
+ .wkst_mask = OMAP3430ES1_ST_FSHOSTUSB_MASK,
.omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP3430ES1),
};
static struct omapdev usbotg_es1_3xxx_omapdev = {
.name = "usbotg_omapdev",
.pwrdm = { .name = "core_pwrdm" },
+ .wkst_mask = OMAP3430ES1_ST_HSOTGUSB_MASK,
.omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP3430ES1),
};
@@ -475,6 +518,7 @@ static struct omapdev usbotg_es1_3xxx_omapdev = {
static struct omapdev uart3_3xxx_omapdev = {
.name = "uart3_omapdev",
.pwrdm = { .name = "per_pwrdm" },
+ .wkst_mask = OMAP3430_ST_UART3_MASK,
.pdev_name = "serial8250",
.pdev_id = PLAT8250_DEV_PLATFORM,
.omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP3430),
@@ -483,6 +527,7 @@ static struct omapdev uart3_3xxx_omapdev = {
static struct omapdev mcbsp2_3xxx_omapdev = {
.name = "mcbsp2_omapdev",
.pwrdm = { .name = "per_pwrdm" },
+ .wkst_mask = OMAP3430_EN_MCBSP2,
.pdev_name = "omap-mcbsp",
.pdev_id = 2,
.omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP3430),
@@ -491,6 +536,7 @@ static struct omapdev mcbsp2_3xxx_omapdev = {
static struct omapdev mcbsp3_3xxx_omapdev = {
.name = "mcbsp3_omapdev",
.pwrdm = { .name = "per_pwrdm" },
+ .wkst_mask = OMAP3430_EN_MCBSP3,
.pdev_name = "omap-mcbsp",
.pdev_id = 3,
.omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP3430),
@@ -499,6 +545,7 @@ static struct omapdev mcbsp3_3xxx_omapdev = {
static struct omapdev mcbsp4_3xxx_omapdev = {
.name = "mcbsp4_omapdev",
.pwrdm = { .name = "per_pwrdm" },
+ .wkst_mask = OMAP3430_EN_MCBSP4,
.pdev_name = "omap-mcbsp",
.pdev_id = 3,
.omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP3430),
@@ -527,78 +574,91 @@ static struct omapdev wdtimer3_3xxx_omapdev = {
static struct omapdev gptimer2_3xxx_omapdev = {
.name = "gptimer2_omapdev",
.pwrdm = { .name = "per_pwrdm" },
+ .wkst_mask = OMAP3430_ST_GPT2_MASK,
.omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP3430),
};
static struct omapdev gptimer3_3xxx_omapdev = {
.name = "gptimer3_omapdev",
.pwrdm = { .name = "per_pwrdm" },
+ .wkst_mask = OMAP3430_ST_GPT3_MASK,
.omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP3430),
};
static struct omapdev gptimer4_3xxx_omapdev = {
.name = "gptimer4_omapdev",
.pwrdm = { .name = "per_pwrdm" },
+ .wkst_mask = OMAP3430_ST_GPT4_MASK,
.omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP3430),
};
static struct omapdev gptimer5_3xxx_omapdev = {
.name = "gptimer5_omapdev",
.pwrdm = { .name = "per_pwrdm" },
+ .wkst_mask = OMAP3430_ST_GPT5_MASK,
.omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP3430),
};
static struct omapdev gptimer6_3xxx_omapdev = {
.name = "gptimer6_omapdev",
.pwrdm = { .name = "per_pwrdm" },
+ .wkst_mask = OMAP3430_ST_GPT6_MASK,
.omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP3430),
};
static struct omapdev gptimer7_3xxx_omapdev = {
.name = "gptimer7_omapdev",
.pwrdm = { .name = "per_pwrdm" },
+ .wkst_mask = OMAP3430_ST_GPT7_MASK,
.omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP3430),
};
static struct omapdev gptimer8_3xxx_omapdev = {
.name = "gptimer8_omapdev",
.pwrdm = { .name = "per_pwrdm" },
+ .wkst_mask = OMAP3430_ST_GPT8_MASK,
.omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP3430),
};
static struct omapdev gptimer9_3xxx_omapdev = {
.name = "gptimer9_omapdev",
.pwrdm = { .name = "per_pwrdm" },
+ .wkst_mask = OMAP3430_ST_GPT9_MASK,
.omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP3430),
};
static struct omapdev gpio2_3xxx_omapdev = {
.name = "gpio2_omapdev",
.pwrdm = { .name = "per_pwrdm" },
+ .wkst_mask = OMAP3430_ST_GPIO2_MASK,
.omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP3430),
};
static struct omapdev gpio3_3xxx_omapdev = {
.name = "gpio3_omapdev",
.pwrdm = { .name = "per_pwrdm" },
+ .wkst_mask = OMAP3430_ST_GPIO3_MASK,
.omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP3430),
};
static struct omapdev gpio4_3xxx_omapdev = {
.name = "gpio4_omapdev",
.pwrdm = { .name = "per_pwrdm" },
+ .wkst_mask = OMAP3430_ST_GPIO4_MASK,
.omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP3430),
};
static struct omapdev gpio5_3xxx_omapdev = {
.name = "gpio5_omapdev",
.pwrdm = { .name = "per_pwrdm" },
+ .wkst_mask = OMAP3430_ST_GPIO5_MASK,
.omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP3430),
};
static struct omapdev gpio6_3xxx_omapdev = {
.name = "gpio6_omapdev",
.pwrdm = { .name = "per_pwrdm" },
+ .wkst_mask = OMAP3430_ST_GPIO6_MASK,
.omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP3430),
};
@@ -656,6 +716,7 @@ static struct omapdev dap_3xxx_omapdev = {
static struct omapdev usbhost_3xxx_omapdev = {
.name = "usbhost_omapdev",
.pwrdm = { .name = "usbhost_pwrdm" },
+ .wkst_mask = OMAP3430ES2_ST_USBHOST,
.pdev_name = "ehci-omap",
.pdev_id = 0,
.omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP3430ES2),
@@ -664,6 +725,7 @@ static struct omapdev usbhost_3xxx_omapdev = {
static struct omapdev usbotg_3xxx_omapdev = {
.name = "usbotg_omapdev",
.pwrdm = { .name = "usbhost_pwrdm" },
+ .wkst_mask = OMAP3430ES2_ST_HSOTGUSB_STDBY_MASK,
.pdev_name = "musb_hdrc",
.pdev_id = -1,
.omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP3430ES2),
@@ -672,6 +734,7 @@ static struct omapdev usbotg_3xxx_omapdev = {
static struct omapdev usbtll_3xxx_omapdev = {
.name = "usbtll_omapdev",
.pwrdm = { .name = "usbhost_pwrdm" },
+ .wkst_mask = OMAP3430ES2_ST_USBTLL_MASK,
.pdev_name = "ehci-omap",
.pdev_id = 0,
.omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP3430),
diff --git a/arch/arm/mach-omap2/pm34xx.c b/arch/arm/mach-omap2/pm34xx.c
index 7a561db..2832e08 100644
--- a/arch/arm/mach-omap2/pm34xx.c
+++ b/arch/arm/mach-omap2/pm34xx.c
@@ -42,6 +42,7 @@
#include <mach/dma.h>
#include <mach/gpmc.h>
#include <mach/dma.h>
+#include <mach/wake.h>
#include <asm/tlbflush.h>
#include "cm.h"
@@ -93,6 +94,13 @@ static struct prm_setup_times prm_setup = {
.voltsetup2 = 0xff,
};
+static struct pm_wakeup_status omap3_pm_wkst;
+
+void omap3_get_last_wakeup_state(struct pm_wakeup_status *pm_wkst)
+{
+ *pm_wkst = omap3_pm_wkst;
+}
+
static inline void omap3_per_save_context(void)
{
omap3_gpio_save_context();
@@ -202,6 +210,7 @@ static irqreturn_t prcm_interrupt_handler (int irq, void *dev_id)
/* WKUP */
wkst = prm_read_mod_reg(WKUP_MOD, PM_WKST);
+ omap3_pm_wkst.wkup = wkst;
if (wkst) {
iclk = cm_read_mod_reg(WKUP_MOD, CM_ICLKEN);
fclk = cm_read_mod_reg(WKUP_MOD, CM_FCLKEN);
@@ -215,6 +224,7 @@ static irqreturn_t prcm_interrupt_handler (int irq, void *dev_id)
/* CORE */
wkst = prm_read_mod_reg(CORE_MOD, PM_WKST1);
+ omap3_pm_wkst.core1 = wkst;
if (wkst) {
iclk = cm_read_mod_reg(CORE_MOD, CM_ICLKEN1);
fclk = cm_read_mod_reg(CORE_MOD, CM_FCLKEN1);
@@ -226,6 +236,7 @@ static irqreturn_t prcm_interrupt_handler (int irq, void *dev_id)
cm_write_mod_reg(fclk, CORE_MOD, CM_FCLKEN1);
}
wkst = prm_read_mod_reg(CORE_MOD, OMAP3430ES2_PM_WKST3);
+ omap3_pm_wkst.core3 = wkst;
if (wkst) {
iclk = cm_read_mod_reg(CORE_MOD, CM_ICLKEN3);
fclk = cm_read_mod_reg(CORE_MOD, OMAP3430ES2_CM_FCLKEN3);
@@ -239,6 +250,7 @@ static irqreturn_t prcm_interrupt_handler (int irq, void *dev_id)
/* PER */
wkst = prm_read_mod_reg(OMAP3430_PER_MOD, PM_WKST);
+ omap3_pm_wkst.per = wkst;
if (wkst) {
iclk = cm_read_mod_reg(OMAP3430_PER_MOD, CM_ICLKEN);
fclk = cm_read_mod_reg(OMAP3430_PER_MOD, CM_FCLKEN);
@@ -253,6 +265,7 @@ static irqreturn_t prcm_interrupt_handler (int irq, void *dev_id)
if (omap_rev() > OMAP3430_REV_ES1_0) {
/* USBHOST */
wkst = prm_read_mod_reg(OMAP3430ES2_USBHOST_MOD, PM_WKST);
+ omap3_pm_wkst.usbhost = wkst;
if (wkst) {
iclk = cm_read_mod_reg(OMAP3430ES2_USBHOST_MOD,
CM_ICLKEN);
diff --git a/arch/arm/mach-omap2/prcm-common.h b/arch/arm/mach-omap2/prcm-common.h
index cb1ae84..8ccadcc 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 OMAP3430ES2_ST_USBTLL_SHIFT 2
+#define OMAP3430ES2_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 06fee29..6826bf0 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 OMAP3430ES2_ST_MMC3_SHIFT 30
+#define OMAP3430ES2_ST_MMC3_MASK (1 << 30)
/* PM_PWSTCTRL_CORE specific bits */
#define OMAP3430_MEM2ONSTATE_SHIFT 18
@@ -432,6 +434,9 @@
/* PM_PREPWSTST_PER specific bits */
+/* PM_WKST_USBHOST specific bits */
+#define OMAP3430ES2_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..52938d8
--- /dev/null
+++ b/arch/arm/mach-omap2/wake34xx.c
@@ -0,0 +1,409 @@
+/*
+ * 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/pm.h>
+#include <mach/mux.h>
+#include <mach/control.h>
+#include <mach/wake.h>
+
+#include "prm-regbits-34xx.h"
+#include "omapdev-common.h"
+
+/*
+ * Sometimes, it is necessary to find out "what does wake up my board from
+ * suspend?". 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 from
+ * Suspend-to-RAM state to minimize power consumption. Note that this
+ * driver can't inform wake-up events from idle state. This driver uses
+ * sysfs interface to give information to user mode applications.
+ */
+
+#define WAKE_STR_LEN 128
+#define WAKE_BUF_LEN 64
+
+struct omap_wake {
+ u32 pending_irqs[INTCPS_NR_MIR_REGS];
+
+ struct omap_wake_platform_data *pdata;
+ struct pm_wakeup_status pm_wkst;
+};
+
+/* Note: Allowed to use Only in the wakeup_source_show() function */
+static struct omap_wake *g_wake;
+
+static ssize_t wakeup_source_show(struct kobject *kobj,
+ struct kobj_attribute *attr, char *buf);
+
+/*
+ * Get the first pending MPU IRQ number from 'irq_start'.
+ * If none, return -EINVAL.
+ */
+static int omap3_wake_get_pending_irq(struct omap_wake *wake,
+ unsigned int irq_start)
+{
+ int i, bits_skip, idx_start;
+
+ if (irq_start >= INTCPS_NR_IRQS)
+ return -EINVAL;
+
+ bits_skip = irq_start % IRQ_BITS_PER_REG;
+ idx_start = irq_start / IRQ_BITS_PER_REG;
+
+ for (i = idx_start; i < ARRAY_SIZE(wake->pending_irqs); i++) {
+ unsigned long val, bit;
+
+ val = wake->pending_irqs[i];
+ if (!val)
+ continue;
+
+ if (idx_start == i)
+ bit = find_next_bit(&val, IRQ_BITS_PER_REG, bits_skip);
+ else
+ bit = find_first_bit(&val, IRQ_BITS_PER_REG);
+
+ if (bit < IRQ_BITS_PER_REG)
+ return i * IRQ_BITS_PER_REG + bit;
+ }
+
+ return -EINVAL;
+}
+
+static void omap3_wake_strncat(char *dest, char *src, size_t count)
+{
+ int len;
+
+ if (!src[0])
+ return;
+
+ if (dest[0])
+ len = strlen(dest) + strlen(src) + 2;
+ else
+ len = strlen(dest) + strlen(src);
+
+ if (len > count) {
+ pr_err("Can't strncat: %s\n", src);
+ return;
+ }
+
+ if (dest[0])
+ strcat(dest, ", ");
+ strcat(dest, src);
+}
+
+static u32 omap3_wake_get_domain_wkst(struct omap_wake *wake,
+ struct omapdev *omap3_dev)
+{
+ struct pm_wakeup_status *pm_wkst = &wake->pm_wkst;
+ const char *pwrdm_name = omap3_dev->pwrdm.name;
+
+ if (!strcmp(pwrdm_name, "wkup_pwrdm")) {
+ return pm_wkst->wkup;
+ } else if (!strcmp(pwrdm_name, "per_pwrdm")) {
+ return pm_wkst->per;
+ } else if (!strcmp(pwrdm_name, "core_pwrdm")) {
+ return pm_wkst->core1;
+ } else if (!strcmp(pwrdm_name, "usbhost_pwrdm")) {
+ if (!strcmp(omap3_dev->name, "usbtll_omapdev"))
+ return pm_wkst->core3;
+ else if (!strcmp(omap3_dev->name, "usbhost_omapdev"))
+ return pm_wkst->usbhost;
+ }
+
+ return -EINVAL;
+}
+
+static void omap3_wake_lookup_wkst(struct omap_wake *wake,
+ char *wake_event, size_t count)
+{
+ struct omapdev **d;
+
+ for (d = omapdevs; *d; d++) {
+ u32 wkst;
+
+ if (!omap_chip_is((*d)->omap_chip))
+ continue;
+
+ wkst = omap3_wake_get_domain_wkst(wake, *d);
+ if (wkst <= 0)
+ continue;
+
+ if (wkst & (*d)->wkst_mask)
+ omap3_wake_strncat(wake_event,
+ (char *)(*d)->name, count);
+ }
+}
+
+static void omap3_wake_lookup_iopad(struct omap_wake *wake,
+ char *wake_event, size_t count)
+{
+ struct omap_wake_platform_data *pdata = wake->pdata;
+ int i;
+
+ for (i = 0; pdata && i < pdata->iopad_wake_num; i++) {
+ struct iopad_wake *iopad = pdata->iopad_wakes + i;
+ char *wksrc_iopad;
+
+ if (!iopad->is_wake_source)
+ continue;
+
+ if (iopad->alias) {
+ wksrc_iopad = (char *)iopad->alias;
+ } else {
+ struct pin_config *cfg = NULL;
+ int err;
+
+ err = omap_get_pin_config(iopad->mux_index, &cfg);
+ if (err || !cfg)
+ continue;
+
+ wksrc_iopad = cfg->name;
+ }
+
+ omap3_wake_strncat(wake_event, wksrc_iopad, count);
+ }
+}
+
+static void omap3_wake_dump_wksrc(struct omap_wake *wake,
+ char *wake_irq, char *wake_event,
+ size_t irq_size, size_t event_size)
+{
+ int irq, prcm_irq = 0;
+
+ /* IRQ */
+ irq = omap3_wake_get_pending_irq(wake, 0);
+ while (irq >= 0) {
+ char buf[WAKE_BUF_LEN] = {0, };
+ int len;
+
+ if (irq == INT_34XX_SYS_NIRQ)
+ omap3_wake_strncat(wake_event, "sys_nirq",
+ event_size - 1);
+ else if (irq == INT_34XX_PRCM_MPU_IRQ)
+ prcm_irq = 1;
+
+ len = strlen(wake_irq) +
+ snprintf(buf, WAKE_BUF_LEN, "%d", irq);
+ if (len > irq_size - 1)
+ break;
+
+ strcat(wake_irq, buf);
+
+ irq = omap3_wake_get_pending_irq(wake, irq + 1);
+ if (irq >= 0) {
+ len = strlen(wake_irq) + 2;
+ if (len > irq_size - 1)
+ break;
+
+ strcat(wake_irq, ", ");
+ }
+ }
+
+ if (prcm_irq) {
+ omap3_wake_lookup_wkst(wake, wake_event, event_size - 1);
+ if (strstr(wake_event, io_3xxx_omapdev.name)) {
+ omap3_wake_lookup_iopad(wake, wake_event,
+ event_size - 1);
+ }
+ }
+
+ if (!wake_irq[0])
+ strncpy(wake_irq, "Unknown", irq_size - 1);
+
+ if (!wake_event[0])
+ strncpy(wake_event, "Unknown", event_size - 1);
+}
+
+static struct kobj_attribute wakeup_irq_attr =
+ __ATTR(omap_resume_irq, 0644, wakeup_source_show, NULL);
+
+static struct kobj_attribute wakeup_event_attr =
+ __ATTR(omap_resume_event, 0644, wakeup_source_show, NULL);
+
+static ssize_t wakeup_source_show(struct kobject *kobj,
+ struct kobj_attribute *attr, char *buf)
+{
+ char wakeup_irq[WAKE_STR_LEN] = {0, };
+ char wakeup_event[WAKE_STR_LEN] = {0, };
+
+ if (!g_wake)
+ return -EINVAL;
+
+ omap3_wake_dump_wksrc(g_wake, wakeup_irq, wakeup_event,
+ sizeof(wakeup_irq), sizeof(wakeup_event));
+
+ 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 int __devinit omap3_wake_probe(struct platform_device *pdev)
+{
+ struct omap_wake *wake;
+ int ret;
+
+ wake = kzalloc(sizeof(struct omap_wake), GFP_KERNEL);
+ if (wake == NULL) {
+ dev_err(&pdev->dev, "failed to allocate driver data\n");
+ return -ENOMEM;
+ }
+
+ wake->pdata = pdev->dev.platform_data;
+ platform_set_drvdata(pdev, wake);
+
+ /*
+ * In wakeup_source_show(), we can't access platform_device
+ * or omap_wake structure without a global variable. so 'g_wake' is
+ * needed, but please use it carefully.
+ */
+ g_wake = wake;
+
+ 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;
+}
+
+static int __devexit omap3_wake_remove(struct platform_device *pdev)
+{
+ struct omap_wake *wake = platform_get_drvdata(pdev);
+
+ kfree(wake);
+ g_wake = NULL;
+
+ return 0;
+}
+
+static int omap3_wake_suspend(struct platform_device *pdev, pm_message_t state)
+{
+ struct omap_wake_platform_data *pdata = pdev->dev.platform_data;
+ int i;
+
+ /*
+ * Whenever the system enters suspend, set WAKEUPENABLE bits again.
+ * Because the omap_cfg_reg() function could clear WAKEUPENABLE bits
+ * at runtime.
+ */
+ for (i = 0; pdata && i < pdata->iopad_wake_num; i++) {
+ struct iopad_wake *iopad = pdata->iopad_wakes + i;
+ struct pin_config *cfg = NULL;
+ int err;
+ u16 v;
+
+ err = omap_get_pin_config(iopad->mux_index, &cfg);
+ if (err || !cfg)
+ continue;
+
+ v = omap_ctrl_readw(cfg->mux_reg);
+ v |= OMAP3_PADCONF_WAKEUPENABLE0;
+ omap_ctrl_writew(v, cfg->mux_reg);
+
+ /* Reset previsous wake-up event information of each pin */
+ iopad->is_wake_source = false;
+ }
+
+ return 0;
+}
+
+static int omap3_wake_resume_early(struct platform_device *pdev)
+{
+ struct omap_wake *wake = platform_get_drvdata(pdev);
+ struct omap_wake_platform_data *pdata = wake->pdata;
+ int i;
+
+ omap_get_pending_irqs(wake->pending_irqs,
+ ARRAY_SIZE(wake->pending_irqs));
+
+ for (i = 0; pdata && i < pdata->iopad_wake_num; i++) {
+ struct iopad_wake *iopad = pdata->iopad_wakes + i;
+ struct pin_config *cfg = NULL;
+ int err;
+ u16 v;
+
+ err = omap_get_pin_config(iopad->mux_index, &cfg);
+ if (err || !cfg)
+ continue;
+
+ v = omap_ctrl_readw(cfg->mux_reg);
+ v &= ~OMAP3_PADCONF_WAKEUPENABLE0;
+ omap_ctrl_writew(v, cfg->mux_reg);
+
+ if (v & OMAP3_PADCONF_WAKEUPEVENT0)
+ iopad->is_wake_source = true;
+ }
+
+ return 0;
+}
+
+static int omap3_wake_resume(struct platform_device *pdev)
+{
+ struct omap_wake *wake = platform_get_drvdata(pdev);
+
+#ifdef CONFIG_PM_DEBUG
+ char wakeup_irq[WAKE_STR_LEN] = {0, };
+ char wakeup_event[WAKE_STR_LEN] = {0, };
+
+ omap3_wake_dump_wksrc(wake, wakeup_irq, wakeup_event,
+ sizeof(wakeup_irq), sizeof(wakeup_event));
+
+ pr_info("OMAP resume IRQ: %s\n", wakeup_irq);
+ pr_info("OMAP resume event: %s\n", wakeup_event);
+#endif
+
+ omap3_get_last_wakeup_state(&wake->pm_wkst);
+
+ return 0;
+}
+
+static struct platform_driver omap3_wake_driver = {
+ .probe = omap3_wake_probe,
+ .remove = __devexit_p(omap3_wake_remove),
+ .suspend = omap3_wake_suspend,
+ .resume_early = omap3_wake_resume_early,
+ .resume = omap3_wake_resume,
+ .driver = {
+ .name = "omap-wake",
+ .owner = THIS_MODULE,
+ },
+};
+
+static int __init omap3_wake_init(void)
+{
+ return platform_driver_register(&omap3_wake_driver);
+}
+late_initcall(omap3_wake_init);
+
+static void __exit omap3_wake_exit(void)
+{
+ platform_driver_unregister(&omap3_wake_driver);
+}
+module_exit(omap3_wake_exit);
+
+MODULE_AUTHOR("Kim Kyuwon <q1.kim@samsung.com>");
+MODULE_DESCRIPTION("OMAP34xx wakeup source driver");
+MODULE_LICENSE("GPL v2");
diff --git a/arch/arm/plat-omap/Kconfig b/arch/arm/plat-omap/Kconfig
index a2d15a1..24eb6c1 100644
--- a/arch/arm/plat-omap/Kconfig
+++ b/arch/arm/plat-omap/Kconfig
@@ -236,6 +236,15 @@ config OMAP_DM_TIMER
help
Select this option if you want to use OMAP Dual-Mode timers.
+config OMAP3_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 suspend. This driver also privides the
+ I/O pad wake-up source configuration.
+
choice
prompt "Low-level debug console UART"
depends on ARCH_OMAP
diff --git a/arch/arm/plat-omap/include/mach/irqs.h b/arch/arm/plat-omap/include/mach/irqs.h
index c9a5b19..ee15402 100644
--- a/arch/arm/plat-omap/include/mach/irqs.h
+++ b/arch/arm/plat-omap/include/mach/irqs.h
@@ -385,9 +385,13 @@
#define INTCPS_NR_MIR_REGS 3
#define INTCPS_NR_IRQS 96
+/* Number of IRQ state bits in each MIR register */
+#define IRQ_BITS_PER_REG 32
+
#ifndef __ASSEMBLY__
extern void omap_init_irq(void);
extern int omap_irq_pending(void);
+extern void omap_get_pending_irqs(u32 *pending_irqs, unsigned len);
void omap3_intc_save_context(void);
void omap3_intc_restore_context(void);
#endif
diff --git a/arch/arm/plat-omap/include/mach/mux.h b/arch/arm/plat-omap/include/mach/mux.h
index f7e298a..f6cb7b1 100644
--- a/arch/arm/plat-omap/include/mach/mux.h
+++ b/arch/arm/plat-omap/include/mach/mux.h
@@ -816,11 +816,14 @@ struct omap_mux_cfg {
extern int omap1_mux_init(void);
extern int omap2_mux_init(void);
extern int omap_mux_register(struct omap_mux_cfg *);
+extern int omap_get_pin_config(unsigned long index, struct pin_config **cfg);
extern int omap_cfg_reg(unsigned long reg_cfg);
#else
/* boot loader does it all (no warnings from CONFIG_OMAP_MUX_WARNINGS) */
static inline int omap1_mux_init(void) { return 0; }
static inline int omap2_mux_init(void) { return 0; }
+static inline int omap_get_pin_config(unsigned long index,
+ struct pin_config **cfg) { return 0; }
static inline int omap_cfg_reg(unsigned long reg_cfg) { return 0; }
#endif
diff --git a/arch/arm/plat-omap/include/mach/omapdev.h b/arch/arm/plat-omap/include/mach/omapdev.h
index 4b379bc..2359073 100644
--- a/arch/arm/plat-omap/include/mach/omapdev.h
+++ b/arch/arm/plat-omap/include/mach/omapdev.h
@@ -24,6 +24,7 @@
* struct omapdev - OMAP on-chip hardware devices
* @name: name of the device - should match TRM
* @pwrdm: powerdomain that the device resides in
+ * @wkst_mask: wake-up state bit in PM_WKST_<domain> associated with pwrdm
* @omap_chip: OMAP chips this omapdev is valid for
* @pdev_name: platform_device name associated with this omapdev (if any)
* @pdev_id: platform_device id associated with this omapdev (if any)
@@ -38,6 +39,8 @@ struct omapdev {
struct powerdomain *ptr;
} pwrdm;
+ const u32 wkst_mask;
+
const struct omap_chip_id omap_chip;
const char *pdev_name;
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..5b725e3
--- /dev/null
+++ b/arch/arm/plat-omap/include/mach/wake.h
@@ -0,0 +1,52 @@
+/*
+ * 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 iopad_wake - used to enable each I/O pad of the device
+ * to wake up the system and detect wake-up events of each I/O pad.
+ *
+ * The mux layer (mux.c/h files) doesn't have resume hook, so checking
+ * WAKEUPEVENT in the CONTROL_PADCONF_X register before being cleared by
+ * PRCM IRQ would be difficult in the mux layer. Thus, this wake source
+ * driver takes charge of Wake-Up Event Detection Scheme
+ *
+ * @mux_index: enumeration index of omapxxxx_index in mux.h
+ * @alias: descriptive name of each pin (optional)
+ * @is_wake_source: automatically set by suspend & resume hooks
+ */
+struct iopad_wake {
+ const u32 mux_index;
+ const char *alias;
+ bool is_wake_source;
+};
+
+struct omap_wake_platform_data{
+ struct iopad_wake *iopad_wakes;
+ int iopad_wake_num;
+};
+
+struct pm_wakeup_status {
+ u32 wkup;
+ u32 per;
+ u32 core1;
+ u32 core3;
+ u32 usbhost;
+};
+
+void omap3_get_last_wakeup_state(struct pm_wakeup_status *pm_wkst);
+
+#endif /* _WAKE_H_ */
+
diff --git a/arch/arm/plat-omap/mux.c b/arch/arm/plat-omap/mux.c
index 80b040f..6bf321b 100644
--- a/arch/arm/plat-omap/mux.c
+++ b/arch/arm/plat-omap/mux.c
@@ -47,13 +47,8 @@ int __init omap_mux_register(struct omap_mux_cfg *arch_mux_cfg)
return 0;
}
-/*
- * Sets the Omap MUX and PULL_DWN registers based on the table
- */
-int __init_or_module omap_cfg_reg(const unsigned long index)
+int omap_get_pin_config(const unsigned long index, struct pin_config **cfg)
{
- struct pin_config *reg;
-
if (mux_cfg == NULL) {
printk(KERN_ERR "Pin mux table not initialized\n");
return -ENODEV;
@@ -66,7 +61,23 @@ int __init_or_module omap_cfg_reg(const unsigned long index)
return -ENODEV;
}
- reg = (struct pin_config *)&mux_cfg->pins[index];
+ *cfg = &mux_cfg->pins[index];
+
+ return 0;
+}
+EXPORT_SYMBOL(omap_get_pin_config);
+
+/*
+ * Sets the Omap MUX and PULL_DWN registers based on the table
+ */
+int __init_or_module omap_cfg_reg(const unsigned long index)
+{
+ struct pin_config *reg = NULL;
+ int err;
+
+ err = omap_get_pin_config(index, ®);
+ if (err || !reg)
+ return err;
if (!mux_cfg->cfg_reg)
return -ENODEV;
--
1.5.2.5
^ permalink raw reply related [flat|nested] 4+ messages in thread
* Re: OMAP3: PM: Add the wakeup source driver, v4
2009-05-05 9:13 OMAP3: PM: Add the wakeup source driver, v4 Kim Kyuwon
@ 2009-05-14 4:49 ` Kim Kyuwon
2009-05-14 18:32 ` Kevin Hilman
0 siblings, 1 reply; 4+ messages in thread
From: Kim Kyuwon @ 2009-05-14 4:49 UTC (permalink / raw)
To: Kevin Hilman; +Cc: OMAP, Paul Walmsley
Hi Kevin,
Could you please review this fourth version of OMAP wakeup source driver?
Regards,
Kyuwon.
On Tue, May 5, 2009 at 6:13 PM, Kim Kyuwon <q1.kim@samsung.com> wrote:
> Sometimes, it is necessary to find out "what does wake up my board from suspend?". 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 from Suspend-to-RAM state to minimize power consumption. Note that this driver can't inform wake-up events from idle state. This driver uses sysfs interface to give information to user mode applications like:
>
> cat /sys/power/omap_resume_irq
> cat /sys/power/omap_resume_event
>
> This driver also provides the I/O pad wake-up source configuration. Specific GPIO settings in the board file are:
>
> /* I/O pad wakeup source configuration */
> static struct iopad_wake boardname_iopad_wake[] = {
> {
> .mux_index = AE7_34XX_GPIO24,
> .alias = "KEY_PWRON",
> },
> {
> .mux_index = ETK_D9_GPIO23,
> .alias = "USB_DETECT",
> },
> };
>
> static struct omap_wake_platform_data boardname_wake_data = {
> .iopad_wakes = boardname_iopad_wake,
> .iopad_wake_num = ARRAY_SIZE(boardname_iopad_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 | 21 ++-
> arch/arm/mach-omap2/omapdev-common.h | 3 +
> arch/arm/mach-omap2/omapdev3xxx.h | 63 +++++
> arch/arm/mach-omap2/pm34xx.c | 13 +
> arch/arm/mach-omap2/prcm-common.h | 4 +
> arch/arm/mach-omap2/prm-regbits-34xx.h | 5 +
> arch/arm/mach-omap2/wake34xx.c | 409 +++++++++++++++++++++++++++++
> arch/arm/plat-omap/Kconfig | 9 +
> arch/arm/plat-omap/include/mach/irqs.h | 4 +
> arch/arm/plat-omap/include/mach/mux.h | 3 +
> arch/arm/plat-omap/include/mach/omapdev.h | 3 +
> arch/arm/plat-omap/include/mach/wake.h | 52 ++++
> arch/arm/plat-omap/mux.c | 25 ++-
> 14 files changed, 605 insertions(+), 10 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 c58bab4..cfc5a13 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_OMAP3_WAKE) += wake34xx.o
> endif
>
> # SmartReflex driver
> diff --git a/arch/arm/mach-omap2/irq.c b/arch/arm/mach-omap2/irq.c
> index 700fc3d..18ac725 100644
> --- a/arch/arm/mach-omap2/irq.c
> +++ b/arch/arm/mach-omap2/irq.c
> @@ -33,9 +33,6 @@
> #define INTC_MIR_SET0 0x008c
> #define INTC_PENDING_IRQ0 0x0098
>
> -/* Number of IRQ state bits in each MIR register */
> -#define IRQ_BITS_PER_REG 32
> -
> /*
> * OMAP2 has a number of different interrupt controllers, each interrupt
> * controller is identified as its own "bank". Register definitions are
> @@ -193,6 +190,24 @@ int omap_irq_pending(void)
> return 0;
> }
>
> +void omap_get_pending_irqs(u32 *pending_irqs, unsigned len)
> +{
> + int i, j = 0;
> +
> + for (i = 0; i < ARRAY_SIZE(irq_banks); i++) {
> + struct omap_irq_bank *bank = irq_banks + i;
> + int irq;
> +
> + for (irq = 0; irq < bank->nr_irqs && j < len;
> + irq += IRQ_BITS_PER_REG) {
> + int offset = irq & (~(IRQ_BITS_PER_REG - 1));
> +
> + pending_irqs[j++] = intc_bank_read_reg(bank,
> + (INTC_PENDING_IRQ0 + offset));
> + }
> + }
> +}
> +
> void __init omap_init_irq(void)
> {
> unsigned long nr_of_irqs = 0;
> diff --git a/arch/arm/mach-omap2/omapdev-common.h b/arch/arm/mach-omap2/omapdev-common.h
> index a2d4855..57b9b0b 100644
> --- a/arch/arm/mach-omap2/omapdev-common.h
> +++ b/arch/arm/mach-omap2/omapdev-common.h
> @@ -228,10 +228,13 @@ static struct omapdev *omapdevs[] = {
> &hsmmc2_3xxx_omapdev,
> &mcspi3_3xxx_omapdev,
> &gptimer1_3xxx_omapdev,
> + &gptimer12_3xxx_omapdev,
> &prm_3xxx_omapdev,
> &cm_3xxx_omapdev,
> &omap_32ksynct_3xxx_omapdev,
> &gpio1_3xxx_omapdev,
> + &io_3xxx_omapdev,
> + &io_chain_3xxx_omapdev,
> &wdtimer2_3xxx_omapdev,
> &wdtimer1_3xxx_omapdev,
> &rng_3xxx_omapdev,
> diff --git a/arch/arm/mach-omap2/omapdev3xxx.h b/arch/arm/mach-omap2/omapdev3xxx.h
> index dce87df..9091a88 100644
> --- a/arch/arm/mach-omap2/omapdev3xxx.h
> +++ b/arch/arm/mach-omap2/omapdev3xxx.h
> @@ -19,6 +19,8 @@
> #include <mach/cpu.h>
> #include <mach/omapdev.h>
>
> +#include "prm-regbits-34xx.h"
> +
> #ifdef CONFIG_ARCH_OMAP3
>
> /* 3xxx data from the 34xx ES2 TRM Rev F */
> @@ -146,6 +148,7 @@ static struct omapdev sdma_3xxx_omapdev = {
> static struct omapdev i2c1_3xxx_omapdev = {
> .name = "i2c1_omapdev",
> .pwrdm = { .name = "core_pwrdm" },
> + .wkst_mask = OMAP3430_ST_I2C1_MASK,
> .pdev_name = "i2c_omap",
> .pdev_id = 1,
> .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP3430),
> @@ -154,6 +157,7 @@ static struct omapdev i2c1_3xxx_omapdev = {
> static struct omapdev i2c2_3xxx_omapdev = {
> .name = "i2c2_omapdev",
> .pwrdm = { .name = "core_pwrdm" },
> + .wkst_mask = OMAP3430_ST_I2C2_MASK,
> .pdev_name = "i2c_omap",
> .pdev_id = 2,
> .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP3430),
> @@ -162,6 +166,7 @@ static struct omapdev i2c2_3xxx_omapdev = {
> static struct omapdev uart1_3xxx_omapdev = {
> .name = "uart1_omapdev",
> .pwrdm = { .name = "core_pwrdm" },
> + .wkst_mask = OMAP3430_ST_UART1_MASK,
> .pdev_name = "serial8250",
> .pdev_id = PLAT8250_DEV_PLATFORM,
> .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP3430),
> @@ -170,6 +175,7 @@ static struct omapdev uart1_3xxx_omapdev = {
> static struct omapdev uart2_3xxx_omapdev = {
> .name = "uart2_omapdev",
> .pwrdm = { .name = "core_pwrdm" },
> + .wkst_mask = OMAP3430_ST_UART2_MASK,
> .pdev_name = "serial8250",
> .pdev_id = PLAT8250_DEV_PLATFORM,
> .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP3430),
> @@ -178,6 +184,7 @@ static struct omapdev uart2_3xxx_omapdev = {
> static struct omapdev mcbsp1_3xxx_omapdev = {
> .name = "mcbsp1_omapdev",
> .pwrdm = { .name = "core_pwrdm" },
> + .wkst_mask = OMAP3430_ST_MCBSP1_MASK,
> .pdev_name = "omap-mcbsp",
> .pdev_id = 1,
> .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP3430),
> @@ -186,12 +193,14 @@ static struct omapdev mcbsp1_3xxx_omapdev = {
> static struct omapdev gptimer10_3xxx_omapdev = {
> .name = "gptimer10_omapdev",
> .pwrdm = { .name = "core_pwrdm" },
> + .wkst_mask = OMAP3430_ST_GPT10_MASK,
> .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP3430),
> };
>
> static struct omapdev gptimer11_3xxx_omapdev = {
> .name = "gptimer11_omapdev",
> .pwrdm = { .name = "core_pwrdm" },
> + .wkst_mask = OMAP3430_ST_GPT11_MASK,
> .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP3430),
> };
>
> @@ -206,6 +215,7 @@ static struct omapdev mailbox_3xxx_omapdev = {
> static struct omapdev mcspi1_3xxx_omapdev = {
> .name = "mcspi1_omapdev",
> .pwrdm = { .name = "core_pwrdm" },
> + .wkst_mask = OMAP3430_ST_MCSPI1_MASK,
> .pdev_name = "omap2_mcspi",
> .pdev_id = 1,
> .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP3430),
> @@ -214,6 +224,7 @@ static struct omapdev mcspi1_3xxx_omapdev = {
> static struct omapdev mcspi2_3xxx_omapdev = {
> .name = "mcspi2_omapdev",
> .pwrdm = { .name = "core_pwrdm" },
> + .wkst_mask = OMAP3430_ST_MCSPI2_MASK,
> .pdev_name = "omap2_mcspi",
> .pdev_id = 2,
> .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP3430),
> @@ -242,6 +253,7 @@ static struct omapdev mspro_3xxx_omapdev = {
> static struct omapdev mcbsp5_3xxx_omapdev = {
> .name = "mcbsp5_omapdev",
> .pwrdm = { .name = "core_pwrdm" },
> + .wkst_mask = OMAP3430_ST_MCBSP5_MASK,
> .pdev_name = "omap-mcbsp",
> .pdev_id = 5,
> .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP3430),
> @@ -250,6 +262,7 @@ static struct omapdev mcbsp5_3xxx_omapdev = {
> static struct omapdev hsmmc1_3xxx_omapdev = {
> .name = "hsmmc1_omapdev",
> .pwrdm = { .name = "core_pwrdm" },
> + .wkst_mask = OMAP3430_ST_MMC1_MASK,
> .pdev_name = "mmci-omap",
> .pdev_id = 0,
> .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP3430),
> @@ -258,6 +271,7 @@ static struct omapdev hsmmc1_3xxx_omapdev = {
> static struct omapdev hsmmc2_3xxx_omapdev = {
> .name = "hsmmc2_omapdev",
> .pwrdm = { .name = "core_pwrdm" },
> + .wkst_mask = OMAP3430_ST_MMC2_MASK,
> .pdev_name = "mmci-omap",
> .pdev_id = 1,
> .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP3430),
> @@ -266,6 +280,7 @@ static struct omapdev hsmmc2_3xxx_omapdev = {
> static struct omapdev mcspi3_3xxx_omapdev = {
> .name = "mcspi3_omapdev",
> .pwrdm = { .name = "core_pwrdm" },
> + .wkst_mask = OMAP3430_ST_MCSPI3_MASK,
> .pdev_name = "omap2_mcspi",
> .pdev_id = 3,
> .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP3430),
> @@ -278,6 +293,14 @@ static struct omapdev mcspi3_3xxx_omapdev = {
> static struct omapdev gptimer1_3xxx_omapdev = {
> .name = "gptimer1_omapdev",
> .pwrdm = { .name = "wkup_pwrdm" },
> + .wkst_mask = OMAP3430_ST_GPT1_MASK,
> + .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP3430),
> +};
> +
> +static struct omapdev gptimer12_3xxx_omapdev = {
> + .name = "gptimer12_omapdev",
> + .pwrdm = { .name = "wkup_pwrdm" },
> + .wkst_mask = OMAP3430_ST_GPT12_MASK,
> .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP3430),
> };
>
> @@ -302,9 +325,24 @@ static struct omapdev omap_32ksynct_3xxx_omapdev = {
> static struct omapdev gpio1_3xxx_omapdev = {
> .name = "gpio1_omapdev",
> .pwrdm = { .name = "wkup_pwrdm" },
> + .wkst_mask = OMAP3430_ST_GPIO1_MASK,
> + .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP3430),
> +};
> +
> +static struct omapdev io_3xxx_omapdev = {
> + .name = "io_omapdev",
> + .pwrdm = { .name = "wkup_pwrdm" },
> + .wkst_mask = OMAP3430_ST_IO,
> .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP3430),
> };
>
> +static struct omapdev io_chain_3xxx_omapdev = {
> + .name = "io_chain_omapdev",
> + .pwrdm = { .name = "wkup_pwrdm" },
> + .wkst_mask = OMAP3430_ST_IO_CHAIN,
> + .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP3430ES3_1),
> +};
> +
> /* aka the "omap wdtimer" on 2430 or the "mpu wdtimer" on 3430 */
> static struct omapdev wdtimer2_3xxx_omapdev = {
> .name = "wdtimer2_omapdev",
> @@ -425,6 +463,7 @@ static struct omapdev control_3xxx_omapdev = {
> static struct omapdev i2c3_3xxx_omapdev = {
> .name = "i2c3_omapdev",
> .pwrdm = { .name = "core_pwrdm" },
> + .wkst_mask = OMAP3430_ST_I2C3_MASK,
> .pdev_name = "i2c_omap",
> .pdev_id = 3,
> .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP3430),
> @@ -433,6 +472,7 @@ static struct omapdev i2c3_3xxx_omapdev = {
> static struct omapdev hsmmc3_3xxx_omapdev = {
> .name = "hsmmc3_omapdev",
> .pwrdm = { .name = "core_pwrdm" },
> + .wkst_mask = OMAP3430ES2_ST_MMC3_MASK,
> .pdev_name = "mmci-omap",
> .pdev_id = 2,
> .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP3430ES2),
> @@ -441,6 +481,7 @@ static struct omapdev hsmmc3_3xxx_omapdev = {
> static struct omapdev mcspi4_3xxx_omapdev = {
> .name = "mcspi4_omapdev",
> .pwrdm = { .name = "core_pwrdm" },
> + .wkst_mask = OMAP3430_ST_MCSPI4_MASK,
> .pdev_name = "omap2_mcspi",
> .pdev_id = 4,
> .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP3430),
> @@ -461,12 +502,14 @@ static struct omapdev sr2_3xxx_omapdev = {
> static struct omapdev usbhost_es1_3xxx_omapdev = {
> .name = "usbhost_omapdev",
> .pwrdm = { .name = "core_pwrdm" },
> + .wkst_mask = OMAP3430ES1_ST_FSHOSTUSB_MASK,
> .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP3430ES1),
> };
>
> static struct omapdev usbotg_es1_3xxx_omapdev = {
> .name = "usbotg_omapdev",
> .pwrdm = { .name = "core_pwrdm" },
> + .wkst_mask = OMAP3430ES1_ST_HSOTGUSB_MASK,
> .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP3430ES1),
> };
>
> @@ -475,6 +518,7 @@ static struct omapdev usbotg_es1_3xxx_omapdev = {
> static struct omapdev uart3_3xxx_omapdev = {
> .name = "uart3_omapdev",
> .pwrdm = { .name = "per_pwrdm" },
> + .wkst_mask = OMAP3430_ST_UART3_MASK,
> .pdev_name = "serial8250",
> .pdev_id = PLAT8250_DEV_PLATFORM,
> .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP3430),
> @@ -483,6 +527,7 @@ static struct omapdev uart3_3xxx_omapdev = {
> static struct omapdev mcbsp2_3xxx_omapdev = {
> .name = "mcbsp2_omapdev",
> .pwrdm = { .name = "per_pwrdm" },
> + .wkst_mask = OMAP3430_EN_MCBSP2,
> .pdev_name = "omap-mcbsp",
> .pdev_id = 2,
> .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP3430),
> @@ -491,6 +536,7 @@ static struct omapdev mcbsp2_3xxx_omapdev = {
> static struct omapdev mcbsp3_3xxx_omapdev = {
> .name = "mcbsp3_omapdev",
> .pwrdm = { .name = "per_pwrdm" },
> + .wkst_mask = OMAP3430_EN_MCBSP3,
> .pdev_name = "omap-mcbsp",
> .pdev_id = 3,
> .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP3430),
> @@ -499,6 +545,7 @@ static struct omapdev mcbsp3_3xxx_omapdev = {
> static struct omapdev mcbsp4_3xxx_omapdev = {
> .name = "mcbsp4_omapdev",
> .pwrdm = { .name = "per_pwrdm" },
> + .wkst_mask = OMAP3430_EN_MCBSP4,
> .pdev_name = "omap-mcbsp",
> .pdev_id = 3,
> .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP3430),
> @@ -527,78 +574,91 @@ static struct omapdev wdtimer3_3xxx_omapdev = {
> static struct omapdev gptimer2_3xxx_omapdev = {
> .name = "gptimer2_omapdev",
> .pwrdm = { .name = "per_pwrdm" },
> + .wkst_mask = OMAP3430_ST_GPT2_MASK,
> .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP3430),
> };
>
> static struct omapdev gptimer3_3xxx_omapdev = {
> .name = "gptimer3_omapdev",
> .pwrdm = { .name = "per_pwrdm" },
> + .wkst_mask = OMAP3430_ST_GPT3_MASK,
> .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP3430),
> };
>
> static struct omapdev gptimer4_3xxx_omapdev = {
> .name = "gptimer4_omapdev",
> .pwrdm = { .name = "per_pwrdm" },
> + .wkst_mask = OMAP3430_ST_GPT4_MASK,
> .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP3430),
> };
>
> static struct omapdev gptimer5_3xxx_omapdev = {
> .name = "gptimer5_omapdev",
> .pwrdm = { .name = "per_pwrdm" },
> + .wkst_mask = OMAP3430_ST_GPT5_MASK,
> .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP3430),
> };
>
> static struct omapdev gptimer6_3xxx_omapdev = {
> .name = "gptimer6_omapdev",
> .pwrdm = { .name = "per_pwrdm" },
> + .wkst_mask = OMAP3430_ST_GPT6_MASK,
> .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP3430),
> };
>
> static struct omapdev gptimer7_3xxx_omapdev = {
> .name = "gptimer7_omapdev",
> .pwrdm = { .name = "per_pwrdm" },
> + .wkst_mask = OMAP3430_ST_GPT7_MASK,
> .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP3430),
> };
>
> static struct omapdev gptimer8_3xxx_omapdev = {
> .name = "gptimer8_omapdev",
> .pwrdm = { .name = "per_pwrdm" },
> + .wkst_mask = OMAP3430_ST_GPT8_MASK,
> .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP3430),
> };
>
> static struct omapdev gptimer9_3xxx_omapdev = {
> .name = "gptimer9_omapdev",
> .pwrdm = { .name = "per_pwrdm" },
> + .wkst_mask = OMAP3430_ST_GPT9_MASK,
> .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP3430),
> };
>
> static struct omapdev gpio2_3xxx_omapdev = {
> .name = "gpio2_omapdev",
> .pwrdm = { .name = "per_pwrdm" },
> + .wkst_mask = OMAP3430_ST_GPIO2_MASK,
> .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP3430),
> };
>
> static struct omapdev gpio3_3xxx_omapdev = {
> .name = "gpio3_omapdev",
> .pwrdm = { .name = "per_pwrdm" },
> + .wkst_mask = OMAP3430_ST_GPIO3_MASK,
> .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP3430),
> };
>
> static struct omapdev gpio4_3xxx_omapdev = {
> .name = "gpio4_omapdev",
> .pwrdm = { .name = "per_pwrdm" },
> + .wkst_mask = OMAP3430_ST_GPIO4_MASK,
> .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP3430),
> };
>
> static struct omapdev gpio5_3xxx_omapdev = {
> .name = "gpio5_omapdev",
> .pwrdm = { .name = "per_pwrdm" },
> + .wkst_mask = OMAP3430_ST_GPIO5_MASK,
> .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP3430),
> };
>
> static struct omapdev gpio6_3xxx_omapdev = {
> .name = "gpio6_omapdev",
> .pwrdm = { .name = "per_pwrdm" },
> + .wkst_mask = OMAP3430_ST_GPIO6_MASK,
> .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP3430),
> };
>
> @@ -656,6 +716,7 @@ static struct omapdev dap_3xxx_omapdev = {
> static struct omapdev usbhost_3xxx_omapdev = {
> .name = "usbhost_omapdev",
> .pwrdm = { .name = "usbhost_pwrdm" },
> + .wkst_mask = OMAP3430ES2_ST_USBHOST,
> .pdev_name = "ehci-omap",
> .pdev_id = 0,
> .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP3430ES2),
> @@ -664,6 +725,7 @@ static struct omapdev usbhost_3xxx_omapdev = {
> static struct omapdev usbotg_3xxx_omapdev = {
> .name = "usbotg_omapdev",
> .pwrdm = { .name = "usbhost_pwrdm" },
> + .wkst_mask = OMAP3430ES2_ST_HSOTGUSB_STDBY_MASK,
> .pdev_name = "musb_hdrc",
> .pdev_id = -1,
> .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP3430ES2),
> @@ -672,6 +734,7 @@ static struct omapdev usbotg_3xxx_omapdev = {
> static struct omapdev usbtll_3xxx_omapdev = {
> .name = "usbtll_omapdev",
> .pwrdm = { .name = "usbhost_pwrdm" },
> + .wkst_mask = OMAP3430ES2_ST_USBTLL_MASK,
> .pdev_name = "ehci-omap",
> .pdev_id = 0,
> .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP3430),
> diff --git a/arch/arm/mach-omap2/pm34xx.c b/arch/arm/mach-omap2/pm34xx.c
> index 7a561db..2832e08 100644
> --- a/arch/arm/mach-omap2/pm34xx.c
> +++ b/arch/arm/mach-omap2/pm34xx.c
> @@ -42,6 +42,7 @@
> #include <mach/dma.h>
> #include <mach/gpmc.h>
> #include <mach/dma.h>
> +#include <mach/wake.h>
> #include <asm/tlbflush.h>
>
> #include "cm.h"
> @@ -93,6 +94,13 @@ static struct prm_setup_times prm_setup = {
> .voltsetup2 = 0xff,
> };
>
> +static struct pm_wakeup_status omap3_pm_wkst;
> +
> +void omap3_get_last_wakeup_state(struct pm_wakeup_status *pm_wkst)
> +{
> + *pm_wkst = omap3_pm_wkst;
> +}
> +
> static inline void omap3_per_save_context(void)
> {
> omap3_gpio_save_context();
> @@ -202,6 +210,7 @@ static irqreturn_t prcm_interrupt_handler (int irq, void *dev_id)
>
> /* WKUP */
> wkst = prm_read_mod_reg(WKUP_MOD, PM_WKST);
> + omap3_pm_wkst.wkup = wkst;
> if (wkst) {
> iclk = cm_read_mod_reg(WKUP_MOD, CM_ICLKEN);
> fclk = cm_read_mod_reg(WKUP_MOD, CM_FCLKEN);
> @@ -215,6 +224,7 @@ static irqreturn_t prcm_interrupt_handler (int irq, void *dev_id)
>
> /* CORE */
> wkst = prm_read_mod_reg(CORE_MOD, PM_WKST1);
> + omap3_pm_wkst.core1 = wkst;
> if (wkst) {
> iclk = cm_read_mod_reg(CORE_MOD, CM_ICLKEN1);
> fclk = cm_read_mod_reg(CORE_MOD, CM_FCLKEN1);
> @@ -226,6 +236,7 @@ static irqreturn_t prcm_interrupt_handler (int irq, void *dev_id)
> cm_write_mod_reg(fclk, CORE_MOD, CM_FCLKEN1);
> }
> wkst = prm_read_mod_reg(CORE_MOD, OMAP3430ES2_PM_WKST3);
> + omap3_pm_wkst.core3 = wkst;
> if (wkst) {
> iclk = cm_read_mod_reg(CORE_MOD, CM_ICLKEN3);
> fclk = cm_read_mod_reg(CORE_MOD, OMAP3430ES2_CM_FCLKEN3);
> @@ -239,6 +250,7 @@ static irqreturn_t prcm_interrupt_handler (int irq, void *dev_id)
>
> /* PER */
> wkst = prm_read_mod_reg(OMAP3430_PER_MOD, PM_WKST);
> + omap3_pm_wkst.per = wkst;
> if (wkst) {
> iclk = cm_read_mod_reg(OMAP3430_PER_MOD, CM_ICLKEN);
> fclk = cm_read_mod_reg(OMAP3430_PER_MOD, CM_FCLKEN);
> @@ -253,6 +265,7 @@ static irqreturn_t prcm_interrupt_handler (int irq, void *dev_id)
> if (omap_rev() > OMAP3430_REV_ES1_0) {
> /* USBHOST */
> wkst = prm_read_mod_reg(OMAP3430ES2_USBHOST_MOD, PM_WKST);
> + omap3_pm_wkst.usbhost = wkst;
> if (wkst) {
> iclk = cm_read_mod_reg(OMAP3430ES2_USBHOST_MOD,
> CM_ICLKEN);
> diff --git a/arch/arm/mach-omap2/prcm-common.h b/arch/arm/mach-omap2/prcm-common.h
> index cb1ae84..8ccadcc 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 OMAP3430ES2_ST_USBTLL_SHIFT 2
> +#define OMAP3430ES2_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 06fee29..6826bf0 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 OMAP3430ES2_ST_MMC3_SHIFT 30
> +#define OMAP3430ES2_ST_MMC3_MASK (1 << 30)
>
> /* PM_PWSTCTRL_CORE specific bits */
> #define OMAP3430_MEM2ONSTATE_SHIFT 18
> @@ -432,6 +434,9 @@
>
> /* PM_PREPWSTST_PER specific bits */
>
> +/* PM_WKST_USBHOST specific bits */
> +#define OMAP3430ES2_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..52938d8
> --- /dev/null
> +++ b/arch/arm/mach-omap2/wake34xx.c
> @@ -0,0 +1,409 @@
> +/*
> + * 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/pm.h>
> +#include <mach/mux.h>
> +#include <mach/control.h>
> +#include <mach/wake.h>
> +
> +#include "prm-regbits-34xx.h"
> +#include "omapdev-common.h"
> +
> +/*
> + * Sometimes, it is necessary to find out "what does wake up my board from
> + * suspend?". 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 from
> + * Suspend-to-RAM state to minimize power consumption. Note that this
> + * driver can't inform wake-up events from idle state. This driver uses
> + * sysfs interface to give information to user mode applications.
> + */
> +
> +#define WAKE_STR_LEN 128
> +#define WAKE_BUF_LEN 64
> +
> +struct omap_wake {
> + u32 pending_irqs[INTCPS_NR_MIR_REGS];
> +
> + struct omap_wake_platform_data *pdata;
> + struct pm_wakeup_status pm_wkst;
> +};
> +
> +/* Note: Allowed to use Only in the wakeup_source_show() function */
> +static struct omap_wake *g_wake;
> +
> +static ssize_t wakeup_source_show(struct kobject *kobj,
> + struct kobj_attribute *attr, char *buf);
> +
> +/*
> + * Get the first pending MPU IRQ number from 'irq_start'.
> + * If none, return -EINVAL.
> + */
> +static int omap3_wake_get_pending_irq(struct omap_wake *wake,
> + unsigned int irq_start)
> +{
> + int i, bits_skip, idx_start;
> +
> + if (irq_start >= INTCPS_NR_IRQS)
> + return -EINVAL;
> +
> + bits_skip = irq_start % IRQ_BITS_PER_REG;
> + idx_start = irq_start / IRQ_BITS_PER_REG;
> +
> + for (i = idx_start; i < ARRAY_SIZE(wake->pending_irqs); i++) {
> + unsigned long val, bit;
> +
> + val = wake->pending_irqs[i];
> + if (!val)
> + continue;
> +
> + if (idx_start == i)
> + bit = find_next_bit(&val, IRQ_BITS_PER_REG, bits_skip);
> + else
> + bit = find_first_bit(&val, IRQ_BITS_PER_REG);
> +
> + if (bit < IRQ_BITS_PER_REG)
> + return i * IRQ_BITS_PER_REG + bit;
> + }
> +
> + return -EINVAL;
> +}
> +
> +static void omap3_wake_strncat(char *dest, char *src, size_t count)
> +{
> + int len;
> +
> + if (!src[0])
> + return;
> +
> + if (dest[0])
> + len = strlen(dest) + strlen(src) + 2;
> + else
> + len = strlen(dest) + strlen(src);
> +
> + if (len > count) {
> + pr_err("Can't strncat: %s\n", src);
> + return;
> + }
> +
> + if (dest[0])
> + strcat(dest, ", ");
> + strcat(dest, src);
> +}
> +
> +static u32 omap3_wake_get_domain_wkst(struct omap_wake *wake,
> + struct omapdev *omap3_dev)
> +{
> + struct pm_wakeup_status *pm_wkst = &wake->pm_wkst;
> + const char *pwrdm_name = omap3_dev->pwrdm.name;
> +
> + if (!strcmp(pwrdm_name, "wkup_pwrdm")) {
> + return pm_wkst->wkup;
> + } else if (!strcmp(pwrdm_name, "per_pwrdm")) {
> + return pm_wkst->per;
> + } else if (!strcmp(pwrdm_name, "core_pwrdm")) {
> + return pm_wkst->core1;
> + } else if (!strcmp(pwrdm_name, "usbhost_pwrdm")) {
> + if (!strcmp(omap3_dev->name, "usbtll_omapdev"))
> + return pm_wkst->core3;
> + else if (!strcmp(omap3_dev->name, "usbhost_omapdev"))
> + return pm_wkst->usbhost;
> + }
> +
> + return -EINVAL;
> +}
> +
> +static void omap3_wake_lookup_wkst(struct omap_wake *wake,
> + char *wake_event, size_t count)
> +{
> + struct omapdev **d;
> +
> + for (d = omapdevs; *d; d++) {
> + u32 wkst;
> +
> + if (!omap_chip_is((*d)->omap_chip))
> + continue;
> +
> + wkst = omap3_wake_get_domain_wkst(wake, *d);
> + if (wkst <= 0)
> + continue;
> +
> + if (wkst & (*d)->wkst_mask)
> + omap3_wake_strncat(wake_event,
> + (char *)(*d)->name, count);
> + }
> +}
> +
> +static void omap3_wake_lookup_iopad(struct omap_wake *wake,
> + char *wake_event, size_t count)
> +{
> + struct omap_wake_platform_data *pdata = wake->pdata;
> + int i;
> +
> + for (i = 0; pdata && i < pdata->iopad_wake_num; i++) {
> + struct iopad_wake *iopad = pdata->iopad_wakes + i;
> + char *wksrc_iopad;
> +
> + if (!iopad->is_wake_source)
> + continue;
> +
> + if (iopad->alias) {
> + wksrc_iopad = (char *)iopad->alias;
> + } else {
> + struct pin_config *cfg = NULL;
> + int err;
> +
> + err = omap_get_pin_config(iopad->mux_index, &cfg);
> + if (err || !cfg)
> + continue;
> +
> + wksrc_iopad = cfg->name;
> + }
> +
> + omap3_wake_strncat(wake_event, wksrc_iopad, count);
> + }
> +}
> +
> +static void omap3_wake_dump_wksrc(struct omap_wake *wake,
> + char *wake_irq, char *wake_event,
> + size_t irq_size, size_t event_size)
> +{
> + int irq, prcm_irq = 0;
> +
> + /* IRQ */
> + irq = omap3_wake_get_pending_irq(wake, 0);
> + while (irq >= 0) {
> + char buf[WAKE_BUF_LEN] = {0, };
> + int len;
> +
> + if (irq == INT_34XX_SYS_NIRQ)
> + omap3_wake_strncat(wake_event, "sys_nirq",
> + event_size - 1);
> + else if (irq == INT_34XX_PRCM_MPU_IRQ)
> + prcm_irq = 1;
> +
> + len = strlen(wake_irq) +
> + snprintf(buf, WAKE_BUF_LEN, "%d", irq);
> + if (len > irq_size - 1)
> + break;
> +
> + strcat(wake_irq, buf);
> +
> + irq = omap3_wake_get_pending_irq(wake, irq + 1);
> + if (irq >= 0) {
> + len = strlen(wake_irq) + 2;
> + if (len > irq_size - 1)
> + break;
> +
> + strcat(wake_irq, ", ");
> + }
> + }
> +
> + if (prcm_irq) {
> + omap3_wake_lookup_wkst(wake, wake_event, event_size - 1);
> + if (strstr(wake_event, io_3xxx_omapdev.name)) {
> + omap3_wake_lookup_iopad(wake, wake_event,
> + event_size - 1);
> + }
> + }
> +
> + if (!wake_irq[0])
> + strncpy(wake_irq, "Unknown", irq_size - 1);
> +
> + if (!wake_event[0])
> + strncpy(wake_event, "Unknown", event_size - 1);
> +}
> +
> +static struct kobj_attribute wakeup_irq_attr =
> + __ATTR(omap_resume_irq, 0644, wakeup_source_show, NULL);
> +
> +static struct kobj_attribute wakeup_event_attr =
> + __ATTR(omap_resume_event, 0644, wakeup_source_show, NULL);
> +
> +static ssize_t wakeup_source_show(struct kobject *kobj,
> + struct kobj_attribute *attr, char *buf)
> +{
> + char wakeup_irq[WAKE_STR_LEN] = {0, };
> + char wakeup_event[WAKE_STR_LEN] = {0, };
> +
> + if (!g_wake)
> + return -EINVAL;
> +
> + omap3_wake_dump_wksrc(g_wake, wakeup_irq, wakeup_event,
> + sizeof(wakeup_irq), sizeof(wakeup_event));
> +
> + 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 int __devinit omap3_wake_probe(struct platform_device *pdev)
> +{
> + struct omap_wake *wake;
> + int ret;
> +
> + wake = kzalloc(sizeof(struct omap_wake), GFP_KERNEL);
> + if (wake == NULL) {
> + dev_err(&pdev->dev, "failed to allocate driver data\n");
> + return -ENOMEM;
> + }
> +
> + wake->pdata = pdev->dev.platform_data;
> + platform_set_drvdata(pdev, wake);
> +
> + /*
> + * In wakeup_source_show(), we can't access platform_device
> + * or omap_wake structure without a global variable. so 'g_wake' is
> + * needed, but please use it carefully.
> + */
> + g_wake = wake;
> +
> + 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;
> +}
> +
> +static int __devexit omap3_wake_remove(struct platform_device *pdev)
> +{
> + struct omap_wake *wake = platform_get_drvdata(pdev);
> +
> + kfree(wake);
> + g_wake = NULL;
> +
> + return 0;
> +}
> +
> +static int omap3_wake_suspend(struct platform_device *pdev, pm_message_t state)
> +{
> + struct omap_wake_platform_data *pdata = pdev->dev.platform_data;
> + int i;
> +
> + /*
> + * Whenever the system enters suspend, set WAKEUPENABLE bits again.
> + * Because the omap_cfg_reg() function could clear WAKEUPENABLE bits
> + * at runtime.
> + */
> + for (i = 0; pdata && i < pdata->iopad_wake_num; i++) {
> + struct iopad_wake *iopad = pdata->iopad_wakes + i;
> + struct pin_config *cfg = NULL;
> + int err;
> + u16 v;
> +
> + err = omap_get_pin_config(iopad->mux_index, &cfg);
> + if (err || !cfg)
> + continue;
> +
> + v = omap_ctrl_readw(cfg->mux_reg);
> + v |= OMAP3_PADCONF_WAKEUPENABLE0;
> + omap_ctrl_writew(v, cfg->mux_reg);
> +
> + /* Reset previsous wake-up event information of each pin */
> + iopad->is_wake_source = false;
> + }
> +
> + return 0;
> +}
> +
> +static int omap3_wake_resume_early(struct platform_device *pdev)
> +{
> + struct omap_wake *wake = platform_get_drvdata(pdev);
> + struct omap_wake_platform_data *pdata = wake->pdata;
> + int i;
> +
> + omap_get_pending_irqs(wake->pending_irqs,
> + ARRAY_SIZE(wake->pending_irqs));
> +
> + for (i = 0; pdata && i < pdata->iopad_wake_num; i++) {
> + struct iopad_wake *iopad = pdata->iopad_wakes + i;
> + struct pin_config *cfg = NULL;
> + int err;
> + u16 v;
> +
> + err = omap_get_pin_config(iopad->mux_index, &cfg);
> + if (err || !cfg)
> + continue;
> +
> + v = omap_ctrl_readw(cfg->mux_reg);
> + v &= ~OMAP3_PADCONF_WAKEUPENABLE0;
> + omap_ctrl_writew(v, cfg->mux_reg);
> +
> + if (v & OMAP3_PADCONF_WAKEUPEVENT0)
> + iopad->is_wake_source = true;
> + }
> +
> + return 0;
> +}
> +
> +static int omap3_wake_resume(struct platform_device *pdev)
> +{
> + struct omap_wake *wake = platform_get_drvdata(pdev);
> +
> +#ifdef CONFIG_PM_DEBUG
> + char wakeup_irq[WAKE_STR_LEN] = {0, };
> + char wakeup_event[WAKE_STR_LEN] = {0, };
> +
> + omap3_wake_dump_wksrc(wake, wakeup_irq, wakeup_event,
> + sizeof(wakeup_irq), sizeof(wakeup_event));
> +
> + pr_info("OMAP resume IRQ: %s\n", wakeup_irq);
> + pr_info("OMAP resume event: %s\n", wakeup_event);
> +#endif
> +
> + omap3_get_last_wakeup_state(&wake->pm_wkst);
> +
> + return 0;
> +}
> +
> +static struct platform_driver omap3_wake_driver = {
> + .probe = omap3_wake_probe,
> + .remove = __devexit_p(omap3_wake_remove),
> + .suspend = omap3_wake_suspend,
> + .resume_early = omap3_wake_resume_early,
> + .resume = omap3_wake_resume,
> + .driver = {
> + .name = "omap-wake",
> + .owner = THIS_MODULE,
> + },
> +};
> +
> +static int __init omap3_wake_init(void)
> +{
> + return platform_driver_register(&omap3_wake_driver);
> +}
> +late_initcall(omap3_wake_init);
> +
> +static void __exit omap3_wake_exit(void)
> +{
> + platform_driver_unregister(&omap3_wake_driver);
> +}
> +module_exit(omap3_wake_exit);
> +
> +MODULE_AUTHOR("Kim Kyuwon <q1.kim@samsung.com>");
> +MODULE_DESCRIPTION("OMAP34xx wakeup source driver");
> +MODULE_LICENSE("GPL v2");
> diff --git a/arch/arm/plat-omap/Kconfig b/arch/arm/plat-omap/Kconfig
> index a2d15a1..24eb6c1 100644
> --- a/arch/arm/plat-omap/Kconfig
> +++ b/arch/arm/plat-omap/Kconfig
> @@ -236,6 +236,15 @@ config OMAP_DM_TIMER
> help
> Select this option if you want to use OMAP Dual-Mode timers.
>
> +config OMAP3_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 suspend. This driver also privides the
> + I/O pad wake-up source configuration.
> +
> choice
> prompt "Low-level debug console UART"
> depends on ARCH_OMAP
> diff --git a/arch/arm/plat-omap/include/mach/irqs.h b/arch/arm/plat-omap/include/mach/irqs.h
> index c9a5b19..ee15402 100644
> --- a/arch/arm/plat-omap/include/mach/irqs.h
> +++ b/arch/arm/plat-omap/include/mach/irqs.h
> @@ -385,9 +385,13 @@
> #define INTCPS_NR_MIR_REGS 3
> #define INTCPS_NR_IRQS 96
>
> +/* Number of IRQ state bits in each MIR register */
> +#define IRQ_BITS_PER_REG 32
> +
> #ifndef __ASSEMBLY__
> extern void omap_init_irq(void);
> extern int omap_irq_pending(void);
> +extern void omap_get_pending_irqs(u32 *pending_irqs, unsigned len);
> void omap3_intc_save_context(void);
> void omap3_intc_restore_context(void);
> #endif
> diff --git a/arch/arm/plat-omap/include/mach/mux.h b/arch/arm/plat-omap/include/mach/mux.h
> index f7e298a..f6cb7b1 100644
> --- a/arch/arm/plat-omap/include/mach/mux.h
> +++ b/arch/arm/plat-omap/include/mach/mux.h
> @@ -816,11 +816,14 @@ struct omap_mux_cfg {
> extern int omap1_mux_init(void);
> extern int omap2_mux_init(void);
> extern int omap_mux_register(struct omap_mux_cfg *);
> +extern int omap_get_pin_config(unsigned long index, struct pin_config **cfg);
> extern int omap_cfg_reg(unsigned long reg_cfg);
> #else
> /* boot loader does it all (no warnings from CONFIG_OMAP_MUX_WARNINGS) */
> static inline int omap1_mux_init(void) { return 0; }
> static inline int omap2_mux_init(void) { return 0; }
> +static inline int omap_get_pin_config(unsigned long index,
> + struct pin_config **cfg) { return 0; }
> static inline int omap_cfg_reg(unsigned long reg_cfg) { return 0; }
> #endif
>
> diff --git a/arch/arm/plat-omap/include/mach/omapdev.h b/arch/arm/plat-omap/include/mach/omapdev.h
> index 4b379bc..2359073 100644
> --- a/arch/arm/plat-omap/include/mach/omapdev.h
> +++ b/arch/arm/plat-omap/include/mach/omapdev.h
> @@ -24,6 +24,7 @@
> * struct omapdev - OMAP on-chip hardware devices
> * @name: name of the device - should match TRM
> * @pwrdm: powerdomain that the device resides in
> + * @wkst_mask: wake-up state bit in PM_WKST_<domain> associated with pwrdm
> * @omap_chip: OMAP chips this omapdev is valid for
> * @pdev_name: platform_device name associated with this omapdev (if any)
> * @pdev_id: platform_device id associated with this omapdev (if any)
> @@ -38,6 +39,8 @@ struct omapdev {
> struct powerdomain *ptr;
> } pwrdm;
>
> + const u32 wkst_mask;
> +
> const struct omap_chip_id omap_chip;
>
> const char *pdev_name;
> 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..5b725e3
> --- /dev/null
> +++ b/arch/arm/plat-omap/include/mach/wake.h
> @@ -0,0 +1,52 @@
> +/*
> + * 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 iopad_wake - used to enable each I/O pad of the device
> + * to wake up the system and detect wake-up events of each I/O pad.
> + *
> + * The mux layer (mux.c/h files) doesn't have resume hook, so checking
> + * WAKEUPEVENT in the CONTROL_PADCONF_X register before being cleared by
> + * PRCM IRQ would be difficult in the mux layer. Thus, this wake source
> + * driver takes charge of Wake-Up Event Detection Scheme
> + *
> + * @mux_index: enumeration index of omapxxxx_index in mux.h
> + * @alias: descriptive name of each pin (optional)
> + * @is_wake_source: automatically set by suspend & resume hooks
> + */
> +struct iopad_wake {
> + const u32 mux_index;
> + const char *alias;
> + bool is_wake_source;
> +};
> +
> +struct omap_wake_platform_data{
> + struct iopad_wake *iopad_wakes;
> + int iopad_wake_num;
> +};
> +
> +struct pm_wakeup_status {
> + u32 wkup;
> + u32 per;
> + u32 core1;
> + u32 core3;
> + u32 usbhost;
> +};
> +
> +void omap3_get_last_wakeup_state(struct pm_wakeup_status *pm_wkst);
> +
> +#endif /* _WAKE_H_ */
> +
> diff --git a/arch/arm/plat-omap/mux.c b/arch/arm/plat-omap/mux.c
> index 80b040f..6bf321b 100644
> --- a/arch/arm/plat-omap/mux.c
> +++ b/arch/arm/plat-omap/mux.c
> @@ -47,13 +47,8 @@ int __init omap_mux_register(struct omap_mux_cfg *arch_mux_cfg)
> return 0;
> }
>
> -/*
> - * Sets the Omap MUX and PULL_DWN registers based on the table
> - */
> -int __init_or_module omap_cfg_reg(const unsigned long index)
> +int omap_get_pin_config(const unsigned long index, struct pin_config **cfg)
> {
> - struct pin_config *reg;
> -
> if (mux_cfg == NULL) {
> printk(KERN_ERR "Pin mux table not initialized\n");
> return -ENODEV;
> @@ -66,7 +61,23 @@ int __init_or_module omap_cfg_reg(const unsigned long index)
> return -ENODEV;
> }
>
> - reg = (struct pin_config *)&mux_cfg->pins[index];
> + *cfg = &mux_cfg->pins[index];
> +
> + return 0;
> +}
> +EXPORT_SYMBOL(omap_get_pin_config);
> +
> +/*
> + * Sets the Omap MUX and PULL_DWN registers based on the table
> + */
> +int __init_or_module omap_cfg_reg(const unsigned long index)
> +{
> + struct pin_config *reg = NULL;
> + int err;
> +
> + err = omap_get_pin_config(index, ®);
> + if (err || !reg)
> + return err;
>
> if (!mux_cfg->cfg_reg)
> return -ENODEV;
> --
> 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
>
--
Kyuwon (규원)
--
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
^ permalink raw reply [flat|nested] 4+ messages in thread
* Re: OMAP3: PM: Add the wakeup source driver, v4
2009-05-14 4:49 ` Kim Kyuwon
@ 2009-05-14 18:32 ` Kevin Hilman
2009-05-14 23:51 ` Kim Kyuwon
0 siblings, 1 reply; 4+ messages in thread
From: Kevin Hilman @ 2009-05-14 18:32 UTC (permalink / raw)
To: Kim Kyuwon; +Cc: OMAP, Paul Walmsley
Kim Kyuwon <chammoru@gmail.com> writes:
> Hi Kevin,
>
> Could you please review this fourth version of OMAP wakeup source driver?
>
Yes. I'm working through my backlog of PM branch submissions this
week.
I've been focusing on getting some of the PM branch reworked and
rebased so I can start submitting upstream.
I apologize for the delays, but the upstream work is currently higher
priority than adding large new features to the PM branch.
Kevin
>
> On Tue, May 5, 2009 at 6:13 PM, Kim Kyuwon <q1.kim@samsung.com> wrote:
>> Sometimes, it is necessary to find out "what does wake up my board from suspend?". 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 from Suspend-to-RAM state to minimize power consumption. Note that this driver can't inform wake-up events from idle state. This driver uses sysfs interface to give information to user mode applications like:
>>
>> cat /sys/power/omap_resume_irq
>> cat /sys/power/omap_resume_event
>>
>> This driver also provides the I/O pad wake-up source configuration. Specific GPIO settings in the board file are:
>>
>> /* I/O pad wakeup source configuration */
>> static struct iopad_wake boardname_iopad_wake[] = {
>> {
>> .mux_index = AE7_34XX_GPIO24,
>> .alias = "KEY_PWRON",
>> },
>> {
>> .mux_index = ETK_D9_GPIO23,
>> .alias = "USB_DETECT",
>> },
>> };
>>
>> static struct omap_wake_platform_data boardname_wake_data = {
>> .iopad_wakes = boardname_iopad_wake,
>> .iopad_wake_num = ARRAY_SIZE(boardname_iopad_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 | 21 ++-
>> arch/arm/mach-omap2/omapdev-common.h | 3 +
>> arch/arm/mach-omap2/omapdev3xxx.h | 63 +++++
>> arch/arm/mach-omap2/pm34xx.c | 13 +
>> arch/arm/mach-omap2/prcm-common.h | 4 +
>> arch/arm/mach-omap2/prm-regbits-34xx.h | 5 +
>> arch/arm/mach-omap2/wake34xx.c | 409 +++++++++++++++++++++++++++++
>> arch/arm/plat-omap/Kconfig | 9 +
>> arch/arm/plat-omap/include/mach/irqs.h | 4 +
>> arch/arm/plat-omap/include/mach/mux.h | 3 +
>> arch/arm/plat-omap/include/mach/omapdev.h | 3 +
>> arch/arm/plat-omap/include/mach/wake.h | 52 ++++
>> arch/arm/plat-omap/mux.c | 25 ++-
>> 14 files changed, 605 insertions(+), 10 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 c58bab4..cfc5a13 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_OMAP3_WAKE) += wake34xx.o
>> endif
>>
>> # SmartReflex driver
>> diff --git a/arch/arm/mach-omap2/irq.c b/arch/arm/mach-omap2/irq.c
>> index 700fc3d..18ac725 100644
>> --- a/arch/arm/mach-omap2/irq.c
>> +++ b/arch/arm/mach-omap2/irq.c
>> @@ -33,9 +33,6 @@
>> #define INTC_MIR_SET0 0x008c
>> #define INTC_PENDING_IRQ0 0x0098
>>
>> -/* Number of IRQ state bits in each MIR register */
>> -#define IRQ_BITS_PER_REG 32
>> -
>> /*
>> * OMAP2 has a number of different interrupt controllers, each interrupt
>> * controller is identified as its own "bank". Register definitions are
>> @@ -193,6 +190,24 @@ int omap_irq_pending(void)
>> return 0;
>> }
>>
>> +void omap_get_pending_irqs(u32 *pending_irqs, unsigned len)
>> +{
>> + int i, j = 0;
>> +
>> + for (i = 0; i < ARRAY_SIZE(irq_banks); i++) {
>> + struct omap_irq_bank *bank = irq_banks + i;
>> + int irq;
>> +
>> + for (irq = 0; irq < bank->nr_irqs && j < len;
>> + irq += IRQ_BITS_PER_REG) {
>> + int offset = irq & (~(IRQ_BITS_PER_REG - 1));
>> +
>> + pending_irqs[j++] = intc_bank_read_reg(bank,
>> + (INTC_PENDING_IRQ0 + offset));
>> + }
>> + }
>> +}
>> +
>> void __init omap_init_irq(void)
>> {
>> unsigned long nr_of_irqs = 0;
>> diff --git a/arch/arm/mach-omap2/omapdev-common.h b/arch/arm/mach-omap2/omapdev-common.h
>> index a2d4855..57b9b0b 100644
>> --- a/arch/arm/mach-omap2/omapdev-common.h
>> +++ b/arch/arm/mach-omap2/omapdev-common.h
>> @@ -228,10 +228,13 @@ static struct omapdev *omapdevs[] = {
>> &hsmmc2_3xxx_omapdev,
>> &mcspi3_3xxx_omapdev,
>> &gptimer1_3xxx_omapdev,
>> + &gptimer12_3xxx_omapdev,
>> &prm_3xxx_omapdev,
>> &cm_3xxx_omapdev,
>> &omap_32ksynct_3xxx_omapdev,
>> &gpio1_3xxx_omapdev,
>> + &io_3xxx_omapdev,
>> + &io_chain_3xxx_omapdev,
>> &wdtimer2_3xxx_omapdev,
>> &wdtimer1_3xxx_omapdev,
>> &rng_3xxx_omapdev,
>> diff --git a/arch/arm/mach-omap2/omapdev3xxx.h b/arch/arm/mach-omap2/omapdev3xxx.h
>> index dce87df..9091a88 100644
>> --- a/arch/arm/mach-omap2/omapdev3xxx.h
>> +++ b/arch/arm/mach-omap2/omapdev3xxx.h
>> @@ -19,6 +19,8 @@
>> #include <mach/cpu.h>
>> #include <mach/omapdev.h>
>>
>> +#include "prm-regbits-34xx.h"
>> +
>> #ifdef CONFIG_ARCH_OMAP3
>>
>> /* 3xxx data from the 34xx ES2 TRM Rev F */
>> @@ -146,6 +148,7 @@ static struct omapdev sdma_3xxx_omapdev = {
>> static struct omapdev i2c1_3xxx_omapdev = {
>> .name = "i2c1_omapdev",
>> .pwrdm = { .name = "core_pwrdm" },
>> + .wkst_mask = OMAP3430_ST_I2C1_MASK,
>> .pdev_name = "i2c_omap",
>> .pdev_id = 1,
>> .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP3430),
>> @@ -154,6 +157,7 @@ static struct omapdev i2c1_3xxx_omapdev = {
>> static struct omapdev i2c2_3xxx_omapdev = {
>> .name = "i2c2_omapdev",
>> .pwrdm = { .name = "core_pwrdm" },
>> + .wkst_mask = OMAP3430_ST_I2C2_MASK,
>> .pdev_name = "i2c_omap",
>> .pdev_id = 2,
>> .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP3430),
>> @@ -162,6 +166,7 @@ static struct omapdev i2c2_3xxx_omapdev = {
>> static struct omapdev uart1_3xxx_omapdev = {
>> .name = "uart1_omapdev",
>> .pwrdm = { .name = "core_pwrdm" },
>> + .wkst_mask = OMAP3430_ST_UART1_MASK,
>> .pdev_name = "serial8250",
>> .pdev_id = PLAT8250_DEV_PLATFORM,
>> .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP3430),
>> @@ -170,6 +175,7 @@ static struct omapdev uart1_3xxx_omapdev = {
>> static struct omapdev uart2_3xxx_omapdev = {
>> .name = "uart2_omapdev",
>> .pwrdm = { .name = "core_pwrdm" },
>> + .wkst_mask = OMAP3430_ST_UART2_MASK,
>> .pdev_name = "serial8250",
>> .pdev_id = PLAT8250_DEV_PLATFORM,
>> .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP3430),
>> @@ -178,6 +184,7 @@ static struct omapdev uart2_3xxx_omapdev = {
>> static struct omapdev mcbsp1_3xxx_omapdev = {
>> .name = "mcbsp1_omapdev",
>> .pwrdm = { .name = "core_pwrdm" },
>> + .wkst_mask = OMAP3430_ST_MCBSP1_MASK,
>> .pdev_name = "omap-mcbsp",
>> .pdev_id = 1,
>> .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP3430),
>> @@ -186,12 +193,14 @@ static struct omapdev mcbsp1_3xxx_omapdev = {
>> static struct omapdev gptimer10_3xxx_omapdev = {
>> .name = "gptimer10_omapdev",
>> .pwrdm = { .name = "core_pwrdm" },
>> + .wkst_mask = OMAP3430_ST_GPT10_MASK,
>> .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP3430),
>> };
>>
>> static struct omapdev gptimer11_3xxx_omapdev = {
>> .name = "gptimer11_omapdev",
>> .pwrdm = { .name = "core_pwrdm" },
>> + .wkst_mask = OMAP3430_ST_GPT11_MASK,
>> .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP3430),
>> };
>>
>> @@ -206,6 +215,7 @@ static struct omapdev mailbox_3xxx_omapdev = {
>> static struct omapdev mcspi1_3xxx_omapdev = {
>> .name = "mcspi1_omapdev",
>> .pwrdm = { .name = "core_pwrdm" },
>> + .wkst_mask = OMAP3430_ST_MCSPI1_MASK,
>> .pdev_name = "omap2_mcspi",
>> .pdev_id = 1,
>> .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP3430),
>> @@ -214,6 +224,7 @@ static struct omapdev mcspi1_3xxx_omapdev = {
>> static struct omapdev mcspi2_3xxx_omapdev = {
>> .name = "mcspi2_omapdev",
>> .pwrdm = { .name = "core_pwrdm" },
>> + .wkst_mask = OMAP3430_ST_MCSPI2_MASK,
>> .pdev_name = "omap2_mcspi",
>> .pdev_id = 2,
>> .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP3430),
>> @@ -242,6 +253,7 @@ static struct omapdev mspro_3xxx_omapdev = {
>> static struct omapdev mcbsp5_3xxx_omapdev = {
>> .name = "mcbsp5_omapdev",
>> .pwrdm = { .name = "core_pwrdm" },
>> + .wkst_mask = OMAP3430_ST_MCBSP5_MASK,
>> .pdev_name = "omap-mcbsp",
>> .pdev_id = 5,
>> .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP3430),
>> @@ -250,6 +262,7 @@ static struct omapdev mcbsp5_3xxx_omapdev = {
>> static struct omapdev hsmmc1_3xxx_omapdev = {
>> .name = "hsmmc1_omapdev",
>> .pwrdm = { .name = "core_pwrdm" },
>> + .wkst_mask = OMAP3430_ST_MMC1_MASK,
>> .pdev_name = "mmci-omap",
>> .pdev_id = 0,
>> .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP3430),
>> @@ -258,6 +271,7 @@ static struct omapdev hsmmc1_3xxx_omapdev = {
>> static struct omapdev hsmmc2_3xxx_omapdev = {
>> .name = "hsmmc2_omapdev",
>> .pwrdm = { .name = "core_pwrdm" },
>> + .wkst_mask = OMAP3430_ST_MMC2_MASK,
>> .pdev_name = "mmci-omap",
>> .pdev_id = 1,
>> .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP3430),
>> @@ -266,6 +280,7 @@ static struct omapdev hsmmc2_3xxx_omapdev = {
>> static struct omapdev mcspi3_3xxx_omapdev = {
>> .name = "mcspi3_omapdev",
>> .pwrdm = { .name = "core_pwrdm" },
>> + .wkst_mask = OMAP3430_ST_MCSPI3_MASK,
>> .pdev_name = "omap2_mcspi",
>> .pdev_id = 3,
>> .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP3430),
>> @@ -278,6 +293,14 @@ static struct omapdev mcspi3_3xxx_omapdev = {
>> static struct omapdev gptimer1_3xxx_omapdev = {
>> .name = "gptimer1_omapdev",
>> .pwrdm = { .name = "wkup_pwrdm" },
>> + .wkst_mask = OMAP3430_ST_GPT1_MASK,
>> + .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP3430),
>> +};
>> +
>> +static struct omapdev gptimer12_3xxx_omapdev = {
>> + .name = "gptimer12_omapdev",
>> + .pwrdm = { .name = "wkup_pwrdm" },
>> + .wkst_mask = OMAP3430_ST_GPT12_MASK,
>> .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP3430),
>> };
>>
>> @@ -302,9 +325,24 @@ static struct omapdev omap_32ksynct_3xxx_omapdev = {
>> static struct omapdev gpio1_3xxx_omapdev = {
>> .name = "gpio1_omapdev",
>> .pwrdm = { .name = "wkup_pwrdm" },
>> + .wkst_mask = OMAP3430_ST_GPIO1_MASK,
>> + .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP3430),
>> +};
>> +
>> +static struct omapdev io_3xxx_omapdev = {
>> + .name = "io_omapdev",
>> + .pwrdm = { .name = "wkup_pwrdm" },
>> + .wkst_mask = OMAP3430_ST_IO,
>> .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP3430),
>> };
>>
>> +static struct omapdev io_chain_3xxx_omapdev = {
>> + .name = "io_chain_omapdev",
>> + .pwrdm = { .name = "wkup_pwrdm" },
>> + .wkst_mask = OMAP3430_ST_IO_CHAIN,
>> + .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP3430ES3_1),
>> +};
>> +
>> /* aka the "omap wdtimer" on 2430 or the "mpu wdtimer" on 3430 */
>> static struct omapdev wdtimer2_3xxx_omapdev = {
>> .name = "wdtimer2_omapdev",
>> @@ -425,6 +463,7 @@ static struct omapdev control_3xxx_omapdev = {
>> static struct omapdev i2c3_3xxx_omapdev = {
>> .name = "i2c3_omapdev",
>> .pwrdm = { .name = "core_pwrdm" },
>> + .wkst_mask = OMAP3430_ST_I2C3_MASK,
>> .pdev_name = "i2c_omap",
>> .pdev_id = 3,
>> .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP3430),
>> @@ -433,6 +472,7 @@ static struct omapdev i2c3_3xxx_omapdev = {
>> static struct omapdev hsmmc3_3xxx_omapdev = {
>> .name = "hsmmc3_omapdev",
>> .pwrdm = { .name = "core_pwrdm" },
>> + .wkst_mask = OMAP3430ES2_ST_MMC3_MASK,
>> .pdev_name = "mmci-omap",
>> .pdev_id = 2,
>> .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP3430ES2),
>> @@ -441,6 +481,7 @@ static struct omapdev hsmmc3_3xxx_omapdev = {
>> static struct omapdev mcspi4_3xxx_omapdev = {
>> .name = "mcspi4_omapdev",
>> .pwrdm = { .name = "core_pwrdm" },
>> + .wkst_mask = OMAP3430_ST_MCSPI4_MASK,
>> .pdev_name = "omap2_mcspi",
>> .pdev_id = 4,
>> .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP3430),
>> @@ -461,12 +502,14 @@ static struct omapdev sr2_3xxx_omapdev = {
>> static struct omapdev usbhost_es1_3xxx_omapdev = {
>> .name = "usbhost_omapdev",
>> .pwrdm = { .name = "core_pwrdm" },
>> + .wkst_mask = OMAP3430ES1_ST_FSHOSTUSB_MASK,
>> .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP3430ES1),
>> };
>>
>> static struct omapdev usbotg_es1_3xxx_omapdev = {
>> .name = "usbotg_omapdev",
>> .pwrdm = { .name = "core_pwrdm" },
>> + .wkst_mask = OMAP3430ES1_ST_HSOTGUSB_MASK,
>> .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP3430ES1),
>> };
>>
>> @@ -475,6 +518,7 @@ static struct omapdev usbotg_es1_3xxx_omapdev = {
>> static struct omapdev uart3_3xxx_omapdev = {
>> .name = "uart3_omapdev",
>> .pwrdm = { .name = "per_pwrdm" },
>> + .wkst_mask = OMAP3430_ST_UART3_MASK,
>> .pdev_name = "serial8250",
>> .pdev_id = PLAT8250_DEV_PLATFORM,
>> .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP3430),
>> @@ -483,6 +527,7 @@ static struct omapdev uart3_3xxx_omapdev = {
>> static struct omapdev mcbsp2_3xxx_omapdev = {
>> .name = "mcbsp2_omapdev",
>> .pwrdm = { .name = "per_pwrdm" },
>> + .wkst_mask = OMAP3430_EN_MCBSP2,
>> .pdev_name = "omap-mcbsp",
>> .pdev_id = 2,
>> .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP3430),
>> @@ -491,6 +536,7 @@ static struct omapdev mcbsp2_3xxx_omapdev = {
>> static struct omapdev mcbsp3_3xxx_omapdev = {
>> .name = "mcbsp3_omapdev",
>> .pwrdm = { .name = "per_pwrdm" },
>> + .wkst_mask = OMAP3430_EN_MCBSP3,
>> .pdev_name = "omap-mcbsp",
>> .pdev_id = 3,
>> .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP3430),
>> @@ -499,6 +545,7 @@ static struct omapdev mcbsp3_3xxx_omapdev = {
>> static struct omapdev mcbsp4_3xxx_omapdev = {
>> .name = "mcbsp4_omapdev",
>> .pwrdm = { .name = "per_pwrdm" },
>> + .wkst_mask = OMAP3430_EN_MCBSP4,
>> .pdev_name = "omap-mcbsp",
>> .pdev_id = 3,
>> .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP3430),
>> @@ -527,78 +574,91 @@ static struct omapdev wdtimer3_3xxx_omapdev = {
>> static struct omapdev gptimer2_3xxx_omapdev = {
>> .name = "gptimer2_omapdev",
>> .pwrdm = { .name = "per_pwrdm" },
>> + .wkst_mask = OMAP3430_ST_GPT2_MASK,
>> .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP3430),
>> };
>>
>> static struct omapdev gptimer3_3xxx_omapdev = {
>> .name = "gptimer3_omapdev",
>> .pwrdm = { .name = "per_pwrdm" },
>> + .wkst_mask = OMAP3430_ST_GPT3_MASK,
>> .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP3430),
>> };
>>
>> static struct omapdev gptimer4_3xxx_omapdev = {
>> .name = "gptimer4_omapdev",
>> .pwrdm = { .name = "per_pwrdm" },
>> + .wkst_mask = OMAP3430_ST_GPT4_MASK,
>> .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP3430),
>> };
>>
>> static struct omapdev gptimer5_3xxx_omapdev = {
>> .name = "gptimer5_omapdev",
>> .pwrdm = { .name = "per_pwrdm" },
>> + .wkst_mask = OMAP3430_ST_GPT5_MASK,
>> .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP3430),
>> };
>>
>> static struct omapdev gptimer6_3xxx_omapdev = {
>> .name = "gptimer6_omapdev",
>> .pwrdm = { .name = "per_pwrdm" },
>> + .wkst_mask = OMAP3430_ST_GPT6_MASK,
>> .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP3430),
>> };
>>
>> static struct omapdev gptimer7_3xxx_omapdev = {
>> .name = "gptimer7_omapdev",
>> .pwrdm = { .name = "per_pwrdm" },
>> + .wkst_mask = OMAP3430_ST_GPT7_MASK,
>> .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP3430),
>> };
>>
>> static struct omapdev gptimer8_3xxx_omapdev = {
>> .name = "gptimer8_omapdev",
>> .pwrdm = { .name = "per_pwrdm" },
>> + .wkst_mask = OMAP3430_ST_GPT8_MASK,
>> .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP3430),
>> };
>>
>> static struct omapdev gptimer9_3xxx_omapdev = {
>> .name = "gptimer9_omapdev",
>> .pwrdm = { .name = "per_pwrdm" },
>> + .wkst_mask = OMAP3430_ST_GPT9_MASK,
>> .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP3430),
>> };
>>
>> static struct omapdev gpio2_3xxx_omapdev = {
>> .name = "gpio2_omapdev",
>> .pwrdm = { .name = "per_pwrdm" },
>> + .wkst_mask = OMAP3430_ST_GPIO2_MASK,
>> .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP3430),
>> };
>>
>> static struct omapdev gpio3_3xxx_omapdev = {
>> .name = "gpio3_omapdev",
>> .pwrdm = { .name = "per_pwrdm" },
>> + .wkst_mask = OMAP3430_ST_GPIO3_MASK,
>> .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP3430),
>> };
>>
>> static struct omapdev gpio4_3xxx_omapdev = {
>> .name = "gpio4_omapdev",
>> .pwrdm = { .name = "per_pwrdm" },
>> + .wkst_mask = OMAP3430_ST_GPIO4_MASK,
>> .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP3430),
>> };
>>
>> static struct omapdev gpio5_3xxx_omapdev = {
>> .name = "gpio5_omapdev",
>> .pwrdm = { .name = "per_pwrdm" },
>> + .wkst_mask = OMAP3430_ST_GPIO5_MASK,
>> .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP3430),
>> };
>>
>> static struct omapdev gpio6_3xxx_omapdev = {
>> .name = "gpio6_omapdev",
>> .pwrdm = { .name = "per_pwrdm" },
>> + .wkst_mask = OMAP3430_ST_GPIO6_MASK,
>> .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP3430),
>> };
>>
>> @@ -656,6 +716,7 @@ static struct omapdev dap_3xxx_omapdev = {
>> static struct omapdev usbhost_3xxx_omapdev = {
>> .name = "usbhost_omapdev",
>> .pwrdm = { .name = "usbhost_pwrdm" },
>> + .wkst_mask = OMAP3430ES2_ST_USBHOST,
>> .pdev_name = "ehci-omap",
>> .pdev_id = 0,
>> .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP3430ES2),
>> @@ -664,6 +725,7 @@ static struct omapdev usbhost_3xxx_omapdev = {
>> static struct omapdev usbotg_3xxx_omapdev = {
>> .name = "usbotg_omapdev",
>> .pwrdm = { .name = "usbhost_pwrdm" },
>> + .wkst_mask = OMAP3430ES2_ST_HSOTGUSB_STDBY_MASK,
>> .pdev_name = "musb_hdrc",
>> .pdev_id = -1,
>> .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP3430ES2),
>> @@ -672,6 +734,7 @@ static struct omapdev usbotg_3xxx_omapdev = {
>> static struct omapdev usbtll_3xxx_omapdev = {
>> .name = "usbtll_omapdev",
>> .pwrdm = { .name = "usbhost_pwrdm" },
>> + .wkst_mask = OMAP3430ES2_ST_USBTLL_MASK,
>> .pdev_name = "ehci-omap",
>> .pdev_id = 0,
>> .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP3430),
>> diff --git a/arch/arm/mach-omap2/pm34xx.c b/arch/arm/mach-omap2/pm34xx.c
>> index 7a561db..2832e08 100644
>> --- a/arch/arm/mach-omap2/pm34xx.c
>> +++ b/arch/arm/mach-omap2/pm34xx.c
>> @@ -42,6 +42,7 @@
>> #include <mach/dma.h>
>> #include <mach/gpmc.h>
>> #include <mach/dma.h>
>> +#include <mach/wake.h>
>> #include <asm/tlbflush.h>
>>
>> #include "cm.h"
>> @@ -93,6 +94,13 @@ static struct prm_setup_times prm_setup = {
>> .voltsetup2 = 0xff,
>> };
>>
>> +static struct pm_wakeup_status omap3_pm_wkst;
>> +
>> +void omap3_get_last_wakeup_state(struct pm_wakeup_status *pm_wkst)
>> +{
>> + *pm_wkst = omap3_pm_wkst;
>> +}
>> +
>> static inline void omap3_per_save_context(void)
>> {
>> omap3_gpio_save_context();
>> @@ -202,6 +210,7 @@ static irqreturn_t prcm_interrupt_handler (int irq, void *dev_id)
>>
>> /* WKUP */
>> wkst = prm_read_mod_reg(WKUP_MOD, PM_WKST);
>> + omap3_pm_wkst.wkup = wkst;
>> if (wkst) {
>> iclk = cm_read_mod_reg(WKUP_MOD, CM_ICLKEN);
>> fclk = cm_read_mod_reg(WKUP_MOD, CM_FCLKEN);
>> @@ -215,6 +224,7 @@ static irqreturn_t prcm_interrupt_handler (int irq, void *dev_id)
>>
>> /* CORE */
>> wkst = prm_read_mod_reg(CORE_MOD, PM_WKST1);
>> + omap3_pm_wkst.core1 = wkst;
>> if (wkst) {
>> iclk = cm_read_mod_reg(CORE_MOD, CM_ICLKEN1);
>> fclk = cm_read_mod_reg(CORE_MOD, CM_FCLKEN1);
>> @@ -226,6 +236,7 @@ static irqreturn_t prcm_interrupt_handler (int irq, void *dev_id)
>> cm_write_mod_reg(fclk, CORE_MOD, CM_FCLKEN1);
>> }
>> wkst = prm_read_mod_reg(CORE_MOD, OMAP3430ES2_PM_WKST3);
>> + omap3_pm_wkst.core3 = wkst;
>> if (wkst) {
>> iclk = cm_read_mod_reg(CORE_MOD, CM_ICLKEN3);
>> fclk = cm_read_mod_reg(CORE_MOD, OMAP3430ES2_CM_FCLKEN3);
>> @@ -239,6 +250,7 @@ static irqreturn_t prcm_interrupt_handler (int irq, void *dev_id)
>>
>> /* PER */
>> wkst = prm_read_mod_reg(OMAP3430_PER_MOD, PM_WKST);
>> + omap3_pm_wkst.per = wkst;
>> if (wkst) {
>> iclk = cm_read_mod_reg(OMAP3430_PER_MOD, CM_ICLKEN);
>> fclk = cm_read_mod_reg(OMAP3430_PER_MOD, CM_FCLKEN);
>> @@ -253,6 +265,7 @@ static irqreturn_t prcm_interrupt_handler (int irq, void *dev_id)
>> if (omap_rev() > OMAP3430_REV_ES1_0) {
>> /* USBHOST */
>> wkst = prm_read_mod_reg(OMAP3430ES2_USBHOST_MOD, PM_WKST);
>> + omap3_pm_wkst.usbhost = wkst;
>> if (wkst) {
>> iclk = cm_read_mod_reg(OMAP3430ES2_USBHOST_MOD,
>> CM_ICLKEN);
>> diff --git a/arch/arm/mach-omap2/prcm-common.h b/arch/arm/mach-omap2/prcm-common.h
>> index cb1ae84..8ccadcc 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 OMAP3430ES2_ST_USBTLL_SHIFT 2
>> +#define OMAP3430ES2_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 06fee29..6826bf0 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 OMAP3430ES2_ST_MMC3_SHIFT 30
>> +#define OMAP3430ES2_ST_MMC3_MASK (1 << 30)
>>
>> /* PM_PWSTCTRL_CORE specific bits */
>> #define OMAP3430_MEM2ONSTATE_SHIFT 18
>> @@ -432,6 +434,9 @@
>>
>> /* PM_PREPWSTST_PER specific bits */
>>
>> +/* PM_WKST_USBHOST specific bits */
>> +#define OMAP3430ES2_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..52938d8
>> --- /dev/null
>> +++ b/arch/arm/mach-omap2/wake34xx.c
>> @@ -0,0 +1,409 @@
>> +/*
>> + * 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/pm.h>
>> +#include <mach/mux.h>
>> +#include <mach/control.h>
>> +#include <mach/wake.h>
>> +
>> +#include "prm-regbits-34xx.h"
>> +#include "omapdev-common.h"
>> +
>> +/*
>> + * Sometimes, it is necessary to find out "what does wake up my board from
>> + * suspend?". 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 from
>> + * Suspend-to-RAM state to minimize power consumption. Note that this
>> + * driver can't inform wake-up events from idle state. This driver uses
>> + * sysfs interface to give information to user mode applications.
>> + */
>> +
>> +#define WAKE_STR_LEN 128
>> +#define WAKE_BUF_LEN 64
>> +
>> +struct omap_wake {
>> + u32 pending_irqs[INTCPS_NR_MIR_REGS];
>> +
>> + struct omap_wake_platform_data *pdata;
>> + struct pm_wakeup_status pm_wkst;
>> +};
>> +
>> +/* Note: Allowed to use Only in the wakeup_source_show() function */
>> +static struct omap_wake *g_wake;
>> +
>> +static ssize_t wakeup_source_show(struct kobject *kobj,
>> + struct kobj_attribute *attr, char *buf);
>> +
>> +/*
>> + * Get the first pending MPU IRQ number from 'irq_start'.
>> + * If none, return -EINVAL.
>> + */
>> +static int omap3_wake_get_pending_irq(struct omap_wake *wake,
>> + unsigned int irq_start)
>> +{
>> + int i, bits_skip, idx_start;
>> +
>> + if (irq_start >= INTCPS_NR_IRQS)
>> + return -EINVAL;
>> +
>> + bits_skip = irq_start % IRQ_BITS_PER_REG;
>> + idx_start = irq_start / IRQ_BITS_PER_REG;
>> +
>> + for (i = idx_start; i < ARRAY_SIZE(wake->pending_irqs); i++) {
>> + unsigned long val, bit;
>> +
>> + val = wake->pending_irqs[i];
>> + if (!val)
>> + continue;
>> +
>> + if (idx_start == i)
>> + bit = find_next_bit(&val, IRQ_BITS_PER_REG, bits_skip);
>> + else
>> + bit = find_first_bit(&val, IRQ_BITS_PER_REG);
>> +
>> + if (bit < IRQ_BITS_PER_REG)
>> + return i * IRQ_BITS_PER_REG + bit;
>> + }
>> +
>> + return -EINVAL;
>> +}
>> +
>> +static void omap3_wake_strncat(char *dest, char *src, size_t count)
>> +{
>> + int len;
>> +
>> + if (!src[0])
>> + return;
>> +
>> + if (dest[0])
>> + len = strlen(dest) + strlen(src) + 2;
>> + else
>> + len = strlen(dest) + strlen(src);
>> +
>> + if (len > count) {
>> + pr_err("Can't strncat: %s\n", src);
>> + return;
>> + }
>> +
>> + if (dest[0])
>> + strcat(dest, ", ");
>> + strcat(dest, src);
>> +}
>> +
>> +static u32 omap3_wake_get_domain_wkst(struct omap_wake *wake,
>> + struct omapdev *omap3_dev)
>> +{
>> + struct pm_wakeup_status *pm_wkst = &wake->pm_wkst;
>> + const char *pwrdm_name = omap3_dev->pwrdm.name;
>> +
>> + if (!strcmp(pwrdm_name, "wkup_pwrdm")) {
>> + return pm_wkst->wkup;
>> + } else if (!strcmp(pwrdm_name, "per_pwrdm")) {
>> + return pm_wkst->per;
>> + } else if (!strcmp(pwrdm_name, "core_pwrdm")) {
>> + return pm_wkst->core1;
>> + } else if (!strcmp(pwrdm_name, "usbhost_pwrdm")) {
>> + if (!strcmp(omap3_dev->name, "usbtll_omapdev"))
>> + return pm_wkst->core3;
>> + else if (!strcmp(omap3_dev->name, "usbhost_omapdev"))
>> + return pm_wkst->usbhost;
>> + }
>> +
>> + return -EINVAL;
>> +}
>> +
>> +static void omap3_wake_lookup_wkst(struct omap_wake *wake,
>> + char *wake_event, size_t count)
>> +{
>> + struct omapdev **d;
>> +
>> + for (d = omapdevs; *d; d++) {
>> + u32 wkst;
>> +
>> + if (!omap_chip_is((*d)->omap_chip))
>> + continue;
>> +
>> + wkst = omap3_wake_get_domain_wkst(wake, *d);
>> + if (wkst <= 0)
>> + continue;
>> +
>> + if (wkst & (*d)->wkst_mask)
>> + omap3_wake_strncat(wake_event,
>> + (char *)(*d)->name, count);
>> + }
>> +}
>> +
>> +static void omap3_wake_lookup_iopad(struct omap_wake *wake,
>> + char *wake_event, size_t count)
>> +{
>> + struct omap_wake_platform_data *pdata = wake->pdata;
>> + int i;
>> +
>> + for (i = 0; pdata && i < pdata->iopad_wake_num; i++) {
>> + struct iopad_wake *iopad = pdata->iopad_wakes + i;
>> + char *wksrc_iopad;
>> +
>> + if (!iopad->is_wake_source)
>> + continue;
>> +
>> + if (iopad->alias) {
>> + wksrc_iopad = (char *)iopad->alias;
>> + } else {
>> + struct pin_config *cfg = NULL;
>> + int err;
>> +
>> + err = omap_get_pin_config(iopad->mux_index, &cfg);
>> + if (err || !cfg)
>> + continue;
>> +
>> + wksrc_iopad = cfg->name;
>> + }
>> +
>> + omap3_wake_strncat(wake_event, wksrc_iopad, count);
>> + }
>> +}
>> +
>> +static void omap3_wake_dump_wksrc(struct omap_wake *wake,
>> + char *wake_irq, char *wake_event,
>> + size_t irq_size, size_t event_size)
>> +{
>> + int irq, prcm_irq = 0;
>> +
>> + /* IRQ */
>> + irq = omap3_wake_get_pending_irq(wake, 0);
>> + while (irq >= 0) {
>> + char buf[WAKE_BUF_LEN] = {0, };
>> + int len;
>> +
>> + if (irq == INT_34XX_SYS_NIRQ)
>> + omap3_wake_strncat(wake_event, "sys_nirq",
>> + event_size - 1);
>> + else if (irq == INT_34XX_PRCM_MPU_IRQ)
>> + prcm_irq = 1;
>> +
>> + len = strlen(wake_irq) +
>> + snprintf(buf, WAKE_BUF_LEN, "%d", irq);
>> + if (len > irq_size - 1)
>> + break;
>> +
>> + strcat(wake_irq, buf);
>> +
>> + irq = omap3_wake_get_pending_irq(wake, irq + 1);
>> + if (irq >= 0) {
>> + len = strlen(wake_irq) + 2;
>> + if (len > irq_size - 1)
>> + break;
>> +
>> + strcat(wake_irq, ", ");
>> + }
>> + }
>> +
>> + if (prcm_irq) {
>> + omap3_wake_lookup_wkst(wake, wake_event, event_size - 1);
>> + if (strstr(wake_event, io_3xxx_omapdev.name)) {
>> + omap3_wake_lookup_iopad(wake, wake_event,
>> + event_size - 1);
>> + }
>> + }
>> +
>> + if (!wake_irq[0])
>> + strncpy(wake_irq, "Unknown", irq_size - 1);
>> +
>> + if (!wake_event[0])
>> + strncpy(wake_event, "Unknown", event_size - 1);
>> +}
>> +
>> +static struct kobj_attribute wakeup_irq_attr =
>> + __ATTR(omap_resume_irq, 0644, wakeup_source_show, NULL);
>> +
>> +static struct kobj_attribute wakeup_event_attr =
>> + __ATTR(omap_resume_event, 0644, wakeup_source_show, NULL);
>> +
>> +static ssize_t wakeup_source_show(struct kobject *kobj,
>> + struct kobj_attribute *attr, char *buf)
>> +{
>> + char wakeup_irq[WAKE_STR_LEN] = {0, };
>> + char wakeup_event[WAKE_STR_LEN] = {0, };
>> +
>> + if (!g_wake)
>> + return -EINVAL;
>> +
>> + omap3_wake_dump_wksrc(g_wake, wakeup_irq, wakeup_event,
>> + sizeof(wakeup_irq), sizeof(wakeup_event));
>> +
>> + 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 int __devinit omap3_wake_probe(struct platform_device *pdev)
>> +{
>> + struct omap_wake *wake;
>> + int ret;
>> +
>> + wake = kzalloc(sizeof(struct omap_wake), GFP_KERNEL);
>> + if (wake == NULL) {
>> + dev_err(&pdev->dev, "failed to allocate driver data\n");
>> + return -ENOMEM;
>> + }
>> +
>> + wake->pdata = pdev->dev.platform_data;
>> + platform_set_drvdata(pdev, wake);
>> +
>> + /*
>> + * In wakeup_source_show(), we can't access platform_device
>> + * or omap_wake structure without a global variable. so 'g_wake' is
>> + * needed, but please use it carefully.
>> + */
>> + g_wake = wake;
>> +
>> + 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;
>> +}
>> +
>> +static int __devexit omap3_wake_remove(struct platform_device *pdev)
>> +{
>> + struct omap_wake *wake = platform_get_drvdata(pdev);
>> +
>> + kfree(wake);
>> + g_wake = NULL;
>> +
>> + return 0;
>> +}
>> +
>> +static int omap3_wake_suspend(struct platform_device *pdev, pm_message_t state)
>> +{
>> + struct omap_wake_platform_data *pdata = pdev->dev.platform_data;
>> + int i;
>> +
>> + /*
>> + * Whenever the system enters suspend, set WAKEUPENABLE bits again.
>> + * Because the omap_cfg_reg() function could clear WAKEUPENABLE bits
>> + * at runtime.
>> + */
>> + for (i = 0; pdata && i < pdata->iopad_wake_num; i++) {
>> + struct iopad_wake *iopad = pdata->iopad_wakes + i;
>> + struct pin_config *cfg = NULL;
>> + int err;
>> + u16 v;
>> +
>> + err = omap_get_pin_config(iopad->mux_index, &cfg);
>> + if (err || !cfg)
>> + continue;
>> +
>> + v = omap_ctrl_readw(cfg->mux_reg);
>> + v |= OMAP3_PADCONF_WAKEUPENABLE0;
>> + omap_ctrl_writew(v, cfg->mux_reg);
>> +
>> + /* Reset previsous wake-up event information of each pin */
>> + iopad->is_wake_source = false;
>> + }
>> +
>> + return 0;
>> +}
>> +
>> +static int omap3_wake_resume_early(struct platform_device *pdev)
>> +{
>> + struct omap_wake *wake = platform_get_drvdata(pdev);
>> + struct omap_wake_platform_data *pdata = wake->pdata;
>> + int i;
>> +
>> + omap_get_pending_irqs(wake->pending_irqs,
>> + ARRAY_SIZE(wake->pending_irqs));
>> +
>> + for (i = 0; pdata && i < pdata->iopad_wake_num; i++) {
>> + struct iopad_wake *iopad = pdata->iopad_wakes + i;
>> + struct pin_config *cfg = NULL;
>> + int err;
>> + u16 v;
>> +
>> + err = omap_get_pin_config(iopad->mux_index, &cfg);
>> + if (err || !cfg)
>> + continue;
>> +
>> + v = omap_ctrl_readw(cfg->mux_reg);
>> + v &= ~OMAP3_PADCONF_WAKEUPENABLE0;
>> + omap_ctrl_writew(v, cfg->mux_reg);
>> +
>> + if (v & OMAP3_PADCONF_WAKEUPEVENT0)
>> + iopad->is_wake_source = true;
>> + }
>> +
>> + return 0;
>> +}
>> +
>> +static int omap3_wake_resume(struct platform_device *pdev)
>> +{
>> + struct omap_wake *wake = platform_get_drvdata(pdev);
>> +
>> +#ifdef CONFIG_PM_DEBUG
>> + char wakeup_irq[WAKE_STR_LEN] = {0, };
>> + char wakeup_event[WAKE_STR_LEN] = {0, };
>> +
>> + omap3_wake_dump_wksrc(wake, wakeup_irq, wakeup_event,
>> + sizeof(wakeup_irq), sizeof(wakeup_event));
>> +
>> + pr_info("OMAP resume IRQ: %s\n", wakeup_irq);
>> + pr_info("OMAP resume event: %s\n", wakeup_event);
>> +#endif
>> +
>> + omap3_get_last_wakeup_state(&wake->pm_wkst);
>> +
>> + return 0;
>> +}
>> +
>> +static struct platform_driver omap3_wake_driver = {
>> + .probe = omap3_wake_probe,
>> + .remove = __devexit_p(omap3_wake_remove),
>> + .suspend = omap3_wake_suspend,
>> + .resume_early = omap3_wake_resume_early,
>> + .resume = omap3_wake_resume,
>> + .driver = {
>> + .name = "omap-wake",
>> + .owner = THIS_MODULE,
>> + },
>> +};
>> +
>> +static int __init omap3_wake_init(void)
>> +{
>> + return platform_driver_register(&omap3_wake_driver);
>> +}
>> +late_initcall(omap3_wake_init);
>> +
>> +static void __exit omap3_wake_exit(void)
>> +{
>> + platform_driver_unregister(&omap3_wake_driver);
>> +}
>> +module_exit(omap3_wake_exit);
>> +
>> +MODULE_AUTHOR("Kim Kyuwon <q1.kim@samsung.com>");
>> +MODULE_DESCRIPTION("OMAP34xx wakeup source driver");
>> +MODULE_LICENSE("GPL v2");
>> diff --git a/arch/arm/plat-omap/Kconfig b/arch/arm/plat-omap/Kconfig
>> index a2d15a1..24eb6c1 100644
>> --- a/arch/arm/plat-omap/Kconfig
>> +++ b/arch/arm/plat-omap/Kconfig
>> @@ -236,6 +236,15 @@ config OMAP_DM_TIMER
>> help
>> Select this option if you want to use OMAP Dual-Mode timers.
>>
>> +config OMAP3_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 suspend. This driver also privides the
>> + I/O pad wake-up source configuration.
>> +
>> choice
>> prompt "Low-level debug console UART"
>> depends on ARCH_OMAP
>> diff --git a/arch/arm/plat-omap/include/mach/irqs.h b/arch/arm/plat-omap/include/mach/irqs.h
>> index c9a5b19..ee15402 100644
>> --- a/arch/arm/plat-omap/include/mach/irqs.h
>> +++ b/arch/arm/plat-omap/include/mach/irqs.h
>> @@ -385,9 +385,13 @@
>> #define INTCPS_NR_MIR_REGS 3
>> #define INTCPS_NR_IRQS 96
>>
>> +/* Number of IRQ state bits in each MIR register */
>> +#define IRQ_BITS_PER_REG 32
>> +
>> #ifndef __ASSEMBLY__
>> extern void omap_init_irq(void);
>> extern int omap_irq_pending(void);
>> +extern void omap_get_pending_irqs(u32 *pending_irqs, unsigned len);
>> void omap3_intc_save_context(void);
>> void omap3_intc_restore_context(void);
>> #endif
>> diff --git a/arch/arm/plat-omap/include/mach/mux.h b/arch/arm/plat-omap/include/mach/mux.h
>> index f7e298a..f6cb7b1 100644
>> --- a/arch/arm/plat-omap/include/mach/mux.h
>> +++ b/arch/arm/plat-omap/include/mach/mux.h
>> @@ -816,11 +816,14 @@ struct omap_mux_cfg {
>> extern int omap1_mux_init(void);
>> extern int omap2_mux_init(void);
>> extern int omap_mux_register(struct omap_mux_cfg *);
>> +extern int omap_get_pin_config(unsigned long index, struct pin_config **cfg);
>> extern int omap_cfg_reg(unsigned long reg_cfg);
>> #else
>> /* boot loader does it all (no warnings from CONFIG_OMAP_MUX_WARNINGS) */
>> static inline int omap1_mux_init(void) { return 0; }
>> static inline int omap2_mux_init(void) { return 0; }
>> +static inline int omap_get_pin_config(unsigned long index,
>> + struct pin_config **cfg) { return 0; }
>> static inline int omap_cfg_reg(unsigned long reg_cfg) { return 0; }
>> #endif
>>
>> diff --git a/arch/arm/plat-omap/include/mach/omapdev.h b/arch/arm/plat-omap/include/mach/omapdev.h
>> index 4b379bc..2359073 100644
>> --- a/arch/arm/plat-omap/include/mach/omapdev.h
>> +++ b/arch/arm/plat-omap/include/mach/omapdev.h
>> @@ -24,6 +24,7 @@
>> * struct omapdev - OMAP on-chip hardware devices
>> * @name: name of the device - should match TRM
>> * @pwrdm: powerdomain that the device resides in
>> + * @wkst_mask: wake-up state bit in PM_WKST_<domain> associated with pwrdm
>> * @omap_chip: OMAP chips this omapdev is valid for
>> * @pdev_name: platform_device name associated with this omapdev (if any)
>> * @pdev_id: platform_device id associated with this omapdev (if any)
>> @@ -38,6 +39,8 @@ struct omapdev {
>> struct powerdomain *ptr;
>> } pwrdm;
>>
>> + const u32 wkst_mask;
>> +
>> const struct omap_chip_id omap_chip;
>>
>> const char *pdev_name;
>> 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..5b725e3
>> --- /dev/null
>> +++ b/arch/arm/plat-omap/include/mach/wake.h
>> @@ -0,0 +1,52 @@
>> +/*
>> + * 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 iopad_wake - used to enable each I/O pad of the device
>> + * to wake up the system and detect wake-up events of each I/O pad.
>> + *
>> + * The mux layer (mux.c/h files) doesn't have resume hook, so checking
>> + * WAKEUPEVENT in the CONTROL_PADCONF_X register before being cleared by
>> + * PRCM IRQ would be difficult in the mux layer. Thus, this wake source
>> + * driver takes charge of Wake-Up Event Detection Scheme
>> + *
>> + * @mux_index: enumeration index of omapxxxx_index in mux.h
>> + * @alias: descriptive name of each pin (optional)
>> + * @is_wake_source: automatically set by suspend & resume hooks
>> + */
>> +struct iopad_wake {
>> + const u32 mux_index;
>> + const char *alias;
>> + bool is_wake_source;
>> +};
>> +
>> +struct omap_wake_platform_data{
>> + struct iopad_wake *iopad_wakes;
>> + int iopad_wake_num;
>> +};
>> +
>> +struct pm_wakeup_status {
>> + u32 wkup;
>> + u32 per;
>> + u32 core1;
>> + u32 core3;
>> + u32 usbhost;
>> +};
>> +
>> +void omap3_get_last_wakeup_state(struct pm_wakeup_status *pm_wkst);
>> +
>> +#endif /* _WAKE_H_ */
>> +
>> diff --git a/arch/arm/plat-omap/mux.c b/arch/arm/plat-omap/mux.c
>> index 80b040f..6bf321b 100644
>> --- a/arch/arm/plat-omap/mux.c
>> +++ b/arch/arm/plat-omap/mux.c
>> @@ -47,13 +47,8 @@ int __init omap_mux_register(struct omap_mux_cfg *arch_mux_cfg)
>> return 0;
>> }
>>
>> -/*
>> - * Sets the Omap MUX and PULL_DWN registers based on the table
>> - */
>> -int __init_or_module omap_cfg_reg(const unsigned long index)
>> +int omap_get_pin_config(const unsigned long index, struct pin_config **cfg)
>> {
>> - struct pin_config *reg;
>> -
>> if (mux_cfg == NULL) {
>> printk(KERN_ERR "Pin mux table not initialized\n");
>> return -ENODEV;
>> @@ -66,7 +61,23 @@ int __init_or_module omap_cfg_reg(const unsigned long index)
>> return -ENODEV;
>> }
>>
>> - reg = (struct pin_config *)&mux_cfg->pins[index];
>> + *cfg = &mux_cfg->pins[index];
>> +
>> + return 0;
>> +}
>> +EXPORT_SYMBOL(omap_get_pin_config);
>> +
>> +/*
>> + * Sets the Omap MUX and PULL_DWN registers based on the table
>> + */
>> +int __init_or_module omap_cfg_reg(const unsigned long index)
>> +{
>> + struct pin_config *reg = NULL;
>> + int err;
>> +
>> + err = omap_get_pin_config(index, ®);
>> + if (err || !reg)
>> + return err;
>>
>> if (!mux_cfg->cfg_reg)
>> return -ENODEV;
>> --
>> 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
>>
>
>
>
> --
> Kyuwon (규원)
--
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
^ permalink raw reply [flat|nested] 4+ messages in thread
* Re: OMAP3: PM: Add the wakeup source driver, v4
2009-05-14 18:32 ` Kevin Hilman
@ 2009-05-14 23:51 ` Kim Kyuwon
0 siblings, 0 replies; 4+ messages in thread
From: Kim Kyuwon @ 2009-05-14 23:51 UTC (permalink / raw)
To: Kevin Hilman; +Cc: OMAP
Kevin Hilman writes:
> Kim Kyuwon <chammoru@gmail.com> writes:
>
>> Hi Kevin,
>>
>> Could you please review this fourth version of OMAP wakeup source driver?
>>
>
> Yes. I'm working through my backlog of PM branch submissions this
> week.
>
> I've been focusing on getting some of the PM branch reworked and
> rebased so I can start submitting upstream.
>
> I apologize for the delays, but the upstream work is currently higher
> priority than adding large new features to the PM branch.
I agree.
Thank you for your works about OMAP tree and OMAP PM brach!
^ permalink raw reply [flat|nested] 4+ messages in thread
end of thread, other threads:[~2009-05-14 23:51 UTC | newest]
Thread overview: 4+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2009-05-05 9:13 OMAP3: PM: Add the wakeup source driver, v4 Kim Kyuwon
2009-05-14 4:49 ` Kim Kyuwon
2009-05-14 18:32 ` Kevin Hilman
2009-05-14 23:51 ` Kim Kyuwon
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.