2 * Copyright (c) 2010-2011,2013-2015 The Linux Foundation. All rights reserved.
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.
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.
13 * lpass-cpu.c -- ALSA SoC CPU DAI driver for QTi LPASS
16 #include <linux/clk.h>
17 #include <linux/compiler.h>
18 #include <linux/device.h>
19 #include <linux/err.h>
20 #include <linux/ioport.h>
21 #include <linux/kernel.h>
22 #include <linux/mod_devicetable.h>
23 #include <linux/module.h>
25 #include <linux/platform_device.h>
26 #include <sound/pcm.h>
27 #include <sound/pcm_params.h>
28 #include <linux/regmap.h>
29 #include <sound/soc.h>
30 #include <sound/soc-dai.h>
31 #include "lpass-lpaif-ipq806x.h"
34 static int lpass_cpu_daiops_set_sysclk(struct snd_soc_dai
*dai
, int clk_id
,
35 unsigned int freq
, int dir
)
37 struct lpass_data
*drvdata
= snd_soc_dai_get_drvdata(dai
);
40 ret
= clk_set_rate(drvdata
->mi2s_osr_clk
, freq
);
42 dev_err(dai
->dev
, "%s() error setting mi2s osrclk to %u: %d\n",
48 static int lpass_cpu_daiops_startup(struct snd_pcm_substream
*substream
,
49 struct snd_soc_dai
*dai
)
51 struct lpass_data
*drvdata
= snd_soc_dai_get_drvdata(dai
);
54 ret
= clk_prepare_enable(drvdata
->mi2s_osr_clk
);
56 dev_err(dai
->dev
, "%s() error in enabling mi2s osr clk: %d\n",
61 ret
= clk_prepare_enable(drvdata
->mi2s_bit_clk
);
63 dev_err(dai
->dev
, "%s() error in enabling mi2s bit clk: %d\n",
65 clk_disable_unprepare(drvdata
->mi2s_osr_clk
);
72 static void lpass_cpu_daiops_shutdown(struct snd_pcm_substream
*substream
,
73 struct snd_soc_dai
*dai
)
75 struct lpass_data
*drvdata
= snd_soc_dai_get_drvdata(dai
);
77 clk_disable_unprepare(drvdata
->mi2s_bit_clk
);
78 clk_disable_unprepare(drvdata
->mi2s_osr_clk
);
81 static int lpass_cpu_daiops_hw_params(struct snd_pcm_substream
*substream
,
82 struct snd_pcm_hw_params
*params
, struct snd_soc_dai
*dai
)
84 struct lpass_data
*drvdata
= snd_soc_dai_get_drvdata(dai
);
85 snd_pcm_format_t format
= params_format(params
);
86 unsigned int channels
= params_channels(params
);
87 unsigned int rate
= params_rate(params
);
91 bitwidth
= snd_pcm_format_width(format
);
93 dev_err(dai
->dev
, "%s() invalid bit width given: %d\n",
98 regval
= LPAIF_I2SCTL_LOOPBACK_DISABLE
|
99 LPAIF_I2SCTL_WSSRC_INTERNAL
;
103 regval
|= LPAIF_I2SCTL_BITWIDTH_16
;
106 regval
|= LPAIF_I2SCTL_BITWIDTH_24
;
109 regval
|= LPAIF_I2SCTL_BITWIDTH_32
;
112 dev_err(dai
->dev
, "%s() invalid bitwidth given: %d\n",
119 regval
|= LPAIF_I2SCTL_SPKMODE_SD0
;
120 regval
|= LPAIF_I2SCTL_SPKMONO_MONO
;
123 regval
|= LPAIF_I2SCTL_SPKMODE_SD0
;
124 regval
|= LPAIF_I2SCTL_SPKMONO_STEREO
;
127 regval
|= LPAIF_I2SCTL_SPKMODE_QUAD01
;
128 regval
|= LPAIF_I2SCTL_SPKMONO_STEREO
;
131 regval
|= LPAIF_I2SCTL_SPKMODE_6CH
;
132 regval
|= LPAIF_I2SCTL_SPKMONO_STEREO
;
135 regval
|= LPAIF_I2SCTL_SPKMODE_8CH
;
136 regval
|= LPAIF_I2SCTL_SPKMONO_STEREO
;
139 dev_err(dai
->dev
, "%s() invalid channels given: %u\n",
144 ret
= regmap_write(drvdata
->lpaif_map
,
145 LPAIF_I2SCTL_REG(LPAIF_I2S_PORT_MI2S
), regval
);
147 dev_err(dai
->dev
, "%s() error writing to i2sctl reg: %d\n",
152 ret
= clk_set_rate(drvdata
->mi2s_bit_clk
, rate
* bitwidth
* 2);
154 dev_err(dai
->dev
, "%s() error setting mi2s bitclk to %u: %d\n",
155 __func__
, rate
* bitwidth
* 2, ret
);
162 static int lpass_cpu_daiops_hw_free(struct snd_pcm_substream
*substream
,
163 struct snd_soc_dai
*dai
)
165 struct lpass_data
*drvdata
= snd_soc_dai_get_drvdata(dai
);
168 ret
= regmap_write(drvdata
->lpaif_map
,
169 LPAIF_I2SCTL_REG(LPAIF_I2S_PORT_MI2S
), 0);
171 dev_err(dai
->dev
, "%s() error writing to i2sctl reg: %d\n",
177 static int lpass_cpu_daiops_prepare(struct snd_pcm_substream
*substream
,
178 struct snd_soc_dai
*dai
)
180 struct lpass_data
*drvdata
= snd_soc_dai_get_drvdata(dai
);
183 ret
= regmap_update_bits(drvdata
->lpaif_map
,
184 LPAIF_I2SCTL_REG(LPAIF_I2S_PORT_MI2S
),
185 LPAIF_I2SCTL_SPKEN_MASK
, LPAIF_I2SCTL_SPKEN_ENABLE
);
187 dev_err(dai
->dev
, "%s() error writing to i2sctl reg: %d\n",
193 static int lpass_cpu_daiops_trigger(struct snd_pcm_substream
*substream
,
194 int cmd
, struct snd_soc_dai
*dai
)
196 struct lpass_data
*drvdata
= snd_soc_dai_get_drvdata(dai
);
200 case SNDRV_PCM_TRIGGER_START
:
201 case SNDRV_PCM_TRIGGER_RESUME
:
202 case SNDRV_PCM_TRIGGER_PAUSE_RELEASE
:
203 ret
= regmap_update_bits(drvdata
->lpaif_map
,
204 LPAIF_I2SCTL_REG(LPAIF_I2S_PORT_MI2S
),
205 LPAIF_I2SCTL_SPKEN_MASK
,
206 LPAIF_I2SCTL_SPKEN_ENABLE
);
208 dev_err(dai
->dev
, "%s() error writing to i2sctl reg: %d\n",
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
,
215 LPAIF_I2SCTL_REG(LPAIF_I2S_PORT_MI2S
),
216 LPAIF_I2SCTL_SPKEN_MASK
,
217 LPAIF_I2SCTL_SPKEN_DISABLE
);
219 dev_err(dai
->dev
, "%s() error writing to i2sctl reg: %d\n",
227 static struct snd_soc_dai_ops lpass_cpu_dai_ops
= {
228 .set_sysclk
= lpass_cpu_daiops_set_sysclk
,
229 .startup
= lpass_cpu_daiops_startup
,
230 .shutdown
= lpass_cpu_daiops_shutdown
,
231 .hw_params
= lpass_cpu_daiops_hw_params
,
232 .hw_free
= lpass_cpu_daiops_hw_free
,
233 .prepare
= lpass_cpu_daiops_prepare
,
234 .trigger
= lpass_cpu_daiops_trigger
,
237 static int lpass_cpu_dai_probe(struct snd_soc_dai
*dai
)
239 struct lpass_data
*drvdata
= snd_soc_dai_get_drvdata(dai
);
242 /* ensure audio hardware is disabled */
243 ret
= regmap_write(drvdata
->lpaif_map
,
244 LPAIF_I2SCTL_REG(LPAIF_I2S_PORT_MI2S
), 0);
246 dev_err(dai
->dev
, "%s() error writing to i2sctl reg: %d\n",
252 static struct snd_soc_dai_driver lpass_cpu_dai_driver
= {
254 .stream_name
= "lpass-cpu-playback",
255 .formats
= SNDRV_PCM_FMTBIT_S16
|
256 SNDRV_PCM_FMTBIT_S24
|
257 SNDRV_PCM_FMTBIT_S32
,
258 .rates
= SNDRV_PCM_RATE_8000
|
259 SNDRV_PCM_RATE_16000
|
260 SNDRV_PCM_RATE_32000
|
261 SNDRV_PCM_RATE_48000
|
262 SNDRV_PCM_RATE_96000
,
268 .probe
= &lpass_cpu_dai_probe
,
269 .ops
= &lpass_cpu_dai_ops
,
272 static const struct snd_soc_component_driver lpass_cpu_comp_driver
= {
276 static bool lpass_cpu_regmap_writeable(struct device
*dev
, unsigned int reg
)
280 for (i
= 0; i
< LPAIF_I2S_PORT_NUM
; ++i
)
281 if (reg
== LPAIF_I2SCTL_REG(i
))
284 for (i
= 0; i
< LPAIF_IRQ_PORT_NUM
; ++i
) {
285 if (reg
== LPAIF_IRQEN_REG(i
))
287 if (reg
== LPAIF_IRQCLEAR_REG(i
))
291 for (i
= 0; i
< LPAIF_RDMA_CHAN_NUM
; ++i
) {
292 if (reg
== LPAIF_RDMACTL_REG(i
))
294 if (reg
== LPAIF_RDMABASE_REG(i
))
296 if (reg
== LPAIF_RDMABUFF_REG(i
))
298 if (reg
== LPAIF_RDMAPER_REG(i
))
305 static bool lpass_cpu_regmap_readable(struct device
*dev
, unsigned int reg
)
309 for (i
= 0; i
< LPAIF_I2S_PORT_NUM
; ++i
)
310 if (reg
== LPAIF_I2SCTL_REG(i
))
313 for (i
= 0; i
< LPAIF_IRQ_PORT_NUM
; ++i
) {
314 if (reg
== LPAIF_IRQEN_REG(i
))
316 if (reg
== LPAIF_IRQSTAT_REG(i
))
320 for (i
= 0; i
< LPAIF_RDMA_CHAN_NUM
; ++i
) {
321 if (reg
== LPAIF_RDMACTL_REG(i
))
323 if (reg
== LPAIF_RDMABASE_REG(i
))
325 if (reg
== LPAIF_RDMABUFF_REG(i
))
327 if (reg
== LPAIF_RDMACURR_REG(i
))
329 if (reg
== LPAIF_RDMAPER_REG(i
))
336 static bool lpass_cpu_regmap_volatile(struct device
*dev
, unsigned int reg
)
340 for (i
= 0; i
< LPAIF_IRQ_PORT_NUM
; ++i
)
341 if (reg
== LPAIF_IRQSTAT_REG(i
))
344 for (i
= 0; i
< LPAIF_RDMA_CHAN_NUM
; ++i
)
345 if (reg
== LPAIF_RDMACURR_REG(i
))
351 static const struct regmap_config lpass_cpu_regmap_config
= {
355 .max_register
= LPAIF_RDMAPER_REG(LPAIF_RDMA_CHAN_MAX
),
356 .writeable_reg
= lpass_cpu_regmap_writeable
,
357 .readable_reg
= lpass_cpu_regmap_readable
,
358 .volatile_reg
= lpass_cpu_regmap_volatile
,
359 .cache_type
= REGCACHE_FLAT
,
362 static int lpass_cpu_platform_probe(struct platform_device
*pdev
)
364 struct lpass_data
*drvdata
;
365 struct device_node
*dsp_of_node
;
366 struct resource
*res
;
369 dsp_of_node
= of_parse_phandle(pdev
->dev
.of_node
, "qcom,adsp", 0);
371 dev_err(&pdev
->dev
, "%s() DSP exists and holds audio resources\n",
376 drvdata
= devm_kzalloc(&pdev
->dev
, sizeof(struct lpass_data
),
380 platform_set_drvdata(pdev
, drvdata
);
382 res
= platform_get_resource_byname(pdev
, IORESOURCE_MEM
, "lpass-lpaif");
384 dev_err(&pdev
->dev
, "%s() error getting resource\n", __func__
);
388 drvdata
->lpaif
= devm_ioremap_resource(&pdev
->dev
, res
);
389 if (IS_ERR((void const __force
*)drvdata
->lpaif
)) {
390 dev_err(&pdev
->dev
, "%s() error mapping reg resource: %ld\n",
392 PTR_ERR((void const __force
*)drvdata
->lpaif
));
393 return PTR_ERR((void const __force
*)drvdata
->lpaif
);
396 drvdata
->lpaif_map
= devm_regmap_init_mmio(&pdev
->dev
, drvdata
->lpaif
,
397 &lpass_cpu_regmap_config
);
398 if (IS_ERR(drvdata
->lpaif_map
)) {
399 dev_err(&pdev
->dev
, "%s() error initializing regmap: %ld\n",
400 __func__
, PTR_ERR(drvdata
->lpaif_map
));
401 return PTR_ERR(drvdata
->lpaif_map
);
404 drvdata
->mi2s_osr_clk
= devm_clk_get(&pdev
->dev
, "mi2s-osr-clk");
405 if (IS_ERR(drvdata
->mi2s_osr_clk
)) {
406 dev_err(&pdev
->dev
, "%s() error getting mi2s-osr-clk: %ld\n",
407 __func__
, PTR_ERR(drvdata
->mi2s_osr_clk
));
408 return PTR_ERR(drvdata
->mi2s_osr_clk
);
411 drvdata
->mi2s_bit_clk
= devm_clk_get(&pdev
->dev
, "mi2s-bit-clk");
412 if (IS_ERR(drvdata
->mi2s_bit_clk
)) {
413 dev_err(&pdev
->dev
, "%s() error getting mi2s-bit-clk: %ld\n",
414 __func__
, PTR_ERR(drvdata
->mi2s_bit_clk
));
415 return PTR_ERR(drvdata
->mi2s_bit_clk
);
418 drvdata
->ahbix_clk
= devm_clk_get(&pdev
->dev
, "ahbix-clk");
419 if (IS_ERR(drvdata
->ahbix_clk
)) {
420 dev_err(&pdev
->dev
, "%s() error getting ahbix-clk: %ld\n",
421 __func__
, PTR_ERR(drvdata
->ahbix_clk
));
422 return PTR_ERR(drvdata
->ahbix_clk
);
425 ret
= clk_set_rate(drvdata
->ahbix_clk
, LPASS_AHBIX_CLOCK_FREQUENCY
);
427 dev_err(&pdev
->dev
, "%s() error setting rate on ahbix_clk: %d\n",
431 dev_dbg(&pdev
->dev
, "%s() set ahbix_clk rate to %lu\n", __func__
,
432 clk_get_rate(drvdata
->ahbix_clk
));
434 ret
= clk_prepare_enable(drvdata
->ahbix_clk
);
436 dev_err(&pdev
->dev
, "%s() error enabling ahbix_clk: %d\n",
441 ret
= devm_snd_soc_register_component(&pdev
->dev
,
442 &lpass_cpu_comp_driver
, &lpass_cpu_dai_driver
, 1);
444 dev_err(&pdev
->dev
, "%s() error registering cpu driver: %d\n",
449 ret
= asoc_qcom_lpass_platform_register(pdev
);
451 dev_err(&pdev
->dev
, "%s() error registering platform driver: %d\n",
459 clk_disable_unprepare(drvdata
->ahbix_clk
);
463 static int lpass_cpu_platform_remove(struct platform_device
*pdev
)
465 struct lpass_data
*drvdata
= platform_get_drvdata(pdev
);
467 clk_disable_unprepare(drvdata
->ahbix_clk
);
473 static const struct of_device_id lpass_cpu_device_id
[] = {
474 { .compatible
= "qcom,lpass-cpu" },
477 MODULE_DEVICE_TABLE(of
, lpass_cpu_device_id
);
480 static struct platform_driver lpass_cpu_platform_driver
= {
483 .of_match_table
= of_match_ptr(lpass_cpu_device_id
),
485 .probe
= lpass_cpu_platform_probe
,
486 .remove
= lpass_cpu_platform_remove
,
488 module_platform_driver(lpass_cpu_platform_driver
);
490 MODULE_DESCRIPTION("QTi LPASS CPU Driver");
491 MODULE_LICENSE("GPL v2");