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