Software APIs
dif_pinmux.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 
11 
12 #include "pinmux_regs.h" // Generated.
13 
14 static bool dif_pinmux_get_reg_offset(dif_pinmux_index_t index,
16  ptrdiff_t mio_reg_base,
17  ptrdiff_t dio_reg_base,
18  ptrdiff_t *reg_offset) {
19  uint32_t num_pads;
20  ptrdiff_t reg_base;
21 
22  switch (kind) {
24  num_pads = PINMUX_PARAM_N_MIO_PADS;
25  reg_base = mio_reg_base;
26  break;
28  num_pads = PINMUX_PARAM_N_DIO_PADS;
29  reg_base = dio_reg_base;
30  break;
31  default:
32  return false;
33  }
34  if (index >= num_pads) {
35  return false;
36  }
37  *reg_offset = reg_base + (ptrdiff_t)(index * sizeof(uint32_t));
38  return true;
39 }
40 
41 static bool dif_pinmux_get_sleep_status_bit(dif_pinmux_pad_kind_t kind,
42  dif_pinmux_index_t index,
43  ptrdiff_t *reg_offset,
45  uint32_t num_pads;
46  ptrdiff_t reg_base;
47 
48  switch (kind) {
50  num_pads = PINMUX_PARAM_N_MIO_PADS;
51  reg_base = PINMUX_MIO_PAD_SLEEP_STATUS_0_REG_OFFSET;
52  break;
54  num_pads = PINMUX_PARAM_N_DIO_PADS;
55  reg_base = PINMUX_DIO_PAD_SLEEP_STATUS_REG_OFFSET;
56  break;
57  default:
58  return false;
59  }
60  if (index >= num_pads) {
61  return false;
62  }
63  *reg_offset = (ptrdiff_t)index / 32 + reg_base;
64  *bit = index % 32;
65  return true;
66 }
67 
68 static bool dif_pinmux_get_lock_reg_offset(dif_pinmux_index_t index,
70  ptrdiff_t *reg_offset) {
71  ptrdiff_t reg_base;
72  size_t reg_count;
73  switch (target) {
75  reg_base = PINMUX_MIO_PERIPH_INSEL_REGWEN_0_REG_OFFSET;
76  reg_count = PINMUX_MIO_PERIPH_INSEL_REGWEN_MULTIREG_COUNT;
77  break;
79  reg_base = PINMUX_MIO_OUTSEL_REGWEN_0_REG_OFFSET;
80  reg_count = PINMUX_MIO_OUTSEL_REGWEN_MULTIREG_COUNT;
81  break;
83  reg_base = PINMUX_MIO_PAD_SLEEP_REGWEN_0_REG_OFFSET;
84  reg_count = PINMUX_MIO_PAD_SLEEP_REGWEN_MULTIREG_COUNT;
85  break;
87  reg_base = PINMUX_DIO_PAD_SLEEP_REGWEN_0_REG_OFFSET;
88  reg_count = PINMUX_DIO_PAD_SLEEP_REGWEN_MULTIREG_COUNT;
89  break;
91  reg_base = PINMUX_MIO_PAD_ATTR_REGWEN_0_REG_OFFSET;
92  reg_count = PINMUX_MIO_PAD_ATTR_REGWEN_MULTIREG_COUNT;
93  break;
95  reg_base = PINMUX_DIO_PAD_ATTR_REGWEN_0_REG_OFFSET;
96  reg_count = PINMUX_DIO_PAD_ATTR_REGWEN_MULTIREG_COUNT;
97  break;
99  reg_base = PINMUX_WKUP_DETECTOR_REGWEN_0_REG_OFFSET;
100  reg_count = PINMUX_WKUP_DETECTOR_REGWEN_MULTIREG_COUNT;
101  break;
102  default:
103  return false;
104  }
105 
106  if (index >= reg_count) {
107  return false;
108  }
109 
110  *reg_offset = reg_base + (ptrdiff_t)index * (ptrdiff_t)sizeof(uint32_t);
111  return true;
112 }
113 
115  dif_pinmux_index_t index,
116  dif_pinmux_lock_target_t target) {
117  if (pinmux == NULL) {
118  return kDifBadArg;
119  }
120 
121  ptrdiff_t reg_offset;
122  if (!dif_pinmux_get_lock_reg_offset(index, target, &reg_offset)) {
123  return kDifBadArg;
124  }
125  mmio_region_write32(pinmux->base_addr, reg_offset, /*value=*/0);
126  return kDifOk;
127 }
128 
130  dif_pinmux_index_t index,
132  bool *is_locked) {
133  if (pinmux == NULL || is_locked == NULL) {
134  return kDifBadArg;
135  }
136 
137  ptrdiff_t reg_offset;
138  if (!dif_pinmux_get_lock_reg_offset(index, target, &reg_offset)) {
139  return kDifBadArg;
140  }
141 
142  uint32_t reg_value = mmio_region_read32(pinmux->base_addr, reg_offset);
143  *is_locked = !bitfield_bit32_read(reg_value,
144  PINMUX_MIO_PERIPH_INSEL_REGWEN_0_EN_0_BIT);
145  return kDifOk;
146 }
147 
149  dif_pinmux_index_t peripheral_input,
150  dif_pinmux_index_t insel) {
151  if (pinmux == NULL || peripheral_input >= PINMUX_PARAM_N_MIO_PERIPH_IN ||
152  insel >= (2 + PINMUX_PARAM_N_MIO_PADS)) {
153  return kDifBadArg;
154  }
155  bool is_locked;
157  pinmux, peripheral_input, kDifPinmuxLockTargetInsel, &is_locked);
158  if (result != kDifOk) {
159  return result;
160  }
161  if (is_locked) {
162  return kDifLocked;
163  }
164  ptrdiff_t reg_offset =
165  PINMUX_MIO_PERIPH_INSEL_0_REG_OFFSET + (ptrdiff_t)(peripheral_input << 2);
166  uint32_t reg_value =
167  bitfield_field32_write(0, PINMUX_MIO_PERIPH_INSEL_0_IN_0_FIELD, insel);
168  mmio_region_write32(pinmux->base_addr, reg_offset, reg_value);
169  return kDifOk;
170 }
171 
173  dif_pinmux_index_t mio_pad_output,
174  dif_pinmux_index_t outsel) {
175  if (pinmux == NULL || mio_pad_output >= PINMUX_PARAM_N_MIO_PADS ||
176  outsel >= (3 + PINMUX_PARAM_N_MIO_PERIPH_OUT)) {
177  return kDifBadArg;
178  }
179  bool is_locked;
181  pinmux, mio_pad_output, kDifPinmuxLockTargetOutsel, &is_locked);
182  if (result != kDifOk) {
183  return result;
184  }
185  if (is_locked) {
186  return kDifLocked;
187  }
188  ptrdiff_t reg_offset =
189  PINMUX_MIO_OUTSEL_0_REG_OFFSET + (ptrdiff_t)(mio_pad_output << 2);
190  uint32_t reg_value =
191  bitfield_field32_write(0, PINMUX_MIO_OUTSEL_0_OUT_0_FIELD, outsel);
192  mmio_region_write32(pinmux->base_addr, reg_offset, reg_value);
193  return kDifOk;
194 }
195 
196 static dif_pinmux_pad_attr_t dif_pinmux_reg_to_pad_attr(uint32_t reg_value) {
197  dif_pinmux_pad_attr_t pad_attrs = {0};
199  reg_value, PINMUX_MIO_PAD_ATTR_0_SLEW_RATE_0_FIELD);
200  pad_attrs.drive_strength =
202  reg_value, PINMUX_MIO_PAD_ATTR_0_DRIVE_STRENGTH_0_FIELD);
203  if (bitfield_bit32_read(reg_value, PINMUX_MIO_PAD_ATTR_0_INVERT_0_BIT)) {
204  pad_attrs.flags |= kDifPinmuxPadAttrInvertLevel;
205  }
206  if (bitfield_bit32_read(reg_value,
207  PINMUX_MIO_PAD_ATTR_0_VIRTUAL_OD_EN_0_BIT)) {
208  pad_attrs.flags |= kDifPinmuxPadAttrVirtualOpenDrain;
209  }
210  if (bitfield_bit32_read(reg_value, PINMUX_MIO_PAD_ATTR_0_PULL_EN_0_BIT)) {
211  pad_attrs.flags |= kDifPinmuxPadAttrPullResistorEnable;
212  }
213  if (bitfield_bit32_read(reg_value, PINMUX_MIO_PAD_ATTR_0_PULL_SELECT_0_BIT)) {
214  pad_attrs.flags |= kDifPinmuxPadAttrPullResistorUp;
215  }
216  if (bitfield_bit32_read(reg_value, PINMUX_MIO_PAD_ATTR_0_KEEPER_EN_0_BIT)) {
217  pad_attrs.flags |= kDifPinmuxPadAttrKeeper;
218  }
219  if (bitfield_bit32_read(reg_value, PINMUX_MIO_PAD_ATTR_0_SCHMITT_EN_0_BIT)) {
220  pad_attrs.flags |= kDifPinmuxPadAttrSchmittTrigger;
221  }
222  if (bitfield_bit32_read(reg_value, PINMUX_MIO_PAD_ATTR_0_OD_EN_0_BIT)) {
223  pad_attrs.flags |= kDifPinmuxPadAttrOpenDrain;
224  }
225  if (bitfield_bit32_read(reg_value,
226  PINMUX_MIO_PAD_ATTR_0_INPUT_DISABLE_0_BIT)) {
227  pad_attrs.flags |= kDifPinmuxPadAttrInputDisable;
228  }
229  return pad_attrs;
230 }
231 
232 enum { kDifPinmuxPadAttrSpinWaitMicros = 5 };
233 
235  dif_pinmux_index_t pad,
237  dif_pinmux_pad_attr_t attrs_in,
238  dif_pinmux_pad_attr_t *attrs_out) {
239  if (pinmux == NULL || attrs_out == NULL) {
240  return kDifBadArg;
241  }
242  if (attrs_in.drive_strength > PINMUX_MIO_PAD_ATTR_0_DRIVE_STRENGTH_0_MASK ||
243  attrs_in.slew_rate > PINMUX_MIO_PAD_ATTR_0_SLEW_RATE_0_MASK) {
244  return kDifBadArg;
245  }
246  ptrdiff_t reg_offset;
247  if (!dif_pinmux_get_reg_offset(pad, type, PINMUX_MIO_PAD_ATTR_0_REG_OFFSET,
248  PINMUX_DIO_PAD_ATTR_0_REG_OFFSET,
249  &reg_offset)) {
250  return kDifBadArg;
251  }
252  const dif_pinmux_lock_target_t lock_target =
255  bool is_locked;
256  dif_result_t result =
257  dif_pinmux_is_locked(pinmux, pad, lock_target, &is_locked);
258  if (result != kDifOk) {
259  return result;
260  }
261  if (is_locked) {
262  return kDifLocked;
263  }
264 
265  uint32_t reg_before = mmio_region_read32(pinmux->base_addr, reg_offset);
266 
267  uint32_t reg_value = bitfield_field32_write(
268  0, PINMUX_MIO_PAD_ATTR_0_SLEW_RATE_0_FIELD, attrs_in.slew_rate);
269  reg_value = bitfield_field32_write(
270  reg_value, PINMUX_MIO_PAD_ATTR_0_DRIVE_STRENGTH_0_FIELD,
271  attrs_in.drive_strength);
272  reg_value =
273  bitfield_bit32_write(reg_value, PINMUX_MIO_PAD_ATTR_0_INVERT_0_BIT,
274  attrs_in.flags & kDifPinmuxPadAttrInvertLevel);
275  reg_value =
276  bitfield_bit32_write(reg_value, PINMUX_MIO_PAD_ATTR_0_VIRTUAL_OD_EN_0_BIT,
277  attrs_in.flags & kDifPinmuxPadAttrVirtualOpenDrain);
278  reg_value = bitfield_bit32_write(
279  reg_value, PINMUX_MIO_PAD_ATTR_0_PULL_EN_0_BIT,
280  attrs_in.flags & kDifPinmuxPadAttrPullResistorEnable);
281  reg_value =
282  bitfield_bit32_write(reg_value, PINMUX_MIO_PAD_ATTR_0_PULL_SELECT_0_BIT,
283  attrs_in.flags & kDifPinmuxPadAttrPullResistorUp);
284  reg_value =
285  bitfield_bit32_write(reg_value, PINMUX_MIO_PAD_ATTR_0_KEEPER_EN_0_BIT,
286  attrs_in.flags & kDifPinmuxPadAttrKeeper);
287  reg_value =
288  bitfield_bit32_write(reg_value, PINMUX_MIO_PAD_ATTR_0_SCHMITT_EN_0_BIT,
289  attrs_in.flags & kDifPinmuxPadAttrSchmittTrigger);
290  reg_value = bitfield_bit32_write(reg_value, PINMUX_MIO_PAD_ATTR_0_OD_EN_0_BIT,
291  attrs_in.flags & kDifPinmuxPadAttrOpenDrain);
292  reg_value =
293  bitfield_bit32_write(reg_value, PINMUX_MIO_PAD_ATTR_0_INPUT_DISABLE_0_BIT,
294  attrs_in.flags & kDifPinmuxPadAttrInputDisable);
295  mmio_region_write32(pinmux->base_addr, reg_offset, reg_value);
296 
297  // Wait for pull enable/disable changes to propagate to the physical pad.
298  dif_pinmux_pad_attr_t attrs_before = dif_pinmux_reg_to_pad_attr(reg_before);
299  if ((attrs_before.flags & kDifPinmuxPadAttrPullResistorEnable) !=
300  (attrs_in.flags & kDifPinmuxPadAttrPullResistorEnable)) {
301  busy_spin_micros(kDifPinmuxPadAttrSpinWaitMicros);
302  }
303 
304  uint32_t read_value = mmio_region_read32(pinmux->base_addr, reg_offset);
305  *attrs_out = dif_pinmux_reg_to_pad_attr(read_value);
306 
307  // Not all pads implement all attributes and not all target platforms support
308  // all attribute values. The underlying hardware registers implement Write-Any
309  // Read-Legal (WARL) semantics. If the specified attribute values are not
310  // supported by the hardware, return `kDifError`. The caller then needs to
311  // decide on how to resolve the situation. Unsupported attribute values can be
312  // identified by comparing `attrs_in` to `attrs_out`.
313  if (reg_value != read_value) {
314  return kDifError;
315  }
316  return kDifOk;
317 }
318 
320  dif_pinmux_index_t pad,
322  dif_pinmux_pad_attr_t *attrs) {
323  if (pinmux == NULL || attrs == NULL) {
324  return kDifBadArg;
325  }
326  ptrdiff_t reg_offset;
327  if (!dif_pinmux_get_reg_offset(pad, type, PINMUX_MIO_PAD_ATTR_0_REG_OFFSET,
328  PINMUX_DIO_PAD_ATTR_0_REG_OFFSET,
329  &reg_offset)) {
330  return kDifBadArg;
331  }
332  uint32_t reg_value = mmio_region_read32(pinmux->base_addr, reg_offset);
333  *attrs = dif_pinmux_reg_to_pad_attr(reg_value);
334  return kDifOk;
335 }
336 
338  dif_pinmux_index_t pad,
341  if (pinmux == NULL) {
342  return kDifBadArg;
343  }
344 
345  ptrdiff_t en_reg_offset, mode_reg_offset;
346  if (!dif_pinmux_get_reg_offset(
347  pad, type, PINMUX_MIO_PAD_SLEEP_EN_0_REG_OFFSET,
348  PINMUX_DIO_PAD_SLEEP_EN_0_REG_OFFSET, &en_reg_offset)) {
349  return kDifBadArg;
350  }
351  if (!dif_pinmux_get_reg_offset(
352  pad, type, PINMUX_MIO_PAD_SLEEP_MODE_0_REG_OFFSET,
353  PINMUX_DIO_PAD_SLEEP_MODE_0_REG_OFFSET, &mode_reg_offset)) {
354  return kDifBadArg;
355  }
356  const dif_pinmux_lock_target_t lock_target =
359  bool is_locked;
360  dif_result_t result =
361  dif_pinmux_is_locked(pinmux, pad, lock_target, &is_locked);
362  if (result != kDifOk) {
363  return result;
364  }
365  if (is_locked) {
366  return kDifLocked;
367  }
368 
369  // Sleep Mode Value
370  uint32_t reg_value;
371  switch (mode) {
373  reg_value = PINMUX_MIO_PAD_SLEEP_MODE_0_OUT_0_VALUE_TIE_LOW;
374  break;
376  reg_value = PINMUX_MIO_PAD_SLEEP_MODE_0_OUT_0_VALUE_TIE_HIGH;
377  break;
379  reg_value = PINMUX_MIO_PAD_SLEEP_MODE_0_OUT_0_VALUE_HIGH_Z;
380  break;
382  reg_value = PINMUX_MIO_PAD_SLEEP_MODE_0_OUT_0_VALUE_KEEP;
383  break;
384  default:
385  return kDifBadArg;
386  }
387  mmio_region_write32(pinmux->base_addr, mode_reg_offset, reg_value);
388 
389  // Sleep Mode Enable
390  reg_value = bitfield_bit32_write(0, PINMUX_MIO_PAD_SLEEP_EN_0_EN_0_BIT, 1);
391  mmio_region_write32(pinmux->base_addr, en_reg_offset, reg_value);
392  return kDifOk;
393 }
394 
396  dif_pinmux_index_t pad,
397  dif_pinmux_pad_kind_t type) {
398  if (pinmux == NULL) {
399  return kDifBadArg;
400  }
401 
402  ptrdiff_t en_reg_offset;
403  if (!dif_pinmux_get_reg_offset(
404  pad, type, PINMUX_MIO_PAD_SLEEP_EN_0_REG_OFFSET,
405  PINMUX_DIO_PAD_SLEEP_EN_0_REG_OFFSET, &en_reg_offset)) {
406  return kDifBadArg;
407  }
408 
409  const dif_pinmux_lock_target_t lock_target =
412  bool is_locked;
413  dif_result_t result =
414  dif_pinmux_is_locked(pinmux, pad, lock_target, &is_locked);
415  if (result != kDifOk) {
416  return result;
417  }
418  if (is_locked) {
419  return kDifLocked;
420  }
421 
422  mmio_region_write32(pinmux->base_addr, en_reg_offset, 0);
423  return kDifOk;
424 }
425 
427  dif_pinmux_index_t pad,
429  bool *in_sleep_mode) {
430  if (pinmux == NULL || in_sleep_mode == NULL) {
431  return kDifBadArg;
432  }
433 
434  ptrdiff_t reg_offset;
436  if (!dif_pinmux_get_sleep_status_bit(type, pad, &reg_offset, &bit)) {
437  return kDifBadArg;
438  }
439 
440  uint32_t reg_value = mmio_region_read32(pinmux->base_addr, reg_offset);
441  *in_sleep_mode = bitfield_bit32_read(reg_value, bit);
442  return kDifOk;
443 }
444 
446  dif_pinmux_index_t pad,
447  dif_pinmux_pad_kind_t type) {
448  if (pinmux == NULL) {
449  return kDifBadArg;
450  }
451 
452  ptrdiff_t reg_offset;
454  if (!dif_pinmux_get_sleep_status_bit(type, pad, &reg_offset, &bit)) {
455  return kDifBadArg;
456  }
457 
458  uint32_t reg_value = mmio_region_read32(pinmux->base_addr, reg_offset);
459  reg_value = bitfield_bit32_write(reg_value, bit, 0);
460  mmio_region_write32(pinmux->base_addr, reg_offset, reg_value);
461  return kDifOk;
462 }
463 
465  const dif_pinmux_t *pinmux, dif_pinmux_index_t detector,
467  // Disable the detector before changing config, and use that function for
468  // some input checking (null pointer, lock status, and detector validity
469  // checks).
470  dif_result_t result = dif_pinmux_wakeup_detector_disable(pinmux, detector);
471  if (result != kDifOk) {
472  return result;
473  }
474 
475  bool set_count = false;
476  uint32_t reg_mode_value;
477  switch (config.mode) {
479  reg_mode_value = PINMUX_WKUP_DETECTOR_0_MODE_0_VALUE_POSEDGE;
480  break;
482  reg_mode_value = PINMUX_WKUP_DETECTOR_0_MODE_0_VALUE_NEGEDGE;
483  break;
485  reg_mode_value = PINMUX_WKUP_DETECTOR_0_MODE_0_VALUE_EDGE;
486  break;
488  set_count = true;
489  reg_mode_value = PINMUX_WKUP_DETECTOR_0_MODE_0_VALUE_TIMEDHIGH;
490  break;
492  set_count = true;
493  reg_mode_value = PINMUX_WKUP_DETECTOR_0_MODE_0_VALUE_TIMEDLOW;
494  break;
495  default:
496  return kDifBadArg;
497  }
498 
499  bool reg_filter_value = dif_toggle_to_bool(config.signal_filter);
500  if (!dif_is_valid_toggle(config.signal_filter)) {
501  return kDifBadArg;
502  }
503 
504  bool reg_miodio_value;
505  switch (config.pad_type) {
507  if (config.pad_select >= (2 + PINMUX_PARAM_N_MIO_PADS)) {
508  return kDifBadArg;
509  }
510  reg_miodio_value = false;
511  break;
513  if (config.pad_select >= PINMUX_PARAM_N_DIO_PADS) {
514  return kDifBadArg;
515  }
516  reg_miodio_value = true;
517  break;
518  default:
519  return kDifBadArg;
520  }
521 
522  ptrdiff_t reg_offset = PINMUX_WKUP_DETECTOR_0_REG_OFFSET +
523  (ptrdiff_t)detector * (ptrdiff_t)sizeof(uint32_t);
524  uint32_t reg_value = bitfield_field32_write(
525  0, PINMUX_WKUP_DETECTOR_0_MODE_0_FIELD, reg_mode_value);
526  reg_value = bitfield_bit32_write(
527  reg_value, PINMUX_WKUP_DETECTOR_0_FILTER_0_BIT, reg_filter_value);
528  reg_value = bitfield_bit32_write(
529  reg_value, PINMUX_WKUP_DETECTOR_0_MIODIO_0_BIT, reg_miodio_value);
530  mmio_region_write32(pinmux->base_addr, reg_offset, reg_value);
531 
532  if (set_count) {
533  reg_offset = PINMUX_WKUP_DETECTOR_CNT_TH_0_REG_OFFSET +
534  (ptrdiff_t)detector * (ptrdiff_t)sizeof(uint32_t);
535  reg_value = bitfield_field32_write(
536  0, PINMUX_WKUP_DETECTOR_CNT_TH_0_TH_0_FIELD, config.counter_threshold);
537  mmio_region_write32(pinmux->base_addr, reg_offset, reg_value);
538  }
539 
540  reg_offset = PINMUX_WKUP_DETECTOR_PADSEL_0_REG_OFFSET +
541  (ptrdiff_t)detector * (ptrdiff_t)sizeof(uint32_t);
542  reg_value = bitfield_field32_write(
543  0, PINMUX_WKUP_DETECTOR_PADSEL_0_SEL_0_FIELD, config.pad_select);
544  mmio_region_write32(pinmux->base_addr, reg_offset, reg_value);
545 
546  reg_offset = PINMUX_WKUP_DETECTOR_EN_0_REG_OFFSET +
547  (ptrdiff_t)detector * (ptrdiff_t)sizeof(uint32_t);
548  reg_value = bitfield_bit32_write(0, PINMUX_WKUP_DETECTOR_EN_0_EN_0_BIT, true);
549  mmio_region_write32(pinmux->base_addr, reg_offset, reg_value);
550  return kDifOk;
551 }
552 
554  dif_pinmux_index_t detector) {
555  if (pinmux == NULL) {
556  return kDifBadArg;
557  }
558  if (detector >= PINMUX_PARAM_N_WKUP_DETECT) {
559  return kDifBadArg;
560  }
561  bool is_locked;
563  pinmux, detector, kDifPinmuxLockTargetWakeupDetector, &is_locked);
564  if (result != kDifOk) {
565  return result;
566  }
567  if (is_locked) {
568  return kDifLocked;
569  }
570 
571  ptrdiff_t reg_offset = PINMUX_WKUP_DETECTOR_EN_0_REG_OFFSET +
572  (ptrdiff_t)sizeof(uint32_t) * (ptrdiff_t)detector;
573  mmio_region_write32(pinmux->base_addr, reg_offset, 0);
574  return kDifOk;
575 }
576 
578  if (pinmux == NULL) {
579  return kDifBadArg;
580  }
581  mmio_region_write32(pinmux->base_addr, PINMUX_WKUP_CAUSE_REG_OFFSET, 0);
582  return kDifOk;
583 }
584 
586  uint32_t *detector_map) {
587  if (pinmux == NULL) {
588  return kDifBadArg;
589  }
590  *detector_map =
591  mmio_region_read32(pinmux->base_addr, PINMUX_WKUP_CAUSE_REG_OFFSET);
592  return kDifOk;
593 }