Software APIs
dif_adc_ctrl.c
1 // Copyright lowRISC contributors (OpenTitan project).
2 // Licensed under the Apache License, Version 2.0, see LICENSE for details.
3 // SPDX-License-Identifier: Apache-2.0
4 
6 
7 #include <assert.h>
8 
13 
14 #include "adc_ctrl_regs.h" // Generated.
15 
16 static_assert(ADC_CTRL_PARAM_NUM_ADC_CHANNEL == 2,
17  "Expected two ADC Controller channels.");
18 static_assert(ADC_CTRL_PARAM_NUM_ADC_FILTER == 8,
19  "Expected eight ADC Controller filters.");
20 static_assert(ADC_CTRL_ADC_CHN0_FILTER_CTL_MIN_V_FIELD_WIDTH == 10,
21  "Expected channel-0 filter min-voltage field to be 10 bits.");
22 static_assert(ADC_CTRL_ADC_CHN1_FILTER_CTL_MIN_V_FIELD_WIDTH == 10,
23  "Expected channel-1 filter min-voltage field to be 10 bits.");
24 static_assert(ADC_CTRL_ADC_CHN0_FILTER_CTL_MAX_V_FIELD_WIDTH == 10,
25  "Expected channel-0 filter max-voltage field to be 10 bits.");
26 static_assert(ADC_CTRL_ADC_CHN1_FILTER_CTL_MAX_V_FIELD_WIDTH == 10,
27  "Expected channel-1 filter max-voltage field to be 10 bits.");
28 
30  dif_adc_ctrl_config_t config) {
31  if (adc_ctrl == NULL ||
32  config.power_up_time_aon_cycles > ADC_CTRL_ADC_PD_CTL_PWRUP_TIME_MASK ||
33  config.wake_up_time_aon_cycles > ADC_CTRL_ADC_PD_CTL_WAKEUP_TIME_MASK ||
34  config.num_low_power_samples == 0 ||
35  config.num_normal_power_samples == 0) {
36  return kDifBadArg;
37  }
38 
39  uint32_t en_ctrl_reg = ADC_CTRL_ADC_EN_CTL_REG_RESVAL;
40  uint32_t pd_ctrl_reg = ADC_CTRL_ADC_PD_CTL_REG_RESVAL;
41  uint32_t lp_sample_ctrl_reg = ADC_CTRL_ADC_LP_SAMPLE_CTL_REG_RESVAL;
42  uint32_t np_sample_ctrl_reg = ADC_CTRL_ADC_SAMPLE_CTL_REG_RESVAL;
43 
44  switch (config.mode) {
46  pd_ctrl_reg = bitfield_bit32_write(pd_ctrl_reg,
47  ADC_CTRL_ADC_PD_CTL_LP_MODE_BIT, true);
48  pd_ctrl_reg = bitfield_field32_write(
49  pd_ctrl_reg, ADC_CTRL_ADC_PD_CTL_WAKEUP_TIME_FIELD,
51  lp_sample_ctrl_reg = bitfield_field32_write(
52  lp_sample_ctrl_reg, ADC_CTRL_ADC_LP_SAMPLE_CTL_LP_SAMPLE_CNT_FIELD,
53  config.num_low_power_samples);
56  np_sample_ctrl_reg = bitfield_field32_write(
57  np_sample_ctrl_reg, ADC_CTRL_ADC_SAMPLE_CTL_NP_SAMPLE_CNT_FIELD,
59  break;
61  en_ctrl_reg = bitfield_bit32_write(
62  en_ctrl_reg, ADC_CTRL_ADC_EN_CTL_ONESHOT_MODE_BIT, true);
63  break;
64  default:
65  return kDifBadArg;
66  }
67 
68  // Regardless of the mode, the ADC could be powered down, so we need to set
69  // the power-up time.
70  pd_ctrl_reg =
71  bitfield_field32_write(pd_ctrl_reg, ADC_CTRL_ADC_PD_CTL_PWRUP_TIME_FIELD,
73  mmio_region_write32(adc_ctrl->base_addr, ADC_CTRL_ADC_EN_CTL_REG_OFFSET,
74  en_ctrl_reg);
75  mmio_region_write32(adc_ctrl->base_addr, ADC_CTRL_ADC_PD_CTL_REG_OFFSET,
76  pd_ctrl_reg);
77  mmio_region_write32(adc_ctrl->base_addr,
78  ADC_CTRL_ADC_LP_SAMPLE_CTL_REG_OFFSET,
79  lp_sample_ctrl_reg);
80  mmio_region_write32(adc_ctrl->base_addr, ADC_CTRL_ADC_SAMPLE_CTL_REG_OFFSET,
81  np_sample_ctrl_reg);
82 
83  return kDifOk;
84 }
85 
87  dif_adc_ctrl_channel_t channel,
89  dif_toggle_t enabled) {
90  if (adc_ctrl == NULL || config.min_voltage > 1023 ||
91  config.max_voltage > 1023) {
92  return kDifBadArg;
93  }
94 
95  ptrdiff_t filter_ctrl_reg_offset;
96  bitfield_field32_t min_voltage_field;
97  bitfield_field32_t max_voltage_field;
98  bitfield_bit32_index_t in_range_bit;
99  bitfield_bit32_index_t enable_bit;
100 
101 #define DIF_ADC_CTRL_CHANNEL0_FILTER_CONFIG_CASE_(filter_) \
102  case kDifAdcCtrlFilter##filter_: \
103  filter_ctrl_reg_offset = \
104  ADC_CTRL_ADC_CHN0_FILTER_CTL_##filter_##_REG_OFFSET; \
105  min_voltage_field = \
106  ADC_CTRL_ADC_CHN0_FILTER_CTL_##filter_##_MIN_V_##filter_##_FIELD; \
107  max_voltage_field = \
108  ADC_CTRL_ADC_CHN0_FILTER_CTL_##filter_##_MAX_V_##filter_##_FIELD; \
109  in_range_bit = \
110  ADC_CTRL_ADC_CHN0_FILTER_CTL_##filter_##_COND_##filter_##_BIT; \
111  enable_bit = ADC_CTRL_ADC_CHN0_FILTER_CTL_##filter_##_EN_##filter_##_BIT; \
112  break;
113 
114 #define DIF_ADC_CTRL_CHANNEL1_FILTER_CONFIG_CASE_(filter_) \
115  case kDifAdcCtrlFilter##filter_: \
116  filter_ctrl_reg_offset = \
117  ADC_CTRL_ADC_CHN1_FILTER_CTL_##filter_##_REG_OFFSET; \
118  min_voltage_field = \
119  ADC_CTRL_ADC_CHN1_FILTER_CTL_##filter_##_MIN_V_##filter_##_FIELD; \
120  max_voltage_field = \
121  ADC_CTRL_ADC_CHN1_FILTER_CTL_##filter_##_MAX_V_##filter_##_FIELD; \
122  in_range_bit = \
123  ADC_CTRL_ADC_CHN1_FILTER_CTL_##filter_##_COND_##filter_##_BIT; \
124  enable_bit = ADC_CTRL_ADC_CHN1_FILTER_CTL_##filter_##_EN_##filter_##_BIT; \
125  break;
126 
127  switch (channel) {
128  case kDifAdcCtrlChannel0:
129  switch (config.filter) {
130  DIF_ADC_CTRL_FILTER_LIST(DIF_ADC_CTRL_CHANNEL0_FILTER_CONFIG_CASE_)
131  default:
132  return kDifBadArg;
133  }
134  break;
135  case kDifAdcCtrlChannel1:
136  switch (config.filter) {
137  DIF_ADC_CTRL_FILTER_LIST(DIF_ADC_CTRL_CHANNEL1_FILTER_CONFIG_CASE_)
138  default:
139  return kDifBadArg;
140  }
141  break;
142  default:
143  return kDifBadArg;
144  }
145 
146 #undef DIF_ADC_CTRL_CHANNEL0_FILTER_CONFIG_CASE_
147 #undef DIF_ADC_CTRL_CHANNEL1_FILTER_CONFIG_CASE_
148 
149  // Configure filter control register.
150  uint32_t filter_ctrl_reg =
151  bitfield_field32_write(0, min_voltage_field, config.min_voltage);
152  filter_ctrl_reg = bitfield_field32_write(filter_ctrl_reg, max_voltage_field,
153  config.max_voltage);
154  filter_ctrl_reg =
155  bitfield_bit32_write(filter_ctrl_reg, in_range_bit, !config.in_range);
156  filter_ctrl_reg = bitfield_bit32_write(filter_ctrl_reg, enable_bit,
157  dif_toggle_to_bool(enabled));
158  mmio_region_write32(adc_ctrl->base_addr, filter_ctrl_reg_offset,
159  filter_ctrl_reg);
160 
161  // Configure wakeup control register.
162  uint32_t wakeup_ctrl_reg = mmio_region_read32(
163  adc_ctrl->base_addr, ADC_CTRL_ADC_WAKEUP_CTL_REG_OFFSET);
164  wakeup_ctrl_reg = bitfield_bit32_write(wakeup_ctrl_reg, config.filter,
165  config.generate_wakeup_on_match);
166  mmio_region_write32(adc_ctrl->base_addr, ADC_CTRL_ADC_WAKEUP_CTL_REG_OFFSET,
167  wakeup_ctrl_reg);
168 
169  // Configure interrupt control register.
170  uint32_t intr_ctrl_reg =
171  mmio_region_read32(adc_ctrl->base_addr, ADC_CTRL_ADC_INTR_CTL_REG_OFFSET);
172  intr_ctrl_reg = bitfield_bit32_write(intr_ctrl_reg, config.filter,
173  config.generate_irq_on_match);
174  mmio_region_write32(adc_ctrl->base_addr, ADC_CTRL_ADC_INTR_CTL_REG_OFFSET,
175  intr_ctrl_reg);
176 
177  return kDifOk;
178 }
179 
181  dif_toggle_t enabled) {
182  if (adc_ctrl == NULL || !dif_is_valid_toggle(enabled)) {
183  return kDifBadArg;
184  }
185 
186  uint32_t en_ctrl_reg =
187  mmio_region_read32(adc_ctrl->base_addr, ADC_CTRL_ADC_EN_CTL_REG_OFFSET);
188  en_ctrl_reg =
189  bitfield_bit32_write(en_ctrl_reg, ADC_CTRL_ADC_EN_CTL_ADC_ENABLE_BIT,
190  dif_toggle_to_bool(enabled));
191  mmio_region_write32(adc_ctrl->base_addr, ADC_CTRL_ADC_EN_CTL_REG_OFFSET,
192  en_ctrl_reg);
193 
194  return kDifOk;
195 }
196 
198  dif_toggle_t *is_enabled) {
199  if (adc_ctrl == NULL || is_enabled == NULL) {
200  return kDifBadArg;
201  }
202 
203  uint32_t en_ctrl_reg =
204  mmio_region_read32(adc_ctrl->base_addr, ADC_CTRL_ADC_EN_CTL_REG_OFFSET);
205  *is_enabled = dif_bool_to_toggle(
206  bitfield_bit32_read(en_ctrl_reg, ADC_CTRL_ADC_EN_CTL_ADC_ENABLE_BIT));
207 
208  return kDifOk;
209 }
210 
211 static bool get_filter_offset(dif_adc_ctrl_channel_t channel,
212  dif_adc_ctrl_filter_t filter,
213  ptrdiff_t *filter_ctrl_reg_offset) {
214 #define DIF_ADC_CTRL_CHANNEL0_FILTER_CTRL_REG_CASE_(filter_) \
215  case kDifAdcCtrlFilter##filter_: \
216  *filter_ctrl_reg_offset = \
217  ADC_CTRL_ADC_CHN0_FILTER_CTL_##filter_##_REG_OFFSET; \
218  break;
219 
220 #define DIF_ADC_CTRL_CHANNEL1_FILTER_CTRL_REG_CASE_(filter_) \
221  case kDifAdcCtrlFilter##filter_: \
222  *filter_ctrl_reg_offset = \
223  ADC_CTRL_ADC_CHN1_FILTER_CTL_##filter_##_REG_OFFSET; \
224  break;
225 
226  switch (channel) {
227  case kDifAdcCtrlChannel0:
228  switch (filter) {
229  DIF_ADC_CTRL_FILTER_LIST(DIF_ADC_CTRL_CHANNEL0_FILTER_CTRL_REG_CASE_)
230  default:
231  return false;
232  }
233  break;
234  case kDifAdcCtrlChannel1:
235  switch (filter) {
236  DIF_ADC_CTRL_FILTER_LIST(DIF_ADC_CTRL_CHANNEL1_FILTER_CTRL_REG_CASE_)
237  default:
238  return false;
239  }
240  break;
241  default:
242  return false;
243  }
244 
245 #undef DIF_ADC_CTRL_CHANNEL0_FILTER_CTRL_REG_CASE_
246 #undef DIF_ADC_CTRL_CHANNEL1_FILTER_CTRL_REG_CASE_
247 
248  return true;
249 }
250 
251 static bool get_filter_enable_bit(dif_adc_ctrl_channel_t channel,
252  dif_adc_ctrl_filter_t filter,
253  bitfield_bit32_index_t *enable_bit) {
254 #define DIF_ADC_CTRL_CHANNEL0_FILTER_ENABLE_CASE_(filter_) \
255  case kDifAdcCtrlFilter##filter_: \
256  *enable_bit = ADC_CTRL_ADC_CHN0_FILTER_CTL_##filter_##_EN_##filter_##_BIT; \
257  break;
258 
259 #define DIF_ADC_CTRL_CHANNEL1_FILTER_ENABLE_CASE_(filter_) \
260  case kDifAdcCtrlFilter##filter_: \
261  *enable_bit = ADC_CTRL_ADC_CHN1_FILTER_CTL_##filter_##_EN_##filter_##_BIT; \
262  break;
263 
264  switch (channel) {
265  case kDifAdcCtrlChannel0:
266  switch (filter) {
267  DIF_ADC_CTRL_FILTER_LIST(DIF_ADC_CTRL_CHANNEL0_FILTER_ENABLE_CASE_)
268  default:
269  return false;
270  }
271  break;
272  case kDifAdcCtrlChannel1:
273  switch (filter) {
274  DIF_ADC_CTRL_FILTER_LIST(DIF_ADC_CTRL_CHANNEL1_FILTER_ENABLE_CASE_)
275  default:
276  return false;
277  }
278  break;
279  default:
280  return false;
281  }
282 
283 #undef DIF_ADC_CTRL_CHANNEL0_FILTER_ENABLE_CASE_
284 #undef DIF_ADC_CTRL_CHANNEL1_FILTER_ENABLE_CASE_
285 
286  return true;
287 }
288 
290  dif_adc_ctrl_channel_t channel,
291  dif_adc_ctrl_filter_t filter,
292  dif_toggle_t enabled) {
293  if (adc_ctrl == NULL || !dif_is_valid_toggle(enabled)) {
294  return kDifBadArg;
295  }
296 
297  ptrdiff_t filter_ctrl_reg_offset;
298  bitfield_bit32_index_t enable_bit;
299  if (!get_filter_offset(channel, filter, &filter_ctrl_reg_offset)) {
300  return kDifBadArg;
301  }
302  if (!get_filter_enable_bit(channel, filter, &enable_bit)) {
303  return kDifBadArg;
304  }
305 
306  uint32_t filter_ctrl_reg =
307  mmio_region_read32(adc_ctrl->base_addr, filter_ctrl_reg_offset);
308  filter_ctrl_reg = bitfield_bit32_write(filter_ctrl_reg, enable_bit,
309  dif_toggle_to_bool(enabled));
310  mmio_region_write32(adc_ctrl->base_addr, filter_ctrl_reg_offset,
311  filter_ctrl_reg);
312 
313  return kDifOk;
314 }
315 
317  dif_adc_ctrl_channel_t channel,
318  dif_adc_ctrl_filter_t filter,
319  dif_toggle_t *is_enabled) {
320  if (adc_ctrl == NULL || is_enabled == NULL) {
321  return kDifBadArg;
322  }
323 
324  ptrdiff_t filter_ctrl_reg_offset;
325  bitfield_bit32_index_t enable_bit;
326  if (!get_filter_offset(channel, filter, &filter_ctrl_reg_offset)) {
327  return kDifBadArg;
328  }
329  if (!get_filter_enable_bit(channel, filter, &enable_bit)) {
330  return kDifBadArg;
331  }
332 
333  uint32_t filter_ctrl_reg =
334  mmio_region_read32(adc_ctrl->base_addr, filter_ctrl_reg_offset);
335  *is_enabled =
336  dif_bool_to_toggle(bitfield_bit32_read(filter_ctrl_reg, enable_bit));
337 
338  return kDifOk;
339 }
340 
342  dif_adc_ctrl_channel_t channel,
343  uint16_t *value) {
344  if (adc_ctrl == NULL || value == NULL) {
345  return kDifBadArg;
346  }
347 
348  uint32_t value_reg;
349 
350 #define DIF_ADC_CTRL_CHANNEL_TRIG_VALUE_CASE_(channel_) \
351  case kDifAdcCtrlChannel##channel_: \
352  value_reg = mmio_region_read32( \
353  adc_ctrl->base_addr, ADC_CTRL_ADC_CHN_VAL_##channel_##_REG_OFFSET); \
354  *value = (uint16_t)bitfield_field32_read( \
355  value_reg, \
356  ADC_CTRL_ADC_CHN_VAL_##channel_##_ADC_CHN_VALUE_INTR_##channel_##_FIELD); \
357  break;
358 
359  switch (channel) {
360  DIF_ADC_CTRL_CHANNEL_LIST(DIF_ADC_CTRL_CHANNEL_TRIG_VALUE_CASE_)
361  default:
362  return kDifBadArg;
363  }
364 
365 #undef DIF_ADC_CTRL_CHANNEL_TRIG_VALUE_CASE_
366 
367  return kDifOk;
368 }
369 
371  dif_adc_ctrl_channel_t channel,
372  uint16_t *value) {
373  if (adc_ctrl == NULL || value == NULL) {
374  return kDifBadArg;
375  }
376 
377  uint32_t value_reg;
378 
379 #define DIF_ADC_CTRL_CHANNEL_LATEST_VALUE_CASE_(channel_) \
380  case kDifAdcCtrlChannel##channel_: \
381  value_reg = mmio_region_read32( \
382  adc_ctrl->base_addr, ADC_CTRL_ADC_CHN_VAL_##channel_##_REG_OFFSET); \
383  *value = (uint16_t)bitfield_field32_read( \
384  value_reg, \
385  ADC_CTRL_ADC_CHN_VAL_##channel_##_ADC_CHN_VALUE_##channel_##_FIELD); \
386  break;
387 
388  switch (channel) {
389  DIF_ADC_CTRL_CHANNEL_LIST(DIF_ADC_CTRL_CHANNEL_LATEST_VALUE_CASE_)
390  default:
391  return kDifBadArg;
392  }
393 
394 #undef DIF_ADC_CTRL_CHANNEL_LATEST_VALUE_CASE_
395 
396  return kDifOk;
397 }
398 
400  if (adc_ctrl == NULL) {
401  return kDifBadArg;
402  }
403 
404  mmio_region_write32(adc_ctrl->base_addr, ADC_CTRL_ADC_FSM_RST_REG_OFFSET, 1);
405  mmio_region_write32(adc_ctrl->base_addr, ADC_CTRL_ADC_FSM_RST_REG_OFFSET, 0);
406 
407  return kDifOk;
408 }
409 
411  uint32_t *causes) {
412  if (adc_ctrl == NULL || causes == NULL) {
413  return kDifBadArg;
414  }
415 
416  *causes = mmio_region_read32(adc_ctrl->base_addr,
417  ADC_CTRL_ADC_INTR_STATUS_REG_OFFSET);
418 
419  return kDifOk;
420 }
421 
423  uint32_t *status) {
424  if (adc_ctrl == NULL || status == NULL) {
425  return kDifBadArg;
426  }
427 
428  *status = mmio_region_read32(adc_ctrl->base_addr,
429  ADC_CTRL_FILTER_STATUS_REG_OFFSET);
430  return kDifOk;
431 }
432 
434  uint32_t causes) {
435  if (adc_ctrl == NULL || causes > kDifAdcCtrlIrqCauseAll) {
436  return kDifBadArg;
437  }
438 
439  uint32_t filter_causes = (~(uint32_t)kDifAdcCtrlIrqCauseOneshot) & causes;
440  if (filter_causes) {
441  mmio_region_write32(adc_ctrl->base_addr, ADC_CTRL_FILTER_STATUS_REG_OFFSET,
442  filter_causes);
443  }
444 
445  mmio_region_write32(adc_ctrl->base_addr, ADC_CTRL_ADC_INTR_STATUS_REG_OFFSET,
446  causes);
447 
448  return kDifOk;
449 }
450 
452  const dif_adc_ctrl_t *adc_ctrl, dif_adc_ctrl_filter_t filter,
453  dif_toggle_t enabled) {
454  if (adc_ctrl == NULL || filter >= (ADC_CTRL_PARAM_NUM_ADC_FILTER + 1) ||
455  !dif_is_valid_toggle(enabled)) {
456  return kDifBadArg;
457  }
458 
459  uint32_t wakeup_ctrl_reg = mmio_region_read32(
460  adc_ctrl->base_addr, ADC_CTRL_ADC_WAKEUP_CTL_REG_OFFSET);
461  wakeup_ctrl_reg = bitfield_bit32_write(wakeup_ctrl_reg, filter,
462  dif_toggle_to_bool(enabled));
463  mmio_region_write32(adc_ctrl->base_addr, ADC_CTRL_ADC_WAKEUP_CTL_REG_OFFSET,
464  wakeup_ctrl_reg);
465 
466  return kDifOk;
467 }
468 
470  const dif_adc_ctrl_t *adc_ctrl, dif_adc_ctrl_filter_t filter,
471  dif_toggle_t *is_enabled) {
472  if (adc_ctrl == NULL || filter >= (ADC_CTRL_PARAM_NUM_ADC_FILTER + 1) ||
473  is_enabled == NULL) {
474  return kDifBadArg;
475  }
476 
477  uint32_t wakeup_ctrl_reg = mmio_region_read32(
478  adc_ctrl->base_addr, ADC_CTRL_ADC_WAKEUP_CTL_REG_OFFSET);
479  *is_enabled =
480  dif_bool_to_toggle(bitfield_bit32_read(wakeup_ctrl_reg, filter));
481 
482  return kDifOk;
483 }
484 
486  uint32_t causes,
487  dif_toggle_t enabled) {
488  if (adc_ctrl == NULL || causes > kDifAdcCtrlIrqCauseAll ||
489  !dif_is_valid_toggle(enabled)) {
490  return kDifBadArg;
491  }
492 
493  uint32_t enabled_causes =
494  mmio_region_read32(adc_ctrl->base_addr, ADC_CTRL_ADC_INTR_CTL_REG_OFFSET);
495  if (enabled == kDifToggleDisabled) {
496  enabled_causes &= ~causes;
497  } else {
498  enabled_causes |= causes;
499  }
500  mmio_region_write32(adc_ctrl->base_addr, ADC_CTRL_ADC_INTR_CTL_REG_OFFSET,
501  enabled_causes);
502 
503  return kDifOk;
504 }
505 
507  uint32_t *enabled_causes) {
508  if (adc_ctrl == NULL || enabled_causes == NULL) {
509  return kDifBadArg;
510  }
511 
512  *enabled_causes =
513  mmio_region_read32(adc_ctrl->base_addr, ADC_CTRL_ADC_INTR_CTL_REG_OFFSET);
514 
515  return kDifOk;
516 }
517 
519  uint32_t aon_freq_hz) {
520  if (adc_ctrl == NULL) {
521  return kDifBadArg;
522  }
523  // Wait 5 AON ticks.
524  busy_spin_micros(5 * 1000000 / aon_freq_hz);
525  return kDifOk;
526 }