diff options
Diffstat (limited to 'sound/soc/qcom/sdm845.c')
| -rw-r--r-- | sound/soc/qcom/sdm845.c | 205 |
1 files changed, 90 insertions, 115 deletions
diff --git a/sound/soc/qcom/sdm845.c b/sound/soc/qcom/sdm845.c index 68e9388ff46f..e18a8e44f2db 100644 --- a/sound/soc/qcom/sdm845.c +++ b/sound/soc/qcom/sdm845.c @@ -3,9 +3,9 @@ * Copyright (c) 2018, The Linux Foundation. All rights reserved. */ +#include <dt-bindings/sound/qcom,q6afe.h> #include <linux/module.h> #include <linux/platform_device.h> -#include <linux/of_device.h> #include <sound/core.h> #include <sound/pcm.h> #include <sound/pcm_params.h> @@ -15,8 +15,10 @@ #include <uapi/linux/input-event-codes.h> #include "common.h" #include "qdsp6/q6afe.h" +#include "sdw.h" #include "../codecs/rt5663.h" +#define DRIVER_NAME "sdm845" #define DEFAULT_SAMPLE_RATE_48K 48000 #define DEFAULT_MCLK_RATE 24576000 #define TDM_BCLK_RATE 6144000 @@ -26,18 +28,29 @@ #define SPK_TDM_RX_MASK 0x03 #define NUM_TDM_SLOTS 8 #define SLIM_MAX_TX_PORTS 16 -#define SLIM_MAX_RX_PORTS 16 +#define SLIM_MAX_RX_PORTS 13 #define WCD934X_DEFAULT_MCLK_RATE 9600000 struct sdm845_snd_data { struct snd_soc_jack jack; bool jack_setup; - bool stream_prepared[SLIM_MAX_RX_PORTS]; + bool slim_port_setup; + bool stream_prepared[AFE_PORT_MAX]; struct snd_soc_card *card; uint32_t pri_mi2s_clk_count; uint32_t sec_mi2s_clk_count; uint32_t quat_tdm_clk_count; - struct sdw_stream_runtime *sruntime[SLIM_MAX_RX_PORTS]; +}; + +static struct snd_soc_jack_pin sdm845_jack_pins[] = { + { + .pin = "Headphone Jack", + .mask = SND_JACK_HEADPHONE, + }, + { + .pin = "Headset Mic", + .mask = SND_JACK_MICROPHONE, + }, }; static unsigned int tdm_slot_offset[8] = {0, 4, 8, 12, 16, 20, 24, 28}; @@ -45,21 +58,14 @@ static unsigned int tdm_slot_offset[8] = {0, 4, 8, 12, 16, 20, 24, 28}; static int sdm845_slim_snd_hw_params(struct snd_pcm_substream *substream, struct snd_pcm_hw_params *params) { - struct snd_soc_pcm_runtime *rtd = substream->private_data; - struct snd_soc_dai *cpu_dai = asoc_rtd_to_cpu(rtd, 0); + struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream); + struct snd_soc_dai *cpu_dai = snd_soc_rtd_to_cpu(rtd, 0); struct snd_soc_dai *codec_dai; - struct sdm845_snd_data *pdata = snd_soc_card_get_drvdata(rtd->card); u32 rx_ch[SLIM_MAX_RX_PORTS], tx_ch[SLIM_MAX_TX_PORTS]; - struct sdw_stream_runtime *sruntime; u32 rx_ch_cnt = 0, tx_ch_cnt = 0; int ret = 0, i; for_each_rtd_codec_dais(rtd, i, codec_dai) { - sruntime = snd_soc_dai_get_sdw_stream(codec_dai, - substream->stream); - if (sruntime != ERR_PTR(-ENOTSUPP)) - pdata->sruntime[cpu_dai->id] = sruntime; - ret = snd_soc_dai_get_channel_map(codec_dai, &tx_ch_cnt, tx_ch, &rx_ch_cnt, rx_ch); @@ -77,6 +83,10 @@ static int sdm845_slim_snd_hw_params(struct snd_pcm_substream *substream, else ret = snd_soc_dai_set_channel_map(cpu_dai, tx_ch_cnt, tx_ch, 0, NULL); + if (ret != 0 && ret != -ENOTSUPP) { + dev_err(rtd->dev, "failed to set cpu chan map, err:%d\n", ret); + return ret; + } } return 0; @@ -85,8 +95,8 @@ static int sdm845_slim_snd_hw_params(struct snd_pcm_substream *substream, static int sdm845_tdm_snd_hw_params(struct snd_pcm_substream *substream, struct snd_pcm_hw_params *params) { - struct snd_soc_pcm_runtime *rtd = substream->private_data; - struct snd_soc_dai *cpu_dai = asoc_rtd_to_cpu(rtd, 0); + struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream); + struct snd_soc_dai *cpu_dai = snd_soc_rtd_to_cpu(rtd, 0); struct snd_soc_dai *codec_dai; int ret = 0, j; int channels, slot_width; @@ -170,9 +180,9 @@ end: static int sdm845_snd_hw_params(struct snd_pcm_substream *substream, struct snd_pcm_hw_params *params) { - struct snd_soc_pcm_runtime *rtd = substream->private_data; - 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_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream); + struct snd_soc_dai *cpu_dai = snd_soc_rtd_to_cpu(rtd, 0); + struct snd_soc_dai *codec_dai = snd_soc_rtd_to_codec(rtd, 0); int ret = 0; switch (cpu_dai->id) { @@ -201,6 +211,7 @@ static int sdm845_snd_hw_params(struct snd_pcm_substream *substream, ret = sdm845_slim_snd_hw_params(substream, params); break; case QUATERNARY_MI2S_RX: + case SECONDARY_MI2S_RX: break; default: pr_err("%s: invalid dai id 0x%x\n", __func__, cpu_dai->id); @@ -220,9 +231,10 @@ static int sdm845_dai_init(struct snd_soc_pcm_runtime *rtd) { struct snd_soc_component *component; struct snd_soc_card *card = rtd->card; - struct snd_soc_dai *codec_dai = asoc_rtd_to_codec(rtd, 0); - struct snd_soc_dai *cpu_dai = asoc_rtd_to_cpu(rtd, 0); + struct snd_soc_dai *codec_dai = snd_soc_rtd_to_codec(rtd, 0); + struct snd_soc_dai *cpu_dai = snd_soc_rtd_to_cpu(rtd, 0); struct sdm845_snd_data *pdata = snd_soc_card_get_drvdata(card); + struct snd_soc_dai_link *link = rtd->dai_link; struct snd_jack *jack; /* * Codec SLIMBUS configuration @@ -239,12 +251,14 @@ static int sdm845_dai_init(struct snd_soc_pcm_runtime *rtd) if (!pdata->jack_setup) { - rval = snd_soc_card_jack_new(card, "Headset Jack", - SND_JACK_HEADSET | - SND_JACK_HEADPHONE | - SND_JACK_BTN_0 | SND_JACK_BTN_1 | - SND_JACK_BTN_2 | SND_JACK_BTN_3, - &pdata->jack, NULL, 0); + rval = snd_soc_card_jack_new_pins(card, "Headset Jack", + SND_JACK_HEADSET | + SND_JACK_HEADPHONE | + SND_JACK_BTN_0 | SND_JACK_BTN_1 | + SND_JACK_BTN_2 | SND_JACK_BTN_3, + &pdata->jack, + sdm845_jack_pins, + ARRAY_SIZE(sdm845_jack_pins)); if (rval < 0) { dev_err(card->dev, "Unable to add Headphone Jack\n"); @@ -275,6 +289,10 @@ static int sdm845_dai_init(struct snd_soc_pcm_runtime *rtd) } break; case SLIMBUS_0_RX...SLIMBUS_6_TX: + /* setting up wcd multiple times for slim port is redundant */ + if (pdata->slim_port_setup || !link->no_pcm) + return 0; + for_each_rtd_codec_dais(rtd, i, codec_dai) { rval = snd_soc_dai_set_channel_map(codec_dai, ARRAY_SIZE(tx_ch), @@ -287,7 +305,17 @@ static int sdm845_dai_init(struct snd_soc_pcm_runtime *rtd) snd_soc_dai_set_sysclk(codec_dai, 0, WCD934X_DEFAULT_MCLK_RATE, SNDRV_PCM_STREAM_PLAYBACK); + + rval = snd_soc_component_set_jack(codec_dai->component, + &pdata->jack, NULL); + if (rval != 0 && rval != -ENOTSUPP) { + dev_warn(card->dev, "Failed to set jack: %d\n", rval); + return rval; + } } + + pdata->slim_port_setup = true; + break; default: break; @@ -299,13 +327,13 @@ static int sdm845_dai_init(struct snd_soc_pcm_runtime *rtd) static int sdm845_snd_startup(struct snd_pcm_substream *substream) { - unsigned int fmt = SND_SOC_DAIFMT_CBS_CFS; - unsigned int codec_dai_fmt = SND_SOC_DAIFMT_CBS_CFS; - struct snd_soc_pcm_runtime *rtd = substream->private_data; + unsigned int fmt = SND_SOC_DAIFMT_BP_FP; + unsigned int codec_dai_fmt = SND_SOC_DAIFMT_BC_FC; + struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream); struct snd_soc_card *card = rtd->card; struct sdm845_snd_data *data = snd_soc_card_get_drvdata(card); - 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_dai *cpu_dai = snd_soc_rtd_to_cpu(rtd, 0); + struct snd_soc_dai *codec_dai = snd_soc_rtd_to_codec(rtd, 0); int j; int ret; @@ -325,6 +353,7 @@ static int sdm845_snd_startup(struct snd_pcm_substream *substream) snd_soc_dai_set_fmt(codec_dai, codec_dai_fmt); break; + case SECONDARY_MI2S_RX: case SECONDARY_MI2S_TX: codec_dai_fmt |= SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_I2S; if (++(data->sec_mi2s_clk_count) == 1) { @@ -339,9 +368,7 @@ static int sdm845_snd_startup(struct snd_pcm_substream *substream) snd_soc_dai_set_sysclk(cpu_dai, Q6AFE_LPASS_CLK_ID_QUAD_MI2S_IBIT, MI2S_BCLK_RATE, SNDRV_PCM_STREAM_PLAYBACK); - snd_soc_dai_set_fmt(cpu_dai, SND_SOC_DAIFMT_CBS_CFS); - - + snd_soc_dai_set_fmt(cpu_dai, fmt); break; case QUATERNARY_TDM_RX_0: @@ -386,15 +413,15 @@ static int sdm845_snd_startup(struct snd_pcm_substream *substream) pr_err("%s: invalid dai id 0x%x\n", __func__, cpu_dai->id); break; } - return 0; + return qcom_snd_sdw_startup(substream); } static void sdm845_snd_shutdown(struct snd_pcm_substream *substream) { - struct snd_soc_pcm_runtime *rtd = substream->private_data; + struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream); struct snd_soc_card *card = rtd->card; struct sdm845_snd_data *data = snd_soc_card_get_drvdata(card); - struct snd_soc_dai *cpu_dai = asoc_rtd_to_cpu(rtd, 0); + struct snd_soc_dai *cpu_dai = snd_soc_rtd_to_cpu(rtd, 0); switch (cpu_dai->id) { case PRIMARY_MI2S_RX: @@ -409,6 +436,7 @@ static void sdm845_snd_shutdown(struct snd_pcm_substream *substream) } break; + case SECONDARY_MI2S_RX: case SECONDARY_MI2S_TX: if (--(data->sec_mi2s_clk_count) == 0) { snd_soc_dai_set_sysclk(cpu_dai, @@ -433,61 +461,26 @@ static void sdm845_snd_shutdown(struct snd_pcm_substream *substream) pr_err("%s: invalid dai id 0x%x\n", __func__, cpu_dai->id); break; } + + qcom_snd_sdw_shutdown(substream); } static int sdm845_snd_prepare(struct snd_pcm_substream *substream) { - struct snd_soc_pcm_runtime *rtd = substream->private_data; + struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream); struct sdm845_snd_data *data = snd_soc_card_get_drvdata(rtd->card); - struct snd_soc_dai *cpu_dai = asoc_rtd_to_cpu(rtd, 0); - struct sdw_stream_runtime *sruntime = data->sruntime[cpu_dai->id]; - int ret; - - if (!sruntime) - return 0; - - if (data->stream_prepared[cpu_dai->id]) { - sdw_disable_stream(sruntime); - sdw_deprepare_stream(sruntime); - data->stream_prepared[cpu_dai->id] = 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. - */ + struct snd_soc_dai *cpu_dai = snd_soc_rtd_to_cpu(rtd, 0); - ret = sdw_enable_stream(sruntime); - if (ret) { - sdw_deprepare_stream(sruntime); - return ret; - } - data->stream_prepared[cpu_dai->id] = true; - - return ret; + return qcom_snd_sdw_prepare(substream, &data->stream_prepared[cpu_dai->id]); } static int sdm845_snd_hw_free(struct snd_pcm_substream *substream) { - struct snd_soc_pcm_runtime *rtd = substream->private_data; + struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream); struct sdm845_snd_data *data = snd_soc_card_get_drvdata(rtd->card); - struct snd_soc_dai *cpu_dai = asoc_rtd_to_cpu(rtd, 0); - struct sdw_stream_runtime *sruntime = data->sruntime[cpu_dai->id]; + struct snd_soc_dai *cpu_dai = snd_soc_rtd_to_cpu(rtd, 0); - if (sruntime && data->stream_prepared[cpu_dai->id]) { - sdw_disable_stream(sruntime); - sdw_deprepare_stream(sruntime); - data->stream_prepared[cpu_dai->id] = false; - } - - return 0; + return qcom_snd_sdw_hw_free(substream, &data->stream_prepared[cpu_dai->id]); } static const struct snd_soc_ops sdm845_be_ops = { @@ -522,6 +515,11 @@ static const struct snd_soc_dapm_widget sdm845_snd_widgets[] = { SND_SOC_DAPM_MIC("Int Mic", NULL), }; +static const struct snd_kcontrol_new sdm845_snd_controls[] = { + SOC_DAPM_PIN_SWITCH("Headphone Jack"), + SOC_DAPM_PIN_SWITCH("Headset Mic"), +}; + static void sdm845_add_ops(struct snd_soc_card *card) { struct snd_soc_dai_link *link; @@ -543,59 +541,37 @@ static int sdm845_snd_platform_probe(struct platform_device *pdev) struct device *dev = &pdev->dev; int ret; - card = kzalloc(sizeof(*card), GFP_KERNEL); + card = devm_kzalloc(dev, sizeof(*card), GFP_KERNEL); if (!card) return -ENOMEM; /* Allocate the private data */ - data = kzalloc(sizeof(*data), GFP_KERNEL); - if (!data) { - ret = -ENOMEM; - goto data_alloc_fail; - } + data = devm_kzalloc(dev, sizeof(*data), GFP_KERNEL); + if (!data) + return -ENOMEM; + card->driver_name = DRIVER_NAME; card->dapm_widgets = sdm845_snd_widgets; card->num_dapm_widgets = ARRAY_SIZE(sdm845_snd_widgets); + card->controls = sdm845_snd_controls; + card->num_controls = ARRAY_SIZE(sdm845_snd_controls); card->dev = dev; + card->owner = THIS_MODULE; dev_set_drvdata(dev, card); ret = qcom_snd_parse_of(card); if (ret) - goto parse_dt_fail; + return ret; data->card = card; snd_soc_card_set_drvdata(card, data); sdm845_add_ops(card); - ret = snd_soc_register_card(card); - if (ret) { - dev_err(dev, "Sound card registration failed\n"); - goto register_card_fail; - } - return ret; - -register_card_fail: - kfree(card->dai_link); -parse_dt_fail: - kfree(data); -data_alloc_fail: - kfree(card); - return ret; -} - -static int sdm845_snd_platform_remove(struct platform_device *pdev) -{ - struct snd_soc_card *card = dev_get_drvdata(&pdev->dev); - struct sdm845_snd_data *data = snd_soc_card_get_drvdata(card); - - snd_soc_unregister_card(card); - kfree(card->dai_link); - kfree(data); - kfree(card); - return 0; + return devm_snd_soc_register_card(dev, card); } static const struct of_device_id sdm845_snd_device_id[] = { { .compatible = "qcom,sdm845-sndcard" }, + /* Do not grow the list for compatible devices */ { .compatible = "qcom,db845c-sndcard" }, { .compatible = "lenovo,yoga-c630-sndcard" }, {}, @@ -604,7 +580,6 @@ MODULE_DEVICE_TABLE(of, sdm845_snd_device_id); static struct platform_driver sdm845_snd_driver = { .probe = sdm845_snd_platform_probe, - .remove = sdm845_snd_platform_remove, .driver = { .name = "msm-snd-sdm845", .of_match_table = sdm845_snd_device_id, @@ -613,4 +588,4 @@ static struct platform_driver sdm845_snd_driver = { module_platform_driver(sdm845_snd_driver); MODULE_DESCRIPTION("sdm845 ASoC Machine Driver"); -MODULE_LICENSE("GPL v2"); +MODULE_LICENSE("GPL"); |
