blob: e06ed80daed75ff92627a580e5ddf853dc371719 [file] [log] [blame]
/*
* 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;
#ifdef CONFIG_SOC_INTEL_ACE20_LNL
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__ */