1 /*
2  * Copyright (c) 2019 Vestas Wind Systems A/S
3  *
4  * Based on adc_mcux_adc16.c, which is:
5  * Copyright (c) 2017-2018, NXP
6  *
7  * SPDX-License-Identifier: Apache-2.0
8  */
9 
10 #define DT_DRV_COMPAT nxp_adc12
11 
12 #include <zephyr/drivers/adc.h>
13 #include <fsl_adc12.h>
14 #include <zephyr/drivers/pinctrl.h>
15 
16 #define LOG_LEVEL CONFIG_ADC_LOG_LEVEL
17 #include <zephyr/logging/log.h>
18 #include <zephyr/irq.h>
19 LOG_MODULE_REGISTER(adc_mcux_adc12);
20 
21 #define ADC_CONTEXT_USES_KERNEL_TIMER
22 #include "adc_context.h"
23 
24 struct mcux_adc12_config {
25 	ADC_Type *base;
26 	adc12_clock_source_t clock_src;
27 	adc12_clock_divider_t clock_div;
28 	adc12_reference_voltage_source_t ref_src;
29 	uint32_t sample_clk_count;
30 	void (*irq_config_func)(const struct device *dev);
31 	const struct pinctrl_dev_config *pincfg;
32 };
33 
34 struct mcux_adc12_data {
35 	const struct device *dev;
36 	struct adc_context ctx;
37 	uint16_t *buffer;
38 	uint16_t *repeat_buffer;
39 	uint32_t channels;
40 	uint8_t channel_id;
41 };
42 
mcux_adc12_channel_setup(const struct device * dev,const struct adc_channel_cfg * channel_cfg)43 static int mcux_adc12_channel_setup(const struct device *dev,
44 				    const struct adc_channel_cfg *channel_cfg)
45 {
46 	uint8_t channel_id = channel_cfg->channel_id;
47 
48 	if (channel_id > (ADC_SC1_ADCH_MASK >> ADC_SC1_ADCH_SHIFT)) {
49 		LOG_ERR("Invalid channel %d", channel_id);
50 		return -EINVAL;
51 	}
52 
53 	if (channel_cfg->acquisition_time != ADC_ACQ_TIME_DEFAULT) {
54 		LOG_ERR("Unsupported channel acquisition time");
55 		return -ENOTSUP;
56 	}
57 
58 	if (channel_cfg->differential) {
59 		LOG_ERR("Differential channels are not supported");
60 		return -ENOTSUP;
61 	}
62 
63 	if (channel_cfg->gain != ADC_GAIN_1) {
64 		LOG_ERR("Unsupported channel gain %d", channel_cfg->gain);
65 		return -ENOTSUP;
66 	}
67 
68 	if (channel_cfg->reference != ADC_REF_INTERNAL) {
69 		LOG_ERR("Unsupported channel reference");
70 		return -ENOTSUP;
71 	}
72 
73 	return 0;
74 }
75 
mcux_adc12_start_read(const struct device * dev,const struct adc_sequence * sequence)76 static int mcux_adc12_start_read(const struct device *dev,
77 				 const struct adc_sequence *sequence)
78 {
79 	const struct mcux_adc12_config *config = dev->config;
80 	struct mcux_adc12_data *data = dev->data;
81 	adc12_hardware_average_mode_t mode;
82 	adc12_resolution_t resolution;
83 	ADC_Type *base = config->base;
84 	int error;
85 	uint32_t tmp32;
86 
87 	switch (sequence->resolution) {
88 	case 8:
89 		resolution = kADC12_Resolution8Bit;
90 		break;
91 	case 10:
92 		resolution = kADC12_Resolution10Bit;
93 		break;
94 	case 12:
95 		resolution = kADC12_Resolution12Bit;
96 		break;
97 	default:
98 		LOG_ERR("Unsupported resolution %d", sequence->resolution);
99 		return -ENOTSUP;
100 	}
101 
102 	tmp32 = base->CFG1 & ~(ADC_CFG1_MODE_MASK);
103 	tmp32 |= ADC_CFG1_MODE(resolution);
104 	base->CFG1 = tmp32;
105 
106 	switch (sequence->oversampling) {
107 	case 0:
108 		mode = kADC12_HardwareAverageDisabled;
109 		break;
110 	case 2:
111 		mode = kADC12_HardwareAverageCount4;
112 		break;
113 	case 3:
114 		mode = kADC12_HardwareAverageCount8;
115 		break;
116 	case 4:
117 		mode = kADC12_HardwareAverageCount16;
118 		break;
119 	case 5:
120 		mode = kADC12_HardwareAverageCount32;
121 		break;
122 	default:
123 		LOG_ERR("Unsupported oversampling value %d",
124 			sequence->oversampling);
125 		return -ENOTSUP;
126 	}
127 	ADC12_SetHardwareAverage(config->base, mode);
128 
129 	data->buffer = sequence->buffer;
130 	adc_context_start_read(&data->ctx, sequence);
131 	error = adc_context_wait_for_completion(&data->ctx);
132 
133 	return error;
134 }
135 
mcux_adc12_read_async(const struct device * dev,const struct adc_sequence * sequence,struct k_poll_signal * async)136 static int mcux_adc12_read_async(const struct device *dev,
137 				 const struct adc_sequence *sequence,
138 				 struct k_poll_signal *async)
139 {
140 	struct mcux_adc12_data *data = dev->data;
141 	int error;
142 
143 	adc_context_lock(&data->ctx, async ? true : false, async);
144 	error = mcux_adc12_start_read(dev, sequence);
145 	adc_context_release(&data->ctx, error);
146 
147 	return error;
148 }
149 
mcux_adc12_read(const struct device * dev,const struct adc_sequence * sequence)150 static int mcux_adc12_read(const struct device *dev,
151 			   const struct adc_sequence *sequence)
152 {
153 	return mcux_adc12_read_async(dev, sequence, NULL);
154 }
155 
mcux_adc12_start_channel(const struct device * dev)156 static void mcux_adc12_start_channel(const struct device *dev)
157 {
158 	const struct mcux_adc12_config *config = dev->config;
159 	struct mcux_adc12_data *data = dev->data;
160 
161 	adc12_channel_config_t channel_config;
162 	uint32_t channel_group = 0U;
163 
164 	data->channel_id = find_lsb_set(data->channels) - 1;
165 
166 	LOG_DBG("Starting channel %d", data->channel_id);
167 	channel_config.enableInterruptOnConversionCompleted = true;
168 	channel_config.channelNumber = data->channel_id;
169 #if defined(CONFIG_SOC_S32K146) || defined(CONFIG_SOC_S32K148)
170 	if (data->channel_id >= 16) {
171 		/*
172 		 * channels 16..31 are encoded as 100000b..101111b in
173 		 * SC1[ADCH] field
174 		 */
175 		channel_config.channelNumber += 16;
176 	}
177 #endif
178 	ADC12_SetChannelConfig(config->base, channel_group, &channel_config);
179 }
180 
adc_context_start_sampling(struct adc_context * ctx)181 static void adc_context_start_sampling(struct adc_context *ctx)
182 {
183 	struct mcux_adc12_data *data =
184 		CONTAINER_OF(ctx, struct mcux_adc12_data, ctx);
185 
186 	data->channels = ctx->sequence.channels;
187 	data->repeat_buffer = data->buffer;
188 
189 	mcux_adc12_start_channel(data->dev);
190 }
191 
adc_context_update_buffer_pointer(struct adc_context * ctx,bool repeat_sampling)192 static void adc_context_update_buffer_pointer(struct adc_context *ctx,
193 					      bool repeat_sampling)
194 {
195 	struct mcux_adc12_data *data =
196 		CONTAINER_OF(ctx, struct mcux_adc12_data, ctx);
197 
198 	if (repeat_sampling) {
199 		data->buffer = data->repeat_buffer;
200 	}
201 }
202 
mcux_adc12_isr(const struct device * dev)203 static void mcux_adc12_isr(const struct device *dev)
204 {
205 	const struct mcux_adc12_config *config = dev->config;
206 	struct mcux_adc12_data *data = dev->data;
207 	ADC_Type *base = config->base;
208 	uint32_t channel_group = 0U;
209 	uint16_t result;
210 
211 	result = ADC12_GetChannelConversionValue(base, channel_group);
212 	LOG_DBG("Finished channel %d. Result is 0x%04x",
213 		data->channel_id, result);
214 
215 	*data->buffer++ = result;
216 	data->channels &= ~BIT(data->channel_id);
217 
218 	if (data->channels) {
219 		mcux_adc12_start_channel(dev);
220 	} else {
221 		adc_context_on_sampling_done(&data->ctx, dev);
222 	}
223 }
224 
mcux_adc12_init(const struct device * dev)225 static int mcux_adc12_init(const struct device *dev)
226 {
227 	const struct mcux_adc12_config *config = dev->config;
228 	struct mcux_adc12_data *data = dev->data;
229 	ADC_Type *base = config->base;
230 	adc12_config_t adc_config;
231 	int err;
232 
233 	ADC12_GetDefaultConfig(&adc_config);
234 
235 	adc_config.referenceVoltageSource = config->ref_src;
236 	adc_config.clockSource = config->clock_src;
237 	adc_config.clockDivider = config->clock_div;
238 	adc_config.sampleClockCount = config->sample_clk_count;
239 	adc_config.resolution = kADC12_Resolution12Bit;
240 	adc_config.enableContinuousConversion = false;
241 
242 	ADC12_Init(base, &adc_config);
243 	ADC12_DoAutoCalibration(base);
244 	ADC12_EnableHardwareTrigger(base, false);
245 
246 	config->irq_config_func(dev);
247 	data->dev = dev;
248 
249 	err = pinctrl_apply_state(config->pincfg, PINCTRL_STATE_DEFAULT);
250 	if (err) {
251 		return err;
252 	}
253 
254 	adc_context_unlock_unconditionally(&data->ctx);
255 
256 	return 0;
257 }
258 
259 #define ASSERT_WITHIN_RANGE(val, min, max, str) \
260 	BUILD_ASSERT(val >= min && val <= max, str)
261 #define ASSERT_ADC12_CLK_DIV_VALID(val, str) \
262 	BUILD_ASSERT(val == 1 || val == 2 || val == 4 || val == 8, str)
263 #define TO_ADC12_CLOCK_SRC(val) _DO_CONCAT(kADC12_ClockSourceAlt, val)
264 #define TO_ADC12_CLOCK_DIV(val) _DO_CONCAT(kADC12_ClockDivider, val)
265 
266 #define ADC12_REF_SRC(n)						\
267 	COND_CODE_1(DT_INST_PROP(0, alternate_voltage_reference),	\
268 				 (kADC12_ReferenceVoltageSourceValt),	\
269 				 (kADC12_ReferenceVoltageSourceVref))
270 
271 #define ADC12_MCUX_DRIVER_API(n)				\
272 	static DEVICE_API(adc, mcux_adc12_driver_api_##n) = {	\
273 		.channel_setup = mcux_adc12_channel_setup,	\
274 		.read = mcux_adc12_read,	\
275 		IF_ENABLED(CONFIG_ADC_ASYNC, (.read_async = mcux_adc12_read_async,))	\
276 		.ref_internal = DT_INST_PROP(n, vref_mv),	\
277 	};
278 
279 #define ACD12_MCUX_INIT(n)						\
280 	static void mcux_adc12_config_func_##n(const struct device *dev); \
281 									\
282 	PINCTRL_DT_INST_DEFINE(n);					\
283 	ADC12_MCUX_DRIVER_API(n);					\
284 									\
285 	ASSERT_WITHIN_RANGE(DT_INST_PROP(n, clk_source), 0, 3,		\
286 			    "Invalid clock source");			\
287 	ASSERT_ADC12_CLK_DIV_VALID(DT_INST_PROP(n, clk_divider),	\
288 				   "Invalid clock divider");		\
289 	ASSERT_WITHIN_RANGE(DT_INST_PROP(n, sample_time), 2, 256,	\
290 			    "Invalid sample time");			\
291 	static const struct mcux_adc12_config mcux_adc12_config_##n = {	\
292 		.base = (ADC_Type *)DT_INST_REG_ADDR(n),		\
293 		.clock_src = TO_ADC12_CLOCK_SRC(DT_INST_PROP(n, clk_source)),\
294 		.clock_div =						\
295 			TO_ADC12_CLOCK_DIV(DT_INST_PROP(n, clk_divider)),\
296 		.ref_src = ADC12_REF_SRC(n),				\
297 		.sample_clk_count = DT_INST_PROP(n, sample_time),	\
298 		.irq_config_func = mcux_adc12_config_func_##n,		\
299 		.pincfg = PINCTRL_DT_INST_DEV_CONFIG_GET(n),		\
300 	};								\
301 									\
302 	static struct mcux_adc12_data mcux_adc12_data_##n = {		\
303 		ADC_CONTEXT_INIT_TIMER(mcux_adc12_data_##n, ctx),	\
304 		ADC_CONTEXT_INIT_LOCK(mcux_adc12_data_##n, ctx),	\
305 		ADC_CONTEXT_INIT_SYNC(mcux_adc12_data_##n, ctx),	\
306 	};								\
307 									\
308 	DEVICE_DT_INST_DEFINE(n, &mcux_adc12_init,			\
309 			    NULL, &mcux_adc12_data_##n,			\
310 			    &mcux_adc12_config_##n, POST_KERNEL,	\
311 			    CONFIG_ADC_INIT_PRIORITY,			\
312 			    &mcux_adc12_driver_api_##n);		\
313 									\
314 	static void mcux_adc12_config_func_##n(const struct device *dev) \
315 	{								\
316 		IRQ_CONNECT(DT_INST_IRQN(n),				\
317 			    DT_INST_IRQ(n, priority), mcux_adc12_isr,	\
318 			    DEVICE_DT_INST_GET(n), 0);			\
319 									\
320 		irq_enable(DT_INST_IRQN(n));				\
321 	}
322 
323 DT_INST_FOREACH_STATUS_OKAY(ACD12_MCUX_INIT)
324