310 lines
8.5 KiB
C
310 lines
8.5 KiB
C
/*
|
|
* 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
|
|
*/
|
|
|
|
/**
|
|
* @file
|
|
* @brief Public API header file for Digital Microphones
|
|
*
|
|
* This file contains the Digital Microphone APIs
|
|
*/
|
|
|
|
#ifndef ZEPHYR_INCLUDE_AUDIO_DMIC_H_
|
|
#define ZEPHYR_INCLUDE_AUDIO_DMIC_H_
|
|
|
|
|
|
/**
|
|
* @defgroup audio_interface Audio
|
|
* @{
|
|
* @}
|
|
*/
|
|
|
|
/**
|
|
* @brief Abstraction for digital microphones
|
|
*
|
|
* @defgroup audio_dmic_interface Digital Microphone Interface
|
|
* @ingroup audio_interface
|
|
* @{
|
|
*/
|
|
|
|
#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 */
|
|
uint32_t min_pdm_clk_freq;
|
|
/* maximum clock frequency supported by the mic */
|
|
uint32_t max_pdm_clk_freq;
|
|
/* minimum duty cycle in % supported by the mic */
|
|
uint8_t min_pdm_clk_dc;
|
|
/* maximum duty cycle in % supported by the mic */
|
|
uint8_t max_pdm_clk_dc;
|
|
|
|
/* parameters unique to each PDM controller */
|
|
|
|
/* Bit mask to optionally invert PDM clock */
|
|
uint8_t pdm_clk_pol;
|
|
/* Bit mask to optionally invert mic data */
|
|
uint8_t pdm_data_pol;
|
|
/* Collection of clock skew values for each PDM port */
|
|
uint32_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 */
|
|
uint32_t pcm_rate;
|
|
/* PCM sample width of stream */
|
|
uint8_t pcm_width;
|
|
/* PCM sample block size per transfer */
|
|
uint16_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 */
|
|
uint32_t req_chan_map_lo; /* Channels 0 to 7 */
|
|
uint32_t req_chan_map_hi; /* Channels 8 to 15 */
|
|
/* Actual channel map that the driver could configure */
|
|
uint32_t act_chan_map_lo; /* Channels 0 to 7 */
|
|
uint32_t act_chan_map_hi; /* Channels 8 to 15 */
|
|
/* requested number of channels */
|
|
uint8_t req_num_chan;
|
|
/* Actual number of channels that the driver could configure */
|
|
uint8_t act_num_chan;
|
|
/* requested number of streams for each channel */
|
|
uint8_t req_num_streams;
|
|
/* Actual number of streams that the driver could configure */
|
|
uint8_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)(const struct device *dev, struct dmic_cfg *config);
|
|
int (*trigger)(const struct device *dev, enum dmic_trigger cmd);
|
|
int (*read)(const struct device *dev, uint8_t stream, void **buffer,
|
|
size_t *size, int32_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 uint32_t dmic_build_channel_map(uint8_t channel, uint8_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(uint32_t channel_map_lo,
|
|
uint32_t channel_map_hi, uint8_t channel, uint8_t *pdm, enum pdm_lr *lr)
|
|
{
|
|
uint32_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 = (enum pdm_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 uint32_t dmic_build_clk_skew_map(uint8_t pdm, uint8_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(const struct device *dev,
|
|
struct dmic_cfg *cfg)
|
|
{
|
|
const struct _dmic_ops *api =
|
|
(const struct _dmic_ops *)dev->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(const struct device *dev,
|
|
enum dmic_trigger cmd)
|
|
{
|
|
const struct _dmic_ops *api =
|
|
(const struct _dmic_ops *)dev->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 in milliseconds to wait in case audio is not yet
|
|
* received, or @ref SYS_FOREVER_MS
|
|
*
|
|
* @return 0 on success, a negative error code on failure
|
|
*/
|
|
static inline int dmic_read(const struct device *dev, uint8_t stream,
|
|
void **buffer,
|
|
size_t *size, int32_t timeout)
|
|
{
|
|
const struct _dmic_ops *api =
|
|
(const struct _dmic_ops *)dev->api;
|
|
|
|
return api->read(dev, stream, buffer, size, timeout);
|
|
}
|
|
|
|
#ifdef __cplusplus
|
|
}
|
|
#endif
|
|
|
|
/**
|
|
* @}
|
|
*/
|
|
|
|
#endif /* ZEPHYR_INCLUDE_AUDIO_DMIC_H_ */
|