Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

power: max17042_battery: add HEALTH and TEMP_* properties support

This patch adds the support for following battery properties
to max17042 fuel gauge driver.

POWER_SUPPLY_PROP_TEMP_ALERT_MIN
POWER_SUPPLY_PROP_TEMP_ALERT_MAX
POWER_SUPPLY_PROP_TEMP_MIN
POWER_SUPPLY_PROP_TEMP_MAX
POWER_SUPPLY_PROP_HEALTH

Signed-off-by: Ramakrishna Pallala <ramakrishna.pallala@intel.com>
Reviewed-by: Krzysztof Kozlowski <k.kozlowski.k@gmail.com>
Signed-off-by: Sebastian Reichel <sre@kernel.org>

authored by

Ramakrishna Pallala and committed by
Sebastian Reichel
edd4ab05 4aeae9cb

+183 -11
+179 -11
drivers/power/max17042_battery.c
··· 63 63 #define dP_ACC_100 0x1900 64 64 #define dP_ACC_200 0x3200 65 65 66 + #define MAX17042_VMAX_TOLERANCE 50 /* 50 mV */ 67 + 66 68 struct max17042_chip { 67 69 struct i2c_client *client; 68 70 struct regmap *regmap; ··· 87 85 POWER_SUPPLY_PROP_CHARGE_FULL, 88 86 POWER_SUPPLY_PROP_CHARGE_COUNTER, 89 87 POWER_SUPPLY_PROP_TEMP, 88 + POWER_SUPPLY_PROP_TEMP_ALERT_MIN, 89 + POWER_SUPPLY_PROP_TEMP_ALERT_MAX, 90 + POWER_SUPPLY_PROP_TEMP_MIN, 91 + POWER_SUPPLY_PROP_TEMP_MAX, 92 + POWER_SUPPLY_PROP_HEALTH, 90 93 POWER_SUPPLY_PROP_CURRENT_NOW, 91 94 POWER_SUPPLY_PROP_CURRENT_AVG, 92 95 }; 96 + 97 + static int max17042_get_temperature(struct max17042_chip *chip, int *temp) 98 + { 99 + int ret; 100 + u32 data; 101 + struct regmap *map = chip->regmap; 102 + 103 + ret = regmap_read(map, MAX17042_TEMP, &data); 104 + if (ret < 0) 105 + return ret; 106 + 107 + *temp = data; 108 + /* The value is signed. */ 109 + if (*temp & 0x8000) { 110 + *temp = (0x7fff & ~*temp) + 1; 111 + *temp *= -1; 112 + } 113 + 114 + /* The value is converted into deci-centigrade scale */ 115 + /* Units of LSB = 1 / 256 degree Celsius */ 116 + *temp = *temp * 10 / 256; 117 + return 0; 118 + } 119 + 120 + static int max17042_get_battery_health(struct max17042_chip *chip, int *health) 121 + { 122 + int temp, vavg, vbatt, ret; 123 + u32 val; 124 + 125 + ret = regmap_read(chip->regmap, MAX17042_AvgVCELL, &val); 126 + if (ret < 0) 127 + goto health_error; 128 + 129 + /* bits [0-3] unused */ 130 + vavg = val * 625 / 8; 131 + /* Convert to millivolts */ 132 + vavg /= 1000; 133 + 134 + ret = regmap_read(chip->regmap, MAX17042_VCELL, &val); 135 + if (ret < 0) 136 + goto health_error; 137 + 138 + /* bits [0-3] unused */ 139 + vbatt = val * 625 / 8; 140 + /* Convert to millivolts */ 141 + vbatt /= 1000; 142 + 143 + if (vavg < chip->pdata->vmin) { 144 + *health = POWER_SUPPLY_HEALTH_DEAD; 145 + goto out; 146 + } 147 + 148 + if (vbatt > chip->pdata->vmax + MAX17042_VMAX_TOLERANCE) { 149 + *health = POWER_SUPPLY_HEALTH_OVERVOLTAGE; 150 + goto out; 151 + } 152 + 153 + ret = max17042_get_temperature(chip, &temp); 154 + if (ret < 0) 155 + goto health_error; 156 + 157 + if (temp <= chip->pdata->temp_min) { 158 + *health = POWER_SUPPLY_HEALTH_COLD; 159 + goto out; 160 + } 161 + 162 + if (temp >= chip->pdata->temp_max) { 163 + *health = POWER_SUPPLY_HEALTH_OVERHEAT; 164 + goto out; 165 + } 166 + 167 + *health = POWER_SUPPLY_HEALTH_GOOD; 168 + 169 + out: 170 + return 0; 171 + 172 + health_error: 173 + return ret; 174 + } 93 175 94 176 static int max17042_get_property(struct power_supply *psy, 95 177 enum power_supply_property psp, ··· 267 181 val->intval = data * 1000 / 2; 268 182 break; 269 183 case POWER_SUPPLY_PROP_TEMP: 270 - ret = regmap_read(map, MAX17042_TEMP, &data); 184 + ret = max17042_get_temperature(chip, &val->intval); 271 185 if (ret < 0) 272 186 return ret; 273 - 274 - val->intval = data; 275 - /* The value is signed. */ 276 - if (val->intval & 0x8000) { 277 - val->intval = (0x7fff & ~val->intval) + 1; 278 - val->intval *= -1; 279 - } 280 - /* The value is converted into deci-centigrade scale */ 281 - /* Units of LSB = 1 / 256 degree Celsius */ 282 - val->intval = val->intval * 10 / 256; 187 + break; 188 + case POWER_SUPPLY_PROP_TEMP_ALERT_MIN: 189 + ret = regmap_read(map, MAX17042_TALRT_Th, &data); 190 + if (ret < 0) 191 + return ret; 192 + /* LSB is Alert Minimum. In deci-centigrade */ 193 + val->intval = (data & 0xff) * 10; 194 + break; 195 + case POWER_SUPPLY_PROP_TEMP_ALERT_MAX: 196 + ret = regmap_read(map, MAX17042_TALRT_Th, &data); 197 + if (ret < 0) 198 + return ret; 199 + /* MSB is Alert Maximum. In deci-centigrade */ 200 + val->intval = (data >> 8) * 10; 201 + break; 202 + case POWER_SUPPLY_PROP_TEMP_MIN: 203 + val->intval = chip->pdata->temp_min; 204 + break; 205 + case POWER_SUPPLY_PROP_TEMP_MAX: 206 + val->intval = chip->pdata->temp_max; 207 + break; 208 + case POWER_SUPPLY_PROP_HEALTH: 209 + ret = max17042_get_battery_health(chip, &val->intval); 210 + if (ret < 0) 211 + return ret; 283 212 break; 284 213 case POWER_SUPPLY_PROP_CURRENT_NOW: 285 214 if (chip->pdata->enable_current_sense) { ··· 336 235 return -EINVAL; 337 236 } 338 237 return 0; 238 + } 239 + 240 + static int max17042_set_property(struct power_supply *psy, 241 + enum power_supply_property psp, 242 + const union power_supply_propval *val) 243 + { 244 + struct max17042_chip *chip = power_supply_get_drvdata(psy); 245 + struct regmap *map = chip->regmap; 246 + int ret = 0; 247 + u32 data; 248 + int8_t temp; 249 + 250 + switch (psp) { 251 + case POWER_SUPPLY_PROP_TEMP_ALERT_MIN: 252 + ret = regmap_read(map, MAX17042_TALRT_Th, &data); 253 + if (ret < 0) 254 + return ret; 255 + 256 + /* Input in deci-centigrade, convert to centigrade */ 257 + temp = val->intval / 10; 258 + /* force min < max */ 259 + if (temp >= (int8_t)(data >> 8)) 260 + temp = (int8_t)(data >> 8) - 1; 261 + /* Write both MAX and MIN ALERT */ 262 + data = (data & 0xff00) + temp; 263 + ret = regmap_write(map, MAX17042_TALRT_Th, data); 264 + break; 265 + case POWER_SUPPLY_PROP_TEMP_ALERT_MAX: 266 + ret = regmap_read(map, MAX17042_TALRT_Th, &data); 267 + if (ret < 0) 268 + return ret; 269 + 270 + /* Input in Deci-Centigrade, convert to centigrade */ 271 + temp = val->intval / 10; 272 + /* force max > min */ 273 + if (temp <= (int8_t)(data & 0xff)) 274 + temp = (int8_t)(data & 0xff) + 1; 275 + /* Write both MAX and MIN ALERT */ 276 + data = (data & 0xff) + (temp << 8); 277 + ret = regmap_write(map, MAX17042_TALRT_Th, data); 278 + break; 279 + default: 280 + ret = -EINVAL; 281 + } 282 + 283 + return ret; 284 + } 285 + 286 + static int max17042_property_is_writeable(struct power_supply *psy, 287 + enum power_supply_property psp) 288 + { 289 + int ret; 290 + 291 + switch (psp) { 292 + case POWER_SUPPLY_PROP_TEMP_ALERT_MIN: 293 + case POWER_SUPPLY_PROP_TEMP_ALERT_MAX: 294 + ret = 1; 295 + break; 296 + default: 297 + ret = 0; 298 + } 299 + 300 + return ret; 339 301 } 340 302 341 303 static int max17042_write_verify_reg(struct regmap *map, u8 reg, u32 value) ··· 829 665 .name = "max170xx_battery", 830 666 .type = POWER_SUPPLY_TYPE_BATTERY, 831 667 .get_property = max17042_get_property, 668 + .set_property = max17042_set_property, 669 + .property_is_writeable = max17042_property_is_writeable, 832 670 .properties = max17042_battery_props, 833 671 .num_properties = ARRAY_SIZE(max17042_battery_props), 834 672 }; ··· 839 673 .name = "max170xx_battery", 840 674 .type = POWER_SUPPLY_TYPE_BATTERY, 841 675 .get_property = max17042_get_property, 676 + .set_property = max17042_set_property, 677 + .property_is_writeable = max17042_property_is_writeable, 842 678 .properties = max17042_battery_props, 843 679 .num_properties = ARRAY_SIZE(max17042_battery_props) - 2, 844 680 };
+4
include/linux/power/max17042_battery.h
··· 215 215 * the datasheet although it can be changed by board designers. 216 216 */ 217 217 unsigned int r_sns; 218 + int vmin; /* in millivolts */ 219 + int vmax; /* in millivolts */ 220 + int temp_min; /* in tenths of degree Celsius */ 221 + int temp_max; /* in tenths of degree Celsius */ 218 222 }; 219 223 220 224 #endif /* __MAX17042_BATTERY_H_ */