1 // SPDX-License-Identifier: GPL-2.0-only
2 // SPDX-FileCopyrightText: Copyright (c) 2021-2024 NVIDIA CORPORATION & AFFILIATES.
3 // All rights reserved.
5 // tegra210_mixer.c - Tegra210 MIXER 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_mixer.h"
21 #include "tegra_cif.h"
23 #define MIXER_REG(reg, id) ((reg) + ((id) * TEGRA210_MIXER_REG_STRIDE))
24 #define MIXER_REG_BASE(reg) ((reg) % TEGRA210_MIXER_REG_STRIDE)
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))
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}
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}
39 #define REG_DURATION_PARAM(reg, i) ((reg) + NUM_GAIN_POLY_COEFFS + 1 + (i))
41 static const struct reg_default tegra210_mixer_reg_defaults
[] = {
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),
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),
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 },
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 },
72 /* Duration Parameters */
73 { 0, 0, 0x400, 0x8000000 },
76 static int __maybe_unused
tegra210_mixer_runtime_suspend(struct device
*dev
)
78 struct tegra210_mixer
*mixer
= dev_get_drvdata(dev
);
80 regcache_cache_only(mixer
->regmap
, true);
81 regcache_mark_dirty(mixer
->regmap
);
86 static int __maybe_unused
tegra210_mixer_runtime_resume(struct device
*dev
)
88 struct tegra210_mixer
*mixer
= dev_get_drvdata(dev
);
90 regcache_cache_only(mixer
->regmap
, false);
91 regcache_sync(mixer
->regmap
);
96 static int tegra210_mixer_write_ram(struct tegra210_mixer
*mixer
,
100 unsigned int reg
, val
;
104 err
= regmap_read_poll_timeout(mixer
->regmap
,
105 TEGRA210_MIXER_GAIN_CFG_RAM_CTRL
,
106 val
, !(val
& 0x80000000), 10, 10000);
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
;
116 regmap_write(mixer
->regmap
,
117 TEGRA210_MIXER_GAIN_CFG_RAM_CTRL
,
119 regmap_write(mixer
->regmap
,
120 TEGRA210_MIXER_GAIN_CFG_RAM_DATA
,
126 static int tegra210_mixer_configure_gain(struct snd_soc_component
*cmpnt
,
127 unsigned int id
, bool instant_gain
)
129 struct tegra210_mixer
*mixer
= snd_soc_component_get_drvdata(cmpnt
);
130 unsigned int reg
= MIXER_GAIN_CFG_RAM_ADDR(id
);
133 pm_runtime_get_sync(cmpnt
->dev
);
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
]);
144 /* Write stored gain value */
145 err
= tegra210_mixer_write_ram(mixer
, reg
+ NUM_GAIN_POLY_COEFFS
,
146 mixer
->gain_value
[id
]);
150 /* Write duration parameters */
151 for (i
= 0; i
< NUM_DURATION_PARMS
; i
++) {
157 val
= gain_params
.duration
[i
];
159 err
= tegra210_mixer_write_ram(mixer
,
160 REG_DURATION_PARAM(reg
, i
),
166 /* Trigger to apply gain configurations */
167 err
= tegra210_mixer_write_ram(mixer
, reg
+ REG_CFG_DONE_TRIGGER
,
168 VAL_CFG_DONE_TRIGGER
);
171 pm_runtime_put(cmpnt
->dev
);
176 static int tegra210_mixer_get_gain(struct snd_kcontrol
*kcontrol
,
177 struct snd_ctl_elem_value
*ucontrol
)
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
;
186 i
= (reg
- TEGRA210_MIXER_GAIN_CFG_RAM_ADDR_0
) /
187 TEGRA210_MIXER_GAIN_CFG_RAM_ADDR_STRIDE
;
189 ucontrol
->value
.integer
.value
[0] = mixer
->gain_value
[i
];
194 static int tegra210_mixer_apply_gain(struct snd_kcontrol
*kcontrol
,
195 struct snd_ctl_elem_value
*ucontrol
,
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
;
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
;
209 if (mixer
->gain_value
[id
] == ucontrol
->value
.integer
.value
[0])
212 mixer
->gain_value
[id
] = ucontrol
->value
.integer
.value
[0];
214 err
= tegra210_mixer_configure_gain(cmpnt
, id
, instant_gain
);
216 dev_err(cmpnt
->dev
, "Failed to apply gain\n");
223 static int tegra210_mixer_put_gain(struct snd_kcontrol
*kcontrol
,
224 struct snd_ctl_elem_value
*ucontrol
)
226 return tegra210_mixer_apply_gain(kcontrol
, ucontrol
, false);
229 static int tegra210_mixer_put_instant_gain(struct snd_kcontrol
*kcontrol
,
230 struct snd_ctl_elem_value
*ucontrol
)
232 return tegra210_mixer_apply_gain(kcontrol
, ucontrol
, true);
235 static int tegra210_mixer_set_audio_cif(struct tegra210_mixer
*mixer
,
236 struct snd_pcm_hw_params
*params
,
240 unsigned int channels
, audio_bits
;
241 struct tegra_cif_conf cif_conf
;
243 memset(&cif_conf
, 0, sizeof(struct tegra_cif_conf
));
245 channels
= params_channels(params
);
247 switch (params_format(params
)) {
248 case SNDRV_PCM_FORMAT_S16_LE
:
249 audio_bits
= TEGRA_ACIF_BITS_16
;
251 case SNDRV_PCM_FORMAT_S24_LE
:
252 case SNDRV_PCM_FORMAT_S32_LE
:
253 audio_bits
= TEGRA_ACIF_BITS_32
;
259 cif_conf
.audio_ch
= channels
;
260 cif_conf
.client_ch
= channels
;
261 cif_conf
.audio_bits
= audio_bits
;
262 cif_conf
.client_bits
= audio_bits
;
264 tegra_set_cif(mixer
->regmap
,
265 reg
+ (id
* TEGRA210_MIXER_REG_STRIDE
),
271 static int tegra210_mixer_in_hw_params(struct snd_pcm_substream
*substream
,
272 struct snd_pcm_hw_params
*params
,
273 struct snd_soc_dai
*dai
)
275 struct tegra210_mixer
*mixer
= snd_soc_dai_get_drvdata(dai
);
278 err
= tegra210_mixer_set_audio_cif(mixer
, params
,
279 TEGRA210_MIXER_RX1_CIF_CTRL
,
284 return tegra210_mixer_configure_gain(dai
->component
, dai
->id
, false);
287 static int tegra210_mixer_out_hw_params(struct snd_pcm_substream
*substream
,
288 struct snd_pcm_hw_params
*params
,
289 struct snd_soc_dai
*dai
)
291 struct tegra210_mixer
*mixer
= snd_soc_dai_get_drvdata(dai
);
293 return tegra210_mixer_set_audio_cif(mixer
, params
,
294 TEGRA210_MIXER_TX1_CIF_CTRL
,
295 dai
->id
- TEGRA210_MIXER_RX_MAX
);
298 static const struct snd_soc_dai_ops tegra210_mixer_out_dai_ops
= {
299 .hw_params
= tegra210_mixer_out_hw_params
,
302 static const struct snd_soc_dai_ops tegra210_mixer_in_dai_ops
= {
303 .hw_params
= tegra210_mixer_in_hw_params
,
308 .name = "MIXER-RX-CIF"#id, \
310 .stream_name = "RX" #id "-CIF-Playback",\
313 .rates = SNDRV_PCM_RATE_8000_192000, \
314 .formats = SNDRV_PCM_FMTBIT_S8 | \
315 SNDRV_PCM_FMTBIT_S16_LE | \
316 SNDRV_PCM_FMTBIT_S24_LE | \
317 SNDRV_PCM_FMTBIT_S32_LE, \
320 .stream_name = "RX" #id "-CIF-Capture", \
323 .rates = SNDRV_PCM_RATE_8000_192000, \
324 .formats = SNDRV_PCM_FMTBIT_S8 | \
325 SNDRV_PCM_FMTBIT_S16_LE | \
326 SNDRV_PCM_FMTBIT_S24_LE | \
327 SNDRV_PCM_FMTBIT_S32_LE, \
329 .ops = &tegra210_mixer_in_dai_ops, \
332 #define OUT_DAI(id) \
334 .name = "MIXER-TX-CIF" #id, \
336 .stream_name = "TX" #id "-CIF-Playback",\
339 .rates = SNDRV_PCM_RATE_8000_192000, \
340 .formats = SNDRV_PCM_FMTBIT_S8 | \
341 SNDRV_PCM_FMTBIT_S16_LE | \
342 SNDRV_PCM_FMTBIT_S24_LE | \
343 SNDRV_PCM_FMTBIT_S32_LE, \
346 .stream_name = "TX" #id "-CIF-Capture", \
349 .rates = SNDRV_PCM_RATE_8000_192000, \
350 .formats = SNDRV_PCM_FMTBIT_S8 | \
351 SNDRV_PCM_FMTBIT_S16_LE | \
352 SNDRV_PCM_FMTBIT_S24_LE | \
353 SNDRV_PCM_FMTBIT_S32_LE, \
355 .ops = &tegra210_mixer_out_dai_ops, \
358 static struct snd_soc_dai_driver tegra210_mixer_dais
[] = {
379 #define ADDER_CTRL_DECL(name, reg) \
380 static const struct snd_kcontrol_new name[] = { \
381 SOC_DAPM_SINGLE("RX1", reg, 0, 1, 0), \
382 SOC_DAPM_SINGLE("RX2", reg, 1, 1, 0), \
383 SOC_DAPM_SINGLE("RX3", reg, 2, 1, 0), \
384 SOC_DAPM_SINGLE("RX4", reg, 3, 1, 0), \
385 SOC_DAPM_SINGLE("RX5", reg, 4, 1, 0), \
386 SOC_DAPM_SINGLE("RX6", reg, 5, 1, 0), \
387 SOC_DAPM_SINGLE("RX7", reg, 6, 1, 0), \
388 SOC_DAPM_SINGLE("RX8", reg, 7, 1, 0), \
389 SOC_DAPM_SINGLE("RX9", reg, 8, 1, 0), \
390 SOC_DAPM_SINGLE("RX10", reg, 9, 1, 0), \
393 ADDER_CTRL_DECL(adder1
, TEGRA210_MIXER_TX1_ADDER_CONFIG
);
394 ADDER_CTRL_DECL(adder2
, TEGRA210_MIXER_TX2_ADDER_CONFIG
);
395 ADDER_CTRL_DECL(adder3
, TEGRA210_MIXER_TX3_ADDER_CONFIG
);
396 ADDER_CTRL_DECL(adder4
, TEGRA210_MIXER_TX4_ADDER_CONFIG
);
397 ADDER_CTRL_DECL(adder5
, TEGRA210_MIXER_TX5_ADDER_CONFIG
);
399 #define GAIN_CTRL(id) \
400 SOC_SINGLE_EXT("RX" #id " Gain Volume", \
401 MIXER_GAIN_CFG_RAM_ADDR((id) - 1), 0, \
402 0x20000, 0, tegra210_mixer_get_gain, \
403 tegra210_mixer_put_gain), \
404 SOC_SINGLE_EXT("RX" #id " Instant Gain Volume", \
405 MIXER_GAIN_CFG_RAM_ADDR((id) - 1), 0, \
406 0x20000, 0, tegra210_mixer_get_gain, \
407 tegra210_mixer_put_instant_gain),
409 /* Volume controls for all MIXER inputs */
410 static const struct snd_kcontrol_new tegra210_mixer_gain_ctls
[] = {
423 static const struct snd_soc_dapm_widget tegra210_mixer_widgets
[] = {
424 SND_SOC_DAPM_AIF_IN("RX1", NULL
, 0, SND_SOC_NOPM
, 0, 0),
425 SND_SOC_DAPM_AIF_IN("RX2", NULL
, 0, SND_SOC_NOPM
, 0, 0),
426 SND_SOC_DAPM_AIF_IN("RX3", NULL
, 0, SND_SOC_NOPM
, 0, 0),
427 SND_SOC_DAPM_AIF_IN("RX4", NULL
, 0, SND_SOC_NOPM
, 0, 0),
428 SND_SOC_DAPM_AIF_IN("RX5", NULL
, 0, SND_SOC_NOPM
, 0, 0),
429 SND_SOC_DAPM_AIF_IN("RX6", NULL
, 0, SND_SOC_NOPM
, 0, 0),
430 SND_SOC_DAPM_AIF_IN("RX7", NULL
, 0, SND_SOC_NOPM
, 0, 0),
431 SND_SOC_DAPM_AIF_IN("RX8", NULL
, 0, SND_SOC_NOPM
, 0, 0),
432 SND_SOC_DAPM_AIF_IN("RX9", NULL
, 0, SND_SOC_NOPM
, 0, 0),
433 SND_SOC_DAPM_AIF_IN("RX10", NULL
, 0, SND_SOC_NOPM
, 0, 0),
434 SND_SOC_DAPM_AIF_OUT("TX1", NULL
, 0, TEGRA210_MIXER_TX1_ENABLE
, 0, 0),
435 SND_SOC_DAPM_AIF_OUT("TX2", NULL
, 0, TEGRA210_MIXER_TX2_ENABLE
, 0, 0),
436 SND_SOC_DAPM_AIF_OUT("TX3", NULL
, 0, TEGRA210_MIXER_TX3_ENABLE
, 0, 0),
437 SND_SOC_DAPM_AIF_OUT("TX4", NULL
, 0, TEGRA210_MIXER_TX4_ENABLE
, 0, 0),
438 SND_SOC_DAPM_AIF_OUT("TX5", NULL
, 0, TEGRA210_MIXER_TX5_ENABLE
, 0, 0),
439 SND_SOC_DAPM_MIXER("Adder1", SND_SOC_NOPM
, 1, 0, adder1
,
441 SND_SOC_DAPM_MIXER("Adder2", SND_SOC_NOPM
, 1, 0, adder2
,
443 SND_SOC_DAPM_MIXER("Adder3", SND_SOC_NOPM
, 1, 0, adder3
,
445 SND_SOC_DAPM_MIXER("Adder4", SND_SOC_NOPM
, 1, 0, adder4
,
447 SND_SOC_DAPM_MIXER("Adder5", SND_SOC_NOPM
, 1, 0, adder5
,
451 #define RX_ROUTES(id, sname) \
452 { "RX" #id " XBAR-" sname, NULL, "RX" #id " XBAR-TX" }, \
453 { "RX" #id "-CIF-" sname, NULL, "RX" #id " XBAR-" sname }, \
454 { "RX" #id, NULL, "RX" #id "-CIF-" sname }
456 #define MIXER_RX_ROUTES(id) \
457 RX_ROUTES(id, "Playback"), \
458 RX_ROUTES(id, "Capture")
460 #define ADDER_ROUTES(id, sname) \
461 { "Adder" #id, "RX1", "RX1" }, \
462 { "Adder" #id, "RX2", "RX2" }, \
463 { "Adder" #id, "RX3", "RX3" }, \
464 { "Adder" #id, "RX4", "RX4" }, \
465 { "Adder" #id, "RX5", "RX5" }, \
466 { "Adder" #id, "RX6", "RX6" }, \
467 { "Adder" #id, "RX7", "RX7" }, \
468 { "Adder" #id, "RX8", "RX8" }, \
469 { "Adder" #id, "RX9", "RX9" }, \
470 { "Adder" #id, "RX10", "RX10" }, \
471 { "TX" #id, NULL, "Adder" #id }, \
472 { "TX" #id "-CIF-" sname, NULL, "TX" #id }, \
473 { "TX" #id " XBAR-" sname, NULL, "TX" #id "-CIF-" sname }, \
474 { "TX" #id " XBAR-RX", NULL, "TX" #id " XBAR-" sname } \
476 #define TX_ROUTES(id, sname) \
477 ADDER_ROUTES(1, sname), \
478 ADDER_ROUTES(2, sname), \
479 ADDER_ROUTES(3, sname), \
480 ADDER_ROUTES(4, sname), \
481 ADDER_ROUTES(5, sname)
483 #define MIXER_TX_ROUTES(id) \
484 TX_ROUTES(id, "Playback"), \
485 TX_ROUTES(id, "Capture")
487 static const struct snd_soc_dapm_route tegra210_mixer_routes
[] = {
507 static const struct snd_soc_component_driver tegra210_mixer_cmpnt
= {
508 .dapm_widgets
= tegra210_mixer_widgets
,
509 .num_dapm_widgets
= ARRAY_SIZE(tegra210_mixer_widgets
),
510 .dapm_routes
= tegra210_mixer_routes
,
511 .num_dapm_routes
= ARRAY_SIZE(tegra210_mixer_routes
),
512 .controls
= tegra210_mixer_gain_ctls
,
513 .num_controls
= ARRAY_SIZE(tegra210_mixer_gain_ctls
),
516 static bool tegra210_mixer_wr_reg(struct device
*dev
,
519 if (reg
< TEGRA210_MIXER_RX_LIMIT
)
520 reg
= MIXER_REG_BASE(reg
);
521 else if (reg
< TEGRA210_MIXER_TX_LIMIT
)
522 reg
= MIXER_REG_BASE(reg
) + TEGRA210_MIXER_TX1_ENABLE
;
525 case TEGRA210_MIXER_RX1_SOFT_RESET
:
526 case TEGRA210_MIXER_RX1_CIF_CTRL
... TEGRA210_MIXER_RX1_PEAK_CTRL
:
528 case TEGRA210_MIXER_TX1_ENABLE
:
529 case TEGRA210_MIXER_TX1_SOFT_RESET
:
530 case TEGRA210_MIXER_TX1_INT_MASK
... TEGRA210_MIXER_TX1_ADDER_CONFIG
:
532 case TEGRA210_MIXER_ENABLE
... TEGRA210_MIXER_CG
:
533 case TEGRA210_MIXER_GAIN_CFG_RAM_CTRL
... TEGRA210_MIXER_CTRL
:
540 static bool tegra210_mixer_rd_reg(struct device
*dev
,
543 if (reg
< TEGRA210_MIXER_RX_LIMIT
)
544 reg
= MIXER_REG_BASE(reg
);
545 else if (reg
< TEGRA210_MIXER_TX_LIMIT
)
546 reg
= MIXER_REG_BASE(reg
) + TEGRA210_MIXER_TX1_ENABLE
;
549 case TEGRA210_MIXER_RX1_SOFT_RESET
... TEGRA210_MIXER_RX1_SAMPLE_COUNT
:
550 case TEGRA210_MIXER_TX1_ENABLE
... TEGRA210_MIXER_TX1_ADDER_CONFIG
:
551 case TEGRA210_MIXER_ENABLE
... TEGRA210_MIXER_CTRL
:
558 static bool tegra210_mixer_volatile_reg(struct device
*dev
,
561 if (reg
< TEGRA210_MIXER_RX_LIMIT
)
562 reg
= MIXER_REG_BASE(reg
);
563 else if (reg
< TEGRA210_MIXER_TX_LIMIT
)
564 reg
= MIXER_REG_BASE(reg
) + TEGRA210_MIXER_TX1_ENABLE
;
567 case TEGRA210_MIXER_RX1_SOFT_RESET
:
568 case TEGRA210_MIXER_RX1_STATUS
:
570 case TEGRA210_MIXER_TX1_SOFT_RESET
:
571 case TEGRA210_MIXER_TX1_STATUS
:
572 case TEGRA210_MIXER_TX1_INT_STATUS
:
573 case TEGRA210_MIXER_TX1_INT_SET
:
575 case TEGRA210_MIXER_SOFT_RESET
:
576 case TEGRA210_MIXER_STATUS
:
577 case TEGRA210_MIXER_INT_STATUS
:
578 case TEGRA210_MIXER_GAIN_CFG_RAM_CTRL
:
579 case TEGRA210_MIXER_GAIN_CFG_RAM_DATA
:
580 case TEGRA210_MIXER_PEAKM_RAM_CTRL
:
581 case TEGRA210_MIXER_PEAKM_RAM_DATA
:
588 static bool tegra210_mixer_precious_reg(struct device
*dev
,
592 case TEGRA210_MIXER_GAIN_CFG_RAM_DATA
:
593 case TEGRA210_MIXER_PEAKM_RAM_DATA
:
600 static const struct regmap_config tegra210_mixer_regmap_config
= {
604 .max_register
= TEGRA210_MIXER_CTRL
,
605 .writeable_reg
= tegra210_mixer_wr_reg
,
606 .readable_reg
= tegra210_mixer_rd_reg
,
607 .volatile_reg
= tegra210_mixer_volatile_reg
,
608 .precious_reg
= tegra210_mixer_precious_reg
,
609 .reg_defaults
= tegra210_mixer_reg_defaults
,
610 .num_reg_defaults
= ARRAY_SIZE(tegra210_mixer_reg_defaults
),
611 .cache_type
= REGCACHE_FLAT
,
614 static const struct of_device_id tegra210_mixer_of_match
[] = {
615 { .compatible
= "nvidia,tegra210-amixer" },
618 MODULE_DEVICE_TABLE(of
, tegra210_mixer_of_match
);
620 static int tegra210_mixer_platform_probe(struct platform_device
*pdev
)
622 struct device
*dev
= &pdev
->dev
;
623 struct tegra210_mixer
*mixer
;
627 mixer
= devm_kzalloc(dev
, sizeof(*mixer
), GFP_KERNEL
);
631 dev_set_drvdata(dev
, mixer
);
633 /* Use default gain value for all MIXER inputs */
634 for (i
= 0; i
< TEGRA210_MIXER_RX_MAX
; i
++)
635 mixer
->gain_value
[i
] = gain_params
.gain_value
;
637 regs
= devm_platform_ioremap_resource(pdev
, 0);
639 return PTR_ERR(regs
);
641 mixer
->regmap
= devm_regmap_init_mmio(dev
, regs
,
642 &tegra210_mixer_regmap_config
);
643 if (IS_ERR(mixer
->regmap
)) {
644 dev_err(dev
, "regmap init failed\n");
645 return PTR_ERR(mixer
->regmap
);
648 regcache_cache_only(mixer
->regmap
, true);
650 err
= devm_snd_soc_register_component(dev
, &tegra210_mixer_cmpnt
,
652 ARRAY_SIZE(tegra210_mixer_dais
));
654 dev_err(dev
, "can't register MIXER component, err: %d\n", err
);
658 pm_runtime_enable(dev
);
663 static void tegra210_mixer_platform_remove(struct platform_device
*pdev
)
665 pm_runtime_disable(&pdev
->dev
);
668 static const struct dev_pm_ops tegra210_mixer_pm_ops
= {
669 SET_RUNTIME_PM_OPS(tegra210_mixer_runtime_suspend
,
670 tegra210_mixer_runtime_resume
, NULL
)
671 SET_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend
,
672 pm_runtime_force_resume
)
675 static struct platform_driver tegra210_mixer_driver
= {
677 .name
= "tegra210_mixer",
678 .of_match_table
= tegra210_mixer_of_match
,
679 .pm
= &tegra210_mixer_pm_ops
,
681 .probe
= tegra210_mixer_platform_probe
,
682 .remove
= tegra210_mixer_platform_remove
,
684 module_platform_driver(tegra210_mixer_driver
);
686 MODULE_AUTHOR("Arun Shamanna Lakshmi <aruns@nvidia.com>");
687 MODULE_DESCRIPTION("Tegra210 MIXER ASoC driver");
688 MODULE_LICENSE("GPL v2");