Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 0f7ef974 authored by Linux Build Service Account's avatar Linux Build Service Account Committed by Gerrit - the friendly Code Review server
Browse files

Merge "ASoC: msm8996: add support for automotive sound card"

parents 9d830ba0 85a85595
Loading
Loading
Loading
Loading
+3 −1
Original line number Diff line number Diff line
@@ -1085,7 +1085,9 @@ Example:
Required properties:
- compatible : "qcom,msm8996-asoc-snd-tomtom" for tomtom codec and
		node is "sound" and "qcom,msm8996-asoc-snd-tasha"
		for tasha codec and node is "sound-9335"
		for tasha codec and node is "sound-9335" and
		"qcom,msm8996-asoc-snd-auto" for auto codec and
		node is "sound-auto"
- qcom,model : The user-visible name of this sound card.
- qcom,tomtom-mclk-clk-freq : MCLK frequency value for tomtom codec
			      and node is "sound"
+265 −6
Original line number Diff line number Diff line
@@ -126,6 +126,15 @@ static struct afe_clk_set mi2s_tx_clk = {
	0,
};

static struct afe_clk_set mi2s_rx_clk = {
	AFE_API_VERSION_I2S_CONFIG,
	Q6AFE_LPASS_CLK_ID_QUAD_MI2S_IBIT,
	Q6AFE_LPASS_IBIT_CLK_1_P536_MHZ,
	Q6AFE_LPASS_CLK_ATTRIBUTE_COUPLE_NO,
	Q6AFE_LPASS_CLK_ROOT_DEFAULT,
	0,
};

struct msm8996_wsa881x_dev_info {
	struct device_node *of_node;
	u32 index;
@@ -164,6 +173,8 @@ static void *def_tasha_mbhc_cal(void);
static int msm_snd_enable_codec_ext_clk(struct snd_soc_codec *codec,
					int enable, bool dapm);
static int msm8996_wsa881x_init(struct snd_soc_component *component);
static bool msm8996_check_auto_snd_card(struct platform_device *pdev);
static int msm8996_init_auto_snd_card(struct platform_device *pdev);

/*
 * Need to report LINEIN
@@ -1222,6 +1233,112 @@ static struct snd_soc_ops msm8996_mi2s_be_ops = {
	.shutdown = msm8996_mi2s_snd_shutdown,
};

static int msm8996_mi2s_snd_auto_startup(struct snd_pcm_substream *substream)
{
	int ret = 0;
	struct snd_soc_pcm_runtime *rtd = substream->private_data;
	struct snd_soc_dai *cpu_dai = rtd->cpu_dai;

	pr_debug("%s: substream = %s  stream = %d\n", __func__,
		 substream->name, substream->stream);

	switch (cpu_dai->id) {
	case 0:	/*MSM_PRIM_MI2S*/
		break;
	case 1:	/*MSM_SEC_MI2S*/
		break;
	case 2:	/*MSM_TERT_MI2S*/
		mi2s_tx_clk.enable = 1;
		ret = afe_set_lpass_clock_v2(AFE_PORT_ID_TERTIARY_MI2S_TX,
					&mi2s_tx_clk);
		if (ret < 0) {
			pr_err("%s: afe lpass clock failed, err:%d\n",
				__func__, ret);
			goto err;
		}
		ret = snd_soc_dai_set_fmt(cpu_dai, SND_SOC_DAIFMT_CBM_CFM);
		if (ret < 0)
			pr_err("%s: set fmt cpu dai failed, err:%d\n",
				__func__, ret);
		break;
	case 3:	/*MSM_QUAT_MI2S*/
		mi2s_rx_clk.enable = 1;
		ret = afe_set_lpass_clock_v2(AFE_PORT_ID_QUATERNARY_MI2S_RX,
					&mi2s_rx_clk);
		if (ret < 0) {
			pr_err("%s: afe lpass clock failed, err:%d\n",
				__func__, ret);
			goto err;
		}
		ret = snd_soc_dai_set_fmt(cpu_dai, SND_SOC_DAIFMT_CBS_CFS);
		if (ret < 0)
			pr_err("%s: set fmt cpu dai failed, err:%d\n",
				__func__, ret);
		break;
	default:
		pr_err("%s: invalid cpu_dai id 0x%x\n", __func__, cpu_dai->id);
		break;
	}

