linux/drivers/power/supply/rn5t618_power.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0+
   2/*
   3 * Power supply driver for the RICOH RN5T618 power management chip family
   4 *
   5 * Copyright (C) 2020 Andreas Kemnade
   6 */
   7
   8#include <linux/kernel.h>
   9#include <linux/device.h>
  10#include <linux/bitops.h>
  11#include <linux/errno.h>
  12#include <linux/iio/consumer.h>
  13#include <linux/init.h>
  14#include <linux/interrupt.h>
  15#include <linux/module.h>
  16#include <linux/mfd/rn5t618.h>
  17#include <linux/of_device.h>
  18#include <linux/platform_device.h>
  19#include <linux/power_supply.h>
  20#include <linux/regmap.h>
  21#include <linux/slab.h>
  22
  23#define CHG_STATE_ADP_INPUT 0x40
  24#define CHG_STATE_USB_INPUT 0x80
  25#define CHG_STATE_MASK  0x1f
  26#define CHG_STATE_CHG_OFF       0
  27#define CHG_STATE_CHG_READY_VADP        1
  28#define CHG_STATE_CHG_TRICKLE   2
  29#define CHG_STATE_CHG_RAPID     3
  30#define CHG_STATE_CHG_COMPLETE  4
  31#define CHG_STATE_SUSPEND       5
  32#define CHG_STATE_VCHG_OVER_VOL 6
  33#define CHG_STATE_BAT_ERROR     7
  34#define CHG_STATE_NO_BAT        8
  35#define CHG_STATE_BAT_OVER_VOL  9
  36#define CHG_STATE_BAT_TEMP_ERR  10
  37#define CHG_STATE_DIE_ERR       11
  38#define CHG_STATE_DIE_SHUTDOWN  12
  39#define CHG_STATE_NO_BAT2       13
  40#define CHG_STATE_CHG_READY_VUSB        14
  41
  42#define GCHGDET_TYPE_MASK 0x30
  43#define GCHGDET_TYPE_SDP 0x00
  44#define GCHGDET_TYPE_CDP 0x10
  45#define GCHGDET_TYPE_DCP 0x20
  46
  47#define FG_ENABLE 1
  48
  49/*
  50 * Formula seems accurate for battery current, but for USB current around 70mA
  51 * per step was seen on Kobo Clara HD but all sources show the same formula
  52 * also fur USB current. To avoid accidentially unwanted high currents we stick
  53 * to that formula
  54 */
  55#define TO_CUR_REG(x) ((x) / 100000 - 1)
  56#define FROM_CUR_REG(x) ((((x) & 0x1f) + 1) * 100000)
  57#define CHG_MIN_CUR 100000
  58#define CHG_MAX_CUR 1800000
  59#define ADP_MAX_CUR 2500000
  60#define USB_MAX_CUR 1400000
  61
  62
  63struct rn5t618_power_info {
  64        struct rn5t618 *rn5t618;
  65        struct platform_device *pdev;
  66        struct power_supply *battery;
  67        struct power_supply *usb;
  68        struct power_supply *adp;
  69        struct iio_channel *channel_vusb;
  70        struct iio_channel *channel_vadp;
  71        int irq;
  72};
  73
  74static enum power_supply_usb_type rn5t618_usb_types[] = {
  75        POWER_SUPPLY_USB_TYPE_SDP,
  76        POWER_SUPPLY_USB_TYPE_DCP,
  77        POWER_SUPPLY_USB_TYPE_CDP,
  78        POWER_SUPPLY_USB_TYPE_UNKNOWN
  79};
  80
  81static enum power_supply_property rn5t618_usb_props[] = {
  82        /* input current limit is not very accurate */
  83        POWER_SUPPLY_PROP_INPUT_CURRENT_LIMIT,
  84        POWER_SUPPLY_PROP_VOLTAGE_NOW,
  85        POWER_SUPPLY_PROP_STATUS,
  86        POWER_SUPPLY_PROP_USB_TYPE,
  87        POWER_SUPPLY_PROP_ONLINE,
  88};
  89
  90static enum power_supply_property rn5t618_adp_props[] = {
  91        /* input current limit is not very accurate */
  92        POWER_SUPPLY_PROP_INPUT_CURRENT_LIMIT,
  93        POWER_SUPPLY_PROP_VOLTAGE_NOW,
  94        POWER_SUPPLY_PROP_STATUS,
  95        POWER_SUPPLY_PROP_ONLINE,
  96};
  97
  98
  99static enum power_supply_property rn5t618_battery_props[] = {
 100        POWER_SUPPLY_PROP_STATUS,
 101        POWER_SUPPLY_PROP_PRESENT,
 102        POWER_SUPPLY_PROP_VOLTAGE_NOW,
 103        POWER_SUPPLY_PROP_CURRENT_NOW,
 104        POWER_SUPPLY_PROP_CAPACITY,
 105        POWER_SUPPLY_PROP_TEMP,
 106        POWER_SUPPLY_PROP_TIME_TO_EMPTY_NOW,
 107        POWER_SUPPLY_PROP_TIME_TO_FULL_NOW,
 108        POWER_SUPPLY_PROP_TECHNOLOGY,
 109        POWER_SUPPLY_PROP_CHARGE_CONTROL_LIMIT,
 110        POWER_SUPPLY_PROP_CHARGE_FULL,
 111        POWER_SUPPLY_PROP_CHARGE_NOW,
 112};
 113
 114static int rn5t618_battery_read_doublereg(struct rn5t618_power_info *info,
 115                                          u8 reg, u16 *result)
 116{
 117        int ret, i;
 118        u8 data[2];
 119        u16 old, new;
 120
 121        old = 0;
 122        /* Prevent races when registers are changing. */
 123        for (i = 0; i < 3; i++) {
 124                ret = regmap_bulk_read(info->rn5t618->regmap,
 125                                       reg, data, sizeof(data));
 126                if (ret)
 127                        return ret;
 128
 129                new = data[0] << 8;
 130                new |= data[1];
 131                if (new == old)
 132                        break;
 133
 134                old = new;
 135        }
 136
 137        *result = new;
 138
 139        return 0;
 140}
 141
 142static int rn5t618_decode_status(unsigned int status)
 143{
 144        switch (status & CHG_STATE_MASK) {
 145        case CHG_STATE_CHG_OFF:
 146        case CHG_STATE_SUSPEND:
 147        case CHG_STATE_VCHG_OVER_VOL:
 148        case CHG_STATE_DIE_SHUTDOWN:
 149                return POWER_SUPPLY_STATUS_DISCHARGING;
 150
 151        case CHG_STATE_CHG_TRICKLE:
 152        case CHG_STATE_CHG_RAPID:
 153                return POWER_SUPPLY_STATUS_CHARGING;
 154
 155        case CHG_STATE_CHG_COMPLETE:
 156                return POWER_SUPPLY_STATUS_FULL;
 157
 158        default:
 159                return POWER_SUPPLY_STATUS_NOT_CHARGING;
 160        }
 161}
 162
 163static int rn5t618_battery_status(struct rn5t618_power_info *info,
 164                                  union power_supply_propval *val)
 165{
 166        unsigned int v;
 167        int ret;
 168
 169        ret = regmap_read(info->rn5t618->regmap, RN5T618_CHGSTATE, &v);
 170        if (ret)
 171                return ret;
 172
 173        val->intval = POWER_SUPPLY_STATUS_UNKNOWN;
 174
 175        if (v & 0xc0) { /* USB or ADP plugged */
 176                val->intval = rn5t618_decode_status(v);
 177        } else
 178                val->intval = POWER_SUPPLY_STATUS_DISCHARGING;
 179
 180        return ret;
 181}
 182
 183static int rn5t618_battery_present(struct rn5t618_power_info *info,
 184                                   union power_supply_propval *val)
 185{
 186        unsigned int v;
 187        int ret;
 188
 189        ret = regmap_read(info->rn5t618->regmap, RN5T618_CHGSTATE, &v);
 190        if (ret)
 191                return ret;
 192
 193        v &= CHG_STATE_MASK;
 194        if ((v == CHG_STATE_NO_BAT) || (v == CHG_STATE_NO_BAT2))
 195                val->intval = 0;
 196        else
 197                val->intval = 1;
 198
 199        return ret;
 200}
 201
 202static int rn5t618_battery_voltage_now(struct rn5t618_power_info *info,
 203                                       union power_supply_propval *val)
 204{
 205        u16 res;
 206        int ret;
 207
 208        ret = rn5t618_battery_read_doublereg(info, RN5T618_VOLTAGE_1, &res);
 209        if (ret)
 210                return ret;
 211
 212        val->intval = res * 2 * 2500 / 4095 * 1000;
 213
 214        return 0;
 215}
 216
 217static int rn5t618_battery_current_now(struct rn5t618_power_info *info,
 218                                       union power_supply_propval *val)
 219{
 220        u16 res;
 221        int ret;
 222
 223        ret = rn5t618_battery_read_doublereg(info, RN5T618_CC_AVEREG1, &res);
 224        if (ret)
 225                return ret;
 226
 227        /* current is negative when discharging */
 228        val->intval = sign_extend32(res, 13) * 1000;
 229
 230        return 0;
 231}
 232
 233static int rn5t618_battery_capacity(struct rn5t618_power_info *info,
 234                                    union power_supply_propval *val)
 235{
 236        unsigned int v;
 237        int ret;
 238
 239        ret = regmap_read(info->rn5t618->regmap, RN5T618_SOC, &v);
 240        if (ret)
 241                return ret;
 242
 243        val->intval = v;
 244
 245        return 0;
 246}
 247
 248static int rn5t618_battery_temp(struct rn5t618_power_info *info,
 249                                union power_supply_propval *val)
 250{
 251        u16 res;
 252        int ret;
 253
 254        ret = rn5t618_battery_read_doublereg(info, RN5T618_TEMP_1, &res);
 255        if (ret)
 256                return ret;
 257
 258        val->intval = sign_extend32(res, 11) * 10 / 16;
 259
 260        return 0;
 261}
 262
 263static int rn5t618_battery_tte(struct rn5t618_power_info *info,
 264                               union power_supply_propval *val)
 265{
 266        u16 res;
 267        int ret;
 268
 269        ret = rn5t618_battery_read_doublereg(info, RN5T618_TT_EMPTY_H, &res);
 270        if (ret)
 271                return ret;
 272
 273        if (res == 65535)
 274                return -ENODATA;
 275
 276        val->intval = res * 60;
 277
 278        return 0;
 279}
 280
 281static int rn5t618_battery_ttf(struct rn5t618_power_info *info,
 282                               union power_supply_propval *val)
 283{
 284        u16 res;
 285        int ret;
 286
 287        ret = rn5t618_battery_read_doublereg(info, RN5T618_TT_FULL_H, &res);
 288        if (ret)
 289                return ret;
 290
 291        if (res == 65535)
 292                return -ENODATA;
 293
 294        val->intval = res * 60;
 295
 296        return 0;
 297}
 298
 299static int rn5t618_battery_set_current_limit(struct rn5t618_power_info *info,
 300                                const union power_supply_propval *val)
 301{
 302        if (val->intval < CHG_MIN_CUR)
 303                return -EINVAL;
 304
 305        if (val->intval >= CHG_MAX_CUR)
 306                return -EINVAL;
 307
 308        return regmap_update_bits(info->rn5t618->regmap,
 309                                  RN5T618_CHGISET,
 310                                  0x1F, TO_CUR_REG(val->intval));
 311}
 312
 313static int rn5t618_battery_get_current_limit(struct rn5t618_power_info *info,
 314                                             union power_supply_propval *val)
 315{
 316        unsigned int regval;
 317        int ret;
 318
 319        ret = regmap_read(info->rn5t618->regmap, RN5T618_CHGISET,
 320                          &regval);
 321        if (ret < 0)
 322                return ret;
 323
 324        val->intval = FROM_CUR_REG(regval);
 325
 326        return 0;
 327}
 328
 329static int rn5t618_battery_charge_full(struct rn5t618_power_info *info,
 330                                       union power_supply_propval *val)
 331{
 332        u16 res;
 333        int ret;
 334
 335        ret = rn5t618_battery_read_doublereg(info, RN5T618_FA_CAP_H, &res);
 336        if (ret)
 337                return ret;
 338
 339        val->intval = res * 1000;
 340
 341        return 0;
 342}
 343
 344static int rn5t618_battery_charge_now(struct rn5t618_power_info *info,
 345                                      union power_supply_propval *val)
 346{
 347        u16 res;
 348        int ret;
 349
 350        ret = rn5t618_battery_read_doublereg(info, RN5T618_RE_CAP_H, &res);
 351        if (ret)
 352                return ret;
 353
 354        val->intval = res * 1000;
 355
 356        return 0;
 357}
 358
 359static int rn5t618_battery_get_property(struct power_supply *psy,
 360                                        enum power_supply_property psp,
 361                                        union power_supply_propval *val)
 362{
 363        int ret = 0;
 364        struct rn5t618_power_info *info = power_supply_get_drvdata(psy);
 365
 366        switch (psp) {
 367        case POWER_SUPPLY_PROP_STATUS:
 368                ret = rn5t618_battery_status(info, val);
 369                break;
 370        case POWER_SUPPLY_PROP_PRESENT:
 371                ret = rn5t618_battery_present(info, val);
 372                break;
 373        case POWER_SUPPLY_PROP_VOLTAGE_NOW:
 374                ret = rn5t618_battery_voltage_now(info, val);
 375                break;
 376        case POWER_SUPPLY_PROP_CURRENT_NOW:
 377                ret = rn5t618_battery_current_now(info, val);
 378                break;
 379        case POWER_SUPPLY_PROP_CAPACITY:
 380                ret = rn5t618_battery_capacity(info, val);
 381                break;
 382        case POWER_SUPPLY_PROP_TEMP:
 383                ret = rn5t618_battery_temp(info, val);
 384                break;
 385        case POWER_SUPPLY_PROP_TIME_TO_EMPTY_NOW:
 386                ret = rn5t618_battery_tte(info, val);
 387                break;
 388        case POWER_SUPPLY_PROP_TIME_TO_FULL_NOW:
 389                ret = rn5t618_battery_ttf(info, val);
 390                break;
 391        case POWER_SUPPLY_PROP_TECHNOLOGY:
 392                val->intval = POWER_SUPPLY_TECHNOLOGY_LION;
 393                break;
 394        case POWER_SUPPLY_PROP_CHARGE_CONTROL_LIMIT:
 395                ret = rn5t618_battery_get_current_limit(info, val);
 396                break;
 397        case POWER_SUPPLY_PROP_CHARGE_FULL:
 398                ret = rn5t618_battery_charge_full(info, val);
 399                break;
 400        case POWER_SUPPLY_PROP_CHARGE_NOW:
 401                ret = rn5t618_battery_charge_now(info, val);
 402                break;
 403        default:
 404                return -EINVAL;
 405        }
 406
 407        return ret;
 408}
 409
 410static int rn5t618_battery_set_property(struct power_supply *psy,
 411                                        enum power_supply_property psp,
 412                                        const union power_supply_propval *val)
 413{
 414        struct rn5t618_power_info *info = power_supply_get_drvdata(psy);
 415
 416        switch (psp) {
 417        case POWER_SUPPLY_PROP_CHARGE_CONTROL_LIMIT:
 418                return rn5t618_battery_set_current_limit(info, val);
 419        default:
 420                return -EINVAL;
 421        }
 422}
 423
 424static int rn5t618_battery_property_is_writeable(struct power_supply *psy,
 425                                                enum power_supply_property psp)
 426{
 427        switch (psp) {
 428        case POWER_SUPPLY_PROP_CHARGE_CONTROL_LIMIT:
 429                return true;
 430        default:
 431                return false;
 432        }
 433}
 434
 435static int rn5t618_adp_get_property(struct power_supply *psy,
 436                                    enum power_supply_property psp,
 437                                    union power_supply_propval *val)
 438{
 439        struct rn5t618_power_info *info = power_supply_get_drvdata(psy);
 440        unsigned int chgstate;
 441        unsigned int regval;
 442        bool online;
 443        int ret;
 444
 445        ret = regmap_read(info->rn5t618->regmap, RN5T618_CHGSTATE, &chgstate);
 446        if (ret)
 447                return ret;
 448
 449        online = !!(chgstate & CHG_STATE_ADP_INPUT);
 450
 451        switch (psp) {
 452        case POWER_SUPPLY_PROP_ONLINE:
 453                val->intval = online;
 454                break;
 455        case POWER_SUPPLY_PROP_STATUS:
 456                if (!online) {
 457                        val->intval = POWER_SUPPLY_STATUS_NOT_CHARGING;
 458                        break;
 459                }
 460                val->intval = rn5t618_decode_status(chgstate);
 461                if (val->intval != POWER_SUPPLY_STATUS_CHARGING)
 462                        val->intval = POWER_SUPPLY_STATUS_NOT_CHARGING;
 463
 464                break;
 465        case POWER_SUPPLY_PROP_INPUT_CURRENT_LIMIT:
 466                ret = regmap_read(info->rn5t618->regmap,
 467                                  RN5T618_REGISET1, &regval);
 468                if (ret < 0)
 469                        return ret;
 470
 471                val->intval = FROM_CUR_REG(regval);
 472                break;
 473        case POWER_SUPPLY_PROP_VOLTAGE_NOW:
 474                if (!info->channel_vadp)
 475                        return -ENODATA;
 476
 477                ret = iio_read_channel_processed_scale(info->channel_vadp, &val->intval, 1000);
 478                if (ret < 0)
 479                        return ret;
 480
 481                break;
 482        default:
 483                return -EINVAL;
 484        }
 485
 486        return 0;
 487}
 488
 489static int rn5t618_adp_set_property(struct power_supply *psy,
 490                                    enum power_supply_property psp,
 491                                    const union power_supply_propval *val)
 492{
 493        struct rn5t618_power_info *info = power_supply_get_drvdata(psy);
 494        int ret;
 495
 496        switch (psp) {
 497        case POWER_SUPPLY_PROP_INPUT_CURRENT_LIMIT:
 498                if (val->intval > ADP_MAX_CUR)
 499                        return -EINVAL;
 500
 501                if (val->intval < CHG_MIN_CUR)
 502                        return -EINVAL;
 503
 504                ret = regmap_write(info->rn5t618->regmap, RN5T618_REGISET1,
 505                                   TO_CUR_REG(val->intval));
 506                if (ret < 0)
 507                        return ret;
 508
 509                break;
 510        default:
 511                return -EINVAL;
 512        }
 513
 514        return 0;
 515}
 516
 517static int rn5t618_adp_property_is_writeable(struct power_supply *psy,
 518                                             enum power_supply_property psp)
 519{
 520        switch (psp) {
 521        case POWER_SUPPLY_PROP_INPUT_CURRENT_LIMIT:
 522                return true;
 523        default:
 524                return false;
 525        }
 526}
 527
 528static int rc5t619_usb_get_type(struct rn5t618_power_info *info,
 529                                union power_supply_propval *val)
 530{
 531        unsigned int regval;
 532        int ret;
 533
 534        ret = regmap_read(info->rn5t618->regmap, RN5T618_GCHGDET, &regval);
 535        if (ret < 0)
 536                return ret;
 537
 538        switch (regval & GCHGDET_TYPE_MASK) {
 539        case GCHGDET_TYPE_SDP:
 540                val->intval = POWER_SUPPLY_USB_TYPE_SDP;
 541                break;
 542        case GCHGDET_TYPE_CDP:
 543                val->intval = POWER_SUPPLY_USB_TYPE_CDP;
 544                break;
 545        case GCHGDET_TYPE_DCP:
 546                val->intval = POWER_SUPPLY_USB_TYPE_DCP;
 547                break;
 548        default:
 549                val->intval = POWER_SUPPLY_USB_TYPE_UNKNOWN;
 550        }
 551
 552        return 0;
 553}
 554
 555static int rn5t618_usb_get_property(struct power_supply *psy,
 556                                    enum power_supply_property psp,
 557                                    union power_supply_propval *val)
 558{
 559        struct rn5t618_power_info *info = power_supply_get_drvdata(psy);
 560        unsigned int chgstate;
 561        unsigned int regval;
 562        bool online;
 563        int ret;
 564
 565        ret = regmap_read(info->rn5t618->regmap, RN5T618_CHGSTATE, &chgstate);
 566        if (ret)
 567                return ret;
 568
 569        online = !!(chgstate & CHG_STATE_USB_INPUT);
 570
 571        switch (psp) {
 572        case POWER_SUPPLY_PROP_ONLINE:
 573                val->intval = online;
 574                break;
 575        case POWER_SUPPLY_PROP_STATUS:
 576                if (!online) {
 577                        val->intval = POWER_SUPPLY_STATUS_NOT_CHARGING;
 578                        break;
 579                }
 580                val->intval = rn5t618_decode_status(chgstate);
 581                if (val->intval != POWER_SUPPLY_STATUS_CHARGING)
 582                        val->intval = POWER_SUPPLY_STATUS_NOT_CHARGING;
 583
 584                break;
 585        case POWER_SUPPLY_PROP_USB_TYPE:
 586                if (!online || (info->rn5t618->variant != RC5T619))
 587                        return -ENODATA;
 588
 589                return rc5t619_usb_get_type(info, val);
 590        case POWER_SUPPLY_PROP_INPUT_CURRENT_LIMIT:
 591                ret = regmap_read(info->rn5t618->regmap, RN5T618_CHGCTL1,
 592                                  &regval);
 593                if (ret < 0)
 594                        return ret;
 595
 596                val->intval = 0;
 597                if (regval & 2) {
 598                        ret = regmap_read(info->rn5t618->regmap,
 599                                          RN5T618_REGISET2,
 600                                          &regval);
 601                        if (ret < 0)
 602                                return ret;
 603
 604                        val->intval = FROM_CUR_REG(regval);
 605                }
 606                break;
 607        case POWER_SUPPLY_PROP_VOLTAGE_NOW:
 608                if (!info->channel_vusb)
 609                        return -ENODATA;
 610
 611                ret = iio_read_channel_processed_scale(info->channel_vusb, &val->intval, 1000);
 612                if (ret < 0)
 613                        return ret;
 614
 615                break;
 616        default:
 617                return -EINVAL;
 618        }
 619
 620        return 0;
 621}
 622
 623static int rn5t618_usb_set_property(struct power_supply *psy,
 624                                    enum power_supply_property psp,
 625                                    const union power_supply_propval *val)
 626{
 627        struct rn5t618_power_info *info = power_supply_get_drvdata(psy);
 628        int ret;
 629
 630        switch (psp) {
 631        case POWER_SUPPLY_PROP_INPUT_CURRENT_LIMIT:
 632                if (val->intval > USB_MAX_CUR)
 633                        return -EINVAL;
 634
 635                if (val->intval < CHG_MIN_CUR)
 636                        return -EINVAL;
 637
 638                ret = regmap_write(info->rn5t618->regmap, RN5T618_REGISET2,
 639                                   0xE0 | TO_CUR_REG(val->intval));
 640                if (ret < 0)
 641                        return ret;
 642
 643                break;
 644        default:
 645                return -EINVAL;
 646        }
 647
 648        return 0;
 649}
 650
 651static int rn5t618_usb_property_is_writeable(struct power_supply *psy,
 652                                             enum power_supply_property psp)
 653{
 654        switch (psp) {
 655        case POWER_SUPPLY_PROP_INPUT_CURRENT_LIMIT:
 656                return true;
 657        default:
 658                return false;
 659        }
 660}
 661
 662static const struct power_supply_desc rn5t618_battery_desc = {
 663        .name                   = "rn5t618-battery",
 664        .type                   = POWER_SUPPLY_TYPE_BATTERY,
 665        .properties             = rn5t618_battery_props,
 666        .num_properties         = ARRAY_SIZE(rn5t618_battery_props),
 667        .get_property           = rn5t618_battery_get_property,
 668        .set_property           = rn5t618_battery_set_property,
 669        .property_is_writeable  = rn5t618_battery_property_is_writeable,
 670};
 671
 672static const struct power_supply_desc rn5t618_adp_desc = {
 673        .name                   = "rn5t618-adp",
 674        .type                   = POWER_SUPPLY_TYPE_MAINS,
 675        .properties             = rn5t618_adp_props,
 676        .num_properties         = ARRAY_SIZE(rn5t618_adp_props),
 677        .get_property           = rn5t618_adp_get_property,
 678        .set_property           = rn5t618_adp_set_property,
 679        .property_is_writeable  = rn5t618_adp_property_is_writeable,
 680};
 681
 682static const struct power_supply_desc rn5t618_usb_desc = {
 683        .name                   = "rn5t618-usb",
 684        .type                   = POWER_SUPPLY_TYPE_USB,
 685        .usb_types              = rn5t618_usb_types,
 686        .num_usb_types          = ARRAY_SIZE(rn5t618_usb_types),
 687        .properties             = rn5t618_usb_props,
 688        .num_properties         = ARRAY_SIZE(rn5t618_usb_props),
 689        .get_property           = rn5t618_usb_get_property,
 690        .set_property           = rn5t618_usb_set_property,
 691        .property_is_writeable  = rn5t618_usb_property_is_writeable,
 692};
 693
 694static irqreturn_t rn5t618_charger_irq(int irq, void *data)
 695{
 696        struct device *dev = data;
 697        struct rn5t618_power_info *info = dev_get_drvdata(dev);
 698
 699        unsigned int ctrl, stat1, stat2, err;
 700
 701        regmap_read(info->rn5t618->regmap, RN5T618_CHGERR_IRR, &err);
 702        regmap_read(info->rn5t618->regmap, RN5T618_CHGCTRL_IRR, &ctrl);
 703        regmap_read(info->rn5t618->regmap, RN5T618_CHGSTAT_IRR1, &stat1);
 704        regmap_read(info->rn5t618->regmap, RN5T618_CHGSTAT_IRR2, &stat2);
 705
 706        regmap_write(info->rn5t618->regmap, RN5T618_CHGERR_IRR, 0);
 707        regmap_write(info->rn5t618->regmap, RN5T618_CHGCTRL_IRR, 0);
 708        regmap_write(info->rn5t618->regmap, RN5T618_CHGSTAT_IRR1, 0);
 709        regmap_write(info->rn5t618->regmap, RN5T618_CHGSTAT_IRR2, 0);
 710
 711        dev_dbg(dev, "chgerr: %x chgctrl: %x chgstat: %x chgstat2: %x\n",
 712                err, ctrl, stat1, stat2);
 713
 714        power_supply_changed(info->usb);
 715        power_supply_changed(info->adp);
 716        power_supply_changed(info->battery);
 717
 718        return IRQ_HANDLED;
 719}
 720
 721static int rn5t618_power_probe(struct platform_device *pdev)
 722{
 723        int ret = 0;
 724        unsigned int v;
 725        struct power_supply_config psy_cfg = {};
 726        struct rn5t618_power_info *info;
 727
 728        info = devm_kzalloc(&pdev->dev, sizeof(*info), GFP_KERNEL);
 729        if (!info)
 730                return -ENOMEM;
 731
 732        info->pdev = pdev;
 733        info->rn5t618 = dev_get_drvdata(pdev->dev.parent);
 734        info->irq = -1;
 735
 736        platform_set_drvdata(pdev, info);
 737
 738        info->channel_vusb = devm_iio_channel_get(&pdev->dev, "vusb");
 739        if (IS_ERR(info->channel_vusb)) {
 740                if (PTR_ERR(info->channel_vusb) == -ENODEV)
 741                        return -EPROBE_DEFER;
 742                return PTR_ERR(info->channel_vusb);
 743        }
 744
 745        info->channel_vadp = devm_iio_channel_get(&pdev->dev, "vadp");
 746        if (IS_ERR(info->channel_vadp)) {
 747                if (PTR_ERR(info->channel_vadp) == -ENODEV)
 748                        return -EPROBE_DEFER;
 749                return PTR_ERR(info->channel_vadp);
 750        }
 751
 752        ret = regmap_read(info->rn5t618->regmap, RN5T618_CONTROL, &v);
 753        if (ret)
 754                return ret;
 755
 756        if (!(v & FG_ENABLE)) {
 757                /* E.g. the vendor kernels of various Kobo and Tolino Ebook
 758                 * readers disable the fuel gauge on shutdown. If a kernel
 759                 * without fuel gauge support is booted after that, the fuel
 760                 * gauge will get decalibrated.
 761                 */
 762                dev_info(&pdev->dev, "Fuel gauge not enabled, enabling now\n");
 763                dev_info(&pdev->dev, "Expect imprecise results\n");
 764                regmap_update_bits(info->rn5t618->regmap, RN5T618_CONTROL,
 765                                   FG_ENABLE, FG_ENABLE);
 766        }
 767
 768        psy_cfg.drv_data = info;
 769        info->battery = devm_power_supply_register(&pdev->dev,
 770                                                   &rn5t618_battery_desc,
 771                                                   &psy_cfg);
 772        if (IS_ERR(info->battery)) {
 773                ret = PTR_ERR(info->battery);
 774                dev_err(&pdev->dev, "failed to register battery: %d\n", ret);
 775                return ret;
 776        }
 777
 778        info->adp = devm_power_supply_register(&pdev->dev,
 779                                               &rn5t618_adp_desc,
 780                                               &psy_cfg);
 781        if (IS_ERR(info->adp)) {
 782                ret = PTR_ERR(info->adp);
 783                dev_err(&pdev->dev, "failed to register adp: %d\n", ret);
 784                return ret;
 785        }
 786
 787        info->usb = devm_power_supply_register(&pdev->dev,
 788                                               &rn5t618_usb_desc,
 789                                               &psy_cfg);
 790        if (IS_ERR(info->usb)) {
 791                ret = PTR_ERR(info->usb);
 792                dev_err(&pdev->dev, "failed to register usb: %d\n", ret);
 793                return ret;
 794        }
 795
 796        if (info->rn5t618->irq_data)
 797                info->irq = regmap_irq_get_virq(info->rn5t618->irq_data,
 798                                                RN5T618_IRQ_CHG);
 799
 800        if (info->irq < 0)
 801                info->irq = -1;
 802        else {
 803                ret = devm_request_threaded_irq(&pdev->dev, info->irq, NULL,
 804                                                rn5t618_charger_irq,
 805                                                IRQF_ONESHOT,
 806                                                "rn5t618_power",
 807                                                &pdev->dev);
 808
 809                if (ret < 0) {
 810                        dev_err(&pdev->dev, "request IRQ:%d fail\n",
 811                                info->irq);
 812                        info->irq = -1;
 813                }
 814        }
 815
 816        return 0;
 817}
 818
 819static struct platform_driver rn5t618_power_driver = {
 820        .driver = {
 821                .name   = "rn5t618-power",
 822        },
 823        .probe = rn5t618_power_probe,
 824};
 825
 826module_platform_driver(rn5t618_power_driver);
 827MODULE_ALIAS("platform:rn5t618-power");
 828MODULE_DESCRIPTION("Power supply driver for RICOH RN5T618");
 829MODULE_LICENSE("GPL");
 830