Unverified Commit d3cfe45f authored by Mark Brown's avatar Mark Brown
Browse files

ASoC: qcom: add support for sc8280xp machine

Merge series from Srinivas Kandagatla <srinivas.kandagatla@linaro.org>:

This patchset adds support for SC8280XP SoC machine driver.

First patch moves some of the commonly used code to common from sm8250 machine driver
and the follow on code adds minimal support for sc8280xp.

Currently this driver is only tested with SmartSpeakers and Headset
on Lenovo Thinkpad X13s.

Support for sm8450 is tested and I will post the patches soon.
parents 9dd28b46 295aeea6
Loading
Loading
Loading
Loading
+3 −1
Original line number Diff line number Diff line
@@ -20,9 +20,11 @@ properties:
      - qcom,apq8016-sbc-sndcard
      - qcom,db845c-sndcard
      - qcom,msm8916-qdsp6-sndcard
      - qcom,qrb5165-rb5-sndcard
      - qcom,sc8280xp-sndcard
      - qcom,sdm845-sndcard
      - qcom,sm8250-sndcard
      - qcom,qrb5165-rb5-sndcard
      - qcom,sm8450-sndcard

  audio-routing:
    $ref: /schemas/types.yaml#/definitions/non-unique-string-array
+12 −0
Original line number Diff line number Diff line
@@ -173,6 +173,18 @@ config SND_SOC_SM8250
	  SM8250 SoC-based systems.
	  Say Y if you want to use audio device on this SoCs.

config SND_SOC_SC8280XP
	tristate "SoC Machine driver for SC8280XP boards"
	depends on QCOM_APR || COMPILE_TEST
	depends on SOUNDWIRE
	depends on COMMON_CLK
	select SND_SOC_QDSP6
	select SND_SOC_QCOM_COMMON
	help
	  To add support for audio on Qualcomm Technologies Inc.
	  SC8280XP SoC-based systems.
	  Say Y if you want to use audio device on this SoCs.

config SND_SOC_SC7180
	tristate "SoC Machine driver for SC7180 boards"
	depends on I2C && GPIOLIB
+2 −0
Original line number Diff line number Diff line
@@ -26,6 +26,7 @@ snd-soc-sc7180-objs := sc7180.o
snd-soc-sc7280-objs := sc7280.o
snd-soc-sdm845-objs := sdm845.o
snd-soc-sm8250-objs := sm8250.o
snd-soc-sc8280xp-objs := sc8280xp.o
snd-soc-qcom-common-objs := common.o

obj-$(CONFIG_SND_SOC_STORM) += snd-soc-storm.o
@@ -33,6 +34,7 @@ obj-$(CONFIG_SND_SOC_APQ8016_SBC) += snd-soc-apq8016-sbc.o
obj-$(CONFIG_SND_SOC_MSM8996) += snd-soc-apq8096.o
obj-$(CONFIG_SND_SOC_SC7180) += snd-soc-sc7180.o
obj-$(CONFIG_SND_SOC_SC7280) += snd-soc-sc7280.o
obj-$(CONFIG_SND_SOC_SC8280XP) += snd-soc-sc8280xp.o
obj-$(CONFIG_SND_SOC_SDM845) += snd-soc-sdm845.o
obj-$(CONFIG_SND_SOC_SM8250) += snd-soc-sm8250.o
obj-$(CONFIG_SND_SOC_QCOM_COMMON) += snd-soc-qcom-common.o
+172 −1
Original line number Diff line number Diff line
@@ -3,6 +3,9 @@
// Copyright (c) 2018, The Linux Foundation. All rights reserved.

#include <linux/module.h>
#include <sound/jack.h>
#include <linux/input-event-codes.h>
#include "qdsp6/q6afe.h"
#include "common.h"

int qcom_snd_parse_of(struct snd_soc_card *card)
@@ -175,6 +178,174 @@ int qcom_snd_parse_of(struct snd_soc_card *card)
	of_node_put(np);
	return ret;
}
EXPORT_SYMBOL(qcom_snd_parse_of);
EXPORT_SYMBOL_GPL(qcom_snd_parse_of);

