1 | // SPDX-License-Identifier: GPL-2.0-only |
2 | /* |
3 | * Copyright (c) 2019-2020, The Linux Foundation. All rights reserved. |
4 | * Copyright (c) 2022, Linaro Ltd |
5 | */ |
6 | #include <linux/auxiliary_bus.h> |
7 | #include <linux/module.h> |
8 | #include <linux/mutex.h> |
9 | #include <linux/of_device.h> |
10 | #include <linux/power_supply.h> |
11 | #include <linux/soc/qcom/pdr.h> |
12 | #include <linux/soc/qcom/pmic_glink.h> |
13 | #include <linux/math.h> |
14 | #include <linux/units.h> |
15 | |
16 | #define BATTMGR_CHEMISTRY_LEN 4 |
17 | #define BATTMGR_STRING_LEN 128 |
18 | |
19 | enum qcom_battmgr_variant { |
20 | QCOM_BATTMGR_SM8350, |
21 | QCOM_BATTMGR_SC8280XP, |
22 | }; |
23 | |
24 | #define BATTMGR_BAT_STATUS 0x1 |
25 | |
26 | #define BATTMGR_REQUEST_NOTIFICATION 0x4 |
27 | |
28 | #define BATTMGR_NOTIFICATION 0x7 |
29 | #define NOTIF_BAT_PROPERTY 0x30 |
30 | #define NOTIF_USB_PROPERTY 0x32 |
31 | #define NOTIF_WLS_PROPERTY 0x34 |
32 | #define NOTIF_BAT_INFO 0x81 |
33 | #define NOTIF_BAT_STATUS 0x80 |
34 | |
35 | #define BATTMGR_BAT_INFO 0x9 |
36 | |
37 | #define BATTMGR_BAT_DISCHARGE_TIME 0xc |
38 | |
39 | #define BATTMGR_BAT_CHARGE_TIME 0xd |
40 | |
41 | #define BATTMGR_BAT_PROPERTY_GET 0x30 |
42 | #define BATTMGR_BAT_PROPERTY_SET 0x31 |
43 | #define BATT_STATUS 0 |
44 | #define BATT_HEALTH 1 |
45 | #define BATT_PRESENT 2 |
46 | #define BATT_CHG_TYPE 3 |
47 | #define BATT_CAPACITY 4 |
48 | #define BATT_SOH 5 |
49 | #define BATT_VOLT_OCV 6 |
50 | #define BATT_VOLT_NOW 7 |
51 | #define BATT_VOLT_MAX 8 |
52 | #define BATT_CURR_NOW 9 |
53 | #define BATT_CHG_CTRL_LIM 10 |
54 | #define BATT_CHG_CTRL_LIM_MAX 11 |
55 | #define BATT_TEMP 12 |
56 | #define BATT_TECHNOLOGY 13 |
57 | #define BATT_CHG_COUNTER 14 |
58 | #define BATT_CYCLE_COUNT 15 |
59 | #define BATT_CHG_FULL_DESIGN 16 |
60 | #define BATT_CHG_FULL 17 |
61 | #define BATT_MODEL_NAME 18 |
62 | #define BATT_TTF_AVG 19 |
63 | #define BATT_TTE_AVG 20 |
64 | #define BATT_RESISTANCE 21 |
65 | #define BATT_POWER_NOW 22 |
66 | #define BATT_POWER_AVG 23 |
67 | |
68 | #define BATTMGR_USB_PROPERTY_GET 0x32 |
69 | #define BATTMGR_USB_PROPERTY_SET 0x33 |
70 | #define USB_ONLINE 0 |
71 | #define USB_VOLT_NOW 1 |
72 | #define USB_VOLT_MAX 2 |
73 | #define USB_CURR_NOW 3 |
74 | #define USB_CURR_MAX 4 |
75 | #define USB_INPUT_CURR_LIMIT 5 |
76 | #define USB_TYPE 6 |
77 | #define USB_ADAP_TYPE 7 |
78 | #define USB_MOISTURE_DET_EN 8 |
79 | #define USB_MOISTURE_DET_STS 9 |
80 | |
81 | #define BATTMGR_WLS_PROPERTY_GET 0x34 |
82 | #define BATTMGR_WLS_PROPERTY_SET 0x35 |
83 | #define WLS_ONLINE 0 |
84 | #define WLS_VOLT_NOW 1 |
85 | #define WLS_VOLT_MAX 2 |
86 | #define WLS_CURR_NOW 3 |
87 | #define WLS_CURR_MAX 4 |
88 | #define WLS_TYPE 5 |
89 | #define WLS_BOOST_EN 6 |
90 | |
91 | struct qcom_battmgr_enable_request { |
92 | struct pmic_glink_hdr hdr; |
93 | __le32 battery_id; |
94 | __le32 power_state; |
95 | __le32 low_capacity; |
96 | __le32 high_capacity; |
97 | }; |
98 | |
99 | struct qcom_battmgr_property_request { |
100 | struct pmic_glink_hdr hdr; |
101 | __le32 battery; |
102 | __le32 property; |
103 | __le32 value; |
104 | }; |
105 | |
106 | struct qcom_battmgr_update_request { |
107 | struct pmic_glink_hdr hdr; |
108 | __le32 battery_id; |
109 | }; |
110 | |
111 | struct qcom_battmgr_charge_time_request { |
112 | struct pmic_glink_hdr hdr; |
113 | __le32 battery_id; |
114 | __le32 percent; |
115 | __le32 reserved; |
116 | }; |
117 | |
118 | struct qcom_battmgr_discharge_time_request { |
119 | struct pmic_glink_hdr hdr; |
120 | __le32 battery_id; |
121 | __le32 rate; /* 0 for current rate */ |
122 | __le32 reserved; |
123 | }; |
124 | |
125 | struct qcom_battmgr_message { |
126 | struct pmic_glink_hdr hdr; |
127 | union { |
128 | struct { |
129 | __le32 property; |
130 | __le32 value; |
131 | __le32 result; |
132 | } intval; |
133 | struct { |
134 | __le32 property; |
135 | char model[BATTMGR_STRING_LEN]; |
136 | } strval; |
137 | struct { |
138 | /* |
139 | * 0: mWh |
140 | * 1: mAh |
141 | */ |
142 | __le32 power_unit; |
143 | __le32 design_capacity; |
144 | __le32 last_full_capacity; |
145 | /* |
146 | * 0 nonrechargable |
147 | * 1 rechargable |
148 | */ |
149 | __le32 battery_tech; |
150 | __le32 design_voltage; /* mV */ |
151 | __le32 capacity_low; |
152 | __le32 capacity_warning; |
153 | __le32 cycle_count; |
154 | /* thousandth of persent */ |
155 | __le32 accuracy; |
156 | __le32 max_sample_time_ms; |
157 | __le32 min_sample_time_ms; |
158 | __le32 max_average_interval_ms; |
159 | __le32 min_average_interval_ms; |
160 | /* granularity between low and warning */ |
161 | __le32 capacity_granularity1; |
162 | /* granularity between warning and full */ |
163 | __le32 capacity_granularity2; |
164 | /* |
165 | * 0: no |
166 | * 1: cold |
167 | * 2: hot |
168 | */ |
169 | __le32 swappable; |
170 | __le32 capabilities; |
171 | char model_number[BATTMGR_STRING_LEN]; |
172 | char serial_number[BATTMGR_STRING_LEN]; |
173 | char battery_type[BATTMGR_STRING_LEN]; |
174 | char oem_info[BATTMGR_STRING_LEN]; |
175 | char battery_chemistry[BATTMGR_CHEMISTRY_LEN]; |
176 | char uid[BATTMGR_STRING_LEN]; |
177 | __le32 critical_bias; |
178 | u8 day; |
179 | u8 month; |
180 | __le16 year; |
181 | __le32 battery_id; |
182 | } info; |
183 | struct { |
184 | /* |
185 | * BIT(0) discharging |
186 | * BIT(1) charging |
187 | * BIT(2) critical low |
188 | */ |
189 | __le32 battery_state; |
190 | /* mWh or mAh, based on info->power_unit */ |
191 | __le32 capacity; |
192 | __le32 rate; |
193 | /* mv */ |
194 | __le32 battery_voltage; |
195 | /* |
196 | * BIT(0) power online |
197 | * BIT(1) discharging |
198 | * BIT(2) charging |
199 | * BIT(3) battery critical |
200 | */ |
201 | __le32 power_state; |
202 | /* |
203 | * 1: AC |
204 | * 2: USB |
205 | * 3: Wireless |
206 | */ |
207 | __le32 charging_source; |
208 | __le32 temperature; |
209 | } status; |
210 | __le32 time; |
211 | __le32 notification; |
212 | }; |
213 | }; |
214 | |
215 | #define BATTMGR_CHARGING_SOURCE_AC 1 |
216 | #define BATTMGR_CHARGING_SOURCE_USB 2 |
217 | #define BATTMGR_CHARGING_SOURCE_WIRELESS 3 |
218 | |
219 | enum qcom_battmgr_unit { |
220 | QCOM_BATTMGR_UNIT_mWh = 0, |
221 | QCOM_BATTMGR_UNIT_mAh = 1 |
222 | }; |
223 | |
224 | struct qcom_battmgr_info { |
225 | bool valid; |
226 | |
227 | bool present; |
228 | unsigned int charge_type; |
229 | unsigned int design_capacity; |
230 | unsigned int last_full_capacity; |
231 | unsigned int voltage_max_design; |
232 | unsigned int voltage_max; |
233 | unsigned int capacity_low; |
234 | unsigned int capacity_warning; |
235 | unsigned int cycle_count; |
236 | unsigned int charge_count; |
237 | char model_number[BATTMGR_STRING_LEN]; |
238 | char serial_number[BATTMGR_STRING_LEN]; |
239 | char oem_info[BATTMGR_STRING_LEN]; |
240 | unsigned char technology; |
241 | unsigned char day; |
242 | unsigned char month; |
243 | unsigned short year; |
244 | }; |
245 | |
246 | struct qcom_battmgr_status { |
247 | unsigned int status; |
248 | unsigned int health; |
249 | unsigned int capacity; |
250 | unsigned int percent; |
251 | int current_now; |
252 | int power_now; |
253 | unsigned int voltage_now; |
254 | unsigned int voltage_ocv; |
255 | unsigned int temperature; |
256 | |
257 | unsigned int discharge_time; |
258 | unsigned int charge_time; |
259 | }; |
260 | |
261 | struct qcom_battmgr_ac { |
262 | bool online; |
263 | }; |
264 | |
265 | struct qcom_battmgr_usb { |
266 | bool online; |
267 | unsigned int voltage_now; |
268 | unsigned int voltage_max; |
269 | unsigned int current_now; |
270 | unsigned int current_max; |
271 | unsigned int current_limit; |
272 | unsigned int usb_type; |
273 | }; |
274 | |
275 | struct qcom_battmgr_wireless { |
276 | bool online; |
277 | unsigned int voltage_now; |
278 | unsigned int voltage_max; |
279 | unsigned int current_now; |
280 | unsigned int current_max; |
281 | }; |
282 | |
283 | struct qcom_battmgr { |
284 | struct device *dev; |
285 | struct pmic_glink_client *client; |
286 | |
287 | enum qcom_battmgr_variant variant; |
288 | |
289 | struct power_supply *ac_psy; |
290 | struct power_supply *bat_psy; |
291 | struct power_supply *usb_psy; |
292 | struct power_supply *wls_psy; |
293 | |
294 | enum qcom_battmgr_unit unit; |
295 | |
296 | int error; |
297 | struct completion ack; |
298 | |
299 | bool service_up; |
300 | |
301 | struct qcom_battmgr_info info; |
302 | struct qcom_battmgr_status status; |
303 | struct qcom_battmgr_ac ac; |
304 | struct qcom_battmgr_usb usb; |
305 | struct qcom_battmgr_wireless wireless; |
306 | |
307 | struct work_struct enable_work; |
308 | |
309 | /* |
310 | * @lock is used to prevent concurrent power supply requests to the |
311 | * firmware, as it then stops responding. |
312 | */ |
313 | struct mutex lock; |
314 | }; |
315 | |
316 | static int qcom_battmgr_request(struct qcom_battmgr *battmgr, void *data, size_t len) |
317 | { |
318 | unsigned long left; |
319 | int ret; |
320 | |
321 | reinit_completion(x: &battmgr->ack); |
322 | |
323 | battmgr->error = 0; |
324 | |
325 | ret = pmic_glink_send(client: battmgr->client, data, len); |
326 | if (ret < 0) |
327 | return ret; |
328 | |
329 | left = wait_for_completion_timeout(x: &battmgr->ack, HZ); |
330 | if (!left) |
331 | return -ETIMEDOUT; |
332 | |
333 | return battmgr->error; |
334 | } |
335 | |
336 | static int qcom_battmgr_request_property(struct qcom_battmgr *battmgr, int opcode, |
337 | int property, u32 value) |
338 | { |
339 | struct qcom_battmgr_property_request request = { |
340 | .hdr.owner = cpu_to_le32(PMIC_GLINK_OWNER_BATTMGR), |
341 | .hdr.type = cpu_to_le32(PMIC_GLINK_REQ_RESP), |
342 | .hdr.opcode = cpu_to_le32(opcode), |
343 | .battery = cpu_to_le32(0), |
344 | .property = cpu_to_le32(property), |
345 | .value = cpu_to_le32(value), |
346 | }; |
347 | |
348 | return qcom_battmgr_request(battmgr, data: &request, len: sizeof(request)); |
349 | } |
350 | |
351 | static int qcom_battmgr_update_status(struct qcom_battmgr *battmgr) |
352 | { |
353 | struct qcom_battmgr_update_request request = { |
354 | .hdr.owner = cpu_to_le32(PMIC_GLINK_OWNER_BATTMGR), |
355 | .hdr.type = cpu_to_le32(PMIC_GLINK_REQ_RESP), |
356 | .hdr.opcode = cpu_to_le32(BATTMGR_BAT_STATUS), |
357 | .battery_id = cpu_to_le32(0), |
358 | }; |
359 | |
360 | return qcom_battmgr_request(battmgr, data: &request, len: sizeof(request)); |
361 | } |
362 | |
363 | static int qcom_battmgr_update_info(struct qcom_battmgr *battmgr) |
364 | { |
365 | struct qcom_battmgr_update_request request = { |
366 | .hdr.owner = cpu_to_le32(PMIC_GLINK_OWNER_BATTMGR), |
367 | .hdr.type = cpu_to_le32(PMIC_GLINK_REQ_RESP), |
368 | .hdr.opcode = cpu_to_le32(BATTMGR_BAT_INFO), |
369 | .battery_id = cpu_to_le32(0), |
370 | }; |
371 | |
372 | return qcom_battmgr_request(battmgr, data: &request, len: sizeof(request)); |
373 | } |
374 | |
375 | static int qcom_battmgr_update_charge_time(struct qcom_battmgr *battmgr) |
376 | { |
377 | struct qcom_battmgr_charge_time_request request = { |
378 | .hdr.owner = cpu_to_le32(PMIC_GLINK_OWNER_BATTMGR), |
379 | .hdr.type = cpu_to_le32(PMIC_GLINK_REQ_RESP), |
380 | .hdr.opcode = cpu_to_le32(BATTMGR_BAT_CHARGE_TIME), |
381 | .battery_id = cpu_to_le32(0), |
382 | .percent = cpu_to_le32(100), |
383 | }; |
384 | |
385 | return qcom_battmgr_request(battmgr, data: &request, len: sizeof(request)); |
386 | } |
387 | |
388 | static int qcom_battmgr_update_discharge_time(struct qcom_battmgr *battmgr) |
389 | { |
390 | struct qcom_battmgr_discharge_time_request request = { |
391 | .hdr.owner = cpu_to_le32(PMIC_GLINK_OWNER_BATTMGR), |
392 | .hdr.type = cpu_to_le32(PMIC_GLINK_REQ_RESP), |
393 | .hdr.opcode = cpu_to_le32(BATTMGR_BAT_DISCHARGE_TIME), |
394 | .battery_id = cpu_to_le32(0), |
395 | .rate = cpu_to_le32(0), |
396 | }; |
397 | |
398 | return qcom_battmgr_request(battmgr, data: &request, len: sizeof(request)); |
399 | } |
400 | |
401 | static const u8 sm8350_bat_prop_map[] = { |
402 | [POWER_SUPPLY_PROP_STATUS] = BATT_STATUS, |
403 | [POWER_SUPPLY_PROP_HEALTH] = BATT_HEALTH, |
404 | [POWER_SUPPLY_PROP_PRESENT] = BATT_PRESENT, |
405 | [POWER_SUPPLY_PROP_CHARGE_TYPE] = BATT_CHG_TYPE, |
406 | [POWER_SUPPLY_PROP_CAPACITY] = BATT_CAPACITY, |
407 | [POWER_SUPPLY_PROP_VOLTAGE_OCV] = BATT_VOLT_OCV, |
408 | [POWER_SUPPLY_PROP_VOLTAGE_NOW] = BATT_VOLT_NOW, |
409 | [POWER_SUPPLY_PROP_VOLTAGE_MAX] = BATT_VOLT_MAX, |
410 | [POWER_SUPPLY_PROP_CURRENT_NOW] = BATT_CURR_NOW, |
411 | [POWER_SUPPLY_PROP_TEMP] = BATT_TEMP, |
412 | [POWER_SUPPLY_PROP_TECHNOLOGY] = BATT_TECHNOLOGY, |
413 | [POWER_SUPPLY_PROP_CHARGE_COUNTER] = BATT_CHG_COUNTER, |
414 | [POWER_SUPPLY_PROP_CYCLE_COUNT] = BATT_CYCLE_COUNT, |
415 | [POWER_SUPPLY_PROP_CHARGE_FULL_DESIGN] = BATT_CHG_FULL_DESIGN, |
416 | [POWER_SUPPLY_PROP_CHARGE_FULL] = BATT_CHG_FULL, |
417 | [POWER_SUPPLY_PROP_MODEL_NAME] = BATT_MODEL_NAME, |
418 | [POWER_SUPPLY_PROP_TIME_TO_FULL_AVG] = BATT_TTF_AVG, |
419 | [POWER_SUPPLY_PROP_TIME_TO_EMPTY_AVG] = BATT_TTE_AVG, |
420 | [POWER_SUPPLY_PROP_POWER_NOW] = BATT_POWER_NOW, |
421 | }; |
422 | |
423 | static int qcom_battmgr_bat_sm8350_update(struct qcom_battmgr *battmgr, |
424 | enum power_supply_property psp) |
425 | { |
426 | unsigned int prop; |
427 | int ret; |
428 | |
429 | if (psp >= ARRAY_SIZE(sm8350_bat_prop_map)) |
430 | return -EINVAL; |
431 | |
432 | prop = sm8350_bat_prop_map[psp]; |
433 | |
434 | mutex_lock(&battmgr->lock); |
435 | ret = qcom_battmgr_request_property(battmgr, BATTMGR_BAT_PROPERTY_GET, property: prop, value: 0); |
436 | mutex_unlock(lock: &battmgr->lock); |
437 | |
438 | return ret; |
439 | } |
440 | |
441 | static int qcom_battmgr_bat_sc8280xp_update(struct qcom_battmgr *battmgr, |
442 | enum power_supply_property psp) |
443 | { |
444 | int ret; |
445 | |
446 | mutex_lock(&battmgr->lock); |
447 | |
448 | if (!battmgr->info.valid) { |
449 | ret = qcom_battmgr_update_info(battmgr); |
450 | if (ret < 0) |
451 | goto out_unlock; |
452 | battmgr->info.valid = true; |
453 | } |
454 | |
455 | ret = qcom_battmgr_update_status(battmgr); |
456 | if (ret < 0) |
457 | goto out_unlock; |
458 | |
459 | if (psp == POWER_SUPPLY_PROP_TIME_TO_FULL_AVG) { |
460 | ret = qcom_battmgr_update_charge_time(battmgr); |
461 | if (ret < 0) { |
462 | ret = -ENODATA; |
463 | goto out_unlock; |
464 | } |
465 | } |
466 | |
467 | if (psp == POWER_SUPPLY_PROP_TIME_TO_EMPTY_AVG) { |
468 | ret = qcom_battmgr_update_discharge_time(battmgr); |
469 | if (ret < 0) { |
470 | ret = -ENODATA; |
471 | goto out_unlock; |
472 | } |
473 | } |
474 | |
475 | out_unlock: |
476 | mutex_unlock(lock: &battmgr->lock); |
477 | return ret; |
478 | } |
479 | |
480 | static int qcom_battmgr_bat_get_property(struct power_supply *psy, |
481 | enum power_supply_property psp, |
482 | union power_supply_propval *val) |
483 | { |
484 | struct qcom_battmgr *battmgr = power_supply_get_drvdata(psy); |
485 | enum qcom_battmgr_unit unit = battmgr->unit; |
486 | int ret; |
487 | |
488 | if (!battmgr->service_up) |
489 | return -ENODEV; |
490 | |
491 | if (battmgr->variant == QCOM_BATTMGR_SC8280XP) |
492 | ret = qcom_battmgr_bat_sc8280xp_update(battmgr, psp); |
493 | else |
494 | ret = qcom_battmgr_bat_sm8350_update(battmgr, psp); |
495 | if (ret < 0) |
496 | return ret; |
497 | |
498 | switch (psp) { |
499 | case POWER_SUPPLY_PROP_STATUS: |
500 | val->intval = battmgr->status.status; |
501 | break; |
502 | case POWER_SUPPLY_PROP_CHARGE_TYPE: |
503 | val->intval = battmgr->info.charge_type; |
504 | break; |
505 | case POWER_SUPPLY_PROP_HEALTH: |
506 | val->intval = battmgr->status.health; |
507 | break; |
508 | case POWER_SUPPLY_PROP_PRESENT: |
509 | val->intval = battmgr->info.present; |
510 | break; |
511 | case POWER_SUPPLY_PROP_TECHNOLOGY: |
512 | val->intval = battmgr->info.technology; |
513 | break; |
514 | case POWER_SUPPLY_PROP_CYCLE_COUNT: |
515 | val->intval = battmgr->info.cycle_count; |
516 | break; |
517 | case POWER_SUPPLY_PROP_VOLTAGE_MAX_DESIGN: |
518 | val->intval = battmgr->info.voltage_max_design; |
519 | break; |
520 | case POWER_SUPPLY_PROP_VOLTAGE_MAX: |
521 | val->intval = battmgr->info.voltage_max; |
522 | break; |
523 | case POWER_SUPPLY_PROP_VOLTAGE_NOW: |
524 | val->intval = battmgr->status.voltage_now; |
525 | break; |
526 | case POWER_SUPPLY_PROP_VOLTAGE_OCV: |
527 | val->intval = battmgr->status.voltage_ocv; |
528 | break; |
529 | case POWER_SUPPLY_PROP_CURRENT_NOW: |
530 | val->intval = battmgr->status.current_now; |
531 | break; |
532 | case POWER_SUPPLY_PROP_POWER_NOW: |
533 | val->intval = battmgr->status.power_now; |
534 | break; |
535 | case POWER_SUPPLY_PROP_CHARGE_FULL_DESIGN: |
536 | if (unit != QCOM_BATTMGR_UNIT_mAh) |
537 | return -ENODATA; |
538 | val->intval = battmgr->info.design_capacity; |
539 | break; |
540 | case POWER_SUPPLY_PROP_CHARGE_FULL: |
541 | if (unit != QCOM_BATTMGR_UNIT_mAh) |
542 | return -ENODATA; |
543 | val->intval = battmgr->info.last_full_capacity; |
544 | break; |
545 | case POWER_SUPPLY_PROP_CHARGE_EMPTY: |
546 | if (unit != QCOM_BATTMGR_UNIT_mAh) |
547 | return -ENODATA; |
548 | val->intval = battmgr->info.capacity_low; |
549 | break; |
550 | case POWER_SUPPLY_PROP_CHARGE_NOW: |
551 | if (unit != QCOM_BATTMGR_UNIT_mAh) |
552 | return -ENODATA; |
553 | val->intval = battmgr->status.capacity; |
554 | break; |
555 | case POWER_SUPPLY_PROP_CHARGE_COUNTER: |
556 | val->intval = battmgr->info.charge_count; |
557 | break; |
558 | case POWER_SUPPLY_PROP_ENERGY_FULL_DESIGN: |
559 | if (unit != QCOM_BATTMGR_UNIT_mWh) |
560 | return -ENODATA; |
561 | val->intval = battmgr->info.design_capacity; |
562 | break; |
563 | case POWER_SUPPLY_PROP_ENERGY_FULL: |
564 | if (unit != QCOM_BATTMGR_UNIT_mWh) |
565 | return -ENODATA; |
566 | val->intval = battmgr->info.last_full_capacity; |
567 | break; |
568 | case POWER_SUPPLY_PROP_ENERGY_EMPTY: |
569 | if (unit != QCOM_BATTMGR_UNIT_mWh) |
570 | return -ENODATA; |
571 | val->intval = battmgr->info.capacity_low; |
572 | break; |
573 | case POWER_SUPPLY_PROP_ENERGY_NOW: |
574 | if (unit != QCOM_BATTMGR_UNIT_mWh) |
575 | return -ENODATA; |
576 | val->intval = battmgr->status.capacity; |
577 | break; |
578 | case POWER_SUPPLY_PROP_CAPACITY: |
579 | val->intval = battmgr->status.percent; |
580 | break; |
581 | case POWER_SUPPLY_PROP_TEMP: |
582 | val->intval = battmgr->status.temperature; |
583 | break; |
584 | case POWER_SUPPLY_PROP_TIME_TO_EMPTY_AVG: |
585 | val->intval = battmgr->status.discharge_time; |
586 | break; |
587 | case POWER_SUPPLY_PROP_TIME_TO_FULL_AVG: |
588 | val->intval = battmgr->status.charge_time; |
589 | break; |
590 | case POWER_SUPPLY_PROP_MANUFACTURE_YEAR: |
591 | val->intval = battmgr->info.year; |
592 | break; |
593 | case POWER_SUPPLY_PROP_MANUFACTURE_MONTH: |
594 | val->intval = battmgr->info.month; |
595 | break; |
596 | case POWER_SUPPLY_PROP_MANUFACTURE_DAY: |
597 | val->intval = battmgr->info.day; |
598 | break; |
599 | case POWER_SUPPLY_PROP_MODEL_NAME: |
600 | val->strval = battmgr->info.model_number; |
601 | break; |
602 | case POWER_SUPPLY_PROP_MANUFACTURER: |
603 | val->strval = battmgr->info.oem_info; |
604 | break; |
605 | case POWER_SUPPLY_PROP_SERIAL_NUMBER: |
606 | val->strval = battmgr->info.serial_number; |
607 | break; |
608 | default: |
609 | return -EINVAL; |
610 | } |
611 | |
612 | return 0; |
613 | } |
614 | |
615 | static const enum power_supply_property sc8280xp_bat_props[] = { |
616 | POWER_SUPPLY_PROP_STATUS, |
617 | POWER_SUPPLY_PROP_PRESENT, |
618 | POWER_SUPPLY_PROP_TECHNOLOGY, |
619 | POWER_SUPPLY_PROP_CYCLE_COUNT, |
620 | POWER_SUPPLY_PROP_VOLTAGE_MAX_DESIGN, |
621 | POWER_SUPPLY_PROP_VOLTAGE_NOW, |
622 | POWER_SUPPLY_PROP_POWER_NOW, |
623 | POWER_SUPPLY_PROP_CHARGE_FULL_DESIGN, |
624 | POWER_SUPPLY_PROP_CHARGE_FULL, |
625 | POWER_SUPPLY_PROP_CHARGE_EMPTY, |
626 | POWER_SUPPLY_PROP_CHARGE_NOW, |
627 | POWER_SUPPLY_PROP_ENERGY_FULL_DESIGN, |
628 | POWER_SUPPLY_PROP_ENERGY_FULL, |
629 | POWER_SUPPLY_PROP_ENERGY_EMPTY, |
630 | POWER_SUPPLY_PROP_ENERGY_NOW, |
631 | POWER_SUPPLY_PROP_TEMP, |
632 | POWER_SUPPLY_PROP_MANUFACTURE_YEAR, |
633 | POWER_SUPPLY_PROP_MANUFACTURE_MONTH, |
634 | POWER_SUPPLY_PROP_MANUFACTURE_DAY, |
635 | POWER_SUPPLY_PROP_MODEL_NAME, |
636 | POWER_SUPPLY_PROP_MANUFACTURER, |
637 | POWER_SUPPLY_PROP_SERIAL_NUMBER, |
638 | }; |
639 | |
640 | static const struct power_supply_desc sc8280xp_bat_psy_desc = { |
641 | .name = "qcom-battmgr-bat" , |
642 | .type = POWER_SUPPLY_TYPE_BATTERY, |
643 | .properties = sc8280xp_bat_props, |
644 | .num_properties = ARRAY_SIZE(sc8280xp_bat_props), |
645 | .get_property = qcom_battmgr_bat_get_property, |
646 | }; |
647 | |
648 | static const enum power_supply_property sm8350_bat_props[] = { |
649 | POWER_SUPPLY_PROP_STATUS, |
650 | POWER_SUPPLY_PROP_HEALTH, |
651 | POWER_SUPPLY_PROP_PRESENT, |
652 | POWER_SUPPLY_PROP_CHARGE_TYPE, |
653 | POWER_SUPPLY_PROP_CAPACITY, |
654 | POWER_SUPPLY_PROP_VOLTAGE_OCV, |
655 | POWER_SUPPLY_PROP_VOLTAGE_NOW, |
656 | POWER_SUPPLY_PROP_VOLTAGE_MAX, |
657 | POWER_SUPPLY_PROP_CURRENT_NOW, |
658 | POWER_SUPPLY_PROP_TEMP, |
659 | POWER_SUPPLY_PROP_TECHNOLOGY, |
660 | POWER_SUPPLY_PROP_CHARGE_COUNTER, |
661 | POWER_SUPPLY_PROP_CYCLE_COUNT, |
662 | POWER_SUPPLY_PROP_CHARGE_FULL_DESIGN, |
663 | POWER_SUPPLY_PROP_CHARGE_FULL, |
664 | POWER_SUPPLY_PROP_MODEL_NAME, |
665 | POWER_SUPPLY_PROP_TIME_TO_FULL_AVG, |
666 | POWER_SUPPLY_PROP_TIME_TO_EMPTY_AVG, |
667 | POWER_SUPPLY_PROP_POWER_NOW, |
668 | }; |
669 | |
670 | static const struct power_supply_desc sm8350_bat_psy_desc = { |
671 | .name = "qcom-battmgr-bat" , |
672 | .type = POWER_SUPPLY_TYPE_BATTERY, |
673 | .properties = sm8350_bat_props, |
674 | .num_properties = ARRAY_SIZE(sm8350_bat_props), |
675 | .get_property = qcom_battmgr_bat_get_property, |
676 | }; |
677 | |
678 | static int qcom_battmgr_ac_get_property(struct power_supply *psy, |
679 | enum power_supply_property psp, |
680 | union power_supply_propval *val) |
681 | { |
682 | struct qcom_battmgr *battmgr = power_supply_get_drvdata(psy); |
683 | int ret; |
684 | |
685 | if (!battmgr->service_up) |
686 | return -ENODEV; |
687 | |
688 | ret = qcom_battmgr_bat_sc8280xp_update(battmgr, psp); |
689 | if (ret) |
690 | return ret; |
691 | |
692 | switch (psp) { |
693 | case POWER_SUPPLY_PROP_ONLINE: |
694 | val->intval = battmgr->ac.online; |
695 | break; |
696 | default: |
697 | return -EINVAL; |
698 | } |
699 | |
700 | return 0; |
701 | } |
702 | |
703 | static const enum power_supply_property sc8280xp_ac_props[] = { |
704 | POWER_SUPPLY_PROP_ONLINE, |
705 | }; |
706 | |
707 | static const struct power_supply_desc sc8280xp_ac_psy_desc = { |
708 | .name = "qcom-battmgr-ac" , |
709 | .type = POWER_SUPPLY_TYPE_MAINS, |
710 | .properties = sc8280xp_ac_props, |
711 | .num_properties = ARRAY_SIZE(sc8280xp_ac_props), |
712 | .get_property = qcom_battmgr_ac_get_property, |
713 | }; |
714 | |
715 | static const u8 sm8350_usb_prop_map[] = { |
716 | [POWER_SUPPLY_PROP_ONLINE] = USB_ONLINE, |
717 | [POWER_SUPPLY_PROP_VOLTAGE_NOW] = USB_VOLT_NOW, |
718 | [POWER_SUPPLY_PROP_VOLTAGE_MAX] = USB_VOLT_MAX, |
719 | [POWER_SUPPLY_PROP_CURRENT_NOW] = USB_CURR_NOW, |
720 | [POWER_SUPPLY_PROP_CURRENT_MAX] = USB_CURR_MAX, |
721 | [POWER_SUPPLY_PROP_INPUT_CURRENT_LIMIT] = USB_INPUT_CURR_LIMIT, |
722 | [POWER_SUPPLY_PROP_USB_TYPE] = USB_TYPE, |
723 | }; |
724 | |
725 | static int qcom_battmgr_usb_sm8350_update(struct qcom_battmgr *battmgr, |
726 | enum power_supply_property psp) |
727 | { |
728 | unsigned int prop; |
729 | int ret; |
730 | |
731 | if (psp >= ARRAY_SIZE(sm8350_usb_prop_map)) |
732 | return -EINVAL; |
733 | |
734 | prop = sm8350_usb_prop_map[psp]; |
735 | |
736 | mutex_lock(&battmgr->lock); |
737 | ret = qcom_battmgr_request_property(battmgr, BATTMGR_USB_PROPERTY_GET, property: prop, value: 0); |
738 | mutex_unlock(lock: &battmgr->lock); |
739 | |
740 | return ret; |
741 | } |
742 | |
743 | static int qcom_battmgr_usb_get_property(struct power_supply *psy, |
744 | enum power_supply_property psp, |
745 | union power_supply_propval *val) |
746 | { |
747 | struct qcom_battmgr *battmgr = power_supply_get_drvdata(psy); |
748 | int ret; |
749 | |
750 | if (!battmgr->service_up) |
751 | return -ENODEV; |
752 | |
753 | if (battmgr->variant == QCOM_BATTMGR_SC8280XP) |
754 | ret = qcom_battmgr_bat_sc8280xp_update(battmgr, psp); |
755 | else |
756 | ret = qcom_battmgr_usb_sm8350_update(battmgr, psp); |
757 | if (ret) |
758 | return ret; |
759 | |
760 | switch (psp) { |
761 | case POWER_SUPPLY_PROP_ONLINE: |
762 | val->intval = battmgr->usb.online; |
763 | break; |
764 | case POWER_SUPPLY_PROP_VOLTAGE_NOW: |
765 | val->intval = battmgr->usb.voltage_now; |
766 | break; |
767 | case POWER_SUPPLY_PROP_VOLTAGE_MAX: |
768 | val->intval = battmgr->usb.voltage_max; |
769 | break; |
770 | case POWER_SUPPLY_PROP_CURRENT_NOW: |
771 | val->intval = battmgr->usb.current_now; |
772 | break; |
773 | case POWER_SUPPLY_PROP_CURRENT_MAX: |
774 | val->intval = battmgr->usb.current_max; |
775 | break; |
776 | case POWER_SUPPLY_PROP_INPUT_CURRENT_LIMIT: |
777 | val->intval = battmgr->usb.current_limit; |
778 | break; |
779 | case POWER_SUPPLY_PROP_USB_TYPE: |
780 | val->intval = battmgr->usb.usb_type; |
781 | break; |
782 | default: |
783 | return -EINVAL; |
784 | } |
785 | |
786 | return 0; |
787 | } |
788 | |
789 | static const enum power_supply_usb_type usb_psy_supported_types[] = { |
790 | POWER_SUPPLY_USB_TYPE_UNKNOWN, |
791 | POWER_SUPPLY_USB_TYPE_SDP, |
792 | POWER_SUPPLY_USB_TYPE_DCP, |
793 | POWER_SUPPLY_USB_TYPE_CDP, |
794 | POWER_SUPPLY_USB_TYPE_ACA, |
795 | POWER_SUPPLY_USB_TYPE_C, |
796 | POWER_SUPPLY_USB_TYPE_PD, |
797 | POWER_SUPPLY_USB_TYPE_PD_DRP, |
798 | POWER_SUPPLY_USB_TYPE_PD_PPS, |
799 | POWER_SUPPLY_USB_TYPE_APPLE_BRICK_ID, |
800 | }; |
801 | |
802 | static const enum power_supply_property sc8280xp_usb_props[] = { |
803 | POWER_SUPPLY_PROP_ONLINE, |
804 | }; |
805 | |
806 | static const struct power_supply_desc sc8280xp_usb_psy_desc = { |
807 | .name = "qcom-battmgr-usb" , |
808 | .type = POWER_SUPPLY_TYPE_USB, |
809 | .properties = sc8280xp_usb_props, |
810 | .num_properties = ARRAY_SIZE(sc8280xp_usb_props), |
811 | .get_property = qcom_battmgr_usb_get_property, |
812 | .usb_types = usb_psy_supported_types, |
813 | .num_usb_types = ARRAY_SIZE(usb_psy_supported_types), |
814 | }; |
815 | |
816 | static const enum power_supply_property sm8350_usb_props[] = { |
817 | POWER_SUPPLY_PROP_ONLINE, |
818 | POWER_SUPPLY_PROP_VOLTAGE_NOW, |
819 | POWER_SUPPLY_PROP_VOLTAGE_MAX, |
820 | POWER_SUPPLY_PROP_CURRENT_NOW, |
821 | POWER_SUPPLY_PROP_CURRENT_MAX, |
822 | POWER_SUPPLY_PROP_INPUT_CURRENT_LIMIT, |
823 | POWER_SUPPLY_PROP_USB_TYPE, |
824 | }; |
825 | |
826 | static const struct power_supply_desc sm8350_usb_psy_desc = { |
827 | .name = "qcom-battmgr-usb" , |
828 | .type = POWER_SUPPLY_TYPE_USB, |
829 | .properties = sm8350_usb_props, |
830 | .num_properties = ARRAY_SIZE(sm8350_usb_props), |
831 | .get_property = qcom_battmgr_usb_get_property, |
832 | .usb_types = usb_psy_supported_types, |
833 | .num_usb_types = ARRAY_SIZE(usb_psy_supported_types), |
834 | }; |
835 | |
836 | static const u8 sm8350_wls_prop_map[] = { |
837 | [POWER_SUPPLY_PROP_ONLINE] = WLS_ONLINE, |
838 | [POWER_SUPPLY_PROP_VOLTAGE_NOW] = WLS_VOLT_NOW, |
839 | [POWER_SUPPLY_PROP_VOLTAGE_MAX] = WLS_VOLT_MAX, |
840 | [POWER_SUPPLY_PROP_CURRENT_NOW] = WLS_CURR_NOW, |
841 | [POWER_SUPPLY_PROP_CURRENT_MAX] = WLS_CURR_MAX, |
842 | }; |
843 | |
844 | static int qcom_battmgr_wls_sm8350_update(struct qcom_battmgr *battmgr, |
845 | enum power_supply_property psp) |
846 | { |
847 | unsigned int prop; |
848 | int ret; |
849 | |
850 | if (psp >= ARRAY_SIZE(sm8350_wls_prop_map)) |
851 | return -EINVAL; |
852 | |
853 | prop = sm8350_wls_prop_map[psp]; |
854 | |
855 | mutex_lock(&battmgr->lock); |
856 | ret = qcom_battmgr_request_property(battmgr, BATTMGR_WLS_PROPERTY_GET, property: prop, value: 0); |
857 | mutex_unlock(lock: &battmgr->lock); |
858 | |
859 | return ret; |
860 | } |
861 | |
862 | static int qcom_battmgr_wls_get_property(struct power_supply *psy, |
863 | enum power_supply_property psp, |
864 | union power_supply_propval *val) |
865 | { |
866 | struct qcom_battmgr *battmgr = power_supply_get_drvdata(psy); |
867 | int ret; |
868 | |
869 | if (!battmgr->service_up) |
870 | return -ENODEV; |
871 | |
872 | if (battmgr->variant == QCOM_BATTMGR_SC8280XP) |
873 | ret = qcom_battmgr_bat_sc8280xp_update(battmgr, psp); |
874 | else |
875 | ret = qcom_battmgr_wls_sm8350_update(battmgr, psp); |
876 | if (ret < 0) |
877 | return ret; |
878 | |
879 | switch (psp) { |
880 | case POWER_SUPPLY_PROP_ONLINE: |
881 | val->intval = battmgr->wireless.online; |
882 | break; |
883 | case POWER_SUPPLY_PROP_VOLTAGE_NOW: |
884 | val->intval = battmgr->wireless.voltage_now; |
885 | break; |
886 | case POWER_SUPPLY_PROP_VOLTAGE_MAX: |
887 | val->intval = battmgr->wireless.voltage_max; |
888 | break; |
889 | case POWER_SUPPLY_PROP_CURRENT_NOW: |
890 | val->intval = battmgr->wireless.current_now; |
891 | break; |
892 | case POWER_SUPPLY_PROP_CURRENT_MAX: |
893 | val->intval = battmgr->wireless.current_max; |
894 | break; |
895 | default: |
896 | return -EINVAL; |
897 | } |
898 | |
899 | return 0; |
900 | } |
901 | |
902 | static const enum power_supply_property sc8280xp_wls_props[] = { |
903 | POWER_SUPPLY_PROP_ONLINE, |
904 | }; |
905 | |
906 | static const struct power_supply_desc sc8280xp_wls_psy_desc = { |
907 | .name = "qcom-battmgr-wls" , |
908 | .type = POWER_SUPPLY_TYPE_WIRELESS, |
909 | .properties = sc8280xp_wls_props, |
910 | .num_properties = ARRAY_SIZE(sc8280xp_wls_props), |
911 | .get_property = qcom_battmgr_wls_get_property, |
912 | }; |
913 | |
914 | static const enum power_supply_property sm8350_wls_props[] = { |
915 | POWER_SUPPLY_PROP_ONLINE, |
916 | POWER_SUPPLY_PROP_VOLTAGE_NOW, |
917 | POWER_SUPPLY_PROP_VOLTAGE_MAX, |
918 | POWER_SUPPLY_PROP_CURRENT_NOW, |
919 | POWER_SUPPLY_PROP_CURRENT_MAX, |
920 | }; |
921 | |
922 | static const struct power_supply_desc sm8350_wls_psy_desc = { |
923 | .name = "qcom-battmgr-wls" , |
924 | .type = POWER_SUPPLY_TYPE_WIRELESS, |
925 | .properties = sm8350_wls_props, |
926 | .num_properties = ARRAY_SIZE(sm8350_wls_props), |
927 | .get_property = qcom_battmgr_wls_get_property, |
928 | }; |
929 | |
930 | static void qcom_battmgr_notification(struct qcom_battmgr *battmgr, |
931 | const struct qcom_battmgr_message *msg, |
932 | int len) |
933 | { |
934 | size_t payload_len = len - sizeof(struct pmic_glink_hdr); |
935 | unsigned int notification; |
936 | |
937 | if (payload_len != sizeof(msg->notification)) { |
938 | dev_warn(battmgr->dev, "ignoring notification with invalid length\n" ); |
939 | return; |
940 | } |
941 | |
942 | notification = le32_to_cpu(msg->notification); |
943 | switch (notification) { |
944 | case NOTIF_BAT_INFO: |
945 | battmgr->info.valid = false; |
946 | fallthrough; |
947 | case NOTIF_BAT_STATUS: |
948 | case NOTIF_BAT_PROPERTY: |
949 | power_supply_changed(psy: battmgr->bat_psy); |
950 | break; |
951 | case NOTIF_USB_PROPERTY: |
952 | power_supply_changed(psy: battmgr->usb_psy); |
953 | break; |
954 | case NOTIF_WLS_PROPERTY: |
955 | power_supply_changed(psy: battmgr->wls_psy); |
956 | break; |
957 | default: |
958 | dev_err(battmgr->dev, "unknown notification: %#x\n" , notification); |
959 | break; |
960 | } |
961 | } |
962 | |
963 | static void qcom_battmgr_sc8280xp_strcpy(char *dest, const char *src) |
964 | { |
965 | size_t len = src[0]; |
966 | |
967 | /* Some firmware versions return Pascal-style strings */ |
968 | if (len < BATTMGR_STRING_LEN && len == strnlen(p: src + 1, BATTMGR_STRING_LEN - 1)) { |
969 | memcpy(dest, src + 1, len); |
970 | dest[len] = '\0'; |
971 | } else { |
972 | memcpy(dest, src, BATTMGR_STRING_LEN); |
973 | } |
974 | } |
975 | |
976 | static unsigned int qcom_battmgr_sc8280xp_parse_technology(const char *chemistry) |
977 | { |
978 | if (!strncmp(chemistry, "LIO" , BATTMGR_CHEMISTRY_LEN)) |
979 | return POWER_SUPPLY_TECHNOLOGY_LION; |
980 | |
981 | pr_err("Unknown battery technology '%s'\n" , chemistry); |
982 | return POWER_SUPPLY_TECHNOLOGY_UNKNOWN; |
983 | } |
984 | |
985 | static unsigned int qcom_battmgr_sc8280xp_convert_temp(unsigned int temperature) |
986 | { |
987 | return DIV_ROUND_CLOSEST(temperature, 10); |
988 | } |
989 | |
990 | static void qcom_battmgr_sc8280xp_callback(struct qcom_battmgr *battmgr, |
991 | const struct qcom_battmgr_message *resp, |
992 | size_t len) |
993 | { |
994 | unsigned int opcode = le32_to_cpu(resp->hdr.opcode); |
995 | unsigned int source; |
996 | unsigned int state; |
997 | size_t payload_len = len - sizeof(struct pmic_glink_hdr); |
998 | |
999 | if (payload_len < sizeof(__le32)) { |
1000 | dev_warn(battmgr->dev, "invalid payload length for %#x: %zd\n" , |
1001 | opcode, len); |
1002 | return; |
1003 | } |
1004 | |
1005 | switch (opcode) { |
1006 | case BATTMGR_REQUEST_NOTIFICATION: |
1007 | battmgr->error = 0; |
1008 | break; |
1009 | case BATTMGR_BAT_INFO: |
1010 | if (payload_len != sizeof(resp->info)) { |
1011 | dev_warn(battmgr->dev, |
1012 | "invalid payload length for battery information request: %zd\n" , |
1013 | payload_len); |
1014 | battmgr->error = -ENODATA; |
1015 | return; |
1016 | } |
1017 | |
1018 | battmgr->unit = le32_to_cpu(resp->info.power_unit); |
1019 | |
1020 | battmgr->info.present = true; |
1021 | battmgr->info.design_capacity = le32_to_cpu(resp->info.design_capacity) * 1000; |
1022 | battmgr->info.last_full_capacity = le32_to_cpu(resp->info.last_full_capacity) * 1000; |
1023 | battmgr->info.voltage_max_design = le32_to_cpu(resp->info.design_voltage) * 1000; |
1024 | battmgr->info.capacity_low = le32_to_cpu(resp->info.capacity_low) * 1000; |
1025 | battmgr->info.cycle_count = le32_to_cpu(resp->info.cycle_count); |
1026 | qcom_battmgr_sc8280xp_strcpy(dest: battmgr->info.model_number, src: resp->info.model_number); |
1027 | qcom_battmgr_sc8280xp_strcpy(dest: battmgr->info.serial_number, src: resp->info.serial_number); |
1028 | battmgr->info.technology = qcom_battmgr_sc8280xp_parse_technology(chemistry: resp->info.battery_chemistry); |
1029 | qcom_battmgr_sc8280xp_strcpy(dest: battmgr->info.oem_info, src: resp->info.oem_info); |
1030 | battmgr->info.day = resp->info.day; |
1031 | battmgr->info.month = resp->info.month; |
1032 | battmgr->info.year = le16_to_cpu(resp->info.year); |
1033 | break; |
1034 | case BATTMGR_BAT_STATUS: |
1035 | if (payload_len != sizeof(resp->status)) { |
1036 | dev_warn(battmgr->dev, |
1037 | "invalid payload length for battery status request: %zd\n" , |
1038 | payload_len); |
1039 | battmgr->error = -ENODATA; |
1040 | return; |
1041 | } |
1042 | |
1043 | state = le32_to_cpu(resp->status.battery_state); |
1044 | if (state & BIT(0)) |
1045 | battmgr->status.status = POWER_SUPPLY_STATUS_DISCHARGING; |
1046 | else if (state & BIT(1)) |
1047 | battmgr->status.status = POWER_SUPPLY_STATUS_CHARGING; |
1048 | else |
1049 | battmgr->status.status = POWER_SUPPLY_STATUS_NOT_CHARGING; |
1050 | |
1051 | battmgr->status.capacity = le32_to_cpu(resp->status.capacity) * 1000; |
1052 | battmgr->status.power_now = le32_to_cpu(resp->status.rate) * 1000; |
1053 | battmgr->status.voltage_now = le32_to_cpu(resp->status.battery_voltage) * 1000; |
1054 | battmgr->status.temperature = qcom_battmgr_sc8280xp_convert_temp(le32_to_cpu(resp->status.temperature)); |
1055 | |
1056 | source = le32_to_cpu(resp->status.charging_source); |
1057 | battmgr->ac.online = source == BATTMGR_CHARGING_SOURCE_AC; |
1058 | battmgr->usb.online = source == BATTMGR_CHARGING_SOURCE_USB; |
1059 | battmgr->wireless.online = source == BATTMGR_CHARGING_SOURCE_WIRELESS; |
1060 | break; |
1061 | case BATTMGR_BAT_DISCHARGE_TIME: |
1062 | battmgr->status.discharge_time = le32_to_cpu(resp->time); |
1063 | break; |
1064 | case BATTMGR_BAT_CHARGE_TIME: |
1065 | battmgr->status.charge_time = le32_to_cpu(resp->time); |
1066 | break; |
1067 | default: |
1068 | dev_warn(battmgr->dev, "unknown message %#x\n" , opcode); |
1069 | break; |
1070 | } |
1071 | |
1072 | complete(&battmgr->ack); |
1073 | } |
1074 | |
1075 | static void qcom_battmgr_sm8350_callback(struct qcom_battmgr *battmgr, |
1076 | const struct qcom_battmgr_message *resp, |
1077 | size_t len) |
1078 | { |
1079 | unsigned int property; |
1080 | unsigned int opcode = le32_to_cpu(resp->hdr.opcode); |
1081 | size_t payload_len = len - sizeof(struct pmic_glink_hdr); |
1082 | unsigned int val; |
1083 | |
1084 | if (payload_len < sizeof(__le32)) { |
1085 | dev_warn(battmgr->dev, "invalid payload length for %#x: %zd\n" , |
1086 | opcode, len); |
1087 | return; |
1088 | } |
1089 | |
1090 | switch (opcode) { |
1091 | case BATTMGR_BAT_PROPERTY_GET: |
1092 | property = le32_to_cpu(resp->intval.property); |
1093 | if (property == BATT_MODEL_NAME) { |
1094 | if (payload_len != sizeof(resp->strval)) { |
1095 | dev_warn(battmgr->dev, |
1096 | "invalid payload length for BATT_MODEL_NAME request: %zd\n" , |
1097 | payload_len); |
1098 | battmgr->error = -ENODATA; |
1099 | return; |
1100 | } |
1101 | } else { |
1102 | if (payload_len != sizeof(resp->intval)) { |
1103 | dev_warn(battmgr->dev, |
1104 | "invalid payload length for %#x request: %zd\n" , |
1105 | property, payload_len); |
1106 | battmgr->error = -ENODATA; |
1107 | return; |
1108 | } |
1109 | |
1110 | battmgr->error = le32_to_cpu(resp->intval.result); |
1111 | if (battmgr->error) |
1112 | goto out_complete; |
1113 | } |
1114 | |
1115 | switch (property) { |
1116 | case BATT_STATUS: |
1117 | battmgr->status.status = le32_to_cpu(resp->intval.value); |
1118 | break; |
1119 | case BATT_HEALTH: |
1120 | battmgr->status.health = le32_to_cpu(resp->intval.value); |
1121 | break; |
1122 | case BATT_PRESENT: |
1123 | battmgr->info.present = le32_to_cpu(resp->intval.value); |
1124 | break; |
1125 | case BATT_CHG_TYPE: |
1126 | battmgr->info.charge_type = le32_to_cpu(resp->intval.value); |
1127 | break; |
1128 | case BATT_CAPACITY: |
1129 | battmgr->status.percent = le32_to_cpu(resp->intval.value) / 100; |
1130 | break; |
1131 | case BATT_VOLT_OCV: |
1132 | battmgr->status.voltage_ocv = le32_to_cpu(resp->intval.value); |
1133 | break; |
1134 | case BATT_VOLT_NOW: |
1135 | battmgr->status.voltage_now = le32_to_cpu(resp->intval.value); |
1136 | break; |
1137 | case BATT_VOLT_MAX: |
1138 | battmgr->info.voltage_max = le32_to_cpu(resp->intval.value); |
1139 | break; |
1140 | case BATT_CURR_NOW: |
1141 | battmgr->status.current_now = le32_to_cpu(resp->intval.value); |
1142 | break; |
1143 | case BATT_TEMP: |
1144 | val = le32_to_cpu(resp->intval.value); |
1145 | battmgr->status.temperature = DIV_ROUND_CLOSEST(val, 10); |
1146 | break; |
1147 | case BATT_TECHNOLOGY: |
1148 | battmgr->info.technology = le32_to_cpu(resp->intval.value); |
1149 | break; |
1150 | case BATT_CHG_COUNTER: |
1151 | battmgr->info.charge_count = le32_to_cpu(resp->intval.value); |
1152 | break; |
1153 | case BATT_CYCLE_COUNT: |
1154 | battmgr->info.cycle_count = le32_to_cpu(resp->intval.value); |
1155 | break; |
1156 | case BATT_CHG_FULL_DESIGN: |
1157 | battmgr->info.design_capacity = le32_to_cpu(resp->intval.value); |
1158 | break; |
1159 | case BATT_CHG_FULL: |
1160 | battmgr->info.last_full_capacity = le32_to_cpu(resp->intval.value); |
1161 | break; |
1162 | case BATT_MODEL_NAME: |
1163 | strscpy(battmgr->info.model_number, resp->strval.model, BATTMGR_STRING_LEN); |
1164 | break; |
1165 | case BATT_TTF_AVG: |
1166 | battmgr->status.charge_time = le32_to_cpu(resp->intval.value); |
1167 | break; |
1168 | case BATT_TTE_AVG: |
1169 | battmgr->status.discharge_time = le32_to_cpu(resp->intval.value); |
1170 | break; |
1171 | case BATT_POWER_NOW: |
1172 | battmgr->status.power_now = le32_to_cpu(resp->intval.value); |
1173 | break; |
1174 | default: |
1175 | dev_warn(battmgr->dev, "unknown property %#x\n" , property); |
1176 | break; |
1177 | } |
1178 | break; |
1179 | case BATTMGR_USB_PROPERTY_GET: |
1180 | property = le32_to_cpu(resp->intval.property); |
1181 | if (payload_len != sizeof(resp->intval)) { |
1182 | dev_warn(battmgr->dev, |
1183 | "invalid payload length for %#x request: %zd\n" , |
1184 | property, payload_len); |
1185 | battmgr->error = -ENODATA; |
1186 | return; |
1187 | } |
1188 | |
1189 | battmgr->error = le32_to_cpu(resp->intval.result); |
1190 | if (battmgr->error) |
1191 | goto out_complete; |
1192 | |
1193 | switch (property) { |
1194 | case USB_ONLINE: |
1195 | battmgr->usb.online = le32_to_cpu(resp->intval.value); |
1196 | break; |
1197 | case USB_VOLT_NOW: |
1198 | battmgr->usb.voltage_now = le32_to_cpu(resp->intval.value); |
1199 | break; |
1200 | case USB_VOLT_MAX: |
1201 | battmgr->usb.voltage_max = le32_to_cpu(resp->intval.value); |
1202 | break; |
1203 | case USB_CURR_NOW: |
1204 | battmgr->usb.current_now = le32_to_cpu(resp->intval.value); |
1205 | break; |
1206 | case USB_CURR_MAX: |
1207 | battmgr->usb.current_max = le32_to_cpu(resp->intval.value); |
1208 | break; |
1209 | case USB_INPUT_CURR_LIMIT: |
1210 | battmgr->usb.current_limit = le32_to_cpu(resp->intval.value); |
1211 | break; |
1212 | case USB_TYPE: |
1213 | battmgr->usb.usb_type = le32_to_cpu(resp->intval.value); |
1214 | break; |
1215 | default: |
1216 | dev_warn(battmgr->dev, "unknown property %#x\n" , property); |
1217 | break; |
1218 | } |
1219 | break; |
1220 | case BATTMGR_WLS_PROPERTY_GET: |
1221 | property = le32_to_cpu(resp->intval.property); |
1222 | if (payload_len != sizeof(resp->intval)) { |
1223 | dev_warn(battmgr->dev, |
1224 | "invalid payload length for %#x request: %zd\n" , |
1225 | property, payload_len); |
1226 | battmgr->error = -ENODATA; |
1227 | return; |
1228 | } |
1229 | |
1230 | battmgr->error = le32_to_cpu(resp->intval.result); |
1231 | if (battmgr->error) |
1232 | goto out_complete; |
1233 | |
1234 | switch (property) { |
1235 | case WLS_ONLINE: |
1236 | battmgr->wireless.online = le32_to_cpu(resp->intval.value); |
1237 | break; |
1238 | case WLS_VOLT_NOW: |
1239 | battmgr->wireless.voltage_now = le32_to_cpu(resp->intval.value); |
1240 | break; |
1241 | case WLS_VOLT_MAX: |
1242 | battmgr->wireless.voltage_max = le32_to_cpu(resp->intval.value); |
1243 | break; |
1244 | case WLS_CURR_NOW: |
1245 | battmgr->wireless.current_now = le32_to_cpu(resp->intval.value); |
1246 | break; |
1247 | case WLS_CURR_MAX: |
1248 | battmgr->wireless.current_max = le32_to_cpu(resp->intval.value); |
1249 | break; |
1250 | default: |
1251 | dev_warn(battmgr->dev, "unknown property %#x\n" , property); |
1252 | break; |
1253 | } |
1254 | break; |
1255 | case BATTMGR_REQUEST_NOTIFICATION: |
1256 | battmgr->error = 0; |
1257 | break; |
1258 | default: |
1259 | dev_warn(battmgr->dev, "unknown message %#x\n" , opcode); |
1260 | break; |
1261 | } |
1262 | |
1263 | out_complete: |
1264 | complete(&battmgr->ack); |
1265 | } |
1266 | |
1267 | static void qcom_battmgr_callback(const void *data, size_t len, void *priv) |
1268 | { |
1269 | const struct pmic_glink_hdr *hdr = data; |
1270 | struct qcom_battmgr *battmgr = priv; |
1271 | unsigned int opcode = le32_to_cpu(hdr->opcode); |
1272 | |
1273 | if (opcode == BATTMGR_NOTIFICATION) |
1274 | qcom_battmgr_notification(battmgr, msg: data, len); |
1275 | else if (battmgr->variant == QCOM_BATTMGR_SC8280XP) |
1276 | qcom_battmgr_sc8280xp_callback(battmgr, resp: data, len); |
1277 | else |
1278 | qcom_battmgr_sm8350_callback(battmgr, resp: data, len); |
1279 | } |
1280 | |
1281 | static void qcom_battmgr_enable_worker(struct work_struct *work) |
1282 | { |
1283 | struct qcom_battmgr *battmgr = container_of(work, struct qcom_battmgr, enable_work); |
1284 | struct qcom_battmgr_enable_request req = { |
1285 | .hdr.owner = cpu_to_le32(PMIC_GLINK_OWNER_BATTMGR), |
1286 | .hdr.type = cpu_to_le32(PMIC_GLINK_NOTIFY), |
1287 | .hdr.opcode = cpu_to_le32(BATTMGR_REQUEST_NOTIFICATION), |
1288 | }; |
1289 | int ret; |
1290 | |
1291 | ret = qcom_battmgr_request(battmgr, data: &req, len: sizeof(req)); |
1292 | if (ret) |
1293 | dev_err(battmgr->dev, "failed to request power notifications\n" ); |
1294 | } |
1295 | |
1296 | static void qcom_battmgr_pdr_notify(void *priv, int state) |
1297 | { |
1298 | struct qcom_battmgr *battmgr = priv; |
1299 | |
1300 | if (state == SERVREG_SERVICE_STATE_UP) { |
1301 | battmgr->service_up = true; |
1302 | schedule_work(work: &battmgr->enable_work); |
1303 | } else { |
1304 | battmgr->service_up = false; |
1305 | } |
1306 | } |
1307 | |
1308 | static const struct of_device_id qcom_battmgr_of_variants[] = { |
1309 | { .compatible = "qcom,sc8180x-pmic-glink" , .data = (void *)QCOM_BATTMGR_SC8280XP }, |
1310 | { .compatible = "qcom,sc8280xp-pmic-glink" , .data = (void *)QCOM_BATTMGR_SC8280XP }, |
1311 | /* Unmatched devices falls back to QCOM_BATTMGR_SM8350 */ |
1312 | {} |
1313 | }; |
1314 | |
1315 | static char *qcom_battmgr_battery[] = { "battery" }; |
1316 | |
1317 | static int qcom_battmgr_probe(struct auxiliary_device *adev, |
1318 | const struct auxiliary_device_id *id) |
1319 | { |
1320 | struct power_supply_config psy_cfg_supply = {}; |
1321 | struct power_supply_config psy_cfg = {}; |
1322 | const struct of_device_id *match; |
1323 | struct qcom_battmgr *battmgr; |
1324 | struct device *dev = &adev->dev; |
1325 | |
1326 | battmgr = devm_kzalloc(dev, size: sizeof(*battmgr), GFP_KERNEL); |
1327 | if (!battmgr) |
1328 | return -ENOMEM; |
1329 | |
1330 | battmgr->dev = dev; |
1331 | |
1332 | psy_cfg.drv_data = battmgr; |
1333 | psy_cfg.of_node = adev->dev.of_node; |
1334 | |
1335 | psy_cfg_supply.drv_data = battmgr; |
1336 | psy_cfg_supply.of_node = adev->dev.of_node; |
1337 | psy_cfg_supply.supplied_to = qcom_battmgr_battery; |
1338 | psy_cfg_supply.num_supplicants = 1; |
1339 | |
1340 | INIT_WORK(&battmgr->enable_work, qcom_battmgr_enable_worker); |
1341 | mutex_init(&battmgr->lock); |
1342 | init_completion(x: &battmgr->ack); |
1343 | |
1344 | match = of_match_device(matches: qcom_battmgr_of_variants, dev: dev->parent); |
1345 | if (match) |
1346 | battmgr->variant = (unsigned long)match->data; |
1347 | else |
1348 | battmgr->variant = QCOM_BATTMGR_SM8350; |
1349 | |
1350 | if (battmgr->variant == QCOM_BATTMGR_SC8280XP) { |
1351 | battmgr->bat_psy = devm_power_supply_register(parent: dev, desc: &sc8280xp_bat_psy_desc, cfg: &psy_cfg); |
1352 | if (IS_ERR(ptr: battmgr->bat_psy)) |
1353 | return dev_err_probe(dev, err: PTR_ERR(ptr: battmgr->bat_psy), |
1354 | fmt: "failed to register battery power supply\n" ); |
1355 | |
1356 | battmgr->ac_psy = devm_power_supply_register(parent: dev, desc: &sc8280xp_ac_psy_desc, cfg: &psy_cfg_supply); |
1357 | if (IS_ERR(ptr: battmgr->ac_psy)) |
1358 | return dev_err_probe(dev, err: PTR_ERR(ptr: battmgr->ac_psy), |
1359 | fmt: "failed to register AC power supply\n" ); |
1360 | |
1361 | battmgr->usb_psy = devm_power_supply_register(parent: dev, desc: &sc8280xp_usb_psy_desc, cfg: &psy_cfg_supply); |
1362 | if (IS_ERR(ptr: battmgr->usb_psy)) |
1363 | return dev_err_probe(dev, err: PTR_ERR(ptr: battmgr->usb_psy), |
1364 | fmt: "failed to register USB power supply\n" ); |
1365 | |
1366 | battmgr->wls_psy = devm_power_supply_register(parent: dev, desc: &sc8280xp_wls_psy_desc, cfg: &psy_cfg_supply); |
1367 | if (IS_ERR(ptr: battmgr->wls_psy)) |
1368 | return dev_err_probe(dev, err: PTR_ERR(ptr: battmgr->wls_psy), |
1369 | fmt: "failed to register wireless charing power supply\n" ); |
1370 | } else { |
1371 | battmgr->bat_psy = devm_power_supply_register(parent: dev, desc: &sm8350_bat_psy_desc, cfg: &psy_cfg); |
1372 | if (IS_ERR(ptr: battmgr->bat_psy)) |
1373 | return dev_err_probe(dev, err: PTR_ERR(ptr: battmgr->bat_psy), |
1374 | fmt: "failed to register battery power supply\n" ); |
1375 | |
1376 | battmgr->usb_psy = devm_power_supply_register(parent: dev, desc: &sm8350_usb_psy_desc, cfg: &psy_cfg_supply); |
1377 | if (IS_ERR(ptr: battmgr->usb_psy)) |
1378 | return dev_err_probe(dev, err: PTR_ERR(ptr: battmgr->usb_psy), |
1379 | fmt: "failed to register USB power supply\n" ); |
1380 | |
1381 | battmgr->wls_psy = devm_power_supply_register(parent: dev, desc: &sm8350_wls_psy_desc, cfg: &psy_cfg_supply); |
1382 | if (IS_ERR(ptr: battmgr->wls_psy)) |
1383 | return dev_err_probe(dev, err: PTR_ERR(ptr: battmgr->wls_psy), |
1384 | fmt: "failed to register wireless charing power supply\n" ); |
1385 | } |
1386 | |
1387 | battmgr->client = devm_pmic_glink_register_client(dev, |
1388 | PMIC_GLINK_OWNER_BATTMGR, |
1389 | cb: qcom_battmgr_callback, |
1390 | pdr: qcom_battmgr_pdr_notify, |
1391 | priv: battmgr); |
1392 | return PTR_ERR_OR_ZERO(ptr: battmgr->client); |
1393 | } |
1394 | |
1395 | static const struct auxiliary_device_id qcom_battmgr_id_table[] = { |
1396 | { .name = "pmic_glink.power-supply" , }, |
1397 | {}, |
1398 | }; |
1399 | MODULE_DEVICE_TABLE(auxiliary, qcom_battmgr_id_table); |
1400 | |
1401 | static struct auxiliary_driver qcom_battmgr_driver = { |
1402 | .name = "pmic_glink_power_supply" , |
1403 | .probe = qcom_battmgr_probe, |
1404 | .id_table = qcom_battmgr_id_table, |
1405 | }; |
1406 | |
1407 | module_auxiliary_driver(qcom_battmgr_driver); |
1408 | |
1409 | MODULE_DESCRIPTION("Qualcomm PMIC GLINK battery manager driver" ); |
1410 | MODULE_LICENSE("GPL" ); |
1411 | |