From 6b98f0a7405aa1adb359c0980044e81b761ef04f Mon Sep 17 00:00:00 2001 From: Sameer Pujar Date: Mon, 24 Feb 2020 11:48:08 +0530 Subject: [PATCH] ASoC: tegra: update AHUB drivers as per upstream AHUB and few components have been pushed for upstream review. Though the changes are still under review, we can leverage the work done on upstream 5.x and use the same here on 5.4 kernel. This helps to align the downstream code. Any changes that happen because of upstream review can be cherry picked here. If we plan for any downstream changes, upstream patch needs to be pushed to keep the code in sync. As of today current snapshot is pulled from v3 of AHUB series, http://patchwork.ozlabs.org/project/linux-tegra/list/?series=159664 Above series was worked on later versions of linux-next and hence following are the changes required for porting back on 5.4 * tegra_pcm_new() and tegra_pcm_free() are exposed from tegra_pcm.c and component driver callbacks use these. * Callback functions required for snd_pcm_ops in component driver are implemented by tegra_pcm.c * With this ADMAIF driver need not register platform device with ASoC core. For components (AHUB, ADMAIF, I2S, DMIC and DSPK) the downsream code differs in few aspects from the code that was pushed for v3. Some of them are listed below. * I2S driver in downstream implements startup()/shutdown() calls for DAI, which does some setup related to pinconfig and regulators. The same is true for DMIC and DSPK drivers as well. * Downstream ADMAIF drivers makes bandwidth requests in startup/shutdown() calls and has helper function for dumping registers. It also has additional DAI interfaces which are used for ADSP audio. * Downstream AHUB driver has DAI interfaces for connecting to all other modules. These differences will be cherry-picked as and when it is necessary. Bug 2845498 Change-Id: Id374967ecae26f6b7334a959fb23308d383c15f2 Signed-off-by: Sameer Pujar --- sound/soc/tegra/tegra186_dspk.c | 590 +++++++++--------- sound/soc/tegra/tegra186_dspk.h | 217 ++----- sound/soc/tegra/tegra210_admaif.c | 888 ++++++++------------------ sound/soc/tegra/tegra210_admaif.h | 289 ++++----- sound/soc/tegra/tegra210_ahub.c | 651 ++++++++++++++++++++ sound/soc/tegra/tegra210_ahub.h | 125 ++++ sound/soc/tegra/tegra210_dmic.c | 527 ++++++---------- sound/soc/tegra/tegra210_dmic.h | 68 +- sound/soc/tegra/tegra210_i2s.c | 992 +++++++++++------------------- sound/soc/tegra/tegra210_i2s.h | 272 +++----- 10 files changed, 2198 insertions(+), 2421 deletions(-) create mode 100644 sound/soc/tegra/tegra210_ahub.c create mode 100644 sound/soc/tegra/tegra210_ahub.h 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