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 #define LPASS_CPU_MAX_MI2S_LINES 4 23 #define LPASS_CPU_I2S_SD0_MASK BIT(0) 24 #define LPASS_CPU_I2S_SD1_MASK BIT(1) 25 #define LPASS_CPU_I2S_SD2_MASK BIT(2) 26 #define LPASS_CPU_I2S_SD3_MASK BIT(3) 27 #define LPASS_CPU_I2S_SD0_1_MASK GENMASK(1, 0) 28 #define LPASS_CPU_I2S_SD2_3_MASK GENMASK(3, 2) 29 #define LPASS_CPU_I2S_SD0_1_2_MASK GENMASK(2, 0) 30 #define LPASS_CPU_I2S_SD0_1_2_3_MASK GENMASK(3, 0) 31 32 static int lpass_cpu_daiops_set_sysclk(struct snd_soc_dai *dai, int clk_id, 33 unsigned int freq, int dir) 34 { 35 struct lpass_data *drvdata = snd_soc_dai_get_drvdata(dai); 36 int ret; 37 38 ret = clk_set_rate(drvdata->mi2s_osr_clk[dai->driver->id], freq); 39 if (ret) 40 dev_err(dai->dev, "error setting mi2s osrclk to %u: %d\n", 41 freq, ret); 42 43 return ret; 44 } 45 46 static int lpass_cpu_daiops_startup(struct snd_pcm_substream *substream, 47 struct snd_soc_dai *dai) 48 { 49 struct lpass_data *drvdata = snd_soc_dai_get_drvdata(dai); 50 int ret; 51 52 ret = clk_prepare_enable(drvdata->mi2s_osr_clk[dai->driver->id]); 53 if (ret) { 54 dev_err(dai->dev, "error in enabling mi2s osr clk: %d\n", ret); 55 return ret; 56 } 57 58 ret = clk_prepare_enable(drvdata->mi2s_bit_clk[dai->driver->id]); 59 if (ret) { 60 dev_err(dai->dev, "error in enabling mi2s bit clk: %d\n", ret); 61 clk_disable_unprepare(drvdata->mi2s_osr_clk[dai->driver->id]); 62 return ret; 63 } 64 65 return 0; 66 } 67 68 static void lpass_cpu_daiops_shutdown(struct snd_pcm_substream *substream, 69 struct snd_soc_dai *dai) 70 { 71 struct lpass_data *drvdata = snd_soc_dai_get_drvdata(dai); 72 73 clk_disable_unprepare(drvdata->mi2s_bit_clk[dai->driver->id]); 74 75 clk_disable_unprepare(drvdata->mi2s_osr_clk[dai->driver->id]); 76 } 77 78 static int lpass_cpu_daiops_hw_params(struct snd_pcm_substream *substream, 79 struct snd_pcm_hw_params *params, struct snd_soc_dai *dai) 80 { 81 struct lpass_data *drvdata = snd_soc_dai_get_drvdata(dai); 82 snd_pcm_format_t format = params_format(params); 83 unsigned int channels = params_channels(params); 84 unsigned int rate = params_rate(params); 85 unsigned int mode; 86 unsigned int regval; 87 int bitwidth, ret; 88 89 bitwidth = snd_pcm_format_width(format); 90 if (bitwidth < 0) { 91 dev_err(dai->dev, "invalid bit width given: %d\n", bitwidth); 92 return bitwidth; 93 } 94 95 regval = LPAIF_I2SCTL_LOOPBACK_DISABLE | 96 LPAIF_I2SCTL_WSSRC_INTERNAL; 97 98 switch (bitwidth) { 99 case 16: 100 regval |= LPAIF_I2SCTL_BITWIDTH_16; 101 break; 102 case 24: 103 regval |= LPAIF_I2SCTL_BITWIDTH_24; 104 break; 105 case 32: 106 regval |= LPAIF_I2SCTL_BITWIDTH_32; 107 break; 108 default: 109 dev_err(dai->dev, "invalid bitwidth given: %d\n", bitwidth); 110 return -EINVAL; 111 } 112 113 if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) 114 mode = drvdata->mi2s_playback_sd_mode[dai->driver->id]; 115 else 116 mode = drvdata->mi2s_capture_sd_mode[dai->driver->id]; 117 118 if (!mode) { 119 dev_err(dai->dev, "no line is assigned\n"); 120 return -EINVAL; 121 } 122 123 switch (channels) { 124 case 1: 125 case 2: 126 switch (mode) { 127 case LPAIF_I2SCTL_MODE_QUAD01: 128 case LPAIF_I2SCTL_MODE_6CH: 129 case LPAIF_I2SCTL_MODE_8CH: 130 mode = LPAIF_I2SCTL_MODE_SD0; 131 break; 132 case LPAIF_I2SCTL_MODE_QUAD23: 133 mode = LPAIF_I2SCTL_MODE_SD2; 134 break; 135 } 136 137 break; 138 case 4: 139 if (mode < LPAIF_I2SCTL_MODE_QUAD01) { 140 dev_err(dai->dev, "cannot configure 4 channels with mode %d\n", 141 mode); 142 return -EINVAL; 143 } 144 145 switch (mode) { 146 case LPAIF_I2SCTL_MODE_6CH: 147 case LPAIF_I2SCTL_MODE_8CH: 148 mode = LPAIF_I2SCTL_MODE_QUAD01; 149 break; 150 } 151 break; 152 case 6: 153 if (mode < LPAIF_I2SCTL_MODE_6CH) { 154 dev_err(dai->dev, "cannot configure 6 channels with mode %d\n", 155 mode); 156 return -EINVAL; 157 } 158 159 switch (mode) { 160 case LPAIF_I2SCTL_MODE_8CH: 161 mode = LPAIF_I2SCTL_MODE_6CH; 162 break; 163 } 164 break; 165 case 8: 166 if (mode < LPAIF_I2SCTL_MODE_8CH) { 167 dev_err(dai->dev, "cannot configure 8 channels with mode %d\n", 168 mode); 169 return -EINVAL; 170 } 171 break; 172 default: 173 dev_err(dai->dev, "invalid channels given: %u\n", channels); 174 return -EINVAL; 175 } 176 177 if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { 178 regval |= LPAIF_I2SCTL_SPKMODE(mode); 179 180 if (channels >= 2) 181 regval |= LPAIF_I2SCTL_SPKMONO_STEREO; 182 else 183 regval |= LPAIF_I2SCTL_SPKMONO_MONO; 184 } else { 185 regval |= LPAIF_I2SCTL_MICMODE(mode); 186 187 if (channels >= 2) 188 regval |= LPAIF_I2SCTL_MICMONO_STEREO; 189 else 190 regval |= LPAIF_I2SCTL_MICMONO_MONO; 191 } 192 193 ret = regmap_write(drvdata->lpaif_map, 194 LPAIF_I2SCTL_REG(drvdata->variant, dai->driver->id), 195 regval); 196 if (ret) { 197 dev_err(dai->dev, "error writing to i2sctl reg: %d\n", ret); 198 return ret; 199 } 200 201 ret = clk_set_rate(drvdata->mi2s_bit_clk[dai->driver->id], 202 rate * bitwidth * 2); 203 if (ret) { 204 dev_err(dai->dev, "error setting mi2s bitclk to %u: %d\n", 205 rate * bitwidth * 2, ret); 206 return ret; 207 } 208 209 return 0; 210 } 211 212 static int lpass_cpu_daiops_hw_free(struct snd_pcm_substream *substream, 213 struct snd_soc_dai *dai) 214 { 215 struct lpass_data *drvdata = snd_soc_dai_get_drvdata(dai); 216 int ret; 217 218 ret = regmap_write(drvdata->lpaif_map, 219 LPAIF_I2SCTL_REG(drvdata->variant, dai->driver->id), 220 0); 221 if (ret) 222 dev_err(dai->dev, "error writing to i2sctl reg: %d\n", ret); 223 224 return ret; 225 } 226 227 static int lpass_cpu_daiops_prepare(struct snd_pcm_substream *substream, 228 struct snd_soc_dai *dai) 229 { 230 struct lpass_data *drvdata = snd_soc_dai_get_drvdata(dai); 231 int ret; 232 unsigned int val, mask; 233 234 if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { 235 val = LPAIF_I2SCTL_SPKEN_ENABLE; 236 mask = LPAIF_I2SCTL_SPKEN_MASK; 237 } else { 238 val = LPAIF_I2SCTL_MICEN_ENABLE; 239 mask = LPAIF_I2SCTL_MICEN_MASK; 240 } 241 242 ret = regmap_update_bits(drvdata->lpaif_map, 243 LPAIF_I2SCTL_REG(drvdata->variant, dai->driver->id), 244 mask, val); 245 if (ret) 246 dev_err(dai->dev, "error writing to i2sctl reg: %d\n", ret); 247 248 return ret; 249 } 250 251 static int lpass_cpu_daiops_trigger(struct snd_pcm_substream *substream, 252 int cmd, struct snd_soc_dai *dai) 253 { 254 struct lpass_data *drvdata = snd_soc_dai_get_drvdata(dai); 255 int ret = -EINVAL; 256 unsigned int val, mask; 257 258 switch (cmd) { 259 case SNDRV_PCM_TRIGGER_START: 260 case SNDRV_PCM_TRIGGER_RESUME: 261 case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: 262 if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { 263 val = LPAIF_I2SCTL_SPKEN_ENABLE; 264 mask = LPAIF_I2SCTL_SPKEN_MASK; 265 } else { 266 val = LPAIF_I2SCTL_MICEN_ENABLE; 267 mask = LPAIF_I2SCTL_MICEN_MASK; 268 } 269 270 ret = regmap_update_bits(drvdata->lpaif_map, 271 LPAIF_I2SCTL_REG(drvdata->variant, 272 dai->driver->id), 273 mask, val); 274 if (ret) 275 dev_err(dai->dev, "error writing to i2sctl reg: %d\n", 276 ret); 277 break; 278 case SNDRV_PCM_TRIGGER_STOP: 279 case SNDRV_PCM_TRIGGER_SUSPEND: 280 case SNDRV_PCM_TRIGGER_PAUSE_PUSH: 281 if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { 282 val = LPAIF_I2SCTL_SPKEN_DISABLE; 283 mask = LPAIF_I2SCTL_SPKEN_MASK; 284 } else { 285 val = LPAIF_I2SCTL_MICEN_DISABLE; 286 mask = LPAIF_I2SCTL_MICEN_MASK; 287 } 288 289 ret = regmap_update_bits(drvdata->lpaif_map, 290 LPAIF_I2SCTL_REG(drvdata->variant, 291 dai->driver->id), 292 mask, val); 293 if (ret) 294 dev_err(dai->dev, "error writing to i2sctl reg: %d\n", 295 ret); 296 break; 297 } 298 299 return ret; 300 } 301 302 const struct snd_soc_dai_ops asoc_qcom_lpass_cpu_dai_ops = { 303 .set_sysclk = lpass_cpu_daiops_set_sysclk, 304 .startup = lpass_cpu_daiops_startup, 305 .shutdown = lpass_cpu_daiops_shutdown, 306 .hw_params = lpass_cpu_daiops_hw_params, 307 .hw_free = lpass_cpu_daiops_hw_free, 308 .prepare = lpass_cpu_daiops_prepare, 309 .trigger = lpass_cpu_daiops_trigger, 310 }; 311 EXPORT_SYMBOL_GPL(asoc_qcom_lpass_cpu_dai_ops); 312 313 int asoc_qcom_lpass_cpu_dai_probe(struct snd_soc_dai *dai) 314 { 315 struct lpass_data *drvdata = snd_soc_dai_get_drvdata(dai); 316 int ret; 317 318 /* ensure audio hardware is disabled */ 319 ret = regmap_write(drvdata->lpaif_map, 320 LPAIF_I2SCTL_REG(drvdata->variant, dai->driver->id), 0); 321 if (ret) 322 dev_err(dai->dev, "error writing to i2sctl reg: %d\n", ret); 323 324 return ret; 325 } 326 EXPORT_SYMBOL_GPL(asoc_qcom_lpass_cpu_dai_probe); 327 328 static const struct snd_soc_component_driver lpass_cpu_comp_driver = { 329 .name = "lpass-cpu", 330 }; 331 332 static bool lpass_cpu_regmap_writeable(struct device *dev, unsigned int reg) 333 { 334 struct lpass_data *drvdata = dev_get_drvdata(dev); 335 struct lpass_variant *v = drvdata->variant; 336 int i; 337 338 for (i = 0; i < v->i2s_ports; ++i) 339 if (reg == LPAIF_I2SCTL_REG(v, i)) 340 return true; 341 342 for (i = 0; i < v->irq_ports; ++i) { 343 if (reg == LPAIF_IRQEN_REG(v, i)) 344 return true; 345 if (reg == LPAIF_IRQCLEAR_REG(v, i)) 346 return true; 347 } 348 349 for (i = 0; i < v->rdma_channels; ++i) { 350 if (reg == LPAIF_RDMACTL_REG(v, i)) 351 return true; 352 if (reg == LPAIF_RDMABASE_REG(v, i)) 353 return true; 354 if (reg == LPAIF_RDMABUFF_REG(v, i)) 355 return true; 356 if (reg == LPAIF_RDMAPER_REG(v, i)) 357 return true; 358 } 359 360 for (i = 0; i < v->wrdma_channels; ++i) { 361 if (reg == LPAIF_WRDMACTL_REG(v, i + v->wrdma_channel_start)) 362 return true; 363 if (reg == LPAIF_WRDMABASE_REG(v, i + v->wrdma_channel_start)) 364 return true; 365 if (reg == LPAIF_WRDMABUFF_REG(v, i + v->wrdma_channel_start)) 366 return true; 367 if (reg == LPAIF_WRDMAPER_REG(v, i + v->wrdma_channel_start)) 368 return true; 369 } 370 371 return false; 372 } 373 374 static bool lpass_cpu_regmap_readable(struct device *dev, unsigned int reg) 375 { 376 struct lpass_data *drvdata = dev_get_drvdata(dev); 377 struct lpass_variant *v = drvdata->variant; 378 int i; 379 380 for (i = 0; i < v->i2s_ports; ++i) 381 if (reg == LPAIF_I2SCTL_REG(v, i)) 382 return true; 383 384 for (i = 0; i < v->irq_ports; ++i) { 385 if (reg == LPAIF_IRQEN_REG(v, i)) 386 return true; 387 if (reg == LPAIF_IRQSTAT_REG(v, i)) 388 return true; 389 } 390 391 for (i = 0; i < v->rdma_channels; ++i) { 392 if (reg == LPAIF_RDMACTL_REG(v, i)) 393 return true; 394 if (reg == LPAIF_RDMABASE_REG(v, i)) 395 return true; 396 if (reg == LPAIF_RDMABUFF_REG(v, i)) 397 return true; 398 if (reg == LPAIF_RDMACURR_REG(v, i)) 399 return true; 400 if (reg == LPAIF_RDMAPER_REG(v, i)) 401 return true; 402 } 403 404 for (i = 0; i < v->wrdma_channels; ++i) { 405 if (reg == LPAIF_WRDMACTL_REG(v, i + v->wrdma_channel_start)) 406 return true; 407 if (reg == LPAIF_WRDMABASE_REG(v, i + v->wrdma_channel_start)) 408 return true; 409 if (reg == LPAIF_WRDMABUFF_REG(v, i + v->wrdma_channel_start)) 410 return true; 411 if (reg == LPAIF_WRDMACURR_REG(v, i + v->wrdma_channel_start)) 412 return true; 413 if (reg == LPAIF_WRDMAPER_REG(v, i + v->wrdma_channel_start)) 414 return true; 415 } 416 417 return false; 418 } 419 420 static bool lpass_cpu_regmap_volatile(struct device *dev, unsigned int reg) 421 { 422 struct lpass_data *drvdata = dev_get_drvdata(dev); 423 struct lpass_variant *v = drvdata->variant; 424 int i; 425 426 for (i = 0; i < v->irq_ports; ++i) 427 if (reg == LPAIF_IRQSTAT_REG(v, i)) 428 return true; 429 430 for (i = 0; i < v->rdma_channels; ++i) 431 if (reg == LPAIF_RDMACURR_REG(v, i)) 432 return true; 433 434 for (i = 0; i < v->wrdma_channels; ++i) 435 if (reg == LPAIF_WRDMACURR_REG(v, i + v->wrdma_channel_start)) 436 return true; 437 438 return false; 439 } 440 441 static struct regmap_config lpass_cpu_regmap_config = { 442 .reg_bits = 32, 443 .reg_stride = 4, 444 .val_bits = 32, 445 .writeable_reg = lpass_cpu_regmap_writeable, 446 .readable_reg = lpass_cpu_regmap_readable, 447 .volatile_reg = lpass_cpu_regmap_volatile, 448 .cache_type = REGCACHE_FLAT, 449 }; 450 451 static unsigned int of_lpass_cpu_parse_sd_lines(struct device *dev, 452 struct device_node *node, 453 const char *name) 454 { 455 unsigned int lines[LPASS_CPU_MAX_MI2S_LINES]; 456 unsigned int sd_line_mask = 0; 457 int num_lines, i; 458 459 num_lines = of_property_read_variable_u32_array(node, name, lines, 0, 460 LPASS_CPU_MAX_MI2S_LINES); 461 if (num_lines < 0) 462 return LPAIF_I2SCTL_MODE_NONE; 463 464 for (i = 0; i < num_lines; i++) 465 sd_line_mask |= BIT(lines[i]); 466 467 switch (sd_line_mask) { 468 case LPASS_CPU_I2S_SD0_MASK: 469 return LPAIF_I2SCTL_MODE_SD0; 470 case LPASS_CPU_I2S_SD1_MASK: 471 return LPAIF_I2SCTL_MODE_SD1; 472 case LPASS_CPU_I2S_SD2_MASK: 473 return LPAIF_I2SCTL_MODE_SD2; 474 case LPASS_CPU_I2S_SD3_MASK: 475 return LPAIF_I2SCTL_MODE_SD3; 476 case LPASS_CPU_I2S_SD0_1_MASK: 477 return LPAIF_I2SCTL_MODE_QUAD01; 478 case LPASS_CPU_I2S_SD2_3_MASK: 479 return LPAIF_I2SCTL_MODE_QUAD23; 480 case LPASS_CPU_I2S_SD0_1_2_MASK: 481 return LPAIF_I2SCTL_MODE_6CH; 482 case LPASS_CPU_I2S_SD0_1_2_3_MASK: 483 return LPAIF_I2SCTL_MODE_8CH; 484 default: 485 dev_err(dev, "Unsupported SD line mask: %#x\n", sd_line_mask); 486 return LPAIF_I2SCTL_MODE_NONE; 487 } 488 } 489 490 static void of_lpass_cpu_parse_dai_data(struct device *dev, 491 struct lpass_data *data) 492 { 493 struct device_node *node; 494 int ret, id; 495 496 /* Allow all channels by default for backwards compatibility */ 497 for (id = 0; id < data->variant->num_dai; id++) { 498 data->mi2s_playback_sd_mode[id] = LPAIF_I2SCTL_MODE_8CH; 499 data->mi2s_capture_sd_mode[id] = LPAIF_I2SCTL_MODE_8CH; 500 } 501 502 for_each_child_of_node(dev->of_node, node) { 503 ret = of_property_read_u32(node, "reg", &id); 504 if (ret || id < 0 || id >= data->variant->num_dai) { 505 dev_err(dev, "valid dai id not found: %d\n", ret); 506 continue; 507 } 508 509 data->mi2s_playback_sd_mode[id] = 510 of_lpass_cpu_parse_sd_lines(dev, node, 511 "qcom,playback-sd-lines"); 512 data->mi2s_capture_sd_mode[id] = 513 of_lpass_cpu_parse_sd_lines(dev, node, 514 "qcom,capture-sd-lines"); 515 } 516 } 517 518 int asoc_qcom_lpass_cpu_platform_probe(struct platform_device *pdev) 519 { 520 struct lpass_data *drvdata; 521 struct device_node *dsp_of_node; 522 struct resource *res; 523 struct lpass_variant *variant; 524 struct device *dev = &pdev->dev; 525 const struct of_device_id *match; 526 int ret, i, dai_id; 527 528 dsp_of_node = of_parse_phandle(pdev->dev.of_node, "qcom,adsp", 0); 529 if (dsp_of_node) { 530 dev_err(dev, "DSP exists and holds audio resources\n"); 531 return -EBUSY; 532 } 533 534 drvdata = devm_kzalloc(dev, sizeof(struct lpass_data), GFP_KERNEL); 535 if (!drvdata) 536 return -ENOMEM; 537 platform_set_drvdata(pdev, drvdata); 538 539 match = of_match_device(dev->driver->of_match_table, dev); 540 if (!match || !match->data) 541 return -EINVAL; 542 543 drvdata->variant = (struct lpass_variant *)match->data; 544 variant = drvdata->variant; 545 546 of_lpass_cpu_parse_dai_data(dev, drvdata); 547 548 res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "lpass-lpaif"); 549 550 drvdata->lpaif = devm_ioremap_resource(dev, res); 551 if (IS_ERR((void const __force *)drvdata->lpaif)) { 552 dev_err(dev, "error mapping reg resource: %ld\n", 553 PTR_ERR((void const __force *)drvdata->lpaif)); 554 return PTR_ERR((void const __force *)drvdata->lpaif); 555 } 556 557 lpass_cpu_regmap_config.max_register = LPAIF_WRDMAPER_REG(variant, 558 variant->wrdma_channels + 559 variant->wrdma_channel_start); 560 561 drvdata->lpaif_map = devm_regmap_init_mmio(dev, drvdata->lpaif, 562 &lpass_cpu_regmap_config); 563 if (IS_ERR(drvdata->lpaif_map)) { 564 dev_err(dev, "error initializing regmap: %ld\n", 565 PTR_ERR(drvdata->lpaif_map)); 566 return PTR_ERR(drvdata->lpaif_map); 567 } 568 569 if (variant->init) 570 variant->init(pdev); 571 572 for (i = 0; i < variant->num_dai; i++) { 573 dai_id = variant->dai_driver[i].id; 574 drvdata->mi2s_osr_clk[dai_id] = devm_clk_get(dev, 575 variant->dai_osr_clk_names[i]); 576 if (IS_ERR(drvdata->mi2s_osr_clk[dai_id])) { 577 dev_warn(dev, 578 "%s() error getting optional %s: %ld\n", 579 __func__, 580 variant->dai_osr_clk_names[i], 581 PTR_ERR(drvdata->mi2s_osr_clk[dai_id])); 582 583 drvdata->mi2s_osr_clk[dai_id] = NULL; 584 } 585 586 drvdata->mi2s_bit_clk[dai_id] = devm_clk_get(dev, 587 variant->dai_bit_clk_names[i]); 588 if (IS_ERR(drvdata->mi2s_bit_clk[dai_id])) { 589 dev_err(dev, 590 "error getting %s: %ld\n", 591 variant->dai_bit_clk_names[i], 592 PTR_ERR(drvdata->mi2s_bit_clk[dai_id])); 593 return PTR_ERR(drvdata->mi2s_bit_clk[dai_id]); 594 } 595 } 596 597 drvdata->ahbix_clk = devm_clk_get(dev, "ahbix-clk"); 598 if (IS_ERR(drvdata->ahbix_clk)) { 599 dev_err(dev, "error getting ahbix-clk: %ld\n", 600 PTR_ERR(drvdata->ahbix_clk)); 601 return PTR_ERR(drvdata->ahbix_clk); 602 } 603 604 ret = clk_set_rate(drvdata->ahbix_clk, LPASS_AHBIX_CLOCK_FREQUENCY); 605 if (ret) { 606 dev_err(dev, "error setting rate on ahbix_clk: %d\n", ret); 607 return ret; 608 } 609 dev_dbg(dev, "set ahbix_clk rate to %lu\n", 610 clk_get_rate(drvdata->ahbix_clk)); 611 612 ret = clk_prepare_enable(drvdata->ahbix_clk); 613 if (ret) { 614 dev_err(dev, "error enabling ahbix_clk: %d\n", ret); 615 return ret; 616 } 617 618 ret = devm_snd_soc_register_component(dev, 619 &lpass_cpu_comp_driver, 620 variant->dai_driver, 621 variant->num_dai); 622 if (ret) { 623 dev_err(dev, "error registering cpu driver: %d\n", ret); 624 goto err_clk; 625 } 626 627 ret = asoc_qcom_lpass_platform_register(pdev); 628 if (ret) { 629 dev_err(dev, "error registering platform driver: %d\n", ret); 630 goto err_clk; 631 } 632 633 return 0; 634 635 err_clk: 636 clk_disable_unprepare(drvdata->ahbix_clk); 637 return ret; 638 } 639 EXPORT_SYMBOL_GPL(asoc_qcom_lpass_cpu_platform_probe); 640 641 int asoc_qcom_lpass_cpu_platform_remove(struct platform_device *pdev) 642 { 643 struct lpass_data *drvdata = platform_get_drvdata(pdev); 644 645 if (drvdata->variant->exit) 646 drvdata->variant->exit(pdev); 647 648 clk_disable_unprepare(drvdata->ahbix_clk); 649 650 return 0; 651 } 652 EXPORT_SYMBOL_GPL(asoc_qcom_lpass_cpu_platform_remove); 653 654 MODULE_DESCRIPTION("QTi LPASS CPU Driver"); 655 MODULE_LICENSE("GPL v2"); 656