Skip to content

Commit 19dd46e

Browse files
scottwcpgcfriedt
authored andcommitted
Microchip: MEC172x: ADC driver
Add ADC driver version 2 for MEC172x using new in-tree headers and device tree properties. Update the ADC shell for the new driver. Signed-off-by: Scott Worley <[email protected]>
1 parent b6bd40f commit 19dd46e

File tree

9 files changed

+418
-1
lines changed

9 files changed

+418
-1
lines changed

boards/arm/mec172xevb_assy6906/mec172xevb_assy6906.dts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -63,3 +63,7 @@
6363
status = "okay";
6464
current-speed = <115200>;
6565
};
66+
67+
&adc0 {
68+
status = "okay";
69+
};

boards/arm/mec172xevb_assy6906/mec172xevb_assy6906_defconfig

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,3 +15,4 @@ CONFIG_PINMUX=y
1515
CONFIG_SERIAL=y
1616
CONFIG_CONSOLE=y
1717
CONFIG_UART_CONSOLE=y
18+
CONFIG_ADC=y

drivers/adc/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,3 +20,4 @@ zephyr_library_sources_ifdef(CONFIG_ADC_NPCX adc_npcx.c)
2020
zephyr_library_sources_ifdef(CONFIG_USERSPACE adc_handlers.c)
2121
zephyr_library_sources_ifdef(CONFIG_ADC_CC32XX adc_cc32xx.c)
2222
zephyr_library_sources_ifdef(CONFIG_ADC_EMUL adc_emul.c)
23+
zephyr_library_sources_ifdef(CONFIG_ADC_XEC_V2 adc_mchp_xec_v2.c)

drivers/adc/Kconfig.xec

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,19 @@
11
# Microchip XEC ADC configuration
22

33
# Copyright (c) 2019 Intel Corporation
4+
# Copyright (c) 2021 Microchip Technology Inc.
45
# SPDX-License-Identifier: Apache-2.0
56

67
config ADC_XEC
78
bool "Microchip XEC series ADC driver"
8-
depends on SOC_FAMILY_MEC
9+
depends on SOC_SERIES_MEC1501X
910
default y
1011
help
1112
Enable ADC driver for Microchip XEC MCU series.
13+
14+
config ADC_XEC_V2
15+
bool "Microchip XEC series ADC V2 driver"
16+
depends on SOC_SERIES_MEC172X
17+
default y
18+
help
19+
Enable ADC driver for Microchip XEC MEC172x MCU series.

drivers/adc/adc_mchp_xec_v2.c

