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/kernel.h>
18 #include <linux/module.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"
30 static int lpass_cpu_daiops_set_sysclk(struct snd_soc_dai
*dai
, int clk_id
,
31 unsigned int freq
, int dir
)
33 struct lpass_data
*drvdata
= snd_soc_dai_get_drvdata(dai
);
36 if (IS_ERR(drvdata
->mi2s_osr_clk
[dai
->driver
->id
]))
39 ret
= clk_set_rate(drvdata
->mi2s_osr_clk
[dai
->driver
->id
], freq
);
41 dev_err(dai
->dev
, "%s() error setting mi2s osrclk to %u: %d\n",
47 static int lpass_cpu_daiops_startup(struct snd_pcm_substream
*substream
,
48 struct snd_soc_dai
*dai
)
50 struct lpass_data
*drvdata
= snd_soc_dai_get_drvdata(dai
);
53 if (!IS_ERR(drvdata
->mi2s_osr_clk
[dai
->driver
->id
])) {
54 ret
= clk_prepare_enable(
55 drvdata
->mi2s_osr_clk
[dai
->driver
->id
]);
57 dev_err(dai
->dev
, "%s() error in enabling mi2s osr clk: %d\n",
63 ret
= clk_prepare_enable(drvdata
->mi2s_bit_clk
[dai
->driver
->id
]);
65 dev_err(dai
->dev
, "%s() error in enabling mi2s bit clk: %d\n",
67 if (!IS_ERR(drvdata
->mi2s_osr_clk
[dai
->driver
->id
]))
68 clk_disable_unprepare(
69 drvdata
->mi2s_osr_clk
[dai
->driver
->id
]);
76 static void lpass_cpu_daiops_shutdown(struct snd_pcm_substream
*substream
,
77 struct snd_soc_dai
*dai
)
79 struct lpass_data
*drvdata
= snd_soc_dai_get_drvdata(dai
);
81 clk_disable_unprepare(drvdata
->mi2s_bit_clk
[dai
->driver
->id
]);
83 if (!IS_ERR(drvdata
->mi2s_osr_clk
[dai
->driver
->id
]))
84 clk_disable_unprepare(drvdata
->mi2s_osr_clk
[dai
->driver
->id
]);
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
)
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
);
97 bitwidth
= snd_pcm_format_width(format
);
99 dev_err(dai
->dev
, "%s() invalid bit width given: %d\n",
104 regval
= LPAIF_I2SCTL_LOOPBACK_DISABLE
|
105 LPAIF_I2SCTL_WSSRC_INTERNAL
;
109 regval
|= LPAIF_I2SCTL_BITWIDTH_16
;
112 regval
|= LPAIF_I2SCTL_BITWIDTH_24
;
115 regval
|= LPAIF_I2SCTL_BITWIDTH_32
;
118 dev_err(dai
->dev
, "%s() invalid bitwidth given: %d\n",
125 regval
|= LPAIF_I2SCTL_SPKMODE_SD0
;
126 regval
|= LPAIF_I2SCTL_SPKMONO_MONO
;
129 regval
|= LPAIF_I2SCTL_SPKMODE_SD0
;
130 regval
|= LPAIF_I2SCTL_SPKMONO_STEREO
;
133 regval
|= LPAIF_I2SCTL_SPKMODE_QUAD01
;
134 regval
|= LPAIF_I2SCTL_SPKMONO_STEREO
;
137 regval
|= LPAIF_I2SCTL_SPKMODE_6CH
;
138 regval
|= LPAIF_I2SCTL_SPKMONO_STEREO
;
141 regval
|= LPAIF_I2SCTL_SPKMODE_8CH
;
142 regval
|= LPAIF_I2SCTL_SPKMONO_STEREO
;
145 dev_err(dai
->dev
, "%s() invalid channels given: %u\n",
150 ret
= regmap_write(drvdata
->lpaif_map
,
151 LPAIF_I2SCTL_REG(drvdata
->variant
, dai
->driver
->id
),
154 dev_err(dai
->dev
, "%s() error writing to i2sctl reg: %d\n",
159 ret
= clk_set_rate(drvdata
->mi2s_bit_clk
[dai
->driver
->id
],
160 rate
* bitwidth
* 2);
162 dev_err(dai
->dev
, "%s() error setting mi2s bitclk to %u: %d\n",
163 __func__
, rate
* bitwidth
* 2, ret
);
170 static int lpass_cpu_daiops_hw_free(struct snd_pcm_substream
*substream
,
171 struct snd_soc_dai
*dai
)
173 struct lpass_data
*drvdata
= snd_soc_dai_get_drvdata(dai
);
176 ret
= regmap_write(drvdata
->lpaif_map
,
177 LPAIF_I2SCTL_REG(drvdata
->variant
, dai
->driver
->id
),
180 dev_err(dai
->dev
, "%s() error writing to i2sctl reg: %d\n",
186 static int lpass_cpu_daiops_prepare(struct snd_pcm_substream
*substream
,
187 struct snd_soc_dai
*dai
)
189 struct lpass_data
*drvdata
= snd_soc_dai_get_drvdata(dai
);
192 ret
= regmap_update_bits(drvdata
->lpaif_map
,
193 LPAIF_I2SCTL_REG(drvdata
->variant
, dai
->driver
->id
),
194 LPAIF_I2SCTL_SPKEN_MASK
, LPAIF_I2SCTL_SPKEN_ENABLE
);
196 dev_err(dai
->dev
, "%s() error writing to i2sctl reg: %d\n",
202 static int lpass_cpu_daiops_trigger(struct snd_pcm_substream
*substream
,
203 int cmd
, struct snd_soc_dai
*dai
)
205 struct lpass_data
*drvdata
= snd_soc_dai_get_drvdata(dai
);
209 case SNDRV_PCM_TRIGGER_START
:
210 case SNDRV_PCM_TRIGGER_RESUME
:
211 case SNDRV_PCM_TRIGGER_PAUSE_RELEASE
:
212 ret
= regmap_update_bits(drvdata
->lpaif_map
,
213 LPAIF_I2SCTL_REG(drvdata
->variant
,
215 LPAIF_I2SCTL_SPKEN_MASK
,
216 LPAIF_I2SCTL_SPKEN_ENABLE
);
218 dev_err(dai
->dev
, "%s() error writing to i2sctl reg: %d\n",
221 case SNDRV_PCM_TRIGGER_STOP
:
222 case SNDRV_PCM_TRIGGER_SUSPEND
:
223 case SNDRV_PCM_TRIGGER_PAUSE_PUSH
:
224 ret
= regmap_update_bits(drvdata
->lpaif_map
,
225 LPAIF_I2SCTL_REG(drvdata
->variant
,
227 LPAIF_I2SCTL_SPKEN_MASK
,
228 LPAIF_I2SCTL_SPKEN_DISABLE
);
230 dev_err(dai
->dev
, "%s() error writing to i2sctl reg: %d\n",
238 const struct snd_soc_dai_ops asoc_qcom_lpass_cpu_dai_ops
= {
239 .set_sysclk
= lpass_cpu_daiops_set_sysclk
,
240 .startup
= lpass_cpu_daiops_startup
,
241 .shutdown
= lpass_cpu_daiops_shutdown
,
242 .hw_params
= lpass_cpu_daiops_hw_params
,
243 .hw_free
= lpass_cpu_daiops_hw_free
,
244 .prepare
= lpass_cpu_daiops_prepare
,
245 .trigger
= lpass_cpu_daiops_trigger
,
247 EXPORT_SYMBOL_GPL(asoc_qcom_lpass_cpu_dai_ops
);
249 int asoc_qcom_lpass_cpu_dai_probe(struct snd_soc_dai
*dai
)
251 struct lpass_data
*drvdata
= snd_soc_dai_get_drvdata(dai
);
254 /* ensure audio hardware is disabled */
255 ret
= regmap_write(drvdata
->lpaif_map
,
256 LPAIF_I2SCTL_REG(drvdata
->variant
, dai
->driver
->id
), 0);
258 dev_err(dai
->dev
, "%s() error writing to i2sctl reg: %d\n",
263 EXPORT_SYMBOL_GPL(asoc_qcom_lpass_cpu_dai_probe
);
265 static const struct snd_soc_component_driver lpass_cpu_comp_driver
= {
269 static bool lpass_cpu_regmap_writeable(struct device
*dev
, unsigned int reg
)
271 struct lpass_data
*drvdata
= dev_get_drvdata(dev
);
272 struct lpass_variant
*v
= drvdata
->variant
;
275 for (i
= 0; i
< v
->i2s_ports
; ++i
)
276 if (reg
== LPAIF_I2SCTL_REG(v
, i
))
279 for (i
= 0; i
< v
->irq_ports
; ++i
) {
280 if (reg
== LPAIF_IRQEN_REG(v
, i
))
282 if (reg
== LPAIF_IRQCLEAR_REG(v
, i
))
286 for (i
= 0; i
< v
->rdma_channels
; ++i
) {
287 if (reg
== LPAIF_RDMACTL_REG(v
, i
))
289 if (reg
== LPAIF_RDMABASE_REG(v
, i
))
291 if (reg
== LPAIF_RDMABUFF_REG(v
, i
))
293 if (reg
== LPAIF_RDMAPER_REG(v
, i
))
300 static bool lpass_cpu_regmap_readable(struct device
*dev
, unsigned int reg
)
302 struct lpass_data
*drvdata
= dev_get_drvdata(dev
);
303 struct lpass_variant
*v
= drvdata
->variant
;
306 for (i
= 0; i
< v
->i2s_ports
; ++i
)
307 if (reg
== LPAIF_I2SCTL_REG(v
, i
))
310 for (i
= 0; i
< v
->irq_ports
; ++i
) {
311 if (reg
== LPAIF_IRQEN_REG(v
, i
))
313 if (reg
== LPAIF_IRQSTAT_REG(v
, i
))
317 for (i
= 0; i
< v
->rdma_channels
; ++i
) {
318 if (reg
== LPAIF_RDMACTL_REG(v
, i
))
320 if (reg
== LPAIF_RDMABASE_REG(v
, i
))
322 if (reg
== LPAIF_RDMABUFF_REG(v
, i
))
324 if (reg
== LPAIF_RDMACURR_REG(v
, i
))
326 if (reg
== LPAIF_RDMAPER_REG(v
, i
))
333 static bool lpass_cpu_regmap_volatile(struct device
*dev
, unsigned int reg
)
335 struct lpass_data
*drvdata
= dev_get_drvdata(dev
);
336 struct lpass_variant
*v
= drvdata
->variant
;
339 for (i
= 0; i
< v
->irq_ports
; ++i
)
340 if (reg
== LPAIF_IRQSTAT_REG(v
, i
))
343 for (i
= 0; i
< v
->rdma_channels
; ++i
)
344 if (reg
== LPAIF_RDMACURR_REG(v
, i
))
350 static struct regmap_config lpass_cpu_regmap_config
= {
354 .writeable_reg
= lpass_cpu_regmap_writeable
,
355 .readable_reg
= lpass_cpu_regmap_readable
,
356 .volatile_reg
= lpass_cpu_regmap_volatile
,
357 .cache_type
= REGCACHE_FLAT
,
360 int asoc_qcom_lpass_cpu_platform_probe(struct platform_device
*pdev
)
362 struct lpass_data
*drvdata
;
363 struct device_node
*dsp_of_node
;
364 struct resource
*res
;
365 struct lpass_variant
*variant
;
366 struct device
*dev
= &pdev
->dev
;
367 const struct of_device_id
*match
;
371 dsp_of_node
= of_parse_phandle(pdev
->dev
.of_node
, "qcom,adsp", 0);
373 dev_err(&pdev
->dev
, "%s() DSP exists and holds audio resources\n",
378 drvdata
= devm_kzalloc(&pdev
->dev
, sizeof(struct lpass_data
),
382 platform_set_drvdata(pdev
, drvdata
);
384 match
= of_match_device(dev
->driver
->of_match_table
, dev
);
385 if (!match
|| !match
->data
)
388 drvdata
->variant
= (struct lpass_variant
*)match
->data
;
389 variant
= drvdata
->variant
;
391 res
= platform_get_resource_byname(pdev
, IORESOURCE_MEM
, "lpass-lpaif");
393 drvdata
->lpaif
= devm_ioremap_resource(&pdev
->dev
, res
);
394 if (IS_ERR((void const __force
*)drvdata
->lpaif
)) {
395 dev_err(&pdev
->dev
, "%s() error mapping reg resource: %ld\n",
397 PTR_ERR((void const __force
*)drvdata
->lpaif
));
398 return PTR_ERR((void const __force
*)drvdata
->lpaif
);
401 lpass_cpu_regmap_config
.max_register
= LPAIF_RDMAPER_REG(variant
,
402 variant
->rdma_channels
);
404 drvdata
->lpaif_map
= devm_regmap_init_mmio(&pdev
->dev
, drvdata
->lpaif
,
405 &lpass_cpu_regmap_config
);
406 if (IS_ERR(drvdata
->lpaif_map
)) {
407 dev_err(&pdev
->dev
, "%s() error initializing regmap: %ld\n",
408 __func__
, PTR_ERR(drvdata
->lpaif_map
));
409 return PTR_ERR(drvdata
->lpaif_map
);
415 for (i
= 0; i
< variant
->num_dai
; i
++) {
416 dai_id
= variant
->dai_driver
[i
].id
;
417 if (variant
->num_dai
> 1)
418 sprintf(clk_name
, "mi2s-osr-clk%d", i
);
420 sprintf(clk_name
, "mi2s-osr-clk");
422 drvdata
->mi2s_osr_clk
[dai_id
] = devm_clk_get(&pdev
->dev
,
424 if (IS_ERR(drvdata
->mi2s_osr_clk
[dai_id
])) {
426 "%s() error getting mi2s-osr-clk: %ld\n",
428 PTR_ERR(drvdata
->mi2s_osr_clk
[dai_id
]));
431 if (variant
->num_dai
> 1)
432 sprintf(clk_name
, "mi2s-bit-clk%d", i
);
434 sprintf(clk_name
, "mi2s-bit-clk");
436 drvdata
->mi2s_bit_clk
[dai_id
] = devm_clk_get(&pdev
->dev
,
438 if (IS_ERR(drvdata
->mi2s_bit_clk
[dai_id
])) {
440 "%s() error getting mi2s-bit-clk: %ld\n",
442 PTR_ERR(drvdata
->mi2s_bit_clk
[dai_id
]));
443 return PTR_ERR(drvdata
->mi2s_bit_clk
[dai_id
]);
447 drvdata
->ahbix_clk
= devm_clk_get(&pdev
->dev
, "ahbix-clk");
448 if (IS_ERR(drvdata
->ahbix_clk
)) {
449 dev_err(&pdev
->dev
, "%s() error getting ahbix-clk: %ld\n",
450 __func__
, PTR_ERR(drvdata
->ahbix_clk
));
451 return PTR_ERR(drvdata
->ahbix_clk
);
454 ret
= clk_set_rate(drvdata
->ahbix_clk
, LPASS_AHBIX_CLOCK_FREQUENCY
);
456 dev_err(&pdev
->dev
, "%s() error setting rate on ahbix_clk: %d\n",
460 dev_dbg(&pdev
->dev
, "%s() set ahbix_clk rate to %lu\n", __func__
,
461 clk_get_rate(drvdata
->ahbix_clk
));
463 ret
= clk_prepare_enable(drvdata
->ahbix_clk
);
465 dev_err(&pdev
->dev
, "%s() error enabling ahbix_clk: %d\n",
470 ret
= devm_snd_soc_register_component(&pdev
->dev
,
471 &lpass_cpu_comp_driver
,
475 dev_err(&pdev
->dev
, "%s() error registering cpu driver: %d\n",
480 ret
= asoc_qcom_lpass_platform_register(pdev
);
482 dev_err(&pdev
->dev
, "%s() error registering platform driver: %d\n",
490 clk_disable_unprepare(drvdata
->ahbix_clk
);
493 EXPORT_SYMBOL_GPL(asoc_qcom_lpass_cpu_platform_probe
);
495 int asoc_qcom_lpass_cpu_platform_remove(struct platform_device
*pdev
)
497 struct lpass_data
*drvdata
= platform_get_drvdata(pdev
);
499 if (drvdata
->variant
->exit
)
500 drvdata
->variant
->exit(pdev
);
502 clk_disable_unprepare(drvdata
->ahbix_clk
);
506 EXPORT_SYMBOL_GPL(asoc_qcom_lpass_cpu_platform_remove
);