xref: /openbmc/linux/drivers/power/supply/max17040_battery.c (revision e55a50613d91515acaddaca8de46162feb9adb45)
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>
188c0984e5SSebastian Reichel #include <linux/max17040_battery.h>
198c0984e5SSebastian Reichel #include <linux/slab.h>
208c0984e5SSebastian Reichel 
2114d60bddSLiu Xiang #define MAX17040_VCELL	0x02
2214d60bddSLiu Xiang #define MAX17040_SOC	0x04
2314d60bddSLiu Xiang #define MAX17040_MODE	0x06
2414d60bddSLiu Xiang #define MAX17040_VER	0x08
2514d60bddSLiu Xiang #define MAX17040_RCOMP	0x0C
2614d60bddSLiu Xiang #define MAX17040_CMD	0xFE
2714d60bddSLiu Xiang 
288c0984e5SSebastian Reichel 
298c0984e5SSebastian Reichel #define MAX17040_DELAY		1000
308c0984e5SSebastian Reichel #define MAX17040_BATTERY_FULL	95
318c0984e5SSebastian Reichel 
32cccdd0caSMatheus Castello #define MAX17040_ATHD_MASK		0xFFC0
33cccdd0caSMatheus Castello #define MAX17040_ATHD_DEFAULT_POWER_UP	4
34cccdd0caSMatheus Castello 
358c0984e5SSebastian Reichel struct max17040_chip {
368c0984e5SSebastian Reichel 	struct i2c_client		*client;
378c0984e5SSebastian Reichel 	struct delayed_work		work;
388c0984e5SSebastian Reichel 	struct power_supply		*battery;
398c0984e5SSebastian Reichel 	struct max17040_platform_data	*pdata;
408c0984e5SSebastian Reichel 
418c0984e5SSebastian Reichel 	/* State Of Connect */
428c0984e5SSebastian Reichel 	int online;
438c0984e5SSebastian Reichel 	/* battery voltage */
448c0984e5SSebastian Reichel 	int vcell;
458c0984e5SSebastian Reichel 	/* battery capacity */
468c0984e5SSebastian Reichel 	int soc;
478c0984e5SSebastian Reichel 	/* State Of Charge */
488c0984e5SSebastian Reichel 	int status;
49cccdd0caSMatheus Castello 	/* Low alert threshold from 32% to 1% of the State of Charge */
50cccdd0caSMatheus Castello 	u32 low_soc_alert;
518c0984e5SSebastian Reichel };
528c0984e5SSebastian Reichel 
538c0984e5SSebastian Reichel static int max17040_get_property(struct power_supply *psy,
548c0984e5SSebastian Reichel 			    enum power_supply_property psp,
558c0984e5SSebastian Reichel 			    union power_supply_propval *val)
568c0984e5SSebastian Reichel {
578c0984e5SSebastian Reichel 	struct max17040_chip *chip = power_supply_get_drvdata(psy);
588c0984e5SSebastian Reichel 
598c0984e5SSebastian Reichel 	switch (psp) {
608c0984e5SSebastian Reichel 	case POWER_SUPPLY_PROP_STATUS:
618c0984e5SSebastian Reichel 		val->intval = chip->status;
628c0984e5SSebastian Reichel 		break;
638c0984e5SSebastian Reichel 	case POWER_SUPPLY_PROP_ONLINE:
648c0984e5SSebastian Reichel 		val->intval = chip->online;
658c0984e5SSebastian Reichel 		break;
668c0984e5SSebastian Reichel 	case POWER_SUPPLY_PROP_VOLTAGE_NOW:
678c0984e5SSebastian Reichel 		val->intval = chip->vcell;
688c0984e5SSebastian Reichel 		break;
698c0984e5SSebastian Reichel 	case POWER_SUPPLY_PROP_CAPACITY:
708c0984e5SSebastian Reichel 		val->intval = chip->soc;
718c0984e5SSebastian Reichel 		break;
722f38dc4dSMatheus Castello 	case POWER_SUPPLY_PROP_CAPACITY_ALERT_MIN:
732f38dc4dSMatheus Castello 		val->intval = chip->low_soc_alert;
742f38dc4dSMatheus Castello 		break;
758c0984e5SSebastian Reichel 	default:
768c0984e5SSebastian Reichel 		return -EINVAL;
778c0984e5SSebastian Reichel 	}
788c0984e5SSebastian Reichel 	return 0;
798c0984e5SSebastian Reichel }
808c0984e5SSebastian Reichel 
8114d60bddSLiu Xiang static int max17040_write_reg(struct i2c_client *client, int reg, u16 value)
828c0984e5SSebastian Reichel {
838c0984e5SSebastian Reichel 	int ret;
848c0984e5SSebastian Reichel 
8514d60bddSLiu Xiang 	ret = i2c_smbus_write_word_swapped(client, reg, value);
868c0984e5SSebastian Reichel 
878c0984e5SSebastian Reichel 	if (ret < 0)
888c0984e5SSebastian Reichel 		dev_err(&client->dev, "%s: err %d\n", __func__, ret);
898c0984e5SSebastian Reichel 
908c0984e5SSebastian Reichel 	return ret;
918c0984e5SSebastian Reichel }
928c0984e5SSebastian Reichel 
938c0984e5SSebastian Reichel static int max17040_read_reg(struct i2c_client *client, int reg)
948c0984e5SSebastian Reichel {
958c0984e5SSebastian Reichel 	int ret;
968c0984e5SSebastian Reichel 
9714d60bddSLiu Xiang 	ret = i2c_smbus_read_word_swapped(client, reg);
988c0984e5SSebastian Reichel 
998c0984e5SSebastian Reichel 	if (ret < 0)
1008c0984e5SSebastian Reichel 		dev_err(&client->dev, "%s: err %d\n", __func__, ret);
1018c0984e5SSebastian Reichel 
1028c0984e5SSebastian Reichel 	return ret;
1038c0984e5SSebastian Reichel }
1048c0984e5SSebastian Reichel 
1058c0984e5SSebastian Reichel static void max17040_reset(struct i2c_client *client)
1068c0984e5SSebastian Reichel {
10714d60bddSLiu Xiang 	max17040_write_reg(client, MAX17040_CMD, 0x0054);
1088c0984e5SSebastian Reichel }
1098c0984e5SSebastian Reichel 
110cccdd0caSMatheus Castello static int max17040_set_low_soc_alert(struct i2c_client *client, u32 level)
111cccdd0caSMatheus Castello {
112cccdd0caSMatheus Castello 	int ret;
113cccdd0caSMatheus Castello 	u16 data;
114cccdd0caSMatheus Castello 
115cccdd0caSMatheus Castello 	level = 32 - level;
116cccdd0caSMatheus Castello 	data = max17040_read_reg(client, MAX17040_RCOMP);
117cccdd0caSMatheus Castello 	/* clear the alrt bit and set LSb 5 bits */
118cccdd0caSMatheus Castello 	data &= MAX17040_ATHD_MASK;
119cccdd0caSMatheus Castello 	data |= level;
120cccdd0caSMatheus Castello 	ret = max17040_write_reg(client, MAX17040_RCOMP, data);
121cccdd0caSMatheus Castello 
122cccdd0caSMatheus Castello 	return ret;
123cccdd0caSMatheus Castello }
124cccdd0caSMatheus Castello 
1258c0984e5SSebastian Reichel static void max17040_get_vcell(struct i2c_client *client)
1268c0984e5SSebastian Reichel {
1278c0984e5SSebastian Reichel 	struct max17040_chip *chip = i2c_get_clientdata(client);
12814d60bddSLiu Xiang 	u16 vcell;
1298c0984e5SSebastian Reichel 
13014d60bddSLiu Xiang 	vcell = max17040_read_reg(client, MAX17040_VCELL);
1318c0984e5SSebastian Reichel 
1320383024fSJonathan Bakker 	chip->vcell = (vcell >> 4) * 1250;
1338c0984e5SSebastian Reichel }
1348c0984e5SSebastian Reichel 
1358c0984e5SSebastian Reichel static void max17040_get_soc(struct i2c_client *client)
1368c0984e5SSebastian Reichel {
1378c0984e5SSebastian Reichel 	struct max17040_chip *chip = i2c_get_clientdata(client);
13814d60bddSLiu Xiang 	u16 soc;
1398c0984e5SSebastian Reichel 
14014d60bddSLiu Xiang 	soc = max17040_read_reg(client, MAX17040_SOC);
1418c0984e5SSebastian Reichel 
14214d60bddSLiu Xiang 	chip->soc = (soc >> 8);
1438c0984e5SSebastian Reichel }
1448c0984e5SSebastian Reichel 
1458c0984e5SSebastian Reichel static void max17040_get_version(struct i2c_client *client)
1468c0984e5SSebastian Reichel {
14714d60bddSLiu Xiang 	u16 version;
1488c0984e5SSebastian Reichel 
14914d60bddSLiu Xiang 	version = max17040_read_reg(client, MAX17040_VER);
1508c0984e5SSebastian Reichel 
15114d60bddSLiu Xiang 	dev_info(&client->dev, "MAX17040 Fuel-Gauge Ver 0x%x\n", version);
1528c0984e5SSebastian Reichel }
1538c0984e5SSebastian Reichel 
1548c0984e5SSebastian Reichel static void max17040_get_online(struct i2c_client *client)
1558c0984e5SSebastian Reichel {
1568c0984e5SSebastian Reichel 	struct max17040_chip *chip = i2c_get_clientdata(client);
1578c0984e5SSebastian Reichel 
1588c0984e5SSebastian Reichel 	if (chip->pdata && chip->pdata->battery_online)
1598c0984e5SSebastian Reichel 		chip->online = chip->pdata->battery_online();
1608c0984e5SSebastian Reichel 	else
1618c0984e5SSebastian Reichel 		chip->online = 1;
1628c0984e5SSebastian Reichel }
1638c0984e5SSebastian Reichel 
1648c0984e5SSebastian Reichel static void max17040_get_status(struct i2c_client *client)
1658c0984e5SSebastian Reichel {
1668c0984e5SSebastian Reichel 	struct max17040_chip *chip = i2c_get_clientdata(client);
1678c0984e5SSebastian Reichel 
1688c0984e5SSebastian Reichel 	if (!chip->pdata || !chip->pdata->charger_online
1698c0984e5SSebastian Reichel 			|| !chip->pdata->charger_enable) {
1708c0984e5SSebastian Reichel 		chip->status = POWER_SUPPLY_STATUS_UNKNOWN;
1718c0984e5SSebastian Reichel 		return;
1728c0984e5SSebastian Reichel 	}
1738c0984e5SSebastian Reichel 
1748c0984e5SSebastian Reichel 	if (chip->pdata->charger_online()) {
1758c0984e5SSebastian Reichel 		if (chip->pdata->charger_enable())
1768c0984e5SSebastian Reichel 			chip->status = POWER_SUPPLY_STATUS_CHARGING;
1778c0984e5SSebastian Reichel 		else
1788c0984e5SSebastian Reichel 			chip->status = POWER_SUPPLY_STATUS_NOT_CHARGING;
1798c0984e5SSebastian Reichel 	} else {
1808c0984e5SSebastian Reichel 		chip->status = POWER_SUPPLY_STATUS_DISCHARGING;
1818c0984e5SSebastian Reichel 	}
1828c0984e5SSebastian Reichel 
1838c0984e5SSebastian Reichel 	if (chip->soc > MAX17040_BATTERY_FULL)
1848c0984e5SSebastian Reichel 		chip->status = POWER_SUPPLY_STATUS_FULL;
1858c0984e5SSebastian Reichel }
1868c0984e5SSebastian Reichel 
187cccdd0caSMatheus Castello static int max17040_get_of_data(struct max17040_chip *chip)
188cccdd0caSMatheus Castello {
189cccdd0caSMatheus Castello 	struct device *dev = &chip->client->dev;
190cccdd0caSMatheus Castello 
191cccdd0caSMatheus Castello 	chip->low_soc_alert = MAX17040_ATHD_DEFAULT_POWER_UP;
192cccdd0caSMatheus Castello 	device_property_read_u32(dev,
193cccdd0caSMatheus Castello 				 "maxim,alert-low-soc-level",
194cccdd0caSMatheus Castello 				 &chip->low_soc_alert);
195cccdd0caSMatheus Castello 
196cccdd0caSMatheus Castello 	if (chip->low_soc_alert <= 0 || chip->low_soc_alert >= 33)
197cccdd0caSMatheus Castello 		return -EINVAL;
198cccdd0caSMatheus Castello 
199cccdd0caSMatheus Castello 	return 0;
200cccdd0caSMatheus Castello }
201cccdd0caSMatheus Castello 
2022e17ed94SMatheus Castello static void max17040_check_changes(struct i2c_client *client)
2032e17ed94SMatheus Castello {
2042e17ed94SMatheus Castello 	max17040_get_vcell(client);
2052e17ed94SMatheus Castello 	max17040_get_soc(client);
2062e17ed94SMatheus Castello 	max17040_get_online(client);
2072e17ed94SMatheus Castello 	max17040_get_status(client);
2082e17ed94SMatheus Castello }
2092e17ed94SMatheus Castello 
210*e55a5061SIskren Chernev static void max17040_queue_work(struct max17040_chip *chip)
211*e55a5061SIskren Chernev {
212*e55a5061SIskren Chernev 	queue_delayed_work(system_power_efficient_wq, &chip->work,
213*e55a5061SIskren Chernev 			   MAX17040_DELAY);
214*e55a5061SIskren Chernev }
215*e55a5061SIskren Chernev 
216*e55a5061SIskren Chernev static void max17040_stop_work(void *data)
217*e55a5061SIskren Chernev {
218*e55a5061SIskren Chernev 	struct max17040_chip *chip = data;
219*e55a5061SIskren Chernev 
220*e55a5061SIskren Chernev 	cancel_delayed_work_sync(&chip->work);
221*e55a5061SIskren Chernev }
222*e55a5061SIskren Chernev 
2238c0984e5SSebastian Reichel static void max17040_work(struct work_struct *work)
2248c0984e5SSebastian Reichel {
2258c0984e5SSebastian Reichel 	struct max17040_chip *chip;
226a08990eaSMatheus Castello 	int last_soc, last_status;
2278c0984e5SSebastian Reichel 
2288c0984e5SSebastian Reichel 	chip = container_of(work, struct max17040_chip, work.work);
229a08990eaSMatheus Castello 
230a08990eaSMatheus Castello 	/* store SOC and status to check changes */
231a08990eaSMatheus Castello 	last_soc = chip->soc;
232a08990eaSMatheus Castello 	last_status = chip->status;
2332e17ed94SMatheus Castello 	max17040_check_changes(chip->client);
2348c0984e5SSebastian Reichel 
235a08990eaSMatheus Castello 	/* check changes and send uevent */
236a08990eaSMatheus Castello 	if (last_soc != chip->soc || last_status != chip->status)
237a08990eaSMatheus Castello 		power_supply_changed(chip->battery);
238a08990eaSMatheus Castello 
239*e55a5061SIskren Chernev 	max17040_queue_work(chip);
2408c0984e5SSebastian Reichel }
2418c0984e5SSebastian Reichel 
2422e17ed94SMatheus Castello static irqreturn_t max17040_thread_handler(int id, void *dev)
2432e17ed94SMatheus Castello {
2442e17ed94SMatheus Castello 	struct max17040_chip *chip = dev;
2452e17ed94SMatheus Castello 	struct i2c_client *client = chip->client;
2462e17ed94SMatheus Castello 
2472e17ed94SMatheus Castello 	dev_warn(&client->dev, "IRQ: Alert battery low level");
2482e17ed94SMatheus Castello 	/* read registers */
2492e17ed94SMatheus Castello 	max17040_check_changes(chip->client);
2502e17ed94SMatheus Castello 
2512e17ed94SMatheus Castello 	/* send uevent */
2522e17ed94SMatheus Castello 	power_supply_changed(chip->battery);
2532e17ed94SMatheus Castello 
254cccdd0caSMatheus Castello 	/* reset alert bit */
255cccdd0caSMatheus Castello 	max17040_set_low_soc_alert(client, chip->low_soc_alert);
256cccdd0caSMatheus Castello 
2572e17ed94SMatheus Castello 	return IRQ_HANDLED;
2582e17ed94SMatheus Castello }
2592e17ed94SMatheus Castello 
2602e17ed94SMatheus Castello static int max17040_enable_alert_irq(struct max17040_chip *chip)
2612e17ed94SMatheus Castello {
2622e17ed94SMatheus Castello 	struct i2c_client *client = chip->client;
2632e17ed94SMatheus Castello 	unsigned int flags;
2642e17ed94SMatheus Castello 	int ret;
2652e17ed94SMatheus Castello 
2662e17ed94SMatheus Castello 	flags = IRQF_TRIGGER_FALLING | IRQF_ONESHOT;
2672e17ed94SMatheus Castello 	ret = devm_request_threaded_irq(&client->dev, client->irq, NULL,
2682e17ed94SMatheus Castello 					max17040_thread_handler, flags,
2692e17ed94SMatheus Castello 					chip->battery->desc->name, chip);
2702e17ed94SMatheus Castello 
2712e17ed94SMatheus Castello 	return ret;
2722e17ed94SMatheus Castello }
2732e17ed94SMatheus Castello 
2742f38dc4dSMatheus Castello static int max17040_prop_writeable(struct power_supply *psy,
2752f38dc4dSMatheus Castello 				   enum power_supply_property psp)
2762f38dc4dSMatheus Castello {
2772f38dc4dSMatheus Castello 	switch (psp) {
2782f38dc4dSMatheus Castello 	case POWER_SUPPLY_PROP_CAPACITY_ALERT_MIN:
2792f38dc4dSMatheus Castello 		return 1;
2802f38dc4dSMatheus Castello 	default:
2812f38dc4dSMatheus Castello 		return 0;
2822f38dc4dSMatheus Castello 	}
2832f38dc4dSMatheus Castello }
2842f38dc4dSMatheus Castello 
2852f38dc4dSMatheus Castello static int max17040_set_property(struct power_supply *psy,
2862f38dc4dSMatheus Castello 			    enum power_supply_property psp,
2872f38dc4dSMatheus Castello 			    const union power_supply_propval *val)
2882f38dc4dSMatheus Castello {
2892f38dc4dSMatheus Castello 	struct max17040_chip *chip = power_supply_get_drvdata(psy);
2902f38dc4dSMatheus Castello 	int ret;
2912f38dc4dSMatheus Castello 
2922f38dc4dSMatheus Castello 	switch (psp) {
2932f38dc4dSMatheus Castello 	case POWER_SUPPLY_PROP_CAPACITY_ALERT_MIN:
2942f38dc4dSMatheus Castello 		/* alert threshold can be programmed from 1% up to 32% */
2952f38dc4dSMatheus Castello 		if ((val->intval < 1) || (val->intval > 32)) {
2962f38dc4dSMatheus Castello 			ret = -EINVAL;
2972f38dc4dSMatheus Castello 			break;
2982f38dc4dSMatheus Castello 		}
2992f38dc4dSMatheus Castello 		ret = max17040_set_low_soc_alert(chip->client, val->intval);
3002f38dc4dSMatheus Castello 		chip->low_soc_alert = val->intval;
3012f38dc4dSMatheus Castello 		break;
3022f38dc4dSMatheus Castello 	default:
3032f38dc4dSMatheus Castello 		ret = -EINVAL;
3042f38dc4dSMatheus Castello 	}
3052f38dc4dSMatheus Castello 
3062f38dc4dSMatheus Castello 	return ret;
3072f38dc4dSMatheus Castello }
3082f38dc4dSMatheus Castello 
3098c0984e5SSebastian Reichel static enum power_supply_property max17040_battery_props[] = {
3108c0984e5SSebastian Reichel 	POWER_SUPPLY_PROP_STATUS,
3118c0984e5SSebastian Reichel 	POWER_SUPPLY_PROP_ONLINE,
3128c0984e5SSebastian Reichel 	POWER_SUPPLY_PROP_VOLTAGE_NOW,
3138c0984e5SSebastian Reichel 	POWER_SUPPLY_PROP_CAPACITY,
3142f38dc4dSMatheus Castello 	POWER_SUPPLY_PROP_CAPACITY_ALERT_MIN,
3158c0984e5SSebastian Reichel };
3168c0984e5SSebastian Reichel 
3178c0984e5SSebastian Reichel static const struct power_supply_desc max17040_battery_desc = {
3188c0984e5SSebastian Reichel 	.name			= "battery",
3198c0984e5SSebastian Reichel 	.type			= POWER_SUPPLY_TYPE_BATTERY,
3208c0984e5SSebastian Reichel 	.get_property		= max17040_get_property,
3212f38dc4dSMatheus Castello 	.set_property		= max17040_set_property,
3222f38dc4dSMatheus Castello 	.property_is_writeable  = max17040_prop_writeable,
3238c0984e5SSebastian Reichel 	.properties		= max17040_battery_props,
3248c0984e5SSebastian Reichel 	.num_properties		= ARRAY_SIZE(max17040_battery_props),
3258c0984e5SSebastian Reichel };
3268c0984e5SSebastian Reichel 
3278c0984e5SSebastian Reichel static int max17040_probe(struct i2c_client *client,
3288c0984e5SSebastian Reichel 			const struct i2c_device_id *id)
3298c0984e5SSebastian Reichel {
3304e9c406dSWolfram Sang 	struct i2c_adapter *adapter = client->adapter;
3318c0984e5SSebastian Reichel 	struct power_supply_config psy_cfg = {};
3328c0984e5SSebastian Reichel 	struct max17040_chip *chip;
333cccdd0caSMatheus Castello 	int ret;
3348c0984e5SSebastian Reichel 
3358c0984e5SSebastian Reichel 	if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE))
3368c0984e5SSebastian Reichel 		return -EIO;
3378c0984e5SSebastian Reichel 
3388c0984e5SSebastian Reichel 	chip = devm_kzalloc(&client->dev, sizeof(*chip), GFP_KERNEL);
3398c0984e5SSebastian Reichel 	if (!chip)
3408c0984e5SSebastian Reichel 		return -ENOMEM;
3418c0984e5SSebastian Reichel 
3428c0984e5SSebastian Reichel 	chip->client = client;
3438c0984e5SSebastian Reichel 	chip->pdata = client->dev.platform_data;
344cccdd0caSMatheus Castello 	ret = max17040_get_of_data(chip);
345cccdd0caSMatheus Castello 	if (ret) {
346cccdd0caSMatheus Castello 		dev_err(&client->dev,
347cccdd0caSMatheus Castello 			"failed: low SOC alert OF data out of bounds\n");
348cccdd0caSMatheus Castello 		return ret;
349cccdd0caSMatheus Castello 	}
3508c0984e5SSebastian Reichel 
3518c0984e5SSebastian Reichel 	i2c_set_clientdata(client, chip);
3528c0984e5SSebastian Reichel 	psy_cfg.drv_data = chip;
3538c0984e5SSebastian Reichel 
354*e55a5061SIskren Chernev 	chip->battery = devm_power_supply_register(&client->dev,
3558c0984e5SSebastian Reichel 				&max17040_battery_desc, &psy_cfg);
3568c0984e5SSebastian Reichel 	if (IS_ERR(chip->battery)) {
3578c0984e5SSebastian Reichel 		dev_err(&client->dev, "failed: power supply register\n");
3588c0984e5SSebastian Reichel 		return PTR_ERR(chip->battery);
3598c0984e5SSebastian Reichel 	}
3608c0984e5SSebastian Reichel 
3618c0984e5SSebastian Reichel 	max17040_reset(client);
3628c0984e5SSebastian Reichel 	max17040_get_version(client);
3638c0984e5SSebastian Reichel 
3642e17ed94SMatheus Castello 	/* check interrupt */
3652e17ed94SMatheus Castello 	if (client->irq && of_device_is_compatible(client->dev.of_node,
3662e17ed94SMatheus Castello 						   "maxim,max77836-battery")) {
367cccdd0caSMatheus Castello 		ret = max17040_set_low_soc_alert(client, chip->low_soc_alert);
368cccdd0caSMatheus Castello 		if (ret) {
369cccdd0caSMatheus Castello 			dev_err(&client->dev,
370cccdd0caSMatheus Castello 				"Failed to set low SOC alert: err %d\n", ret);
371cccdd0caSMatheus Castello 			return ret;
372cccdd0caSMatheus Castello 		}
3732e17ed94SMatheus Castello 
3742e17ed94SMatheus Castello 		ret = max17040_enable_alert_irq(chip);
3752e17ed94SMatheus Castello 		if (ret) {
3762e17ed94SMatheus Castello 			client->irq = 0;
3772e17ed94SMatheus Castello 			dev_warn(&client->dev,
3782e17ed94SMatheus Castello 				 "Failed to get IRQ err %d\n", ret);
3792e17ed94SMatheus Castello 		}
3802e17ed94SMatheus Castello 	}
3812e17ed94SMatheus Castello 
3828c0984e5SSebastian Reichel 	INIT_DEFERRABLE_WORK(&chip->work, max17040_work);
383*e55a5061SIskren Chernev 	ret = devm_add_action(&client->dev, max17040_stop_work, chip);
384*e55a5061SIskren Chernev 	if (ret)
385*e55a5061SIskren Chernev 		return ret;
386*e55a5061SIskren Chernev 	max17040_queue_work(chip);
3878c0984e5SSebastian Reichel 
3888c0984e5SSebastian Reichel 	return 0;
3898c0984e5SSebastian Reichel }
3908c0984e5SSebastian Reichel 
3918c0984e5SSebastian Reichel #ifdef CONFIG_PM_SLEEP
3928c0984e5SSebastian Reichel 
3938c0984e5SSebastian Reichel static int max17040_suspend(struct device *dev)
3948c0984e5SSebastian Reichel {
3958c0984e5SSebastian Reichel 	struct i2c_client *client = to_i2c_client(dev);
3968c0984e5SSebastian Reichel 	struct max17040_chip *chip = i2c_get_clientdata(client);
3978c0984e5SSebastian Reichel 
3988c0984e5SSebastian Reichel 	cancel_delayed_work(&chip->work);
3992e17ed94SMatheus Castello 
400e29242adSMarek Szyprowski 	if (client->irq && device_may_wakeup(dev))
4012e17ed94SMatheus Castello 		enable_irq_wake(client->irq);
4022e17ed94SMatheus Castello 
4038c0984e5SSebastian Reichel 	return 0;
4048c0984e5SSebastian Reichel }
4058c0984e5SSebastian Reichel 
4068c0984e5SSebastian Reichel static int max17040_resume(struct device *dev)
4078c0984e5SSebastian Reichel {
4088c0984e5SSebastian Reichel 	struct i2c_client *client = to_i2c_client(dev);
4098c0984e5SSebastian Reichel 	struct max17040_chip *chip = i2c_get_clientdata(client);
4108c0984e5SSebastian Reichel 
411e29242adSMarek Szyprowski 	if (client->irq && device_may_wakeup(dev))
4122e17ed94SMatheus Castello 		disable_irq_wake(client->irq);
4132e17ed94SMatheus Castello 
414*e55a5061SIskren Chernev 	max17040_queue_work(chip);
415*e55a5061SIskren Chernev 
4168c0984e5SSebastian Reichel 	return 0;
4178c0984e5SSebastian Reichel }
4188c0984e5SSebastian Reichel 
4198c0984e5SSebastian Reichel static SIMPLE_DEV_PM_OPS(max17040_pm_ops, max17040_suspend, max17040_resume);
4208c0984e5SSebastian Reichel #define MAX17040_PM_OPS (&max17040_pm_ops)
4218c0984e5SSebastian Reichel 
4228c0984e5SSebastian Reichel #else
4238c0984e5SSebastian Reichel 
4248c0984e5SSebastian Reichel #define MAX17040_PM_OPS NULL
4258c0984e5SSebastian Reichel 
4268c0984e5SSebastian Reichel #endif /* CONFIG_PM_SLEEP */
4278c0984e5SSebastian Reichel 
4288c0984e5SSebastian Reichel static const struct i2c_device_id max17040_id[] = {
4298c0984e5SSebastian Reichel 	{ "max17040" },
4308c0984e5SSebastian Reichel 	{ "max77836-battery" },
4318c0984e5SSebastian Reichel 	{ }
4328c0984e5SSebastian Reichel };
4338c0984e5SSebastian Reichel MODULE_DEVICE_TABLE(i2c, max17040_id);
4348c0984e5SSebastian Reichel 
435da28122cSJavier Martinez Canillas static const struct of_device_id max17040_of_match[] = {
436da28122cSJavier Martinez Canillas 	{ .compatible = "maxim,max17040" },
437da28122cSJavier Martinez Canillas 	{ .compatible = "maxim,max77836-battery" },
438da28122cSJavier Martinez Canillas 	{ },
439da28122cSJavier Martinez Canillas };
440da28122cSJavier Martinez Canillas MODULE_DEVICE_TABLE(of, max17040_of_match);
441da28122cSJavier Martinez Canillas 
4428c0984e5SSebastian Reichel static struct i2c_driver max17040_i2c_driver = {
4438c0984e5SSebastian Reichel 	.driver	= {
4448c0984e5SSebastian Reichel 		.name	= "max17040",
445da28122cSJavier Martinez Canillas 		.of_match_table = max17040_of_match,
4468c0984e5SSebastian Reichel 		.pm	= MAX17040_PM_OPS,
4478c0984e5SSebastian Reichel 	},
4488c0984e5SSebastian Reichel 	.probe		= max17040_probe,
4498c0984e5SSebastian Reichel 	.id_table	= max17040_id,
4508c0984e5SSebastian Reichel };
4518c0984e5SSebastian Reichel module_i2c_driver(max17040_i2c_driver);
4528c0984e5SSebastian Reichel 
4538c0984e5SSebastian Reichel MODULE_AUTHOR("Minkyu Kang <mk7.kang@samsung.com>");
4548c0984e5SSebastian Reichel MODULE_DESCRIPTION("MAX17040 Fuel Gauge");
4558c0984e5SSebastian Reichel MODULE_LICENSE("GPL");
456