1 /* ipm_dummy.c - Fake IPM driver for testing upper-level drivers */
2
3 /*
4 * Copyright (c) 2015 Intel Corporation
5 *
6 * SPDX-License-Identifier: Apache-2.0
7 */
8
9 #include <zephyr/kernel.h>
10 #include <zephyr/drivers/ipm.h>
11 #include <errno.h>
12 #include <zephyr/device.h>
13 #include <zephyr/init.h>
14 #include <zephyr/sys/printk.h>
15 #include <zephyr/irq_offload.h>
16
17 #include "ipm_dummy.h"
18
19
20
21 /* Implemented as a software interrupt so that callbacks are executed
22 * in the expected context
23 */
ipm_dummy_isr(const void * data)24 static void ipm_dummy_isr(const void *data)
25 {
26 const struct device *d = (const struct device *)data;
27 struct ipm_dummy_driver_data *driver_data = d->data;
28
29 /* In a real driver the interrupt simply wouldn't fire, we fake
30 * that here
31 */
32 if (!driver_data->regs.enabled || !driver_data->regs.busy) {
33 return;
34 }
35
36 if (driver_data->cb) {
37 driver_data->cb(d,
38 driver_data->cb_context, driver_data->regs.id,
39 (volatile void *)&driver_data->regs.data);
40 }
41 driver_data->regs.busy = 0U;
42 }
43
44
45 /* IPM API functions for the dummy driver */
46
ipm_dummy_send(const struct device * d,int wait,uint32_t id,const void * data,int size)47 static int ipm_dummy_send(const struct device *d, int wait, uint32_t id,
48 const void *data, int size)
49 {
50 struct ipm_dummy_driver_data *driver_data;
51 volatile uint8_t *datareg;
52 const uint8_t *data8;
53 int i;
54
55 driver_data = d->data;
56 if (size > ipm_max_data_size_get(d)) {
57 return -EMSGSIZE;
58 }
59
60 if (driver_data->regs.busy) {
61 return -EBUSY;
62 }
63
64 data8 = (const uint8_t *)data;
65 datareg = (volatile uint8_t *)driver_data->regs.data;
66
67 for (i = 0; i < size; ++i) {
68 datareg[i] = data8[i];
69 }
70 driver_data->regs.id = id;
71 driver_data->regs.busy = 1U;
72
73 irq_offload(ipm_dummy_isr, (const void *)d);
74
75 if (wait) {
76 while (driver_data->regs.busy) {
77 /* busy-wait */
78 }
79 }
80 return 0;
81 }
82
ipm_dummy_register_callback(const struct device * d,ipm_callback_t cb,void * cb_context)83 static void ipm_dummy_register_callback(const struct device *d,
84 ipm_callback_t cb,
85 void *cb_context)
86 {
87 struct ipm_dummy_driver_data *driver_data;
88
89 driver_data = d->data;
90 driver_data->cb = cb;
91 driver_data->cb_context = cb_context;
92 }
93
ipm_dummy_set_enabled(const struct device * d,int enable)94 static int ipm_dummy_set_enabled(const struct device *d, int enable)
95 {
96 struct ipm_dummy_driver_data *driver_data = d->data;
97
98 driver_data->regs.enabled = enable;
99 if (enable) {
100 /* In case there are pending messages */
101 irq_offload(ipm_dummy_isr, (const void *)d);
102 }
103 return 0;
104 }
105
ipm_dummy_max_id_val_get(const struct device * d)106 static uint32_t ipm_dummy_max_id_val_get(const struct device *d)
107 {
108 return 0xFFFFFFFF;
109 }
110
ipm_dummy_max_data_size_get(const struct device * d)111 static int ipm_dummy_max_data_size_get(const struct device *d)
112 {
113 return DUMMY_IPM_DATA_WORDS * sizeof(uint32_t);
114 }
115
116 struct ipm_driver_api ipm_dummy_api = {
117 .send = ipm_dummy_send,
118 .register_callback = ipm_dummy_register_callback,
119 .max_data_size_get = ipm_dummy_max_data_size_get,
120 .max_id_val_get = ipm_dummy_max_id_val_get,
121 .set_enabled = ipm_dummy_set_enabled
122 };
123