171 lines
4.3 KiB
C
171 lines
4.3 KiB
C
/*
|
|
* Copyright (c) 2018 STMicroelectronics
|
|
*
|
|
* SPDX-License-Identifier: Apache-2.0
|
|
*/
|
|
|
|
#define DT_DRV_COMPAT st_mpxxdtyy
|
|
|
|
#include "mpxxdtyy.h"
|
|
|
|
#define LOG_LEVEL CONFIG_AUDIO_DMIC_LOG_LEVEL
|
|
#include <logging/log.h>
|
|
LOG_MODULE_REGISTER(mpxxdtyy);
|
|
|
|
#define CHANNEL_MASK 0x55
|
|
|
|
static u8_t ch_demux[128] = {
|
|
0x00, 0x01, 0x00, 0x01, 0x02, 0x03, 0x02, 0x03,
|
|
0x00, 0x01, 0x00, 0x01, 0x02, 0x03, 0x02, 0x03,
|
|
0x04, 0x05, 0x04, 0x05, 0x06, 0x07, 0x06, 0x07,
|
|
0x04, 0x05, 0x04, 0x05, 0x06, 0x07, 0x06, 0x07,
|
|
0x00, 0x01, 0x00, 0x01, 0x02, 0x03, 0x02, 0x03,
|
|
0x00, 0x01, 0x00, 0x01, 0x02, 0x03, 0x02, 0x03,
|
|
0x04, 0x05, 0x04, 0x05, 0x06, 0x07, 0x06, 0x07,
|
|
0x04, 0x05, 0x04, 0x05, 0x06, 0x07, 0x06, 0x07,
|
|
0x08, 0x09, 0x08, 0x09, 0x0a, 0x0b, 0x0a, 0x0b,
|
|
0x08, 0x09, 0x08, 0x09, 0x0a, 0x0b, 0x0a, 0x0b,
|
|
0x0c, 0x0d, 0x0c, 0x0d, 0x0e, 0x0f, 0x0e, 0x0f,
|
|
0x0c, 0x0d, 0x0c, 0x0d, 0x0e, 0x0f, 0x0e, 0x0f,
|
|
0x08, 0x09, 0x08, 0x09, 0x0a, 0x0b, 0x0a, 0x0b,
|
|
0x08, 0x09, 0x08, 0x09, 0x0a, 0x0b, 0x0a, 0x0b,
|
|
0x0c, 0x0d, 0x0c, 0x0d, 0x0e, 0x0f, 0x0e, 0x0f,
|
|
0x0c, 0x0d, 0x0c, 0x0d, 0x0e, 0x0f, 0x0e, 0x0f
|
|
};
|
|
|
|
static u8_t left_channel(u8_t a, u8_t b)
|
|
{
|
|
return ch_demux[a & CHANNEL_MASK] | (ch_demux[b & CHANNEL_MASK] << 4);
|
|
}
|
|
|
|
static u8_t right_channel(u8_t a, u8_t b)
|
|
{
|
|
a >>= 1;
|
|
b >>= 1;
|
|
return ch_demux[a & CHANNEL_MASK] | (ch_demux[b & CHANNEL_MASK] << 4);
|
|
}
|
|
|
|
u16_t sw_filter_lib_init(struct device *dev, struct dmic_cfg *cfg)
|
|
{
|
|
struct mpxxdtyy_data *const data = DEV_DATA(dev);
|
|
TPDMFilter_InitStruct *pdm_filter = &data->pdm_filter[0];
|
|
u16_t factor;
|
|
u32_t audio_freq = cfg->streams->pcm_rate;
|
|
int i;
|
|
|
|
/* calculate oversampling factor based on pdm clock */
|
|
for (factor = 64U; factor <= 128U; factor += 64U) {
|
|
u32_t pdm_bit_clk = (audio_freq * factor *
|
|
cfg->channel.req_num_chan);
|
|
|
|
if (pdm_bit_clk >= cfg->io.min_pdm_clk_freq &&
|
|
pdm_bit_clk <= cfg->io.max_pdm_clk_freq) {
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (factor != 64U && factor != 128U) {
|
|
return 0;
|
|
}
|
|
|
|
for (i = 0; i < cfg->channel.req_num_chan; i++) {
|
|
/* init the filter lib */
|
|
pdm_filter[i].LP_HZ = audio_freq / 2U;
|
|
pdm_filter[i].HP_HZ = 10;
|
|
pdm_filter[i].Fs = audio_freq;
|
|
pdm_filter[i].Out_MicChannels = cfg->channel.req_num_chan;
|
|
pdm_filter[i].In_MicChannels = cfg->channel.req_num_chan;
|
|
pdm_filter[i].Decimation = factor;
|
|
pdm_filter[i].MaxVolume = 64;
|
|
|
|
Open_PDM_Filter_Init(&data->pdm_filter[i]);
|
|
}
|
|
|
|
return factor;
|
|
}
|
|
|
|
int sw_filter_lib_run(TPDMFilter_InitStruct *pdm_filter,
|
|
void *pdm_block, void *pcm_block,
|
|
size_t pdm_size, size_t pcm_size)
|
|
{
|
|
int i;
|
|
u8_t a, b;
|
|
|
|
if (pdm_block == NULL || pcm_block == NULL || pdm_filter == NULL) {
|
|
return -EINVAL;
|
|
}
|
|
|
|
for (i = 0; i < pdm_size/2; i++) {
|
|
switch (pdm_filter[0].In_MicChannels) {
|
|
case 1: /* MONO */
|
|
((u16_t *)pdm_block)[i] = HTONS(((u16_t *)pdm_block)[i]);
|
|
break;
|
|
|
|
case 2: /* STEREO */
|
|
if (pdm_filter[0].In_MicChannels > 1) {
|
|
a = ((u8_t *)pdm_block)[2*i];
|
|
b = ((u8_t *)pdm_block)[2*i + 1];
|
|
|
|
((u8_t *)pdm_block)[2*i] = left_channel(a, b);
|
|
((u8_t *)pdm_block)[2*i + 1] = right_channel(a, b);
|
|
}
|
|
break;
|
|
|
|
default:
|
|
return -EINVAL;
|
|
}
|
|
}
|
|
|
|
switch (pdm_filter[0].Decimation) {
|
|
case 64:
|
|
for (i = 0; i < pdm_filter[0].In_MicChannels; i++) {
|
|
Open_PDM_Filter_64(&((u8_t *) pdm_block)[i],
|
|
&((u16_t *) pcm_block)[i],
|
|
pdm_filter->MaxVolume,
|
|
&pdm_filter[i]);
|
|
}
|
|
break;
|
|
case 128:
|
|
for (i = 0; i < pdm_filter[0].In_MicChannels; i++) {
|
|
Open_PDM_Filter_128(&((u8_t *) pdm_block)[i],
|
|
&((u16_t *) pcm_block)[i],
|
|
pdm_filter->MaxVolume,
|
|
&pdm_filter[i]);
|
|
}
|
|
break;
|
|
default:
|
|
return -EINVAL;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
static const struct _dmic_ops mpxxdtyy_driver_api = {
|
|
#ifdef DT_ST_MPXXDTYY_BUS_I2S
|
|
.configure = mpxxdtyy_i2s_configure,
|
|
.trigger = mpxxdtyy_i2s_trigger,
|
|
.read = mpxxdtyy_i2s_read,
|
|
#endif /* DT_ST_MPXXDTYY_BUS_I2S */
|
|
};
|
|
|
|
static int mpxxdtyy_initialize(struct device *dev)
|
|
{
|
|
struct mpxxdtyy_data *const data = DEV_DATA(dev);
|
|
|
|
data->comm_master = device_get_binding(DT_INST_BUS_LABEL(0));
|
|
|
|
if (data->comm_master == NULL) {
|
|
LOG_ERR("master %s not found", DT_INST_BUS_LABEL(0));
|
|
return -EINVAL;
|
|
}
|
|
|
|
data->state = DMIC_STATE_INITIALIZED;
|
|
return 0;
|
|
}
|
|
|
|
static struct mpxxdtyy_data mpxxdtyy_data;
|
|
|
|
DEVICE_AND_API_INIT(mpxxdtyy, DT_INST_LABEL(0), mpxxdtyy_initialize,
|
|
&mpxxdtyy_data, NULL, POST_KERNEL,
|
|
CONFIG_AUDIO_DMIC_INIT_PRIORITY, &mpxxdtyy_driver_api);
|