2 * tegra210_mvc_alt.c - Tegra210 MVC driver
4 * Copyright (c) 2014-2017 NVIDIA CORPORATION. All rights reserved.
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.
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
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/>.
18 #include <linux/clk.h>
19 #include <linux/device.h>
21 #include <linux/module.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>
35 #include "tegra210_xbar_alt.h"
36 #include "tegra210_mvc_alt.h"
38 #define DRV_NAME "tegra210-mvc"
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},
57 static int tegra210_mvc_runtime_suspend(struct device *dev)
59 struct tegra210_mvc *mvc = dev_get_drvdata(dev);
61 regcache_cache_only(mvc->regmap, true);
63 pm_runtime_put_sync(dev->parent);
68 static int tegra210_mvc_runtime_resume(struct device *dev)
70 struct tegra210_mvc *mvc = dev_get_drvdata(dev);
73 ret = pm_runtime_get_sync(dev->parent);
75 dev_err(dev, "parent get_sync failed: %d\n", ret);
79 regcache_cache_only(mvc->regmap, false);
81 if (!mvc->is_shutdown) {
82 regcache_sync(mvc->regmap);
84 regmap_update_bits(mvc->regmap, TEGRA210_MVC_CTRL,
85 TEGRA210_MVC_CURVE_TYPE_MASK,
86 mvc->curve_type << TEGRA210_MVC_CURVE_TYPE_SHIFT);
92 #ifdef CONFIG_PM_SLEEP
93 static int tegra210_mvc_suspend(struct device *dev)
95 struct tegra210_mvc *mvc = dev_get_drvdata(dev);
98 regcache_mark_dirty(mvc->regmap);
104 static int tegra210_mvc_write_ram(struct tegra210_mvc *mvc,
108 unsigned int reg, value, wait = 0xffff;
112 regmap_read(mvc->regmap,
113 TEGRA210_MVC_AHUBRAMCTL_CONFIG_RAM_CTRL,
118 } while (value & 0x80000000);
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;
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);
135 static int tegra210_mvc_get_vol(struct snd_kcontrol *kcontrol,
136 struct snd_ctl_elem_value *ucontrol)
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;
144 pm_runtime_get_sync(codec->dev);
145 if (reg == TEGRA210_MVC_TARGET_VOL) {
148 regmap_read(mvc->regmap, reg, &val);
149 if (mvc->curve_type == CURVE_POLY)
155 ucontrol->value.integer.value[0] = val;
159 regmap_read(mvc->regmap, reg, &val);
160 ucontrol->value.integer.value[0] =
161 ((val & TEGRA210_MVC_MUTE_MASK) != 0);
163 pm_runtime_put(codec->dev);
167 static int tegra210_mvc_put_vol(struct snd_kcontrol *kcontrol,
168 struct snd_ctl_elem_value *ucontrol)
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;
179 pm_runtime_get_sync(codec->dev);
180 /* check if VOLUME_SWITCH is triggered*/
182 regmap_read(mvc->regmap,
183 TEGRA210_MVC_SWITCH, &value);
189 } while (value & TEGRA210_MVC_VOLUME_SWITCH_MASK);
191 if (reg == TEGRA210_MVC_TARGET_VOL) {
192 if (mvc->curve_type == CURVE_POLY) {
193 val = ucontrol->value.integer.value[0];
196 mvc->volume = val * (1<<24);
198 val = ucontrol->value.integer.value[0] - 120;
202 ret = regmap_write(mvc->regmap, reg, mvc->volume);
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));
209 ret |= regmap_update_bits(mvc->regmap, TEGRA210_MVC_SWITCH,
210 TEGRA210_MVC_VOLUME_SWITCH_MASK,
211 TEGRA210_MVC_VOLUME_SWITCH_TRIGGER);
214 pm_runtime_put(codec->dev);
219 static int tegra210_mvc_get_curve_type(struct snd_kcontrol *kcontrol,
220 struct snd_ctl_elem_value *ucontrol)
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;
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);
237 static int tegra210_mvc_put_curve_type(struct snd_kcontrol *kcontrol,
238 struct snd_ctl_elem_value *ucontrol)
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;
247 /* if no change in curve type, do nothing */
248 if (mvc->curve_type == ucontrol->value.integer.value[0])
251 pm_runtime_get_sync(codec->dev);
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];
260 /* issue soft reset */
261 regmap_write(mvc->regmap, TEGRA210_MVC_SOFT_RESET, 1);
262 /* wait for soft reset bit to clear */
265 ret = regmap_read(mvc->regmap, TEGRA210_MVC_SOFT_RESET, &value);
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;
277 mvc->volume = TEGRA210_MVC_INIT_VOL_DEFAULT_LINEAR;
280 pm_runtime_put(codec->dev);
285 static int tegra210_mvc_get_audio_bits(struct snd_kcontrol *kcontrol,
286 struct snd_ctl_elem_value *ucontrol)
288 struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
289 struct tegra210_mvc *mvc = snd_soc_codec_get_drvdata(codec);
291 ucontrol->value.integer.value[0] = (mvc->audio_bits + 1) * 4;
296 static int tegra210_mvc_put_audio_bits(struct snd_kcontrol *kcontrol,
297 struct snd_ctl_elem_value *ucontrol)
299 struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
300 struct tegra210_mvc *mvc = snd_soc_codec_get_drvdata(codec);
303 val = ucontrol->value.integer.value[0];
304 if ((val >= 8) && (val <= 32) && (val%4 == 0))
305 mvc->audio_bits = val/4 - 1;
312 static int tegra210_mvc_get_channels(struct snd_kcontrol *kcontrol,
313 struct snd_ctl_elem_value *ucontrol)
315 struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
316 struct tegra210_mvc *mvc = snd_soc_codec_get_drvdata(codec);
318 ucontrol->value.integer.value[0] = mvc->cif_channels;
323 static int tegra210_mvc_put_channels(struct snd_kcontrol *kcontrol,
324 struct snd_ctl_elem_value *ucontrol)
326 struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
327 struct tegra210_mvc *mvc = snd_soc_codec_get_drvdata(codec);
330 val = ucontrol->value.integer.value[0];
331 if ((val > 0) && (val <= 8))
332 mvc->cif_channels = val;
339 static int tegra210_mvc_set_audio_cif(struct tegra210_mvc *mvc,
340 struct snd_pcm_hw_params *params,
343 int channels, audio_bits;
344 struct tegra210_xbar_cif_conf cif_conf;
346 memset(&cif_conf, 0, sizeof(struct tegra210_xbar_cif_conf));
348 channels = params_channels(params);
349 if (mvc->cif_channels > 0)
350 channels = mvc->cif_channels;
355 switch (params_format(params)) {
356 case SNDRV_PCM_FORMAT_S16_LE:
357 audio_bits = TEGRA210_AUDIOCIF_BITS_16;
359 case SNDRV_PCM_FORMAT_S32_LE:
360 audio_bits = TEGRA210_AUDIOCIF_BITS_32;
366 if (mvc->audio_bits > 0)
367 audio_bits = mvc->audio_bits;
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;
374 mvc->soc_data->set_audio_cif(mvc->regmap, reg, &cif_conf);
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)
383 struct device *dev = dai->dev;
384 struct tegra210_mvc *mvc = snd_soc_dai_get_drvdata(dai);
387 /* set RX cif and TX cif */
388 ret = tegra210_mvc_set_audio_cif(mvc, params,
389 TEGRA210_MVC_AXBAR_RX_CIF_CTRL);
391 dev_err(dev, "Can't set MVC RX CIF: %d\n", ret);
394 ret = tegra210_mvc_set_audio_cif(mvc, params,
395 TEGRA210_MVC_AXBAR_TX_CIF_CTRL);
397 dev_err(dev, "Can't set MVC TX CIF: %d\n", ret);
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));
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);
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);
419 /* program the poly coefficients */
420 for (i = 0; i < 9; i++)
421 tegra210_mvc_write_ram(mvc, i, mvc->poly_coeff[i]);
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);
429 /* program duration_inv */
430 regmap_write(mvc->regmap, TEGRA210_MVC_DURATION_INV, mvc->duration_inv);
435 static int tegra210_mvc_codec_probe(struct snd_soc_codec *codec)
437 struct tegra210_mvc *mvc = snd_soc_codec_get_drvdata(codec);
439 codec->control_data = mvc->regmap;
444 static struct snd_soc_dai_ops tegra210_mvc_dai_ops = {
445 .hw_params = tegra210_mvc_hw_params,
448 static const unsigned int tegra210_mvc_curve_type_values[] = {
453 static const char * const tegra210_mvc_curve_type_text[] = {
458 static const struct soc_enum tegra210_mvc_curve_type_ctrl =
459 SOC_ENUM_SINGLE_EXT(2, tegra210_mvc_curve_type_text);
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),
474 static struct snd_soc_dai_driver tegra210_mvc_dais[] = {
478 .stream_name = "MVC Receive",
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,
491 .stream_name = "MVC Transmit",
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,
500 .ops = &tegra210_mvc_dai_ops,
504 static const struct snd_soc_dapm_widget tegra210_mvc_widgets[] = {
505 SND_SOC_DAPM_AIF_IN("MVC RX", NULL, 0, SND_SOC_NOPM,
507 SND_SOC_DAPM_AIF_OUT("MVC TX", NULL, 0, TEGRA210_MVC_ENABLE,
508 TEGRA210_MVC_EN_SHIFT, 0),
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" },
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),
528 static bool tegra210_mvc_wr_rd_reg(struct device *dev, unsigned int 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:
573 static bool tegra210_mvc_volatile_reg(struct device *dev, unsigned int reg)
576 case TEGRA210_MVC_AXBAR_RX_STATUS:
577 case TEGRA210_MVC_AXBAR_RX_INT_STATUS:
578 case TEGRA210_MVC_AXBAR_RX_INT_SET:
580 case TEGRA210_MVC_AXBAR_TX_STATUS:
581 case TEGRA210_MVC_AXBAR_TX_INT_STATUS:
582 case TEGRA210_MVC_AXBAR_TX_INT_SET:
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:
598 static const struct regmap_config tegra210_mvc_regmap_config = {
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,
611 static const struct tegra210_mvc_soc_data soc_data_tegra210 = {
612 .set_audio_cif = tegra210_xbar_set_cif,
615 static const struct of_device_id tegra210_mvc_of_match[] = {
616 { .compatible = "nvidia,tegra210-mvc", .data = &soc_data_tegra210 },
620 static int tegra210_mvc_platform_probe(struct platform_device *pdev)
622 struct tegra210_mvc *mvc;
623 struct resource *mem, *memregion;
626 const struct of_device_id *match;
627 struct tegra210_mvc_soc_data *soc_data;
629 match = of_match_device(tegra210_mvc_of_match, &pdev->dev);
631 dev_err(&pdev->dev, "Error: No device match found\n");
635 soc_data = (struct tegra210_mvc_soc_data *)match->data;
637 mvc = devm_kzalloc(&pdev->dev, sizeof(struct tegra210_mvc), GFP_KERNEL);
639 dev_err(&pdev->dev, "Can't allocate mvc\n");
644 mvc->soc_data = soc_data;
645 mvc->is_shutdown = false;
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;
663 mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
665 dev_err(&pdev->dev, "No memory resource\n");
670 memregion = devm_request_mem_region(&pdev->dev, mem->start,
671 resource_size(mem), pdev->name);
673 dev_err(&pdev->dev, "Memory region already claimed\n");
678 regs = devm_ioremap(&pdev->dev, mem->start, resource_size(mem));
680 dev_err(&pdev->dev, "ioremap failed\n");
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);
692 regcache_cache_only(mvc->regmap, true);
694 if (of_property_read_u32(pdev->dev.of_node,
695 "nvidia,ahub-mvc-id",
696 &pdev->dev.id) < 0) {
698 "Missing property nvidia,ahub-mvc-id\n");
703 pm_runtime_enable(&pdev->dev);
704 if (!pm_runtime_enabled(&pdev->dev)) {
705 ret = tegra210_mvc_runtime_resume(&pdev->dev);
710 ret = snd_soc_register_codec(&pdev->dev, &tegra210_mvc_codec,
712 ARRAY_SIZE(tegra210_mvc_dais));
714 dev_err(&pdev->dev, "Could not register CODEC: %d\n", ret);
718 dev_set_drvdata(&pdev->dev, mvc);
723 if (!pm_runtime_status_suspended(&pdev->dev))
724 tegra210_mvc_runtime_suspend(&pdev->dev);
726 pm_runtime_disable(&pdev->dev);
731 static void tegra210_mvc_platform_shutdown(struct platform_device *pdev)
733 struct tegra210_mvc *mvc = dev_get_drvdata(&pdev->dev);
735 mvc->is_shutdown = true;
738 static int tegra210_mvc_platform_remove(struct platform_device *pdev)
740 snd_soc_unregister_codec(&pdev->dev);
742 pm_runtime_disable(&pdev->dev);
743 if (!pm_runtime_status_suspended(&pdev->dev))
744 tegra210_mvc_runtime_suspend(&pdev->dev);
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)
755 static struct platform_driver tegra210_mvc_driver = {
758 .owner = THIS_MODULE,
759 .of_match_table = tegra210_mvc_of_match,
760 .pm = &tegra210_mvc_pm_ops,
762 .probe = tegra210_mvc_platform_probe,
763 .remove = tegra210_mvc_platform_remove,
764 .shutdown = tegra210_mvc_platform_shutdown,
766 module_platform_driver(tegra210_mvc_driver)
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);