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