We have a board with OMAP3530 (based on BeagleBoard C3), but with PWRON
connected. I want to be able to put the board in suspend and shutdown
from sw, and make it wake when it senses PWRON.
Currently I compile my own Angstrom-rootfs with OpenEmbedded, and
therefore run the linux-omap-psp 2.6.32 kernel from
git://arago-project.org/git/projects/linux-omap3.git.
By default the powerbutton worked, but pressing for 8 seconds did
nothing. I pulled in some twl4030_scripts and setup from a TI Android
Kernel with working powermanagement (patch attached), and that got the 8
second reboot working, but I don't know how to get suspend/wake/shutdown
working.
Suspend:
The following was output in my serial console:
root@board1:~# echo mem > /sys/power/state
[ 4042.726776] PM: Syncing filesystems ... done.
Then I pressed Ctrl-C and got some more output:
^C[ 4046.452270] Freezing user space processes ... (elapsed 0.01
seconds) done.
[ 4046.478424] Freezing remaining freezable tasks ... (elapsed 0.01
seconds) done.
[ 4046.501892] Suspending console(s) (use no_console_suspend to debug)
I tried using no_console_suspend, and saw a crash in mmc_suspend_host
(attached).
Shutdown:
The patch gives me "pm_power_off = twl4030_poweroff", but I don't know
how to shutdown my board in a way that would cause this function to be run.
And that's pretty much where I am now. I've collected some pieces of the
puzzle, but I'm not entirely sure it's the right puzzle. Should I be
able to achieve my goals with this kernel? If so, what's missing/wrong?
Regards,
Tasslehoff
>From c8d51a054bc5c6f926846aa8b1e61bc0c705cb83 Mon Sep 17 00:00:00 2001
From: tasslehoff <tasskjapp@xxxxxxxxx>
Date: Tue, 15 Mar 2011 15:33:33 +0100
Subject: [PATCH] Add powerscript and i2c driver for twl4030_poweroff.
---
arch/arm/mach-omap2/board-omap3beagle.c | 109 +++++++++++++++++
drivers/i2c/chips/Makefile | 1 +
drivers/i2c/chips/twl4030-poweroff.c | 200 +++++++++++++++++++++++++++++++
3 files changed, 310 insertions(+), 0 deletions(-)
create mode 100644 drivers/i2c/chips/twl4030-poweroff.c
diff --git a/arch/arm/mach-omap2/board-omap3beagle.c b/arch/arm/mach-omap2/board-omap3beagle.c
index 6dc7b23..fd247d1 100644
--- a/arch/arm/mach-omap2/board-omap3beagle.c
+++ b/arch/arm/mach-omap2/board-omap3beagle.c
@@ -404,6 +404,105 @@ static int beagle_twl_gpio_setup(struct device *dev,
return 0;
}
+
+static struct twl4030_ins __initdata sleep_on_seq[] = {
+ /* Turn OFF VAUX2 */
+ {MSG_SINGULAR(DEV_GRP_P1, RES_VAUX2, RES_STATE_OFF), 2},
+ /* Turn off HFCLKOUT */
+ {MSG_SINGULAR(DEV_GRP_P1, RES_HFCLKOUT, RES_STATE_OFF), 2},
+ /* Turn OFF VDD1 */
+ {MSG_SINGULAR(DEV_GRP_P1, RES_VDD1, RES_STATE_OFF), 2},
+ /* Turn OFF VDD2 */
+ {MSG_SINGULAR(DEV_GRP_P1, RES_VDD2, RES_STATE_OFF), 2},
+ /* Turn OFF VPLL1 */
+ {MSG_SINGULAR(DEV_GRP_P1, RES_VPLL1, RES_STATE_OFF), 2},
+};
+
+static struct twl4030_script sleep_on_script __initdata = {
+ .script = sleep_on_seq,
+ .size = ARRAY_SIZE(sleep_on_seq),
+ .flags = TWL4030_SLEEP_SCRIPT,
+};
+
+static struct twl4030_ins wakeup_p12_seq[] __initdata = {
+ /* Turn on VAUX2 */
+ {MSG_SINGULAR(DEV_GRP_P1, RES_VAUX2, RES_STATE_ACTIVE), 2},
+ /* Turn on HFCLKOUT */
+ {MSG_SINGULAR(DEV_GRP_P1, RES_HFCLKOUT, RES_STATE_ACTIVE), 2},
+ /* Turn ON VDD1 */
+ {MSG_SINGULAR(DEV_GRP_P1, RES_VDD1, RES_STATE_ACTIVE), 2},
+ /* Turn ON VDD2 */
+ {MSG_SINGULAR(DEV_GRP_P1, RES_VDD2, RES_STATE_ACTIVE), 2},
+ /* Turn ON VPLL1 */
+ {MSG_SINGULAR(DEV_GRP_P1, RES_VPLL1, RES_STATE_ACTIVE), 2},
+};
+
+static struct twl4030_script wakeup_p12_script __initdata = {
+ .script = wakeup_p12_seq,
+ .size = ARRAY_SIZE(wakeup_p12_seq),
+ .flags = TWL4030_WAKEUP12_SCRIPT,
+};
+
+static struct twl4030_ins wakeup_p3_seq[] __initdata = {
+ {MSG_SINGULAR(DEV_GRP_P1, 0x19, RES_STATE_ACTIVE), 2},
+};
+
+static struct twl4030_script wakeup_p3_script __initdata = {
+ .script = wakeup_p3_seq,
+ .size = ARRAY_SIZE(wakeup_p3_seq),
+ .flags = TWL4030_WAKEUP3_SCRIPT,
+};
+
+static struct twl4030_ins wrst_seq[] __initdata = {
+/*
+ * Reset twl4030.
+ * Reset VDD1 regulator.
+ * Reset VDD2 regulator.
+ * Reset VPLL1 regulator.
+ * Enable sysclk output.
+ * Reenable twl4030.
+ */
+ {MSG_SINGULAR(DEV_GRP_NULL, RES_RESET, RES_STATE_OFF), 2},
+ {MSG_SINGULAR(DEV_GRP_P1, RES_VDD1, RES_STATE_WRST), 15},
+ {MSG_SINGULAR(DEV_GRP_P1, RES_VDD2, RES_STATE_WRST), 15},
+ {MSG_SINGULAR(DEV_GRP_P1, RES_VPLL1, RES_STATE_WRST), 0x60},
+ {MSG_SINGULAR(DEV_GRP_P1, RES_HFCLKOUT, RES_STATE_ACTIVE), 2},
+ {MSG_SINGULAR(DEV_GRP_P1, RES_VAUX2, RES_STATE_ACTIVE), 2},
+ {MSG_SINGULAR(DEV_GRP_NULL, RES_RESET, RES_STATE_ACTIVE), 2},
+};
+
+static struct twl4030_script wrst_script __initdata = {
+ .script = wrst_seq,
+ .size = ARRAY_SIZE(wrst_seq),
+ .flags = TWL4030_WRST_SCRIPT,
+};
+
+static struct twl4030_script *twl4030_scripts[] __initdata = {
+ &sleep_on_script,
+ &wakeup_p12_script,
+ &wakeup_p3_script,
+ &wrst_script,
+};
+
+static struct twl4030_resconfig twl4030_rconfig[] = {
+ { .resource = RES_HFCLKOUT, .devgroup = DEV_GRP_P3, .type = -1,
+ .type2 = -1 },
+/* XXX removed, breaks booting after power-off
+ { .resource = RES_VDD1, .devgroup = DEV_GRP_P1, .type = -1,
+ .type2 = -1 },
+ { .resource = RES_VDD2, .devgroup = DEV_GRP_P1, .type = -1,
+ .type2 = -1 },
+*/
+ { 0, 0},
+};
+
+static struct twl4030_power_data beagle_power_data __initdata = {
+ .scripts = twl4030_scripts,
+ .num = ARRAY_SIZE(twl4030_scripts),
+ .resource_config = twl4030_rconfig,
+};
+
+
static struct twl4030_gpio_platform_data beagle_gpio_data = {
.gpio_base = OMAP_MAX_GPIO_LINES,
.irq_base = TWL4030_GPIO_IRQ_BASE,
@@ -544,6 +643,7 @@ static struct twl4030_platform_data beagle_twldata = {
/* platform_data for children goes here */
.usb = &beagle_usb_data,
.gpio = &beagle_gpio_data,
+ .power = &beagle_power_data,
.codec = &beagle_codec_data,
.madc = &beagle_madc_data,
.vmmc1 = &beagle_vmmc1,
@@ -799,6 +899,13 @@ static struct ehci_hcd_omap_platform_data ehci_pdata __initdata = {
.reset_gpio_port[2] = -EINVAL
};
+static void enable_board_wakeup_source(void)
+{
+ /* T2 interrupt line (keypad) */
+ omap_mux_init_signal("sys_nirq",
+ OMAP_WAKEUP_EN | OMAP_PIN_INPUT_PULLUP);
+}
+
#ifdef CONFIG_OMAP_MUX
static struct omap_board_mux board_mux[] __initdata = {
/* Camera - Parallel Data */
@@ -925,6 +1032,8 @@ static void __init omap3_beagle_init(void)
usb_musb_init();
usb_ehci_init(&ehci_pdata);
+ enable_board_wakeup_source();
+
omap3beagle_flash_init();
/* Ensure SDRC pins are mux'd for self-refresh */
diff --git a/drivers/i2c/chips/Makefile b/drivers/i2c/chips/Makefile
index fe0af0f..d085c59 100644
--- a/drivers/i2c/chips/Makefile
+++ b/drivers/i2c/chips/Makefile
@@ -11,6 +11,7 @@
#
obj-$(CONFIG_SENSORS_TSL2550) += tsl2550.o
+obj-$(CONFIG_TWL4030_POWER) += twl4030-poweroff.o
ifeq ($(CONFIG_I2C_DEBUG_CHIP),y)
EXTRA_CFLAGS += -DDEBUG
diff --git a/drivers/i2c/chips/twl4030-poweroff.c b/drivers/i2c/chips/twl4030-poweroff.c
new file mode 100644
index 0000000..dbbba72
--- /dev/null
+++ b/drivers/i2c/chips/twl4030-poweroff.c
@@ -0,0 +1,200 @@
+/*
+ * linux/drivers/i2c/chips/twl4030_poweroff.c
+ *
+ * Power off device
+ *
+ * Copyright (C) 2008 Nokia Corporation
+ *
+ * Written by Peter De Schrijver <peter.de-schrijver@xxxxxxxxx>
+ *
+ * This file is subject to the terms and conditions of the GNU General
+ * Public License. See the file "COPYING" in the main directory of this
+ * archive for more details.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include <linux/module.h>
+#include <linux/pm.h>
+#include <linux/i2c/twl.h>
+#ifdef CONFIG_MACH_ARCHOS
+#include <mach/board-archos.h>
+#endif
+
+#define PWR_P1_SW_EVENTS 0x10
+#define PWR_P2_SW_EVENTS 0x11
+#define PWR_P3_SW_EVENTS 0x13
+#define PWR_DEVOFF (1<<0)
+#define PWR_STOPON_POWERON (1<<6)
+#define PWR_LVL_WAKEUP (1<<3)
+
+#define PWR_CFG_P1_TRANSITION 0x00
+#define PWR_CFG_P2_TRANSITION 0x01
+#define PWR_CFG_P3_TRANSITION 0x02
+#define PWR_CFG_P123_TRANSITION 0x03
+
+#define SEQ_OFFSYNC (1<<0)
+#define STARTON_PWRON 0x01
+#define STARTON_VBUS 0x20
+
+#define R_PROTECT_KEY 0x0E
+#define KEY_1 0xFC
+#define KEY_2 0x96
+
+#define R_VDD1_DEV_GRP 0x55
+#define R_VDD2_DEV_GRP 0x63
+
+static void twl_dump_power_regs(void)
+{
+ u8 i;
+
+ for (i = 0; i < 0x25; i++) {
+ u8 regval;
+ twl_i2c_read_u8(TWL4030_MODULE_PM_MASTER, ®val, i);
+ printk("PM_MASTER reg 0x%02x => %02x\n", i, regval);
+ }
+}
+
+static int unprotect_pm_master(void)
+{
+ int err;
+
+ /* unlock registers for writing
+ * FIXME: should this sequence be protected with a spin lock?
+ */
+ err = twl_i2c_write_u8(TWL4030_MODULE_PM_MASTER, KEY_1,
+ R_PROTECT_KEY);
+ err |= twl_i2c_write_u8(TWL4030_MODULE_PM_MASTER, KEY_2,
+ R_PROTECT_KEY);
+ if (err)
+ pr_warning("TWL4030 Unable to unlock registers\n");
+
+ return err;
+}
+
+static int protect_pm_master(void)
+{
+ int err;
+
+ /* lock registers again */
+ if ((err = twl_i2c_write_u8(TWL4030_MODULE_PM_MASTER, 0, R_PROTECT_KEY)) != 0)
+ printk(KERN_ERR
+ "TWL4030 Unable to relock registers\n");
+
+ return err;
+}
+
+static int twl_set_bits(u8 mod_no, u8 val, u8 reg)
+{
+ int err;
+ u8 uninitialized_var(reg_val);
+
+ err = twl_i2c_read_u8(mod_no, ®_val, reg);
+ if (err < 0)
+ return err;
+
+ reg_val |= val;
+ err = twl_i2c_write_u8(mod_no, reg_val, reg);
+
+ return err;
+}
+
+static int twl_clear_bits(u8 mod_no, u8 val, u8 reg)
+{
+ int err;
+ u8 uninitialized_var(reg_val);
+
+ err = twl_i2c_read_u8(mod_no, ®_val, reg);
+ if (err < 0)
+ return err;
+
+ reg_val &= ~val;
+ err = twl_i2c_write_u8(mod_no, reg_val, reg);
+
+ return err;
+}
+
+static void twl4030_poweroff(void)
+{
+ u8 uninitialized_var(val);
+ int err;
+
+ unprotect_pm_master();
+ /* Make sure SEQ_OFFSYNC is set so that all the res goes to wait-on */
+ err = twl_set_bits(TWL4030_MODULE_PM_MASTER, SEQ_OFFSYNC,
+ PWR_CFG_P123_TRANSITION);
+ protect_pm_master();
+
+ if (err < 0) {
+ pr_warning("I2C error %d while setting TWL4030 PM_MASTER CFG_P123_TRANSITION\n", err);
+ return;
+ }
+
+ err = twl_set_bits(TWL4030_MODULE_PM_MASTER,
+ PWR_STOPON_POWERON | PWR_DEVOFF, PWR_P1_SW_EVENTS);
+
+ if (err < 0) {
+ pr_warning("I2C error %d while writing TWL4030 PM_MASTER P1_SW_EVENTS\n", err);
+ }
+
+ return;
+}
+
+static int __init twl4030_poweroff_init(void)
+{
+ int err;
+ u8 starton_flags;
+
+ unprotect_pm_master();
+
+ starton_flags = STARTON_PWRON;
+
+ /*if (!machine_has_usbhost_plug())
+ starton_flags |= STARTON_VBUS; */
+
+ err = twl_i2c_write_u8(TWL4030_MODULE_PM_MASTER, starton_flags,
+ PWR_CFG_P1_TRANSITION);
+ err |= twl_i2c_write_u8(TWL4030_MODULE_PM_MASTER, starton_flags,
+ PWR_CFG_P2_TRANSITION);
+ err |= twl_i2c_write_u8(TWL4030_MODULE_PM_MASTER, starton_flags,
+ PWR_CFG_P3_TRANSITION);
+ if (err)
+ pr_warning("TWL4030 Unable to configure STARTON transition\n");
+
+ protect_pm_master();
+
+ err = twl_set_bits(TWL4030_MODULE_PM_MASTER, PWR_STOPON_POWERON,
+ PWR_P1_SW_EVENTS);
+ err |= twl_set_bits(TWL4030_MODULE_PM_MASTER, PWR_STOPON_POWERON,
+ PWR_P2_SW_EVENTS);
+ err |= twl_set_bits(TWL4030_MODULE_PM_MASTER, PWR_STOPON_POWERON,
+ PWR_P3_SW_EVENTS);
+ if (err) {
+ printk(KERN_WARNING "I2C error %d while writing TWL4030"
+ "PM_MASTER P1_SW_EVENTS\n", err);
+ }
+
+ pm_power_off = twl4030_poweroff;
+ printk(KERN_INFO "TWL4030 POWEROFF INIT");
+ return 0;
+}
+
+static void __exit twl4030_poweroff_exit(void)
+{
+ pm_power_off = NULL;
+}
+
+module_init(twl4030_poweroff_init);
+module_exit(twl4030_poweroff_exit);
+
+MODULE_ALIAS("i2c:twl4030-poweroff");
+MODULE_DESCRIPTION("Triton2 device power off");
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Peter De Schrijver");
--
1.7.1
root@board1:~# echo mem > /sys/power/state
[ 469.046936] PM: Syncing filesystems ... done.
^C[ 478.647308] Freezing user space processes ... (elapsed 0.01 seconds) done.
[ 478.673461] Freezing remaining freezable tasks ... (elapsed 0.01 seconds) done.
[ 478.765441] Unable to handle kernel paging request at virtual address 3d454341
[ 478.772735] pgd = cf0c0000
[ 478.775451] [3d454341] *pgd=00000000
[ 478.779052] Internal error: Oops: 805 [#1] PREEMPT
[ 478.783874] last sysfs file: /sys/devices/platform/ehci-omap.0/usb2/2-2/2-2.4/devnum
[ 478.791656] Modules linked in: sdmak lpm_omap3530 dsplinkk cmemk ipv6 rtc_twl rtc_core
[ 478.799682] CPU: 0 Tainted: G W (2.6.32 #3)
[ 478.804931] PC is at del_timer+0xbc/0x138
[ 478.808959] LR is at lock_timer_base+0x34/0x6c
[ 478.813446] pc : [<c0075dcc>] lr : [<c0075cd8>] psr: 60000093
[ 478.813446] sp : cfb81e78 ip : cfb81e60 fp : cfb81ec8
[ 478.824981] r10: c064f240 r9 : 00000005 r8 : 00000002
[ 478.830230] r7 : 00000000 r6 : 656e0064 r5 : c05c70dd r4 : c05c6f15
[ 478.836791] r3 : 00000000 r2 : 46524554 r1 : 3d454341 r0 : 46524554
[ 478.843383] Flags: nZCv IRQs off FIQs on Mode SVC_32 ISA ARM Segment user
[ 478.850646] Control: 10c5387d Table: 8f0c0019 DAC: 00000015
[ 478.856414] Process sh (pid: 809, stack limit = 0xcfb802f0)
[ 478.861999] Stack: (0xcfb81e78 to 0xcfb82000)
[ 478.866394] 1e60: c0632c08 20000013
[ 478.874633] 1e80: c05c6f15 00000000 cf887808 c03826f8 cfa28240 00000000 cf887808 c038bc24
[ 478.882843] 1ea0: c04a8c58 00000000 cf887860 00000002 cf88783c c02b7d7c cf887808 c02ba8bc
[ 478.891082] 1ec0: cf887808 c02badc4 cf887660 cfbe7658 c056cf42 00000000 00000003 00000003
[ 478.899291] 1ee0: c0485878 cfbe8000 cf21e4d8 00000004 000a3008 c009da34 c05707a0 00000000
[ 478.907531] 1f00: c056cf42 c009dca0 c056cf42 00000003 00000003 c009d324 4001e000 00000004
[ 478.915740] 1f20: cf80eba8 cf21e4c0 cf81ba00 c0649d08 cfb81f80 c0252534 cf80eba8 c013dbd8
[ 478.923980] 1f40: cf11cec0 4001e000 cfb81f80 4001e000 00000004 cfb80000 00000001 c00e89b4
[ 478.932220] 1f60: 00000003 00000007 00000000 00000000 cf11cec0 4001e000 00000004 c00e8b60
[ 478.940429] 1f80: 00000000 00000000 c0039144 00000000 00000004 4001e000 401bc5d0 00000004
[ 478.948669] 1fa0: c0039144 c0038fc0 00000004 4001e000 00000001 4001e000 00000004 00000000
[ 478.956878] 1fc0: 00000004 4001e000 401bc5d0 00000004 00000004 000a33f0 00000001 000a3008
[ 478.965118] 1fe0: 00000000 bed5a5b0 400fa028 4014d32c 60000010 00000001 00000000 00000000
[ 478.973358] [<c0075dcc>] (del_timer+0xbc/0x138) from [<c03826f8>] (mmc_suspend_host+0x44/0x1c4)
[ 478.982116] [<c03826f8>] (mmc_suspend_host+0x44/0x1c4) from [<c038bc24>] (omap_hsmmc_suspend+0x74/0x104)
[ 478.991668] [<c038bc24>] (omap_hsmmc_suspend+0x74/0x104) from [<c02b7d7c>] (platform_pm_suspend+0x4c/0x5c)
[ 479.001403] [<c02b7d7c>] (platform_pm_suspend+0x4c/0x5c) from [<c02ba8bc>] (pm_op+0x30/0x7c)
[ 479.009887] [<c02ba8bc>] (pm_op+0x30/0x7c) from [<c02badc4>] (dpm_suspend_start+0x36c/0x4a0)
[ 479.018402] [<c02badc4>] (dpm_suspend_start+0x36c/0x4a0) from [<c009da34>] (suspend_devices_and_enter+0x40/0x1cc)
[ 479.028717] [<c009da34>] (suspend_devices_and_enter+0x40/0x1cc) from [<c009dca0>] (enter_state+0xe0/0x138)
[ 479.038452] [<c009dca0>] (enter_state+0xe0/0x138) from [<c009d324>] (state_store+0x94/0xc8)
[ 479.046844] [<c009d324>] (state_store+0x94/0xc8) from [<c0252534>] (kobj_attr_store+0x1c/0x24)
[ 479.055511] [<c0252534>] (kobj_attr_store+0x1c/0x24) from [<c013dbd8>] (sysfs_write_file+0x104/0x138)
[ 479.064788] [<c013dbd8>] (sysfs_write_file+0x104/0x138) from [<c00e89b4>] (vfs_write+0xac/0x1a0)
[ 479.073638] [<c00e89b4>] (vfs_write+0xac/0x1a0) from [<c00e8b60>] (sys_write+0x40/0x6c)
[ 479.081695] [<c00e8b60>] (sys_write+0x40/0x6c) from [<c0038fc0>] (ret_fast_syscall+0x0/0x2c)
[ 479.090209] Code: eb102aaa e5952000 e5951004 e3a03000 (e5812000)