1 // SPDX-License-Identifier: GPL-2.0 2 // Copyright (c) 2020, Linaro Limited 3 4 #include <linux/module.h> 5 #include <linux/platform_device.h> 6 #include <linux/of_device.h> 7 #include <sound/soc.h> 8 #include <sound/soc-dapm.h> 9 #include <sound/pcm.h> 10 #include <linux/soundwire/sdw.h> 11 #include "qdsp6/q6afe.h" 12 #include "common.h" 13 14 #define DRIVER_NAME "sm8250" 15 #define MI2S_BCLK_RATE 1536000 16 17 struct sm8250_snd_data { 18 bool stream_prepared[AFE_PORT_MAX]; 19 struct snd_soc_card *card; 20 struct sdw_stream_runtime *sruntime[AFE_PORT_MAX]; 21 }; 22 23 static int sm8250_be_hw_params_fixup(struct snd_soc_pcm_runtime *rtd, 24 struct snd_pcm_hw_params *params) 25 { 26 struct snd_interval *rate = hw_param_interval(params, 27 SNDRV_PCM_HW_PARAM_RATE); 28 struct snd_interval *channels = hw_param_interval(params, 29 SNDRV_PCM_HW_PARAM_CHANNELS); 30 31 rate->min = rate->max = 48000; 32 channels->min = channels->max = 2; 33 34 return 0; 35 } 36 37 static int sm8250_snd_startup(struct snd_pcm_substream *substream) 38 { 39 unsigned int fmt = SND_SOC_DAIFMT_CBS_CFS; 40 unsigned int codec_dai_fmt = SND_SOC_DAIFMT_CBS_CFS; 41 struct snd_soc_pcm_runtime *rtd = substream->private_data; 42 struct snd_soc_dai *cpu_dai = asoc_rtd_to_cpu(rtd, 0); 43 struct snd_soc_dai *codec_dai = asoc_rtd_to_codec(rtd, 0); 44 45 switch (cpu_dai->id) { 46 case TERTIARY_MI2S_RX: 47 codec_dai_fmt |= SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_I2S; 48 snd_soc_dai_set_sysclk(cpu_dai, 49 Q6AFE_LPASS_CLK_ID_TER_MI2S_IBIT, 50 MI2S_BCLK_RATE, SNDRV_PCM_STREAM_PLAYBACK); 51 snd_soc_dai_set_fmt(cpu_dai, fmt); 52 snd_soc_dai_set_fmt(codec_dai, codec_dai_fmt); 53 break; 54 default: 55 break; 56 } 57 return 0; 58 } 59 60 static int sm8250_snd_hw_params(struct snd_pcm_substream *substream, 61 struct snd_pcm_hw_params *params) 62 { 63 struct snd_soc_pcm_runtime *rtd = substream->private_data; 64 struct snd_soc_dai *codec_dai; 65 struct snd_soc_dai *cpu_dai = asoc_rtd_to_cpu(rtd, 0); 66 struct sm8250_snd_data *pdata = snd_soc_card_get_drvdata(rtd->card); 67 struct sdw_stream_runtime *sruntime; 68 int i; 69 70 switch (cpu_dai->id) { 71 case WSA_CODEC_DMA_RX_0: 72 for_each_rtd_codec_dais(rtd, i, codec_dai) { 73 sruntime = snd_soc_dai_get_sdw_stream(codec_dai, 74 substream->stream); 75 if (sruntime != ERR_PTR(-ENOTSUPP)) 76 pdata->sruntime[cpu_dai->id] = sruntime; 77 } 78 break; 79 } 80 81 return 0; 82 83 } 84 85 static int sm8250_snd_wsa_dma_prepare(struct snd_pcm_substream *substream) 86 { 87 struct snd_soc_pcm_runtime *rtd = substream->private_data; 88 struct snd_soc_dai *cpu_dai = asoc_rtd_to_cpu(rtd, 0); 89 struct sm8250_snd_data *data = snd_soc_card_get_drvdata(rtd->card); 90 struct sdw_stream_runtime *sruntime = data->sruntime[cpu_dai->id]; 91 int ret; 92 93 if (!sruntime) 94 return 0; 95 96 if (data->stream_prepared[cpu_dai->id]) { 97 sdw_disable_stream(sruntime); 98 sdw_deprepare_stream(sruntime); 99 data->stream_prepared[cpu_dai->id] = false; 100 } 101 102 ret = sdw_prepare_stream(sruntime); 103 if (ret) 104 return ret; 105 106 /** 107 * NOTE: there is a strict hw requirement about the ordering of port 108 * enables and actual WSA881x PA enable. PA enable should only happen 109 * after soundwire ports are enabled if not DC on the line is 110 * accumulated resulting in Click/Pop Noise 111 * PA enable/mute are handled as part of codec DAPM and digital mute. 112 */ 113 114 ret = sdw_enable_stream(sruntime); 115 if (ret) { 116 sdw_deprepare_stream(sruntime); 117 return ret; 118 } 119 data->stream_prepared[cpu_dai->id] = true; 120 121 return ret; 122 } 123 124 static int sm8250_snd_prepare(struct snd_pcm_substream *substream) 125 { 126 struct snd_soc_pcm_runtime *rtd = substream->private_data; 127 struct snd_soc_dai *cpu_dai = asoc_rtd_to_cpu(rtd, 0); 128 129 switch (cpu_dai->id) { 130 case WSA_CODEC_DMA_RX_0: 131 case WSA_CODEC_DMA_RX_1: 132 return sm8250_snd_wsa_dma_prepare(substream); 133 default: 134 break; 135 } 136 137 return 0; 138 } 139 140 static int sm8250_snd_hw_free(struct snd_pcm_substream *substream) 141 { 142 struct snd_soc_pcm_runtime *rtd = substream->private_data; 143 struct sm8250_snd_data *data = snd_soc_card_get_drvdata(rtd->card); 144 struct snd_soc_dai *cpu_dai = asoc_rtd_to_cpu(rtd, 0); 145 struct sdw_stream_runtime *sruntime = data->sruntime[cpu_dai->id]; 146 147 switch (cpu_dai->id) { 148 case WSA_CODEC_DMA_RX_0: 149 case WSA_CODEC_DMA_RX_1: 150 if (sruntime && data->stream_prepared[cpu_dai->id]) { 151 sdw_disable_stream(sruntime); 152 sdw_deprepare_stream(sruntime); 153 data->stream_prepared[cpu_dai->id] = false; 154 } 155 break; 156 default: 157 break; 158 } 159 160 return 0; 161 } 162 163 static const struct snd_soc_ops sm8250_be_ops = { 164 .startup = sm8250_snd_startup, 165 .hw_params = sm8250_snd_hw_params, 166 .hw_free = sm8250_snd_hw_free, 167 .prepare = sm8250_snd_prepare, 168 }; 169 170 static void sm8250_add_be_ops(struct snd_soc_card *card) 171 { 172 struct snd_soc_dai_link *link; 173 int i; 174 175 for_each_card_prelinks(card, i, link) { 176 if (link->no_pcm == 1) { 177 link->be_hw_params_fixup = sm8250_be_hw_params_fixup; 178 link->ops = &sm8250_be_ops; 179 } 180 } 181 } 182 183 static int sm8250_platform_probe(struct platform_device *pdev) 184 { 185 struct snd_soc_card *card; 186 struct sm8250_snd_data *data; 187 struct device *dev = &pdev->dev; 188 int ret; 189 190 card = devm_kzalloc(dev, sizeof(*card), GFP_KERNEL); 191 if (!card) 192 return -ENOMEM; 193 194 /* Allocate the private data */ 195 data = devm_kzalloc(dev, sizeof(*data), GFP_KERNEL); 196 if (!data) 197 return -ENOMEM; 198 199 card->dev = dev; 200 dev_set_drvdata(dev, card); 201 snd_soc_card_set_drvdata(card, data); 202 ret = qcom_snd_parse_of(card); 203 if (ret) 204 return ret; 205 206 card->driver_name = DRIVER_NAME; 207 sm8250_add_be_ops(card); 208 return devm_snd_soc_register_card(dev, card); 209 } 210 211 static const struct of_device_id snd_sm8250_dt_match[] = { 212 {.compatible = "qcom,sm8250-sndcard"}, 213 {.compatible = "qcom,qrb5165-rb5-sndcard"}, 214 {} 215 }; 216 217 MODULE_DEVICE_TABLE(of, snd_sm8250_dt_match); 218 219 static struct platform_driver snd_sm8250_driver = { 220 .probe = sm8250_platform_probe, 221 .driver = { 222 .name = "snd-sm8250", 223 .of_match_table = snd_sm8250_dt_match, 224 }, 225 }; 226 module_platform_driver(snd_sm8250_driver); 227 MODULE_AUTHOR("Srinivas Kandagatla <srinivas.kandagatla@linaro.org"); 228 MODULE_DESCRIPTION("SM8250 ASoC Machine Driver"); 229 MODULE_LICENSE("GPL v2"); 230