[OLPC] Add basic power management handling for CS5536
David Woodhouse
dwmw2 at infradead.unroutableorg
Sun Nov 12 02:15:14 EST 2006
Commit: 9771ebdee3875356d50bbadc0bc8f06cc0dd4e73
Parent: e9c07c37bc2ab224c13c54fa5d78f141ea748ad6
commit 9771ebdee3875356d50bbadc0bc8f06cc0dd4e73
Author: David Woodhouse <dwmw2 at infradead.org>
AuthorDate: Sun Nov 12 15:16:13 2006 +0800
Commit: David Woodhouse <dwmw2 at infradead.org>
CommitDate: Sun Nov 12 15:16:13 2006 +0800
[OLPC] Add basic power management handling for CS5536
Just power button handling for now.
Signed-off-by: David Woodhouse <dwmw2 at infradead.org>
---
arch/i386/Kconfig | 10 +++
arch/i386/kernel/Makefile | 1
arch/i386/kernel/olpc-pm.c | 143 ++++++++++++++++++++++++++++++++++++++++++++
3 files changed, 153 insertions(+), 1 deletions(-)
diff --git a/arch/i386/Kconfig b/arch/i386/Kconfig
index 14f642d..3a2eccf 100644
--- a/arch/i386/Kconfig
+++ b/arch/i386/Kconfig
@@ -1132,7 +1132,15 @@ config OLPC
help
Add support for detecting the unique features of the OLPC
Childrens Machine
-
+
+config OLPC_PM
+ tristate "OLPC power management support"
+ default y
+ depends on OLPC
+ help
+ Add support for the Geode power management facilities on the
+ OLPC Childrens Machine
+
source "drivers/pcmcia/Kconfig"
source "drivers/pci/hotplug/Kconfig"
diff --git a/arch/i386/kernel/Makefile b/arch/i386/kernel/Makefile
index b834d3d..8b365db 100644
--- a/arch/i386/kernel/Makefile
+++ b/arch/i386/kernel/Makefile
@@ -44,6 +44,7 @@ EXTRA_AFLAGS := -traditional
obj-$(CONFIG_SCx200) += scx200.o
obj-$(CONFIG_OLPC) += olpc.o
+obj-$(CONFIG_OLPC_PM) += olpc-pm.o
# vsyscall.o contains the vsyscall DSO images as __initdata.
# We must build both images before we can assemble it.
diff --git a/arch/i386/kernel/olpc-pm.c b/arch/i386/kernel/olpc-pm.c
new file mode 100644
index 0000000..01c8adc
--- /dev/null
+++ b/arch/i386/kernel/olpc-pm.c
@@ -0,0 +1,143 @@
+/* olpc-pm.c
+ * © 2006 Red Hat, Inc.
+ * GPLv2
+ */
+
+#include <linux/kernel.h>
+#include <linux/interrupt.h>
+#include <linux/module.h>
+#include <linux/delay.h>
+#include <linux/input.h>
+#include <asm/io.h>
+
+extern int machine_is_olpc;
+#define PM_IRQ 3
+
+
+#define MSR_LBAR_ACPI 0x5140000E
+#define MSR_LBAR_PMS 0x5140000F
+
+static unsigned long acpi_base;
+static unsigned long pms_base;
+static int sci;
+
+static struct input_dev *pm_inputdev;
+
+static int olpc_pm_interrupt(int irq, void *id)
+{
+ uint16_t sts = inw(acpi_base);
+ outw(sts, acpi_base);
+
+ /* It has to be 0x100 for now because we don't permit anything else */
+ if (sts & 0x100) {
+ input_report_key(pm_inputdev, KEY_POWER, 1);
+ input_sync(pm_inputdev);
+ /* Do we need to delay this (and hence schedule_work)? */
+ input_report_key(pm_inputdev, KEY_POWER, 0);
+ input_sync(pm_inputdev);
+ } else {
+ printk(KERN_WARNING "Strange PM1_STS %x\n", sts);
+ }
+
+ return IRQ_HANDLED;
+}
+
+static int __init olpc_pm_init(void)
+{
+ uint32_t lo, hi;
+ int ret;
+
+ if (!machine_is_olpc)
+ return -ENODEV;
+
+ pm_inputdev = input_allocate_device();
+ if (!pm_inputdev)
+ return -ENOMEM;
+
+ rdmsr(MSR_LBAR_ACPI, lo, hi);
+ /* Check the mask and whether GPIO is enabled (sanity check) */
+ if (hi != 0x0000f001) {
+ printk(KERN_ERR "ACPI registers not enabled -- cannot use OLPC power management\n");
+ return -ENODEV;
+ }
+ acpi_base = lo & 0x0000ffff;
+
+ rdmsr(MSR_LBAR_PMS, lo, hi);
+ /* Check the mask and whether GPIO is enabled (sanity check) */
+ if (hi != 0x0000f001) {
+ printk(KERN_ERR "PM Support not enabled -- cannot use OLPC power management\n");
+ return -ENODEV;
+ }
+ pms_base = lo & 0x0000ffff;
+
+ lo = inl(pms_base + 0x40);
+ printk("PM_FSD was %08x\n", lo);
+ /* Lock, enable failsafe, 4 seconds */
+ outl(0xc001f400, pms_base + 0x40);
+
+ rdmsr(0x51400020, lo, hi);
+ sci = (lo >> 20) & 15;
+ if (sci) {
+ printk(KERN_INFO "SCI is mapped to IRQ %d\n", sci);
+ } else {
+ /* Zero doesn't mean zero -- it means masked */
+ printk(KERN_INFO "SCI unmapped. Mapping to IRQ 3\n");
+ sci = 3;
+ lo |= 0x00300000;
+ wrmsrl(0x51400020, lo);
+ }
+
+ pm_inputdev->name = "Geode PM";
+ pm_inputdev->phys = "geode_pmc/input0";
+
+ pm_inputdev->evbit[0] = BIT(EV_KEY);
+ set_bit(KEY_POWER, pm_inputdev->keybit);
+
+ ret = input_register_device(pm_inputdev);
+ if (ret < 0) {
+ printk(KERN_ERR "Unable to register OLPC PM input device: %d\n",
+ ret);
+ return ret;
+ }
+
+ ret = request_irq(sci, &olpc_pm_interrupt, 0, "SCI", &acpi_base);
+ if (ret) {
+ printk(KERN_ERR "Error registering SCI: %d\n", ret);
+ return ret;
+ }
+
+ /* Set only power button to generate SCI */
+ outw(0x100, acpi_base + 2);
+
+ /* Select level triggered in PIC */
+ if (sci < 8) {
+ lo = inb(0x4d0);
+ lo |= 1 << sci;
+ outb(lo, 0x4d0);
+ } else {
+ lo = inb(0x4d1);
+ lo |= 1 << (sci - 8);
+ outb(lo, 0x4d1);
+ }
+ /* Clear pending interrupt */
+ outw(inw(acpi_base), acpi_base);
+
+ return 0;
+}
+
+
+static void olpc_pm_exit(void)
+{
+ /* Disable all events */
+ outw(0, acpi_base+2);
+
+ free_irq(sci, &acpi_base);
+ input_unregister_device(pm_inputdev);
+}
+
+module_init(olpc_pm_init);
+module_exit(olpc_pm_exit);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("David Woodhouse <dwmw2 at infradead.org>");
+MODULE_DESCRIPTION("AMD Geode power management for OLPC CL1");
More information about the Commits-kernel
mailing list