1 /*
2 * Copyright (c) 2022 Intel Corporation
3 *
4 * SPDX-License-Identifier: Apache-2.0
5 */
6
7 #define DT_DRV_COMPAT vnd_sensor
8
9 #include <zephyr/kernel.h>
10 #include <zephyr/rtio/rtio.h>
11 #include <zephyr/logging/log.h>
12 #include <zephyr/sys/util.h>
13
14 LOG_MODULE_REGISTER(vnd_sensor, LOG_LEVEL_DBG);
15
16 struct vnd_sensor_config {
17 uint32_t sample_period;
18 size_t sample_size;
19 };
20
21 struct vnd_sensor_data {
22 struct rtio_iodev iodev;
23 struct mpsc io_q;
24 struct k_timer timer;
25 const struct device *dev;
26 uint32_t sample_number;
27 };
28
vnd_sensor_iodev_read(const struct device * dev,uint8_t * buf,uint32_t buf_len)29 static int vnd_sensor_iodev_read(const struct device *dev, uint8_t *buf,
30 uint32_t buf_len)
31 {
32 const struct vnd_sensor_config *config = dev->config;
33 struct vnd_sensor_data *data = dev->data;
34 uint32_t sample_number;
35 uint32_t key;
36
37 LOG_DBG("%s: buf_len = %d, buf = %p", dev->name, buf_len, buf);
38
39 key = irq_lock();
40 sample_number = data->sample_number++;
41 irq_unlock(key);
42
43 if (buf_len < config->sample_size) {
44 LOG_ERR("%s: Buffer is too small", dev->name);
45 return -ENOMEM;
46 }
47
48 for (int i = 0; i < MIN(config->sample_size, buf_len); i++) {
49 buf[i] = sample_number * config->sample_size + i;
50 }
51
52 return 0;
53 }
54
vnd_sensor_iodev_execute(const struct device * dev,struct rtio_iodev_sqe * iodev_sqe)55 static void vnd_sensor_iodev_execute(const struct device *dev,
56 struct rtio_iodev_sqe *iodev_sqe)
57 {
58 const struct vnd_sensor_config *config = dev->config;
59 uint8_t *buf = NULL;
60 uint32_t buf_len;
61 int result;
62
63 if (iodev_sqe->sqe.op == RTIO_OP_RX) {
64 result = rtio_sqe_rx_buf(iodev_sqe, config->sample_size, config->sample_size, &buf,
65 &buf_len);
66 if (result != 0) {
67 LOG_ERR("Failed to get RX buffer");
68 } else {
69 result = vnd_sensor_iodev_read(dev, buf, buf_len);
70 }
71 } else {
72 LOG_ERR("%s: Invalid op", dev->name);
73 result = -EINVAL;
74 }
75
76 if (result < 0) {
77 rtio_iodev_sqe_err(iodev_sqe, result);
78 } else {
79 rtio_iodev_sqe_ok(iodev_sqe, result);
80 }
81 }
82
vnd_sensor_iodev_submit(struct rtio_iodev_sqe * iodev_sqe)83 static void vnd_sensor_iodev_submit(struct rtio_iodev_sqe *iodev_sqe)
84 {
85 struct vnd_sensor_data *data = (struct vnd_sensor_data *) iodev_sqe->sqe.iodev;
86
87 mpsc_push(&data->io_q, &iodev_sqe->q);
88 }
89
vnd_sensor_handle_int(const struct device * dev)90 static void vnd_sensor_handle_int(const struct device *dev)
91 {
92 struct vnd_sensor_data *data = dev->data;
93 struct mpsc_node *node = mpsc_pop(&data->io_q);
94
95 if (node != NULL) {
96 struct rtio_iodev_sqe *iodev_sqe = CONTAINER_OF(node, struct rtio_iodev_sqe, q);
97
98 vnd_sensor_iodev_execute(dev, iodev_sqe);
99 } else {
100 LOG_ERR("%s: Could not get a msg", dev->name);
101 }
102 }
103
vnd_sensor_timer_expiry(struct k_timer * timer)104 static void vnd_sensor_timer_expiry(struct k_timer *timer)
105 {
106 struct vnd_sensor_data *data =
107 CONTAINER_OF(timer, struct vnd_sensor_data, timer);
108
109 vnd_sensor_handle_int(data->dev);
110 }
111
vnd_sensor_init(const struct device * dev)112 static int vnd_sensor_init(const struct device *dev)
113 {
114 const struct vnd_sensor_config *config = dev->config;
115 struct vnd_sensor_data *data = dev->data;
116 uint32_t sample_period = config->sample_period;
117
118 data->dev = dev;
119
120 mpsc_init(&data->io_q);
121
122 k_timer_init(&data->timer, vnd_sensor_timer_expiry, NULL);
123
124 k_timer_start(&data->timer, K_MSEC(sample_period),
125 K_MSEC(sample_period));
126
127 return 0;
128 }
129
130 static const struct rtio_iodev_api vnd_sensor_iodev_api = {
131 .submit = vnd_sensor_iodev_submit,
132 };
133
134 #define VND_SENSOR_INIT(n) \
135 \
136 static const struct vnd_sensor_config vnd_sensor_config_##n = { \
137 .sample_period = DT_INST_PROP(n, sample_period), \
138 .sample_size = DT_INST_PROP(n, sample_size), \
139 }; \
140 \
141 static struct vnd_sensor_data vnd_sensor_data_##n = { \
142 .iodev = \
143 { \
144 .api = &vnd_sensor_iodev_api, \
145 }, \
146 }; \
147 \
148 DEVICE_DT_INST_DEFINE(n, vnd_sensor_init, NULL, &vnd_sensor_data_##n, \
149 &vnd_sensor_config_##n, POST_KERNEL, \
150 CONFIG_KERNEL_INIT_PRIORITY_DEVICE, NULL);
151
152 DT_INST_FOREACH_STATUS_OKAY(VND_SENSOR_INIT)
153