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
16static_assert(ADC_CTRL_PARAM_NUM_ADC_CHANNEL == 2,
17 "Expected two ADC Controller channels.");
18static_assert(ADC_CTRL_PARAM_NUM_ADC_FILTER == 8,
19 "Expected eight ADC Controller filters.");
20static_assert(ADC_CTRL_ADC_CHN0_FILTER_CTL_MIN_V_FIELD_WIDTH == 10,
21 "Expected channel-0 filter min-voltage field to be 10 bits.");
22static_assert(ADC_CTRL_ADC_CHN1_FILTER_CTL_MIN_V_FIELD_WIDTH == 10,
23 "Expected channel-1 filter min-voltage field to be 10 bits.");
24static_assert(ADC_CTRL_ADC_CHN0_FILTER_CTL_MAX_V_FIELD_WIDTH == 10,
25 "Expected channel-0 filter max-voltage field to be 10 bits.");
26static_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
29dif_result_t dif_adc_ctrl_configure(const dif_adc_ctrl_t *adc_ctrl,
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,
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
86dif_result_t dif_adc_ctrl_configure_filter(const dif_adc_ctrl_t *adc_ctrl,
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,
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
180dif_result_t dif_adc_ctrl_set_enabled(const dif_adc_ctrl_t *adc_ctrl,
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
197dif_result_t dif_adc_ctrl_get_enabled(const dif_adc_ctrl_t *adc_ctrl,
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
211static bool get_filter_offset(dif_adc_ctrl_channel_t channel,
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
251static bool get_filter_enable_bit(dif_adc_ctrl_channel_t channel,
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
289dif_result_t dif_adc_ctrl_filter_set_enabled(const dif_adc_ctrl_t *adc_ctrl,
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
316dif_result_t dif_adc_ctrl_filter_get_enabled(const dif_adc_ctrl_t *adc_ctrl,
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
341dif_result_t dif_adc_ctrl_get_triggered_value(const dif_adc_ctrl_t *adc_ctrl,
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
370dif_result_t dif_adc_ctrl_get_latest_value(const dif_adc_ctrl_t *adc_ctrl,
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
399dif_result_t dif_adc_ctrl_reset(const dif_adc_ctrl_t *adc_ctrl) {
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
410dif_result_t dif_adc_ctrl_irq_get_causes(const dif_adc_ctrl_t *adc_ctrl,
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
422dif_result_t dif_adc_ctrl_get_filter_status(const dif_adc_ctrl_t *adc_ctrl,
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
433dif_result_t dif_adc_ctrl_irq_clear_causes(const dif_adc_ctrl_t *adc_ctrl,
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
451dif_result_t dif_adc_ctrl_filter_match_wakeup_set_enabled(
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
469dif_result_t dif_adc_ctrl_filter_match_wakeup_get_enabled(
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
485dif_result_t dif_adc_ctrl_irq_cause_set_enabled(const dif_adc_ctrl_t *adc_ctrl,
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
506dif_result_t dif_adc_ctrl_irq_cause_get_enabled(const dif_adc_ctrl_t *adc_ctrl,
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
518dif_result_t dif_adc_ctrl_wait_cdc_sync(const dif_adc_ctrl_t *adc_ctrl,
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}