Lines Matching +full:sbs +full:- +full:battery
1 // SPDX-License-Identifier: GPL-2.0-or-later
3 * Gas Gauge driver for SBS Compliant Batteries
10 #include <linux/devm-helpers.h>
20 #include <linux/power/sbs-battery.h>
66 /* Battery Mode defines */
79 /* battery status value bits */
102 SBS_DATA(-1, 0x03, 0, 65535),
108 SBS_DATA(POWER_SUPPLY_PROP_CURRENT_NOW, 0x0A, -32768, 32767),
110 SBS_DATA(POWER_SUPPLY_PROP_CURRENT_AVG, 0x0B, -32768, 32767),
228 return chip->strings[i]; in sbs_get_string_buf()
230 return ERR_PTR(-EINVAL); in sbs_get_string_buf()
237 chip->technology = -1; in sbs_invalidate_cached_props()
240 chip->strings[i][0] = 0; in sbs_invalidate_cached_props()
250 int val = sbs_read_word_data(chip->client, BATTERY_MODE_OFFSET); in sbs_disable_charger_broadcasts()
256 val = sbs_write_word_data(chip->client, BATTERY_MODE_OFFSET, val); in sbs_disable_charger_broadcasts()
260 dev_err(&chip->client->dev, in sbs_disable_charger_broadcasts()
263 dev_dbg(&chip->client->dev, "%s\n", __func__); in sbs_disable_charger_broadcasts()
268 struct i2c_client *client = chip->client; in sbs_update_presence()
269 int retries = chip->i2c_retry_count; in sbs_update_presence()
273 if (chip->is_present == is_present) in sbs_update_presence()
277 chip->is_present = false; in sbs_update_presence()
279 client->flags &= ~I2C_CLIENT_PEC; in sbs_update_presence()
297 retries--; in sbs_update_presence()
301 dev_dbg(&client->dev, "failed to read spec info: %d\n", ret); in sbs_update_presence()
304 client->flags &= ~I2C_CLIENT_PEC; in sbs_update_presence()
305 chip->is_present = true; in sbs_update_presence()
313 client->flags |= I2C_CLIENT_PEC; in sbs_update_presence()
315 client->flags &= ~I2C_CLIENT_PEC; in sbs_update_presence()
317 if (of_device_is_compatible(client->dev.parent->of_node, "google,cros-ec-i2c-tunnel") in sbs_update_presence()
318 && client->flags & I2C_CLIENT_PEC) { in sbs_update_presence()
319 dev_info(&client->dev, "Disabling PEC because of broken Cros-EC implementation\n"); in sbs_update_presence()
320 client->flags &= ~I2C_CLIENT_PEC; in sbs_update_presence()
323 dev_dbg(&client->dev, "PEC: %s\n", (client->flags & I2C_CLIENT_PEC) ? in sbs_update_presence()
326 if (!chip->is_present && is_present && !chip->charger_broadcasts) in sbs_update_presence()
329 chip->is_present = true; in sbs_update_presence()
337 int retries = chip->i2c_retry_count; in sbs_read_word_data()
344 retries--; in sbs_read_word_data()
348 dev_dbg(&client->dev, in sbs_read_word_data()
364 retries_length = chip->i2c_retry_count; in sbs_read_string_data_fallback()
365 retries_block = chip->i2c_retry_count; in sbs_read_string_data_fallback()
367 dev_warn_once(&client->dev, "I2C adapter does not support I2C_FUNC_SMBUS_READ_BLOCK_DATA.\n" in sbs_read_string_data_fallback()
371 if (!i2c_check_functionality(client->adapter, in sbs_read_string_data_fallback()
374 return -ENODEV; in sbs_read_string_data_fallback()
382 retries_length--; in sbs_read_string_data_fallback()
386 dev_dbg(&client->dev, in sbs_read_string_data_fallback()
395 dev_err(&client->dev, in sbs_read_string_data_fallback()
398 return -EINVAL; in sbs_read_string_data_fallback()
408 retries_block--; in sbs_read_string_data_fallback()
412 dev_dbg(&client->dev, in sbs_read_string_data_fallback()
428 int retries = chip->i2c_retry_count; in sbs_read_string_data()
431 if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_READ_BLOCK_DATA)) { in sbs_read_string_data()
432 bool pec = client->flags & I2C_CLIENT_PEC; in sbs_read_string_data()
433 client->flags &= ~I2C_CLIENT_PEC; in sbs_read_string_data()
436 client->flags |= I2C_CLIENT_PEC; in sbs_read_string_data()
444 retries--; in sbs_read_string_data()
448 dev_dbg(&client->dev, "failed to read block 0x%x: %d\n", address, ret); in sbs_read_string_data()
461 int retries = chip->i2c_retry_count; in sbs_write_word_data()
468 retries--; in sbs_write_word_data()
472 dev_dbg(&client->dev, in sbs_write_word_data()
491 /* Not drawing current -> not charging (i.e. idle) */ in sbs_status_correct()
531 val->intval = 0; /* battery removed */ in sbs_get_ti_battery_presence_and_health()
538 val->intval = 0; /* battery removed */ in sbs_get_ti_battery_presence_and_health()
544 val->intval = 0; in sbs_get_ti_battery_presence_and_health()
555 /* battery removed */ in sbs_get_ti_battery_presence_and_health()
556 val->intval = 0; in sbs_get_ti_battery_presence_and_health()
558 val->intval = 1; in sbs_get_ti_battery_presence_and_health()
561 val->intval = POWER_SUPPLY_HEALTH_UNSPEC_FAILURE; in sbs_get_ti_battery_presence_and_health()
563 val->intval = POWER_SUPPLY_HEALTH_OVERHEAT; in sbs_get_ti_battery_presence_and_health()
565 val->intval = POWER_SUPPLY_HEALTH_DEAD; in sbs_get_ti_battery_presence_and_health()
567 val->intval = POWER_SUPPLY_HEALTH_CALIBRATION_REQUIRED; in sbs_get_ti_battery_presence_and_health()
569 val->intval = POWER_SUPPLY_HEALTH_GOOD; in sbs_get_ti_battery_presence_and_health()
582 if (chip->flags & SBS_FLAGS_TI_BQ20ZX5) in sbs_get_battery_presence_and_health()
585 /* Dummy command; if it succeeds, battery is present. */ in sbs_get_battery_presence_and_health()
588 if (ret < 0) { /* battery not present*/ in sbs_get_battery_presence_and_health()
590 val->intval = 0; in sbs_get_battery_presence_and_health()
597 val->intval = 1; /* battery present */ in sbs_get_battery_presence_and_health()
600 val->intval = POWER_SUPPLY_HEALTH_CALIBRATION_REQUIRED; in sbs_get_battery_presence_and_health()
602 /* SBS spec doesn't have a general health command. */ in sbs_get_battery_presence_and_health()
603 val->intval = POWER_SUPPLY_HEALTH_UNKNOWN; in sbs_get_battery_presence_and_health()
627 val->intval = ret; in sbs_get_battery_property()
630 val->intval = in sbs_get_battery_property()
633 val->intval = in sbs_get_battery_property()
636 val->intval = in sbs_get_battery_property()
639 val->intval = in sbs_get_battery_property()
647 val->intval = POWER_SUPPLY_STATUS_FULL; in sbs_get_battery_property()
649 val->intval = POWER_SUPPLY_STATUS_DISCHARGING; in sbs_get_battery_property()
651 val->intval = POWER_SUPPLY_STATUS_CHARGING; in sbs_get_battery_property()
653 sbs_status_correct(client, &val->intval); in sbs_get_battery_property()
655 if (chip->poll_time == 0) in sbs_get_battery_property()
656 chip->last_state = val->intval; in sbs_get_battery_property()
657 else if (chip->last_state != val->intval) { in sbs_get_battery_property()
658 cancel_delayed_work_sync(&chip->work); in sbs_get_battery_property()
659 power_supply_changed(chip->power_supply); in sbs_get_battery_property()
660 chip->poll_time = 0; in sbs_get_battery_property()
664 val->intval = POWER_SUPPLY_STATUS_UNKNOWN; in sbs_get_battery_property()
666 /* sbs spec says that this can be >100 % in sbs_get_battery_property()
669 val->intval = min(ret, 100); in sbs_get_battery_property()
671 val->intval = 0; in sbs_get_battery_property()
686 dev_warn(&client->dev, in sbs_get_property_index()
687 "%s: Invalid Property - %d\n", __func__, psp); in sbs_get_property_index()
689 return -EINVAL; in sbs_get_property_index()
704 ret = sbs_get_property_index(chip->client, psp); in sbs_get_constant_string()
710 ret = sbs_read_string_data(chip->client, addr, buf); in sbs_get_constant_string()
729 /* sbs provides energy in units of 10mWh. in sbs_unit_adjustment()
732 val->intval *= BATTERY_MODE_CAP_MULT_WATT; in sbs_unit_adjustment()
745 val->intval *= BASE_UNIT_CONVERSION; in sbs_unit_adjustment()
749 /* sbs provides battery temperature in 0.1K in sbs_unit_adjustment()
752 val->intval -= TEMP_KELVIN_TO_CELSIUS; in sbs_unit_adjustment()
758 /* sbs provides time to empty and time to full in minutes. in sbs_unit_adjustment()
761 val->intval *= TIME_UNIT_CONVERSION; in sbs_unit_adjustment()
765 dev_dbg(&client->dev, in sbs_unit_adjustment()
814 val->intval = ret; in sbs_get_battery_capacity()
834 val->strval = sbs_serial; in sbs_get_battery_serial_number()
844 if (chip->technology != -1) { in sbs_get_chemistry()
845 val->intval = chip->technology; in sbs_get_chemistry()
855 chip->technology = POWER_SUPPLY_TECHNOLOGY_LION; in sbs_get_chemistry()
857 chip->technology = POWER_SUPPLY_TECHNOLOGY_LIPO; in sbs_get_chemistry()
859 chip->technology = POWER_SUPPLY_TECHNOLOGY_NiCd; in sbs_get_chemistry()
861 chip->technology = POWER_SUPPLY_TECHNOLOGY_NiMH; in sbs_get_chemistry()
863 chip->technology = POWER_SUPPLY_TECHNOLOGY_UNKNOWN; in sbs_get_chemistry()
865 if (chip->technology == POWER_SUPPLY_TECHNOLOGY_UNKNOWN) in sbs_get_chemistry()
866 dev_warn(&chip->client->dev, "Unknown chemistry: %s\n", chemistry); in sbs_get_chemistry()
868 val->intval = chip->technology; in sbs_get_chemistry()
890 val->intval = year; in sbs_get_battery_manufacture_date()
893 val->intval = month; in sbs_get_battery_manufacture_date()
896 val->intval = day; in sbs_get_battery_manufacture_date()
899 return -EINVAL; in sbs_get_battery_manufacture_date()
911 struct i2c_client *client = chip->client; in sbs_get_property()
914 if (chip->gpio_detect) { in sbs_get_property()
915 ret = gpiod_get_value_cansleep(chip->gpio_detect); in sbs_get_property()
919 val->intval = ret; in sbs_get_property()
924 return -ENODATA; in sbs_get_property()
954 /* sbs_get_battery_capacity() will change the battery mode in sbs_get_property()
958 mutex_lock(&chip->mode_lock); in sbs_get_property()
960 mutex_unlock(&chip->mode_lock); in sbs_get_property()
996 val->strval = str; in sbs_get_property()
1006 dev_err(&client->dev, in sbs_get_property()
1008 return -EINVAL; in sbs_get_property()
1011 if (!chip->gpio_detect && chip->is_present != (ret >= 0)) { in sbs_get_property()
1012 bool old_present = chip->is_present; in sbs_get_property()
1019 if (old_present != chip->is_present) in sbs_get_property()
1020 power_supply_changed(chip->power_supply); in sbs_get_property()
1027 dev_dbg(&client->dev, in sbs_get_property()
1029 psp, val->intval); in sbs_get_property()
1030 } else if (!chip->is_present) { in sbs_get_property()
1031 /* battery not present, so return NODATA for properties */ in sbs_get_property()
1032 ret = -ENODATA; in sbs_get_property()
1039 struct power_supply *battery = chip->power_supply; in sbs_supply_changed() local
1042 ret = gpiod_get_value_cansleep(chip->gpio_detect); in sbs_supply_changed()
1046 power_supply_changed(battery); in sbs_supply_changed()
1066 cancel_delayed_work_sync(&chip->work); in sbs_external_power_changed()
1068 schedule_delayed_work(&chip->work, HZ); in sbs_external_power_changed()
1069 chip->poll_time = chip->poll_retry_count; in sbs_external_power_changed()
1079 ret = sbs_read_word_data(chip->client, sbs_data[REG_STATUS].addr); in sbs_delayed_work()
1082 chip->poll_time = 0; in sbs_delayed_work()
1093 sbs_status_correct(chip->client, &ret); in sbs_delayed_work()
1095 if (chip->last_state != ret) { in sbs_delayed_work()
1096 chip->poll_time = 0; in sbs_delayed_work()
1097 power_supply_changed(chip->power_supply); in sbs_delayed_work()
1100 if (chip->poll_time > 0) { in sbs_delayed_work()
1101 schedule_delayed_work(&chip->work, HZ); in sbs_delayed_work()
1102 chip->poll_time--; in sbs_delayed_work()
1119 struct sbs_platform_data *pdata = client->dev.platform_data; in sbs_probe()
1124 sbs_desc = devm_kmemdup(&client->dev, &sbs_default_desc, in sbs_probe()
1127 return -ENOMEM; in sbs_probe()
1129 sbs_desc->name = devm_kasprintf(&client->dev, GFP_KERNEL, "sbs-%s", in sbs_probe()
1130 dev_name(&client->dev)); in sbs_probe()
1131 if (!sbs_desc->name) in sbs_probe()
1132 return -ENOMEM; in sbs_probe()
1134 chip = devm_kzalloc(&client->dev, sizeof(struct sbs_info), GFP_KERNEL); in sbs_probe()
1136 return -ENOMEM; in sbs_probe()
1138 chip->flags = (uintptr_t)i2c_get_match_data(client); in sbs_probe()
1139 chip->client = client; in sbs_probe()
1140 psy_cfg.of_node = client->dev.of_node; in sbs_probe()
1142 chip->last_state = POWER_SUPPLY_STATUS_UNKNOWN; in sbs_probe()
1144 mutex_init(&chip->mode_lock); in sbs_probe()
1149 rc = device_property_read_u32(&client->dev, "sbs,i2c-retry-count", in sbs_probe()
1150 &chip->i2c_retry_count); in sbs_probe()
1152 chip->i2c_retry_count = 0; in sbs_probe()
1154 rc = device_property_read_u32(&client->dev, "sbs,poll-retry-count", in sbs_probe()
1155 &chip->poll_retry_count); in sbs_probe()
1157 chip->poll_retry_count = 0; in sbs_probe()
1160 chip->poll_retry_count = pdata->poll_retry_count; in sbs_probe()
1161 chip->i2c_retry_count = pdata->i2c_retry_count; in sbs_probe()
1163 chip->i2c_retry_count = chip->i2c_retry_count + 1; in sbs_probe()
1165 chip->charger_broadcasts = !device_property_read_bool(&client->dev, in sbs_probe()
1166 "sbs,disable-charger-broadcasts"); in sbs_probe()
1168 chip->gpio_detect = devm_gpiod_get_optional(&client->dev, in sbs_probe()
1169 "sbs,battery-detect", GPIOD_IN); in sbs_probe()
1170 if (IS_ERR(chip->gpio_detect)) in sbs_probe()
1171 return dev_err_probe(&client->dev, PTR_ERR(chip->gpio_detect), in sbs_probe()
1176 if (!chip->gpio_detect) in sbs_probe()
1179 irq = gpiod_to_irq(chip->gpio_detect); in sbs_probe()
1181 dev_warn(&client->dev, "Failed to get gpio as irq: %d\n", irq); in sbs_probe()
1185 rc = devm_request_threaded_irq(&client->dev, irq, NULL, sbs_irq, in sbs_probe()
1187 dev_name(&client->dev), chip); in sbs_probe()
1189 dev_warn(&client->dev, "Failed to request irq: %d\n", rc); in sbs_probe()
1196 * to the battery. in sbs_probe()
1198 if (!(force_load || chip->gpio_detect)) { in sbs_probe()
1204 return dev_err_probe(&client->dev, -ENODEV, in sbs_probe()
1208 rc = devm_delayed_work_autocancel(&client->dev, &chip->work, in sbs_probe()
1213 chip->power_supply = devm_power_supply_register(&client->dev, sbs_desc, in sbs_probe()
1215 if (IS_ERR(chip->power_supply)) in sbs_probe()
1216 return dev_err_probe(&client->dev, PTR_ERR(chip->power_supply), in sbs_probe()
1219 dev_info(&client->dev, in sbs_probe()
1220 "%s: battery gas gauge device registered\n", client->name); in sbs_probe()
1233 if (chip->poll_time > 0) in sbs_suspend()
1234 cancel_delayed_work_sync(&chip->work); in sbs_suspend()
1236 if (chip->flags & SBS_FLAGS_TI_BQ20ZX5) { in sbs_suspend()
1241 if (chip->is_present && ret < 0) in sbs_suspend()
1258 { "sbs-battery", 0 },
1264 { .compatible = "sbs,sbs-battery" },
1282 .name = "sbs-battery",
1289 MODULE_DESCRIPTION("SBS battery monitor driver");
1294 "Attempt to load the driver even if no battery is connected");