2 * Power management driver for HTC Magician (suspend/resume code)
4 * Copyright (c) 2006 Philipp Zabel
6 * Based on: hx4700_core.c
7 * Copyright (c) 2005 SDG Systems, LLC
11 #include <linux/module.h>
12 #include <linux/version.h>
13 #include <linux/platform_device.h>
17 #include <asm/arch/pxa-regs.h>
18 #include <asm/arch/pxa-pm_ll.h>
19 #include <asm/arch/magician.h>
21 static int htc_bootloader
= 0; /* Is the stock HTC bootloader installed? */
26 static int magician_suspend(struct platform_device
*dev
, pm_message_t state
)
28 // PWER = PWER_RTC | PWER_GPIO0 | PWER_GPIO1 /* | PWER_WEP1 */;
29 PWER
= PWER_GPIO0
| PWER_GPIO1
; /* PWER, PFER, PRER = 3 in haret */
33 // PGSR0 = 0x080DC01C;
34 // PGSR1 = 0x34CF0002;
35 // PGSR2 = 0x0123C18C;
36 // PGSR3 = 0x00100202; /* PGSR3 = 0x00104202; */
39 // PCFR = PCFR_GPROD|PCFR_DC_EN|PCFR_GPR_EN|PCFR_OPDE;
40 /* |PCFR_FP|PCFR_PI2CEN; */
45 // PSLR=0xc8000000 /*| (2 << 2)*/ /* SL_PI = 2, PI power domain active, clocks running;*/
54 static int magician_resume(struct platform_device
*dev
)
59 printk("CCCR = %08x\n", CCCR
);
60 asm("mrc\tp14, 0, %0, c6, c0, 0":"=r"(tmp
));
61 printk("CLKCFG = %08x\n", tmp
);
62 printk("MSC0 = %08x\n", MSC0
);
63 printk("MSC1 = %08x\n", MSC1
);
64 printk("MSC2 = %08x\n", MSC2
);
69 #define magician_suspend NULL
70 #define magician_resume NULL
73 static void magician_pxa_ll_pm_suspend(unsigned long resume_addr
)
78 /* Save the 13 words at 0xa0038000. */
79 for (p
= phys_to_virt(0xa0038000), i
= 0; i
< 13; i
++)
82 /* Save the first four words at 0xa0000000. */
83 for (p
= phys_to_virt(0xa0000000), i
= 0; i
< 4; i
++)
86 /* Set the first four words at 0xa0000000 to:
87 * resume address; MMU control; TLB base addr; domain id */
90 asm("mrc\tp15, 0, %0, c1, c0, 0":"=r"(tmp
));
91 p
[1] = tmp
& ~(0x3987); /* mmu off */
93 asm("mrc\tp15, 0, %0, c2, c0, 0":"=r"(tmp
));
94 p
[2] = tmp
; /* Shouldn't matter, since MMU will be off. */
96 asm("mrc\tp15, 0, %0, c3, c0, 0":"=r"(tmp
));
97 p
[3] = tmp
; /* Shouldn't matter, since MMU will be off. */
99 /* Set PSPR to the checksum the HTC bootloader wants to see. */
100 for (csum
= 0, i
= 0; i
< 52; i
++) {
110 static void magician_pxa_ll_pm_resume(void)
115 /* Restore the first four words at 0xa0000000. */
116 for (p
= phys_to_virt(0xa0000000), i
= 0; i
< 4; i
++)
119 /* Restore the 13 words at 0xa0038000. */
120 for (p
= phys_to_virt(0xa0038000), i
= 0; i
< 13; i
++)
123 /* XXX Do we need to flush the cache? */
126 struct pxa_ll_pm_ops magician_ll_pm_ops
= {
127 .suspend
= magician_pxa_ll_pm_suspend
,
128 .resume
= magician_pxa_ll_pm_resume
,
131 static int magician_pm_probe(struct platform_device
*dev
)
137 printk(KERN_NOTICE
"HTC Magician power management driver\n");
139 /* Is the stock HTC bootloader installed? */
141 bootldr
= (u32
*) ioremap(PXA_CS0_PHYS
, 1024 * 1024);
144 if (bootldr
[i
] == 0xe59f1534 && /* ldr r1, [pc, #1332] ; power base */
145 bootldr
[i
+ 1] == 0xe5914008 && /* ldr r4, [r1, #8] ; PSPR */
146 bootldr
[i
+ 2] == 0xe1320004) { /* teq r2, r4 */
148 printk("Stock HTC bootloader detected\n");
150 pxa_pm_set_ll_ops(&magician_ll_pm_ops
);
155 printk("CCCR = %08x\n", CCCR
);
156 asm("mrc\tp14, 0, %0, c6, c0, 0":"=r"(tmp
));
157 printk("CLKCFG = %08x\n", tmp
);
158 printk("MSC0 = %08x\n", MSC0
);
159 printk("MSC1 = %08x\n", MSC1
);
160 printk("MSC2 = %08x\n", MSC2
);
165 struct platform_driver magician_pm_driver
= {
166 .probe
= magician_pm_probe
,
167 .suspend
= magician_suspend
,
168 .resume
= magician_resume
,
170 .name
= "magician-pm",
174 static int __init
magician_pm_init(void)
176 return platform_driver_register(&magician_pm_driver
);
179 static void __exit
magician_pm_exit(void)
181 platform_driver_unregister(&magician_pm_driver
);
184 module_init(magician_pm_init
);
185 module_exit(magician_pm_exit
);
187 MODULE_AUTHOR("Philipp Zabel");
188 MODULE_DESCRIPTION("HTC Magician power management driver");
189 MODULE_LICENSE("GPL");