err:
	return ret;
}

static void msm8996_mi2s_snd_auto_shutdown(struct snd_pcm_substream *substream)
{
	int ret = 0;
	struct snd_soc_pcm_runtime *rtd = substream->private_data;
	struct snd_soc_dai *cpu_dai = rtd->cpu_dai;

	pr_debug("%s: substream = %s  stream = %d\n", __func__,
		substream->name, substream->stream);

	switch (cpu_dai->id) {
	case 0:	/*MSM_PRIM_MI2S*/
		break;
	case 1:	/*MSM_SEC_MI2S*/
		break;
	case 2:	/*MSM_TERT_MI2S*/
		mi2s_tx_clk.enable = 0;
		ret = afe_set_lpass_clock_v2(AFE_PORT_ID_TERTIARY_MI2S_TX,
					&mi2s_tx_clk);
		if (ret < 0)
			pr_err("%s: afe lpass clock failed, err:%d\n",
				__func__, ret);
		break;
	case 3:	/*MSM_QUAT_MI2S*/
		mi2s_rx_clk.enable = 0;
		ret = afe_set_lpass_clock_v2(AFE_PORT_ID_QUATERNARY_MI2S_RX,
					&mi2s_rx_clk);
		if (ret < 0)
			pr_err("%s: afe lpass clock failed, err:%d\n",
				__func__, ret);
		break;
	default:
		pr_err("%s: invalid cpu_dai id 0x%x\n", __func__, cpu_dai->id);
		break;
	}
}

static struct snd_soc_ops msm8996_mi2s_auto_be_ops = {
	.startup = msm8996_mi2s_snd_auto_startup,
	.shutdown = msm8996_mi2s_snd_auto_shutdown,
};

static int msm_mi2s_rx_be_hw_params_fixup(struct snd_soc_pcm_runtime *rtd,
				     struct snd_pcm_hw_params *params)
{
	struct snd_interval *rate = hw_param_interval(params,
					SNDRV_PCM_HW_PARAM_RATE);
	struct snd_interval *channels = hw_param_interval(params,
					SNDRV_PCM_HW_PARAM_CHANNELS);

	pr_debug("%s: channel:%d\n", __func__, msm_tert_mi2s_tx_ch);
	rate->min = rate->max = SAMPLING_RATE_48KHZ;
	channels->min = channels->max = msm_tert_mi2s_tx_ch;
	return 0;
}

static int msm_slim_5_rx_be_hw_params_fixup(struct snd_soc_pcm_runtime *rtd,
					    struct snd_pcm_hw_params *params)
{
@@ -2894,7 +3011,11 @@ static struct snd_soc_dai_link msm8996_common_be_dai_links[] = {
		.be_id = MSM_BACKEND_DAI_VOICE2_PLAYBACK_TX,
		.be_hw_params_fixup = msm_be_hw_params_fixup,
		.ignore_suspend = 1,
	},
	}
};

