linux/drivers/power/supply/da9150-fg.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0-or-later
   2/*
   3 * DA9150 Fuel-Gauge Driver
   4 *
   5 * Copyright (c) 2015 Dialog Semiconductor
   6 *
   7 * Author: Adam Thomson <Adam.Thomson.Opensource@diasemi.com>
   8 */
   9
  10#include <linux/kernel.h>
  11#include <linux/module.h>
  12#include <linux/platform_device.h>
  13#include <linux/of.h>
  14#include <linux/of_platform.h>
  15#include <linux/slab.h>
  16#include <linux/interrupt.h>
  17#include <linux/delay.h>
  18#include <linux/power_supply.h>
  19#include <linux/list.h>
  20#include <asm/div64.h>
  21#include <linux/mfd/da9150/core.h>
  22#include <linux/mfd/da9150/registers.h>
  23
  24/* Core2Wire */
  25#define DA9150_QIF_READ         (0x0 << 7)
  26#define DA9150_QIF_WRITE        (0x1 << 7)
  27#define DA9150_QIF_CODE_MASK    0x7F
  28
  29#define DA9150_QIF_BYTE_SIZE    8
  30#define DA9150_QIF_BYTE_MASK    0xFF
  31#define DA9150_QIF_SHORT_SIZE   2
  32#define DA9150_QIF_LONG_SIZE    4
  33
  34/* QIF Codes */
  35#define DA9150_QIF_UAVG                 6
  36#define DA9150_QIF_UAVG_SIZE            DA9150_QIF_LONG_SIZE
  37#define DA9150_QIF_IAVG                 8
  38#define DA9150_QIF_IAVG_SIZE            DA9150_QIF_LONG_SIZE
  39#define DA9150_QIF_NTCAVG               12
  40#define DA9150_QIF_NTCAVG_SIZE          DA9150_QIF_LONG_SIZE
  41#define DA9150_QIF_SHUNT_VAL            36
  42#define DA9150_QIF_SHUNT_VAL_SIZE       DA9150_QIF_SHORT_SIZE
  43#define DA9150_QIF_SD_GAIN              38
  44#define DA9150_QIF_SD_GAIN_SIZE         DA9150_QIF_LONG_SIZE
  45#define DA9150_QIF_FCC_MAH              40
  46#define DA9150_QIF_FCC_MAH_SIZE         DA9150_QIF_SHORT_SIZE
  47#define DA9150_QIF_SOC_PCT              43
  48#define DA9150_QIF_SOC_PCT_SIZE         DA9150_QIF_SHORT_SIZE
  49#define DA9150_QIF_CHARGE_LIMIT         44
  50#define DA9150_QIF_CHARGE_LIMIT_SIZE    DA9150_QIF_SHORT_SIZE
  51#define DA9150_QIF_DISCHARGE_LIMIT      45
  52#define DA9150_QIF_DISCHARGE_LIMIT_SIZE DA9150_QIF_SHORT_SIZE
  53#define DA9150_QIF_FW_MAIN_VER          118
  54#define DA9150_QIF_FW_MAIN_VER_SIZE     DA9150_QIF_SHORT_SIZE
  55#define DA9150_QIF_E_FG_STATUS          126
  56#define DA9150_QIF_E_FG_STATUS_SIZE     DA9150_QIF_SHORT_SIZE
  57#define DA9150_QIF_SYNC                 127
  58#define DA9150_QIF_SYNC_SIZE            DA9150_QIF_SHORT_SIZE
  59#define DA9150_QIF_MAX_CODES            128
  60
  61/* QIF Sync Timeout */
  62#define DA9150_QIF_SYNC_TIMEOUT         1000
  63#define DA9150_QIF_SYNC_RETRIES         10
  64
  65/* QIF E_FG_STATUS */
  66#define DA9150_FG_IRQ_LOW_SOC_MASK      (1 << 0)
  67#define DA9150_FG_IRQ_HIGH_SOC_MASK     (1 << 1)
  68#define DA9150_FG_IRQ_SOC_MASK  \
  69        (DA9150_FG_IRQ_LOW_SOC_MASK | DA9150_FG_IRQ_HIGH_SOC_MASK)
  70
  71/* Private data */
  72struct da9150_fg {
  73        struct da9150 *da9150;
  74        struct device *dev;
  75
  76        struct mutex io_lock;
  77
  78        struct power_supply *battery;
  79        struct delayed_work work;
  80        u32 interval;
  81
  82        int warn_soc;
  83        int crit_soc;
  84        int soc;
  85};
  86
  87/* Battery Properties */
  88static u32 da9150_fg_read_attr(struct da9150_fg *fg, u8 code, u8 size)
  89
  90{
  91        u8 buf[DA9150_QIF_LONG_SIZE];
  92        u8 read_addr;
  93        u32 res = 0;
  94        int i;
  95
  96        /* Set QIF code (READ mode) */
  97        read_addr = (code & DA9150_QIF_CODE_MASK) | DA9150_QIF_READ;
  98
  99        da9150_read_qif(fg->da9150, read_addr, size, buf);
 100        for (i = 0; i < size; ++i)
 101                res |= (buf[i] << (i * DA9150_QIF_BYTE_SIZE));
 102
 103        return res;
 104}
 105
 106static void da9150_fg_write_attr(struct da9150_fg *fg, u8 code, u8 size,
 107                                 u32 val)
 108
 109{
 110        u8 buf[DA9150_QIF_LONG_SIZE];
 111        u8 write_addr;
 112        int i;
 113
 114        /* Set QIF code (WRITE mode) */
 115        write_addr = (code & DA9150_QIF_CODE_MASK) | DA9150_QIF_WRITE;
 116
 117        for (i = 0; i < size; ++i) {
 118                buf[i] = (val >> (i * DA9150_QIF_BYTE_SIZE)) &
 119                         DA9150_QIF_BYTE_MASK;
 120        }
 121        da9150_write_qif(fg->da9150, write_addr, size, buf);
 122}
 123
 124/* Trigger QIF Sync to update QIF readable data */
 125static void da9150_fg_read_sync_start(struct da9150_fg *fg)
 126{
 127        int i = 0;
 128        u32 res = 0;
 129
 130        mutex_lock(&fg->io_lock);
 131
 132        /* Check if QIF sync already requested, and write to sync if not */
 133        res = da9150_fg_read_attr(fg, DA9150_QIF_SYNC,
 134                                  DA9150_QIF_SYNC_SIZE);
 135        if (res > 0)
 136                da9150_fg_write_attr(fg, DA9150_QIF_SYNC,
 137                                     DA9150_QIF_SYNC_SIZE, 0);
 138
 139        /* Wait for sync to complete */
 140        res = 0;
 141        while ((res == 0) && (i++ < DA9150_QIF_SYNC_RETRIES)) {
 142                usleep_range(DA9150_QIF_SYNC_TIMEOUT,
 143                             DA9150_QIF_SYNC_TIMEOUT * 2);
 144                res = da9150_fg_read_attr(fg, DA9150_QIF_SYNC,
 145                                          DA9150_QIF_SYNC_SIZE);
 146        }
 147
 148        /* Check if sync completed */
 149        if (res == 0)
 150                dev_err(fg->dev, "Failed to perform QIF read sync!\n");
 151}
 152
 153/*
 154 * Should always be called after QIF sync read has been performed, and all
 155 * attributes required have been accessed.
 156 */
 157static inline void da9150_fg_read_sync_end(struct da9150_fg *fg)
 158{
 159        mutex_unlock(&fg->io_lock);
 160}
 161
 162/* Sync read of single QIF attribute */
 163static u32 da9150_fg_read_attr_sync(struct da9150_fg *fg, u8 code, u8 size)
 164{
 165        u32 val;
 166
 167        da9150_fg_read_sync_start(fg);
 168        val = da9150_fg_read_attr(fg, code, size);
 169        da9150_fg_read_sync_end(fg);
 170
 171        return val;
 172}
 173
 174/* Wait for QIF Sync, write QIF data and wait for ack */
 175static void da9150_fg_write_attr_sync(struct da9150_fg *fg, u8 code, u8 size,
 176                                      u32 val)
 177{
 178        int i = 0;
 179        u32 res = 0, sync_val;
 180
 181        mutex_lock(&fg->io_lock);
 182
 183        /* Check if QIF sync already requested */
 184        res = da9150_fg_read_attr(fg, DA9150_QIF_SYNC,
 185                                  DA9150_QIF_SYNC_SIZE);
 186
 187        /* Wait for an existing sync to complete */
 188        while ((res == 0) && (i++ < DA9150_QIF_SYNC_RETRIES)) {
 189                usleep_range(DA9150_QIF_SYNC_TIMEOUT,
 190                             DA9150_QIF_SYNC_TIMEOUT * 2);
 191                res = da9150_fg_read_attr(fg, DA9150_QIF_SYNC,
 192                                          DA9150_QIF_SYNC_SIZE);
 193        }
 194
 195        if (res == 0) {
 196                dev_err(fg->dev, "Timeout waiting for existing QIF sync!\n");
 197                mutex_unlock(&fg->io_lock);
 198                return;
 199        }
 200
 201        /* Write value for QIF code */
 202        da9150_fg_write_attr(fg, code, size, val);
 203
 204        /* Wait for write acknowledgment */
 205        i = 0;
 206        sync_val = res;
 207        while ((res == sync_val) && (i++ < DA9150_QIF_SYNC_RETRIES)) {
 208                usleep_range(DA9150_QIF_SYNC_TIMEOUT,
 209                             DA9150_QIF_SYNC_TIMEOUT * 2);
 210                res = da9150_fg_read_attr(fg, DA9150_QIF_SYNC,
 211                                          DA9150_QIF_SYNC_SIZE);
 212        }
 213
 214        mutex_unlock(&fg->io_lock);
 215
 216        /* Check write was actually successful */
 217        if (res != (sync_val + 1))
 218                dev_err(fg->dev, "Error performing QIF sync write for code %d\n",
 219                        code);
 220}
 221
 222/* Power Supply attributes */
 223static int da9150_fg_capacity(struct da9150_fg *fg,
 224                              union power_supply_propval *val)
 225{
 226        val->intval = da9150_fg_read_attr_sync(fg, DA9150_QIF_SOC_PCT,
 227                                               DA9150_QIF_SOC_PCT_SIZE);
 228
 229        if (val->intval > 100)
 230                val->intval = 100;
 231
 232        return 0;
 233}
 234
 235static int da9150_fg_current_avg(struct da9150_fg *fg,
 236                                 union power_supply_propval *val)
 237{
 238        u32 iavg, sd_gain, shunt_val;
 239        u64 div, res;
 240
 241        da9150_fg_read_sync_start(fg);
 242        iavg = da9150_fg_read_attr(fg, DA9150_QIF_IAVG,
 243                                   DA9150_QIF_IAVG_SIZE);
 244        shunt_val = da9150_fg_read_attr(fg, DA9150_QIF_SHUNT_VAL,
 245                                        DA9150_QIF_SHUNT_VAL_SIZE);
 246        sd_gain = da9150_fg_read_attr(fg, DA9150_QIF_SD_GAIN,
 247                                      DA9150_QIF_SD_GAIN_SIZE);
 248        da9150_fg_read_sync_end(fg);
 249
 250        div = (u64) (sd_gain * shunt_val * 65536ULL);
 251        do_div(div, 1000000);
 252        res = (u64) (iavg * 1000000ULL);
 253        do_div(res, div);
 254
 255        val->intval = (int) res;
 256
 257        return 0;
 258}
 259
 260static int da9150_fg_voltage_avg(struct da9150_fg *fg,
 261                                 union power_supply_propval *val)
 262{
 263        u64 res;
 264
 265        val->intval = da9150_fg_read_attr_sync(fg, DA9150_QIF_UAVG,
 266                                               DA9150_QIF_UAVG_SIZE);
 267
 268        res = (u64) (val->intval * 186ULL);
 269        do_div(res, 10000);
 270        val->intval = (int) res;
 271
 272        return 0;
 273}
 274
 275static int da9150_fg_charge_full(struct da9150_fg *fg,
 276                                 union power_supply_propval *val)
 277{
 278        val->intval = da9150_fg_read_attr_sync(fg, DA9150_QIF_FCC_MAH,
 279                                               DA9150_QIF_FCC_MAH_SIZE);
 280
 281        val->intval = val->intval * 1000;
 282
 283        return 0;
 284}
 285
 286/*
 287 * Temperature reading from device is only valid if battery/system provides
 288 * valid NTC to associated pin of DA9150 chip.
 289 */
 290static int da9150_fg_temp(struct da9150_fg *fg,
 291                          union power_supply_propval *val)
 292{
 293        val->intval = da9150_fg_read_attr_sync(fg, DA9150_QIF_NTCAVG,
 294                                               DA9150_QIF_NTCAVG_SIZE);
 295
 296        val->intval = (val->intval * 10) / 1048576;
 297
 298        return 0;
 299}
 300
 301static enum power_supply_property da9150_fg_props[] = {
 302        POWER_SUPPLY_PROP_CAPACITY,
 303        POWER_SUPPLY_PROP_CURRENT_AVG,
 304        POWER_SUPPLY_PROP_VOLTAGE_AVG,
 305        POWER_SUPPLY_PROP_CHARGE_FULL,
 306        POWER_SUPPLY_PROP_TEMP,
 307};
 308
 309static int da9150_fg_get_prop(struct power_supply *psy,
 310                              enum power_supply_property psp,
 311                              union power_supply_propval *val)
 312{
 313        struct da9150_fg *fg = dev_get_drvdata(psy->dev.parent);
 314        int ret;
 315
 316        switch (psp) {
 317        case POWER_SUPPLY_PROP_CAPACITY:
 318                ret = da9150_fg_capacity(fg, val);
 319                break;
 320        case POWER_SUPPLY_PROP_CURRENT_AVG:
 321                ret = da9150_fg_current_avg(fg, val);
 322                break;
 323        case POWER_SUPPLY_PROP_VOLTAGE_AVG:
 324                ret = da9150_fg_voltage_avg(fg, val);
 325                break;
 326        case POWER_SUPPLY_PROP_CHARGE_FULL:
 327                ret = da9150_fg_charge_full(fg, val);
 328                break;
 329        case POWER_SUPPLY_PROP_TEMP:
 330                ret = da9150_fg_temp(fg, val);
 331                break;
 332        default:
 333                ret = -EINVAL;
 334                break;
 335        }
 336
 337        return ret;
 338}
 339
 340/* Repeated SOC check */
 341static bool da9150_fg_soc_changed(struct da9150_fg *fg)
 342{
 343        union power_supply_propval val;
 344
 345        da9150_fg_capacity(fg, &val);
 346        if (val.intval != fg->soc) {
 347                fg->soc = val.intval;
 348                return true;
 349        }
 350
 351        return false;
 352}
 353
 354static void da9150_fg_work(struct work_struct *work)
 355{
 356        struct da9150_fg *fg = container_of(work, struct da9150_fg, work.work);
 357
 358        /* Report if SOC has changed */
 359        if (da9150_fg_soc_changed(fg))
 360                power_supply_changed(fg->battery);
 361
 362        schedule_delayed_work(&fg->work, msecs_to_jiffies(fg->interval));
 363}
 364
 365/* SOC level event configuration */
 366static void da9150_fg_soc_event_config(struct da9150_fg *fg)
 367{
 368        int soc;
 369
 370        soc = da9150_fg_read_attr_sync(fg, DA9150_QIF_SOC_PCT,
 371                                       DA9150_QIF_SOC_PCT_SIZE);
 372
 373        if (soc > fg->warn_soc) {
 374                /* If SOC > warn level, set discharge warn level event */
 375                da9150_fg_write_attr_sync(fg, DA9150_QIF_DISCHARGE_LIMIT,
 376                                          DA9150_QIF_DISCHARGE_LIMIT_SIZE,
 377                                          fg->warn_soc + 1);
 378        } else if ((soc <= fg->warn_soc) && (soc > fg->crit_soc)) {
 379                /*
 380                 * If SOC <= warn level, set discharge crit level event,
 381                 * and set charge warn level event.
 382                 */
 383                da9150_fg_write_attr_sync(fg, DA9150_QIF_DISCHARGE_LIMIT,
 384                                          DA9150_QIF_DISCHARGE_LIMIT_SIZE,
 385                                          fg->crit_soc + 1);
 386
 387                da9150_fg_write_attr_sync(fg, DA9150_QIF_CHARGE_LIMIT,
 388                                          DA9150_QIF_CHARGE_LIMIT_SIZE,
 389                                          fg->warn_soc);
 390        } else if (soc <= fg->crit_soc) {
 391                /* If SOC <= crit level, set charge crit level event */
 392                da9150_fg_write_attr_sync(fg, DA9150_QIF_CHARGE_LIMIT,
 393                                          DA9150_QIF_CHARGE_LIMIT_SIZE,
 394                                          fg->crit_soc);
 395        }
 396}
 397
 398static irqreturn_t da9150_fg_irq(int irq, void *data)
 399{
 400        struct da9150_fg *fg = data;
 401        u32 e_fg_status;
 402
 403        /* Read FG IRQ status info */
 404        e_fg_status = da9150_fg_read_attr(fg, DA9150_QIF_E_FG_STATUS,
 405                                          DA9150_QIF_E_FG_STATUS_SIZE);
 406
 407        /* Handle warning/critical threhold events */
 408        if (e_fg_status & DA9150_FG_IRQ_SOC_MASK)
 409                da9150_fg_soc_event_config(fg);
 410
 411        /* Clear any FG IRQs */
 412        da9150_fg_write_attr(fg, DA9150_QIF_E_FG_STATUS,
 413                             DA9150_QIF_E_FG_STATUS_SIZE, e_fg_status);
 414
 415        return IRQ_HANDLED;
 416}
 417
 418static struct da9150_fg_pdata *da9150_fg_dt_pdata(struct device *dev)
 419{
 420        struct device_node *fg_node = dev->of_node;
 421        struct da9150_fg_pdata *pdata;
 422
 423        pdata = devm_kzalloc(dev, sizeof(struct da9150_fg_pdata), GFP_KERNEL);
 424        if (!pdata)
 425                return NULL;
 426
 427        of_property_read_u32(fg_node, "dlg,update-interval",
 428                             &pdata->update_interval);
 429        of_property_read_u8(fg_node, "dlg,warn-soc-level",
 430                            &pdata->warn_soc_lvl);
 431        of_property_read_u8(fg_node, "dlg,crit-soc-level",
 432                            &pdata->crit_soc_lvl);
 433
 434        return pdata;
 435}
 436
 437static const struct power_supply_desc fg_desc = {
 438        .name           = "da9150-fg",
 439        .type           = POWER_SUPPLY_TYPE_BATTERY,
 440        .properties     = da9150_fg_props,
 441        .num_properties = ARRAY_SIZE(da9150_fg_props),
 442        .get_property   = da9150_fg_get_prop,
 443};
 444
 445static int da9150_fg_probe(struct platform_device *pdev)
 446{
 447        struct device *dev = &pdev->dev;
 448        struct da9150 *da9150 = dev_get_drvdata(dev->parent);
 449        struct da9150_fg_pdata *fg_pdata = dev_get_platdata(dev);
 450        struct da9150_fg *fg;
 451        int ver, irq, ret = 0;
 452
 453        fg = devm_kzalloc(dev, sizeof(*fg), GFP_KERNEL);
 454        if (fg == NULL)
 455                return -ENOMEM;
 456
 457        platform_set_drvdata(pdev, fg);
 458        fg->da9150 = da9150;
 459        fg->dev = dev;
 460
 461        mutex_init(&fg->io_lock);
 462
 463        /* Enable QIF */
 464        da9150_set_bits(da9150, DA9150_CORE2WIRE_CTRL_A, DA9150_FG_QIF_EN_MASK,
 465                        DA9150_FG_QIF_EN_MASK);
 466
 467        fg->battery = devm_power_supply_register(dev, &fg_desc, NULL);
 468        if (IS_ERR(fg->battery)) {
 469                ret = PTR_ERR(fg->battery);
 470                return ret;
 471        }
 472
 473        ver = da9150_fg_read_attr(fg, DA9150_QIF_FW_MAIN_VER,
 474                                  DA9150_QIF_FW_MAIN_VER_SIZE);
 475        dev_info(dev, "Version: 0x%x\n", ver);
 476
 477        /* Handle DT data if provided */
 478        if (dev->of_node) {
 479                fg_pdata = da9150_fg_dt_pdata(dev);
 480                dev->platform_data = fg_pdata;
 481        }
 482
 483        /* Handle any pdata provided */
 484        if (fg_pdata) {
 485                fg->interval = fg_pdata->update_interval;
 486
 487                if (fg_pdata->warn_soc_lvl > 100)
 488                        dev_warn(dev, "Invalid SOC warning level provided, Ignoring");
 489                else
 490                        fg->warn_soc = fg_pdata->warn_soc_lvl;
 491
 492                if ((fg_pdata->crit_soc_lvl > 100) ||
 493                    (fg_pdata->crit_soc_lvl >= fg_pdata->warn_soc_lvl))
 494                        dev_warn(dev, "Invalid SOC critical level provided, Ignoring");
 495                else
 496                        fg->crit_soc = fg_pdata->crit_soc_lvl;
 497
 498
 499        }
 500
 501        /* Configure initial SOC level events */
 502        da9150_fg_soc_event_config(fg);
 503
 504        /*
 505         * If an interval period has been provided then setup repeating
 506         * work for reporting data updates.
 507         */
 508        if (fg->interval) {
 509                INIT_DELAYED_WORK(&fg->work, da9150_fg_work);
 510                schedule_delayed_work(&fg->work,
 511                                      msecs_to_jiffies(fg->interval));
 512        }
 513
 514        /* Register IRQ */
 515        irq = platform_get_irq_byname(pdev, "FG");
 516        if (irq < 0) {
 517                dev_err(dev, "Failed to get IRQ FG: %d\n", irq);
 518                ret = irq;
 519                goto irq_fail;
 520        }
 521
 522        ret = devm_request_threaded_irq(dev, irq, NULL, da9150_fg_irq,
 523                                        IRQF_ONESHOT, "FG", fg);
 524        if (ret) {
 525                dev_err(dev, "Failed to request IRQ %d: %d\n", irq, ret);
 526                goto irq_fail;
 527        }
 528
 529        return 0;
 530
 531irq_fail:
 532        if (fg->interval)
 533                cancel_delayed_work(&fg->work);
 534
 535        return ret;
 536}
 537
 538static int da9150_fg_remove(struct platform_device *pdev)
 539{
 540        struct da9150_fg *fg = platform_get_drvdata(pdev);
 541
 542        if (fg->interval)
 543                cancel_delayed_work(&fg->work);
 544
 545        return 0;
 546}
 547
 548static int da9150_fg_resume(struct platform_device *pdev)
 549{
 550        struct da9150_fg *fg = platform_get_drvdata(pdev);
 551
 552        /*
 553         * Trigger SOC check to happen now so as to indicate any value change
 554         * since last check before suspend.
 555         */
 556        if (fg->interval)
 557                flush_delayed_work(&fg->work);
 558
 559        return 0;
 560}
 561
 562static struct platform_driver da9150_fg_driver = {
 563        .driver = {
 564                .name = "da9150-fuel-gauge",
 565        },
 566        .probe = da9150_fg_probe,
 567        .remove = da9150_fg_remove,
 568        .resume = da9150_fg_resume,
 569};
 570
 571module_platform_driver(da9150_fg_driver);
 572
 573MODULE_DESCRIPTION("Fuel-Gauge Driver for DA9150");
 574MODULE_AUTHOR("Adam Thomson <Adam.Thomson.Opensource@diasemi.com>");
 575MODULE_LICENSE("GPL");
 576