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

Configure Feed

Select the types of activity you want to include in your feed.

Merge tag 'for-v6.18' of git://git.kernel.org/pub/scm/linux/kernel/git/sre/linux-power-supply

Pull power supply and reset updates from Sebastian Reichel:
"Power-supply core:
- introduce adc-battery-helper for capacity estimation based on
simple ADC readings of battery voltage and current
- add new properties for battery internal resistance and state of
health

Power-supply drivers:
- ug3105_battery: convert to adc-battery-helper
- intel_dc_ti_battery: New driver for Intel Dollar Cove TI batteries
- rt9467-charger: add voltage and current ADC support
- sbs-charger: support multiple instances
- qcom_battmgr:
- add charge control support
- add support for state of health and internal resistance
- max77705_charger:
- big driver cleanup
- add support for setting charge current
- misc minor fixes and cleanups"

* tag 'for-v6.18' of git://git.kernel.org/pub/scm/linux/kernel/git/sre/linux-power-supply: (38 commits)
power: supply: qcom_battmgr: handle charging state change notifications
power: supply: max77705_charger: use REGMAP_IRQ_REG_LINE macro
power: supply: max77705_charger: rework interrupts
power: supply: max77705_charger: add writable properties
power: supply: max77705_charger: return error when config fails
power: supply: max77705_charger: use regfields for config registers
power: supply: max77705_charger: refactoring: rename charger to chg
mfd: max77705: max77705_charger: move active discharge setting to mfd parent
power: supply: max77976_charger: fix constant current reporting
power: supply: qcom_battmgr: Add charge control support
dt-bindings: soc: qcom,pmic-glink: Add charge limit nvmem properties
power: supply: qcom_battmgr: update compats for SM8550 and X1E80100
power: supply: qcom_battmgr: Add state_of_health property
power: supply: qcom_battmgr: Add resistance power supply property
power: supply: core: Add state_of_health power supply property
power: supply: core: Add resistance power supply property
power: supply: rx51: remove redundant condition checks
dt-bindings: power: supply: bq24190: document charge enable pin
dt-bindings: power: supply: bq27xxx: document optional interrupt
power: supply: intel_dc_ti_battery: Drop no longer relevant comment
...

