diff --git a/sound/soc/tegra/tegra186_dspk.c b/sound/soc/tegra/tegra186_dspk.c index 1447985a..3cdb4bca 100644 --- a/sound/soc/tegra/tegra186_dspk.c +++ b/sound/soc/tegra/tegra186_dspk.c @@ -1,88 +1,86 @@ +// SPDX-License-Identifier: GPL-2.0-only /* - * tegra186_dspk_alt.c - Tegra186 DSPK driver + * tegra186_dspk.c - Tegra186 DSPK driver * - * Copyright (c) 2015-2019 NVIDIA CORPORATION. All rights reserved. + * Copyright (c) 2020 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 - -#include "tegra210_xbar_alt.h" -#include "tegra186_dspk_alt.h" -#include "ahub_unit_fpga_clock.h" - -#define DRV_NAME "tegra186-dspk" +#include "tegra186_dspk.h" +#include "tegra_cif.h" static const struct reg_default tegra186_dspk_reg_defaults[] = { - { TEGRA186_DSPK_AXBAR_RX_INT_MASK, 0x00000007}, - { TEGRA186_DSPK_AXBAR_RX_CIF_CTRL, 0x00007700}, - { TEGRA186_DSPK_CG, 0x00000001}, - { TEGRA186_DSPK_CORE_CTRL, 0x00000310}, - { TEGRA186_DSPK_CODEC_CTRL, 0x03000000}, - { TEGRA186_DSPK_SDM_COEF_A_2, 0x000013bb}, - { TEGRA186_DSPK_SDM_COEF_A_3, 0x00001cbf}, - { TEGRA186_DSPK_SDM_COEF_A_4, 0x000029d7}, - { TEGRA186_DSPK_SDM_COEF_A_5, 0x00003782}, - { TEGRA186_DSPK_SDM_COEF_C_1, 0x000000a6}, - { TEGRA186_DSPK_SDM_COEF_C_2, 0x00001959}, - { TEGRA186_DSPK_SDM_COEF_C_3, 0x00002b9f}, - { TEGRA186_DSPK_SDM_COEF_C_4, 0x00004218}, - { TEGRA186_DSPK_SDM_COEF_G_1, 0x00000074}, - { TEGRA186_DSPK_SDM_COEF_G_2, 0x0000007d}, + { TEGRA186_DSPK_RX_INT_MASK, 0x00000007 }, + { TEGRA186_DSPK_RX_CIF_CTRL, 0x00007700 }, + { TEGRA186_DSPK_CG, 0x00000001 }, + { TEGRA186_DSPK_CORE_CTRL, 0x00000310 }, + { TEGRA186_DSPK_CODEC_CTRL, 0x03000000 }, }; static int tegra186_dspk_get_control(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) + struct snd_ctl_elem_value *ucontrol) { - struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol); - struct tegra186_dspk *dspk = snd_soc_codec_get_drvdata(codec); + struct snd_soc_component *codec = snd_soc_kcontrol_component(kcontrol); + struct tegra186_dspk *dspk = snd_soc_component_get_drvdata(codec); - if (strstr(kcontrol->id.name, "Rx fifo threshold")) + if (strstr(kcontrol->id.name, "FIFO Threshold")) ucontrol->value.integer.value[0] = dspk->rx_fifo_th; else if (strstr(kcontrol->id.name, "OSR Value")) ucontrol->value.integer.value[0] = dspk->osr_val; + else if (strstr(kcontrol->id.name, "LR Polarity Select")) + ucontrol->value.integer.value[0] = dspk->lrsel; + else if (strstr(kcontrol->id.name, "Sample Rate")) + ucontrol->value.integer.value[0] = dspk->srate_override; + else if (strstr(kcontrol->id.name, "Audio Channels")) + ucontrol->value.integer.value[0] = dspk->audio_ch_override; + else if (strstr(kcontrol->id.name, "Channel Select")) + ucontrol->value.integer.value[0] = dspk->ch_sel; + else if (strstr(kcontrol->id.name, "Audio Bit Format")) + ucontrol->value.integer.value[0] = dspk->audio_fmt_override; + else if (strstr(kcontrol->id.name, "Mono To Stereo")) + ucontrol->value.integer.value[0] = dspk->mono_to_stereo; + else if (strstr(kcontrol->id.name, "Stereo To Mono")) + ucontrol->value.integer.value[0] = dspk->stereo_to_mono; return 0; } static int tegra186_dspk_put_control(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) + struct snd_ctl_elem_value *ucontrol) { - struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol); - struct tegra186_dspk *dspk = snd_soc_codec_get_drvdata(codec); + struct snd_soc_component *codec = snd_soc_kcontrol_component(kcontrol); + struct tegra186_dspk *dspk = snd_soc_component_get_drvdata(codec); int val = ucontrol->value.integer.value[0]; - if (strstr(kcontrol->id.name, "Rx fifo threshold")) { - if (val >= 0 && val < TEGRA186_DSPK_RX_FIFO_DEPTH) - dspk->rx_fifo_th = val; - else - return -EINVAL; - } else if (strstr(kcontrol->id.name, "OSR Value")) + if (strstr(kcontrol->id.name, "FIFO Threshold")) + dspk->rx_fifo_th = val; + else if (strstr(kcontrol->id.name, "OSR Value")) dspk->osr_val = val; + else if (strstr(kcontrol->id.name, "LR Polarity Select")) + dspk->lrsel = val; + else if (strstr(kcontrol->id.name, "Sample Rate")) + dspk->srate_override = val; + else if (strstr(kcontrol->id.name, "Audio Channels")) + dspk->audio_ch_override = val; + else if (strstr(kcontrol->id.name, "Channel Select")) + dspk->ch_sel = val; + else if (strstr(kcontrol->id.name, "Audio Bit Format")) + dspk->audio_fmt_override = val; + else if (strstr(kcontrol->id.name, "Mono To Stereo")) + dspk->mono_to_stereo = val; + else if (strstr(kcontrol->id.name, "Stereo To Mono")) + dspk->stereo_to_mono = val; return 0; } @@ -94,8 +92,7 @@ static int tegra186_dspk_runtime_suspend(struct device *dev) regcache_cache_only(dspk->regmap, true); regcache_mark_dirty(dspk->regmap); - if (!(tegra_platform_is_unit_fpga() || tegra_platform_is_fpga())) - clk_disable_unprepare(dspk->clk_dspk); + clk_disable_unprepare(dspk->clk_dspk); return 0; } @@ -103,14 +100,12 @@ static int tegra186_dspk_runtime_suspend(struct device *dev) static int tegra186_dspk_runtime_resume(struct device *dev) { struct tegra186_dspk *dspk = dev_get_drvdata(dev); - int ret; + int err; - if (!(tegra_platform_is_unit_fpga() || tegra_platform_is_fpga())) { - ret = clk_prepare_enable(dspk->clk_dspk); - if (ret) { - dev_err(dev, "clk_enable failed: %d\n", ret); - return ret; - } + err = clk_prepare_enable(dspk->clk_dspk); + if (err) { + dev_err(dev, "failed to enable DSPK clock, err: %d\n", err); + return err; } regcache_cache_only(dspk->regmap, false); @@ -119,114 +114,129 @@ static int tegra186_dspk_runtime_resume(struct device *dev) return 0; } -static int tegra186_dspk_set_audio_cif(struct tegra186_dspk *dspk, - struct snd_pcm_hw_params *params, - unsigned int reg, struct snd_soc_dai *dai) +static const unsigned int tegra186_dspk_fmts[] = { + 0, + TEGRA_ACIF_BITS_16, + TEGRA_ACIF_BITS_32, +}; + +static int tegra186_dspk_hw_params(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params, + struct snd_soc_dai *dai) { - int channels, max_th; - struct tegra210_xbar_cif_conf cif_conf; + struct tegra186_dspk *dspk = snd_soc_dai_get_drvdata(dai); + unsigned int channels, srate, dspk_clk; struct device *dev = dai->dev; + struct tegra_cif_conf cif_conf; + unsigned int max_th; + int err; + + memset(&cif_conf, 0, sizeof(struct tegra_cif_conf)); channels = params_channels(params); - memset(&cif_conf, 0, sizeof(struct tegra210_xbar_cif_conf)); - cif_conf.audio_channels = channels; - cif_conf.client_channels = channels; - cif_conf.client_bits = TEGRA210_AUDIOCIF_BITS_24; + cif_conf.audio_ch = channels; - /* RX FIFO threshold interms of frames */ - max_th = (TEGRA186_DSPK_RX_FIFO_DEPTH / channels) - 1; - max_th = (max_th < 0) ? 0 : max_th; - if (dspk->rx_fifo_th > max_th) { /* error handling */ - cif_conf.threshold = max_th; - dspk->rx_fifo_th = max_th; - } else - cif_conf.threshold = dspk->rx_fifo_th; + /* Override audio channel */ + if (dspk->audio_ch_override) + cif_conf.audio_ch = dspk->audio_ch_override; - switch (params_format(params)) { - case SNDRV_PCM_FORMAT_S16_LE: - cif_conf.audio_bits = TEGRA210_AUDIOCIF_BITS_16; - cif_conf.client_bits = TEGRA210_AUDIOCIF_BITS_16; + /* Client channel */ + switch (dspk->ch_sel) { + case DSPK_CH_SELECT_LEFT: + case DSPK_CH_SELECT_RIGHT: + cif_conf.client_ch = 1; break; - case SNDRV_PCM_FORMAT_S32_LE: - cif_conf.audio_bits = TEGRA210_AUDIOCIF_BITS_32; + case DSPK_CH_SELECT_STEREO: + cif_conf.client_ch = 2; break; default: - dev_err(dev, "Wrong format!\n"); + dev_err(dev, "Invalid DSPK client channels\n"); return -EINVAL; } - tegra210_xbar_set_cif(dspk->regmap, TEGRA186_DSPK_AXBAR_RX_CIF_CTRL, - &cif_conf); - return 0; -} + cif_conf.client_bits = TEGRA_ACIF_BITS_24; -static int tegra186_dspk_startup(struct snd_pcm_substream *substream, - struct snd_soc_dai *dai) -{ - struct device *dev = dai->dev; - struct tegra186_dspk *dspk = snd_soc_dai_get_drvdata(dai); - int ret; - - if (dspk->prod_name != NULL) { - ret = tegra_pinctrl_config_prod(dev, dspk->prod_name); - if (ret < 0) - dev_warn(dev, "Failed to set %s setting\n", - dspk->prod_name); + switch (params_format(params)) { + case SNDRV_PCM_FORMAT_S16_LE: + cif_conf.audio_bits = TEGRA_ACIF_BITS_16; + cif_conf.client_bits = TEGRA_ACIF_BITS_16; + break; + case SNDRV_PCM_FORMAT_S32_LE: + cif_conf.audio_bits = TEGRA_ACIF_BITS_32; + break; + default: + dev_err(dev, "unsupported format!\n"); + return -ENOTSUPP; } - return 0; -} + /* Audio bit format override */ + if (dspk->audio_fmt_override) + cif_conf.audio_bits = + tegra186_dspk_fmts[dspk->audio_fmt_override]; -static int tegra186_dspk_hw_params(struct snd_pcm_substream *substream, - struct snd_pcm_hw_params *params, - struct snd_soc_dai *dai) -{ - struct device *dev = dai->dev; - struct tegra186_dspk *dspk = snd_soc_dai_get_drvdata(dai); - int channels, srate, ret, dspk_clk; - int osr = dspk->osr_val; - int interface_clk_ratio = 4; /* dspk interface clock should be fsout*4 */ - - channels = params_channels(params); srate = params_rate(params); - dspk_clk = (1 << (5+osr)) * srate * interface_clk_ratio; + /* Sample rate override */ + if (dspk->srate_override) + srate = dspk->srate_override; - if ((tegra_platform_is_unit_fpga() || tegra_platform_is_fpga())) { - program_dspk_clk(dspk_clk); - } else { - ret = clk_set_rate(dspk->clk_dspk, dspk_clk); - if (ret) { - dev_err(dev, "Can't set dspk clock rate: %d\n", ret); - return ret; - } + /* RX FIFO threshold in terms of frames */ + max_th = (TEGRA186_DSPK_RX_FIFO_DEPTH / cif_conf.audio_ch) - 1; + + if (dspk->rx_fifo_th > max_th) + dspk->rx_fifo_th = max_th; + + cif_conf.threshold = dspk->rx_fifo_th; + cif_conf.mono_conv = dspk->mono_to_stereo; + cif_conf.stereo_conv = dspk->stereo_to_mono; + + tegra_set_cif(dspk->regmap, TEGRA186_DSPK_RX_CIF_CTRL, + &cif_conf); + + /* + * DSPK clock and PDM codec clock should be synchronous with 4:1 ratio, + * this is because it takes 4 clock cycles to send out one sample to + * codec by sigma delta modulator. Finally the clock rate is a multiple + * of 'Over Sampling Ratio', 'Sample Rate' and 'Interface Clock Ratio'. + */ + dspk_clk = (DSPK_OSR_FACTOR << dspk->osr_val) * srate * DSPK_CLK_RATIO; + + err = clk_set_rate(dspk->clk_dspk, dspk_clk); + if (err) { + dev_err(dev, "can't set DSPK clock rate %u, err: %d\n", + dspk_clk, err); + + return err; } regmap_update_bits(dspk->regmap, - TEGRA186_DSPK_CORE_CTRL, - TEGRA186_DSPK_OSR_MASK, - osr << TEGRA186_DSPK_OSR_SHIFT); + /* Reg */ + TEGRA186_DSPK_CORE_CTRL, + /* Mask */ + TEGRA186_DSPK_OSR_MASK | + TEGRA186_DSPK_CHANNEL_SELECT_MASK | + TEGRA186_DSPK_CTRL_LRSEL_POLARITY_MASK, + /* Value */ + (dspk->osr_val << DSPK_OSR_SHIFT) | + ((dspk->ch_sel + 1) << CH_SEL_SHIFT) | + (dspk->lrsel << LRSEL_POL_SHIFT)); - regmap_update_bits(dspk->regmap, - TEGRA186_DSPK_CORE_CTRL, - TEGRA186_DSPK_CHANNEL_SELECT_MASK, - ((1 << channels) - 1) << - TEGRA186_DSPK_CHANNEL_SELECT_SHIFT); - - /* program cif control register */ - ret = tegra186_dspk_set_audio_cif(dspk, params, - TEGRA186_DSPK_AXBAR_RX_CIF_CTRL, - dai); - - if (ret) - dev_err(dev, "Can't set dspk RX CIF: %d\n", ret); - return ret; + return 0; } -static struct snd_soc_dai_ops tegra186_dspk_dai_ops = { +static const struct snd_soc_dai_ops tegra186_dspk_dai_ops = { .hw_params = tegra186_dspk_hw_params, - .startup = tegra186_dspk_startup, }; +/* + * Three DAIs are exposed + * 1. "CIF" DAI for connecting with XBAR + * 2. "DAP" DAI for connecting with CODEC + * 3. "DUMMY_SINK" can be used when no external + * codec connection is available. In such case + * "DAP" is connected with "DUMMY_SINK" + * Order of these DAIs should not be changed, since DAI links in DT refer + * to these DAIs depending on the index. + */ static struct snd_soc_dai_driver tegra186_dspk_dais[] = { { .name = "CIF", @@ -252,33 +262,6 @@ static struct snd_soc_dai_driver tegra186_dspk_dais[] = { .ops = &tegra186_dspk_dai_ops, .symmetric_rates = 1, }, - /* The second DAI is used when the output of the DSPK is connected - * to two mono codecs. When the output of the DSPK is connected to - * a single stereo codec, then only the first DAI should be used. - */ - { - .name = "CIF2", - .playback = { - .stream_name = "CIF2 Receive", - .channels_min = 1, - .channels_max = 2, - .rates = SNDRV_PCM_RATE_8000_48000, - .formats = SNDRV_PCM_FMTBIT_S16_LE | - SNDRV_PCM_FMTBIT_S32_LE, - }, - }, - { - .name = "DAP2", - .capture = { - .stream_name = "DAP2 Transmit", - .channels_min = 1, - .channels_max = 2, - .rates = SNDRV_PCM_RATE_8000_48000, - .formats = SNDRV_PCM_FMTBIT_S16_LE | - SNDRV_PCM_FMTBIT_S32_LE, - }, - .symmetric_rates = 1, - }, { .name = "DUMMY_SINK", .playback = { @@ -294,74 +277,107 @@ static struct snd_soc_dai_driver tegra186_dspk_dais[] = { static const struct snd_soc_dapm_widget tegra186_dspk_widgets[] = { SND_SOC_DAPM_AIF_OUT("DAP TX", NULL, 0, TEGRA186_DSPK_ENABLE, 0, 0), - SND_SOC_DAPM_AIF_OUT("DAP2 TX", NULL, 0, 0, 0, 0), SND_SOC_DAPM_SPK("Dummy Output", NULL), }; static const struct snd_soc_dapm_route tegra186_dspk_routes[] = { - { "DAP TX", NULL, "CIF Receive" }, + { "DAP TX", NULL, "CIF Receive" }, { "DAP Transmit", NULL, "DAP TX" }, - { "DAP2 TX", NULL, "CIF2 Receive" }, - { "DAP2 Transmit", NULL, "DAP2 TX" }, - { "Dummy Output", NULL, "Dummy Playback" }, + { "Dummy Output", NULL, "Dummy Playback" }, }; +static const char * const tegra186_dspk_format_text[] = { + "None", + "16", + "32", +}; + +static const struct soc_enum tegra186_dspk_format_enum = + SOC_ENUM_SINGLE(SND_SOC_NOPM, 0, ARRAY_SIZE(tegra186_dspk_format_text), + tegra186_dspk_format_text); + +static const char * const tegra186_dspk_ch_sel_text[] = { + "Left", "Right", "Stereo", +}; + +static const struct soc_enum tegra186_dspk_ch_sel_enum = + SOC_ENUM_SINGLE(SND_SOC_NOPM, 0, ARRAY_SIZE(tegra186_dspk_ch_sel_text), + tegra186_dspk_ch_sel_text); + static const char * const tegra186_dspk_osr_text[] = { "OSR_32", "OSR_64", "OSR_128", "OSR_256", }; static const struct soc_enum tegra186_dspk_osr_enum = - SOC_ENUM_SINGLE(SND_SOC_NOPM, 0, - ARRAY_SIZE(tegra186_dspk_osr_text), - tegra186_dspk_osr_text); + SOC_ENUM_SINGLE(SND_SOC_NOPM, 0, ARRAY_SIZE(tegra186_dspk_osr_text), + tegra186_dspk_osr_text); -#define NV_SOC_SINGLE_RANGE_EXT(xname, xmin, xmax, xget, xput) \ -{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = (xname), \ - .info = snd_soc_info_xr_sx, .get = xget, .put = xput, \ - .private_value = (unsigned long)&(struct soc_mixer_control) \ - {.invert = 0, .min = xmin, .max = xmax, \ - .platform_max = xmax} \ -} +static const char * const tegra186_dspk_lrsel_text[] = { + "Left", "Right", +}; + +static const char * const tegra186_dspk_mono_conv_text[] = { + "ZERO", "COPY", +}; + +static const struct soc_enum tegra186_dspk_mono_conv_enum = + SOC_ENUM_SINGLE(SND_SOC_NOPM, 0, + ARRAY_SIZE(tegra186_dspk_mono_conv_text), + tegra186_dspk_mono_conv_text); + +static const char * const tegra186_dspk_stereo_conv_text[] = { + "CH0", "CH1", "AVG", +}; + +static const struct soc_enum tegra186_dspk_stereo_conv_enum = + SOC_ENUM_SINGLE(SND_SOC_NOPM, 0, + ARRAY_SIZE(tegra186_dspk_stereo_conv_text), + tegra186_dspk_stereo_conv_text); + +static const struct soc_enum tegra186_dspk_lrsel_enum = + SOC_ENUM_SINGLE(SND_SOC_NOPM, 0, ARRAY_SIZE(tegra186_dspk_lrsel_text), + tegra186_dspk_lrsel_text); static const struct snd_kcontrol_new tegrat186_dspk_controls[] = { - NV_SOC_SINGLE_RANGE_EXT("Rx fifo threshold", 0, - TEGRA186_DSPK_RX_FIFO_DEPTH - 1, tegra186_dspk_get_control, - tegra186_dspk_put_control), + SOC_SINGLE_EXT("FIFO Threshold", SND_SOC_NOPM, 0, + TEGRA186_DSPK_RX_FIFO_DEPTH - 1, 0, + tegra186_dspk_get_control, tegra186_dspk_put_control), SOC_ENUM_EXT("OSR Value", tegra186_dspk_osr_enum, - tegra186_dspk_get_control, tegra186_dspk_put_control), + tegra186_dspk_get_control, tegra186_dspk_put_control), + SOC_ENUM_EXT("LR Polarity Select", tegra186_dspk_lrsel_enum, + tegra186_dspk_get_control, tegra186_dspk_put_control), + SOC_SINGLE_EXT("Sample Rate", SND_SOC_NOPM, 0, 48000, 0, + tegra186_dspk_get_control, tegra186_dspk_put_control), + SOC_SINGLE_EXT("Audio Channels", SND_SOC_NOPM, 0, 2, 0, + tegra186_dspk_get_control, tegra186_dspk_put_control), + SOC_ENUM_EXT("Channel Select", tegra186_dspk_ch_sel_enum, + tegra186_dspk_get_control, tegra186_dspk_put_control), + SOC_ENUM_EXT("Audio Bit Format", tegra186_dspk_format_enum, + tegra186_dspk_get_control, tegra186_dspk_put_control), + SOC_ENUM_EXT("Mono To Stereo", tegra186_dspk_mono_conv_enum, + tegra186_dspk_get_control, tegra186_dspk_put_control), + SOC_ENUM_EXT("Stereo To Mono", tegra186_dspk_stereo_conv_enum, + tegra186_dspk_get_control, tegra186_dspk_put_control), }; -static struct snd_soc_codec_driver tegra186_dspk_codec = { - .idle_bias_off = 1, - .component_driver = { - .dapm_widgets = tegra186_dspk_widgets, - .num_dapm_widgets = ARRAY_SIZE(tegra186_dspk_widgets), - .dapm_routes = tegra186_dspk_routes, - .num_dapm_routes = ARRAY_SIZE(tegra186_dspk_routes), - .controls = tegrat186_dspk_controls, - .num_controls = ARRAY_SIZE(tegrat186_dspk_controls), - }, +static const struct snd_soc_component_driver tegra186_dspk_cmpnt = { + .dapm_widgets = tegra186_dspk_widgets, + .num_dapm_widgets = ARRAY_SIZE(tegra186_dspk_widgets), + .dapm_routes = tegra186_dspk_routes, + .num_dapm_routes = ARRAY_SIZE(tegra186_dspk_routes), + .controls = tegrat186_dspk_controls, + .num_controls = ARRAY_SIZE(tegrat186_dspk_controls), }; -/* Regmap callback functions */ static bool tegra186_dspk_wr_reg(struct device *dev, unsigned int reg) { switch (reg) { - case TEGRA186_DSPK_AXBAR_RX_INT_MASK: - case TEGRA186_DSPK_AXBAR_RX_INT_SET: - case TEGRA186_DSPK_AXBAR_RX_INT_CLEAR: - case TEGRA186_DSPK_AXBAR_RX_CIF_CTRL: - case TEGRA186_DSPK_AXBAR_RX_CYA: - case TEGRA186_DSPK_ENABLE: - case TEGRA186_DSPK_SOFT_RESET: - case TEGRA186_DSPK_CG: + case TEGRA186_DSPK_RX_INT_MASK ... TEGRA186_DSPK_RX_CIF_CTRL: + case TEGRA186_DSPK_ENABLE ... TEGRA186_DSPK_CG: + case TEGRA186_DSPK_CORE_CTRL ... TEGRA186_DSPK_CODEC_CTRL: return true; default: - if (((reg % 4) == 0) && (reg >= TEGRA186_DSPK_CORE_CTRL) && - (reg <= TEGRA186_DSPK_SDM_COEF_G_2)) - return true; - else - return false; + return false; }; } @@ -371,27 +387,8 @@ static bool tegra186_dspk_rd_reg(struct device *dev, unsigned int reg) return true; switch (reg) { - case TEGRA186_DSPK_AXBAR_RX_STATUS: - case TEGRA186_DSPK_AXBAR_RX_INT_STATUS: - case TEGRA186_DSPK_AXBAR_RX_CIF_FIFO_STATUS: - case TEGRA186_DSPK_STATUS: - case TEGRA186_DSPK_INT_STATUS: - return true; - default: - if (((reg % 4) == 0) && (reg >= TEGRA186_DSPK_DEBUG_STATUS) && - (reg <= TEGRA186_DSPK_DEBUG_STAGE4_CNTR)) - return true; - else - return false; - }; -} - -static bool tegra186_dspk_volatile_reg(struct device *dev, unsigned int reg) -{ - switch (reg) { - case TEGRA186_DSPK_AXBAR_RX_STATUS: - case TEGRA186_DSPK_AXBAR_RX_INT_STATUS: - case TEGRA186_DSPK_AXBAR_RX_CIF_FIFO_STATUS: + case TEGRA186_DSPK_RX_STATUS: + case TEGRA186_DSPK_RX_INT_STATUS: case TEGRA186_DSPK_STATUS: case TEGRA186_DSPK_INT_STATUS: return true; @@ -400,114 +397,105 @@ static bool tegra186_dspk_volatile_reg(struct device *dev, unsigned int reg) }; } -static const struct regmap_config tegra186_dspk_regmap_config = { - .reg_bits = 32, - .reg_stride = 4, - .val_bits = 32, - .max_register = TEGRA186_DSPK_DEBUG_STAGE4_CNTR, - .writeable_reg = tegra186_dspk_wr_reg, - .readable_reg = tegra186_dspk_rd_reg, - .volatile_reg = tegra186_dspk_volatile_reg, - .precious_reg = NULL, - .reg_defaults = tegra186_dspk_reg_defaults, - .num_reg_defaults = ARRAY_SIZE(tegra186_dspk_reg_defaults), - .cache_type = REGCACHE_FLAT, +static bool tegra186_dspk_volatile_reg(struct device *dev, unsigned int reg) +{ + switch (reg) { + case TEGRA186_DSPK_RX_STATUS: + case TEGRA186_DSPK_RX_INT_STATUS: + case TEGRA186_DSPK_STATUS: + case TEGRA186_DSPK_INT_STATUS: + return true; + default: + return false; + }; +} + +static const struct regmap_config tegra186_dspk_regmap = { + .reg_bits = 32, + .reg_stride = 4, + .val_bits = 32, + .max_register = TEGRA186_DSPK_CODEC_CTRL, + .writeable_reg = tegra186_dspk_wr_reg, + .readable_reg = tegra186_dspk_rd_reg, + .volatile_reg = tegra186_dspk_volatile_reg, + .reg_defaults = tegra186_dspk_reg_defaults, + .num_reg_defaults = ARRAY_SIZE(tegra186_dspk_reg_defaults), + .cache_type = REGCACHE_FLAT, }; static const struct of_device_id tegra186_dspk_of_match[] = { { .compatible = "nvidia,tegra186-dspk" }, {}, }; +MODULE_DEVICE_TABLE(of, tegra186_dspk_of_match); static int tegra186_dspk_platform_probe(struct platform_device *pdev) { + struct device *dev = &pdev->dev; struct tegra186_dspk *dspk; - struct device_node *np = pdev->dev.of_node; - struct resource *mem; void __iomem *regs; - int ret = 0; - const struct of_device_id *match; + int err; - match = of_match_device(tegra186_dspk_of_match, &pdev->dev); - if (!match) { - dev_err(&pdev->dev, "Error: No device match found\n"); - return -ENODEV; - } - - dspk = devm_kzalloc(&pdev->dev, sizeof(*dspk), GFP_KERNEL); + dspk = devm_kzalloc(dev, sizeof(*dspk), GFP_KERNEL); if (!dspk) return -ENOMEM; - dspk->prod_name = NULL; - dspk->rx_fifo_th = 0; - dspk->osr_val = TEGRA186_DSPK_OSR_64; - dev_set_drvdata(&pdev->dev, dspk); + dspk->osr_val = DSPK_OSR_64; + dspk->lrsel = DSPK_LRSEL_LEFT; + dspk->ch_sel = DSPK_CH_SELECT_STEREO; + dspk->mono_to_stereo = 0; /* "ZERO" */ - if (!(tegra_platform_is_unit_fpga() || tegra_platform_is_fpga())) { - dspk->clk_dspk = devm_clk_get(&pdev->dev, "dspk"); - if (IS_ERR(dspk->clk_dspk)) { - dev_err(&pdev->dev, "Can't retrieve dspk clock\n"); - return PTR_ERR(dspk->clk_dspk); - } + dev_set_drvdata(dev, dspk); + + dspk->clk_dspk = devm_clk_get(dev, "dspk"); + if (IS_ERR(dspk->clk_dspk)) { + dev_err(dev, "can't retrieve DSPK clock\n"); + return PTR_ERR(dspk->clk_dspk); } - mem = platform_get_resource(pdev, IORESOURCE_MEM, 0); - regs = devm_ioremap_resource(&pdev->dev, mem); + regs = devm_platform_ioremap_resource(pdev, 0); if (IS_ERR(regs)) return PTR_ERR(regs); - dspk->regmap = devm_regmap_init_mmio(&pdev->dev, regs, - &tegra186_dspk_regmap_config); + + dspk->regmap = devm_regmap_init_mmio(dev, regs, &tegra186_dspk_regmap); if (IS_ERR(dspk->regmap)) { - dev_err(&pdev->dev, "regmap init failed\n"); + dev_err(dev, "regmap init failed\n"); return PTR_ERR(dspk->regmap); } + regcache_cache_only(dspk->regmap, true); - pm_runtime_enable(&pdev->dev); - ret = snd_soc_register_codec(&pdev->dev, &tegra186_dspk_codec, - tegra186_dspk_dais, - ARRAY_SIZE(tegra186_dspk_dais)); - if (ret != 0) { - dev_err(&pdev->dev, "Could not register CODEC: %d\n", ret); - pm_runtime_disable(&pdev->dev); - return ret; + err = devm_snd_soc_register_component(dev, &tegra186_dspk_cmpnt, + tegra186_dspk_dais, + ARRAY_SIZE(tegra186_dspk_dais)); + if (err) { + dev_err(dev, "can't register DSPK component, err: %d\n", + err); + return err; } - if (of_property_read_string(np, "prod-name", &dspk->prod_name) == 0) { - ret = tegra_pinctrl_config_prod(&pdev->dev, dspk->prod_name); - if (ret < 0) - dev_warn(&pdev->dev, "Failed to set %s setting\n", - dspk->prod_name); - } + pm_runtime_enable(dev); return 0; } static int tegra186_dspk_platform_remove(struct platform_device *pdev) { - struct tegra186_dspk *dspk; - - dspk = dev_get_drvdata(&pdev->dev); - snd_soc_unregister_codec(&pdev->dev); - pm_runtime_disable(&pdev->dev); - if (!pm_runtime_status_suspended(&pdev->dev)) - tegra186_dspk_runtime_suspend(&pdev->dev); return 0; } static const struct dev_pm_ops tegra186_dspk_pm_ops = { SET_RUNTIME_PM_OPS(tegra186_dspk_runtime_suspend, - tegra186_dspk_runtime_resume, NULL) - SET_LATE_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend, - pm_runtime_force_resume) + tegra186_dspk_runtime_resume, NULL) + SET_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend, + pm_runtime_force_resume) }; static struct platform_driver tegra186_dspk_driver = { .driver = { - .name = DRV_NAME, - .owner = THIS_MODULE, + .name = "tegra186-dspk", .of_match_table = tegra186_dspk_of_match, .pm = &tegra186_dspk_pm_ops, }, @@ -516,9 +504,7 @@ static struct platform_driver tegra186_dspk_driver = { }; module_platform_driver(tegra186_dspk_driver); - MODULE_AUTHOR("Mohan Kumar "); -MODULE_DESCRIPTION("Tegra186 DSPK ASoC driver"); -MODULE_LICENSE("GPL"); -MODULE_ALIAS("platform:" DRV_NAME); -MODULE_DEVICE_TABLE(of, tegra186_dspk_of_match); +MODULE_AUTHOR("Sameer Pujar "); +MODULE_DESCRIPTION("Tegra186 ASoC DSPK driver"); +MODULE_LICENSE("GPL v2"); diff --git a/sound/soc/tegra/tegra186_dspk.h b/sound/soc/tegra/tegra186_dspk.h index 520912f6..ad48c23c 100644 --- a/sound/soc/tegra/tegra186_dspk.h +++ b/sound/soc/tegra/tegra186_dspk.h @@ -1,182 +1,73 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ /* - * tegra186_dspk_alt.h - Definitions for Tegra186 DSPK driver + * tegra186_dspk.h - Definitions for Tegra186 DSPK driver * - * Copyright (c) 2015-2019 NVIDIA CORPORATION. All rights reserved. + * Copyright (c) 2020 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 . */ -#ifndef __TEGRA186_DSPK_ALT_H__ -#define __TEGRA186_DSPK_ALT_H__ +#ifndef __TEGRA186_DSPK_H__ +#define __TEGRA186_DSPK_H__ /* Register offsets from DSPK BASE */ -#define TEGRA186_DSPK_AXBAR_RX_STATUS 0x0c -#define TEGRA186_DSPK_AXBAR_RX_INT_STATUS 0x10 -#define TEGRA186_DSPK_AXBAR_RX_INT_MASK 0x14 -#define TEGRA186_DSPK_AXBAR_RX_INT_SET 0x18 -#define TEGRA186_DSPK_AXBAR_RX_INT_CLEAR 0x1c -#define TEGRA186_DSPK_AXBAR_RX_CIF_CTRL 0x20 -#define TEGRA186_DSPK_AXBAR_RX_CYA 0x24 -#define TEGRA186_DSPK_AXBAR_RX_CIF_FIFO_STATUS 0x28 - -#define TEGRA186_DSPK_ENABLE 0x40 -#define TEGRA186_DSPK_SOFT_RESET 0x44 -#define TEGRA186_DSPK_CG 0x48 -#define TEGRA186_DSPK_STATUS 0x4c -#define TEGRA186_DSPK_INT_STATUS 0x50 -#define TEGRA186_DSPK_CORE_CTRL 0x60 -#define TEGRA186_DSPK_CODEC_CTRL 0x64 -#define TEGRA186_DSPK_CODEC_DATA 0x68 -#define TEGRA186_DSPK_CODEC_ENABLE 0x6c -#define TEGRA186_DSPK_CLK_TRIM 0x70 -#define TEGRA186_DSPK_SDM_COEF_A_2 0x74 -#define TEGRA186_DSPK_SDM_COEF_A_3 0x78 -#define TEGRA186_DSPK_SDM_COEF_A_4 0x7c -#define TEGRA186_DSPK_SDM_COEF_A_5 0x80 -#define TEGRA186_DSPK_SDM_COEF_C_1 0x84 -#define TEGRA186_DSPK_SDM_COEF_C_2 0x88 -#define TEGRA186_DSPK_SDM_COEF_C_3 0x8c -#define TEGRA186_DSPK_SDM_COEF_C_4 0x90 -#define TEGRA186_DSPK_SDM_COEF_G_1 0x94 -#define TEGRA186_DSPK_SDM_COEF_G_2 0x98 -#define TEGRA186_DSPK_DEBUG_STATUS 0x9c -#define TEGRA186_DSPK_DEBUG_CIF_CNTR 0xa0 -#define TEGRA186_DSPK_DEBUG_STAGE1_CNTR 0xa4 -#define TEGRA186_DSPK_DEBUG_STAGE2_CNTR 0xa8 -#define TEGRA186_DSPK_DEBUG_STAGE3_CNTR 0xac -#define TEGRA186_DSPK_DEBUG_STAGE4_CNTR 0xb0 - -/* Constants for DSPK */ -#define TEGRA186_DSPK_OSR_32 0 -#define TEGRA186_DSPK_OSR_64 1 -#define TEGRA186_DSPK_OSR_128 2 -#define TEGRA186_DSPK_OSR_256 3 - -/* DSPK ENABLE Register field */ -#define TEGRA186_DSPK_ENABLE_EN BIT(0) - -/* DSPK SOFT RESET field */ -#define TEGRA186_DSPK_SOFT_RESET_EN BIT(0) - -/* DSPK CG field */ -#define TEGRA186_DSPK_CG_SLCG_EN BIT(0) - -/* DSPK STATUS fields */ -#define TEGRA186_DSPK_CODEC_CONFIG_DONE_SHIFT 14 -#define TEGRA186_DSPK_CODEC_CONFIG_DONE_MASK (0x1 << TEGRA186_DSPK_CODEC_CONFIG_DONE_SHIFT) - -#define TEGRA186_DSPK_SLCG_CLKEN_SHIFT 12 -#define TEGRA186_DSPK_SLCG_CLKEN_MASK (0x1 << TEGRA186_DSPK_SLCG_CLKEN_SHIFT) - -#define TEGRA186_DSPK_RX_CIF_FULL_SHIFT 10 -#define TEGRA186_DSPK_RX_CIF_FULL_MASK (0x1 << TEGRA186_DSPK_RX_CIF_FULL_SHIFT) - -#define TEGRA186_DSPK_RX_CIF_EMPTY_SHIFT 9 -#define TEGRA186_DSPK_RX_CIF_EMPTY_MASK (0x1 << TEGRA186_DSPK_RX_CIF_EMPTY_SHIFT) - -#define TEGRA186_DSPK_RX_ENABLED_SHIFT 8 -#define TEGRA186_DSPK_RX_ENABLED_MASK (0x1 << TEGRA186_DSPK_RX_ENABLED_SHIFT) - -/* DSPK INT STATUS fields */ -#define TEGRA186_DSPK_INT_CODEC_CONFIG_DONE_SHIFT 12 -#define TEGRA186_DSPK_INT_CODEC_CONFIG_DONE_MASK (0x1 << TEGRA186_DSPK_INT_CODEC_CONFIG_DONE_SHIFT) - -#define TEGRA186_DSPK_RX_CIF_FIFO_UNDERRUN_SHIFT 9 -#define TEGRA186_DSPK_RX_CIF_FIFO_UNDERRUN_MASK (0x1 << TEGRA186_DSPK_RX_CIF_FIFO_UNDERRUN_SHIFT) - -#define TEGRA186_DSPK_RX_DONE_SHIFT 8 -#define TEGRA186_DSPK_RX_DONE_MASK (0x1 << TEGRA186_DSPK_RX_DONE_SHIFT) +#define TEGRA186_DSPK_RX_STATUS 0x0c +#define TEGRA186_DSPK_RX_INT_STATUS 0x10 +#define TEGRA186_DSPK_RX_INT_MASK 0x14 +#define TEGRA186_DSPK_RX_INT_SET 0x18 +#define TEGRA186_DSPK_RX_INT_CLEAR 0x1c +#define TEGRA186_DSPK_RX_CIF_CTRL 0x20 +#define TEGRA186_DSPK_ENABLE 0x40 +#define TEGRA186_DSPK_SOFT_RESET 0x44 +#define TEGRA186_DSPK_CG 0x48 +#define TEGRA186_DSPK_STATUS 0x4c +#define TEGRA186_DSPK_INT_STATUS 0x50 +#define TEGRA186_DSPK_CORE_CTRL 0x60 +#define TEGRA186_DSPK_CODEC_CTRL 0x64 /* DSPK CORE CONTROL fields */ -#define TEGRA186_DSPK_GAIN1_SHIFT 28 -#define TEGRA186_DSPK_GAIN1_MASK (0x7 << TEGRA186_DSPK_GAIN1_SHIFT) +#define CH_SEL_SHIFT 8 +#define TEGRA186_DSPK_CHANNEL_SELECT_MASK (0x3 << CH_SEL_SHIFT) +#define DSPK_OSR_SHIFT 4 +#define TEGRA186_DSPK_OSR_MASK (0x3 << DSPK_OSR_SHIFT) +#define LRSEL_POL_SHIFT 0 +#define TEGRA186_DSPK_CTRL_LRSEL_POLARITY_MASK (0x1 << LRSEL_POL_SHIFT) +#define TEGRA186_DSPK_RX_FIFO_DEPTH 64 -#define TEGRA186_DSPK_GAIN2_SHIFT 24 -#define TEGRA186_DSPK_GAIN2_MASK (0x7 << TEGRA186_DSPK_GAIN2_SHIFT) +#define DSPK_OSR_FACTOR 32 -#define TEGRA186_DSPK_GAIN3_SHIFT 20 -#define TEGRA186_DSPK_GAIN3_MASK (0x7 << TEGRA186_DSPK_GAIN3_SHIFT) +/* DSPK interface clock ratio */ +#define DSPK_CLK_RATIO 4 -#define TEGRA186_DSPK_FILTER_MODE_SHIFT 16 -#define TEGRA186_DSPK_FILTER_MODE_MASK (0x1 << TEGRA186_DSPK_FILTER_MODE_SHIFT) +enum tegra_dspk_osr { + DSPK_OSR_32, + DSPK_OSR_64, + DSPK_OSR_128, + DSPK_OSR_256, +}; -#define TEGRA186_DSPK_CHANNEL_SELECT_SHIFT 8 -#define TEGRA186_DSPK_CHANNEL_SELECT_MASK (0x3 << TEGRA186_DSPK_CHANNEL_SELECT_SHIFT) +enum tegra_dspk_ch_sel { + DSPK_CH_SELECT_LEFT, + DSPK_CH_SELECT_RIGHT, + DSPK_CH_SELECT_STEREO, +}; -#define TEGRA186_DSPK_OSR_SHIFT 4 -#define TEGRA186_DSPK_OSR_MASK (0x3 << TEGRA186_DSPK_OSR_SHIFT) - -#define TEGRA186_DSPK_LRSEL_POLARITY_SHIFT 0 -#define TEGRA186_DSPK_LRSEL_POLARITY_MASK (0x1 << TEGRA186_DSPK_LRSEL_POLARITY_SHIFT) - -/* DSPK CODEC CONTROL fileds */ -#define TEGRA186_DSPK_CODEC_CHANNEL_SELECT_SHIFT 24 -#define TEGRA186_DSPK_CODEC_CHANNEL_SELECT_MASK (0x3 << TEGRA186_DSPK_CODEC_CHANNEL_SELECT_SHIFT) - -#define TEGRA186_DSPK_CODEC_BIT_ORDER_SHIFT 16 -#define TEGRA186_DSPK_CODEC_BIT_MASK (0x1 << TEGRA186_DSPK_CODEC_BIT_ORDER_SHIFT) - -#define TEGRA186_DSPK_CODEC_CONFIG_MODE_SHIFT 12 -#define TEGRA186_DSPK_CODEC_CONFIG_MODE_MASK (0x1 << TEGRA186_DSPK_CODEC_CONFIG_MODE_SHIFT) - -#define TEGRA186_DSPK_CODEC_CONFIG_REP_NUM_SHIFT 0 -#define TEGRA186_DSPK_CODEC_CONFIG_REP_NUM_MASK (0xff << TEGRA186_DSPK_CODEC_CONFIG_REP_NUM_SHIFT) - -/* DSPK CODEC ENABLE fields */ -#define TEGRA186_DSPK_CODEC_ENABLE_SHIFT 0 -#define TEGRA186_DSPK_CODEC_ENABLE_MASK (0x1 << TEGRA186_DSPK_CODEC_ENABLE_SHIFT) - -/* DSPL CLK TRIM field */ -#define TEGRA186_DSPK_CLK_TRIM_SHIFT 0 -#define TEGRA186_DSPK_CLK_TRIM_MASK (0x1f << TEGRA186_DSPK_CLK_TRIM_SHIFT) - -/* DSPK DEBUG Register fields*/ -#define TEGRA186_DSPK_DEBUG_STATUS_SHIFT 0 -#define TEGRA186_DSPK_DEBUG_STATUS_MASK (0xff << TEGRA186_DSPK_DEBUG_STATUS_SHIFT) - -#define TEGRA186_DSPK_DEBUG_CIF_CH0_SHIFT 16 -#define TEGRA186_DSPK_DEBUG_CIF_CH0_MASK (0xffff << TEGRA186_DSPK_DEBUG_CIF_CH0_SHIFT) -#define TEGRA186_DSPK_DEBUG_CIF_CH1_SHIFT 0 -#define TEGRA186_DSPK_DEBUG_CIF_CH1_MASK (0xffff << TEGRA186_DSPK_DEBUG_CIF_CH1_SHIFT) - -#define TEGRA186_DSPK_DEBUG_STAGE1_CH0_SHIFT 16 -#define TEGRA186_DSPK_DEBUG_STAGE1_CH0_MASK (0xffff << TEGRA186_DSPK_DEBUG_STAGE1_CH0_SHIFT) -#define TEGRA186_DSPK_DEBUG_STAGE1_CH1_SHIFT 0 -#define TEGRA186_DSPK_DEBUG_STAGE1_CH1_MASK (0xffff << TEGRA186_DSPK_DEBUG_STAGE1_CH1_SHIFT) - -#define TEGRA186_DSPK_DEBUG_STAGE2_CH0_SHIFT 16 -#define TEGRA186_DSPK_DEBUG_STAGE2_CH0_MASK (0xffff << TEGRA186_DSPK_DEBUG_STAGE2_CH0_SHIFT) -#define TEGRA186_DSPK_DEBUG_STAGE2_CH1_SHIFT 0 -#define TEGRA186_DSPK_DEBUG_STAGE2_CH1_MASK (0xffff << TEGRA186_DSPK_DEBUG_STAGE2_CH1_SHIFT) - -#define TEGRA186_DSPK_DEBUG_STAGE3_CH0_SHIFT 16 -#define TEGRA186_DSPK_DEBUG_STAGE3_CH0_MASK (0xffff << TEGRA186_DSPK_DEBUG_STAGE3_CH0_SHIFT) -#define TEGRA186_DSPK_DEBUG_STAGE3_CH1_SHIFT 0 -#define TEGRA186_DSPK_DEBUG_STAGE3_CH1_MASK (0xffff << TEGRA186_DSPK_DEBUG_STAGE3_CH1_SHIFT) - -#define TEGRA186_DSPK_DEBUG_STAGE4_CH0_SHIFT 16 -#define TEGRA186_DSPK_DEBUG_STAGE4_CH0_MASK (0xffff << TEGRA186_DSPK_DEBUG_STAGE4_CH0_SHIFT) -#define TEGRA186_DSPK_DEBUG_STAGE4_CH1_SHIFT 0 -#define TEGRA186_DSPK_DEBUG_STAGE4_CH1_MASK (0xffff << TEGRA186_DSPK_DEBUG_STAGE4_CH1_SHIFT) - -#define TEGRA186_DSPK_RX_FIFO_DEPTH 4 +enum tegra_dspk_lrsel { + DSPK_LRSEL_LEFT, + DSPK_LRSEL_RIGHT, +}; struct tegra186_dspk { - struct clk *clk_dspk; - struct regmap *regmap; - const char *prod_name; - unsigned int rx_fifo_th; /* threshold in terms of frames */ - unsigned int osr_val; /* osr value */ + unsigned int rx_fifo_th; + unsigned int osr_val; + unsigned int lrsel; + unsigned int srate_override; + unsigned int audio_ch_override; + unsigned int ch_sel; /* Used for client channel override */ + unsigned int audio_fmt_override; + unsigned int mono_to_stereo; + unsigned int stereo_to_mono; + struct clk *clk_dspk; + struct regmap *regmap; }; #endif diff --git a/sound/soc/tegra/tegra210_admaif.c b/sound/soc/tegra/tegra210_admaif.c index 28210884..cd819ab0 100644 --- a/sound/soc/tegra/tegra210_admaif.c +++ b/sound/soc/tegra/tegra210_admaif.c @@ -1,37 +1,23 @@ +// SPDX-License-Identifier: GPL-2.0-only /* - * tegra210_admaif_alt.c - Tegra ADMAIF driver + * tegra210_admaif.c - Tegra ADMAIF driver * - * Copyright (c) 2014-2020 NVIDIA CORPORATION. All rights reserved. + * Copyright (c) 2020 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 "tegra_pcm_alt.h" -#include "tegra210_xbar_alt.h" -#include "tegra_isomgr_bw_alt.h" -#include "tegra210_admaif_alt.h" - -#define DRV_NAME "tegra210-ape-admaif" +#include +#include "tegra210_admaif.h" +#include "tegra_cif.h" +#include "tegra_pcm.h" #define CH_REG(offset, reg, id) \ ((offset) + (reg) + (TEGRA_ADMAIF_CHANNEL_REG_STRIDE * (id))) @@ -40,25 +26,23 @@ #define CH_RX_REG(reg, id) CH_REG(admaif->soc_data->rx_base, reg, id) -#define REG_IOVA(reg) (admaif->base_addr + (reg)) - #define REG_DEFAULTS(id, rx_ctrl, tx_ctrl, tx_base, rx_base) \ - { CH_REG(rx_base, TEGRA_ADMAIF_XBAR_RX_INT_MASK, id), 0x00000001}, \ - { CH_REG(rx_base, TEGRA_ADMAIF_CHAN_ACIF_RX_CTRL, id), 0x00007700}, \ - { CH_REG(rx_base, TEGRA_ADMAIF_XBAR_RX_FIFO_CTRL, id), rx_ctrl}, \ - { CH_REG(tx_base, TEGRA_ADMAIF_XBAR_TX_INT_MASK, id), 0x00000001}, \ - { CH_REG(tx_base, TEGRA_ADMAIF_CHAN_ACIF_TX_CTRL, id), 0x00007700}, \ - { CH_REG(tx_base, TEGRA_ADMAIF_XBAR_TX_FIFO_CTRL, id), tx_ctrl} + { CH_REG(rx_base, TEGRA_ADMAIF_RX_INT_MASK, id), 0x00000001 }, \ + { CH_REG(rx_base, TEGRA_ADMAIF_CH_ACIF_RX_CTRL, id), 0x00007700 }, \ + { CH_REG(rx_base, TEGRA_ADMAIF_RX_FIFO_CTRL, id), rx_ctrl }, \ + { CH_REG(tx_base, TEGRA_ADMAIF_TX_INT_MASK, id), 0x00000001 }, \ + { CH_REG(tx_base, TEGRA_ADMAIF_CH_ACIF_TX_CTRL, id), 0x00007700 }, \ + { CH_REG(tx_base, TEGRA_ADMAIF_TX_FIFO_CTRL, id), tx_ctrl } #define ADMAIF_REG_DEFAULTS(id, chip) \ - REG_DEFAULTS((id - 1), \ + REG_DEFAULTS((id) - 1, \ chip ## _ADMAIF_RX ## id ## _FIFO_CTRL_REG_DEFAULT, \ chip ## _ADMAIF_TX ## id ## _FIFO_CTRL_REG_DEFAULT, \ - chip ## _ADMAIF_XBAR_TX_BASE, \ - chip ## _ADMAIF_XBAR_RX_BASE) + chip ## _ADMAIF_TX_BASE, \ + chip ## _ADMAIF_RX_BASE) static const struct reg_default tegra186_admaif_reg_defaults[] = { - {(TEGRA_ADMAIF_GLOBAL_CG_0+TEGRA186_ADMAIF_GLOBAL_BASE), 0x00000003}, + {(TEGRA_ADMAIF_GLOBAL_CG_0 + TEGRA186_ADMAIF_GLOBAL_BASE), 0x00000003}, ADMAIF_REG_DEFAULTS(1, TEGRA186), ADMAIF_REG_DEFAULTS(2, TEGRA186), ADMAIF_REG_DEFAULTS(3, TEGRA186), @@ -82,7 +66,7 @@ static const struct reg_default tegra186_admaif_reg_defaults[] = { }; static const struct reg_default tegra210_admaif_reg_defaults[] = { - {(TEGRA_ADMAIF_GLOBAL_CG_0+TEGRA210_ADMAIF_GLOBAL_BASE), 0x00000003}, + {(TEGRA_ADMAIF_GLOBAL_CG_0 + TEGRA210_ADMAIF_GLOBAL_BASE), 0x00000003}, ADMAIF_REG_DEFAULTS(1, TEGRA210), ADMAIF_REG_DEFAULTS(2, TEGRA210), ADMAIF_REG_DEFAULTS(3, TEGRA210), @@ -109,22 +93,23 @@ static bool tegra_admaif_wr_reg(struct device *dev, unsigned int reg) if ((reg >= rx_base) && (reg < rx_max)) { reg = (reg - rx_base) % ch_stride; - if ((reg == TEGRA_ADMAIF_XBAR_RX_ENABLE) || - (reg == TEGRA_ADMAIF_XBAR_RX_FIFO_CTRL) || - (reg == TEGRA_ADMAIF_XBAR_RX_SOFT_RESET) || - (reg == TEGRA_ADMAIF_CHAN_ACIF_RX_CTRL)) + if ((reg == TEGRA_ADMAIF_RX_ENABLE) || + (reg == TEGRA_ADMAIF_RX_FIFO_CTRL) || + (reg == TEGRA_ADMAIF_RX_SOFT_RESET) || + (reg == TEGRA_ADMAIF_CH_ACIF_RX_CTRL)) return true; } else if ((reg >= tx_base) && (reg < tx_max)) { reg = (reg - tx_base) % ch_stride; - if ((reg == TEGRA_ADMAIF_XBAR_TX_ENABLE) || - (reg == TEGRA_ADMAIF_XBAR_TX_FIFO_CTRL) || - (reg == TEGRA_ADMAIF_XBAR_TX_SOFT_RESET) || - (reg == TEGRA_ADMAIF_CHAN_ACIF_TX_CTRL)) + if ((reg == TEGRA_ADMAIF_TX_ENABLE) || + (reg == TEGRA_ADMAIF_TX_FIFO_CTRL) || + (reg == TEGRA_ADMAIF_TX_SOFT_RESET) || + (reg == TEGRA_ADMAIF_CH_ACIF_TX_CTRL)) return true; } else if ((reg >= global_base) && (reg < reg_max)) { if (reg == (global_base + TEGRA_ADMAIF_GLOBAL_ENABLE)) return true; } + return false; } @@ -142,21 +127,21 @@ static bool tegra_admaif_rd_reg(struct device *dev, unsigned int reg) if ((reg >= rx_base) && (reg < rx_max)) { reg = (reg - rx_base) % ch_stride; - if ((reg == TEGRA_ADMAIF_XBAR_RX_ENABLE) || - (reg == TEGRA_ADMAIF_XBAR_RX_STATUS) || - (reg == TEGRA_ADMAIF_XBAR_RX_INT_STATUS) || - (reg == TEGRA_ADMAIF_XBAR_RX_FIFO_CTRL) || - (reg == TEGRA_ADMAIF_XBAR_RX_SOFT_RESET) || - (reg == TEGRA_ADMAIF_CHAN_ACIF_RX_CTRL)) + if ((reg == TEGRA_ADMAIF_RX_ENABLE) || + (reg == TEGRA_ADMAIF_RX_STATUS) || + (reg == TEGRA_ADMAIF_RX_INT_STATUS) || + (reg == TEGRA_ADMAIF_RX_FIFO_CTRL) || + (reg == TEGRA_ADMAIF_RX_SOFT_RESET) || + (reg == TEGRA_ADMAIF_CH_ACIF_RX_CTRL)) return true; } else if ((reg >= tx_base) && (reg < tx_max)) { reg = (reg - tx_base) % ch_stride; - if ((reg == TEGRA_ADMAIF_XBAR_TX_ENABLE) || - (reg == TEGRA_ADMAIF_XBAR_TX_STATUS) || - (reg == TEGRA_ADMAIF_XBAR_TX_INT_STATUS) || - (reg == TEGRA_ADMAIF_XBAR_TX_FIFO_CTRL) || - (reg == TEGRA_ADMAIF_XBAR_TX_SOFT_RESET) || - (reg == TEGRA_ADMAIF_CHAN_ACIF_TX_CTRL)) + if ((reg == TEGRA_ADMAIF_TX_ENABLE) || + (reg == TEGRA_ADMAIF_TX_STATUS) || + (reg == TEGRA_ADMAIF_TX_INT_STATUS) || + (reg == TEGRA_ADMAIF_TX_FIFO_CTRL) || + (reg == TEGRA_ADMAIF_TX_SOFT_RESET) || + (reg == TEGRA_ADMAIF_CH_ACIF_TX_CTRL)) return true; } else if ((reg >= global_base) && (reg < reg_max)) { if ((reg == (global_base + TEGRA_ADMAIF_GLOBAL_ENABLE)) || @@ -168,6 +153,7 @@ static bool tegra_admaif_rd_reg(struct device *dev, unsigned int reg) TEGRA_ADMAIF_GLOBAL_TX_ENABLE_STATUS))) return true; } + return false; } @@ -185,17 +171,17 @@ static bool tegra_admaif_volatile_reg(struct device *dev, unsigned int reg) if ((reg >= rx_base) && (reg < rx_max)) { reg = (reg - rx_base) % ch_stride; - if ((reg == TEGRA_ADMAIF_XBAR_RX_ENABLE) || - (reg == TEGRA_ADMAIF_XBAR_RX_STATUS) || - (reg == TEGRA_ADMAIF_XBAR_RX_INT_STATUS) || - (reg == TEGRA_ADMAIF_XBAR_RX_SOFT_RESET)) + if ((reg == TEGRA_ADMAIF_RX_ENABLE) || + (reg == TEGRA_ADMAIF_RX_STATUS) || + (reg == TEGRA_ADMAIF_RX_INT_STATUS) || + (reg == TEGRA_ADMAIF_RX_SOFT_RESET)) return true; } else if ((reg >= tx_base) && (reg < tx_max)) { reg = (reg - tx_base) % ch_stride; - if ((reg == TEGRA_ADMAIF_XBAR_TX_ENABLE) || - (reg == TEGRA_ADMAIF_XBAR_TX_STATUS) || - (reg == TEGRA_ADMAIF_XBAR_TX_INT_STATUS) || - (reg == TEGRA_ADMAIF_XBAR_TX_SOFT_RESET)) + if ((reg == TEGRA_ADMAIF_TX_ENABLE) || + (reg == TEGRA_ADMAIF_TX_STATUS) || + (reg == TEGRA_ADMAIF_TX_INT_STATUS) || + (reg == TEGRA_ADMAIF_TX_SOFT_RESET)) return true; } else if ((reg >= global_base) && (reg < reg_max)) { if ((reg == (global_base + TEGRA_ADMAIF_GLOBAL_STATUS)) || @@ -205,33 +191,34 @@ static bool tegra_admaif_volatile_reg(struct device *dev, unsigned int reg) TEGRA_ADMAIF_GLOBAL_TX_ENABLE_STATUS))) return true; } + return false; } static const struct regmap_config tegra210_admaif_regmap_config = { - .reg_bits = 32, - .reg_stride = 4, - .val_bits = 32, - .max_register = TEGRA210_ADMAIF_LAST_REG, - .writeable_reg = tegra_admaif_wr_reg, - .readable_reg = tegra_admaif_rd_reg, - .volatile_reg = tegra_admaif_volatile_reg, - .reg_defaults = tegra210_admaif_reg_defaults, - .num_reg_defaults = TEGRA210_ADMAIF_CHANNEL_COUNT * 6 + 1, - .cache_type = REGCACHE_FLAT, + .reg_bits = 32, + .reg_stride = 4, + .val_bits = 32, + .max_register = TEGRA210_ADMAIF_LAST_REG, + .writeable_reg = tegra_admaif_wr_reg, + .readable_reg = tegra_admaif_rd_reg, + .volatile_reg = tegra_admaif_volatile_reg, + .reg_defaults = tegra210_admaif_reg_defaults, + .num_reg_defaults = TEGRA210_ADMAIF_CHANNEL_COUNT * 6 + 1, + .cache_type = REGCACHE_FLAT, }; static const struct regmap_config tegra186_admaif_regmap_config = { - .reg_bits = 32, - .reg_stride = 4, - .val_bits = 32, - .max_register = TEGRA186_ADMAIF_LAST_REG, - .writeable_reg = tegra_admaif_wr_reg, - .readable_reg = tegra_admaif_rd_reg, - .volatile_reg = tegra_admaif_volatile_reg, - .reg_defaults = tegra186_admaif_reg_defaults, - .num_reg_defaults = TEGRA186_ADMAIF_CHANNEL_COUNT * 6 + 1, - .cache_type = REGCACHE_FLAT, + .reg_bits = 32, + .reg_stride = 4, + .val_bits = 32, + .max_register = TEGRA186_ADMAIF_LAST_REG, + .writeable_reg = tegra_admaif_wr_reg, + .readable_reg = tegra_admaif_rd_reg, + .volatile_reg = tegra_admaif_volatile_reg, + .reg_defaults = tegra186_admaif_reg_defaults, + .num_reg_defaults = TEGRA186_ADMAIF_CHANNEL_COUNT * 6 + 1, + .cache_type = REGCACHE_FLAT, }; static int tegra_admaif_runtime_suspend(struct device *dev) @@ -255,32 +242,20 @@ static int tegra_admaif_runtime_resume(struct device *dev) } static int tegra_admaif_set_pack_mode(struct regmap *map, unsigned int reg, - int valid_bit) + int valid_bit) { switch (valid_bit) { case DATA_8BIT: - regmap_update_bits(map, reg, - TEGRA_ADMAIF_CHAN_ACIF_CTRL_PACK8_EN_MASK, - TEGRA_ADMAIF_CHAN_ACIF_CTRL_PACK8_EN); - regmap_update_bits(map, reg, - TEGRA_ADMAIF_CHAN_ACIF_CTRL_PACK16_EN_MASK, - 0); + regmap_update_bits(map, reg, PACK8_EN_MASK, PACK8_EN); + regmap_update_bits(map, reg, PACK16_EN_MASK, 0); break; case DATA_16BIT: - regmap_update_bits(map, reg, - TEGRA_ADMAIF_CHAN_ACIF_CTRL_PACK16_EN_MASK, - TEGRA_ADMAIF_CHAN_ACIF_CTRL_PACK16_EN); - regmap_update_bits(map, reg, - TEGRA_ADMAIF_CHAN_ACIF_CTRL_PACK8_EN_MASK, - 0); + regmap_update_bits(map, reg, PACK16_EN_MASK, PACK16_EN); + regmap_update_bits(map, reg, PACK8_EN_MASK, 0); break; case DATA_32BIT: - regmap_update_bits(map, reg, - TEGRA_ADMAIF_CHAN_ACIF_CTRL_PACK16_EN_MASK, - 0); - regmap_update_bits(map, reg, - TEGRA_ADMAIF_CHAN_ACIF_CTRL_PACK8_EN_MASK, - 0); + regmap_update_bits(map, reg, PACK16_EN_MASK, 0); + regmap_update_bits(map, reg, PACK8_EN_MASK, 0); break; default: return -EINVAL; @@ -289,85 +264,63 @@ static int tegra_admaif_set_pack_mode(struct regmap *map, unsigned int reg, return 0; } -static int tegra_admaif_prepare(struct snd_pcm_substream *substream, - struct snd_soc_dai *dai) -{ - struct tegra_admaif *admaif = snd_soc_dai_get_drvdata(dai); - - if (admaif->soc_data->is_isomgr_client) - tegra_isomgr_adma_setbw(substream, true); - - return 0; -} - -static void tegra_admaif_shutdown(struct snd_pcm_substream *substream, - struct snd_soc_dai *dai) -{ - struct tegra_admaif *admaif = snd_soc_dai_get_drvdata(dai); - - if (admaif->soc_data->is_isomgr_client) - tegra_isomgr_adma_setbw(substream, false); -} - static int tegra_admaif_hw_params(struct snd_pcm_substream *substream, - struct snd_pcm_hw_params *params, - struct snd_soc_dai *dai) + struct snd_pcm_hw_params *params, + struct snd_soc_dai *dai) { struct device *dev = dai->dev; struct tegra_admaif *admaif = snd_soc_dai_get_drvdata(dai); - struct tegra210_xbar_cif_conf cif_conf; + struct tegra_cif_conf cif_conf; unsigned int reg, path; int valid_bit, channels; - memset(&cif_conf, 0, sizeof(struct tegra210_xbar_cif_conf)); + memset(&cif_conf, 0, sizeof(struct tegra_cif_conf)); switch (params_format(params)) { case SNDRV_PCM_FORMAT_S8: - cif_conf.audio_bits = TEGRA210_AUDIOCIF_BITS_8; - cif_conf.client_bits = TEGRA210_AUDIOCIF_BITS_8; + cif_conf.audio_bits = TEGRA_ACIF_BITS_8; + cif_conf.client_bits = TEGRA_ACIF_BITS_8; valid_bit = DATA_8BIT; break; case SNDRV_PCM_FORMAT_S16_LE: - cif_conf.audio_bits = TEGRA210_AUDIOCIF_BITS_16; - cif_conf.client_bits = TEGRA210_AUDIOCIF_BITS_16; + cif_conf.audio_bits = TEGRA_ACIF_BITS_16; + cif_conf.client_bits = TEGRA_ACIF_BITS_16; valid_bit = DATA_16BIT; break; case SNDRV_PCM_FORMAT_S32_LE: - cif_conf.audio_bits = TEGRA210_AUDIOCIF_BITS_32; - cif_conf.client_bits = TEGRA210_AUDIOCIF_BITS_32; + cif_conf.audio_bits = TEGRA_ACIF_BITS_32; + cif_conf.client_bits = TEGRA_ACIF_BITS_32; valid_bit = DATA_32BIT; break; default: - dev_err(dev, "Wrong format!\n"); - return -EINVAL; + dev_err(dev, "unsupported format!\n"); + return -ENOTSUPP; } channels = params_channels(params); - cif_conf.client_channels = channels; - cif_conf.audio_channels = channels; + cif_conf.client_ch = channels; + cif_conf.audio_ch = channels; if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { path = ADMAIF_TX_PATH; - reg = CH_TX_REG(TEGRA_ADMAIF_CHAN_ACIF_TX_CTRL, dai->id); + reg = CH_TX_REG(TEGRA_ADMAIF_CH_ACIF_TX_CTRL, dai->id); } else { path = ADMAIF_RX_PATH; - reg = CH_RX_REG(TEGRA_ADMAIF_CHAN_ACIF_RX_CTRL, dai->id); + reg = CH_RX_REG(TEGRA_ADMAIF_CH_ACIF_RX_CTRL, dai->id); } if (admaif->audio_ch_override[path][dai->id]) - cif_conf.audio_channels = - admaif->audio_ch_override[path][dai->id]; + cif_conf.audio_ch = admaif->audio_ch_override[path][dai->id]; if (admaif->client_ch_override[path][dai->id]) - cif_conf.client_channels = - admaif->client_ch_override[path][dai->id]; + cif_conf.client_ch = admaif->client_ch_override[path][dai->id]; cif_conf.mono_conv = admaif->mono_to_stereo[path][dai->id]; cif_conf.stereo_conv = admaif->stereo_to_mono[path][dai->id]; tegra_admaif_set_pack_mode(admaif->regmap, reg, valid_bit); - tegra210_xbar_set_cif(admaif->regmap, reg, &cif_conf); + tegra_set_cif(admaif->regmap, reg, &cif_conf); return 0; } @@ -379,14 +332,14 @@ static int tegra_admaif_start(struct snd_soc_dai *dai, int direction) switch (direction) { case SNDRV_PCM_STREAM_PLAYBACK: - mask = TEGRA_ADMAIF_XBAR_TX_ENABLE_MASK; - val = TEGRA_ADMAIF_XBAR_TX_EN; - reg = CH_TX_REG(TEGRA_ADMAIF_XBAR_TX_ENABLE, dai->id); + mask = TX_ENABLE_MASK; + val = TX_ENABLE; + reg = CH_TX_REG(TEGRA_ADMAIF_TX_ENABLE, dai->id); break; case SNDRV_PCM_STREAM_CAPTURE: - mask = TEGRA_ADMAIF_XBAR_RX_ENABLE_MASK; - val = TEGRA_ADMAIF_XBAR_RX_EN; - reg = CH_RX_REG(TEGRA_ADMAIF_XBAR_RX_ENABLE, dai->id); + mask = RX_ENABLE_MASK; + val = RX_ENABLE; + reg = CH_RX_REG(TEGRA_ADMAIF_RX_ENABLE, dai->id); break; default: return -EINVAL; @@ -400,61 +353,59 @@ static int tegra_admaif_start(struct snd_soc_dai *dai, int direction) static int tegra_admaif_stop(struct snd_soc_dai *dai, int direction) { struct tegra_admaif *admaif = snd_soc_dai_get_drvdata(dai); - unsigned int enable_reg, status_reg, reset_reg, mask, val, enable; + unsigned int enable_reg, status_reg, reset_reg, mask, val; char *dir_name; - int ret; + int err, enable; switch (direction) { case SNDRV_PCM_STREAM_PLAYBACK: - mask = TEGRA_ADMAIF_XBAR_TX_ENABLE_MASK; - enable = TEGRA_ADMAIF_XBAR_TX_EN; + mask = TX_ENABLE_MASK; + enable = TX_ENABLE; dir_name = "TX"; - enable_reg = CH_TX_REG(TEGRA_ADMAIF_XBAR_TX_ENABLE, dai->id); - status_reg = CH_TX_REG(TEGRA_ADMAIF_XBAR_TX_STATUS, dai->id); - reset_reg = CH_TX_REG(TEGRA_ADMAIF_XBAR_TX_SOFT_RESET, dai->id); + enable_reg = CH_TX_REG(TEGRA_ADMAIF_TX_ENABLE, dai->id); + status_reg = CH_TX_REG(TEGRA_ADMAIF_TX_STATUS, dai->id); + reset_reg = CH_TX_REG(TEGRA_ADMAIF_TX_SOFT_RESET, dai->id); break; case SNDRV_PCM_STREAM_CAPTURE: - mask = TEGRA_ADMAIF_XBAR_RX_ENABLE_MASK; - enable = TEGRA_ADMAIF_XBAR_RX_EN; + mask = RX_ENABLE_MASK; + enable = RX_ENABLE; dir_name = "RX"; - enable_reg = CH_RX_REG(TEGRA_ADMAIF_XBAR_RX_ENABLE, dai->id); - status_reg = CH_RX_REG(TEGRA_ADMAIF_XBAR_RX_STATUS, dai->id); - reset_reg = CH_RX_REG(TEGRA_ADMAIF_XBAR_RX_SOFT_RESET, dai->id); + enable_reg = CH_RX_REG(TEGRA_ADMAIF_RX_ENABLE, dai->id); + status_reg = CH_RX_REG(TEGRA_ADMAIF_RX_STATUS, dai->id); + reset_reg = CH_RX_REG(TEGRA_ADMAIF_RX_SOFT_RESET, dai->id); break; default: return -EINVAL; } - /* disable TX/RX channel */ + /* Disable TX/RX channel */ regmap_update_bits(admaif->regmap, enable_reg, mask, ~enable); - /* wait until ADMAIF TX/RX status is disabled */ - ret = regmap_read_poll_timeout_atomic(admaif->regmap, status_reg, val, + /* Wait until ADMAIF TX/RX status is disabled */ + err = regmap_read_poll_timeout_atomic(admaif->regmap, status_reg, val, !(val & enable), 10, 10000); - - /* Timeout may be hit if sink gets closed/blocked ahead of source */ - if (ret < 0) + if (err < 0) dev_warn(dai->dev, "timeout: failed to disable ADMAIF%d_%s\n", dai->id + 1, dir_name); /* SW reset */ regmap_update_bits(admaif->regmap, reset_reg, SW_RESET_MASK, SW_RESET); - /* wait till SW reset is complete */ - ret = regmap_read_poll_timeout_atomic(admaif->regmap, reset_reg, val, + /* Wait till SW reset is complete */ + err = regmap_read_poll_timeout_atomic(admaif->regmap, reset_reg, val, !(val & SW_RESET_MASK & SW_RESET), 10, 10000); - if (ret < 0) { + if (err) { dev_err(dai->dev, "timeout: SW reset failed for ADMAIF%d_%s\n", dai->id + 1, dir_name); - return ret; + return err; } return 0; } static int tegra_admaif_trigger(struct snd_pcm_substream *substream, int cmd, - struct snd_soc_dai *dai) + struct snd_soc_dai *dai) { switch (cmd) { case SNDRV_PCM_TRIGGER_START: @@ -470,21 +421,19 @@ static int tegra_admaif_trigger(struct snd_pcm_substream *substream, int cmd, } } -static struct snd_soc_dai_ops tegra_admaif_dai_ops = { +static const struct snd_soc_dai_ops tegra_admaif_dai_ops = { .hw_params = tegra_admaif_hw_params, .trigger = tegra_admaif_trigger, - .shutdown = tegra_admaif_shutdown, - .prepare = tegra_admaif_prepare, }; -static int tegra_admaif_get_format(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) +static int tegra_admaif_get_control(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) { - struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol); + struct snd_soc_component *cmpnt = snd_soc_kcontrol_component(kcontrol); struct soc_mixer_control *mc = (struct soc_mixer_control *)kcontrol->private_value; struct soc_enum *ec = (struct soc_enum *)kcontrol->private_value; - struct tegra_admaif *admaif = snd_soc_codec_get_drvdata(codec); + struct tegra_admaif *admaif = snd_soc_component_get_drvdata(cmpnt); long *uctl_val = &ucontrol->value.integer.value[0]; if (strstr(kcontrol->id.name, "Playback Audio Channels")) @@ -495,26 +444,26 @@ static int tegra_admaif_get_format(struct snd_kcontrol *kcontrol, *uctl_val = admaif->client_ch_override[ADMAIF_TX_PATH][mc->reg]; else if (strstr(kcontrol->id.name, "Capture Client Channels")) *uctl_val = admaif->client_ch_override[ADMAIF_RX_PATH][mc->reg]; - else if (strstr(kcontrol->id.name, "Playback mono to stereo")) + else if (strstr(kcontrol->id.name, "Playback Mono To Stereo")) *uctl_val = admaif->mono_to_stereo[ADMAIF_TX_PATH][ec->reg]; - else if (strstr(kcontrol->id.name, "Playback stereo to mono")) - *uctl_val = admaif->stereo_to_mono[ADMAIF_TX_PATH][ec->reg]; - else if (strstr(kcontrol->id.name, "Capture mono to stereo")) + else if (strstr(kcontrol->id.name, "Capture Mono To Stereo")) *uctl_val = admaif->mono_to_stereo[ADMAIF_RX_PATH][ec->reg]; - else if (strstr(kcontrol->id.name, "Capture stereo to mono")) + else if (strstr(kcontrol->id.name, "Playback Stereo To Mono")) + *uctl_val = admaif->stereo_to_mono[ADMAIF_TX_PATH][ec->reg]; + else if (strstr(kcontrol->id.name, "Capture Stereo To Mono")) *uctl_val = admaif->stereo_to_mono[ADMAIF_RX_PATH][ec->reg]; return 0; } -static int tegra_admaif_put_format(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) +static int tegra_admaif_put_control(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 soc_enum *ec = (struct soc_enum *)kcontrol->private_value; - struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol); - struct tegra_admaif *admaif = snd_soc_codec_get_drvdata(codec); + struct tegra_admaif *admaif = snd_soc_component_get_drvdata(cmpnt); int value = ucontrol->value.integer.value[0]; if (strstr(kcontrol->id.name, "Playback Audio Channels")) @@ -525,90 +474,18 @@ static int tegra_admaif_put_format(struct snd_kcontrol *kcontrol, admaif->client_ch_override[ADMAIF_TX_PATH][mc->reg] = value; else if (strstr(kcontrol->id.name, "Capture Client Channels")) admaif->client_ch_override[ADMAIF_RX_PATH][mc->reg] = value; - else if (strstr(kcontrol->id.name, "Playback mono to stereo")) + else if (strstr(kcontrol->id.name, "Playback Mono To Stereo")) admaif->mono_to_stereo[ADMAIF_TX_PATH][ec->reg] = value; - else if (strstr(kcontrol->id.name, "Playback stereo to mono")) - admaif->stereo_to_mono[ADMAIF_TX_PATH][ec->reg] = value; - else if (strstr(kcontrol->id.name, "Capture mono to stereo")) + else if (strstr(kcontrol->id.name, "Capture Mono To Stereo")) admaif->mono_to_stereo[ADMAIF_RX_PATH][ec->reg] = value; - else if (strstr(kcontrol->id.name, "Capture stereo to mono")) + else if (strstr(kcontrol->id.name, "Playback Stereo To Mono")) + admaif->stereo_to_mono[ADMAIF_TX_PATH][ec->reg] = value; + else if (strstr(kcontrol->id.name, "Capture Stereo To Mono")) admaif->stereo_to_mono[ADMAIF_RX_PATH][ec->reg] = value; return 0; } -static void tegra_admaif_reg_dump(struct tegra_admaif *admaif) -{ - int i, stride; - int ret; - int tx_offset = admaif->soc_data->tx_base; - - ret = pm_runtime_get_sync(admaif->dev->parent); - if (ret < 0) { - dev_err(admaif->dev, "parent get_sync failed: %d\n", ret); - return; - } - - pr_info("=========ADMAIF reg dump=========\n"); - - for (i = 0; i < admaif->soc_data->num_ch; i++) { - stride = (i * TEGRA_ADMAIF_CHANNEL_REG_STRIDE); - pr_info("RX%d_Enable = %#x\n", i+1, - readl(admaif->base_addr + - TEGRA_ADMAIF_XBAR_RX_ENABLE + stride)); - pr_info("RX%d_STATUS = %#x\n", i+1, - readl(admaif->base_addr + - TEGRA_ADMAIF_XBAR_RX_STATUS + stride)); - pr_info("RX%d_CIF_CTRL = %#x\n", i+1, - readl(admaif->base_addr + - TEGRA_ADMAIF_CHAN_ACIF_RX_CTRL + stride)); - pr_info("RX%d_FIFO_CTRL = %#x\n", i+1, - readl(admaif->base_addr + - TEGRA_ADMAIF_XBAR_RX_FIFO_CTRL + stride)); - pr_info("TX%d_Enable = %#x\n", i+1, - readl(admaif->base_addr + tx_offset + - TEGRA_ADMAIF_XBAR_TX_ENABLE + stride)); - pr_info("TX%d_STATUS = %#x\n", i+1, - readl(admaif->base_addr + tx_offset + - TEGRA_ADMAIF_XBAR_TX_STATUS + stride)); - pr_info("TX%d_CIF_CTRL = %#x\n", i+1, - readl(admaif->base_addr + tx_offset + - TEGRA_ADMAIF_CHAN_ACIF_TX_CTRL + stride)); - pr_info("TX%d_FIFO_CTRL = %#x\n", i+1, - readl(admaif->base_addr + tx_offset + - TEGRA_ADMAIF_XBAR_TX_FIFO_CTRL + stride)); - } - pm_runtime_put_sync(admaif->dev->parent); -} -static int tegra210_ape_dump_reg_get(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) -{ - struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol); - struct tegra_admaif *admaif = snd_soc_codec_get_drvdata(codec); - - ucontrol->value.integer.value[0] = admaif->reg_dump_flag; - - return 0; -} - -static int tegra210_ape_dump_reg_put(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) -{ - struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol); - struct tegra_admaif *admaif = snd_soc_codec_get_drvdata(codec); - - admaif->reg_dump_flag = ucontrol->value.integer.value[0]; - - if (admaif->reg_dump_flag) { -#if IS_ENABLED(CONFIG_TEGRA210_ADMA) - tegra_adma_dump_ch_reg(); -#endif - tegra_admaif_reg_dump(admaif); - } - - return 0; -} - static int tegra_admaif_dai_probe(struct snd_soc_dai *dai) { struct tegra_admaif *admaif = snd_soc_dai_get_drvdata(dai); @@ -619,7 +496,7 @@ static int tegra_admaif_dai_probe(struct snd_soc_dai *dai) return 0; } -#define ADMAIF_DAI(id) \ +#define ADMAIF_DAI(id) \ { \ .name = "ADMAIF" #id, \ .probe = tegra_admaif_dai_probe, \ @@ -636,62 +513,15 @@ static int tegra_admaif_dai_probe(struct snd_soc_dai *dai) .stream_name = "Capture " #id, \ .channels_min = 1, \ .channels_max = 16, \ - .rates = SNDRV_PCM_RATE_8000_192000, \ - .formats = SNDRV_PCM_FMTBIT_S8 | \ - SNDRV_PCM_FMTBIT_S16_LE | \ - SNDRV_PCM_FMTBIT_S32_LE, \ + .rates = SNDRV_PCM_RATE_8000_192000, \ + .formats = SNDRV_PCM_FMTBIT_S8 | \ + SNDRV_PCM_FMTBIT_S16_LE | \ + SNDRV_PCM_FMTBIT_S32_LE, \ }, \ .ops = &tegra_admaif_dai_ops, \ } -#define ADMAIF_CODEC_FIFO_DAI(id) \ - { \ - .name = "ADMAIF" #id " FIFO", \ - .playback = { \ - .stream_name = "ADMAIF" #id " FIFO Transmit", \ - .channels_min = 1, \ - .channels_max = 16, \ - .rates = SNDRV_PCM_RATE_8000_192000, \ - .formats = SNDRV_PCM_FMTBIT_S8 | \ - SNDRV_PCM_FMTBIT_S16_LE | \ - SNDRV_PCM_FMTBIT_S32_LE, \ - }, \ - .capture = { \ - .stream_name = "ADMAIF" #id " FIFO Receive", \ - .channels_min = 1, \ - .channels_max = 16, \ - .rates = SNDRV_PCM_RATE_8000_192000, \ - .formats = SNDRV_PCM_FMTBIT_S8 | \ - SNDRV_PCM_FMTBIT_S16_LE | \ - SNDRV_PCM_FMTBIT_S32_LE, \ - }, \ - .ops = &tegra_admaif_dai_ops, \ - } - -#define ADMAIF_CODEC_CIF_DAI(id) \ - { \ - .name = "ADMAIF" #id " CIF", \ - .playback = { \ - .stream_name = "ADMAIF" #id " CIF Transmit", \ - .channels_min = 1, \ - .channels_max = 16, \ - .rates = SNDRV_PCM_RATE_8000_192000, \ - .formats = SNDRV_PCM_FMTBIT_S8 | \ - SNDRV_PCM_FMTBIT_S16_LE | \ - SNDRV_PCM_FMTBIT_S32_LE, \ - }, \ - .capture = { \ - .stream_name = "ADMAIF" #id " CIF Receive", \ - .channels_min = 1, \ - .channels_max = 16, \ - .rates = SNDRV_PCM_RATE_8000_192000, \ - .formats = SNDRV_PCM_FMTBIT_S8 | \ - SNDRV_PCM_FMTBIT_S16_LE | \ - SNDRV_PCM_FMTBIT_S32_LE, \ - }, \ - } - -static struct snd_soc_dai_driver tegra210_admaif_codec_dais[] = { +static struct snd_soc_dai_driver tegra210_admaif_cmpnt_dais[] = { ADMAIF_DAI(1), ADMAIF_DAI(2), ADMAIF_DAI(3), @@ -702,29 +532,9 @@ static struct snd_soc_dai_driver tegra210_admaif_codec_dais[] = { ADMAIF_DAI(8), ADMAIF_DAI(9), ADMAIF_DAI(10), - ADMAIF_CODEC_FIFO_DAI(1), - ADMAIF_CODEC_FIFO_DAI(2), - ADMAIF_CODEC_FIFO_DAI(3), - ADMAIF_CODEC_FIFO_DAI(4), - ADMAIF_CODEC_FIFO_DAI(5), - ADMAIF_CODEC_FIFO_DAI(6), - ADMAIF_CODEC_FIFO_DAI(7), - ADMAIF_CODEC_FIFO_DAI(8), - ADMAIF_CODEC_FIFO_DAI(9), - ADMAIF_CODEC_FIFO_DAI(10), - ADMAIF_CODEC_CIF_DAI(1), - ADMAIF_CODEC_CIF_DAI(2), - ADMAIF_CODEC_CIF_DAI(3), - ADMAIF_CODEC_CIF_DAI(4), - ADMAIF_CODEC_CIF_DAI(5), - ADMAIF_CODEC_CIF_DAI(6), - ADMAIF_CODEC_CIF_DAI(7), - ADMAIF_CODEC_CIF_DAI(8), - ADMAIF_CODEC_CIF_DAI(9), - ADMAIF_CODEC_CIF_DAI(10), }; -static struct snd_soc_dai_driver tegra186_admaif_codec_dais[] = { +static struct snd_soc_dai_driver tegra186_admaif_cmpnt_dais[] = { ADMAIF_DAI(1), ADMAIF_DAI(2), ADMAIF_DAI(3), @@ -745,110 +555,6 @@ static struct snd_soc_dai_driver tegra186_admaif_codec_dais[] = { ADMAIF_DAI(18), ADMAIF_DAI(19), ADMAIF_DAI(20), - ADMAIF_CODEC_FIFO_DAI(1), - ADMAIF_CODEC_FIFO_DAI(2), - ADMAIF_CODEC_FIFO_DAI(3), - ADMAIF_CODEC_FIFO_DAI(4), - ADMAIF_CODEC_FIFO_DAI(5), - ADMAIF_CODEC_FIFO_DAI(6), - ADMAIF_CODEC_FIFO_DAI(7), - ADMAIF_CODEC_FIFO_DAI(8), - ADMAIF_CODEC_FIFO_DAI(9), - ADMAIF_CODEC_FIFO_DAI(10), - ADMAIF_CODEC_FIFO_DAI(11), - ADMAIF_CODEC_FIFO_DAI(12), - ADMAIF_CODEC_FIFO_DAI(13), - ADMAIF_CODEC_FIFO_DAI(14), - ADMAIF_CODEC_FIFO_DAI(15), - ADMAIF_CODEC_FIFO_DAI(16), - ADMAIF_CODEC_FIFO_DAI(17), - ADMAIF_CODEC_FIFO_DAI(18), - ADMAIF_CODEC_FIFO_DAI(19), - ADMAIF_CODEC_FIFO_DAI(20), - ADMAIF_CODEC_CIF_DAI(1), - ADMAIF_CODEC_CIF_DAI(2), - ADMAIF_CODEC_CIF_DAI(3), - ADMAIF_CODEC_CIF_DAI(4), - ADMAIF_CODEC_CIF_DAI(5), - ADMAIF_CODEC_CIF_DAI(6), - ADMAIF_CODEC_CIF_DAI(7), - ADMAIF_CODEC_CIF_DAI(8), - ADMAIF_CODEC_CIF_DAI(9), - ADMAIF_CODEC_CIF_DAI(10), - ADMAIF_CODEC_CIF_DAI(11), - ADMAIF_CODEC_CIF_DAI(12), - ADMAIF_CODEC_CIF_DAI(13), - ADMAIF_CODEC_CIF_DAI(14), - ADMAIF_CODEC_CIF_DAI(15), - ADMAIF_CODEC_CIF_DAI(16), - ADMAIF_CODEC_CIF_DAI(17), - ADMAIF_CODEC_CIF_DAI(18), - ADMAIF_CODEC_CIF_DAI(19), - ADMAIF_CODEC_CIF_DAI(20), -}; - -#define ADMAIF_WIDGETS(id) \ - SND_SOC_DAPM_AIF_IN("ADMAIF" #id " FIFO RX", NULL, 0, \ - SND_SOC_NOPM, 0, 0), \ - SND_SOC_DAPM_AIF_OUT("ADMAIF" #id " FIFO TX", NULL, 0, \ - SND_SOC_NOPM, 0, 0), \ - SND_SOC_DAPM_AIF_IN("ADMAIF" #id " CIF RX", NULL, 0, \ - SND_SOC_NOPM, 0, 0), \ - SND_SOC_DAPM_AIF_OUT("ADMAIF" #id " CIF TX", NULL, 0, \ - SND_SOC_NOPM, 0, 0) - -static const struct snd_soc_dapm_widget tegra_admaif_widgets[] = { - ADMAIF_WIDGETS(1), - ADMAIF_WIDGETS(2), - ADMAIF_WIDGETS(3), - ADMAIF_WIDGETS(4), - ADMAIF_WIDGETS(5), - ADMAIF_WIDGETS(6), - ADMAIF_WIDGETS(7), - ADMAIF_WIDGETS(8), - ADMAIF_WIDGETS(9), - ADMAIF_WIDGETS(10), - ADMAIF_WIDGETS(11), - ADMAIF_WIDGETS(12), - ADMAIF_WIDGETS(13), - ADMAIF_WIDGETS(14), - ADMAIF_WIDGETS(15), - ADMAIF_WIDGETS(16), - ADMAIF_WIDGETS(17), - ADMAIF_WIDGETS(18), - ADMAIF_WIDGETS(19), - ADMAIF_WIDGETS(20) -}; - -#define ADMAIF_ROUTES(id) \ - { "ADMAIF" #id " FIFO RX", NULL, "ADMAIF" #id " FIFO Transmit" }, \ - { "ADMAIF" #id " CIF TX", NULL, "ADMAIF" #id " FIFO RX" },\ - { "ADMAIF" #id " CIF Receive", NULL, "ADMAIF" #id " CIF TX" }, \ - { "ADMAIF" #id " CIF RX", NULL, "ADMAIF" #id " CIF Transmit" }, \ - { "ADMAIF" #id " FIFO TX", NULL, "ADMAIF" #id " CIF RX" }, \ - { "ADMAIF" #id " FIFO Receive", NULL, "ADMAIF" #id " FIFO TX" } \ - -static const struct snd_soc_dapm_route tegra_admaif_routes[] = { - ADMAIF_ROUTES(1), - ADMAIF_ROUTES(2), - ADMAIF_ROUTES(3), - ADMAIF_ROUTES(4), - ADMAIF_ROUTES(5), - ADMAIF_ROUTES(6), - ADMAIF_ROUTES(7), - ADMAIF_ROUTES(8), - ADMAIF_ROUTES(9), - ADMAIF_ROUTES(10), - ADMAIF_ROUTES(11), - ADMAIF_ROUTES(12), - ADMAIF_ROUTES(13), - ADMAIF_ROUTES(14), - ADMAIF_ROUTES(15), - ADMAIF_ROUTES(16), - ADMAIF_ROUTES(17), - ADMAIF_ROUTES(18), - ADMAIF_ROUTES(19), - ADMAIF_ROUTES(20) }; static const char * const tegra_admaif_stereo_conv_text[] = { @@ -859,32 +565,22 @@ static const char * const tegra_admaif_mono_conv_text[] = { "ZERO", "COPY", }; -static const struct soc_enum tegra_admaif_mono_conv_enum = - SOC_ENUM_SINGLE(SND_SOC_NOPM, 0, - ARRAY_SIZE(tegra_admaif_mono_conv_text), - tegra_admaif_mono_conv_text); - -static const struct soc_enum tegra_admaif_stereo_conv_enum = - SOC_ENUM_SINGLE(SND_SOC_NOPM, 0, - ARRAY_SIZE(tegra_admaif_stereo_conv_text), - tegra_admaif_stereo_conv_text); - -#define TEGRA_ADMAIF_CHANNEL_CTRL(reg) \ - SOC_SINGLE_EXT("ADMAIF" #reg " Playback Audio Channels", reg - 1, \ - 0, 16, 0, tegra_admaif_get_format, \ - tegra_admaif_put_format), \ - SOC_SINGLE_EXT("ADMAIF" #reg " Capture Audio Channels", reg - 1, \ - 0, 16, 0, tegra_admaif_get_format, \ - tegra_admaif_put_format), \ - SOC_SINGLE_EXT("ADMAIF" #reg " Playback Client Channels", reg - 1, \ - 0, 16, 0, tegra_admaif_get_format, \ - tegra_admaif_put_format), \ - SOC_SINGLE_EXT("ADMAIF" #reg " Capture Client Channels", reg - 1, \ - 0, 16, 0, tegra_admaif_get_format, \ - tegra_admaif_put_format) +#define TEGRA_ADMAIF_CHANNEL_CTRL(reg) \ + SOC_SINGLE_EXT("ADMAIF" #reg " Playback Audio Channels", reg - 1, \ + 0, 16, 0, tegra_admaif_get_control, \ + tegra_admaif_put_control), \ + SOC_SINGLE_EXT("ADMAIF" #reg " Capture Audio Channels", reg - 1, \ + 0, 16, 0, tegra_admaif_get_control, \ + tegra_admaif_put_control), \ + SOC_SINGLE_EXT("ADMAIF" #reg " Playback Client Channels", reg - 1,\ + 0, 16, 0, tegra_admaif_get_control, \ + tegra_admaif_put_control), \ + SOC_SINGLE_EXT("ADMAIF" #reg " Capture Client Channels", reg - 1, \ + 0, 16, 0, tegra_admaif_get_control, \ + tegra_admaif_put_control) /* - * below macro is added to avoid looping over all ADMAIFx controls related + * Below macro is added to avoid looping over all ADMAIFx controls related * to mono/stereo conversions in get()/put() callbacks. */ #define NV_SOC_ENUM_EXT(xname, xreg, xhandler_get, xhandler_put, xenum_text) \ @@ -899,17 +595,17 @@ static const struct soc_enum tegra_admaif_stereo_conv_enum = } #define TEGRA_ADMAIF_CIF_CTRL(reg) \ - NV_SOC_ENUM_EXT("ADMAIF" #reg " Playback mono to stereo conv", reg - 1,\ - tegra_admaif_get_format, tegra_admaif_put_format, \ + NV_SOC_ENUM_EXT("ADMAIF" #reg " Playback Mono To Stereo", reg - 1,\ + tegra_admaif_get_control, tegra_admaif_put_control, \ tegra_admaif_mono_conv_text), \ - NV_SOC_ENUM_EXT("ADMAIF" #reg " Playback stereo to mono conv", reg - 1,\ - tegra_admaif_get_format, tegra_admaif_put_format, \ + NV_SOC_ENUM_EXT("ADMAIF" #reg " Playback Stereo To Mono", reg - 1,\ + tegra_admaif_get_control, tegra_admaif_put_control, \ tegra_admaif_stereo_conv_text), \ - NV_SOC_ENUM_EXT("ADMAIF" #reg " Capture mono to stereo conv", reg - 1, \ - tegra_admaif_get_format, tegra_admaif_put_format, \ + NV_SOC_ENUM_EXT("ADMAIF" #reg " Capture Mono To Stereo", reg - 1, \ + tegra_admaif_get_control, tegra_admaif_put_control, \ tegra_admaif_mono_conv_text), \ - NV_SOC_ENUM_EXT("ADMAIF" #reg " Capture stereo to mono conv", reg - 1, \ - tegra_admaif_get_format, tegra_admaif_put_format, \ + NV_SOC_ENUM_EXT("ADMAIF" #reg " Capture Stereo To Mono", reg - 1, \ + tegra_admaif_get_control, tegra_admaif_put_control, \ tegra_admaif_stereo_conv_text) static struct snd_kcontrol_new tegra210_admaif_controls[] = { @@ -933,8 +629,6 @@ static struct snd_kcontrol_new tegra210_admaif_controls[] = { TEGRA_ADMAIF_CIF_CTRL(8), TEGRA_ADMAIF_CIF_CTRL(9), TEGRA_ADMAIF_CIF_CTRL(10), - SOC_SINGLE_EXT("APE Reg Dump", SND_SOC_NOPM, 0, 1, 0, - tegra210_ape_dump_reg_get, tegra210_ape_dump_reg_put), }; static struct snd_kcontrol_new tegra186_admaif_controls[] = { @@ -978,97 +672,81 @@ static struct snd_kcontrol_new tegra186_admaif_controls[] = { TEGRA_ADMAIF_CIF_CTRL(18), TEGRA_ADMAIF_CIF_CTRL(19), TEGRA_ADMAIF_CIF_CTRL(20), - SOC_SINGLE_EXT("APE Reg Dump", SND_SOC_NOPM, 0, 1, 0, - tegra210_ape_dump_reg_get, tegra210_ape_dump_reg_put), }; -static struct snd_soc_codec_driver tegra210_admaif_codec = { - .idle_bias_off = 1, - .component_driver = { - .dapm_widgets = tegra_admaif_widgets, - .num_dapm_widgets = TEGRA210_ADMAIF_CHANNEL_COUNT * 4, - .dapm_routes = tegra_admaif_routes, - .num_dapm_routes = TEGRA210_ADMAIF_CHANNEL_COUNT * 6, - .controls = tegra210_admaif_controls, - .num_controls = ARRAY_SIZE(tegra210_admaif_controls), - }, +extern const struct snd_pcm_ops tegra_pcm_ops; + +static const struct snd_soc_component_driver tegra210_admaif_cmpnt = { + .controls = tegra210_admaif_controls, + .num_controls = ARRAY_SIZE(tegra210_admaif_controls), + .pcm_new = tegra_pcm_new, + .pcm_free = tegra_pcm_free, + .ops = &tegra_pcm_ops, }; -static struct snd_soc_codec_driver tegra186_admaif_codec = { - .idle_bias_off = 1, - .component_driver = { - .dapm_widgets = tegra_admaif_widgets, - .num_dapm_widgets = TEGRA186_ADMAIF_CHANNEL_COUNT * 4, - .dapm_routes = tegra_admaif_routes, - .num_dapm_routes = TEGRA186_ADMAIF_CHANNEL_COUNT * 6, - .controls = tegra186_admaif_controls, - .num_controls = ARRAY_SIZE(tegra186_admaif_controls), - }, +static const struct snd_soc_component_driver tegra186_admaif_cmpnt = { + .controls = tegra186_admaif_controls, + .num_controls = ARRAY_SIZE(tegra186_admaif_controls), + .pcm_new = tegra_pcm_new, + .pcm_free = tegra_pcm_free, + .ops = &tegra_pcm_ops, }; -static struct tegra_admaif_soc_data soc_data_tegra210 = { - .num_ch = TEGRA210_ADMAIF_CHANNEL_COUNT, - .admaif_codec = &tegra210_admaif_codec, - .codec_dais = tegra210_admaif_codec_dais, - .regmap_conf = &tegra210_admaif_regmap_config, - .global_base = TEGRA210_ADMAIF_GLOBAL_BASE, - .tx_base = TEGRA210_ADMAIF_XBAR_TX_BASE, - .rx_base = TEGRA210_ADMAIF_XBAR_RX_BASE, - .is_isomgr_client = false, +static const struct tegra_admaif_soc_data soc_data_tegra210 = { + .num_ch = TEGRA210_ADMAIF_CHANNEL_COUNT, + .cmpnt = &tegra210_admaif_cmpnt, + .dais = tegra210_admaif_cmpnt_dais, + .regmap_conf = &tegra210_admaif_regmap_config, + .global_base = TEGRA210_ADMAIF_GLOBAL_BASE, + .tx_base = TEGRA210_ADMAIF_TX_BASE, + .rx_base = TEGRA210_ADMAIF_RX_BASE, }; -static struct tegra_admaif_soc_data soc_data_tegra186 = { - .num_ch = TEGRA186_ADMAIF_CHANNEL_COUNT, - .admaif_codec = &tegra186_admaif_codec, - .codec_dais = tegra186_admaif_codec_dais, - .regmap_conf = &tegra186_admaif_regmap_config, - .global_base = TEGRA186_ADMAIF_GLOBAL_BASE, - .tx_base = TEGRA186_ADMAIF_XBAR_TX_BASE, - .rx_base = TEGRA186_ADMAIF_XBAR_RX_BASE, - .is_isomgr_client = true, +static const struct tegra_admaif_soc_data soc_data_tegra186 = { + .num_ch = TEGRA186_ADMAIF_CHANNEL_COUNT, + .cmpnt = &tegra186_admaif_cmpnt, + .dais = tegra186_admaif_cmpnt_dais, + .regmap_conf = &tegra186_admaif_regmap_config, + .global_base = TEGRA186_ADMAIF_GLOBAL_BASE, + .tx_base = TEGRA186_ADMAIF_TX_BASE, + .rx_base = TEGRA186_ADMAIF_RX_BASE, }; - static const struct of_device_id tegra_admaif_of_match[] = { { .compatible = "nvidia,tegra210-admaif", .data = &soc_data_tegra210 }, { .compatible = "nvidia,tegra186-admaif", .data = &soc_data_tegra186 }, {}, }; +MODULE_DEVICE_TABLE(of, tegra_admaif_of_match); static int tegra_admaif_probe(struct platform_device *pdev) { - int ret, i; struct tegra_admaif *admaif; void __iomem *regs; struct resource *res; - const struct of_device_id *match; - unsigned int buffer_size; - - match = of_match_device(tegra_admaif_of_match, &pdev->dev); - if (!match) { - dev_err(&pdev->dev, "Error: No device match found\n"); - return -ENODEV; - } + int err, i; admaif = devm_kzalloc(&pdev->dev, sizeof(*admaif), GFP_KERNEL); if (!admaif) return -ENOMEM; - admaif->dev = &pdev->dev; - admaif->soc_data = (struct tegra_admaif_soc_data *)match->data; + admaif->soc_data = of_device_get_match_data(&pdev->dev); + dev_set_drvdata(&pdev->dev, admaif); - admaif->capture_dma_data = devm_kzalloc(&pdev->dev, - sizeof(struct tegra_alt_pcm_dma_params) * - admaif->soc_data->num_ch, - GFP_KERNEL); + admaif->capture_dma_data = + devm_kcalloc(&pdev->dev, + admaif->soc_data->num_ch, + sizeof(struct snd_dmaengine_dai_dma_data), + GFP_KERNEL); if (!admaif->capture_dma_data) return -ENOMEM; - admaif->playback_dma_data = devm_kzalloc(&pdev->dev, - sizeof(struct tegra_alt_pcm_dma_params) * - admaif->soc_data->num_ch, - GFP_KERNEL); + admaif->playback_dma_data = + devm_kcalloc(&pdev->dev, + admaif->soc_data->num_ch, + sizeof(struct snd_dmaengine_dai_dma_data), + GFP_KERNEL); if (!admaif->playback_dma_data) return -ENOMEM; @@ -1099,113 +777,72 @@ static int tegra_admaif_probe(struct platform_device *pdev) } res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + regs = devm_ioremap_resource(&pdev->dev, res); if (IS_ERR(regs)) return PTR_ERR(regs); - admaif->base_addr = regs; + admaif->regmap = devm_regmap_init_mmio(&pdev->dev, regs, admaif->soc_data->regmap_conf); if (IS_ERR(admaif->regmap)) { dev_err(&pdev->dev, "regmap init failed\n"); return PTR_ERR(admaif->regmap); } + regcache_cache_only(admaif->regmap, true); - if (admaif->soc_data->is_isomgr_client) - tegra_isomgr_adma_register(); - - for (i = 0; i < admaif->soc_data->num_ch; i++) { - admaif->playback_dma_data[i].addr = res->start + - CH_TX_REG(TEGRA_ADMAIF_XBAR_TX_FIFO_WRITE, i); - - admaif->capture_dma_data[i].addr = res->start + - CH_RX_REG(TEGRA_ADMAIF_XBAR_RX_FIFO_READ, i); - - admaif->playback_dma_data[i].width = 32; - admaif->playback_dma_data[i].req_sel = i + 1; - ret = of_property_read_string_index(pdev->dev.of_node, - "dma-names", - (i * 2) + 1, - &admaif->playback_dma_data[i].chan_name); - if (ret < 0) { - dev_err(&pdev->dev, - "Missing property nvidia,dma-names\n"); - return ret; - } - buffer_size = 0; - if (of_property_read_u32_index(pdev->dev.of_node, - "dma-buffer-size", - (i * 2) + 1, - &buffer_size) < 0) { - dev_dbg(&pdev->dev, - "Missing property nvidia,dma-buffer-size\n"); - } - admaif->playback_dma_data[i].buffer_size = buffer_size; - - admaif->capture_dma_data[i].width = 32; - admaif->capture_dma_data[i].req_sel = i + 1; - ret = of_property_read_string_index(pdev->dev.of_node, - "dma-names", - (i * 2), - &admaif->capture_dma_data[i].chan_name); - if (ret < 0) { - dev_err(&pdev->dev, - "Missing property nvidia,dma-names\n"); - return ret; - } - buffer_size = 0; - if (of_property_read_u32_index(pdev->dev.of_node, - "dma-buffer-size", - (i * 2), - &buffer_size) < 0) { - dev_dbg(&pdev->dev, - "Missing property nvidia,dma-buffer-size\n"); - } - admaif->capture_dma_data[i].buffer_size = buffer_size; - } - regmap_update_bits(admaif->regmap, admaif->soc_data->global_base + TEGRA_ADMAIF_GLOBAL_ENABLE, 1, 1); - pm_runtime_enable(&pdev->dev); - ret = snd_soc_register_codec(&pdev->dev, admaif->soc_data->admaif_codec, - admaif->soc_data->codec_dais, - admaif->soc_data->num_ch * 3); - if (ret != 0) { - dev_err(&pdev->dev, "Could not register CODEC: %d\n", ret); - goto pm_disable; + for (i = 0; i < admaif->soc_data->num_ch; i++) { + admaif->playback_dma_data[i].addr = res->start + + CH_TX_REG(TEGRA_ADMAIF_TX_FIFO_WRITE, i); + + admaif->capture_dma_data[i].addr = res->start + + CH_RX_REG(TEGRA_ADMAIF_RX_FIFO_READ, i); + + admaif->playback_dma_data[i].addr_width = 32; + + if (of_property_read_string_index(pdev->dev.of_node, + "dma-names", (i * 2) + 1, + &admaif->playback_dma_data[i].chan_name) < 0) { + dev_err(&pdev->dev, + "missing property nvidia,dma-names\n"); + + return -ENODEV; + } + + admaif->capture_dma_data[i].addr_width = 32; + + if (of_property_read_string_index(pdev->dev.of_node, + "dma-names", + (i * 2), + &admaif->capture_dma_data[i].chan_name) < 0) { + dev_err(&pdev->dev, + "missing property nvidia,dma-names\n"); + + return -ENODEV; + } } - ret = tegra_alt_pcm_platform_register(&pdev->dev); - if (ret) { - dev_err(&pdev->dev, "Could not register PCM: %d\n", ret); - goto unregister_codec; + err = devm_snd_soc_register_component(&pdev->dev, + admaif->soc_data->cmpnt, + admaif->soc_data->dais, + admaif->soc_data->num_ch); + if (err) { + dev_err(&pdev->dev, + "can't register ADMAIF component, err: %d\n", err); + return err; } + pm_runtime_enable(&pdev->dev); + return 0; - -unregister_codec: - snd_soc_unregister_codec(&pdev->dev); -pm_disable: - pm_runtime_disable(&pdev->dev); - - return ret; } static int tegra_admaif_remove(struct platform_device *pdev) { - struct tegra_admaif *admaif = dev_get_drvdata(&pdev->dev); - - if (admaif->soc_data->is_isomgr_client) - tegra_isomgr_adma_unregister(); - - snd_soc_unregister_codec(&pdev->dev); - - tegra_alt_pcm_platform_unregister(&pdev->dev); - pm_runtime_disable(&pdev->dev); - if (!pm_runtime_status_suspended(&pdev->dev)) - tegra_admaif_runtime_suspend(&pdev->dev); return 0; } @@ -1213,24 +850,21 @@ static int tegra_admaif_remove(struct platform_device *pdev) static const struct dev_pm_ops tegra_admaif_pm_ops = { SET_RUNTIME_PM_OPS(tegra_admaif_runtime_suspend, tegra_admaif_runtime_resume, NULL) - SET_LATE_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend, - pm_runtime_force_resume) + SET_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend, + pm_runtime_force_resume) }; static struct platform_driver tegra_admaif_driver = { .probe = tegra_admaif_probe, .remove = tegra_admaif_remove, .driver = { - .name = DRV_NAME, - .owner = THIS_MODULE, + .name = "tegra210-admaif", .of_match_table = tegra_admaif_of_match, .pm = &tegra_admaif_pm_ops, }, }; module_platform_driver(tegra_admaif_driver); -MODULE_DEVICE_TABLE(of, tegra_admaif_of_match); MODULE_AUTHOR("Songhee Baek "); -MODULE_DESCRIPTION("Tegra ADMAIF driver"); +MODULE_DESCRIPTION("Tegra210 ASoC ADMAIF driver"); MODULE_LICENSE("GPL v2"); -MODULE_ALIAS("platform:" DRV_NAME); diff --git a/sound/soc/tegra/tegra210_admaif.h b/sound/soc/tegra/tegra210_admaif.h index 5afe983e..e9622d10 100644 --- a/sound/soc/tegra/tegra210_admaif.h +++ b/sound/soc/tegra/tegra210_admaif.h @@ -1,156 +1,132 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ /* - * tegra210_admaif_alt.h - Tegra ADMAIF registers + * tegra210_admaif.h - Tegra ADMAIF registers * - * Copyright (c) 2014-2019 NVIDIA CORPORATION. All rights reserved. + * Copyright (c) 2020 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 . */ -#ifndef __TEGRA_ADMAIF_ALT_H__ -#define __TEGRA_ADMAIF_ALT_H__ +#ifndef __TEGRA_ADMAIF_H__ +#define __TEGRA_ADMAIF_H__ -#define TEGRA_ADMAIF_CHANNEL_REG_STRIDE 0x40 - -#define TEGRA210_ADMAIF_LAST_REG 0x75f -#define TEGRA186_ADMAIF_LAST_REG 0xd5f - -#define TEGRA210_ADMAIF_CHANNEL_COUNT 10 -#define TEGRA186_ADMAIF_CHANNEL_COUNT 20 - -#define TEGRA210_ADMAIF_XBAR_RX_BASE 0x0 -#define TEGRA210_ADMAIF_XBAR_TX_BASE 0x300 -#define TEGRA210_ADMAIF_GLOBAL_BASE 0x700 - -#define TEGRA186_ADMAIF_XBAR_RX_BASE 0x0 -#define TEGRA186_ADMAIF_XBAR_TX_BASE 0x500 -#define TEGRA186_ADMAIF_GLOBAL_BASE 0xd00 - -#define TEGRA_ADMAIF_XBAR_RX_ENABLE 0x0 -#define TEGRA_ADMAIF_XBAR_RX_SOFT_RESET 0x4 -#define TEGRA_ADMAIF_XBAR_RX_STATUS 0xc -#define TEGRA_ADMAIF_XBAR_RX_INT_STATUS 0x10 -#define TEGRA_ADMAIF_XBAR_RX_INT_MASK 0x14 -#define TEGRA_ADMAIF_XBAR_RX_INT_SET 0x18 -#define TEGRA_ADMAIF_XBAR_RX_INT_CLEAR 0x1c -#define TEGRA_ADMAIF_CHAN_ACIF_RX_CTRL 0x20 -#define TEGRA_ADMAIF_XBAR_RX_FIFO_CTRL 0x28 -#define TEGRA_ADMAIF_XBAR_RX_FIFO_READ 0x2c -#define TEGRA_ADMAIF_GLOBAL_ENABLE 0x0 -#define TEGRA_ADMAIF_GLOBAL_CG_0 0x8 -#define TEGRA_ADMAIF_GLOBAL_STATUS 0x10 -#define TEGRA_ADMAIF_GLOBAL_RX_ENABLE_STATUS 0x20 -#define TEGRA_ADMAIF_GLOBAL_TX_ENABLE_STATUS 0x24 - -#define TEGRA_ADMAIF_XBAR_TX_ENABLE 0x0 -#define TEGRA_ADMAIF_XBAR_TX_SOFT_RESET 0x4 -#define TEGRA_ADMAIF_XBAR_TX_STATUS 0xc -#define TEGRA_ADMAIF_XBAR_TX_INT_STATUS 0x10 -#define TEGRA_ADMAIF_XBAR_TX_INT_MASK 0x14 -#define TEGRA_ADMAIF_XBAR_TX_INT_SET 0x18 -#define TEGRA_ADMAIF_XBAR_TX_INT_CLEAR 0x1c -#define TEGRA_ADMAIF_CHAN_ACIF_TX_CTRL 0x20 -#define TEGRA_ADMAIF_XBAR_TX_FIFO_CTRL 0x28 -#define TEGRA_ADMAIF_XBAR_TX_FIFO_WRITE 0x2c - -#define TEGRA_ADMAIF_CHAN_ACIF_CTRL_PACK8_EN_SHIFT 31 -#define TEGRA_ADMAIF_CHAN_ACIF_CTRL_PACK8_EN_MASK \ - (1 << TEGRA_ADMAIF_CHAN_ACIF_CTRL_PACK8_EN_SHIFT) -#define TEGRA_ADMAIF_CHAN_ACIF_CTRL_PACK8_EN \ - (1 << TEGRA_ADMAIF_CHAN_ACIF_CTRL_PACK8_EN_SHIFT) -#define TEGRA_ADMAIF_CHAN_ACIF_CTRL_PACK16_EN_SHIFT 30 -#define TEGRA_ADMAIF_CHAN_ACIF_CTRL_PACK16_EN_MASK \ - (1 << TEGRA_ADMAIF_CHAN_ACIF_CTRL_PACK16_EN_SHIFT) -#define TEGRA_ADMAIF_CHAN_ACIF_CTRL_PACK16_EN \ - (1 << TEGRA_ADMAIF_CHAN_ACIF_CTRL_PACK16_EN_SHIFT) - -#define TEGRA_ADMAIF_XBAR_TX_ENABLE_SHIFT 0 -#define TEGRA_ADMAIF_XBAR_TX_EN \ - (1 << TEGRA_ADMAIF_XBAR_TX_ENABLE_SHIFT) -#define TEGRA_ADMAIF_XBAR_TX_ENABLE_MASK \ - (1 << TEGRA_ADMAIF_XBAR_TX_ENABLE_SHIFT) - -#define TEGRA_ADMAIF_XBAR_RX_ENABLE_SHIFT 0 -#define TEGRA_ADMAIF_XBAR_RX_EN \ - (1 << TEGRA_ADMAIF_XBAR_RX_ENABLE_SHIFT) -#define TEGRA_ADMAIF_XBAR_RX_ENABLE_MASK \ - (1 << TEGRA_ADMAIF_XBAR_RX_ENABLE_SHIFT) - -#define SW_RESET_MASK 1 -#define SW_RESET 1 - -#define TEGRA210_ADMAIF_RX1_FIFO_CTRL_REG_DEFAULT 0x00000300 -#define TEGRA210_ADMAIF_RX2_FIFO_CTRL_REG_DEFAULT 0x00000304 -#define TEGRA210_ADMAIF_RX3_FIFO_CTRL_REG_DEFAULT 0x00000208 -#define TEGRA210_ADMAIF_RX4_FIFO_CTRL_REG_DEFAULT 0x0000020b -#define TEGRA210_ADMAIF_RX5_FIFO_CTRL_REG_DEFAULT 0x0000020e -#define TEGRA210_ADMAIF_RX6_FIFO_CTRL_REG_DEFAULT 0x00000211 -#define TEGRA210_ADMAIF_RX7_FIFO_CTRL_REG_DEFAULT 0x00000214 -#define TEGRA210_ADMAIF_RX8_FIFO_CTRL_REG_DEFAULT 0x00000217 -#define TEGRA210_ADMAIF_RX9_FIFO_CTRL_REG_DEFAULT 0x0000021a -#define TEGRA210_ADMAIF_RX10_FIFO_CTRL_REG_DEFAULT 0x0000021d - -#define TEGRA210_ADMAIF_TX1_FIFO_CTRL_REG_DEFAULT 0x02000300 -#define TEGRA210_ADMAIF_TX2_FIFO_CTRL_REG_DEFAULT 0x02000304 -#define TEGRA210_ADMAIF_TX3_FIFO_CTRL_REG_DEFAULT 0x01800208 -#define TEGRA210_ADMAIF_TX4_FIFO_CTRL_REG_DEFAULT 0x0180020b -#define TEGRA210_ADMAIF_TX5_FIFO_CTRL_REG_DEFAULT 0x0180020e -#define TEGRA210_ADMAIF_TX6_FIFO_CTRL_REG_DEFAULT 0x01800211 -#define TEGRA210_ADMAIF_TX7_FIFO_CTRL_REG_DEFAULT 0x01800214 -#define TEGRA210_ADMAIF_TX8_FIFO_CTRL_REG_DEFAULT 0x01800217 -#define TEGRA210_ADMAIF_TX9_FIFO_CTRL_REG_DEFAULT 0x0180021a -#define TEGRA210_ADMAIF_TX10_FIFO_CTRL_REG_DEFAULT 0x0180021d - -#define TEGRA186_ADMAIF_RX1_FIFO_CTRL_REG_DEFAULT 0x00000300 -#define TEGRA186_ADMAIF_RX2_FIFO_CTRL_REG_DEFAULT 0x00000304 -#define TEGRA186_ADMAIF_RX3_FIFO_CTRL_REG_DEFAULT 0x00000308 -#define TEGRA186_ADMAIF_RX4_FIFO_CTRL_REG_DEFAULT 0x0000030c -#define TEGRA186_ADMAIF_RX5_FIFO_CTRL_REG_DEFAULT 0x00000210 -#define TEGRA186_ADMAIF_RX6_FIFO_CTRL_REG_DEFAULT 0x00000213 -#define TEGRA186_ADMAIF_RX7_FIFO_CTRL_REG_DEFAULT 0x00000216 -#define TEGRA186_ADMAIF_RX8_FIFO_CTRL_REG_DEFAULT 0x00000219 -#define TEGRA186_ADMAIF_RX9_FIFO_CTRL_REG_DEFAULT 0x0000021c -#define TEGRA186_ADMAIF_RX10_FIFO_CTRL_REG_DEFAULT 0x0000021f -#define TEGRA186_ADMAIF_RX11_FIFO_CTRL_REG_DEFAULT 0x00000222 -#define TEGRA186_ADMAIF_RX12_FIFO_CTRL_REG_DEFAULT 0x00000225 -#define TEGRA186_ADMAIF_RX13_FIFO_CTRL_REG_DEFAULT 0x00000228 -#define TEGRA186_ADMAIF_RX14_FIFO_CTRL_REG_DEFAULT 0x0000022b -#define TEGRA186_ADMAIF_RX15_FIFO_CTRL_REG_DEFAULT 0x0000022e -#define TEGRA186_ADMAIF_RX16_FIFO_CTRL_REG_DEFAULT 0x00000231 -#define TEGRA186_ADMAIF_RX17_FIFO_CTRL_REG_DEFAULT 0x00000234 -#define TEGRA186_ADMAIF_RX18_FIFO_CTRL_REG_DEFAULT 0x00000237 -#define TEGRA186_ADMAIF_RX19_FIFO_CTRL_REG_DEFAULT 0x0000023a -#define TEGRA186_ADMAIF_RX20_FIFO_CTRL_REG_DEFAULT 0x0000023d - -#define TEGRA186_ADMAIF_TX1_FIFO_CTRL_REG_DEFAULT 0x02000300 -#define TEGRA186_ADMAIF_TX2_FIFO_CTRL_REG_DEFAULT 0x02000304 -#define TEGRA186_ADMAIF_TX3_FIFO_CTRL_REG_DEFAULT 0x02000308 -#define TEGRA186_ADMAIF_TX4_FIFO_CTRL_REG_DEFAULT 0x0200030c -#define TEGRA186_ADMAIF_TX5_FIFO_CTRL_REG_DEFAULT 0x01800210 -#define TEGRA186_ADMAIF_TX6_FIFO_CTRL_REG_DEFAULT 0x01800213 -#define TEGRA186_ADMAIF_TX7_FIFO_CTRL_REG_DEFAULT 0x01800216 -#define TEGRA186_ADMAIF_TX8_FIFO_CTRL_REG_DEFAULT 0x01800219 -#define TEGRA186_ADMAIF_TX9_FIFO_CTRL_REG_DEFAULT 0x0180021c -#define TEGRA186_ADMAIF_TX10_FIFO_CTRL_REG_DEFAULT 0x0180021f -#define TEGRA186_ADMAIF_TX11_FIFO_CTRL_REG_DEFAULT 0x01800222 -#define TEGRA186_ADMAIF_TX12_FIFO_CTRL_REG_DEFAULT 0x01800225 -#define TEGRA186_ADMAIF_TX13_FIFO_CTRL_REG_DEFAULT 0x01800228 -#define TEGRA186_ADMAIF_TX14_FIFO_CTRL_REG_DEFAULT 0x0180022b -#define TEGRA186_ADMAIF_TX15_FIFO_CTRL_REG_DEFAULT 0x0180022e -#define TEGRA186_ADMAIF_TX16_FIFO_CTRL_REG_DEFAULT 0x01800231 -#define TEGRA186_ADMAIF_TX17_FIFO_CTRL_REG_DEFAULT 0x01800234 -#define TEGRA186_ADMAIF_TX18_FIFO_CTRL_REG_DEFAULT 0x01800237 -#define TEGRA186_ADMAIF_TX19_FIFO_CTRL_REG_DEFAULT 0x0180023a -#define TEGRA186_ADMAIF_TX20_FIFO_CTRL_REG_DEFAULT 0x0180023d +#define TEGRA_ADMAIF_CHANNEL_REG_STRIDE 0x40 +/* Tegra210 specific */ +#define TEGRA210_ADMAIF_LAST_REG 0x75f +#define TEGRA210_ADMAIF_CHANNEL_COUNT 10 +#define TEGRA210_ADMAIF_RX_BASE 0x0 +#define TEGRA210_ADMAIF_TX_BASE 0x300 +#define TEGRA210_ADMAIF_GLOBAL_BASE 0x700 +/* Tegra186 specific */ +#define TEGRA186_ADMAIF_LAST_REG 0xd5f +#define TEGRA186_ADMAIF_CHANNEL_COUNT 20 +#define TEGRA186_ADMAIF_RX_BASE 0x0 +#define TEGRA186_ADMAIF_TX_BASE 0x500 +#define TEGRA186_ADMAIF_GLOBAL_BASE 0xd00 +/* Global registers */ +#define TEGRA_ADMAIF_GLOBAL_ENABLE 0x0 +#define TEGRA_ADMAIF_GLOBAL_CG_0 0x8 +#define TEGRA_ADMAIF_GLOBAL_STATUS 0x10 +#define TEGRA_ADMAIF_GLOBAL_RX_ENABLE_STATUS 0x20 +#define TEGRA_ADMAIF_GLOBAL_TX_ENABLE_STATUS 0x24 +/* RX channel registers */ +#define TEGRA_ADMAIF_RX_ENABLE 0x0 +#define TEGRA_ADMAIF_RX_SOFT_RESET 0x4 +#define TEGRA_ADMAIF_RX_STATUS 0xc +#define TEGRA_ADMAIF_RX_INT_STATUS 0x10 +#define TEGRA_ADMAIF_RX_INT_MASK 0x14 +#define TEGRA_ADMAIF_RX_INT_SET 0x18 +#define TEGRA_ADMAIF_RX_INT_CLEAR 0x1c +#define TEGRA_ADMAIF_CH_ACIF_RX_CTRL 0x20 +#define TEGRA_ADMAIF_RX_FIFO_CTRL 0x28 +#define TEGRA_ADMAIF_RX_FIFO_READ 0x2c +/* TX channel registers */ +#define TEGRA_ADMAIF_TX_ENABLE 0x0 +#define TEGRA_ADMAIF_TX_SOFT_RESET 0x4 +#define TEGRA_ADMAIF_TX_STATUS 0xc +#define TEGRA_ADMAIF_TX_INT_STATUS 0x10 +#define TEGRA_ADMAIF_TX_INT_MASK 0x14 +#define TEGRA_ADMAIF_TX_INT_SET 0x18 +#define TEGRA_ADMAIF_TX_INT_CLEAR 0x1c +#define TEGRA_ADMAIF_CH_ACIF_TX_CTRL 0x20 +#define TEGRA_ADMAIF_TX_FIFO_CTRL 0x28 +#define TEGRA_ADMAIF_TX_FIFO_WRITE 0x2c +/* Bit fields */ +#define PACK8_EN_SHIFT 31 +#define PACK8_EN_MASK BIT(PACK8_EN_SHIFT) +#define PACK8_EN BIT(PACK8_EN_SHIFT) +#define PACK16_EN_SHIFT 30 +#define PACK16_EN_MASK BIT(PACK16_EN_SHIFT) +#define PACK16_EN BIT(PACK16_EN_SHIFT) +#define TX_ENABLE_SHIFT 0 +#define TX_ENABLE_MASK BIT(TX_ENABLE_SHIFT) +#define TX_ENABLE BIT(TX_ENABLE_SHIFT) +#define RX_ENABLE_SHIFT 0 +#define RX_ENABLE_MASK BIT(RX_ENABLE_SHIFT) +#define RX_ENABLE BIT(RX_ENABLE_SHIFT) +#define SW_RESET_MASK 1 +#define SW_RESET 1 +/* Default values - Tegra210 */ +#define TEGRA210_ADMAIF_RX1_FIFO_CTRL_REG_DEFAULT 0x00000300 +#define TEGRA210_ADMAIF_RX2_FIFO_CTRL_REG_DEFAULT 0x00000304 +#define TEGRA210_ADMAIF_RX3_FIFO_CTRL_REG_DEFAULT 0x00000208 +#define TEGRA210_ADMAIF_RX4_FIFO_CTRL_REG_DEFAULT 0x0000020b +#define TEGRA210_ADMAIF_RX5_FIFO_CTRL_REG_DEFAULT 0x0000020e +#define TEGRA210_ADMAIF_RX6_FIFO_CTRL_REG_DEFAULT 0x00000211 +#define TEGRA210_ADMAIF_RX7_FIFO_CTRL_REG_DEFAULT 0x00000214 +#define TEGRA210_ADMAIF_RX8_FIFO_CTRL_REG_DEFAULT 0x00000217 +#define TEGRA210_ADMAIF_RX9_FIFO_CTRL_REG_DEFAULT 0x0000021a +#define TEGRA210_ADMAIF_RX10_FIFO_CTRL_REG_DEFAULT 0x0000021d +#define TEGRA210_ADMAIF_TX1_FIFO_CTRL_REG_DEFAULT 0x02000300 +#define TEGRA210_ADMAIF_TX2_FIFO_CTRL_REG_DEFAULT 0x02000304 +#define TEGRA210_ADMAIF_TX3_FIFO_CTRL_REG_DEFAULT 0x01800208 +#define TEGRA210_ADMAIF_TX4_FIFO_CTRL_REG_DEFAULT 0x0180020b +#define TEGRA210_ADMAIF_TX5_FIFO_CTRL_REG_DEFAULT 0x0180020e +#define TEGRA210_ADMAIF_TX6_FIFO_CTRL_REG_DEFAULT 0x01800211 +#define TEGRA210_ADMAIF_TX7_FIFO_CTRL_REG_DEFAULT 0x01800214 +#define TEGRA210_ADMAIF_TX8_FIFO_CTRL_REG_DEFAULT 0x01800217 +#define TEGRA210_ADMAIF_TX9_FIFO_CTRL_REG_DEFAULT 0x0180021a +#define TEGRA210_ADMAIF_TX10_FIFO_CTRL_REG_DEFAULT 0x0180021d +/* Default values - Tegra186 */ +#define TEGRA186_ADMAIF_RX1_FIFO_CTRL_REG_DEFAULT 0x00000300 +#define TEGRA186_ADMAIF_RX2_FIFO_CTRL_REG_DEFAULT 0x00000304 +#define TEGRA186_ADMAIF_RX3_FIFO_CTRL_REG_DEFAULT 0x00000308 +#define TEGRA186_ADMAIF_RX4_FIFO_CTRL_REG_DEFAULT 0x0000030c +#define TEGRA186_ADMAIF_RX5_FIFO_CTRL_REG_DEFAULT 0x00000210 +#define TEGRA186_ADMAIF_RX6_FIFO_CTRL_REG_DEFAULT 0x00000213 +#define TEGRA186_ADMAIF_RX7_FIFO_CTRL_REG_DEFAULT 0x00000216 +#define TEGRA186_ADMAIF_RX8_FIFO_CTRL_REG_DEFAULT 0x00000219 +#define TEGRA186_ADMAIF_RX9_FIFO_CTRL_REG_DEFAULT 0x0000021c +#define TEGRA186_ADMAIF_RX10_FIFO_CTRL_REG_DEFAULT 0x0000021f +#define TEGRA186_ADMAIF_RX11_FIFO_CTRL_REG_DEFAULT 0x00000222 +#define TEGRA186_ADMAIF_RX12_FIFO_CTRL_REG_DEFAULT 0x00000225 +#define TEGRA186_ADMAIF_RX13_FIFO_CTRL_REG_DEFAULT 0x00000228 +#define TEGRA186_ADMAIF_RX14_FIFO_CTRL_REG_DEFAULT 0x0000022b +#define TEGRA186_ADMAIF_RX15_FIFO_CTRL_REG_DEFAULT 0x0000022e +#define TEGRA186_ADMAIF_RX16_FIFO_CTRL_REG_DEFAULT 0x00000231 +#define TEGRA186_ADMAIF_RX17_FIFO_CTRL_REG_DEFAULT 0x00000234 +#define TEGRA186_ADMAIF_RX18_FIFO_CTRL_REG_DEFAULT 0x00000237 +#define TEGRA186_ADMAIF_RX19_FIFO_CTRL_REG_DEFAULT 0x0000023a +#define TEGRA186_ADMAIF_RX20_FIFO_CTRL_REG_DEFAULT 0x0000023d +#define TEGRA186_ADMAIF_TX1_FIFO_CTRL_REG_DEFAULT 0x02000300 +#define TEGRA186_ADMAIF_TX2_FIFO_CTRL_REG_DEFAULT 0x02000304 +#define TEGRA186_ADMAIF_TX3_FIFO_CTRL_REG_DEFAULT 0x02000308 +#define TEGRA186_ADMAIF_TX4_FIFO_CTRL_REG_DEFAULT 0x0200030c +#define TEGRA186_ADMAIF_TX5_FIFO_CTRL_REG_DEFAULT 0x01800210 +#define TEGRA186_ADMAIF_TX6_FIFO_CTRL_REG_DEFAULT 0x01800213 +#define TEGRA186_ADMAIF_TX7_FIFO_CTRL_REG_DEFAULT 0x01800216 +#define TEGRA186_ADMAIF_TX8_FIFO_CTRL_REG_DEFAULT 0x01800219 +#define TEGRA186_ADMAIF_TX9_FIFO_CTRL_REG_DEFAULT 0x0180021c +#define TEGRA186_ADMAIF_TX10_FIFO_CTRL_REG_DEFAULT 0x0180021f +#define TEGRA186_ADMAIF_TX11_FIFO_CTRL_REG_DEFAULT 0x01800222 +#define TEGRA186_ADMAIF_TX12_FIFO_CTRL_REG_DEFAULT 0x01800225 +#define TEGRA186_ADMAIF_TX13_FIFO_CTRL_REG_DEFAULT 0x01800228 +#define TEGRA186_ADMAIF_TX14_FIFO_CTRL_REG_DEFAULT 0x0180022b +#define TEGRA186_ADMAIF_TX15_FIFO_CTRL_REG_DEFAULT 0x0180022e +#define TEGRA186_ADMAIF_TX16_FIFO_CTRL_REG_DEFAULT 0x01800231 +#define TEGRA186_ADMAIF_TX17_FIFO_CTRL_REG_DEFAULT 0x01800234 +#define TEGRA186_ADMAIF_TX18_FIFO_CTRL_REG_DEFAULT 0x01800237 +#define TEGRA186_ADMAIF_TX19_FIFO_CTRL_REG_DEFAULT 0x0180023a +#define TEGRA186_ADMAIF_TX20_FIFO_CTRL_REG_DEFAULT 0x0180023d enum { DATA_8BIT, @@ -165,31 +141,24 @@ enum { }; struct tegra_admaif_soc_data { - unsigned int num_ch; - struct snd_soc_dai_driver *codec_dais; - struct snd_soc_codec_driver *admaif_codec; + const struct snd_soc_component_driver *cmpnt; const struct regmap_config *regmap_conf; - bool is_isomgr_client; + struct snd_soc_dai_driver *dais; unsigned int global_base; unsigned int tx_base; unsigned int rx_base; + unsigned int num_ch; }; struct tegra_admaif { - /* regmap for admaif */ - struct regmap *regmap; - struct device *dev; - struct tegra_alt_pcm_dma_params *capture_dma_data; - struct tegra_alt_pcm_dma_params *playback_dma_data; + struct snd_dmaengine_dai_dma_data *capture_dma_data; + struct snd_dmaengine_dai_dma_data *playback_dma_data; const struct tegra_admaif_soc_data *soc_data; unsigned int *audio_ch_override[ADMAIF_PATHS]; unsigned int *client_ch_override[ADMAIF_PATHS]; unsigned int *mono_to_stereo[ADMAIF_PATHS]; unsigned int *stereo_to_mono[ADMAIF_PATHS]; - int reg_dump_flag; - void __iomem *base_addr; + struct regmap *regmap; }; -extern void tegra_adma_dump_ch_reg(void); - #endif diff --git a/sound/soc/tegra/tegra210_ahub.c b/sound/soc/tegra/tegra210_ahub.c new file mode 100644 index 00000000..e1358ea7 --- /dev/null +++ b/sound/soc/tegra/tegra210_ahub.c @@ -0,0 +1,651 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * tegra210_ahub.c - Tegra210 AHUB driver + * + * Copyright (c) 2020 NVIDIA CORPORATION. All rights reserved. + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include "tegra210_ahub.h" + +static int tegra_ahub_get_value_enum(struct snd_kcontrol *kctl, + struct snd_ctl_elem_value *uctl) +{ + struct snd_soc_component *cmpnt = snd_soc_dapm_kcontrol_component(kctl); + struct tegra_ahub *ahub = snd_soc_component_get_drvdata(cmpnt); + struct soc_enum *e = (struct soc_enum *)kctl->private_value; + unsigned int reg, i, bit_pos = 0; + + /* + * Find the bit position of current MUX input. + * If nothing is set, position would be 0 and it corresponds to 'None'. + */ + for (i = 0; i < ahub->soc_data->reg_count; i++) { + unsigned int reg_val; + + reg = e->reg + (TEGRA210_XBAR_PART1_RX * i); + snd_soc_component_read(cmpnt, reg, ®_val); + reg_val &= ahub->soc_data->mask[i]; + + if (reg_val) { + bit_pos = ffs(reg_val) + + (8 * cmpnt->val_bytes * i); + break; + } + } + + /* Find index related to the item in array *_ahub_mux_texts[] */ + for (i = 0; i < e->items; i++) { + if (bit_pos == e->values[i]) { + uctl->value.enumerated.item[0] = i; + break; + } + } + + return 0; +} + +static int tegra_ahub_put_value_enum(struct snd_kcontrol *kctl, + struct snd_ctl_elem_value *uctl) +{ + struct snd_soc_component *cmpnt = snd_soc_dapm_kcontrol_component(kctl); + struct tegra_ahub *ahub = snd_soc_component_get_drvdata(cmpnt); + struct snd_soc_dapm_context *dapm = snd_soc_dapm_kcontrol_dapm(kctl); + struct soc_enum *e = (struct soc_enum *)kctl->private_value; + struct snd_soc_dapm_update update[TEGRA_XBAR_UPDATE_MAX_REG] = { }; + unsigned int *item = uctl->value.enumerated.item; + unsigned int value = e->values[item[0]]; + unsigned int i, bit_pos, reg_idx = 0, reg_val = 0; + + if (item[0] >= e->items) + return -EINVAL; + + if (value) { + /* Get the register index and value to set */ + reg_idx = (value - 1) / (8 * cmpnt->val_bytes); + bit_pos = (value - 1) % (8 * cmpnt->val_bytes); + reg_val = BIT(bit_pos); + } + + /* + * Run through all parts of a MUX register to find the state changes. + * There will be an additional update if new MUX input value is from + * different part of the MUX register. + */ + for (i = 0; i < ahub->soc_data->reg_count; i++) { + update[i].reg = e->reg + (TEGRA210_XBAR_PART1_RX * i); + update[i].val = (i == reg_idx) ? reg_val : 0; + update[i].mask = ahub->soc_data->mask[i]; + update[i].kcontrol = kctl; + + /* Update widget power if state has changed */ + if (snd_soc_component_test_bits(cmpnt, update[i].reg, + update[i].mask, update[i].val)) + snd_soc_dapm_mux_update_power(dapm, kctl, item[0], e, + &update[i]); + } + + return 0; +} + +static struct snd_soc_dai_driver tegra210_ahub_dais[] = { + DAI(ADMAIF1), + DAI(ADMAIF2), + DAI(ADMAIF3), + DAI(ADMAIF4), + DAI(ADMAIF5), + DAI(ADMAIF6), + DAI(ADMAIF7), + DAI(ADMAIF8), + DAI(ADMAIF9), + DAI(ADMAIF10), + DAI(I2S1), + DAI(I2S2), + DAI(I2S3), + DAI(I2S4), + DAI(I2S5), + DAI(DMIC1), + DAI(DMIC2), + DAI(DMIC3), +}; + +static struct snd_soc_dai_driver tegra186_ahub_dais[] = { + DAI(ADMAIF1), + DAI(ADMAIF2), + DAI(ADMAIF3), + DAI(ADMAIF4), + DAI(ADMAIF5), + DAI(ADMAIF6), + DAI(ADMAIF7), + DAI(ADMAIF8), + DAI(ADMAIF9), + DAI(ADMAIF10), + DAI(ADMAIF11), + DAI(ADMAIF12), + DAI(ADMAIF13), + DAI(ADMAIF14), + DAI(ADMAIF15), + DAI(ADMAIF16), + DAI(ADMAIF17), + DAI(ADMAIF18), + DAI(ADMAIF19), + DAI(ADMAIF20), + DAI(I2S1), + DAI(I2S2), + DAI(I2S3), + DAI(I2S4), + DAI(I2S5), + DAI(I2S6), + DAI(DMIC1), + DAI(DMIC2), + DAI(DMIC3), + DAI(DMIC4), + DAI(DSPK1), + DAI(DSPK2), +}; + +static const char * const tegra210_ahub_mux_texts[] = { + "None", + "ADMAIF1", + "ADMAIF2", + "ADMAIF3", + "ADMAIF4", + "ADMAIF5", + "ADMAIF6", + "ADMAIF7", + "ADMAIF8", + "ADMAIF9", + "ADMAIF10", + "I2S1", + "I2S2", + "I2S3", + "I2S4", + "I2S5", + "DMIC1", + "DMIC2", + "DMIC3", +}; + +static const char * const tegra186_ahub_mux_texts[] = { + "None", + "ADMAIF1", + "ADMAIF2", + "ADMAIF3", + "ADMAIF4", + "ADMAIF5", + "ADMAIF6", + "ADMAIF7", + "ADMAIF8", + "ADMAIF9", + "ADMAIF10", + "ADMAIF11", + "ADMAIF12", + "ADMAIF13", + "ADMAIF14", + "ADMAIF15", + "ADMAIF16", + "I2S1", + "I2S2", + "I2S3", + "I2S4", + "I2S5", + "I2S6", + "ADMAIF17", + "ADMAIF18", + "ADMAIF19", + "ADMAIF20", + "DMIC1", + "DMIC2", + "DMIC3", + "DMIC4", +}; + +static const unsigned int tegra210_ahub_mux_values[] = { + 0, + MUX_VALUE(0, 0), + MUX_VALUE(0, 1), + MUX_VALUE(0, 2), + MUX_VALUE(0, 3), + MUX_VALUE(0, 4), + MUX_VALUE(0, 5), + MUX_VALUE(0, 6), + MUX_VALUE(0, 7), + MUX_VALUE(0, 8), + MUX_VALUE(0, 9), + MUX_VALUE(0, 16), + MUX_VALUE(0, 17), + MUX_VALUE(0, 18), + MUX_VALUE(0, 19), + MUX_VALUE(0, 20), +}; + +static const unsigned int tegra186_ahub_mux_values[] = { + 0, + MUX_VALUE(0, 0), + MUX_VALUE(0, 1), + MUX_VALUE(0, 2), + MUX_VALUE(0, 3), + MUX_VALUE(0, 4), + MUX_VALUE(0, 5), + MUX_VALUE(0, 6), + MUX_VALUE(0, 7), + MUX_VALUE(0, 8), + MUX_VALUE(0, 9), + MUX_VALUE(0, 10), + MUX_VALUE(0, 11), + MUX_VALUE(0, 12), + MUX_VALUE(0, 13), + MUX_VALUE(0, 14), + MUX_VALUE(0, 15), + MUX_VALUE(0, 16), + MUX_VALUE(0, 17), + MUX_VALUE(0, 18), + MUX_VALUE(0, 19), + MUX_VALUE(0, 20), + MUX_VALUE(0, 21), + MUX_VALUE(3, 16), + MUX_VALUE(3, 17), + MUX_VALUE(3, 18), + MUX_VALUE(3, 19), + MUX_VALUE(2, 18), + MUX_VALUE(2, 19), + MUX_VALUE(2, 20), + MUX_VALUE(2, 21), +}; + +/* Controls for t210 */ +MUX_ENUM_CTRL_DECL(t210_admaif1_tx, 0x00); +MUX_ENUM_CTRL_DECL(t210_admaif2_tx, 0x01); +MUX_ENUM_CTRL_DECL(t210_admaif3_tx, 0x02); +MUX_ENUM_CTRL_DECL(t210_admaif4_tx, 0x03); +MUX_ENUM_CTRL_DECL(t210_admaif5_tx, 0x04); +MUX_ENUM_CTRL_DECL(t210_admaif6_tx, 0x05); +MUX_ENUM_CTRL_DECL(t210_admaif7_tx, 0x06); +MUX_ENUM_CTRL_DECL(t210_admaif8_tx, 0x07); +MUX_ENUM_CTRL_DECL(t210_admaif9_tx, 0x08); +MUX_ENUM_CTRL_DECL(t210_admaif10_tx, 0x09); +MUX_ENUM_CTRL_DECL(t210_i2s1_tx, 0x10); +MUX_ENUM_CTRL_DECL(t210_i2s2_tx, 0x11); +MUX_ENUM_CTRL_DECL(t210_i2s3_tx, 0x12); +MUX_ENUM_CTRL_DECL(t210_i2s4_tx, 0x13); +MUX_ENUM_CTRL_DECL(t210_i2s5_tx, 0x14); + +/* Controls for t186 */ +MUX_ENUM_CTRL_DECL_186(t186_admaif1_tx, 0x00); +MUX_ENUM_CTRL_DECL_186(t186_admaif2_tx, 0x01); +MUX_ENUM_CTRL_DECL_186(t186_admaif3_tx, 0x02); +MUX_ENUM_CTRL_DECL_186(t186_admaif4_tx, 0x03); +MUX_ENUM_CTRL_DECL_186(t186_admaif5_tx, 0x04); +MUX_ENUM_CTRL_DECL_186(t186_admaif6_tx, 0x05); +MUX_ENUM_CTRL_DECL_186(t186_admaif7_tx, 0x06); +MUX_ENUM_CTRL_DECL_186(t186_admaif8_tx, 0x07); +MUX_ENUM_CTRL_DECL_186(t186_admaif9_tx, 0x08); +MUX_ENUM_CTRL_DECL_186(t186_admaif10_tx, 0x09); +MUX_ENUM_CTRL_DECL_186(t186_i2s1_tx, 0x10); +MUX_ENUM_CTRL_DECL_186(t186_i2s2_tx, 0x11); +MUX_ENUM_CTRL_DECL_186(t186_i2s3_tx, 0x12); +MUX_ENUM_CTRL_DECL_186(t186_i2s4_tx, 0x13); +MUX_ENUM_CTRL_DECL_186(t186_i2s5_tx, 0x14); +MUX_ENUM_CTRL_DECL_186(t186_admaif11_tx, 0x0a); +MUX_ENUM_CTRL_DECL_186(t186_admaif12_tx, 0x0b); +MUX_ENUM_CTRL_DECL_186(t186_admaif13_tx, 0x0c); +MUX_ENUM_CTRL_DECL_186(t186_admaif14_tx, 0x0d); +MUX_ENUM_CTRL_DECL_186(t186_admaif15_tx, 0x0e); +MUX_ENUM_CTRL_DECL_186(t186_admaif16_tx, 0x0f); +MUX_ENUM_CTRL_DECL_186(t186_i2s6_tx, 0x15); +MUX_ENUM_CTRL_DECL_186(t186_dspk1_tx, 0x30); +MUX_ENUM_CTRL_DECL_186(t186_dspk2_tx, 0x31); +MUX_ENUM_CTRL_DECL_186(t186_admaif17_tx, 0x68); +MUX_ENUM_CTRL_DECL_186(t186_admaif18_tx, 0x69); +MUX_ENUM_CTRL_DECL_186(t186_admaif19_tx, 0x6a); +MUX_ENUM_CTRL_DECL_186(t186_admaif20_tx, 0x6b); + +/* + * The number of entries in, and order of, this array is closely tied to the + * calculation of tegra210_ahub_codec.num_dapm_widgets near the end of + * tegra210_ahub_probe() + */ +static const struct snd_soc_dapm_widget tegra210_ahub_widgets[] = { + WIDGETS("ADMAIF1", t210_admaif1_tx), + WIDGETS("ADMAIF2", t210_admaif2_tx), + WIDGETS("ADMAIF3", t210_admaif3_tx), + WIDGETS("ADMAIF4", t210_admaif4_tx), + WIDGETS("ADMAIF5", t210_admaif5_tx), + WIDGETS("ADMAIF6", t210_admaif6_tx), + WIDGETS("ADMAIF7", t210_admaif7_tx), + WIDGETS("ADMAIF8", t210_admaif8_tx), + WIDGETS("ADMAIF9", t210_admaif9_tx), + WIDGETS("ADMAIF10", t210_admaif10_tx), + WIDGETS("I2S1", t210_i2s1_tx), + WIDGETS("I2S2", t210_i2s2_tx), + WIDGETS("I2S3", t210_i2s3_tx), + WIDGETS("I2S4", t210_i2s4_tx), + WIDGETS("I2S5", t210_i2s5_tx), + TX_WIDGETS("DMIC1"), + TX_WIDGETS("DMIC2"), + TX_WIDGETS("DMIC3"), +}; + +static const struct snd_soc_dapm_widget tegra186_ahub_widgets[] = { + WIDGETS("ADMAIF1", t186_admaif1_tx), + WIDGETS("ADMAIF2", t186_admaif2_tx), + WIDGETS("ADMAIF3", t186_admaif3_tx), + WIDGETS("ADMAIF4", t186_admaif4_tx), + WIDGETS("ADMAIF5", t186_admaif5_tx), + WIDGETS("ADMAIF6", t186_admaif6_tx), + WIDGETS("ADMAIF7", t186_admaif7_tx), + WIDGETS("ADMAIF8", t186_admaif8_tx), + WIDGETS("ADMAIF9", t186_admaif9_tx), + WIDGETS("ADMAIF10", t186_admaif10_tx), + WIDGETS("ADMAIF11", t186_admaif11_tx), + WIDGETS("ADMAIF12", t186_admaif12_tx), + WIDGETS("ADMAIF13", t186_admaif13_tx), + WIDGETS("ADMAIF14", t186_admaif14_tx), + WIDGETS("ADMAIF15", t186_admaif15_tx), + WIDGETS("ADMAIF16", t186_admaif16_tx), + WIDGETS("ADMAIF17", t186_admaif17_tx), + WIDGETS("ADMAIF18", t186_admaif18_tx), + WIDGETS("ADMAIF19", t186_admaif19_tx), + WIDGETS("ADMAIF20", t186_admaif20_tx), + WIDGETS("I2S1", t186_i2s1_tx), + WIDGETS("I2S2", t186_i2s2_tx), + WIDGETS("I2S3", t186_i2s3_tx), + WIDGETS("I2S4", t186_i2s4_tx), + WIDGETS("I2S5", t186_i2s5_tx), + WIDGETS("I2S6", t186_i2s6_tx), + TX_WIDGETS("DMIC1"), + TX_WIDGETS("DMIC2"), + TX_WIDGETS("DMIC3"), + TX_WIDGETS("DMIC4"), + WIDGETS("DSPK1", t186_dspk1_tx), + WIDGETS("DSPK2", t186_dspk2_tx), +}; + +#define TEGRA_COMMON_ROUTES(name) \ + { name " RX", NULL, name " Receive" }, \ + { name " Transmit", NULL, name " TX" }, \ + { name " TX", NULL, name " Mux" }, \ + { name " Mux", "ADMAIF1", "ADMAIF1 RX" }, \ + { name " Mux", "ADMAIF2", "ADMAIF2 RX" }, \ + { name " Mux", "ADMAIF3", "ADMAIF3 RX" }, \ + { name " Mux", "ADMAIF4", "ADMAIF4 RX" }, \ + { name " Mux", "ADMAIF5", "ADMAIF5 RX" }, \ + { name " Mux", "ADMAIF6", "ADMAIF6 RX" }, \ + { name " Mux", "ADMAIF7", "ADMAIF7 RX" }, \ + { name " Mux", "ADMAIF8", "ADMAIF8 RX" }, \ + { name " Mux", "ADMAIF9", "ADMAIF9 RX" }, \ + { name " Mux", "ADMAIF10", "ADMAIF10 RX" }, \ + { name " Mux", "I2S1", "I2S1 RX" }, \ + { name " Mux", "I2S2", "I2S2 RX" }, \ + { name " Mux", "I2S3", "I2S3 RX" }, \ + { name " Mux", "I2S4", "I2S4 RX" }, \ + { name " Mux", "I2S5", "I2S5 RX" }, \ + { name " Mux", "DMIC1", "DMIC1 RX" }, \ + { name " Mux", "DMIC2", "DMIC2 RX" }, \ + { name " Mux", "DMIC3", "DMIC3 RX" }, + +#define TEGRA186_ONLY_ROUTES(name) \ + { name " Mux", "ADMAIF11", "ADMAIF11 RX" }, \ + { name " Mux", "ADMAIF12", "ADMAIF12 RX" }, \ + { name " Mux", "ADMAIF13", "ADMAIF13 RX" }, \ + { name " Mux", "ADMAIF14", "ADMAIF14 RX" }, \ + { name " Mux", "ADMAIF15", "ADMAIF15 RX" }, \ + { name " Mux", "ADMAIF16", "ADMAIF16 RX" }, \ + { name " Mux", "ADMAIF17", "ADMAIF17 RX" }, \ + { name " Mux", "ADMAIF18", "ADMAIF18 RX" }, \ + { name " Mux", "ADMAIF19", "ADMAIF19 RX" }, \ + { name " Mux", "ADMAIF20", "ADMAIF20 RX" }, \ + { name " Mux", "I2S6", "I2S6 RX" }, \ + { name " Mux", "DMIC4", "DMIC4 RX" }, + +#define TEGRA210_ROUTES(name) \ + TEGRA_COMMON_ROUTES(name) + +#define TEGRA186_ROUTES(name) \ + TEGRA_COMMON_ROUTES(name) \ + TEGRA186_ONLY_ROUTES(name) + +#define IN_OUT_ROUTES(name) \ + { name " RX", NULL, name " Receive" }, \ + { name " Transmit", NULL, name " TX" }, + +/* + * The number of entries in, and order of, this array is closely tied to the + * calculation of tegra210_ahub_codec.num_dapm_routes near the end of + * tegra210_ahub_probe() + */ +static const struct snd_soc_dapm_route tegra210_ahub_routes[] = { + TEGRA210_ROUTES("ADMAIF1") + TEGRA210_ROUTES("ADMAIF2") + TEGRA210_ROUTES("ADMAIF3") + TEGRA210_ROUTES("ADMAIF4") + TEGRA210_ROUTES("ADMAIF5") + TEGRA210_ROUTES("ADMAIF6") + TEGRA210_ROUTES("ADMAIF7") + TEGRA210_ROUTES("ADMAIF8") + TEGRA210_ROUTES("ADMAIF9") + TEGRA210_ROUTES("ADMAIF10") + TEGRA210_ROUTES("I2S1") + TEGRA210_ROUTES("I2S2") + TEGRA210_ROUTES("I2S3") + TEGRA210_ROUTES("I2S4") + TEGRA210_ROUTES("I2S5") + IN_OUT_ROUTES("DMIC1") + IN_OUT_ROUTES("DMIC2") + IN_OUT_ROUTES("DMIC3") +}; + +static const struct snd_soc_dapm_route tegra186_ahub_routes[] = { + TEGRA186_ROUTES("ADMAIF1") + TEGRA186_ROUTES("ADMAIF2") + TEGRA186_ROUTES("ADMAIF3") + TEGRA186_ROUTES("ADMAIF4") + TEGRA186_ROUTES("ADMAIF5") + TEGRA186_ROUTES("ADMAIF6") + TEGRA186_ROUTES("ADMAIF7") + TEGRA186_ROUTES("ADMAIF8") + TEGRA186_ROUTES("ADMAIF9") + TEGRA186_ROUTES("ADMAIF10") + TEGRA186_ROUTES("ADMAIF11") + TEGRA186_ROUTES("ADMAIF12") + TEGRA186_ROUTES("ADMAIF13") + TEGRA186_ROUTES("ADMAIF14") + TEGRA186_ROUTES("ADMAIF15") + TEGRA186_ROUTES("ADMAIF16") + TEGRA186_ROUTES("ADMAIF17") + TEGRA186_ROUTES("ADMAIF18") + TEGRA186_ROUTES("ADMAIF19") + TEGRA186_ROUTES("ADMAIF20") + TEGRA186_ROUTES("I2S1") + TEGRA186_ROUTES("I2S2") + TEGRA186_ROUTES("I2S3") + TEGRA186_ROUTES("I2S4") + TEGRA186_ROUTES("I2S5") + TEGRA186_ROUTES("I2S6") + TEGRA186_ROUTES("DSPK1") + TEGRA186_ROUTES("DSPK2") + IN_OUT_ROUTES("DMIC1") + IN_OUT_ROUTES("DMIC2") + IN_OUT_ROUTES("DMIC3") + IN_OUT_ROUTES("DMIC4") +}; + +static const struct snd_soc_component_driver tegra210_ahub_component = { + .dapm_widgets = tegra210_ahub_widgets, + .num_dapm_widgets = ARRAY_SIZE(tegra210_ahub_widgets), + .dapm_routes = tegra210_ahub_routes, + .num_dapm_routes = ARRAY_SIZE(tegra210_ahub_routes), +}; + +static const struct snd_soc_component_driver tegra186_ahub_component = { + .dapm_widgets = tegra186_ahub_widgets, + .num_dapm_widgets = ARRAY_SIZE(tegra186_ahub_widgets), + .dapm_routes = tegra186_ahub_routes, + .num_dapm_routes = ARRAY_SIZE(tegra186_ahub_routes), +}; + +static const struct regmap_config tegra210_ahub_regmap_config = { + .reg_bits = 32, + .val_bits = 32, + .reg_stride = 4, + .max_register = TEGRA210_MAX_REGISTER_ADDR, + .cache_type = REGCACHE_FLAT, +}; + +static const struct regmap_config tegra186_ahub_regmap_config = { + .reg_bits = 32, + .val_bits = 32, + .reg_stride = 4, + .max_register = TEGRA186_MAX_REGISTER_ADDR, + .cache_type = REGCACHE_FLAT, +}; + +static const struct tegra_ahub_soc_data soc_data_tegra210 = { + .cmpnt_drv = &tegra210_ahub_component, + .dai_drv = tegra210_ahub_dais, + .num_dais = ARRAY_SIZE(tegra210_ahub_dais), + .regmap_config = &tegra210_ahub_regmap_config, + .mask[0] = TEGRA210_XBAR_REG_MASK_0, + .mask[1] = TEGRA210_XBAR_REG_MASK_1, + .mask[2] = TEGRA210_XBAR_REG_MASK_2, + .mask[3] = TEGRA210_XBAR_REG_MASK_3, + .reg_count = TEGRA210_XBAR_UPDATE_MAX_REG, +}; + +static const struct tegra_ahub_soc_data soc_data_tegra186 = { + .cmpnt_drv = &tegra186_ahub_component, + .dai_drv = tegra186_ahub_dais, + .num_dais = ARRAY_SIZE(tegra186_ahub_dais), + .regmap_config = &tegra186_ahub_regmap_config, + .mask[0] = TEGRA186_XBAR_REG_MASK_0, + .mask[1] = TEGRA186_XBAR_REG_MASK_1, + .mask[2] = TEGRA186_XBAR_REG_MASK_2, + .mask[3] = TEGRA186_XBAR_REG_MASK_3, + .reg_count = TEGRA186_XBAR_UPDATE_MAX_REG, +}; + +static const struct of_device_id tegra_ahub_of_match[] = { + { .compatible = "nvidia,tegra210-ahub", .data = &soc_data_tegra210 }, + { .compatible = "nvidia,tegra186-ahub", .data = &soc_data_tegra186 }, + {}, +}; +MODULE_DEVICE_TABLE(of, tegra_ahub_of_match); + +static int tegra_ahub_runtime_suspend(struct device *dev) +{ + struct tegra_ahub *ahub = dev_get_drvdata(dev); + + regcache_cache_only(ahub->regmap, true); + regcache_mark_dirty(ahub->regmap); + + clk_disable_unprepare(ahub->clk); + + return 0; +} + +static int tegra_ahub_runtime_resume(struct device *dev) +{ + struct tegra_ahub *ahub = dev_get_drvdata(dev); + int err; + + err = clk_prepare_enable(ahub->clk); + if (err) { + dev_err(dev, "failed to enable AHUB clock, err: %d\n", err); + return err; + } + + regcache_cache_only(ahub->regmap, false); + regcache_sync(ahub->regmap); + + return 0; +} + +static int tegra_ahub_probe(struct platform_device *pdev) +{ + struct tegra_ahub *ahub; + void __iomem *regs; + int err; + + ahub = devm_kzalloc(&pdev->dev, sizeof(*ahub), GFP_KERNEL); + if (!ahub) + return -ENOMEM; + + ahub->soc_data = of_device_get_match_data(&pdev->dev); + + platform_set_drvdata(pdev, ahub); + + ahub->clk = devm_clk_get(&pdev->dev, "ahub"); + if (IS_ERR(ahub->clk)) { + dev_err(&pdev->dev, "can't retrieve AHUB clock\n"); + return PTR_ERR(ahub->clk); + } + + regs = devm_platform_ioremap_resource(pdev, 0); + if (IS_ERR(regs)) + return PTR_ERR(regs); + + ahub->regmap = devm_regmap_init_mmio(&pdev->dev, regs, + ahub->soc_data->regmap_config); + if (IS_ERR(ahub->regmap)) { + dev_err(&pdev->dev, "regmap init failed\n"); + return PTR_ERR(ahub->regmap); + } + + regcache_cache_only(ahub->regmap, true); + + err = devm_snd_soc_register_component(&pdev->dev, + ahub->soc_data->cmpnt_drv, + ahub->soc_data->dai_drv, + ahub->soc_data->num_dais); + if (err) { + dev_err(&pdev->dev, "can't register AHUB component, err: %d\n", + err); + return err; + } + + err = of_platform_populate(pdev->dev.of_node, NULL, NULL, &pdev->dev); + if (err) + return err; + + pm_runtime_enable(&pdev->dev); + + return 0; +} + +static int tegra_ahub_remove(struct platform_device *pdev) +{ + pm_runtime_disable(&pdev->dev); + + return 0; +} + +static const struct dev_pm_ops tegra_ahub_pm_ops = { + SET_RUNTIME_PM_OPS(tegra_ahub_runtime_suspend, + tegra_ahub_runtime_resume, NULL) + SET_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend, + pm_runtime_force_resume) +}; + +static struct platform_driver tegra_ahub_driver = { + .probe = tegra_ahub_probe, + .remove = tegra_ahub_remove, + .driver = { + .name = "tegra210-ahub", + .of_match_table = tegra_ahub_of_match, + .pm = &tegra_ahub_pm_ops, + }, +}; +module_platform_driver(tegra_ahub_driver); + +MODULE_AUTHOR("Stephen Warren "); +MODULE_AUTHOR("Mohan Kumar "); +MODULE_DESCRIPTION("Tegra210 ASoC AHUB driver"); +MODULE_LICENSE("GPL v2"); diff --git a/sound/soc/tegra/tegra210_ahub.h b/sound/soc/tegra/tegra210_ahub.h new file mode 100644 index 00000000..d0fb35ca --- /dev/null +++ b/sound/soc/tegra/tegra210_ahub.h @@ -0,0 +1,125 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * tegra210_ahub.h - TEGRA210 AHUB + * + * Copyright (c) 2020 NVIDIA CORPORATION. All rights reserved. + * + */ + +#ifndef __TEGRA210_AHUB__H__ +#define __TEGRA210_AHUB__H__ + +/* Tegra210 specific */ +#define TEGRA210_XBAR_PART1_RX 0x200 +#define TEGRA210_XBAR_PART2_RX 0x400 +#define TEGRA210_XBAR_RX_STRIDE 0x4 +#define TEGRA210_XBAR_AUDIO_RX_COUNT 90 +#define TEGRA210_XBAR_REG_MASK_0 0xf1f03ff +#define TEGRA210_XBAR_REG_MASK_1 0x3f30031f +#define TEGRA210_XBAR_REG_MASK_2 0xff1cf313 +#define TEGRA210_XBAR_REG_MASK_3 0x0 +#define TEGRA210_XBAR_UPDATE_MAX_REG 3 +/* Tegra186 specific */ +#define TEGRA186_XBAR_PART3_RX 0x600 +#define TEGRA186_XBAR_AUDIO_RX_COUNT 115 +#define TEGRA186_XBAR_REG_MASK_0 0xf3fffff +#define TEGRA186_XBAR_REG_MASK_1 0x3f310f1f +#define TEGRA186_XBAR_REG_MASK_2 0xff3cf311 +#define TEGRA186_XBAR_REG_MASK_3 0x3f0f00ff +#define TEGRA186_XBAR_UPDATE_MAX_REG 4 + +#define TEGRA_XBAR_UPDATE_MAX_REG (TEGRA186_XBAR_UPDATE_MAX_REG) + +#define TEGRA186_MAX_REGISTER_ADDR (TEGRA186_XBAR_PART3_RX + \ + (TEGRA210_XBAR_RX_STRIDE * (TEGRA186_XBAR_AUDIO_RX_COUNT - 1))) + +#define TEGRA210_MAX_REGISTER_ADDR (TEGRA210_XBAR_PART2_RX + \ + (TEGRA210_XBAR_RX_STRIDE * (TEGRA210_XBAR_AUDIO_RX_COUNT - 1))) + +#define MUX_REG(id) (TEGRA210_XBAR_RX_STRIDE * (id)) + +#define MUX_VALUE(npart, nbit) (1 + (nbit) + (npart) * 32) + +#define DAI(sname) \ + { \ + .name = #sname, \ + .playback = { \ + .stream_name = #sname " Receive", \ + .channels_min = 1, \ + .channels_max = 16, \ + .rates = SNDRV_PCM_RATE_8000_192000, \ + .formats = SNDRV_PCM_FMTBIT_S8 | \ + SNDRV_PCM_FMTBIT_S16_LE | \ + SNDRV_PCM_FMTBIT_S32_LE, \ + }, \ + .capture = { \ + .stream_name = #sname " Transmit", \ + .channels_min = 1, \ + .channels_max = 16, \ + .rates = SNDRV_PCM_RATE_8000_192000, \ + .formats = SNDRV_PCM_FMTBIT_S8 | \ + SNDRV_PCM_FMTBIT_S16_LE | \ + SNDRV_PCM_FMTBIT_S32_LE, \ + }, \ + } + +#define SOC_VALUE_ENUM_WIDE(xreg, shift, xmax, xtexts, xvalues) \ + { \ + .reg = xreg, \ + .shift_l = shift, \ + .shift_r = shift, \ + .items = xmax, \ + .texts = xtexts, \ + .values = xvalues, \ + .mask = xmax ? roundup_pow_of_two(xmax) - 1 : 0 \ + } + +#define SOC_VALUE_ENUM_WIDE_DECL(name, xreg, shift, xtexts, xvalues) \ + static struct soc_enum name = \ + SOC_VALUE_ENUM_WIDE(xreg, shift, ARRAY_SIZE(xtexts), \ + xtexts, xvalues) + +#define MUX_ENUM_CTRL_DECL(ename, id) \ + SOC_VALUE_ENUM_WIDE_DECL(ename##_enum, MUX_REG(id), 0, \ + tegra210_ahub_mux_texts, \ + tegra210_ahub_mux_values); \ + static const struct snd_kcontrol_new ename##_control = \ + SOC_DAPM_ENUM_EXT("Route", ename##_enum, \ + tegra_ahub_get_value_enum, \ + tegra_ahub_put_value_enum) + +#define MUX_ENUM_CTRL_DECL_186(ename, id) \ + SOC_VALUE_ENUM_WIDE_DECL(ename##_enum, MUX_REG(id), 0, \ + tegra186_ahub_mux_texts, \ + tegra186_ahub_mux_values); \ + static const struct snd_kcontrol_new ename##_control = \ + SOC_DAPM_ENUM_EXT("Route", ename##_enum, \ + tegra_ahub_get_value_enum, \ + tegra_ahub_put_value_enum) + +#define WIDGETS(sname, ename) \ + SND_SOC_DAPM_AIF_IN(sname " RX", NULL, 0, SND_SOC_NOPM, 0, 0), \ + SND_SOC_DAPM_AIF_OUT(sname " TX", NULL, 0, SND_SOC_NOPM, 0, 0), \ + SND_SOC_DAPM_MUX(sname " Mux", SND_SOC_NOPM, 0, 0, \ + &ename##_control) + +#define TX_WIDGETS(sname) \ + SND_SOC_DAPM_AIF_IN(sname " RX", NULL, 0, SND_SOC_NOPM, 0, 0), \ + SND_SOC_DAPM_AIF_OUT(sname " TX", NULL, 0, SND_SOC_NOPM, 0, 0) + +struct tegra_ahub_soc_data { + const struct regmap_config *regmap_config; + const struct snd_soc_component_driver *cmpnt_drv; + struct snd_soc_dai_driver *dai_drv; + unsigned int mask[4]; + unsigned int reg_count; + unsigned int num_dais; +}; + +struct tegra_ahub { + const struct tegra_ahub_soc_data *soc_data; + struct regmap *regmap; + struct clk *clk; +}; + +#endif diff --git a/sound/soc/tegra/tegra210_dmic.c b/sound/soc/tegra/tegra210_dmic.c index 11469c38..f7a217a4 100644 --- a/sound/soc/tegra/tegra210_dmic.c +++ b/sound/soc/tegra/tegra210_dmic.c @@ -1,70 +1,43 @@ +// SPDX-License-Identifier: GPL-2.0-only /* - * tegra210_dmic_alt.c - Tegra210 DMIC driver + * tegra210_dmic.c - Tegra210 DMIC driver * - * Copyright (c) 2014-2019 NVIDIA CORPORATION. All rights reserved. + * Copyright (c) 2020 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 - -#include "tegra210_xbar_alt.h" -#include "tegra210_dmic_alt.h" -#include "ahub_unit_fpga_clock.h" - -#define DRV_NAME "tegra210-dmic" +#include "tegra210_dmic.h" +#include "tegra_cif.h" static const struct reg_default tegra210_dmic_reg_defaults[] = { - { TEGRA210_DMIC_TX_INT_MASK, 0x00000001}, - { TEGRA210_DMIC_TX_CIF_CTRL, 0x00007700}, - { TEGRA210_DMIC_CG, 0x1}, - { TEGRA210_DMIC_CTRL, 0x00000301}, - { TEGRA210_DMIC_DCR_FILTER_GAIN, 0x00800000}, - { TEGRA210_DMIC_DCR_BIQUAD_0_COEF_0, 0x00800000}, - { TEGRA210_DMIC_DCR_BIQUAD_0_COEF_1, 0xff800000}, - { TEGRA210_DMIC_DCR_BIQUAD_0_COEF_3, 0xff800347}, - { TEGRA210_DMIC_DCR_BIQUAD_0_COEF_4, 0xffc0ff97}, - { TEGRA210_DMIC_LP_FILTER_GAIN, 0x004c255a}, - { TEGRA210_DMIC_LP_BIQUAD_0_COEF_0, 0x00800000}, - { TEGRA210_DMIC_LP_BIQUAD_0_COEF_1, 0x00ffa74b}, - { TEGRA210_DMIC_LP_BIQUAD_0_COEF_2, 0x00800000}, - { TEGRA210_DMIC_LP_BIQUAD_0_COEF_3, 0x009e382a}, - { TEGRA210_DMIC_LP_BIQUAD_0_COEF_4, 0x00380f38}, - { TEGRA210_DMIC_LP_BIQUAD_1_COEF_0, 0x00800000}, - { TEGRA210_DMIC_LP_BIQUAD_1_COEF_1, 0x00fe1178}, - { TEGRA210_DMIC_LP_BIQUAD_1_COEF_2, 0x00800000}, - { TEGRA210_DMIC_LP_BIQUAD_1_COEF_3, 0x00e05f02}, - { TEGRA210_DMIC_LP_BIQUAD_1_COEF_4, 0x006fc80d}, - { TEGRA210_DMIC_CORRECTION_FILTER_GAIN, 0x010628f6}, - { TEGRA210_DMIC_CORRECTION_BIQUAD_0_COEF_0, 0x00800000}, - { TEGRA210_DMIC_CORRECTION_BIQUAD_0_COEF_3, 0x0067ffff}, - { TEGRA210_DMIC_CORRECTION_BIQUAD_1_COEF_0, 0x00800000}, - { TEGRA210_DMIC_CORRECTION_BIQUAD_1_COEF_1, 0x0048f5c2}, - { TEGRA210_DMIC_CORRECTION_BIQUAD_1_COEF_3, 0x00562394}, - { TEGRA210_DMIC_CORRECTION_BIQUAD_1_COEF_4, 0x00169446}, + { TEGRA210_DMIC_TX_INT_MASK, 0x00000001 }, + { TEGRA210_DMIC_TX_CIF_CTRL, 0x00007700 }, + { TEGRA210_DMIC_CG, 0x1 }, + { TEGRA210_DMIC_CTRL, 0x00000301 }, + /* Below enables all filters - DCR, LP and SC */ + { TEGRA210_DMIC_DBG_CTRL, 0xe }, + /* Below as per latest POR value */ + { TEGRA210_DMIC_DCR_BIQUAD_0_COEF_4, 0x0 }, + /* LP filter is configured for pass through and used to apply gain */ + { TEGRA210_DMIC_LP_BIQUAD_0_COEF_0, 0x00800000 }, + { TEGRA210_DMIC_LP_BIQUAD_0_COEF_1, 0x0 }, + { TEGRA210_DMIC_LP_BIQUAD_0_COEF_2, 0x0 }, + { TEGRA210_DMIC_LP_BIQUAD_0_COEF_3, 0x0 }, + { TEGRA210_DMIC_LP_BIQUAD_0_COEF_4, 0x0 }, + { TEGRA210_DMIC_LP_BIQUAD_1_COEF_0, 0x00800000 }, + { TEGRA210_DMIC_LP_BIQUAD_1_COEF_1, 0x0 }, + { TEGRA210_DMIC_LP_BIQUAD_1_COEF_2, 0x0 }, + { TEGRA210_DMIC_LP_BIQUAD_1_COEF_3, 0x0 }, + { TEGRA210_DMIC_LP_BIQUAD_1_COEF_4, 0x0 }, }; static int tegra210_dmic_runtime_suspend(struct device *dev) @@ -74,8 +47,7 @@ static int tegra210_dmic_runtime_suspend(struct device *dev) regcache_cache_only(dmic->regmap, true); regcache_mark_dirty(dmic->regmap); - if (!(tegra_platform_is_unit_fpga() || tegra_platform_is_fpga())) - clk_disable_unprepare(dmic->clk_dmic); + clk_disable_unprepare(dmic->clk_dmic); return 0; } @@ -83,14 +55,12 @@ static int tegra210_dmic_runtime_suspend(struct device *dev) static int tegra210_dmic_runtime_resume(struct device *dev) { struct tegra210_dmic *dmic = dev_get_drvdata(dev); - int ret; + int err; - if (!(tegra_platform_is_unit_fpga() || tegra_platform_is_fpga())) { - ret = clk_prepare_enable(dmic->clk_dmic); - if (ret) { - dev_err(dev, "clk_enable failed: %d\n", ret); - return ret; - } + err = clk_prepare_enable(dmic->clk_dmic); + if (err) { + dev_err(dev, "failed to enable DMIC clock, err: %d\n", err); + return err; } regcache_cache_only(dmic->regmap, false); @@ -99,221 +69,176 @@ static int tegra210_dmic_runtime_resume(struct device *dev) return 0; } -static const int tegra210_dmic_fmt_values[] = { +static const unsigned int tegra210_dmic_fmts[] = { 0, - TEGRA210_AUDIOCIF_BITS_16, - TEGRA210_AUDIOCIF_BITS_32, + TEGRA_ACIF_BITS_16, + TEGRA_ACIF_BITS_32, }; -static int tegra210_dmic_startup(struct snd_pcm_substream *substream, - struct snd_soc_dai *dai) -{ - struct device *dev = dai->dev; - struct tegra210_dmic *dmic = snd_soc_dai_get_drvdata(dai); - int ret; - - if (dmic->prod_name != NULL) { - ret = tegra_pinctrl_config_prod(dev, dmic->prod_name); - if (ret < 0) { - dev_warn(dev, "Failed to set %s setting\n", - dmic->prod_name); - } - } - - return 0; -} - static int tegra210_dmic_hw_params(struct snd_pcm_substream *substream, - struct snd_pcm_hw_params *params, - struct snd_soc_dai *dai) + struct snd_pcm_hw_params *params, + struct snd_soc_dai *dai) { - struct device *dev = dai->dev; struct tegra210_dmic *dmic = snd_soc_dai_get_drvdata(dai); - int srate, dmic_clk, osr = dmic->osr_val, ret; - struct tegra210_xbar_cif_conf cif_conf; - unsigned long long boost_gain; - unsigned int channels; + unsigned int srate, clk_rate, channels; + struct tegra_cif_conf cif_conf; + unsigned long long gain_q23 = DEFAULT_GAIN_Q23; + int err; - memset(&cif_conf, 0, sizeof(struct tegra210_xbar_cif_conf)); - - srate = params_rate(params); - if (dmic->sample_rate_via_control) - srate = dmic->sample_rate_via_control; - dmic_clk = (1 << (6+osr)) * srate; + memset(&cif_conf, 0, sizeof(struct tegra_cif_conf)); channels = params_channels(params); - if (dmic->channels_via_control) - channels = dmic->channels_via_control; - cif_conf.audio_channels = channels; + + cif_conf.audio_ch = channels; + if (dmic->audio_ch_override) + cif_conf.audio_ch = dmic->audio_ch_override; switch (dmic->ch_select) { case DMIC_CH_SELECT_LEFT: case DMIC_CH_SELECT_RIGHT: - cif_conf.client_channels = 1; + cif_conf.client_ch = 1; break; case DMIC_CH_SELECT_STEREO: - cif_conf.client_channels = 2; + cif_conf.client_ch = 2; break; default: - dev_err(dev, "unsupported ch_select value\n"); + dev_err(dai->dev, "invalid DMIC client channels\n"); return -EINVAL; } - if ((tegra_platform_is_unit_fpga() || tegra_platform_is_fpga())) { - program_dmic_gpio(); - program_dmic_clk(dmic_clk); - } else { - ret = clk_set_rate(dmic->clk_dmic, dmic_clk); - if (ret) { - dev_err(dev, "Can't set dmic clock rate: %d\n", ret); - return ret; - } + srate = params_rate(params); + if (dmic->srate_override) + srate = dmic->srate_override; + + /* + * DMIC clock rate is a multiple of 'Over Sampling Ratio' and + * 'Sample Rate'. The supported OSR values are 64, 128 and 256. + */ + clk_rate = (DMIC_OSR_FACTOR << dmic->osr_val) * srate; + + err = clk_set_rate(dmic->clk_dmic, clk_rate); + if (err) { + dev_err(dai->dev, "can't set DMIC clock rate %u, err: %d\n", + clk_rate, err); + return err; } - regmap_update_bits(dmic->regmap, TEGRA210_DMIC_CTRL, - TEGRA210_DMIC_CTRL_LRSEL_POLARITY_MASK, - dmic->lrsel << LRSEL_POL_SHIFT); - regmap_update_bits(dmic->regmap, TEGRA210_DMIC_CTRL, - TEGRA210_DMIC_CTRL_OSR_MASK, osr << OSR_SHIFT); - regmap_update_bits(dmic->regmap, TEGRA210_DMIC_DBG_CTRL, - TEGRA210_DMIC_DBG_CTRL_SC_ENABLE, - TEGRA210_DMIC_DBG_CTRL_SC_ENABLE); - regmap_update_bits(dmic->regmap, TEGRA210_DMIC_DBG_CTRL, - TEGRA210_DMIC_DBG_CTRL_DCR_ENABLE, - TEGRA210_DMIC_DBG_CTRL_DCR_ENABLE); - regmap_update_bits(dmic->regmap, TEGRA210_DMIC_CTRL, + regmap_update_bits(dmic->regmap, + /* Reg */ + TEGRA210_DMIC_CTRL, + /* Mask */ + TEGRA210_DMIC_CTRL_LRSEL_POLARITY_MASK | + TEGRA210_DMIC_CTRL_OSR_MASK | TEGRA210_DMIC_CTRL_CHANNEL_SELECT_MASK, - (dmic->ch_select + 1) << CH_SEL_SHIFT); + /* Value */ + (dmic->lrsel << LRSEL_POL_SHIFT) | + (dmic->osr_val << OSR_SHIFT) | + ((dmic->ch_select + 1) << CH_SEL_SHIFT)); + + /* + * Use LP filter gain register to apply boost. + * Boost Gain control has 100x factor. + */ + if (dmic->boost_gain) + gain_q23 = (gain_q23 * dmic->boost_gain) / 100; - /* Configure LPF for passthrough and use */ - /* its gain register for applying boost; */ - /* Boost Gain control has 100x factor */ - boost_gain = 0x00800000; - if (dmic->boost_gain > 0) { - boost_gain = ((boost_gain * dmic->boost_gain) / 100); - if (boost_gain > 0x7FFFFFFF) { - dev_warn(dev, "Boost Gain overflow\n"); - boost_gain = 0x7FFFFFFF; - } - } regmap_write(dmic->regmap, TEGRA210_DMIC_LP_FILTER_GAIN, - (unsigned int)boost_gain); - - regmap_update_bits(dmic->regmap, TEGRA210_DMIC_DBG_CTRL, - TEGRA210_DMIC_DBG_CTRL_LP_ENABLE, - TEGRA210_DMIC_DBG_CTRL_LP_ENABLE); - - /* Configure the two biquads for passthrough, */ - /* i.e. b0=1, b1=0, b2=0, a1=0, a2=0 */ - regmap_write(dmic->regmap, TEGRA210_DMIC_LP_BIQUAD_0_COEF_0, - 0x00800000); - regmap_write(dmic->regmap, TEGRA210_DMIC_LP_BIQUAD_0_COEF_1, - 0x00000000); - regmap_write(dmic->regmap, TEGRA210_DMIC_LP_BIQUAD_0_COEF_2, - 0x00000000); - regmap_write(dmic->regmap, TEGRA210_DMIC_LP_BIQUAD_0_COEF_3, - 0x00000000); - regmap_write(dmic->regmap, TEGRA210_DMIC_LP_BIQUAD_0_COEF_4, - 0x00000000); - regmap_write(dmic->regmap, TEGRA210_DMIC_LP_BIQUAD_1_COEF_0, - 0x00800000); - regmap_write(dmic->regmap, TEGRA210_DMIC_LP_BIQUAD_1_COEF_1, - 0x00000000); - regmap_write(dmic->regmap, TEGRA210_DMIC_LP_BIQUAD_1_COEF_2, - 0x00000000); - regmap_write(dmic->regmap, TEGRA210_DMIC_LP_BIQUAD_1_COEF_3, - 0x00000000); - regmap_write(dmic->regmap, TEGRA210_DMIC_LP_BIQUAD_1_COEF_4, - 0x00000000); + (unsigned int)gain_q23); switch (params_format(params)) { case SNDRV_PCM_FORMAT_S16_LE: - cif_conf.audio_bits = TEGRA210_AUDIOCIF_BITS_16; + cif_conf.audio_bits = TEGRA_ACIF_BITS_16; break; case SNDRV_PCM_FORMAT_S32_LE: - cif_conf.audio_bits = TEGRA210_AUDIOCIF_BITS_32; + cif_conf.audio_bits = TEGRA_ACIF_BITS_32; break; default: - dev_err(dev, "Wrong format!\n"); - return -EINVAL; + dev_err(dai->dev, "unsupported format!\n"); + return -ENOTSUPP; } - if (dmic->format_out) - cif_conf.audio_bits = tegra210_dmic_fmt_values[dmic->format_out]; - cif_conf.client_bits = TEGRA210_AUDIOCIF_BITS_24; + if (dmic->audio_bits_override) + cif_conf.audio_bits = + tegra210_dmic_fmts[dmic->audio_bits_override]; + + cif_conf.client_bits = TEGRA_ACIF_BITS_24; cif_conf.mono_conv = dmic->mono_to_stereo; cif_conf.stereo_conv = dmic->stereo_to_mono; - tegra210_xbar_set_cif(dmic->regmap, TEGRA210_DMIC_TX_CIF_CTRL, - &cif_conf); + tegra_set_cif(dmic->regmap, TEGRA210_DMIC_TX_CIF_CTRL, &cif_conf); return 0; } static int tegra210_dmic_get_control(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) + struct snd_ctl_elem_value *ucontrol) { - struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol); - struct tegra210_dmic *dmic = snd_soc_codec_get_drvdata(codec); + struct snd_soc_component *comp = snd_soc_kcontrol_component(kcontrol); + struct tegra210_dmic *dmic = snd_soc_component_get_drvdata(comp); - if (strstr(kcontrol->id.name, "Boost")) + if (strstr(kcontrol->id.name, "Boost Gain")) ucontrol->value.integer.value[0] = dmic->boost_gain; - else if (strstr(kcontrol->id.name, "Controller Channel Select")) + else if (strstr(kcontrol->id.name, "Channel Select")) ucontrol->value.integer.value[0] = dmic->ch_select; - else if (strstr(kcontrol->id.name, "Capture mono to stereo")) + else if (strstr(kcontrol->id.name, "Mono To Stereo")) ucontrol->value.integer.value[0] = dmic->mono_to_stereo; - else if (strstr(kcontrol->id.name, "Capture stereo to mono")) + else if (strstr(kcontrol->id.name, "Stereo To Mono")) ucontrol->value.integer.value[0] = dmic->stereo_to_mono; - else if (strstr(kcontrol->id.name, "output bit format")) - ucontrol->value.integer.value[0] = dmic->format_out; + else if (strstr(kcontrol->id.name, "Audio Bit Format")) + ucontrol->value.integer.value[0] = dmic->audio_bits_override; else if (strstr(kcontrol->id.name, "Sample Rate")) - ucontrol->value.integer.value[0] = - dmic->sample_rate_via_control; - else if (strstr(kcontrol->id.name, "Channels")) - ucontrol->value.integer.value[0] = - dmic->channels_via_control; + ucontrol->value.integer.value[0] = dmic->srate_override; + else if (strstr(kcontrol->id.name, "Audio Channels")) + ucontrol->value.integer.value[0] = dmic->audio_ch_override; else if (strstr(kcontrol->id.name, "OSR Value")) ucontrol->value.integer.value[0] = dmic->osr_val; - else if (strstr(kcontrol->id.name, "LR Select")) + else if (strstr(kcontrol->id.name, "LR Polarity Select")) ucontrol->value.integer.value[0] = dmic->lrsel; return 0; } static int tegra210_dmic_put_control(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) + struct snd_ctl_elem_value *ucontrol) { - struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol); - struct tegra210_dmic *dmic = snd_soc_codec_get_drvdata(codec); + struct snd_soc_component *comp = snd_soc_kcontrol_component(kcontrol); + struct tegra210_dmic *dmic = snd_soc_component_get_drvdata(comp); int value = ucontrol->value.integer.value[0]; - if (strstr(kcontrol->id.name, "Boost")) + if (strstr(kcontrol->id.name, "Boost Gain")) dmic->boost_gain = value; - else if (strstr(kcontrol->id.name, "Controller Channel Select")) + else if (strstr(kcontrol->id.name, "Channel Select")) dmic->ch_select = ucontrol->value.integer.value[0]; - else if (strstr(kcontrol->id.name, "Capture mono to stereo")) + else if (strstr(kcontrol->id.name, "Mono To Stereo")) dmic->mono_to_stereo = value; - else if (strstr(kcontrol->id.name, "Capture stereo to mono")) + else if (strstr(kcontrol->id.name, "Stereo To Mono")) dmic->stereo_to_mono = value; - else if (strstr(kcontrol->id.name, "output bit format")) - dmic->format_out = value; + else if (strstr(kcontrol->id.name, "Audio Bit Format")) + dmic->audio_bits_override = value; else if (strstr(kcontrol->id.name, "Sample Rate")) - dmic->sample_rate_via_control = value; - else if (strstr(kcontrol->id.name, "Channels")) - dmic->channels_via_control = value; + dmic->srate_override = value; + else if (strstr(kcontrol->id.name, "Audio Channels")) + dmic->audio_ch_override = value; else if (strstr(kcontrol->id.name, "OSR Value")) dmic->osr_val = value; - else if (strstr(kcontrol->id.name, "LR Select")) + else if (strstr(kcontrol->id.name, "LR Polarity Select")) dmic->lrsel = value; return 0; } -static struct snd_soc_dai_ops tegra210_dmic_dai_ops = { +static const struct snd_soc_dai_ops tegra210_dmic_dai_ops = { .hw_params = tegra210_dmic_hw_params, - .startup = tegra210_dmic_startup, }; +/* + * Three DAIs are exposed + * 1. "CIF" DAI for connecting with XBAR + * 2. "DAP" DAI for connecting with CODEC + * 3. "DUMMY_SOURCE" can be used when no external + * codec connection is available. In such case + * "DAP" is connected with "DUMMY_SOURCE" + */ static struct snd_soc_dai_driver tegra210_dmic_dais[] = { { .name = "CIF", @@ -322,7 +247,8 @@ static struct snd_soc_dai_driver tegra210_dmic_dais[] = { .channels_min = 1, .channels_max = 2, .rates = SNDRV_PCM_RATE_8000_48000, - .formats = SNDRV_PCM_FMTBIT_S16_LE, + .formats = SNDRV_PCM_FMTBIT_S16_LE | + SNDRV_PCM_FMTBIT_S32_LE, }, .ops = &tegra210_dmic_dai_ops, .symmetric_rates = 1, @@ -334,10 +260,9 @@ static struct snd_soc_dai_driver tegra210_dmic_dais[] = { .channels_min = 1, .channels_max = 2, .rates = SNDRV_PCM_RATE_8000_48000, - .formats = SNDRV_PCM_FMTBIT_S16_LE, + .formats = SNDRV_PCM_FMTBIT_S16_LE | + SNDRV_PCM_FMTBIT_S32_LE, }, - .ops = &tegra210_dmic_dai_ops, - .symmetric_rates = 1, }, { .name = "DUMMY_SOURCE", @@ -346,32 +271,29 @@ static struct snd_soc_dai_driver tegra210_dmic_dais[] = { .channels_min = 1, .channels_max = 2, .rates = SNDRV_PCM_RATE_8000_48000, - .formats = SNDRV_PCM_FMTBIT_S16_LE, + .formats = SNDRV_PCM_FMTBIT_S16_LE | + SNDRV_PCM_FMTBIT_S32_LE, }, } }; static const struct snd_soc_dapm_widget tegra210_dmic_widgets[] = { - SND_SOC_DAPM_AIF_OUT("DMIC TX", NULL, 0, SND_SOC_NOPM, - 0, 0), - SND_SOC_DAPM_AIF_IN("DMIC RX", NULL, 0, TEGRA210_DMIC_ENABLE, - 0, 0), + SND_SOC_DAPM_AIF_IN("DMIC TX", NULL, 0, TEGRA210_DMIC_ENABLE, 0, 0), SND_SOC_DAPM_MIC("Dummy Input", NULL), }; static const struct snd_soc_dapm_route tegra210_dmic_routes[] = { - { "DMIC RX", NULL, "DMIC Receive" }, - { "DMIC TX", NULL, "DMIC RX" }, + { "DMIC TX", NULL, "DMIC Receive" }, { "DMIC Transmit", NULL, "DMIC TX" }, { "Dummy Capture", NULL, "Dummy Input" }, }; static const char * const tegra210_dmic_ch_select[] = { - "L", "R", "Stereo", + "Left", "Right", "Stereo", }; static const struct soc_enum tegra210_dmic_ch_enum = - SOC_ENUM_SINGLE(SND_SOC_NOPM, 0, ARRAY_SIZE(tegra210_dmic_ch_select), + SOC_ENUM_SINGLE(0, 0, ARRAY_SIZE(tegra210_dmic_ch_select), tegra210_dmic_ch_select); static const char * const tegra210_dmic_mono_conv_text[] = { @@ -383,13 +305,11 @@ static const char * const tegra210_dmic_stereo_conv_text[] = { }; static const struct soc_enum tegra210_dmic_mono_conv_enum = - SOC_ENUM_SINGLE(SND_SOC_NOPM, 0, - ARRAY_SIZE(tegra210_dmic_mono_conv_text), + SOC_ENUM_SINGLE(0, 0, ARRAY_SIZE(tegra210_dmic_mono_conv_text), tegra210_dmic_mono_conv_text); static const struct soc_enum tegra210_dmic_stereo_conv_enum = - SOC_ENUM_SINGLE(SND_SOC_NOPM, 0, - ARRAY_SIZE(tegra210_dmic_stereo_conv_text), + SOC_ENUM_SINGLE(0, 0, ARRAY_SIZE(tegra210_dmic_stereo_conv_text), tegra210_dmic_stereo_conv_text); static const char * const tegra210_dmic_format_text[] = { @@ -399,7 +319,7 @@ static const char * const tegra210_dmic_format_text[] = { }; static const struct soc_enum tegra210_dmic_format_enum = - SOC_ENUM_SINGLE(SND_SOC_NOPM, 0, ARRAY_SIZE(tegra210_dmic_format_text), + SOC_ENUM_SINGLE(0, 0, ARRAY_SIZE(tegra210_dmic_format_text), tegra210_dmic_format_text); static const char * const tegra210_dmic_osr_text[] = { @@ -407,7 +327,7 @@ static const char * const tegra210_dmic_osr_text[] = { }; static const struct soc_enum tegra210_dmic_osr_enum = - SOC_ENUM_SINGLE(SND_SOC_NOPM, 0, ARRAY_SIZE(tegra210_dmic_osr_text), + SOC_ENUM_SINGLE(0, 0, ARRAY_SIZE(tegra210_dmic_osr_text), tegra210_dmic_osr_text); static const char * const tegra210_dmic_lrsel_text[] = { @@ -415,88 +335,68 @@ static const char * const tegra210_dmic_lrsel_text[] = { }; static const struct soc_enum tegra210_dmic_lrsel_enum = - SOC_ENUM_SINGLE(SND_SOC_NOPM, 0, ARRAY_SIZE(tegra210_dmic_lrsel_text), + SOC_ENUM_SINGLE(0, 0, ARRAY_SIZE(tegra210_dmic_lrsel_text), tegra210_dmic_lrsel_text); static const struct snd_kcontrol_new tegra210_dmic_controls[] = { - SOC_SINGLE_EXT("Boost Gain", 0, 0, 25599, 0, tegra210_dmic_get_control, - tegra210_dmic_put_control), - SOC_ENUM_EXT("Controller Channel Select", tegra210_dmic_ch_enum, + SOC_SINGLE_EXT("Boost Gain", 0, 0, MAX_BOOST_GAIN, 0, + tegra210_dmic_get_control, tegra210_dmic_put_control), + SOC_ENUM_EXT("Channel Select", tegra210_dmic_ch_enum, tegra210_dmic_get_control, tegra210_dmic_put_control), - SOC_ENUM_EXT("Capture mono to stereo conv", + SOC_ENUM_EXT("Mono To Stereo", tegra210_dmic_mono_conv_enum, tegra210_dmic_get_control, tegra210_dmic_put_control), - SOC_ENUM_EXT("Capture stereo to mono conv", + SOC_ENUM_EXT("Stereo To Mono", tegra210_dmic_stereo_conv_enum, tegra210_dmic_get_control, tegra210_dmic_put_control), - SOC_ENUM_EXT("output bit format", tegra210_dmic_format_enum, + SOC_ENUM_EXT("Audio Bit Format", tegra210_dmic_format_enum, tegra210_dmic_get_control, tegra210_dmic_put_control), SOC_SINGLE_EXT("Sample Rate", 0, 0, 48000, 0, tegra210_dmic_get_control, tegra210_dmic_put_control), - SOC_SINGLE_EXT("Channels", 0, 0, 2, 0, tegra210_dmic_get_control, + SOC_SINGLE_EXT("Audio Channels", 0, 0, 2, 0, tegra210_dmic_get_control, tegra210_dmic_put_control), SOC_ENUM_EXT("OSR Value", tegra210_dmic_osr_enum, tegra210_dmic_get_control, tegra210_dmic_put_control), - SOC_ENUM_EXT("LR Select", tegra210_dmic_lrsel_enum, + SOC_ENUM_EXT("LR Polarity Select", tegra210_dmic_lrsel_enum, tegra210_dmic_get_control, tegra210_dmic_put_control), }; -static struct snd_soc_codec_driver tegra210_dmic_codec = { - .idle_bias_off = 1, - .component_driver = { - .dapm_widgets = tegra210_dmic_widgets, - .num_dapm_widgets = ARRAY_SIZE(tegra210_dmic_widgets), - .dapm_routes = tegra210_dmic_routes, - .num_dapm_routes = ARRAY_SIZE(tegra210_dmic_routes), - .controls = tegra210_dmic_controls, - .num_controls = ARRAY_SIZE(tegra210_dmic_controls), - }, +static const struct snd_soc_component_driver tegra210_dmic_compnt = { + .dapm_widgets = tegra210_dmic_widgets, + .num_dapm_widgets = ARRAY_SIZE(tegra210_dmic_widgets), + .dapm_routes = tegra210_dmic_routes, + .num_dapm_routes = ARRAY_SIZE(tegra210_dmic_routes), + .controls = tegra210_dmic_controls, + .num_controls = ARRAY_SIZE(tegra210_dmic_controls), }; -/* Regmap callback functions */ static bool tegra210_dmic_wr_reg(struct device *dev, unsigned int reg) { switch (reg) { - case TEGRA210_DMIC_TX_INT_MASK: - case TEGRA210_DMIC_TX_INT_SET: - case TEGRA210_DMIC_TX_INT_CLEAR: - case TEGRA210_DMIC_TX_CIF_CTRL: - case TEGRA210_DMIC_ENABLE: - case TEGRA210_DMIC_SOFT_RESET: - case TEGRA210_DMIC_CG: + case TEGRA210_DMIC_TX_INT_MASK ... TEGRA210_DMIC_TX_CIF_CTRL: + case TEGRA210_DMIC_ENABLE ... TEGRA210_DMIC_CG: case TEGRA210_DMIC_CTRL: + case TEGRA210_DMIC_DBG_CTRL: + case TEGRA210_DMIC_DCR_BIQUAD_0_COEF_4 ... TEGRA210_DMIC_LP_BIQUAD_1_COEF_4: return true; default: - if (((reg % 4) == 0) && (reg >= TEGRA210_DMIC_DBG_CTRL) && - (reg <= TEGRA210_DMIC_CORRECTION_BIQUAD_1_COEF_4)) - return true; - else - return false; + return false; }; } static bool tegra210_dmic_rd_reg(struct device *dev, unsigned int reg) { + if (tegra210_dmic_wr_reg(dev, reg)) + return true; + switch (reg) { case TEGRA210_DMIC_TX_STATUS: case TEGRA210_DMIC_TX_INT_STATUS: - case TEGRA210_DMIC_TX_INT_MASK: - case TEGRA210_DMIC_TX_INT_SET: - case TEGRA210_DMIC_TX_INT_CLEAR: - case TEGRA210_DMIC_TX_CIF_CTRL: - case TEGRA210_DMIC_ENABLE: - case TEGRA210_DMIC_SOFT_RESET: - case TEGRA210_DMIC_CG: case TEGRA210_DMIC_STATUS: case TEGRA210_DMIC_INT_STATUS: - case TEGRA210_DMIC_CTRL: return true; default: - if (((reg % 4) == 0) && (reg >= TEGRA210_DMIC_DBG_CTRL) && - (reg <= TEGRA210_DMIC_CORRECTION_BIQUAD_1_COEF_4)) - return true; - else - return false; + return false; }; } @@ -519,11 +419,10 @@ static const struct regmap_config tegra210_dmic_regmap_config = { .reg_bits = 32, .reg_stride = 4, .val_bits = 32, - .max_register = TEGRA210_DMIC_CORRECTION_BIQUAD_1_COEF_4, + .max_register = TEGRA210_DMIC_LP_BIQUAD_1_COEF_4, .writeable_reg = tegra210_dmic_wr_reg, .readable_reg = tegra210_dmic_rd_reg, .volatile_reg = tegra210_dmic_volatile_reg, - .precious_reg = NULL, .reg_defaults = tegra210_dmic_reg_defaults, .num_reg_defaults = ARRAY_SIZE(tegra210_dmic_reg_defaults), .cache_type = REGCACHE_FLAT, @@ -533,85 +432,62 @@ static const struct of_device_id tegra210_dmic_of_match[] = { { .compatible = "nvidia,tegra210-dmic" }, {}, }; +MODULE_DEVICE_TABLE(of, tegra210_dmic_of_match); -static int tegra210_dmic_platform_probe(struct platform_device *pdev) +static int tegra210_dmic_probe(struct platform_device *pdev) { + struct device *dev = &pdev->dev; struct tegra210_dmic *dmic; - struct device_node *np = pdev->dev.of_node; - struct resource *mem; void __iomem *regs; - int ret = 0; - const struct of_device_id *match; + int err; - match = of_match_device(tegra210_dmic_of_match, &pdev->dev); - if (!match) { - dev_err(&pdev->dev, "Error: No device match found\n"); - return -ENODEV; - } - - dmic = devm_kzalloc(&pdev->dev, sizeof(*dmic), GFP_KERNEL); + dmic = devm_kzalloc(dev, sizeof(*dmic), GFP_KERNEL); if (!dmic) return -ENOMEM; - dmic->prod_name = NULL; dmic->osr_val = DMIC_OSR_64; dmic->ch_select = DMIC_CH_SELECT_STEREO; - dev_set_drvdata(&pdev->dev, dmic); + dmic->lrsel = DMIC_LRSEL_LEFT; + dmic->boost_gain = 0; + dmic->stereo_to_mono = 0; /* "CH0" */ - if (!(tegra_platform_is_unit_fpga() || tegra_platform_is_fpga())) { - dmic->clk_dmic = devm_clk_get(&pdev->dev, "dmic"); - if (IS_ERR(dmic->clk_dmic)) { - dev_err(&pdev->dev, "Can't retrieve dmic clock\n"); - return PTR_ERR(dmic->clk_dmic); - } + dev_set_drvdata(dev, dmic); + + dmic->clk_dmic = devm_clk_get(dev, "dmic"); + if (IS_ERR(dmic->clk_dmic)) { + dev_err(dev, "can't retrieve DMIC clock\n"); + return PTR_ERR(dmic->clk_dmic); } - mem = platform_get_resource(pdev, IORESOURCE_MEM, 0); - regs = devm_ioremap_resource(&pdev->dev, mem); + regs = devm_platform_ioremap_resource(pdev, 0); if (IS_ERR(regs)) return PTR_ERR(regs); - dmic->regmap = devm_regmap_init_mmio(&pdev->dev, regs, + + dmic->regmap = devm_regmap_init_mmio(dev, regs, &tegra210_dmic_regmap_config); if (IS_ERR(dmic->regmap)) { - dev_err(&pdev->dev, "regmap init failed\n"); + dev_err(dev, "regmap init failed\n"); return PTR_ERR(dmic->regmap); } + regcache_cache_only(dmic->regmap, true); - /* Below patch is as per latest POR value */ - regmap_write(dmic->regmap, TEGRA210_DMIC_DCR_BIQUAD_0_COEF_4, - 0x00000000); - - pm_runtime_enable(&pdev->dev); - ret = snd_soc_register_codec(&pdev->dev, &tegra210_dmic_codec, - tegra210_dmic_dais, - ARRAY_SIZE(tegra210_dmic_dais)); - if (ret != 0) { - dev_err(&pdev->dev, "Could not register CODEC: %d\n", ret); - pm_runtime_disable(&pdev->dev); - return ret; + err = devm_snd_soc_register_component(dev, &tegra210_dmic_compnt, + tegra210_dmic_dais, + ARRAY_SIZE(tegra210_dmic_dais)); + if (err) { + dev_err(dev, "can't register DMIC component, err: %d\n", err); + return err; } - if (of_property_read_string(np, "prod-name", &dmic->prod_name) == 0) { - ret = tegra_pinctrl_config_prod(&pdev->dev, dmic->prod_name); - if (ret < 0) - dev_warn(&pdev->dev, "Failed to set %s setting\n", - dmic->prod_name); - } + pm_runtime_enable(dev); return 0; } -static int tegra210_dmic_platform_remove(struct platform_device *pdev) +static int tegra210_dmic_remove(struct platform_device *pdev) { - struct tegra210_dmic *dmic; - - dmic = dev_get_drvdata(&pdev->dev); - snd_soc_unregister_codec(&pdev->dev); - pm_runtime_disable(&pdev->dev); - if (!pm_runtime_status_suspended(&pdev->dev)) - tegra210_dmic_runtime_suspend(&pdev->dev); return 0; } @@ -619,24 +495,21 @@ static int tegra210_dmic_platform_remove(struct platform_device *pdev) static const struct dev_pm_ops tegra210_dmic_pm_ops = { SET_RUNTIME_PM_OPS(tegra210_dmic_runtime_suspend, tegra210_dmic_runtime_resume, NULL) - SET_LATE_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend, - pm_runtime_force_resume) + SET_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend, + pm_runtime_force_resume) }; static struct platform_driver tegra210_dmic_driver = { .driver = { - .name = DRV_NAME, - .owner = THIS_MODULE, + .name = "tegra210-dmic", .of_match_table = tegra210_dmic_of_match, .pm = &tegra210_dmic_pm_ops, }, - .probe = tegra210_dmic_platform_probe, - .remove = tegra210_dmic_platform_remove, + .probe = tegra210_dmic_probe, + .remove = tegra210_dmic_remove, }; module_platform_driver(tegra210_dmic_driver) MODULE_AUTHOR("Rahul Mittal "); -MODULE_DESCRIPTION("Tegra210 DMIC ASoC driver"); -MODULE_LICENSE("GPL"); -MODULE_ALIAS("platform:" DRV_NAME); -MODULE_DEVICE_TABLE(of, tegra210_dmic_of_match); +MODULE_DESCRIPTION("Tegra210 ASoC DMIC driver"); +MODULE_LICENSE("GPL v2"); diff --git a/sound/soc/tegra/tegra210_dmic.h b/sound/soc/tegra/tegra210_dmic.h index abe611f3..a08d1364 100644 --- a/sound/soc/tegra/tegra210_dmic.h +++ b/sound/soc/tegra/tegra210_dmic.h @@ -1,23 +1,13 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ /* - * tegra210_dmic_alt.h - Definitions for Tegra210 DMIC driver + * tegra210_dmic.h - Definitions for Tegra210 DMIC driver * - * Copyright (c) 2014-2019 NVIDIA CORPORATION. All rights reserved. + * Copyright (c) 2020 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 . */ -#ifndef __TEGRA210_DMIC_ALT_H__ -#define __TEGRA210_DMIC_ALT_H__ +#ifndef __TEGRA210_DMIC_H__ +#define __TEGRA210_DMIC_H__ /* Register offsets from DMIC BASE */ #define TEGRA210_DMIC_TX_STATUS 0x0c @@ -33,11 +23,6 @@ #define TEGRA210_DMIC_INT_STATUS 0x50 #define TEGRA210_DMIC_CTRL 0x64 #define TEGRA210_DMIC_DBG_CTRL 0x70 -#define TEGRA210_DMIC_DCR_FILTER_GAIN 0x74 -#define TEGRA210_DMIC_DCR_BIQUAD_0_COEF_0 0x78 -#define TEGRA210_DMIC_DCR_BIQUAD_0_COEF_1 0x7c -#define TEGRA210_DMIC_DCR_BIQUAD_0_COEF_2 0x80 -#define TEGRA210_DMIC_DCR_BIQUAD_0_COEF_3 0x84 #define TEGRA210_DMIC_DCR_BIQUAD_0_COEF_4 0x88 #define TEGRA210_DMIC_LP_FILTER_GAIN 0x8c #define TEGRA210_DMIC_LP_BIQUAD_0_COEF_0 0x90 @@ -50,17 +35,6 @@ #define TEGRA210_DMIC_LP_BIQUAD_1_COEF_2 0xac #define TEGRA210_DMIC_LP_BIQUAD_1_COEF_3 0xb0 #define TEGRA210_DMIC_LP_BIQUAD_1_COEF_4 0xb4 -#define TEGRA210_DMIC_CORRECTION_FILTER_GAIN 0xb8 -#define TEGRA210_DMIC_CORRECTION_BIQUAD_0_COEF_0 0xbc -#define TEGRA210_DMIC_CORRECTION_BIQUAD_0_COEF_1 0xc0 -#define TEGRA210_DMIC_CORRECTION_BIQUAD_0_COEF_2 0xc4 -#define TEGRA210_DMIC_CORRECTION_BIQUAD_0_COEF_3 0xc8 -#define TEGRA210_DMIC_CORRECTION_BIQUAD_0_COEF_4 0xcc -#define TEGRA210_DMIC_CORRECTION_BIQUAD_1_COEF_0 0xd0 -#define TEGRA210_DMIC_CORRECTION_BIQUAD_1_COEF_1 0xd4 -#define TEGRA210_DMIC_CORRECTION_BIQUAD_1_COEF_2 0xd8 -#define TEGRA210_DMIC_CORRECTION_BIQUAD_1_COEF_3 0xdc -#define TEGRA210_DMIC_CORRECTION_BIQUAD_1_COEF_4 0xe0 /* Fields in TEGRA210_DMIC_CTRL */ #define CH_SEL_SHIFT 8 @@ -69,11 +43,13 @@ #define TEGRA210_DMIC_CTRL_LRSEL_POLARITY_MASK (0x1 << LRSEL_POL_SHIFT) #define OSR_SHIFT 0 #define TEGRA210_DMIC_CTRL_OSR_MASK (0x3 << OSR_SHIFT) -/* Fields in TEGRA210_DMIC_DBG_CTRL */ -#define TEGRA210_DMIC_DBG_CTRL_DCR_ENABLE BIT(3) -#define TEGRA210_DMIC_DBG_CTRL_LP_ENABLE BIT(2) -#define TEGRA210_DMIC_DBG_CTRL_SC_ENABLE BIT(1) -#define TEGRA210_DMIC_DBG_CTRL_BYPASS BIT(0) + +#define DMIC_OSR_FACTOR 64 + +#define DEFAULT_GAIN_Q23 0x800000 + +/* Max boost gain factor used for mixer control */ +#define MAX_BOOST_GAIN 25599 enum tegra_dmic_ch_select { DMIC_CH_SELECT_LEFT, @@ -87,19 +63,23 @@ enum tegra_dmic_osr { DMIC_OSR_256, }; +enum tegra_dmic_lrsel { + DMIC_LRSEL_LEFT, + DMIC_LRSEL_RIGHT, +}; + struct tegra210_dmic { struct clk *clk_dmic; struct regmap *regmap; - const char *prod_name; - int boost_gain; /* with 100x factor */ - unsigned int ch_select; + unsigned int audio_ch_override; + unsigned int audio_bits_override; + unsigned int srate_override; unsigned int mono_to_stereo; unsigned int stereo_to_mono; - unsigned int sample_rate_via_control; - unsigned int channels_via_control; - unsigned int osr_val; /* osr value */ - int lrsel; - int format_out; + unsigned int boost_gain; + unsigned int ch_select; + unsigned int osr_val; + unsigned int lrsel; }; #endif diff --git a/sound/soc/tegra/tegra210_i2s.c b/sound/soc/tegra/tegra210_i2s.c index 31a8effe..dfdb6fd9 100644 --- a/sound/soc/tegra/tegra210_i2s.c +++ b/sound/soc/tegra/tegra210_i2s.c @@ -1,154 +1,128 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * tegra210_i2s.c - Tegra210 I2S driver * - * Copyright (c) 2014-2020 NVIDIA CORPORATION. All rights reserved. + * Copyright (c) 2020 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 -#include -#include -#include - -#include "tegra210_xbar_alt.h" -#include "tegra210_i2s_alt.h" - -#define DRV_NAME "tegra210-i2s" +#include "tegra210_i2s.h" +#include "tegra_cif.h" static const struct reg_default tegra210_i2s_reg_defaults[] = { - { TEGRA210_I2S_AXBAR_RX_INT_MASK, 0x00000003}, - { TEGRA210_I2S_AXBAR_RX_CIF_CTRL, 0x00007700}, - { TEGRA210_I2S_AXBAR_TX_INT_MASK, 0x00000003}, - { TEGRA210_I2S_AXBAR_TX_CIF_CTRL, 0x00007700}, - { TEGRA210_I2S_CG, 0x1}, - { TEGRA210_I2S_TIMING, 0x0000001f}, - { TEGRA210_I2S_ENABLE, 0x1}, + { TEGRA210_I2S_RX_INT_MASK, 0x00000003 }, + { TEGRA210_I2S_RX_CIF_CTRL, 0x00007700 }, + { TEGRA210_I2S_TX_INT_MASK, 0x00000003 }, + { TEGRA210_I2S_TX_CIF_CTRL, 0x00007700 }, + { TEGRA210_I2S_CG, 0x1 }, + { TEGRA210_I2S_TIMING, 0x0000001f }, + { TEGRA210_I2S_ENABLE, 0x1 }, /* * Below update does not have any effect on Tegra186 and Tegra194. * On Tegra210, I2S4 has "i2s4a" and "i2s4b" pins and below update * is required to select i2s4b for it to be functional for I2S * operation. */ - { TEGRA210_I2S_CYA, 0x1}, + { TEGRA210_I2S_CYA, 0x1 }, }; static void tegra210_i2s_set_slot_ctrl(struct regmap *regmap, - unsigned int total_slots, - unsigned int tx_slot_mask, - unsigned int rx_slot_mask) + unsigned int total_slots, + unsigned int tx_slot_mask, + unsigned int rx_slot_mask) { regmap_write(regmap, TEGRA210_I2S_SLOT_CTRL, total_slots - 1); - regmap_write(regmap, TEGRA210_I2S_AXBAR_TX_SLOT_CTRL, - tx_slot_mask); - regmap_write(regmap, TEGRA210_I2S_AXBAR_RX_SLOT_CTRL, - rx_slot_mask); + regmap_write(regmap, TEGRA210_I2S_TX_SLOT_CTRL, tx_slot_mask); + regmap_write(regmap, TEGRA210_I2S_RX_SLOT_CTRL, rx_slot_mask); } -static int tegra210_i2s_set_clock_rate(struct device *dev, int clock_rate) +static int tegra210_i2s_set_clock_rate(struct device *dev, + unsigned int clock_rate) { - unsigned int val; struct tegra210_i2s *i2s = dev_get_drvdata(dev); - int ret; + unsigned int val; + int err; regmap_read(i2s->regmap, TEGRA210_I2S_CTRL, &val); - val &= TEGRA210_I2S_CTRL_MASTER_EN; - /* no need to set rates if I2S is being operated in slave */ - if (!val) + /* No need to set rates if I2S is being operated in slave */ + if (!(val & I2S_CTRL_MASTER_EN)) return 0; - /* skip for fpga units */ - if (tegra_platform_is_unit_fpga() || tegra_platform_is_fpga()) - return 0; - - ret = clk_set_rate(i2s->clk_i2s, clock_rate); - if (ret) { - dev_err(dev, "Can't set I2S clock rate: %d\n", ret); - return ret; + err = clk_set_rate(i2s->clk_i2s, clock_rate); + if (err) { + dev_err(dev, "can't set I2S bit clock rate %u, err: %d\n", + clock_rate, err); + return err; } if (!IS_ERR(i2s->clk_sync_input)) { /* - * other I/O modules in AHUB can use i2s bclk as reference + * Other I/O modules in AHUB can use i2s bclk as reference * clock. Below sets sync input clock rate as per bclk, * which can be used as input to other I/O modules. */ - ret = clk_set_rate(i2s->clk_sync_input, clock_rate); - if (ret) { - dev_err(dev, "Can't set I2S sync input clock rate\n"); - return ret; + err = clk_set_rate(i2s->clk_sync_input, clock_rate); + if (err) { + dev_err(dev, + "can't set I2S sync input rate %u, err = %d\n", + clock_rate, err); + return err; } } return 0; } -static int tegra210_i2s_sw_reset(struct snd_soc_codec *codec, bool is_playback) +static int tegra210_i2s_sw_reset(struct snd_soc_component *compnt, + bool is_playback) { - struct device *dev = codec->dev; + struct device *dev = compnt->dev; struct tegra210_i2s *i2s = dev_get_drvdata(dev); + unsigned int reset_mask = I2S_SOFT_RESET_MASK; + unsigned int reset_en = I2S_SOFT_RESET_EN; unsigned int reset_reg, cif_reg, stream_reg; unsigned int cif_ctrl, stream_ctrl, i2s_ctrl, val; - unsigned int reset_mask, reset_en; - int ret; + int err; if (is_playback) { - reset_mask = TEGRA210_I2S_AXBAR_RX_SOFT_RESET_MASK; - reset_en = TEGRA210_I2S_AXBAR_RX_SOFT_RESET_EN; - reset_reg = TEGRA210_I2S_AXBAR_RX_SOFT_RESET; - cif_reg = TEGRA210_I2S_AXBAR_RX_CIF_CTRL; - stream_reg = TEGRA210_I2S_AXBAR_RX_CTRL; + reset_reg = TEGRA210_I2S_RX_SOFT_RESET; + cif_reg = TEGRA210_I2S_RX_CIF_CTRL; + stream_reg = TEGRA210_I2S_RX_CTRL; } else { - reset_mask = TEGRA210_I2S_AXBAR_TX_SOFT_RESET_MASK; - reset_en = TEGRA210_I2S_AXBAR_TX_SOFT_RESET_EN; - reset_reg = TEGRA210_I2S_AXBAR_TX_SOFT_RESET; - cif_reg = TEGRA210_I2S_AXBAR_TX_CIF_CTRL; - stream_reg = TEGRA210_I2S_AXBAR_TX_CTRL; + reset_reg = TEGRA210_I2S_TX_SOFT_RESET; + cif_reg = TEGRA210_I2S_TX_CIF_CTRL; + stream_reg = TEGRA210_I2S_TX_CTRL; } - /* store */ + /* Store CIF and I2S control values */ regmap_read(i2s->regmap, cif_reg, &cif_ctrl); regmap_read(i2s->regmap, stream_reg, &stream_ctrl); regmap_read(i2s->regmap, TEGRA210_I2S_CTRL, &i2s_ctrl); - /* SW reset */ + /* Reset to make sure the previous transactions are clean */ regmap_update_bits(i2s->regmap, reset_reg, reset_mask, reset_en); - ret = regmap_read_poll_timeout(i2s->regmap, reset_reg, val, + err = regmap_read_poll_timeout(i2s->regmap, reset_reg, val, !(val & reset_mask & reset_en), 10, 10000); - if (ret < 0) { + if (err) { dev_err(dev, "timeout: failed to reset I2S for %s\n", is_playback ? "playback" : "capture"); - return ret; + return err; } - /* restore */ + /* Restore CIF and I2S control values */ regmap_write(i2s->regmap, cif_reg, cif_ctrl); regmap_write(i2s->regmap, stream_reg, stream_ctrl); regmap_write(i2s->regmap, TEGRA210_I2S_CTRL, i2s_ctrl); @@ -159,42 +133,37 @@ static int tegra210_i2s_sw_reset(struct snd_soc_codec *codec, bool is_playback) static int tegra210_i2s_init(struct snd_soc_dapm_widget *w, struct snd_kcontrol *kcontrol, int event) { - struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm); - struct device *dev = codec->dev; + struct snd_soc_component *compnt = snd_soc_dapm_to_component(w->dapm); + struct device *dev = compnt->dev; struct tegra210_i2s *i2s = dev_get_drvdata(dev); unsigned int val, status_reg; bool is_playback; - int ret; + int err; switch (w->reg) { - case TEGRA210_I2S_AXBAR_RX_ENABLE: + case TEGRA210_I2S_RX_ENABLE: is_playback = true; - status_reg = TEGRA210_I2S_AXBAR_RX_STATUS; + status_reg = TEGRA210_I2S_RX_STATUS; break; - case TEGRA210_I2S_AXBAR_TX_ENABLE: + case TEGRA210_I2S_TX_ENABLE: is_playback = false; - status_reg = TEGRA210_I2S_AXBAR_TX_STATUS; + status_reg = TEGRA210_I2S_TX_STATUS; break; default: return -EINVAL; } - /* ensure I2S is in disabled state before new session */ - ret = regmap_read_poll_timeout(i2s->regmap, status_reg, val, - !(val & TEGRA210_I2S_EN_MASK & TEGRA210_I2S_EN), - 10, 10000); - if (ret < 0) { + /* Ensure I2S is in disabled state before new session */ + err = regmap_read_poll_timeout(i2s->regmap, status_reg, val, + !(val & I2S_EN_MASK & I2S_EN), + 10, 10000); + if (err) { dev_err(dev, "timeout: previous I2S %s is still active\n", is_playback ? "playback" : "capture"); - return ret; + return err; } - /* SW reset */ - ret = tegra210_i2s_sw_reset(codec, is_playback); - if (ret < 0) - return ret; - - return 0; + return tegra210_i2s_sw_reset(compnt, is_playback); } static int tegra210_i2s_runtime_suspend(struct device *dev) @@ -202,10 +171,9 @@ static int tegra210_i2s_runtime_suspend(struct device *dev) struct tegra210_i2s *i2s = dev_get_drvdata(dev); regcache_cache_only(i2s->regmap, true); - if (!(tegra_platform_is_unit_fpga() || tegra_platform_is_fpga())) { - regcache_mark_dirty(i2s->regmap); - clk_disable_unprepare(i2s->clk_i2s); - } + regcache_mark_dirty(i2s->regmap); + + clk_disable_unprepare(i2s->clk_i2s); return 0; } @@ -213,14 +181,12 @@ static int tegra210_i2s_runtime_suspend(struct device *dev) static int tegra210_i2s_runtime_resume(struct device *dev) { struct tegra210_i2s *i2s = dev_get_drvdata(dev); - int ret; + int err; - if (!(tegra_platform_is_unit_fpga() || tegra_platform_is_fpga())) { - ret = clk_prepare_enable(i2s->clk_i2s); - if (ret) { - dev_err(dev, "clk_enable failed: %d\n", ret); - return ret; - } + err = clk_prepare_enable(i2s->clk_i2s); + if (err) { + dev_err(dev, "failed to enable I2S bit clock, err: %d\n", err); + return err; } regcache_cache_only(i2s->regmap, false); @@ -232,16 +198,14 @@ static int tegra210_i2s_runtime_resume(struct device *dev) static void tegra210_i2s_set_data_offset(struct tegra210_i2s *i2s, unsigned int data_offset) { - unsigned int reg, mask, shift; + unsigned int mask = I2S_CTRL_DATA_OFFSET_MASK; + unsigned int shift = I2S_DATA_SHIFT; + unsigned int reg; - reg = TEGRA210_I2S_AXBAR_TX_CTRL; - mask = TEGRA210_I2S_AXBAR_TX_CTRL_DATA_OFFSET_MASK; - shift = TEGRA210_I2S_AXBAR_TX_CTRL_DATA_OFFSET_SHIFT; + reg = TEGRA210_I2S_TX_CTRL; regmap_update_bits(i2s->regmap, reg, mask, data_offset << shift); - reg = TEGRA210_I2S_AXBAR_RX_CTRL; - mask = TEGRA210_I2S_AXBAR_RX_CTRL_DATA_OFFSET_MASK; - shift = TEGRA210_I2S_AXBAR_RX_CTRL_DATA_OFFSET_SHIFT; + reg = TEGRA210_I2S_RX_CTRL; regmap_update_bits(i2s->regmap, reg, mask, data_offset << shift); } @@ -251,35 +215,34 @@ static int tegra210_i2s_set_fmt(struct snd_soc_dai *dai, struct tegra210_i2s *i2s = snd_soc_dai_get_drvdata(dai); unsigned int mask, val; - mask = TEGRA210_I2S_CTRL_MASTER_EN_MASK; + mask = I2S_CTRL_MASTER_EN_MASK; switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { case SND_SOC_DAIFMT_CBS_CFS: val = 0; break; case SND_SOC_DAIFMT_CBM_CFM: - val = TEGRA210_I2S_CTRL_MASTER_EN; + val = I2S_CTRL_MASTER_EN; break; default: return -EINVAL; } - mask |= TEGRA210_I2S_CTRL_FRAME_FORMAT_MASK | - TEGRA210_I2S_CTRL_LRCK_POLARITY_MASK; + mask |= I2S_CTRL_FRAME_FMT_MASK | I2S_CTRL_LRCK_POL_MASK; switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) { case SND_SOC_DAIFMT_DSP_A: - val |= TEGRA210_I2S_CTRL_FRAME_FORMAT_FSYNC_MODE; - val |= TEGRA210_I2S_CTRL_LRCK_POLARITY_HIGH; + val |= I2S_CTRL_FRAME_FMT_FSYNC_MODE; + val |= I2S_CTRL_LRCK_POL_HIGH; tegra210_i2s_set_data_offset(i2s, 1); break; case SND_SOC_DAIFMT_DSP_B: - val |= TEGRA210_I2S_CTRL_FRAME_FORMAT_FSYNC_MODE; - val |= TEGRA210_I2S_CTRL_LRCK_POLARITY_HIGH; + val |= I2S_CTRL_FRAME_FMT_FSYNC_MODE; + val |= I2S_CTRL_LRCK_POL_HIGH; tegra210_i2s_set_data_offset(i2s, 0); break; /* I2S mode has data offset of 1 */ case SND_SOC_DAIFMT_I2S: - val |= TEGRA210_I2S_CTRL_FRAME_FORMAT_LRCK_MODE; - val |= TEGRA210_I2S_CTRL_LRCK_POLARITY_LOW; + val |= I2S_CTRL_FRAME_FMT_LRCK_MODE; + val |= I2S_CTRL_LRCK_POL_LOW; tegra210_i2s_set_data_offset(i2s, 1); break; /* @@ -287,33 +250,33 @@ static int tegra210_i2s_set_fmt(struct snd_soc_dai *dai, * and the bclk ratio, and so is set when hw_params is called. */ case SND_SOC_DAIFMT_RIGHT_J: - val |= TEGRA210_I2S_CTRL_FRAME_FORMAT_LRCK_MODE; - val |= TEGRA210_I2S_CTRL_LRCK_POLARITY_HIGH; + val |= I2S_CTRL_FRAME_FMT_LRCK_MODE; + val |= I2S_CTRL_LRCK_POL_HIGH; break; case SND_SOC_DAIFMT_LEFT_J: - val |= TEGRA210_I2S_CTRL_FRAME_FORMAT_LRCK_MODE; - val |= TEGRA210_I2S_CTRL_LRCK_POLARITY_HIGH; + val |= I2S_CTRL_FRAME_FMT_LRCK_MODE; + val |= I2S_CTRL_LRCK_POL_HIGH; tegra210_i2s_set_data_offset(i2s, 0); break; default: return -EINVAL; } - mask |= TEGRA210_I2S_CTRL_EDGE_CTRL_MASK; + mask |= I2S_CTRL_EDGE_CTRL_MASK; switch (fmt & SND_SOC_DAIFMT_INV_MASK) { case SND_SOC_DAIFMT_NB_NF: - val |= TEGRA210_I2S_CTRL_EDGE_CTRL_POS_EDGE; + val |= I2S_CTRL_EDGE_CTRL_POS_EDGE; break; case SND_SOC_DAIFMT_NB_IF: - val |= TEGRA210_I2S_CTRL_EDGE_CTRL_POS_EDGE; - val ^= TEGRA210_I2S_CTRL_LRCK_POLARITY_MASK; + val |= I2S_CTRL_EDGE_CTRL_POS_EDGE; + val ^= I2S_CTRL_LRCK_POL_MASK; break; case SND_SOC_DAIFMT_IB_NF: - val |= TEGRA210_I2S_CTRL_EDGE_CTRL_NEG_EDGE; + val |= I2S_CTRL_EDGE_CTRL_NEG_EDGE; break; case SND_SOC_DAIFMT_IB_IF: - val |= TEGRA210_I2S_CTRL_EDGE_CTRL_NEG_EDGE; - val ^= TEGRA210_I2S_CTRL_LRCK_POLARITY_MASK; + val |= I2S_CTRL_EDGE_CTRL_NEG_EDGE; + val ^= I2S_CTRL_LRCK_POL_MASK; break; default: return -EINVAL; @@ -321,20 +284,22 @@ static int tegra210_i2s_set_fmt(struct snd_soc_dai *dai, regmap_update_bits(i2s->regmap, TEGRA210_I2S_CTRL, mask, val); - i2s->format = fmt & SND_SOC_DAIFMT_FORMAT_MASK; + i2s->dai_fmt = fmt & SND_SOC_DAIFMT_FORMAT_MASK; return 0; } static int tegra210_i2s_set_tdm_slot(struct snd_soc_dai *dai, - unsigned int tx_mask, unsigned int rx_mask, - int slots, int slot_width) + unsigned int tx_mask, unsigned int rx_mask, + int slots, int slot_width) { struct tegra210_i2s *i2s = snd_soc_dai_get_drvdata(dai); - /* copy the required tx and rx mask */ - i2s->tx_mask = (tx_mask > 0xFFFF) ? 0xFFFF : tx_mask; - i2s->rx_mask = (rx_mask > 0xFFFF) ? 0xFFFF : rx_mask; + /* Copy the required tx and rx mask */ + i2s->tx_mask = (tx_mask > DEFAULT_I2S_SLOT_MASK) ? + DEFAULT_I2S_SLOT_MASK : tx_mask; + i2s->rx_mask = (rx_mask > DEFAULT_I2S_SLOT_MASK) ? + DEFAULT_I2S_SLOT_MASK : rx_mask; return 0; } @@ -349,37 +314,40 @@ static int tegra210_i2s_set_dai_bclk_ratio(struct snd_soc_dai *dai, return 0; } -static int tegra210_i2s_get_format(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) +static int tegra210_i2s_get_control(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) { - struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol); - struct tegra210_i2s *i2s = snd_soc_codec_get_drvdata(codec); + struct snd_soc_component *compnt = snd_soc_kcontrol_component(kcontrol); + struct tegra210_i2s *i2s = snd_soc_component_get_drvdata(compnt); long *uctl_val = &ucontrol->value.integer.value[0]; - /* get the format control flag */ - if (strstr(kcontrol->id.name, "Playback Audio Bit Format")) + if (strstr(kcontrol->id.name, "Loopback")) + *uctl_val = i2s->loopback; + else if (strstr(kcontrol->id.name, "Sample Rate")) + *uctl_val = i2s->srate_override; + else if (strstr(kcontrol->id.name, "FSYNC Width")) + *uctl_val = i2s->fsync_width; + else if (strstr(kcontrol->id.name, "Playback Audio Bit Format")) *uctl_val = i2s->audio_fmt_override[I2S_RX_PATH]; else if (strstr(kcontrol->id.name, "Capture Audio Bit Format")) *uctl_val = i2s->audio_fmt_override[I2S_TX_PATH]; - else if (strstr(kcontrol->id.name, "codec")) - *uctl_val = i2s->codec_bit_format; - else if (strstr(kcontrol->id.name, "Sample Rate")) - *uctl_val = i2s->sample_rate_via_control; + else if (strstr(kcontrol->id.name, "Client Bit Format")) + *uctl_val = i2s->client_fmt_override; else if (strstr(kcontrol->id.name, "Playback Audio Channels")) *uctl_val = i2s->audio_ch_override[I2S_RX_PATH]; else if (strstr(kcontrol->id.name, "Capture Audio Channels")) *uctl_val = i2s->audio_ch_override[I2S_TX_PATH]; else if (strstr(kcontrol->id.name, "Client Channels")) *uctl_val = i2s->client_ch_override; - else if (strstr(kcontrol->id.name, "Capture stereo to mono")) + else if (strstr(kcontrol->id.name, "Capture Stereo To Mono")) *uctl_val = i2s->stereo_to_mono[I2S_TX_PATH]; - else if (strstr(kcontrol->id.name, "Capture mono to stereo")) + else if (strstr(kcontrol->id.name, "Capture Mono To Stereo")) *uctl_val = i2s->mono_to_stereo[I2S_TX_PATH]; - else if (strstr(kcontrol->id.name, "Playback stereo to mono")) + else if (strstr(kcontrol->id.name, "Playback Stereo To Mono")) *uctl_val = i2s->stereo_to_mono[I2S_RX_PATH]; - else if (strstr(kcontrol->id.name, "Playback mono to stereo")) + else if (strstr(kcontrol->id.name, "Playback Mono To Stereo")) *uctl_val = i2s->mono_to_stereo[I2S_RX_PATH]; - else if (strstr(kcontrol->id.name, "Playback FIFO threshold")) + else if (strstr(kcontrol->id.name, "Playback FIFO Threshold")) *uctl_val = i2s->rx_fifo_th; else if (strstr(kcontrol->id.name, "BCLK Ratio")) *uctl_val = i2s->bclk_ratio; @@ -387,43 +355,62 @@ static int tegra210_i2s_get_format(struct snd_kcontrol *kcontrol, return 0; } -static int tegra210_i2s_put_format(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) +static int tegra210_i2s_put_control(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) { - struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol); - struct tegra210_i2s *i2s = snd_soc_codec_get_drvdata(codec); + struct snd_soc_component *compnt = snd_soc_kcontrol_component(kcontrol); + struct tegra210_i2s *i2s = snd_soc_component_get_drvdata(compnt); int value = ucontrol->value.integer.value[0]; - /* set the format control flag */ - if (strstr(kcontrol->id.name, "Playback Audio Bit Format")) + if (strstr(kcontrol->id.name, "Loopback")) { + i2s->loopback = value; + + regmap_update_bits(i2s->regmap, TEGRA210_I2S_CTRL, + I2S_CTRL_LPBK_MASK, + i2s->loopback << I2S_CTRL_LPBK_SHIFT); + + } else if (strstr(kcontrol->id.name, "Sample Rate")) { + i2s->srate_override = value; + } else if (strstr(kcontrol->id.name, "FSYNC Width")) { + /* + * Frame sync width is used only for FSYNC modes and not + * applicable for LRCK modes. Reset value for this field is "0", + * which means the width is one bit clock wide. + * The width requirement may depend on the codec and in such + * cases mixer control is used to update custom values. A value + * of "N" here means, width is "N + 1" bit clock wide. + */ + i2s->fsync_width = value; + + regmap_update_bits(i2s->regmap, TEGRA210_I2S_CTRL, + I2S_CTRL_FSYNC_WIDTH_MASK, + i2s->fsync_width << I2S_FSYNC_WIDTH_SHIFT); + + } else if (strstr(kcontrol->id.name, "Playback Audio Bit Format")) { i2s->audio_fmt_override[I2S_RX_PATH] = value; - else if (strstr(kcontrol->id.name, "Capture Audio Bit Format")) + } else if (strstr(kcontrol->id.name, "Capture Audio Bit Format")) { i2s->audio_fmt_override[I2S_TX_PATH] = value; - else if (strstr(kcontrol->id.name, "codec")) - i2s->codec_bit_format = value; - else if (strstr(kcontrol->id.name, "Sample Rate")) - i2s->sample_rate_via_control = value; - else if (strstr(kcontrol->id.name, "Playback Audio Channels")) + } else if (strstr(kcontrol->id.name, "Client Bit Format")) { + i2s->client_fmt_override = value; + } else if (strstr(kcontrol->id.name, "Playback Audio Channels")) { i2s->audio_ch_override[I2S_RX_PATH] = value; - else if (strstr(kcontrol->id.name, "Capture Audio Channels")) + } else if (strstr(kcontrol->id.name, "Capture Audio Channels")) { i2s->audio_ch_override[I2S_TX_PATH] = value; - else if (strstr(kcontrol->id.name, "Client Channels")) + } else if (strstr(kcontrol->id.name, "Client Channels")) { i2s->client_ch_override = value; - else if (strstr(kcontrol->id.name, "Capture stereo to mono")) + } else if (strstr(kcontrol->id.name, "Capture Stereo To Mono")) { i2s->stereo_to_mono[I2S_TX_PATH] = value; - else if (strstr(kcontrol->id.name, "Capture mono to stereo")) + } else if (strstr(kcontrol->id.name, "Capture Mono To Stereo")) { i2s->mono_to_stereo[I2S_TX_PATH] = value; - else if (strstr(kcontrol->id.name, "Playback stereo to mono")) + } else if (strstr(kcontrol->id.name, "Playback Stereo To Mono")) { i2s->stereo_to_mono[I2S_RX_PATH] = value; - else if (strstr(kcontrol->id.name, "Playback mono to stereo")) + } else if (strstr(kcontrol->id.name, "Playback Mono To Stereo")) { i2s->mono_to_stereo[I2S_RX_PATH] = value; - else if (strstr(kcontrol->id.name, "Playback FIFO threshold")) { - if (value >= 0 && value < TEGRA210_I2S_RX_FIFO_DEPTH) - i2s->rx_fifo_th = value; - else - return -EINVAL; - } else if (strstr(kcontrol->id.name, "BCLK Ratio")) + } else if (strstr(kcontrol->id.name, "Playback FIFO Threshold")) { + i2s->rx_fifo_th = value; + } else if (strstr(kcontrol->id.name, "BCLK Ratio")) { i2s->bclk_ratio = value; + } return 0; } @@ -434,75 +421,27 @@ static const char * const tegra210_i2s_format_text[] = { "32", }; -static const int tegra210_cif_fmt[] = { +static const unsigned int tegra210_cif_fmt[] = { 0, - TEGRA210_AUDIOCIF_BITS_16, - TEGRA210_AUDIOCIF_BITS_32, + TEGRA_ACIF_BITS_16, + TEGRA_ACIF_BITS_32, }; -static const int tegra210_i2s_bit_fmt[] = { +static const unsigned int tegra210_i2s_bit_fmt[] = { 0, - TEGRA210_I2S_CTRL_BIT_SIZE_16, - TEGRA210_I2S_CTRL_BIT_SIZE_32, + I2S_BITS_16, + I2S_BITS_32, }; -static const int tegra210_i2s_sample_size[] = { +static const unsigned int tegra210_i2s_sample_size[] = { 0, 16, 32, }; static const struct soc_enum tegra210_i2s_format_enum = - SOC_ENUM_SINGLE(SND_SOC_NOPM, 0, - ARRAY_SIZE(tegra210_i2s_format_text), - tegra210_i2s_format_text); - -static int tegra210_i2s_startup(struct snd_pcm_substream *substream, - struct snd_soc_dai *dai) -{ - struct device *dev = dai->dev; - struct tegra210_i2s *i2s = dev_get_drvdata(dev); - int ret; - - if (!(tegra_platform_is_unit_fpga() || tegra_platform_is_fpga()) && - !i2s->loopback) { - if (i2s->prod_name != NULL) { - ret = tegra_pinctrl_config_prod(dev, i2s->prod_name); - if (ret < 0) { - dev_warn(dev, "Failed to set %s setting\n", - i2s->prod_name); - } - } - - if (i2s->num_supplies > 0) { - ret = regulator_bulk_enable(i2s->num_supplies, - i2s->supplies); - if (ret < 0) - dev_err(dev, "failed to enable i2s io regulator\n"); - } - } - - return 0; -} - -static void tegra210_i2s_shutdown(struct snd_pcm_substream *substream, - struct snd_soc_dai *dai) -{ - struct device *dev = dai->dev; - struct tegra210_i2s *i2s = dev_get_drvdata(dev); - int ret; - - if (!(tegra_platform_is_unit_fpga() || tegra_platform_is_fpga())) { - if (i2s->num_supplies > 0) { - ret = regulator_bulk_disable(i2s->num_supplies, - i2s->supplies); - if (ret < 0) { - dev_err(dev, - "failed to disable i2s io regulator\n"); - } - } - } -} + SOC_ENUM_SINGLE(0, 0, ARRAY_SIZE(tegra210_i2s_format_text), + tegra210_i2s_format_text); static int tegra210_i2s_set_timing_params(struct device *dev, unsigned int sample_size, @@ -511,22 +450,22 @@ static int tegra210_i2s_set_timing_params(struct device *dev, { struct tegra210_i2s *i2s = dev_get_drvdata(dev); unsigned int val, bit_count, bclk_rate, num_bclk = sample_size; - int ret; + int err; if (i2s->bclk_ratio) num_bclk *= i2s->bclk_ratio; - if (i2s->format == SND_SOC_DAIFMT_RIGHT_J) + if (i2s->dai_fmt == SND_SOC_DAIFMT_RIGHT_J) tegra210_i2s_set_data_offset(i2s, num_bclk - sample_size); /* I2S bit clock rate */ bclk_rate = srate * channels * num_bclk; - ret = tegra210_i2s_set_clock_rate(dev, bclk_rate); - if (ret) { - dev_err(dev, "Can't set I2S bit clock rate for %u, err: %d\n", - bclk_rate, ret); - return ret; + err = tegra210_i2s_set_clock_rate(dev, bclk_rate); + if (err) { + dev_err(dev, "can't set I2S bit clock rate %u, err: %d\n", + bclk_rate, err); + return err; } regmap_read(i2s->regmap, TEGRA210_I2S_CTRL, &val); @@ -538,28 +477,28 @@ static int tegra210_i2s_set_timing_params(struct device *dev, * mode or the number of bit clocks in one TDM frame. * */ - switch (val & TEGRA210_I2S_CTRL_FRAME_FORMAT_MASK) { - case TEGRA210_I2S_CTRL_FRAME_FORMAT_LRCK_MODE: + switch (val & I2S_CTRL_FRAME_FMT_MASK) { + case I2S_CTRL_FRAME_FMT_LRCK_MODE: bit_count = (bclk_rate / (srate * 2)) - 1; break; - case TEGRA210_I2S_CTRL_FRAME_FORMAT_FSYNC_MODE: + case I2S_CTRL_FRAME_FMT_FSYNC_MODE: bit_count = (bclk_rate / srate) - 1; tegra210_i2s_set_slot_ctrl(i2s->regmap, channels, i2s->tx_mask, i2s->rx_mask); break; default: - dev_err(dev, "invalid I2S mode\n"); + dev_err(dev, "invalid I2S frame format\n"); return -EINVAL; } - if (bit_count > TEGRA210_I2S_TIMING_CHANNEL_BIT_CNT_MASK) { - dev_err(dev, "invalid channel bit count %u\n", bit_count); + if (bit_count > I2S_TIMING_CH_BIT_CNT_MASK) { + dev_err(dev, "invalid I2S channel bit count %u\n", bit_count); return -EINVAL; } regmap_write(i2s->regmap, TEGRA210_I2S_TIMING, - bit_count << TEGRA210_I2S_TIMING_CHANNEL_BIT_CNT_SHIFT); + bit_count << I2S_TIMING_CH_BIT_CNT_SHIFT); return 0; } @@ -571,58 +510,61 @@ static int tegra210_i2s_hw_params(struct snd_pcm_substream *substream, struct device *dev = dai->dev; struct tegra210_i2s *i2s = snd_soc_dai_get_drvdata(dai); unsigned int sample_size, channels, srate, val, reg, path; - struct tegra210_xbar_cif_conf cif_conf; - int ret, max_th; + struct tegra_cif_conf cif_conf; - memset(&cif_conf, 0, sizeof(struct tegra210_xbar_cif_conf)); + memset(&cif_conf, 0, sizeof(struct tegra_cif_conf)); channels = params_channels(params); if (channels < 1) { - dev_err(dev, "Doesn't support %d channels\n", channels); + dev_err(dev, "invalid I2S %d channel configuration\n", + channels); return -EINVAL; } - cif_conf.audio_channels = channels; - cif_conf.client_channels = channels; + cif_conf.audio_ch = channels; + cif_conf.client_ch = channels; switch (params_format(params)) { case SNDRV_PCM_FORMAT_S8: - val = TEGRA210_I2S_CTRL_BIT_SIZE_8; + val = I2S_BITS_8; sample_size = 8; - cif_conf.audio_bits = TEGRA210_AUDIOCIF_BITS_8; - cif_conf.client_bits = TEGRA210_AUDIOCIF_BITS_8; + cif_conf.audio_bits = TEGRA_ACIF_BITS_8; + cif_conf.client_bits = TEGRA_ACIF_BITS_8; break; case SNDRV_PCM_FORMAT_S16_LE: - val = TEGRA210_I2S_CTRL_BIT_SIZE_16; + val = I2S_BITS_16; sample_size = 16; - cif_conf.audio_bits = TEGRA210_AUDIOCIF_BITS_16; - cif_conf.client_bits = TEGRA210_AUDIOCIF_BITS_16; + cif_conf.audio_bits = TEGRA_ACIF_BITS_16; + cif_conf.client_bits = TEGRA_ACIF_BITS_16; break; case SNDRV_PCM_FORMAT_S32_LE: - val = TEGRA210_I2S_CTRL_BIT_SIZE_32; + val = I2S_BITS_32; sample_size = 32; - cif_conf.audio_bits = TEGRA210_AUDIOCIF_BITS_32; - cif_conf.client_bits = TEGRA210_AUDIOCIF_BITS_32; + cif_conf.audio_bits = TEGRA_ACIF_BITS_32; + cif_conf.client_bits = TEGRA_ACIF_BITS_32; break; default: - dev_err(dev, "Wrong format!\n"); - return -EINVAL; + dev_err(dev, "unsupported format!\n"); + return -ENOTSUPP; } - if (i2s->codec_bit_format) { - val = tegra210_i2s_bit_fmt[i2s->codec_bit_format]; - sample_size = tegra210_i2s_sample_size[i2s->codec_bit_format]; + if (i2s->client_fmt_override) { + val = tegra210_i2s_bit_fmt[i2s->client_fmt_override]; + sample_size = + tegra210_i2s_sample_size[i2s->client_fmt_override]; cif_conf.client_bits = - tegra210_cif_fmt[i2s->codec_bit_format]; + tegra210_cif_fmt[i2s->client_fmt_override]; } + /* Program sample size */ regmap_update_bits(i2s->regmap, TEGRA210_I2S_CTRL, - TEGRA210_I2S_CTRL_BIT_SIZE_MASK, val); + I2S_CTRL_BIT_SIZE_MASK, val); srate = params_rate(params); - if (i2s->sample_rate_via_control) - srate = i2s->sample_rate_via_control; + /* Override rate, channel and audio bit params as applicable */ + if (i2s->srate_override) + srate = i2s->srate_override; /* * For playback I2S RX-CIF and for capture TX-CIF is used. @@ -633,55 +575,56 @@ static int tegra210_i2s_hw_params(struct snd_pcm_substream *substream, I2S_RX_PATH : I2S_TX_PATH; if (i2s->audio_ch_override[path]) - cif_conf.audio_channels = i2s->audio_ch_override[path]; + cif_conf.audio_ch = i2s->audio_ch_override[path]; if (i2s->client_ch_override) - cif_conf.client_channels = i2s->client_ch_override; + cif_conf.client_ch = i2s->client_ch_override; if (i2s->audio_fmt_override[path]) cif_conf.audio_bits = tegra210_cif_fmt[i2s->audio_fmt_override[path]]; - /* As a COCEC DAI, CAPTURE is transmit */ if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) { - unsigned int audio_ch = cif_conf.audio_channels; + unsigned int max_th; - reg = TEGRA210_I2S_AXBAR_RX_CIF_CTRL; + /* FIFO threshold in terms of frames */ + max_th = (I2S_RX_FIFO_DEPTH / cif_conf.audio_ch) - 1; - /* RX FIFO threshold interms of frames */ - max_th = (TEGRA210_I2S_RX_FIFO_DEPTH / audio_ch) - 1; - if (max_th < 0) - return -EINVAL; - - if (i2s->rx_fifo_th > max_th) /* error handling */ + if (i2s->rx_fifo_th > max_th) i2s->rx_fifo_th = max_th; cif_conf.threshold = i2s->rx_fifo_th; - } else - reg = TEGRA210_I2S_AXBAR_TX_CIF_CTRL; - cif_conf.stereo_conv = i2s->stereo_to_mono[path]; + reg = TEGRA210_I2S_RX_CIF_CTRL; + } else { + reg = TEGRA210_I2S_TX_CIF_CTRL; + } + cif_conf.mono_conv = i2s->mono_to_stereo[path]; + cif_conf.stereo_conv = i2s->stereo_to_mono[path]; - tegra210_xbar_set_cif(i2s->regmap, reg, &cif_conf); + tegra_set_cif(i2s->regmap, reg, &cif_conf); - ret = tegra210_i2s_set_timing_params(dev, sample_size, srate, - cif_conf.client_channels); - if (ret < 0) - return ret; - - return 0; + return tegra210_i2s_set_timing_params(dev, sample_size, srate, + cif_conf.client_ch); } -static struct snd_soc_dai_ops tegra210_i2s_dai_ops = { +static const struct snd_soc_dai_ops tegra210_i2s_dai_ops = { .set_fmt = tegra210_i2s_set_fmt, .hw_params = tegra210_i2s_hw_params, .set_bclk_ratio = tegra210_i2s_set_dai_bclk_ratio, .set_tdm_slot = tegra210_i2s_set_tdm_slot, - .startup = tegra210_i2s_startup, - .shutdown = tegra210_i2s_shutdown, }; +/* + * Three DAIs are exposed + * 1. "CIF" DAI for connecting with XBAR + * 2. "DAP" DAI for connecting with CODEC + * 3. "DUMMY" can be used when no external codec connection is + * available. In such case "DAP" is connected with "DUMMY". + * Order of these DAIs should not be changed, since DAI links in DT refer + * to these DAIs depending on the index. + */ static struct snd_soc_dai_driver tegra210_i2s_dais[] = { { .name = "CIF", @@ -750,89 +693,6 @@ static struct snd_soc_dai_driver tegra210_i2s_dais[] = { }, }; -static int tegra210_i2s_loopback_get(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) -{ - struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol); - struct tegra210_i2s *i2s = snd_soc_codec_get_drvdata(codec); - - ucontrol->value.integer.value[0] = i2s->loopback; - - return 0; -} - -static int tegra210_i2s_loopback_put(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) -{ - struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol); - struct tegra210_i2s *i2s = snd_soc_codec_get_drvdata(codec); - - i2s->loopback = ucontrol->value.integer.value[0]; - - regmap_update_bits(i2s->regmap, TEGRA210_I2S_CTRL, - TEGRA210_I2S_CTRL_LPBK_MASK, - i2s->loopback << TEGRA210_I2S_CTRL_LPBK_SHIFT); - - return 0; -} - -static int tegra210_i2s_get_bclk_ratio(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) -{ - struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol); - struct tegra210_i2s *i2s = snd_soc_codec_get_drvdata(codec); - - ucontrol->value.integer.value[0] = i2s->bclk_ratio; - - return 0; -} - -static int tegra210_i2s_put_bclk_ratio(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) -{ - struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol); - struct tegra210_i2s *i2s = snd_soc_codec_get_drvdata(codec); - - i2s->bclk_ratio = ucontrol->value.integer.value[0]; - - return 0; -} - -static int tegra210_i2s_fsync_width_get(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) -{ - struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol); - struct tegra210_i2s *i2s = snd_soc_codec_get_drvdata(codec); - - ucontrol->value.integer.value[0] = i2s->fsync_width; - - return 0; -} - -static int tegra210_i2s_fsync_width_put(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) -{ - struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol); - struct tegra210_i2s *i2s = snd_soc_codec_get_drvdata(codec); - - i2s->fsync_width = ucontrol->value.integer.value[0]; - - /* - * frame sync width is used only for FSYNC modes and not applicable - * for LRCK modes. Reset value for this field is "0", which means - * the width is one bit clock wide. The width requirement may depend - * on the codec and in such cases mixer control is used to update - * custom values. A value of "N" here means, width is "N + 1" bit - * clock wide. - */ - regmap_update_bits(i2s->regmap, TEGRA210_I2S_CTRL, - TEGRA210_I2S_CTRL_FSYNC_WIDTH_MASK, - i2s->fsync_width << - TEGRA210_I2S_CTRL_FSYNC_WIDTH_SHIFT); - - return 0; -} - static const char * const tegra210_i2s_stereo_conv_text[] = { "CH0", "CH1", "AVG", }; @@ -842,131 +702,89 @@ static const char * const tegra210_i2s_mono_conv_text[] = { }; static const struct soc_enum tegra210_i2s_mono_conv_enum = - SOC_ENUM_SINGLE(SND_SOC_NOPM, 0, - ARRAY_SIZE(tegra210_i2s_mono_conv_text), - tegra210_i2s_mono_conv_text); + SOC_ENUM_SINGLE(0, 0, ARRAY_SIZE(tegra210_i2s_mono_conv_text), + tegra210_i2s_mono_conv_text); static const struct soc_enum tegra210_i2s_stereo_conv_enum = - SOC_ENUM_SINGLE(SND_SOC_NOPM, 0, - ARRAY_SIZE(tegra210_i2s_stereo_conv_text), - tegra210_i2s_stereo_conv_text); - -#define NV_SOC_SINGLE_RANGE_EXT(xname, xmin, xmax, xget, xput) \ -{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = (xname), \ - .info = snd_soc_info_xr_sx, .get = xget, .put = xput, \ - .private_value = (unsigned long)&(struct soc_mixer_control) \ - {.invert = 0, .min = xmin, .max = xmax, \ - .platform_max = xmax}} + SOC_ENUM_SINGLE(0, 0, ARRAY_SIZE(tegra210_i2s_stereo_conv_text), + tegra210_i2s_stereo_conv_text); static const struct snd_kcontrol_new tegra210_i2s_controls[] = { - SOC_SINGLE_EXT("Loopback", SND_SOC_NOPM, 0, 1, 0, - tegra210_i2s_loopback_get, tegra210_i2s_loopback_put), + SOC_SINGLE_EXT("Loopback", 0, 0, 1, 0, tegra210_i2s_get_control, + tegra210_i2s_put_control), + SOC_SINGLE_EXT("FSYNC Width", 0, 0, 255, 0, tegra210_i2s_get_control, + tegra210_i2s_put_control), + SOC_SINGLE_EXT("Sample Rate", 0, 0, 192000, 0, tegra210_i2s_get_control, + tegra210_i2s_put_control), SOC_ENUM_EXT("Playback Audio Bit Format", tegra210_i2s_format_enum, - tegra210_i2s_get_format, tegra210_i2s_put_format), + tegra210_i2s_get_control, tegra210_i2s_put_control), SOC_ENUM_EXT("Capture Audio Bit Format", tegra210_i2s_format_enum, - tegra210_i2s_get_format, tegra210_i2s_put_format), - SOC_ENUM_EXT("codec bit format", tegra210_i2s_format_enum, - tegra210_i2s_get_format, tegra210_i2s_put_format), - SOC_SINGLE_EXT("fsync width", SND_SOC_NOPM, 0, 255, 0, - tegra210_i2s_fsync_width_get, tegra210_i2s_fsync_width_put), - SOC_SINGLE_EXT("Sample Rate", 0, 0, 192000, 0, - tegra210_i2s_get_format, tegra210_i2s_put_format), + tegra210_i2s_get_control, tegra210_i2s_put_control), + SOC_ENUM_EXT("Client Bit Format", tegra210_i2s_format_enum, + tegra210_i2s_get_control, tegra210_i2s_put_control), SOC_SINGLE_EXT("Playback Audio Channels", 0, 0, 16, 0, - tegra210_i2s_get_format, tegra210_i2s_put_format), + tegra210_i2s_get_control, tegra210_i2s_put_control), SOC_SINGLE_EXT("Capture Audio Channels", 0, 0, 16, 0, - tegra210_i2s_get_format, tegra210_i2s_put_format), + tegra210_i2s_get_control, tegra210_i2s_put_control), SOC_SINGLE_EXT("Client Channels", 0, 0, 16, 0, - tegra210_i2s_get_format, tegra210_i2s_put_format), - SOC_SINGLE_EXT("BCLK Ratio", SND_SOC_NOPM, 0, INT_MAX, 0, - tegra210_i2s_get_bclk_ratio, - tegra210_i2s_put_bclk_ratio), - SOC_ENUM_EXT("Capture stereo to mono conv", - tegra210_i2s_stereo_conv_enum, tegra210_i2s_get_format, - tegra210_i2s_put_format), - SOC_ENUM_EXT("Capture mono to stereo conv", - tegra210_i2s_mono_conv_enum, tegra210_i2s_get_format, - tegra210_i2s_put_format), - SOC_ENUM_EXT("Playback stereo to mono conv", - tegra210_i2s_stereo_conv_enum, tegra210_i2s_get_format, - tegra210_i2s_put_format), - SOC_ENUM_EXT("Playback mono to stereo conv", - tegra210_i2s_mono_conv_enum, tegra210_i2s_get_format, - tegra210_i2s_put_format), - NV_SOC_SINGLE_RANGE_EXT("Playback FIFO threshold", 0, - TEGRA210_I2S_RX_FIFO_DEPTH - 1, - tegra210_i2s_get_format, - tegra210_i2s_put_format), + tegra210_i2s_get_control, tegra210_i2s_put_control), + SOC_ENUM_EXT("Capture Stereo To Mono", tegra210_i2s_stereo_conv_enum, + tegra210_i2s_get_control, tegra210_i2s_put_control), + SOC_ENUM_EXT("Capture Mono To Stereo", tegra210_i2s_mono_conv_enum, + tegra210_i2s_get_control, tegra210_i2s_put_control), + SOC_ENUM_EXT("Playback Stereo To Mono", tegra210_i2s_stereo_conv_enum, + tegra210_i2s_get_control, tegra210_i2s_put_control), + SOC_ENUM_EXT("Playback Mono To Stereo", tegra210_i2s_mono_conv_enum, + tegra210_i2s_get_control, tegra210_i2s_put_control), + SOC_SINGLE_EXT("Playback FIFO Threshold", 0, 0, I2S_RX_FIFO_DEPTH - 1, + 0, tegra210_i2s_get_control, tegra210_i2s_put_control), + SOC_SINGLE_EXT("BCLK Ratio", 0, 0, INT_MAX, 0, tegra210_i2s_get_control, + tegra210_i2s_put_control), }; static const struct snd_soc_dapm_widget tegra210_i2s_widgets[] = { - SND_SOC_DAPM_AIF_IN("CIF RX", NULL, 0, SND_SOC_NOPM, - 0, 0), - SND_SOC_DAPM_AIF_OUT("CIF TX", NULL, 0, SND_SOC_NOPM, - 0, 0), - SND_SOC_DAPM_AIF_IN_E("DAP RX", NULL, 0, TEGRA210_I2S_AXBAR_TX_ENABLE, - TEGRA210_I2S_AXBAR_TX_EN_SHIFT, 0, - tegra210_i2s_init, SND_SOC_DAPM_PRE_PMU), - SND_SOC_DAPM_AIF_OUT_E("DAP TX", NULL, 0, TEGRA210_I2S_AXBAR_RX_ENABLE, - TEGRA210_I2S_AXBAR_RX_EN_SHIFT, 0, - tegra210_i2s_init, SND_SOC_DAPM_PRE_PMU), + SND_SOC_DAPM_AIF_IN("CIF RX", NULL, 0, SND_SOC_NOPM, 0, 0), + SND_SOC_DAPM_AIF_OUT("CIF TX", NULL, 0, SND_SOC_NOPM, 0, 0), + SND_SOC_DAPM_AIF_IN_E("DAP RX", NULL, 0, TEGRA210_I2S_TX_ENABLE, + 0, 0, tegra210_i2s_init, SND_SOC_DAPM_PRE_PMU), + SND_SOC_DAPM_AIF_OUT_E("DAP TX", NULL, 0, TEGRA210_I2S_RX_ENABLE, + 0, 0, tegra210_i2s_init, SND_SOC_DAPM_PRE_PMU), SND_SOC_DAPM_MIC("Dummy Input", NULL), SND_SOC_DAPM_SPK("Dummy Output", NULL), }; static const struct snd_soc_dapm_route tegra210_i2s_routes[] = { - { "CIF RX", NULL, "CIF Receive" }, - { "DAP TX", NULL, "CIF RX" }, + { "CIF RX", NULL, "CIF Receive" }, + { "DAP TX", NULL, "CIF RX" }, { "DAP Transmit", NULL, "DAP TX" }, - { "DAP RX", NULL, "DAP Receive" }, - { "CIF TX", NULL, "DAP RX" }, + { "DAP RX", NULL, "DAP Receive" }, + { "CIF TX", NULL, "DAP RX" }, { "CIF Transmit", NULL, "CIF TX" }, - {"Dummy Capture", NULL, "Dummy Input"}, - {"Dummy Output", NULL, "Dummy Playback"}, + { "Dummy Capture", NULL, "Dummy Input" }, + { "Dummy Output", NULL, "Dummy Playback" }, }; -static struct snd_soc_codec_driver tegra210_i2s_codec = { - .idle_bias_off = 1, - .component_driver = { - .dapm_widgets = tegra210_i2s_widgets, - .num_dapm_widgets = ARRAY_SIZE(tegra210_i2s_widgets), - .dapm_routes = tegra210_i2s_routes, - .num_dapm_routes = ARRAY_SIZE(tegra210_i2s_routes), - .controls = tegra210_i2s_controls, - .num_controls = ARRAY_SIZE(tegra210_i2s_controls), - }, +static const struct snd_soc_component_driver tegra210_i2s_cmpnt = { + .dapm_widgets = tegra210_i2s_widgets, + .num_dapm_widgets = ARRAY_SIZE(tegra210_i2s_widgets), + .dapm_routes = tegra210_i2s_routes, + .num_dapm_routes = ARRAY_SIZE(tegra210_i2s_routes), + .controls = tegra210_i2s_controls, + .num_controls = ARRAY_SIZE(tegra210_i2s_controls), + .non_legacy_dai_naming = 1, }; static bool tegra210_i2s_wr_reg(struct device *dev, unsigned int reg) { switch (reg) { - case TEGRA210_I2S_AXBAR_RX_ENABLE: - case TEGRA210_I2S_AXBAR_RX_SOFT_RESET: - case TEGRA210_I2S_AXBAR_RX_INT_MASK: - case TEGRA210_I2S_AXBAR_RX_INT_SET: - case TEGRA210_I2S_AXBAR_RX_INT_CLEAR: - case TEGRA210_I2S_AXBAR_RX_CIF_CTRL: - case TEGRA210_I2S_AXBAR_RX_CTRL: - case TEGRA210_I2S_AXBAR_RX_SLOT_CTRL: - case TEGRA210_I2S_AXBAR_RX_CLK_TRIM: - case TEGRA210_I2S_AXBAR_TX_ENABLE: - case TEGRA210_I2S_AXBAR_TX_SOFT_RESET: - case TEGRA210_I2S_AXBAR_TX_INT_MASK: - case TEGRA210_I2S_AXBAR_TX_INT_SET: - case TEGRA210_I2S_AXBAR_TX_INT_CLEAR: - case TEGRA210_I2S_AXBAR_TX_CIF_CTRL: - case TEGRA210_I2S_AXBAR_TX_CTRL: - case TEGRA210_I2S_AXBAR_TX_SLOT_CTRL: - case TEGRA210_I2S_AXBAR_TX_CLK_TRIM: - case TEGRA210_I2S_ENABLE: - case TEGRA210_I2S_SOFT_RESET: - case TEGRA210_I2S_CG: - case TEGRA210_I2S_CTRL: - case TEGRA210_I2S_TIMING: - case TEGRA210_I2S_SLOT_CTRL: - case TEGRA210_I2S_CLK_TRIM: - case TEGRA210_I2S_CYA: + case TEGRA210_I2S_RX_ENABLE ... TEGRA210_I2S_RX_SOFT_RESET: + case TEGRA210_I2S_RX_INT_MASK ... TEGRA210_I2S_RX_CLK_TRIM: + case TEGRA210_I2S_TX_ENABLE ... TEGRA210_I2S_TX_SOFT_RESET: + case TEGRA210_I2S_TX_INT_MASK ... TEGRA210_I2S_TX_CLK_TRIM: + case TEGRA210_I2S_ENABLE ... TEGRA210_I2S_CG: + case TEGRA210_I2S_CTRL ... TEGRA210_I2S_CYA: return true; default: return false; @@ -975,41 +793,18 @@ static bool tegra210_i2s_wr_reg(struct device *dev, unsigned int reg) static bool tegra210_i2s_rd_reg(struct device *dev, unsigned int reg) { + if (tegra210_i2s_wr_reg(dev, reg)) + return true; + switch (reg) { - case TEGRA210_I2S_AXBAR_RX_STATUS: - case TEGRA210_I2S_AXBAR_RX_CIF_FIFO_STATUS: - case TEGRA210_I2S_AXBAR_RX_ENABLE: - case TEGRA210_I2S_AXBAR_RX_INT_MASK: - case TEGRA210_I2S_AXBAR_RX_INT_SET: - case TEGRA210_I2S_AXBAR_RX_INT_CLEAR: - case TEGRA210_I2S_AXBAR_RX_CIF_CTRL: - case TEGRA210_I2S_AXBAR_RX_CTRL: - case TEGRA210_I2S_AXBAR_RX_SLOT_CTRL: - case TEGRA210_I2S_AXBAR_RX_CLK_TRIM: - case TEGRA210_I2S_AXBAR_RX_INT_STATUS: - case TEGRA210_I2S_AXBAR_RX_SOFT_RESET: - case TEGRA210_I2S_AXBAR_TX_STATUS: - case TEGRA210_I2S_AXBAR_TX_CIF_FIFO_STATUS: - case TEGRA210_I2S_AXBAR_TX_ENABLE: - case TEGRA210_I2S_AXBAR_TX_INT_MASK: - case TEGRA210_I2S_AXBAR_TX_INT_SET: - case TEGRA210_I2S_AXBAR_TX_INT_CLEAR: - case TEGRA210_I2S_AXBAR_TX_CIF_CTRL: - case TEGRA210_I2S_AXBAR_TX_CTRL: - case TEGRA210_I2S_AXBAR_TX_SLOT_CTRL: - case TEGRA210_I2S_AXBAR_TX_CLK_TRIM: - case TEGRA210_I2S_AXBAR_TX_INT_STATUS: - case TEGRA210_I2S_AXBAR_TX_SOFT_RESET: - case TEGRA210_I2S_ENABLE: + case TEGRA210_I2S_RX_STATUS: + case TEGRA210_I2S_RX_INT_STATUS: + case TEGRA210_I2S_RX_CIF_FIFO_STATUS: + case TEGRA210_I2S_TX_STATUS: + case TEGRA210_I2S_TX_INT_STATUS: + case TEGRA210_I2S_TX_CIF_FIFO_STATUS: case TEGRA210_I2S_STATUS: - case TEGRA210_I2S_SOFT_RESET: - case TEGRA210_I2S_CG: - case TEGRA210_I2S_CTRL: - case TEGRA210_I2S_TIMING: - case TEGRA210_I2S_SLOT_CTRL: - case TEGRA210_I2S_CLK_TRIM: case TEGRA210_I2S_INT_STATUS: - case TEGRA210_I2S_CYA: return true; default: return false; @@ -1019,13 +814,16 @@ static bool tegra210_i2s_rd_reg(struct device *dev, unsigned int reg) static bool tegra210_i2s_volatile_reg(struct device *dev, unsigned int reg) { switch (reg) { - case TEGRA210_I2S_AXBAR_RX_INT_STATUS: - case TEGRA210_I2S_AXBAR_RX_STATUS: - case TEGRA210_I2S_AXBAR_TX_STATUS: - case TEGRA210_I2S_AXBAR_TX_INT_STATUS: + case TEGRA210_I2S_RX_STATUS: + case TEGRA210_I2S_RX_INT_STATUS: + case TEGRA210_I2S_RX_CIF_FIFO_STATUS: + case TEGRA210_I2S_TX_STATUS: + case TEGRA210_I2S_TX_INT_STATUS: + case TEGRA210_I2S_TX_CIF_FIFO_STATUS: + case TEGRA210_I2S_STATUS: case TEGRA210_I2S_INT_STATUS: - case TEGRA210_I2S_AXBAR_RX_SOFT_RESET: - case TEGRA210_I2S_AXBAR_TX_SOFT_RESET: + case TEGRA210_I2S_RX_SOFT_RESET: + case TEGRA210_I2S_TX_SOFT_RESET: return true; default: return false; @@ -1033,131 +831,86 @@ static bool tegra210_i2s_volatile_reg(struct device *dev, unsigned int reg) } static const struct regmap_config tegra210_i2s_regmap_config = { - .reg_bits = 32, - .reg_stride = 4, - .val_bits = 32, - .max_register = TEGRA210_I2S_CYA, - .writeable_reg = tegra210_i2s_wr_reg, - .readable_reg = tegra210_i2s_rd_reg, - .volatile_reg = tegra210_i2s_volatile_reg, - .reg_defaults = tegra210_i2s_reg_defaults, - .num_reg_defaults = ARRAY_SIZE(tegra210_i2s_reg_defaults), - .cache_type = REGCACHE_FLAT, + .reg_bits = 32, + .reg_stride = 4, + .val_bits = 32, + .max_register = TEGRA210_I2S_CYA, + .writeable_reg = tegra210_i2s_wr_reg, + .readable_reg = tegra210_i2s_rd_reg, + .volatile_reg = tegra210_i2s_volatile_reg, + .reg_defaults = tegra210_i2s_reg_defaults, + .num_reg_defaults = ARRAY_SIZE(tegra210_i2s_reg_defaults), + .cache_type = REGCACHE_FLAT, }; static const struct of_device_id tegra210_i2s_of_match[] = { { .compatible = "nvidia,tegra210-i2s" }, {}, }; +MODULE_DEVICE_TABLE(of, tegra210_i2s_of_match); -static int tegra210_i2s_platform_probe(struct platform_device *pdev) +static int tegra210_i2s_probe(struct platform_device *pdev) { - const struct of_device_id *match; - struct device_node *np = pdev->dev.of_node; + struct device *dev = &pdev->dev; struct tegra210_i2s *i2s; - struct resource *mem; - struct property *prop; void __iomem *regs; - int ret = 0, count = 0, num_supplies; - const char *supply; + int err; - match = of_match_device(tegra210_i2s_of_match, &pdev->dev); - if (!match) { - dev_err(&pdev->dev, "Error: No device match found\n"); - return -ENODEV; - } - - i2s = devm_kzalloc(&pdev->dev, sizeof(*i2s), GFP_KERNEL); + i2s = devm_kzalloc(dev, sizeof(*i2s), GFP_KERNEL); if (!i2s) return -ENOMEM; - i2s->tx_mask = i2s->rx_mask = 0xFFFF; - i2s->loopback = 0; - i2s->prod_name = NULL; - /* default threshold settings */ - i2s->rx_fifo_th = 3; - dev_set_drvdata(&pdev->dev, i2s); + i2s->rx_fifo_th = DEFAULT_I2S_RX_FIFO_THRESHOLD; + i2s->tx_mask = DEFAULT_I2S_SLOT_MASK; + i2s->rx_mask = DEFAULT_I2S_SLOT_MASK; + i2s->loopback = false; - if (!(tegra_platform_is_unit_fpga() || tegra_platform_is_fpga())) { - i2s->clk_i2s = devm_clk_get(&pdev->dev, "i2s"); - if (IS_ERR(i2s->clk_i2s)) { - dev_err(&pdev->dev, "Can't retrieve i2s clock\n"); - return PTR_ERR(i2s->clk_i2s); - } - i2s->clk_sync_input = - devm_clk_get(&pdev->dev, "clk_sync_input"); - if (IS_ERR(i2s->clk_sync_input)) - dev_dbg(&pdev->dev, "Can't get i2s sync input clock\n"); + dev_set_drvdata(dev, i2s); + + i2s->clk_i2s = devm_clk_get(dev, "i2s"); + if (IS_ERR(i2s->clk_i2s)) { + dev_err(dev, "can't retrieve I2S bit clock\n"); + return PTR_ERR(i2s->clk_i2s); } - mem = platform_get_resource(pdev, IORESOURCE_MEM, 0); - regs = devm_ioremap_resource(&pdev->dev, mem); + /* + * Not an error, as this clock is needed only when some other I/O + * requires input clock from current I2S instance, which is + * configurable from DT. + */ + i2s->clk_sync_input = devm_clk_get(dev, "sync_input"); + if (IS_ERR(i2s->clk_sync_input)) + dev_dbg(dev, "can't retrieve I2S sync input clock\n"); + + regs = devm_platform_ioremap_resource(pdev, 0); if (IS_ERR(regs)) return PTR_ERR(regs); - i2s->regmap = devm_regmap_init_mmio(&pdev->dev, regs, + i2s->regmap = devm_regmap_init_mmio(dev, regs, &tegra210_i2s_regmap_config); if (IS_ERR(i2s->regmap)) { - dev_err(&pdev->dev, "regmap init failed\n"); + dev_err(dev, "regmap init failed\n"); return PTR_ERR(i2s->regmap); } + regcache_cache_only(i2s->regmap, true); - if (of_property_read_u32(pdev->dev.of_node, "bclk-ratio", - &i2s->bclk_ratio) < 0) { - dev_dbg(&pdev->dev, "Missing prop bclk-ratio for I2S\n"); - i2s->bclk_ratio = 1; + err = devm_snd_soc_register_component(dev, &tegra210_i2s_cmpnt, + tegra210_i2s_dais, + ARRAY_SIZE(tegra210_i2s_dais)); + if (err) { + dev_err(dev, "can't register I2S component, err: %d\n", err); + return err; } - if (!(tegra_platform_is_unit_fpga() || tegra_platform_is_fpga())) { - if (of_property_read_string(np, "prod-name", - &i2s->prod_name) == 0) - tegra_pinctrl_config_prod(&pdev->dev, i2s->prod_name); - - num_supplies = of_property_count_strings(np, - "regulator-supplies"); - if (num_supplies > 0) { - i2s->num_supplies = num_supplies; - i2s->supplies = devm_kzalloc(&pdev->dev, num_supplies * - sizeof(*i2s->supplies), - GFP_KERNEL); - if (!i2s->supplies) - return -ENOMEM; - - of_property_for_each_string(np, "regulator-supplies", - prop, supply) - i2s->supplies[count++].supply = supply; - - ret = devm_regulator_bulk_get(&pdev->dev, - i2s->num_supplies, - i2s->supplies); - if (ret) { - dev_err(&pdev->dev, - "Failed to get supplies: %d\n", ret); - return ret; - } - } - } - pm_runtime_enable(&pdev->dev); - ret = snd_soc_register_codec(&pdev->dev, &tegra210_i2s_codec, - tegra210_i2s_dais, - ARRAY_SIZE(tegra210_i2s_dais)); - if (ret != 0) { - dev_err(&pdev->dev, "Could not register CODEC: %d\n", ret); - pm_runtime_disable(&pdev->dev); - return ret; - } + pm_runtime_enable(dev); return 0; } -static int tegra210_i2s_platform_remove(struct platform_device *pdev) +static int tegra210_i2s_remove(struct platform_device *pdev) { - snd_soc_unregister_codec(&pdev->dev); - pm_runtime_disable(&pdev->dev); - if (!pm_runtime_status_suspended(&pdev->dev)) - tegra210_i2s_runtime_suspend(&pdev->dev); return 0; } @@ -1165,24 +918,21 @@ static int tegra210_i2s_platform_remove(struct platform_device *pdev) static const struct dev_pm_ops tegra210_i2s_pm_ops = { SET_RUNTIME_PM_OPS(tegra210_i2s_runtime_suspend, tegra210_i2s_runtime_resume, NULL) - SET_LATE_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend, - pm_runtime_force_resume) + SET_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend, + pm_runtime_force_resume) }; static struct platform_driver tegra210_i2s_driver = { .driver = { - .name = DRV_NAME, - .owner = THIS_MODULE, + .name = "tegra210-i2s", .of_match_table = tegra210_i2s_of_match, .pm = &tegra210_i2s_pm_ops, }, - .probe = tegra210_i2s_platform_probe, - .remove = tegra210_i2s_platform_remove, + .probe = tegra210_i2s_probe, + .remove = tegra210_i2s_remove, }; module_platform_driver(tegra210_i2s_driver) MODULE_AUTHOR("Songhee Baek "); -MODULE_DESCRIPTION("Tegra210 I2S ASoC driver"); -MODULE_LICENSE("GPL"); -MODULE_ALIAS("platform:" DRV_NAME); -MODULE_DEVICE_TABLE(of, tegra210_i2s_of_match); +MODULE_DESCRIPTION("Tegra210 ASoC I2S driver"); +MODULE_LICENSE("GPL v2"); diff --git a/sound/soc/tegra/tegra210_i2s.h b/sound/soc/tegra/tegra210_i2s.h index e3b0de7b..67454a24 100644 --- a/sound/soc/tegra/tegra210_i2s.h +++ b/sound/soc/tegra/tegra210_i2s.h @@ -1,185 +1,106 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ /* - * tegra210_i2s_alt.h - Definitions for Tegra210 I2S driver + * tegra210_i2s.h - Definitions for Tegra210 I2S driver * - * Copyright (c) 2014-2020 NVIDIA CORPORATION. All rights reserved. + * Copyright (c) 2020 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 . */ -#ifndef __TEGRA210_I2S_ALT_H__ -#define __TEGRA210_I2S_ALT_H__ +#ifndef __TEGRA210_I2S_H__ +#define __TEGRA210_I2S_H__ -/* Register offsets from TEGRA210_I2S*_BASE */ +/* Register offsets from I2S*_BASE */ +#define TEGRA210_I2S_RX_ENABLE 0x0 +#define TEGRA210_I2S_RX_SOFT_RESET 0x4 +#define TEGRA210_I2S_RX_STATUS 0x0c +#define TEGRA210_I2S_RX_INT_STATUS 0x10 +#define TEGRA210_I2S_RX_INT_MASK 0x14 +#define TEGRA210_I2S_RX_INT_SET 0x18 +#define TEGRA210_I2S_RX_INT_CLEAR 0x1c +#define TEGRA210_I2S_RX_CIF_CTRL 0x20 +#define TEGRA210_I2S_RX_CTRL 0x24 +#define TEGRA210_I2S_RX_SLOT_CTRL 0x28 +#define TEGRA210_I2S_RX_CLK_TRIM 0x2c +#define TEGRA210_I2S_RX_CYA 0x30 +#define TEGRA210_I2S_RX_CIF_FIFO_STATUS 0x34 +#define TEGRA210_I2S_TX_ENABLE 0x40 +#define TEGRA210_I2S_TX_SOFT_RESET 0x44 +#define TEGRA210_I2S_TX_STATUS 0x4c +#define TEGRA210_I2S_TX_INT_STATUS 0x50 +#define TEGRA210_I2S_TX_INT_MASK 0x54 +#define TEGRA210_I2S_TX_INT_SET 0x58 +#define TEGRA210_I2S_TX_INT_CLEAR 0x5c +#define TEGRA210_I2S_TX_CIF_CTRL 0x60 +#define TEGRA210_I2S_TX_CTRL 0x64 +#define TEGRA210_I2S_TX_SLOT_CTRL 0x68 +#define TEGRA210_I2S_TX_CLK_TRIM 0x6c +#define TEGRA210_I2S_TX_CYA 0x70 +#define TEGRA210_I2S_TX_CIF_FIFO_STATUS 0x74 +#define TEGRA210_I2S_ENABLE 0x80 +#define TEGRA210_I2S_SOFT_RESET 0x84 +#define TEGRA210_I2S_CG 0x88 +#define TEGRA210_I2S_STATUS 0x8c +#define TEGRA210_I2S_INT_STATUS 0x90 +#define TEGRA210_I2S_CTRL 0xa0 +#define TEGRA210_I2S_TIMING 0xa4 +#define TEGRA210_I2S_SLOT_CTRL 0xa8 +#define TEGRA210_I2S_CLK_TRIM 0xac +#define TEGRA210_I2S_CYA 0xb0 -#define TEGRA210_I2S_AXBAR_RX_ENABLE 0x0 -#define TEGRA210_I2S_AXBAR_RX_SOFT_RESET 0x4 -#define TEGRA210_I2S_AXBAR_RX_STATUS 0x0c -#define TEGRA210_I2S_AXBAR_RX_INT_STATUS 0x10 -#define TEGRA210_I2S_AXBAR_RX_INT_MASK 0x14 -#define TEGRA210_I2S_AXBAR_RX_INT_SET 0x18 -#define TEGRA210_I2S_AXBAR_RX_INT_CLEAR 0x1c -#define TEGRA210_I2S_AXBAR_RX_CIF_CTRL 0x20 -#define TEGRA210_I2S_AXBAR_RX_CTRL 0x24 -#define TEGRA210_I2S_AXBAR_RX_SLOT_CTRL 0x28 -#define TEGRA210_I2S_AXBAR_RX_CLK_TRIM 0x2c -#define TEGRA210_I2S_AXBAR_RX_CYA 0x30 -#define TEGRA210_I2S_AXBAR_RX_CIF_FIFO_STATUS 0x34 -#define TEGRA210_I2S_AXBAR_TX_ENABLE 0x40 -#define TEGRA210_I2S_AXBAR_TX_SOFT_RESET 0x44 -#define TEGRA210_I2S_AXBAR_TX_STATUS 0x4c -#define TEGRA210_I2S_AXBAR_TX_INT_STATUS 0x50 -#define TEGRA210_I2S_AXBAR_TX_INT_MASK 0x54 -#define TEGRA210_I2S_AXBAR_TX_INT_SET 0x58 -#define TEGRA210_I2S_AXBAR_TX_INT_CLEAR 0x5c -#define TEGRA210_I2S_AXBAR_TX_CIF_CTRL 0x60 -#define TEGRA210_I2S_AXBAR_TX_CTRL 0x64 -#define TEGRA210_I2S_AXBAR_TX_SLOT_CTRL 0x68 -#define TEGRA210_I2S_AXBAR_TX_CLK_TRIM 0x6c -#define TEGRA210_I2S_AXBAR_TX_CYA 0x70 -#define TEGRA210_I2S_AXBAR_TX_CIF_FIFO_STATUS 0x74 -#define TEGRA210_I2S_ENABLE 0x80 -#define TEGRA210_I2S_SOFT_RESET 0x84 -#define TEGRA210_I2S_CG 0x88 -#define TEGRA210_I2S_STATUS 0x8c -#define TEGRA210_I2S_INT_STATUS 0x90 -#define TEGRA210_I2S_CTRL 0xa0 -#define TEGRA210_I2S_TIMING 0xa4 -#define TEGRA210_I2S_SLOT_CTRL 0xa8 -#define TEGRA210_I2S_CLK_TRIM 0xac -#define TEGRA210_I2S_CYA 0xb0 +/* Bit fields, shifts and masks */ +#define I2S_DATA_SHIFT 8 +#define I2S_CTRL_DATA_OFFSET_MASK (0x7ff << I2S_DATA_SHIFT) -/* - * I2S_AXBAAR_RX registers are with respect to AXBAR. - * The data is coming from AXBAR to I2S for playback. - */ +#define I2S_EN_SHIFT 0 +#define I2S_EN_MASK BIT(I2S_EN_SHIFT) +#define I2S_EN BIT(I2S_EN_SHIFT) -/* Fields in TEGRA210_I2S_AXBAR_RX_ENABLE */ -#define TEGRA210_I2S_AXBAR_RX_EN_SHIFT 0 -#define TEGRA210_I2S_AXBAR_RX_EN (1 << TEGRA210_I2S_AXBAR_RX_EN_SHIFT) +#define I2S_FSYNC_WIDTH_SHIFT 24 +#define I2S_CTRL_FSYNC_WIDTH_MASK (0xff << I2S_FSYNC_WIDTH_SHIFT) -/* Fields in TEGRA210_I2S_AXBAR_RX_CTRL */ -#define TEGRA210_I2S_AXBAR_RX_CTRL_DATA_OFFSET_SHIFT 8 -#define TEGRA210_I2S_AXBAR_RX_CTRL_DATA_OFFSET_MASK (0x7ff << TEGRA210_I2S_AXBAR_RX_CTRL_DATA_OFFSET_SHIFT) +#define I2S_POS_EDGE 0 +#define I2S_NEG_EDGE 1 +#define I2S_EDGE_SHIFT 20 +#define I2S_CTRL_EDGE_CTRL_MASK BIT(I2S_EDGE_SHIFT) +#define I2S_CTRL_EDGE_CTRL_POS_EDGE (I2S_POS_EDGE << I2S_EDGE_SHIFT) +#define I2S_CTRL_EDGE_CTRL_NEG_EDGE (I2S_NEG_EDGE << I2S_EDGE_SHIFT) -#define TEGRA210_I2S_AXBAR_RX_CTRL_MASK_BITS_SHIFT 4 +#define I2S_FMT_LRCK 0 +#define I2S_FMT_FSYNC 1 +#define I2S_FMT_SHIFT 12 +#define I2S_CTRL_FRAME_FMT_MASK (7 << I2S_FMT_SHIFT) +#define I2S_CTRL_FRAME_FMT_LRCK_MODE (I2S_FMT_LRCK << I2S_FMT_SHIFT) +#define I2S_CTRL_FRAME_FMT_FSYNC_MODE (I2S_FMT_FSYNC << I2S_FMT_SHIFT) -#define TEGRA210_I2S_AXBAR_RX_CTRL_HIGHZ_CTRL_SHIFT 1 -#define TEGRA210_I2S_AXBAR_RX_CTRL_HIGHZ_CTRL_MASK (3 << TEGRA210_I2S_AXBAR_RX_CTRL_HIGHZ_CTRL_SHIFT) -#define TEGRA210_I2S_AXBAR_RX_CTRL_HIGHZ_CTRL_NOHIGHZ (0 << TEGRA210_I2S_AXBAR_RX_CTRL_HIGHZ_CTRL_SHIFT) -#define TEGRA210_I2S_AXBAR_RX_CTRL_HIGHZ_CTRL_HIGHZ (1 << TEGRA210_I2S_AXBAR_RX_CTRL_HIGHZ_CTRL_SHIFT) -#define TEGRA210_I2S_AXBAR_RX_CTRL_HIGHZ_CTRL_HIGHZ_ON_HALF_BIT_CLK (2 << TEGRA210_I2S_AXBAR_RX_CTRL_HIGHZ_CTRL_SHIFT) +#define I2S_CTRL_MASTER_EN_SHIFT 10 +#define I2S_CTRL_MASTER_EN_MASK BIT(I2S_CTRL_MASTER_EN_SHIFT) +#define I2S_CTRL_MASTER_EN BIT(I2S_CTRL_MASTER_EN_SHIFT) -#define TEGRA210_I2S_AXBAR_RX_CTRL_BIT_ORDER_SHIFT 0 -#define TEGRA210_I2S_AXBAR_RX_CTRL_BIT_ORDER_MASK (1 << TEGRA210_I2S_AXBAR_RX_CTRL_BIT_ORDER_SHIFT) -#define TEGRA210_I2S_AXBAR_RX_CTRL_BIT_ORDER_MSB_FIRST (0 << TEGRA210_I2S_AXBAR_RX_CTRL_BIT_ORDER_SHIFT) -#define TEGRA210_I2S_AXBAR_RX_CTRL_BIT_ORDER_LSB_FIRST (1 << TEGRA210_I2S_AXBAR_RX_CTRL_BIT_ORDER_SHIFT) +#define I2S_CTRL_LRCK_POL_SHIFT 9 +#define I2S_CTRL_LRCK_POL_MASK BIT(I2S_CTRL_LRCK_POL_SHIFT) +#define I2S_CTRL_LRCK_POL_LOW (0 << I2S_CTRL_LRCK_POL_SHIFT) +#define I2S_CTRL_LRCK_POL_HIGH BIT(I2S_CTRL_LRCK_POL_SHIFT) -/* - * I2S_AXBAAR_TX registers are with respect to AXBAR. - * The data is goint to AXBAR from I2S for capture. - */ +#define I2S_CTRL_LPBK_SHIFT 8 +#define I2S_CTRL_LPBK_MASK BIT(I2S_CTRL_LPBK_SHIFT) +#define I2S_CTRL_LPBK_EN BIT(I2S_CTRL_LPBK_SHIFT) -/* Fields in TEGRA210_I2S_AXBAR_TX_ENABLE */ -#define TEGRA210_I2S_AXBAR_TX_EN_SHIFT 0 -#define TEGRA210_I2S_AXBAR_TX_EN (1 << TEGRA210_I2S_AXBAR_TX_EN_SHIFT) +#define I2S_BITS_8 1 +#define I2S_BITS_16 3 +#define I2S_BITS_32 7 +#define I2S_CTRL_BIT_SIZE_MASK 0x7 -/* Fields in TEGRA210_I2S_AXBAR_TX_CTRL */ -#define TEGRA210_I2S_AXBAR_TX_CTRL_DATA_OFFSET_SHIFT 8 -#define TEGRA210_I2S_AXBAR_TX_CTRL_DATA_OFFSET_MASK (0x7ff << TEGRA210_I2S_AXBAR_TX_CTRL_DATA_OFFSET_SHIFT) +#define I2S_TIMING_CH_BIT_CNT_MASK 0x7ff +#define I2S_TIMING_CH_BIT_CNT_SHIFT 0 -#define TEGRA210_I2S_AXBAR_TX_CTRL_MASK_BITS_SHIFT 4 +#define I2S_SOFT_RESET_SHIFT 0 +#define I2S_SOFT_RESET_MASK BIT(I2S_SOFT_RESET_SHIFT) +#define I2S_SOFT_RESET_EN BIT(I2S_SOFT_RESET_SHIFT) -#define TEGRA210_I2S_AXBAR_TX_CTRL_HIGHZ_CTRL_SHIFT 1 -#define TEGRA210_I2S_AXBAR_TX_CTRL_HIGHZ_CTRL_MASK (3 << TEGRA210_I2S_AXBAR_TX_CTRL_HIGHZ_CTRL_SHIFT) -#define TEGRA210_I2S_AXBAR_TX_CTRL_HIGHZ_CTRL_NOHIGHZ (0 << TEGRA210_I2S_AXBAR_TX_CTRL_HIGHZ_CTRL_SHIFT) -#define TEGRA210_I2S_AXBAR_TX_CTRL_HIGHZ_CTRL_HIGHZ (1 << TEGRA210_I2S_AXBAR_TX_CTRL_HIGHZ_CTRL_SHIFT) -#define TEGRA210_I2S_AXBAR_TX_CTRL_HIGHZ_CTRL_HIGHZ_ON_HALF_BIT_CLK (2 << TEGRA210_I2S_AXBAR_TX_CTRL_HIGHZ_CTRL_SHIFT) +#define I2S_RX_FIFO_DEPTH 64 +#define DEFAULT_I2S_RX_FIFO_THRESHOLD 3 -#define TEGRA210_I2S_AXBAR_TX_CTRL_BIT_ORDER_SHIFT 0 -#define TEGRA210_I2S_AXBAR_TX_CTRL_BIT_ORDER_MASK (1 << TEGRA210_I2S_AXBAR_TX_CTRL_BIT_ORDER_SHIFT) -#define TEGRA210_I2S_AXBAR_TX_CTRL_BIT_ORDER_MSB_FIRST (0 << TEGRA210_I2S_AXBAR_TX_CTRL_BIT_ORDER_SHIFT) -#define TEGRA210_I2S_AXBAR_TX_CTRL_BIT_ORDER_LSB_FIRST (1 << TEGRA210_I2S_AXBAR_TX_CTRL_BIT_ORDER_SHIFT) - -/* Fields in TEGRA210_I2S_ENABLE */ -#define TEGRA210_I2S_EN_SHIFT 0 -#define TEGRA210_I2S_EN_MASK (1 << TEGRA210_I2S_EN_SHIFT) -#define TEGRA210_I2S_EN (1 << TEGRA210_I2S_EN_SHIFT) - -/* Fields in TEGRA210_I2S_CTRL */ -#define TEGRA210_I2S_CTRL_FSYNC_WIDTH_SHIFT 24 -#define TEGRA210_I2S_CTRL_FSYNC_WIDTH_MASK (0xff << TEGRA210_I2S_CTRL_FSYNC_WIDTH_SHIFT) - -#define TEGRA210_I2S_POS_EDGE 0 -#define TEGRA210_I2S_NEG_EDGE 1 -#define TEGRA210_I2S_CTRL_EDGE_CTRL_SHIFT 20 -#define TEGRA210_I2S_CTRL_EDGE_CTRL_MASK (1 << TEGRA210_I2S_CTRL_EDGE_CTRL_SHIFT) -#define TEGRA210_I2S_CTRL_EDGE_CTRL_POS_EDGE (TEGRA210_I2S_POS_EDGE << TEGRA210_I2S_CTRL_EDGE_CTRL_SHIFT) -#define TEGRA210_I2S_CTRL_EDGE_CTRL_NEG_EDGE (TEGRA210_I2S_NEG_EDGE << TEGRA210_I2S_CTRL_EDGE_CTRL_SHIFT) - -#define TEGRA210_I2S_CTRL_PIPE_MACRO_EN_SHIFT 19 -#define TEGRA210_I2S_CTRL_PIPE_MACRO_EN (1 << TEGRA210_I2S_CTRL_PIPE_MACRO_EN_SHIFT) - -#define TEGRA210_I2S_FRAME_FORMAT_LRCK 0 -#define TEGRA210_I2S_FRAME_FORMAT_FSYNC 1 -#define TEGRA210_I2S_CTRL_FRAME_FORMAT_SHIFT 12 -#define TEGRA210_I2S_CTRL_FRAME_FORMAT_MASK (7 << TEGRA210_I2S_CTRL_FRAME_FORMAT_SHIFT) -#define TEGRA210_I2S_CTRL_FRAME_FORMAT_LRCK_MODE (TEGRA210_I2S_FRAME_FORMAT_LRCK << TEGRA210_I2S_CTRL_FRAME_FORMAT_SHIFT) -#define TEGRA210_I2S_CTRL_FRAME_FORMAT_FSYNC_MODE (TEGRA210_I2S_FRAME_FORMAT_FSYNC << TEGRA210_I2S_CTRL_FRAME_FORMAT_SHIFT) - -#define TEGRA210_I2S_CTRL_MASTER_EN_SHIFT 10 -#define TEGRA210_I2S_CTRL_MASTER_EN_MASK (1 << TEGRA210_I2S_CTRL_MASTER_EN_SHIFT) -#define TEGRA210_I2S_CTRL_MASTER_EN (1 << TEGRA210_I2S_CTRL_MASTER_EN_SHIFT) -#define TEGRA210_I2S_CTRL_SLAVE_EN (1 << TEGRA210_I2S_CTRL_MASTER_EN_SHIFT) - -#define TEGRA210_I2S_CTRL_LRCK_POLARITY_SHIFT 9 -#define TEGRA210_I2S_CTRL_LRCK_POLARITY_MASK (1 << TEGRA210_I2S_CTRL_LRCK_POLARITY_SHIFT) -#define TEGRA210_I2S_CTRL_LRCK_POLARITY_LOW (0 << TEGRA210_I2S_CTRL_LRCK_POLARITY_SHIFT) -#define TEGRA210_I2S_CTRL_LRCK_POLARITY_HIGH (1 << TEGRA210_I2S_CTRL_LRCK_POLARITY_SHIFT) - -#define TEGRA210_I2S_CTRL_LPBK_SHIFT 8 -#define TEGRA210_I2S_CTRL_LPBK_MASK (1 << TEGRA210_I2S_CTRL_LPBK_SHIFT) -#define TEGRA210_I2S_CTRL_LPBK_EN (1 << TEGRA210_I2S_CTRL_LPBK_SHIFT) - -#define TEGRA210_I2S_BITS_8 1 -#define TEGRA210_I2S_BITS_16 3 -#define TEGRA210_I2S_BITS_32 7 -#define TEGRA210_I2S_CTRL_BIT_SIZE_SHIFT 0 -#define TEGRA210_I2S_CTRL_BIT_SIZE_MASK (7 << TEGRA210_I2S_CTRL_BIT_SIZE_SHIFT) -#define TEGRA210_I2S_CTRL_BIT_SIZE_8 (TEGRA210_I2S_BITS_8 << TEGRA210_I2S_CTRL_BIT_SIZE_SHIFT) -#define TEGRA210_I2S_CTRL_BIT_SIZE_16 (TEGRA210_I2S_BITS_16 << TEGRA210_I2S_CTRL_BIT_SIZE_SHIFT) -#define TEGRA210_I2S_CTRL_BIT_SIZE_32 (TEGRA210_I2S_BITS_32 << TEGRA210_I2S_CTRL_BIT_SIZE_SHIFT) - -/* Fields in TEGRA210_I2S_TIMING */ -#define TEGRA210_I2S_TIMING_CHANNEL_BIT_CNT_MASK 0x3ff -#define TEGRA210_I2S_TIMING_CHANNEL_BIT_CNT_SHIFT 0 - -/* Fields in TEGRA210_I2S_RX_SOFT_RESET */ -#define TEGRA210_I2S_AXBAR_RX_SOFT_RESET_SHIFT 0 -#define TEGRA210_I2S_AXBAR_RX_SOFT_RESET_MASK (1 << TEGRA210_I2S_AXBAR_RX_SOFT_RESET_SHIFT) -#define TEGRA210_I2S_AXBAR_RX_SOFT_RESET_EN (1 << TEGRA210_I2S_AXBAR_RX_SOFT_RESET_SHIFT) -#define TEGRA210_I2S_AXBAR_RX_SOFT_RESET_DEFAULT (0 << TEGRA210_I2S_AXBAR_RX_SOFT_RESET_SHIFT) - -/* Fields in TEGRA210_I2S_TX_SOFT_RESET */ -#define TEGRA210_I2S_AXBAR_TX_SOFT_RESET_SHIFT 0 -#define TEGRA210_I2S_AXBAR_TX_SOFT_RESET_MASK (1 << TEGRA210_I2S_AXBAR_TX_SOFT_RESET_SHIFT) -#define TEGRA210_I2S_AXBAR_TX_SOFT_RESET_EN (1 << TEGRA210_I2S_AXBAR_TX_SOFT_RESET_SHIFT) -#define TEGRA210_I2S_AXBAR_TX_SOFT_RESET_DEFAULT (0 << TEGRA210_I2S_AXBAR_TX_SOFT_RESET_SHIFT) - -/* Fields in TEGRA210_I2S_SLOT_CTRL */ -#define TEGRA210_I2S_SLOT_CTRL_TOTAL_SLOTS_SHIFT 0 -#define TEGRA210_I2S_SLOT_CTRL_TOTAL_SLOTS_MASK 0xf - -#define TEGRA210_I2S_RX_FIFO_DEPTH 64 +#define DEFAULT_I2S_SLOT_MASK 0xffff enum tegra210_i2s_path { I2S_RX_PATH, @@ -191,24 +112,21 @@ struct tegra210_i2s { struct clk *clk_i2s; struct clk *clk_sync_input; struct regmap *regmap; - const char *prod_name; - struct regulator_bulk_data *supplies; - struct notifier_block slgc_notifier; - int num_supplies; - int bclk_ratio; - int audio_fmt_override[I2S_PATHS]; - int codec_bit_format; - int sample_rate_via_control; - int audio_ch_override[I2S_PATHS]; - int client_ch_override; /* common for both TX and RX */ - int stereo_to_mono[I2S_PATHS]; - int mono_to_stereo[I2S_PATHS]; + unsigned int stereo_to_mono[I2S_PATHS]; + unsigned int mono_to_stereo[I2S_PATHS]; + unsigned int audio_ch_override[I2S_PATHS]; + unsigned int audio_fmt_override[I2S_PATHS]; + /* Client overrides are common for TX and RX paths */ + unsigned int client_ch_override; + unsigned int client_fmt_override; + unsigned int srate_override; + unsigned int dai_fmt; unsigned int fsync_width; + unsigned int bclk_ratio; unsigned int tx_mask; unsigned int rx_mask; + unsigned int rx_fifo_th; bool loopback; - unsigned int format; - unsigned int rx_fifo_th; /* should be programmed interms of frames */ }; #endif