sm8250.c (8005B)
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 <sound/jack.h> 12#include <linux/input-event-codes.h> 13#include "qdsp6/q6afe.h" 14#include "common.h" 15 16#define DRIVER_NAME "sm8250" 17#define MI2S_BCLK_RATE 1536000 18 19struct sm8250_snd_data { 20 bool stream_prepared[AFE_PORT_MAX]; 21 struct snd_soc_card *card; 22 struct sdw_stream_runtime *sruntime[AFE_PORT_MAX]; 23 struct snd_soc_jack jack; 24 bool jack_setup; 25}; 26 27static int sm8250_snd_init(struct snd_soc_pcm_runtime *rtd) 28{ 29 struct sm8250_snd_data *data = snd_soc_card_get_drvdata(rtd->card); 30 struct snd_soc_dai *cpu_dai = asoc_rtd_to_cpu(rtd, 0); 31 struct snd_soc_dai *codec_dai = asoc_rtd_to_codec(rtd, 0); 32 struct snd_soc_card *card = rtd->card; 33 int rval, i; 34 35 if (!data->jack_setup) { 36 struct snd_jack *jack; 37 38 rval = snd_soc_card_jack_new(card, "Headset Jack", 39 SND_JACK_HEADSET | SND_JACK_LINEOUT | 40 SND_JACK_MECHANICAL | 41 SND_JACK_BTN_0 | SND_JACK_BTN_1 | 42 SND_JACK_BTN_2 | SND_JACK_BTN_3 | 43 SND_JACK_BTN_4 | SND_JACK_BTN_5, 44 &data->jack); 45 46 if (rval < 0) { 47 dev_err(card->dev, "Unable to add Headphone Jack\n"); 48 return rval; 49 } 50 51 jack = data->jack.jack; 52 53 snd_jack_set_key(jack, SND_JACK_BTN_0, KEY_MEDIA); 54 snd_jack_set_key(jack, SND_JACK_BTN_1, KEY_VOICECOMMAND); 55 snd_jack_set_key(jack, SND_JACK_BTN_2, KEY_VOLUMEUP); 56 snd_jack_set_key(jack, SND_JACK_BTN_3, KEY_VOLUMEDOWN); 57 data->jack_setup = true; 58 } 59 60 switch (cpu_dai->id) { 61 case TX_CODEC_DMA_TX_0: 62 case TX_CODEC_DMA_TX_1: 63 case TX_CODEC_DMA_TX_2: 64 case TX_CODEC_DMA_TX_3: 65 for_each_rtd_codec_dais(rtd, i, codec_dai) { 66 rval = snd_soc_component_set_jack(codec_dai->component, 67 &data->jack, NULL); 68 if (rval != 0 && rval != -ENOTSUPP) { 69 dev_warn(card->dev, "Failed to set jack: %d\n", rval); 70 return rval; 71 } 72 } 73 74 break; 75 default: 76 break; 77 } 78 79 80 return 0; 81} 82 83static int sm8250_be_hw_params_fixup(struct snd_soc_pcm_runtime *rtd, 84 struct snd_pcm_hw_params *params) 85{ 86 struct snd_interval *rate = hw_param_interval(params, 87 SNDRV_PCM_HW_PARAM_RATE); 88 struct snd_interval *channels = hw_param_interval(params, 89 SNDRV_PCM_HW_PARAM_CHANNELS); 90 91 rate->min = rate->max = 48000; 92 channels->min = channels->max = 2; 93 94 return 0; 95} 96 97static int sm8250_snd_startup(struct snd_pcm_substream *substream) 98{ 99 unsigned int fmt = SND_SOC_DAIFMT_CBS_CFS; 100 unsigned int codec_dai_fmt = SND_SOC_DAIFMT_CBS_CFS; 101 struct snd_soc_pcm_runtime *rtd = substream->private_data; 102 struct snd_soc_dai *cpu_dai = asoc_rtd_to_cpu(rtd, 0); 103 struct snd_soc_dai *codec_dai = asoc_rtd_to_codec(rtd, 0); 104 105 switch (cpu_dai->id) { 106 case TERTIARY_MI2S_RX: 107 codec_dai_fmt |= SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_I2S; 108 snd_soc_dai_set_sysclk(cpu_dai, 109 Q6AFE_LPASS_CLK_ID_TER_MI2S_IBIT, 110 MI2S_BCLK_RATE, SNDRV_PCM_STREAM_PLAYBACK); 111 snd_soc_dai_set_fmt(cpu_dai, fmt); 112 snd_soc_dai_set_fmt(codec_dai, codec_dai_fmt); 113 break; 114 default: 115 break; 116 } 117 return 0; 118} 119 120static int sm8250_snd_hw_params(struct snd_pcm_substream *substream, 121 struct snd_pcm_hw_params *params) 122{ 123 struct snd_soc_pcm_runtime *rtd = substream->private_data; 124 struct snd_soc_dai *codec_dai; 125 struct snd_soc_dai *cpu_dai = asoc_rtd_to_cpu(rtd, 0); 126 struct sm8250_snd_data *pdata = snd_soc_card_get_drvdata(rtd->card); 127 struct sdw_stream_runtime *sruntime; 128 int i; 129 130 switch (cpu_dai->id) { 131 case WSA_CODEC_DMA_RX_0: 132 case RX_CODEC_DMA_RX_0: 133 case RX_CODEC_DMA_RX_1: 134 case TX_CODEC_DMA_TX_0: 135 case TX_CODEC_DMA_TX_1: 136 case TX_CODEC_DMA_TX_2: 137 case TX_CODEC_DMA_TX_3: 138 for_each_rtd_codec_dais(rtd, i, codec_dai) { 139 sruntime = snd_soc_dai_get_stream(codec_dai, 140 substream->stream); 141 if (sruntime != ERR_PTR(-ENOTSUPP)) 142 pdata->sruntime[cpu_dai->id] = sruntime; 143 } 144 break; 145 } 146 147 return 0; 148 149} 150 151static int sm8250_snd_wsa_dma_prepare(struct snd_pcm_substream *substream) 152{ 153 struct snd_soc_pcm_runtime *rtd = substream->private_data; 154 struct snd_soc_dai *cpu_dai = asoc_rtd_to_cpu(rtd, 0); 155 struct sm8250_snd_data *data = snd_soc_card_get_drvdata(rtd->card); 156 struct sdw_stream_runtime *sruntime = data->sruntime[cpu_dai->id]; 157 int ret; 158 159 if (!sruntime) 160 return 0; 161 162 if (data->stream_prepared[cpu_dai->id]) { 163 sdw_disable_stream(sruntime); 164 sdw_deprepare_stream(sruntime); 165 data->stream_prepared[cpu_dai->id] = false; 166 } 167 168 ret = sdw_prepare_stream(sruntime); 169 if (ret) 170 return ret; 171 172 /** 173 * NOTE: there is a strict hw requirement about the ordering of port 174 * enables and actual WSA881x PA enable. PA enable should only happen 175 * after soundwire ports are enabled if not DC on the line is 176 * accumulated resulting in Click/Pop Noise 177 * PA enable/mute are handled as part of codec DAPM and digital mute. 178 */ 179 180 ret = sdw_enable_stream(sruntime); 181 if (ret) { 182 sdw_deprepare_stream(sruntime); 183 return ret; 184 } 185 data->stream_prepared[cpu_dai->id] = true; 186 187 return ret; 188} 189 190static int sm8250_snd_prepare(struct snd_pcm_substream *substream) 191{ 192 struct snd_soc_pcm_runtime *rtd = substream->private_data; 193 struct snd_soc_dai *cpu_dai = asoc_rtd_to_cpu(rtd, 0); 194 195 switch (cpu_dai->id) { 196 case WSA_CODEC_DMA_RX_0: 197 case WSA_CODEC_DMA_RX_1: 198 case RX_CODEC_DMA_RX_0: 199 case RX_CODEC_DMA_RX_1: 200 case TX_CODEC_DMA_TX_0: 201 case TX_CODEC_DMA_TX_1: 202 case TX_CODEC_DMA_TX_2: 203 case TX_CODEC_DMA_TX_3: 204 return sm8250_snd_wsa_dma_prepare(substream); 205 default: 206 break; 207 } 208 209 return 0; 210} 211 212static int sm8250_snd_hw_free(struct snd_pcm_substream *substream) 213{ 214 struct snd_soc_pcm_runtime *rtd = substream->private_data; 215 struct sm8250_snd_data *data = snd_soc_card_get_drvdata(rtd->card); 216 struct snd_soc_dai *cpu_dai = asoc_rtd_to_cpu(rtd, 0); 217 struct sdw_stream_runtime *sruntime = data->sruntime[cpu_dai->id]; 218 219 switch (cpu_dai->id) { 220 case WSA_CODEC_DMA_RX_0: 221 case WSA_CODEC_DMA_RX_1: 222 case RX_CODEC_DMA_RX_0: 223 case RX_CODEC_DMA_RX_1: 224 case TX_CODEC_DMA_TX_0: 225 case TX_CODEC_DMA_TX_1: 226 case TX_CODEC_DMA_TX_2: 227 case TX_CODEC_DMA_TX_3: 228 if (sruntime && data->stream_prepared[cpu_dai->id]) { 229 sdw_disable_stream(sruntime); 230 sdw_deprepare_stream(sruntime); 231 data->stream_prepared[cpu_dai->id] = false; 232 } 233 break; 234 default: 235 break; 236 } 237 238 return 0; 239} 240 241static const struct snd_soc_ops sm8250_be_ops = { 242 .startup = sm8250_snd_startup, 243 .hw_params = sm8250_snd_hw_params, 244 .hw_free = sm8250_snd_hw_free, 245 .prepare = sm8250_snd_prepare, 246}; 247 248static void sm8250_add_be_ops(struct snd_soc_card *card) 249{ 250 struct snd_soc_dai_link *link; 251 int i; 252 253 for_each_card_prelinks(card, i, link) { 254 if (link->no_pcm == 1) { 255 link->init = sm8250_snd_init; 256 link->be_hw_params_fixup = sm8250_be_hw_params_fixup; 257 link->ops = &sm8250_be_ops; 258 } 259 } 260} 261 262static int sm8250_platform_probe(struct platform_device *pdev) 263{ 264 struct snd_soc_card *card; 265 struct sm8250_snd_data *data; 266 struct device *dev = &pdev->dev; 267 int ret; 268 269 card = devm_kzalloc(dev, sizeof(*card), GFP_KERNEL); 270 if (!card) 271 return -ENOMEM; 272 273 /* Allocate the private data */ 274 data = devm_kzalloc(dev, sizeof(*data), GFP_KERNEL); 275 if (!data) 276 return -ENOMEM; 277 278 card->dev = dev; 279 dev_set_drvdata(dev, card); 280 snd_soc_card_set_drvdata(card, data); 281 ret = qcom_snd_parse_of(card); 282 if (ret) 283 return ret; 284 285 card->driver_name = DRIVER_NAME; 286 sm8250_add_be_ops(card); 287 return devm_snd_soc_register_card(dev, card); 288} 289 290static const struct of_device_id snd_sm8250_dt_match[] = { 291 {.compatible = "qcom,sm8250-sndcard"}, 292 {.compatible = "qcom,qrb5165-rb5-sndcard"}, 293 {} 294}; 295 296MODULE_DEVICE_TABLE(of, snd_sm8250_dt_match); 297 298static struct platform_driver snd_sm8250_driver = { 299 .probe = sm8250_platform_probe, 300 .driver = { 301 .name = "snd-sm8250", 302 .of_match_table = snd_sm8250_dt_match, 303 }, 304}; 305module_platform_driver(snd_sm8250_driver); 306MODULE_AUTHOR("Srinivas Kandagatla <srinivas.kandagatla@linaro.org"); 307MODULE_DESCRIPTION("SM8250 ASoC Machine Driver"); 308MODULE_LICENSE("GPL v2");