Skip to content

Commit fe53749

Browse files
Phuc Phamkartben
authored andcommitted
drivers: adc: Initial support for RZ/G3S
Add ADC driver support for Renesas RZ/G3S Signed-off-by: Phuc Pham <[email protected]> Signed-off-by: Binh Nguyen <[email protected]>
1 parent b7970cc commit fe53749

File tree

6 files changed

+417
-0
lines changed

6 files changed

+417
-0
lines changed

drivers/adc/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,7 @@ zephyr_library_sources_ifdef(CONFIG_ADC_ENE_KB1200 adc_ene_kb1200.c)
5555
zephyr_library_sources_ifdef(CONFIG_ADC_MCUX_GAU adc_mcux_gau_adc.c)
5656
zephyr_library_sources_ifdef(CONFIG_ADC_AMBIQ adc_ambiq.c)
5757
zephyr_library_sources_ifdef(CONFIG_ADC_RENESAS_RA adc_renesas_ra.c)
58+
zephyr_library_sources_ifdef(CONFIG_ADC_RENESAS_RZ adc_renesas_rz.c)
5859
zephyr_library_sources_ifdef(CONFIG_ADC_MAX32 adc_max32.c)
5960
zephyr_library_sources_ifdef(CONFIG_ADC_AD4114 adc_ad4114.c)
6061
zephyr_library_sources_ifdef(CONFIG_ADC_AD7124 adc_ad7124.c)

drivers/adc/Kconfig

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -134,6 +134,8 @@ source "drivers/adc/Kconfig.ambiq"
134134

135135
source "drivers/adc/Kconfig.renesas_ra"
136136

137+
source "drivers/adc/Kconfig.renesas_rz"
138+
137139
source "drivers/adc/Kconfig.max32"
138140

139141
source "drivers/adc/Kconfig.ad4114"

drivers/adc/Kconfig.renesas_rz

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
# Renesas RZ Family
2+
3+
# Copyright (c) 2024 Renesas Electronics Corporation
4+
# SPDX-License-Identifier: Apache-2.0
5+
6+
config ADC_RENESAS_RZ
7+
bool "Renesas RZ ADC Driver"
8+
default y
9+
depends on DT_HAS_RENESAS_RZ_ADC_ENABLED
10+
select USE_RZ_FSP_ADC
11+
help
12+
Enable the RZ ADC driver.

drivers/adc/adc_renesas_rz.c

