1 /*
2  * Copyright (c) 2023 The ChromiumOS Authors
3  *
4  * SPDX-License-Identifier: Apache-2.0
5  */
6 
7 #include <zephyr/drivers/adc.h>
8 #include <zephyr/drivers/adc/adc_emul.h>
9 #include <zephyr/drivers/adc/voltage_divider.h>
10 #include <zephyr/drivers/adc/current_sense_shunt.h>
11 #include <zephyr/drivers/adc/current_sense_amplifier.h>
12 #include <zephyr/kernel.h>
13 #include <zephyr/ztest.h>
14 
15 /* Raw to millivolt conversion doesn't handle rounding */
16 #define MV_OUTPUT_EPS 10
17 
18 #define ADC_TEST_NODE_0 DT_NODELABEL(sensor0)
19 #define ADC_TEST_NODE_1 DT_NODELABEL(sensor1)
20 #define ADC_TEST_NODE_2 DT_NODELABEL(sensor2)
21 
22 /**
23  * @brief Get ADC emulated device
24  *
25  * @return pointer to ADC device
26  */
get_adc_device(void)27 const struct device *get_adc_device(void)
28 {
29 	const struct device *const adc_dev = DEVICE_DT_GET(DT_NODELABEL(adc0));
30 
31 	zassert_true(device_is_ready(adc_dev), "ADC device is not ready");
32 
33 	return adc_dev;
34 }
35 
init_adc(const struct adc_dt_spec * spec,int input_mv)36 static int init_adc(const struct adc_dt_spec *spec, int input_mv)
37 {
38 	int ret;
39 
40 	zassert_true(adc_is_ready_dt(spec), "ADC device is not ready");
41 
42 	ret = adc_channel_setup_dt(spec);
43 	zassert_equal(ret, 0, "Setting up of the first channel failed with code %d", ret);
44 
45 	/* ADC emulator-specific setup */
46 	ret = adc_emul_const_value_set(spec->dev, spec->channel_id, input_mv);
47 	zassert_ok(ret, "adc_emul_const_value_set() failed with code %d", ret);
48 
49 	return ret;
50 }
51 
52 /*
53  * test_adc_voltage_divider
54  */
test_task_voltage_divider(void)55 static int test_task_voltage_divider(void)
56 {
57 	int ret;
58 	int32_t calculated_voltage = 0;
59 	int32_t input_mv = 1000;
60 	const struct voltage_divider_dt_spec adc_node_0 =
61 		VOLTAGE_DIVIDER_DT_SPEC_GET(ADC_TEST_NODE_0);
62 
63 	ret = init_adc(&adc_node_0.port, input_mv);
64 	zassert_equal(ret, 0, "Setting up of the first channel failed with code %d", ret);
65 
66 	struct adc_sequence sequence = {
67 		.buffer = &calculated_voltage,
68 		.buffer_size = sizeof(calculated_voltage),
69 	};
70 	adc_sequence_init_dt(&adc_node_0.port, &sequence);
71 
72 	ret = adc_read_dt(&adc_node_0.port, &sequence);
73 	zassert_equal(ret, 0, "adc_read() failed with code %d", ret);
74 
75 	ret = adc_raw_to_millivolts_dt(&adc_node_0.port, &calculated_voltage);
76 	zassert_equal(ret, 0, "adc_raw_to_millivolts_dt() failed with code %d", ret);
77 
78 	ret = voltage_divider_scale_dt(&adc_node_0, &calculated_voltage);
79 	zassert_equal(ret, 0, "divider_scale_voltage_dt() failed with code %d", ret);
80 
81 	zassert_within(calculated_voltage, input_mv * 2, MV_OUTPUT_EPS,
82 		       "%u != %u should have set value", calculated_voltage, input_mv * 2);
83 
84 	return TC_PASS;
85 }
86 
ZTEST_USER(adc_rescale,test_adc_voltage_divider)87 ZTEST_USER(adc_rescale, test_adc_voltage_divider)
88 {
89 	zassert_true(test_task_voltage_divider() == TC_PASS);
90 }
91 
92 /*
93  * test_adc_current_sense_shunt
94  */
test_task_current_sense_shunt(void)95 static int test_task_current_sense_shunt(void)
96 {
97 	int ret;
98 	int32_t calculated_current = 0;
99 	int32_t input_mv = 3000;
100 	const struct current_sense_shunt_dt_spec adc_node_1 =
101 		CURRENT_SENSE_SHUNT_DT_SPEC_GET(ADC_TEST_NODE_1);
102 
103 	ret = init_adc(&adc_node_1.port, input_mv);
104 	zassert_equal(ret, 0, "Setting up of the second channel failed with code %d", ret);
105 
106 	struct adc_sequence sequence = {
107 		.buffer = &calculated_current,
108 		.buffer_size = sizeof(calculated_current),
109 	};
110 	adc_sequence_init_dt(&adc_node_1.port, &sequence);
111 
112 	ret = adc_read_dt(&adc_node_1.port, &sequence);
113 	zassert_equal(ret, 0, "adc_read() failed with code %d", ret);
114 
115 	ret = adc_raw_to_millivolts_dt(&adc_node_1.port, &calculated_current);
116 	zassert_equal(ret, 0, "adc_raw_to_millivolts_dt() failed with code %d", ret);
117 
118 	current_sense_shunt_scale_dt(&adc_node_1, &calculated_current);
119 
120 	zassert_within(calculated_current, input_mv * 2, MV_OUTPUT_EPS,
121 		       "%u != %u should have set value", calculated_current,
122 		       input_mv * 2);
123 
124 	return TC_PASS;
125 }
126 
ZTEST_USER(adc_rescale,test_adc_current_sense_shunt)127 ZTEST_USER(adc_rescale, test_adc_current_sense_shunt)
128 {
129 	zassert_true(test_task_current_sense_shunt() == TC_PASS);
130 }
131 
132 /*
133  * test_adc_current_sense_amplifier
134  */
test_task_current_sense_amplifier(void)135 static int test_task_current_sense_amplifier(void)
136 {
137 	int ret;
138 	int32_t calculated_current = 0;
139 	int32_t input_mv = 3000;
140 	const struct current_sense_amplifier_dt_spec adc_node_2 =
141 		CURRENT_SENSE_AMPLIFIER_DT_SPEC_GET(ADC_TEST_NODE_2);
142 
143 	ret = init_adc(&adc_node_2.port, input_mv);
144 	zassert_equal(ret, 0, "Setting up of the third channel failed with code %d", ret);
145 
146 	struct adc_sequence sequence = {
147 		.buffer = &calculated_current,
148 		.buffer_size = sizeof(calculated_current),
149 	};
150 	adc_sequence_init_dt(&adc_node_2.port, &sequence);
151 
152 	ret = adc_read_dt(&adc_node_2.port, &sequence);
153 	zassert_equal(ret, 0, "adc_read() failed with code %d", ret);
154 
155 	ret = adc_raw_to_millivolts_dt(&adc_node_2.port, &calculated_current);
156 	zassert_equal(ret, 0, "adc_raw_to_millivolts_dt() failed with code %d", ret);
157 
158 	current_sense_amplifier_scale_dt(&adc_node_2, &calculated_current);
159 
160 	zassert_within(calculated_current, input_mv * 2, MV_OUTPUT_EPS,
161 		       "%u != %u should have set value", calculated_current,
162 		       input_mv * 2);
163 
164 	return TC_PASS;
165 }
166 
ZTEST_USER(adc_rescale,test_adc_current_sense_amplifier)167 ZTEST_USER(adc_rescale, test_adc_current_sense_amplifier)
168 {
169 	zassert_true(test_task_current_sense_amplifier() == TC_PASS);
170 }
171 
adc_rescale_setup(void)172 void *adc_rescale_setup(void)
173 {
174 	k_object_access_grant(get_adc_device(), k_current_get());
175 
176 	return NULL;
177 }
178 
179 ZTEST_SUITE(adc_rescale, NULL, adc_rescale_setup, NULL, NULL, NULL);
180