xref: /linux/sound/soc/qcom/lpass-hdmi.c (revision 06d07429858317ded2db7986113a9e0129cd599b)
17cb37b7bSV Sujith Kumar Reddy // SPDX-License-Identifier: GPL-2.0-only
27cb37b7bSV Sujith Kumar Reddy /*
37cb37b7bSV Sujith Kumar Reddy  * Copyright (c) 2020 The Linux Foundation. All rights reserved.
47cb37b7bSV Sujith Kumar Reddy  *
57cb37b7bSV Sujith Kumar Reddy  * lpass-hdmi.c -- ALSA SoC HDMI-CPU DAI driver for QTi LPASS HDMI
67cb37b7bSV Sujith Kumar Reddy  */
77cb37b7bSV Sujith Kumar Reddy 
87cb37b7bSV Sujith Kumar Reddy 
97cb37b7bSV Sujith Kumar Reddy #include <linux/kernel.h>
107cb37b7bSV Sujith Kumar Reddy #include <linux/module.h>
117cb37b7bSV Sujith Kumar Reddy #include <sound/pcm_params.h>
127cb37b7bSV Sujith Kumar Reddy #include <linux/regmap.h>
137cb37b7bSV Sujith Kumar Reddy #include <sound/soc.h>
147cb37b7bSV Sujith Kumar Reddy #include <sound/soc-dai.h>
157cb37b7bSV Sujith Kumar Reddy #include <dt-bindings/sound/sc7180-lpass.h>
167cb37b7bSV Sujith Kumar Reddy #include "lpass-lpaif-reg.h"
177cb37b7bSV Sujith Kumar Reddy #include "lpass.h"
187cb37b7bSV Sujith Kumar Reddy 
lpass_hdmi_daiops_hw_params(struct snd_pcm_substream * substream,struct snd_pcm_hw_params * params,struct snd_soc_dai * dai)197cb37b7bSV Sujith Kumar Reddy static int lpass_hdmi_daiops_hw_params(struct snd_pcm_substream *substream,
207cb37b7bSV Sujith Kumar Reddy 		struct snd_pcm_hw_params *params, struct snd_soc_dai *dai)
217cb37b7bSV Sujith Kumar Reddy {
227cb37b7bSV Sujith Kumar Reddy 	struct lpass_data *drvdata = snd_soc_dai_get_drvdata(dai);
237cb37b7bSV Sujith Kumar Reddy 	snd_pcm_format_t format = params_format(params);
247cb37b7bSV Sujith Kumar Reddy 	unsigned int rate = params_rate(params);
257cb37b7bSV Sujith Kumar Reddy 	unsigned int channels = params_channels(params);
267cb37b7bSV Sujith Kumar Reddy 	unsigned int ret;
27bcc96dc3SColin Ian King 	int bitwidth;
287cb37b7bSV Sujith Kumar Reddy 	unsigned int word_length;
297cb37b7bSV Sujith Kumar Reddy 	unsigned int ch_sts_buf0;
307cb37b7bSV Sujith Kumar Reddy 	unsigned int ch_sts_buf1;
317cb37b7bSV Sujith Kumar Reddy 	unsigned int data_format;
327cb37b7bSV Sujith Kumar Reddy 	unsigned int sampling_freq;
337cb37b7bSV Sujith Kumar Reddy 	unsigned int ch = 0;
347cb37b7bSV Sujith Kumar Reddy 	struct lpass_dp_metadata_ctl *meta_ctl = drvdata->meta_ctl;
357cb37b7bSV Sujith Kumar Reddy 	struct lpass_sstream_ctl *sstream_ctl = drvdata->sstream_ctl;
367cb37b7bSV Sujith Kumar Reddy 
377cb37b7bSV Sujith Kumar Reddy 	bitwidth = snd_pcm_format_width(format);
387cb37b7bSV Sujith Kumar Reddy 	if (bitwidth < 0) {
397cb37b7bSV Sujith Kumar Reddy 		dev_err(dai->dev, "%s invalid bit width given : %d\n",
407cb37b7bSV Sujith Kumar Reddy 					__func__, bitwidth);
417cb37b7bSV Sujith Kumar Reddy 		return bitwidth;
427cb37b7bSV Sujith Kumar Reddy 	}
437cb37b7bSV Sujith Kumar Reddy 
447cb37b7bSV Sujith Kumar Reddy 	switch (bitwidth) {
457cb37b7bSV Sujith Kumar Reddy 	case 16:
467cb37b7bSV Sujith Kumar Reddy 		word_length = LPASS_DP_AUDIO_BITWIDTH16;
477cb37b7bSV Sujith Kumar Reddy 		break;
487cb37b7bSV Sujith Kumar Reddy 	case 24:
497cb37b7bSV Sujith Kumar Reddy 		word_length = LPASS_DP_AUDIO_BITWIDTH24;
507cb37b7bSV Sujith Kumar Reddy 		break;
517cb37b7bSV Sujith Kumar Reddy 	default:
527cb37b7bSV Sujith Kumar Reddy 		dev_err(dai->dev, "%s invalid bit width given : %d\n",
537cb37b7bSV Sujith Kumar Reddy 					__func__, bitwidth);
547cb37b7bSV Sujith Kumar Reddy 		return -EINVAL;
557cb37b7bSV Sujith Kumar Reddy 	}
567cb37b7bSV Sujith Kumar Reddy 
577cb37b7bSV Sujith Kumar Reddy 	switch (rate) {
587cb37b7bSV Sujith Kumar Reddy 	case 32000:
597cb37b7bSV Sujith Kumar Reddy 		sampling_freq = LPASS_SAMPLING_FREQ32;
607cb37b7bSV Sujith Kumar Reddy 		break;
617cb37b7bSV Sujith Kumar Reddy 	case 44100:
627cb37b7bSV Sujith Kumar Reddy 		sampling_freq = LPASS_SAMPLING_FREQ44;
637cb37b7bSV Sujith Kumar Reddy 		break;
647cb37b7bSV Sujith Kumar Reddy 	case 48000:
657cb37b7bSV Sujith Kumar Reddy 		sampling_freq = LPASS_SAMPLING_FREQ48;
667cb37b7bSV Sujith Kumar Reddy 		break;
677cb37b7bSV Sujith Kumar Reddy 	default:
687cb37b7bSV Sujith Kumar Reddy 		dev_err(dai->dev, "%s invalid bit width given : %d\n",
697cb37b7bSV Sujith Kumar Reddy 					__func__, bitwidth);
707cb37b7bSV Sujith Kumar Reddy 		return -EINVAL;
717cb37b7bSV Sujith Kumar Reddy 	}
727cb37b7bSV Sujith Kumar Reddy 	data_format = LPASS_DATA_FORMAT_LINEAR;
737cb37b7bSV Sujith Kumar Reddy 	ch_sts_buf0 = (((data_format << LPASS_DATA_FORMAT_SHIFT) & LPASS_DATA_FORMAT_MASK)
747cb37b7bSV Sujith Kumar Reddy 				| ((sampling_freq << LPASS_FREQ_BIT_SHIFT) & LPASS_FREQ_BIT_MASK));
757cb37b7bSV Sujith Kumar Reddy 	ch_sts_buf1 = (word_length) & LPASS_WORDLENGTH_MASK;
767cb37b7bSV Sujith Kumar Reddy 
777cb37b7bSV Sujith Kumar Reddy 	ret = regmap_field_write(drvdata->tx_ctl->soft_reset, LPASS_TX_CTL_RESET);
787cb37b7bSV Sujith Kumar Reddy 	if (ret)
797cb37b7bSV Sujith Kumar Reddy 		return ret;
807cb37b7bSV Sujith Kumar Reddy 
817cb37b7bSV Sujith Kumar Reddy 	ret = regmap_field_write(drvdata->tx_ctl->soft_reset, LPASS_TX_CTL_CLEAR);
827cb37b7bSV Sujith Kumar Reddy 	if (ret)
837cb37b7bSV Sujith Kumar Reddy 		return ret;
847cb37b7bSV Sujith Kumar Reddy 
857cb37b7bSV Sujith Kumar Reddy 	ret = regmap_field_write(drvdata->hdmitx_legacy_en, LPASS_HDMITX_LEGACY_DISABLE);
867cb37b7bSV Sujith Kumar Reddy 	if (ret)
877cb37b7bSV Sujith Kumar Reddy 		return ret;
887cb37b7bSV Sujith Kumar Reddy 
897cb37b7bSV Sujith Kumar Reddy 	ret = regmap_field_write(drvdata->hdmitx_parity_calc_en, HDMITX_PARITY_CALC_EN);
907cb37b7bSV Sujith Kumar Reddy 	if (ret)
917cb37b7bSV Sujith Kumar Reddy 		return ret;
927cb37b7bSV Sujith Kumar Reddy 
937cb37b7bSV Sujith Kumar Reddy 	ret = regmap_field_write(drvdata->vbit_ctl->replace_vbit, REPLACE_VBIT);
947cb37b7bSV Sujith Kumar Reddy 	if (ret)
957cb37b7bSV Sujith Kumar Reddy 		return ret;
967cb37b7bSV Sujith Kumar Reddy 
977cb37b7bSV Sujith Kumar Reddy 	ret = regmap_field_write(drvdata->vbit_ctl->vbit_stream, LINEAR_PCM_DATA);
987cb37b7bSV Sujith Kumar Reddy 	if (ret)
997cb37b7bSV Sujith Kumar Reddy 		return ret;
1007cb37b7bSV Sujith Kumar Reddy 
1017cb37b7bSV Sujith Kumar Reddy 	ret = regmap_field_write(drvdata->hdmitx_ch_msb[0], ch_sts_buf1);
1027cb37b7bSV Sujith Kumar Reddy 	if (ret)
1037cb37b7bSV Sujith Kumar Reddy 		return ret;
1047cb37b7bSV Sujith Kumar Reddy 
1057cb37b7bSV Sujith Kumar Reddy 	ret = regmap_field_write(drvdata->hdmitx_ch_lsb[0], ch_sts_buf0);
1067cb37b7bSV Sujith Kumar Reddy 	if (ret)
1077cb37b7bSV Sujith Kumar Reddy 		return ret;
1087cb37b7bSV Sujith Kumar Reddy 
1097cb37b7bSV Sujith Kumar Reddy 	ret = regmap_field_write(drvdata->hdmi_tx_dmactl[0]->use_hw_chs, HW_MODE);
1107cb37b7bSV Sujith Kumar Reddy 	if (ret)
1117cb37b7bSV Sujith Kumar Reddy 		return ret;
1127cb37b7bSV Sujith Kumar Reddy 
1137cb37b7bSV Sujith Kumar Reddy 	ret = regmap_field_write(drvdata->hdmi_tx_dmactl[0]->hw_chs_sel, SW_MODE);
1147cb37b7bSV Sujith Kumar Reddy 	if (ret)
1157cb37b7bSV Sujith Kumar Reddy 		return ret;
1167cb37b7bSV Sujith Kumar Reddy 
1177cb37b7bSV Sujith Kumar Reddy 	ret = regmap_field_write(drvdata->hdmi_tx_dmactl[0]->use_hw_usr, HW_MODE);
1187cb37b7bSV Sujith Kumar Reddy 	if (ret)
1197cb37b7bSV Sujith Kumar Reddy 		return ret;
1207cb37b7bSV Sujith Kumar Reddy 
1217cb37b7bSV Sujith Kumar Reddy 	ret = regmap_field_write(drvdata->hdmi_tx_dmactl[0]->hw_usr_sel, SW_MODE);
1227cb37b7bSV Sujith Kumar Reddy 	if (ret)
1237cb37b7bSV Sujith Kumar Reddy 		return ret;
1247cb37b7bSV Sujith Kumar Reddy 
1257cb37b7bSV Sujith Kumar Reddy 	ret = regmap_field_write(meta_ctl->mute, LPASS_MUTE_ENABLE);
1267cb37b7bSV Sujith Kumar Reddy 	if (ret)
1277cb37b7bSV Sujith Kumar Reddy 		return ret;
1287cb37b7bSV Sujith Kumar Reddy 
1297cb37b7bSV Sujith Kumar Reddy 	ret = regmap_field_write(meta_ctl->as_sdp_cc, channels - 1);
1307cb37b7bSV Sujith Kumar Reddy 	if (ret)
1317cb37b7bSV Sujith Kumar Reddy 		return ret;
1327cb37b7bSV Sujith Kumar Reddy 
1337cb37b7bSV Sujith Kumar Reddy 	ret = regmap_field_write(meta_ctl->as_sdp_ct, LPASS_META_DEFAULT_VAL);
1347cb37b7bSV Sujith Kumar Reddy 	if (ret)
1357cb37b7bSV Sujith Kumar Reddy 		return ret;
1367cb37b7bSV Sujith Kumar Reddy 
1377cb37b7bSV Sujith Kumar Reddy 	ret = regmap_field_write(meta_ctl->aif_db4, LPASS_META_DEFAULT_VAL);
1387cb37b7bSV Sujith Kumar Reddy 	if (ret)
1397cb37b7bSV Sujith Kumar Reddy 		return ret;
1407cb37b7bSV Sujith Kumar Reddy 
1417cb37b7bSV Sujith Kumar Reddy 	ret = regmap_field_write(meta_ctl->frequency, sampling_freq);
1427cb37b7bSV Sujith Kumar Reddy 	if (ret)
1437cb37b7bSV Sujith Kumar Reddy 		return ret;
1447cb37b7bSV Sujith Kumar Reddy 
1457cb37b7bSV Sujith Kumar Reddy 	ret = regmap_field_write(meta_ctl->mst_index, LPASS_META_DEFAULT_VAL);
1467cb37b7bSV Sujith Kumar Reddy 	if (ret)
1477cb37b7bSV Sujith Kumar Reddy 		return ret;
1487cb37b7bSV Sujith Kumar Reddy 
1497cb37b7bSV Sujith Kumar Reddy 	ret = regmap_field_write(meta_ctl->dptx_index, LPASS_META_DEFAULT_VAL);
1507cb37b7bSV Sujith Kumar Reddy 	if (ret)
1517cb37b7bSV Sujith Kumar Reddy 		return ret;
1527cb37b7bSV Sujith Kumar Reddy 
1537cb37b7bSV Sujith Kumar Reddy 	ret = regmap_field_write(sstream_ctl->sstream_en, LPASS_SSTREAM_DISABLE);
1547cb37b7bSV Sujith Kumar Reddy 	if (ret)
1557cb37b7bSV Sujith Kumar Reddy 		return ret;
1567cb37b7bSV Sujith Kumar Reddy 
1577cb37b7bSV Sujith Kumar Reddy 	ret = regmap_field_write(sstream_ctl->dma_sel, ch);
1587cb37b7bSV Sujith Kumar Reddy 	if (ret)
1597cb37b7bSV Sujith Kumar Reddy 		return ret;
1607cb37b7bSV Sujith Kumar Reddy 
1617cb37b7bSV Sujith Kumar Reddy 	ret = regmap_field_write(sstream_ctl->auto_bbit_en, LPASS_SSTREAM_DEFAULT_ENABLE);
1627cb37b7bSV Sujith Kumar Reddy 	if (ret)
1637cb37b7bSV Sujith Kumar Reddy 		return ret;
1647cb37b7bSV Sujith Kumar Reddy 
1657cb37b7bSV Sujith Kumar Reddy 	ret = regmap_field_write(sstream_ctl->layout, LPASS_SSTREAM_DEFAULT_DISABLE);
1667cb37b7bSV Sujith Kumar Reddy 	if (ret)
1677cb37b7bSV Sujith Kumar Reddy 		return ret;
1687cb37b7bSV Sujith Kumar Reddy 
1697cb37b7bSV Sujith Kumar Reddy 	ret = regmap_field_write(sstream_ctl->layout_sp, LPASS_LAYOUT_SP_DEFAULT);
1707cb37b7bSV Sujith Kumar Reddy 	if (ret)
1717cb37b7bSV Sujith Kumar Reddy 		return ret;
1727cb37b7bSV Sujith Kumar Reddy 
1737cb37b7bSV Sujith Kumar Reddy 	ret = regmap_field_write(sstream_ctl->dp_audio, LPASS_SSTREAM_DEFAULT_ENABLE);
1747cb37b7bSV Sujith Kumar Reddy 	if (ret)
1757cb37b7bSV Sujith Kumar Reddy 		return ret;
1767cb37b7bSV Sujith Kumar Reddy 
1777cb37b7bSV Sujith Kumar Reddy 	ret = regmap_field_write(sstream_ctl->set_sp_on_en, LPASS_SSTREAM_DEFAULT_ENABLE);
1787cb37b7bSV Sujith Kumar Reddy 	if (ret)
1797cb37b7bSV Sujith Kumar Reddy 		return ret;
1807cb37b7bSV Sujith Kumar Reddy 
1817cb37b7bSV Sujith Kumar Reddy 	ret = regmap_field_write(sstream_ctl->dp_sp_b_hw_en, LPASS_SSTREAM_DEFAULT_ENABLE);
1827cb37b7bSV Sujith Kumar Reddy 	if (ret)
1837cb37b7bSV Sujith Kumar Reddy 		return ret;
1847cb37b7bSV Sujith Kumar Reddy 
1857cb37b7bSV Sujith Kumar Reddy 	ret = regmap_field_write(sstream_ctl->dp_staffing_en, LPASS_SSTREAM_DEFAULT_ENABLE);
1867cb37b7bSV Sujith Kumar Reddy 
1877cb37b7bSV Sujith Kumar Reddy 	return ret;
1887cb37b7bSV Sujith Kumar Reddy }
1897cb37b7bSV Sujith Kumar Reddy 
lpass_hdmi_daiops_prepare(struct snd_pcm_substream * substream,struct snd_soc_dai * dai)1907cb37b7bSV Sujith Kumar Reddy static int lpass_hdmi_daiops_prepare(struct snd_pcm_substream *substream,
1917cb37b7bSV Sujith Kumar Reddy 		struct snd_soc_dai *dai)
1927cb37b7bSV Sujith Kumar Reddy {
1937cb37b7bSV Sujith Kumar Reddy 	int ret;
1947cb37b7bSV Sujith Kumar Reddy 	struct lpass_data *drvdata = snd_soc_dai_get_drvdata(dai);
1957cb37b7bSV Sujith Kumar Reddy 
1967cb37b7bSV Sujith Kumar Reddy 	ret = regmap_field_write(drvdata->sstream_ctl->sstream_en, LPASS_SSTREAM_ENABLE);
1977cb37b7bSV Sujith Kumar Reddy 	if (ret)
1987cb37b7bSV Sujith Kumar Reddy 		return ret;
1997cb37b7bSV Sujith Kumar Reddy 
2007cb37b7bSV Sujith Kumar Reddy 	ret = regmap_field_write(drvdata->meta_ctl->mute, LPASS_MUTE_DISABLE);
2017cb37b7bSV Sujith Kumar Reddy 
2027cb37b7bSV Sujith Kumar Reddy 	return ret;
2037cb37b7bSV Sujith Kumar Reddy }
2047cb37b7bSV Sujith Kumar Reddy 
lpass_hdmi_daiops_trigger(struct snd_pcm_substream * substream,int cmd,struct snd_soc_dai * dai)2057cb37b7bSV Sujith Kumar Reddy static int lpass_hdmi_daiops_trigger(struct snd_pcm_substream *substream,
2067cb37b7bSV Sujith Kumar Reddy 		int cmd, struct snd_soc_dai *dai)
2077cb37b7bSV Sujith Kumar Reddy {
2087cb37b7bSV Sujith Kumar Reddy 	struct lpass_data *drvdata = snd_soc_dai_get_drvdata(dai);
2097cb37b7bSV Sujith Kumar Reddy 	struct lpass_dp_metadata_ctl *meta_ctl = drvdata->meta_ctl;
2107cb37b7bSV Sujith Kumar Reddy 	struct lpass_sstream_ctl *sstream_ctl = drvdata->sstream_ctl;
2117cb37b7bSV Sujith Kumar Reddy 	int ret = -EINVAL;
2127cb37b7bSV Sujith Kumar Reddy 
2137cb37b7bSV Sujith Kumar Reddy 	switch (cmd) {
2147cb37b7bSV Sujith Kumar Reddy 	case SNDRV_PCM_TRIGGER_START:
2157cb37b7bSV Sujith Kumar Reddy 	case SNDRV_PCM_TRIGGER_RESUME:
2167cb37b7bSV Sujith Kumar Reddy 	case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
2177cb37b7bSV Sujith Kumar Reddy 		ret = regmap_field_write(sstream_ctl->sstream_en, LPASS_SSTREAM_ENABLE);
2187cb37b7bSV Sujith Kumar Reddy 		if (ret)
2197cb37b7bSV Sujith Kumar Reddy 			return ret;
2207cb37b7bSV Sujith Kumar Reddy 
2217cb37b7bSV Sujith Kumar Reddy 		ret = regmap_field_write(meta_ctl->mute, LPASS_MUTE_DISABLE);
2227cb37b7bSV Sujith Kumar Reddy 		if (ret)
2237cb37b7bSV Sujith Kumar Reddy 			return ret;
2247cb37b7bSV Sujith Kumar Reddy 
2257cb37b7bSV Sujith Kumar Reddy 		break;
2267cb37b7bSV Sujith Kumar Reddy 	case SNDRV_PCM_TRIGGER_STOP:
2277cb37b7bSV Sujith Kumar Reddy 	case SNDRV_PCM_TRIGGER_SUSPEND:
2287cb37b7bSV Sujith Kumar Reddy 	case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
2297cb37b7bSV Sujith Kumar Reddy 		ret = regmap_field_write(sstream_ctl->sstream_en, LPASS_SSTREAM_DISABLE);
2307cb37b7bSV Sujith Kumar Reddy 		if (ret)
2317cb37b7bSV Sujith Kumar Reddy 			return ret;
2327cb37b7bSV Sujith Kumar Reddy 
2337cb37b7bSV Sujith Kumar Reddy 		ret = regmap_field_write(meta_ctl->mute, LPASS_MUTE_ENABLE);
2347cb37b7bSV Sujith Kumar Reddy 		if (ret)
2357cb37b7bSV Sujith Kumar Reddy 			return ret;
2367cb37b7bSV Sujith Kumar Reddy 
2377cb37b7bSV Sujith Kumar Reddy 		ret = regmap_field_write(sstream_ctl->dp_audio, 0);
2387cb37b7bSV Sujith Kumar Reddy 		if (ret)
2397cb37b7bSV Sujith Kumar Reddy 			return ret;
2407cb37b7bSV Sujith Kumar Reddy 
2417cb37b7bSV Sujith Kumar Reddy 		break;
2427cb37b7bSV Sujith Kumar Reddy 	}
2437cb37b7bSV Sujith Kumar Reddy 	return ret;
2447cb37b7bSV Sujith Kumar Reddy }
2457cb37b7bSV Sujith Kumar Reddy 
2467cb37b7bSV Sujith Kumar Reddy const struct snd_soc_dai_ops asoc_qcom_lpass_hdmi_dai_ops = {
2477cb37b7bSV Sujith Kumar Reddy 	.hw_params	= lpass_hdmi_daiops_hw_params,
2487cb37b7bSV Sujith Kumar Reddy 	.prepare	= lpass_hdmi_daiops_prepare,
2497cb37b7bSV Sujith Kumar Reddy 	.trigger	= lpass_hdmi_daiops_trigger,
2507cb37b7bSV Sujith Kumar Reddy };
2517cb37b7bSV Sujith Kumar Reddy EXPORT_SYMBOL_GPL(asoc_qcom_lpass_hdmi_dai_ops);
2527cb37b7bSV Sujith Kumar Reddy 
2537cb37b7bSV Sujith Kumar Reddy MODULE_DESCRIPTION("QTi LPASS HDMI Driver");
254*bb339245SKrzysztof Kozlowski MODULE_LICENSE("GPL");
255