1 /*
2  * Copyright (c) 2023 Kenneth J. Miller <ken@miller.ec>
3  *
4  * SPDX-License-Identifier: Apache-2.0
5  */
6 
7 #define DT_DRV_COMPAT st_stm32_vref
8 
9 #include <zephyr/device.h>
10 #include <zephyr/devicetree.h>
11 #include <zephyr/drivers/sensor.h>
12 #include <zephyr/drivers/adc.h>
13 #include <zephyr/logging/log.h>
14 #include <zephyr/pm/device_runtime.h>
15 #include <stm32_ll_adc.h>
16 #if defined(CONFIG_SOC_SERIES_STM32H5X)
17 #include <stm32_ll_icache.h>
18 #endif /* CONFIG_SOC_SERIES_STM32H5X */
19 
20 LOG_MODULE_REGISTER(stm32_vref, CONFIG_SENSOR_LOG_LEVEL);
21 
22 struct stm32_vref_data {
23 	const struct device *adc;
24 	const struct adc_channel_cfg adc_cfg;
25 	ADC_TypeDef *adc_base;
26 	struct adc_sequence adc_seq;
27 	struct k_mutex mutex;
28 	int16_t sample_buffer;
29 	int16_t raw; /* raw adc Sensor value */
30 };
31 
32 struct stm32_vref_config {
33 	uint16_t *cal_addr;
34 	int cal_mv;
35 };
36 
stm32_vref_sample_fetch(const struct device * dev,enum sensor_channel chan)37 static int stm32_vref_sample_fetch(const struct device *dev, enum sensor_channel chan)
38 {
39 	struct stm32_vref_data *data = dev->data;
40 	struct adc_sequence *sp = &data->adc_seq;
41 	int rc;
42 	uint32_t path;
43 
44 	if (chan != SENSOR_CHAN_ALL && chan != SENSOR_CHAN_VOLTAGE) {
45 		return -ENOTSUP;
46 	}
47 
48 	k_mutex_lock(&data->mutex, K_FOREVER);
49 	pm_device_runtime_get(data->adc);
50 
51 	rc = adc_channel_setup(data->adc, &data->adc_cfg);
52 	if (rc) {
53 		LOG_DBG("Setup AIN%u got %d", data->adc_cfg.channel_id, rc);
54 		goto unlock;
55 	}
56 
57 	path = LL_ADC_GetCommonPathInternalCh(__LL_ADC_COMMON_INSTANCE(data->adc_base));
58 	LL_ADC_SetCommonPathInternalCh(__LL_ADC_COMMON_INSTANCE(data->adc_base),
59 				       LL_ADC_PATH_INTERNAL_VREFINT | path);
60 
61 #ifdef LL_ADC_DELAY_VREFINT_STAB_US
62 	k_usleep(LL_ADC_DELAY_VREFINT_STAB_US);
63 #endif
64 
65 	rc = adc_read(data->adc, sp);
66 	if (rc == 0) {
67 		data->raw = data->sample_buffer;
68 	}
69 
70 	path = LL_ADC_GetCommonPathInternalCh(__LL_ADC_COMMON_INSTANCE(data->adc_base));
71 	LL_ADC_SetCommonPathInternalCh(__LL_ADC_COMMON_INSTANCE(data->adc_base),
72 				       path &= ~LL_ADC_PATH_INTERNAL_VREFINT);
73 
74 
75 unlock:
76 	pm_device_runtime_put(data->adc);
77 	k_mutex_unlock(&data->mutex);
78 
79 	return rc;
80 }
81 
stm32_vref_channel_get(const struct device * dev,enum sensor_channel chan,struct sensor_value * val)82 static int stm32_vref_channel_get(const struct device *dev, enum sensor_channel chan,
83 				  struct sensor_value *val)
84 {
85 	struct stm32_vref_data *data = dev->data;
86 	const struct stm32_vref_config *cfg = dev->config;
87 	int32_t vref;
88 
89 	if (chan != SENSOR_CHAN_VOLTAGE) {
90 		return -ENOTSUP;
91 	}
92 
93 	if (data->raw == 0) {
94 		LOG_ERR("Raw ADC value is zero");
95 		return -ENODATA;
96 	}
97 
98 /*
99  * STM32H5X: accesses to flash RO region must be done with caching disabled.
100  */
101 #if defined(CONFIG_SOC_SERIES_STM32H5X)
102 	LL_ICACHE_Disable();
103 #endif /* CONFIG_SOC_SERIES_STM32H5X */
104 
105 	/* Calculate VREF+ using VREFINT bandgap voltage and calibration data */
106 #if defined(CONFIG_SOC_SERIES_STM32U5X)
107 	/*
108 	 * The VREF CALIBRATION value is acquired on 14 bits
109 	 * and the data acquired is on 12 bits
110 	 * since the adc_sequence.resolution is 12
111 	 */
112 	vref = (cfg->cal_mv * (*cfg->cal_addr) >> 2) / data->raw;
113 #else
114 	vref = cfg->cal_mv * (*cfg->cal_addr) / data->raw;
115 #endif /* CONFIG_SOC_SERIES_STM32H5X */
116 
117 #if defined(CONFIG_SOC_SERIES_STM32H5X)
118 	LL_ICACHE_Enable();
119 #endif /* CONFIG_SOC_SERIES_STM32H5X */
120 
121 	return sensor_value_from_milli(val, vref);
122 }
123 
124 static const struct sensor_driver_api stm32_vref_driver_api = {
125 	.sample_fetch = stm32_vref_sample_fetch,
126 	.channel_get = stm32_vref_channel_get,
127 };
128 
stm32_vref_init(const struct device * dev)129 static int stm32_vref_init(const struct device *dev)
130 {
131 	struct stm32_vref_data *data = dev->data;
132 	struct adc_sequence *asp = &data->adc_seq;
133 
134 	k_mutex_init(&data->mutex);
135 
136 	if (!device_is_ready(data->adc)) {
137 		LOG_ERR("Device %s is not ready", data->adc->name);
138 		return -ENODEV;
139 	}
140 
141 	*asp = (struct adc_sequence){
142 		.channels = BIT(data->adc_cfg.channel_id),
143 		.buffer = &data->sample_buffer,
144 		.buffer_size = sizeof(data->sample_buffer),
145 		.resolution = 12U,
146 	};
147 
148 	return 0;
149 }
150 
151 /**
152  * Verify that the ADC instance which this driver uses to measure internal
153  * voltage reference is enabled. On STM32 MCUs with more than one ADC, it is
154  * possible to compile this driver even if the ADC used for measurement is
155  * disabled. In such cases, fail build with an explicit error message.
156  */
157 #if !DT_NODE_HAS_STATUS(DT_INST_IO_CHANNELS_CTLR(0), okay)
158 
159 /* Use BUILD_ASSERT to get preprocessing on the message */
160 BUILD_ASSERT(0,	"ADC '" DT_NODE_FULL_NAME(DT_INST_IO_CHANNELS_CTLR(0)) "' needed by "
161 		"Vref sensor '" DT_NODE_FULL_NAME(DT_DRV_INST(0)) "' is not enabled");
162 
163 /* To reduce noise in the compiler error log, do not attempt
164  * to instantiate device if the sensor's ADC is not enabled.
165  */
166 #else
167 
168 static struct stm32_vref_data stm32_vref_dev_data = {
169 	.adc = DEVICE_DT_GET(DT_INST_IO_CHANNELS_CTLR(0)),
170 	.adc_base = (ADC_TypeDef *)DT_REG_ADDR(DT_INST_IO_CHANNELS_CTLR(0)),
171 	.adc_cfg = {.gain = ADC_GAIN_1,
172 		    .reference = ADC_REF_INTERNAL,
173 		    .acquisition_time = ADC_ACQ_TIME_MAX,
174 		    .channel_id = DT_INST_IO_CHANNELS_INPUT(0),
175 		    .differential = 0},
176 };
177 
178 static const struct stm32_vref_config stm32_vref_dev_config = {
179 	.cal_addr = (uint16_t *)DT_INST_PROP(0, vrefint_cal_addr),
180 	.cal_mv = DT_INST_PROP(0, vrefint_cal_mv),
181 };
182 
183 SENSOR_DEVICE_DT_INST_DEFINE(0, stm32_vref_init, NULL, &stm32_vref_dev_data, &stm32_vref_dev_config,
184 			     POST_KERNEL, CONFIG_SENSOR_INIT_PRIORITY, &stm32_vref_driver_api);
185 
186 #endif /* !DT_NODE_HAS_STATUS(DT_INST_IO_CHANNELS_CTLR(0), okay) */
187