931 lines · c
1// SPDX-License-Identifier: GPL-2.0-or-later2/*3 * Driver for Analog Devices (Linear Technology) LTC4162-L charger IC.4 * Copyright (C) 2020, Topic Embedded Products5 */6 7#include <linux/module.h>8#include <linux/delay.h>9#include <linux/of.h>10#include <linux/pm_runtime.h>11#include <linux/power_supply.h>12#include <linux/i2c.h>13#include <linux/regmap.h>14 15/* Registers (names based on what datasheet uses) */16#define LTC4162L_EN_LIMIT_ALERTS_REG 0x0D17#define LTC4162L_EN_CHARGER_STATE_ALERTS_REG 0x0E18#define LTC4162L_EN_CHARGE_STATUS_ALERTS_REG 0x0F19#define LTC4162L_CONFIG_BITS_REG 0x1420#define LTC4162L_IIN_LIMIT_TARGET 0x1521#define LTC4162L_ARM_SHIP_MODE 0x1922#define LTC4162L_CHARGE_CURRENT_SETTING 0X1A23#define LTC4162L_VCHARGE_SETTING 0X1B24#define LTC4162L_C_OVER_X_THRESHOLD 0x1C25#define LTC4162L_MAX_CV_TIME 0X1D26#define LTC4162L_MAX_CHARGE_TIME 0X1E27#define LTC4162L_CHARGER_CONFIG_BITS 0x2928#define LTC4162L_CHARGER_STATE 0x3429#define LTC4162L_CHARGE_STATUS 0x3530#define LTC4162L_LIMIT_ALERTS_REG 0x3631#define LTC4162L_CHARGER_STATE_ALERTS_REG 0x3732#define LTC4162L_CHARGE_STATUS_ALERTS_REG 0x3833#define LTC4162L_SYSTEM_STATUS_REG 0x3934#define LTC4162L_VBAT 0x3A35#define LTC4162L_VIN 0x3B36#define LTC4162L_VOUT 0x3C37#define LTC4162L_IBAT 0x3D38#define LTC4162L_IIN 0x3E39#define LTC4162L_DIE_TEMPERATURE 0x3F40#define LTC4162L_THERMISTOR_VOLTAGE 0x4041#define LTC4162L_BSR 0x4142#define LTC4162L_JEITA_REGION 0x4243#define LTC4162L_CHEM_CELLS_REG 0x4344#define LTC4162L_ICHARGE_DAC 0x4445#define LTC4162L_VCHARGE_DAC 0x4546#define LTC4162L_IIN_LIMIT_DAC 0x4647#define LTC4162L_VBAT_FILT 0x4748#define LTC4162L_INPUT_UNDERVOLTAGE_DAC 0x4B49 50/* Enumeration as in datasheet. Individual bits are mutually exclusive. */51enum ltc4162l_state {52 battery_detection = 2048,53 charger_suspended = 256,54 precharge = 128, /* trickle on low bat voltage */55 cc_cv_charge = 64, /* normal charge */56 ntc_pause = 32,57 timer_term = 16,58 c_over_x_term = 8, /* battery is full */59 max_charge_time_fault = 4,60 bat_missing_fault = 2,61 bat_short_fault = 162};63 64/* Individual bits are mutually exclusive. Only active in charging states.*/65enum ltc4162l_charge_status {66 ilim_reg_active = 32,67 thermal_reg_active = 16,68 vin_uvcl_active = 8,69 iin_limit_active = 4,70 constant_current = 2,71 constant_voltage = 1,72 charger_off = 073};74 75/* Magic number to write to ARM_SHIP_MODE register */76#define LTC4162L_ARM_SHIP_MODE_MAGIC 2132577 78struct ltc4162l_info {79 struct i2c_client *client;80 struct regmap *regmap;81 struct power_supply *charger;82 u32 rsnsb; /* Series resistor that sets charge current, microOhm */83 u32 rsnsi; /* Series resistor to measure input current, microOhm */84 u8 cell_count; /* Number of connected cells, 0 while unknown */85};86 87static u8 ltc4162l_get_cell_count(struct ltc4162l_info *info)88{89 int ret;90 unsigned int val;91 92 /* Once read successfully */93 if (info->cell_count)94 return info->cell_count;95 96 ret = regmap_read(info->regmap, LTC4162L_CHEM_CELLS_REG, &val);97 if (ret)98 return 0;99 100 /* Lower 4 bits is the cell count, or 0 if the chip doesn't know yet */101 val &= 0x0f;102 if (!val)103 return 0;104 105 /* Once determined, keep the value */106 info->cell_count = val;107 108 return val;109};110 111/* Convert enum value to POWER_SUPPLY_STATUS value */112static int ltc4162l_state_decode(enum ltc4162l_state value)113{114 switch (value) {115 case precharge:116 case cc_cv_charge:117 return POWER_SUPPLY_STATUS_CHARGING;118 case c_over_x_term:119 return POWER_SUPPLY_STATUS_FULL;120 case bat_missing_fault:121 case bat_short_fault:122 return POWER_SUPPLY_STATUS_UNKNOWN;123 default:124 return POWER_SUPPLY_STATUS_NOT_CHARGING;125 }126};127 128static int ltc4162l_get_status(struct ltc4162l_info *info,129 union power_supply_propval *val)130{131 unsigned int regval;132 int ret;133 134 ret = regmap_read(info->regmap, LTC4162L_CHARGER_STATE, ®val);135 if (ret) {136 dev_err(&info->client->dev, "Failed to read CHARGER_STATE\n");137 return ret;138 }139 140 val->intval = ltc4162l_state_decode(regval);141 142 return 0;143}144 145static int ltc4162l_charge_status_decode(enum ltc4162l_charge_status value)146{147 if (!value)148 return POWER_SUPPLY_CHARGE_TYPE_NONE;149 150 /* constant voltage/current and input_current limit are "fast" modes */151 if (value <= iin_limit_active)152 return POWER_SUPPLY_CHARGE_TYPE_FAST;153 154 /* Anything that's not fast we'll return as trickle */155 return POWER_SUPPLY_CHARGE_TYPE_TRICKLE;156}157 158static int ltc4162l_get_charge_type(struct ltc4162l_info *info,159 union power_supply_propval *val)160{161 unsigned int regval;162 int ret;163 164 ret = regmap_read(info->regmap, LTC4162L_CHARGE_STATUS, ®val);165 if (ret)166 return ret;167 168 val->intval = ltc4162l_charge_status_decode(regval);169 170 return 0;171}172 173static int ltc4162l_state_to_health(enum ltc4162l_state value)174{175 switch (value) {176 case ntc_pause:177 return POWER_SUPPLY_HEALTH_OVERHEAT;178 case timer_term:179 return POWER_SUPPLY_HEALTH_SAFETY_TIMER_EXPIRE;180 case max_charge_time_fault:181 return POWER_SUPPLY_HEALTH_WATCHDOG_TIMER_EXPIRE;182 case bat_missing_fault:183 return POWER_SUPPLY_HEALTH_UNSPEC_FAILURE;184 case bat_short_fault:185 return POWER_SUPPLY_HEALTH_DEAD;186 default:187 return POWER_SUPPLY_HEALTH_GOOD;188 }189}190 191static int ltc4162l_get_health(struct ltc4162l_info *info,192 union power_supply_propval *val)193{194 unsigned int regval;195 int ret;196 197 ret = regmap_read(info->regmap, LTC4162L_CHARGER_STATE, ®val);198 if (ret)199 return ret;200 201 val->intval = ltc4162l_state_to_health(regval);202 203 return 0;204}205 206static int ltc4162l_get_online(struct ltc4162l_info *info,207 union power_supply_propval *val)208{209 unsigned int regval;210 int ret;211 212 ret = regmap_read(info->regmap, LTC4162L_SYSTEM_STATUS_REG, ®val);213 if (ret)214 return ret;215 216 /* BIT(2) indicates if input voltage is sufficient to charge */217 val->intval = !!(regval & BIT(2));218 219 return 0;220}221 222static int ltc4162l_get_vbat(struct ltc4162l_info *info,223 unsigned int reg,224 union power_supply_propval *val)225{226 unsigned int regval;227 int ret;228 229 ret = regmap_read(info->regmap, reg, ®val);230 if (ret)231 return ret;232 233 /* cell_count × 192.4μV/LSB */234 regval *= 1924;235 regval *= ltc4162l_get_cell_count(info);236 regval /= 10;237 val->intval = regval;238 239 return 0;240}241 242static int ltc4162l_get_ibat(struct ltc4162l_info *info,243 union power_supply_propval *val)244{245 unsigned int regval;246 int ret;247 248 ret = regmap_read(info->regmap, LTC4162L_IBAT, ®val);249 if (ret)250 return ret;251 252 /* Signed 16-bit number, 1.466μV / RSNSB amperes/LSB. */253 ret = (s16)(regval & 0xFFFF);254 val->intval = 100 * mult_frac(ret, 14660, (int)info->rsnsb);255 256 return 0;257}258 259 260static int ltc4162l_get_input_voltage(struct ltc4162l_info *info,261 union power_supply_propval *val)262{263 unsigned int regval;264 int ret;265 266 ret = regmap_read(info->regmap, LTC4162L_VIN, ®val);267 if (ret)268 return ret;269 270 /* 1.649mV/LSB */271 val->intval = regval * 1694;272 273 return 0;274}275 276static int ltc4162l_get_input_current(struct ltc4162l_info *info,277 union power_supply_propval *val)278{279 unsigned int regval;280 int ret;281 282 ret = regmap_read(info->regmap, LTC4162L_IIN, ®val);283 if (ret)284 return ret;285 286 /* Signed 16-bit number, 1.466μV / RSNSI amperes/LSB. */287 ret = (s16)(regval & 0xFFFF);288 ret *= 14660;289 ret /= info->rsnsi;290 ret *= 100;291 292 val->intval = ret;293 294 return 0;295}296 297static int ltc4162l_get_icharge(struct ltc4162l_info *info,298 unsigned int reg,299 union power_supply_propval *val)300{301 unsigned int regval;302 int ret;303 304 ret = regmap_read(info->regmap, reg, ®val);305 if (ret)306 return ret;307 308 regval &= BIT(6) - 1; /* Only the lower 5 bits */309 310 /* The charge current servo level: (icharge_dac + 1) × 1mV/RSNSB */311 ++regval;312 val->intval = 10000u * mult_frac(regval, 100000u, info->rsnsb);313 314 return 0;315}316 317static int ltc4162l_set_icharge(struct ltc4162l_info *info,318 unsigned int reg,319 unsigned int value)320{321 value = mult_frac(value, info->rsnsb, 100000u);322 value /= 10000u;323 324 /* Round to lowest possible */325 if (value)326 --value;327 328 if (value > 31)329 return -EINVAL;330 331 return regmap_write(info->regmap, reg, value);332}333 334 335static int ltc4162l_get_vcharge(struct ltc4162l_info *info,336 unsigned int reg,337 union power_supply_propval *val)338{339 unsigned int regval;340 int ret;341 u32 voltage;342 343 ret = regmap_read(info->regmap, reg, ®val);344 if (ret)345 return ret;346 347 regval &= BIT(6) - 1; /* Only the lower 5 bits */348 349 /*350 * charge voltage setting can be computed from351 * cell_count × (vcharge_setting × 12.5mV + 3.8125V)352 * where vcharge_setting ranges from 0 to 31 (4.2V max).353 */354 voltage = 3812500 + (regval * 12500);355 voltage *= ltc4162l_get_cell_count(info);356 val->intval = voltage;357 358 return 0;359}360 361static int ltc4162l_set_vcharge(struct ltc4162l_info *info,362 unsigned int reg,363 unsigned int value)364{365 u8 cell_count = ltc4162l_get_cell_count(info);366 367 if (!cell_count)368 return -EBUSY; /* Not available yet, try again later */369 370 value /= cell_count;371 372 if (value < 3812500)373 return -EINVAL;374 375 value -= 3812500;376 value /= 12500;377 378 if (value > 31)379 return -EINVAL;380 381 return regmap_write(info->regmap, reg, value);382}383 384static int ltc4162l_get_iin_limit_dac(struct ltc4162l_info *info,385 union power_supply_propval *val)386{387 unsigned int regval;388 int ret;389 390 ret = regmap_read(info->regmap, LTC4162L_IIN_LIMIT_DAC, ®val);391 if (ret)392 return ret;393 394 regval &= BIT(6) - 1; /* Only 6 bits */395 396 /* (iin_limit_dac + 1) × 500μV / RSNSI */397 ++regval;398 regval *= 5000000u;399 regval /= info->rsnsi;400 val->intval = 100u * regval;401 402 return 0;403}404 405static int ltc4162l_set_iin_limit(struct ltc4162l_info *info,406 unsigned int value)407{408 unsigned int regval;409 410 regval = mult_frac(value, info->rsnsi, 50000u);411 regval /= 10000u;412 if (regval)413 --regval;414 if (regval > 63)415 regval = 63;416 417 return regmap_write(info->regmap, LTC4162L_IIN_LIMIT_TARGET, regval);418}419 420static int ltc4162l_get_die_temp(struct ltc4162l_info *info,421 union power_supply_propval *val)422{423 unsigned int regval;424 int ret;425 426 ret = regmap_read(info->regmap, LTC4162L_DIE_TEMPERATURE, ®val);427 if (ret)428 return ret;429 430 /* die_temp × 0.0215°C/LSB - 264.4°C */431 ret = (s16)(regval & 0xFFFF);432 ret *= 215;433 ret /= 100; /* Centidegrees scale */434 ret -= 26440;435 val->intval = ret;436 437 return 0;438}439 440static int ltc4162l_get_term_current(struct ltc4162l_info *info,441 union power_supply_propval *val)442{443 unsigned int regval;444 int ret;445 446 ret = regmap_read(info->regmap, LTC4162L_CHARGER_CONFIG_BITS, ®val);447 if (ret)448 return ret;449 450 /* Check if C_OVER_X_THRESHOLD is enabled */451 if (!(regval & BIT(2))) {452 val->intval = 0;453 return 0;454 }455 456 ret = regmap_read(info->regmap, LTC4162L_C_OVER_X_THRESHOLD, ®val);457 if (ret)458 return ret;459 460 /* 1.466μV / RSNSB amperes/LSB */461 regval *= 14660u;462 regval /= info->rsnsb;463 val->intval = 100 * regval;464 465 return 0;466}467 468static int ltc4162l_set_term_current(struct ltc4162l_info *info,469 unsigned int value)470{471 int ret;472 unsigned int regval;473 474 if (!value) {475 /* Disable en_c_over_x_term when set to zero */476 return regmap_update_bits(info->regmap,477 LTC4162L_CHARGER_CONFIG_BITS,478 BIT(2), 0);479 }480 481 regval = mult_frac(value, info->rsnsb, 14660u);482 regval /= 100u;483 484 ret = regmap_write(info->regmap, LTC4162L_C_OVER_X_THRESHOLD, regval);485 if (ret)486 return ret;487 488 /* Set en_c_over_x_term after changing the threshold value */489 return regmap_update_bits(info->regmap, LTC4162L_CHARGER_CONFIG_BITS,490 BIT(2), BIT(2));491}492 493/* Custom properties */494static const char * const ltc4162l_charge_status_name[] = {495 "ilim_reg_active", /* 32 */496 "thermal_reg_active",497 "vin_uvcl_active",498 "iin_limit_active",499 "constant_current",500 "constant_voltage",501 "charger_off" /* 0 */502};503 504static ssize_t charge_status_show(struct device *dev,505 struct device_attribute *attr, char *buf)506{507 struct power_supply *psy = to_power_supply(dev);508 struct ltc4162l_info *info = power_supply_get_drvdata(psy);509 const char *result = ltc4162l_charge_status_name[510 ARRAY_SIZE(ltc4162l_charge_status_name) - 1];511 unsigned int regval;512 unsigned int mask;513 unsigned int index;514 int ret;515 516 ret = regmap_read(info->regmap, LTC4162L_CHARGE_STATUS, ®val);517 if (ret)518 return ret;519 520 /* Only one bit is set according to datasheet, let's be safe here */521 for (mask = 32, index = 0; mask != 0; mask >>= 1, ++index) {522 if (regval & mask) {523 result = ltc4162l_charge_status_name[index];524 break;525 }526 }527 528 return sysfs_emit(buf, "%s\n", result);529}530static DEVICE_ATTR_RO(charge_status);531 532static ssize_t vbat_show(struct device *dev,533 struct device_attribute *attr, char *buf)534{535 struct power_supply *psy = to_power_supply(dev);536 struct ltc4162l_info *info = power_supply_get_drvdata(psy);537 union power_supply_propval val;538 int ret;539 540 ret = ltc4162l_get_vbat(info, LTC4162L_VBAT, &val);541 if (ret)542 return ret;543 544 return sysfs_emit(buf, "%d\n", val.intval);545}546static DEVICE_ATTR_RO(vbat);547 548static ssize_t vbat_avg_show(struct device *dev,549 struct device_attribute *attr, char *buf)550{551 struct power_supply *psy = to_power_supply(dev);552 struct ltc4162l_info *info = power_supply_get_drvdata(psy);553 union power_supply_propval val;554 int ret;555 556 ret = ltc4162l_get_vbat(info, LTC4162L_VBAT_FILT, &val);557 if (ret)558 return ret;559 560 return sysfs_emit(buf, "%d\n", val.intval);561}562static DEVICE_ATTR_RO(vbat_avg);563 564static ssize_t ibat_show(struct device *dev,565 struct device_attribute *attr, char *buf)566{567 struct power_supply *psy = to_power_supply(dev);568 struct ltc4162l_info *info = power_supply_get_drvdata(psy);569 union power_supply_propval val;570 int ret;571 572 ret = ltc4162l_get_ibat(info, &val);573 if (ret)574 return ret;575 576 return sysfs_emit(buf, "%d\n", val.intval);577}578static DEVICE_ATTR_RO(ibat);579 580static ssize_t force_telemetry_show(struct device *dev,581 struct device_attribute *attr, char *buf)582{583 struct power_supply *psy = to_power_supply(dev);584 struct ltc4162l_info *info = power_supply_get_drvdata(psy);585 unsigned int regval;586 int ret;587 588 ret = regmap_read(info->regmap, LTC4162L_CONFIG_BITS_REG, ®val);589 if (ret)590 return ret;591 592 return sysfs_emit(buf, "%u\n", regval & BIT(2) ? 1 : 0);593}594 595static ssize_t force_telemetry_store(struct device *dev,596 struct device_attribute *attr,597 const char *buf,598 size_t count)599{600 struct power_supply *psy = to_power_supply(dev);601 struct ltc4162l_info *info = power_supply_get_drvdata(psy);602 int ret;603 unsigned int value;604 605 ret = kstrtouint(buf, 0, &value);606 if (ret < 0)607 return ret;608 609 ret = regmap_update_bits(info->regmap, LTC4162L_CONFIG_BITS_REG,610 BIT(2), value ? BIT(2) : 0);611 if (ret < 0)612 return ret;613 614 return count;615}616 617static DEVICE_ATTR_RW(force_telemetry);618 619static ssize_t arm_ship_mode_show(struct device *dev,620 struct device_attribute *attr, char *buf)621{622 struct power_supply *psy = to_power_supply(dev);623 struct ltc4162l_info *info = power_supply_get_drvdata(psy);624 unsigned int regval;625 int ret;626 627 ret = regmap_read(info->regmap, LTC4162L_ARM_SHIP_MODE, ®val);628 if (ret)629 return ret;630 631 return sysfs_emit(buf, "%u\n",632 regval == LTC4162L_ARM_SHIP_MODE_MAGIC ? 1 : 0);633}634 635static ssize_t arm_ship_mode_store(struct device *dev,636 struct device_attribute *attr,637 const char *buf,638 size_t count)639{640 struct power_supply *psy = to_power_supply(dev);641 struct ltc4162l_info *info = power_supply_get_drvdata(psy);642 int ret;643 unsigned int value;644 645 ret = kstrtouint(buf, 0, &value);646 if (ret < 0)647 return ret;648 649 ret = regmap_write(info->regmap, LTC4162L_ARM_SHIP_MODE,650 value ? LTC4162L_ARM_SHIP_MODE_MAGIC : 0);651 if (ret < 0)652 return ret;653 654 return count;655}656 657static DEVICE_ATTR_RW(arm_ship_mode);658 659static struct attribute *ltc4162l_sysfs_entries[] = {660 &dev_attr_charge_status.attr,661 &dev_attr_ibat.attr,662 &dev_attr_vbat.attr,663 &dev_attr_vbat_avg.attr,664 &dev_attr_force_telemetry.attr,665 &dev_attr_arm_ship_mode.attr,666 NULL,667};668 669static const struct attribute_group ltc4162l_attr_group = {670 .name = NULL, /* put in device directory */671 .attrs = ltc4162l_sysfs_entries,672};673 674static const struct attribute_group *ltc4162l_attr_groups[] = {675 <c4162l_attr_group,676 NULL,677};678 679static int ltc4162l_get_property(struct power_supply *psy,680 enum power_supply_property psp,681 union power_supply_propval *val)682{683 struct ltc4162l_info *info = power_supply_get_drvdata(psy);684 685 switch (psp) {686 case POWER_SUPPLY_PROP_STATUS:687 return ltc4162l_get_status(info, val);688 case POWER_SUPPLY_PROP_CHARGE_TYPE:689 return ltc4162l_get_charge_type(info, val);690 case POWER_SUPPLY_PROP_HEALTH:691 return ltc4162l_get_health(info, val);692 case POWER_SUPPLY_PROP_ONLINE:693 return ltc4162l_get_online(info, val);694 case POWER_SUPPLY_PROP_VOLTAGE_NOW:695 return ltc4162l_get_input_voltage(info, val);696 case POWER_SUPPLY_PROP_CURRENT_NOW:697 return ltc4162l_get_input_current(info, val);698 case POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT:699 return ltc4162l_get_icharge(info,700 LTC4162L_ICHARGE_DAC, val);701 case POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT_MAX:702 return ltc4162l_get_icharge(info,703 LTC4162L_CHARGE_CURRENT_SETTING, val);704 case POWER_SUPPLY_PROP_CONSTANT_CHARGE_VOLTAGE:705 return ltc4162l_get_vcharge(info,706 LTC4162L_VCHARGE_DAC, val);707 case POWER_SUPPLY_PROP_CONSTANT_CHARGE_VOLTAGE_MAX:708 return ltc4162l_get_vcharge(info,709 LTC4162L_VCHARGE_SETTING, val);710 case POWER_SUPPLY_PROP_INPUT_CURRENT_LIMIT:711 return ltc4162l_get_iin_limit_dac(info, val);712 case POWER_SUPPLY_PROP_TEMP:713 return ltc4162l_get_die_temp(info, val);714 case POWER_SUPPLY_PROP_CHARGE_TERM_CURRENT:715 return ltc4162l_get_term_current(info, val);716 default:717 return -EINVAL;718 }719}720 721static int ltc4162l_set_property(struct power_supply *psy,722 enum power_supply_property psp,723 const union power_supply_propval *val)724{725 struct ltc4162l_info *info = power_supply_get_drvdata(psy);726 727 switch (psp) {728 case POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT_MAX:729 return ltc4162l_set_icharge(info,730 LTC4162L_CHARGE_CURRENT_SETTING, val->intval);731 case POWER_SUPPLY_PROP_CONSTANT_CHARGE_VOLTAGE_MAX:732 return ltc4162l_set_vcharge(info,733 LTC4162L_VCHARGE_SETTING, val->intval);734 case POWER_SUPPLY_PROP_INPUT_CURRENT_LIMIT:735 return ltc4162l_set_iin_limit(info, val->intval);736 case POWER_SUPPLY_PROP_CHARGE_TERM_CURRENT:737 return ltc4162l_set_term_current(info, val->intval);738 default:739 return -EINVAL;740 }741}742 743static int ltc4162l_property_is_writeable(struct power_supply *psy,744 enum power_supply_property psp)745{746 switch (psp) {747 case POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT_MAX:748 case POWER_SUPPLY_PROP_CONSTANT_CHARGE_VOLTAGE_MAX:749 case POWER_SUPPLY_PROP_INPUT_CURRENT_LIMIT:750 case POWER_SUPPLY_PROP_CHARGE_TERM_CURRENT:751 return 1;752 default:753 return 0;754 }755}756 757/* Charger power supply property routines */758static enum power_supply_property ltc4162l_properties[] = {759 POWER_SUPPLY_PROP_STATUS,760 POWER_SUPPLY_PROP_CHARGE_TYPE,761 POWER_SUPPLY_PROP_HEALTH,762 POWER_SUPPLY_PROP_ONLINE,763 POWER_SUPPLY_PROP_VOLTAGE_NOW,764 POWER_SUPPLY_PROP_CURRENT_NOW,765 POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT,766 POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT_MAX,767 POWER_SUPPLY_PROP_CONSTANT_CHARGE_VOLTAGE,768 POWER_SUPPLY_PROP_CONSTANT_CHARGE_VOLTAGE_MAX,769 POWER_SUPPLY_PROP_INPUT_CURRENT_LIMIT,770 POWER_SUPPLY_PROP_TEMP,771 POWER_SUPPLY_PROP_CHARGE_TERM_CURRENT,772};773 774static const struct power_supply_desc ltc4162l_desc = {775 .name = "ltc4162-l",776 .type = POWER_SUPPLY_TYPE_MAINS,777 .properties = ltc4162l_properties,778 .num_properties = ARRAY_SIZE(ltc4162l_properties),779 .get_property = ltc4162l_get_property,780 .set_property = ltc4162l_set_property,781 .property_is_writeable = ltc4162l_property_is_writeable,782};783 784static bool ltc4162l_is_writeable_reg(struct device *dev, unsigned int reg)785{786 /* all registers up to this one are writeable */787 if (reg <= LTC4162L_CHARGER_CONFIG_BITS)788 return true;789 790 /* The ALERTS registers can be written to clear alerts */791 if (reg >= LTC4162L_LIMIT_ALERTS_REG &&792 reg <= LTC4162L_CHARGE_STATUS_ALERTS_REG)793 return true;794 795 return false;796}797 798static bool ltc4162l_is_volatile_reg(struct device *dev, unsigned int reg)799{800 /* all registers after this one are read-only status registers */801 return reg > LTC4162L_CHARGER_CONFIG_BITS;802}803 804static const struct regmap_config ltc4162l_regmap_config = {805 .reg_bits = 8,806 .val_bits = 16,807 .val_format_endian = REGMAP_ENDIAN_LITTLE,808 .writeable_reg = ltc4162l_is_writeable_reg,809 .volatile_reg = ltc4162l_is_volatile_reg,810 .max_register = LTC4162L_INPUT_UNDERVOLTAGE_DAC,811 .cache_type = REGCACHE_RBTREE,812};813 814static void ltc4162l_clear_interrupts(struct ltc4162l_info *info)815{816 /* Acknowledge interrupt to chip by clearing all events */817 regmap_write(info->regmap, LTC4162L_LIMIT_ALERTS_REG, 0);818 regmap_write(info->regmap, LTC4162L_CHARGER_STATE_ALERTS_REG, 0);819 regmap_write(info->regmap, LTC4162L_CHARGE_STATUS_ALERTS_REG, 0);820}821 822static int ltc4162l_probe(struct i2c_client *client)823{824 struct i2c_adapter *adapter = client->adapter;825 struct device *dev = &client->dev;826 struct ltc4162l_info *info;827 struct power_supply_config ltc4162l_config = {};828 u32 value;829 int ret;830 831 if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_WORD_DATA)) {832 dev_err(dev, "No support for SMBUS_WORD_DATA\n");833 return -ENODEV;834 }835 info = devm_kzalloc(dev, sizeof(*info), GFP_KERNEL);836 if (!info)837 return -ENOMEM;838 839 info->client = client;840 i2c_set_clientdata(client, info);841 842 info->regmap = devm_regmap_init_i2c(client, <c4162l_regmap_config);843 if (IS_ERR(info->regmap)) {844 dev_err(dev, "Failed to initialize register map\n");845 return PTR_ERR(info->regmap);846 }847 848 ret = device_property_read_u32(dev, "lltc,rsnsb-micro-ohms",849 &info->rsnsb);850 if (ret) {851 dev_err(dev, "Missing lltc,rsnsb-micro-ohms property\n");852 return ret;853 }854 if (!info->rsnsb)855 return -EINVAL;856 857 ret = device_property_read_u32(dev, "lltc,rsnsi-micro-ohms",858 &info->rsnsi);859 if (ret) {860 dev_err(dev, "Missing lltc,rsnsi-micro-ohms property\n");861 return ret;862 }863 if (!info->rsnsi)864 return -EINVAL;865 866 if (!device_property_read_u32(dev, "lltc,cell-count", &value))867 info->cell_count = value;868 869 ltc4162l_config.of_node = dev->of_node;870 ltc4162l_config.drv_data = info;871 ltc4162l_config.attr_grp = ltc4162l_attr_groups;872 873 info->charger = devm_power_supply_register(dev, <c4162l_desc,874 <c4162l_config);875 if (IS_ERR(info->charger)) {876 dev_err(dev, "Failed to register charger\n");877 return PTR_ERR(info->charger);878 }879 880 /* Disable the threshold alerts, we're not using them */881 regmap_write(info->regmap, LTC4162L_EN_LIMIT_ALERTS_REG, 0);882 883 /* Enable interrupts on all status changes */884 regmap_write(info->regmap, LTC4162L_EN_CHARGER_STATE_ALERTS_REG,885 0x1fff);886 regmap_write(info->regmap, LTC4162L_EN_CHARGE_STATUS_ALERTS_REG, 0x1f);887 888 ltc4162l_clear_interrupts(info);889 890 return 0;891}892 893static void ltc4162l_alert(struct i2c_client *client,894 enum i2c_alert_protocol type, unsigned int flag)895{896 struct ltc4162l_info *info = i2c_get_clientdata(client);897 898 if (type != I2C_PROTOCOL_SMBUS_ALERT)899 return;900 901 ltc4162l_clear_interrupts(info);902 power_supply_changed(info->charger);903}904 905static const struct i2c_device_id ltc4162l_i2c_id_table[] = {906 { "ltc4162-l" },907 { }908};909MODULE_DEVICE_TABLE(i2c, ltc4162l_i2c_id_table);910 911static const struct of_device_id ltc4162l_of_match[] __maybe_unused = {912 { .compatible = "lltc,ltc4162-l", },913 { },914};915MODULE_DEVICE_TABLE(of, ltc4162l_of_match);916 917static struct i2c_driver ltc4162l_driver = {918 .probe = ltc4162l_probe,919 .alert = ltc4162l_alert,920 .id_table = ltc4162l_i2c_id_table,921 .driver = {922 .name = "ltc4162-l-charger",923 .of_match_table = of_match_ptr(ltc4162l_of_match),924 },925};926module_i2c_driver(ltc4162l_driver);927 928MODULE_LICENSE("GPL");929MODULE_AUTHOR("Mike Looijmans <mike.looijmans@topic.nl>");930MODULE_DESCRIPTION("LTC4162-L charger driver");931