blob: c4161f6670ed1d99b1486855f29a169ff1a431fa [file] [log] [blame]
/*
* 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)) * 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_ */