linux/drivers/power/twl4030_charger.c
<<
>>
Prefs
   1/*
   2 * TWL4030/TPS65950 BCI (Battery Charger Interface) driver
   3 *
   4 * Copyright (C) 2010 Gra\xC5\xBEvydas Ignotas <notasas@gmail.com>
   5 *
   6 * based on twl4030_bci_battery.c by TI
   7 * Copyright (C) 2008 Texas Instruments, Inc.
   8 *
   9 * This program is free software; you can redistribute it and/or modify
  10 * it under the terms of the GNU General Public License as published by
  11 * the Free Software Foundation; either version 2 of the License, or
  12 * (at your option) any later version.
  13 */
  14
  15#include <linux/init.h>
  16#include <linux/module.h>
  17#include <linux/slab.h>
  18#include <linux/platform_device.h>
  19#include <linux/interrupt.h>
  20#include <linux/i2c/twl.h>
  21#include <linux/power_supply.h>
  22#include <linux/notifier.h>
  23#include <linux/usb/otg.h>
  24
  25#define TWL4030_BCIMSTATEC      0x02
  26#define TWL4030_BCIICHG         0x08
  27#define TWL4030_BCIVAC          0x0a
  28#define TWL4030_BCIVBUS         0x0c
  29#define TWL4030_BCIMFSTS4       0x10
  30#define TWL4030_BCICTL1         0x23
  31
  32#define TWL4030_BCIAUTOWEN      BIT(5)
  33#define TWL4030_CONFIG_DONE     BIT(4)
  34#define TWL4030_BCIAUTOUSB      BIT(1)
  35#define TWL4030_BCIAUTOAC       BIT(0)
  36#define TWL4030_CGAIN           BIT(5)
  37#define TWL4030_USBFASTMCHG     BIT(2)
  38#define TWL4030_STS_VBUS        BIT(7)
  39#define TWL4030_STS_USB_ID      BIT(2)
  40
  41/* BCI interrupts */
  42#define TWL4030_WOVF            BIT(0) /* Watchdog overflow */
  43#define TWL4030_TMOVF           BIT(1) /* Timer overflow */
  44#define TWL4030_ICHGHIGH        BIT(2) /* Battery charge current high */
  45#define TWL4030_ICHGLOW         BIT(3) /* Battery cc. low / FSM state change */
  46#define TWL4030_ICHGEOC         BIT(4) /* Battery current end-of-charge */
  47#define TWL4030_TBATOR2         BIT(5) /* Battery temperature out of range 2 */
  48#define TWL4030_TBATOR1         BIT(6) /* Battery temperature out of range 1 */
  49#define TWL4030_BATSTS          BIT(7) /* Battery status */
  50
  51#define TWL4030_VBATLVL         BIT(0) /* VBAT level */
  52#define TWL4030_VBATOV          BIT(1) /* VBAT overvoltage */
  53#define TWL4030_VBUSOV          BIT(2) /* VBUS overvoltage */
  54#define TWL4030_ACCHGOV         BIT(3) /* Ac charger overvoltage */
  55
  56#define TWL4030_MSTATEC_USB             BIT(4)
  57#define TWL4030_MSTATEC_AC              BIT(5)
  58#define TWL4030_MSTATEC_MASK            0x0f
  59#define TWL4030_MSTATEC_QUICK1          0x02
  60#define TWL4030_MSTATEC_QUICK7          0x07
  61#define TWL4030_MSTATEC_COMPLETE1       0x0b
  62#define TWL4030_MSTATEC_COMPLETE4       0x0e
  63
  64static bool allow_usb;
  65module_param(allow_usb, bool, 1);
  66MODULE_PARM_DESC(allow_usb, "Allow USB charge drawing default current");
  67
  68struct twl4030_bci {
  69        struct device           *dev;
  70        struct power_supply     ac;
  71        struct power_supply     usb;
  72        struct otg_transceiver  *transceiver;
  73        struct notifier_block   otg_nb;
  74        int                     irq_chg;
  75        int                     irq_bci;
  76};
  77
  78/*
  79 * clear and set bits on an given register on a given module
  80 */
  81static int twl4030_clear_set(u8 mod_no, u8 clear, u8 set, u8 reg)
  82{
  83        u8 val = 0;
  84        int ret;
  85
  86        ret = twl_i2c_read_u8(mod_no, &val, reg);
  87        if (ret)
  88                return ret;
  89
  90        val &= ~clear;
  91        val |= set;
  92
  93        return twl_i2c_write_u8(mod_no, val, reg);
  94}
  95
  96static int twl4030_bci_read(u8 reg, u8 *val)
  97{
  98        return twl_i2c_read_u8(TWL4030_MODULE_MAIN_CHARGE, val, reg);
  99}
 100
 101static int twl4030_clear_set_boot_bci(u8 clear, u8 set)
 102{
 103        return twl4030_clear_set(TWL4030_MODULE_PM_MASTER, 0,
 104                        TWL4030_CONFIG_DONE | TWL4030_BCIAUTOWEN | set,
 105                        TWL4030_PM_MASTER_BOOT_BCI);
 106}
 107
 108static int twl4030bci_read_adc_val(u8 reg)
 109{
 110        int ret, temp;
 111        u8 val;
 112
 113        /* read MSB */
 114        ret = twl4030_bci_read(reg + 1, &val);
 115        if (ret)
 116                return ret;
 117
 118        temp = (int)(val & 0x03) << 8;
 119
 120        /* read LSB */
 121        ret = twl4030_bci_read(reg, &val);
 122        if (ret)
 123                return ret;
 124
 125        return temp | val;
 126}
 127
 128/*
 129 * Check if VBUS power is present
 130 */
 131static int twl4030_bci_have_vbus(struct twl4030_bci *bci)
 132{
 133        int ret;
 134        u8 hwsts;
 135
 136        ret = twl_i2c_read_u8(TWL4030_MODULE_PM_MASTER, &hwsts,
 137                              TWL4030_PM_MASTER_STS_HW_CONDITIONS);
 138        if (ret < 0)
 139                return 0;
 140
 141        dev_dbg(bci->dev, "check_vbus: HW_CONDITIONS %02x\n", hwsts);
 142
 143        /* in case we also have STS_USB_ID, VBUS is driven by TWL itself */
 144        if ((hwsts & TWL4030_STS_VBUS) && !(hwsts & TWL4030_STS_USB_ID))
 145                return 1;
 146
 147        return 0;
 148}
 149
 150/*
 151 * Enable/Disable USB Charge funtionality.
 152 */
 153static int twl4030_charger_enable_usb(struct twl4030_bci *bci, bool enable)
 154{
 155        int ret;
 156
 157        if (enable) {
 158                /* Check for USB charger conneted */
 159                if (!twl4030_bci_have_vbus(bci))
 160                        return -ENODEV;
 161
 162                /*
 163                 * Until we can find out what current the device can provide,
 164                 * require a module param to enable USB charging.
 165                 */
 166                if (!allow_usb) {
 167                        dev_warn(bci->dev, "USB charging is disabled.\n");
 168                        return -EACCES;
 169                }
 170
 171                /* forcing the field BCIAUTOUSB (BOOT_BCI[1]) to 1 */
 172                ret = twl4030_clear_set_boot_bci(0, TWL4030_BCIAUTOUSB);
 173                if (ret < 0)
 174                        return ret;
 175
 176                /* forcing USBFASTMCHG(BCIMFSTS4[2]) to 1 */
 177                ret = twl4030_clear_set(TWL4030_MODULE_MAIN_CHARGE, 0,
 178                        TWL4030_USBFASTMCHG, TWL4030_BCIMFSTS4);
 179        } else {
 180                ret = twl4030_clear_set_boot_bci(TWL4030_BCIAUTOUSB, 0);
 181        }
 182
 183        return ret;
 184}
 185
 186/*
 187 * Enable/Disable AC Charge funtionality.
 188 */
 189static int twl4030_charger_enable_ac(bool enable)
 190{
 191        int ret;
 192
 193        if (enable)
 194                ret = twl4030_clear_set_boot_bci(0, TWL4030_BCIAUTOAC);
 195        else
 196                ret = twl4030_clear_set_boot_bci(TWL4030_BCIAUTOAC, 0);
 197
 198        return ret;
 199}
 200
 201/*
 202 * TWL4030 CHG_PRES (AC charger presence) events
 203 */
 204static irqreturn_t twl4030_charger_interrupt(int irq, void *arg)
 205{
 206        struct twl4030_bci *bci = arg;
 207
 208        dev_dbg(bci->dev, "CHG_PRES irq\n");
 209        power_supply_changed(&bci->ac);
 210        power_supply_changed(&bci->usb);
 211
 212        return IRQ_HANDLED;
 213}
 214
 215/*
 216 * TWL4030 BCI monitoring events
 217 */
 218static irqreturn_t twl4030_bci_interrupt(int irq, void *arg)
 219{
 220        struct twl4030_bci *bci = arg;
 221        u8 irqs1, irqs2;
 222        int ret;
 223
 224        ret = twl_i2c_read_u8(TWL4030_MODULE_INTERRUPTS, &irqs1,
 225                              TWL4030_INTERRUPTS_BCIISR1A);
 226        if (ret < 0)
 227                return IRQ_HANDLED;
 228
 229        ret = twl_i2c_read_u8(TWL4030_MODULE_INTERRUPTS, &irqs2,
 230                              TWL4030_INTERRUPTS_BCIISR2A);
 231        if (ret < 0)
 232                return IRQ_HANDLED;
 233
 234        dev_dbg(bci->dev, "BCI irq %02x %02x\n", irqs2, irqs1);
 235
 236        if (irqs1 & (TWL4030_ICHGLOW | TWL4030_ICHGEOC)) {
 237                /* charger state change, inform the core */
 238                power_supply_changed(&bci->ac);
 239                power_supply_changed(&bci->usb);
 240        }
 241
 242        /* various monitoring events, for now we just log them here */
 243        if (irqs1 & (TWL4030_TBATOR2 | TWL4030_TBATOR1))
 244                dev_warn(bci->dev, "battery temperature out of range\n");
 245
 246        if (irqs1 & TWL4030_BATSTS)
 247                dev_crit(bci->dev, "battery disconnected\n");
 248
 249        if (irqs2 & TWL4030_VBATOV)
 250                dev_crit(bci->dev, "VBAT overvoltage\n");
 251
 252        if (irqs2 & TWL4030_VBUSOV)
 253                dev_crit(bci->dev, "VBUS overvoltage\n");
 254
 255        if (irqs2 & TWL4030_ACCHGOV)
 256                dev_crit(bci->dev, "Ac charger overvoltage\n");
 257
 258        return IRQ_HANDLED;
 259}
 260
 261static int twl4030_bci_usb_ncb(struct notifier_block *nb, unsigned long val,
 262                               void *priv)
 263{
 264        struct twl4030_bci *bci = container_of(nb, struct twl4030_bci, otg_nb);
 265
 266        dev_dbg(bci->dev, "OTG notify %lu\n", val);
 267
 268        switch (val) {
 269        case USB_EVENT_VBUS:
 270        case USB_EVENT_CHARGER:
 271                twl4030_charger_enable_usb(bci, true);
 272                break;
 273        case USB_EVENT_NONE:
 274                twl4030_charger_enable_usb(bci, false);
 275                break;
 276        }
 277
 278        return NOTIFY_OK;
 279}
 280
 281/*
 282 * TI provided formulas:
 283 * CGAIN == 0: ICHG = (BCIICHG * 1.7) / (2^10 - 1) - 0.85
 284 * CGAIN == 1: ICHG = (BCIICHG * 3.4) / (2^10 - 1) - 1.7
 285 * Here we use integer approximation of:
 286 * CGAIN == 0: val * 1.6618 - 0.85
 287 * CGAIN == 1: (val * 1.6618 - 0.85) * 2
 288 */
 289static int twl4030_charger_get_current(void)
 290{
 291        int curr;
 292        int ret;
 293        u8 bcictl1;
 294
 295        curr = twl4030bci_read_adc_val(TWL4030_BCIICHG);
 296        if (curr < 0)
 297                return curr;
 298
 299        ret = twl4030_bci_read(TWL4030_BCICTL1, &bcictl1);
 300        if (ret)
 301                return ret;
 302
 303        ret = (curr * 16618 - 850 * 10000) / 10;
 304        if (bcictl1 & TWL4030_CGAIN)
 305                ret *= 2;
 306
 307        return ret;
 308}
 309
 310/*
 311 * Returns the main charge FSM state
 312 * Or < 0 on failure.
 313 */
 314static int twl4030bci_state(struct twl4030_bci *bci)
 315{
 316        int ret;
 317        u8 state;
 318
 319        ret = twl4030_bci_read(TWL4030_BCIMSTATEC, &state);
 320        if (ret) {
 321                pr_err("twl4030_bci: error reading BCIMSTATEC\n");
 322                return ret;
 323        }
 324
 325        dev_dbg(bci->dev, "state: %02x\n", state);
 326
 327        return state;
 328}
 329
 330static int twl4030_bci_state_to_status(int state)
 331{
 332        state &= TWL4030_MSTATEC_MASK;
 333        if (TWL4030_MSTATEC_QUICK1 <= state && state <= TWL4030_MSTATEC_QUICK7)
 334                return POWER_SUPPLY_STATUS_CHARGING;
 335        else if (TWL4030_MSTATEC_COMPLETE1 <= state &&
 336                                        state <= TWL4030_MSTATEC_COMPLETE4)
 337                return POWER_SUPPLY_STATUS_FULL;
 338        else
 339                return POWER_SUPPLY_STATUS_NOT_CHARGING;
 340}
 341
 342static int twl4030_bci_get_property(struct power_supply *psy,
 343                                    enum power_supply_property psp,
 344                                    union power_supply_propval *val)
 345{
 346        struct twl4030_bci *bci = dev_get_drvdata(psy->dev->parent);
 347        int is_charging;
 348        int state;
 349        int ret;
 350
 351        state = twl4030bci_state(bci);
 352        if (state < 0)
 353                return state;
 354
 355        if (psy->type == POWER_SUPPLY_TYPE_USB)
 356                is_charging = state & TWL4030_MSTATEC_USB;
 357        else
 358                is_charging = state & TWL4030_MSTATEC_AC;
 359
 360        switch (psp) {
 361        case POWER_SUPPLY_PROP_STATUS:
 362                if (is_charging)
 363                        val->intval = twl4030_bci_state_to_status(state);
 364                else
 365                        val->intval = POWER_SUPPLY_STATUS_NOT_CHARGING;
 366                break;
 367        case POWER_SUPPLY_PROP_VOLTAGE_NOW:
 368                /* charging must be active for meaningful result */
 369                if (!is_charging)
 370                        return -ENODATA;
 371                if (psy->type == POWER_SUPPLY_TYPE_USB) {
 372                        ret = twl4030bci_read_adc_val(TWL4030_BCIVBUS);
 373                        if (ret < 0)
 374                                return ret;
 375                        /* BCIVBUS uses ADCIN8, 7/1023 V/step */
 376                        val->intval = ret * 6843;
 377                } else {
 378                        ret = twl4030bci_read_adc_val(TWL4030_BCIVAC);
 379                        if (ret < 0)
 380                                return ret;
 381                        /* BCIVAC uses ADCIN11, 10/1023 V/step */
 382                        val->intval = ret * 9775;
 383                }
 384                break;
 385        case POWER_SUPPLY_PROP_CURRENT_NOW:
 386                if (!is_charging)
 387                        return -ENODATA;
 388                /* current measurement is shared between AC and USB */
 389                ret = twl4030_charger_get_current();
 390                if (ret < 0)
 391                        return ret;
 392                val->intval = ret;
 393                break;
 394        case POWER_SUPPLY_PROP_ONLINE:
 395                val->intval = is_charging &&
 396                        twl4030_bci_state_to_status(state) !=
 397                                POWER_SUPPLY_STATUS_NOT_CHARGING;
 398                break;
 399        default:
 400                return -EINVAL;
 401        }
 402
 403        return 0;
 404}
 405
 406static enum power_supply_property twl4030_charger_props[] = {
 407        POWER_SUPPLY_PROP_STATUS,
 408        POWER_SUPPLY_PROP_ONLINE,
 409        POWER_SUPPLY_PROP_VOLTAGE_NOW,
 410        POWER_SUPPLY_PROP_CURRENT_NOW,
 411};
 412
 413static int __init twl4030_bci_probe(struct platform_device *pdev)
 414{
 415        struct twl4030_bci *bci;
 416        int ret;
 417        int reg;
 418
 419        bci = kzalloc(sizeof(*bci), GFP_KERNEL);
 420        if (bci == NULL)
 421                return -ENOMEM;
 422
 423        bci->dev = &pdev->dev;
 424        bci->irq_chg = platform_get_irq(pdev, 0);
 425        bci->irq_bci = platform_get_irq(pdev, 1);
 426
 427        platform_set_drvdata(pdev, bci);
 428
 429        bci->ac.name = "twl4030_ac";
 430        bci->ac.type = POWER_SUPPLY_TYPE_MAINS;
 431        bci->ac.properties = twl4030_charger_props;
 432        bci->ac.num_properties = ARRAY_SIZE(twl4030_charger_props);
 433        bci->ac.get_property = twl4030_bci_get_property;
 434
 435        ret = power_supply_register(&pdev->dev, &bci->ac);
 436        if (ret) {
 437                dev_err(&pdev->dev, "failed to register ac: %d\n", ret);
 438                goto fail_register_ac;
 439        }
 440
 441        bci->usb.name = "twl4030_usb";
 442        bci->usb.type = POWER_SUPPLY_TYPE_USB;
 443        bci->usb.properties = twl4030_charger_props;
 444        bci->usb.num_properties = ARRAY_SIZE(twl4030_charger_props);
 445        bci->usb.get_property = twl4030_bci_get_property;
 446
 447        ret = power_supply_register(&pdev->dev, &bci->usb);
 448        if (ret) {
 449                dev_err(&pdev->dev, "failed to register usb: %d\n", ret);
 450                goto fail_register_usb;
 451        }
 452
 453        ret = request_threaded_irq(bci->irq_chg, NULL,
 454                        twl4030_charger_interrupt, 0, pdev->name, bci);
 455        if (ret < 0) {
 456                dev_err(&pdev->dev, "could not request irq %d, status %d\n",
 457                        bci->irq_chg, ret);
 458                goto fail_chg_irq;
 459        }
 460
 461        ret = request_threaded_irq(bci->irq_bci, NULL,
 462                        twl4030_bci_interrupt, 0, pdev->name, bci);
 463        if (ret < 0) {
 464                dev_err(&pdev->dev, "could not request irq %d, status %d\n",
 465                        bci->irq_bci, ret);
 466                goto fail_bci_irq;
 467        }
 468
 469        bci->transceiver = otg_get_transceiver();
 470        if (bci->transceiver != NULL) {
 471                bci->otg_nb.notifier_call = twl4030_bci_usb_ncb;
 472                otg_register_notifier(bci->transceiver, &bci->otg_nb);
 473        }
 474
 475        /* Enable interrupts now. */
 476        reg = ~(TWL4030_ICHGLOW | TWL4030_ICHGEOC | TWL4030_TBATOR2 |
 477                TWL4030_TBATOR1 | TWL4030_BATSTS);
 478        ret = twl_i2c_write_u8(TWL4030_MODULE_INTERRUPTS, reg,
 479                               TWL4030_INTERRUPTS_BCIIMR1A);
 480        if (ret < 0) {
 481                dev_err(&pdev->dev, "failed to unmask interrupts: %d\n", ret);
 482                goto fail_unmask_interrupts;
 483        }
 484
 485        reg = ~(TWL4030_VBATOV | TWL4030_VBUSOV | TWL4030_ACCHGOV);
 486        ret = twl_i2c_write_u8(TWL4030_MODULE_INTERRUPTS, reg,
 487                               TWL4030_INTERRUPTS_BCIIMR2A);
 488        if (ret < 0)
 489                dev_warn(&pdev->dev, "failed to unmask interrupts: %d\n", ret);
 490
 491        twl4030_charger_enable_ac(true);
 492        twl4030_charger_enable_usb(bci, true);
 493
 494        return 0;
 495
 496fail_unmask_interrupts:
 497        if (bci->transceiver != NULL) {
 498                otg_unregister_notifier(bci->transceiver, &bci->otg_nb);
 499                otg_put_transceiver(bci->transceiver);
 500        }
 501        free_irq(bci->irq_bci, bci);
 502fail_bci_irq:
 503        free_irq(bci->irq_chg, bci);
 504fail_chg_irq:
 505        power_supply_unregister(&bci->usb);
 506fail_register_usb:
 507        power_supply_unregister(&bci->ac);
 508fail_register_ac:
 509        platform_set_drvdata(pdev, NULL);
 510        kfree(bci);
 511
 512        return ret;
 513}
 514
 515static int __exit twl4030_bci_remove(struct platform_device *pdev)
 516{
 517        struct twl4030_bci *bci = platform_get_drvdata(pdev);
 518
 519        twl4030_charger_enable_ac(false);
 520        twl4030_charger_enable_usb(bci, false);
 521
 522        /* mask interrupts */
 523        twl_i2c_write_u8(TWL4030_MODULE_INTERRUPTS, 0xff,
 524                         TWL4030_INTERRUPTS_BCIIMR1A);
 525        twl_i2c_write_u8(TWL4030_MODULE_INTERRUPTS, 0xff,
 526                         TWL4030_INTERRUPTS_BCIIMR2A);
 527
 528        if (bci->transceiver != NULL) {
 529                otg_unregister_notifier(bci->transceiver, &bci->otg_nb);
 530                otg_put_transceiver(bci->transceiver);
 531        }
 532        free_irq(bci->irq_bci, bci);
 533        free_irq(bci->irq_chg, bci);
 534        power_supply_unregister(&bci->usb);
 535        power_supply_unregister(&bci->ac);
 536        platform_set_drvdata(pdev, NULL);
 537        kfree(bci);
 538
 539        return 0;
 540}
 541
 542static struct platform_driver twl4030_bci_driver = {
 543        .driver = {
 544                .name   = "twl4030_bci",
 545                .owner  = THIS_MODULE,
 546        },
 547        .remove = __exit_p(twl4030_bci_remove),
 548};
 549
 550static int __init twl4030_bci_init(void)
 551{
 552        return platform_driver_probe(&twl4030_bci_driver, twl4030_bci_probe);
 553}
 554module_init(twl4030_bci_init);
 555
 556static void __exit twl4030_bci_exit(void)
 557{
 558        platform_driver_unregister(&twl4030_bci_driver);
 559}
 560module_exit(twl4030_bci_exit);
 561
 562MODULE_AUTHOR("Gra\xC5\xBEydas Ignotas");
 563MODULE_DESCRIPTION("TWL4030 Battery Charger Interface driver");
 564MODULE_LICENSE("GPL");
 565MODULE_ALIAS("platform:twl4030_bci");
 566