1 /* NXP PCF50633 Main Battery Charger Driver 2 * 3 * (C) 2006-2008 by Openmoko, Inc. 4 * Author: Balaji Rao <balajirrao@openmoko.org> 5 * All rights reserved. 6 * 7 * Broken down from monstrous PCF50633 driver mainly by 8 * Harald Welte, Andy Green and Werner Almesberger 9 * 10 * This program is free software; you can redistribute it and/or modify it 11 * under the terms of the GNU General Public License as published by the 12 * Free Software Foundation; either version 2 of the License, or (at your 13 * option) any later version. 14 * 15 */ 16 17 #include <linux/kernel.h> 18 #include <linux/module.h> 19 #include <linux/slab.h> 20 #include <linux/init.h> 21 #include <linux/types.h> 22 #include <linux/device.h> 23 #include <linux/sysfs.h> 24 #include <linux/platform_device.h> 25 #include <linux/power_supply.h> 26 27 #include <linux/mfd/pcf50633/core.h> 28 #include <linux/mfd/pcf50633/mbc.h> 29 30 struct pcf50633_mbc { 31 struct pcf50633 *pcf; 32 33 int adapter_online; 34 int usb_online; 35 36 struct power_supply *usb; 37 struct power_supply *adapter; 38 struct power_supply *ac; 39 }; 40 41 int pcf50633_mbc_usb_curlim_set(struct pcf50633 *pcf, int ma) 42 { 43 struct pcf50633_mbc *mbc = platform_get_drvdata(pcf->mbc_pdev); 44 int ret = 0; 45 u8 bits; 46 u8 mbcs2, chgmod; 47 unsigned int mbcc5; 48 49 if (ma >= 1000) { 50 bits = PCF50633_MBCC7_USB_1000mA; 51 ma = 1000; 52 } else if (ma >= 500) { 53 bits = PCF50633_MBCC7_USB_500mA; 54 ma = 500; 55 } else if (ma >= 100) { 56 bits = PCF50633_MBCC7_USB_100mA; 57 ma = 100; 58 } else { 59 bits = PCF50633_MBCC7_USB_SUSPEND; 60 ma = 0; 61 } 62 63 ret = pcf50633_reg_set_bit_mask(pcf, PCF50633_REG_MBCC7, 64 PCF50633_MBCC7_USB_MASK, bits); 65 if (ret) 66 dev_err(pcf->dev, "error setting usb curlim to %d mA\n", ma); 67 else 68 dev_info(pcf->dev, "usb curlim to %d mA\n", ma); 69 70 /* 71 * We limit the charging current to be the USB current limit. 72 * The reason is that on pcf50633, when it enters PMU Standby mode, 73 * which it does when the device goes "off", the USB current limit 74 * reverts to the variant default. In at least one common case, that 75 * default is 500mA. By setting the charging current to be the same 76 * as the USB limit we set here before PMU standby, we enforce it only 77 * using the correct amount of current even when the USB current limit 78 * gets reset to the wrong thing 79 */ 80 81 if (mbc->pcf->pdata->charger_reference_current_ma) { 82 mbcc5 = (ma << 8) / mbc->pcf->pdata->charger_reference_current_ma; 83 if (mbcc5 > 255) 84 mbcc5 = 255; 85 pcf50633_reg_write(mbc->pcf, PCF50633_REG_MBCC5, mbcc5); 86 } 87 88 mbcs2 = pcf50633_reg_read(mbc->pcf, PCF50633_REG_MBCS2); 89 chgmod = (mbcs2 & PCF50633_MBCS2_MBC_MASK); 90 91 /* If chgmod == BATFULL, setting chgena has no effect. 92 * Datasheet says we need to set resume instead but when autoresume is 93 * used resume doesn't work. Clear and set chgena instead. 94 */ 95 if (chgmod != PCF50633_MBCS2_MBC_BAT_FULL) 96 pcf50633_reg_set_bit_mask(pcf, PCF50633_REG_MBCC1, 97 PCF50633_MBCC1_CHGENA, PCF50633_MBCC1_CHGENA); 98 else { 99 pcf50633_reg_clear_bits(pcf, PCF50633_REG_MBCC1, 100 PCF50633_MBCC1_CHGENA); 101 pcf50633_reg_set_bit_mask(pcf, PCF50633_REG_MBCC1, 102 PCF50633_MBCC1_CHGENA, PCF50633_MBCC1_CHGENA); 103 } 104 105 power_supply_changed(mbc->usb); 106 107 return ret; 108 } 109 EXPORT_SYMBOL_GPL(pcf50633_mbc_usb_curlim_set); 110 111 int pcf50633_mbc_get_status(struct pcf50633 *pcf) 112 { 113 struct pcf50633_mbc *mbc = platform_get_drvdata(pcf->mbc_pdev); 114 int status = 0; 115 u8 chgmod; 116 117 if (!mbc) 118 return 0; 119 120 chgmod = pcf50633_reg_read(mbc->pcf, PCF50633_REG_MBCS2) 121 & PCF50633_MBCS2_MBC_MASK; 122 123 if (mbc->usb_online) 124 status |= PCF50633_MBC_USB_ONLINE; 125 if (chgmod == PCF50633_MBCS2_MBC_USB_PRE || 126 chgmod == PCF50633_MBCS2_MBC_USB_PRE_WAIT || 127 chgmod == PCF50633_MBCS2_MBC_USB_FAST || 128 chgmod == PCF50633_MBCS2_MBC_USB_FAST_WAIT) 129 status |= PCF50633_MBC_USB_ACTIVE; 130 if (mbc->adapter_online) 131 status |= PCF50633_MBC_ADAPTER_ONLINE; 132 if (chgmod == PCF50633_MBCS2_MBC_ADP_PRE || 133 chgmod == PCF50633_MBCS2_MBC_ADP_PRE_WAIT || 134 chgmod == PCF50633_MBCS2_MBC_ADP_FAST || 135 chgmod == PCF50633_MBCS2_MBC_ADP_FAST_WAIT) 136 status |= PCF50633_MBC_ADAPTER_ACTIVE; 137 138 return status; 139 } 140 EXPORT_SYMBOL_GPL(pcf50633_mbc_get_status); 141 142 int pcf50633_mbc_get_usb_online_status(struct pcf50633 *pcf) 143 { 144 struct pcf50633_mbc *mbc = platform_get_drvdata(pcf->mbc_pdev); 145 146 if (!mbc) 147 return 0; 148 149 return mbc->usb_online; 150 } 151 EXPORT_SYMBOL_GPL(pcf50633_mbc_get_usb_online_status); 152 153 static ssize_t 154 show_chgmode(struct device *dev, struct device_attribute *attr, char *buf) 155 { 156 struct pcf50633_mbc *mbc = dev_get_drvdata(dev); 157 158 u8 mbcs2 = pcf50633_reg_read(mbc->pcf, PCF50633_REG_MBCS2); 159 u8 chgmod = (mbcs2 & PCF50633_MBCS2_MBC_MASK); 160 161 return sprintf(buf, "%d\n", chgmod); 162 } 163 static DEVICE_ATTR(chgmode, S_IRUGO, show_chgmode, NULL); 164 165 static ssize_t 166 show_usblim(struct device *dev, struct device_attribute *attr, char *buf) 167 { 168 struct pcf50633_mbc *mbc = dev_get_drvdata(dev); 169 u8 usblim = pcf50633_reg_read(mbc->pcf, PCF50633_REG_MBCC7) & 170 PCF50633_MBCC7_USB_MASK; 171 unsigned int ma; 172 173 if (usblim == PCF50633_MBCC7_USB_1000mA) 174 ma = 1000; 175 else if (usblim == PCF50633_MBCC7_USB_500mA) 176 ma = 500; 177 else if (usblim == PCF50633_MBCC7_USB_100mA) 178 ma = 100; 179 else 180 ma = 0; 181 182 return sprintf(buf, "%u\n", ma); 183 } 184 185 static ssize_t set_usblim(struct device *dev, 186 struct device_attribute *attr, const char *buf, size_t count) 187 { 188 struct pcf50633_mbc *mbc = dev_get_drvdata(dev); 189 unsigned long ma; 190 int ret; 191 192 ret = kstrtoul(buf, 10, &ma); 193 if (ret) 194 return ret; 195 196 pcf50633_mbc_usb_curlim_set(mbc->pcf, ma); 197 198 return count; 199 } 200 201 static DEVICE_ATTR(usb_curlim, S_IRUGO | S_IWUSR, show_usblim, set_usblim); 202 203 static ssize_t 204 show_chglim(struct device *dev, struct device_attribute *attr, char *buf) 205 { 206 struct pcf50633_mbc *mbc = dev_get_drvdata(dev); 207 u8 mbcc5 = pcf50633_reg_read(mbc->pcf, PCF50633_REG_MBCC5); 208 unsigned int ma; 209 210 if (!mbc->pcf->pdata->charger_reference_current_ma) 211 return -ENODEV; 212 213 ma = (mbc->pcf->pdata->charger_reference_current_ma * mbcc5) >> 8; 214 215 return sprintf(buf, "%u\n", ma); 216 } 217 218 static ssize_t set_chglim(struct device *dev, 219 struct device_attribute *attr, const char *buf, size_t count) 220 { 221 struct pcf50633_mbc *mbc = dev_get_drvdata(dev); 222 unsigned long ma; 223 unsigned int mbcc5; 224 int ret; 225 226 if (!mbc->pcf->pdata->charger_reference_current_ma) 227 return -ENODEV; 228 229 ret = kstrtoul(buf, 10, &ma); 230 if (ret) 231 return ret; 232 233 mbcc5 = (ma << 8) / mbc->pcf->pdata->charger_reference_current_ma; 234 if (mbcc5 > 255) 235 mbcc5 = 255; 236 pcf50633_reg_write(mbc->pcf, PCF50633_REG_MBCC5, mbcc5); 237 238 return count; 239 } 240 241 /* 242 * This attribute allows to change MBC charging limit on the fly 243 * independently of usb current limit. It also gets set automatically every 244 * time usb current limit is changed. 245 */ 246 static DEVICE_ATTR(chg_curlim, S_IRUGO | S_IWUSR, show_chglim, set_chglim); 247 248 static struct attribute *pcf50633_mbc_sysfs_entries[] = { 249 &dev_attr_chgmode.attr, 250 &dev_attr_usb_curlim.attr, 251 &dev_attr_chg_curlim.attr, 252 NULL, 253 }; 254 255 static const struct attribute_group mbc_attr_group = { 256 .name = NULL, /* put in device directory */ 257 .attrs = pcf50633_mbc_sysfs_entries, 258 }; 259 260 static void 261 pcf50633_mbc_irq_handler(int irq, void *data) 262 { 263 struct pcf50633_mbc *mbc = data; 264 265 /* USB */ 266 if (irq == PCF50633_IRQ_USBINS) { 267 mbc->usb_online = 1; 268 } else if (irq == PCF50633_IRQ_USBREM) { 269 mbc->usb_online = 0; 270 pcf50633_mbc_usb_curlim_set(mbc->pcf, 0); 271 } 272 273 /* Adapter */ 274 if (irq == PCF50633_IRQ_ADPINS) 275 mbc->adapter_online = 1; 276 else if (irq == PCF50633_IRQ_ADPREM) 277 mbc->adapter_online = 0; 278 279 power_supply_changed(mbc->ac); 280 power_supply_changed(mbc->usb); 281 power_supply_changed(mbc->adapter); 282 283 if (mbc->pcf->pdata->mbc_event_callback) 284 mbc->pcf->pdata->mbc_event_callback(mbc->pcf, irq); 285 } 286 287 static int adapter_get_property(struct power_supply *psy, 288 enum power_supply_property psp, 289 union power_supply_propval *val) 290 { 291 struct pcf50633_mbc *mbc = power_supply_get_drvdata(psy); 292 int ret = 0; 293 294 switch (psp) { 295 case POWER_SUPPLY_PROP_ONLINE: 296 val->intval = mbc->adapter_online; 297 break; 298 default: 299 ret = -EINVAL; 300 break; 301 } 302 return ret; 303 } 304 305 static int usb_get_property(struct power_supply *psy, 306 enum power_supply_property psp, 307 union power_supply_propval *val) 308 { 309 struct pcf50633_mbc *mbc = power_supply_get_drvdata(psy); 310 int ret = 0; 311 u8 usblim = pcf50633_reg_read(mbc->pcf, PCF50633_REG_MBCC7) & 312 PCF50633_MBCC7_USB_MASK; 313 314 switch (psp) { 315 case POWER_SUPPLY_PROP_ONLINE: 316 val->intval = mbc->usb_online && 317 (usblim <= PCF50633_MBCC7_USB_500mA); 318 break; 319 default: 320 ret = -EINVAL; 321 break; 322 } 323 return ret; 324 } 325 326 static int ac_get_property(struct power_supply *psy, 327 enum power_supply_property psp, 328 union power_supply_propval *val) 329 { 330 struct pcf50633_mbc *mbc = power_supply_get_drvdata(psy); 331 int ret = 0; 332 u8 usblim = pcf50633_reg_read(mbc->pcf, PCF50633_REG_MBCC7) & 333 PCF50633_MBCC7_USB_MASK; 334 335 switch (psp) { 336 case POWER_SUPPLY_PROP_ONLINE: 337 val->intval = mbc->usb_online && 338 (usblim == PCF50633_MBCC7_USB_1000mA); 339 break; 340 default: 341 ret = -EINVAL; 342 break; 343 } 344 return ret; 345 } 346 347 static enum power_supply_property power_props[] = { 348 POWER_SUPPLY_PROP_ONLINE, 349 }; 350 351 static const u8 mbc_irq_handlers[] = { 352 PCF50633_IRQ_ADPINS, 353 PCF50633_IRQ_ADPREM, 354 PCF50633_IRQ_USBINS, 355 PCF50633_IRQ_USBREM, 356 PCF50633_IRQ_BATFULL, 357 PCF50633_IRQ_CHGHALT, 358 PCF50633_IRQ_THLIMON, 359 PCF50633_IRQ_THLIMOFF, 360 PCF50633_IRQ_USBLIMON, 361 PCF50633_IRQ_USBLIMOFF, 362 PCF50633_IRQ_LOWSYS, 363 PCF50633_IRQ_LOWBAT, 364 }; 365 366 static const struct power_supply_desc pcf50633_mbc_adapter_desc = { 367 .name = "adapter", 368 .type = POWER_SUPPLY_TYPE_MAINS, 369 .properties = power_props, 370 .num_properties = ARRAY_SIZE(power_props), 371 .get_property = &adapter_get_property, 372 }; 373 374 static const struct power_supply_desc pcf50633_mbc_usb_desc = { 375 .name = "usb", 376 .type = POWER_SUPPLY_TYPE_USB, 377 .properties = power_props, 378 .num_properties = ARRAY_SIZE(power_props), 379 .get_property = usb_get_property, 380 }; 381 382 static const struct power_supply_desc pcf50633_mbc_ac_desc = { 383 .name = "ac", 384 .type = POWER_SUPPLY_TYPE_MAINS, 385 .properties = power_props, 386 .num_properties = ARRAY_SIZE(power_props), 387 .get_property = ac_get_property, 388 }; 389 390 static int pcf50633_mbc_probe(struct platform_device *pdev) 391 { 392 struct power_supply_config psy_cfg = {}; 393 struct pcf50633_mbc *mbc; 394 int i; 395 u8 mbcs1; 396 397 mbc = devm_kzalloc(&pdev->dev, sizeof(*mbc), GFP_KERNEL); 398 if (!mbc) 399 return -ENOMEM; 400 401 platform_set_drvdata(pdev, mbc); 402 mbc->pcf = dev_to_pcf50633(pdev->dev.parent); 403 404 /* Set up IRQ handlers */ 405 for (i = 0; i < ARRAY_SIZE(mbc_irq_handlers); i++) 406 pcf50633_register_irq(mbc->pcf, mbc_irq_handlers[i], 407 pcf50633_mbc_irq_handler, mbc); 408 409 psy_cfg.supplied_to = mbc->pcf->pdata->batteries; 410 psy_cfg.num_supplicants = mbc->pcf->pdata->num_batteries; 411 psy_cfg.drv_data = mbc; 412 413 /* Create power supplies */ 414 mbc->adapter = power_supply_register(&pdev->dev, 415 &pcf50633_mbc_adapter_desc, 416 &psy_cfg); 417 if (IS_ERR(mbc->adapter)) { 418 dev_err(mbc->pcf->dev, "failed to register adapter\n"); 419 return PTR_ERR(mbc->adapter); 420 } 421 422 mbc->usb = power_supply_register(&pdev->dev, &pcf50633_mbc_usb_desc, 423 &psy_cfg); 424 if (IS_ERR(mbc->usb)) { 425 dev_err(mbc->pcf->dev, "failed to register usb\n"); 426 power_supply_unregister(mbc->adapter); 427 return PTR_ERR(mbc->usb); 428 } 429 430 mbc->ac = power_supply_register(&pdev->dev, &pcf50633_mbc_ac_desc, 431 &psy_cfg); 432 if (IS_ERR(mbc->ac)) { 433 dev_err(mbc->pcf->dev, "failed to register ac\n"); 434 power_supply_unregister(mbc->adapter); 435 power_supply_unregister(mbc->usb); 436 return PTR_ERR(mbc->ac); 437 } 438 439 if (sysfs_create_group(&pdev->dev.kobj, &mbc_attr_group)) 440 dev_err(mbc->pcf->dev, "failed to create sysfs entries\n"); 441 442 mbcs1 = pcf50633_reg_read(mbc->pcf, PCF50633_REG_MBCS1); 443 if (mbcs1 & PCF50633_MBCS1_USBPRES) 444 pcf50633_mbc_irq_handler(PCF50633_IRQ_USBINS, mbc); 445 if (mbcs1 & PCF50633_MBCS1_ADAPTPRES) 446 pcf50633_mbc_irq_handler(PCF50633_IRQ_ADPINS, mbc); 447 448 return 0; 449 } 450 451 static int pcf50633_mbc_remove(struct platform_device *pdev) 452 { 453 struct pcf50633_mbc *mbc = platform_get_drvdata(pdev); 454 int i; 455 456 /* Remove IRQ handlers */ 457 for (i = 0; i < ARRAY_SIZE(mbc_irq_handlers); i++) 458 pcf50633_free_irq(mbc->pcf, mbc_irq_handlers[i]); 459 460 sysfs_remove_group(&pdev->dev.kobj, &mbc_attr_group); 461 power_supply_unregister(mbc->usb); 462 power_supply_unregister(mbc->adapter); 463 power_supply_unregister(mbc->ac); 464 465 return 0; 466 } 467 468 static struct platform_driver pcf50633_mbc_driver = { 469 .driver = { 470 .name = "pcf50633-mbc", 471 }, 472 .probe = pcf50633_mbc_probe, 473 .remove = pcf50633_mbc_remove, 474 }; 475 476 module_platform_driver(pcf50633_mbc_driver); 477 478 MODULE_AUTHOR("Balaji Rao <balajirrao@openmoko.org>"); 479 MODULE_DESCRIPTION("PCF50633 mbc driver"); 480 MODULE_LICENSE("GPL"); 481 MODULE_ALIAS("platform:pcf50633-mbc"); 482