arm64: dts: qcom: sm8550: add TRNG node
[linux-modified.git] / sound / soc / qcom / lpass-apq8016.c
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-apq8016.c -- ALSA SoC CPU DAI driver for APQ8016 LPASS
6  */
7
8
9 #include <linux/clk.h>
10 #include <linux/device.h>
11 #include <linux/err.h>
12 #include <linux/kernel.h>
13 #include <linux/module.h>
14 #include <linux/of.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>
20
21 #include <dt-bindings/sound/apq8016-lpass.h>
22 #include "lpass-lpaif-reg.h"
23 #include "lpass.h"
24
25 static struct snd_soc_dai_driver apq8016_lpass_cpu_dai_driver[] = {
26         [MI2S_PRIMARY] =  {
27                 .id = MI2S_PRIMARY,
28                 .name = "Primary MI2S",
29                 .playback = {
30                         .stream_name    = "Primary Playback",
31                         .formats        = SNDRV_PCM_FMTBIT_S16 |
32                                                 SNDRV_PCM_FMTBIT_S24 |
33                                                 SNDRV_PCM_FMTBIT_S32,
34                         .rates          = SNDRV_PCM_RATE_8000 |
35                                                 SNDRV_PCM_RATE_16000 |
36                                                 SNDRV_PCM_RATE_32000 |
37                                                 SNDRV_PCM_RATE_48000 |
38                                                 SNDRV_PCM_RATE_96000,
39                         .rate_min       = 8000,
40                         .rate_max       = 96000,
41                         .channels_min   = 1,
42                         .channels_max   = 8,
43                 },
44                 .ops    = &asoc_qcom_lpass_cpu_dai_ops,
45         },
46         [MI2S_SECONDARY] =  {
47                 .id = MI2S_SECONDARY,
48                 .name = "Secondary MI2S",
49                 .playback = {
50                         .stream_name    = "Secondary Playback",
51                         .formats        = SNDRV_PCM_FMTBIT_S16 |
52                                                 SNDRV_PCM_FMTBIT_S24 |
53                                                 SNDRV_PCM_FMTBIT_S32,
54                         .rates          = SNDRV_PCM_RATE_8000 |
55                                                 SNDRV_PCM_RATE_16000 |
56                                                 SNDRV_PCM_RATE_32000 |
57                                                 SNDRV_PCM_RATE_48000 |
58                                                 SNDRV_PCM_RATE_96000,
59                         .rate_min       = 8000,
60                         .rate_max       = 96000,
61                         .channels_min   = 1,
62                         .channels_max   = 8,
63                 },
64                 .ops    = &asoc_qcom_lpass_cpu_dai_ops,
65         },
66         [MI2S_TERTIARY] =  {
67                 .id = MI2S_TERTIARY,
68                 .name = "Tertiary MI2S",
69                 .capture = {
70                         .stream_name    = "Tertiary Capture",
71                         .formats        = SNDRV_PCM_FMTBIT_S16 |
72                                                 SNDRV_PCM_FMTBIT_S24 |
73                                                 SNDRV_PCM_FMTBIT_S32,
74                         .rates          = SNDRV_PCM_RATE_8000 |
75                                                 SNDRV_PCM_RATE_16000 |
76                                                 SNDRV_PCM_RATE_32000 |
77                                                 SNDRV_PCM_RATE_48000 |
78                                                 SNDRV_PCM_RATE_96000,
79                         .rate_min       = 8000,
80                         .rate_max       = 96000,
81                         .channels_min   = 1,
82                         .channels_max   = 8,
83                 },
84                 .ops    = &asoc_qcom_lpass_cpu_dai_ops,
85         },
86         [MI2S_QUATERNARY] =  {
87                 .id = MI2S_QUATERNARY,
88                 .name = "Quatenary MI2S",
89                 .playback = {
90                         .stream_name    = "Quatenary Playback",
91                         .formats        = SNDRV_PCM_FMTBIT_S16 |
92                                                 SNDRV_PCM_FMTBIT_S24 |
93                                                 SNDRV_PCM_FMTBIT_S32,
94                         .rates          = SNDRV_PCM_RATE_8000 |
95                                                 SNDRV_PCM_RATE_16000 |
96                                                 SNDRV_PCM_RATE_32000 |
97                                                 SNDRV_PCM_RATE_48000 |
98                                                 SNDRV_PCM_RATE_96000,
99                         .rate_min       = 8000,
100                         .rate_max       = 96000,
101                         .channels_min   = 1,
102                         .channels_max   = 8,
103                 },
104                 .capture = {
105                         .stream_name    = "Quatenary Capture",
106                         .formats        = SNDRV_PCM_FMTBIT_S16 |
107                                                 SNDRV_PCM_FMTBIT_S24 |
108                                                 SNDRV_PCM_FMTBIT_S32,
109                         .rates          = SNDRV_PCM_RATE_8000 |
110                                                 SNDRV_PCM_RATE_16000 |
111                                                 SNDRV_PCM_RATE_32000 |
112                                                 SNDRV_PCM_RATE_48000 |
113                                                 SNDRV_PCM_RATE_96000,
114                         .rate_min       = 8000,
115                         .rate_max       = 96000,
116                         .channels_min   = 1,
117                         .channels_max   = 8,
118                 },
119                 .ops    = &asoc_qcom_lpass_cpu_dai_ops,
120         },
121 };
122
123 static int apq8016_lpass_alloc_dma_channel(struct lpass_data *drvdata,
124                                            int direction, unsigned int dai_id)
125 {
126         const struct lpass_variant *v = drvdata->variant;
127         int chan = 0;
128
129         if (direction == SNDRV_PCM_STREAM_PLAYBACK) {
130                 chan = find_first_zero_bit(&drvdata->dma_ch_bit_map,
131                                         v->rdma_channels);
132
133                 if (chan >= v->rdma_channels)
134                         return -EBUSY;
135         } else {
136                 chan = find_next_zero_bit(&drvdata->dma_ch_bit_map,
137                                         v->wrdma_channel_start +
138                                         v->wrdma_channels,
139                                         v->wrdma_channel_start);
140
141                 if (chan >=  v->wrdma_channel_start + v->wrdma_channels)
142                         return -EBUSY;
143         }
144
145         set_bit(chan, &drvdata->dma_ch_bit_map);
146
147         return chan;
148 }
149
150 static int apq8016_lpass_free_dma_channel(struct lpass_data *drvdata, int chan, unsigned int dai_id)
151 {
152         clear_bit(chan, &drvdata->dma_ch_bit_map);
153
154         return 0;
155 }
156
157 static int apq8016_lpass_init(struct platform_device *pdev)
158 {
159         struct lpass_data *drvdata = platform_get_drvdata(pdev);
160         const struct lpass_variant *variant = drvdata->variant;
161         struct device *dev = &pdev->dev;
162         int ret, i;
163
164
165         drvdata->clks = devm_kcalloc(dev, variant->num_clks,
166                                      sizeof(*drvdata->clks), GFP_KERNEL);
167         if (!drvdata->clks)
168                 return -ENOMEM;
169         drvdata->num_clks = variant->num_clks;
170
171         for (i = 0; i < drvdata->num_clks; i++)
172                 drvdata->clks[i].id = variant->clk_name[i];
173
174         ret = devm_clk_bulk_get(dev, drvdata->num_clks, drvdata->clks);
175         if (ret) {
176                 dev_err(dev, "Failed to get clocks %d\n", ret);
177                 return ret;
178         }
179
180         ret = clk_bulk_prepare_enable(drvdata->num_clks, drvdata->clks);
181         if (ret) {
182                 dev_err(dev, "apq8016 clk_enable failed\n");
183                 return ret;
184         }
185
186         drvdata->ahbix_clk = devm_clk_get(dev, "ahbix-clk");
187         if (IS_ERR(drvdata->ahbix_clk)) {
188                 dev_err(dev, "error getting ahbix-clk: %ld\n",
189                                 PTR_ERR(drvdata->ahbix_clk));
190                 ret = PTR_ERR(drvdata->ahbix_clk);
191                 goto err_ahbix_clk;
192         }
193
194         ret = clk_set_rate(drvdata->ahbix_clk, LPASS_AHBIX_CLOCK_FREQUENCY);
195         if (ret) {
196                 dev_err(dev, "error setting rate on ahbix_clk: %d\n", ret);
197                 goto err_ahbix_clk;
198         }
199         dev_dbg(dev, "set ahbix_clk rate to %lu\n",
200                         clk_get_rate(drvdata->ahbix_clk));
201
202         ret = clk_prepare_enable(drvdata->ahbix_clk);
203         if (ret) {
204                 dev_err(dev, "error enabling ahbix_clk: %d\n", ret);
205                 goto err_ahbix_clk;
206         }
207
208         return 0;
209
210 err_ahbix_clk:
211         clk_bulk_disable_unprepare(drvdata->num_clks, drvdata->clks);
212         return ret;
213 }
214
215 static int apq8016_lpass_exit(struct platform_device *pdev)
216 {
217         struct lpass_data *drvdata = platform_get_drvdata(pdev);
218
219         clk_bulk_disable_unprepare(drvdata->num_clks, drvdata->clks);
220         clk_disable_unprepare(drvdata->ahbix_clk);
221
222         return 0;
223 }
224
225
226 static const struct lpass_variant apq8016_data = {
227         .i2sctrl_reg_base       = 0x1000,
228         .i2sctrl_reg_stride     = 0x1000,
229         .i2s_ports              = 4,
230         .irq_reg_base           = 0x6000,
231         .irq_reg_stride         = 0x1000,
232         .irq_ports              = 3,
233         .rdma_reg_base          = 0x8400,
234         .rdma_reg_stride        = 0x1000,
235         .rdma_channels          = 2,
236         .dmactl_audif_start     = 1,
237         .wrdma_reg_base         = 0xB000,
238         .wrdma_reg_stride       = 0x1000,
239         .wrdma_channel_start    = 5,
240         .wrdma_channels         = 2,
241         .loopback               = REG_FIELD_ID(0x1000, 15, 15, 4, 0x1000),
242         .spken                  = REG_FIELD_ID(0x1000, 14, 14, 4, 0x1000),
243         .spkmode                = REG_FIELD_ID(0x1000, 10, 13, 4, 0x1000),
244         .spkmono                = REG_FIELD_ID(0x1000, 9, 9, 4, 0x1000),
245         .micen                  = REG_FIELD_ID(0x1000, 8, 8, 4, 0x1000),
246         .micmode                = REG_FIELD_ID(0x1000, 4, 7, 4, 0x1000),
247         .micmono                = REG_FIELD_ID(0x1000, 3, 3, 4, 0x1000),
248         .wssrc                  = REG_FIELD_ID(0x1000, 2, 2, 4, 0x1000),
249         .bitwidth               = REG_FIELD_ID(0x1000, 0, 1, 4, 0x1000),
250
251         .rdma_dyncclk           = REG_FIELD_ID(0x8400, 12, 12, 2, 0x1000),
252         .rdma_bursten           = REG_FIELD_ID(0x8400, 11, 11, 2, 0x1000),
253         .rdma_wpscnt            = REG_FIELD_ID(0x8400, 8, 10, 2, 0x1000),
254         .rdma_intf              = REG_FIELD_ID(0x8400, 4, 7, 2, 0x1000),
255         .rdma_fifowm            = REG_FIELD_ID(0x8400, 1, 3, 2, 0x1000),
256         .rdma_enable            = REG_FIELD_ID(0x8400, 0, 0, 2, 0x1000),
257
258         .wrdma_dyncclk          = REG_FIELD_ID(0xB000, 12, 12, 2, 0x1000),
259         .wrdma_bursten          = REG_FIELD_ID(0xB000, 11, 11, 2, 0x1000),
260         .wrdma_wpscnt           = REG_FIELD_ID(0xB000, 8, 10, 2, 0x1000),
261         .wrdma_intf             = REG_FIELD_ID(0xB000, 4, 7, 2, 0x1000),
262         .wrdma_fifowm           = REG_FIELD_ID(0xB000, 1, 3, 2, 0x1000),
263         .wrdma_enable           = REG_FIELD_ID(0xB000, 0, 0, 2, 0x1000),
264
265         .clk_name               = (const char*[]) {
266                                    "pcnoc-mport-clk",
267                                    "pcnoc-sway-clk",
268                                   },
269         .num_clks               = 2,
270         .dai_driver             = apq8016_lpass_cpu_dai_driver,
271         .num_dai                = ARRAY_SIZE(apq8016_lpass_cpu_dai_driver),
272         .dai_osr_clk_names      = (const char *[]) {
273                                 "mi2s-osr-clk0",
274                                 "mi2s-osr-clk1",
275                                 "mi2s-osr-clk2",
276                                 "mi2s-osr-clk3",
277                                 },
278         .dai_bit_clk_names      = (const char *[]) {
279                                 "mi2s-bit-clk0",
280                                 "mi2s-bit-clk1",
281                                 "mi2s-bit-clk2",
282                                 "mi2s-bit-clk3",
283                                 },
284         .init                   = apq8016_lpass_init,
285         .exit                   = apq8016_lpass_exit,
286         .alloc_dma_channel      = apq8016_lpass_alloc_dma_channel,
287         .free_dma_channel       = apq8016_lpass_free_dma_channel,
288 };
289
290 static const struct of_device_id apq8016_lpass_cpu_device_id[] __maybe_unused = {
291         { .compatible = "qcom,lpass-cpu-apq8016", .data = &apq8016_data },
292         { .compatible = "qcom,apq8016-lpass-cpu", .data = &apq8016_data },
293         {}
294 };
295 MODULE_DEVICE_TABLE(of, apq8016_lpass_cpu_device_id);
296
297 static struct platform_driver apq8016_lpass_cpu_platform_driver = {
298         .driver = {
299                 .name           = "apq8016-lpass-cpu",
300                 .of_match_table = of_match_ptr(apq8016_lpass_cpu_device_id),
301         },
302         .probe  = asoc_qcom_lpass_cpu_platform_probe,
303         .remove_new = asoc_qcom_lpass_cpu_platform_remove,
304 };
305 module_platform_driver(apq8016_lpass_cpu_platform_driver);
306
307 MODULE_DESCRIPTION("APQ8016 LPASS CPU Driver");
308 MODULE_LICENSE("GPL v2");
309