Merge branch 'master' of git://git.kernel.org/pub/scm/linux/kernel/git/klassert/ipsec
[platform/kernel/linux-starfive.git] / sound / soc / tegra / tegra210_mixer.c
1 // SPDX-License-Identifier: GPL-2.0-only
2 //
3 // tegra210_mixer.c - Tegra210 MIXER driver
4 //
5 // Copyright (c) 2021 NVIDIA CORPORATION.  All rights reserved.
6
7 #include <linux/clk.h>
8 #include <linux/device.h>
9 #include <linux/io.h>
10 #include <linux/module.h>
11 #include <linux/of.h>
12 #include <linux/of_device.h>
13 #include <linux/platform_device.h>
14 #include <linux/pm_runtime.h>
15 #include <linux/regmap.h>
16 #include <sound/core.h>
17 #include <sound/pcm.h>
18 #include <sound/pcm_params.h>
19 #include <sound/soc.h>
20
21 #include "tegra210_mixer.h"
22 #include "tegra_cif.h"
23
24 #define MIXER_REG(reg, id)      ((reg) + ((id) * TEGRA210_MIXER_REG_STRIDE))
25 #define MIXER_REG_BASE(reg)     ((reg) % TEGRA210_MIXER_REG_STRIDE)
26
27 #define MIXER_GAIN_CFG_RAM_ADDR(id)                                     \
28         (TEGRA210_MIXER_GAIN_CFG_RAM_ADDR_0 +                           \
29          ((id) * TEGRA210_MIXER_GAIN_CFG_RAM_ADDR_STRIDE))
30
31 #define MIXER_RX_REG_DEFAULTS(id)                                       \
32         { MIXER_REG(TEGRA210_MIXER_RX1_CIF_CTRL, id), 0x00007700},      \
33         { MIXER_REG(TEGRA210_MIXER_RX1_CTRL, id), 0x00010823},  \
34         { MIXER_REG(TEGRA210_MIXER_RX1_PEAK_CTRL, id), 0x000012c0}
35
36 #define MIXER_TX_REG_DEFAULTS(id)                                       \
37         { MIXER_REG(TEGRA210_MIXER_TX1_INT_MASK, (id)), 0x00000001},    \
38         { MIXER_REG(TEGRA210_MIXER_TX1_CIF_CTRL, (id)), 0x00007700}
39
40 #define REG_DURATION_PARAM(reg, i) ((reg) + NUM_GAIN_POLY_COEFFS + 1 + (i))
41
42 static const struct reg_default tegra210_mixer_reg_defaults[] = {
43         /* Inputs */
44         MIXER_RX_REG_DEFAULTS(0),
45         MIXER_RX_REG_DEFAULTS(1),
46         MIXER_RX_REG_DEFAULTS(2),
47         MIXER_RX_REG_DEFAULTS(3),
48         MIXER_RX_REG_DEFAULTS(4),
49         MIXER_RX_REG_DEFAULTS(5),
50         MIXER_RX_REG_DEFAULTS(6),
51         MIXER_RX_REG_DEFAULTS(7),
52         MIXER_RX_REG_DEFAULTS(8),
53         MIXER_RX_REG_DEFAULTS(9),
54         /* Outputs */
55         MIXER_TX_REG_DEFAULTS(0),
56         MIXER_TX_REG_DEFAULTS(1),
57         MIXER_TX_REG_DEFAULTS(2),
58         MIXER_TX_REG_DEFAULTS(3),
59         MIXER_TX_REG_DEFAULTS(4),
60
61         { TEGRA210_MIXER_CG, 0x00000001},
62         { TEGRA210_MIXER_GAIN_CFG_RAM_CTRL, 0x00004000},
63         { TEGRA210_MIXER_PEAKM_RAM_CTRL, 0x00004000},
64         { TEGRA210_MIXER_ENABLE, 0x1 },
65 };
66
67 /* Default gain parameters */
68 static const struct tegra210_mixer_gain_params gain_params = {
69         /* Polynomial coefficients */
70         { 0, 0, 0, 0, 0, 0, 0, 0x1000000, 0 },
71         /* Gain value */
72         0x10000,
73         /* Duration Parameters */
74         { 0, 0, 0x400, 0x8000000 },
75 };
76
77 static int __maybe_unused tegra210_mixer_runtime_suspend(struct device *dev)
78 {
79         struct tegra210_mixer *mixer = dev_get_drvdata(dev);
80
81         regcache_cache_only(mixer->regmap, true);
82         regcache_mark_dirty(mixer->regmap);
83
84         return 0;
85 }
86
87 static int __maybe_unused tegra210_mixer_runtime_resume(struct device *dev)
88 {
89         struct tegra210_mixer *mixer = dev_get_drvdata(dev);
90
91         regcache_cache_only(mixer->regmap, false);
92         regcache_sync(mixer->regmap);
93
94         return 0;
95 }
96
97 static int tegra210_mixer_write_ram(struct tegra210_mixer *mixer,
98                                     unsigned int addr,
99                                     unsigned int coef)
100 {
101         unsigned int reg, val;
102         int err;
103
104         /* Check if busy */
105         err = regmap_read_poll_timeout(mixer->regmap,
106                                        TEGRA210_MIXER_GAIN_CFG_RAM_CTRL,
107                                        val, !(val & 0x80000000), 10, 10000);
108         if (err < 0)
109                 return err;
110
111         reg = (addr << TEGRA210_MIXER_GAIN_CFG_RAM_ADDR_SHIFT) &
112               TEGRA210_MIXER_GAIN_CFG_RAM_ADDR_MASK;
113         reg |= TEGRA210_MIXER_GAIN_CFG_RAM_ADDR_INIT_EN;
114         reg |= TEGRA210_MIXER_GAIN_CFG_RAM_RW_WRITE;
115         reg |= TEGRA210_MIXER_GAIN_CFG_RAM_SEQ_ACCESS_EN;
116
117         regmap_write(mixer->regmap,
118                      TEGRA210_MIXER_GAIN_CFG_RAM_CTRL,
119                      reg);
120         regmap_write(mixer->regmap,
121                      TEGRA210_MIXER_GAIN_CFG_RAM_DATA,
122                      coef);
123
124         return 0;
125 }
126
127 static int tegra210_mixer_configure_gain(struct snd_soc_component *cmpnt,
128                                          unsigned int id, bool instant_gain)
129 {
130         struct tegra210_mixer *mixer = snd_soc_component_get_drvdata(cmpnt);
131         unsigned int reg = MIXER_GAIN_CFG_RAM_ADDR(id);
132         int err, i;
133
134         pm_runtime_get_sync(cmpnt->dev);
135
136         /* Write default gain poly coefficients */
137         for (i = 0; i < NUM_GAIN_POLY_COEFFS; i++) {
138                 err = tegra210_mixer_write_ram(mixer, reg + i,
139                                                gain_params.poly_coeff[i]);
140
141                 if (err < 0)
142                         goto rpm_put;
143         }
144
145         /* Write stored gain value */
146         err = tegra210_mixer_write_ram(mixer, reg + NUM_GAIN_POLY_COEFFS,
147                                        mixer->gain_value[id]);
148         if (err < 0)
149                 goto rpm_put;
150
151         /* Write duration parameters */
152         for (i = 0; i < NUM_DURATION_PARMS; i++) {
153                 int val;
154
155                 if (instant_gain)
156                         val = 1;
157                 else
158                         val = gain_params.duration[i];
159
160                 err = tegra210_mixer_write_ram(mixer,
161                                                REG_DURATION_PARAM(reg, i),
162                                                val);
163                 if (err < 0)
164                         goto rpm_put;
165         }
166
167         /* Trigger to apply gain configurations */
168         err = tegra210_mixer_write_ram(mixer, reg + REG_CFG_DONE_TRIGGER,
169                                        VAL_CFG_DONE_TRIGGER);
170
171 rpm_put:
172         pm_runtime_put(cmpnt->dev);
173
174         return err;
175 }
176
177 static int tegra210_mixer_get_gain(struct snd_kcontrol *kcontrol,
178                                    struct snd_ctl_elem_value *ucontrol)
179 {
180         struct soc_mixer_control *mc =
181                 (struct soc_mixer_control *)kcontrol->private_value;
182         struct snd_soc_component *cmpnt = snd_soc_kcontrol_component(kcontrol);
183         struct tegra210_mixer *mixer = snd_soc_component_get_drvdata(cmpnt);
184         unsigned int reg = mc->reg;
185         unsigned int i;
186
187         i = (reg - TEGRA210_MIXER_GAIN_CFG_RAM_ADDR_0) /
188             TEGRA210_MIXER_GAIN_CFG_RAM_ADDR_STRIDE;
189
190         ucontrol->value.integer.value[0] = mixer->gain_value[i];
191
192         return 0;
193 }
194
195 static int tegra210_mixer_apply_gain(struct snd_kcontrol *kcontrol,
196                                      struct snd_ctl_elem_value *ucontrol,
197                                      bool instant_gain)
198 {
199         struct soc_mixer_control *mc =
200                 (struct soc_mixer_control *)kcontrol->private_value;
201         struct snd_soc_component *cmpnt = snd_soc_kcontrol_component(kcontrol);
202         struct tegra210_mixer *mixer = snd_soc_component_get_drvdata(cmpnt);
203         unsigned int reg = mc->reg, id;
204         int err;
205
206         /* Save gain value for specific MIXER input */
207         id = (reg - TEGRA210_MIXER_GAIN_CFG_RAM_ADDR_0) /
208              TEGRA210_MIXER_GAIN_CFG_RAM_ADDR_STRIDE;
209
210         if (mixer->gain_value[id] == ucontrol->value.integer.value[0])
211                 return 0;
212
213         mixer->gain_value[id] = ucontrol->value.integer.value[0];
214
215         err = tegra210_mixer_configure_gain(cmpnt, id, instant_gain);
216         if (err) {
217                 dev_err(cmpnt->dev, "Failed to apply gain\n");
218                 return err;
219         }
220
221         return 1;
222 }
223
224 static int tegra210_mixer_put_gain(struct snd_kcontrol *kcontrol,
225                                    struct snd_ctl_elem_value *ucontrol)
226 {
227         return tegra210_mixer_apply_gain(kcontrol, ucontrol, false);
228 }
229
230 static int tegra210_mixer_put_instant_gain(struct snd_kcontrol *kcontrol,
231                                            struct snd_ctl_elem_value *ucontrol)
232 {
233         return tegra210_mixer_apply_gain(kcontrol, ucontrol, true);
234 }
235
236 static int tegra210_mixer_set_audio_cif(struct tegra210_mixer *mixer,
237                                         struct snd_pcm_hw_params *params,
238                                         unsigned int reg,
239                                         unsigned int id)
240 {
241         unsigned int channels, audio_bits;
242         struct tegra_cif_conf cif_conf;
243
244         memset(&cif_conf, 0, sizeof(struct tegra_cif_conf));
245
246         channels = params_channels(params);
247
248         switch (params_format(params)) {
249         case SNDRV_PCM_FORMAT_S16_LE:
250                 audio_bits = TEGRA_ACIF_BITS_16;
251                 break;
252         case SNDRV_PCM_FORMAT_S32_LE:
253                 audio_bits = TEGRA_ACIF_BITS_32;
254                 break;
255         default:
256                 return -EINVAL;
257         }
258
259         cif_conf.audio_ch = channels;
260         cif_conf.client_ch = channels;
261         cif_conf.audio_bits = audio_bits;
262         cif_conf.client_bits = audio_bits;
263
264         tegra_set_cif(mixer->regmap,
265                       reg + (id * TEGRA210_MIXER_REG_STRIDE),
266                       &cif_conf);
267
268         return 0;
269 }
270
271 static int tegra210_mixer_in_hw_params(struct snd_pcm_substream *substream,
272                                        struct snd_pcm_hw_params *params,
273                                        struct snd_soc_dai *dai)
274 {
275         struct tegra210_mixer *mixer = snd_soc_dai_get_drvdata(dai);
276         int err;
277
278         err = tegra210_mixer_set_audio_cif(mixer, params,
279                                            TEGRA210_MIXER_RX1_CIF_CTRL,
280                                            dai->id);
281         if (err < 0)
282                 return err;
283
284         return tegra210_mixer_configure_gain(dai->component, dai->id, false);
285 }
286
287 static int tegra210_mixer_out_hw_params(struct snd_pcm_substream *substream,
288                                         struct snd_pcm_hw_params *params,
289                                         struct snd_soc_dai *dai)
290 {
291         struct tegra210_mixer *mixer = snd_soc_dai_get_drvdata(dai);
292
293         return tegra210_mixer_set_audio_cif(mixer, params,
294                                             TEGRA210_MIXER_TX1_CIF_CTRL,
295                                             dai->id - TEGRA210_MIXER_RX_MAX);
296 }
297
298 static const struct snd_soc_dai_ops tegra210_mixer_out_dai_ops = {
299         .hw_params      = tegra210_mixer_out_hw_params,
300 };
301
302 static const struct snd_soc_dai_ops tegra210_mixer_in_dai_ops = {
303         .hw_params      = tegra210_mixer_in_hw_params,
304 };
305
306 #define IN_DAI(id)                                              \
307         {                                                       \
308                 .name = "MIXER-RX-CIF"#id,                      \
309                 .playback = {                                   \
310                         .stream_name = "RX" #id "-CIF-Playback",\
311                         .channels_min = 1,                      \
312                         .channels_max = 8,                      \
313                         .rates = SNDRV_PCM_RATE_8000_192000,    \
314                         .formats = SNDRV_PCM_FMTBIT_S8 |        \
315                                 SNDRV_PCM_FMTBIT_S16_LE |       \
316                                 SNDRV_PCM_FMTBIT_S32_LE,        \
317                 },                                              \
318                 .capture = {                                    \
319                         .stream_name = "RX" #id "-CIF-Capture", \
320                         .channels_min = 1,                      \
321                         .channels_max = 8,                      \
322                         .rates = SNDRV_PCM_RATE_8000_192000,    \
323                         .formats = SNDRV_PCM_FMTBIT_S8 |        \
324                                 SNDRV_PCM_FMTBIT_S16_LE |       \
325                                 SNDRV_PCM_FMTBIT_S32_LE,        \
326                 },                                              \
327                 .ops = &tegra210_mixer_in_dai_ops,              \
328         }
329
330 #define OUT_DAI(id)                                             \
331         {                                                       \
332                 .name = "MIXER-TX-CIF" #id,                     \
333                 .playback = {                                   \
334                         .stream_name = "TX" #id "-CIF-Playback",\
335                         .channels_min = 1,                      \
336                         .channels_max = 8,                      \
337                         .rates = SNDRV_PCM_RATE_8000_192000,    \
338                         .formats = SNDRV_PCM_FMTBIT_S8 |        \
339                                 SNDRV_PCM_FMTBIT_S16_LE |       \
340                                 SNDRV_PCM_FMTBIT_S32_LE,        \
341                 },                                              \
342                 .capture = {                                    \
343                         .stream_name = "TX" #id "-CIF-Capture", \
344                         .channels_min = 1,                      \
345                         .channels_max = 8,                      \
346                         .rates = SNDRV_PCM_RATE_8000_192000,    \
347                         .formats = SNDRV_PCM_FMTBIT_S8 |        \
348                                 SNDRV_PCM_FMTBIT_S16_LE |       \
349                                 SNDRV_PCM_FMTBIT_S32_LE,        \
350                 },                                              \
351                 .ops = &tegra210_mixer_out_dai_ops,             \
352         }
353
354 static struct snd_soc_dai_driver tegra210_mixer_dais[] = {
355         /* Mixer Input */
356         IN_DAI(1),
357         IN_DAI(2),
358         IN_DAI(3),
359         IN_DAI(4),
360         IN_DAI(5),
361         IN_DAI(6),
362         IN_DAI(7),
363         IN_DAI(8),
364         IN_DAI(9),
365         IN_DAI(10),
366
367         /* Mixer Output */
368         OUT_DAI(1),
369         OUT_DAI(2),
370         OUT_DAI(3),
371         OUT_DAI(4),
372         OUT_DAI(5),
373 };
374
375 #define ADDER_CTRL_DECL(name, reg)                      \
376         static const struct snd_kcontrol_new name[] = { \
377                 SOC_DAPM_SINGLE("RX1", reg, 0, 1, 0),   \
378                 SOC_DAPM_SINGLE("RX2", reg, 1, 1, 0),   \
379                 SOC_DAPM_SINGLE("RX3", reg, 2, 1, 0),   \
380                 SOC_DAPM_SINGLE("RX4", reg, 3, 1, 0),   \
381                 SOC_DAPM_SINGLE("RX5", reg, 4, 1, 0),   \
382                 SOC_DAPM_SINGLE("RX6", reg, 5, 1, 0),   \
383                 SOC_DAPM_SINGLE("RX7", reg, 6, 1, 0),   \
384                 SOC_DAPM_SINGLE("RX8", reg, 7, 1, 0),   \
385                 SOC_DAPM_SINGLE("RX9", reg, 8, 1, 0),   \
386                 SOC_DAPM_SINGLE("RX10", reg, 9, 1, 0),  \
387         }
388
389 ADDER_CTRL_DECL(adder1, TEGRA210_MIXER_TX1_ADDER_CONFIG);
390 ADDER_CTRL_DECL(adder2, TEGRA210_MIXER_TX2_ADDER_CONFIG);
391 ADDER_CTRL_DECL(adder3, TEGRA210_MIXER_TX3_ADDER_CONFIG);
392 ADDER_CTRL_DECL(adder4, TEGRA210_MIXER_TX4_ADDER_CONFIG);
393 ADDER_CTRL_DECL(adder5, TEGRA210_MIXER_TX5_ADDER_CONFIG);
394
395 #define GAIN_CTRL(id)   \
396         SOC_SINGLE_EXT("RX" #id " Gain Volume",                 \
397                        MIXER_GAIN_CFG_RAM_ADDR((id) - 1), 0,    \
398                        0x20000, 0, tegra210_mixer_get_gain,     \
399                        tegra210_mixer_put_gain),                \
400         SOC_SINGLE_EXT("RX" #id " Instant Gain Volume",         \
401                        MIXER_GAIN_CFG_RAM_ADDR((id) - 1), 0,    \
402                        0x20000, 0, tegra210_mixer_get_gain,     \
403                        tegra210_mixer_put_instant_gain),
404
405 /* Volume controls for all MIXER inputs */
406 static const struct snd_kcontrol_new tegra210_mixer_gain_ctls[] = {
407         GAIN_CTRL(1)
408         GAIN_CTRL(2)
409         GAIN_CTRL(3)
410         GAIN_CTRL(4)
411         GAIN_CTRL(5)
412         GAIN_CTRL(6)
413         GAIN_CTRL(7)
414         GAIN_CTRL(8)
415         GAIN_CTRL(9)
416         GAIN_CTRL(10)
417 };
418
419 static const struct snd_soc_dapm_widget tegra210_mixer_widgets[] = {
420         SND_SOC_DAPM_AIF_IN("RX1", NULL, 0, SND_SOC_NOPM, 0, 0),
421         SND_SOC_DAPM_AIF_IN("RX2", NULL, 0, SND_SOC_NOPM, 0, 0),
422         SND_SOC_DAPM_AIF_IN("RX3", NULL, 0, SND_SOC_NOPM, 0, 0),
423         SND_SOC_DAPM_AIF_IN("RX4", NULL, 0, SND_SOC_NOPM, 0, 0),
424         SND_SOC_DAPM_AIF_IN("RX5", NULL, 0, SND_SOC_NOPM, 0, 0),
425         SND_SOC_DAPM_AIF_IN("RX6", NULL, 0, SND_SOC_NOPM, 0, 0),
426         SND_SOC_DAPM_AIF_IN("RX7", NULL, 0, SND_SOC_NOPM, 0, 0),
427         SND_SOC_DAPM_AIF_IN("RX8", NULL, 0, SND_SOC_NOPM, 0, 0),
428         SND_SOC_DAPM_AIF_IN("RX9", NULL, 0, SND_SOC_NOPM, 0, 0),
429         SND_SOC_DAPM_AIF_IN("RX10", NULL, 0, SND_SOC_NOPM, 0, 0),
430         SND_SOC_DAPM_AIF_OUT("TX1", NULL, 0, TEGRA210_MIXER_TX1_ENABLE, 0, 0),
431         SND_SOC_DAPM_AIF_OUT("TX2", NULL, 0, TEGRA210_MIXER_TX2_ENABLE, 0, 0),
432         SND_SOC_DAPM_AIF_OUT("TX3", NULL, 0, TEGRA210_MIXER_TX3_ENABLE, 0, 0),
433         SND_SOC_DAPM_AIF_OUT("TX4", NULL, 0, TEGRA210_MIXER_TX4_ENABLE, 0, 0),
434         SND_SOC_DAPM_AIF_OUT("TX5", NULL, 0, TEGRA210_MIXER_TX5_ENABLE, 0, 0),
435         SND_SOC_DAPM_MIXER("Adder1", SND_SOC_NOPM, 1, 0, adder1,
436                            ARRAY_SIZE(adder1)),
437         SND_SOC_DAPM_MIXER("Adder2", SND_SOC_NOPM, 1, 0, adder2,
438                            ARRAY_SIZE(adder2)),
439         SND_SOC_DAPM_MIXER("Adder3", SND_SOC_NOPM, 1, 0, adder3,
440                            ARRAY_SIZE(adder3)),
441         SND_SOC_DAPM_MIXER("Adder4", SND_SOC_NOPM, 1, 0, adder4,
442                            ARRAY_SIZE(adder4)),
443         SND_SOC_DAPM_MIXER("Adder5", SND_SOC_NOPM, 1, 0, adder5,
444                            ARRAY_SIZE(adder5)),
445 };
446
447 #define RX_ROUTES(id, sname)                                               \
448         { "RX" #id " XBAR-" sname,      NULL,   "RX" #id " XBAR-TX" },     \
449         { "RX" #id "-CIF-" sname,       NULL,   "RX" #id " XBAR-" sname }, \
450         { "RX" #id,                     NULL,   "RX" #id "-CIF-" sname }
451
452 #define MIXER_RX_ROUTES(id)             \
453         RX_ROUTES(id, "Playback"),      \
454         RX_ROUTES(id, "Capture")
455
456 #define ADDER_ROUTES(id, sname)                                           \
457         { "Adder" #id,                  "RX1",  "RX1" },                  \
458         { "Adder" #id,                  "RX2",  "RX2" },                  \
459         { "Adder" #id,                  "RX3",  "RX3" },                  \
460         { "Adder" #id,                  "RX4",  "RX4" },                  \
461         { "Adder" #id,                  "RX5",  "RX5" },                  \
462         { "Adder" #id,                  "RX6",  "RX6" },                  \
463         { "Adder" #id,                  "RX7",  "RX7" },                  \
464         { "Adder" #id,                  "RX8",  "RX8" },                  \
465         { "Adder" #id,                  "RX9",  "RX9" },                  \
466         { "Adder" #id,                  "RX10", "RX10" },                 \
467         { "TX" #id,                     NULL,   "Adder" #id },            \
468         { "TX" #id "-CIF-" sname,       NULL,   "TX" #id },               \
469         { "TX" #id " XBAR-" sname,      NULL,   "TX" #id "-CIF-" sname }, \
470         { "TX" #id " XBAR-RX",          NULL,   "TX" #id " XBAR-" sname } \
471
472 #define TX_ROUTES(id, sname)            \
473         ADDER_ROUTES(1, sname),         \
474         ADDER_ROUTES(2, sname),         \
475         ADDER_ROUTES(3, sname),         \
476         ADDER_ROUTES(4, sname),         \
477         ADDER_ROUTES(5, sname)
478
479 #define MIXER_TX_ROUTES(id)             \
480         TX_ROUTES(id, "Playback"),      \
481         TX_ROUTES(id, "Capture")
482
483 static const struct snd_soc_dapm_route tegra210_mixer_routes[] = {
484         /* Input */
485         MIXER_RX_ROUTES(1),
486         MIXER_RX_ROUTES(2),
487         MIXER_RX_ROUTES(3),
488         MIXER_RX_ROUTES(4),
489         MIXER_RX_ROUTES(5),
490         MIXER_RX_ROUTES(6),
491         MIXER_RX_ROUTES(7),
492         MIXER_RX_ROUTES(8),
493         MIXER_RX_ROUTES(9),
494         MIXER_RX_ROUTES(10),
495         /* Output */
496         MIXER_TX_ROUTES(1),
497         MIXER_TX_ROUTES(2),
498         MIXER_TX_ROUTES(3),
499         MIXER_TX_ROUTES(4),
500         MIXER_TX_ROUTES(5),
501 };
502
503 static const struct snd_soc_component_driver tegra210_mixer_cmpnt = {
504         .dapm_widgets           = tegra210_mixer_widgets,
505         .num_dapm_widgets       = ARRAY_SIZE(tegra210_mixer_widgets),
506         .dapm_routes            = tegra210_mixer_routes,
507         .num_dapm_routes        = ARRAY_SIZE(tegra210_mixer_routes),
508         .controls               = tegra210_mixer_gain_ctls,
509         .num_controls           = ARRAY_SIZE(tegra210_mixer_gain_ctls),
510 };
511
512 static bool tegra210_mixer_wr_reg(struct device *dev,
513                                 unsigned int reg)
514 {
515         if (reg < TEGRA210_MIXER_RX_LIMIT)
516                 reg = MIXER_REG_BASE(reg);
517         else if (reg < TEGRA210_MIXER_TX_LIMIT)
518                 reg = MIXER_REG_BASE(reg) + TEGRA210_MIXER_TX1_ENABLE;
519
520         switch (reg) {
521         case TEGRA210_MIXER_RX1_SOFT_RESET:
522         case TEGRA210_MIXER_RX1_CIF_CTRL ... TEGRA210_MIXER_RX1_PEAK_CTRL:
523
524         case TEGRA210_MIXER_TX1_ENABLE:
525         case TEGRA210_MIXER_TX1_SOFT_RESET:
526         case TEGRA210_MIXER_TX1_INT_MASK ... TEGRA210_MIXER_TX1_ADDER_CONFIG:
527
528         case TEGRA210_MIXER_ENABLE ... TEGRA210_MIXER_CG:
529         case TEGRA210_MIXER_GAIN_CFG_RAM_CTRL ... TEGRA210_MIXER_CTRL:
530                 return true;
531         default:
532                 return false;
533         }
534 }
535
536 static bool tegra210_mixer_rd_reg(struct device *dev,
537                                 unsigned int reg)
538 {
539         if (reg < TEGRA210_MIXER_RX_LIMIT)
540                 reg = MIXER_REG_BASE(reg);
541         else if (reg < TEGRA210_MIXER_TX_LIMIT)
542                 reg = MIXER_REG_BASE(reg) + TEGRA210_MIXER_TX1_ENABLE;
543
544         switch (reg) {
545         case TEGRA210_MIXER_RX1_SOFT_RESET ... TEGRA210_MIXER_RX1_SAMPLE_COUNT:
546         case TEGRA210_MIXER_TX1_ENABLE ... TEGRA210_MIXER_TX1_ADDER_CONFIG:
547         case TEGRA210_MIXER_ENABLE ... TEGRA210_MIXER_CTRL:
548                 return true;
549         default:
550                 return false;
551         }
552 }
553
554 static bool tegra210_mixer_volatile_reg(struct device *dev,
555                                 unsigned int reg)
556 {
557         if (reg < TEGRA210_MIXER_RX_LIMIT)
558                 reg = MIXER_REG_BASE(reg);
559         else if (reg < TEGRA210_MIXER_TX_LIMIT)
560                 reg = MIXER_REG_BASE(reg) + TEGRA210_MIXER_TX1_ENABLE;
561
562         switch (reg) {
563         case TEGRA210_MIXER_RX1_SOFT_RESET:
564         case TEGRA210_MIXER_RX1_STATUS:
565
566         case TEGRA210_MIXER_TX1_SOFT_RESET:
567         case TEGRA210_MIXER_TX1_STATUS:
568         case TEGRA210_MIXER_TX1_INT_STATUS:
569         case TEGRA210_MIXER_TX1_INT_SET:
570
571         case TEGRA210_MIXER_SOFT_RESET:
572         case TEGRA210_MIXER_STATUS:
573         case TEGRA210_MIXER_INT_STATUS:
574         case TEGRA210_MIXER_GAIN_CFG_RAM_CTRL:
575         case TEGRA210_MIXER_GAIN_CFG_RAM_DATA:
576         case TEGRA210_MIXER_PEAKM_RAM_CTRL:
577         case TEGRA210_MIXER_PEAKM_RAM_DATA:
578                 return true;
579         default:
580                 return false;
581         }
582 }
583
584 static bool tegra210_mixer_precious_reg(struct device *dev,
585                                 unsigned int reg)
586 {
587         switch (reg) {
588         case TEGRA210_MIXER_GAIN_CFG_RAM_DATA:
589         case TEGRA210_MIXER_PEAKM_RAM_DATA:
590                 return true;
591         default:
592                 return false;
593         }
594 }
595
596 static const struct regmap_config tegra210_mixer_regmap_config = {
597         .reg_bits               = 32,
598         .reg_stride             = 4,
599         .val_bits               = 32,
600         .max_register           = TEGRA210_MIXER_CTRL,
601         .writeable_reg          = tegra210_mixer_wr_reg,
602         .readable_reg           = tegra210_mixer_rd_reg,
603         .volatile_reg           = tegra210_mixer_volatile_reg,
604         .precious_reg           = tegra210_mixer_precious_reg,
605         .reg_defaults           = tegra210_mixer_reg_defaults,
606         .num_reg_defaults       = ARRAY_SIZE(tegra210_mixer_reg_defaults),
607         .cache_type             = REGCACHE_FLAT,
608 };
609
610 static const struct of_device_id tegra210_mixer_of_match[] = {
611         { .compatible = "nvidia,tegra210-amixer" },
612         {},
613 };
614 MODULE_DEVICE_TABLE(of, tegra210_mixer_of_match);
615
616 static int tegra210_mixer_platform_probe(struct platform_device *pdev)
617 {
618         struct device *dev = &pdev->dev;
619         struct tegra210_mixer *mixer;
620         void __iomem *regs;
621         int err, i;
622
623         mixer = devm_kzalloc(dev, sizeof(*mixer), GFP_KERNEL);
624         if (!mixer)
625                 return -ENOMEM;
626
627         dev_set_drvdata(dev, mixer);
628
629         /* Use default gain value for all MIXER inputs */
630         for (i = 0; i < TEGRA210_MIXER_RX_MAX; i++)
631                 mixer->gain_value[i] = gain_params.gain_value;
632
633         regs = devm_platform_ioremap_resource(pdev, 0);
634         if (IS_ERR(regs))
635                 return PTR_ERR(regs);
636
637         mixer->regmap = devm_regmap_init_mmio(dev, regs,
638                                               &tegra210_mixer_regmap_config);
639         if (IS_ERR(mixer->regmap)) {
640                 dev_err(dev, "regmap init failed\n");
641                 return PTR_ERR(mixer->regmap);
642         }
643
644         regcache_cache_only(mixer->regmap, true);
645
646         err = devm_snd_soc_register_component(dev, &tegra210_mixer_cmpnt,
647                                               tegra210_mixer_dais,
648                                               ARRAY_SIZE(tegra210_mixer_dais));
649         if (err) {
650                 dev_err(dev, "can't register MIXER component, err: %d\n", err);
651                 return err;
652         }
653
654         pm_runtime_enable(dev);
655
656         return 0;
657 }
658
659 static int tegra210_mixer_platform_remove(struct platform_device *pdev)
660 {
661         pm_runtime_disable(&pdev->dev);
662
663         return 0;
664 }
665
666 static const struct dev_pm_ops tegra210_mixer_pm_ops = {
667         SET_RUNTIME_PM_OPS(tegra210_mixer_runtime_suspend,
668                            tegra210_mixer_runtime_resume, NULL)
669         SET_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend,
670                                 pm_runtime_force_resume)
671 };
672
673 static struct platform_driver tegra210_mixer_driver = {
674         .driver = {
675                 .name = "tegra210_mixer",
676                 .of_match_table = tegra210_mixer_of_match,
677                 .pm = &tegra210_mixer_pm_ops,
678         },
679         .probe = tegra210_mixer_platform_probe,
680         .remove = tegra210_mixer_platform_remove,
681 };
682 module_platform_driver(tegra210_mixer_driver);
683
684 MODULE_AUTHOR("Arun Shamanna Lakshmi <aruns@nvidia.com>");
685 MODULE_DESCRIPTION("Tegra210 MIXER ASoC driver");
686 MODULE_LICENSE("GPL v2");