1*f059b46eSHans de Goede // SPDX-License-Identifier: GPL-2.0+ 2*f059b46eSHans de Goede /* 3*f059b46eSHans de Goede * Battery monitor driver for the uPI uG3105 battery monitor 4*f059b46eSHans de Goede * 5*f059b46eSHans de Goede * Note the uG3105 is not a full-featured autonomous fuel-gauge. Instead it is 6*f059b46eSHans de Goede * expected to be use in combination with some always on microcontroller reading 7*f059b46eSHans de Goede * its coulomb-counter before it can wrap (must be read every 400 seconds!). 8*f059b46eSHans de Goede * 9*f059b46eSHans de Goede * Since Linux does not monitor coulomb-counter changes while the device 10*f059b46eSHans de Goede * is off or suspended, the coulomb counter is not used atm. 11*f059b46eSHans de Goede * 12*f059b46eSHans de Goede * Possible improvements: 13*f059b46eSHans de Goede * 1. Activate commented out total_coulomb_count code 14*f059b46eSHans de Goede * 2. Reset total_coulomb_count val to 0 when the battery is as good as empty 15*f059b46eSHans de Goede * and remember that we did this (and clear the flag for this on susp/resume) 16*f059b46eSHans de Goede * 3. When the battery is full check if the flag that we set total_coulomb_count 17*f059b46eSHans de Goede * to when the battery was empty is set. If so we now know the capacity, 18*f059b46eSHans de Goede * not the design, but actual capacity, of the battery 19*f059b46eSHans de Goede * 4. Add some mechanism (needs userspace help, or maybe use efivar?) to remember 20*f059b46eSHans de Goede * the actual capacity of the battery over reboots 21*f059b46eSHans de Goede * 5. When we know the actual capacity at probe time, add energy_now and 22*f059b46eSHans de Goede * energy_full attributes. Guess boot + resume energy_now value based on ocv 23*f059b46eSHans de Goede * and then use total_coulomb_count to report energy_now over time, resetting 24*f059b46eSHans de Goede * things to adjust for drift when empty/full. This should give more accurate 25*f059b46eSHans de Goede * readings, esp. in the 30-70% range and allow userspace to estimate time 26*f059b46eSHans de Goede * remaining till empty/full 27*f059b46eSHans de Goede * 6. Maybe unregister + reregister the psy device when we learn the actual 28*f059b46eSHans de Goede * capacity during run-time ? 29*f059b46eSHans de Goede * 30*f059b46eSHans de Goede * The above will also require some sort of mwh_per_unit calculation. Testing 31*f059b46eSHans de Goede * has shown that an estimated 7404mWh increase of the battery's energy results 32*f059b46eSHans de Goede * in a total_coulomb_count increase of 3277 units with a 5 milli-ohm sense R. 33*f059b46eSHans de Goede * 34*f059b46eSHans de Goede * Copyright (C) 2021 Hans de Goede <hdegoede@redhat.com> 35*f059b46eSHans de Goede */ 36*f059b46eSHans de Goede 37*f059b46eSHans de Goede #include <linux/devm-helpers.h> 38*f059b46eSHans de Goede #include <linux/module.h> 39*f059b46eSHans de Goede #include <linux/mutex.h> 40*f059b46eSHans de Goede #include <linux/slab.h> 41*f059b46eSHans de Goede #include <linux/i2c.h> 42*f059b46eSHans de Goede #include <linux/mod_devicetable.h> 43*f059b46eSHans de Goede #include <linux/power_supply.h> 44*f059b46eSHans de Goede #include <linux/workqueue.h> 45*f059b46eSHans de Goede 46*f059b46eSHans de Goede #define UG3105_MOV_AVG_WINDOW 8 47*f059b46eSHans de Goede #define UG3105_INIT_POLL_TIME (5 * HZ) 48*f059b46eSHans de Goede #define UG3105_POLL_TIME (30 * HZ) 49*f059b46eSHans de Goede #define UG3105_SETTLE_TIME (1 * HZ) 50*f059b46eSHans de Goede 51*f059b46eSHans de Goede #define UG3105_INIT_POLL_COUNT 30 52*f059b46eSHans de Goede 53*f059b46eSHans de Goede #define UG3105_REG_MODE 0x00 54*f059b46eSHans de Goede #define UG3105_REG_CTRL1 0x01 55*f059b46eSHans de Goede #define UG3105_REG_COULOMB_CNT 0x02 56*f059b46eSHans de Goede #define UG3105_REG_BAT_VOLT 0x08 57*f059b46eSHans de Goede #define UG3105_REG_BAT_CURR 0x0c 58*f059b46eSHans de Goede 59*f059b46eSHans de Goede #define UG3105_MODE_STANDBY 0x00 60*f059b46eSHans de Goede #define UG3105_MODE_RUN 0x10 61*f059b46eSHans de Goede 62*f059b46eSHans de Goede #define UG3105_CTRL1_RESET_COULOMB_CNT 0x03 63*f059b46eSHans de Goede 64*f059b46eSHans de Goede #define UG3105_CURR_HYST_UA 65000 65*f059b46eSHans de Goede 66*f059b46eSHans de Goede #define UG3105_LOW_BAT_UV 3700000 67*f059b46eSHans de Goede #define UG3105_FULL_BAT_HYST_UV 38000 68*f059b46eSHans de Goede 69*f059b46eSHans de Goede struct ug3105_chip { 70*f059b46eSHans de Goede struct i2c_client *client; 71*f059b46eSHans de Goede struct power_supply *psy; 72*f059b46eSHans de Goede struct power_supply_battery_info *info; 73*f059b46eSHans de Goede struct delayed_work work; 74*f059b46eSHans de Goede struct mutex lock; 75*f059b46eSHans de Goede int ocv[UG3105_MOV_AVG_WINDOW]; /* micro-volt */ 76*f059b46eSHans de Goede int intern_res[UG3105_MOV_AVG_WINDOW]; /* milli-ohm */ 77*f059b46eSHans de Goede int poll_count; 78*f059b46eSHans de Goede int ocv_avg_index; 79*f059b46eSHans de Goede int ocv_avg; /* micro-volt */ 80*f059b46eSHans de Goede int intern_res_poll_count; 81*f059b46eSHans de Goede int intern_res_avg_index; 82*f059b46eSHans de Goede int intern_res_avg; /* milli-ohm */ 83*f059b46eSHans de Goede int volt; /* micro-volt */ 84*f059b46eSHans de Goede int curr; /* micro-ampere */ 85*f059b46eSHans de Goede int total_coulomb_count; 86*f059b46eSHans de Goede int uv_per_unit; 87*f059b46eSHans de Goede int ua_per_unit; 88*f059b46eSHans de Goede int status; 89*f059b46eSHans de Goede int capacity; 90*f059b46eSHans de Goede bool supplied; 91*f059b46eSHans de Goede }; 92*f059b46eSHans de Goede 93*f059b46eSHans de Goede static int ug3105_read_word(struct i2c_client *client, u8 reg) 94*f059b46eSHans de Goede { 95*f059b46eSHans de Goede int val; 96*f059b46eSHans de Goede 97*f059b46eSHans de Goede val = i2c_smbus_read_word_data(client, reg); 98*f059b46eSHans de Goede if (val < 0) 99*f059b46eSHans de Goede dev_err(&client->dev, "Error reading reg 0x%02x\n", reg); 100*f059b46eSHans de Goede 101*f059b46eSHans de Goede return val; 102*f059b46eSHans de Goede } 103*f059b46eSHans de Goede 104*f059b46eSHans de Goede static int ug3105_get_status(struct ug3105_chip *chip) 105*f059b46eSHans de Goede { 106*f059b46eSHans de Goede int full = chip->info->constant_charge_voltage_max_uv - UG3105_FULL_BAT_HYST_UV; 107*f059b46eSHans de Goede 108*f059b46eSHans de Goede if (chip->curr > UG3105_CURR_HYST_UA) 109*f059b46eSHans de Goede return POWER_SUPPLY_STATUS_CHARGING; 110*f059b46eSHans de Goede 111*f059b46eSHans de Goede if (chip->curr < -UG3105_CURR_HYST_UA) 112*f059b46eSHans de Goede return POWER_SUPPLY_STATUS_DISCHARGING; 113*f059b46eSHans de Goede 114*f059b46eSHans de Goede if (chip->supplied && chip->ocv_avg > full) 115*f059b46eSHans de Goede return POWER_SUPPLY_STATUS_FULL; 116*f059b46eSHans de Goede 117*f059b46eSHans de Goede return POWER_SUPPLY_STATUS_NOT_CHARGING; 118*f059b46eSHans de Goede } 119*f059b46eSHans de Goede 120*f059b46eSHans de Goede static int ug3105_get_capacity(struct ug3105_chip *chip) 121*f059b46eSHans de Goede { 122*f059b46eSHans de Goede /* 123*f059b46eSHans de Goede * OCV voltages in uV for 0-110% in 5% increments, the 100-110% is 124*f059b46eSHans de Goede * for LiPo HV (High-Voltage) bateries which can go up to 4.35V 125*f059b46eSHans de Goede * instead of the usual 4.2V. 126*f059b46eSHans de Goede */ 127*f059b46eSHans de Goede static const int ocv_capacity_tbl[23] = { 128*f059b46eSHans de Goede 3350000, 129*f059b46eSHans de Goede 3610000, 130*f059b46eSHans de Goede 3690000, 131*f059b46eSHans de Goede 3710000, 132*f059b46eSHans de Goede 3730000, 133*f059b46eSHans de Goede 3750000, 134*f059b46eSHans de Goede 3770000, 135*f059b46eSHans de Goede 3786667, 136*f059b46eSHans de Goede 3803333, 137*f059b46eSHans de Goede 3820000, 138*f059b46eSHans de Goede 3836667, 139*f059b46eSHans de Goede 3853333, 140*f059b46eSHans de Goede 3870000, 141*f059b46eSHans de Goede 3907500, 142*f059b46eSHans de Goede 3945000, 143*f059b46eSHans de Goede 3982500, 144*f059b46eSHans de Goede 4020000, 145*f059b46eSHans de Goede 4075000, 146*f059b46eSHans de Goede 4110000, 147*f059b46eSHans de Goede 4150000, 148*f059b46eSHans de Goede 4200000, 149*f059b46eSHans de Goede 4250000, 150*f059b46eSHans de Goede 4300000, 151*f059b46eSHans de Goede }; 152*f059b46eSHans de Goede int i, ocv_diff, ocv_step; 153*f059b46eSHans de Goede 154*f059b46eSHans de Goede if (chip->ocv_avg < ocv_capacity_tbl[0]) 155*f059b46eSHans de Goede return 0; 156*f059b46eSHans de Goede 157*f059b46eSHans de Goede if (chip->status == POWER_SUPPLY_STATUS_FULL) 158*f059b46eSHans de Goede return 100; 159*f059b46eSHans de Goede 160*f059b46eSHans de Goede for (i = 1; i < ARRAY_SIZE(ocv_capacity_tbl); i++) { 161*f059b46eSHans de Goede if (chip->ocv_avg > ocv_capacity_tbl[i]) 162*f059b46eSHans de Goede continue; 163*f059b46eSHans de Goede 164*f059b46eSHans de Goede ocv_diff = ocv_capacity_tbl[i] - chip->ocv_avg; 165*f059b46eSHans de Goede ocv_step = ocv_capacity_tbl[i] - ocv_capacity_tbl[i - 1]; 166*f059b46eSHans de Goede /* scale 0-110% down to 0-100% for LiPo HV */ 167*f059b46eSHans de Goede if (chip->info->constant_charge_voltage_max_uv >= 4300000) 168*f059b46eSHans de Goede return (i * 500 - ocv_diff * 500 / ocv_step) / 110; 169*f059b46eSHans de Goede else 170*f059b46eSHans de Goede return i * 5 - ocv_diff * 5 / ocv_step; 171*f059b46eSHans de Goede } 172*f059b46eSHans de Goede 173*f059b46eSHans de Goede return 100; 174*f059b46eSHans de Goede } 175*f059b46eSHans de Goede 176*f059b46eSHans de Goede static void ug3105_work(struct work_struct *work) 177*f059b46eSHans de Goede { 178*f059b46eSHans de Goede struct ug3105_chip *chip = container_of(work, struct ug3105_chip, 179*f059b46eSHans de Goede work.work); 180*f059b46eSHans de Goede int i, val, curr_diff, volt_diff, res, win_size; 181*f059b46eSHans de Goede bool prev_supplied = chip->supplied; 182*f059b46eSHans de Goede int prev_status = chip->status; 183*f059b46eSHans de Goede int prev_volt = chip->volt; 184*f059b46eSHans de Goede int prev_curr = chip->curr; 185*f059b46eSHans de Goede struct power_supply *psy; 186*f059b46eSHans de Goede 187*f059b46eSHans de Goede mutex_lock(&chip->lock); 188*f059b46eSHans de Goede 189*f059b46eSHans de Goede psy = chip->psy; 190*f059b46eSHans de Goede if (!psy) 191*f059b46eSHans de Goede goto out; 192*f059b46eSHans de Goede 193*f059b46eSHans de Goede val = ug3105_read_word(chip->client, UG3105_REG_BAT_VOLT); 194*f059b46eSHans de Goede if (val < 0) 195*f059b46eSHans de Goede goto out; 196*f059b46eSHans de Goede chip->volt = val * chip->uv_per_unit; 197*f059b46eSHans de Goede 198*f059b46eSHans de Goede val = ug3105_read_word(chip->client, UG3105_REG_BAT_CURR); 199*f059b46eSHans de Goede if (val < 0) 200*f059b46eSHans de Goede goto out; 201*f059b46eSHans de Goede chip->curr = (s16)val * chip->ua_per_unit; 202*f059b46eSHans de Goede 203*f059b46eSHans de Goede chip->ocv[chip->ocv_avg_index] = 204*f059b46eSHans de Goede chip->volt - chip->curr * chip->intern_res_avg / 1000; 205*f059b46eSHans de Goede chip->ocv_avg_index = (chip->ocv_avg_index + 1) % UG3105_MOV_AVG_WINDOW; 206*f059b46eSHans de Goede chip->poll_count++; 207*f059b46eSHans de Goede 208*f059b46eSHans de Goede /* 209*f059b46eSHans de Goede * See possible improvements comment above. 210*f059b46eSHans de Goede * 211*f059b46eSHans de Goede * Read + reset coulomb counter every 10 polls (every 300 seconds) 212*f059b46eSHans de Goede * if ((chip->poll_count % 10) == 0) { 213*f059b46eSHans de Goede * val = ug3105_read_word(chip->client, UG3105_REG_COULOMB_CNT); 214*f059b46eSHans de Goede * if (val < 0) 215*f059b46eSHans de Goede * goto out; 216*f059b46eSHans de Goede * 217*f059b46eSHans de Goede * i2c_smbus_write_byte_data(chip->client, UG3105_REG_CTRL1, 218*f059b46eSHans de Goede * UG3105_CTRL1_RESET_COULOMB_CNT); 219*f059b46eSHans de Goede * 220*f059b46eSHans de Goede * chip->total_coulomb_count += (s16)val; 221*f059b46eSHans de Goede * dev_dbg(&chip->client->dev, "coulomb count %d total %d\n", 222*f059b46eSHans de Goede * (s16)val, chip->total_coulomb_count); 223*f059b46eSHans de Goede * } 224*f059b46eSHans de Goede */ 225*f059b46eSHans de Goede 226*f059b46eSHans de Goede chip->ocv_avg = 0; 227*f059b46eSHans de Goede win_size = min(chip->poll_count, UG3105_MOV_AVG_WINDOW); 228*f059b46eSHans de Goede for (i = 0; i < win_size; i++) 229*f059b46eSHans de Goede chip->ocv_avg += chip->ocv[i]; 230*f059b46eSHans de Goede chip->ocv_avg /= win_size; 231*f059b46eSHans de Goede 232*f059b46eSHans de Goede chip->supplied = power_supply_am_i_supplied(psy); 233*f059b46eSHans de Goede chip->status = ug3105_get_status(chip); 234*f059b46eSHans de Goede chip->capacity = ug3105_get_capacity(chip); 235*f059b46eSHans de Goede 236*f059b46eSHans de Goede /* 237*f059b46eSHans de Goede * Skip internal resistance calc on charger [un]plug and 238*f059b46eSHans de Goede * when the battery is almost empty (voltage low). 239*f059b46eSHans de Goede */ 240*f059b46eSHans de Goede if (chip->supplied != prev_supplied || 241*f059b46eSHans de Goede chip->volt < UG3105_LOW_BAT_UV || 242*f059b46eSHans de Goede chip->poll_count < 2) 243*f059b46eSHans de Goede goto out; 244*f059b46eSHans de Goede 245*f059b46eSHans de Goede /* 246*f059b46eSHans de Goede * Assuming that the OCV voltage does not change significantly 247*f059b46eSHans de Goede * between 2 polls, then we can calculate the internal resistance 248*f059b46eSHans de Goede * on a significant current change by attributing all voltage 249*f059b46eSHans de Goede * change between the 2 readings to the internal resistance. 250*f059b46eSHans de Goede */ 251*f059b46eSHans de Goede curr_diff = abs(chip->curr - prev_curr); 252*f059b46eSHans de Goede if (curr_diff < UG3105_CURR_HYST_UA) 253*f059b46eSHans de Goede goto out; 254*f059b46eSHans de Goede 255*f059b46eSHans de Goede volt_diff = abs(chip->volt - prev_volt); 256*f059b46eSHans de Goede res = volt_diff * 1000 / curr_diff; 257*f059b46eSHans de Goede 258*f059b46eSHans de Goede if ((res < (chip->intern_res_avg * 2 / 3)) || 259*f059b46eSHans de Goede (res > (chip->intern_res_avg * 4 / 3))) { 260*f059b46eSHans de Goede dev_dbg(&chip->client->dev, "Ignoring outlier internal resistance %d mOhm\n", res); 261*f059b46eSHans de Goede goto out; 262*f059b46eSHans de Goede } 263*f059b46eSHans de Goede 264*f059b46eSHans de Goede dev_dbg(&chip->client->dev, "Internal resistance %d mOhm\n", res); 265*f059b46eSHans de Goede 266*f059b46eSHans de Goede chip->intern_res[chip->intern_res_avg_index] = res; 267*f059b46eSHans de Goede chip->intern_res_avg_index = (chip->intern_res_avg_index + 1) % UG3105_MOV_AVG_WINDOW; 268*f059b46eSHans de Goede chip->intern_res_poll_count++; 269*f059b46eSHans de Goede 270*f059b46eSHans de Goede chip->intern_res_avg = 0; 271*f059b46eSHans de Goede win_size = min(chip->intern_res_poll_count, UG3105_MOV_AVG_WINDOW); 272*f059b46eSHans de Goede for (i = 0; i < win_size; i++) 273*f059b46eSHans de Goede chip->intern_res_avg += chip->intern_res[i]; 274*f059b46eSHans de Goede chip->intern_res_avg /= win_size; 275*f059b46eSHans de Goede 276*f059b46eSHans de Goede out: 277*f059b46eSHans de Goede mutex_unlock(&chip->lock); 278*f059b46eSHans de Goede 279*f059b46eSHans de Goede queue_delayed_work(system_wq, &chip->work, 280*f059b46eSHans de Goede (chip->poll_count <= UG3105_INIT_POLL_COUNT) ? 281*f059b46eSHans de Goede UG3105_INIT_POLL_TIME : UG3105_POLL_TIME); 282*f059b46eSHans de Goede 283*f059b46eSHans de Goede if (chip->status != prev_status && psy) 284*f059b46eSHans de Goede power_supply_changed(psy); 285*f059b46eSHans de Goede } 286*f059b46eSHans de Goede 287*f059b46eSHans de Goede static enum power_supply_property ug3105_battery_props[] = { 288*f059b46eSHans de Goede POWER_SUPPLY_PROP_STATUS, 289*f059b46eSHans de Goede POWER_SUPPLY_PROP_PRESENT, 290*f059b46eSHans de Goede POWER_SUPPLY_PROP_TECHNOLOGY, 291*f059b46eSHans de Goede POWER_SUPPLY_PROP_SCOPE, 292*f059b46eSHans de Goede POWER_SUPPLY_PROP_VOLTAGE_NOW, 293*f059b46eSHans de Goede POWER_SUPPLY_PROP_VOLTAGE_OCV, 294*f059b46eSHans de Goede POWER_SUPPLY_PROP_CURRENT_NOW, 295*f059b46eSHans de Goede POWER_SUPPLY_PROP_CAPACITY, 296*f059b46eSHans de Goede }; 297*f059b46eSHans de Goede 298*f059b46eSHans de Goede static int ug3105_get_property(struct power_supply *psy, 299*f059b46eSHans de Goede enum power_supply_property psp, 300*f059b46eSHans de Goede union power_supply_propval *val) 301*f059b46eSHans de Goede { 302*f059b46eSHans de Goede struct ug3105_chip *chip = power_supply_get_drvdata(psy); 303*f059b46eSHans de Goede int ret = 0; 304*f059b46eSHans de Goede 305*f059b46eSHans de Goede mutex_lock(&chip->lock); 306*f059b46eSHans de Goede 307*f059b46eSHans de Goede if (!chip->psy) { 308*f059b46eSHans de Goede ret = -EAGAIN; 309*f059b46eSHans de Goede goto out; 310*f059b46eSHans de Goede } 311*f059b46eSHans de Goede 312*f059b46eSHans de Goede switch (psp) { 313*f059b46eSHans de Goede case POWER_SUPPLY_PROP_STATUS: 314*f059b46eSHans de Goede val->intval = chip->status; 315*f059b46eSHans de Goede break; 316*f059b46eSHans de Goede case POWER_SUPPLY_PROP_PRESENT: 317*f059b46eSHans de Goede val->intval = 1; 318*f059b46eSHans de Goede break; 319*f059b46eSHans de Goede case POWER_SUPPLY_PROP_TECHNOLOGY: 320*f059b46eSHans de Goede val->intval = chip->info->technology; 321*f059b46eSHans de Goede break; 322*f059b46eSHans de Goede case POWER_SUPPLY_PROP_SCOPE: 323*f059b46eSHans de Goede val->intval = POWER_SUPPLY_SCOPE_SYSTEM; 324*f059b46eSHans de Goede break; 325*f059b46eSHans de Goede case POWER_SUPPLY_PROP_VOLTAGE_NOW: 326*f059b46eSHans de Goede ret = ug3105_read_word(chip->client, UG3105_REG_BAT_VOLT); 327*f059b46eSHans de Goede if (ret < 0) 328*f059b46eSHans de Goede break; 329*f059b46eSHans de Goede val->intval = ret * chip->uv_per_unit; 330*f059b46eSHans de Goede ret = 0; 331*f059b46eSHans de Goede break; 332*f059b46eSHans de Goede case POWER_SUPPLY_PROP_VOLTAGE_OCV: 333*f059b46eSHans de Goede val->intval = chip->ocv_avg; 334*f059b46eSHans de Goede break; 335*f059b46eSHans de Goede case POWER_SUPPLY_PROP_CURRENT_NOW: 336*f059b46eSHans de Goede ret = ug3105_read_word(chip->client, UG3105_REG_BAT_CURR); 337*f059b46eSHans de Goede if (ret < 0) 338*f059b46eSHans de Goede break; 339*f059b46eSHans de Goede val->intval = (s16)ret * chip->ua_per_unit; 340*f059b46eSHans de Goede ret = 0; 341*f059b46eSHans de Goede break; 342*f059b46eSHans de Goede case POWER_SUPPLY_PROP_CAPACITY: 343*f059b46eSHans de Goede val->intval = chip->capacity; 344*f059b46eSHans de Goede break; 345*f059b46eSHans de Goede default: 346*f059b46eSHans de Goede ret = -EINVAL; 347*f059b46eSHans de Goede } 348*f059b46eSHans de Goede 349*f059b46eSHans de Goede out: 350*f059b46eSHans de Goede mutex_unlock(&chip->lock); 351*f059b46eSHans de Goede return ret; 352*f059b46eSHans de Goede } 353*f059b46eSHans de Goede 354*f059b46eSHans de Goede static void ug3105_external_power_changed(struct power_supply *psy) 355*f059b46eSHans de Goede { 356*f059b46eSHans de Goede struct ug3105_chip *chip = power_supply_get_drvdata(psy); 357*f059b46eSHans de Goede 358*f059b46eSHans de Goede dev_dbg(&chip->client->dev, "external power changed\n"); 359*f059b46eSHans de Goede mod_delayed_work(system_wq, &chip->work, UG3105_SETTLE_TIME); 360*f059b46eSHans de Goede } 361*f059b46eSHans de Goede 362*f059b46eSHans de Goede static const struct power_supply_desc ug3105_psy_desc = { 363*f059b46eSHans de Goede .name = "ug3105_battery", 364*f059b46eSHans de Goede .type = POWER_SUPPLY_TYPE_BATTERY, 365*f059b46eSHans de Goede .get_property = ug3105_get_property, 366*f059b46eSHans de Goede .external_power_changed = ug3105_external_power_changed, 367*f059b46eSHans de Goede .properties = ug3105_battery_props, 368*f059b46eSHans de Goede .num_properties = ARRAY_SIZE(ug3105_battery_props), 369*f059b46eSHans de Goede }; 370*f059b46eSHans de Goede 371*f059b46eSHans de Goede static void ug3105_init(struct ug3105_chip *chip) 372*f059b46eSHans de Goede { 373*f059b46eSHans de Goede chip->poll_count = 0; 374*f059b46eSHans de Goede chip->ocv_avg_index = 0; 375*f059b46eSHans de Goede chip->total_coulomb_count = 0; 376*f059b46eSHans de Goede i2c_smbus_write_byte_data(chip->client, UG3105_REG_MODE, 377*f059b46eSHans de Goede UG3105_MODE_RUN); 378*f059b46eSHans de Goede i2c_smbus_write_byte_data(chip->client, UG3105_REG_CTRL1, 379*f059b46eSHans de Goede UG3105_CTRL1_RESET_COULOMB_CNT); 380*f059b46eSHans de Goede queue_delayed_work(system_wq, &chip->work, 0); 381*f059b46eSHans de Goede flush_delayed_work(&chip->work); 382*f059b46eSHans de Goede } 383*f059b46eSHans de Goede 384*f059b46eSHans de Goede static int ug3105_probe(struct i2c_client *client) 385*f059b46eSHans de Goede { 386*f059b46eSHans de Goede struct power_supply_config psy_cfg = {}; 387*f059b46eSHans de Goede struct device *dev = &client->dev; 388*f059b46eSHans de Goede u32 curr_sense_res_uohm = 10000; 389*f059b46eSHans de Goede struct power_supply *psy; 390*f059b46eSHans de Goede struct ug3105_chip *chip; 391*f059b46eSHans de Goede int ret; 392*f059b46eSHans de Goede 393*f059b46eSHans de Goede chip = devm_kzalloc(dev, sizeof(*chip), GFP_KERNEL); 394*f059b46eSHans de Goede if (!chip) 395*f059b46eSHans de Goede return -ENOMEM; 396*f059b46eSHans de Goede 397*f059b46eSHans de Goede chip->client = client; 398*f059b46eSHans de Goede mutex_init(&chip->lock); 399*f059b46eSHans de Goede ret = devm_delayed_work_autocancel(dev, &chip->work, ug3105_work); 400*f059b46eSHans de Goede if (ret) 401*f059b46eSHans de Goede return ret; 402*f059b46eSHans de Goede 403*f059b46eSHans de Goede psy_cfg.drv_data = chip; 404*f059b46eSHans de Goede psy = devm_power_supply_register(dev, &ug3105_psy_desc, &psy_cfg); 405*f059b46eSHans de Goede if (IS_ERR(psy)) 406*f059b46eSHans de Goede return PTR_ERR(psy); 407*f059b46eSHans de Goede 408*f059b46eSHans de Goede ret = power_supply_get_battery_info(psy, &chip->info); 409*f059b46eSHans de Goede if (ret) 410*f059b46eSHans de Goede return ret; 411*f059b46eSHans de Goede 412*f059b46eSHans de Goede if (chip->info->factory_internal_resistance_uohm == -EINVAL || 413*f059b46eSHans de Goede chip->info->constant_charge_voltage_max_uv == -EINVAL) { 414*f059b46eSHans de Goede dev_err(dev, "error required properties are missing\n"); 415*f059b46eSHans de Goede return -ENODEV; 416*f059b46eSHans de Goede } 417*f059b46eSHans de Goede 418*f059b46eSHans de Goede device_property_read_u32(dev, "upisemi,rsns-microohm", &curr_sense_res_uohm); 419*f059b46eSHans de Goede 420*f059b46eSHans de Goede /* 421*f059b46eSHans de Goede * DAC maximum is 4.5V divided by 65536 steps + an unknown factor of 10 422*f059b46eSHans de Goede * coming from somewhere for some reason (verified with a volt-meter). 423*f059b46eSHans de Goede */ 424*f059b46eSHans de Goede chip->uv_per_unit = 45000000/65536; 425*f059b46eSHans de Goede /* Datasheet says 8.1 uV per unit for the current ADC */ 426*f059b46eSHans de Goede chip->ua_per_unit = 8100000 / curr_sense_res_uohm; 427*f059b46eSHans de Goede 428*f059b46eSHans de Goede /* Use provided internal resistance as start point (in milli-ohm) */ 429*f059b46eSHans de Goede chip->intern_res_avg = chip->info->factory_internal_resistance_uohm / 1000; 430*f059b46eSHans de Goede /* Also add it to the internal resistance moving average window */ 431*f059b46eSHans de Goede chip->intern_res[0] = chip->intern_res_avg; 432*f059b46eSHans de Goede chip->intern_res_avg_index = 1; 433*f059b46eSHans de Goede chip->intern_res_poll_count = 1; 434*f059b46eSHans de Goede 435*f059b46eSHans de Goede mutex_lock(&chip->lock); 436*f059b46eSHans de Goede chip->psy = psy; 437*f059b46eSHans de Goede mutex_unlock(&chip->lock); 438*f059b46eSHans de Goede 439*f059b46eSHans de Goede ug3105_init(chip); 440*f059b46eSHans de Goede 441*f059b46eSHans de Goede i2c_set_clientdata(client, chip); 442*f059b46eSHans de Goede return 0; 443*f059b46eSHans de Goede } 444*f059b46eSHans de Goede 445*f059b46eSHans de Goede static int __maybe_unused ug3105_suspend(struct device *dev) 446*f059b46eSHans de Goede { 447*f059b46eSHans de Goede struct ug3105_chip *chip = dev_get_drvdata(dev); 448*f059b46eSHans de Goede 449*f059b46eSHans de Goede cancel_delayed_work_sync(&chip->work); 450*f059b46eSHans de Goede i2c_smbus_write_byte_data(chip->client, UG3105_REG_MODE, 451*f059b46eSHans de Goede UG3105_MODE_STANDBY); 452*f059b46eSHans de Goede 453*f059b46eSHans de Goede return 0; 454*f059b46eSHans de Goede } 455*f059b46eSHans de Goede 456*f059b46eSHans de Goede static int __maybe_unused ug3105_resume(struct device *dev) 457*f059b46eSHans de Goede { 458*f059b46eSHans de Goede struct ug3105_chip *chip = dev_get_drvdata(dev); 459*f059b46eSHans de Goede 460*f059b46eSHans de Goede ug3105_init(chip); 461*f059b46eSHans de Goede 462*f059b46eSHans de Goede return 0; 463*f059b46eSHans de Goede } 464*f059b46eSHans de Goede 465*f059b46eSHans de Goede static SIMPLE_DEV_PM_OPS(ug3105_pm_ops, ug3105_suspend, 466*f059b46eSHans de Goede ug3105_resume); 467*f059b46eSHans de Goede 468*f059b46eSHans de Goede static const struct i2c_device_id ug3105_id[] = { 469*f059b46eSHans de Goede { "ug3105" }, 470*f059b46eSHans de Goede { } 471*f059b46eSHans de Goede }; 472*f059b46eSHans de Goede MODULE_DEVICE_TABLE(i2c, ug3105_id); 473*f059b46eSHans de Goede 474*f059b46eSHans de Goede static struct i2c_driver ug3105_i2c_driver = { 475*f059b46eSHans de Goede .driver = { 476*f059b46eSHans de Goede .name = "ug3105", 477*f059b46eSHans de Goede .pm = &ug3105_pm_ops, 478*f059b46eSHans de Goede }, 479*f059b46eSHans de Goede .probe_new = ug3105_probe, 480*f059b46eSHans de Goede .id_table = ug3105_id, 481*f059b46eSHans de Goede }; 482*f059b46eSHans de Goede module_i2c_driver(ug3105_i2c_driver); 483*f059b46eSHans de Goede 484*f059b46eSHans de Goede MODULE_AUTHOR("Hans de Goede <hdegoede@redhat.com"); 485*f059b46eSHans de Goede MODULE_DESCRIPTION("uPI uG3105 battery monitor driver"); 486*f059b46eSHans de Goede MODULE_LICENSE("GPL"); 487