Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

drm/bridge: adv7511: Add Audio support

This patch adds support to Audio for both adv7511 and adv7533
bridge chips.

This patch was originally from [1] by Lars-Peter Clausen <lars@metafoo.de>
and was adapted by Archit Taneja <architt@codeaurora.org> and
Srinivas Kandagatla <srinivas.kandagatla@linaro.org>.

Then I heavily reworked it to use the hdmi-codec driver. And also
folded in some audio packet initialization done by Andy Green
<andy.green@linaro.org>. So credit to them, but blame to me.

[1] https://github.com/analogdevicesinc/linux/blob/xcomm_zynq/drivers/gpu/drm/i2c/adv7511_audio.c

Cc: David Airlie <airlied@linux.ie>
Cc: Archit Taneja <architt@codeaurora.org>
Cc: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
Cc: Wolfram Sang <wsa+renesas@sang-engineering.com>
Cc: Srinivas Kandagatla <srinivas.kandagatla@linaro.org>
Cc: "Ville Syrjälä" <ville.syrjala@linux.intel.com>
Cc: Boris Brezillon <boris.brezillon@free-electrons.com>
Cc: Andy Green <andy@warmcat.com>
Cc: Dave Long <dave.long@linaro.org>
Cc: Guodong Xu <guodong.xu@linaro.org>
Cc: Zhangfei Gao <zhangfei.gao@linaro.org>
Cc: Mark Brown <broonie@kernel.org>
Cc: Lars-Peter Clausen <lars@metafoo.de>
Cc: Jose Abreu <joabreu@synopsys.com>
Cc: Kuninori Morimoto <kuninori.morimoto.gx@renesas.com>
Cc: dri-devel@lists.freedesktop.org
Acked-by: Lars-Peter Clausen <lars@metafoo.de>
Signed-off-by: John Stultz <john.stultz@linaro.org>
Signed-off-by: Archit Taneja <architt@codeaurora.org>
Link: http://patchwork.freedesktop.org/patch/msgid/1480382552-28219-2-git-send-email-john.stultz@linaro.org

authored by

John Stultz and committed by
Archit Taneja
53c515be c45a4e46

