1 /*
2  * Copyright (c) 2023 Grinn
3  * SPDX-License-Identifier: Apache-2.0
4  */
5 
6 #define DT_DRV_COMPAT adi_ad559x_adc
7 
8 #include <zephyr/drivers/adc.h>
9 #include <zephyr/kernel.h>
10 #include <zephyr/sys/byteorder.h>
11 
12 #include <zephyr/drivers/mfd/ad559x.h>
13 
14 #define ADC_CONTEXT_USES_KERNEL_TIMER
15 #include "adc_context.h"
16 
17 #include <zephyr/logging/log.h>
18 LOG_MODULE_REGISTER(adc_ad559x, CONFIG_ADC_LOG_LEVEL);
19 
20 #define AD559X_ADC_RD_POINTER_SIZE 1
21 #define AD559X_ADC_RD_POINTER      0x40
22 
23 #define AD559X_ADC_RESOLUTION 12U
24 #define AD559X_ADC_VREF_MV 2500U
25 
26 #define AD559X_ADC_RES_IND_BIT BIT(15)
27 #define AD559X_ADC_RES_CHAN_MASK GENMASK(14, 12)
28 #define AD559X_ADC_RES_VAL_MASK GENMASK(11, 0)
29 
30 struct adc_ad559x_config {
31 	const struct device *mfd_dev;
32 };
33 
34 struct adc_ad559x_data {
35 	struct adc_context ctx;
36 	const struct device *dev;
37 	uint8_t adc_conf;
38 	uint16_t *buffer;
39 	uint16_t *repeat_buffer;
40 	uint8_t channels;
41 	struct k_thread thread;
42 	struct k_sem sem;
43 
44 	K_KERNEL_STACK_MEMBER(stack, CONFIG_ADC_AD559X_ACQUISITION_THREAD_STACK_SIZE);
45 };
46 
adc_ad559x_channel_setup(const struct device * dev,const struct adc_channel_cfg * channel_cfg)47 static int adc_ad559x_channel_setup(const struct device *dev,
48 				    const struct adc_channel_cfg *channel_cfg)
49 {
50 	const struct adc_ad559x_config *config = dev->config;
51 	struct adc_ad559x_data *data = dev->data;
52 
53 	if (channel_cfg->channel_id >= AD559X_PIN_MAX) {
54 		LOG_ERR("invalid channel id %d", channel_cfg->channel_id);
55 		return -EINVAL;
56 	}
57 
58 	data->adc_conf |= BIT(channel_cfg->channel_id);
59 
60 	return mfd_ad559x_write_reg(config->mfd_dev, AD559X_REG_ADC_CONFIG, data->adc_conf);
61 }
62 
adc_ad559x_validate_buffer_size(const struct device * dev,const struct adc_sequence * sequence)63 static int adc_ad559x_validate_buffer_size(const struct device *dev,
64 					   const struct adc_sequence *sequence)
65 {
66 	uint8_t channels;
67 	size_t needed;
68 
69 	channels = POPCOUNT(sequence->channels);
70 	needed = channels * sizeof(uint16_t);
71 
72 	if (sequence->buffer_size < needed) {
73 		return -ENOMEM;
74 	}
75 
76 	return 0;
77 }
78 
adc_ad559x_start_read(const struct device * dev,const struct adc_sequence * sequence)79 static int adc_ad559x_start_read(const struct device *dev, const struct adc_sequence *sequence)
80 {
81 	struct adc_ad559x_data *data = dev->data;
82 	int ret;
83 
84 	if (sequence->resolution != AD559X_ADC_RESOLUTION) {
85 		LOG_ERR("invalid resolution %d", sequence->resolution);
86 		return -EINVAL;
87 	}
88 
89 	if (find_msb_set(sequence->channels) > AD559X_PIN_MAX) {
90 		LOG_ERR("invalid channels in mask: 0x%08x", sequence->channels);
91 		return -EINVAL;
92 	}
93 
94 	ret = adc_ad559x_validate_buffer_size(dev, sequence);
95 	if (ret < 0) {
96 		LOG_ERR("insufficient buffer size");
97 		return ret;
98 	}
99 
100 	data->buffer = sequence->buffer;
101 	adc_context_start_read(&data->ctx, sequence);
102 
103 	return adc_context_wait_for_completion(&data->ctx);
104 }
105 
adc_ad559x_read_channel(const struct device * dev,uint8_t channel,uint16_t * result)106 static int adc_ad559x_read_channel(const struct device *dev, uint8_t channel, uint16_t *result)
107 {
108 	const struct adc_ad559x_config *config = dev->config;
109 	uint16_t val;
110 	uint8_t conv_channel;
111 	int ret;
112 
113 	/* Select channel */
114 	ret = mfd_ad559x_write_reg(config->mfd_dev, AD559X_REG_SEQ_ADC, BIT(channel));
115 	if (ret < 0) {
116 		return ret;
117 	}
118 
119 	if (mfd_ad559x_has_pointer_byte_map(config->mfd_dev)) {
120 		/* Start readback */
121 		val = AD559X_ADC_RD_POINTER;
122 		ret = mfd_ad559x_write_raw(config->mfd_dev, (uint8_t *)&val,
123 					   AD559X_ADC_RD_POINTER_SIZE);
124 		if (ret < 0) {
125 			return ret;
126 		}
127 
128 		/* Read channel */
129 		ret = mfd_ad559x_read_raw(config->mfd_dev, (uint8_t *)&val, sizeof(val));
130 		if (ret < 0) {
131 			return ret;
132 		}
133 	} else {
134 		/*
135 		 * Invalid data:
136 		 * See Figure 46. Single-Channel ADC Conversion Sequence.
137 		 * The first conversion result always returns invalid data.
138 		 */
139 		(void)mfd_ad559x_read_raw(config->mfd_dev, (uint8_t *)&val, sizeof(val));
140 
141 		ret = mfd_ad559x_read_raw(config->mfd_dev, (uint8_t *)&val, sizeof(val));
142 		if (ret < 0) {
143 			return ret;
144 		}
145 	}
146 
147 	val = sys_be16_to_cpu(val);
148 
149 	/*
150 	 * Invalid data:
151 	 * See AD5592 "ADC section" in "Theory of operation" chapter.
152 	 * Valid ADC result has MSB bit set to 0.
153 	 */
154 	if ((val & AD559X_ADC_RES_IND_BIT) != 0) {
155 		return -EAGAIN;
156 	}
157 
158 	/*
159 	 * Invalid channel converted:
160 	 * See AD5592 "ADC section" in "Theory of operation" chapter.
161 	 * Conversion result contains channel number which should match requested channel.
162 	 */
163 	conv_channel = FIELD_GET(AD559X_ADC_RES_CHAN_MASK, val);
164 	if (conv_channel != channel) {
165 		return -EIO;
166 	}
167 
168 	*result = val & AD559X_ADC_RES_VAL_MASK;
169 
170 	return 0;
171 }
172 
adc_context_start_sampling(struct adc_context * ctx)173 static void adc_context_start_sampling(struct adc_context *ctx)
174 {
175 	struct adc_ad559x_data *data = CONTAINER_OF(ctx, struct adc_ad559x_data, ctx);
176 
177 	data->channels = ctx->sequence.channels;
178 	data->repeat_buffer = data->buffer;
179 
180 	k_sem_give(&data->sem);
181 }
182 
adc_context_update_buffer_pointer(struct adc_context * ctx,bool repeat_sampling)183 static void adc_context_update_buffer_pointer(struct adc_context *ctx, bool repeat_sampling)
184 {
185 	struct adc_ad559x_data *data = CONTAINER_OF(ctx, struct adc_ad559x_data, ctx);
186 
187 	if (repeat_sampling) {
188 		data->buffer = data->repeat_buffer;
189 	}
190 }
191 
adc_ad559x_acquisition_thread(struct adc_ad559x_data * data)192 static void adc_ad559x_acquisition_thread(struct adc_ad559x_data *data)
193 {
194 	uint16_t result;
195 	uint8_t channel;
196 	int ret;
197 
198 	while (true) {
199 		k_sem_take(&data->sem, K_FOREVER);
200 
201 		while (data->channels != 0) {
202 			channel = find_lsb_set(data->channels) - 1;
203 
204 			ret = adc_ad559x_read_channel(data->dev, channel, &result);
205 			if (ret < 0) {
206 				LOG_ERR("failed to read channel %d (ret %d)", channel, ret);
207 				adc_context_complete(&data->ctx, ret);
208 				break;
209 			}
210 
211 			*data->buffer++ = result;
212 			WRITE_BIT(data->channels, channel, 0);
213 		}
214 
215 		adc_context_on_sampling_done(&data->ctx, data->dev);
216 	}
217 }
218 
adc_ad559x_read_async(const struct device * dev,const struct adc_sequence * sequence,struct k_poll_signal * async)219 static int adc_ad559x_read_async(const struct device *dev, const struct adc_sequence *sequence,
220 				 struct k_poll_signal *async)
221 {
222 	struct adc_ad559x_data *data = dev->data;
223 	int ret;
224 
225 	adc_context_lock(&data->ctx, async ? true : false, async);
226 	ret = adc_ad559x_start_read(dev, sequence);
227 	adc_context_release(&data->ctx, ret);
228 
229 	return ret;
230 }
231 
adc_ad559x_read(const struct device * dev,const struct adc_sequence * sequence)232 static int adc_ad559x_read(const struct device *dev, const struct adc_sequence *sequence)
233 {
234 	return adc_ad559x_read_async(dev, sequence, NULL);
235 }
236 
adc_ad559x_init(const struct device * dev)237 static int adc_ad559x_init(const struct device *dev)
238 {
239 	const struct adc_ad559x_config *config = dev->config;
240 	struct adc_ad559x_data *data = dev->data;
241 	k_tid_t tid;
242 	int ret;
243 
244 	if (!device_is_ready(config->mfd_dev)) {
245 		return -ENODEV;
246 	}
247 
248 	ret = mfd_ad559x_write_reg(config->mfd_dev, AD559X_REG_PD_REF_CTRL, AD559X_EN_REF);
249 	if (ret < 0) {
250 		return ret;
251 	}
252 
253 	data->dev = dev;
254 
255 	k_sem_init(&data->sem, 0, 1);
256 	adc_context_init(&data->ctx);
257 
258 	tid = k_thread_create(&data->thread, data->stack,
259 			K_KERNEL_STACK_SIZEOF(data->stack),
260 			(k_thread_entry_t)adc_ad559x_acquisition_thread, data, NULL, NULL,
261 			CONFIG_ADC_AD559X_ACQUISITION_THREAD_PRIO, 0, K_NO_WAIT);
262 
263 	if (IS_ENABLED(CONFIG_THREAD_NAME)) {
264 		ret = k_thread_name_set(tid, "adc_ad559x");
265 		if (ret < 0) {
266 			return ret;
267 		}
268 	}
269 
270 	adc_context_unlock_unconditionally(&data->ctx);
271 
272 	return 0;
273 }
274 
275 static const struct adc_driver_api adc_ad559x_api = {
276 	.channel_setup = adc_ad559x_channel_setup,
277 	.read = adc_ad559x_read,
278 #ifdef CONFIG_ADC_ASYNC
279 	.read_async = adc_ad559x_read_async,
280 #endif
281 	.ref_internal = AD559X_ADC_VREF_MV,
282 };
283 
284 #define ADC_AD559X_DEFINE(inst)                                                                    \
285 	static const struct adc_ad559x_config adc_ad559x_config##inst = {                          \
286 		.mfd_dev = DEVICE_DT_GET(DT_INST_PARENT(inst)),                                    \
287 	};                                                                                         \
288                                                                                                    \
289 	static struct adc_ad559x_data adc_ad559x_data##inst;                                       \
290                                                                                                    \
291 	DEVICE_DT_INST_DEFINE(inst, adc_ad559x_init, NULL, &adc_ad559x_data##inst,                 \
292 			      &adc_ad559x_config##inst, POST_KERNEL, CONFIG_MFD_INIT_PRIORITY,     \
293 			      &adc_ad559x_api);
294 
295 DT_INST_FOREACH_STATUS_OKAY(ADC_AD559X_DEFINE)
296