linux/drivers/power/supply/max1721x_battery.c
<<
>>
Prefs
   1/*
   2 * 1-Wire implementation for Maxim Semiconductor
   3 * MAX7211/MAX17215 stanalone fuel gauge chip
   4 *
   5 * Copyright (C) 2017 Radioavionica Corporation
   6 * Author: Alex A. Mihaylov <minimumlaw@rambler.ru>
   7 *
   8 * Use consistent with the GNU GPL is permitted,
   9 * provided that this copyright notice is
  10 * preserved in its entirety in all copies and derived works.
  11 *
  12 */
  13
  14#include <linux/module.h>
  15#include <linux/slab.h>
  16#include <linux/w1.h>
  17#include <linux/regmap.h>
  18#include <linux/power_supply.h>
  19
  20#define W1_MAX1721X_FAMILY_ID           0x26
  21#define DEF_DEV_NAME_MAX17211           "MAX17211"
  22#define DEF_DEV_NAME_MAX17215           "MAX17215"
  23#define DEF_DEV_NAME_UNKNOWN            "UNKNOWN"
  24#define DEF_MFG_NAME                    "MAXIM"
  25
  26#define PSY_MAX_NAME_LEN        32
  27
  28/* Number of valid register addresses in W1 mode */
  29#define MAX1721X_MAX_REG_NR     0x1EF
  30
  31/* Factory settings (nonvilatile registers) (W1 specific) */
  32#define MAX1721X_REG_NRSENSE    0x1CF   /* RSense in 10^-5 Ohm */
  33/* Strings */
  34#define MAX1721X_REG_MFG_STR    0x1CC
  35#define MAX1721X_REG_MFG_NUMB   3
  36#define MAX1721X_REG_DEV_STR    0x1DB
  37#define MAX1721X_REG_DEV_NUMB   5
  38/* HEX Strings */
  39#define MAX1721X_REG_SER_HEX    0x1D8
  40
  41/* MAX172XX Output Registers for W1 chips */
  42#define MAX172XX_REG_STATUS     0x000   /* status reg */
  43#define MAX172XX_BAT_PRESENT    (1<<4)  /* battery connected bit */
  44#define MAX172XX_REG_DEVNAME    0x021   /* chip config */
  45#define MAX172XX_DEV_MASK       0x000F  /* chip type mask */
  46#define MAX172X1_DEV            0x0001
  47#define MAX172X5_DEV            0x0005
  48#define MAX172XX_REG_TEMP       0x008   /* Temperature */
  49#define MAX172XX_REG_BATT       0x0DA   /* Battery voltage */
  50#define MAX172XX_REG_CURRENT    0x00A   /* Actual current */
  51#define MAX172XX_REG_AVGCURRENT 0x00B   /* Average current */
  52#define MAX172XX_REG_REPSOC     0x006   /* Percentage of charge */
  53#define MAX172XX_REG_DESIGNCAP  0x018   /* Design capacity */
  54#define MAX172XX_REG_REPCAP     0x005   /* Average capacity */
  55#define MAX172XX_REG_TTE        0x011   /* Time to empty */
  56#define MAX172XX_REG_TTF        0x020   /* Time to full */
  57
  58struct max17211_device_info {
  59        char name[PSY_MAX_NAME_LEN];
  60        struct power_supply *bat;
  61        struct power_supply_desc bat_desc;
  62        struct device *w1_dev;
  63        struct regmap *regmap;
  64        /* battery design format */
  65        unsigned int rsense; /* in tenths uOhm */
  66        char DeviceName[2 * MAX1721X_REG_DEV_NUMB + 1];
  67        char ManufacturerName[2 * MAX1721X_REG_MFG_NUMB + 1];
  68        char SerialNumber[13]; /* see get_sn_str() later for comment */
  69};
  70
  71/* Convert regs value to power_supply units */
  72
  73static inline int max172xx_time_to_ps(unsigned int reg)
  74{
  75        return reg * 5625 / 1000;       /* in sec. */
  76}
  77
  78static inline int max172xx_percent_to_ps(unsigned int reg)
  79{
  80        return reg / 256;       /* in percent from 0 to 100 */
  81}
  82
  83static inline int max172xx_voltage_to_ps(unsigned int reg)
  84{
  85        return reg * 1250;      /* in uV */
  86}
  87
  88static inline int max172xx_capacity_to_ps(unsigned int reg)
  89{
  90        return reg * 500;       /* in uAh */
  91}
  92
  93/*
  94 * Current and temperature is signed values, so unsigned regs
  95 * value must be converted to signed type
  96 */
  97
  98static inline int max172xx_temperature_to_ps(unsigned int reg)
  99{
 100        int val = (int16_t)(reg);
 101
 102        return val * 10 / 256; /* in tenths of deg. C */
 103}
 104
 105/*
 106 * Calculating current registers resolution:
 107 *
 108 * RSense stored in 10^-5 Ohm, so mesaurment voltage must be
 109 * in 10^-11 Volts for get current in uA.
 110 * 16 bit current reg fullscale +/-51.2mV is 102400 uV.
 111 * So: 102400 / 65535 * 10^5 = 156252
 112 */
 113static inline int max172xx_current_to_voltage(unsigned int reg)
 114{
 115        int val = (int16_t)(reg);
 116
 117        return val * 156252;
 118}
 119
 120
 121static inline struct max17211_device_info *
 122to_device_info(struct power_supply *psy)
 123{
 124        return power_supply_get_drvdata(psy);
 125}
 126
 127static int max1721x_battery_get_property(struct power_supply *psy,
 128        enum power_supply_property psp,
 129        union power_supply_propval *val)
 130{
 131        struct max17211_device_info *info = to_device_info(psy);
 132        unsigned int reg = 0;
 133        int ret = 0;
 134
 135        switch (psp) {
 136        case POWER_SUPPLY_PROP_PRESENT:
 137                /*
 138                 * POWER_SUPPLY_PROP_PRESENT will always readable via
 139                 * sysfs interface. Value return 0 if battery not
 140                 * present or unaccesable via W1.
 141                 */
 142                val->intval =
 143                        regmap_read(info->regmap, MAX172XX_REG_STATUS,
 144                        &reg) ? 0 : !(reg & MAX172XX_BAT_PRESENT);
 145                break;
 146        case POWER_SUPPLY_PROP_CAPACITY:
 147                ret = regmap_read(info->regmap, MAX172XX_REG_REPSOC, &reg);
 148                val->intval = max172xx_percent_to_ps(reg);
 149                break;
 150        case POWER_SUPPLY_PROP_VOLTAGE_NOW:
 151                ret = regmap_read(info->regmap, MAX172XX_REG_BATT, &reg);
 152                val->intval = max172xx_voltage_to_ps(reg);
 153                break;
 154        case POWER_SUPPLY_PROP_CHARGE_FULL_DESIGN:
 155                ret = regmap_read(info->regmap, MAX172XX_REG_DESIGNCAP, &reg);
 156                val->intval = max172xx_capacity_to_ps(reg);
 157                break;
 158        case POWER_SUPPLY_PROP_CHARGE_AVG:
 159                ret = regmap_read(info->regmap, MAX172XX_REG_REPCAP, &reg);
 160                val->intval = max172xx_capacity_to_ps(reg);
 161                break;
 162        case POWER_SUPPLY_PROP_TIME_TO_EMPTY_AVG:
 163                ret = regmap_read(info->regmap, MAX172XX_REG_TTE, &reg);
 164                val->intval = max172xx_time_to_ps(reg);
 165                break;
 166        case POWER_SUPPLY_PROP_TIME_TO_FULL_AVG:
 167                ret = regmap_read(info->regmap, MAX172XX_REG_TTF, &reg);
 168                val->intval = max172xx_time_to_ps(reg);
 169                break;
 170        case POWER_SUPPLY_PROP_TEMP:
 171                ret = regmap_read(info->regmap, MAX172XX_REG_TEMP, &reg);
 172                val->intval = max172xx_temperature_to_ps(reg);
 173                break;
 174        /* We need signed current, so must cast info->rsense to signed type */
 175        case POWER_SUPPLY_PROP_CURRENT_NOW:
 176                ret = regmap_read(info->regmap, MAX172XX_REG_CURRENT, &reg);
 177                val->intval =
 178                        max172xx_current_to_voltage(reg) / (int)info->rsense;
 179                break;
 180        case POWER_SUPPLY_PROP_CURRENT_AVG:
 181                ret = regmap_read(info->regmap, MAX172XX_REG_AVGCURRENT, &reg);
 182                val->intval =
 183                        max172xx_current_to_voltage(reg) / (int)info->rsense;
 184                break;
 185        /*
 186         * Strings already received and inited by probe.
 187         * We do dummy read for check battery still available.
 188         */
 189        case POWER_SUPPLY_PROP_MODEL_NAME:
 190                ret = regmap_read(info->regmap, MAX1721X_REG_DEV_STR, &reg);
 191                val->strval = info->DeviceName;
 192                break;
 193        case POWER_SUPPLY_PROP_MANUFACTURER:
 194                ret = regmap_read(info->regmap, MAX1721X_REG_MFG_STR, &reg);
 195                val->strval = info->ManufacturerName;
 196                break;
 197        case POWER_SUPPLY_PROP_SERIAL_NUMBER:
 198                ret = regmap_read(info->regmap, MAX1721X_REG_SER_HEX, &reg);
 199                val->strval = info->SerialNumber;
 200                break;
 201        default:
 202                ret = -EINVAL;
 203        }
 204
 205        return ret;
 206}
 207
 208static enum power_supply_property max1721x_battery_props[] = {
 209        /* int */
 210        POWER_SUPPLY_PROP_PRESENT,
 211        POWER_SUPPLY_PROP_CAPACITY,
 212        POWER_SUPPLY_PROP_VOLTAGE_NOW,
 213        POWER_SUPPLY_PROP_CHARGE_FULL_DESIGN,
 214        POWER_SUPPLY_PROP_CHARGE_AVG,
 215        POWER_SUPPLY_PROP_TIME_TO_EMPTY_AVG,
 216        POWER_SUPPLY_PROP_TIME_TO_FULL_AVG,
 217        POWER_SUPPLY_PROP_TEMP,
 218        POWER_SUPPLY_PROP_CURRENT_NOW,
 219        POWER_SUPPLY_PROP_CURRENT_AVG,
 220        /* strings */
 221        POWER_SUPPLY_PROP_MODEL_NAME,
 222        POWER_SUPPLY_PROP_MANUFACTURER,
 223        POWER_SUPPLY_PROP_SERIAL_NUMBER,
 224};
 225
 226static int get_string(struct max17211_device_info *info,
 227                        uint16_t reg, uint8_t nr, char *str)
 228{
 229        unsigned int val;
 230
 231        if (!str || !(reg == MAX1721X_REG_MFG_STR ||
 232                        reg == MAX1721X_REG_DEV_STR))
 233                return -EFAULT;
 234
 235        while (nr--) {
 236                if (regmap_read(info->regmap, reg++, &val))
 237                        return -EFAULT;
 238                *str++ = val>>8 & 0x00FF;
 239                *str++ = val & 0x00FF;
 240        }
 241        return 0;
 242}
 243
 244/* Maxim say: Serial number is a hex string up to 12 hex characters */
 245static int get_sn_string(struct max17211_device_info *info, char *str)
 246{
 247        unsigned int val[3];
 248
 249        if (!str)
 250                return -EFAULT;
 251
 252        if (regmap_read(info->regmap, MAX1721X_REG_SER_HEX, &val[0]))
 253                return -EFAULT;
 254        if (regmap_read(info->regmap, MAX1721X_REG_SER_HEX + 1, &val[1]))
 255                return -EFAULT;
 256        if (regmap_read(info->regmap, MAX1721X_REG_SER_HEX + 2, &val[2]))
 257                return -EFAULT;
 258
 259        snprintf(str, 13, "%04X%04X%04X", val[0], val[1], val[2]);
 260        return 0;
 261}
 262
 263/*
 264 * MAX1721x registers description for w1-regmap
 265 */
 266static const struct regmap_range max1721x_allow_range[] = {
 267        regmap_reg_range(0, 0xDF),      /* volatile data */
 268        regmap_reg_range(0x180, 0x1DF), /* non-volatile memory */
 269        regmap_reg_range(0x1E0, 0x1EF), /* non-volatile history (unused) */
 270};
 271
 272static const struct regmap_range max1721x_deny_range[] = {
 273        /* volatile data unused registers */
 274        regmap_reg_range(0x24, 0x26),
 275        regmap_reg_range(0x30, 0x31),
 276        regmap_reg_range(0x33, 0x34),
 277        regmap_reg_range(0x37, 0x37),
 278        regmap_reg_range(0x3B, 0x3C),
 279        regmap_reg_range(0x40, 0x41),
 280        regmap_reg_range(0x43, 0x44),
 281        regmap_reg_range(0x47, 0x49),
 282        regmap_reg_range(0x4B, 0x4C),
 283        regmap_reg_range(0x4E, 0xAF),
 284        regmap_reg_range(0xB1, 0xB3),
 285        regmap_reg_range(0xB5, 0xB7),
 286        regmap_reg_range(0xBF, 0xD0),
 287        regmap_reg_range(0xDB, 0xDB),
 288        /* hole between volatile and non-volatile registers */
 289        regmap_reg_range(0xE0, 0x17F),
 290};
 291
 292static const struct regmap_access_table max1721x_regs = {
 293        .yes_ranges     = max1721x_allow_range,
 294        .n_yes_ranges   = ARRAY_SIZE(max1721x_allow_range),
 295        .no_ranges      = max1721x_deny_range,
 296        .n_no_ranges    = ARRAY_SIZE(max1721x_deny_range),
 297};
 298
 299/*
 300 * Model Gauge M5 Algorithm output register
 301 * Volatile data (must not be cached)
 302 */
 303static const struct regmap_range max1721x_volatile_allow[] = {
 304        regmap_reg_range(0, 0xDF),
 305};
 306
 307static const struct regmap_access_table max1721x_volatile_regs = {
 308        .yes_ranges     = max1721x_volatile_allow,
 309        .n_yes_ranges   = ARRAY_SIZE(max1721x_volatile_allow),
 310};
 311
 312/*
 313 * W1-regmap config
 314 */
 315static const struct regmap_config max1721x_regmap_w1_config = {
 316        .reg_bits = 16,
 317        .val_bits = 16,
 318        .rd_table = &max1721x_regs,
 319        .volatile_table = &max1721x_volatile_regs,
 320        .max_register = MAX1721X_MAX_REG_NR,
 321};
 322
 323static int devm_w1_max1721x_add_device(struct w1_slave *sl)
 324{
 325        struct power_supply_config psy_cfg = {};
 326        struct max17211_device_info *info;
 327
 328        info = devm_kzalloc(&sl->dev, sizeof(*info), GFP_KERNEL);
 329        if (!info)
 330                return -ENOMEM;
 331
 332        sl->family_data = (void *)info;
 333        info->w1_dev = &sl->dev;
 334
 335        /*
 336         * power_supply class battery name translated from W1 slave device
 337         * unical ID (look like 26-0123456789AB) to "max1721x-0123456789AB\0"
 338         * so, 26 (device family) correcpondent to max1721x devices.
 339         * Device name still unical for any numbers connected devices.
 340         */
 341        snprintf(info->name, sizeof(info->name),
 342                "max1721x-%012X", (unsigned int)sl->reg_num.id);
 343        info->bat_desc.name = info->name;
 344
 345        /*
 346         * FixMe: battery device name exceed max len for thermal_zone device
 347         * name and translation to thermal_zone must be disabled.
 348         */
 349        info->bat_desc.no_thermal = true;
 350        info->bat_desc.type = POWER_SUPPLY_TYPE_BATTERY;
 351        info->bat_desc.properties = max1721x_battery_props;
 352        info->bat_desc.num_properties = ARRAY_SIZE(max1721x_battery_props);
 353        info->bat_desc.get_property = max1721x_battery_get_property;
 354        psy_cfg.drv_data = info;
 355
 356        /* regmap init */
 357        info->regmap = devm_regmap_init_w1(info->w1_dev,
 358                                        &max1721x_regmap_w1_config);
 359        if (IS_ERR(info->regmap)) {
 360                int err = PTR_ERR(info->regmap);
 361
 362                dev_err(info->w1_dev, "Failed to allocate register map: %d\n",
 363                        err);
 364                return err;
 365        }
 366
 367        /* rsense init */
 368        info->rsense = 0;
 369        if (regmap_read(info->regmap, MAX1721X_REG_NRSENSE, &info->rsense)) {
 370                dev_err(info->w1_dev, "Can't read RSense. Hardware error.\n");
 371                return -ENODEV;
 372        }
 373
 374        if (!info->rsense) {
 375                dev_warn(info->w1_dev, "RSense not calibrated, set 10 mOhms!\n");
 376                info->rsense = 1000; /* in regs in 10^-5 */
 377        }
 378        dev_info(info->w1_dev, "RSense: %d mOhms.\n", info->rsense / 100);
 379
 380        if (get_string(info, MAX1721X_REG_MFG_STR,
 381                        MAX1721X_REG_MFG_NUMB, info->ManufacturerName)) {
 382                dev_err(info->w1_dev, "Can't read manufacturer. Hardware error.\n");
 383                return -ENODEV;
 384        }
 385
 386        if (!info->ManufacturerName[0])
 387                strncpy(info->ManufacturerName, DEF_MFG_NAME,
 388                        2 * MAX1721X_REG_MFG_NUMB);
 389
 390        if (get_string(info, MAX1721X_REG_DEV_STR,
 391                        MAX1721X_REG_DEV_NUMB, info->DeviceName)) {
 392                dev_err(info->w1_dev, "Can't read device. Hardware error.\n");
 393                return -ENODEV;
 394        }
 395        if (!info->DeviceName[0]) {
 396                unsigned int dev_name;
 397
 398                if (regmap_read(info->regmap,
 399                                MAX172XX_REG_DEVNAME, &dev_name)) {
 400                        dev_err(info->w1_dev, "Can't read device name reg.\n");
 401                        return -ENODEV;
 402                }
 403
 404                switch (dev_name & MAX172XX_DEV_MASK) {
 405                case MAX172X1_DEV:
 406                        strncpy(info->DeviceName, DEF_DEV_NAME_MAX17211,
 407                                2 * MAX1721X_REG_DEV_NUMB);
 408                        break;
 409                case MAX172X5_DEV:
 410                        strncpy(info->DeviceName, DEF_DEV_NAME_MAX17215,
 411                                2 * MAX1721X_REG_DEV_NUMB);
 412                        break;
 413                default:
 414                        strncpy(info->DeviceName, DEF_DEV_NAME_UNKNOWN,
 415                                2 * MAX1721X_REG_DEV_NUMB);
 416                }
 417        }
 418
 419        if (get_sn_string(info, info->SerialNumber)) {
 420                dev_err(info->w1_dev, "Can't read serial. Hardware error.\n");
 421                return -ENODEV;
 422        }
 423
 424        info->bat = devm_power_supply_register(&sl->dev, &info->bat_desc,
 425                                                &psy_cfg);
 426        if (IS_ERR(info->bat)) {
 427                dev_err(info->w1_dev, "failed to register battery\n");
 428                return PTR_ERR(info->bat);
 429        }
 430
 431        return 0;
 432}
 433
 434static struct w1_family_ops w1_max1721x_fops = {
 435        .add_slave = devm_w1_max1721x_add_device,
 436};
 437
 438static struct w1_family w1_max1721x_family = {
 439        .fid = W1_MAX1721X_FAMILY_ID,
 440        .fops = &w1_max1721x_fops,
 441};
 442
 443module_w1_family(w1_max1721x_family);
 444
 445MODULE_LICENSE("GPL");
 446MODULE_AUTHOR("Alex A. Mihaylov <minimumlaw@rambler.ru>");
 447MODULE_DESCRIPTION("Maxim MAX17211/MAX17215 Fuel Gauage IC driver");
 448MODULE_ALIAS("w1-family-" __stringify(W1_MAX1721X_FAMILY_ID));
 449