forked from zephyrproject-rtos/zephyr
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathmpxxdtyy-i2s.c
146 lines (121 loc) · 3.59 KB
/
mpxxdtyy-i2s.c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
/*
* Copyright (c) 2018 STMicroelectronics
*
* SPDX-License-Identifier: Apache-2.0
*/
#define DT_DRV_COMPAT st_mpxxdtyy
#include "mpxxdtyy.h"
#include <zephyr/drivers/i2s.h>
#define LOG_LEVEL CONFIG_AUDIO_DMIC_LOG_LEVEL
#include <zephyr/logging/log.h>
LOG_MODULE_DECLARE(mpxxdtyy);
#if DT_ANY_INST_ON_BUS_STATUS_OKAY(i2s)
#define NUM_RX_BLOCKS 4
#define PDM_BLOCK_MAX_SIZE_BYTES 512
K_MEM_SLAB_DEFINE(rx_pdm_i2s_mslab, PDM_BLOCK_MAX_SIZE_BYTES, NUM_RX_BLOCKS, 1);
int mpxxdtyy_i2s_read(const struct device *dev, uint8_t stream, void **buffer,
size_t *size, int32_t timeout)
{
int ret;
const struct mpxxdtyy_config *config = dev->config;
struct mpxxdtyy_data *const data = dev->data;
void *pdm_block, *pcm_block;
size_t pdm_size;
TPDMFilter_InitStruct *pdm_filter = &data->pdm_filter[0];
ret = i2s_read(config->comm_master, &pdm_block, &pdm_size);
if (ret != 0) {
LOG_ERR("read failed (%d)", ret);
return ret;
}
ret = k_mem_slab_alloc(data->pcm_mem_slab,
&pcm_block, K_NO_WAIT);
if (ret < 0) {
return ret;
}
sw_filter_lib_run(pdm_filter, pdm_block, pcm_block, pdm_size,
data->pcm_mem_size);
k_mem_slab_free(&rx_pdm_i2s_mslab, pdm_block);
*buffer = pcm_block;
*size = data->pcm_mem_size;
return 0;
}
int mpxxdtyy_i2s_trigger(const struct device *dev, enum dmic_trigger cmd)
{
int ret;
const struct mpxxdtyy_config *config = dev->config;
struct mpxxdtyy_data *const data = dev->data;
enum i2s_trigger_cmd i2s_cmd;
enum dmic_state tmp_state;
switch (cmd) {
case DMIC_TRIGGER_START:
if (data->state == DMIC_STATE_CONFIGURED) {
tmp_state = DMIC_STATE_ACTIVE;
i2s_cmd = I2S_TRIGGER_START;
} else {
return 0;
}
break;
case DMIC_TRIGGER_STOP:
if (data->state == DMIC_STATE_ACTIVE) {
tmp_state = DMIC_STATE_CONFIGURED;
i2s_cmd = I2S_TRIGGER_STOP;
} else {
return 0;
}
break;
default:
return -EINVAL;
}
ret = i2s_trigger(config->comm_master, I2S_DIR_RX, i2s_cmd);
if (ret != 0) {
LOG_ERR("trigger failed with %d error", ret);
return ret;
}
data->state = tmp_state;
return 0;
}
int mpxxdtyy_i2s_configure(const struct device *dev, struct dmic_cfg *cfg)
{
int ret;
const struct mpxxdtyy_config *config = dev->config;
struct mpxxdtyy_data *const data = dev->data;
uint8_t chan_size = cfg->streams->pcm_width;
uint32_t audio_freq = cfg->streams->pcm_rate;
uint16_t factor;
/* PCM buffer size */
data->pcm_mem_slab = cfg->streams->mem_slab;
data->pcm_mem_size = cfg->streams->block_size;
/* check requested min pdm frequency */
if (cfg->io.min_pdm_clk_freq < MPXXDTYY_MIN_PDM_FREQ ||
cfg->io.min_pdm_clk_freq > cfg->io.max_pdm_clk_freq) {
return -EINVAL;
}
/* check requested max pdm frequency */
if (cfg->io.max_pdm_clk_freq > MPXXDTYY_MAX_PDM_FREQ ||
cfg->io.max_pdm_clk_freq < cfg->io.min_pdm_clk_freq) {
return -EINVAL;
}
factor = sw_filter_lib_init(dev, cfg);
if (factor == 0U) {
return -EINVAL;
}
/* configure I2S channels */
struct i2s_config i2s_cfg;
i2s_cfg.word_size = chan_size;
i2s_cfg.channels = cfg->channel.req_num_chan;
i2s_cfg.format = I2S_FMT_DATA_FORMAT_LEFT_JUSTIFIED |
I2S_FMT_BIT_CLK_INV;
i2s_cfg.options = I2S_OPT_FRAME_CLK_MASTER | I2S_OPT_BIT_CLK_MASTER;
i2s_cfg.frame_clk_freq = audio_freq * factor / chan_size;
i2s_cfg.block_size = data->pcm_mem_size * (factor / chan_size);
i2s_cfg.mem_slab = &rx_pdm_i2s_mslab;
i2s_cfg.timeout = 2000;
ret = i2s_configure(config->comm_master, I2S_DIR_RX, &i2s_cfg);
if (ret != 0) {
LOG_ERR("I2S device configuration error");
return ret;
}
data->state = DMIC_STATE_CONFIGURED;
return 0;
}
#endif /* DT_ANY_INST_ON_BUS_STATUS_OKAY(i2s) */