Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

Merge git://git.infradead.org/battery-2.6

* git://git.infradead.org/battery-2.6:
intel_mid_battery: Fix battery scaling
intel_mid_battery: Fix the argument order to intel_scu_ipc_command
olpc_battery: Fix build failure caused by sysfs changes
Add s3c-adc-battery driver
Intel MID platform battery driver

Fix up trivial conflicts (battery drivers added from different branches)
in drivers/power/{Kconfig,Makefile}

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