blob: 96cb4950b2fd9779b8299b0a222b76c524bd1e30 [file] [log] [blame]
Kenneth Westfield80beab82015-03-03 16:21:54 -08001/*
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>
Kenneth Westfield80beab82015-03-03 16:21:54 -080017#include <linux/kernel.h>
Kenneth Westfield80beab82015-03-03 16:21:54 -080018#include <linux/module.h>
19#include <linux/of.h>
Srinivas Kandagatla9bae4882015-05-16 13:32:17 +010020#include <linux/of_device.h>
Kenneth Westfield80beab82015-03-03 16:21:54 -080021#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>
Srinivas Kandagatla9bae4882015-05-16 13:32:17 +010027#include "lpass-lpaif-reg.h"
Kenneth Westfield80beab82015-03-03 16:21:54 -080028#include "lpass.h"
29
30static 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
Srinivas Kandagatla9a127cf2015-05-21 22:52:49 +010036 ret = clk_set_rate(drvdata->mi2s_osr_clk[dai->driver->id], freq);
Kenneth Westfield80beab82015-03-03 16:21:54 -080037 if (ret)
38 dev_err(dai->dev, "%s() error setting mi2s osrclk to %u: %d\n",
39 __func__, freq, ret);
40
41 return ret;
42}
43
44static int lpass_cpu_daiops_startup(struct snd_pcm_substream *substream,
45 struct snd_soc_dai *dai)
46{
47 struct lpass_data *drvdata = snd_soc_dai_get_drvdata(dai);
48 int ret;
49
Srinivas Kandagatla9a127cf2015-05-21 22:52:49 +010050 ret = clk_prepare_enable(drvdata->mi2s_osr_clk[dai->diver->id]);
Kenneth Westfield80beab82015-03-03 16:21:54 -080051 if (ret) {
52 dev_err(dai->dev, "%s() error in enabling mi2s osr clk: %d\n",
53 __func__, ret);
54 return ret;
55 }
56
Srinivas Kandagatla9a127cf2015-05-21 22:52:49 +010057 ret = clk_prepare_enable(drvdata->mi2s_bit_clk[dai->driver->id]);
Kenneth Westfield80beab82015-03-03 16:21:54 -080058 if (ret) {
59 dev_err(dai->dev, "%s() error in enabling mi2s bit clk: %d\n",
60 __func__, ret);
Srinivas Kandagatla9a127cf2015-05-21 22:52:49 +010061 clk_disable_unprepare(drvdata->mi2s_osr_clk[dai->driver->id]);
Kenneth Westfield80beab82015-03-03 16:21:54 -080062 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
Srinivas Kandagatla9a127cf2015-05-21 22:52:49 +010073 clk_disable_unprepare(drvdata->mi2s_bit_clk[dai->driver->id]);
74 clk_disable_unprepare(drvdata->mi2s_osr_clk[dai->driver->id]);
Kenneth Westfield80beab82015-03-03 16:21:54 -080075}
76
77static int lpass_cpu_daiops_hw_params(struct snd_pcm_substream *substream,
78 struct snd_pcm_hw_params *params, struct snd_soc_dai *dai)
79{
80 struct lpass_data *drvdata = snd_soc_dai_get_drvdata(dai);
81 snd_pcm_format_t format = params_format(params);
82 unsigned int channels = params_channels(params);
83 unsigned int rate = params_rate(params);
84 unsigned int regval;
85 int bitwidth, ret;
86
87 bitwidth = snd_pcm_format_width(format);
88 if (bitwidth < 0) {
89 dev_err(dai->dev, "%s() invalid bit width given: %d\n",
90 __func__, bitwidth);
91 return bitwidth;
92 }
93
94 regval = LPAIF_I2SCTL_LOOPBACK_DISABLE |
95 LPAIF_I2SCTL_WSSRC_INTERNAL;
96
97 switch (bitwidth) {
98 case 16:
99 regval |= LPAIF_I2SCTL_BITWIDTH_16;
100 break;
101 case 24:
102 regval |= LPAIF_I2SCTL_BITWIDTH_24;
103 break;
104 case 32:
105 regval |= LPAIF_I2SCTL_BITWIDTH_32;
106 break;
107 default:
108 dev_err(dai->dev, "%s() invalid bitwidth given: %d\n",
109 __func__, bitwidth);
110 return -EINVAL;
111 }
112
113 switch (channels) {
114 case 1:
115 regval |= LPAIF_I2SCTL_SPKMODE_SD0;
116 regval |= LPAIF_I2SCTL_SPKMONO_MONO;
117 break;
118 case 2:
119 regval |= LPAIF_I2SCTL_SPKMODE_SD0;
120 regval |= LPAIF_I2SCTL_SPKMONO_STEREO;
121 break;
122 case 4:
123 regval |= LPAIF_I2SCTL_SPKMODE_QUAD01;
124 regval |= LPAIF_I2SCTL_SPKMONO_STEREO;
125 break;
126 case 6:
127 regval |= LPAIF_I2SCTL_SPKMODE_6CH;
128 regval |= LPAIF_I2SCTL_SPKMONO_STEREO;
129 break;
130 case 8:
131 regval |= LPAIF_I2SCTL_SPKMODE_8CH;
132 regval |= LPAIF_I2SCTL_SPKMONO_STEREO;
133 break;
134 default:
135 dev_err(dai->dev, "%s() invalid channels given: %u\n",
136 __func__, channels);
137 return -EINVAL;
138 }
139
140 ret = regmap_write(drvdata->lpaif_map,
Srinivas Kandagatla0ae9fd32015-05-16 13:32:25 +0100141 LPAIF_I2SCTL_REG(drvdata->variant, dai->driver->id),
Srinivas Kandagatla9bae4882015-05-16 13:32:17 +0100142 regval);
Kenneth Westfield80beab82015-03-03 16:21:54 -0800143 if (ret) {
144 dev_err(dai->dev, "%s() error writing to i2sctl reg: %d\n",
145 __func__, ret);
146 return ret;
147 }
148
Srinivas Kandagatla9a127cf2015-05-21 22:52:49 +0100149 ret = clk_set_rate(drvdata->mi2s_bit_clk[dai->driver->id],
150 rate * bitwidth * 2);
Kenneth Westfield80beab82015-03-03 16:21:54 -0800151 if (ret) {
152 dev_err(dai->dev, "%s() error setting mi2s bitclk to %u: %d\n",
153 __func__, rate * bitwidth * 2, ret);
154 return ret;
155 }
156
157 return 0;
158}
159
160static int lpass_cpu_daiops_hw_free(struct snd_pcm_substream *substream,
161 struct snd_soc_dai *dai)
162{
163 struct lpass_data *drvdata = snd_soc_dai_get_drvdata(dai);
164 int ret;
165
166 ret = regmap_write(drvdata->lpaif_map,
Srinivas Kandagatla0ae9fd32015-05-16 13:32:25 +0100167 LPAIF_I2SCTL_REG(drvdata->variant, dai->driver->id),
168 0);
Kenneth Westfield80beab82015-03-03 16:21:54 -0800169 if (ret)
170 dev_err(dai->dev, "%s() error writing to i2sctl reg: %d\n",
171 __func__, ret);
172
173 return ret;
174}
175
176static int lpass_cpu_daiops_prepare(struct snd_pcm_substream *substream,
177 struct snd_soc_dai *dai)
178{
179 struct lpass_data *drvdata = snd_soc_dai_get_drvdata(dai);
180 int ret;
181
182 ret = regmap_update_bits(drvdata->lpaif_map,
Srinivas Kandagatla0ae9fd32015-05-16 13:32:25 +0100183 LPAIF_I2SCTL_REG(drvdata->variant, dai->driver->id),
Kenneth Westfield80beab82015-03-03 16:21:54 -0800184 LPAIF_I2SCTL_SPKEN_MASK, LPAIF_I2SCTL_SPKEN_ENABLE);
185 if (ret)
186 dev_err(dai->dev, "%s() error writing to i2sctl reg: %d\n",
187 __func__, ret);
188
189 return ret;
190}
191
192static int lpass_cpu_daiops_trigger(struct snd_pcm_substream *substream,
193 int cmd, struct snd_soc_dai *dai)
194{
195 struct lpass_data *drvdata = snd_soc_dai_get_drvdata(dai);
196 int ret;
197
198 switch (cmd) {
199 case SNDRV_PCM_TRIGGER_START:
200 case SNDRV_PCM_TRIGGER_RESUME:
201 case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
202 ret = regmap_update_bits(drvdata->lpaif_map,
Srinivas Kandagatla9bae4882015-05-16 13:32:17 +0100203 LPAIF_I2SCTL_REG(drvdata->variant,
Srinivas Kandagatla0ae9fd32015-05-16 13:32:25 +0100204 dai->driver->id),
Kenneth Westfield80beab82015-03-03 16:21:54 -0800205 LPAIF_I2SCTL_SPKEN_MASK,
206 LPAIF_I2SCTL_SPKEN_ENABLE);
207 if (ret)
208 dev_err(dai->dev, "%s() error writing to i2sctl reg: %d\n",
209 __func__, ret);
210 break;
211 case SNDRV_PCM_TRIGGER_STOP:
212 case SNDRV_PCM_TRIGGER_SUSPEND:
213 case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
214 ret = regmap_update_bits(drvdata->lpaif_map,
Srinivas Kandagatla9bae4882015-05-16 13:32:17 +0100215 LPAIF_I2SCTL_REG(drvdata->variant,
Srinivas Kandagatla0ae9fd32015-05-16 13:32:25 +0100216 dai->driver->id),
Kenneth Westfield80beab82015-03-03 16:21:54 -0800217 LPAIF_I2SCTL_SPKEN_MASK,
218 LPAIF_I2SCTL_SPKEN_DISABLE);
219 if (ret)
220 dev_err(dai->dev, "%s() error writing to i2sctl reg: %d\n",
221 __func__, ret);
222 break;
223 }
224
225 return ret;
226}
227
Srinivas Kandagatla9bae4882015-05-16 13:32:17 +0100228struct snd_soc_dai_ops asoc_qcom_lpass_cpu_dai_ops = {
Kenneth Westfield80beab82015-03-03 16:21:54 -0800229 .set_sysclk = lpass_cpu_daiops_set_sysclk,
230 .startup = lpass_cpu_daiops_startup,
231 .shutdown = lpass_cpu_daiops_shutdown,
232 .hw_params = lpass_cpu_daiops_hw_params,
233 .hw_free = lpass_cpu_daiops_hw_free,
234 .prepare = lpass_cpu_daiops_prepare,
235 .trigger = lpass_cpu_daiops_trigger,
236};
Srinivas Kandagatla9bae4882015-05-16 13:32:17 +0100237EXPORT_SYMBOL_GPL(asoc_qcom_lpass_cpu_dai_ops);
Kenneth Westfield80beab82015-03-03 16:21:54 -0800238
Srinivas Kandagatla9bae4882015-05-16 13:32:17 +0100239int asoc_qcom_lpass_cpu_dai_probe(struct snd_soc_dai *dai)
Kenneth Westfield80beab82015-03-03 16:21:54 -0800240{
241 struct lpass_data *drvdata = snd_soc_dai_get_drvdata(dai);
242 int ret;
243
244 /* ensure audio hardware is disabled */
245 ret = regmap_write(drvdata->lpaif_map,
Srinivas Kandagatla0ae9fd32015-05-16 13:32:25 +0100246 LPAIF_I2SCTL_REG(drvdata->variant, dai->driver->id), 0);
Kenneth Westfield80beab82015-03-03 16:21:54 -0800247 if (ret)
248 dev_err(dai->dev, "%s() error writing to i2sctl reg: %d\n",
249 __func__, ret);
250
251 return ret;
252}
Srinivas Kandagatla9bae4882015-05-16 13:32:17 +0100253EXPORT_SYMBOL_GPL(asoc_qcom_lpass_cpu_dai_probe);
Kenneth Westfield80beab82015-03-03 16:21:54 -0800254
255static const struct snd_soc_component_driver lpass_cpu_comp_driver = {
256 .name = "lpass-cpu",
257};
258
259static bool lpass_cpu_regmap_writeable(struct device *dev, unsigned int reg)
260{
Srinivas Kandagatla9bae4882015-05-16 13:32:17 +0100261 struct lpass_data *drvdata = dev_get_drvdata(dev);
262 struct lpass_variant *v = drvdata->variant;
Kenneth Westfield80beab82015-03-03 16:21:54 -0800263 int i;
264
Srinivas Kandagatla9bae4882015-05-16 13:32:17 +0100265 for (i = 0; i < v->i2s_ports; ++i)
266 if (reg == LPAIF_I2SCTL_REG(v, i))
Kenneth Westfield80beab82015-03-03 16:21:54 -0800267 return true;
268
Srinivas Kandagatla9bae4882015-05-16 13:32:17 +0100269 for (i = 0; i < v->irq_ports; ++i) {
270 if (reg == LPAIF_IRQEN_REG(v, i))
Kenneth Westfield80beab82015-03-03 16:21:54 -0800271 return true;
Srinivas Kandagatla9bae4882015-05-16 13:32:17 +0100272 if (reg == LPAIF_IRQCLEAR_REG(v, i))
Kenneth Westfield80beab82015-03-03 16:21:54 -0800273 return true;
274 }
275
Srinivas Kandagatla9bae4882015-05-16 13:32:17 +0100276 for (i = 0; i < v->rdma_channels; ++i) {
277 if (reg == LPAIF_RDMACTL_REG(v, i))
Kenneth Westfield80beab82015-03-03 16:21:54 -0800278 return true;
Srinivas Kandagatla9bae4882015-05-16 13:32:17 +0100279 if (reg == LPAIF_RDMABASE_REG(v, i))
Kenneth Westfield80beab82015-03-03 16:21:54 -0800280 return true;
Srinivas Kandagatla9bae4882015-05-16 13:32:17 +0100281 if (reg == LPAIF_RDMABUFF_REG(v, i))
Kenneth Westfield80beab82015-03-03 16:21:54 -0800282 return true;
Srinivas Kandagatla9bae4882015-05-16 13:32:17 +0100283 if (reg == LPAIF_RDMAPER_REG(v, i))
Kenneth Westfield80beab82015-03-03 16:21:54 -0800284 return true;
285 }
286
287 return false;
288}
289
290static bool lpass_cpu_regmap_readable(struct device *dev, unsigned int reg)
291{
Srinivas Kandagatla9bae4882015-05-16 13:32:17 +0100292 struct lpass_data *drvdata = dev_get_drvdata(dev);
293 struct lpass_variant *v = drvdata->variant;
Kenneth Westfield80beab82015-03-03 16:21:54 -0800294 int i;
295
Srinivas Kandagatla9bae4882015-05-16 13:32:17 +0100296 for (i = 0; i < v->i2s_ports; ++i)
297 if (reg == LPAIF_I2SCTL_REG(v, i))
Kenneth Westfield80beab82015-03-03 16:21:54 -0800298 return true;
299
Srinivas Kandagatla9bae4882015-05-16 13:32:17 +0100300 for (i = 0; i < v->irq_ports; ++i) {
301 if (reg == LPAIF_IRQEN_REG(v, i))
Kenneth Westfield80beab82015-03-03 16:21:54 -0800302 return true;
Srinivas Kandagatla9bae4882015-05-16 13:32:17 +0100303 if (reg == LPAIF_IRQSTAT_REG(v, i))
Kenneth Westfield80beab82015-03-03 16:21:54 -0800304 return true;
305 }
306
Srinivas Kandagatla9bae4882015-05-16 13:32:17 +0100307 for (i = 0; i < v->rdma_channels; ++i) {
308 if (reg == LPAIF_RDMACTL_REG(v, i))
Kenneth Westfield80beab82015-03-03 16:21:54 -0800309 return true;
Srinivas Kandagatla9bae4882015-05-16 13:32:17 +0100310 if (reg == LPAIF_RDMABASE_REG(v, i))
Kenneth Westfield80beab82015-03-03 16:21:54 -0800311 return true;
Srinivas Kandagatla9bae4882015-05-16 13:32:17 +0100312 if (reg == LPAIF_RDMABUFF_REG(v, i))
Kenneth Westfield80beab82015-03-03 16:21:54 -0800313 return true;
Srinivas Kandagatla9bae4882015-05-16 13:32:17 +0100314 if (reg == LPAIF_RDMACURR_REG(v, i))
Kenneth Westfield80beab82015-03-03 16:21:54 -0800315 return true;
Srinivas Kandagatla9bae4882015-05-16 13:32:17 +0100316 if (reg == LPAIF_RDMAPER_REG(v, i))
Kenneth Westfield80beab82015-03-03 16:21:54 -0800317 return true;
318 }
319
320 return false;
321}
322
323static bool lpass_cpu_regmap_volatile(struct device *dev, unsigned int reg)
324{
Srinivas Kandagatla9bae4882015-05-16 13:32:17 +0100325 struct lpass_data *drvdata = dev_get_drvdata(dev);
326 struct lpass_variant *v = drvdata->variant;
Kenneth Westfield80beab82015-03-03 16:21:54 -0800327 int i;
328
Srinivas Kandagatla9bae4882015-05-16 13:32:17 +0100329 for (i = 0; i < v->irq_ports; ++i)
330 if (reg == LPAIF_IRQSTAT_REG(v, i))
Kenneth Westfield80beab82015-03-03 16:21:54 -0800331 return true;
332
Srinivas Kandagatla9bae4882015-05-16 13:32:17 +0100333 for (i = 0; i < v->rdma_channels; ++i)
334 if (reg == LPAIF_RDMACURR_REG(v, i))
Kenneth Westfield80beab82015-03-03 16:21:54 -0800335 return true;
336
337 return false;
338}
339
Srinivas Kandagatla9bae4882015-05-16 13:32:17 +0100340static struct regmap_config lpass_cpu_regmap_config = {
Kenneth Westfield80beab82015-03-03 16:21:54 -0800341 .reg_bits = 32,
342 .reg_stride = 4,
343 .val_bits = 32,
Kenneth Westfield80beab82015-03-03 16:21:54 -0800344 .writeable_reg = lpass_cpu_regmap_writeable,
345 .readable_reg = lpass_cpu_regmap_readable,
346 .volatile_reg = lpass_cpu_regmap_volatile,
347 .cache_type = REGCACHE_FLAT,
348};
349
Srinivas Kandagatla9bae4882015-05-16 13:32:17 +0100350int asoc_qcom_lpass_cpu_platform_probe(struct platform_device *pdev)
Kenneth Westfield80beab82015-03-03 16:21:54 -0800351{
352 struct lpass_data *drvdata;
Kenneth Westfield8ebe1482015-03-13 00:54:17 -0700353 struct device_node *dsp_of_node;
Kenneth Westfield80beab82015-03-03 16:21:54 -0800354 struct resource *res;
Srinivas Kandagatla9bae4882015-05-16 13:32:17 +0100355 struct lpass_variant *variant;
356 struct device *dev = &pdev->dev;
357 const struct of_device_id *match;
Srinivas Kandagatla9a127cf2015-05-21 22:52:49 +0100358 char clk_name[16];
359 int ret, i, dai_id;
Kenneth Westfield80beab82015-03-03 16:21:54 -0800360
Kenneth Westfield8ebe1482015-03-13 00:54:17 -0700361 dsp_of_node = of_parse_phandle(pdev->dev.of_node, "qcom,adsp", 0);
362 if (dsp_of_node) {
363 dev_err(&pdev->dev, "%s() DSP exists and holds audio resources\n",
364 __func__);
365 return -EBUSY;
366 }
367
Kenneth Westfield80beab82015-03-03 16:21:54 -0800368 drvdata = devm_kzalloc(&pdev->dev, sizeof(struct lpass_data),
369 GFP_KERNEL);
370 if (!drvdata)
371 return -ENOMEM;
372 platform_set_drvdata(pdev, drvdata);
373
Srinivas Kandagatla9bae4882015-05-16 13:32:17 +0100374 match = of_match_device(dev->driver->of_match_table, dev);
375 if (!match || !match->data)
376 return -EINVAL;
377
378 drvdata->variant = (struct lpass_variant *)match->data;
379 variant = drvdata->variant;
380
Kenneth Westfield80beab82015-03-03 16:21:54 -0800381 res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "lpass-lpaif");
Kenneth Westfield80beab82015-03-03 16:21:54 -0800382
383 drvdata->lpaif = devm_ioremap_resource(&pdev->dev, res);
384 if (IS_ERR((void const __force *)drvdata->lpaif)) {
385 dev_err(&pdev->dev, "%s() error mapping reg resource: %ld\n",
386 __func__,
387 PTR_ERR((void const __force *)drvdata->lpaif));
388 return PTR_ERR((void const __force *)drvdata->lpaif);
389 }
390
Srinivas Kandagatla9bae4882015-05-16 13:32:17 +0100391 lpass_cpu_regmap_config.max_register = LPAIF_RDMAPER_REG(variant,
392 variant->rdma_channels);
393
Kenneth Westfield80beab82015-03-03 16:21:54 -0800394 drvdata->lpaif_map = devm_regmap_init_mmio(&pdev->dev, drvdata->lpaif,
395 &lpass_cpu_regmap_config);
396 if (IS_ERR(drvdata->lpaif_map)) {
397 dev_err(&pdev->dev, "%s() error initializing regmap: %ld\n",
398 __func__, PTR_ERR(drvdata->lpaif_map));
399 return PTR_ERR(drvdata->lpaif_map);
400 }
401
Srinivas Kandagatla9bae4882015-05-16 13:32:17 +0100402 if (variant->init)
403 variant->init(pdev);
404
Srinivas Kandagatla9a127cf2015-05-21 22:52:49 +0100405 for (i = 0; i < variant->num_dai; i++) {
406 dai_id = variant->dai_driver[i].id;
407 if (variant->num_dai > 1)
408 sprintf(clk_name, "mi2s-osr-clk%d", i);
409 else
410 sprintf(clk_name, "mi2s-osr-clk");
Kenneth Westfield80beab82015-03-03 16:21:54 -0800411
Srinivas Kandagatla9a127cf2015-05-21 22:52:49 +0100412 drvdata->mi2s_osr_clk[dai_id] = devm_clk_get(&pdev->dev,
413 clk_name);
414 if (IS_ERR(drvdata->mi2s_osr_clk[dai_id])) {
415 dev_err(&pdev->dev,
416 "%s() error getting mi2s-osr-clk: %ld\n",
417 __func__,
418 PTR_ERR(drvdata->mi2s_osr_clk[dai_id]));
419 return PTR_ERR(drvdata->mi2s_osr_clk[dai_id]);
420 }
421
422 if (variant->num_dai > 1)
423 sprintf(clk_name, "mi2s-bit-clk%d", i);
424 else
425 sprintf(clk_name, "mi2s-bit-clk");
426
427 drvdata->mi2s_bit_clk[dai_id] = devm_clk_get(&pdev->dev,
428 clk_name);
429 if (IS_ERR(drvdata->mi2s_bit_clk[dai_id])) {
430 dev_err(&pdev->dev,
431 "%s() error getting mi2s-bit-clk: %ld\n",
432 __func__, PTR_ERR(drvdata->mi2s_bit_clk[i]));
433 return PTR_ERR(drvdata->mi2s_bit_clk[dai_id]);
434 }
Kenneth Westfield80beab82015-03-03 16:21:54 -0800435 }
436
437 drvdata->ahbix_clk = devm_clk_get(&pdev->dev, "ahbix-clk");
438 if (IS_ERR(drvdata->ahbix_clk)) {
439 dev_err(&pdev->dev, "%s() error getting ahbix-clk: %ld\n",
440 __func__, PTR_ERR(drvdata->ahbix_clk));
441 return PTR_ERR(drvdata->ahbix_clk);
442 }
443
444 ret = clk_set_rate(drvdata->ahbix_clk, LPASS_AHBIX_CLOCK_FREQUENCY);
445 if (ret) {
446 dev_err(&pdev->dev, "%s() error setting rate on ahbix_clk: %d\n",
447 __func__, ret);
448 return ret;
449 }
450 dev_dbg(&pdev->dev, "%s() set ahbix_clk rate to %lu\n", __func__,
451 clk_get_rate(drvdata->ahbix_clk));
452
453 ret = clk_prepare_enable(drvdata->ahbix_clk);
454 if (ret) {
455 dev_err(&pdev->dev, "%s() error enabling ahbix_clk: %d\n",
456 __func__, ret);
457 return ret;
458 }
459
460 ret = devm_snd_soc_register_component(&pdev->dev,
Srinivas Kandagatla9bae4882015-05-16 13:32:17 +0100461 &lpass_cpu_comp_driver,
462 variant->dai_driver,
463 variant->num_dai);
Kenneth Westfield80beab82015-03-03 16:21:54 -0800464 if (ret) {
465 dev_err(&pdev->dev, "%s() error registering cpu driver: %d\n",
466 __func__, ret);
467 goto err_clk;
468 }
469
470 ret = asoc_qcom_lpass_platform_register(pdev);
471 if (ret) {
472 dev_err(&pdev->dev, "%s() error registering platform driver: %d\n",
473 __func__, ret);
474 goto err_clk;
475 }
476
477 return 0;
478
479err_clk:
480 clk_disable_unprepare(drvdata->ahbix_clk);
481 return ret;
482}
Srinivas Kandagatla9bae4882015-05-16 13:32:17 +0100483EXPORT_SYMBOL_GPL(asoc_qcom_lpass_cpu_platform_probe);
Kenneth Westfield80beab82015-03-03 16:21:54 -0800484
Srinivas Kandagatla9bae4882015-05-16 13:32:17 +0100485int asoc_qcom_lpass_cpu_platform_remove(struct platform_device *pdev)
Kenneth Westfield80beab82015-03-03 16:21:54 -0800486{
487 struct lpass_data *drvdata = platform_get_drvdata(pdev);
488
Srinivas Kandagatla9bae4882015-05-16 13:32:17 +0100489 if (drvdata->variant->exit)
490 drvdata->variant->exit(pdev);
491
Kenneth Westfield80beab82015-03-03 16:21:54 -0800492 clk_disable_unprepare(drvdata->ahbix_clk);
493
494 return 0;
495}
Srinivas Kandagatla9bae4882015-05-16 13:32:17 +0100496EXPORT_SYMBOL_GPL(asoc_qcom_lpass_cpu_platform_remove);