diff --git a/sound/soc/tegra-alt/Kconfig b/sound/soc/tegra-alt/Kconfig index 0fe7c48d..42b002bb 100644 --- a/sound/soc/tegra-alt/Kconfig +++ b/sound/soc/tegra-alt/Kconfig @@ -148,6 +148,12 @@ config SND_SOC_TEGRA210_SPDIF_ALT help Say Y or M if you want to add support for Tegra210 SPDIF module. +config SND_SOC_TEGRA210_OPE_ALT + tristate "Tegra210 OPE driver" + depends on SND_SOC_TEGRA_ALT && SND_SOC_TEGRA_ALT_210 + help + Say Y or M if you want to add support for Tegra210 OPE module. + config SND_SOC_TEGRA210_ADSP_ALT tristate "Tegra210 ADSP driver" depends on SND_SOC_TEGRA_ALT && SND_SOC_TEGRA_ALT_210 && TEGRA_NVADSP @@ -199,6 +205,7 @@ config SND_SOC_TEGRA_GRENADA_ALT select SND_SOC_TEGRA210_SFC_ALT select SND_SOC_TEGRA210_AFC_ALT select SND_SOC_TEGRA210_MVC_ALT + select SND_SOC_TEGRA210_OPE_ALT select SND_SOC_TEGRA210_IQC_ALT select SND_SOC_TEGRA210_SPDIF_ALT select SND_SOC_TEGRA210_ADSP_ALT @@ -222,6 +229,7 @@ config SND_SOC_TEGRA_T210REF_MOBILE_ALT select SND_SOC_TEGRA210_SFC_ALT select SND_SOC_TEGRA210_AFC_ALT select SND_SOC_TEGRA210_MVC_ALT + select SND_SOC_TEGRA210_OPE_ALT select SND_SOC_TEGRA210_SPDIF_ALT select SND_SOC_TEGRA210_ADSP_ALT select SND_SOC_SPDIF diff --git a/sound/soc/tegra-alt/Makefile b/sound/soc/tegra-alt/Makefile index 847aa5d8..eadf3892 100644 --- a/sound/soc/tegra-alt/Makefile +++ b/sound/soc/tegra-alt/Makefile @@ -26,6 +26,9 @@ snd-soc-tegra210-alt-afc-objs := tegra210_afc_alt.o snd-soc-tegra210-alt-mvc-objs := tegra210_mvc_alt.o snd-soc-tegra210-alt-iqc-objs := tegra210_iqc_alt.o snd-soc-tegra210-alt-spdif-objs := tegra210_spdif_alt.o +snd-soc-tegra210-alt-ope-objs := tegra210_ope_alt.o +snd-soc-tegra210-alt-peq-objs := tegra210_peq_alt.o +snd-soc-tegra210-alt-mbdrc-objs := tegra210_mbdrc_alt.o snd-soc-tegra210-alt-adsp-objs := tegra210_adsp_alt.o snd-soc-tegra210-alt-fpga-clock-objs := ahub_unit_fpga_clock.o @@ -53,6 +56,9 @@ obj-$(CONFIG_SND_SOC_TEGRA210_AFC_ALT) += snd-soc-tegra210-alt-afc.o obj-$(CONFIG_SND_SOC_TEGRA210_MVC_ALT) += snd-soc-tegra210-alt-mvc.o obj-$(CONFIG_SND_SOC_TEGRA210_IQC_ALT) += snd-soc-tegra210-alt-iqc.o obj-$(CONFIG_SND_SOC_TEGRA210_SPDIF_ALT) += snd-soc-tegra210-alt-spdif.o +obj-$(CONFIG_SND_SOC_TEGRA210_OPE_ALT) += snd-soc-tegra210-alt-ope.o +obj-$(CONFIG_SND_SOC_TEGRA210_OPE_ALT) += snd-soc-tegra210-alt-peq.o +obj-$(CONFIG_SND_SOC_TEGRA210_OPE_ALT) += snd-soc-tegra210-alt-mbdrc.o obj-$(CONFIG_SND_SOC_TEGRA210_ADSP_ALT) += snd-soc-tegra210-alt-adsp.o # Tegra machine Support diff --git a/sound/soc/tegra-alt/tegra210_mbdrc_alt.c b/sound/soc/tegra-alt/tegra210_mbdrc_alt.c new file mode 100644 index 00000000..fdb5378e --- /dev/null +++ b/sound/soc/tegra-alt/tegra210_mbdrc_alt.c @@ -0,0 +1,787 @@ +/* + * tegra210_mbdrc_alt.c - Tegra210 MBDRC driver + * + * Copyright (c) 2014 NVIDIA CORPORATION. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "tegra210_xbar_alt.h" +#include "tegra210_ope_alt.h" +#include "tegra210_mbdrc_alt.h" + +/* 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_codec *codec = snd_kcontrol_chip(kcontrol); + struct tegra210_ope *ope = snd_soc_codec_get_drvdata(codec); + unsigned int mask = (1 << fls(mc->max)) - 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_codec *codec = snd_kcontrol_chip(kcontrol); + struct tegra210_ope *ope = snd_soc_codec_get_drvdata(codec); + unsigned int mask = (1 << fls(mc->max)) - 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); +} + +int tegra210_mbdrc_get_enum(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); + struct tegra210_ope *ope = snd_soc_codec_get_drvdata(codec); + 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; +} + +int tegra210_mbdrc_put_enum(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); + struct tegra210_ope *ope = snd_soc_codec_get_drvdata(codec); + struct soc_enum *e = (struct soc_enum *)kcontrol->private_value; + unsigned int val; + unsigned int mask; + + if (ucontrol->value.enumerated.item[0] > e->max - 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_codec *codec = snd_kcontrol_chip(kcontrol); + struct tegra210_ope *ope = snd_soc_codec_get_drvdata(codec); + 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 += codec->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_codec *codec = snd_kcontrol_chip(kcontrol); + struct tegra210_ope *ope = snd_soc_codec_get_drvdata(codec); + 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 += codec->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_codec *codec = snd_kcontrol_chip(kcontrol); + struct tegra210_ope *ope = snd_soc_codec_get_drvdata(codec); + 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 += codec->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_codec *codec = snd_kcontrol_chip(kcontrol); + struct tegra210_ope *ope = snd_soc_codec_get_drvdata(codec); + 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 += codec->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_codec *codec = snd_kcontrol_chip(kcontrol); + u32 *data = (u32 *)ucontrol->value.bytes.data; + + memset(data, 0, params->soc.num_regs * codec->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_codec *codec = snd_kcontrol_chip(kcontrol); + struct tegra210_ope *ope = snd_soc_codec_get_drvdata(codec); + u32 reg_ctrl = params->soc.base; + u32 reg_data = reg_ctrl + codec->val_bytes; + u32 *data = (u32 *)ucontrol->value.bytes.data; + + tegra210_xbar_write_ahubram(ope->mbdrc_regmap, reg_ctrl, reg_data, + params->shift, data, params->soc.num_regs); + + return 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_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) \ + TEGRA_SOC_BYTES_EXT(xname, xbase, xregs, xshift, xmask, \ + tegra210_mbdrc_band_params_get, tegra210_mbdrc_band_params_put) + +#define TEGRA_MBDRC_BAND_BYTES_EXT(xname, xbase, xshift, xmask) \ + TEGRA_MBDRC_BYTES_EXT(xname, xbase, TEGRA210_MBDRC_FILTER_COUNT, \ + xshift, xmask) + +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 master volume", TEGRA210_MBDRC_MASTER_VOLUME, + TEGRA210_MBDRC_MASTER_VOLUME_SHIFT, 0xffffffff, 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), + + 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), + 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), + 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), + 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), + + 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), + 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), + + 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), + + 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), + 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), + 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), + 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), + 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), + + 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), + 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), + 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), +}; + +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_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, + .cache_type = REGCACHE_RBTREE, +}; + +int tegra210_mbdrc_codec_init(struct snd_soc_codec *codec) +{ + struct tegra210_ope *ope = snd_soc_codec_get_drvdata(codec); + const struct tegra210_mbdrc_config *conf = &mbdrc_init_config; + u32 val; + int i; + + pm_runtime_get_sync(codec->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_xbar_write_ahubram(ope->mbdrc_regmap, + reg_off + TEGRA210_MBDRC_AHUBRAMCTL_CONFIG_RAM_CTRL, + reg_off + TEGRA210_MBDRC_AHUBRAMCTL_CONFIG_RAM_DATA, 0, + (u32 *)¶ms->biquad_params[0], + TEGRA210_MBDRC_MAX_BIQUAD_STAGES * 5); + } + pm_runtime_put_sync(codec->dev); + + snd_soc_add_codec_controls(codec, tegra210_mbdrc_controls, + ARRAY_SIZE(tegra210_mbdrc_controls)); + return 0; +} +EXPORT_SYMBOL_GPL(tegra210_mbdrc_codec_init); + +int tegra210_mbdrc_init(struct platform_device *pdev, int id) +{ + struct tegra210_ope *ope = dev_get_drvdata(&pdev->dev); + struct resource *mem, *memregion; + void __iomem *regs; + int ret = 0; + + mem = platform_get_resource(pdev, IORESOURCE_MEM, id); + if (!mem) { + dev_err(&pdev->dev, "No memory resource\n"); + ret = -ENODEV; + goto err; + } + + memregion = devm_request_mem_region(&pdev->dev, mem->start, + resource_size(mem), pdev->name); + if (!memregion) { + dev_err(&pdev->dev, "Memory region already claimed\n"); + ret = -EBUSY; + goto err; + } + + regs = devm_ioremap(&pdev->dev, mem->start, resource_size(mem)); + if (!regs) { + dev_err(&pdev->dev, "ioremap failed\n"); + ret = -ENOMEM; + goto err; + } + + 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"); + ret = PTR_ERR(ope->mbdrc_regmap); + goto err; + } + + return 0; +err: + return ret; +} +EXPORT_SYMBOL_GPL(tegra210_mbdrc_init); + +MODULE_AUTHOR("Sumit Bhattacharya "); +MODULE_DESCRIPTION("Tegra210 MBDRC module"); +MODULE_LICENSE("GPL"); diff --git a/sound/soc/tegra-alt/tegra210_ope_alt.c b/sound/soc/tegra-alt/tegra210_ope_alt.c new file mode 100644 index 00000000..ccc3676e --- /dev/null +++ b/sound/soc/tegra-alt/tegra210_ope_alt.c @@ -0,0 +1,462 @@ +/* + * tegra210_ope_alt.c - Tegra210 OPE driver + * + * Copyright (c) 2014 NVIDIA CORPORATION. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "tegra210_xbar_alt.h" +#include "tegra210_ope_alt.h" + +#define DRV_NAME "tegra210-ope" + +static int tegra210_ope_runtime_suspend(struct device *dev) +{ + struct tegra210_ope *ope = dev_get_drvdata(dev); + + regcache_cache_only(ope->mbdrc_regmap, true); + regcache_cache_only(ope->peq_regmap, true); + regcache_cache_only(ope->regmap, true); + clk_disable_unprepare(ope->clk_ope); + return 0; +} + +static int tegra210_ope_runtime_resume(struct device *dev) +{ + struct tegra210_ope *ope = dev_get_drvdata(dev); + int ret; + + ret = clk_prepare_enable(ope->clk_ope); + if (ret) { + dev_err(dev, "clk_enable failed: %d\n", ret); + return ret; + } + regcache_cache_only(ope->regmap, false); + regcache_cache_only(ope->peq_regmap, false); + regcache_cache_only(ope->mbdrc_regmap, false); + + return 0; +} + +static int tegra210_ope_set_audio_cif(struct tegra210_ope *ope, + struct snd_pcm_hw_params *params, + unsigned int reg) +{ + int channels, audio_bits; + struct tegra210_xbar_cif_conf cif_conf; + + channels = params_channels(params); + if (channels < 2) + return -EINVAL; + + switch (params_format(params)) { + case SNDRV_PCM_FORMAT_S16_LE: + audio_bits = TEGRA210_AUDIOCIF_BITS_16; + break; + case SNDRV_PCM_FORMAT_S32_LE: + audio_bits = TEGRA210_AUDIOCIF_BITS_32; + break; + default: + return -EINVAL; + } + + cif_conf.threshold = 0; + cif_conf.audio_channels = channels; + cif_conf.client_channels = channels; + cif_conf.audio_bits = audio_bits; + cif_conf.client_bits = audio_bits; + cif_conf.expand = 0; + cif_conf.stereo_conv = 0; + cif_conf.replicate = 0; + cif_conf.truncate = 0; + cif_conf.mono_conv = 0; + + ope->soc_data->set_audio_cif(ope->regmap, reg, &cif_conf); + + return 0; +} + +static int tegra210_ope_hw_params(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params, + struct snd_soc_dai *dai) +{ + struct device *dev = dai->dev; + struct tegra210_ope *ope = snd_soc_dai_get_drvdata(dai); + int ret; + + /* set RX cif and TX cif */ + ret = tegra210_ope_set_audio_cif(ope, params, + TEGRA210_OPE_AXBAR_RX_CIF_CTRL); + if (ret) { + dev_err(dev, "Can't set OPE RX CIF: %d\n", ret); + return ret; + } + + ret = tegra210_ope_set_audio_cif(ope, params, + TEGRA210_OPE_AXBAR_TX_CIF_CTRL); + if (ret) { + dev_err(dev, "Can't set OPE TX CIF: %d\n", ret); + return ret; + } + + return ret; +} + +static int tegra210_ope_codec_probe(struct snd_soc_codec *codec) +{ + struct tegra210_ope *ope = snd_soc_codec_get_drvdata(codec); + int ret; + + codec->control_data = ope->regmap; + ret = snd_soc_codec_set_cache_io(codec, 32, 32, SND_SOC_REGMAP); + if (ret != 0) { + dev_err(codec->dev, "Failed to set cache I/O: %d\n", ret); + return ret; + } + + ope->soc_data->peq_soc_data.codec_init(codec); + ope->soc_data->mbdrc_soc_data.codec_init(codec); + + return 0; +} + +static struct snd_soc_dai_ops tegra210_ope_dai_ops = { + .hw_params = tegra210_ope_hw_params, +}; + +static struct snd_soc_dai_driver tegra210_ope_dais[] = { + { + .name = "OPE IN", + .playback = { + .stream_name = "OPE Receive", + .channels_min = 1, + .channels_max = 8, + .rates = SNDRV_PCM_RATE_8000_96000, + .formats = SNDRV_PCM_FMTBIT_S16_LE, + }, + }, + { + .name = "OPE OUT", + .capture = { + .stream_name = "OPE Transmit", + .channels_min = 1, + .channels_max = 8, + .rates = SNDRV_PCM_RATE_8000_96000, + .formats = SNDRV_PCM_FMTBIT_S16_LE, + }, + .ops = &tegra210_ope_dai_ops, + } +}; + +static const struct snd_soc_dapm_widget tegra210_ope_widgets[] = { + SND_SOC_DAPM_AIF_IN("OPE RX", NULL, 0, SND_SOC_NOPM, + 0, 0), + SND_SOC_DAPM_AIF_OUT("OPE TX", NULL, 0, TEGRA210_OPE_ENABLE, + TEGRA210_OPE_EN_SHIFT, 0), +}; + +static const struct snd_soc_dapm_route tegra210_ope_routes[] = { + { "OPE RX", NULL, "OPE Receive" }, + { "OPE TX", NULL, "OPE RX" }, + { "OPE Transmit", NULL, "OPE TX" }, +}; + +static const struct snd_kcontrol_new tegra210_ope_controls[] = { + SOC_SINGLE("direction peq to mbdrc", TEGRA210_OPE_DIRECTION, + TEGRA210_OPE_DIRECTION_SHIFT, 1, 0), +}; + +static struct snd_soc_codec_driver tegra210_ope_codec = { + .probe = tegra210_ope_codec_probe, + .dapm_widgets = tegra210_ope_widgets, + .num_dapm_widgets = ARRAY_SIZE(tegra210_ope_widgets), + .dapm_routes = tegra210_ope_routes, + .num_dapm_routes = ARRAY_SIZE(tegra210_ope_routes), + .controls = tegra210_ope_controls, + .num_controls = ARRAY_SIZE(tegra210_ope_controls), +}; + +static bool tegra210_ope_wr_reg(struct device *dev, unsigned int reg) +{ + switch (reg) { + case TEGRA210_OPE_AXBAR_RX_INT_MASK: + case TEGRA210_OPE_AXBAR_RX_INT_SET: + case TEGRA210_OPE_AXBAR_RX_INT_CLEAR: + case TEGRA210_OPE_AXBAR_RX_CIF_CTRL: + + case TEGRA210_OPE_AXBAR_TX_INT_MASK: + case TEGRA210_OPE_AXBAR_TX_INT_SET: + case TEGRA210_OPE_AXBAR_TX_INT_CLEAR: + case TEGRA210_OPE_AXBAR_TX_CIF_CTRL: + + case TEGRA210_OPE_ENABLE: + case TEGRA210_OPE_SOFT_RESET: + case TEGRA210_OPE_CG: + case TEGRA210_OPE_DIRECTION: + return true; + default: + return false; + }; +} + +static bool tegra210_ope_rd_reg(struct device *dev, unsigned int reg) +{ + switch (reg) { + case TEGRA210_OPE_AXBAR_RX_STATUS: + case TEGRA210_OPE_AXBAR_RX_INT_STATUS: + case TEGRA210_OPE_AXBAR_RX_INT_MASK: + case TEGRA210_OPE_AXBAR_RX_INT_SET: + case TEGRA210_OPE_AXBAR_RX_INT_CLEAR: + case TEGRA210_OPE_AXBAR_RX_CIF_CTRL: + + case TEGRA210_OPE_AXBAR_TX_STATUS: + case TEGRA210_OPE_AXBAR_TX_INT_STATUS: + case TEGRA210_OPE_AXBAR_TX_INT_MASK: + case TEGRA210_OPE_AXBAR_TX_INT_SET: + case TEGRA210_OPE_AXBAR_TX_INT_CLEAR: + case TEGRA210_OPE_AXBAR_TX_CIF_CTRL: + + case TEGRA210_OPE_ENABLE: + case TEGRA210_OPE_SOFT_RESET: + case TEGRA210_OPE_CG: + case TEGRA210_OPE_STATUS: + case TEGRA210_OPE_INT_STATUS: + case TEGRA210_OPE_DIRECTION: + return true; + default: + return false; + }; +} + +static bool tegra210_ope_volatile_reg(struct device *dev, unsigned int reg) +{ + switch (reg) { + case TEGRA210_OPE_AXBAR_RX_STATUS: + case TEGRA210_OPE_AXBAR_RX_INT_SET: + case TEGRA210_OPE_AXBAR_RX_INT_STATUS: + + case TEGRA210_OPE_AXBAR_TX_STATUS: + case TEGRA210_OPE_AXBAR_TX_INT_SET: + case TEGRA210_OPE_AXBAR_TX_INT_STATUS: + + case TEGRA210_OPE_SOFT_RESET: + case TEGRA210_OPE_STATUS: + case TEGRA210_OPE_INT_STATUS: + return true; + default: + return false; + }; +} + +static const struct regmap_config tegra210_ope_regmap_config = { + .reg_bits = 32, + .reg_stride = 4, + .val_bits = 32, + .max_register = TEGRA210_OPE_DIRECTION, + .writeable_reg = tegra210_ope_wr_reg, + .readable_reg = tegra210_ope_rd_reg, + .volatile_reg = tegra210_ope_volatile_reg, + .cache_type = REGCACHE_RBTREE, +}; + +static const struct tegra210_ope_soc_data soc_data_tegra210 = { + .set_audio_cif = tegra210_xbar_set_cif, + .peq_soc_data = { + .init = tegra210_peq_init, + .codec_init = tegra210_peq_codec_init, + }, + .mbdrc_soc_data = { + .init = tegra210_mbdrc_init, + .codec_init = tegra210_mbdrc_codec_init, + }, +}; + +static const struct of_device_id tegra210_ope_of_match[] = { + { .compatible = "nvidia,tegra210-ope", .data = &soc_data_tegra210 }, + {}, +}; + +static int tegra210_ope_platform_probe(struct platform_device *pdev) +{ + struct tegra210_ope *ope; + struct resource *mem, *memregion; + void __iomem *regs; + int ret = 0; + const struct of_device_id *match; + struct tegra210_ope_soc_data *soc_data; + + pr_info("OPE platform probe\n"); + + match = of_match_device(tegra210_ope_of_match, &pdev->dev); + if (!match) { + dev_err(&pdev->dev, "Error: No device match found\n"); + ret = -ENODEV; + goto err; + } + soc_data = (struct tegra210_ope_soc_data *)match->data; + + ope = devm_kzalloc(&pdev->dev, sizeof(struct tegra210_ope), GFP_KERNEL); + if (!ope) { + dev_err(&pdev->dev, "Can't allocate ope\n"); + ret = -ENOMEM; + goto err; + } + dev_set_drvdata(&pdev->dev, ope); + + ope->soc_data = soc_data; + + ope->clk_ope = devm_clk_get(&pdev->dev, NULL); + if (IS_ERR(ope->clk_ope)) { + dev_err(&pdev->dev, "Can't retrieve ope clock\n"); + ret = PTR_ERR(ope->clk_ope); + goto err; + } + + mem = platform_get_resource(pdev, IORESOURCE_MEM, 0); + if (!mem) { + dev_err(&pdev->dev, "No memory resource\n"); + ret = -ENODEV; + goto err_clk_put; + } + + memregion = devm_request_mem_region(&pdev->dev, mem->start, + resource_size(mem), pdev->name); + if (!memregion) { + dev_err(&pdev->dev, "Memory region already claimed\n"); + ret = -EBUSY; + goto err_clk_put; + } + + regs = devm_ioremap(&pdev->dev, mem->start, resource_size(mem)); + if (!regs) { + dev_err(&pdev->dev, "ioremap failed\n"); + ret = -ENOMEM; + goto err_clk_put; + } + + ope->regmap = devm_regmap_init_mmio(&pdev->dev, regs, + &tegra210_ope_regmap_config); + if (IS_ERR(ope->regmap)) { + dev_err(&pdev->dev, "regmap init failed\n"); + ret = PTR_ERR(ope->regmap); + goto err_clk_put; + } + regcache_cache_only(ope->regmap, true); + + ret = ope->soc_data->peq_soc_data.init(pdev, + TEGRA210_PEQ_IORESOURCE_MEM); + if (ret < 0) { + dev_err(&pdev->dev, "peq init failed\n"); + goto err_clk_put; + } + regcache_cache_only(ope->peq_regmap, true); + + ret = ope->soc_data->mbdrc_soc_data.init(pdev, + TEGRA210_MBDRC_IORESOURCE_MEM); + if (ret < 0) { + dev_err(&pdev->dev, "mbdrc init failed\n"); + goto err_clk_put; + } + regcache_cache_only(ope->mbdrc_regmap, true); + + if (of_property_read_u32(pdev->dev.of_node, + "nvidia,ahub-ope-id", + &pdev->dev.id) < 0) { + dev_err(&pdev->dev, + "Missing property nvidia,ahub-ope-id\n"); + ret = -ENODEV; + goto err_clk_put; + } + + pm_runtime_enable(&pdev->dev); + if (!pm_runtime_enabled(&pdev->dev)) { + ret = tegra210_ope_runtime_resume(&pdev->dev); + if (ret) + goto err_pm_disable; + } + + ret = snd_soc_register_codec(&pdev->dev, &tegra210_ope_codec, + tegra210_ope_dais, + ARRAY_SIZE(tegra210_ope_dais)); + if (ret != 0) { + dev_err(&pdev->dev, "Could not register CODEC: %d\n", ret); + goto err_suspend; + } + + pr_info("OPE platform probe successful\n"); + + return 0; + +err_suspend: + if (!pm_runtime_status_suspended(&pdev->dev)) + tegra210_ope_runtime_suspend(&pdev->dev); +err_pm_disable: + pm_runtime_disable(&pdev->dev); +err_clk_put: + devm_clk_put(&pdev->dev, ope->clk_ope); +err: + return ret; +} + +static int tegra210_ope_platform_remove(struct platform_device *pdev) +{ + struct tegra210_ope *ope = dev_get_drvdata(&pdev->dev); + snd_soc_unregister_codec(&pdev->dev); + + pm_runtime_disable(&pdev->dev); + if (!pm_runtime_status_suspended(&pdev->dev)) + tegra210_ope_runtime_suspend(&pdev->dev); + + devm_clk_put(&pdev->dev, ope->clk_ope); + return 0; +} + +static const struct dev_pm_ops tegra210_ope_pm_ops = { + SET_RUNTIME_PM_OPS(tegra210_ope_runtime_suspend, + tegra210_ope_runtime_resume, NULL) +}; + +static struct platform_driver tegra210_ope_driver = { + .driver = { + .name = DRV_NAME, + .owner = THIS_MODULE, + .of_match_table = tegra210_ope_of_match, + .pm = &tegra210_ope_pm_ops, + }, + .probe = tegra210_ope_platform_probe, + .remove = tegra210_ope_platform_remove, +}; +module_platform_driver(tegra210_ope_driver) + +MODULE_AUTHOR("Sumit Bhattacharya "); +MODULE_DESCRIPTION("Tegra210 OPE ASoC driver"); +MODULE_LICENSE("GPL"); +MODULE_ALIAS("platform:" DRV_NAME); +MODULE_DEVICE_TABLE(of, tegra210_ope_of_match); diff --git a/sound/soc/tegra-alt/tegra210_peq_alt.c b/sound/soc/tegra-alt/tegra210_peq_alt.c new file mode 100644 index 00000000..1a76c678 --- /dev/null +++ b/sound/soc/tegra-alt/tegra210_peq_alt.c @@ -0,0 +1,316 @@ +/* + * tegra210_peq_alt.c - Tegra210 PEQ driver + * + * Copyright (c) 2014 NVIDIA CORPORATION. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "tegra210_xbar_alt.h" +#include "tegra210_ope_alt.h" +#include "tegra210_peq_alt.h" + +/* Default PEQ filter parameters for a 5-stage biquad*/ +static const int biquad_init_stage = 5; +static const u32 biquad_init_gains[TEGRA210_PEQ_GAIN_PARAM_SIZE_PER_CH] = { + 1495012349, /* pre-gain */ + /* Gains : b0, b1, a0, a1, a2 */ + 536870912, -1073741824, 536870912, 2143508246, -1069773768, /* band-0 */ + 134217728, -265414508, 131766272, 2140402222, -1071252997, /* band-1 */ + 268435456, -233515765, -33935948, 1839817267, -773826124, /* band-2 */ + 536870912, -672537913, 139851540, 1886437554, -824433167, /* band-3 */ + 268435456, -114439279, 173723964, 205743566, 278809729, /* band-4 */ + 1, 0, 0, 0, 0, /* band-5 */ + 1, 0, 0, 0, 0, /* band-6 */ + 1, 0, 0, 0, 0, /* band-7 */ + 1, 0, 0, 0, 0, /* band-8 */ + 1, 0, 0, 0, 0, /* band-9 */ + 1, 0, 0, 0, 0, /* band-10 */ + 1, 0, 0, 0, 0, /* band-11 */ + 963423114, /* post-gain */ +}; + +static const u32 biquad_init_shifts[TEGRA210_PEQ_SHIFT_PARAM_SIZE_PER_CH] = { + 23, /* pre-shift */ + 30, 30, 30, 30, 30, 0, 0, 0, 0, 0, 0, 0, /* shift for bands */ + 28, /* post-shift */ +}; + +static int tegra210_peq_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_codec *codec = snd_kcontrol_chip(kcontrol); + struct tegra210_ope *ope = snd_soc_codec_get_drvdata(codec); + unsigned int mask = (1 << fls(mc->max)) - 1; + unsigned int val; + + regmap_read(ope->peq_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_peq_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_codec *codec = snd_kcontrol_chip(kcontrol); + struct tegra210_ope *ope = snd_soc_codec_get_drvdata(codec); + unsigned int mask = (1 << fls(mc->max)) - 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->peq_regmap, mc->reg, + (mask << mc->shift), val); +} + +static int tegra210_peq_ahub_ram_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct tegra_soc_bytes *params = (void *)kcontrol->private_value; + struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); + u32 *data = (u32 *)ucontrol->value.bytes.data; + + memset(data, 0, params->soc.num_regs * codec->val_bytes); + return 0; +} + +static int tegra210_peq_ahub_ram_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct tegra_soc_bytes *params = (void *)kcontrol->private_value; + struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); + struct tegra210_ope *ope = snd_soc_codec_get_drvdata(codec); + u32 reg_ctrl = params->soc.base; + u32 reg_data = reg_ctrl + codec->val_bytes; + u32 *data = (u32 *)ucontrol->value.bytes.data; + + tegra210_xbar_write_ahubram(ope->peq_regmap, reg_ctrl, reg_data, + params->shift, data, params->soc.num_regs); + return 0; +} + +#define TEGRA210_PEQ_GAIN_PARAMS_CTRL(chan) \ + TEGRA_SOC_BYTES_EXT("peq channel" #chan " biquad gain params", \ + TEGRA210_PEQ_AHUBRAMCTL_CONFIG_RAM_CTRL, \ + TEGRA210_PEQ_GAIN_PARAM_SIZE_PER_CH, \ + (TEGRA210_PEQ_GAIN_PARAM_SIZE_PER_CH * chan), 0xffffffff, \ + tegra210_peq_ahub_ram_get, tegra210_peq_ahub_ram_put) + +#define TEGRA210_PEQ_SHIFT_PARAMS_CTRL(chan) \ + TEGRA_SOC_BYTES_EXT("peq channel" #chan " biquad shift params", \ + TEGRA210_PEQ_AHUBRAMCTL_CONFIG_RAM_SHIFT_CTRL, \ + TEGRA210_PEQ_SHIFT_PARAM_SIZE_PER_CH, \ + (TEGRA210_PEQ_SHIFT_PARAM_SIZE_PER_CH * chan), 0x1f, \ + tegra210_peq_ahub_ram_get, tegra210_peq_ahub_ram_put) + +static const struct snd_kcontrol_new tegra210_peq_controls[] = { + SOC_SINGLE_EXT("peq active", TEGRA210_PEQ_CONFIG, + TEGRA210_PEQ_CONFIG_MODE_SHIFT, 1, 0, + tegra210_peq_get, tegra210_peq_put), + SOC_SINGLE_EXT("peq biquad stages", TEGRA210_PEQ_CONFIG, + TEGRA210_PEQ_CONFIG_BIQUAD_STAGES_SHIFT, + TEGRA210_PEQ_MAX_BIQUAD_STAGES - 1, 0, + tegra210_peq_get, tegra210_peq_put), + + TEGRA210_PEQ_GAIN_PARAMS_CTRL(0), + TEGRA210_PEQ_GAIN_PARAMS_CTRL(1), + + TEGRA210_PEQ_SHIFT_PARAMS_CTRL(0), + TEGRA210_PEQ_SHIFT_PARAMS_CTRL(1), +}; + +static bool tegra210_peq_wr_reg(struct device *dev, unsigned int reg) +{ + switch (reg) { + case TEGRA210_PEQ_SOFT_RESET: + case TEGRA210_PEQ_CG: + case TEGRA210_PEQ_CONFIG: + case TEGRA210_PEQ_AHUBRAMCTL_CONFIG_RAM_CTRL: + case TEGRA210_PEQ_AHUBRAMCTL_CONFIG_RAM_DATA: + case TEGRA210_PEQ_AHUBRAMCTL_CONFIG_RAM_SHIFT_CTRL: + case TEGRA210_PEQ_AHUBRAMCTL_CONFIG_RAM_SHIFT_DATA: + return true; + default: + return false; + }; +} + +static bool tegra210_peq_rd_reg(struct device *dev, unsigned int reg) +{ + switch (reg) { + case TEGRA210_PEQ_SOFT_RESET: + case TEGRA210_PEQ_CG: + case TEGRA210_PEQ_STATUS: + case TEGRA210_PEQ_CONFIG: + case TEGRA210_PEQ_AHUBRAMCTL_CONFIG_RAM_CTRL: + case TEGRA210_PEQ_AHUBRAMCTL_CONFIG_RAM_DATA: + case TEGRA210_PEQ_AHUBRAMCTL_CONFIG_RAM_SHIFT_CTRL: + case TEGRA210_PEQ_AHUBRAMCTL_CONFIG_RAM_SHIFT_DATA: + return true; + default: + return false; + }; +} + +static bool tegra210_peq_volatile_reg(struct device *dev, unsigned int reg) +{ + switch (reg) { + case TEGRA210_PEQ_SOFT_RESET: + case TEGRA210_PEQ_STATUS: + case TEGRA210_PEQ_AHUBRAMCTL_CONFIG_RAM_CTRL: + case TEGRA210_PEQ_AHUBRAMCTL_CONFIG_RAM_DATA: + case TEGRA210_PEQ_AHUBRAMCTL_CONFIG_RAM_SHIFT_CTRL: + case TEGRA210_PEQ_AHUBRAMCTL_CONFIG_RAM_SHIFT_DATA: + return true; + default: + return false; + }; +} + +static bool tegra210_peq_precious_reg(struct device *dev, unsigned int reg) +{ + switch (reg) { + case TEGRA210_PEQ_AHUBRAMCTL_CONFIG_RAM_DATA: + case TEGRA210_PEQ_AHUBRAMCTL_CONFIG_RAM_SHIFT_DATA: + return true; + default: + return false; + }; +} + +static const struct regmap_config tegra210_peq_regmap_config = { + .name = "peq", + .reg_bits = 32, + .reg_stride = 4, + .val_bits = 32, + .max_register = TEGRA210_PEQ_AHUBRAMCTL_CONFIG_RAM_SHIFT_DATA, + .writeable_reg = tegra210_peq_wr_reg, + .readable_reg = tegra210_peq_rd_reg, + .volatile_reg = tegra210_peq_volatile_reg, + .precious_reg = tegra210_peq_precious_reg, + .cache_type = REGCACHE_RBTREE, +}; + +int tegra210_peq_codec_init(struct snd_soc_codec *codec) +{ + struct tegra210_ope *ope = snd_soc_codec_get_drvdata(codec); + int i = 0; + + pm_runtime_get_sync(codec->dev); + regmap_update_bits(ope->peq_regmap, TEGRA210_PEQ_CONFIG, + TEGRA210_PEQ_CONFIG_MODE_MASK, + 0 << TEGRA210_PEQ_CONFIG_MODE_SHIFT); + regmap_update_bits(ope->peq_regmap, TEGRA210_PEQ_CONFIG, + TEGRA210_PEQ_CONfIG_BIQUAD_STAGES_MASK, + (biquad_init_stage - 1) << + TEGRA210_PEQ_CONFIG_BIQUAD_STAGES_SHIFT); + + /* Initialize PEQ AHUB RAM with default params */ + for (i = 0; i < TEGRA210_PEQ_MAX_CHANNELS; i++) { + /* Set default gain params */ + tegra210_xbar_write_ahubram(ope->peq_regmap, + TEGRA210_PEQ_AHUBRAMCTL_CONFIG_RAM_CTRL, + TEGRA210_PEQ_AHUBRAMCTL_CONFIG_RAM_DATA, + (i * TEGRA210_PEQ_GAIN_PARAM_SIZE_PER_CH), + (u32 *)&biquad_init_gains, + TEGRA210_PEQ_GAIN_PARAM_SIZE_PER_CH); + + /* Set default shift params */ + tegra210_xbar_write_ahubram(ope->peq_regmap, + TEGRA210_PEQ_AHUBRAMCTL_CONFIG_RAM_SHIFT_CTRL, + TEGRA210_PEQ_AHUBRAMCTL_CONFIG_RAM_SHIFT_DATA, + (i * TEGRA210_PEQ_SHIFT_PARAM_SIZE_PER_CH), + (u32 *)&biquad_init_shifts, + TEGRA210_PEQ_SHIFT_PARAM_SIZE_PER_CH); + } + pm_runtime_put_sync(codec->dev); + + snd_soc_add_codec_controls(codec, tegra210_peq_controls, + ARRAY_SIZE(tegra210_peq_controls)); + return 0; +} +EXPORT_SYMBOL_GPL(tegra210_peq_codec_init); + +int tegra210_peq_init(struct platform_device *pdev, int id) +{ + struct tegra210_ope *ope = dev_get_drvdata(&pdev->dev); + struct resource *mem, *memregion; + void __iomem *regs; + int ret = 0; + + mem = platform_get_resource(pdev, IORESOURCE_MEM, id); + if (!mem) { + dev_err(&pdev->dev, "No memory resource\n"); + ret = -ENODEV; + goto err; + } + + memregion = devm_request_mem_region(&pdev->dev, mem->start, + resource_size(mem), pdev->name); + if (!memregion) { + dev_err(&pdev->dev, "Memory region already claimed\n"); + ret = -EBUSY; + goto err; + } + + regs = devm_ioremap(&pdev->dev, mem->start, resource_size(mem)); + if (!regs) { + dev_err(&pdev->dev, "ioremap failed\n"); + ret = -ENOMEM; + goto err; + } + + ope->peq_regmap = devm_regmap_init_mmio(&pdev->dev, regs, + &tegra210_peq_regmap_config); + if (IS_ERR(ope->peq_regmap)) { + dev_err(&pdev->dev, "regmap init failed\n"); + ret = PTR_ERR(ope->peq_regmap); + goto err; + } + + return 0; +err: + return ret; +} +EXPORT_SYMBOL_GPL(tegra210_peq_init); + +MODULE_AUTHOR("Sumit Bhattacharya "); +MODULE_DESCRIPTION("Tegra210 PEQ module"); +MODULE_LICENSE("GPL"); diff --git a/sound/soc/tegra-alt/tegra210_xbar_alt.c b/sound/soc/tegra-alt/tegra210_xbar_alt.c index e0b87961..9291550d 100644 --- a/sound/soc/tegra-alt/tegra210_xbar_alt.c +++ b/sound/soc/tegra-alt/tegra210_xbar_alt.c @@ -769,6 +769,8 @@ struct of_dev_auxdata tegra210_xbar_auxdata[] = { OF_DEV_AUXDATA("nvidia,tegra210-dmic", 0x702d4000, "tegra210-dmic.0", NULL), OF_DEV_AUXDATA("nvidia,tegra210-dmic", 0x702d4100, "tegra210-dmic.1", NULL), OF_DEV_AUXDATA("nvidia,tegra210-dmic", 0x702d4200, "tegra210-dmic.2", NULL), + OF_DEV_AUXDATA("nvidia,tegra210-ope", 0x702d8000, "tegra210-ope.0", NULL), + OF_DEV_AUXDATA("nvidia,tegra210-ope", 0x702d8400, "tegra210-ope.1", NULL), OF_DEV_AUXDATA("nvidia,tegra210-amixer", 0x702dbb00, "tegra210-mixer", NULL), OF_DEV_AUXDATA("nvidia,tegra210-spdif", 0x702d6000, "tegra210-spdif", NULL), {} @@ -961,6 +963,50 @@ void tegra210_xbar_set_cif(struct regmap *regmap, unsigned int reg, } EXPORT_SYMBOL_GPL(tegra210_xbar_set_cif); +void tegra210_xbar_write_ahubram(struct regmap *regmap, unsigned int reg_ctrl, + unsigned int reg_data, unsigned int ram_offset, + unsigned int *data, size_t size) +{ + unsigned int val = 0; + int i = 0; + + val = (ram_offset << TEGRA210_AHUBRAMCTL_CTRL_RAM_ADDR_SHIFT) & + TEGRA210_AHUBRAMCTL_CTRL_RAM_ADDR_MASK; + val |= TEGRA210_AHUBRAMCTL_CTRL_ADDR_INIT_EN; + val |= TEGRA210_AHUBRAMCTL_CTRL_SEQ_ACCESS_EN; + val |= TEGRA210_AHUBRAMCTL_CTRL_RW_WRITE; + + regmap_write(regmap, reg_ctrl, val); + for (i = 0; i < size; i++) + regmap_write(regmap, reg_data, data[i]); + + return; +} +EXPORT_SYMBOL_GPL(tegra210_xbar_write_ahubram); + +void tegra210_xbar_read_ahubram(struct regmap *regmap, unsigned int reg_ctrl, + unsigned int reg_data, unsigned int ram_offset, + unsigned int *data, size_t size) +{ + unsigned int val = 0; + int i = 0; + + val = (ram_offset << TEGRA210_AHUBRAMCTL_CTRL_RAM_ADDR_SHIFT) & + TEGRA210_AHUBRAMCTL_CTRL_RAM_ADDR_MASK; + val |= TEGRA210_AHUBRAMCTL_CTRL_ADDR_INIT_EN; + val |= TEGRA210_AHUBRAMCTL_CTRL_SEQ_ACCESS_EN; + val |= TEGRA210_AHUBRAMCTL_CTRL_RW_READ; + + regmap_write(regmap, reg_ctrl, val); + /* Since all ahub non-io modules work under same ahub clock it is not + necessary to check ahub read busy bit after every read */ + for (i = 0; i < size; i++) + regmap_read(regmap, reg_data, &data[i]); + + return; +} +EXPORT_SYMBOL_GPL(tegra210_xbar_read_ahubram); + int tegra210_xbar_read_reg (unsigned int reg, unsigned int *val) { int ret;