neo1973_wm8753.c (9808B)
1// SPDX-License-Identifier: GPL-2.0+ 2// 3// neo1973_wm8753.c - SoC audio for Openmoko Neo1973 and Freerunner devices 4// 5// Copyright 2007 Openmoko Inc 6// Author: Graeme Gregory <graeme@openmoko.org> 7// Copyright 2007 Wolfson Microelectronics PLC. 8// Author: Graeme Gregory 9// graeme.gregory@wolfsonmicro.com or linux@wolfsonmicro.com 10// Copyright 2009 Wolfson Microelectronics 11 12#include <linux/module.h> 13#include <linux/platform_device.h> 14#include <linux/gpio/consumer.h> 15 16#include <sound/soc.h> 17 18#include "regs-iis.h" 19#include "../codecs/wm8753.h" 20#include "s3c24xx-i2s.h" 21 22static int neo1973_hifi_hw_params(struct snd_pcm_substream *substream, 23 struct snd_pcm_hw_params *params) 24{ 25 struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream); 26 struct snd_soc_dai *codec_dai = asoc_rtd_to_codec(rtd, 0); 27 struct snd_soc_dai *cpu_dai = asoc_rtd_to_cpu(rtd, 0); 28 unsigned int pll_out = 0, bclk = 0; 29 int ret = 0; 30 unsigned long iis_clkrate; 31 32 iis_clkrate = s3c24xx_i2s_get_clockrate(); 33 34 switch (params_rate(params)) { 35 case 8000: 36 case 16000: 37 pll_out = 12288000; 38 break; 39 case 48000: 40 bclk = WM8753_BCLK_DIV_4; 41 pll_out = 12288000; 42 break; 43 case 96000: 44 bclk = WM8753_BCLK_DIV_2; 45 pll_out = 12288000; 46 break; 47 case 11025: 48 bclk = WM8753_BCLK_DIV_16; 49 pll_out = 11289600; 50 break; 51 case 22050: 52 bclk = WM8753_BCLK_DIV_8; 53 pll_out = 11289600; 54 break; 55 case 44100: 56 bclk = WM8753_BCLK_DIV_4; 57 pll_out = 11289600; 58 break; 59 case 88200: 60 bclk = WM8753_BCLK_DIV_2; 61 pll_out = 11289600; 62 break; 63 } 64 65 /* set the codec system clock for DAC and ADC */ 66 ret = snd_soc_dai_set_sysclk(codec_dai, WM8753_MCLK, pll_out, 67 SND_SOC_CLOCK_IN); 68 if (ret < 0) 69 return ret; 70 71 /* set MCLK division for sample rate */ 72 ret = snd_soc_dai_set_clkdiv(cpu_dai, S3C24XX_DIV_MCLK, 73 S3C2410_IISMOD_32FS); 74 if (ret < 0) 75 return ret; 76 77 /* set codec BCLK division for sample rate */ 78 ret = snd_soc_dai_set_clkdiv(codec_dai, WM8753_BCLKDIV, bclk); 79 if (ret < 0) 80 return ret; 81 82 /* set prescaler division for sample rate */ 83 ret = snd_soc_dai_set_clkdiv(cpu_dai, S3C24XX_DIV_PRESCALER, 84 S3C24XX_PRESCALE(4, 4)); 85 if (ret < 0) 86 return ret; 87 88 /* codec PLL input is PCLK/4 */ 89 ret = snd_soc_dai_set_pll(codec_dai, WM8753_PLL1, 0, 90 iis_clkrate / 4, pll_out); 91 if (ret < 0) 92 return ret; 93 94 return 0; 95} 96 97static int neo1973_hifi_hw_free(struct snd_pcm_substream *substream) 98{ 99 struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream); 100 struct snd_soc_dai *codec_dai = asoc_rtd_to_codec(rtd, 0); 101 102 /* disable the PLL */ 103 return snd_soc_dai_set_pll(codec_dai, WM8753_PLL1, 0, 0, 0); 104} 105 106/* 107 * Neo1973 WM8753 HiFi DAI opserations. 108 */ 109static const struct snd_soc_ops neo1973_hifi_ops = { 110 .hw_params = neo1973_hifi_hw_params, 111 .hw_free = neo1973_hifi_hw_free, 112}; 113 114static int neo1973_voice_hw_params(struct snd_pcm_substream *substream, 115 struct snd_pcm_hw_params *params) 116{ 117 struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream); 118 struct snd_soc_dai *codec_dai = asoc_rtd_to_codec(rtd, 0); 119 unsigned int pcmdiv = 0; 120 int ret = 0; 121 unsigned long iis_clkrate; 122 123 iis_clkrate = s3c24xx_i2s_get_clockrate(); 124 125 if (params_rate(params) != 8000) 126 return -EINVAL; 127 if (params_channels(params) != 1) 128 return -EINVAL; 129 130 pcmdiv = WM8753_PCM_DIV_6; /* 2.048 MHz */ 131 132 /* set the codec system clock for DAC and ADC */ 133 ret = snd_soc_dai_set_sysclk(codec_dai, WM8753_PCMCLK, 12288000, 134 SND_SOC_CLOCK_IN); 135 if (ret < 0) 136 return ret; 137 138 /* set codec PCM division for sample rate */ 139 ret = snd_soc_dai_set_clkdiv(codec_dai, WM8753_PCMDIV, pcmdiv); 140 if (ret < 0) 141 return ret; 142 143 /* configure and enable PLL for 12.288MHz output */ 144 ret = snd_soc_dai_set_pll(codec_dai, WM8753_PLL2, 0, 145 iis_clkrate / 4, 12288000); 146 if (ret < 0) 147 return ret; 148 149 return 0; 150} 151 152static int neo1973_voice_hw_free(struct snd_pcm_substream *substream) 153{ 154 struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream); 155 struct snd_soc_dai *codec_dai = asoc_rtd_to_codec(rtd, 0); 156 157 /* disable the PLL */ 158 return snd_soc_dai_set_pll(codec_dai, WM8753_PLL2, 0, 0, 0); 159} 160 161static const struct snd_soc_ops neo1973_voice_ops = { 162 .hw_params = neo1973_voice_hw_params, 163 .hw_free = neo1973_voice_hw_free, 164}; 165 166static struct gpio_desc *gpiod_hp_in, *gpiod_amp_shut; 167static int gta02_speaker_enabled; 168 169static int lm4853_set_spk(struct snd_kcontrol *kcontrol, 170 struct snd_ctl_elem_value *ucontrol) 171{ 172 gta02_speaker_enabled = ucontrol->value.integer.value[0]; 173 174 gpiod_set_value(gpiod_hp_in, !gta02_speaker_enabled); 175 176 return 0; 177} 178 179static int lm4853_get_spk(struct snd_kcontrol *kcontrol, 180 struct snd_ctl_elem_value *ucontrol) 181{ 182 ucontrol->value.integer.value[0] = gta02_speaker_enabled; 183 return 0; 184} 185 186static int lm4853_event(struct snd_soc_dapm_widget *w, 187 struct snd_kcontrol *k, int event) 188{ 189 gpiod_set_value(gpiod_amp_shut, SND_SOC_DAPM_EVENT_OFF(event)); 190 191 return 0; 192} 193 194static const struct snd_soc_dapm_widget neo1973_wm8753_dapm_widgets[] = { 195 SND_SOC_DAPM_LINE("GSM Line Out", NULL), 196 SND_SOC_DAPM_LINE("GSM Line In", NULL), 197 SND_SOC_DAPM_MIC("Headset Mic", NULL), 198 SND_SOC_DAPM_MIC("Handset Mic", NULL), 199 SND_SOC_DAPM_SPK("Handset Spk", NULL), 200 SND_SOC_DAPM_SPK("Stereo Out", lm4853_event), 201}; 202 203static const struct snd_soc_dapm_route neo1973_wm8753_routes[] = { 204 /* Connections to the GSM Module */ 205 {"GSM Line Out", NULL, "MONO1"}, 206 {"GSM Line Out", NULL, "MONO2"}, 207 {"RXP", NULL, "GSM Line In"}, 208 {"RXN", NULL, "GSM Line In"}, 209 210 /* Connections to Headset */ 211 {"MIC1", NULL, "Mic Bias"}, 212 {"Mic Bias", NULL, "Headset Mic"}, 213 214 /* Call Mic */ 215 {"MIC2", NULL, "Mic Bias"}, 216 {"MIC2N", NULL, "Mic Bias"}, 217 {"Mic Bias", NULL, "Handset Mic"}, 218 219 /* Connect the ALC pins */ 220 {"ACIN", NULL, "ACOP"}, 221 222 /* Connections to the amp */ 223 {"Stereo Out", NULL, "LOUT1"}, 224 {"Stereo Out", NULL, "ROUT1"}, 225 226 /* Call Speaker */ 227 {"Handset Spk", NULL, "LOUT2"}, 228 {"Handset Spk", NULL, "ROUT2"}, 229}; 230 231static const struct snd_kcontrol_new neo1973_wm8753_controls[] = { 232 SOC_DAPM_PIN_SWITCH("GSM Line Out"), 233 SOC_DAPM_PIN_SWITCH("GSM Line In"), 234 SOC_DAPM_PIN_SWITCH("Headset Mic"), 235 SOC_DAPM_PIN_SWITCH("Handset Mic"), 236 SOC_DAPM_PIN_SWITCH("Handset Spk"), 237 SOC_DAPM_PIN_SWITCH("Stereo Out"), 238 239 SOC_SINGLE_BOOL_EXT("Amp Spk Switch", 0, 240 lm4853_get_spk, 241 lm4853_set_spk), 242}; 243 244static int neo1973_wm8753_init(struct snd_soc_pcm_runtime *rtd) 245{ 246 struct snd_soc_card *card = rtd->card; 247 248 /* set endpoints to default off mode */ 249 snd_soc_dapm_disable_pin(&card->dapm, "GSM Line Out"); 250 snd_soc_dapm_disable_pin(&card->dapm, "GSM Line In"); 251 snd_soc_dapm_disable_pin(&card->dapm, "Headset Mic"); 252 snd_soc_dapm_disable_pin(&card->dapm, "Handset Mic"); 253 snd_soc_dapm_disable_pin(&card->dapm, "Stereo Out"); 254 snd_soc_dapm_disable_pin(&card->dapm, "Handset Spk"); 255 256 /* allow audio paths from the GSM modem to run during suspend */ 257 snd_soc_dapm_ignore_suspend(&card->dapm, "GSM Line Out"); 258 snd_soc_dapm_ignore_suspend(&card->dapm, "GSM Line In"); 259 snd_soc_dapm_ignore_suspend(&card->dapm, "Headset Mic"); 260 snd_soc_dapm_ignore_suspend(&card->dapm, "Handset Mic"); 261 snd_soc_dapm_ignore_suspend(&card->dapm, "Stereo Out"); 262 snd_soc_dapm_ignore_suspend(&card->dapm, "Handset Spk"); 263 264 return 0; 265} 266 267SND_SOC_DAILINK_DEFS(wm8753, 268 DAILINK_COMP_ARRAY(COMP_CPU("s3c24xx-iis")), 269 DAILINK_COMP_ARRAY(COMP_CODEC("wm8753.0-001a", "wm8753-hifi")), 270 DAILINK_COMP_ARRAY(COMP_PLATFORM("s3c24xx-iis"))); 271 272SND_SOC_DAILINK_DEFS(bluetooth, 273 DAILINK_COMP_ARRAY(COMP_CPU("bt-sco-pcm")), 274 DAILINK_COMP_ARRAY(COMP_CODEC("wm8753.0-001a", "wm8753-voice"))); 275 276static struct snd_soc_dai_link neo1973_dai[] = { 277{ /* Hifi Playback - for similatious use with voice below */ 278 .name = "WM8753", 279 .stream_name = "WM8753 HiFi", 280 .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF | 281 SND_SOC_DAIFMT_CBM_CFM, 282 .init = neo1973_wm8753_init, 283 .ops = &neo1973_hifi_ops, 284 SND_SOC_DAILINK_REG(wm8753), 285}, 286{ /* Voice via BT */ 287 .name = "Bluetooth", 288 .stream_name = "Voice", 289 .dai_fmt = SND_SOC_DAIFMT_DSP_B | SND_SOC_DAIFMT_NB_NF | 290 SND_SOC_DAIFMT_CBS_CFS, 291 .ops = &neo1973_voice_ops, 292 SND_SOC_DAILINK_REG(bluetooth), 293}, 294}; 295 296static struct snd_soc_aux_dev neo1973_aux_devs[] = { 297 { 298 .dlc = COMP_AUX("dfbmcs320.0"), 299 }, 300}; 301 302static struct snd_soc_codec_conf neo1973_codec_conf[] = { 303 { 304 .dlc = COMP_CODEC_CONF("lm4857.0-007c"), 305 .name_prefix = "Amp", 306 }, 307}; 308 309static struct snd_soc_card neo1973 = { 310 .name = "neo1973gta02", 311 .owner = THIS_MODULE, 312 .dai_link = neo1973_dai, 313 .num_links = ARRAY_SIZE(neo1973_dai), 314 .aux_dev = neo1973_aux_devs, 315 .num_aux_devs = ARRAY_SIZE(neo1973_aux_devs), 316 .codec_conf = neo1973_codec_conf, 317 .num_configs = ARRAY_SIZE(neo1973_codec_conf), 318 319 .controls = neo1973_wm8753_controls, 320 .num_controls = ARRAY_SIZE(neo1973_wm8753_controls), 321 .dapm_widgets = neo1973_wm8753_dapm_widgets, 322 .num_dapm_widgets = ARRAY_SIZE(neo1973_wm8753_dapm_widgets), 323 .dapm_routes = neo1973_wm8753_routes, 324 .num_dapm_routes = ARRAY_SIZE(neo1973_wm8753_routes), 325 .fully_routed = true, 326}; 327 328static int neo1973_probe(struct platform_device *pdev) 329{ 330 struct device *dev = &pdev->dev; 331 332 gpiod_hp_in = devm_gpiod_get(dev, "hp", GPIOD_OUT_HIGH); 333 if (IS_ERR(gpiod_hp_in)) { 334 dev_err(dev, "missing gpio %s\n", "hp"); 335 return PTR_ERR(gpiod_hp_in); 336 } 337 gpiod_amp_shut = devm_gpiod_get(dev, "amp-shut", GPIOD_OUT_HIGH); 338 if (IS_ERR(gpiod_amp_shut)) { 339 dev_err(dev, "missing gpio %s\n", "amp-shut"); 340 return PTR_ERR(gpiod_amp_shut); 341 } 342 343 neo1973.dev = dev; 344 return devm_snd_soc_register_card(dev, &neo1973); 345} 346 347struct platform_driver neo1973_audio = { 348 .driver = { 349 .name = "neo1973-audio", 350 .pm = &snd_soc_pm_ops, 351 }, 352 .probe = neo1973_probe, 353}; 354module_platform_driver(neo1973_audio); 355 356/* Module information */ 357MODULE_AUTHOR("Graeme Gregory, graeme@openmoko.org, www.openmoko.org"); 358MODULE_DESCRIPTION("ALSA SoC WM8753 Neo1973 and Frerunner"); 359MODULE_LICENSE("GPL"); 360MODULE_ALIAS("platform:neo1973-audio");