xref: /openbmc/linux/sound/soc/qcom/lpass-cpu.c (revision 86edee97)
1 // SPDX-License-Identifier: GPL-2.0-only
2 /*
3  * Copyright (c) 2010-2011,2013-2015 The Linux Foundation. All rights reserved.
4  *
5  * lpass-cpu.c -- ALSA SoC CPU DAI driver for QTi LPASS
6  */
7 
8 #include <linux/clk.h>
9 #include <linux/kernel.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 <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"
20 #include "lpass.h"
21 
22 static int lpass_cpu_daiops_set_sysclk(struct snd_soc_dai *dai, int clk_id,
23 		unsigned int freq, int dir)
24 {
25 	struct lpass_data *drvdata = snd_soc_dai_get_drvdata(dai);
26 	int ret;
27 
28 	ret = clk_set_rate(drvdata->mi2s_osr_clk[dai->driver->id], freq);
29 	if (ret)
30 		dev_err(dai->dev, "error setting mi2s osrclk to %u: %d\n",
31 			freq, ret);
32 
33 	return ret;
34 }
35 
36 static int lpass_cpu_daiops_startup(struct snd_pcm_substream *substream,
37 		struct snd_soc_dai *dai)
38 {
39 	struct lpass_data *drvdata = snd_soc_dai_get_drvdata(dai);
40 	int ret;
41 
42 	ret = clk_prepare_enable(drvdata->mi2s_osr_clk[dai->driver->id]);
43 	if (ret) {
44 		dev_err(dai->dev, "error in enabling mi2s osr clk: %d\n", ret);
45 		return ret;
46 	}
47 
48 	ret = clk_prepare_enable(drvdata->mi2s_bit_clk[dai->driver->id]);
49 	if (ret) {
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]);
52 		return ret;
53 	}
54 
55 	return 0;
56 }
57 
58 static void lpass_cpu_daiops_shutdown(struct snd_pcm_substream *substream,
59 		struct snd_soc_dai *dai)
60 {
61 	struct lpass_data *drvdata = snd_soc_dai_get_drvdata(dai);
62 
63 	clk_disable_unprepare(drvdata->mi2s_bit_clk[dai->driver->id]);
64 
65 	clk_disable_unprepare(drvdata->mi2s_osr_clk[dai->driver->id]);
66 }
67 
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)
70 {
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);
75 	unsigned int regval;
76 	int bitwidth, ret;
77 
78 	bitwidth = snd_pcm_format_width(format);
79 	if (bitwidth < 0) {
80 		dev_err(dai->dev, "invalid bit width given: %d\n", bitwidth);
81 		return bitwidth;
82 	}
83 
84 	regval = LPAIF_I2SCTL_LOOPBACK_DISABLE |
85 			LPAIF_I2SCTL_WSSRC_INTERNAL;
86 
87 	switch (bitwidth) {
88 	case 16:
89 		regval |= LPAIF_I2SCTL_BITWIDTH_16;
90 		break;
91 	case 24:
92 		regval |= LPAIF_I2SCTL_BITWIDTH_24;
93 		break;
94 	case 32:
95 		regval |= LPAIF_I2SCTL_BITWIDTH_32;
96 		break;
97 	default:
98 		dev_err(dai->dev, "invalid bitwidth given: %d\n", bitwidth);
99 		return -EINVAL;
100 	}
101 
102 	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
103 		switch (channels) {
104 		case 1:
105 			regval |= LPAIF_I2SCTL_SPKMODE_SD0;
106 			regval |= LPAIF_I2SCTL_SPKMONO_MONO;
107 			break;
108 		case 2:
109 			regval |= LPAIF_I2SCTL_SPKMODE_SD0;
110 			regval |= LPAIF_I2SCTL_SPKMONO_STEREO;
111 			break;
112 		case 4:
113 			regval |= LPAIF_I2SCTL_SPKMODE_QUAD01;
114 			regval |= LPAIF_I2SCTL_SPKMONO_STEREO;
115 			break;
116 		case 6:
117 			regval |= LPAIF_I2SCTL_SPKMODE_6CH;
118 			regval |= LPAIF_I2SCTL_SPKMONO_STEREO;
119 			break;
120 		case 8:
121 			regval |= LPAIF_I2SCTL_SPKMODE_8CH;
122 			regval |= LPAIF_I2SCTL_SPKMONO_STEREO;
123 			break;
124 		default:
125 			dev_err(dai->dev, "invalid channels given: %u\n",
126 				channels);
127 			return -EINVAL;
128 		}
129 	} else {
130 		switch (channels) {
131 		case 1:
132 			regval |= LPAIF_I2SCTL_MICMODE_SD0;
133 			regval |= LPAIF_I2SCTL_MICMONO_MONO;
134 			break;
135 		case 2:
136 			regval |= LPAIF_I2SCTL_MICMODE_SD0;
137 			regval |= LPAIF_I2SCTL_MICMONO_STEREO;
138 			break;
139 		case 4:
140 			regval |= LPAIF_I2SCTL_MICMODE_QUAD01;
141 			regval |= LPAIF_I2SCTL_MICMONO_STEREO;
142 			break;
143 		case 6:
144 			regval |= LPAIF_I2SCTL_MICMODE_6CH;
145 			regval |= LPAIF_I2SCTL_MICMONO_STEREO;
146 			break;
147 		case 8:
148 			regval |= LPAIF_I2SCTL_MICMODE_8CH;
149 			regval |= LPAIF_I2SCTL_MICMONO_STEREO;
150 			break;
151 		default:
152 			dev_err(dai->dev, "invalid channels given: %u\n",
153 				channels);
154 			return -EINVAL;
155 		}
156 	}
157 
158 	ret = regmap_write(drvdata->lpaif_map,
159 			   LPAIF_I2SCTL_REG(drvdata->variant, dai->driver->id),
160 			   regval);
161 	if (ret) {
162 		dev_err(dai->dev, "error writing to i2sctl reg: %d\n", ret);
163 		return ret;
164 	}
165 
166 	ret = clk_set_rate(drvdata->mi2s_bit_clk[dai->driver->id],
167 			   rate * bitwidth * 2);
168 	if (ret) {
169 		dev_err(dai->dev, "error setting mi2s bitclk to %u: %d\n",
170 			rate * bitwidth * 2, ret);
171 		return ret;
172 	}
173 
174 	return 0;
175 }
176 
177 static int lpass_cpu_daiops_hw_free(struct snd_pcm_substream *substream,
178 		struct snd_soc_dai *dai)
179 {
180 	struct lpass_data *drvdata = snd_soc_dai_get_drvdata(dai);
181 	int ret;
182 
183 	ret = regmap_write(drvdata->lpaif_map,
184 			   LPAIF_I2SCTL_REG(drvdata->variant, dai->driver->id),
185 			   0);
186 	if (ret)
187 		dev_err(dai->dev, "error writing to i2sctl reg: %d\n", ret);
188 
189 	return ret;
190 }
191 
192 static int lpass_cpu_daiops_prepare(struct snd_pcm_substream *substream,
193 		struct snd_soc_dai *dai)
194 {
195 	struct lpass_data *drvdata = snd_soc_dai_get_drvdata(dai);
196 	int ret;
197 	unsigned int val, mask;
198 
199 	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
200 		val = LPAIF_I2SCTL_SPKEN_ENABLE;
201 		mask = LPAIF_I2SCTL_SPKEN_MASK;
202 	} else  {
203 		val = LPAIF_I2SCTL_MICEN_ENABLE;
204 		mask = LPAIF_I2SCTL_MICEN_MASK;
205 	}
206 
207 	ret = regmap_update_bits(drvdata->lpaif_map,
208 			LPAIF_I2SCTL_REG(drvdata->variant, dai->driver->id),
209 			mask, val);
210 	if (ret)
211 		dev_err(dai->dev, "error writing to i2sctl reg: %d\n", ret);
212 
213 	return ret;
214 }
215 
216 static int lpass_cpu_daiops_trigger(struct snd_pcm_substream *substream,
217 		int cmd, struct snd_soc_dai *dai)
218 {
219 	struct lpass_data *drvdata = snd_soc_dai_get_drvdata(dai);
220 	int ret = -EINVAL;
221 	unsigned int val, mask;
222 
223 	switch (cmd) {
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;
230 		} else  {
231 			val = LPAIF_I2SCTL_MICEN_ENABLE;
232 			mask = LPAIF_I2SCTL_MICEN_MASK;
233 		}
234 
235 		ret = regmap_update_bits(drvdata->lpaif_map,
236 				LPAIF_I2SCTL_REG(drvdata->variant,
237 						dai->driver->id),
238 				mask, val);
239 		if (ret)
240 			dev_err(dai->dev, "error writing to i2sctl reg: %d\n",
241 				ret);
242 		break;
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;
249 		} else  {
250 			val = LPAIF_I2SCTL_MICEN_DISABLE;
251 			mask = LPAIF_I2SCTL_MICEN_MASK;
252 		}
253 
254 		ret = regmap_update_bits(drvdata->lpaif_map,
255 				LPAIF_I2SCTL_REG(drvdata->variant,
256 						dai->driver->id),
257 				mask, val);
258 		if (ret)
259 			dev_err(dai->dev, "error writing to i2sctl reg: %d\n",
260 				ret);
261 		break;
262 	}
263 
264 	return ret;
265 }
266 
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,
275 };
276 EXPORT_SYMBOL_GPL(asoc_qcom_lpass_cpu_dai_ops);
277 
278 int asoc_qcom_lpass_cpu_dai_probe(struct snd_soc_dai *dai)
279 {
280 	struct lpass_data *drvdata = snd_soc_dai_get_drvdata(dai);
281 	int ret;
282 
283 	/* ensure audio hardware is disabled */
284 	ret = regmap_write(drvdata->lpaif_map,
285 			LPAIF_I2SCTL_REG(drvdata->variant, dai->driver->id), 0);
286 	if (ret)
287 		dev_err(dai->dev, "error writing to i2sctl reg: %d\n", ret);
288 
289 	return ret;
290 }
291 EXPORT_SYMBOL_GPL(asoc_qcom_lpass_cpu_dai_probe);
292 
293 static const struct snd_soc_component_driver lpass_cpu_comp_driver = {
294 	.name = "lpass-cpu",
295 };
296 
297 static bool lpass_cpu_regmap_writeable(struct device *dev, unsigned int reg)
298 {
299 	struct lpass_data *drvdata = dev_get_drvdata(dev);
300 	struct lpass_variant *v = drvdata->variant;
301 	int i;
302 
303 	for (i = 0; i < v->i2s_ports; ++i)
304 		if (reg == LPAIF_I2SCTL_REG(v, i))
305 			return true;
306 
307 	for (i = 0; i < v->irq_ports; ++i) {
308 		if (reg == LPAIF_IRQEN_REG(v, i))
309 			return true;
310 		if (reg == LPAIF_IRQCLEAR_REG(v, i))
311 			return true;
312 	}
313 
314 	for (i = 0; i < v->rdma_channels; ++i) {
315 		if (reg == LPAIF_RDMACTL_REG(v, i))
316 			return true;
317 		if (reg == LPAIF_RDMABASE_REG(v, i))
318 			return true;
319 		if (reg == LPAIF_RDMABUFF_REG(v, i))
320 			return true;
321 		if (reg == LPAIF_RDMAPER_REG(v, i))
322 			return true;
323 	}
324 
325 	for (i = 0; i < v->wrdma_channels; ++i) {
326 		if (reg == LPAIF_WRDMACTL_REG(v, i + v->wrdma_channel_start))
327 			return true;
328 		if (reg == LPAIF_WRDMABASE_REG(v, i + v->wrdma_channel_start))
329 			return true;
330 		if (reg == LPAIF_WRDMABUFF_REG(v, i + v->wrdma_channel_start))
331 			return true;
332 		if (reg == LPAIF_WRDMAPER_REG(v, i + v->wrdma_channel_start))
333 			return true;
334 	}
335 
336 	return false;
337 }
338 
339 static bool lpass_cpu_regmap_readable(struct device *dev, unsigned int reg)
340 {
341 	struct lpass_data *drvdata = dev_get_drvdata(dev);
342 	struct lpass_variant *v = drvdata->variant;
343 	int i;
344 
345 	for (i = 0; i < v->i2s_ports; ++i)
346 		if (reg == LPAIF_I2SCTL_REG(v, i))
347 			return true;
348 
349 	for (i = 0; i < v->irq_ports; ++i) {
350 		if (reg == LPAIF_IRQEN_REG(v, i))
351 			return true;
352 		if (reg == LPAIF_IRQSTAT_REG(v, i))
353 			return true;
354 	}
355 
356 	for (i = 0; i < v->rdma_channels; ++i) {
357 		if (reg == LPAIF_RDMACTL_REG(v, i))
358 			return true;
359 		if (reg == LPAIF_RDMABASE_REG(v, i))
360 			return true;
361 		if (reg == LPAIF_RDMABUFF_REG(v, i))
362 			return true;
363 		if (reg == LPAIF_RDMACURR_REG(v, i))
364 			return true;
365 		if (reg == LPAIF_RDMAPER_REG(v, i))
366 			return true;
367 	}
368 
369 	for (i = 0; i < v->wrdma_channels; ++i) {
370 		if (reg == LPAIF_WRDMACTL_REG(v, i + v->wrdma_channel_start))
371 			return true;
372 		if (reg == LPAIF_WRDMABASE_REG(v, i + v->wrdma_channel_start))
373 			return true;
374 		if (reg == LPAIF_WRDMABUFF_REG(v, i + v->wrdma_channel_start))
375 			return true;
376 		if (reg == LPAIF_WRDMACURR_REG(v, i + v->wrdma_channel_start))
377 			return true;
378 		if (reg == LPAIF_WRDMAPER_REG(v, i + v->wrdma_channel_start))
379 			return true;
380 	}
381 
382 	return false;
383 }
384 
385 static bool lpass_cpu_regmap_volatile(struct device *dev, unsigned int reg)
386 {
387 	struct lpass_data *drvdata = dev_get_drvdata(dev);
388 	struct lpass_variant *v = drvdata->variant;
389 	int i;
390 
391 	for (i = 0; i < v->irq_ports; ++i)
392 		if (reg == LPAIF_IRQSTAT_REG(v, i))
393 			return true;
394 
395 	for (i = 0; i < v->rdma_channels; ++i)
396 		if (reg == LPAIF_RDMACURR_REG(v, i))
397 			return true;
398 
399 	for (i = 0; i < v->wrdma_channels; ++i)
400 		if (reg == LPAIF_WRDMACURR_REG(v, i + v->wrdma_channel_start))
401 			return true;
402 
403 	return false;
404 }
405 
406 static struct regmap_config lpass_cpu_regmap_config = {
407 	.reg_bits = 32,
408 	.reg_stride = 4,
409 	.val_bits = 32,
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,
414 };
415 
416 int asoc_qcom_lpass_cpu_platform_probe(struct platform_device *pdev)
417 {
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;
424 	int ret, i, dai_id;
425 
426 	dsp_of_node = of_parse_phandle(pdev->dev.of_node, "qcom,adsp", 0);
427 	if (dsp_of_node) {
428 		dev_err(&pdev->dev, "DSP exists and holds audio resources\n");
429 		return -EBUSY;
430 	}
431 
432 	drvdata = devm_kzalloc(&pdev->dev, sizeof(struct lpass_data),
433 			GFP_KERNEL);
434 	if (!drvdata)
435 		return -ENOMEM;
436 	platform_set_drvdata(pdev, drvdata);
437 
438 	match = of_match_device(dev->driver->of_match_table, dev);
439 	if (!match || !match->data)
440 		return -EINVAL;
441 
442 	drvdata->variant = (struct lpass_variant *)match->data;
443 	variant = drvdata->variant;
444 
445 	res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "lpass-lpaif");
446 
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);
452 	}
453 
454 	lpass_cpu_regmap_config.max_register = LPAIF_WRDMAPER_REG(variant,
455 						variant->wrdma_channels +
456 						variant->wrdma_channel_start);
457 
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);
464 	}
465 
466 	if (variant->init)
467 		variant->init(pdev);
468 
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])) {
474 			dev_warn(&pdev->dev,
475 				"%s() error getting optional %s: %ld\n",
476 				__func__,
477 				variant->dai_osr_clk_names[i],
478 				PTR_ERR(drvdata->mi2s_osr_clk[dai_id]));
479 
480 			drvdata->mi2s_osr_clk[dai_id] = NULL;
481 		}
482 
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])) {
486 			dev_err(&pdev->dev,
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]);
491 		}
492 	}
493 
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);
499 	}
500 
501 	ret = clk_set_rate(drvdata->ahbix_clk, LPASS_AHBIX_CLOCK_FREQUENCY);
502 	if (ret) {
503 		dev_err(&pdev->dev, "error setting rate on ahbix_clk: %d\n",
504 			ret);
505 		return ret;
506 	}
507 	dev_dbg(&pdev->dev, "set ahbix_clk rate to %lu\n",
508 		clk_get_rate(drvdata->ahbix_clk));
509 
510 	ret = clk_prepare_enable(drvdata->ahbix_clk);
511 	if (ret) {
512 		dev_err(&pdev->dev, "error enabling ahbix_clk: %d\n", ret);
513 		return ret;
514 	}
515 
516 	ret = devm_snd_soc_register_component(&pdev->dev,
517 					      &lpass_cpu_comp_driver,
518 					      variant->dai_driver,
519 					      variant->num_dai);
520 	if (ret) {
521 		dev_err(&pdev->dev, "error registering cpu driver: %d\n", ret);
522 		goto err_clk;
523 	}
524 
525 	ret = asoc_qcom_lpass_platform_register(pdev);
526 	if (ret) {
527 		dev_err(&pdev->dev, "error registering platform driver: %d\n",
528 			ret);
529 		goto err_clk;
530 	}
531 
532 	return 0;
533 
534 err_clk:
535 	clk_disable_unprepare(drvdata->ahbix_clk);
536 	return ret;
537 }
538 EXPORT_SYMBOL_GPL(asoc_qcom_lpass_cpu_platform_probe);
539 
540 int asoc_qcom_lpass_cpu_platform_remove(struct platform_device *pdev)
541 {
542 	struct lpass_data *drvdata = platform_get_drvdata(pdev);
543 
544 	if (drvdata->variant->exit)
545 		drvdata->variant->exit(pdev);
546 
547 	clk_disable_unprepare(drvdata->ahbix_clk);
548 
549 	return 0;
550 }
551 EXPORT_SYMBOL_GPL(asoc_qcom_lpass_cpu_platform_remove);
552 
553 MODULE_DESCRIPTION("QTi LPASS CPU Driver");
554 MODULE_LICENSE("GPL v2");
555