18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0+
28c2ecf20Sopenharmony_ci//
38c2ecf20Sopenharmony_ci// Fuel gauge driver for Maxim 17042 / 8966 / 8997
48c2ecf20Sopenharmony_ci//  Note that Maxim 8966 and 8997 are mfd and this is its subdevice.
58c2ecf20Sopenharmony_ci//
68c2ecf20Sopenharmony_ci// Copyright (C) 2011 Samsung Electronics
78c2ecf20Sopenharmony_ci// MyungJoo Ham <myungjoo.ham@samsung.com>
88c2ecf20Sopenharmony_ci//
98c2ecf20Sopenharmony_ci// This driver is based on max17040_battery.c
108c2ecf20Sopenharmony_ci
118c2ecf20Sopenharmony_ci#include <linux/acpi.h>
128c2ecf20Sopenharmony_ci#include <linux/init.h>
138c2ecf20Sopenharmony_ci#include <linux/module.h>
148c2ecf20Sopenharmony_ci#include <linux/slab.h>
158c2ecf20Sopenharmony_ci#include <linux/i2c.h>
168c2ecf20Sopenharmony_ci#include <linux/delay.h>
178c2ecf20Sopenharmony_ci#include <linux/interrupt.h>
188c2ecf20Sopenharmony_ci#include <linux/pm.h>
198c2ecf20Sopenharmony_ci#include <linux/mod_devicetable.h>
208c2ecf20Sopenharmony_ci#include <linux/power_supply.h>
218c2ecf20Sopenharmony_ci#include <linux/power/max17042_battery.h>
228c2ecf20Sopenharmony_ci#include <linux/of.h>
238c2ecf20Sopenharmony_ci#include <linux/regmap.h>
248c2ecf20Sopenharmony_ci
258c2ecf20Sopenharmony_ci/* Status register bits */
268c2ecf20Sopenharmony_ci#define STATUS_POR_BIT         (1 << 1)
278c2ecf20Sopenharmony_ci#define STATUS_BST_BIT         (1 << 3)
288c2ecf20Sopenharmony_ci#define STATUS_VMN_BIT         (1 << 8)
298c2ecf20Sopenharmony_ci#define STATUS_TMN_BIT         (1 << 9)
308c2ecf20Sopenharmony_ci#define STATUS_SMN_BIT         (1 << 10)
318c2ecf20Sopenharmony_ci#define STATUS_BI_BIT          (1 << 11)
328c2ecf20Sopenharmony_ci#define STATUS_VMX_BIT         (1 << 12)
338c2ecf20Sopenharmony_ci#define STATUS_TMX_BIT         (1 << 13)
348c2ecf20Sopenharmony_ci#define STATUS_SMX_BIT         (1 << 14)
358c2ecf20Sopenharmony_ci#define STATUS_BR_BIT          (1 << 15)
368c2ecf20Sopenharmony_ci
378c2ecf20Sopenharmony_ci/* Interrupt mask bits */
388c2ecf20Sopenharmony_ci#define CONFIG_ALRT_BIT_ENBL	(1 << 2)
398c2ecf20Sopenharmony_ci#define STATUS_INTR_SOCMIN_BIT	(1 << 10)
408c2ecf20Sopenharmony_ci#define STATUS_INTR_SOCMAX_BIT	(1 << 14)
418c2ecf20Sopenharmony_ci
428c2ecf20Sopenharmony_ci#define VFSOC0_LOCK		0x0000
438c2ecf20Sopenharmony_ci#define VFSOC0_UNLOCK		0x0080
448c2ecf20Sopenharmony_ci#define MODEL_UNLOCK1	0X0059
458c2ecf20Sopenharmony_ci#define MODEL_UNLOCK2	0X00C4
468c2ecf20Sopenharmony_ci#define MODEL_LOCK1		0X0000
478c2ecf20Sopenharmony_ci#define MODEL_LOCK2		0X0000
488c2ecf20Sopenharmony_ci
498c2ecf20Sopenharmony_ci#define dQ_ACC_DIV	0x4
508c2ecf20Sopenharmony_ci#define dP_ACC_100	0x1900
518c2ecf20Sopenharmony_ci#define dP_ACC_200	0x3200
528c2ecf20Sopenharmony_ci
538c2ecf20Sopenharmony_ci#define MAX17042_VMAX_TOLERANCE		50 /* 50 mV */
548c2ecf20Sopenharmony_ci
558c2ecf20Sopenharmony_cistruct max17042_chip {
568c2ecf20Sopenharmony_ci	struct i2c_client *client;
578c2ecf20Sopenharmony_ci	struct regmap *regmap;
588c2ecf20Sopenharmony_ci	struct power_supply *battery;
598c2ecf20Sopenharmony_ci	enum max170xx_chip_type chip_type;
608c2ecf20Sopenharmony_ci	struct max17042_platform_data *pdata;
618c2ecf20Sopenharmony_ci	struct work_struct work;
628c2ecf20Sopenharmony_ci	int    init_complete;
638c2ecf20Sopenharmony_ci};
648c2ecf20Sopenharmony_ci
658c2ecf20Sopenharmony_cistatic enum power_supply_property max17042_battery_props[] = {
668c2ecf20Sopenharmony_ci	POWER_SUPPLY_PROP_STATUS,
678c2ecf20Sopenharmony_ci	POWER_SUPPLY_PROP_PRESENT,
688c2ecf20Sopenharmony_ci	POWER_SUPPLY_PROP_TECHNOLOGY,
698c2ecf20Sopenharmony_ci	POWER_SUPPLY_PROP_CYCLE_COUNT,
708c2ecf20Sopenharmony_ci	POWER_SUPPLY_PROP_VOLTAGE_MAX,
718c2ecf20Sopenharmony_ci	POWER_SUPPLY_PROP_VOLTAGE_MIN,
728c2ecf20Sopenharmony_ci	POWER_SUPPLY_PROP_VOLTAGE_MIN_DESIGN,
738c2ecf20Sopenharmony_ci	POWER_SUPPLY_PROP_VOLTAGE_NOW,
748c2ecf20Sopenharmony_ci	POWER_SUPPLY_PROP_VOLTAGE_AVG,
758c2ecf20Sopenharmony_ci	POWER_SUPPLY_PROP_VOLTAGE_OCV,
768c2ecf20Sopenharmony_ci	POWER_SUPPLY_PROP_CAPACITY,
778c2ecf20Sopenharmony_ci	POWER_SUPPLY_PROP_CHARGE_FULL_DESIGN,
788c2ecf20Sopenharmony_ci	POWER_SUPPLY_PROP_CHARGE_FULL,
798c2ecf20Sopenharmony_ci	POWER_SUPPLY_PROP_CHARGE_NOW,
808c2ecf20Sopenharmony_ci	POWER_SUPPLY_PROP_CHARGE_COUNTER,
818c2ecf20Sopenharmony_ci	POWER_SUPPLY_PROP_TEMP,
828c2ecf20Sopenharmony_ci	POWER_SUPPLY_PROP_TEMP_ALERT_MIN,
838c2ecf20Sopenharmony_ci	POWER_SUPPLY_PROP_TEMP_ALERT_MAX,
848c2ecf20Sopenharmony_ci	POWER_SUPPLY_PROP_TEMP_MIN,
858c2ecf20Sopenharmony_ci	POWER_SUPPLY_PROP_TEMP_MAX,
868c2ecf20Sopenharmony_ci	POWER_SUPPLY_PROP_HEALTH,
878c2ecf20Sopenharmony_ci	POWER_SUPPLY_PROP_SCOPE,
888c2ecf20Sopenharmony_ci	POWER_SUPPLY_PROP_TIME_TO_EMPTY_NOW,
898c2ecf20Sopenharmony_ci	// these two have to be at the end on the list
908c2ecf20Sopenharmony_ci	POWER_SUPPLY_PROP_CURRENT_NOW,
918c2ecf20Sopenharmony_ci	POWER_SUPPLY_PROP_CURRENT_AVG,
928c2ecf20Sopenharmony_ci};
938c2ecf20Sopenharmony_ci
948c2ecf20Sopenharmony_cistatic int max17042_get_temperature(struct max17042_chip *chip, int *temp)
958c2ecf20Sopenharmony_ci{
968c2ecf20Sopenharmony_ci	int ret;
978c2ecf20Sopenharmony_ci	u32 data;
988c2ecf20Sopenharmony_ci	struct regmap *map = chip->regmap;
998c2ecf20Sopenharmony_ci
1008c2ecf20Sopenharmony_ci	ret = regmap_read(map, MAX17042_TEMP, &data);
1018c2ecf20Sopenharmony_ci	if (ret < 0)
1028c2ecf20Sopenharmony_ci		return ret;
1038c2ecf20Sopenharmony_ci
1048c2ecf20Sopenharmony_ci	*temp = sign_extend32(data, 15);
1058c2ecf20Sopenharmony_ci	/* The value is converted into deci-centigrade scale */
1068c2ecf20Sopenharmony_ci	/* Units of LSB = 1 / 256 degree Celsius */
1078c2ecf20Sopenharmony_ci	*temp = *temp * 10 / 256;
1088c2ecf20Sopenharmony_ci	return 0;
1098c2ecf20Sopenharmony_ci}
1108c2ecf20Sopenharmony_ci
1118c2ecf20Sopenharmony_cistatic int max17042_get_status(struct max17042_chip *chip, int *status)
1128c2ecf20Sopenharmony_ci{
1138c2ecf20Sopenharmony_ci	int ret, charge_full, charge_now;
1148c2ecf20Sopenharmony_ci	int avg_current;
1158c2ecf20Sopenharmony_ci	u32 data;
1168c2ecf20Sopenharmony_ci
1178c2ecf20Sopenharmony_ci	ret = power_supply_am_i_supplied(chip->battery);
1188c2ecf20Sopenharmony_ci	if (ret < 0) {
1198c2ecf20Sopenharmony_ci		*status = POWER_SUPPLY_STATUS_UNKNOWN;
1208c2ecf20Sopenharmony_ci		return 0;
1218c2ecf20Sopenharmony_ci	}
1228c2ecf20Sopenharmony_ci	if (ret == 0) {
1238c2ecf20Sopenharmony_ci		*status = POWER_SUPPLY_STATUS_DISCHARGING;
1248c2ecf20Sopenharmony_ci		return 0;
1258c2ecf20Sopenharmony_ci	}
1268c2ecf20Sopenharmony_ci
1278c2ecf20Sopenharmony_ci	/*
1288c2ecf20Sopenharmony_ci	 * The MAX170xx has builtin end-of-charge detection and will update
1298c2ecf20Sopenharmony_ci	 * FullCAP to match RepCap when it detects end of charging.
1308c2ecf20Sopenharmony_ci	 *
1318c2ecf20Sopenharmony_ci	 * When this cycle the battery gets charged to a higher (calculated)
1328c2ecf20Sopenharmony_ci	 * capacity then the previous cycle then FullCAP will get updated
1338c2ecf20Sopenharmony_ci	 * contineously once end-of-charge detection kicks in, so allow the
1348c2ecf20Sopenharmony_ci	 * 2 to differ a bit.
1358c2ecf20Sopenharmony_ci	 */
1368c2ecf20Sopenharmony_ci
1378c2ecf20Sopenharmony_ci	ret = regmap_read(chip->regmap, MAX17042_FullCAP, &charge_full);
1388c2ecf20Sopenharmony_ci	if (ret < 0)
1398c2ecf20Sopenharmony_ci		return ret;
1408c2ecf20Sopenharmony_ci
1418c2ecf20Sopenharmony_ci	ret = regmap_read(chip->regmap, MAX17042_RepCap, &charge_now);
1428c2ecf20Sopenharmony_ci	if (ret < 0)
1438c2ecf20Sopenharmony_ci		return ret;
1448c2ecf20Sopenharmony_ci
1458c2ecf20Sopenharmony_ci	if ((charge_full - charge_now) <= MAX17042_FULL_THRESHOLD) {
1468c2ecf20Sopenharmony_ci		*status = POWER_SUPPLY_STATUS_FULL;
1478c2ecf20Sopenharmony_ci		return 0;
1488c2ecf20Sopenharmony_ci	}
1498c2ecf20Sopenharmony_ci
1508c2ecf20Sopenharmony_ci	/*
1518c2ecf20Sopenharmony_ci	 * Even though we are supplied, we may still be discharging if the
1528c2ecf20Sopenharmony_ci	 * supply is e.g. only delivering 5V 0.5A. Check current if available.
1538c2ecf20Sopenharmony_ci	 */
1548c2ecf20Sopenharmony_ci	if (!chip->pdata->enable_current_sense) {
1558c2ecf20Sopenharmony_ci		*status = POWER_SUPPLY_STATUS_CHARGING;
1568c2ecf20Sopenharmony_ci		return 0;
1578c2ecf20Sopenharmony_ci	}
1588c2ecf20Sopenharmony_ci
1598c2ecf20Sopenharmony_ci	ret = regmap_read(chip->regmap, MAX17042_AvgCurrent, &data);
1608c2ecf20Sopenharmony_ci	if (ret < 0)
1618c2ecf20Sopenharmony_ci		return ret;
1628c2ecf20Sopenharmony_ci
1638c2ecf20Sopenharmony_ci	avg_current = sign_extend32(data, 15);
1648c2ecf20Sopenharmony_ci	avg_current *= 1562500 / chip->pdata->r_sns;
1658c2ecf20Sopenharmony_ci
1668c2ecf20Sopenharmony_ci	if (avg_current > 0)
1678c2ecf20Sopenharmony_ci		*status = POWER_SUPPLY_STATUS_CHARGING;
1688c2ecf20Sopenharmony_ci	else
1698c2ecf20Sopenharmony_ci		*status = POWER_SUPPLY_STATUS_DISCHARGING;
1708c2ecf20Sopenharmony_ci
1718c2ecf20Sopenharmony_ci	return 0;
1728c2ecf20Sopenharmony_ci}
1738c2ecf20Sopenharmony_ci
1748c2ecf20Sopenharmony_cistatic int max17042_get_battery_health(struct max17042_chip *chip, int *health)
1758c2ecf20Sopenharmony_ci{
1768c2ecf20Sopenharmony_ci	int temp, vavg, vbatt, ret;
1778c2ecf20Sopenharmony_ci	u32 val;
1788c2ecf20Sopenharmony_ci
1798c2ecf20Sopenharmony_ci	ret = regmap_read(chip->regmap, MAX17042_AvgVCELL, &val);
1808c2ecf20Sopenharmony_ci	if (ret < 0)
1818c2ecf20Sopenharmony_ci		goto health_error;
1828c2ecf20Sopenharmony_ci
1838c2ecf20Sopenharmony_ci	/* bits [0-3] unused */
1848c2ecf20Sopenharmony_ci	vavg = val * 625 / 8;
1858c2ecf20Sopenharmony_ci	/* Convert to millivolts */
1868c2ecf20Sopenharmony_ci	vavg /= 1000;
1878c2ecf20Sopenharmony_ci
1888c2ecf20Sopenharmony_ci	ret = regmap_read(chip->regmap, MAX17042_VCELL, &val);
1898c2ecf20Sopenharmony_ci	if (ret < 0)
1908c2ecf20Sopenharmony_ci		goto health_error;
1918c2ecf20Sopenharmony_ci
1928c2ecf20Sopenharmony_ci	/* bits [0-3] unused */
1938c2ecf20Sopenharmony_ci	vbatt = val * 625 / 8;
1948c2ecf20Sopenharmony_ci	/* Convert to millivolts */
1958c2ecf20Sopenharmony_ci	vbatt /= 1000;
1968c2ecf20Sopenharmony_ci
1978c2ecf20Sopenharmony_ci	if (vavg < chip->pdata->vmin) {
1988c2ecf20Sopenharmony_ci		*health = POWER_SUPPLY_HEALTH_DEAD;
1998c2ecf20Sopenharmony_ci		goto out;
2008c2ecf20Sopenharmony_ci	}
2018c2ecf20Sopenharmony_ci
2028c2ecf20Sopenharmony_ci	if (vbatt > chip->pdata->vmax + MAX17042_VMAX_TOLERANCE) {
2038c2ecf20Sopenharmony_ci		*health = POWER_SUPPLY_HEALTH_OVERVOLTAGE;
2048c2ecf20Sopenharmony_ci		goto out;
2058c2ecf20Sopenharmony_ci	}
2068c2ecf20Sopenharmony_ci
2078c2ecf20Sopenharmony_ci	ret = max17042_get_temperature(chip, &temp);
2088c2ecf20Sopenharmony_ci	if (ret < 0)
2098c2ecf20Sopenharmony_ci		goto health_error;
2108c2ecf20Sopenharmony_ci
2118c2ecf20Sopenharmony_ci	if (temp < chip->pdata->temp_min) {
2128c2ecf20Sopenharmony_ci		*health = POWER_SUPPLY_HEALTH_COLD;
2138c2ecf20Sopenharmony_ci		goto out;
2148c2ecf20Sopenharmony_ci	}
2158c2ecf20Sopenharmony_ci
2168c2ecf20Sopenharmony_ci	if (temp > chip->pdata->temp_max) {
2178c2ecf20Sopenharmony_ci		*health = POWER_SUPPLY_HEALTH_OVERHEAT;
2188c2ecf20Sopenharmony_ci		goto out;
2198c2ecf20Sopenharmony_ci	}
2208c2ecf20Sopenharmony_ci
2218c2ecf20Sopenharmony_ci	*health = POWER_SUPPLY_HEALTH_GOOD;
2228c2ecf20Sopenharmony_ci
2238c2ecf20Sopenharmony_ciout:
2248c2ecf20Sopenharmony_ci	return 0;
2258c2ecf20Sopenharmony_ci
2268c2ecf20Sopenharmony_cihealth_error:
2278c2ecf20Sopenharmony_ci	return ret;
2288c2ecf20Sopenharmony_ci}
2298c2ecf20Sopenharmony_ci
2308c2ecf20Sopenharmony_cistatic int max17042_get_property(struct power_supply *psy,
2318c2ecf20Sopenharmony_ci			    enum power_supply_property psp,
2328c2ecf20Sopenharmony_ci			    union power_supply_propval *val)
2338c2ecf20Sopenharmony_ci{
2348c2ecf20Sopenharmony_ci	struct max17042_chip *chip = power_supply_get_drvdata(psy);
2358c2ecf20Sopenharmony_ci	struct regmap *map = chip->regmap;
2368c2ecf20Sopenharmony_ci	int ret;
2378c2ecf20Sopenharmony_ci	u32 data;
2388c2ecf20Sopenharmony_ci	u64 data64;
2398c2ecf20Sopenharmony_ci
2408c2ecf20Sopenharmony_ci	if (!chip->init_complete)
2418c2ecf20Sopenharmony_ci		return -EAGAIN;
2428c2ecf20Sopenharmony_ci
2438c2ecf20Sopenharmony_ci	switch (psp) {
2448c2ecf20Sopenharmony_ci	case POWER_SUPPLY_PROP_STATUS:
2458c2ecf20Sopenharmony_ci		ret = max17042_get_status(chip, &val->intval);
2468c2ecf20Sopenharmony_ci		if (ret < 0)
2478c2ecf20Sopenharmony_ci			return ret;
2488c2ecf20Sopenharmony_ci		break;
2498c2ecf20Sopenharmony_ci	case POWER_SUPPLY_PROP_PRESENT:
2508c2ecf20Sopenharmony_ci		ret = regmap_read(map, MAX17042_STATUS, &data);
2518c2ecf20Sopenharmony_ci		if (ret < 0)
2528c2ecf20Sopenharmony_ci			return ret;
2538c2ecf20Sopenharmony_ci
2548c2ecf20Sopenharmony_ci		if (data & MAX17042_STATUS_BattAbsent)
2558c2ecf20Sopenharmony_ci			val->intval = 0;
2568c2ecf20Sopenharmony_ci		else
2578c2ecf20Sopenharmony_ci			val->intval = 1;
2588c2ecf20Sopenharmony_ci		break;
2598c2ecf20Sopenharmony_ci	case POWER_SUPPLY_PROP_TECHNOLOGY:
2608c2ecf20Sopenharmony_ci		val->intval = POWER_SUPPLY_TECHNOLOGY_LION;
2618c2ecf20Sopenharmony_ci		break;
2628c2ecf20Sopenharmony_ci	case POWER_SUPPLY_PROP_CYCLE_COUNT:
2638c2ecf20Sopenharmony_ci		ret = regmap_read(map, MAX17042_Cycles, &data);
2648c2ecf20Sopenharmony_ci		if (ret < 0)
2658c2ecf20Sopenharmony_ci			return ret;
2668c2ecf20Sopenharmony_ci
2678c2ecf20Sopenharmony_ci		val->intval = data;
2688c2ecf20Sopenharmony_ci		break;
2698c2ecf20Sopenharmony_ci	case POWER_SUPPLY_PROP_VOLTAGE_MAX:
2708c2ecf20Sopenharmony_ci		ret = regmap_read(map, MAX17042_MinMaxVolt, &data);
2718c2ecf20Sopenharmony_ci		if (ret < 0)
2728c2ecf20Sopenharmony_ci			return ret;
2738c2ecf20Sopenharmony_ci
2748c2ecf20Sopenharmony_ci		val->intval = data >> 8;
2758c2ecf20Sopenharmony_ci		val->intval *= 20000; /* Units of LSB = 20mV */
2768c2ecf20Sopenharmony_ci		break;
2778c2ecf20Sopenharmony_ci	case POWER_SUPPLY_PROP_VOLTAGE_MIN:
2788c2ecf20Sopenharmony_ci		ret = regmap_read(map, MAX17042_MinMaxVolt, &data);
2798c2ecf20Sopenharmony_ci		if (ret < 0)
2808c2ecf20Sopenharmony_ci			return ret;
2818c2ecf20Sopenharmony_ci
2828c2ecf20Sopenharmony_ci		val->intval = (data & 0xff) * 20000; /* Units of 20mV */
2838c2ecf20Sopenharmony_ci		break;
2848c2ecf20Sopenharmony_ci	case POWER_SUPPLY_PROP_VOLTAGE_MIN_DESIGN:
2858c2ecf20Sopenharmony_ci		if (chip->chip_type == MAXIM_DEVICE_TYPE_MAX17042)
2868c2ecf20Sopenharmony_ci			ret = regmap_read(map, MAX17042_V_empty, &data);
2878c2ecf20Sopenharmony_ci		else if (chip->chip_type == MAXIM_DEVICE_TYPE_MAX17055)
2888c2ecf20Sopenharmony_ci			ret = regmap_read(map, MAX17055_V_empty, &data);
2898c2ecf20Sopenharmony_ci		else
2908c2ecf20Sopenharmony_ci			ret = regmap_read(map, MAX17047_V_empty, &data);
2918c2ecf20Sopenharmony_ci		if (ret < 0)
2928c2ecf20Sopenharmony_ci			return ret;
2938c2ecf20Sopenharmony_ci
2948c2ecf20Sopenharmony_ci		val->intval = data >> 7;
2958c2ecf20Sopenharmony_ci		val->intval *= 10000; /* Units of LSB = 10mV */
2968c2ecf20Sopenharmony_ci		break;
2978c2ecf20Sopenharmony_ci	case POWER_SUPPLY_PROP_VOLTAGE_NOW:
2988c2ecf20Sopenharmony_ci		ret = regmap_read(map, MAX17042_VCELL, &data);
2998c2ecf20Sopenharmony_ci		if (ret < 0)
3008c2ecf20Sopenharmony_ci			return ret;
3018c2ecf20Sopenharmony_ci
3028c2ecf20Sopenharmony_ci		val->intval = data * 625 / 8;
3038c2ecf20Sopenharmony_ci		break;
3048c2ecf20Sopenharmony_ci	case POWER_SUPPLY_PROP_VOLTAGE_AVG:
3058c2ecf20Sopenharmony_ci		ret = regmap_read(map, MAX17042_AvgVCELL, &data);
3068c2ecf20Sopenharmony_ci		if (ret < 0)
3078c2ecf20Sopenharmony_ci			return ret;
3088c2ecf20Sopenharmony_ci
3098c2ecf20Sopenharmony_ci		val->intval = data * 625 / 8;
3108c2ecf20Sopenharmony_ci		break;
3118c2ecf20Sopenharmony_ci	case POWER_SUPPLY_PROP_VOLTAGE_OCV:
3128c2ecf20Sopenharmony_ci		ret = regmap_read(map, MAX17042_OCVInternal, &data);
3138c2ecf20Sopenharmony_ci		if (ret < 0)
3148c2ecf20Sopenharmony_ci			return ret;
3158c2ecf20Sopenharmony_ci
3168c2ecf20Sopenharmony_ci		val->intval = data * 625 / 8;
3178c2ecf20Sopenharmony_ci		break;
3188c2ecf20Sopenharmony_ci	case POWER_SUPPLY_PROP_CAPACITY:
3198c2ecf20Sopenharmony_ci		if (chip->pdata->enable_current_sense)
3208c2ecf20Sopenharmony_ci			ret = regmap_read(map, MAX17042_RepSOC, &data);
3218c2ecf20Sopenharmony_ci		else
3228c2ecf20Sopenharmony_ci			ret = regmap_read(map, MAX17042_VFSOC, &data);
3238c2ecf20Sopenharmony_ci		if (ret < 0)
3248c2ecf20Sopenharmony_ci			return ret;
3258c2ecf20Sopenharmony_ci
3268c2ecf20Sopenharmony_ci		val->intval = data >> 8;
3278c2ecf20Sopenharmony_ci		break;
3288c2ecf20Sopenharmony_ci	case POWER_SUPPLY_PROP_CHARGE_FULL_DESIGN:
3298c2ecf20Sopenharmony_ci		ret = regmap_read(map, MAX17042_DesignCap, &data);
3308c2ecf20Sopenharmony_ci		if (ret < 0)
3318c2ecf20Sopenharmony_ci			return ret;
3328c2ecf20Sopenharmony_ci
3338c2ecf20Sopenharmony_ci		data64 = data * 5000000ll;
3348c2ecf20Sopenharmony_ci		do_div(data64, chip->pdata->r_sns);
3358c2ecf20Sopenharmony_ci		val->intval = data64;
3368c2ecf20Sopenharmony_ci		break;
3378c2ecf20Sopenharmony_ci	case POWER_SUPPLY_PROP_CHARGE_FULL:
3388c2ecf20Sopenharmony_ci		ret = regmap_read(map, MAX17042_FullCAP, &data);
3398c2ecf20Sopenharmony_ci		if (ret < 0)
3408c2ecf20Sopenharmony_ci			return ret;
3418c2ecf20Sopenharmony_ci
3428c2ecf20Sopenharmony_ci		data64 = data * 5000000ll;
3438c2ecf20Sopenharmony_ci		do_div(data64, chip->pdata->r_sns);
3448c2ecf20Sopenharmony_ci		val->intval = data64;
3458c2ecf20Sopenharmony_ci		break;
3468c2ecf20Sopenharmony_ci	case POWER_SUPPLY_PROP_CHARGE_NOW:
3478c2ecf20Sopenharmony_ci		ret = regmap_read(map, MAX17042_RepCap, &data);
3488c2ecf20Sopenharmony_ci		if (ret < 0)
3498c2ecf20Sopenharmony_ci			return ret;
3508c2ecf20Sopenharmony_ci
3518c2ecf20Sopenharmony_ci		data64 = data * 5000000ll;
3528c2ecf20Sopenharmony_ci		do_div(data64, chip->pdata->r_sns);
3538c2ecf20Sopenharmony_ci		val->intval = data64;
3548c2ecf20Sopenharmony_ci		break;
3558c2ecf20Sopenharmony_ci	case POWER_SUPPLY_PROP_CHARGE_COUNTER:
3568c2ecf20Sopenharmony_ci		ret = regmap_read(map, MAX17042_QH, &data);
3578c2ecf20Sopenharmony_ci		if (ret < 0)
3588c2ecf20Sopenharmony_ci			return ret;
3598c2ecf20Sopenharmony_ci
3608c2ecf20Sopenharmony_ci		val->intval = data * 1000 / 2;
3618c2ecf20Sopenharmony_ci		break;
3628c2ecf20Sopenharmony_ci	case POWER_SUPPLY_PROP_TEMP:
3638c2ecf20Sopenharmony_ci		ret = max17042_get_temperature(chip, &val->intval);
3648c2ecf20Sopenharmony_ci		if (ret < 0)
3658c2ecf20Sopenharmony_ci			return ret;
3668c2ecf20Sopenharmony_ci		break;
3678c2ecf20Sopenharmony_ci	case POWER_SUPPLY_PROP_TEMP_ALERT_MIN:
3688c2ecf20Sopenharmony_ci		ret = regmap_read(map, MAX17042_TALRT_Th, &data);
3698c2ecf20Sopenharmony_ci		if (ret < 0)
3708c2ecf20Sopenharmony_ci			return ret;
3718c2ecf20Sopenharmony_ci		/* LSB is Alert Minimum. In deci-centigrade */
3728c2ecf20Sopenharmony_ci		val->intval = sign_extend32(data & 0xff, 7) * 10;
3738c2ecf20Sopenharmony_ci		break;
3748c2ecf20Sopenharmony_ci	case POWER_SUPPLY_PROP_TEMP_ALERT_MAX:
3758c2ecf20Sopenharmony_ci		ret = regmap_read(map, MAX17042_TALRT_Th, &data);
3768c2ecf20Sopenharmony_ci		if (ret < 0)
3778c2ecf20Sopenharmony_ci			return ret;
3788c2ecf20Sopenharmony_ci		/* MSB is Alert Maximum. In deci-centigrade */
3798c2ecf20Sopenharmony_ci		val->intval = sign_extend32(data >> 8, 7) * 10;
3808c2ecf20Sopenharmony_ci		break;
3818c2ecf20Sopenharmony_ci	case POWER_SUPPLY_PROP_TEMP_MIN:
3828c2ecf20Sopenharmony_ci		val->intval = chip->pdata->temp_min;
3838c2ecf20Sopenharmony_ci		break;
3848c2ecf20Sopenharmony_ci	case POWER_SUPPLY_PROP_TEMP_MAX:
3858c2ecf20Sopenharmony_ci		val->intval = chip->pdata->temp_max;
3868c2ecf20Sopenharmony_ci		break;
3878c2ecf20Sopenharmony_ci	case POWER_SUPPLY_PROP_HEALTH:
3888c2ecf20Sopenharmony_ci		ret = max17042_get_battery_health(chip, &val->intval);
3898c2ecf20Sopenharmony_ci		if (ret < 0)
3908c2ecf20Sopenharmony_ci			return ret;
3918c2ecf20Sopenharmony_ci		break;
3928c2ecf20Sopenharmony_ci	case POWER_SUPPLY_PROP_SCOPE:
3938c2ecf20Sopenharmony_ci		val->intval = POWER_SUPPLY_SCOPE_SYSTEM;
3948c2ecf20Sopenharmony_ci		break;
3958c2ecf20Sopenharmony_ci	case POWER_SUPPLY_PROP_CURRENT_NOW:
3968c2ecf20Sopenharmony_ci		if (chip->pdata->enable_current_sense) {
3978c2ecf20Sopenharmony_ci			ret = regmap_read(map, MAX17042_Current, &data);
3988c2ecf20Sopenharmony_ci			if (ret < 0)
3998c2ecf20Sopenharmony_ci				return ret;
4008c2ecf20Sopenharmony_ci
4018c2ecf20Sopenharmony_ci			val->intval = sign_extend32(data, 15);
4028c2ecf20Sopenharmony_ci			val->intval *= 1562500 / chip->pdata->r_sns;
4038c2ecf20Sopenharmony_ci		} else {
4048c2ecf20Sopenharmony_ci			return -EINVAL;
4058c2ecf20Sopenharmony_ci		}
4068c2ecf20Sopenharmony_ci		break;
4078c2ecf20Sopenharmony_ci	case POWER_SUPPLY_PROP_CURRENT_AVG:
4088c2ecf20Sopenharmony_ci		if (chip->pdata->enable_current_sense) {
4098c2ecf20Sopenharmony_ci			ret = regmap_read(map, MAX17042_AvgCurrent, &data);
4108c2ecf20Sopenharmony_ci			if (ret < 0)
4118c2ecf20Sopenharmony_ci				return ret;
4128c2ecf20Sopenharmony_ci
4138c2ecf20Sopenharmony_ci			val->intval = sign_extend32(data, 15);
4148c2ecf20Sopenharmony_ci			val->intval *= 1562500 / chip->pdata->r_sns;
4158c2ecf20Sopenharmony_ci		} else {
4168c2ecf20Sopenharmony_ci			return -EINVAL;
4178c2ecf20Sopenharmony_ci		}
4188c2ecf20Sopenharmony_ci		break;
4198c2ecf20Sopenharmony_ci	case POWER_SUPPLY_PROP_TIME_TO_EMPTY_NOW:
4208c2ecf20Sopenharmony_ci		ret = regmap_read(map, MAX17042_TTE, &data);
4218c2ecf20Sopenharmony_ci		if (ret < 0)
4228c2ecf20Sopenharmony_ci			return ret;
4238c2ecf20Sopenharmony_ci
4248c2ecf20Sopenharmony_ci		val->intval = data * 5625 / 1000;
4258c2ecf20Sopenharmony_ci		break;
4268c2ecf20Sopenharmony_ci	default:
4278c2ecf20Sopenharmony_ci		return -EINVAL;
4288c2ecf20Sopenharmony_ci	}
4298c2ecf20Sopenharmony_ci	return 0;
4308c2ecf20Sopenharmony_ci}
4318c2ecf20Sopenharmony_ci
4328c2ecf20Sopenharmony_cistatic int max17042_set_property(struct power_supply *psy,
4338c2ecf20Sopenharmony_ci			    enum power_supply_property psp,
4348c2ecf20Sopenharmony_ci			    const union power_supply_propval *val)
4358c2ecf20Sopenharmony_ci{
4368c2ecf20Sopenharmony_ci	struct max17042_chip *chip = power_supply_get_drvdata(psy);
4378c2ecf20Sopenharmony_ci	struct regmap *map = chip->regmap;
4388c2ecf20Sopenharmony_ci	int ret = 0;
4398c2ecf20Sopenharmony_ci	u32 data;
4408c2ecf20Sopenharmony_ci	int8_t temp;
4418c2ecf20Sopenharmony_ci
4428c2ecf20Sopenharmony_ci	switch (psp) {
4438c2ecf20Sopenharmony_ci	case POWER_SUPPLY_PROP_TEMP_ALERT_MIN:
4448c2ecf20Sopenharmony_ci		ret = regmap_read(map, MAX17042_TALRT_Th, &data);
4458c2ecf20Sopenharmony_ci		if (ret < 0)
4468c2ecf20Sopenharmony_ci			return ret;
4478c2ecf20Sopenharmony_ci
4488c2ecf20Sopenharmony_ci		/* Input in deci-centigrade, convert to centigrade */
4498c2ecf20Sopenharmony_ci		temp = val->intval / 10;
4508c2ecf20Sopenharmony_ci		/* force min < max */
4518c2ecf20Sopenharmony_ci		if (temp >= (int8_t)(data >> 8))
4528c2ecf20Sopenharmony_ci			temp = (int8_t)(data >> 8) - 1;
4538c2ecf20Sopenharmony_ci		/* Write both MAX and MIN ALERT */
4548c2ecf20Sopenharmony_ci		data = (data & 0xff00) + temp;
4558c2ecf20Sopenharmony_ci		ret = regmap_write(map, MAX17042_TALRT_Th, data);
4568c2ecf20Sopenharmony_ci		break;
4578c2ecf20Sopenharmony_ci	case POWER_SUPPLY_PROP_TEMP_ALERT_MAX:
4588c2ecf20Sopenharmony_ci		ret = regmap_read(map, MAX17042_TALRT_Th, &data);
4598c2ecf20Sopenharmony_ci		if (ret < 0)
4608c2ecf20Sopenharmony_ci			return ret;
4618c2ecf20Sopenharmony_ci
4628c2ecf20Sopenharmony_ci		/* Input in Deci-Centigrade, convert to centigrade */
4638c2ecf20Sopenharmony_ci		temp = val->intval / 10;
4648c2ecf20Sopenharmony_ci		/* force max > min */
4658c2ecf20Sopenharmony_ci		if (temp <= (int8_t)(data & 0xff))
4668c2ecf20Sopenharmony_ci			temp = (int8_t)(data & 0xff) + 1;
4678c2ecf20Sopenharmony_ci		/* Write both MAX and MIN ALERT */
4688c2ecf20Sopenharmony_ci		data = (data & 0xff) + (temp << 8);
4698c2ecf20Sopenharmony_ci		ret = regmap_write(map, MAX17042_TALRT_Th, data);
4708c2ecf20Sopenharmony_ci		break;
4718c2ecf20Sopenharmony_ci	default:
4728c2ecf20Sopenharmony_ci		ret = -EINVAL;
4738c2ecf20Sopenharmony_ci	}
4748c2ecf20Sopenharmony_ci
4758c2ecf20Sopenharmony_ci	return ret;
4768c2ecf20Sopenharmony_ci}
4778c2ecf20Sopenharmony_ci
4788c2ecf20Sopenharmony_cistatic int max17042_property_is_writeable(struct power_supply *psy,
4798c2ecf20Sopenharmony_ci		enum power_supply_property psp)
4808c2ecf20Sopenharmony_ci{
4818c2ecf20Sopenharmony_ci	int ret;
4828c2ecf20Sopenharmony_ci
4838c2ecf20Sopenharmony_ci	switch (psp) {
4848c2ecf20Sopenharmony_ci	case POWER_SUPPLY_PROP_TEMP_ALERT_MIN:
4858c2ecf20Sopenharmony_ci	case POWER_SUPPLY_PROP_TEMP_ALERT_MAX:
4868c2ecf20Sopenharmony_ci		ret = 1;
4878c2ecf20Sopenharmony_ci		break;
4888c2ecf20Sopenharmony_ci	default:
4898c2ecf20Sopenharmony_ci		ret = 0;
4908c2ecf20Sopenharmony_ci	}
4918c2ecf20Sopenharmony_ci
4928c2ecf20Sopenharmony_ci	return ret;
4938c2ecf20Sopenharmony_ci}
4948c2ecf20Sopenharmony_ci
4958c2ecf20Sopenharmony_cistatic void max17042_external_power_changed(struct power_supply *psy)
4968c2ecf20Sopenharmony_ci{
4978c2ecf20Sopenharmony_ci	power_supply_changed(psy);
4988c2ecf20Sopenharmony_ci}
4998c2ecf20Sopenharmony_ci
5008c2ecf20Sopenharmony_cistatic int max17042_write_verify_reg(struct regmap *map, u8 reg, u32 value)
5018c2ecf20Sopenharmony_ci{
5028c2ecf20Sopenharmony_ci	int retries = 8;
5038c2ecf20Sopenharmony_ci	int ret;
5048c2ecf20Sopenharmony_ci	u32 read_value;
5058c2ecf20Sopenharmony_ci
5068c2ecf20Sopenharmony_ci	do {
5078c2ecf20Sopenharmony_ci		ret = regmap_write(map, reg, value);
5088c2ecf20Sopenharmony_ci		regmap_read(map, reg, &read_value);
5098c2ecf20Sopenharmony_ci		if (read_value != value) {
5108c2ecf20Sopenharmony_ci			ret = -EIO;
5118c2ecf20Sopenharmony_ci			retries--;
5128c2ecf20Sopenharmony_ci		}
5138c2ecf20Sopenharmony_ci	} while (retries && read_value != value);
5148c2ecf20Sopenharmony_ci
5158c2ecf20Sopenharmony_ci	if (ret < 0)
5168c2ecf20Sopenharmony_ci		pr_err("%s: err %d\n", __func__, ret);
5178c2ecf20Sopenharmony_ci
5188c2ecf20Sopenharmony_ci	return ret;
5198c2ecf20Sopenharmony_ci}
5208c2ecf20Sopenharmony_ci
5218c2ecf20Sopenharmony_cistatic inline void max17042_override_por(struct regmap *map,
5228c2ecf20Sopenharmony_ci					 u8 reg, u16 value)
5238c2ecf20Sopenharmony_ci{
5248c2ecf20Sopenharmony_ci	if (value)
5258c2ecf20Sopenharmony_ci		regmap_write(map, reg, value);
5268c2ecf20Sopenharmony_ci}
5278c2ecf20Sopenharmony_ci
5288c2ecf20Sopenharmony_cistatic inline void max17042_unlock_model(struct max17042_chip *chip)
5298c2ecf20Sopenharmony_ci{
5308c2ecf20Sopenharmony_ci	struct regmap *map = chip->regmap;
5318c2ecf20Sopenharmony_ci
5328c2ecf20Sopenharmony_ci	regmap_write(map, MAX17042_MLOCKReg1, MODEL_UNLOCK1);
5338c2ecf20Sopenharmony_ci	regmap_write(map, MAX17042_MLOCKReg2, MODEL_UNLOCK2);
5348c2ecf20Sopenharmony_ci}
5358c2ecf20Sopenharmony_ci
5368c2ecf20Sopenharmony_cistatic inline void max17042_lock_model(struct max17042_chip *chip)
5378c2ecf20Sopenharmony_ci{
5388c2ecf20Sopenharmony_ci	struct regmap *map = chip->regmap;
5398c2ecf20Sopenharmony_ci
5408c2ecf20Sopenharmony_ci	regmap_write(map, MAX17042_MLOCKReg1, MODEL_LOCK1);
5418c2ecf20Sopenharmony_ci	regmap_write(map, MAX17042_MLOCKReg2, MODEL_LOCK2);
5428c2ecf20Sopenharmony_ci}
5438c2ecf20Sopenharmony_ci
5448c2ecf20Sopenharmony_cistatic inline void max17042_write_model_data(struct max17042_chip *chip,
5458c2ecf20Sopenharmony_ci					u8 addr, int size)
5468c2ecf20Sopenharmony_ci{
5478c2ecf20Sopenharmony_ci	struct regmap *map = chip->regmap;
5488c2ecf20Sopenharmony_ci	int i;
5498c2ecf20Sopenharmony_ci
5508c2ecf20Sopenharmony_ci	for (i = 0; i < size; i++)
5518c2ecf20Sopenharmony_ci		regmap_write(map, addr + i,
5528c2ecf20Sopenharmony_ci			chip->pdata->config_data->cell_char_tbl[i]);
5538c2ecf20Sopenharmony_ci}
5548c2ecf20Sopenharmony_ci
5558c2ecf20Sopenharmony_cistatic inline void max17042_read_model_data(struct max17042_chip *chip,
5568c2ecf20Sopenharmony_ci					u8 addr, u16 *data, int size)
5578c2ecf20Sopenharmony_ci{
5588c2ecf20Sopenharmony_ci	struct regmap *map = chip->regmap;
5598c2ecf20Sopenharmony_ci	int i;
5608c2ecf20Sopenharmony_ci	u32 tmp;
5618c2ecf20Sopenharmony_ci
5628c2ecf20Sopenharmony_ci	for (i = 0; i < size; i++) {
5638c2ecf20Sopenharmony_ci		regmap_read(map, addr + i, &tmp);
5648c2ecf20Sopenharmony_ci		data[i] = (u16)tmp;
5658c2ecf20Sopenharmony_ci	}
5668c2ecf20Sopenharmony_ci}
5678c2ecf20Sopenharmony_ci
5688c2ecf20Sopenharmony_cistatic inline int max17042_model_data_compare(struct max17042_chip *chip,
5698c2ecf20Sopenharmony_ci					u16 *data1, u16 *data2, int size)
5708c2ecf20Sopenharmony_ci{
5718c2ecf20Sopenharmony_ci	int i;
5728c2ecf20Sopenharmony_ci
5738c2ecf20Sopenharmony_ci	if (memcmp(data1, data2, size)) {
5748c2ecf20Sopenharmony_ci		dev_err(&chip->client->dev, "%s compare failed\n", __func__);
5758c2ecf20Sopenharmony_ci		for (i = 0; i < size; i++)
5768c2ecf20Sopenharmony_ci			dev_info(&chip->client->dev, "0x%x, 0x%x",
5778c2ecf20Sopenharmony_ci				data1[i], data2[i]);
5788c2ecf20Sopenharmony_ci		dev_info(&chip->client->dev, "\n");
5798c2ecf20Sopenharmony_ci		return -EINVAL;
5808c2ecf20Sopenharmony_ci	}
5818c2ecf20Sopenharmony_ci	return 0;
5828c2ecf20Sopenharmony_ci}
5838c2ecf20Sopenharmony_ci
5848c2ecf20Sopenharmony_cistatic int max17042_init_model(struct max17042_chip *chip)
5858c2ecf20Sopenharmony_ci{
5868c2ecf20Sopenharmony_ci	int ret;
5878c2ecf20Sopenharmony_ci	int table_size = ARRAY_SIZE(chip->pdata->config_data->cell_char_tbl);
5888c2ecf20Sopenharmony_ci	u16 *temp_data;
5898c2ecf20Sopenharmony_ci
5908c2ecf20Sopenharmony_ci	temp_data = kcalloc(table_size, sizeof(*temp_data), GFP_KERNEL);
5918c2ecf20Sopenharmony_ci	if (!temp_data)
5928c2ecf20Sopenharmony_ci		return -ENOMEM;
5938c2ecf20Sopenharmony_ci
5948c2ecf20Sopenharmony_ci	max17042_unlock_model(chip);
5958c2ecf20Sopenharmony_ci	max17042_write_model_data(chip, MAX17042_MODELChrTbl,
5968c2ecf20Sopenharmony_ci				table_size);
5978c2ecf20Sopenharmony_ci	max17042_read_model_data(chip, MAX17042_MODELChrTbl, temp_data,
5988c2ecf20Sopenharmony_ci				table_size);
5998c2ecf20Sopenharmony_ci
6008c2ecf20Sopenharmony_ci	ret = max17042_model_data_compare(
6018c2ecf20Sopenharmony_ci		chip,
6028c2ecf20Sopenharmony_ci		chip->pdata->config_data->cell_char_tbl,
6038c2ecf20Sopenharmony_ci		temp_data,
6048c2ecf20Sopenharmony_ci		table_size);
6058c2ecf20Sopenharmony_ci
6068c2ecf20Sopenharmony_ci	max17042_lock_model(chip);
6078c2ecf20Sopenharmony_ci	kfree(temp_data);
6088c2ecf20Sopenharmony_ci
6098c2ecf20Sopenharmony_ci	return ret;
6108c2ecf20Sopenharmony_ci}
6118c2ecf20Sopenharmony_ci
6128c2ecf20Sopenharmony_cistatic int max17042_verify_model_lock(struct max17042_chip *chip)
6138c2ecf20Sopenharmony_ci{
6148c2ecf20Sopenharmony_ci	int i;
6158c2ecf20Sopenharmony_ci	int table_size = ARRAY_SIZE(chip->pdata->config_data->cell_char_tbl);
6168c2ecf20Sopenharmony_ci	u16 *temp_data;
6178c2ecf20Sopenharmony_ci	int ret = 0;
6188c2ecf20Sopenharmony_ci
6198c2ecf20Sopenharmony_ci	temp_data = kcalloc(table_size, sizeof(*temp_data), GFP_KERNEL);
6208c2ecf20Sopenharmony_ci	if (!temp_data)
6218c2ecf20Sopenharmony_ci		return -ENOMEM;
6228c2ecf20Sopenharmony_ci
6238c2ecf20Sopenharmony_ci	max17042_read_model_data(chip, MAX17042_MODELChrTbl, temp_data,
6248c2ecf20Sopenharmony_ci				table_size);
6258c2ecf20Sopenharmony_ci	for (i = 0; i < table_size; i++)
6268c2ecf20Sopenharmony_ci		if (temp_data[i])
6278c2ecf20Sopenharmony_ci			ret = -EINVAL;
6288c2ecf20Sopenharmony_ci
6298c2ecf20Sopenharmony_ci	kfree(temp_data);
6308c2ecf20Sopenharmony_ci	return ret;
6318c2ecf20Sopenharmony_ci}
6328c2ecf20Sopenharmony_ci
6338c2ecf20Sopenharmony_cistatic void max17042_write_config_regs(struct max17042_chip *chip)
6348c2ecf20Sopenharmony_ci{
6358c2ecf20Sopenharmony_ci	struct max17042_config_data *config = chip->pdata->config_data;
6368c2ecf20Sopenharmony_ci	struct regmap *map = chip->regmap;
6378c2ecf20Sopenharmony_ci
6388c2ecf20Sopenharmony_ci	regmap_write(map, MAX17042_CONFIG, config->config);
6398c2ecf20Sopenharmony_ci	regmap_write(map, MAX17042_LearnCFG, config->learn_cfg);
6408c2ecf20Sopenharmony_ci	regmap_write(map, MAX17042_FilterCFG,
6418c2ecf20Sopenharmony_ci			config->filter_cfg);
6428c2ecf20Sopenharmony_ci	regmap_write(map, MAX17042_RelaxCFG, config->relax_cfg);
6438c2ecf20Sopenharmony_ci	if (chip->chip_type == MAXIM_DEVICE_TYPE_MAX17047 ||
6448c2ecf20Sopenharmony_ci			chip->chip_type == MAXIM_DEVICE_TYPE_MAX17050 ||
6458c2ecf20Sopenharmony_ci			chip->chip_type == MAXIM_DEVICE_TYPE_MAX17055)
6468c2ecf20Sopenharmony_ci		regmap_write(map, MAX17047_FullSOCThr,
6478c2ecf20Sopenharmony_ci						config->full_soc_thresh);
6488c2ecf20Sopenharmony_ci}
6498c2ecf20Sopenharmony_ci
6508c2ecf20Sopenharmony_cistatic void  max17042_write_custom_regs(struct max17042_chip *chip)
6518c2ecf20Sopenharmony_ci{
6528c2ecf20Sopenharmony_ci	struct max17042_config_data *config = chip->pdata->config_data;
6538c2ecf20Sopenharmony_ci	struct regmap *map = chip->regmap;
6548c2ecf20Sopenharmony_ci
6558c2ecf20Sopenharmony_ci	max17042_write_verify_reg(map, MAX17042_RCOMP0, config->rcomp0);
6568c2ecf20Sopenharmony_ci	max17042_write_verify_reg(map, MAX17042_TempCo,	config->tcompc0);
6578c2ecf20Sopenharmony_ci	max17042_write_verify_reg(map, MAX17042_ICHGTerm, config->ichgt_term);
6588c2ecf20Sopenharmony_ci	if (chip->chip_type == MAXIM_DEVICE_TYPE_MAX17042) {
6598c2ecf20Sopenharmony_ci		regmap_write(map, MAX17042_EmptyTempCo,	config->empty_tempco);
6608c2ecf20Sopenharmony_ci		max17042_write_verify_reg(map, MAX17042_K_empty0,
6618c2ecf20Sopenharmony_ci					config->kempty0);
6628c2ecf20Sopenharmony_ci	} else {
6638c2ecf20Sopenharmony_ci		max17042_write_verify_reg(map, MAX17047_QRTbl00,
6648c2ecf20Sopenharmony_ci						config->qrtbl00);
6658c2ecf20Sopenharmony_ci		max17042_write_verify_reg(map, MAX17047_QRTbl10,
6668c2ecf20Sopenharmony_ci						config->qrtbl10);
6678c2ecf20Sopenharmony_ci		max17042_write_verify_reg(map, MAX17047_QRTbl20,
6688c2ecf20Sopenharmony_ci						config->qrtbl20);
6698c2ecf20Sopenharmony_ci		max17042_write_verify_reg(map, MAX17047_QRTbl30,
6708c2ecf20Sopenharmony_ci						config->qrtbl30);
6718c2ecf20Sopenharmony_ci	}
6728c2ecf20Sopenharmony_ci}
6738c2ecf20Sopenharmony_ci
6748c2ecf20Sopenharmony_cistatic void max17042_update_capacity_regs(struct max17042_chip *chip)
6758c2ecf20Sopenharmony_ci{
6768c2ecf20Sopenharmony_ci	struct max17042_config_data *config = chip->pdata->config_data;
6778c2ecf20Sopenharmony_ci	struct regmap *map = chip->regmap;
6788c2ecf20Sopenharmony_ci
6798c2ecf20Sopenharmony_ci	max17042_write_verify_reg(map, MAX17042_FullCAP,
6808c2ecf20Sopenharmony_ci				config->fullcap);
6818c2ecf20Sopenharmony_ci	regmap_write(map, MAX17042_DesignCap, config->design_cap);
6828c2ecf20Sopenharmony_ci	max17042_write_verify_reg(map, MAX17042_FullCAPNom,
6838c2ecf20Sopenharmony_ci				config->fullcapnom);
6848c2ecf20Sopenharmony_ci}
6858c2ecf20Sopenharmony_ci
6868c2ecf20Sopenharmony_cistatic void max17042_reset_vfsoc0_reg(struct max17042_chip *chip)
6878c2ecf20Sopenharmony_ci{
6888c2ecf20Sopenharmony_ci	unsigned int vfSoc;
6898c2ecf20Sopenharmony_ci	struct regmap *map = chip->regmap;
6908c2ecf20Sopenharmony_ci
6918c2ecf20Sopenharmony_ci	regmap_read(map, MAX17042_VFSOC, &vfSoc);
6928c2ecf20Sopenharmony_ci	regmap_write(map, MAX17042_VFSOC0Enable, VFSOC0_UNLOCK);
6938c2ecf20Sopenharmony_ci	max17042_write_verify_reg(map, MAX17042_VFSOC0, vfSoc);
6948c2ecf20Sopenharmony_ci	regmap_write(map, MAX17042_VFSOC0Enable, VFSOC0_LOCK);
6958c2ecf20Sopenharmony_ci}
6968c2ecf20Sopenharmony_ci
6978c2ecf20Sopenharmony_cistatic void max17042_load_new_capacity_params(struct max17042_chip *chip)
6988c2ecf20Sopenharmony_ci{
6998c2ecf20Sopenharmony_ci	u32 full_cap0, rep_cap, dq_acc, vfSoc;
7008c2ecf20Sopenharmony_ci	u32 rem_cap;
7018c2ecf20Sopenharmony_ci
7028c2ecf20Sopenharmony_ci	struct max17042_config_data *config = chip->pdata->config_data;
7038c2ecf20Sopenharmony_ci	struct regmap *map = chip->regmap;
7048c2ecf20Sopenharmony_ci
7058c2ecf20Sopenharmony_ci	regmap_read(map, MAX17042_FullCAP0, &full_cap0);
7068c2ecf20Sopenharmony_ci	regmap_read(map, MAX17042_VFSOC, &vfSoc);
7078c2ecf20Sopenharmony_ci
7088c2ecf20Sopenharmony_ci	/* fg_vfSoc needs to shifted by 8 bits to get the
7098c2ecf20Sopenharmony_ci	 * perc in 1% accuracy, to get the right rem_cap multiply
7108c2ecf20Sopenharmony_ci	 * full_cap0, fg_vfSoc and devide by 100
7118c2ecf20Sopenharmony_ci	 */
7128c2ecf20Sopenharmony_ci	rem_cap = ((vfSoc >> 8) * full_cap0) / 100;
7138c2ecf20Sopenharmony_ci	max17042_write_verify_reg(map, MAX17042_RemCap, rem_cap);
7148c2ecf20Sopenharmony_ci
7158c2ecf20Sopenharmony_ci	rep_cap = rem_cap;
7168c2ecf20Sopenharmony_ci	max17042_write_verify_reg(map, MAX17042_RepCap, rep_cap);
7178c2ecf20Sopenharmony_ci
7188c2ecf20Sopenharmony_ci	/* Write dQ_acc to 200% of Capacity and dP_acc to 200% */
7198c2ecf20Sopenharmony_ci	dq_acc = config->fullcap / dQ_ACC_DIV;
7208c2ecf20Sopenharmony_ci	max17042_write_verify_reg(map, MAX17042_dQacc, dq_acc);
7218c2ecf20Sopenharmony_ci	max17042_write_verify_reg(map, MAX17042_dPacc, dP_ACC_200);
7228c2ecf20Sopenharmony_ci
7238c2ecf20Sopenharmony_ci	max17042_write_verify_reg(map, MAX17042_FullCAP,
7248c2ecf20Sopenharmony_ci			config->fullcap);
7258c2ecf20Sopenharmony_ci	regmap_write(map, MAX17042_DesignCap,
7268c2ecf20Sopenharmony_ci			config->design_cap);
7278c2ecf20Sopenharmony_ci	max17042_write_verify_reg(map, MAX17042_FullCAPNom,
7288c2ecf20Sopenharmony_ci			config->fullcapnom);
7298c2ecf20Sopenharmony_ci	/* Update SOC register with new SOC */
7308c2ecf20Sopenharmony_ci	regmap_write(map, MAX17042_RepSOC, vfSoc);
7318c2ecf20Sopenharmony_ci}
7328c2ecf20Sopenharmony_ci
7338c2ecf20Sopenharmony_ci/*
7348c2ecf20Sopenharmony_ci * Block write all the override values coming from platform data.
7358c2ecf20Sopenharmony_ci * This function MUST be called before the POR initialization proceedure
7368c2ecf20Sopenharmony_ci * specified by maxim.
7378c2ecf20Sopenharmony_ci */
7388c2ecf20Sopenharmony_cistatic inline void max17042_override_por_values(struct max17042_chip *chip)
7398c2ecf20Sopenharmony_ci{
7408c2ecf20Sopenharmony_ci	struct regmap *map = chip->regmap;
7418c2ecf20Sopenharmony_ci	struct max17042_config_data *config = chip->pdata->config_data;
7428c2ecf20Sopenharmony_ci
7438c2ecf20Sopenharmony_ci	max17042_override_por(map, MAX17042_TGAIN, config->tgain);
7448c2ecf20Sopenharmony_ci	max17042_override_por(map, MAX17042_TOFF, config->toff);
7458c2ecf20Sopenharmony_ci	max17042_override_por(map, MAX17042_CGAIN, config->cgain);
7468c2ecf20Sopenharmony_ci	max17042_override_por(map, MAX17042_COFF, config->coff);
7478c2ecf20Sopenharmony_ci
7488c2ecf20Sopenharmony_ci	max17042_override_por(map, MAX17042_VALRT_Th, config->valrt_thresh);
7498c2ecf20Sopenharmony_ci	max17042_override_por(map, MAX17042_TALRT_Th, config->talrt_thresh);
7508c2ecf20Sopenharmony_ci	max17042_override_por(map, MAX17042_SALRT_Th,
7518c2ecf20Sopenharmony_ci						config->soc_alrt_thresh);
7528c2ecf20Sopenharmony_ci	max17042_override_por(map, MAX17042_CONFIG, config->config);
7538c2ecf20Sopenharmony_ci	max17042_override_por(map, MAX17042_SHDNTIMER, config->shdntimer);
7548c2ecf20Sopenharmony_ci
7558c2ecf20Sopenharmony_ci	max17042_override_por(map, MAX17042_DesignCap, config->design_cap);
7568c2ecf20Sopenharmony_ci	max17042_override_por(map, MAX17042_ICHGTerm, config->ichgt_term);
7578c2ecf20Sopenharmony_ci
7588c2ecf20Sopenharmony_ci	max17042_override_por(map, MAX17042_AtRate, config->at_rate);
7598c2ecf20Sopenharmony_ci	max17042_override_por(map, MAX17042_LearnCFG, config->learn_cfg);
7608c2ecf20Sopenharmony_ci	max17042_override_por(map, MAX17042_FilterCFG, config->filter_cfg);
7618c2ecf20Sopenharmony_ci	max17042_override_por(map, MAX17042_RelaxCFG, config->relax_cfg);
7628c2ecf20Sopenharmony_ci	max17042_override_por(map, MAX17042_MiscCFG, config->misc_cfg);
7638c2ecf20Sopenharmony_ci	max17042_override_por(map, MAX17042_MaskSOC, config->masksoc);
7648c2ecf20Sopenharmony_ci
7658c2ecf20Sopenharmony_ci	max17042_override_por(map, MAX17042_FullCAP, config->fullcap);
7668c2ecf20Sopenharmony_ci	max17042_override_por(map, MAX17042_FullCAPNom, config->fullcapnom);
7678c2ecf20Sopenharmony_ci	if (chip->chip_type == MAXIM_DEVICE_TYPE_MAX17042)
7688c2ecf20Sopenharmony_ci		max17042_override_por(map, MAX17042_SOC_empty,
7698c2ecf20Sopenharmony_ci						config->socempty);
7708c2ecf20Sopenharmony_ci	max17042_override_por(map, MAX17042_LAvg_empty, config->lavg_empty);
7718c2ecf20Sopenharmony_ci	max17042_override_por(map, MAX17042_dQacc, config->dqacc);
7728c2ecf20Sopenharmony_ci	max17042_override_por(map, MAX17042_dPacc, config->dpacc);
7738c2ecf20Sopenharmony_ci
7748c2ecf20Sopenharmony_ci	if (chip->chip_type == MAXIM_DEVICE_TYPE_MAX17042)
7758c2ecf20Sopenharmony_ci		max17042_override_por(map, MAX17042_V_empty, config->vempty);
7768c2ecf20Sopenharmony_ci	if (chip->chip_type == MAXIM_DEVICE_TYPE_MAX17055)
7778c2ecf20Sopenharmony_ci		max17042_override_por(map, MAX17055_V_empty, config->vempty);
7788c2ecf20Sopenharmony_ci	else
7798c2ecf20Sopenharmony_ci		max17042_override_por(map, MAX17047_V_empty, config->vempty);
7808c2ecf20Sopenharmony_ci	max17042_override_por(map, MAX17042_TempNom, config->temp_nom);
7818c2ecf20Sopenharmony_ci	max17042_override_por(map, MAX17042_TempLim, config->temp_lim);
7828c2ecf20Sopenharmony_ci	max17042_override_por(map, MAX17042_FCTC, config->fctc);
7838c2ecf20Sopenharmony_ci	max17042_override_por(map, MAX17042_RCOMP0, config->rcomp0);
7848c2ecf20Sopenharmony_ci	max17042_override_por(map, MAX17042_TempCo, config->tcompc0);
7858c2ecf20Sopenharmony_ci	if (chip->chip_type &&
7868c2ecf20Sopenharmony_ci	    ((chip->chip_type == MAXIM_DEVICE_TYPE_MAX17042) ||
7878c2ecf20Sopenharmony_ci	    (chip->chip_type == MAXIM_DEVICE_TYPE_MAX17047) ||
7888c2ecf20Sopenharmony_ci	    (chip->chip_type == MAXIM_DEVICE_TYPE_MAX17050))) {
7898c2ecf20Sopenharmony_ci		max17042_override_por(map, MAX17042_EmptyTempCo,
7908c2ecf20Sopenharmony_ci						config->empty_tempco);
7918c2ecf20Sopenharmony_ci		max17042_override_por(map, MAX17042_K_empty0,
7928c2ecf20Sopenharmony_ci						config->kempty0);
7938c2ecf20Sopenharmony_ci	}
7948c2ecf20Sopenharmony_ci}
7958c2ecf20Sopenharmony_ci
7968c2ecf20Sopenharmony_cistatic int max17042_init_chip(struct max17042_chip *chip)
7978c2ecf20Sopenharmony_ci{
7988c2ecf20Sopenharmony_ci	struct regmap *map = chip->regmap;
7998c2ecf20Sopenharmony_ci	int ret;
8008c2ecf20Sopenharmony_ci
8018c2ecf20Sopenharmony_ci	max17042_override_por_values(chip);
8028c2ecf20Sopenharmony_ci	/* After Power up, the MAX17042 requires 500mS in order
8038c2ecf20Sopenharmony_ci	 * to perform signal debouncing and initial SOC reporting
8048c2ecf20Sopenharmony_ci	 */
8058c2ecf20Sopenharmony_ci	msleep(500);
8068c2ecf20Sopenharmony_ci
8078c2ecf20Sopenharmony_ci	/* Initialize configaration */
8088c2ecf20Sopenharmony_ci	max17042_write_config_regs(chip);
8098c2ecf20Sopenharmony_ci
8108c2ecf20Sopenharmony_ci	/* write cell characterization data */
8118c2ecf20Sopenharmony_ci	ret = max17042_init_model(chip);
8128c2ecf20Sopenharmony_ci	if (ret) {
8138c2ecf20Sopenharmony_ci		dev_err(&chip->client->dev, "%s init failed\n",
8148c2ecf20Sopenharmony_ci			__func__);
8158c2ecf20Sopenharmony_ci		return -EIO;
8168c2ecf20Sopenharmony_ci	}
8178c2ecf20Sopenharmony_ci
8188c2ecf20Sopenharmony_ci	ret = max17042_verify_model_lock(chip);
8198c2ecf20Sopenharmony_ci	if (ret) {
8208c2ecf20Sopenharmony_ci		dev_err(&chip->client->dev, "%s lock verify failed\n",
8218c2ecf20Sopenharmony_ci			__func__);
8228c2ecf20Sopenharmony_ci		return -EIO;
8238c2ecf20Sopenharmony_ci	}
8248c2ecf20Sopenharmony_ci	/* write custom parameters */
8258c2ecf20Sopenharmony_ci	max17042_write_custom_regs(chip);
8268c2ecf20Sopenharmony_ci
8278c2ecf20Sopenharmony_ci	/* update capacity params */
8288c2ecf20Sopenharmony_ci	max17042_update_capacity_regs(chip);
8298c2ecf20Sopenharmony_ci
8308c2ecf20Sopenharmony_ci	/* delay must be atleast 350mS to allow VFSOC
8318c2ecf20Sopenharmony_ci	 * to be calculated from the new configuration
8328c2ecf20Sopenharmony_ci	 */
8338c2ecf20Sopenharmony_ci	msleep(350);
8348c2ecf20Sopenharmony_ci
8358c2ecf20Sopenharmony_ci	/* reset vfsoc0 reg */
8368c2ecf20Sopenharmony_ci	max17042_reset_vfsoc0_reg(chip);
8378c2ecf20Sopenharmony_ci
8388c2ecf20Sopenharmony_ci	/* load new capacity params */
8398c2ecf20Sopenharmony_ci	max17042_load_new_capacity_params(chip);
8408c2ecf20Sopenharmony_ci
8418c2ecf20Sopenharmony_ci	/* Init complete, Clear the POR bit */
8428c2ecf20Sopenharmony_ci	regmap_update_bits(map, MAX17042_STATUS, STATUS_POR_BIT, 0x0);
8438c2ecf20Sopenharmony_ci	return 0;
8448c2ecf20Sopenharmony_ci}
8458c2ecf20Sopenharmony_ci
8468c2ecf20Sopenharmony_cistatic void max17042_set_soc_threshold(struct max17042_chip *chip, u16 off)
8478c2ecf20Sopenharmony_ci{
8488c2ecf20Sopenharmony_ci	struct regmap *map = chip->regmap;
8498c2ecf20Sopenharmony_ci	u32 soc, soc_tr;
8508c2ecf20Sopenharmony_ci
8518c2ecf20Sopenharmony_ci	/* program interrupt thesholds such that we should
8528c2ecf20Sopenharmony_ci	 * get interrupt for every 'off' perc change in the soc
8538c2ecf20Sopenharmony_ci	 */
8548c2ecf20Sopenharmony_ci	regmap_read(map, MAX17042_RepSOC, &soc);
8558c2ecf20Sopenharmony_ci	soc >>= 8;
8568c2ecf20Sopenharmony_ci	soc_tr = (soc + off) << 8;
8578c2ecf20Sopenharmony_ci	if (off < soc)
8588c2ecf20Sopenharmony_ci		soc_tr |= soc - off;
8598c2ecf20Sopenharmony_ci	regmap_write(map, MAX17042_SALRT_Th, soc_tr);
8608c2ecf20Sopenharmony_ci}
8618c2ecf20Sopenharmony_ci
8628c2ecf20Sopenharmony_cistatic irqreturn_t max17042_thread_handler(int id, void *dev)
8638c2ecf20Sopenharmony_ci{
8648c2ecf20Sopenharmony_ci	struct max17042_chip *chip = dev;
8658c2ecf20Sopenharmony_ci	u32 val;
8668c2ecf20Sopenharmony_ci	int ret;
8678c2ecf20Sopenharmony_ci
8688c2ecf20Sopenharmony_ci	ret = regmap_read(chip->regmap, MAX17042_STATUS, &val);
8698c2ecf20Sopenharmony_ci	if (ret)
8708c2ecf20Sopenharmony_ci		return IRQ_HANDLED;
8718c2ecf20Sopenharmony_ci
8728c2ecf20Sopenharmony_ci	if ((val & STATUS_INTR_SOCMIN_BIT) ||
8738c2ecf20Sopenharmony_ci		(val & STATUS_INTR_SOCMAX_BIT)) {
8748c2ecf20Sopenharmony_ci		dev_info(&chip->client->dev, "SOC threshold INTR\n");
8758c2ecf20Sopenharmony_ci		max17042_set_soc_threshold(chip, 1);
8768c2ecf20Sopenharmony_ci	}
8778c2ecf20Sopenharmony_ci
8788c2ecf20Sopenharmony_ci	/* we implicitly handle all alerts via power_supply_changed */
8798c2ecf20Sopenharmony_ci	regmap_clear_bits(chip->regmap, MAX17042_STATUS,
8808c2ecf20Sopenharmony_ci			  0xFFFF & ~(STATUS_POR_BIT | STATUS_BST_BIT));
8818c2ecf20Sopenharmony_ci
8828c2ecf20Sopenharmony_ci	power_supply_changed(chip->battery);
8838c2ecf20Sopenharmony_ci	return IRQ_HANDLED;
8848c2ecf20Sopenharmony_ci}
8858c2ecf20Sopenharmony_ci
8868c2ecf20Sopenharmony_cistatic void max17042_init_worker(struct work_struct *work)
8878c2ecf20Sopenharmony_ci{
8888c2ecf20Sopenharmony_ci	struct max17042_chip *chip = container_of(work,
8898c2ecf20Sopenharmony_ci				struct max17042_chip, work);
8908c2ecf20Sopenharmony_ci	int ret;
8918c2ecf20Sopenharmony_ci
8928c2ecf20Sopenharmony_ci	/* Initialize registers according to values from the platform data */
8938c2ecf20Sopenharmony_ci	if (chip->pdata->enable_por_init && chip->pdata->config_data) {
8948c2ecf20Sopenharmony_ci		ret = max17042_init_chip(chip);
8958c2ecf20Sopenharmony_ci		if (ret)
8968c2ecf20Sopenharmony_ci			return;
8978c2ecf20Sopenharmony_ci	}
8988c2ecf20Sopenharmony_ci
8998c2ecf20Sopenharmony_ci	chip->init_complete = 1;
9008c2ecf20Sopenharmony_ci}
9018c2ecf20Sopenharmony_ci
9028c2ecf20Sopenharmony_ci#ifdef CONFIG_OF
9038c2ecf20Sopenharmony_cistatic struct max17042_platform_data *
9048c2ecf20Sopenharmony_cimax17042_get_of_pdata(struct max17042_chip *chip)
9058c2ecf20Sopenharmony_ci{
9068c2ecf20Sopenharmony_ci	struct device *dev = &chip->client->dev;
9078c2ecf20Sopenharmony_ci	struct device_node *np = dev->of_node;
9088c2ecf20Sopenharmony_ci	u32 prop;
9098c2ecf20Sopenharmony_ci	struct max17042_platform_data *pdata;
9108c2ecf20Sopenharmony_ci
9118c2ecf20Sopenharmony_ci	pdata = devm_kzalloc(dev, sizeof(*pdata), GFP_KERNEL);
9128c2ecf20Sopenharmony_ci	if (!pdata)
9138c2ecf20Sopenharmony_ci		return NULL;
9148c2ecf20Sopenharmony_ci
9158c2ecf20Sopenharmony_ci	/*
9168c2ecf20Sopenharmony_ci	 * Require current sense resistor value to be specified for
9178c2ecf20Sopenharmony_ci	 * current-sense functionality to be enabled at all.
9188c2ecf20Sopenharmony_ci	 */
9198c2ecf20Sopenharmony_ci	if (of_property_read_u32(np, "maxim,rsns-microohm", &prop) == 0) {
9208c2ecf20Sopenharmony_ci		pdata->r_sns = prop;
9218c2ecf20Sopenharmony_ci		pdata->enable_current_sense = true;
9228c2ecf20Sopenharmony_ci	}
9238c2ecf20Sopenharmony_ci
9248c2ecf20Sopenharmony_ci	if (of_property_read_s32(np, "maxim,cold-temp", &pdata->temp_min))
9258c2ecf20Sopenharmony_ci		pdata->temp_min = INT_MIN;
9268c2ecf20Sopenharmony_ci	if (of_property_read_s32(np, "maxim,over-heat-temp", &pdata->temp_max))
9278c2ecf20Sopenharmony_ci		pdata->temp_max = INT_MAX;
9288c2ecf20Sopenharmony_ci	if (of_property_read_s32(np, "maxim,dead-volt", &pdata->vmin))
9298c2ecf20Sopenharmony_ci		pdata->vmin = INT_MIN;
9308c2ecf20Sopenharmony_ci	if (of_property_read_s32(np, "maxim,over-volt", &pdata->vmax))
9318c2ecf20Sopenharmony_ci		pdata->vmax = INT_MAX;
9328c2ecf20Sopenharmony_ci
9338c2ecf20Sopenharmony_ci	return pdata;
9348c2ecf20Sopenharmony_ci}
9358c2ecf20Sopenharmony_ci#endif
9368c2ecf20Sopenharmony_ci
9378c2ecf20Sopenharmony_cistatic struct max17042_reg_data max17047_default_pdata_init_regs[] = {
9388c2ecf20Sopenharmony_ci	/*
9398c2ecf20Sopenharmony_ci	 * Some firmwares do not set FullSOCThr, Enable End-of-Charge Detection
9408c2ecf20Sopenharmony_ci	 * when the voltage FG reports 95%, as recommended in the datasheet.
9418c2ecf20Sopenharmony_ci	 */
9428c2ecf20Sopenharmony_ci	{ MAX17047_FullSOCThr, MAX17042_BATTERY_FULL << 8 },
9438c2ecf20Sopenharmony_ci};
9448c2ecf20Sopenharmony_ci
9458c2ecf20Sopenharmony_cistatic struct max17042_platform_data *
9468c2ecf20Sopenharmony_cimax17042_get_default_pdata(struct max17042_chip *chip)
9478c2ecf20Sopenharmony_ci{
9488c2ecf20Sopenharmony_ci	struct device *dev = &chip->client->dev;
9498c2ecf20Sopenharmony_ci	struct max17042_platform_data *pdata;
9508c2ecf20Sopenharmony_ci	int ret, misc_cfg;
9518c2ecf20Sopenharmony_ci
9528c2ecf20Sopenharmony_ci	/*
9538c2ecf20Sopenharmony_ci	 * The MAX17047 gets used on x86 where we might not have pdata, assume
9548c2ecf20Sopenharmony_ci	 * the firmware will already have initialized the fuel-gauge and provide
9558c2ecf20Sopenharmony_ci	 * default values for the non init bits to make things work.
9568c2ecf20Sopenharmony_ci	 */
9578c2ecf20Sopenharmony_ci	pdata = devm_kzalloc(dev, sizeof(*pdata), GFP_KERNEL);
9588c2ecf20Sopenharmony_ci	if (!pdata)
9598c2ecf20Sopenharmony_ci		return pdata;
9608c2ecf20Sopenharmony_ci
9618c2ecf20Sopenharmony_ci	if ((chip->chip_type == MAXIM_DEVICE_TYPE_MAX17047) ||
9628c2ecf20Sopenharmony_ci	    (chip->chip_type == MAXIM_DEVICE_TYPE_MAX17050)) {
9638c2ecf20Sopenharmony_ci		pdata->init_data = max17047_default_pdata_init_regs;
9648c2ecf20Sopenharmony_ci		pdata->num_init_data =
9658c2ecf20Sopenharmony_ci			ARRAY_SIZE(max17047_default_pdata_init_regs);
9668c2ecf20Sopenharmony_ci	}
9678c2ecf20Sopenharmony_ci
9688c2ecf20Sopenharmony_ci	ret = regmap_read(chip->regmap, MAX17042_MiscCFG, &misc_cfg);
9698c2ecf20Sopenharmony_ci	if (ret < 0)
9708c2ecf20Sopenharmony_ci		return NULL;
9718c2ecf20Sopenharmony_ci
9728c2ecf20Sopenharmony_ci	/* If bits 0-1 are set to 3 then only Voltage readings are used */
9738c2ecf20Sopenharmony_ci	if ((misc_cfg & 0x3) == 0x3)
9748c2ecf20Sopenharmony_ci		pdata->enable_current_sense = false;
9758c2ecf20Sopenharmony_ci	else
9768c2ecf20Sopenharmony_ci		pdata->enable_current_sense = true;
9778c2ecf20Sopenharmony_ci
9788c2ecf20Sopenharmony_ci	pdata->vmin = MAX17042_DEFAULT_VMIN;
9798c2ecf20Sopenharmony_ci	pdata->vmax = MAX17042_DEFAULT_VMAX;
9808c2ecf20Sopenharmony_ci	pdata->temp_min = MAX17042_DEFAULT_TEMP_MIN;
9818c2ecf20Sopenharmony_ci	pdata->temp_max = MAX17042_DEFAULT_TEMP_MAX;
9828c2ecf20Sopenharmony_ci
9838c2ecf20Sopenharmony_ci	return pdata;
9848c2ecf20Sopenharmony_ci}
9858c2ecf20Sopenharmony_ci
9868c2ecf20Sopenharmony_cistatic struct max17042_platform_data *
9878c2ecf20Sopenharmony_cimax17042_get_pdata(struct max17042_chip *chip)
9888c2ecf20Sopenharmony_ci{
9898c2ecf20Sopenharmony_ci	struct device *dev = &chip->client->dev;
9908c2ecf20Sopenharmony_ci
9918c2ecf20Sopenharmony_ci#ifdef CONFIG_OF
9928c2ecf20Sopenharmony_ci	if (dev->of_node)
9938c2ecf20Sopenharmony_ci		return max17042_get_of_pdata(chip);
9948c2ecf20Sopenharmony_ci#endif
9958c2ecf20Sopenharmony_ci	if (dev->platform_data)
9968c2ecf20Sopenharmony_ci		return dev->platform_data;
9978c2ecf20Sopenharmony_ci
9988c2ecf20Sopenharmony_ci	return max17042_get_default_pdata(chip);
9998c2ecf20Sopenharmony_ci}
10008c2ecf20Sopenharmony_ci
10018c2ecf20Sopenharmony_cistatic const struct regmap_config max17042_regmap_config = {
10028c2ecf20Sopenharmony_ci	.reg_bits = 8,
10038c2ecf20Sopenharmony_ci	.val_bits = 16,
10048c2ecf20Sopenharmony_ci	.val_format_endian = REGMAP_ENDIAN_NATIVE,
10058c2ecf20Sopenharmony_ci};
10068c2ecf20Sopenharmony_ci
10078c2ecf20Sopenharmony_cistatic const struct power_supply_desc max17042_psy_desc = {
10088c2ecf20Sopenharmony_ci	.name		= "max170xx_battery",
10098c2ecf20Sopenharmony_ci	.type		= POWER_SUPPLY_TYPE_BATTERY,
10108c2ecf20Sopenharmony_ci	.get_property	= max17042_get_property,
10118c2ecf20Sopenharmony_ci	.set_property	= max17042_set_property,
10128c2ecf20Sopenharmony_ci	.property_is_writeable	= max17042_property_is_writeable,
10138c2ecf20Sopenharmony_ci	.external_power_changed	= max17042_external_power_changed,
10148c2ecf20Sopenharmony_ci	.properties	= max17042_battery_props,
10158c2ecf20Sopenharmony_ci	.num_properties	= ARRAY_SIZE(max17042_battery_props),
10168c2ecf20Sopenharmony_ci};
10178c2ecf20Sopenharmony_ci
10188c2ecf20Sopenharmony_cistatic const struct power_supply_desc max17042_no_current_sense_psy_desc = {
10198c2ecf20Sopenharmony_ci	.name		= "max170xx_battery",
10208c2ecf20Sopenharmony_ci	.type		= POWER_SUPPLY_TYPE_BATTERY,
10218c2ecf20Sopenharmony_ci	.get_property	= max17042_get_property,
10228c2ecf20Sopenharmony_ci	.set_property	= max17042_set_property,
10238c2ecf20Sopenharmony_ci	.property_is_writeable	= max17042_property_is_writeable,
10248c2ecf20Sopenharmony_ci	.properties	= max17042_battery_props,
10258c2ecf20Sopenharmony_ci	.num_properties	= ARRAY_SIZE(max17042_battery_props) - 2,
10268c2ecf20Sopenharmony_ci};
10278c2ecf20Sopenharmony_ci
10288c2ecf20Sopenharmony_cistatic void max17042_stop_work(void *data)
10298c2ecf20Sopenharmony_ci{
10308c2ecf20Sopenharmony_ci	struct max17042_chip *chip = data;
10318c2ecf20Sopenharmony_ci
10328c2ecf20Sopenharmony_ci	cancel_work_sync(&chip->work);
10338c2ecf20Sopenharmony_ci}
10348c2ecf20Sopenharmony_ci
10358c2ecf20Sopenharmony_cistatic int max17042_probe(struct i2c_client *client,
10368c2ecf20Sopenharmony_ci			const struct i2c_device_id *id)
10378c2ecf20Sopenharmony_ci{
10388c2ecf20Sopenharmony_ci	struct i2c_adapter *adapter = client->adapter;
10398c2ecf20Sopenharmony_ci	const struct power_supply_desc *max17042_desc = &max17042_psy_desc;
10408c2ecf20Sopenharmony_ci	struct power_supply_config psy_cfg = {};
10418c2ecf20Sopenharmony_ci	const struct acpi_device_id *acpi_id = NULL;
10428c2ecf20Sopenharmony_ci	struct device *dev = &client->dev;
10438c2ecf20Sopenharmony_ci	struct max17042_chip *chip;
10448c2ecf20Sopenharmony_ci	int ret;
10458c2ecf20Sopenharmony_ci	int i;
10468c2ecf20Sopenharmony_ci	u32 val;
10478c2ecf20Sopenharmony_ci
10488c2ecf20Sopenharmony_ci	if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_WORD_DATA))
10498c2ecf20Sopenharmony_ci		return -EIO;
10508c2ecf20Sopenharmony_ci
10518c2ecf20Sopenharmony_ci	chip = devm_kzalloc(&client->dev, sizeof(*chip), GFP_KERNEL);
10528c2ecf20Sopenharmony_ci	if (!chip)
10538c2ecf20Sopenharmony_ci		return -ENOMEM;
10548c2ecf20Sopenharmony_ci
10558c2ecf20Sopenharmony_ci	chip->client = client;
10568c2ecf20Sopenharmony_ci	if (id) {
10578c2ecf20Sopenharmony_ci		chip->chip_type = id->driver_data;
10588c2ecf20Sopenharmony_ci	} else {
10598c2ecf20Sopenharmony_ci		acpi_id = acpi_match_device(dev->driver->acpi_match_table, dev);
10608c2ecf20Sopenharmony_ci		if (!acpi_id)
10618c2ecf20Sopenharmony_ci			return -ENODEV;
10628c2ecf20Sopenharmony_ci
10638c2ecf20Sopenharmony_ci		chip->chip_type = acpi_id->driver_data;
10648c2ecf20Sopenharmony_ci	}
10658c2ecf20Sopenharmony_ci	chip->regmap = devm_regmap_init_i2c(client, &max17042_regmap_config);
10668c2ecf20Sopenharmony_ci	if (IS_ERR(chip->regmap)) {
10678c2ecf20Sopenharmony_ci		dev_err(&client->dev, "Failed to initialize regmap\n");
10688c2ecf20Sopenharmony_ci		return -EINVAL;
10698c2ecf20Sopenharmony_ci	}
10708c2ecf20Sopenharmony_ci
10718c2ecf20Sopenharmony_ci	chip->pdata = max17042_get_pdata(chip);
10728c2ecf20Sopenharmony_ci	if (!chip->pdata) {
10738c2ecf20Sopenharmony_ci		dev_err(&client->dev, "no platform data provided\n");
10748c2ecf20Sopenharmony_ci		return -EINVAL;
10758c2ecf20Sopenharmony_ci	}
10768c2ecf20Sopenharmony_ci
10778c2ecf20Sopenharmony_ci	i2c_set_clientdata(client, chip);
10788c2ecf20Sopenharmony_ci	psy_cfg.drv_data = chip;
10798c2ecf20Sopenharmony_ci	psy_cfg.of_node = dev->of_node;
10808c2ecf20Sopenharmony_ci
10818c2ecf20Sopenharmony_ci	/* When current is not measured,
10828c2ecf20Sopenharmony_ci	 * CURRENT_NOW and CURRENT_AVG properties should be invisible. */
10838c2ecf20Sopenharmony_ci	if (!chip->pdata->enable_current_sense)
10848c2ecf20Sopenharmony_ci		max17042_desc = &max17042_no_current_sense_psy_desc;
10858c2ecf20Sopenharmony_ci
10868c2ecf20Sopenharmony_ci	if (chip->pdata->r_sns == 0)
10878c2ecf20Sopenharmony_ci		chip->pdata->r_sns = MAX17042_DEFAULT_SNS_RESISTOR;
10888c2ecf20Sopenharmony_ci
10898c2ecf20Sopenharmony_ci	if (chip->pdata->init_data)
10908c2ecf20Sopenharmony_ci		for (i = 0; i < chip->pdata->num_init_data; i++)
10918c2ecf20Sopenharmony_ci			regmap_write(chip->regmap,
10928c2ecf20Sopenharmony_ci					chip->pdata->init_data[i].addr,
10938c2ecf20Sopenharmony_ci					chip->pdata->init_data[i].data);
10948c2ecf20Sopenharmony_ci
10958c2ecf20Sopenharmony_ci	if (!chip->pdata->enable_current_sense) {
10968c2ecf20Sopenharmony_ci		regmap_write(chip->regmap, MAX17042_CGAIN, 0x0000);
10978c2ecf20Sopenharmony_ci		regmap_write(chip->regmap, MAX17042_MiscCFG, 0x0003);
10988c2ecf20Sopenharmony_ci		regmap_write(chip->regmap, MAX17042_LearnCFG, 0x0007);
10998c2ecf20Sopenharmony_ci	}
11008c2ecf20Sopenharmony_ci
11018c2ecf20Sopenharmony_ci	chip->battery = devm_power_supply_register(&client->dev, max17042_desc,
11028c2ecf20Sopenharmony_ci						   &psy_cfg);
11038c2ecf20Sopenharmony_ci	if (IS_ERR(chip->battery)) {
11048c2ecf20Sopenharmony_ci		dev_err(&client->dev, "failed: power supply register\n");
11058c2ecf20Sopenharmony_ci		return PTR_ERR(chip->battery);
11068c2ecf20Sopenharmony_ci	}
11078c2ecf20Sopenharmony_ci
11088c2ecf20Sopenharmony_ci	if (client->irq) {
11098c2ecf20Sopenharmony_ci		unsigned int flags = IRQF_ONESHOT;
11108c2ecf20Sopenharmony_ci
11118c2ecf20Sopenharmony_ci		/*
11128c2ecf20Sopenharmony_ci		 * On ACPI systems the IRQ may be handled by ACPI-event code,
11138c2ecf20Sopenharmony_ci		 * so we need to share (if the ACPI code is willing to share).
11148c2ecf20Sopenharmony_ci		 */
11158c2ecf20Sopenharmony_ci		if (acpi_id)
11168c2ecf20Sopenharmony_ci			flags |= IRQF_SHARED | IRQF_PROBE_SHARED;
11178c2ecf20Sopenharmony_ci
11188c2ecf20Sopenharmony_ci		ret = devm_request_threaded_irq(&client->dev, client->irq,
11198c2ecf20Sopenharmony_ci						NULL,
11208c2ecf20Sopenharmony_ci						max17042_thread_handler, flags,
11218c2ecf20Sopenharmony_ci						chip->battery->desc->name,
11228c2ecf20Sopenharmony_ci						chip);
11238c2ecf20Sopenharmony_ci		if (!ret) {
11248c2ecf20Sopenharmony_ci			regmap_update_bits(chip->regmap, MAX17042_CONFIG,
11258c2ecf20Sopenharmony_ci					CONFIG_ALRT_BIT_ENBL,
11268c2ecf20Sopenharmony_ci					CONFIG_ALRT_BIT_ENBL);
11278c2ecf20Sopenharmony_ci			max17042_set_soc_threshold(chip, 1);
11288c2ecf20Sopenharmony_ci		} else {
11298c2ecf20Sopenharmony_ci			client->irq = 0;
11308c2ecf20Sopenharmony_ci			if (ret != -EBUSY)
11318c2ecf20Sopenharmony_ci				dev_err(&client->dev, "Failed to get IRQ\n");
11328c2ecf20Sopenharmony_ci		}
11338c2ecf20Sopenharmony_ci	}
11348c2ecf20Sopenharmony_ci	/* Not able to update the charge threshold when exceeded? -> disable */
11358c2ecf20Sopenharmony_ci	if (!client->irq)
11368c2ecf20Sopenharmony_ci		regmap_write(chip->regmap, MAX17042_SALRT_Th, 0xff00);
11378c2ecf20Sopenharmony_ci
11388c2ecf20Sopenharmony_ci	regmap_read(chip->regmap, MAX17042_STATUS, &val);
11398c2ecf20Sopenharmony_ci	if (val & STATUS_POR_BIT) {
11408c2ecf20Sopenharmony_ci		INIT_WORK(&chip->work, max17042_init_worker);
11418c2ecf20Sopenharmony_ci		ret = devm_add_action(&client->dev, max17042_stop_work, chip);
11428c2ecf20Sopenharmony_ci		if (ret)
11438c2ecf20Sopenharmony_ci			return ret;
11448c2ecf20Sopenharmony_ci		schedule_work(&chip->work);
11458c2ecf20Sopenharmony_ci	} else {
11468c2ecf20Sopenharmony_ci		chip->init_complete = 1;
11478c2ecf20Sopenharmony_ci	}
11488c2ecf20Sopenharmony_ci
11498c2ecf20Sopenharmony_ci	return 0;
11508c2ecf20Sopenharmony_ci}
11518c2ecf20Sopenharmony_ci
11528c2ecf20Sopenharmony_ci#ifdef CONFIG_PM_SLEEP
11538c2ecf20Sopenharmony_cistatic int max17042_suspend(struct device *dev)
11548c2ecf20Sopenharmony_ci{
11558c2ecf20Sopenharmony_ci	struct max17042_chip *chip = dev_get_drvdata(dev);
11568c2ecf20Sopenharmony_ci
11578c2ecf20Sopenharmony_ci	/*
11588c2ecf20Sopenharmony_ci	 * disable the irq and enable irq_wake
11598c2ecf20Sopenharmony_ci	 * capability to the interrupt line.
11608c2ecf20Sopenharmony_ci	 */
11618c2ecf20Sopenharmony_ci	if (chip->client->irq) {
11628c2ecf20Sopenharmony_ci		disable_irq(chip->client->irq);
11638c2ecf20Sopenharmony_ci		enable_irq_wake(chip->client->irq);
11648c2ecf20Sopenharmony_ci	}
11658c2ecf20Sopenharmony_ci
11668c2ecf20Sopenharmony_ci	return 0;
11678c2ecf20Sopenharmony_ci}
11688c2ecf20Sopenharmony_ci
11698c2ecf20Sopenharmony_cistatic int max17042_resume(struct device *dev)
11708c2ecf20Sopenharmony_ci{
11718c2ecf20Sopenharmony_ci	struct max17042_chip *chip = dev_get_drvdata(dev);
11728c2ecf20Sopenharmony_ci
11738c2ecf20Sopenharmony_ci	if (chip->client->irq) {
11748c2ecf20Sopenharmony_ci		disable_irq_wake(chip->client->irq);
11758c2ecf20Sopenharmony_ci		enable_irq(chip->client->irq);
11768c2ecf20Sopenharmony_ci		/* re-program the SOC thresholds to 1% change */
11778c2ecf20Sopenharmony_ci		max17042_set_soc_threshold(chip, 1);
11788c2ecf20Sopenharmony_ci	}
11798c2ecf20Sopenharmony_ci
11808c2ecf20Sopenharmony_ci	return 0;
11818c2ecf20Sopenharmony_ci}
11828c2ecf20Sopenharmony_ci#endif
11838c2ecf20Sopenharmony_ci
11848c2ecf20Sopenharmony_cistatic SIMPLE_DEV_PM_OPS(max17042_pm_ops, max17042_suspend,
11858c2ecf20Sopenharmony_ci			max17042_resume);
11868c2ecf20Sopenharmony_ci
11878c2ecf20Sopenharmony_ci#ifdef CONFIG_ACPI
11888c2ecf20Sopenharmony_cistatic const struct acpi_device_id max17042_acpi_match[] = {
11898c2ecf20Sopenharmony_ci	{ "MAX17047", MAXIM_DEVICE_TYPE_MAX17047 },
11908c2ecf20Sopenharmony_ci	{ }
11918c2ecf20Sopenharmony_ci};
11928c2ecf20Sopenharmony_ciMODULE_DEVICE_TABLE(acpi, max17042_acpi_match);
11938c2ecf20Sopenharmony_ci#endif
11948c2ecf20Sopenharmony_ci
11958c2ecf20Sopenharmony_ci#ifdef CONFIG_OF
11968c2ecf20Sopenharmony_cistatic const struct of_device_id max17042_dt_match[] = {
11978c2ecf20Sopenharmony_ci	{ .compatible = "maxim,max17042" },
11988c2ecf20Sopenharmony_ci	{ .compatible = "maxim,max17047" },
11998c2ecf20Sopenharmony_ci	{ .compatible = "maxim,max17050" },
12008c2ecf20Sopenharmony_ci	{ .compatible = "maxim,max17055" },
12018c2ecf20Sopenharmony_ci	{ },
12028c2ecf20Sopenharmony_ci};
12038c2ecf20Sopenharmony_ciMODULE_DEVICE_TABLE(of, max17042_dt_match);
12048c2ecf20Sopenharmony_ci#endif
12058c2ecf20Sopenharmony_ci
12068c2ecf20Sopenharmony_cistatic const struct i2c_device_id max17042_id[] = {
12078c2ecf20Sopenharmony_ci	{ "max17042", MAXIM_DEVICE_TYPE_MAX17042 },
12088c2ecf20Sopenharmony_ci	{ "max17047", MAXIM_DEVICE_TYPE_MAX17047 },
12098c2ecf20Sopenharmony_ci	{ "max17050", MAXIM_DEVICE_TYPE_MAX17050 },
12108c2ecf20Sopenharmony_ci	{ "max17055", MAXIM_DEVICE_TYPE_MAX17055 },
12118c2ecf20Sopenharmony_ci	{ }
12128c2ecf20Sopenharmony_ci};
12138c2ecf20Sopenharmony_ciMODULE_DEVICE_TABLE(i2c, max17042_id);
12148c2ecf20Sopenharmony_ci
12158c2ecf20Sopenharmony_cistatic struct i2c_driver max17042_i2c_driver = {
12168c2ecf20Sopenharmony_ci	.driver	= {
12178c2ecf20Sopenharmony_ci		.name	= "max17042",
12188c2ecf20Sopenharmony_ci		.acpi_match_table = ACPI_PTR(max17042_acpi_match),
12198c2ecf20Sopenharmony_ci		.of_match_table = of_match_ptr(max17042_dt_match),
12208c2ecf20Sopenharmony_ci		.pm	= &max17042_pm_ops,
12218c2ecf20Sopenharmony_ci	},
12228c2ecf20Sopenharmony_ci	.probe		= max17042_probe,
12238c2ecf20Sopenharmony_ci	.id_table	= max17042_id,
12248c2ecf20Sopenharmony_ci};
12258c2ecf20Sopenharmony_cimodule_i2c_driver(max17042_i2c_driver);
12268c2ecf20Sopenharmony_ci
12278c2ecf20Sopenharmony_ciMODULE_AUTHOR("MyungJoo Ham <myungjoo.ham@samsung.com>");
12288c2ecf20Sopenharmony_ciMODULE_DESCRIPTION("MAX17042 Fuel Gauge");
12298c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL");
1230