17b38ebdfSKrzysztof Kozlowski // SPDX-License-Identifier: GPL-2.0+
27b38ebdfSKrzysztof Kozlowski //
37b38ebdfSKrzysztof Kozlowski // Fuel gauge driver for Maxim 17042 / 8966 / 8997
47b38ebdfSKrzysztof Kozlowski // Note that Maxim 8966 and 8997 are mfd and this is its subdevice.
57b38ebdfSKrzysztof Kozlowski //
67b38ebdfSKrzysztof Kozlowski // Copyright (C) 2011 Samsung Electronics
77b38ebdfSKrzysztof Kozlowski // MyungJoo Ham <myungjoo.ham@samsung.com>
87b38ebdfSKrzysztof Kozlowski //
97b38ebdfSKrzysztof Kozlowski // This driver is based on max17040_battery.c
108c0984e5SSebastian Reichel
11e2116202SHans de Goede #include <linux/acpi.h>
12e5372503SChristophe JAILLET #include <linux/devm-helpers.h>
138c0984e5SSebastian Reichel #include <linux/init.h>
148c0984e5SSebastian Reichel #include <linux/module.h>
158c0984e5SSebastian Reichel #include <linux/slab.h>
168c0984e5SSebastian Reichel #include <linux/i2c.h>
178c0984e5SSebastian Reichel #include <linux/delay.h>
188c0984e5SSebastian Reichel #include <linux/interrupt.h>
198c0984e5SSebastian Reichel #include <linux/pm.h>
208c0984e5SSebastian Reichel #include <linux/mod_devicetable.h>
218c0984e5SSebastian Reichel #include <linux/power_supply.h>
228c0984e5SSebastian Reichel #include <linux/power/max17042_battery.h>
238c0984e5SSebastian Reichel #include <linux/of.h>
248c0984e5SSebastian Reichel #include <linux/regmap.h>
258c0984e5SSebastian Reichel
268c0984e5SSebastian Reichel /* Status register bits */
278c0984e5SSebastian Reichel #define STATUS_POR_BIT (1 << 1)
288c0984e5SSebastian Reichel #define STATUS_BST_BIT (1 << 3)
298c0984e5SSebastian Reichel #define STATUS_VMN_BIT (1 << 8)
308c0984e5SSebastian Reichel #define STATUS_TMN_BIT (1 << 9)
318c0984e5SSebastian Reichel #define STATUS_SMN_BIT (1 << 10)
328c0984e5SSebastian Reichel #define STATUS_BI_BIT (1 << 11)
338c0984e5SSebastian Reichel #define STATUS_VMX_BIT (1 << 12)
348c0984e5SSebastian Reichel #define STATUS_TMX_BIT (1 << 13)
358c0984e5SSebastian Reichel #define STATUS_SMX_BIT (1 << 14)
368c0984e5SSebastian Reichel #define STATUS_BR_BIT (1 << 15)
378c0984e5SSebastian Reichel
388c0984e5SSebastian Reichel /* Interrupt mask bits */
39c06a65acSPrzemyslaw Chwiala #define CFG_ALRT_BIT_ENBL (1 << 2)
408c0984e5SSebastian Reichel
418c0984e5SSebastian Reichel #define VFSOC0_LOCK 0x0000
428c0984e5SSebastian Reichel #define VFSOC0_UNLOCK 0x0080
438c0984e5SSebastian Reichel #define MODEL_UNLOCK1 0X0059
448c0984e5SSebastian Reichel #define MODEL_UNLOCK2 0X00C4
458c0984e5SSebastian Reichel #define MODEL_LOCK1 0X0000
468c0984e5SSebastian Reichel #define MODEL_LOCK2 0X0000
478c0984e5SSebastian Reichel
488c0984e5SSebastian Reichel #define dQ_ACC_DIV 0x4
498c0984e5SSebastian Reichel #define dP_ACC_100 0x1900
508c0984e5SSebastian Reichel #define dP_ACC_200 0x3200
518c0984e5SSebastian Reichel
528c0984e5SSebastian Reichel #define MAX17042_VMAX_TOLERANCE 50 /* 50 mV */
538c0984e5SSebastian Reichel
548c0984e5SSebastian Reichel struct max17042_chip {
558c0984e5SSebastian Reichel struct i2c_client *client;
568c0984e5SSebastian Reichel struct regmap *regmap;
578c0984e5SSebastian Reichel struct power_supply *battery;
588c0984e5SSebastian Reichel enum max170xx_chip_type chip_type;
598c0984e5SSebastian Reichel struct max17042_platform_data *pdata;
608c0984e5SSebastian Reichel struct work_struct work;
618c0984e5SSebastian Reichel int init_complete;
628c0984e5SSebastian Reichel };
638c0984e5SSebastian Reichel
648c0984e5SSebastian Reichel static enum power_supply_property max17042_battery_props[] = {
65a9df22c0SHans de Goede POWER_SUPPLY_PROP_STATUS,
668c0984e5SSebastian Reichel POWER_SUPPLY_PROP_PRESENT,
67ef7fcdaeSHans de Goede POWER_SUPPLY_PROP_TECHNOLOGY,
688c0984e5SSebastian Reichel POWER_SUPPLY_PROP_CYCLE_COUNT,
698c0984e5SSebastian Reichel POWER_SUPPLY_PROP_VOLTAGE_MAX,
707bfc9397SHans de Goede POWER_SUPPLY_PROP_VOLTAGE_MIN,
718c0984e5SSebastian Reichel POWER_SUPPLY_PROP_VOLTAGE_MIN_DESIGN,
728c0984e5SSebastian Reichel POWER_SUPPLY_PROP_VOLTAGE_NOW,
738c0984e5SSebastian Reichel POWER_SUPPLY_PROP_VOLTAGE_AVG,
748c0984e5SSebastian Reichel POWER_SUPPLY_PROP_VOLTAGE_OCV,
758c0984e5SSebastian Reichel POWER_SUPPLY_PROP_CAPACITY,
762e015412SHans de Goede POWER_SUPPLY_PROP_CHARGE_FULL_DESIGN,
778c0984e5SSebastian Reichel POWER_SUPPLY_PROP_CHARGE_FULL,
786d6b61eaSHans de Goede POWER_SUPPLY_PROP_CHARGE_NOW,
798c0984e5SSebastian Reichel POWER_SUPPLY_PROP_CHARGE_COUNTER,
805225371eSSebastian Krzyszkowiak POWER_SUPPLY_PROP_CHARGE_TERM_CURRENT,
818c0984e5SSebastian Reichel POWER_SUPPLY_PROP_TEMP,
828c0984e5SSebastian Reichel POWER_SUPPLY_PROP_TEMP_ALERT_MIN,
838c0984e5SSebastian Reichel POWER_SUPPLY_PROP_TEMP_ALERT_MAX,
848c0984e5SSebastian Reichel POWER_SUPPLY_PROP_TEMP_MIN,
858c0984e5SSebastian Reichel POWER_SUPPLY_PROP_TEMP_MAX,
868c0984e5SSebastian Reichel POWER_SUPPLY_PROP_HEALTH,
87adb69a3cSHans de Goede POWER_SUPPLY_PROP_SCOPE,
884b0a56e6SSebastian Krzyszkowiak POWER_SUPPLY_PROP_TIME_TO_EMPTY_NOW,
894b0a56e6SSebastian Krzyszkowiak // these two have to be at the end on the list
908c0984e5SSebastian Reichel POWER_SUPPLY_PROP_CURRENT_NOW,
918c0984e5SSebastian Reichel POWER_SUPPLY_PROP_CURRENT_AVG,
928c0984e5SSebastian Reichel };
938c0984e5SSebastian Reichel
max17042_get_temperature(struct max17042_chip * chip,int * temp)948c0984e5SSebastian Reichel static int max17042_get_temperature(struct max17042_chip *chip, int *temp)
958c0984e5SSebastian Reichel {
968c0984e5SSebastian Reichel int ret;
978c0984e5SSebastian Reichel u32 data;
988c0984e5SSebastian Reichel struct regmap *map = chip->regmap;
998c0984e5SSebastian Reichel
1008c0984e5SSebastian Reichel ret = regmap_read(map, MAX17042_TEMP, &data);
1018c0984e5SSebastian Reichel if (ret < 0)
1028c0984e5SSebastian Reichel return ret;
1038c0984e5SSebastian Reichel
104c67c0693SHans de Goede *temp = sign_extend32(data, 15);
1058c0984e5SSebastian Reichel /* The value is converted into deci-centigrade scale */
1068c0984e5SSebastian Reichel /* Units of LSB = 1 / 256 degree Celsius */
1078c0984e5SSebastian Reichel *temp = *temp * 10 / 256;
1088c0984e5SSebastian Reichel return 0;
1098c0984e5SSebastian Reichel }
1108c0984e5SSebastian Reichel
max17042_get_status(struct max17042_chip * chip,int * status)111a9df22c0SHans de Goede static int max17042_get_status(struct max17042_chip *chip, int *status)
112a9df22c0SHans de Goede {
113a9df22c0SHans de Goede int ret, charge_full, charge_now;
1146e5ab19dSHans de Goede int avg_current;
1156e5ab19dSHans de Goede u32 data;
116a9df22c0SHans de Goede
117a9df22c0SHans de Goede ret = power_supply_am_i_supplied(chip->battery);
118a9df22c0SHans de Goede if (ret < 0) {
119a9df22c0SHans de Goede *status = POWER_SUPPLY_STATUS_UNKNOWN;
120a9df22c0SHans de Goede return 0;
121a9df22c0SHans de Goede }
122a9df22c0SHans de Goede if (ret == 0) {
123a9df22c0SHans de Goede *status = POWER_SUPPLY_STATUS_DISCHARGING;
124a9df22c0SHans de Goede return 0;
125a9df22c0SHans de Goede }
126a9df22c0SHans de Goede
127a9df22c0SHans de Goede /*
128a9df22c0SHans de Goede * The MAX170xx has builtin end-of-charge detection and will update
129a9df22c0SHans de Goede * FullCAP to match RepCap when it detects end of charging.
130a9df22c0SHans de Goede *
131a9df22c0SHans de Goede * When this cycle the battery gets charged to a higher (calculated)
132a9df22c0SHans de Goede * capacity then the previous cycle then FullCAP will get updated
13337ad56aaSBhaskar Chowdhury * continuously once end-of-charge detection kicks in, so allow the
134a9df22c0SHans de Goede * 2 to differ a bit.
135a9df22c0SHans de Goede */
136a9df22c0SHans de Goede
137a9df22c0SHans de Goede ret = regmap_read(chip->regmap, MAX17042_FullCAP, &charge_full);
138a9df22c0SHans de Goede if (ret < 0)
139a9df22c0SHans de Goede return ret;
140a9df22c0SHans de Goede
141a9df22c0SHans de Goede ret = regmap_read(chip->regmap, MAX17042_RepCap, &charge_now);
142a9df22c0SHans de Goede if (ret < 0)
143a9df22c0SHans de Goede return ret;
144a9df22c0SHans de Goede
1456e5ab19dSHans de Goede if ((charge_full - charge_now) <= MAX17042_FULL_THRESHOLD) {
146a9df22c0SHans de Goede *status = POWER_SUPPLY_STATUS_FULL;
1476e5ab19dSHans de Goede return 0;
1486e5ab19dSHans de Goede }
1496e5ab19dSHans de Goede
1506e5ab19dSHans de Goede /*
1516e5ab19dSHans de Goede * Even though we are supplied, we may still be discharging if the
1526e5ab19dSHans de Goede * supply is e.g. only delivering 5V 0.5A. Check current if available.
1536e5ab19dSHans de Goede */
1546e5ab19dSHans de Goede if (!chip->pdata->enable_current_sense) {
155a9df22c0SHans de Goede *status = POWER_SUPPLY_STATUS_CHARGING;
1566e5ab19dSHans de Goede return 0;
1576e5ab19dSHans de Goede }
1586e5ab19dSHans de Goede
1596e5ab19dSHans de Goede ret = regmap_read(chip->regmap, MAX17042_AvgCurrent, &data);
1606e5ab19dSHans de Goede if (ret < 0)
1616e5ab19dSHans de Goede return ret;
1626e5ab19dSHans de Goede
1636e5ab19dSHans de Goede avg_current = sign_extend32(data, 15);
1646e5ab19dSHans de Goede avg_current *= 1562500 / chip->pdata->r_sns;
1656e5ab19dSHans de Goede
1666e5ab19dSHans de Goede if (avg_current > 0)
1676e5ab19dSHans de Goede *status = POWER_SUPPLY_STATUS_CHARGING;
1686e5ab19dSHans de Goede else
1696e5ab19dSHans de Goede *status = POWER_SUPPLY_STATUS_DISCHARGING;
170a9df22c0SHans de Goede
171a9df22c0SHans de Goede return 0;
172a9df22c0SHans de Goede }
173a9df22c0SHans de Goede
max17042_get_battery_health(struct max17042_chip * chip,int * health)1748c0984e5SSebastian Reichel static int max17042_get_battery_health(struct max17042_chip *chip, int *health)
1758c0984e5SSebastian Reichel {
1768c0984e5SSebastian Reichel int temp, vavg, vbatt, ret;
1778c0984e5SSebastian Reichel u32 val;
1788c0984e5SSebastian Reichel
1798c0984e5SSebastian Reichel ret = regmap_read(chip->regmap, MAX17042_AvgVCELL, &val);
1808c0984e5SSebastian Reichel if (ret < 0)
1818c0984e5SSebastian Reichel goto health_error;
1828c0984e5SSebastian Reichel
1838c0984e5SSebastian Reichel /* bits [0-3] unused */
1848c0984e5SSebastian Reichel vavg = val * 625 / 8;
1858c0984e5SSebastian Reichel /* Convert to millivolts */
1868c0984e5SSebastian Reichel vavg /= 1000;
1878c0984e5SSebastian Reichel
1888c0984e5SSebastian Reichel ret = regmap_read(chip->regmap, MAX17042_VCELL, &val);
1898c0984e5SSebastian Reichel if (ret < 0)
1908c0984e5SSebastian Reichel goto health_error;
1918c0984e5SSebastian Reichel
1928c0984e5SSebastian Reichel /* bits [0-3] unused */
1938c0984e5SSebastian Reichel vbatt = val * 625 / 8;
1948c0984e5SSebastian Reichel /* Convert to millivolts */
1958c0984e5SSebastian Reichel vbatt /= 1000;
1968c0984e5SSebastian Reichel
1978c0984e5SSebastian Reichel if (vavg < chip->pdata->vmin) {
1988c0984e5SSebastian Reichel *health = POWER_SUPPLY_HEALTH_DEAD;
1998c0984e5SSebastian Reichel goto out;
2008c0984e5SSebastian Reichel }
2018c0984e5SSebastian Reichel
2028c0984e5SSebastian Reichel if (vbatt > chip->pdata->vmax + MAX17042_VMAX_TOLERANCE) {
2038c0984e5SSebastian Reichel *health = POWER_SUPPLY_HEALTH_OVERVOLTAGE;
2048c0984e5SSebastian Reichel goto out;
2058c0984e5SSebastian Reichel }
2068c0984e5SSebastian Reichel
2078c0984e5SSebastian Reichel ret = max17042_get_temperature(chip, &temp);
2088c0984e5SSebastian Reichel if (ret < 0)
2098c0984e5SSebastian Reichel goto health_error;
2108c0984e5SSebastian Reichel
21191736213SHans de Goede if (temp < chip->pdata->temp_min) {
2128c0984e5SSebastian Reichel *health = POWER_SUPPLY_HEALTH_COLD;
2138c0984e5SSebastian Reichel goto out;
2148c0984e5SSebastian Reichel }
2158c0984e5SSebastian Reichel
21691736213SHans de Goede if (temp > chip->pdata->temp_max) {
2178c0984e5SSebastian Reichel *health = POWER_SUPPLY_HEALTH_OVERHEAT;
2188c0984e5SSebastian Reichel goto out;
2198c0984e5SSebastian Reichel }
2208c0984e5SSebastian Reichel
2218c0984e5SSebastian Reichel *health = POWER_SUPPLY_HEALTH_GOOD;
2228c0984e5SSebastian Reichel
2238c0984e5SSebastian Reichel out:
2248c0984e5SSebastian Reichel return 0;
2258c0984e5SSebastian Reichel
2268c0984e5SSebastian Reichel health_error:
2278c0984e5SSebastian Reichel return ret;
2288c0984e5SSebastian Reichel }
2298c0984e5SSebastian Reichel
max17042_get_property(struct power_supply * psy,enum power_supply_property psp,union power_supply_propval * val)2308c0984e5SSebastian Reichel static int max17042_get_property(struct power_supply *psy,
2318c0984e5SSebastian Reichel enum power_supply_property psp,
2328c0984e5SSebastian Reichel union power_supply_propval *val)
2338c0984e5SSebastian Reichel {
2348c0984e5SSebastian Reichel struct max17042_chip *chip = power_supply_get_drvdata(psy);
2358c0984e5SSebastian Reichel struct regmap *map = chip->regmap;
2368c0984e5SSebastian Reichel int ret;
2378c0984e5SSebastian Reichel u32 data;
238d7d15fc6SHans de Goede u64 data64;
2398c0984e5SSebastian Reichel
2408c0984e5SSebastian Reichel if (!chip->init_complete)
2418c0984e5SSebastian Reichel return -EAGAIN;
2428c0984e5SSebastian Reichel
2438c0984e5SSebastian Reichel switch (psp) {
244a9df22c0SHans de Goede case POWER_SUPPLY_PROP_STATUS:
245a9df22c0SHans de Goede ret = max17042_get_status(chip, &val->intval);
246a9df22c0SHans de Goede if (ret < 0)
247a9df22c0SHans de Goede return ret;
248a9df22c0SHans de Goede break;
2498c0984e5SSebastian Reichel case POWER_SUPPLY_PROP_PRESENT:
2508c0984e5SSebastian Reichel ret = regmap_read(map, MAX17042_STATUS, &data);
2518c0984e5SSebastian Reichel if (ret < 0)
2528c0984e5SSebastian Reichel return ret;
2538c0984e5SSebastian Reichel
2548c0984e5SSebastian Reichel if (data & MAX17042_STATUS_BattAbsent)
2558c0984e5SSebastian Reichel val->intval = 0;
2568c0984e5SSebastian Reichel else
2578c0984e5SSebastian Reichel val->intval = 1;
2588c0984e5SSebastian Reichel break;
259ef7fcdaeSHans de Goede case POWER_SUPPLY_PROP_TECHNOLOGY:
260ef7fcdaeSHans de Goede val->intval = POWER_SUPPLY_TECHNOLOGY_LION;
261ef7fcdaeSHans de Goede break;
2628c0984e5SSebastian Reichel case POWER_SUPPLY_PROP_CYCLE_COUNT:
2638c0984e5SSebastian Reichel ret = regmap_read(map, MAX17042_Cycles, &data);
2648c0984e5SSebastian Reichel if (ret < 0)
2658c0984e5SSebastian Reichel return ret;
2668c0984e5SSebastian Reichel
2678c0984e5SSebastian Reichel val->intval = data;
2688c0984e5SSebastian Reichel break;
2698c0984e5SSebastian Reichel case POWER_SUPPLY_PROP_VOLTAGE_MAX:
2708c0984e5SSebastian Reichel ret = regmap_read(map, MAX17042_MinMaxVolt, &data);
2718c0984e5SSebastian Reichel if (ret < 0)
2728c0984e5SSebastian Reichel return ret;
2738c0984e5SSebastian Reichel
2748c0984e5SSebastian Reichel val->intval = data >> 8;
2758c0984e5SSebastian Reichel val->intval *= 20000; /* Units of LSB = 20mV */
2768c0984e5SSebastian Reichel break;
2777bfc9397SHans de Goede case POWER_SUPPLY_PROP_VOLTAGE_MIN:
2787bfc9397SHans de Goede ret = regmap_read(map, MAX17042_MinMaxVolt, &data);
2797bfc9397SHans de Goede if (ret < 0)
2807bfc9397SHans de Goede return ret;
2817bfc9397SHans de Goede
2827bfc9397SHans de Goede val->intval = (data & 0xff) * 20000; /* Units of 20mV */
2837bfc9397SHans de Goede break;
2848c0984e5SSebastian Reichel case POWER_SUPPLY_PROP_VOLTAGE_MIN_DESIGN:
2858c0984e5SSebastian Reichel if (chip->chip_type == MAXIM_DEVICE_TYPE_MAX17042)
2868c0984e5SSebastian Reichel ret = regmap_read(map, MAX17042_V_empty, &data);
2878c0984e5SSebastian Reichel else
2888c0984e5SSebastian Reichel ret = regmap_read(map, MAX17047_V_empty, &data);
2898c0984e5SSebastian Reichel if (ret < 0)
2908c0984e5SSebastian Reichel return ret;
2918c0984e5SSebastian Reichel
2928c0984e5SSebastian Reichel val->intval = data >> 7;
2938c0984e5SSebastian Reichel val->intval *= 10000; /* Units of LSB = 10mV */
2948c0984e5SSebastian Reichel break;
2958c0984e5SSebastian Reichel case POWER_SUPPLY_PROP_VOLTAGE_NOW:
2968c0984e5SSebastian Reichel ret = regmap_read(map, MAX17042_VCELL, &data);
2978c0984e5SSebastian Reichel if (ret < 0)
2988c0984e5SSebastian Reichel return ret;
2998c0984e5SSebastian Reichel
3008c0984e5SSebastian Reichel val->intval = data * 625 / 8;
3018c0984e5SSebastian Reichel break;
3028c0984e5SSebastian Reichel case POWER_SUPPLY_PROP_VOLTAGE_AVG:
3038c0984e5SSebastian Reichel ret = regmap_read(map, MAX17042_AvgVCELL, &data);
3048c0984e5SSebastian Reichel if (ret < 0)
3058c0984e5SSebastian Reichel return ret;
3068c0984e5SSebastian Reichel
3078c0984e5SSebastian Reichel val->intval = data * 625 / 8;
3088c0984e5SSebastian Reichel break;
3098c0984e5SSebastian Reichel case POWER_SUPPLY_PROP_VOLTAGE_OCV:
3108c0984e5SSebastian Reichel ret = regmap_read(map, MAX17042_OCVInternal, &data);
3118c0984e5SSebastian Reichel if (ret < 0)
3128c0984e5SSebastian Reichel return ret;
3138c0984e5SSebastian Reichel
3148c0984e5SSebastian Reichel val->intval = data * 625 / 8;
3158c0984e5SSebastian Reichel break;
3168c0984e5SSebastian Reichel case POWER_SUPPLY_PROP_CAPACITY:
317223a3b82SHenrik Grimler if (chip->pdata->enable_current_sense)
3188c0984e5SSebastian Reichel ret = regmap_read(map, MAX17042_RepSOC, &data);
319223a3b82SHenrik Grimler else
320223a3b82SHenrik Grimler ret = regmap_read(map, MAX17042_VFSOC, &data);
3218c0984e5SSebastian Reichel if (ret < 0)
3228c0984e5SSebastian Reichel return ret;
3238c0984e5SSebastian Reichel
3248c0984e5SSebastian Reichel val->intval = data >> 8;
3258c0984e5SSebastian Reichel break;
3262e015412SHans de Goede case POWER_SUPPLY_PROP_CHARGE_FULL_DESIGN:
3272e015412SHans de Goede ret = regmap_read(map, MAX17042_DesignCap, &data);
3282e015412SHans de Goede if (ret < 0)
3292e015412SHans de Goede return ret;
3302e015412SHans de Goede
3312e015412SHans de Goede data64 = data * 5000000ll;
3322e015412SHans de Goede do_div(data64, chip->pdata->r_sns);
3332e015412SHans de Goede val->intval = data64;
3342e015412SHans de Goede break;
3358c0984e5SSebastian Reichel case POWER_SUPPLY_PROP_CHARGE_FULL:
3368c0984e5SSebastian Reichel ret = regmap_read(map, MAX17042_FullCAP, &data);
3378c0984e5SSebastian Reichel if (ret < 0)
3388c0984e5SSebastian Reichel return ret;
3398c0984e5SSebastian Reichel
340d7d15fc6SHans de Goede data64 = data * 5000000ll;
341d7d15fc6SHans de Goede do_div(data64, chip->pdata->r_sns);
342d7d15fc6SHans de Goede val->intval = data64;
3438c0984e5SSebastian Reichel break;
3446d6b61eaSHans de Goede case POWER_SUPPLY_PROP_CHARGE_NOW:
3456d6b61eaSHans de Goede ret = regmap_read(map, MAX17042_RepCap, &data);
3466d6b61eaSHans de Goede if (ret < 0)
3476d6b61eaSHans de Goede return ret;
3486d6b61eaSHans de Goede
3496d6b61eaSHans de Goede data64 = data * 5000000ll;
3506d6b61eaSHans de Goede do_div(data64, chip->pdata->r_sns);
3516d6b61eaSHans de Goede val->intval = data64;
3526d6b61eaSHans de Goede break;
3538c0984e5SSebastian Reichel case POWER_SUPPLY_PROP_CHARGE_COUNTER:
3548c0984e5SSebastian Reichel ret = regmap_read(map, MAX17042_QH, &data);
3558c0984e5SSebastian Reichel if (ret < 0)
3568c0984e5SSebastian Reichel return ret;
3578c0984e5SSebastian Reichel
3586dcfa009SSebastian Krzyszkowiak data64 = sign_extend64(data, 15) * 5000000ll;
3596dcfa009SSebastian Krzyszkowiak val->intval = div_s64(data64, chip->pdata->r_sns);
3608c0984e5SSebastian Reichel break;
3618c0984e5SSebastian Reichel case POWER_SUPPLY_PROP_TEMP:
3628c0984e5SSebastian Reichel ret = max17042_get_temperature(chip, &val->intval);
3638c0984e5SSebastian Reichel if (ret < 0)
3648c0984e5SSebastian Reichel return ret;
3658c0984e5SSebastian Reichel break;
3668c0984e5SSebastian Reichel case POWER_SUPPLY_PROP_TEMP_ALERT_MIN:
3678c0984e5SSebastian Reichel ret = regmap_read(map, MAX17042_TALRT_Th, &data);
3688c0984e5SSebastian Reichel if (ret < 0)
3698c0984e5SSebastian Reichel return ret;
3708c0984e5SSebastian Reichel /* LSB is Alert Minimum. In deci-centigrade */
3712814913cSHans de Goede val->intval = sign_extend32(data & 0xff, 7) * 10;
3728c0984e5SSebastian Reichel break;
3738c0984e5SSebastian Reichel case POWER_SUPPLY_PROP_TEMP_ALERT_MAX:
3748c0984e5SSebastian Reichel ret = regmap_read(map, MAX17042_TALRT_Th, &data);
3758c0984e5SSebastian Reichel if (ret < 0)
3768c0984e5SSebastian Reichel return ret;
3778c0984e5SSebastian Reichel /* MSB is Alert Maximum. In deci-centigrade */
3782814913cSHans de Goede val->intval = sign_extend32(data >> 8, 7) * 10;
3798c0984e5SSebastian Reichel break;
3808c0984e5SSebastian Reichel case POWER_SUPPLY_PROP_TEMP_MIN:
3818c0984e5SSebastian Reichel val->intval = chip->pdata->temp_min;
3828c0984e5SSebastian Reichel break;
3838c0984e5SSebastian Reichel case POWER_SUPPLY_PROP_TEMP_MAX:
3848c0984e5SSebastian Reichel val->intval = chip->pdata->temp_max;
3858c0984e5SSebastian Reichel break;
3868c0984e5SSebastian Reichel case POWER_SUPPLY_PROP_HEALTH:
3878c0984e5SSebastian Reichel ret = max17042_get_battery_health(chip, &val->intval);
3888c0984e5SSebastian Reichel if (ret < 0)
3898c0984e5SSebastian Reichel return ret;
3908c0984e5SSebastian Reichel break;
391adb69a3cSHans de Goede case POWER_SUPPLY_PROP_SCOPE:
392adb69a3cSHans de Goede val->intval = POWER_SUPPLY_SCOPE_SYSTEM;
393adb69a3cSHans de Goede break;
3948c0984e5SSebastian Reichel case POWER_SUPPLY_PROP_CURRENT_NOW:
3958c0984e5SSebastian Reichel if (chip->pdata->enable_current_sense) {
3968c0984e5SSebastian Reichel ret = regmap_read(map, MAX17042_Current, &data);
3978c0984e5SSebastian Reichel if (ret < 0)
3988c0984e5SSebastian Reichel return ret;
3998c0984e5SSebastian Reichel
4009e39ef14SSebastian Krzyszkowiak data64 = sign_extend64(data, 15) * 1562500ll;
4019e39ef14SSebastian Krzyszkowiak val->intval = div_s64(data64, chip->pdata->r_sns);
4028c0984e5SSebastian Reichel } else {
4038c0984e5SSebastian Reichel return -EINVAL;
4048c0984e5SSebastian Reichel }
4058c0984e5SSebastian Reichel break;
4068c0984e5SSebastian Reichel case POWER_SUPPLY_PROP_CURRENT_AVG:
4078c0984e5SSebastian Reichel if (chip->pdata->enable_current_sense) {
4088c0984e5SSebastian Reichel ret = regmap_read(map, MAX17042_AvgCurrent, &data);
4098c0984e5SSebastian Reichel if (ret < 0)
4108c0984e5SSebastian Reichel return ret;
4118c0984e5SSebastian Reichel
4129e39ef14SSebastian Krzyszkowiak data64 = sign_extend64(data, 15) * 1562500ll;
4139e39ef14SSebastian Krzyszkowiak val->intval = div_s64(data64, chip->pdata->r_sns);
4148c0984e5SSebastian Reichel } else {
4158c0984e5SSebastian Reichel return -EINVAL;
4168c0984e5SSebastian Reichel }
4178c0984e5SSebastian Reichel break;
4185225371eSSebastian Krzyszkowiak case POWER_SUPPLY_PROP_CHARGE_TERM_CURRENT:
4195225371eSSebastian Krzyszkowiak ret = regmap_read(map, MAX17042_ICHGTerm, &data);
4205225371eSSebastian Krzyszkowiak if (ret < 0)
4215225371eSSebastian Krzyszkowiak return ret;
4225225371eSSebastian Krzyszkowiak
4235225371eSSebastian Krzyszkowiak data64 = data * 1562500ll;
4245225371eSSebastian Krzyszkowiak val->intval = div_s64(data64, chip->pdata->r_sns);
4255225371eSSebastian Krzyszkowiak break;
42621b01cc8SGeordan Neukum case POWER_SUPPLY_PROP_TIME_TO_EMPTY_NOW:
42721b01cc8SGeordan Neukum ret = regmap_read(map, MAX17042_TTE, &data);
42821b01cc8SGeordan Neukum if (ret < 0)
42921b01cc8SGeordan Neukum return ret;
43021b01cc8SGeordan Neukum
43121b01cc8SGeordan Neukum val->intval = data * 5625 / 1000;
43221b01cc8SGeordan Neukum break;
4338c0984e5SSebastian Reichel default:
4348c0984e5SSebastian Reichel return -EINVAL;
4358c0984e5SSebastian Reichel }
4368c0984e5SSebastian Reichel return 0;
4378c0984e5SSebastian Reichel }
4388c0984e5SSebastian Reichel
max17042_set_property(struct power_supply * psy,enum power_supply_property psp,const union power_supply_propval * val)4398c0984e5SSebastian Reichel static int max17042_set_property(struct power_supply *psy,
4408c0984e5SSebastian Reichel enum power_supply_property psp,
4418c0984e5SSebastian Reichel const union power_supply_propval *val)
4428c0984e5SSebastian Reichel {
4438c0984e5SSebastian Reichel struct max17042_chip *chip = power_supply_get_drvdata(psy);
4448c0984e5SSebastian Reichel struct regmap *map = chip->regmap;
4458c0984e5SSebastian Reichel int ret = 0;
4468c0984e5SSebastian Reichel u32 data;
4478c0984e5SSebastian Reichel int8_t temp;
4488c0984e5SSebastian Reichel
4498c0984e5SSebastian Reichel switch (psp) {
4508c0984e5SSebastian Reichel case POWER_SUPPLY_PROP_TEMP_ALERT_MIN:
4518c0984e5SSebastian Reichel ret = regmap_read(map, MAX17042_TALRT_Th, &data);
4528c0984e5SSebastian Reichel if (ret < 0)
4538c0984e5SSebastian Reichel return ret;
4548c0984e5SSebastian Reichel
4558c0984e5SSebastian Reichel /* Input in deci-centigrade, convert to centigrade */
4568c0984e5SSebastian Reichel temp = val->intval / 10;
4578c0984e5SSebastian Reichel /* force min < max */
4588c0984e5SSebastian Reichel if (temp >= (int8_t)(data >> 8))
4598c0984e5SSebastian Reichel temp = (int8_t)(data >> 8) - 1;
4608c0984e5SSebastian Reichel /* Write both MAX and MIN ALERT */
4618c0984e5SSebastian Reichel data = (data & 0xff00) + temp;
4628c0984e5SSebastian Reichel ret = regmap_write(map, MAX17042_TALRT_Th, data);
4638c0984e5SSebastian Reichel break;
4648c0984e5SSebastian Reichel case POWER_SUPPLY_PROP_TEMP_ALERT_MAX:
4658c0984e5SSebastian Reichel ret = regmap_read(map, MAX17042_TALRT_Th, &data);
4668c0984e5SSebastian Reichel if (ret < 0)
4678c0984e5SSebastian Reichel return ret;
4688c0984e5SSebastian Reichel
4698c0984e5SSebastian Reichel /* Input in Deci-Centigrade, convert to centigrade */
4708c0984e5SSebastian Reichel temp = val->intval / 10;
4718c0984e5SSebastian Reichel /* force max > min */
4728c0984e5SSebastian Reichel if (temp <= (int8_t)(data & 0xff))
4738c0984e5SSebastian Reichel temp = (int8_t)(data & 0xff) + 1;
4748c0984e5SSebastian Reichel /* Write both MAX and MIN ALERT */
4758c0984e5SSebastian Reichel data = (data & 0xff) + (temp << 8);
4768c0984e5SSebastian Reichel ret = regmap_write(map, MAX17042_TALRT_Th, data);
4778c0984e5SSebastian Reichel break;
4788c0984e5SSebastian Reichel default:
4798c0984e5SSebastian Reichel ret = -EINVAL;
4808c0984e5SSebastian Reichel }
4818c0984e5SSebastian Reichel
4828c0984e5SSebastian Reichel return ret;
4838c0984e5SSebastian Reichel }
4848c0984e5SSebastian Reichel
max17042_property_is_writeable(struct power_supply * psy,enum power_supply_property psp)4858c0984e5SSebastian Reichel static int max17042_property_is_writeable(struct power_supply *psy,
4868c0984e5SSebastian Reichel enum power_supply_property psp)
4878c0984e5SSebastian Reichel {
4888c0984e5SSebastian Reichel int ret;
4898c0984e5SSebastian Reichel
4908c0984e5SSebastian Reichel switch (psp) {
4918c0984e5SSebastian Reichel case POWER_SUPPLY_PROP_TEMP_ALERT_MIN:
4928c0984e5SSebastian Reichel case POWER_SUPPLY_PROP_TEMP_ALERT_MAX:
4938c0984e5SSebastian Reichel ret = 1;
4948c0984e5SSebastian Reichel break;
4958c0984e5SSebastian Reichel default:
4968c0984e5SSebastian Reichel ret = 0;
4978c0984e5SSebastian Reichel }
4988c0984e5SSebastian Reichel
4998c0984e5SSebastian Reichel return ret;
5008c0984e5SSebastian Reichel }
5018c0984e5SSebastian Reichel
max17042_write_verify_reg(struct regmap * map,u8 reg,u32 value)5028c0984e5SSebastian Reichel static int max17042_write_verify_reg(struct regmap *map, u8 reg, u32 value)
5038c0984e5SSebastian Reichel {
5048c0984e5SSebastian Reichel int retries = 8;
5058c0984e5SSebastian Reichel int ret;
5068c0984e5SSebastian Reichel u32 read_value;
5078c0984e5SSebastian Reichel
5088c0984e5SSebastian Reichel do {
5098c0984e5SSebastian Reichel ret = regmap_write(map, reg, value);
5108c0984e5SSebastian Reichel regmap_read(map, reg, &read_value);
5118c0984e5SSebastian Reichel if (read_value != value) {
5128c0984e5SSebastian Reichel ret = -EIO;
5138c0984e5SSebastian Reichel retries--;
5148c0984e5SSebastian Reichel }
5158c0984e5SSebastian Reichel } while (retries && read_value != value);
5168c0984e5SSebastian Reichel
5178c0984e5SSebastian Reichel if (ret < 0)
5188c0984e5SSebastian Reichel pr_err("%s: err %d\n", __func__, ret);
5198c0984e5SSebastian Reichel
5208c0984e5SSebastian Reichel return ret;
5218c0984e5SSebastian Reichel }
5228c0984e5SSebastian Reichel
max17042_override_por(struct regmap * map,u8 reg,u16 value)5238c0984e5SSebastian Reichel static inline void max17042_override_por(struct regmap *map,
5248c0984e5SSebastian Reichel u8 reg, u16 value)
5258c0984e5SSebastian Reichel {
5268c0984e5SSebastian Reichel if (value)
5278c0984e5SSebastian Reichel regmap_write(map, reg, value);
5288c0984e5SSebastian Reichel }
5298c0984e5SSebastian Reichel
max17042_unlock_model(struct max17042_chip * chip)53040badfa3SChristophe JAILLET static inline void max17042_unlock_model(struct max17042_chip *chip)
5318c0984e5SSebastian Reichel {
5328c0984e5SSebastian Reichel struct regmap *map = chip->regmap;
5338c0984e5SSebastian Reichel
5348c0984e5SSebastian Reichel regmap_write(map, MAX17042_MLOCKReg1, MODEL_UNLOCK1);
5358c0984e5SSebastian Reichel regmap_write(map, MAX17042_MLOCKReg2, MODEL_UNLOCK2);
5368c0984e5SSebastian Reichel }
5378c0984e5SSebastian Reichel
max17042_lock_model(struct max17042_chip * chip)53840badfa3SChristophe JAILLET static inline void max17042_lock_model(struct max17042_chip *chip)
5398c0984e5SSebastian Reichel {
5408c0984e5SSebastian Reichel struct regmap *map = chip->regmap;
5418c0984e5SSebastian Reichel
5428c0984e5SSebastian Reichel regmap_write(map, MAX17042_MLOCKReg1, MODEL_LOCK1);
5438c0984e5SSebastian Reichel regmap_write(map, MAX17042_MLOCKReg2, MODEL_LOCK2);
5448c0984e5SSebastian Reichel }
5458c0984e5SSebastian Reichel
max17042_write_model_data(struct max17042_chip * chip,u8 addr,int size)5468c0984e5SSebastian Reichel static inline void max17042_write_model_data(struct max17042_chip *chip,
5478c0984e5SSebastian Reichel u8 addr, int size)
5488c0984e5SSebastian Reichel {
5498c0984e5SSebastian Reichel struct regmap *map = chip->regmap;
5508c0984e5SSebastian Reichel int i;
5518c0984e5SSebastian Reichel
5528c0984e5SSebastian Reichel for (i = 0; i < size; i++)
5538c0984e5SSebastian Reichel regmap_write(map, addr + i,
5548c0984e5SSebastian Reichel chip->pdata->config_data->cell_char_tbl[i]);
5558c0984e5SSebastian Reichel }
5568c0984e5SSebastian Reichel
max17042_read_model_data(struct max17042_chip * chip,u8 addr,u16 * data,int size)5578c0984e5SSebastian Reichel static inline void max17042_read_model_data(struct max17042_chip *chip,
558f7c8f1deSSebastian Reichel u8 addr, u16 *data, int size)
5598c0984e5SSebastian Reichel {
5608c0984e5SSebastian Reichel struct regmap *map = chip->regmap;
5618c0984e5SSebastian Reichel int i;
562f7c8f1deSSebastian Reichel u32 tmp;
5638c0984e5SSebastian Reichel
564f7c8f1deSSebastian Reichel for (i = 0; i < size; i++) {
565f7c8f1deSSebastian Reichel regmap_read(map, addr + i, &tmp);
566f7c8f1deSSebastian Reichel data[i] = (u16)tmp;
567f7c8f1deSSebastian Reichel }
5688c0984e5SSebastian Reichel }
5698c0984e5SSebastian Reichel
max17042_model_data_compare(struct max17042_chip * chip,u16 * data1,u16 * data2,int size)5708c0984e5SSebastian Reichel static inline int max17042_model_data_compare(struct max17042_chip *chip,
5718c0984e5SSebastian Reichel u16 *data1, u16 *data2, int size)
5728c0984e5SSebastian Reichel {
5738c0984e5SSebastian Reichel int i;
5748c0984e5SSebastian Reichel
5758c0984e5SSebastian Reichel if (memcmp(data1, data2, size)) {
5768c0984e5SSebastian Reichel dev_err(&chip->client->dev, "%s compare failed\n", __func__);
5778c0984e5SSebastian Reichel for (i = 0; i < size; i++)
5788c0984e5SSebastian Reichel dev_info(&chip->client->dev, "0x%x, 0x%x",
5798c0984e5SSebastian Reichel data1[i], data2[i]);
5808c0984e5SSebastian Reichel dev_info(&chip->client->dev, "\n");
5818c0984e5SSebastian Reichel return -EINVAL;
5828c0984e5SSebastian Reichel }
5838c0984e5SSebastian Reichel return 0;
5848c0984e5SSebastian Reichel }
5858c0984e5SSebastian Reichel
max17042_init_model(struct max17042_chip * chip)5868c0984e5SSebastian Reichel static int max17042_init_model(struct max17042_chip *chip)
5878c0984e5SSebastian Reichel {
5888c0984e5SSebastian Reichel int ret;
5898c0984e5SSebastian Reichel int table_size = ARRAY_SIZE(chip->pdata->config_data->cell_char_tbl);
590f7c8f1deSSebastian Reichel u16 *temp_data;
5918c0984e5SSebastian Reichel
5928c0984e5SSebastian Reichel temp_data = kcalloc(table_size, sizeof(*temp_data), GFP_KERNEL);
5938c0984e5SSebastian Reichel if (!temp_data)
5948c0984e5SSebastian Reichel return -ENOMEM;
5958c0984e5SSebastian Reichel
59640badfa3SChristophe JAILLET max17042_unlock_model(chip);
5978c0984e5SSebastian Reichel max17042_write_model_data(chip, MAX17042_MODELChrTbl,
5988c0984e5SSebastian Reichel table_size);
5998c0984e5SSebastian Reichel max17042_read_model_data(chip, MAX17042_MODELChrTbl, temp_data,
6008c0984e5SSebastian Reichel table_size);
6018c0984e5SSebastian Reichel
6028c0984e5SSebastian Reichel ret = max17042_model_data_compare(
6038c0984e5SSebastian Reichel chip,
6048c0984e5SSebastian Reichel chip->pdata->config_data->cell_char_tbl,
605f7c8f1deSSebastian Reichel temp_data,
6068c0984e5SSebastian Reichel table_size);
6078c0984e5SSebastian Reichel
60840badfa3SChristophe JAILLET max17042_lock_model(chip);
6098c0984e5SSebastian Reichel kfree(temp_data);
6108c0984e5SSebastian Reichel
6118c0984e5SSebastian Reichel return ret;
6128c0984e5SSebastian Reichel }
6138c0984e5SSebastian Reichel
max17042_verify_model_lock(struct max17042_chip * chip)6148c0984e5SSebastian Reichel static int max17042_verify_model_lock(struct max17042_chip *chip)
6158c0984e5SSebastian Reichel {
6168c0984e5SSebastian Reichel int i;
6178c0984e5SSebastian Reichel int table_size = ARRAY_SIZE(chip->pdata->config_data->cell_char_tbl);
618f7c8f1deSSebastian Reichel u16 *temp_data;
6198c0984e5SSebastian Reichel int ret = 0;
6208c0984e5SSebastian Reichel
6218c0984e5SSebastian Reichel temp_data = kcalloc(table_size, sizeof(*temp_data), GFP_KERNEL);
6228c0984e5SSebastian Reichel if (!temp_data)
6238c0984e5SSebastian Reichel return -ENOMEM;
6248c0984e5SSebastian Reichel
6258c0984e5SSebastian Reichel max17042_read_model_data(chip, MAX17042_MODELChrTbl, temp_data,
6268c0984e5SSebastian Reichel table_size);
6278c0984e5SSebastian Reichel for (i = 0; i < table_size; i++)
6288c0984e5SSebastian Reichel if (temp_data[i])
6298c0984e5SSebastian Reichel ret = -EINVAL;
6308c0984e5SSebastian Reichel
6318c0984e5SSebastian Reichel kfree(temp_data);
6328c0984e5SSebastian Reichel return ret;
6338c0984e5SSebastian Reichel }
6348c0984e5SSebastian Reichel
max17042_write_config_regs(struct max17042_chip * chip)6358c0984e5SSebastian Reichel static void max17042_write_config_regs(struct max17042_chip *chip)
6368c0984e5SSebastian Reichel {
6378c0984e5SSebastian Reichel struct max17042_config_data *config = chip->pdata->config_data;
6388c0984e5SSebastian Reichel struct regmap *map = chip->regmap;
6398c0984e5SSebastian Reichel
6408c0984e5SSebastian Reichel regmap_write(map, MAX17042_CONFIG, config->config);
6418c0984e5SSebastian Reichel regmap_write(map, MAX17042_LearnCFG, config->learn_cfg);
6428c0984e5SSebastian Reichel regmap_write(map, MAX17042_FilterCFG,
6438c0984e5SSebastian Reichel config->filter_cfg);
6448c0984e5SSebastian Reichel regmap_write(map, MAX17042_RelaxCFG, config->relax_cfg);
6458c0984e5SSebastian Reichel if (chip->chip_type == MAXIM_DEVICE_TYPE_MAX17047 ||
646bc90705bSAngus Ainslie (Purism) chip->chip_type == MAXIM_DEVICE_TYPE_MAX17050 ||
647bc90705bSAngus Ainslie (Purism) chip->chip_type == MAXIM_DEVICE_TYPE_MAX17055)
6488c0984e5SSebastian Reichel regmap_write(map, MAX17047_FullSOCThr,
6498c0984e5SSebastian Reichel config->full_soc_thresh);
6508c0984e5SSebastian Reichel }
6518c0984e5SSebastian Reichel
max17042_write_custom_regs(struct max17042_chip * chip)6528c0984e5SSebastian Reichel static void max17042_write_custom_regs(struct max17042_chip *chip)
6538c0984e5SSebastian Reichel {
6548c0984e5SSebastian Reichel struct max17042_config_data *config = chip->pdata->config_data;
6558c0984e5SSebastian Reichel struct regmap *map = chip->regmap;
6568c0984e5SSebastian Reichel
6578c0984e5SSebastian Reichel max17042_write_verify_reg(map, MAX17042_RCOMP0, config->rcomp0);
6588c0984e5SSebastian Reichel max17042_write_verify_reg(map, MAX17042_TempCo, config->tcompc0);
6598c0984e5SSebastian Reichel max17042_write_verify_reg(map, MAX17042_ICHGTerm, config->ichgt_term);
6608c0984e5SSebastian Reichel if (chip->chip_type == MAXIM_DEVICE_TYPE_MAX17042) {
6618c0984e5SSebastian Reichel regmap_write(map, MAX17042_EmptyTempCo, config->empty_tempco);
6628c0984e5SSebastian Reichel max17042_write_verify_reg(map, MAX17042_K_empty0,
6638c0984e5SSebastian Reichel config->kempty0);
6648c0984e5SSebastian Reichel } else {
6658c0984e5SSebastian Reichel max17042_write_verify_reg(map, MAX17047_QRTbl00,
6668c0984e5SSebastian Reichel config->qrtbl00);
6678c0984e5SSebastian Reichel max17042_write_verify_reg(map, MAX17047_QRTbl10,
6688c0984e5SSebastian Reichel config->qrtbl10);
6698c0984e5SSebastian Reichel max17042_write_verify_reg(map, MAX17047_QRTbl20,
6708c0984e5SSebastian Reichel config->qrtbl20);
6718c0984e5SSebastian Reichel max17042_write_verify_reg(map, MAX17047_QRTbl30,
6728c0984e5SSebastian Reichel config->qrtbl30);
6738c0984e5SSebastian Reichel }
6748c0984e5SSebastian Reichel }
6758c0984e5SSebastian Reichel
max17042_update_capacity_regs(struct max17042_chip * chip)6768c0984e5SSebastian Reichel static void max17042_update_capacity_regs(struct max17042_chip *chip)
6778c0984e5SSebastian Reichel {
6788c0984e5SSebastian Reichel struct max17042_config_data *config = chip->pdata->config_data;
6798c0984e5SSebastian Reichel struct regmap *map = chip->regmap;
6808c0984e5SSebastian Reichel
6818c0984e5SSebastian Reichel max17042_write_verify_reg(map, MAX17042_FullCAP,
6828c0984e5SSebastian Reichel config->fullcap);
6838c0984e5SSebastian Reichel regmap_write(map, MAX17042_DesignCap, config->design_cap);
6848c0984e5SSebastian Reichel max17042_write_verify_reg(map, MAX17042_FullCAPNom,
6858c0984e5SSebastian Reichel config->fullcapnom);
6868c0984e5SSebastian Reichel }
6878c0984e5SSebastian Reichel
max17042_reset_vfsoc0_reg(struct max17042_chip * chip)6888c0984e5SSebastian Reichel static void max17042_reset_vfsoc0_reg(struct max17042_chip *chip)
6898c0984e5SSebastian Reichel {
6908c0984e5SSebastian Reichel unsigned int vfSoc;
6918c0984e5SSebastian Reichel struct regmap *map = chip->regmap;
6928c0984e5SSebastian Reichel
6938c0984e5SSebastian Reichel regmap_read(map, MAX17042_VFSOC, &vfSoc);
6948c0984e5SSebastian Reichel regmap_write(map, MAX17042_VFSOC0Enable, VFSOC0_UNLOCK);
6958c0984e5SSebastian Reichel max17042_write_verify_reg(map, MAX17042_VFSOC0, vfSoc);
6968c0984e5SSebastian Reichel regmap_write(map, MAX17042_VFSOC0Enable, VFSOC0_LOCK);
6978c0984e5SSebastian Reichel }
6988c0984e5SSebastian Reichel
max17042_load_new_capacity_params(struct max17042_chip * chip)6998c0984e5SSebastian Reichel static void max17042_load_new_capacity_params(struct max17042_chip *chip)
7008c0984e5SSebastian Reichel {
7018c0984e5SSebastian Reichel u32 full_cap0, rep_cap, dq_acc, vfSoc;
7028c0984e5SSebastian Reichel u32 rem_cap;
7038c0984e5SSebastian Reichel
7048c0984e5SSebastian Reichel struct max17042_config_data *config = chip->pdata->config_data;
7058c0984e5SSebastian Reichel struct regmap *map = chip->regmap;
7068c0984e5SSebastian Reichel
7078c0984e5SSebastian Reichel regmap_read(map, MAX17042_FullCAP0, &full_cap0);
7088c0984e5SSebastian Reichel regmap_read(map, MAX17042_VFSOC, &vfSoc);
7098c0984e5SSebastian Reichel
7108c0984e5SSebastian Reichel /* fg_vfSoc needs to shifted by 8 bits to get the
7118c0984e5SSebastian Reichel * perc in 1% accuracy, to get the right rem_cap multiply
7128c0984e5SSebastian Reichel * full_cap0, fg_vfSoc and devide by 100
7138c0984e5SSebastian Reichel */
7148c0984e5SSebastian Reichel rem_cap = ((vfSoc >> 8) * full_cap0) / 100;
7158c0984e5SSebastian Reichel max17042_write_verify_reg(map, MAX17042_RemCap, rem_cap);
7168c0984e5SSebastian Reichel
7178c0984e5SSebastian Reichel rep_cap = rem_cap;
7188c0984e5SSebastian Reichel max17042_write_verify_reg(map, MAX17042_RepCap, rep_cap);
7198c0984e5SSebastian Reichel
7208c0984e5SSebastian Reichel /* Write dQ_acc to 200% of Capacity and dP_acc to 200% */
7218c0984e5SSebastian Reichel dq_acc = config->fullcap / dQ_ACC_DIV;
7228c0984e5SSebastian Reichel max17042_write_verify_reg(map, MAX17042_dQacc, dq_acc);
7238c0984e5SSebastian Reichel max17042_write_verify_reg(map, MAX17042_dPacc, dP_ACC_200);
7248c0984e5SSebastian Reichel
7258c0984e5SSebastian Reichel max17042_write_verify_reg(map, MAX17042_FullCAP,
7268c0984e5SSebastian Reichel config->fullcap);
7278c0984e5SSebastian Reichel regmap_write(map, MAX17042_DesignCap,
7288c0984e5SSebastian Reichel config->design_cap);
7298c0984e5SSebastian Reichel max17042_write_verify_reg(map, MAX17042_FullCAPNom,
7308c0984e5SSebastian Reichel config->fullcapnom);
7318c0984e5SSebastian Reichel /* Update SOC register with new SOC */
7328c0984e5SSebastian Reichel regmap_write(map, MAX17042_RepSOC, vfSoc);
7338c0984e5SSebastian Reichel }
7348c0984e5SSebastian Reichel
7358c0984e5SSebastian Reichel /*
7368c0984e5SSebastian Reichel * Block write all the override values coming from platform data.
73737ad56aaSBhaskar Chowdhury * This function MUST be called before the POR initialization procedure
7388c0984e5SSebastian Reichel * specified by maxim.
7398c0984e5SSebastian Reichel */
max17042_override_por_values(struct max17042_chip * chip)7408c0984e5SSebastian Reichel static inline void max17042_override_por_values(struct max17042_chip *chip)
7418c0984e5SSebastian Reichel {
7428c0984e5SSebastian Reichel struct regmap *map = chip->regmap;
7438c0984e5SSebastian Reichel struct max17042_config_data *config = chip->pdata->config_data;
7448c0984e5SSebastian Reichel
7458c0984e5SSebastian Reichel max17042_override_por(map, MAX17042_TGAIN, config->tgain);
746ed0d0a05SSebastian Krzyszkowiak max17042_override_por(map, MAX17042_TOFF, config->toff);
7478c0984e5SSebastian Reichel max17042_override_por(map, MAX17042_CGAIN, config->cgain);
7488c0984e5SSebastian Reichel max17042_override_por(map, MAX17042_COFF, config->coff);
7498c0984e5SSebastian Reichel
7508c0984e5SSebastian Reichel max17042_override_por(map, MAX17042_VALRT_Th, config->valrt_thresh);
7518c0984e5SSebastian Reichel max17042_override_por(map, MAX17042_TALRT_Th, config->talrt_thresh);
7528c0984e5SSebastian Reichel max17042_override_por(map, MAX17042_SALRT_Th,
7538c0984e5SSebastian Reichel config->soc_alrt_thresh);
7548c0984e5SSebastian Reichel max17042_override_por(map, MAX17042_CONFIG, config->config);
7558c0984e5SSebastian Reichel max17042_override_por(map, MAX17042_SHDNTIMER, config->shdntimer);
7568c0984e5SSebastian Reichel
7578c0984e5SSebastian Reichel max17042_override_por(map, MAX17042_DesignCap, config->design_cap);
7588c0984e5SSebastian Reichel max17042_override_por(map, MAX17042_ICHGTerm, config->ichgt_term);
7598c0984e5SSebastian Reichel
7608c0984e5SSebastian Reichel max17042_override_por(map, MAX17042_AtRate, config->at_rate);
7618c0984e5SSebastian Reichel max17042_override_por(map, MAX17042_LearnCFG, config->learn_cfg);
7628c0984e5SSebastian Reichel max17042_override_por(map, MAX17042_FilterCFG, config->filter_cfg);
7638c0984e5SSebastian Reichel max17042_override_por(map, MAX17042_RelaxCFG, config->relax_cfg);
7648c0984e5SSebastian Reichel max17042_override_por(map, MAX17042_MiscCFG, config->misc_cfg);
7658c0984e5SSebastian Reichel
7668c0984e5SSebastian Reichel max17042_override_por(map, MAX17042_FullCAP, config->fullcap);
7678c0984e5SSebastian Reichel max17042_override_por(map, MAX17042_FullCAPNom, config->fullcapnom);
7688c0984e5SSebastian Reichel max17042_override_por(map, MAX17042_dQacc, config->dqacc);
7698c0984e5SSebastian Reichel max17042_override_por(map, MAX17042_dPacc, config->dpacc);
7708c0984e5SSebastian Reichel
7714bf00434SSebastian Krzyszkowiak max17042_override_por(map, MAX17042_RCOMP0, config->rcomp0);
7724bf00434SSebastian Krzyszkowiak max17042_override_por(map, MAX17042_TempCo, config->tcompc0);
7734bf00434SSebastian Krzyszkowiak
7744bf00434SSebastian Krzyszkowiak if (chip->chip_type == MAXIM_DEVICE_TYPE_MAX17042) {
7754bf00434SSebastian Krzyszkowiak max17042_override_por(map, MAX17042_MaskSOC, config->masksoc);
7764bf00434SSebastian Krzyszkowiak max17042_override_por(map, MAX17042_SOC_empty, config->socempty);
7778c0984e5SSebastian Reichel max17042_override_por(map, MAX17042_V_empty, config->vempty);
7784bf00434SSebastian Krzyszkowiak max17042_override_por(map, MAX17042_EmptyTempCo, config->empty_tempco);
7794bf00434SSebastian Krzyszkowiak max17042_override_por(map, MAX17042_K_empty0, config->kempty0);
7804bf00434SSebastian Krzyszkowiak }
7814bf00434SSebastian Krzyszkowiak
7824bf00434SSebastian Krzyszkowiak if ((chip->chip_type == MAXIM_DEVICE_TYPE_MAX17042) ||
7834bf00434SSebastian Krzyszkowiak (chip->chip_type == MAXIM_DEVICE_TYPE_MAX17047) ||
7844bf00434SSebastian Krzyszkowiak (chip->chip_type == MAXIM_DEVICE_TYPE_MAX17050)) {
785d0c27c92SHenrik Grimler max17042_override_por(map, MAX17042_IAvg_empty, config->iavg_empty);
7868c0984e5SSebastian Reichel max17042_override_por(map, MAX17042_TempNom, config->temp_nom);
7878c0984e5SSebastian Reichel max17042_override_por(map, MAX17042_TempLim, config->temp_lim);
7888c0984e5SSebastian Reichel max17042_override_por(map, MAX17042_FCTC, config->fctc);
7894bf00434SSebastian Krzyszkowiak }
7904bf00434SSebastian Krzyszkowiak
7914bf00434SSebastian Krzyszkowiak if ((chip->chip_type == MAXIM_DEVICE_TYPE_MAX17047) ||
7924bf00434SSebastian Krzyszkowiak (chip->chip_type == MAXIM_DEVICE_TYPE_MAX17050) ||
7934bf00434SSebastian Krzyszkowiak (chip->chip_type == MAXIM_DEVICE_TYPE_MAX17055)) {
7944bf00434SSebastian Krzyszkowiak max17042_override_por(map, MAX17047_V_empty, config->vempty);
7958c0984e5SSebastian Reichel }
7968c0984e5SSebastian Reichel }
7978c0984e5SSebastian Reichel
max17042_init_chip(struct max17042_chip * chip)7988c0984e5SSebastian Reichel static int max17042_init_chip(struct max17042_chip *chip)
7998c0984e5SSebastian Reichel {
8008c0984e5SSebastian Reichel struct regmap *map = chip->regmap;
8018c0984e5SSebastian Reichel int ret;
8028c0984e5SSebastian Reichel
8038c0984e5SSebastian Reichel max17042_override_por_values(chip);
8048c0984e5SSebastian Reichel /* After Power up, the MAX17042 requires 500mS in order
8058c0984e5SSebastian Reichel * to perform signal debouncing and initial SOC reporting
8068c0984e5SSebastian Reichel */
8078c0984e5SSebastian Reichel msleep(500);
8088c0984e5SSebastian Reichel
80937ad56aaSBhaskar Chowdhury /* Initialize configuration */
8108c0984e5SSebastian Reichel max17042_write_config_regs(chip);
8118c0984e5SSebastian Reichel
8128c0984e5SSebastian Reichel /* write cell characterization data */
8138c0984e5SSebastian Reichel ret = max17042_init_model(chip);
8148c0984e5SSebastian Reichel if (ret) {
8158c0984e5SSebastian Reichel dev_err(&chip->client->dev, "%s init failed\n",
8168c0984e5SSebastian Reichel __func__);
8178c0984e5SSebastian Reichel return -EIO;
8188c0984e5SSebastian Reichel }
8198c0984e5SSebastian Reichel
8208c0984e5SSebastian Reichel ret = max17042_verify_model_lock(chip);
8218c0984e5SSebastian Reichel if (ret) {
8228c0984e5SSebastian Reichel dev_err(&chip->client->dev, "%s lock verify failed\n",
8238c0984e5SSebastian Reichel __func__);
8248c0984e5SSebastian Reichel return -EIO;
8258c0984e5SSebastian Reichel }
8268c0984e5SSebastian Reichel /* write custom parameters */
8278c0984e5SSebastian Reichel max17042_write_custom_regs(chip);
8288c0984e5SSebastian Reichel
8298c0984e5SSebastian Reichel /* update capacity params */
8308c0984e5SSebastian Reichel max17042_update_capacity_regs(chip);
8318c0984e5SSebastian Reichel
8328c0984e5SSebastian Reichel /* delay must be atleast 350mS to allow VFSOC
8338c0984e5SSebastian Reichel * to be calculated from the new configuration
8348c0984e5SSebastian Reichel */
8358c0984e5SSebastian Reichel msleep(350);
8368c0984e5SSebastian Reichel
8378c0984e5SSebastian Reichel /* reset vfsoc0 reg */
8388c0984e5SSebastian Reichel max17042_reset_vfsoc0_reg(chip);
8398c0984e5SSebastian Reichel
8408c0984e5SSebastian Reichel /* load new capacity params */
8418c0984e5SSebastian Reichel max17042_load_new_capacity_params(chip);
8428c0984e5SSebastian Reichel
8438c0984e5SSebastian Reichel /* Init complete, Clear the POR bit */
8448c0984e5SSebastian Reichel regmap_update_bits(map, MAX17042_STATUS, STATUS_POR_BIT, 0x0);
8458c0984e5SSebastian Reichel return 0;
8468c0984e5SSebastian Reichel }
8478c0984e5SSebastian Reichel
max17042_set_soc_threshold(struct max17042_chip * chip,u16 off)8488c0984e5SSebastian Reichel static void max17042_set_soc_threshold(struct max17042_chip *chip, u16 off)
8498c0984e5SSebastian Reichel {
8508c0984e5SSebastian Reichel struct regmap *map = chip->regmap;
8518c0984e5SSebastian Reichel u32 soc, soc_tr;
8528c0984e5SSebastian Reichel
85337ad56aaSBhaskar Chowdhury /* program interrupt thresholds such that we should
8548c0984e5SSebastian Reichel * get interrupt for every 'off' perc change in the soc
8558c0984e5SSebastian Reichel */
856*3a3acf83SArtur Weber if (chip->pdata->enable_current_sense)
8578c0984e5SSebastian Reichel regmap_read(map, MAX17042_RepSOC, &soc);
858*3a3acf83SArtur Weber else
859*3a3acf83SArtur Weber regmap_read(map, MAX17042_VFSOC, &soc);
8608c0984e5SSebastian Reichel soc >>= 8;
8618c0984e5SSebastian Reichel soc_tr = (soc + off) << 8;
862e660dbb6SSebastian Krzyszkowiak if (off < soc)
863e660dbb6SSebastian Krzyszkowiak soc_tr |= soc - off;
8648c0984e5SSebastian Reichel regmap_write(map, MAX17042_SALRT_Th, soc_tr);
8658c0984e5SSebastian Reichel }
8668c0984e5SSebastian Reichel
max17042_thread_handler(int id,void * dev)8678c0984e5SSebastian Reichel static irqreturn_t max17042_thread_handler(int id, void *dev)
8688c0984e5SSebastian Reichel {
8698c0984e5SSebastian Reichel struct max17042_chip *chip = dev;
8708c0984e5SSebastian Reichel u32 val;
87154784ffaSKrzysztof Kozlowski int ret;
8728c0984e5SSebastian Reichel
87354784ffaSKrzysztof Kozlowski ret = regmap_read(chip->regmap, MAX17042_STATUS, &val);
87454784ffaSKrzysztof Kozlowski if (ret)
87554784ffaSKrzysztof Kozlowski return IRQ_HANDLED;
87654784ffaSKrzysztof Kozlowski
87722b6907cSKrzysztof Kozlowski if ((val & STATUS_SMN_BIT) || (val & STATUS_SMX_BIT)) {
878eaa2c490SSebastian Krzyszkowiak dev_dbg(&chip->client->dev, "SOC threshold INTR\n");
8798c0984e5SSebastian Reichel max17042_set_soc_threshold(chip, 1);
8808c0984e5SSebastian Reichel }
8818c0984e5SSebastian Reichel
8820cf48167SSebastian Krzyszkowiak /* we implicitly handle all alerts via power_supply_changed */
8830cf48167SSebastian Krzyszkowiak regmap_clear_bits(chip->regmap, MAX17042_STATUS,
8840cf48167SSebastian Krzyszkowiak 0xFFFF & ~(STATUS_POR_BIT | STATUS_BST_BIT));
8850cf48167SSebastian Krzyszkowiak
8868c0984e5SSebastian Reichel power_supply_changed(chip->battery);
8878c0984e5SSebastian Reichel return IRQ_HANDLED;
8888c0984e5SSebastian Reichel }
8898c0984e5SSebastian Reichel
max17042_init_worker(struct work_struct * work)8908c0984e5SSebastian Reichel static void max17042_init_worker(struct work_struct *work)
8918c0984e5SSebastian Reichel {
8928c0984e5SSebastian Reichel struct max17042_chip *chip = container_of(work,
8938c0984e5SSebastian Reichel struct max17042_chip, work);
8948c0984e5SSebastian Reichel int ret;
8958c0984e5SSebastian Reichel
8968c0984e5SSebastian Reichel /* Initialize registers according to values from the platform data */
8978c0984e5SSebastian Reichel if (chip->pdata->enable_por_init && chip->pdata->config_data) {
8988c0984e5SSebastian Reichel ret = max17042_init_chip(chip);
8998c0984e5SSebastian Reichel if (ret)
9008c0984e5SSebastian Reichel return;
9018c0984e5SSebastian Reichel }
9028c0984e5SSebastian Reichel
9038c0984e5SSebastian Reichel chip->init_complete = 1;
9048c0984e5SSebastian Reichel }
9058c0984e5SSebastian Reichel
9068c0984e5SSebastian Reichel #ifdef CONFIG_OF
9078c0984e5SSebastian Reichel static struct max17042_platform_data *
max17042_get_of_pdata(struct max17042_chip * chip)9082d7e6a83SHans de Goede max17042_get_of_pdata(struct max17042_chip *chip)
9098c0984e5SSebastian Reichel {
91091736213SHans de Goede struct device *dev = &chip->client->dev;
9118c0984e5SSebastian Reichel struct device_node *np = dev->of_node;
9128c0984e5SSebastian Reichel u32 prop;
9138c0984e5SSebastian Reichel struct max17042_platform_data *pdata;
9148c0984e5SSebastian Reichel
9158c0984e5SSebastian Reichel pdata = devm_kzalloc(dev, sizeof(*pdata), GFP_KERNEL);
9168c0984e5SSebastian Reichel if (!pdata)
9178c0984e5SSebastian Reichel return NULL;
9188c0984e5SSebastian Reichel
9198c0984e5SSebastian Reichel /*
9208c0984e5SSebastian Reichel * Require current sense resistor value to be specified for
9218c0984e5SSebastian Reichel * current-sense functionality to be enabled at all.
9228c0984e5SSebastian Reichel */
9238c0984e5SSebastian Reichel if (of_property_read_u32(np, "maxim,rsns-microohm", &prop) == 0) {
9248c0984e5SSebastian Reichel pdata->r_sns = prop;
9258c0984e5SSebastian Reichel pdata->enable_current_sense = true;
9268c0984e5SSebastian Reichel }
9278c0984e5SSebastian Reichel
9288c0984e5SSebastian Reichel if (of_property_read_s32(np, "maxim,cold-temp", &pdata->temp_min))
9298c0984e5SSebastian Reichel pdata->temp_min = INT_MIN;
9308c0984e5SSebastian Reichel if (of_property_read_s32(np, "maxim,over-heat-temp", &pdata->temp_max))
9318c0984e5SSebastian Reichel pdata->temp_max = INT_MAX;
9328c0984e5SSebastian Reichel if (of_property_read_s32(np, "maxim,dead-volt", &pdata->vmin))
9338c0984e5SSebastian Reichel pdata->vmin = INT_MIN;
9348c0984e5SSebastian Reichel if (of_property_read_s32(np, "maxim,over-volt", &pdata->vmax))
9358c0984e5SSebastian Reichel pdata->vmax = INT_MAX;
9368c0984e5SSebastian Reichel
9378c0984e5SSebastian Reichel return pdata;
9388c0984e5SSebastian Reichel }
9392d7e6a83SHans de Goede #endif
9402d7e6a83SHans de Goede
94191736213SHans de Goede static struct max17042_reg_data max17047_default_pdata_init_regs[] = {
94291736213SHans de Goede /*
94391736213SHans de Goede * Some firmwares do not set FullSOCThr, Enable End-of-Charge Detection
94491736213SHans de Goede * when the voltage FG reports 95%, as recommended in the datasheet.
94591736213SHans de Goede */
94691736213SHans de Goede { MAX17047_FullSOCThr, MAX17042_BATTERY_FULL << 8 },
94791736213SHans de Goede };
94891736213SHans de Goede
9498c0984e5SSebastian Reichel static struct max17042_platform_data *
max17042_get_default_pdata(struct max17042_chip * chip)9502d7e6a83SHans de Goede max17042_get_default_pdata(struct max17042_chip *chip)
9518c0984e5SSebastian Reichel {
95291736213SHans de Goede struct device *dev = &chip->client->dev;
95391736213SHans de Goede struct max17042_platform_data *pdata;
95491736213SHans de Goede int ret, misc_cfg;
95591736213SHans de Goede
95691736213SHans de Goede /*
95791736213SHans de Goede * The MAX17047 gets used on x86 where we might not have pdata, assume
95891736213SHans de Goede * the firmware will already have initialized the fuel-gauge and provide
95991736213SHans de Goede * default values for the non init bits to make things work.
96091736213SHans de Goede */
96191736213SHans de Goede pdata = devm_kzalloc(dev, sizeof(*pdata), GFP_KERNEL);
96291736213SHans de Goede if (!pdata)
96391736213SHans de Goede return pdata;
96491736213SHans de Goede
965bc90705bSAngus Ainslie (Purism) if ((chip->chip_type == MAXIM_DEVICE_TYPE_MAX17047) ||
966bc90705bSAngus Ainslie (Purism) (chip->chip_type == MAXIM_DEVICE_TYPE_MAX17050)) {
96791736213SHans de Goede pdata->init_data = max17047_default_pdata_init_regs;
96891736213SHans de Goede pdata->num_init_data =
96991736213SHans de Goede ARRAY_SIZE(max17047_default_pdata_init_regs);
97091736213SHans de Goede }
97191736213SHans de Goede
97291736213SHans de Goede ret = regmap_read(chip->regmap, MAX17042_MiscCFG, &misc_cfg);
97391736213SHans de Goede if (ret < 0)
97491736213SHans de Goede return NULL;
97591736213SHans de Goede
97691736213SHans de Goede /* If bits 0-1 are set to 3 then only Voltage readings are used */
97791736213SHans de Goede if ((misc_cfg & 0x3) == 0x3)
97891736213SHans de Goede pdata->enable_current_sense = false;
97991736213SHans de Goede else
98091736213SHans de Goede pdata->enable_current_sense = true;
98191736213SHans de Goede
98291736213SHans de Goede pdata->vmin = MAX17042_DEFAULT_VMIN;
98391736213SHans de Goede pdata->vmax = MAX17042_DEFAULT_VMAX;
98491736213SHans de Goede pdata->temp_min = MAX17042_DEFAULT_TEMP_MIN;
98591736213SHans de Goede pdata->temp_max = MAX17042_DEFAULT_TEMP_MAX;
98691736213SHans de Goede
98791736213SHans de Goede return pdata;
9888c0984e5SSebastian Reichel }
9892d7e6a83SHans de Goede
9902d7e6a83SHans de Goede static struct max17042_platform_data *
max17042_get_pdata(struct max17042_chip * chip)9912d7e6a83SHans de Goede max17042_get_pdata(struct max17042_chip *chip)
9922d7e6a83SHans de Goede {
9932d7e6a83SHans de Goede struct device *dev = &chip->client->dev;
9942d7e6a83SHans de Goede
9952d7e6a83SHans de Goede #ifdef CONFIG_OF
9962d7e6a83SHans de Goede if (dev->of_node)
9972d7e6a83SHans de Goede return max17042_get_of_pdata(chip);
9988c0984e5SSebastian Reichel #endif
9992d7e6a83SHans de Goede if (dev->platform_data)
10002d7e6a83SHans de Goede return dev->platform_data;
10012d7e6a83SHans de Goede
10022d7e6a83SHans de Goede return max17042_get_default_pdata(chip);
10032d7e6a83SHans de Goede }
10048c0984e5SSebastian Reichel
10058c0984e5SSebastian Reichel static const struct regmap_config max17042_regmap_config = {
10068c0984e5SSebastian Reichel .reg_bits = 8,
10078c0984e5SSebastian Reichel .val_bits = 16,
10088c0984e5SSebastian Reichel .val_format_endian = REGMAP_ENDIAN_NATIVE,
10098c0984e5SSebastian Reichel };
10108c0984e5SSebastian Reichel
10118c0984e5SSebastian Reichel static const struct power_supply_desc max17042_psy_desc = {
10128c0984e5SSebastian Reichel .name = "max170xx_battery",
10138c0984e5SSebastian Reichel .type = POWER_SUPPLY_TYPE_BATTERY,
10148c0984e5SSebastian Reichel .get_property = max17042_get_property,
10158c0984e5SSebastian Reichel .set_property = max17042_set_property,
10168c0984e5SSebastian Reichel .property_is_writeable = max17042_property_is_writeable,
10171269774aSHans de Goede .external_power_changed = power_supply_changed,
10188c0984e5SSebastian Reichel .properties = max17042_battery_props,
10198c0984e5SSebastian Reichel .num_properties = ARRAY_SIZE(max17042_battery_props),
10208c0984e5SSebastian Reichel };
10218c0984e5SSebastian Reichel
10228c0984e5SSebastian Reichel static const struct power_supply_desc max17042_no_current_sense_psy_desc = {
10238c0984e5SSebastian Reichel .name = "max170xx_battery",
10248c0984e5SSebastian Reichel .type = POWER_SUPPLY_TYPE_BATTERY,
10258c0984e5SSebastian Reichel .get_property = max17042_get_property,
10268c0984e5SSebastian Reichel .set_property = max17042_set_property,
10278c0984e5SSebastian Reichel .property_is_writeable = max17042_property_is_writeable,
10288c0984e5SSebastian Reichel .properties = max17042_battery_props,
10298c0984e5SSebastian Reichel .num_properties = ARRAY_SIZE(max17042_battery_props) - 2,
10308c0984e5SSebastian Reichel };
10318c0984e5SSebastian Reichel
max17042_probe(struct i2c_client * client)1032d9ac265bSUwe Kleine-König static int max17042_probe(struct i2c_client *client)
10338c0984e5SSebastian Reichel {
1034d9ac265bSUwe Kleine-König const struct i2c_device_id *id = i2c_client_get_device_id(client);
1035dee2f3cfSWolfram Sang struct i2c_adapter *adapter = client->adapter;
10368c0984e5SSebastian Reichel const struct power_supply_desc *max17042_desc = &max17042_psy_desc;
10378c0984e5SSebastian Reichel struct power_supply_config psy_cfg = {};
10384f1e0cb7SHans de Goede const struct acpi_device_id *acpi_id = NULL;
1039e2116202SHans de Goede struct device *dev = &client->dev;
10408c0984e5SSebastian Reichel struct max17042_chip *chip;
10418c0984e5SSebastian Reichel int ret;
10428c0984e5SSebastian Reichel int i;
10438c0984e5SSebastian Reichel u32 val;
10448c0984e5SSebastian Reichel
10458c0984e5SSebastian Reichel if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_WORD_DATA))
10468c0984e5SSebastian Reichel return -EIO;
10478c0984e5SSebastian Reichel
10488c0984e5SSebastian Reichel chip = devm_kzalloc(&client->dev, sizeof(*chip), GFP_KERNEL);
10498c0984e5SSebastian Reichel if (!chip)
10508c0984e5SSebastian Reichel return -ENOMEM;
10518c0984e5SSebastian Reichel
10528c0984e5SSebastian Reichel chip->client = client;
1053e2116202SHans de Goede if (id) {
105491736213SHans de Goede chip->chip_type = id->driver_data;
1055e2116202SHans de Goede } else {
1056e2116202SHans de Goede acpi_id = acpi_match_device(dev->driver->acpi_match_table, dev);
1057e2116202SHans de Goede if (!acpi_id)
1058e2116202SHans de Goede return -ENODEV;
1059e2116202SHans de Goede
1060e2116202SHans de Goede chip->chip_type = acpi_id->driver_data;
1061e2116202SHans de Goede }
10628c0984e5SSebastian Reichel chip->regmap = devm_regmap_init_i2c(client, &max17042_regmap_config);
10638c0984e5SSebastian Reichel if (IS_ERR(chip->regmap)) {
10648c0984e5SSebastian Reichel dev_err(&client->dev, "Failed to initialize regmap\n");
10658c0984e5SSebastian Reichel return -EINVAL;
10668c0984e5SSebastian Reichel }
10678c0984e5SSebastian Reichel
106891736213SHans de Goede chip->pdata = max17042_get_pdata(chip);
10698c0984e5SSebastian Reichel if (!chip->pdata) {
10708c0984e5SSebastian Reichel dev_err(&client->dev, "no platform data provided\n");
10718c0984e5SSebastian Reichel return -EINVAL;
10728c0984e5SSebastian Reichel }
10738c0984e5SSebastian Reichel
10748c0984e5SSebastian Reichel i2c_set_clientdata(client, chip);
10758c0984e5SSebastian Reichel psy_cfg.drv_data = chip;
107666ec32fcSPierre Bourdon psy_cfg.of_node = dev->of_node;
10778c0984e5SSebastian Reichel
10788c0984e5SSebastian Reichel /* When current is not measured,
10798c0984e5SSebastian Reichel * CURRENT_NOW and CURRENT_AVG properties should be invisible. */
10808c0984e5SSebastian Reichel if (!chip->pdata->enable_current_sense)
10818c0984e5SSebastian Reichel max17042_desc = &max17042_no_current_sense_psy_desc;
10828c0984e5SSebastian Reichel
10838c0984e5SSebastian Reichel if (chip->pdata->r_sns == 0)
10848c0984e5SSebastian Reichel chip->pdata->r_sns = MAX17042_DEFAULT_SNS_RESISTOR;
10858c0984e5SSebastian Reichel
10868c0984e5SSebastian Reichel if (chip->pdata->init_data)
10878c0984e5SSebastian Reichel for (i = 0; i < chip->pdata->num_init_data; i++)
10888c0984e5SSebastian Reichel regmap_write(chip->regmap,
10898c0984e5SSebastian Reichel chip->pdata->init_data[i].addr,
10908c0984e5SSebastian Reichel chip->pdata->init_data[i].data);
10918c0984e5SSebastian Reichel
10928c0984e5SSebastian Reichel if (!chip->pdata->enable_current_sense) {
10938c0984e5SSebastian Reichel regmap_write(chip->regmap, MAX17042_CGAIN, 0x0000);
10948c0984e5SSebastian Reichel regmap_write(chip->regmap, MAX17042_MiscCFG, 0x0003);
10958c0984e5SSebastian Reichel regmap_write(chip->regmap, MAX17042_LearnCFG, 0x0007);
10968c0984e5SSebastian Reichel }
10978c0984e5SSebastian Reichel
10988c0984e5SSebastian Reichel chip->battery = devm_power_supply_register(&client->dev, max17042_desc,
10998c0984e5SSebastian Reichel &psy_cfg);
11008c0984e5SSebastian Reichel if (IS_ERR(chip->battery)) {
11018c0984e5SSebastian Reichel dev_err(&client->dev, "failed: power supply register\n");
11028c0984e5SSebastian Reichel return PTR_ERR(chip->battery);
11038c0984e5SSebastian Reichel }
11048c0984e5SSebastian Reichel
11058c0984e5SSebastian Reichel if (client->irq) {
11067fbf6b73SKrzysztof Kozlowski unsigned int flags = IRQF_ONESHOT;
1107a865a155SHans de Goede
1108a865a155SHans de Goede /*
1109a865a155SHans de Goede * On ACPI systems the IRQ may be handled by ACPI-event code,
1110a865a155SHans de Goede * so we need to share (if the ACPI code is willing to share).
1111a865a155SHans de Goede */
1112a865a155SHans de Goede if (acpi_id)
1113a865a155SHans de Goede flags |= IRQF_SHARED | IRQF_PROBE_SHARED;
1114a865a155SHans de Goede
11158c0984e5SSebastian Reichel ret = devm_request_threaded_irq(&client->dev, client->irq,
11168c0984e5SSebastian Reichel NULL,
1117a865a155SHans de Goede max17042_thread_handler, flags,
11188c0984e5SSebastian Reichel chip->battery->desc->name,
11198c0984e5SSebastian Reichel chip);
11208c0984e5SSebastian Reichel if (!ret) {
11218c0984e5SSebastian Reichel regmap_update_bits(chip->regmap, MAX17042_CONFIG,
1122c06a65acSPrzemyslaw Chwiala CFG_ALRT_BIT_ENBL,
1123c06a65acSPrzemyslaw Chwiala CFG_ALRT_BIT_ENBL);
11248c0984e5SSebastian Reichel max17042_set_soc_threshold(chip, 1);
11258c0984e5SSebastian Reichel } else {
11268c0984e5SSebastian Reichel client->irq = 0;
1127a865a155SHans de Goede if (ret != -EBUSY)
1128a865a155SHans de Goede dev_err(&client->dev, "Failed to get IRQ\n");
11298c0984e5SSebastian Reichel }
11308c0984e5SSebastian Reichel }
1131a865a155SHans de Goede /* Not able to update the charge threshold when exceeded? -> disable */
1132a865a155SHans de Goede if (!client->irq)
1133a865a155SHans de Goede regmap_write(chip->regmap, MAX17042_SALRT_Th, 0xff00);
11348c0984e5SSebastian Reichel
11358c0984e5SSebastian Reichel regmap_read(chip->regmap, MAX17042_STATUS, &val);
11368c0984e5SSebastian Reichel if (val & STATUS_POR_BIT) {
1137e5372503SChristophe JAILLET ret = devm_work_autocancel(&client->dev, &chip->work,
1138e5372503SChristophe JAILLET max17042_init_worker);
1139bf592c56SSven Van Asbroeck if (ret)
1140bf592c56SSven Van Asbroeck return ret;
11418c0984e5SSebastian Reichel schedule_work(&chip->work);
11428c0984e5SSebastian Reichel } else {
11438c0984e5SSebastian Reichel chip->init_complete = 1;
11448c0984e5SSebastian Reichel }
11458c0984e5SSebastian Reichel
11468c0984e5SSebastian Reichel return 0;
11478c0984e5SSebastian Reichel }
11488c0984e5SSebastian Reichel
11498c0984e5SSebastian Reichel #ifdef CONFIG_PM_SLEEP
max17042_suspend(struct device * dev)11508c0984e5SSebastian Reichel static int max17042_suspend(struct device *dev)
11518c0984e5SSebastian Reichel {
11528c0984e5SSebastian Reichel struct max17042_chip *chip = dev_get_drvdata(dev);
11538c0984e5SSebastian Reichel
11548c0984e5SSebastian Reichel /*
11558c0984e5SSebastian Reichel * disable the irq and enable irq_wake
11568c0984e5SSebastian Reichel * capability to the interrupt line.
11578c0984e5SSebastian Reichel */
11588c0984e5SSebastian Reichel if (chip->client->irq) {
11598c0984e5SSebastian Reichel disable_irq(chip->client->irq);
11608c0984e5SSebastian Reichel enable_irq_wake(chip->client->irq);
11618c0984e5SSebastian Reichel }
11628c0984e5SSebastian Reichel
11638c0984e5SSebastian Reichel return 0;
11648c0984e5SSebastian Reichel }
11658c0984e5SSebastian Reichel
max17042_resume(struct device * dev)11668c0984e5SSebastian Reichel static int max17042_resume(struct device *dev)
11678c0984e5SSebastian Reichel {
11688c0984e5SSebastian Reichel struct max17042_chip *chip = dev_get_drvdata(dev);
11698c0984e5SSebastian Reichel
11708c0984e5SSebastian Reichel if (chip->client->irq) {
11718c0984e5SSebastian Reichel disable_irq_wake(chip->client->irq);
11728c0984e5SSebastian Reichel enable_irq(chip->client->irq);
11738c0984e5SSebastian Reichel /* re-program the SOC thresholds to 1% change */
11748c0984e5SSebastian Reichel max17042_set_soc_threshold(chip, 1);
11758c0984e5SSebastian Reichel }
11768c0984e5SSebastian Reichel
11778c0984e5SSebastian Reichel return 0;
11788c0984e5SSebastian Reichel }
11798c0984e5SSebastian Reichel #endif
11808c0984e5SSebastian Reichel
11818c0984e5SSebastian Reichel static SIMPLE_DEV_PM_OPS(max17042_pm_ops, max17042_suspend,
11828c0984e5SSebastian Reichel max17042_resume);
11838c0984e5SSebastian Reichel
1184e2116202SHans de Goede #ifdef CONFIG_ACPI
1185e2116202SHans de Goede static const struct acpi_device_id max17042_acpi_match[] = {
1186e2116202SHans de Goede { "MAX17047", MAXIM_DEVICE_TYPE_MAX17047 },
1187e2116202SHans de Goede { }
1188e2116202SHans de Goede };
1189e2116202SHans de Goede MODULE_DEVICE_TABLE(acpi, max17042_acpi_match);
1190e2116202SHans de Goede #endif
1191e2116202SHans de Goede
11928c0984e5SSebastian Reichel #ifdef CONFIG_OF
11938c0984e5SSebastian Reichel static const struct of_device_id max17042_dt_match[] = {
11948c0984e5SSebastian Reichel { .compatible = "maxim,max17042" },
11958c0984e5SSebastian Reichel { .compatible = "maxim,max17047" },
11968c0984e5SSebastian Reichel { .compatible = "maxim,max17050" },
1197bc90705bSAngus Ainslie (Purism) { .compatible = "maxim,max17055" },
11984415e4ceSNikita Travkin { .compatible = "maxim,max77849-battery" },
11998c0984e5SSebastian Reichel { },
12008c0984e5SSebastian Reichel };
12018c0984e5SSebastian Reichel MODULE_DEVICE_TABLE(of, max17042_dt_match);
12028c0984e5SSebastian Reichel #endif
12038c0984e5SSebastian Reichel
12048c0984e5SSebastian Reichel static const struct i2c_device_id max17042_id[] = {
12058c0984e5SSebastian Reichel { "max17042", MAXIM_DEVICE_TYPE_MAX17042 },
12068c0984e5SSebastian Reichel { "max17047", MAXIM_DEVICE_TYPE_MAX17047 },
12078c0984e5SSebastian Reichel { "max17050", MAXIM_DEVICE_TYPE_MAX17050 },
1208bc90705bSAngus Ainslie (Purism) { "max17055", MAXIM_DEVICE_TYPE_MAX17055 },
12094415e4ceSNikita Travkin { "max77849-battery", MAXIM_DEVICE_TYPE_MAX17047 },
12108c0984e5SSebastian Reichel { }
12118c0984e5SSebastian Reichel };
12128c0984e5SSebastian Reichel MODULE_DEVICE_TABLE(i2c, max17042_id);
12138c0984e5SSebastian Reichel
12148c0984e5SSebastian Reichel static struct i2c_driver max17042_i2c_driver = {
12158c0984e5SSebastian Reichel .driver = {
12168c0984e5SSebastian Reichel .name = "max17042",
1217e2116202SHans de Goede .acpi_match_table = ACPI_PTR(max17042_acpi_match),
12188c0984e5SSebastian Reichel .of_match_table = of_match_ptr(max17042_dt_match),
12198c0984e5SSebastian Reichel .pm = &max17042_pm_ops,
12208c0984e5SSebastian Reichel },
1221fe20b1dcSUwe Kleine-König .probe = max17042_probe,
12228c0984e5SSebastian Reichel .id_table = max17042_id,
12238c0984e5SSebastian Reichel };
12248c0984e5SSebastian Reichel module_i2c_driver(max17042_i2c_driver);
12258c0984e5SSebastian Reichel
12268c0984e5SSebastian Reichel MODULE_AUTHOR("MyungJoo Ham <myungjoo.ham@samsung.com>");
12278c0984e5SSebastian Reichel MODULE_DESCRIPTION("MAX17042 Fuel Gauge");
12288c0984e5SSebastian Reichel MODULE_LICENSE("GPL");
1229