Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
torvalds
GitHub Repository: torvalds/linux
Path: blob/master/sound/soc/qcom/lpass-hdmi.c
26428 views
1
// SPDX-License-Identifier: GPL-2.0-only
2
/*
3
* Copyright (c) 2020 The Linux Foundation. All rights reserved.
4
*
5
* lpass-hdmi.c -- ALSA SoC HDMI-CPU DAI driver for QTi LPASS HDMI
6
*/
7
8
9
#include <linux/kernel.h>
10
#include <linux/module.h>
11
#include <sound/pcm_params.h>
12
#include <linux/regmap.h>
13
#include <sound/soc.h>
14
#include <sound/soc-dai.h>
15
#include <dt-bindings/sound/sc7180-lpass.h>
16
#include "lpass-lpaif-reg.h"
17
#include "lpass.h"
18
19
static int lpass_hdmi_daiops_hw_params(struct snd_pcm_substream *substream,
20
struct snd_pcm_hw_params *params, struct snd_soc_dai *dai)
21
{
22
struct lpass_data *drvdata = snd_soc_dai_get_drvdata(dai);
23
snd_pcm_format_t format = params_format(params);
24
unsigned int rate = params_rate(params);
25
unsigned int channels = params_channels(params);
26
unsigned int ret;
27
int bitwidth;
28
unsigned int word_length;
29
unsigned int ch_sts_buf0;
30
unsigned int ch_sts_buf1;
31
unsigned int data_format;
32
unsigned int sampling_freq;
33
unsigned int ch = 0;
34
struct lpass_dp_metadata_ctl *meta_ctl = drvdata->meta_ctl;
35
struct lpass_sstream_ctl *sstream_ctl = drvdata->sstream_ctl;
36
37
bitwidth = snd_pcm_format_width(format);
38
if (bitwidth < 0) {
39
dev_err(dai->dev, "%s invalid bit width given : %d\n",
40
__func__, bitwidth);
41
return bitwidth;
42
}
43
44
switch (bitwidth) {
45
case 16:
46
word_length = LPASS_DP_AUDIO_BITWIDTH16;
47
break;
48
case 24:
49
word_length = LPASS_DP_AUDIO_BITWIDTH24;
50
break;
51
default:
52
dev_err(dai->dev, "%s invalid bit width given : %d\n",
53
__func__, bitwidth);
54
return -EINVAL;
55
}
56
57
switch (rate) {
58
case 32000:
59
sampling_freq = LPASS_SAMPLING_FREQ32;
60
break;
61
case 44100:
62
sampling_freq = LPASS_SAMPLING_FREQ44;
63
break;
64
case 48000:
65
sampling_freq = LPASS_SAMPLING_FREQ48;
66
break;
67
default:
68
dev_err(dai->dev, "%s invalid bit width given : %d\n",
69
__func__, bitwidth);
70
return -EINVAL;
71
}
72
data_format = LPASS_DATA_FORMAT_LINEAR;
73
ch_sts_buf0 = (((data_format << LPASS_DATA_FORMAT_SHIFT) & LPASS_DATA_FORMAT_MASK)
74
| ((sampling_freq << LPASS_FREQ_BIT_SHIFT) & LPASS_FREQ_BIT_MASK));
75
ch_sts_buf1 = (word_length) & LPASS_WORDLENGTH_MASK;
76
77
ret = regmap_field_write(drvdata->tx_ctl->soft_reset, LPASS_TX_CTL_RESET);
78
if (ret)
79
return ret;
80
81
ret = regmap_field_write(drvdata->tx_ctl->soft_reset, LPASS_TX_CTL_CLEAR);
82
if (ret)
83
return ret;
84
85
ret = regmap_field_write(drvdata->hdmitx_legacy_en, LPASS_HDMITX_LEGACY_DISABLE);
86
if (ret)
87
return ret;
88
89
ret = regmap_field_write(drvdata->hdmitx_parity_calc_en, HDMITX_PARITY_CALC_EN);
90
if (ret)
91
return ret;
92
93
ret = regmap_field_write(drvdata->vbit_ctl->replace_vbit, REPLACE_VBIT);
94
if (ret)
95
return ret;
96
97
ret = regmap_field_write(drvdata->vbit_ctl->vbit_stream, LINEAR_PCM_DATA);
98
if (ret)
99
return ret;
100
101
ret = regmap_field_write(drvdata->hdmitx_ch_msb[0], ch_sts_buf1);
102
if (ret)
103
return ret;
104
105
ret = regmap_field_write(drvdata->hdmitx_ch_lsb[0], ch_sts_buf0);
106
if (ret)
107
return ret;
108
109
ret = regmap_field_write(drvdata->hdmi_tx_dmactl[0]->use_hw_chs, HW_MODE);
110
if (ret)
111
return ret;
112
113
ret = regmap_field_write(drvdata->hdmi_tx_dmactl[0]->hw_chs_sel, SW_MODE);
114
if (ret)
115
return ret;
116
117
ret = regmap_field_write(drvdata->hdmi_tx_dmactl[0]->use_hw_usr, HW_MODE);
118
if (ret)
119
return ret;
120
121
ret = regmap_field_write(drvdata->hdmi_tx_dmactl[0]->hw_usr_sel, SW_MODE);
122
if (ret)
123
return ret;
124
125
ret = regmap_field_write(meta_ctl->mute, LPASS_MUTE_ENABLE);
126
if (ret)
127
return ret;
128
129
ret = regmap_field_write(meta_ctl->as_sdp_cc, channels - 1);
130
if (ret)
131
return ret;
132
133
ret = regmap_field_write(meta_ctl->as_sdp_ct, LPASS_META_DEFAULT_VAL);
134
if (ret)
135
return ret;
136
137
ret = regmap_field_write(meta_ctl->aif_db4, LPASS_META_DEFAULT_VAL);
138
if (ret)
139
return ret;
140
141
ret = regmap_field_write(meta_ctl->frequency, sampling_freq);
142
if (ret)
143
return ret;
144
145
ret = regmap_field_write(meta_ctl->mst_index, LPASS_META_DEFAULT_VAL);
146
if (ret)
147
return ret;
148
149
ret = regmap_field_write(meta_ctl->dptx_index, LPASS_META_DEFAULT_VAL);
150
if (ret)
151
return ret;
152
153
ret = regmap_field_write(sstream_ctl->sstream_en, LPASS_SSTREAM_DISABLE);
154
if (ret)
155
return ret;
156
157
ret = regmap_field_write(sstream_ctl->dma_sel, ch);
158
if (ret)
159
return ret;
160
161
ret = regmap_field_write(sstream_ctl->auto_bbit_en, LPASS_SSTREAM_DEFAULT_ENABLE);
162
if (ret)
163
return ret;
164
165
ret = regmap_field_write(sstream_ctl->layout, LPASS_SSTREAM_DEFAULT_DISABLE);
166
if (ret)
167
return ret;
168
169
ret = regmap_field_write(sstream_ctl->layout_sp, LPASS_LAYOUT_SP_DEFAULT);
170
if (ret)
171
return ret;
172
173
ret = regmap_field_write(sstream_ctl->dp_audio, LPASS_SSTREAM_DEFAULT_ENABLE);
174
if (ret)
175
return ret;
176
177
ret = regmap_field_write(sstream_ctl->set_sp_on_en, LPASS_SSTREAM_DEFAULT_ENABLE);
178
if (ret)
179
return ret;
180
181
ret = regmap_field_write(sstream_ctl->dp_sp_b_hw_en, LPASS_SSTREAM_DEFAULT_ENABLE);
182
if (ret)
183
return ret;
184
185
ret = regmap_field_write(sstream_ctl->dp_staffing_en, LPASS_SSTREAM_DEFAULT_ENABLE);
186
187
return ret;
188
}
189
190
static int lpass_hdmi_daiops_prepare(struct snd_pcm_substream *substream,
191
struct snd_soc_dai *dai)
192
{
193
int ret;
194
struct lpass_data *drvdata = snd_soc_dai_get_drvdata(dai);
195
196
ret = regmap_field_write(drvdata->sstream_ctl->sstream_en, LPASS_SSTREAM_ENABLE);
197
if (ret)
198
return ret;
199
200
ret = regmap_field_write(drvdata->meta_ctl->mute, LPASS_MUTE_DISABLE);
201
202
return ret;
203
}
204
205
static int lpass_hdmi_daiops_trigger(struct snd_pcm_substream *substream,
206
int cmd, struct snd_soc_dai *dai)
207
{
208
struct lpass_data *drvdata = snd_soc_dai_get_drvdata(dai);
209
struct lpass_dp_metadata_ctl *meta_ctl = drvdata->meta_ctl;
210
struct lpass_sstream_ctl *sstream_ctl = drvdata->sstream_ctl;
211
int ret = -EINVAL;
212
213
switch (cmd) {
214
case SNDRV_PCM_TRIGGER_START:
215
case SNDRV_PCM_TRIGGER_RESUME:
216
case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
217
ret = regmap_field_write(sstream_ctl->sstream_en, LPASS_SSTREAM_ENABLE);
218
if (ret)
219
return ret;
220
221
ret = regmap_field_write(meta_ctl->mute, LPASS_MUTE_DISABLE);
222
if (ret)
223
return ret;
224
225
break;
226
case SNDRV_PCM_TRIGGER_STOP:
227
case SNDRV_PCM_TRIGGER_SUSPEND:
228
case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
229
ret = regmap_field_write(sstream_ctl->sstream_en, LPASS_SSTREAM_DISABLE);
230
if (ret)
231
return ret;
232
233
ret = regmap_field_write(meta_ctl->mute, LPASS_MUTE_ENABLE);
234
if (ret)
235
return ret;
236
237
ret = regmap_field_write(sstream_ctl->dp_audio, 0);
238
if (ret)
239
return ret;
240
241
break;
242
}
243
return ret;
244
}
245
246
const struct snd_soc_dai_ops asoc_qcom_lpass_hdmi_dai_ops = {
247
.hw_params = lpass_hdmi_daiops_hw_params,
248
.prepare = lpass_hdmi_daiops_prepare,
249
.trigger = lpass_hdmi_daiops_trigger,
250
};
251
EXPORT_SYMBOL_GPL(asoc_qcom_lpass_hdmi_dai_ops);
252
253
MODULE_DESCRIPTION("QTi LPASS HDMI Driver");
254
MODULE_LICENSE("GPL");
255
256