FILE
lowland.c
File preview with syntax highlighting.
linux-6.19.14/sound/soc/samsung/lowland.c
1// SPDX-License-Identifier: GPL-2.0+ 2// 3// Lowland audio support 4// 5// Copyright 2011 Wolfson Microelectronics 6 7#include <sound/soc.h> 8#include <sound/soc-dapm.h> 9#include <sound/jack.h> 10#include <linux/module.h> 11 12#include "../codecs/wm5100.h" 13#include "../codecs/wm9081.h" 14 15#define MCLK1_RATE (44100 * 512) 16#define CLKOUT_RATE (44100 * 256) 17 18static struct snd_soc_jack lowland_headset; 19 20/* Headset jack detection DAPM pins */ 21static struct snd_soc_jack_pin lowland_headset_pins[] = { 22 { 23 .pin = "Headphone", 24 .mask = SND_JACK_HEADPHONE, 25 }, 26 { 27 .pin = "Headset Mic", 28 .mask = SND_JACK_MICROPHONE, 29 }, 30 { 31 .pin = "Line Out", 32 .mask = SND_JACK_LINEOUT, 33 }, 34}; 35 36static int lowland_wm5100_init(struct snd_soc_pcm_runtime *rtd) 37{ 38 struct snd_soc_component *component = snd_soc_rtd_to_codec(rtd, 0)->component; 39 int ret; 40 41 ret = snd_soc_component_set_sysclk(component, WM5100_CLK_SYSCLK, 42 WM5100_CLKSRC_MCLK1, MCLK1_RATE, 43 SND_SOC_CLOCK_IN); 44 if (ret < 0) { 45 pr_err("Failed to set SYSCLK clock source: %d\n", ret); 46 return ret; 47 } 48 49 /* Clock OPCLK, used by the other audio components. */ 50 ret = snd_soc_component_set_sysclk(component, WM5100_CLK_OPCLK, 0, 51 CLKOUT_RATE, 0); 52 if (ret < 0) { 53 pr_err("Failed to set OPCLK rate: %d\n", ret); 54 return ret; 55 } 56 57 ret = snd_soc_card_jack_new_pins(rtd->card, "Headset", 58 SND_JACK_LINEOUT | SND_JACK_HEADSET | 59 SND_JACK_BTN_0, 60 &lowland_headset, lowland_headset_pins, 61 ARRAY_SIZE(lowland_headset_pins)); 62 if (ret) 63 return ret; 64 65 wm5100_detect(component, &lowland_headset); 66 67 return 0; 68} 69 70static int lowland_wm9081_init(struct snd_soc_pcm_runtime *rtd) 71{ 72 struct snd_soc_component *component = snd_soc_rtd_to_codec(rtd, 0)->component; 73 struct snd_soc_dapm_context *dapm = snd_soc_card_to_dapm(rtd->card); 74 75 snd_soc_dapm_disable_pin(dapm, "LINEOUT"); 76 77 /* At any time the WM9081 is active it will have this clock */ 78 return snd_soc_component_set_sysclk(component, WM9081_SYSCLK_MCLK, 0, 79 CLKOUT_RATE, 0); 80} 81 82static const struct snd_soc_pcm_stream sub_params = { 83 .formats = SNDRV_PCM_FMTBIT_S32_LE, 84 .rate_min = 44100, 85 .rate_max = 44100, 86 .channels_min = 2, 87 .channels_max = 2, 88}; 89 90SND_SOC_DAILINK_DEFS(cpu, 91 DAILINK_COMP_ARRAY(COMP_CPU("samsung-i2s.0")), 92 DAILINK_COMP_ARRAY(COMP_CODEC("wm5100.1-001a", "wm5100-aif1")), 93 DAILINK_COMP_ARRAY(COMP_PLATFORM("samsung-i2s.0"))); 94 95SND_SOC_DAILINK_DEFS(baseband, 96 DAILINK_COMP_ARRAY(COMP_CPU("wm5100-aif2")), 97 DAILINK_COMP_ARRAY(COMP_CODEC("wm1250-ev1.1-0027", "wm1250-ev1"))); 98 99SND_SOC_DAILINK_DEFS(speaker, 100 DAILINK_COMP_ARRAY(COMP_CPU("wm5100-aif3")), 101 DAILINK_COMP_ARRAY(COMP_CODEC("wm9081.1-006c", "wm9081-hifi"))); 102 103static struct snd_soc_dai_link lowland_dai[] = { 104 { 105 .name = "CPU", 106 .stream_name = "CPU", 107 .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF | 108 SND_SOC_DAIFMT_CBP_CFP, 109 .init = lowland_wm5100_init, 110 SND_SOC_DAILINK_REG(cpu), 111 }, 112 { 113 .name = "Baseband", 114 .stream_name = "Baseband", 115 .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF | 116 SND_SOC_DAIFMT_CBP_CFP, 117 .ignore_suspend = 1, 118 SND_SOC_DAILINK_REG(baseband), 119 }, 120 { 121 .name = "Sub Speaker", 122 .stream_name = "Sub Speaker", 123 .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF | 124 SND_SOC_DAIFMT_CBP_CFP, 125 .ignore_suspend = 1, 126 .c2c_params = &sub_params, 127 .num_c2c_params = 1, 128 .init = lowland_wm9081_init, 129 SND_SOC_DAILINK_REG(speaker), 130 }, 131}; 132 133static struct snd_soc_codec_conf lowland_codec_conf[] = { 134 { 135 .dlc = COMP_CODEC_CONF("wm9081.1-006c"), 136 .name_prefix = "Sub", 137 }, 138}; 139 140static const struct snd_kcontrol_new controls[] = { 141 SOC_DAPM_PIN_SWITCH("Main Speaker"), 142 SOC_DAPM_PIN_SWITCH("Main DMIC"), 143 SOC_DAPM_PIN_SWITCH("Main AMIC"), 144 SOC_DAPM_PIN_SWITCH("WM1250 Input"), 145 SOC_DAPM_PIN_SWITCH("WM1250 Output"), 146 SOC_DAPM_PIN_SWITCH("Headphone"), 147 SOC_DAPM_PIN_SWITCH("Line Out"), 148}; 149 150static const struct snd_soc_dapm_widget widgets[] = { 151 SND_SOC_DAPM_HP("Headphone", NULL), 152 SND_SOC_DAPM_MIC("Headset Mic", NULL), 153 SND_SOC_DAPM_LINE("Line Out", NULL), 154 155 SND_SOC_DAPM_SPK("Main Speaker", NULL), 156 157 SND_SOC_DAPM_MIC("Main AMIC", NULL), 158 SND_SOC_DAPM_MIC("Main DMIC", NULL), 159}; 160 161static const struct snd_soc_dapm_route audio_paths[] = { 162 { "Sub IN1", NULL, "HPOUT2L" }, 163 { "Sub IN2", NULL, "HPOUT2R" }, 164 165 { "Main Speaker", NULL, "Sub SPKN" }, 166 { "Main Speaker", NULL, "Sub SPKP" }, 167 { "Main Speaker", NULL, "SPKDAT1" }, 168}; 169 170static struct snd_soc_card lowland = { 171 .name = "Lowland", 172 .owner = THIS_MODULE, 173 .dai_link = lowland_dai, 174 .num_links = ARRAY_SIZE(lowland_dai), 175 .codec_conf = lowland_codec_conf, 176 .num_configs = ARRAY_SIZE(lowland_codec_conf), 177 178 .controls = controls, 179 .num_controls = ARRAY_SIZE(controls), 180 .dapm_widgets = widgets, 181 .num_dapm_widgets = ARRAY_SIZE(widgets), 182 .dapm_routes = audio_paths, 183 .num_dapm_routes = ARRAY_SIZE(audio_paths), 184}; 185 186static int lowland_probe(struct platform_device *pdev) 187{ 188 struct snd_soc_card *card = &lowland; 189 int ret; 190 191 card->dev = &pdev->dev; 192 193 ret = devm_snd_soc_register_card(&pdev->dev, card); 194 if (ret) 195 dev_err_probe(&pdev->dev, ret, "snd_soc_register_card() failed\n"); 196 197 return ret; 198} 199 200static struct platform_driver lowland_driver = { 201 .driver = { 202 .name = "lowland", 203 .pm = &snd_soc_pm_ops, 204 }, 205 .probe = lowland_probe, 206}; 207 208module_platform_driver(lowland_driver); 209 210MODULE_DESCRIPTION("Lowland audio support"); 211MODULE_AUTHOR("Mark Brown <broonie@opensource.wolfsonmicro.com>"); 212MODULE_LICENSE("GPL"); 213MODULE_ALIAS("platform:lowland");
~/
Read-only file preview.