Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-or-later
0002 /*
0003  *  Driver for Analog Devices (Linear Technology) LTC4162-L charger IC.
0004  *  Copyright (C) 2020, Topic Embedded Products
0005  */
0006 
0007 #include <linux/module.h>
0008 #include <linux/delay.h>
0009 #include <linux/of_device.h>
0010 #include <linux/pm_runtime.h>
0011 #include <linux/power_supply.h>
0012 #include <linux/i2c.h>
0013 #include <linux/regmap.h>
0014 
0015 /* Registers (names based on what datasheet uses) */
0016 #define LTC4162L_EN_LIMIT_ALERTS_REG        0x0D
0017 #define LTC4162L_EN_CHARGER_STATE_ALERTS_REG    0x0E
0018 #define LTC4162L_EN_CHARGE_STATUS_ALERTS_REG    0x0F
0019 #define LTC4162L_CONFIG_BITS_REG        0x14
0020 #define LTC4162L_IIN_LIMIT_TARGET       0x15
0021 #define LTC4162L_ARM_SHIP_MODE          0x19
0022 #define LTC4162L_CHARGE_CURRENT_SETTING     0X1A
0023 #define LTC4162L_VCHARGE_SETTING        0X1B
0024 #define LTC4162L_C_OVER_X_THRESHOLD     0x1C
0025 #define LTC4162L_MAX_CV_TIME            0X1D
0026 #define LTC4162L_MAX_CHARGE_TIME        0X1E
0027 #define LTC4162L_CHARGER_CONFIG_BITS        0x29
0028 #define LTC4162L_CHARGER_STATE          0x34
0029 #define LTC4162L_CHARGE_STATUS          0x35
0030 #define LTC4162L_LIMIT_ALERTS_REG       0x36
0031 #define LTC4162L_CHARGER_STATE_ALERTS_REG   0x37
0032 #define LTC4162L_CHARGE_STATUS_ALERTS_REG   0x38
0033 #define LTC4162L_SYSTEM_STATUS_REG      0x39
0034 #define LTC4162L_VBAT               0x3A
0035 #define LTC4162L_VIN                0x3B
0036 #define LTC4162L_VOUT               0x3C
0037 #define LTC4162L_IBAT               0x3D
0038 #define LTC4162L_IIN                0x3E
0039 #define LTC4162L_DIE_TEMPERATURE        0x3F
0040 #define LTC4162L_THERMISTOR_VOLTAGE     0x40
0041 #define LTC4162L_BSR                0x41
0042 #define LTC4162L_JEITA_REGION           0x42
0043 #define LTC4162L_CHEM_CELLS_REG         0x43
0044 #define LTC4162L_ICHARGE_DAC            0x44
0045 #define LTC4162L_VCHARGE_DAC            0x45
0046 #define LTC4162L_IIN_LIMIT_DAC          0x46
0047 #define LTC4162L_VBAT_FILT          0x47
0048 #define LTC4162L_INPUT_UNDERVOLTAGE_DAC     0x4B
0049 
0050 /* Enumeration as in datasheet. Individual bits are mutually exclusive. */
0051 enum ltc4162l_state {
0052     battery_detection = 2048,
0053     charger_suspended = 256,
0054     precharge = 128,   /* trickle on low bat voltage */
0055     cc_cv_charge = 64, /* normal charge */
0056     ntc_pause = 32,
0057     timer_term = 16,
0058     c_over_x_term = 8, /* battery is full */
0059     max_charge_time_fault = 4,
0060     bat_missing_fault = 2,
0061     bat_short_fault = 1
0062 };
0063 
0064 /* Individual bits are mutually exclusive. Only active in charging states.*/
0065 enum ltc4162l_charge_status {
0066     ilim_reg_active = 32,
0067     thermal_reg_active = 16,
0068     vin_uvcl_active = 8,
0069     iin_limit_active = 4,
0070     constant_current = 2,
0071     constant_voltage = 1,
0072     charger_off = 0
0073 };
0074 
0075 /* Magic number to write to ARM_SHIP_MODE register */
0076 #define LTC4162L_ARM_SHIP_MODE_MAGIC 21325
0077 
0078 struct ltc4162l_info {
0079     struct i2c_client   *client;
0080     struct regmap       *regmap;
0081     struct power_supply *charger;
0082     u32 rsnsb;  /* Series resistor that sets charge current, microOhm */
0083     u32 rsnsi;  /* Series resistor to measure input current, microOhm */
0084     u8 cell_count;  /* Number of connected cells, 0 while unknown */
0085 };
0086 
0087 static u8 ltc4162l_get_cell_count(struct ltc4162l_info *info)
0088 {
0089     int ret;
0090     unsigned int val;
0091 
0092     /* Once read successfully */
0093     if (info->cell_count)
0094         return info->cell_count;
0095 
0096     ret = regmap_read(info->regmap, LTC4162L_CHEM_CELLS_REG, &val);
0097     if (ret)
0098         return 0;
0099 
0100     /* Lower 4 bits is the cell count, or 0 if the chip doesn't know yet */
0101     val &= 0x0f;
0102     if (!val)
0103         return 0;
0104 
0105     /* Once determined, keep the value */
0106     info->cell_count = val;
0107 
0108     return val;
0109 };
0110 
0111 /* Convert enum value to POWER_SUPPLY_STATUS value */
0112 static int ltc4162l_state_decode(enum ltc4162l_state value)
0113 {
0114     switch (value) {
0115     case precharge:
0116     case cc_cv_charge:
0117         return POWER_SUPPLY_STATUS_CHARGING;
0118     case c_over_x_term:
0119         return POWER_SUPPLY_STATUS_FULL;
0120     case bat_missing_fault:
0121     case bat_short_fault:
0122         return POWER_SUPPLY_STATUS_UNKNOWN;
0123     default:
0124         return POWER_SUPPLY_STATUS_NOT_CHARGING;
0125     }
0126 };
0127 
0128 static int ltc4162l_get_status(struct ltc4162l_info *info,
0129                    union power_supply_propval *val)
0130 {
0131     unsigned int regval;
0132     int ret;
0133 
0134     ret = regmap_read(info->regmap, LTC4162L_CHARGER_STATE, &regval);
0135     if (ret) {
0136         dev_err(&info->client->dev, "Failed to read CHARGER_STATE\n");
0137         return ret;
0138     }
0139 
0140     val->intval = ltc4162l_state_decode(regval);
0141 
0142     return 0;
0143 }
0144 
0145 static int ltc4162l_charge_status_decode(enum ltc4162l_charge_status value)
0146 {
0147     if (!value)
0148         return POWER_SUPPLY_CHARGE_TYPE_NONE;
0149 
0150     /* constant voltage/current and input_current limit are "fast" modes */
0151     if (value <= iin_limit_active)
0152         return POWER_SUPPLY_CHARGE_TYPE_FAST;
0153 
0154     /* Anything that's not fast we'll return as trickle */
0155     return POWER_SUPPLY_CHARGE_TYPE_TRICKLE;
0156 }
0157 
0158 static int ltc4162l_get_charge_type(struct ltc4162l_info *info,
0159                     union power_supply_propval *val)
0160 {
0161     unsigned int regval;
0162     int ret;
0163 
0164     ret = regmap_read(info->regmap, LTC4162L_CHARGE_STATUS, &regval);
0165     if (ret)
0166         return ret;
0167 
0168     val->intval = ltc4162l_charge_status_decode(regval);
0169 
0170     return 0;
0171 }
0172 
0173 static int ltc4162l_state_to_health(enum ltc4162l_state value)
0174 {
0175     switch (value) {
0176     case ntc_pause:
0177         return POWER_SUPPLY_HEALTH_OVERHEAT;
0178     case timer_term:
0179         return POWER_SUPPLY_HEALTH_SAFETY_TIMER_EXPIRE;
0180     case max_charge_time_fault:
0181         return POWER_SUPPLY_HEALTH_WATCHDOG_TIMER_EXPIRE;
0182     case bat_missing_fault:
0183         return POWER_SUPPLY_HEALTH_UNSPEC_FAILURE;
0184     case bat_short_fault:
0185         return POWER_SUPPLY_HEALTH_DEAD;
0186     default:
0187         return POWER_SUPPLY_HEALTH_GOOD;
0188     }
0189 }
0190 
0191 static int ltc4162l_get_health(struct ltc4162l_info *info,
0192                    union power_supply_propval *val)
0193 {
0194     unsigned int regval;
0195     int ret;
0196 
0197     ret = regmap_read(info->regmap, LTC4162L_CHARGER_STATE, &regval);
0198     if (ret)
0199         return ret;
0200 
0201     val->intval = ltc4162l_state_to_health(regval);
0202 
0203     return 0;
0204 }
0205 
0206 static int ltc4162l_get_online(struct ltc4162l_info *info,
0207                    union power_supply_propval *val)
0208 {
0209     unsigned int regval;
0210     int ret;
0211 
0212     ret = regmap_read(info->regmap, LTC4162L_SYSTEM_STATUS_REG, &regval);
0213     if (ret)
0214         return ret;
0215 
0216     /* BIT(2) indicates if input voltage is sufficient to charge */
0217     val->intval = !!(regval & BIT(2));
0218 
0219     return 0;
0220 }
0221 
0222 static int ltc4162l_get_vbat(struct ltc4162l_info *info,
0223                   unsigned int reg,
0224                   union power_supply_propval *val)
0225 {
0226     unsigned int regval;
0227     int ret;
0228 
0229     ret = regmap_read(info->regmap, reg, &regval);
0230     if (ret)
0231         return ret;
0232 
0233     /* cell_count × 192.4μV/LSB */
0234     regval *= 1924;
0235     regval *= ltc4162l_get_cell_count(info);
0236     regval /= 10;
0237     val->intval = regval;
0238 
0239     return 0;
0240 }
0241 
0242 static int ltc4162l_get_ibat(struct ltc4162l_info *info,
0243                  union power_supply_propval *val)
0244 {
0245     unsigned int regval;
0246     int ret;
0247 
0248     ret = regmap_read(info->regmap, LTC4162L_IBAT, &regval);
0249     if (ret)
0250         return ret;
0251 
0252     /* Signed 16-bit number, 1.466μV / RSNSB amperes/LSB. */
0253     ret = (s16)(regval & 0xFFFF);
0254     val->intval = 100 * mult_frac(ret, 14660, (int)info->rsnsb);
0255 
0256     return 0;
0257 }
0258 
0259 
0260 static int ltc4162l_get_input_voltage(struct ltc4162l_info *info,
0261                       union power_supply_propval *val)
0262 {
0263     unsigned int regval;
0264     int ret;
0265 
0266     ret = regmap_read(info->regmap, LTC4162L_VIN, &regval);
0267     if (ret)
0268         return ret;
0269 
0270     /* 1.649mV/LSB */
0271     val->intval =  regval * 1694;
0272 
0273     return 0;
0274 }
0275 
0276 static int ltc4162l_get_input_current(struct ltc4162l_info *info,
0277                       union power_supply_propval *val)
0278 {
0279     unsigned int regval;
0280     int ret;
0281 
0282     ret = regmap_read(info->regmap, LTC4162L_IIN, &regval);
0283     if (ret)
0284         return ret;
0285 
0286     /* Signed 16-bit number, 1.466μV / RSNSI amperes/LSB. */
0287     ret = (s16)(regval & 0xFFFF);
0288     ret *= 14660;
0289     ret /= info->rsnsi;
0290     ret *= 100;
0291 
0292     val->intval = ret;
0293 
0294     return 0;
0295 }
0296 
0297 static int ltc4162l_get_icharge(struct ltc4162l_info *info,
0298                 unsigned int reg,
0299                 union power_supply_propval *val)
0300 {
0301     unsigned int regval;
0302     int ret;
0303 
0304     ret = regmap_read(info->regmap, reg, &regval);
0305     if (ret)
0306         return ret;
0307 
0308     regval &= BIT(6) - 1; /* Only the lower 5 bits */
0309 
0310     /* The charge current servo level: (icharge_dac + 1) × 1mV/RSNSB */
0311     ++regval;
0312     val->intval = 10000u * mult_frac(regval, 100000u, info->rsnsb);
0313 
0314     return 0;
0315 }
0316 
0317 static int ltc4162l_set_icharge(struct ltc4162l_info *info,
0318                 unsigned int reg,
0319                 unsigned int value)
0320 {
0321     value = mult_frac(value, info->rsnsb, 100000u);
0322     value /= 10000u;
0323 
0324     /* Round to lowest possible */
0325     if (value)
0326         --value;
0327 
0328     if (value > 31)
0329         return -EINVAL;
0330 
0331     return regmap_write(info->regmap, reg, value);
0332 }
0333 
0334 
0335 static int ltc4162l_get_vcharge(struct ltc4162l_info *info,
0336                 unsigned int reg,
0337                 union power_supply_propval *val)
0338 {
0339     unsigned int regval;
0340     int ret;
0341     u32 voltage;
0342 
0343     ret = regmap_read(info->regmap, reg, &regval);
0344     if (ret)
0345         return ret;
0346 
0347     regval &= BIT(6) - 1; /* Only the lower 5 bits */
0348 
0349     /*
0350      * charge voltage setting can be computed from
0351      * cell_count × (vcharge_setting × 12.5mV + 3.8125V)
0352      * where vcharge_setting ranges from 0 to 31 (4.2V max).
0353      */
0354     voltage = 3812500 + (regval * 12500);
0355     voltage *= ltc4162l_get_cell_count(info);
0356     val->intval = voltage;
0357 
0358     return 0;
0359 }
0360 
0361 static int ltc4162l_set_vcharge(struct ltc4162l_info *info,
0362                 unsigned int reg,
0363                 unsigned int value)
0364 {
0365     u8 cell_count = ltc4162l_get_cell_count(info);
0366 
0367     if (!cell_count)
0368         return -EBUSY; /* Not available yet, try again later */
0369 
0370     value /= cell_count;
0371 
0372     if (value < 3812500)
0373         return -EINVAL;
0374 
0375     value -= 3812500;
0376     value /= 12500;
0377 
0378     if (value > 31)
0379         return -EINVAL;
0380 
0381     return regmap_write(info->regmap, reg, value);
0382 }
0383 
0384 static int ltc4162l_get_iin_limit_dac(struct ltc4162l_info *info,
0385                      union power_supply_propval *val)
0386 {
0387     unsigned int regval;
0388     int ret;
0389 
0390     ret = regmap_read(info->regmap, LTC4162L_IIN_LIMIT_DAC, &regval);
0391     if (ret)
0392         return ret;
0393 
0394     regval &= BIT(6) - 1; /* Only 6 bits */
0395 
0396     /* (iin_limit_dac + 1) × 500μV / RSNSI */
0397     ++regval;
0398     regval *= 5000000u;
0399     regval /= info->rsnsi;
0400     val->intval = 100u * regval;
0401 
0402     return 0;
0403 }
0404 
0405 static int ltc4162l_set_iin_limit(struct ltc4162l_info *info,
0406                   unsigned int value)
0407 {
0408     unsigned int regval;
0409 
0410     regval = mult_frac(value, info->rsnsi, 50000u);
0411     regval /= 10000u;
0412     if (regval)
0413         --regval;
0414     if (regval > 63)
0415         regval = 63;
0416 
0417     return regmap_write(info->regmap, LTC4162L_IIN_LIMIT_TARGET, regval);
0418 }
0419 
0420 static int ltc4162l_get_die_temp(struct ltc4162l_info *info,
0421                  union power_supply_propval *val)
0422 {
0423     unsigned int regval;
0424     int ret;
0425 
0426     ret = regmap_read(info->regmap, LTC4162L_DIE_TEMPERATURE, &regval);
0427     if (ret)
0428         return ret;
0429 
0430     /* die_temp × 0.0215°C/LSB - 264.4°C */
0431     ret = (s16)(regval & 0xFFFF);
0432     ret *= 215;
0433     ret /= 100; /* Centidegrees scale */
0434     ret -= 26440;
0435     val->intval = ret;
0436 
0437     return 0;
0438 }
0439 
0440 static int ltc4162l_get_term_current(struct ltc4162l_info *info,
0441                      union power_supply_propval *val)
0442 {
0443     unsigned int regval;
0444     int ret;
0445 
0446     ret = regmap_read(info->regmap, LTC4162L_CHARGER_CONFIG_BITS, &regval);
0447     if (ret)
0448         return ret;
0449 
0450     /* Check if C_OVER_X_THRESHOLD is enabled */
0451     if (!(regval & BIT(2))) {
0452         val->intval = 0;
0453         return 0;
0454     }
0455 
0456     ret = regmap_read(info->regmap, LTC4162L_C_OVER_X_THRESHOLD, &regval);
0457     if (ret)
0458         return ret;
0459 
0460     /* 1.466μV / RSNSB amperes/LSB */
0461     regval *= 14660u;
0462     regval /= info->rsnsb;
0463     val->intval = 100 * regval;
0464 
0465     return 0;
0466 }
0467 
0468 static int ltc4162l_set_term_current(struct ltc4162l_info *info,
0469                      unsigned int value)
0470 {
0471     int ret;
0472     unsigned int regval;
0473 
0474     if (!value) {
0475         /* Disable en_c_over_x_term when set to zero */
0476         return regmap_update_bits(info->regmap,
0477                       LTC4162L_CHARGER_CONFIG_BITS,
0478                       BIT(2), 0);
0479     }
0480 
0481     regval = mult_frac(value, info->rsnsb, 14660u);
0482     regval /= 100u;
0483 
0484     ret =  regmap_write(info->regmap, LTC4162L_C_OVER_X_THRESHOLD, regval);
0485     if (ret)
0486         return ret;
0487 
0488     /* Set en_c_over_x_term after changing the threshold value */
0489     return regmap_update_bits(info->regmap, LTC4162L_CHARGER_CONFIG_BITS,
0490                   BIT(2), BIT(2));
0491 }
0492 
0493 /* Custom properties */
0494 static const char * const ltc4162l_charge_status_name[] = {
0495     "ilim_reg_active", /* 32 */
0496     "thermal_reg_active",
0497     "vin_uvcl_active",
0498     "iin_limit_active",
0499     "constant_current",
0500     "constant_voltage",
0501     "charger_off" /* 0 */
0502 };
0503 
0504 static ssize_t charge_status_show(struct device *dev,
0505                   struct device_attribute *attr, char *buf)
0506 {
0507     struct power_supply *psy = to_power_supply(dev);
0508     struct ltc4162l_info *info = power_supply_get_drvdata(psy);
0509     const char *result = ltc4162l_charge_status_name[
0510                 ARRAY_SIZE(ltc4162l_charge_status_name) - 1];
0511     unsigned int regval;
0512     unsigned int mask;
0513     unsigned int index;
0514     int ret;
0515 
0516     ret = regmap_read(info->regmap, LTC4162L_CHARGE_STATUS, &regval);
0517     if (ret)
0518         return ret;
0519 
0520     /* Only one bit is set according to datasheet, let's be safe here */
0521     for (mask = 32, index = 0; mask != 0; mask >>= 1, ++index) {
0522         if (regval & mask) {
0523             result = ltc4162l_charge_status_name[index];
0524             break;
0525         }
0526     }
0527 
0528     return sprintf(buf, "%s\n", result);
0529 }
0530 static DEVICE_ATTR_RO(charge_status);
0531 
0532 static ssize_t vbat_show(struct device *dev,
0533                   struct device_attribute *attr, char *buf)
0534 {
0535     struct power_supply *psy = to_power_supply(dev);
0536     struct ltc4162l_info *info = power_supply_get_drvdata(psy);
0537     union power_supply_propval val;
0538     int ret;
0539 
0540     ret = ltc4162l_get_vbat(info, LTC4162L_VBAT, &val);
0541     if (ret)
0542         return ret;
0543 
0544     return sprintf(buf, "%d\n", val.intval);
0545 }
0546 static DEVICE_ATTR_RO(vbat);
0547 
0548 static ssize_t vbat_avg_show(struct device *dev,
0549                   struct device_attribute *attr, char *buf)
0550 {
0551     struct power_supply *psy = to_power_supply(dev);
0552     struct ltc4162l_info *info = power_supply_get_drvdata(psy);
0553     union power_supply_propval val;
0554     int ret;
0555 
0556     ret = ltc4162l_get_vbat(info, LTC4162L_VBAT_FILT, &val);
0557     if (ret)
0558         return ret;
0559 
0560     return sprintf(buf, "%d\n", val.intval);
0561 }
0562 static DEVICE_ATTR_RO(vbat_avg);
0563 
0564 static ssize_t ibat_show(struct device *dev,
0565                   struct device_attribute *attr, char *buf)
0566 {
0567     struct power_supply *psy = to_power_supply(dev);
0568     struct ltc4162l_info *info = power_supply_get_drvdata(psy);
0569     union power_supply_propval val;
0570     int ret;
0571 
0572     ret = ltc4162l_get_ibat(info, &val);
0573     if (ret)
0574         return ret;
0575 
0576     return sprintf(buf, "%d\n", val.intval);
0577 }
0578 static DEVICE_ATTR_RO(ibat);
0579 
0580 static ssize_t force_telemetry_show(struct device *dev,
0581                     struct device_attribute *attr, char *buf)
0582 {
0583     struct power_supply *psy = to_power_supply(dev);
0584     struct ltc4162l_info *info = power_supply_get_drvdata(psy);
0585     unsigned int regval;
0586     int ret;
0587 
0588     ret = regmap_read(info->regmap, LTC4162L_CONFIG_BITS_REG, &regval);
0589     if (ret)
0590         return ret;
0591 
0592     return sprintf(buf, "%u\n", regval & BIT(2) ? 1 : 0);
0593 }
0594 
0595 static ssize_t force_telemetry_store(struct device *dev,
0596     struct device_attribute *attr,
0597     const char *buf,
0598     size_t count)
0599 {
0600     struct power_supply *psy = to_power_supply(dev);
0601     struct ltc4162l_info *info = power_supply_get_drvdata(psy);
0602     int ret;
0603     unsigned int value;
0604 
0605     ret = kstrtouint(buf, 0, &value);
0606     if (ret < 0)
0607         return ret;
0608 
0609     ret = regmap_update_bits(info->regmap, LTC4162L_CONFIG_BITS_REG,
0610                  BIT(2), value ? BIT(2) : 0);
0611     if (ret < 0)
0612         return ret;
0613 
0614     return count;
0615 }
0616 
0617 static DEVICE_ATTR_RW(force_telemetry);
0618 
0619 static ssize_t arm_ship_mode_show(struct device *dev,
0620                     struct device_attribute *attr, char *buf)
0621 {
0622     struct power_supply *psy = to_power_supply(dev);
0623     struct ltc4162l_info *info = power_supply_get_drvdata(psy);
0624     unsigned int regval;
0625     int ret;
0626 
0627     ret = regmap_read(info->regmap, LTC4162L_ARM_SHIP_MODE, &regval);
0628     if (ret)
0629         return ret;
0630 
0631     return sprintf(buf, "%u\n",
0632         regval == LTC4162L_ARM_SHIP_MODE_MAGIC ? 1 : 0);
0633 }
0634 
0635 static ssize_t arm_ship_mode_store(struct device *dev,
0636     struct device_attribute *attr,
0637     const char *buf,
0638     size_t count)
0639 {
0640     struct power_supply *psy = to_power_supply(dev);
0641     struct ltc4162l_info *info = power_supply_get_drvdata(psy);
0642     int ret;
0643     unsigned int value;
0644 
0645     ret = kstrtouint(buf, 0, &value);
0646     if (ret < 0)
0647         return ret;
0648 
0649     ret = regmap_write(info->regmap, LTC4162L_ARM_SHIP_MODE,
0650                 value ? LTC4162L_ARM_SHIP_MODE_MAGIC : 0);
0651     if (ret < 0)
0652         return ret;
0653 
0654     return count;
0655 }
0656 
0657 static DEVICE_ATTR_RW(arm_ship_mode);
0658 
0659 static struct attribute *ltc4162l_sysfs_entries[] = {
0660     &dev_attr_charge_status.attr,
0661     &dev_attr_ibat.attr,
0662     &dev_attr_vbat.attr,
0663     &dev_attr_vbat_avg.attr,
0664     &dev_attr_force_telemetry.attr,
0665     &dev_attr_arm_ship_mode.attr,
0666     NULL,
0667 };
0668 
0669 static const struct attribute_group ltc4162l_attr_group = {
0670     .name   = NULL, /* put in device directory */
0671     .attrs  = ltc4162l_sysfs_entries,
0672 };
0673 
0674 static const struct attribute_group *ltc4162l_attr_groups[] = {
0675     &ltc4162l_attr_group,
0676     NULL,
0677 };
0678 
0679 static int ltc4162l_get_property(struct power_supply *psy,
0680                  enum power_supply_property psp,
0681                  union power_supply_propval *val)
0682 {
0683     struct ltc4162l_info *info = power_supply_get_drvdata(psy);
0684 
0685     switch (psp) {
0686     case POWER_SUPPLY_PROP_STATUS:
0687         return ltc4162l_get_status(info, val);
0688     case POWER_SUPPLY_PROP_CHARGE_TYPE:
0689         return ltc4162l_get_charge_type(info, val);
0690     case POWER_SUPPLY_PROP_HEALTH:
0691         return ltc4162l_get_health(info, val);
0692     case POWER_SUPPLY_PROP_ONLINE:
0693         return ltc4162l_get_online(info, val);
0694     case POWER_SUPPLY_PROP_VOLTAGE_NOW:
0695         return ltc4162l_get_input_voltage(info, val);
0696     case POWER_SUPPLY_PROP_CURRENT_NOW:
0697         return ltc4162l_get_input_current(info, val);
0698     case POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT:
0699         return ltc4162l_get_icharge(info,
0700                 LTC4162L_ICHARGE_DAC, val);
0701     case POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT_MAX:
0702         return ltc4162l_get_icharge(info,
0703                 LTC4162L_CHARGE_CURRENT_SETTING, val);
0704     case POWER_SUPPLY_PROP_CONSTANT_CHARGE_VOLTAGE:
0705         return ltc4162l_get_vcharge(info,
0706                 LTC4162L_VCHARGE_DAC, val);
0707     case POWER_SUPPLY_PROP_CONSTANT_CHARGE_VOLTAGE_MAX:
0708         return ltc4162l_get_vcharge(info,
0709                 LTC4162L_VCHARGE_SETTING, val);
0710     case POWER_SUPPLY_PROP_INPUT_CURRENT_LIMIT:
0711         return ltc4162l_get_iin_limit_dac(info, val);
0712     case POWER_SUPPLY_PROP_TEMP:
0713         return ltc4162l_get_die_temp(info, val);
0714     case POWER_SUPPLY_PROP_CHARGE_TERM_CURRENT:
0715         return ltc4162l_get_term_current(info, val);
0716     default:
0717         return -EINVAL;
0718     }
0719 }
0720 
0721 static int ltc4162l_set_property(struct power_supply *psy,
0722                      enum power_supply_property psp,
0723                      const union power_supply_propval *val)
0724 {
0725     struct ltc4162l_info *info = power_supply_get_drvdata(psy);
0726 
0727     switch (psp) {
0728     case POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT_MAX:
0729         return ltc4162l_set_icharge(info,
0730                 LTC4162L_CHARGE_CURRENT_SETTING, val->intval);
0731     case POWER_SUPPLY_PROP_CONSTANT_CHARGE_VOLTAGE_MAX:
0732         return ltc4162l_set_vcharge(info,
0733                 LTC4162L_VCHARGE_SETTING, val->intval);
0734     case POWER_SUPPLY_PROP_INPUT_CURRENT_LIMIT:
0735         return ltc4162l_set_iin_limit(info, val->intval);
0736     case POWER_SUPPLY_PROP_CHARGE_TERM_CURRENT:
0737         return ltc4162l_set_term_current(info, val->intval);
0738     default:
0739         return -EINVAL;
0740     }
0741 }
0742 
0743 static int ltc4162l_property_is_writeable(struct power_supply *psy,
0744                         enum power_supply_property psp)
0745 {
0746     switch (psp) {
0747     case POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT_MAX:
0748     case POWER_SUPPLY_PROP_CONSTANT_CHARGE_VOLTAGE_MAX:
0749     case POWER_SUPPLY_PROP_INPUT_CURRENT_LIMIT:
0750     case POWER_SUPPLY_PROP_CHARGE_TERM_CURRENT:
0751         return 1;
0752     default:
0753         return 0;
0754     }
0755 }
0756 
0757 /* Charger power supply property routines */
0758 static enum power_supply_property ltc4162l_properties[] = {
0759     POWER_SUPPLY_PROP_STATUS,
0760     POWER_SUPPLY_PROP_CHARGE_TYPE,
0761     POWER_SUPPLY_PROP_HEALTH,
0762     POWER_SUPPLY_PROP_ONLINE,
0763     POWER_SUPPLY_PROP_VOLTAGE_NOW,
0764     POWER_SUPPLY_PROP_CURRENT_NOW,
0765     POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT,
0766     POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT_MAX,
0767     POWER_SUPPLY_PROP_CONSTANT_CHARGE_VOLTAGE,
0768     POWER_SUPPLY_PROP_CONSTANT_CHARGE_VOLTAGE_MAX,
0769     POWER_SUPPLY_PROP_INPUT_CURRENT_LIMIT,
0770     POWER_SUPPLY_PROP_TEMP,
0771     POWER_SUPPLY_PROP_CHARGE_TERM_CURRENT,
0772 };
0773 
0774 static const struct power_supply_desc ltc4162l_desc = {
0775     .name       = "ltc4162-l",
0776     .type       = POWER_SUPPLY_TYPE_MAINS,
0777     .properties = ltc4162l_properties,
0778     .num_properties = ARRAY_SIZE(ltc4162l_properties),
0779     .get_property   = ltc4162l_get_property,
0780     .set_property   = ltc4162l_set_property,
0781     .property_is_writeable = ltc4162l_property_is_writeable,
0782 };
0783 
0784 static bool ltc4162l_is_writeable_reg(struct device *dev, unsigned int reg)
0785 {
0786     /* all registers up to this one are writeable */
0787     if (reg <= LTC4162L_CHARGER_CONFIG_BITS)
0788         return true;
0789 
0790     /* The ALERTS registers can be written to clear alerts */
0791     if (reg >= LTC4162L_LIMIT_ALERTS_REG &&
0792         reg <= LTC4162L_CHARGE_STATUS_ALERTS_REG)
0793         return true;
0794 
0795     return false;
0796 }
0797 
0798 static bool ltc4162l_is_volatile_reg(struct device *dev, unsigned int reg)
0799 {
0800     /* all registers after this one are read-only status registers */
0801     return reg > LTC4162L_CHARGER_CONFIG_BITS;
0802 }
0803 
0804 static const struct regmap_config ltc4162l_regmap_config = {
0805     .reg_bits   = 8,
0806     .val_bits   = 16,
0807     .val_format_endian = REGMAP_ENDIAN_LITTLE,
0808     .writeable_reg  = ltc4162l_is_writeable_reg,
0809     .volatile_reg   = ltc4162l_is_volatile_reg,
0810     .max_register   = LTC4162L_INPUT_UNDERVOLTAGE_DAC,
0811     .cache_type = REGCACHE_RBTREE,
0812 };
0813 
0814 static void ltc4162l_clear_interrupts(struct ltc4162l_info *info)
0815 {
0816     /* Acknowledge interrupt to chip by clearing all events */
0817     regmap_write(info->regmap, LTC4162L_LIMIT_ALERTS_REG, 0);
0818     regmap_write(info->regmap, LTC4162L_CHARGER_STATE_ALERTS_REG, 0);
0819     regmap_write(info->regmap, LTC4162L_CHARGE_STATUS_ALERTS_REG, 0);
0820 }
0821 
0822 static int ltc4162l_probe(struct i2c_client *client,
0823             const struct i2c_device_id *id)
0824 {
0825     struct i2c_adapter *adapter = client->adapter;
0826     struct device *dev = &client->dev;
0827     struct ltc4162l_info *info;
0828     struct power_supply_config ltc4162l_config = {};
0829     u32 value;
0830     int ret;
0831 
0832     if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_WORD_DATA)) {
0833         dev_err(dev, "No support for SMBUS_WORD_DATA\n");
0834         return -ENODEV;
0835     }
0836     info = devm_kzalloc(dev, sizeof(*info), GFP_KERNEL);
0837     if (!info)
0838         return -ENOMEM;
0839 
0840     info->client = client;
0841     i2c_set_clientdata(client, info);
0842 
0843     info->regmap = devm_regmap_init_i2c(client, &ltc4162l_regmap_config);
0844     if (IS_ERR(info->regmap)) {
0845         dev_err(dev, "Failed to initialize register map\n");
0846         return PTR_ERR(info->regmap);
0847     }
0848 
0849     ret = device_property_read_u32(dev, "lltc,rsnsb-micro-ohms",
0850                        &info->rsnsb);
0851     if (ret) {
0852         dev_err(dev, "Missing lltc,rsnsb-micro-ohms property\n");
0853         return ret;
0854     }
0855     if (!info->rsnsb)
0856         return -EINVAL;
0857 
0858     ret = device_property_read_u32(dev, "lltc,rsnsi-micro-ohms",
0859                        &info->rsnsi);
0860     if (ret) {
0861         dev_err(dev, "Missing lltc,rsnsi-micro-ohms property\n");
0862         return ret;
0863     }
0864     if (!info->rsnsi)
0865         return -EINVAL;
0866 
0867     if (!device_property_read_u32(dev, "lltc,cell-count", &value))
0868         info->cell_count = value;
0869 
0870     ltc4162l_config.of_node = dev->of_node;
0871     ltc4162l_config.drv_data = info;
0872     ltc4162l_config.attr_grp = ltc4162l_attr_groups;
0873 
0874     info->charger = devm_power_supply_register(dev, &ltc4162l_desc,
0875                            &ltc4162l_config);
0876     if (IS_ERR(info->charger)) {
0877         dev_err(dev, "Failed to register charger\n");
0878         return PTR_ERR(info->charger);
0879     }
0880 
0881     /* Disable the threshold alerts, we're not using them */
0882     regmap_write(info->regmap, LTC4162L_EN_LIMIT_ALERTS_REG, 0);
0883 
0884     /* Enable interrupts on all status changes */
0885     regmap_write(info->regmap, LTC4162L_EN_CHARGER_STATE_ALERTS_REG,
0886              0x1fff);
0887     regmap_write(info->regmap, LTC4162L_EN_CHARGE_STATUS_ALERTS_REG, 0x1f);
0888 
0889     ltc4162l_clear_interrupts(info);
0890 
0891     return 0;
0892 }
0893 
0894 static void ltc4162l_alert(struct i2c_client *client,
0895                enum i2c_alert_protocol type, unsigned int flag)
0896 {
0897     struct ltc4162l_info *info = i2c_get_clientdata(client);
0898 
0899     if (type != I2C_PROTOCOL_SMBUS_ALERT)
0900         return;
0901 
0902     ltc4162l_clear_interrupts(info);
0903     power_supply_changed(info->charger);
0904 }
0905 
0906 static const struct i2c_device_id ltc4162l_i2c_id_table[] = {
0907     { "ltc4162-l", 0 },
0908     { },
0909 };
0910 MODULE_DEVICE_TABLE(i2c, ltc4162l_i2c_id_table);
0911 
0912 static const struct of_device_id ltc4162l_of_match[] = {
0913     { .compatible = "lltc,ltc4162-l", },
0914     { },
0915 };
0916 MODULE_DEVICE_TABLE(of, ltc4162l_of_match);
0917 
0918 static struct i2c_driver ltc4162l_driver = {
0919     .probe      = ltc4162l_probe,
0920     .alert      = ltc4162l_alert,
0921     .id_table   = ltc4162l_i2c_id_table,
0922     .driver = {
0923         .name       = "ltc4162-l-charger",
0924         .of_match_table = of_match_ptr(ltc4162l_of_match),
0925     },
0926 };
0927 module_i2c_driver(ltc4162l_driver);
0928 
0929 MODULE_LICENSE("GPL");
0930 MODULE_AUTHOR("Mike Looijmans <mike.looijmans@topic.nl>");
0931 MODULE_DESCRIPTION("LTC4162-L charger driver");