1 // SPDX-License-Identifier: GPL-2.0-only
3 * Copyright (c) 2020, The Linux Foundation. All rights reserved.
5 * lpass-sc7180.c -- ALSA SoC platform-machine driver for QTi LPASS
9 #include <linux/device.h>
10 #include <linux/err.h>
11 #include <linux/kernel.h>
12 #include <linux/module.h>
14 #include <linux/platform_device.h>
15 #include <dt-bindings/sound/sc7180-lpass.h>
16 #include <sound/pcm.h>
17 #include <sound/soc.h>
19 #include "lpass-lpaif-reg.h"
22 static struct snd_soc_dai_driver sc7180_lpass_cpu_dai_driver
[] = {
25 .name
= "Primary MI2S",
27 .stream_name
= "Primary Playback",
28 .formats
= SNDRV_PCM_FMTBIT_S16
,
29 .rates
= SNDRV_PCM_RATE_48000
,
36 .stream_name
= "Primary Capture",
37 .formats
= SNDRV_PCM_FMTBIT_S16
|
39 .rates
= SNDRV_PCM_RATE_48000
,
45 .probe
= &asoc_qcom_lpass_cpu_dai_probe
,
46 .ops
= &asoc_qcom_lpass_cpu_dai_ops
,
51 .name
= "Secondary MI2S",
53 .stream_name
= "Secondary Playback",
54 .formats
= SNDRV_PCM_FMTBIT_S16
,
55 .rates
= SNDRV_PCM_RATE_48000
,
61 .probe
= &asoc_qcom_lpass_cpu_dai_probe
,
62 .ops
= &asoc_qcom_lpass_cpu_dai_ops
,
68 .stream_name
= "Hdmi Playback",
69 .formats
= SNDRV_PCM_FMTBIT_S24
,
70 .rates
= SNDRV_PCM_RATE_48000
,
76 .ops
= &asoc_qcom_lpass_hdmi_dai_ops
,
80 static int sc7180_lpass_alloc_dma_channel(struct lpass_data
*drvdata
,
81 int direction
, unsigned int dai_id
)
83 struct lpass_variant
*v
= drvdata
->variant
;
86 if (dai_id
== LPASS_DP_RX
) {
87 if (direction
== SNDRV_PCM_STREAM_PLAYBACK
) {
88 chan
= find_first_zero_bit(&drvdata
->hdmi_dma_ch_bit_map
,
89 v
->hdmi_rdma_channels
);
91 if (chan
>= v
->hdmi_rdma_channels
)
94 set_bit(chan
, &drvdata
->hdmi_dma_ch_bit_map
);
96 if (direction
== SNDRV_PCM_STREAM_PLAYBACK
) {
97 chan
= find_first_zero_bit(&drvdata
->dma_ch_bit_map
,
100 if (chan
>= v
->rdma_channels
)
103 chan
= find_next_zero_bit(&drvdata
->dma_ch_bit_map
,
104 v
->wrdma_channel_start
+
106 v
->wrdma_channel_start
);
108 if (chan
>= v
->wrdma_channel_start
+ v
->wrdma_channels
)
112 set_bit(chan
, &drvdata
->dma_ch_bit_map
);
117 static int sc7180_lpass_free_dma_channel(struct lpass_data
*drvdata
, int chan
, unsigned int dai_id
)
119 if (dai_id
== LPASS_DP_RX
)
120 clear_bit(chan
, &drvdata
->hdmi_dma_ch_bit_map
);
122 clear_bit(chan
, &drvdata
->dma_ch_bit_map
);
127 static int sc7180_lpass_init(struct platform_device
*pdev
)
129 struct lpass_data
*drvdata
= platform_get_drvdata(pdev
);
130 struct lpass_variant
*variant
= drvdata
->variant
;
131 struct device
*dev
= &pdev
->dev
;
134 drvdata
->clks
= devm_kcalloc(dev
, variant
->num_clks
,
135 sizeof(*drvdata
->clks
), GFP_KERNEL
);
136 drvdata
->num_clks
= variant
->num_clks
;
138 for (i
= 0; i
< drvdata
->num_clks
; i
++)
139 drvdata
->clks
[i
].id
= variant
->clk_name
[i
];
141 ret
= devm_clk_bulk_get(dev
, drvdata
->num_clks
, drvdata
->clks
);
143 dev_err(dev
, "Failed to get clocks %d\n", ret
);
147 ret
= clk_bulk_prepare_enable(drvdata
->num_clks
, drvdata
->clks
);
149 dev_err(dev
, "sc7180 clk_enable failed\n");
156 static int sc7180_lpass_exit(struct platform_device
*pdev
)
158 struct lpass_data
*drvdata
= platform_get_drvdata(pdev
);
160 clk_bulk_disable_unprepare(drvdata
->num_clks
, drvdata
->clks
);
165 static struct lpass_variant sc7180_data
= {
166 .i2sctrl_reg_base
= 0x1000,
167 .i2sctrl_reg_stride
= 0x1000,
169 .irq_reg_base
= 0x9000,
170 .irq_reg_stride
= 0x1000,
172 .rdma_reg_base
= 0xC000,
173 .rdma_reg_stride
= 0x1000,
175 .hdmi_rdma_reg_base
= 0x64000,
176 .hdmi_rdma_reg_stride
= 0x1000,
177 .hdmi_rdma_channels
= 4,
178 .dmactl_audif_start
= 1,
179 .wrdma_reg_base
= 0x18000,
180 .wrdma_reg_stride
= 0x1000,
181 .wrdma_channel_start
= 5,
184 .loopback
= REG_FIELD_ID(0x1000, 17, 17, 3, 0x1000),
185 .spken
= REG_FIELD_ID(0x1000, 16, 16, 3, 0x1000),
186 .spkmode
= REG_FIELD_ID(0x1000, 11, 15, 3, 0x1000),
187 .spkmono
= REG_FIELD_ID(0x1000, 10, 10, 3, 0x1000),
188 .micen
= REG_FIELD_ID(0x1000, 9, 9, 3, 0x1000),
189 .micmode
= REG_FIELD_ID(0x1000, 4, 8, 3, 0x1000),
190 .micmono
= REG_FIELD_ID(0x1000, 3, 3, 3, 0x1000),
191 .wssrc
= REG_FIELD_ID(0x1000, 2, 2, 3, 0x1000),
192 .bitwidth
= REG_FIELD_ID(0x1000, 0, 1, 3, 0x1000),
194 .rdma_dyncclk
= REG_FIELD_ID(0xC000, 21, 21, 5, 0x1000),
195 .rdma_bursten
= REG_FIELD_ID(0xC000, 20, 20, 5, 0x1000),
196 .rdma_wpscnt
= REG_FIELD_ID(0xC000, 16, 19, 5, 0x1000),
197 .rdma_intf
= REG_FIELD_ID(0xC000, 12, 15, 5, 0x1000),
198 .rdma_fifowm
= REG_FIELD_ID(0xC000, 1, 5, 5, 0x1000),
199 .rdma_enable
= REG_FIELD_ID(0xC000, 0, 0, 5, 0x1000),
201 .wrdma_dyncclk
= REG_FIELD_ID(0x18000, 22, 22, 4, 0x1000),
202 .wrdma_bursten
= REG_FIELD_ID(0x18000, 21, 21, 4, 0x1000),
203 .wrdma_wpscnt
= REG_FIELD_ID(0x18000, 17, 20, 4, 0x1000),
204 .wrdma_intf
= REG_FIELD_ID(0x18000, 12, 16, 4, 0x1000),
205 .wrdma_fifowm
= REG_FIELD_ID(0x18000, 1, 5, 4, 0x1000),
206 .wrdma_enable
= REG_FIELD_ID(0x18000, 0, 0, 4, 0x1000),
208 .hdmi_tx_ctl_addr
= 0x1000,
209 .hdmi_legacy_addr
= 0x1008,
210 .hdmi_vbit_addr
= 0x610c0,
211 .hdmi_ch_lsb_addr
= 0x61048,
212 .hdmi_ch_msb_addr
= 0x6104c,
214 .hdmi_parity_addr
= 0x61034,
215 .hdmi_dmactl_addr
= 0x61038,
216 .hdmi_dma_stride
= 0x4,
217 .hdmi_DP_addr
= 0x610c8,
218 .hdmi_sstream_addr
= 0x6101c,
219 .hdmi_irq_reg_base
= 0x63000,
222 .hdmi_rdma_dyncclk
= REG_FIELD_ID(0x64000, 14, 14, 4, 0x1000),
223 .hdmi_rdma_bursten
= REG_FIELD_ID(0x64000, 13, 13, 4, 0x1000),
224 .hdmi_rdma_burst8
= REG_FIELD_ID(0x64000, 15, 15, 4, 0x1000),
225 .hdmi_rdma_burst16
= REG_FIELD_ID(0x64000, 16, 16, 4, 0x1000),
226 .hdmi_rdma_dynburst
= REG_FIELD_ID(0x64000, 18, 18, 4, 0x1000),
227 .hdmi_rdma_wpscnt
= REG_FIELD_ID(0x64000, 10, 12, 4, 0x1000),
228 .hdmi_rdma_fifowm
= REG_FIELD_ID(0x64000, 1, 5, 4, 0x1000),
229 .hdmi_rdma_enable
= REG_FIELD_ID(0x64000, 0, 0, 4, 0x1000),
231 .sstream_en
= REG_FIELD(0x6101c, 0, 0),
232 .dma_sel
= REG_FIELD(0x6101c, 1, 2),
233 .auto_bbit_en
= REG_FIELD(0x6101c, 3, 3),
234 .layout
= REG_FIELD(0x6101c, 4, 4),
235 .layout_sp
= REG_FIELD(0x6101c, 5, 8),
236 .set_sp_on_en
= REG_FIELD(0x6101c, 10, 10),
237 .dp_audio
= REG_FIELD(0x6101c, 11, 11),
238 .dp_staffing_en
= REG_FIELD(0x6101c, 12, 12),
239 .dp_sp_b_hw_en
= REG_FIELD(0x6101c, 13, 13),
241 .mute
= REG_FIELD(0x610c8, 0, 0),
242 .as_sdp_cc
= REG_FIELD(0x610c8, 1, 3),
243 .as_sdp_ct
= REG_FIELD(0x610c8, 4, 7),
244 .aif_db4
= REG_FIELD(0x610c8, 8, 15),
245 .frequency
= REG_FIELD(0x610c8, 16, 21),
246 .mst_index
= REG_FIELD(0x610c8, 28, 29),
247 .dptx_index
= REG_FIELD(0x610c8, 30, 31),
249 .soft_reset
= REG_FIELD(0x1000, 31, 31),
250 .force_reset
= REG_FIELD(0x1000, 30, 30),
252 .use_hw_chs
= REG_FIELD(0x61038, 0, 0),
253 .use_hw_usr
= REG_FIELD(0x61038, 1, 1),
254 .hw_chs_sel
= REG_FIELD(0x61038, 2, 4),
255 .hw_usr_sel
= REG_FIELD(0x61038, 5, 6),
257 .replace_vbit
= REG_FIELD(0x610c0, 0, 0),
258 .vbit_stream
= REG_FIELD(0x610c0, 1, 1),
260 .legacy_en
= REG_FIELD(0x1008, 0, 0),
261 .calc_en
= REG_FIELD(0x61034, 0, 0),
262 .lsb_bits
= REG_FIELD(0x61048, 0, 31),
263 .msb_bits
= REG_FIELD(0x6104c, 0, 31),
266 .clk_name
= (const char*[]) {
272 .dai_driver
= sc7180_lpass_cpu_dai_driver
,
273 .num_dai
= ARRAY_SIZE(sc7180_lpass_cpu_dai_driver
),
274 .dai_osr_clk_names
= (const char *[]) {
278 .dai_bit_clk_names
= (const char *[]) {
282 .init
= sc7180_lpass_init
,
283 .exit
= sc7180_lpass_exit
,
284 .alloc_dma_channel
= sc7180_lpass_alloc_dma_channel
,
285 .free_dma_channel
= sc7180_lpass_free_dma_channel
,
288 static const struct of_device_id sc7180_lpass_cpu_device_id
[] __maybe_unused
= {
289 {.compatible
= "qcom,sc7180-lpass-cpu", .data
= &sc7180_data
},
292 MODULE_DEVICE_TABLE(of
, sc7180_lpass_cpu_device_id
);
294 static struct platform_driver sc7180_lpass_cpu_platform_driver
= {
296 .name
= "sc7180-lpass-cpu",
297 .of_match_table
= of_match_ptr(sc7180_lpass_cpu_device_id
),
299 .probe
= asoc_qcom_lpass_cpu_platform_probe
,
300 .remove
= asoc_qcom_lpass_cpu_platform_remove
,
301 .shutdown
= asoc_qcom_lpass_cpu_platform_shutdown
,
304 module_platform_driver(sc7180_lpass_cpu_platform_driver
);
306 MODULE_DESCRIPTION("SC7180 LPASS CPU DRIVER");
307 MODULE_LICENSE("GPL v2");