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