static void hdmi_core_write_avi_infoframe(struct hdmi_core_data *core, struct hdmi_avi_infoframe *frame) { void __iomem *av_base = hdmi_av_base(core); u8 data[HDMI_INFOFRAME_SIZE(AVI)]; int i; hdmi_avi_infoframe_pack(frame, data, sizeof(data)); print_hex_dump_debug("AVI: ", DUMP_PREFIX_NONE, 16, 1, data, HDMI_INFOFRAME_SIZE(AVI), false); for (i = 0; i < sizeof(data); ++i) { hdmi_write_reg(av_base, HDMI_CORE_AV_AVI_BASE + i * 4, data[i]); } }
static int sii9022_audio_start(struct snd_soc_dai *dai, struct snd_pcm_hw_params *params) { struct panel_drv_data *dd = dev_get_drvdata(dai->dev); u8 i2s_config_reg = TPI_I2S_SD_DIRECTION_MSB_FIRST; u8 config_byte3_reg = TPI_AUDIO_CHANNEL_STREAM; u8 i2s_strm_hdr_reg[5] = { IEC958_AES0_CON_NOT_COPYRIGHT, IEC958_AES1_CON_GENERAL, IEC958_AES2_CON_SOURCE_UNSPEC, IEC958_AES3_CON_CLOCK_VARIABLE, 0 }; u8 infoframe_buf[HDMI_INFOFRAME_SIZE(AUDIO)]; struct hdmi_audio_infoframe infoframe; int ret, i; hdmi_audio_infoframe_init(&infoframe); dd->audio->channels = params_channels(params); switch (dd->audio->fmt & SND_SOC_DAIFMT_MASTER_MASK) { case SND_SOC_DAIFMT_CBS_CFS: break; default: dev_err(dai->dev, "Unsupported daifmt (0x%x) master\n", dd->audio->fmt); return -EINVAL; } switch (dd->audio->fmt & SND_SOC_DAIFMT_FORMAT_MASK) { case SND_SOC_DAIFMT_I2S: i2s_config_reg |= TPI_I2S_FIRST_BIT_SHIFT_YES | TPI_I2S_SD_JUSTIFY_LEFT; break; case SND_SOC_DAIFMT_LEFT_J: i2s_config_reg |= TPI_I2S_SD_JUSTIFY_LEFT; break; case SND_SOC_DAIFMT_RIGHT_J: i2s_config_reg |= TPI_I2S_SD_JUSTIFY_RIGHT; break; default: dev_err(dai->dev, "Unsupported daifmt (0x%x) format\n", dd->audio->fmt); return -EINVAL; } switch (dd->audio->fmt & SND_SOC_DAIFMT_INV_MASK) { case SND_SOC_DAIFMT_NB_NF: i2s_config_reg |= TPI_I2S_WS_POLARITY_HIGH | TPI_I2S_SCK_EDGE_RISING; break; case SND_SOC_DAIFMT_IB_NF: i2s_config_reg |= TPI_I2S_WS_POLARITY_HIGH | TPI_I2S_SCK_EDGE_FALLING; break; case SND_SOC_DAIFMT_NB_IF: i2s_config_reg |= TPI_I2S_WS_POLARITY_LOW | TPI_I2S_SCK_EDGE_RISING; break; case SND_SOC_DAIFMT_IB_IF: i2s_config_reg |= TPI_I2S_WS_POLARITY_LOW | TPI_I2S_SCK_EDGE_FALLING; break; } switch (params_format(params)) { case SNDRV_PCM_FORMAT_S16_LE: config_byte3_reg |= TPI_AUDIO_SAMPLE_SIZE_16; i2s_strm_hdr_reg[4] |= IEC958_AES4_CON_WORDLEN_20_16; infoframe.sample_size = HDMI_AUDIO_SAMPLE_SIZE_16; break; case SNDRV_PCM_FORMAT_S20_3LE: config_byte3_reg |= TPI_AUDIO_SAMPLE_SIZE_20; i2s_strm_hdr_reg[4] |= IEC958_AES4_CON_WORDLEN_24_20; infoframe.sample_size = HDMI_AUDIO_SAMPLE_SIZE_20; break; case SNDRV_PCM_FORMAT_S24_3LE: case SNDRV_PCM_FORMAT_S24_LE: case SNDRV_PCM_FORMAT_S32_LE: config_byte3_reg |= TPI_AUDIO_SAMPLE_SIZE_24; i2s_strm_hdr_reg[4] |= IEC958_AES4_CON_MAX_WORDLEN_24 | IEC958_AES4_CON_WORDLEN_24_20; infoframe.sample_size = HDMI_AUDIO_SAMPLE_SIZE_24; break; default: dev_err(dai->dev, "Unsupported sample format %d\n", params_format(params)); return -EINVAL; } ret = sii9022_select_mclk_div(&i2s_config_reg, params_rate(params), dd->audio->mclk); if (ret) dev_warn(dai->dev, "Inaccurate reference clock (%u/%d != %u)\n", dd->audio->mclk, ret, params_rate(params)); switch (params_rate(params)) { case 32000: i2s_strm_hdr_reg[3] |= IEC958_AES3_CON_FS_32000; i2s_strm_hdr_reg[4] |= IEC958_AES4_CON_ORIGFS_32000; infoframe.sample_frequency = HDMI_AUDIO_SAMPLE_FREQUENCY_32000; break; case 44100: i2s_strm_hdr_reg[3] |= IEC958_AES3_CON_FS_44100; i2s_strm_hdr_reg[4] |= IEC958_AES4_CON_ORIGFS_44100; infoframe.sample_frequency = HDMI_AUDIO_SAMPLE_FREQUENCY_44100; break; case 48000: i2s_strm_hdr_reg[3] |= IEC958_AES3_CON_FS_48000; i2s_strm_hdr_reg[4] |= IEC958_AES4_CON_ORIGFS_48000; infoframe.sample_frequency = HDMI_AUDIO_SAMPLE_FREQUENCY_48000; break; case 88200: i2s_strm_hdr_reg[3] |= IEC958_AES3_CON_FS_88200; i2s_strm_hdr_reg[4] |= IEC958_AES4_CON_ORIGFS_88200; infoframe.sample_frequency = HDMI_AUDIO_SAMPLE_FREQUENCY_88200; break; case 96000: i2s_strm_hdr_reg[3] |= IEC958_AES3_CON_FS_96000; i2s_strm_hdr_reg[4] |= IEC958_AES4_CON_ORIGFS_96000; infoframe.sample_frequency = HDMI_AUDIO_SAMPLE_FREQUENCY_96000; break; case 176400: i2s_strm_hdr_reg[3] |= IEC958_AES3_CON_FS_176400; i2s_strm_hdr_reg[4] |= IEC958_AES4_CON_ORIGFS_176400; infoframe.sample_frequency = HDMI_AUDIO_SAMPLE_FREQUENCY_176400; break; case 192000: i2s_strm_hdr_reg[3] |= IEC958_AES3_CON_FS_192000; i2s_strm_hdr_reg[4] |= IEC958_AES4_CON_ORIGFS_192000; infoframe.sample_frequency = HDMI_AUDIO_SAMPLE_FREQUENCY_192000; break; default: dev_err(dai->dev, "Unsupported sample rate %d\n", params_rate(params)); return -EINVAL; } ret = sii9022_mute(dai, true); if (ret < 0) return ret; regmap_write(dd->regmap, HDMI_TPI_I2S_INPUT_CONFIG_REG, i2s_config_reg); for (i = 0; i < ARRAY_SIZE(dd->audio->i2s_fifo_routing); i++) regmap_write(dd->regmap, HDMI_TPI_I2S_ENABLE_MAPPING_REG, dd->audio->i2s_fifo_routing[i]); regmap_write(dd->regmap, HDMI_TPI_AUDIO_CONFIG_BYTE3_REG, config_byte3_reg); regmap_bulk_write(dd->regmap, HDMI_TPI_I2S_STRM_HDR_BASE, i2s_strm_hdr_reg, ARRAY_SIZE(i2s_strm_hdr_reg)); infoframe.channels = params_channels(params); infoframe.coding_type = HDMI_AUDIO_CODING_TYPE_PCM; ret = hdmi_audio_infoframe_pack(&infoframe, infoframe_buf, sizeof(infoframe_buf)); if (ret < 0) { dev_err(dai->dev, "Failed to pack audio infoframe: %d\n", ret); return ret; } regmap_bulk_write(dd->regmap, HDMI_CPI_MISC_IF_SELECT_REG, infoframe_buf, ret); /* Decode Level 0 Packets */ regmap_write(dd->regmap, HDMI_IND_SET_PAGE, 0x02); regmap_write(dd->regmap, HDMI_IND_OFFSET, 0x24); regmap_write(dd->regmap, HDMI_IND_VALUE, 0x02); dev_dbg(dai->dev, "hdmi audio enabled\n"); return 0; }