// SPDX-License-Identifier: GPL-2.0-only
//
// tegra210_mbdrc.c - Tegra210 MBDRC driver
//
// Copyright (c) 2022, NVIDIA CORPORATION. All rights reserved.
#include <linux/device.h>
#include <linux/io.h>
#include <linux/module.h>
#include <linux/of_address.h>
#include <linux/pm_runtime.h>
#include <linux/regmap.h>
#include <sound/core.h>
#include <sound/soc.h>
#include <sound/tlv.h>
#include "tegra210_mbdrc.h"
#include "tegra210_ope.h"
#define MBDRC_FILTER_REG(reg, id) \
((reg) + ((id) * TEGRA210_MBDRC_FILTER_PARAM_STRIDE))
#define MBDRC_FILTER_REG_DEFAULTS(id) \
{ MBDRC_FILTER_REG(TEGRA210_MBDRC_IIR_CFG, id), 0 x00000005}, \
{ MBDRC_FILTER_REG(TEGRA210_MBDRC_IN_ATTACK, id), 0 x3e48590c}, \
{ MBDRC_FILTER_REG(TEGRA210_MBDRC_IN_RELEASE, id), 0 x08414e9f}, \
{ MBDRC_FILTER_REG(TEGRA210_MBDRC_FAST_ATTACK, id), 0 x7fffffff}, \
{ MBDRC_FILTER_REG(TEGRA210_MBDRC_IN_THRESHOLD, id), 0 x06145082}, \
{ MBDRC_FILTER_REG(TEGRA210_MBDRC_OUT_THRESHOLD, id), 0 x060d379b}, \
{ MBDRC_FILTER_REG(TEGRA210_MBDRC_RATIO_1ST, id), 0 x0000a000}, \
{ MBDRC_FILTER_REG(TEGRA210_MBDRC_RATIO_2ND, id), 0 x00002000}, \
{ MBDRC_FILTER_REG(TEGRA210_MBDRC_RATIO_3RD, id), 0 x00000b33}, \
{ MBDRC_FILTER_REG(TEGRA210_MBDRC_RATIO_4TH, id), 0 x00000800}, \
{ MBDRC_FILTER_REG(TEGRA210_MBDRC_RATIO_5TH, id), 0 x0000019a}, \
{ MBDRC_FILTER_REG(TEGRA210_MBDRC_MAKEUP_GAIN, id), 0 x00000002}, \
{ MBDRC_FILTER_REG(TEGRA210_MBDRC_INIT_GAIN, id), 0 x00066666}, \
{ MBDRC_FILTER_REG(TEGRA210_MBDRC_GAIN_ATTACK, id), 0 x00d9ba0e}, \
{ MBDRC_FILTER_REG(TEGRA210_MBDRC_GAIN_RELEASE, id), 0 x3e48590c}, \
{ MBDRC_FILTER_REG(TEGRA210_MBDRC_FAST_RELEASE, id), 0 x7ffff26a}, \
{ MBDRC_FILTER_REG(TEGRA210_MBDRC_CFG_RAM_CTRL, id), 0 x4000}
static const struct reg_default tegra210_mbdrc_reg_defaults[] = {
{ TEGRA210_MBDRC_CFG, 0 x0030de51},
{ TEGRA210_MBDRC_CHANNEL_MASK, 0 x00000003},
{ TEGRA210_MBDRC_FAST_FACTOR, 0 x30000800},
MBDRC_FILTER_REG_DEFAULTS(0 ),
MBDRC_FILTER_REG_DEFAULTS(1 ),
MBDRC_FILTER_REG_DEFAULTS(2 ),
};
/* Default MBDRC parameters */
static const struct tegra210_mbdrc_config mbdrc_init_config = {
.mode = 0 , /* Bypass */
.rms_off = 48 ,
.peak_rms_mode = 1 , /* PEAK */
.filter_structure = 0 , /* All-pass tree */
.shift_ctrl = 30 ,
.frame_size = 32 ,
.channel_mask = 0 x3,
.fa_factor = 2048 ,
.fr_factor = 14747 ,
.band_params[MBDRC_LOW_BAND] = {
.band = MBDRC_LOW_BAND,
.iir_stages = 5 ,
.in_attack_tc = 1044928780 ,
.in_release_tc = 138497695 ,
.fast_attack_tc = 2147483647 ,
.in_threshold = {130 , 80 , 20 , 6 },
.out_threshold = {155 , 55 , 13 , 6 },
.ratio = {40960 , 8192 , 2867 , 2048 , 410 },
.makeup_gain = 4 ,
.gain_init = 419430 ,
.gain_attack_tc = 14268942 ,
.gain_release_tc = 1440547090 ,
.fast_release_tc = 2147480170 ,
.biquad_params = {
/*
* Gains:
*
* b0, b1, a0,
* a1, a2,
*/
/* Band-0 */
961046798 , -2030431983 , 1073741824 ,
2030431983 , -961046798 ,
/* Band-1 */
1030244425 , -2099481453 , 1073741824 ,
2099481453 , -1030244425 ,
/* Band-2 */
1067169294 , -2136327263 , 1073741824 ,
2136327263 , -1067169294 ,
/* Band-3 */
434951949 , -1306567134 , 1073741824 ,
1306567134 , -434951949 ,
/* Band-4 */
780656019 , -1605955641 , 1073741824 ,
1605955641 , -780656019 ,
/* Band-5 */
1024497031 , -1817128152 , 1073741824 ,
1817128152 , -1024497031 ,
/* Band-6 */
1073741824 , 0 , 0 ,
0 , 0 ,
/* Band-7 */
1073741824 , 0 , 0 ,
0 , 0 ,
}
},
.band_params[MBDRC_MID_BAND] = {
.band = MBDRC_MID_BAND,
.iir_stages = 5 ,
.in_attack_tc = 1581413104 ,
.in_release_tc = 35494783 ,
.fast_attack_tc = 2147483647 ,
.in_threshold = {130 , 50 , 30 , 6 },
.out_threshold = {106 , 50 , 30 , 13 },
.ratio = {40960 , 2867 , 4096 , 2867 , 410 },
.makeup_gain = 6 ,
.gain_init = 419430 ,
.gain_attack_tc = 4766887 ,
.gain_release_tc = 1044928780 ,
.fast_release_tc = 2147480170 ,
.biquad_params = {
/*
* Gains:
*
* b0, b1, a0,
* a1, a2,
*/
/* Band-0 */
-1005668963 , 1073741824 , 0 ,
1005668963 , 0 ,
/* Band-1 */
998437058 , -2067742187 , 1073741824 ,
2067742187 , -998437058 ,
/* Band-2 */
1051963422 , -2121153948 , 1073741824 ,
2121153948 , -1051963422 ,
/* Band-3 */
434951949 , -1306567134 , 1073741824 ,
1306567134 , -434951949 ,
/* Band-4 */
780656019 , -1605955641 , 1073741824 ,
1605955641 , -780656019 ,
/* Band-5 */
1024497031 , -1817128152 , 1073741824 ,
1817128152 , -1024497031 ,
/* Band-6 */
1073741824 , 0 , 0 ,
0 , 0 ,
/* Band-7 */
1073741824 , 0 , 0 ,
0 , 0 ,
}
},
.band_params[MBDRC_HIGH_BAND] = {
.band = MBDRC_HIGH_BAND,
.iir_stages = 5 ,
.in_attack_tc = 2144750688 ,
.in_release_tc = 70402888 ,
.fast_attack_tc = 2147483647 ,
.in_threshold = {130 , 50 , 30 , 6 },
.out_threshold = {106 , 50 , 30 , 13 },
.ratio = {40960 , 2867 , 4096 , 2867 , 410 },
.makeup_gain = 6 ,
.gain_init = 419430 ,
.gain_attack_tc = 4766887 ,
.gain_release_tc = 1044928780 ,
.fast_release_tc = 2147480170 ,
.biquad_params = {
/*
* Gains:
*
* b0, b1, a0,
* a1, a2,
*/
/* Band-0 */
1073741824 , 0 , 0 ,
0 , 0 ,
/* Band-1 */
1073741824 , 0 , 0 ,
0 , 0 ,
/* Band-2 */
1073741824 , 0 , 0 ,
0 , 0 ,
/* Band-3 */
-619925131 , 1073741824 , 0 ,
619925131 , 0 ,
/* Band-4 */
606839335 , -1455425976 , 1073741824 ,
1455425976 , -606839335 ,
/* Band-5 */
917759617 , -1724690840 , 1073741824 ,
1724690840 , -917759617 ,
/* Band-6 */
1073741824 , 0 , 0 ,
0 , 0 ,
/* Band-7 */
1073741824 , 0 , 0 ,
0 , 0 ,
}
}
};
static void tegra210_mbdrc_write_ram(struct regmap *regmap, unsigned int reg_ctrl,
unsigned int reg_data, unsigned int ram_offset,
unsigned int *data, size_t size)
{
unsigned int val;
unsigned int i;
val = ram_offset & TEGRA210_MBDRC_RAM_CTRL_RAM_ADDR_MASK;
val |= TEGRA210_MBDRC_RAM_CTRL_ADDR_INIT_EN;
val |= TEGRA210_MBDRC_RAM_CTRL_SEQ_ACCESS_EN;
val |= TEGRA210_MBDRC_RAM_CTRL_RW_WRITE;
regmap_write(regmap, reg_ctrl, val);
for (i = 0 ; i < size; i++)
regmap_write(regmap, reg_data, data[i]);
}
static int tegra210_mbdrc_get(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
struct soc_mixer_control *mc =
(struct soc_mixer_control *)kcontrol->private_value;
struct snd_soc_component *cmpnt = snd_soc_kcontrol_component(kcontrol);
struct tegra210_ope *ope = snd_soc_component_get_drvdata(cmpnt);
unsigned int val;
regmap_read(ope->mbdrc_regmap, mc->reg, &val);
ucontrol->value.integer.value[0 ] = (val >> mc->shift) & mc->max;
return 0 ;
}
static int tegra210_mbdrc_put(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
struct soc_mixer_control *mc =
(struct soc_mixer_control *)kcontrol->private_value;
struct snd_soc_component *cmpnt = snd_soc_kcontrol_component(kcontrol);
struct tegra210_ope *ope = snd_soc_component_get_drvdata(cmpnt);
unsigned int val = ucontrol->value.integer.value[0 ];
bool change = false ;
val = val << mc->shift;
regmap_update_bits_check(ope->mbdrc_regmap, mc->reg,
(mc->max << mc->shift), val, &change);
return change ? 1 : 0 ;
}
static int tegra210_mbdrc_get_enum(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
struct snd_soc_component *cmpnt = snd_soc_kcontrol_component(kcontrol);
struct tegra210_ope *ope = snd_soc_component_get_drvdata(cmpnt);
struct soc_enum *e = (struct soc_enum *)kcontrol->private_value;
unsigned int val;
regmap_read(ope->mbdrc_regmap, e->reg, &val);
ucontrol->value.enumerated.item[0 ] = (val >> e->shift_l) & e->mask;
return 0 ;
}
static int tegra210_mbdrc_put_enum(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
struct snd_soc_component *cmpnt = snd_soc_kcontrol_component(kcontrol);
struct tegra210_ope *ope = snd_soc_component_get_drvdata(cmpnt);
struct soc_enum *e = (struct soc_enum *)kcontrol->private_value;
bool change = false ;
unsigned int val;
unsigned int mask;
if (ucontrol->value.enumerated.item[0 ] > e->items - 1 )
return -EINVAL;
val = ucontrol->value.enumerated.item[0 ] << e->shift_l;
mask = e->mask << e->shift_l;
regmap_update_bits_check(ope->mbdrc_regmap, e->reg, mask, val,
&change);
return change ? 1 : 0 ;
}
static int tegra210_mbdrc_band_params_get(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
struct tegra_soc_bytes *params = (void *)kcontrol->private_value;
struct snd_soc_component *cmpnt = snd_soc_kcontrol_component(kcontrol);
struct tegra210_ope *ope = snd_soc_component_get_drvdata(cmpnt);
u32 *data = (u32 *)ucontrol->value.bytes.data;
u32 regs = params->soc.base;
u32 mask = params->soc.mask;
u32 shift = params->shift;
unsigned int i;
for (i = 0 ; i < params->soc.num_regs; i++, regs += cmpnt->val_bytes) {
regmap_read(ope->mbdrc_regmap, regs, &data[i]);
data[i] = ((data[i] & mask) >> shift);
}
return 0 ;
}
static int tegra210_mbdrc_band_params_put(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
struct tegra_soc_bytes *params = (void *)kcontrol->private_value;
struct snd_soc_component *cmpnt = snd_soc_kcontrol_component(kcontrol);
struct tegra210_ope *ope = snd_soc_component_get_drvdata(cmpnt);
u32 *data = (u32 *)ucontrol->value.bytes.data;
u32 regs = params->soc.base;
u32 mask = params->soc.mask;
u32 shift = params->shift;
bool change = false ;
unsigned int i;
for (i = 0 ; i < params->soc.num_regs; i++, regs += cmpnt->val_bytes) {
bool update = false ;
regmap_update_bits_check(ope->mbdrc_regmap, regs, mask,
data[i] << shift, &update);
change |= update;
}
return change ? 1 : 0 ;
}
static int tegra210_mbdrc_threshold_get(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
struct tegra_soc_bytes *params = (void *)kcontrol->private_value;
struct snd_soc_component *cmpnt = snd_soc_kcontrol_component(kcontrol);
struct tegra210_ope *ope = snd_soc_component_get_drvdata(cmpnt);
u32 *data = (u32 *)ucontrol->value.bytes.data;
u32 regs = params->soc.base;
u32 num_regs = params->soc.num_regs;
u32 val;
unsigned int i;
for (i = 0 ; i < num_regs; i += 4 , regs += cmpnt->val_bytes) {
regmap_read(ope->mbdrc_regmap, regs, &val);
data[i] = (val & TEGRA210_MBDRC_THRESH_1ST_MASK) >>
TEGRA210_MBDRC_THRESH_1ST_SHIFT;
data[i + 1 ] = (val & TEGRA210_MBDRC_THRESH_2ND_MASK) >>
TEGRA210_MBDRC_THRESH_2ND_SHIFT;
data[i + 2 ] = (val & TEGRA210_MBDRC_THRESH_3RD_MASK) >>
TEGRA210_MBDRC_THRESH_3RD_SHIFT;
data[i + 3 ] = (val & TEGRA210_MBDRC_THRESH_4TH_MASK) >>
TEGRA210_MBDRC_THRESH_4TH_SHIFT;
}
return 0 ;
}
static int tegra210_mbdrc_threshold_put(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
struct tegra_soc_bytes *params = (void *)kcontrol->private_value;
struct snd_soc_component *cmpnt = snd_soc_kcontrol_component(kcontrol);
struct tegra210_ope *ope = snd_soc_component_get_drvdata(cmpnt);
u32 *data = (u32 *)ucontrol->value.bytes.data;
u32 regs = params->soc.base;
u32 num_regs = params->soc.num_regs;
bool change = false ;
unsigned int i;
for (i = 0 ; i < num_regs; i += 4 , regs += cmpnt->val_bytes) {
bool update = false ;
data[i] = (((data[i] >> TEGRA210_MBDRC_THRESH_1ST_SHIFT) &
TEGRA210_MBDRC_THRESH_1ST_MASK) |
((data[i + 1 ] >> TEGRA210_MBDRC_THRESH_2ND_SHIFT) &
TEGRA210_MBDRC_THRESH_2ND_MASK) |
((data[i + 2 ] >> TEGRA210_MBDRC_THRESH_3RD_SHIFT) &
TEGRA210_MBDRC_THRESH_3RD_MASK) |
((data[i + 3 ] >> TEGRA210_MBDRC_THRESH_4TH_SHIFT) &
TEGRA210_MBDRC_THRESH_4TH_MASK));
regmap_update_bits_check(ope->mbdrc_regmap, regs, 0 xffffffff,
data[i], &update);
change |= update;
}
return change ? 1 : 0 ;
}
static int tegra210_mbdrc_biquad_coeffs_get(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
struct tegra_soc_bytes *params = (void *)kcontrol->private_value;
struct snd_soc_component *cmpnt = snd_soc_kcontrol_component(kcontrol);
u32 *data = (u32 *)ucontrol->value.bytes.data;
memset(data, 0 , params->soc.num_regs * cmpnt->val_bytes);
return 0 ;
}
static int tegra210_mbdrc_biquad_coeffs_put(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
struct tegra_soc_bytes *params = (void *)kcontrol->private_value;
struct snd_soc_component *cmpnt = snd_soc_kcontrol_component(kcontrol);
struct tegra210_ope *ope = snd_soc_component_get_drvdata(cmpnt);
u32 reg_ctrl = params->soc.base;
u32 reg_data = reg_ctrl + cmpnt->val_bytes;
u32 *data = (u32 *)ucontrol->value.bytes.data;
tegra210_mbdrc_write_ram(ope->mbdrc_regmap, reg_ctrl, reg_data,
params->shift, data, params->soc.num_regs);
return 1 ;
}
static int tegra210_mbdrc_param_info(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_info *uinfo)
{
struct soc_bytes *params = (void *)kcontrol->private_value;
uinfo->type = SNDRV_CTL_ELEM_TYPE_BYTES;
uinfo->count = params->num_regs * sizeof (u32);
return 0 ;
}
static int tegra210_mbdrc_vol_get(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
struct soc_mixer_control *mc =
(struct soc_mixer_control *)kcontrol->private_value;
struct snd_soc_component *cmpnt = snd_soc_kcontrol_component(kcontrol);
struct tegra210_ope *ope = snd_soc_component_get_drvdata(cmpnt);
int val;
regmap_read(ope->mbdrc_regmap, mc->reg, &val);
ucontrol->value.integer.value[0 ] =
((val >> mc->shift) - TEGRA210_MBDRC_MASTER_VOL_MIN);
return 0 ;
}
static int tegra210_mbdrc_vol_put(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
struct soc_mixer_control *mc =
(struct soc_mixer_control *)kcontrol->private_value;
struct snd_soc_component *cmpnt = snd_soc_kcontrol_component(kcontrol);
struct tegra210_ope *ope = snd_soc_component_get_drvdata(cmpnt);
int val = ucontrol->value.integer.value[0 ];
bool change = false ;
val += TEGRA210_MBDRC_MASTER_VOL_MIN;
regmap_update_bits_check(ope->mbdrc_regmap, mc->reg,
mc->max << mc->shift, val << mc->shift,
&change);
regmap_read(ope->mbdrc_regmap, mc->reg, &val);
return change ? 1 : 0 ;
}
static const char * const tegra210_mbdrc_mode_text[] = {
"Bypass" , "Fullband" , "Dualband" , "Multiband"
};
static const struct soc_enum tegra210_mbdrc_mode_enum =
SOC_ENUM_SINGLE(TEGRA210_MBDRC_CFG, TEGRA210_MBDRC_CFG_MBDRC_MODE_SHIFT,
4 , tegra210_mbdrc_mode_text);
static const char * const tegra210_mbdrc_peak_rms_text[] = {
"Peak" , "RMS"
};
static const struct soc_enum tegra210_mbdrc_peak_rms_enum =
SOC_ENUM_SINGLE(TEGRA210_MBDRC_CFG, TEGRA210_MBDRC_CFG_PEAK_RMS_SHIFT,
2 , tegra210_mbdrc_peak_rms_text);
static const char * const tegra210_mbdrc_filter_structure_text[] = {
"All-pass-tree" , "Flexible"
};
static const struct soc_enum tegra210_mbdrc_filter_structure_enum =
SOC_ENUM_SINGLE(TEGRA210_MBDRC_CFG,
TEGRA210_MBDRC_CFG_FILTER_STRUCTURE_SHIFT, 2 ,
tegra210_mbdrc_filter_structure_text);
static const char * const tegra210_mbdrc_frame_size_text[] = {
"N1" , "N2" , "N4" , "N8" , "N16" , "N32" , "N64"
};
static const struct soc_enum tegra210_mbdrc_frame_size_enum =
SOC_ENUM_SINGLE(TEGRA210_MBDRC_CFG, TEGRA210_MBDRC_CFG_FRAME_SIZE_SHIFT,
7 , tegra210_mbdrc_frame_size_text);
#define TEGRA_MBDRC_BYTES_EXT(xname, xbase, xregs, xshift, xmask, xinfo) \
TEGRA_SOC_BYTES_EXT(xname, xbase, xregs, xshift, xmask, \
tegra210_mbdrc_band_params_get, \
tegra210_mbdrc_band_params_put, \
tegra210_mbdrc_param_info)
#define TEGRA_MBDRC_BAND_BYTES_EXT(xname, xbase, xshift, xmask, xinfo) \
TEGRA_MBDRC_BYTES_EXT(xname, xbase, TEGRA210_MBDRC_FILTER_COUNT, \
xshift, xmask, xinfo)
static const DECLARE_TLV_DB_MINMAX(mdbrc_vol_tlv, -25600 , 25500 );
static const struct snd_kcontrol_new tegra210_mbdrc_controls[] = {
SOC_ENUM_EXT("MBDRC Peak RMS Mode" , tegra210_mbdrc_peak_rms_enum,
tegra210_mbdrc_get_enum, tegra210_mbdrc_put_enum),
SOC_ENUM_EXT("MBDRC Filter Structure" ,
tegra210_mbdrc_filter_structure_enum,
tegra210_mbdrc_get_enum, tegra210_mbdrc_put_enum),
SOC_ENUM_EXT("MBDRC Frame Size" , tegra210_mbdrc_frame_size_enum,
tegra210_mbdrc_get_enum, tegra210_mbdrc_put_enum),
SOC_ENUM_EXT("MBDRC Mode" , tegra210_mbdrc_mode_enum,
tegra210_mbdrc_get_enum, tegra210_mbdrc_put_enum),
SOC_SINGLE_EXT("MBDRC RMS Offset" , TEGRA210_MBDRC_CFG,
TEGRA210_MBDRC_CFG_RMS_OFFSET_SHIFT, 0 x1ff, 0 ,
tegra210_mbdrc_get, tegra210_mbdrc_put),
SOC_SINGLE_EXT("MBDRC Shift Control" , TEGRA210_MBDRC_CFG,
TEGRA210_MBDRC_CFG_SHIFT_CTRL_SHIFT, 0 x1f, 0 ,
tegra210_mbdrc_get, tegra210_mbdrc_put),
SOC_SINGLE_EXT("MBDRC Fast Attack Factor" , TEGRA210_MBDRC_FAST_FACTOR,
TEGRA210_MBDRC_FAST_FACTOR_ATTACK_SHIFT, 0 xffff, 0 ,
tegra210_mbdrc_get, tegra210_mbdrc_put),
SOC_SINGLE_EXT("MBDRC Fast Release Factor" , TEGRA210_MBDRC_FAST_FACTOR,
TEGRA210_MBDRC_FAST_FACTOR_RELEASE_SHIFT, 0 xffff, 0 ,
tegra210_mbdrc_get, tegra210_mbdrc_put),
SOC_SINGLE_RANGE_EXT_TLV("MBDRC Master Volume" ,
TEGRA210_MBDRC_MASTER_VOL,
TEGRA210_MBDRC_MASTER_VOL_SHIFT,
0 , 0 x1ff, 0 ,
tegra210_mbdrc_vol_get, tegra210_mbdrc_vol_put,
mdbrc_vol_tlv),
TEGRA_SOC_BYTES_EXT("MBDRC IIR Stages" , TEGRA210_MBDRC_IIR_CFG,
TEGRA210_MBDRC_FILTER_COUNT,
TEGRA210_MBDRC_IIR_CFG_NUM_STAGES_SHIFT,
TEGRA210_MBDRC_IIR_CFG_NUM_STAGES_MASK,
tegra210_mbdrc_band_params_get,
tegra210_mbdrc_band_params_put,
tegra210_mbdrc_param_info),
TEGRA_SOC_BYTES_EXT("MBDRC In Attack Time Const" , TEGRA210_MBDRC_IN_ATTACK,
TEGRA210_MBDRC_FILTER_COUNT,
TEGRA210_MBDRC_IN_ATTACK_TC_SHIFT,
TEGRA210_MBDRC_IN_ATTACK_TC_MASK,
tegra210_mbdrc_band_params_get,
tegra210_mbdrc_band_params_put,
tegra210_mbdrc_param_info),
TEGRA_SOC_BYTES_EXT("MBDRC In Release Time Const" , TEGRA210_MBDRC_IN_RELEASE,
TEGRA210_MBDRC_FILTER_COUNT,
TEGRA210_MBDRC_IN_RELEASE_TC_SHIFT,
TEGRA210_MBDRC_IN_RELEASE_TC_MASK,
tegra210_mbdrc_band_params_get,
tegra210_mbdrc_band_params_put,
tegra210_mbdrc_param_info),
TEGRA_SOC_BYTES_EXT("MBDRC Fast Attack Time Const" , TEGRA210_MBDRC_FAST_ATTACK,
TEGRA210_MBDRC_FILTER_COUNT,
TEGRA210_MBDRC_FAST_ATTACK_TC_SHIFT,
TEGRA210_MBDRC_FAST_ATTACK_TC_MASK,
tegra210_mbdrc_band_params_get,
tegra210_mbdrc_band_params_put,
tegra210_mbdrc_param_info),
TEGRA_SOC_BYTES_EXT("MBDRC In Threshold" , TEGRA210_MBDRC_IN_THRESHOLD,
TEGRA210_MBDRC_FILTER_COUNT * 4 , 0 , 0 xffffffff,
tegra210_mbdrc_threshold_get,
tegra210_mbdrc_threshold_put,
tegra210_mbdrc_param_info),
TEGRA_SOC_BYTES_EXT("MBDRC Out Threshold" , TEGRA210_MBDRC_OUT_THRESHOLD,
TEGRA210_MBDRC_FILTER_COUNT * 4 , 0 , 0 xffffffff,
tegra210_mbdrc_threshold_get,
tegra210_mbdrc_threshold_put,
tegra210_mbdrc_param_info),
TEGRA_SOC_BYTES_EXT("MBDRC Ratio" , TEGRA210_MBDRC_RATIO_1ST,
TEGRA210_MBDRC_FILTER_COUNT * 5 ,
TEGRA210_MBDRC_RATIO_1ST_SHIFT, TEGRA210_MBDRC_RATIO_1ST_MASK,
tegra210_mbdrc_band_params_get,
tegra210_mbdrc_band_params_put,
tegra210_mbdrc_param_info),
TEGRA_SOC_BYTES_EXT("MBDRC Makeup Gain" , TEGRA210_MBDRC_MAKEUP_GAIN,
TEGRA210_MBDRC_FILTER_COUNT,
TEGRA210_MBDRC_MAKEUP_GAIN_SHIFT,
TEGRA210_MBDRC_MAKEUP_GAIN_MASK,
tegra210_mbdrc_band_params_get,
tegra210_mbdrc_band_params_put,
tegra210_mbdrc_param_info),
TEGRA_SOC_BYTES_EXT("MBDRC Init Gain" , TEGRA210_MBDRC_INIT_GAIN,
TEGRA210_MBDRC_FILTER_COUNT,
TEGRA210_MBDRC_INIT_GAIN_SHIFT,
TEGRA210_MBDRC_INIT_GAIN_MASK,
tegra210_mbdrc_band_params_get,
tegra210_mbdrc_band_params_put,
tegra210_mbdrc_param_info),
TEGRA_SOC_BYTES_EXT("MBDRC Attack Gain" , TEGRA210_MBDRC_GAIN_ATTACK,
TEGRA210_MBDRC_FILTER_COUNT,
TEGRA210_MBDRC_GAIN_ATTACK_SHIFT,
TEGRA210_MBDRC_GAIN_ATTACK_MASK,
tegra210_mbdrc_band_params_get,
tegra210_mbdrc_band_params_put,
tegra210_mbdrc_param_info),
TEGRA_SOC_BYTES_EXT("MBDRC Release Gain" , TEGRA210_MBDRC_GAIN_RELEASE,
TEGRA210_MBDRC_FILTER_COUNT,
TEGRA210_MBDRC_GAIN_RELEASE_SHIFT,
TEGRA210_MBDRC_GAIN_RELEASE_MASK,
tegra210_mbdrc_band_params_get,
tegra210_mbdrc_band_params_put,
tegra210_mbdrc_param_info),
TEGRA_SOC_BYTES_EXT("MBDRC Fast Release Gain" ,
TEGRA210_MBDRC_FAST_RELEASE,
TEGRA210_MBDRC_FILTER_COUNT,
TEGRA210_MBDRC_FAST_RELEASE_SHIFT,
TEGRA210_MBDRC_FAST_RELEASE_MASK,
tegra210_mbdrc_band_params_get,
tegra210_mbdrc_band_params_put,
tegra210_mbdrc_param_info),
TEGRA_SOC_BYTES_EXT("MBDRC Low Band Biquad Coeffs" ,
TEGRA210_MBDRC_CFG_RAM_CTRL,
TEGRA210_MBDRC_MAX_BIQUAD_STAGES * 5 , 0 , 0 xffffffff,
tegra210_mbdrc_biquad_coeffs_get,
tegra210_mbdrc_biquad_coeffs_put,
tegra210_mbdrc_param_info),
TEGRA_SOC_BYTES_EXT("MBDRC Mid Band Biquad Coeffs" ,
TEGRA210_MBDRC_CFG_RAM_CTRL +
TEGRA210_MBDRC_FILTER_PARAM_STRIDE,
TEGRA210_MBDRC_MAX_BIQUAD_STAGES * 5 , 0 , 0 xffffffff,
tegra210_mbdrc_biquad_coeffs_get,
tegra210_mbdrc_biquad_coeffs_put,
tegra210_mbdrc_param_info),
TEGRA_SOC_BYTES_EXT("MBDRC High Band Biquad Coeffs" ,
TEGRA210_MBDRC_CFG_RAM_CTRL +
(TEGRA210_MBDRC_FILTER_PARAM_STRIDE * 2 ),
TEGRA210_MBDRC_MAX_BIQUAD_STAGES * 5 , 0 , 0 xffffffff,
tegra210_mbdrc_biquad_coeffs_get,
tegra210_mbdrc_biquad_coeffs_put,
tegra210_mbdrc_param_info),
};
static bool tegra210_mbdrc_wr_reg(struct device *dev, unsigned int reg)
{
if (reg >= TEGRA210_MBDRC_IIR_CFG)
reg -= ((reg - TEGRA210_MBDRC_IIR_CFG) %
(TEGRA210_MBDRC_FILTER_PARAM_STRIDE *
TEGRA210_MBDRC_FILTER_COUNT));
switch (reg) {
case TEGRA210_MBDRC_SOFT_RESET:
case TEGRA210_MBDRC_CG:
case TEGRA210_MBDRC_CFG ... TEGRA210_MBDRC_CFG_RAM_DATA:
return true ;
default :
return false ;
}
}
static bool tegra210_mbdrc_rd_reg(struct device *dev, unsigned int reg)
{
if (tegra210_mbdrc_wr_reg(dev, reg))
return true ;
if (reg >= TEGRA210_MBDRC_IIR_CFG)
reg -= ((reg - TEGRA210_MBDRC_IIR_CFG) %
(TEGRA210_MBDRC_FILTER_PARAM_STRIDE *
TEGRA210_MBDRC_FILTER_COUNT));
switch (reg) {
case TEGRA210_MBDRC_STATUS:
return true ;
default :
return false ;
}
}
static bool tegra210_mbdrc_volatile_reg(struct device *dev, unsigned int reg)
{
if (reg >= TEGRA210_MBDRC_IIR_CFG)
reg -= ((reg - TEGRA210_MBDRC_IIR_CFG) %
(TEGRA210_MBDRC_FILTER_PARAM_STRIDE *
TEGRA210_MBDRC_FILTER_COUNT));
switch (reg) {
case TEGRA210_MBDRC_SOFT_RESET:
case TEGRA210_MBDRC_STATUS:
case TEGRA210_MBDRC_CFG_RAM_CTRL:
case TEGRA210_MBDRC_CFG_RAM_DATA:
return true ;
default :
return false ;
}
}
static bool tegra210_mbdrc_precious_reg(struct device *dev, unsigned int reg)
{
if (reg >= TEGRA210_MBDRC_IIR_CFG)
reg -= ((reg - TEGRA210_MBDRC_IIR_CFG) %
(TEGRA210_MBDRC_FILTER_PARAM_STRIDE *
TEGRA210_MBDRC_FILTER_COUNT));
switch (reg) {
case TEGRA210_MBDRC_CFG_RAM_DATA:
return true ;
default :
return false ;
}
}
static const struct regmap_config tegra210_mbdrc_regmap_cfg = {
.name = "mbdrc" ,
.reg_bits = 32 ,
.reg_stride = 4 ,
.val_bits = 32 ,
.max_register = TEGRA210_MBDRC_MAX_REG,
.writeable_reg = tegra210_mbdrc_wr_reg,
.readable_reg = tegra210_mbdrc_rd_reg,
.volatile_reg = tegra210_mbdrc_volatile_reg,
.precious_reg = tegra210_mbdrc_precious_reg,
.reg_defaults = tegra210_mbdrc_reg_defaults,
.num_reg_defaults = ARRAY_SIZE(tegra210_mbdrc_reg_defaults),
.cache_type = REGCACHE_FLAT,
};
int tegra210_mbdrc_hw_params(struct snd_soc_component *cmpnt)
{
struct tegra210_ope *ope = snd_soc_component_get_drvdata(cmpnt);
const struct tegra210_mbdrc_config *conf = &mbdrc_init_config;
u32 val = 0 ;
unsigned int i;
regmap_read(ope->mbdrc_regmap, TEGRA210_MBDRC_CFG, &val);
val &= TEGRA210_MBDRC_CFG_MBDRC_MODE_MASK;
if (val == TEGRA210_MBDRC_CFG_MBDRC_MODE_BYPASS)
return 0 ;
for (i = 0 ; i < MBDRC_NUM_BAND; i++) {
const struct tegra210_mbdrc_band_params *params =
&conf->band_params[i];
u32 reg_off = i * TEGRA210_MBDRC_FILTER_PARAM_STRIDE;
tegra210_mbdrc_write_ram(ope->mbdrc_regmap,
reg_off + TEGRA210_MBDRC_CFG_RAM_CTRL,
reg_off + TEGRA210_MBDRC_CFG_RAM_DATA,
0 , (u32 *)¶ms->biquad_params[0 ],
TEGRA210_MBDRC_MAX_BIQUAD_STAGES * 5 );
}
return 0 ;
}
int tegra210_mbdrc_component_init(struct snd_soc_component *cmpnt)
{
struct tegra210_ope *ope = snd_soc_component_get_drvdata(cmpnt);
const struct tegra210_mbdrc_config *conf = &mbdrc_init_config;
unsigned int i;
u32 val;
pm_runtime_get_sync(cmpnt->dev);
/* Initialize MBDRC registers and AHUB RAM with default params */
regmap_update_bits(ope->mbdrc_regmap, TEGRA210_MBDRC_CFG,
TEGRA210_MBDRC_CFG_MBDRC_MODE_MASK,
conf->mode << TEGRA210_MBDRC_CFG_MBDRC_MODE_SHIFT);
regmap_update_bits(ope->mbdrc_regmap, TEGRA210_MBDRC_CFG,
TEGRA210_MBDRC_CFG_RMS_OFFSET_MASK,
conf->rms_off << TEGRA210_MBDRC_CFG_RMS_OFFSET_SHIFT);
regmap_update_bits(ope->mbdrc_regmap, TEGRA210_MBDRC_CFG,
TEGRA210_MBDRC_CFG_PEAK_RMS_MASK,
conf->peak_rms_mode << TEGRA210_MBDRC_CFG_PEAK_RMS_SHIFT);
regmap_update_bits(ope->mbdrc_regmap, TEGRA210_MBDRC_CFG,
TEGRA210_MBDRC_CFG_FILTER_STRUCTURE_MASK,
conf->filter_structure <<
TEGRA210_MBDRC_CFG_FILTER_STRUCTURE_SHIFT);
regmap_update_bits(ope->mbdrc_regmap, TEGRA210_MBDRC_CFG,
TEGRA210_MBDRC_CFG_SHIFT_CTRL_MASK,
conf->shift_ctrl << TEGRA210_MBDRC_CFG_SHIFT_CTRL_SHIFT);
regmap_update_bits(ope->mbdrc_regmap, TEGRA210_MBDRC_CFG,
TEGRA210_MBDRC_CFG_FRAME_SIZE_MASK,
__ffs(conf->frame_size) <<
TEGRA210_MBDRC_CFG_FRAME_SIZE_SHIFT);
regmap_update_bits(ope->mbdrc_regmap, TEGRA210_MBDRC_CHANNEL_MASK,
TEGRA210_MBDRC_CHANNEL_MASK_MASK,
conf->channel_mask << TEGRA210_MBDRC_CHANNEL_MASK_SHIFT);
regmap_update_bits(ope->mbdrc_regmap, TEGRA210_MBDRC_FAST_FACTOR,
TEGRA210_MBDRC_FAST_FACTOR_ATTACK_MASK,
conf->fa_factor << TEGRA210_MBDRC_FAST_FACTOR_ATTACK_SHIFT);
regmap_update_bits(ope->mbdrc_regmap, TEGRA210_MBDRC_FAST_FACTOR,
TEGRA210_MBDRC_FAST_FACTOR_ATTACK_MASK,
conf->fr_factor << TEGRA210_MBDRC_FAST_FACTOR_ATTACK_SHIFT);
for (i = 0 ; i < MBDRC_NUM_BAND; i++) {
const struct tegra210_mbdrc_band_params *params =
&conf->band_params[i];
u32 reg_off = i * TEGRA210_MBDRC_FILTER_PARAM_STRIDE;
regmap_update_bits(ope->mbdrc_regmap,
reg_off + TEGRA210_MBDRC_IIR_CFG,
TEGRA210_MBDRC_IIR_CFG_NUM_STAGES_MASK,
params->iir_stages <<
TEGRA210_MBDRC_IIR_CFG_NUM_STAGES_SHIFT);
regmap_update_bits(ope->mbdrc_regmap,
reg_off + TEGRA210_MBDRC_IN_ATTACK,
TEGRA210_MBDRC_IN_ATTACK_TC_MASK,
params->in_attack_tc <<
TEGRA210_MBDRC_IN_ATTACK_TC_SHIFT);
regmap_update_bits(ope->mbdrc_regmap,
reg_off + TEGRA210_MBDRC_IN_RELEASE,
TEGRA210_MBDRC_IN_RELEASE_TC_MASK,
params->in_release_tc <<
TEGRA210_MBDRC_IN_RELEASE_TC_SHIFT);
regmap_update_bits(ope->mbdrc_regmap,
reg_off + TEGRA210_MBDRC_FAST_ATTACK,
TEGRA210_MBDRC_FAST_ATTACK_TC_MASK,
params->fast_attack_tc <<
TEGRA210_MBDRC_FAST_ATTACK_TC_SHIFT);
val = (((params->in_threshold[0 ] >>
TEGRA210_MBDRC_THRESH_1ST_SHIFT) &
TEGRA210_MBDRC_THRESH_1ST_MASK) |
((params->in_threshold[1 ] >>
TEGRA210_MBDRC_THRESH_2ND_SHIFT) &
TEGRA210_MBDRC_THRESH_2ND_MASK) |
((params->in_threshold[2 ] >>
TEGRA210_MBDRC_THRESH_3RD_SHIFT) &
TEGRA210_MBDRC_THRESH_3RD_MASK) |
((params->in_threshold[3 ] >>
TEGRA210_MBDRC_THRESH_4TH_SHIFT) &
TEGRA210_MBDRC_THRESH_4TH_MASK));
regmap_update_bits(ope->mbdrc_regmap,
reg_off + TEGRA210_MBDRC_IN_THRESHOLD,
0 xffffffff, val);
val = (((params->out_threshold[0 ] >>
TEGRA210_MBDRC_THRESH_1ST_SHIFT) &
TEGRA210_MBDRC_THRESH_1ST_MASK) |
((params->out_threshold[1 ] >>
TEGRA210_MBDRC_THRESH_2ND_SHIFT) &
TEGRA210_MBDRC_THRESH_2ND_MASK) |
((params->out_threshold[2 ] >>
TEGRA210_MBDRC_THRESH_3RD_SHIFT) &
TEGRA210_MBDRC_THRESH_3RD_MASK) |
((params->out_threshold[3 ] >>
TEGRA210_MBDRC_THRESH_4TH_SHIFT) &
TEGRA210_MBDRC_THRESH_4TH_MASK));
regmap_update_bits(ope->mbdrc_regmap,
reg_off + TEGRA210_MBDRC_OUT_THRESHOLD,
0 xffffffff, val);
regmap_update_bits(ope->mbdrc_regmap,
reg_off + TEGRA210_MBDRC_RATIO_1ST,
TEGRA210_MBDRC_RATIO_1ST_MASK,
params->ratio[0 ] << TEGRA210_MBDRC_RATIO_1ST_SHIFT);
regmap_update_bits(ope->mbdrc_regmap,
reg_off + TEGRA210_MBDRC_RATIO_2ND,
TEGRA210_MBDRC_RATIO_2ND_MASK,
params->ratio[1 ] << TEGRA210_MBDRC_RATIO_2ND_SHIFT);
regmap_update_bits(ope->mbdrc_regmap,
reg_off + TEGRA210_MBDRC_RATIO_3RD,
TEGRA210_MBDRC_RATIO_3RD_MASK,
params->ratio[2 ] << TEGRA210_MBDRC_RATIO_3RD_SHIFT);
regmap_update_bits(ope->mbdrc_regmap,
reg_off + TEGRA210_MBDRC_RATIO_4TH,
TEGRA210_MBDRC_RATIO_4TH_MASK,
params->ratio[3 ] << TEGRA210_MBDRC_RATIO_4TH_SHIFT);
regmap_update_bits(ope->mbdrc_regmap,
reg_off + TEGRA210_MBDRC_RATIO_5TH,
TEGRA210_MBDRC_RATIO_5TH_MASK,
params->ratio[4 ] << TEGRA210_MBDRC_RATIO_5TH_SHIFT);
regmap_update_bits(ope->mbdrc_regmap,
reg_off + TEGRA210_MBDRC_MAKEUP_GAIN,
TEGRA210_MBDRC_MAKEUP_GAIN_MASK,
params->makeup_gain <<
TEGRA210_MBDRC_MAKEUP_GAIN_SHIFT);
regmap_update_bits(ope->mbdrc_regmap,
reg_off + TEGRA210_MBDRC_INIT_GAIN,
TEGRA210_MBDRC_INIT_GAIN_MASK,
params->gain_init <<
TEGRA210_MBDRC_INIT_GAIN_SHIFT);
regmap_update_bits(ope->mbdrc_regmap,
reg_off + TEGRA210_MBDRC_GAIN_ATTACK,
TEGRA210_MBDRC_GAIN_ATTACK_MASK,
params->gain_attack_tc <<
TEGRA210_MBDRC_GAIN_ATTACK_SHIFT);
regmap_update_bits(ope->mbdrc_regmap,
reg_off + TEGRA210_MBDRC_GAIN_RELEASE,
TEGRA210_MBDRC_GAIN_RELEASE_MASK,
params->gain_release_tc <<
TEGRA210_MBDRC_GAIN_RELEASE_SHIFT);
regmap_update_bits(ope->mbdrc_regmap,
reg_off + TEGRA210_MBDRC_FAST_RELEASE,
TEGRA210_MBDRC_FAST_RELEASE_MASK,
params->fast_release_tc <<
TEGRA210_MBDRC_FAST_RELEASE_SHIFT);
tegra210_mbdrc_write_ram(ope->mbdrc_regmap,
reg_off + TEGRA210_MBDRC_CFG_RAM_CTRL,
reg_off + TEGRA210_MBDRC_CFG_RAM_DATA, 0 ,
(u32 *)¶ms->biquad_params[0 ],
TEGRA210_MBDRC_MAX_BIQUAD_STAGES * 5 );
}
pm_runtime_put_sync(cmpnt->dev);
snd_soc_add_component_controls(cmpnt, tegra210_mbdrc_controls,
ARRAY_SIZE(tegra210_mbdrc_controls));
return 0 ;
}
int tegra210_mbdrc_regmap_init(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
struct tegra210_ope *ope = dev_get_drvdata(dev);
struct device_node *child;
struct resource mem;
void __iomem *regs;
int err;
child = of_get_child_by_name(dev->of_node, "dynamic-range-compressor" );
if (!child)
return -ENODEV;
err = of_address_to_resource(child, 0 , &mem);
of_node_put(child);
if (err < 0 ) {
dev_err(dev, "fail to get MBDRC resource\n" );
return err;
}
mem.flags = IORESOURCE_MEM;
regs = devm_ioremap_resource(dev, &mem);
if (IS_ERR(regs))
return PTR_ERR(regs);
ope->mbdrc_regmap = devm_regmap_init_mmio(dev, regs,
&tegra210_mbdrc_regmap_cfg);
if (IS_ERR(ope->mbdrc_regmap)) {
dev_err(dev, "regmap init failed\n" );
return PTR_ERR(ope->mbdrc_regmap);
}
regcache_cache_only(ope->mbdrc_regmap, true );
return 0 ;
}
Messung V0.5 in Prozent C=91 H=92 G=91
¤ Dauer der Verarbeitung: 0.11 Sekunden
(vorverarbeitet am 2026-06-08)
¤
*© Formatika GbR, Deutschland