Loading...
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 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 | /*
* Copyright (c) 2018, Intel Corporation
*
* Author: Seppo Ingalsuo <seppo.ingalsuo@linux.intel.com>
* Sathish Kuttan <sathish.k.kuttan@intel.com>
*
* SPDX-License-Identifier: Apache-2.0
*/
#ifndef ZEPHYR_INCLUDE_AUDIO_DMIC_H_
#define ZEPHYR_INCLUDE_AUDIO_DMIC_H_
#include <kernel.h>
#include <device.h>
#ifdef __cplusplus
extern "C" {
#endif
/**
* DMIC driver states
*/
enum dmic_state {
DMIC_STATE_UNINIT, /* Uninitialized */
DMIC_STATE_INITIALIZED, /* Initialized */
DMIC_STATE_CONFIGURED, /* Configured */
DMIC_STATE_ACTIVE, /* Active */
DMIC_STATE_PAUSED, /* Paused */
};
/**
* DMIC driver trigger commands
*/
enum dmic_trigger {
DMIC_TRIGGER_STOP, /* stop stream */
DMIC_TRIGGER_START, /* start stream */
DMIC_TRIGGER_PAUSE, /* pause the stream */
DMIC_TRIGGER_RELEASE, /* release paused stream */
DMIC_TRIGGER_RESET, /* reset */
};
/**
* PDM Channels LEFT / RIGHT
*/
enum pdm_lr {
PDM_CHAN_LEFT,
PDM_CHAN_RIGHT,
};
/**
* PDM Input/Output signal configuration
*/
struct pdm_io_cfg {
/* parameters global to all PDM controllers */
/* minimum clock frequency supported by the mic */
u32_t min_pdm_clk_freq;
/* maximum clock frequency supported by the mic */
u32_t max_pdm_clk_freq;
/* minimum duty cycle in % supported by the mic */
u8_t min_pdm_clk_dc;
/* maximum duty cycle in % supported by the mic */
u8_t max_pdm_clk_dc;
/* parameters unique to each PDM controller */
/* Bit mask to optionally invert PDM clock */
u8_t pdm_clk_pol;
/* Bit mask to optionally invert mic data */
u8_t pdm_data_pol;
/* Collection of clock skew values for each PDM port */
u32_t pdm_clk_skew;
};
/**
* Configuration of the PCM streams to be output by the PDM hardware
*/
struct pcm_stream_cfg {
/*
* if either rate or width is set to 0 for a stream,
* the stream would be disabled
*/
/* PCM sample rate of stream */
u32_t pcm_rate;
/* PCM sample width of stream */
u8_t pcm_width;
/* PCM sample block size per transfer */
u16_t block_size;
/* SLAB for DMIC driver to allocate buffers for stream */
struct k_mem_slab *mem_slab;
};
/**
* Mapping/ordering of the PDM channels to logical PCM output channel
*/
struct pdm_chan_cfg {
/*
* mapping of PDM controller and mic channel to logical channel
* since each controller can have 2 audio channels (stereo),
* there can be total of 8x2=16 channels.
* The actual number of channels shall be described in
* pcm_stream_cfg.num_chan.
* if 2 streams are enabled, the channel order will be the same for
* both streams
* Each channel is described as a 4 bit number, the least significant
* bit indicates LEFT/RIGHT selection of the PDM controller.
* The most significant 3 bits indicate the PDM controller number.
* bits 0-3 are for channel 0, bit 0 indicates LEFT or RIGHT
* bits 4-7 are for channel 1, bit 4 indicates LEFT or RIGHT
* and so on.
* CONSTRAINT: The LEFT and RIGHT channels of EACH PDM controller needs
* to be adjacent to each other.
*/
/* Requested channel map */
u32_t req_chan_map_lo; /* Channels 0 to 7 */
u32_t req_chan_map_hi; /* Channels 8 to 15 */
/* Actual channel map that the driver could configure */
u32_t act_chan_map_lo; /* Channels 0 to 7 */
u32_t act_chan_map_hi; /* Channels 8 to 15 */
/* requested number of channels */
u8_t req_num_chan;
/* Actual number of channels that the driver could configure */
u8_t act_num_chan;
/* requested number of streams for each channel */
u8_t req_num_streams;
/* Actual number of streams that the driver could configure */
u8_t act_num_streams;
};
/**
* Input configuration structure for the DMIC configuration API
*/
struct dmic_cfg {
struct pdm_io_cfg io;
/*
* Array of pcm_stream_cfg for application to provide
* configuration for each stream
*/
struct pcm_stream_cfg *streams;
struct pdm_chan_cfg channel;
};
/**
* Function pointers for the DMIC driver operations
*/
struct _dmic_ops {
int (*configure)(struct device *dev, struct dmic_cfg *config);
int (*trigger)(struct device *dev, enum dmic_trigger cmd);
int (*read)(struct device *dev, u8_t stream, void **buffer,
size_t *size, s32_t timeout);
};
/**
* Build the channel map to populate struct pdm_chan_cfg
*
* Returns the map of PDM controller and LEFT/RIGHT channel shifted to
* the bit position corresponding to the input logical channel value
*
* @param channel The logical channel number
* @param pdm The PDM hardware controller number
* @param lr LEFT/RIGHT channel within the chosen PDM hardware controller
*
* @return Bit-map containing the PDM and L/R channel information
*/
static inline u32_t dmic_build_channel_map(u8_t channel, u8_t pdm,
enum pdm_lr lr)
{
return ((((pdm & BIT_MASK(3)) << 1) | lr) <<
((channel & BIT_MASK(3)) * 4U));
}
/**
* Helper function to parse the channel map in pdm_chan_cfg
*
* Returns the PDM controller and LEFT/RIGHT channel corresponding to
* the channel map and the logical channel provided as input
*
* @param channel_map_lo Lower order/significant bits of the channel map
* @param channel_map_hi Higher order/significant bits of the channel map
* @param channel The logical channel number
* @param pdm Pointer to the PDM hardware controller number
* @param lr Pointer to the LEFT/RIGHT channel within the PDM controller
*
* @return none
*/
static inline void dmic_parse_channel_map(u32_t channel_map_lo,
u32_t channel_map_hi, u8_t channel, u8_t *pdm, enum pdm_lr *lr)
{
u32_t channel_map;
channel_map = (channel < 8) ? channel_map_lo : channel_map_hi;
channel_map >>= ((channel & BIT_MASK(3)) * 4U);
*pdm = (channel >> 1) & BIT_MASK(3);
*lr = channel & BIT(0);
}
/**
* Build a bit map of clock skew values for each PDM channel
*
* Returns the bit-map of clock skew value shifted to the bit position
* corresponding to the input PDM controller value
*
* @param pdm The PDM hardware controller number
* @param skew The skew to apply for the clock output from the PDM controller
*
* @return Bit-map containing the clock skew information
*/
static inline u32_t dmic_build_clk_skew_map(u8_t pdm, u8_t skew)
{
return ((skew & BIT_MASK(4)) << ((pdm & BIT_MASK(3)) * 4U));
}
/**
* Configure the DMIC driver and controller(s)
*
* Configures the DMIC driver device according to the number of channels,
* channel mapping, PDM I/O configuration, PCM stream configuration, etc.
*
* @param dev Pointer to the device structure for DMIC driver instance
* @param cfg Pointer to the structure containing the DMIC configuration
*
* @return 0 on success, a negative error code on failure
*/
static inline int dmic_configure(struct device *dev, struct dmic_cfg *cfg)
{
const struct _dmic_ops *api = dev->driver_api;
return api->configure(dev, cfg);
}
/**
* Send a command to the DMIC driver
*
* Sends a command to the driver to perform a specific action
*
* @param dev Pointer to the device structure for DMIC driver instance
* @param cmd The command to be sent to the driver instance
*
* @return 0 on success, a negative error code on failure
*/
static inline int dmic_trigger(struct device *dev, enum dmic_trigger cmd)
{
const struct _dmic_ops *api = dev->driver_api;
return api->trigger(dev, cmd);
}
/**
* Read received decimated PCM data stream
*
* Optionally waits for audio to be received and provides the received
* audio buffer from the requested stream
*
* @param dev Pointer to the device structure for DMIC driver instance
* @param stream Stream identifier
* @param buffer Pointer to the received buffer address
* @param size Pointer to the received buffer size
* @param timeout Timeout value to wait in case audio is not yet received
*
* @return 0 on success, a negative error code on failure
*/
static inline int dmic_read(struct device *dev, u8_t stream, void **buffer,
size_t *size, s32_t timeout)
{
const struct _dmic_ops *api = dev->driver_api;
return api->read(dev, stream, buffer, size, timeout);
}
#ifdef __cplusplus
}
#endif
#endif /* ZEPHYR_INCLUDE_AUDIO_DMIC_H_ */
|