linux/drivers/power/supply/ab8500_btemp.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0-only
   2/*
   3 * Copyright (C) ST-Ericsson SA 2012
   4 *
   5 * Battery temperature driver for AB8500
   6 *
   7 * Author:
   8 *      Johan Palsson <johan.palsson@stericsson.com>
   9 *      Karl Komierowski <karl.komierowski@stericsson.com>
  10 *      Arun R Murthy <arun.murthy@stericsson.com>
  11 */
  12
  13#include <linux/init.h>
  14#include <linux/module.h>
  15#include <linux/device.h>
  16#include <linux/component.h>
  17#include <linux/interrupt.h>
  18#include <linux/delay.h>
  19#include <linux/slab.h>
  20#include <linux/platform_device.h>
  21#include <linux/power_supply.h>
  22#include <linux/completion.h>
  23#include <linux/workqueue.h>
  24#include <linux/jiffies.h>
  25#include <linux/of.h>
  26#include <linux/mfd/core.h>
  27#include <linux/mfd/abx500.h>
  28#include <linux/mfd/abx500/ab8500.h>
  29#include <linux/iio/consumer.h>
  30#include <linux/fixp-arith.h>
  31
  32#include "ab8500-bm.h"
  33
  34#define VTVOUT_V                        1800
  35
  36#define BTEMP_THERMAL_LOW_LIMIT         -10
  37#define BTEMP_THERMAL_MED_LIMIT         0
  38#define BTEMP_THERMAL_HIGH_LIMIT_52     52
  39#define BTEMP_THERMAL_HIGH_LIMIT_57     57
  40#define BTEMP_THERMAL_HIGH_LIMIT_62     62
  41
  42#define BTEMP_BATCTRL_CURR_SRC_7UA      7
  43#define BTEMP_BATCTRL_CURR_SRC_20UA     20
  44
  45#define BTEMP_BATCTRL_CURR_SRC_16UA     16
  46#define BTEMP_BATCTRL_CURR_SRC_18UA     18
  47
  48#define BTEMP_BATCTRL_CURR_SRC_60UA     60
  49#define BTEMP_BATCTRL_CURR_SRC_120UA    120
  50
  51/**
  52 * struct ab8500_btemp_interrupts - ab8500 interrupts
  53 * @name:       name of the interrupt
  54 * @isr         function pointer to the isr
  55 */
  56struct ab8500_btemp_interrupts {
  57        char *name;
  58        irqreturn_t (*isr)(int irq, void *data);
  59};
  60
  61struct ab8500_btemp_events {
  62        bool batt_rem;
  63        bool btemp_high;
  64        bool btemp_medhigh;
  65        bool btemp_lowmed;
  66        bool btemp_low;
  67        bool ac_conn;
  68        bool usb_conn;
  69};
  70
  71struct ab8500_btemp_ranges {
  72        int btemp_high_limit;
  73        int btemp_med_limit;
  74        int btemp_low_limit;
  75};
  76
  77/**
  78 * struct ab8500_btemp - ab8500 BTEMP device information
  79 * @dev:                Pointer to the structure device
  80 * @node:               List of AB8500 BTEMPs, hence prepared for reentrance
  81 * @curr_source:        What current source we use, in uA
  82 * @bat_temp:           Dispatched battery temperature in degree Celsius
  83 * @prev_bat_temp       Last measured battery temperature in degree Celsius
  84 * @parent:             Pointer to the struct ab8500
  85 * @adc_btemp_ball:     ADC channel for the battery ball temperature
  86 * @adc_bat_ctrl:       ADC channel for the battery control
  87 * @fg:                 Pointer to the struct fg
  88 * @bm:                 Platform specific battery management information
  89 * @btemp_psy:          Structure for BTEMP specific battery properties
  90 * @events:             Structure for information about events triggered
  91 * @btemp_ranges:       Battery temperature range structure
  92 * @btemp_wq:           Work queue for measuring the temperature periodically
  93 * @btemp_periodic_work:        Work for measuring the temperature periodically
  94 * @initialized:        True if battery id read.
  95 */
  96struct ab8500_btemp {
  97        struct device *dev;
  98        struct list_head node;
  99        int curr_source;
 100        int bat_temp;
 101        int prev_bat_temp;
 102        struct ab8500 *parent;
 103        struct iio_channel *btemp_ball;
 104        struct iio_channel *bat_ctrl;
 105        struct ab8500_fg *fg;
 106        struct ab8500_bm_data *bm;
 107        struct power_supply *btemp_psy;
 108        struct ab8500_btemp_events events;
 109        struct ab8500_btemp_ranges btemp_ranges;
 110        struct workqueue_struct *btemp_wq;
 111        struct delayed_work btemp_periodic_work;
 112        bool initialized;
 113};
 114
 115/* BTEMP power supply properties */
 116static enum power_supply_property ab8500_btemp_props[] = {
 117        POWER_SUPPLY_PROP_PRESENT,
 118        POWER_SUPPLY_PROP_ONLINE,
 119        POWER_SUPPLY_PROP_TECHNOLOGY,
 120        POWER_SUPPLY_PROP_TEMP,
 121};
 122
 123static LIST_HEAD(ab8500_btemp_list);
 124
 125/**
 126 * ab8500_btemp_batctrl_volt_to_res() - convert batctrl voltage to resistance
 127 * @di:         pointer to the ab8500_btemp structure
 128 * @v_batctrl:  measured batctrl voltage
 129 * @inst_curr:  measured instant current
 130 *
 131 * This function returns the battery resistance that is
 132 * derived from the BATCTRL voltage.
 133 * Returns value in Ohms.
 134 */
 135static int ab8500_btemp_batctrl_volt_to_res(struct ab8500_btemp *di,
 136        int v_batctrl, int inst_curr)
 137{
 138        int rbs;
 139
 140        if (is_ab8500_1p1_or_earlier(di->parent)) {
 141                /*
 142                 * For ABB cut1.0 and 1.1 BAT_CTRL is internally
 143                 * connected to 1.8V through a 450k resistor
 144                 */
 145                return (450000 * (v_batctrl)) / (1800 - v_batctrl);
 146        }
 147
 148        if (di->bm->adc_therm == AB8500_ADC_THERM_BATCTRL) {
 149                /*
 150                 * If the battery has internal NTC, we use the current
 151                 * source to calculate the resistance.
 152                 */
 153                rbs = (v_batctrl * 1000
 154                       - di->bm->gnd_lift_resistance * inst_curr)
 155                      / di->curr_source;
 156        } else {
 157                /*
 158                 * BAT_CTRL is internally
 159                 * connected to 1.8V through a 80k resistor
 160                 */
 161                rbs = (80000 * (v_batctrl)) / (1800 - v_batctrl);
 162        }
 163
 164        return rbs;
 165}
 166
 167/**
 168 * ab8500_btemp_read_batctrl_voltage() - measure batctrl voltage
 169 * @di:         pointer to the ab8500_btemp structure
 170 *
 171 * This function returns the voltage on BATCTRL. Returns value in mV.
 172 */
 173static int ab8500_btemp_read_batctrl_voltage(struct ab8500_btemp *di)
 174{
 175        int vbtemp, ret;
 176        static int prev;
 177
 178        ret = iio_read_channel_processed(di->bat_ctrl, &vbtemp);
 179        if (ret < 0) {
 180                dev_err(di->dev,
 181                        "%s ADC conversion failed, using previous value",
 182                        __func__);
 183                return prev;
 184        }
 185        prev = vbtemp;
 186        return vbtemp;
 187}
 188
 189/**
 190 * ab8500_btemp_curr_source_enable() - enable/disable batctrl current source
 191 * @di:         pointer to the ab8500_btemp structure
 192 * @enable:     enable or disable the current source
 193 *
 194 * Enable or disable the current sources for the BatCtrl AD channel
 195 */
 196static int ab8500_btemp_curr_source_enable(struct ab8500_btemp *di,
 197        bool enable)
 198{
 199        int curr;
 200        int ret = 0;
 201
 202        /*
 203         * BATCTRL current sources are included on AB8500 cut2.0
 204         * and future versions
 205         */
 206        if (is_ab8500_1p1_or_earlier(di->parent))
 207                return 0;
 208
 209        /* Only do this for batteries with internal NTC */
 210        if (di->bm->adc_therm == AB8500_ADC_THERM_BATCTRL && enable) {
 211
 212                if (di->curr_source == BTEMP_BATCTRL_CURR_SRC_7UA)
 213                        curr = BAT_CTRL_7U_ENA;
 214                else
 215                        curr = BAT_CTRL_20U_ENA;
 216
 217                dev_dbg(di->dev, "Set BATCTRL %duA\n", di->curr_source);
 218
 219                ret = abx500_mask_and_set_register_interruptible(di->dev,
 220                        AB8500_CHARGER, AB8500_BAT_CTRL_CURRENT_SOURCE,
 221                        FORCE_BAT_CTRL_CMP_HIGH, FORCE_BAT_CTRL_CMP_HIGH);
 222                if (ret) {
 223                        dev_err(di->dev, "%s failed setting cmp_force\n",
 224                                __func__);
 225                        return ret;
 226                }
 227
 228                /*
 229                 * We have to wait one 32kHz cycle before enabling
 230                 * the current source, since ForceBatCtrlCmpHigh needs
 231                 * to be written in a separate cycle
 232                 */
 233                udelay(32);
 234
 235                ret = abx500_set_register_interruptible(di->dev,
 236                        AB8500_CHARGER, AB8500_BAT_CTRL_CURRENT_SOURCE,
 237                        FORCE_BAT_CTRL_CMP_HIGH | curr);
 238                if (ret) {
 239                        dev_err(di->dev, "%s failed enabling current source\n",
 240                                __func__);
 241                        goto disable_curr_source;
 242                }
 243        } else if (di->bm->adc_therm == AB8500_ADC_THERM_BATCTRL && !enable) {
 244                dev_dbg(di->dev, "Disable BATCTRL curr source\n");
 245
 246                /* Write 0 to the curr bits */
 247                ret = abx500_mask_and_set_register_interruptible(
 248                        di->dev,
 249                        AB8500_CHARGER, AB8500_BAT_CTRL_CURRENT_SOURCE,
 250                        BAT_CTRL_7U_ENA | BAT_CTRL_20U_ENA,
 251                        ~(BAT_CTRL_7U_ENA | BAT_CTRL_20U_ENA));
 252
 253                if (ret) {
 254                        dev_err(di->dev, "%s failed disabling current source\n",
 255                                __func__);
 256                        goto disable_curr_source;
 257                }
 258
 259                /* Enable Pull-Up and comparator */
 260                ret = abx500_mask_and_set_register_interruptible(di->dev,
 261                        AB8500_CHARGER, AB8500_BAT_CTRL_CURRENT_SOURCE,
 262                        BAT_CTRL_PULL_UP_ENA | BAT_CTRL_CMP_ENA,
 263                        BAT_CTRL_PULL_UP_ENA | BAT_CTRL_CMP_ENA);
 264                if (ret) {
 265                        dev_err(di->dev, "%s failed enabling PU and comp\n",
 266                                __func__);
 267                        goto enable_pu_comp;
 268                }
 269
 270                /*
 271                 * We have to wait one 32kHz cycle before disabling
 272                 * ForceBatCtrlCmpHigh since this needs to be written
 273                 * in a separate cycle
 274                 */
 275                udelay(32);
 276
 277                /* Disable 'force comparator' */
 278                ret = abx500_mask_and_set_register_interruptible(di->dev,
 279                        AB8500_CHARGER, AB8500_BAT_CTRL_CURRENT_SOURCE,
 280                        FORCE_BAT_CTRL_CMP_HIGH, ~FORCE_BAT_CTRL_CMP_HIGH);
 281                if (ret) {
 282                        dev_err(di->dev, "%s failed disabling force comp\n",
 283                                __func__);
 284                        goto disable_force_comp;
 285                }
 286        }
 287        return ret;
 288
 289        /*
 290         * We have to try unsetting FORCE_BAT_CTRL_CMP_HIGH one more time
 291         * if we got an error above
 292         */
 293disable_curr_source:
 294        /* Write 0 to the curr bits */
 295        ret = abx500_mask_and_set_register_interruptible(di->dev,
 296                AB8500_CHARGER, AB8500_BAT_CTRL_CURRENT_SOURCE,
 297                BAT_CTRL_7U_ENA | BAT_CTRL_20U_ENA,
 298                ~(BAT_CTRL_7U_ENA | BAT_CTRL_20U_ENA));
 299
 300        if (ret) {
 301                dev_err(di->dev, "%s failed disabling current source\n",
 302                        __func__);
 303                return ret;
 304        }
 305enable_pu_comp:
 306        /* Enable Pull-Up and comparator */
 307        ret = abx500_mask_and_set_register_interruptible(di->dev,
 308                AB8500_CHARGER, AB8500_BAT_CTRL_CURRENT_SOURCE,
 309                BAT_CTRL_PULL_UP_ENA | BAT_CTRL_CMP_ENA,
 310                BAT_CTRL_PULL_UP_ENA | BAT_CTRL_CMP_ENA);
 311        if (ret) {
 312                dev_err(di->dev, "%s failed enabling PU and comp\n",
 313                        __func__);
 314                return ret;
 315        }
 316
 317disable_force_comp:
 318        /*
 319         * We have to wait one 32kHz cycle before disabling
 320         * ForceBatCtrlCmpHigh since this needs to be written
 321         * in a separate cycle
 322         */
 323        udelay(32);
 324
 325        /* Disable 'force comparator' */
 326        ret = abx500_mask_and_set_register_interruptible(di->dev,
 327                AB8500_CHARGER, AB8500_BAT_CTRL_CURRENT_SOURCE,
 328                FORCE_BAT_CTRL_CMP_HIGH, ~FORCE_BAT_CTRL_CMP_HIGH);
 329        if (ret) {
 330                dev_err(di->dev, "%s failed disabling force comp\n",
 331                        __func__);
 332                return ret;
 333        }
 334
 335        return ret;
 336}
 337
 338/**
 339 * ab8500_btemp_get_batctrl_res() - get battery resistance
 340 * @di:         pointer to the ab8500_btemp structure
 341 *
 342 * This function returns the battery pack identification resistance.
 343 * Returns value in Ohms.
 344 */
 345static int ab8500_btemp_get_batctrl_res(struct ab8500_btemp *di)
 346{
 347        int ret;
 348        int batctrl = 0;
 349        int res;
 350        int inst_curr;
 351        int i;
 352
 353        /*
 354         * BATCTRL current sources are included on AB8500 cut2.0
 355         * and future versions
 356         */
 357        ret = ab8500_btemp_curr_source_enable(di, true);
 358        if (ret) {
 359                dev_err(di->dev, "%s curr source enabled failed\n", __func__);
 360                return ret;
 361        }
 362
 363        if (!di->fg)
 364                di->fg = ab8500_fg_get();
 365        if (!di->fg) {
 366                dev_err(di->dev, "No fg found\n");
 367                return -EINVAL;
 368        }
 369
 370        ret = ab8500_fg_inst_curr_start(di->fg);
 371
 372        if (ret) {
 373                dev_err(di->dev, "Failed to start current measurement\n");
 374                return ret;
 375        }
 376
 377        do {
 378                msleep(20);
 379        } while (!ab8500_fg_inst_curr_started(di->fg));
 380
 381        i = 0;
 382
 383        do {
 384                batctrl += ab8500_btemp_read_batctrl_voltage(di);
 385                i++;
 386                msleep(20);
 387        } while (!ab8500_fg_inst_curr_done(di->fg));
 388        batctrl /= i;
 389
 390        ret = ab8500_fg_inst_curr_finalize(di->fg, &inst_curr);
 391        if (ret) {
 392                dev_err(di->dev, "Failed to finalize current measurement\n");
 393                return ret;
 394        }
 395
 396        res = ab8500_btemp_batctrl_volt_to_res(di, batctrl, inst_curr);
 397
 398        ret = ab8500_btemp_curr_source_enable(di, false);
 399        if (ret) {
 400                dev_err(di->dev, "%s curr source disable failed\n", __func__);
 401                return ret;
 402        }
 403
 404        dev_dbg(di->dev, "%s batctrl: %d res: %d inst_curr: %d samples: %d\n",
 405                __func__, batctrl, res, inst_curr, i);
 406
 407        return res;
 408}
 409
 410/**
 411 * ab8500_btemp_res_to_temp() - resistance to temperature
 412 * @di:         pointer to the ab8500_btemp structure
 413 * @tbl:        pointer to the resiatance to temperature table
 414 * @tbl_size:   size of the resistance to temperature table
 415 * @res:        resistance to calculate the temperature from
 416 *
 417 * This function returns the battery temperature in degrees Celsius
 418 * based on the NTC resistance.
 419 */
 420static int ab8500_btemp_res_to_temp(struct ab8500_btemp *di,
 421        const struct ab8500_res_to_temp *tbl, int tbl_size, int res)
 422{
 423        int i;
 424        /*
 425         * Calculate the formula for the straight line
 426         * Simple interpolation if we are within
 427         * the resistance table limits, extrapolate
 428         * if resistance is outside the limits.
 429         */
 430        if (res > tbl[0].resist)
 431                i = 0;
 432        else if (res <= tbl[tbl_size - 1].resist)
 433                i = tbl_size - 2;
 434        else {
 435                i = 0;
 436                while (!(res <= tbl[i].resist &&
 437                        res > tbl[i + 1].resist))
 438                        i++;
 439        }
 440
 441        return fixp_linear_interpolate(tbl[i].resist, tbl[i].temp,
 442                                       tbl[i + 1].resist, tbl[i + 1].temp,
 443                                       res);
 444}
 445
 446/**
 447 * ab8500_btemp_measure_temp() - measure battery temperature
 448 * @di:         pointer to the ab8500_btemp structure
 449 *
 450 * Returns battery temperature (on success) else the previous temperature
 451 */
 452static int ab8500_btemp_measure_temp(struct ab8500_btemp *di)
 453{
 454        int temp, ret;
 455        static int prev;
 456        int rbat, rntc, vntc;
 457        u8 id;
 458
 459        id = di->bm->batt_id;
 460
 461        if (di->bm->adc_therm == AB8500_ADC_THERM_BATCTRL &&
 462                        id != BATTERY_UNKNOWN) {
 463
 464                rbat = ab8500_btemp_get_batctrl_res(di);
 465                if (rbat < 0) {
 466                        dev_err(di->dev, "%s get batctrl res failed\n",
 467                                __func__);
 468                        /*
 469                         * Return out-of-range temperature so that
 470                         * charging is stopped
 471                         */
 472                        return BTEMP_THERMAL_LOW_LIMIT;
 473                }
 474
 475                temp = ab8500_btemp_res_to_temp(di,
 476                        di->bm->bat_type[id].r_to_t_tbl,
 477                        di->bm->bat_type[id].n_temp_tbl_elements, rbat);
 478        } else {
 479                ret = iio_read_channel_processed(di->btemp_ball, &vntc);
 480                if (ret < 0) {
 481                        dev_err(di->dev,
 482                                "%s ADC conversion failed,"
 483                                " using previous value\n", __func__);
 484                        return prev;
 485                }
 486                /*
 487                 * The PCB NTC is sourced from VTVOUT via a 230kOhm
 488                 * resistor.
 489                 */
 490                rntc = 230000 * vntc / (VTVOUT_V - vntc);
 491
 492                temp = ab8500_btemp_res_to_temp(di,
 493                        di->bm->bat_type[id].r_to_t_tbl,
 494                        di->bm->bat_type[id].n_temp_tbl_elements, rntc);
 495                prev = temp;
 496        }
 497        dev_dbg(di->dev, "Battery temperature is %d\n", temp);
 498        return temp;
 499}
 500
 501/**
 502 * ab8500_btemp_id() - Identify the connected battery
 503 * @di:         pointer to the ab8500_btemp structure
 504 *
 505 * This function will try to identify the battery by reading the ID
 506 * resistor. Some brands use a combined ID resistor with a NTC resistor to
 507 * both be able to identify and to read the temperature of it.
 508 */
 509static int ab8500_btemp_id(struct ab8500_btemp *di)
 510{
 511        int res;
 512        u8 i;
 513
 514        di->curr_source = BTEMP_BATCTRL_CURR_SRC_7UA;
 515        di->bm->batt_id = BATTERY_UNKNOWN;
 516
 517        res =  ab8500_btemp_get_batctrl_res(di);
 518        if (res < 0) {
 519                dev_err(di->dev, "%s get batctrl res failed\n", __func__);
 520                return -ENXIO;
 521        }
 522
 523        /* BATTERY_UNKNOWN is defined on position 0, skip it! */
 524        for (i = BATTERY_UNKNOWN + 1; i < di->bm->n_btypes; i++) {
 525                if ((res <= di->bm->bat_type[i].resis_high) &&
 526                        (res >= di->bm->bat_type[i].resis_low)) {
 527                        dev_dbg(di->dev, "Battery detected on %s"
 528                                " low %d < res %d < high: %d"
 529                                " index: %d\n",
 530                                di->bm->adc_therm == AB8500_ADC_THERM_BATCTRL ?
 531                                "BATCTRL" : "BATTEMP",
 532                                di->bm->bat_type[i].resis_low, res,
 533                                di->bm->bat_type[i].resis_high, i);
 534
 535                        di->bm->batt_id = i;
 536                        break;
 537                }
 538        }
 539
 540        if (di->bm->batt_id == BATTERY_UNKNOWN) {
 541                dev_warn(di->dev, "Battery identified as unknown"
 542                        ", resistance %d Ohm\n", res);
 543                return -ENXIO;
 544        }
 545
 546        /*
 547         * We only have to change current source if the
 548         * detected type is Type 1.
 549         */
 550        if (di->bm->adc_therm == AB8500_ADC_THERM_BATCTRL &&
 551            di->bm->batt_id == 1) {
 552                dev_dbg(di->dev, "Set BATCTRL current source to 20uA\n");
 553                di->curr_source = BTEMP_BATCTRL_CURR_SRC_20UA;
 554        }
 555
 556        return di->bm->batt_id;
 557}
 558
 559/**
 560 * ab8500_btemp_periodic_work() - Measuring the temperature periodically
 561 * @work:       pointer to the work_struct structure
 562 *
 563 * Work function for measuring the temperature periodically
 564 */
 565static void ab8500_btemp_periodic_work(struct work_struct *work)
 566{
 567        int interval;
 568        int bat_temp;
 569        struct ab8500_btemp *di = container_of(work,
 570                struct ab8500_btemp, btemp_periodic_work.work);
 571
 572        if (!di->initialized) {
 573                /* Identify the battery */
 574                if (ab8500_btemp_id(di) < 0)
 575                        dev_warn(di->dev, "failed to identify the battery\n");
 576        }
 577
 578        bat_temp = ab8500_btemp_measure_temp(di);
 579        /*
 580         * Filter battery temperature.
 581         * Allow direct updates on temperature only if two samples result in
 582         * same temperature. Else only allow 1 degree change from previous
 583         * reported value in the direction of the new measurement.
 584         */
 585        if ((bat_temp == di->prev_bat_temp) || !di->initialized) {
 586                if ((di->bat_temp != di->prev_bat_temp) || !di->initialized) {
 587                        di->initialized = true;
 588                        di->bat_temp = bat_temp;
 589                        power_supply_changed(di->btemp_psy);
 590                }
 591        } else if (bat_temp < di->prev_bat_temp) {
 592                di->bat_temp--;
 593                power_supply_changed(di->btemp_psy);
 594        } else if (bat_temp > di->prev_bat_temp) {
 595                di->bat_temp++;
 596                power_supply_changed(di->btemp_psy);
 597        }
 598        di->prev_bat_temp = bat_temp;
 599
 600        if (di->events.ac_conn || di->events.usb_conn)
 601                interval = di->bm->temp_interval_chg;
 602        else
 603                interval = di->bm->temp_interval_nochg;
 604
 605        /* Schedule a new measurement */
 606        queue_delayed_work(di->btemp_wq,
 607                &di->btemp_periodic_work,
 608                round_jiffies(interval * HZ));
 609}
 610
 611/**
 612 * ab8500_btemp_batctrlindb_handler() - battery removal detected
 613 * @irq:       interrupt number
 614 * @_di:       void pointer that has to address of ab8500_btemp
 615 *
 616 * Returns IRQ status(IRQ_HANDLED)
 617 */
 618static irqreturn_t ab8500_btemp_batctrlindb_handler(int irq, void *_di)
 619{
 620        struct ab8500_btemp *di = _di;
 621        dev_err(di->dev, "Battery removal detected!\n");
 622
 623        di->events.batt_rem = true;
 624        power_supply_changed(di->btemp_psy);
 625
 626        return IRQ_HANDLED;
 627}
 628
 629/**
 630 * ab8500_btemp_templow_handler() - battery temp lower than 10 degrees
 631 * @irq:       interrupt number
 632 * @_di:       void pointer that has to address of ab8500_btemp
 633 *
 634 * Returns IRQ status(IRQ_HANDLED)
 635 */
 636static irqreturn_t ab8500_btemp_templow_handler(int irq, void *_di)
 637{
 638        struct ab8500_btemp *di = _di;
 639
 640        if (is_ab8500_3p3_or_earlier(di->parent)) {
 641                dev_dbg(di->dev, "Ignore false btemp low irq"
 642                        " for ABB cut 1.0, 1.1, 2.0 and 3.3\n");
 643        } else {
 644                dev_crit(di->dev, "Battery temperature lower than -10deg c\n");
 645
 646                di->events.btemp_low = true;
 647                di->events.btemp_high = false;
 648                di->events.btemp_medhigh = false;
 649                di->events.btemp_lowmed = false;
 650                power_supply_changed(di->btemp_psy);
 651        }
 652
 653        return IRQ_HANDLED;
 654}
 655
 656/**
 657 * ab8500_btemp_temphigh_handler() - battery temp higher than max temp
 658 * @irq:       interrupt number
 659 * @_di:       void pointer that has to address of ab8500_btemp
 660 *
 661 * Returns IRQ status(IRQ_HANDLED)
 662 */
 663static irqreturn_t ab8500_btemp_temphigh_handler(int irq, void *_di)
 664{
 665        struct ab8500_btemp *di = _di;
 666
 667        dev_crit(di->dev, "Battery temperature is higher than MAX temp\n");
 668
 669        di->events.btemp_high = true;
 670        di->events.btemp_medhigh = false;
 671        di->events.btemp_lowmed = false;
 672        di->events.btemp_low = false;
 673        power_supply_changed(di->btemp_psy);
 674
 675        return IRQ_HANDLED;
 676}
 677
 678/**
 679 * ab8500_btemp_lowmed_handler() - battery temp between low and medium
 680 * @irq:       interrupt number
 681 * @_di:       void pointer that has to address of ab8500_btemp
 682 *
 683 * Returns IRQ status(IRQ_HANDLED)
 684 */
 685static irqreturn_t ab8500_btemp_lowmed_handler(int irq, void *_di)
 686{
 687        struct ab8500_btemp *di = _di;
 688
 689        dev_dbg(di->dev, "Battery temperature is between low and medium\n");
 690
 691        di->events.btemp_lowmed = true;
 692        di->events.btemp_medhigh = false;
 693        di->events.btemp_high = false;
 694        di->events.btemp_low = false;
 695        power_supply_changed(di->btemp_psy);
 696
 697        return IRQ_HANDLED;
 698}
 699
 700/**
 701 * ab8500_btemp_medhigh_handler() - battery temp between medium and high
 702 * @irq:       interrupt number
 703 * @_di:       void pointer that has to address of ab8500_btemp
 704 *
 705 * Returns IRQ status(IRQ_HANDLED)
 706 */
 707static irqreturn_t ab8500_btemp_medhigh_handler(int irq, void *_di)
 708{
 709        struct ab8500_btemp *di = _di;
 710
 711        dev_dbg(di->dev, "Battery temperature is between medium and high\n");
 712
 713        di->events.btemp_medhigh = true;
 714        di->events.btemp_lowmed = false;
 715        di->events.btemp_high = false;
 716        di->events.btemp_low = false;
 717        power_supply_changed(di->btemp_psy);
 718
 719        return IRQ_HANDLED;
 720}
 721
 722/**
 723 * ab8500_btemp_periodic() - Periodic temperature measurements
 724 * @di:         pointer to the ab8500_btemp structure
 725 * @enable:     enable or disable periodic temperature measurements
 726 *
 727 * Starts of stops periodic temperature measurements. Periodic measurements
 728 * should only be done when a charger is connected.
 729 */
 730static void ab8500_btemp_periodic(struct ab8500_btemp *di,
 731        bool enable)
 732{
 733        dev_dbg(di->dev, "Enable periodic temperature measurements: %d\n",
 734                enable);
 735        /*
 736         * Make sure a new measurement is done directly by cancelling
 737         * any pending work
 738         */
 739        cancel_delayed_work_sync(&di->btemp_periodic_work);
 740
 741        if (enable)
 742                queue_delayed_work(di->btemp_wq, &di->btemp_periodic_work, 0);
 743}
 744
 745/**
 746 * ab8500_btemp_get_temp() - get battery temperature
 747 * @di:         pointer to the ab8500_btemp structure
 748 *
 749 * Returns battery temperature
 750 */
 751static int ab8500_btemp_get_temp(struct ab8500_btemp *di)
 752{
 753        int temp = 0;
 754
 755        /*
 756         * The BTEMP events are not reliabe on AB8500 cut3.3
 757         * and prior versions
 758         */
 759        if (is_ab8500_3p3_or_earlier(di->parent)) {
 760                temp = di->bat_temp * 10;
 761        } else {
 762                if (di->events.btemp_low) {
 763                        if (temp > di->btemp_ranges.btemp_low_limit)
 764                                temp = di->btemp_ranges.btemp_low_limit * 10;
 765                        else
 766                                temp = di->bat_temp * 10;
 767                } else if (di->events.btemp_high) {
 768                        if (temp < di->btemp_ranges.btemp_high_limit)
 769                                temp = di->btemp_ranges.btemp_high_limit * 10;
 770                        else
 771                                temp = di->bat_temp * 10;
 772                } else if (di->events.btemp_lowmed) {
 773                        if (temp > di->btemp_ranges.btemp_med_limit)
 774                                temp = di->btemp_ranges.btemp_med_limit * 10;
 775                        else
 776                                temp = di->bat_temp * 10;
 777                } else if (di->events.btemp_medhigh) {
 778                        if (temp < di->btemp_ranges.btemp_med_limit)
 779                                temp = di->btemp_ranges.btemp_med_limit * 10;
 780                        else
 781                                temp = di->bat_temp * 10;
 782                } else
 783                        temp = di->bat_temp * 10;
 784        }
 785        return temp;
 786}
 787
 788/**
 789 * ab8500_btemp_get_property() - get the btemp properties
 790 * @psy:        pointer to the power_supply structure
 791 * @psp:        pointer to the power_supply_property structure
 792 * @val:        pointer to the power_supply_propval union
 793 *
 794 * This function gets called when an application tries to get the btemp
 795 * properties by reading the sysfs files.
 796 * online:      presence of the battery
 797 * present:     presence of the battery
 798 * technology:  battery technology
 799 * temp:        battery temperature
 800 * Returns error code in case of failure else 0(on success)
 801 */
 802static int ab8500_btemp_get_property(struct power_supply *psy,
 803        enum power_supply_property psp,
 804        union power_supply_propval *val)
 805{
 806        struct ab8500_btemp *di = power_supply_get_drvdata(psy);
 807
 808        switch (psp) {
 809        case POWER_SUPPLY_PROP_PRESENT:
 810        case POWER_SUPPLY_PROP_ONLINE:
 811                if (di->events.batt_rem)
 812                        val->intval = 0;
 813                else
 814                        val->intval = 1;
 815                break;
 816        case POWER_SUPPLY_PROP_TECHNOLOGY:
 817                val->intval = di->bm->bat_type[di->bm->batt_id].name;
 818                break;
 819        case POWER_SUPPLY_PROP_TEMP:
 820                val->intval = ab8500_btemp_get_temp(di);
 821                break;
 822        default:
 823                return -EINVAL;
 824        }
 825        return 0;
 826}
 827
 828static int ab8500_btemp_get_ext_psy_data(struct device *dev, void *data)
 829{
 830        struct power_supply *psy;
 831        struct power_supply *ext = dev_get_drvdata(dev);
 832        const char **supplicants = (const char **)ext->supplied_to;
 833        struct ab8500_btemp *di;
 834        union power_supply_propval ret;
 835        int j;
 836
 837        psy = (struct power_supply *)data;
 838        di = power_supply_get_drvdata(psy);
 839
 840        /*
 841         * For all psy where the name of your driver
 842         * appears in any supplied_to
 843         */
 844        j = match_string(supplicants, ext->num_supplicants, psy->desc->name);
 845        if (j < 0)
 846                return 0;
 847
 848        /* Go through all properties for the psy */
 849        for (j = 0; j < ext->desc->num_properties; j++) {
 850                enum power_supply_property prop;
 851                prop = ext->desc->properties[j];
 852
 853                if (power_supply_get_property(ext, prop, &ret))
 854                        continue;
 855
 856                switch (prop) {
 857                case POWER_SUPPLY_PROP_PRESENT:
 858                        switch (ext->desc->type) {
 859                        case POWER_SUPPLY_TYPE_MAINS:
 860                                /* AC disconnected */
 861                                if (!ret.intval && di->events.ac_conn) {
 862                                        di->events.ac_conn = false;
 863                                }
 864                                /* AC connected */
 865                                else if (ret.intval && !di->events.ac_conn) {
 866                                        di->events.ac_conn = true;
 867                                        if (!di->events.usb_conn)
 868                                                ab8500_btemp_periodic(di, true);
 869                                }
 870                                break;
 871                        case POWER_SUPPLY_TYPE_USB:
 872                                /* USB disconnected */
 873                                if (!ret.intval && di->events.usb_conn) {
 874                                        di->events.usb_conn = false;
 875                                }
 876                                /* USB connected */
 877                                else if (ret.intval && !di->events.usb_conn) {
 878                                        di->events.usb_conn = true;
 879                                        if (!di->events.ac_conn)
 880                                                ab8500_btemp_periodic(di, true);
 881                                }
 882                                break;
 883                        default:
 884                                break;
 885                        }
 886                        break;
 887                default:
 888                        break;
 889                }
 890        }
 891        return 0;
 892}
 893
 894/**
 895 * ab8500_btemp_external_power_changed() - callback for power supply changes
 896 * @psy:       pointer to the structure power_supply
 897 *
 898 * This function is pointing to the function pointer external_power_changed
 899 * of the structure power_supply.
 900 * This function gets executed when there is a change in the external power
 901 * supply to the btemp.
 902 */
 903static void ab8500_btemp_external_power_changed(struct power_supply *psy)
 904{
 905        struct ab8500_btemp *di = power_supply_get_drvdata(psy);
 906
 907        class_for_each_device(power_supply_class, NULL,
 908                di->btemp_psy, ab8500_btemp_get_ext_psy_data);
 909}
 910
 911/* ab8500 btemp driver interrupts and their respective isr */
 912static struct ab8500_btemp_interrupts ab8500_btemp_irq[] = {
 913        {"BAT_CTRL_INDB", ab8500_btemp_batctrlindb_handler},
 914        {"BTEMP_LOW", ab8500_btemp_templow_handler},
 915        {"BTEMP_HIGH", ab8500_btemp_temphigh_handler},
 916        {"BTEMP_LOW_MEDIUM", ab8500_btemp_lowmed_handler},
 917        {"BTEMP_MEDIUM_HIGH", ab8500_btemp_medhigh_handler},
 918};
 919
 920static int __maybe_unused ab8500_btemp_resume(struct device *dev)
 921{
 922        struct ab8500_btemp *di = dev_get_drvdata(dev);
 923
 924        ab8500_btemp_periodic(di, true);
 925
 926        return 0;
 927}
 928
 929static int __maybe_unused ab8500_btemp_suspend(struct device *dev)
 930{
 931        struct ab8500_btemp *di = dev_get_drvdata(dev);
 932
 933        ab8500_btemp_periodic(di, false);
 934
 935        return 0;
 936}
 937
 938static char *supply_interface[] = {
 939        "ab8500_chargalg",
 940        "ab8500_fg",
 941};
 942
 943static const struct power_supply_desc ab8500_btemp_desc = {
 944        .name                   = "ab8500_btemp",
 945        .type                   = POWER_SUPPLY_TYPE_BATTERY,
 946        .properties             = ab8500_btemp_props,
 947        .num_properties         = ARRAY_SIZE(ab8500_btemp_props),
 948        .get_property           = ab8500_btemp_get_property,
 949        .external_power_changed = ab8500_btemp_external_power_changed,
 950};
 951
 952static int ab8500_btemp_bind(struct device *dev, struct device *master,
 953                             void *data)
 954{
 955        struct ab8500_btemp *di = dev_get_drvdata(dev);
 956
 957        /* Create a work queue for the btemp */
 958        di->btemp_wq =
 959                alloc_workqueue("ab8500_btemp_wq", WQ_MEM_RECLAIM, 0);
 960        if (di->btemp_wq == NULL) {
 961                dev_err(dev, "failed to create work queue\n");
 962                return -ENOMEM;
 963        }
 964
 965        /* Kick off periodic temperature measurements */
 966        ab8500_btemp_periodic(di, true);
 967
 968        return 0;
 969}
 970
 971static void ab8500_btemp_unbind(struct device *dev, struct device *master,
 972                                void *data)
 973{
 974        struct ab8500_btemp *di = dev_get_drvdata(dev);
 975
 976        /* Delete the work queue */
 977        destroy_workqueue(di->btemp_wq);
 978        flush_scheduled_work();
 979}
 980
 981static const struct component_ops ab8500_btemp_component_ops = {
 982        .bind = ab8500_btemp_bind,
 983        .unbind = ab8500_btemp_unbind,
 984};
 985
 986static int ab8500_btemp_probe(struct platform_device *pdev)
 987{
 988        struct power_supply_config psy_cfg = {};
 989        struct device *dev = &pdev->dev;
 990        struct ab8500_btemp *di;
 991        int irq, i, ret = 0;
 992        u8 val;
 993
 994        di = devm_kzalloc(dev, sizeof(*di), GFP_KERNEL);
 995        if (!di)
 996                return -ENOMEM;
 997
 998        di->bm = &ab8500_bm_data;
 999
1000        /* get parent data */
1001        di->dev = dev;
1002        di->parent = dev_get_drvdata(pdev->dev.parent);
1003
1004        /* Get ADC channels */
1005        di->btemp_ball = devm_iio_channel_get(dev, "btemp_ball");
1006        if (IS_ERR(di->btemp_ball)) {
1007                ret = dev_err_probe(dev, PTR_ERR(di->btemp_ball),
1008                                    "failed to get BTEMP BALL ADC channel\n");
1009                return ret;
1010        }
1011        di->bat_ctrl = devm_iio_channel_get(dev, "bat_ctrl");
1012        if (IS_ERR(di->bat_ctrl)) {
1013                ret = dev_err_probe(dev, PTR_ERR(di->bat_ctrl),
1014                                    "failed to get BAT CTRL ADC channel\n");
1015                return ret;
1016        }
1017
1018        di->initialized = false;
1019
1020        psy_cfg.supplied_to = supply_interface;
1021        psy_cfg.num_supplicants = ARRAY_SIZE(supply_interface);
1022        psy_cfg.drv_data = di;
1023
1024        /* Init work for measuring temperature periodically */
1025        INIT_DEFERRABLE_WORK(&di->btemp_periodic_work,
1026                ab8500_btemp_periodic_work);
1027
1028        /* Set BTEMP thermal limits. Low and Med are fixed */
1029        di->btemp_ranges.btemp_low_limit = BTEMP_THERMAL_LOW_LIMIT;
1030        di->btemp_ranges.btemp_med_limit = BTEMP_THERMAL_MED_LIMIT;
1031
1032        ret = abx500_get_register_interruptible(dev, AB8500_CHARGER,
1033                AB8500_BTEMP_HIGH_TH, &val);
1034        if (ret < 0) {
1035                dev_err(dev, "%s ab8500 read failed\n", __func__);
1036                return ret;
1037        }
1038        switch (val) {
1039        case BTEMP_HIGH_TH_57_0:
1040        case BTEMP_HIGH_TH_57_1:
1041                di->btemp_ranges.btemp_high_limit =
1042                        BTEMP_THERMAL_HIGH_LIMIT_57;
1043                break;
1044        case BTEMP_HIGH_TH_52:
1045                di->btemp_ranges.btemp_high_limit =
1046                        BTEMP_THERMAL_HIGH_LIMIT_52;
1047                break;
1048        case BTEMP_HIGH_TH_62:
1049                di->btemp_ranges.btemp_high_limit =
1050                        BTEMP_THERMAL_HIGH_LIMIT_62;
1051                break;
1052        }
1053
1054        /* Register BTEMP power supply class */
1055        di->btemp_psy = devm_power_supply_register(dev, &ab8500_btemp_desc,
1056                                                   &psy_cfg);
1057        if (IS_ERR(di->btemp_psy)) {
1058                dev_err(dev, "failed to register BTEMP psy\n");
1059                return PTR_ERR(di->btemp_psy);
1060        }
1061
1062        /* Register interrupts */
1063        for (i = 0; i < ARRAY_SIZE(ab8500_btemp_irq); i++) {
1064                irq = platform_get_irq_byname(pdev, ab8500_btemp_irq[i].name);
1065                if (irq < 0)
1066                        return irq;
1067
1068                ret = devm_request_threaded_irq(dev, irq, NULL,
1069                        ab8500_btemp_irq[i].isr,
1070                        IRQF_SHARED | IRQF_NO_SUSPEND | IRQF_ONESHOT,
1071                        ab8500_btemp_irq[i].name, di);
1072
1073                if (ret) {
1074                        dev_err(dev, "failed to request %s IRQ %d: %d\n"
1075                                , ab8500_btemp_irq[i].name, irq, ret);
1076                        return ret;
1077                }
1078                dev_dbg(dev, "Requested %s IRQ %d: %d\n",
1079                        ab8500_btemp_irq[i].name, irq, ret);
1080        }
1081
1082        platform_set_drvdata(pdev, di);
1083
1084        list_add_tail(&di->node, &ab8500_btemp_list);
1085
1086        return component_add(dev, &ab8500_btemp_component_ops);
1087}
1088
1089static int ab8500_btemp_remove(struct platform_device *pdev)
1090{
1091        component_del(&pdev->dev, &ab8500_btemp_component_ops);
1092
1093        return 0;
1094}
1095
1096static SIMPLE_DEV_PM_OPS(ab8500_btemp_pm_ops, ab8500_btemp_suspend, ab8500_btemp_resume);
1097
1098static const struct of_device_id ab8500_btemp_match[] = {
1099        { .compatible = "stericsson,ab8500-btemp", },
1100        { },
1101};
1102MODULE_DEVICE_TABLE(of, ab8500_btemp_match);
1103
1104struct platform_driver ab8500_btemp_driver = {
1105        .probe = ab8500_btemp_probe,
1106        .remove = ab8500_btemp_remove,
1107        .driver = {
1108                .name = "ab8500-btemp",
1109                .of_match_table = ab8500_btemp_match,
1110                .pm = &ab8500_btemp_pm_ops,
1111        },
1112};
1113MODULE_LICENSE("GPL v2");
1114MODULE_AUTHOR("Johan Palsson, Karl Komierowski, Arun R Murthy");
1115MODULE_ALIAS("platform:ab8500-btemp");
1116MODULE_DESCRIPTION("AB8500 battery temperature driver");
1117