1/* 2 * intel_mid_battery.c - Intel MID PMIC Battery Driver 3 * 4 * Copyright (C) 2009 Intel Corporation 5 * 6 * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 7 * 8 * This program is free software; you can redistribute it and/or modify 9 * it under the terms of the GNU General Public License as published by 10 * the Free Software Foundation; version 2 of the License. 11 * 12 * This program is distributed in the hope that it will be useful, but 13 * WITHOUT ANY WARRANTY; without even the implied warranty of 14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 15 * General Public License for more details. 16 * 17 * You should have received a copy of the GNU General Public License along 18 * with this program; if not, write to the Free Software Foundation, Inc., 19 * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. 20 * 21 * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 22 * Author: Nithish Mahalingam <nithish.mahalingam@intel.com> 23 */ 24 25#include <linux/module.h> 26#include <linux/init.h> 27#include <linux/err.h> 28#include <linux/interrupt.h> 29#include <linux/workqueue.h> 30#include <linux/jiffies.h> 31#include <linux/param.h> 32#include <linux/device.h> 33#include <linux/spi/spi.h> 34#include <linux/platform_device.h> 35#include <linux/power_supply.h> 36 37#include <asm/intel_scu_ipc.h> 38 39#define DRIVER_NAME "pmic_battery" 40 41/********************************************************************* 42 * Generic defines 43 *********************************************************************/ 44 45static int debug; 46module_param(debug, int, 0444); 47MODULE_PARM_DESC(debug, "Flag to enable PMIC Battery debug messages."); 48 49#define PMIC_BATT_DRV_INFO_UPDATED 1 50#define PMIC_BATT_PRESENT 1 51#define PMIC_BATT_NOT_PRESENT 0 52#define PMIC_USB_PRESENT PMIC_BATT_PRESENT 53#define PMIC_USB_NOT_PRESENT PMIC_BATT_NOT_PRESENT 54 55/* pmic battery register related */ 56#define PMIC_BATT_CHR_SCHRGINT_ADDR 0xD2 57#define PMIC_BATT_CHR_SBATOVP_MASK (1 << 1) 58#define PMIC_BATT_CHR_STEMP_MASK (1 << 2) 59#define PMIC_BATT_CHR_SCOMP_MASK (1 << 3) 60#define PMIC_BATT_CHR_SUSBDET_MASK (1 << 4) 61#define PMIC_BATT_CHR_SBATDET_MASK (1 << 5) 62#define PMIC_BATT_CHR_SDCLMT_MASK (1 << 6) 63#define PMIC_BATT_CHR_SUSBOVP_MASK (1 << 7) 64#define PMIC_BATT_CHR_EXCPT_MASK 0x86 65 66#define PMIC_BATT_ADC_ACCCHRG_MASK (1 << 31) 67#define PMIC_BATT_ADC_ACCCHRGVAL_MASK 0x7FFFFFFF 68 69/* pmic ipc related */ 70#define PMIC_BATT_CHR_IPC_FCHRG_SUBID 0x4 71#define PMIC_BATT_CHR_IPC_TCHRG_SUBID 0x6 72 73/* types of battery charging */ 74enum batt_charge_type { 75 BATT_USBOTG_500MA_CHARGE, 76 BATT_USBOTG_TRICKLE_CHARGE, 77}; 78 79/* valid battery events */ 80enum batt_event { 81 BATT_EVENT_BATOVP_EXCPT, 82 BATT_EVENT_USBOVP_EXCPT, 83 BATT_EVENT_TEMP_EXCPT, 84 BATT_EVENT_DCLMT_EXCPT, 85 BATT_EVENT_EXCPT 86}; 87 88 89/********************************************************************* 90 * Battery properties 91 *********************************************************************/ 92 93/* 94 * pmic battery info 95 */ 96struct pmic_power_module_info { 97 bool is_dev_info_updated; 98 struct device *dev; 99 /* pmic battery data */ 100 unsigned long update_time; /* jiffies when data read */ 101 unsigned int usb_is_present; 102 unsigned int batt_is_present; 103 unsigned int batt_health; 104 unsigned int usb_health; 105 unsigned int batt_status; 106 unsigned int batt_charge_now; /* in mAS */ 107 unsigned int batt_prev_charge_full; /* in mAS */ 108 unsigned int batt_charge_rate; /* in units per second */ 109 110 struct power_supply *usb; 111 struct power_supply *batt; 112 int irq; /* GPE_ID or IRQ# */ 113 struct workqueue_struct *monitor_wqueue; 114 struct delayed_work monitor_battery; 115 struct work_struct handler; 116}; 117 118static unsigned int delay_time = 2000; /* in ms */ 119 120/* 121 * pmic ac properties 122 */ 123static enum power_supply_property pmic_usb_props[] = { 124 POWER_SUPPLY_PROP_PRESENT, 125 POWER_SUPPLY_PROP_HEALTH, 126}; 127 128/* 129 * pmic battery properties 130 */ 131static enum power_supply_property pmic_battery_props[] = { 132 POWER_SUPPLY_PROP_STATUS, 133 POWER_SUPPLY_PROP_HEALTH, 134 POWER_SUPPLY_PROP_PRESENT, 135 POWER_SUPPLY_PROP_CHARGE_NOW, 136 POWER_SUPPLY_PROP_CHARGE_FULL, 137}; 138 139 140/* 141 * Glue functions for talking to the IPC 142 */ 143 144struct battery_property { 145 u32 capacity; /* Charger capacity */ 146 u8 crnt; /* Quick charge current value*/ 147 u8 volt; /* Fine adjustment of constant charge voltage */ 148 u8 prot; /* CHRGPROT register value */ 149 u8 prot2; /* CHRGPROT1 register value */ 150 u8 timer; /* Charging timer */ 151}; 152 153#define IPCMSG_BATTERY 0xEF 154 155/* Battery coulomb counter accumulator commands */ 156#define IPC_CMD_CC_WR 0 /* Update coulomb counter value */ 157#define IPC_CMD_CC_RD 1 /* Read coulomb counter value */ 158#define IPC_CMD_BATTERY_PROPERTY 2 /* Read Battery property */ 159 160/** 161 * pmic_scu_ipc_battery_cc_read - read battery cc 162 * @value: battery coulomb counter read 163 * 164 * Reads the battery couloumb counter value, returns 0 on success, or 165 * an error code 166 * 167 * This function may sleep. Locking for SCU accesses is handled for 168 * the caller. 169 */ 170static int pmic_scu_ipc_battery_cc_read(u32 *value) 171{ 172 return intel_scu_ipc_command(IPCMSG_BATTERY, IPC_CMD_CC_RD, 173 NULL, 0, value, 1); 174} 175 176/** 177 * pmic_scu_ipc_battery_property_get - fetch properties 178 * @prop: battery properties 179 * 180 * Retrieve the battery properties from the power management 181 * 182 * This function may sleep. Locking for SCU accesses is handled for 183 * the caller. 184 */ 185static int pmic_scu_ipc_battery_property_get(struct battery_property *prop) 186{ 187 u32 data[3]; 188 u8 *p = (u8 *)&data[1]; 189 int err = intel_scu_ipc_command(IPCMSG_BATTERY, 190 IPC_CMD_BATTERY_PROPERTY, NULL, 0, data, 3); 191 192 prop->capacity = data[0]; 193 prop->crnt = *p++; 194 prop->volt = *p++; 195 prop->prot = *p++; 196 prop->prot2 = *p++; 197 prop->timer = *p++; 198 199 return err; 200} 201 202/** 203 * pmic_scu_ipc_set_charger - set charger 204 * @charger: charger to select 205 * 206 * Switch the charging mode for the SCU 207 */ 208 209static int pmic_scu_ipc_set_charger(int charger) 210{ 211 return intel_scu_ipc_simple_command(IPCMSG_BATTERY, charger); 212} 213 214/** 215 * pmic_battery_log_event - log battery events 216 * @event: battery event to be logged 217 * Context: can sleep 218 * 219 * There are multiple battery events which may be of interest to users; 220 * this battery function logs the different battery events onto the 221 * kernel log messages. 222 */ 223static void pmic_battery_log_event(enum batt_event event) 224{ 225 printk(KERN_WARNING "pmic-battery: "); 226 switch (event) { 227 case BATT_EVENT_BATOVP_EXCPT: 228 printk(KERN_CONT "battery overvoltage condition\n"); 229 break; 230 case BATT_EVENT_USBOVP_EXCPT: 231 printk(KERN_CONT "usb charger overvoltage condition\n"); 232 break; 233 case BATT_EVENT_TEMP_EXCPT: 234 printk(KERN_CONT "high battery temperature condition\n"); 235 break; 236 case BATT_EVENT_DCLMT_EXCPT: 237 printk(KERN_CONT "over battery charge current condition\n"); 238 break; 239 default: 240 printk(KERN_CONT "charger/battery exception %d\n", event); 241 break; 242 } 243} 244 245/** 246 * pmic_battery_read_status - read battery status information 247 * @pbi: device info structure to update the read information 248 * Context: can sleep 249 * 250 * PMIC power source information need to be updated based on the data read 251 * from the PMIC battery registers. 252 * 253 */ 254static void pmic_battery_read_status(struct pmic_power_module_info *pbi) 255{ 256 unsigned int update_time_intrvl; 257 unsigned int chrg_val; 258 u32 ccval; 259 u8 r8; 260 struct battery_property batt_prop; 261 int batt_present = 0; 262 int usb_present = 0; 263 int batt_exception = 0; 264 265 /* make sure the last batt_status read happened delay_time before */ 266 if (pbi->update_time && time_before(jiffies, pbi->update_time + 267 msecs_to_jiffies(delay_time))) 268 return; 269 270 update_time_intrvl = jiffies_to_msecs(jiffies - pbi->update_time); 271 pbi->update_time = jiffies; 272 273 /* read coulomb counter registers and schrgint register */ 274 if (pmic_scu_ipc_battery_cc_read(&ccval)) { 275 dev_warn(pbi->dev, "%s(): ipc config cmd failed\n", 276 __func__); 277 return; 278 } 279 280 if (intel_scu_ipc_ioread8(PMIC_BATT_CHR_SCHRGINT_ADDR, &r8)) { 281 dev_warn(pbi->dev, "%s(): ipc pmic read failed\n", 282 __func__); 283 return; 284 } 285 286 /* 287 * set pmic_power_module_info members based on pmic register values 288 * read. 289 */ 290 291 /* set batt_is_present */ 292 if (r8 & PMIC_BATT_CHR_SBATDET_MASK) { 293 pbi->batt_is_present = PMIC_BATT_PRESENT; 294 batt_present = 1; 295 } else { 296 pbi->batt_is_present = PMIC_BATT_NOT_PRESENT; 297 pbi->batt_health = POWER_SUPPLY_HEALTH_UNKNOWN; 298 pbi->batt_status = POWER_SUPPLY_STATUS_UNKNOWN; 299 } 300 301 /* set batt_health */ 302 if (batt_present) { 303 if (r8 & PMIC_BATT_CHR_SBATOVP_MASK) { 304 pbi->batt_health = POWER_SUPPLY_HEALTH_OVERVOLTAGE; 305 pbi->batt_status = POWER_SUPPLY_STATUS_NOT_CHARGING; 306 pmic_battery_log_event(BATT_EVENT_BATOVP_EXCPT); 307 batt_exception = 1; 308 } else if (r8 & PMIC_BATT_CHR_STEMP_MASK) { 309 pbi->batt_health = POWER_SUPPLY_HEALTH_OVERHEAT; 310 pbi->batt_status = POWER_SUPPLY_STATUS_NOT_CHARGING; 311 pmic_battery_log_event(BATT_EVENT_TEMP_EXCPT); 312 batt_exception = 1; 313 } else { 314 pbi->batt_health = POWER_SUPPLY_HEALTH_GOOD; 315 if (r8 & PMIC_BATT_CHR_SDCLMT_MASK) { 316 /* PMIC will change charging current automatically */ 317 pmic_battery_log_event(BATT_EVENT_DCLMT_EXCPT); 318 } 319 } 320 } 321 322 /* set usb_is_present */ 323 if (r8 & PMIC_BATT_CHR_SUSBDET_MASK) { 324 pbi->usb_is_present = PMIC_USB_PRESENT; 325 usb_present = 1; 326 } else { 327 pbi->usb_is_present = PMIC_USB_NOT_PRESENT; 328 pbi->usb_health = POWER_SUPPLY_HEALTH_UNKNOWN; 329 } 330 331 if (usb_present) { 332 if (r8 & PMIC_BATT_CHR_SUSBOVP_MASK) { 333 pbi->usb_health = POWER_SUPPLY_HEALTH_OVERVOLTAGE; 334 pmic_battery_log_event(BATT_EVENT_USBOVP_EXCPT); 335 } else { 336 pbi->usb_health = POWER_SUPPLY_HEALTH_GOOD; 337 } 338 } 339 340 chrg_val = ccval & PMIC_BATT_ADC_ACCCHRGVAL_MASK; 341 342 /* set batt_prev_charge_full to battery capacity the first time */ 343 if (!pbi->is_dev_info_updated) { 344 if (pmic_scu_ipc_battery_property_get(&batt_prop)) { 345 dev_warn(pbi->dev, "%s(): ipc config cmd failed\n", 346 __func__); 347 return; 348 } 349 pbi->batt_prev_charge_full = batt_prop.capacity; 350 } 351 352 /* set batt_status */ 353 if (batt_present && !batt_exception) { 354 if (r8 & PMIC_BATT_CHR_SCOMP_MASK) { 355 pbi->batt_status = POWER_SUPPLY_STATUS_FULL; 356 pbi->batt_prev_charge_full = chrg_val; 357 } else if (ccval & PMIC_BATT_ADC_ACCCHRG_MASK) { 358 pbi->batt_status = POWER_SUPPLY_STATUS_DISCHARGING; 359 } else { 360 pbi->batt_status = POWER_SUPPLY_STATUS_CHARGING; 361 } 362 } 363 364 /* set batt_charge_rate */ 365 if (pbi->is_dev_info_updated && batt_present && !batt_exception) { 366 if (pbi->batt_status == POWER_SUPPLY_STATUS_DISCHARGING) { 367 if (pbi->batt_charge_now - chrg_val) { 368 pbi->batt_charge_rate = ((pbi->batt_charge_now - 369 chrg_val) * 1000 * 60) / 370 update_time_intrvl; 371 } 372 } else if (pbi->batt_status == POWER_SUPPLY_STATUS_CHARGING) { 373 if (chrg_val - pbi->batt_charge_now) { 374 pbi->batt_charge_rate = ((chrg_val - 375 pbi->batt_charge_now) * 1000 * 60) / 376 update_time_intrvl; 377 } 378 } else 379 pbi->batt_charge_rate = 0; 380 } else { 381 pbi->batt_charge_rate = -1; 382 } 383 384 /* batt_charge_now */ 385 if (batt_present && !batt_exception) 386 pbi->batt_charge_now = chrg_val; 387 else 388 pbi->batt_charge_now = -1; 389 390 pbi->is_dev_info_updated = PMIC_BATT_DRV_INFO_UPDATED; 391} 392 393/** 394 * pmic_usb_get_property - usb power source get property 395 * @psy: usb power supply context 396 * @psp: usb power source property 397 * @val: usb power source property value 398 * Context: can sleep 399 * 400 * PMIC usb power source property needs to be provided to power_supply 401 * subsytem for it to provide the information to users. 402 */ 403static int pmic_usb_get_property(struct power_supply *psy, 404 enum power_supply_property psp, 405 union power_supply_propval *val) 406{ 407 struct pmic_power_module_info *pbi = power_supply_get_drvdata(psy); 408 409 /* update pmic_power_module_info members */ 410 pmic_battery_read_status(pbi); 411 412 switch (psp) { 413 case POWER_SUPPLY_PROP_PRESENT: 414 val->intval = pbi->usb_is_present; 415 break; 416 case POWER_SUPPLY_PROP_HEALTH: 417 val->intval = pbi->usb_health; 418 break; 419 default: 420 return -EINVAL; 421 } 422 423 return 0; 424} 425 426static inline unsigned long mAStouAh(unsigned long v) 427{ 428 /* seconds to hours, mA to ��A */ 429 return (v * 1000) / 3600; 430} 431 432/** 433 * pmic_battery_get_property - battery power source get property 434 * @psy: battery power supply context 435 * @psp: battery power source property 436 * @val: battery power source property value 437 * Context: can sleep 438 * 439 * PMIC battery power source property needs to be provided to power_supply 440 * subsytem for it to provide the information to users. 441 */ 442static int pmic_battery_get_property(struct power_supply *psy, 443 enum power_supply_property psp, 444 union power_supply_propval *val) 445{ 446 struct pmic_power_module_info *pbi = power_supply_get_drvdata(psy); 447 448 /* update pmic_power_module_info members */ 449 pmic_battery_read_status(pbi); 450 451 switch (psp) { 452 case POWER_SUPPLY_PROP_STATUS: 453 val->intval = pbi->batt_status; 454 break; 455 case POWER_SUPPLY_PROP_HEALTH: 456 val->intval = pbi->batt_health; 457 break; 458 case POWER_SUPPLY_PROP_PRESENT: 459 val->intval = pbi->batt_is_present; 460 break; 461 case POWER_SUPPLY_PROP_CHARGE_NOW: 462 val->intval = mAStouAh(pbi->batt_charge_now); 463 break; 464 case POWER_SUPPLY_PROP_CHARGE_FULL: 465 val->intval = mAStouAh(pbi->batt_prev_charge_full); 466 break; 467 default: 468 return -EINVAL; 469 } 470 471 return 0; 472} 473 474/** 475 * pmic_battery_monitor - monitor battery status 476 * @work: work structure 477 * Context: can sleep 478 * 479 * PMIC battery status needs to be monitored for any change 480 * and information needs to be frequently updated. 481 */ 482static void pmic_battery_monitor(struct work_struct *work) 483{ 484 struct pmic_power_module_info *pbi = container_of(work, 485 struct pmic_power_module_info, monitor_battery.work); 486 487 /* update pmic_power_module_info members */ 488 pmic_battery_read_status(pbi); 489 queue_delayed_work(pbi->monitor_wqueue, &pbi->monitor_battery, HZ * 10); 490} 491 492/** 493 * pmic_battery_set_charger - set battery charger 494 * @pbi: device info structure 495 * @chrg: charge mode to set battery charger in 496 * Context: can sleep 497 * 498 * PMIC battery charger needs to be enabled based on the usb charge 499 * capabilities connected to the platform. 500 */ 501static int pmic_battery_set_charger(struct pmic_power_module_info *pbi, 502 enum batt_charge_type chrg) 503{ 504 int retval; 505 506 /* set usblmt bits and chrgcntl register bits appropriately */ 507 switch (chrg) { 508 case BATT_USBOTG_500MA_CHARGE: 509 retval = pmic_scu_ipc_set_charger(PMIC_BATT_CHR_IPC_FCHRG_SUBID); 510 break; 511 case BATT_USBOTG_TRICKLE_CHARGE: 512 retval = pmic_scu_ipc_set_charger(PMIC_BATT_CHR_IPC_TCHRG_SUBID); 513 break; 514 default: 515 dev_warn(pbi->dev, "%s(): out of range usb charger " 516 "charge detected\n", __func__); 517 return -EINVAL; 518 } 519 520 if (retval) { 521 dev_warn(pbi->dev, "%s(): ipc pmic read failed\n", 522 __func__); 523 return retval; 524 } 525 526 return 0; 527} 528 529/** 530 * pmic_battery_interrupt_handler - pmic battery interrupt handler 531 * Context: interrupt context 532 * 533 * PMIC battery interrupt handler which will be called with either 534 * battery full condition occurs or usb otg & battery connect 535 * condition occurs. 536 */ 537static irqreturn_t pmic_battery_interrupt_handler(int id, void *dev) 538{ 539 struct pmic_power_module_info *pbi = dev; 540 541 schedule_work(&pbi->handler); 542 543 return IRQ_HANDLED; 544} 545 546/** 547 * pmic_battery_handle_intrpt - pmic battery service interrupt 548 * @work: work structure 549 * Context: can sleep 550 * 551 * PMIC battery needs to either update the battery status as full 552 * if it detects battery full condition caused the interrupt or needs 553 * to enable battery charger if it detects usb and battery detect 554 * caused the source of interrupt. 555 */ 556static void pmic_battery_handle_intrpt(struct work_struct *work) 557{ 558 struct pmic_power_module_info *pbi = container_of(work, 559 struct pmic_power_module_info, handler); 560 enum batt_charge_type chrg; 561 u8 r8; 562 563 if (intel_scu_ipc_ioread8(PMIC_BATT_CHR_SCHRGINT_ADDR, &r8)) { 564 dev_warn(pbi->dev, "%s(): ipc pmic read failed\n", 565 __func__); 566 return; 567 } 568 /* find the cause of the interrupt */ 569 if (r8 & PMIC_BATT_CHR_SBATDET_MASK) { 570 pbi->batt_is_present = PMIC_BATT_PRESENT; 571 } else { 572 pbi->batt_is_present = PMIC_BATT_NOT_PRESENT; 573 pbi->batt_health = POWER_SUPPLY_HEALTH_UNKNOWN; 574 pbi->batt_status = POWER_SUPPLY_STATUS_UNKNOWN; 575 return; 576 } 577 578 if (r8 & PMIC_BATT_CHR_EXCPT_MASK) { 579 pbi->batt_health = POWER_SUPPLY_HEALTH_UNKNOWN; 580 pbi->batt_status = POWER_SUPPLY_STATUS_NOT_CHARGING; 581 pbi->usb_health = POWER_SUPPLY_HEALTH_UNKNOWN; 582 pmic_battery_log_event(BATT_EVENT_EXCPT); 583 return; 584 } else { 585 pbi->batt_health = POWER_SUPPLY_HEALTH_GOOD; 586 pbi->usb_health = POWER_SUPPLY_HEALTH_GOOD; 587 } 588 589 if (r8 & PMIC_BATT_CHR_SCOMP_MASK) { 590 u32 ccval; 591 pbi->batt_status = POWER_SUPPLY_STATUS_FULL; 592 593 if (pmic_scu_ipc_battery_cc_read(&ccval)) { 594 dev_warn(pbi->dev, "%s(): ipc config cmd " 595 "failed\n", __func__); 596 return; 597 } 598 pbi->batt_prev_charge_full = ccval & 599 PMIC_BATT_ADC_ACCCHRGVAL_MASK; 600 return; 601 } 602 603 if (r8 & PMIC_BATT_CHR_SUSBDET_MASK) { 604 pbi->usb_is_present = PMIC_USB_PRESENT; 605 } else { 606 pbi->usb_is_present = PMIC_USB_NOT_PRESENT; 607 pbi->usb_health = POWER_SUPPLY_HEALTH_UNKNOWN; 608 return; 609 } 610 611 /* setup battery charging */ 612 613#if 0 614 /* check usb otg power capability and set charger accordingly */ 615 retval = langwell_udc_maxpower(&power); 616 if (retval) { 617 dev_warn(pbi->dev, 618 "%s(): usb otg power query failed with error code %d\n", 619 __func__, retval); 620 return; 621 } 622 623 if (power >= 500) 624 chrg = BATT_USBOTG_500MA_CHARGE; 625 else 626#endif 627 chrg = BATT_USBOTG_TRICKLE_CHARGE; 628 629 /* enable battery charging */ 630 if (pmic_battery_set_charger(pbi, chrg)) { 631 dev_warn(pbi->dev, 632 "%s(): failed to set up battery charging\n", __func__); 633 return; 634 } 635 636 dev_dbg(pbi->dev, 637 "pmic-battery: %s() - setting up battery charger successful\n", 638 __func__); 639} 640 641/* 642 * Description of power supplies 643 */ 644static const struct power_supply_desc pmic_usb_desc = { 645 .name = "pmic-usb", 646 .type = POWER_SUPPLY_TYPE_USB, 647 .properties = pmic_usb_props, 648 .num_properties = ARRAY_SIZE(pmic_usb_props), 649 .get_property = pmic_usb_get_property, 650}; 651 652static const struct power_supply_desc pmic_batt_desc = { 653 .name = "pmic-batt", 654 .type = POWER_SUPPLY_TYPE_BATTERY, 655 .properties = pmic_battery_props, 656 .num_properties = ARRAY_SIZE(pmic_battery_props), 657 .get_property = pmic_battery_get_property, 658}; 659 660/** 661 * pmic_battery_probe - pmic battery initialize 662 * @irq: pmic battery device irq 663 * @dev: pmic battery device structure 664 * Context: can sleep 665 * 666 * PMIC battery initializes its internal data structue and other 667 * infrastructure components for it to work as expected. 668 */ 669static int probe(int irq, struct device *dev) 670{ 671 int retval = 0; 672 struct pmic_power_module_info *pbi; 673 struct power_supply_config psy_cfg = {}; 674 675 dev_dbg(dev, "pmic-battery: found pmic battery device\n"); 676 677 pbi = kzalloc(sizeof(*pbi), GFP_KERNEL); 678 if (!pbi) { 679 dev_err(dev, "%s(): memory allocation failed\n", 680 __func__); 681 return -ENOMEM; 682 } 683 684 pbi->dev = dev; 685 pbi->irq = irq; 686 dev_set_drvdata(dev, pbi); 687 psy_cfg.drv_data = pbi; 688 689 /* initialize all required framework before enabling interrupts */ 690 INIT_WORK(&pbi->handler, pmic_battery_handle_intrpt); 691 INIT_DELAYED_WORK(&pbi->monitor_battery, pmic_battery_monitor); 692 pbi->monitor_wqueue = 693 create_singlethread_workqueue(dev_name(dev)); 694 if (!pbi->monitor_wqueue) { 695 dev_err(dev, "%s(): wqueue init failed\n", __func__); 696 retval = -ESRCH; 697 goto wqueue_failed; 698 } 699 700 /* register interrupt */ 701 retval = request_irq(pbi->irq, pmic_battery_interrupt_handler, 702 0, DRIVER_NAME, pbi); 703 if (retval) { 704 dev_err(dev, "%s(): cannot get IRQ\n", __func__); 705 goto requestirq_failed; 706 } 707 708 /* register pmic-batt with power supply subsystem */ 709 pbi->batt = power_supply_register(dev, &pmic_usb_desc, &psy_cfg); 710 if (IS_ERR(pbi->batt)) { 711 dev_err(dev, 712 "%s(): failed to register pmic battery device with power supply subsystem\n", 713 __func__); 714 retval = PTR_ERR(pbi->batt); 715 goto power_reg_failed; 716 } 717 718 dev_dbg(dev, "pmic-battery: %s() - pmic battery device " 719 "registration with power supply subsystem successful\n", 720 __func__); 721 722 queue_delayed_work(pbi->monitor_wqueue, &pbi->monitor_battery, HZ * 1); 723 724 /* register pmic-usb with power supply subsystem */ 725 pbi->usb = power_supply_register(dev, &pmic_batt_desc, &psy_cfg); 726 if (IS_ERR(pbi->usb)) { 727 dev_err(dev, 728 "%s(): failed to register pmic usb device with power supply subsystem\n", 729 __func__); 730 retval = PTR_ERR(pbi->usb); 731 goto power_reg_failed_1; 732 } 733 734 if (debug) 735 printk(KERN_INFO "pmic-battery: %s() - pmic usb device " 736 "registration with power supply subsystem successful\n", 737 __func__); 738 739 return retval; 740 741power_reg_failed_1: 742 power_supply_unregister(pbi->batt); 743power_reg_failed: 744 cancel_delayed_work_sync(&pbi->monitor_battery); 745requestirq_failed: 746 destroy_workqueue(pbi->monitor_wqueue); 747wqueue_failed: 748 kfree(pbi); 749 750 return retval; 751} 752 753static int platform_pmic_battery_probe(struct platform_device *pdev) 754{ 755 return probe(pdev->id, &pdev->dev); 756} 757 758/** 759 * pmic_battery_remove - pmic battery finalize 760 * @dev: pmic battery device structure 761 * Context: can sleep 762 * 763 * PMIC battery finalizes its internal data structue and other 764 * infrastructure components that it initialized in 765 * pmic_battery_probe. 766 */ 767 768static int platform_pmic_battery_remove(struct platform_device *pdev) 769{ 770 struct pmic_power_module_info *pbi = platform_get_drvdata(pdev); 771 772 free_irq(pbi->irq, pbi); 773 cancel_delayed_work_sync(&pbi->monitor_battery); 774 destroy_workqueue(pbi->monitor_wqueue); 775 776 power_supply_unregister(pbi->usb); 777 power_supply_unregister(pbi->batt); 778 779 cancel_work_sync(&pbi->handler); 780 kfree(pbi); 781 return 0; 782} 783 784static struct platform_driver platform_pmic_battery_driver = { 785 .driver = { 786 .name = DRIVER_NAME, 787 }, 788 .probe = platform_pmic_battery_probe, 789 .remove = platform_pmic_battery_remove, 790}; 791 792module_platform_driver(platform_pmic_battery_driver); 793 794MODULE_AUTHOR("Nithish Mahalingam <nithish.mahalingam@intel.com>"); 795MODULE_DESCRIPTION("Intel Moorestown PMIC Battery Driver"); 796MODULE_LICENSE("GPL"); 797