1/* 2 * Battery driver for Maxim MAX8925 3 * 4 * Copyright (c) 2009-2010 Marvell International Ltd. 5 * Haojian Zhuang <haojian.zhuang@marvell.com> 6 * 7 * This program is free software; you can redistribute it and/or modify 8 * it under the terms of the GNU General Public License version 2 as 9 * published by the Free Software Foundation. 10 */ 11 12#include <linux/module.h> 13#include <linux/err.h> 14#include <linux/slab.h> 15#include <linux/i2c.h> 16#include <linux/interrupt.h> 17#include <linux/platform_device.h> 18#include <linux/power_supply.h> 19#include <linux/mfd/max8925.h> 20 21/* registers in GPM */ 22#define MAX8925_OUT5VEN 0x54 23#define MAX8925_OUT3VEN 0x58 24#define MAX8925_CHG_CNTL1 0x7c 25 26/* bits definition */ 27#define MAX8925_CHG_STAT_VSYSLOW (1 << 0) 28#define MAX8925_CHG_STAT_MODE_MASK (3 << 2) 29#define MAX8925_CHG_STAT_EN_MASK (1 << 4) 30#define MAX8925_CHG_MBDET (1 << 1) 31#define MAX8925_CHG_AC_RANGE_MASK (3 << 6) 32 33/* registers in ADC */ 34#define MAX8925_ADC_RES_CNFG1 0x06 35#define MAX8925_ADC_AVG_CNFG1 0x07 36#define MAX8925_ADC_ACQ_CNFG1 0x08 37#define MAX8925_ADC_ACQ_CNFG2 0x09 38/* 2 bytes registers in below. MSB is 1st, LSB is 2nd. */ 39#define MAX8925_ADC_AUX2 0x62 40#define MAX8925_ADC_VCHG 0x64 41#define MAX8925_ADC_VBBATT 0x66 42#define MAX8925_ADC_VMBATT 0x68 43#define MAX8925_ADC_ISNS 0x6a 44#define MAX8925_ADC_THM 0x6c 45#define MAX8925_ADC_TDIE 0x6e 46#define MAX8925_CMD_AUX2 0xc8 47#define MAX8925_CMD_VCHG 0xd0 48#define MAX8925_CMD_VBBATT 0xd8 49#define MAX8925_CMD_VMBATT 0xe0 50#define MAX8925_CMD_ISNS 0xe8 51#define MAX8925_CMD_THM 0xf0 52#define MAX8925_CMD_TDIE 0xf8 53 54enum { 55 MEASURE_AUX2, 56 MEASURE_VCHG, 57 MEASURE_VBBATT, 58 MEASURE_VMBATT, 59 MEASURE_ISNS, 60 MEASURE_THM, 61 MEASURE_TDIE, 62 MEASURE_MAX, 63}; 64 65struct max8925_power_info { 66 struct max8925_chip *chip; 67 struct i2c_client *gpm; 68 struct i2c_client *adc; 69 70 struct power_supply ac; 71 struct power_supply usb; 72 struct power_supply battery; 73 int irq_base; 74 unsigned ac_online:1; 75 unsigned usb_online:1; 76 unsigned bat_online:1; 77 unsigned chg_mode:2; 78 unsigned batt_detect:1; /* detecing MB by ID pin */ 79 unsigned topoff_threshold:2; 80 unsigned fast_charge:3; 81 82 int (*set_charger) (int); 83}; 84 85static int __set_charger(struct max8925_power_info *info, int enable) 86{ 87 struct max8925_chip *chip = info->chip; 88 if (enable) { 89 /* enable charger in platform */ 90 if (info->set_charger) 91 info->set_charger(1); 92 /* enable charger */ 93 max8925_set_bits(info->gpm, MAX8925_CHG_CNTL1, 1 << 7, 0); 94 } else { 95 /* disable charge */ 96 max8925_set_bits(info->gpm, MAX8925_CHG_CNTL1, 1 << 7, 1 << 7); 97 if (info->set_charger) 98 info->set_charger(0); 99 } 100 dev_dbg(chip->dev, "%s\n", (enable) ? "Enable charger" 101 : "Disable charger"); 102 return 0; 103} 104 105static irqreturn_t max8925_charger_handler(int irq, void *data) 106{ 107 struct max8925_power_info *info = (struct max8925_power_info *)data; 108 struct max8925_chip *chip = info->chip; 109 110 switch (irq - chip->irq_base) { 111 case MAX8925_IRQ_VCHG_DC_R: 112 info->ac_online = 1; 113 __set_charger(info, 1); 114 dev_dbg(chip->dev, "Adapter inserted\n"); 115 break; 116 case MAX8925_IRQ_VCHG_DC_F: 117 info->ac_online = 0; 118 __set_charger(info, 0); 119 dev_dbg(chip->dev, "Adapter is removal\n"); 120 break; 121 case MAX8925_IRQ_VCHG_USB_R: 122 info->usb_online = 1; 123 __set_charger(info, 1); 124 dev_dbg(chip->dev, "USB inserted\n"); 125 break; 126 case MAX8925_IRQ_VCHG_USB_F: 127 info->usb_online = 0; 128 __set_charger(info, 0); 129 dev_dbg(chip->dev, "USB is removal\n"); 130 break; 131 case MAX8925_IRQ_VCHG_THM_OK_F: 132 /* Battery is not ready yet */ 133 dev_dbg(chip->dev, "Battery temperature is out of range\n"); 134 case MAX8925_IRQ_VCHG_DC_OVP: 135 dev_dbg(chip->dev, "Error detection\n"); 136 __set_charger(info, 0); 137 break; 138 case MAX8925_IRQ_VCHG_THM_OK_R: 139 /* Battery is ready now */ 140 dev_dbg(chip->dev, "Battery temperature is in range\n"); 141 break; 142 case MAX8925_IRQ_VCHG_SYSLOW_R: 143 /* VSYS is low */ 144 dev_info(chip->dev, "Sys power is too low\n"); 145 break; 146 case MAX8925_IRQ_VCHG_SYSLOW_F: 147 dev_dbg(chip->dev, "Sys power is above low threshold\n"); 148 break; 149 case MAX8925_IRQ_VCHG_DONE: 150 __set_charger(info, 0); 151 dev_dbg(chip->dev, "Charging is done\n"); 152 break; 153 case MAX8925_IRQ_VCHG_TOPOFF: 154 dev_dbg(chip->dev, "Charging in top-off mode\n"); 155 break; 156 case MAX8925_IRQ_VCHG_TMR_FAULT: 157 __set_charger(info, 0); 158 dev_dbg(chip->dev, "Safe timer is expired\n"); 159 break; 160 case MAX8925_IRQ_VCHG_RST: 161 __set_charger(info, 0); 162 dev_dbg(chip->dev, "Charger is reset\n"); 163 break; 164 } 165 return IRQ_HANDLED; 166} 167 168static int start_measure(struct max8925_power_info *info, int type) 169{ 170 unsigned char buf[2] = {0, 0}; 171 int meas_reg = 0, ret; 172 173 switch (type) { 174 case MEASURE_VCHG: 175 meas_reg = MAX8925_ADC_VCHG; 176 break; 177 case MEASURE_VBBATT: 178 meas_reg = MAX8925_ADC_VBBATT; 179 break; 180 case MEASURE_VMBATT: 181 meas_reg = MAX8925_ADC_VMBATT; 182 break; 183 case MEASURE_ISNS: 184 meas_reg = MAX8925_ADC_ISNS; 185 break; 186 default: 187 return -EINVAL; 188 } 189 190 max8925_bulk_read(info->adc, meas_reg, 2, buf); 191 ret = (buf[0] << 4) | (buf[1] >> 4); 192 193 return ret; 194} 195 196static int max8925_ac_get_prop(struct power_supply *psy, 197 enum power_supply_property psp, 198 union power_supply_propval *val) 199{ 200 struct max8925_power_info *info = dev_get_drvdata(psy->dev->parent); 201 int ret = 0; 202 203 switch (psp) { 204 case POWER_SUPPLY_PROP_ONLINE: 205 val->intval = info->ac_online; 206 break; 207 case POWER_SUPPLY_PROP_VOLTAGE_NOW: 208 if (info->ac_online) { 209 ret = start_measure(info, MEASURE_VCHG); 210 if (ret >= 0) { 211 val->intval = ret << 1; /* unit is mV */ 212 goto out; 213 } 214 } 215 ret = -ENODATA; 216 break; 217 default: 218 ret = -ENODEV; 219 break; 220 } 221out: 222 return ret; 223} 224 225static enum power_supply_property max8925_ac_props[] = { 226 POWER_SUPPLY_PROP_ONLINE, 227 POWER_SUPPLY_PROP_VOLTAGE_NOW, 228}; 229 230static int max8925_usb_get_prop(struct power_supply *psy, 231 enum power_supply_property psp, 232 union power_supply_propval *val) 233{ 234 struct max8925_power_info *info = dev_get_drvdata(psy->dev->parent); 235 int ret = 0; 236 237 switch (psp) { 238 case POWER_SUPPLY_PROP_ONLINE: 239 val->intval = info->usb_online; 240 break; 241 case POWER_SUPPLY_PROP_VOLTAGE_NOW: 242 if (info->usb_online) { 243 ret = start_measure(info, MEASURE_VCHG); 244 if (ret >= 0) { 245 val->intval = ret << 1; /* unit is mV */ 246 goto out; 247 } 248 } 249 ret = -ENODATA; 250 break; 251 default: 252 ret = -ENODEV; 253 break; 254 } 255out: 256 return ret; 257} 258 259static enum power_supply_property max8925_usb_props[] = { 260 POWER_SUPPLY_PROP_ONLINE, 261 POWER_SUPPLY_PROP_VOLTAGE_NOW, 262}; 263 264static int max8925_bat_get_prop(struct power_supply *psy, 265 enum power_supply_property psp, 266 union power_supply_propval *val) 267{ 268 struct max8925_power_info *info = dev_get_drvdata(psy->dev->parent); 269 long long int tmp = 0; 270 int ret = 0; 271 272 switch (psp) { 273 case POWER_SUPPLY_PROP_ONLINE: 274 val->intval = info->bat_online; 275 break; 276 case POWER_SUPPLY_PROP_VOLTAGE_NOW: 277 if (info->bat_online) { 278 ret = start_measure(info, MEASURE_VMBATT); 279 if (ret >= 0) { 280 val->intval = ret << 1; /* unit is mV */ 281 ret = 0; 282 break; 283 } 284 } 285 ret = -ENODATA; 286 break; 287 case POWER_SUPPLY_PROP_CURRENT_NOW: 288 if (info->bat_online) { 289 ret = start_measure(info, MEASURE_ISNS); 290 if (ret >= 0) { 291 tmp = (long long int)ret * 6250 / 4096 - 3125; 292 ret = (int)tmp; 293 val->intval = 0; 294 if (ret > 0) 295 val->intval = ret; /* unit is mA */ 296 ret = 0; 297 break; 298 } 299 } 300 ret = -ENODATA; 301 break; 302 case POWER_SUPPLY_PROP_CHARGE_TYPE: 303 if (!info->bat_online) { 304 ret = -ENODATA; 305 break; 306 } 307 ret = max8925_reg_read(info->gpm, MAX8925_CHG_STATUS); 308 ret = (ret & MAX8925_CHG_STAT_MODE_MASK) >> 2; 309 switch (ret) { 310 case 1: 311 val->intval = POWER_SUPPLY_CHARGE_TYPE_FAST; 312 break; 313 case 0: 314 case 2: 315 val->intval = POWER_SUPPLY_CHARGE_TYPE_TRICKLE; 316 break; 317 case 3: 318 val->intval = POWER_SUPPLY_CHARGE_TYPE_NONE; 319 break; 320 } 321 ret = 0; 322 break; 323 case POWER_SUPPLY_PROP_STATUS: 324 if (!info->bat_online) { 325 ret = -ENODATA; 326 break; 327 } 328 ret = max8925_reg_read(info->gpm, MAX8925_CHG_STATUS); 329 if (info->usb_online || info->ac_online) { 330 val->intval = POWER_SUPPLY_STATUS_NOT_CHARGING; 331 if (ret & MAX8925_CHG_STAT_EN_MASK) 332 val->intval = POWER_SUPPLY_STATUS_CHARGING; 333 } else 334 val->intval = POWER_SUPPLY_STATUS_DISCHARGING; 335 ret = 0; 336 break; 337 default: 338 ret = -ENODEV; 339 break; 340 } 341 return ret; 342} 343 344static enum power_supply_property max8925_battery_props[] = { 345 POWER_SUPPLY_PROP_ONLINE, 346 POWER_SUPPLY_PROP_VOLTAGE_NOW, 347 POWER_SUPPLY_PROP_CURRENT_NOW, 348 POWER_SUPPLY_PROP_CHARGE_TYPE, 349 POWER_SUPPLY_PROP_STATUS, 350}; 351 352#define REQUEST_IRQ(_irq, _name) \ 353do { \ 354 ret = request_threaded_irq(chip->irq_base + _irq, NULL, \ 355 max8925_charger_handler, \ 356 IRQF_ONESHOT, _name, info); \ 357 if (ret) \ 358 dev_err(chip->dev, "Failed to request IRQ #%d: %d\n", \ 359 _irq, ret); \ 360} while (0) 361 362static __devinit int max8925_init_charger(struct max8925_chip *chip, 363 struct max8925_power_info *info) 364{ 365 int ret; 366 367 REQUEST_IRQ(MAX8925_IRQ_VCHG_DC_OVP, "ac-ovp"); 368 REQUEST_IRQ(MAX8925_IRQ_VCHG_DC_F, "ac-remove"); 369 REQUEST_IRQ(MAX8925_IRQ_VCHG_DC_R, "ac-insert"); 370 REQUEST_IRQ(MAX8925_IRQ_VCHG_USB_OVP, "usb-ovp"); 371 REQUEST_IRQ(MAX8925_IRQ_VCHG_USB_F, "usb-remove"); 372 REQUEST_IRQ(MAX8925_IRQ_VCHG_USB_R, "usb-insert"); 373 REQUEST_IRQ(MAX8925_IRQ_VCHG_THM_OK_R, "batt-temp-in-range"); 374 REQUEST_IRQ(MAX8925_IRQ_VCHG_THM_OK_F, "batt-temp-out-range"); 375 REQUEST_IRQ(MAX8925_IRQ_VCHG_SYSLOW_F, "vsys-high"); 376 REQUEST_IRQ(MAX8925_IRQ_VCHG_SYSLOW_R, "vsys-low"); 377 REQUEST_IRQ(MAX8925_IRQ_VCHG_RST, "charger-reset"); 378 REQUEST_IRQ(MAX8925_IRQ_VCHG_DONE, "charger-done"); 379 REQUEST_IRQ(MAX8925_IRQ_VCHG_TOPOFF, "charger-topoff"); 380 REQUEST_IRQ(MAX8925_IRQ_VCHG_TMR_FAULT, "charger-timer-expire"); 381 382 info->ac_online = 0; 383 info->usb_online = 0; 384 info->bat_online = 0; 385 ret = max8925_reg_read(info->gpm, MAX8925_CHG_STATUS); 386 if (ret >= 0) { 387 /* 388 * If battery detection is enabled, ID pin of battery is 389 * connected to MBDET pin of MAX8925. It could be used to 390 * detect battery presence. 391 * Otherwise, we have to assume that battery is always on. 392 */ 393 if (info->batt_detect) 394 info->bat_online = (ret & MAX8925_CHG_MBDET) ? 0 : 1; 395 else 396 info->bat_online = 1; 397 if (ret & MAX8925_CHG_AC_RANGE_MASK) 398 info->ac_online = 1; 399 else 400 info->ac_online = 0; 401 } 402 /* disable charge */ 403 max8925_set_bits(info->gpm, MAX8925_CHG_CNTL1, 1 << 7, 1 << 7); 404 /* set charging current in charge topoff mode */ 405 max8925_set_bits(info->gpm, MAX8925_CHG_CNTL1, 3 << 5, 406 info->topoff_threshold << 5); 407 /* set charing current in fast charge mode */ 408 max8925_set_bits(info->gpm, MAX8925_CHG_CNTL1, 7, info->fast_charge); 409 410 return 0; 411} 412 413static __devexit int max8925_deinit_charger(struct max8925_power_info *info) 414{ 415 struct max8925_chip *chip = info->chip; 416 int irq; 417 418 irq = chip->irq_base + MAX8925_IRQ_VCHG_DC_OVP; 419 for (; irq <= chip->irq_base + MAX8925_IRQ_VCHG_TMR_FAULT; irq++) 420 free_irq(irq, info); 421 422 return 0; 423} 424 425static __devinit int max8925_power_probe(struct platform_device *pdev) 426{ 427 struct max8925_chip *chip = dev_get_drvdata(pdev->dev.parent); 428 struct max8925_platform_data *max8925_pdata; 429 struct max8925_power_pdata *pdata = NULL; 430 struct max8925_power_info *info; 431 int ret; 432 433 if (pdev->dev.parent->platform_data) { 434 max8925_pdata = pdev->dev.parent->platform_data; 435 pdata = max8925_pdata->power; 436 } 437 438 if (!pdata) { 439 dev_err(&pdev->dev, "platform data isn't assigned to " 440 "power supply\n"); 441 return -EINVAL; 442 } 443 444 info = kzalloc(sizeof(struct max8925_power_info), GFP_KERNEL); 445 if (!info) 446 return -ENOMEM; 447 info->chip = chip; 448 info->gpm = chip->i2c; 449 info->adc = chip->adc; 450 451 info->ac.name = "max8925-ac"; 452 info->ac.type = POWER_SUPPLY_TYPE_MAINS; 453 info->ac.properties = max8925_ac_props; 454 info->ac.num_properties = ARRAY_SIZE(max8925_ac_props); 455 info->ac.get_property = max8925_ac_get_prop; 456 ret = power_supply_register(&pdev->dev, &info->ac); 457 if (ret) 458 goto out; 459 info->ac.dev->parent = &pdev->dev; 460 461 info->usb.name = "max8925-usb"; 462 info->usb.type = POWER_SUPPLY_TYPE_USB; 463 info->usb.properties = max8925_usb_props; 464 info->usb.num_properties = ARRAY_SIZE(max8925_usb_props); 465 info->usb.get_property = max8925_usb_get_prop; 466 ret = power_supply_register(&pdev->dev, &info->usb); 467 if (ret) 468 goto out_usb; 469 info->usb.dev->parent = &pdev->dev; 470 471 info->battery.name = "max8925-battery"; 472 info->battery.type = POWER_SUPPLY_TYPE_BATTERY; 473 info->battery.properties = max8925_battery_props; 474 info->battery.num_properties = ARRAY_SIZE(max8925_battery_props); 475 info->battery.get_property = max8925_bat_get_prop; 476 ret = power_supply_register(&pdev->dev, &info->battery); 477 if (ret) 478 goto out_battery; 479 info->battery.dev->parent = &pdev->dev; 480 481 info->batt_detect = pdata->batt_detect; 482 info->topoff_threshold = pdata->topoff_threshold; 483 info->fast_charge = pdata->fast_charge; 484 info->set_charger = pdata->set_charger; 485 dev_set_drvdata(&pdev->dev, info); 486 platform_set_drvdata(pdev, info); 487 488 max8925_init_charger(chip, info); 489 return 0; 490out_battery: 491 power_supply_unregister(&info->battery); 492out_usb: 493 power_supply_unregister(&info->ac); 494out: 495 kfree(info); 496 return ret; 497} 498 499static __devexit int max8925_power_remove(struct platform_device *pdev) 500{ 501 struct max8925_power_info *info = platform_get_drvdata(pdev); 502 503 if (info) { 504 power_supply_unregister(&info->ac); 505 power_supply_unregister(&info->usb); 506 power_supply_unregister(&info->battery); 507 max8925_deinit_charger(info); 508 kfree(info); 509 } 510 return 0; 511} 512 513static struct platform_driver max8925_power_driver = { 514 .probe = max8925_power_probe, 515 .remove = __devexit_p(max8925_power_remove), 516 .driver = { 517 .name = "max8925-power", 518 }, 519}; 520 521static int __init max8925_power_init(void) 522{ 523 return platform_driver_register(&max8925_power_driver); 524} 525module_init(max8925_power_init); 526 527static void __exit max8925_power_exit(void) 528{ 529 platform_driver_unregister(&max8925_power_driver); 530} 531module_exit(max8925_power_exit); 532 533MODULE_LICENSE("GPL"); 534MODULE_DESCRIPTION("Power supply driver for MAX8925"); 535MODULE_ALIAS("platform:max8925-power"); 536