110e48b7dSAlex A. Mihaylov /*
210e48b7dSAlex A. Mihaylov  * 1-Wire implementation for Maxim Semiconductor
3bd3689a6SXiaofeng Cao  * MAX7211/MAX17215 standalone fuel gauge chip
410e48b7dSAlex A. Mihaylov  *
510e48b7dSAlex A. Mihaylov  * Copyright (C) 2017 Radioavionica Corporation
610e48b7dSAlex A. Mihaylov  * Author: Alex A. Mihaylov <minimumlaw@rambler.ru>
710e48b7dSAlex A. Mihaylov  *
810e48b7dSAlex A. Mihaylov  * Use consistent with the GNU GPL is permitted,
910e48b7dSAlex A. Mihaylov  * provided that this copyright notice is
1010e48b7dSAlex A. Mihaylov  * preserved in its entirety in all copies and derived works.
1110e48b7dSAlex A. Mihaylov  *
1210e48b7dSAlex A. Mihaylov  */
1310e48b7dSAlex A. Mihaylov 
1410e48b7dSAlex A. Mihaylov #include <linux/module.h>
1510e48b7dSAlex A. Mihaylov #include <linux/slab.h>
1610e48b7dSAlex A. Mihaylov #include <linux/w1.h>
1710e48b7dSAlex A. Mihaylov #include <linux/regmap.h>
1810e48b7dSAlex A. Mihaylov #include <linux/power_supply.h>
1910e48b7dSAlex A. Mihaylov 
2010e48b7dSAlex A. Mihaylov #define W1_MAX1721X_FAMILY_ID		0x26
2110e48b7dSAlex A. Mihaylov #define DEF_DEV_NAME_MAX17211		"MAX17211"
2210e48b7dSAlex A. Mihaylov #define DEF_DEV_NAME_MAX17215		"MAX17215"
2310e48b7dSAlex A. Mihaylov #define DEF_DEV_NAME_UNKNOWN		"UNKNOWN"
2410e48b7dSAlex A. Mihaylov #define DEF_MFG_NAME			"MAXIM"
2510e48b7dSAlex A. Mihaylov 
2610e48b7dSAlex A. Mihaylov #define PSY_MAX_NAME_LEN	32
2710e48b7dSAlex A. Mihaylov 
2810e48b7dSAlex A. Mihaylov /* Number of valid register addresses in W1 mode */
2910e48b7dSAlex A. Mihaylov #define MAX1721X_MAX_REG_NR	0x1EF
3010e48b7dSAlex A. Mihaylov 
31bd3689a6SXiaofeng Cao /* Factory settings (nonvolatile registers) (W1 specific) */
3210e48b7dSAlex A. Mihaylov #define MAX1721X_REG_NRSENSE	0x1CF	/* RSense in 10^-5 Ohm */
3310e48b7dSAlex A. Mihaylov /* Strings */
3410e48b7dSAlex A. Mihaylov #define MAX1721X_REG_MFG_STR	0x1CC
3510e48b7dSAlex A. Mihaylov #define MAX1721X_REG_MFG_NUMB	3
3610e48b7dSAlex A. Mihaylov #define MAX1721X_REG_DEV_STR	0x1DB
3710e48b7dSAlex A. Mihaylov #define MAX1721X_REG_DEV_NUMB	5
3810e48b7dSAlex A. Mihaylov /* HEX Strings */
3910e48b7dSAlex A. Mihaylov #define MAX1721X_REG_SER_HEX	0x1D8
4010e48b7dSAlex A. Mihaylov 
4110e48b7dSAlex A. Mihaylov /* MAX172XX Output Registers for W1 chips */
4210e48b7dSAlex A. Mihaylov #define MAX172XX_REG_STATUS	0x000	/* status reg */
4310e48b7dSAlex A. Mihaylov #define MAX172XX_BAT_PRESENT	(1<<4)	/* battery connected bit */
4410e48b7dSAlex A. Mihaylov #define MAX172XX_REG_DEVNAME	0x021	/* chip config */
4510e48b7dSAlex A. Mihaylov #define MAX172XX_DEV_MASK	0x000F	/* chip type mask */
4610e48b7dSAlex A. Mihaylov #define MAX172X1_DEV		0x0001
4710e48b7dSAlex A. Mihaylov #define MAX172X5_DEV		0x0005
4810e48b7dSAlex A. Mihaylov #define MAX172XX_REG_TEMP	0x008	/* Temperature */
4910e48b7dSAlex A. Mihaylov #define MAX172XX_REG_BATT	0x0DA	/* Battery voltage */
5010e48b7dSAlex A. Mihaylov #define MAX172XX_REG_CURRENT	0x00A	/* Actual current */
5110e48b7dSAlex A. Mihaylov #define MAX172XX_REG_AVGCURRENT	0x00B	/* Average current */
5210e48b7dSAlex A. Mihaylov #define MAX172XX_REG_REPSOC	0x006	/* Percentage of charge */
5310e48b7dSAlex A. Mihaylov #define MAX172XX_REG_DESIGNCAP	0x018	/* Design capacity */
5410e48b7dSAlex A. Mihaylov #define MAX172XX_REG_REPCAP	0x005	/* Average capacity */
5510e48b7dSAlex A. Mihaylov #define MAX172XX_REG_TTE	0x011	/* Time to empty */
5610e48b7dSAlex A. Mihaylov #define MAX172XX_REG_TTF	0x020	/* Time to full */
5710e48b7dSAlex A. Mihaylov 
5810e48b7dSAlex A. Mihaylov struct max17211_device_info {
5910e48b7dSAlex A. Mihaylov 	char name[PSY_MAX_NAME_LEN];
6010e48b7dSAlex A. Mihaylov 	struct power_supply *bat;
6110e48b7dSAlex A. Mihaylov 	struct power_supply_desc bat_desc;
6210e48b7dSAlex A. Mihaylov 	struct device *w1_dev;
6310e48b7dSAlex A. Mihaylov 	struct regmap *regmap;
6410e48b7dSAlex A. Mihaylov 	/* battery design format */
6510e48b7dSAlex A. Mihaylov 	unsigned int rsense; /* in tenths uOhm */
6610e48b7dSAlex A. Mihaylov 	char DeviceName[2 * MAX1721X_REG_DEV_NUMB + 1];
6710e48b7dSAlex A. Mihaylov 	char ManufacturerName[2 * MAX1721X_REG_MFG_NUMB + 1];
6810e48b7dSAlex A. Mihaylov 	char SerialNumber[13]; /* see get_sn_str() later for comment */
6910e48b7dSAlex A. Mihaylov };
7010e48b7dSAlex A. Mihaylov 
7110e48b7dSAlex A. Mihaylov /* Convert regs value to power_supply units */
7210e48b7dSAlex A. Mihaylov 
max172xx_time_to_ps(unsigned int reg)7310e48b7dSAlex A. Mihaylov static inline int max172xx_time_to_ps(unsigned int reg)
7410e48b7dSAlex A. Mihaylov {
7510e48b7dSAlex A. Mihaylov 	return reg * 5625 / 1000;	/* in sec. */
7610e48b7dSAlex A. Mihaylov }
7710e48b7dSAlex A. Mihaylov 
max172xx_percent_to_ps(unsigned int reg)7810e48b7dSAlex A. Mihaylov static inline int max172xx_percent_to_ps(unsigned int reg)
7910e48b7dSAlex A. Mihaylov {
8010e48b7dSAlex A. Mihaylov 	return reg / 256;	/* in percent from 0 to 100 */
8110e48b7dSAlex A. Mihaylov }
8210e48b7dSAlex A. Mihaylov 
max172xx_voltage_to_ps(unsigned int reg)8310e48b7dSAlex A. Mihaylov static inline int max172xx_voltage_to_ps(unsigned int reg)
8410e48b7dSAlex A. Mihaylov {
8510e48b7dSAlex A. Mihaylov 	return reg * 1250;	/* in uV */
8610e48b7dSAlex A. Mihaylov }
8710e48b7dSAlex A. Mihaylov 
max172xx_capacity_to_ps(unsigned int reg)8810e48b7dSAlex A. Mihaylov static inline int max172xx_capacity_to_ps(unsigned int reg)
8910e48b7dSAlex A. Mihaylov {
9010e48b7dSAlex A. Mihaylov 	return reg * 500;	/* in uAh */
9110e48b7dSAlex A. Mihaylov }
9210e48b7dSAlex A. Mihaylov 
9310e48b7dSAlex A. Mihaylov /*
9410e48b7dSAlex A. Mihaylov  * Current and temperature is signed values, so unsigned regs
9510e48b7dSAlex A. Mihaylov  * value must be converted to signed type
9610e48b7dSAlex A. Mihaylov  */
9710e48b7dSAlex A. Mihaylov 
max172xx_temperature_to_ps(unsigned int reg)9810e48b7dSAlex A. Mihaylov static inline int max172xx_temperature_to_ps(unsigned int reg)
9910e48b7dSAlex A. Mihaylov {
10010e48b7dSAlex A. Mihaylov 	int val = (int16_t)(reg);
10110e48b7dSAlex A. Mihaylov 
10210e48b7dSAlex A. Mihaylov 	return val * 10 / 256; /* in tenths of deg. C */
10310e48b7dSAlex A. Mihaylov }
10410e48b7dSAlex A. Mihaylov 
10510e48b7dSAlex A. Mihaylov /*
10610e48b7dSAlex A. Mihaylov  * Calculating current registers resolution:
10710e48b7dSAlex A. Mihaylov  *
108bd3689a6SXiaofeng Cao  * RSense stored in 10^-5 Ohm, so measurement voltage must be
10910e48b7dSAlex A. Mihaylov  * in 10^-11 Volts for get current in uA.
11010e48b7dSAlex A. Mihaylov  * 16 bit current reg fullscale +/-51.2mV is 102400 uV.
11110e48b7dSAlex A. Mihaylov  * So: 102400 / 65535 * 10^5 = 156252
11210e48b7dSAlex A. Mihaylov  */
max172xx_current_to_voltage(unsigned int reg)11310e48b7dSAlex A. Mihaylov static inline int max172xx_current_to_voltage(unsigned int reg)
11410e48b7dSAlex A. Mihaylov {
11510e48b7dSAlex A. Mihaylov 	int val = (int16_t)(reg);
11610e48b7dSAlex A. Mihaylov 
11710e48b7dSAlex A. Mihaylov 	return val * 156252;
11810e48b7dSAlex A. Mihaylov }
11910e48b7dSAlex A. Mihaylov 
12010e48b7dSAlex A. Mihaylov 
12110e48b7dSAlex A. Mihaylov static inline struct max17211_device_info *
to_device_info(struct power_supply * psy)12210e48b7dSAlex A. Mihaylov to_device_info(struct power_supply *psy)
12310e48b7dSAlex A. Mihaylov {
12410e48b7dSAlex A. Mihaylov 	return power_supply_get_drvdata(psy);
12510e48b7dSAlex A. Mihaylov }
12610e48b7dSAlex A. Mihaylov 
max1721x_battery_get_property(struct power_supply * psy,enum power_supply_property psp,union power_supply_propval * val)12710e48b7dSAlex A. Mihaylov static int max1721x_battery_get_property(struct power_supply *psy,
12810e48b7dSAlex A. Mihaylov 	enum power_supply_property psp,
12910e48b7dSAlex A. Mihaylov 	union power_supply_propval *val)
13010e48b7dSAlex A. Mihaylov {
13110e48b7dSAlex A. Mihaylov 	struct max17211_device_info *info = to_device_info(psy);
13210e48b7dSAlex A. Mihaylov 	unsigned int reg = 0;
13310e48b7dSAlex A. Mihaylov 	int ret = 0;
13410e48b7dSAlex A. Mihaylov 
13510e48b7dSAlex A. Mihaylov 	switch (psp) {
13610e48b7dSAlex A. Mihaylov 	case POWER_SUPPLY_PROP_PRESENT:
13710e48b7dSAlex A. Mihaylov 		/*
13810e48b7dSAlex A. Mihaylov 		 * POWER_SUPPLY_PROP_PRESENT will always readable via
13910e48b7dSAlex A. Mihaylov 		 * sysfs interface. Value return 0 if battery not
140bd3689a6SXiaofeng Cao 		 * present or unaccessible via W1.
14110e48b7dSAlex A. Mihaylov 		 */
14210e48b7dSAlex A. Mihaylov 		val->intval =
14310e48b7dSAlex A. Mihaylov 			regmap_read(info->regmap, MAX172XX_REG_STATUS,
14410e48b7dSAlex A. Mihaylov 			&reg) ? 0 : !(reg & MAX172XX_BAT_PRESENT);
14510e48b7dSAlex A. Mihaylov 		break;
14610e48b7dSAlex A. Mihaylov 	case POWER_SUPPLY_PROP_CAPACITY:
14710e48b7dSAlex A. Mihaylov 		ret = regmap_read(info->regmap, MAX172XX_REG_REPSOC, &reg);
14810e48b7dSAlex A. Mihaylov 		val->intval = max172xx_percent_to_ps(reg);
14910e48b7dSAlex A. Mihaylov 		break;
15010e48b7dSAlex A. Mihaylov 	case POWER_SUPPLY_PROP_VOLTAGE_NOW:
15110e48b7dSAlex A. Mihaylov 		ret = regmap_read(info->regmap, MAX172XX_REG_BATT, &reg);
15210e48b7dSAlex A. Mihaylov 		val->intval = max172xx_voltage_to_ps(reg);
15310e48b7dSAlex A. Mihaylov 		break;
15410e48b7dSAlex A. Mihaylov 	case POWER_SUPPLY_PROP_CHARGE_FULL_DESIGN:
15510e48b7dSAlex A. Mihaylov 		ret = regmap_read(info->regmap, MAX172XX_REG_DESIGNCAP, &reg);
15610e48b7dSAlex A. Mihaylov 		val->intval = max172xx_capacity_to_ps(reg);
15710e48b7dSAlex A. Mihaylov 		break;
15810e48b7dSAlex A. Mihaylov 	case POWER_SUPPLY_PROP_CHARGE_AVG:
15910e48b7dSAlex A. Mihaylov 		ret = regmap_read(info->regmap, MAX172XX_REG_REPCAP, &reg);
16010e48b7dSAlex A. Mihaylov 		val->intval = max172xx_capacity_to_ps(reg);
16110e48b7dSAlex A. Mihaylov 		break;
16210e48b7dSAlex A. Mihaylov 	case POWER_SUPPLY_PROP_TIME_TO_EMPTY_AVG:
16310e48b7dSAlex A. Mihaylov 		ret = regmap_read(info->regmap, MAX172XX_REG_TTE, &reg);
16410e48b7dSAlex A. Mihaylov 		val->intval = max172xx_time_to_ps(reg);
16510e48b7dSAlex A. Mihaylov 		break;
16610e48b7dSAlex A. Mihaylov 	case POWER_SUPPLY_PROP_TIME_TO_FULL_AVG:
16710e48b7dSAlex A. Mihaylov 		ret = regmap_read(info->regmap, MAX172XX_REG_TTF, &reg);
16810e48b7dSAlex A. Mihaylov 		val->intval = max172xx_time_to_ps(reg);
16910e48b7dSAlex A. Mihaylov 		break;
17010e48b7dSAlex A. Mihaylov 	case POWER_SUPPLY_PROP_TEMP:
17110e48b7dSAlex A. Mihaylov 		ret = regmap_read(info->regmap, MAX172XX_REG_TEMP, &reg);
17210e48b7dSAlex A. Mihaylov 		val->intval = max172xx_temperature_to_ps(reg);
17310e48b7dSAlex A. Mihaylov 		break;
17410e48b7dSAlex A. Mihaylov 	/* We need signed current, so must cast info->rsense to signed type */
17510e48b7dSAlex A. Mihaylov 	case POWER_SUPPLY_PROP_CURRENT_NOW:
17610e48b7dSAlex A. Mihaylov 		ret = regmap_read(info->regmap, MAX172XX_REG_CURRENT, &reg);
17710e48b7dSAlex A. Mihaylov 		val->intval =
17810e48b7dSAlex A. Mihaylov 			max172xx_current_to_voltage(reg) / (int)info->rsense;
17910e48b7dSAlex A. Mihaylov 		break;
18010e48b7dSAlex A. Mihaylov 	case POWER_SUPPLY_PROP_CURRENT_AVG:
18110e48b7dSAlex A. Mihaylov 		ret = regmap_read(info->regmap, MAX172XX_REG_AVGCURRENT, &reg);
18210e48b7dSAlex A. Mihaylov 		val->intval =
18310e48b7dSAlex A. Mihaylov 			max172xx_current_to_voltage(reg) / (int)info->rsense;
18410e48b7dSAlex A. Mihaylov 		break;
18510e48b7dSAlex A. Mihaylov 	/*
18610e48b7dSAlex A. Mihaylov 	 * Strings already received and inited by probe.
18710e48b7dSAlex A. Mihaylov 	 * We do dummy read for check battery still available.
18810e48b7dSAlex A. Mihaylov 	 */
18910e48b7dSAlex A. Mihaylov 	case POWER_SUPPLY_PROP_MODEL_NAME:
19010e48b7dSAlex A. Mihaylov 		ret = regmap_read(info->regmap, MAX1721X_REG_DEV_STR, &reg);
19110e48b7dSAlex A. Mihaylov 		val->strval = info->DeviceName;
19210e48b7dSAlex A. Mihaylov 		break;
19310e48b7dSAlex A. Mihaylov 	case POWER_SUPPLY_PROP_MANUFACTURER:
19410e48b7dSAlex A. Mihaylov 		ret = regmap_read(info->regmap, MAX1721X_REG_MFG_STR, &reg);
19510e48b7dSAlex A. Mihaylov 		val->strval = info->ManufacturerName;
19610e48b7dSAlex A. Mihaylov 		break;
19710e48b7dSAlex A. Mihaylov 	case POWER_SUPPLY_PROP_SERIAL_NUMBER:
19810e48b7dSAlex A. Mihaylov 		ret = regmap_read(info->regmap, MAX1721X_REG_SER_HEX, &reg);
19910e48b7dSAlex A. Mihaylov 		val->strval = info->SerialNumber;
20010e48b7dSAlex A. Mihaylov 		break;
20110e48b7dSAlex A. Mihaylov 	default:
20210e48b7dSAlex A. Mihaylov 		ret = -EINVAL;
20310e48b7dSAlex A. Mihaylov 	}
20410e48b7dSAlex A. Mihaylov 
20510e48b7dSAlex A. Mihaylov 	return ret;
20610e48b7dSAlex A. Mihaylov }
20710e48b7dSAlex A. Mihaylov 
20810e48b7dSAlex A. Mihaylov static enum power_supply_property max1721x_battery_props[] = {
20910e48b7dSAlex A. Mihaylov 	/* int */
21010e48b7dSAlex A. Mihaylov 	POWER_SUPPLY_PROP_PRESENT,
21110e48b7dSAlex A. Mihaylov 	POWER_SUPPLY_PROP_CAPACITY,
21210e48b7dSAlex A. Mihaylov 	POWER_SUPPLY_PROP_VOLTAGE_NOW,
21310e48b7dSAlex A. Mihaylov 	POWER_SUPPLY_PROP_CHARGE_FULL_DESIGN,
21410e48b7dSAlex A. Mihaylov 	POWER_SUPPLY_PROP_CHARGE_AVG,
21510e48b7dSAlex A. Mihaylov 	POWER_SUPPLY_PROP_TIME_TO_EMPTY_AVG,
21610e48b7dSAlex A. Mihaylov 	POWER_SUPPLY_PROP_TIME_TO_FULL_AVG,
21710e48b7dSAlex A. Mihaylov 	POWER_SUPPLY_PROP_TEMP,
21810e48b7dSAlex A. Mihaylov 	POWER_SUPPLY_PROP_CURRENT_NOW,
21910e48b7dSAlex A. Mihaylov 	POWER_SUPPLY_PROP_CURRENT_AVG,
22010e48b7dSAlex A. Mihaylov 	/* strings */
22110e48b7dSAlex A. Mihaylov 	POWER_SUPPLY_PROP_MODEL_NAME,
22210e48b7dSAlex A. Mihaylov 	POWER_SUPPLY_PROP_MANUFACTURER,
22310e48b7dSAlex A. Mihaylov 	POWER_SUPPLY_PROP_SERIAL_NUMBER,
22410e48b7dSAlex A. Mihaylov };
22510e48b7dSAlex A. Mihaylov 
get_string(struct max17211_device_info * info,uint16_t reg,uint8_t nr,char * str)22610e48b7dSAlex A. Mihaylov static int get_string(struct max17211_device_info *info,
22710e48b7dSAlex A. Mihaylov 			uint16_t reg, uint8_t nr, char *str)
22810e48b7dSAlex A. Mihaylov {
22910e48b7dSAlex A. Mihaylov 	unsigned int val;
23010e48b7dSAlex A. Mihaylov 
23110e48b7dSAlex A. Mihaylov 	if (!str || !(reg == MAX1721X_REG_MFG_STR ||
23210e48b7dSAlex A. Mihaylov 			reg == MAX1721X_REG_DEV_STR))
23310e48b7dSAlex A. Mihaylov 		return -EFAULT;
23410e48b7dSAlex A. Mihaylov 
23510e48b7dSAlex A. Mihaylov 	while (nr--) {
23610e48b7dSAlex A. Mihaylov 		if (regmap_read(info->regmap, reg++, &val))
23710e48b7dSAlex A. Mihaylov 			return -EFAULT;
23810e48b7dSAlex A. Mihaylov 		*str++ = val>>8 & 0x00FF;
23910e48b7dSAlex A. Mihaylov 		*str++ = val & 0x00FF;
24010e48b7dSAlex A. Mihaylov 	}
24110e48b7dSAlex A. Mihaylov 	return 0;
24210e48b7dSAlex A. Mihaylov }
24310e48b7dSAlex A. Mihaylov 
24410e48b7dSAlex A. Mihaylov /* Maxim say: Serial number is a hex string up to 12 hex characters */
get_sn_string(struct max17211_device_info * info,char * str)24510e48b7dSAlex A. Mihaylov static int get_sn_string(struct max17211_device_info *info, char *str)
24610e48b7dSAlex A. Mihaylov {
24710e48b7dSAlex A. Mihaylov 	unsigned int val[3];
24810e48b7dSAlex A. Mihaylov 
24910e48b7dSAlex A. Mihaylov 	if (!str)
25010e48b7dSAlex A. Mihaylov 		return -EFAULT;
25110e48b7dSAlex A. Mihaylov 
25210e48b7dSAlex A. Mihaylov 	if (regmap_read(info->regmap, MAX1721X_REG_SER_HEX, &val[0]))
25310e48b7dSAlex A. Mihaylov 		return -EFAULT;
25410e48b7dSAlex A. Mihaylov 	if (regmap_read(info->regmap, MAX1721X_REG_SER_HEX + 1, &val[1]))
25510e48b7dSAlex A. Mihaylov 		return -EFAULT;
25610e48b7dSAlex A. Mihaylov 	if (regmap_read(info->regmap, MAX1721X_REG_SER_HEX + 2, &val[2]))
25710e48b7dSAlex A. Mihaylov 		return -EFAULT;
25810e48b7dSAlex A. Mihaylov 
25910e48b7dSAlex A. Mihaylov 	snprintf(str, 13, "%04X%04X%04X", val[0], val[1], val[2]);
26010e48b7dSAlex A. Mihaylov 	return 0;
26110e48b7dSAlex A. Mihaylov }
26210e48b7dSAlex A. Mihaylov 
26310e48b7dSAlex A. Mihaylov /*
26410e48b7dSAlex A. Mihaylov  * MAX1721x registers description for w1-regmap
26510e48b7dSAlex A. Mihaylov  */
26610e48b7dSAlex A. Mihaylov static const struct regmap_range max1721x_allow_range[] = {
26710e48b7dSAlex A. Mihaylov 	regmap_reg_range(0, 0xDF),	/* volatile data */
26810e48b7dSAlex A. Mihaylov 	regmap_reg_range(0x180, 0x1DF),	/* non-volatile memory */
26910e48b7dSAlex A. Mihaylov 	regmap_reg_range(0x1E0, 0x1EF),	/* non-volatile history (unused) */
27010e48b7dSAlex A. Mihaylov };
27110e48b7dSAlex A. Mihaylov 
27210e48b7dSAlex A. Mihaylov static const struct regmap_range max1721x_deny_range[] = {
27310e48b7dSAlex A. Mihaylov 	/* volatile data unused registers */
27410e48b7dSAlex A. Mihaylov 	regmap_reg_range(0x24, 0x26),
27510e48b7dSAlex A. Mihaylov 	regmap_reg_range(0x30, 0x31),
27610e48b7dSAlex A. Mihaylov 	regmap_reg_range(0x33, 0x34),
27710e48b7dSAlex A. Mihaylov 	regmap_reg_range(0x37, 0x37),
27810e48b7dSAlex A. Mihaylov 	regmap_reg_range(0x3B, 0x3C),
27910e48b7dSAlex A. Mihaylov 	regmap_reg_range(0x40, 0x41),
28010e48b7dSAlex A. Mihaylov 	regmap_reg_range(0x43, 0x44),
28110e48b7dSAlex A. Mihaylov 	regmap_reg_range(0x47, 0x49),
28210e48b7dSAlex A. Mihaylov 	regmap_reg_range(0x4B, 0x4C),
28310e48b7dSAlex A. Mihaylov 	regmap_reg_range(0x4E, 0xAF),
28410e48b7dSAlex A. Mihaylov 	regmap_reg_range(0xB1, 0xB3),
28510e48b7dSAlex A. Mihaylov 	regmap_reg_range(0xB5, 0xB7),
28610e48b7dSAlex A. Mihaylov 	regmap_reg_range(0xBF, 0xD0),
28710e48b7dSAlex A. Mihaylov 	regmap_reg_range(0xDB, 0xDB),
28810e48b7dSAlex A. Mihaylov 	/* hole between volatile and non-volatile registers */
28910e48b7dSAlex A. Mihaylov 	regmap_reg_range(0xE0, 0x17F),
29010e48b7dSAlex A. Mihaylov };
29110e48b7dSAlex A. Mihaylov 
29210e48b7dSAlex A. Mihaylov static const struct regmap_access_table max1721x_regs = {
29310e48b7dSAlex A. Mihaylov 	.yes_ranges	= max1721x_allow_range,
29410e48b7dSAlex A. Mihaylov 	.n_yes_ranges	= ARRAY_SIZE(max1721x_allow_range),
29510e48b7dSAlex A. Mihaylov 	.no_ranges	= max1721x_deny_range,
29610e48b7dSAlex A. Mihaylov 	.n_no_ranges	= ARRAY_SIZE(max1721x_deny_range),
29710e48b7dSAlex A. Mihaylov };
29810e48b7dSAlex A. Mihaylov 
29910e48b7dSAlex A. Mihaylov /*
30010e48b7dSAlex A. Mihaylov  * Model Gauge M5 Algorithm output register
30110e48b7dSAlex A. Mihaylov  * Volatile data (must not be cached)
30210e48b7dSAlex A. Mihaylov  */
30310e48b7dSAlex A. Mihaylov static const struct regmap_range max1721x_volatile_allow[] = {
30410e48b7dSAlex A. Mihaylov 	regmap_reg_range(0, 0xDF),
30510e48b7dSAlex A. Mihaylov };
30610e48b7dSAlex A. Mihaylov 
30710e48b7dSAlex A. Mihaylov static const struct regmap_access_table max1721x_volatile_regs = {
30810e48b7dSAlex A. Mihaylov 	.yes_ranges	= max1721x_volatile_allow,
30910e48b7dSAlex A. Mihaylov 	.n_yes_ranges	= ARRAY_SIZE(max1721x_volatile_allow),
31010e48b7dSAlex A. Mihaylov };
31110e48b7dSAlex A. Mihaylov 
31210e48b7dSAlex A. Mihaylov /*
31310e48b7dSAlex A. Mihaylov  * W1-regmap config
31410e48b7dSAlex A. Mihaylov  */
31510e48b7dSAlex A. Mihaylov static const struct regmap_config max1721x_regmap_w1_config = {
31610e48b7dSAlex A. Mihaylov 	.reg_bits = 16,
31710e48b7dSAlex A. Mihaylov 	.val_bits = 16,
31810e48b7dSAlex A. Mihaylov 	.rd_table = &max1721x_regs,
31910e48b7dSAlex A. Mihaylov 	.volatile_table = &max1721x_volatile_regs,
32010e48b7dSAlex A. Mihaylov 	.max_register = MAX1721X_MAX_REG_NR,
32110e48b7dSAlex A. Mihaylov };
32210e48b7dSAlex A. Mihaylov 
devm_w1_max1721x_add_device(struct w1_slave * sl)32310e48b7dSAlex A. Mihaylov static int devm_w1_max1721x_add_device(struct w1_slave *sl)
32410e48b7dSAlex A. Mihaylov {
32510e48b7dSAlex A. Mihaylov 	struct power_supply_config psy_cfg = {};
32610e48b7dSAlex A. Mihaylov 	struct max17211_device_info *info;
32710e48b7dSAlex A. Mihaylov 
32810e48b7dSAlex A. Mihaylov 	info = devm_kzalloc(&sl->dev, sizeof(*info), GFP_KERNEL);
32910e48b7dSAlex A. Mihaylov 	if (!info)
33010e48b7dSAlex A. Mihaylov 		return -ENOMEM;
33110e48b7dSAlex A. Mihaylov 
33210e48b7dSAlex A. Mihaylov 	sl->family_data = (void *)info;
33310e48b7dSAlex A. Mihaylov 	info->w1_dev = &sl->dev;
33410e48b7dSAlex A. Mihaylov 
33510e48b7dSAlex A. Mihaylov 	/*
33610e48b7dSAlex A. Mihaylov 	 * power_supply class battery name translated from W1 slave device
337bd3689a6SXiaofeng Cao 	 * unique ID (look like 26-0123456789AB) to "max1721x-0123456789AB\0"
338bd3689a6SXiaofeng Cao 	 * so, 26 (device family) correspond to max1721x devices.
339bd3689a6SXiaofeng Cao 	 * Device name still unique for any number of connected devices.
34010e48b7dSAlex A. Mihaylov 	 */
34110e48b7dSAlex A. Mihaylov 	snprintf(info->name, sizeof(info->name),
34210e48b7dSAlex A. Mihaylov 		"max1721x-%012X", (unsigned int)sl->reg_num.id);
34310e48b7dSAlex A. Mihaylov 	info->bat_desc.name = info->name;
34410e48b7dSAlex A. Mihaylov 
34510e48b7dSAlex A. Mihaylov 	/*
34610e48b7dSAlex A. Mihaylov 	 * FixMe: battery device name exceed max len for thermal_zone device
34710e48b7dSAlex A. Mihaylov 	 * name and translation to thermal_zone must be disabled.
34810e48b7dSAlex A. Mihaylov 	 */
34910e48b7dSAlex A. Mihaylov 	info->bat_desc.no_thermal = true;
35010e48b7dSAlex A. Mihaylov 	info->bat_desc.type = POWER_SUPPLY_TYPE_BATTERY;
35110e48b7dSAlex A. Mihaylov 	info->bat_desc.properties = max1721x_battery_props;
35210e48b7dSAlex A. Mihaylov 	info->bat_desc.num_properties = ARRAY_SIZE(max1721x_battery_props);
35310e48b7dSAlex A. Mihaylov 	info->bat_desc.get_property = max1721x_battery_get_property;
35410e48b7dSAlex A. Mihaylov 	psy_cfg.drv_data = info;
35510e48b7dSAlex A. Mihaylov 
35610e48b7dSAlex A. Mihaylov 	/* regmap init */
35710e48b7dSAlex A. Mihaylov 	info->regmap = devm_regmap_init_w1(info->w1_dev,
35810e48b7dSAlex A. Mihaylov 					&max1721x_regmap_w1_config);
35910e48b7dSAlex A. Mihaylov 	if (IS_ERR(info->regmap)) {
36010e48b7dSAlex A. Mihaylov 		int err = PTR_ERR(info->regmap);
36110e48b7dSAlex A. Mihaylov 
36210e48b7dSAlex A. Mihaylov 		dev_err(info->w1_dev, "Failed to allocate register map: %d\n",
36310e48b7dSAlex A. Mihaylov 			err);
36410e48b7dSAlex A. Mihaylov 		return err;
36510e48b7dSAlex A. Mihaylov 	}
36610e48b7dSAlex A. Mihaylov 
36710e48b7dSAlex A. Mihaylov 	/* rsense init */
36810e48b7dSAlex A. Mihaylov 	info->rsense = 0;
36910e48b7dSAlex A. Mihaylov 	if (regmap_read(info->regmap, MAX1721X_REG_NRSENSE, &info->rsense)) {
37010e48b7dSAlex A. Mihaylov 		dev_err(info->w1_dev, "Can't read RSense. Hardware error.\n");
37110e48b7dSAlex A. Mihaylov 		return -ENODEV;
37210e48b7dSAlex A. Mihaylov 	}
37310e48b7dSAlex A. Mihaylov 
37410e48b7dSAlex A. Mihaylov 	if (!info->rsense) {
3751d45d2d2SColin Ian King 		dev_warn(info->w1_dev, "RSense not calibrated, set 10 mOhms!\n");
37610e48b7dSAlex A. Mihaylov 		info->rsense = 1000; /* in regs in 10^-5 */
37710e48b7dSAlex A. Mihaylov 	}
37810e48b7dSAlex A. Mihaylov 	dev_info(info->w1_dev, "RSense: %d mOhms.\n", info->rsense / 100);
37910e48b7dSAlex A. Mihaylov 
38010e48b7dSAlex A. Mihaylov 	if (get_string(info, MAX1721X_REG_MFG_STR,
38110e48b7dSAlex A. Mihaylov 			MAX1721X_REG_MFG_NUMB, info->ManufacturerName)) {
38210e48b7dSAlex A. Mihaylov 		dev_err(info->w1_dev, "Can't read manufacturer. Hardware error.\n");
38310e48b7dSAlex A. Mihaylov 		return -ENODEV;
38410e48b7dSAlex A. Mihaylov 	}
38510e48b7dSAlex A. Mihaylov 
38610e48b7dSAlex A. Mihaylov 	if (!info->ManufacturerName[0])
387*301cfbc1SMinghao Chi 		strscpy(info->ManufacturerName, DEF_MFG_NAME,
38810e48b7dSAlex A. Mihaylov 			2 * MAX1721X_REG_MFG_NUMB);
38910e48b7dSAlex A. Mihaylov 
39010e48b7dSAlex A. Mihaylov 	if (get_string(info, MAX1721X_REG_DEV_STR,
39110e48b7dSAlex A. Mihaylov 			MAX1721X_REG_DEV_NUMB, info->DeviceName)) {
39210e48b7dSAlex A. Mihaylov 		dev_err(info->w1_dev, "Can't read device. Hardware error.\n");
39310e48b7dSAlex A. Mihaylov 		return -ENODEV;
39410e48b7dSAlex A. Mihaylov 	}
39510e48b7dSAlex A. Mihaylov 	if (!info->DeviceName[0]) {
39610e48b7dSAlex A. Mihaylov 		unsigned int dev_name;
39710e48b7dSAlex A. Mihaylov 
39810e48b7dSAlex A. Mihaylov 		if (regmap_read(info->regmap,
39910e48b7dSAlex A. Mihaylov 				MAX172XX_REG_DEVNAME, &dev_name)) {
40010e48b7dSAlex A. Mihaylov 			dev_err(info->w1_dev, "Can't read device name reg.\n");
40110e48b7dSAlex A. Mihaylov 			return -ENODEV;
40210e48b7dSAlex A. Mihaylov 		}
40310e48b7dSAlex A. Mihaylov 
40410e48b7dSAlex A. Mihaylov 		switch (dev_name & MAX172XX_DEV_MASK) {
40510e48b7dSAlex A. Mihaylov 		case MAX172X1_DEV:
406*301cfbc1SMinghao Chi 			strscpy(info->DeviceName, DEF_DEV_NAME_MAX17211,
40710e48b7dSAlex A. Mihaylov 				2 * MAX1721X_REG_DEV_NUMB);
40810e48b7dSAlex A. Mihaylov 			break;
40910e48b7dSAlex A. Mihaylov 		case MAX172X5_DEV:
410*301cfbc1SMinghao Chi 			strscpy(info->DeviceName, DEF_DEV_NAME_MAX17215,
41110e48b7dSAlex A. Mihaylov 				2 * MAX1721X_REG_DEV_NUMB);
41210e48b7dSAlex A. Mihaylov 			break;
41310e48b7dSAlex A. Mihaylov 		default:
414*301cfbc1SMinghao Chi 			strscpy(info->DeviceName, DEF_DEV_NAME_UNKNOWN,
41510e48b7dSAlex A. Mihaylov 				2 * MAX1721X_REG_DEV_NUMB);
41610e48b7dSAlex A. Mihaylov 		}
41710e48b7dSAlex A. Mihaylov 	}
41810e48b7dSAlex A. Mihaylov 
41910e48b7dSAlex A. Mihaylov 	if (get_sn_string(info, info->SerialNumber)) {
42010e48b7dSAlex A. Mihaylov 		dev_err(info->w1_dev, "Can't read serial. Hardware error.\n");
42110e48b7dSAlex A. Mihaylov 		return -ENODEV;
42210e48b7dSAlex A. Mihaylov 	}
42310e48b7dSAlex A. Mihaylov 
42410e48b7dSAlex A. Mihaylov 	info->bat = devm_power_supply_register(&sl->dev, &info->bat_desc,
42510e48b7dSAlex A. Mihaylov 						&psy_cfg);
42610e48b7dSAlex A. Mihaylov 	if (IS_ERR(info->bat)) {
42710e48b7dSAlex A. Mihaylov 		dev_err(info->w1_dev, "failed to register battery\n");
42810e48b7dSAlex A. Mihaylov 		return PTR_ERR(info->bat);
42910e48b7dSAlex A. Mihaylov 	}
43010e48b7dSAlex A. Mihaylov 
43110e48b7dSAlex A. Mihaylov 	return 0;
43210e48b7dSAlex A. Mihaylov }
43310e48b7dSAlex A. Mihaylov 
4346925478cSRikard Falkeborn static const struct w1_family_ops w1_max1721x_fops = {
43510e48b7dSAlex A. Mihaylov 	.add_slave = devm_w1_max1721x_add_device,
43610e48b7dSAlex A. Mihaylov };
43710e48b7dSAlex A. Mihaylov 
43810e48b7dSAlex A. Mihaylov static struct w1_family w1_max1721x_family = {
43910e48b7dSAlex A. Mihaylov 	.fid = W1_MAX1721X_FAMILY_ID,
44010e48b7dSAlex A. Mihaylov 	.fops = &w1_max1721x_fops,
44110e48b7dSAlex A. Mihaylov };
44210e48b7dSAlex A. Mihaylov 
44310e48b7dSAlex A. Mihaylov module_w1_family(w1_max1721x_family);
44410e48b7dSAlex A. Mihaylov 
44510e48b7dSAlex A. Mihaylov MODULE_LICENSE("GPL");
44610e48b7dSAlex A. Mihaylov MODULE_AUTHOR("Alex A. Mihaylov <minimumlaw@rambler.ru>");
4478bc80006SColin Ian King MODULE_DESCRIPTION("Maxim MAX17211/MAX17215 Fuel Gauge IC driver");
44810e48b7dSAlex A. Mihaylov MODULE_ALIAS("w1-family-" __stringify(W1_MAX1721X_FAMILY_ID));
449