xref: /openbmc/linux/drivers/power/supply/max17040_battery.c (revision 4f7f8e87c49e029a52318dd76d561860119d0372)
17b38ebdfSKrzysztof Kozlowski // SPDX-License-Identifier: GPL-2.0
27b38ebdfSKrzysztof Kozlowski //
37b38ebdfSKrzysztof Kozlowski //  max17040_battery.c
47b38ebdfSKrzysztof Kozlowski //  fuel-gauge systems for lithium-ion (Li+) batteries
57b38ebdfSKrzysztof Kozlowski //
67b38ebdfSKrzysztof Kozlowski //  Copyright (C) 2009 Samsung Electronics
77b38ebdfSKrzysztof Kozlowski //  Minkyu Kang <mk7.kang@samsung.com>
88c0984e5SSebastian Reichel 
98c0984e5SSebastian Reichel #include <linux/module.h>
108c0984e5SSebastian Reichel #include <linux/init.h>
118c0984e5SSebastian Reichel #include <linux/platform_device.h>
128c0984e5SSebastian Reichel #include <linux/mutex.h>
138c0984e5SSebastian Reichel #include <linux/err.h>
148c0984e5SSebastian Reichel #include <linux/i2c.h>
158c0984e5SSebastian Reichel #include <linux/delay.h>
162e17ed94SMatheus Castello #include <linux/interrupt.h>
178c0984e5SSebastian Reichel #include <linux/power_supply.h>
18*4f7f8e87SIskren Chernev #include <linux/of_device.h>
198c0984e5SSebastian Reichel #include <linux/max17040_battery.h>
206455a8a8SIskren Chernev #include <linux/regmap.h>
218c0984e5SSebastian Reichel #include <linux/slab.h>
228c0984e5SSebastian Reichel 
2314d60bddSLiu Xiang #define MAX17040_VCELL	0x02
2414d60bddSLiu Xiang #define MAX17040_SOC	0x04
2514d60bddSLiu Xiang #define MAX17040_MODE	0x06
2614d60bddSLiu Xiang #define MAX17040_VER	0x08
276455a8a8SIskren Chernev #define MAX17040_CONFIG	0x0C
2814d60bddSLiu Xiang #define MAX17040_CMD	0xFE
2914d60bddSLiu Xiang 
308c0984e5SSebastian Reichel 
318c0984e5SSebastian Reichel #define MAX17040_DELAY		1000
328c0984e5SSebastian Reichel #define MAX17040_BATTERY_FULL	95
338c0984e5SSebastian Reichel 
346455a8a8SIskren Chernev #define MAX17040_ATHD_MASK		0x3f
35cccdd0caSMatheus Castello #define MAX17040_ATHD_DEFAULT_POWER_UP	4
36cccdd0caSMatheus Castello 
37*4f7f8e87SIskren Chernev enum chip_id {
38*4f7f8e87SIskren Chernev 	ID_MAX17040,
39*4f7f8e87SIskren Chernev 	ID_MAX17041,
40*4f7f8e87SIskren Chernev 	ID_MAX17043,
41*4f7f8e87SIskren Chernev 	ID_MAX17044,
42*4f7f8e87SIskren Chernev 	ID_MAX17048,
43*4f7f8e87SIskren Chernev 	ID_MAX17049,
44*4f7f8e87SIskren Chernev 	ID_MAX17058,
45*4f7f8e87SIskren Chernev 	ID_MAX17059,
46*4f7f8e87SIskren Chernev };
47*4f7f8e87SIskren Chernev 
48*4f7f8e87SIskren Chernev /* values that differ by chip_id */
49*4f7f8e87SIskren Chernev struct chip_data {
50*4f7f8e87SIskren Chernev 	u16 reset_val;
51*4f7f8e87SIskren Chernev 	u16 vcell_shift;
52*4f7f8e87SIskren Chernev 	u16 vcell_mul;
53*4f7f8e87SIskren Chernev 	u16 vcell_div;
54*4f7f8e87SIskren Chernev 	u8  has_low_soc_alert;
55*4f7f8e87SIskren Chernev };
56*4f7f8e87SIskren Chernev 
57*4f7f8e87SIskren Chernev static struct chip_data max17040_family[] = {
58*4f7f8e87SIskren Chernev 	[ID_MAX17040] = {
59*4f7f8e87SIskren Chernev 		.reset_val = 0x0054,
60*4f7f8e87SIskren Chernev 		.vcell_shift = 4,
61*4f7f8e87SIskren Chernev 		.vcell_mul = 1250,
62*4f7f8e87SIskren Chernev 		.vcell_div = 1,
63*4f7f8e87SIskren Chernev 		.has_low_soc_alert = 0,
64*4f7f8e87SIskren Chernev 	},
65*4f7f8e87SIskren Chernev 	[ID_MAX17041] = {
66*4f7f8e87SIskren Chernev 		.reset_val = 0x0054,
67*4f7f8e87SIskren Chernev 		.vcell_shift = 4,
68*4f7f8e87SIskren Chernev 		.vcell_mul = 2500,
69*4f7f8e87SIskren Chernev 		.vcell_div = 1,
70*4f7f8e87SIskren Chernev 		.has_low_soc_alert = 0,
71*4f7f8e87SIskren Chernev 	},
72*4f7f8e87SIskren Chernev 	[ID_MAX17043] = {
73*4f7f8e87SIskren Chernev 		.reset_val = 0x0054,
74*4f7f8e87SIskren Chernev 		.vcell_shift = 4,
75*4f7f8e87SIskren Chernev 		.vcell_mul = 1250,
76*4f7f8e87SIskren Chernev 		.vcell_div = 1,
77*4f7f8e87SIskren Chernev 		.has_low_soc_alert = 1,
78*4f7f8e87SIskren Chernev 	},
79*4f7f8e87SIskren Chernev 	[ID_MAX17044] = {
80*4f7f8e87SIskren Chernev 		.reset_val = 0x0054,
81*4f7f8e87SIskren Chernev 		.vcell_shift = 4,
82*4f7f8e87SIskren Chernev 		.vcell_mul = 2500,
83*4f7f8e87SIskren Chernev 		.vcell_div = 1,
84*4f7f8e87SIskren Chernev 		.has_low_soc_alert = 1,
85*4f7f8e87SIskren Chernev 	},
86*4f7f8e87SIskren Chernev 	[ID_MAX17048] = {
87*4f7f8e87SIskren Chernev 		.reset_val = 0x5400,
88*4f7f8e87SIskren Chernev 		.vcell_shift = 0,
89*4f7f8e87SIskren Chernev 		.vcell_mul = 625,
90*4f7f8e87SIskren Chernev 		.vcell_div = 8,
91*4f7f8e87SIskren Chernev 		.has_low_soc_alert = 1,
92*4f7f8e87SIskren Chernev 	},
93*4f7f8e87SIskren Chernev 	[ID_MAX17049] = {
94*4f7f8e87SIskren Chernev 		.reset_val = 0x5400,
95*4f7f8e87SIskren Chernev 		.vcell_shift = 0,
96*4f7f8e87SIskren Chernev 		.vcell_mul = 625,
97*4f7f8e87SIskren Chernev 		.vcell_div = 4,
98*4f7f8e87SIskren Chernev 		.has_low_soc_alert = 1,
99*4f7f8e87SIskren Chernev 	},
100*4f7f8e87SIskren Chernev 	[ID_MAX17058] = {
101*4f7f8e87SIskren Chernev 		.reset_val = 0x5400,
102*4f7f8e87SIskren Chernev 		.vcell_shift = 0,
103*4f7f8e87SIskren Chernev 		.vcell_mul = 625,
104*4f7f8e87SIskren Chernev 		.vcell_div = 8,
105*4f7f8e87SIskren Chernev 		.has_low_soc_alert = 1,
106*4f7f8e87SIskren Chernev 	},
107*4f7f8e87SIskren Chernev 	[ID_MAX17059] = {
108*4f7f8e87SIskren Chernev 		.reset_val = 0x5400,
109*4f7f8e87SIskren Chernev 		.vcell_shift = 0,
110*4f7f8e87SIskren Chernev 		.vcell_mul = 625,
111*4f7f8e87SIskren Chernev 		.vcell_div = 4,
112*4f7f8e87SIskren Chernev 		.has_low_soc_alert = 1,
113*4f7f8e87SIskren Chernev 	},
114*4f7f8e87SIskren Chernev };
115*4f7f8e87SIskren Chernev 
1168c0984e5SSebastian Reichel struct max17040_chip {
1178c0984e5SSebastian Reichel 	struct i2c_client		*client;
1186455a8a8SIskren Chernev 	struct regmap			*regmap;
1198c0984e5SSebastian Reichel 	struct delayed_work		work;
1208c0984e5SSebastian Reichel 	struct power_supply		*battery;
1218c0984e5SSebastian Reichel 	struct max17040_platform_data	*pdata;
122*4f7f8e87SIskren Chernev 	struct chip_data		data;
1238c0984e5SSebastian Reichel 
1248c0984e5SSebastian Reichel 	/* battery capacity */
1258c0984e5SSebastian Reichel 	int soc;
1268c0984e5SSebastian Reichel 	/* State Of Charge */
1278c0984e5SSebastian Reichel 	int status;
128cccdd0caSMatheus Castello 	/* Low alert threshold from 32% to 1% of the State of Charge */
129cccdd0caSMatheus Castello 	u32 low_soc_alert;
130*4f7f8e87SIskren Chernev 	/* some devices return twice the capacity */
131*4f7f8e87SIskren Chernev 	bool quirk_double_soc;
1328c0984e5SSebastian Reichel };
1338c0984e5SSebastian Reichel 
1346455a8a8SIskren Chernev static int max17040_reset(struct max17040_chip *chip)
1358c0984e5SSebastian Reichel {
136*4f7f8e87SIskren Chernev 	return regmap_write(chip->regmap, MAX17040_CMD, chip->data.reset_val);
1378c0984e5SSebastian Reichel }
1388c0984e5SSebastian Reichel 
1396455a8a8SIskren Chernev static int max17040_set_low_soc_alert(struct max17040_chip *chip, u32 level)
1408c0984e5SSebastian Reichel {
141*4f7f8e87SIskren Chernev 	level = 32 - level * (chip->quirk_double_soc ? 2 : 1);
1426455a8a8SIskren Chernev 	return regmap_update_bits(chip->regmap, MAX17040_CONFIG,
1436455a8a8SIskren Chernev 			MAX17040_ATHD_MASK, level);
144cccdd0caSMatheus Castello }
145cccdd0caSMatheus Castello 
146*4f7f8e87SIskren Chernev static int max17040_raw_vcell_to_uvolts(struct max17040_chip *chip, u16 vcell)
147*4f7f8e87SIskren Chernev {
148*4f7f8e87SIskren Chernev 	struct chip_data *d = &chip->data;
149*4f7f8e87SIskren Chernev 
150*4f7f8e87SIskren Chernev 	return (vcell >> d->vcell_shift) * d->vcell_mul / d->vcell_div;
151*4f7f8e87SIskren Chernev }
152*4f7f8e87SIskren Chernev 
153*4f7f8e87SIskren Chernev 
1546455a8a8SIskren Chernev static int max17040_get_vcell(struct max17040_chip *chip)
1558c0984e5SSebastian Reichel {
1566455a8a8SIskren Chernev 	u32 vcell;
1578c0984e5SSebastian Reichel 
1586455a8a8SIskren Chernev 	regmap_read(chip->regmap, MAX17040_VCELL, &vcell);
1598c0984e5SSebastian Reichel 
160*4f7f8e87SIskren Chernev 	return max17040_raw_vcell_to_uvolts(chip, vcell);
1618c0984e5SSebastian Reichel }
1628c0984e5SSebastian Reichel 
1636455a8a8SIskren Chernev static int max17040_get_soc(struct max17040_chip *chip)
1648c0984e5SSebastian Reichel {
1656455a8a8SIskren Chernev 	u32 soc;
1668c0984e5SSebastian Reichel 
1676455a8a8SIskren Chernev 	regmap_read(chip->regmap, MAX17040_SOC, &soc);
1688c0984e5SSebastian Reichel 
169*4f7f8e87SIskren Chernev 	return soc >> (chip->quirk_double_soc ? 9 : 8);
1708c0984e5SSebastian Reichel }
1718c0984e5SSebastian Reichel 
1726455a8a8SIskren Chernev static int max17040_get_version(struct max17040_chip *chip)
1738c0984e5SSebastian Reichel {
1746455a8a8SIskren Chernev 	int ret;
1756455a8a8SIskren Chernev 	u32 version;
1768c0984e5SSebastian Reichel 
1776455a8a8SIskren Chernev 	ret = regmap_read(chip->regmap, MAX17040_VER, &version);
1788c0984e5SSebastian Reichel 
1796455a8a8SIskren Chernev 	return ret ? ret : version;
1808c0984e5SSebastian Reichel }
1818c0984e5SSebastian Reichel 
1826455a8a8SIskren Chernev static int max17040_get_online(struct max17040_chip *chip)
1838c0984e5SSebastian Reichel {
1846455a8a8SIskren Chernev 	return chip->pdata && chip->pdata->battery_online ?
1856455a8a8SIskren Chernev 		chip->pdata->battery_online() : 1;
1868c0984e5SSebastian Reichel }
1878c0984e5SSebastian Reichel 
1886455a8a8SIskren Chernev static int max17040_get_status(struct max17040_chip *chip)
1898c0984e5SSebastian Reichel {
1908c0984e5SSebastian Reichel 	if (!chip->pdata || !chip->pdata->charger_online
1916455a8a8SIskren Chernev 			|| !chip->pdata->charger_enable)
1926455a8a8SIskren Chernev 		return POWER_SUPPLY_STATUS_UNKNOWN;
1938c0984e5SSebastian Reichel 
1946455a8a8SIskren Chernev 	if (max17040_get_soc(chip) > MAX17040_BATTERY_FULL)
1956455a8a8SIskren Chernev 		return POWER_SUPPLY_STATUS_FULL;
1966455a8a8SIskren Chernev 
1976455a8a8SIskren Chernev 	if (chip->pdata->charger_online())
1988c0984e5SSebastian Reichel 		if (chip->pdata->charger_enable())
1996455a8a8SIskren Chernev 			return POWER_SUPPLY_STATUS_CHARGING;
2008c0984e5SSebastian Reichel 		else
2016455a8a8SIskren Chernev 			return POWER_SUPPLY_STATUS_NOT_CHARGING;
2026455a8a8SIskren Chernev 	else
2036455a8a8SIskren Chernev 		return POWER_SUPPLY_STATUS_DISCHARGING;
2048c0984e5SSebastian Reichel }
2058c0984e5SSebastian Reichel 
206cccdd0caSMatheus Castello static int max17040_get_of_data(struct max17040_chip *chip)
207cccdd0caSMatheus Castello {
208cccdd0caSMatheus Castello 	struct device *dev = &chip->client->dev;
209cccdd0caSMatheus Castello 
210*4f7f8e87SIskren Chernev 	chip->quirk_double_soc = device_property_read_bool(dev,
211*4f7f8e87SIskren Chernev 							   "maxim,double-soc");
212*4f7f8e87SIskren Chernev 
213cccdd0caSMatheus Castello 	chip->low_soc_alert = MAX17040_ATHD_DEFAULT_POWER_UP;
214cccdd0caSMatheus Castello 	device_property_read_u32(dev,
215cccdd0caSMatheus Castello 				 "maxim,alert-low-soc-level",
216cccdd0caSMatheus Castello 				 &chip->low_soc_alert);
217cccdd0caSMatheus Castello 
218*4f7f8e87SIskren Chernev 	if (chip->low_soc_alert <= 0 ||
219*4f7f8e87SIskren Chernev 	    chip->low_soc_alert > (chip->quirk_double_soc ? 16 : 32)) {
2206455a8a8SIskren Chernev 		dev_err(dev, "maxim,alert-low-soc-level out of bounds\n");
221cccdd0caSMatheus Castello 		return -EINVAL;
2226455a8a8SIskren Chernev 	}
223cccdd0caSMatheus Castello 
224cccdd0caSMatheus Castello 	return 0;
225cccdd0caSMatheus Castello }
226cccdd0caSMatheus Castello 
2276455a8a8SIskren Chernev static void max17040_check_changes(struct max17040_chip *chip)
2282e17ed94SMatheus Castello {
2296455a8a8SIskren Chernev 	chip->soc = max17040_get_soc(chip);
2306455a8a8SIskren Chernev 	chip->status = max17040_get_status(chip);
2312e17ed94SMatheus Castello }
2322e17ed94SMatheus Castello 
233e55a5061SIskren Chernev static void max17040_queue_work(struct max17040_chip *chip)
234e55a5061SIskren Chernev {
235e55a5061SIskren Chernev 	queue_delayed_work(system_power_efficient_wq, &chip->work,
236e55a5061SIskren Chernev 			   MAX17040_DELAY);
237e55a5061SIskren Chernev }
238e55a5061SIskren Chernev 
239e55a5061SIskren Chernev static void max17040_stop_work(void *data)
240e55a5061SIskren Chernev {
241e55a5061SIskren Chernev 	struct max17040_chip *chip = data;
242e55a5061SIskren Chernev 
243e55a5061SIskren Chernev 	cancel_delayed_work_sync(&chip->work);
244e55a5061SIskren Chernev }
245e55a5061SIskren Chernev 
2468c0984e5SSebastian Reichel static void max17040_work(struct work_struct *work)
2478c0984e5SSebastian Reichel {
2488c0984e5SSebastian Reichel 	struct max17040_chip *chip;
249a08990eaSMatheus Castello 	int last_soc, last_status;
2508c0984e5SSebastian Reichel 
2518c0984e5SSebastian Reichel 	chip = container_of(work, struct max17040_chip, work.work);
252a08990eaSMatheus Castello 
253a08990eaSMatheus Castello 	/* store SOC and status to check changes */
254a08990eaSMatheus Castello 	last_soc = chip->soc;
255a08990eaSMatheus Castello 	last_status = chip->status;
2566455a8a8SIskren Chernev 	max17040_check_changes(chip);
2578c0984e5SSebastian Reichel 
258a08990eaSMatheus Castello 	/* check changes and send uevent */
259a08990eaSMatheus Castello 	if (last_soc != chip->soc || last_status != chip->status)
260a08990eaSMatheus Castello 		power_supply_changed(chip->battery);
261a08990eaSMatheus Castello 
262e55a5061SIskren Chernev 	max17040_queue_work(chip);
2638c0984e5SSebastian Reichel }
2648c0984e5SSebastian Reichel 
2652e17ed94SMatheus Castello static irqreturn_t max17040_thread_handler(int id, void *dev)
2662e17ed94SMatheus Castello {
2672e17ed94SMatheus Castello 	struct max17040_chip *chip = dev;
2682e17ed94SMatheus Castello 
2696455a8a8SIskren Chernev 	dev_warn(&chip->client->dev, "IRQ: Alert battery low level");
2706455a8a8SIskren Chernev 
2712e17ed94SMatheus Castello 	/* read registers */
2726455a8a8SIskren Chernev 	max17040_check_changes(chip);
2732e17ed94SMatheus Castello 
2742e17ed94SMatheus Castello 	/* send uevent */
2752e17ed94SMatheus Castello 	power_supply_changed(chip->battery);
2762e17ed94SMatheus Castello 
277cccdd0caSMatheus Castello 	/* reset alert bit */
2786455a8a8SIskren Chernev 	max17040_set_low_soc_alert(chip, chip->low_soc_alert);
279cccdd0caSMatheus Castello 
2802e17ed94SMatheus Castello 	return IRQ_HANDLED;
2812e17ed94SMatheus Castello }
2822e17ed94SMatheus Castello 
2832e17ed94SMatheus Castello static int max17040_enable_alert_irq(struct max17040_chip *chip)
2842e17ed94SMatheus Castello {
2852e17ed94SMatheus Castello 	struct i2c_client *client = chip->client;
2862e17ed94SMatheus Castello 	unsigned int flags;
2872e17ed94SMatheus Castello 	int ret;
2882e17ed94SMatheus Castello 
2892e17ed94SMatheus Castello 	flags = IRQF_TRIGGER_FALLING | IRQF_ONESHOT;
2902e17ed94SMatheus Castello 	ret = devm_request_threaded_irq(&client->dev, client->irq, NULL,
2912e17ed94SMatheus Castello 					max17040_thread_handler, flags,
2922e17ed94SMatheus Castello 					chip->battery->desc->name, chip);
2932e17ed94SMatheus Castello 
2942e17ed94SMatheus Castello 	return ret;
2952e17ed94SMatheus Castello }
2962e17ed94SMatheus Castello 
2972f38dc4dSMatheus Castello static int max17040_prop_writeable(struct power_supply *psy,
2982f38dc4dSMatheus Castello 				   enum power_supply_property psp)
2992f38dc4dSMatheus Castello {
3002f38dc4dSMatheus Castello 	switch (psp) {
3012f38dc4dSMatheus Castello 	case POWER_SUPPLY_PROP_CAPACITY_ALERT_MIN:
3022f38dc4dSMatheus Castello 		return 1;
3032f38dc4dSMatheus Castello 	default:
3042f38dc4dSMatheus Castello 		return 0;
3052f38dc4dSMatheus Castello 	}
3062f38dc4dSMatheus Castello }
3072f38dc4dSMatheus Castello 
3082f38dc4dSMatheus Castello static int max17040_set_property(struct power_supply *psy,
3092f38dc4dSMatheus Castello 			    enum power_supply_property psp,
3102f38dc4dSMatheus Castello 			    const union power_supply_propval *val)
3112f38dc4dSMatheus Castello {
3122f38dc4dSMatheus Castello 	struct max17040_chip *chip = power_supply_get_drvdata(psy);
3132f38dc4dSMatheus Castello 	int ret;
3142f38dc4dSMatheus Castello 
3152f38dc4dSMatheus Castello 	switch (psp) {
3162f38dc4dSMatheus Castello 	case POWER_SUPPLY_PROP_CAPACITY_ALERT_MIN:
317*4f7f8e87SIskren Chernev 		/* alert threshold can be programmed from 1% up to 16/32% */
318*4f7f8e87SIskren Chernev 		if ((val->intval < 1) ||
319*4f7f8e87SIskren Chernev 		    (val->intval > (chip->quirk_double_soc ? 16 : 32))) {
3202f38dc4dSMatheus Castello 			ret = -EINVAL;
3212f38dc4dSMatheus Castello 			break;
3222f38dc4dSMatheus Castello 		}
3236455a8a8SIskren Chernev 		ret = max17040_set_low_soc_alert(chip, val->intval);
3242f38dc4dSMatheus Castello 		chip->low_soc_alert = val->intval;
3252f38dc4dSMatheus Castello 		break;
3262f38dc4dSMatheus Castello 	default:
3272f38dc4dSMatheus Castello 		ret = -EINVAL;
3282f38dc4dSMatheus Castello 	}
3292f38dc4dSMatheus Castello 
3302f38dc4dSMatheus Castello 	return ret;
3312f38dc4dSMatheus Castello }
3322f38dc4dSMatheus Castello 
3336455a8a8SIskren Chernev static int max17040_get_property(struct power_supply *psy,
3346455a8a8SIskren Chernev 			    enum power_supply_property psp,
3356455a8a8SIskren Chernev 			    union power_supply_propval *val)
3366455a8a8SIskren Chernev {
3376455a8a8SIskren Chernev 	struct max17040_chip *chip = power_supply_get_drvdata(psy);
3386455a8a8SIskren Chernev 
3396455a8a8SIskren Chernev 	switch (psp) {
3406455a8a8SIskren Chernev 	case POWER_SUPPLY_PROP_STATUS:
3416455a8a8SIskren Chernev 		val->intval = max17040_get_status(chip);
3426455a8a8SIskren Chernev 		break;
3436455a8a8SIskren Chernev 	case POWER_SUPPLY_PROP_ONLINE:
3446455a8a8SIskren Chernev 		val->intval = max17040_get_online(chip);
3456455a8a8SIskren Chernev 		break;
3466455a8a8SIskren Chernev 	case POWER_SUPPLY_PROP_VOLTAGE_NOW:
3476455a8a8SIskren Chernev 		val->intval = max17040_get_vcell(chip);
3486455a8a8SIskren Chernev 		break;
3496455a8a8SIskren Chernev 	case POWER_SUPPLY_PROP_CAPACITY:
3506455a8a8SIskren Chernev 		val->intval = max17040_get_soc(chip);
3516455a8a8SIskren Chernev 		break;
3526455a8a8SIskren Chernev 	case POWER_SUPPLY_PROP_CAPACITY_ALERT_MIN:
3536455a8a8SIskren Chernev 		val->intval = chip->low_soc_alert;
3546455a8a8SIskren Chernev 		break;
3556455a8a8SIskren Chernev 	default:
3566455a8a8SIskren Chernev 		return -EINVAL;
3576455a8a8SIskren Chernev 	}
3586455a8a8SIskren Chernev 	return 0;
3596455a8a8SIskren Chernev }
3606455a8a8SIskren Chernev 
3616455a8a8SIskren Chernev static const struct regmap_config max17040_regmap = {
3626455a8a8SIskren Chernev 	.reg_bits	= 8,
3636455a8a8SIskren Chernev 	.reg_stride	= 2,
3646455a8a8SIskren Chernev 	.val_bits	= 16,
3656455a8a8SIskren Chernev 	.val_format_endian = REGMAP_ENDIAN_BIG,
3666455a8a8SIskren Chernev };
3676455a8a8SIskren Chernev 
3688c0984e5SSebastian Reichel static enum power_supply_property max17040_battery_props[] = {
3698c0984e5SSebastian Reichel 	POWER_SUPPLY_PROP_STATUS,
3708c0984e5SSebastian Reichel 	POWER_SUPPLY_PROP_ONLINE,
3718c0984e5SSebastian Reichel 	POWER_SUPPLY_PROP_VOLTAGE_NOW,
3728c0984e5SSebastian Reichel 	POWER_SUPPLY_PROP_CAPACITY,
3732f38dc4dSMatheus Castello 	POWER_SUPPLY_PROP_CAPACITY_ALERT_MIN,
3748c0984e5SSebastian Reichel };
3758c0984e5SSebastian Reichel 
3768c0984e5SSebastian Reichel static const struct power_supply_desc max17040_battery_desc = {
3778c0984e5SSebastian Reichel 	.name			= "battery",
3788c0984e5SSebastian Reichel 	.type			= POWER_SUPPLY_TYPE_BATTERY,
3798c0984e5SSebastian Reichel 	.get_property		= max17040_get_property,
3802f38dc4dSMatheus Castello 	.set_property		= max17040_set_property,
3812f38dc4dSMatheus Castello 	.property_is_writeable  = max17040_prop_writeable,
3828c0984e5SSebastian Reichel 	.properties		= max17040_battery_props,
3838c0984e5SSebastian Reichel 	.num_properties		= ARRAY_SIZE(max17040_battery_props),
3848c0984e5SSebastian Reichel };
3858c0984e5SSebastian Reichel 
3868c0984e5SSebastian Reichel static int max17040_probe(struct i2c_client *client,
3878c0984e5SSebastian Reichel 			const struct i2c_device_id *id)
3888c0984e5SSebastian Reichel {
3894e9c406dSWolfram Sang 	struct i2c_adapter *adapter = client->adapter;
3908c0984e5SSebastian Reichel 	struct power_supply_config psy_cfg = {};
3918c0984e5SSebastian Reichel 	struct max17040_chip *chip;
392*4f7f8e87SIskren Chernev 	enum chip_id chip_id;
393cccdd0caSMatheus Castello 	int ret;
3948c0984e5SSebastian Reichel 
3958c0984e5SSebastian Reichel 	if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE))
3968c0984e5SSebastian Reichel 		return -EIO;
3978c0984e5SSebastian Reichel 
3988c0984e5SSebastian Reichel 	chip = devm_kzalloc(&client->dev, sizeof(*chip), GFP_KERNEL);
3998c0984e5SSebastian Reichel 	if (!chip)
4008c0984e5SSebastian Reichel 		return -ENOMEM;
4018c0984e5SSebastian Reichel 
4028c0984e5SSebastian Reichel 	chip->client = client;
4036455a8a8SIskren Chernev 	chip->regmap = devm_regmap_init_i2c(client, &max17040_regmap);
4048c0984e5SSebastian Reichel 	chip->pdata = client->dev.platform_data;
405*4f7f8e87SIskren Chernev 	chip_id = (enum chip_id) id->driver_data;
406*4f7f8e87SIskren Chernev 	if (client->dev.of_node) {
407cccdd0caSMatheus Castello 		ret = max17040_get_of_data(chip);
4086455a8a8SIskren Chernev 		if (ret)
409cccdd0caSMatheus Castello 			return ret;
410*4f7f8e87SIskren Chernev 		chip_id = (enum chip_id) (uintptr_t)
411*4f7f8e87SIskren Chernev 			of_device_get_match_data(&client->dev);
412*4f7f8e87SIskren Chernev 	}
413*4f7f8e87SIskren Chernev 	chip->data = max17040_family[chip_id];
4148c0984e5SSebastian Reichel 
4158c0984e5SSebastian Reichel 	i2c_set_clientdata(client, chip);
4168c0984e5SSebastian Reichel 	psy_cfg.drv_data = chip;
4178c0984e5SSebastian Reichel 
418e55a5061SIskren Chernev 	chip->battery = devm_power_supply_register(&client->dev,
4198c0984e5SSebastian Reichel 				&max17040_battery_desc, &psy_cfg);
4208c0984e5SSebastian Reichel 	if (IS_ERR(chip->battery)) {
4218c0984e5SSebastian Reichel 		dev_err(&client->dev, "failed: power supply register\n");
4228c0984e5SSebastian Reichel 		return PTR_ERR(chip->battery);
4238c0984e5SSebastian Reichel 	}
4248c0984e5SSebastian Reichel 
4256455a8a8SIskren Chernev 	ret = max17040_get_version(chip);
4266455a8a8SIskren Chernev 	if (ret < 0)
4276455a8a8SIskren Chernev 		return ret;
4286455a8a8SIskren Chernev 	dev_dbg(&chip->client->dev, "MAX17040 Fuel-Gauge Ver 0x%x\n", ret);
4296455a8a8SIskren Chernev 
430*4f7f8e87SIskren Chernev 	if (chip_id == ID_MAX17040 || chip_id == ID_MAX17041)
4316455a8a8SIskren Chernev 		max17040_reset(chip);
4328c0984e5SSebastian Reichel 
4332e17ed94SMatheus Castello 	/* check interrupt */
434*4f7f8e87SIskren Chernev 	if (client->irq && chip->data.has_low_soc_alert) {
4356455a8a8SIskren Chernev 		ret = max17040_set_low_soc_alert(chip, chip->low_soc_alert);
436cccdd0caSMatheus Castello 		if (ret) {
437cccdd0caSMatheus Castello 			dev_err(&client->dev,
438cccdd0caSMatheus Castello 				"Failed to set low SOC alert: err %d\n", ret);
439cccdd0caSMatheus Castello 			return ret;
440cccdd0caSMatheus Castello 		}
4412e17ed94SMatheus Castello 
4422e17ed94SMatheus Castello 		ret = max17040_enable_alert_irq(chip);
4432e17ed94SMatheus Castello 		if (ret) {
4442e17ed94SMatheus Castello 			client->irq = 0;
4452e17ed94SMatheus Castello 			dev_warn(&client->dev,
4462e17ed94SMatheus Castello 				 "Failed to get IRQ err %d\n", ret);
4472e17ed94SMatheus Castello 		}
4482e17ed94SMatheus Castello 	}
4492e17ed94SMatheus Castello 
4508c0984e5SSebastian Reichel 	INIT_DEFERRABLE_WORK(&chip->work, max17040_work);
451e55a5061SIskren Chernev 	ret = devm_add_action(&client->dev, max17040_stop_work, chip);
452e55a5061SIskren Chernev 	if (ret)
453e55a5061SIskren Chernev 		return ret;
454e55a5061SIskren Chernev 	max17040_queue_work(chip);
4558c0984e5SSebastian Reichel 
4568c0984e5SSebastian Reichel 	return 0;
4578c0984e5SSebastian Reichel }
4588c0984e5SSebastian Reichel 
4598c0984e5SSebastian Reichel #ifdef CONFIG_PM_SLEEP
4608c0984e5SSebastian Reichel 
4618c0984e5SSebastian Reichel static int max17040_suspend(struct device *dev)
4628c0984e5SSebastian Reichel {
4638c0984e5SSebastian Reichel 	struct i2c_client *client = to_i2c_client(dev);
4648c0984e5SSebastian Reichel 	struct max17040_chip *chip = i2c_get_clientdata(client);
4658c0984e5SSebastian Reichel 
4668c0984e5SSebastian Reichel 	cancel_delayed_work(&chip->work);
4672e17ed94SMatheus Castello 
468e29242adSMarek Szyprowski 	if (client->irq && device_may_wakeup(dev))
4692e17ed94SMatheus Castello 		enable_irq_wake(client->irq);
4702e17ed94SMatheus Castello 
4718c0984e5SSebastian Reichel 	return 0;
4728c0984e5SSebastian Reichel }
4738c0984e5SSebastian Reichel 
4748c0984e5SSebastian Reichel static int max17040_resume(struct device *dev)
4758c0984e5SSebastian Reichel {
4768c0984e5SSebastian Reichel 	struct i2c_client *client = to_i2c_client(dev);
4778c0984e5SSebastian Reichel 	struct max17040_chip *chip = i2c_get_clientdata(client);
4788c0984e5SSebastian Reichel 
479e29242adSMarek Szyprowski 	if (client->irq && device_may_wakeup(dev))
4802e17ed94SMatheus Castello 		disable_irq_wake(client->irq);
4812e17ed94SMatheus Castello 
482e55a5061SIskren Chernev 	max17040_queue_work(chip);
483e55a5061SIskren Chernev 
4848c0984e5SSebastian Reichel 	return 0;
4858c0984e5SSebastian Reichel }
4868c0984e5SSebastian Reichel 
4878c0984e5SSebastian Reichel static SIMPLE_DEV_PM_OPS(max17040_pm_ops, max17040_suspend, max17040_resume);
4888c0984e5SSebastian Reichel #define MAX17040_PM_OPS (&max17040_pm_ops)
4898c0984e5SSebastian Reichel 
4908c0984e5SSebastian Reichel #else
4918c0984e5SSebastian Reichel 
4928c0984e5SSebastian Reichel #define MAX17040_PM_OPS NULL
4938c0984e5SSebastian Reichel 
4948c0984e5SSebastian Reichel #endif /* CONFIG_PM_SLEEP */
4958c0984e5SSebastian Reichel 
4968c0984e5SSebastian Reichel static const struct i2c_device_id max17040_id[] = {
497*4f7f8e87SIskren Chernev 	{ "max17040", ID_MAX17040 },
498*4f7f8e87SIskren Chernev 	{ "max17041", ID_MAX17041 },
499*4f7f8e87SIskren Chernev 	{ "max17043", ID_MAX17043 },
500*4f7f8e87SIskren Chernev 	{ "max77836-battery", ID_MAX17043 },
501*4f7f8e87SIskren Chernev 	{ "max17044", ID_MAX17044 },
502*4f7f8e87SIskren Chernev 	{ "max17048", ID_MAX17048 },
503*4f7f8e87SIskren Chernev 	{ "max17049", ID_MAX17049 },
504*4f7f8e87SIskren Chernev 	{ "max17058", ID_MAX17058 },
505*4f7f8e87SIskren Chernev 	{ "max17059", ID_MAX17059 },
506*4f7f8e87SIskren Chernev 	{ /* sentinel */ }
5078c0984e5SSebastian Reichel };
5088c0984e5SSebastian Reichel MODULE_DEVICE_TABLE(i2c, max17040_id);
5098c0984e5SSebastian Reichel 
510da28122cSJavier Martinez Canillas static const struct of_device_id max17040_of_match[] = {
511*4f7f8e87SIskren Chernev 	{ .compatible = "maxim,max17040", .data = (void *) ID_MAX17040 },
512*4f7f8e87SIskren Chernev 	{ .compatible = "maxim,max17041", .data = (void *) ID_MAX17041 },
513*4f7f8e87SIskren Chernev 	{ .compatible = "maxim,max17043", .data = (void *) ID_MAX17043 },
514*4f7f8e87SIskren Chernev 	{ .compatible = "maxim,max77836-battery", .data = (void *) ID_MAX17043 },
515*4f7f8e87SIskren Chernev 	{ .compatible = "maxim,max17044", .data = (void *) ID_MAX17044 },
516*4f7f8e87SIskren Chernev 	{ .compatible = "maxim,max17048", .data = (void *) ID_MAX17048 },
517*4f7f8e87SIskren Chernev 	{ .compatible = "maxim,max17049", .data = (void *) ID_MAX17049 },
518*4f7f8e87SIskren Chernev 	{ .compatible = "maxim,max17058", .data = (void *) ID_MAX17058 },
519*4f7f8e87SIskren Chernev 	{ .compatible = "maxim,max17059", .data = (void *) ID_MAX17059 },
520*4f7f8e87SIskren Chernev 	{ /* sentinel */ },
521da28122cSJavier Martinez Canillas };
522da28122cSJavier Martinez Canillas MODULE_DEVICE_TABLE(of, max17040_of_match);
523da28122cSJavier Martinez Canillas 
5248c0984e5SSebastian Reichel static struct i2c_driver max17040_i2c_driver = {
5258c0984e5SSebastian Reichel 	.driver	= {
5268c0984e5SSebastian Reichel 		.name	= "max17040",
527da28122cSJavier Martinez Canillas 		.of_match_table = max17040_of_match,
5288c0984e5SSebastian Reichel 		.pm	= MAX17040_PM_OPS,
5298c0984e5SSebastian Reichel 	},
5308c0984e5SSebastian Reichel 	.probe		= max17040_probe,
5318c0984e5SSebastian Reichel 	.id_table	= max17040_id,
5328c0984e5SSebastian Reichel };
5338c0984e5SSebastian Reichel module_i2c_driver(max17040_i2c_driver);
5348c0984e5SSebastian Reichel 
5358c0984e5SSebastian Reichel MODULE_AUTHOR("Minkyu Kang <mk7.kang@samsung.com>");
5368c0984e5SSebastian Reichel MODULE_DESCRIPTION("MAX17040 Fuel Gauge");
5378c0984e5SSebastian Reichel MODULE_LICENSE("GPL");
538