powerpc/86xx: Add power management support for MPC8610HPCD boards
Anton Vorontsov [Tue, 15 Sep 2009 21:44:00 +0000 (01:44 +0400)]
This patch adds needed nodes and properties to support suspend/resume
on the MPC8610HPCD boards.

There is a dedicated switch (SW9) that is used to wake up the boards.
By default the SW9 button is routed to IRQ8, but could be re-routed
(via PIXIS) to sreset.

With 'no_console_suspend' kernel command line argument specified, the
board is also able to wakeup upon serial port input.

Signed-off-by: Anton Vorontsov <avorontsov@ru.mvista.com>
Acked-by: Scott Wood <scottwood@freescale.com> [dts]
Signed-off-by: Kumar Gala <galak@kernel.crashing.org>

Documentation/powerpc/dts-bindings/fsl/board.txt
arch/powerpc/boot/dts/mpc8610_hpcd.dts
arch/powerpc/platforms/86xx/mpc8610_hpcd.c

index e8b5bc2..39e9415 100644 (file)
@@ -20,12 +20,16 @@ Required properities:
 - compatible : should be "fsl,fpga-pixis".
 - reg : should contain the address and the length of the FPPGA register
   set.
+- interrupt-parent: should specify phandle for the interrupt controller.
+- interrupts : should specify event (wakeup) IRQ.
 
 Example (MPC8610HPCD):
 
        board-control@e8000000 {
                compatible = "fsl,fpga-pixis";
                reg = <0xe8000000 32>;
+               interrupt-parent = <&mpic>;
+               interrupts = <8 8>;
        };
 
 * Freescale BCSR GPIO banks
index f468d21..9535ce6 100644 (file)
@@ -35,6 +35,8 @@
                        i-cache-line-size = <32>;
                        d-cache-size = <32768>;         // L1
                        i-cache-size = <32768>;         // L1
+                       sleep = <&pmc 0x00008000 0      // core
+                                &pmc 0x00004000 0>;    // timebase
                        timebase-frequency = <0>;       // From uboot
                        bus-frequency = <0>;            // From uboot
                        clock-frequency = <0>;          // From uboot
@@ -60,6 +62,7 @@
                          5 0 0xe8480000 0x00008000
                          6 0 0xe84c0000 0x00008000
                          3 0 0xe8000000 0x00000020>;
