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
29285 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 <drm/display/drm_hdmi_state_helper.h>
16
17
#include "adv7511.h"
18
19
static void adv7511_calc_cts_n(unsigned int f_tmds, unsigned int fs,
20
unsigned int *cts, unsigned int *n)
21
{
22
switch (fs) {
23
case 32000:
24
case 48000:
25
case 96000:
26
case 192000:
27
*n = fs * 128 / 1000;
28
break;
29
case 44100:
30
case 88200:
31
case 176400:
32
*n = fs * 128 / 900;
33
break;
34
}
35
36
*cts = ((f_tmds * *n) / (128 * fs)) * 1000;
37
}
38
39
static int adv7511_update_cts_n(struct adv7511 *adv7511)
40
{
41
unsigned int cts = 0;
42
unsigned int n = 0;
43
44
adv7511_calc_cts_n(adv7511->f_tmds, adv7511->f_audio, &cts, &n);
45
46
regmap_write(adv7511->regmap, ADV7511_REG_N0, (n >> 16) & 0xf);
47
regmap_write(adv7511->regmap, ADV7511_REG_N1, (n >> 8) & 0xff);
48
regmap_write(adv7511->regmap, ADV7511_REG_N2, n & 0xff);
49
50
regmap_write(adv7511->regmap, ADV7511_REG_CTS_MANUAL0,
51
(cts >> 16) & 0xf);
52
regmap_write(adv7511->regmap, ADV7511_REG_CTS_MANUAL1,
53
(cts >> 8) & 0xff);
54
regmap_write(adv7511->regmap, ADV7511_REG_CTS_MANUAL2,
55
cts & 0xff);
56
57
return 0;
58
}
59
60
int adv7511_hdmi_audio_prepare(struct drm_bridge *bridge,
61
struct drm_connector *connector,
62
struct hdmi_codec_daifmt *fmt,
63
struct hdmi_codec_params *hparms)
64
{
65
struct adv7511 *adv7511 = bridge_to_adv7511(bridge);
66
unsigned int audio_source, i2s_format = 0;
67
unsigned int invert_clock;
68
unsigned int rate;
69
unsigned int len;
70
71
switch (hparms->sample_rate) {
72
case 32000:
73
rate = ADV7511_SAMPLE_FREQ_32000;
74
break;
75
case 44100:
76
rate = ADV7511_SAMPLE_FREQ_44100;
77
break;
78
case 48000:
79
rate = ADV7511_SAMPLE_FREQ_48000;
80
break;
81
case 88200:
82
rate = ADV7511_SAMPLE_FREQ_88200;
83
break;
84
case 96000:
85
rate = ADV7511_SAMPLE_FREQ_96000;
86
break;
87
case 176400:
88
rate = ADV7511_SAMPLE_FREQ_176400;
89
break;
90
case 192000:
91
rate = ADV7511_SAMPLE_FREQ_192000;
92
break;
93
default:
94
return -EINVAL;
95
}
96
97
switch (hparms->sample_width) {
98
case 16:
99
len = ADV7511_I2S_SAMPLE_LEN_16;
100
break;
101
case 18:
102
len = ADV7511_I2S_SAMPLE_LEN_18;
103
break;
104
case 20:
105
len = ADV7511_I2S_SAMPLE_LEN_20;
106
break;
107
case 32:
108
if (fmt->bit_fmt != SNDRV_PCM_FORMAT_IEC958_SUBFRAME_LE)
109
return -EINVAL;
110
fallthrough;
111
case 24:
112
len = ADV7511_I2S_SAMPLE_LEN_24;
113
break;
114
default:
115
return -EINVAL;
116
}
117
118
switch (fmt->fmt) {
119
case HDMI_I2S:
120
audio_source = ADV7511_AUDIO_SOURCE_I2S;
121
i2s_format = ADV7511_I2S_FORMAT_I2S;
122
if (fmt->bit_fmt == SNDRV_PCM_FORMAT_IEC958_SUBFRAME_LE)
123
i2s_format = ADV7511_I2S_IEC958_DIRECT;
124
break;
125
case HDMI_RIGHT_J:
126
audio_source = ADV7511_AUDIO_SOURCE_I2S;
127
i2s_format = ADV7511_I2S_FORMAT_RIGHT_J;
128
break;
129
case HDMI_LEFT_J:
130
audio_source = ADV7511_AUDIO_SOURCE_I2S;
131
i2s_format = ADV7511_I2S_FORMAT_LEFT_J;
132
break;
133
case HDMI_SPDIF:
134
audio_source = ADV7511_AUDIO_SOURCE_SPDIF;
135
break;
136
default:
137
return -EINVAL;
138
}
139
140
invert_clock = fmt->bit_clk_inv;
141
142
regmap_update_bits(adv7511->regmap, ADV7511_REG_AUDIO_SOURCE, 0x70,
143
audio_source << 4);
144
regmap_update_bits(adv7511->regmap, ADV7511_REG_AUDIO_CONFIG, BIT(6),
145
invert_clock << 6);
146
regmap_update_bits(adv7511->regmap, ADV7511_REG_I2S_CONFIG, 0x03,
147
i2s_format);
148
149
adv7511->audio_source = audio_source;
150
151
adv7511->f_audio = hparms->sample_rate;
152
153
adv7511_update_cts_n(adv7511);
154
155
regmap_update_bits(adv7511->regmap, ADV7511_REG_AUDIO_CFG3,
156
ADV7511_AUDIO_CFG3_LEN_MASK, len);
157
regmap_update_bits(adv7511->regmap, ADV7511_REG_I2C_FREQ_ID_CFG,
158
ADV7511_I2C_FREQ_ID_CFG_RATE_MASK, rate << 4);
159
160
return drm_atomic_helper_connector_hdmi_update_audio_infoframe(connector,
161
&hparms->cea);
162
}
163
164
int adv7511_hdmi_audio_startup(struct drm_bridge *bridge,
165
struct drm_connector *connector)
166
{
167
struct adv7511 *adv7511 = bridge_to_adv7511(bridge);
168
169
regmap_update_bits(adv7511->regmap, ADV7511_REG_AUDIO_CONFIG,
170
BIT(7), 0);
171
172
/* hide Audio infoframe updates */
173
regmap_update_bits(adv7511->regmap, ADV7511_REG_INFOFRAME_UPDATE,
174
BIT(5), BIT(5));
175
/* enable N/CTS, enable Audio sample packets */
176
regmap_update_bits(adv7511->regmap, ADV7511_REG_PACKET_ENABLE1,
177
BIT(5), BIT(5));
178
/* enable N/CTS */
179
regmap_update_bits(adv7511->regmap, ADV7511_REG_PACKET_ENABLE1,
180
BIT(6), BIT(6));
181
/* not copyrighted */
182
regmap_update_bits(adv7511->regmap, ADV7511_REG_AUDIO_CFG1,
183
BIT(5), BIT(5));
184
/* AV mute disable */
185
regmap_update_bits(adv7511->regmap, ADV7511_REG_GC(0),
186
BIT(7) | BIT(6), BIT(7));
187
188
/* enable SPDIF receiver */
189
if (adv7511->audio_source == ADV7511_AUDIO_SOURCE_SPDIF)
190
regmap_update_bits(adv7511->regmap, ADV7511_REG_AUDIO_CONFIG,
191
BIT(7), BIT(7));
192
193
return 0;
194
}
195
196
void adv7511_hdmi_audio_shutdown(struct drm_bridge *bridge,
197
struct drm_connector *connector)
198
{
199
struct adv7511 *adv7511 = bridge_to_adv7511(bridge);
200
201
if (adv7511->audio_source == ADV7511_AUDIO_SOURCE_SPDIF)
202
regmap_update_bits(adv7511->regmap, ADV7511_REG_AUDIO_CONFIG,
203
BIT(7), 0);
204
205
drm_atomic_helper_connector_hdmi_clear_audio_infoframe(connector);
206
}
207
208