Commit | Line | Data |
---|---|---|
29e8142b BA |
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; | |
383eba9f | 108 | __le32 battery_id; |
29e8142b BA |
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(&battmgr->ack); | |
322 | ||
323 | battmgr->error = 0; | |
324 | ||
325 | ret = pmic_glink_send(battmgr->client, data, len); | |
326 | if (ret < 0) | |
327 | return ret; | |
328 | ||
329 | left = wait_for_completion_timeout(&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, &request, 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, &request, 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, &request, 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, &request, 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, &request, 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, prop, 0); | |
436 | mutex_unlock(&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(&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, prop, 0); | |
738 | mutex_unlock(&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, prop, 0); | |
857 | mutex_unlock(&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(battmgr->bat_psy); | |
950 | break; | |
951 | case NOTIF_USB_PROPERTY: | |
952 | power_supply_changed(battmgr->usb_psy); | |
953 | break; | |
954 | case NOTIF_WLS_PROPERTY: | |
955 | power_supply_changed(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(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(battmgr->info.model_number, resp->info.model_number); | |
1027 | qcom_battmgr_sc8280xp_strcpy(battmgr->info.serial_number, resp->info.serial_number); | |
1028 | battmgr->info.technology = qcom_battmgr_sc8280xp_parse_technology(resp->info.battery_chemistry); | |
1029 | qcom_battmgr_sc8280xp_strcpy(battmgr->info.oem_info, 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: | |
92304df8 | 1129 | battmgr->status.percent = le32_to_cpu(resp->intval.value) / 100; |
29e8142b BA |
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, data, len); | |
1275 | else if (battmgr->variant == QCOM_BATTMGR_SC8280XP) | |
1276 | qcom_battmgr_sc8280xp_callback(battmgr, data, len); | |
1277 | else | |
1278 | qcom_battmgr_sm8350_callback(battmgr, 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 = { | |
8894b432 JH |
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), | |
29e8142b BA |
1288 | }; |
1289 | int ret; | |
1290 | ||
1291 | ret = qcom_battmgr_request(battmgr, &req, 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(&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 | ||
d0266d7a JH |
1315 | static char *qcom_battmgr_battery[] = { "battery" }; |
1316 | ||
29e8142b BA |
1317 | static int qcom_battmgr_probe(struct auxiliary_device *adev, |
1318 | const struct auxiliary_device_id *id) | |
1319 | { | |
d0266d7a JH |
1320 | struct power_supply_config psy_cfg_supply = {}; |
1321 | struct power_supply_config psy_cfg = {}; | |
29e8142b BA |
1322 | const struct of_device_id *match; |
1323 | struct qcom_battmgr *battmgr; | |
1324 | struct device *dev = &adev->dev; | |
1325 | ||
1326 | battmgr = devm_kzalloc(dev, sizeof(*battmgr), GFP_KERNEL); | |
1327 | if (!battmgr) | |
1328 | return -ENOMEM; | |
1329 | ||
1330 | battmgr->dev = dev; | |
d0266d7a JH |
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; | |
29e8142b BA |
1339 | |
1340 | INIT_WORK(&battmgr->enable_work, qcom_battmgr_enable_worker); | |
1341 | mutex_init(&battmgr->lock); | |
1342 | init_completion(&battmgr->ack); | |
1343 | ||
1344 | match = of_match_device(qcom_battmgr_of_variants, dev->parent); | |
1345 | if (match) | |
1346 | battmgr->variant = (unsigned long)match->data; | |
1347 | else | |
1348 | battmgr->variant = QCOM_BATTMGR_SM8350; | |
1349 | ||
d0266d7a JH |
1350 | if (battmgr->variant == QCOM_BATTMGR_SC8280XP) { |
1351 | battmgr->bat_psy = devm_power_supply_register(dev, &sc8280xp_bat_psy_desc, &psy_cfg); | |
1352 | if (IS_ERR(battmgr->bat_psy)) | |
1353 | return dev_err_probe(dev, PTR_ERR(battmgr->bat_psy), | |
1354 | "failed to register battery power supply\n"); | |
1355 | ||
1356 | battmgr->ac_psy = devm_power_supply_register(dev, &sc8280xp_ac_psy_desc, &psy_cfg_supply); | |
1357 | if (IS_ERR(battmgr->ac_psy)) | |
1358 | return dev_err_probe(dev, PTR_ERR(battmgr->ac_psy), | |
1359 | "failed to register AC power supply\n"); | |
1360 | ||
1361 | battmgr->usb_psy = devm_power_supply_register(dev, &sc8280xp_usb_psy_desc, &psy_cfg_supply); | |
1362 | if (IS_ERR(battmgr->usb_psy)) | |
1363 | return dev_err_probe(dev, PTR_ERR(battmgr->usb_psy), | |
1364 | "failed to register USB power supply\n"); | |
1365 | ||
1366 | battmgr->wls_psy = devm_power_supply_register(dev, &sc8280xp_wls_psy_desc, &psy_cfg_supply); | |
1367 | if (IS_ERR(battmgr->wls_psy)) | |
1368 | return dev_err_probe(dev, PTR_ERR(battmgr->wls_psy), | |
1369 | "failed to register wireless charing power supply\n"); | |
1370 | } else { | |
1371 | battmgr->bat_psy = devm_power_supply_register(dev, &sm8350_bat_psy_desc, &psy_cfg); | |
1372 | if (IS_ERR(battmgr->bat_psy)) | |
1373 | return dev_err_probe(dev, PTR_ERR(battmgr->bat_psy), | |
1374 | "failed to register battery power supply\n"); | |
1375 | ||
1376 | battmgr->usb_psy = devm_power_supply_register(dev, &sm8350_usb_psy_desc, &psy_cfg_supply); | |
1377 | if (IS_ERR(battmgr->usb_psy)) | |
1378 | return dev_err_probe(dev, PTR_ERR(battmgr->usb_psy), | |
1379 | "failed to register USB power supply\n"); | |
1380 | ||
1381 | battmgr->wls_psy = devm_power_supply_register(dev, &sm8350_wls_psy_desc, &psy_cfg_supply); | |
1382 | if (IS_ERR(battmgr->wls_psy)) | |
1383 | return dev_err_probe(dev, PTR_ERR(battmgr->wls_psy), | |
1384 | "failed to register wireless charing power supply\n"); | |
1385 | } | |
1386 | ||
29e8142b BA |
1387 | battmgr->client = devm_pmic_glink_register_client(dev, |
1388 | PMIC_GLINK_OWNER_BATTMGR, | |
1389 | qcom_battmgr_callback, | |
1390 | qcom_battmgr_pdr_notify, | |
1391 | battmgr); | |
1392 | return PTR_ERR_OR_ZERO(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"); |