1 // SPDX-License-Identifier: GPL-2.0-only
3 * Copyright (c) 2010-2011,2013-2015 The Linux Foundation. All rights reserved.
5 * lpass-cpu.c -- ALSA SoC CPU DAI driver for QTi LPASS
9 #include <linux/kernel.h>
10 #include <linux/module.h>
12 #include <linux/of_device.h>
13 #include <linux/platform_device.h>
14 #include <sound/pcm.h>
15 #include <sound/pcm_params.h>
16 #include <linux/regmap.h>
17 #include <sound/soc.h>
18 #include <sound/soc-dai.h>
19 #include "lpass-lpaif-reg.h"
22 static int lpass_cpu_daiops_set_sysclk(struct snd_soc_dai
*dai
, int clk_id
,
23 unsigned int freq
, int dir
)
25 struct lpass_data
*drvdata
= snd_soc_dai_get_drvdata(dai
);
28 ret
= clk_set_rate(drvdata
->mi2s_osr_clk
[dai
->driver
->id
], freq
);
30 dev_err(dai
->dev
, "error setting mi2s osrclk to %u: %d\n",
36 static int lpass_cpu_daiops_startup(struct snd_pcm_substream
*substream
,
37 struct snd_soc_dai
*dai
)
39 struct lpass_data
*drvdata
= snd_soc_dai_get_drvdata(dai
);
42 ret
= clk_prepare_enable(drvdata
->mi2s_osr_clk
[dai
->driver
->id
]);
44 dev_err(dai
->dev
, "error in enabling mi2s osr clk: %d\n", ret
);
48 ret
= clk_prepare_enable(drvdata
->mi2s_bit_clk
[dai
->driver
->id
]);
50 dev_err(dai
->dev
, "error in enabling mi2s bit clk: %d\n", ret
);
51 clk_disable_unprepare(drvdata
->mi2s_osr_clk
[dai
->driver
->id
]);
58 static void lpass_cpu_daiops_shutdown(struct snd_pcm_substream
*substream
,
59 struct snd_soc_dai
*dai
)
61 struct lpass_data
*drvdata
= snd_soc_dai_get_drvdata(dai
);
63 clk_disable_unprepare(drvdata
->mi2s_bit_clk
[dai
->driver
->id
]);
65 clk_disable_unprepare(drvdata
->mi2s_osr_clk
[dai
->driver
->id
]);
68 static int lpass_cpu_daiops_hw_params(struct snd_pcm_substream
*substream
,
69 struct snd_pcm_hw_params
*params
, struct snd_soc_dai
*dai
)
71 struct lpass_data
*drvdata
= snd_soc_dai_get_drvdata(dai
);
72 snd_pcm_format_t format
= params_format(params
);
73 unsigned int channels
= params_channels(params
);
74 unsigned int rate
= params_rate(params
);
78 bitwidth
= snd_pcm_format_width(format
);
80 dev_err(dai
->dev
, "invalid bit width given: %d\n", bitwidth
);
84 regval
= LPAIF_I2SCTL_LOOPBACK_DISABLE
|
85 LPAIF_I2SCTL_WSSRC_INTERNAL
;
89 regval
|= LPAIF_I2SCTL_BITWIDTH_16
;
92 regval
|= LPAIF_I2SCTL_BITWIDTH_24
;
95 regval
|= LPAIF_I2SCTL_BITWIDTH_32
;
98 dev_err(dai
->dev
, "invalid bitwidth given: %d\n", bitwidth
);
102 if (substream
->stream
== SNDRV_PCM_STREAM_PLAYBACK
) {
105 regval
|= LPAIF_I2SCTL_SPKMODE_SD0
;
106 regval
|= LPAIF_I2SCTL_SPKMONO_MONO
;
109 regval
|= LPAIF_I2SCTL_SPKMODE_SD0
;
110 regval
|= LPAIF_I2SCTL_SPKMONO_STEREO
;
113 regval
|= LPAIF_I2SCTL_SPKMODE_QUAD01
;
114 regval
|= LPAIF_I2SCTL_SPKMONO_STEREO
;
117 regval
|= LPAIF_I2SCTL_SPKMODE_6CH
;
118 regval
|= LPAIF_I2SCTL_SPKMONO_STEREO
;
121 regval
|= LPAIF_I2SCTL_SPKMODE_8CH
;
122 regval
|= LPAIF_I2SCTL_SPKMONO_STEREO
;
125 dev_err(dai
->dev
, "invalid channels given: %u\n",
132 regval
|= LPAIF_I2SCTL_MICMODE_SD0
;
133 regval
|= LPAIF_I2SCTL_MICMONO_MONO
;
136 regval
|= LPAIF_I2SCTL_MICMODE_SD0
;
137 regval
|= LPAIF_I2SCTL_MICMONO_STEREO
;
140 regval
|= LPAIF_I2SCTL_MICMODE_QUAD01
;
141 regval
|= LPAIF_I2SCTL_MICMONO_STEREO
;
144 regval
|= LPAIF_I2SCTL_MICMODE_6CH
;
145 regval
|= LPAIF_I2SCTL_MICMONO_STEREO
;
148 regval
|= LPAIF_I2SCTL_MICMODE_8CH
;
149 regval
|= LPAIF_I2SCTL_MICMONO_STEREO
;
152 dev_err(dai
->dev
, "invalid channels given: %u\n",
158 ret
= regmap_write(drvdata
->lpaif_map
,
159 LPAIF_I2SCTL_REG(drvdata
->variant
, dai
->driver
->id
),
162 dev_err(dai
->dev
, "error writing to i2sctl reg: %d\n", ret
);
166 ret
= clk_set_rate(drvdata
->mi2s_bit_clk
[dai
->driver
->id
],
167 rate
* bitwidth
* 2);
169 dev_err(dai
->dev
, "error setting mi2s bitclk to %u: %d\n",
170 rate
* bitwidth
* 2, ret
);
177 static int lpass_cpu_daiops_hw_free(struct snd_pcm_substream
*substream
,
178 struct snd_soc_dai
*dai
)
180 struct lpass_data
*drvdata
= snd_soc_dai_get_drvdata(dai
);
183 ret
= regmap_write(drvdata
->lpaif_map
,
184 LPAIF_I2SCTL_REG(drvdata
->variant
, dai
->driver
->id
),
187 dev_err(dai
->dev
, "error writing to i2sctl reg: %d\n", ret
);
192 static int lpass_cpu_daiops_prepare(struct snd_pcm_substream
*substream
,
193 struct snd_soc_dai
*dai
)
195 struct lpass_data
*drvdata
= snd_soc_dai_get_drvdata(dai
);
197 unsigned int val
, mask
;
199 if (substream
->stream
== SNDRV_PCM_STREAM_PLAYBACK
) {
200 val
= LPAIF_I2SCTL_SPKEN_ENABLE
;
201 mask
= LPAIF_I2SCTL_SPKEN_MASK
;
203 val
= LPAIF_I2SCTL_MICEN_ENABLE
;
204 mask
= LPAIF_I2SCTL_MICEN_MASK
;
207 ret
= regmap_update_bits(drvdata
->lpaif_map
,
208 LPAIF_I2SCTL_REG(drvdata
->variant
, dai
->driver
->id
),
211 dev_err(dai
->dev
, "error writing to i2sctl reg: %d\n", ret
);
216 static int lpass_cpu_daiops_trigger(struct snd_pcm_substream
*substream
,
217 int cmd
, struct snd_soc_dai
*dai
)
219 struct lpass_data
*drvdata
= snd_soc_dai_get_drvdata(dai
);
221 unsigned int val
, mask
;
224 case SNDRV_PCM_TRIGGER_START
:
225 case SNDRV_PCM_TRIGGER_RESUME
:
226 case SNDRV_PCM_TRIGGER_PAUSE_RELEASE
:
227 if (substream
->stream
== SNDRV_PCM_STREAM_PLAYBACK
) {
228 val
= LPAIF_I2SCTL_SPKEN_ENABLE
;
229 mask
= LPAIF_I2SCTL_SPKEN_MASK
;
231 val
= LPAIF_I2SCTL_MICEN_ENABLE
;
232 mask
= LPAIF_I2SCTL_MICEN_MASK
;
235 ret
= regmap_update_bits(drvdata
->lpaif_map
,
236 LPAIF_I2SCTL_REG(drvdata
->variant
,
240 dev_err(dai
->dev
, "error writing to i2sctl reg: %d\n",
243 case SNDRV_PCM_TRIGGER_STOP
:
244 case SNDRV_PCM_TRIGGER_SUSPEND
:
245 case SNDRV_PCM_TRIGGER_PAUSE_PUSH
:
246 if (substream
->stream
== SNDRV_PCM_STREAM_PLAYBACK
) {
247 val
= LPAIF_I2SCTL_SPKEN_DISABLE
;
248 mask
= LPAIF_I2SCTL_SPKEN_MASK
;
250 val
= LPAIF_I2SCTL_MICEN_DISABLE
;
251 mask
= LPAIF_I2SCTL_MICEN_MASK
;
254 ret
= regmap_update_bits(drvdata
->lpaif_map
,
255 LPAIF_I2SCTL_REG(drvdata
->variant
,
259 dev_err(dai
->dev
, "error writing to i2sctl reg: %d\n",
267 const struct snd_soc_dai_ops asoc_qcom_lpass_cpu_dai_ops
= {
268 .set_sysclk
= lpass_cpu_daiops_set_sysclk
,
269 .startup
= lpass_cpu_daiops_startup
,
270 .shutdown
= lpass_cpu_daiops_shutdown
,
271 .hw_params
= lpass_cpu_daiops_hw_params
,
272 .hw_free
= lpass_cpu_daiops_hw_free
,
273 .prepare
= lpass_cpu_daiops_prepare
,
274 .trigger
= lpass_cpu_daiops_trigger
,
276 EXPORT_SYMBOL_GPL(asoc_qcom_lpass_cpu_dai_ops
);
278 int asoc_qcom_lpass_cpu_dai_probe(struct snd_soc_dai
*dai
)
280 struct lpass_data
*drvdata
= snd_soc_dai_get_drvdata(dai
);
283 /* ensure audio hardware is disabled */
284 ret
= regmap_write(drvdata
->lpaif_map
,
285 LPAIF_I2SCTL_REG(drvdata
->variant
, dai
->driver
->id
), 0);
287 dev_err(dai
->dev
, "error writing to i2sctl reg: %d\n", ret
);
291 EXPORT_SYMBOL_GPL(asoc_qcom_lpass_cpu_dai_probe
);
293 static const struct snd_soc_component_driver lpass_cpu_comp_driver
= {
297 static bool lpass_cpu_regmap_writeable(struct device
*dev
, unsigned int reg
)
299 struct lpass_data
*drvdata
= dev_get_drvdata(dev
);
300 struct lpass_variant
*v
= drvdata
->variant
;
303 for (i
= 0; i
< v
->i2s_ports
; ++i
)
304 if (reg
== LPAIF_I2SCTL_REG(v
, i
))
307 for (i
= 0; i
< v
->irq_ports
; ++i
) {
308 if (reg
== LPAIF_IRQEN_REG(v
, i
))
310 if (reg
== LPAIF_IRQCLEAR_REG(v
, i
))
314 for (i
= 0; i
< v
->rdma_channels
; ++i
) {
315 if (reg
== LPAIF_RDMACTL_REG(v
, i
))
317 if (reg
== LPAIF_RDMABASE_REG(v
, i
))
319 if (reg
== LPAIF_RDMABUFF_REG(v
, i
))
321 if (reg
== LPAIF_RDMAPER_REG(v
, i
))
325 for (i
= 0; i
< v
->wrdma_channels
; ++i
) {
326 if (reg
== LPAIF_WRDMACTL_REG(v
, i
+ v
->wrdma_channel_start
))
328 if (reg
== LPAIF_WRDMABASE_REG(v
, i
+ v
->wrdma_channel_start
))
330 if (reg
== LPAIF_WRDMABUFF_REG(v
, i
+ v
->wrdma_channel_start
))
332 if (reg
== LPAIF_WRDMAPER_REG(v
, i
+ v
->wrdma_channel_start
))
339 static bool lpass_cpu_regmap_readable(struct device
*dev
, unsigned int reg
)
341 struct lpass_data
*drvdata
= dev_get_drvdata(dev
);
342 struct lpass_variant
*v
= drvdata
->variant
;
345 for (i
= 0; i
< v
->i2s_ports
; ++i
)
346 if (reg
== LPAIF_I2SCTL_REG(v
, i
))
349 for (i
= 0; i
< v
->irq_ports
; ++i
) {
350 if (reg
== LPAIF_IRQEN_REG(v
, i
))
352 if (reg
== LPAIF_IRQSTAT_REG(v
, i
))
356 for (i
= 0; i
< v
->rdma_channels
; ++i
) {
357 if (reg
== LPAIF_RDMACTL_REG(v
, i
))
359 if (reg
== LPAIF_RDMABASE_REG(v
, i
))
361 if (reg
== LPAIF_RDMABUFF_REG(v
, i
))
363 if (reg
== LPAIF_RDMACURR_REG(v
, i
))
365 if (reg
== LPAIF_RDMAPER_REG(v
, i
))
369 for (i
= 0; i
< v
->wrdma_channels
; ++i
) {
370 if (reg
== LPAIF_WRDMACTL_REG(v
, i
+ v
->wrdma_channel_start
))
372 if (reg
== LPAIF_WRDMABASE_REG(v
, i
+ v
->wrdma_channel_start
))
374 if (reg
== LPAIF_WRDMABUFF_REG(v
, i
+ v
->wrdma_channel_start
))
376 if (reg
== LPAIF_WRDMACURR_REG(v
, i
+ v
->wrdma_channel_start
))
378 if (reg
== LPAIF_WRDMAPER_REG(v
, i
+ v
->wrdma_channel_start
))
385 static bool lpass_cpu_regmap_volatile(struct device
*dev
, unsigned int reg
)
387 struct lpass_data
*drvdata
= dev_get_drvdata(dev
);
388 struct lpass_variant
*v
= drvdata
->variant
;
391 for (i
= 0; i
< v
->irq_ports
; ++i
)
392 if (reg
== LPAIF_IRQSTAT_REG(v
, i
))
395 for (i
= 0; i
< v
->rdma_channels
; ++i
)
396 if (reg
== LPAIF_RDMACURR_REG(v
, i
))
399 for (i
= 0; i
< v
->wrdma_channels
; ++i
)
400 if (reg
== LPAIF_WRDMACURR_REG(v
, i
+ v
->wrdma_channel_start
))
406 static struct regmap_config lpass_cpu_regmap_config
= {
410 .writeable_reg
= lpass_cpu_regmap_writeable
,
411 .readable_reg
= lpass_cpu_regmap_readable
,
412 .volatile_reg
= lpass_cpu_regmap_volatile
,
413 .cache_type
= REGCACHE_FLAT
,
416 int asoc_qcom_lpass_cpu_platform_probe(struct platform_device
*pdev
)
418 struct lpass_data
*drvdata
;
419 struct device_node
*dsp_of_node
;
420 struct resource
*res
;
421 struct lpass_variant
*variant
;
422 struct device
*dev
= &pdev
->dev
;
423 const struct of_device_id
*match
;
426 dsp_of_node
= of_parse_phandle(pdev
->dev
.of_node
, "qcom,adsp", 0);
428 dev_err(&pdev
->dev
, "DSP exists and holds audio resources\n");
432 drvdata
= devm_kzalloc(&pdev
->dev
, sizeof(struct lpass_data
),
436 platform_set_drvdata(pdev
, drvdata
);
438 match
= of_match_device(dev
->driver
->of_match_table
, dev
);
439 if (!match
|| !match
->data
)
442 drvdata
->variant
= (struct lpass_variant
*)match
->data
;
443 variant
= drvdata
->variant
;
445 res
= platform_get_resource_byname(pdev
, IORESOURCE_MEM
, "lpass-lpaif");
447 drvdata
->lpaif
= devm_ioremap_resource(&pdev
->dev
, res
);
448 if (IS_ERR((void const __force
*)drvdata
->lpaif
)) {
449 dev_err(&pdev
->dev
, "error mapping reg resource: %ld\n",
450 PTR_ERR((void const __force
*)drvdata
->lpaif
));
451 return PTR_ERR((void const __force
*)drvdata
->lpaif
);
454 lpass_cpu_regmap_config
.max_register
= LPAIF_WRDMAPER_REG(variant
,
455 variant
->wrdma_channels
+
456 variant
->wrdma_channel_start
);
458 drvdata
->lpaif_map
= devm_regmap_init_mmio(&pdev
->dev
, drvdata
->lpaif
,
459 &lpass_cpu_regmap_config
);
460 if (IS_ERR(drvdata
->lpaif_map
)) {
461 dev_err(&pdev
->dev
, "error initializing regmap: %ld\n",
462 PTR_ERR(drvdata
->lpaif_map
));
463 return PTR_ERR(drvdata
->lpaif_map
);
469 for (i
= 0; i
< variant
->num_dai
; i
++) {
470 dai_id
= variant
->dai_driver
[i
].id
;
471 drvdata
->mi2s_osr_clk
[dai_id
] = devm_clk_get(&pdev
->dev
,
472 variant
->dai_osr_clk_names
[i
]);
473 if (IS_ERR(drvdata
->mi2s_osr_clk
[dai_id
])) {
475 "%s() error getting optional %s: %ld\n",
477 variant
->dai_osr_clk_names
[i
],
478 PTR_ERR(drvdata
->mi2s_osr_clk
[dai_id
]));
480 drvdata
->mi2s_osr_clk
[dai_id
] = NULL
;
483 drvdata
->mi2s_bit_clk
[dai_id
] = devm_clk_get(&pdev
->dev
,
484 variant
->dai_bit_clk_names
[i
]);
485 if (IS_ERR(drvdata
->mi2s_bit_clk
[dai_id
])) {
487 "error getting %s: %ld\n",
488 variant
->dai_bit_clk_names
[i
],
489 PTR_ERR(drvdata
->mi2s_bit_clk
[dai_id
]));
490 return PTR_ERR(drvdata
->mi2s_bit_clk
[dai_id
]);
494 drvdata
->ahbix_clk
= devm_clk_get(&pdev
->dev
, "ahbix-clk");
495 if (IS_ERR(drvdata
->ahbix_clk
)) {
496 dev_err(&pdev
->dev
, "error getting ahbix-clk: %ld\n",
497 PTR_ERR(drvdata
->ahbix_clk
));
498 return PTR_ERR(drvdata
->ahbix_clk
);
501 ret
= clk_set_rate(drvdata
->ahbix_clk
, LPASS_AHBIX_CLOCK_FREQUENCY
);
503 dev_err(&pdev
->dev
, "error setting rate on ahbix_clk: %d\n",
507 dev_dbg(&pdev
->dev
, "set ahbix_clk rate to %lu\n",
508 clk_get_rate(drvdata
->ahbix_clk
));
510 ret
= clk_prepare_enable(drvdata
->ahbix_clk
);
512 dev_err(&pdev
->dev
, "error enabling ahbix_clk: %d\n", ret
);
516 ret
= devm_snd_soc_register_component(&pdev
->dev
,
517 &lpass_cpu_comp_driver
,
521 dev_err(&pdev
->dev
, "error registering cpu driver: %d\n", ret
);
525 ret
= asoc_qcom_lpass_platform_register(pdev
);
527 dev_err(&pdev
->dev
, "error registering platform driver: %d\n",
535 clk_disable_unprepare(drvdata
->ahbix_clk
);
538 EXPORT_SYMBOL_GPL(asoc_qcom_lpass_cpu_platform_probe
);
540 int asoc_qcom_lpass_cpu_platform_remove(struct platform_device
*pdev
)
542 struct lpass_data
*drvdata
= platform_get_drvdata(pdev
);
544 if (drvdata
->variant
->exit
)
545 drvdata
->variant
->exit(pdev
);
547 clk_disable_unprepare(drvdata
->ahbix_clk
);
551 EXPORT_SYMBOL_GPL(asoc_qcom_lpass_cpu_platform_remove
);
553 MODULE_DESCRIPTION("QTi LPASS CPU Driver");
554 MODULE_LICENSE("GPL v2");