Intel® Quark™ Microcontroller Software Interface  1.4.0
Intel® Quark™ Microcontroller BSP
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,
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,
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,
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,
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,
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,
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 
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 
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 
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 
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 
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 
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)
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 
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 
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 */
uint32_t samples_len
Length of sample array.
Definition: qm_ss_adc.h:115
ADC sequence entry register.
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
Calibration complete callback.
Definition: qm_ss_adc.h:92
qm_ss_adc_cb_source_t
SS ADC interrupt callback source.
Definition: qm_ss_adc.h:89
uint32_t adc_ctrl
ADC control.
Transfer complete or error callback.
Definition: qm_ss_adc.h:90
qm_ss_adc_status_t
SS ADC status.
Definition: qm_ss_adc.h:32
qm_ss_adc_resolution_t
SS ADC resolution type.
Definition: qm_ss_adc.h:43
ADC clock and sequencer status register.
12-bit mode.
Definition: qm_ss_adc.h:47
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
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
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
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
Normal mode, no calibration.
Definition: qm_ss_adc.h:58
qm_ss_adc_channel_t * ch
Channel sequence array (1-32 channels).
Definition: qm_ss_adc.h:112
Mode change complete callback.
Definition: qm_ss_adc.h:91
qm_ss_adc_mode_t
SS ADC operating mode type.
Definition: qm_ss_adc.h:53
qm_ss_adc_sample_t * samples
Array to store samples.
Definition: qm_ss_adc.h:114
qm_ss_adc_t
Sensor Subsystem ADC.
ADC data available.
Definition: qm_ss_adc.h:34
ADC control register.
Slave control register.
ADC and sequencer settings register.
ADC interrupt status register.
ADC first module.
ADC sequencer error.
Definition: qm_ss_adc.h:37
ADC overflow error.
Definition: qm_ss_adc.h:35
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.
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
ADC sample register.
QM_ISR_DECLARE(qm_ss_adc_0_isr)
ISR for ADC interrupt.
Definition: qm_ss_adc.c:197
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
SS ADC configuration type.
Definition: qm_ss_adc.h:98
Master control register.
SS ADC context type.
ADC underflow error.
Definition: qm_ss_adc.h:36
uint32_t adc_set
ADC settings.
int qm_ss_adc_set_calibration(const qm_ss_adc_t adc, const qm_ss_adc_calibration_t cal)
Set SS ADC calibration data.
ADC idle.
Definition: qm_ss_adc.h:33
uint32_t adc_seq
ADC sequencer entry.
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
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
SS ADC transfer type.
Definition: qm_ss_adc.h:111
uint8_t ch_len
Number of channels in the above array.
Definition: qm_ss_adc.h:113
int qm_ss_adc_calibrate(const qm_ss_adc_t adc)
Calibrate the SS ADC.
Normal mode, with calibration.
Definition: qm_ss_adc.h:57
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
uint32_t adc_divseqstat
ADC clock divider and sequencer status.
qm_ss_adc_resolution_t resolution
12, 10, 8, 6-bit resolution.
Definition: qm_ss_adc.h:105
uint8_t qm_ss_adc_calibration_t
SS ADC calibration type.
Definition: qm_ss_adc.h:27