Path: blob/master/drivers/gpu/drm/bridge/adv7511/adv7511_audio.c
26516 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 "adv7511.h"1516static void adv7511_calc_cts_n(unsigned int f_tmds, unsigned int fs,17unsigned int *cts, unsigned int *n)18{19switch (fs) {20case 32000:21case 48000:22case 96000:23case 192000:24*n = fs * 128 / 1000;25break;26case 44100:27case 88200:28case 176400:29*n = fs * 128 / 900;30break;31}3233*cts = ((f_tmds * *n) / (128 * fs)) * 1000;34}3536static int adv7511_update_cts_n(struct adv7511 *adv7511)37{38unsigned int cts = 0;39unsigned int n = 0;4041adv7511_calc_cts_n(adv7511->f_tmds, adv7511->f_audio, &cts, &n);4243regmap_write(adv7511->regmap, ADV7511_REG_N0, (n >> 16) & 0xf);44regmap_write(adv7511->regmap, ADV7511_REG_N1, (n >> 8) & 0xff);45regmap_write(adv7511->regmap, ADV7511_REG_N2, n & 0xff);4647regmap_write(adv7511->regmap, ADV7511_REG_CTS_MANUAL0,48(cts >> 16) & 0xf);49regmap_write(adv7511->regmap, ADV7511_REG_CTS_MANUAL1,50(cts >> 8) & 0xff);51regmap_write(adv7511->regmap, ADV7511_REG_CTS_MANUAL2,52cts & 0xff);5354return 0;55}5657int adv7511_hdmi_audio_prepare(struct drm_bridge *bridge,58struct drm_connector *connector,59struct hdmi_codec_daifmt *fmt,60struct hdmi_codec_params *hparms)61{62struct adv7511 *adv7511 = bridge_to_adv7511(bridge);63unsigned int audio_source, i2s_format = 0;64unsigned int invert_clock;65unsigned int rate;66unsigned int len;6768switch (hparms->sample_rate) {69case 32000:70rate = ADV7511_SAMPLE_FREQ_32000;71break;72case 44100:73rate = ADV7511_SAMPLE_FREQ_44100;74break;75case 48000:76rate = ADV7511_SAMPLE_FREQ_48000;77break;78case 88200:79rate = ADV7511_SAMPLE_FREQ_88200;80break;81case 96000:82rate = ADV7511_SAMPLE_FREQ_96000;83break;84case 176400:85rate = ADV7511_SAMPLE_FREQ_176400;86break;87case 192000:88rate = ADV7511_SAMPLE_FREQ_192000;89break;90default:91return -EINVAL;92}9394switch (hparms->sample_width) {95case 16:96len = ADV7511_I2S_SAMPLE_LEN_16;97break;98case 18:99len = ADV7511_I2S_SAMPLE_LEN_18;100break;101case 20:102len = ADV7511_I2S_SAMPLE_LEN_20;103break;104case 32:105if (fmt->bit_fmt != SNDRV_PCM_FORMAT_IEC958_SUBFRAME_LE)106return -EINVAL;107fallthrough;108case 24:109len = ADV7511_I2S_SAMPLE_LEN_24;110break;111default:112return -EINVAL;113}114115switch (fmt->fmt) {116case HDMI_I2S:117audio_source = ADV7511_AUDIO_SOURCE_I2S;118i2s_format = ADV7511_I2S_FORMAT_I2S;119if (fmt->bit_fmt == SNDRV_PCM_FORMAT_IEC958_SUBFRAME_LE)120i2s_format = ADV7511_I2S_IEC958_DIRECT;121break;122case HDMI_RIGHT_J:123audio_source = ADV7511_AUDIO_SOURCE_I2S;124i2s_format = ADV7511_I2S_FORMAT_RIGHT_J;125break;126case HDMI_LEFT_J:127audio_source = ADV7511_AUDIO_SOURCE_I2S;128i2s_format = ADV7511_I2S_FORMAT_LEFT_J;129break;130case HDMI_SPDIF:131audio_source = ADV7511_AUDIO_SOURCE_SPDIF;132break;133default:134return -EINVAL;135}136137invert_clock = fmt->bit_clk_inv;138139regmap_update_bits(adv7511->regmap, ADV7511_REG_AUDIO_SOURCE, 0x70,140audio_source << 4);141regmap_update_bits(adv7511->regmap, ADV7511_REG_AUDIO_CONFIG, BIT(6),142invert_clock << 6);143regmap_update_bits(adv7511->regmap, ADV7511_REG_I2S_CONFIG, 0x03,144i2s_format);145146adv7511->audio_source = audio_source;147148adv7511->f_audio = hparms->sample_rate;149150adv7511_update_cts_n(adv7511);151152regmap_update_bits(adv7511->regmap, ADV7511_REG_AUDIO_CFG3,153ADV7511_AUDIO_CFG3_LEN_MASK, len);154regmap_update_bits(adv7511->regmap, ADV7511_REG_I2C_FREQ_ID_CFG,155ADV7511_I2C_FREQ_ID_CFG_RATE_MASK, rate << 4);156157/* send current Audio infoframe values while updating */158regmap_update_bits(adv7511->regmap, ADV7511_REG_INFOFRAME_UPDATE,159BIT(5), BIT(5));160161regmap_write(adv7511->regmap, ADV7511_REG_AUDIO_INFOFRAME(0), 0x1);162163/* use Audio infoframe updated info */164regmap_update_bits(adv7511->regmap, ADV7511_REG_INFOFRAME_UPDATE,165BIT(5), 0);166167return 0;168}169170int adv7511_hdmi_audio_startup(struct drm_bridge *bridge,171struct drm_connector *connector)172{173struct adv7511 *adv7511 = bridge_to_adv7511(bridge);174175regmap_update_bits(adv7511->regmap, ADV7511_REG_AUDIO_CONFIG,176BIT(7), 0);177178/* hide Audio infoframe updates */179regmap_update_bits(adv7511->regmap, ADV7511_REG_INFOFRAME_UPDATE,180BIT(5), BIT(5));181/* enable N/CTS, enable Audio sample packets */182regmap_update_bits(adv7511->regmap, ADV7511_REG_PACKET_ENABLE1,183BIT(5), BIT(5));184/* enable N/CTS */185regmap_update_bits(adv7511->regmap, ADV7511_REG_PACKET_ENABLE1,186BIT(6), BIT(6));187/* not copyrighted */188regmap_update_bits(adv7511->regmap, ADV7511_REG_AUDIO_CFG1,189BIT(5), BIT(5));190/* enable audio infoframes */191regmap_update_bits(adv7511->regmap, ADV7511_REG_PACKET_ENABLE1,192BIT(3), BIT(3));193/* AV mute disable */194regmap_update_bits(adv7511->regmap, ADV7511_REG_GC(0),195BIT(7) | BIT(6), BIT(7));196/* use Audio infoframe updated info */197regmap_update_bits(adv7511->regmap, ADV7511_REG_INFOFRAME_UPDATE,198BIT(5), 0);199200/* enable SPDIF receiver */201if (adv7511->audio_source == ADV7511_AUDIO_SOURCE_SPDIF)202regmap_update_bits(adv7511->regmap, ADV7511_REG_AUDIO_CONFIG,203BIT(7), BIT(7));204205return 0;206}207208void adv7511_hdmi_audio_shutdown(struct drm_bridge *bridge,209struct drm_connector *connector)210{211struct adv7511 *adv7511 = bridge_to_adv7511(bridge);212213if (adv7511->audio_source == ADV7511_AUDIO_SOURCE_SPDIF)214regmap_update_bits(adv7511->regmap, ADV7511_REG_AUDIO_CONFIG,215BIT(7), 0);216}217218219