linux/sound/soc/qcom/lpass-cpu.c
<<
>>
Prefs
   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
  32static 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
  46static 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
  68static 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
  78static 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
 212static 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
 227static 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
 251static 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
 302const 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};
 311EXPORT_SYMBOL_GPL(asoc_qcom_lpass_cpu_dai_ops);
 312
 313int 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}
 326EXPORT_SYMBOL_GPL(asoc_qcom_lpass_cpu_dai_probe);
 327
 328static const struct snd_soc_component_driver lpass_cpu_comp_driver = {
 329        .name = "lpass-cpu",
 330};
 331
 332static 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
 374static 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
 420static 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
 441static 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
 451static 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
 490static 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
 518int 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
 635err_clk:
 636        clk_disable_unprepare(drvdata->ahbix_clk);
 637        return ret;
 638}
 639EXPORT_SYMBOL_GPL(asoc_qcom_lpass_cpu_platform_probe);
 640
 641int 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}
 652EXPORT_SYMBOL_GPL(asoc_qcom_lpass_cpu_platform_remove);
 653
 654MODULE_DESCRIPTION("QTi LPASS CPU Driver");
 655MODULE_LICENSE("GPL v2");
 656