hh.org updates
[hh.org.git] / arch / arm / mach-pxa / magician / magician_pm.c
blob6cc0737a47a698e47f791ce9cfe907a8c2fe6d9e
1 /*
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
9 */
11 #include <linux/module.h>
12 #include <linux/version.h>
13 #include <linux/platform_device.h>
14 #include <linux/pm.h>
16 #include <asm/io.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? */
22 static u32 save[4];
23 static u32 save2[13];
25 #ifdef CONFIG_PM
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 */
30 PFER = PWER_GPIO1;
31 PRER = PWER_GPIO0;
33 // PGSR0 = 0x080DC01C;
34 // PGSR1 = 0x34CF0002;
35 // PGSR2 = 0x0123C18C;
36 // PGSR3 = 0x00100202; /* PGSR3 = 0x00104202; */
38 /*see 3.6.2.3 */
39 // PCFR = PCFR_GPROD|PCFR_DC_EN|PCFR_GPR_EN|PCFR_OPDE;
40 /* |PCFR_FP|PCFR_PI2CEN; */
41 /*haret: 00001071 */
42 PCFR = 0x00001071;
44 //hx4700:
45 // PSLR=0xc8000000 /*| (2 << 2)*/ /* SL_PI = 2, PI power domain active, clocks running;*/
46 /* ^---- SYS_DEL =
47 ^--- PWR_DEL */
48 /* haret: cc000000 */
49 PSLR = 0xcc000000;
51 return 0;
54 static int magician_resume(struct platform_device *dev)
56 u32 tmp;
58 printk("resume:\n");
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);
66 return 0;
68 #else
69 #define magician_suspend NULL
70 #define magician_resume NULL
71 #endif
73 static void magician_pxa_ll_pm_suspend(unsigned long resume_addr)
75 int i;
76 u32 csum, tmp, *p;
78 /* Save the 13 words at 0xa0038000. */
79 for (p = phys_to_virt(0xa0038000), i = 0; i < 13; i++)
80 save2[i] = p[i];
82 /* Save the first four words at 0xa0000000. */
83 for (p = phys_to_virt(0xa0000000), i = 0; i < 4; i++)
84 save[i] = p[i];
86 /* Set the first four words at 0xa0000000 to:
87 * resume address; MMU control; TLB base addr; domain id */
88 p[0] = resume_addr;
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++) {
101 tmp = p[i] & 0x1;
102 tmp = tmp << 31;
103 tmp |= tmp >> 1;
104 csum += tmp;
107 PSPR = csum;
110 static void magician_pxa_ll_pm_resume(void)
112 int i;
113 u32 *p;
115 /* Restore the first four words at 0xa0000000. */
116 for (p = phys_to_virt(0xa0000000), i = 0; i < 4; i++)
117 p[i] = save[i];
119 /* Restore the 13 words at 0xa0038000. */
120 for (p = phys_to_virt(0xa0038000), i = 0; i < 13; i++)
121 p[i] = save2[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)
133 u32 *bootldr;
134 int i;
135 u32 tmp;
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);
142 i = 0x0004156c / 4;
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");
149 htc_bootloader = 1;
150 pxa_pm_set_ll_ops(&magician_ll_pm_ops);
153 iounmap(bootldr);
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);
162 return 0;
165 struct platform_driver magician_pm_driver = {
166 .probe = magician_pm_probe,
167 .suspend = magician_suspend,
168 .resume = magician_resume,
169 .driver = {
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");