/* * Copyright (c) 2018, Intel Corporation * * Author: Seppo Ingalsuo * Sathish Kuttan * * SPDX-License-Identifier: Apache-2.0 */ #ifndef ZEPHYR_INCLUDE_AUDIO_DMIC_H_ #define ZEPHYR_INCLUDE_AUDIO_DMIC_H_ #include #include #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)) * 4)); } /** * 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)) * 4); *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)) * 4)); } /** * 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_ */