1 /* 2 * tegra_wm8903.c - Tegra machine ASoC driver for boards using WM8903 codec. 3 * 4 * Author: Stephen Warren <swarren@nvidia.com> 5 * Copyright (C) 2010-2011 - NVIDIA, Inc. 6 * 7 * Based on code copyright/by: 8 * 9 * (c) 2009, 2010 Nvidia Graphics Pvt. Ltd. 10 * 11 * Copyright 2007 Wolfson Microelectronics PLC. 12 * Author: Graeme Gregory 13 * graeme.gregory@wolfsonmicro.com or linux@wolfsonmicro.com 14 * 15 * This program is free software; you can redistribute it and/or 16 * modify it under the terms of the GNU General Public License 17 * version 2 as published by the Free Software Foundation. 18 * 19 * This program is distributed in the hope that it will be useful, but 20 * WITHOUT ANY WARRANTY; without even the implied warranty of 21 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 22 * General Public License for more details. 23 * 24 * You should have received a copy of the GNU General Public License 25 * along with this program; if not, write to the Free Software 26 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 27 * 02110-1301 USA 28 * 29 */ 30 31 #include <asm/mach-types.h> 32 33 #include <linux/module.h> 34 #include <linux/platform_device.h> 35 #include <linux/slab.h> 36 #include <linux/gpio.h> 37 38 #include <mach/tegra_wm8903_pdata.h> 39 40 #include <sound/core.h> 41 #include <sound/jack.h> 42 #include <sound/pcm.h> 43 #include <sound/pcm_params.h> 44 #include <sound/soc.h> 45 46 #include "../codecs/wm8903.h" 47 48 #include "tegra_das.h" 49 #include "tegra_i2s.h" 50 #include "tegra_pcm.h" 51 #include "tegra_asoc_utils.h" 52 53 #define DRV_NAME "tegra-snd-wm8903" 54 55 #define GPIO_SPKR_EN BIT(0) 56 #define GPIO_HP_MUTE BIT(1) 57 #define GPIO_INT_MIC_EN BIT(2) 58 #define GPIO_EXT_MIC_EN BIT(3) 59 #define GPIO_HP_DET BIT(4) 60 61 struct tegra_wm8903 { 62 struct tegra_asoc_utils_data util_data; 63 struct tegra_wm8903_platform_data *pdata; 64 int gpio_requested; 65 }; 66 67 static int tegra_wm8903_hw_params(struct snd_pcm_substream *substream, 68 struct snd_pcm_hw_params *params) 69 { 70 struct snd_soc_pcm_runtime *rtd = substream->private_data; 71 struct snd_soc_dai *codec_dai = rtd->codec_dai; 72 struct snd_soc_dai *cpu_dai = rtd->cpu_dai; 73 struct snd_soc_codec *codec = rtd->codec; 74 struct snd_soc_card *card = codec->card; 75 struct tegra_wm8903 *machine = snd_soc_card_get_drvdata(card); 76 int srate, mclk; 77 int err; 78 79 srate = params_rate(params); 80 switch (srate) { 81 case 64000: 82 case 88200: 83 case 96000: 84 mclk = 128 * srate; 85 break; 86 default: 87 mclk = 256 * srate; 88 break; 89 } 90 /* FIXME: Codec only requires >= 3MHz if OSR==0 */ 91 while (mclk < 6000000) 92 mclk *= 2; 93 94 err = tegra_asoc_utils_set_rate(&machine->util_data, srate, mclk); 95 if (err < 0) { 96 dev_err(card->dev, "Can't configure clocks\n"); 97 return err; 98 } 99 100 err = snd_soc_dai_set_fmt(codec_dai, 101 SND_SOC_DAIFMT_I2S | 102 SND_SOC_DAIFMT_NB_NF | 103 SND_SOC_DAIFMT_CBS_CFS); 104 if (err < 0) { 105 dev_err(card->dev, "codec_dai fmt not set\n"); 106 return err; 107 } 108 109 err = snd_soc_dai_set_fmt(cpu_dai, 110 SND_SOC_DAIFMT_I2S | 111 SND_SOC_DAIFMT_NB_NF | 112 SND_SOC_DAIFMT_CBS_CFS); 113 if (err < 0) { 114 dev_err(card->dev, "cpu_dai fmt not set\n"); 115 return err; 116 } 117 118 err = snd_soc_dai_set_sysclk(codec_dai, 0, mclk, 119 SND_SOC_CLOCK_IN); 120 if (err < 0) { 121 dev_err(card->dev, "codec_dai clock not set\n"); 122 return err; 123 } 124 125 return 0; 126 } 127 128 static struct snd_soc_ops tegra_wm8903_ops = { 129 .hw_params = tegra_wm8903_hw_params, 130 }; 131 132 static struct snd_soc_jack tegra_wm8903_hp_jack; 133 134 static struct snd_soc_jack_pin tegra_wm8903_hp_jack_pins[] = { 135 { 136 .pin = "Headphone Jack", 137 .mask = SND_JACK_HEADPHONE, 138 }, 139 }; 140 141 static struct snd_soc_jack_gpio tegra_wm8903_hp_jack_gpio = { 142 .name = "headphone detect", 143 .report = SND_JACK_HEADPHONE, 144 .debounce_time = 150, 145 .invert = 1, 146 }; 147 148 static struct snd_soc_jack tegra_wm8903_mic_jack; 149 150 static struct snd_soc_jack_pin tegra_wm8903_mic_jack_pins[] = { 151 { 152 .pin = "Mic Jack", 153 .mask = SND_JACK_MICROPHONE, 154 }, 155 }; 156 157 static int tegra_wm8903_event_int_spk(struct snd_soc_dapm_widget *w, 158 struct snd_kcontrol *k, int event) 159 { 160 struct snd_soc_dapm_context *dapm = w->dapm; 161 struct snd_soc_card *card = dapm->card; 162 struct tegra_wm8903 *machine = snd_soc_card_get_drvdata(card); 163 struct tegra_wm8903_platform_data *pdata = machine->pdata; 164 165 if (!(machine->gpio_requested & GPIO_SPKR_EN)) 166 return 0; 167 168 gpio_set_value_cansleep(pdata->gpio_spkr_en, 169 SND_SOC_DAPM_EVENT_ON(event)); 170 171 return 0; 172 } 173 174 static int tegra_wm8903_event_hp(struct snd_soc_dapm_widget *w, 175 struct snd_kcontrol *k, int event) 176 { 177 struct snd_soc_dapm_context *dapm = w->dapm; 178 struct snd_soc_card *card = dapm->card; 179 struct tegra_wm8903 *machine = snd_soc_card_get_drvdata(card); 180 struct tegra_wm8903_platform_data *pdata = machine->pdata; 181 182 if (!(machine->gpio_requested & GPIO_HP_MUTE)) 183 return 0; 184 185 gpio_set_value_cansleep(pdata->gpio_hp_mute, 186 !SND_SOC_DAPM_EVENT_ON(event)); 187 188 return 0; 189 } 190 191 static const struct snd_soc_dapm_widget tegra_wm8903_dapm_widgets[] = { 192 SND_SOC_DAPM_SPK("Int Spk", tegra_wm8903_event_int_spk), 193 SND_SOC_DAPM_HP("Headphone Jack", tegra_wm8903_event_hp), 194 SND_SOC_DAPM_MIC("Mic Jack", NULL), 195 }; 196 197 static const struct snd_soc_dapm_route harmony_audio_map[] = { 198 {"Headphone Jack", NULL, "HPOUTR"}, 199 {"Headphone Jack", NULL, "HPOUTL"}, 200 {"Int Spk", NULL, "ROP"}, 201 {"Int Spk", NULL, "RON"}, 202 {"Int Spk", NULL, "LOP"}, 203 {"Int Spk", NULL, "LON"}, 204 {"Mic Bias", NULL, "Mic Jack"}, 205 {"IN1L", NULL, "Mic Bias"}, 206 }; 207 208 static const struct snd_soc_dapm_route seaboard_audio_map[] = { 209 {"Headphone Jack", NULL, "HPOUTR"}, 210 {"Headphone Jack", NULL, "HPOUTL"}, 211 {"Int Spk", NULL, "ROP"}, 212 {"Int Spk", NULL, "RON"}, 213 {"Int Spk", NULL, "LOP"}, 214 {"Int Spk", NULL, "LON"}, 215 {"Mic Bias", NULL, "Mic Jack"}, 216 {"IN1R", NULL, "Mic Bias"}, 217 }; 218 219 static const struct snd_soc_dapm_route kaen_audio_map[] = { 220 {"Headphone Jack", NULL, "HPOUTR"}, 221 {"Headphone Jack", NULL, "HPOUTL"}, 222 {"Int Spk", NULL, "ROP"}, 223 {"Int Spk", NULL, "RON"}, 224 {"Int Spk", NULL, "LOP"}, 225 {"Int Spk", NULL, "LON"}, 226 {"Mic Bias", NULL, "Mic Jack"}, 227 {"IN2R", NULL, "Mic Bias"}, 228 }; 229 230 static const struct snd_soc_dapm_route aebl_audio_map[] = { 231 {"Headphone Jack", NULL, "HPOUTR"}, 232 {"Headphone Jack", NULL, "HPOUTL"}, 233 {"Int Spk", NULL, "LINEOUTR"}, 234 {"Int Spk", NULL, "LINEOUTL"}, 235 {"Mic Bias", NULL, "Mic Jack"}, 236 {"IN1R", NULL, "Mic Bias"}, 237 }; 238 239 static const struct snd_kcontrol_new tegra_wm8903_controls[] = { 240 SOC_DAPM_PIN_SWITCH("Int Spk"), 241 }; 242 243 static int tegra_wm8903_init(struct snd_soc_pcm_runtime *rtd) 244 { 245 struct snd_soc_codec *codec = rtd->codec; 246 struct snd_soc_dapm_context *dapm = &codec->dapm; 247 struct snd_soc_card *card = codec->card; 248 struct tegra_wm8903 *machine = snd_soc_card_get_drvdata(card); 249 struct tegra_wm8903_platform_data *pdata = machine->pdata; 250 int ret; 251 252 if (gpio_is_valid(pdata->gpio_spkr_en)) { 253 ret = gpio_request(pdata->gpio_spkr_en, "spkr_en"); 254 if (ret) { 255 dev_err(card->dev, "cannot get spkr_en gpio\n"); 256 return ret; 257 } 258 machine->gpio_requested |= GPIO_SPKR_EN; 259 260 gpio_direction_output(pdata->gpio_spkr_en, 0); 261 } 262 263 if (gpio_is_valid(pdata->gpio_hp_mute)) { 264 ret = gpio_request(pdata->gpio_hp_mute, "hp_mute"); 265 if (ret) { 266 dev_err(card->dev, "cannot get hp_mute gpio\n"); 267 return ret; 268 } 269 machine->gpio_requested |= GPIO_HP_MUTE; 270 271 gpio_direction_output(pdata->gpio_hp_mute, 1); 272 } 273 274 if (gpio_is_valid(pdata->gpio_int_mic_en)) { 275 ret = gpio_request(pdata->gpio_int_mic_en, "int_mic_en"); 276 if (ret) { 277 dev_err(card->dev, "cannot get int_mic_en gpio\n"); 278 return ret; 279 } 280 machine->gpio_requested |= GPIO_INT_MIC_EN; 281 282 /* Disable int mic; enable signal is active-high */ 283 gpio_direction_output(pdata->gpio_int_mic_en, 0); 284 } 285 286 if (gpio_is_valid(pdata->gpio_ext_mic_en)) { 287 ret = gpio_request(pdata->gpio_ext_mic_en, "ext_mic_en"); 288 if (ret) { 289 dev_err(card->dev, "cannot get ext_mic_en gpio\n"); 290 return ret; 291 } 292 machine->gpio_requested |= GPIO_EXT_MIC_EN; 293 294 /* Enable ext mic; enable signal is active-low */ 295 gpio_direction_output(pdata->gpio_ext_mic_en, 0); 296 } 297 298 if (gpio_is_valid(pdata->gpio_hp_det)) { 299 tegra_wm8903_hp_jack_gpio.gpio = pdata->gpio_hp_det; 300 snd_soc_jack_new(codec, "Headphone Jack", SND_JACK_HEADPHONE, 301 &tegra_wm8903_hp_jack); 302 snd_soc_jack_add_pins(&tegra_wm8903_hp_jack, 303 ARRAY_SIZE(tegra_wm8903_hp_jack_pins), 304 tegra_wm8903_hp_jack_pins); 305 snd_soc_jack_add_gpios(&tegra_wm8903_hp_jack, 306 1, 307 &tegra_wm8903_hp_jack_gpio); 308 machine->gpio_requested |= GPIO_HP_DET; 309 } 310 311 snd_soc_jack_new(codec, "Mic Jack", SND_JACK_MICROPHONE, 312 &tegra_wm8903_mic_jack); 313 snd_soc_jack_add_pins(&tegra_wm8903_mic_jack, 314 ARRAY_SIZE(tegra_wm8903_mic_jack_pins), 315 tegra_wm8903_mic_jack_pins); 316 wm8903_mic_detect(codec, &tegra_wm8903_mic_jack, SND_JACK_MICROPHONE, 317 0); 318 319 snd_soc_dapm_force_enable_pin(dapm, "Mic Bias"); 320 321 /* FIXME: Calculate automatically based on DAPM routes? */ 322 if (!machine_is_harmony()) 323 snd_soc_dapm_nc_pin(dapm, "IN1L"); 324 if (!machine_is_seaboard() && !machine_is_aebl()) 325 snd_soc_dapm_nc_pin(dapm, "IN1R"); 326 snd_soc_dapm_nc_pin(dapm, "IN2L"); 327 if (!machine_is_kaen()) 328 snd_soc_dapm_nc_pin(dapm, "IN2R"); 329 snd_soc_dapm_nc_pin(dapm, "IN3L"); 330 snd_soc_dapm_nc_pin(dapm, "IN3R"); 331 332 if (machine_is_aebl()) { 333 snd_soc_dapm_nc_pin(dapm, "LON"); 334 snd_soc_dapm_nc_pin(dapm, "RON"); 335 snd_soc_dapm_nc_pin(dapm, "ROP"); 336 snd_soc_dapm_nc_pin(dapm, "LOP"); 337 } else { 338 snd_soc_dapm_nc_pin(dapm, "LINEOUTR"); 339 snd_soc_dapm_nc_pin(dapm, "LINEOUTL"); 340 } 341 342 snd_soc_dapm_sync(dapm); 343 344 return 0; 345 } 346 347 static struct snd_soc_dai_link tegra_wm8903_dai = { 348 .name = "WM8903", 349 .stream_name = "WM8903 PCM", 350 .codec_name = "wm8903.0-001a", 351 .platform_name = "tegra-pcm-audio", 352 .cpu_dai_name = "tegra-i2s.0", 353 .codec_dai_name = "wm8903-hifi", 354 .init = tegra_wm8903_init, 355 .ops = &tegra_wm8903_ops, 356 }; 357 358 static struct snd_soc_card snd_soc_tegra_wm8903 = { 359 .name = "tegra-wm8903", 360 .dai_link = &tegra_wm8903_dai, 361 .num_links = 1, 362 363 .controls = tegra_wm8903_controls, 364 .num_controls = ARRAY_SIZE(tegra_wm8903_controls), 365 .dapm_widgets = tegra_wm8903_dapm_widgets, 366 .num_dapm_widgets = ARRAY_SIZE(tegra_wm8903_dapm_widgets), 367 }; 368 369 static __devinit int tegra_wm8903_driver_probe(struct platform_device *pdev) 370 { 371 struct snd_soc_card *card = &snd_soc_tegra_wm8903; 372 struct tegra_wm8903 *machine; 373 struct tegra_wm8903_platform_data *pdata; 374 int ret; 375 376 pdata = pdev->dev.platform_data; 377 if (!pdata) { 378 dev_err(&pdev->dev, "No platform data supplied\n"); 379 return -EINVAL; 380 } 381 382 machine = kzalloc(sizeof(struct tegra_wm8903), GFP_KERNEL); 383 if (!machine) { 384 dev_err(&pdev->dev, "Can't allocate tegra_wm8903 struct\n"); 385 return -ENOMEM; 386 } 387 388 machine->pdata = pdata; 389 390 ret = tegra_asoc_utils_init(&machine->util_data, &pdev->dev); 391 if (ret) 392 goto err_free_machine; 393 394 card->dev = &pdev->dev; 395 platform_set_drvdata(pdev, card); 396 snd_soc_card_set_drvdata(card, machine); 397 398 if (machine_is_harmony()) { 399 card->dapm_routes = harmony_audio_map; 400 card->num_dapm_routes = ARRAY_SIZE(harmony_audio_map); 401 } else if (machine_is_seaboard()) { 402 card->dapm_routes = seaboard_audio_map; 403 card->num_dapm_routes = ARRAY_SIZE(seaboard_audio_map); 404 } else if (machine_is_kaen()) { 405 card->dapm_routes = kaen_audio_map; 406 card->num_dapm_routes = ARRAY_SIZE(kaen_audio_map); 407 } else { 408 card->dapm_routes = aebl_audio_map; 409 card->num_dapm_routes = ARRAY_SIZE(aebl_audio_map); 410 } 411 412 ret = snd_soc_register_card(card); 413 if (ret) { 414 dev_err(&pdev->dev, "snd_soc_register_card failed (%d)\n", 415 ret); 416 goto err_fini_utils; 417 } 418 419 return 0; 420 421 err_fini_utils: 422 tegra_asoc_utils_fini(&machine->util_data); 423 err_free_machine: 424 kfree(machine); 425 return ret; 426 } 427 428 static int __devexit tegra_wm8903_driver_remove(struct platform_device *pdev) 429 { 430 struct snd_soc_card *card = platform_get_drvdata(pdev); 431 struct tegra_wm8903 *machine = snd_soc_card_get_drvdata(card); 432 struct tegra_wm8903_platform_data *pdata = machine->pdata; 433 434 if (machine->gpio_requested & GPIO_HP_DET) 435 snd_soc_jack_free_gpios(&tegra_wm8903_hp_jack, 436 1, 437 &tegra_wm8903_hp_jack_gpio); 438 if (machine->gpio_requested & GPIO_EXT_MIC_EN) 439 gpio_free(pdata->gpio_ext_mic_en); 440 if (machine->gpio_requested & GPIO_INT_MIC_EN) 441 gpio_free(pdata->gpio_int_mic_en); 442 if (machine->gpio_requested & GPIO_HP_MUTE) 443 gpio_free(pdata->gpio_hp_mute); 444 if (machine->gpio_requested & GPIO_SPKR_EN) 445 gpio_free(pdata->gpio_spkr_en); 446 machine->gpio_requested = 0; 447 448 snd_soc_unregister_card(card); 449 450 tegra_asoc_utils_fini(&machine->util_data); 451 452 kfree(machine); 453 454 return 0; 455 } 456 457 static struct platform_driver tegra_wm8903_driver = { 458 .driver = { 459 .name = DRV_NAME, 460 .owner = THIS_MODULE, 461 .pm = &snd_soc_pm_ops, 462 }, 463 .probe = tegra_wm8903_driver_probe, 464 .remove = __devexit_p(tegra_wm8903_driver_remove), 465 }; 466 467 static int __init tegra_wm8903_modinit(void) 468 { 469 return platform_driver_register(&tegra_wm8903_driver); 470 } 471 module_init(tegra_wm8903_modinit); 472 473 static void __exit tegra_wm8903_modexit(void) 474 { 475 platform_driver_unregister(&tegra_wm8903_driver); 476 } 477 module_exit(tegra_wm8903_modexit); 478 479 MODULE_AUTHOR("Stephen Warren <swarren@nvidia.com>"); 480 MODULE_DESCRIPTION("Tegra+WM8903 machine ASoC driver"); 481 MODULE_LICENSE("GPL"); 482 MODULE_ALIAS("platform:" DRV_NAME); 483