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