1 /*
2 * Copyright (c) 2018 STMicroelectronics
3 *
4 * SPDX-License-Identifier: Apache-2.0
5 */
6
7 #define DT_DRV_COMPAT st_mpxxdtyy
8
9 #include <zephyr/devicetree.h>
10
11 #include "mpxxdtyy.h"
12
13 #define LOG_LEVEL CONFIG_AUDIO_DMIC_LOG_LEVEL
14 #include <zephyr/logging/log.h>
15 LOG_MODULE_REGISTER(mpxxdtyy);
16
17 #define CHANNEL_MASK 0x55
18
19 static uint8_t ch_demux[128] = {
20 0x00, 0x01, 0x00, 0x01, 0x02, 0x03, 0x02, 0x03,
21 0x00, 0x01, 0x00, 0x01, 0x02, 0x03, 0x02, 0x03,
22 0x04, 0x05, 0x04, 0x05, 0x06, 0x07, 0x06, 0x07,
23 0x04, 0x05, 0x04, 0x05, 0x06, 0x07, 0x06, 0x07,
24 0x00, 0x01, 0x00, 0x01, 0x02, 0x03, 0x02, 0x03,
25 0x00, 0x01, 0x00, 0x01, 0x02, 0x03, 0x02, 0x03,
26 0x04, 0x05, 0x04, 0x05, 0x06, 0x07, 0x06, 0x07,
27 0x04, 0x05, 0x04, 0x05, 0x06, 0x07, 0x06, 0x07,
28 0x08, 0x09, 0x08, 0x09, 0x0a, 0x0b, 0x0a, 0x0b,
29 0x08, 0x09, 0x08, 0x09, 0x0a, 0x0b, 0x0a, 0x0b,
30 0x0c, 0x0d, 0x0c, 0x0d, 0x0e, 0x0f, 0x0e, 0x0f,
31 0x0c, 0x0d, 0x0c, 0x0d, 0x0e, 0x0f, 0x0e, 0x0f,
32 0x08, 0x09, 0x08, 0x09, 0x0a, 0x0b, 0x0a, 0x0b,
33 0x08, 0x09, 0x08, 0x09, 0x0a, 0x0b, 0x0a, 0x0b,
34 0x0c, 0x0d, 0x0c, 0x0d, 0x0e, 0x0f, 0x0e, 0x0f,
35 0x0c, 0x0d, 0x0c, 0x0d, 0x0e, 0x0f, 0x0e, 0x0f
36 };
37
left_channel(uint8_t a,uint8_t b)38 static uint8_t left_channel(uint8_t a, uint8_t b)
39 {
40 return ch_demux[a & CHANNEL_MASK] | (ch_demux[b & CHANNEL_MASK] << 4);
41 }
42
right_channel(uint8_t a,uint8_t b)43 static uint8_t right_channel(uint8_t a, uint8_t b)
44 {
45 a >>= 1;
46 b >>= 1;
47 return ch_demux[a & CHANNEL_MASK] | (ch_demux[b & CHANNEL_MASK] << 4);
48 }
49
sw_filter_lib_init(const struct device * dev,struct dmic_cfg * cfg)50 uint16_t sw_filter_lib_init(const struct device *dev, struct dmic_cfg *cfg)
51 {
52 struct mpxxdtyy_data *const data = dev->data;
53 TPDMFilter_InitStruct *pdm_filter = &data->pdm_filter[0];
54 uint16_t factor;
55 uint32_t audio_freq = cfg->streams->pcm_rate;
56 int i;
57
58 /* calculate oversampling factor based on pdm clock */
59 for (factor = 64U; factor <= 128U; factor += 64U) {
60 uint32_t pdm_bit_clk = (audio_freq * factor *
61 cfg->channel.req_num_chan);
62
63 if (pdm_bit_clk >= cfg->io.min_pdm_clk_freq &&
64 pdm_bit_clk <= cfg->io.max_pdm_clk_freq) {
65 break;
66 }
67 }
68
69 if (factor != 64U && factor != 128U) {
70 return 0;
71 }
72
73 for (i = 0; i < cfg->channel.req_num_chan; i++) {
74 /* init the filter lib */
75 pdm_filter[i].LP_HZ = audio_freq / 2U;
76 pdm_filter[i].HP_HZ = 10;
77 pdm_filter[i].Fs = audio_freq;
78 pdm_filter[i].Out_MicChannels = cfg->channel.req_num_chan;
79 pdm_filter[i].In_MicChannels = cfg->channel.req_num_chan;
80 pdm_filter[i].Decimation = factor;
81 pdm_filter[i].MaxVolume = 64;
82
83 Open_PDM_Filter_Init(&data->pdm_filter[i]);
84 }
85
86 return factor;
87 }
88
sw_filter_lib_run(TPDMFilter_InitStruct * pdm_filter,void * pdm_block,void * pcm_block,size_t pdm_size,size_t pcm_size)89 int sw_filter_lib_run(TPDMFilter_InitStruct *pdm_filter,
90 void *pdm_block, void *pcm_block,
91 size_t pdm_size, size_t pcm_size)
92 {
93 int i;
94 uint8_t a, b;
95
96 if (pdm_block == NULL || pcm_block == NULL || pdm_filter == NULL) {
97 return -EINVAL;
98 }
99
100 for (i = 0; i < pdm_size/2; i++) {
101 switch (pdm_filter[0].In_MicChannels) {
102 case 1: /* MONO */
103 ((uint16_t *)pdm_block)[i] = HTONS(((uint16_t *)pdm_block)[i]);
104 break;
105
106 case 2: /* STEREO */
107 if (pdm_filter[0].In_MicChannels > 1) {
108 a = ((uint8_t *)pdm_block)[2*i];
109 b = ((uint8_t *)pdm_block)[2*i + 1];
110
111 ((uint8_t *)pdm_block)[2*i] = left_channel(a, b);
112 ((uint8_t *)pdm_block)[2*i + 1] = right_channel(a, b);
113 }
114 break;
115
116 default:
117 return -EINVAL;
118 }
119 }
120
121 switch (pdm_filter[0].Decimation) {
122 case 64:
123 for (i = 0; i < pdm_filter[0].In_MicChannels; i++) {
124 Open_PDM_Filter_64(&((uint8_t *) pdm_block)[i],
125 &((uint16_t *) pcm_block)[i],
126 pdm_filter->MaxVolume,
127 &pdm_filter[i]);
128 }
129 break;
130 case 128:
131 for (i = 0; i < pdm_filter[0].In_MicChannels; i++) {
132 Open_PDM_Filter_128(&((uint8_t *) pdm_block)[i],
133 &((uint16_t *) pcm_block)[i],
134 pdm_filter->MaxVolume,
135 &pdm_filter[i]);
136 }
137 break;
138 default:
139 return -EINVAL;
140 }
141
142 return 0;
143 }
144
145 static const struct _dmic_ops mpxxdtyy_driver_api = {
146 #if DT_ANY_INST_ON_BUS_STATUS_OKAY(i2s)
147 .configure = mpxxdtyy_i2s_configure,
148 .trigger = mpxxdtyy_i2s_trigger,
149 .read = mpxxdtyy_i2s_read,
150 #endif /* DT_ANY_INST_ON_BUS_STATUS_OKAY(i2s) */
151 };
152
mpxxdtyy_initialize(const struct device * dev)153 static int mpxxdtyy_initialize(const struct device *dev)
154 {
155 const struct mpxxdtyy_config *config = dev->config;
156 struct mpxxdtyy_data *const data = dev->data;
157
158 if (!device_is_ready(config->comm_master)) {
159 return -ENODEV;
160 }
161
162 data->state = DMIC_STATE_INITIALIZED;
163 return 0;
164 }
165
166 static const struct mpxxdtyy_config mpxxdtyy_config = {
167 .comm_master = DEVICE_DT_GET(DT_INST_BUS(0)),
168 };
169
170 static struct mpxxdtyy_data mpxxdtyy_data;
171
172 DEVICE_DT_INST_DEFINE(0, mpxxdtyy_initialize, NULL, &mpxxdtyy_data,
173 &mpxxdtyy_config, POST_KERNEL,
174 CONFIG_AUDIO_DMIC_INIT_PRIORITY, &mpxxdtyy_driver_api);
175