1fda8d26eSThomas Gleixner // SPDX-License-Identifier: GPL-2.0-only
253c515beSJohn Stultz /*
353c515beSJohn Stultz * Analog Devices ADV7511 HDMI transmitter driver
453c515beSJohn Stultz *
553c515beSJohn Stultz * Copyright 2012 Analog Devices Inc.
653c515beSJohn Stultz * Copyright (c) 2016, Linaro Limited
753c515beSJohn Stultz */
853c515beSJohn Stultz
953c515beSJohn Stultz #include <sound/core.h>
1053c515beSJohn Stultz #include <sound/hdmi-codec.h>
1153c515beSJohn Stultz #include <sound/pcm.h>
1253c515beSJohn Stultz #include <sound/soc.h>
137204e976SJohn Stultz #include <linux/of_graph.h>
1453c515beSJohn Stultz
1553c515beSJohn Stultz #include "adv7511.h"
1653c515beSJohn Stultz
adv7511_calc_cts_n(unsigned int f_tmds,unsigned int fs,unsigned int * cts,unsigned int * n)1753c515beSJohn Stultz static void adv7511_calc_cts_n(unsigned int f_tmds, unsigned int fs,
1853c515beSJohn Stultz unsigned int *cts, unsigned int *n)
1953c515beSJohn Stultz {
2053c515beSJohn Stultz switch (fs) {
2153c515beSJohn Stultz case 32000:
22b97b6a1fSBogdan Togorean case 48000:
23b97b6a1fSBogdan Togorean case 96000:
24b97b6a1fSBogdan Togorean case 192000:
25b97b6a1fSBogdan Togorean *n = fs * 128 / 1000;
2653c515beSJohn Stultz break;
2753c515beSJohn Stultz case 44100:
28b97b6a1fSBogdan Togorean case 88200:
29b97b6a1fSBogdan Togorean case 176400:
30b97b6a1fSBogdan Togorean *n = fs * 128 / 900;
3153c515beSJohn Stultz break;
3253c515beSJohn Stultz }
3353c515beSJohn Stultz
3453c515beSJohn Stultz *cts = ((f_tmds * *n) / (128 * fs)) * 1000;
3553c515beSJohn Stultz }
3653c515beSJohn Stultz
adv7511_update_cts_n(struct adv7511 * adv7511)3753c515beSJohn Stultz static int adv7511_update_cts_n(struct adv7511 *adv7511)
3853c515beSJohn Stultz {
3953c515beSJohn Stultz unsigned int cts = 0;
4053c515beSJohn Stultz unsigned int n = 0;
4153c515beSJohn Stultz
4253c515beSJohn Stultz adv7511_calc_cts_n(adv7511->f_tmds, adv7511->f_audio, &cts, &n);
4353c515beSJohn Stultz
4453c515beSJohn Stultz regmap_write(adv7511->regmap, ADV7511_REG_N0, (n >> 16) & 0xf);
4553c515beSJohn Stultz regmap_write(adv7511->regmap, ADV7511_REG_N1, (n >> 8) & 0xff);
4653c515beSJohn Stultz regmap_write(adv7511->regmap, ADV7511_REG_N2, n & 0xff);
4753c515beSJohn Stultz
4853c515beSJohn Stultz regmap_write(adv7511->regmap, ADV7511_REG_CTS_MANUAL0,
4953c515beSJohn Stultz (cts >> 16) & 0xf);
5053c515beSJohn Stultz regmap_write(adv7511->regmap, ADV7511_REG_CTS_MANUAL1,
5153c515beSJohn Stultz (cts >> 8) & 0xff);
5253c515beSJohn Stultz regmap_write(adv7511->regmap, ADV7511_REG_CTS_MANUAL2,
5353c515beSJohn Stultz cts & 0xff);
5453c515beSJohn Stultz
5553c515beSJohn Stultz return 0;
5653c515beSJohn Stultz }
5753c515beSJohn Stultz
adv7511_hdmi_hw_params(struct device * dev,void * data,struct hdmi_codec_daifmt * fmt,struct hdmi_codec_params * hparms)58759962b5SJason Yan static int adv7511_hdmi_hw_params(struct device *dev, void *data,
5953c515beSJohn Stultz struct hdmi_codec_daifmt *fmt,
6053c515beSJohn Stultz struct hdmi_codec_params *hparms)
6153c515beSJohn Stultz {
6253c515beSJohn Stultz struct adv7511 *adv7511 = dev_get_drvdata(dev);
6353c515beSJohn Stultz unsigned int audio_source, i2s_format = 0;
6453c515beSJohn Stultz unsigned int invert_clock;
6553c515beSJohn Stultz unsigned int rate;
6653c515beSJohn Stultz unsigned int len;
6753c515beSJohn Stultz
6853c515beSJohn Stultz switch (hparms->sample_rate) {
6953c515beSJohn Stultz case 32000:
7053c515beSJohn Stultz rate = ADV7511_SAMPLE_FREQ_32000;
7153c515beSJohn Stultz break;
7253c515beSJohn Stultz case 44100:
7353c515beSJohn Stultz rate = ADV7511_SAMPLE_FREQ_44100;
7453c515beSJohn Stultz break;
7553c515beSJohn Stultz case 48000:
7653c515beSJohn Stultz rate = ADV7511_SAMPLE_FREQ_48000;
7753c515beSJohn Stultz break;
7853c515beSJohn Stultz case 88200:
7953c515beSJohn Stultz rate = ADV7511_SAMPLE_FREQ_88200;
8053c515beSJohn Stultz break;
8153c515beSJohn Stultz case 96000:
8253c515beSJohn Stultz rate = ADV7511_SAMPLE_FREQ_96000;
8353c515beSJohn Stultz break;
8453c515beSJohn Stultz case 176400:
8553c515beSJohn Stultz rate = ADV7511_SAMPLE_FREQ_176400;
8653c515beSJohn Stultz break;
8753c515beSJohn Stultz case 192000:
8853c515beSJohn Stultz rate = ADV7511_SAMPLE_FREQ_192000;
8953c515beSJohn Stultz break;
9053c515beSJohn Stultz default:
9153c515beSJohn Stultz return -EINVAL;
9253c515beSJohn Stultz }
9353c515beSJohn Stultz
9453c515beSJohn Stultz switch (hparms->sample_width) {
9553c515beSJohn Stultz case 16:
9653c515beSJohn Stultz len = ADV7511_I2S_SAMPLE_LEN_16;
9753c515beSJohn Stultz break;
9853c515beSJohn Stultz case 18:
9953c515beSJohn Stultz len = ADV7511_I2S_SAMPLE_LEN_18;
10053c515beSJohn Stultz break;
10153c515beSJohn Stultz case 20:
10253c515beSJohn Stultz len = ADV7511_I2S_SAMPLE_LEN_20;
10353c515beSJohn Stultz break;
104ae053fa2SSia Jee Heng case 32:
105ae053fa2SSia Jee Heng if (fmt->bit_fmt != SNDRV_PCM_FORMAT_IEC958_SUBFRAME_LE)
106ae053fa2SSia Jee Heng return -EINVAL;
107ae053fa2SSia Jee Heng fallthrough;
10853c515beSJohn Stultz case 24:
10953c515beSJohn Stultz len = ADV7511_I2S_SAMPLE_LEN_24;
11053c515beSJohn Stultz break;
11153c515beSJohn Stultz default:
11253c515beSJohn Stultz return -EINVAL;
11353c515beSJohn Stultz }
11453c515beSJohn Stultz
11553c515beSJohn Stultz switch (fmt->fmt) {
11653c515beSJohn Stultz case HDMI_I2S:
11753c515beSJohn Stultz audio_source = ADV7511_AUDIO_SOURCE_I2S;
11853c515beSJohn Stultz i2s_format = ADV7511_I2S_FORMAT_I2S;
119ae053fa2SSia Jee Heng if (fmt->bit_fmt == SNDRV_PCM_FORMAT_IEC958_SUBFRAME_LE)
120ae053fa2SSia Jee Heng i2s_format = ADV7511_I2S_IEC958_DIRECT;
12153c515beSJohn Stultz break;
12253c515beSJohn Stultz case HDMI_RIGHT_J:
12353c515beSJohn Stultz audio_source = ADV7511_AUDIO_SOURCE_I2S;
12453c515beSJohn Stultz i2s_format = ADV7511_I2S_FORMAT_RIGHT_J;
12553c515beSJohn Stultz break;
12653c515beSJohn Stultz case HDMI_LEFT_J:
12753c515beSJohn Stultz audio_source = ADV7511_AUDIO_SOURCE_I2S;
12853c515beSJohn Stultz i2s_format = ADV7511_I2S_FORMAT_LEFT_J;
12953c515beSJohn Stultz break;
130f7f436b9SBogdan Togorean case HDMI_SPDIF:
131f7f436b9SBogdan Togorean audio_source = ADV7511_AUDIO_SOURCE_SPDIF;
132f7f436b9SBogdan Togorean break;
13353c515beSJohn Stultz default:
13453c515beSJohn Stultz return -EINVAL;
13553c515beSJohn Stultz }
13653c515beSJohn Stultz
13753c515beSJohn Stultz invert_clock = fmt->bit_clk_inv;
13853c515beSJohn Stultz
13953c515beSJohn Stultz regmap_update_bits(adv7511->regmap, ADV7511_REG_AUDIO_SOURCE, 0x70,
14053c515beSJohn Stultz audio_source << 4);
14153c515beSJohn Stultz regmap_update_bits(adv7511->regmap, ADV7511_REG_AUDIO_CONFIG, BIT(6),
14253c515beSJohn Stultz invert_clock << 6);
14353c515beSJohn Stultz regmap_update_bits(adv7511->regmap, ADV7511_REG_I2S_CONFIG, 0x03,
14453c515beSJohn Stultz i2s_format);
14553c515beSJohn Stultz
14653c515beSJohn Stultz adv7511->audio_source = audio_source;
14753c515beSJohn Stultz
14853c515beSJohn Stultz adv7511->f_audio = hparms->sample_rate;
14953c515beSJohn Stultz
15053c515beSJohn Stultz adv7511_update_cts_n(adv7511);
15153c515beSJohn Stultz
15253c515beSJohn Stultz regmap_update_bits(adv7511->regmap, ADV7511_REG_AUDIO_CFG3,
15353c515beSJohn Stultz ADV7511_AUDIO_CFG3_LEN_MASK, len);
15453c515beSJohn Stultz regmap_update_bits(adv7511->regmap, ADV7511_REG_I2C_FREQ_ID_CFG,
15553c515beSJohn Stultz ADV7511_I2C_FREQ_ID_CFG_RATE_MASK, rate << 4);
156*fa7f9658SStefan Ekenberg
157*fa7f9658SStefan Ekenberg /* send current Audio infoframe values while updating */
158*fa7f9658SStefan Ekenberg regmap_update_bits(adv7511->regmap, ADV7511_REG_INFOFRAME_UPDATE,
159*fa7f9658SStefan Ekenberg BIT(5), BIT(5));
160*fa7f9658SStefan Ekenberg
161*fa7f9658SStefan Ekenberg regmap_write(adv7511->regmap, ADV7511_REG_AUDIO_INFOFRAME(0), 0x1);
162*fa7f9658SStefan Ekenberg
163*fa7f9658SStefan Ekenberg /* use Audio infoframe updated info */
164*fa7f9658SStefan Ekenberg regmap_update_bits(adv7511->regmap, ADV7511_REG_INFOFRAME_UPDATE,
165*fa7f9658SStefan Ekenberg BIT(5), 0);
16653c515beSJohn Stultz
16753c515beSJohn Stultz return 0;
16853c515beSJohn Stultz }
16953c515beSJohn Stultz
audio_startup(struct device * dev,void * data)17053c515beSJohn Stultz static int audio_startup(struct device *dev, void *data)
17153c515beSJohn Stultz {
17253c515beSJohn Stultz struct adv7511 *adv7511 = dev_get_drvdata(dev);
17353c515beSJohn Stultz
17453c515beSJohn Stultz regmap_update_bits(adv7511->regmap, ADV7511_REG_AUDIO_CONFIG,
17553c515beSJohn Stultz BIT(7), 0);
17653c515beSJohn Stultz
17753c515beSJohn Stultz /* hide Audio infoframe updates */
17853c515beSJohn Stultz regmap_update_bits(adv7511->regmap, ADV7511_REG_INFOFRAME_UPDATE,
17953c515beSJohn Stultz BIT(5), BIT(5));
18053c515beSJohn Stultz /* enable N/CTS, enable Audio sample packets */
18153c515beSJohn Stultz regmap_update_bits(adv7511->regmap, ADV7511_REG_PACKET_ENABLE1,
18253c515beSJohn Stultz BIT(5), BIT(5));
18353c515beSJohn Stultz /* enable N/CTS */
18453c515beSJohn Stultz regmap_update_bits(adv7511->regmap, ADV7511_REG_PACKET_ENABLE1,
18553c515beSJohn Stultz BIT(6), BIT(6));
18653c515beSJohn Stultz /* not copyrighted */
18753c515beSJohn Stultz regmap_update_bits(adv7511->regmap, ADV7511_REG_AUDIO_CFG1,
18853c515beSJohn Stultz BIT(5), BIT(5));
18953c515beSJohn Stultz /* enable audio infoframes */
19053c515beSJohn Stultz regmap_update_bits(adv7511->regmap, ADV7511_REG_PACKET_ENABLE1,
19153c515beSJohn Stultz BIT(3), BIT(3));
19253c515beSJohn Stultz /* AV mute disable */
19353c515beSJohn Stultz regmap_update_bits(adv7511->regmap, ADV7511_REG_GC(0),
19453c515beSJohn Stultz BIT(7) | BIT(6), BIT(7));
19553c515beSJohn Stultz /* use Audio infoframe updated info */
196*fa7f9658SStefan Ekenberg regmap_update_bits(adv7511->regmap, ADV7511_REG_INFOFRAME_UPDATE,
19753c515beSJohn Stultz BIT(5), 0);
198*fa7f9658SStefan Ekenberg
199f7f436b9SBogdan Togorean /* enable SPDIF receiver */
200f7f436b9SBogdan Togorean if (adv7511->audio_source == ADV7511_AUDIO_SOURCE_SPDIF)
201f7f436b9SBogdan Togorean regmap_update_bits(adv7511->regmap, ADV7511_REG_AUDIO_CONFIG,
202f7f436b9SBogdan Togorean BIT(7), BIT(7));
203f7f436b9SBogdan Togorean
20453c515beSJohn Stultz return 0;
20553c515beSJohn Stultz }
20653c515beSJohn Stultz
audio_shutdown(struct device * dev,void * data)20753c515beSJohn Stultz static void audio_shutdown(struct device *dev, void *data)
20853c515beSJohn Stultz {
209f7f436b9SBogdan Togorean struct adv7511 *adv7511 = dev_get_drvdata(dev);
210f7f436b9SBogdan Togorean
211f7f436b9SBogdan Togorean if (adv7511->audio_source == ADV7511_AUDIO_SOURCE_SPDIF)
212f7f436b9SBogdan Togorean regmap_update_bits(adv7511->regmap, ADV7511_REG_AUDIO_CONFIG,
213f7f436b9SBogdan Togorean BIT(7), 0);
21453c515beSJohn Stultz }
21553c515beSJohn Stultz
adv7511_hdmi_i2s_get_dai_id(struct snd_soc_component * component,struct device_node * endpoint)2167204e976SJohn Stultz static int adv7511_hdmi_i2s_get_dai_id(struct snd_soc_component *component,
2177204e976SJohn Stultz struct device_node *endpoint)
2187204e976SJohn Stultz {
2197204e976SJohn Stultz struct of_endpoint of_ep;
2207204e976SJohn Stultz int ret;
2217204e976SJohn Stultz
2227204e976SJohn Stultz ret = of_graph_parse_endpoint(endpoint, &of_ep);
2237204e976SJohn Stultz if (ret < 0)
2247204e976SJohn Stultz return ret;
2257204e976SJohn Stultz
2267204e976SJohn Stultz /*
2277204e976SJohn Stultz * HDMI sound should be located as reg = <2>
2287204e976SJohn Stultz * Then, it is sound port 0
2297204e976SJohn Stultz */
2307204e976SJohn Stultz if (of_ep.port == 2)
2317204e976SJohn Stultz return 0;
2327204e976SJohn Stultz
2337204e976SJohn Stultz return -EINVAL;
2347204e976SJohn Stultz }
2357204e976SJohn Stultz
23653c515beSJohn Stultz static const struct hdmi_codec_ops adv7511_codec_ops = {
23753c515beSJohn Stultz .hw_params = adv7511_hdmi_hw_params,
23853c515beSJohn Stultz .audio_shutdown = audio_shutdown,
23953c515beSJohn Stultz .audio_startup = audio_startup,
2407204e976SJohn Stultz .get_dai_id = adv7511_hdmi_i2s_get_dai_id,
24153c515beSJohn Stultz };
24253c515beSJohn Stultz
24315910174SLars-Peter Clausen static const struct hdmi_codec_pdata codec_data = {
24453c515beSJohn Stultz .ops = &adv7511_codec_ops,
24553c515beSJohn Stultz .max_i2s_channels = 2,
24653c515beSJohn Stultz .i2s = 1,
247f7f436b9SBogdan Togorean .spdif = 1,
24853c515beSJohn Stultz };
24953c515beSJohn Stultz
adv7511_audio_init(struct device * dev,struct adv7511 * adv7511)25053c515beSJohn Stultz int adv7511_audio_init(struct device *dev, struct adv7511 *adv7511)
25153c515beSJohn Stultz {
25253c515beSJohn Stultz adv7511->audio_pdev = platform_device_register_data(dev,
25353c515beSJohn Stultz HDMI_CODEC_DRV_NAME,
25453c515beSJohn Stultz PLATFORM_DEVID_AUTO,
25553c515beSJohn Stultz &codec_data,
25653c515beSJohn Stultz sizeof(codec_data));
25753c515beSJohn Stultz return PTR_ERR_OR_ZERO(adv7511->audio_pdev);
25853c515beSJohn Stultz }
25953c515beSJohn Stultz
adv7511_audio_exit(struct adv7511 * adv7511)26053c515beSJohn Stultz void adv7511_audio_exit(struct adv7511 *adv7511)
26153c515beSJohn Stultz {
26253c515beSJohn Stultz if (adv7511->audio_pdev) {
26353c515beSJohn Stultz platform_device_unregister(adv7511->audio_pdev);
26453c515beSJohn Stultz adv7511->audio_pdev = NULL;
26553c515beSJohn Stultz }
26653c515beSJohn Stultz }
267