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 ®) ? 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, ®); 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, ®); 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, ®); 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, ®); 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, ®); 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, ®); 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, ®); 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, ®); 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, ®); 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, ®); 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, ®); 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, ®); 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