+1609 -589
+37
Documentation/ABI/testing/sysfs-class-power
··· 553 553 Integer > 0: representing full cycles 554 554 Integer = 0: cycle_count info is not available 555 555 556 + What: /sys/class/power_supply/<supply_name>/internal_resistance 557 + Date: August 2025 558 + Contact: linux-arm-msm@vger.kernel.org 559 + Description: 560 + Represent the battery's internal resistance, often referred 561 + to as Equivalent Series Resistance (ESR). It is a dynamic 562 + parameter that reflects the opposition to current flow within 563 + the cell. It is not a fixed value but varies significantly 564 + based on several operational conditions, including battery 565 + state of charge (SoC), temperature, and whether the battery 566 + is in a charging or discharging state. 567 + 568 + Access: Read 569 + 570 + Valid values: Represented in microohms 571 + 572 + What: /sys/class/power_supply/<supply_name>/state_of_health 573 + Date: August 2025 574 + Contact: linux-arm-msm@vger.kernel.org 575 + Description: 576 + The state_of_health parameter quantifies the overall condition 577 + of a battery as a percentage, reflecting its ability to deliver 578 + rated performance relative to its original specifications. It is 579 + dynamically computed using a combination of learned capacity 580 + and impedance-based degradation indicators, both of which evolve 581 + over the battery's lifecycle. 582 + Note that the exact algorithms are kept secret by most battery 583 + vendors and the value from different battery vendors cannot be 584 + compared with each other as there is no vendor-agnostic definition 585 + of "performance". Also this usually cannot be used for any 586 + calculations (i.e. this is not the factor between charge_full and 587 + charge_full_design). 588 + 589 + Access: Read 590 + 591 + Valid values: 0 - 100 (percent) 592 + 556 593 **USB Properties** 557 594 558 595 What: /sys/class/power_supply/<supply_name>/input_current_limit
+6
Documentation/devicetree/bindings/power/supply/bq24190.yaml
··· 30 30 interrupts: 31 31 maxItems: 1 32 32 33 + ce-gpios: 34 + description: 35 + Active low Charge Enable pin. Battery charging is enabled when 36 + REG01[5:4] = 01 and CE pin is Low. CE pin must be pulled high or low. 37 + maxItems: 1 38 + 33 39 usb-otg-vbus: 34 40 $ref: /schemas/regulator/regulator.yaml# 35 41 description: |
+34 -3
Documentation/devicetree/bindings/power/supply/bq27xxx.yaml
··· 16 16 Support various Texas Instruments fuel gauge devices that share similar 17 17 register maps and power supply properties 18 18 19 - allOf: 20 - - $ref: power-supply.yaml# 21 - 22 19 properties: 23 20 compatible: 24 21 enum: ··· 55 58 maxItems: 1 56 59 description: integer, I2C address of the fuel gauge. 57 60 61 + interrupts: 62 + maxItems: 1 63 + description: the SOC_INT or GPOUT pin 64 + 58 65 monitored-battery: 59 66 description: | 60 67 The fuel gauge uses the following battery properties: ··· 68 67 Both or neither of the *-full-design-*-hours properties must be set. 69 68 70 69 power-supplies: true 70 + 71 + allOf: 72 + - $ref: power-supply.yaml# 73 + - if: 74 + properties: 75 + compatible: 76 + contains: 77 + enum: 78 + - ti,bq27200 79 + - ti,bq27210 80 + - ti,bq27500 # deprecated, use revision specific property below 81 + - ti,bq27510 # deprecated, use revision specific property below 82 + - ti,bq27520 # deprecated, use revision specific property below 83 + - ti,bq27500-1 84 + - ti,bq27510g1 85 + - ti,bq27510g2 86 + - ti,bq27521 87 + - ti,bq27541 88 + - ti,bq27542 89 + - ti,bq27546 90 + - ti,bq27742 91 + - ti,bq27545 92 + - ti,bq27411 93 + - ti,bq27z561 94 + - ti,bq28z610 95 + - ti,bq34z100 96 + - ti,bq78z100 97 + then: 98 + properties: 99 + interrupts: false 71 100 72 101 required: 73 102 - compatible
+14
Documentation/devicetree/bindings/soc/qcom/qcom,pmic-glink.yaml
··· 56 56 The array should contain a gpio entry for each PMIC Glink connector, in reg order. 57 57 It is defined that GPIO active level means "CC2" or Reversed/Flipped orientation. 58 58 59 + nvmem-cells: 60 + minItems: 3 61 + maxItems: 3 62 + description: 63 + The nvmem cells contain the charge control settings, including the charge control 64 + enable status, the battery state of charge (SoC) threshold for stopping charging, 65 + and the battery SoC delta required to restart charging. 66 + 67 + nvmem-cell-names: 68 + items: 69 + - const: charge_limit_en 70 + - const: charge_limit_end 71 + - const: charge_limit_delta 72 + 59 73 patternProperties: 60 74 '^connector@\d$': 61 75 $ref: /schemas/connector/usb-connector.yaml#
+3
drivers/mfd/max77705.c
··· 108 108 if (pmic_rev != MAX77705_PASS3) 109 109 return dev_err_probe(dev, -ENODEV, "Rev.0x%x is not tested\n", pmic_rev); 110 110 111 + /* Active Discharge Enable */ 112 + regmap_update_bits(max77705->regmap, MAX77705_PMIC_REG_MAINCTRL1, 1, 1); 113 + 111 114 ret = devm_regmap_add_irq_chip(dev, max77705->regmap, 112 115 i2c->irq, 113 116 IRQF_ONESHOT, 0,
+4 -4
drivers/power/supply/88pm860x_charger.c
··· 284 284 { 285 285 struct power_supply *psy; 286 286 union power_supply_propval data; 287 - unsigned char fsm_state[][16] = { "init", "discharge", "precharge", 288 - "fastcharge", 287 + static const unsigned char fsm_state[][16] = { 288 + "init", "discharge", "precharge", "fastcharge", 289 289 }; 290 290 int ret; 291 291 int vbatt; ··· 313 313 314 314 dev_dbg(info->dev, "Entering FSM:%s, Charger:%s, Battery:%s, " 315 315 "Allowed:%d\n", 316 - &fsm_state[info->state][0], 316 + fsm_state[info->state], 317 317 (info->online) ? "online" : "N/A", 318 318 (info->present) ? "present" : "N/A", info->allowed); 319 319 dev_dbg(info->dev, "set_charging_fsm:vbatt:%d(mV)\n", vbatt); ··· 385 385 } 386 386 dev_dbg(info->dev, 387 387 "Out FSM:%s, Charger:%s, Battery:%s, Allowed:%d\n", 388 - &fsm_state[info->state][0], 388 + fsm_state[info->state], 389 389 (info->online) ? "online" : "N/A", 390 390 (info->present) ? "present" : "N/A", info->allowed); 391 391 mutex_unlock(&info->lock);
+16
drivers/power/supply/Kconfig
··· 35 35 Say Y here to enable support APM status emulation using 36 36 battery class devices. 37 37 38 + config ADC_BATTERY_HELPER 39 + tristate 40 + 38 41 config GENERIC_ADC_BATTERY 39 42 tristate "Generic battery support using IIO" 40 43 depends on IIO ··· 246 243 247 244 This driver can also be built as a module. If so, the module will be 248 245 called ingenic-battery. 246 + 247 + config BATTERY_INTEL_DC_TI 248 + tristate "Intel Bay / Cherry Trail Dollar Cove TI battery driver" 249 + depends on INTEL_SOC_PMIC_CHTDC_TI && INTEL_DC_TI_ADC && IIO && ACPI 250 + select ADC_BATTERY_HELPER 251 + help 252 + Choose this option if you want to monitor battery status on Intel 253 + Bay Trail / Cherry Trail tablets using the Dollar Cove TI PMIC's 254 + coulomb-counter as fuel-gauge. 255 + 256 + To compile this driver as a module, choose M here: the module will be 257 + called intel_dc_ti_battery. 249 258 250 259 config BATTERY_IPAQ_MICRO 251 260 tristate "iPAQ Atmel Micro ASIC battery driver" ··· 1065 1050 config BATTERY_UG3105 1066 1051 tristate "uPI uG3105 battery monitor driver" 1067 1052 depends on I2C 1053 + select ADC_BATTERY_HELPER 1068 1054 help 1069 1055 Battery monitor driver for the uPI uG3105 battery monitor. 1070 1056
+2
drivers/power/supply/Makefile
··· 7 7 8 8 obj-$(CONFIG_POWER_SUPPLY) += power_supply.o 9 9 obj-$(CONFIG_POWER_SUPPLY_HWMON) += power_supply_hwmon.o 10 + obj-$(CONFIG_ADC_BATTERY_HELPER) += adc-battery-helper.o 10 11 obj-$(CONFIG_GENERIC_ADC_BATTERY) += generic-adc-battery.o 11 12 12 13 obj-$(CONFIG_APM_POWER) += apm_power.o ··· 42 41 obj-$(CONFIG_BATTERY_SAMSUNG_SDI) += samsung-sdi-battery.o 43 42 obj-$(CONFIG_BATTERY_COLLIE) += collie_battery.o 44 43 obj-$(CONFIG_BATTERY_INGENIC) += ingenic-battery.o 44 + obj-$(CONFIG_BATTERY_INTEL_DC_TI) += intel_dc_ti_battery.o 45 45 obj-$(CONFIG_BATTERY_IPAQ_MICRO) += ipaq_micro_battery.o 46 46 obj-$(CONFIG_BATTERY_WM97XX) += wm97xx_battery.o 47 47 obj-$(CONFIG_BATTERY_SBS) += sbs-battery.o
+2 -1
drivers/power/supply/ab8500_btemp.c
··· 667 667 668 668 /* Create a work queue for the btemp */ 669 669 di->btemp_wq = 670 - alloc_workqueue("ab8500_btemp_wq", WQ_MEM_RECLAIM, 0); 670 + alloc_workqueue("ab8500_btemp_wq", WQ_MEM_RECLAIM | WQ_PERCPU, 671 + 0); 671 672 if (di->btemp_wq == NULL) { 672 673 dev_err(dev, "failed to create work queue\n"); 673 674 return -ENOMEM;
+327
drivers/power/supply/adc-battery-helper.c
··· 1 + // SPDX-License-Identifier: GPL-2.0+ 2 + /* 3 + * Helper for batteries with accurate current and voltage measurement, but 4 + * without temperature measurement or without a "resistance-temp-table". 5 + * 6 + * Some fuel-gauges are not full-featured autonomous fuel-gauges. 7 + * These fuel-gauges offer accurate current and voltage measurements but 8 + * their coulomb-counters are intended to work together with an always on 9 + * micro-controller monitoring the fuel-gauge. 10 + * 11 + * This adc-battery-helper code offers open-circuit-voltage (ocv) and through 12 + * that capacity estimation for devices where such limited functionality 13 + * fuel-gauges are exposed directly to Linux. 14 + * 15 + * This helper requires the hw to provide accurate battery current_now and 16 + * voltage_now measurement and this helper the provides the following properties 17 + * based on top of those readings: 18 + * 19 + * POWER_SUPPLY_PROP_STATUS 20 + * POWER_SUPPLY_PROP_VOLTAGE_OCV 21 + * POWER_SUPPLY_PROP_VOLTAGE_NOW 22 + * POWER_SUPPLY_PROP_CURRENT_NOW 23 + * POWER_SUPPLY_PROP_CAPACITY 24 + * 25 + * As well as optional the following properties assuming an always present 26 + * system-scope battery, allowing direct use of adc_battery_helper_get_prop() 27 + * in this common case: 28 + * POWER_SUPPLY_PROP_PRESENT 29 + * POWER_SUPPLY_PROP_SCOPE 30 + * 31 + * Using this helper is as simple as: 32 + * 33 + * 1. Embed a struct adc_battery_helper this MUST be the first member of 34 + * the battery driver's data struct. 35 + * 2. Use adc_battery_helper_props[] or add the above properties to 36 + * the list of properties in power_supply_desc 37 + * 3. Call adc_battery_helper_init() after registering the power_supply and 38 + * before returning from the probe() function 39 + * 4. Use adc_battery_helper_get_prop() as the power-supply's get_property() 40 + * method, or call it for the above properties. 41 + * 5. Use adc_battery_helper_external_power_changed() as the power-supply's 42 + * external_power_changed() method or call it from that method. 43 + * 6. Use adc_battery_helper_[suspend|resume]() as suspend-resume methods or 44 + * call them from the driver's suspend-resume methods. 45 + * 46 + * The provided get_voltage_and_current_now() method will be called by this 47 + * helper at adc_battery_helper_init() time and later. 48 + * 49 + * Copyright (c) 2021-2025 Hans de Goede <hansg@kernel.org> 50 + */ 51 + 52 + #include <linux/cleanup.h> 53 + #include <linux/devm-helpers.h> 54 + #include <linux/gpio/consumer.h> 55 + #include <linux/mutex.h> 56 + #include <linux/power_supply.h> 57 + #include <linux/workqueue.h> 58 + 59 + #include "adc-battery-helper.h" 60 + 61 + #define MOV_AVG_WINDOW_SIZE ADC_BAT_HELPER_MOV_AVG_WINDOW_SIZE 62 + #define INIT_POLL_TIME (5 * HZ) 63 + #define POLL_TIME (30 * HZ) 64 + #define SETTLE_TIME (1 * HZ) 65 + 66 + #define INIT_POLL_COUNT 30 67 + 68 + #define CURR_HYST_UA 65000 69 + 70 + #define LOW_BAT_UV 3700000 71 + #define FULL_BAT_HYST_UV 38000 72 + 73 + #define AMBIENT_TEMP_CELSIUS 25 74 + 75 + static int adc_battery_helper_get_status(struct adc_battery_helper *help) 76 + { 77 + int full_uv = 78 + help->psy->battery_info->constant_charge_voltage_max_uv - FULL_BAT_HYST_UV; 79 + 80 + if (help->curr_ua > CURR_HYST_UA) 81 + return POWER_SUPPLY_STATUS_CHARGING; 82 + 83 + if (help->curr_ua < -CURR_HYST_UA) 84 + return POWER_SUPPLY_STATUS_DISCHARGING; 85 + 86 + if (help->supplied) { 87 + bool full; 88 + 89 + if (help->charge_finished) 90 + full = gpiod_get_value_cansleep(help->charge_finished); 91 + else 92 + full = help->ocv_avg_uv > full_uv; 93 + 94 + if (full) 95 + return POWER_SUPPLY_STATUS_FULL; 96 + } 97 + 98 + return POWER_SUPPLY_STATUS_NOT_CHARGING; 99 + } 100 + 101 + static void adc_battery_helper_work(struct work_struct *work) 102 + { 103 + struct adc_battery_helper *help = container_of(work, struct adc_battery_helper, 104 + work.work); 105 + int i, curr_diff_ua, volt_diff_uv, res_mohm, ret, win_size; 106 + struct device *dev = help->psy->dev.parent; 107 + int volt_uv, prev_volt_uv = help->volt_uv; 108 + int curr_ua, prev_curr_ua = help->curr_ua; 109 + bool prev_supplied = help->supplied; 110 + int prev_status = help->status; 111 + 112 + guard(mutex)(&help->lock); 113 + 114 + ret = help->get_voltage_and_current_now(help->psy, &volt_uv, &curr_ua); 115 + if (ret) 116 + goto out; 117 + 118 + help->volt_uv = volt_uv; 119 + help->curr_ua = curr_ua; 120 + 121 + help->ocv_uv[help->ocv_avg_index] = 122 + help->volt_uv - help->curr_ua * help->intern_res_avg_mohm / 1000; 123 + dev_dbg(dev, "volt-now: %d, curr-now: %d, volt-ocv: %d\n", 124 + help->volt_uv, help->curr_ua, help->ocv_uv[help->ocv_avg_index]); 125 + help->ocv_avg_index = (help->ocv_avg_index + 1) % MOV_AVG_WINDOW_SIZE; 126 + help->poll_count++; 127 + 128 + help->ocv_avg_uv = 0; 129 + win_size = min(help->poll_count, MOV_AVG_WINDOW_SIZE); 130 + for (i = 0; i < win_size; i++) 131 + help->ocv_avg_uv += help->ocv_uv[i]; 132 + help->ocv_avg_uv /= win_size; 133 + 134 + help->supplied = power_supply_am_i_supplied(help->psy); 135 + help->status = adc_battery_helper_get_status(help); 136 + if (help->status == POWER_SUPPLY_STATUS_FULL) 137 + help->capacity = 100; 138 + else 139 + help->capacity = power_supply_batinfo_ocv2cap(help->psy->battery_info, 140 + help->ocv_avg_uv, 141 + AMBIENT_TEMP_CELSIUS); 142 + 143 + /* 144 + * Skip internal resistance calc on charger [un]plug and 145 + * when the battery is almost empty (voltage low). 146 + */ 147 + if (help->supplied != prev_supplied || 148 + help->volt_uv < LOW_BAT_UV || 149 + help->poll_count < 2) 150 + goto out; 151 + 152 + /* 153 + * Assuming that the OCV voltage does not change significantly 154 + * between 2 polls, then we can calculate the internal resistance 155 + * on a significant current change by attributing all voltage 156 + * change between the 2 readings to the internal resistance. 157 + */ 158 + curr_diff_ua = abs(help->curr_ua - prev_curr_ua); 159 + if (curr_diff_ua < CURR_HYST_UA) 160 + goto out; 161 + 162 + volt_diff_uv = abs(help->volt_uv - prev_volt_uv); 163 + res_mohm = volt_diff_uv * 1000 / curr_diff_ua; 164 + 165 + if ((res_mohm < (help->intern_res_avg_mohm * 2 / 3)) || 166 + (res_mohm > (help->intern_res_avg_mohm * 4 / 3))) { 167 + dev_dbg(dev, "Ignoring outlier internal resistance %d mOhm\n", res_mohm); 168 + goto out; 169 + } 170 + 171 + dev_dbg(dev, "Internal resistance %d mOhm\n", res_mohm); 172 + 173 + help->intern_res_mohm[help->intern_res_avg_index] = res_mohm; 174 + help->intern_res_avg_index = (help->intern_res_avg_index + 1) % MOV_AVG_WINDOW_SIZE; 175 + help->intern_res_poll_count++; 176 + 177 + help->intern_res_avg_mohm = 0; 178 + win_size = min(help->intern_res_poll_count, MOV_AVG_WINDOW_SIZE); 179 + for (i = 0; i < win_size; i++) 180 + help->intern_res_avg_mohm += help->intern_res_mohm[i]; 181 + help->intern_res_avg_mohm /= win_size; 182 + 183 + out: 184 + queue_delayed_work(system_percpu_wq, &help->work, 185 + (help->poll_count <= INIT_POLL_COUNT) ? 186 + INIT_POLL_TIME : POLL_TIME); 187 + 188 + if (help->status != prev_status) 189 + power_supply_changed(help->psy); 190 + } 191 + 192 + const enum power_supply_property adc_battery_helper_properties[] = { 193 + POWER_SUPPLY_PROP_STATUS, 194 + POWER_SUPPLY_PROP_VOLTAGE_NOW, 195 + POWER_SUPPLY_PROP_VOLTAGE_OCV, 196 + POWER_SUPPLY_PROP_CURRENT_NOW, 197 + POWER_SUPPLY_PROP_CAPACITY, 198 + POWER_SUPPLY_PROP_PRESENT, 199 + POWER_SUPPLY_PROP_SCOPE, 200 + }; 201 + EXPORT_SYMBOL_GPL(adc_battery_helper_properties); 202 + 203 + static_assert(ARRAY_SIZE(adc_battery_helper_properties) == 204 + ADC_HELPER_NUM_PROPERTIES); 205 + 206 + int adc_battery_helper_get_property(struct power_supply *psy, 207 + enum power_supply_property psp, 208 + union power_supply_propval *val) 209 + { 210 + struct adc_battery_helper *help = power_supply_get_drvdata(psy); 211 + int dummy, ret = 0; 212 + 213 + /* 214 + * Avoid racing with adc_battery_helper_work() while it is updating 215 + * variables and avoid calling get_voltage_and_current_now() reentrantly. 216 + */ 217 + guard(mutex)(&help->lock); 218 + 219 + switch (psp) { 220 + case POWER_SUPPLY_PROP_STATUS: 221 + val->intval = help->status; 222 + break; 223 + case POWER_SUPPLY_PROP_VOLTAGE_NOW: 224 + ret = help->get_voltage_and_current_now(psy, &val->intval, &dummy); 225 + break; 226 + case POWER_SUPPLY_PROP_VOLTAGE_OCV: 227 + val->intval = help->ocv_avg_uv; 228 + break; 229 + case POWER_SUPPLY_PROP_CURRENT_NOW: 230 + ret = help->get_voltage_and_current_now(psy, &dummy, &val->intval); 231 + break; 232 + case POWER_SUPPLY_PROP_CAPACITY: 233 + val->intval = help->capacity; 234 + break; 235 + case POWER_SUPPLY_PROP_PRESENT: 236 + val->intval = 1; 237 + break; 238 + case POWER_SUPPLY_PROP_SCOPE: 239 + val->intval = POWER_SUPPLY_SCOPE_SYSTEM; 240 + break; 241 + default: 242 + return -EINVAL; 243 + } 244 + 245 + return ret; 246 + } 247 + EXPORT_SYMBOL_GPL(adc_battery_helper_get_property); 248 + 249 + void adc_battery_helper_external_power_changed(struct power_supply *psy) 250 + { 251 + struct adc_battery_helper *help = power_supply_get_drvdata(psy); 252 + 253 + dev_dbg(help->psy->dev.parent, "external power changed\n"); 254 + mod_delayed_work(system_percpu_wq, &help->work, SETTLE_TIME); 255 + } 256 + EXPORT_SYMBOL_GPL(adc_battery_helper_external_power_changed); 257 + 258 + static void adc_battery_helper_start_work(struct adc_battery_helper *help) 259 + { 260 + help->poll_count = 0; 261 + help->ocv_avg_index = 0; 262 + 263 + queue_delayed_work(system_percpu_wq, &help->work, 0); 264 + flush_delayed_work(&help->work); 265 + } 266 + 267 + int adc_battery_helper_init(struct adc_battery_helper *help, struct power_supply *psy, 268 + adc_battery_helper_get_func get_voltage_and_current_now, 269 + struct gpio_desc *charge_finished_gpio) 270 + { 271 + struct device *dev = psy->dev.parent; 272 + int ret; 273 + 274 + help->psy = psy; 275 + help->get_voltage_and_current_now = get_voltage_and_current_now; 276 + help->charge_finished = charge_finished_gpio; 277 + 278 + ret = devm_mutex_init(dev, &help->lock); 279 + if (ret) 280 + return ret; 281 + 282 + ret = devm_delayed_work_autocancel(dev, &help->work, adc_battery_helper_work); 283 + if (ret) 284 + return ret; 285 + 286 + if (!help->psy->battery_info || 287 + help->psy->battery_info->factory_internal_resistance_uohm == -EINVAL || 288 + help->psy->battery_info->constant_charge_voltage_max_uv == -EINVAL || 289 + !psy->battery_info->ocv_table[0]) { 290 + dev_err(dev, "error required properties are missing\n"); 291 + return -ENODEV; 292 + } 293 + 294 + /* Use provided internal resistance as start point (in milli-ohm) */ 295 + help->intern_res_avg_mohm = 296 + help->psy->battery_info->factory_internal_resistance_uohm / 1000; 297 + /* Also add it to the internal resistance moving average window */ 298 + help->intern_res_mohm[0] = help->intern_res_avg_mohm; 299 + help->intern_res_avg_index = 1; 300 + help->intern_res_poll_count = 1; 301 + 302 + adc_battery_helper_start_work(help); 303 + return 0; 304 + } 305 + EXPORT_SYMBOL_GPL(adc_battery_helper_init); 306 + 307 + int adc_battery_helper_suspend(struct device *dev) 308 + { 309 + struct adc_battery_helper *help = dev_get_drvdata(dev); 310 + 311 + cancel_delayed_work_sync(&help->work); 312 + return 0; 313 + } 314 + EXPORT_SYMBOL_GPL(adc_battery_helper_suspend); 315 + 316 + int adc_battery_helper_resume(struct device *dev) 317 + { 318 + struct adc_battery_helper *help = dev_get_drvdata(dev); 319 + 320 + adc_battery_helper_start_work(help); 321 + return 0; 322 + } 323 + EXPORT_SYMBOL_GPL(adc_battery_helper_resume); 324 + 325 + MODULE_AUTHOR("Hans de Goede <hansg@kernel.org>"); 326 + MODULE_DESCRIPTION("ADC battery capacity estimation helper"); 327 + MODULE_LICENSE("GPL");
+62
drivers/power/supply/adc-battery-helper.h
··· 1 + /* SPDX-License-Identifier: GPL-2.0+ */ 2 + /* 3 + * Helper for batteries with accurate current and voltage measurement, but 4 + * without temperature measurement or without a "resistance-temp-table". 5 + * Copyright (c) 2021-2025 Hans de Goede <hansg@kernel.org> 6 + */ 7 + 8 + #include <linux/mutex.h> 9 + #include <linux/workqueue.h> 10 + 11 + #define ADC_BAT_HELPER_MOV_AVG_WINDOW_SIZE 8 12 + 13 + struct power_supply; 14 + struct gpio_desc; 15 + 16 + /* 17 + * The adc battery helper code needs voltage- and current-now to be sampled as 18 + * close to each other (in sample-time) as possible. A single getter function is 19 + * used to allow the battery driver to handle this in the best way possible. 20 + */ 21 + typedef int (*adc_battery_helper_get_func)(struct power_supply *psy, int *volt, int *curr); 22 + 23 + struct adc_battery_helper { 24 + struct power_supply *psy; 25 + struct gpio_desc *charge_finished; 26 + struct delayed_work work; 27 + struct mutex lock; 28 + adc_battery_helper_get_func get_voltage_and_current_now; 29 + int ocv_uv[ADC_BAT_HELPER_MOV_AVG_WINDOW_SIZE]; /* micro-volt */ 30 + int intern_res_mohm[ADC_BAT_HELPER_MOV_AVG_WINDOW_SIZE]; /* milli-ohm */ 31 + int poll_count; 32 + int ocv_avg_index; 33 + int ocv_avg_uv; /* micro-volt */ 34 + int intern_res_poll_count; 35 + int intern_res_avg_index; 36 + int intern_res_avg_mohm; /* milli-ohm */ 37 + int volt_uv; /* micro-volt */ 38 + int curr_ua; /* micro-ampere */ 39 + int capacity; /* percent */ 40 + int status; 41 + bool supplied; 42 + }; 43 + 44 + extern const enum power_supply_property adc_battery_helper_properties[]; 45 + /* Must be const cannot be an external. Asserted in adc-battery-helper.c */ 46 + #define ADC_HELPER_NUM_PROPERTIES 7 47 + 48 + int adc_battery_helper_init(struct adc_battery_helper *help, struct power_supply *psy, 49 + adc_battery_helper_get_func get_voltage_and_current_now, 50 + struct gpio_desc *charge_finished_gpio); 51 + /* 52 + * The below functions can be directly used as power-supply / suspend-resume 53 + * callbacks. They cast the power_supply_get_drvdata() / dev_get_drvdata() data 54 + * directly to struct adc_battery_helper. Therefor struct adc_battery_helper 55 + * MUST be the first member of the battery driver's data struct. 56 + */ 57 + int adc_battery_helper_get_property(struct power_supply *psy, 58 + enum power_supply_property psp, 59 + union power_supply_propval *val); 60 + void adc_battery_helper_external_power_changed(struct power_supply *psy); 61 + int adc_battery_helper_suspend(struct device *dev); 62 + int adc_battery_helper_resume(struct device *dev);
+2 -2
drivers/power/supply/bq2415x_charger.c
··· 842 842 if (bq->automode < 1) 843 843 return NOTIFY_OK; 844 844 845 - mod_delayed_work(system_wq, &bq->work, 0); 845 + mod_delayed_work(system_percpu_wq, &bq->work, 0); 846 846 847 847 return NOTIFY_OK; 848 848 } ··· 1516 1516 1517 1517 ret = bq2415x_detect_revision(bq); 1518 1518 if (ret < 0) 1519 - strcpy(revstr, "unknown"); 1519 + strscpy(revstr, "unknown", sizeof(revstr)); 1520 1520 else 1521 1521 sprintf(revstr, "1.%d", ret); 1522 1522
+1 -1
drivers/power/supply/bq24190_charger.c
··· 1467 1467 * too low default 500mA iinlim. Delay setting the input-current-limit 1468 1468 * for 300ms to avoid this. 1469 1469 */ 1470 - queue_delayed_work(system_wq, &bdi->input_current_limit_work, 1470 + queue_delayed_work(system_percpu_wq, &bdi->input_current_limit_work, 1471 1471 msecs_to_jiffies(300)); 1472 1472 } 1473 1473
+4 -13
drivers/power/supply/bq27xxx_battery.c
··· 1127 1127 1128 1128 mutex_lock(&bq27xxx_list_lock); 1129 1129 list_for_each_entry(di, &bq27xxx_battery_devices, list) 1130 - mod_delayed_work(system_wq, &di->work, 0); 1130 + mod_delayed_work(system_percpu_wq, &di->work, 0); 1131 1131 mutex_unlock(&bq27xxx_list_lock); 1132 1132 1133 1133 return ret; ··· 1945 1945 di->last_update = jiffies; 1946 1946 1947 1947 if (!di->removed && poll_interval > 0) 1948 - mod_delayed_work(system_wq, &di->work, poll_interval * HZ); 1948 + mod_delayed_work(system_percpu_wq, &di->work, poll_interval * HZ); 1949 1949 } 1950 1950 1951 1951 void bq27xxx_battery_update(struct bq27xxx_device_info *di) ··· 2221 2221 struct bq27xxx_device_info *di = power_supply_get_drvdata(psy); 2222 2222 2223 2223 /* After charger plug in/out wait 0.5s for things to stabilize */ 2224 - mod_delayed_work(system_wq, &di->work, HZ / 2); 2225 - } 2226 - 2227 - static void bq27xxx_battery_mutex_destroy(void *data) 2228 - { 2229 - struct mutex *lock = data; 2230 - 2231 - mutex_destroy(lock); 2224 + mod_delayed_work(system_percpu_wq, &di->work, HZ / 2); 2232 2225 } 2233 2226 2234 2227 int bq27xxx_battery_setup(struct bq27xxx_device_info *di) ··· 2235 2242 int ret; 2236 2243 2237 2244 INIT_DELAYED_WORK(&di->work, bq27xxx_battery_poll); 2238 - mutex_init(&di->lock); 2239 - ret = devm_add_action_or_reset(di->dev, bq27xxx_battery_mutex_destroy, 2240 - &di->lock); 2245 + ret = devm_mutex_init(di->dev, &di->lock); 2241 2246 if (ret) 2242 2247 return ret; 2243 2248
+2 -6
drivers/power/supply/cw2015_battery.c
··· 506 506 507 507 case POWER_SUPPLY_PROP_CHARGE_FULL: 508 508 case POWER_SUPPLY_PROP_CHARGE_FULL_DESIGN: 509 - if (cw_bat->battery->charge_full_design_uah > 0) 510 - val->intval = cw_bat->battery->charge_full_design_uah; 511 - else 512 - val->intval = 0; 509 + val->intval = max(cw_bat->battery->charge_full_design_uah, 0); 513 510 break; 514 511 515 512 case POWER_SUPPLY_PROP_CHARGE_NOW: ··· 699 702 if (!cw_bat->battery_workqueue) 700 703 return -ENOMEM; 701 704 702 - devm_delayed_work_autocancel(&client->dev, 703 - &cw_bat->battery_delay_work, cw_bat_work); 705 + devm_delayed_work_autocancel(&client->dev, &cw_bat->battery_delay_work, cw_bat_work); 704 706 queue_delayed_work(cw_bat->battery_workqueue, 705 707 &cw_bat->battery_delay_work, msecs_to_jiffies(10)); 706 708 return 0;
+4 -3
drivers/power/supply/gpio-charger.c
··· 79 79 80 80 for (i = 0; i < ndescs; i++) { 81 81 bool val = (mapping.gpiodata >> i) & 1; 82 - gpiod_set_value_cansleep(gpios[ndescs-i-1], val); 82 + 83 + gpiod_set_value_cansleep(gpios[ndescs - i - 1], val); 83 84 } 84 85 85 86 gpio_charger->charge_current_limit = mapping.limit_ua; ··· 227 226 gpio_charger->current_limit_map_size = len / 2; 228 227 229 228 len = device_property_read_u32_array(dev, "charge-current-limit-mapping", 230 - (u32*) gpio_charger->current_limit_map, len); 229 + (u32 *) gpio_charger->current_limit_map, len); 231 230 if (len < 0) 232 231 return len; 233 232 234 233 set_def_limit = !device_property_read_u32(dev, 235 234 "charge-current-limit-default-microamp", 236 235 &def_limit); 237 - for (i=0; i < gpio_charger->current_limit_map_size; i++) { 236 + for (i = 0; i < gpio_charger->current_limit_map_size; i++) { 238 237 if (gpio_charger->current_limit_map[i].limit_ua > cur_limit) { 239 238 dev_err(dev, "charge-current-limit-mapping not sorted by current in descending order\n"); 240 239 return -EINVAL;
+389
drivers/power/supply/intel_dc_ti_battery.c
··· 1 + // SPDX-License-Identifier: GPL-2.0-only 2 + /* 3 + * Battery driver for the coulomb-counter of the Intel Dollar Cove TI PMIC 4 + * 5 + * Note the Intel Dollar Cove TI PMIC coulomb-counter is not a full-featured 6 + * autonomous fuel-gauge. It is intended to work together with an always on 7 + * micro-controller monitoring it. 8 + * 9 + * Since Linux does not monitor coulomb-counter changes while the device 10 + * is off or suspended, voltage based capacity estimation from 11 + * the adc-battery-helper code is used. 12 + * 13 + * Copyright (C) 2024 Hans de Goede <hansg@kernel.org> 14 + * 15 + * Register definitions and calibration code was taken from 16 + * kernel/drivers/platform/x86/dc_ti_cc.c from the Acer A1-840 Android kernel 17 + * which has the following copyright header: 18 + * 19 + * Copyright (C) 2014 Intel Corporation 20 + * Author: Ramakrishna Pallala <ramakrishna.pallala@intel.com> 21 + * 22 + * dc_ti_cc.c is part of the Acer A1-840 Android kernel source-code archive 23 + * named: "App. Guide_Acer_20151221_A_A.zip" 24 + * which is distributed by Acer from the Acer A1-840 support page: 25 + * https://www.acer.com/us-en/support/product-support/A1-840/downloads 26 + */ 27 + 28 + #include <linux/acpi.h> 29 + #include <linux/bits.h> 30 + #include <linux/bitfield.h> 31 + #include <linux/cleanup.h> 32 + #include <linux/err.h> 33 + #include <linux/gpio/consumer.h> 34 + #include <linux/iio/consumer.h> 35 + #include <linux/mfd/intel_soc_pmic.h> 36 + #include <linux/module.h> 37 + #include <linux/platform_device.h> 38 + #include <linux/pm_runtime.h> 39 + #include <linux/power_supply.h> 40 + #include <linux/property.h> 41 + #include <linux/regmap.h> 42 + #include <linux/timekeeping.h> 43 + 44 + #include "adc-battery-helper.h" 45 + 46 + #define DC_TI_PMIC_VERSION_REG 0x00 47 + #define PMIC_VERSION_A0 0xC0 48 + #define PMIC_VERSION_A1 0xC1 49 + 50 + #define DC_TI_CC_CNTL_REG 0x60 51 + #define CC_CNTL_CC_CTR_EN BIT(0) 52 + #define CC_CNTL_CC_CLR_EN BIT(1) 53 + #define CC_CNTL_CC_CAL_EN BIT(2) 54 + #define CC_CNTL_CC_OFFSET_EN BIT(3) 55 + #define CC_CNTL_SMPL_INTVL GENMASK(5, 4) 56 + #define CC_CNTL_SMPL_INTVL_15MS FIELD_PREP(CC_CNTL_SMPL_INTVL, 0) 57 + #define CC_CNTL_SMPL_INTVL_62MS FIELD_PREP(CC_CNTL_SMPL_INTVL, 1) 58 + #define CC_CNTL_SMPL_INTVL_125MS FIELD_PREP(CC_CNTL_SMPL_INTVL, 2) 59 + #define CC_CNTL_SMPL_INTVL_250MS FIELD_PREP(CC_CNTL_SMPL_INTVL, 3) 60 + 61 + #define DC_TI_SMPL_CTR0_REG 0x69 62 + #define DC_TI_SMPL_CTR1_REG 0x68 63 + #define DC_TI_SMPL_CTR2_REG 0x67 64 + 65 + #define DC_TI_CC_OFFSET_HI_REG 0x61 66 + #define CC_OFFSET_HI_MASK 0x3F 67 + #define DC_TI_CC_OFFSET_LO_REG 0x62 68 + 69 + #define DC_TI_SW_OFFSET_REG 0x6C 70 + 71 + #define DC_TI_CC_ACC3_REG 0x63 72 + #define DC_TI_CC_ACC2_REG 0x64 73 + #define DC_TI_CC_ACC1_REG 0x65 74 + #define DC_TI_CC_ACC0_REG 0x66 75 + 76 + #define DC_TI_CC_INTG1_REG 0x6A 77 + #define DC_TI_CC_INTG1_MASK 0x3F 78 + #define DC_TI_CC_INTG0_REG 0x6B 79 + 80 + #define DC_TI_EEPROM_ACCESS_CONTROL 0x88 81 + #define EEPROM_UNLOCK 0xDA 82 + #define EEPROM_LOCK 0x00 83 + 84 + #define DC_TI_EEPROM_CC_GAIN_REG 0xF4 85 + #define CC_TRIM_REVISION GENMASK(3, 0) 86 + #define CC_GAIN_CORRECTION GENMASK(7, 4) 87 + 88 + #define PMIC_VERSION_A0_TRIM_REV 3 89 + #define PMIC_VERSION_A1_MIN_TRIM_REV 1 90 + 91 + #define DC_TI_EEPROM_CC_OFFSET_REG 0xFD 92 + 93 + #define DC_TI_EEPROM_CTRL 0xFE 94 + #define EEPROM_BANK0_SEL 0x01 95 + #define EEPROM_BANK1_SEL 0x02 96 + 97 + #define SMPL_INTVL_US 15000 98 + #define SMPL_INTVL_MS (SMPL_INTVL_US / USEC_PER_MSEC) 99 + #define CALIBRATION_TIME_US (10 * SMPL_INTVL_US) 100 + #define SLEEP_SLACK_US 2500 101 + 102 + /* CC gain correction is in 0.0025 increments */ 103 + #define CC_GAIN_STEP 25 104 + #define CC_GAIN_DIV 10000 105 + 106 + /* CC offset is in 0.5 units per 250ms (default sample interval) */ 107 + #define CC_OFFSET_DIV 2 108 + #define CC_OFFSET_SMPL_INTVL_MS 250 109 + 110 + /* CC accumulator scale is 366.2 ųCoulumb / unit */ 111 + #define CC_ACC_TO_UA(acc, smpl_ctr) \ 112 + ((acc) * (3662 * MSEC_PER_SEC / 10) / ((smpl_ctr) * SMPL_INTVL_MS)) 113 + 114 + #define DEV_NAME "chtdc_ti_battery" 115 + 116 + struct dc_ti_battery_chip { 117 + /* Must be the first member see adc-battery-helper documentation */ 118 + struct adc_battery_helper helper; 119 + struct device *dev; 120 + struct regmap *regmap; 121 + struct iio_channel *vbat_channel; 122 + struct power_supply *psy; 123 + int cc_gain; 124 + int cc_offset; 125 + }; 126 + 127 + static int dc_ti_battery_get_voltage_and_current_now(struct power_supply *psy, int *volt, int *curr) 128 + { 129 + struct dc_ti_battery_chip *chip = power_supply_get_drvdata(psy); 130 + s64 cnt_start_usec, now_usec, sleep_usec; 131 + unsigned int reg_val; 132 + s32 acc, smpl_ctr; 133 + int ret; 134 + 135 + /* 136 + * Enable coulomb-counter before reading Vbat from ADC, so that the CC 137 + * samples are from the same time period as the Vbat reading. 138 + */ 139 + ret = regmap_write(chip->regmap, DC_TI_CC_CNTL_REG, 140 + CC_CNTL_SMPL_INTVL_15MS | CC_CNTL_CC_OFFSET_EN | CC_CNTL_CC_CTR_EN); 141 + if (ret) 142 + goto out_err; 143 + 144 + cnt_start_usec = ktime_get_ns() / NSEC_PER_USEC; 145 + 146 + /* Read Vbat, convert IIO mV to power-supply ųV */ 147 + ret = iio_read_channel_processed_scale(chip->vbat_channel, volt, 1000); 148 + if (ret < 0) 149 + goto out_err; 150 + 151 + /* Sleep at least 3 sample-times + slack to get 3+ CC samples */ 152 + now_usec = ktime_get_ns() / NSEC_PER_USEC; 153 + sleep_usec = 3 * SMPL_INTVL_US + SLEEP_SLACK_US - (now_usec - cnt_start_usec); 154 + if (sleep_usec > 0 && sleep_usec < 1000000) 155 + usleep_range(sleep_usec, sleep_usec + SLEEP_SLACK_US); 156 + 157 + /* 158 + * The PMIC latches the coulomb- and sample-counters upon reading the 159 + * CC_ACC0 register. Reading multiple registers at once is not supported. 160 + * 161 + * Step 1: Read CC_ACC0 - CC_ACC3 162 + */ 163 + ret = regmap_read(chip->regmap, DC_TI_CC_ACC0_REG, &reg_val); 164 + if (ret) 165 + goto out_err; 166 + 167 + acc = reg_val; 168 + 169 + ret = regmap_read(chip->regmap, DC_TI_CC_ACC1_REG, &reg_val); 170 + if (ret) 171 + goto out_err; 172 + 173 + acc |= reg_val << 8; 174 + 175 + ret = regmap_read(chip->regmap, DC_TI_CC_ACC2_REG, &reg_val); 176 + if (ret) 177 + goto out_err; 178 + 179 + acc |= reg_val << 16; 180 + 181 + ret = regmap_read(chip->regmap, DC_TI_CC_ACC3_REG, &reg_val); 182 + if (ret) 183 + goto out_err; 184 + 185 + acc |= reg_val << 24; 186 + 187 + /* Step 2: Read SMPL_CTR0 - SMPL_CTR2 */ 188 + ret = regmap_read(chip->regmap, DC_TI_SMPL_CTR0_REG, &reg_val); 189 + if (ret) 190 + goto out_err; 191 + 192 + smpl_ctr = reg_val; 193 + 194 + ret = regmap_read(chip->regmap, DC_TI_SMPL_CTR1_REG, &reg_val); 195 + if (ret) 196 + goto out_err; 197 + 198 + smpl_ctr |= reg_val << 8; 199 + 200 + ret = regmap_read(chip->regmap, DC_TI_SMPL_CTR2_REG, &reg_val); 201 + if (ret) 202 + goto out_err; 203 + 204 + smpl_ctr |= reg_val << 16; 205 + 206 + /* Disable the coulumb-counter again */ 207 + ret = regmap_write(chip->regmap, DC_TI_CC_CNTL_REG, 208 + CC_CNTL_SMPL_INTVL_15MS | CC_CNTL_CC_OFFSET_EN); 209 + if (ret) 210 + goto out_err; 211 + 212 + /* Apply calibration */ 213 + acc -= chip->cc_offset * smpl_ctr * SMPL_INTVL_MS / 214 + (CC_OFFSET_SMPL_INTVL_MS * CC_OFFSET_DIV); 215 + acc = acc * (CC_GAIN_DIV - chip->cc_gain * CC_GAIN_STEP) / CC_GAIN_DIV; 216 + *curr = CC_ACC_TO_UA(acc, smpl_ctr); 217 + 218 + return 0; 219 + 220 + out_err: 221 + dev_err(chip->dev, "IO-error %d communicating with PMIC\n", ret); 222 + return ret; 223 + } 224 + 225 + static const struct power_supply_desc dc_ti_battery_psy_desc = { 226 + .name = "intel_dc_ti_battery", 227 + .type = POWER_SUPPLY_TYPE_BATTERY, 228 + .get_property = adc_battery_helper_get_property, 229 + .external_power_changed = adc_battery_helper_external_power_changed, 230 + .properties = adc_battery_helper_properties, 231 + .num_properties = ADC_HELPER_NUM_PROPERTIES, 232 + }; 233 + 234 + static int dc_ti_battery_hw_init(struct dc_ti_battery_chip *chip) 235 + { 236 + u8 pmic_version, cc_trim_rev; 237 + unsigned int reg_val; 238 + int ret; 239 + 240 + /* Set sample rate to 15 ms and calibrate the coulomb-counter */ 241 + ret = regmap_write(chip->regmap, DC_TI_CC_CNTL_REG, 242 + CC_CNTL_SMPL_INTVL_15MS | CC_CNTL_CC_OFFSET_EN | 243 + CC_CNTL_CC_CAL_EN | CC_CNTL_CC_CTR_EN); 244 + if (ret) 245 + goto out; 246 + 247 + fsleep(CALIBRATION_TIME_US); 248 + 249 + /* Disable coulomb-counter it is only used while getting the current */ 250 + ret = regmap_write(chip->regmap, DC_TI_CC_CNTL_REG, 251 + CC_CNTL_SMPL_INTVL_15MS | CC_CNTL_CC_OFFSET_EN); 252 + if (ret) 253 + goto out; 254 + 255 + ret = regmap_read(chip->regmap, DC_TI_PMIC_VERSION_REG, &reg_val); 256 + if (ret) 257 + goto out; 258 + 259 + pmic_version = reg_val; 260 + 261 + /* 262 + * As per the PMIC vendor (TI), the calibration offset and gain err 263 + * values are stored in EEPROM Bank 0 and Bank 1 of the PMIC. 264 + * We need to read the stored offset and gain margins and need 265 + * to apply the corrections to the raw coulomb counter value. 266 + */ 267 + 268 + /* Unlock the EEPROM Access */ 269 + ret = regmap_write(chip->regmap, DC_TI_EEPROM_ACCESS_CONTROL, EEPROM_UNLOCK); 270 + if (ret) 271 + goto out; 272 + 273 + /* Select Bank 1 to read CC GAIN Err correction */ 274 + ret = regmap_write(chip->regmap, DC_TI_EEPROM_CTRL, EEPROM_BANK1_SEL); 275 + if (ret) 276 + goto out; 277 + 278 + ret = regmap_read(chip->regmap, DC_TI_EEPROM_CC_GAIN_REG, &reg_val); 279 + if (ret) 280 + goto out; 281 + 282 + cc_trim_rev = FIELD_GET(CC_TRIM_REVISION, reg_val); 283 + 284 + dev_dbg(chip->dev, "pmic-ver 0x%02x trim-rev %d\n", pmic_version, cc_trim_rev); 285 + 286 + if (!(pmic_version == PMIC_VERSION_A0 && cc_trim_rev == PMIC_VERSION_A0_TRIM_REV) && 287 + !(pmic_version == PMIC_VERSION_A1 && cc_trim_rev >= PMIC_VERSION_A1_MIN_TRIM_REV)) { 288 + dev_dbg(chip->dev, "unsupported trim-revision, using uncalibrated CC values\n"); 289 + goto out_relock; 290 + } 291 + 292 + chip->cc_gain = 1 - (int)FIELD_GET(CC_GAIN_CORRECTION, reg_val); 293 + 294 + /* Select Bank 0 to read CC OFFSET Correction */ 295 + ret = regmap_write(chip->regmap, DC_TI_EEPROM_CTRL, EEPROM_BANK0_SEL); 296 + if (ret) 297 + goto out_relock; 298 + 299 + ret = regmap_read(chip->regmap, DC_TI_EEPROM_CC_OFFSET_REG, &reg_val); 300 + if (ret) 301 + goto out_relock; 302 + 303 + chip->cc_offset = (s8)reg_val; 304 + 305 + dev_dbg(chip->dev, "cc-offset %d cc-gain %d\n", chip->cc_offset, chip->cc_gain); 306 + 307 + out_relock: 308 + /* Re-lock the EEPROM Access */ 309 + regmap_write(chip->regmap, DC_TI_EEPROM_ACCESS_CONTROL, EEPROM_LOCK); 310 + out: 311 + if (ret) 312 + dev_err(chip->dev, "IO-error %d initializing PMIC\n", ret); 313 + 314 + return ret; 315 + } 316 + 317 + static int dc_ti_battery_probe(struct platform_device *pdev) 318 + { 319 + struct device *dev = &pdev->dev; 320 + struct intel_soc_pmic *pmic = dev_get_drvdata(dev->parent); 321 + struct power_supply_config psy_cfg = {}; 322 + struct fwnode_reference_args args; 323 + struct gpio_desc *charge_finished; 324 + struct dc_ti_battery_chip *chip; 325 + int ret; 326 + 327 + /* On most devices with a Dollar Cove TI the battery is handled by ACPI */ 328 + if (!acpi_quirk_skip_acpi_ac_and_battery()) 329 + return -ENODEV; 330 + 331 + /* ACPI glue code adds a "monitored-battery" fwnode, wait for this */ 332 + ret = fwnode_property_get_reference_args(dev_fwnode(dev), "monitored-battery", 333 + NULL, 0, 0, &args); 334 + if (ret) { 335 + dev_dbg(dev, "fwnode_property_get_ref() ret %d\n", ret); 336 + return dev_err_probe(dev, -EPROBE_DEFER, "Waiting for monitored-battery fwnode\n"); 337 + } 338 + 339 + fwnode_handle_put(args.fwnode); 340 + 341 + chip = devm_kzalloc(dev, sizeof(*chip), GFP_KERNEL); 342 + if (!chip) 343 + return -ENOMEM; 344 + 345 + chip->dev = dev; 346 + chip->regmap = pmic->regmap; 347 + 348 + chip->vbat_channel = devm_iio_channel_get(dev, "VBAT"); 349 + if (IS_ERR(chip->vbat_channel)) { 350 + dev_dbg(dev, "devm_iio_channel_get() ret %ld\n", PTR_ERR(chip->vbat_channel)); 351 + return dev_err_probe(dev, -EPROBE_DEFER, "Waiting for VBAT IIO channel\n"); 352 + } 353 + 354 + charge_finished = devm_gpiod_get_optional(dev, "charged", GPIOD_IN); 355 + if (IS_ERR(charge_finished)) 356 + return dev_err_probe(dev, PTR_ERR(charge_finished), "Getting charged GPIO\n"); 357 + 358 + ret = dc_ti_battery_hw_init(chip); 359 + if (ret) 360 + return ret; 361 + 362 + platform_set_drvdata(pdev, chip); 363 + 364 + psy_cfg.drv_data = chip; 365 + chip->psy = devm_power_supply_register(dev, &dc_ti_battery_psy_desc, &psy_cfg); 366 + if (IS_ERR(chip->psy)) 367 + return PTR_ERR(chip->psy); 368 + 369 + return adc_battery_helper_init(&chip->helper, chip->psy, 370 + dc_ti_battery_get_voltage_and_current_now, 371 + charge_finished); 372 + } 373 + 374 + static DEFINE_RUNTIME_DEV_PM_OPS(dc_ti_battery_pm_ops, adc_battery_helper_suspend, 375 + adc_battery_helper_resume, NULL); 376 + 377 + static struct platform_driver dc_ti_battery_driver = { 378 + .driver = { 379 + .name = DEV_NAME, 380 + .pm = pm_sleep_ptr(&dc_ti_battery_pm_ops), 381 + }, 382 + .probe = dc_ti_battery_probe, 383 + }; 384 + module_platform_driver(dc_ti_battery_driver); 385 + 386 + MODULE_ALIAS("platform:" DEV_NAME); 387 + MODULE_AUTHOR("Hans de Goede <hansg@kernel.org>"); 388 + MODULE_DESCRIPTION("Intel Dollar Cove (TI) battery driver"); 389 + MODULE_LICENSE("GPL");
+2 -1
drivers/power/supply/ipaq_micro_battery.c
··· 232 232 return -ENOMEM; 233 233 234 234 mb->micro = dev_get_drvdata(pdev->dev.parent); 235 - mb->wq = alloc_workqueue("ipaq-battery-wq", WQ_MEM_RECLAIM, 0); 235 + mb->wq = alloc_workqueue("ipaq-battery-wq", 236 + WQ_MEM_RECLAIM | WQ_PERCPU, 0); 236 237 if (!mb->wq) 237 238 return -ENOMEM; 238 239
+203 -127
drivers/power/supply/max77705_charger.c
··· 40 40 POWER_SUPPLY_PROP_INPUT_CURRENT_LIMIT, 41 41 }; 42 42 43 - static int max77705_chgin_irq(void *irq_drv_data) 43 + static irqreturn_t max77705_chgin_irq(int irq, void *irq_drv_data) 44 44 { 45 - struct max77705_charger_data *charger = irq_drv_data; 45 + struct max77705_charger_data *chg = irq_drv_data; 46 46 47 - queue_work(charger->wqueue, &charger->chgin_work); 47 + queue_work(chg->wqueue, &chg->chgin_work); 48 48 49 - return 0; 49 + return IRQ_HANDLED; 50 50 } 51 51 52 52 static const struct regmap_irq max77705_charger_irqs[] = { 53 - { .mask = MAX77705_BYP_IM, }, 54 - { .mask = MAX77705_INP_LIMIT_IM, }, 55 - { .mask = MAX77705_BATP_IM, }, 56 - { .mask = MAX77705_BAT_IM, }, 57 - { .mask = MAX77705_CHG_IM, }, 58 - { .mask = MAX77705_WCIN_IM, }, 59 - { .mask = MAX77705_CHGIN_IM, }, 60 - { .mask = MAX77705_AICL_IM, }, 53 + REGMAP_IRQ_REG_LINE(MAX77705_BYP_I, BITS_PER_BYTE), 54 + REGMAP_IRQ_REG_LINE(MAX77705_INP_LIMIT_I, BITS_PER_BYTE), 55 + REGMAP_IRQ_REG_LINE(MAX77705_BATP_I, BITS_PER_BYTE), 56 + REGMAP_IRQ_REG_LINE(MAX77705_BAT_I, BITS_PER_BYTE), 57 + REGMAP_IRQ_REG_LINE(MAX77705_CHG_I, BITS_PER_BYTE), 58 + REGMAP_IRQ_REG_LINE(MAX77705_WCIN_I, BITS_PER_BYTE), 59 + REGMAP_IRQ_REG_LINE(MAX77705_CHGIN_I, BITS_PER_BYTE), 60 + REGMAP_IRQ_REG_LINE(MAX77705_AICL_I, BITS_PER_BYTE), 61 61 }; 62 62 63 63 static struct regmap_irq_chip max77705_charger_irq_chip = { 64 64 .name = "max77705-charger", 65 65 .status_base = MAX77705_CHG_REG_INT, 66 66 .mask_base = MAX77705_CHG_REG_INT_MASK, 67 - .handle_post_irq = max77705_chgin_irq, 68 67 .num_regs = 1, 69 68 .irqs = max77705_charger_irqs, 70 69 .num_irqs = ARRAY_SIZE(max77705_charger_irqs), ··· 73 74 { 74 75 int rv; 75 76 76 - rv = regmap_update_bits(chg->regmap, MAX77705_CHG_REG_CNFG_09, 77 - MAX77705_CHG_EN_MASK, MAX77705_CHG_EN_MASK); 77 + rv = regmap_field_write(chg->rfield[MAX77705_CHG_EN], 1); 78 78 if (rv) 79 79 dev_err(chg->dev, "unable to enable the charger: %d\n", rv); 80 80 ··· 85 87 struct max77705_charger_data *chg = data; 86 88 int rv; 87 89 88 - rv = regmap_update_bits(chg->regmap, 89 - MAX77705_CHG_REG_CNFG_09, 90 - MAX77705_CHG_EN_MASK, 91 - MAX77705_CHG_DISABLE); 90 + rv = regmap_field_write(chg->rfield[MAX77705_CHG_EN], MAX77705_CHG_DISABLE); 92 91 if (rv) 93 92 dev_err(chg->dev, "unable to disable the charger: %d\n", rv); 94 93 } ··· 104 109 return 0; 105 110 } 106 111 107 - static int max77705_check_battery(struct max77705_charger_data *charger, int *val) 112 + static int max77705_set_integer(struct max77705_charger_data *chg, enum max77705_field_idx fidx, 113 + unsigned int clamp_min, unsigned int clamp_max, 114 + unsigned int div, int val) 115 + { 116 + unsigned int regval; 117 + 118 + regval = clamp_val(val, clamp_min, clamp_max) / div; 119 + 120 + return regmap_field_write(chg->rfield[fidx], regval); 121 + } 122 + 123 + static int max77705_check_battery(struct max77705_charger_data *chg, int *val) 108 124 { 109 125 unsigned int reg_data; 110 126 unsigned int reg_data2; 111 - struct regmap *regmap = charger->regmap; 127 + struct regmap *regmap = chg->regmap; 112 128 113 129 regmap_read(regmap, MAX77705_CHG_REG_INT_OK, &reg_data); 114 130 115 - dev_dbg(charger->dev, "CHG_INT_OK(0x%x)\n", reg_data); 131 + dev_dbg(chg->dev, "CHG_INT_OK(0x%x)\n", reg_data); 116 132 117 133 regmap_read(regmap, MAX77705_CHG_REG_DETAILS_00, &reg_data2); 118 134 119 - dev_dbg(charger->dev, "CHG_DETAILS00(0x%x)\n", reg_data2); 135 + dev_dbg(chg->dev, "CHG_DETAILS00(0x%x)\n", reg_data2); 120 136 121 137 if ((reg_data & MAX77705_BATP_OK) || !(reg_data2 & MAX77705_BATP_DTLS)) 122 138 *val = true; ··· 137 131 return 0; 138 132 } 139 133 140 - static int max77705_get_charge_type(struct max77705_charger_data *charger, int *val) 134 + static int max77705_get_charge_type(struct max77705_charger_data *chg, int *val) 141 135 { 142 - struct regmap *regmap = charger->regmap; 143 - unsigned int reg_data; 136 + struct regmap *regmap = chg->regmap; 137 + unsigned int reg_data, chg_en; 144 138 145 - regmap_read(regmap, MAX77705_CHG_REG_CNFG_09, &reg_data); 146 - if (!MAX77705_CHARGER_CHG_CHARGING(reg_data)) { 139 + regmap_field_read(chg->rfield[MAX77705_CHG_EN], &chg_en); 140 + if (!chg_en) { 147 141 *val = POWER_SUPPLY_CHARGE_TYPE_NONE; 148 142 return 0; 149 143 } ··· 165 159 return 0; 166 160 } 167 161 168 - static int max77705_get_status(struct max77705_charger_data *charger, int *val) 162 + static int max77705_get_status(struct max77705_charger_data *chg, int *val) 169 163 { 170 - struct regmap *regmap = charger->regmap; 171 - unsigned int reg_data; 164 + struct regmap *regmap = chg->regmap; 165 + unsigned int reg_data, chg_en; 172 166 173 - regmap_read(regmap, MAX77705_CHG_REG_CNFG_09, &reg_data); 174 - if (!MAX77705_CHARGER_CHG_CHARGING(reg_data)) { 167 + regmap_field_read(chg->rfield[MAX77705_CHG_EN], &chg_en); 168 + if (!chg_en) { 175 169 *val = POWER_SUPPLY_CHARGE_TYPE_NONE; 176 170 return 0; 177 171 } ··· 240 234 return 0; 241 235 } 242 236 243 - static int max77705_get_battery_health(struct max77705_charger_data *charger, 237 + static int max77705_get_battery_health(struct max77705_charger_data *chg, 244 238 int *value) 245 239 { 246 - struct regmap *regmap = charger->regmap; 240 + struct regmap *regmap = chg->regmap; 247 241 unsigned int bat_dtls; 248 242 249 243 regmap_read(regmap, MAX77705_CHG_REG_DETAILS_01, &bat_dtls); ··· 251 245 252 246 switch (bat_dtls) { 253 247 case MAX77705_BATTERY_NOBAT: 254 - dev_dbg(charger->dev, "%s: No battery and the charger is suspended\n", 248 + dev_dbg(chg->dev, "%s: No battery and the chg is suspended\n", 255 249 __func__); 256 250 *value = POWER_SUPPLY_HEALTH_NO_BATTERY; 257 251 break; 258 252 case MAX77705_BATTERY_PREQUALIFICATION: 259 - dev_dbg(charger->dev, "%s: battery is okay but its voltage is low(~VPQLB)\n", 253 + dev_dbg(chg->dev, "%s: battery is okay but its voltage is low(~VPQLB)\n", 260 254 __func__); 261 255 break; 262 256 case MAX77705_BATTERY_DEAD: 263 - dev_dbg(charger->dev, "%s: battery dead\n", __func__); 257 + dev_dbg(chg->dev, "%s: battery dead\n", __func__); 264 258 *value = POWER_SUPPLY_HEALTH_DEAD; 265 259 break; 266 260 case MAX77705_BATTERY_GOOD: ··· 268 262 *value = POWER_SUPPLY_HEALTH_GOOD; 269 263 break; 270 264 case MAX77705_BATTERY_OVERVOLTAGE: 271 - dev_dbg(charger->dev, "%s: battery ovp\n", __func__); 265 + dev_dbg(chg->dev, "%s: battery ovp\n", __func__); 272 266 *value = POWER_SUPPLY_HEALTH_OVERVOLTAGE; 273 267 break; 274 268 default: 275 - dev_dbg(charger->dev, "%s: battery unknown\n", __func__); 269 + dev_dbg(chg->dev, "%s: battery unknown\n", __func__); 276 270 *value = POWER_SUPPLY_HEALTH_UNSPEC_FAILURE; 277 271 break; 278 272 } ··· 280 274 return 0; 281 275 } 282 276 283 - static int max77705_get_health(struct max77705_charger_data *charger, int *val) 277 + static int max77705_get_health(struct max77705_charger_data *chg, int *val) 284 278 { 285 - struct regmap *regmap = charger->regmap; 279 + struct regmap *regmap = chg->regmap; 286 280 int ret, is_online = 0; 287 281 288 282 ret = max77705_get_online(regmap, &is_online); ··· 293 287 if (ret || (*val != POWER_SUPPLY_HEALTH_GOOD)) 294 288 return ret; 295 289 } 296 - return max77705_get_battery_health(charger, val); 290 + return max77705_get_battery_health(chg, val); 297 291 } 298 292 299 - static int max77705_get_input_current(struct max77705_charger_data *charger, 293 + static int max77705_get_input_current(struct max77705_charger_data *chg, 300 294 int *val) 301 295 { 302 296 unsigned int reg_data; 303 297 int get_current = 0; 304 - struct regmap *regmap = charger->regmap; 305 298 306 - regmap_read(regmap, MAX77705_CHG_REG_CNFG_09, &reg_data); 307 - 308 - reg_data &= MAX77705_CHG_CHGIN_LIM_MASK; 299 + regmap_field_read(chg->rfield[MAX77705_CHG_CHGIN_LIM], &reg_data); 309 300 310 301 if (reg_data <= 3) 311 302 get_current = MAX77705_CURRENT_CHGIN_MIN; 312 - else if (reg_data >= MAX77705_CHG_CHGIN_LIM_MASK) 313 - get_current = MAX77705_CURRENT_CHGIN_MAX; 314 303 else 315 304 get_current = (reg_data + 1) * MAX77705_CURRENT_CHGIN_STEP; 316 305 ··· 314 313 return 0; 315 314 } 316 315 317 - static int max77705_get_charge_current(struct max77705_charger_data *charger, 316 + static int max77705_get_charge_current(struct max77705_charger_data *chg, 318 317 int *val) 319 318 { 320 319 unsigned int reg_data; 321 - struct regmap *regmap = charger->regmap; 322 320 323 - regmap_read(regmap, MAX77705_CHG_REG_CNFG_02, &reg_data); 324 - reg_data &= MAX77705_CHG_CC; 321 + regmap_field_read(chg->rfield[MAX77705_CHG_CC_LIM], &reg_data); 325 322 326 323 *val = reg_data <= 0x2 ? MAX77705_CURRENT_CHGIN_MIN : reg_data * MAX77705_CURRENT_CHG_STEP; 327 324 328 325 return 0; 329 326 } 330 327 331 - static int max77705_set_float_voltage(struct max77705_charger_data *charger, 328 + static int max77705_set_float_voltage(struct max77705_charger_data *chg, 332 329 int float_voltage) 333 330 { 334 331 int float_voltage_mv; 335 332 unsigned int reg_data = 0; 336 - struct regmap *regmap = charger->regmap; 337 333 338 334 float_voltage_mv = float_voltage / 1000; 339 335 reg_data = float_voltage_mv <= 4000 ? 0x0 : ··· 338 340 (float_voltage_mv <= 4200) ? (float_voltage_mv - 4000) / 50 : 339 341 (((float_voltage_mv - 4200) / 10) + 0x04); 340 342 341 - return regmap_update_bits(regmap, MAX77705_CHG_REG_CNFG_04, 342 - MAX77705_CHG_CV_PRM_MASK, 343 - (reg_data << MAX77705_CHG_CV_PRM_SHIFT)); 343 + return regmap_field_write(chg->rfield[MAX77705_CHG_CV_PRM], reg_data); 344 344 } 345 345 346 - static int max77705_get_float_voltage(struct max77705_charger_data *charger, 346 + static int max77705_get_float_voltage(struct max77705_charger_data *chg, 347 347 int *val) 348 348 { 349 349 unsigned int reg_data = 0; 350 350 int voltage_mv; 351 - struct regmap *regmap = charger->regmap; 352 351 353 - regmap_read(regmap, MAX77705_CHG_REG_CNFG_04, &reg_data); 354 - reg_data &= MAX77705_CHG_PRM_MASK; 352 + regmap_field_read(chg->rfield[MAX77705_CHG_CV_PRM], &reg_data); 355 353 voltage_mv = reg_data <= 0x04 ? reg_data * 50 + 4000 : 356 354 (reg_data - 4) * 10 + 4200; 357 355 *val = voltage_mv * 1000; ··· 359 365 enum power_supply_property psp, 360 366 union power_supply_propval *val) 361 367 { 362 - struct max77705_charger_data *charger = power_supply_get_drvdata(psy); 363 - struct regmap *regmap = charger->regmap; 368 + struct max77705_charger_data *chg = power_supply_get_drvdata(psy); 369 + struct regmap *regmap = chg->regmap; 364 370 365 371 switch (psp) { 366 372 case POWER_SUPPLY_PROP_ONLINE: 367 373 return max77705_get_online(regmap, &val->intval); 368 374 case POWER_SUPPLY_PROP_PRESENT: 369 - return max77705_check_battery(charger, &val->intval); 375 + return max77705_check_battery(chg, &val->intval); 370 376 case POWER_SUPPLY_PROP_STATUS: 371 - return max77705_get_status(charger, &val->intval); 377 + return max77705_get_status(chg, &val->intval); 372 378 case POWER_SUPPLY_PROP_CHARGE_TYPE: 373 - return max77705_get_charge_type(charger, &val->intval); 379 + return max77705_get_charge_type(chg, &val->intval); 374 380 case POWER_SUPPLY_PROP_HEALTH: 375 - return max77705_get_health(charger, &val->intval); 381 + return max77705_get_health(chg, &val->intval); 376 382 case POWER_SUPPLY_PROP_INPUT_CURRENT_LIMIT: 377 - return max77705_get_input_current(charger, &val->intval); 383 + return max77705_get_input_current(chg, &val->intval); 378 384 case POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT: 379 - return max77705_get_charge_current(charger, &val->intval); 385 + return max77705_get_charge_current(chg, &val->intval); 380 386 case POWER_SUPPLY_PROP_CONSTANT_CHARGE_VOLTAGE: 381 - return max77705_get_float_voltage(charger, &val->intval); 387 + return max77705_get_float_voltage(chg, &val->intval); 382 388 case POWER_SUPPLY_PROP_VOLTAGE_MAX_DESIGN: 383 - val->intval = charger->bat_info->voltage_max_design_uv; 389 + val->intval = chg->bat_info->voltage_max_design_uv; 384 390 break; 385 391 case POWER_SUPPLY_PROP_MODEL_NAME: 386 392 val->strval = max77705_charger_model; ··· 394 400 return 0; 395 401 } 396 402 403 + static int max77705_set_property(struct power_supply *psy, 404 + enum power_supply_property psp, 405 + const union power_supply_propval *val) 406 + { 407 + struct max77705_charger_data *chg = power_supply_get_drvdata(psy); 408 + int err = 0; 409 + 410 + switch (psp) { 411 + case POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT: 412 + err = max77705_set_integer(chg, MAX77705_CHG_CC_LIM, 413 + MAX77705_CURRENT_CHGIN_MIN, 414 + MAX77705_CURRENT_CHGIN_MAX, 415 + MAX77705_CURRENT_CHG_STEP, 416 + val->intval); 417 + break; 418 + case POWER_SUPPLY_PROP_INPUT_CURRENT_LIMIT: 419 + err = max77705_set_integer(chg, MAX77705_CHG_CHGIN_LIM, 420 + MAX77705_CURRENT_CHGIN_MIN, 421 + MAX77705_CURRENT_CHGIN_MAX, 422 + MAX77705_CURRENT_CHGIN_STEP, 423 + val->intval); 424 + break; 425 + default: 426 + err = -EINVAL; 427 + } 428 + 429 + return err; 430 + }; 431 + 432 + static int max77705_property_is_writeable(struct power_supply *psy, 433 + enum power_supply_property psp) 434 + { 435 + switch (psp) { 436 + case POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT: 437 + case POWER_SUPPLY_PROP_INPUT_CURRENT_LIMIT: 438 + return true; 439 + default: 440 + return false; 441 + } 442 + } 443 + 397 444 static const struct power_supply_desc max77705_charger_psy_desc = { 398 445 .name = "max77705-charger", 399 - .type = POWER_SUPPLY_TYPE_USB, 446 + .type = POWER_SUPPLY_TYPE_USB, 400 447 .properties = max77705_charger_props, 448 + .property_is_writeable = max77705_property_is_writeable, 401 449 .num_properties = ARRAY_SIZE(max77705_charger_props), 402 450 .get_property = max77705_chg_get_property, 451 + .set_property = max77705_set_property, 403 452 }; 404 453 405 454 static void max77705_chgin_isr_work(struct work_struct *work) 406 455 { 407 - struct max77705_charger_data *charger = 456 + struct max77705_charger_data *chg = 408 457 container_of(work, struct max77705_charger_data, chgin_work); 409 458 410 - power_supply_changed(charger->psy_chg); 459 + power_supply_changed(chg->psy_chg); 411 460 } 412 461 413 - static void max77705_charger_initialize(struct max77705_charger_data *chg) 462 + static int max77705_charger_initialize(struct max77705_charger_data *chg) 414 463 { 415 - u8 reg_data; 416 464 struct power_supply_battery_info *info; 417 465 struct regmap *regmap = chg->regmap; 466 + int err; 418 467 419 - if (power_supply_get_battery_info(chg->psy_chg, &info) < 0) 420 - return; 468 + err = power_supply_get_battery_info(chg->psy_chg, &info); 469 + if (err) 470 + return dev_err_probe(chg->dev, err, "error on getting battery info"); 421 471 422 472 chg->bat_info = info; 423 473 424 474 /* unlock charger setting protect */ 425 475 /* slowest LX slope */ 426 - reg_data = MAX77705_CHGPROT_MASK | MAX77705_SLOWEST_LX_SLOPE; 427 - regmap_update_bits(regmap, MAX77705_CHG_REG_CNFG_06, reg_data, 428 - reg_data); 476 + err = regmap_field_write(chg->rfield[MAX77705_CHGPROT], MAX77705_CHGPROT_UNLOCKED); 477 + if (err) 478 + goto err; 479 + 480 + err = regmap_field_write(chg->rfield[MAX77705_LX_SLOPE], MAX77705_SLOWEST_LX_SLOPE); 481 + if (err) 482 + goto err; 429 483 430 484 /* fast charge timer disable */ 431 485 /* restart threshold disable */ 432 486 /* pre-qual charge disable */ 433 - reg_data = (MAX77705_FCHGTIME_DISABLE << MAX77705_FCHGTIME_SHIFT) | 434 - (MAX77705_CHG_RSTRT_DISABLE << MAX77705_CHG_RSTRT_SHIFT) | 435 - (MAX77705_CHG_PQEN_DISABLE << MAX77705_PQEN_SHIFT); 436 - regmap_update_bits(regmap, MAX77705_CHG_REG_CNFG_01, 437 - (MAX77705_FCHGTIME_MASK | 438 - MAX77705_CHG_RSTRT_MASK | 439 - MAX77705_PQEN_MASK), 440 - reg_data); 487 + err = regmap_field_write(chg->rfield[MAX77705_FCHGTIME], MAX77705_FCHGTIME_DISABLE); 488 + if (err) 489 + goto err; 441 490 442 - /* OTG off(UNO on), boost off */ 443 - regmap_update_bits(regmap, MAX77705_CHG_REG_CNFG_00, 444 - MAX77705_OTG_CTRL, 0); 491 + err = regmap_field_write(chg->rfield[MAX77705_CHG_RSTRT], MAX77705_CHG_RSTRT_DISABLE); 492 + if (err) 493 + goto err; 494 + 495 + err = regmap_field_write(chg->rfield[MAX77705_CHG_PQEN], MAX77705_CHG_PQEN_DISABLE); 496 + if (err) 497 + goto err; 498 + 499 + err = regmap_field_write(chg->rfield[MAX77705_MODE], 500 + MAX77705_CHG_MASK | MAX77705_BUCK_MASK); 501 + if (err) 502 + goto err; 445 503 446 504 /* charge current 450mA(default) */ 447 505 /* otg current limit 900mA */ 448 - regmap_update_bits(regmap, MAX77705_CHG_REG_CNFG_02, 449 - MAX77705_OTG_ILIM_MASK, 450 - MAX77705_OTG_ILIM_900 << MAX77705_OTG_ILIM_SHIFT); 506 + err = regmap_field_write(chg->rfield[MAX77705_OTG_ILIM], MAX77705_OTG_ILIM_900); 507 + if (err) 508 + goto err; 451 509 452 510 /* BAT to SYS OCP 4.80A */ 453 - regmap_update_bits(regmap, MAX77705_CHG_REG_CNFG_05, 454 - MAX77705_REG_B2SOVRC_MASK, 455 - MAX77705_B2SOVRC_4_8A << MAX77705_REG_B2SOVRC_SHIFT); 511 + err = regmap_field_write(chg->rfield[MAX77705_REG_B2SOVRC], MAX77705_B2SOVRC_4_8A); 512 + if (err) 513 + goto err; 514 + 456 515 /* top off current 150mA */ 457 516 /* top off timer 30min */ 458 - reg_data = (MAX77705_TO_ITH_150MA << MAX77705_TO_ITH_SHIFT) | 459 - (MAX77705_TO_TIME_30M << MAX77705_TO_TIME_SHIFT) | 460 - (MAX77705_SYS_TRACK_DISABLE << MAX77705_SYS_TRACK_DIS_SHIFT); 461 - regmap_update_bits(regmap, MAX77705_CHG_REG_CNFG_03, 462 - (MAX77705_TO_ITH_MASK | 463 - MAX77705_TO_TIME_MASK | 464 - MAX77705_SYS_TRACK_DIS_MASK), reg_data); 517 + err = regmap_field_write(chg->rfield[MAX77705_TO], MAX77705_TO_ITH_150MA); 518 + if (err) 519 + goto err; 520 + 521 + err = regmap_field_write(chg->rfield[MAX77705_TO_TIME], MAX77705_TO_TIME_30M); 522 + if (err) 523 + goto err; 524 + 525 + err = regmap_field_write(chg->rfield[MAX77705_SYS_TRACK], MAX77705_SYS_TRACK_DISABLE); 526 + if (err) 527 + goto err; 465 528 466 529 /* cv voltage 4.2V or 4.35V */ 467 530 /* MINVSYS 3.6V(default) */ ··· 529 478 max77705_set_float_voltage(chg, info->voltage_max_design_uv); 530 479 } 531 480 532 - regmap_update_bits(regmap, MAX77705_CHG_REG_CNFG_12, 533 - MAX77705_VCHGIN_REG_MASK, MAX77705_VCHGIN_4_5); 534 - regmap_update_bits(regmap, MAX77705_CHG_REG_CNFG_12, 535 - MAX77705_WCIN_REG_MASK, MAX77705_WCIN_4_5); 481 + err = regmap_field_write(chg->rfield[MAX77705_VCHGIN], MAX77705_VCHGIN_4_5); 482 + if (err) 483 + goto err; 484 + 485 + err = regmap_field_write(chg->rfield[MAX77705_WCIN], MAX77705_WCIN_4_5); 486 + if (err) 487 + goto err; 536 488 537 489 /* Watchdog timer */ 538 490 regmap_update_bits(regmap, MAX77705_CHG_REG_CNFG_00, 539 491 MAX77705_WDTEN_MASK, 0); 540 492 541 - /* Active Discharge Enable */ 542 - regmap_update_bits(regmap, MAX77705_PMIC_REG_MAINCTRL1, 1, 1); 543 - 544 493 /* VBYPSET=5.0V */ 545 - regmap_update_bits(regmap, MAX77705_CHG_REG_CNFG_11, MAX77705_VBYPSET_MASK, 0); 494 + err = regmap_field_write(chg->rfield[MAX77705_VBYPSET], 0); 495 + if (err) 496 + goto err; 546 497 547 498 /* Switching Frequency : 1.5MHz */ 548 - regmap_update_bits(regmap, MAX77705_CHG_REG_CNFG_08, MAX77705_REG_FSW_MASK, 549 - (MAX77705_CHG_FSW_1_5MHz << MAX77705_REG_FSW_SHIFT)); 499 + err = regmap_field_write(chg->rfield[MAX77705_REG_FSW], MAX77705_CHG_FSW_1_5MHz); 500 + if (err) 501 + goto err; 550 502 551 503 /* Auto skip mode */ 552 - regmap_update_bits(regmap, MAX77705_CHG_REG_CNFG_12, MAX77705_REG_DISKIP_MASK, 553 - (MAX77705_AUTO_SKIP << MAX77705_REG_DISKIP_SHIFT)); 504 + err = regmap_field_write(chg->rfield[MAX77705_REG_DISKIP], MAX77705_AUTO_SKIP); 505 + if (err) 506 + goto err; 507 + 508 + return 0; 509 + 510 + err: 511 + return dev_err_probe(chg->dev, err, "error while configuring"); 512 + 554 513 } 555 514 556 515 static int max77705_charger_probe(struct i2c_client *i2c) ··· 584 523 if (IS_ERR(chg->regmap)) 585 524 return PTR_ERR(chg->regmap); 586 525 587 - ret = regmap_update_bits(chg->regmap, 588 - MAX77705_CHG_REG_INT_MASK, 589 - MAX77705_CHGIN_IM, 0); 590 - if (ret) 591 - return ret; 526 + for (int i = 0; i < MAX77705_N_REGMAP_FIELDS; i++) { 527 + chg->rfield[i] = devm_regmap_field_alloc(dev, chg->regmap, 528 + max77705_reg_field[i]); 529 + if (IS_ERR(chg->rfield[i])) 530 + return dev_err_probe(dev, PTR_ERR(chg->rfield[i]), 531 + "cannot allocate regmap field\n"); 532 + } 592 533 593 534 pscfg.fwnode = dev_fwnode(dev); 594 535 pscfg.drv_data = chg; ··· 601 538 602 539 max77705_charger_irq_chip.irq_drv_data = chg; 603 540 ret = devm_regmap_add_irq_chip(chg->dev, chg->regmap, i2c->irq, 604 - IRQF_ONESHOT | IRQF_SHARED, 0, 541 + IRQF_ONESHOT, 0, 605 542 &max77705_charger_irq_chip, 606 543 &irq_data); 607 544 if (ret) ··· 609 546 610 547 chg->wqueue = create_singlethread_workqueue(dev_name(dev)); 611 548 if (!chg->wqueue) 612 - return dev_err_probe(dev, -ENOMEM, "failed to create workqueue\n"); 549 + return -ENOMEM; 613 550 614 551 ret = devm_work_autocancel(dev, &chg->chgin_work, max77705_chgin_isr_work); 615 552 if (ret) { ··· 617 554 goto destroy_wq; 618 555 } 619 556 620 - max77705_charger_initialize(chg); 557 + ret = max77705_charger_initialize(chg); 558 + if (ret) { 559 + dev_err_probe(dev, ret, "failed to initialize charger IC\n"); 560 + goto destroy_wq; 561 + } 562 + 563 + ret = devm_request_threaded_irq(dev, regmap_irq_get_virq(irq_data, MAX77705_CHGIN_I), 564 + NULL, max77705_chgin_irq, 565 + IRQF_TRIGGER_NONE, 566 + "chgin-irq", chg); 567 + if (ret) { 568 + dev_err_probe(dev, ret, "Failed to Request chgin IRQ\n"); 569 + goto destroy_wq; 570 + } 621 571 622 572 ret = max77705_charger_enable(chg); 623 573 if (ret) {
+6 -6
drivers/power/supply/max77976_charger.c
··· 292 292 case POWER_SUPPLY_PROP_ONLINE: 293 293 err = max77976_get_online(chg, &val->intval); 294 294 break; 295 - case POWER_SUPPLY_PROP_CHARGE_CONTROL_LIMIT_MAX: 295 + case POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT_MAX: 296 296 val->intval = MAX77976_CHG_CC_MAX; 297 297 break; 298 - case POWER_SUPPLY_PROP_CHARGE_CONTROL_LIMIT: 298 + case POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT: 299 299 err = max77976_get_integer(chg, CHG_CC, 300 300 MAX77976_CHG_CC_MIN, 301 301 MAX77976_CHG_CC_MAX, ··· 330 330 int err = 0; 331 331 332 332 switch (psp) { 333 - case POWER_SUPPLY_PROP_CHARGE_CONTROL_LIMIT: 333 + case POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT: 334 334 err = max77976_set_integer(chg, CHG_CC, 335 335 MAX77976_CHG_CC_MIN, 336 336 MAX77976_CHG_CC_MAX, ··· 355 355 enum power_supply_property psp) 356 356 { 357 357 switch (psp) { 358 - case POWER_SUPPLY_PROP_CHARGE_CONTROL_LIMIT: 358 + case POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT: 359 359 case POWER_SUPPLY_PROP_INPUT_CURRENT_LIMIT: 360 360 return true; 361 361 default: ··· 368 368 POWER_SUPPLY_PROP_CHARGE_TYPE, 369 369 POWER_SUPPLY_PROP_HEALTH, 370 370 POWER_SUPPLY_PROP_ONLINE, 371 - POWER_SUPPLY_PROP_CHARGE_CONTROL_LIMIT, 372 - POWER_SUPPLY_PROP_CHARGE_CONTROL_LIMIT_MAX, 371 + POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT, 372 + POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT_MAX, 373 373 POWER_SUPPLY_PROP_INPUT_CURRENT_LIMIT, 374 374 POWER_SUPPLY_PROP_MODEL_NAME, 375 375 POWER_SUPPLY_PROP_MANUFACTURER,
+4 -14
drivers/power/supply/mt6370-charger.c
··· 761 761 return PTR_ERR_OR_ZERO(priv->psy); 762 762 } 763 763 764 - static void mt6370_chg_destroy_attach_lock(void *data) 765 - { 766 - struct mutex *attach_lock = data; 767 - 768 - mutex_destroy(attach_lock); 769 - } 770 - 771 764 static void mt6370_chg_destroy_wq(void *data) 772 765 { 773 766 struct workqueue_struct *wq = data; ··· 887 894 if (ret) 888 895 return dev_err_probe(dev, ret, "Failed to init psy\n"); 889 896 890 - mutex_init(&priv->attach_lock); 891 - ret = devm_add_action_or_reset(dev, mt6370_chg_destroy_attach_lock, 892 - &priv->attach_lock); 897 + ret = devm_mutex_init(dev, &priv->attach_lock); 893 898 if (ret) 894 - return dev_err_probe(dev, ret, "Failed to init attach lock\n"); 899 + return ret; 895 900 896 901 priv->attach = MT6370_ATTACH_STAT_DETACH; 897 902 898 903 priv->wq = create_singlethread_workqueue(dev_name(priv->dev)); 899 904 if (!priv->wq) 900 - return dev_err_probe(dev, -ENOMEM, 901 - "Failed to create workqueue\n"); 905 + return -ENOMEM; 902 906 903 907 ret = devm_add_action_or_reset(dev, mt6370_chg_destroy_wq, priv->wq); 904 908 if (ret) 905 - return dev_err_probe(dev, ret, "Failed to init wq\n"); 909 + return ret; 906 910 907 911 ret = devm_work_autocancel(dev, &priv->bc12_work, mt6370_chg_bc12_work_func); 908 912 if (ret)
+2
drivers/power/supply/power_supply_sysfs.c
··· 223 223 POWER_SUPPLY_ATTR(MANUFACTURE_YEAR), 224 224 POWER_SUPPLY_ATTR(MANUFACTURE_MONTH), 225 225 POWER_SUPPLY_ATTR(MANUFACTURE_DAY), 226 + POWER_SUPPLY_ATTR(INTERNAL_RESISTANCE), 227 + POWER_SUPPLY_ATTR(STATE_OF_HEALTH), 226 228 /* Properties of type `const char *' */ 227 229 POWER_SUPPLY_ATTR(MODEL_NAME), 228 230 POWER_SUPPLY_ATTR(MANUFACTURER),
+313 -11
drivers/power/supply/qcom_battmgr.c
··· 2 2 /* 3 3 * Copyright (c) 2019-2020, The Linux Foundation. All rights reserved. 4 4 * Copyright (c) 2022, Linaro Ltd 5 + * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. 5 6 */ 6 7 #include <linux/auxiliary_bus.h> 7 8 #include <linux/module.h> 8 9 #include <linux/mutex.h> 10 + #include <linux/nvmem-consumer.h> 9 11 #include <linux/of_device.h> 10 12 #include <linux/power_supply.h> 11 13 #include <linux/property.h> ··· 20 18 #define BATTMGR_STRING_LEN 128 21 19 22 20 enum qcom_battmgr_variant { 23 - QCOM_BATTMGR_SM8350, 24 21 QCOM_BATTMGR_SC8280XP, 22 + QCOM_BATTMGR_SM8350, 23 + QCOM_BATTMGR_SM8550, 24 + QCOM_BATTMGR_X1E80100, 25 25 }; 26 26 27 27 #define BATTMGR_BAT_STATUS 0x1 ··· 34 30 #define NOTIF_BAT_PROPERTY 0x30 35 31 #define NOTIF_USB_PROPERTY 0x32 36 32 #define NOTIF_WLS_PROPERTY 0x34 37 - #define NOTIF_BAT_INFO 0x81 38 33 #define NOTIF_BAT_STATUS 0x80 34 + #define NOTIF_BAT_INFO 0x81 35 + #define NOTIF_BAT_CHARGING_STATE 0x83 39 36 40 37 #define BATTMGR_BAT_INFO 0x9 41 38 ··· 70 65 #define BATT_RESISTANCE 21 71 66 #define BATT_POWER_NOW 22 72 67 #define BATT_POWER_AVG 23 68 + #define BATT_CHG_CTRL_EN 24 69 + #define BATT_CHG_CTRL_START_THR 25 70 + #define BATT_CHG_CTRL_END_THR 26 73 71 74 72 #define BATTMGR_USB_PROPERTY_GET 0x32 75 73 #define BATTMGR_USB_PROPERTY_SET 0x33 ··· 96 88 #define WLS_CURR_MAX 4 97 89 #define WLS_TYPE 5 98 90 #define WLS_BOOST_EN 6 91 + 92 + #define BATTMGR_CHG_CTRL_LIMIT_EN 0x48 93 + #define CHARGE_CTRL_START_THR_MIN 50 94 + #define CHARGE_CTRL_START_THR_MAX 95 95 + #define CHARGE_CTRL_END_THR_MIN 55 96 + #define CHARGE_CTRL_END_THR_MAX 100 97 + #define CHARGE_CTRL_DELTA_SOC 5 99 98 100 99 struct qcom_battmgr_enable_request { 101 100 struct pmic_glink_hdr hdr; ··· 136 121 __le32 battery_id; 137 122 __le32 rate; /* 0 for current rate */ 138 123 __le32 reserved; 124 + }; 125 + 126 + struct qcom_battmgr_charge_ctrl_request { 127 + struct pmic_glink_hdr hdr; 128 + __le32 enable; 129 + __le32 target_soc; 130 + __le32 delta_soc; 139 131 }; 140 132 141 133 struct qcom_battmgr_message { ··· 257 235 unsigned int capacity_warning; 258 236 unsigned int cycle_count; 259 237 unsigned int charge_count; 238 + unsigned int charge_ctrl_start; 239 + unsigned int charge_ctrl_end; 260 240 char model_number[BATTMGR_STRING_LEN]; 261 241 char serial_number[BATTMGR_STRING_LEN]; 262 242 char oem_info[BATTMGR_STRING_LEN]; ··· 278 254 unsigned int voltage_now; 279 255 unsigned int voltage_ocv; 280 256 unsigned int temperature; 257 + unsigned int resistance; 258 + unsigned int soh_percent; 281 259 282 260 unsigned int discharge_time; 283 261 unsigned int charge_time; ··· 444 418 [POWER_SUPPLY_PROP_MODEL_NAME] = BATT_MODEL_NAME, 445 419 [POWER_SUPPLY_PROP_TIME_TO_FULL_AVG] = BATT_TTF_AVG, 446 420 [POWER_SUPPLY_PROP_TIME_TO_EMPTY_AVG] = BATT_TTE_AVG, 421 + [POWER_SUPPLY_PROP_INTERNAL_RESISTANCE] = BATT_RESISTANCE, 422 + [POWER_SUPPLY_PROP_STATE_OF_HEALTH] = BATT_SOH, 447 423 [POWER_SUPPLY_PROP_POWER_NOW] = BATT_POWER_NOW, 424 + [POWER_SUPPLY_PROP_CHARGE_CONTROL_START_THRESHOLD] = BATT_CHG_CTRL_START_THR, 425 + [POWER_SUPPLY_PROP_CHARGE_CONTROL_END_THRESHOLD] = BATT_CHG_CTRL_END_THR, 448 426 }; 449 427 450 428 static int qcom_battmgr_bat_sm8350_update(struct qcom_battmgr *battmgr, ··· 519 489 if (!battmgr->service_up) 520 490 return -EAGAIN; 521 491 522 - if (battmgr->variant == QCOM_BATTMGR_SC8280XP) 492 + if (battmgr->variant == QCOM_BATTMGR_SC8280XP || 493 + battmgr->variant == QCOM_BATTMGR_X1E80100) 523 494 ret = qcom_battmgr_bat_sc8280xp_update(battmgr, psp); 524 495 else 525 496 ret = qcom_battmgr_bat_sm8350_update(battmgr, psp); ··· 615 584 case POWER_SUPPLY_PROP_TEMP: 616 585 val->intval = battmgr->status.temperature; 617 586 break; 587 + case POWER_SUPPLY_PROP_INTERNAL_RESISTANCE: 588 + val->intval = battmgr->status.resistance; 589 + break; 590 + case POWER_SUPPLY_PROP_STATE_OF_HEALTH: 591 + val->intval = battmgr->status.soh_percent; 592 + break; 618 593 case POWER_SUPPLY_PROP_TIME_TO_EMPTY_AVG: 619 594 val->intval = battmgr->status.discharge_time; 620 595 break; 621 596 case POWER_SUPPLY_PROP_TIME_TO_FULL_AVG: 622 597 val->intval = battmgr->status.charge_time; 598 + break; 599 + case POWER_SUPPLY_PROP_CHARGE_CONTROL_START_THRESHOLD: 600 + val->intval = battmgr->info.charge_ctrl_start; 601 + break; 602 + case POWER_SUPPLY_PROP_CHARGE_CONTROL_END_THRESHOLD: 603 + val->intval = battmgr->info.charge_ctrl_end; 623 604 break; 624 605 case POWER_SUPPLY_PROP_MANUFACTURE_YEAR: 625 606 val->intval = battmgr->info.year; ··· 651 608 case POWER_SUPPLY_PROP_SERIAL_NUMBER: 652 609 val->strval = battmgr->info.serial_number; 653 610 break; 611 + default: 612 + return -EINVAL; 613 + } 614 + 615 + return 0; 616 + } 617 + 618 + static int qcom_battmgr_set_charge_control(struct qcom_battmgr *battmgr, 619 + u32 target_soc, u32 delta_soc) 620 + { 621 + struct qcom_battmgr_charge_ctrl_request request = { 622 + .hdr.owner = cpu_to_le32(PMIC_GLINK_OWNER_BATTMGR), 623 + .hdr.type = cpu_to_le32(PMIC_GLINK_REQ_RESP), 624 + .hdr.opcode = cpu_to_le32(BATTMGR_CHG_CTRL_LIMIT_EN), 625 + .enable = cpu_to_le32(1), 626 + .target_soc = cpu_to_le32(target_soc), 627 + .delta_soc = cpu_to_le32(delta_soc), 628 + }; 629 + 630 + return qcom_battmgr_request(battmgr, &request, sizeof(request)); 631 + } 632 + 633 + static int qcom_battmgr_set_charge_start_threshold(struct qcom_battmgr *battmgr, int start_soc) 634 + { 635 + u32 target_soc, delta_soc; 636 + int ret; 637 + 638 + if (start_soc < CHARGE_CTRL_START_THR_MIN || 639 + start_soc > CHARGE_CTRL_START_THR_MAX) { 640 + dev_err(battmgr->dev, "charge control start threshold exceed range: [%u - %u]\n", 641 + CHARGE_CTRL_START_THR_MIN, CHARGE_CTRL_START_THR_MAX); 642 + return -EINVAL; 643 + } 644 + 645 + /* 646 + * If the new start threshold is larger than the old end threshold, 647 + * move the end threshold one step (DELTA_SOC) after the new start 648 + * threshold. 649 + */ 650 + if (start_soc > battmgr->info.charge_ctrl_end) { 651 + target_soc = start_soc + CHARGE_CTRL_DELTA_SOC; 652 + target_soc = min_t(u32, target_soc, CHARGE_CTRL_END_THR_MAX); 653 + delta_soc = target_soc - start_soc; 654 + delta_soc = min_t(u32, delta_soc, CHARGE_CTRL_DELTA_SOC); 655 + } else { 656 + target_soc = battmgr->info.charge_ctrl_end; 657 + delta_soc = battmgr->info.charge_ctrl_end - start_soc; 658 + } 659 + 660 + mutex_lock(&battmgr->lock); 661 + ret = qcom_battmgr_set_charge_control(battmgr, target_soc, delta_soc); 662 + mutex_unlock(&battmgr->lock); 663 + if (!ret) { 664 + battmgr->info.charge_ctrl_start = start_soc; 665 + battmgr->info.charge_ctrl_end = target_soc; 666 + } 667 + 668 + return 0; 669 + } 670 + 671 + static int qcom_battmgr_set_charge_end_threshold(struct qcom_battmgr *battmgr, int end_soc) 672 + { 673 + u32 delta_soc = CHARGE_CTRL_DELTA_SOC; 674 + int ret; 675 + 676 + if (end_soc < CHARGE_CTRL_END_THR_MIN || 677 + end_soc > CHARGE_CTRL_END_THR_MAX) { 678 + dev_err(battmgr->dev, "charge control end threshold exceed range: [%u - %u]\n", 679 + CHARGE_CTRL_END_THR_MIN, CHARGE_CTRL_END_THR_MAX); 680 + return -EINVAL; 681 + } 682 + 683 + if (battmgr->info.charge_ctrl_start && end_soc > battmgr->info.charge_ctrl_start) 684 + delta_soc = end_soc - battmgr->info.charge_ctrl_start; 685 + 686 + mutex_lock(&battmgr->lock); 687 + ret = qcom_battmgr_set_charge_control(battmgr, end_soc, delta_soc); 688 + mutex_unlock(&battmgr->lock); 689 + if (!ret) { 690 + battmgr->info.charge_ctrl_start = end_soc - delta_soc; 691 + battmgr->info.charge_ctrl_end = end_soc; 692 + } 693 + 694 + return 0; 695 + } 696 + 697 + static int qcom_battmgr_charge_control_thresholds_init(struct qcom_battmgr *battmgr) 698 + { 699 + int ret; 700 + u8 en, end_soc, start_soc, delta_soc; 701 + 702 + ret = nvmem_cell_read_u8(battmgr->dev->parent, "charge_limit_en", &en); 703 + if (!ret && en != 0) { 704 + ret = nvmem_cell_read_u8(battmgr->dev->parent, "charge_limit_end", &end_soc); 705 + if (ret < 0) 706 + return ret; 707 + 708 + ret = nvmem_cell_read_u8(battmgr->dev->parent, "charge_limit_delta", &delta_soc); 709 + if (ret < 0) 710 + return ret; 711 + 712 + if (delta_soc >= end_soc) 713 + return -EINVAL; 714 + 715 + start_soc = end_soc - delta_soc; 716 + end_soc = clamp(end_soc, CHARGE_CTRL_END_THR_MIN, CHARGE_CTRL_END_THR_MAX); 717 + start_soc = clamp(start_soc, CHARGE_CTRL_START_THR_MIN, CHARGE_CTRL_START_THR_MAX); 718 + 719 + battmgr->info.charge_ctrl_start = start_soc; 720 + battmgr->info.charge_ctrl_end = end_soc; 721 + } 722 + 723 + return 0; 724 + } 725 + 726 + static int qcom_battmgr_bat_is_writeable(struct power_supply *psy, 727 + enum power_supply_property psp) 728 + { 729 + switch (psp) { 730 + case POWER_SUPPLY_PROP_CHARGE_CONTROL_START_THRESHOLD: 731 + case POWER_SUPPLY_PROP_CHARGE_CONTROL_END_THRESHOLD: 732 + return 1; 733 + default: 734 + return 0; 735 + } 736 + 737 + return 0; 738 + } 739 + 740 + static int qcom_battmgr_bat_set_property(struct power_supply *psy, 741 + enum power_supply_property psp, 742 + const union power_supply_propval *pval) 743 + { 744 + struct qcom_battmgr *battmgr = power_supply_get_drvdata(psy); 745 + 746 + if (!battmgr->service_up) 747 + return -EAGAIN; 748 + 749 + switch (psp) { 750 + case POWER_SUPPLY_PROP_CHARGE_CONTROL_START_THRESHOLD: 751 + return qcom_battmgr_set_charge_start_threshold(battmgr, pval->intval); 752 + case POWER_SUPPLY_PROP_CHARGE_CONTROL_END_THRESHOLD: 753 + return qcom_battmgr_set_charge_end_threshold(battmgr, pval->intval); 654 754 default: 655 755 return -EINVAL; 656 756 } ··· 835 649 .get_property = qcom_battmgr_bat_get_property, 836 650 }; 837 651 652 + static const enum power_supply_property x1e80100_bat_props[] = { 653 + POWER_SUPPLY_PROP_STATUS, 654 + POWER_SUPPLY_PROP_PRESENT, 655 + POWER_SUPPLY_PROP_TECHNOLOGY, 656 + POWER_SUPPLY_PROP_CYCLE_COUNT, 657 + POWER_SUPPLY_PROP_VOLTAGE_MAX_DESIGN, 658 + POWER_SUPPLY_PROP_VOLTAGE_NOW, 659 + POWER_SUPPLY_PROP_POWER_NOW, 660 + POWER_SUPPLY_PROP_CHARGE_FULL_DESIGN, 661 + POWER_SUPPLY_PROP_CHARGE_FULL, 662 + POWER_SUPPLY_PROP_CHARGE_EMPTY, 663 + POWER_SUPPLY_PROP_CHARGE_NOW, 664 + POWER_SUPPLY_PROP_ENERGY_FULL_DESIGN, 665 + POWER_SUPPLY_PROP_ENERGY_FULL, 666 + POWER_SUPPLY_PROP_ENERGY_EMPTY, 667 + POWER_SUPPLY_PROP_ENERGY_NOW, 668 + POWER_SUPPLY_PROP_TEMP, 669 + POWER_SUPPLY_PROP_MANUFACTURE_YEAR, 670 + POWER_SUPPLY_PROP_MANUFACTURE_MONTH, 671 + POWER_SUPPLY_PROP_MANUFACTURE_DAY, 672 + POWER_SUPPLY_PROP_MODEL_NAME, 673 + POWER_SUPPLY_PROP_MANUFACTURER, 674 + POWER_SUPPLY_PROP_SERIAL_NUMBER, 675 + POWER_SUPPLY_PROP_CHARGE_CONTROL_START_THRESHOLD, 676 + POWER_SUPPLY_PROP_CHARGE_CONTROL_END_THRESHOLD, 677 + }; 678 + 679 + static const struct power_supply_desc x1e80100_bat_psy_desc = { 680 + .name = "qcom-battmgr-bat", 681 + .type = POWER_SUPPLY_TYPE_BATTERY, 682 + .properties = x1e80100_bat_props, 683 + .num_properties = ARRAY_SIZE(x1e80100_bat_props), 684 + .get_property = qcom_battmgr_bat_get_property, 685 + .set_property = qcom_battmgr_bat_set_property, 686 + .property_is_writeable = qcom_battmgr_bat_is_writeable, 687 + }; 688 + 838 689 static const enum power_supply_property sm8350_bat_props[] = { 839 690 POWER_SUPPLY_PROP_STATUS, 840 691 POWER_SUPPLY_PROP_HEALTH, ··· 891 668 POWER_SUPPLY_PROP_MODEL_NAME, 892 669 POWER_SUPPLY_PROP_TIME_TO_FULL_AVG, 893 670 POWER_SUPPLY_PROP_TIME_TO_EMPTY_AVG, 671 + POWER_SUPPLY_PROP_INTERNAL_RESISTANCE, 672 + POWER_SUPPLY_PROP_STATE_OF_HEALTH, 894 673 POWER_SUPPLY_PROP_POWER_NOW, 895 674 }; 896 675 ··· 902 677 .properties = sm8350_bat_props, 903 678 .num_properties = ARRAY_SIZE(sm8350_bat_props), 904 679 .get_property = qcom_battmgr_bat_get_property, 680 + }; 681 + 682 + static const enum power_supply_property sm8550_bat_props[] = { 683 + POWER_SUPPLY_PROP_STATUS, 684 + POWER_SUPPLY_PROP_HEALTH, 685 + POWER_SUPPLY_PROP_PRESENT, 686 + POWER_SUPPLY_PROP_CHARGE_TYPE, 687 + POWER_SUPPLY_PROP_CAPACITY, 688 + POWER_SUPPLY_PROP_VOLTAGE_OCV, 689 + POWER_SUPPLY_PROP_VOLTAGE_NOW, 690 + POWER_SUPPLY_PROP_VOLTAGE_MAX, 691 + POWER_SUPPLY_PROP_CURRENT_NOW, 692 + POWER_SUPPLY_PROP_TEMP, 693 + POWER_SUPPLY_PROP_TECHNOLOGY, 694 + POWER_SUPPLY_PROP_CHARGE_COUNTER, 695 + POWER_SUPPLY_PROP_CYCLE_COUNT, 696 + POWER_SUPPLY_PROP_CHARGE_FULL_DESIGN, 697 + POWER_SUPPLY_PROP_CHARGE_FULL, 698 + POWER_SUPPLY_PROP_MODEL_NAME, 699 + POWER_SUPPLY_PROP_TIME_TO_FULL_AVG, 700 + POWER_SUPPLY_PROP_TIME_TO_EMPTY_AVG, 701 + POWER_SUPPLY_PROP_INTERNAL_RESISTANCE, 702 + POWER_SUPPLY_PROP_STATE_OF_HEALTH, 703 + POWER_SUPPLY_PROP_POWER_NOW, 704 + POWER_SUPPLY_PROP_CHARGE_CONTROL_START_THRESHOLD, 705 + POWER_SUPPLY_PROP_CHARGE_CONTROL_END_THRESHOLD, 706 + }; 707 + 708 + static const struct power_supply_desc sm8550_bat_psy_desc = { 709 + .name = "qcom-battmgr-bat", 710 + .type = POWER_SUPPLY_TYPE_BATTERY, 711 + .properties = sm8550_bat_props, 712 + .num_properties = ARRAY_SIZE(sm8550_bat_props), 713 + .get_property = qcom_battmgr_bat_get_property, 714 + .set_property = qcom_battmgr_bat_set_property, 715 + .property_is_writeable = qcom_battmgr_bat_is_writeable, 905 716 }; 906 717 907 718 static int qcom_battmgr_ac_get_property(struct power_supply *psy, ··· 1015 754 if (!battmgr->service_up) 1016 755 return -EAGAIN; 1017 756 1018 - if (battmgr->variant == QCOM_BATTMGR_SC8280XP) 757 + if (battmgr->variant == QCOM_BATTMGR_SC8280XP || 758 + battmgr->variant == QCOM_BATTMGR_X1E80100) 1019 759 ret = qcom_battmgr_bat_sc8280xp_update(battmgr, psp); 1020 760 else 1021 761 ret = qcom_battmgr_usb_sm8350_update(battmgr, psp); ··· 1138 876 if (!battmgr->service_up) 1139 877 return -EAGAIN; 1140 878 1141 - if (battmgr->variant == QCOM_BATTMGR_SC8280XP) 879 + if (battmgr->variant == QCOM_BATTMGR_SC8280XP || 880 + battmgr->variant == QCOM_BATTMGR_X1E80100) 1142 881 ret = qcom_battmgr_bat_sc8280xp_update(battmgr, psp); 1143 882 else 1144 883 ret = qcom_battmgr_wls_sm8350_update(battmgr, psp); ··· 1210 947 } 1211 948 1212 949 notification = le32_to_cpu(msg->notification); 950 + notification &= 0xff; 1213 951 switch (notification) { 1214 952 case NOTIF_BAT_INFO: 1215 953 battmgr->info.valid = false; 1216 954 fallthrough; 1217 955 case NOTIF_BAT_STATUS: 1218 956 case NOTIF_BAT_PROPERTY: 957 + case NOTIF_BAT_CHARGING_STATE: 1219 958 power_supply_changed(battmgr->bat_psy); 1220 959 break; 1221 960 case NOTIF_USB_PROPERTY: ··· 1247 982 1248 983 static unsigned int qcom_battmgr_sc8280xp_parse_technology(const char *chemistry) 1249 984 { 1250 - if (!strncmp(chemistry, "LIO", BATTMGR_CHEMISTRY_LEN)) 985 + if ((!strncmp(chemistry, "LIO", BATTMGR_CHEMISTRY_LEN)) || 986 + (!strncmp(chemistry, "OOI", BATTMGR_CHEMISTRY_LEN))) 1251 987 return POWER_SUPPLY_TECHNOLOGY_LION; 1252 988 if (!strncmp(chemistry, "LIP", BATTMGR_CHEMISTRY_LEN)) 1253 989 return POWER_SUPPLY_TECHNOLOGY_LIPO; ··· 1361 1095 case BATTMGR_BAT_CHARGE_TIME: 1362 1096 battmgr->status.charge_time = le32_to_cpu(resp->time); 1363 1097 break; 1098 + case BATTMGR_CHG_CTRL_LIMIT_EN: 1099 + battmgr->error = 0; 1100 + break; 1364 1101 default: 1365 1102 dev_warn(battmgr->dev, "unknown message %#x\n", opcode); 1366 1103 break; ··· 1428 1159 case BATT_CAPACITY: 1429 1160 battmgr->status.percent = le32_to_cpu(resp->intval.value) / 100; 1430 1161 break; 1162 + case BATT_SOH: 1163 + battmgr->status.soh_percent = le32_to_cpu(resp->intval.value); 1164 + break; 1431 1165 case BATT_VOLT_OCV: 1432 1166 battmgr->status.voltage_ocv = le32_to_cpu(resp->intval.value); 1433 1167 break; ··· 1471 1199 case BATT_TTE_AVG: 1472 1200 battmgr->status.discharge_time = le32_to_cpu(resp->intval.value); 1473 1201 break; 1202 + case BATT_RESISTANCE: 1203 + battmgr->status.resistance = le32_to_cpu(resp->intval.value); 1204 + break; 1474 1205 case BATT_POWER_NOW: 1475 1206 battmgr->status.power_now = le32_to_cpu(resp->intval.value); 1207 + break; 1208 + case BATT_CHG_CTRL_START_THR: 1209 + battmgr->info.charge_ctrl_start = le32_to_cpu(resp->intval.value); 1210 + break; 1211 + case BATT_CHG_CTRL_END_THR: 1212 + battmgr->info.charge_ctrl_end = le32_to_cpu(resp->intval.value); 1476 1213 break; 1477 1214 default: 1478 1215 dev_warn(battmgr->dev, "unknown property %#x\n", property); ··· 1565 1284 } 1566 1285 break; 1567 1286 case BATTMGR_REQUEST_NOTIFICATION: 1287 + case BATTMGR_CHG_CTRL_LIMIT_EN: 1568 1288 battmgr->error = 0; 1569 1289 break; 1570 1290 default: ··· 1585 1303 1586 1304 if (opcode == BATTMGR_NOTIFICATION) 1587 1305 qcom_battmgr_notification(battmgr, data, len); 1588 - else if (battmgr->variant == QCOM_BATTMGR_SC8280XP) 1306 + else if (battmgr->variant == QCOM_BATTMGR_SC8280XP || 1307 + battmgr->variant == QCOM_BATTMGR_X1E80100) 1589 1308 qcom_battmgr_sc8280xp_callback(battmgr, data, len); 1590 1309 else 1591 1310 qcom_battmgr_sm8350_callback(battmgr, data, len); ··· 1622 1339 static const struct of_device_id qcom_battmgr_of_variants[] = { 1623 1340 { .compatible = "qcom,sc8180x-pmic-glink", .data = (void *)QCOM_BATTMGR_SC8280XP }, 1624 1341 { .compatible = "qcom,sc8280xp-pmic-glink", .data = (void *)QCOM_BATTMGR_SC8280XP }, 1625 - { .compatible = "qcom,x1e80100-pmic-glink", .data = (void *)QCOM_BATTMGR_SC8280XP }, 1342 + { .compatible = "qcom,sm8550-pmic-glink", .data = (void *)QCOM_BATTMGR_SM8550 }, 1343 + { .compatible = "qcom,x1e80100-pmic-glink", .data = (void *)QCOM_BATTMGR_X1E80100 }, 1626 1344 /* Unmatched devices falls back to QCOM_BATTMGR_SM8350 */ 1627 1345 {} 1628 1346 }; ··· 1633 1349 static int qcom_battmgr_probe(struct auxiliary_device *adev, 1634 1350 const struct auxiliary_device_id *id) 1635 1351 { 1352 + const struct power_supply_desc *psy_desc; 1636 1353 struct power_supply_config psy_cfg_supply = {}; 1637 1354 struct power_supply_config psy_cfg = {}; 1638 1355 const struct of_device_id *match; 1639 1356 struct qcom_battmgr *battmgr; 1640 1357 struct device *dev = &adev->dev; 1358 + int ret; 1641 1359 1642 1360 battmgr = devm_kzalloc(dev, sizeof(*battmgr), GFP_KERNEL); 1643 1361 if (!battmgr) ··· 1665 1379 else 1666 1380 battmgr->variant = QCOM_BATTMGR_SM8350; 1667 1381 1668 - if (battmgr->variant == QCOM_BATTMGR_SC8280XP) { 1669 - battmgr->bat_psy = devm_power_supply_register(dev, &sc8280xp_bat_psy_desc, &psy_cfg); 1382 + ret = qcom_battmgr_charge_control_thresholds_init(battmgr); 1383 + if (ret < 0) 1384 + return dev_err_probe(dev, ret, 1385 + "failed to init battery charge control thresholds\n"); 1386 + 1387 + if (battmgr->variant == QCOM_BATTMGR_SC8280XP || 1388 + battmgr->variant == QCOM_BATTMGR_X1E80100) { 1389 + if (battmgr->variant == QCOM_BATTMGR_X1E80100) 1390 + psy_desc = &x1e80100_bat_psy_desc; 1391 + else 1392 + psy_desc = &sc8280xp_bat_psy_desc; 1393 + 1394 + battmgr->bat_psy = devm_power_supply_register(dev, psy_desc, &psy_cfg); 1670 1395 if (IS_ERR(battmgr->bat_psy)) 1671 1396 return dev_err_probe(dev, PTR_ERR(battmgr->bat_psy), 1672 1397 "failed to register battery power supply\n"); ··· 1697 1400 return dev_err_probe(dev, PTR_ERR(battmgr->wls_psy), 1698 1401 "failed to register wireless charing power supply\n"); 1699 1402 } else { 1700 - battmgr->bat_psy = devm_power_supply_register(dev, &sm8350_bat_psy_desc, &psy_cfg); 1403 + if (battmgr->variant == QCOM_BATTMGR_SM8550) 1404 + psy_desc = &sm8550_bat_psy_desc; 1405 + else 1406 + psy_desc = &sm8350_bat_psy_desc; 1407 + 1408 + battmgr->bat_psy = devm_power_supply_register(dev, psy_desc, &psy_cfg); 1701 1409 if (IS_ERR(battmgr->bat_psy)) 1702 1410 return dev_err_probe(dev, PTR_ERR(battmgr->bat_psy), 1703 1411 "failed to register battery power supply\n");
+3 -3
drivers/power/supply/rk817_charger.c
··· 1046 1046 rk817_read_props(charger); 1047 1047 1048 1048 /* Run every 8 seconds like the BSP driver did. */ 1049 - queue_delayed_work(system_wq, &charger->work, msecs_to_jiffies(8000)); 1049 + queue_delayed_work(system_percpu_wq, &charger->work, msecs_to_jiffies(8000)); 1050 1050 } 1051 1051 1052 1052 static void rk817_cleanup_node(void *data) ··· 1206 1206 return ret; 1207 1207 1208 1208 /* Force the first update immediately. */ 1209 - mod_delayed_work(system_wq, &charger->work, 0); 1209 + mod_delayed_work(system_percpu_wq, &charger->work, 0); 1210 1210 1211 1211 return 0; 1212 1212 } ··· 1226 1226 struct rk817_charger *charger = dev_get_drvdata(dev); 1227 1227 1228 1228 /* force an immediate update */ 1229 - mod_delayed_work(system_wq, &charger->work, 0); 1229 + mod_delayed_work(system_percpu_wq, &charger->work, 0); 1230 1230 1231 1231 return 0; 1232 1232 }
+13 -34
drivers/power/supply/rt9467-charger.c
··· 633 633 static const enum power_supply_property rt9467_chg_properties[] = { 634 634 POWER_SUPPLY_PROP_STATUS, 635 635 POWER_SUPPLY_PROP_ONLINE, 636 + POWER_SUPPLY_PROP_VOLTAGE_NOW, 636 637 POWER_SUPPLY_PROP_CURRENT_MAX, 638 + POWER_SUPPLY_PROP_CURRENT_NOW, 637 639 POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT, 638 640 POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT_MAX, 639 641 POWER_SUPPLY_PROP_CONSTANT_CHARGE_VOLTAGE, ··· 658 656 return rt9467_psy_get_status(data, &val->intval); 659 657 case POWER_SUPPLY_PROP_ONLINE: 660 658 return regmap_field_read(data->rm_field[F_PWR_RDY], &val->intval); 659 + case POWER_SUPPLY_PROP_VOLTAGE_NOW: 660 + return rt9467_get_adc(data, RT9467_ADC_VBUS_DIV5, &val->intval); 661 661 case POWER_SUPPLY_PROP_CURRENT_MAX: 662 662 mutex_lock(&data->attach_lock); 663 663 if (data->psy_usb_type == POWER_SUPPLY_USB_TYPE_UNKNOWN || ··· 669 665 val->intval = 1500000; 670 666 mutex_unlock(&data->attach_lock); 671 667 return 0; 668 + case POWER_SUPPLY_PROP_CURRENT_NOW: 669 + return rt9467_get_adc(data, RT9467_ADC_IBUS, &val->intval); 672 670 case POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT: 673 671 mutex_lock(&data->ichg_ieoc_lock); 674 672 val->intval = data->ichg_ua; ··· 1147 1141 return regmap_field_write(data->rm_field[F_RST], 1); 1148 1142 } 1149 1143 1150 - static void rt9467_chg_destroy_adc_lock(void *data) 1151 - { 1152 - struct mutex *adc_lock = data; 1153 - 1154 - mutex_destroy(adc_lock); 1155 - } 1156 - 1157 - static void rt9467_chg_destroy_attach_lock(void *data) 1158 - { 1159 - struct mutex *attach_lock = data; 1160 - 1161 - mutex_destroy(attach_lock); 1162 - } 1163 - 1164 - static void rt9467_chg_destroy_ichg_ieoc_lock(void *data) 1165 - { 1166 - struct mutex *ichg_ieoc_lock = data; 1167 - 1168 - mutex_destroy(ichg_ieoc_lock); 1169 - } 1170 - 1171 1144 static void rt9467_chg_complete_aicl_done(void *data) 1172 1145 { 1173 1146 struct completion *aicl_done = data; ··· 1199 1214 if (ret) 1200 1215 return dev_err_probe(dev, ret, "Failed to add irq chip\n"); 1201 1216 1202 - mutex_init(&data->adc_lock); 1203 - ret = devm_add_action_or_reset(dev, rt9467_chg_destroy_adc_lock, 1204 - &data->adc_lock); 1217 + ret = devm_mutex_init(dev, &data->adc_lock); 1205 1218 if (ret) 1206 - return dev_err_probe(dev, ret, "Failed to init ADC lock\n"); 1219 + return ret; 1207 1220 1208 - mutex_init(&data->attach_lock); 1209 - ret = devm_add_action_or_reset(dev, rt9467_chg_destroy_attach_lock, 1210 - &data->attach_lock); 1221 + ret = devm_mutex_init(dev, &data->attach_lock); 1211 1222 if (ret) 1212 - return dev_err_probe(dev, ret, "Failed to init attach lock\n"); 1223 + return ret; 1213 1224 1214 - mutex_init(&data->ichg_ieoc_lock); 1215 - ret = devm_add_action_or_reset(dev, rt9467_chg_destroy_ichg_ieoc_lock, 1216 - &data->ichg_ieoc_lock); 1225 + ret = devm_mutex_init(dev, &data->ichg_ieoc_lock); 1217 1226 if (ret) 1218 - return dev_err_probe(dev, ret, "Failed to init ICHG/IEOC lock\n"); 1227 + return ret; 1219 1228 1220 1229 init_completion(&data->aicl_done); 1221 1230 ret = devm_add_action_or_reset(dev, rt9467_chg_complete_aicl_done, 1222 1231 &data->aicl_done); 1223 1232 if (ret) 1224 - return dev_err_probe(dev, ret, "Failed to init AICL done completion\n"); 1233 + return ret; 1225 1234 1226 1235 ret = rt9467_do_charger_init(data); 1227 1236 if (ret)
+1 -1
drivers/power/supply/rx51_battery.c
··· 116 116 int mid = (max + min) / 2; 117 117 if (rx51_temp_table2[mid] <= raw) 118 118 min = mid; 119 - else if (rx51_temp_table2[mid] > raw) 119 + else 120 120 max = mid; 121 121 if (rx51_temp_table2[mid] == raw) 122 122 break;
+13 -3
drivers/power/supply/sbs-charger.c
··· 154 154 .val_format_endian = REGMAP_ENDIAN_LITTLE, /* since based on SMBus */ 155 155 }; 156 156 157 - static const struct power_supply_desc sbs_desc = { 158 - .name = "sbs-charger", 157 + static const struct power_supply_desc sbs_default_desc = { 159 158 .type = POWER_SUPPLY_TYPE_MAINS, 160 159 .properties = sbs_properties, 161 160 .num_properties = ARRAY_SIZE(sbs_properties), ··· 164 165 static int sbs_probe(struct i2c_client *client) 165 166 { 166 167 struct power_supply_config psy_cfg = {}; 168 + struct power_supply_desc *sbs_desc; 167 169 struct sbs_info *chip; 168 170 int ret, val; 171 + 172 + sbs_desc = devm_kmemdup(&client->dev, &sbs_default_desc, 173 + sizeof(*sbs_desc), GFP_KERNEL); 174 + if (!sbs_desc) 175 + return -ENOMEM; 176 + 177 + sbs_desc->name = devm_kasprintf(&client->dev, GFP_KERNEL, "sbs-%s", 178 + dev_name(&client->dev)); 179 + if (!sbs_desc->name) 180 + return -ENOMEM; 169 181 170 182 chip = devm_kzalloc(&client->dev, sizeof(struct sbs_info), GFP_KERNEL); 171 183 if (!chip) ··· 201 191 return dev_err_probe(&client->dev, ret, "Failed to get device status\n"); 202 192 chip->last_state = val; 203 193 204 - chip->power_supply = devm_power_supply_register(&client->dev, &sbs_desc, &psy_cfg); 194 + chip->power_supply = devm_power_supply_register(&client->dev, sbs_desc, &psy_cfg); 205 195 if (IS_ERR(chip->power_supply)) 206 196 return dev_err_probe(&client->dev, PTR_ERR(chip->power_supply), 207 197 "Failed to register power supply\n");
+1 -1
drivers/power/supply/sbs-manager.c
··· 348 348 data->muxc = i2c_mux_alloc(adapter, dev, SBSM_MAX_BATS, 0, 349 349 I2C_MUX_LOCKED, &sbsm_select, NULL); 350 350 if (!data->muxc) 351 - return dev_err_probe(dev, -ENOMEM, "failed to alloc i2c mux\n"); 351 + return -ENOMEM; 352 352 data->muxc->priv = data; 353 353 354 354 ret = devm_add_action_or_reset(dev, sbsm_del_mux_adapter, data);
+1 -1
drivers/power/supply/ucs1002_power.c
··· 493 493 { 494 494 struct ucs1002_info *info = data; 495 495 496 - mod_delayed_work(system_wq, &info->health_poll, 0); 496 + mod_delayed_work(system_percpu_wq, &info->health_poll, 0); 497 497 498 498 return IRQ_HANDLED; 499 499 }
+66 -280
drivers/power/supply/ug3105_battery.c
··· 10 10 * is off or suspended, the coulomb counter is not used atm. 11 11 * 12 12 * Possible improvements: 13 - * 1. Activate commented out total_coulomb_count code 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 + * 14 29 * 2. Reset total_coulomb_count val to 0 when the battery is as good as empty 15 30 * and remember that we did this (and clear the flag for this on susp/resume) 16 31 * 3. When the battery is full check if the flag that we set total_coulomb_count ··· 46 31 * has shown that an estimated 7404mWh increase of the battery's energy results 47 32 * in a total_coulomb_count increase of 3277 units with a 5 milli-ohm sense R. 48 33 * 49 - * Copyright (C) 2021 Hans de Goede <hdegoede@redhat.com> 34 + * Copyright (C) 2021 - 2025 Hans de Goede <hansg@kernel.org> 50 35 */ 51 36 52 - #include <linux/devm-helpers.h> 53 37 #include <linux/module.h> 54 - #include <linux/mutex.h> 55 38 #include <linux/slab.h> 56 39 #include <linux/i2c.h> 57 40 #include <linux/mod_devicetable.h> 58 41 #include <linux/power_supply.h> 59 - #include <linux/workqueue.h> 60 42 61 - #define UG3105_MOV_AVG_WINDOW 8 62 - #define UG3105_INIT_POLL_TIME (5 * HZ) 63 - #define UG3105_POLL_TIME (30 * HZ) 64 - #define UG3105_SETTLE_TIME (1 * HZ) 65 - 66 - #define UG3105_INIT_POLL_COUNT 30 43 + #include "adc-battery-helper.h" 67 44 68 45 #define UG3105_REG_MODE 0x00 69 46 #define UG3105_REG_CTRL1 0x01 ··· 68 61 69 62 #define UG3105_CTRL1_RESET_COULOMB_CNT 0x03 70 63 71 - #define UG3105_CURR_HYST_UA 65000 72 - 73 - #define UG3105_LOW_BAT_UV 3700000 74 - #define UG3105_FULL_BAT_HYST_UV 38000 75 - 76 - #define AMBIENT_TEMP_CELCIUS 25 77 - 78 64 struct ug3105_chip { 65 + /* Must be the first member see adc-battery-helper documentation */ 66 + struct adc_battery_helper helper; 79 67 struct i2c_client *client; 80 68 struct power_supply *psy; 81 - struct delayed_work work; 82 - struct mutex lock; 83 - int ocv[UG3105_MOV_AVG_WINDOW]; /* micro-volt */ 84 - int intern_res[UG3105_MOV_AVG_WINDOW]; /* milli-ohm */ 85 - int poll_count; 86 - int ocv_avg_index; 87 - int ocv_avg; /* micro-volt */ 88 - int intern_res_poll_count; 89 - int intern_res_avg_index; 90 - int intern_res_avg; /* milli-ohm */ 91 - int volt; /* micro-volt */ 92 - int curr; /* micro-ampere */ 93 - int total_coulomb_count; 94 69 int uv_per_unit; 95 70 int ua_per_unit; 96 - int status; 97 - int capacity; 98 - bool supplied; 99 71 }; 100 72 101 73 static int ug3105_read_word(struct i2c_client *client, u8 reg) ··· 88 102 return val; 89 103 } 90 104 91 - static int ug3105_get_status(struct ug3105_chip *chip) 92 - { 93 - int full = chip->psy->battery_info->constant_charge_voltage_max_uv - 94 - UG3105_FULL_BAT_HYST_UV; 95 - 96 - if (chip->curr > UG3105_CURR_HYST_UA) 97 - return POWER_SUPPLY_STATUS_CHARGING; 98 - 99 - if (chip->curr < -UG3105_CURR_HYST_UA) 100 - return POWER_SUPPLY_STATUS_DISCHARGING; 101 - 102 - if (chip->supplied && chip->ocv_avg > full) 103 - return POWER_SUPPLY_STATUS_FULL; 104 - 105 - return POWER_SUPPLY_STATUS_NOT_CHARGING; 106 - } 107 - 108 - static void ug3105_work(struct work_struct *work) 109 - { 110 - struct ug3105_chip *chip = container_of(work, struct ug3105_chip, 111 - work.work); 112 - int i, val, curr_diff, volt_diff, res, win_size; 113 - bool prev_supplied = chip->supplied; 114 - int prev_status = chip->status; 115 - int prev_volt = chip->volt; 116 - int prev_curr = chip->curr; 117 - struct power_supply *psy; 118 - 119 - mutex_lock(&chip->lock); 120 - 121 - psy = chip->psy; 122 - if (!psy) 123 - goto out; 124 - 125 - val = ug3105_read_word(chip->client, UG3105_REG_BAT_VOLT); 126 - if (val < 0) 127 - goto out; 128 - chip->volt = val * chip->uv_per_unit; 129 - 130 - val = ug3105_read_word(chip->client, UG3105_REG_BAT_CURR); 131 - if (val < 0) 132 - goto out; 133 - chip->curr = (s16)val * chip->ua_per_unit; 134 - 135 - chip->ocv[chip->ocv_avg_index] = 136 - chip->volt - chip->curr * chip->intern_res_avg / 1000; 137 - chip->ocv_avg_index = (chip->ocv_avg_index + 1) % UG3105_MOV_AVG_WINDOW; 138 - chip->poll_count++; 139 - 140 - /* 141 - * See possible improvements comment above. 142 - * 143 - * Read + reset coulomb counter every 10 polls (every 300 seconds) 144 - * if ((chip->poll_count % 10) == 0) { 145 - * val = ug3105_read_word(chip->client, UG3105_REG_COULOMB_CNT); 146 - * if (val < 0) 147 - * goto out; 148 - * 149 - * i2c_smbus_write_byte_data(chip->client, UG3105_REG_CTRL1, 150 - * UG3105_CTRL1_RESET_COULOMB_CNT); 151 - * 152 - * chip->total_coulomb_count += (s16)val; 153 - * dev_dbg(&chip->client->dev, "coulomb count %d total %d\n", 154 - * (s16)val, chip->total_coulomb_count); 155 - * } 156 - */ 157 - 158 - chip->ocv_avg = 0; 159 - win_size = min(chip->poll_count, UG3105_MOV_AVG_WINDOW); 160 - for (i = 0; i < win_size; i++) 161 - chip->ocv_avg += chip->ocv[i]; 162 - chip->ocv_avg /= win_size; 163 - 164 - chip->supplied = power_supply_am_i_supplied(psy); 165 - chip->status = ug3105_get_status(chip); 166 - if (chip->status == POWER_SUPPLY_STATUS_FULL) 167 - chip->capacity = 100; 168 - else 169 - chip->capacity = power_supply_batinfo_ocv2cap(chip->psy->battery_info, 170 - chip->ocv_avg, 171 - AMBIENT_TEMP_CELCIUS); 172 - 173 - /* 174 - * Skip internal resistance calc on charger [un]plug and 175 - * when the battery is almost empty (voltage low). 176 - */ 177 - if (chip->supplied != prev_supplied || 178 - chip->volt < UG3105_LOW_BAT_UV || 179 - chip->poll_count < 2) 180 - goto out; 181 - 182 - /* 183 - * Assuming that the OCV voltage does not change significantly 184 - * between 2 polls, then we can calculate the internal resistance 185 - * on a significant current change by attributing all voltage 186 - * change between the 2 readings to the internal resistance. 187 - */ 188 - curr_diff = abs(chip->curr - prev_curr); 189 - if (curr_diff < UG3105_CURR_HYST_UA) 190 - goto out; 191 - 192 - volt_diff = abs(chip->volt - prev_volt); 193 - res = volt_diff * 1000 / curr_diff; 194 - 195 - if ((res < (chip->intern_res_avg * 2 / 3)) || 196 - (res > (chip->intern_res_avg * 4 / 3))) { 197 - dev_dbg(&chip->client->dev, "Ignoring outlier internal resistance %d mOhm\n", res); 198 - goto out; 199 - } 200 - 201 - dev_dbg(&chip->client->dev, "Internal resistance %d mOhm\n", res); 202 - 203 - chip->intern_res[chip->intern_res_avg_index] = res; 204 - chip->intern_res_avg_index = (chip->intern_res_avg_index + 1) % UG3105_MOV_AVG_WINDOW; 205 - chip->intern_res_poll_count++; 206 - 207 - chip->intern_res_avg = 0; 208 - win_size = min(chip->intern_res_poll_count, UG3105_MOV_AVG_WINDOW); 209 - for (i = 0; i < win_size; i++) 210 - chip->intern_res_avg += chip->intern_res[i]; 211 - chip->intern_res_avg /= win_size; 212 - 213 - out: 214 - mutex_unlock(&chip->lock); 215 - 216 - queue_delayed_work(system_wq, &chip->work, 217 - (chip->poll_count <= UG3105_INIT_POLL_COUNT) ? 218 - UG3105_INIT_POLL_TIME : UG3105_POLL_TIME); 219 - 220 - if (chip->status != prev_status && psy) 221 - power_supply_changed(psy); 222 - } 223 - 224 - static enum power_supply_property ug3105_battery_props[] = { 225 - POWER_SUPPLY_PROP_STATUS, 226 - POWER_SUPPLY_PROP_PRESENT, 227 - POWER_SUPPLY_PROP_SCOPE, 228 - POWER_SUPPLY_PROP_VOLTAGE_NOW, 229 - POWER_SUPPLY_PROP_VOLTAGE_OCV, 230 - POWER_SUPPLY_PROP_CURRENT_NOW, 231 - POWER_SUPPLY_PROP_CAPACITY, 232 - }; 233 - 234 - static int ug3105_get_property(struct power_supply *psy, 235 - enum power_supply_property psp, 236 - union power_supply_propval *val) 105 + static int ug3105_get_voltage_and_current_now(struct power_supply *psy, int *volt, int *curr) 237 106 { 238 107 struct ug3105_chip *chip = power_supply_get_drvdata(psy); 239 - int ret = 0; 108 + int ret; 240 109 241 - mutex_lock(&chip->lock); 110 + ret = ug3105_read_word(chip->client, UG3105_REG_BAT_VOLT); 111 + if (ret < 0) 112 + return ret; 242 113 243 - if (!chip->psy) { 244 - ret = -EAGAIN; 245 - goto out; 246 - } 114 + *volt = ret * chip->uv_per_unit; 247 115 248 - switch (psp) { 249 - case POWER_SUPPLY_PROP_STATUS: 250 - val->intval = chip->status; 251 - break; 252 - case POWER_SUPPLY_PROP_PRESENT: 253 - val->intval = 1; 254 - break; 255 - case POWER_SUPPLY_PROP_SCOPE: 256 - val->intval = POWER_SUPPLY_SCOPE_SYSTEM; 257 - break; 258 - case POWER_SUPPLY_PROP_VOLTAGE_NOW: 259 - ret = ug3105_read_word(chip->client, UG3105_REG_BAT_VOLT); 260 - if (ret < 0) 261 - break; 262 - val->intval = ret * chip->uv_per_unit; 263 - ret = 0; 264 - break; 265 - case POWER_SUPPLY_PROP_VOLTAGE_OCV: 266 - val->intval = chip->ocv_avg; 267 - break; 268 - case POWER_SUPPLY_PROP_CURRENT_NOW: 269 - ret = ug3105_read_word(chip->client, UG3105_REG_BAT_CURR); 270 - if (ret < 0) 271 - break; 272 - val->intval = (s16)ret * chip->ua_per_unit; 273 - ret = 0; 274 - break; 275 - case POWER_SUPPLY_PROP_CAPACITY: 276 - val->intval = chip->capacity; 277 - break; 278 - default: 279 - ret = -EINVAL; 280 - } 116 + ret = ug3105_read_word(chip->client, UG3105_REG_BAT_CURR); 117 + if (ret < 0) 118 + return ret; 281 119 282 - out: 283 - mutex_unlock(&chip->lock); 284 - return ret; 285 - } 286 - 287 - static void ug3105_external_power_changed(struct power_supply *psy) 288 - { 289 - struct ug3105_chip *chip = power_supply_get_drvdata(psy); 290 - 291 - dev_dbg(&chip->client->dev, "external power changed\n"); 292 - mod_delayed_work(system_wq, &chip->work, UG3105_SETTLE_TIME); 120 + *curr = (s16)ret * chip->ua_per_unit; 121 + return 0; 293 122 } 294 123 295 124 static const struct power_supply_desc ug3105_psy_desc = { 296 125 .name = "ug3105_battery", 297 126 .type = POWER_SUPPLY_TYPE_BATTERY, 298 - .get_property = ug3105_get_property, 299 - .external_power_changed = ug3105_external_power_changed, 300 - .properties = ug3105_battery_props, 301 - .num_properties = ARRAY_SIZE(ug3105_battery_props), 127 + .get_property = adc_battery_helper_get_property, 128 + .external_power_changed = adc_battery_helper_external_power_changed, 129 + .properties = adc_battery_helper_properties, 130 + .num_properties = ADC_HELPER_NUM_PROPERTIES, 302 131 }; 303 132 304 - static void ug3105_init(struct ug3105_chip *chip) 133 + static void ug3105_start(struct i2c_client *client) 305 134 { 306 - chip->poll_count = 0; 307 - chip->ocv_avg_index = 0; 308 - chip->total_coulomb_count = 0; 309 - i2c_smbus_write_byte_data(chip->client, UG3105_REG_MODE, 310 - UG3105_MODE_RUN); 311 - i2c_smbus_write_byte_data(chip->client, UG3105_REG_CTRL1, 312 - UG3105_CTRL1_RESET_COULOMB_CNT); 313 - queue_delayed_work(system_wq, &chip->work, 0); 314 - flush_delayed_work(&chip->work); 135 + i2c_smbus_write_byte_data(client, UG3105_REG_MODE, UG3105_MODE_RUN); 136 + i2c_smbus_write_byte_data(client, UG3105_REG_CTRL1, UG3105_CTRL1_RESET_COULOMB_CNT); 137 + } 138 + 139 + static void ug3105_stop(struct i2c_client *client) 140 + { 141 + i2c_smbus_write_byte_data(client, UG3105_REG_MODE, UG3105_MODE_STANDBY); 315 142 } 316 143 317 144 static int ug3105_probe(struct i2c_client *client) ··· 132 333 struct power_supply_config psy_cfg = {}; 133 334 struct device *dev = &client->dev; 134 335 u32 curr_sense_res_uohm = 10000; 135 - struct power_supply *psy; 136 336 struct ug3105_chip *chip; 137 337 int ret; 138 338 ··· 140 342 return -ENOMEM; 141 343 142 344 chip->client = client; 143 - mutex_init(&chip->lock); 144 - ret = devm_delayed_work_autocancel(dev, &chip->work, ug3105_work); 145 - if (ret) 146 - return ret; 147 345 148 - psy_cfg.drv_data = chip; 149 - psy = devm_power_supply_register(dev, &ug3105_psy_desc, &psy_cfg); 150 - if (IS_ERR(psy)) 151 - return PTR_ERR(psy); 152 - 153 - if (!psy->battery_info || 154 - psy->battery_info->factory_internal_resistance_uohm == -EINVAL || 155 - psy->battery_info->constant_charge_voltage_max_uv == -EINVAL || 156 - !psy->battery_info->ocv_table[0]) { 157 - dev_err(dev, "error required properties are missing\n"); 158 - return -ENODEV; 159 - } 346 + ug3105_start(client); 160 347 161 348 device_property_read_u32(dev, "upisemi,rsns-microohm", &curr_sense_res_uohm); 162 349 ··· 149 366 * DAC maximum is 4.5V divided by 65536 steps + an unknown factor of 10 150 367 * coming from somewhere for some reason (verified with a volt-meter). 151 368 */ 152 - chip->uv_per_unit = 45000000/65536; 369 + chip->uv_per_unit = 45000000 / 65536; 153 370 /* Datasheet says 8.1 uV per unit for the current ADC */ 154 371 chip->ua_per_unit = 8100000 / curr_sense_res_uohm; 155 372 156 - /* Use provided internal resistance as start point (in milli-ohm) */ 157 - chip->intern_res_avg = psy->battery_info->factory_internal_resistance_uohm / 1000; 158 - /* Also add it to the internal resistance moving average window */ 159 - chip->intern_res[0] = chip->intern_res_avg; 160 - chip->intern_res_avg_index = 1; 161 - chip->intern_res_poll_count = 1; 373 + psy_cfg.drv_data = chip; 374 + chip->psy = devm_power_supply_register(dev, &ug3105_psy_desc, &psy_cfg); 375 + if (IS_ERR(chip->psy)) { 376 + ret = PTR_ERR(chip->psy); 377 + goto stop; 378 + } 162 379 163 - mutex_lock(&chip->lock); 164 - chip->psy = psy; 165 - mutex_unlock(&chip->lock); 166 - 167 - ug3105_init(chip); 380 + ret = adc_battery_helper_init(&chip->helper, chip->psy, 381 + ug3105_get_voltage_and_current_now, NULL); 382 + if (ret) 383 + goto stop; 168 384 169 385 i2c_set_clientdata(client, chip); 170 386 return 0; 387 + 388 + stop: 389 + ug3105_stop(client); 390 + return ret; 171 391 } 172 392 173 393 static int __maybe_unused ug3105_suspend(struct device *dev) 174 394 { 175 395 struct ug3105_chip *chip = dev_get_drvdata(dev); 176 396 177 - cancel_delayed_work_sync(&chip->work); 178 - i2c_smbus_write_byte_data(chip->client, UG3105_REG_MODE, 179 - UG3105_MODE_STANDBY); 180 - 397 + adc_battery_helper_suspend(dev); 398 + ug3105_stop(chip->client); 181 399 return 0; 182 400 } 183 401 ··· 186 402 { 187 403 struct ug3105_chip *chip = dev_get_drvdata(dev); 188 404 189 - ug3105_init(chip); 190 - 405 + ug3105_start(chip->client); 406 + adc_battery_helper_resume(dev); 191 407 return 0; 192 408 } 193 409 ··· 206 422 .pm = &ug3105_pm_ops, 207 423 }, 208 424 .probe = ug3105_probe, 425 + .remove = ug3105_stop, 426 + .shutdown = ug3105_stop, 209 427 .id_table = ug3105_id, 210 428 }; 211 429 module_i2c_driver(ug3105_i2c_driver); 212 430 213 - MODULE_AUTHOR("Hans de Goede <hdegoede@redhat.com"); 431 + MODULE_AUTHOR("Hans de Goede <hansg@kernel.org"); 214 432 MODULE_DESCRIPTION("uPI uG3105 battery monitor driver"); 215 433 MODULE_LICENSE("GPL");
+70 -74
include/linux/power/max77705_charger.h
··· 9 9 #ifndef __MAX77705_CHARGER_H 10 10 #define __MAX77705_CHARGER_H __FILE__ 11 11 12 - /* MAX77705_CHG_REG_CHG_INT */ 13 - #define MAX77705_BYP_I BIT(0) 14 - #define MAX77705_INP_LIMIT_I BIT(1) 15 - #define MAX77705_BATP_I BIT(2) 16 - #define MAX77705_BAT_I BIT(3) 17 - #define MAX77705_CHG_I BIT(4) 18 - #define MAX77705_WCIN_I BIT(5) 19 - #define MAX77705_CHGIN_I BIT(6) 20 - #define MAX77705_AICL_I BIT(7) 12 + #include <linux/regmap.h> 21 13 22 - /* MAX77705_CHG_REG_CHG_INT_MASK */ 23 - #define MAX77705_BYP_IM BIT(0) 24 - #define MAX77705_INP_LIMIT_IM BIT(1) 25 - #define MAX77705_BATP_IM BIT(2) 26 - #define MAX77705_BAT_IM BIT(3) 27 - #define MAX77705_CHG_IM BIT(4) 28 - #define MAX77705_WCIN_IM BIT(5) 29 - #define MAX77705_CHGIN_IM BIT(6) 30 - #define MAX77705_AICL_IM BIT(7) 14 + /* MAX77705_CHG_REG_CHG_INT */ 15 + #define MAX77705_BYP_I (0) 16 + #define MAX77705_INP_LIMIT_I (1) 17 + #define MAX77705_BATP_I (2) 18 + #define MAX77705_BAT_I (3) 19 + #define MAX77705_CHG_I (4) 20 + #define MAX77705_WCIN_I (5) 21 + #define MAX77705_CHGIN_I (6) 22 + #define MAX77705_AICL_I (7) 31 23 32 24 /* MAX77705_CHG_REG_CHG_INT_OK */ 33 - #define MAX77705_BYP_OK BIT(0) 34 - #define MAX77705_DISQBAT_OK BIT(1) 35 - #define MAX77705_BATP_OK BIT(2) 36 - #define MAX77705_BAT_OK BIT(3) 37 - #define MAX77705_CHG_OK BIT(4) 38 - #define MAX77705_WCIN_OK BIT(5) 39 - #define MAX77705_CHGIN_OK BIT(6) 40 - #define MAX77705_AICL_OK BIT(7) 25 + #define MAX77705_BYP_OK BIT(MAX77705_BYP_I) 26 + #define MAX77705_DISQBAT_OK BIT(MAX77705_INP_LIMIT_I) 27 + #define MAX77705_BATP_OK BIT(MAX77705_BATP_I) 28 + #define MAX77705_BAT_OK BIT(MAX77705_BAT_I) 29 + #define MAX77705_CHG_OK BIT(MAX77705_CHG_I) 30 + #define MAX77705_WCIN_OK BIT(MAX77705_WCIN_I) 31 + #define MAX77705_CHGIN_OK BIT(MAX77705_CHGIN_I) 32 + #define MAX77705_AICL_OK BIT(MAX77705_AICL_I) 41 33 42 34 /* MAX77705_CHG_REG_DETAILS_00 */ 43 35 #define MAX77705_BATP_DTLS BIT(0) ··· 55 63 #define MAX77705_BUCK_SHIFT 2 56 64 #define MAX77705_BOOST_SHIFT 3 57 65 #define MAX77705_WDTEN_SHIFT 4 58 - #define MAX77705_MODE_MASK GENMASK(3, 0) 59 66 #define MAX77705_CHG_MASK BIT(MAX77705_CHG_SHIFT) 60 67 #define MAX77705_UNO_MASK BIT(MAX77705_UNO_SHIFT) 61 68 #define MAX77705_OTG_MASK BIT(MAX77705_OTG_SHIFT) ··· 65 74 #define MAX77705_OTG_CTRL (MAX77705_OTG_MASK | MAX77705_BOOST_MASK) 66 75 67 76 /* MAX77705_CHG_REG_CNFG_01 */ 68 - #define MAX77705_FCHGTIME_SHIFT 0 69 - #define MAX77705_FCHGTIME_MASK GENMASK(2, 0) 70 - #define MAX77705_CHG_RSTRT_SHIFT 4 71 - #define MAX77705_CHG_RSTRT_MASK GENMASK(5, 4) 72 77 #define MAX77705_FCHGTIME_DISABLE 0 73 78 #define MAX77705_CHG_RSTRT_DISABLE 0x3 74 79 75 - #define MAX77705_PQEN_SHIFT 7 76 - #define MAX77705_PQEN_MASK BIT(7) 77 80 #define MAX77705_CHG_PQEN_DISABLE 0 78 81 #define MAX77705_CHG_PQEN_ENABLE 1 79 82 80 83 /* MAX77705_CHG_REG_CNFG_02 */ 81 - #define MAX77705_OTG_ILIM_SHIFT 6 82 - #define MAX77705_OTG_ILIM_MASK GENMASK(7, 6) 83 84 #define MAX77705_OTG_ILIM_500 0 84 85 #define MAX77705_OTG_ILIM_900 1 85 86 #define MAX77705_OTG_ILIM_1200 2 86 87 #define MAX77705_OTG_ILIM_1500 3 87 - #define MAX77705_CHG_CC GENMASK(5, 0) 88 88 89 89 /* MAX77705_CHG_REG_CNFG_03 */ 90 - #define MAX77705_TO_ITH_SHIFT 0 91 - #define MAX77705_TO_ITH_MASK GENMASK(2, 0) 92 - #define MAX77705_TO_TIME_SHIFT 3 93 - #define MAX77705_TO_TIME_MASK GENMASK(5, 3) 94 - #define MAX77705_SYS_TRACK_DIS_SHIFT 7 95 - #define MAX77705_SYS_TRACK_DIS_MASK BIT(7) 96 90 #define MAX77705_TO_ITH_150MA 0 97 91 #define MAX77705_TO_TIME_30M 3 98 92 #define MAX77705_SYS_TRACK_ENABLE 0 ··· 86 110 /* MAX77705_CHG_REG_CNFG_04 */ 87 111 #define MAX77705_CHG_MINVSYS_SHIFT 6 88 112 #define MAX77705_CHG_MINVSYS_MASK GENMASK(7, 6) 89 - #define MAX77705_CHG_PRM_SHIFT 0 90 - #define MAX77705_CHG_PRM_MASK GENMASK(5, 0) 91 - 92 - #define MAX77705_CHG_CV_PRM_SHIFT 0 93 - #define MAX77705_CHG_CV_PRM_MASK GENMASK(5, 0) 94 113 95 114 /* MAX77705_CHG_REG_CNFG_05 */ 96 - #define MAX77705_REG_B2SOVRC_SHIFT 0 97 - #define MAX77705_REG_B2SOVRC_MASK GENMASK(3, 0) 98 115 #define MAX77705_B2SOVRC_DISABLE 0 99 116 #define MAX77705_B2SOVRC_4_5A 6 100 117 #define MAX77705_B2SOVRC_4_8A 8 ··· 97 128 #define MAX77705_WDTCLR_SHIFT 0 98 129 #define MAX77705_WDTCLR_MASK GENMASK(1, 0) 99 130 #define MAX77705_WDTCLR 1 100 - #define MAX77705_CHGPROT_MASK GENMASK(3, 2) 101 - #define MAX77705_CHGPROT_UNLOCKED GENMASK(3, 2) 102 - #define MAX77705_SLOWEST_LX_SLOPE GENMASK(6, 5) 131 + #define MAX77705_CHGPROT_UNLOCKED 3 132 + #define MAX77705_SLOWEST_LX_SLOPE 3 103 133 104 134 /* MAX77705_CHG_REG_CNFG_07 */ 105 135 #define MAX77705_CHG_FMBST 4 ··· 108 140 #define MAX77705_REG_FGSRC_MASK BIT(MAX77705_REG_FGSRC_SHIFT) 109 141 110 142 /* MAX77705_CHG_REG_CNFG_08 */ 111 - #define MAX77705_REG_FSW_SHIFT 0 112 - #define MAX77705_REG_FSW_MASK GENMASK(1, 0) 113 143 #define MAX77705_CHG_FSW_3MHz 0 114 144 #define MAX77705_CHG_FSW_2MHz 1 115 145 #define MAX77705_CHG_FSW_1_5MHz 2 116 146 117 147 /* MAX77705_CHG_REG_CNFG_09 */ 118 - #define MAX77705_CHG_CHGIN_LIM_MASK GENMASK(6, 0) 119 - #define MAX77705_CHG_EN_MASK BIT(7) 120 148 #define MAX77705_CHG_DISABLE 0 121 - #define MAX77705_CHARGER_CHG_CHARGING(_reg) \ 122 - (((_reg) & MAX77705_CHG_EN_MASK) > 1) 123 - 124 - 125 - /* MAX77705_CHG_REG_CNFG_10 */ 126 - #define MAX77705_CHG_WCIN_LIM GENMASK(5, 0) 127 - 128 - /* MAX77705_CHG_REG_CNFG_11 */ 129 - #define MAX77705_VBYPSET_SHIFT 0 130 - #define MAX77705_VBYPSET_MASK GENMASK(6, 0) 131 149 132 150 /* MAX77705_CHG_REG_CNFG_12 */ 133 - #define MAX77705_CHGINSEL_SHIFT 5 134 - #define MAX77705_CHGINSEL_MASK BIT(MAX77705_CHGINSEL_SHIFT) 135 - #define MAX77705_WCINSEL_SHIFT 6 136 - #define MAX77705_WCINSEL_MASK BIT(MAX77705_WCINSEL_SHIFT) 137 - #define MAX77705_VCHGIN_REG_MASK GENMASK(4, 3) 138 - #define MAX77705_WCIN_REG_MASK GENMASK(2, 1) 139 - #define MAX77705_REG_DISKIP_SHIFT 0 140 - #define MAX77705_REG_DISKIP_MASK BIT(MAX77705_REG_DISKIP_SHIFT) 141 151 /* REG=4.5V, UVLO=4.7V */ 142 152 #define MAX77705_VCHGIN_4_5 0 143 153 /* REG=4.5V, UVLO=4.7V */ ··· 129 183 #define MAX77705_CURRENT_CHGIN_MIN 100000 130 184 #define MAX77705_CURRENT_CHGIN_MAX 3200000 131 185 186 + enum max77705_field_idx { 187 + MAX77705_CHGPROT, 188 + MAX77705_CHG_EN, 189 + MAX77705_CHG_CC_LIM, 190 + MAX77705_CHG_CHGIN_LIM, 191 + MAX77705_CHG_CV_PRM, 192 + MAX77705_CHG_PQEN, 193 + MAX77705_CHG_RSTRT, 194 + MAX77705_CHG_WCIN, 195 + MAX77705_FCHGTIME, 196 + MAX77705_LX_SLOPE, 197 + MAX77705_MODE, 198 + MAX77705_OTG_ILIM, 199 + MAX77705_REG_B2SOVRC, 200 + MAX77705_REG_DISKIP, 201 + MAX77705_REG_FSW, 202 + MAX77705_SYS_TRACK, 203 + MAX77705_TO, 204 + MAX77705_TO_TIME, 205 + MAX77705_VBYPSET, 206 + MAX77705_VCHGIN, 207 + MAX77705_WCIN, 208 + MAX77705_N_REGMAP_FIELDS, 209 + }; 210 + 211 + static const struct reg_field max77705_reg_field[MAX77705_N_REGMAP_FIELDS] = { 212 + [MAX77705_MODE] = REG_FIELD(MAX77705_CHG_REG_CNFG_00, 0, 3), 213 + [MAX77705_FCHGTIME] = REG_FIELD(MAX77705_CHG_REG_CNFG_01, 0, 2), 214 + [MAX77705_CHG_RSTRT] = REG_FIELD(MAX77705_CHG_REG_CNFG_01, 4, 5), 215 + [MAX77705_CHG_PQEN] = REG_FIELD(MAX77705_CHG_REG_CNFG_01, 7, 7), 216 + [MAX77705_CHG_CC_LIM] = REG_FIELD(MAX77705_CHG_REG_CNFG_02, 0, 5), 217 + [MAX77705_OTG_ILIM] = REG_FIELD(MAX77705_CHG_REG_CNFG_02, 6, 7), 218 + [MAX77705_TO] = REG_FIELD(MAX77705_CHG_REG_CNFG_03, 0, 2), 219 + [MAX77705_TO_TIME] = REG_FIELD(MAX77705_CHG_REG_CNFG_03, 3, 5), 220 + [MAX77705_SYS_TRACK] = REG_FIELD(MAX77705_CHG_REG_CNFG_03, 7, 7), 221 + [MAX77705_CHG_CV_PRM] = REG_FIELD(MAX77705_CHG_REG_CNFG_04, 0, 5), 222 + [MAX77705_REG_B2SOVRC] = REG_FIELD(MAX77705_CHG_REG_CNFG_05, 0, 3), 223 + [MAX77705_CHGPROT] = REG_FIELD(MAX77705_CHG_REG_CNFG_06, 2, 3), 224 + [MAX77705_LX_SLOPE] = REG_FIELD(MAX77705_CHG_REG_CNFG_06, 5, 6), 225 + [MAX77705_REG_FSW] = REG_FIELD(MAX77705_CHG_REG_CNFG_08, 0, 1), 226 + [MAX77705_CHG_CHGIN_LIM] = REG_FIELD(MAX77705_CHG_REG_CNFG_09, 0, 6), 227 + [MAX77705_CHG_EN] = REG_FIELD(MAX77705_CHG_REG_CNFG_09, 7, 7), 228 + [MAX77705_CHG_WCIN] = REG_FIELD(MAX77705_CHG_REG_CNFG_10, 0, 5), 229 + [MAX77705_VBYPSET] = REG_FIELD(MAX77705_CHG_REG_CNFG_11, 0, 6), 230 + [MAX77705_REG_DISKIP] = REG_FIELD(MAX77705_CHG_REG_CNFG_12, 0, 0), 231 + [MAX77705_WCIN] = REG_FIELD(MAX77705_CHG_REG_CNFG_12, 1, 2), 232 + [MAX77705_VCHGIN] = REG_FIELD(MAX77705_CHG_REG_CNFG_12, 3, 4), 233 + }; 234 + 132 235 struct max77705_charger_data { 133 236 struct device *dev; 134 237 struct regmap *regmap; 238 + struct regmap_field *rfield[MAX77705_N_REGMAP_FIELDS]; 135 239 struct power_supply_battery_info *bat_info; 136 240 struct workqueue_struct *wqueue; 137 241 struct work_struct chgin_work;
+2
include/linux/power_supply.h
··· 176 176 POWER_SUPPLY_PROP_MANUFACTURE_YEAR, 177 177 POWER_SUPPLY_PROP_MANUFACTURE_MONTH, 178 178 POWER_SUPPLY_PROP_MANUFACTURE_DAY, 179 + POWER_SUPPLY_PROP_INTERNAL_RESISTANCE, 180 + POWER_SUPPLY_PROP_STATE_OF_HEALTH, 179 181 /* Properties of type `const char *' */ 180 182 POWER_SUPPLY_PROP_MODEL_NAME, 181 183 POWER_SUPPLY_PROP_MANUFACTURER,