1 /*
2  * Arm SCP/MCP Software
3  * Copyright (c) 2015-2024, Arm Limited and Contributors. All rights reserved.
4  *
5  * SPDX-License-Identifier: BSD-3-Clause
6  */
7 
8 #include "sensor.h"
9 
10 #ifdef BUILD_HAS_SCMI_SENSOR_EVENTS
11 #    include <mod_scmi_sensor.h>
12 #endif
13 #include <mod_sensor.h>
14 
15 #include <fwk_assert.h>
16 #include <fwk_core.h>
17 #include <fwk_event.h>
18 #include <fwk_id.h>
19 #include <fwk_mm.h>
20 #include <fwk_module.h>
21 #include <fwk_module_idx.h>
22 #include <fwk_status.h>
23 #include <fwk_string.h>
24 
25 #include <stdbool.h>
26 #include <stddef.h>
27 #include <stdint.h>
28 
29 static struct sensor_dev_ctx *ctx_table;
30 static struct mod_sensor_ctx sensor_mod_ctx;
31 
sensor_get_ctx(fwk_id_t id)32 struct sensor_dev_ctx *sensor_get_ctx(fwk_id_t id)
33 {
34     return ctx_table + fwk_id_get_element_idx(id);
35 }
36 
get_ctx_if_valid_call(fwk_id_t id,const void * data,struct sensor_dev_ctx ** ctx)37 static int get_ctx_if_valid_call(
38     fwk_id_t id,
39     const void *data,
40     struct sensor_dev_ctx **ctx)
41 {
42     fwk_assert(ctx != NULL);
43 
44     if (!fwk_expect(data != NULL)) {
45         return FWK_E_PARAM;
46     }
47 
48     *ctx = ctx_table + fwk_id_get_element_idx(id);
49 
50     return FWK_SUCCESS;
51 }
52 
sensor_data_copy(struct mod_sensor_data * dest,const struct mod_sensor_data * origin)53 static inline void sensor_data_copy(
54     struct mod_sensor_data *dest,
55     const struct mod_sensor_data *origin)
56 {
57 #ifdef BUILD_HAS_SENSOR_MULTI_AXIS
58     mod_sensor_value_t *value = dest->axis_value;
59 #endif
60 
61     fwk_str_memcpy(dest, origin, sizeof(struct mod_sensor_data));
62 
63 #ifdef BUILD_HAS_SENSOR_MULTI_AXIS
64     if (dest->axis_count > 1) {
65         dest->axis_value = value;
66         fwk_str_memcpy(
67             dest->axis_value,
68             origin->axis_value,
69             sizeof(uint64_t) * dest->axis_count);
70     }
71 #endif
72 }
73 
74 #ifdef BUILD_HAS_SCMI_SENSOR_EVENTS
trip_point_evaluate(struct sensor_trip_point_ctx * ctx,uint64_t value)75 static bool trip_point_evaluate(
76     struct sensor_trip_point_ctx *ctx,
77     uint64_t value)
78 {
79     uint64_t threshold;
80     bool new_above_threshold, trigger = false;
81 
82     threshold = ctx->params.tp_value;
83     new_above_threshold = value > threshold;
84 
85     switch (ctx->params.mode) {
86     case MOD_SENSOR_TRIP_POINT_MODE_POSITIVE:
87         if (!ctx->above_threshold && value > threshold)
88             trigger = true;
89         break;
90 
91     case MOD_SENSOR_TRIP_POINT_MODE_NEGATIVE:
92         if (ctx->above_threshold && (value <= threshold))
93             trigger = true;
94         break;
95 
96     case MOD_SENSOR_TRIP_POINT_MODE_TRANSITION:
97         if ((!ctx->above_threshold && value > threshold) ||
98             (ctx->above_threshold && value <= threshold))
99             trigger = true;
100         break;
101 
102     default:
103         break;
104     }
105 
106     ctx->above_threshold = new_above_threshold;
107     return trigger;
108 }
109 #endif
110 
111 #ifdef BUILD_HAS_SCMI_SENSOR_EVENTS
trip_point_process(fwk_id_t id,struct mod_sensor_data * data)112 static void trip_point_process(fwk_id_t id, struct mod_sensor_data *data)
113 {
114     struct sensor_dev_ctx *ctx;
115     unsigned int i;
116 
117     fwk_check(!fwk_id_is_equal(id, FWK_ID_NONE));
118     ctx = ctx_table + fwk_id_get_element_idx(id);
119 
120     if (!ctx->trip_point_ctx->enabled) {
121         return;
122     }
123 
124     for (i = 0; i < ctx->config->trip_point.count; i++) {
125         if (trip_point_evaluate(&(ctx->trip_point_ctx[i]), data->value)) {
126             /* Handle trip point event*/
127             if (sensor_mod_ctx.sensor_trip_point_api != NULL)
128                 sensor_mod_ctx.sensor_trip_point_api->notify_sensor_trip_point(
129                     id, ctx->trip_point_ctx->above_threshold, i);
130         }
131     }
132 }
133 #endif
134 
is_sensor_enabled(fwk_id_t id,bool * sensor_is_enabled)135 static int is_sensor_enabled(fwk_id_t id, bool *sensor_is_enabled)
136 {
137     int status;
138 
139     if (fwk_id_is_type(id, FWK_ID_TYPE_ELEMENT)) {
140         struct mod_sensor_complete_info complete_info;
141         struct sensor_dev_ctx *ctx;
142 
143         ctx = &ctx_table[fwk_id_get_element_idx(id)];
144 
145         status = ctx->driver_api->get_info(
146             ctx->config->driver_id, &(complete_info.hal_info));
147 
148         if (status != FWK_SUCCESS) {
149             return status;
150         }
151 
152         *sensor_is_enabled = !complete_info.hal_info.disabled;
153 
154         return FWK_SUCCESS;
155     }
156 
157     return FWK_E_PARAM;
158 }
159 
160 /*
161  * Module API
162  */
get_data(fwk_id_t id,struct mod_sensor_data * data)163 static int get_data(fwk_id_t id, struct mod_sensor_data *data)
164 {
165     int status;
166     bool sensor_enabled;
167     struct sensor_dev_ctx *ctx;
168     struct fwk_event req;
169     struct mod_sensor_event_params *event_params =
170         (struct mod_sensor_event_params *)req.params;
171 
172     status = get_ctx_if_valid_call(id, data, &ctx);
173     if (status != FWK_SUCCESS) {
174         return status;
175     }
176 
177     status = is_sensor_enabled(id, &sensor_enabled);
178     if (status != FWK_SUCCESS) {
179         return status;
180     }
181 
182     if (!sensor_enabled) {
183         return FWK_E_SUPPORT;
184     }
185 
186     if (ctx->concurrency_readings.dequeuing) {
187         /* Prevent new reading request while dequeuing pending readings
188          * cached data is returned
189          */
190         sensor_data_copy(data, &ctx->last_read);
191         return ctx->last_read.status;
192     }
193 
194     if (ctx->concurrency_readings.pending_requests == 0) {
195         status = ctx->driver_api->get_value(
196             ctx->config->driver_id, &ctx->last_read.value);
197         ctx->last_read.status = status;
198         if (status == FWK_SUCCESS) {
199 #ifdef BUILD_HAS_SCMI_SENSOR_EVENTS
200             trip_point_process(id, &ctx->last_read);
201 #endif
202 #ifdef BUILD_HAS_SENSOR_TIMESTAMP
203             ctx->last_read.timestamp = sensor_get_timestamp(id);
204 #endif
205             sensor_data_copy(data, &ctx->last_read);
206 
207             return status;
208         } else if (status != FWK_PENDING) {
209             return status;
210         }
211     }
212 
213     if (ctx->concurrency_readings.pending_requests >=
214         SENSOR_MAX_PENDING_REQUESTS) {
215         return FWK_E_BUSY;
216     }
217 
218     req = (struct fwk_event){
219         .target_id = id,
220         .id = mod_sensor_event_id_read_request,
221         .response_requested = true,
222     };
223 
224     /* Save data address to copy return values in there */
225     event_params->sensor_data = data;
226 
227     status = fwk_put_event(&req);
228     if (status != FWK_SUCCESS) {
229         return status;
230     }
231 
232     ctx->concurrency_readings.pending_requests++;
233     /*
234      * We return FWK_PENDING here to indicate to the caller that the
235      * result of the request is pending and will arrive later through
236      * an event.
237      */
238     return FWK_PENDING;
239 }
240 
get_info(fwk_id_t id,struct mod_sensor_complete_info * info)241 static int get_info(fwk_id_t id, struct mod_sensor_complete_info *info)
242 {
243     int status;
244     struct sensor_dev_ctx *ctx;
245 
246     status = get_ctx_if_valid_call(id, info, &ctx);
247     if (status != FWK_SUCCESS) {
248         return status;
249     }
250 
251     status = ctx->driver_api->get_info(ctx->config->driver_id, &info->hal_info);
252     if (!fwk_expect(status == FWK_SUCCESS)) {
253         return FWK_E_DEVICE;
254     }
255     info->trip_point = ctx->config->trip_point;
256 
257 #ifdef BUILD_HAS_SENSOR_TIMESTAMP
258     status = sensor_get_timestamp_config(id, &info->timestamp);
259     if (status == FWK_E_SUPPORT) {
260         info->timestamp.timestamp_support = false;
261     } else {
262         return status;
263     }
264 #endif
265 #ifdef BUILD_HAS_SENSOR_MULTI_AXIS
266     if (ctx->axis_count > 1) {
267         info->multi_axis.support = true;
268         info->multi_axis.axis_count = ctx->axis_count;
269     }
270 #endif
271 
272     return FWK_SUCCESS;
273 }
274 
sensor_get_trip_point(fwk_id_t id,uint32_t trip_point_idx,struct mod_sensor_trip_point_params * params)275 static int sensor_get_trip_point(
276     fwk_id_t id,
277     uint32_t trip_point_idx,
278     struct mod_sensor_trip_point_params *params)
279 {
280     struct sensor_dev_ctx *ctx;
281 
282     fwk_check(params != NULL);
283 
284     ctx = ctx_table + fwk_id_get_element_idx(id);
285 
286     if (trip_point_idx >= ctx->config->trip_point.count) {
287         return FWK_E_PARAM;
288     }
289 
290     *params = ctx->trip_point_ctx[trip_point_idx].params;
291 
292     return FWK_SUCCESS;
293 }
294 
sensor_set_trip_point(fwk_id_t id,uint32_t trip_point_idx,const struct mod_sensor_trip_point_params * params)295 static int sensor_set_trip_point(
296     fwk_id_t id,
297     uint32_t trip_point_idx,
298     const struct mod_sensor_trip_point_params *params)
299 {
300     struct sensor_dev_ctx *ctx;
301 
302     if (params == NULL) {
303         return FWK_E_PARAM;
304     }
305 
306     ctx = ctx_table + fwk_id_get_element_idx(id);
307 
308     if (trip_point_idx >= ctx->config->trip_point.count) {
309         return FWK_E_PARAM;
310     }
311 
312     ctx->trip_point_ctx[trip_point_idx].params = *params;
313 
314     /* Clear the trip point flag */
315     ctx->trip_point_ctx[trip_point_idx].above_threshold = false;
316     return FWK_SUCCESS;
317 }
318 
sensor_enable(fwk_id_t id)319 static int sensor_enable(fwk_id_t id)
320 {
321     struct sensor_dev_ctx *ctx;
322 
323     ctx = sensor_get_ctx(id);
324 
325     if (ctx->driver_api->enable != NULL) {
326         return ctx->driver_api->enable(id);
327     }
328 
329     return FWK_E_SUPPORT;
330 }
331 
sensor_disable(fwk_id_t id)332 static int sensor_disable(fwk_id_t id)
333 {
334     struct sensor_dev_ctx *ctx;
335 
336     ctx = sensor_get_ctx(id);
337 
338     if (ctx->driver_api->disable != NULL) {
339         return ctx->driver_api->disable(id);
340     }
341 
342     return FWK_E_SUPPORT;
343 }
344 
sensor_set_update_interval(fwk_id_t id,unsigned int time_interval,int time_interval_multiplier)345 static int sensor_set_update_interval(
346     fwk_id_t id,
347     unsigned int time_interval,
348     int time_interval_multiplier)
349 {
350     struct sensor_dev_ctx *ctx;
351 
352     if (!fwk_id_is_type(id, FWK_ID_TYPE_ELEMENT)) {
353         return FWK_E_PARAM;
354     }
355 
356     ctx = &ctx_table[fwk_id_get_element_idx(id)];
357 
358     if (ctx->driver_api->set_update_interval == NULL) {
359         return FWK_E_SUPPORT;
360     }
361 
362     return ctx->driver_api->set_update_interval(
363         id, time_interval, time_interval_multiplier);
364 }
365 
sensor_get_update_interval(fwk_id_t id,unsigned int * time_interval,int * time_interval_multiplier)366 static int sensor_get_update_interval(
367     fwk_id_t id,
368     unsigned int *time_interval,
369     int *time_interval_multiplier)
370 {
371     int status;
372     struct sensor_dev_ctx *ctx;
373     struct mod_sensor_complete_info complete_info;
374 
375     if (!fwk_id_is_type(id, FWK_ID_TYPE_ELEMENT)) {
376         return FWK_E_PARAM;
377     }
378 
379     ctx = &ctx_table[fwk_id_get_element_idx(id)];
380 
381     status = ctx->driver_api->get_info(
382         ctx->config->driver_id, &(complete_info.hal_info));
383 
384     if (status != FWK_SUCCESS) {
385         return status;
386     }
387 
388     *time_interval = complete_info.hal_info.update_interval;
389     *time_interval_multiplier =
390         complete_info.hal_info.update_interval_multiplier;
391 
392     return FWK_SUCCESS;
393 }
394 
395 static struct mod_sensor_api sensor_api = {
396     .get_data = get_data,
397     .get_info = get_info,
398     .get_trip_point = sensor_get_trip_point,
399     .set_trip_point = sensor_set_trip_point,
400     .enable = sensor_enable,
401     .disable = sensor_disable,
402     .set_update_interval = sensor_set_update_interval,
403     .get_update_interval = sensor_get_update_interval,
404 #ifdef BUILD_HAS_SENSOR_TIMESTAMP
405     .set_timestamp_config = sensor_set_timestamp_config,
406     .get_timestamp_config = sensor_get_timestamp_config,
407 #endif
408 #ifdef BUILD_HAS_SENSOR_MULTI_AXIS
409     .get_axis_info = sensor_get_axis_info,
410 #endif
411 };
412 
413 /*
414  * Driver response API.
415  */
reading_complete(fwk_id_t dev_id,struct mod_sensor_driver_resp_params * response)416 static void reading_complete(fwk_id_t dev_id,
417                              struct mod_sensor_driver_resp_params *response)
418 {
419     int status = FWK_SUCCESS;
420     struct fwk_event event;
421     struct sensor_dev_ctx *ctx;
422 
423     if (!fwk_expect(fwk_id_get_module_idx(dev_id) == FWK_MODULE_IDX_SENSOR)) {
424         return;
425     }
426 
427     ctx = &ctx_table[fwk_id_get_element_idx(dev_id)];
428     event = (struct fwk_event) {
429         .id = mod_sensor_event_id_read_complete,
430         .source_id = ctx->config->driver_id,
431         .target_id = dev_id,
432     };
433 
434     if (response != NULL) {
435         ctx->last_read.status = response->status;
436 
437 #ifdef BUILD_HAS_SENSOR_TIMESTAMP
438         ctx->last_read.timestamp = sensor_get_timestamp(dev_id);
439 #endif
440 #ifdef BUILD_HAS_SENSOR_MULTI_AXIS
441         if (ctx->axis_count > 1) {
442             fwk_str_memcpy(
443                 ctx->last_read.axis_value,
444                 response->axis_value,
445                 sizeof(uint64_t) * ctx->axis_count);
446         } else {
447             ctx->last_read.value = response->value;
448         }
449 #else
450         ctx->last_read.value = response->value;
451 #endif
452 
453 #ifdef BUILD_HAS_SCMI_SENSOR_EVENTS
454         trip_point_process(dev_id, &ctx->last_read);
455 #endif
456     } else {
457         ctx->last_read.status = FWK_E_DEVICE;
458     }
459 
460     ctx->concurrency_readings.dequeuing = true;
461 
462     status = fwk_put_event(&event);
463     fwk_assert(status == FWK_SUCCESS);
464 }
465 
466 static struct mod_sensor_driver_response_api sensor_driver_response_api = {
467     .reading_complete = reading_complete,
468 };
469 
470 /*
471  * Framework handlers
472  */
sensor_init(fwk_id_t module_id,unsigned int element_count,const void * data)473 static int sensor_init(
474     fwk_id_t module_id,
475     unsigned int element_count,
476     const void *data)
477 {
478     struct mod_sensor_config *config;
479 
480     ctx_table = fwk_mm_calloc(element_count, sizeof(ctx_table[0]));
481     fwk_str_memset(&sensor_mod_ctx, 0, sizeof(sensor_mod_ctx));
482     config = (struct mod_sensor_config *)data;
483 
484     sensor_mod_ctx.config = config;
485     return FWK_SUCCESS;
486 }
487 
sensor_dev_init(fwk_id_t element_id,unsigned int unused,const void * data)488 static int sensor_dev_init(fwk_id_t element_id,
489                            unsigned int unused,
490                            const void *data)
491 {
492     struct sensor_dev_ctx *ctx;
493     struct mod_sensor_dev_config *config;
494 
495     ctx = ctx_table + fwk_id_get_element_idx(element_id);
496 
497     fwk_check(data != NULL);
498     config = (struct mod_sensor_dev_config*)data;
499 
500     ctx->config = config;
501 
502     if (config->trip_point.count > 0) {
503         ctx->trip_point_ctx = fwk_mm_calloc(
504             config->trip_point.count, sizeof(struct sensor_trip_point_ctx));
505         ctx->trip_point_ctx->enabled = true;
506     } else {
507         ctx->trip_point_ctx = NULL;
508     }
509 
510     /* Pre-init last read with an invalid status */
511     ctx->last_read.status = FWK_E_DEVICE;
512 
513 #ifndef BUILD_HAS_SENSOR_MULTI_AXIS
514     ctx->axis_count = 1;
515 #endif
516 #ifdef BUILD_HAS_SENSOR_TIMESTAMP
517     return sensor_timestamp_dev_init(element_id, ctx);
518 #else
519     return FWK_SUCCESS;
520 #endif
521 }
522 
sensor_bind(fwk_id_t id,unsigned int round)523 static int sensor_bind(fwk_id_t id, unsigned int round)
524 {
525     struct sensor_dev_ctx *ctx;
526     int status;
527     struct mod_sensor_driver_api *driver = NULL;
528 
529     if (round > 0) {
530         /*
531          * Only bind in first round of calls
532          */
533         return FWK_SUCCESS;
534     }
535     if (fwk_id_is_type(id, FWK_ID_TYPE_MODULE)) {
536         if (sensor_mod_ctx.config == NULL) {
537             return FWK_SUCCESS;
538         }
539 
540 #ifdef BUILD_HAS_NOTIFICATION
541         if (fwk_id_is_equal(
542                 sensor_mod_ctx.config->notification_id, FWK_ID_NONE)) {
543             return FWK_SUCCESS;
544         }
545 
546         return fwk_module_bind(
547             sensor_mod_ctx.config->notification_id,
548             sensor_mod_ctx.config->trip_point_api_id,
549             &sensor_mod_ctx.sensor_trip_point_api);
550 #else
551         return FWK_SUCCESS;
552 #endif
553     }
554     ctx = ctx_table + fwk_id_get_element_idx(id);
555     /* Bind to driver */
556     status = fwk_module_bind(ctx->config->driver_id,
557         ctx->config->driver_api_id,
558         &driver);
559     if (status != FWK_SUCCESS) {
560         return status;
561     }
562 
563     /* Validate driver API */
564     if ((driver == NULL) || (driver->get_value == NULL)) {
565         return FWK_E_DATA;
566     }
567 
568     ctx->driver_api = driver;
569 
570     return FWK_SUCCESS;
571 }
572 
573 #ifdef BUILD_HAS_SENSOR_MULTI_AXIS
sensor_start(fwk_id_t id)574 int sensor_start(fwk_id_t id)
575 {
576     int status;
577 
578     if (fwk_id_is_type(id, FWK_ID_TYPE_MODULE)) {
579         return FWK_SUCCESS;
580     }
581     status = sensor_axis_start(id);
582     if (status != FWK_SUCCESS) {
583         return status;
584     }
585 
586     return FWK_SUCCESS;
587 }
588 #endif
589 
sensor_process_bind_request(fwk_id_t source_id,fwk_id_t target_id,fwk_id_t api_id,const void ** api)590 static int sensor_process_bind_request(fwk_id_t source_id,
591                                        fwk_id_t target_id,
592                                        fwk_id_t api_id,
593                                        const void **api)
594 {
595     struct sensor_dev_ctx *ctx;
596     fwk_id_t driver_id;
597 
598     if (fwk_id_is_equal(api_id, mod_sensor_api_id_sensor)) {
599         *api = &sensor_api;
600 
601         return FWK_SUCCESS;
602     }
603 
604     if (fwk_id_is_equal(api_id, mod_sensor_api_id_driver_response)) {
605         if (!fwk_id_is_type(target_id, FWK_ID_TYPE_ELEMENT)) {
606             return FWK_E_PARAM;
607         }
608 
609         ctx = ctx_table + fwk_id_get_element_idx(target_id);
610         driver_id = ctx->config->driver_id;
611 
612         /* Allow element to sub-element binding */
613         if ((fwk_id_get_module_idx(driver_id) ==
614             fwk_id_get_module_idx(source_id)) &&
615             (fwk_id_get_element_idx(driver_id) ==
616             fwk_id_get_element_idx(source_id))) {
617 
618             *api = &sensor_driver_response_api;
619 
620             return FWK_SUCCESS;
621         } else {
622             return FWK_E_ACCESS;
623         }
624     }
625 
626     return FWK_E_PARAM;
627 }
628 
process_pending_requests(fwk_id_t dev_id,const struct mod_sensor_data * event_params)629 static int process_pending_requests(
630     fwk_id_t dev_id,
631     const struct mod_sensor_data *event_params)
632 {
633     int status;
634     bool list_is_empty;
635     struct fwk_event delayed_response;
636     struct mod_sensor_event_params *response_params =
637         (struct mod_sensor_event_params *)delayed_response.params;
638     struct sensor_dev_ctx *ctx;
639 
640     status = fwk_is_delayed_response_list_empty(dev_id, &list_is_empty);
641     if (status != FWK_SUCCESS) {
642         return status;
643     }
644 
645     ctx = &ctx_table[fwk_id_get_element_idx(dev_id)];
646 
647     for (; !list_is_empty && ctx->concurrency_readings.pending_requests > 0;
648          ctx->concurrency_readings.pending_requests--) {
649         status = fwk_get_first_delayed_response(dev_id, &delayed_response);
650         if (status != FWK_SUCCESS) {
651             return status;
652         }
653 
654         sensor_data_copy(response_params->sensor_data, &ctx->last_read);
655 
656         status = fwk_put_event(&delayed_response);
657         if (status != FWK_SUCCESS) {
658             return status;
659         }
660 
661         status = fwk_is_delayed_response_list_empty(dev_id, &list_is_empty);
662         if (status != FWK_SUCCESS) {
663             return status;
664         }
665     }
666 
667     ctx->concurrency_readings.pending_requests = 0;
668     ctx->concurrency_readings.dequeuing = false;
669 
670     return FWK_SUCCESS;
671 }
672 
sensor_process_event(const struct fwk_event * event,struct fwk_event * resp_event)673 static int sensor_process_event(const struct fwk_event *event,
674                                 struct fwk_event *resp_event)
675 {
676     int status;
677     struct sensor_dev_ctx *ctx;
678     struct fwk_event read_req_event;
679     struct mod_sensor_event_params *event_params =
680         (struct mod_sensor_event_params *)read_req_event.params;
681     enum mod_sensor_event_idx event_id_type;
682 
683     if (!fwk_module_is_valid_element_id(event->target_id)) {
684         return FWK_E_PARAM;
685     }
686 
687     ctx = ctx_table + fwk_id_get_element_idx(event->target_id);
688 
689     event_id_type = (enum mod_sensor_event_idx)fwk_id_get_event_idx(event->id);
690 
691     switch (event_id_type) {
692     case SENSOR_EVENT_IDX_READ_REQUEST:
693         if (ctx->concurrency_readings.pending_requests == 1) {
694             /*
695              * We keep the cookie event of the request that triggers the
696              * reading.
697              */
698             ctx->cookie = event->cookie;
699         }
700         resp_event->is_delayed_response = true;
701 
702         return FWK_SUCCESS;
703 
704     case SENSOR_EVENT_IDX_READ_COMPLETE:
705         status = fwk_get_delayed_response(
706             event->target_id, ctx->cookie, &read_req_event);
707         if (status != FWK_SUCCESS) {
708             return status;
709         }
710 
711         sensor_data_copy(
712             (struct mod_sensor_data *)event_params->sensor_data,
713             &ctx->last_read);
714 
715         status = fwk_put_event(&read_req_event);
716         if (status != FWK_SUCCESS) {
717             return status;
718         }
719 
720         /*
721          * After a read complete event all pending requests are processed.
722          * We are processing pending events until it reaches a new reading
723          * or the event queue is empty.
724          */
725         return process_pending_requests(
726             event->target_id, (const struct mod_sensor_data *)event->params);
727 
728     default:
729         return FWK_E_PARAM;
730     }
731 }
732 
733 const struct fwk_module module_sensor = {
734     .api_count = (unsigned int)MOD_SENSOR_API_IDX_COUNT,
735     .event_count = (unsigned int)SENSOR_EVENT_IDX_COUNT,
736     .type = FWK_MODULE_TYPE_HAL,
737     .init = sensor_init,
738     .element_init = sensor_dev_init,
739     .bind = sensor_bind,
740 #ifdef BUILD_HAS_SENSOR_MULTI_AXIS
741     .start = sensor_start,
742 #endif
743     .process_bind_request = sensor_process_bind_request,
744     .process_event = sensor_process_event,
745 };
746