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