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