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