Intel® Quark™ Microcontroller Software Interface 1.4.0 Intel® Quark™ Microcontroller BSP

- Main Page
- Modules
- Data Structures
- Files

- File List

qm_ss_adc.c
1 /*
2 * {% copyright %}
3 */
4
5 #include "qm_ss_adc.h"
6 #include <string.h>
7 #include "clk.h"
8
9 /* FIFO_INTERRUPT_THRESHOLD is used by qm_ss_adc_irq_convert to set the
10 * threshold at which the FIFO will trigger an interrupt. It is also used the
11 * ISR handler to determine the number of samples to read from the FIFO. */
12 #define FIFO_INTERRUPT_THRESHOLD (16)
13
14 #define QM_SS_ADC_CHAN_SEQ_MAX (32)
15 #define ADC_SAMPLE_SHIFT (11)
16
17 /* SS ADC commands. */
18 #define QM_SS_ADC_CMD_START_CAL (3)
19 #define QM_SS_ADC_CMD_LOAD_CAL (4)
20
21 /* Mode change delay is (clock speed * 5). */
22 #define CALCULATE_DELAY() (clk_sys_get_ticks_per_us() * 5)
23
24 static uint32_t adc_base[QM_SS_ADC_NUM] = {QM_SS_ADC_BASE};
25 static qm_ss_adc_xfer_t *irq_xfer[QM_SS_ADC_NUM];
26
27 static uint8_t sample_window[QM_SS_ADC_NUM];
28 static qm_ss_adc_resolution_t resolution[QM_SS_ADC_NUM];
29
30 static uint32_t count[QM_SS_ADC_NUM];
31
32 static void (*mode_callback[QM_SS_ADC_NUM])(void *data, int error,
33 qm_ss_adc_status_t status,
34 qm_ss_adc_cb_source_t source);
35 static void (*cal_callback[QM_SS_ADC_NUM])(void *data, int error,
36 qm_ss_adc_status_t status,
37 qm_ss_adc_cb_source_t source);
38 static void *mode_callback_data[QM_SS_ADC_NUM];
39 static void *cal_callback_data[QM_SS_ADC_NUM];
40
41 static void dummy_conversion(uint32_t controller);
42
43 /* As the mode change interrupt is always asserted when the requested mode
44 * matches the current mode, an interrupt will be triggered whenever it is
45 * unmasked, which may need to be suppressed. */
46 static volatile bool ignore_spurious_interrupt[QM_SS_ADC_NUM] = {true};
47 static qm_ss_adc_mode_t requested_mode[QM_SS_ADC_NUM];
48
49 static void enable_adc(void)
50 {
51 QM_SS_REG_AUX_OR(QM_SS_ADC_BASE + QM_SS_ADC_CTRL,
52 QM_SS_ADC_CTRL_ADC_ENA);
53 }
54
55 static void disable_adc(void)
56 {
57 QM_SS_REG_AUX_NAND(QM_SS_ADC_BASE + QM_SS_ADC_CTRL,
58 QM_SS_ADC_CTRL_ADC_ENA);
59 }
60
61 static void qm_ss_adc_isr_handler(const qm_ss_adc_t adc)
62 {
63 uint32_t i, samples_to_read;
64 uint32_t controller = adc_base[adc];
65
66 /* Calculate the number of samples to read. */
67 samples_to_read = FIFO_INTERRUPT_THRESHOLD;
68 if (samples_to_read > (irq_xfer[adc]->samples_len - count[adc])) {
69 samples_to_read = irq_xfer[adc]->samples_len - count[adc];
70 }
71
72 /* Read the samples into the array. */
73 for (i = 0; i < samples_to_read; i++) {
74 /* Pop one sample into the sample register. */
75 QM_SS_REG_AUX_OR(controller + QM_SS_ADC_SET,
76 QM_SS_ADC_SET_POP_RX);
77 /* Read the sample in the array. */
78 irq_xfer[adc]->samples[count[adc]] =
79 (__builtin_arc_lr(controller + QM_SS_ADC_SAMPLE) >>
80 (ADC_SAMPLE_SHIFT - resolution[adc]));
81 count[adc]++;
82 }
83 /* Clear the data available status register. */
84 QM_SS_REG_AUX_OR(controller + QM_SS_ADC_CTRL,
85 QM_SS_ADC_CTRL_CLR_DATA_A);
86
87 if (count[adc] == irq_xfer[adc]->samples_len) {
88 /* Stop the sequencer. */
89 QM_SS_REG_AUX_NAND(controller + QM_SS_ADC_CTRL,
90 QM_SS_ADC_CTRL_SEQ_START);
91
92 /* Mask all interrupts. */
93 QM_SS_REG_AUX_OR(controller + QM_SS_ADC_CTRL,
94 QM_SS_ADC_CTRL_MSK_ALL_INT);
95
96 /* Call the user callback. */
97 if (irq_xfer[adc]->callback) {
98 irq_xfer[adc]->callback(irq_xfer[adc]->callback_data, 0,
99 QM_SS_ADC_COMPLETE,
100 QM_SS_ADC_TRANSFER);
101 }
102
103 /* Disable the ADC. */
104 disable_adc();
105
106 return;
107 }
108 }
109
110 static void qm_ss_adc_isr_err_handler(const qm_ss_adc_t adc)
111 {
112 uint32_t controller = adc_base[adc];
113 uint32_t intstat = __builtin_arc_lr(controller + QM_SS_ADC_INTSTAT);
114
115 /* Stop the sequencer. */
116 QM_SS_REG_AUX_NAND(controller + QM_SS_ADC_CTRL,
117 QM_SS_ADC_CTRL_SEQ_START);
118
119 /* Mask all interrupts. */
120 QM_SS_REG_AUX_OR(controller + QM_SS_ADC_CTRL,
121 QM_SS_ADC_CTRL_MSK_ALL_INT);
122
123 /* Call the user callback and pass it the status code. */
124 if (intstat & QM_SS_ADC_INTSTAT_OVERFLOW) {
125 if (irq_xfer[adc]->callback) {
126 irq_xfer[adc]->callback(irq_xfer[adc]->callback_data,
127 -EIO, QM_SS_ADC_OVERFLOW,
128 QM_SS_ADC_TRANSFER);
129 }
130 }
131 if (intstat & QM_SS_ADC_INTSTAT_UNDERFLOW) {
132 if (irq_xfer[adc]->callback) {
133 irq_xfer[adc]->callback(irq_xfer[adc]->callback_data,
134 -EIO, QM_SS_ADC_UNDERFLOW,
135 QM_SS_ADC_TRANSFER);
136 }
137 }
138 if (intstat & QM_SS_ADC_INTSTAT_SEQERROR) {
139 if (irq_xfer[adc]->callback) {
140 irq_xfer[adc]->callback(irq_xfer[adc]->callback_data,
141 -EIO, QM_SS_ADC_SEQERROR,
142 QM_SS_ADC_TRANSFER);
143 }
144 }
145
146 /* Clear all error interrupts. */
147 QM_SS_REG_AUX_OR(controller + QM_SS_ADC_CTRL,
148 (QM_SS_ADC_CTRL_CLR_SEQERROR |
149 QM_SS_ADC_CTRL_CLR_OVERFLOW |
150 QM_SS_ADC_CTRL_CLR_UNDERFLOW));
151
152 /* Disable the ADC. */
153 disable_adc();
154 }
155
156 static void qm_ss_adc_isr_pwr_handler(const qm_ss_adc_t adc)
157 {
158 uint32_t controller = adc_base[adc];
159
160 /* The IRQ associated with the mode change fires an interrupt as soon
161 * as it is enabled so it is necessary to ignore it the first time the
162 * ISR runs. */
163 if (ignore_spurious_interrupt[adc]) {
164 ignore_spurious_interrupt[adc] = false;
165 return;
166 }
167
168 /* Perform a dummy conversion if we are transitioning to Normal Mode. */
169 if ((requested_mode[adc] >= QM_SS_ADC_MODE_NORM_CAL)) {
170 dummy_conversion(controller);
171 }
172
173 /* Call the user callback if it is set. */
174 if (mode_callback[adc]) {
175 mode_callback[adc](mode_callback_data[adc], 0, QM_SS_ADC_IDLE,
176 QM_SS_ADC_MODE_CHANGED);
177 }
178 }
179
180 static void qm_ss_adc_isr_cal_handler(const qm_ss_adc_t adc)
181 {
182 /* Clear the calibration request reg. */
183 QM_SS_REG_AUX_NAND(QM_SS_CREG_BASE + QM_SS_IO_CREG_MST0_CTRL,
184 QM_SS_IO_CREG_MST0_CTRL_ADC_CAL_REQ);
185
186 /* Call the user callback if it is set. */
187 if (cal_callback[adc]) {
188 cal_callback[adc](cal_callback_data[adc], 0, QM_SS_ADC_IDLE,
189 QM_SS_ADC_CAL_COMPLETE);
190 }
191
192 /* Disable the ADC. */
193 disable_adc();
194 }
195
196 /* ISR for SS ADC 0 Data available. */
197 QM_ISR_DECLARE(qm_ss_adc_0_isr)
198 {
199 qm_ss_adc_isr_handler(QM_SS_ADC_0);
200 }
201
202 /* ISR for SS ADC 0 Error. */
203 QM_ISR_DECLARE(qm_ss_adc_0_error_isr)
204 {
205 qm_ss_adc_isr_err_handler(QM_SS_ADC_0);
206 }
207
208 /* ISR for SS ADC 0 Mode change. */
209 QM_ISR_DECLARE(qm_ss_adc_0_pwr_isr)
210 {
211 qm_ss_adc_isr_pwr_handler(QM_SS_ADC_0);
212 }
213
214 /* ISR for SS ADC 0 Calibration. */
215 QM_ISR_DECLARE(qm_ss_adc_0_cal_isr)
216 {
217 qm_ss_adc_isr_cal_handler(QM_SS_ADC_0);
218 }
219
220 static void setup_seq_table(const qm_ss_adc_t adc, qm_ss_adc_xfer_t *xfer,
221 bool single_run)
222 {
223 uint32_t i, reg, ch_odd, ch_even, seq_entry = 0;
224 uint32_t num_channels, controller = adc_base[adc];
225 /* The sample window is the time in cycles between the start of one
226 * sample and the start of the next. Resolution is indexed from 0 so we
227 * need to add 1 and a further 2 for the time it takes to process. */
228 uint16_t delay = (sample_window[adc] - (resolution[adc] + 3));
229
230 /* Reset the sequence table and sequence pointer. */
231 QM_SS_REG_AUX_OR(controller + QM_SS_ADC_CTRL,
232 QM_SS_ADC_CTRL_SEQ_TABLE_RST);
233
234 /* If a single run is requested and the number of channels in ch is less
235 * than the number of samples requested we need to insert multiple
236 * channels into the sequence table. */
237 num_channels = single_run ? xfer->samples_len : xfer->ch_len;
238
239 /* The sequence table has to be populated with pairs of entries so there
240 * are sample_len/2 pairs of entries. These entries are read from the
241 * ch array in pairs. The same delay is used between all entries. */
242 for (i = 0; i < (num_channels - 1); i += 2) {
243 ch_odd = xfer->ch[(i + 1) % xfer->ch_len];
244 ch_even = xfer->ch[i % xfer->ch_len];
245 seq_entry =
246 ((delay << QM_SS_ADC_SEQ_DELAYODD_OFFSET) |
247 (ch_odd << QM_SS_ADC_SEQ_MUXODD_OFFSET) |
248 (delay << QM_SS_ADC_SEQ_DELAYEVEN_OFFSET) | ch_even);
249 __builtin_arc_sr(seq_entry, controller + QM_SS_ADC_SEQ);
250 }
251 /* If there is an uneven number of entries we need to create a final
252 * pair with a singly entry. */
253 if (num_channels % 2) {
254 ch_even = xfer->ch[i % xfer->ch_len];
255 seq_entry =
256 ((delay << QM_SS_ADC_SEQ_DELAYEVEN_OFFSET) | (ch_even));
257 __builtin_arc_sr(seq_entry, controller + QM_SS_ADC_SEQ);
258 }
259
260 /* Reset the sequence pointer back to 0. */
261 QM_SS_REG_AUX_OR(controller + QM_SS_ADC_CTRL,
262 QM_SS_ADC_CTRL_SEQ_PTR_RST);
263
264 /* Set the number of entries in the sequencer. */
265 reg = __builtin_arc_lr(controller + QM_SS_ADC_SET);
266 reg &= ~QM_SS_ADC_SET_SEQ_ENTRIES_MASK;
267 reg |= ((num_channels - 1) << QM_SS_ADC_SET_SEQ_ENTRIES_OFFSET);
268 __builtin_arc_sr(reg, controller + QM_SS_ADC_SET);
269 }
270
271 static void dummy_conversion(uint32_t controller)
272 {
273 uint32_t reg;
274 int res;
275
276 /* Flush the FIFO. */
277 QM_SS_REG_AUX_OR(controller + QM_SS_ADC_SET, QM_SS_ADC_SET_FLUSH_RX);
278
279 /* Set up sequence table. */
280 QM_SS_REG_AUX_OR(controller + QM_SS_ADC_CTRL,
281 QM_SS_ADC_CTRL_SEQ_TABLE_RST);
282
283 /* Populate the seq table. */
284 __builtin_arc_sr(QM_SS_ADC_SEQ_DUMMY, controller + QM_SS_ADC_SEQ);
285
286 /* Reset the sequence pointer back to 0. */
287 QM_SS_REG_AUX_OR(controller + QM_SS_ADC_CTRL,
288 QM_SS_ADC_CTRL_SEQ_PTR_RST);
289
290 /* Set the number of entries in the sequencer. */
291 reg = __builtin_arc_lr(controller + QM_SS_ADC_SET);
292 reg &= ~QM_SS_ADC_SET_SEQ_ENTRIES_MASK;
293 reg |= (0 << QM_SS_ADC_SET_SEQ_ENTRIES_OFFSET);
294 __builtin_arc_sr(reg, controller + QM_SS_ADC_SET);
295
296 /* Set the threshold. */
297 reg = __builtin_arc_lr(controller + QM_SS_ADC_SET);
298 reg &= ~QM_SS_ADC_SET_THRESHOLD_MASK;
299 reg |= (0 << QM_SS_ADC_SET_THRESHOLD_OFFSET);
300 __builtin_arc_sr(reg, controller + QM_SS_ADC_SET);
301
302 /* Set the sequence mode to single run. */
303 QM_SS_REG_AUX_NAND(controller + QM_SS_ADC_SET, QM_SS_ADC_SET_SEQ_MODE);
304
305 /* Clear all interrupts. */
306 QM_SS_REG_AUX_OR(controller + QM_SS_ADC_CTRL,
307 QM_SS_ADC_CTRL_CLR_ALL_INT);
308 /* Mask all interrupts. */
309 QM_SS_REG_AUX_OR(controller + QM_SS_ADC_CTRL,
310 QM_SS_ADC_CTRL_MSK_ALL_INT);
311
312 /* Enable the ADC. */
313 enable_adc();
314
315 /* Start the sequencer. */
316 QM_SS_REG_AUX_OR(controller + QM_SS_ADC_CTRL, QM_SS_ADC_CTRL_SEQ_START);
317
318 /* Wait for the sequence to finish. */
319 while (!(res = __builtin_arc_lr(controller + QM_SS_ADC_INTSTAT))) {
320 }
321
322 /* Flush the FIFO. */
323 QM_SS_REG_AUX_OR(controller + QM_SS_ADC_SET, QM_SS_ADC_SET_FLUSH_RX);
324 /* Clear the data available status register. */
325 QM_SS_REG_AUX_OR(controller + QM_SS_ADC_CTRL,
326 QM_SS_ADC_CTRL_CLR_DATA_A);
327
328 /* Unmask all interrupts. */
329 QM_SS_REG_AUX_NAND(controller + QM_SS_ADC_CTRL,
330 QM_SS_ADC_CTRL_MSK_ALL_INT);
331 /* Disable the ADC. */
332 disable_adc();
333 }
334
335 int qm_ss_adc_set_config(const qm_ss_adc_t adc,
336 const qm_ss_adc_config_t *const cfg)
337 {
338 uint32_t reg;
339 uint32_t controller = adc_base[adc];
340
341 QM_CHECK(adc < QM_SS_ADC_NUM, -EINVAL);
342 QM_CHECK(NULL != cfg, -EINVAL);
343 QM_CHECK(cfg->resolution <= QM_SS_ADC_RES_12_BITS, -EINVAL);
344 /* The window must be 2 greater than the resolution but since this is
345 * indexed from 0 we need to add a further 1. */
346 QM_CHECK(cfg->window >= (cfg->resolution + 3), -EINVAL);
347
348 /* Set the sample window and resolution. */
349 sample_window[adc] = cfg->window;
350 resolution[adc] = cfg->resolution;
351
352 /* Set the resolution. */
353 reg = __builtin_arc_lr(controller + QM_SS_ADC_SET);
354 reg &= ~QM_SS_ADC_SET_SAMPLE_WIDTH_MASK;
355 reg |= resolution[adc];
356 __builtin_arc_sr(reg, controller + QM_SS_ADC_SET);
357
358 return 0;
359 }
360
361 int qm_ss_adc_set_mode(const qm_ss_adc_t adc, const qm_ss_adc_mode_t mode)
362 {
363 uint32_t creg, delay, intstat;
364 uint32_t controller = adc_base[adc];
365
366 QM_CHECK(adc < QM_SS_ADC_NUM, -EINVAL);
367 QM_CHECK(mode <= QM_SS_ADC_MODE_NORM_NO_CAL, -EINVAL);
368
369 /* Save the state of the mode interrupt mask. */
370 intstat = QM_IR_GET_MASK(QM_INTERRUPT_ROUTER->adc_0_pwr_int_mask);
371 /* Mask the ADC mode change interrupt. */
372 QM_IR_MASK_INTERRUPTS(QM_INTERRUPT_ROUTER->adc_0_pwr_int_mask);
373
374 /* Calculate the delay. */
375 delay = CALCULATE_DELAY();
376
377 /* Issue mode change command and wait for it to complete. */
378 creg = __builtin_arc_lr(QM_SS_CREG_BASE + QM_SS_IO_CREG_MST0_CTRL);
379 creg &= ~((QM_SS_IO_CREG_MST0_CTRL_ADC_DELAY_MASK
380 << QM_SS_IO_CREG_MST0_CTRL_ADC_DELAY_OFFSET) |
381 QM_SS_IO_CREG_MST0_CTRL_ADC_PWR_MODE_MASK);
382 creg |= ((delay << QM_SS_IO_CREG_MST0_CTRL_ADC_DELAY_OFFSET) | mode);
383 __builtin_arc_sr(creg, QM_SS_CREG_BASE + QM_SS_IO_CREG_MST0_CTRL);
384
385 /* Wait for the mode change to complete. */
386 while (!(__builtin_arc_lr(QM_SS_CREG_BASE + QM_SS_IO_CREG_SLV0_OBSR) &
387 QM_SS_IO_CREG_SLV0_OBSR_ADC_PWR_MODE_STS)) {
388 }
389
390 /* Restore the state of the mode change interrupt mask if necessary. */
391 if (!intstat) {
392 ignore_spurious_interrupt[adc] = true;
393 QM_IR_UNMASK_INTERRUPTS(
394 QM_INTERRUPT_ROUTER->adc_0_pwr_int_mask);
395 }
396
397 /* Perform a dummy conversion if transitioning to Normal Mode. */
398 if ((mode >= QM_SS_ADC_MODE_NORM_CAL)) {
399 dummy_conversion(controller);
400 }
401
402 return 0;
403 }
404
405 int qm_ss_adc_irq_set_mode(const qm_ss_adc_t adc, const qm_ss_adc_mode_t mode,
406 void (*callback)(void *data, int error,
407 qm_ss_adc_status_t status,
408 qm_ss_adc_cb_source_t source),
409 void *callback_data)
410 {
411 uint32_t creg, delay;
412 QM_CHECK(adc < QM_SS_ADC_NUM, -EINVAL);
413 QM_CHECK(mode <= QM_SS_ADC_MODE_NORM_NO_CAL, -EINVAL);
414
415 mode_callback[adc] = callback;
416 mode_callback_data[adc] = callback_data;
417 requested_mode[adc] = mode;
418
419 /* Calculate the delay. */
420 delay = CALCULATE_DELAY();
421
422 /* Issue mode change command and wait for it to complete. */
423 creg = __builtin_arc_lr(QM_SS_CREG_BASE + QM_SS_IO_CREG_MST0_CTRL);
424 creg &= ~((QM_SS_IO_CREG_MST0_CTRL_ADC_DELAY_MASK
425 << QM_SS_IO_CREG_MST0_CTRL_ADC_DELAY_OFFSET) |
426 QM_SS_IO_CREG_MST0_CTRL_ADC_PWR_MODE_MASK);
427 creg |= ((delay << QM_SS_IO_CREG_MST0_CTRL_ADC_DELAY_OFFSET) | mode);
428 __builtin_arc_sr(creg, QM_SS_CREG_BASE + QM_SS_IO_CREG_MST0_CTRL);
429
430 return 0;
431 }
432
433 int qm_ss_adc_calibrate(const qm_ss_adc_t adc __attribute__((unused)))
434 {
435 uint32_t creg, intstat;
436 QM_CHECK(adc < QM_SS_ADC_NUM, -EINVAL);
437
438 /* Save the state of the calibration interrupt mask. */
439 intstat = QM_IR_GET_MASK(QM_INTERRUPT_ROUTER->adc_0_cal_int_mask);
440 /* Mask the ADC calibration interrupt. */
441 QM_IR_MASK_INTERRUPTS(QM_INTERRUPT_ROUTER->adc_0_cal_int_mask);
442
443 /* Enable the ADC. */
444 enable_adc();
445
446 /* Issue the start calibrate command. */
447 creg = __builtin_arc_lr(QM_SS_CREG_BASE + QM_SS_IO_CREG_MST0_CTRL);
448 creg &= ~(QM_SS_IO_CREG_MST0_CTRL_ADC_CAL_CMD_MASK |
449 QM_SS_IO_CREG_MST0_CTRL_ADC_CAL_REQ);
450 creg |= ((QM_SS_ADC_CMD_START_CAL
451 << QM_SS_IO_CREG_MST0_CTRL_ADC_CAL_CMD_OFFSET) |
452 QM_SS_IO_CREG_MST0_CTRL_ADC_CAL_REQ);
453 __builtin_arc_sr(creg, QM_SS_CREG_BASE + QM_SS_IO_CREG_MST0_CTRL);
454
455 /* Wait for the calibrate command to complete. */
456 while (!(__builtin_arc_lr(QM_SS_CREG_BASE + QM_SS_IO_CREG_SLV0_OBSR) &
457 QM_SS_IO_CREG_SLV0_OBSR_ADC_CAL_ACK)) {
458 }
459
460 /* Clear the calibration request reg and wait for it to complete. */
461 QM_SS_REG_AUX_NAND(QM_SS_CREG_BASE + QM_SS_IO_CREG_MST0_CTRL,
462 QM_SS_IO_CREG_MST0_CTRL_ADC_CAL_REQ);
463 while (__builtin_arc_lr(QM_SS_CREG_BASE + QM_SS_IO_CREG_SLV0_OBSR) &
464 QM_SS_IO_CREG_SLV0_OBSR_ADC_CAL_ACK) {
465 }
466
467 /* Disable the ADC. */
468 disable_adc();
469
470 /* Restore the state of the calibration interrupt mask if necessary. */
471 if (!intstat) {
472 QM_IR_UNMASK_INTERRUPTS(
473 QM_INTERRUPT_ROUTER->adc_0_cal_int_mask);
474 }
475
476 return 0;
477 }
478
479 int qm_ss_adc_irq_calibrate(const qm_ss_adc_t adc,
480 void (*callback)(void *data, int error,
481 qm_ss_adc_status_t status,
482 qm_ss_adc_cb_source_t source),
483 void *callback_data)
484 {
485 uint32_t creg;
486 QM_CHECK(adc < QM_SS_ADC_NUM, -EINVAL);
487
488 cal_callback[adc] = callback;
489 cal_callback_data[adc] = callback_data;
490
491 /* Enable the ADC. */
492 enable_adc();
493
494 /* Issue the start calibrate command. */
495 creg = __builtin_arc_lr(QM_SS_CREG_BASE + QM_SS_IO_CREG_MST0_CTRL);
496 creg &= ~(QM_SS_IO_CREG_MST0_CTRL_ADC_CAL_CMD_MASK |
497 QM_SS_IO_CREG_MST0_CTRL_ADC_CAL_REQ);
498 creg |= ((QM_SS_ADC_CMD_START_CAL
499 << QM_SS_IO_CREG_MST0_CTRL_ADC_CAL_CMD_OFFSET) |
500 QM_SS_IO_CREG_MST0_CTRL_ADC_CAL_REQ);
501 __builtin_arc_sr(creg, QM_SS_CREG_BASE + QM_SS_IO_CREG_MST0_CTRL);
502
503 return 0;
504 }
505
506 int qm_ss_adc_set_calibration(const qm_ss_adc_t adc __attribute__((unused)),
507 const qm_ss_adc_calibration_t cal_data)
508 {
509 uint32_t creg, intstat;
510
511 QM_CHECK(adc < QM_SS_ADC_NUM, -EINVAL);
512 QM_CHECK(cal_data <= QM_SS_IO_CREG_MST0_CTRL_ADC_CAL_VAL_MAX, -EINVAL);
513
514 /* Save the state of the calibration interrupt mask. */
515 intstat = QM_IR_GET_MASK(QM_INTERRUPT_ROUTER->adc_0_cal_int_mask);
516 /* Mask the ADC calibration interrupt. */
517 QM_IR_MASK_INTERRUPTS(QM_INTERRUPT_ROUTER->adc_0_cal_int_mask);
518
519 /* Issue the load calibrate command. */
520 creg = __builtin_arc_lr(QM_SS_CREG_BASE + QM_SS_IO_CREG_MST0_CTRL);
521 creg &= ~(QM_SS_IO_CREG_MST0_CTRL_ADC_CAL_VAL_MASK |
522 QM_SS_IO_CREG_MST0_CTRL_ADC_CAL_CMD_MASK |
523 QM_SS_IO_CREG_MST0_CTRL_ADC_CAL_REQ);
524 creg |= ((cal_data << QM_SS_IO_CREG_MST0_CTRL_ADC_CAL_VAL_OFFSET) |
525 (QM_SS_ADC_CMD_LOAD_CAL
526 << QM_SS_IO_CREG_MST0_CTRL_ADC_CAL_CMD_OFFSET) |
527 QM_SS_IO_CREG_MST0_CTRL_ADC_CAL_REQ);
528 __builtin_arc_sr(creg, QM_SS_CREG_BASE + QM_SS_IO_CREG_MST0_CTRL);
529
530 /* Wait for the calibrate command to complete. */
531 while (!(__builtin_arc_lr(QM_SS_CREG_BASE + QM_SS_IO_CREG_SLV0_OBSR) &
532 QM_SS_IO_CREG_SLV0_OBSR_ADC_CAL_ACK)) {
533 }
534
535 /* Clear the calibration request reg and wait for it to complete. */
536 QM_SS_REG_AUX_NAND(QM_SS_CREG_BASE + QM_SS_IO_CREG_MST0_CTRL,
537 QM_SS_IO_CREG_MST0_CTRL_ADC_CAL_REQ);
538 while (__builtin_arc_lr(QM_SS_CREG_BASE + QM_SS_IO_CREG_SLV0_OBSR) &
539 QM_SS_IO_CREG_SLV0_OBSR_ADC_CAL_ACK) {
540 }
541
542 /* Restore the state of the calibration interrupt mask if necessary. */
543 if (!intstat) {
544 QM_IR_UNMASK_INTERRUPTS(
545 QM_INTERRUPT_ROUTER->adc_0_cal_int_mask);
546 }
547
548 return 0;
549 }
550
551 int qm_ss_adc_get_calibration(const qm_ss_adc_t adc __attribute__((unused)),
552 qm_ss_adc_calibration_t *const cal)
553 {
554 QM_CHECK(adc < QM_SS_ADC_NUM, -EINVAL);
555 QM_CHECK(NULL != cal, -EINVAL);
556
557 *cal = ((__builtin_arc_lr(QM_SS_CREG_BASE + QM_SS_IO_CREG_SLV0_OBSR) &
558 QM_SS_IO_CREG_SLV0_OBSR_ADC_CAL_VAL_MASK) >>
559 QM_SS_IO_CREG_SLV0_OBSR_ADC_CAL_VAL_OFFSET);
560
561 return 0;
562 }
563
564 int qm_ss_adc_convert(const qm_ss_adc_t adc, qm_ss_adc_xfer_t *xfer,
565 qm_ss_adc_status_t *const status)
566 {
567 uint32_t reg, i;
568 uint32_t controller = adc_base[adc];
569 int res;
570
571 QM_CHECK(adc < QM_SS_ADC_NUM, -EINVAL);
572 QM_CHECK(NULL != xfer, -EINVAL);
573 QM_CHECK(NULL != xfer->ch, -EINVAL);
574 QM_CHECK(NULL != xfer->samples, -EINVAL);
575 QM_CHECK(xfer->ch_len > 0, -EINVAL);
576 QM_CHECK(xfer->ch_len <= QM_SS_ADC_CHAN_SEQ_MAX, -EINVAL);
577 QM_CHECK(xfer->samples_len > 0, -EINVAL);
578 QM_CHECK(xfer->samples_len <= QM_SS_ADC_FIFO_LEN, -EINVAL);
579
580 /* Flush the FIFO. */
581 QM_SS_REG_AUX_OR(controller + QM_SS_ADC_SET, QM_SS_ADC_SET_FLUSH_RX);
582
583 /* Populate the sequence table. */
584 setup_seq_table(adc, xfer, true);
585
586 /* Set the threshold. */
587 reg = __builtin_arc_lr(controller + QM_SS_ADC_SET);
588 reg &= ~QM_SS_ADC_SET_THRESHOLD_MASK;
589 reg |= ((xfer->samples_len - 1) << QM_SS_ADC_SET_THRESHOLD_OFFSET);
590 __builtin_arc_sr(reg, controller + QM_SS_ADC_SET);
591
592 /* Set the sequence mode to single run. */
593 QM_SS_REG_AUX_NAND(controller + QM_SS_ADC_SET, QM_SS_ADC_SET_SEQ_MODE);
594
595 /* Mask all interrupts. */
596 QM_SS_REG_AUX_OR(controller + QM_SS_ADC_CTRL,
597 QM_SS_ADC_CTRL_MSK_ALL_INT);
598
599 /* Enable the ADC. */
600 enable_adc();
601
602 /* Start the sequencer. */
603 QM_SS_REG_AUX_OR(controller + QM_SS_ADC_CTRL, QM_SS_ADC_CTRL_SEQ_START);
604
605 /* Wait for the sequence to finish. */
606 while (!(res = __builtin_arc_lr(controller + QM_SS_ADC_INTSTAT))) {
607 }
608
609 /* Return if we get an error (UNDERFLOW, OVERFLOW, SEQ_ERROR). */
610 if (res > 1) {
611 if (status) {
612 *status = res;
613 }
614 return -EIO;
615 }
616
617 /* Read the samples into the array. */
618 for (i = 0; i < xfer->samples_len; i++) {
619 /* Pop one sample into the sample register. */
620 QM_SS_REG_AUX_OR(controller + QM_SS_ADC_SET,
621 QM_SS_ADC_SET_POP_RX);
622 /* Read the sample in the array. */
623 xfer->samples[i] =
624 (__builtin_arc_lr(controller + QM_SS_ADC_SAMPLE) >>
625 (ADC_SAMPLE_SHIFT - resolution[adc]));
626 }
627
628 /* Clear the data available status register. */
629 QM_SS_REG_AUX_OR(controller + QM_SS_ADC_CTRL,
630 QM_SS_ADC_CTRL_CLR_DATA_A);
631
632 /* Disable the ADC. */
633 disable_adc();
634
635 return 0;
636 }
637
638 int qm_ss_adc_irq_convert(const qm_ss_adc_t adc, qm_ss_adc_xfer_t *xfer)
639 {
640 uint32_t reg;
641 uint32_t controller = adc_base[adc];
642
643 QM_CHECK(adc < QM_SS_ADC_NUM, -EINVAL);
644 QM_CHECK(NULL != xfer, -EINVAL);
645 QM_CHECK(NULL != xfer->ch, -EINVAL);
646 QM_CHECK(NULL != xfer->samples, -EINVAL);
647 QM_CHECK(xfer->ch_len > 0, -EINVAL);
648 QM_CHECK(xfer->samples_len > 0, -EINVAL);
649 QM_CHECK(xfer->ch_len <= QM_SS_ADC_CHAN_SEQ_MAX, -EINVAL);
650
651 /* Flush the FIFO. */
652 QM_SS_REG_AUX_OR(controller + QM_SS_ADC_SET, QM_SS_ADC_SET_FLUSH_RX);
653
654 /* Populate the sequence table. */
655 setup_seq_table(adc, xfer, false);
656
657 /* Copy the xfer struct so we can get access from the ISR. */
658 irq_xfer[adc] = xfer;
659
660 /* Set count back to 0. */
661 count[adc] = 0;
662
663 /* Set the threshold. */
664 reg = __builtin_arc_lr(controller + QM_SS_ADC_SET);
665 reg &= ~QM_SS_ADC_SET_THRESHOLD_MASK;
666 reg |= (FIFO_INTERRUPT_THRESHOLD - 1) << QM_SS_ADC_SET_THRESHOLD_OFFSET;
667 __builtin_arc_sr(reg, controller + QM_SS_ADC_SET);
668
669 /* Set the sequence mode to repetitive. */
670 QM_SS_REG_AUX_OR(controller + QM_SS_ADC_SET, QM_SS_ADC_SET_SEQ_MODE);
671
672 /* Enable all interrupts. */
673 QM_SS_REG_AUX_NAND(controller + QM_SS_ADC_CTRL, 0x1F00);
674
675 /* Enable the ADC. */
676 enable_adc();
677
678 /* Start the sequencer. */
679 QM_SS_REG_AUX_OR(controller + QM_SS_ADC_CTRL, QM_SS_ADC_CTRL_SEQ_START);
680
681 return 0;
682 }
683
684 #if (ENABLE_RESTORE_CONTEXT)
685 int qm_ss_adc_save_context(const qm_ss_adc_t adc,
686 qm_ss_adc_context_t *const ctx)
687 {
688 const uint32_t controller = adc_base[adc];
689
690 QM_CHECK(adc < QM_SS_ADC_NUM, -EINVAL);
691 QM_CHECK(NULL != ctx, -EINVAL);
692
693 ctx->adc_set = __builtin_arc_lr(controller + QM_SS_ADC_SET);
694 ctx->adc_divseqstat =
695 __builtin_arc_lr(controller + QM_SS_ADC_DIVSEQSTAT);
696 ctx->adc_seq = __builtin_arc_lr(controller + QM_SS_ADC_SEQ);
697 /* Restore control register with ADC enable bit cleared. */
698 ctx->adc_ctrl = __builtin_arc_lr(controller + QM_SS_ADC_CTRL) &
699 ~QM_SS_ADC_CTRL_ADC_ENA;
700
701 /*
702 * The IRQ associated with the mode change fires an interrupt as soon
703 * as it is enabled so it is necessary to ignore it the first time the
704 * ISR runs. This is set in the save function in case interrupts are
705 * enabled before the restore function runs.
706 */
707 ignore_spurious_interrupt[adc] = true;
708
709 return 0;
710 }
711
712 int qm_ss_adc_restore_context(const qm_ss_adc_t adc,
713 const qm_ss_adc_context_t *const ctx)
714 {
715 const uint32_t controller = adc_base[adc];
716
717 QM_CHECK(adc < QM_SS_ADC_NUM, -EINVAL);
718 QM_CHECK(NULL != ctx, -EINVAL);
719
720 __builtin_arc_sr(ctx->adc_set, controller + QM_SS_ADC_SET);
721 __builtin_arc_sr(ctx->adc_divseqstat,
722 controller + QM_SS_ADC_DIVSEQSTAT);
723 __builtin_arc_sr(ctx->adc_seq, controller + QM_SS_ADC_SEQ);
724 __builtin_arc_sr(ctx->adc_ctrl, controller + QM_SS_ADC_CTRL);
725
726 return 0;
727 }
728 #else
729 int qm_ss_adc_save_context(const qm_ss_adc_t adc,
730 qm_ss_adc_context_t *const ctx)
731 {
732 (void)adc;
733 (void)ctx;
734
735 return 0;
736 }
737
738 int qm_ss_adc_restore_context(const qm_ss_adc_t adc,
739 const qm_ss_adc_context_t *const ctx)
740 {
741 (void)adc;
742 (void)ctx;
743
744 return 0;
745 }
746 #endif /* ENABLE_RESTORE_CONTEXT */
qm_ss_adc_xfer_t::samples_len
uint32_t samples_len
Length of sample array.
Definition: qm_ss_adc.h:115
QM_SS_ADC_SEQ
ADC sequence entry register.
Definition: qm_sensor_regs.h:544
qm_ss_adc_convert
int qm_ss_adc_convert(const qm_ss_adc_t adc, qm_ss_adc_xfer_t *xfer, qm_ss_adc_status_t *const status)
Synchronously read values from the ADC.
Definition: qm_ss_adc.c:564
QM_SS_ADC_CAL_COMPLETE
Calibration complete callback.
Definition: qm_ss_adc.h:92
qm_ss_adc_cb_source_t
qm_ss_adc_cb_source_t
SS ADC interrupt callback source.
Definition: qm_ss_adc.h:89
qm_ss_adc_context_t::adc_ctrl
uint32_t adc_ctrl
ADC control.
Definition: qm_sensor_regs.h:568
QM_SS_ADC_TRANSFER
Transfer complete or error callback.
Definition: qm_ss_adc.h:90
qm_ss_adc_status_t
qm_ss_adc_status_t
SS ADC status.
Definition: qm_ss_adc.h:32
qm_ss_adc_resolution_t
qm_ss_adc_resolution_t
SS ADC resolution type.
Definition: qm_ss_adc.h:43
QM_SS_ADC_DIVSEQSTAT
ADC clock and sequencer status register.
Definition: qm_sensor_regs.h:543
QM_SS_ADC_RES_12_BITS
12-bit mode.
Definition: qm_ss_adc.h:47
qm_ss_adc_xfer_t::callback
void(* callback)(void *data, int error, qm_ss_adc_status_t status, qm_ss_adc_cb_source_t source)
Transfer callback.
Definition: qm_ss_adc.h:128
qm_ss_adc_irq_set_mode
int qm_ss_adc_irq_set_mode(const qm_ss_adc_t adc, const qm_ss_adc_mode_t mode, void(*callback)(void *data, int error, qm_ss_adc_status_t status, qm_ss_adc_cb_source_t source), void *callback_data)
Switch operating mode of SS ADC.
Definition: qm_ss_adc.c:405
qm_ss_adc_irq_convert
int qm_ss_adc_irq_convert(const qm_ss_adc_t adc, qm_ss_adc_xfer_t *xfer)
Asynchronously read values from the SS ADC.
Definition: qm_ss_adc.c:638
qm_ss_adc_set_mode
int qm_ss_adc_set_mode(const qm_ss_adc_t adc, const qm_ss_adc_mode_t mode)
Switch operating mode of SS ADC.
Definition: qm_ss_adc.c:361
QM_SS_ADC_MODE_NORM_NO_CAL
Normal mode, no calibration.
Definition: qm_ss_adc.h:58
qm_ss_adc_xfer_t::ch
qm_ss_adc_channel_t * ch
Channel sequence array (1-32 channels).
Definition: qm_ss_adc.h:112
QM_SS_ADC_MODE_CHANGED
Mode change complete callback.
Definition: qm_ss_adc.h:91
qm_ss_adc_mode_t
qm_ss_adc_mode_t
SS ADC operating mode type.
Definition: qm_ss_adc.h:53
qm_ss_adc_xfer_t::samples
qm_ss_adc_sample_t * samples
Array to store samples.
Definition: qm_ss_adc.h:114
qm_ss_adc_t
qm_ss_adc_t
Sensor Subsystem ADC.
Definition: qm_sensor_regs.h:551
QM_SS_ADC_COMPLETE
ADC data available.
Definition: qm_ss_adc.h:34
QM_SS_ADC_CTRL
ADC control register.
Definition: qm_sensor_regs.h:545
QM_SS_IO_CREG_SLV0_OBSR
Slave control register.
Definition: qm_sensor_regs.h:630
QM_SS_ADC_SET
ADC and sequencer settings register.
Definition: qm_sensor_regs.h:542
QM_SS_ADC_INTSTAT
ADC interrupt status register.
Definition: qm_sensor_regs.h:546
QM_SS_ADC_0
ADC first module.
Definition: qm_sensor_regs.h:552
QM_SS_ADC_SEQERROR
ADC sequencer error.
Definition: qm_ss_adc.h:37
QM_SS_ADC_OVERFLOW
ADC overflow error.
Definition: qm_ss_adc.h:35
qm_ss_adc_get_calibration
int qm_ss_adc_get_calibration(const qm_ss_adc_t adc, qm_ss_adc_calibration_t *const cal)
Get the current calibration data for an SS ADC.
qm_ss_adc_config_t::window
uint8_t window
Sample interval in ADC clock cycles, defines the period to wait between the start of each sample and ...
Definition: qm_ss_adc.h:104
QM_SS_ADC_SAMPLE
ADC sample register.
Definition: qm_sensor_regs.h:547
QM_ISR_DECLARE
QM_ISR_DECLARE(qm_ss_adc_0_isr)
ISR for ADC interrupt.
Definition: qm_ss_adc.c:197
qm_ss_adc_restore_context
int qm_ss_adc_restore_context(const qm_ss_adc_t adc, const qm_ss_adc_context_t *const ctx)
Restore SS ADC context.
Definition: qm_ss_adc.c:712
qm_ss_adc_config_t
SS ADC configuration type.
Definition: qm_ss_adc.h:98
QM_SS_IO_CREG_MST0_CTRL
Master control register.
Definition: qm_sensor_regs.h:629
qm_ss_adc_context_t
SS ADC context type.
Definition: qm_sensor_regs.h:564
QM_SS_ADC_UNDERFLOW
ADC underflow error.
Definition: qm_ss_adc.h:36
qm_ss_adc_context_t::adc_set
uint32_t adc_set
ADC settings.
Definition: qm_sensor_regs.h:565
qm_ss_adc_set_calibration
int qm_ss_adc_set_calibration(const qm_ss_adc_t adc, const qm_ss_adc_calibration_t cal)
Set SS ADC calibration data.
QM_SS_ADC_IDLE
ADC idle.
Definition: qm_ss_adc.h:33
qm_ss_adc_context_t::adc_seq
uint32_t adc_seq
ADC sequencer entry.
Definition: qm_sensor_regs.h:567
qm_ss_adc_save_context
int qm_ss_adc_save_context(const qm_ss_adc_t adc, qm_ss_adc_context_t *const ctx)
Save SS ADC context.
Definition: qm_ss_adc.c:685
qm_ss_adc_irq_calibrate
int qm_ss_adc_irq_calibrate(const qm_ss_adc_t adc, void(*callback)(void *data, int error, qm_ss_adc_status_t status, qm_ss_adc_cb_source_t source), void *callback_data)
Calibrate the SS ADC.
Definition: qm_ss_adc.c:479
qm_ss_adc_xfer_t
SS ADC transfer type.
Definition: qm_ss_adc.h:111
qm_ss_adc_xfer_t::ch_len
uint8_t ch_len
Number of channels in the above array.
Definition: qm_ss_adc.h:113
qm_ss_adc_calibrate
int qm_ss_adc_calibrate(const qm_ss_adc_t adc)
Calibrate the SS ADC.
QM_SS_ADC_MODE_NORM_CAL
Normal mode, with calibration.
Definition: qm_ss_adc.h:57
qm_ss_adc_set_config
int qm_ss_adc_set_config(const qm_ss_adc_t adc, const qm_ss_adc_config_t *const cfg)
Set SS ADC configuration.
Definition: qm_ss_adc.c:335
qm_ss_adc_context_t::adc_divseqstat
uint32_t adc_divseqstat
ADC clock divider and sequencer status.
Definition: qm_sensor_regs.h:566
qm_ss_adc_config_t::resolution
qm_ss_adc_resolution_t resolution
12, 10, 8, 6-bit resolution.
Definition: qm_ss_adc.h:105
qm_ss_adc_calibration_t
uint8_t qm_ss_adc_calibration_t
SS ADC calibration type.
Definition: qm_ss_adc.h:27