Lines changed: 366 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,366 @@
1+
/*
2+
* Copyright (c) 2024 Renesas Electronics Corporation
3+
* SPDX-License-Identifier: Apache-2.0
4+
*/
5+
6+
#define DT_DRV_COMPAT renesas_rz_adc
7+
8+
#include <zephyr/drivers/adc.h>
9+
#include <zephyr/irq.h>
10+
#include <zephyr/logging/log.h>
11+
#include "r_adc_c.h"
12+
13+
LOG_MODULE_REGISTER(adc_renesas_rz, CONFIG_ADC_LOG_LEVEL);
14+
15+
#define ADC_CONTEXT_USES_KERNEL_TIMER
16+
#include "adc_context.h"
17+
18+
#define ADC_RZ_MAX_RESOLUTION 12
19+
20+
void adc_c_scan_end_isr(void);
21+
22+
/**
23+
* @brief RZ ADC config
24+
*
25+
* This structure contains constant config data for given instance of RZ ADC.
26+
*/
27+
struct adc_rz_config {
28+
/** Mask for channels existed in each board */
29+
uint32_t channel_available_mask;
30+
/** Structure that handle FSP API */
31+
const adc_api_t *fsp_api;
32+
};
33+
34+
/**
35+
* @brief RZ ADC data
36+
*
37+
* This structure contains data structures used by a RZ ADC.
38+
*/
39+
struct adc_rz_data {
40+
/** Structure that handle state of ongoing read operation */
41+
struct adc_context ctx;
42+
/** Pointer to RZ ADC own device structure */
43+
const struct device *dev;
44+
/** Structure that handle fsp ADC */
45+
adc_c_instance_ctrl_t fsp_ctrl;
46+
/** Structure that handle fsp ADC config */
47+
struct st_adc_cfg fsp_cfg;
48+
/** Structure that handle fsp ADC channel config */
49+
adc_c_channel_cfg_t fsp_channel_cfg;
50+
/** Pointer to memory where next sample will be written */
51+
uint16_t *buf;
52+
/** Mask with channels that will be sampled */
53+
uint32_t channels;
54+
/** Buffer id */
55+
uint16_t buf_id;
56+
};
57+
58+
/**
59+
* @brief Setup channels before starting to scan ADC
60+
*
61+
* @param dev RZ ADC device
62+
* @param channel_cfg channel configuration (user-defined)
63+
*
64+
* @return 0 on success
65+
* @return -ENOTSUP if channel id or differential is wrong value
66+
* @return -EINVAL if channel configuration is invalid
67+
*/
68+
static int adc_rz_channel_setup(const struct device *dev, const struct adc_channel_cfg *channel_cfg)
69+
{
70+
71+
fsp_err_t fsp_err = FSP_SUCCESS;
72+
struct adc_rz_data *data = dev->data;
73+
const struct adc_rz_config *config = dev->config;
74+
75+
if (!((config->channel_available_mask & BIT(channel_cfg->channel_id)) != 0)) {
76+
LOG_ERR("unsupported channel id '%d'", channel_cfg->channel_id);
77+
return -ENOTSUP;
78+
}
79+
80+
if (channel_cfg->acquisition_time != ADC_ACQ_TIME_DEFAULT) {
81+
LOG_ERR("Unsupported channel acquisition time");
82+
return -ENOTSUP;
83+
}
84+
85+
if (channel_cfg->differential) {
86+
LOG_ERR("Differential channels are not supported");
87+
return -ENOTSUP;
88+
}
89+
90+
if (channel_cfg->gain != ADC_GAIN_1) {
91+
LOG_ERR("Unsupported channel gain %d", channel_cfg->gain);
92+
return -ENOTSUP;
93+
}
94+
95+
if (channel_cfg->reference != ADC_REF_INTERNAL) {
96+
LOG_ERR("Unsupported channel reference");
97+
return -ENOTSUP;
98+
}
99+
data->fsp_channel_cfg.scan_mask |= (1U << channel_cfg->channel_id);
100+
/** Enable channels. */
101+
config->fsp_api->scanCfg(&data->fsp_ctrl, &data->fsp_channel_cfg);
102+
103+
if (FSP_SUCCESS != fsp_err) {
104+
return -ENOTSUP;
105+
}
106+
107+
return 0;
108+
}
109+
110+
/**
111+
* Interrupt handler
112+
*/
113+
static void adc_rz_isr(const struct device *dev)
114+
{
115+
struct adc_rz_data *data = dev->data;
116+
const struct adc_rz_config *config = dev->config;
117+
fsp_err_t fsp_err = FSP_SUCCESS;
118+
adc_channel_t channel_id = 0;
119+
uint32_t channels = 0;
120+
int16_t *sample_buffer = (int16_t *)data->buf;
121+
122+
channels = data->channels;
123+
for (channel_id = 0; channels > 0; channel_id++) {
124+
/** Get channel ids from scan mask "channels" */
125+
if ((channels & 0x01) != 0) {
126+
/** Read converted data */
127+
config->fsp_api->read(&data->fsp_ctrl, channel_id,
128+
&sample_buffer[data->buf_id]);
129+
if (FSP_SUCCESS != fsp_err) {
130+
break;
131+
}
132+
data->buf_id = data->buf_id + 1;
133+
}
134+
channels = channels >> 1;
135+
}
136+
adc_c_scan_end_isr();
137+
adc_context_on_sampling_done(&data->ctx, dev);
138+
}
139+
140+
/**
141+
* @brief Check if buffer in @p sequence is big enough to hold all ADC samples
142+
*
143+
* @param dev RZ ADC device
144+
* @param sequence ADC sequence description
145+
*
146+
* @return 0 on success
147+
* @return -ENOMEM if buffer is not big enough
148+
*/
149+
static int adc_rz_check_buffer_size(const struct device *dev, const struct adc_sequence *sequence)
150+
{
151+
uint8_t channels = 0;
152+
size_t needed;
153+
154+
channels = POPCOUNT(sequence->channels);
155+
needed = channels * sizeof(uint16_t);
156+
157+
if (sequence->options) {
158+
needed *= (1 + sequence->options->extra_samplings);
159+
}
160+
161+
if (sequence->buffer_size < needed) {
162+
return -ENOMEM;
163+
}
164+
165+
return 0;
166+
}
167+
168+
/**
169+
* @brief Start processing read request
170+
*
171+
* @param dev RZ ADC device
172+
* @param sequence ADC sequence description
173+
*
174+
* @return 0 on success
175+
* @return -ENOTSUP if requested resolution or channel is out side of supported
176+
* range
177+
* @return -ENOMEM if buffer is not big enough
178+
* (see @ref adc_rz_check_buffer_size)
179+
* @return other error code returned by adc_context_wait_for_completion
180+
*/
181+
static int adc_rz_start_read(const struct device *dev, const struct adc_sequence *sequence)
182+
{
183+
const struct adc_rz_config *config = dev->config;
184+
struct adc_rz_data *data = dev->data;
185+
int err;
186+
187+
if (sequence->resolution > ADC_RZ_MAX_RESOLUTION || sequence->resolution == 0) {
188+
LOG_ERR("unsupported resolution %d", sequence->resolution);
189+
return -ENOTSUP;
190+
}
191+
192+
if ((sequence->channels & ~config->channel_available_mask) != 0) {
193+
LOG_ERR("unsupported channels in mask: 0x%08x", sequence->channels);
194+
return -ENOTSUP;
195+
}
196+
err = adc_rz_check_buffer_size(dev, sequence);
197+
198+
if (err) {
199+
LOG_ERR("buffer size too small");
200+
return err;
201+
}
202+
data->buf_id = 0;
203+
data->buf = sequence->buffer;
204+
adc_context_start_read(&data->ctx, sequence);
205+
adc_context_wait_for_completion(&data->ctx);
206+
207+
return 0;
208+
}
209+
210+
/**
211+
* @brief Start processing read request asynchronously.
212+
*
213+
* @param dev RZ ADC device
214+
* @param sequence ADC sequence description
215+
* @param async async pointer to asynchronous signal
216+
*
217+
* @return 0 on success
218+
* @return -ENOTSUP if requested resolution or channel is out side of supported
219+
* range
220+
* @return -ENOMEM if buffer is not big enough
221+
* (see @ref adc_rz_check_buffer_size)
222+
* @return other error code returned by adc_context_wait_for_completion
223+
*/
224+
static int adc_rz_read_async(const struct device *dev, const struct adc_sequence *sequence,
225+
struct k_poll_signal *async)
226+
{
227+
struct adc_rz_data *data = dev->data;
228+
int err;
229+
230+
adc_context_lock(&data->ctx, async ? true : false, async);
231+
err = adc_rz_start_read(dev, sequence);
232+
adc_context_release(&data->ctx, err);
233+
234+
return err;
235+
}
236+
237+
/**
238+
* @brief Start processing read request synchronously.
239+
*
240+
* @param dev RZ ADC device
241+
* @param sequence ADC sequence description
242+
*
243+
* @return 0 on success
244+
* @return -ENOTSUP if requested resolution or channel is out side of supported
245+
* range
246+
* @return -ENOMEM if buffer is not big enough
247+
* (see @ref adc_rz_check_buffer_size)
248+
* @return other error code returned by adc_context_wait_for_completion
249+
*/
250+
static int adc_rz_read(const struct device *dev, const struct adc_sequence *sequence)
251+
{
252+
return adc_rz_read_async(dev, sequence, NULL);
253+
}
254+
255+
static void adc_context_start_sampling(struct adc_context *ctx)
256+
{
257+
struct adc_rz_data *data = CONTAINER_OF(ctx, struct adc_rz_data, ctx);
258+
const struct device *dev = data->dev;
259+
const struct adc_rz_config *config = dev->config;
260+
261+
data->channels = ctx->sequence.channels;
262+
/** Start a scan */
263+
config->fsp_api->scanStart(&data->fsp_ctrl);
264+
}
265+
266+
static void adc_context_update_buffer_pointer(struct adc_context *ctx, bool repeat_sampling)
267+
{
268+
struct adc_rz_data *data = CONTAINER_OF(ctx, struct adc_rz_data, ctx);
269+
270+
if (repeat_sampling) {
271+
data->buf_id = 0;
272+
}
273+
}
274+
275+
/**
276+
* @brief Function called on init for each RZ ADC device. It setups all
277+
* channels.
278+
*
279+
* @param dev RZ ADC device
280+
*
281+
* @return -EIO if error
282+
*
283+
* @return 0 on success
284+
*/
285+
static int adc_rz_init(const struct device *dev)
286+
{
287+
const struct adc_rz_config *config = dev->config;
288+
struct adc_rz_data *data = dev->data;
289+
fsp_err_t fsp_err = FSP_SUCCESS;
290+
/**Open the ADC module */
291+
config->fsp_api->open(&data->fsp_ctrl, &data->fsp_cfg);
292+
293+
if (FSP_SUCCESS != fsp_err) {
294+
return -EIO;
295+
}
296+
/** Release context unconditionally */
297+
adc_context_unlock_unconditionally(&data->ctx);
298+
299+
return 0;
300+
}
301+
302+
/**
303+
* ************************* DRIVER REGISTER SECTION ***************************
304+
*/
305+
306+
#define ADC_RZG_IRQ_CONNECT(idx, irq_name, isr) \
307+
do { \
308+
IRQ_CONNECT(DT_INST_IRQ_BY_NAME(idx, irq_name, irq), \
309+
DT_INST_IRQ_BY_NAME(idx, irq_name, priority), isr, \
310+
DEVICE_DT_INST_GET(idx), 0); \
311+
irq_enable(DT_INST_IRQ_BY_NAME(idx, irq_name, irq)); \
312+
} while (0)
313+
314+
#define ADC_RZG_CONFIG_FUNC(idx) ADC_RZG_IRQ_CONNECT(idx, scanend, adc_rz_isr);
315+
316+
#define ADC_RZG_INIT(idx) \
317+
static const adc_c_extended_cfg_t g_adc##idx##_cfg_extend = { \
318+
.trigger_mode = ADC_C_TRIGGER_MODE_SOFTWARE, \
319+
.trigger_source = ADC_C_ACTIVE_TRIGGER_EXTERNAL, \
320+
.trigger_edge = ADC_C_TRIGGER_EDGE_FALLING, \
321+
.input_mode = ADC_C_INPUT_MODE_AUTO, \
322+
.operating_mode = ADC_C_OPERATING_MODE_SCAN, \
323+
.buffer_mode = ADC_C_BUFFER_MODE_1, \
324+
.sampling_time = 100, \
325+
.external_trigger_filter = ADC_C_FILTER_STAGE_SETTING_DISABLE, \
326+
}; \
327+
static DEVICE_API(adc, adc_rz_api_##idx) = { \
328+
.channel_setup = adc_rz_channel_setup, \
329+
.read = adc_rz_read, \
330+
.ref_internal = DT_INST_PROP(idx, vref_mv), \
331+
IF_ENABLED(CONFIG_ADC_ASYNC, \
332+
(.read_async = adc_rz_read_async))}; \
333+
static const struct adc_rz_config adc_rz_config_##idx = { \
334+
.channel_available_mask = DT_INST_PROP(idx, channel_available_mask), \
335+
.fsp_api = &g_adc_on_adc, \
336+
}; \
337+
static struct adc_rz_data adc_rz_data_##idx = { \
338+
ADC_CONTEXT_INIT_TIMER(adc_rz_data_##idx, ctx), \
339+
ADC_CONTEXT_INIT_LOCK(adc_rz_data_##idx, ctx), \
340+
ADC_CONTEXT_INIT_SYNC(adc_rz_data_##idx, ctx), \
341+
.dev = DEVICE_DT_INST_GET(idx), \
342+
.fsp_cfg = \
343+
{ \
344+
.mode = ADC_MODE_SINGLE_SCAN, \
345+
.p_callback = NULL, \
346+
.p_context = NULL, \
347+
.p_extend = &g_adc##idx##_cfg_extend, \
348+
.scan_end_irq = DT_INST_IRQ_BY_NAME(idx, scanend, irq), \
349+
.scan_end_ipl = DT_INST_IRQ_BY_NAME(idx, scanend, priority), \
350+
}, \
351+
.fsp_channel_cfg = \
352+
{ \
353+
.scan_mask = 0, \
354+
.interrupt_setting = ADC_C_INTERRUPT_CHANNEL_SETTING_ENABLE, \
355+
}, \
356+
}; \
357+
static int adc_rz_init_##idx(const struct device *dev) \
358+
{ \
359+
ADC_RZG_CONFIG_FUNC(idx) \
360+
return adc_rz_init(dev); \
361+
} \
362+
DEVICE_DT_INST_DEFINE(idx, adc_rz_init_##idx, NULL, &adc_rz_data_##idx, \
363+
&adc_rz_config_##idx, POST_KERNEL, CONFIG_ADC_INIT_PRIORITY, \
364+
&adc_rz_api_##idx)
365+
366+
DT_INST_FOREACH_STATUS_OKAY(ADC_RZG_INIT);

0 commit comments

Comments
 (0)