#if IS_ENABLED(CONFIG_SOUNDWIRE)
int qcom_snd_sdw_prepare(struct snd_pcm_substream *substream,
			 struct sdw_stream_runtime *sruntime,
			 bool *stream_prepared)
{
	struct snd_soc_pcm_runtime *rtd = substream->private_data;
	struct snd_soc_dai *cpu_dai = asoc_rtd_to_cpu(rtd, 0);
	int ret;

	if (!sruntime)
		return 0;

	switch (cpu_dai->id) {
	case WSA_CODEC_DMA_RX_0:
	case WSA_CODEC_DMA_RX_1:
	case RX_CODEC_DMA_RX_0:
	case RX_CODEC_DMA_RX_1:
	case TX_CODEC_DMA_TX_0:
	case TX_CODEC_DMA_TX_1:
	case TX_CODEC_DMA_TX_2:
	case TX_CODEC_DMA_TX_3:
		break;
	default:
		return 0;
	}

	if (*stream_prepared) {
		sdw_disable_stream(sruntime);
		sdw_deprepare_stream(sruntime);
		*stream_prepared = false;
	}

	ret = sdw_prepare_stream(sruntime);
	if (ret)
		return ret;

	/**
	 * NOTE: there is a strict hw requirement about the ordering of port
	 * enables and actual WSA881x PA enable. PA enable should only happen
	 * after soundwire ports are enabled if not DC on the line is
	 * accumulated resulting in Click/Pop Noise
	 * PA enable/mute are handled as part of codec DAPM and digital mute.
	 */

	ret = sdw_enable_stream(sruntime);
	if (ret) {
		sdw_deprepare_stream(sruntime);
		return ret;
	}
	*stream_prepared  = true;

	return ret;
}
EXPORT_SYMBOL_GPL(qcom_snd_sdw_prepare);

int qcom_snd_sdw_hw_params(struct snd_pcm_substream *substream,
			   struct snd_pcm_hw_params *params,
			   struct sdw_stream_runtime **psruntime)
{
	struct snd_soc_pcm_runtime *rtd = substream->private_data;
	struct snd_soc_dai *codec_dai;
	struct snd_soc_dai *cpu_dai = asoc_rtd_to_cpu(rtd, 0);
	struct sdw_stream_runtime *sruntime;
	int i;

	switch (cpu_dai->id) {
	case WSA_CODEC_DMA_RX_0:
	case RX_CODEC_DMA_RX_0:
	case RX_CODEC_DMA_RX_1:
	case TX_CODEC_DMA_TX_0:
	case TX_CODEC_DMA_TX_1:
	case TX_CODEC_DMA_TX_2:
	case TX_CODEC_DMA_TX_3:
		for_each_rtd_codec_dais(rtd, i, codec_dai) {
			sruntime = snd_soc_dai_get_stream(codec_dai, substream->stream);
			if (sruntime != ERR_PTR(-ENOTSUPP))
				*psruntime = sruntime;
		}
		break;
	}

	return 0;

}
EXPORT_SYMBOL_GPL(qcom_snd_sdw_hw_params);

int qcom_snd_sdw_hw_free(struct snd_pcm_substream *substream,
			 struct sdw_stream_runtime *sruntime, bool *stream_prepared)
{
	struct snd_soc_pcm_runtime *rtd = substream->private_data;
	struct snd_soc_dai *cpu_dai = asoc_rtd_to_cpu(rtd, 0);

	switch (cpu_dai->id) {
	case WSA_CODEC_DMA_RX_0:
	case WSA_CODEC_DMA_RX_1:
	case RX_CODEC_DMA_RX_0:
	case RX_CODEC_DMA_RX_1:
	case TX_CODEC_DMA_TX_0:
	case TX_CODEC_DMA_TX_1:
	case TX_CODEC_DMA_TX_2:
	case TX_CODEC_DMA_TX_3:
		if (sruntime && *stream_prepared) {
			sdw_disable_stream(sruntime);
			sdw_deprepare_stream(sruntime);
			*stream_prepared = false;
		}
		break;
	default:
		break;
	}

