blob: 5fbed6d9aa82de1daf2a64bd4ac507f95007ba1a [file] [log] [blame]
Andrzej Głąbekaad21ec2018-05-21 15:01:08 +02001/*
2 * Copyright (c) 2018 Nordic Semiconductor ASA
3 *
4 * SPDX-License-Identifier: Apache-2.0
5 */
6
7#define ADC_CONTEXT_USES_KERNEL_TIMER
8#include "adc_context.h"
9#include <nrfx_adc.h>
10
Anas Nashif9a8567f2018-09-17 12:00:47 -050011#define LOG_LEVEL CONFIG_ADC_LOG_LEVEL
12#include <logging/log.h>
Andrzej Głąbek7c52bf92018-12-14 11:36:13 +010013LOG_MODULE_REGISTER(adc_nrfx_adc);
Andrzej Głąbekaad21ec2018-05-21 15:01:08 +020014
15struct driver_data {
16 struct adc_context ctx;
17
18 nrf_adc_value_t *buffer;
19 u8_t active_channels;
20};
21
22static struct driver_data m_data = {
23 ADC_CONTEXT_INIT_TIMER(m_data, ctx),
24 ADC_CONTEXT_INIT_LOCK(m_data, ctx),
25 ADC_CONTEXT_INIT_SYNC(m_data, ctx),
26};
27
28static nrfx_adc_channel_t m_channels[CONFIG_ADC_NRFX_ADC_CHANNEL_COUNT];
29
30
31/* Implementation of the ADC driver API function: adc_channel_setup. */
32static int adc_nrfx_channel_setup(struct device *dev,
33 const struct adc_channel_cfg *channel_cfg)
34{
35 u8_t channel_id = channel_cfg->channel_id;
36 nrf_adc_config_t *config = &m_channels[channel_id].config;
37
38 if (channel_id >= CONFIG_ADC_NRFX_ADC_CHANNEL_COUNT) {
39 return -EINVAL;
40 }
41
42 if (channel_cfg->acquisition_time != ADC_ACQ_TIME_DEFAULT) {
Anas Nashif9a8567f2018-09-17 12:00:47 -050043 LOG_ERR("Selected ADC acquisition time is not valid");
Andrzej Głąbekaad21ec2018-05-21 15:01:08 +020044 return -EINVAL;
45 }
46
47 if (channel_cfg->differential) {
Anas Nashif9a8567f2018-09-17 12:00:47 -050048 LOG_ERR("Differential channels are not supported");
Andrzej Głąbekaad21ec2018-05-21 15:01:08 +020049 return -EINVAL;
50 }
51
52 switch (channel_cfg->gain) {
53 case ADC_GAIN_1_3:
54 config->scaling = NRF_ADC_CONFIG_SCALING_INPUT_ONE_THIRD;
55 break;
56 case ADC_GAIN_2_3:
57 config->scaling = NRF_ADC_CONFIG_SCALING_INPUT_TWO_THIRDS;
58 break;
59 case ADC_GAIN_1:
60 config->scaling = NRF_ADC_CONFIG_SCALING_INPUT_FULL_SCALE;
61 break;
62 default:
Anas Nashif9a8567f2018-09-17 12:00:47 -050063 LOG_ERR("Selected ADC gain is not valid");
Andrzej Głąbekaad21ec2018-05-21 15:01:08 +020064 return -EINVAL;
65 }
66
67 switch (channel_cfg->reference) {
68 case ADC_REF_INTERNAL:
69 config->reference = NRF_ADC_CONFIG_REF_VBG;
70 config->extref = NRF_ADC_CONFIG_EXTREFSEL_NONE;
71 break;
72 case ADC_REF_VDD_1_2:
73 config->reference = NRF_ADC_CONFIG_REF_SUPPLY_ONE_HALF;
74 config->extref = NRF_ADC_CONFIG_EXTREFSEL_NONE;
75 break;
76 case ADC_REF_VDD_1_3:
77 config->reference = NRF_ADC_CONFIG_REF_SUPPLY_ONE_THIRD;
78 config->extref = NRF_ADC_CONFIG_EXTREFSEL_NONE;
79 break;
80 case ADC_REF_EXTERNAL0:
81 config->reference = NRF_ADC_CONFIG_REF_EXT;
82 config->extref = NRF_ADC_CONFIG_EXTREFSEL_AREF0;
83 break;
84 case ADC_REF_EXTERNAL1:
85 config->reference = NRF_ADC_CONFIG_REF_EXT;
86 config->extref = NRF_ADC_CONFIG_EXTREFSEL_AREF1;
87 break;
88 default:
Anas Nashif9a8567f2018-09-17 12:00:47 -050089 LOG_ERR("Selected ADC reference is not valid");
Andrzej Głąbekaad21ec2018-05-21 15:01:08 +020090 return -EINVAL;
91 }
92
93 config->input = channel_cfg->input_positive;
94
95 config->resolution = NRF_ADC_CONFIG_RES_8BIT;
96
97 return 0;
98}
99
100static void adc_context_start_sampling(struct adc_context *ctx)
101{
102 ARG_UNUSED(ctx);
103
104 nrfx_adc_buffer_convert(m_data.buffer, m_data.active_channels);
105 nrfx_adc_sample();
106}
107
108static void adc_context_update_buffer_pointer(struct adc_context *ctx,
109 bool repeat)
110{
111 ARG_UNUSED(ctx);
112
113 if (!repeat) {
114 m_data.buffer += m_data.active_channels;
115 }
116}
117
118static int check_buffer_size(const struct adc_sequence *sequence,
119 u8_t active_channels)
120{
121 size_t needed_buffer_size;
122
123 needed_buffer_size = active_channels * sizeof(nrf_adc_value_t);
124 if (sequence->options) {
125 needed_buffer_size *= (1 + sequence->options->extra_samplings);
126 }
127
128 if (sequence->buffer_size < needed_buffer_size) {
Anas Nashif9a8567f2018-09-17 12:00:47 -0500129 LOG_ERR("Provided buffer is too small (%u/%u)",
Andrzej Głąbekaad21ec2018-05-21 15:01:08 +0200130 sequence->buffer_size, needed_buffer_size);
131 return -ENOMEM;
132 }
133
134 return 0;
135}
136
137static int start_read(struct device *dev, const struct adc_sequence *sequence)
138{
Andrzej Głąbek0906a512018-12-17 08:04:10 +0100139 int error;
Andrzej Głąbekaad21ec2018-05-21 15:01:08 +0200140 u32_t selected_channels = sequence->channels;
141 u8_t active_channels;
142 u8_t channel_id;
143 nrf_adc_config_resolution_t nrf_resolution;
144
145 /* Signal an error if channel selection is invalid (no channels or
146 * a non-existing one is selected).
147 */
148 if (!selected_channels ||
149 (selected_channels &
150 ~BIT_MASK(CONFIG_ADC_NRFX_ADC_CHANNEL_COUNT))) {
Anas Nashif9a8567f2018-09-17 12:00:47 -0500151 LOG_ERR("Invalid selection of channels");
Andrzej Głąbekaad21ec2018-05-21 15:01:08 +0200152 return -EINVAL;
153 }
154
Patrik Flykt24d71432019-03-26 19:57:45 -0600155 if (sequence->oversampling != 0U) {
Anas Nashif9a8567f2018-09-17 12:00:47 -0500156 LOG_ERR("Oversampling is not supported");
Andrzej Głąbekaad21ec2018-05-21 15:01:08 +0200157 return -EINVAL;
158 }
159
160 switch (sequence->resolution) {
161 case 8:
162 nrf_resolution = NRF_ADC_CONFIG_RES_8BIT;
163 break;
164 case 9:
165 nrf_resolution = NRF_ADC_CONFIG_RES_9BIT;
166 break;
167 case 10:
168 nrf_resolution = NRF_ADC_CONFIG_RES_10BIT;
169 break;
170 default:
Anas Nashif9a8567f2018-09-17 12:00:47 -0500171 LOG_ERR("ADC resolution value %d is not valid",
Andrzej Głąbekaad21ec2018-05-21 15:01:08 +0200172 sequence->resolution);
173 return -EINVAL;
174 }
175
Patrik Flykt8ff96b52018-11-29 11:12:22 -0800176 active_channels = 0U;
Andrzej Głąbekaad21ec2018-05-21 15:01:08 +0200177 nrfx_adc_all_channels_disable();
178
179 /* Enable the channels selected for the pointed sequence.
180 */
Patrik Flykt8ff96b52018-11-29 11:12:22 -0800181 channel_id = 0U;
Andrzej Głąbekaad21ec2018-05-21 15:01:08 +0200182 while (selected_channels) {
183 if (selected_channels & BIT(0)) {
184 /* The nrfx driver requires setting the resolution
185 * for each enabled channel individually.
186 */
187 m_channels[channel_id].config.resolution =
188 nrf_resolution;
189 nrfx_adc_channel_enable(&m_channels[channel_id]);
190 ++active_channels;
191 }
192 selected_channels >>= 1;
193 ++channel_id;
194 }
195
196 error = check_buffer_size(sequence, active_channels);
197 if (error) {
198 return error;
199 }
200
201 m_data.buffer = sequence->buffer;
202 m_data.active_channels = active_channels;
203
204 adc_context_start_read(&m_data.ctx, sequence);
205
Andrzej Głąbek0906a512018-12-17 08:04:10 +0100206 error = adc_context_wait_for_completion(&m_data.ctx);
Andrzej Głąbekaad21ec2018-05-21 15:01:08 +0200207 return error;
208}
209
210/* Implementation of the ADC driver API function: adc_read. */
211static int adc_nrfx_read(struct device *dev,
212 const struct adc_sequence *sequence)
213{
Andrzej Głąbek0906a512018-12-17 08:04:10 +0100214 int error;
215
Andrzej Głąbekaad21ec2018-05-21 15:01:08 +0200216 adc_context_lock(&m_data.ctx, false, NULL);
Andrzej Głąbek0906a512018-12-17 08:04:10 +0100217 error = start_read(dev, sequence);
218 adc_context_release(&m_data.ctx, error);
219
220 return error;
Andrzej Głąbekaad21ec2018-05-21 15:01:08 +0200221}
222
223#ifdef CONFIG_ADC_ASYNC
224/* Implementation of the ADC driver API function: adc_read_sync. */
225static int adc_nrfx_read_async(struct device *dev,
226 const struct adc_sequence *sequence,
227 struct k_poll_signal *async)
228{
Andrzej Głąbek0906a512018-12-17 08:04:10 +0100229 int error;
230
Andrzej Głąbekaad21ec2018-05-21 15:01:08 +0200231 adc_context_lock(&m_data.ctx, true, async);
Andrzej Głąbek0906a512018-12-17 08:04:10 +0100232 error = start_read(dev, sequence);
233 adc_context_release(&m_data.ctx, error);
234
235 return error;
Andrzej Głąbekaad21ec2018-05-21 15:01:08 +0200236}
Andrzej Głąbek0906a512018-12-17 08:04:10 +0100237#endif /* CONFIG_ADC_ASYNC */
Andrzej Głąbekaad21ec2018-05-21 15:01:08 +0200238
239DEVICE_DECLARE(adc_0);
240
241static void event_handler(const nrfx_adc_evt_t *p_event)
242{
243 struct device *dev = DEVICE_GET(adc_0);
244
245 if (p_event->type == NRFX_ADC_EVT_DONE) {
246 adc_context_on_sampling_done(&m_data.ctx, dev);
247 }
248}
249
250static int init_adc(struct device *dev)
251{
252 const nrfx_adc_config_t config = NRFX_ADC_DEFAULT_CONFIG;
253
254 nrfx_err_t result = nrfx_adc_init(&config, event_handler);
255
256 if (result != NRFX_SUCCESS) {
Anas Nashif9a8567f2018-09-17 12:00:47 -0500257 LOG_ERR("Failed to initialize device: %s",
Andrzej Głąbekaad21ec2018-05-21 15:01:08 +0200258 dev->config->name);
259 return -EBUSY;
260 }
261
Kumar Galadba65ce2019-06-19 12:55:29 -0500262 IRQ_CONNECT(DT_NORDIC_NRF_ADC_ADC_0_IRQ_0,
263 DT_NORDIC_NRF_ADC_ADC_0_IRQ_0_PRIORITY,
Andrzej Głąbekaad21ec2018-05-21 15:01:08 +0200264 nrfx_isr, nrfx_adc_irq_handler, 0);
265
266 adc_context_unlock_unconditionally(&m_data.ctx);
267
268 return 0;
269}
270
271static const struct adc_driver_api adc_nrfx_driver_api = {
272 .channel_setup = adc_nrfx_channel_setup,
273 .read = adc_nrfx_read,
274#ifdef CONFIG_ADC_ASYNC
275 .read_async = adc_nrfx_read_async,
276#endif
Peter A. Bigot5a39bca2019-07-29 09:35:33 -0500277 .ref_internal = 1200,
Andrzej Głąbekaad21ec2018-05-21 15:01:08 +0200278};
279
280#ifdef CONFIG_ADC_0
Mieszko Mierunskib370b2b2018-10-03 16:07:41 +0200281DEVICE_AND_API_INIT(adc_0, DT_NORDIC_NRF_ADC_ADC_0_LABEL,
Andrzej Głąbekaad21ec2018-05-21 15:01:08 +0200282 init_adc, NULL, NULL,
283 POST_KERNEL, CONFIG_KERNEL_INIT_PRIORITY_DEVICE,
284 &adc_nrfx_driver_api);
285#endif /* CONFIG_ADC_0 */