root/drivers/power/supply/max1721x_battery.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. max172xx_time_to_ps
  2. max172xx_percent_to_ps
  3. max172xx_voltage_to_ps
  4. max172xx_capacity_to_ps
  5. max172xx_temperature_to_ps
  6. max172xx_current_to_voltage
  7. to_device_info
  8. max1721x_battery_get_property
  9. get_string
  10. get_sn_string
  11. devm_w1_max1721x_add_device

   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 
  58 struct 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 
  73 static inline int max172xx_time_to_ps(unsigned int reg)
  74 {
  75         return reg * 5625 / 1000;       /* in sec. */
  76 }
  77 
  78 static inline int max172xx_percent_to_ps(unsigned int reg)
  79 {
  80         return reg / 256;       /* in percent from 0 to 100 */
  81 }
  82 
  83 static inline int max172xx_voltage_to_ps(unsigned int reg)
  84 {
  85         return reg * 1250;      /* in uV */
  86 }
  87 
  88 static 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 
  98 static 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  */
 113 static inline int max172xx_current_to_voltage(unsigned int reg)
 114 {
 115         int val = (int16_t)(reg);
 116 
 117         return val * 156252;
 118 }
 119 
 120 
 121 static inline struct max17211_device_info *
 122 to_device_info(struct power_supply *psy)
 123 {
 124         return power_supply_get_drvdata(psy);
 125 }
 126 
 127 static 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 
 208 static 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 
 226 static 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 */
 245 static 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  */
 266 static 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 
 272 static 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 
 292 static 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  */
 303 static const struct regmap_range max1721x_volatile_allow[] = {
 304         regmap_reg_range(0, 0xDF),
 305 };
 306 
 307 static 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  */
 315 static 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 
 323 static 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 
 434 static struct w1_family_ops w1_max1721x_fops = {
 435         .add_slave = devm_w1_max1721x_add_device,
 436 };
 437 
 438 static struct w1_family w1_max1721x_family = {
 439         .fid = W1_MAX1721X_FAMILY_ID,
 440         .fops = &w1_max1721x_fops,
 441 };
 442 
 443 module_w1_family(w1_max1721x_family);
 444 
 445 MODULE_LICENSE("GPL");
 446 MODULE_AUTHOR("Alex A. Mihaylov <minimumlaw@rambler.ru>");
 447 MODULE_DESCRIPTION("Maxim MAX17211/MAX17215 Fuel Gauage IC driver");
 448 MODULE_ALIAS("w1-family-" __stringify(W1_MAX1721X_FAMILY_ID));

/* [<][>][^][v][top][bottom][index][help] */