1 // SPDX-License-Identifier: GPL-2.0-only
2 // SPDX-FileCopyrightText: Copyright (c) 2021-2024 NVIDIA CORPORATION & AFFILIATES.
3 // All rights reserved.
5 // tegra210_mvc.c - Tegra210 MVC driver
8 #include <linux/device.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>
20 #include "tegra210_mvc.h"
21 #include "tegra_cif.h"
23 static const struct reg_default tegra210_mvc_reg_defaults
[] = {
24 { TEGRA210_MVC_RX_INT_MASK
, 0x00000001},
25 { TEGRA210_MVC_RX_CIF_CTRL
, 0x00007700},
26 { TEGRA210_MVC_TX_INT_MASK
, 0x00000001},
27 { TEGRA210_MVC_TX_CIF_CTRL
, 0x00007700},
28 { TEGRA210_MVC_CG
, 0x1},
29 { TEGRA210_MVC_CTRL
, TEGRA210_MVC_CTRL_DEFAULT
},
30 { TEGRA210_MVC_INIT_VOL
, 0x00800000},
31 { TEGRA210_MVC_TARGET_VOL
, 0x00800000},
32 { TEGRA210_MVC_DURATION
, 0x000012c0},
33 { TEGRA210_MVC_DURATION_INV
, 0x0006d3a0},
34 { TEGRA210_MVC_POLY_N1
, 0x0000007d},
35 { TEGRA210_MVC_POLY_N2
, 0x00000271},
36 { TEGRA210_MVC_PEAK_CTRL
, 0x000012c0},
37 { TEGRA210_MVC_CFG_RAM_CTRL
, 0x00004000},
40 static const struct tegra210_mvc_gain_params gain_params
= {
41 .poly_coeff
= { 23738319, 659403, -3680,
42 15546680, 2530732, -120985,
43 12048422, 5527252, -785042 },
47 .duration_inv
= 14316558,
50 static int __maybe_unused
tegra210_mvc_runtime_suspend(struct device
*dev
)
52 struct tegra210_mvc
*mvc
= dev_get_drvdata(dev
);
54 regmap_read(mvc
->regmap
, TEGRA210_MVC_CTRL
, &(mvc
->ctrl_value
));
56 regcache_cache_only(mvc
->regmap
, true);
57 regcache_mark_dirty(mvc
->regmap
);
62 static int __maybe_unused
tegra210_mvc_runtime_resume(struct device
*dev
)
64 struct tegra210_mvc
*mvc
= dev_get_drvdata(dev
);
66 regcache_cache_only(mvc
->regmap
, false);
67 regcache_sync(mvc
->regmap
);
69 regmap_write(mvc
->regmap
, TEGRA210_MVC_CTRL
, mvc
->ctrl_value
);
70 regmap_update_bits(mvc
->regmap
,
72 TEGRA210_MVC_VOLUME_SWITCH_MASK
,
73 TEGRA210_MVC_VOLUME_SWITCH_TRIGGER
);
78 static void tegra210_mvc_write_ram(struct regmap
*regmap
)
82 regmap_write(regmap
, TEGRA210_MVC_CFG_RAM_CTRL
,
83 TEGRA210_MVC_CFG_RAM_CTRL_SEQ_ACCESS_EN
|
84 TEGRA210_MVC_CFG_RAM_CTRL_ADDR_INIT_EN
|
85 TEGRA210_MVC_CFG_RAM_CTRL_RW_WRITE
);
87 for (i
= 0; i
< NUM_GAIN_POLY_COEFFS
; i
++)
88 regmap_write(regmap
, TEGRA210_MVC_CFG_RAM_DATA
,
89 gain_params
.poly_coeff
[i
]);
92 static void tegra210_mvc_conv_vol(struct tegra210_mvc
*mvc
, u8 chan
, s32 val
)
95 * Volume control read from mixer control is with
96 * 100x scaling; for CURVE_POLY the reg range
97 * is 0-100 (linear, Q24) and for CURVE_LINEAR
98 * it is -120dB to +40dB (Q8)
100 if (mvc
->curve_type
== CURVE_POLY
) {
103 mvc
->volume
[chan
] = ((val
* (1<<8)) / 100) << 16;
106 mvc
->volume
[chan
] = (val
* (1<<8)) / 100;
110 static u32
tegra210_mvc_get_ctrl_reg(struct snd_kcontrol
*kcontrol
)
112 struct snd_soc_component
*cmpnt
= snd_soc_kcontrol_component(kcontrol
);
113 struct tegra210_mvc
*mvc
= snd_soc_component_get_drvdata(cmpnt
);
116 pm_runtime_get_sync(cmpnt
->dev
);
117 regmap_read(mvc
->regmap
, TEGRA210_MVC_CTRL
, &val
);
118 pm_runtime_put(cmpnt
->dev
);
123 static int tegra210_mvc_get_mute(struct snd_kcontrol
*kcontrol
,
124 struct snd_ctl_elem_value
*ucontrol
)
126 u32 val
= tegra210_mvc_get_ctrl_reg(kcontrol
);
127 u8 mute_mask
= TEGRA210_GET_MUTE_VAL(val
);
130 * If per channel control is enabled, then return
131 * exact mute/unmute setting of all channels.
133 * Else report setting based on CH0 bit to reflect
134 * the correct HW state.
136 if (val
& TEGRA210_MVC_PER_CHAN_CTRL_EN
) {
137 ucontrol
->value
.integer
.value
[0] = mute_mask
;
139 if (mute_mask
& TEGRA210_MVC_CH0_MUTE_EN
)
140 ucontrol
->value
.integer
.value
[0] =
141 TEGRA210_MUTE_MASK_EN
;
143 ucontrol
->value
.integer
.value
[0] = 0;
149 static int tegra210_mvc_get_master_mute(struct snd_kcontrol
*kcontrol
,
150 struct snd_ctl_elem_value
*ucontrol
)
152 u32 val
= tegra210_mvc_get_ctrl_reg(kcontrol
);
153 u8 mute_mask
= TEGRA210_GET_MUTE_VAL(val
);
156 * If per channel control is disabled, then return
157 * master mute/unmute setting based on CH0 bit.
159 * Else report settings based on state of all
162 if (!(val
& TEGRA210_MVC_PER_CHAN_CTRL_EN
)) {
163 ucontrol
->value
.integer
.value
[0] =
164 mute_mask
& TEGRA210_MVC_CH0_MUTE_EN
;
166 if (mute_mask
== TEGRA210_MUTE_MASK_EN
)
167 ucontrol
->value
.integer
.value
[0] =
168 TEGRA210_MVC_CH0_MUTE_EN
;
170 ucontrol
->value
.integer
.value
[0] = 0;
176 static int tegra210_mvc_volume_switch_timeout(struct snd_soc_component
*cmpnt
)
178 struct tegra210_mvc
*mvc
= snd_soc_component_get_drvdata(cmpnt
);
182 err
= regmap_read_poll_timeout(mvc
->regmap
, TEGRA210_MVC_SWITCH
,
183 value
, !(value
& TEGRA210_MVC_VOLUME_SWITCH_MASK
),
187 "Volume switch trigger is still active, err = %d\n",
193 static int tegra210_mvc_update_mute(struct snd_kcontrol
*kcontrol
,
194 struct snd_ctl_elem_value
*ucontrol
,
197 struct snd_soc_component
*cmpnt
= snd_soc_kcontrol_component(kcontrol
);
198 struct tegra210_mvc
*mvc
= snd_soc_component_get_drvdata(cmpnt
);
199 u32 mute_val
= ucontrol
->value
.integer
.value
[0];
204 pm_runtime_get_sync(cmpnt
->dev
);
206 err
= tegra210_mvc_volume_switch_timeout(cmpnt
);
211 per_ch_ctrl_val
= TEGRA210_MVC_PER_CHAN_CTRL_EN
;
216 mute_val
= TEGRA210_MUTE_MASK_EN
;
219 regmap_update_bits_check(mvc
->regmap
, TEGRA210_MVC_CTRL
,
220 TEGRA210_MVC_MUTE_MASK
,
221 mute_val
<< TEGRA210_MVC_MUTE_SHIFT
,
225 regmap_update_bits(mvc
->regmap
, TEGRA210_MVC_CTRL
,
226 TEGRA210_MVC_PER_CHAN_CTRL_EN_MASK
,
229 regmap_update_bits(mvc
->regmap
, TEGRA210_MVC_SWITCH
,
230 TEGRA210_MVC_VOLUME_SWITCH_MASK
,
231 TEGRA210_MVC_VOLUME_SWITCH_TRIGGER
);
235 pm_runtime_put(cmpnt
->dev
);
246 static int tegra210_mvc_put_mute(struct snd_kcontrol
*kcontrol
,
247 struct snd_ctl_elem_value
*ucontrol
)
249 return tegra210_mvc_update_mute(kcontrol
, ucontrol
, true);
252 static int tegra210_mvc_put_master_mute(struct snd_kcontrol
*kcontrol
,
253 struct snd_ctl_elem_value
*ucontrol
)
255 return tegra210_mvc_update_mute(kcontrol
, ucontrol
, false);
258 static int tegra210_mvc_get_vol(struct snd_kcontrol
*kcontrol
,
259 struct snd_ctl_elem_value
*ucontrol
)
261 struct soc_mixer_control
*mc
=
262 (struct soc_mixer_control
*)kcontrol
->private_value
;
263 struct snd_soc_component
*cmpnt
= snd_soc_kcontrol_component(kcontrol
);
264 struct tegra210_mvc
*mvc
= snd_soc_component_get_drvdata(cmpnt
);
265 u8 chan
= TEGRA210_MVC_GET_CHAN(mc
->reg
, TEGRA210_MVC_TARGET_VOL
);
266 s32 val
= mvc
->volume
[chan
];
268 if (mvc
->curve_type
== CURVE_POLY
) {
269 val
= ((val
>> 16) * 100) >> 8;
271 val
= (val
* 100) >> 8;
275 ucontrol
->value
.integer
.value
[0] = val
;
280 static int tegra210_mvc_get_master_vol(struct snd_kcontrol
*kcontrol
,
281 struct snd_ctl_elem_value
*ucontrol
)
283 return tegra210_mvc_get_vol(kcontrol
, ucontrol
);
286 static int tegra210_mvc_update_vol(struct snd_kcontrol
*kcontrol
,
287 struct snd_ctl_elem_value
*ucontrol
,
290 struct soc_mixer_control
*mc
=
291 (struct soc_mixer_control
*)kcontrol
->private_value
;
292 struct snd_soc_component
*cmpnt
= snd_soc_kcontrol_component(kcontrol
);
293 struct tegra210_mvc
*mvc
= snd_soc_component_get_drvdata(cmpnt
);
294 u8 chan
= TEGRA210_MVC_GET_CHAN(mc
->reg
, TEGRA210_MVC_TARGET_VOL
);
295 int old_volume
= mvc
->volume
[chan
];
298 pm_runtime_get_sync(cmpnt
->dev
);
300 err
= tegra210_mvc_volume_switch_timeout(cmpnt
);
304 tegra210_mvc_conv_vol(mvc
, chan
, ucontrol
->value
.integer
.value
[0]);
306 if (mvc
->volume
[chan
] == old_volume
) {
312 regmap_update_bits(mvc
->regmap
, TEGRA210_MVC_CTRL
,
313 TEGRA210_MVC_PER_CHAN_CTRL_EN_MASK
,
314 TEGRA210_MVC_PER_CHAN_CTRL_EN
);
316 regmap_update_bits(mvc
->regmap
, TEGRA210_MVC_CTRL
,
317 TEGRA210_MVC_PER_CHAN_CTRL_EN_MASK
, 0);
319 for (i
= 1; i
< TEGRA210_MVC_MAX_CHAN_COUNT
; i
++)
320 mvc
->volume
[i
] = mvc
->volume
[chan
];
323 /* Configure init volume same as target volume */
324 regmap_write(mvc
->regmap
,
325 TEGRA210_MVC_REG_OFFSET(TEGRA210_MVC_INIT_VOL
, chan
),
328 regmap_write(mvc
->regmap
, mc
->reg
, mvc
->volume
[chan
]);
330 regmap_update_bits(mvc
->regmap
, TEGRA210_MVC_SWITCH
,
331 TEGRA210_MVC_VOLUME_SWITCH_MASK
,
332 TEGRA210_MVC_VOLUME_SWITCH_TRIGGER
);
337 pm_runtime_put(cmpnt
->dev
);
342 static int tegra210_mvc_put_vol(struct snd_kcontrol
*kcontrol
,
343 struct snd_ctl_elem_value
*ucontrol
)
345 return tegra210_mvc_update_vol(kcontrol
, ucontrol
, true);
348 static int tegra210_mvc_put_master_vol(struct snd_kcontrol
*kcontrol
,
349 struct snd_ctl_elem_value
*ucontrol
)
351 return tegra210_mvc_update_vol(kcontrol
, ucontrol
, false);
354 static void tegra210_mvc_reset_vol_settings(struct tegra210_mvc
*mvc
,
359 /* Change volume to default init for new curve type */
360 if (mvc
->curve_type
== CURVE_POLY
) {
361 for (i
= 0; i
< TEGRA210_MVC_MAX_CHAN_COUNT
; i
++)
362 mvc
->volume
[i
] = TEGRA210_MVC_INIT_VOL_DEFAULT_POLY
;
364 for (i
= 0; i
< TEGRA210_MVC_MAX_CHAN_COUNT
; i
++)
365 mvc
->volume
[i
] = TEGRA210_MVC_INIT_VOL_DEFAULT_LINEAR
;
368 pm_runtime_get_sync(dev
);
370 /* Program curve type */
371 regmap_update_bits(mvc
->regmap
, TEGRA210_MVC_CTRL
,
372 TEGRA210_MVC_CURVE_TYPE_MASK
,
374 TEGRA210_MVC_CURVE_TYPE_SHIFT
);
376 /* Init volume for all channels */
377 for (i
= 0; i
< TEGRA210_MVC_MAX_CHAN_COUNT
; i
++) {
378 regmap_write(mvc
->regmap
,
379 TEGRA210_MVC_REG_OFFSET(TEGRA210_MVC_INIT_VOL
, i
),
381 regmap_write(mvc
->regmap
,
382 TEGRA210_MVC_REG_OFFSET(TEGRA210_MVC_TARGET_VOL
, i
),
386 /* Trigger volume switch */
387 regmap_update_bits(mvc
->regmap
, TEGRA210_MVC_SWITCH
,
388 TEGRA210_MVC_VOLUME_SWITCH_MASK
,
389 TEGRA210_MVC_VOLUME_SWITCH_TRIGGER
);
394 static int tegra210_mvc_get_curve_type(struct snd_kcontrol
*kcontrol
,
395 struct snd_ctl_elem_value
*ucontrol
)
397 struct snd_soc_component
*cmpnt
= snd_soc_kcontrol_component(kcontrol
);
398 struct tegra210_mvc
*mvc
= snd_soc_component_get_drvdata(cmpnt
);
400 ucontrol
->value
.enumerated
.item
[0] = mvc
->curve_type
;
405 static int tegra210_mvc_put_curve_type(struct snd_kcontrol
*kcontrol
,
406 struct snd_ctl_elem_value
*ucontrol
)
408 struct snd_soc_component
*cmpnt
= snd_soc_kcontrol_component(kcontrol
);
409 struct tegra210_mvc
*mvc
= snd_soc_component_get_drvdata(cmpnt
);
412 regmap_read(mvc
->regmap
, TEGRA210_MVC_ENABLE
, &value
);
413 if (value
& TEGRA210_MVC_EN
) {
415 "Curve type can't be set when MVC is running\n");
419 if (mvc
->curve_type
== ucontrol
->value
.enumerated
.item
[0])
422 mvc
->curve_type
= ucontrol
->value
.enumerated
.item
[0];
424 tegra210_mvc_reset_vol_settings(mvc
, cmpnt
->dev
);
429 static int tegra210_mvc_set_audio_cif(struct tegra210_mvc
*mvc
,
430 struct snd_pcm_hw_params
*params
,
433 unsigned int channels
, audio_bits
;
434 struct tegra_cif_conf cif_conf
;
436 memset(&cif_conf
, 0, sizeof(struct tegra_cif_conf
));
438 channels
= params_channels(params
);
440 switch (params_format(params
)) {
441 case SNDRV_PCM_FORMAT_S16_LE
:
442 audio_bits
= TEGRA_ACIF_BITS_16
;
444 case SNDRV_PCM_FORMAT_S24_LE
:
445 case SNDRV_PCM_FORMAT_S32_LE
:
446 audio_bits
= TEGRA_ACIF_BITS_32
;
452 cif_conf
.audio_ch
= channels
;
453 cif_conf
.client_ch
= channels
;
454 cif_conf
.audio_bits
= audio_bits
;
455 cif_conf
.client_bits
= audio_bits
;
457 tegra_set_cif(mvc
->regmap
, reg
, &cif_conf
);
462 static int tegra210_mvc_hw_params(struct snd_pcm_substream
*substream
,
463 struct snd_pcm_hw_params
*params
,
464 struct snd_soc_dai
*dai
)
466 struct device
*dev
= dai
->dev
;
467 struct tegra210_mvc
*mvc
= snd_soc_dai_get_drvdata(dai
);
471 * Soft Reset: Below performs module soft reset which clears
472 * all FSM logic, flushes flow control of FIFO and resets the
473 * state register. It also brings module back to disabled
474 * state (without flushing the data in the pipe).
476 regmap_write(mvc
->regmap
, TEGRA210_MVC_SOFT_RESET
, 1);
478 err
= regmap_read_poll_timeout(mvc
->regmap
, TEGRA210_MVC_SOFT_RESET
,
479 val
, !val
, 10, 10000);
481 dev_err(dev
, "SW reset failed, err = %d\n", err
);
486 err
= tegra210_mvc_set_audio_cif(mvc
, params
, TEGRA210_MVC_RX_CIF_CTRL
);
488 dev_err(dev
, "Can't set MVC RX CIF: %d\n", err
);
493 err
= tegra210_mvc_set_audio_cif(mvc
, params
, TEGRA210_MVC_TX_CIF_CTRL
);
495 dev_err(dev
, "Can't set MVC TX CIF: %d\n", err
);
499 tegra210_mvc_write_ram(mvc
->regmap
);
501 /* Program poly_n1, poly_n2, duration */
502 regmap_write(mvc
->regmap
, TEGRA210_MVC_POLY_N1
, gain_params
.poly_n1
);
503 regmap_write(mvc
->regmap
, TEGRA210_MVC_POLY_N2
, gain_params
.poly_n2
);
504 regmap_write(mvc
->regmap
, TEGRA210_MVC_DURATION
, gain_params
.duration
);
506 /* Program duration_inv */
507 regmap_write(mvc
->regmap
, TEGRA210_MVC_DURATION_INV
,
508 gain_params
.duration_inv
);
513 static const struct snd_soc_dai_ops tegra210_mvc_dai_ops
= {
514 .hw_params
= tegra210_mvc_hw_params
,
517 static const char * const tegra210_mvc_curve_type_text
[] = {
522 static const struct soc_enum tegra210_mvc_curve_type_ctrl
=
523 SOC_ENUM_SINGLE_EXT(2, tegra210_mvc_curve_type_text
);
525 #define TEGRA210_MVC_VOL_CTRL(chan) \
526 SOC_SINGLE_EXT("Channel" #chan " Volume", \
527 TEGRA210_MVC_REG_OFFSET(TEGRA210_MVC_TARGET_VOL, \
529 0, 16000, 0, tegra210_mvc_get_vol, \
530 tegra210_mvc_put_vol)
532 static const struct snd_kcontrol_new tegra210_mvc_vol_ctrl
[] = {
533 /* Per channel volume control */
534 TEGRA210_MVC_VOL_CTRL(1),
535 TEGRA210_MVC_VOL_CTRL(2),
536 TEGRA210_MVC_VOL_CTRL(3),
537 TEGRA210_MVC_VOL_CTRL(4),
538 TEGRA210_MVC_VOL_CTRL(5),
539 TEGRA210_MVC_VOL_CTRL(6),
540 TEGRA210_MVC_VOL_CTRL(7),
541 TEGRA210_MVC_VOL_CTRL(8),
543 /* Per channel mute */
544 SOC_SINGLE_EXT("Per Chan Mute Mask",
545 TEGRA210_MVC_CTRL
, 0, TEGRA210_MUTE_MASK_EN
, 0,
546 tegra210_mvc_get_mute
, tegra210_mvc_put_mute
),
549 SOC_SINGLE_EXT("Volume", TEGRA210_MVC_TARGET_VOL
, 0, 16000, 0,
550 tegra210_mvc_get_master_vol
,
551 tegra210_mvc_put_master_vol
),
554 SOC_SINGLE_EXT("Mute", TEGRA210_MVC_CTRL
, 0, 1, 0,
555 tegra210_mvc_get_master_mute
,
556 tegra210_mvc_put_master_mute
),
558 SOC_ENUM_EXT("Curve Type", tegra210_mvc_curve_type_ctrl
,
559 tegra210_mvc_get_curve_type
, tegra210_mvc_put_curve_type
),
562 static struct snd_soc_dai_driver tegra210_mvc_dais
[] = {
565 .name
= "MVC-RX-CIF",
567 .stream_name
= "RX-CIF-Playback",
570 .rates
= SNDRV_PCM_RATE_8000_192000
,
571 .formats
= SNDRV_PCM_FMTBIT_S8
|
572 SNDRV_PCM_FMTBIT_S16_LE
|
573 SNDRV_PCM_FMTBIT_S24_LE
|
574 SNDRV_PCM_FMTBIT_S32_LE
,
577 .stream_name
= "RX-CIF-Capture",
580 .rates
= SNDRV_PCM_RATE_8000_192000
,
581 .formats
= SNDRV_PCM_FMTBIT_S8
|
582 SNDRV_PCM_FMTBIT_S16_LE
|
583 SNDRV_PCM_FMTBIT_S24_LE
|
584 SNDRV_PCM_FMTBIT_S32_LE
,
590 .name
= "MVC-TX-CIF",
592 .stream_name
= "TX-CIF-Playback",
595 .rates
= SNDRV_PCM_RATE_8000_192000
,
596 .formats
= SNDRV_PCM_FMTBIT_S8
|
597 SNDRV_PCM_FMTBIT_S16_LE
|
598 SNDRV_PCM_FMTBIT_S24_LE
|
599 SNDRV_PCM_FMTBIT_S32_LE
,
602 .stream_name
= "TX-CIF-Capture",
605 .rates
= SNDRV_PCM_RATE_8000_192000
,
606 .formats
= SNDRV_PCM_FMTBIT_S8
|
607 SNDRV_PCM_FMTBIT_S16_LE
|
608 SNDRV_PCM_FMTBIT_S24_LE
|
609 SNDRV_PCM_FMTBIT_S32_LE
,
611 .ops
= &tegra210_mvc_dai_ops
,
615 static const struct snd_soc_dapm_widget tegra210_mvc_widgets
[] = {
616 SND_SOC_DAPM_AIF_IN("RX", NULL
, 0, SND_SOC_NOPM
, 0, 0),
617 SND_SOC_DAPM_AIF_OUT("TX", NULL
, 0, TEGRA210_MVC_ENABLE
,
618 TEGRA210_MVC_EN_SHIFT
, 0),
621 #define MVC_ROUTES(sname) \
622 { "RX XBAR-" sname, NULL, "XBAR-TX" }, \
623 { "RX-CIF-" sname, NULL, "RX XBAR-" sname }, \
624 { "RX", NULL, "RX-CIF-" sname }, \
625 { "TX-CIF-" sname, NULL, "TX" }, \
626 { "TX XBAR-" sname, NULL, "TX-CIF-" sname }, \
627 { "XBAR-RX", NULL, "TX XBAR-" sname }
629 static const struct snd_soc_dapm_route tegra210_mvc_routes
[] = {
630 { "TX", NULL
, "RX" },
631 MVC_ROUTES("Playback"),
632 MVC_ROUTES("Capture"),
635 static const struct snd_soc_component_driver tegra210_mvc_cmpnt
= {
636 .dapm_widgets
= tegra210_mvc_widgets
,
637 .num_dapm_widgets
= ARRAY_SIZE(tegra210_mvc_widgets
),
638 .dapm_routes
= tegra210_mvc_routes
,
639 .num_dapm_routes
= ARRAY_SIZE(tegra210_mvc_routes
),
640 .controls
= tegra210_mvc_vol_ctrl
,
641 .num_controls
= ARRAY_SIZE(tegra210_mvc_vol_ctrl
),
644 static bool tegra210_mvc_rd_reg(struct device
*dev
, unsigned int reg
)
647 case TEGRA210_MVC_RX_STATUS
... TEGRA210_MVC_CONFIG_ERR_TYPE
:
654 static bool tegra210_mvc_wr_reg(struct device
*dev
, unsigned int reg
)
657 case TEGRA210_MVC_RX_INT_MASK
... TEGRA210_MVC_RX_CIF_CTRL
:
658 case TEGRA210_MVC_TX_INT_MASK
... TEGRA210_MVC_TX_CIF_CTRL
:
659 case TEGRA210_MVC_ENABLE
... TEGRA210_MVC_CG
:
660 case TEGRA210_MVC_CTRL
... TEGRA210_MVC_CFG_RAM_DATA
:
667 static bool tegra210_mvc_volatile_reg(struct device
*dev
, unsigned int reg
)
670 case TEGRA210_MVC_RX_STATUS
:
671 case TEGRA210_MVC_RX_INT_STATUS
:
672 case TEGRA210_MVC_RX_INT_SET
:
674 case TEGRA210_MVC_TX_STATUS
:
675 case TEGRA210_MVC_TX_INT_STATUS
:
676 case TEGRA210_MVC_TX_INT_SET
:
678 case TEGRA210_MVC_SOFT_RESET
:
679 case TEGRA210_MVC_STATUS
:
680 case TEGRA210_MVC_INT_STATUS
:
681 case TEGRA210_MVC_SWITCH
:
682 case TEGRA210_MVC_CFG_RAM_CTRL
:
683 case TEGRA210_MVC_CFG_RAM_DATA
:
684 case TEGRA210_MVC_PEAK_VALUE
:
685 case TEGRA210_MVC_CTRL
:
692 static const struct regmap_config tegra210_mvc_regmap_config
= {
696 .max_register
= TEGRA210_MVC_CONFIG_ERR_TYPE
,
697 .writeable_reg
= tegra210_mvc_wr_reg
,
698 .readable_reg
= tegra210_mvc_rd_reg
,
699 .volatile_reg
= tegra210_mvc_volatile_reg
,
700 .reg_defaults
= tegra210_mvc_reg_defaults
,
701 .num_reg_defaults
= ARRAY_SIZE(tegra210_mvc_reg_defaults
),
702 .cache_type
= REGCACHE_FLAT
,
705 static const struct of_device_id tegra210_mvc_of_match
[] = {
706 { .compatible
= "nvidia,tegra210-mvc" },
709 MODULE_DEVICE_TABLE(of
, tegra210_mvc_of_match
);
711 static int tegra210_mvc_platform_probe(struct platform_device
*pdev
)
713 struct device
*dev
= &pdev
->dev
;
714 struct tegra210_mvc
*mvc
;
718 mvc
= devm_kzalloc(dev
, sizeof(*mvc
), GFP_KERNEL
);
722 dev_set_drvdata(dev
, mvc
);
724 mvc
->curve_type
= CURVE_LINEAR
;
725 mvc
->ctrl_value
= TEGRA210_MVC_CTRL_DEFAULT
;
727 regs
= devm_platform_ioremap_resource(pdev
, 0);
729 return PTR_ERR(regs
);
731 mvc
->regmap
= devm_regmap_init_mmio(dev
, regs
,
732 &tegra210_mvc_regmap_config
);
733 if (IS_ERR(mvc
->regmap
)) {
734 dev_err(dev
, "regmap init failed\n");
735 return PTR_ERR(mvc
->regmap
);
738 regcache_cache_only(mvc
->regmap
, true);
740 err
= devm_snd_soc_register_component(dev
, &tegra210_mvc_cmpnt
,
742 ARRAY_SIZE(tegra210_mvc_dais
));
744 dev_err(dev
, "can't register MVC component, err: %d\n", err
);
748 pm_runtime_enable(dev
);
750 tegra210_mvc_reset_vol_settings(mvc
, &pdev
->dev
);
755 static void tegra210_mvc_platform_remove(struct platform_device
*pdev
)
757 pm_runtime_disable(&pdev
->dev
);
760 static const struct dev_pm_ops tegra210_mvc_pm_ops
= {
761 SET_RUNTIME_PM_OPS(tegra210_mvc_runtime_suspend
,
762 tegra210_mvc_runtime_resume
, NULL
)
763 SET_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend
,
764 pm_runtime_force_resume
)
767 static struct platform_driver tegra210_mvc_driver
= {
769 .name
= "tegra210-mvc",
770 .of_match_table
= tegra210_mvc_of_match
,
771 .pm
= &tegra210_mvc_pm_ops
,
773 .probe
= tegra210_mvc_platform_probe
,
774 .remove
= tegra210_mvc_platform_remove
,
776 module_platform_driver(tegra210_mvc_driver
)
778 MODULE_AUTHOR("Arun Shamanna Lakshmi <aruns@nvidia.com>");
779 MODULE_DESCRIPTION("Tegra210 MVC ASoC driver");
780 MODULE_LICENSE("GPL v2");