xref: /linux/drivers/power/supply/max17042_battery.c (revision e21162029a57d3fe657e1eae12283702360cd5c5)
18c0984e5SSebastian Reichel /*
28c0984e5SSebastian Reichel  * Fuel gauge driver for Maxim 17042 / 8966 / 8997
38c0984e5SSebastian Reichel  *  Note that Maxim 8966 and 8997 are mfd and this is its subdevice.
48c0984e5SSebastian Reichel  *
58c0984e5SSebastian Reichel  * Copyright (C) 2011 Samsung Electronics
68c0984e5SSebastian Reichel  * MyungJoo Ham <myungjoo.ham@samsung.com>
78c0984e5SSebastian Reichel  *
88c0984e5SSebastian Reichel  * This program is free software; you can redistribute it and/or modify
98c0984e5SSebastian Reichel  * it under the terms of the GNU General Public License as published by
108c0984e5SSebastian Reichel  * the Free Software Foundation; either version 2 of the License, or
118c0984e5SSebastian Reichel  * (at your option) any later version.
128c0984e5SSebastian Reichel  *
138c0984e5SSebastian Reichel  * This program is distributed in the hope that it will be useful,
148c0984e5SSebastian Reichel  * but WITHOUT ANY WARRANTY; without even the implied warranty of
158c0984e5SSebastian Reichel  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
168c0984e5SSebastian Reichel  * GNU General Public License for more details.
178c0984e5SSebastian Reichel  *
188c0984e5SSebastian Reichel  * You should have received a copy of the GNU General Public License
198c0984e5SSebastian Reichel  * along with this program; if not, write to the Free Software
208c0984e5SSebastian Reichel  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
218c0984e5SSebastian Reichel  *
228c0984e5SSebastian Reichel  * This driver is based on max17040_battery.c
238c0984e5SSebastian Reichel  */
248c0984e5SSebastian Reichel 
25*e2116202SHans de Goede #include <linux/acpi.h>
268c0984e5SSebastian Reichel #include <linux/init.h>
278c0984e5SSebastian Reichel #include <linux/module.h>
288c0984e5SSebastian Reichel #include <linux/slab.h>
298c0984e5SSebastian Reichel #include <linux/i2c.h>
308c0984e5SSebastian Reichel #include <linux/delay.h>
318c0984e5SSebastian Reichel #include <linux/interrupt.h>
328c0984e5SSebastian Reichel #include <linux/pm.h>
338c0984e5SSebastian Reichel #include <linux/mod_devicetable.h>
348c0984e5SSebastian Reichel #include <linux/power_supply.h>
358c0984e5SSebastian Reichel #include <linux/power/max17042_battery.h>
368c0984e5SSebastian Reichel #include <linux/of.h>
378c0984e5SSebastian Reichel #include <linux/regmap.h>
388c0984e5SSebastian Reichel 
398c0984e5SSebastian Reichel /* Status register bits */
408c0984e5SSebastian Reichel #define STATUS_POR_BIT         (1 << 1)
418c0984e5SSebastian Reichel #define STATUS_BST_BIT         (1 << 3)
428c0984e5SSebastian Reichel #define STATUS_VMN_BIT         (1 << 8)
438c0984e5SSebastian Reichel #define STATUS_TMN_BIT         (1 << 9)
448c0984e5SSebastian Reichel #define STATUS_SMN_BIT         (1 << 10)
458c0984e5SSebastian Reichel #define STATUS_BI_BIT          (1 << 11)
468c0984e5SSebastian Reichel #define STATUS_VMX_BIT         (1 << 12)
478c0984e5SSebastian Reichel #define STATUS_TMX_BIT         (1 << 13)
488c0984e5SSebastian Reichel #define STATUS_SMX_BIT         (1 << 14)
498c0984e5SSebastian Reichel #define STATUS_BR_BIT          (1 << 15)
508c0984e5SSebastian Reichel 
518c0984e5SSebastian Reichel /* Interrupt mask bits */
528c0984e5SSebastian Reichel #define CONFIG_ALRT_BIT_ENBL	(1 << 2)
538c0984e5SSebastian Reichel #define STATUS_INTR_SOCMIN_BIT	(1 << 10)
548c0984e5SSebastian Reichel #define STATUS_INTR_SOCMAX_BIT	(1 << 14)
558c0984e5SSebastian Reichel 
568c0984e5SSebastian Reichel #define VFSOC0_LOCK		0x0000
578c0984e5SSebastian Reichel #define VFSOC0_UNLOCK		0x0080
588c0984e5SSebastian Reichel #define MODEL_UNLOCK1	0X0059
598c0984e5SSebastian Reichel #define MODEL_UNLOCK2	0X00C4
608c0984e5SSebastian Reichel #define MODEL_LOCK1		0X0000
618c0984e5SSebastian Reichel #define MODEL_LOCK2		0X0000
628c0984e5SSebastian Reichel 
638c0984e5SSebastian Reichel #define dQ_ACC_DIV	0x4
648c0984e5SSebastian Reichel #define dP_ACC_100	0x1900
658c0984e5SSebastian Reichel #define dP_ACC_200	0x3200
668c0984e5SSebastian Reichel 
678c0984e5SSebastian Reichel #define MAX17042_VMAX_TOLERANCE		50 /* 50 mV */
688c0984e5SSebastian Reichel 
698c0984e5SSebastian Reichel struct max17042_chip {
708c0984e5SSebastian Reichel 	struct i2c_client *client;
718c0984e5SSebastian Reichel 	struct regmap *regmap;
728c0984e5SSebastian Reichel 	struct power_supply *battery;
738c0984e5SSebastian Reichel 	enum max170xx_chip_type chip_type;
748c0984e5SSebastian Reichel 	struct max17042_platform_data *pdata;
758c0984e5SSebastian Reichel 	struct work_struct work;
768c0984e5SSebastian Reichel 	int    init_complete;
778c0984e5SSebastian Reichel };
788c0984e5SSebastian Reichel 
798c0984e5SSebastian Reichel static enum power_supply_property max17042_battery_props[] = {
80a9df22c0SHans de Goede 	POWER_SUPPLY_PROP_STATUS,
818c0984e5SSebastian Reichel 	POWER_SUPPLY_PROP_PRESENT,
82ef7fcdaeSHans de Goede 	POWER_SUPPLY_PROP_TECHNOLOGY,
838c0984e5SSebastian Reichel 	POWER_SUPPLY_PROP_CYCLE_COUNT,
848c0984e5SSebastian Reichel 	POWER_SUPPLY_PROP_VOLTAGE_MAX,
857bfc9397SHans de Goede 	POWER_SUPPLY_PROP_VOLTAGE_MIN,
868c0984e5SSebastian Reichel 	POWER_SUPPLY_PROP_VOLTAGE_MIN_DESIGN,
878c0984e5SSebastian Reichel 	POWER_SUPPLY_PROP_VOLTAGE_NOW,
888c0984e5SSebastian Reichel 	POWER_SUPPLY_PROP_VOLTAGE_AVG,
898c0984e5SSebastian Reichel 	POWER_SUPPLY_PROP_VOLTAGE_OCV,
908c0984e5SSebastian Reichel 	POWER_SUPPLY_PROP_CAPACITY,
912e015412SHans de Goede 	POWER_SUPPLY_PROP_CHARGE_FULL_DESIGN,
928c0984e5SSebastian Reichel 	POWER_SUPPLY_PROP_CHARGE_FULL,
936d6b61eaSHans de Goede 	POWER_SUPPLY_PROP_CHARGE_NOW,
948c0984e5SSebastian Reichel 	POWER_SUPPLY_PROP_CHARGE_COUNTER,
958c0984e5SSebastian Reichel 	POWER_SUPPLY_PROP_TEMP,
968c0984e5SSebastian Reichel 	POWER_SUPPLY_PROP_TEMP_ALERT_MIN,
978c0984e5SSebastian Reichel 	POWER_SUPPLY_PROP_TEMP_ALERT_MAX,
988c0984e5SSebastian Reichel 	POWER_SUPPLY_PROP_TEMP_MIN,
998c0984e5SSebastian Reichel 	POWER_SUPPLY_PROP_TEMP_MAX,
1008c0984e5SSebastian Reichel 	POWER_SUPPLY_PROP_HEALTH,
101adb69a3cSHans de Goede 	POWER_SUPPLY_PROP_SCOPE,
1028c0984e5SSebastian Reichel 	POWER_SUPPLY_PROP_CURRENT_NOW,
1038c0984e5SSebastian Reichel 	POWER_SUPPLY_PROP_CURRENT_AVG,
1048c0984e5SSebastian Reichel };
1058c0984e5SSebastian Reichel 
1068c0984e5SSebastian Reichel static int max17042_get_temperature(struct max17042_chip *chip, int *temp)
1078c0984e5SSebastian Reichel {
1088c0984e5SSebastian Reichel 	int ret;
1098c0984e5SSebastian Reichel 	u32 data;
1108c0984e5SSebastian Reichel 	struct regmap *map = chip->regmap;
1118c0984e5SSebastian Reichel 
1128c0984e5SSebastian Reichel 	ret = regmap_read(map, MAX17042_TEMP, &data);
1138c0984e5SSebastian Reichel 	if (ret < 0)
1148c0984e5SSebastian Reichel 		return ret;
1158c0984e5SSebastian Reichel 
116c67c0693SHans de Goede 	*temp = sign_extend32(data, 15);
1178c0984e5SSebastian Reichel 	/* The value is converted into deci-centigrade scale */
1188c0984e5SSebastian Reichel 	/* Units of LSB = 1 / 256 degree Celsius */
1198c0984e5SSebastian Reichel 	*temp = *temp * 10 / 256;
1208c0984e5SSebastian Reichel 	return 0;
1218c0984e5SSebastian Reichel }
1228c0984e5SSebastian Reichel 
123a9df22c0SHans de Goede static int max17042_get_status(struct max17042_chip *chip, int *status)
124a9df22c0SHans de Goede {
125a9df22c0SHans de Goede 	int ret, charge_full, charge_now;
126a9df22c0SHans de Goede 
127a9df22c0SHans de Goede 	ret = power_supply_am_i_supplied(chip->battery);
128a9df22c0SHans de Goede 	if (ret < 0) {
129a9df22c0SHans de Goede 		*status = POWER_SUPPLY_STATUS_UNKNOWN;
130a9df22c0SHans de Goede 		return 0;
131a9df22c0SHans de Goede 	}
132a9df22c0SHans de Goede 	if (ret == 0) {
133a9df22c0SHans de Goede 		*status = POWER_SUPPLY_STATUS_DISCHARGING;
134a9df22c0SHans de Goede 		return 0;
135a9df22c0SHans de Goede 	}
136a9df22c0SHans de Goede 
137a9df22c0SHans de Goede 	/*
138a9df22c0SHans de Goede 	 * The MAX170xx has builtin end-of-charge detection and will update
139a9df22c0SHans de Goede 	 * FullCAP to match RepCap when it detects end of charging.
140a9df22c0SHans de Goede 	 *
141a9df22c0SHans de Goede 	 * When this cycle the battery gets charged to a higher (calculated)
142a9df22c0SHans de Goede 	 * capacity then the previous cycle then FullCAP will get updated
143a9df22c0SHans de Goede 	 * contineously once end-of-charge detection kicks in, so allow the
144a9df22c0SHans de Goede 	 * 2 to differ a bit.
145a9df22c0SHans de Goede 	 */
146a9df22c0SHans de Goede 
147a9df22c0SHans de Goede 	ret = regmap_read(chip->regmap, MAX17042_FullCAP, &charge_full);
148a9df22c0SHans de Goede 	if (ret < 0)
149a9df22c0SHans de Goede 		return ret;
150a9df22c0SHans de Goede 
151a9df22c0SHans de Goede 	ret = regmap_read(chip->regmap, MAX17042_RepCap, &charge_now);
152a9df22c0SHans de Goede 	if (ret < 0)
153a9df22c0SHans de Goede 		return ret;
154a9df22c0SHans de Goede 
155a9df22c0SHans de Goede 	if ((charge_full - charge_now) <= MAX17042_FULL_THRESHOLD)
156a9df22c0SHans de Goede 		*status = POWER_SUPPLY_STATUS_FULL;
157a9df22c0SHans de Goede 	else
158a9df22c0SHans de Goede 		*status = POWER_SUPPLY_STATUS_CHARGING;
159a9df22c0SHans de Goede 
160a9df22c0SHans de Goede 	return 0;
161a9df22c0SHans de Goede }
162a9df22c0SHans de Goede 
1638c0984e5SSebastian Reichel static int max17042_get_battery_health(struct max17042_chip *chip, int *health)
1648c0984e5SSebastian Reichel {
1658c0984e5SSebastian Reichel 	int temp, vavg, vbatt, ret;
1668c0984e5SSebastian Reichel 	u32 val;
1678c0984e5SSebastian Reichel 
1688c0984e5SSebastian Reichel 	ret = regmap_read(chip->regmap, MAX17042_AvgVCELL, &val);
1698c0984e5SSebastian Reichel 	if (ret < 0)
1708c0984e5SSebastian Reichel 		goto health_error;
1718c0984e5SSebastian Reichel 
1728c0984e5SSebastian Reichel 	/* bits [0-3] unused */
1738c0984e5SSebastian Reichel 	vavg = val * 625 / 8;
1748c0984e5SSebastian Reichel 	/* Convert to millivolts */
1758c0984e5SSebastian Reichel 	vavg /= 1000;
1768c0984e5SSebastian Reichel 
1778c0984e5SSebastian Reichel 	ret = regmap_read(chip->regmap, MAX17042_VCELL, &val);
1788c0984e5SSebastian Reichel 	if (ret < 0)
1798c0984e5SSebastian Reichel 		goto health_error;
1808c0984e5SSebastian Reichel 
1818c0984e5SSebastian Reichel 	/* bits [0-3] unused */
1828c0984e5SSebastian Reichel 	vbatt = val * 625 / 8;
1838c0984e5SSebastian Reichel 	/* Convert to millivolts */
1848c0984e5SSebastian Reichel 	vbatt /= 1000;
1858c0984e5SSebastian Reichel 
1868c0984e5SSebastian Reichel 	if (vavg < chip->pdata->vmin) {
1878c0984e5SSebastian Reichel 		*health = POWER_SUPPLY_HEALTH_DEAD;
1888c0984e5SSebastian Reichel 		goto out;
1898c0984e5SSebastian Reichel 	}
1908c0984e5SSebastian Reichel 
1918c0984e5SSebastian Reichel 	if (vbatt > chip->pdata->vmax + MAX17042_VMAX_TOLERANCE) {
1928c0984e5SSebastian Reichel 		*health = POWER_SUPPLY_HEALTH_OVERVOLTAGE;
1938c0984e5SSebastian Reichel 		goto out;
1948c0984e5SSebastian Reichel 	}
1958c0984e5SSebastian Reichel 
1968c0984e5SSebastian Reichel 	ret = max17042_get_temperature(chip, &temp);
1978c0984e5SSebastian Reichel 	if (ret < 0)
1988c0984e5SSebastian Reichel 		goto health_error;
1998c0984e5SSebastian Reichel 
20091736213SHans de Goede 	if (temp < chip->pdata->temp_min) {
2018c0984e5SSebastian Reichel 		*health = POWER_SUPPLY_HEALTH_COLD;
2028c0984e5SSebastian Reichel 		goto out;
2038c0984e5SSebastian Reichel 	}
2048c0984e5SSebastian Reichel 
20591736213SHans de Goede 	if (temp > chip->pdata->temp_max) {
2068c0984e5SSebastian Reichel 		*health = POWER_SUPPLY_HEALTH_OVERHEAT;
2078c0984e5SSebastian Reichel 		goto out;
2088c0984e5SSebastian Reichel 	}
2098c0984e5SSebastian Reichel 
2108c0984e5SSebastian Reichel 	*health = POWER_SUPPLY_HEALTH_GOOD;
2118c0984e5SSebastian Reichel 
2128c0984e5SSebastian Reichel out:
2138c0984e5SSebastian Reichel 	return 0;
2148c0984e5SSebastian Reichel 
2158c0984e5SSebastian Reichel health_error:
2168c0984e5SSebastian Reichel 	return ret;
2178c0984e5SSebastian Reichel }
2188c0984e5SSebastian Reichel 
2198c0984e5SSebastian Reichel static int max17042_get_property(struct power_supply *psy,
2208c0984e5SSebastian Reichel 			    enum power_supply_property psp,
2218c0984e5SSebastian Reichel 			    union power_supply_propval *val)
2228c0984e5SSebastian Reichel {
2238c0984e5SSebastian Reichel 	struct max17042_chip *chip = power_supply_get_drvdata(psy);
2248c0984e5SSebastian Reichel 	struct regmap *map = chip->regmap;
2258c0984e5SSebastian Reichel 	int ret;
2268c0984e5SSebastian Reichel 	u32 data;
227d7d15fc6SHans de Goede 	u64 data64;
2288c0984e5SSebastian Reichel 
2298c0984e5SSebastian Reichel 	if (!chip->init_complete)
2308c0984e5SSebastian Reichel 		return -EAGAIN;
2318c0984e5SSebastian Reichel 
2328c0984e5SSebastian Reichel 	switch (psp) {
233a9df22c0SHans de Goede 	case POWER_SUPPLY_PROP_STATUS:
234a9df22c0SHans de Goede 		ret = max17042_get_status(chip, &val->intval);
235a9df22c0SHans de Goede 		if (ret < 0)
236a9df22c0SHans de Goede 			return ret;
237a9df22c0SHans de Goede 		break;
2388c0984e5SSebastian Reichel 	case POWER_SUPPLY_PROP_PRESENT:
2398c0984e5SSebastian Reichel 		ret = regmap_read(map, MAX17042_STATUS, &data);
2408c0984e5SSebastian Reichel 		if (ret < 0)
2418c0984e5SSebastian Reichel 			return ret;
2428c0984e5SSebastian Reichel 
2438c0984e5SSebastian Reichel 		if (data & MAX17042_STATUS_BattAbsent)
2448c0984e5SSebastian Reichel 			val->intval = 0;
2458c0984e5SSebastian Reichel 		else
2468c0984e5SSebastian Reichel 			val->intval = 1;
2478c0984e5SSebastian Reichel 		break;
248ef7fcdaeSHans de Goede 	case POWER_SUPPLY_PROP_TECHNOLOGY:
249ef7fcdaeSHans de Goede 		val->intval = POWER_SUPPLY_TECHNOLOGY_LION;
250ef7fcdaeSHans de Goede 		break;
2518c0984e5SSebastian Reichel 	case POWER_SUPPLY_PROP_CYCLE_COUNT:
2528c0984e5SSebastian Reichel 		ret = regmap_read(map, MAX17042_Cycles, &data);
2538c0984e5SSebastian Reichel 		if (ret < 0)
2548c0984e5SSebastian Reichel 			return ret;
2558c0984e5SSebastian Reichel 
2568c0984e5SSebastian Reichel 		val->intval = data;
2578c0984e5SSebastian Reichel 		break;
2588c0984e5SSebastian Reichel 	case POWER_SUPPLY_PROP_VOLTAGE_MAX:
2598c0984e5SSebastian Reichel 		ret = regmap_read(map, MAX17042_MinMaxVolt, &data);
2608c0984e5SSebastian Reichel 		if (ret < 0)
2618c0984e5SSebastian Reichel 			return ret;
2628c0984e5SSebastian Reichel 
2638c0984e5SSebastian Reichel 		val->intval = data >> 8;
2648c0984e5SSebastian Reichel 		val->intval *= 20000; /* Units of LSB = 20mV */
2658c0984e5SSebastian Reichel 		break;
2667bfc9397SHans de Goede 	case POWER_SUPPLY_PROP_VOLTAGE_MIN:
2677bfc9397SHans de Goede 		ret = regmap_read(map, MAX17042_MinMaxVolt, &data);
2687bfc9397SHans de Goede 		if (ret < 0)
2697bfc9397SHans de Goede 			return ret;
2707bfc9397SHans de Goede 
2717bfc9397SHans de Goede 		val->intval = (data & 0xff) * 20000; /* Units of 20mV */
2727bfc9397SHans de Goede 		break;
2738c0984e5SSebastian Reichel 	case POWER_SUPPLY_PROP_VOLTAGE_MIN_DESIGN:
2748c0984e5SSebastian Reichel 		if (chip->chip_type == MAXIM_DEVICE_TYPE_MAX17042)
2758c0984e5SSebastian Reichel 			ret = regmap_read(map, MAX17042_V_empty, &data);
2768c0984e5SSebastian Reichel 		else
2778c0984e5SSebastian Reichel 			ret = regmap_read(map, MAX17047_V_empty, &data);
2788c0984e5SSebastian Reichel 		if (ret < 0)
2798c0984e5SSebastian Reichel 			return ret;
2808c0984e5SSebastian Reichel 
2818c0984e5SSebastian Reichel 		val->intval = data >> 7;
2828c0984e5SSebastian Reichel 		val->intval *= 10000; /* Units of LSB = 10mV */
2838c0984e5SSebastian Reichel 		break;
2848c0984e5SSebastian Reichel 	case POWER_SUPPLY_PROP_VOLTAGE_NOW:
2858c0984e5SSebastian Reichel 		ret = regmap_read(map, MAX17042_VCELL, &data);
2868c0984e5SSebastian Reichel 		if (ret < 0)
2878c0984e5SSebastian Reichel 			return ret;
2888c0984e5SSebastian Reichel 
2898c0984e5SSebastian Reichel 		val->intval = data * 625 / 8;
2908c0984e5SSebastian Reichel 		break;
2918c0984e5SSebastian Reichel 	case POWER_SUPPLY_PROP_VOLTAGE_AVG:
2928c0984e5SSebastian Reichel 		ret = regmap_read(map, MAX17042_AvgVCELL, &data);
2938c0984e5SSebastian Reichel 		if (ret < 0)
2948c0984e5SSebastian Reichel 			return ret;
2958c0984e5SSebastian Reichel 
2968c0984e5SSebastian Reichel 		val->intval = data * 625 / 8;
2978c0984e5SSebastian Reichel 		break;
2988c0984e5SSebastian Reichel 	case POWER_SUPPLY_PROP_VOLTAGE_OCV:
2998c0984e5SSebastian Reichel 		ret = regmap_read(map, MAX17042_OCVInternal, &data);
3008c0984e5SSebastian Reichel 		if (ret < 0)
3018c0984e5SSebastian Reichel 			return ret;
3028c0984e5SSebastian Reichel 
3038c0984e5SSebastian Reichel 		val->intval = data * 625 / 8;
3048c0984e5SSebastian Reichel 		break;
3058c0984e5SSebastian Reichel 	case POWER_SUPPLY_PROP_CAPACITY:
3068c0984e5SSebastian Reichel 		ret = regmap_read(map, MAX17042_RepSOC, &data);
3078c0984e5SSebastian Reichel 		if (ret < 0)
3088c0984e5SSebastian Reichel 			return ret;
3098c0984e5SSebastian Reichel 
3108c0984e5SSebastian Reichel 		val->intval = data >> 8;
3118c0984e5SSebastian Reichel 		break;
3122e015412SHans de Goede 	case POWER_SUPPLY_PROP_CHARGE_FULL_DESIGN:
3132e015412SHans de Goede 		ret = regmap_read(map, MAX17042_DesignCap, &data);
3142e015412SHans de Goede 		if (ret < 0)
3152e015412SHans de Goede 			return ret;
3162e015412SHans de Goede 
3172e015412SHans de Goede 		data64 = data * 5000000ll;
3182e015412SHans de Goede 		do_div(data64, chip->pdata->r_sns);
3192e015412SHans de Goede 		val->intval = data64;
3202e015412SHans de Goede 		break;
3218c0984e5SSebastian Reichel 	case POWER_SUPPLY_PROP_CHARGE_FULL:
3228c0984e5SSebastian Reichel 		ret = regmap_read(map, MAX17042_FullCAP, &data);
3238c0984e5SSebastian Reichel 		if (ret < 0)
3248c0984e5SSebastian Reichel 			return ret;
3258c0984e5SSebastian Reichel 
326d7d15fc6SHans de Goede 		data64 = data * 5000000ll;
327d7d15fc6SHans de Goede 		do_div(data64, chip->pdata->r_sns);
328d7d15fc6SHans de Goede 		val->intval = data64;
3298c0984e5SSebastian Reichel 		break;
3306d6b61eaSHans de Goede 	case POWER_SUPPLY_PROP_CHARGE_NOW:
3316d6b61eaSHans de Goede 		ret = regmap_read(map, MAX17042_RepCap, &data);
3326d6b61eaSHans de Goede 		if (ret < 0)
3336d6b61eaSHans de Goede 			return ret;
3346d6b61eaSHans de Goede 
3356d6b61eaSHans de Goede 		data64 = data * 5000000ll;
3366d6b61eaSHans de Goede 		do_div(data64, chip->pdata->r_sns);
3376d6b61eaSHans de Goede 		val->intval = data64;
3386d6b61eaSHans de Goede 		break;
3398c0984e5SSebastian Reichel 	case POWER_SUPPLY_PROP_CHARGE_COUNTER:
3408c0984e5SSebastian Reichel 		ret = regmap_read(map, MAX17042_QH, &data);
3418c0984e5SSebastian Reichel 		if (ret < 0)
3428c0984e5SSebastian Reichel 			return ret;
3438c0984e5SSebastian Reichel 
3448c0984e5SSebastian Reichel 		val->intval = data * 1000 / 2;
3458c0984e5SSebastian Reichel 		break;
3468c0984e5SSebastian Reichel 	case POWER_SUPPLY_PROP_TEMP:
3478c0984e5SSebastian Reichel 		ret = max17042_get_temperature(chip, &val->intval);
3488c0984e5SSebastian Reichel 		if (ret < 0)
3498c0984e5SSebastian Reichel 			return ret;
3508c0984e5SSebastian Reichel 		break;
3518c0984e5SSebastian Reichel 	case POWER_SUPPLY_PROP_TEMP_ALERT_MIN:
3528c0984e5SSebastian Reichel 		ret = regmap_read(map, MAX17042_TALRT_Th, &data);
3538c0984e5SSebastian Reichel 		if (ret < 0)
3548c0984e5SSebastian Reichel 			return ret;
3558c0984e5SSebastian Reichel 		/* LSB is Alert Minimum. In deci-centigrade */
3562814913cSHans de Goede 		val->intval = sign_extend32(data & 0xff, 7) * 10;
3578c0984e5SSebastian Reichel 		break;
3588c0984e5SSebastian Reichel 	case POWER_SUPPLY_PROP_TEMP_ALERT_MAX:
3598c0984e5SSebastian Reichel 		ret = regmap_read(map, MAX17042_TALRT_Th, &data);
3608c0984e5SSebastian Reichel 		if (ret < 0)
3618c0984e5SSebastian Reichel 			return ret;
3628c0984e5SSebastian Reichel 		/* MSB is Alert Maximum. In deci-centigrade */
3632814913cSHans de Goede 		val->intval = sign_extend32(data >> 8, 7) * 10;
3648c0984e5SSebastian Reichel 		break;
3658c0984e5SSebastian Reichel 	case POWER_SUPPLY_PROP_TEMP_MIN:
3668c0984e5SSebastian Reichel 		val->intval = chip->pdata->temp_min;
3678c0984e5SSebastian Reichel 		break;
3688c0984e5SSebastian Reichel 	case POWER_SUPPLY_PROP_TEMP_MAX:
3698c0984e5SSebastian Reichel 		val->intval = chip->pdata->temp_max;
3708c0984e5SSebastian Reichel 		break;
3718c0984e5SSebastian Reichel 	case POWER_SUPPLY_PROP_HEALTH:
3728c0984e5SSebastian Reichel 		ret = max17042_get_battery_health(chip, &val->intval);
3738c0984e5SSebastian Reichel 		if (ret < 0)
3748c0984e5SSebastian Reichel 			return ret;
3758c0984e5SSebastian Reichel 		break;
376adb69a3cSHans de Goede 	case POWER_SUPPLY_PROP_SCOPE:
377adb69a3cSHans de Goede 		val->intval = POWER_SUPPLY_SCOPE_SYSTEM;
378adb69a3cSHans de Goede 		break;
3798c0984e5SSebastian Reichel 	case POWER_SUPPLY_PROP_CURRENT_NOW:
3808c0984e5SSebastian Reichel 		if (chip->pdata->enable_current_sense) {
3818c0984e5SSebastian Reichel 			ret = regmap_read(map, MAX17042_Current, &data);
3828c0984e5SSebastian Reichel 			if (ret < 0)
3838c0984e5SSebastian Reichel 				return ret;
3848c0984e5SSebastian Reichel 
385c67c0693SHans de Goede 			val->intval = sign_extend32(data, 15);
3868c0984e5SSebastian Reichel 			val->intval *= 1562500 / chip->pdata->r_sns;
3878c0984e5SSebastian Reichel 		} else {
3888c0984e5SSebastian Reichel 			return -EINVAL;
3898c0984e5SSebastian Reichel 		}
3908c0984e5SSebastian Reichel 		break;
3918c0984e5SSebastian Reichel 	case POWER_SUPPLY_PROP_CURRENT_AVG:
3928c0984e5SSebastian Reichel 		if (chip->pdata->enable_current_sense) {
3938c0984e5SSebastian Reichel 			ret = regmap_read(map, MAX17042_AvgCurrent, &data);
3948c0984e5SSebastian Reichel 			if (ret < 0)
3958c0984e5SSebastian Reichel 				return ret;
3968c0984e5SSebastian Reichel 
397c67c0693SHans de Goede 			val->intval = sign_extend32(data, 15);
3988c0984e5SSebastian Reichel 			val->intval *= 1562500 / chip->pdata->r_sns;
3998c0984e5SSebastian Reichel 		} else {
4008c0984e5SSebastian Reichel 			return -EINVAL;
4018c0984e5SSebastian Reichel 		}
4028c0984e5SSebastian Reichel 		break;
4038c0984e5SSebastian Reichel 	default:
4048c0984e5SSebastian Reichel 		return -EINVAL;
4058c0984e5SSebastian Reichel 	}
4068c0984e5SSebastian Reichel 	return 0;
4078c0984e5SSebastian Reichel }
4088c0984e5SSebastian Reichel 
4098c0984e5SSebastian Reichel static int max17042_set_property(struct power_supply *psy,
4108c0984e5SSebastian Reichel 			    enum power_supply_property psp,
4118c0984e5SSebastian Reichel 			    const union power_supply_propval *val)
4128c0984e5SSebastian Reichel {
4138c0984e5SSebastian Reichel 	struct max17042_chip *chip = power_supply_get_drvdata(psy);
4148c0984e5SSebastian Reichel 	struct regmap *map = chip->regmap;
4158c0984e5SSebastian Reichel 	int ret = 0;
4168c0984e5SSebastian Reichel 	u32 data;
4178c0984e5SSebastian Reichel 	int8_t temp;
4188c0984e5SSebastian Reichel 
4198c0984e5SSebastian Reichel 	switch (psp) {
4208c0984e5SSebastian Reichel 	case POWER_SUPPLY_PROP_TEMP_ALERT_MIN:
4218c0984e5SSebastian Reichel 		ret = regmap_read(map, MAX17042_TALRT_Th, &data);
4228c0984e5SSebastian Reichel 		if (ret < 0)
4238c0984e5SSebastian Reichel 			return ret;
4248c0984e5SSebastian Reichel 
4258c0984e5SSebastian Reichel 		/* Input in deci-centigrade, convert to centigrade */
4268c0984e5SSebastian Reichel 		temp = val->intval / 10;
4278c0984e5SSebastian Reichel 		/* force min < max */
4288c0984e5SSebastian Reichel 		if (temp >= (int8_t)(data >> 8))
4298c0984e5SSebastian Reichel 			temp = (int8_t)(data >> 8) - 1;
4308c0984e5SSebastian Reichel 		/* Write both MAX and MIN ALERT */
4318c0984e5SSebastian Reichel 		data = (data & 0xff00) + temp;
4328c0984e5SSebastian Reichel 		ret = regmap_write(map, MAX17042_TALRT_Th, data);
4338c0984e5SSebastian Reichel 		break;
4348c0984e5SSebastian Reichel 	case POWER_SUPPLY_PROP_TEMP_ALERT_MAX:
4358c0984e5SSebastian Reichel 		ret = regmap_read(map, MAX17042_TALRT_Th, &data);
4368c0984e5SSebastian Reichel 		if (ret < 0)
4378c0984e5SSebastian Reichel 			return ret;
4388c0984e5SSebastian Reichel 
4398c0984e5SSebastian Reichel 		/* Input in Deci-Centigrade, convert to centigrade */
4408c0984e5SSebastian Reichel 		temp = val->intval / 10;
4418c0984e5SSebastian Reichel 		/* force max > min */
4428c0984e5SSebastian Reichel 		if (temp <= (int8_t)(data & 0xff))
4438c0984e5SSebastian Reichel 			temp = (int8_t)(data & 0xff) + 1;
4448c0984e5SSebastian Reichel 		/* Write both MAX and MIN ALERT */
4458c0984e5SSebastian Reichel 		data = (data & 0xff) + (temp << 8);
4468c0984e5SSebastian Reichel 		ret = regmap_write(map, MAX17042_TALRT_Th, data);
4478c0984e5SSebastian Reichel 		break;
4488c0984e5SSebastian Reichel 	default:
4498c0984e5SSebastian Reichel 		ret = -EINVAL;
4508c0984e5SSebastian Reichel 	}
4518c0984e5SSebastian Reichel 
4528c0984e5SSebastian Reichel 	return ret;
4538c0984e5SSebastian Reichel }
4548c0984e5SSebastian Reichel 
4558c0984e5SSebastian Reichel static int max17042_property_is_writeable(struct power_supply *psy,
4568c0984e5SSebastian Reichel 		enum power_supply_property psp)
4578c0984e5SSebastian Reichel {
4588c0984e5SSebastian Reichel 	int ret;
4598c0984e5SSebastian Reichel 
4608c0984e5SSebastian Reichel 	switch (psp) {
4618c0984e5SSebastian Reichel 	case POWER_SUPPLY_PROP_TEMP_ALERT_MIN:
4628c0984e5SSebastian Reichel 	case POWER_SUPPLY_PROP_TEMP_ALERT_MAX:
4638c0984e5SSebastian Reichel 		ret = 1;
4648c0984e5SSebastian Reichel 		break;
4658c0984e5SSebastian Reichel 	default:
4668c0984e5SSebastian Reichel 		ret = 0;
4678c0984e5SSebastian Reichel 	}
4688c0984e5SSebastian Reichel 
4698c0984e5SSebastian Reichel 	return ret;
4708c0984e5SSebastian Reichel }
4718c0984e5SSebastian Reichel 
472dcdddda8SHans de Goede static void max17042_external_power_changed(struct power_supply *psy)
473dcdddda8SHans de Goede {
474dcdddda8SHans de Goede 	power_supply_changed(psy);
475dcdddda8SHans de Goede }
476dcdddda8SHans de Goede 
4778c0984e5SSebastian Reichel static int max17042_write_verify_reg(struct regmap *map, u8 reg, u32 value)
4788c0984e5SSebastian Reichel {
4798c0984e5SSebastian Reichel 	int retries = 8;
4808c0984e5SSebastian Reichel 	int ret;
4818c0984e5SSebastian Reichel 	u32 read_value;
4828c0984e5SSebastian Reichel 
4838c0984e5SSebastian Reichel 	do {
4848c0984e5SSebastian Reichel 		ret = regmap_write(map, reg, value);
4858c0984e5SSebastian Reichel 		regmap_read(map, reg, &read_value);
4868c0984e5SSebastian Reichel 		if (read_value != value) {
4878c0984e5SSebastian Reichel 			ret = -EIO;
4888c0984e5SSebastian Reichel 			retries--;
4898c0984e5SSebastian Reichel 		}
4908c0984e5SSebastian Reichel 	} while (retries && read_value != value);
4918c0984e5SSebastian Reichel 
4928c0984e5SSebastian Reichel 	if (ret < 0)
4938c0984e5SSebastian Reichel 		pr_err("%s: err %d\n", __func__, ret);
4948c0984e5SSebastian Reichel 
4958c0984e5SSebastian Reichel 	return ret;
4968c0984e5SSebastian Reichel }
4978c0984e5SSebastian Reichel 
4988c0984e5SSebastian Reichel static inline void max17042_override_por(struct regmap *map,
4998c0984e5SSebastian Reichel 					 u8 reg, u16 value)
5008c0984e5SSebastian Reichel {
5018c0984e5SSebastian Reichel 	if (value)
5028c0984e5SSebastian Reichel 		regmap_write(map, reg, value);
5038c0984e5SSebastian Reichel }
5048c0984e5SSebastian Reichel 
5058c0984e5SSebastian Reichel static inline void max10742_unlock_model(struct max17042_chip *chip)
5068c0984e5SSebastian Reichel {
5078c0984e5SSebastian Reichel 	struct regmap *map = chip->regmap;
5088c0984e5SSebastian Reichel 
5098c0984e5SSebastian Reichel 	regmap_write(map, MAX17042_MLOCKReg1, MODEL_UNLOCK1);
5108c0984e5SSebastian Reichel 	regmap_write(map, MAX17042_MLOCKReg2, MODEL_UNLOCK2);
5118c0984e5SSebastian Reichel }
5128c0984e5SSebastian Reichel 
5138c0984e5SSebastian Reichel static inline void max10742_lock_model(struct max17042_chip *chip)
5148c0984e5SSebastian Reichel {
5158c0984e5SSebastian Reichel 	struct regmap *map = chip->regmap;
5168c0984e5SSebastian Reichel 
5178c0984e5SSebastian Reichel 	regmap_write(map, MAX17042_MLOCKReg1, MODEL_LOCK1);
5188c0984e5SSebastian Reichel 	regmap_write(map, MAX17042_MLOCKReg2, MODEL_LOCK2);
5198c0984e5SSebastian Reichel }
5208c0984e5SSebastian Reichel 
5218c0984e5SSebastian Reichel static inline void max17042_write_model_data(struct max17042_chip *chip,
5228c0984e5SSebastian Reichel 					u8 addr, int size)
5238c0984e5SSebastian Reichel {
5248c0984e5SSebastian Reichel 	struct regmap *map = chip->regmap;
5258c0984e5SSebastian Reichel 	int i;
5268c0984e5SSebastian Reichel 
5278c0984e5SSebastian Reichel 	for (i = 0; i < size; i++)
5288c0984e5SSebastian Reichel 		regmap_write(map, addr + i,
5298c0984e5SSebastian Reichel 			chip->pdata->config_data->cell_char_tbl[i]);
5308c0984e5SSebastian Reichel }
5318c0984e5SSebastian Reichel 
5328c0984e5SSebastian Reichel static inline void max17042_read_model_data(struct max17042_chip *chip,
533f7c8f1deSSebastian Reichel 					u8 addr, u16 *data, int size)
5348c0984e5SSebastian Reichel {
5358c0984e5SSebastian Reichel 	struct regmap *map = chip->regmap;
5368c0984e5SSebastian Reichel 	int i;
537f7c8f1deSSebastian Reichel 	u32 tmp;
5388c0984e5SSebastian Reichel 
539f7c8f1deSSebastian Reichel 	for (i = 0; i < size; i++) {
540f7c8f1deSSebastian Reichel 		regmap_read(map, addr + i, &tmp);
541f7c8f1deSSebastian Reichel 		data[i] = (u16)tmp;
542f7c8f1deSSebastian Reichel 	}
5438c0984e5SSebastian Reichel }
5448c0984e5SSebastian Reichel 
5458c0984e5SSebastian Reichel static inline int max17042_model_data_compare(struct max17042_chip *chip,
5468c0984e5SSebastian Reichel 					u16 *data1, u16 *data2, int size)
5478c0984e5SSebastian Reichel {
5488c0984e5SSebastian Reichel 	int i;
5498c0984e5SSebastian Reichel 
5508c0984e5SSebastian Reichel 	if (memcmp(data1, data2, size)) {
5518c0984e5SSebastian Reichel 		dev_err(&chip->client->dev, "%s compare failed\n", __func__);
5528c0984e5SSebastian Reichel 		for (i = 0; i < size; i++)
5538c0984e5SSebastian Reichel 			dev_info(&chip->client->dev, "0x%x, 0x%x",
5548c0984e5SSebastian Reichel 				data1[i], data2[i]);
5558c0984e5SSebastian Reichel 		dev_info(&chip->client->dev, "\n");
5568c0984e5SSebastian Reichel 		return -EINVAL;
5578c0984e5SSebastian Reichel 	}
5588c0984e5SSebastian Reichel 	return 0;
5598c0984e5SSebastian Reichel }
5608c0984e5SSebastian Reichel 
5618c0984e5SSebastian Reichel static int max17042_init_model(struct max17042_chip *chip)
5628c0984e5SSebastian Reichel {
5638c0984e5SSebastian Reichel 	int ret;
5648c0984e5SSebastian Reichel 	int table_size = ARRAY_SIZE(chip->pdata->config_data->cell_char_tbl);
565f7c8f1deSSebastian Reichel 	u16 *temp_data;
5668c0984e5SSebastian Reichel 
5678c0984e5SSebastian Reichel 	temp_data = kcalloc(table_size, sizeof(*temp_data), GFP_KERNEL);
5688c0984e5SSebastian Reichel 	if (!temp_data)
5698c0984e5SSebastian Reichel 		return -ENOMEM;
5708c0984e5SSebastian Reichel 
5718c0984e5SSebastian Reichel 	max10742_unlock_model(chip);
5728c0984e5SSebastian Reichel 	max17042_write_model_data(chip, MAX17042_MODELChrTbl,
5738c0984e5SSebastian Reichel 				table_size);
5748c0984e5SSebastian Reichel 	max17042_read_model_data(chip, MAX17042_MODELChrTbl, temp_data,
5758c0984e5SSebastian Reichel 				table_size);
5768c0984e5SSebastian Reichel 
5778c0984e5SSebastian Reichel 	ret = max17042_model_data_compare(
5788c0984e5SSebastian Reichel 		chip,
5798c0984e5SSebastian Reichel 		chip->pdata->config_data->cell_char_tbl,
580f7c8f1deSSebastian Reichel 		temp_data,
5818c0984e5SSebastian Reichel 		table_size);
5828c0984e5SSebastian Reichel 
5838c0984e5SSebastian Reichel 	max10742_lock_model(chip);
5848c0984e5SSebastian Reichel 	kfree(temp_data);
5858c0984e5SSebastian Reichel 
5868c0984e5SSebastian Reichel 	return ret;
5878c0984e5SSebastian Reichel }
5888c0984e5SSebastian Reichel 
5898c0984e5SSebastian Reichel static int max17042_verify_model_lock(struct max17042_chip *chip)
5908c0984e5SSebastian Reichel {
5918c0984e5SSebastian Reichel 	int i;
5928c0984e5SSebastian Reichel 	int table_size = ARRAY_SIZE(chip->pdata->config_data->cell_char_tbl);
593f7c8f1deSSebastian Reichel 	u16 *temp_data;
5948c0984e5SSebastian Reichel 	int ret = 0;
5958c0984e5SSebastian Reichel 
5968c0984e5SSebastian Reichel 	temp_data = kcalloc(table_size, sizeof(*temp_data), GFP_KERNEL);
5978c0984e5SSebastian Reichel 	if (!temp_data)
5988c0984e5SSebastian Reichel 		return -ENOMEM;
5998c0984e5SSebastian Reichel 
6008c0984e5SSebastian Reichel 	max17042_read_model_data(chip, MAX17042_MODELChrTbl, temp_data,
6018c0984e5SSebastian Reichel 				table_size);
6028c0984e5SSebastian Reichel 	for (i = 0; i < table_size; i++)
6038c0984e5SSebastian Reichel 		if (temp_data[i])
6048c0984e5SSebastian Reichel 			ret = -EINVAL;
6058c0984e5SSebastian Reichel 
6068c0984e5SSebastian Reichel 	kfree(temp_data);
6078c0984e5SSebastian Reichel 	return ret;
6088c0984e5SSebastian Reichel }
6098c0984e5SSebastian Reichel 
6108c0984e5SSebastian Reichel static void max17042_write_config_regs(struct max17042_chip *chip)
6118c0984e5SSebastian Reichel {
6128c0984e5SSebastian Reichel 	struct max17042_config_data *config = chip->pdata->config_data;
6138c0984e5SSebastian Reichel 	struct regmap *map = chip->regmap;
6148c0984e5SSebastian Reichel 
6158c0984e5SSebastian Reichel 	regmap_write(map, MAX17042_CONFIG, config->config);
6168c0984e5SSebastian Reichel 	regmap_write(map, MAX17042_LearnCFG, config->learn_cfg);
6178c0984e5SSebastian Reichel 	regmap_write(map, MAX17042_FilterCFG,
6188c0984e5SSebastian Reichel 			config->filter_cfg);
6198c0984e5SSebastian Reichel 	regmap_write(map, MAX17042_RelaxCFG, config->relax_cfg);
6208c0984e5SSebastian Reichel 	if (chip->chip_type == MAXIM_DEVICE_TYPE_MAX17047 ||
6218c0984e5SSebastian Reichel 			chip->chip_type == MAXIM_DEVICE_TYPE_MAX17050)
6228c0984e5SSebastian Reichel 		regmap_write(map, MAX17047_FullSOCThr,
6238c0984e5SSebastian Reichel 						config->full_soc_thresh);
6248c0984e5SSebastian Reichel }
6258c0984e5SSebastian Reichel 
6268c0984e5SSebastian Reichel static void  max17042_write_custom_regs(struct max17042_chip *chip)
6278c0984e5SSebastian Reichel {
6288c0984e5SSebastian Reichel 	struct max17042_config_data *config = chip->pdata->config_data;
6298c0984e5SSebastian Reichel 	struct regmap *map = chip->regmap;
6308c0984e5SSebastian Reichel 
6318c0984e5SSebastian Reichel 	max17042_write_verify_reg(map, MAX17042_RCOMP0, config->rcomp0);
6328c0984e5SSebastian Reichel 	max17042_write_verify_reg(map, MAX17042_TempCo,	config->tcompc0);
6338c0984e5SSebastian Reichel 	max17042_write_verify_reg(map, MAX17042_ICHGTerm, config->ichgt_term);
6348c0984e5SSebastian Reichel 	if (chip->chip_type == MAXIM_DEVICE_TYPE_MAX17042) {
6358c0984e5SSebastian Reichel 		regmap_write(map, MAX17042_EmptyTempCo,	config->empty_tempco);
6368c0984e5SSebastian Reichel 		max17042_write_verify_reg(map, MAX17042_K_empty0,
6378c0984e5SSebastian Reichel 					config->kempty0);
6388c0984e5SSebastian Reichel 	} else {
6398c0984e5SSebastian Reichel 		max17042_write_verify_reg(map, MAX17047_QRTbl00,
6408c0984e5SSebastian Reichel 						config->qrtbl00);
6418c0984e5SSebastian Reichel 		max17042_write_verify_reg(map, MAX17047_QRTbl10,
6428c0984e5SSebastian Reichel 						config->qrtbl10);
6438c0984e5SSebastian Reichel 		max17042_write_verify_reg(map, MAX17047_QRTbl20,
6448c0984e5SSebastian Reichel 						config->qrtbl20);
6458c0984e5SSebastian Reichel 		max17042_write_verify_reg(map, MAX17047_QRTbl30,
6468c0984e5SSebastian Reichel 						config->qrtbl30);
6478c0984e5SSebastian Reichel 	}
6488c0984e5SSebastian Reichel }
6498c0984e5SSebastian Reichel 
6508c0984e5SSebastian Reichel static void max17042_update_capacity_regs(struct max17042_chip *chip)
6518c0984e5SSebastian Reichel {
6528c0984e5SSebastian Reichel 	struct max17042_config_data *config = chip->pdata->config_data;
6538c0984e5SSebastian Reichel 	struct regmap *map = chip->regmap;
6548c0984e5SSebastian Reichel 
6558c0984e5SSebastian Reichel 	max17042_write_verify_reg(map, MAX17042_FullCAP,
6568c0984e5SSebastian Reichel 				config->fullcap);
6578c0984e5SSebastian Reichel 	regmap_write(map, MAX17042_DesignCap, config->design_cap);
6588c0984e5SSebastian Reichel 	max17042_write_verify_reg(map, MAX17042_FullCAPNom,
6598c0984e5SSebastian Reichel 				config->fullcapnom);
6608c0984e5SSebastian Reichel }
6618c0984e5SSebastian Reichel 
6628c0984e5SSebastian Reichel static void max17042_reset_vfsoc0_reg(struct max17042_chip *chip)
6638c0984e5SSebastian Reichel {
6648c0984e5SSebastian Reichel 	unsigned int vfSoc;
6658c0984e5SSebastian Reichel 	struct regmap *map = chip->regmap;
6668c0984e5SSebastian Reichel 
6678c0984e5SSebastian Reichel 	regmap_read(map, MAX17042_VFSOC, &vfSoc);
6688c0984e5SSebastian Reichel 	regmap_write(map, MAX17042_VFSOC0Enable, VFSOC0_UNLOCK);
6698c0984e5SSebastian Reichel 	max17042_write_verify_reg(map, MAX17042_VFSOC0, vfSoc);
6708c0984e5SSebastian Reichel 	regmap_write(map, MAX17042_VFSOC0Enable, VFSOC0_LOCK);
6718c0984e5SSebastian Reichel }
6728c0984e5SSebastian Reichel 
6738c0984e5SSebastian Reichel static void max17042_load_new_capacity_params(struct max17042_chip *chip)
6748c0984e5SSebastian Reichel {
6758c0984e5SSebastian Reichel 	u32 full_cap0, rep_cap, dq_acc, vfSoc;
6768c0984e5SSebastian Reichel 	u32 rem_cap;
6778c0984e5SSebastian Reichel 
6788c0984e5SSebastian Reichel 	struct max17042_config_data *config = chip->pdata->config_data;
6798c0984e5SSebastian Reichel 	struct regmap *map = chip->regmap;
6808c0984e5SSebastian Reichel 
6818c0984e5SSebastian Reichel 	regmap_read(map, MAX17042_FullCAP0, &full_cap0);
6828c0984e5SSebastian Reichel 	regmap_read(map, MAX17042_VFSOC, &vfSoc);
6838c0984e5SSebastian Reichel 
6848c0984e5SSebastian Reichel 	/* fg_vfSoc needs to shifted by 8 bits to get the
6858c0984e5SSebastian Reichel 	 * perc in 1% accuracy, to get the right rem_cap multiply
6868c0984e5SSebastian Reichel 	 * full_cap0, fg_vfSoc and devide by 100
6878c0984e5SSebastian Reichel 	 */
6888c0984e5SSebastian Reichel 	rem_cap = ((vfSoc >> 8) * full_cap0) / 100;
6898c0984e5SSebastian Reichel 	max17042_write_verify_reg(map, MAX17042_RemCap, rem_cap);
6908c0984e5SSebastian Reichel 
6918c0984e5SSebastian Reichel 	rep_cap = rem_cap;
6928c0984e5SSebastian Reichel 	max17042_write_verify_reg(map, MAX17042_RepCap, rep_cap);
6938c0984e5SSebastian Reichel 
6948c0984e5SSebastian Reichel 	/* Write dQ_acc to 200% of Capacity and dP_acc to 200% */
6958c0984e5SSebastian Reichel 	dq_acc = config->fullcap / dQ_ACC_DIV;
6968c0984e5SSebastian Reichel 	max17042_write_verify_reg(map, MAX17042_dQacc, dq_acc);
6978c0984e5SSebastian Reichel 	max17042_write_verify_reg(map, MAX17042_dPacc, dP_ACC_200);
6988c0984e5SSebastian Reichel 
6998c0984e5SSebastian Reichel 	max17042_write_verify_reg(map, MAX17042_FullCAP,
7008c0984e5SSebastian Reichel 			config->fullcap);
7018c0984e5SSebastian Reichel 	regmap_write(map, MAX17042_DesignCap,
7028c0984e5SSebastian Reichel 			config->design_cap);
7038c0984e5SSebastian Reichel 	max17042_write_verify_reg(map, MAX17042_FullCAPNom,
7048c0984e5SSebastian Reichel 			config->fullcapnom);
7058c0984e5SSebastian Reichel 	/* Update SOC register with new SOC */
7068c0984e5SSebastian Reichel 	regmap_write(map, MAX17042_RepSOC, vfSoc);
7078c0984e5SSebastian Reichel }
7088c0984e5SSebastian Reichel 
7098c0984e5SSebastian Reichel /*
7108c0984e5SSebastian Reichel  * Block write all the override values coming from platform data.
7118c0984e5SSebastian Reichel  * This function MUST be called before the POR initialization proceedure
7128c0984e5SSebastian Reichel  * specified by maxim.
7138c0984e5SSebastian Reichel  */
7148c0984e5SSebastian Reichel static inline void max17042_override_por_values(struct max17042_chip *chip)
7158c0984e5SSebastian Reichel {
7168c0984e5SSebastian Reichel 	struct regmap *map = chip->regmap;
7178c0984e5SSebastian Reichel 	struct max17042_config_data *config = chip->pdata->config_data;
7188c0984e5SSebastian Reichel 
7198c0984e5SSebastian Reichel 	max17042_override_por(map, MAX17042_TGAIN, config->tgain);
7208c0984e5SSebastian Reichel 	max17042_override_por(map, MAx17042_TOFF, config->toff);
7218c0984e5SSebastian Reichel 	max17042_override_por(map, MAX17042_CGAIN, config->cgain);
7228c0984e5SSebastian Reichel 	max17042_override_por(map, MAX17042_COFF, config->coff);
7238c0984e5SSebastian Reichel 
7248c0984e5SSebastian Reichel 	max17042_override_por(map, MAX17042_VALRT_Th, config->valrt_thresh);
7258c0984e5SSebastian Reichel 	max17042_override_por(map, MAX17042_TALRT_Th, config->talrt_thresh);
7268c0984e5SSebastian Reichel 	max17042_override_por(map, MAX17042_SALRT_Th,
7278c0984e5SSebastian Reichel 						config->soc_alrt_thresh);
7288c0984e5SSebastian Reichel 	max17042_override_por(map, MAX17042_CONFIG, config->config);
7298c0984e5SSebastian Reichel 	max17042_override_por(map, MAX17042_SHDNTIMER, config->shdntimer);
7308c0984e5SSebastian Reichel 
7318c0984e5SSebastian Reichel 	max17042_override_por(map, MAX17042_DesignCap, config->design_cap);
7328c0984e5SSebastian Reichel 	max17042_override_por(map, MAX17042_ICHGTerm, config->ichgt_term);
7338c0984e5SSebastian Reichel 
7348c0984e5SSebastian Reichel 	max17042_override_por(map, MAX17042_AtRate, config->at_rate);
7358c0984e5SSebastian Reichel 	max17042_override_por(map, MAX17042_LearnCFG, config->learn_cfg);
7368c0984e5SSebastian Reichel 	max17042_override_por(map, MAX17042_FilterCFG, config->filter_cfg);
7378c0984e5SSebastian Reichel 	max17042_override_por(map, MAX17042_RelaxCFG, config->relax_cfg);
7388c0984e5SSebastian Reichel 	max17042_override_por(map, MAX17042_MiscCFG, config->misc_cfg);
7398c0984e5SSebastian Reichel 	max17042_override_por(map, MAX17042_MaskSOC, config->masksoc);
7408c0984e5SSebastian Reichel 
7418c0984e5SSebastian Reichel 	max17042_override_por(map, MAX17042_FullCAP, config->fullcap);
7428c0984e5SSebastian Reichel 	max17042_override_por(map, MAX17042_FullCAPNom, config->fullcapnom);
7438c0984e5SSebastian Reichel 	if (chip->chip_type == MAXIM_DEVICE_TYPE_MAX17042)
7448c0984e5SSebastian Reichel 		max17042_override_por(map, MAX17042_SOC_empty,
7458c0984e5SSebastian Reichel 						config->socempty);
7468c0984e5SSebastian Reichel 	max17042_override_por(map, MAX17042_LAvg_empty, config->lavg_empty);
7478c0984e5SSebastian Reichel 	max17042_override_por(map, MAX17042_dQacc, config->dqacc);
7488c0984e5SSebastian Reichel 	max17042_override_por(map, MAX17042_dPacc, config->dpacc);
7498c0984e5SSebastian Reichel 
7508c0984e5SSebastian Reichel 	if (chip->chip_type == MAXIM_DEVICE_TYPE_MAX17042)
7518c0984e5SSebastian Reichel 		max17042_override_por(map, MAX17042_V_empty, config->vempty);
7528c0984e5SSebastian Reichel 	else
7538c0984e5SSebastian Reichel 		max17042_override_por(map, MAX17047_V_empty, config->vempty);
7548c0984e5SSebastian Reichel 	max17042_override_por(map, MAX17042_TempNom, config->temp_nom);
7558c0984e5SSebastian Reichel 	max17042_override_por(map, MAX17042_TempLim, config->temp_lim);
7568c0984e5SSebastian Reichel 	max17042_override_por(map, MAX17042_FCTC, config->fctc);
7578c0984e5SSebastian Reichel 	max17042_override_por(map, MAX17042_RCOMP0, config->rcomp0);
7588c0984e5SSebastian Reichel 	max17042_override_por(map, MAX17042_TempCo, config->tcompc0);
7598c0984e5SSebastian Reichel 	if (chip->chip_type) {
7608c0984e5SSebastian Reichel 		max17042_override_por(map, MAX17042_EmptyTempCo,
7618c0984e5SSebastian Reichel 						config->empty_tempco);
7628c0984e5SSebastian Reichel 		max17042_override_por(map, MAX17042_K_empty0,
7638c0984e5SSebastian Reichel 						config->kempty0);
7648c0984e5SSebastian Reichel 	}
7658c0984e5SSebastian Reichel }
7668c0984e5SSebastian Reichel 
7678c0984e5SSebastian Reichel static int max17042_init_chip(struct max17042_chip *chip)
7688c0984e5SSebastian Reichel {
7698c0984e5SSebastian Reichel 	struct regmap *map = chip->regmap;
7708c0984e5SSebastian Reichel 	int ret;
7718c0984e5SSebastian Reichel 
7728c0984e5SSebastian Reichel 	max17042_override_por_values(chip);
7738c0984e5SSebastian Reichel 	/* After Power up, the MAX17042 requires 500mS in order
7748c0984e5SSebastian Reichel 	 * to perform signal debouncing and initial SOC reporting
7758c0984e5SSebastian Reichel 	 */
7768c0984e5SSebastian Reichel 	msleep(500);
7778c0984e5SSebastian Reichel 
7788c0984e5SSebastian Reichel 	/* Initialize configaration */
7798c0984e5SSebastian Reichel 	max17042_write_config_regs(chip);
7808c0984e5SSebastian Reichel 
7818c0984e5SSebastian Reichel 	/* write cell characterization data */
7828c0984e5SSebastian Reichel 	ret = max17042_init_model(chip);
7838c0984e5SSebastian Reichel 	if (ret) {
7848c0984e5SSebastian Reichel 		dev_err(&chip->client->dev, "%s init failed\n",
7858c0984e5SSebastian Reichel 			__func__);
7868c0984e5SSebastian Reichel 		return -EIO;
7878c0984e5SSebastian Reichel 	}
7888c0984e5SSebastian Reichel 
7898c0984e5SSebastian Reichel 	ret = max17042_verify_model_lock(chip);
7908c0984e5SSebastian Reichel 	if (ret) {
7918c0984e5SSebastian Reichel 		dev_err(&chip->client->dev, "%s lock verify failed\n",
7928c0984e5SSebastian Reichel 			__func__);
7938c0984e5SSebastian Reichel 		return -EIO;
7948c0984e5SSebastian Reichel 	}
7958c0984e5SSebastian Reichel 	/* write custom parameters */
7968c0984e5SSebastian Reichel 	max17042_write_custom_regs(chip);
7978c0984e5SSebastian Reichel 
7988c0984e5SSebastian Reichel 	/* update capacity params */
7998c0984e5SSebastian Reichel 	max17042_update_capacity_regs(chip);
8008c0984e5SSebastian Reichel 
8018c0984e5SSebastian Reichel 	/* delay must be atleast 350mS to allow VFSOC
8028c0984e5SSebastian Reichel 	 * to be calculated from the new configuration
8038c0984e5SSebastian Reichel 	 */
8048c0984e5SSebastian Reichel 	msleep(350);
8058c0984e5SSebastian Reichel 
8068c0984e5SSebastian Reichel 	/* reset vfsoc0 reg */
8078c0984e5SSebastian Reichel 	max17042_reset_vfsoc0_reg(chip);
8088c0984e5SSebastian Reichel 
8098c0984e5SSebastian Reichel 	/* load new capacity params */
8108c0984e5SSebastian Reichel 	max17042_load_new_capacity_params(chip);
8118c0984e5SSebastian Reichel 
8128c0984e5SSebastian Reichel 	/* Init complete, Clear the POR bit */
8138c0984e5SSebastian Reichel 	regmap_update_bits(map, MAX17042_STATUS, STATUS_POR_BIT, 0x0);
8148c0984e5SSebastian Reichel 	return 0;
8158c0984e5SSebastian Reichel }
8168c0984e5SSebastian Reichel 
8178c0984e5SSebastian Reichel static void max17042_set_soc_threshold(struct max17042_chip *chip, u16 off)
8188c0984e5SSebastian Reichel {
8198c0984e5SSebastian Reichel 	struct regmap *map = chip->regmap;
8208c0984e5SSebastian Reichel 	u32 soc, soc_tr;
8218c0984e5SSebastian Reichel 
8228c0984e5SSebastian Reichel 	/* program interrupt thesholds such that we should
8238c0984e5SSebastian Reichel 	 * get interrupt for every 'off' perc change in the soc
8248c0984e5SSebastian Reichel 	 */
8258c0984e5SSebastian Reichel 	regmap_read(map, MAX17042_RepSOC, &soc);
8268c0984e5SSebastian Reichel 	soc >>= 8;
8278c0984e5SSebastian Reichel 	soc_tr = (soc + off) << 8;
8288c0984e5SSebastian Reichel 	soc_tr |= (soc - off);
8298c0984e5SSebastian Reichel 	regmap_write(map, MAX17042_SALRT_Th, soc_tr);
8308c0984e5SSebastian Reichel }
8318c0984e5SSebastian Reichel 
8328c0984e5SSebastian Reichel static irqreturn_t max17042_thread_handler(int id, void *dev)
8338c0984e5SSebastian Reichel {
8348c0984e5SSebastian Reichel 	struct max17042_chip *chip = dev;
8358c0984e5SSebastian Reichel 	u32 val;
8368c0984e5SSebastian Reichel 
8378c0984e5SSebastian Reichel 	regmap_read(chip->regmap, MAX17042_STATUS, &val);
8388c0984e5SSebastian Reichel 	if ((val & STATUS_INTR_SOCMIN_BIT) ||
8398c0984e5SSebastian Reichel 		(val & STATUS_INTR_SOCMAX_BIT)) {
8408c0984e5SSebastian Reichel 		dev_info(&chip->client->dev, "SOC threshold INTR\n");
8418c0984e5SSebastian Reichel 		max17042_set_soc_threshold(chip, 1);
8428c0984e5SSebastian Reichel 	}
8438c0984e5SSebastian Reichel 
8448c0984e5SSebastian Reichel 	power_supply_changed(chip->battery);
8458c0984e5SSebastian Reichel 	return IRQ_HANDLED;
8468c0984e5SSebastian Reichel }
8478c0984e5SSebastian Reichel 
8488c0984e5SSebastian Reichel static void max17042_init_worker(struct work_struct *work)
8498c0984e5SSebastian Reichel {
8508c0984e5SSebastian Reichel 	struct max17042_chip *chip = container_of(work,
8518c0984e5SSebastian Reichel 				struct max17042_chip, work);
8528c0984e5SSebastian Reichel 	int ret;
8538c0984e5SSebastian Reichel 
8548c0984e5SSebastian Reichel 	/* Initialize registers according to values from the platform data */
8558c0984e5SSebastian Reichel 	if (chip->pdata->enable_por_init && chip->pdata->config_data) {
8568c0984e5SSebastian Reichel 		ret = max17042_init_chip(chip);
8578c0984e5SSebastian Reichel 		if (ret)
8588c0984e5SSebastian Reichel 			return;
8598c0984e5SSebastian Reichel 	}
8608c0984e5SSebastian Reichel 
8618c0984e5SSebastian Reichel 	chip->init_complete = 1;
8628c0984e5SSebastian Reichel }
8638c0984e5SSebastian Reichel 
8648c0984e5SSebastian Reichel #ifdef CONFIG_OF
8658c0984e5SSebastian Reichel static struct max17042_platform_data *
86691736213SHans de Goede max17042_get_pdata(struct max17042_chip *chip)
8678c0984e5SSebastian Reichel {
86891736213SHans de Goede 	struct device *dev = &chip->client->dev;
8698c0984e5SSebastian Reichel 	struct device_node *np = dev->of_node;
8708c0984e5SSebastian Reichel 	u32 prop;
8718c0984e5SSebastian Reichel 	struct max17042_platform_data *pdata;
8728c0984e5SSebastian Reichel 
8738c0984e5SSebastian Reichel 	if (!np)
8748c0984e5SSebastian Reichel 		return dev->platform_data;
8758c0984e5SSebastian Reichel 
8768c0984e5SSebastian Reichel 	pdata = devm_kzalloc(dev, sizeof(*pdata), GFP_KERNEL);
8778c0984e5SSebastian Reichel 	if (!pdata)
8788c0984e5SSebastian Reichel 		return NULL;
8798c0984e5SSebastian Reichel 
8808c0984e5SSebastian Reichel 	/*
8818c0984e5SSebastian Reichel 	 * Require current sense resistor value to be specified for
8828c0984e5SSebastian Reichel 	 * current-sense functionality to be enabled at all.
8838c0984e5SSebastian Reichel 	 */
8848c0984e5SSebastian Reichel 	if (of_property_read_u32(np, "maxim,rsns-microohm", &prop) == 0) {
8858c0984e5SSebastian Reichel 		pdata->r_sns = prop;
8868c0984e5SSebastian Reichel 		pdata->enable_current_sense = true;
8878c0984e5SSebastian Reichel 	}
8888c0984e5SSebastian Reichel 
8898c0984e5SSebastian Reichel 	if (of_property_read_s32(np, "maxim,cold-temp", &pdata->temp_min))
8908c0984e5SSebastian Reichel 		pdata->temp_min = INT_MIN;
8918c0984e5SSebastian Reichel 	if (of_property_read_s32(np, "maxim,over-heat-temp", &pdata->temp_max))
8928c0984e5SSebastian Reichel 		pdata->temp_max = INT_MAX;
8938c0984e5SSebastian Reichel 	if (of_property_read_s32(np, "maxim,dead-volt", &pdata->vmin))
8948c0984e5SSebastian Reichel 		pdata->vmin = INT_MIN;
8958c0984e5SSebastian Reichel 	if (of_property_read_s32(np, "maxim,over-volt", &pdata->vmax))
8968c0984e5SSebastian Reichel 		pdata->vmax = INT_MAX;
8978c0984e5SSebastian Reichel 
8988c0984e5SSebastian Reichel 	return pdata;
8998c0984e5SSebastian Reichel }
9008c0984e5SSebastian Reichel #else
90191736213SHans de Goede static struct max17042_reg_data max17047_default_pdata_init_regs[] = {
90291736213SHans de Goede 	/*
90391736213SHans de Goede 	 * Some firmwares do not set FullSOCThr, Enable End-of-Charge Detection
90491736213SHans de Goede 	 * when the voltage FG reports 95%, as recommended in the datasheet.
90591736213SHans de Goede 	 */
90691736213SHans de Goede 	{ MAX17047_FullSOCThr, MAX17042_BATTERY_FULL << 8 },
90791736213SHans de Goede };
90891736213SHans de Goede 
9098c0984e5SSebastian Reichel static struct max17042_platform_data *
91091736213SHans de Goede max17042_get_pdata(struct max17042_chip *chip)
9118c0984e5SSebastian Reichel {
91291736213SHans de Goede 	struct device *dev = &chip->client->dev;
91391736213SHans de Goede 	struct max17042_platform_data *pdata;
91491736213SHans de Goede 	int ret, misc_cfg;
91591736213SHans de Goede 
91691736213SHans de Goede 	if (dev->platform_data)
9178c0984e5SSebastian Reichel 		return dev->platform_data;
91891736213SHans de Goede 
91991736213SHans de Goede 	/*
92091736213SHans de Goede 	 * The MAX17047 gets used on x86 where we might not have pdata, assume
92191736213SHans de Goede 	 * the firmware will already have initialized the fuel-gauge and provide
92291736213SHans de Goede 	 * default values for the non init bits to make things work.
92391736213SHans de Goede 	 */
92491736213SHans de Goede 	pdata = devm_kzalloc(dev, sizeof(*pdata), GFP_KERNEL);
92591736213SHans de Goede 	if (!pdata)
92691736213SHans de Goede 		return pdata;
92791736213SHans de Goede 
92891736213SHans de Goede 	if (chip->chip_type != MAXIM_DEVICE_TYPE_MAX17042) {
92991736213SHans de Goede 		pdata->init_data = max17047_default_pdata_init_regs;
93091736213SHans de Goede 		pdata->num_init_data =
93191736213SHans de Goede 			ARRAY_SIZE(max17047_default_pdata_init_regs);
93291736213SHans de Goede 	}
93391736213SHans de Goede 
93491736213SHans de Goede 	ret = regmap_read(chip->regmap, MAX17042_MiscCFG, &misc_cfg);
93591736213SHans de Goede 	if (ret < 0)
93691736213SHans de Goede 		return NULL;
93791736213SHans de Goede 
93891736213SHans de Goede 	/* If bits 0-1 are set to 3 then only Voltage readings are used */
93991736213SHans de Goede 	if ((misc_cfg & 0x3) == 0x3)
94091736213SHans de Goede 		pdata->enable_current_sense = false;
94191736213SHans de Goede 	else
94291736213SHans de Goede 		pdata->enable_current_sense = true;
94391736213SHans de Goede 
94491736213SHans de Goede 	pdata->vmin = MAX17042_DEFAULT_VMIN;
94591736213SHans de Goede 	pdata->vmax = MAX17042_DEFAULT_VMAX;
94691736213SHans de Goede 	pdata->temp_min = MAX17042_DEFAULT_TEMP_MIN;
94791736213SHans de Goede 	pdata->temp_max = MAX17042_DEFAULT_TEMP_MAX;
94891736213SHans de Goede 
94991736213SHans de Goede 	return pdata;
9508c0984e5SSebastian Reichel }
9518c0984e5SSebastian Reichel #endif
9528c0984e5SSebastian Reichel 
9538c0984e5SSebastian Reichel static const struct regmap_config max17042_regmap_config = {
9548c0984e5SSebastian Reichel 	.reg_bits = 8,
9558c0984e5SSebastian Reichel 	.val_bits = 16,
9568c0984e5SSebastian Reichel 	.val_format_endian = REGMAP_ENDIAN_NATIVE,
9578c0984e5SSebastian Reichel };
9588c0984e5SSebastian Reichel 
9598c0984e5SSebastian Reichel static const struct power_supply_desc max17042_psy_desc = {
9608c0984e5SSebastian Reichel 	.name		= "max170xx_battery",
9618c0984e5SSebastian Reichel 	.type		= POWER_SUPPLY_TYPE_BATTERY,
9628c0984e5SSebastian Reichel 	.get_property	= max17042_get_property,
9638c0984e5SSebastian Reichel 	.set_property	= max17042_set_property,
9648c0984e5SSebastian Reichel 	.property_is_writeable	= max17042_property_is_writeable,
965dcdddda8SHans de Goede 	.external_power_changed	= max17042_external_power_changed,
9668c0984e5SSebastian Reichel 	.properties	= max17042_battery_props,
9678c0984e5SSebastian Reichel 	.num_properties	= ARRAY_SIZE(max17042_battery_props),
9688c0984e5SSebastian Reichel };
9698c0984e5SSebastian Reichel 
9708c0984e5SSebastian Reichel static const struct power_supply_desc max17042_no_current_sense_psy_desc = {
9718c0984e5SSebastian Reichel 	.name		= "max170xx_battery",
9728c0984e5SSebastian Reichel 	.type		= POWER_SUPPLY_TYPE_BATTERY,
9738c0984e5SSebastian Reichel 	.get_property	= max17042_get_property,
9748c0984e5SSebastian Reichel 	.set_property	= max17042_set_property,
9758c0984e5SSebastian Reichel 	.property_is_writeable	= max17042_property_is_writeable,
9768c0984e5SSebastian Reichel 	.properties	= max17042_battery_props,
9778c0984e5SSebastian Reichel 	.num_properties	= ARRAY_SIZE(max17042_battery_props) - 2,
9788c0984e5SSebastian Reichel };
9798c0984e5SSebastian Reichel 
9808c0984e5SSebastian Reichel static int max17042_probe(struct i2c_client *client,
9818c0984e5SSebastian Reichel 			const struct i2c_device_id *id)
9828c0984e5SSebastian Reichel {
9838c0984e5SSebastian Reichel 	struct i2c_adapter *adapter = to_i2c_adapter(client->dev.parent);
9848c0984e5SSebastian Reichel 	const struct power_supply_desc *max17042_desc = &max17042_psy_desc;
9858c0984e5SSebastian Reichel 	struct power_supply_config psy_cfg = {};
986*e2116202SHans de Goede 	const struct acpi_device_id *acpi_id;
987*e2116202SHans de Goede 	struct device *dev = &client->dev;
9888c0984e5SSebastian Reichel 	struct max17042_chip *chip;
9898c0984e5SSebastian Reichel 	int ret;
9908c0984e5SSebastian Reichel 	int i;
9918c0984e5SSebastian Reichel 	u32 val;
9928c0984e5SSebastian Reichel 
9938c0984e5SSebastian Reichel 	if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_WORD_DATA))
9948c0984e5SSebastian Reichel 		return -EIO;
9958c0984e5SSebastian Reichel 
9968c0984e5SSebastian Reichel 	chip = devm_kzalloc(&client->dev, sizeof(*chip), GFP_KERNEL);
9978c0984e5SSebastian Reichel 	if (!chip)
9988c0984e5SSebastian Reichel 		return -ENOMEM;
9998c0984e5SSebastian Reichel 
10008c0984e5SSebastian Reichel 	chip->client = client;
1001*e2116202SHans de Goede 	if (id) {
100291736213SHans de Goede 		chip->chip_type = id->driver_data;
1003*e2116202SHans de Goede 	} else {
1004*e2116202SHans de Goede 		acpi_id = acpi_match_device(dev->driver->acpi_match_table, dev);
1005*e2116202SHans de Goede 		if (!acpi_id)
1006*e2116202SHans de Goede 			return -ENODEV;
1007*e2116202SHans de Goede 
1008*e2116202SHans de Goede 		chip->chip_type = acpi_id->driver_data;
1009*e2116202SHans de Goede 	}
10108c0984e5SSebastian Reichel 	chip->regmap = devm_regmap_init_i2c(client, &max17042_regmap_config);
10118c0984e5SSebastian Reichel 	if (IS_ERR(chip->regmap)) {
10128c0984e5SSebastian Reichel 		dev_err(&client->dev, "Failed to initialize regmap\n");
10138c0984e5SSebastian Reichel 		return -EINVAL;
10148c0984e5SSebastian Reichel 	}
10158c0984e5SSebastian Reichel 
101691736213SHans de Goede 	chip->pdata = max17042_get_pdata(chip);
10178c0984e5SSebastian Reichel 	if (!chip->pdata) {
10188c0984e5SSebastian Reichel 		dev_err(&client->dev, "no platform data provided\n");
10198c0984e5SSebastian Reichel 		return -EINVAL;
10208c0984e5SSebastian Reichel 	}
10218c0984e5SSebastian Reichel 
10228c0984e5SSebastian Reichel 	i2c_set_clientdata(client, chip);
10238c0984e5SSebastian Reichel 	psy_cfg.drv_data = chip;
10248c0984e5SSebastian Reichel 
10258c0984e5SSebastian Reichel 	/* When current is not measured,
10268c0984e5SSebastian Reichel 	 * CURRENT_NOW and CURRENT_AVG properties should be invisible. */
10278c0984e5SSebastian Reichel 	if (!chip->pdata->enable_current_sense)
10288c0984e5SSebastian Reichel 		max17042_desc = &max17042_no_current_sense_psy_desc;
10298c0984e5SSebastian Reichel 
10308c0984e5SSebastian Reichel 	if (chip->pdata->r_sns == 0)
10318c0984e5SSebastian Reichel 		chip->pdata->r_sns = MAX17042_DEFAULT_SNS_RESISTOR;
10328c0984e5SSebastian Reichel 
10338c0984e5SSebastian Reichel 	if (chip->pdata->init_data)
10348c0984e5SSebastian Reichel 		for (i = 0; i < chip->pdata->num_init_data; i++)
10358c0984e5SSebastian Reichel 			regmap_write(chip->regmap,
10368c0984e5SSebastian Reichel 					chip->pdata->init_data[i].addr,
10378c0984e5SSebastian Reichel 					chip->pdata->init_data[i].data);
10388c0984e5SSebastian Reichel 
10398c0984e5SSebastian Reichel 	if (!chip->pdata->enable_current_sense) {
10408c0984e5SSebastian Reichel 		regmap_write(chip->regmap, MAX17042_CGAIN, 0x0000);
10418c0984e5SSebastian Reichel 		regmap_write(chip->regmap, MAX17042_MiscCFG, 0x0003);
10428c0984e5SSebastian Reichel 		regmap_write(chip->regmap, MAX17042_LearnCFG, 0x0007);
10438c0984e5SSebastian Reichel 	}
10448c0984e5SSebastian Reichel 
10458c0984e5SSebastian Reichel 	chip->battery = devm_power_supply_register(&client->dev, max17042_desc,
10468c0984e5SSebastian Reichel 						   &psy_cfg);
10478c0984e5SSebastian Reichel 	if (IS_ERR(chip->battery)) {
10488c0984e5SSebastian Reichel 		dev_err(&client->dev, "failed: power supply register\n");
10498c0984e5SSebastian Reichel 		return PTR_ERR(chip->battery);
10508c0984e5SSebastian Reichel 	}
10518c0984e5SSebastian Reichel 
10528c0984e5SSebastian Reichel 	if (client->irq) {
10538c0984e5SSebastian Reichel 		ret = devm_request_threaded_irq(&client->dev, client->irq,
10548c0984e5SSebastian Reichel 						NULL,
10558c0984e5SSebastian Reichel 						max17042_thread_handler,
10568c0984e5SSebastian Reichel 						IRQF_TRIGGER_FALLING |
10578c0984e5SSebastian Reichel 						IRQF_ONESHOT,
10588c0984e5SSebastian Reichel 						chip->battery->desc->name,
10598c0984e5SSebastian Reichel 						chip);
10608c0984e5SSebastian Reichel 		if (!ret) {
10618c0984e5SSebastian Reichel 			regmap_update_bits(chip->regmap, MAX17042_CONFIG,
10628c0984e5SSebastian Reichel 					CONFIG_ALRT_BIT_ENBL,
10638c0984e5SSebastian Reichel 					CONFIG_ALRT_BIT_ENBL);
10648c0984e5SSebastian Reichel 			max17042_set_soc_threshold(chip, 1);
10658c0984e5SSebastian Reichel 		} else {
10668c0984e5SSebastian Reichel 			client->irq = 0;
10678c0984e5SSebastian Reichel 			dev_err(&client->dev, "%s(): cannot get IRQ\n",
10688c0984e5SSebastian Reichel 				__func__);
10698c0984e5SSebastian Reichel 		}
10708c0984e5SSebastian Reichel 	}
10718c0984e5SSebastian Reichel 
10728c0984e5SSebastian Reichel 	regmap_read(chip->regmap, MAX17042_STATUS, &val);
10738c0984e5SSebastian Reichel 	if (val & STATUS_POR_BIT) {
10748c0984e5SSebastian Reichel 		INIT_WORK(&chip->work, max17042_init_worker);
10758c0984e5SSebastian Reichel 		schedule_work(&chip->work);
10768c0984e5SSebastian Reichel 	} else {
10778c0984e5SSebastian Reichel 		chip->init_complete = 1;
10788c0984e5SSebastian Reichel 	}
10798c0984e5SSebastian Reichel 
10808c0984e5SSebastian Reichel 	return 0;
10818c0984e5SSebastian Reichel }
10828c0984e5SSebastian Reichel 
10838c0984e5SSebastian Reichel #ifdef CONFIG_PM_SLEEP
10848c0984e5SSebastian Reichel static int max17042_suspend(struct device *dev)
10858c0984e5SSebastian Reichel {
10868c0984e5SSebastian Reichel 	struct max17042_chip *chip = dev_get_drvdata(dev);
10878c0984e5SSebastian Reichel 
10888c0984e5SSebastian Reichel 	/*
10898c0984e5SSebastian Reichel 	 * disable the irq and enable irq_wake
10908c0984e5SSebastian Reichel 	 * capability to the interrupt line.
10918c0984e5SSebastian Reichel 	 */
10928c0984e5SSebastian Reichel 	if (chip->client->irq) {
10938c0984e5SSebastian Reichel 		disable_irq(chip->client->irq);
10948c0984e5SSebastian Reichel 		enable_irq_wake(chip->client->irq);
10958c0984e5SSebastian Reichel 	}
10968c0984e5SSebastian Reichel 
10978c0984e5SSebastian Reichel 	return 0;
10988c0984e5SSebastian Reichel }
10998c0984e5SSebastian Reichel 
11008c0984e5SSebastian Reichel static int max17042_resume(struct device *dev)
11018c0984e5SSebastian Reichel {
11028c0984e5SSebastian Reichel 	struct max17042_chip *chip = dev_get_drvdata(dev);
11038c0984e5SSebastian Reichel 
11048c0984e5SSebastian Reichel 	if (chip->client->irq) {
11058c0984e5SSebastian Reichel 		disable_irq_wake(chip->client->irq);
11068c0984e5SSebastian Reichel 		enable_irq(chip->client->irq);
11078c0984e5SSebastian Reichel 		/* re-program the SOC thresholds to 1% change */
11088c0984e5SSebastian Reichel 		max17042_set_soc_threshold(chip, 1);
11098c0984e5SSebastian Reichel 	}
11108c0984e5SSebastian Reichel 
11118c0984e5SSebastian Reichel 	return 0;
11128c0984e5SSebastian Reichel }
11138c0984e5SSebastian Reichel #endif
11148c0984e5SSebastian Reichel 
11158c0984e5SSebastian Reichel static SIMPLE_DEV_PM_OPS(max17042_pm_ops, max17042_suspend,
11168c0984e5SSebastian Reichel 			max17042_resume);
11178c0984e5SSebastian Reichel 
1118*e2116202SHans de Goede #ifdef CONFIG_ACPI
1119*e2116202SHans de Goede static const struct acpi_device_id max17042_acpi_match[] = {
1120*e2116202SHans de Goede 	{ "MAX17047", MAXIM_DEVICE_TYPE_MAX17047 },
1121*e2116202SHans de Goede 	{ }
1122*e2116202SHans de Goede };
1123*e2116202SHans de Goede MODULE_DEVICE_TABLE(acpi, max17042_acpi_match);
1124*e2116202SHans de Goede #endif
1125*e2116202SHans de Goede 
11268c0984e5SSebastian Reichel #ifdef CONFIG_OF
11278c0984e5SSebastian Reichel static const struct of_device_id max17042_dt_match[] = {
11288c0984e5SSebastian Reichel 	{ .compatible = "maxim,max17042" },
11298c0984e5SSebastian Reichel 	{ .compatible = "maxim,max17047" },
11308c0984e5SSebastian Reichel 	{ .compatible = "maxim,max17050" },
11318c0984e5SSebastian Reichel 	{ },
11328c0984e5SSebastian Reichel };
11338c0984e5SSebastian Reichel MODULE_DEVICE_TABLE(of, max17042_dt_match);
11348c0984e5SSebastian Reichel #endif
11358c0984e5SSebastian Reichel 
11368c0984e5SSebastian Reichel static const struct i2c_device_id max17042_id[] = {
11378c0984e5SSebastian Reichel 	{ "max17042", MAXIM_DEVICE_TYPE_MAX17042 },
11388c0984e5SSebastian Reichel 	{ "max17047", MAXIM_DEVICE_TYPE_MAX17047 },
11398c0984e5SSebastian Reichel 	{ "max17050", MAXIM_DEVICE_TYPE_MAX17050 },
11408c0984e5SSebastian Reichel 	{ }
11418c0984e5SSebastian Reichel };
11428c0984e5SSebastian Reichel MODULE_DEVICE_TABLE(i2c, max17042_id);
11438c0984e5SSebastian Reichel 
11448c0984e5SSebastian Reichel static struct i2c_driver max17042_i2c_driver = {
11458c0984e5SSebastian Reichel 	.driver	= {
11468c0984e5SSebastian Reichel 		.name	= "max17042",
1147*e2116202SHans de Goede 		.acpi_match_table = ACPI_PTR(max17042_acpi_match),
11488c0984e5SSebastian Reichel 		.of_match_table = of_match_ptr(max17042_dt_match),
11498c0984e5SSebastian Reichel 		.pm	= &max17042_pm_ops,
11508c0984e5SSebastian Reichel 	},
11518c0984e5SSebastian Reichel 	.probe		= max17042_probe,
11528c0984e5SSebastian Reichel 	.id_table	= max17042_id,
11538c0984e5SSebastian Reichel };
11548c0984e5SSebastian Reichel module_i2c_driver(max17042_i2c_driver);
11558c0984e5SSebastian Reichel 
11568c0984e5SSebastian Reichel MODULE_AUTHOR("MyungJoo Ham <myungjoo.ham@samsung.com>");
11578c0984e5SSebastian Reichel MODULE_DESCRIPTION("MAX17042 Fuel Gauge");
11588c0984e5SSebastian Reichel MODULE_LICENSE("GPL");
1159