Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
torvalds
GitHub Repository: torvalds/linux
Path: blob/master/drivers/gpu/drm/bridge/adv7511/adv7511_audio.c
26516 views
1
// SPDX-License-Identifier: GPL-2.0-only
2
/*
3
* Analog Devices ADV7511 HDMI transmitter driver
4
*
5
* Copyright 2012 Analog Devices Inc.
6
* Copyright (c) 2016, Linaro Limited
7
*/
8
9
#include <sound/core.h>
10
#include <sound/hdmi-codec.h>
11
#include <sound/pcm.h>
12
#include <sound/soc.h>
13
#include <linux/of_graph.h>
14
15
#include "adv7511.h"
16
17
static void adv7511_calc_cts_n(unsigned int f_tmds, unsigned int fs,
18
unsigned int *cts, unsigned int *n)
19
{
20
switch (fs) {
21
case 32000:
22
case 48000:
23
case 96000:
24
case 192000:
25
*n = fs * 128 / 1000;
26
break;
27
case 44100:
28
case 88200:
29
case 176400:
30
*n = fs * 128 / 900;
31
break;
32
}
33
34
*cts = ((f_tmds * *n) / (128 * fs)) * 1000;
35
}
36
37
static int adv7511_update_cts_n(struct adv7511 *adv7511)
38
{
39
unsigned int cts = 0;
40
unsigned int n = 0;
41
42
adv7511_calc_cts_n(adv7511->f_tmds, adv7511->f_audio, &cts, &n);
43
44
regmap_write(adv7511->regmap, ADV7511_REG_N0, (n >> 16) & 0xf);
45
regmap_write(adv7511->regmap, ADV7511_REG_N1, (n >> 8) & 0xff);
46
regmap_write(adv7511->regmap, ADV7511_REG_N2, n & 0xff);
47
48
regmap_write(adv7511->regmap, ADV7511_REG_CTS_MANUAL0,
49
(cts >> 16) & 0xf);
50
regmap_write(adv7511->regmap, ADV7511_REG_CTS_MANUAL1,
51
(cts >> 8) & 0xff);
52
regmap_write(adv7511->regmap, ADV7511_REG_CTS_MANUAL2,
53
cts & 0xff);
54
55
return 0;
56
}
57
58
int adv7511_hdmi_audio_prepare(struct drm_bridge *bridge,
59
struct drm_connector *connector,
60
struct hdmi_codec_daifmt *fmt,
61
struct hdmi_codec_params *hparms)
62
{
63
struct adv7511 *adv7511 = bridge_to_adv7511(bridge);
64
unsigned int audio_source, i2s_format = 0;
65
unsigned int invert_clock;
66
unsigned int rate;
67
unsigned int len;
68
69
switch (hparms->sample_rate) {
70
case 32000:
71
rate = ADV7511_SAMPLE_FREQ_32000;
72
break;
73
case 44100:
74
rate = ADV7511_SAMPLE_FREQ_44100;
75
break;
76
case 48000:
77
rate = ADV7511_SAMPLE_FREQ_48000;
78
break;
79
case 88200:
80
rate = ADV7511_SAMPLE_FREQ_88200;
81
break;
82
case 96000:
83
rate = ADV7511_SAMPLE_FREQ_96000;
84
break;
85
case 176400:
86
rate = ADV7511_SAMPLE_FREQ_176400;
87
break;
88
case 192000:
89
rate = ADV7511_SAMPLE_FREQ_192000;
90
break;
91
default:
92
return -EINVAL;
93
}
94
95
switch (hparms->sample_width) {
96
case 16:
97
len = ADV7511_I2S_SAMPLE_LEN_16;
98
break;
99
case 18:
100
len = ADV7511_I2S_SAMPLE_LEN_18;
101
break;
102
case 20:
103
len = ADV7511_I2S_SAMPLE_LEN_20;
104
break;
105
case 32:
106
if (fmt->bit_fmt != SNDRV_PCM_FORMAT_IEC958_SUBFRAME_LE)
107
return -EINVAL;
108
fallthrough;
109
case 24:
110
len = ADV7511_I2S_SAMPLE_LEN_24;
111
break;
112
default:
113
return -EINVAL;
114
}
115
116
switch (fmt->fmt) {
117
case HDMI_I2S:
118
audio_source = ADV7511_AUDIO_SOURCE_I2S;
119
i2s_format = ADV7511_I2S_FORMAT_I2S;
120
if (fmt->bit_fmt == SNDRV_PCM_FORMAT_IEC958_SUBFRAME_LE)
121
i2s_format = ADV7511_I2S_IEC958_DIRECT;
122
break;
123
case HDMI_RIGHT_J:
124
audio_source = ADV7511_AUDIO_SOURCE_I2S;
125
i2s_format = ADV7511_I2S_FORMAT_RIGHT_J;
126
break;
127
case HDMI_LEFT_J:
128
audio_source = ADV7511_AUDIO_SOURCE_I2S;
129
i2s_format = ADV7511_I2S_FORMAT_LEFT_J;
130
break;
131
case HDMI_SPDIF:
132
audio_source = ADV7511_AUDIO_SOURCE_SPDIF;
133
break;
134
default:
135
return -EINVAL;
136
}
137
138
invert_clock = fmt->bit_clk_inv;
139
140
regmap_update_bits(adv7511->regmap, ADV7511_REG_AUDIO_SOURCE, 0x70,
141
audio_source << 4);
142
regmap_update_bits(adv7511->regmap, ADV7511_REG_AUDIO_CONFIG, BIT(6),
143
invert_clock << 6);
144
regmap_update_bits(adv7511->regmap, ADV7511_REG_I2S_CONFIG, 0x03,
145
i2s_format);
146
147
adv7511->audio_source = audio_source;
148
149
adv7511->f_audio = hparms->sample_rate;
150
151
adv7511_update_cts_n(adv7511);
152
153
regmap_update_bits(adv7511->regmap, ADV7511_REG_AUDIO_CFG3,
154
ADV7511_AUDIO_CFG3_LEN_MASK, len);
155
regmap_update_bits(adv7511->regmap, ADV7511_REG_I2C_FREQ_ID_CFG,
156
ADV7511_I2C_FREQ_ID_CFG_RATE_MASK, rate << 4);
157
158
/* send current Audio infoframe values while updating */
159
regmap_update_bits(adv7511->regmap, ADV7511_REG_INFOFRAME_UPDATE,
160
BIT(5), BIT(5));
161
162
regmap_write(adv7511->regmap, ADV7511_REG_AUDIO_INFOFRAME(0), 0x1);
163
164
/* use Audio infoframe updated info */
165
regmap_update_bits(adv7511->regmap, ADV7511_REG_INFOFRAME_UPDATE,
166
BIT(5), 0);
167
168
return 0;
169
}
170
171
int adv7511_hdmi_audio_startup(struct drm_bridge *bridge,
172
struct drm_connector *connector)
173
{
174
struct adv7511 *adv7511 = bridge_to_adv7511(bridge);
175
176
regmap_update_bits(adv7511->regmap, ADV7511_REG_AUDIO_CONFIG,
177
BIT(7), 0);
178
179
/* hide Audio infoframe updates */
180
regmap_update_bits(adv7511->regmap, ADV7511_REG_INFOFRAME_UPDATE,
181
BIT(5), BIT(5));
182
/* enable N/CTS, enable Audio sample packets */
183
regmap_update_bits(adv7511->regmap, ADV7511_REG_PACKET_ENABLE1,
184
BIT(5), BIT(5));
185
/* enable N/CTS */
186
regmap_update_bits(adv7511->regmap, ADV7511_REG_PACKET_ENABLE1,
187
BIT(6), BIT(6));
188
/* not copyrighted */
189
regmap_update_bits(adv7511->regmap, ADV7511_REG_AUDIO_CFG1,
190
BIT(5), BIT(5));
191
/* enable audio infoframes */
192
regmap_update_bits(adv7511->regmap, ADV7511_REG_PACKET_ENABLE1,
193
BIT(3), BIT(3));
194
/* AV mute disable */
195
regmap_update_bits(adv7511->regmap, ADV7511_REG_GC(0),
196
BIT(7) | BIT(6), BIT(7));
197
/* use Audio infoframe updated info */
198
regmap_update_bits(adv7511->regmap, ADV7511_REG_INFOFRAME_UPDATE,
199
BIT(5), 0);
200
201
/* enable SPDIF receiver */
202
if (adv7511->audio_source == ADV7511_AUDIO_SOURCE_SPDIF)
203
regmap_update_bits(adv7511->regmap, ADV7511_REG_AUDIO_CONFIG,
204
BIT(7), BIT(7));
205
206
return 0;
207
}
208
209
void adv7511_hdmi_audio_shutdown(struct drm_bridge *bridge,
210
struct drm_connector *connector)
211
{
212
struct adv7511 *adv7511 = bridge_to_adv7511(bridge);
213
214
if (adv7511->audio_source == ADV7511_AUDIO_SOURCE_SPDIF)
215
regmap_update_bits(adv7511->regmap, ADV7511_REG_AUDIO_CONFIG,
216
BIT(7), 0);
217
}
218
219