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
19static 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
39static 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(f_tmds: adv7511->f_tmds, fs: adv7511->f_audio, cts: &cts, n: &n);
45
46 regmap_write(map: adv7511->regmap, ADV7511_REG_N0, val: (n >> 16) & 0xf);
47 regmap_write(map: adv7511->regmap, ADV7511_REG_N1, val: (n >> 8) & 0xff);
48 regmap_write(map: adv7511->regmap, ADV7511_REG_N2, val: n & 0xff);
49
50 regmap_write(map: adv7511->regmap, ADV7511_REG_CTS_MANUAL0,
51 val: (cts >> 16) & 0xf);
52 regmap_write(map: adv7511->regmap, ADV7511_REG_CTS_MANUAL1,
53 val: (cts >> 8) & 0xff);
54 regmap_write(map: adv7511->regmap, ADV7511_REG_CTS_MANUAL2,
55 val: cts & 0xff);
56
57 return 0;
58}
59
60int 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(map: adv7511->regmap, ADV7511_REG_AUDIO_SOURCE, mask: 0x70,
143 val: audio_source << 4);
144 regmap_update_bits(map: adv7511->regmap, ADV7511_REG_AUDIO_CONFIG, BIT(6),
145 val: invert_clock << 6);
146 regmap_update_bits(map: adv7511->regmap, ADV7511_REG_I2S_CONFIG, mask: 0x03,
147 val: 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(map: adv7511->regmap, ADV7511_REG_AUDIO_CFG3,
156 ADV7511_AUDIO_CFG3_LEN_MASK, val: len);
157 regmap_update_bits(map: adv7511->regmap, ADV7511_REG_I2C_FREQ_ID_CFG,
158 ADV7511_I2C_FREQ_ID_CFG_RATE_MASK, val: rate << 4);
159
160 return drm_atomic_helper_connector_hdmi_update_audio_infoframe(connector,
161 frame: &hparms->cea);
162}
163
164int 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(map: adv7511->regmap, ADV7511_REG_AUDIO_CONFIG,
170 BIT(7), val: 0);
171
172 /* hide Audio infoframe updates */
173 regmap_update_bits(map: adv7511->regmap, ADV7511_REG_INFOFRAME_UPDATE,
174 BIT(5), BIT(5));
175 /* enable N/CTS, enable Audio sample packets */
176 regmap_update_bits(map: adv7511->regmap, ADV7511_REG_PACKET_ENABLE1,
177 BIT(5), BIT(5));
178 /* enable N/CTS */
179 regmap_update_bits(map: adv7511->regmap, ADV7511_REG_PACKET_ENABLE1,
180 BIT(6), BIT(6));
181 /* not copyrighted */
182 regmap_update_bits(map: adv7511->regmap, ADV7511_REG_AUDIO_CFG1,
183 BIT(5), BIT(5));
184 /* AV mute disable */
185 regmap_update_bits(map: 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(map: adv7511->regmap, ADV7511_REG_AUDIO_CONFIG,
191 BIT(7), BIT(7));
192
193 return 0;
194}
195
196void 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(map: adv7511->regmap, ADV7511_REG_AUDIO_CONFIG,
203 BIT(7), val: 0);
204
205 drm_atomic_helper_connector_hdmi_clear_audio_infoframe(connector);
206}
207

source code of linux/drivers/gpu/drm/bridge/adv7511/adv7511_audio.c