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

Configure Feed

Select the types of activity you want to include in your feed.

at v3.7 530 lines 14 kB view raw
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 unsigned no_temp_support:1; 82 unsigned no_insert_detect:1; 83 84 int (*set_charger) (int); 85}; 86 87static int __set_charger(struct max8925_power_info *info, int enable) 88{ 89 struct max8925_chip *chip = info->chip; 90 if (enable) { 91 /* enable charger in platform */ 92 if (info->set_charger) 93 info->set_charger(1); 94 /* enable charger */ 95 max8925_set_bits(info->gpm, MAX8925_CHG_CNTL1, 1 << 7, 0); 96 } else { 97 /* disable charge */ 98 max8925_set_bits(info->gpm, MAX8925_CHG_CNTL1, 1 << 7, 1 << 7); 99 if (info->set_charger) 100 info->set_charger(0); 101 } 102 dev_dbg(chip->dev, "%s\n", (enable) ? "Enable charger" 103 : "Disable charger"); 104 return 0; 105} 106 107static irqreturn_t max8925_charger_handler(int irq, void *data) 108{ 109 struct max8925_power_info *info = (struct max8925_power_info *)data; 110 struct max8925_chip *chip = info->chip; 111 112 switch (irq - chip->irq_base) { 113 case MAX8925_IRQ_VCHG_DC_R: 114 info->ac_online = 1; 115 __set_charger(info, 1); 116 dev_dbg(chip->dev, "Adapter inserted\n"); 117 break; 118 case MAX8925_IRQ_VCHG_DC_F: 119 info->ac_online = 0; 120 __set_charger(info, 0); 121 dev_dbg(chip->dev, "Adapter removed\n"); 122 break; 123 case MAX8925_IRQ_VCHG_THM_OK_F: 124 /* Battery is not ready yet */ 125 dev_dbg(chip->dev, "Battery temperature is out of range\n"); 126 case MAX8925_IRQ_VCHG_DC_OVP: 127 dev_dbg(chip->dev, "Error detection\n"); 128 __set_charger(info, 0); 129 break; 130 case MAX8925_IRQ_VCHG_THM_OK_R: 131 /* Battery is ready now */ 132 dev_dbg(chip->dev, "Battery temperature is in range\n"); 133 break; 134 case MAX8925_IRQ_VCHG_SYSLOW_R: 135 /* VSYS is low */ 136 dev_info(chip->dev, "Sys power is too low\n"); 137 break; 138 case MAX8925_IRQ_VCHG_SYSLOW_F: 139 dev_dbg(chip->dev, "Sys power is above low threshold\n"); 140 break; 141 case MAX8925_IRQ_VCHG_DONE: 142 __set_charger(info, 0); 143 dev_dbg(chip->dev, "Charging is done\n"); 144 break; 145 case MAX8925_IRQ_VCHG_TOPOFF: 146 dev_dbg(chip->dev, "Charging in top-off mode\n"); 147 break; 148 case MAX8925_IRQ_VCHG_TMR_FAULT: 149 __set_charger(info, 0); 150 dev_dbg(chip->dev, "Safe timer is expired\n"); 151 break; 152 case MAX8925_IRQ_VCHG_RST: 153 __set_charger(info, 0); 154 dev_dbg(chip->dev, "Charger is reset\n"); 155 break; 156 } 157 return IRQ_HANDLED; 158} 159 160static int start_measure(struct max8925_power_info *info, int type) 161{ 162 unsigned char buf[2] = {0, 0}; 163 int meas_cmd; 164 int meas_reg = 0, ret; 165 166 switch (type) { 167 case MEASURE_VCHG: 168 meas_cmd = MAX8925_CMD_VCHG; 169 meas_reg = MAX8925_ADC_VCHG; 170 break; 171 case MEASURE_VBBATT: 172 meas_cmd = MAX8925_CMD_VBBATT; 173 meas_reg = MAX8925_ADC_VBBATT; 174 break; 175 case MEASURE_VMBATT: 176 meas_cmd = MAX8925_CMD_VMBATT; 177 meas_reg = MAX8925_ADC_VMBATT; 178 break; 179 case MEASURE_ISNS: 180 meas_cmd = MAX8925_CMD_ISNS; 181 meas_reg = MAX8925_ADC_ISNS; 182 break; 183 default: 184 return -EINVAL; 185 } 186 187 max8925_reg_write(info->adc, meas_cmd, 0); 188 max8925_bulk_read(info->adc, meas_reg, 2, buf); 189 ret = ((buf[0]<<8) | buf[1]) >> 4; 190 191 return ret; 192} 193 194static int max8925_ac_get_prop(struct power_supply *psy, 195 enum power_supply_property psp, 196 union power_supply_propval *val) 197{ 198 struct max8925_power_info *info = dev_get_drvdata(psy->dev->parent); 199 int ret = 0; 200 201 switch (psp) { 202 case POWER_SUPPLY_PROP_ONLINE: 203 val->intval = info->ac_online; 204 break; 205 case POWER_SUPPLY_PROP_VOLTAGE_NOW: 206 if (info->ac_online) { 207 ret = start_measure(info, MEASURE_VCHG); 208 if (ret >= 0) { 209 val->intval = ret * 2000; /* unit is uV */ 210 goto out; 211 } 212 } 213 ret = -ENODATA; 214 break; 215 default: 216 ret = -ENODEV; 217 break; 218 } 219out: 220 return ret; 221} 222 223static enum power_supply_property max8925_ac_props[] = { 224 POWER_SUPPLY_PROP_ONLINE, 225 POWER_SUPPLY_PROP_VOLTAGE_NOW, 226}; 227 228static int max8925_usb_get_prop(struct power_supply *psy, 229 enum power_supply_property psp, 230 union power_supply_propval *val) 231{ 232 struct max8925_power_info *info = dev_get_drvdata(psy->dev->parent); 233 int ret = 0; 234 235 switch (psp) { 236 case POWER_SUPPLY_PROP_ONLINE: 237 val->intval = info->usb_online; 238 break; 239 case POWER_SUPPLY_PROP_VOLTAGE_NOW: 240 if (info->usb_online) { 241 ret = start_measure(info, MEASURE_VCHG); 242 if (ret >= 0) { 243 val->intval = ret * 2000; /* unit is uV */ 244 goto out; 245 } 246 } 247 ret = -ENODATA; 248 break; 249 default: 250 ret = -ENODEV; 251 break; 252 } 253out: 254 return ret; 255} 256 257static enum power_supply_property max8925_usb_props[] = { 258 POWER_SUPPLY_PROP_ONLINE, 259 POWER_SUPPLY_PROP_VOLTAGE_NOW, 260}; 261 262static int max8925_bat_get_prop(struct power_supply *psy, 263 enum power_supply_property psp, 264 union power_supply_propval *val) 265{ 266 struct max8925_power_info *info = dev_get_drvdata(psy->dev->parent); 267 int ret = 0; 268 269 switch (psp) { 270 case POWER_SUPPLY_PROP_ONLINE: 271 val->intval = info->bat_online; 272 break; 273 case POWER_SUPPLY_PROP_VOLTAGE_NOW: 274 if (info->bat_online) { 275 ret = start_measure(info, MEASURE_VMBATT); 276 if (ret >= 0) { 277 val->intval = ret * 2000; /* unit is uV */ 278 ret = 0; 279 break; 280 } 281 } 282 ret = -ENODATA; 283 break; 284 case POWER_SUPPLY_PROP_CURRENT_NOW: 285 if (info->bat_online) { 286 ret = start_measure(info, MEASURE_ISNS); 287 if (ret >= 0) { 288 /* assume r_sns is 0.02 */ 289 ret = ((ret * 6250) - 3125) /* uA */; 290 val->intval = 0; 291 if (ret > 0) 292 val->intval = ret; /* unit is mA */ 293 ret = 0; 294 break; 295 } 296 } 297 ret = -ENODATA; 298 break; 299 case POWER_SUPPLY_PROP_CHARGE_TYPE: 300 if (!info->bat_online) { 301 ret = -ENODATA; 302 break; 303 } 304 ret = max8925_reg_read(info->gpm, MAX8925_CHG_STATUS); 305 ret = (ret & MAX8925_CHG_STAT_MODE_MASK) >> 2; 306 switch (ret) { 307 case 1: 308 val->intval = POWER_SUPPLY_CHARGE_TYPE_FAST; 309 break; 310 case 0: 311 case 2: 312 val->intval = POWER_SUPPLY_CHARGE_TYPE_TRICKLE; 313 break; 314 case 3: 315 val->intval = POWER_SUPPLY_CHARGE_TYPE_NONE; 316 break; 317 } 318 ret = 0; 319 break; 320 case POWER_SUPPLY_PROP_STATUS: 321 if (!info->bat_online) { 322 ret = -ENODATA; 323 break; 324 } 325 ret = max8925_reg_read(info->gpm, MAX8925_CHG_STATUS); 326 if (info->usb_online || info->ac_online) { 327 val->intval = POWER_SUPPLY_STATUS_NOT_CHARGING; 328 if (ret & MAX8925_CHG_STAT_EN_MASK) 329 val->intval = POWER_SUPPLY_STATUS_CHARGING; 330 } else 331 val->intval = POWER_SUPPLY_STATUS_DISCHARGING; 332 ret = 0; 333 break; 334 default: 335 ret = -ENODEV; 336 break; 337 } 338 return ret; 339} 340 341static enum power_supply_property max8925_battery_props[] = { 342 POWER_SUPPLY_PROP_ONLINE, 343 POWER_SUPPLY_PROP_VOLTAGE_NOW, 344 POWER_SUPPLY_PROP_CURRENT_NOW, 345 POWER_SUPPLY_PROP_CHARGE_TYPE, 346 POWER_SUPPLY_PROP_STATUS, 347}; 348 349#define REQUEST_IRQ(_irq, _name) \ 350do { \ 351 ret = request_threaded_irq(chip->irq_base + _irq, NULL, \ 352 max8925_charger_handler, \ 353 IRQF_ONESHOT, _name, info); \ 354 if (ret) \ 355 dev_err(chip->dev, "Failed to request IRQ #%d: %d\n", \ 356 _irq, ret); \ 357} while (0) 358 359static __devinit int max8925_init_charger(struct max8925_chip *chip, 360 struct max8925_power_info *info) 361{ 362 int ret; 363 364 REQUEST_IRQ(MAX8925_IRQ_VCHG_DC_OVP, "ac-ovp"); 365 if (!info->no_insert_detect) { 366 REQUEST_IRQ(MAX8925_IRQ_VCHG_DC_F, "ac-remove"); 367 REQUEST_IRQ(MAX8925_IRQ_VCHG_DC_R, "ac-insert"); 368 } 369 if (!info->no_temp_support) { 370 REQUEST_IRQ(MAX8925_IRQ_VCHG_THM_OK_R, "batt-temp-in-range"); 371 REQUEST_IRQ(MAX8925_IRQ_VCHG_THM_OK_F, "batt-temp-out-range"); 372 } 373 REQUEST_IRQ(MAX8925_IRQ_VCHG_SYSLOW_F, "vsys-high"); 374 REQUEST_IRQ(MAX8925_IRQ_VCHG_SYSLOW_R, "vsys-low"); 375 REQUEST_IRQ(MAX8925_IRQ_VCHG_RST, "charger-reset"); 376 REQUEST_IRQ(MAX8925_IRQ_VCHG_DONE, "charger-done"); 377 REQUEST_IRQ(MAX8925_IRQ_VCHG_TOPOFF, "charger-topoff"); 378 REQUEST_IRQ(MAX8925_IRQ_VCHG_TMR_FAULT, "charger-timer-expire"); 379 380 info->usb_online = 0; 381 info->bat_online = 0; 382 383 /* check for power - can miss interrupt at boot time */ 384 if (start_measure(info, MEASURE_VCHG) * 2000 > 500000) 385 info->ac_online = 1; 386 else 387 info->ac_online = 0; 388 389 ret = max8925_reg_read(info->gpm, MAX8925_CHG_STATUS); 390 if (ret >= 0) { 391 /* 392 * If battery detection is enabled, ID pin of battery is 393 * connected to MBDET pin of MAX8925. It could be used to 394 * detect battery presence. 395 * Otherwise, we have to assume that battery is always on. 396 */ 397 if (info->batt_detect) 398 info->bat_online = (ret & MAX8925_CHG_MBDET) ? 0 : 1; 399 else 400 info->bat_online = 1; 401 if (ret & MAX8925_CHG_AC_RANGE_MASK) 402 info->ac_online = 1; 403 else 404 info->ac_online = 0; 405 } 406 /* disable charge */ 407 max8925_set_bits(info->gpm, MAX8925_CHG_CNTL1, 1 << 7, 1 << 7); 408 /* set charging current in charge topoff mode */ 409 max8925_set_bits(info->gpm, MAX8925_CHG_CNTL1, 3 << 5, 410 info->topoff_threshold << 5); 411 /* set charing current in fast charge mode */ 412 max8925_set_bits(info->gpm, MAX8925_CHG_CNTL1, 7, info->fast_charge); 413 414 return 0; 415} 416 417static __devexit int max8925_deinit_charger(struct max8925_power_info *info) 418{ 419 struct max8925_chip *chip = info->chip; 420 int irq; 421 422 irq = chip->irq_base + MAX8925_IRQ_VCHG_DC_OVP; 423 for (; irq <= chip->irq_base + MAX8925_IRQ_VCHG_TMR_FAULT; irq++) 424 free_irq(irq, info); 425 426 return 0; 427} 428 429static __devinit int max8925_power_probe(struct platform_device *pdev) 430{ 431 struct max8925_chip *chip = dev_get_drvdata(pdev->dev.parent); 432 struct max8925_power_pdata *pdata = NULL; 433 struct max8925_power_info *info; 434 int ret; 435 436 pdata = pdev->dev.platform_data; 437 if (!pdata) { 438 dev_err(&pdev->dev, "platform data isn't assigned to " 439 "power supply\n"); 440 return -EINVAL; 441 } 442 443 info = kzalloc(sizeof(struct max8925_power_info), GFP_KERNEL); 444 if (!info) 445 return -ENOMEM; 446 info->chip = chip; 447 info->gpm = chip->i2c; 448 info->adc = chip->adc; 449 platform_set_drvdata(pdev, info); 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 info->ac.supplied_to = pdata->supplied_to; 457 info->ac.num_supplicants = pdata->num_supplicants; 458 ret = power_supply_register(&pdev->dev, &info->ac); 459 if (ret) 460 goto out; 461 info->ac.dev->parent = &pdev->dev; 462 463 info->usb.name = "max8925-usb"; 464 info->usb.type = POWER_SUPPLY_TYPE_USB; 465 info->usb.properties = max8925_usb_props; 466 info->usb.num_properties = ARRAY_SIZE(max8925_usb_props); 467 info->usb.get_property = max8925_usb_get_prop; 468 info->usb.supplied_to = pdata->supplied_to; 469 info->usb.num_supplicants = pdata->num_supplicants; 470 471 ret = power_supply_register(&pdev->dev, &info->usb); 472 if (ret) 473 goto out_usb; 474 info->usb.dev->parent = &pdev->dev; 475 476 info->battery.name = "max8925-battery"; 477 info->battery.type = POWER_SUPPLY_TYPE_BATTERY; 478 info->battery.properties = max8925_battery_props; 479 info->battery.num_properties = ARRAY_SIZE(max8925_battery_props); 480 info->battery.get_property = max8925_bat_get_prop; 481 ret = power_supply_register(&pdev->dev, &info->battery); 482 if (ret) 483 goto out_battery; 484 info->battery.dev->parent = &pdev->dev; 485 486 info->batt_detect = pdata->batt_detect; 487 info->topoff_threshold = pdata->topoff_threshold; 488 info->fast_charge = pdata->fast_charge; 489 info->set_charger = pdata->set_charger; 490 info->no_temp_support = pdata->no_temp_support; 491 info->no_insert_detect = pdata->no_insert_detect; 492 493 max8925_init_charger(chip, info); 494 return 0; 495out_battery: 496 power_supply_unregister(&info->battery); 497out_usb: 498 power_supply_unregister(&info->ac); 499out: 500 kfree(info); 501 return ret; 502} 503 504static __devexit int max8925_power_remove(struct platform_device *pdev) 505{ 506 struct max8925_power_info *info = platform_get_drvdata(pdev); 507 508 if (info) { 509 power_supply_unregister(&info->ac); 510 power_supply_unregister(&info->usb); 511 power_supply_unregister(&info->battery); 512 max8925_deinit_charger(info); 513 kfree(info); 514 } 515 return 0; 516} 517 518static struct platform_driver max8925_power_driver = { 519 .probe = max8925_power_probe, 520 .remove = __devexit_p(max8925_power_remove), 521 .driver = { 522 .name = "max8925-power", 523 }, 524}; 525 526module_platform_driver(max8925_power_driver); 527 528MODULE_LICENSE("GPL"); 529MODULE_DESCRIPTION("Power supply driver for MAX8925"); 530MODULE_ALIAS("platform:max8925-power");