Pull release into acpica branch
[pandora-kernel.git] / arch / arm / mach-pxa / corgi_pm.c
1 /*
2  * Battery and Power Management code for the Sharp SL-C7xx
3  *
4  * Copyright (c) 2005 Richard Purdie
5  *
6  * This program is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License version 2 as
8  * published by the Free Software Foundation.
9  *
10  */
11
12 #include <linux/module.h>
13 #include <linux/stat.h>
14 #include <linux/init.h>
15 #include <linux/kernel.h>
16 #include <linux/delay.h>
17 #include <linux/interrupt.h>
18 #include <linux/platform_device.h>
19 #include <asm/apm.h>
20 #include <asm/irq.h>
21 #include <asm/mach-types.h>
22 #include <asm/hardware.h>
23 #include <asm/hardware/scoop.h>
24
25 #include <asm/arch/sharpsl.h>
26 #include <asm/arch/corgi.h>
27 #include <asm/arch/pxa-regs.h>
28 #include "sharpsl.h"
29
30 static void corgi_charger_init(void)
31 {
32         pxa_gpio_mode(CORGI_GPIO_ADC_TEMP_ON | GPIO_OUT);
33         pxa_gpio_mode(CORGI_GPIO_CHRG_ON | GPIO_OUT);
34         pxa_gpio_mode(CORGI_GPIO_CHRG_UKN | GPIO_OUT);
35         pxa_gpio_mode(CORGI_GPIO_KEY_INT | GPIO_IN);
36 }
37
38 static void corgi_charge_led(int val)
39 {
40         if (val == SHARPSL_LED_ERROR) {
41                 dev_dbg(sharpsl_pm.dev, "Charge LED Error\n");
42         } else if (val == SHARPSL_LED_ON) {
43                 dev_dbg(sharpsl_pm.dev, "Charge LED On\n");
44                 GPSR0 = GPIO_bit(CORGI_GPIO_LED_ORANGE);
45         } else {
46                 dev_dbg(sharpsl_pm.dev, "Charge LED Off\n");
47                 GPCR0 = GPIO_bit(CORGI_GPIO_LED_ORANGE);
48         }
49 }
50
51 static void corgi_measure_temp(int on)
52 {
53         if (on)
54                 GPSR(CORGI_GPIO_ADC_TEMP_ON) = GPIO_bit(CORGI_GPIO_ADC_TEMP_ON);
55         else
56                 GPCR(CORGI_GPIO_ADC_TEMP_ON) = GPIO_bit(CORGI_GPIO_ADC_TEMP_ON);
57 }
58
59 static void corgi_charge(int on)
60 {
61         if (on) {
62                 if (machine_is_corgi() && (sharpsl_pm.flags & SHARPSL_SUSPENDED)) {
63                         GPCR(CORGI_GPIO_CHRG_ON) = GPIO_bit(CORGI_GPIO_CHRG_ON);
64                         GPSR(CORGI_GPIO_CHRG_UKN) = GPIO_bit(CORGI_GPIO_CHRG_UKN);
65                 } else {
66                         GPSR(CORGI_GPIO_CHRG_ON) = GPIO_bit(CORGI_GPIO_CHRG_ON);
67                         GPCR(CORGI_GPIO_CHRG_UKN) = GPIO_bit(CORGI_GPIO_CHRG_UKN);
68                 }
69         } else {
70                 GPCR(CORGI_GPIO_CHRG_ON) = GPIO_bit(CORGI_GPIO_CHRG_ON);
71                 GPCR(CORGI_GPIO_CHRG_UKN) = GPIO_bit(CORGI_GPIO_CHRG_UKN);
72         }
73 }
74
75 static void corgi_discharge(int on)
76 {
77         if (on)
78                 GPSR(CORGI_GPIO_DISCHARGE_ON) = GPIO_bit(CORGI_GPIO_DISCHARGE_ON);
79         else
80                 GPCR(CORGI_GPIO_DISCHARGE_ON) = GPIO_bit(CORGI_GPIO_DISCHARGE_ON);
81 }
82
83 static void corgi_presuspend(void)
84 {
85         int i;
86         unsigned long wakeup_mask;
87
88         /* charging , so CHARGE_ON bit is HIGH during OFF. */
89         if (READ_GPIO_BIT(CORGI_GPIO_CHRG_ON))
90                 PGSR1 |= GPIO_bit(CORGI_GPIO_CHRG_ON);
91         else
92                 PGSR1 &= ~GPIO_bit(CORGI_GPIO_CHRG_ON);
93
94         if (READ_GPIO_BIT(CORGI_GPIO_LED_ORANGE))
95                 PGSR0 |= GPIO_bit(CORGI_GPIO_LED_ORANGE);
96         else
97                 PGSR0 &= ~GPIO_bit(CORGI_GPIO_LED_ORANGE);
98
99         if (READ_GPIO_BIT(CORGI_GPIO_CHRG_UKN))
100                 PGSR1 |= GPIO_bit(CORGI_GPIO_CHRG_UKN);
101         else
102                 PGSR1 &= ~GPIO_bit(CORGI_GPIO_CHRG_UKN);
103
104         /* Resume on keyboard power key */
105         PGSR2 = (PGSR2 & ~CORGI_GPIO_ALL_STROBE_BIT) | CORGI_GPIO_STROBE_BIT(0);
106
107         wakeup_mask = GPIO_bit(CORGI_GPIO_KEY_INT) | GPIO_bit(CORGI_GPIO_WAKEUP) | GPIO_bit(CORGI_GPIO_AC_IN) | GPIO_bit(CORGI_GPIO_CHRG_FULL);
108
109         if (!machine_is_corgi())
110                 wakeup_mask |= GPIO_bit(CORGI_GPIO_MAIN_BAT_LOW);
111
112         PWER = wakeup_mask | PWER_RTC;
113         PRER = wakeup_mask;
114         PFER = wakeup_mask;
115
116         for (i = 0; i <=15; i++) {
117                 if (PRER & PFER & GPIO_bit(i)) {
118                         if (GPLR0 & GPIO_bit(i) )
119                                 PRER &= ~GPIO_bit(i);
120                         else
121                                 PFER &= ~GPIO_bit(i);
122                 }
123         }
124 }
125
126 static void corgi_postsuspend(void)
127 {
128 }
129
130 /*
131  * Check what brought us out of the suspend.
132  * Return: 0 to sleep, otherwise wake
133  */
134 static int corgi_should_wakeup(unsigned int resume_on_alarm)
135 {
136         int is_resume = 0;
137
138         dev_dbg(sharpsl_pm.dev, "GPLR0 = %x,%x\n", GPLR0, PEDR);
139
140         if ((PEDR & GPIO_bit(CORGI_GPIO_AC_IN))) {
141                 if (STATUS_AC_IN()) {
142                         /* charge on */
143                         dev_dbg(sharpsl_pm.dev, "ac insert\n");
144                         sharpsl_pm.flags |= SHARPSL_DO_OFFLINE_CHRG;
145                 } else {
146                         /* charge off */
147                         dev_dbg(sharpsl_pm.dev, "ac remove\n");
148                         CHARGE_LED_OFF();
149                         CHARGE_OFF();
150                         sharpsl_pm.charge_mode = CHRG_OFF;
151                 }
152         }
153
154         if ((PEDR & GPIO_bit(CORGI_GPIO_CHRG_FULL)))
155                 dev_dbg(sharpsl_pm.dev, "Charge full interrupt\n");
156
157         if (PEDR & GPIO_bit(CORGI_GPIO_KEY_INT))
158                 is_resume |= GPIO_bit(CORGI_GPIO_KEY_INT);
159
160         if (PEDR & GPIO_bit(CORGI_GPIO_WAKEUP))
161                 is_resume |= GPIO_bit(CORGI_GPIO_WAKEUP);
162
163         if (resume_on_alarm && (PEDR & PWER_RTC))
164                 is_resume |= PWER_RTC;
165
166         dev_dbg(sharpsl_pm.dev, "is_resume: %x\n",is_resume);
167         return is_resume;
168 }
169
170 static unsigned long corgi_charger_wakeup(void)
171 {
172         return ~GPLR0 & ( GPIO_bit(CORGI_GPIO_AC_IN) | GPIO_bit(CORGI_GPIO_KEY_INT) | GPIO_bit(CORGI_GPIO_WAKEUP) );
173 }
174
175 static int corgi_acin_status(void)
176 {
177         return ((GPLR(CORGI_GPIO_AC_IN) & GPIO_bit(CORGI_GPIO_AC_IN)) != 0);
178 }
179
180 static struct sharpsl_charger_machinfo corgi_pm_machinfo = {
181         .init            = corgi_charger_init,
182         .gpio_batlock    = CORGI_GPIO_BAT_COVER,
183         .gpio_acin       = CORGI_GPIO_AC_IN,
184         .gpio_batfull    = CORGI_GPIO_CHRG_FULL,
185         .status_acin     = corgi_acin_status,
186         .discharge       = corgi_discharge,
187         .charge          = corgi_charge,
188         .chargeled       = corgi_charge_led,
189         .measure_temp    = corgi_measure_temp,
190         .presuspend      = corgi_presuspend,
191         .postsuspend     = corgi_postsuspend,
192         .charger_wakeup  = corgi_charger_wakeup,
193         .should_wakeup   = corgi_should_wakeup,
194         .bat_levels      = 40,
195         .bat_levels_noac = spitz_battery_levels_noac,
196         .bat_levels_acin = spitz_battery_levels_acin,
197         .status_high_acin = 188,
198         .status_low_acin  = 178,
199         .status_high_noac = 185,
200         .status_low_noac  = 175,
201 };
202
203 static struct platform_device *corgipm_device;
204
205 static int __devinit corgipm_init(void)
206 {
207         int ret;
208
209         corgipm_device = platform_device_alloc("sharpsl-pm", -1);
210         if (!corgipm_device)
211                 return -ENOMEM;
212
213         corgipm_device->dev.platform_data = &corgi_pm_machinfo;
214         ret = platform_device_add(corgipm_device);
215
216         if (ret)
217                 platform_device_put(corgipm_device);
218
219         return ret;
220 }
221
222 static void corgipm_exit(void)
223 {
224         platform_device_unregister(corgipm_device);
225 }
226
227 module_init(corgipm_init);
228 module_exit(corgipm_exit);