+242
+8
drivers/gpu/drm/bridge/adv7511/Kconfig
··· 6 6 help 7 7 Support for the Analog Device ADV7511(W) and ADV7513 HDMI encoders. 8 8 9 + config DRM_I2C_ADV7511_AUDIO 10 + bool "ADV7511 HDMI Audio driver" 11 + depends on DRM_I2C_ADV7511 && SND_SOC 12 + select SND_SOC_HDMI_CODEC 13 + help 14 + Support the ADV7511 HDMI Audio interface. This is used in 15 + conjunction with the AV7511 HDMI driver. 16 + 9 17 config DRM_I2C_ADV7533 10 18 bool "ADV7533 encoder" 11 19 depends on DRM_I2C_ADV7511
+1
drivers/gpu/drm/bridge/adv7511/Makefile
··· 1 1 adv7511-y := adv7511_drv.o 2 + adv7511-$(CONFIG_DRM_I2C_ADV7511_AUDIO) += adv7511_audio.o 2 3 adv7511-$(CONFIG_DRM_I2C_ADV7533) += adv7533.o 3 4 obj-$(CONFIG_DRM_I2C_ADV7511) += adv7511.o
+16
drivers/gpu/drm/bridge/adv7511/adv7511.h
··· 309 309 struct drm_display_mode curr_mode; 310 310 311 311 unsigned int f_tmds; 312 + unsigned int f_audio; 313 + unsigned int audio_source; 312 314 313 315 unsigned int current_edid_segment; 314 316 uint8_t edid_buf[256]; ··· 336 334 bool use_timing_gen; 337 335 338 336 enum adv7511_type type; 337 + struct platform_device *audio_pdev; 339 338 }; 340 339 341 340 #ifdef CONFIG_DRM_I2C_ADV7533 ··· 391 388 return -ENODEV; 392 389 } 393 390 #endif 391 + 392 + #ifdef CONFIG_DRM_I2C_ADV7511_AUDIO 393 + int adv7511_audio_init(struct device *dev, struct adv7511 *adv7511); 394 + void adv7511_audio_exit(struct adv7511 *adv7511); 395 + #else /*CONFIG_DRM_I2C_ADV7511_AUDIO */ 396 + static inline int adv7511_audio_init(struct device *dev, struct adv7511 *adv7511) 397 + { 398 + return 0; 399 + } 400 + static inline void adv7511_audio_exit(struct adv7511 *adv7511) 401 + { 402 + } 403 + #endif /* CONFIG_DRM_I2C_ADV7511_AUDIO */ 394 404 395 405 #endif /* __DRM_I2C_ADV7511_H__ */
+213
drivers/gpu/drm/bridge/adv7511/adv7511_audio.c
··· 1 + /* 2 + * Analog Devices ADV7511 HDMI transmitter driver 3 + * 4 + * Copyright 2012 Analog Devices Inc. 5 + * Copyright (c) 2016, Linaro Limited 6 + * 7 + * Licensed under the GPL-2. 8 + */ 9 + 10 + #include <sound/core.h> 11 + #include <sound/hdmi-codec.h> 12 + #include <sound/pcm.h> 13 + #include <sound/soc.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 + *n = 4096; 23 + break; 24 + case 44100: 25 + *n = 6272; 26 + break; 27 + case 48000: 28 + *n = 6144; 29 + break; 30 + } 31 + 32 + *cts = ((f_tmds * *n) / (128 * fs)) * 1000; 33 + } 34 + 35 + static int adv7511_update_cts_n(struct adv7511 *adv7511) 36 + { 37 + unsigned int cts = 0; 38 + unsigned int n = 0; 39 + 40 + adv7511_calc_cts_n(adv7511->f_tmds, adv7511->f_audio, &cts, &n); 41 + 42 + regmap_write(adv7511->regmap, ADV7511_REG_N0, (n >> 16) & 0xf); 43 + regmap_write(adv7511->regmap, ADV7511_REG_N1, (n >> 8) & 0xff); 44 + regmap_write(adv7511->regmap, ADV7511_REG_N2, n & 0xff); 45 + 46 + regmap_write(adv7511->regmap, ADV7511_REG_CTS_MANUAL0, 47 + (cts >> 16) & 0xf); 48 + regmap_write(adv7511->regmap, ADV7511_REG_CTS_MANUAL1, 49 + (cts >> 8) & 0xff); 50 + regmap_write(adv7511->regmap, ADV7511_REG_CTS_MANUAL2, 51 + cts & 0xff); 52 + 53 + return 0; 54 + } 55 + 56 + int adv7511_hdmi_hw_params(struct device *dev, void *data, 57 + struct hdmi_codec_daifmt *fmt, 58 + struct hdmi_codec_params *hparms) 59 + { 60 + struct adv7511 *adv7511 = dev_get_drvdata(dev); 61 + unsigned int audio_source, i2s_format = 0; 62 + unsigned int invert_clock; 63 + unsigned int rate; 64 + unsigned int len; 65 + 66 + switch (hparms->sample_rate) { 67 + case 32000: 68 + rate = ADV7511_SAMPLE_FREQ_32000; 69 + break; 70 + case 44100: 71 + rate = ADV7511_SAMPLE_FREQ_44100; 72 + break; 73 + case 48000: 74 + rate = ADV7511_SAMPLE_FREQ_48000; 75 + break; 76 + case 88200: 77 + rate = ADV7511_SAMPLE_FREQ_88200; 78 + break; 79 + case 96000: 80 + rate = ADV7511_SAMPLE_FREQ_96000; 81 + break; 82 + case 176400: 83 + rate = ADV7511_SAMPLE_FREQ_176400; 84 + break; 85 + case 192000: 86 + rate = ADV7511_SAMPLE_FREQ_192000; 87 + break; 88 + default: 89 + return -EINVAL; 90 + } 91 + 92 + switch (hparms->sample_width) { 93 + case 16: 94 + len = ADV7511_I2S_SAMPLE_LEN_16; 95 + break; 96 + case 18: 97 + len = ADV7511_I2S_SAMPLE_LEN_18; 98 + break; 99 + case 20: 100 + len = ADV7511_I2S_SAMPLE_LEN_20; 101 + break; 102 + case 24: 103 + len = ADV7511_I2S_SAMPLE_LEN_24; 104 + break; 105 + default: 106 + return -EINVAL; 107 + } 108 + 109 + switch (fmt->fmt) { 110 + case HDMI_I2S: 111 + audio_source = ADV7511_AUDIO_SOURCE_I2S; 112 + i2s_format = ADV7511_I2S_FORMAT_I2S; 113 + break; 114 + case HDMI_RIGHT_J: 115 + audio_source = ADV7511_AUDIO_SOURCE_I2S; 116 + i2s_format = ADV7511_I2S_FORMAT_RIGHT_J; 117 + break; 118 + case HDMI_LEFT_J: 119 + audio_source = ADV7511_AUDIO_SOURCE_I2S; 120 + i2s_format = ADV7511_I2S_FORMAT_LEFT_J; 121 + break; 122 + default: 123 + return -EINVAL; 124 + } 125 + 126 + invert_clock = fmt->bit_clk_inv; 127 + 128 + regmap_update_bits(adv7511->regmap, ADV7511_REG_AUDIO_SOURCE, 0x70, 129 + audio_source << 4); 130 + regmap_update_bits(adv7511->regmap, ADV7511_REG_AUDIO_CONFIG, BIT(6), 131 + invert_clock << 6); 132 + regmap_update_bits(adv7511->regmap, ADV7511_REG_I2S_CONFIG, 0x03, 133 + i2s_format); 134 + 135 + adv7511->audio_source = audio_source; 136 + 137 + adv7511->f_audio = hparms->sample_rate; 138 + 139 + adv7511_update_cts_n(adv7511); 140 + 141 + regmap_update_bits(adv7511->regmap, ADV7511_REG_AUDIO_CFG3, 142 + ADV7511_AUDIO_CFG3_LEN_MASK, len); 143 + regmap_update_bits(adv7511->regmap, ADV7511_REG_I2C_FREQ_ID_CFG, 144 + ADV7511_I2C_FREQ_ID_CFG_RATE_MASK, rate << 4); 145 + regmap_write(adv7511->regmap, 0x73, 0x1); 146 + 147 + return 0; 148 + } 149 + 150 + static int audio_startup(struct device *dev, void *data) 151 + { 152 + struct adv7511 *adv7511 = dev_get_drvdata(dev); 153 + 154 + regmap_update_bits(adv7511->regmap, ADV7511_REG_AUDIO_CONFIG, 155 + BIT(7), 0); 156 + 157 + /* hide Audio infoframe updates */ 158 + regmap_update_bits(adv7511->regmap, ADV7511_REG_INFOFRAME_UPDATE, 159 + BIT(5), BIT(5)); 160 + /* enable N/CTS, enable Audio sample packets */ 161 + regmap_update_bits(adv7511->regmap, ADV7511_REG_PACKET_ENABLE1, 162 + BIT(5), BIT(5)); 163 + /* enable N/CTS */ 164 + regmap_update_bits(adv7511->regmap, ADV7511_REG_PACKET_ENABLE1, 165 + BIT(6), BIT(6)); 166 + /* not copyrighted */ 167 + regmap_update_bits(adv7511->regmap, ADV7511_REG_AUDIO_CFG1, 168 + BIT(5), BIT(5)); 169 + /* enable audio infoframes */ 170 + regmap_update_bits(adv7511->regmap, ADV7511_REG_PACKET_ENABLE1, 171 + BIT(3), BIT(3)); 172 + /* AV mute disable */ 173 + regmap_update_bits(adv7511->regmap, ADV7511_REG_GC(0), 174 + BIT(7) | BIT(6), BIT(7)); 175 + /* use Audio infoframe updated info */ 176 + regmap_update_bits(adv7511->regmap, ADV7511_REG_GC(1), 177 + BIT(5), 0); 178 + return 0; 179 + } 180 + 181 + static void audio_shutdown(struct device *dev, void *data) 182 + { 183 + } 184 + 185 + static const struct hdmi_codec_ops adv7511_codec_ops = { 186 + .hw_params = adv7511_hdmi_hw_params, 187 + .audio_shutdown = audio_shutdown, 188 + .audio_startup = audio_startup, 189 + }; 190 + 191 + static struct hdmi_codec_pdata codec_data = { 192 + .ops = &adv7511_codec_ops, 193 + .max_i2s_channels = 2, 194 + .i2s = 1, 195 + }; 196 + 197 + int adv7511_audio_init(struct device *dev, struct adv7511 *adv7511) 198 + { 199 + adv7511->audio_pdev = platform_device_register_data(dev, 200 + HDMI_CODEC_DRV_NAME, 201 + PLATFORM_DEVID_AUTO, 202 + &codec_data, 203 + sizeof(codec_data)); 204 + return PTR_ERR_OR_ZERO(adv7511->audio_pdev); 205 + } 206 + 207 + void adv7511_audio_exit(struct adv7511 *adv7511) 208 + { 209 + if (adv7511->audio_pdev) { 210 + platform_device_unregister(adv7511->audio_pdev); 211 + adv7511->audio_pdev = NULL; 212 + } 213 + }
+4
drivers/gpu/drm/bridge/adv7511/adv7511_drv.c
··· 1037 1037 goto err_unregister_cec; 1038 1038 } 1039 1039 1040 + adv7511_audio_init(dev, adv7511); 1041 + 1040 1042 return 0; 1041 1043 1042 1044 err_unregister_cec: ··· 1059 1057 } 1060 1058 1061 1059 drm_bridge_remove(&adv7511->bridge); 1060 + 1061 + adv7511_audio_exit(adv7511); 1062 1062 1063 1063 i2c_unregister_device(adv7511->i2c_edid); 1064 1064