162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0+ 262306a36Sopenharmony_ci// 362306a36Sopenharmony_ci// Fuel gauge driver for Maxim 17042 / 8966 / 8997 462306a36Sopenharmony_ci// Note that Maxim 8966 and 8997 are mfd and this is its subdevice. 562306a36Sopenharmony_ci// 662306a36Sopenharmony_ci// Copyright (C) 2011 Samsung Electronics 762306a36Sopenharmony_ci// MyungJoo Ham <myungjoo.ham@samsung.com> 862306a36Sopenharmony_ci// 962306a36Sopenharmony_ci// This driver is based on max17040_battery.c 1062306a36Sopenharmony_ci 1162306a36Sopenharmony_ci#include <linux/acpi.h> 1262306a36Sopenharmony_ci#include <linux/devm-helpers.h> 1362306a36Sopenharmony_ci#include <linux/init.h> 1462306a36Sopenharmony_ci#include <linux/module.h> 1562306a36Sopenharmony_ci#include <linux/slab.h> 1662306a36Sopenharmony_ci#include <linux/i2c.h> 1762306a36Sopenharmony_ci#include <linux/delay.h> 1862306a36Sopenharmony_ci#include <linux/interrupt.h> 1962306a36Sopenharmony_ci#include <linux/pm.h> 2062306a36Sopenharmony_ci#include <linux/mod_devicetable.h> 2162306a36Sopenharmony_ci#include <linux/power_supply.h> 2262306a36Sopenharmony_ci#include <linux/power/max17042_battery.h> 2362306a36Sopenharmony_ci#include <linux/of.h> 2462306a36Sopenharmony_ci#include <linux/regmap.h> 2562306a36Sopenharmony_ci 2662306a36Sopenharmony_ci/* Status register bits */ 2762306a36Sopenharmony_ci#define STATUS_POR_BIT (1 << 1) 2862306a36Sopenharmony_ci#define STATUS_BST_BIT (1 << 3) 2962306a36Sopenharmony_ci#define STATUS_VMN_BIT (1 << 8) 3062306a36Sopenharmony_ci#define STATUS_TMN_BIT (1 << 9) 3162306a36Sopenharmony_ci#define STATUS_SMN_BIT (1 << 10) 3262306a36Sopenharmony_ci#define STATUS_BI_BIT (1 << 11) 3362306a36Sopenharmony_ci#define STATUS_VMX_BIT (1 << 12) 3462306a36Sopenharmony_ci#define STATUS_TMX_BIT (1 << 13) 3562306a36Sopenharmony_ci#define STATUS_SMX_BIT (1 << 14) 3662306a36Sopenharmony_ci#define STATUS_BR_BIT (1 << 15) 3762306a36Sopenharmony_ci 3862306a36Sopenharmony_ci/* Interrupt mask bits */ 3962306a36Sopenharmony_ci#define CONFIG_ALRT_BIT_ENBL (1 << 2) 4062306a36Sopenharmony_ci 4162306a36Sopenharmony_ci#define VFSOC0_LOCK 0x0000 4262306a36Sopenharmony_ci#define VFSOC0_UNLOCK 0x0080 4362306a36Sopenharmony_ci#define MODEL_UNLOCK1 0X0059 4462306a36Sopenharmony_ci#define MODEL_UNLOCK2 0X00C4 4562306a36Sopenharmony_ci#define MODEL_LOCK1 0X0000 4662306a36Sopenharmony_ci#define MODEL_LOCK2 0X0000 4762306a36Sopenharmony_ci 4862306a36Sopenharmony_ci#define dQ_ACC_DIV 0x4 4962306a36Sopenharmony_ci#define dP_ACC_100 0x1900 5062306a36Sopenharmony_ci#define dP_ACC_200 0x3200 5162306a36Sopenharmony_ci 5262306a36Sopenharmony_ci#define MAX17042_VMAX_TOLERANCE 50 /* 50 mV */ 5362306a36Sopenharmony_ci 5462306a36Sopenharmony_cistruct max17042_chip { 5562306a36Sopenharmony_ci struct i2c_client *client; 5662306a36Sopenharmony_ci struct regmap *regmap; 5762306a36Sopenharmony_ci struct power_supply *battery; 5862306a36Sopenharmony_ci enum max170xx_chip_type chip_type; 5962306a36Sopenharmony_ci struct max17042_platform_data *pdata; 6062306a36Sopenharmony_ci struct work_struct work; 6162306a36Sopenharmony_ci int init_complete; 6262306a36Sopenharmony_ci}; 6362306a36Sopenharmony_ci 6462306a36Sopenharmony_cistatic enum power_supply_property max17042_battery_props[] = { 6562306a36Sopenharmony_ci POWER_SUPPLY_PROP_STATUS, 6662306a36Sopenharmony_ci POWER_SUPPLY_PROP_PRESENT, 6762306a36Sopenharmony_ci POWER_SUPPLY_PROP_TECHNOLOGY, 6862306a36Sopenharmony_ci POWER_SUPPLY_PROP_CYCLE_COUNT, 6962306a36Sopenharmony_ci POWER_SUPPLY_PROP_VOLTAGE_MAX, 7062306a36Sopenharmony_ci POWER_SUPPLY_PROP_VOLTAGE_MIN, 7162306a36Sopenharmony_ci POWER_SUPPLY_PROP_VOLTAGE_MIN_DESIGN, 7262306a36Sopenharmony_ci POWER_SUPPLY_PROP_VOLTAGE_NOW, 7362306a36Sopenharmony_ci POWER_SUPPLY_PROP_VOLTAGE_AVG, 7462306a36Sopenharmony_ci POWER_SUPPLY_PROP_VOLTAGE_OCV, 7562306a36Sopenharmony_ci POWER_SUPPLY_PROP_CAPACITY, 7662306a36Sopenharmony_ci POWER_SUPPLY_PROP_CHARGE_FULL_DESIGN, 7762306a36Sopenharmony_ci POWER_SUPPLY_PROP_CHARGE_FULL, 7862306a36Sopenharmony_ci POWER_SUPPLY_PROP_CHARGE_NOW, 7962306a36Sopenharmony_ci POWER_SUPPLY_PROP_CHARGE_COUNTER, 8062306a36Sopenharmony_ci POWER_SUPPLY_PROP_CHARGE_TERM_CURRENT, 8162306a36Sopenharmony_ci POWER_SUPPLY_PROP_TEMP, 8262306a36Sopenharmony_ci POWER_SUPPLY_PROP_TEMP_ALERT_MIN, 8362306a36Sopenharmony_ci POWER_SUPPLY_PROP_TEMP_ALERT_MAX, 8462306a36Sopenharmony_ci POWER_SUPPLY_PROP_TEMP_MIN, 8562306a36Sopenharmony_ci POWER_SUPPLY_PROP_TEMP_MAX, 8662306a36Sopenharmony_ci POWER_SUPPLY_PROP_HEALTH, 8762306a36Sopenharmony_ci POWER_SUPPLY_PROP_SCOPE, 8862306a36Sopenharmony_ci POWER_SUPPLY_PROP_TIME_TO_EMPTY_NOW, 8962306a36Sopenharmony_ci // these two have to be at the end on the list 9062306a36Sopenharmony_ci POWER_SUPPLY_PROP_CURRENT_NOW, 9162306a36Sopenharmony_ci POWER_SUPPLY_PROP_CURRENT_AVG, 9262306a36Sopenharmony_ci}; 9362306a36Sopenharmony_ci 9462306a36Sopenharmony_cistatic int max17042_get_temperature(struct max17042_chip *chip, int *temp) 9562306a36Sopenharmony_ci{ 9662306a36Sopenharmony_ci int ret; 9762306a36Sopenharmony_ci u32 data; 9862306a36Sopenharmony_ci struct regmap *map = chip->regmap; 9962306a36Sopenharmony_ci 10062306a36Sopenharmony_ci ret = regmap_read(map, MAX17042_TEMP, &data); 10162306a36Sopenharmony_ci if (ret < 0) 10262306a36Sopenharmony_ci return ret; 10362306a36Sopenharmony_ci 10462306a36Sopenharmony_ci *temp = sign_extend32(data, 15); 10562306a36Sopenharmony_ci /* The value is converted into deci-centigrade scale */ 10662306a36Sopenharmony_ci /* Units of LSB = 1 / 256 degree Celsius */ 10762306a36Sopenharmony_ci *temp = *temp * 10 / 256; 10862306a36Sopenharmony_ci return 0; 10962306a36Sopenharmony_ci} 11062306a36Sopenharmony_ci 11162306a36Sopenharmony_cistatic int max17042_get_status(struct max17042_chip *chip, int *status) 11262306a36Sopenharmony_ci{ 11362306a36Sopenharmony_ci int ret, charge_full, charge_now; 11462306a36Sopenharmony_ci int avg_current; 11562306a36Sopenharmony_ci u32 data; 11662306a36Sopenharmony_ci 11762306a36Sopenharmony_ci ret = power_supply_am_i_supplied(chip->battery); 11862306a36Sopenharmony_ci if (ret < 0) { 11962306a36Sopenharmony_ci *status = POWER_SUPPLY_STATUS_UNKNOWN; 12062306a36Sopenharmony_ci return 0; 12162306a36Sopenharmony_ci } 12262306a36Sopenharmony_ci if (ret == 0) { 12362306a36Sopenharmony_ci *status = POWER_SUPPLY_STATUS_DISCHARGING; 12462306a36Sopenharmony_ci return 0; 12562306a36Sopenharmony_ci } 12662306a36Sopenharmony_ci 12762306a36Sopenharmony_ci /* 12862306a36Sopenharmony_ci * The MAX170xx has builtin end-of-charge detection and will update 12962306a36Sopenharmony_ci * FullCAP to match RepCap when it detects end of charging. 13062306a36Sopenharmony_ci * 13162306a36Sopenharmony_ci * When this cycle the battery gets charged to a higher (calculated) 13262306a36Sopenharmony_ci * capacity then the previous cycle then FullCAP will get updated 13362306a36Sopenharmony_ci * continuously once end-of-charge detection kicks in, so allow the 13462306a36Sopenharmony_ci * 2 to differ a bit. 13562306a36Sopenharmony_ci */ 13662306a36Sopenharmony_ci 13762306a36Sopenharmony_ci ret = regmap_read(chip->regmap, MAX17042_FullCAP, &charge_full); 13862306a36Sopenharmony_ci if (ret < 0) 13962306a36Sopenharmony_ci return ret; 14062306a36Sopenharmony_ci 14162306a36Sopenharmony_ci ret = regmap_read(chip->regmap, MAX17042_RepCap, &charge_now); 14262306a36Sopenharmony_ci if (ret < 0) 14362306a36Sopenharmony_ci return ret; 14462306a36Sopenharmony_ci 14562306a36Sopenharmony_ci if ((charge_full - charge_now) <= MAX17042_FULL_THRESHOLD) { 14662306a36Sopenharmony_ci *status = POWER_SUPPLY_STATUS_FULL; 14762306a36Sopenharmony_ci return 0; 14862306a36Sopenharmony_ci } 14962306a36Sopenharmony_ci 15062306a36Sopenharmony_ci /* 15162306a36Sopenharmony_ci * Even though we are supplied, we may still be discharging if the 15262306a36Sopenharmony_ci * supply is e.g. only delivering 5V 0.5A. Check current if available. 15362306a36Sopenharmony_ci */ 15462306a36Sopenharmony_ci if (!chip->pdata->enable_current_sense) { 15562306a36Sopenharmony_ci *status = POWER_SUPPLY_STATUS_CHARGING; 15662306a36Sopenharmony_ci return 0; 15762306a36Sopenharmony_ci } 15862306a36Sopenharmony_ci 15962306a36Sopenharmony_ci ret = regmap_read(chip->regmap, MAX17042_AvgCurrent, &data); 16062306a36Sopenharmony_ci if (ret < 0) 16162306a36Sopenharmony_ci return ret; 16262306a36Sopenharmony_ci 16362306a36Sopenharmony_ci avg_current = sign_extend32(data, 15); 16462306a36Sopenharmony_ci avg_current *= 1562500 / chip->pdata->r_sns; 16562306a36Sopenharmony_ci 16662306a36Sopenharmony_ci if (avg_current > 0) 16762306a36Sopenharmony_ci *status = POWER_SUPPLY_STATUS_CHARGING; 16862306a36Sopenharmony_ci else 16962306a36Sopenharmony_ci *status = POWER_SUPPLY_STATUS_DISCHARGING; 17062306a36Sopenharmony_ci 17162306a36Sopenharmony_ci return 0; 17262306a36Sopenharmony_ci} 17362306a36Sopenharmony_ci 17462306a36Sopenharmony_cistatic int max17042_get_battery_health(struct max17042_chip *chip, int *health) 17562306a36Sopenharmony_ci{ 17662306a36Sopenharmony_ci int temp, vavg, vbatt, ret; 17762306a36Sopenharmony_ci u32 val; 17862306a36Sopenharmony_ci 17962306a36Sopenharmony_ci ret = regmap_read(chip->regmap, MAX17042_AvgVCELL, &val); 18062306a36Sopenharmony_ci if (ret < 0) 18162306a36Sopenharmony_ci goto health_error; 18262306a36Sopenharmony_ci 18362306a36Sopenharmony_ci /* bits [0-3] unused */ 18462306a36Sopenharmony_ci vavg = val * 625 / 8; 18562306a36Sopenharmony_ci /* Convert to millivolts */ 18662306a36Sopenharmony_ci vavg /= 1000; 18762306a36Sopenharmony_ci 18862306a36Sopenharmony_ci ret = regmap_read(chip->regmap, MAX17042_VCELL, &val); 18962306a36Sopenharmony_ci if (ret < 0) 19062306a36Sopenharmony_ci goto health_error; 19162306a36Sopenharmony_ci 19262306a36Sopenharmony_ci /* bits [0-3] unused */ 19362306a36Sopenharmony_ci vbatt = val * 625 / 8; 19462306a36Sopenharmony_ci /* Convert to millivolts */ 19562306a36Sopenharmony_ci vbatt /= 1000; 19662306a36Sopenharmony_ci 19762306a36Sopenharmony_ci if (vavg < chip->pdata->vmin) { 19862306a36Sopenharmony_ci *health = POWER_SUPPLY_HEALTH_DEAD; 19962306a36Sopenharmony_ci goto out; 20062306a36Sopenharmony_ci } 20162306a36Sopenharmony_ci 20262306a36Sopenharmony_ci if (vbatt > chip->pdata->vmax + MAX17042_VMAX_TOLERANCE) { 20362306a36Sopenharmony_ci *health = POWER_SUPPLY_HEALTH_OVERVOLTAGE; 20462306a36Sopenharmony_ci goto out; 20562306a36Sopenharmony_ci } 20662306a36Sopenharmony_ci 20762306a36Sopenharmony_ci ret = max17042_get_temperature(chip, &temp); 20862306a36Sopenharmony_ci if (ret < 0) 20962306a36Sopenharmony_ci goto health_error; 21062306a36Sopenharmony_ci 21162306a36Sopenharmony_ci if (temp < chip->pdata->temp_min) { 21262306a36Sopenharmony_ci *health = POWER_SUPPLY_HEALTH_COLD; 21362306a36Sopenharmony_ci goto out; 21462306a36Sopenharmony_ci } 21562306a36Sopenharmony_ci 21662306a36Sopenharmony_ci if (temp > chip->pdata->temp_max) { 21762306a36Sopenharmony_ci *health = POWER_SUPPLY_HEALTH_OVERHEAT; 21862306a36Sopenharmony_ci goto out; 21962306a36Sopenharmony_ci } 22062306a36Sopenharmony_ci 22162306a36Sopenharmony_ci *health = POWER_SUPPLY_HEALTH_GOOD; 22262306a36Sopenharmony_ci 22362306a36Sopenharmony_ciout: 22462306a36Sopenharmony_ci return 0; 22562306a36Sopenharmony_ci 22662306a36Sopenharmony_cihealth_error: 22762306a36Sopenharmony_ci return ret; 22862306a36Sopenharmony_ci} 22962306a36Sopenharmony_ci 23062306a36Sopenharmony_cistatic int max17042_get_property(struct power_supply *psy, 23162306a36Sopenharmony_ci enum power_supply_property psp, 23262306a36Sopenharmony_ci union power_supply_propval *val) 23362306a36Sopenharmony_ci{ 23462306a36Sopenharmony_ci struct max17042_chip *chip = power_supply_get_drvdata(psy); 23562306a36Sopenharmony_ci struct regmap *map = chip->regmap; 23662306a36Sopenharmony_ci int ret; 23762306a36Sopenharmony_ci u32 data; 23862306a36Sopenharmony_ci u64 data64; 23962306a36Sopenharmony_ci 24062306a36Sopenharmony_ci if (!chip->init_complete) 24162306a36Sopenharmony_ci return -EAGAIN; 24262306a36Sopenharmony_ci 24362306a36Sopenharmony_ci switch (psp) { 24462306a36Sopenharmony_ci case POWER_SUPPLY_PROP_STATUS: 24562306a36Sopenharmony_ci ret = max17042_get_status(chip, &val->intval); 24662306a36Sopenharmony_ci if (ret < 0) 24762306a36Sopenharmony_ci return ret; 24862306a36Sopenharmony_ci break; 24962306a36Sopenharmony_ci case POWER_SUPPLY_PROP_PRESENT: 25062306a36Sopenharmony_ci ret = regmap_read(map, MAX17042_STATUS, &data); 25162306a36Sopenharmony_ci if (ret < 0) 25262306a36Sopenharmony_ci return ret; 25362306a36Sopenharmony_ci 25462306a36Sopenharmony_ci if (data & MAX17042_STATUS_BattAbsent) 25562306a36Sopenharmony_ci val->intval = 0; 25662306a36Sopenharmony_ci else 25762306a36Sopenharmony_ci val->intval = 1; 25862306a36Sopenharmony_ci break; 25962306a36Sopenharmony_ci case POWER_SUPPLY_PROP_TECHNOLOGY: 26062306a36Sopenharmony_ci val->intval = POWER_SUPPLY_TECHNOLOGY_LION; 26162306a36Sopenharmony_ci break; 26262306a36Sopenharmony_ci case POWER_SUPPLY_PROP_CYCLE_COUNT: 26362306a36Sopenharmony_ci ret = regmap_read(map, MAX17042_Cycles, &data); 26462306a36Sopenharmony_ci if (ret < 0) 26562306a36Sopenharmony_ci return ret; 26662306a36Sopenharmony_ci 26762306a36Sopenharmony_ci val->intval = data; 26862306a36Sopenharmony_ci break; 26962306a36Sopenharmony_ci case POWER_SUPPLY_PROP_VOLTAGE_MAX: 27062306a36Sopenharmony_ci ret = regmap_read(map, MAX17042_MinMaxVolt, &data); 27162306a36Sopenharmony_ci if (ret < 0) 27262306a36Sopenharmony_ci return ret; 27362306a36Sopenharmony_ci 27462306a36Sopenharmony_ci val->intval = data >> 8; 27562306a36Sopenharmony_ci val->intval *= 20000; /* Units of LSB = 20mV */ 27662306a36Sopenharmony_ci break; 27762306a36Sopenharmony_ci case POWER_SUPPLY_PROP_VOLTAGE_MIN: 27862306a36Sopenharmony_ci ret = regmap_read(map, MAX17042_MinMaxVolt, &data); 27962306a36Sopenharmony_ci if (ret < 0) 28062306a36Sopenharmony_ci return ret; 28162306a36Sopenharmony_ci 28262306a36Sopenharmony_ci val->intval = (data & 0xff) * 20000; /* Units of 20mV */ 28362306a36Sopenharmony_ci break; 28462306a36Sopenharmony_ci case POWER_SUPPLY_PROP_VOLTAGE_MIN_DESIGN: 28562306a36Sopenharmony_ci if (chip->chip_type == MAXIM_DEVICE_TYPE_MAX17042) 28662306a36Sopenharmony_ci ret = regmap_read(map, MAX17042_V_empty, &data); 28762306a36Sopenharmony_ci else 28862306a36Sopenharmony_ci ret = regmap_read(map, MAX17047_V_empty, &data); 28962306a36Sopenharmony_ci if (ret < 0) 29062306a36Sopenharmony_ci return ret; 29162306a36Sopenharmony_ci 29262306a36Sopenharmony_ci val->intval = data >> 7; 29362306a36Sopenharmony_ci val->intval *= 10000; /* Units of LSB = 10mV */ 29462306a36Sopenharmony_ci break; 29562306a36Sopenharmony_ci case POWER_SUPPLY_PROP_VOLTAGE_NOW: 29662306a36Sopenharmony_ci ret = regmap_read(map, MAX17042_VCELL, &data); 29762306a36Sopenharmony_ci if (ret < 0) 29862306a36Sopenharmony_ci return ret; 29962306a36Sopenharmony_ci 30062306a36Sopenharmony_ci val->intval = data * 625 / 8; 30162306a36Sopenharmony_ci break; 30262306a36Sopenharmony_ci case POWER_SUPPLY_PROP_VOLTAGE_AVG: 30362306a36Sopenharmony_ci ret = regmap_read(map, MAX17042_AvgVCELL, &data); 30462306a36Sopenharmony_ci if (ret < 0) 30562306a36Sopenharmony_ci return ret; 30662306a36Sopenharmony_ci 30762306a36Sopenharmony_ci val->intval = data * 625 / 8; 30862306a36Sopenharmony_ci break; 30962306a36Sopenharmony_ci case POWER_SUPPLY_PROP_VOLTAGE_OCV: 31062306a36Sopenharmony_ci ret = regmap_read(map, MAX17042_OCVInternal, &data); 31162306a36Sopenharmony_ci if (ret < 0) 31262306a36Sopenharmony_ci return ret; 31362306a36Sopenharmony_ci 31462306a36Sopenharmony_ci val->intval = data * 625 / 8; 31562306a36Sopenharmony_ci break; 31662306a36Sopenharmony_ci case POWER_SUPPLY_PROP_CAPACITY: 31762306a36Sopenharmony_ci if (chip->pdata->enable_current_sense) 31862306a36Sopenharmony_ci ret = regmap_read(map, MAX17042_RepSOC, &data); 31962306a36Sopenharmony_ci else 32062306a36Sopenharmony_ci ret = regmap_read(map, MAX17042_VFSOC, &data); 32162306a36Sopenharmony_ci if (ret < 0) 32262306a36Sopenharmony_ci return ret; 32362306a36Sopenharmony_ci 32462306a36Sopenharmony_ci val->intval = data >> 8; 32562306a36Sopenharmony_ci break; 32662306a36Sopenharmony_ci case POWER_SUPPLY_PROP_CHARGE_FULL_DESIGN: 32762306a36Sopenharmony_ci ret = regmap_read(map, MAX17042_DesignCap, &data); 32862306a36Sopenharmony_ci if (ret < 0) 32962306a36Sopenharmony_ci return ret; 33062306a36Sopenharmony_ci 33162306a36Sopenharmony_ci data64 = data * 5000000ll; 33262306a36Sopenharmony_ci do_div(data64, chip->pdata->r_sns); 33362306a36Sopenharmony_ci val->intval = data64; 33462306a36Sopenharmony_ci break; 33562306a36Sopenharmony_ci case POWER_SUPPLY_PROP_CHARGE_FULL: 33662306a36Sopenharmony_ci ret = regmap_read(map, MAX17042_FullCAP, &data); 33762306a36Sopenharmony_ci if (ret < 0) 33862306a36Sopenharmony_ci return ret; 33962306a36Sopenharmony_ci 34062306a36Sopenharmony_ci data64 = data * 5000000ll; 34162306a36Sopenharmony_ci do_div(data64, chip->pdata->r_sns); 34262306a36Sopenharmony_ci val->intval = data64; 34362306a36Sopenharmony_ci break; 34462306a36Sopenharmony_ci case POWER_SUPPLY_PROP_CHARGE_NOW: 34562306a36Sopenharmony_ci ret = regmap_read(map, MAX17042_RepCap, &data); 34662306a36Sopenharmony_ci if (ret < 0) 34762306a36Sopenharmony_ci return ret; 34862306a36Sopenharmony_ci 34962306a36Sopenharmony_ci data64 = data * 5000000ll; 35062306a36Sopenharmony_ci do_div(data64, chip->pdata->r_sns); 35162306a36Sopenharmony_ci val->intval = data64; 35262306a36Sopenharmony_ci break; 35362306a36Sopenharmony_ci case POWER_SUPPLY_PROP_CHARGE_COUNTER: 35462306a36Sopenharmony_ci ret = regmap_read(map, MAX17042_QH, &data); 35562306a36Sopenharmony_ci if (ret < 0) 35662306a36Sopenharmony_ci return ret; 35762306a36Sopenharmony_ci 35862306a36Sopenharmony_ci data64 = sign_extend64(data, 15) * 5000000ll; 35962306a36Sopenharmony_ci val->intval = div_s64(data64, chip->pdata->r_sns); 36062306a36Sopenharmony_ci break; 36162306a36Sopenharmony_ci case POWER_SUPPLY_PROP_TEMP: 36262306a36Sopenharmony_ci ret = max17042_get_temperature(chip, &val->intval); 36362306a36Sopenharmony_ci if (ret < 0) 36462306a36Sopenharmony_ci return ret; 36562306a36Sopenharmony_ci break; 36662306a36Sopenharmony_ci case POWER_SUPPLY_PROP_TEMP_ALERT_MIN: 36762306a36Sopenharmony_ci ret = regmap_read(map, MAX17042_TALRT_Th, &data); 36862306a36Sopenharmony_ci if (ret < 0) 36962306a36Sopenharmony_ci return ret; 37062306a36Sopenharmony_ci /* LSB is Alert Minimum. In deci-centigrade */ 37162306a36Sopenharmony_ci val->intval = sign_extend32(data & 0xff, 7) * 10; 37262306a36Sopenharmony_ci break; 37362306a36Sopenharmony_ci case POWER_SUPPLY_PROP_TEMP_ALERT_MAX: 37462306a36Sopenharmony_ci ret = regmap_read(map, MAX17042_TALRT_Th, &data); 37562306a36Sopenharmony_ci if (ret < 0) 37662306a36Sopenharmony_ci return ret; 37762306a36Sopenharmony_ci /* MSB is Alert Maximum. In deci-centigrade */ 37862306a36Sopenharmony_ci val->intval = sign_extend32(data >> 8, 7) * 10; 37962306a36Sopenharmony_ci break; 38062306a36Sopenharmony_ci case POWER_SUPPLY_PROP_TEMP_MIN: 38162306a36Sopenharmony_ci val->intval = chip->pdata->temp_min; 38262306a36Sopenharmony_ci break; 38362306a36Sopenharmony_ci case POWER_SUPPLY_PROP_TEMP_MAX: 38462306a36Sopenharmony_ci val->intval = chip->pdata->temp_max; 38562306a36Sopenharmony_ci break; 38662306a36Sopenharmony_ci case POWER_SUPPLY_PROP_HEALTH: 38762306a36Sopenharmony_ci ret = max17042_get_battery_health(chip, &val->intval); 38862306a36Sopenharmony_ci if (ret < 0) 38962306a36Sopenharmony_ci return ret; 39062306a36Sopenharmony_ci break; 39162306a36Sopenharmony_ci case POWER_SUPPLY_PROP_SCOPE: 39262306a36Sopenharmony_ci val->intval = POWER_SUPPLY_SCOPE_SYSTEM; 39362306a36Sopenharmony_ci break; 39462306a36Sopenharmony_ci case POWER_SUPPLY_PROP_CURRENT_NOW: 39562306a36Sopenharmony_ci if (chip->pdata->enable_current_sense) { 39662306a36Sopenharmony_ci ret = regmap_read(map, MAX17042_Current, &data); 39762306a36Sopenharmony_ci if (ret < 0) 39862306a36Sopenharmony_ci return ret; 39962306a36Sopenharmony_ci 40062306a36Sopenharmony_ci data64 = sign_extend64(data, 15) * 1562500ll; 40162306a36Sopenharmony_ci val->intval = div_s64(data64, chip->pdata->r_sns); 40262306a36Sopenharmony_ci } else { 40362306a36Sopenharmony_ci return -EINVAL; 40462306a36Sopenharmony_ci } 40562306a36Sopenharmony_ci break; 40662306a36Sopenharmony_ci case POWER_SUPPLY_PROP_CURRENT_AVG: 40762306a36Sopenharmony_ci if (chip->pdata->enable_current_sense) { 40862306a36Sopenharmony_ci ret = regmap_read(map, MAX17042_AvgCurrent, &data); 40962306a36Sopenharmony_ci if (ret < 0) 41062306a36Sopenharmony_ci return ret; 41162306a36Sopenharmony_ci 41262306a36Sopenharmony_ci data64 = sign_extend64(data, 15) * 1562500ll; 41362306a36Sopenharmony_ci val->intval = div_s64(data64, chip->pdata->r_sns); 41462306a36Sopenharmony_ci } else { 41562306a36Sopenharmony_ci return -EINVAL; 41662306a36Sopenharmony_ci } 41762306a36Sopenharmony_ci break; 41862306a36Sopenharmony_ci case POWER_SUPPLY_PROP_CHARGE_TERM_CURRENT: 41962306a36Sopenharmony_ci ret = regmap_read(map, MAX17042_ICHGTerm, &data); 42062306a36Sopenharmony_ci if (ret < 0) 42162306a36Sopenharmony_ci return ret; 42262306a36Sopenharmony_ci 42362306a36Sopenharmony_ci data64 = data * 1562500ll; 42462306a36Sopenharmony_ci val->intval = div_s64(data64, chip->pdata->r_sns); 42562306a36Sopenharmony_ci break; 42662306a36Sopenharmony_ci case POWER_SUPPLY_PROP_TIME_TO_EMPTY_NOW: 42762306a36Sopenharmony_ci ret = regmap_read(map, MAX17042_TTE, &data); 42862306a36Sopenharmony_ci if (ret < 0) 42962306a36Sopenharmony_ci return ret; 43062306a36Sopenharmony_ci 43162306a36Sopenharmony_ci val->intval = data * 5625 / 1000; 43262306a36Sopenharmony_ci break; 43362306a36Sopenharmony_ci default: 43462306a36Sopenharmony_ci return -EINVAL; 43562306a36Sopenharmony_ci } 43662306a36Sopenharmony_ci return 0; 43762306a36Sopenharmony_ci} 43862306a36Sopenharmony_ci 43962306a36Sopenharmony_cistatic int max17042_set_property(struct power_supply *psy, 44062306a36Sopenharmony_ci enum power_supply_property psp, 44162306a36Sopenharmony_ci const union power_supply_propval *val) 44262306a36Sopenharmony_ci{ 44362306a36Sopenharmony_ci struct max17042_chip *chip = power_supply_get_drvdata(psy); 44462306a36Sopenharmony_ci struct regmap *map = chip->regmap; 44562306a36Sopenharmony_ci int ret = 0; 44662306a36Sopenharmony_ci u32 data; 44762306a36Sopenharmony_ci int8_t temp; 44862306a36Sopenharmony_ci 44962306a36Sopenharmony_ci switch (psp) { 45062306a36Sopenharmony_ci case POWER_SUPPLY_PROP_TEMP_ALERT_MIN: 45162306a36Sopenharmony_ci ret = regmap_read(map, MAX17042_TALRT_Th, &data); 45262306a36Sopenharmony_ci if (ret < 0) 45362306a36Sopenharmony_ci return ret; 45462306a36Sopenharmony_ci 45562306a36Sopenharmony_ci /* Input in deci-centigrade, convert to centigrade */ 45662306a36Sopenharmony_ci temp = val->intval / 10; 45762306a36Sopenharmony_ci /* force min < max */ 45862306a36Sopenharmony_ci if (temp >= (int8_t)(data >> 8)) 45962306a36Sopenharmony_ci temp = (int8_t)(data >> 8) - 1; 46062306a36Sopenharmony_ci /* Write both MAX and MIN ALERT */ 46162306a36Sopenharmony_ci data = (data & 0xff00) + temp; 46262306a36Sopenharmony_ci ret = regmap_write(map, MAX17042_TALRT_Th, data); 46362306a36Sopenharmony_ci break; 46462306a36Sopenharmony_ci case POWER_SUPPLY_PROP_TEMP_ALERT_MAX: 46562306a36Sopenharmony_ci ret = regmap_read(map, MAX17042_TALRT_Th, &data); 46662306a36Sopenharmony_ci if (ret < 0) 46762306a36Sopenharmony_ci return ret; 46862306a36Sopenharmony_ci 46962306a36Sopenharmony_ci /* Input in Deci-Centigrade, convert to centigrade */ 47062306a36Sopenharmony_ci temp = val->intval / 10; 47162306a36Sopenharmony_ci /* force max > min */ 47262306a36Sopenharmony_ci if (temp <= (int8_t)(data & 0xff)) 47362306a36Sopenharmony_ci temp = (int8_t)(data & 0xff) + 1; 47462306a36Sopenharmony_ci /* Write both MAX and MIN ALERT */ 47562306a36Sopenharmony_ci data = (data & 0xff) + (temp << 8); 47662306a36Sopenharmony_ci ret = regmap_write(map, MAX17042_TALRT_Th, data); 47762306a36Sopenharmony_ci break; 47862306a36Sopenharmony_ci default: 47962306a36Sopenharmony_ci ret = -EINVAL; 48062306a36Sopenharmony_ci } 48162306a36Sopenharmony_ci 48262306a36Sopenharmony_ci return ret; 48362306a36Sopenharmony_ci} 48462306a36Sopenharmony_ci 48562306a36Sopenharmony_cistatic int max17042_property_is_writeable(struct power_supply *psy, 48662306a36Sopenharmony_ci enum power_supply_property psp) 48762306a36Sopenharmony_ci{ 48862306a36Sopenharmony_ci int ret; 48962306a36Sopenharmony_ci 49062306a36Sopenharmony_ci switch (psp) { 49162306a36Sopenharmony_ci case POWER_SUPPLY_PROP_TEMP_ALERT_MIN: 49262306a36Sopenharmony_ci case POWER_SUPPLY_PROP_TEMP_ALERT_MAX: 49362306a36Sopenharmony_ci ret = 1; 49462306a36Sopenharmony_ci break; 49562306a36Sopenharmony_ci default: 49662306a36Sopenharmony_ci ret = 0; 49762306a36Sopenharmony_ci } 49862306a36Sopenharmony_ci 49962306a36Sopenharmony_ci return ret; 50062306a36Sopenharmony_ci} 50162306a36Sopenharmony_ci 50262306a36Sopenharmony_cistatic int max17042_write_verify_reg(struct regmap *map, u8 reg, u32 value) 50362306a36Sopenharmony_ci{ 50462306a36Sopenharmony_ci int retries = 8; 50562306a36Sopenharmony_ci int ret; 50662306a36Sopenharmony_ci u32 read_value; 50762306a36Sopenharmony_ci 50862306a36Sopenharmony_ci do { 50962306a36Sopenharmony_ci ret = regmap_write(map, reg, value); 51062306a36Sopenharmony_ci regmap_read(map, reg, &read_value); 51162306a36Sopenharmony_ci if (read_value != value) { 51262306a36Sopenharmony_ci ret = -EIO; 51362306a36Sopenharmony_ci retries--; 51462306a36Sopenharmony_ci } 51562306a36Sopenharmony_ci } while (retries && read_value != value); 51662306a36Sopenharmony_ci 51762306a36Sopenharmony_ci if (ret < 0) 51862306a36Sopenharmony_ci pr_err("%s: err %d\n", __func__, ret); 51962306a36Sopenharmony_ci 52062306a36Sopenharmony_ci return ret; 52162306a36Sopenharmony_ci} 52262306a36Sopenharmony_ci 52362306a36Sopenharmony_cistatic inline void max17042_override_por(struct regmap *map, 52462306a36Sopenharmony_ci u8 reg, u16 value) 52562306a36Sopenharmony_ci{ 52662306a36Sopenharmony_ci if (value) 52762306a36Sopenharmony_ci regmap_write(map, reg, value); 52862306a36Sopenharmony_ci} 52962306a36Sopenharmony_ci 53062306a36Sopenharmony_cistatic inline void max17042_unlock_model(struct max17042_chip *chip) 53162306a36Sopenharmony_ci{ 53262306a36Sopenharmony_ci struct regmap *map = chip->regmap; 53362306a36Sopenharmony_ci 53462306a36Sopenharmony_ci regmap_write(map, MAX17042_MLOCKReg1, MODEL_UNLOCK1); 53562306a36Sopenharmony_ci regmap_write(map, MAX17042_MLOCKReg2, MODEL_UNLOCK2); 53662306a36Sopenharmony_ci} 53762306a36Sopenharmony_ci 53862306a36Sopenharmony_cistatic inline void max17042_lock_model(struct max17042_chip *chip) 53962306a36Sopenharmony_ci{ 54062306a36Sopenharmony_ci struct regmap *map = chip->regmap; 54162306a36Sopenharmony_ci 54262306a36Sopenharmony_ci regmap_write(map, MAX17042_MLOCKReg1, MODEL_LOCK1); 54362306a36Sopenharmony_ci regmap_write(map, MAX17042_MLOCKReg2, MODEL_LOCK2); 54462306a36Sopenharmony_ci} 54562306a36Sopenharmony_ci 54662306a36Sopenharmony_cistatic inline void max17042_write_model_data(struct max17042_chip *chip, 54762306a36Sopenharmony_ci u8 addr, int size) 54862306a36Sopenharmony_ci{ 54962306a36Sopenharmony_ci struct regmap *map = chip->regmap; 55062306a36Sopenharmony_ci int i; 55162306a36Sopenharmony_ci 55262306a36Sopenharmony_ci for (i = 0; i < size; i++) 55362306a36Sopenharmony_ci regmap_write(map, addr + i, 55462306a36Sopenharmony_ci chip->pdata->config_data->cell_char_tbl[i]); 55562306a36Sopenharmony_ci} 55662306a36Sopenharmony_ci 55762306a36Sopenharmony_cistatic inline void max17042_read_model_data(struct max17042_chip *chip, 55862306a36Sopenharmony_ci u8 addr, u16 *data, int size) 55962306a36Sopenharmony_ci{ 56062306a36Sopenharmony_ci struct regmap *map = chip->regmap; 56162306a36Sopenharmony_ci int i; 56262306a36Sopenharmony_ci u32 tmp; 56362306a36Sopenharmony_ci 56462306a36Sopenharmony_ci for (i = 0; i < size; i++) { 56562306a36Sopenharmony_ci regmap_read(map, addr + i, &tmp); 56662306a36Sopenharmony_ci data[i] = (u16)tmp; 56762306a36Sopenharmony_ci } 56862306a36Sopenharmony_ci} 56962306a36Sopenharmony_ci 57062306a36Sopenharmony_cistatic inline int max17042_model_data_compare(struct max17042_chip *chip, 57162306a36Sopenharmony_ci u16 *data1, u16 *data2, int size) 57262306a36Sopenharmony_ci{ 57362306a36Sopenharmony_ci int i; 57462306a36Sopenharmony_ci 57562306a36Sopenharmony_ci if (memcmp(data1, data2, size)) { 57662306a36Sopenharmony_ci dev_err(&chip->client->dev, "%s compare failed\n", __func__); 57762306a36Sopenharmony_ci for (i = 0; i < size; i++) 57862306a36Sopenharmony_ci dev_info(&chip->client->dev, "0x%x, 0x%x", 57962306a36Sopenharmony_ci data1[i], data2[i]); 58062306a36Sopenharmony_ci dev_info(&chip->client->dev, "\n"); 58162306a36Sopenharmony_ci return -EINVAL; 58262306a36Sopenharmony_ci } 58362306a36Sopenharmony_ci return 0; 58462306a36Sopenharmony_ci} 58562306a36Sopenharmony_ci 58662306a36Sopenharmony_cistatic int max17042_init_model(struct max17042_chip *chip) 58762306a36Sopenharmony_ci{ 58862306a36Sopenharmony_ci int ret; 58962306a36Sopenharmony_ci int table_size = ARRAY_SIZE(chip->pdata->config_data->cell_char_tbl); 59062306a36Sopenharmony_ci u16 *temp_data; 59162306a36Sopenharmony_ci 59262306a36Sopenharmony_ci temp_data = kcalloc(table_size, sizeof(*temp_data), GFP_KERNEL); 59362306a36Sopenharmony_ci if (!temp_data) 59462306a36Sopenharmony_ci return -ENOMEM; 59562306a36Sopenharmony_ci 59662306a36Sopenharmony_ci max17042_unlock_model(chip); 59762306a36Sopenharmony_ci max17042_write_model_data(chip, MAX17042_MODELChrTbl, 59862306a36Sopenharmony_ci table_size); 59962306a36Sopenharmony_ci max17042_read_model_data(chip, MAX17042_MODELChrTbl, temp_data, 60062306a36Sopenharmony_ci table_size); 60162306a36Sopenharmony_ci 60262306a36Sopenharmony_ci ret = max17042_model_data_compare( 60362306a36Sopenharmony_ci chip, 60462306a36Sopenharmony_ci chip->pdata->config_data->cell_char_tbl, 60562306a36Sopenharmony_ci temp_data, 60662306a36Sopenharmony_ci table_size); 60762306a36Sopenharmony_ci 60862306a36Sopenharmony_ci max17042_lock_model(chip); 60962306a36Sopenharmony_ci kfree(temp_data); 61062306a36Sopenharmony_ci 61162306a36Sopenharmony_ci return ret; 61262306a36Sopenharmony_ci} 61362306a36Sopenharmony_ci 61462306a36Sopenharmony_cistatic int max17042_verify_model_lock(struct max17042_chip *chip) 61562306a36Sopenharmony_ci{ 61662306a36Sopenharmony_ci int i; 61762306a36Sopenharmony_ci int table_size = ARRAY_SIZE(chip->pdata->config_data->cell_char_tbl); 61862306a36Sopenharmony_ci u16 *temp_data; 61962306a36Sopenharmony_ci int ret = 0; 62062306a36Sopenharmony_ci 62162306a36Sopenharmony_ci temp_data = kcalloc(table_size, sizeof(*temp_data), GFP_KERNEL); 62262306a36Sopenharmony_ci if (!temp_data) 62362306a36Sopenharmony_ci return -ENOMEM; 62462306a36Sopenharmony_ci 62562306a36Sopenharmony_ci max17042_read_model_data(chip, MAX17042_MODELChrTbl, temp_data, 62662306a36Sopenharmony_ci table_size); 62762306a36Sopenharmony_ci for (i = 0; i < table_size; i++) 62862306a36Sopenharmony_ci if (temp_data[i]) 62962306a36Sopenharmony_ci ret = -EINVAL; 63062306a36Sopenharmony_ci 63162306a36Sopenharmony_ci kfree(temp_data); 63262306a36Sopenharmony_ci return ret; 63362306a36Sopenharmony_ci} 63462306a36Sopenharmony_ci 63562306a36Sopenharmony_cistatic void max17042_write_config_regs(struct max17042_chip *chip) 63662306a36Sopenharmony_ci{ 63762306a36Sopenharmony_ci struct max17042_config_data *config = chip->pdata->config_data; 63862306a36Sopenharmony_ci struct regmap *map = chip->regmap; 63962306a36Sopenharmony_ci 64062306a36Sopenharmony_ci regmap_write(map, MAX17042_CONFIG, config->config); 64162306a36Sopenharmony_ci regmap_write(map, MAX17042_LearnCFG, config->learn_cfg); 64262306a36Sopenharmony_ci regmap_write(map, MAX17042_FilterCFG, 64362306a36Sopenharmony_ci config->filter_cfg); 64462306a36Sopenharmony_ci regmap_write(map, MAX17042_RelaxCFG, config->relax_cfg); 64562306a36Sopenharmony_ci if (chip->chip_type == MAXIM_DEVICE_TYPE_MAX17047 || 64662306a36Sopenharmony_ci chip->chip_type == MAXIM_DEVICE_TYPE_MAX17050 || 64762306a36Sopenharmony_ci chip->chip_type == MAXIM_DEVICE_TYPE_MAX17055) 64862306a36Sopenharmony_ci regmap_write(map, MAX17047_FullSOCThr, 64962306a36Sopenharmony_ci config->full_soc_thresh); 65062306a36Sopenharmony_ci} 65162306a36Sopenharmony_ci 65262306a36Sopenharmony_cistatic void max17042_write_custom_regs(struct max17042_chip *chip) 65362306a36Sopenharmony_ci{ 65462306a36Sopenharmony_ci struct max17042_config_data *config = chip->pdata->config_data; 65562306a36Sopenharmony_ci struct regmap *map = chip->regmap; 65662306a36Sopenharmony_ci 65762306a36Sopenharmony_ci max17042_write_verify_reg(map, MAX17042_RCOMP0, config->rcomp0); 65862306a36Sopenharmony_ci max17042_write_verify_reg(map, MAX17042_TempCo, config->tcompc0); 65962306a36Sopenharmony_ci max17042_write_verify_reg(map, MAX17042_ICHGTerm, config->ichgt_term); 66062306a36Sopenharmony_ci if (chip->chip_type == MAXIM_DEVICE_TYPE_MAX17042) { 66162306a36Sopenharmony_ci regmap_write(map, MAX17042_EmptyTempCo, config->empty_tempco); 66262306a36Sopenharmony_ci max17042_write_verify_reg(map, MAX17042_K_empty0, 66362306a36Sopenharmony_ci config->kempty0); 66462306a36Sopenharmony_ci } else { 66562306a36Sopenharmony_ci max17042_write_verify_reg(map, MAX17047_QRTbl00, 66662306a36Sopenharmony_ci config->qrtbl00); 66762306a36Sopenharmony_ci max17042_write_verify_reg(map, MAX17047_QRTbl10, 66862306a36Sopenharmony_ci config->qrtbl10); 66962306a36Sopenharmony_ci max17042_write_verify_reg(map, MAX17047_QRTbl20, 67062306a36Sopenharmony_ci config->qrtbl20); 67162306a36Sopenharmony_ci max17042_write_verify_reg(map, MAX17047_QRTbl30, 67262306a36Sopenharmony_ci config->qrtbl30); 67362306a36Sopenharmony_ci } 67462306a36Sopenharmony_ci} 67562306a36Sopenharmony_ci 67662306a36Sopenharmony_cistatic void max17042_update_capacity_regs(struct max17042_chip *chip) 67762306a36Sopenharmony_ci{ 67862306a36Sopenharmony_ci struct max17042_config_data *config = chip->pdata->config_data; 67962306a36Sopenharmony_ci struct regmap *map = chip->regmap; 68062306a36Sopenharmony_ci 68162306a36Sopenharmony_ci max17042_write_verify_reg(map, MAX17042_FullCAP, 68262306a36Sopenharmony_ci config->fullcap); 68362306a36Sopenharmony_ci regmap_write(map, MAX17042_DesignCap, config->design_cap); 68462306a36Sopenharmony_ci max17042_write_verify_reg(map, MAX17042_FullCAPNom, 68562306a36Sopenharmony_ci config->fullcapnom); 68662306a36Sopenharmony_ci} 68762306a36Sopenharmony_ci 68862306a36Sopenharmony_cistatic void max17042_reset_vfsoc0_reg(struct max17042_chip *chip) 68962306a36Sopenharmony_ci{ 69062306a36Sopenharmony_ci unsigned int vfSoc; 69162306a36Sopenharmony_ci struct regmap *map = chip->regmap; 69262306a36Sopenharmony_ci 69362306a36Sopenharmony_ci regmap_read(map, MAX17042_VFSOC, &vfSoc); 69462306a36Sopenharmony_ci regmap_write(map, MAX17042_VFSOC0Enable, VFSOC0_UNLOCK); 69562306a36Sopenharmony_ci max17042_write_verify_reg(map, MAX17042_VFSOC0, vfSoc); 69662306a36Sopenharmony_ci regmap_write(map, MAX17042_VFSOC0Enable, VFSOC0_LOCK); 69762306a36Sopenharmony_ci} 69862306a36Sopenharmony_ci 69962306a36Sopenharmony_cistatic void max17042_load_new_capacity_params(struct max17042_chip *chip) 70062306a36Sopenharmony_ci{ 70162306a36Sopenharmony_ci u32 full_cap0, rep_cap, dq_acc, vfSoc; 70262306a36Sopenharmony_ci u32 rem_cap; 70362306a36Sopenharmony_ci 70462306a36Sopenharmony_ci struct max17042_config_data *config = chip->pdata->config_data; 70562306a36Sopenharmony_ci struct regmap *map = chip->regmap; 70662306a36Sopenharmony_ci 70762306a36Sopenharmony_ci regmap_read(map, MAX17042_FullCAP0, &full_cap0); 70862306a36Sopenharmony_ci regmap_read(map, MAX17042_VFSOC, &vfSoc); 70962306a36Sopenharmony_ci 71062306a36Sopenharmony_ci /* fg_vfSoc needs to shifted by 8 bits to get the 71162306a36Sopenharmony_ci * perc in 1% accuracy, to get the right rem_cap multiply 71262306a36Sopenharmony_ci * full_cap0, fg_vfSoc and devide by 100 71362306a36Sopenharmony_ci */ 71462306a36Sopenharmony_ci rem_cap = ((vfSoc >> 8) * full_cap0) / 100; 71562306a36Sopenharmony_ci max17042_write_verify_reg(map, MAX17042_RemCap, rem_cap); 71662306a36Sopenharmony_ci 71762306a36Sopenharmony_ci rep_cap = rem_cap; 71862306a36Sopenharmony_ci max17042_write_verify_reg(map, MAX17042_RepCap, rep_cap); 71962306a36Sopenharmony_ci 72062306a36Sopenharmony_ci /* Write dQ_acc to 200% of Capacity and dP_acc to 200% */ 72162306a36Sopenharmony_ci dq_acc = config->fullcap / dQ_ACC_DIV; 72262306a36Sopenharmony_ci max17042_write_verify_reg(map, MAX17042_dQacc, dq_acc); 72362306a36Sopenharmony_ci max17042_write_verify_reg(map, MAX17042_dPacc, dP_ACC_200); 72462306a36Sopenharmony_ci 72562306a36Sopenharmony_ci max17042_write_verify_reg(map, MAX17042_FullCAP, 72662306a36Sopenharmony_ci config->fullcap); 72762306a36Sopenharmony_ci regmap_write(map, MAX17042_DesignCap, 72862306a36Sopenharmony_ci config->design_cap); 72962306a36Sopenharmony_ci max17042_write_verify_reg(map, MAX17042_FullCAPNom, 73062306a36Sopenharmony_ci config->fullcapnom); 73162306a36Sopenharmony_ci /* Update SOC register with new SOC */ 73262306a36Sopenharmony_ci regmap_write(map, MAX17042_RepSOC, vfSoc); 73362306a36Sopenharmony_ci} 73462306a36Sopenharmony_ci 73562306a36Sopenharmony_ci/* 73662306a36Sopenharmony_ci * Block write all the override values coming from platform data. 73762306a36Sopenharmony_ci * This function MUST be called before the POR initialization procedure 73862306a36Sopenharmony_ci * specified by maxim. 73962306a36Sopenharmony_ci */ 74062306a36Sopenharmony_cistatic inline void max17042_override_por_values(struct max17042_chip *chip) 74162306a36Sopenharmony_ci{ 74262306a36Sopenharmony_ci struct regmap *map = chip->regmap; 74362306a36Sopenharmony_ci struct max17042_config_data *config = chip->pdata->config_data; 74462306a36Sopenharmony_ci 74562306a36Sopenharmony_ci max17042_override_por(map, MAX17042_TGAIN, config->tgain); 74662306a36Sopenharmony_ci max17042_override_por(map, MAX17042_TOFF, config->toff); 74762306a36Sopenharmony_ci max17042_override_por(map, MAX17042_CGAIN, config->cgain); 74862306a36Sopenharmony_ci max17042_override_por(map, MAX17042_COFF, config->coff); 74962306a36Sopenharmony_ci 75062306a36Sopenharmony_ci max17042_override_por(map, MAX17042_VALRT_Th, config->valrt_thresh); 75162306a36Sopenharmony_ci max17042_override_por(map, MAX17042_TALRT_Th, config->talrt_thresh); 75262306a36Sopenharmony_ci max17042_override_por(map, MAX17042_SALRT_Th, 75362306a36Sopenharmony_ci config->soc_alrt_thresh); 75462306a36Sopenharmony_ci max17042_override_por(map, MAX17042_CONFIG, config->config); 75562306a36Sopenharmony_ci max17042_override_por(map, MAX17042_SHDNTIMER, config->shdntimer); 75662306a36Sopenharmony_ci 75762306a36Sopenharmony_ci max17042_override_por(map, MAX17042_DesignCap, config->design_cap); 75862306a36Sopenharmony_ci max17042_override_por(map, MAX17042_ICHGTerm, config->ichgt_term); 75962306a36Sopenharmony_ci 76062306a36Sopenharmony_ci max17042_override_por(map, MAX17042_AtRate, config->at_rate); 76162306a36Sopenharmony_ci max17042_override_por(map, MAX17042_LearnCFG, config->learn_cfg); 76262306a36Sopenharmony_ci max17042_override_por(map, MAX17042_FilterCFG, config->filter_cfg); 76362306a36Sopenharmony_ci max17042_override_por(map, MAX17042_RelaxCFG, config->relax_cfg); 76462306a36Sopenharmony_ci max17042_override_por(map, MAX17042_MiscCFG, config->misc_cfg); 76562306a36Sopenharmony_ci 76662306a36Sopenharmony_ci max17042_override_por(map, MAX17042_FullCAP, config->fullcap); 76762306a36Sopenharmony_ci max17042_override_por(map, MAX17042_FullCAPNom, config->fullcapnom); 76862306a36Sopenharmony_ci max17042_override_por(map, MAX17042_dQacc, config->dqacc); 76962306a36Sopenharmony_ci max17042_override_por(map, MAX17042_dPacc, config->dpacc); 77062306a36Sopenharmony_ci 77162306a36Sopenharmony_ci max17042_override_por(map, MAX17042_RCOMP0, config->rcomp0); 77262306a36Sopenharmony_ci max17042_override_por(map, MAX17042_TempCo, config->tcompc0); 77362306a36Sopenharmony_ci 77462306a36Sopenharmony_ci if (chip->chip_type == MAXIM_DEVICE_TYPE_MAX17042) { 77562306a36Sopenharmony_ci max17042_override_por(map, MAX17042_MaskSOC, config->masksoc); 77662306a36Sopenharmony_ci max17042_override_por(map, MAX17042_SOC_empty, config->socempty); 77762306a36Sopenharmony_ci max17042_override_por(map, MAX17042_V_empty, config->vempty); 77862306a36Sopenharmony_ci max17042_override_por(map, MAX17042_EmptyTempCo, config->empty_tempco); 77962306a36Sopenharmony_ci max17042_override_por(map, MAX17042_K_empty0, config->kempty0); 78062306a36Sopenharmony_ci } 78162306a36Sopenharmony_ci 78262306a36Sopenharmony_ci if ((chip->chip_type == MAXIM_DEVICE_TYPE_MAX17042) || 78362306a36Sopenharmony_ci (chip->chip_type == MAXIM_DEVICE_TYPE_MAX17047) || 78462306a36Sopenharmony_ci (chip->chip_type == MAXIM_DEVICE_TYPE_MAX17050)) { 78562306a36Sopenharmony_ci max17042_override_por(map, MAX17042_IAvg_empty, config->iavg_empty); 78662306a36Sopenharmony_ci max17042_override_por(map, MAX17042_TempNom, config->temp_nom); 78762306a36Sopenharmony_ci max17042_override_por(map, MAX17042_TempLim, config->temp_lim); 78862306a36Sopenharmony_ci max17042_override_por(map, MAX17042_FCTC, config->fctc); 78962306a36Sopenharmony_ci } 79062306a36Sopenharmony_ci 79162306a36Sopenharmony_ci if ((chip->chip_type == MAXIM_DEVICE_TYPE_MAX17047) || 79262306a36Sopenharmony_ci (chip->chip_type == MAXIM_DEVICE_TYPE_MAX17050) || 79362306a36Sopenharmony_ci (chip->chip_type == MAXIM_DEVICE_TYPE_MAX17055)) { 79462306a36Sopenharmony_ci max17042_override_por(map, MAX17047_V_empty, config->vempty); 79562306a36Sopenharmony_ci } 79662306a36Sopenharmony_ci} 79762306a36Sopenharmony_ci 79862306a36Sopenharmony_cistatic int max17042_init_chip(struct max17042_chip *chip) 79962306a36Sopenharmony_ci{ 80062306a36Sopenharmony_ci struct regmap *map = chip->regmap; 80162306a36Sopenharmony_ci int ret; 80262306a36Sopenharmony_ci 80362306a36Sopenharmony_ci max17042_override_por_values(chip); 80462306a36Sopenharmony_ci /* After Power up, the MAX17042 requires 500mS in order 80562306a36Sopenharmony_ci * to perform signal debouncing and initial SOC reporting 80662306a36Sopenharmony_ci */ 80762306a36Sopenharmony_ci msleep(500); 80862306a36Sopenharmony_ci 80962306a36Sopenharmony_ci /* Initialize configuration */ 81062306a36Sopenharmony_ci max17042_write_config_regs(chip); 81162306a36Sopenharmony_ci 81262306a36Sopenharmony_ci /* write cell characterization data */ 81362306a36Sopenharmony_ci ret = max17042_init_model(chip); 81462306a36Sopenharmony_ci if (ret) { 81562306a36Sopenharmony_ci dev_err(&chip->client->dev, "%s init failed\n", 81662306a36Sopenharmony_ci __func__); 81762306a36Sopenharmony_ci return -EIO; 81862306a36Sopenharmony_ci } 81962306a36Sopenharmony_ci 82062306a36Sopenharmony_ci ret = max17042_verify_model_lock(chip); 82162306a36Sopenharmony_ci if (ret) { 82262306a36Sopenharmony_ci dev_err(&chip->client->dev, "%s lock verify failed\n", 82362306a36Sopenharmony_ci __func__); 82462306a36Sopenharmony_ci return -EIO; 82562306a36Sopenharmony_ci } 82662306a36Sopenharmony_ci /* write custom parameters */ 82762306a36Sopenharmony_ci max17042_write_custom_regs(chip); 82862306a36Sopenharmony_ci 82962306a36Sopenharmony_ci /* update capacity params */ 83062306a36Sopenharmony_ci max17042_update_capacity_regs(chip); 83162306a36Sopenharmony_ci 83262306a36Sopenharmony_ci /* delay must be atleast 350mS to allow VFSOC 83362306a36Sopenharmony_ci * to be calculated from the new configuration 83462306a36Sopenharmony_ci */ 83562306a36Sopenharmony_ci msleep(350); 83662306a36Sopenharmony_ci 83762306a36Sopenharmony_ci /* reset vfsoc0 reg */ 83862306a36Sopenharmony_ci max17042_reset_vfsoc0_reg(chip); 83962306a36Sopenharmony_ci 84062306a36Sopenharmony_ci /* load new capacity params */ 84162306a36Sopenharmony_ci max17042_load_new_capacity_params(chip); 84262306a36Sopenharmony_ci 84362306a36Sopenharmony_ci /* Init complete, Clear the POR bit */ 84462306a36Sopenharmony_ci regmap_update_bits(map, MAX17042_STATUS, STATUS_POR_BIT, 0x0); 84562306a36Sopenharmony_ci return 0; 84662306a36Sopenharmony_ci} 84762306a36Sopenharmony_ci 84862306a36Sopenharmony_cistatic void max17042_set_soc_threshold(struct max17042_chip *chip, u16 off) 84962306a36Sopenharmony_ci{ 85062306a36Sopenharmony_ci struct regmap *map = chip->regmap; 85162306a36Sopenharmony_ci u32 soc, soc_tr; 85262306a36Sopenharmony_ci 85362306a36Sopenharmony_ci /* program interrupt thresholds such that we should 85462306a36Sopenharmony_ci * get interrupt for every 'off' perc change in the soc 85562306a36Sopenharmony_ci */ 85662306a36Sopenharmony_ci regmap_read(map, MAX17042_RepSOC, &soc); 85762306a36Sopenharmony_ci soc >>= 8; 85862306a36Sopenharmony_ci soc_tr = (soc + off) << 8; 85962306a36Sopenharmony_ci if (off < soc) 86062306a36Sopenharmony_ci soc_tr |= soc - off; 86162306a36Sopenharmony_ci regmap_write(map, MAX17042_SALRT_Th, soc_tr); 86262306a36Sopenharmony_ci} 86362306a36Sopenharmony_ci 86462306a36Sopenharmony_cistatic irqreturn_t max17042_thread_handler(int id, void *dev) 86562306a36Sopenharmony_ci{ 86662306a36Sopenharmony_ci struct max17042_chip *chip = dev; 86762306a36Sopenharmony_ci u32 val; 86862306a36Sopenharmony_ci int ret; 86962306a36Sopenharmony_ci 87062306a36Sopenharmony_ci ret = regmap_read(chip->regmap, MAX17042_STATUS, &val); 87162306a36Sopenharmony_ci if (ret) 87262306a36Sopenharmony_ci return IRQ_HANDLED; 87362306a36Sopenharmony_ci 87462306a36Sopenharmony_ci if ((val & STATUS_SMN_BIT) || (val & STATUS_SMX_BIT)) { 87562306a36Sopenharmony_ci dev_dbg(&chip->client->dev, "SOC threshold INTR\n"); 87662306a36Sopenharmony_ci max17042_set_soc_threshold(chip, 1); 87762306a36Sopenharmony_ci } 87862306a36Sopenharmony_ci 87962306a36Sopenharmony_ci /* we implicitly handle all alerts via power_supply_changed */ 88062306a36Sopenharmony_ci regmap_clear_bits(chip->regmap, MAX17042_STATUS, 88162306a36Sopenharmony_ci 0xFFFF & ~(STATUS_POR_BIT | STATUS_BST_BIT)); 88262306a36Sopenharmony_ci 88362306a36Sopenharmony_ci power_supply_changed(chip->battery); 88462306a36Sopenharmony_ci return IRQ_HANDLED; 88562306a36Sopenharmony_ci} 88662306a36Sopenharmony_ci 88762306a36Sopenharmony_cistatic void max17042_init_worker(struct work_struct *work) 88862306a36Sopenharmony_ci{ 88962306a36Sopenharmony_ci struct max17042_chip *chip = container_of(work, 89062306a36Sopenharmony_ci struct max17042_chip, work); 89162306a36Sopenharmony_ci int ret; 89262306a36Sopenharmony_ci 89362306a36Sopenharmony_ci /* Initialize registers according to values from the platform data */ 89462306a36Sopenharmony_ci if (chip->pdata->enable_por_init && chip->pdata->config_data) { 89562306a36Sopenharmony_ci ret = max17042_init_chip(chip); 89662306a36Sopenharmony_ci if (ret) 89762306a36Sopenharmony_ci return; 89862306a36Sopenharmony_ci } 89962306a36Sopenharmony_ci 90062306a36Sopenharmony_ci chip->init_complete = 1; 90162306a36Sopenharmony_ci} 90262306a36Sopenharmony_ci 90362306a36Sopenharmony_ci#ifdef CONFIG_OF 90462306a36Sopenharmony_cistatic struct max17042_platform_data * 90562306a36Sopenharmony_cimax17042_get_of_pdata(struct max17042_chip *chip) 90662306a36Sopenharmony_ci{ 90762306a36Sopenharmony_ci struct device *dev = &chip->client->dev; 90862306a36Sopenharmony_ci struct device_node *np = dev->of_node; 90962306a36Sopenharmony_ci u32 prop; 91062306a36Sopenharmony_ci struct max17042_platform_data *pdata; 91162306a36Sopenharmony_ci 91262306a36Sopenharmony_ci pdata = devm_kzalloc(dev, sizeof(*pdata), GFP_KERNEL); 91362306a36Sopenharmony_ci if (!pdata) 91462306a36Sopenharmony_ci return NULL; 91562306a36Sopenharmony_ci 91662306a36Sopenharmony_ci /* 91762306a36Sopenharmony_ci * Require current sense resistor value to be specified for 91862306a36Sopenharmony_ci * current-sense functionality to be enabled at all. 91962306a36Sopenharmony_ci */ 92062306a36Sopenharmony_ci if (of_property_read_u32(np, "maxim,rsns-microohm", &prop) == 0) { 92162306a36Sopenharmony_ci pdata->r_sns = prop; 92262306a36Sopenharmony_ci pdata->enable_current_sense = true; 92362306a36Sopenharmony_ci } 92462306a36Sopenharmony_ci 92562306a36Sopenharmony_ci if (of_property_read_s32(np, "maxim,cold-temp", &pdata->temp_min)) 92662306a36Sopenharmony_ci pdata->temp_min = INT_MIN; 92762306a36Sopenharmony_ci if (of_property_read_s32(np, "maxim,over-heat-temp", &pdata->temp_max)) 92862306a36Sopenharmony_ci pdata->temp_max = INT_MAX; 92962306a36Sopenharmony_ci if (of_property_read_s32(np, "maxim,dead-volt", &pdata->vmin)) 93062306a36Sopenharmony_ci pdata->vmin = INT_MIN; 93162306a36Sopenharmony_ci if (of_property_read_s32(np, "maxim,over-volt", &pdata->vmax)) 93262306a36Sopenharmony_ci pdata->vmax = INT_MAX; 93362306a36Sopenharmony_ci 93462306a36Sopenharmony_ci return pdata; 93562306a36Sopenharmony_ci} 93662306a36Sopenharmony_ci#endif 93762306a36Sopenharmony_ci 93862306a36Sopenharmony_cistatic struct max17042_reg_data max17047_default_pdata_init_regs[] = { 93962306a36Sopenharmony_ci /* 94062306a36Sopenharmony_ci * Some firmwares do not set FullSOCThr, Enable End-of-Charge Detection 94162306a36Sopenharmony_ci * when the voltage FG reports 95%, as recommended in the datasheet. 94262306a36Sopenharmony_ci */ 94362306a36Sopenharmony_ci { MAX17047_FullSOCThr, MAX17042_BATTERY_FULL << 8 }, 94462306a36Sopenharmony_ci}; 94562306a36Sopenharmony_ci 94662306a36Sopenharmony_cistatic struct max17042_platform_data * 94762306a36Sopenharmony_cimax17042_get_default_pdata(struct max17042_chip *chip) 94862306a36Sopenharmony_ci{ 94962306a36Sopenharmony_ci struct device *dev = &chip->client->dev; 95062306a36Sopenharmony_ci struct max17042_platform_data *pdata; 95162306a36Sopenharmony_ci int ret, misc_cfg; 95262306a36Sopenharmony_ci 95362306a36Sopenharmony_ci /* 95462306a36Sopenharmony_ci * The MAX17047 gets used on x86 where we might not have pdata, assume 95562306a36Sopenharmony_ci * the firmware will already have initialized the fuel-gauge and provide 95662306a36Sopenharmony_ci * default values for the non init bits to make things work. 95762306a36Sopenharmony_ci */ 95862306a36Sopenharmony_ci pdata = devm_kzalloc(dev, sizeof(*pdata), GFP_KERNEL); 95962306a36Sopenharmony_ci if (!pdata) 96062306a36Sopenharmony_ci return pdata; 96162306a36Sopenharmony_ci 96262306a36Sopenharmony_ci if ((chip->chip_type == MAXIM_DEVICE_TYPE_MAX17047) || 96362306a36Sopenharmony_ci (chip->chip_type == MAXIM_DEVICE_TYPE_MAX17050)) { 96462306a36Sopenharmony_ci pdata->init_data = max17047_default_pdata_init_regs; 96562306a36Sopenharmony_ci pdata->num_init_data = 96662306a36Sopenharmony_ci ARRAY_SIZE(max17047_default_pdata_init_regs); 96762306a36Sopenharmony_ci } 96862306a36Sopenharmony_ci 96962306a36Sopenharmony_ci ret = regmap_read(chip->regmap, MAX17042_MiscCFG, &misc_cfg); 97062306a36Sopenharmony_ci if (ret < 0) 97162306a36Sopenharmony_ci return NULL; 97262306a36Sopenharmony_ci 97362306a36Sopenharmony_ci /* If bits 0-1 are set to 3 then only Voltage readings are used */ 97462306a36Sopenharmony_ci if ((misc_cfg & 0x3) == 0x3) 97562306a36Sopenharmony_ci pdata->enable_current_sense = false; 97662306a36Sopenharmony_ci else 97762306a36Sopenharmony_ci pdata->enable_current_sense = true; 97862306a36Sopenharmony_ci 97962306a36Sopenharmony_ci pdata->vmin = MAX17042_DEFAULT_VMIN; 98062306a36Sopenharmony_ci pdata->vmax = MAX17042_DEFAULT_VMAX; 98162306a36Sopenharmony_ci pdata->temp_min = MAX17042_DEFAULT_TEMP_MIN; 98262306a36Sopenharmony_ci pdata->temp_max = MAX17042_DEFAULT_TEMP_MAX; 98362306a36Sopenharmony_ci 98462306a36Sopenharmony_ci return pdata; 98562306a36Sopenharmony_ci} 98662306a36Sopenharmony_ci 98762306a36Sopenharmony_cistatic struct max17042_platform_data * 98862306a36Sopenharmony_cimax17042_get_pdata(struct max17042_chip *chip) 98962306a36Sopenharmony_ci{ 99062306a36Sopenharmony_ci struct device *dev = &chip->client->dev; 99162306a36Sopenharmony_ci 99262306a36Sopenharmony_ci#ifdef CONFIG_OF 99362306a36Sopenharmony_ci if (dev->of_node) 99462306a36Sopenharmony_ci return max17042_get_of_pdata(chip); 99562306a36Sopenharmony_ci#endif 99662306a36Sopenharmony_ci if (dev->platform_data) 99762306a36Sopenharmony_ci return dev->platform_data; 99862306a36Sopenharmony_ci 99962306a36Sopenharmony_ci return max17042_get_default_pdata(chip); 100062306a36Sopenharmony_ci} 100162306a36Sopenharmony_ci 100262306a36Sopenharmony_cistatic const struct regmap_config max17042_regmap_config = { 100362306a36Sopenharmony_ci .reg_bits = 8, 100462306a36Sopenharmony_ci .val_bits = 16, 100562306a36Sopenharmony_ci .val_format_endian = REGMAP_ENDIAN_NATIVE, 100662306a36Sopenharmony_ci}; 100762306a36Sopenharmony_ci 100862306a36Sopenharmony_cistatic const struct power_supply_desc max17042_psy_desc = { 100962306a36Sopenharmony_ci .name = "max170xx_battery", 101062306a36Sopenharmony_ci .type = POWER_SUPPLY_TYPE_BATTERY, 101162306a36Sopenharmony_ci .get_property = max17042_get_property, 101262306a36Sopenharmony_ci .set_property = max17042_set_property, 101362306a36Sopenharmony_ci .property_is_writeable = max17042_property_is_writeable, 101462306a36Sopenharmony_ci .external_power_changed = power_supply_changed, 101562306a36Sopenharmony_ci .properties = max17042_battery_props, 101662306a36Sopenharmony_ci .num_properties = ARRAY_SIZE(max17042_battery_props), 101762306a36Sopenharmony_ci}; 101862306a36Sopenharmony_ci 101962306a36Sopenharmony_cistatic const struct power_supply_desc max17042_no_current_sense_psy_desc = { 102062306a36Sopenharmony_ci .name = "max170xx_battery", 102162306a36Sopenharmony_ci .type = POWER_SUPPLY_TYPE_BATTERY, 102262306a36Sopenharmony_ci .get_property = max17042_get_property, 102362306a36Sopenharmony_ci .set_property = max17042_set_property, 102462306a36Sopenharmony_ci .property_is_writeable = max17042_property_is_writeable, 102562306a36Sopenharmony_ci .properties = max17042_battery_props, 102662306a36Sopenharmony_ci .num_properties = ARRAY_SIZE(max17042_battery_props) - 2, 102762306a36Sopenharmony_ci}; 102862306a36Sopenharmony_ci 102962306a36Sopenharmony_cistatic int max17042_probe(struct i2c_client *client) 103062306a36Sopenharmony_ci{ 103162306a36Sopenharmony_ci const struct i2c_device_id *id = i2c_client_get_device_id(client); 103262306a36Sopenharmony_ci struct i2c_adapter *adapter = client->adapter; 103362306a36Sopenharmony_ci const struct power_supply_desc *max17042_desc = &max17042_psy_desc; 103462306a36Sopenharmony_ci struct power_supply_config psy_cfg = {}; 103562306a36Sopenharmony_ci const struct acpi_device_id *acpi_id = NULL; 103662306a36Sopenharmony_ci struct device *dev = &client->dev; 103762306a36Sopenharmony_ci struct max17042_chip *chip; 103862306a36Sopenharmony_ci int ret; 103962306a36Sopenharmony_ci int i; 104062306a36Sopenharmony_ci u32 val; 104162306a36Sopenharmony_ci 104262306a36Sopenharmony_ci if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_WORD_DATA)) 104362306a36Sopenharmony_ci return -EIO; 104462306a36Sopenharmony_ci 104562306a36Sopenharmony_ci chip = devm_kzalloc(&client->dev, sizeof(*chip), GFP_KERNEL); 104662306a36Sopenharmony_ci if (!chip) 104762306a36Sopenharmony_ci return -ENOMEM; 104862306a36Sopenharmony_ci 104962306a36Sopenharmony_ci chip->client = client; 105062306a36Sopenharmony_ci if (id) { 105162306a36Sopenharmony_ci chip->chip_type = id->driver_data; 105262306a36Sopenharmony_ci } else { 105362306a36Sopenharmony_ci acpi_id = acpi_match_device(dev->driver->acpi_match_table, dev); 105462306a36Sopenharmony_ci if (!acpi_id) 105562306a36Sopenharmony_ci return -ENODEV; 105662306a36Sopenharmony_ci 105762306a36Sopenharmony_ci chip->chip_type = acpi_id->driver_data; 105862306a36Sopenharmony_ci } 105962306a36Sopenharmony_ci chip->regmap = devm_regmap_init_i2c(client, &max17042_regmap_config); 106062306a36Sopenharmony_ci if (IS_ERR(chip->regmap)) { 106162306a36Sopenharmony_ci dev_err(&client->dev, "Failed to initialize regmap\n"); 106262306a36Sopenharmony_ci return -EINVAL; 106362306a36Sopenharmony_ci } 106462306a36Sopenharmony_ci 106562306a36Sopenharmony_ci chip->pdata = max17042_get_pdata(chip); 106662306a36Sopenharmony_ci if (!chip->pdata) { 106762306a36Sopenharmony_ci dev_err(&client->dev, "no platform data provided\n"); 106862306a36Sopenharmony_ci return -EINVAL; 106962306a36Sopenharmony_ci } 107062306a36Sopenharmony_ci 107162306a36Sopenharmony_ci i2c_set_clientdata(client, chip); 107262306a36Sopenharmony_ci psy_cfg.drv_data = chip; 107362306a36Sopenharmony_ci psy_cfg.of_node = dev->of_node; 107462306a36Sopenharmony_ci 107562306a36Sopenharmony_ci /* When current is not measured, 107662306a36Sopenharmony_ci * CURRENT_NOW and CURRENT_AVG properties should be invisible. */ 107762306a36Sopenharmony_ci if (!chip->pdata->enable_current_sense) 107862306a36Sopenharmony_ci max17042_desc = &max17042_no_current_sense_psy_desc; 107962306a36Sopenharmony_ci 108062306a36Sopenharmony_ci if (chip->pdata->r_sns == 0) 108162306a36Sopenharmony_ci chip->pdata->r_sns = MAX17042_DEFAULT_SNS_RESISTOR; 108262306a36Sopenharmony_ci 108362306a36Sopenharmony_ci if (chip->pdata->init_data) 108462306a36Sopenharmony_ci for (i = 0; i < chip->pdata->num_init_data; i++) 108562306a36Sopenharmony_ci regmap_write(chip->regmap, 108662306a36Sopenharmony_ci chip->pdata->init_data[i].addr, 108762306a36Sopenharmony_ci chip->pdata->init_data[i].data); 108862306a36Sopenharmony_ci 108962306a36Sopenharmony_ci if (!chip->pdata->enable_current_sense) { 109062306a36Sopenharmony_ci regmap_write(chip->regmap, MAX17042_CGAIN, 0x0000); 109162306a36Sopenharmony_ci regmap_write(chip->regmap, MAX17042_MiscCFG, 0x0003); 109262306a36Sopenharmony_ci regmap_write(chip->regmap, MAX17042_LearnCFG, 0x0007); 109362306a36Sopenharmony_ci } 109462306a36Sopenharmony_ci 109562306a36Sopenharmony_ci chip->battery = devm_power_supply_register(&client->dev, max17042_desc, 109662306a36Sopenharmony_ci &psy_cfg); 109762306a36Sopenharmony_ci if (IS_ERR(chip->battery)) { 109862306a36Sopenharmony_ci dev_err(&client->dev, "failed: power supply register\n"); 109962306a36Sopenharmony_ci return PTR_ERR(chip->battery); 110062306a36Sopenharmony_ci } 110162306a36Sopenharmony_ci 110262306a36Sopenharmony_ci if (client->irq) { 110362306a36Sopenharmony_ci unsigned int flags = IRQF_ONESHOT; 110462306a36Sopenharmony_ci 110562306a36Sopenharmony_ci /* 110662306a36Sopenharmony_ci * On ACPI systems the IRQ may be handled by ACPI-event code, 110762306a36Sopenharmony_ci * so we need to share (if the ACPI code is willing to share). 110862306a36Sopenharmony_ci */ 110962306a36Sopenharmony_ci if (acpi_id) 111062306a36Sopenharmony_ci flags |= IRQF_SHARED | IRQF_PROBE_SHARED; 111162306a36Sopenharmony_ci 111262306a36Sopenharmony_ci ret = devm_request_threaded_irq(&client->dev, client->irq, 111362306a36Sopenharmony_ci NULL, 111462306a36Sopenharmony_ci max17042_thread_handler, flags, 111562306a36Sopenharmony_ci chip->battery->desc->name, 111662306a36Sopenharmony_ci chip); 111762306a36Sopenharmony_ci if (!ret) { 111862306a36Sopenharmony_ci regmap_update_bits(chip->regmap, MAX17042_CONFIG, 111962306a36Sopenharmony_ci CONFIG_ALRT_BIT_ENBL, 112062306a36Sopenharmony_ci CONFIG_ALRT_BIT_ENBL); 112162306a36Sopenharmony_ci max17042_set_soc_threshold(chip, 1); 112262306a36Sopenharmony_ci } else { 112362306a36Sopenharmony_ci client->irq = 0; 112462306a36Sopenharmony_ci if (ret != -EBUSY) 112562306a36Sopenharmony_ci dev_err(&client->dev, "Failed to get IRQ\n"); 112662306a36Sopenharmony_ci } 112762306a36Sopenharmony_ci } 112862306a36Sopenharmony_ci /* Not able to update the charge threshold when exceeded? -> disable */ 112962306a36Sopenharmony_ci if (!client->irq) 113062306a36Sopenharmony_ci regmap_write(chip->regmap, MAX17042_SALRT_Th, 0xff00); 113162306a36Sopenharmony_ci 113262306a36Sopenharmony_ci regmap_read(chip->regmap, MAX17042_STATUS, &val); 113362306a36Sopenharmony_ci if (val & STATUS_POR_BIT) { 113462306a36Sopenharmony_ci ret = devm_work_autocancel(&client->dev, &chip->work, 113562306a36Sopenharmony_ci max17042_init_worker); 113662306a36Sopenharmony_ci if (ret) 113762306a36Sopenharmony_ci return ret; 113862306a36Sopenharmony_ci schedule_work(&chip->work); 113962306a36Sopenharmony_ci } else { 114062306a36Sopenharmony_ci chip->init_complete = 1; 114162306a36Sopenharmony_ci } 114262306a36Sopenharmony_ci 114362306a36Sopenharmony_ci return 0; 114462306a36Sopenharmony_ci} 114562306a36Sopenharmony_ci 114662306a36Sopenharmony_ci#ifdef CONFIG_PM_SLEEP 114762306a36Sopenharmony_cistatic int max17042_suspend(struct device *dev) 114862306a36Sopenharmony_ci{ 114962306a36Sopenharmony_ci struct max17042_chip *chip = dev_get_drvdata(dev); 115062306a36Sopenharmony_ci 115162306a36Sopenharmony_ci /* 115262306a36Sopenharmony_ci * disable the irq and enable irq_wake 115362306a36Sopenharmony_ci * capability to the interrupt line. 115462306a36Sopenharmony_ci */ 115562306a36Sopenharmony_ci if (chip->client->irq) { 115662306a36Sopenharmony_ci disable_irq(chip->client->irq); 115762306a36Sopenharmony_ci enable_irq_wake(chip->client->irq); 115862306a36Sopenharmony_ci } 115962306a36Sopenharmony_ci 116062306a36Sopenharmony_ci return 0; 116162306a36Sopenharmony_ci} 116262306a36Sopenharmony_ci 116362306a36Sopenharmony_cistatic int max17042_resume(struct device *dev) 116462306a36Sopenharmony_ci{ 116562306a36Sopenharmony_ci struct max17042_chip *chip = dev_get_drvdata(dev); 116662306a36Sopenharmony_ci 116762306a36Sopenharmony_ci if (chip->client->irq) { 116862306a36Sopenharmony_ci disable_irq_wake(chip->client->irq); 116962306a36Sopenharmony_ci enable_irq(chip->client->irq); 117062306a36Sopenharmony_ci /* re-program the SOC thresholds to 1% change */ 117162306a36Sopenharmony_ci max17042_set_soc_threshold(chip, 1); 117262306a36Sopenharmony_ci } 117362306a36Sopenharmony_ci 117462306a36Sopenharmony_ci return 0; 117562306a36Sopenharmony_ci} 117662306a36Sopenharmony_ci#endif 117762306a36Sopenharmony_ci 117862306a36Sopenharmony_cistatic SIMPLE_DEV_PM_OPS(max17042_pm_ops, max17042_suspend, 117962306a36Sopenharmony_ci max17042_resume); 118062306a36Sopenharmony_ci 118162306a36Sopenharmony_ci#ifdef CONFIG_ACPI 118262306a36Sopenharmony_cistatic const struct acpi_device_id max17042_acpi_match[] = { 118362306a36Sopenharmony_ci { "MAX17047", MAXIM_DEVICE_TYPE_MAX17047 }, 118462306a36Sopenharmony_ci { } 118562306a36Sopenharmony_ci}; 118662306a36Sopenharmony_ciMODULE_DEVICE_TABLE(acpi, max17042_acpi_match); 118762306a36Sopenharmony_ci#endif 118862306a36Sopenharmony_ci 118962306a36Sopenharmony_ci#ifdef CONFIG_OF 119062306a36Sopenharmony_cistatic const struct of_device_id max17042_dt_match[] = { 119162306a36Sopenharmony_ci { .compatible = "maxim,max17042" }, 119262306a36Sopenharmony_ci { .compatible = "maxim,max17047" }, 119362306a36Sopenharmony_ci { .compatible = "maxim,max17050" }, 119462306a36Sopenharmony_ci { .compatible = "maxim,max17055" }, 119562306a36Sopenharmony_ci { .compatible = "maxim,max77849-battery" }, 119662306a36Sopenharmony_ci { }, 119762306a36Sopenharmony_ci}; 119862306a36Sopenharmony_ciMODULE_DEVICE_TABLE(of, max17042_dt_match); 119962306a36Sopenharmony_ci#endif 120062306a36Sopenharmony_ci 120162306a36Sopenharmony_cistatic const struct i2c_device_id max17042_id[] = { 120262306a36Sopenharmony_ci { "max17042", MAXIM_DEVICE_TYPE_MAX17042 }, 120362306a36Sopenharmony_ci { "max17047", MAXIM_DEVICE_TYPE_MAX17047 }, 120462306a36Sopenharmony_ci { "max17050", MAXIM_DEVICE_TYPE_MAX17050 }, 120562306a36Sopenharmony_ci { "max17055", MAXIM_DEVICE_TYPE_MAX17055 }, 120662306a36Sopenharmony_ci { "max77849-battery", MAXIM_DEVICE_TYPE_MAX17047 }, 120762306a36Sopenharmony_ci { } 120862306a36Sopenharmony_ci}; 120962306a36Sopenharmony_ciMODULE_DEVICE_TABLE(i2c, max17042_id); 121062306a36Sopenharmony_ci 121162306a36Sopenharmony_cistatic struct i2c_driver max17042_i2c_driver = { 121262306a36Sopenharmony_ci .driver = { 121362306a36Sopenharmony_ci .name = "max17042", 121462306a36Sopenharmony_ci .acpi_match_table = ACPI_PTR(max17042_acpi_match), 121562306a36Sopenharmony_ci .of_match_table = of_match_ptr(max17042_dt_match), 121662306a36Sopenharmony_ci .pm = &max17042_pm_ops, 121762306a36Sopenharmony_ci }, 121862306a36Sopenharmony_ci .probe = max17042_probe, 121962306a36Sopenharmony_ci .id_table = max17042_id, 122062306a36Sopenharmony_ci}; 122162306a36Sopenharmony_cimodule_i2c_driver(max17042_i2c_driver); 122262306a36Sopenharmony_ci 122362306a36Sopenharmony_ciMODULE_AUTHOR("MyungJoo Ham <myungjoo.ham@samsung.com>"); 122462306a36Sopenharmony_ciMODULE_DESCRIPTION("MAX17042 Fuel Gauge"); 122562306a36Sopenharmony_ciMODULE_LICENSE("GPL"); 1226