diff options
Diffstat (limited to 'drivers/power')
-rw-r--r-- | drivers/power/pda_power.c | 147 |
1 files changed, 92 insertions, 55 deletions
diff --git a/drivers/power/pda_power.c b/drivers/power/pda_power.c index 35dc25973f33..d6c6dbc20e2a 100644 --- a/drivers/power/pda_power.c +++ b/drivers/power/pda_power.c | |||
@@ -33,6 +33,16 @@ static struct resource *ac_irq, *usb_irq; | |||
33 | static struct timer_list charger_timer; | 33 | static struct timer_list charger_timer; |
34 | static struct timer_list supply_timer; | 34 | static struct timer_list supply_timer; |
35 | 35 | ||
36 | enum { | ||
37 | PDA_PSY_OFFLINE = 0, | ||
38 | PDA_PSY_ONLINE = 1, | ||
39 | PDA_PSY_TO_CHANGE, | ||
40 | }; | ||
41 | static int new_ac_status = -1; | ||
42 | static int new_usb_status = -1; | ||
43 | static int ac_status = -1; | ||
44 | static int usb_status = -1; | ||
45 | |||
36 | static int pda_power_get_property(struct power_supply *psy, | 46 | static int pda_power_get_property(struct power_supply *psy, |
37 | enum power_supply_property psp, | 47 | enum power_supply_property psp, |
38 | union power_supply_propval *val) | 48 | union power_supply_propval *val) |
@@ -61,36 +71,44 @@ static char *pda_power_supplied_to[] = { | |||
61 | "backup-battery", | 71 | "backup-battery", |
62 | }; | 72 | }; |
63 | 73 | ||
64 | static struct power_supply pda_power_supplies[] = { | 74 | static struct power_supply pda_psy_ac = { |
65 | { | 75 | .name = "ac", |
66 | .name = "ac", | 76 | .type = POWER_SUPPLY_TYPE_MAINS, |
67 | .type = POWER_SUPPLY_TYPE_MAINS, | 77 | .supplied_to = pda_power_supplied_to, |
68 | .supplied_to = pda_power_supplied_to, | 78 | .num_supplicants = ARRAY_SIZE(pda_power_supplied_to), |
69 | .num_supplicants = ARRAY_SIZE(pda_power_supplied_to), | 79 | .properties = pda_power_props, |
70 | .properties = pda_power_props, | 80 | .num_properties = ARRAY_SIZE(pda_power_props), |
71 | .num_properties = ARRAY_SIZE(pda_power_props), | 81 | .get_property = pda_power_get_property, |
72 | .get_property = pda_power_get_property, | 82 | }; |
73 | }, | 83 | |
74 | { | 84 | static struct power_supply pda_psy_usb = { |
75 | .name = "usb", | 85 | .name = "usb", |
76 | .type = POWER_SUPPLY_TYPE_USB, | 86 | .type = POWER_SUPPLY_TYPE_USB, |
77 | .supplied_to = pda_power_supplied_to, | 87 | .supplied_to = pda_power_supplied_to, |
78 | .num_supplicants = ARRAY_SIZE(pda_power_supplied_to), | 88 | .num_supplicants = ARRAY_SIZE(pda_power_supplied_to), |
79 | .properties = pda_power_props, | 89 | .properties = pda_power_props, |
80 | .num_properties = ARRAY_SIZE(pda_power_props), | 90 | .num_properties = ARRAY_SIZE(pda_power_props), |
81 | .get_property = pda_power_get_property, | 91 | .get_property = pda_power_get_property, |
82 | }, | ||
83 | }; | 92 | }; |
84 | 93 | ||
94 | static void update_status(void) | ||
95 | { | ||
96 | if (pdata->is_ac_online) | ||
97 | new_ac_status = !!pdata->is_ac_online(); | ||
98 | |||
99 | if (pdata->is_usb_online) | ||
100 | new_usb_status = !!pdata->is_usb_online(); | ||
101 | } | ||
102 | |||
85 | static void update_charger(void) | 103 | static void update_charger(void) |
86 | { | 104 | { |
87 | if (!pdata->set_charge) | 105 | if (!pdata->set_charge) |
88 | return; | 106 | return; |
89 | 107 | ||
90 | if (pdata->is_ac_online && pdata->is_ac_online()) { | 108 | if (new_ac_status > 0) { |
91 | dev_dbg(dev, "charger on (AC)\n"); | 109 | dev_dbg(dev, "charger on (AC)\n"); |
92 | pdata->set_charge(PDA_POWER_CHARGE_AC); | 110 | pdata->set_charge(PDA_POWER_CHARGE_AC); |
93 | } else if (pdata->is_usb_online && pdata->is_usb_online()) { | 111 | } else if (new_usb_status > 0) { |
94 | dev_dbg(dev, "charger on (USB)\n"); | 112 | dev_dbg(dev, "charger on (USB)\n"); |
95 | pdata->set_charge(PDA_POWER_CHARGE_USB); | 113 | pdata->set_charge(PDA_POWER_CHARGE_USB); |
96 | } else { | 114 | } else { |
@@ -99,31 +117,53 @@ static void update_charger(void) | |||
99 | } | 117 | } |
100 | } | 118 | } |
101 | 119 | ||
102 | static void supply_timer_func(unsigned long power_supply_ptr) | 120 | static void supply_timer_func(unsigned long unused) |
103 | { | 121 | { |
104 | void *power_supply = (void *)power_supply_ptr; | 122 | if (ac_status == PDA_PSY_TO_CHANGE) { |
123 | ac_status = new_ac_status; | ||
124 | power_supply_changed(&pda_psy_ac); | ||
125 | } | ||
105 | 126 | ||
106 | power_supply_changed(power_supply); | 127 | if (usb_status == PDA_PSY_TO_CHANGE) { |
128 | usb_status = new_usb_status; | ||
129 | power_supply_changed(&pda_psy_usb); | ||
130 | } | ||
107 | } | 131 | } |
108 | 132 | ||
109 | static void charger_timer_func(unsigned long power_supply_ptr) | 133 | static void psy_changed(void) |
110 | { | 134 | { |
111 | update_charger(); | 135 | update_charger(); |
112 | 136 | ||
113 | /* Okay, charger set. Now wait a bit before notifying supplicants, | 137 | /* |
114 | * charge power should stabilize. */ | 138 | * Okay, charger set. Now wait a bit before notifying supplicants, |
115 | supply_timer.data = power_supply_ptr; | 139 | * charge power should stabilize. |
140 | */ | ||
116 | mod_timer(&supply_timer, | 141 | mod_timer(&supply_timer, |
117 | jiffies + msecs_to_jiffies(pdata->wait_for_charger)); | 142 | jiffies + msecs_to_jiffies(pdata->wait_for_charger)); |
118 | } | 143 | } |
119 | 144 | ||
145 | static void charger_timer_func(unsigned long unused) | ||
146 | { | ||
147 | update_status(); | ||
148 | psy_changed(); | ||
149 | } | ||
150 | |||
120 | static irqreturn_t power_changed_isr(int irq, void *power_supply) | 151 | static irqreturn_t power_changed_isr(int irq, void *power_supply) |
121 | { | 152 | { |
122 | /* Wait a bit before reading ac/usb line status and setting charger, | 153 | if (power_supply == &pda_psy_ac) |
123 | * because ac/usb status readings may lag from irq. */ | 154 | ac_status = PDA_PSY_TO_CHANGE; |
124 | charger_timer.data = (unsigned long)power_supply; | 155 | else if (power_supply == &pda_psy_usb) |
156 | usb_status = PDA_PSY_TO_CHANGE; | ||
157 | else | ||
158 | return IRQ_NONE; | ||
159 | |||
160 | /* | ||
161 | * Wait a bit before reading ac/usb line status and setting charger, | ||
162 | * because ac/usb status readings may lag from irq. | ||
163 | */ | ||
125 | mod_timer(&charger_timer, | 164 | mod_timer(&charger_timer, |
126 | jiffies + msecs_to_jiffies(pdata->wait_for_status)); | 165 | jiffies + msecs_to_jiffies(pdata->wait_for_status)); |
166 | |||
127 | return IRQ_HANDLED; | 167 | return IRQ_HANDLED; |
128 | } | 168 | } |
129 | 169 | ||
@@ -142,6 +182,7 @@ static int pda_power_probe(struct platform_device *pdev) | |||
142 | 182 | ||
143 | pdata = pdev->dev.platform_data; | 183 | pdata = pdev->dev.platform_data; |
144 | 184 | ||
185 | update_status(); | ||
145 | update_charger(); | 186 | update_charger(); |
146 | 187 | ||
147 | if (!pdata->wait_for_status) | 188 | if (!pdata->wait_for_status) |
@@ -155,31 +196,26 @@ static int pda_power_probe(struct platform_device *pdev) | |||
155 | 196 | ||
156 | ac_irq = platform_get_resource_byname(pdev, IORESOURCE_IRQ, "ac"); | 197 | ac_irq = platform_get_resource_byname(pdev, IORESOURCE_IRQ, "ac"); |
157 | usb_irq = platform_get_resource_byname(pdev, IORESOURCE_IRQ, "usb"); | 198 | usb_irq = platform_get_resource_byname(pdev, IORESOURCE_IRQ, "usb"); |
158 | if (!ac_irq && !usb_irq) { | ||
159 | dev_err(dev, "no ac/usb irq specified\n"); | ||
160 | ret = -ENODEV; | ||
161 | goto noirqs; | ||
162 | } | ||
163 | 199 | ||
164 | if (pdata->supplied_to) { | 200 | if (pdata->supplied_to) { |
165 | pda_power_supplies[0].supplied_to = pdata->supplied_to; | 201 | pda_psy_ac.supplied_to = pdata->supplied_to; |
166 | pda_power_supplies[1].supplied_to = pdata->supplied_to; | 202 | pda_psy_ac.num_supplicants = pdata->num_supplicants; |
167 | pda_power_supplies[0].num_supplicants = pdata->num_supplicants; | 203 | pda_psy_usb.supplied_to = pdata->supplied_to; |
168 | pda_power_supplies[1].num_supplicants = pdata->num_supplicants; | 204 | pda_psy_usb.num_supplicants = pdata->num_supplicants; |
169 | } | 205 | } |
170 | 206 | ||
171 | if (pdata->is_ac_online) { | 207 | if (pdata->is_ac_online) { |
172 | ret = power_supply_register(&pdev->dev, &pda_power_supplies[0]); | 208 | ret = power_supply_register(&pdev->dev, &pda_psy_ac); |
173 | if (ret) { | 209 | if (ret) { |
174 | dev_err(dev, "failed to register %s power supply\n", | 210 | dev_err(dev, "failed to register %s power supply\n", |
175 | pda_power_supplies[0].name); | 211 | pda_psy_ac.name); |
176 | goto ac_supply_failed; | 212 | goto ac_supply_failed; |
177 | } | 213 | } |
178 | 214 | ||
179 | if (ac_irq) { | 215 | if (ac_irq) { |
180 | ret = request_irq(ac_irq->start, power_changed_isr, | 216 | ret = request_irq(ac_irq->start, power_changed_isr, |
181 | get_irq_flags(ac_irq), ac_irq->name, | 217 | get_irq_flags(ac_irq), ac_irq->name, |
182 | &pda_power_supplies[0]); | 218 | &pda_psy_ac); |
183 | if (ret) { | 219 | if (ret) { |
184 | dev_err(dev, "request ac irq failed\n"); | 220 | dev_err(dev, "request ac irq failed\n"); |
185 | goto ac_irq_failed; | 221 | goto ac_irq_failed; |
@@ -188,18 +224,17 @@ static int pda_power_probe(struct platform_device *pdev) | |||
188 | } | 224 | } |
189 | 225 | ||
190 | if (pdata->is_usb_online) { | 226 | if (pdata->is_usb_online) { |
191 | ret = power_supply_register(&pdev->dev, &pda_power_supplies[1]); | 227 | ret = power_supply_register(&pdev->dev, &pda_psy_usb); |
192 | if (ret) { | 228 | if (ret) { |
193 | dev_err(dev, "failed to register %s power supply\n", | 229 | dev_err(dev, "failed to register %s power supply\n", |
194 | pda_power_supplies[1].name); | 230 | pda_psy_usb.name); |
195 | goto usb_supply_failed; | 231 | goto usb_supply_failed; |
196 | } | 232 | } |
197 | 233 | ||
198 | if (usb_irq) { | 234 | if (usb_irq) { |
199 | ret = request_irq(usb_irq->start, power_changed_isr, | 235 | ret = request_irq(usb_irq->start, power_changed_isr, |
200 | get_irq_flags(usb_irq), | 236 | get_irq_flags(usb_irq), |
201 | usb_irq->name, | 237 | usb_irq->name, &pda_psy_usb); |
202 | &pda_power_supplies[1]); | ||
203 | if (ret) { | 238 | if (ret) { |
204 | dev_err(dev, "request usb irq failed\n"); | 239 | dev_err(dev, "request usb irq failed\n"); |
205 | goto usb_irq_failed; | 240 | goto usb_irq_failed; |
@@ -213,15 +248,14 @@ static int pda_power_probe(struct platform_device *pdev) | |||
213 | 248 | ||
214 | usb_irq_failed: | 249 | usb_irq_failed: |
215 | if (pdata->is_usb_online) | 250 | if (pdata->is_usb_online) |
216 | power_supply_unregister(&pda_power_supplies[1]); | 251 | power_supply_unregister(&pda_psy_usb); |
217 | usb_supply_failed: | 252 | usb_supply_failed: |
218 | if (pdata->is_ac_online && ac_irq) | 253 | if (pdata->is_ac_online && ac_irq) |
219 | free_irq(ac_irq->start, &pda_power_supplies[0]); | 254 | free_irq(ac_irq->start, &pda_psy_ac); |
220 | ac_irq_failed: | 255 | ac_irq_failed: |
221 | if (pdata->is_ac_online) | 256 | if (pdata->is_ac_online) |
222 | power_supply_unregister(&pda_power_supplies[0]); | 257 | power_supply_unregister(&pda_psy_ac); |
223 | ac_supply_failed: | 258 | ac_supply_failed: |
224 | noirqs: | ||
225 | wrongid: | 259 | wrongid: |
226 | return ret; | 260 | return ret; |
227 | } | 261 | } |
@@ -229,15 +263,18 @@ wrongid: | |||
229 | static int pda_power_remove(struct platform_device *pdev) | 263 | static int pda_power_remove(struct platform_device *pdev) |
230 | { | 264 | { |
231 | if (pdata->is_usb_online && usb_irq) | 265 | if (pdata->is_usb_online && usb_irq) |
232 | free_irq(usb_irq->start, &pda_power_supplies[1]); | 266 | free_irq(usb_irq->start, &pda_psy_usb); |
233 | if (pdata->is_ac_online && ac_irq) | 267 | if (pdata->is_ac_online && ac_irq) |
234 | free_irq(ac_irq->start, &pda_power_supplies[0]); | 268 | free_irq(ac_irq->start, &pda_psy_ac); |
269 | |||
235 | del_timer_sync(&charger_timer); | 270 | del_timer_sync(&charger_timer); |
236 | del_timer_sync(&supply_timer); | 271 | del_timer_sync(&supply_timer); |
272 | |||
237 | if (pdata->is_usb_online) | 273 | if (pdata->is_usb_online) |
238 | power_supply_unregister(&pda_power_supplies[1]); | 274 | power_supply_unregister(&pda_psy_usb); |
239 | if (pdata->is_ac_online) | 275 | if (pdata->is_ac_online) |
240 | power_supply_unregister(&pda_power_supplies[0]); | 276 | power_supply_unregister(&pda_psy_ac); |
277 | |||
241 | return 0; | 278 | return 0; |
242 | } | 279 | } |
243 | 280 | ||