1 /*
2 * Copyright (c) 2021 Pavlo Hamov <pasha.gamov@gmail.com>
3 *
4 * SPDX-License-Identifier: Apache-2.0
5 */
6
7 #define DT_DRV_COMPAT ti_cc32xx_adc
8
9 #include <errno.h>
10
11 #include <zephyr/drivers/adc.h>
12 #include <zephyr/device.h>
13 #include <zephyr/kernel.h>
14 #include <zephyr/init.h>
15 #include <soc.h>
16
17 /* Driverlib includes */
18 #include <inc/hw_types.h>
19 #include <driverlib/pin.h>
20 #include <driverlib/rom.h>
21 #include <driverlib/rom_map.h>
22 #include <driverlib/prcm.h>
23 #include <driverlib/adc.h>
24
25 #define CHAN_COUNT 4
26
27 #define ADC_CONTEXT_USES_KERNEL_TIMER
28 #include "adc_context.h"
29
30 #define LOG_LEVEL CONFIG_ADC_LOG_LEVEL
31 #include <zephyr/logging/log.h>
32 #include <zephyr/irq.h>
33 LOG_MODULE_REGISTER(adc_cc32xx);
34
35 #define ISR_MASK (ADC_DMA_DONE | ADC_FIFO_OVERFLOW | ADC_FIFO_UNDERFLOW \
36 | ADC_FIFO_EMPTY | ADC_FIFO_FULL)
37
38 struct adc_cc32xx_data {
39 struct adc_context ctx;
40 const struct device *dev;
41 uint16_t *buffer;
42 uint16_t *repeat_buffer;
43 uint32_t channels;
44 uint8_t offset[CHAN_COUNT];
45 size_t active_channels;
46 };
47
48 struct adc_cc32xx_cfg {
49 unsigned long base;
50 void (*irq_cfg_func)(void);
51 };
52
53 static const int s_chPin[CHAN_COUNT] = {
54 PIN_57,
55 PIN_58,
56 PIN_59,
57 PIN_60,
58 };
59
60 static const int s_channel[CHAN_COUNT] = {
61 ADC_CH_0,
62 ADC_CH_1,
63 ADC_CH_2,
64 ADC_CH_3,
65 };
66
start_sampling(unsigned long base,int ch)67 static inline void start_sampling(unsigned long base, int ch)
68 {
69 MAP_ADCChannelEnable(base, ch);
70 for (int i = 0; i < 5; i++) {
71 while (!MAP_ADCFIFOLvlGet(base, ch)) {
72 }
73 MAP_ADCFIFORead(base, ch);
74 }
75 MAP_ADCIntClear(base, ch, ISR_MASK);
76 MAP_ADCIntEnable(base, ch, ISR_MASK);
77 }
78
adc_context_start_sampling(struct adc_context * ctx)79 static void adc_context_start_sampling(struct adc_context *ctx)
80 {
81 struct adc_cc32xx_data *data =
82 CONTAINER_OF(ctx, struct adc_cc32xx_data, ctx);
83 const struct adc_cc32xx_cfg *config = data->dev->config;
84
85 data->channels = ctx->sequence.channels;
86 data->repeat_buffer = data->buffer;
87
88 for (int i = 0; i < CHAN_COUNT; ++i) {
89 if (ctx->sequence.channels & BIT(i)) {
90 start_sampling(config->base, s_channel[i]);
91 }
92 }
93 }
94
adc_context_update_buffer_pointer(struct adc_context * ctx,bool repeat)95 static void adc_context_update_buffer_pointer(struct adc_context *ctx,
96 bool repeat)
97 {
98 struct adc_cc32xx_data *data =
99 CONTAINER_OF(ctx, struct adc_cc32xx_data, ctx);
100
101 if (repeat) {
102 data->buffer = data->repeat_buffer;
103 } else {
104 data->buffer += data->active_channels;
105 }
106 }
107
adc_cc32xx_init(const struct device * dev)108 static int adc_cc32xx_init(const struct device *dev)
109 {
110 struct adc_cc32xx_data *data = dev->data;
111 const struct adc_cc32xx_cfg *config = dev->config;
112
113 data->dev = dev;
114
115 LOG_DBG("Initializing....");
116
117 for (int i = 0; i < CHAN_COUNT; ++i) {
118 const int ch = s_channel[i];
119
120 MAP_ADCIntDisable(config->base, ch, ISR_MASK);
121 MAP_ADCChannelDisable(config->base, ch);
122 MAP_ADCDMADisable(config->base, ch);
123 MAP_ADCIntClear(config->base, ch, ISR_MASK);
124 }
125 MAP_ADCEnable(config->base);
126 config->irq_cfg_func();
127
128 adc_context_unlock_unconditionally(&data->ctx);
129 return 0;
130 }
131
adc_cc32xx_channel_setup(const struct device * dev,const struct adc_channel_cfg * channel_cfg)132 static int adc_cc32xx_channel_setup(const struct device *dev,
133 const struct adc_channel_cfg *channel_cfg)
134 {
135 const struct adc_cc32xx_cfg *config = dev->config;
136 const uint8_t ch = channel_cfg->channel_id;
137
138 if (ch >= CHAN_COUNT) {
139 LOG_ERR("Channel %d is not supported, max %d", ch, CHAN_COUNT);
140 return -EINVAL;
141 }
142
143 if (channel_cfg->acquisition_time != ADC_ACQ_TIME_DEFAULT) {
144 LOG_ERR("Acquisition time is not valid");
145 return -EINVAL;
146 }
147
148 if (channel_cfg->differential) {
149 LOG_ERR("Differential channels are not supported");
150 return -EINVAL;
151 }
152
153 if (channel_cfg->gain != ADC_GAIN_1) {
154 LOG_ERR("Gain is not valid");
155 return -EINVAL;
156 }
157
158 if (channel_cfg->reference != ADC_REF_INTERNAL) {
159 LOG_ERR("Reference is not valid");
160 return -EINVAL;
161 }
162
163 LOG_DBG("Setup %d", ch);
164
165 MAP_ADCChannelDisable(config->base, s_channel[ch]);
166 MAP_ADCIntDisable(config->base, s_channel[ch], ISR_MASK);
167 MAP_PinDirModeSet(s_chPin[ch], PIN_DIR_MODE_IN);
168 MAP_PinTypeADC(s_chPin[ch], PIN_MODE_255);
169
170 return 0;
171 }
172
cc32xx_read(const struct device * dev,const struct adc_sequence * sequence,bool asynchronous,struct k_poll_signal * sig)173 static int cc32xx_read(const struct device *dev,
174 const struct adc_sequence *sequence,
175 bool asynchronous,
176 struct k_poll_signal *sig)
177 {
178 struct adc_cc32xx_data *data = dev->data;
179 int rv;
180 size_t exp_size;
181
182 if (sequence->resolution != 12) {
183 LOG_ERR("Only 12 Resolution is supported, but %d got",
184 sequence->resolution);
185 return -EINVAL;
186 }
187
188 data->active_channels = 0;
189 for (int i = 0; i < CHAN_COUNT; ++i) {
190 if (!(sequence->channels & BIT(i))) {
191 continue;
192 }
193 data->offset[i] = data->active_channels++;
194 }
195 exp_size = data->active_channels * sizeof(uint16_t);
196 if (sequence->options) {
197 exp_size *= (1 + sequence->options->extra_samplings);
198 }
199
200 if (sequence->buffer_size < exp_size) {
201 LOG_ERR("Required buffer size is %u, but %u got",
202 exp_size, sequence->buffer_size);
203 return -ENOMEM;
204 }
205
206 data->buffer = sequence->buffer;
207
208 adc_context_lock(&data->ctx, asynchronous, sig);
209 adc_context_start_read(&data->ctx, sequence);
210 rv = adc_context_wait_for_completion(&data->ctx);
211 adc_context_release(&data->ctx, rv);
212 return rv;
213 }
214
adc_cc32xx_read(const struct device * dev,const struct adc_sequence * sequence)215 static int adc_cc32xx_read(const struct device *dev,
216 const struct adc_sequence *sequence)
217 {
218 return cc32xx_read(dev, sequence, false, NULL);
219 }
220
221 #ifdef CONFIG_ADC_ASYNC
adc_cc32xx_read_async(const struct device * dev,const struct adc_sequence * sequence,struct k_poll_signal * async)222 static int adc_cc32xx_read_async(const struct device *dev,
223 const struct adc_sequence *sequence,
224 struct k_poll_signal *async)
225 {
226 return cc32xx_read(dev, sequence, true, async);
227 }
228 #endif
229
adc_cc32xx_isr(const struct device * dev,int no)230 static void adc_cc32xx_isr(const struct device *dev, int no)
231 {
232 const struct adc_cc32xx_cfg *config = dev->config;
233 struct adc_cc32xx_data *data = dev->data;
234 const int chan = s_channel[no];
235 unsigned long mask = MAP_ADCIntStatus(config->base, chan);
236 int cnt = 0;
237 int rv = 0;
238
239 MAP_ADCIntClear(config->base, chan, mask);
240
241 if ((mask & ADC_FIFO_EMPTY) || !(mask & ADC_FIFO_FULL)) {
242 return;
243 }
244
245 while (MAP_ADCFIFOLvlGet(config->base, chan)) {
246 rv += (MAP_ADCFIFORead(config->base, chan) >> 2) & 0x0FFF;
247 cnt++;
248 }
249
250 *(data->buffer + data->offset[no]) = rv / cnt;
251 data->channels &= ~BIT(no);
252
253 MAP_ADCIntDisable(config->base, chan, ISR_MASK);
254 MAP_ADCChannelDisable(config->base, chan);
255
256 LOG_DBG("ISR %d, 0x%lX %d %d", chan, mask, rv, cnt);
257 if (!data->channels) {
258 adc_context_on_sampling_done(&data->ctx, dev);
259 }
260 }
261
adc_cc32xx_isr_ch0(const struct device * dev)262 static void adc_cc32xx_isr_ch0(const struct device *dev)
263 {
264 adc_cc32xx_isr(dev, 0);
265 }
266
adc_cc32xx_isr_ch1(const struct device * dev)267 static void adc_cc32xx_isr_ch1(const struct device *dev)
268 {
269 adc_cc32xx_isr(dev, 1);
270 }
271
adc_cc32xx_isr_ch2(const struct device * dev)272 static void adc_cc32xx_isr_ch2(const struct device *dev)
273 {
274 adc_cc32xx_isr(dev, 2);
275 }
276
adc_cc32xx_isr_ch3(const struct device * dev)277 static void adc_cc32xx_isr_ch3(const struct device *dev)
278 {
279 adc_cc32xx_isr(dev, 3);
280 }
281
282 static const struct adc_driver_api cc32xx_driver_api = {
283 .channel_setup = adc_cc32xx_channel_setup,
284 .read = adc_cc32xx_read,
285 #ifdef CONFIG_ADC_ASYNC
286 .read_async = adc_cc32xx_read_async,
287 #endif
288 .ref_internal = 1467,
289 };
290
291 #define cc32xx_ADC_IRQ_CONNECT(index, chan) \
292 do { \
293 IRQ_CONNECT(DT_INST_IRQ_BY_IDX(index, chan, irq), \
294 DT_INST_IRQ_BY_IDX(index, chan, priority), \
295 adc_cc32xx_isr_ch##chan, \
296 DEVICE_DT_INST_GET(index), 0); \
297 irq_enable(DT_INST_IRQ_BY_IDX(index, chan, irq)); \
298 } while (false)
299
300 #define cc32xx_ADC_INIT(index) \
301 \
302 static void adc_cc32xx_cfg_func_##index(void); \
303 \
304 static const struct adc_cc32xx_cfg adc_cc32xx_cfg_##index = { \
305 .base = DT_INST_REG_ADDR(index), \
306 .irq_cfg_func = adc_cc32xx_cfg_func_##index, \
307 }; \
308 static struct adc_cc32xx_data adc_cc32xx_data_##index = { \
309 ADC_CONTEXT_INIT_TIMER(adc_cc32xx_data_##index, ctx), \
310 ADC_CONTEXT_INIT_LOCK(adc_cc32xx_data_##index, ctx), \
311 ADC_CONTEXT_INIT_SYNC(adc_cc32xx_data_##index, ctx), \
312 }; \
313 \
314 DEVICE_DT_INST_DEFINE(index, \
315 &adc_cc32xx_init, NULL, &adc_cc32xx_data_##index, \
316 &adc_cc32xx_cfg_##index, POST_KERNEL, \
317 CONFIG_ADC_INIT_PRIORITY, \
318 &cc32xx_driver_api); \
319 \
320 static void adc_cc32xx_cfg_func_##index(void) \
321 { \
322 cc32xx_ADC_IRQ_CONNECT(index, 0); \
323 cc32xx_ADC_IRQ_CONNECT(index, 1); \
324 cc32xx_ADC_IRQ_CONNECT(index, 2); \
325 cc32xx_ADC_IRQ_CONNECT(index, 3); \
326 }
327
328 DT_INST_FOREACH_STATUS_OKAY(cc32xx_ADC_INIT)
329