blob: 497843bb1a743e468f1145506897647158dafb3b [file] [log] [blame]
/*
* Copyright (c) 2017, Intel Corporation
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
* 3. Neither the name of the Intel Corporation nor the names of its
* contributors may be used to endorse or promote products derived from this
* software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE INTEL CORPORATION OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef __QM_I2S_H__
#define __QM_I2S_H__
#include "qm_common.h"
#include "qm_soc_regs.h"
#include "qm_dma.h"
/**
* I2S.
*
* @defgroup groupI2S I2S
* @{
*/
/**
* I2S master/slave configuration.
*/
typedef enum {
QM_I2S_MASTER = 0, /**< Master configuration selection */
QM_I2S_SLAVE /**< Slave configuration selection */
} qm_i2s_master_slave_t;
/**
* I2S Audio stream identifiers.
*/
typedef enum {
QM_I2S_AUDIO_STREAM_TRANSMIT = 0, /**< Playback audio stream */
QM_I2S_AUDIO_STREAM_RECEIVE /**< Capture audio stream */
} qm_i2s_audio_stream_t;
/**
* I2S audio formats.
*/
typedef enum {
QM_I2S_AUDIO_FORMAT_I2S_MODE = 0, /**< I2S Mode audio format */
QM_I2S_AUDIO_FORMAT_RIGHT_J, /**< Right justified audio format */
QM_I2S_AUDIO_FORMAT_LEFT_J, /**< Left justified audio format */
QM_I2S_AUDIO_FORMAT_DSP_MODE /**< DSP mode audio format */
} qm_i2s_audio_format_t;
/**
* I2S Audio sample resolution. Resolution ranges between 12 bits and 32 bits.
*/
typedef enum {
/** 12 bits audio sample resolution */
QM_I2S_12_BIT_SAMPLE_RESOLUTION = 12,
/** 13 bits audio sample resolution */
QM_I2S_13_BIT_SAMPLE_RESOLUTION = 13,
/** 14 bits audio sample resolution */
QM_I2S_14_BIT_SAMPLE_RESOLUTION = 14,
/** 15 bits audio sample resolution */
QM_I2S_15_BIT_SAMPLE_RESOLUTION = 15,
/** 16 bits audio sample resolution */
QM_I2S_16_BIT_SAMPLE_RESOLUTION = 16,
/** 17 bits audio sample resolution */
QM_I2S_17_BIT_SAMPLE_RESOLUTION = 17,
/** 18 bits audio sample resolution */
QM_I2S_18_BIT_SAMPLE_RESOLUTION = 18,
/** 19 bits audio sample resolution */
QM_I2S_19_BIT_SAMPLE_RESOLUTION = 19,
/** 20 bits audio sample resolution */
QM_I2S_20_BIT_SAMPLE_RESOLUTION = 20,
/** 21 bits audio sample resolution */
QM_I2S_21_BIT_SAMPLE_RESOLUTION = 21,
/** 22 bits audio sample resolution */
QM_I2S_22_BIT_SAMPLE_RESOLUTION = 22,
/** 23 bits audio sample resolution */
QM_I2S_23_BIT_SAMPLE_RESOLUTION = 23,
/** 24 bits audio sample resolution */
QM_I2S_24_BIT_SAMPLE_RESOLUTION = 24,
/** 25 bits audio sample resolution */
QM_I2S_25_BIT_SAMPLE_RESOLUTION = 25,
/** 26 bits audio sample resolution */
QM_I2S_26_BIT_SAMPLE_RESOLUTION = 26,
/** 27 bits audio sample resolution */
QM_I2S_27_BIT_SAMPLE_RESOLUTION = 27,
/** 28 bits audio sample resolution */
QM_I2S_28_BIT_SAMPLE_RESOLUTION = 28,
/** 29 bits audio sample resolution */
QM_I2S_29_BIT_SAMPLE_RESOLUTION = 29,
/** 30 bits audio sample resolution */
QM_I2S_30_BIT_SAMPLE_RESOLUTION = 30,
/** 31 bits audio sample resolution */
QM_I2S_31_BIT_SAMPLE_RESOLUTION = 31,
/** 32 bits audio sample resolution */
QM_I2S_32_BIT_SAMPLE_RESOLUTION = 32
} qm_i2s_sample_resolution_t;
/**
* I2S Audio rates available.
*/
typedef enum {
QM_I2S_RATE_4000KHZ = 0, /**< 4kHz audio rate */
QM_I2S_RATE_8000KHZ, /**< 8kHz audio rate */
QM_I2S_RATE_11025KHZ, /**< 11.025kHz audio rate */
QM_I2S_RATE_16000KHZ, /**< 16kHz audio rate */
QM_I2S_RATE_22050KHZ, /**< 22.05kHz audio rate */
QM_I2S_RATE_32000KHZ, /**< 32kHz audio rate */
QM_I2S_RATE_44100KHZ, /**< 44.1kHz audio rate */
QM_I2S_RATE_48000KHZ, /**< 48kHz audio rate */
} qm_i2s_audio_rate_t;
/**
* I2S Audio buffer termination.
*/
typedef enum {
/** Used for single audio playback/recording. */
QM_I2S_TERMINATED_BUFFER = 0,
QM_I2S_RING_BUFFER /**< Used for continuous audio playback/recording. */
} qm_i2s_buffer_mode_t;
/**
* I2S Reference Clock Source Select
*/
typedef enum {
QM_I2S_INT_CLK = 0, /**< Use internal clock. */
QM_I2S_MCLK, /**< Take in clock from external source. */
} qm_i2s_clk_src_t;
/**
* I2S status type.
*/
typedef enum {
/** Indicates that a FIFO overflow error was detected. */
QM_I2S_FIFO_OVERFLOW = BIT(0),
/** Indicates that a FIFO underrun error was detected. */
QM_I2S_FIFO_UNDERRUN = BIT(1),
/** Indicates TX FIFO full interrupt occurred */
QM_I2S_TX_FIFO_FULL = BIT(2),
/** Indicates TX FIFO almost full interrupt occurred */
QM_I2S_TX_FIFO_ALMOST_FULL = BIT(3),
/** Indicates TX FIFO almost empty interrupt occurred */
QM_I2S_TX_FIFO_ALMOST_EMPTY = BIT(4),
/** Indicates TX FIFO empty interrupt occurred */
QM_I2S_TX_FIFO_EMPTY = BIT(5),
/** Indicates RX FIFO full interrupt occurred */
QM_I2S_RX_FIFO_FULL = BIT(6),
/** Indicates RX FIFO almost full interrupt occurred */
QM_I2S_RX_FIFO_ALMOST_FULL = BIT(7),
/** Indicates RX FIFO almost empty interrupt occurred */
QM_I2S_RX_FIFO_ALMOST_EMPTY = BIT(8),
/** Indicates RX FIFO empty interrupt occurred */
QM_I2S_RX_FIFO_EMPTY = BIT(9),
/** Indicates that a DMA error was detected */
QM_I2S_DMA_ERROR = BIT(10),
/** Indicates that DMA operation was completed */
QM_I2S_DMA_COMPLETE = BIT(11),
} qm_i2s_status_t;
/**
* Ring buffer link definition.
*/
typedef struct qm_i2s_buffer_link {
uint32_t *buff; /**< Pointer to the buffer base address. */
/** Pointer to the head of the DMA link list for the buffer link. */
qm_dma_lli_item_t *dma_link_head;
/** Link list item's pointer to the next link. */
struct qm_i2s_buffer_link *next;
} qm_i2s_buffer_link_t;
/**
* I2S controller configuration.
* Driver instantiates one of these with given parameters for each I2S
* channel configured using the "qm_i2s_set_channel_config" function.
*/
typedef struct {
qm_dma_channel_id_t dma_channel; /**< DMA controller Channel ID */
qm_i2s_audio_stream_t audio_stream; /**< I2S audio stream identifier */
/** I2S audio format configuration */
qm_i2s_audio_format_t audio_format;
/** I2S Master or Slave configuration */
qm_i2s_master_slave_t master_slave;
/** Sampling resolution */
qm_i2s_sample_resolution_t sample_resolution;
qm_i2s_audio_rate_t audio_rate; /**< Audio rate */
/** Terminated link list or ring buffer configuration */
qm_i2s_buffer_mode_t audio_buff_cfg;
/**
* DMA block size configuration:
* The source and destination transfer width is 32-bits for I2S.
* Min = 1, Max = see DMA configuration
*/
uint32_t block_size;
uint32_t num_dma_links; /**< Total number of DMA links. */
qm_dma_lli_item_t *dma_link; /**< Pointer to the DMA link list */
/** Number of buffer links in the ring buffer. */
uint32_t num_buffer_links;
qm_i2s_buffer_link_t *buffer_link; /**< Ring buffer head pointer. */
/** Number of DMA links per audio buffer. */
uint32_t num_dma_link_per_buffer;
uint32_t buffer_len; /**< Length of a buffer in the ring buffer. */
uint32_t afull_thresh; /**< TX/RX almost full threshold. */
uint32_t aempty_thresh; /**< TX/RX almost empty threshold. */
/**
* Transfer callback.
*
* @param[in] data Callback user data
* @param[in] i2s_status I2S status
*/
void (*callback)(void *data, qm_i2s_status_t i2s_status);
void *callback_data; /**< Callback user data. */
} qm_i2s_channel_cfg_data_t;
/**
* I2S Clock Configuration
*/
typedef struct {
/** Select Internal NCO or external reference clock for I2S block */
qm_i2s_clk_src_t i2s_clock_sel;
/**
* Used by the driver when configuring I2S reference clock from
* the NCO.
*/
uint32_t i2s_clk_freq;
/** Enable MCLK output. */
bool i2s_mclk_output_en;
/**
* MCLK output is generated from the Internal
* NCO output, normally \@24.576Mhz, using a divisor.
* Valid divisor range is 0 to 4095.
* E.g. with a 48kHz data rate, and NCO =
* 24.576Mhz, then required MCLK = 256 * data rate = 12.288MHz
* MCLK divisor = 2 (24.576Mhz/2 = 12.288MHz)
*/
uint32_t i2s_mclk_divisor;
/**
* Informs the driver of frequency of external clock
* when it is enabled.
*/
uint32_t i2s_ext_clk_freq;
} qm_i2s_clock_cfg_data_t;
/**
* Function to configure specified I2S controller stream
* Configuration parameters must be valid or an error is returned - see return
* values below.
*
* @param [in] i2s I2S controller identifier
* @param [in] audio_stream I2S audio_stream identifier
* @param [in] config Pointer to configuration structure
*
* @return Standard errno return type for QMSI.
* @retval 0 on success.
* @retval Negative @ref errno for possible error codes.
*/
int qm_i2s_dma_channel_config(const qm_i2s_t i2s,
const qm_i2s_audio_stream_t audio_stream,
const qm_i2s_channel_cfg_data_t *const config);
/**
* Function to place I2S controller into a disabled state.
* This function assumes that there is no pending transaction on the I2S
* interface in question.
* It is the responsibility of the calling application to do so.
*
* @param [in] i2s I2S controller identifier
* @param [in] audio_stream I2S audio_stream identifier
*
* @return Standard errno return type for QMSI.
* @retval 0 on success.
* @retval Negative @ref errno for possible error codes.
*/
int qm_i2s_channel_disable(const qm_i2s_t i2s,
const qm_i2s_audio_stream_t audio_stream);
/**
* Function to configure and enable I2S clocks
* Configuration parameters must be valid or an error is returned - see return
* values below.
*
* @param [in] i2s I2S controller identifier
* @param [in] i2s_clk_cfg I2S Clock configuration
*
* @return Standard errno return type for QMSI.
* @retval 0 on success.
* @retval Negative @ref errno for possible error codes.
*/
int qm_i2s_set_clock_config(const qm_i2s_t i2s,
const qm_i2s_clock_cfg_data_t *const i2s_clk_cfg);
/**
* Function to transmit a block of data to the specified I2S channel.
*
* @param [in] i2s I2S controller identifier
* @param [in] audio_stream I2S audio_stream identifier
*
* @return Standard errno return type for QMSI.
* @retval 0 on success.
* @retval Negative @ref errno for possible error codes.
*/
int qm_i2s_dma_transfer(const qm_i2s_t i2s,
const qm_i2s_audio_stream_t audio_stream);
/**
* Terminate the current DMA transfer on the given I2S peripheral channel.
*
* Terminate the current DMA transfer on the I2S channel.
* This will cause the relevant callbacks to be invoked.
*
* In the case the user is doing a continuous transfer using a circular linked
* list, it might be useful to fine control at which point in the linked list
* that we stop the transfer. To do this, set the relevant linked list item's
* "next" item to NULL.
*
* @param [in] i2s I2S controller identifier
* @param [in] config Pointer to configuration structure
*
* @return Standard errno return type for QMSI.
* @retval 0 on success.
* @retval Negative @ref errno for possible error codes.
*/
int qm_i2s_dma_transfer_terminate(const qm_i2s_t i2s,
qm_i2s_channel_cfg_data_t *const config);
/**
* @}
*/
#endif /* __QM_I2S_H__ */