static struct snd_soc_dai_link msm8996_tasha_be_dai_links[] = {
	/* Backend DAI Links */
	{
		.name = LPASS_BE_TERT_MI2S_TX,
		.stream_name = "Tertiary MI2S Capture",
@@ -2908,11 +3029,7 @@ static struct snd_soc_dai_link msm8996_common_be_dai_links[] = {
		.be_hw_params_fixup = msm_tx_be_hw_params_fixup,
		.ops = &msm8996_mi2s_be_ops,
		.ignore_suspend = 1,
	}
};

static struct snd_soc_dai_link msm8996_tasha_be_dai_links[] = {
	/* Backend DAI Links */
	},
	{
		.name = LPASS_BE_SLIMBUS_0_RX,
		.stream_name = "Slimbus Playback",
@@ -3053,6 +3170,38 @@ static struct snd_soc_dai_link msm8996_tasha_be_dai_links[] = {
	},
};

static struct snd_soc_dai_link msm8996_auto_be_dai_links[] = {
	/* Backend DAI Links */
	{
		.name = LPASS_BE_TERT_MI2S_TX,
		.stream_name = "Tertiary MI2S Capture",
		.cpu_dai_name = "msm-dai-q6-mi2s.2",
		.platform_name = "msm-pcm-routing",
		.codec_name = "msm-stub-codec.1",
		.codec_dai_name = "msm-stub-tx",
		.no_pcm = 1,
		.dpcm_capture = 1,
		.be_id = MSM_BACKEND_DAI_TERTIARY_MI2S_TX,
		.be_hw_params_fixup = msm_tx_be_hw_params_fixup,
		.ops = &msm8996_mi2s_auto_be_ops,
		.ignore_suspend = 1,
	},
	{
		.name = LPASS_BE_QUAT_MI2S_RX,
		.stream_name = "Quaternary MI2S Playback",
		.cpu_dai_name = "msm-dai-q6-mi2s.3",
		.platform_name = "msm-pcm-routing",
		.codec_name = "msm-stub-codec.1",
		.codec_dai_name = "msm-stub-rx",
		.no_pcm = 1,
		.dpcm_playback = 1,
		.be_id = MSM_BACKEND_DAI_QUATERNARY_MI2S_RX,
		.be_hw_params_fixup = msm_mi2s_rx_be_hw_params_fixup,
		.ops = &msm8996_mi2s_auto_be_ops,
		.ignore_suspend = 1,
	},
};

static struct snd_soc_dai_link msm8996_hdmi_dai_link[] = {
	/* HDMI BACK END DAI Link */
	{
@@ -3078,6 +3227,12 @@ static struct snd_soc_dai_link msm8996_tasha_dai_links[
			 ARRAY_SIZE(msm8996_tasha_be_dai_links) +
			 ARRAY_SIZE(msm8996_hdmi_dai_link)];

static struct snd_soc_dai_link msm8996_auto_dai_links[
			 ARRAY_SIZE(msm8996_common_dai_links) +
			 ARRAY_SIZE(msm8996_common_be_dai_links) +
			 ARRAY_SIZE(msm8996_auto_be_dai_links) +
			 ARRAY_SIZE(msm8996_hdmi_dai_link)];

static int msm8996_wsa881x_init(struct snd_soc_component *component)
{
	u8 spkleft_ports[WSA881X_MAX_SWR_PORTS] = {100, 101, 102, 106};
@@ -3132,6 +3287,10 @@ struct snd_soc_card snd_soc_card_tasha_msm8996 = {
	.name		= "msm8996-tasha-snd-card",
};

struct snd_soc_card snd_soc_card_auto_msm8996 = {
	.name		= "msm8996-auto-snd-card",
};

static int msm8996_populate_dai_link_component_of_node(
					struct snd_soc_card *card)
{
@@ -3272,6 +3431,8 @@ static int msm8996_prepare_hifi(struct snd_soc_card *card)
static const struct of_device_id msm8996_asoc_machine_of_match[]  = {
	{ .compatible = "qcom,msm8996-asoc-snd-tasha",
	  .data = "tasha_codec"},
	{ .compatible = "qcom,msm8996-asoc-snd-auto",
	  .data = "auto_codec"},
	{},
};

@@ -3310,6 +3471,23 @@ static struct snd_soc_card *populate_snd_card_dailinks(struct device *dev)

		dailink = msm8996_tasha_dai_links;
		len_4 = len_3 + ARRAY_SIZE(msm8996_tasha_be_dai_links);
	} else if (!strcmp(match->data, "auto_codec")) {
		card = &snd_soc_card_auto_msm8996;
		len_1 = ARRAY_SIZE(msm8996_common_dai_links);
		len_2 = len_1 + ARRAY_SIZE(msm8996_common_be_dai_links);

		memcpy(msm8996_auto_dai_links,
		       msm8996_common_dai_links,
		       sizeof(msm8996_common_dai_links));
		memcpy(msm8996_auto_dai_links + len_1,
		       msm8996_common_be_dai_links,
		       sizeof(msm8996_common_be_dai_links));
		memcpy(msm8996_auto_dai_links + len_2,
		       msm8996_auto_be_dai_links,
		       sizeof(msm8996_auto_be_dai_links));

		dailink = msm8996_auto_dai_links;
		len_4 = len_2 + ARRAY_SIZE(msm8996_auto_be_dai_links);
	}

	if (of_property_read_bool(dev->of_node, "qcom,hdmi-audio-rx")) {
@@ -3492,6 +3670,84 @@ static int msm8996_init_wsa_dev(struct platform_device *pdev,
	return 0;
}

static bool msm8996_check_auto_snd_card(struct platform_device *pdev)
{
	const struct of_device_id *match;
	bool ret = false;

	match = of_match_node(msm8996_asoc_machine_of_match,
			pdev->dev.of_node);
	if (!match) {
		dev_err(&pdev->dev, "%s: no matched codec is found.\n",
			__func__);
		goto end;
	}

	if (!strcmp(match->data, "auto_codec"))
		ret = true;
end:
	return ret;
}

static int msm8996_init_auto_snd_card(struct platform_device *pdev)
{
	struct snd_soc_card *card = NULL;
	struct msm8996_asoc_mach_data *pdata = NULL;
	int ret = 0;

	pdata = devm_kzalloc(&pdev->dev,
			sizeof(struct msm8996_asoc_mach_data), GFP_KERNEL);
	if (!pdata) {
		ret = -ENOMEM;
		dev_err(&pdev->dev, "Can't allocate msm8996_asoc_mach_data\n");
		return ret;
	}

	card = populate_snd_card_dailinks(&pdev->dev);
	if (!card) {
		dev_err(&pdev->dev, "%s: Card uninitialized\n", __func__);
		ret = -EINVAL;
		goto err;
	}
	card->dev = &pdev->dev;
	platform_set_drvdata(pdev, card);
	snd_soc_card_set_drvdata(card, pdata);

	ret = snd_soc_of_parse_card_name(card, "qcom,model");
	if (ret) {
		dev_err(&pdev->dev, "parse card name failed, err:%d\n",
			ret);
		goto err;
	}

	spdev = pdev;

	/* populate controls of snd card */
	card->controls = msm_snd_controls;
	card->num_controls = ARRAY_SIZE(msm_snd_controls);

	ret = msm8996_populate_dai_link_component_of_node(card);
	if (ret) {
		ret = -EPROBE_DEFER;
		goto err;
	}

	ret = snd_soc_register_card(card);
	if (ret == -EPROBE_DEFER) {
		goto err;
	} else if (ret) {
		dev_err(&pdev->dev, "snd_soc_register_card failed, err:%d\n",
			ret);
		goto err;
	}
	dev_info(&pdev->dev, "Sound card %s registered\n", card->name);

	return 0;
err:
	devm_kfree(&pdev->dev, pdata);
	return ret;
}

static int msm8996_asoc_machine_probe(struct platform_device *pdev)
{
	struct snd_soc_card *card;
@@ -3506,6 +3762,9 @@ static int msm8996_asoc_machine_probe(struct platform_device *pdev)
		return -EINVAL;
	}

	if (msm8996_check_auto_snd_card(pdev))
		return msm8996_init_auto_snd_card(pdev);

	pdata = devm_kzalloc(&pdev->dev,
			sizeof(struct msm8996_asoc_mach_data), GFP_KERNEL);
	if (!pdata) {