1 // SPDX-License-Identifier: GPL-2.0-only
2 //
3 // tegra210_ope.c - Tegra210 OPE driver
4 //
5 // Copyright (c) 2022, NVIDIA CORPORATION. All rights reserved.
6
7 #include <linux/clk.h>
8 #include <linux/device.h>
9 #include <linux/io.h>
10 #include <linux/module.h>
11 #include <linux/of.h>
12 #include <linux/of_device.h>
13 #include <linux/platform_device.h>
14 #include <linux/pm_runtime.h>
15 #include <linux/regmap.h>
16 #include <sound/core.h>
17 #include <sound/pcm.h>
18 #include <sound/pcm_params.h>
19 #include <sound/soc.h>
20
21 #include "tegra210_mbdrc.h"
22 #include "tegra210_ope.h"
23 #include "tegra210_peq.h"
24 #include "tegra_cif.h"
25
26 static const struct reg_default tegra210_ope_reg_defaults[] = {
27 { TEGRA210_OPE_RX_INT_MASK, 0x00000001},
28 { TEGRA210_OPE_RX_CIF_CTRL, 0x00007700},
29 { TEGRA210_OPE_TX_INT_MASK, 0x00000001},
30 { TEGRA210_OPE_TX_CIF_CTRL, 0x00007700},
31 { TEGRA210_OPE_CG, 0x1},
32 };
33
tegra210_ope_set_audio_cif(struct tegra210_ope * ope,struct snd_pcm_hw_params * params,unsigned int reg)34 static int tegra210_ope_set_audio_cif(struct tegra210_ope *ope,
35 struct snd_pcm_hw_params *params,
36 unsigned int reg)
37 {
38 int channels, audio_bits;
39 struct tegra_cif_conf cif_conf;
40
41 memset(&cif_conf, 0, sizeof(struct tegra_cif_conf));
42
43 channels = params_channels(params);
44 if (channels < 2)
45 return -EINVAL;
46
47 switch (params_format(params)) {
48 case SNDRV_PCM_FORMAT_S16_LE:
49 audio_bits = TEGRA_ACIF_BITS_16;
50 break;
51 case SNDRV_PCM_FORMAT_S32_LE:
52 audio_bits = TEGRA_ACIF_BITS_32;
53 break;
54 default:
55 return -EINVAL;
56 }
57
58 cif_conf.audio_ch = channels;
59 cif_conf.client_ch = channels;
60 cif_conf.audio_bits = audio_bits;
61 cif_conf.client_bits = audio_bits;
62
63 tegra_set_cif(ope->regmap, reg, &cif_conf);
64
65 return 0;
66 }
67
tegra210_ope_hw_params(struct snd_pcm_substream * substream,struct snd_pcm_hw_params * params,struct snd_soc_dai * dai)68 static int tegra210_ope_hw_params(struct snd_pcm_substream *substream,
69 struct snd_pcm_hw_params *params,
70 struct snd_soc_dai *dai)
71 {
72 struct device *dev = dai->dev;
73 struct tegra210_ope *ope = snd_soc_dai_get_drvdata(dai);
74 int err;
75
76 /* Set RX and TX CIF */
77 err = tegra210_ope_set_audio_cif(ope, params,
78 TEGRA210_OPE_RX_CIF_CTRL);
79 if (err) {
80 dev_err(dev, "Can't set OPE RX CIF: %d\n", err);
81 return err;
82 }
83
84 err = tegra210_ope_set_audio_cif(ope, params,
85 TEGRA210_OPE_TX_CIF_CTRL);
86 if (err) {
87 dev_err(dev, "Can't set OPE TX CIF: %d\n", err);
88 return err;
89 }
90
91 tegra210_mbdrc_hw_params(dai->component);
92
93 return err;
94 }
95
tegra210_ope_component_probe(struct snd_soc_component * cmpnt)96 static int tegra210_ope_component_probe(struct snd_soc_component *cmpnt)
97 {
98 struct tegra210_ope *ope = dev_get_drvdata(cmpnt->dev);
99
100 tegra210_peq_component_init(cmpnt);
101 tegra210_mbdrc_component_init(cmpnt);
102
103 /*
104 * The OPE, PEQ and MBDRC functionalities are combined under one
105 * device registered by OPE driver. In fact OPE HW block includes
106 * sub blocks PEQ and MBDRC. However driver registers separate
107 * regmap interfaces for each of these. ASoC core depends on
108 * dev_get_regmap() to populate the regmap field for a given ASoC
109 * component. A component can have one regmap reference and since
110 * the DAPM routes depend on OPE regmap only, below explicit
111 * assignment is done to highlight this. This is needed for ASoC
112 * core to access correct regmap during DAPM path setup.
113 */
114 snd_soc_component_init_regmap(cmpnt, ope->regmap);
115
116 return 0;
117 }
118
119 static const struct snd_soc_dai_ops tegra210_ope_dai_ops = {
120 .hw_params = tegra210_ope_hw_params,
121 };
122
123 static struct snd_soc_dai_driver tegra210_ope_dais[] = {
124 {
125 .name = "OPE-RX-CIF",
126 .playback = {
127 .stream_name = "RX-CIF-Playback",
128 .channels_min = 1,
129 .channels_max = 8,
130 .rates = SNDRV_PCM_RATE_8000_192000,
131 .formats = SNDRV_PCM_FMTBIT_S8 |
132 SNDRV_PCM_FMTBIT_S16_LE |
133 SNDRV_PCM_FMTBIT_S32_LE,
134 },
135 .capture = {
136 .stream_name = "RX-CIF-Capture",
137 .channels_min = 1,
138 .channels_max = 8,
139 .rates = SNDRV_PCM_RATE_8000_192000,
140 .formats = SNDRV_PCM_FMTBIT_S8 |
141 SNDRV_PCM_FMTBIT_S16_LE |
142 SNDRV_PCM_FMTBIT_S32_LE,
143 },
144 },
145 {
146 .name = "OPE-TX-CIF",
147 .playback = {
148 .stream_name = "TX-CIF-Playback",
149 .channels_min = 1,
150 .channels_max = 8,
151 .rates = SNDRV_PCM_RATE_8000_192000,
152 .formats = SNDRV_PCM_FMTBIT_S8 |
153 SNDRV_PCM_FMTBIT_S16_LE |
154 SNDRV_PCM_FMTBIT_S32_LE,
155 },
156 .capture = {
157 .stream_name = "TX-CIF-Capture",
158 .channels_min = 1,
159 .channels_max = 8,
160 .rates = SNDRV_PCM_RATE_8000_192000,
161 .formats = SNDRV_PCM_FMTBIT_S8 |
162 SNDRV_PCM_FMTBIT_S16_LE |
163 SNDRV_PCM_FMTBIT_S32_LE,
164 },
165 .ops = &tegra210_ope_dai_ops,
166 }
167 };
168
169 static const struct snd_soc_dapm_widget tegra210_ope_widgets[] = {
170 SND_SOC_DAPM_AIF_IN("RX", NULL, 0, SND_SOC_NOPM, 0, 0),
171 SND_SOC_DAPM_AIF_OUT("TX", NULL, 0, TEGRA210_OPE_ENABLE,
172 TEGRA210_OPE_EN_SHIFT, 0),
173 };
174
175 #define OPE_ROUTES(sname) \
176 { "RX XBAR-" sname, NULL, "XBAR-TX" }, \
177 { "RX-CIF-" sname, NULL, "RX XBAR-" sname }, \
178 { "RX", NULL, "RX-CIF-" sname }, \
179 { "TX-CIF-" sname, NULL, "TX" }, \
180 { "TX XBAR-" sname, NULL, "TX-CIF-" sname }, \
181 { "XBAR-RX", NULL, "TX XBAR-" sname }
182
183 static const struct snd_soc_dapm_route tegra210_ope_routes[] = {
184 { "TX", NULL, "RX" },
185 OPE_ROUTES("Playback"),
186 OPE_ROUTES("Capture"),
187 };
188
189 static const char * const tegra210_ope_data_dir_text[] = {
190 "MBDRC to PEQ",
191 "PEQ to MBDRC"
192 };
193
194 static const struct soc_enum tegra210_ope_data_dir_enum =
195 SOC_ENUM_SINGLE(TEGRA210_OPE_DIR, TEGRA210_OPE_DIR_SHIFT,
196 2, tegra210_ope_data_dir_text);
197
tegra210_ope_get_data_dir(struct snd_kcontrol * kcontrol,struct snd_ctl_elem_value * ucontrol)198 static int tegra210_ope_get_data_dir(struct snd_kcontrol *kcontrol,
199 struct snd_ctl_elem_value *ucontrol)
200 {
201 struct snd_soc_component *cmpnt = snd_soc_kcontrol_component(kcontrol);
202 struct tegra210_ope *ope = snd_soc_component_get_drvdata(cmpnt);
203
204 ucontrol->value.enumerated.item[0] = ope->data_dir;
205
206 return 0;
207 }
208
tegra210_ope_put_data_dir(struct snd_kcontrol * kcontrol,struct snd_ctl_elem_value * ucontrol)209 static int tegra210_ope_put_data_dir(struct snd_kcontrol *kcontrol,
210 struct snd_ctl_elem_value *ucontrol)
211 {
212 struct snd_soc_component *cmpnt = snd_soc_kcontrol_component(kcontrol);
213 struct tegra210_ope *ope = snd_soc_component_get_drvdata(cmpnt);
214 unsigned int value = ucontrol->value.enumerated.item[0];
215
216 if (value == ope->data_dir)
217 return 0;
218
219 ope->data_dir = value;
220
221 return 1;
222 }
223
224 static const struct snd_kcontrol_new tegra210_ope_controls[] = {
225 SOC_ENUM_EXT("Data Flow Direction", tegra210_ope_data_dir_enum,
226 tegra210_ope_get_data_dir, tegra210_ope_put_data_dir),
227 };
228
229 static const struct snd_soc_component_driver tegra210_ope_cmpnt = {
230 .probe = tegra210_ope_component_probe,
231 .dapm_widgets = tegra210_ope_widgets,
232 .num_dapm_widgets = ARRAY_SIZE(tegra210_ope_widgets),
233 .dapm_routes = tegra210_ope_routes,
234 .num_dapm_routes = ARRAY_SIZE(tegra210_ope_routes),
235 .controls = tegra210_ope_controls,
236 .num_controls = ARRAY_SIZE(tegra210_ope_controls),
237 };
238
tegra210_ope_wr_reg(struct device * dev,unsigned int reg)239 static bool tegra210_ope_wr_reg(struct device *dev, unsigned int reg)
240 {
241 switch (reg) {
242 case TEGRA210_OPE_RX_INT_MASK ... TEGRA210_OPE_RX_CIF_CTRL:
243 case TEGRA210_OPE_TX_INT_MASK ... TEGRA210_OPE_TX_CIF_CTRL:
244 case TEGRA210_OPE_ENABLE ... TEGRA210_OPE_CG:
245 case TEGRA210_OPE_DIR:
246 return true;
247 default:
248 return false;
249 }
250 }
251
tegra210_ope_rd_reg(struct device * dev,unsigned int reg)252 static bool tegra210_ope_rd_reg(struct device *dev, unsigned int reg)
253 {
254 if (tegra210_ope_wr_reg(dev, reg))
255 return true;
256
257 switch (reg) {
258 case TEGRA210_OPE_RX_STATUS:
259 case TEGRA210_OPE_RX_INT_STATUS:
260 case TEGRA210_OPE_TX_STATUS:
261 case TEGRA210_OPE_TX_INT_STATUS:
262 case TEGRA210_OPE_STATUS:
263 case TEGRA210_OPE_INT_STATUS:
264 return true;
265 default:
266 return false;
267 }
268 }
269
tegra210_ope_volatile_reg(struct device * dev,unsigned int reg)270 static bool tegra210_ope_volatile_reg(struct device *dev, unsigned int reg)
271 {
272 switch (reg) {
273 case TEGRA210_OPE_RX_STATUS:
274 case TEGRA210_OPE_RX_INT_STATUS:
275 case TEGRA210_OPE_TX_STATUS:
276 case TEGRA210_OPE_TX_INT_STATUS:
277 case TEGRA210_OPE_SOFT_RESET:
278 case TEGRA210_OPE_STATUS:
279 case TEGRA210_OPE_INT_STATUS:
280 return true;
281 default:
282 return false;
283 }
284 }
285
286 static const struct regmap_config tegra210_ope_regmap_config = {
287 .reg_bits = 32,
288 .reg_stride = 4,
289 .val_bits = 32,
290 .max_register = TEGRA210_OPE_DIR,
291 .writeable_reg = tegra210_ope_wr_reg,
292 .readable_reg = tegra210_ope_rd_reg,
293 .volatile_reg = tegra210_ope_volatile_reg,
294 .reg_defaults = tegra210_ope_reg_defaults,
295 .num_reg_defaults = ARRAY_SIZE(tegra210_ope_reg_defaults),
296 .cache_type = REGCACHE_FLAT,
297 };
298
tegra210_ope_probe(struct platform_device * pdev)299 static int tegra210_ope_probe(struct platform_device *pdev)
300 {
301 struct device *dev = &pdev->dev;
302 struct tegra210_ope *ope;
303 void __iomem *regs;
304 int err;
305
306 ope = devm_kzalloc(dev, sizeof(*ope), GFP_KERNEL);
307 if (!ope)
308 return -ENOMEM;
309
310 regs = devm_platform_ioremap_resource(pdev, 0);
311 if (IS_ERR(regs))
312 return PTR_ERR(regs);
313
314 ope->regmap = devm_regmap_init_mmio(dev, regs,
315 &tegra210_ope_regmap_config);
316 if (IS_ERR(ope->regmap)) {
317 dev_err(dev, "regmap init failed\n");
318 return PTR_ERR(ope->regmap);
319 }
320
321 regcache_cache_only(ope->regmap, true);
322
323 dev_set_drvdata(dev, ope);
324
325 err = tegra210_peq_regmap_init(pdev);
326 if (err < 0) {
327 dev_err(dev, "PEQ init failed\n");
328 return err;
329 }
330
331 err = tegra210_mbdrc_regmap_init(pdev);
332 if (err < 0) {
333 dev_err(dev, "MBDRC init failed\n");
334 return err;
335 }
336
337 err = devm_snd_soc_register_component(dev, &tegra210_ope_cmpnt,
338 tegra210_ope_dais,
339 ARRAY_SIZE(tegra210_ope_dais));
340 if (err) {
341 dev_err(dev, "can't register OPE component, err: %d\n", err);
342 return err;
343 }
344
345 pm_runtime_enable(dev);
346
347 return 0;
348 }
349
tegra210_ope_remove(struct platform_device * pdev)350 static void tegra210_ope_remove(struct platform_device *pdev)
351 {
352 pm_runtime_disable(&pdev->dev);
353 }
354
tegra210_ope_runtime_suspend(struct device * dev)355 static int __maybe_unused tegra210_ope_runtime_suspend(struct device *dev)
356 {
357 struct tegra210_ope *ope = dev_get_drvdata(dev);
358
359 tegra210_peq_save(ope->peq_regmap, ope->peq_biquad_gains,
360 ope->peq_biquad_shifts);
361
362 regcache_cache_only(ope->mbdrc_regmap, true);
363 regcache_cache_only(ope->peq_regmap, true);
364 regcache_cache_only(ope->regmap, true);
365
366 regcache_mark_dirty(ope->regmap);
367 regcache_mark_dirty(ope->peq_regmap);
368 regcache_mark_dirty(ope->mbdrc_regmap);
369
370 return 0;
371 }
372
tegra210_ope_runtime_resume(struct device * dev)373 static int __maybe_unused tegra210_ope_runtime_resume(struct device *dev)
374 {
375 struct tegra210_ope *ope = dev_get_drvdata(dev);
376
377 regcache_cache_only(ope->regmap, false);
378 regcache_cache_only(ope->peq_regmap, false);
379 regcache_cache_only(ope->mbdrc_regmap, false);
380
381 regcache_sync(ope->regmap);
382 regcache_sync(ope->peq_regmap);
383 regcache_sync(ope->mbdrc_regmap);
384
385 tegra210_peq_restore(ope->peq_regmap, ope->peq_biquad_gains,
386 ope->peq_biquad_shifts);
387
388 return 0;
389 }
390
391 static const struct dev_pm_ops tegra210_ope_pm_ops = {
392 SET_RUNTIME_PM_OPS(tegra210_ope_runtime_suspend,
393 tegra210_ope_runtime_resume, NULL)
394 SET_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend,
395 pm_runtime_force_resume)
396 };
397
398 static const struct of_device_id tegra210_ope_of_match[] = {
399 { .compatible = "nvidia,tegra210-ope" },
400 {},
401 };
402 MODULE_DEVICE_TABLE(of, tegra210_ope_of_match);
403
404 static struct platform_driver tegra210_ope_driver = {
405 .driver = {
406 .name = "tegra210-ope",
407 .of_match_table = tegra210_ope_of_match,
408 .pm = &tegra210_ope_pm_ops,
409 },
410 .probe = tegra210_ope_probe,
411 .remove_new = tegra210_ope_remove,
412 };
413 module_platform_driver(tegra210_ope_driver)
414
415 MODULE_AUTHOR("Sumit Bhattacharya <sumitb@nvidia.com>");
416 MODULE_DESCRIPTION("Tegra210 OPE ASoC driver");
417 MODULE_LICENSE("GPL");
418