diff options
| -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 | ||
