| // 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), 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_CFG_RAM_CTRL, id), 0x4000} |
| |
| static const struct reg_default tegra210_mbdrc_reg_defaults[] = { |
| { TEGRA210_MBDRC_CFG, 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 */ |
| .filter_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, |
| */ |
| |
| /* 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, 0xffffffff, |
| 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, 0x1ff, 0, |
| tegra210_mbdrc_get, tegra210_mbdrc_put), |
| |
| SOC_SINGLE_EXT("MBDRC Shift Control", TEGRA210_MBDRC_CFG, |
| TEGRA210_MBDRC_CFG_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_VOL, |
| TEGRA210_MBDRC_MASTER_VOL_SHIFT, |
| 0, 0x1ff, 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, 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_CFG_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_CFG_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_CFG_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_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, |
| 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_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; |
| } |