]> rtime.felk.cvut.cz Git - hercules2020/nv-tegra/linux-4.4.git/blob - sound/soc/tegra-alt/tegra210_mvc_alt.c
176c19bf6a4ccf7f036510b7aecf6ac079963b75
[hercules2020/nv-tegra/linux-4.4.git] / sound / soc / tegra-alt / tegra210_mvc_alt.c
1 /*
2  * tegra210_mvc_alt.c - Tegra210 MVC driver
3  *
4  * Copyright (c) 2014-2017 NVIDIA CORPORATION.  All rights reserved.
5  *
6  * This program is free software; you can redistribute it and/or modify it
7  * under the terms and conditions of the GNU General Public License,
8  * version 2, as published by the Free Software Foundation.
9  *
10  * This program is distributed in the hope it will be useful, but WITHOUT
11  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
12  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
13  * more details.
14  *
15  * You should have received a copy of the GNU General Public License
16  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
17  */
18 #include <linux/clk.h>
19 #include <linux/device.h>
20 #include <linux/io.h>
21 #include <linux/module.h>
22 #include <linux/of.h>
23 #include <linux/platform_device.h>
24 #include <linux/pm_runtime.h>
25 #include <linux/regmap.h>
26 #include <linux/slab.h>
27 #include <sound/core.h>
28 #include <sound/pcm.h>
29 #include <sound/pcm_params.h>
30 #include <sound/soc.h>
31 #include <linux/pinctrl/consumer.h>
32 #include <linux/of_device.h>
33 #include <linux/delay.h>
34
35 #include "tegra210_xbar_alt.h"
36 #include "tegra210_mvc_alt.h"
37
38 #define DRV_NAME "tegra210-mvc"
39
40 static const struct reg_default tegra210_mvc_reg_defaults[] = {
41         { TEGRA210_MVC_AXBAR_RX_INT_MASK, 0x00000001},
42         { TEGRA210_MVC_AXBAR_RX_CIF_CTRL, 0x00007700},
43         { TEGRA210_MVC_AXBAR_TX_INT_MASK, 0x00000001},
44         { TEGRA210_MVC_AXBAR_TX_CIF_CTRL, 0x00007700},
45         { TEGRA210_MVC_CG, 0x1},
46         { TEGRA210_MVC_CTRL, 0x40000001},
47         { TEGRA210_MVC_INIT_VOL, 0x00800000},
48         { TEGRA210_MVC_TARGET_VOL, 0x00800000},
49         { TEGRA210_MVC_DURATION, 0x000012c0},
50         { TEGRA210_MVC_DURATION_INV, 0x0006d3a0},
51         { TEGRA210_MVC_POLY_N1, 0x0000007d},
52         { TEGRA210_MVC_POLY_N2, 0x00000271},
53         { TEGRA210_MVC_PEAK_CTRL, 0x000012c0},
54         { TEGRA210_MVC_AHUBRAMCTL_CONFIG_RAM_CTRL, 0x00004000},
55 };
56
57 static int tegra210_mvc_runtime_suspend(struct device *dev)
58 {
59         struct tegra210_mvc *mvc = dev_get_drvdata(dev);
60
61         regcache_cache_only(mvc->regmap, true);
62
63         pm_runtime_put_sync(dev->parent);
64
65         return 0;
66 }
67
68 static int tegra210_mvc_runtime_resume(struct device *dev)
69 {
70         struct tegra210_mvc *mvc = dev_get_drvdata(dev);
71         int ret;
72
73         ret = pm_runtime_get_sync(dev->parent);
74         if (ret < 0) {
75                 dev_err(dev, "parent get_sync failed: %d\n", ret);
76                 return ret;
77         }
78
79         regcache_cache_only(mvc->regmap, false);
80
81         if (!mvc->is_shutdown) {
82                 regcache_sync(mvc->regmap);
83
84                 regmap_update_bits(mvc->regmap, TEGRA210_MVC_CTRL,
85                         TEGRA210_MVC_CURVE_TYPE_MASK,
86                         mvc->curve_type << TEGRA210_MVC_CURVE_TYPE_SHIFT);
87         }
88
89         return 0;
90 }
91
92 #ifdef CONFIG_PM_SLEEP
93 static int tegra210_mvc_suspend(struct device *dev)
94 {
95         struct tegra210_mvc *mvc = dev_get_drvdata(dev);
96
97         if (mvc)
98                 regcache_mark_dirty(mvc->regmap);
99
100         return 0;
101 }
102 #endif
103
104 static int tegra210_mvc_write_ram(struct tegra210_mvc *mvc,
105                                 unsigned int addr,
106                                 unsigned int val)
107 {
108         unsigned int reg, value, wait = 0xffff;
109
110         /* check if busy */
111         do {
112                 regmap_read(mvc->regmap,
113                         TEGRA210_MVC_AHUBRAMCTL_CONFIG_RAM_CTRL,
114                         &value);
115                 wait--;
116                 if (!wait)
117                         return -EINVAL;
118         } while (value & 0x80000000);
119         value = 0;
120
121         reg = (addr << TEGRA210_MVC_AHUBRAMCTL_CONFIG_RAM_CTRL_RAM_ADDR_SHIFT) &
122                         TEGRA210_MVC_AHUBRAMCTL_CONFIG_RAM_CTRL_RAM_ADDR_MASK;
123         reg |= TEGRA210_MVC_AHUBRAMCTL_CONFIG_RAM_CTRL_ADDR_INIT_EN;
124         reg |= TEGRA210_MVC_AHUBRAMCTL_CONFIG_RAM_CTRL_RW_WRITE;
125         reg |= TEGRA210_MVC_AHUBRAMCTL_CONFIG_RAM_CTRL_SEQ_ACCESS_EN;
126
127         regmap_write(mvc->regmap,
128                 TEGRA210_MVC_AHUBRAMCTL_CONFIG_RAM_CTRL, reg);
129         regmap_write(mvc->regmap,
130                 TEGRA210_MVC_AHUBRAMCTL_CONFIG_RAM_DATA, val);
131
132         return 0;
133 }
134
135 static int tegra210_mvc_get_vol(struct snd_kcontrol *kcontrol,
136         struct snd_ctl_elem_value *ucontrol)
137 {
138         struct soc_mixer_control *mc =
139                 (struct soc_mixer_control *)kcontrol->private_value;
140         struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
141         struct tegra210_mvc *mvc = snd_soc_codec_get_drvdata(codec);
142         unsigned int reg = mc->reg;
143
144         pm_runtime_get_sync(codec->dev);
145         if (reg == TEGRA210_MVC_TARGET_VOL) {
146                 s32 val;
147
148                 regmap_read(mvc->regmap, reg, &val);
149                 if (mvc->curve_type == CURVE_POLY)
150                         val >>= 24;
151                 else {
152                         val >>= 8;
153                         val += 120;
154                 }
155                 ucontrol->value.integer.value[0] = val;
156         } else {
157                 u32 val;
158
159                 regmap_read(mvc->regmap, reg, &val);
160                 ucontrol->value.integer.value[0] =
161                         ((val & TEGRA210_MVC_MUTE_MASK) != 0);
162         }
163         pm_runtime_put(codec->dev);
164         return 0;
165 }
166
167 static int tegra210_mvc_put_vol(struct snd_kcontrol *kcontrol,
168         struct snd_ctl_elem_value *ucontrol)
169 {
170         struct soc_mixer_control *mc =
171                 (struct soc_mixer_control *)kcontrol->private_value;
172         struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
173         struct tegra210_mvc *mvc = snd_soc_codec_get_drvdata(codec);
174         unsigned int reg = mc->reg;
175         unsigned int value, wait = 0xffff;
176         int ret = 0;
177         s32 val;
178
179         pm_runtime_get_sync(codec->dev);
180         /* check if VOLUME_SWITCH is triggered*/
181         do {
182                 regmap_read(mvc->regmap,
183                                 TEGRA210_MVC_SWITCH, &value);
184                 wait--;
185                 if (!wait) {
186                         ret = -EINVAL;
187                         goto end;
188                 }
189         } while (value & TEGRA210_MVC_VOLUME_SWITCH_MASK);
190
191         if (reg == TEGRA210_MVC_TARGET_VOL) {
192                 if (mvc->curve_type == CURVE_POLY) {
193                         val = ucontrol->value.integer.value[0];
194                         if (val > 100)
195                                 val = 100;
196                         mvc->volume = val * (1<<24);
197                 } else {
198                         val = ucontrol->value.integer.value[0] - 120;
199                         val <<= 8;
200                         mvc->volume = val;
201                 }
202                 ret = regmap_write(mvc->regmap, reg, mvc->volume);
203         } else {
204                 ret = regmap_update_bits(mvc->regmap, reg,
205                                 TEGRA210_MVC_MUTE_MASK,
206                                 (ucontrol->value.integer.value[0] ?
207                                 TEGRA210_MVC_MUTE_EN : 0));
208         }
209         ret |= regmap_update_bits(mvc->regmap, TEGRA210_MVC_SWITCH,
210                         TEGRA210_MVC_VOLUME_SWITCH_MASK,
211                         TEGRA210_MVC_VOLUME_SWITCH_TRIGGER);
212
213 end:
214         pm_runtime_put(codec->dev);
215
216         return ret;
217 }
218
219 static int tegra210_mvc_get_curve_type(struct snd_kcontrol *kcontrol,
220         struct snd_ctl_elem_value *ucontrol)
221 {
222         struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
223         struct tegra210_mvc *mvc = snd_soc_codec_get_drvdata(codec);
224         unsigned int reg = TEGRA210_MVC_CTRL;
225         u32 val;
226
227         pm_runtime_get_sync(codec->dev);
228         regmap_read(mvc->regmap, reg, &val);
229         ucontrol->value.integer.value[0] =
230                 (val & TEGRA210_MVC_CURVE_TYPE_MASK) >>
231                 TEGRA210_MVC_CURVE_TYPE_SHIFT;
232         pm_runtime_put(codec->dev);
233
234         return 0;
235 }
236
237 static int tegra210_mvc_put_curve_type(struct snd_kcontrol *kcontrol,
238         struct snd_ctl_elem_value *ucontrol)
239 {
240         struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
241         struct tegra210_mvc *mvc = snd_soc_codec_get_drvdata(codec);
242         unsigned int reg = TEGRA210_MVC_CTRL;
243         int dcnt = 10;
244         int ret = 0;
245         u32 value;
246
247         /* if no change in curve type, do nothing */
248         if (mvc->curve_type == ucontrol->value.integer.value[0])
249                 return ret;
250
251         pm_runtime_get_sync(codec->dev);
252
253         /* change curve type */
254         ret |= regmap_update_bits(mvc->regmap, reg,
255                         TEGRA210_MVC_CURVE_TYPE_MASK,
256                         ucontrol->value.integer.value[0] <<
257                         TEGRA210_MVC_CURVE_TYPE_SHIFT);
258         mvc->curve_type = ucontrol->value.integer.value[0];
259
260         /* issue soft reset */
261         regmap_write(mvc->regmap, TEGRA210_MVC_SOFT_RESET, 1);
262         /* wait for soft reset bit to clear */
263         do {
264                 udelay(10);
265                 ret = regmap_read(mvc->regmap, TEGRA210_MVC_SOFT_RESET, &value);
266                 dcnt--;
267                 if (dcnt < 0) {
268                         ret = -EINVAL;
269                         goto end;
270                 }
271         } while (value);
272
273         /* change volume to default init for new curve type */
274         if (ucontrol->value.integer.value[0] == CURVE_POLY)
275                 mvc->volume = TEGRA210_MVC_INIT_VOL_DEFAULT_POLY;
276         else
277                 mvc->volume = TEGRA210_MVC_INIT_VOL_DEFAULT_LINEAR;
278
279 end:
280         pm_runtime_put(codec->dev);
281
282         return ret;
283 }
284
285 static int tegra210_mvc_get_audio_bits(struct snd_kcontrol *kcontrol,
286         struct snd_ctl_elem_value *ucontrol)
287 {
288         struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
289         struct tegra210_mvc *mvc = snd_soc_codec_get_drvdata(codec);
290
291         ucontrol->value.integer.value[0] = (mvc->audio_bits + 1) * 4;
292
293         return 0;
294 }
295
296 static int tegra210_mvc_put_audio_bits(struct snd_kcontrol *kcontrol,
297         struct snd_ctl_elem_value *ucontrol)
298 {
299         struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
300         struct tegra210_mvc *mvc = snd_soc_codec_get_drvdata(codec);
301         unsigned int val;
302
303         val = ucontrol->value.integer.value[0];
304         if ((val >= 8) && (val <= 32) && (val%4 == 0))
305                 mvc->audio_bits = val/4 - 1;
306         else
307                 return -EINVAL;
308
309         return 0;
310 }
311
312 static int tegra210_mvc_get_channels(struct snd_kcontrol *kcontrol,
313         struct snd_ctl_elem_value *ucontrol)
314 {
315         struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
316         struct tegra210_mvc *mvc = snd_soc_codec_get_drvdata(codec);
317
318         ucontrol->value.integer.value[0] = mvc->cif_channels;
319
320         return 0;
321 }
322
323 static int tegra210_mvc_put_channels(struct snd_kcontrol *kcontrol,
324         struct snd_ctl_elem_value *ucontrol)
325 {
326         struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
327         struct tegra210_mvc *mvc = snd_soc_codec_get_drvdata(codec);
328         unsigned int val;
329
330         val = ucontrol->value.integer.value[0];
331         if ((val > 0) && (val <= 8))
332                 mvc->cif_channels = val;
333         else
334                 return -EINVAL;
335
336         return 0;
337 }
338
339 static int tegra210_mvc_set_audio_cif(struct tegra210_mvc *mvc,
340                                 struct snd_pcm_hw_params *params,
341                                 unsigned int reg)
342 {
343         int channels, audio_bits;
344         struct tegra210_xbar_cif_conf cif_conf;
345
346         memset(&cif_conf, 0, sizeof(struct tegra210_xbar_cif_conf));
347
348         channels = params_channels(params);
349         if (mvc->cif_channels > 0)
350                 channels = mvc->cif_channels;
351
352         if (channels > 8)
353                 return -EINVAL;
354
355         switch (params_format(params)) {
356         case SNDRV_PCM_FORMAT_S16_LE:
357                 audio_bits = TEGRA210_AUDIOCIF_BITS_16;
358                 break;
359         case SNDRV_PCM_FORMAT_S32_LE:
360                 audio_bits = TEGRA210_AUDIOCIF_BITS_32;
361                 break;
362         default:
363                 return -EINVAL;
364         }
365
366         if (mvc->audio_bits > 0)
367                 audio_bits = mvc->audio_bits;
368
369         cif_conf.audio_channels = channels;
370         cif_conf.client_channels = channels;
371         cif_conf.audio_bits = audio_bits;
372         cif_conf.client_bits = audio_bits;
373
374         mvc->soc_data->set_audio_cif(mvc->regmap, reg, &cif_conf);
375
376         return 0;
377 }
378
379 static int tegra210_mvc_hw_params(struct snd_pcm_substream *substream,
380                                  struct snd_pcm_hw_params *params,
381                                  struct snd_soc_dai *dai)
382 {
383         struct device *dev = dai->dev;
384         struct tegra210_mvc *mvc = snd_soc_dai_get_drvdata(dai);
385         int i, ret;
386
387         /* set RX cif and TX cif */
388         ret = tegra210_mvc_set_audio_cif(mvc, params,
389                                 TEGRA210_MVC_AXBAR_RX_CIF_CTRL);
390         if (ret) {
391                 dev_err(dev, "Can't set MVC RX CIF: %d\n", ret);
392                 return ret;
393         }
394         ret = tegra210_mvc_set_audio_cif(mvc, params,
395                                 TEGRA210_MVC_AXBAR_TX_CIF_CTRL);
396         if (ret) {
397                 dev_err(dev, "Can't set MVC TX CIF: %d\n", ret);
398                 return ret;
399         }
400
401         /* disable per_channel_cntrl_en */
402         regmap_update_bits(mvc->regmap, TEGRA210_MVC_CTRL,
403                 TEGRA210_MVC_PER_CHAN_CTRL_EN_MASK,
404                 ~(TEGRA210_MVC_PER_CHAN_CTRL_EN_MASK));
405
406         /* init the default volume=1 for MVC */
407         regmap_write(mvc->regmap, TEGRA210_MVC_INIT_VOL,
408                 (mvc->curve_type == CURVE_POLY) ?
409                 TEGRA210_MVC_INIT_VOL_DEFAULT_POLY :
410                 TEGRA210_MVC_INIT_VOL_DEFAULT_LINEAR);
411
412         regmap_write(mvc->regmap, TEGRA210_MVC_TARGET_VOL, mvc->volume);
413         /* trigger volume switch */
414         ret |= regmap_update_bits(mvc->regmap, TEGRA210_MVC_SWITCH,
415                         TEGRA210_MVC_VOLUME_SWITCH_MASK,
416                         TEGRA210_MVC_VOLUME_SWITCH_TRIGGER);
417
418
419         /* program the poly coefficients */
420         for (i = 0; i < 9; i++)
421                 tegra210_mvc_write_ram(mvc, i, mvc->poly_coeff[i]);
422
423
424         /* program poly_n1, poly_n2, duration */
425         regmap_write(mvc->regmap, TEGRA210_MVC_POLY_N1, mvc->poly_n1);
426         regmap_write(mvc->regmap, TEGRA210_MVC_POLY_N2, mvc->poly_n2);
427         regmap_write(mvc->regmap, TEGRA210_MVC_DURATION, mvc->duration);
428
429         /* program duration_inv */
430         regmap_write(mvc->regmap, TEGRA210_MVC_DURATION_INV, mvc->duration_inv);
431
432         return ret;
433 }
434
435 static int tegra210_mvc_codec_probe(struct snd_soc_codec *codec)
436 {
437         struct tegra210_mvc *mvc = snd_soc_codec_get_drvdata(codec);
438
439         codec->control_data = mvc->regmap;
440
441         return 0;
442 }
443
444 static struct snd_soc_dai_ops tegra210_mvc_dai_ops = {
445         .hw_params      = tegra210_mvc_hw_params,
446 };
447
448 static const unsigned int tegra210_mvc_curve_type_values[] = {
449         CURVE_POLY,
450         CURVE_LINEAR,
451 };
452
453 static const char * const tegra210_mvc_curve_type_text[] = {
454         "Poly",
455         "Linear",
456 };
457
458 static const struct soc_enum tegra210_mvc_curve_type_ctrl =
459         SOC_ENUM_SINGLE_EXT(2, tegra210_mvc_curve_type_text);
460
461 static const struct snd_kcontrol_new tegra210_mvc_vol_ctrl[] = {
462         SOC_SINGLE_EXT("Vol", TEGRA210_MVC_TARGET_VOL, 0, 160, 0,
463                 tegra210_mvc_get_vol, tegra210_mvc_put_vol),
464         SOC_SINGLE_EXT("Mute", TEGRA210_MVC_CTRL, 0, 1, 0,
465                 tegra210_mvc_get_vol, tegra210_mvc_put_vol),
466         SOC_ENUM_EXT("Curve Type", tegra210_mvc_curve_type_ctrl,
467                 tegra210_mvc_get_curve_type, tegra210_mvc_put_curve_type),
468         SOC_SINGLE_EXT("Bits", 0, 0, 32, 0,
469                 tegra210_mvc_get_audio_bits, tegra210_mvc_put_audio_bits),
470         SOC_SINGLE_EXT("Channels", 0, 0, 16, 0,
471                 tegra210_mvc_get_channels, tegra210_mvc_put_channels),
472 };
473
474 static struct snd_soc_dai_driver tegra210_mvc_dais[] = {
475         {
476                 .name = "MVC IN",
477                 .playback = {
478                         .stream_name = "MVC Receive",
479                         .channels_min = 1,
480                         .channels_max = 8,
481                         .rates = SNDRV_PCM_RATE_8000_192000,
482                         .formats = SNDRV_PCM_FMTBIT_S8 |
483                                 SNDRV_PCM_FMTBIT_S16_LE |
484                                 SNDRV_PCM_FMTBIT_S24_LE |
485                                 SNDRV_PCM_FMTBIT_S32_LE,
486                 },
487         },
488         {
489                 .name = "MVC OUT",
490                 .capture = {
491                         .stream_name = "MVC Transmit",
492                         .channels_min = 1,
493                         .channels_max = 8,
494                         .rates = SNDRV_PCM_RATE_8000_192000,
495                         .formats = SNDRV_PCM_FMTBIT_S8 |
496                                 SNDRV_PCM_FMTBIT_S16_LE |
497                                 SNDRV_PCM_FMTBIT_S24_LE |
498                                 SNDRV_PCM_FMTBIT_S32_LE,
499                 },
500                 .ops = &tegra210_mvc_dai_ops,
501         }
502 };
503
504 static const struct snd_soc_dapm_widget tegra210_mvc_widgets[] = {
505         SND_SOC_DAPM_AIF_IN("MVC RX", NULL, 0, SND_SOC_NOPM,
506                                 0, 0),
507         SND_SOC_DAPM_AIF_OUT("MVC TX", NULL, 0, TEGRA210_MVC_ENABLE,
508                                 TEGRA210_MVC_EN_SHIFT, 0),
509 };
510
511 static const struct snd_soc_dapm_route tegra210_mvc_routes[] = {
512         { "MVC RX",       NULL, "MVC Receive" },
513         { "MVC TX",       NULL, "MVC RX" },
514         { "MVC Transmit", NULL, "MVC TX" },
515 };
516
517 static struct snd_soc_codec_driver tegra210_mvc_codec = {
518         .probe = tegra210_mvc_codec_probe,
519         .dapm_widgets = tegra210_mvc_widgets,
520         .num_dapm_widgets = ARRAY_SIZE(tegra210_mvc_widgets),
521         .dapm_routes = tegra210_mvc_routes,
522         .num_dapm_routes = ARRAY_SIZE(tegra210_mvc_routes),
523         .controls = tegra210_mvc_vol_ctrl,
524         .num_controls = ARRAY_SIZE(tegra210_mvc_vol_ctrl),
525         .idle_bias_off = 1,
526 };
527
528 static bool tegra210_mvc_wr_rd_reg(struct device *dev, unsigned int reg)
529 {
530         switch (reg) {
531         case TEGRA210_MVC_AXBAR_RX_STATUS:
532         case TEGRA210_MVC_AXBAR_RX_INT_STATUS:
533         case TEGRA210_MVC_AXBAR_RX_INT_MASK:
534         case TEGRA210_MVC_AXBAR_RX_INT_SET:
535         case TEGRA210_MVC_AXBAR_RX_INT_CLEAR:
536         case TEGRA210_MVC_AXBAR_RX_CIF_CTRL:
537         case TEGRA210_MVC_AXBAR_RX_CYA:
538         case TEGRA210_MVC_AXBAR_RX_DBG:
539         case TEGRA210_MVC_AXBAR_TX_STATUS:
540         case TEGRA210_MVC_AXBAR_TX_INT_STATUS:
541         case TEGRA210_MVC_AXBAR_TX_INT_MASK:
542         case TEGRA210_MVC_AXBAR_TX_INT_SET:
543         case TEGRA210_MVC_AXBAR_TX_INT_CLEAR:
544         case TEGRA210_MVC_AXBAR_TX_CIF_CTRL:
545         case TEGRA210_MVC_AXBAR_TX_CYA:
546         case TEGRA210_MVC_AXBAR_TX_DBG:
547         case TEGRA210_MVC_ENABLE:
548         case TEGRA210_MVC_SOFT_RESET:
549         case TEGRA210_MVC_CG:
550         case TEGRA210_MVC_STATUS:
551         case TEGRA210_MVC_INT_STATUS:
552         case TEGRA210_MVC_CTRL:
553         case TEGRA210_MVC_SWITCH:
554         case TEGRA210_MVC_INIT_VOL:
555         case TEGRA210_MVC_TARGET_VOL:
556         case TEGRA210_MVC_DURATION:
557         case TEGRA210_MVC_DURATION_INV:
558         case TEGRA210_MVC_POLY_N1:
559         case TEGRA210_MVC_POLY_N2:
560         case TEGRA210_MVC_PEAK_CTRL:
561         case TEGRA210_MVC_AHUBRAMCTL_CONFIG_RAM_CTRL:
562         case TEGRA210_MVC_AHUBRAMCTL_CONFIG_RAM_DATA:
563         case TEGRA210_MVC_PEAK_VALUE:
564         case TEGRA210_MVC_CONFIG_ERR_TYPE:
565         case TEGRA210_MVC_CYA:
566         case TEGRA210_MVC_DBG:
567                 return true;
568         default:
569                 return false;
570         };
571 }
572
573 static bool tegra210_mvc_volatile_reg(struct device *dev, unsigned int reg)
574 {
575         switch (reg) {
576         case TEGRA210_MVC_AXBAR_RX_STATUS:
577         case TEGRA210_MVC_AXBAR_RX_INT_STATUS:
578         case TEGRA210_MVC_AXBAR_RX_INT_SET:
579
580         case TEGRA210_MVC_AXBAR_TX_STATUS:
581         case TEGRA210_MVC_AXBAR_TX_INT_STATUS:
582         case TEGRA210_MVC_AXBAR_TX_INT_SET:
583
584         case TEGRA210_MVC_SOFT_RESET:
585         case TEGRA210_MVC_STATUS:
586         case TEGRA210_MVC_INT_STATUS:
587         case TEGRA210_MVC_SWITCH:
588         case TEGRA210_MVC_AHUBRAMCTL_CONFIG_RAM_CTRL:
589         case TEGRA210_MVC_AHUBRAMCTL_CONFIG_RAM_DATA:
590         case TEGRA210_MVC_PEAK_VALUE:
591         case TEGRA210_MVC_CTRL:
592                 return true;
593         default:
594                 return false;
595         };
596 }
597
598 static const struct regmap_config tegra210_mvc_regmap_config = {
599         .reg_bits = 32,
600         .reg_stride = 4,
601         .val_bits = 32,
602         .max_register = TEGRA210_MVC_CYA,
603         .writeable_reg = tegra210_mvc_wr_rd_reg,
604         .readable_reg = tegra210_mvc_wr_rd_reg,
605         .volatile_reg = tegra210_mvc_volatile_reg,
606         .reg_defaults = tegra210_mvc_reg_defaults,
607         .num_reg_defaults = ARRAY_SIZE(tegra210_mvc_reg_defaults),
608         .cache_type = REGCACHE_FLAT,
609 };
610
611 static const struct tegra210_mvc_soc_data soc_data_tegra210 = {
612         .set_audio_cif = tegra210_xbar_set_cif,
613 };
614
615 static const struct of_device_id tegra210_mvc_of_match[] = {
616         { .compatible = "nvidia,tegra210-mvc", .data = &soc_data_tegra210 },
617         {},
618 };
619
620 static int tegra210_mvc_platform_probe(struct platform_device *pdev)
621 {
622         struct tegra210_mvc *mvc;
623         struct resource *mem, *memregion;
624         void __iomem *regs;
625         int ret = 0;
626         const struct of_device_id *match;
627         struct tegra210_mvc_soc_data *soc_data;
628
629         match = of_match_device(tegra210_mvc_of_match, &pdev->dev);
630         if (!match) {
631                 dev_err(&pdev->dev, "Error: No device match found\n");
632                 ret = -ENODEV;
633                 goto err;
634         }
635         soc_data = (struct tegra210_mvc_soc_data *)match->data;
636
637         mvc = devm_kzalloc(&pdev->dev, sizeof(struct tegra210_mvc), GFP_KERNEL);
638         if (!mvc) {
639                 dev_err(&pdev->dev, "Can't allocate mvc\n");
640                 ret = -ENOMEM;
641                 goto err;
642         }
643
644         mvc->soc_data = soc_data;
645         mvc->is_shutdown = false;
646
647         mvc->poly_n1 = 16;
648         mvc->poly_n2 = 63;
649         mvc->duration = 150;
650         mvc->duration_inv = 14316558;
651         mvc->poly_coeff[0] = 23738319;
652         mvc->poly_coeff[1] = 659403;
653         mvc->poly_coeff[2] = -3680;
654         mvc->poly_coeff[3] = 15546680;
655         mvc->poly_coeff[4] = 2530732;
656         mvc->poly_coeff[5] = -120985;
657         mvc->poly_coeff[6] = 12048422;
658         mvc->poly_coeff[7] = 5527252;
659         mvc->poly_coeff[8] = -785042;
660         mvc->curve_type = CURVE_LINEAR;
661         mvc->volume = TEGRA210_MVC_INIT_VOL_DEFAULT_POLY;
662
663         mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
664         if (!mem) {
665                 dev_err(&pdev->dev, "No memory resource\n");
666                 ret = -ENODEV;
667                 goto err;
668         }
669
670         memregion = devm_request_mem_region(&pdev->dev, mem->start,
671                                             resource_size(mem), pdev->name);
672         if (!memregion) {
673                 dev_err(&pdev->dev, "Memory region already claimed\n");
674                 ret = -EBUSY;
675                 goto err;
676         }
677
678         regs = devm_ioremap(&pdev->dev, mem->start, resource_size(mem));
679         if (!regs) {
680                 dev_err(&pdev->dev, "ioremap failed\n");
681                 ret = -ENOMEM;
682                 goto err;
683         }
684
685         mvc->regmap = devm_regmap_init_mmio(&pdev->dev, regs,
686                                             &tegra210_mvc_regmap_config);
687         if (IS_ERR(mvc->regmap)) {
688                 dev_err(&pdev->dev, "regmap init failed\n");
689                 ret = PTR_ERR(mvc->regmap);
690                 goto err;
691         }
692         regcache_cache_only(mvc->regmap, true);
693
694         if (of_property_read_u32(pdev->dev.of_node,
695                                 "nvidia,ahub-mvc-id",
696                                 &pdev->dev.id) < 0) {
697                 dev_err(&pdev->dev,
698                         "Missing property nvidia,ahub-mvc-id\n");
699                 ret = -ENODEV;
700                 goto err;
701         }
702
703         pm_runtime_enable(&pdev->dev);
704         if (!pm_runtime_enabled(&pdev->dev)) {
705                 ret = tegra210_mvc_runtime_resume(&pdev->dev);
706                 if (ret)
707                         goto err_pm_disable;
708         }
709
710         ret = snd_soc_register_codec(&pdev->dev, &tegra210_mvc_codec,
711                                      tegra210_mvc_dais,
712                                      ARRAY_SIZE(tegra210_mvc_dais));
713         if (ret != 0) {
714                 dev_err(&pdev->dev, "Could not register CODEC: %d\n", ret);
715                 goto err_suspend;
716         }
717
718         dev_set_drvdata(&pdev->dev, mvc);
719
720         return 0;
721
722 err_suspend:
723         if (!pm_runtime_status_suspended(&pdev->dev))
724                 tegra210_mvc_runtime_suspend(&pdev->dev);
725 err_pm_disable:
726         pm_runtime_disable(&pdev->dev);
727 err:
728         return ret;
729 }
730
731 static void tegra210_mvc_platform_shutdown(struct platform_device *pdev)
732 {
733         struct tegra210_mvc *mvc = dev_get_drvdata(&pdev->dev);
734
735         mvc->is_shutdown = true;
736 }
737
738 static int tegra210_mvc_platform_remove(struct platform_device *pdev)
739 {
740         snd_soc_unregister_codec(&pdev->dev);
741
742         pm_runtime_disable(&pdev->dev);
743         if (!pm_runtime_status_suspended(&pdev->dev))
744                 tegra210_mvc_runtime_suspend(&pdev->dev);
745
746         return 0;
747 }
748
749 static const struct dev_pm_ops tegra210_mvc_pm_ops = {
750         SET_RUNTIME_PM_OPS(tegra210_mvc_runtime_suspend,
751                            tegra210_mvc_runtime_resume, NULL)
752         SET_SYSTEM_SLEEP_PM_OPS(tegra210_mvc_suspend, NULL)
753 };
754
755 static struct platform_driver tegra210_mvc_driver = {
756         .driver = {
757                 .name = DRV_NAME,
758                 .owner = THIS_MODULE,
759                 .of_match_table = tegra210_mvc_of_match,
760                 .pm = &tegra210_mvc_pm_ops,
761         },
762         .probe = tegra210_mvc_platform_probe,
763         .remove = tegra210_mvc_platform_remove,
764         .shutdown = tegra210_mvc_platform_shutdown,
765 };
766 module_platform_driver(tegra210_mvc_driver)
767
768 MODULE_AUTHOR("Arun Shamanna Lakshmi <aruns@nvidia.com>");
769 MODULE_DESCRIPTION("Tegra210 MVC ASoC driver");
770 MODULE_LICENSE("GPL");
771 MODULE_ALIAS("platform:" DRV_NAME);
772 MODULE_DEVICE_TABLE(of, tegra210_mvc_of_match);