pda_power.c (12174B)
1// SPDX-License-Identifier: GPL-2.0-only 2/* 3 * Common power driver for PDAs and phones with one or two external 4 * power supplies (AC/USB) connected to main and backup batteries, 5 * and optional builtin charger. 6 * 7 * Copyright © 2007 Anton Vorontsov <cbou@mail.ru> 8 */ 9 10#include <linux/module.h> 11#include <linux/platform_device.h> 12#include <linux/err.h> 13#include <linux/interrupt.h> 14#include <linux/notifier.h> 15#include <linux/power_supply.h> 16#include <linux/pda_power.h> 17#include <linux/regulator/consumer.h> 18#include <linux/timer.h> 19#include <linux/jiffies.h> 20#include <linux/usb/otg.h> 21 22static inline unsigned int get_irq_flags(struct resource *res) 23{ 24 return IRQF_SHARED | (res->flags & IRQF_TRIGGER_MASK); 25} 26 27static struct device *dev; 28static struct pda_power_pdata *pdata; 29static struct resource *ac_irq, *usb_irq; 30static struct delayed_work charger_work; 31static struct delayed_work polling_work; 32static struct delayed_work supply_work; 33static int polling; 34static struct power_supply *pda_psy_ac, *pda_psy_usb; 35 36#if IS_ENABLED(CONFIG_USB_PHY) 37static struct usb_phy *transceiver; 38static struct notifier_block otg_nb; 39#endif 40 41static struct regulator *ac_draw; 42 43enum { 44 PDA_PSY_OFFLINE = 0, 45 PDA_PSY_ONLINE = 1, 46 PDA_PSY_TO_CHANGE, 47}; 48static int new_ac_status = -1; 49static int new_usb_status = -1; 50static int ac_status = -1; 51static int usb_status = -1; 52 53static int pda_power_get_property(struct power_supply *psy, 54 enum power_supply_property psp, 55 union power_supply_propval *val) 56{ 57 switch (psp) { 58 case POWER_SUPPLY_PROP_ONLINE: 59 if (psy->desc->type == POWER_SUPPLY_TYPE_MAINS) 60 val->intval = pdata->is_ac_online ? 61 pdata->is_ac_online() : 0; 62 else 63 val->intval = pdata->is_usb_online ? 64 pdata->is_usb_online() : 0; 65 break; 66 default: 67 return -EINVAL; 68 } 69 return 0; 70} 71 72static enum power_supply_property pda_power_props[] = { 73 POWER_SUPPLY_PROP_ONLINE, 74}; 75 76static char *pda_power_supplied_to[] = { 77 "main-battery", 78 "backup-battery", 79}; 80 81static const struct power_supply_desc pda_psy_ac_desc = { 82 .name = "ac", 83 .type = POWER_SUPPLY_TYPE_MAINS, 84 .properties = pda_power_props, 85 .num_properties = ARRAY_SIZE(pda_power_props), 86 .get_property = pda_power_get_property, 87}; 88 89static const struct power_supply_desc pda_psy_usb_desc = { 90 .name = "usb", 91 .type = POWER_SUPPLY_TYPE_USB, 92 .properties = pda_power_props, 93 .num_properties = ARRAY_SIZE(pda_power_props), 94 .get_property = pda_power_get_property, 95}; 96 97static void update_status(void) 98{ 99 if (pdata->is_ac_online) 100 new_ac_status = !!pdata->is_ac_online(); 101 102 if (pdata->is_usb_online) 103 new_usb_status = !!pdata->is_usb_online(); 104} 105 106static void update_charger(void) 107{ 108 static int regulator_enabled; 109 int max_uA = pdata->ac_max_uA; 110 111 if (pdata->set_charge) { 112 if (new_ac_status > 0) { 113 dev_dbg(dev, "charger on (AC)\n"); 114 pdata->set_charge(PDA_POWER_CHARGE_AC); 115 } else if (new_usb_status > 0) { 116 dev_dbg(dev, "charger on (USB)\n"); 117 pdata->set_charge(PDA_POWER_CHARGE_USB); 118 } else { 119 dev_dbg(dev, "charger off\n"); 120 pdata->set_charge(0); 121 } 122 } else if (ac_draw) { 123 if (new_ac_status > 0) { 124 regulator_set_current_limit(ac_draw, max_uA, max_uA); 125 if (!regulator_enabled) { 126 dev_dbg(dev, "charger on (AC)\n"); 127 WARN_ON(regulator_enable(ac_draw)); 128 regulator_enabled = 1; 129 } 130 } else { 131 if (regulator_enabled) { 132 dev_dbg(dev, "charger off\n"); 133 WARN_ON(regulator_disable(ac_draw)); 134 regulator_enabled = 0; 135 } 136 } 137 } 138} 139 140static void supply_work_func(struct work_struct *work) 141{ 142 if (ac_status == PDA_PSY_TO_CHANGE) { 143 ac_status = new_ac_status; 144 power_supply_changed(pda_psy_ac); 145 } 146 147 if (usb_status == PDA_PSY_TO_CHANGE) { 148 usb_status = new_usb_status; 149 power_supply_changed(pda_psy_usb); 150 } 151} 152 153static void psy_changed(void) 154{ 155 update_charger(); 156 157 /* 158 * Okay, charger set. Now wait a bit before notifying supplicants, 159 * charge power should stabilize. 160 */ 161 cancel_delayed_work(&supply_work); 162 schedule_delayed_work(&supply_work, 163 msecs_to_jiffies(pdata->wait_for_charger)); 164} 165 166static void charger_work_func(struct work_struct *work) 167{ 168 update_status(); 169 psy_changed(); 170} 171 172static irqreturn_t power_changed_isr(int irq, void *power_supply) 173{ 174 if (power_supply == pda_psy_ac) 175 ac_status = PDA_PSY_TO_CHANGE; 176 else if (power_supply == pda_psy_usb) 177 usb_status = PDA_PSY_TO_CHANGE; 178 else 179 return IRQ_NONE; 180 181 /* 182 * Wait a bit before reading ac/usb line status and setting charger, 183 * because ac/usb status readings may lag from irq. 184 */ 185 cancel_delayed_work(&charger_work); 186 schedule_delayed_work(&charger_work, 187 msecs_to_jiffies(pdata->wait_for_status)); 188 189 return IRQ_HANDLED; 190} 191 192static void polling_work_func(struct work_struct *work) 193{ 194 int changed = 0; 195 196 dev_dbg(dev, "polling...\n"); 197 198 update_status(); 199 200 if (!ac_irq && new_ac_status != ac_status) { 201 ac_status = PDA_PSY_TO_CHANGE; 202 changed = 1; 203 } 204 205 if (!usb_irq && new_usb_status != usb_status) { 206 usb_status = PDA_PSY_TO_CHANGE; 207 changed = 1; 208 } 209 210 if (changed) 211 psy_changed(); 212 213 cancel_delayed_work(&polling_work); 214 schedule_delayed_work(&polling_work, 215 msecs_to_jiffies(pdata->polling_interval)); 216} 217 218#if IS_ENABLED(CONFIG_USB_PHY) 219static int otg_is_usb_online(void) 220{ 221 return (transceiver->last_event == USB_EVENT_VBUS || 222 transceiver->last_event == USB_EVENT_ENUMERATED); 223} 224 225static int otg_is_ac_online(void) 226{ 227 return (transceiver->last_event == USB_EVENT_CHARGER); 228} 229 230static int otg_handle_notification(struct notifier_block *nb, 231 unsigned long event, void *unused) 232{ 233 switch (event) { 234 case USB_EVENT_CHARGER: 235 ac_status = PDA_PSY_TO_CHANGE; 236 break; 237 case USB_EVENT_VBUS: 238 case USB_EVENT_ENUMERATED: 239 usb_status = PDA_PSY_TO_CHANGE; 240 break; 241 case USB_EVENT_NONE: 242 ac_status = PDA_PSY_TO_CHANGE; 243 usb_status = PDA_PSY_TO_CHANGE; 244 break; 245 default: 246 return NOTIFY_OK; 247 } 248 249 /* 250 * Wait a bit before reading ac/usb line status and setting charger, 251 * because ac/usb status readings may lag from irq. 252 */ 253 cancel_delayed_work(&charger_work); 254 schedule_delayed_work(&charger_work, 255 msecs_to_jiffies(pdata->wait_for_status)); 256 257 return NOTIFY_OK; 258} 259#endif 260 261static int pda_power_probe(struct platform_device *pdev) 262{ 263 struct power_supply_config psy_cfg = {}; 264 int ret = 0; 265 266 dev = &pdev->dev; 267 268 if (pdev->id != -1) { 269 dev_err(dev, "it's meaningless to register several " 270 "pda_powers; use id = -1\n"); 271 ret = -EINVAL; 272 goto wrongid; 273 } 274 275 pdata = pdev->dev.platform_data; 276 277 if (pdata->init) { 278 ret = pdata->init(dev); 279 if (ret < 0) 280 goto init_failed; 281 } 282 283 ac_draw = regulator_get(dev, "ac_draw"); 284 if (IS_ERR(ac_draw)) { 285 dev_dbg(dev, "couldn't get ac_draw regulator\n"); 286 ac_draw = NULL; 287 } 288 289 update_status(); 290 update_charger(); 291 292 if (!pdata->wait_for_status) 293 pdata->wait_for_status = 500; 294 295 if (!pdata->wait_for_charger) 296 pdata->wait_for_charger = 500; 297 298 if (!pdata->polling_interval) 299 pdata->polling_interval = 2000; 300 301 if (!pdata->ac_max_uA) 302 pdata->ac_max_uA = 500000; 303 304 INIT_DELAYED_WORK(&charger_work, charger_work_func); 305 INIT_DELAYED_WORK(&supply_work, supply_work_func); 306 307 ac_irq = platform_get_resource_byname(pdev, IORESOURCE_IRQ, "ac"); 308 usb_irq = platform_get_resource_byname(pdev, IORESOURCE_IRQ, "usb"); 309 310 if (pdata->supplied_to) { 311 psy_cfg.supplied_to = pdata->supplied_to; 312 psy_cfg.num_supplicants = pdata->num_supplicants; 313 } else { 314 psy_cfg.supplied_to = pda_power_supplied_to; 315 psy_cfg.num_supplicants = ARRAY_SIZE(pda_power_supplied_to); 316 } 317 318#if IS_ENABLED(CONFIG_USB_PHY) 319 transceiver = usb_get_phy(USB_PHY_TYPE_USB2); 320 if (!IS_ERR_OR_NULL(transceiver)) { 321 if (!pdata->is_usb_online) 322 pdata->is_usb_online = otg_is_usb_online; 323 if (!pdata->is_ac_online) 324 pdata->is_ac_online = otg_is_ac_online; 325 } 326#endif 327 328 if (pdata->is_ac_online) { 329 pda_psy_ac = power_supply_register(&pdev->dev, 330 &pda_psy_ac_desc, &psy_cfg); 331 if (IS_ERR(pda_psy_ac)) { 332 dev_err(dev, "failed to register %s power supply\n", 333 pda_psy_ac_desc.name); 334 ret = PTR_ERR(pda_psy_ac); 335 goto ac_supply_failed; 336 } 337 338 if (ac_irq) { 339 ret = request_irq(ac_irq->start, power_changed_isr, 340 get_irq_flags(ac_irq), ac_irq->name, 341 pda_psy_ac); 342 if (ret) { 343 dev_err(dev, "request ac irq failed\n"); 344 goto ac_irq_failed; 345 } 346 } else { 347 polling = 1; 348 } 349 } 350 351 if (pdata->is_usb_online) { 352 pda_psy_usb = power_supply_register(&pdev->dev, 353 &pda_psy_usb_desc, 354 &psy_cfg); 355 if (IS_ERR(pda_psy_usb)) { 356 dev_err(dev, "failed to register %s power supply\n", 357 pda_psy_usb_desc.name); 358 ret = PTR_ERR(pda_psy_usb); 359 goto usb_supply_failed; 360 } 361 362 if (usb_irq) { 363 ret = request_irq(usb_irq->start, power_changed_isr, 364 get_irq_flags(usb_irq), 365 usb_irq->name, pda_psy_usb); 366 if (ret) { 367 dev_err(dev, "request usb irq failed\n"); 368 goto usb_irq_failed; 369 } 370 } else { 371 polling = 1; 372 } 373 } 374 375#if IS_ENABLED(CONFIG_USB_PHY) 376 if (!IS_ERR_OR_NULL(transceiver) && pdata->use_otg_notifier) { 377 otg_nb.notifier_call = otg_handle_notification; 378 ret = usb_register_notifier(transceiver, &otg_nb); 379 if (ret) { 380 dev_err(dev, "failure to register otg notifier\n"); 381 goto otg_reg_notifier_failed; 382 } 383 polling = 0; 384 } 385#endif 386 387 if (polling) { 388 dev_dbg(dev, "will poll for status\n"); 389 INIT_DELAYED_WORK(&polling_work, polling_work_func); 390 cancel_delayed_work(&polling_work); 391 schedule_delayed_work(&polling_work, 392 msecs_to_jiffies(pdata->polling_interval)); 393 } 394 395 if (ac_irq || usb_irq) 396 device_init_wakeup(&pdev->dev, 1); 397 398 return 0; 399 400#if IS_ENABLED(CONFIG_USB_PHY) 401otg_reg_notifier_failed: 402 if (pdata->is_usb_online && usb_irq) 403 free_irq(usb_irq->start, pda_psy_usb); 404#endif 405usb_irq_failed: 406 if (pdata->is_usb_online) 407 power_supply_unregister(pda_psy_usb); 408usb_supply_failed: 409 if (pdata->is_ac_online && ac_irq) 410 free_irq(ac_irq->start, pda_psy_ac); 411#if IS_ENABLED(CONFIG_USB_PHY) 412 if (!IS_ERR_OR_NULL(transceiver)) 413 usb_put_phy(transceiver); 414#endif 415ac_irq_failed: 416 if (pdata->is_ac_online) 417 power_supply_unregister(pda_psy_ac); 418ac_supply_failed: 419 if (ac_draw) { 420 regulator_put(ac_draw); 421 ac_draw = NULL; 422 } 423 if (pdata->exit) 424 pdata->exit(dev); 425init_failed: 426wrongid: 427 return ret; 428} 429 430static int pda_power_remove(struct platform_device *pdev) 431{ 432#if IS_ENABLED(CONFIG_USB_PHY) 433 if (!IS_ERR_OR_NULL(transceiver) && pdata->use_otg_notifier) 434 usb_unregister_notifier(transceiver, &otg_nb); 435#endif 436 if (pdata->is_usb_online && usb_irq) 437 free_irq(usb_irq->start, pda_psy_usb); 438 if (pdata->is_ac_online && ac_irq) 439 free_irq(ac_irq->start, pda_psy_ac); 440 441 if (polling) 442 cancel_delayed_work_sync(&polling_work); 443 cancel_delayed_work_sync(&charger_work); 444 cancel_delayed_work_sync(&supply_work); 445 446 if (pdata->is_usb_online) 447 power_supply_unregister(pda_psy_usb); 448 if (pdata->is_ac_online) 449 power_supply_unregister(pda_psy_ac); 450#if IS_ENABLED(CONFIG_USB_PHY) 451 if (!IS_ERR_OR_NULL(transceiver)) 452 usb_put_phy(transceiver); 453#endif 454 if (ac_draw) { 455 regulator_put(ac_draw); 456 ac_draw = NULL; 457 } 458 if (pdata->exit) 459 pdata->exit(dev); 460 461 return 0; 462} 463 464#ifdef CONFIG_PM 465static int ac_wakeup_enabled; 466static int usb_wakeup_enabled; 467 468static int pda_power_suspend(struct platform_device *pdev, pm_message_t state) 469{ 470 if (pdata->suspend) { 471 int ret = pdata->suspend(state); 472 473 if (ret) 474 return ret; 475 } 476 477 if (device_may_wakeup(&pdev->dev)) { 478 if (ac_irq) 479 ac_wakeup_enabled = !enable_irq_wake(ac_irq->start); 480 if (usb_irq) 481 usb_wakeup_enabled = !enable_irq_wake(usb_irq->start); 482 } 483 484 return 0; 485} 486 487static int pda_power_resume(struct platform_device *pdev) 488{ 489 if (device_may_wakeup(&pdev->dev)) { 490 if (usb_irq && usb_wakeup_enabled) 491 disable_irq_wake(usb_irq->start); 492 if (ac_irq && ac_wakeup_enabled) 493 disable_irq_wake(ac_irq->start); 494 } 495 496 if (pdata->resume) 497 return pdata->resume(); 498 499 return 0; 500} 501#else 502#define pda_power_suspend NULL 503#define pda_power_resume NULL 504#endif /* CONFIG_PM */ 505 506static struct platform_driver pda_power_pdrv = { 507 .driver = { 508 .name = "pda-power", 509 }, 510 .probe = pda_power_probe, 511 .remove = pda_power_remove, 512 .suspend = pda_power_suspend, 513 .resume = pda_power_resume, 514}; 515 516module_platform_driver(pda_power_pdrv); 517 518MODULE_LICENSE("GPL"); 519MODULE_AUTHOR("Anton Vorontsov <cbou@mail.ru>"); 520MODULE_ALIAS("platform:pda-power");