1 // SPDX-License-Identifier: GPL-2.0 2 /* 3 * stc3117_fuel_gauge.c - STMicroelectronics STC3117 Fuel Gauge Driver 4 * 5 * Copyright (c) 2024 Silicon Signals Pvt Ltd. 6 * Author: Hardevsinh Palaniya <hardevsinh.palaniya@siliconsignals.io> 7 * Bhavin Sharma <bhavin.sharma@siliconsignals.io> 8 */ 9 10 #include <linux/crc8.h> 11 #include <linux/devm-helpers.h> 12 #include <linux/i2c.h> 13 #include <linux/power_supply.h> 14 #include <linux/regmap.h> 15 #include <linux/workqueue.h> 16 17 #define STC3117_ADDR_MODE 0x00 18 #define STC3117_ADDR_CTRL 0x01 19 #define STC3117_ADDR_SOC_L 0x02 20 #define STC3117_ADDR_SOC_H 0x03 21 #define STC3117_ADDR_COUNTER_L 0x04 22 #define STC3117_ADDR_COUNTER_H 0x05 23 #define STC3117_ADDR_CURRENT_L 0x06 24 #define STC3117_ADDR_CURRENT_H 0x07 25 #define STC3117_ADDR_VOLTAGE_L 0x08 26 #define STC3117_ADDR_VOLTAGE_H 0x09 27 #define STC3117_ADDR_TEMPERATURE 0x0A 28 #define STC3117_ADDR_AVG_CURRENT_L 0x0B 29 #define STC3117_ADDR_AVG_CURRENT_H 0x0C 30 #define STC3117_ADDR_OCV_L 0x0D 31 #define STC3117_ADDR_OCV_H 0x0E 32 #define STC3117_ADDR_CC_CNF_L 0x0F 33 #define STC3117_ADDR_CC_CNF_H 0x10 34 #define STC3117_ADDR_VM_CNF_L 0x11 35 #define STC3117_ADDR_VM_CNF_H 0x12 36 #define STC3117_ADDR_ALARM_soc 0x13 37 #define STC3117_ADDR_ALARM_VOLTAGE 0x14 38 #define STC3117_ADDR_ID 0x18 39 #define STC3117_ADDR_CC_ADJ_L 0x1B 40 #define STC3117_ADDR_CC_ADJ_H 0x1C 41 #define STC3117_ADDR_VM_ADJ_L 0x1D 42 #define STC3117_ADDR_VM_ADJ_H 0x1E 43 #define STC3117_ADDR_RAM 0x20 44 #define STC3117_ADDR_OCV_TABLE 0x30 45 #define STC3117_ADDR_SOC_TABLE 0x30 46 47 /* Bit mask definition */ 48 #define STC3117_ID 0x16 49 #define STC3117_MIXED_MODE 0x00 50 #define STC3117_VMODE BIT(0) 51 #define STC3117_GG_RUN BIT(4) 52 #define STC3117_CC_MODE BIT(5) 53 #define STC3117_BATFAIL BIT(3) 54 #define STC3117_PORDET BIT(4) 55 #define STC3117_RAM_SIZE 16 56 #define STC3117_OCV_TABLE_SIZE 16 57 #define STC3117_RAM_TESTWORD 0x53A9 58 #define STC3117_SOFT_RESET 0x11 59 #define STC3117_NOMINAL_CAPACITY 2600 60 61 #define VOLTAGE_LSB_VALUE 9011 62 #define CURRENT_LSB_VALUE 24084 63 #define APP_CUTOFF_VOLTAGE 2500 64 #define MAX_HRSOC 51200 65 #define MAX_SOC 1000 66 #define CHG_MIN_CURRENT 200 67 #define CHG_END_CURRENT 20 68 #define APP_MIN_CURRENT (-5) 69 #define BATTERY_FULL 95 70 #define CRC8_POLYNOMIAL 0x07 71 #define CRC8_INIT 0x00 72 73 DECLARE_CRC8_TABLE(stc3117_crc_table); 74 75 enum stc3117_state { 76 STC3117_INIT, 77 STC3117_RUNNING, 78 STC3117_POWERDN, 79 }; 80 81 /* Default ocv curve Li-ion battery */ 82 static const int ocv_value[16] = { 83 3400, 3582, 3669, 3676, 3699, 3737, 3757, 3774, 84 3804, 3844, 3936, 3984, 4028, 4131, 4246, 4320 85 }; 86 87 union stc3117_internal_ram { 88 u8 ram_bytes[STC3117_RAM_SIZE]; 89 struct { 90 u16 testword; /* 0-1 Bytes */ 91 u16 hrsoc; /* 2-3 Bytes */ 92 u16 cc_cnf; /* 4-5 Bytes */ 93 u16 vm_cnf; /* 6-7 Bytes */ 94 u8 soc; /* 8 Byte */ 95 u8 state; /* 9 Byte */ 96 u8 unused[5]; /* 10-14 Bytes */ 97 u8 crc; /* 15 Byte */ 98 } reg; 99 }; 100 101 struct stc3117_battery_info { 102 int voltage_min_mv; 103 int voltage_max_mv; 104 int battery_capacity_mah; 105 int sense_resistor; 106 }; 107 108 struct stc3117_data { 109 struct i2c_client *client; 110 struct regmap *regmap; 111 struct delayed_work update_work; 112 struct power_supply *battery; 113 union stc3117_internal_ram ram_data; 114 struct stc3117_battery_info battery_info; 115 116 u8 soc_tab[16]; 117 int cc_cnf; 118 int vm_cnf; 119 int cc_adj; 120 int vm_adj; 121 int avg_current; 122 int avg_voltage; 123 int batt_current; 124 int voltage; 125 int temp; 126 int soc; 127 int ocv; 128 int hrsoc; 129 int presence; 130 }; 131 132 static int stc3117_convert(int value, int factor) 133 { 134 value = (value * factor) / 4096; 135 return value * 1000; 136 } 137 138 static int stc3117_get_battery_data(struct stc3117_data *data) 139 { 140 u8 reg_list[16]; 141 u8 data_adjust[4]; 142 int value, mode; 143 144 regmap_bulk_read(data->regmap, STC3117_ADDR_MODE, 145 reg_list, sizeof(reg_list)); 146 147 /* soc */ 148 value = (reg_list[3] << 8) + reg_list[2]; 149 data->hrsoc = value; 150 data->soc = (value * 10 + 256) / 512; 151 152 /* current in uA*/ 153 value = (reg_list[7] << 8) + reg_list[6]; 154 data->batt_current = stc3117_convert(value, 155 CURRENT_LSB_VALUE / data->battery_info.sense_resistor); 156 157 /* voltage in uV */ 158 value = (reg_list[9] << 8) + reg_list[8]; 159 data->voltage = stc3117_convert(value, VOLTAGE_LSB_VALUE); 160 161 /* temp in 1/10 °C */ 162 data->temp = reg_list[10] * 10; 163 164 /* Avg current in uA */ 165 value = (reg_list[12] << 8) + reg_list[11]; 166 regmap_read(data->regmap, STC3117_ADDR_MODE, &mode); 167 if (!(mode & STC3117_VMODE)) { 168 value = stc3117_convert(value, 169 CURRENT_LSB_VALUE / data->battery_info.sense_resistor); 170 value = value / 4; 171 } else { 172 value = stc3117_convert(value, 36 * STC3117_NOMINAL_CAPACITY); 173 } 174 data->avg_current = value; 175 176 /* ocv in uV */ 177 value = (reg_list[14] << 8) + reg_list[13]; 178 value = stc3117_convert(value, VOLTAGE_LSB_VALUE); 179 value = (value + 2) / 4; 180 data->ocv = value; 181 182 /* CC & VM adjustment counters */ 183 regmap_bulk_read(data->regmap, STC3117_ADDR_CC_ADJ_L, 184 data_adjust, sizeof(data_adjust)); 185 value = (data_adjust[1] << 8) + data_adjust[0]; 186 data->cc_adj = value; 187 188 value = (data_adjust[3] << 8) + data_adjust[2]; 189 data->vm_adj = value; 190 191 return 0; 192 } 193 194 static int ram_write(struct stc3117_data *data) 195 { 196 int ret; 197 198 ret = regmap_bulk_write(data->regmap, STC3117_ADDR_RAM, 199 data->ram_data.ram_bytes, STC3117_RAM_SIZE); 200 if (ret) 201 return ret; 202 203 return 0; 204 }; 205 206 static int ram_read(struct stc3117_data *data) 207 { 208 int ret; 209 210 ret = regmap_bulk_read(data->regmap, STC3117_ADDR_RAM, 211 data->ram_data.ram_bytes, STC3117_RAM_SIZE); 212 if (ret) 213 return ret; 214 215 return 0; 216 }; 217 218 static int stc3117_set_para(struct stc3117_data *data) 219 { 220 int ret; 221 222 ret = regmap_write(data->regmap, STC3117_ADDR_MODE, STC3117_VMODE); 223 224 for (int i = 0; i < STC3117_OCV_TABLE_SIZE; i++) 225 ret |= regmap_write(data->regmap, STC3117_ADDR_OCV_TABLE + i, 226 ocv_value[i] * 100 / 55); 227 if (data->soc_tab[1] != 0) 228 ret |= regmap_bulk_write(data->regmap, STC3117_ADDR_SOC_TABLE, 229 data->soc_tab, STC3117_OCV_TABLE_SIZE); 230 231 ret |= regmap_write(data->regmap, STC3117_ADDR_CC_CNF_H, 232 (data->ram_data.reg.cc_cnf >> 8) & 0xFF); 233 234 ret |= regmap_write(data->regmap, STC3117_ADDR_CC_CNF_L, 235 data->ram_data.reg.cc_cnf & 0xFF); 236 237 ret |= regmap_write(data->regmap, STC3117_ADDR_VM_CNF_H, 238 (data->ram_data.reg.vm_cnf >> 8) & 0xFF); 239 240 ret |= regmap_write(data->regmap, STC3117_ADDR_VM_CNF_L, 241 data->ram_data.reg.vm_cnf & 0xFF); 242 243 ret |= regmap_write(data->regmap, STC3117_ADDR_CTRL, 0x03); 244 245 ret |= regmap_write(data->regmap, STC3117_ADDR_MODE, 246 STC3117_MIXED_MODE | STC3117_GG_RUN); 247 248 return ret; 249 }; 250 251 static int stc3117_init(struct stc3117_data *data) 252 { 253 int id, ret; 254 int ctrl; 255 int ocv_m, ocv_l; 256 257 regmap_read(data->regmap, STC3117_ADDR_ID, &id); 258 if (id != STC3117_ID) 259 return -EINVAL; 260 261 data->cc_cnf = (data->battery_info.battery_capacity_mah * 262 data->battery_info.sense_resistor * 250 + 6194) / 12389; 263 data->vm_cnf = (data->battery_info.battery_capacity_mah 264 * 200 * 50 + 24444) / 48889; 265 266 /* Battery has not been removed */ 267 data->presence = 1; 268 269 /* Read RAM data */ 270 ret = ram_read(data); 271 if (ret) 272 return ret; 273 274 if (data->ram_data.reg.testword != STC3117_RAM_TESTWORD || 275 (crc8(stc3117_crc_table, data->ram_data.ram_bytes, 276 STC3117_RAM_SIZE, CRC8_INIT)) != 0) { 277 data->ram_data.reg.testword = STC3117_RAM_TESTWORD; 278 data->ram_data.reg.cc_cnf = data->cc_cnf; 279 data->ram_data.reg.vm_cnf = data->vm_cnf; 280 data->ram_data.reg.crc = crc8(stc3117_crc_table, 281 data->ram_data.ram_bytes, 282 STC3117_RAM_SIZE - 1, CRC8_INIT); 283 284 ret = regmap_read(data->regmap, STC3117_ADDR_OCV_H, &ocv_m); 285 286 ret |= regmap_read(data->regmap, STC3117_ADDR_OCV_L, &ocv_l); 287 288 ret |= stc3117_set_para(data); 289 290 ret |= regmap_write(data->regmap, STC3117_ADDR_OCV_H, ocv_m); 291 292 ret |= regmap_write(data->regmap, STC3117_ADDR_OCV_L, ocv_l); 293 if (ret) 294 return ret; 295 } else { 296 ret = regmap_read(data->regmap, STC3117_ADDR_CTRL, &ctrl); 297 if (ret) 298 return ret; 299 300 if ((ctrl & STC3117_BATFAIL) != 0 || 301 (ctrl & STC3117_PORDET) != 0) { 302 ret = regmap_read(data->regmap, 303 STC3117_ADDR_OCV_H, &ocv_m); 304 305 ret |= regmap_read(data->regmap, 306 STC3117_ADDR_OCV_L, &ocv_l); 307 308 ret |= stc3117_set_para(data); 309 310 ret |= regmap_write(data->regmap, 311 STC3117_ADDR_OCV_H, ocv_m); 312 313 ret |= regmap_write(data->regmap, 314 STC3117_ADDR_OCV_L, ocv_l); 315 if (ret) 316 return ret; 317 } else { 318 ret = stc3117_set_para(data); 319 ret |= regmap_write(data->regmap, STC3117_ADDR_SOC_H, 320 (data->ram_data.reg.hrsoc >> 8 & 0xFF)); 321 ret |= regmap_write(data->regmap, STC3117_ADDR_SOC_L, 322 (data->ram_data.reg.hrsoc & 0xFF)); 323 if (ret) 324 return ret; 325 } 326 } 327 328 data->ram_data.reg.state = STC3117_INIT; 329 data->ram_data.reg.crc = crc8(stc3117_crc_table, 330 data->ram_data.ram_bytes, 331 STC3117_RAM_SIZE - 1, CRC8_INIT); 332 ret = ram_write(data); 333 if (ret) 334 return ret; 335 336 return 0; 337 }; 338 339 static int stc3117_task(struct stc3117_data *data) 340 { 341 int id, mode, ret; 342 int count_l, count_m; 343 int ocv_l, ocv_m; 344 345 regmap_read(data->regmap, STC3117_ADDR_ID, &id); 346 if (id != STC3117_ID) { 347 data->presence = 0; 348 return -EINVAL; 349 } 350 351 stc3117_get_battery_data(data); 352 353 /* Read RAM data */ 354 ret = ram_read(data); 355 if (ret) 356 return ret; 357 358 if (data->ram_data.reg.testword != STC3117_RAM_TESTWORD || 359 (crc8(stc3117_crc_table, data->ram_data.ram_bytes, 360 STC3117_RAM_SIZE, CRC8_INIT) != 0)) { 361 data->ram_data.reg.testword = STC3117_RAM_TESTWORD; 362 data->ram_data.reg.cc_cnf = data->cc_cnf; 363 data->ram_data.reg.vm_cnf = data->vm_cnf; 364 data->ram_data.reg.crc = crc8(stc3117_crc_table, 365 data->ram_data.ram_bytes, 366 STC3117_RAM_SIZE - 1, CRC8_INIT); 367 data->ram_data.reg.state = STC3117_INIT; 368 } 369 370 /* check battery presence status */ 371 ret = regmap_read(data->regmap, STC3117_ADDR_CTRL, &mode); 372 if ((mode & STC3117_BATFAIL) != 0) { 373 data->presence = 0; 374 data->ram_data.reg.testword = 0; 375 data->ram_data.reg.state = STC3117_INIT; 376 ret = ram_write(data); 377 ret |= regmap_write(data->regmap, STC3117_ADDR_CTRL, STC3117_PORDET); 378 if (ret) 379 return ret; 380 } 381 382 data->presence = 1; 383 384 ret = regmap_read(data->regmap, STC3117_ADDR_MODE, &mode); 385 if (ret) 386 return ret; 387 if ((mode & STC3117_GG_RUN) == 0) { 388 if (data->ram_data.reg.state > STC3117_INIT) { 389 ret = stc3117_set_para(data); 390 391 ret |= regmap_write(data->regmap, STC3117_ADDR_SOC_H, 392 (data->ram_data.reg.hrsoc >> 8 & 0xFF)); 393 ret |= regmap_write(data->regmap, STC3117_ADDR_SOC_L, 394 (data->ram_data.reg.hrsoc & 0xFF)); 395 if (ret) 396 return ret; 397 } else { 398 ret = regmap_read(data->regmap, STC3117_ADDR_OCV_H, &ocv_m); 399 400 ret |= regmap_read(data->regmap, STC3117_ADDR_OCV_L, &ocv_l); 401 402 ret |= stc3117_set_para(data); 403 404 ret |= regmap_write(data->regmap, STC3117_ADDR_OCV_H, ocv_m); 405 406 ret |= regmap_write(data->regmap, STC3117_ADDR_OCV_L, ocv_l); 407 if (ret) 408 return ret; 409 } 410 data->ram_data.reg.state = STC3117_INIT; 411 } 412 413 regmap_read(data->regmap, STC3117_ADDR_COUNTER_L, &count_l); 414 regmap_read(data->regmap, STC3117_ADDR_COUNTER_H, &count_m); 415 416 count_m = (count_m << 8) + count_l; 417 418 /* INIT state, wait for batt_current & temperature value available: */ 419 if (data->ram_data.reg.state == STC3117_INIT && count_m > 4) { 420 data->avg_voltage = data->voltage; 421 data->avg_current = data->batt_current; 422 data->ram_data.reg.state = STC3117_RUNNING; 423 } 424 425 if (data->ram_data.reg.state != STC3117_RUNNING) { 426 data->batt_current = -ENODATA; 427 data->temp = -ENODATA; 428 } else { 429 if (data->voltage < APP_CUTOFF_VOLTAGE) 430 data->soc = -ENODATA; 431 432 if (mode & STC3117_VMODE) { 433 data->avg_current = -ENODATA; 434 data->batt_current = -ENODATA; 435 } 436 } 437 438 data->ram_data.reg.hrsoc = data->hrsoc; 439 data->ram_data.reg.soc = (data->soc + 5) / 10; 440 data->ram_data.reg.crc = crc8(stc3117_crc_table, 441 data->ram_data.ram_bytes, 442 STC3117_RAM_SIZE - 1, CRC8_INIT); 443 444 ret = ram_write(data); 445 if (ret) 446 return ret; 447 return 0; 448 }; 449 450 static void fuel_gauge_update_work(struct work_struct *work) 451 { 452 struct stc3117_data *data = 453 container_of(work, struct stc3117_data, update_work.work); 454 455 stc3117_task(data); 456 457 /* Schedule the work to run again in 2 seconds */ 458 schedule_delayed_work(&data->update_work, msecs_to_jiffies(2000)); 459 } 460 461 static int stc3117_get_property(struct power_supply *psy, 462 enum power_supply_property psp, union power_supply_propval *val) 463 { 464 struct stc3117_data *data = power_supply_get_drvdata(psy); 465 466 switch (psp) { 467 case POWER_SUPPLY_PROP_STATUS: 468 if (data->soc > BATTERY_FULL) 469 val->intval = POWER_SUPPLY_STATUS_FULL; 470 else if (data->batt_current < 0) 471 val->intval = POWER_SUPPLY_STATUS_CHARGING; 472 else if (data->batt_current > 0) 473 val->intval = POWER_SUPPLY_STATUS_DISCHARGING; 474 else 475 val->intval = POWER_SUPPLY_STATUS_NOT_CHARGING; 476 break; 477 case POWER_SUPPLY_PROP_VOLTAGE_NOW: 478 val->intval = data->voltage; 479 break; 480 case POWER_SUPPLY_PROP_CURRENT_NOW: 481 val->intval = data->batt_current; 482 break; 483 case POWER_SUPPLY_PROP_VOLTAGE_OCV: 484 val->intval = data->ocv; 485 break; 486 case POWER_SUPPLY_PROP_CURRENT_AVG: 487 val->intval = data->avg_current; 488 break; 489 case POWER_SUPPLY_PROP_CAPACITY: 490 val->intval = data->soc; 491 break; 492 case POWER_SUPPLY_PROP_TEMP: 493 val->intval = data->temp; 494 break; 495 case POWER_SUPPLY_PROP_PRESENT: 496 val->intval = data->presence; 497 break; 498 default: 499 return -EINVAL; 500 } 501 return 0; 502 } 503 504 static enum power_supply_property stc3117_battery_props[] = { 505 POWER_SUPPLY_PROP_STATUS, 506 POWER_SUPPLY_PROP_VOLTAGE_NOW, 507 POWER_SUPPLY_PROP_CURRENT_NOW, 508 POWER_SUPPLY_PROP_VOLTAGE_OCV, 509 POWER_SUPPLY_PROP_CURRENT_AVG, 510 POWER_SUPPLY_PROP_CAPACITY, 511 POWER_SUPPLY_PROP_TEMP, 512 POWER_SUPPLY_PROP_PRESENT, 513 }; 514 515 static const struct power_supply_desc stc3117_battery_desc = { 516 .name = "stc3117-battery", 517 .type = POWER_SUPPLY_TYPE_BATTERY, 518 .get_property = stc3117_get_property, 519 .properties = stc3117_battery_props, 520 .num_properties = ARRAY_SIZE(stc3117_battery_props), 521 }; 522 523 static const struct regmap_config stc3117_regmap_config = { 524 .reg_bits = 8, 525 .val_bits = 8, 526 }; 527 528 static int stc3117_probe(struct i2c_client *client) 529 { 530 struct stc3117_data *data; 531 struct power_supply_config psy_cfg = {}; 532 struct power_supply_battery_info *info; 533 int ret; 534 535 data = devm_kzalloc(&client->dev, sizeof(*data), GFP_KERNEL); 536 if (!data) 537 return -ENOMEM; 538 539 data->client = client; 540 data->regmap = devm_regmap_init_i2c(client, &stc3117_regmap_config); 541 if (IS_ERR(data->regmap)) 542 return PTR_ERR(data->regmap); 543 544 psy_cfg.drv_data = data; 545 psy_cfg.fwnode = dev_fwnode(&client->dev); 546 547 crc8_populate_msb(stc3117_crc_table, CRC8_POLYNOMIAL); 548 549 data->battery = devm_power_supply_register(&client->dev, 550 &stc3117_battery_desc, &psy_cfg); 551 if (IS_ERR(data->battery)) 552 return dev_err_probe(&client->dev, PTR_ERR(data->battery), 553 "failed to register battery\n"); 554 555 ret = device_property_read_u32(&client->dev, "shunt-resistor-micro-ohms", 556 &data->battery_info.sense_resistor); 557 if (ret) 558 return dev_err_probe(&client->dev, ret, 559 "failed to get shunt-resistor-micro-ohms\n"); 560 data->battery_info.sense_resistor = data->battery_info.sense_resistor / 1000; 561 562 ret = power_supply_get_battery_info(data->battery, &info); 563 if (ret) 564 return dev_err_probe(&client->dev, ret, 565 "failed to get battery information\n"); 566 567 data->battery_info.battery_capacity_mah = info->charge_full_design_uah / 1000; 568 data->battery_info.voltage_min_mv = info->voltage_min_design_uv / 1000; 569 data->battery_info.voltage_max_mv = info->voltage_max_design_uv / 1000; 570 571 ret = stc3117_init(data); 572 if (ret) 573 return dev_err_probe(&client->dev, ret, 574 "failed to initialize of stc3117\n"); 575 576 ret = devm_delayed_work_autocancel(&client->dev, &data->update_work, 577 fuel_gauge_update_work); 578 if (ret) 579 return ret; 580 581 schedule_delayed_work(&data->update_work, 0); 582 583 return 0; 584 } 585 586 static const struct i2c_device_id stc3117_id[] = { 587 { "stc3117", 0 }, 588 { } 589 }; 590 MODULE_DEVICE_TABLE(i2c, stc3117_id); 591 592 static const struct of_device_id stc3117_of_match[] = { 593 { .compatible = "st,stc3117" }, 594 { } 595 }; 596 MODULE_DEVICE_TABLE(of, stc3117_of_match); 597 598 static struct i2c_driver stc3117_i2c_driver = { 599 .driver = { 600 .name = "stc3117_i2c_driver", 601 .of_match_table = stc3117_of_match, 602 }, 603 .probe = stc3117_probe, 604 .id_table = stc3117_id, 605 }; 606 607 module_i2c_driver(stc3117_i2c_driver); 608 609 MODULE_LICENSE("GPL"); 610 MODULE_AUTHOR("Hardevsinh Palaniya <hardevsinh.palaniya@siliconsignals.io>"); 611 MODULE_AUTHOR("Bhavin Sharma <bhavin.sharma@siliconsignals.io>"); 612 MODULE_DESCRIPTION("STC3117 Fuel Gauge Driver"); 613