1 /*
2 * Copyright (c) 2018, Intel Corporation
3 *
4 * Author: Seppo Ingalsuo <seppo.ingalsuo@linux.intel.com>
5 * Sathish Kuttan <sathish.k.kuttan@intel.com>
6 *
7 * SPDX-License-Identifier: Apache-2.0
8 */
9
10 /**
11 * @file
12 * @brief Public API header file for Digital Microphones
13 *
14 * This file contains the Digital Microphone APIs
15 */
16
17 #ifndef ZEPHYR_INCLUDE_AUDIO_DMIC_H_
18 #define ZEPHYR_INCLUDE_AUDIO_DMIC_H_
19
20
21 /**
22 * @defgroup audio_interface Audio
23 * @{
24 * @}
25 */
26
27 /**
28 * @brief Abstraction for digital microphones
29 *
30 * @defgroup audio_dmic_interface Digital Microphone Interface
31 * @ingroup audio_interface
32 * @{
33 */
34
35 #include <kernel.h>
36 #include <device.h>
37
38 #ifdef __cplusplus
39 extern "C" {
40 #endif
41
42 /**
43 * DMIC driver states
44 */
45 enum dmic_state {
46 DMIC_STATE_UNINIT, /* Uninitialized */
47 DMIC_STATE_INITIALIZED, /* Initialized */
48 DMIC_STATE_CONFIGURED, /* Configured */
49 DMIC_STATE_ACTIVE, /* Active */
50 DMIC_STATE_PAUSED, /* Paused */
51 };
52
53 /**
54 * DMIC driver trigger commands
55 */
56 enum dmic_trigger {
57 DMIC_TRIGGER_STOP, /* stop stream */
58 DMIC_TRIGGER_START, /* start stream */
59 DMIC_TRIGGER_PAUSE, /* pause the stream */
60 DMIC_TRIGGER_RELEASE, /* release paused stream */
61 DMIC_TRIGGER_RESET, /* reset */
62 };
63
64 /**
65 * PDM Channels LEFT / RIGHT
66 */
67 enum pdm_lr {
68 PDM_CHAN_LEFT,
69 PDM_CHAN_RIGHT,
70 };
71
72 /**
73 * PDM Input/Output signal configuration
74 */
75 struct pdm_io_cfg {
76 /* parameters global to all PDM controllers */
77
78 /* minimum clock frequency supported by the mic */
79 uint32_t min_pdm_clk_freq;
80 /* maximum clock frequency supported by the mic */
81 uint32_t max_pdm_clk_freq;
82 /* minimum duty cycle in % supported by the mic */
83 uint8_t min_pdm_clk_dc;
84 /* maximum duty cycle in % supported by the mic */
85 uint8_t max_pdm_clk_dc;
86
87 /* parameters unique to each PDM controller */
88
89 /* Bit mask to optionally invert PDM clock */
90 uint8_t pdm_clk_pol;
91 /* Bit mask to optionally invert mic data */
92 uint8_t pdm_data_pol;
93 /* Collection of clock skew values for each PDM port */
94 uint32_t pdm_clk_skew;
95 };
96
97 /**
98 * Configuration of the PCM streams to be output by the PDM hardware
99 */
100 struct pcm_stream_cfg {
101 /*
102 * if either rate or width is set to 0 for a stream,
103 * the stream would be disabled
104 */
105
106 /* PCM sample rate of stream */
107 uint32_t pcm_rate;
108 /* PCM sample width of stream */
109 uint8_t pcm_width;
110 /* PCM sample block size per transfer */
111 uint16_t block_size;
112 /* SLAB for DMIC driver to allocate buffers for stream */
113 struct k_mem_slab *mem_slab;
114 };
115
116 /**
117 * Mapping/ordering of the PDM channels to logical PCM output channel
118 */
119 struct pdm_chan_cfg {
120 /*
121 * mapping of PDM controller and mic channel to logical channel
122 * since each controller can have 2 audio channels (stereo),
123 * there can be total of 8x2=16 channels.
124 * The actual number of channels shall be described in
125 * pcm_stream_cfg.num_chan.
126 * if 2 streams are enabled, the channel order will be the same for
127 * both streams
128 * Each channel is described as a 4 bit number, the least significant
129 * bit indicates LEFT/RIGHT selection of the PDM controller.
130 * The most significant 3 bits indicate the PDM controller number.
131 * bits 0-3 are for channel 0, bit 0 indicates LEFT or RIGHT
132 * bits 4-7 are for channel 1, bit 4 indicates LEFT or RIGHT
133 * and so on.
134 * CONSTRAINT: The LEFT and RIGHT channels of EACH PDM controller needs
135 * to be adjacent to each other.
136 */
137 /* Requested channel map */
138 uint32_t req_chan_map_lo; /* Channels 0 to 7 */
139 uint32_t req_chan_map_hi; /* Channels 8 to 15 */
140 /* Actual channel map that the driver could configure */
141 uint32_t act_chan_map_lo; /* Channels 0 to 7 */
142 uint32_t act_chan_map_hi; /* Channels 8 to 15 */
143 /* requested number of channels */
144 uint8_t req_num_chan;
145 /* Actual number of channels that the driver could configure */
146 uint8_t act_num_chan;
147 /* requested number of streams for each channel */
148 uint8_t req_num_streams;
149 /* Actual number of streams that the driver could configure */
150 uint8_t act_num_streams;
151 };
152
153 /**
154 * Input configuration structure for the DMIC configuration API
155 */
156 struct dmic_cfg {
157 struct pdm_io_cfg io;
158 /*
159 * Array of pcm_stream_cfg for application to provide
160 * configuration for each stream
161 */
162 struct pcm_stream_cfg *streams;
163 struct pdm_chan_cfg channel;
164 };
165
166 /**
167 * Function pointers for the DMIC driver operations
168 */
169 struct _dmic_ops {
170 int (*configure)(const struct device *dev, struct dmic_cfg *config);
171 int (*trigger)(const struct device *dev, enum dmic_trigger cmd);
172 int (*read)(const struct device *dev, uint8_t stream, void **buffer,
173 size_t *size, int32_t timeout);
174 };
175
176 /**
177 * Build the channel map to populate struct pdm_chan_cfg
178 *
179 * Returns the map of PDM controller and LEFT/RIGHT channel shifted to
180 * the bit position corresponding to the input logical channel value
181 *
182 * @param channel The logical channel number
183 * @param pdm The PDM hardware controller number
184 * @param lr LEFT/RIGHT channel within the chosen PDM hardware controller
185 *
186 * @return Bit-map containing the PDM and L/R channel information
187 */
dmic_build_channel_map(uint8_t channel,uint8_t pdm,enum pdm_lr lr)188 static inline uint32_t dmic_build_channel_map(uint8_t channel, uint8_t pdm,
189 enum pdm_lr lr)
190 {
191 return ((((pdm & BIT_MASK(3)) << 1) | lr) <<
192 ((channel & BIT_MASK(3)) * 4U));
193 }
194
195 /**
196 * Helper function to parse the channel map in pdm_chan_cfg
197 *
198 * Returns the PDM controller and LEFT/RIGHT channel corresponding to
199 * the channel map and the logical channel provided as input
200 *
201 * @param channel_map_lo Lower order/significant bits of the channel map
202 * @param channel_map_hi Higher order/significant bits of the channel map
203 * @param channel The logical channel number
204 * @param pdm Pointer to the PDM hardware controller number
205 * @param lr Pointer to the LEFT/RIGHT channel within the PDM controller
206 *
207 * @return none
208 */
dmic_parse_channel_map(uint32_t channel_map_lo,uint32_t channel_map_hi,uint8_t channel,uint8_t * pdm,enum pdm_lr * lr)209 static inline void dmic_parse_channel_map(uint32_t channel_map_lo,
210 uint32_t channel_map_hi, uint8_t channel, uint8_t *pdm, enum pdm_lr *lr)
211 {
212 uint32_t channel_map;
213
214 channel_map = (channel < 8) ? channel_map_lo : channel_map_hi;
215 channel_map >>= ((channel & BIT_MASK(3)) * 4U);
216
217 *pdm = (channel >> 1) & BIT_MASK(3);
218 *lr = (enum pdm_lr) (channel & BIT(0));
219 }
220
221 /**
222 * Build a bit map of clock skew values for each PDM channel
223 *
224 * Returns the bit-map of clock skew value shifted to the bit position
225 * corresponding to the input PDM controller value
226 *
227 * @param pdm The PDM hardware controller number
228 * @param skew The skew to apply for the clock output from the PDM controller
229 *
230 * @return Bit-map containing the clock skew information
231 */
dmic_build_clk_skew_map(uint8_t pdm,uint8_t skew)232 static inline uint32_t dmic_build_clk_skew_map(uint8_t pdm, uint8_t skew)
233 {
234 return ((skew & BIT_MASK(4)) << ((pdm & BIT_MASK(3)) * 4U));
235 }
236
237 /**
238 * Configure the DMIC driver and controller(s)
239 *
240 * Configures the DMIC driver device according to the number of channels,
241 * channel mapping, PDM I/O configuration, PCM stream configuration, etc.
242 *
243 * @param dev Pointer to the device structure for DMIC driver instance
244 * @param cfg Pointer to the structure containing the DMIC configuration
245 *
246 * @return 0 on success, a negative error code on failure
247 */
dmic_configure(const struct device * dev,struct dmic_cfg * cfg)248 static inline int dmic_configure(const struct device *dev,
249 struct dmic_cfg *cfg)
250 {
251 const struct _dmic_ops *api =
252 (const struct _dmic_ops *)dev->api;
253
254 return api->configure(dev, cfg);
255 }
256
257 /**
258 * Send a command to the DMIC driver
259 *
260 * Sends a command to the driver to perform a specific action
261 *
262 * @param dev Pointer to the device structure for DMIC driver instance
263 * @param cmd The command to be sent to the driver instance
264 *
265 * @return 0 on success, a negative error code on failure
266 */
dmic_trigger(const struct device * dev,enum dmic_trigger cmd)267 static inline int dmic_trigger(const struct device *dev,
268 enum dmic_trigger cmd)
269 {
270 const struct _dmic_ops *api =
271 (const struct _dmic_ops *)dev->api;
272
273 return api->trigger(dev, cmd);
274 }
275
276 /**
277 * Read received decimated PCM data stream
278 *
279 * Optionally waits for audio to be received and provides the received
280 * audio buffer from the requested stream
281 *
282 * @param dev Pointer to the device structure for DMIC driver instance
283 * @param stream Stream identifier
284 * @param buffer Pointer to the received buffer address
285 * @param size Pointer to the received buffer size
286 * @param timeout Timeout in milliseconds to wait in case audio is not yet
287 * received, or @ref SYS_FOREVER_MS
288 *
289 * @return 0 on success, a negative error code on failure
290 */
dmic_read(const struct device * dev,uint8_t stream,void ** buffer,size_t * size,int32_t timeout)291 static inline int dmic_read(const struct device *dev, uint8_t stream,
292 void **buffer,
293 size_t *size, int32_t timeout)
294 {
295 const struct _dmic_ops *api =
296 (const struct _dmic_ops *)dev->api;
297
298 return api->read(dev, stream, buffer, size, timeout);
299 }
300
301 #ifdef __cplusplus
302 }
303 #endif
304
305 /**
306 * @}
307 */
308
309 #endif /* ZEPHYR_INCLUDE_AUDIO_DMIC_H_ */
310