1 | // SPDX-License-Identifier: GPL-2.0 |
2 | /* |
3 | * Power Supply driver for a Greybus module. |
4 | * |
5 | * Copyright 2014-2015 Google Inc. |
6 | * Copyright 2014-2015 Linaro Ltd. |
7 | */ |
8 | |
9 | #include <linux/kernel.h> |
10 | #include <linux/module.h> |
11 | #include <linux/power_supply.h> |
12 | #include <linux/slab.h> |
13 | #include <linux/greybus.h> |
14 | |
15 | #define PROP_MAX 32 |
16 | |
17 | struct gb_power_supply_prop { |
18 | enum power_supply_property prop; |
19 | u8 gb_prop; |
20 | int val; |
21 | int previous_val; |
22 | bool is_writeable; |
23 | }; |
24 | |
25 | struct gb_power_supply { |
26 | u8 id; |
27 | bool registered; |
28 | struct power_supply *psy; |
29 | struct power_supply_desc desc; |
30 | char name[64]; |
31 | struct gb_power_supplies *supplies; |
32 | struct delayed_work work; |
33 | char *manufacturer; |
34 | char *model_name; |
35 | char *serial_number; |
36 | u8 type; |
37 | u8 properties_count; |
38 | u8 properties_count_str; |
39 | unsigned long last_update; |
40 | u8 cache_invalid; |
41 | unsigned int update_interval; |
42 | bool changed; |
43 | struct gb_power_supply_prop *props; |
44 | enum power_supply_property *props_raw; |
45 | bool pm_acquired; |
46 | struct mutex supply_lock; |
47 | }; |
48 | |
49 | struct gb_power_supplies { |
50 | struct gb_connection *connection; |
51 | u8 supplies_count; |
52 | struct gb_power_supply *supply; |
53 | struct mutex supplies_lock; |
54 | }; |
55 | |
56 | #define to_gb_power_supply(x) power_supply_get_drvdata(x) |
57 | |
58 | /* |
59 | * General power supply properties that could be absent from various reasons, |
60 | * like kernel versions or vendor specific versions |
61 | */ |
62 | #ifndef POWER_SUPPLY_PROP_VOLTAGE_BOOT |
63 | #define POWER_SUPPLY_PROP_VOLTAGE_BOOT -1 |
64 | #endif |
65 | #ifndef POWER_SUPPLY_PROP_CURRENT_BOOT |
66 | #define POWER_SUPPLY_PROP_CURRENT_BOOT -1 |
67 | #endif |
68 | #ifndef POWER_SUPPLY_PROP_CALIBRATE |
69 | #define POWER_SUPPLY_PROP_CALIBRATE -1 |
70 | #endif |
71 | |
72 | /* cache time in milliseconds, if cache_time is set to 0 cache is disable */ |
73 | static unsigned int cache_time = 1000; |
74 | /* |
75 | * update interval initial and maximum value, between the two will |
76 | * back-off exponential |
77 | */ |
78 | static unsigned int update_interval_init = 1 * HZ; |
79 | static unsigned int update_interval_max = 30 * HZ; |
80 | |
81 | struct gb_power_supply_changes { |
82 | enum power_supply_property prop; |
83 | u32 tolerance_change; |
84 | void (*prop_changed)(struct gb_power_supply *gbpsy, |
85 | struct gb_power_supply_prop *prop); |
86 | }; |
87 | |
88 | static void gb_power_supply_state_change(struct gb_power_supply *gbpsy, |
89 | struct gb_power_supply_prop *prop); |
90 | |
91 | static const struct gb_power_supply_changes psy_props_changes[] = { |
92 | { .prop = GB_POWER_SUPPLY_PROP_STATUS, |
93 | .tolerance_change = 0, |
94 | .prop_changed = gb_power_supply_state_change, |
95 | }, |
96 | { .prop = GB_POWER_SUPPLY_PROP_TEMP, |
97 | .tolerance_change = 500, |
98 | .prop_changed = NULL, |
99 | }, |
100 | { .prop = GB_POWER_SUPPLY_PROP_ONLINE, |
101 | .tolerance_change = 0, |
102 | .prop_changed = NULL, |
103 | }, |
104 | }; |
105 | |
106 | static int get_psp_from_gb_prop(int gb_prop, enum power_supply_property *psp) |
107 | { |
108 | int prop; |
109 | |
110 | switch (gb_prop) { |
111 | case GB_POWER_SUPPLY_PROP_STATUS: |
112 | prop = POWER_SUPPLY_PROP_STATUS; |
113 | break; |
114 | case GB_POWER_SUPPLY_PROP_CHARGE_TYPE: |
115 | prop = POWER_SUPPLY_PROP_CHARGE_TYPE; |
116 | break; |
117 | case GB_POWER_SUPPLY_PROP_HEALTH: |
118 | prop = POWER_SUPPLY_PROP_HEALTH; |
119 | break; |
120 | case GB_POWER_SUPPLY_PROP_PRESENT: |
121 | prop = POWER_SUPPLY_PROP_PRESENT; |
122 | break; |
123 | case GB_POWER_SUPPLY_PROP_ONLINE: |
124 | prop = POWER_SUPPLY_PROP_ONLINE; |
125 | break; |
126 | case GB_POWER_SUPPLY_PROP_AUTHENTIC: |
127 | prop = POWER_SUPPLY_PROP_AUTHENTIC; |
128 | break; |
129 | case GB_POWER_SUPPLY_PROP_TECHNOLOGY: |
130 | prop = POWER_SUPPLY_PROP_TECHNOLOGY; |
131 | break; |
132 | case GB_POWER_SUPPLY_PROP_CYCLE_COUNT: |
133 | prop = POWER_SUPPLY_PROP_CYCLE_COUNT; |
134 | break; |
135 | case GB_POWER_SUPPLY_PROP_VOLTAGE_MAX: |
136 | prop = POWER_SUPPLY_PROP_VOLTAGE_MAX; |
137 | break; |
138 | case GB_POWER_SUPPLY_PROP_VOLTAGE_MIN: |
139 | prop = POWER_SUPPLY_PROP_VOLTAGE_MIN; |
140 | break; |
141 | case GB_POWER_SUPPLY_PROP_VOLTAGE_MAX_DESIGN: |
142 | prop = POWER_SUPPLY_PROP_VOLTAGE_MAX_DESIGN; |
143 | break; |
144 | case GB_POWER_SUPPLY_PROP_VOLTAGE_MIN_DESIGN: |
145 | prop = POWER_SUPPLY_PROP_VOLTAGE_MIN_DESIGN; |
146 | break; |
147 | case GB_POWER_SUPPLY_PROP_VOLTAGE_NOW: |
148 | prop = POWER_SUPPLY_PROP_VOLTAGE_NOW; |
149 | break; |
150 | case GB_POWER_SUPPLY_PROP_VOLTAGE_AVG: |
151 | prop = POWER_SUPPLY_PROP_VOLTAGE_AVG; |
152 | break; |
153 | case GB_POWER_SUPPLY_PROP_VOLTAGE_OCV: |
154 | prop = POWER_SUPPLY_PROP_VOLTAGE_OCV; |
155 | break; |
156 | case GB_POWER_SUPPLY_PROP_VOLTAGE_BOOT: |
157 | prop = POWER_SUPPLY_PROP_VOLTAGE_BOOT; |
158 | break; |
159 | case GB_POWER_SUPPLY_PROP_CURRENT_MAX: |
160 | prop = POWER_SUPPLY_PROP_CURRENT_MAX; |
161 | break; |
162 | case GB_POWER_SUPPLY_PROP_CURRENT_NOW: |
163 | prop = POWER_SUPPLY_PROP_CURRENT_NOW; |
164 | break; |
165 | case GB_POWER_SUPPLY_PROP_CURRENT_AVG: |
166 | prop = POWER_SUPPLY_PROP_CURRENT_AVG; |
167 | break; |
168 | case GB_POWER_SUPPLY_PROP_CURRENT_BOOT: |
169 | prop = POWER_SUPPLY_PROP_CURRENT_BOOT; |
170 | break; |
171 | case GB_POWER_SUPPLY_PROP_POWER_NOW: |
172 | prop = POWER_SUPPLY_PROP_POWER_NOW; |
173 | break; |
174 | case GB_POWER_SUPPLY_PROP_POWER_AVG: |
175 | prop = POWER_SUPPLY_PROP_POWER_AVG; |
176 | break; |
177 | case GB_POWER_SUPPLY_PROP_CHARGE_FULL_DESIGN: |
178 | prop = POWER_SUPPLY_PROP_CHARGE_FULL_DESIGN; |
179 | break; |
180 | case GB_POWER_SUPPLY_PROP_CHARGE_EMPTY_DESIGN: |
181 | prop = POWER_SUPPLY_PROP_CHARGE_EMPTY_DESIGN; |
182 | break; |
183 | case GB_POWER_SUPPLY_PROP_CHARGE_FULL: |
184 | prop = POWER_SUPPLY_PROP_CHARGE_FULL; |
185 | break; |
186 | case GB_POWER_SUPPLY_PROP_CHARGE_EMPTY: |
187 | prop = POWER_SUPPLY_PROP_CHARGE_EMPTY; |
188 | break; |
189 | case GB_POWER_SUPPLY_PROP_CHARGE_NOW: |
190 | prop = POWER_SUPPLY_PROP_CHARGE_NOW; |
191 | break; |
192 | case GB_POWER_SUPPLY_PROP_CHARGE_AVG: |
193 | prop = POWER_SUPPLY_PROP_CHARGE_AVG; |
194 | break; |
195 | case GB_POWER_SUPPLY_PROP_CHARGE_COUNTER: |
196 | prop = POWER_SUPPLY_PROP_CHARGE_COUNTER; |
197 | break; |
198 | case GB_POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT: |
199 | prop = POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT; |
200 | break; |
201 | case GB_POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT_MAX: |
202 | prop = POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT_MAX; |
203 | break; |
204 | case GB_POWER_SUPPLY_PROP_CONSTANT_CHARGE_VOLTAGE: |
205 | prop = POWER_SUPPLY_PROP_CONSTANT_CHARGE_VOLTAGE; |
206 | break; |
207 | case GB_POWER_SUPPLY_PROP_CONSTANT_CHARGE_VOLTAGE_MAX: |
208 | prop = POWER_SUPPLY_PROP_CONSTANT_CHARGE_VOLTAGE_MAX; |
209 | break; |
210 | case GB_POWER_SUPPLY_PROP_CHARGE_CONTROL_LIMIT: |
211 | prop = POWER_SUPPLY_PROP_CHARGE_CONTROL_LIMIT; |
212 | break; |
213 | case GB_POWER_SUPPLY_PROP_CHARGE_CONTROL_LIMIT_MAX: |
214 | prop = POWER_SUPPLY_PROP_CHARGE_CONTROL_LIMIT_MAX; |
215 | break; |
216 | case GB_POWER_SUPPLY_PROP_INPUT_CURRENT_LIMIT: |
217 | prop = POWER_SUPPLY_PROP_INPUT_CURRENT_LIMIT; |
218 | break; |
219 | case GB_POWER_SUPPLY_PROP_ENERGY_FULL_DESIGN: |
220 | prop = POWER_SUPPLY_PROP_ENERGY_FULL_DESIGN; |
221 | break; |
222 | case GB_POWER_SUPPLY_PROP_ENERGY_EMPTY_DESIGN: |
223 | prop = POWER_SUPPLY_PROP_ENERGY_EMPTY_DESIGN; |
224 | break; |
225 | case GB_POWER_SUPPLY_PROP_ENERGY_FULL: |
226 | prop = POWER_SUPPLY_PROP_ENERGY_FULL; |
227 | break; |
228 | case GB_POWER_SUPPLY_PROP_ENERGY_EMPTY: |
229 | prop = POWER_SUPPLY_PROP_ENERGY_EMPTY; |
230 | break; |
231 | case GB_POWER_SUPPLY_PROP_ENERGY_NOW: |
232 | prop = POWER_SUPPLY_PROP_ENERGY_NOW; |
233 | break; |
234 | case GB_POWER_SUPPLY_PROP_ENERGY_AVG: |
235 | prop = POWER_SUPPLY_PROP_ENERGY_AVG; |
236 | break; |
237 | case GB_POWER_SUPPLY_PROP_CAPACITY: |
238 | prop = POWER_SUPPLY_PROP_CAPACITY; |
239 | break; |
240 | case GB_POWER_SUPPLY_PROP_CAPACITY_ALERT_MIN: |
241 | prop = POWER_SUPPLY_PROP_CAPACITY_ALERT_MIN; |
242 | break; |
243 | case GB_POWER_SUPPLY_PROP_CAPACITY_ALERT_MAX: |
244 | prop = POWER_SUPPLY_PROP_CAPACITY_ALERT_MAX; |
245 | break; |
246 | case GB_POWER_SUPPLY_PROP_CAPACITY_LEVEL: |
247 | prop = POWER_SUPPLY_PROP_CAPACITY_LEVEL; |
248 | break; |
249 | case GB_POWER_SUPPLY_PROP_TEMP: |
250 | prop = POWER_SUPPLY_PROP_TEMP; |
251 | break; |
252 | case GB_POWER_SUPPLY_PROP_TEMP_MAX: |
253 | prop = POWER_SUPPLY_PROP_TEMP_MAX; |
254 | break; |
255 | case GB_POWER_SUPPLY_PROP_TEMP_MIN: |
256 | prop = POWER_SUPPLY_PROP_TEMP_MIN; |
257 | break; |
258 | case GB_POWER_SUPPLY_PROP_TEMP_ALERT_MIN: |
259 | prop = POWER_SUPPLY_PROP_TEMP_ALERT_MIN; |
260 | break; |
261 | case GB_POWER_SUPPLY_PROP_TEMP_ALERT_MAX: |
262 | prop = POWER_SUPPLY_PROP_TEMP_ALERT_MAX; |
263 | break; |
264 | case GB_POWER_SUPPLY_PROP_TEMP_AMBIENT: |
265 | prop = POWER_SUPPLY_PROP_TEMP_AMBIENT; |
266 | break; |
267 | case GB_POWER_SUPPLY_PROP_TEMP_AMBIENT_ALERT_MIN: |
268 | prop = POWER_SUPPLY_PROP_TEMP_AMBIENT_ALERT_MIN; |
269 | break; |
270 | case GB_POWER_SUPPLY_PROP_TEMP_AMBIENT_ALERT_MAX: |
271 | prop = POWER_SUPPLY_PROP_TEMP_AMBIENT_ALERT_MAX; |
272 | break; |
273 | case GB_POWER_SUPPLY_PROP_TIME_TO_EMPTY_NOW: |
274 | prop = POWER_SUPPLY_PROP_TIME_TO_EMPTY_NOW; |
275 | break; |
276 | case GB_POWER_SUPPLY_PROP_TIME_TO_EMPTY_AVG: |
277 | prop = POWER_SUPPLY_PROP_TIME_TO_EMPTY_AVG; |
278 | break; |
279 | case GB_POWER_SUPPLY_PROP_TIME_TO_FULL_NOW: |
280 | prop = POWER_SUPPLY_PROP_TIME_TO_FULL_NOW; |
281 | break; |
282 | case GB_POWER_SUPPLY_PROP_TIME_TO_FULL_AVG: |
283 | prop = POWER_SUPPLY_PROP_TIME_TO_FULL_AVG; |
284 | break; |
285 | case GB_POWER_SUPPLY_PROP_TYPE: |
286 | prop = POWER_SUPPLY_PROP_TYPE; |
287 | break; |
288 | case GB_POWER_SUPPLY_PROP_SCOPE: |
289 | prop = POWER_SUPPLY_PROP_SCOPE; |
290 | break; |
291 | case GB_POWER_SUPPLY_PROP_CHARGE_TERM_CURRENT: |
292 | prop = POWER_SUPPLY_PROP_CHARGE_TERM_CURRENT; |
293 | break; |
294 | case GB_POWER_SUPPLY_PROP_CALIBRATE: |
295 | prop = POWER_SUPPLY_PROP_CALIBRATE; |
296 | break; |
297 | default: |
298 | prop = -1; |
299 | break; |
300 | } |
301 | |
302 | if (prop < 0) |
303 | return prop; |
304 | |
305 | *psp = (enum power_supply_property)prop; |
306 | |
307 | return 0; |
308 | } |
309 | |
310 | static struct gb_connection *get_conn_from_psy(struct gb_power_supply *gbpsy) |
311 | { |
312 | return gbpsy->supplies->connection; |
313 | } |
314 | |
315 | static struct gb_power_supply_prop *get_psy_prop(struct gb_power_supply *gbpsy, |
316 | enum power_supply_property psp) |
317 | { |
318 | int i; |
319 | |
320 | for (i = 0; i < gbpsy->properties_count; i++) |
321 | if (gbpsy->props[i].prop == psp) |
322 | return &gbpsy->props[i]; |
323 | return NULL; |
324 | } |
325 | |
326 | static int is_psy_prop_writeable(struct gb_power_supply *gbpsy, |
327 | enum power_supply_property psp) |
328 | { |
329 | struct gb_power_supply_prop *prop; |
330 | |
331 | prop = get_psy_prop(gbpsy, psp); |
332 | if (!prop) |
333 | return -ENOENT; |
334 | return prop->is_writeable ? 1 : 0; |
335 | } |
336 | |
337 | static int is_prop_valint(enum power_supply_property psp) |
338 | { |
339 | return ((psp < POWER_SUPPLY_PROP_MODEL_NAME) ? 1 : 0); |
340 | } |
341 | |
342 | static void next_interval(struct gb_power_supply *gbpsy) |
343 | { |
344 | if (gbpsy->update_interval == update_interval_max) |
345 | return; |
346 | |
347 | /* do some exponential back-off in the update interval */ |
348 | gbpsy->update_interval *= 2; |
349 | if (gbpsy->update_interval > update_interval_max) |
350 | gbpsy->update_interval = update_interval_max; |
351 | } |
352 | |
353 | static void __gb_power_supply_changed(struct gb_power_supply *gbpsy) |
354 | { |
355 | power_supply_changed(psy: gbpsy->psy); |
356 | } |
357 | |
358 | static void gb_power_supply_state_change(struct gb_power_supply *gbpsy, |
359 | struct gb_power_supply_prop *prop) |
360 | { |
361 | struct gb_connection *connection = get_conn_from_psy(gbpsy); |
362 | int ret; |
363 | |
364 | /* |
365 | * Check gbpsy->pm_acquired to make sure only one pair of 'get_sync' |
366 | * and 'put_autosuspend' runtime pm call for state property change. |
367 | */ |
368 | mutex_lock(&gbpsy->supply_lock); |
369 | |
370 | if ((prop->val == GB_POWER_SUPPLY_STATUS_CHARGING) && |
371 | !gbpsy->pm_acquired) { |
372 | ret = gb_pm_runtime_get_sync(bundle: connection->bundle); |
373 | if (ret) |
374 | dev_err(&connection->bundle->dev, |
375 | "Fail to set wake lock for charging state\n" ); |
376 | else |
377 | gbpsy->pm_acquired = true; |
378 | } else { |
379 | if (gbpsy->pm_acquired) { |
380 | ret = gb_pm_runtime_put_autosuspend(bundle: connection->bundle); |
381 | if (ret) |
382 | dev_err(&connection->bundle->dev, |
383 | "Fail to set wake unlock for none charging\n" ); |
384 | else |
385 | gbpsy->pm_acquired = false; |
386 | } |
387 | } |
388 | |
389 | mutex_unlock(lock: &gbpsy->supply_lock); |
390 | } |
391 | |
392 | static void check_changed(struct gb_power_supply *gbpsy, |
393 | struct gb_power_supply_prop *prop) |
394 | { |
395 | const struct gb_power_supply_changes *psyc; |
396 | int val = prop->val; |
397 | int prev_val = prop->previous_val; |
398 | bool changed = false; |
399 | int i; |
400 | |
401 | for (i = 0; i < ARRAY_SIZE(psy_props_changes); i++) { |
402 | psyc = &psy_props_changes[i]; |
403 | if (prop->prop == psyc->prop) { |
404 | if (!psyc->tolerance_change) |
405 | changed = true; |
406 | else if (val < prev_val && |
407 | prev_val - val > psyc->tolerance_change) |
408 | changed = true; |
409 | else if (val > prev_val && |
410 | val - prev_val > psyc->tolerance_change) |
411 | changed = true; |
412 | |
413 | if (changed && psyc->prop_changed) |
414 | psyc->prop_changed(gbpsy, prop); |
415 | |
416 | if (changed) |
417 | gbpsy->changed = true; |
418 | break; |
419 | } |
420 | } |
421 | } |
422 | |
423 | static int total_props(struct gb_power_supply *gbpsy) |
424 | { |
425 | /* this return the intval plus the strval properties */ |
426 | return (gbpsy->properties_count + gbpsy->properties_count_str); |
427 | } |
428 | |
429 | static void prop_append(struct gb_power_supply *gbpsy, |
430 | enum power_supply_property prop) |
431 | { |
432 | enum power_supply_property *new_props_raw; |
433 | |
434 | gbpsy->properties_count_str++; |
435 | new_props_raw = krealloc(objp: gbpsy->props_raw, new_size: total_props(gbpsy) * |
436 | sizeof(enum power_supply_property), |
437 | GFP_KERNEL); |
438 | if (!new_props_raw) |
439 | return; |
440 | gbpsy->props_raw = new_props_raw; |
441 | gbpsy->props_raw[total_props(gbpsy) - 1] = prop; |
442 | } |
443 | |
444 | static int __gb_power_supply_set_name(char *init_name, char *name, size_t len) |
445 | { |
446 | unsigned int i = 0; |
447 | int ret = 0; |
448 | struct power_supply *psy; |
449 | |
450 | if (!strlen(init_name)) |
451 | init_name = "gb_power_supply" ; |
452 | strscpy(name, init_name, len); |
453 | |
454 | while ((ret < len) && (psy = power_supply_get_by_name(name))) { |
455 | power_supply_put(psy); |
456 | |
457 | ret = snprintf(buf: name, size: len, fmt: "%s_%u" , init_name, ++i); |
458 | } |
459 | if (ret >= len) |
460 | return -ENOMEM; |
461 | return i; |
462 | } |
463 | |
464 | static void _gb_power_supply_append_props(struct gb_power_supply *gbpsy) |
465 | { |
466 | if (strlen(gbpsy->manufacturer)) |
467 | prop_append(gbpsy, prop: POWER_SUPPLY_PROP_MANUFACTURER); |
468 | if (strlen(gbpsy->model_name)) |
469 | prop_append(gbpsy, prop: POWER_SUPPLY_PROP_MODEL_NAME); |
470 | if (strlen(gbpsy->serial_number)) |
471 | prop_append(gbpsy, prop: POWER_SUPPLY_PROP_SERIAL_NUMBER); |
472 | } |
473 | |
474 | static int gb_power_supply_description_get(struct gb_power_supply *gbpsy) |
475 | { |
476 | struct gb_connection *connection = get_conn_from_psy(gbpsy); |
477 | struct gb_power_supply_get_description_request req; |
478 | struct gb_power_supply_get_description_response resp; |
479 | int ret; |
480 | |
481 | req.psy_id = gbpsy->id; |
482 | |
483 | ret = gb_operation_sync(connection, |
484 | GB_POWER_SUPPLY_TYPE_GET_DESCRIPTION, |
485 | request: &req, request_size: sizeof(req), response: &resp, response_size: sizeof(resp)); |
486 | if (ret < 0) |
487 | return ret; |
488 | |
489 | gbpsy->manufacturer = kstrndup(s: resp.manufacturer, PROP_MAX, GFP_KERNEL); |
490 | if (!gbpsy->manufacturer) |
491 | return -ENOMEM; |
492 | gbpsy->model_name = kstrndup(s: resp.model, PROP_MAX, GFP_KERNEL); |
493 | if (!gbpsy->model_name) |
494 | return -ENOMEM; |
495 | gbpsy->serial_number = kstrndup(s: resp.serial_number, PROP_MAX, |
496 | GFP_KERNEL); |
497 | if (!gbpsy->serial_number) |
498 | return -ENOMEM; |
499 | |
500 | gbpsy->type = le16_to_cpu(resp.type); |
501 | gbpsy->properties_count = resp.properties_count; |
502 | |
503 | return 0; |
504 | } |
505 | |
506 | static int gb_power_supply_prop_descriptors_get(struct gb_power_supply *gbpsy) |
507 | { |
508 | struct gb_connection *connection = get_conn_from_psy(gbpsy); |
509 | struct gb_power_supply_get_property_descriptors_request *req; |
510 | struct gb_power_supply_get_property_descriptors_response *resp; |
511 | struct gb_operation *op; |
512 | u8 props_count = gbpsy->properties_count; |
513 | enum power_supply_property psp; |
514 | int ret; |
515 | int i, r = 0; |
516 | |
517 | if (props_count == 0) |
518 | return 0; |
519 | |
520 | op = gb_operation_create(connection, |
521 | GB_POWER_SUPPLY_TYPE_GET_PROP_DESCRIPTORS, |
522 | request_size: sizeof(*req), |
523 | struct_size(resp, props, props_count), |
524 | GFP_KERNEL); |
525 | if (!op) |
526 | return -ENOMEM; |
527 | |
528 | req = op->request->payload; |
529 | req->psy_id = gbpsy->id; |
530 | |
531 | ret = gb_operation_request_send_sync(operation: op); |
532 | if (ret < 0) |
533 | goto out_put_operation; |
534 | |
535 | resp = op->response->payload; |
536 | |
537 | /* validate received properties */ |
538 | for (i = 0; i < props_count; i++) { |
539 | ret = get_psp_from_gb_prop(gb_prop: resp->props[i].property, psp: &psp); |
540 | if (ret < 0) { |
541 | dev_warn(&connection->bundle->dev, |
542 | "greybus property %u it is not supported by this kernel, dropped\n" , |
543 | resp->props[i].property); |
544 | gbpsy->properties_count--; |
545 | } |
546 | } |
547 | |
548 | gbpsy->props = kcalloc(n: gbpsy->properties_count, size: sizeof(*gbpsy->props), |
549 | GFP_KERNEL); |
550 | if (!gbpsy->props) { |
551 | ret = -ENOMEM; |
552 | goto out_put_operation; |
553 | } |
554 | |
555 | gbpsy->props_raw = kcalloc(n: gbpsy->properties_count, |
556 | size: sizeof(*gbpsy->props_raw), GFP_KERNEL); |
557 | if (!gbpsy->props_raw) { |
558 | ret = -ENOMEM; |
559 | goto out_put_operation; |
560 | } |
561 | |
562 | /* Store available properties, skip the ones we do not support */ |
563 | for (i = 0; i < props_count; i++) { |
564 | ret = get_psp_from_gb_prop(gb_prop: resp->props[i].property, psp: &psp); |
565 | if (ret < 0) { |
566 | r++; |
567 | continue; |
568 | } |
569 | gbpsy->props[i - r].prop = psp; |
570 | gbpsy->props[i - r].gb_prop = resp->props[i].property; |
571 | gbpsy->props_raw[i - r] = psp; |
572 | if (resp->props[i].is_writeable) |
573 | gbpsy->props[i - r].is_writeable = true; |
574 | } |
575 | |
576 | /* |
577 | * now append the properties that we already got information in the |
578 | * get_description operation. (char * ones) |
579 | */ |
580 | _gb_power_supply_append_props(gbpsy); |
581 | |
582 | ret = 0; |
583 | out_put_operation: |
584 | gb_operation_put(operation: op); |
585 | |
586 | return ret; |
587 | } |
588 | |
589 | static int __gb_power_supply_property_update(struct gb_power_supply *gbpsy, |
590 | enum power_supply_property psp) |
591 | { |
592 | struct gb_connection *connection = get_conn_from_psy(gbpsy); |
593 | struct gb_power_supply_prop *prop; |
594 | struct gb_power_supply_get_property_request req; |
595 | struct gb_power_supply_get_property_response resp; |
596 | int val; |
597 | int ret; |
598 | |
599 | prop = get_psy_prop(gbpsy, psp); |
600 | if (!prop) |
601 | return -EINVAL; |
602 | req.psy_id = gbpsy->id; |
603 | req.property = prop->gb_prop; |
604 | |
605 | ret = gb_operation_sync(connection, GB_POWER_SUPPLY_TYPE_GET_PROPERTY, |
606 | request: &req, request_size: sizeof(req), response: &resp, response_size: sizeof(resp)); |
607 | if (ret < 0) |
608 | return ret; |
609 | |
610 | val = le32_to_cpu(resp.prop_val); |
611 | if (val == prop->val) |
612 | return 0; |
613 | |
614 | prop->previous_val = prop->val; |
615 | prop->val = val; |
616 | |
617 | check_changed(gbpsy, prop); |
618 | |
619 | return 0; |
620 | } |
621 | |
622 | static int __gb_power_supply_property_get(struct gb_power_supply *gbpsy, |
623 | enum power_supply_property psp, |
624 | union power_supply_propval *val) |
625 | { |
626 | struct gb_power_supply_prop *prop; |
627 | |
628 | prop = get_psy_prop(gbpsy, psp); |
629 | if (!prop) |
630 | return -EINVAL; |
631 | |
632 | val->intval = prop->val; |
633 | return 0; |
634 | } |
635 | |
636 | static int __gb_power_supply_property_strval_get(struct gb_power_supply *gbpsy, |
637 | enum power_supply_property psp, |
638 | union power_supply_propval *val) |
639 | { |
640 | switch (psp) { |
641 | case POWER_SUPPLY_PROP_MODEL_NAME: |
642 | val->strval = gbpsy->model_name; |
643 | break; |
644 | case POWER_SUPPLY_PROP_MANUFACTURER: |
645 | val->strval = gbpsy->manufacturer; |
646 | break; |
647 | case POWER_SUPPLY_PROP_SERIAL_NUMBER: |
648 | val->strval = gbpsy->serial_number; |
649 | break; |
650 | default: |
651 | break; |
652 | } |
653 | |
654 | return 0; |
655 | } |
656 | |
657 | static int _gb_power_supply_property_get(struct gb_power_supply *gbpsy, |
658 | enum power_supply_property psp, |
659 | union power_supply_propval *val) |
660 | { |
661 | struct gb_connection *connection = get_conn_from_psy(gbpsy); |
662 | int ret; |
663 | |
664 | /* |
665 | * Properties of type const char *, were already fetched on |
666 | * get_description operation and should be cached in gb |
667 | */ |
668 | if (is_prop_valint(psp)) |
669 | ret = __gb_power_supply_property_get(gbpsy, psp, val); |
670 | else |
671 | ret = __gb_power_supply_property_strval_get(gbpsy, psp, val); |
672 | |
673 | if (ret < 0) |
674 | dev_err(&connection->bundle->dev, "get property %u\n" , psp); |
675 | |
676 | return 0; |
677 | } |
678 | |
679 | static int is_cache_valid(struct gb_power_supply *gbpsy) |
680 | { |
681 | /* check if cache is good enough or it has expired */ |
682 | if (gbpsy->cache_invalid) { |
683 | gbpsy->cache_invalid = 0; |
684 | return 0; |
685 | } |
686 | |
687 | if (gbpsy->last_update && |
688 | time_is_after_jiffies(gbpsy->last_update + |
689 | msecs_to_jiffies(cache_time))) |
690 | return 1; |
691 | |
692 | return 0; |
693 | } |
694 | |
695 | static int gb_power_supply_status_get(struct gb_power_supply *gbpsy) |
696 | { |
697 | struct gb_connection *connection = get_conn_from_psy(gbpsy); |
698 | int ret = 0; |
699 | int i; |
700 | |
701 | if (is_cache_valid(gbpsy)) |
702 | return 0; |
703 | |
704 | ret = gb_pm_runtime_get_sync(bundle: connection->bundle); |
705 | if (ret) |
706 | return ret; |
707 | |
708 | for (i = 0; i < gbpsy->properties_count; i++) { |
709 | ret = __gb_power_supply_property_update(gbpsy, |
710 | psp: gbpsy->props[i].prop); |
711 | if (ret < 0) |
712 | break; |
713 | } |
714 | |
715 | if (ret == 0) |
716 | gbpsy->last_update = jiffies; |
717 | |
718 | gb_pm_runtime_put_autosuspend(bundle: connection->bundle); |
719 | return ret; |
720 | } |
721 | |
722 | static void gb_power_supply_status_update(struct gb_power_supply *gbpsy) |
723 | { |
724 | /* check if there a change that need to be reported */ |
725 | gb_power_supply_status_get(gbpsy); |
726 | |
727 | if (!gbpsy->changed) |
728 | return; |
729 | |
730 | gbpsy->update_interval = update_interval_init; |
731 | __gb_power_supply_changed(gbpsy); |
732 | gbpsy->changed = false; |
733 | } |
734 | |
735 | static void gb_power_supply_work(struct work_struct *work) |
736 | { |
737 | struct gb_power_supply *gbpsy = container_of(work, |
738 | struct gb_power_supply, |
739 | work.work); |
740 | |
741 | /* |
742 | * if the poll interval is not set, disable polling, this is helpful |
743 | * specially at unregister time. |
744 | */ |
745 | if (!gbpsy->update_interval) |
746 | return; |
747 | |
748 | gb_power_supply_status_update(gbpsy); |
749 | next_interval(gbpsy); |
750 | schedule_delayed_work(dwork: &gbpsy->work, delay: gbpsy->update_interval); |
751 | } |
752 | |
753 | static int get_property(struct power_supply *b, |
754 | enum power_supply_property psp, |
755 | union power_supply_propval *val) |
756 | { |
757 | struct gb_power_supply *gbpsy = to_gb_power_supply(b); |
758 | |
759 | gb_power_supply_status_get(gbpsy); |
760 | |
761 | return _gb_power_supply_property_get(gbpsy, psp, val); |
762 | } |
763 | |
764 | static int gb_power_supply_property_set(struct gb_power_supply *gbpsy, |
765 | enum power_supply_property psp, |
766 | int val) |
767 | { |
768 | struct gb_connection *connection = get_conn_from_psy(gbpsy); |
769 | struct gb_power_supply_prop *prop; |
770 | struct gb_power_supply_set_property_request req; |
771 | int ret; |
772 | |
773 | ret = gb_pm_runtime_get_sync(bundle: connection->bundle); |
774 | if (ret) |
775 | return ret; |
776 | |
777 | prop = get_psy_prop(gbpsy, psp); |
778 | if (!prop) { |
779 | ret = -EINVAL; |
780 | goto out; |
781 | } |
782 | |
783 | req.psy_id = gbpsy->id; |
784 | req.property = prop->gb_prop; |
785 | req.prop_val = cpu_to_le32((s32)val); |
786 | |
787 | ret = gb_operation_sync(connection, GB_POWER_SUPPLY_TYPE_SET_PROPERTY, |
788 | request: &req, request_size: sizeof(req), NULL, response_size: 0); |
789 | if (ret < 0) |
790 | goto out; |
791 | |
792 | /* cache immediately the new value */ |
793 | prop->val = val; |
794 | |
795 | out: |
796 | gb_pm_runtime_put_autosuspend(bundle: connection->bundle); |
797 | return ret; |
798 | } |
799 | |
800 | static int set_property(struct power_supply *b, |
801 | enum power_supply_property psp, |
802 | const union power_supply_propval *val) |
803 | { |
804 | struct gb_power_supply *gbpsy = to_gb_power_supply(b); |
805 | |
806 | return gb_power_supply_property_set(gbpsy, psp, val: val->intval); |
807 | } |
808 | |
809 | static int property_is_writeable(struct power_supply *b, |
810 | enum power_supply_property psp) |
811 | { |
812 | struct gb_power_supply *gbpsy = to_gb_power_supply(b); |
813 | |
814 | return is_psy_prop_writeable(gbpsy, psp); |
815 | } |
816 | |
817 | static int gb_power_supply_register(struct gb_power_supply *gbpsy) |
818 | { |
819 | struct gb_connection *connection = get_conn_from_psy(gbpsy); |
820 | struct power_supply_config cfg = {}; |
821 | |
822 | cfg.drv_data = gbpsy; |
823 | |
824 | gbpsy->desc.name = gbpsy->name; |
825 | gbpsy->desc.type = gbpsy->type; |
826 | gbpsy->desc.properties = gbpsy->props_raw; |
827 | gbpsy->desc.num_properties = total_props(gbpsy); |
828 | gbpsy->desc.get_property = get_property; |
829 | gbpsy->desc.set_property = set_property; |
830 | gbpsy->desc.property_is_writeable = property_is_writeable; |
831 | |
832 | gbpsy->psy = power_supply_register(parent: &connection->bundle->dev, |
833 | desc: &gbpsy->desc, cfg: &cfg); |
834 | return PTR_ERR_OR_ZERO(ptr: gbpsy->psy); |
835 | } |
836 | |
837 | static void _gb_power_supply_free(struct gb_power_supply *gbpsy) |
838 | { |
839 | kfree(objp: gbpsy->serial_number); |
840 | kfree(objp: gbpsy->model_name); |
841 | kfree(objp: gbpsy->manufacturer); |
842 | kfree(objp: gbpsy->props_raw); |
843 | kfree(objp: gbpsy->props); |
844 | } |
845 | |
846 | static void _gb_power_supply_release(struct gb_power_supply *gbpsy) |
847 | { |
848 | gbpsy->update_interval = 0; |
849 | |
850 | cancel_delayed_work_sync(dwork: &gbpsy->work); |
851 | |
852 | if (gbpsy->registered) |
853 | power_supply_unregister(psy: gbpsy->psy); |
854 | |
855 | _gb_power_supply_free(gbpsy); |
856 | } |
857 | |
858 | static void _gb_power_supplies_release(struct gb_power_supplies *supplies) |
859 | { |
860 | int i; |
861 | |
862 | if (!supplies->supply) |
863 | return; |
864 | |
865 | mutex_lock(&supplies->supplies_lock); |
866 | for (i = 0; i < supplies->supplies_count; i++) |
867 | _gb_power_supply_release(gbpsy: &supplies->supply[i]); |
868 | kfree(objp: supplies->supply); |
869 | mutex_unlock(lock: &supplies->supplies_lock); |
870 | kfree(objp: supplies); |
871 | } |
872 | |
873 | static int gb_power_supplies_get_count(struct gb_power_supplies *supplies) |
874 | { |
875 | struct gb_power_supply_get_supplies_response resp; |
876 | int ret; |
877 | |
878 | ret = gb_operation_sync(connection: supplies->connection, |
879 | GB_POWER_SUPPLY_TYPE_GET_SUPPLIES, |
880 | NULL, request_size: 0, response: &resp, response_size: sizeof(resp)); |
881 | if (ret < 0) |
882 | return ret; |
883 | |
884 | if (!resp.supplies_count) |
885 | return -EINVAL; |
886 | |
887 | supplies->supplies_count = resp.supplies_count; |
888 | |
889 | return ret; |
890 | } |
891 | |
892 | static int gb_power_supply_config(struct gb_power_supplies *supplies, int id) |
893 | { |
894 | struct gb_power_supply *gbpsy = &supplies->supply[id]; |
895 | int ret; |
896 | |
897 | gbpsy->supplies = supplies; |
898 | gbpsy->id = id; |
899 | |
900 | ret = gb_power_supply_description_get(gbpsy); |
901 | if (ret < 0) |
902 | return ret; |
903 | |
904 | return gb_power_supply_prop_descriptors_get(gbpsy); |
905 | } |
906 | |
907 | static int gb_power_supply_enable(struct gb_power_supply *gbpsy) |
908 | { |
909 | int ret; |
910 | |
911 | /* guarantee that we have an unique name, before register */ |
912 | ret = __gb_power_supply_set_name(init_name: gbpsy->model_name, name: gbpsy->name, |
913 | len: sizeof(gbpsy->name)); |
914 | if (ret < 0) |
915 | return ret; |
916 | |
917 | mutex_init(&gbpsy->supply_lock); |
918 | |
919 | ret = gb_power_supply_register(gbpsy); |
920 | if (ret < 0) |
921 | return ret; |
922 | |
923 | gbpsy->update_interval = update_interval_init; |
924 | INIT_DELAYED_WORK(&gbpsy->work, gb_power_supply_work); |
925 | schedule_delayed_work(dwork: &gbpsy->work, delay: 0); |
926 | |
927 | /* everything went fine, mark it for release code to know */ |
928 | gbpsy->registered = true; |
929 | |
930 | return 0; |
931 | } |
932 | |
933 | static int gb_power_supplies_setup(struct gb_power_supplies *supplies) |
934 | { |
935 | struct gb_connection *connection = supplies->connection; |
936 | int ret; |
937 | int i; |
938 | |
939 | mutex_lock(&supplies->supplies_lock); |
940 | |
941 | ret = gb_power_supplies_get_count(supplies); |
942 | if (ret < 0) |
943 | goto out; |
944 | |
945 | supplies->supply = kcalloc(n: supplies->supplies_count, |
946 | size: sizeof(struct gb_power_supply), |
947 | GFP_KERNEL); |
948 | |
949 | if (!supplies->supply) { |
950 | ret = -ENOMEM; |
951 | goto out; |
952 | } |
953 | |
954 | for (i = 0; i < supplies->supplies_count; i++) { |
955 | ret = gb_power_supply_config(supplies, id: i); |
956 | if (ret < 0) { |
957 | dev_err(&connection->bundle->dev, |
958 | "Fail to configure supplies devices\n" ); |
959 | goto out; |
960 | } |
961 | } |
962 | out: |
963 | mutex_unlock(lock: &supplies->supplies_lock); |
964 | return ret; |
965 | } |
966 | |
967 | static int gb_power_supplies_register(struct gb_power_supplies *supplies) |
968 | { |
969 | struct gb_connection *connection = supplies->connection; |
970 | int ret = 0; |
971 | int i; |
972 | |
973 | mutex_lock(&supplies->supplies_lock); |
974 | |
975 | for (i = 0; i < supplies->supplies_count; i++) { |
976 | ret = gb_power_supply_enable(gbpsy: &supplies->supply[i]); |
977 | if (ret < 0) { |
978 | dev_err(&connection->bundle->dev, |
979 | "Fail to enable supplies devices\n" ); |
980 | break; |
981 | } |
982 | } |
983 | |
984 | mutex_unlock(lock: &supplies->supplies_lock); |
985 | return ret; |
986 | } |
987 | |
988 | static int gb_supplies_request_handler(struct gb_operation *op) |
989 | { |
990 | struct gb_connection *connection = op->connection; |
991 | struct gb_power_supplies *supplies = gb_connection_get_data(connection); |
992 | struct gb_power_supply *gbpsy; |
993 | struct gb_message *request; |
994 | struct gb_power_supply_event_request *payload; |
995 | u8 psy_id; |
996 | u8 event; |
997 | int ret = 0; |
998 | |
999 | if (op->type != GB_POWER_SUPPLY_TYPE_EVENT) { |
1000 | dev_err(&connection->bundle->dev, |
1001 | "Unsupported unsolicited event: %u\n" , op->type); |
1002 | return -EINVAL; |
1003 | } |
1004 | |
1005 | request = op->request; |
1006 | |
1007 | if (request->payload_size < sizeof(*payload)) { |
1008 | dev_err(&connection->bundle->dev, |
1009 | "Wrong event size received (%zu < %zu)\n" , |
1010 | request->payload_size, sizeof(*payload)); |
1011 | return -EINVAL; |
1012 | } |
1013 | |
1014 | payload = request->payload; |
1015 | psy_id = payload->psy_id; |
1016 | mutex_lock(&supplies->supplies_lock); |
1017 | if (psy_id >= supplies->supplies_count || |
1018 | !supplies->supply[psy_id].registered) { |
1019 | dev_err(&connection->bundle->dev, |
1020 | "Event received for unconfigured power_supply id: %d\n" , |
1021 | psy_id); |
1022 | ret = -EINVAL; |
1023 | goto out_unlock; |
1024 | } |
1025 | |
1026 | event = payload->event; |
1027 | /* |
1028 | * we will only handle events after setup is done and before release is |
1029 | * running. For that just check update_interval. |
1030 | */ |
1031 | gbpsy = &supplies->supply[psy_id]; |
1032 | if (!gbpsy->update_interval) { |
1033 | ret = -ESHUTDOWN; |
1034 | goto out_unlock; |
1035 | } |
1036 | |
1037 | if (event & GB_POWER_SUPPLY_UPDATE) { |
1038 | /* |
1039 | * we need to make sure we invalidate cache, if not no new |
1040 | * values for the properties will be fetch and the all propose |
1041 | * of this event is missed |
1042 | */ |
1043 | gbpsy->cache_invalid = 1; |
1044 | gb_power_supply_status_update(gbpsy); |
1045 | } |
1046 | |
1047 | out_unlock: |
1048 | mutex_unlock(lock: &supplies->supplies_lock); |
1049 | return ret; |
1050 | } |
1051 | |
1052 | static int gb_power_supply_probe(struct gb_bundle *bundle, |
1053 | const struct greybus_bundle_id *id) |
1054 | { |
1055 | struct greybus_descriptor_cport *cport_desc; |
1056 | struct gb_connection *connection; |
1057 | struct gb_power_supplies *supplies; |
1058 | int ret; |
1059 | |
1060 | if (bundle->num_cports != 1) |
1061 | return -ENODEV; |
1062 | |
1063 | cport_desc = &bundle->cport_desc[0]; |
1064 | if (cport_desc->protocol_id != GREYBUS_PROTOCOL_POWER_SUPPLY) |
1065 | return -ENODEV; |
1066 | |
1067 | supplies = kzalloc(size: sizeof(*supplies), GFP_KERNEL); |
1068 | if (!supplies) |
1069 | return -ENOMEM; |
1070 | |
1071 | connection = gb_connection_create(bundle, le16_to_cpu(cport_desc->id), |
1072 | handler: gb_supplies_request_handler); |
1073 | if (IS_ERR(ptr: connection)) { |
1074 | ret = PTR_ERR(ptr: connection); |
1075 | goto out; |
1076 | } |
1077 | |
1078 | supplies->connection = connection; |
1079 | gb_connection_set_data(connection, data: supplies); |
1080 | |
1081 | mutex_init(&supplies->supplies_lock); |
1082 | |
1083 | greybus_set_drvdata(bundle, data: supplies); |
1084 | |
1085 | /* We aren't ready to receive an incoming request yet */ |
1086 | ret = gb_connection_enable_tx(connection); |
1087 | if (ret) |
1088 | goto error_connection_destroy; |
1089 | |
1090 | ret = gb_power_supplies_setup(supplies); |
1091 | if (ret < 0) |
1092 | goto error_connection_disable; |
1093 | |
1094 | /* We are ready to receive an incoming request now, enable RX as well */ |
1095 | ret = gb_connection_enable(connection); |
1096 | if (ret) |
1097 | goto error_connection_disable; |
1098 | |
1099 | ret = gb_power_supplies_register(supplies); |
1100 | if (ret < 0) |
1101 | goto error_connection_disable; |
1102 | |
1103 | gb_pm_runtime_put_autosuspend(bundle); |
1104 | return 0; |
1105 | |
1106 | error_connection_disable: |
1107 | gb_connection_disable(connection); |
1108 | error_connection_destroy: |
1109 | gb_connection_destroy(connection); |
1110 | out: |
1111 | _gb_power_supplies_release(supplies); |
1112 | return ret; |
1113 | } |
1114 | |
1115 | static void gb_power_supply_disconnect(struct gb_bundle *bundle) |
1116 | { |
1117 | struct gb_power_supplies *supplies = greybus_get_drvdata(bundle); |
1118 | |
1119 | gb_connection_disable(connection: supplies->connection); |
1120 | gb_connection_destroy(connection: supplies->connection); |
1121 | |
1122 | _gb_power_supplies_release(supplies); |
1123 | } |
1124 | |
1125 | static const struct greybus_bundle_id gb_power_supply_id_table[] = { |
1126 | { GREYBUS_DEVICE_CLASS(GREYBUS_CLASS_POWER_SUPPLY) }, |
1127 | { } |
1128 | }; |
1129 | MODULE_DEVICE_TABLE(greybus, gb_power_supply_id_table); |
1130 | |
1131 | static struct greybus_driver gb_power_supply_driver = { |
1132 | .name = "power_supply" , |
1133 | .probe = gb_power_supply_probe, |
1134 | .disconnect = gb_power_supply_disconnect, |
1135 | .id_table = gb_power_supply_id_table, |
1136 | }; |
1137 | module_greybus_driver(gb_power_supply_driver); |
1138 | |
1139 | MODULE_LICENSE("GPL v2" ); |
1140 | |