1 | // SPDX-License-Identifier: GPL-2.0 |
2 | /* |
3 | * System Control and Management Interface (SCMI) Sensor Protocol |
4 | * |
5 | * Copyright (C) 2018-2022 ARM Ltd. |
6 | */ |
7 | |
8 | #define pr_fmt(fmt) "SCMI Notifications SENSOR - " fmt |
9 | |
10 | #include <linux/bitfield.h> |
11 | #include <linux/module.h> |
12 | #include <linux/scmi_protocol.h> |
13 | |
14 | #include "protocols.h" |
15 | #include "notify.h" |
16 | |
17 | /* Updated only after ALL the mandatory features for that version are merged */ |
18 | #define SCMI_PROTOCOL_SUPPORTED_VERSION 0x30000 |
19 | |
20 | #define SCMI_MAX_NUM_SENSOR_AXIS 63 |
21 | #define SCMIv2_SENSOR_PROTOCOL 0x10000 |
22 | |
23 | enum scmi_sensor_protocol_cmd { |
24 | SENSOR_DESCRIPTION_GET = 0x3, |
25 | SENSOR_TRIP_POINT_NOTIFY = 0x4, |
26 | SENSOR_TRIP_POINT_CONFIG = 0x5, |
27 | SENSOR_READING_GET = 0x6, |
28 | SENSOR_AXIS_DESCRIPTION_GET = 0x7, |
29 | SENSOR_LIST_UPDATE_INTERVALS = 0x8, |
30 | SENSOR_CONFIG_GET = 0x9, |
31 | SENSOR_CONFIG_SET = 0xA, |
32 | SENSOR_CONTINUOUS_UPDATE_NOTIFY = 0xB, |
33 | SENSOR_NAME_GET = 0xC, |
34 | SENSOR_AXIS_NAME_GET = 0xD, |
35 | }; |
36 | |
37 | struct scmi_msg_resp_sensor_attributes { |
38 | __le16 num_sensors; |
39 | u8 max_requests; |
40 | u8 reserved; |
41 | __le32 reg_addr_low; |
42 | __le32 reg_addr_high; |
43 | __le32 reg_size; |
44 | }; |
45 | |
46 | /* v3 attributes_low macros */ |
47 | #define SUPPORTS_UPDATE_NOTIFY(x) FIELD_GET(BIT(30), (x)) |
48 | #define SENSOR_TSTAMP_EXP(x) FIELD_GET(GENMASK(14, 10), (x)) |
49 | #define SUPPORTS_TIMESTAMP(x) FIELD_GET(BIT(9), (x)) |
50 | #define SUPPORTS_EXTEND_ATTRS(x) FIELD_GET(BIT(8), (x)) |
51 | |
52 | /* v2 attributes_high macros */ |
53 | #define SENSOR_UPDATE_BASE(x) FIELD_GET(GENMASK(31, 27), (x)) |
54 | #define SENSOR_UPDATE_SCALE(x) FIELD_GET(GENMASK(26, 22), (x)) |
55 | |
56 | /* v3 attributes_high macros */ |
57 | #define SENSOR_AXIS_NUMBER(x) FIELD_GET(GENMASK(21, 16), (x)) |
58 | #define SUPPORTS_AXIS(x) FIELD_GET(BIT(8), (x)) |
59 | |
60 | /* v3 resolution macros */ |
61 | #define SENSOR_RES(x) FIELD_GET(GENMASK(26, 0), (x)) |
62 | #define SENSOR_RES_EXP(x) FIELD_GET(GENMASK(31, 27), (x)) |
63 | |
64 | struct scmi_msg_resp_attrs { |
65 | __le32 min_range_low; |
66 | __le32 min_range_high; |
67 | __le32 max_range_low; |
68 | __le32 max_range_high; |
69 | }; |
70 | |
71 | struct scmi_msg_sensor_description { |
72 | __le32 desc_index; |
73 | }; |
74 | |
75 | struct scmi_msg_resp_sensor_description { |
76 | __le16 num_returned; |
77 | __le16 num_remaining; |
78 | struct scmi_sensor_descriptor { |
79 | __le32 id; |
80 | __le32 attributes_low; |
81 | /* Common attributes_low macros */ |
82 | #define SUPPORTS_ASYNC_READ(x) FIELD_GET(BIT(31), (x)) |
83 | #define SUPPORTS_EXTENDED_NAMES(x) FIELD_GET(BIT(29), (x)) |
84 | #define NUM_TRIP_POINTS(x) FIELD_GET(GENMASK(7, 0), (x)) |
85 | __le32 attributes_high; |
86 | /* Common attributes_high macros */ |
87 | #define SENSOR_SCALE(x) FIELD_GET(GENMASK(15, 11), (x)) |
88 | #define SENSOR_SCALE_SIGN BIT(4) |
89 | #define SENSOR_SCALE_EXTEND GENMASK(31, 5) |
90 | #define SENSOR_TYPE(x) FIELD_GET(GENMASK(7, 0), (x)) |
91 | u8 name[SCMI_SHORT_NAME_MAX_SIZE]; |
92 | /* only for version > 2.0 */ |
93 | __le32 power; |
94 | __le32 resolution; |
95 | struct scmi_msg_resp_attrs scalar_attrs; |
96 | } desc[]; |
97 | }; |
98 | |
99 | /* Base scmi_sensor_descriptor size excluding extended attrs after name */ |
100 | #define SCMI_MSG_RESP_SENS_DESCR_BASE_SZ 28 |
101 | |
102 | /* Sign extend to a full s32 */ |
103 | #define S32_EXT(v) \ |
104 | ({ \ |
105 | int __v = (v); \ |
106 | \ |
107 | if (__v & SENSOR_SCALE_SIGN) \ |
108 | __v |= SENSOR_SCALE_EXTEND; \ |
109 | __v; \ |
110 | }) |
111 | |
112 | struct scmi_msg_sensor_axis_description_get { |
113 | __le32 id; |
114 | __le32 axis_desc_index; |
115 | }; |
116 | |
117 | struct scmi_msg_resp_sensor_axis_description { |
118 | __le32 num_axis_flags; |
119 | #define NUM_AXIS_RETURNED(x) FIELD_GET(GENMASK(5, 0), (x)) |
120 | #define NUM_AXIS_REMAINING(x) FIELD_GET(GENMASK(31, 26), (x)) |
121 | struct scmi_axis_descriptor { |
122 | __le32 id; |
123 | __le32 attributes_low; |
124 | #define SUPPORTS_EXTENDED_AXIS_NAMES(x) FIELD_GET(BIT(9), (x)) |
125 | __le32 attributes_high; |
126 | u8 name[SCMI_SHORT_NAME_MAX_SIZE]; |
127 | __le32 resolution; |
128 | struct scmi_msg_resp_attrs attrs; |
129 | } desc[]; |
130 | }; |
131 | |
132 | struct scmi_msg_resp_sensor_axis_names_description { |
133 | __le32 num_axis_flags; |
134 | struct scmi_sensor_axis_name_descriptor { |
135 | __le32 axis_id; |
136 | u8 name[SCMI_MAX_STR_SIZE]; |
137 | } desc[]; |
138 | }; |
139 | |
140 | /* Base scmi_axis_descriptor size excluding extended attrs after name */ |
141 | #define SCMI_MSG_RESP_AXIS_DESCR_BASE_SZ 28 |
142 | |
143 | struct scmi_msg_sensor_list_update_intervals { |
144 | __le32 id; |
145 | __le32 index; |
146 | }; |
147 | |
148 | struct scmi_msg_resp_sensor_list_update_intervals { |
149 | __le32 num_intervals_flags; |
150 | #define NUM_INTERVALS_RETURNED(x) FIELD_GET(GENMASK(11, 0), (x)) |
151 | #define SEGMENTED_INTVL_FORMAT(x) FIELD_GET(BIT(12), (x)) |
152 | #define NUM_INTERVALS_REMAINING(x) FIELD_GET(GENMASK(31, 16), (x)) |
153 | __le32 intervals[]; |
154 | }; |
155 | |
156 | struct scmi_msg_sensor_request_notify { |
157 | __le32 id; |
158 | __le32 event_control; |
159 | #define SENSOR_NOTIFY_ALL BIT(0) |
160 | }; |
161 | |
162 | struct scmi_msg_set_sensor_trip_point { |
163 | __le32 id; |
164 | __le32 event_control; |
165 | #define SENSOR_TP_EVENT_MASK (0x3) |
166 | #define SENSOR_TP_DISABLED 0x0 |
167 | #define SENSOR_TP_POSITIVE 0x1 |
168 | #define SENSOR_TP_NEGATIVE 0x2 |
169 | #define SENSOR_TP_BOTH 0x3 |
170 | #define SENSOR_TP_ID(x) (((x) & 0xff) << 4) |
171 | __le32 value_low; |
172 | __le32 value_high; |
173 | }; |
174 | |
175 | struct scmi_msg_sensor_config_set { |
176 | __le32 id; |
177 | __le32 sensor_config; |
178 | }; |
179 | |
180 | struct scmi_msg_sensor_reading_get { |
181 | __le32 id; |
182 | __le32 flags; |
183 | #define SENSOR_READ_ASYNC BIT(0) |
184 | }; |
185 | |
186 | struct scmi_resp_sensor_reading_complete { |
187 | __le32 id; |
188 | __le32 readings_low; |
189 | __le32 readings_high; |
190 | }; |
191 | |
192 | struct scmi_sensor_reading_resp { |
193 | __le32 sensor_value_low; |
194 | __le32 sensor_value_high; |
195 | __le32 timestamp_low; |
196 | __le32 timestamp_high; |
197 | }; |
198 | |
199 | struct scmi_resp_sensor_reading_complete_v3 { |
200 | __le32 id; |
201 | struct scmi_sensor_reading_resp readings[]; |
202 | }; |
203 | |
204 | struct scmi_sensor_trip_notify_payld { |
205 | __le32 agent_id; |
206 | __le32 sensor_id; |
207 | __le32 trip_point_desc; |
208 | }; |
209 | |
210 | struct scmi_sensor_update_notify_payld { |
211 | __le32 agent_id; |
212 | __le32 sensor_id; |
213 | struct scmi_sensor_reading_resp readings[]; |
214 | }; |
215 | |
216 | struct sensors_info { |
217 | u32 version; |
218 | bool notify_trip_point_cmd; |
219 | bool notify_continuos_update_cmd; |
220 | int num_sensors; |
221 | int max_requests; |
222 | u64 reg_addr; |
223 | u32 reg_size; |
224 | struct scmi_sensor_info *sensors; |
225 | }; |
226 | |
227 | static int scmi_sensor_attributes_get(const struct scmi_protocol_handle *ph, |
228 | struct sensors_info *si) |
229 | { |
230 | int ret; |
231 | struct scmi_xfer *t; |
232 | struct scmi_msg_resp_sensor_attributes *attr; |
233 | |
234 | ret = ph->xops->xfer_get_init(ph, PROTOCOL_ATTRIBUTES, |
235 | 0, sizeof(*attr), &t); |
236 | if (ret) |
237 | return ret; |
238 | |
239 | attr = t->rx.buf; |
240 | |
241 | ret = ph->xops->do_xfer(ph, t); |
242 | if (!ret) { |
243 | si->num_sensors = le16_to_cpu(attr->num_sensors); |
244 | si->max_requests = attr->max_requests; |
245 | si->reg_addr = le32_to_cpu(attr->reg_addr_low) | |
246 | (u64)le32_to_cpu(attr->reg_addr_high) << 32; |
247 | si->reg_size = le32_to_cpu(attr->reg_size); |
248 | } |
249 | |
250 | ph->xops->xfer_put(ph, t); |
251 | |
252 | if (!ret) { |
253 | if (!ph->hops->protocol_msg_check(ph, |
254 | SENSOR_TRIP_POINT_NOTIFY, NULL)) |
255 | si->notify_trip_point_cmd = true; |
256 | |
257 | if (!ph->hops->protocol_msg_check(ph, |
258 | SENSOR_CONTINUOUS_UPDATE_NOTIFY, |
259 | NULL)) |
260 | si->notify_continuos_update_cmd = true; |
261 | } |
262 | |
263 | return ret; |
264 | } |
265 | |
266 | static inline void scmi_parse_range_attrs(struct scmi_range_attrs *out, |
267 | const struct scmi_msg_resp_attrs *in) |
268 | { |
269 | out->min_range = get_unaligned_le64(p: (void *)&in->min_range_low); |
270 | out->max_range = get_unaligned_le64(p: (void *)&in->max_range_low); |
271 | } |
272 | |
273 | struct scmi_sens_ipriv { |
274 | void *priv; |
275 | struct device *dev; |
276 | }; |
277 | |
278 | static void iter_intervals_prepare_message(void *message, |
279 | unsigned int desc_index, |
280 | const void *p) |
281 | { |
282 | struct scmi_msg_sensor_list_update_intervals *msg = message; |
283 | const struct scmi_sensor_info *s; |
284 | |
285 | s = ((const struct scmi_sens_ipriv *)p)->priv; |
286 | /* Set the number of sensors to be skipped/already read */ |
287 | msg->id = cpu_to_le32(s->id); |
288 | msg->index = cpu_to_le32(desc_index); |
289 | } |
290 | |
291 | static int iter_intervals_update_state(struct scmi_iterator_state *st, |
292 | const void *response, void *p) |
293 | { |
294 | u32 flags; |
295 | struct scmi_sensor_info *s = ((struct scmi_sens_ipriv *)p)->priv; |
296 | struct device *dev = ((struct scmi_sens_ipriv *)p)->dev; |
297 | const struct scmi_msg_resp_sensor_list_update_intervals *r = response; |
298 | |
299 | flags = le32_to_cpu(r->num_intervals_flags); |
300 | st->num_returned = NUM_INTERVALS_RETURNED(flags); |
301 | st->num_remaining = NUM_INTERVALS_REMAINING(flags); |
302 | |
303 | /* |
304 | * Max intervals is not declared previously anywhere so we |
305 | * assume it's returned+remaining on first call. |
306 | */ |
307 | if (!st->max_resources) { |
308 | s->intervals.segmented = SEGMENTED_INTVL_FORMAT(flags); |
309 | s->intervals.count = st->num_returned + st->num_remaining; |
310 | /* segmented intervals are reported in one triplet */ |
311 | if (s->intervals.segmented && |
312 | (st->num_remaining || st->num_returned != 3)) { |
313 | dev_err(dev, |
314 | "Sensor ID:%d advertises an invalid segmented interval (%d)\n" , |
315 | s->id, s->intervals.count); |
316 | s->intervals.segmented = false; |
317 | s->intervals.count = 0; |
318 | return -EINVAL; |
319 | } |
320 | /* Direct allocation when exceeding pre-allocated */ |
321 | if (s->intervals.count >= SCMI_MAX_PREALLOC_POOL) { |
322 | s->intervals.desc = |
323 | devm_kcalloc(dev, |
324 | n: s->intervals.count, |
325 | size: sizeof(*s->intervals.desc), |
326 | GFP_KERNEL); |
327 | if (!s->intervals.desc) { |
328 | s->intervals.segmented = false; |
329 | s->intervals.count = 0; |
330 | return -ENOMEM; |
331 | } |
332 | } |
333 | |
334 | st->max_resources = s->intervals.count; |
335 | } |
336 | |
337 | return 0; |
338 | } |
339 | |
340 | static int |
341 | iter_intervals_process_response(const struct scmi_protocol_handle *ph, |
342 | const void *response, |
343 | struct scmi_iterator_state *st, void *p) |
344 | { |
345 | const struct scmi_msg_resp_sensor_list_update_intervals *r = response; |
346 | struct scmi_sensor_info *s = ((struct scmi_sens_ipriv *)p)->priv; |
347 | |
348 | s->intervals.desc[st->desc_index + st->loop_idx] = |
349 | le32_to_cpu(r->intervals[st->loop_idx]); |
350 | |
351 | return 0; |
352 | } |
353 | |
354 | static int scmi_sensor_update_intervals(const struct scmi_protocol_handle *ph, |
355 | struct scmi_sensor_info *s) |
356 | { |
357 | void *iter; |
358 | struct scmi_iterator_ops ops = { |
359 | .prepare_message = iter_intervals_prepare_message, |
360 | .update_state = iter_intervals_update_state, |
361 | .process_response = iter_intervals_process_response, |
362 | }; |
363 | struct scmi_sens_ipriv upriv = { |
364 | .priv = s, |
365 | .dev = ph->dev, |
366 | }; |
367 | |
368 | iter = ph->hops->iter_response_init(ph, &ops, s->intervals.count, |
369 | SENSOR_LIST_UPDATE_INTERVALS, |
370 | sizeof(struct scmi_msg_sensor_list_update_intervals), |
371 | &upriv); |
372 | if (IS_ERR(ptr: iter)) |
373 | return PTR_ERR(ptr: iter); |
374 | |
375 | return ph->hops->iter_response_run(iter); |
376 | } |
377 | |
378 | struct scmi_apriv { |
379 | bool any_axes_support_extended_names; |
380 | struct scmi_sensor_info *s; |
381 | }; |
382 | |
383 | static void iter_axes_desc_prepare_message(void *message, |
384 | const unsigned int desc_index, |
385 | const void *priv) |
386 | { |
387 | struct scmi_msg_sensor_axis_description_get *msg = message; |
388 | const struct scmi_apriv *apriv = priv; |
389 | |
390 | /* Set the number of sensors to be skipped/already read */ |
391 | msg->id = cpu_to_le32(apriv->s->id); |
392 | msg->axis_desc_index = cpu_to_le32(desc_index); |
393 | } |
394 | |
395 | static int |
396 | iter_axes_desc_update_state(struct scmi_iterator_state *st, |
397 | const void *response, void *priv) |
398 | { |
399 | u32 flags; |
400 | const struct scmi_msg_resp_sensor_axis_description *r = response; |
401 | |
402 | flags = le32_to_cpu(r->num_axis_flags); |
403 | st->num_returned = NUM_AXIS_RETURNED(flags); |
404 | st->num_remaining = NUM_AXIS_REMAINING(flags); |
405 | st->priv = (void *)&r->desc[0]; |
406 | |
407 | return 0; |
408 | } |
409 | |
410 | static int |
411 | iter_axes_desc_process_response(const struct scmi_protocol_handle *ph, |
412 | const void *response, |
413 | struct scmi_iterator_state *st, void *priv) |
414 | { |
415 | u32 attrh, attrl; |
416 | struct scmi_sensor_axis_info *a; |
417 | size_t dsize = SCMI_MSG_RESP_AXIS_DESCR_BASE_SZ; |
418 | struct scmi_apriv *apriv = priv; |
419 | const struct scmi_axis_descriptor *adesc = st->priv; |
420 | |
421 | attrl = le32_to_cpu(adesc->attributes_low); |
422 | if (SUPPORTS_EXTENDED_AXIS_NAMES(attrl)) |
423 | apriv->any_axes_support_extended_names = true; |
424 | |
425 | a = &apriv->s->axis[st->desc_index + st->loop_idx]; |
426 | a->id = le32_to_cpu(adesc->id); |
427 | a->extended_attrs = SUPPORTS_EXTEND_ATTRS(attrl); |
428 | |
429 | attrh = le32_to_cpu(adesc->attributes_high); |
430 | a->scale = S32_EXT(SENSOR_SCALE(attrh)); |
431 | a->type = SENSOR_TYPE(attrh); |
432 | strscpy(a->name, adesc->name, SCMI_SHORT_NAME_MAX_SIZE); |
433 | |
434 | if (a->extended_attrs) { |
435 | unsigned int ares = le32_to_cpu(adesc->resolution); |
436 | |
437 | a->resolution = SENSOR_RES(ares); |
438 | a->exponent = S32_EXT(SENSOR_RES_EXP(ares)); |
439 | dsize += sizeof(adesc->resolution); |
440 | |
441 | scmi_parse_range_attrs(out: &a->attrs, in: &adesc->attrs); |
442 | dsize += sizeof(adesc->attrs); |
443 | } |
444 | st->priv = ((u8 *)adesc + dsize); |
445 | |
446 | return 0; |
447 | } |
448 | |
449 | static int |
450 | iter_axes_extended_name_update_state(struct scmi_iterator_state *st, |
451 | const void *response, void *priv) |
452 | { |
453 | u32 flags; |
454 | const struct scmi_msg_resp_sensor_axis_names_description *r = response; |
455 | |
456 | flags = le32_to_cpu(r->num_axis_flags); |
457 | st->num_returned = NUM_AXIS_RETURNED(flags); |
458 | st->num_remaining = NUM_AXIS_REMAINING(flags); |
459 | st->priv = (void *)&r->desc[0]; |
460 | |
461 | return 0; |
462 | } |
463 | |
464 | static int |
465 | iter_axes_extended_name_process_response(const struct scmi_protocol_handle *ph, |
466 | const void *response, |
467 | struct scmi_iterator_state *st, |
468 | void *priv) |
469 | { |
470 | struct scmi_sensor_axis_info *a; |
471 | const struct scmi_apriv *apriv = priv; |
472 | struct scmi_sensor_axis_name_descriptor *adesc = st->priv; |
473 | u32 axis_id = le32_to_cpu(adesc->axis_id); |
474 | |
475 | if (axis_id >= st->max_resources) |
476 | return -EPROTO; |
477 | |
478 | /* |
479 | * Pick the corresponding descriptor based on the axis_id embedded |
480 | * in the reply since the list of axes supporting extended names |
481 | * can be a subset of all the axes. |
482 | */ |
483 | a = &apriv->s->axis[axis_id]; |
484 | strscpy(a->name, adesc->name, SCMI_MAX_STR_SIZE); |
485 | st->priv = ++adesc; |
486 | |
487 | return 0; |
488 | } |
489 | |
490 | static int |
491 | scmi_sensor_axis_extended_names_get(const struct scmi_protocol_handle *ph, |
492 | struct scmi_sensor_info *s) |
493 | { |
494 | int ret; |
495 | void *iter; |
496 | struct scmi_iterator_ops ops = { |
497 | .prepare_message = iter_axes_desc_prepare_message, |
498 | .update_state = iter_axes_extended_name_update_state, |
499 | .process_response = iter_axes_extended_name_process_response, |
500 | }; |
501 | struct scmi_apriv apriv = { |
502 | .any_axes_support_extended_names = false, |
503 | .s = s, |
504 | }; |
505 | |
506 | iter = ph->hops->iter_response_init(ph, &ops, s->num_axis, |
507 | SENSOR_AXIS_NAME_GET, |
508 | sizeof(struct scmi_msg_sensor_axis_description_get), |
509 | &apriv); |
510 | if (IS_ERR(ptr: iter)) |
511 | return PTR_ERR(ptr: iter); |
512 | |
513 | /* |
514 | * Do not cause whole protocol initialization failure when failing to |
515 | * get extended names for axes. |
516 | */ |
517 | ret = ph->hops->iter_response_run(iter); |
518 | if (ret) |
519 | dev_warn(ph->dev, |
520 | "Failed to get axes extended names for %s (ret:%d).\n" , |
521 | s->name, ret); |
522 | |
523 | return 0; |
524 | } |
525 | |
526 | static int scmi_sensor_axis_description(const struct scmi_protocol_handle *ph, |
527 | struct scmi_sensor_info *s, |
528 | u32 version) |
529 | { |
530 | int ret; |
531 | void *iter; |
532 | struct scmi_iterator_ops ops = { |
533 | .prepare_message = iter_axes_desc_prepare_message, |
534 | .update_state = iter_axes_desc_update_state, |
535 | .process_response = iter_axes_desc_process_response, |
536 | }; |
537 | struct scmi_apriv apriv = { |
538 | .any_axes_support_extended_names = false, |
539 | .s = s, |
540 | }; |
541 | |
542 | s->axis = devm_kcalloc(dev: ph->dev, n: s->num_axis, |
543 | size: sizeof(*s->axis), GFP_KERNEL); |
544 | if (!s->axis) |
545 | return -ENOMEM; |
546 | |
547 | iter = ph->hops->iter_response_init(ph, &ops, s->num_axis, |
548 | SENSOR_AXIS_DESCRIPTION_GET, |
549 | sizeof(struct scmi_msg_sensor_axis_description_get), |
550 | &apriv); |
551 | if (IS_ERR(ptr: iter)) |
552 | return PTR_ERR(ptr: iter); |
553 | |
554 | ret = ph->hops->iter_response_run(iter); |
555 | if (ret) |
556 | return ret; |
557 | |
558 | if (PROTOCOL_REV_MAJOR(version) >= 0x3 && |
559 | apriv.any_axes_support_extended_names) |
560 | ret = scmi_sensor_axis_extended_names_get(ph, s); |
561 | |
562 | return ret; |
563 | } |
564 | |
565 | static void iter_sens_descr_prepare_message(void *message, |
566 | unsigned int desc_index, |
567 | const void *priv) |
568 | { |
569 | struct scmi_msg_sensor_description *msg = message; |
570 | |
571 | msg->desc_index = cpu_to_le32(desc_index); |
572 | } |
573 | |
574 | static int iter_sens_descr_update_state(struct scmi_iterator_state *st, |
575 | const void *response, void *priv) |
576 | { |
577 | const struct scmi_msg_resp_sensor_description *r = response; |
578 | |
579 | st->num_returned = le16_to_cpu(r->num_returned); |
580 | st->num_remaining = le16_to_cpu(r->num_remaining); |
581 | st->priv = (void *)&r->desc[0]; |
582 | |
583 | return 0; |
584 | } |
585 | |
586 | static int |
587 | iter_sens_descr_process_response(const struct scmi_protocol_handle *ph, |
588 | const void *response, |
589 | struct scmi_iterator_state *st, void *priv) |
590 | |
591 | { |
592 | int ret = 0; |
593 | u32 attrh, attrl; |
594 | size_t dsize = SCMI_MSG_RESP_SENS_DESCR_BASE_SZ; |
595 | struct scmi_sensor_info *s; |
596 | struct sensors_info *si = priv; |
597 | const struct scmi_sensor_descriptor *sdesc = st->priv; |
598 | |
599 | s = &si->sensors[st->desc_index + st->loop_idx]; |
600 | s->id = le32_to_cpu(sdesc->id); |
601 | |
602 | attrl = le32_to_cpu(sdesc->attributes_low); |
603 | /* common bitfields parsing */ |
604 | s->async = SUPPORTS_ASYNC_READ(attrl); |
605 | s->num_trip_points = NUM_TRIP_POINTS(attrl); |
606 | /** |
607 | * only SCMIv3.0 specific bitfield below. |
608 | * Such bitfields are assumed to be zeroed on non |
609 | * relevant fw versions...assuming fw not buggy ! |
610 | */ |
611 | if (si->notify_continuos_update_cmd) |
612 | s->update = SUPPORTS_UPDATE_NOTIFY(attrl); |
613 | s->timestamped = SUPPORTS_TIMESTAMP(attrl); |
614 | if (s->timestamped) |
615 | s->tstamp_scale = S32_EXT(SENSOR_TSTAMP_EXP(attrl)); |
616 | s->extended_scalar_attrs = SUPPORTS_EXTEND_ATTRS(attrl); |
617 | |
618 | attrh = le32_to_cpu(sdesc->attributes_high); |
619 | /* common bitfields parsing */ |
620 | s->scale = S32_EXT(SENSOR_SCALE(attrh)); |
621 | s->type = SENSOR_TYPE(attrh); |
622 | /* Use pre-allocated pool wherever possible */ |
623 | s->intervals.desc = s->intervals.prealloc_pool; |
624 | if (si->version == SCMIv2_SENSOR_PROTOCOL) { |
625 | s->intervals.segmented = false; |
626 | s->intervals.count = 1; |
627 | /* |
628 | * Convert SCMIv2.0 update interval format to |
629 | * SCMIv3.0 to be used as the common exposed |
630 | * descriptor, accessible via common macros. |
631 | */ |
632 | s->intervals.desc[0] = (SENSOR_UPDATE_BASE(attrh) << 5) | |
633 | SENSOR_UPDATE_SCALE(attrh); |
634 | } else { |
635 | /* |
636 | * From SCMIv3.0 update intervals are retrieved |
637 | * via a dedicated (optional) command. |
638 | * Since the command is optional, on error carry |
639 | * on without any update interval. |
640 | */ |
641 | if (scmi_sensor_update_intervals(ph, s)) |
642 | dev_dbg(ph->dev, |
643 | "Update Intervals not available for sensor ID:%d\n" , |
644 | s->id); |
645 | } |
646 | /** |
647 | * only > SCMIv2.0 specific bitfield below. |
648 | * Such bitfields are assumed to be zeroed on non |
649 | * relevant fw versions...assuming fw not buggy ! |
650 | */ |
651 | s->num_axis = min_t(unsigned int, |
652 | SUPPORTS_AXIS(attrh) ? |
653 | SENSOR_AXIS_NUMBER(attrh) : 0, |
654 | SCMI_MAX_NUM_SENSOR_AXIS); |
655 | strscpy(s->name, sdesc->name, SCMI_SHORT_NAME_MAX_SIZE); |
656 | |
657 | /* |
658 | * If supported overwrite short name with the extended |
659 | * one; on error just carry on and use already provided |
660 | * short name. |
661 | */ |
662 | if (PROTOCOL_REV_MAJOR(si->version) >= 0x3 && |
663 | SUPPORTS_EXTENDED_NAMES(attrl)) |
664 | ph->hops->extended_name_get(ph, SENSOR_NAME_GET, s->id, |
665 | NULL, s->name, SCMI_MAX_STR_SIZE); |
666 | |
667 | if (s->extended_scalar_attrs) { |
668 | s->sensor_power = le32_to_cpu(sdesc->power); |
669 | dsize += sizeof(sdesc->power); |
670 | |
671 | /* Only for sensors reporting scalar values */ |
672 | if (s->num_axis == 0) { |
673 | unsigned int sres = le32_to_cpu(sdesc->resolution); |
674 | |
675 | s->resolution = SENSOR_RES(sres); |
676 | s->exponent = S32_EXT(SENSOR_RES_EXP(sres)); |
677 | dsize += sizeof(sdesc->resolution); |
678 | |
679 | scmi_parse_range_attrs(out: &s->scalar_attrs, |
680 | in: &sdesc->scalar_attrs); |
681 | dsize += sizeof(sdesc->scalar_attrs); |
682 | } |
683 | } |
684 | |
685 | if (s->num_axis > 0) |
686 | ret = scmi_sensor_axis_description(ph, s, version: si->version); |
687 | |
688 | st->priv = ((u8 *)sdesc + dsize); |
689 | |
690 | return ret; |
691 | } |
692 | |
693 | static int scmi_sensor_description_get(const struct scmi_protocol_handle *ph, |
694 | struct sensors_info *si) |
695 | { |
696 | void *iter; |
697 | struct scmi_iterator_ops ops = { |
698 | .prepare_message = iter_sens_descr_prepare_message, |
699 | .update_state = iter_sens_descr_update_state, |
700 | .process_response = iter_sens_descr_process_response, |
701 | }; |
702 | |
703 | iter = ph->hops->iter_response_init(ph, &ops, si->num_sensors, |
704 | SENSOR_DESCRIPTION_GET, |
705 | sizeof(__le32), si); |
706 | if (IS_ERR(ptr: iter)) |
707 | return PTR_ERR(ptr: iter); |
708 | |
709 | return ph->hops->iter_response_run(iter); |
710 | } |
711 | |
712 | static inline int |
713 | scmi_sensor_request_notify(const struct scmi_protocol_handle *ph, u32 sensor_id, |
714 | u8 message_id, bool enable) |
715 | { |
716 | int ret; |
717 | u32 evt_cntl = enable ? SENSOR_NOTIFY_ALL : 0; |
718 | struct scmi_xfer *t; |
719 | struct scmi_msg_sensor_request_notify *cfg; |
720 | |
721 | ret = ph->xops->xfer_get_init(ph, message_id, sizeof(*cfg), 0, &t); |
722 | if (ret) |
723 | return ret; |
724 | |
725 | cfg = t->tx.buf; |
726 | cfg->id = cpu_to_le32(sensor_id); |
727 | cfg->event_control = cpu_to_le32(evt_cntl); |
728 | |
729 | ret = ph->xops->do_xfer(ph, t); |
730 | |
731 | ph->xops->xfer_put(ph, t); |
732 | return ret; |
733 | } |
734 | |
735 | static int scmi_sensor_trip_point_notify(const struct scmi_protocol_handle *ph, |
736 | u32 sensor_id, bool enable) |
737 | { |
738 | return scmi_sensor_request_notify(ph, sensor_id, |
739 | message_id: SENSOR_TRIP_POINT_NOTIFY, |
740 | enable); |
741 | } |
742 | |
743 | static int |
744 | scmi_sensor_continuous_update_notify(const struct scmi_protocol_handle *ph, |
745 | u32 sensor_id, bool enable) |
746 | { |
747 | return scmi_sensor_request_notify(ph, sensor_id, |
748 | message_id: SENSOR_CONTINUOUS_UPDATE_NOTIFY, |
749 | enable); |
750 | } |
751 | |
752 | static int |
753 | scmi_sensor_trip_point_config(const struct scmi_protocol_handle *ph, |
754 | u32 sensor_id, u8 trip_id, u64 trip_value) |
755 | { |
756 | int ret; |
757 | u32 evt_cntl = SENSOR_TP_BOTH; |
758 | struct scmi_xfer *t; |
759 | struct scmi_msg_set_sensor_trip_point *trip; |
760 | |
761 | ret = ph->xops->xfer_get_init(ph, SENSOR_TRIP_POINT_CONFIG, |
762 | sizeof(*trip), 0, &t); |
763 | if (ret) |
764 | return ret; |
765 | |
766 | trip = t->tx.buf; |
767 | trip->id = cpu_to_le32(sensor_id); |
768 | trip->event_control = cpu_to_le32(evt_cntl | SENSOR_TP_ID(trip_id)); |
769 | trip->value_low = cpu_to_le32(trip_value & 0xffffffff); |
770 | trip->value_high = cpu_to_le32(trip_value >> 32); |
771 | |
772 | ret = ph->xops->do_xfer(ph, t); |
773 | |
774 | ph->xops->xfer_put(ph, t); |
775 | return ret; |
776 | } |
777 | |
778 | static int scmi_sensor_config_get(const struct scmi_protocol_handle *ph, |
779 | u32 sensor_id, u32 *sensor_config) |
780 | { |
781 | int ret; |
782 | struct scmi_xfer *t; |
783 | struct sensors_info *si = ph->get_priv(ph); |
784 | |
785 | if (sensor_id >= si->num_sensors) |
786 | return -EINVAL; |
787 | |
788 | ret = ph->xops->xfer_get_init(ph, SENSOR_CONFIG_GET, |
789 | sizeof(__le32), sizeof(__le32), &t); |
790 | if (ret) |
791 | return ret; |
792 | |
793 | put_unaligned_le32(val: sensor_id, p: t->tx.buf); |
794 | ret = ph->xops->do_xfer(ph, t); |
795 | if (!ret) { |
796 | struct scmi_sensor_info *s = si->sensors + sensor_id; |
797 | |
798 | *sensor_config = get_unaligned_le64(p: t->rx.buf); |
799 | s->sensor_config = *sensor_config; |
800 | } |
801 | |
802 | ph->xops->xfer_put(ph, t); |
803 | return ret; |
804 | } |
805 | |
806 | static int scmi_sensor_config_set(const struct scmi_protocol_handle *ph, |
807 | u32 sensor_id, u32 sensor_config) |
808 | { |
809 | int ret; |
810 | struct scmi_xfer *t; |
811 | struct scmi_msg_sensor_config_set *msg; |
812 | struct sensors_info *si = ph->get_priv(ph); |
813 | |
814 | if (sensor_id >= si->num_sensors) |
815 | return -EINVAL; |
816 | |
817 | ret = ph->xops->xfer_get_init(ph, SENSOR_CONFIG_SET, |
818 | sizeof(*msg), 0, &t); |
819 | if (ret) |
820 | return ret; |
821 | |
822 | msg = t->tx.buf; |
823 | msg->id = cpu_to_le32(sensor_id); |
824 | msg->sensor_config = cpu_to_le32(sensor_config); |
825 | |
826 | ret = ph->xops->do_xfer(ph, t); |
827 | if (!ret) { |
828 | struct scmi_sensor_info *s = si->sensors + sensor_id; |
829 | |
830 | s->sensor_config = sensor_config; |
831 | } |
832 | |
833 | ph->xops->xfer_put(ph, t); |
834 | return ret; |
835 | } |
836 | |
837 | /** |
838 | * scmi_sensor_reading_get - Read scalar sensor value |
839 | * @ph: Protocol handle |
840 | * @sensor_id: Sensor ID |
841 | * @value: The 64bit value sensor reading |
842 | * |
843 | * This function returns a single 64 bit reading value representing the sensor |
844 | * value; if the platform SCMI Protocol implementation and the sensor support |
845 | * multiple axis and timestamped-reads, this just returns the first axis while |
846 | * dropping the timestamp value. |
847 | * Use instead the @scmi_sensor_reading_get_timestamped to retrieve the array of |
848 | * timestamped multi-axis values. |
849 | * |
850 | * Return: 0 on Success |
851 | */ |
852 | static int scmi_sensor_reading_get(const struct scmi_protocol_handle *ph, |
853 | u32 sensor_id, u64 *value) |
854 | { |
855 | int ret; |
856 | struct scmi_xfer *t; |
857 | struct scmi_msg_sensor_reading_get *sensor; |
858 | struct scmi_sensor_info *s; |
859 | struct sensors_info *si = ph->get_priv(ph); |
860 | |
861 | if (sensor_id >= si->num_sensors) |
862 | return -EINVAL; |
863 | |
864 | ret = ph->xops->xfer_get_init(ph, SENSOR_READING_GET, |
865 | sizeof(*sensor), 0, &t); |
866 | if (ret) |
867 | return ret; |
868 | |
869 | sensor = t->tx.buf; |
870 | sensor->id = cpu_to_le32(sensor_id); |
871 | s = si->sensors + sensor_id; |
872 | if (s->async) { |
873 | sensor->flags = cpu_to_le32(SENSOR_READ_ASYNC); |
874 | ret = ph->xops->do_xfer_with_response(ph, t); |
875 | if (!ret) { |
876 | struct scmi_resp_sensor_reading_complete *resp; |
877 | |
878 | resp = t->rx.buf; |
879 | if (le32_to_cpu(resp->id) == sensor_id) |
880 | *value = |
881 | get_unaligned_le64(p: &resp->readings_low); |
882 | else |
883 | ret = -EPROTO; |
884 | } |
885 | } else { |
886 | sensor->flags = cpu_to_le32(0); |
887 | ret = ph->xops->do_xfer(ph, t); |
888 | if (!ret) |
889 | *value = get_unaligned_le64(p: t->rx.buf); |
890 | } |
891 | |
892 | ph->xops->xfer_put(ph, t); |
893 | return ret; |
894 | } |
895 | |
896 | static inline void |
897 | scmi_parse_sensor_readings(struct scmi_sensor_reading *out, |
898 | const struct scmi_sensor_reading_resp *in) |
899 | { |
900 | out->value = get_unaligned_le64(p: (void *)&in->sensor_value_low); |
901 | out->timestamp = get_unaligned_le64(p: (void *)&in->timestamp_low); |
902 | } |
903 | |
904 | /** |
905 | * scmi_sensor_reading_get_timestamped - Read multiple-axis timestamped values |
906 | * @ph: Protocol handle |
907 | * @sensor_id: Sensor ID |
908 | * @count: The length of the provided @readings array |
909 | * @readings: An array of elements each representing a timestamped per-axis |
910 | * reading of type @struct scmi_sensor_reading. |
911 | * Returned readings are ordered as the @axis descriptors array |
912 | * included in @struct scmi_sensor_info and the max number of |
913 | * returned elements is min(@count, @num_axis); ideally the provided |
914 | * array should be of length @count equal to @num_axis. |
915 | * |
916 | * Return: 0 on Success |
917 | */ |
918 | static int |
919 | scmi_sensor_reading_get_timestamped(const struct scmi_protocol_handle *ph, |
920 | u32 sensor_id, u8 count, |
921 | struct scmi_sensor_reading *readings) |
922 | { |
923 | int ret; |
924 | struct scmi_xfer *t; |
925 | struct scmi_msg_sensor_reading_get *sensor; |
926 | struct scmi_sensor_info *s; |
927 | struct sensors_info *si = ph->get_priv(ph); |
928 | |
929 | if (sensor_id >= si->num_sensors) |
930 | return -EINVAL; |
931 | |
932 | s = si->sensors + sensor_id; |
933 | if (!count || !readings || |
934 | (!s->num_axis && count > 1) || (s->num_axis && count > s->num_axis)) |
935 | return -EINVAL; |
936 | |
937 | ret = ph->xops->xfer_get_init(ph, SENSOR_READING_GET, |
938 | sizeof(*sensor), 0, &t); |
939 | if (ret) |
940 | return ret; |
941 | |
942 | sensor = t->tx.buf; |
943 | sensor->id = cpu_to_le32(sensor_id); |
944 | if (s->async) { |
945 | sensor->flags = cpu_to_le32(SENSOR_READ_ASYNC); |
946 | ret = ph->xops->do_xfer_with_response(ph, t); |
947 | if (!ret) { |
948 | int i; |
949 | struct scmi_resp_sensor_reading_complete_v3 *resp; |
950 | |
951 | resp = t->rx.buf; |
952 | /* Retrieve only the number of requested axis anyway */ |
953 | if (le32_to_cpu(resp->id) == sensor_id) |
954 | for (i = 0; i < count; i++) |
955 | scmi_parse_sensor_readings(out: &readings[i], |
956 | in: &resp->readings[i]); |
957 | else |
958 | ret = -EPROTO; |
959 | } |
960 | } else { |
961 | sensor->flags = cpu_to_le32(0); |
962 | ret = ph->xops->do_xfer(ph, t); |
963 | if (!ret) { |
964 | int i; |
965 | struct scmi_sensor_reading_resp *resp_readings; |
966 | |
967 | resp_readings = t->rx.buf; |
968 | for (i = 0; i < count; i++) |
969 | scmi_parse_sensor_readings(out: &readings[i], |
970 | in: &resp_readings[i]); |
971 | } |
972 | } |
973 | |
974 | ph->xops->xfer_put(ph, t); |
975 | return ret; |
976 | } |
977 | |
978 | static const struct scmi_sensor_info * |
979 | scmi_sensor_info_get(const struct scmi_protocol_handle *ph, u32 sensor_id) |
980 | { |
981 | struct sensors_info *si = ph->get_priv(ph); |
982 | |
983 | if (sensor_id >= si->num_sensors) |
984 | return NULL; |
985 | |
986 | return si->sensors + sensor_id; |
987 | } |
988 | |
989 | static int scmi_sensor_count_get(const struct scmi_protocol_handle *ph) |
990 | { |
991 | struct sensors_info *si = ph->get_priv(ph); |
992 | |
993 | return si->num_sensors; |
994 | } |
995 | |
996 | static const struct scmi_sensor_proto_ops sensor_proto_ops = { |
997 | .count_get = scmi_sensor_count_get, |
998 | .info_get = scmi_sensor_info_get, |
999 | .trip_point_config = scmi_sensor_trip_point_config, |
1000 | .reading_get = scmi_sensor_reading_get, |
1001 | .reading_get_timestamped = scmi_sensor_reading_get_timestamped, |
1002 | .config_get = scmi_sensor_config_get, |
1003 | .config_set = scmi_sensor_config_set, |
1004 | }; |
1005 | |
1006 | static bool scmi_sensor_notify_supported(const struct scmi_protocol_handle *ph, |
1007 | u8 evt_id, u32 src_id) |
1008 | { |
1009 | bool supported = false; |
1010 | const struct scmi_sensor_info *s; |
1011 | struct sensors_info *sinfo = ph->get_priv(ph); |
1012 | |
1013 | s = scmi_sensor_info_get(ph, sensor_id: src_id); |
1014 | if (!s) |
1015 | return false; |
1016 | |
1017 | if (evt_id == SCMI_EVENT_SENSOR_TRIP_POINT_EVENT) |
1018 | supported = sinfo->notify_trip_point_cmd; |
1019 | else if (evt_id == SCMI_EVENT_SENSOR_UPDATE) |
1020 | supported = s->update; |
1021 | |
1022 | return supported; |
1023 | } |
1024 | |
1025 | static int scmi_sensor_set_notify_enabled(const struct scmi_protocol_handle *ph, |
1026 | u8 evt_id, u32 src_id, bool enable) |
1027 | { |
1028 | int ret; |
1029 | |
1030 | switch (evt_id) { |
1031 | case SCMI_EVENT_SENSOR_TRIP_POINT_EVENT: |
1032 | ret = scmi_sensor_trip_point_notify(ph, sensor_id: src_id, enable); |
1033 | break; |
1034 | case SCMI_EVENT_SENSOR_UPDATE: |
1035 | ret = scmi_sensor_continuous_update_notify(ph, sensor_id: src_id, enable); |
1036 | break; |
1037 | default: |
1038 | ret = -EINVAL; |
1039 | break; |
1040 | } |
1041 | |
1042 | if (ret) |
1043 | pr_debug("FAIL_ENABLED - evt[%X] dom[%d] - ret:%d\n" , |
1044 | evt_id, src_id, ret); |
1045 | |
1046 | return ret; |
1047 | } |
1048 | |
1049 | static void * |
1050 | scmi_sensor_fill_custom_report(const struct scmi_protocol_handle *ph, |
1051 | u8 evt_id, ktime_t timestamp, |
1052 | const void *payld, size_t payld_sz, |
1053 | void *report, u32 *src_id) |
1054 | { |
1055 | void *rep = NULL; |
1056 | |
1057 | switch (evt_id) { |
1058 | case SCMI_EVENT_SENSOR_TRIP_POINT_EVENT: |
1059 | { |
1060 | const struct scmi_sensor_trip_notify_payld *p = payld; |
1061 | struct scmi_sensor_trip_point_report *r = report; |
1062 | |
1063 | if (sizeof(*p) != payld_sz) |
1064 | break; |
1065 | |
1066 | r->timestamp = timestamp; |
1067 | r->agent_id = le32_to_cpu(p->agent_id); |
1068 | r->sensor_id = le32_to_cpu(p->sensor_id); |
1069 | r->trip_point_desc = le32_to_cpu(p->trip_point_desc); |
1070 | *src_id = r->sensor_id; |
1071 | rep = r; |
1072 | break; |
1073 | } |
1074 | case SCMI_EVENT_SENSOR_UPDATE: |
1075 | { |
1076 | int i; |
1077 | struct scmi_sensor_info *s; |
1078 | const struct scmi_sensor_update_notify_payld *p = payld; |
1079 | struct scmi_sensor_update_report *r = report; |
1080 | struct sensors_info *sinfo = ph->get_priv(ph); |
1081 | |
1082 | /* payld_sz is variable for this event */ |
1083 | r->sensor_id = le32_to_cpu(p->sensor_id); |
1084 | if (r->sensor_id >= sinfo->num_sensors) |
1085 | break; |
1086 | r->timestamp = timestamp; |
1087 | r->agent_id = le32_to_cpu(p->agent_id); |
1088 | s = &sinfo->sensors[r->sensor_id]; |
1089 | /* |
1090 | * The generated report r (@struct scmi_sensor_update_report) |
1091 | * was pre-allocated to contain up to SCMI_MAX_NUM_SENSOR_AXIS |
1092 | * readings: here it is filled with the effective @num_axis |
1093 | * readings defined for this sensor or 1 for scalar sensors. |
1094 | */ |
1095 | r->readings_count = s->num_axis ?: 1; |
1096 | for (i = 0; i < r->readings_count; i++) |
1097 | scmi_parse_sensor_readings(out: &r->readings[i], |
1098 | in: &p->readings[i]); |
1099 | *src_id = r->sensor_id; |
1100 | rep = r; |
1101 | break; |
1102 | } |
1103 | default: |
1104 | break; |
1105 | } |
1106 | |
1107 | return rep; |
1108 | } |
1109 | |
1110 | static int scmi_sensor_get_num_sources(const struct scmi_protocol_handle *ph) |
1111 | { |
1112 | struct sensors_info *si = ph->get_priv(ph); |
1113 | |
1114 | return si->num_sensors; |
1115 | } |
1116 | |
1117 | static const struct scmi_event sensor_events[] = { |
1118 | { |
1119 | .id = SCMI_EVENT_SENSOR_TRIP_POINT_EVENT, |
1120 | .max_payld_sz = sizeof(struct scmi_sensor_trip_notify_payld), |
1121 | .max_report_sz = sizeof(struct scmi_sensor_trip_point_report), |
1122 | }, |
1123 | { |
1124 | .id = SCMI_EVENT_SENSOR_UPDATE, |
1125 | .max_payld_sz = |
1126 | sizeof(struct scmi_sensor_update_notify_payld) + |
1127 | SCMI_MAX_NUM_SENSOR_AXIS * |
1128 | sizeof(struct scmi_sensor_reading_resp), |
1129 | .max_report_sz = sizeof(struct scmi_sensor_update_report) + |
1130 | SCMI_MAX_NUM_SENSOR_AXIS * |
1131 | sizeof(struct scmi_sensor_reading), |
1132 | }, |
1133 | }; |
1134 | |
1135 | static const struct scmi_event_ops sensor_event_ops = { |
1136 | .is_notify_supported = scmi_sensor_notify_supported, |
1137 | .get_num_sources = scmi_sensor_get_num_sources, |
1138 | .set_notify_enabled = scmi_sensor_set_notify_enabled, |
1139 | .fill_custom_report = scmi_sensor_fill_custom_report, |
1140 | }; |
1141 | |
1142 | static const struct scmi_protocol_events sensor_protocol_events = { |
1143 | .queue_sz = SCMI_PROTO_QUEUE_SZ, |
1144 | .ops = &sensor_event_ops, |
1145 | .evts = sensor_events, |
1146 | .num_events = ARRAY_SIZE(sensor_events), |
1147 | }; |
1148 | |
1149 | static int scmi_sensors_protocol_init(const struct scmi_protocol_handle *ph) |
1150 | { |
1151 | u32 version; |
1152 | int ret; |
1153 | struct sensors_info *sinfo; |
1154 | |
1155 | ret = ph->xops->version_get(ph, &version); |
1156 | if (ret) |
1157 | return ret; |
1158 | |
1159 | dev_dbg(ph->dev, "Sensor Version %d.%d\n" , |
1160 | PROTOCOL_REV_MAJOR(version), PROTOCOL_REV_MINOR(version)); |
1161 | |
1162 | sinfo = devm_kzalloc(dev: ph->dev, size: sizeof(*sinfo), GFP_KERNEL); |
1163 | if (!sinfo) |
1164 | return -ENOMEM; |
1165 | sinfo->version = version; |
1166 | |
1167 | ret = scmi_sensor_attributes_get(ph, si: sinfo); |
1168 | if (ret) |
1169 | return ret; |
1170 | sinfo->sensors = devm_kcalloc(dev: ph->dev, n: sinfo->num_sensors, |
1171 | size: sizeof(*sinfo->sensors), GFP_KERNEL); |
1172 | if (!sinfo->sensors) |
1173 | return -ENOMEM; |
1174 | |
1175 | ret = scmi_sensor_description_get(ph, si: sinfo); |
1176 | if (ret) |
1177 | return ret; |
1178 | |
1179 | return ph->set_priv(ph, sinfo, version); |
1180 | } |
1181 | |
1182 | static const struct scmi_protocol scmi_sensors = { |
1183 | .id = SCMI_PROTOCOL_SENSOR, |
1184 | .owner = THIS_MODULE, |
1185 | .instance_init = &scmi_sensors_protocol_init, |
1186 | .ops = &sensor_proto_ops, |
1187 | .events = &sensor_protocol_events, |
1188 | .supported_version = SCMI_PROTOCOL_SUPPORTED_VERSION, |
1189 | }; |
1190 | |
1191 | DEFINE_SCMI_PROTOCOL_REGISTER_UNREGISTER(sensors, scmi_sensors) |
1192 | |