Path: blob/master/drivers/gpu/drm/bridge/adv7511/adv7511_audio.c
29285 views
// SPDX-License-Identifier: GPL-2.0-only1/*2* Analog Devices ADV7511 HDMI transmitter driver3*4* Copyright 2012 Analog Devices Inc.5* Copyright (c) 2016, Linaro Limited6*/78#include <sound/core.h>9#include <sound/hdmi-codec.h>10#include <sound/pcm.h>11#include <sound/soc.h>12#include <linux/of_graph.h>1314#include <drm/display/drm_hdmi_state_helper.h>1516#include "adv7511.h"1718static void adv7511_calc_cts_n(unsigned int f_tmds, unsigned int fs,19unsigned int *cts, unsigned int *n)20{21switch (fs) {22case 32000:23case 48000:24case 96000:25case 192000:26*n = fs * 128 / 1000;27break;28case 44100:29case 88200:30case 176400:31*n = fs * 128 / 900;32break;33}3435*cts = ((f_tmds * *n) / (128 * fs)) * 1000;36}3738static int adv7511_update_cts_n(struct adv7511 *adv7511)39{40unsigned int cts = 0;41unsigned int n = 0;4243adv7511_calc_cts_n(adv7511->f_tmds, adv7511->f_audio, &cts, &n);4445regmap_write(adv7511->regmap, ADV7511_REG_N0, (n >> 16) & 0xf);46regmap_write(adv7511->regmap, ADV7511_REG_N1, (n >> 8) & 0xff);47regmap_write(adv7511->regmap, ADV7511_REG_N2, n & 0xff);4849regmap_write(adv7511->regmap, ADV7511_REG_CTS_MANUAL0,50(cts >> 16) & 0xf);51regmap_write(adv7511->regmap, ADV7511_REG_CTS_MANUAL1,52(cts >> 8) & 0xff);53regmap_write(adv7511->regmap, ADV7511_REG_CTS_MANUAL2,54cts & 0xff);5556return 0;57}5859int adv7511_hdmi_audio_prepare(struct drm_bridge *bridge,60struct drm_connector *connector,61struct hdmi_codec_daifmt *fmt,62struct hdmi_codec_params *hparms)63{64struct adv7511 *adv7511 = bridge_to_adv7511(bridge);65unsigned int audio_source, i2s_format = 0;66unsigned int invert_clock;67unsigned int rate;68unsigned int len;6970switch (hparms->sample_rate) {71case 32000:72rate = ADV7511_SAMPLE_FREQ_32000;73break;74case 44100:75rate = ADV7511_SAMPLE_FREQ_44100;76break;77case 48000:78rate = ADV7511_SAMPLE_FREQ_48000;79break;80case 88200:81rate = ADV7511_SAMPLE_FREQ_88200;82break;83case 96000:84rate = ADV7511_SAMPLE_FREQ_96000;85break;86case 176400:87rate = ADV7511_SAMPLE_FREQ_176400;88break;89case 192000:90rate = ADV7511_SAMPLE_FREQ_192000;91break;92default:93return -EINVAL;94}9596switch (hparms->sample_width) {97case 16:98len = ADV7511_I2S_SAMPLE_LEN_16;99break;100case 18:101len = ADV7511_I2S_SAMPLE_LEN_18;102break;103case 20:104len = ADV7511_I2S_SAMPLE_LEN_20;105break;106case 32:107if (fmt->bit_fmt != SNDRV_PCM_FORMAT_IEC958_SUBFRAME_LE)108return -EINVAL;109fallthrough;110case 24:111len = ADV7511_I2S_SAMPLE_LEN_24;112break;113default:114return -EINVAL;115}116117switch (fmt->fmt) {118case HDMI_I2S:119audio_source = ADV7511_AUDIO_SOURCE_I2S;120i2s_format = ADV7511_I2S_FORMAT_I2S;121if (fmt->bit_fmt == SNDRV_PCM_FORMAT_IEC958_SUBFRAME_LE)122i2s_format = ADV7511_I2S_IEC958_DIRECT;123break;124case HDMI_RIGHT_J:125audio_source = ADV7511_AUDIO_SOURCE_I2S;126i2s_format = ADV7511_I2S_FORMAT_RIGHT_J;127break;128case HDMI_LEFT_J:129audio_source = ADV7511_AUDIO_SOURCE_I2S;130i2s_format = ADV7511_I2S_FORMAT_LEFT_J;131break;132case HDMI_SPDIF:133audio_source = ADV7511_AUDIO_SOURCE_SPDIF;134break;135default:136return -EINVAL;137}138139invert_clock = fmt->bit_clk_inv;140141regmap_update_bits(adv7511->regmap, ADV7511_REG_AUDIO_SOURCE, 0x70,142audio_source << 4);143regmap_update_bits(adv7511->regmap, ADV7511_REG_AUDIO_CONFIG, BIT(6),144invert_clock << 6);145regmap_update_bits(adv7511->regmap, ADV7511_REG_I2S_CONFIG, 0x03,146i2s_format);147148adv7511->audio_source = audio_source;149150adv7511->f_audio = hparms->sample_rate;151152adv7511_update_cts_n(adv7511);153154regmap_update_bits(adv7511->regmap, ADV7511_REG_AUDIO_CFG3,155ADV7511_AUDIO_CFG3_LEN_MASK, len);156regmap_update_bits(adv7511->regmap, ADV7511_REG_I2C_FREQ_ID_CFG,157ADV7511_I2C_FREQ_ID_CFG_RATE_MASK, rate << 4);158159return drm_atomic_helper_connector_hdmi_update_audio_infoframe(connector,160&hparms->cea);161}162163int adv7511_hdmi_audio_startup(struct drm_bridge *bridge,164struct drm_connector *connector)165{166struct adv7511 *adv7511 = bridge_to_adv7511(bridge);167168regmap_update_bits(adv7511->regmap, ADV7511_REG_AUDIO_CONFIG,169BIT(7), 0);170171/* hide Audio infoframe updates */172regmap_update_bits(adv7511->regmap, ADV7511_REG_INFOFRAME_UPDATE,173BIT(5), BIT(5));174/* enable N/CTS, enable Audio sample packets */175regmap_update_bits(adv7511->regmap, ADV7511_REG_PACKET_ENABLE1,176BIT(5), BIT(5));177/* enable N/CTS */178regmap_update_bits(adv7511->regmap, ADV7511_REG_PACKET_ENABLE1,179BIT(6), BIT(6));180/* not copyrighted */181regmap_update_bits(adv7511->regmap, ADV7511_REG_AUDIO_CFG1,182BIT(5), BIT(5));183/* AV mute disable */184regmap_update_bits(adv7511->regmap, ADV7511_REG_GC(0),185BIT(7) | BIT(6), BIT(7));186187/* enable SPDIF receiver */188if (adv7511->audio_source == ADV7511_AUDIO_SOURCE_SPDIF)189regmap_update_bits(adv7511->regmap, ADV7511_REG_AUDIO_CONFIG,190BIT(7), BIT(7));191192return 0;193}194195void adv7511_hdmi_audio_shutdown(struct drm_bridge *bridge,196struct drm_connector *connector)197{198struct adv7511 *adv7511 = bridge_to_adv7511(bridge);199200if (adv7511->audio_source == ADV7511_AUDIO_SOURCE_SPDIF)201regmap_update_bits(adv7511->regmap, ADV7511_REG_AUDIO_CONFIG,202BIT(7), 0);203204drm_atomic_helper_connector_hdmi_clear_audio_infoframe(connector);205}206207208