1 // SPDX-License-Identifier: GPL-2.0-only 2 // 3 // Copyright (c) 2020, The Linux Foundation. All rights reserved. 4 // 5 // sc7180.c -- ALSA SoC Machine driver for SC7180 6 7 #include <dt-bindings/sound/sc7180-lpass.h> 8 #include <linux/gpio.h> 9 #include <linux/gpio/consumer.h> 10 #include <linux/module.h> 11 #include <linux/of_device.h> 12 #include <linux/platform_device.h> 13 #include <sound/core.h> 14 #include <sound/jack.h> 15 #include <sound/pcm.h> 16 #include <sound/soc.h> 17 #include <uapi/linux/input-event-codes.h> 18 19 #include "../codecs/rt5682.h" 20 #include "common.h" 21 #include "lpass.h" 22 23 #define DEFAULT_MCLK_RATE 19200000 24 #define RT5682_PLL1_FREQ (48000 * 512) 25 26 #define DRIVER_NAME "SC7180" 27 28 struct sc7180_snd_data { 29 struct snd_soc_card card; 30 u32 pri_mi2s_clk_count; 31 struct snd_soc_jack hs_jack; 32 struct snd_soc_jack hdmi_jack; 33 struct gpio_desc *dmic_sel; 34 int dmic_switch; 35 }; 36 37 static void sc7180_jack_free(struct snd_jack *jack) 38 { 39 struct snd_soc_component *component = jack->private_data; 40 41 snd_soc_component_set_jack(component, NULL, NULL); 42 } 43 44 static int sc7180_headset_init(struct snd_soc_pcm_runtime *rtd) 45 { 46 struct snd_soc_card *card = rtd->card; 47 struct sc7180_snd_data *pdata = snd_soc_card_get_drvdata(card); 48 struct snd_soc_dai *codec_dai = asoc_rtd_to_codec(rtd, 0); 49 struct snd_soc_component *component = codec_dai->component; 50 struct snd_jack *jack; 51 int rval; 52 53 rval = snd_soc_card_jack_new( 54 card, "Headset Jack", 55 SND_JACK_HEADSET | 56 SND_JACK_HEADPHONE | 57 SND_JACK_BTN_0 | SND_JACK_BTN_1 | 58 SND_JACK_BTN_2 | SND_JACK_BTN_3, 59 &pdata->hs_jack, NULL, 0); 60 61 if (rval < 0) { 62 dev_err(card->dev, "Unable to add Headset Jack\n"); 63 return rval; 64 } 65 66 jack = pdata->hs_jack.jack; 67 68 snd_jack_set_key(jack, SND_JACK_BTN_0, KEY_PLAYPAUSE); 69 snd_jack_set_key(jack, SND_JACK_BTN_1, KEY_VOICECOMMAND); 70 snd_jack_set_key(jack, SND_JACK_BTN_2, KEY_VOLUMEUP); 71 snd_jack_set_key(jack, SND_JACK_BTN_3, KEY_VOLUMEDOWN); 72 73 jack->private_data = component; 74 jack->private_free = sc7180_jack_free; 75 76 return snd_soc_component_set_jack(component, &pdata->hs_jack, NULL); 77 } 78 79 static int sc7180_hdmi_init(struct snd_soc_pcm_runtime *rtd) 80 { 81 struct snd_soc_card *card = rtd->card; 82 struct sc7180_snd_data *pdata = snd_soc_card_get_drvdata(card); 83 struct snd_soc_dai *codec_dai = asoc_rtd_to_codec(rtd, 0); 84 struct snd_soc_component *component = codec_dai->component; 85 struct snd_jack *jack; 86 int rval; 87 88 rval = snd_soc_card_jack_new( 89 card, "HDMI Jack", 90 SND_JACK_LINEOUT, 91 &pdata->hdmi_jack, NULL, 0); 92 93 if (rval < 0) { 94 dev_err(card->dev, "Unable to add HDMI Jack\n"); 95 return rval; 96 } 97 98 jack = pdata->hdmi_jack.jack; 99 jack->private_data = component; 100 jack->private_free = sc7180_jack_free; 101 102 return snd_soc_component_set_jack(component, &pdata->hdmi_jack, NULL); 103 } 104 105 static int sc7180_init(struct snd_soc_pcm_runtime *rtd) 106 { 107 struct snd_soc_dai *cpu_dai = asoc_rtd_to_cpu(rtd, 0); 108 109 switch (cpu_dai->id) { 110 case MI2S_PRIMARY: 111 return sc7180_headset_init(rtd); 112 case MI2S_SECONDARY: 113 return 0; 114 case LPASS_DP_RX: 115 return sc7180_hdmi_init(rtd); 116 default: 117 dev_err(rtd->dev, "%s: invalid dai id 0x%x\n", __func__, 118 cpu_dai->id); 119 return -EINVAL; 120 } 121 return 0; 122 } 123 124 static int sc7180_snd_startup(struct snd_pcm_substream *substream) 125 { 126 struct snd_soc_pcm_runtime *rtd = substream->private_data; 127 struct snd_soc_card *card = rtd->card; 128 struct sc7180_snd_data *data = snd_soc_card_get_drvdata(card); 129 struct snd_soc_dai *cpu_dai = asoc_rtd_to_cpu(rtd, 0); 130 struct snd_soc_dai *codec_dai = asoc_rtd_to_codec(rtd, 0); 131 int ret; 132 133 switch (cpu_dai->id) { 134 case MI2S_PRIMARY: 135 if (++data->pri_mi2s_clk_count == 1) { 136 snd_soc_dai_set_sysclk(cpu_dai, 137 LPASS_MCLK0, 138 DEFAULT_MCLK_RATE, 139 SNDRV_PCM_STREAM_PLAYBACK); 140 } 141 142 snd_soc_dai_set_fmt(codec_dai, 143 SND_SOC_DAIFMT_CBS_CFS | 144 SND_SOC_DAIFMT_NB_NF | 145 SND_SOC_DAIFMT_I2S); 146 147 /* Configure PLL1 for codec */ 148 ret = snd_soc_dai_set_pll(codec_dai, 0, RT5682_PLL1_S_MCLK, 149 DEFAULT_MCLK_RATE, RT5682_PLL1_FREQ); 150 if (ret) { 151 dev_err(rtd->dev, "can't set codec pll: %d\n", ret); 152 return ret; 153 } 154 155 /* Configure sysclk for codec */ 156 ret = snd_soc_dai_set_sysclk(codec_dai, RT5682_SCLK_S_PLL1, 157 RT5682_PLL1_FREQ, 158 SND_SOC_CLOCK_IN); 159 if (ret) 160 dev_err(rtd->dev, "snd_soc_dai_set_sysclk err = %d\n", 161 ret); 162 163 break; 164 case MI2S_SECONDARY: 165 break; 166 case LPASS_DP_RX: 167 break; 168 default: 169 dev_err(rtd->dev, "%s: invalid dai id 0x%x\n", __func__, 170 cpu_dai->id); 171 return -EINVAL; 172 } 173 return 0; 174 } 175 176 static int dmic_get(struct snd_kcontrol *kcontrol, 177 struct snd_ctl_elem_value *ucontrol) 178 { 179 struct snd_soc_dapm_context *dapm = snd_soc_dapm_kcontrol_dapm(kcontrol); 180 struct sc7180_snd_data *data = snd_soc_card_get_drvdata(dapm->card); 181 182 ucontrol->value.integer.value[0] = data->dmic_switch; 183 return 0; 184 } 185 186 static int dmic_set(struct snd_kcontrol *kcontrol, 187 struct snd_ctl_elem_value *ucontrol) 188 { 189 struct snd_soc_dapm_context *dapm = snd_soc_dapm_kcontrol_dapm(kcontrol); 190 struct sc7180_snd_data *data = snd_soc_card_get_drvdata(dapm->card); 191 192 data->dmic_switch = ucontrol->value.integer.value[0]; 193 gpiod_set_value(data->dmic_sel, data->dmic_switch); 194 return 0; 195 } 196 197 static void sc7180_snd_shutdown(struct snd_pcm_substream *substream) 198 { 199 struct snd_soc_pcm_runtime *rtd = substream->private_data; 200 struct snd_soc_card *card = rtd->card; 201 struct sc7180_snd_data *data = snd_soc_card_get_drvdata(card); 202 struct snd_soc_dai *cpu_dai = asoc_rtd_to_cpu(rtd, 0); 203 204 switch (cpu_dai->id) { 205 case MI2S_PRIMARY: 206 if (--data->pri_mi2s_clk_count == 0) { 207 snd_soc_dai_set_sysclk(cpu_dai, 208 LPASS_MCLK0, 209 0, 210 SNDRV_PCM_STREAM_PLAYBACK); 211 } 212 break; 213 case MI2S_SECONDARY: 214 break; 215 case LPASS_DP_RX: 216 break; 217 default: 218 dev_err(rtd->dev, "%s: invalid dai id 0x%x\n", __func__, 219 cpu_dai->id); 220 break; 221 } 222 } 223 224 static int sc7180_adau7002_init(struct snd_soc_pcm_runtime *rtd) 225 { 226 struct snd_soc_dai *cpu_dai = asoc_rtd_to_cpu(rtd, 0); 227 228 switch (cpu_dai->id) { 229 case MI2S_PRIMARY: 230 return 0; 231 case MI2S_SECONDARY: 232 return 0; 233 case LPASS_DP_RX: 234 return sc7180_hdmi_init(rtd); 235 default: 236 dev_err(rtd->dev, "%s: invalid dai id 0x%x\n", __func__, 237 cpu_dai->id); 238 return -EINVAL; 239 } 240 return 0; 241 } 242 243 static int sc7180_adau7002_snd_startup(struct snd_pcm_substream *substream) 244 { 245 struct snd_soc_pcm_runtime *rtd = substream->private_data; 246 struct snd_soc_dai *cpu_dai = asoc_rtd_to_cpu(rtd, 0); 247 struct snd_soc_dai *codec_dai = asoc_rtd_to_codec(rtd, 0); 248 struct snd_pcm_runtime *runtime = substream->runtime; 249 250 switch (cpu_dai->id) { 251 case MI2S_PRIMARY: 252 snd_soc_dai_set_fmt(codec_dai, 253 SND_SOC_DAIFMT_CBS_CFS | 254 SND_SOC_DAIFMT_NB_NF | 255 SND_SOC_DAIFMT_I2S); 256 runtime->hw.formats = SNDRV_PCM_FMTBIT_S32_LE; 257 snd_pcm_hw_constraint_msbits(runtime, 0, 32, 32); 258 259 break; 260 case MI2S_SECONDARY: 261 break; 262 case LPASS_DP_RX: 263 break; 264 default: 265 dev_err(rtd->dev, "%s: invalid dai id 0x%x\n", __func__, 266 cpu_dai->id); 267 return -EINVAL; 268 } 269 return 0; 270 } 271 272 static const struct snd_soc_ops sc7180_ops = { 273 .startup = sc7180_snd_startup, 274 .shutdown = sc7180_snd_shutdown, 275 }; 276 277 static const struct snd_soc_ops sc7180_adau7002_ops = { 278 .startup = sc7180_adau7002_snd_startup, 279 }; 280 281 static const struct snd_soc_dapm_widget sc7180_snd_widgets[] = { 282 SND_SOC_DAPM_HP("Headphone Jack", NULL), 283 SND_SOC_DAPM_MIC("Headset Mic", NULL), 284 }; 285 286 static const struct snd_soc_dapm_widget sc7180_adau7002_snd_widgets[] = { 287 SND_SOC_DAPM_MIC("DMIC", NULL), 288 }; 289 290 static const char * const dmic_mux_text[] = { 291 "Front Mic", 292 "Rear Mic", 293 }; 294 295 static SOC_ENUM_SINGLE_DECL(sc7180_dmic_enum, 296 SND_SOC_NOPM, 0, dmic_mux_text); 297 298 static const struct snd_kcontrol_new sc7180_dmic_mux_control = 299 SOC_DAPM_ENUM_EXT("DMIC Select Mux", sc7180_dmic_enum, 300 dmic_get, dmic_set); 301 302 static const struct snd_soc_dapm_widget sc7180_snd_dual_mic_widgets[] = { 303 SND_SOC_DAPM_HP("Headphone Jack", NULL), 304 SND_SOC_DAPM_MIC("Headset Mic", NULL), 305 SND_SOC_DAPM_MIC("DMIC", NULL), 306 SND_SOC_DAPM_MUX("Dmic Mux", SND_SOC_NOPM, 0, 0, &sc7180_dmic_mux_control), 307 }; 308 309 static const struct snd_soc_dapm_route sc7180_snd_dual_mic_audio_route[] = { 310 {"Dmic Mux", "Front Mic", "DMIC"}, 311 {"Dmic Mux", "Rear Mic", "DMIC"}, 312 }; 313 314 static int sc7180_snd_platform_probe(struct platform_device *pdev) 315 { 316 struct snd_soc_card *card; 317 struct sc7180_snd_data *data; 318 struct device *dev = &pdev->dev; 319 struct snd_soc_dai_link *link; 320 int ret; 321 int i; 322 bool no_headphone = false; 323 324 /* Allocate the private data */ 325 data = devm_kzalloc(dev, sizeof(*data), GFP_KERNEL); 326 if (!data) 327 return -ENOMEM; 328 329 card = &data->card; 330 snd_soc_card_set_drvdata(card, data); 331 332 card->owner = THIS_MODULE; 333 card->driver_name = DRIVER_NAME; 334 card->dev = dev; 335 card->dapm_widgets = sc7180_snd_widgets; 336 card->num_dapm_widgets = ARRAY_SIZE(sc7180_snd_widgets); 337 338 if (of_property_read_bool(dev->of_node, "dmic-gpios")) { 339 card->dapm_widgets = sc7180_snd_dual_mic_widgets, 340 card->num_dapm_widgets = ARRAY_SIZE(sc7180_snd_dual_mic_widgets), 341 card->dapm_routes = sc7180_snd_dual_mic_audio_route, 342 card->num_dapm_routes = ARRAY_SIZE(sc7180_snd_dual_mic_audio_route), 343 data->dmic_sel = devm_gpiod_get(&pdev->dev, "dmic", GPIOD_OUT_LOW); 344 if (IS_ERR(data->dmic_sel)) { 345 dev_err(&pdev->dev, "DMIC gpio failed err=%ld\n", PTR_ERR(data->dmic_sel)); 346 return PTR_ERR(data->dmic_sel); 347 } 348 } 349 350 if (of_device_is_compatible(dev->of_node, "google,sc7180-coachz")) { 351 no_headphone = true; 352 card->dapm_widgets = sc7180_adau7002_snd_widgets; 353 card->num_dapm_widgets = ARRAY_SIZE(sc7180_adau7002_snd_widgets); 354 } 355 356 ret = qcom_snd_parse_of(card); 357 if (ret) 358 return ret; 359 360 for_each_card_prelinks(card, i, link) { 361 if (no_headphone) { 362 link->ops = &sc7180_adau7002_ops; 363 link->init = sc7180_adau7002_init; 364 } else { 365 link->ops = &sc7180_ops; 366 link->init = sc7180_init; 367 } 368 } 369 370 return devm_snd_soc_register_card(dev, card); 371 } 372 373 static const struct of_device_id sc7180_snd_device_id[] = { 374 {.compatible = "google,sc7180-trogdor"}, 375 {.compatible = "google,sc7180-coachz"}, 376 {}, 377 }; 378 MODULE_DEVICE_TABLE(of, sc7180_snd_device_id); 379 380 static struct platform_driver sc7180_snd_driver = { 381 .probe = sc7180_snd_platform_probe, 382 .driver = { 383 .name = "msm-snd-sc7180", 384 .of_match_table = sc7180_snd_device_id, 385 .pm = &snd_soc_pm_ops, 386 }, 387 }; 388 module_platform_driver(sc7180_snd_driver); 389 390 MODULE_DESCRIPTION("sc7180 ASoC Machine Driver"); 391 MODULE_LICENSE("GPL v2"); 392