1 // SPDX-License-Identifier: GPL-2.0-only
3 * Copyright (c) 2010-2011,2013-2015 The Linux Foundation. All rights reserved.
5 * lpass-apq8016.c -- ALSA SoC CPU DAI driver for APQ8016 LPASS
10 #include <linux/device.h>
11 #include <linux/err.h>
12 #include <linux/kernel.h>
13 #include <linux/module.h>
15 #include <linux/platform_device.h>
16 #include <sound/pcm.h>
17 #include <sound/pcm_params.h>
18 #include <sound/soc.h>
19 #include <sound/soc-dai.h>
21 #include <dt-bindings/sound/apq8016-lpass.h>
22 #include "lpass-lpaif-reg.h"
25 static struct snd_soc_dai_driver apq8016_lpass_cpu_dai_driver
[] = {
28 .name
= "Primary MI2S",
30 .stream_name
= "Primary Playback",
31 .formats
= SNDRV_PCM_FMTBIT_S16
|
32 SNDRV_PCM_FMTBIT_S24
|
34 .rates
= SNDRV_PCM_RATE_8000
|
35 SNDRV_PCM_RATE_16000
|
36 SNDRV_PCM_RATE_32000
|
37 SNDRV_PCM_RATE_48000
|
44 .probe
= &asoc_qcom_lpass_cpu_dai_probe
,
45 .ops
= &asoc_qcom_lpass_cpu_dai_ops
,
49 .name
= "Secondary MI2S",
51 .stream_name
= "Secondary Playback",
52 .formats
= SNDRV_PCM_FMTBIT_S16
|
53 SNDRV_PCM_FMTBIT_S24
|
55 .rates
= SNDRV_PCM_RATE_8000
|
56 SNDRV_PCM_RATE_16000
|
57 SNDRV_PCM_RATE_32000
|
58 SNDRV_PCM_RATE_48000
|
65 .probe
= &asoc_qcom_lpass_cpu_dai_probe
,
66 .ops
= &asoc_qcom_lpass_cpu_dai_ops
,
70 .name
= "Tertiary MI2S",
72 .stream_name
= "Tertiary Capture",
73 .formats
= SNDRV_PCM_FMTBIT_S16
|
74 SNDRV_PCM_FMTBIT_S24
|
76 .rates
= SNDRV_PCM_RATE_8000
|
77 SNDRV_PCM_RATE_16000
|
78 SNDRV_PCM_RATE_32000
|
79 SNDRV_PCM_RATE_48000
|
86 .probe
= &asoc_qcom_lpass_cpu_dai_probe
,
87 .ops
= &asoc_qcom_lpass_cpu_dai_ops
,
90 .id
= MI2S_QUATERNARY
,
91 .name
= "Quatenary MI2S",
93 .stream_name
= "Quatenary Playback",
94 .formats
= SNDRV_PCM_FMTBIT_S16
|
95 SNDRV_PCM_FMTBIT_S24
|
97 .rates
= SNDRV_PCM_RATE_8000
|
98 SNDRV_PCM_RATE_16000
|
99 SNDRV_PCM_RATE_32000
|
100 SNDRV_PCM_RATE_48000
|
101 SNDRV_PCM_RATE_96000
,
108 .stream_name
= "Quatenary Capture",
109 .formats
= SNDRV_PCM_FMTBIT_S16
|
110 SNDRV_PCM_FMTBIT_S24
|
111 SNDRV_PCM_FMTBIT_S32
,
112 .rates
= SNDRV_PCM_RATE_8000
|
113 SNDRV_PCM_RATE_16000
|
114 SNDRV_PCM_RATE_32000
|
115 SNDRV_PCM_RATE_48000
|
116 SNDRV_PCM_RATE_96000
,
122 .probe
= &asoc_qcom_lpass_cpu_dai_probe
,
123 .ops
= &asoc_qcom_lpass_cpu_dai_ops
,
127 static int apq8016_lpass_alloc_dma_channel(struct lpass_data
*drvdata
,
130 struct lpass_variant
*v
= drvdata
->variant
;
133 if (direction
== SNDRV_PCM_STREAM_PLAYBACK
) {
134 chan
= find_first_zero_bit(&drvdata
->dma_ch_bit_map
,
137 if (chan
>= v
->rdma_channels
)
140 chan
= find_next_zero_bit(&drvdata
->dma_ch_bit_map
,
141 v
->wrdma_channel_start
+
143 v
->wrdma_channel_start
);
145 if (chan
>= v
->wrdma_channel_start
+ v
->wrdma_channels
)
149 set_bit(chan
, &drvdata
->dma_ch_bit_map
);
154 static int apq8016_lpass_free_dma_channel(struct lpass_data
*drvdata
, int chan
)
156 clear_bit(chan
, &drvdata
->dma_ch_bit_map
);
161 static int apq8016_lpass_init(struct platform_device
*pdev
)
163 struct lpass_data
*drvdata
= platform_get_drvdata(pdev
);
164 struct device
*dev
= &pdev
->dev
;
167 drvdata
->pcnoc_mport_clk
= devm_clk_get(dev
, "pcnoc-mport-clk");
168 if (IS_ERR(drvdata
->pcnoc_mport_clk
)) {
169 dev_err(&pdev
->dev
, "error getting pcnoc-mport-clk: %ld\n",
170 PTR_ERR(drvdata
->pcnoc_mport_clk
));
171 return PTR_ERR(drvdata
->pcnoc_mport_clk
);
174 ret
= clk_prepare_enable(drvdata
->pcnoc_mport_clk
);
176 dev_err(&pdev
->dev
, "Error enabling pcnoc-mport-clk: %d\n",
181 drvdata
->pcnoc_sway_clk
= devm_clk_get(dev
, "pcnoc-sway-clk");
182 if (IS_ERR(drvdata
->pcnoc_sway_clk
)) {
183 dev_err(&pdev
->dev
, "error getting pcnoc-sway-clk: %ld\n",
184 PTR_ERR(drvdata
->pcnoc_sway_clk
));
185 return PTR_ERR(drvdata
->pcnoc_sway_clk
);
188 ret
= clk_prepare_enable(drvdata
->pcnoc_sway_clk
);
190 dev_err(&pdev
->dev
, "Error enabling pcnoc_sway_clk: %d\n", ret
);
197 static int apq8016_lpass_exit(struct platform_device
*pdev
)
199 struct lpass_data
*drvdata
= platform_get_drvdata(pdev
);
201 clk_disable_unprepare(drvdata
->pcnoc_mport_clk
);
202 clk_disable_unprepare(drvdata
->pcnoc_sway_clk
);
208 static struct lpass_variant apq8016_data
= {
209 .i2sctrl_reg_base
= 0x1000,
210 .i2sctrl_reg_stride
= 0x1000,
212 .irq_reg_base
= 0x6000,
213 .irq_reg_stride
= 0x1000,
215 .rdma_reg_base
= 0x8400,
216 .rdma_reg_stride
= 0x1000,
218 .dmactl_audif_start
= 1,
219 .wrdma_reg_base
= 0xB000,
220 .wrdma_reg_stride
= 0x1000,
221 .wrdma_channel_start
= 5,
223 .dai_driver
= apq8016_lpass_cpu_dai_driver
,
224 .num_dai
= ARRAY_SIZE(apq8016_lpass_cpu_dai_driver
),
225 .dai_osr_clk_names
= (const char *[]) {
231 .dai_bit_clk_names
= (const char *[]) {
237 .init
= apq8016_lpass_init
,
238 .exit
= apq8016_lpass_exit
,
239 .alloc_dma_channel
= apq8016_lpass_alloc_dma_channel
,
240 .free_dma_channel
= apq8016_lpass_free_dma_channel
,
243 static const struct of_device_id apq8016_lpass_cpu_device_id
[] = {
244 { .compatible
= "qcom,lpass-cpu-apq8016", .data
= &apq8016_data
},
247 MODULE_DEVICE_TABLE(of
, apq8016_lpass_cpu_device_id
);
249 static struct platform_driver apq8016_lpass_cpu_platform_driver
= {
251 .name
= "apq8016-lpass-cpu",
252 .of_match_table
= of_match_ptr(apq8016_lpass_cpu_device_id
),
254 .probe
= asoc_qcom_lpass_cpu_platform_probe
,
255 .remove
= asoc_qcom_lpass_cpu_platform_remove
,
257 module_platform_driver(apq8016_lpass_cpu_platform_driver
);
259 MODULE_DESCRIPTION("APQ8016 LPASS CPU Driver");
260 MODULE_LICENSE("GPL v2");