Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-only
0002 //
0003 // tegra210_mixer.c - Tegra210 MIXER driver
0004 //
0005 // Copyright (c) 2021 NVIDIA CORPORATION.  All rights reserved.
0006 
0007 #include <linux/clk.h>
0008 #include <linux/device.h>
0009 #include <linux/io.h>
0010 #include <linux/module.h>
0011 #include <linux/of.h>
0012 #include <linux/of_device.h>
0013 #include <linux/platform_device.h>
0014 #include <linux/pm_runtime.h>
0015 #include <linux/regmap.h>
0016 #include <sound/core.h>
0017 #include <sound/pcm.h>
0018 #include <sound/pcm_params.h>
0019 #include <sound/soc.h>
0020 
0021 #include "tegra210_mixer.h"
0022 #include "tegra_cif.h"
0023 
0024 #define MIXER_REG(reg, id)  ((reg) + ((id) * TEGRA210_MIXER_REG_STRIDE))
0025 #define MIXER_REG_BASE(reg) ((reg) % TEGRA210_MIXER_REG_STRIDE)
0026 
0027 #define MIXER_GAIN_CFG_RAM_ADDR(id)                 \
0028     (TEGRA210_MIXER_GAIN_CFG_RAM_ADDR_0 +               \
0029      ((id) * TEGRA210_MIXER_GAIN_CFG_RAM_ADDR_STRIDE))
0030 
0031 #define MIXER_RX_REG_DEFAULTS(id)                   \
0032     { MIXER_REG(TEGRA210_MIXER_RX1_CIF_CTRL, id), 0x00007700},  \
0033     { MIXER_REG(TEGRA210_MIXER_RX1_CTRL, id), 0x00010823},  \
0034     { MIXER_REG(TEGRA210_MIXER_RX1_PEAK_CTRL, id), 0x000012c0}
0035 
0036 #define MIXER_TX_REG_DEFAULTS(id)                   \
0037     { MIXER_REG(TEGRA210_MIXER_TX1_INT_MASK, (id)), 0x00000001},    \
0038     { MIXER_REG(TEGRA210_MIXER_TX1_CIF_CTRL, (id)), 0x00007700}
0039 
0040 #define REG_DURATION_PARAM(reg, i) ((reg) + NUM_GAIN_POLY_COEFFS + 1 + (i))
0041 
0042 static const struct reg_default tegra210_mixer_reg_defaults[] = {
0043     /* Inputs */
0044     MIXER_RX_REG_DEFAULTS(0),
0045     MIXER_RX_REG_DEFAULTS(1),
0046     MIXER_RX_REG_DEFAULTS(2),
0047     MIXER_RX_REG_DEFAULTS(3),
0048     MIXER_RX_REG_DEFAULTS(4),
0049     MIXER_RX_REG_DEFAULTS(5),
0050     MIXER_RX_REG_DEFAULTS(6),
0051     MIXER_RX_REG_DEFAULTS(7),
0052     MIXER_RX_REG_DEFAULTS(8),
0053     MIXER_RX_REG_DEFAULTS(9),
0054     /* Outputs */
0055     MIXER_TX_REG_DEFAULTS(0),
0056     MIXER_TX_REG_DEFAULTS(1),
0057     MIXER_TX_REG_DEFAULTS(2),
0058     MIXER_TX_REG_DEFAULTS(3),
0059     MIXER_TX_REG_DEFAULTS(4),
0060 
0061     { TEGRA210_MIXER_CG, 0x00000001},
0062     { TEGRA210_MIXER_GAIN_CFG_RAM_CTRL, 0x00004000},
0063     { TEGRA210_MIXER_PEAKM_RAM_CTRL, 0x00004000},
0064     { TEGRA210_MIXER_ENABLE, 0x1 },
0065 };
0066 
0067 /* Default gain parameters */
0068 static const struct tegra210_mixer_gain_params gain_params = {
0069     /* Polynomial coefficients */
0070     { 0, 0, 0, 0, 0, 0, 0, 0x1000000, 0 },
0071     /* Gain value */
0072     0x10000,
0073     /* Duration Parameters */
0074     { 0, 0, 0x400, 0x8000000 },
0075 };
0076 
0077 static int __maybe_unused tegra210_mixer_runtime_suspend(struct device *dev)
0078 {
0079     struct tegra210_mixer *mixer = dev_get_drvdata(dev);
0080 
0081     regcache_cache_only(mixer->regmap, true);
0082     regcache_mark_dirty(mixer->regmap);
0083 
0084     return 0;
0085 }
0086 
0087 static int __maybe_unused tegra210_mixer_runtime_resume(struct device *dev)
0088 {
0089     struct tegra210_mixer *mixer = dev_get_drvdata(dev);
0090 
0091     regcache_cache_only(mixer->regmap, false);
0092     regcache_sync(mixer->regmap);
0093 
0094     return 0;
0095 }
0096 
0097 static int tegra210_mixer_write_ram(struct tegra210_mixer *mixer,
0098                     unsigned int addr,
0099                     unsigned int coef)
0100 {
0101     unsigned int reg, val;
0102     int err;
0103 
0104     /* Check if busy */
0105     err = regmap_read_poll_timeout(mixer->regmap,
0106                        TEGRA210_MIXER_GAIN_CFG_RAM_CTRL,
0107                        val, !(val & 0x80000000), 10, 10000);
0108     if (err < 0)
0109         return err;
0110 
0111     reg = (addr << TEGRA210_MIXER_GAIN_CFG_RAM_ADDR_SHIFT) &
0112           TEGRA210_MIXER_GAIN_CFG_RAM_ADDR_MASK;
0113     reg |= TEGRA210_MIXER_GAIN_CFG_RAM_ADDR_INIT_EN;
0114     reg |= TEGRA210_MIXER_GAIN_CFG_RAM_RW_WRITE;
0115     reg |= TEGRA210_MIXER_GAIN_CFG_RAM_SEQ_ACCESS_EN;
0116 
0117     regmap_write(mixer->regmap,
0118              TEGRA210_MIXER_GAIN_CFG_RAM_CTRL,
0119              reg);
0120     regmap_write(mixer->regmap,
0121              TEGRA210_MIXER_GAIN_CFG_RAM_DATA,
0122              coef);
0123 
0124     return 0;
0125 }
0126 
0127 static int tegra210_mixer_configure_gain(struct snd_soc_component *cmpnt,
0128                      unsigned int id, bool instant_gain)
0129 {
0130     struct tegra210_mixer *mixer = snd_soc_component_get_drvdata(cmpnt);
0131     unsigned int reg = MIXER_GAIN_CFG_RAM_ADDR(id);
0132     int err, i;
0133 
0134     pm_runtime_get_sync(cmpnt->dev);
0135 
0136     /* Write default gain poly coefficients */
0137     for (i = 0; i < NUM_GAIN_POLY_COEFFS; i++) {
0138         err = tegra210_mixer_write_ram(mixer, reg + i,
0139                            gain_params.poly_coeff[i]);
0140 
0141         if (err < 0)
0142             goto rpm_put;
0143     }
0144 
0145     /* Write stored gain value */
0146     err = tegra210_mixer_write_ram(mixer, reg + NUM_GAIN_POLY_COEFFS,
0147                        mixer->gain_value[id]);
0148     if (err < 0)
0149         goto rpm_put;
0150 
0151     /* Write duration parameters */
0152     for (i = 0; i < NUM_DURATION_PARMS; i++) {
0153         int val;
0154 
0155         if (instant_gain)
0156             val = 1;
0157         else
0158             val = gain_params.duration[i];
0159 
0160         err = tegra210_mixer_write_ram(mixer,
0161                            REG_DURATION_PARAM(reg, i),
0162                            val);
0163         if (err < 0)
0164             goto rpm_put;
0165     }
0166 
0167     /* Trigger to apply gain configurations */
0168     err = tegra210_mixer_write_ram(mixer, reg + REG_CFG_DONE_TRIGGER,
0169                        VAL_CFG_DONE_TRIGGER);
0170 
0171 rpm_put:
0172     pm_runtime_put(cmpnt->dev);
0173 
0174     return err;
0175 }
0176 
0177 static int tegra210_mixer_get_gain(struct snd_kcontrol *kcontrol,
0178                    struct snd_ctl_elem_value *ucontrol)
0179 {
0180     struct soc_mixer_control *mc =
0181         (struct soc_mixer_control *)kcontrol->private_value;
0182     struct snd_soc_component *cmpnt = snd_soc_kcontrol_component(kcontrol);
0183     struct tegra210_mixer *mixer = snd_soc_component_get_drvdata(cmpnt);
0184     unsigned int reg = mc->reg;
0185     unsigned int i;
0186 
0187     i = (reg - TEGRA210_MIXER_GAIN_CFG_RAM_ADDR_0) /
0188         TEGRA210_MIXER_GAIN_CFG_RAM_ADDR_STRIDE;
0189 
0190     ucontrol->value.integer.value[0] = mixer->gain_value[i];
0191 
0192     return 0;
0193 }
0194 
0195 static int tegra210_mixer_apply_gain(struct snd_kcontrol *kcontrol,
0196                      struct snd_ctl_elem_value *ucontrol,
0197                      bool instant_gain)
0198 {
0199     struct soc_mixer_control *mc =
0200         (struct soc_mixer_control *)kcontrol->private_value;
0201     struct snd_soc_component *cmpnt = snd_soc_kcontrol_component(kcontrol);
0202     struct tegra210_mixer *mixer = snd_soc_component_get_drvdata(cmpnt);
0203     unsigned int reg = mc->reg, id;
0204     int err;
0205 
0206     /* Save gain value for specific MIXER input */
0207     id = (reg - TEGRA210_MIXER_GAIN_CFG_RAM_ADDR_0) /
0208          TEGRA210_MIXER_GAIN_CFG_RAM_ADDR_STRIDE;
0209 
0210     if (mixer->gain_value[id] == ucontrol->value.integer.value[0])
0211         return 0;
0212 
0213     mixer->gain_value[id] = ucontrol->value.integer.value[0];
0214 
0215     err = tegra210_mixer_configure_gain(cmpnt, id, instant_gain);
0216     if (err) {
0217         dev_err(cmpnt->dev, "Failed to apply gain\n");
0218         return err;
0219     }
0220 
0221     return 1;
0222 }
0223 
0224 static int tegra210_mixer_put_gain(struct snd_kcontrol *kcontrol,
0225                    struct snd_ctl_elem_value *ucontrol)
0226 {
0227     return tegra210_mixer_apply_gain(kcontrol, ucontrol, false);
0228 }
0229 
0230 static int tegra210_mixer_put_instant_gain(struct snd_kcontrol *kcontrol,
0231                        struct snd_ctl_elem_value *ucontrol)
0232 {
0233     return tegra210_mixer_apply_gain(kcontrol, ucontrol, true);
0234 }
0235 
0236 static int tegra210_mixer_set_audio_cif(struct tegra210_mixer *mixer,
0237                     struct snd_pcm_hw_params *params,
0238                     unsigned int reg,
0239                     unsigned int id)
0240 {
0241     unsigned int channels, audio_bits;
0242     struct tegra_cif_conf cif_conf;
0243 
0244     memset(&cif_conf, 0, sizeof(struct tegra_cif_conf));
0245 
0246     channels = params_channels(params);
0247 
0248     switch (params_format(params)) {
0249     case SNDRV_PCM_FORMAT_S16_LE:
0250         audio_bits = TEGRA_ACIF_BITS_16;
0251         break;
0252     case SNDRV_PCM_FORMAT_S32_LE:
0253         audio_bits = TEGRA_ACIF_BITS_32;
0254         break;
0255     default:
0256         return -EINVAL;
0257     }
0258 
0259     cif_conf.audio_ch = channels;
0260     cif_conf.client_ch = channels;
0261     cif_conf.audio_bits = audio_bits;
0262     cif_conf.client_bits = audio_bits;
0263 
0264     tegra_set_cif(mixer->regmap,
0265               reg + (id * TEGRA210_MIXER_REG_STRIDE),
0266               &cif_conf);
0267 
0268     return 0;
0269 }
0270 
0271 static int tegra210_mixer_in_hw_params(struct snd_pcm_substream *substream,
0272                        struct snd_pcm_hw_params *params,
0273                        struct snd_soc_dai *dai)
0274 {
0275     struct tegra210_mixer *mixer = snd_soc_dai_get_drvdata(dai);
0276     int err;
0277 
0278     err = tegra210_mixer_set_audio_cif(mixer, params,
0279                        TEGRA210_MIXER_RX1_CIF_CTRL,
0280                        dai->id);
0281     if (err < 0)
0282         return err;
0283 
0284     return tegra210_mixer_configure_gain(dai->component, dai->id, false);
0285 }
0286 
0287 static int tegra210_mixer_out_hw_params(struct snd_pcm_substream *substream,
0288                     struct snd_pcm_hw_params *params,
0289                     struct snd_soc_dai *dai)
0290 {
0291     struct tegra210_mixer *mixer = snd_soc_dai_get_drvdata(dai);
0292 
0293     return tegra210_mixer_set_audio_cif(mixer, params,
0294                         TEGRA210_MIXER_TX1_CIF_CTRL,
0295                         dai->id - TEGRA210_MIXER_RX_MAX);
0296 }
0297 
0298 static const struct snd_soc_dai_ops tegra210_mixer_out_dai_ops = {
0299     .hw_params  = tegra210_mixer_out_hw_params,
0300 };
0301 
0302 static const struct snd_soc_dai_ops tegra210_mixer_in_dai_ops = {
0303     .hw_params  = tegra210_mixer_in_hw_params,
0304 };
0305 
0306 #define IN_DAI(id)                      \
0307     {                           \
0308         .name = "MIXER-RX-CIF"#id,          \
0309         .playback = {                   \
0310             .stream_name = "RX" #id "-CIF-Playback",\
0311             .channels_min = 1,          \
0312             .channels_max = 8,          \
0313             .rates = SNDRV_PCM_RATE_8000_192000,    \
0314             .formats = SNDRV_PCM_FMTBIT_S8 |    \
0315                 SNDRV_PCM_FMTBIT_S16_LE |   \
0316                 SNDRV_PCM_FMTBIT_S32_LE,    \
0317         },                      \
0318         .capture = {                    \
0319             .stream_name = "RX" #id "-CIF-Capture", \
0320             .channels_min = 1,          \
0321             .channels_max = 8,          \
0322             .rates = SNDRV_PCM_RATE_8000_192000,    \
0323             .formats = SNDRV_PCM_FMTBIT_S8 |    \
0324                 SNDRV_PCM_FMTBIT_S16_LE |   \
0325                 SNDRV_PCM_FMTBIT_S32_LE,    \
0326         },                      \
0327         .ops = &tegra210_mixer_in_dai_ops,      \
0328     }
0329 
0330 #define OUT_DAI(id)                     \
0331     {                           \
0332         .name = "MIXER-TX-CIF" #id,         \
0333         .playback = {                   \
0334             .stream_name = "TX" #id "-CIF-Playback",\
0335             .channels_min = 1,          \
0336             .channels_max = 8,          \
0337             .rates = SNDRV_PCM_RATE_8000_192000,    \
0338             .formats = SNDRV_PCM_FMTBIT_S8 |    \
0339                 SNDRV_PCM_FMTBIT_S16_LE |   \
0340                 SNDRV_PCM_FMTBIT_S32_LE,    \
0341         },                      \
0342         .capture = {                    \
0343             .stream_name = "TX" #id "-CIF-Capture", \
0344             .channels_min = 1,          \
0345             .channels_max = 8,          \
0346             .rates = SNDRV_PCM_RATE_8000_192000,    \
0347             .formats = SNDRV_PCM_FMTBIT_S8 |    \
0348                 SNDRV_PCM_FMTBIT_S16_LE |   \
0349                 SNDRV_PCM_FMTBIT_S32_LE,    \
0350         },                      \
0351         .ops = &tegra210_mixer_out_dai_ops,     \
0352     }
0353 
0354 static struct snd_soc_dai_driver tegra210_mixer_dais[] = {
0355     /* Mixer Input */
0356     IN_DAI(1),
0357     IN_DAI(2),
0358     IN_DAI(3),
0359     IN_DAI(4),
0360     IN_DAI(5),
0361     IN_DAI(6),
0362     IN_DAI(7),
0363     IN_DAI(8),
0364     IN_DAI(9),
0365     IN_DAI(10),
0366 
0367     /* Mixer Output */
0368     OUT_DAI(1),
0369     OUT_DAI(2),
0370     OUT_DAI(3),
0371     OUT_DAI(4),
0372     OUT_DAI(5),
0373 };
0374 
0375 #define ADDER_CTRL_DECL(name, reg)          \
0376     static const struct snd_kcontrol_new name[] = { \
0377         SOC_DAPM_SINGLE("RX1", reg, 0, 1, 0),   \
0378         SOC_DAPM_SINGLE("RX2", reg, 1, 1, 0),   \
0379         SOC_DAPM_SINGLE("RX3", reg, 2, 1, 0),   \
0380         SOC_DAPM_SINGLE("RX4", reg, 3, 1, 0),   \
0381         SOC_DAPM_SINGLE("RX5", reg, 4, 1, 0),   \
0382         SOC_DAPM_SINGLE("RX6", reg, 5, 1, 0),   \
0383         SOC_DAPM_SINGLE("RX7", reg, 6, 1, 0),   \
0384         SOC_DAPM_SINGLE("RX8", reg, 7, 1, 0),   \
0385         SOC_DAPM_SINGLE("RX9", reg, 8, 1, 0),   \
0386         SOC_DAPM_SINGLE("RX10", reg, 9, 1, 0),  \
0387     }
0388 
0389 ADDER_CTRL_DECL(adder1, TEGRA210_MIXER_TX1_ADDER_CONFIG);
0390 ADDER_CTRL_DECL(adder2, TEGRA210_MIXER_TX2_ADDER_CONFIG);
0391 ADDER_CTRL_DECL(adder3, TEGRA210_MIXER_TX3_ADDER_CONFIG);
0392 ADDER_CTRL_DECL(adder4, TEGRA210_MIXER_TX4_ADDER_CONFIG);
0393 ADDER_CTRL_DECL(adder5, TEGRA210_MIXER_TX5_ADDER_CONFIG);
0394 
0395 #define GAIN_CTRL(id)   \
0396     SOC_SINGLE_EXT("RX" #id " Gain Volume",         \
0397                MIXER_GAIN_CFG_RAM_ADDR((id) - 1), 0,    \
0398                0x20000, 0, tegra210_mixer_get_gain, \
0399                tegra210_mixer_put_gain),        \
0400     SOC_SINGLE_EXT("RX" #id " Instant Gain Volume",     \
0401                MIXER_GAIN_CFG_RAM_ADDR((id) - 1), 0,    \
0402                0x20000, 0, tegra210_mixer_get_gain, \
0403                tegra210_mixer_put_instant_gain),
0404 
0405 /* Volume controls for all MIXER inputs */
0406 static const struct snd_kcontrol_new tegra210_mixer_gain_ctls[] = {
0407     GAIN_CTRL(1)
0408     GAIN_CTRL(2)
0409     GAIN_CTRL(3)
0410     GAIN_CTRL(4)
0411     GAIN_CTRL(5)
0412     GAIN_CTRL(6)
0413     GAIN_CTRL(7)
0414     GAIN_CTRL(8)
0415     GAIN_CTRL(9)
0416     GAIN_CTRL(10)
0417 };
0418 
0419 static const struct snd_soc_dapm_widget tegra210_mixer_widgets[] = {
0420     SND_SOC_DAPM_AIF_IN("RX1", NULL, 0, SND_SOC_NOPM, 0, 0),
0421     SND_SOC_DAPM_AIF_IN("RX2", NULL, 0, SND_SOC_NOPM, 0, 0),
0422     SND_SOC_DAPM_AIF_IN("RX3", NULL, 0, SND_SOC_NOPM, 0, 0),
0423     SND_SOC_DAPM_AIF_IN("RX4", NULL, 0, SND_SOC_NOPM, 0, 0),
0424     SND_SOC_DAPM_AIF_IN("RX5", NULL, 0, SND_SOC_NOPM, 0, 0),
0425     SND_SOC_DAPM_AIF_IN("RX6", NULL, 0, SND_SOC_NOPM, 0, 0),
0426     SND_SOC_DAPM_AIF_IN("RX7", NULL, 0, SND_SOC_NOPM, 0, 0),
0427     SND_SOC_DAPM_AIF_IN("RX8", NULL, 0, SND_SOC_NOPM, 0, 0),
0428     SND_SOC_DAPM_AIF_IN("RX9", NULL, 0, SND_SOC_NOPM, 0, 0),
0429     SND_SOC_DAPM_AIF_IN("RX10", NULL, 0, SND_SOC_NOPM, 0, 0),
0430     SND_SOC_DAPM_AIF_OUT("TX1", NULL, 0, TEGRA210_MIXER_TX1_ENABLE, 0, 0),
0431     SND_SOC_DAPM_AIF_OUT("TX2", NULL, 0, TEGRA210_MIXER_TX2_ENABLE, 0, 0),
0432     SND_SOC_DAPM_AIF_OUT("TX3", NULL, 0, TEGRA210_MIXER_TX3_ENABLE, 0, 0),
0433     SND_SOC_DAPM_AIF_OUT("TX4", NULL, 0, TEGRA210_MIXER_TX4_ENABLE, 0, 0),
0434     SND_SOC_DAPM_AIF_OUT("TX5", NULL, 0, TEGRA210_MIXER_TX5_ENABLE, 0, 0),
0435     SND_SOC_DAPM_MIXER("Adder1", SND_SOC_NOPM, 1, 0, adder1,
0436                ARRAY_SIZE(adder1)),
0437     SND_SOC_DAPM_MIXER("Adder2", SND_SOC_NOPM, 1, 0, adder2,
0438                ARRAY_SIZE(adder2)),
0439     SND_SOC_DAPM_MIXER("Adder3", SND_SOC_NOPM, 1, 0, adder3,
0440                ARRAY_SIZE(adder3)),
0441     SND_SOC_DAPM_MIXER("Adder4", SND_SOC_NOPM, 1, 0, adder4,
0442                ARRAY_SIZE(adder4)),
0443     SND_SOC_DAPM_MIXER("Adder5", SND_SOC_NOPM, 1, 0, adder5,
0444                ARRAY_SIZE(adder5)),
0445 };
0446 
0447 #define RX_ROUTES(id, sname)                           \
0448     { "RX" #id " XBAR-" sname,  NULL,   "RX" #id " XBAR-TX" },     \
0449     { "RX" #id "-CIF-" sname,   NULL,   "RX" #id " XBAR-" sname }, \
0450     { "RX" #id,         NULL,   "RX" #id "-CIF-" sname }
0451 
0452 #define MIXER_RX_ROUTES(id)     \
0453     RX_ROUTES(id, "Playback"),  \
0454     RX_ROUTES(id, "Capture")
0455 
0456 #define ADDER_ROUTES(id, sname)                       \
0457     { "Adder" #id,          "RX1",  "RX1" },          \
0458     { "Adder" #id,          "RX2",  "RX2" },          \
0459     { "Adder" #id,          "RX3",  "RX3" },          \
0460     { "Adder" #id,          "RX4",  "RX4" },          \
0461     { "Adder" #id,          "RX5",  "RX5" },          \
0462     { "Adder" #id,          "RX6",  "RX6" },          \
0463     { "Adder" #id,          "RX7",  "RX7" },          \
0464     { "Adder" #id,          "RX8",  "RX8" },          \
0465     { "Adder" #id,          "RX9",  "RX9" },          \
0466     { "Adder" #id,          "RX10", "RX10" },         \
0467     { "TX" #id,         NULL,   "Adder" #id },        \
0468     { "TX" #id "-CIF-" sname,   NULL,   "TX" #id },       \
0469     { "TX" #id " XBAR-" sname,  NULL,   "TX" #id "-CIF-" sname }, \
0470     { "TX" #id " XBAR-RX",      NULL,   "TX" #id " XBAR-" sname } \
0471 
0472 #define TX_ROUTES(id, sname)        \
0473     ADDER_ROUTES(1, sname),     \
0474     ADDER_ROUTES(2, sname),     \
0475     ADDER_ROUTES(3, sname),     \
0476     ADDER_ROUTES(4, sname),     \
0477     ADDER_ROUTES(5, sname)
0478 
0479 #define MIXER_TX_ROUTES(id)     \
0480     TX_ROUTES(id, "Playback"),  \
0481     TX_ROUTES(id, "Capture")
0482 
0483 static const struct snd_soc_dapm_route tegra210_mixer_routes[] = {
0484     /* Input */
0485     MIXER_RX_ROUTES(1),
0486     MIXER_RX_ROUTES(2),
0487     MIXER_RX_ROUTES(3),
0488     MIXER_RX_ROUTES(4),
0489     MIXER_RX_ROUTES(5),
0490     MIXER_RX_ROUTES(6),
0491     MIXER_RX_ROUTES(7),
0492     MIXER_RX_ROUTES(8),
0493     MIXER_RX_ROUTES(9),
0494     MIXER_RX_ROUTES(10),
0495     /* Output */
0496     MIXER_TX_ROUTES(1),
0497     MIXER_TX_ROUTES(2),
0498     MIXER_TX_ROUTES(3),
0499     MIXER_TX_ROUTES(4),
0500     MIXER_TX_ROUTES(5),
0501 };
0502 
0503 static const struct snd_soc_component_driver tegra210_mixer_cmpnt = {
0504     .dapm_widgets       = tegra210_mixer_widgets,
0505     .num_dapm_widgets   = ARRAY_SIZE(tegra210_mixer_widgets),
0506     .dapm_routes        = tegra210_mixer_routes,
0507     .num_dapm_routes    = ARRAY_SIZE(tegra210_mixer_routes),
0508     .controls       = tegra210_mixer_gain_ctls,
0509     .num_controls       = ARRAY_SIZE(tegra210_mixer_gain_ctls),
0510 };
0511 
0512 static bool tegra210_mixer_wr_reg(struct device *dev,
0513                 unsigned int reg)
0514 {
0515     if (reg < TEGRA210_MIXER_RX_LIMIT)
0516         reg = MIXER_REG_BASE(reg);
0517     else if (reg < TEGRA210_MIXER_TX_LIMIT)
0518         reg = MIXER_REG_BASE(reg) + TEGRA210_MIXER_TX1_ENABLE;
0519 
0520     switch (reg) {
0521     case TEGRA210_MIXER_RX1_SOFT_RESET:
0522     case TEGRA210_MIXER_RX1_CIF_CTRL ... TEGRA210_MIXER_RX1_PEAK_CTRL:
0523 
0524     case TEGRA210_MIXER_TX1_ENABLE:
0525     case TEGRA210_MIXER_TX1_SOFT_RESET:
0526     case TEGRA210_MIXER_TX1_INT_MASK ... TEGRA210_MIXER_TX1_ADDER_CONFIG:
0527 
0528     case TEGRA210_MIXER_ENABLE ... TEGRA210_MIXER_CG:
0529     case TEGRA210_MIXER_GAIN_CFG_RAM_CTRL ... TEGRA210_MIXER_CTRL:
0530         return true;
0531     default:
0532         return false;
0533     }
0534 }
0535 
0536 static bool tegra210_mixer_rd_reg(struct device *dev,
0537                 unsigned int reg)
0538 {
0539     if (reg < TEGRA210_MIXER_RX_LIMIT)
0540         reg = MIXER_REG_BASE(reg);
0541     else if (reg < TEGRA210_MIXER_TX_LIMIT)
0542         reg = MIXER_REG_BASE(reg) + TEGRA210_MIXER_TX1_ENABLE;
0543 
0544     switch (reg) {
0545     case TEGRA210_MIXER_RX1_SOFT_RESET ... TEGRA210_MIXER_RX1_SAMPLE_COUNT:
0546     case TEGRA210_MIXER_TX1_ENABLE ... TEGRA210_MIXER_TX1_ADDER_CONFIG:
0547     case TEGRA210_MIXER_ENABLE ... TEGRA210_MIXER_CTRL:
0548         return true;
0549     default:
0550         return false;
0551     }
0552 }
0553 
0554 static bool tegra210_mixer_volatile_reg(struct device *dev,
0555                 unsigned int reg)
0556 {
0557     if (reg < TEGRA210_MIXER_RX_LIMIT)
0558         reg = MIXER_REG_BASE(reg);
0559     else if (reg < TEGRA210_MIXER_TX_LIMIT)
0560         reg = MIXER_REG_BASE(reg) + TEGRA210_MIXER_TX1_ENABLE;
0561 
0562     switch (reg) {
0563     case TEGRA210_MIXER_RX1_SOFT_RESET:
0564     case TEGRA210_MIXER_RX1_STATUS:
0565 
0566     case TEGRA210_MIXER_TX1_SOFT_RESET:
0567     case TEGRA210_MIXER_TX1_STATUS:
0568     case TEGRA210_MIXER_TX1_INT_STATUS:
0569     case TEGRA210_MIXER_TX1_INT_SET:
0570 
0571     case TEGRA210_MIXER_SOFT_RESET:
0572     case TEGRA210_MIXER_STATUS:
0573     case TEGRA210_MIXER_INT_STATUS:
0574     case TEGRA210_MIXER_GAIN_CFG_RAM_CTRL:
0575     case TEGRA210_MIXER_GAIN_CFG_RAM_DATA:
0576     case TEGRA210_MIXER_PEAKM_RAM_CTRL:
0577     case TEGRA210_MIXER_PEAKM_RAM_DATA:
0578         return true;
0579     default:
0580         return false;
0581     }
0582 }
0583 
0584 static bool tegra210_mixer_precious_reg(struct device *dev,
0585                 unsigned int reg)
0586 {
0587     switch (reg) {
0588     case TEGRA210_MIXER_GAIN_CFG_RAM_DATA:
0589     case TEGRA210_MIXER_PEAKM_RAM_DATA:
0590         return true;
0591     default:
0592         return false;
0593     }
0594 }
0595 
0596 static const struct regmap_config tegra210_mixer_regmap_config = {
0597     .reg_bits       = 32,
0598     .reg_stride     = 4,
0599     .val_bits       = 32,
0600     .max_register       = TEGRA210_MIXER_CTRL,
0601     .writeable_reg      = tegra210_mixer_wr_reg,
0602     .readable_reg       = tegra210_mixer_rd_reg,
0603     .volatile_reg       = tegra210_mixer_volatile_reg,
0604     .precious_reg       = tegra210_mixer_precious_reg,
0605     .reg_defaults       = tegra210_mixer_reg_defaults,
0606     .num_reg_defaults   = ARRAY_SIZE(tegra210_mixer_reg_defaults),
0607     .cache_type     = REGCACHE_FLAT,
0608 };
0609 
0610 static const struct of_device_id tegra210_mixer_of_match[] = {
0611     { .compatible = "nvidia,tegra210-amixer" },
0612     {},
0613 };
0614 MODULE_DEVICE_TABLE(of, tegra210_mixer_of_match);
0615 
0616 static int tegra210_mixer_platform_probe(struct platform_device *pdev)
0617 {
0618     struct device *dev = &pdev->dev;
0619     struct tegra210_mixer *mixer;
0620     void __iomem *regs;
0621     int err, i;
0622 
0623     mixer = devm_kzalloc(dev, sizeof(*mixer), GFP_KERNEL);
0624     if (!mixer)
0625         return -ENOMEM;
0626 
0627     dev_set_drvdata(dev, mixer);
0628 
0629     /* Use default gain value for all MIXER inputs */
0630     for (i = 0; i < TEGRA210_MIXER_RX_MAX; i++)
0631         mixer->gain_value[i] = gain_params.gain_value;
0632 
0633     regs = devm_platform_ioremap_resource(pdev, 0);
0634     if (IS_ERR(regs))
0635         return PTR_ERR(regs);
0636 
0637     mixer->regmap = devm_regmap_init_mmio(dev, regs,
0638                           &tegra210_mixer_regmap_config);
0639     if (IS_ERR(mixer->regmap)) {
0640         dev_err(dev, "regmap init failed\n");
0641         return PTR_ERR(mixer->regmap);
0642     }
0643 
0644     regcache_cache_only(mixer->regmap, true);
0645 
0646     err = devm_snd_soc_register_component(dev, &tegra210_mixer_cmpnt,
0647                           tegra210_mixer_dais,
0648                           ARRAY_SIZE(tegra210_mixer_dais));
0649     if (err) {
0650         dev_err(dev, "can't register MIXER component, err: %d\n", err);
0651         return err;
0652     }
0653 
0654     pm_runtime_enable(dev);
0655 
0656     return 0;
0657 }
0658 
0659 static int tegra210_mixer_platform_remove(struct platform_device *pdev)
0660 {
0661     pm_runtime_disable(&pdev->dev);
0662 
0663     return 0;
0664 }
0665 
0666 static const struct dev_pm_ops tegra210_mixer_pm_ops = {
0667     SET_RUNTIME_PM_OPS(tegra210_mixer_runtime_suspend,
0668                tegra210_mixer_runtime_resume, NULL)
0669     SET_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend,
0670                 pm_runtime_force_resume)
0671 };
0672 
0673 static struct platform_driver tegra210_mixer_driver = {
0674     .driver = {
0675         .name = "tegra210_mixer",
0676         .of_match_table = tegra210_mixer_of_match,
0677         .pm = &tegra210_mixer_pm_ops,
0678     },
0679     .probe = tegra210_mixer_platform_probe,
0680     .remove = tegra210_mixer_platform_remove,
0681 };
0682 module_platform_driver(tegra210_mixer_driver);
0683 
0684 MODULE_AUTHOR("Arun Shamanna Lakshmi <aruns@nvidia.com>");
0685 MODULE_DESCRIPTION("Tegra210 MIXER ASoC driver");
0686 MODULE_LICENSE("GPL v2");