xref: /linux/sound/soc/qcom/lpass-cpu.c (revision f3a8b6645dc2e60d11f20c1c23afd964ff4e55ae)
1 /*
2  * Copyright (c) 2010-2011,2013-2015 The Linux Foundation. All rights reserved.
3  *
4  * This program is free software; you can redistribute it and/or modify
5  * it under the terms of the GNU General Public License version 2 and
6  * only version 2 as published by the Free Software Foundation.
7  *
8  * This program is distributed in the hope that it will be useful,
9  * but WITHOUT ANY WARRANTY; without even the implied warranty of
10  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
11  * GNU General Public License for more details.
12  *
13  * lpass-cpu.c -- ALSA SoC CPU DAI driver for QTi LPASS
14  */
15 
16 #include <linux/clk.h>
17 #include <linux/kernel.h>
18 #include <linux/module.h>
19 #include <linux/of.h>
20 #include <linux/of_device.h>
21 #include <linux/platform_device.h>
22 #include <sound/pcm.h>
23 #include <sound/pcm_params.h>
24 #include <linux/regmap.h>
25 #include <sound/soc.h>
26 #include <sound/soc-dai.h>
27 #include "lpass-lpaif-reg.h"
28 #include "lpass.h"
29 
30 static int lpass_cpu_daiops_set_sysclk(struct snd_soc_dai *dai, int clk_id,
31 		unsigned int freq, int dir)
32 {
33 	struct lpass_data *drvdata = snd_soc_dai_get_drvdata(dai);
34 	int ret;
35 
36 	if (IS_ERR(drvdata->mi2s_osr_clk[dai->driver->id]))
37 		return 0;
38 
39 	ret = clk_set_rate(drvdata->mi2s_osr_clk[dai->driver->id], freq);
40 	if (ret)
41 		dev_err(dai->dev, "%s() error setting mi2s osrclk to %u: %d\n",
42 				__func__, freq, ret);
43 
44 	return ret;
45 }
46 
47 static int lpass_cpu_daiops_startup(struct snd_pcm_substream *substream,
48 		struct snd_soc_dai *dai)
49 {
50 	struct lpass_data *drvdata = snd_soc_dai_get_drvdata(dai);
51 	int ret;
52 
53 	if (!IS_ERR(drvdata->mi2s_osr_clk[dai->driver->id])) {
54 		ret = clk_prepare_enable(
55 				drvdata->mi2s_osr_clk[dai->driver->id]);
56 		if (ret) {
57 			dev_err(dai->dev, "%s() error in enabling mi2s osr clk: %d\n",
58 					__func__, ret);
59 			return ret;
60 		}
61 	}
62 
63 	ret = clk_prepare_enable(drvdata->mi2s_bit_clk[dai->driver->id]);
64 	if (ret) {
65 		dev_err(dai->dev, "%s() error in enabling mi2s bit clk: %d\n",
66 				__func__, ret);
67 		if (!IS_ERR(drvdata->mi2s_osr_clk[dai->driver->id]))
68 			clk_disable_unprepare(
69 				drvdata->mi2s_osr_clk[dai->driver->id]);
70 		return ret;
71 	}
72 
73 	return 0;
74 }
75 
76 static void lpass_cpu_daiops_shutdown(struct snd_pcm_substream *substream,
77 		struct snd_soc_dai *dai)
78 {
79 	struct lpass_data *drvdata = snd_soc_dai_get_drvdata(dai);
80 
81 	clk_disable_unprepare(drvdata->mi2s_bit_clk[dai->driver->id]);
82 
83 	if (!IS_ERR(drvdata->mi2s_osr_clk[dai->driver->id]))
84 		clk_disable_unprepare(drvdata->mi2s_osr_clk[dai->driver->id]);
85 }
86 
87 static int lpass_cpu_daiops_hw_params(struct snd_pcm_substream *substream,
88 		struct snd_pcm_hw_params *params, struct snd_soc_dai *dai)
89 {
90 	struct lpass_data *drvdata = snd_soc_dai_get_drvdata(dai);
91 	snd_pcm_format_t format = params_format(params);
92 	unsigned int channels = params_channels(params);
93 	unsigned int rate = params_rate(params);
94 	unsigned int regval;
95 	int bitwidth, ret;
96 
97 	bitwidth = snd_pcm_format_width(format);
98 	if (bitwidth < 0) {
99 		dev_err(dai->dev, "%s() invalid bit width given: %d\n",
100 				__func__, bitwidth);
101 		return bitwidth;
102 	}
103 
104 	regval = LPAIF_I2SCTL_LOOPBACK_DISABLE |
105 			LPAIF_I2SCTL_WSSRC_INTERNAL;
106 
107 	switch (bitwidth) {
108 	case 16:
109 		regval |= LPAIF_I2SCTL_BITWIDTH_16;
110 		break;
111 	case 24:
112 		regval |= LPAIF_I2SCTL_BITWIDTH_24;
113 		break;
114 	case 32:
115 		regval |= LPAIF_I2SCTL_BITWIDTH_32;
116 		break;
117 	default:
118 		dev_err(dai->dev, "%s() invalid bitwidth given: %d\n",
119 				__func__, bitwidth);
120 		return -EINVAL;
121 	}
122 
123 	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
124 		switch (channels) {
125 		case 1:
126 			regval |= LPAIF_I2SCTL_SPKMODE_SD0;
127 			regval |= LPAIF_I2SCTL_SPKMONO_MONO;
128 			break;
129 		case 2:
130 			regval |= LPAIF_I2SCTL_SPKMODE_SD0;
131 			regval |= LPAIF_I2SCTL_SPKMONO_STEREO;
132 			break;
133 		case 4:
134 			regval |= LPAIF_I2SCTL_SPKMODE_QUAD01;
135 			regval |= LPAIF_I2SCTL_SPKMONO_STEREO;
136 			break;
137 		case 6:
138 			regval |= LPAIF_I2SCTL_SPKMODE_6CH;
139 			regval |= LPAIF_I2SCTL_SPKMONO_STEREO;
140 			break;
141 		case 8:
142 			regval |= LPAIF_I2SCTL_SPKMODE_8CH;
143 			regval |= LPAIF_I2SCTL_SPKMONO_STEREO;
144 			break;
145 		default:
146 			dev_err(dai->dev, "%s() invalid channels given: %u\n",
147 					__func__, channels);
148 			return -EINVAL;
149 		}
150 	} else {
151 		switch (channels) {
152 		case 1:
153 			regval |= LPAIF_I2SCTL_MICMODE_SD0;
154 			regval |= LPAIF_I2SCTL_MICMONO_MONO;
155 			break;
156 		case 2:
157 			regval |= LPAIF_I2SCTL_MICMODE_SD0;
158 			regval |= LPAIF_I2SCTL_MICMONO_STEREO;
159 			break;
160 		case 4:
161 			regval |= LPAIF_I2SCTL_MICMODE_QUAD01;
162 			regval |= LPAIF_I2SCTL_MICMONO_STEREO;
163 			break;
164 		case 6:
165 			regval |= LPAIF_I2SCTL_MICMODE_6CH;
166 			regval |= LPAIF_I2SCTL_MICMONO_STEREO;
167 			break;
168 		case 8:
169 			regval |= LPAIF_I2SCTL_MICMODE_8CH;
170 			regval |= LPAIF_I2SCTL_MICMONO_STEREO;
171 			break;
172 		default:
173 			dev_err(dai->dev, "%s() invalid channels given: %u\n",
174 					__func__, channels);
175 			return -EINVAL;
176 		}
177 	}
178 
179 	ret = regmap_write(drvdata->lpaif_map,
180 			   LPAIF_I2SCTL_REG(drvdata->variant, dai->driver->id),
181 			   regval);
182 	if (ret) {
183 		dev_err(dai->dev, "%s() error writing to i2sctl reg: %d\n",
184 				__func__, ret);
185 		return ret;
186 	}
187 
188 	ret = clk_set_rate(drvdata->mi2s_bit_clk[dai->driver->id],
189 			   rate * bitwidth * 2);
190 	if (ret) {
191 		dev_err(dai->dev, "%s() error setting mi2s bitclk to %u: %d\n",
192 				__func__, rate * bitwidth * 2, ret);
193 		return ret;
194 	}
195 
196 	return 0;
197 }
198 
199 static int lpass_cpu_daiops_hw_free(struct snd_pcm_substream *substream,
200 		struct snd_soc_dai *dai)
201 {
202 	struct lpass_data *drvdata = snd_soc_dai_get_drvdata(dai);
203 	int ret;
204 
205 	ret = regmap_write(drvdata->lpaif_map,
206 			   LPAIF_I2SCTL_REG(drvdata->variant, dai->driver->id),
207 			   0);
208 	if (ret)
209 		dev_err(dai->dev, "%s() error writing to i2sctl reg: %d\n",
210 				__func__, ret);
211 
212 	return ret;
213 }
214 
215 static int lpass_cpu_daiops_prepare(struct snd_pcm_substream *substream,
216 		struct snd_soc_dai *dai)
217 {
218 	struct lpass_data *drvdata = snd_soc_dai_get_drvdata(dai);
219 	int ret;
220 	unsigned int val, mask;
221 
222 	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
223 		val = LPAIF_I2SCTL_SPKEN_ENABLE;
224 		mask = LPAIF_I2SCTL_SPKEN_MASK;
225 	} else  {
226 		val = LPAIF_I2SCTL_MICEN_ENABLE;
227 		mask = LPAIF_I2SCTL_MICEN_MASK;
228 	}
229 
230 	ret = regmap_update_bits(drvdata->lpaif_map,
231 			LPAIF_I2SCTL_REG(drvdata->variant, dai->driver->id),
232 			mask, val);
233 	if (ret)
234 		dev_err(dai->dev, "%s() error writing to i2sctl reg: %d\n",
235 				__func__, ret);
236 
237 	return ret;
238 }
239 
240 static int lpass_cpu_daiops_trigger(struct snd_pcm_substream *substream,
241 		int cmd, struct snd_soc_dai *dai)
242 {
243 	struct lpass_data *drvdata = snd_soc_dai_get_drvdata(dai);
244 	int ret = -EINVAL;
245 	unsigned int val, mask;
246 
247 	switch (cmd) {
248 	case SNDRV_PCM_TRIGGER_START:
249 	case SNDRV_PCM_TRIGGER_RESUME:
250 	case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
251 		if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
252 			val = LPAIF_I2SCTL_SPKEN_ENABLE;
253 			mask = LPAIF_I2SCTL_SPKEN_MASK;
254 		} else  {
255 			val = LPAIF_I2SCTL_MICEN_ENABLE;
256 			mask = LPAIF_I2SCTL_MICEN_MASK;
257 		}
258 
259 		ret = regmap_update_bits(drvdata->lpaif_map,
260 				LPAIF_I2SCTL_REG(drvdata->variant,
261 						dai->driver->id),
262 				mask, val);
263 		if (ret)
264 			dev_err(dai->dev, "%s() error writing to i2sctl reg: %d\n",
265 					__func__, ret);
266 		break;
267 	case SNDRV_PCM_TRIGGER_STOP:
268 	case SNDRV_PCM_TRIGGER_SUSPEND:
269 	case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
270 		if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
271 			val = LPAIF_I2SCTL_SPKEN_DISABLE;
272 			mask = LPAIF_I2SCTL_SPKEN_MASK;
273 		} else  {
274 			val = LPAIF_I2SCTL_MICEN_DISABLE;
275 			mask = LPAIF_I2SCTL_MICEN_MASK;
276 		}
277 
278 		ret = regmap_update_bits(drvdata->lpaif_map,
279 				LPAIF_I2SCTL_REG(drvdata->variant,
280 						dai->driver->id),
281 				mask, val);
282 		if (ret)
283 			dev_err(dai->dev, "%s() error writing to i2sctl reg: %d\n",
284 					__func__, ret);
285 		break;
286 	}
287 
288 	return ret;
289 }
290 
291 const struct snd_soc_dai_ops asoc_qcom_lpass_cpu_dai_ops = {
292 	.set_sysclk	= lpass_cpu_daiops_set_sysclk,
293 	.startup	= lpass_cpu_daiops_startup,
294 	.shutdown	= lpass_cpu_daiops_shutdown,
295 	.hw_params	= lpass_cpu_daiops_hw_params,
296 	.hw_free	= lpass_cpu_daiops_hw_free,
297 	.prepare	= lpass_cpu_daiops_prepare,
298 	.trigger	= lpass_cpu_daiops_trigger,
299 };
300 EXPORT_SYMBOL_GPL(asoc_qcom_lpass_cpu_dai_ops);
301 
302 int asoc_qcom_lpass_cpu_dai_probe(struct snd_soc_dai *dai)
303 {
304 	struct lpass_data *drvdata = snd_soc_dai_get_drvdata(dai);
305 	int ret;
306 
307 	/* ensure audio hardware is disabled */
308 	ret = regmap_write(drvdata->lpaif_map,
309 			LPAIF_I2SCTL_REG(drvdata->variant, dai->driver->id), 0);
310 	if (ret)
311 		dev_err(dai->dev, "%s() error writing to i2sctl reg: %d\n",
312 				__func__, ret);
313 
314 	return ret;
315 }
316 EXPORT_SYMBOL_GPL(asoc_qcom_lpass_cpu_dai_probe);
317 
318 static const struct snd_soc_component_driver lpass_cpu_comp_driver = {
319 	.name = "lpass-cpu",
320 };
321 
322 static bool lpass_cpu_regmap_writeable(struct device *dev, unsigned int reg)
323 {
324 	struct lpass_data *drvdata = dev_get_drvdata(dev);
325 	struct lpass_variant *v = drvdata->variant;
326 	int i;
327 
328 	for (i = 0; i < v->i2s_ports; ++i)
329 		if (reg == LPAIF_I2SCTL_REG(v, i))
330 			return true;
331 
332 	for (i = 0; i < v->irq_ports; ++i) {
333 		if (reg == LPAIF_IRQEN_REG(v, i))
334 			return true;
335 		if (reg == LPAIF_IRQCLEAR_REG(v, i))
336 			return true;
337 	}
338 
339 	for (i = 0; i < v->rdma_channels; ++i) {
340 		if (reg == LPAIF_RDMACTL_REG(v, i))
341 			return true;
342 		if (reg == LPAIF_RDMABASE_REG(v, i))
343 			return true;
344 		if (reg == LPAIF_RDMABUFF_REG(v, i))
345 			return true;
346 		if (reg == LPAIF_RDMAPER_REG(v, i))
347 			return true;
348 	}
349 
350 	for (i = 0; i < v->wrdma_channels; ++i) {
351 		if (reg == LPAIF_WRDMACTL_REG(v, i + v->wrdma_channel_start))
352 			return true;
353 		if (reg == LPAIF_WRDMABASE_REG(v, i + v->wrdma_channel_start))
354 			return true;
355 		if (reg == LPAIF_WRDMABUFF_REG(v, i + v->wrdma_channel_start))
356 			return true;
357 		if (reg == LPAIF_WRDMAPER_REG(v, i + v->wrdma_channel_start))
358 			return true;
359 	}
360 
361 	return false;
362 }
363 
364 static bool lpass_cpu_regmap_readable(struct device *dev, unsigned int reg)
365 {
366 	struct lpass_data *drvdata = dev_get_drvdata(dev);
367 	struct lpass_variant *v = drvdata->variant;
368 	int i;
369 
370 	for (i = 0; i < v->i2s_ports; ++i)
371 		if (reg == LPAIF_I2SCTL_REG(v, i))
372 			return true;
373 
374 	for (i = 0; i < v->irq_ports; ++i) {
375 		if (reg == LPAIF_IRQEN_REG(v, i))
376 			return true;
377 		if (reg == LPAIF_IRQSTAT_REG(v, i))
378 			return true;
379 	}
380 
381 	for (i = 0; i < v->rdma_channels; ++i) {
382 		if (reg == LPAIF_RDMACTL_REG(v, i))
383 			return true;
384 		if (reg == LPAIF_RDMABASE_REG(v, i))
385 			return true;
386 		if (reg == LPAIF_RDMABUFF_REG(v, i))
387 			return true;
388 		if (reg == LPAIF_RDMACURR_REG(v, i))
389 			return true;
390 		if (reg == LPAIF_RDMAPER_REG(v, i))
391 			return true;
392 	}
393 
394 	for (i = 0; i < v->wrdma_channels; ++i) {
395 		if (reg == LPAIF_WRDMACTL_REG(v, i + v->wrdma_channel_start))
396 			return true;
397 		if (reg == LPAIF_WRDMABASE_REG(v, i + v->wrdma_channel_start))
398 			return true;
399 		if (reg == LPAIF_WRDMABUFF_REG(v, i + v->wrdma_channel_start))
400 			return true;
401 		if (reg == LPAIF_WRDMACURR_REG(v, i + v->wrdma_channel_start))
402 			return true;
403 		if (reg == LPAIF_WRDMAPER_REG(v, i + v->wrdma_channel_start))
404 			return true;
405 	}
406 
407 	return false;
408 }
409 
410 static bool lpass_cpu_regmap_volatile(struct device *dev, unsigned int reg)
411 {
412 	struct lpass_data *drvdata = dev_get_drvdata(dev);
413 	struct lpass_variant *v = drvdata->variant;
414 	int i;
415 
416 	for (i = 0; i < v->irq_ports; ++i)
417 		if (reg == LPAIF_IRQSTAT_REG(v, i))
418 			return true;
419 
420 	for (i = 0; i < v->rdma_channels; ++i)
421 		if (reg == LPAIF_RDMACURR_REG(v, i))
422 			return true;
423 
424 	for (i = 0; i < v->wrdma_channels; ++i)
425 		if (reg == LPAIF_WRDMACURR_REG(v, i + v->wrdma_channel_start))
426 			return true;
427 
428 	return false;
429 }
430 
431 static struct regmap_config lpass_cpu_regmap_config = {
432 	.reg_bits = 32,
433 	.reg_stride = 4,
434 	.val_bits = 32,
435 	.writeable_reg = lpass_cpu_regmap_writeable,
436 	.readable_reg = lpass_cpu_regmap_readable,
437 	.volatile_reg = lpass_cpu_regmap_volatile,
438 	.cache_type = REGCACHE_FLAT,
439 };
440 
441 int asoc_qcom_lpass_cpu_platform_probe(struct platform_device *pdev)
442 {
443 	struct lpass_data *drvdata;
444 	struct device_node *dsp_of_node;
445 	struct resource *res;
446 	struct lpass_variant *variant;
447 	struct device *dev = &pdev->dev;
448 	const struct of_device_id *match;
449 	char clk_name[16];
450 	int ret, i, dai_id;
451 
452 	dsp_of_node = of_parse_phandle(pdev->dev.of_node, "qcom,adsp", 0);
453 	if (dsp_of_node) {
454 		dev_err(&pdev->dev, "%s() DSP exists and holds audio resources\n",
455 				__func__);
456 		return -EBUSY;
457 	}
458 
459 	drvdata = devm_kzalloc(&pdev->dev, sizeof(struct lpass_data),
460 			GFP_KERNEL);
461 	if (!drvdata)
462 		return -ENOMEM;
463 	platform_set_drvdata(pdev, drvdata);
464 
465 	match = of_match_device(dev->driver->of_match_table, dev);
466 	if (!match || !match->data)
467 		return -EINVAL;
468 
469 	drvdata->variant = (struct lpass_variant *)match->data;
470 	variant = drvdata->variant;
471 
472 	res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "lpass-lpaif");
473 
474 	drvdata->lpaif = devm_ioremap_resource(&pdev->dev, res);
475 	if (IS_ERR((void const __force *)drvdata->lpaif)) {
476 		dev_err(&pdev->dev, "%s() error mapping reg resource: %ld\n",
477 				__func__,
478 				PTR_ERR((void const __force *)drvdata->lpaif));
479 		return PTR_ERR((void const __force *)drvdata->lpaif);
480 	}
481 
482 	lpass_cpu_regmap_config.max_register = LPAIF_WRDMAPER_REG(variant,
483 						variant->wrdma_channels +
484 						variant->wrdma_channel_start);
485 
486 	drvdata->lpaif_map = devm_regmap_init_mmio(&pdev->dev, drvdata->lpaif,
487 			&lpass_cpu_regmap_config);
488 	if (IS_ERR(drvdata->lpaif_map)) {
489 		dev_err(&pdev->dev, "%s() error initializing regmap: %ld\n",
490 				__func__, PTR_ERR(drvdata->lpaif_map));
491 		return PTR_ERR(drvdata->lpaif_map);
492 	}
493 
494 	if (variant->init)
495 		variant->init(pdev);
496 
497 	for (i = 0; i < variant->num_dai; i++) {
498 		dai_id = variant->dai_driver[i].id;
499 		if (variant->num_dai > 1)
500 			sprintf(clk_name, "mi2s-osr-clk%d", i);
501 		else
502 			sprintf(clk_name, "mi2s-osr-clk");
503 
504 		drvdata->mi2s_osr_clk[dai_id] = devm_clk_get(&pdev->dev,
505 								clk_name);
506 		if (IS_ERR(drvdata->mi2s_osr_clk[dai_id])) {
507 			dev_warn(&pdev->dev,
508 				"%s() error getting mi2s-osr-clk: %ld\n",
509 				__func__,
510 				PTR_ERR(drvdata->mi2s_osr_clk[dai_id]));
511 		}
512 
513 		if (variant->num_dai > 1)
514 			sprintf(clk_name, "mi2s-bit-clk%d", i);
515 		else
516 			sprintf(clk_name, "mi2s-bit-clk");
517 
518 		drvdata->mi2s_bit_clk[dai_id] = devm_clk_get(&pdev->dev,
519 							    clk_name);
520 		if (IS_ERR(drvdata->mi2s_bit_clk[dai_id])) {
521 			dev_err(&pdev->dev,
522 				"%s() error getting mi2s-bit-clk: %ld\n",
523 				__func__,
524 				PTR_ERR(drvdata->mi2s_bit_clk[dai_id]));
525 			return PTR_ERR(drvdata->mi2s_bit_clk[dai_id]);
526 		}
527 	}
528 
529 	drvdata->ahbix_clk = devm_clk_get(&pdev->dev, "ahbix-clk");
530 	if (IS_ERR(drvdata->ahbix_clk)) {
531 		dev_err(&pdev->dev, "%s() error getting ahbix-clk: %ld\n",
532 				__func__, PTR_ERR(drvdata->ahbix_clk));
533 		return PTR_ERR(drvdata->ahbix_clk);
534 	}
535 
536 	ret = clk_set_rate(drvdata->ahbix_clk, LPASS_AHBIX_CLOCK_FREQUENCY);
537 	if (ret) {
538 		dev_err(&pdev->dev, "%s() error setting rate on ahbix_clk: %d\n",
539 				__func__, ret);
540 		return ret;
541 	}
542 	dev_dbg(&pdev->dev, "%s() set ahbix_clk rate to %lu\n", __func__,
543 			clk_get_rate(drvdata->ahbix_clk));
544 
545 	ret = clk_prepare_enable(drvdata->ahbix_clk);
546 	if (ret) {
547 		dev_err(&pdev->dev, "%s() error enabling ahbix_clk: %d\n",
548 				__func__, ret);
549 		return ret;
550 	}
551 
552 	ret = devm_snd_soc_register_component(&pdev->dev,
553 					      &lpass_cpu_comp_driver,
554 					      variant->dai_driver,
555 					      variant->num_dai);
556 	if (ret) {
557 		dev_err(&pdev->dev, "%s() error registering cpu driver: %d\n",
558 				__func__, ret);
559 		goto err_clk;
560 	}
561 
562 	ret = asoc_qcom_lpass_platform_register(pdev);
563 	if (ret) {
564 		dev_err(&pdev->dev, "%s() error registering platform driver: %d\n",
565 				__func__, ret);
566 		goto err_clk;
567 	}
568 
569 	return 0;
570 
571 err_clk:
572 	clk_disable_unprepare(drvdata->ahbix_clk);
573 	return ret;
574 }
575 EXPORT_SYMBOL_GPL(asoc_qcom_lpass_cpu_platform_probe);
576 
577 int asoc_qcom_lpass_cpu_platform_remove(struct platform_device *pdev)
578 {
579 	struct lpass_data *drvdata = platform_get_drvdata(pdev);
580 
581 	if (drvdata->variant->exit)
582 		drvdata->variant->exit(pdev);
583 
584 	clk_disable_unprepare(drvdata->ahbix_clk);
585 
586 	return 0;
587 }
588 EXPORT_SYMBOL_GPL(asoc_qcom_lpass_cpu_platform_remove);
589