Lines Matching +full:adc +full:- +full:mode
4 * SPDX-License-Identifier: Apache-2.0
10 #include <zephyr/drivers/adc.h>
11 #include <zephyr/drivers/adc/adc_npcx_threshold.h>
25 /* ADC speed/delay values during initialization */
31 /* ADC targeted operating frequency (2MHz) */
34 /* ADC conversion mode */
46 /* adc controller base address */
50 /* the number of ADC channels */
54 /* routine for configuring ADC's ISR */
61 * Selects ADC channel number, for which the measured data is compared
84 * sampling mode after adc_npcx_read is called. This variable records
85 * channels being used in repetitive mode in order to set ADC registers
102 /* Input clock for ADC converter */
104 /* mutex of ADC channels */
107 * Bit-mask indicating the channels to be included in each sampling
111 /* ADC Device pointer used in api functions */
115 /* end pointer of buffer to ensure enough space for storing ADC data. */
131 #define HAL_INSTANCE(dev) ((struct adc_reg *)((const struct adc_npcx_config *)(dev)->config)->base)
133 /* ADC local functions */
138 if (atomic_test_and_set_bit(&data->current_pm_lock, 0) == 0) { in adc_npcx_pm_policy_state_lock_get()
145 if (atomic_test_and_clear_bit(&data->current_pm_lock, 0) == 1) { in adc_npcx_pm_policy_state_lock_put()
153 const struct adc_npcx_config *config = dev->config; in adc_npcx_config_channels()
156 inst->ADCCS = channels & BIT_MASK(NPCX_ADCCS_MAX_CHANNEL_COUNT); in adc_npcx_config_channels()
158 /* Only npcx4 and later series support over 16 ADC channels */ in adc_npcx_config_channels()
159 if (config->channel_count > NPCX_ADCCS_MAX_CHANNEL_COUNT) { in adc_npcx_config_channels()
160 inst->ADCCS2 = (channels >> NPCX_ADCCS_MAX_CHANNEL_COUNT) & in adc_npcx_config_channels()
168 const struct adc_npcx_config *config = dev->config; in adc_npcx_enable_threshold_detect()
172 THEN(config->base) |= BIT(th_sel); in adc_npcx_enable_threshold_detect()
174 THRCTL(config->base, th_sel) |= BIT(NPCX_THRCTL_THEN); in adc_npcx_enable_threshold_detect()
179 THEN(config->base) &= ~BIT(th_sel); in adc_npcx_enable_threshold_detect()
181 THRCTL(config->base, th_sel) &= ~BIT(NPCX_THRCTL_THEN); in adc_npcx_enable_threshold_detect()
188 const struct adc_npcx_config *config = dev->config; in adc_npcx_isr()
189 struct adc_npcx_data *const data = dev->data; in adc_npcx_isr()
191 struct adc_npcx_threshold_data *const t_data = data->threshold_data; in adc_npcx_isr()
192 uint16_t status = inst->ADCSTS; in adc_npcx_isr()
196 inst->ADCSTS = status; in adc_npcx_isr()
201 IS_BIT_SET(inst->ADCCNF, NPCX_ADCCNF_INTECCEN)) { in adc_npcx_isr()
202 /* Stop conversion for scan conversion mode */ in adc_npcx_isr()
203 inst->ADCCNF |= BIT(NPCX_ADCCNF_STOP); in adc_npcx_isr()
205 /* Get result for each ADC selected channel */ in adc_npcx_isr()
206 while (data->channels) { in adc_npcx_isr()
207 channel = find_lsb_set(data->channels) - 1; in adc_npcx_isr()
208 result = GET_FIELD(CHNDAT(config->base, channel), in adc_npcx_isr()
211 * Save ADC result and adc_npcx_validate_buffer_size() in adc_npcx_isr()
215 if (data->buffer < data->buf_end) { in adc_npcx_isr()
216 *data->buffer++ = result; in adc_npcx_isr()
218 data->channels &= ~BIT(channel); in adc_npcx_isr()
221 inst->ADCCNF &= ~BIT(NPCX_ADCCNF_INTECCEN); in adc_npcx_isr()
224 t_data->active_thresholds) { in adc_npcx_isr()
226 adc_npcx_config_channels(dev, t_data->repetitive_channels); in adc_npcx_isr()
228 inst->ADCCNF |= BIT(NPCX_ADCCNF_START); in adc_npcx_isr()
232 /* Turn off ADC */ in adc_npcx_isr()
233 inst->ADCCNF &= ~(BIT(NPCX_ADCCNF_ADCEN)); in adc_npcx_isr()
240 adc_context_on_sampling_done(&data->ctx, data->adc_dev); in adc_npcx_isr()
243 if (!(IS_ENABLED(CONFIG_ADC_CMP_NPCX) && t_data->active_thresholds)) { in adc_npcx_isr()
248 for (uint8_t i = 0; i < config->threshold_count; i++) { in adc_npcx_isr()
249 if (IS_BIT_SET(inst->THRCTS, i) && IS_BIT_SET(inst->THRCTS, in adc_npcx_isr()
252 thrcts = inst->THRCTS & in adc_npcx_isr()
253 ~GENMASK(config->threshold_count - 1, 0); in adc_npcx_isr()
256 inst->THRCTS = thrcts; in adc_npcx_isr()
257 if (t_data->control[i].work) { in adc_npcx_isr()
260 t_data->control[i].work); in adc_npcx_isr()
267 * Validate the buffer size with adc channels mask. If it is lower than what
268 * we need return -ENOSPC.
273 const struct adc_npcx_config *config = dev->config; in adc_npcx_validate_buffer_size()
278 for (mask = BIT(config->channel_count - 1); mask != 0; mask >>= 1) { in adc_npcx_validate_buffer_size()
279 if (mask & sequence->channels) { in adc_npcx_validate_buffer_size()
285 if (sequence->options) { in adc_npcx_validate_buffer_size()
286 needed *= (1 + sequence->options->extra_samplings); in adc_npcx_validate_buffer_size()
289 if (sequence->buffer_size < needed) { in adc_npcx_validate_buffer_size()
290 return -ENOSPC; in adc_npcx_validate_buffer_size()
298 const struct adc_npcx_config *config = dev->config; in adc_npcx_start_scan()
299 struct adc_npcx_data *const data = dev->data; in adc_npcx_start_scan()
305 /* Turn on ADC first */ in adc_npcx_start_scan()
306 inst->ADCCNF |= BIT(NPCX_ADCCNF_ADCEN); in adc_npcx_start_scan()
308 /* Stop conversion for scan conversion mode */ in adc_npcx_start_scan()
309 inst->ADCCNF |= BIT(NPCX_ADCCNF_STOP); in adc_npcx_start_scan()
312 inst->ADCSTS |= BIT(NPCX_ADCSTS_EOCCEV); in adc_npcx_start_scan()
314 /* Update selected channels in scan mode by channels mask */ in adc_npcx_start_scan()
315 adc_npcx_config_channels(dev, data->channels); in adc_npcx_start_scan()
317 /* Select 'Scan' Conversion mode. */ in adc_npcx_start_scan()
318 SET_FIELD(inst->ADCCNF, NPCX_ADCCNF_ADCMD_FIELD, in adc_npcx_start_scan()
322 inst->ADCCNF |= BIT(NPCX_ADCCNF_INTECCEN); in adc_npcx_start_scan()
325 inst->ADCCNF |= BIT(NPCX_ADCCNF_START); in adc_npcx_start_scan()
327 if (config->channel_count > NPCX_ADCCS_MAX_CHANNEL_COUNT) { in adc_npcx_start_scan()
328 LOG_DBG("Start ADC scan conversion and ADCCNF,ADCCS, ADCCS2 are " in adc_npcx_start_scan()
329 "(%04X,%04X,%04X)\n", inst->ADCCNF, inst->ADCCS, inst->ADCCS2); in adc_npcx_start_scan()
331 LOG_DBG("Start ADC scan conversion and ADCCNF,ADCCS are (%04X,%04X)\n", in adc_npcx_start_scan()
332 inst->ADCCNF, inst->ADCCS); in adc_npcx_start_scan()
339 const struct adc_npcx_config *config = dev->config; in adc_npcx_start_read()
340 struct adc_npcx_data *const data = dev->data; in adc_npcx_start_read()
343 if (!sequence->channels || in adc_npcx_start_read()
344 (sequence->channels & ~BIT_MASK(config->channel_count))) { in adc_npcx_start_read()
345 LOG_ERR("Invalid ADC channels"); in adc_npcx_start_read()
346 return -EINVAL; in adc_npcx_start_read()
349 /* Fixed 10 bit resolution of npcx ADC */ in adc_npcx_start_read()
350 if (sequence->resolution != 10) { in adc_npcx_start_read()
351 LOG_ERR("Unfixed 10 bit ADC resolution"); in adc_npcx_start_read()
352 return -ENOTSUP; in adc_npcx_start_read()
357 LOG_ERR("ADC buffer size too small"); in adc_npcx_start_read()
361 /* Save ADC sequence sampling buffer and its end pointer address */ in adc_npcx_start_read()
362 data->buffer = sequence->buffer; in adc_npcx_start_read()
363 data->buf_end = data->buffer + sequence->buffer_size / sizeof(uint16_t); in adc_npcx_start_read()
365 /* Start ADC conversion */ in adc_npcx_start_read()
366 adc_context_start_read(&data->ctx, sequence); in adc_npcx_start_read()
367 error = adc_context_wait_for_completion(&data->ctx); in adc_npcx_start_read()
372 /* ADC api functions */
378 data->repeat_buffer = data->buffer; in adc_context_start_sampling()
379 data->channels = ctx->sequence.channels; in adc_context_start_sampling()
381 /* Start ADC scan conversion */ in adc_context_start_sampling()
382 adc_npcx_start_scan(data->adc_dev); in adc_context_start_sampling()
392 data->buffer = data->repeat_buffer; in adc_context_update_buffer_pointer()
399 const struct adc_npcx_config *config = dev->config; in adc_npcx_channel_setup()
400 uint8_t channel_id = channel_cfg->channel_id; in adc_npcx_channel_setup()
402 if (channel_id >= config->channel_count) { in adc_npcx_channel_setup()
404 return -EINVAL; in adc_npcx_channel_setup()
407 if (channel_cfg->acquisition_time != ADC_ACQ_TIME_DEFAULT) { in adc_npcx_channel_setup()
409 return -ENOTSUP; in adc_npcx_channel_setup()
412 if (channel_cfg->differential) { in adc_npcx_channel_setup()
414 return -ENOTSUP; in adc_npcx_channel_setup()
417 if (channel_cfg->gain != ADC_GAIN_1) { in adc_npcx_channel_setup()
418 LOG_ERR("Unsupported channel gain %d", channel_cfg->gain); in adc_npcx_channel_setup()
419 return -ENOTSUP; in adc_npcx_channel_setup()
422 if (channel_cfg->reference != ADC_REF_INTERNAL) { in adc_npcx_channel_setup()
424 return -ENOTSUP; in adc_npcx_channel_setup()
427 LOG_DBG("ADC channel %d configured", channel_cfg->channel_id); in adc_npcx_channel_setup()
434 struct adc_npcx_data *const data = dev->data; in adc_npcx_read()
437 adc_context_lock(&data->ctx, false, NULL); in adc_npcx_read()
439 adc_context_release(&data->ctx, error); in adc_npcx_read()
449 struct adc_npcx_data *const data = dev->data; in adc_npcx_read_async()
452 adc_context_lock(&data->ctx, true, async); in adc_npcx_read_async()
454 adc_context_release(&data->ctx, error); in adc_npcx_read_async()
464 struct adc_npcx_data *const data = dev->data; in adc_npcx_set_repetitive()
465 struct adc_npcx_threshold_data *const t_data = data->threshold_data; in adc_npcx_set_repetitive()
467 /* Stop ADC conversion */ in adc_npcx_set_repetitive()
468 inst->ADCCNF |= BIT(NPCX_ADCCNF_STOP); in adc_npcx_set_repetitive()
474 /* Turn on ADC */ in adc_npcx_set_repetitive()
475 inst->ADCCNF |= BIT(NPCX_ADCCNF_ADCEN); in adc_npcx_set_repetitive()
476 /* Set ADC conversion code to SW conversion mode */ in adc_npcx_set_repetitive()
477 SET_FIELD(inst->ADCCNF, NPCX_ADCCNF_ADCMD_FIELD, in adc_npcx_set_repetitive()
480 /* Add selected ADC channel to be converted */ in adc_npcx_set_repetitive()
481 t_data->repetitive_channels |= BIT(chnsel); in adc_npcx_set_repetitive()
482 adc_npcx_config_channels(dev, t_data->repetitive_channels); in adc_npcx_set_repetitive()
485 inst->ADCCNF |= BIT(NPCX_ADCCNF_ADCRPTC); in adc_npcx_set_repetitive()
488 inst->ADCCNF |= BIT(NPCX_ADCCNF_START); in adc_npcx_set_repetitive()
490 /* Remove selected ADC channel to be converted */ in adc_npcx_set_repetitive()
491 t_data->repetitive_channels &= ~BIT(chnsel); in adc_npcx_set_repetitive()
492 adc_npcx_config_channels(dev, t_data->repetitive_channels); in adc_npcx_set_repetitive()
494 if (!t_data->repetitive_channels) { in adc_npcx_set_repetitive()
495 /* No thesholdd active left, disable repetitive mode */ in adc_npcx_set_repetitive()
496 inst->ADCCNF &= ~BIT(NPCX_ADCCNF_ADCRPTC); in adc_npcx_set_repetitive()
497 /* Turn off ADC */ in adc_npcx_set_repetitive()
498 inst->ADCCNF &= ~BIT(NPCX_ADCCNF_ADCEN); in adc_npcx_set_repetitive()
504 inst->ADCCNF |= BIT(NPCX_ADCCNF_START); in adc_npcx_set_repetitive()
514 const struct adc_npcx_config *config = dev->config; in adc_npcx_threshold_ctrl_set_param()
515 struct adc_npcx_data *const data = dev->data; in adc_npcx_threshold_ctrl_set_param()
516 struct adc_npcx_threshold_data *const t_data = data->threshold_data; in adc_npcx_threshold_ctrl_set_param()
518 &t_data->control[th_sel]; in adc_npcx_threshold_ctrl_set_param()
522 return -EOPNOTSUPP; in adc_npcx_threshold_ctrl_set_param()
525 if (!param || th_sel >= config->threshold_count) { in adc_npcx_threshold_ctrl_set_param()
526 return -EINVAL; in adc_npcx_threshold_ctrl_set_param()
529 adc_context_lock(&data->ctx, false, NULL); in adc_npcx_threshold_ctrl_set_param()
530 switch (param->type) { in adc_npcx_threshold_ctrl_set_param()
532 if (param->val >= config->channel_count) { in adc_npcx_threshold_ctrl_set_param()
533 ret = -EINVAL; in adc_npcx_threshold_ctrl_set_param()
536 t_ctrl->chnsel = (uint8_t)param->val; in adc_npcx_threshold_ctrl_set_param()
540 t_ctrl->l_h = !!param->val; in adc_npcx_threshold_ctrl_set_param()
544 if (param->val == 0 || param->val >= ADC_NPCX_THRVAL_MAX) { in adc_npcx_threshold_ctrl_set_param()
545 ret = -EINVAL; in adc_npcx_threshold_ctrl_set_param()
548 t_ctrl->thrval = (uint16_t)param->val; in adc_npcx_threshold_ctrl_set_param()
552 if (param->val == 0) { in adc_npcx_threshold_ctrl_set_param()
553 ret = -EINVAL; in adc_npcx_threshold_ctrl_set_param()
556 t_ctrl->work = (struct k_work *)param->val; in adc_npcx_threshold_ctrl_set_param()
559 ret = -EINVAL; in adc_npcx_threshold_ctrl_set_param()
561 adc_context_release(&data->ctx, 0); in adc_npcx_threshold_ctrl_set_param()
568 struct adc_npcx_data *const data = dev->data; in adc_npcx_threshold_ctrl_setup()
569 struct adc_driver_api *api = (struct adc_driver_api *)dev->api; in adc_npcx_threshold_ctrl_setup()
570 struct adc_npcx_threshold_data *const t_data = data->threshold_data; in adc_npcx_threshold_ctrl_setup()
571 const struct adc_npcx_config *config = dev->config; in adc_npcx_threshold_ctrl_setup()
573 &t_data->control[th_sel]; in adc_npcx_threshold_ctrl_setup()
575 if (th_sel >= config->threshold_count) { in adc_npcx_threshold_ctrl_setup()
576 return -EINVAL; in adc_npcx_threshold_ctrl_setup()
579 adc_context_lock(&data->ctx, false, NULL); in adc_npcx_threshold_ctrl_setup()
581 if (t_data->active_thresholds & BIT(th_sel)) { in adc_npcx_threshold_ctrl_setup()
583 adc_context_release(&data->ctx, 0); in adc_npcx_threshold_ctrl_setup()
585 return -EBUSY; in adc_npcx_threshold_ctrl_setup()
588 if (t_ctrl->chnsel >= config->channel_count || in adc_npcx_threshold_ctrl_setup()
589 t_ctrl->thrval >= api->ref_internal || in adc_npcx_threshold_ctrl_setup()
590 t_ctrl->thrval == 0 || t_ctrl->work == 0) { in adc_npcx_threshold_ctrl_setup()
591 adc_context_release(&data->ctx, 0); in adc_npcx_threshold_ctrl_setup()
593 return -EINVAL; in adc_npcx_threshold_ctrl_setup()
596 SET_FIELD(THRCTL(config->base, th_sel), in adc_npcx_threshold_ctrl_setup()
597 NPCX_THRCTL_CHNSEL, t_ctrl->chnsel); in adc_npcx_threshold_ctrl_setup()
599 if (t_ctrl->l_h) { in adc_npcx_threshold_ctrl_setup()
600 THRCTL(config->base, th_sel) |= BIT(NPCX_THRCTL_L_H); in adc_npcx_threshold_ctrl_setup()
602 THRCTL(config->base, th_sel) &= ~BIT(NPCX_THRCTL_L_H); in adc_npcx_threshold_ctrl_setup()
605 SET_FIELD(THRCTL(config->base, th_sel), NPCX_THRCTL_THRVAL, in adc_npcx_threshold_ctrl_setup()
606 t_ctrl->thrval); in adc_npcx_threshold_ctrl_setup()
608 adc_context_release(&data->ctx, 0); in adc_npcx_threshold_ctrl_setup()
616 struct adc_driver_api *api = (struct adc_driver_api *)dev->api; in adc_npcx_threshold_enable_irq()
617 struct adc_npcx_data *const data = dev->data; in adc_npcx_threshold_enable_irq()
618 const struct adc_npcx_config *config = dev->config; in adc_npcx_threshold_enable_irq()
619 struct adc_npcx_threshold_data *const t_data = data->threshold_data; in adc_npcx_threshold_enable_irq()
621 &t_data->control[th_sel]; in adc_npcx_threshold_enable_irq()
624 if (th_sel >= config->threshold_count) { in adc_npcx_threshold_enable_irq()
625 LOG_ERR("Invalid ADC threshold selection! (%d)", th_sel); in adc_npcx_threshold_enable_irq()
626 return -EINVAL; in adc_npcx_threshold_enable_irq()
629 adc_context_lock(&data->ctx, false, NULL); in adc_npcx_threshold_enable_irq()
630 if (t_ctrl->chnsel >= config->channel_count || in adc_npcx_threshold_enable_irq()
631 t_ctrl->thrval >= api->ref_internal || in adc_npcx_threshold_enable_irq()
632 t_ctrl->thrval == 0 || t_ctrl->work == 0) { in adc_npcx_threshold_enable_irq()
633 adc_context_release(&data->ctx, 0); in adc_npcx_threshold_enable_irq()
635 return -EINVAL; in adc_npcx_threshold_enable_irq()
639 t_data->active_thresholds |= BIT(th_sel); in adc_npcx_threshold_enable_irq()
642 thrcts = inst->THRCTS & ~GENMASK(config->threshold_count - 1, 0); in adc_npcx_threshold_enable_irq()
653 inst->THRCTS = thrcts; in adc_npcx_threshold_enable_irq()
655 adc_npcx_set_repetitive(dev, t_data->control[th_sel].chnsel, true); in adc_npcx_threshold_enable_irq()
657 adc_context_release(&data->ctx, 0); in adc_npcx_threshold_enable_irq()
665 const struct adc_npcx_config *config = dev->config; in adc_npcx_threshold_disable_irq()
666 struct adc_npcx_data *const data = dev->data; in adc_npcx_threshold_disable_irq()
667 struct adc_npcx_threshold_data *const t_data = data->threshold_data; in adc_npcx_threshold_disable_irq()
671 return -EOPNOTSUPP; in adc_npcx_threshold_disable_irq()
674 if (th_sel >= config->threshold_count) { in adc_npcx_threshold_disable_irq()
675 LOG_ERR("Invalid ADC threshold selection! (%d)", th_sel); in adc_npcx_threshold_disable_irq()
676 return -EINVAL; in adc_npcx_threshold_disable_irq()
679 adc_context_lock(&data->ctx, false, NULL); in adc_npcx_threshold_disable_irq()
680 if (!(t_data->active_thresholds & BIT(th_sel))) { in adc_npcx_threshold_disable_irq()
681 adc_context_release(&data->ctx, 0); in adc_npcx_threshold_disable_irq()
683 return -ENODEV; in adc_npcx_threshold_disable_irq()
686 thrcts = inst->THRCTS & ~GENMASK(config->threshold_count - 1, 0); in adc_npcx_threshold_disable_irq()
690 inst->THRCTS = thrcts; in adc_npcx_threshold_disable_irq()
696 t_data->active_thresholds &= ~BIT(th_sel); in adc_npcx_threshold_disable_irq()
698 adc_npcx_set_repetitive(dev, t_data->control[th_sel].chnsel, false); in adc_npcx_threshold_disable_irq()
700 adc_context_release(&data->ctx, 0); in adc_npcx_threshold_disable_irq()
711 return -EOPNOTSUPP; in adc_npcx_threshold_ctrl_enable()
731 struct adc_driver_api *api = (struct adc_driver_api *)dev->api; in adc_npcx_threshold_mv_to_thrval()
734 return -EOPNOTSUPP; in adc_npcx_threshold_mv_to_thrval()
737 if (val_mv >= api->ref_internal) { in adc_npcx_threshold_mv_to_thrval()
738 return -EINVAL; in adc_npcx_threshold_mv_to_thrval()
742 api->ref_internal; in adc_npcx_threshold_mv_to_thrval()
773 const struct adc_npcx_config *const config = dev->config; in adc_npcx_init()
774 struct adc_npcx_data *const data = dev->data; in adc_npcx_init()
781 return -ENODEV; in adc_npcx_init()
784 /* Save ADC device in data */ in adc_npcx_init()
785 data->adc_dev = dev; in adc_npcx_init()
789 &config->clk_cfg); in adc_npcx_init()
791 LOG_ERR("Turn on ADC clock fail %d", ret); in adc_npcx_init()
796 &config->clk_cfg, &data->input_clk); in adc_npcx_init()
798 LOG_ERR("Get ADC clock rate error %d", ret); in adc_npcx_init()
802 /* Configure the ADC clock */ in adc_npcx_init()
803 prescaler = DIV_ROUND_UP(data->input_clk, NPCX_ADC_CLK); in adc_npcx_init()
808 /* Set Core Clock Division Factor in order to obtain the ADC clock */ in adc_npcx_init()
809 SET_FIELD(inst->ATCTL, NPCX_ATCTL_SCLKDIV_FIELD, prescaler - 1); in adc_npcx_init()
811 /* Set regular ADC delay */ in adc_npcx_init()
812 SET_FIELD(inst->ATCTL, NPCX_ATCTL_DLY_FIELD, ADC_REGULAR_DLY_VAL); in adc_npcx_init()
814 /* Set ADC speed sequentially */ in adc_npcx_init()
815 inst->ADCCNF2 = ADC_REGULAR_ADCCNF2_VAL; in adc_npcx_init()
816 inst->GENDLY = ADC_REGULAR_GENDLY_VAL; in adc_npcx_init()
817 inst->MEAST = ADC_REGULAR_MEAST_VAL; in adc_npcx_init()
819 /* Configure ADC interrupt and enable it */ in adc_npcx_init()
820 config->irq_cfg_func(); in adc_npcx_init()
822 /* Initialize mutex of ADC channels */ in adc_npcx_init()
823 adc_context_unlock_unconditionally(&data->ctx); in adc_npcx_init()
825 /* Configure pin-mux for ADC device */ in adc_npcx_init()
826 ret = pinctrl_apply_state(config->pcfg, PINCTRL_STATE_DEFAULT); in adc_npcx_init()
828 LOG_ERR("ADC pinctrl setup failed (%d)", ret); in adc_npcx_init()
844 static DEVICE_API(adc, adc_npcx_driver_api_##n) = { \