summaryrefslogtreecommitdiff
path: root/zephyr/shim/src/adc.c
blob: 9d5e64376c864ef7d3fb6ea005a128d0d30a26e3 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
/* Copyright 2021 The ChromiumOS Authors
 * Use of this source code is governed by a BSD-style license that can be
 * found in the LICENSE file.
 */

#include <zephyr/devicetree/io-channels.h>
#include <zephyr/drivers/adc.h>
#include <zephyr/logging/log.h>
#include "adc.h"
#include "zephyr_adc.h"

LOG_MODULE_REGISTER(shim_adc, LOG_LEVEL_ERR);

#if defined(CONFIG_PLATFORM_EC_ADC_CMD) && defined(CONFIG_ADC_SHELL)
#error "Define only one 'adc' console command."
#endif

#define HAS_NAMED_ADC_CHANNELS DT_NODE_EXISTS(DT_INST(0, named_adc_channels))

#if HAS_NAMED_ADC_CHANNELS
#define ADC_CHANNEL_INIT(node_id) \
	[ZSHIM_ADC_ID(node_id)] = {                                       \
		.name = DT_NODE_FULL_NAME(node_id),                       \
		.dev = DEVICE_DT_GET(DT_IO_CHANNELS_CTLR(node_id)),       \
		.input_ch = DT_IO_CHANNELS_INPUT(node_id),                \
		.factor_mul = DT_PROP(node_id, mul),                      \
		.factor_div = DT_PROP(node_id, div),                      \
		.channel_cfg = {                                          \
			.channel_id = DT_IO_CHANNELS_INPUT(node_id),      \
			.gain = DT_STRING_TOKEN(node_id, gain),           \
			.reference = DT_STRING_TOKEN(node_id, reference), \
			.acquisition_time =                               \
				DT_PROP(node_id, acquisition_time),       \
			.differential = DT_PROP(node_id, differential),   \
		},                                                        \
	},
#ifdef CONFIG_ADC_CHANNELS_RUNTIME_CONFIG
struct adc_t adc_channels[] = { DT_FOREACH_CHILD(DT_INST(0, named_adc_channels),
						 ADC_CHANNEL_INIT) };
#else
const struct adc_t adc_channels[] = { DT_FOREACH_CHILD(
	DT_INST(0, named_adc_channels), ADC_CHANNEL_INIT) };
#endif
#endif /* named_adc_channels */

static int init_device_bindings(const struct device *device)
{
	ARG_UNUSED(device);

#if HAS_NAMED_ADC_CHANNELS
	for (int i = 0; i < ARRAY_SIZE(adc_channels); i++) {
		if (!device_is_ready(adc_channels[i].dev))
			k_oops();

		adc_channel_setup(adc_channels[i].dev,
				  &adc_channels[i].channel_cfg);
	}
#endif

	return 0;
}
SYS_INIT(init_device_bindings, POST_KERNEL, 51);

test_mockable int adc_read_channel(enum adc_channel ch)
{
	int ret = 0, rv;
	struct adc_sequence seq = {
		.options = NULL,
		.channels = BIT(adc_channels[ch].input_ch),
		.buffer = &ret,
		.buffer_size = sizeof(ret),
		.resolution = CONFIG_PLATFORM_EC_ADC_RESOLUTION,
		.oversampling = CONFIG_PLATFORM_EC_ADC_OVERSAMPLING,
		.calibrate = false,
	};

	rv = adc_read(adc_channels[ch].dev, &seq);
	if (rv)
		return rv;

	adc_raw_to_millivolts(adc_ref_internal(adc_channels[ch].dev),
			      ADC_GAIN_1, CONFIG_PLATFORM_EC_ADC_RESOLUTION,
			      &ret);
	ret = (ret * adc_channels[ch].factor_mul) / adc_channels[ch].factor_div;
	return ret;
}