1 // SPDX-License-Identifier: GPL-2.0+ 2 /* 3 * Battery monitor driver for the uPI uG3105 battery monitor 4 * 5 * Note the uG3105 is not a full-featured autonomous fuel-gauge. Instead it is 6 * expected to be use in combination with some always on microcontroller reading 7 * its coulomb-counter before it can wrap (must be read every 400 seconds!). 8 * 9 * Since Linux does not monitor coulomb-counter changes while the device 10 * is off or suspended, the coulomb counter is not used atm. 11 * 12 * Possible improvements: 13 * 1. Add coulumb counter reading, e.g. something like this: 14 * Read + reset coulomb counter every 10 polls (every 300 seconds) 15 * 16 * if ((chip->poll_count % 10) == 0) { 17 * val = ug3105_read_word(chip->client, UG3105_REG_COULOMB_CNT); 18 * if (val < 0) 19 * goto out; 20 * 21 * i2c_smbus_write_byte_data(chip->client, UG3105_REG_CTRL1, 22 * UG3105_CTRL1_RESET_COULOMB_CNT); 23 * 24 * chip->total_coulomb_count += (s16)val; 25 * dev_dbg(&chip->client->dev, "coulomb count %d total %d\n", 26 * (s16)val, chip->total_coulomb_count); 27 * } 28 * 29 * 2. Reset total_coulomb_count val to 0 when the battery is as good as empty 30 * and remember that we did this (and clear the flag for this on susp/resume) 31 * 3. When the battery is full check if the flag that we set total_coulomb_count 32 * to when the battery was empty is set. If so we now know the capacity, 33 * not the design, but actual capacity, of the battery 34 * 4. Add some mechanism (needs userspace help, or maybe use efivar?) to remember 35 * the actual capacity of the battery over reboots 36 * 5. When we know the actual capacity at probe time, add energy_now and 37 * energy_full attributes. Guess boot + resume energy_now value based on ocv 38 * and then use total_coulomb_count to report energy_now over time, resetting 39 * things to adjust for drift when empty/full. This should give more accurate 40 * readings, esp. in the 30-70% range and allow userspace to estimate time 41 * remaining till empty/full 42 * 6. Maybe unregister + reregister the psy device when we learn the actual 43 * capacity during run-time ? 44 * 45 * The above will also require some sort of mwh_per_unit calculation. Testing 46 * has shown that an estimated 7404mWh increase of the battery's energy results 47 * in a total_coulomb_count increase of 3277 units with a 5 milli-ohm sense R. 48 * 49 * Copyright (C) 2021 - 2025 Hans de Goede <hansg@kernel.org> 50 */ 51 52 #include <linux/module.h> 53 #include <linux/slab.h> 54 #include <linux/i2c.h> 55 #include <linux/mod_devicetable.h> 56 #include <linux/power_supply.h> 57 58 #include "adc-battery-helper.h" 59 60 #define UG3105_REG_MODE 0x00 61 #define UG3105_REG_CTRL1 0x01 62 #define UG3105_REG_COULOMB_CNT 0x02 63 #define UG3105_REG_BAT_VOLT 0x08 64 #define UG3105_REG_BAT_CURR 0x0c 65 66 #define UG3105_MODE_STANDBY 0x00 67 #define UG3105_MODE_RUN 0x10 68 69 #define UG3105_CTRL1_RESET_COULOMB_CNT 0x03 70 71 struct ug3105_chip { 72 /* Must be the first member see adc-battery-helper documentation */ 73 struct adc_battery_helper helper; 74 struct i2c_client *client; 75 struct power_supply *psy; 76 int uv_per_unit; 77 int ua_per_unit; 78 }; 79 80 static int ug3105_read_word(struct i2c_client *client, u8 reg) 81 { 82 int val; 83 84 val = i2c_smbus_read_word_data(client, reg); 85 if (val < 0) 86 dev_err(&client->dev, "Error reading reg 0x%02x\n", reg); 87 88 return val; 89 } 90 91 static int ug3105_get_voltage_and_current_now(struct power_supply *psy, int *volt, int *curr) 92 { 93 struct ug3105_chip *chip = power_supply_get_drvdata(psy); 94 int ret; 95 96 ret = ug3105_read_word(chip->client, UG3105_REG_BAT_VOLT); 97 if (ret < 0) 98 return ret; 99 100 *volt = ret * chip->uv_per_unit; 101 102 ret = ug3105_read_word(chip->client, UG3105_REG_BAT_CURR); 103 if (ret < 0) 104 return ret; 105 106 *curr = (s16)ret * chip->ua_per_unit; 107 return 0; 108 } 109 110 static const struct power_supply_desc ug3105_psy_desc = { 111 .name = "ug3105_battery", 112 .type = POWER_SUPPLY_TYPE_BATTERY, 113 .get_property = adc_battery_helper_get_property, 114 .external_power_changed = adc_battery_helper_external_power_changed, 115 .properties = adc_battery_helper_properties, 116 .num_properties = ADC_HELPER_NUM_PROPERTIES, 117 }; 118 119 static void ug3105_start(struct i2c_client *client) 120 { 121 i2c_smbus_write_byte_data(client, UG3105_REG_MODE, UG3105_MODE_RUN); 122 i2c_smbus_write_byte_data(client, UG3105_REG_CTRL1, UG3105_CTRL1_RESET_COULOMB_CNT); 123 } 124 125 static void ug3105_stop(struct i2c_client *client) 126 { 127 i2c_smbus_write_byte_data(client, UG3105_REG_MODE, UG3105_MODE_STANDBY); 128 } 129 130 static int ug3105_probe(struct i2c_client *client) 131 { 132 struct power_supply_config psy_cfg = {}; 133 struct device *dev = &client->dev; 134 u32 curr_sense_res_uohm = 10000; 135 struct ug3105_chip *chip; 136 int ret; 137 138 chip = devm_kzalloc(dev, sizeof(*chip), GFP_KERNEL); 139 if (!chip) 140 return -ENOMEM; 141 142 chip->client = client; 143 144 ug3105_start(client); 145 146 device_property_read_u32(dev, "upisemi,rsns-microohm", &curr_sense_res_uohm); 147 148 /* 149 * DAC maximum is 4.5V divided by 65536 steps + an unknown factor of 10 150 * coming from somewhere for some reason (verified with a volt-meter). 151 */ 152 chip->uv_per_unit = 45000000 / 65536; 153 /* Datasheet says 8.1 uV per unit for the current ADC */ 154 chip->ua_per_unit = 8100000 / curr_sense_res_uohm; 155 156 psy_cfg.drv_data = chip; 157 chip->psy = devm_power_supply_register(dev, &ug3105_psy_desc, &psy_cfg); 158 if (IS_ERR(chip->psy)) { 159 ret = PTR_ERR(chip->psy); 160 goto stop; 161 } 162 163 ret = adc_battery_helper_init(&chip->helper, chip->psy, 164 ug3105_get_voltage_and_current_now, NULL); 165 if (ret) 166 goto stop; 167 168 i2c_set_clientdata(client, chip); 169 return 0; 170 171 stop: 172 ug3105_stop(client); 173 return ret; 174 } 175 176 static int __maybe_unused ug3105_suspend(struct device *dev) 177 { 178 struct ug3105_chip *chip = dev_get_drvdata(dev); 179 180 adc_battery_helper_suspend(dev); 181 ug3105_stop(chip->client); 182 return 0; 183 } 184 185 static int __maybe_unused ug3105_resume(struct device *dev) 186 { 187 struct ug3105_chip *chip = dev_get_drvdata(dev); 188 189 ug3105_start(chip->client); 190 adc_battery_helper_resume(dev); 191 return 0; 192 } 193 194 static SIMPLE_DEV_PM_OPS(ug3105_pm_ops, ug3105_suspend, 195 ug3105_resume); 196 197 static const struct i2c_device_id ug3105_id[] = { 198 { "ug3105" }, 199 { } 200 }; 201 MODULE_DEVICE_TABLE(i2c, ug3105_id); 202 203 static struct i2c_driver ug3105_i2c_driver = { 204 .driver = { 205 .name = "ug3105", 206 .pm = &ug3105_pm_ops, 207 }, 208 .probe = ug3105_probe, 209 .remove = ug3105_stop, 210 .shutdown = ug3105_stop, 211 .id_table = ug3105_id, 212 }; 213 module_i2c_driver(ug3105_i2c_driver); 214 215 MODULE_AUTHOR("Hans de Goede <hansg@kernel.org"); 216 MODULE_DESCRIPTION("uPI uG3105 battery monitor driver"); 217 MODULE_LICENSE("GPL"); 218