Пример #1
0
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;
}