Lines changed: 348 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,348 @@
1+
/*
2+
* Copyright (c) 2019 Intel Corporation.
3+
*
4+
* SPDX-License-Identifier: Apache-2.0
5+
*/
6+
7+
#define DT_DRV_COMPAT microchip_xec_adc_v2
8+
9+
#define LOG_LEVEL CONFIG_ADC_LOG_LEVEL
10+
#include <logging/log.h>
11+
LOG_MODULE_REGISTER(adc_mchp_xec);
12+
13+
#include <drivers/adc.h>
14+
#include <drivers/interrupt_controller/intc_mchp_xec_ecia.h>
15+
#include <soc.h>
16+
#include <errno.h>
17+
18+
#define ADC_CONTEXT_USES_KERNEL_TIMER
19+
#include "adc_context.h"
20+
21+
#define XEC_ADC_VREF_ANALOG 3300
22+
23+
/* ADC Control Register */
24+
#define XEC_ADC_CTRL_SINGLE_DONE_STATUS BIT(7)
25+
#define XEC_ADC_CTRL_REPEAT_DONE_STATUS BIT(6)
26+
#define XER_ADC_CTRL_SOFT_RESET BIT(4)
27+
#define XEC_ADC_CTRL_POWER_SAVER_DIS BIT(3)
28+
#define XEC_ADC_CTRL_START_REPEAT BIT(2)
29+
#define XEC_ADC_CTRL_START_SINGLE BIT(1)
30+
#define XEC_ADC_CTRL_ACTIVATE BIT(0)
31+
32+
struct adc_xec_config {
33+
uintptr_t base_addr;
34+
uint8_t girq_single;
35+
uint8_t girq_single_pos;
36+
uint8_t girq_repeat;
37+
uint8_t girq_repeat_pos;
38+
uint8_t pcr_regidx;
39+
uint8_t pcr_bitpos;
40+
};
41+
42+
struct adc_xec_data {
43+
struct adc_context ctx;
44+
uint16_t *buffer;
45+
uint16_t *repeat_buffer;
46+
};
47+
48+
struct adc_xec_regs {
49+
uint32_t control_reg;
50+
uint32_t delay_reg;
51+
uint32_t status_reg;
52+
uint32_t single_reg;
53+
uint32_t repeat_reg;
54+
uint32_t channel_read_reg[8];
55+
uint32_t unused[18];
56+
uint32_t config_reg;
57+
uint32_t vref_channel_reg;
58+
uint32_t vref_control_reg;
59+
uint32_t sar_control_reg;
60+
};
61+
62+
#define ADC_XEC_CONFIG(dev) \
63+
((struct adc_xec_config const *)(dev)->config)
64+
65+
#define ADC_XEC_DATA(dev) \
66+
((struct adc_xec_data *const)(dev)->data)
67+
68+
#define ADC_XEC_REG_BASE(dev) \
69+
((struct adc_xec_regs *)ADC_XEC_CONFIG(dev)->base_addr)
70+
71+
#define ADC_XEC_0_REG_BASE \
72+
(struct adc_xec_regs *)(DT_INST_REG_ADDR(0))
73+
74+
static void adc_context_start_sampling(struct adc_context *ctx)
75+
{
76+
struct adc_xec_data *data = CONTAINER_OF(ctx, struct adc_xec_data, ctx);
77+
struct adc_xec_regs *adc_regs = ADC_XEC_0_REG_BASE;
78+
79+
data->repeat_buffer = data->buffer;
80+
81+
adc_regs->single_reg = ctx->sequence.channels;
82+
adc_regs->control_reg |= XEC_ADC_CTRL_START_SINGLE;
83+
}
84+
85+
static void adc_context_update_buffer_pointer(struct adc_context *ctx,
86+
bool repeat_sampling)
87+
{
88+
struct adc_xec_data *data = CONTAINER_OF(ctx, struct adc_xec_data, ctx);
89+
90+
if (repeat_sampling) {
91+
data->buffer = data->repeat_buffer;
92+
}
93+
}
94+
95+
static int adc_xec_channel_setup(const struct device *dev,
96+
const struct adc_channel_cfg *channel_cfg)
97+
{
98+
struct adc_xec_regs *adc_regs = ADC_XEC_0_REG_BASE;
99+
uint32_t reg;
100+
101+
ARG_UNUSED(dev);
102+
103+
if (channel_cfg->acquisition_time != ADC_ACQ_TIME_DEFAULT) {
104+
return -EINVAL;
105+
}
106+
107+
if (channel_cfg->channel_id >= MCHP_ADC_MAX_CHAN) {
108+
return -EINVAL;
109+
}
110+
111+
if (channel_cfg->gain != ADC_GAIN_1) {
112+
return -EINVAL;
113+
}
114+
115+
/* Setup VREF */
116+
reg = adc_regs->vref_channel_reg;
117+
reg &= ~MCHP_ADC_CH_VREF_SEL_MASK(channel_cfg->channel_id);
118+
119+
if (channel_cfg->reference == ADC_REF_INTERNAL) {
120+
reg |= MCHP_ADC_CH_VREF_SEL_PAD(channel_cfg->channel_id);
121+
} else if (channel_cfg->reference == ADC_REF_EXTERNAL0) {
122+
reg |= MCHP_ADC_CH_VREF_SEL_GPIO(channel_cfg->channel_id);
123+
} else {
124+
return -EINVAL;
125+
}
126+
127+
adc_regs->vref_channel_reg = reg;
128+
129+
/* Differential mode? */
130+
reg = adc_regs->sar_control_reg;
131+
reg &= ~BIT(MCHP_ADC_SAR_CTRL_SELDIFF_POS);
132+
if (channel_cfg->differential != 0) {
133+
reg |= MCHP_ADC_SAR_CTRL_SELDIFF_EN;
134+
}
135+
adc_regs->sar_control_reg = reg;
136+
137+
return 0;
138+
}
139+
140+
static bool adc_xec_validate_buffer_size(const struct adc_sequence *sequence)
141+
{
142+
int chan_count = 0;
143+
size_t buff_need;
144+
uint32_t chan_mask;
145+
146+
for (chan_mask = 0x80; chan_mask != 0; chan_mask >>= 1) {
147+
if (chan_mask & sequence->channels) {
148+
chan_count++;
149+
}
150+
}
151+
152+
buff_need = chan_count * sizeof(uint16_t);
153+
154+
if (sequence->options) {
155+
buff_need *= 1 + sequence->options->extra_samplings;
156+
}
157+
158+
if (buff_need > sequence->buffer_size) {
159+
return false;
160+
}
161+
162+
return true;
163+
}
164+
165+
static int adc_xec_start_read(const struct device *dev,
166+
const struct adc_sequence *sequence)
167+
{
168+
struct adc_xec_regs *adc_regs = ADC_XEC_REG_BASE(dev);
169+
struct adc_xec_data *data = ADC_XEC_DATA(dev);
170+
uint32_t reg;
171+
172+
if (sequence->channels & ~BIT_MASK(MCHP_ADC_MAX_CHAN)) {
173+
LOG_ERR("Incorrect channels, bitmask 0x%x", sequence->channels);
174+
return -EINVAL;
175+
}
176+
177+
if (sequence->channels == 0UL) {
178+
LOG_ERR("No channel selected");
179+
return -EINVAL;
180+
}
181+
182+
if (!adc_xec_validate_buffer_size(sequence)) {
183+
LOG_ERR("Incorrect buffer size");
184+
return -ENOMEM;
185+
}
186+
187+
/* Setup ADC resolution */
188+
reg = adc_regs->sar_control_reg;
189+
reg &= ~(MCHP_ADC_SAR_CTRL_RES_MASK |
190+
(1 << MCHP_ADC_SAR_CTRL_SHIFTD_POS));
191+
192+
if (sequence->resolution == 12) {
193+
reg |= MCHP_ADC_SAR_CTRL_RES_12_BITS;
194+
} else if (sequence->resolution == 10) {
195+
reg |= MCHP_ADC_SAR_CTRL_RES_10_BITS;
196+
reg |= MCHP_ADC_SAR_CTRL_SHIFTD_EN;
197+
} else {
198+
return -EINVAL;
199+
}
200+
201+
adc_regs->sar_control_reg = reg;
202+
203+
data->buffer = sequence->buffer;
204+
205+
adc_context_start_read(&data->ctx, sequence);
206+
207+
return adc_context_wait_for_completion(&data->ctx);
208+
}
209+
210+
static int adc_xec_read(const struct device *dev,
211+
const struct adc_sequence *sequence)
212+
{
213+
struct adc_xec_data *data = ADC_XEC_DATA(dev);
214+
int error;
215+
216+
adc_context_lock(&data->ctx, false, NULL);
217+
error = adc_xec_start_read(dev, sequence);
218+
adc_context_release(&data->ctx, error);
219+
220+
return error;
221+
}
222+
223+
#ifdef CONFIG_ADC_ASYNC
224+
static int adc_xec_read_async(const struct device *dev,
225+
const struct adc_sequence *sequence,
226+
struct k_poll_signal *async)
227+
{
228+
struct adc_xec_data *data = ADC_XEC_DATA(dev);
229+
int error;
230+
231+
adc_context_lock(&data->ctx, true, async);
232+
error = adc_xec_start_read(dev, sequence);
233+
adc_context_release(&data->ctx, error);
234+
235+
return error;
236+
}
237+
#endif /* CONFIG_ADC_ASYNC */
238+
239+
static void xec_adc_get_sample(const struct device *dev)
240+
{
241+
struct adc_xec_regs *adc_regs = ADC_XEC_REG_BASE(dev);
242+
struct adc_xec_data *data = ADC_XEC_DATA(dev);
243+
uint32_t idx;
244+
uint32_t channels = adc_regs->status_reg;
245+
uint32_t ch_status = channels;
246+
uint32_t bit;
247+
248+
/*
249+
* Using the enabled channel bit set, from
250+
* lowest channel number to highest, find out
251+
* which channel is enabled and copy the ADC
252+
* values from hardware registers to the data
253+
* buffer.
254+
*/
255+
bit = find_lsb_set(channels);
256+
while (bit != 0) {
257+
idx = bit - 1;
258+
259+
*data->buffer = (uint16_t)adc_regs->channel_read_reg[idx];
260+
data->buffer++;
261+
262+
channels &= ~BIT(idx);
263+
bit = find_lsb_set(channels);
264+
}
265+
266+
/* Clear the status register */
267+
adc_regs->status_reg = ch_status;
268+
}
269+
270+
static void adc_xec_isr(const struct device *dev)
271+
{
272+
const struct adc_xec_config *const cfg = ADC_XEC_CONFIG(dev);
273+
struct adc_xec_regs *adc_regs = ADC_XEC_REG_BASE(dev);
274+
struct adc_xec_data *data = ADC_XEC_DATA(dev);
275+
uint32_t reg;
276+
277+
/* Clear START_SINGLE bit and clear SINGLE_DONE_STATUS */
278+
reg = adc_regs->control_reg;
279+
reg &= ~XEC_ADC_CTRL_START_SINGLE;
280+
reg |= XEC_ADC_CTRL_SINGLE_DONE_STATUS;
281+
adc_regs->control_reg = reg;
282+
283+
/* Also clear GIRQ source status bit */
284+
mchp_xec_ecia_girq_src_clr(cfg->girq_single, cfg->girq_single_pos);
285+
286+
xec_adc_get_sample(dev);
287+
288+
adc_context_on_sampling_done(&data->ctx, dev);
289+
290+
LOG_DBG("ADC ISR triggered.");
291+
}
292+
293+
struct adc_driver_api adc_xec_api = {
294+
.channel_setup = adc_xec_channel_setup,
295+
.read = adc_xec_read,
296+
#if defined(CONFIG_ADC_ASYNC)
297+
.read_async = adc_xec_read_async,
298+
#endif
299+
.ref_internal = XEC_ADC_VREF_ANALOG,
300+
};
301+
302+
static int adc_xec_init(const struct device *dev)
303+
{
304+
const struct adc_xec_config *const cfg = ADC_XEC_CONFIG(dev);
305+
struct adc_xec_regs *adc_regs = ADC_XEC_REG_BASE(dev);
306+
struct adc_xec_data *data = ADC_XEC_DATA(dev);
307+
308+
adc_regs->control_reg = XEC_ADC_CTRL_ACTIVATE
309+
| XEC_ADC_CTRL_POWER_SAVER_DIS
310+
| XEC_ADC_CTRL_SINGLE_DONE_STATUS
311+
| XEC_ADC_CTRL_REPEAT_DONE_STATUS;
312+
313+
mchp_xec_ecia_girq_src_dis(cfg->girq_single, cfg->girq_single_pos);
314+
mchp_xec_ecia_girq_src_dis(cfg->girq_repeat, cfg->girq_repeat_pos);
315+
mchp_xec_ecia_girq_src_clr(cfg->girq_single, cfg->girq_single_pos);
316+
mchp_xec_ecia_girq_src_clr(cfg->girq_repeat, cfg->girq_repeat_pos);
317+
mchp_xec_ecia_girq_src_en(cfg->girq_single, cfg->girq_single_pos);
318+
319+
IRQ_CONNECT(DT_INST_IRQN(0),
320+
DT_INST_IRQ(0, priority),
321+
adc_xec_isr, DEVICE_DT_INST_GET(0), 0);
322+
irq_enable(DT_INST_IRQN(0));
323+
324+
adc_context_unlock_unconditionally(&data->ctx);
325+
326+
return 0;
327+
}
328+
329+
static struct adc_xec_config adc_xec_dev_cfg_0 = {
330+
.base_addr = (uintptr_t)(DT_INST_REG_ADDR(0)),
331+
.girq_single = (uint8_t)(DT_INST_PROP_BY_IDX(0, girqs, 0)),
332+
.girq_single_pos = (uint8_t)(DT_INST_PROP_BY_IDX(0, girqs, 1)),
333+
.girq_repeat = (uint8_t)(DT_INST_PROP_BY_IDX(0, girqs, 2)),
334+
.girq_repeat_pos = (uint8_t)(DT_INST_PROP_BY_IDX(0, girqs, 3)),
335+
.pcr_regidx = (uint8_t)(DT_INST_PROP_BY_IDX(0, pcrs, 0)),
336+
.pcr_bitpos = (uint8_t)(DT_INST_PROP_BY_IDX(0, pcrs, 1)),
337+
};
338+
339+
static struct adc_xec_data adc_xec_dev_data_0 = {
340+
ADC_CONTEXT_INIT_TIMER(adc_xec_dev_data_0, ctx),
341+
ADC_CONTEXT_INIT_LOCK(adc_xec_dev_data_0, ctx),
342+
ADC_CONTEXT_INIT_SYNC(adc_xec_dev_data_0, ctx),
343+
};
344+
345+
DEVICE_DT_INST_DEFINE(0, adc_xec_init, NULL,
346+
&adc_xec_dev_data_0, &adc_xec_dev_cfg_0,
347+
PRE_KERNEL_1, CONFIG_KERNEL_INIT_PRIORITY_DEVICE,
348+
&adc_xec_api);

drivers/adc/adc_shell.c

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,8 @@
1919
#define DT_DRV_COMPAT ite_it8xxx2_adc
2020
#elif DT_HAS_COMPAT_STATUS_OKAY(microchip_xec_adc)
2121
#define DT_DRV_COMPAT microchip_xec_adc
22+
#elif DT_HAS_COMPAT_STATUS_OKAY(microchip_xec_adc_v2)
23+
#define DT_DRV_COMPAT microchip_xec_adc_v2
2224
#elif DT_HAS_COMPAT_STATUS_OKAY(nordic_nrf_adc)
2325
#define DT_DRV_COMPAT nordic_nrf_adc
2426
#elif DT_HAS_COMPAT_STATUS_OKAY(nordic_nrf_saadc)

0 commit comments

Comments
 (0)