| /* |
| * Copyright 2021 NXP |
| * SPDX-License-Identifier: Apache-2.0 |
| */ |
| |
| /* |
| * Based on regulator-fixed test and adc driver sample, with are |
| * copyright Peter Bigot Consulting, LLC and Libre Solar Technologies GmbH, |
| * respectively. |
| */ |
| |
| #include <zephyr/zephyr.h> |
| #include <zephyr/drivers/gpio.h> |
| #include <zephyr/drivers/adc.h> |
| #include <zephyr/drivers/regulator.h> |
| #include <zephyr/drivers/regulator/consumer.h> |
| #include <ztest.h> |
| |
| #if !DT_NODE_EXISTS(DT_PATH(zephyr_user)) || \ |
| !DT_NODE_HAS_PROP(DT_PATH(zephyr_user), io_channels) |
| #error "No suitable devicetree overlay specified" |
| #endif |
| |
| #define ADC_NODE DT_PHANDLE(DT_PATH(zephyr_user), io_channels) |
| |
| /* Common settings supported by most ADCs */ |
| #define ADC_RESOLUTION 12 |
| #define ADC_GAIN ADC_GAIN_1 |
| #define ADC_REFERENCE ADC_REF_INTERNAL |
| #define ADC_ACQUISITION_TIME ADC_ACQ_TIME_DEFAULT |
| |
| static int16_t sample_buffer[1]; |
| |
| #define CHANNEL_ID DT_IO_CHANNELS_INPUT_BY_IDX(DT_PATH(zephyr_user), 0) |
| |
| struct adc_channel_cfg channel_cfg = { |
| .gain = ADC_GAIN, |
| .reference = ADC_REFERENCE, |
| .acquisition_time = ADC_ACQUISITION_TIME, |
| .channel_id = CHANNEL_ID, |
| .differential = 0 |
| }; |
| |
| struct adc_sequence sequence = { |
| /* individual channels will be added below */ |
| .channels = BIT(CHANNEL_ID), |
| .buffer = sample_buffer, |
| /* buffer size in bytes, not number of samples */ |
| .buffer_size = sizeof(sample_buffer), |
| .resolution = ADC_RESOLUTION, |
| }; |
| |
| static struct onoff_client cli; |
| static struct onoff_manager *callback_srv; |
| static struct onoff_client *callback_cli; |
| static uint32_t callback_state; |
| static int callback_res; |
| static onoff_client_callback callback_fn; |
| |
| static void callback(struct onoff_manager *srv, |
| struct onoff_client *cli, |
| uint32_t state, |
| int res) |
| { |
| onoff_client_callback cb = callback_fn; |
| |
| callback_srv = srv; |
| callback_cli = cli; |
| callback_state = state; |
| callback_res = res; |
| callback_fn = NULL; |
| |
| if (cb != NULL) { |
| cb(srv, cli, state, res); |
| } |
| } |
| |
| static void reset_callback(void) |
| { |
| callback_srv = NULL; |
| callback_cli = NULL; |
| callback_state = INT_MIN; |
| callback_res = 0; |
| callback_fn = NULL; |
| } |
| |
| static void reset_client(void) |
| { |
| cli = (struct onoff_client){}; |
| reset_callback(); |
| sys_notify_init_callback(&cli.notify, callback); |
| } |
| |
| /* Returns voltage level of ADC in mV, or negative value on error */ |
| static int adc_get_reading(const struct device *adc_dev) |
| { |
| int rc, adc_vref, mv_value; |
| |
| adc_vref = adc_ref_internal(adc_dev); |
| |
| rc = adc_read(adc_dev, &sequence); |
| if (rc) { |
| return rc; |
| } |
| mv_value = sample_buffer[0]; |
| if (adc_vref > 0) { |
| adc_raw_to_millivolts(adc_vref, ADC_GAIN, ADC_RESOLUTION, &mv_value); |
| } |
| TC_PRINT("ADC read %d mV\n", mv_value); |
| return mv_value; |
| } |
| |
| static void test_basic(void) |
| { |
| const struct device *reg_dev, *adc_dev; |
| int rc, adc_reading; |
| |
| adc_dev = device_get_binding(DT_LABEL(ADC_NODE)); |
| reg_dev = device_get_binding(CONFIG_TEST_PMIC_REGULATOR_NAME); |
| zassert_not_null(adc_dev, |
| "ADC device to check regulator output not defined"); |
| zassert_not_null(reg_dev, |
| "Could not get regulator device binding"); |
| |
| /* Configure ADC */ |
| adc_channel_setup(adc_dev, &channel_cfg); |
| |
| |
| reset_client(); |
| |
| /* Turn regulator on */ |
| rc = regulator_enable(reg_dev, &cli); |
| zassert_true(rc >= 0, |
| "first enable failed: %d", rc); |
| |
| /* Wait for regulator to start */ |
| while (sys_notify_fetch_result(&cli.notify, &rc) == -EAGAIN) { |
| k_yield(); |
| } |
| rc = sys_notify_fetch_result(&cli.notify, &rc); |
| zassert_true(rc == 0, "Could not fetch regulator enable result"); |
| |
| zassert_equal(callback_cli, &cli, |
| "callback not invoked"); |
| zassert_equal(callback_res, 0, |
| "callback res: %d", callback_res); |
| zassert_equal(callback_state, ONOFF_STATE_ON, |
| "callback state: 0x%x", callback_res); |
| |
| /* Read adc to ensure regulator actually booted */ |
| adc_reading = adc_get_reading(adc_dev); |
| zassert_true(adc_reading > 200, /* Assume regulator provides at least 200mV */ |
| "Regulator did not supply power, ADC read %d mV", |
| adc_reading); |
| |
| /* Turn it on again (another client) */ |
| |
| reset_client(); |
| rc = regulator_enable(reg_dev, &cli); |
| zassert_true(rc >= 0, |
| "second enable failed: %d", rc); |
| |
| zassert_equal(callback_cli, &cli, |
| "callback not invoked"); |
| zassert_true(callback_res >= 0, |
| "callback res: %d", callback_res); |
| zassert_equal(callback_state, ONOFF_STATE_ON, |
| "callback state: 0x%x", callback_res); |
| |
| /* Make sure it's still on */ |
| |
| adc_reading = adc_get_reading(adc_dev); |
| zassert_true(adc_reading >= 200, |
| "Second on attempt failed, ADC read %d mV", adc_reading); |
| |
| /* Turn it off once (still has a client) */ |
| |
| rc = regulator_disable(reg_dev); |
| zassert_true(rc >= 0, |
| "first disable failed: %d", rc); |
| |
| /* Make sure it's still on */ |
| |
| adc_reading = adc_get_reading(adc_dev); |
| zassert_true(adc_reading >= 200, |
| "Regulator still has client, but ADC read %d mV", adc_reading); |
| |
| /* Turn it off again (no more clients) */ |
| |
| rc = regulator_disable(reg_dev); |
| zassert_true(rc >= 0, |
| "second disable failed: %d", rc); |
| |
| /* Verify the regulator is off */ |
| adc_reading = adc_get_reading(adc_dev); |
| zassert_true(adc_reading <= 200, |
| "Regulator is on with no clients, ADC read %d mV", adc_reading); |
| } |
| |
| void test_main(void) |
| { |
| ztest_test_suite(regulator_test, |
| ztest_unit_test(test_basic) |
| ); |
| ztest_run_test_suite(regulator_test); |
| } |