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