162306a36Sopenharmony_ci/*
262306a36Sopenharmony_ci * 1-Wire implementation for Maxim Semiconductor
362306a36Sopenharmony_ci * MAX7211/MAX17215 standalone fuel gauge chip
462306a36Sopenharmony_ci *
562306a36Sopenharmony_ci * Copyright (C) 2017 Radioavionica Corporation
662306a36Sopenharmony_ci * Author: Alex A. Mihaylov <minimumlaw@rambler.ru>
762306a36Sopenharmony_ci *
862306a36Sopenharmony_ci * Use consistent with the GNU GPL is permitted,
962306a36Sopenharmony_ci * provided that this copyright notice is
1062306a36Sopenharmony_ci * preserved in its entirety in all copies and derived works.
1162306a36Sopenharmony_ci *
1262306a36Sopenharmony_ci */
1362306a36Sopenharmony_ci
1462306a36Sopenharmony_ci#include <linux/module.h>
1562306a36Sopenharmony_ci#include <linux/slab.h>
1662306a36Sopenharmony_ci#include <linux/w1.h>
1762306a36Sopenharmony_ci#include <linux/regmap.h>
1862306a36Sopenharmony_ci#include <linux/power_supply.h>
1962306a36Sopenharmony_ci
2062306a36Sopenharmony_ci#define W1_MAX1721X_FAMILY_ID		0x26
2162306a36Sopenharmony_ci#define DEF_DEV_NAME_MAX17211		"MAX17211"
2262306a36Sopenharmony_ci#define DEF_DEV_NAME_MAX17215		"MAX17215"
2362306a36Sopenharmony_ci#define DEF_DEV_NAME_UNKNOWN		"UNKNOWN"
2462306a36Sopenharmony_ci#define DEF_MFG_NAME			"MAXIM"
2562306a36Sopenharmony_ci
2662306a36Sopenharmony_ci#define PSY_MAX_NAME_LEN	32
2762306a36Sopenharmony_ci
2862306a36Sopenharmony_ci/* Number of valid register addresses in W1 mode */
2962306a36Sopenharmony_ci#define MAX1721X_MAX_REG_NR	0x1EF
3062306a36Sopenharmony_ci
3162306a36Sopenharmony_ci/* Factory settings (nonvolatile registers) (W1 specific) */
3262306a36Sopenharmony_ci#define MAX1721X_REG_NRSENSE	0x1CF	/* RSense in 10^-5 Ohm */
3362306a36Sopenharmony_ci/* Strings */
3462306a36Sopenharmony_ci#define MAX1721X_REG_MFG_STR	0x1CC
3562306a36Sopenharmony_ci#define MAX1721X_REG_MFG_NUMB	3
3662306a36Sopenharmony_ci#define MAX1721X_REG_DEV_STR	0x1DB
3762306a36Sopenharmony_ci#define MAX1721X_REG_DEV_NUMB	5
3862306a36Sopenharmony_ci/* HEX Strings */
3962306a36Sopenharmony_ci#define MAX1721X_REG_SER_HEX	0x1D8
4062306a36Sopenharmony_ci
4162306a36Sopenharmony_ci/* MAX172XX Output Registers for W1 chips */
4262306a36Sopenharmony_ci#define MAX172XX_REG_STATUS	0x000	/* status reg */
4362306a36Sopenharmony_ci#define MAX172XX_BAT_PRESENT	(1<<4)	/* battery connected bit */
4462306a36Sopenharmony_ci#define MAX172XX_REG_DEVNAME	0x021	/* chip config */
4562306a36Sopenharmony_ci#define MAX172XX_DEV_MASK	0x000F	/* chip type mask */
4662306a36Sopenharmony_ci#define MAX172X1_DEV		0x0001
4762306a36Sopenharmony_ci#define MAX172X5_DEV		0x0005
4862306a36Sopenharmony_ci#define MAX172XX_REG_TEMP	0x008	/* Temperature */
4962306a36Sopenharmony_ci#define MAX172XX_REG_BATT	0x0DA	/* Battery voltage */
5062306a36Sopenharmony_ci#define MAX172XX_REG_CURRENT	0x00A	/* Actual current */
5162306a36Sopenharmony_ci#define MAX172XX_REG_AVGCURRENT	0x00B	/* Average current */
5262306a36Sopenharmony_ci#define MAX172XX_REG_REPSOC	0x006	/* Percentage of charge */
5362306a36Sopenharmony_ci#define MAX172XX_REG_DESIGNCAP	0x018	/* Design capacity */
5462306a36Sopenharmony_ci#define MAX172XX_REG_REPCAP	0x005	/* Average capacity */
5562306a36Sopenharmony_ci#define MAX172XX_REG_TTE	0x011	/* Time to empty */
5662306a36Sopenharmony_ci#define MAX172XX_REG_TTF	0x020	/* Time to full */
5762306a36Sopenharmony_ci
5862306a36Sopenharmony_cistruct max17211_device_info {
5962306a36Sopenharmony_ci	char name[PSY_MAX_NAME_LEN];
6062306a36Sopenharmony_ci	struct power_supply *bat;
6162306a36Sopenharmony_ci	struct power_supply_desc bat_desc;
6262306a36Sopenharmony_ci	struct device *w1_dev;
6362306a36Sopenharmony_ci	struct regmap *regmap;
6462306a36Sopenharmony_ci	/* battery design format */
6562306a36Sopenharmony_ci	unsigned int rsense; /* in tenths uOhm */
6662306a36Sopenharmony_ci	char DeviceName[2 * MAX1721X_REG_DEV_NUMB + 1];
6762306a36Sopenharmony_ci	char ManufacturerName[2 * MAX1721X_REG_MFG_NUMB + 1];
6862306a36Sopenharmony_ci	char SerialNumber[13]; /* see get_sn_str() later for comment */
6962306a36Sopenharmony_ci};
7062306a36Sopenharmony_ci
7162306a36Sopenharmony_ci/* Convert regs value to power_supply units */
7262306a36Sopenharmony_ci
7362306a36Sopenharmony_cistatic inline int max172xx_time_to_ps(unsigned int reg)
7462306a36Sopenharmony_ci{
7562306a36Sopenharmony_ci	return reg * 5625 / 1000;	/* in sec. */
7662306a36Sopenharmony_ci}
7762306a36Sopenharmony_ci
7862306a36Sopenharmony_cistatic inline int max172xx_percent_to_ps(unsigned int reg)
7962306a36Sopenharmony_ci{
8062306a36Sopenharmony_ci	return reg / 256;	/* in percent from 0 to 100 */
8162306a36Sopenharmony_ci}
8262306a36Sopenharmony_ci
8362306a36Sopenharmony_cistatic inline int max172xx_voltage_to_ps(unsigned int reg)
8462306a36Sopenharmony_ci{
8562306a36Sopenharmony_ci	return reg * 1250;	/* in uV */
8662306a36Sopenharmony_ci}
8762306a36Sopenharmony_ci
8862306a36Sopenharmony_cistatic inline int max172xx_capacity_to_ps(unsigned int reg)
8962306a36Sopenharmony_ci{
9062306a36Sopenharmony_ci	return reg * 500;	/* in uAh */
9162306a36Sopenharmony_ci}
9262306a36Sopenharmony_ci
9362306a36Sopenharmony_ci/*
9462306a36Sopenharmony_ci * Current and temperature is signed values, so unsigned regs
9562306a36Sopenharmony_ci * value must be converted to signed type
9662306a36Sopenharmony_ci */
9762306a36Sopenharmony_ci
9862306a36Sopenharmony_cistatic inline int max172xx_temperature_to_ps(unsigned int reg)
9962306a36Sopenharmony_ci{
10062306a36Sopenharmony_ci	int val = (int16_t)(reg);
10162306a36Sopenharmony_ci
10262306a36Sopenharmony_ci	return val * 10 / 256; /* in tenths of deg. C */
10362306a36Sopenharmony_ci}
10462306a36Sopenharmony_ci
10562306a36Sopenharmony_ci/*
10662306a36Sopenharmony_ci * Calculating current registers resolution:
10762306a36Sopenharmony_ci *
10862306a36Sopenharmony_ci * RSense stored in 10^-5 Ohm, so measurement voltage must be
10962306a36Sopenharmony_ci * in 10^-11 Volts for get current in uA.
11062306a36Sopenharmony_ci * 16 bit current reg fullscale +/-51.2mV is 102400 uV.
11162306a36Sopenharmony_ci * So: 102400 / 65535 * 10^5 = 156252
11262306a36Sopenharmony_ci */
11362306a36Sopenharmony_cistatic inline int max172xx_current_to_voltage(unsigned int reg)
11462306a36Sopenharmony_ci{
11562306a36Sopenharmony_ci	int val = (int16_t)(reg);
11662306a36Sopenharmony_ci
11762306a36Sopenharmony_ci	return val * 156252;
11862306a36Sopenharmony_ci}
11962306a36Sopenharmony_ci
12062306a36Sopenharmony_ci
12162306a36Sopenharmony_cistatic inline struct max17211_device_info *
12262306a36Sopenharmony_cito_device_info(struct power_supply *psy)
12362306a36Sopenharmony_ci{
12462306a36Sopenharmony_ci	return power_supply_get_drvdata(psy);
12562306a36Sopenharmony_ci}
12662306a36Sopenharmony_ci
12762306a36Sopenharmony_cistatic int max1721x_battery_get_property(struct power_supply *psy,
12862306a36Sopenharmony_ci	enum power_supply_property psp,
12962306a36Sopenharmony_ci	union power_supply_propval *val)
13062306a36Sopenharmony_ci{
13162306a36Sopenharmony_ci	struct max17211_device_info *info = to_device_info(psy);
13262306a36Sopenharmony_ci	unsigned int reg = 0;
13362306a36Sopenharmony_ci	int ret = 0;
13462306a36Sopenharmony_ci
13562306a36Sopenharmony_ci	switch (psp) {
13662306a36Sopenharmony_ci	case POWER_SUPPLY_PROP_PRESENT:
13762306a36Sopenharmony_ci		/*
13862306a36Sopenharmony_ci		 * POWER_SUPPLY_PROP_PRESENT will always readable via
13962306a36Sopenharmony_ci		 * sysfs interface. Value return 0 if battery not
14062306a36Sopenharmony_ci		 * present or unaccessible via W1.
14162306a36Sopenharmony_ci		 */
14262306a36Sopenharmony_ci		val->intval =
14362306a36Sopenharmony_ci			regmap_read(info->regmap, MAX172XX_REG_STATUS,
14462306a36Sopenharmony_ci			&reg) ? 0 : !(reg & MAX172XX_BAT_PRESENT);
14562306a36Sopenharmony_ci		break;
14662306a36Sopenharmony_ci	case POWER_SUPPLY_PROP_CAPACITY:
14762306a36Sopenharmony_ci		ret = regmap_read(info->regmap, MAX172XX_REG_REPSOC, &reg);
14862306a36Sopenharmony_ci		val->intval = max172xx_percent_to_ps(reg);
14962306a36Sopenharmony_ci		break;
15062306a36Sopenharmony_ci	case POWER_SUPPLY_PROP_VOLTAGE_NOW:
15162306a36Sopenharmony_ci		ret = regmap_read(info->regmap, MAX172XX_REG_BATT, &reg);
15262306a36Sopenharmony_ci		val->intval = max172xx_voltage_to_ps(reg);
15362306a36Sopenharmony_ci		break;
15462306a36Sopenharmony_ci	case POWER_SUPPLY_PROP_CHARGE_FULL_DESIGN:
15562306a36Sopenharmony_ci		ret = regmap_read(info->regmap, MAX172XX_REG_DESIGNCAP, &reg);
15662306a36Sopenharmony_ci		val->intval = max172xx_capacity_to_ps(reg);
15762306a36Sopenharmony_ci		break;
15862306a36Sopenharmony_ci	case POWER_SUPPLY_PROP_CHARGE_AVG:
15962306a36Sopenharmony_ci		ret = regmap_read(info->regmap, MAX172XX_REG_REPCAP, &reg);
16062306a36Sopenharmony_ci		val->intval = max172xx_capacity_to_ps(reg);
16162306a36Sopenharmony_ci		break;
16262306a36Sopenharmony_ci	case POWER_SUPPLY_PROP_TIME_TO_EMPTY_AVG:
16362306a36Sopenharmony_ci		ret = regmap_read(info->regmap, MAX172XX_REG_TTE, &reg);
16462306a36Sopenharmony_ci		val->intval = max172xx_time_to_ps(reg);
16562306a36Sopenharmony_ci		break;
16662306a36Sopenharmony_ci	case POWER_SUPPLY_PROP_TIME_TO_FULL_AVG:
16762306a36Sopenharmony_ci		ret = regmap_read(info->regmap, MAX172XX_REG_TTF, &reg);
16862306a36Sopenharmony_ci		val->intval = max172xx_time_to_ps(reg);
16962306a36Sopenharmony_ci		break;
17062306a36Sopenharmony_ci	case POWER_SUPPLY_PROP_TEMP:
17162306a36Sopenharmony_ci		ret = regmap_read(info->regmap, MAX172XX_REG_TEMP, &reg);
17262306a36Sopenharmony_ci		val->intval = max172xx_temperature_to_ps(reg);
17362306a36Sopenharmony_ci		break;
17462306a36Sopenharmony_ci	/* We need signed current, so must cast info->rsense to signed type */
17562306a36Sopenharmony_ci	case POWER_SUPPLY_PROP_CURRENT_NOW:
17662306a36Sopenharmony_ci		ret = regmap_read(info->regmap, MAX172XX_REG_CURRENT, &reg);
17762306a36Sopenharmony_ci		val->intval =
17862306a36Sopenharmony_ci			max172xx_current_to_voltage(reg) / (int)info->rsense;
17962306a36Sopenharmony_ci		break;
18062306a36Sopenharmony_ci	case POWER_SUPPLY_PROP_CURRENT_AVG:
18162306a36Sopenharmony_ci		ret = regmap_read(info->regmap, MAX172XX_REG_AVGCURRENT, &reg);
18262306a36Sopenharmony_ci		val->intval =
18362306a36Sopenharmony_ci			max172xx_current_to_voltage(reg) / (int)info->rsense;
18462306a36Sopenharmony_ci		break;
18562306a36Sopenharmony_ci	/*
18662306a36Sopenharmony_ci	 * Strings already received and inited by probe.
18762306a36Sopenharmony_ci	 * We do dummy read for check battery still available.
18862306a36Sopenharmony_ci	 */
18962306a36Sopenharmony_ci	case POWER_SUPPLY_PROP_MODEL_NAME:
19062306a36Sopenharmony_ci		ret = regmap_read(info->regmap, MAX1721X_REG_DEV_STR, &reg);
19162306a36Sopenharmony_ci		val->strval = info->DeviceName;
19262306a36Sopenharmony_ci		break;
19362306a36Sopenharmony_ci	case POWER_SUPPLY_PROP_MANUFACTURER:
19462306a36Sopenharmony_ci		ret = regmap_read(info->regmap, MAX1721X_REG_MFG_STR, &reg);
19562306a36Sopenharmony_ci		val->strval = info->ManufacturerName;
19662306a36Sopenharmony_ci		break;
19762306a36Sopenharmony_ci	case POWER_SUPPLY_PROP_SERIAL_NUMBER:
19862306a36Sopenharmony_ci		ret = regmap_read(info->regmap, MAX1721X_REG_SER_HEX, &reg);
19962306a36Sopenharmony_ci		val->strval = info->SerialNumber;
20062306a36Sopenharmony_ci		break;
20162306a36Sopenharmony_ci	default:
20262306a36Sopenharmony_ci		ret = -EINVAL;
20362306a36Sopenharmony_ci	}
20462306a36Sopenharmony_ci
20562306a36Sopenharmony_ci	return ret;
20662306a36Sopenharmony_ci}
20762306a36Sopenharmony_ci
20862306a36Sopenharmony_cistatic enum power_supply_property max1721x_battery_props[] = {
20962306a36Sopenharmony_ci	/* int */
21062306a36Sopenharmony_ci	POWER_SUPPLY_PROP_PRESENT,
21162306a36Sopenharmony_ci	POWER_SUPPLY_PROP_CAPACITY,
21262306a36Sopenharmony_ci	POWER_SUPPLY_PROP_VOLTAGE_NOW,
21362306a36Sopenharmony_ci	POWER_SUPPLY_PROP_CHARGE_FULL_DESIGN,
21462306a36Sopenharmony_ci	POWER_SUPPLY_PROP_CHARGE_AVG,
21562306a36Sopenharmony_ci	POWER_SUPPLY_PROP_TIME_TO_EMPTY_AVG,
21662306a36Sopenharmony_ci	POWER_SUPPLY_PROP_TIME_TO_FULL_AVG,
21762306a36Sopenharmony_ci	POWER_SUPPLY_PROP_TEMP,
21862306a36Sopenharmony_ci	POWER_SUPPLY_PROP_CURRENT_NOW,
21962306a36Sopenharmony_ci	POWER_SUPPLY_PROP_CURRENT_AVG,
22062306a36Sopenharmony_ci	/* strings */
22162306a36Sopenharmony_ci	POWER_SUPPLY_PROP_MODEL_NAME,
22262306a36Sopenharmony_ci	POWER_SUPPLY_PROP_MANUFACTURER,
22362306a36Sopenharmony_ci	POWER_SUPPLY_PROP_SERIAL_NUMBER,
22462306a36Sopenharmony_ci};
22562306a36Sopenharmony_ci
22662306a36Sopenharmony_cistatic int get_string(struct max17211_device_info *info,
22762306a36Sopenharmony_ci			uint16_t reg, uint8_t nr, char *str)
22862306a36Sopenharmony_ci{
22962306a36Sopenharmony_ci	unsigned int val;
23062306a36Sopenharmony_ci
23162306a36Sopenharmony_ci	if (!str || !(reg == MAX1721X_REG_MFG_STR ||
23262306a36Sopenharmony_ci			reg == MAX1721X_REG_DEV_STR))
23362306a36Sopenharmony_ci		return -EFAULT;
23462306a36Sopenharmony_ci
23562306a36Sopenharmony_ci	while (nr--) {
23662306a36Sopenharmony_ci		if (regmap_read(info->regmap, reg++, &val))
23762306a36Sopenharmony_ci			return -EFAULT;
23862306a36Sopenharmony_ci		*str++ = val>>8 & 0x00FF;
23962306a36Sopenharmony_ci		*str++ = val & 0x00FF;
24062306a36Sopenharmony_ci	}
24162306a36Sopenharmony_ci	return 0;
24262306a36Sopenharmony_ci}
24362306a36Sopenharmony_ci
24462306a36Sopenharmony_ci/* Maxim say: Serial number is a hex string up to 12 hex characters */
24562306a36Sopenharmony_cistatic int get_sn_string(struct max17211_device_info *info, char *str)
24662306a36Sopenharmony_ci{
24762306a36Sopenharmony_ci	unsigned int val[3];
24862306a36Sopenharmony_ci
24962306a36Sopenharmony_ci	if (!str)
25062306a36Sopenharmony_ci		return -EFAULT;
25162306a36Sopenharmony_ci
25262306a36Sopenharmony_ci	if (regmap_read(info->regmap, MAX1721X_REG_SER_HEX, &val[0]))
25362306a36Sopenharmony_ci		return -EFAULT;
25462306a36Sopenharmony_ci	if (regmap_read(info->regmap, MAX1721X_REG_SER_HEX + 1, &val[1]))
25562306a36Sopenharmony_ci		return -EFAULT;
25662306a36Sopenharmony_ci	if (regmap_read(info->regmap, MAX1721X_REG_SER_HEX + 2, &val[2]))
25762306a36Sopenharmony_ci		return -EFAULT;
25862306a36Sopenharmony_ci
25962306a36Sopenharmony_ci	snprintf(str, 13, "%04X%04X%04X", val[0], val[1], val[2]);
26062306a36Sopenharmony_ci	return 0;
26162306a36Sopenharmony_ci}
26262306a36Sopenharmony_ci
26362306a36Sopenharmony_ci/*
26462306a36Sopenharmony_ci * MAX1721x registers description for w1-regmap
26562306a36Sopenharmony_ci */
26662306a36Sopenharmony_cistatic const struct regmap_range max1721x_allow_range[] = {
26762306a36Sopenharmony_ci	regmap_reg_range(0, 0xDF),	/* volatile data */
26862306a36Sopenharmony_ci	regmap_reg_range(0x180, 0x1DF),	/* non-volatile memory */
26962306a36Sopenharmony_ci	regmap_reg_range(0x1E0, 0x1EF),	/* non-volatile history (unused) */
27062306a36Sopenharmony_ci};
27162306a36Sopenharmony_ci
27262306a36Sopenharmony_cistatic const struct regmap_range max1721x_deny_range[] = {
27362306a36Sopenharmony_ci	/* volatile data unused registers */
27462306a36Sopenharmony_ci	regmap_reg_range(0x24, 0x26),
27562306a36Sopenharmony_ci	regmap_reg_range(0x30, 0x31),
27662306a36Sopenharmony_ci	regmap_reg_range(0x33, 0x34),
27762306a36Sopenharmony_ci	regmap_reg_range(0x37, 0x37),
27862306a36Sopenharmony_ci	regmap_reg_range(0x3B, 0x3C),
27962306a36Sopenharmony_ci	regmap_reg_range(0x40, 0x41),
28062306a36Sopenharmony_ci	regmap_reg_range(0x43, 0x44),
28162306a36Sopenharmony_ci	regmap_reg_range(0x47, 0x49),
28262306a36Sopenharmony_ci	regmap_reg_range(0x4B, 0x4C),
28362306a36Sopenharmony_ci	regmap_reg_range(0x4E, 0xAF),
28462306a36Sopenharmony_ci	regmap_reg_range(0xB1, 0xB3),
28562306a36Sopenharmony_ci	regmap_reg_range(0xB5, 0xB7),
28662306a36Sopenharmony_ci	regmap_reg_range(0xBF, 0xD0),
28762306a36Sopenharmony_ci	regmap_reg_range(0xDB, 0xDB),
28862306a36Sopenharmony_ci	/* hole between volatile and non-volatile registers */
28962306a36Sopenharmony_ci	regmap_reg_range(0xE0, 0x17F),
29062306a36Sopenharmony_ci};
29162306a36Sopenharmony_ci
29262306a36Sopenharmony_cistatic const struct regmap_access_table max1721x_regs = {
29362306a36Sopenharmony_ci	.yes_ranges	= max1721x_allow_range,
29462306a36Sopenharmony_ci	.n_yes_ranges	= ARRAY_SIZE(max1721x_allow_range),
29562306a36Sopenharmony_ci	.no_ranges	= max1721x_deny_range,
29662306a36Sopenharmony_ci	.n_no_ranges	= ARRAY_SIZE(max1721x_deny_range),
29762306a36Sopenharmony_ci};
29862306a36Sopenharmony_ci
29962306a36Sopenharmony_ci/*
30062306a36Sopenharmony_ci * Model Gauge M5 Algorithm output register
30162306a36Sopenharmony_ci * Volatile data (must not be cached)
30262306a36Sopenharmony_ci */
30362306a36Sopenharmony_cistatic const struct regmap_range max1721x_volatile_allow[] = {
30462306a36Sopenharmony_ci	regmap_reg_range(0, 0xDF),
30562306a36Sopenharmony_ci};
30662306a36Sopenharmony_ci
30762306a36Sopenharmony_cistatic const struct regmap_access_table max1721x_volatile_regs = {
30862306a36Sopenharmony_ci	.yes_ranges	= max1721x_volatile_allow,
30962306a36Sopenharmony_ci	.n_yes_ranges	= ARRAY_SIZE(max1721x_volatile_allow),
31062306a36Sopenharmony_ci};
31162306a36Sopenharmony_ci
31262306a36Sopenharmony_ci/*
31362306a36Sopenharmony_ci * W1-regmap config
31462306a36Sopenharmony_ci */
31562306a36Sopenharmony_cistatic const struct regmap_config max1721x_regmap_w1_config = {
31662306a36Sopenharmony_ci	.reg_bits = 16,
31762306a36Sopenharmony_ci	.val_bits = 16,
31862306a36Sopenharmony_ci	.rd_table = &max1721x_regs,
31962306a36Sopenharmony_ci	.volatile_table = &max1721x_volatile_regs,
32062306a36Sopenharmony_ci	.max_register = MAX1721X_MAX_REG_NR,
32162306a36Sopenharmony_ci};
32262306a36Sopenharmony_ci
32362306a36Sopenharmony_cistatic int devm_w1_max1721x_add_device(struct w1_slave *sl)
32462306a36Sopenharmony_ci{
32562306a36Sopenharmony_ci	struct power_supply_config psy_cfg = {};
32662306a36Sopenharmony_ci	struct max17211_device_info *info;
32762306a36Sopenharmony_ci
32862306a36Sopenharmony_ci	info = devm_kzalloc(&sl->dev, sizeof(*info), GFP_KERNEL);
32962306a36Sopenharmony_ci	if (!info)
33062306a36Sopenharmony_ci		return -ENOMEM;
33162306a36Sopenharmony_ci
33262306a36Sopenharmony_ci	sl->family_data = (void *)info;
33362306a36Sopenharmony_ci	info->w1_dev = &sl->dev;
33462306a36Sopenharmony_ci
33562306a36Sopenharmony_ci	/*
33662306a36Sopenharmony_ci	 * power_supply class battery name translated from W1 slave device
33762306a36Sopenharmony_ci	 * unique ID (look like 26-0123456789AB) to "max1721x-0123456789AB\0"
33862306a36Sopenharmony_ci	 * so, 26 (device family) correspond to max1721x devices.
33962306a36Sopenharmony_ci	 * Device name still unique for any number of connected devices.
34062306a36Sopenharmony_ci	 */
34162306a36Sopenharmony_ci	snprintf(info->name, sizeof(info->name),
34262306a36Sopenharmony_ci		"max1721x-%012X", (unsigned int)sl->reg_num.id);
34362306a36Sopenharmony_ci	info->bat_desc.name = info->name;
34462306a36Sopenharmony_ci
34562306a36Sopenharmony_ci	/*
34662306a36Sopenharmony_ci	 * FixMe: battery device name exceed max len for thermal_zone device
34762306a36Sopenharmony_ci	 * name and translation to thermal_zone must be disabled.
34862306a36Sopenharmony_ci	 */
34962306a36Sopenharmony_ci	info->bat_desc.no_thermal = true;
35062306a36Sopenharmony_ci	info->bat_desc.type = POWER_SUPPLY_TYPE_BATTERY;
35162306a36Sopenharmony_ci	info->bat_desc.properties = max1721x_battery_props;
35262306a36Sopenharmony_ci	info->bat_desc.num_properties = ARRAY_SIZE(max1721x_battery_props);
35362306a36Sopenharmony_ci	info->bat_desc.get_property = max1721x_battery_get_property;
35462306a36Sopenharmony_ci	psy_cfg.drv_data = info;
35562306a36Sopenharmony_ci
35662306a36Sopenharmony_ci	/* regmap init */
35762306a36Sopenharmony_ci	info->regmap = devm_regmap_init_w1(info->w1_dev,
35862306a36Sopenharmony_ci					&max1721x_regmap_w1_config);
35962306a36Sopenharmony_ci	if (IS_ERR(info->regmap)) {
36062306a36Sopenharmony_ci		int err = PTR_ERR(info->regmap);
36162306a36Sopenharmony_ci
36262306a36Sopenharmony_ci		dev_err(info->w1_dev, "Failed to allocate register map: %d\n",
36362306a36Sopenharmony_ci			err);
36462306a36Sopenharmony_ci		return err;
36562306a36Sopenharmony_ci	}
36662306a36Sopenharmony_ci
36762306a36Sopenharmony_ci	/* rsense init */
36862306a36Sopenharmony_ci	info->rsense = 0;
36962306a36Sopenharmony_ci	if (regmap_read(info->regmap, MAX1721X_REG_NRSENSE, &info->rsense)) {
37062306a36Sopenharmony_ci		dev_err(info->w1_dev, "Can't read RSense. Hardware error.\n");
37162306a36Sopenharmony_ci		return -ENODEV;
37262306a36Sopenharmony_ci	}
37362306a36Sopenharmony_ci
37462306a36Sopenharmony_ci	if (!info->rsense) {
37562306a36Sopenharmony_ci		dev_warn(info->w1_dev, "RSense not calibrated, set 10 mOhms!\n");
37662306a36Sopenharmony_ci		info->rsense = 1000; /* in regs in 10^-5 */
37762306a36Sopenharmony_ci	}
37862306a36Sopenharmony_ci	dev_info(info->w1_dev, "RSense: %d mOhms.\n", info->rsense / 100);
37962306a36Sopenharmony_ci
38062306a36Sopenharmony_ci	if (get_string(info, MAX1721X_REG_MFG_STR,
38162306a36Sopenharmony_ci			MAX1721X_REG_MFG_NUMB, info->ManufacturerName)) {
38262306a36Sopenharmony_ci		dev_err(info->w1_dev, "Can't read manufacturer. Hardware error.\n");
38362306a36Sopenharmony_ci		return -ENODEV;
38462306a36Sopenharmony_ci	}
38562306a36Sopenharmony_ci
38662306a36Sopenharmony_ci	if (!info->ManufacturerName[0])
38762306a36Sopenharmony_ci		strscpy(info->ManufacturerName, DEF_MFG_NAME,
38862306a36Sopenharmony_ci			2 * MAX1721X_REG_MFG_NUMB);
38962306a36Sopenharmony_ci
39062306a36Sopenharmony_ci	if (get_string(info, MAX1721X_REG_DEV_STR,
39162306a36Sopenharmony_ci			MAX1721X_REG_DEV_NUMB, info->DeviceName)) {
39262306a36Sopenharmony_ci		dev_err(info->w1_dev, "Can't read device. Hardware error.\n");
39362306a36Sopenharmony_ci		return -ENODEV;
39462306a36Sopenharmony_ci	}
39562306a36Sopenharmony_ci	if (!info->DeviceName[0]) {
39662306a36Sopenharmony_ci		unsigned int dev_name;
39762306a36Sopenharmony_ci
39862306a36Sopenharmony_ci		if (regmap_read(info->regmap,
39962306a36Sopenharmony_ci				MAX172XX_REG_DEVNAME, &dev_name)) {
40062306a36Sopenharmony_ci			dev_err(info->w1_dev, "Can't read device name reg.\n");
40162306a36Sopenharmony_ci			return -ENODEV;
40262306a36Sopenharmony_ci		}
40362306a36Sopenharmony_ci
40462306a36Sopenharmony_ci		switch (dev_name & MAX172XX_DEV_MASK) {
40562306a36Sopenharmony_ci		case MAX172X1_DEV:
40662306a36Sopenharmony_ci			strscpy(info->DeviceName, DEF_DEV_NAME_MAX17211,
40762306a36Sopenharmony_ci				2 * MAX1721X_REG_DEV_NUMB);
40862306a36Sopenharmony_ci			break;
40962306a36Sopenharmony_ci		case MAX172X5_DEV:
41062306a36Sopenharmony_ci			strscpy(info->DeviceName, DEF_DEV_NAME_MAX17215,
41162306a36Sopenharmony_ci				2 * MAX1721X_REG_DEV_NUMB);
41262306a36Sopenharmony_ci			break;
41362306a36Sopenharmony_ci		default:
41462306a36Sopenharmony_ci			strscpy(info->DeviceName, DEF_DEV_NAME_UNKNOWN,
41562306a36Sopenharmony_ci				2 * MAX1721X_REG_DEV_NUMB);
41662306a36Sopenharmony_ci		}
41762306a36Sopenharmony_ci	}
41862306a36Sopenharmony_ci
41962306a36Sopenharmony_ci	if (get_sn_string(info, info->SerialNumber)) {
42062306a36Sopenharmony_ci		dev_err(info->w1_dev, "Can't read serial. Hardware error.\n");
42162306a36Sopenharmony_ci		return -ENODEV;
42262306a36Sopenharmony_ci	}
42362306a36Sopenharmony_ci
42462306a36Sopenharmony_ci	info->bat = devm_power_supply_register(&sl->dev, &info->bat_desc,
42562306a36Sopenharmony_ci						&psy_cfg);
42662306a36Sopenharmony_ci	if (IS_ERR(info->bat)) {
42762306a36Sopenharmony_ci		dev_err(info->w1_dev, "failed to register battery\n");
42862306a36Sopenharmony_ci		return PTR_ERR(info->bat);
42962306a36Sopenharmony_ci	}
43062306a36Sopenharmony_ci
43162306a36Sopenharmony_ci	return 0;
43262306a36Sopenharmony_ci}
43362306a36Sopenharmony_ci
43462306a36Sopenharmony_cistatic const struct w1_family_ops w1_max1721x_fops = {
43562306a36Sopenharmony_ci	.add_slave = devm_w1_max1721x_add_device,
43662306a36Sopenharmony_ci};
43762306a36Sopenharmony_ci
43862306a36Sopenharmony_cistatic struct w1_family w1_max1721x_family = {
43962306a36Sopenharmony_ci	.fid = W1_MAX1721X_FAMILY_ID,
44062306a36Sopenharmony_ci	.fops = &w1_max1721x_fops,
44162306a36Sopenharmony_ci};
44262306a36Sopenharmony_ci
44362306a36Sopenharmony_cimodule_w1_family(w1_max1721x_family);
44462306a36Sopenharmony_ci
44562306a36Sopenharmony_ciMODULE_LICENSE("GPL");
44662306a36Sopenharmony_ciMODULE_AUTHOR("Alex A. Mihaylov <minimumlaw@rambler.ru>");
44762306a36Sopenharmony_ciMODULE_DESCRIPTION("Maxim MAX17211/MAX17215 Fuel Gauge IC driver");
44862306a36Sopenharmony_ciMODULE_ALIAS("w1-family-" __stringify(W1_MAX1721X_FAMILY_ID));
449