diff options
| -rw-r--r-- | drivers/gpu/drm/bridge/adv7511/Kconfig | 8 | ||||
| -rw-r--r-- | drivers/gpu/drm/bridge/adv7511/Makefile | 1 | ||||
| -rw-r--r-- | drivers/gpu/drm/bridge/adv7511/adv7511.h | 16 | ||||
| -rw-r--r-- | drivers/gpu/drm/bridge/adv7511/adv7511_audio.c | 213 | ||||
| -rw-r--r-- | drivers/gpu/drm/bridge/adv7511/adv7511_drv.c | 4 |
5 files changed, 242 insertions, 0 deletions
diff --git a/drivers/gpu/drm/bridge/adv7511/Kconfig b/drivers/gpu/drm/bridge/adv7511/Kconfig index d2b0499ab7d7..2fed567f9943 100644 --- a/drivers/gpu/drm/bridge/adv7511/Kconfig +++ b/drivers/gpu/drm/bridge/adv7511/Kconfig | |||
| @@ -6,6 +6,14 @@ config DRM_I2C_ADV7511 | |||
| 6 | help | 6 | help |
| 7 | Support for the Analog Device ADV7511(W) and ADV7513 HDMI encoders. | 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 | config DRM_I2C_ADV7533 | 17 | config DRM_I2C_ADV7533 |
| 10 | bool "ADV7533 encoder" | 18 | bool "ADV7533 encoder" |
| 11 | depends on DRM_I2C_ADV7511 | 19 | depends on DRM_I2C_ADV7511 |
diff --git a/drivers/gpu/drm/bridge/adv7511/Makefile b/drivers/gpu/drm/bridge/adv7511/Makefile index 9019327fff4c..5ba675534f6e 100644 --- a/drivers/gpu/drm/bridge/adv7511/Makefile +++ b/drivers/gpu/drm/bridge/adv7511/Makefile | |||
| @@ -1,3 +1,4 @@ | |||
| 1 | adv7511-y := adv7511_drv.o | 1 | adv7511-y := adv7511_drv.o |
| 2 | adv7511-$(CONFIG_DRM_I2C_ADV7511_AUDIO) += adv7511_audio.o | ||
| 2 | adv7511-$(CONFIG_DRM_I2C_ADV7533) += adv7533.o | 3 | adv7511-$(CONFIG_DRM_I2C_ADV7533) += adv7533.o |
| 3 | obj-$(CONFIG_DRM_I2C_ADV7511) += adv7511.o | 4 | obj-$(CONFIG_DRM_I2C_ADV7511) += adv7511.o |
diff --git a/drivers/gpu/drm/bridge/adv7511/adv7511.h b/drivers/gpu/drm/bridge/adv7511/adv7511.h index 161c923d6162..992d76ce02bb 100644 --- a/drivers/gpu/drm/bridge/adv7511/adv7511.h +++ b/drivers/gpu/drm/bridge/adv7511/adv7511.h | |||
| @@ -309,6 +309,8 @@ struct adv7511 { | |||
| 309 | struct drm_display_mode curr_mode; | 309 | struct drm_display_mode curr_mode; |
| 310 | 310 | ||
| 311 | unsigned int f_tmds; | 311 | unsigned int f_tmds; |
| 312 | unsigned int f_audio; | ||
| 313 | unsigned int audio_source; | ||
| 312 | 314 | ||
| 313 | unsigned int current_edid_segment; | 315 | unsigned int current_edid_segment; |
| 314 | uint8_t edid_buf[256]; | 316 | uint8_t edid_buf[256]; |
| @@ -334,6 +336,7 @@ struct adv7511 { | |||
| 334 | bool use_timing_gen; | 336 | bool use_timing_gen; |
| 335 | 337 | ||
| 336 | enum adv7511_type type; | 338 | enum adv7511_type type; |
| 339 | struct platform_device *audio_pdev; | ||
| 337 | }; | 340 | }; |
| 338 | 341 | ||
| 339 | #ifdef CONFIG_DRM_I2C_ADV7533 | 342 | #ifdef CONFIG_DRM_I2C_ADV7533 |
| @@ -389,4 +392,17 @@ static inline int adv7533_parse_dt(struct device_node *np, struct adv7511 *adv) | |||
| 389 | } | 392 | } |
| 390 | #endif | 393 | #endif |
| 391 | 394 | ||
| 395 | #ifdef CONFIG_DRM_I2C_ADV7511_AUDIO | ||
| 396 | int adv7511_audio_init(struct device *dev, struct adv7511 *adv7511); | ||
| 397 | void adv7511_audio_exit(struct adv7511 *adv7511); | ||
| 398 | #else /*CONFIG_DRM_I2C_ADV7511_AUDIO */ | ||
| 399 | static inline int adv7511_audio_init(struct device *dev, struct adv7511 *adv7511) | ||
| 400 | { | ||
| 401 | return 0; | ||
| 402 | } | ||
| 403 | static inline void adv7511_audio_exit(struct adv7511 *adv7511) | ||
| 404 | { | ||
| 405 | } | ||
| 406 | #endif /* CONFIG_DRM_I2C_ADV7511_AUDIO */ | ||
| 407 | |||
| 392 | #endif /* __DRM_I2C_ADV7511_H__ */ | 408 | #endif /* __DRM_I2C_ADV7511_H__ */ |
diff --git a/drivers/gpu/drm/bridge/adv7511/adv7511_audio.c b/drivers/gpu/drm/bridge/adv7511/adv7511_audio.c new file mode 100644 index 000000000000..cf92ebfe6ab7 --- /dev/null +++ b/drivers/gpu/drm/bridge/adv7511/adv7511_audio.c | |||
| @@ -0,0 +1,213 @@ | |||
| 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 | } | ||
diff --git a/drivers/gpu/drm/bridge/adv7511/adv7511_drv.c b/drivers/gpu/drm/bridge/adv7511/adv7511_drv.c index 8ed3906dd411..8dba729f6ef9 100644 --- a/drivers/gpu/drm/bridge/adv7511/adv7511_drv.c +++ b/drivers/gpu/drm/bridge/adv7511/adv7511_drv.c | |||
| @@ -1037,6 +1037,8 @@ static int adv7511_probe(struct i2c_client *i2c, const struct i2c_device_id *id) | |||
| 1037 | goto err_unregister_cec; | 1037 | goto err_unregister_cec; |
| 1038 | } | 1038 | } |
| 1039 | 1039 | ||
| 1040 | adv7511_audio_init(dev, adv7511); | ||
| 1041 | |||
| 1040 | return 0; | 1042 | return 0; |
| 1041 | 1043 | ||
| 1042 | err_unregister_cec: | 1044 | err_unregister_cec: |
| @@ -1058,6 +1060,8 @@ static int adv7511_remove(struct i2c_client *i2c) | |||
| 1058 | 1060 | ||
| 1059 | drm_bridge_remove(&adv7511->bridge); | 1061 | drm_bridge_remove(&adv7511->bridge); |
| 1060 | 1062 | ||
| 1063 | adv7511_audio_exit(adv7511); | ||
| 1064 | |||
| 1061 | i2c_unregister_device(adv7511->i2c_edid); | 1065 | i2c_unregister_device(adv7511->i2c_edid); |
| 1062 | 1066 | ||
| 1063 | kfree(adv7511->edid); | 1067 | kfree(adv7511->edid); |