+               sleep = <&pmc 0x08000000 0>;
 
                flash@0,0 {
                        compatible = "cfi-flash";
                        compatible = "fsl,fpga-pixis";
                        reg = <3 0 0x20>;
                        ranges = <0 3 0 0x20>;
+                       interrupt-parent = <&mpic>;
+                       interrupts = <8 8>;
 
                        sdcsr_pio: gpio-controller@a {
                                #gpio-cells = <2>;
                        reg = <0x3100 0x100>;
                        interrupts = <43 2>;
                        interrupt-parent = <&mpic>;
+                       sleep = <&pmc 0x00000004 0>;
                        dfsrr;
                };
 
                        clock-frequency = <0>;
                        interrupts = <42 2>;
                        interrupt-parent = <&mpic>;
+                       sleep = <&pmc 0x00000002 0>;
                };
 
                serial1: serial@4600 {
                        clock-frequency = <0>;
                        interrupts = <42 2>;
                        interrupt-parent = <&mpic>;
+                       sleep = <&pmc 0x00000008 0>;
                };
 
                spi@7000 {
                        interrupt-parent = <&mpic>;
                        mode = "cpu";
                        gpios = <&sdcsr_pio 7 0>;
+                       sleep = <&pmc 0x00000800 0>;
 
                        mmc-slot@0 {
                                compatible = "fsl,mpc8610hpcd-mmc-slot",
                        reg = <0x2c000 100>;
                        interrupts = <72 2>;
                        interrupt-parent = <&mpic>;
+                       sleep = <&pmc 0x04000000 0>;
                };
 
                mpic: interrupt-controller@40000 {
                };
 
                global-utilities@e0000 {
+                       #address-cells = <1>;
+                       #size-cells = <1>;
                        compatible = "fsl,mpc8610-guts";
                        reg = <0xe0000 0x1000>;
+                       ranges = <0 0xe0000 0x1000>;
                        fsl,has-rstcr;
+
+                       pmc: power@70 {
+                               compatible = "fsl,mpc8610-pmc",
+                                            "fsl,mpc8641d-pmc";
+                               reg = <0x70 0x20>;
+                       };
                };
 
                wdt@e4000 {
                        fsl,playback-dma = <&dma00>;
                        fsl,capture-dma = <&dma01>;
                        fsl,fifo-depth = <8>;
+                       sleep = <&pmc 0 0x08000000>;
                };
 
                ssi@16100 {
                        interrupt-parent = <&mpic>;
                        interrupts = <63 2>;
                        fsl,fifo-depth = <8>;
+                       sleep = <&pmc 0 0x04000000>;
                };
 
                dma@21300 {
                        cell-index = <0>;
                        reg = <0x21300 0x4>; /* DMA general status register */
                        ranges = <0x0 0x21100 0x200>;
+                       sleep = <&pmc 0x00000400 0>;
 
                        dma00: dma-channel@0 {
                                compatible = "fsl,mpc8610-dma-channel",
                        cell-index = <1>;
                        reg = <0xc300 0x4>; /* DMA general status register */
                        ranges = <0x0 0xc100 0x200>;
+                       sleep = <&pmc 0x00000200 0>;
 
                        dma-channel@0 {
                                compatible = "fsl,mpc8610-dma-channel",
                bus-range = <0 0>;
                ranges = <0x02000000 0x0 0x80000000 0x80000000 0x0 0x10000000
                          0x01000000 0x0 0x00000000 0xe1000000 0x0 0x00100000>;
+               sleep = <&pmc 0x80000000 0>;
                clock-frequency = <33333333>;
                interrupt-parent = <&mpic>;
                interrupts = <24 2>;
                bus-range = <1 3>;
                ranges = <0x02000000 0x0 0xa0000000 0xa0000000 0x0 0x10000000
                          0x01000000 0x0 0x00000000 0xe3000000 0x0 0x00100000>;
+               sleep = <&pmc 0x40000000 0>;
                clock-frequency = <33333333>;
                interrupt-parent = <&mpic>;
                interrupts = <26 2>;
                                 0x0000 0 0 4 &mpic 7 1>;
                interrupt-parent = <&mpic>;
                interrupts = <25 2>;
+               sleep = <&pmc 0x20000000 0>;
                clock-frequency = <33333333>;
        };
 };
index 627908a..5abe137 100644 (file)
@@ -19,6 +19,7 @@
 #include <linux/stddef.h>
 #include <linux/kernel.h>
 #include <linux/pci.h>
+#include <linux/interrupt.h>
 #include <linux/kdev_t.h>
 #include <linux/delay.h>
 #include <linux/seq_file.h>
 
 #include "mpc86xx.h"
 
+static struct device_node *pixis_node;
 static unsigned char *pixis_bdcfg0, *pixis_arch;
 
+#ifdef CONFIG_SUSPEND
+static irqreturn_t mpc8610_sw9_irq(int irq, void *data)
+{
+       pr_debug("%s: PIXIS' event (sw9/wakeup) IRQ handled\n", __func__);
+       return IRQ_HANDLED;
+}
+
+static void __init mpc8610_suspend_init(void)
+{
+       int irq;
+       int ret;
+
+       if (!pixis_node)
+               return;
+
+       irq = irq_of_parse_and_map(pixis_node, 0);
+       if (!irq) {
+               pr_err("%s: can't map pixis event IRQ.\n", __func__);
+               return;
+       }
+
+       ret = request_irq(irq, mpc8610_sw9_irq, 0, "sw9/wakeup", NULL);
+       if (ret) {
+               pr_err("%s: can't request pixis event IRQ: %d\n",
+                      __func__, ret);
+               irq_dispose_mapping(irq);
+       }
+
+       enable_irq_wake(irq);
+}
+#else
+static inline void mpc8610_suspend_init(void) { }
+#endif /* CONFIG_SUSPEND */
+
 static struct of_device_id __initdata mpc8610_ids[] = {
        { .compatible = "fsl,mpc8610-immr", },
+       { .compatible = "fsl,mpc8610-guts", },
        { .compatible = "simple-bus", },
        { .compatible = "gianfar", },
        {}
@@ -55,6 +92,9 @@ static int __init mpc8610_declare_of_platform_devices(void)
        /* Firstly, register PIXIS GPIOs. */
        simple_gpiochip_init("fsl,fpga-pixis-gpio-bank");
 
+       /* Enable wakeup on PIXIS' event IRQ. */
+       mpc8610_suspend_init();
+
        /* Without this call, the SSI device driver won't get probed. */
        of_platform_bus_probe(NULL, mpc8610_ids, NULL);
 
@@ -250,10 +290,10 @@ static void __init mpc86xx_hpcd_setup_arch(void)
        diu_ops.set_sysfs_monitor_port  = mpc8610hpcd_set_sysfs_monitor_port;
 #endif
 
-       np = of_find_compatible_node(NULL, NULL, "fsl,fpga-pixis");
-       if (np) {
-               of_address_to_resource(np, 0, &r);
-               of_node_put(np);
+       pixis_node = of_find_compatible_node(NULL, NULL, "fsl,fpga-pixis");
+       if (pixis_node) {
+               of_address_to_resource(pixis_node, 0, &r);
+               of_node_put(pixis_node);
                pixis = ioremap(r.start, 32);
                if (!pixis) {
                        printk(KERN_ERR "Err: can't map FPGA cfg register!\n");