	return 0;
}
EXPORT_SYMBOL_GPL(qcom_snd_sdw_hw_free);
#endif

int qcom_snd_wcd_jack_setup(struct snd_soc_pcm_runtime *rtd,
			    struct snd_soc_jack *jack, bool *jack_setup)
{
	struct snd_soc_dai *cpu_dai = asoc_rtd_to_cpu(rtd, 0);
	struct snd_soc_dai *codec_dai = asoc_rtd_to_codec(rtd, 0);
	struct snd_soc_card *card = rtd->card;
	int rval, i;

	if (!*jack_setup) {
		rval = snd_soc_card_jack_new(card, "Headset Jack",
					     SND_JACK_HEADSET | SND_JACK_LINEOUT |
					     SND_JACK_MECHANICAL |
					     SND_JACK_BTN_0 | SND_JACK_BTN_1 |
					     SND_JACK_BTN_2 | SND_JACK_BTN_3 |
					     SND_JACK_BTN_4 | SND_JACK_BTN_5,
					     jack);

		if (rval < 0) {
			dev_err(card->dev, "Unable to add Headphone Jack\n");
			return rval;
		}

		snd_jack_set_key(jack->jack, SND_JACK_BTN_0, KEY_MEDIA);
		snd_jack_set_key(jack->jack, SND_JACK_BTN_1, KEY_VOICECOMMAND);
		snd_jack_set_key(jack->jack, SND_JACK_BTN_2, KEY_VOLUMEUP);
		snd_jack_set_key(jack->jack, SND_JACK_BTN_3, KEY_VOLUMEDOWN);
		*jack_setup = true;
	}

	switch (cpu_dai->id) {
	case TX_CODEC_DMA_TX_0:
	case TX_CODEC_DMA_TX_1:
	case TX_CODEC_DMA_TX_2:
	case TX_CODEC_DMA_TX_3:
		for_each_rtd_codec_dais(rtd, i, codec_dai) {
			rval = snd_soc_component_set_jack(codec_dai->component,
							  jack, NULL);
			if (rval != 0 && rval != -ENOTSUPP) {
				dev_warn(card->dev, "Failed to set jack: %d\n", rval);
				return rval;
			}
		}

		break;
	default:
		break;
	}


	return 0;
}
EXPORT_SYMBOL_GPL(qcom_snd_wcd_jack_setup);
MODULE_LICENSE("GPL v2");
+35 −0
Original line number Diff line number Diff line
@@ -5,7 +5,42 @@
#define __QCOM_SND_COMMON_H__

#include <sound/soc.h>
#include <linux/soundwire/sdw.h>

int qcom_snd_parse_of(struct snd_soc_card *card);
int qcom_snd_wcd_jack_setup(struct snd_soc_pcm_runtime *rtd,
			    struct snd_soc_jack *jack, bool *jack_setup);

#if IS_ENABLED(CONFIG_SOUNDWIRE)
int qcom_snd_sdw_prepare(struct snd_pcm_substream *substream,
			 struct sdw_stream_runtime *runtime,
			 bool *stream_prepared);
int qcom_snd_sdw_hw_params(struct snd_pcm_substream *substream,
			   struct snd_pcm_hw_params *params,
			   struct sdw_stream_runtime **psruntime);
int qcom_snd_sdw_hw_free(struct snd_pcm_substream *substream,
			 struct sdw_stream_runtime *sruntime,
			 bool *stream_prepared);
#else
static inline int qcom_snd_sdw_prepare(struct snd_pcm_substream *substream,
				       struct sdw_stream_runtime *runtime,
				       bool *stream_prepared)
{
	return -ENOTSUPP;
}

static inline int qcom_snd_sdw_hw_params(struct snd_pcm_substream *substream,
					 struct snd_pcm_hw_params *params,
					 struct sdw_stream_runtime **psruntime)
{
	return -ENOTSUPP;
}

static inline int qcom_snd_sdw_hw_free(struct snd_pcm_substream *substream,
				       struct sdw_stream_runtime *sruntime,
				       bool *stream_prepared)
{
	return -ENOTSUPP;
}
#endif
#endif
Loading