Files
linux-nv-oot/sound/soc/tegra/tegra210_mbdrc.c
Sameer Pujar c4ab6f5a0e ASoC: tegra: Align with new device model
PEQ and MBDRC are sub blocks of OPE module. So far, these sub blocks
were not represented by separate device nodes in DT. This has changed
now where PEQ and MBDRC are children of OPE block. For now the driver
structure is maintained as it is and explicitly parse PEQ and MBDRC
nodes to create corresponding regmap interfaces. With this there is
flexibility now to create separate device drivers for PEQ and MBDRC
if necessary in future.

Bug 3583581

Change-Id: I16ceb9b1a30b4ddb1a57fdef28db20c554c58b03
Signed-off-by: Sameer Pujar <spujar@nvidia.com>
Reviewed-on: https://git-master.nvidia.com/r/c/linux-nv-oot/+/2783022
Reviewed-by: Mohan Kumar D <mkumard@nvidia.com>
Reviewed-by: Sharad Gupta <sharadg@nvidia.com>
GVS: Gerrit_Virtual_Submit <buildbot_gerritrpt@nvidia.com>
2022-10-01 10:51:57 -07:00

913 lines
31 KiB
C

// SPDX-License-Identifier: GPL-2.0-only
//
// tegra210_mbdrc.c - Tegra210 MBDRC driver
//
// Copyright (c) 2014-2021, 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_ahub.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_CONFIG, id), 0x00000005}, \
{ MBDRC_FILTER_REG(TEGRA210_MBDRC_IN_ATTACK, id), 0x3e48590c}, \
{ MBDRC_FILTER_REG(TEGRA210_MBDRC_IN_RELEASE, id), 0x08414e9f}, \
{ MBDRC_FILTER_REG(TEGRA210_MBDRC_FAST_ATTACK, id), 0x7fffffff}, \
{ MBDRC_FILTER_REG(TEGRA210_MBDRC_IN_THRESHOLD, id), 0x06145082}, \
{ MBDRC_FILTER_REG(TEGRA210_MBDRC_OUT_THRESHOLD, id), 0x060d379b}, \
{ MBDRC_FILTER_REG(TEGRA210_MBDRC_RATIO_1ST, id), 0x0000a000}, \
{ MBDRC_FILTER_REG(TEGRA210_MBDRC_RATIO_2ND, id), 0x00002000}, \
{ MBDRC_FILTER_REG(TEGRA210_MBDRC_RATIO_3RD, id), 0x00000b33}, \
{ MBDRC_FILTER_REG(TEGRA210_MBDRC_RATIO_4TH, id), 0x00000800}, \
{ MBDRC_FILTER_REG(TEGRA210_MBDRC_RATIO_5TH, id), 0x0000019a}, \
{ MBDRC_FILTER_REG(TEGRA210_MBDRC_MAKEUP_GAIN, id), 0x00000002}, \
{ MBDRC_FILTER_REG(TEGRA210_MBDRC_INIT_GAIN, id), 0x00066666}, \
{ MBDRC_FILTER_REG(TEGRA210_MBDRC_GAIN_ATTACK, id), 0x00d9ba0e}, \
{ MBDRC_FILTER_REG(TEGRA210_MBDRC_GAIN_RELEASE, id), 0x3e48590c}, \
{ MBDRC_FILTER_REG(TEGRA210_MBDRC_FAST_RELEASE, id), 0x7ffff26a}, \
{ MBDRC_FILTER_REG(TEGRA210_MBDRC_AHUBRAMCTL_CONFIG_RAM_CTRL, id), 0x4000}
static const struct reg_default tegra210_mbdrc_reg_defaults[] = {
{ TEGRA210_MBDRC_CONFIG, 0x0030de51},
{ TEGRA210_MBDRC_CHANNEL_MASK, 0x00000003},
{ TEGRA210_MBDRC_FAST_FACTOR, 0x30000800},
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 */
.fliter_structure = 0, /* All-pass tree */
.shift_ctrl = 30,
.frame_size = 32,
.channel_mask = 0x3,
.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 */
961046798, -2030431983, 1073741824, 2030431983, -961046798, /* band-0 */
1030244425, -2099481453, 1073741824, 2099481453, -1030244425, /* band-1 */
1067169294, -2136327263, 1073741824, 2136327263, -1067169294, /* band-2 */
434951949, -1306567134, 1073741824, 1306567134, -434951949, /* band-3 */
780656019, -1605955641, 1073741824, 1605955641, -780656019, /* band-4 */
1024497031, -1817128152, 1073741824, 1817128152, -1024497031, /* band-5 */
1073741824, 0, 0, 0, 0, /* band-6 */
1073741824, 0, 0, 0, 0, /* band-7 */
}
},
.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 */
-1005668963, 1073741824, 0, 1005668963, 0, /* band-0 */
998437058, -2067742187, 1073741824, 2067742187, -998437058, /* band-1 */
1051963422, -2121153948, 1073741824, 2121153948, -1051963422, /* band-2 */
434951949, -1306567134, 1073741824, 1306567134, -434951949, /* band-3 */
780656019, -1605955641, 1073741824, 1605955641, -780656019, /* band-4 */
1024497031, -1817128152, 1073741824, 1817128152, -1024497031, /* band-5 */
1073741824, 0, 0, 0, 0, /* band-6 */
1073741824, 0, 0, 0, 0, /* band-7 */
}
},
.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 */
1073741824, 0, 0, 0, 0, /* band-0 */
1073741824, 0, 0, 0, 0, /* band-1 */
1073741824, 0, 0, 0, 0, /* band-2 */
-619925131, 1073741824, 0, 619925131, 0, /* band-3 */
606839335, -1455425976, 1073741824, 1455425976, -606839335, /* band-4 */
917759617, -1724690840, 1073741824, 1724690840, -917759617, /* band-5 */
1073741824, 0, 0, 0, 0, /* band-6 */
1073741824, 0, 0, 0, 0, /* band-7 */
}
}
};
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 long long fls_val = 1ULL << fls(mc->max);
unsigned int mask = fls_val - 1;
unsigned int val;
regmap_read(ope->mbdrc_regmap, mc->reg, &val);
ucontrol->value.integer.value[0] = (val >> mc->shift) & mask;
if (mc->invert)
ucontrol->value.integer.value[0] =
mc->max - ucontrol->value.integer.value[0];
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 long long fls_val = 1ULL << fls(mc->max);
unsigned int mask = fls_val - 1;
unsigned int val;
val = (ucontrol->value.integer.value[0] & mask);
if (mc->invert)
val = mc->max - val;
val = val << mc->shift;
return regmap_update_bits(ope->mbdrc_regmap, mc->reg,
(mask << mc->shift), val);
}
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;
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;
return regmap_update_bits(ope->mbdrc_regmap, e->reg, mask, val);
}
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;
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;
int i;
for (i = 0; i < params->soc.num_regs; i++,
regs += cmpnt->val_bytes)
regmap_update_bits(ope->mbdrc_regmap, regs, mask,
data[i] << shift);
return 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;
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;
int i;
for (i = 0; i < num_regs; i += 4, regs += cmpnt->val_bytes) {
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(ope->mbdrc_regmap, regs,
0xffffffff, data[i]);
}
return 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_ahub_write_ram(ope->mbdrc_regmap, reg_ctrl, reg_data,
params->shift, data, params->soc.num_regs);
return 0;
}
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;
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);
unsigned long long fls_val = 1ULL << fls(mc->max);
unsigned int mask = fls_val - 1;
int val;
regmap_read(ope->mbdrc_regmap, mc->reg, &val);
ucontrol->value.integer.value[0] = ((val >> mc->shift) -
TEGRA210_MBDRC_MASTER_VOL_MIN) & mask;
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);
unsigned long long fls_val = 1ULL << fls(mc->max);
unsigned int mask = fls_val - 1;
unsigned int val;
val = (ucontrol->value.integer.value[0] & mask);
val = val + TEGRA210_MBDRC_MASTER_VOL_MIN;
val = val << mc->shift;
return regmap_write(ope->mbdrc_regmap, mc->reg, val);
}
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_CONFIG,
TEGRA210_MBDRC_CONFIG_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_CONFIG,
TEGRA210_MBDRC_CONFIG_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_CONFIG,
TEGRA210_MBDRC_CONFIG_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_CONFIG,
TEGRA210_MBDRC_CONFIG_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_CONFIG,
TEGRA210_MBDRC_CONFIG_RMS_OFFSET_SHIFT, 0x1ff, 0,
tegra210_mbdrc_get, tegra210_mbdrc_put),
SOC_SINGLE_EXT("mbdrc shift control", TEGRA210_MBDRC_CONFIG,
TEGRA210_MBDRC_CONFIG_SHIFT_CTRL_SHIFT, 0x1f, 0,
tegra210_mbdrc_get, tegra210_mbdrc_put),
SOC_SINGLE_EXT("mbdrc fast attack factor", TEGRA210_MBDRC_FAST_FACTOR,
TEGRA210_MBDRC_FAST_FACTOR_ATTACK_SHIFT, 0xffff, 0,
tegra210_mbdrc_get, tegra210_mbdrc_put),
SOC_SINGLE_EXT("mbdrc fast release factor", TEGRA210_MBDRC_FAST_FACTOR,
TEGRA210_MBDRC_FAST_FACTOR_RELEASE_SHIFT, 0xffff, 0,
tegra210_mbdrc_get, tegra210_mbdrc_put),
SOC_SINGLE_RANGE_EXT_TLV("mbdrc master volume", TEGRA210_MBDRC_MASTER_VOLUME,
TEGRA210_MBDRC_MASTER_VOLUME_SHIFT, TEGRA210_MBDRC_MASTER_VOL_MIN,
TEGRA210_MBDRC_MASTER_VOL_MAX, 0,
tegra210_mbdrc_vol_get, tegra210_mbdrc_vol_put, mdbrc_vol_tlv),
TEGRA_SOC_BYTES_EXT("mbdrc iir stages", TEGRA210_MBDRC_IIR_CONFIG,
TEGRA210_MBDRC_FILTER_COUNT,
TEGRA210_MBDRC_IIR_CONFIG_NUM_STAGES_SHIFT,
TEGRA210_MBDRC_IIR_CONFIG_NUM_STAGES_MASK,
tegra210_mbdrc_band_params_get,
tegra210_mbdrc_band_params_put,
tegra210_mbdrc_param_info),
TEGRA_SOC_BYTES_EXT("mbdrc in attack tc", 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 tc", 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 tc", 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, 0xffffffff,
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, 0xffffffff,
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_AHUBRAMCTL_CONFIG_RAM_CTRL,
TEGRA210_MBDRC_MAX_BIQUAD_STAGES * 5, 0, 0xffffffff,
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_AHUBRAMCTL_CONFIG_RAM_CTRL +
TEGRA210_MBDRC_FILTER_PARAM_STRIDE,
TEGRA210_MBDRC_MAX_BIQUAD_STAGES * 5, 0, 0xffffffff,
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_AHUBRAMCTL_CONFIG_RAM_CTRL +
(TEGRA210_MBDRC_FILTER_PARAM_STRIDE * 2),
TEGRA210_MBDRC_MAX_BIQUAD_STAGES * 5, 0, 0xffffffff,
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_CONFIG)
reg -= ((reg - TEGRA210_MBDRC_IIR_CONFIG) %
(TEGRA210_MBDRC_FILTER_PARAM_STRIDE *
TEGRA210_MBDRC_FILTER_COUNT));
switch (reg) {
case TEGRA210_MBDRC_CG:
case TEGRA210_MBDRC_SOFT_RESET:
case TEGRA210_MBDRC_CONFIG:
case TEGRA210_MBDRC_CHANNEL_MASK:
case TEGRA210_MBDRC_MASTER_VOLUME:
case TEGRA210_MBDRC_FAST_FACTOR:
case TEGRA210_MBDRC_IIR_CONFIG:
case TEGRA210_MBDRC_IN_ATTACK:
case TEGRA210_MBDRC_IN_RELEASE:
case TEGRA210_MBDRC_FAST_ATTACK:
case TEGRA210_MBDRC_IN_THRESHOLD:
case TEGRA210_MBDRC_OUT_THRESHOLD:
case TEGRA210_MBDRC_RATIO_1ST:
case TEGRA210_MBDRC_RATIO_2ND:
case TEGRA210_MBDRC_RATIO_3RD:
case TEGRA210_MBDRC_RATIO_4TH:
case TEGRA210_MBDRC_RATIO_5TH:
case TEGRA210_MBDRC_MAKEUP_GAIN:
case TEGRA210_MBDRC_INIT_GAIN:
case TEGRA210_MBDRC_GAIN_ATTACK:
case TEGRA210_MBDRC_GAIN_RELEASE:
case TEGRA210_MBDRC_FAST_RELEASE:
case TEGRA210_MBDRC_AHUBRAMCTL_CONFIG_RAM_CTRL:
case TEGRA210_MBDRC_AHUBRAMCTL_CONFIG_RAM_DATA:
return true;
default:
return false;
}
}
static bool tegra210_mbdrc_rd_reg(struct device *dev, unsigned int reg)
{
if (reg >= TEGRA210_MBDRC_IIR_CONFIG)
reg -= ((reg - TEGRA210_MBDRC_IIR_CONFIG) %
(TEGRA210_MBDRC_FILTER_PARAM_STRIDE *
TEGRA210_MBDRC_FILTER_COUNT));
switch (reg) {
case TEGRA210_MBDRC_CG:
case TEGRA210_MBDRC_SOFT_RESET:
case TEGRA210_MBDRC_STATUS:
case TEGRA210_MBDRC_CONFIG:
case TEGRA210_MBDRC_CHANNEL_MASK:
case TEGRA210_MBDRC_MASTER_VOLUME:
case TEGRA210_MBDRC_FAST_FACTOR:
case TEGRA210_MBDRC_IIR_CONFIG:
case TEGRA210_MBDRC_IN_ATTACK:
case TEGRA210_MBDRC_IN_RELEASE:
case TEGRA210_MBDRC_FAST_ATTACK:
case TEGRA210_MBDRC_IN_THRESHOLD:
case TEGRA210_MBDRC_OUT_THRESHOLD:
case TEGRA210_MBDRC_RATIO_1ST:
case TEGRA210_MBDRC_RATIO_2ND:
case TEGRA210_MBDRC_RATIO_3RD:
case TEGRA210_MBDRC_RATIO_4TH:
case TEGRA210_MBDRC_RATIO_5TH:
case TEGRA210_MBDRC_MAKEUP_GAIN:
case TEGRA210_MBDRC_INIT_GAIN:
case TEGRA210_MBDRC_GAIN_ATTACK:
case TEGRA210_MBDRC_GAIN_RELEASE:
case TEGRA210_MBDRC_FAST_RELEASE:
case TEGRA210_MBDRC_AHUBRAMCTL_CONFIG_RAM_CTRL:
case TEGRA210_MBDRC_AHUBRAMCTL_CONFIG_RAM_DATA:
return true;
default:
return false;
}
}
static bool tegra210_mbdrc_volatile_reg(struct device *dev, unsigned int reg)
{
if (reg >= TEGRA210_MBDRC_IIR_CONFIG)
reg -= ((reg - TEGRA210_MBDRC_IIR_CONFIG) %
(TEGRA210_MBDRC_FILTER_PARAM_STRIDE *
TEGRA210_MBDRC_FILTER_COUNT));
switch (reg) {
case TEGRA210_MBDRC_SOFT_RESET:
case TEGRA210_MBDRC_STATUS:
case TEGRA210_MBDRC_AHUBRAMCTL_CONFIG_RAM_CTRL:
case TEGRA210_MBDRC_AHUBRAMCTL_CONFIG_RAM_DATA:
return true;
default:
return false;
}
}
static bool tegra210_mbdrc_precious_reg(struct device *dev, unsigned int reg)
{
if (reg >= TEGRA210_MBDRC_IIR_CONFIG)
reg -= ((reg - TEGRA210_MBDRC_IIR_CONFIG) %
(TEGRA210_MBDRC_FILTER_PARAM_STRIDE *
TEGRA210_MBDRC_FILTER_COUNT));
switch (reg) {
case TEGRA210_MBDRC_AHUBRAMCTL_CONFIG_RAM_DATA:
return true;
default:
return false;
}
}
static const struct regmap_config tegra210_mbdrc_regmap_config = {
.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;
int i;
regmap_read(ope->mbdrc_regmap, TEGRA210_MBDRC_CONFIG, &val);
if (val & TEGRA210_MBDRC_CONFIG_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_ahub_write_ram(ope->mbdrc_regmap,
reg_off + TEGRA210_MBDRC_AHUBRAMCTL_CONFIG_RAM_CTRL,
reg_off + TEGRA210_MBDRC_AHUBRAMCTL_CONFIG_RAM_DATA, 0,
(u32 *)&params->biquad_params[0],
TEGRA210_MBDRC_MAX_BIQUAD_STAGES * 5);
}
return 0;
}
EXPORT_SYMBOL_GPL(tegra210_mbdrc_hw_params);
int tegra210_mbdrc_codec_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;
u32 val;
int i;
pm_runtime_get_sync(cmpnt->dev);
/* Initialize MBDRC registers and ahub-ram with default params */
regmap_update_bits(ope->mbdrc_regmap, TEGRA210_MBDRC_CONFIG,
TEGRA210_MBDRC_CONFIG_MBDRC_MODE_MASK,
conf->mode << TEGRA210_MBDRC_CONFIG_MBDRC_MODE_SHIFT);
regmap_update_bits(ope->mbdrc_regmap, TEGRA210_MBDRC_CONFIG,
TEGRA210_MBDRC_CONFIG_RMS_OFFSET_MASK,
conf->rms_off << TEGRA210_MBDRC_CONFIG_RMS_OFFSET_SHIFT);
regmap_update_bits(ope->mbdrc_regmap, TEGRA210_MBDRC_CONFIG,
TEGRA210_MBDRC_CONFIG_PEAK_RMS_MASK,
conf->peak_rms_mode << TEGRA210_MBDRC_CONFIG_PEAK_RMS_SHIFT);
regmap_update_bits(ope->mbdrc_regmap, TEGRA210_MBDRC_CONFIG,
TEGRA210_MBDRC_CONFIG_FILTER_STRUCTURE_MASK,
conf->fliter_structure <<
TEGRA210_MBDRC_CONFIG_FILTER_STRUCTURE_SHIFT);
regmap_update_bits(ope->mbdrc_regmap, TEGRA210_MBDRC_CONFIG,
TEGRA210_MBDRC_CONFIG_SHIFT_CTRL_MASK,
conf->shift_ctrl << TEGRA210_MBDRC_CONFIG_SHIFT_CTRL_SHIFT);
regmap_update_bits(ope->mbdrc_regmap, TEGRA210_MBDRC_CONFIG,
TEGRA210_MBDRC_CONFIG_FRAME_SIZE_MASK,
__ffs(conf->frame_size) <<
TEGRA210_MBDRC_CONFIG_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_CONFIG,
TEGRA210_MBDRC_IIR_CONFIG_NUM_STAGES_MASK,
params->iir_stages <<
TEGRA210_MBDRC_IIR_CONFIG_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, 0xffffffff, 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,
0xffffffff, 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_ahub_write_ram(ope->mbdrc_regmap,
reg_off + TEGRA210_MBDRC_AHUBRAMCTL_CONFIG_RAM_CTRL,
reg_off + TEGRA210_MBDRC_AHUBRAMCTL_CONFIG_RAM_DATA, 0,
(u32 *)&params->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;
}
EXPORT_SYMBOL_GPL(tegra210_mbdrc_codec_init);
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(&pdev->dev, &mem);
if (IS_ERR(regs))
return PTR_ERR(regs);
ope->mbdrc_regmap =
devm_regmap_init_mmio(&pdev->dev, regs,
&tegra210_mbdrc_regmap_config);
if (IS_ERR(ope->mbdrc_regmap)) {
dev_err(&pdev->dev, "regmap init failed\n");
return PTR_ERR(ope->mbdrc_regmap);
}
regcache_cache_only(ope->mbdrc_regmap, true);
return 0;
}
EXPORT_SYMBOL_GPL(tegra210_mbdrc_regmap_init);
MODULE_AUTHOR("Sumit Bhattacharya <sumitb@nvidia.com>");
MODULE_DESCRIPTION("Tegra210 MBDRC module");
MODULE_LICENSE("GPL");