1 /*
2 * Copyright (c) 2023 Grinn
3 * SPDX-License-Identifier: Apache-2.0
4 */
5
6 #define DT_DRV_COMPAT adi_ad5592_adc
7
8 #include <zephyr/drivers/adc.h>
9 #include <zephyr/kernel.h>
10 #include <zephyr/sys/byteorder.h>
11
12 #include <zephyr/drivers/mfd/ad5592.h>
13
14 #define ADC_CONTEXT_USES_KERNEL_TIMER
15 #include "adc_context.h"
16
17 #include <zephyr/logging/log.h>
18 LOG_MODULE_REGISTER(adc_ad5592, CONFIG_ADC_LOG_LEVEL);
19
20 #define AD5592_ADC_RESOLUTION 12U
21 #define AD5592_ADC_MAX_VAL 4096
22
23 struct adc_ad5592_config {
24 const struct device *mfd_dev;
25 };
26
27 struct adc_ad5592_data {
28 struct adc_context ctx;
29 const struct device *dev;
30 uint8_t adc_conf;
31 uint16_t *buffer;
32 uint16_t *repeat_buffer;
33 uint8_t channels;
34 struct k_thread thread;
35 struct k_sem sem;
36
37 K_KERNEL_STACK_MEMBER(stack, CONFIG_ADC_AD5592_ACQUISITION_THREAD_STACK_SIZE);
38 };
39
adc_ad5592_channel_setup(const struct device * dev,const struct adc_channel_cfg * channel_cfg)40 static int adc_ad5592_channel_setup(const struct device *dev,
41 const struct adc_channel_cfg *channel_cfg)
42 {
43 const struct adc_ad5592_config *config = dev->config;
44 struct adc_ad5592_data *data = dev->data;
45
46 if (channel_cfg->channel_id >= AD5592_PIN_MAX) {
47 LOG_ERR("invalid channel id %d", channel_cfg->channel_id);
48 return -EINVAL;
49 }
50
51 data->adc_conf |= BIT(channel_cfg->channel_id);
52
53 return mfd_ad5592_write_reg(config->mfd_dev, AD5592_REG_ADC_CONFIG, data->adc_conf);
54 }
55
adc_ad5592_validate_buffer_size(const struct device * dev,const struct adc_sequence * sequence)56 static int adc_ad5592_validate_buffer_size(const struct device *dev,
57 const struct adc_sequence *sequence)
58 {
59 uint8_t channels;
60 size_t needed;
61
62 channels = POPCOUNT(sequence->channels);
63 needed = channels * sizeof(uint16_t);
64
65 if (sequence->buffer_size < needed) {
66 return -ENOMEM;
67 }
68
69 return 0;
70 }
71
adc_ad5592_start_read(const struct device * dev,const struct adc_sequence * sequence)72 static int adc_ad5592_start_read(const struct device *dev, const struct adc_sequence *sequence)
73 {
74 struct adc_ad5592_data *data = dev->data;
75 int ret;
76
77 if (sequence->resolution != AD5592_ADC_RESOLUTION) {
78 LOG_ERR("invalid resolution %d", sequence->resolution);
79 return -EINVAL;
80 }
81
82 if (find_msb_set(sequence->channels) > AD5592_PIN_MAX) {
83 LOG_ERR("invalid channels in mask: 0x%08x", sequence->channels);
84 return -EINVAL;
85 }
86
87 ret = adc_ad5592_validate_buffer_size(dev, sequence);
88 if (ret < 0) {
89 LOG_ERR("insufficient buffer size");
90 return ret;
91 }
92
93 data->buffer = sequence->buffer;
94 adc_context_start_read(&data->ctx, sequence);
95
96 return adc_context_wait_for_completion(&data->ctx);
97 }
98
adc_ad5592_read_channel(const struct device * dev,uint8_t channel,uint16_t * result)99 static int adc_ad5592_read_channel(const struct device *dev, uint8_t channel, uint16_t *result)
100 {
101 const struct adc_ad5592_config *config = dev->config;
102 uint16_t val;
103 int ret;
104
105 ret = mfd_ad5592_write_reg(config->mfd_dev, AD5592_REG_SEQ_ADC, BIT(channel));
106 if (ret < 0) {
107 return ret;
108 }
109
110 /*
111 * Invalid data:
112 * See Figure 46. Single-Channel ADC Conversion Sequence.
113 * The first conversion result always returns invalid data.
114 */
115 (void) mfd_ad5592_read_raw(config->mfd_dev, &val);
116
117 ret = mfd_ad5592_read_raw(config->mfd_dev, &val);
118 if (ret < 0) {
119 return ret;
120 }
121
122 val = sys_be16_to_cpu(val);
123 if (channel >= 1) {
124 val -= channel * AD5592_ADC_MAX_VAL;
125 }
126
127 *result = val;
128
129 return 0;
130 }
131
adc_context_start_sampling(struct adc_context * ctx)132 static void adc_context_start_sampling(struct adc_context *ctx)
133 {
134 struct adc_ad5592_data *data = CONTAINER_OF(ctx, struct adc_ad5592_data, ctx);
135
136 data->channels = ctx->sequence.channels;
137 data->repeat_buffer = data->buffer;
138
139 k_sem_give(&data->sem);
140 }
141
adc_context_update_buffer_pointer(struct adc_context * ctx,bool repeat_sampling)142 static void adc_context_update_buffer_pointer(struct adc_context *ctx,
143 bool repeat_sampling)
144 {
145 struct adc_ad5592_data *data = CONTAINER_OF(ctx, struct adc_ad5592_data, ctx);
146
147 if (repeat_sampling) {
148 data->buffer = data->repeat_buffer;
149 }
150 }
151
adc_ad5592_acquisition_thread(struct adc_ad5592_data * data)152 static void adc_ad5592_acquisition_thread(struct adc_ad5592_data *data)
153 {
154 uint16_t result;
155 uint8_t channel;
156 int ret;
157
158 while (true) {
159 k_sem_take(&data->sem, K_FOREVER);
160
161 while (data->channels != 0) {
162 channel = find_lsb_set(data->channels) - 1;
163
164 ret = adc_ad5592_read_channel(data->dev, channel, &result);
165 if (ret < 0) {
166 LOG_ERR("failed to read channel %d (ret %d)", channel, ret);
167 adc_context_complete(&data->ctx, ret);
168 break;
169 }
170
171 *data->buffer++ = result;
172 WRITE_BIT(data->channels, channel, 0);
173 }
174
175 adc_context_on_sampling_done(&data->ctx, data->dev);
176 }
177 }
178
adc_ad5592_read_async(const struct device * dev,const struct adc_sequence * sequence,struct k_poll_signal * async)179 static int adc_ad5592_read_async(const struct device *dev,
180 const struct adc_sequence *sequence,
181 struct k_poll_signal *async)
182 {
183 struct adc_ad5592_data *data = dev->data;
184 int ret;
185
186 adc_context_lock(&data->ctx, async ? true : false, async);
187 ret = adc_ad5592_start_read(dev, sequence);
188 adc_context_release(&data->ctx, ret);
189
190 return ret;
191 }
192
adc_ad5592_read(const struct device * dev,const struct adc_sequence * sequence)193 static int adc_ad5592_read(const struct device *dev,
194 const struct adc_sequence *sequence)
195 {
196 return adc_ad5592_read_async(dev, sequence, NULL);
197 }
198
adc_ad5592_init(const struct device * dev)199 static int adc_ad5592_init(const struct device *dev)
200 {
201 const struct adc_ad5592_config *config = dev->config;
202 struct adc_ad5592_data *data = dev->data;
203 k_tid_t tid;
204 int ret;
205
206 if (!device_is_ready(config->mfd_dev)) {
207 return -ENODEV;
208 }
209
210 ret = mfd_ad5592_write_reg(config->mfd_dev, AD5592_REG_PD_REF_CTRL, AD5592_EN_REF);
211 if (ret < 0) {
212 return ret;
213 }
214
215 data->dev = dev;
216
217 k_sem_init(&data->sem, 0, 1);
218 adc_context_init(&data->ctx);
219
220 tid = k_thread_create(&data->thread, data->stack,
221 K_KERNEL_STACK_SIZEOF(data->stack),
222 (k_thread_entry_t)adc_ad5592_acquisition_thread, data, NULL, NULL,
223 CONFIG_ADC_AD5592_ACQUISITION_THREAD_PRIO, 0, K_NO_WAIT);
224
225 ret = k_thread_name_set(tid, "adc_ad5592");
226 if (ret < 0) {
227 return ret;
228 }
229
230 adc_context_unlock_unconditionally(&data->ctx);
231
232 return 0;
233 }
234
235 static const struct adc_driver_api adc_ad5592_api = {
236 .channel_setup = adc_ad5592_channel_setup,
237 .read = adc_ad5592_read,
238 #ifdef CONFIG_ADC_ASYNC
239 .read_async = adc_ad5592_read_async,
240 #endif
241 };
242
243 #define ADC_AD5592_DEFINE(inst) \
244 static const struct adc_ad5592_config adc_ad5592_config##inst = { \
245 .mfd_dev = DEVICE_DT_GET(DT_INST_PARENT(inst)), \
246 }; \
247 \
248 static struct adc_ad5592_data adc_ad5592_data##inst; \
249 \
250 DEVICE_DT_INST_DEFINE(inst, adc_ad5592_init, NULL, \
251 &adc_ad5592_data##inst, &adc_ad5592_config##inst, \
252 POST_KERNEL, CONFIG_MFD_INIT_PRIORITY, \
253 &adc_ad5592_api);
254
255 DT_INST_FOREACH_STATUS_OKAY(ADC_AD5592_DEFINE)
256