218 lines
7.1 KiB
C
218 lines
7.1 KiB
C
/*
|
|
* Copyright (c) 2022 Intel Corporation.
|
|
*
|
|
* SPDX-License-Identifier: Apache-2.0
|
|
*/
|
|
|
|
#ifndef __INTEL_DAI_DRIVER_DMIC_H__
|
|
#define __INTEL_DAI_DRIVER_DMIC_H__
|
|
|
|
#include <zephyr/sys/util_macro.h>
|
|
|
|
/* The microphones create a low frequecy thump sound when clock is enabled.
|
|
* The unmute linear gain ramp chacteristic is defined here.
|
|
* NOTE: Do not set any of these to 0.
|
|
*/
|
|
#define DMIC_UNMUTE_RAMP_US 1000 /* 1 ms (in microseconds) */
|
|
#define DMIC_UNMUTE_CIC 1 /* Unmute CIC at 1 ms */
|
|
#define DMIC_UNMUTE_FIR 2 /* Unmute FIR at 2 ms */
|
|
|
|
/* Parameters used in modes computation */
|
|
#define DMIC_HW_BITS_CIC 26
|
|
#define DMIC_HW_BITS_FIR_COEF 20
|
|
#define DMIC_HW_BITS_FIR_GAIN 20
|
|
#define DMIC_HW_BITS_FIR_INPUT 22
|
|
#define DMIC_HW_BITS_FIR_OUTPUT 24
|
|
#define DMIC_HW_BITS_FIR_INTERNAL 26
|
|
#define DMIC_HW_BITS_GAIN_OUTPUT 22
|
|
#define DMIC_HW_FIR_LENGTH_MAX 250
|
|
#define DMIC_HW_CIC_SHIFT_MIN -8
|
|
#define DMIC_HW_CIC_SHIFT_MAX 4
|
|
#define DMIC_HW_FIR_SHIFT_MIN 0
|
|
#define DMIC_HW_FIR_SHIFT_MAX 8
|
|
#define DMIC_HW_CIC_DECIM_MIN 5
|
|
#define DMIC_HW_CIC_DECIM_MAX 31 /* Note: Limited by BITS_CIC */
|
|
#define DMIC_HW_FIR_DECIM_MIN 2
|
|
#define DMIC_HW_FIR_DECIM_MAX 20 /* Note: Practical upper limit */
|
|
#define DMIC_HW_SENS_Q28 Q_CONVERT_FLOAT(1.0, 28) /* Q1.28 */
|
|
#define DMIC_HW_PDM_CLK_MIN 100000 /* Note: Practical min value */
|
|
#define DMIC_HW_DUTY_MIN 20 /* Note: Practical min value */
|
|
#define DMIC_HW_DUTY_MAX 80 /* Note: Practical max value */
|
|
|
|
/* DC offset compensation time constants */
|
|
#define DCCOMP_TC0 0
|
|
#define DCCOMP_TC1 1
|
|
#define DCCOMP_TC2 2
|
|
#define DCCOMP_TC3 3
|
|
#define DCCOMP_TC4 4
|
|
#define DCCOMP_TC5 5
|
|
#define DCCOMP_TC6 6
|
|
#define DCCOMP_TC7 7
|
|
|
|
/* Used for scaling FIR coefficients for HW */
|
|
#define DMIC_HW_FIR_COEF_MAX ((1 << (DMIC_HW_BITS_FIR_COEF - 1)) - 1)
|
|
#define DMIC_HW_FIR_COEF_Q (DMIC_HW_BITS_FIR_COEF - 1)
|
|
|
|
/* Internal precision in gains computation, e.g. Q4.28 in int32_t */
|
|
#define DMIC_FIR_SCALE_Q 28
|
|
|
|
/* Used in unmute ramp values calculation */
|
|
#define DMIC_HW_FIR_GAIN_MAX ((1 << (DMIC_HW_BITS_FIR_GAIN - 1)) - 1)
|
|
|
|
#define DB2LIN_FIXED_INPUT_QY 24
|
|
#define DB2LIN_FIXED_OUTPUT_QY 20
|
|
|
|
/* Hardcoded log ramp parameters. The default ramp is 100 ms for 48 kHz
|
|
* and 200 ms for 16 kHz. The first parameter is the initial gain in
|
|
* decibels, set to -90 dB.
|
|
* The rate dependent ramp duration is provided by 1st order equation
|
|
* duration = coef * samplerate + offset.
|
|
* E.g. 100 ms @ 48 kHz, 200 ms @ 16 kHz
|
|
* y48 = 100; y16 = 200;
|
|
* dy = y48 - y16; dx = 48000 - 16000;
|
|
* coef = round(dy/dx * 2^15)
|
|
* offs = round(y16 - coef/2^15 * 16000)
|
|
* Note: The rate dependence can be disabled with zero time_coef with
|
|
* use of just the offset.
|
|
*/
|
|
#define LOGRAMP_START_DB Q_CONVERT_FLOAT(-90, DB2LIN_FIXED_INPUT_QY)
|
|
#define LOGRAMP_TIME_COEF_Q15 -102 /* coef = dy/dx */
|
|
#define LOGRAMP_TIME_OFFS_Q0 250 /* offs = Offset for line slope in ms */
|
|
|
|
/* Limits for ramp time from topology */
|
|
#define LOGRAMP_TIME_MIN_MS 10 /* Min. 10 ms */
|
|
#define LOGRAMP_TIME_MAX_MS 1000 /* Max. 1s */
|
|
|
|
/* Simplify log ramp step calculation equation with this constant term */
|
|
#define LOGRAMP_CONST_TERM ((int32_t) \
|
|
((int64_t)-LOGRAMP_START_DB * DMIC_UNMUTE_RAMP_US / 1000))
|
|
|
|
/* Fractional shift for gain update. Gain format is Q2.30. */
|
|
#define Q_SHIFT_GAIN_X_GAIN_COEF \
|
|
(Q_SHIFT_BITS_32(30, DB2LIN_FIXED_OUTPUT_QY, 30))
|
|
|
|
/* Compute the number of shifts
|
|
* This will result in a compiler overflow error if shift bits are out of
|
|
* range as INT64_MAX/MIN is greater than 32 bit Q shift parameter
|
|
*/
|
|
#define Q_SHIFT_BITS_64(qx, qy, qz) \
|
|
((qx + qy - qz) <= 63 ? (((qx + qy - qz) >= 0) ? \
|
|
(qx + qy - qz) : INT64_MIN) : INT64_MAX)
|
|
|
|
#define Q_SHIFT_BITS_32(qx, qy, qz) \
|
|
((qx + qy - qz) <= 31 ? (((qx + qy - qz) >= 0) ? \
|
|
(qx + qy - qz) : INT32_MIN) : INT32_MAX)
|
|
|
|
/* Fractional multiplication with shift and round
|
|
* Note that the parameters px and py must be cast to (int64_t) if other type.
|
|
*/
|
|
#define Q_MULTSR_32X32(px, py, qx, qy, qp) \
|
|
((((px) * (py) >> ((qx)+(qy)-(qp)-1)) + 1) >> 1)
|
|
|
|
/* A more clever macro for Q-shifts */
|
|
#define Q_SHIFT(x, src_q, dst_q) ((x) >> ((src_q) - (dst_q)))
|
|
#define Q_SHIFT_RND(x, src_q, dst_q) \
|
|
((((x) >> ((src_q) - (dst_q) - 1)) + 1) >> 1)
|
|
|
|
/* Alternative version since compiler does not allow (x >> -1) */
|
|
#define Q_SHIFT_LEFT(x, src_q, dst_q) ((x) << ((dst_q) - (src_q)))
|
|
|
|
/* Convert a float number to fractional Qnx.ny format. Note that there is no
|
|
* check for nx+ny number of bits to fit the word length of int. The parameter
|
|
* qy must be 31 or less.
|
|
*/
|
|
#define Q_CONVERT_FLOAT(f, qy) \
|
|
((int32_t)(((const double)f) * ((int64_t)1 << (const int)qy) + 0.5))
|
|
|
|
#define TWO_Q27 Q_CONVERT_FLOAT(2.0, 27) /* Use Q5.27 */
|
|
#define MINUS_TWO_Q27 Q_CONVERT_FLOAT(-2.0, 27) /* Use Q5.27 */
|
|
#define ONE_Q20 Q_CONVERT_FLOAT(1.0, 20) /* Use Q12.20 */
|
|
#define ONE_Q23 Q_CONVERT_FLOAT(1.0, 23) /* Use Q9.23 */
|
|
#define LOG10_DIV20_Q27 Q_CONVERT_FLOAT(0.1151292546, 27) /* Use Q5.27 */
|
|
|
|
#define DMA_HANDSHAKE_DMIC_CH0 0
|
|
#define DMA_HANDSHAKE_DMIC_CH1 1
|
|
|
|
enum dai_dmic_frame_format {
|
|
DAI_DMIC_FRAME_S16_LE = 0,
|
|
DAI_DMIC_FRAME_S24_4LE,
|
|
DAI_DMIC_FRAME_S32_LE,
|
|
DAI_DMIC_FRAME_FLOAT,
|
|
/* other formats here */
|
|
DAI_DMIC_FRAME_S24_3LE,
|
|
};
|
|
|
|
/* Common data for all DMIC DAI instances */
|
|
struct dai_dmic_global_shared {
|
|
uint32_t active_fifos_mask; /* Bits (dai->index) are set to indicate active FIFO */
|
|
uint32_t pause_mask; /* Bits (dai->index) are set to indicate driver pause */
|
|
};
|
|
|
|
struct dai_dmic_plat_fifo_data {
|
|
uint32_t offset;
|
|
uint32_t width;
|
|
uint32_t depth;
|
|
uint32_t watermark;
|
|
uint32_t handshake;
|
|
};
|
|
|
|
|
|
struct dai_intel_dmic {
|
|
struct dai_config dai_config_params;
|
|
|
|
struct k_spinlock lock; /**< locking mechanism */
|
|
int sref; /**< simple ref counter, guarded by lock */
|
|
enum dai_state state; /* Driver component state */
|
|
uint16_t enable[CONFIG_DAI_DMIC_HW_CONTROLLERS];/* Mic 0 and 1 enable bits array for PDMx */
|
|
struct dai_dmic_plat_fifo_data fifo; /* dmic capture fifo stream */
|
|
int32_t gain_coef; /* Gain update constant */
|
|
int32_t gain; /* Gain value to be applied to HW */
|
|
int32_t startcount; /* Counter that controls HW unmute */
|
|
int32_t unmute_time_ms; /* Unmute ramp time in milliseconds */
|
|
|
|
/* hardware parameters */
|
|
uint32_t reg_base;
|
|
uint32_t shim_base;
|
|
#if defined(CONFIG_SOC_INTEL_ACE20_LNL) || defined(CONFIG_SOC_INTEL_ACE30_PTL)
|
|
uint32_t hdamldmic_base;
|
|
uint32_t vshim_base;
|
|
#endif
|
|
int irq;
|
|
uint32_t flags;
|
|
uint32_t gain_left;
|
|
uint32_t gain_right;
|
|
};
|
|
|
|
static inline int32_t sat_int32(int64_t x)
|
|
{
|
|
if (x > INT32_MAX)
|
|
return INT32_MAX;
|
|
else if (x < INT32_MIN)
|
|
return INT32_MIN;
|
|
else
|
|
return (int32_t)x;
|
|
}
|
|
/* Fractional multiplication with shift and saturation */
|
|
static inline int32_t q_multsr_sat_32x32(int32_t x, int32_t y,
|
|
const int shift_bits)
|
|
{
|
|
return sat_int32(((((int64_t)x * y) >> (shift_bits - 1)) + 1) >> 1);
|
|
}
|
|
|
|
static inline int dmic_get_unmute_ramp_from_samplerate(int rate)
|
|
{
|
|
int time_ms;
|
|
|
|
time_ms = Q_MULTSR_32X32((int32_t)rate, LOGRAMP_TIME_COEF_Q15, 0, 15, 0) +
|
|
LOGRAMP_TIME_OFFS_Q0;
|
|
if (time_ms > LOGRAMP_TIME_MAX_MS)
|
|
return LOGRAMP_TIME_MAX_MS;
|
|
|
|
if (time_ms < LOGRAMP_TIME_MIN_MS)
|
|
return LOGRAMP_TIME_MIN_MS;
|
|
|
|
return time_ms;
|
|
}
|
|
|
|
#endif /* __INTEL_DAI_DRIVER_DMIC_H__ */
|