Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
201 changes: 94 additions & 107 deletions drivers/audio/dmic_mcux.c
Original file line number Diff line number Diff line change
Expand Up @@ -61,21 +61,18 @@ static int dmic_mcux_get_osr(uint32_t pcm_rate, uint32_t bit_clk, bool use_2fs)
}

/* Gets hardware channel index from logical channel */
static uint8_t dmic_mcux_hw_chan(struct mcux_dmic_drv_data *drv_data,
uint8_t log_chan)
static uint8_t dmic_mcux_hw_chan(struct mcux_dmic_drv_data *drv_data, uint8_t log_chan)
{
enum pdm_lr lr;
uint8_t hw_chan;

dmic_parse_channel_map(drv_data->chan_map_lo,
drv_data->chan_map_hi,
log_chan, &hw_chan, &lr);
dmic_parse_channel_map(drv_data->chan_map_lo, drv_data->chan_map_hi, log_chan, &hw_chan,
&lr);

return hw_chan;
}

static void dmic_mcux_activate_channels(struct mcux_dmic_drv_data *drv_data,
bool enable)
static void dmic_mcux_activate_channels(struct mcux_dmic_drv_data *drv_data, bool enable)
{

/* PDM channel 0 must always be enabled, as the RM states:
Expand Down Expand Up @@ -112,27 +109,23 @@ static int dmic_mcux_enable_dma(struct mcux_dmic_drv_data *drv_data, bool enable
if (enable) {
ret = dma_start(pdm_channel->dma, pdm_channel->dma_chan);
if (ret < 0) {
LOG_ERR("Could not start DMA for HW channel %d",
hw_chan);
LOG_ERR("Could not start DMA for HW channel %d", hw_chan);
return ret;
}
} else {
if (dma_stop(pdm_channel->dma, pdm_channel->dma_chan)) {
LOG_ERR("Error stopping DMA for HW channel %d",
hw_chan);
LOG_ERR("Error stopping DMA for HW channel %d", hw_chan);
ret = -EIO;
}
}
DMIC_EnableChannelDma(drv_data->base_address,
(dmic_channel_t)hw_chan, enable);
DMIC_EnableChannelDma(drv_data->base_address, (dmic_channel_t)hw_chan, enable);
}

return ret;
}

/* Helper to reload DMA engine for all active channels with new buffer */
static void dmic_mcux_reload_dma(struct mcux_dmic_drv_data *drv_data,
void *buffer)
static void dmic_mcux_reload_dma(struct mcux_dmic_drv_data *drv_data, void *buffer)
{
int ret;
uint8_t hw_chan;
Expand All @@ -151,8 +144,7 @@ static void dmic_mcux_reload_dma(struct mcux_dmic_drv_data *drv_data,
pdm_channel = drv_data->pdm_channels[hw_chan];
src = DMIC_FifoGetAddress(drv_data->base_address, hw_chan);
dst = (uint32_t)(((uint16_t *)buffer) + chan);
ret = dma_reload(pdm_channel->dma, pdm_channel->dma_chan,
src, dst, dma_buf_size);
ret = dma_reload(pdm_channel->dma, pdm_channel->dma_chan, src, dst, dma_buf_size);
if (ret < 0) {
LOG_ERR("Could not reload DMIC HW channel %d", hw_chan);
return;
Expand Down Expand Up @@ -192,8 +184,8 @@ static int dmic_mcux_stop(struct mcux_dmic_drv_data *drv_data)
return 0;
}

static void dmic_mcux_dma_cb(const struct device *dev, void *user_data,
uint32_t channel, int status)
static void dmic_mcux_dma_cb(const struct device *dev, void *user_data, uint32_t channel,
int status)
{

struct mcux_dmic_drv_data *drv_data = (struct mcux_dmic_drv_data *)user_data;
Expand Down Expand Up @@ -230,8 +222,7 @@ static void dmic_mcux_dma_cb(const struct device *dev, void *user_data,
/* Reload DMA */
dmic_mcux_reload_dma(drv_data, done_buffer);
/* Advance active buffer index */
drv_data->active_buf_idx =
dmic_mcux_next_buf_idx(drv_data->active_buf_idx);
drv_data->active_buf_idx = dmic_mcux_next_buf_idx(drv_data->active_buf_idx);
return;
}

Expand All @@ -253,8 +244,7 @@ static void dmic_mcux_dma_cb(const struct device *dev, void *user_data,
/* Reload DMA */
dmic_mcux_reload_dma(drv_data, done_buffer);
/* Advance active buffer index */
drv_data->active_buf_idx =
dmic_mcux_next_buf_idx(drv_data->active_buf_idx);
drv_data->active_buf_idx = dmic_mcux_next_buf_idx(drv_data->active_buf_idx);
return;
}

Expand Down Expand Up @@ -314,10 +304,8 @@ static int dmic_mcux_setup_dma(const struct device *dev)
* pdm0_l_s1, pdm0_r_s1, pdm1_r_s1, pdm1_l_s1, ...]
* Each sample is 16 bits wide.
*/
blk_cfg[blk].dest_address =
(uint32_t)(((uint16_t *)dma_buf) + chan);
blk_cfg[blk].dest_scatter_interval =
num_chan * sizeof(uint16_t);
blk_cfg[blk].dest_address = (uint32_t)(((uint16_t *)dma_buf) + chan);
blk_cfg[blk].dest_scatter_interval = num_chan * sizeof(uint16_t);
blk_cfg[blk].dest_scatter_en = 1;
blk_cfg[blk].source_addr_adj = DMA_ADDR_ADJ_NO_CHANGE;
blk_cfg[blk].dest_addr_adj = DMA_ADDR_ADJ_INCREMENT;
Expand Down Expand Up @@ -355,8 +343,8 @@ static int dmic_mcux_setup_dma(const struct device *dev)
}

/* Initializes a DMIC hardware channel */
static int dmic_mcux_init_channel(const struct device *dev, uint32_t osr,
uint8_t chan, enum pdm_lr lr)
static int dmic_mcux_init_channel(const struct device *dev, uint32_t osr, uint8_t chan,
enum pdm_lr lr)
{
struct mcux_dmic_drv_data *drv_data = dev->data;

Expand Down Expand Up @@ -399,8 +387,7 @@ static int mcux_dmic_init(const struct device *dev)
return 0;
}

static int dmic_mcux_configure(const struct device *dev,
struct dmic_cfg *config)
static int dmic_mcux_configure(const struct device *dev, struct dmic_cfg *config)
{

const struct mcux_dmic_cfg *drv_config = dev->config;
Expand Down Expand Up @@ -460,8 +447,7 @@ static int dmic_mcux_configure(const struct device *dev,
return -ENOTSUP;
}

ret = clock_control_get_rate(drv_config->clock_dev,
drv_config->clock_name, &bit_clk_rate);
ret = clock_control_get_rate(drv_config->clock_dev, drv_config->clock_name, &bit_clk_rate);
if (ret < 0) {
return ret;
}
Expand All @@ -486,34 +472,27 @@ static int dmic_mcux_configure(const struct device *dev,
drv_data->chan_map_hi = channel->req_chan_map_hi;
for (uint8_t chan = 0; chan < channel->req_num_chan; chan += 2) {
/* Get the channel map data for channel pair */
dmic_parse_channel_map(channel->req_chan_map_lo,
channel->req_chan_map_hi,
chan, &hw_chan_0, &lr_0);
dmic_parse_channel_map(channel->req_chan_map_lo, channel->req_chan_map_hi, chan,
&hw_chan_0, &lr_0);
if ((chan + 1) < channel->req_num_chan) {
/* Paired channel is enabled */
dmic_parse_channel_map(channel->req_chan_map_lo,
channel->req_chan_map_hi,
dmic_parse_channel_map(channel->req_chan_map_lo, channel->req_chan_map_hi,
chan + 1, &hw_chan_1, &lr_1);
/* Verify that paired channels use consecutive hardware index */
if ((lr_0 == lr_1) ||
(hw_chan_1 != (hw_chan_0 + 1))) {
if ((lr_0 == lr_1) || (hw_chan_1 != (hw_chan_0 + 1))) {
return -EINVAL;
}
}
/* Configure selected channels in DMIC */
ret = dmic_mcux_init_channel(dev, osr,
dmic_mcux_hw_chan(drv_data, chan),
lr_0);
ret = dmic_mcux_init_channel(dev, osr, dmic_mcux_hw_chan(drv_data, chan), lr_0);
if (ret < 0) {
return ret;
}
channel->act_num_chan++;
if ((chan + 1) < channel->req_num_chan) {
/* Paired channel is enabled */
ret = dmic_mcux_init_channel(dev, osr,
dmic_mcux_hw_chan(drv_data,
chan + 1),
lr_1);
dmic_mcux_hw_chan(drv_data, chan + 1), lr_1);
if (ret < 0) {
return ret;
}
Expand All @@ -524,8 +503,8 @@ static int dmic_mcux_configure(const struct device *dev,
channel->act_chan_map_lo = channel->req_chan_map_lo;
channel->act_chan_map_hi = channel->req_chan_map_hi;

drv_data->mem_slab = stream->mem_slab;
drv_data->block_size = stream->block_size;
drv_data->mem_slab = stream->mem_slab;
drv_data->block_size = stream->block_size;
drv_data->act_num_chan = channel->act_num_chan;
drv_data->dmic_state = DMIC_STATE_CONFIGURED;

Expand All @@ -547,8 +526,7 @@ static int dmic_mcux_start(const struct device *dev)

for (uint32_t i = 0; i < CONFIG_DMIC_MCUX_DMA_BUFFERS; i++) {
/* Allocate buffers for DMA */
ret = k_mem_slab_alloc(drv_data->mem_slab,
&drv_data->dma_bufs[i], K_NO_WAIT);
ret = k_mem_slab_alloc(drv_data->mem_slab, &drv_data->dma_bufs[i], K_NO_WAIT);
if (ret < 0) {
LOG_ERR("failed to allocate buffer");
return -ENOBUFS;
Expand All @@ -569,8 +547,7 @@ static int dmic_mcux_start(const struct device *dev)
return 0;
}

static int dmic_mcux_trigger(const struct device *dev,
enum dmic_trigger cmd)
static int dmic_mcux_trigger(const struct device *dev, enum dmic_trigger cmd)
{
struct mcux_dmic_drv_data *drv_data = dev->data;

Expand Down Expand Up @@ -620,9 +597,8 @@ static int dmic_mcux_trigger(const struct device *dev,
return 0;
}

static int dmic_mcux_read(const struct device *dev,
uint8_t stream,
void **buffer, size_t *size, int32_t timeout)
static int dmic_mcux_read(const struct device *dev, uint8_t stream, void **buffer, size_t *size,
int32_t timeout)
{
struct mcux_dmic_drv_data *drv_data = dev->data;
int ret;
Expand Down Expand Up @@ -651,76 +627,87 @@ static int dmic_mcux_read(const struct device *dev,
return 0;
}

static int dmic_mcux_get_caps(const struct device *dev, struct audio_caps *caps)
{
memset(caps, 0, sizeof(struct audio_caps));

caps->min_total_channels = 1;
caps->max_total_channels = FSL_FEATURE_DMIC_CHANNEL_NUM;
caps->supported_sample_rates = AUDIO_SAMPLE_RATE_16000 | AUDIO_SAMPLE_RATE_48000;
/* Currently, driver supports only 16-bit samples */
caps->supported_bit_widths = AUDIO_BIT_WIDTH_16;
caps->min_num_buffers = CONFIG_DMIC_MCUX_DMA_BUFFERS;
/* Workaround: Set to 10ms because MediaPipe library does not have a cap filter implemented
* yet */
caps->min_frame_interval = 10000; /* 10ms minimum */
caps->max_frame_interval = 100000; /* 100ms maximum */
caps->interleaved = true;

return 0;
}

static const struct _dmic_ops dmic_ops = {
.configure = dmic_mcux_configure,
.trigger = dmic_mcux_trigger,
.read = dmic_mcux_read,
.get_caps = dmic_mcux_get_caps,
};

/* Converts integer gainshift into 5 bit 2's complement value for GAINSHIFT reg */
#define PDM_DMIC_GAINSHIFT(val) \
(val >= 0) ? (val & 0xF) : (BIT(4) | (0x10 - (val & 0xF)))
#define PDM_DMIC_GAINSHIFT(val) (val >= 0) ? (val & 0xF) : (BIT(4) | (0x10 - (val & 0xF)))

/* Defines structure for a given PDM channel node */
#define PDM_DMIC_CHAN_DEFINE(pdm_node) \
static struct mcux_dmic_pdm_chan \
pdm_channel_##pdm_node = { \
.dma = DEVICE_DT_GET(DT_DMAS_CTLR(pdm_node)), \
.dma_chan = DT_DMAS_CELL_BY_IDX(pdm_node, 0, channel), \
.dmic_channel_cfg = { \
.gainshft = PDM_DMIC_GAINSHIFT(DT_PROP(pdm_node, \
gainshift)), \
.preac2coef = DT_ENUM_IDX(pdm_node, compensation_2fs), \
.preac4coef = DT_ENUM_IDX(pdm_node, compensation_4fs), \
.dc_cut_level = DT_ENUM_IDX(pdm_node, dc_cutoff), \
.post_dc_gain_reduce = DT_PROP(pdm_node, dc_gain), \
.sample_rate = kDMIC_PhyFullSpeed, \
.saturate16bit = 1U, \
}, \
#define PDM_DMIC_CHAN_DEFINE(pdm_node) \
static struct mcux_dmic_pdm_chan pdm_channel_##pdm_node = { \
.dma = DEVICE_DT_GET(DT_DMAS_CTLR(pdm_node)), \
.dma_chan = DT_DMAS_CELL_BY_IDX(pdm_node, 0, channel), \
.dmic_channel_cfg = \
{ \
.gainshft = PDM_DMIC_GAINSHIFT(DT_PROP(pdm_node, gainshift)), \
.preac2coef = DT_ENUM_IDX(pdm_node, compensation_2fs), \
.preac4coef = DT_ENUM_IDX(pdm_node, compensation_4fs), \
.dc_cut_level = DT_ENUM_IDX(pdm_node, dc_cutoff), \
.post_dc_gain_reduce = DT_PROP(pdm_node, dc_gain), \
.sample_rate = kDMIC_PhyFullSpeed, \
.saturate16bit = 1U, \
}, \
};

/* Defines structures for all enabled PDM channels */
#define PDM_DMIC_CHANNELS_DEFINE(idx) \
DT_INST_FOREACH_CHILD_STATUS_OKAY(idx, PDM_DMIC_CHAN_DEFINE)
#define PDM_DMIC_CHANNELS_DEFINE(idx) DT_INST_FOREACH_CHILD_STATUS_OKAY(idx, PDM_DMIC_CHAN_DEFINE)

/* Gets pointer for a given PDM channel node */
#define PDM_DMIC_CHAN_GET(pdm_node) \
#define PDM_DMIC_CHAN_GET(pdm_node) \
COND_CODE_1(DT_NODE_HAS_STATUS_OKAY(pdm_node), \
(&pdm_channel_##pdm_node), (NULL)),

/* Gets array of pointers to PDM channels */
#define PDM_DMIC_CHANNELS_GET(idx) \
DT_INST_FOREACH_CHILD(idx, PDM_DMIC_CHAN_GET)

#define MCUX_DMIC_DEVICE(idx) \
PDM_DMIC_CHANNELS_DEFINE(idx); \
static struct mcux_dmic_pdm_chan \
*pdm_channels##idx[FSL_FEATURE_DMIC_CHANNEL_NUM] = { \
PDM_DMIC_CHANNELS_GET(idx) \
}; \
K_MSGQ_DEFINE(dmic_msgq##idx, sizeof(void *), \
CONFIG_DMIC_MCUX_QUEUE_SIZE, 1); \
static struct mcux_dmic_drv_data mcux_dmic_data##idx = { \
.pdm_channels = pdm_channels##idx, \
.base_address = (DMIC_Type *) DT_INST_REG_ADDR(idx), \
.dmic_state = DMIC_STATE_UNINIT, \
.rx_queue = &dmic_msgq##idx, \
.active_buf_idx = 0U, \
}; \
\
PINCTRL_DT_INST_DEFINE(idx); \
static struct mcux_dmic_cfg mcux_dmic_cfg##idx = { \
.pcfg = PINCTRL_DT_INST_DEV_CONFIG_GET(idx), \
.clock_dev = DEVICE_DT_GET(DT_INST_CLOCKS_CTLR(idx)), \
.clock_name = (clock_control_subsys_t) \
DT_INST_CLOCKS_CELL(idx, name), \
.use2fs = DT_INST_PROP(idx, use2fs), \
}; \
\
DEVICE_DT_INST_DEFINE(idx, mcux_dmic_init, NULL, \
&mcux_dmic_data##idx, &mcux_dmic_cfg##idx, \
POST_KERNEL, CONFIG_AUDIO_DMIC_INIT_PRIORITY, \
&dmic_ops);
#define PDM_DMIC_CHANNELS_GET(idx) DT_INST_FOREACH_CHILD(idx, PDM_DMIC_CHAN_GET)

#define MCUX_DMIC_DEVICE(idx) \
PDM_DMIC_CHANNELS_DEFINE(idx); \
static struct mcux_dmic_pdm_chan *pdm_channels##idx[FSL_FEATURE_DMIC_CHANNEL_NUM] = { \
PDM_DMIC_CHANNELS_GET(idx)}; \
K_MSGQ_DEFINE(dmic_msgq##idx, sizeof(void *), CONFIG_DMIC_MCUX_QUEUE_SIZE, 1); \
static struct mcux_dmic_drv_data mcux_dmic_data##idx = { \
.pdm_channels = pdm_channels##idx, \
.base_address = (DMIC_Type *)DT_INST_REG_ADDR(idx), \
.dmic_state = DMIC_STATE_UNINIT, \
.rx_queue = &dmic_msgq##idx, \
.active_buf_idx = 0U, \
}; \
\
PINCTRL_DT_INST_DEFINE(idx); \
static struct mcux_dmic_cfg mcux_dmic_cfg##idx = { \
.pcfg = PINCTRL_DT_INST_DEV_CONFIG_GET(idx), \
.clock_dev = DEVICE_DT_GET(DT_INST_CLOCKS_CTLR(idx)), \
.clock_name = (clock_control_subsys_t)DT_INST_CLOCKS_CELL(idx, name), \
.use2fs = DT_INST_PROP(idx, use2fs), \
}; \
\
DEVICE_DT_INST_DEFINE(idx, mcux_dmic_init, NULL, &mcux_dmic_data##idx, \
&mcux_dmic_cfg##idx, POST_KERNEL, CONFIG_AUDIO_DMIC_INIT_PRIORITY, \
&dmic_ops);

/* Existing SoCs only have one PDM instance. */
DT_INST_FOREACH_STATUS_OKAY(MCUX_DMIC_DEVICE)
Loading