1/* 2 * ASoC driver for TI DAVINCI EVM platform 3 * 4 * Author: Vladimir Barinov, <vbarinov@embeddedalley.com> 5 * Copyright: (C) 2007 MontaVista Software, Inc., <source@mvista.com> 6 * 7 * This program is free software; you can redistribute it and/or modify 8 * it under the terms of the GNU General Public License version 2 as 9 * published by the Free Software Foundation. 10 */ 11 12#include <linux/module.h> 13#include <linux/moduleparam.h> 14#include <linux/timer.h> 15#include <linux/interrupt.h> 16#include <linux/platform_device.h> 17#include <linux/i2c.h> 18#include <sound/core.h> 19#include <sound/pcm.h> 20#include <sound/soc.h> 21#include <sound/soc-dapm.h> 22 23#include <asm/dma.h> 24#include <asm/mach-types.h> 25 26#include <mach/asp.h> 27#include <mach/edma.h> 28#include <mach/mux.h> 29 30#include "../codecs/tlv320aic3x.h" 31#include "../codecs/cq93vc.h" 32#include "../codecs/spdif_transciever.h" 33#include "davinci-pcm.h" 34#include "davinci-i2s.h" 35#include "davinci-mcasp.h" 36#include "davinci-vcif.h" 37 38#define AUDIO_FORMAT (SND_SOC_DAIFMT_DSP_B | \ 39 SND_SOC_DAIFMT_CBM_CFM | SND_SOC_DAIFMT_IB_NF) 40static int evm_hw_params(struct snd_pcm_substream *substream, 41 struct snd_pcm_hw_params *params) 42{ 43 struct snd_soc_pcm_runtime *rtd = substream->private_data; 44 struct snd_soc_dai *codec_dai = rtd->dai->codec_dai; 45 struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai; 46 int ret = 0; 47 unsigned sysclk; 48 49 /* ASP1 on DM355 EVM is clocked by an external oscillator */ 50 if (machine_is_davinci_dm355_evm() || machine_is_davinci_dm6467_evm() || 51 machine_is_davinci_dm365_evm()) 52 sysclk = 27000000; 53 54 /* ASP0 in DM6446 EVM is clocked by U55, as configured by 55 * board-dm644x-evm.c using GPIOs from U18. There are six 56 * options; here we "know" we use a 48 KHz sample rate. 57 */ 58 else if (machine_is_davinci_evm()) 59 sysclk = 12288000; 60 61 else if (machine_is_davinci_da830_evm() || 62 machine_is_davinci_da850_evm()) 63 sysclk = 24576000; 64 65 else 66 return -EINVAL; 67 68 /* set codec DAI configuration */ 69 ret = snd_soc_dai_set_fmt(codec_dai, AUDIO_FORMAT); 70 if (ret < 0) 71 return ret; 72 73 /* set cpu DAI configuration */ 74 ret = snd_soc_dai_set_fmt(cpu_dai, AUDIO_FORMAT); 75 if (ret < 0) 76 return ret; 77 78 /* set the codec system clock */ 79 ret = snd_soc_dai_set_sysclk(codec_dai, 0, sysclk, SND_SOC_CLOCK_OUT); 80 if (ret < 0) 81 return ret; 82 83 return 0; 84} 85 86static int evm_spdif_hw_params(struct snd_pcm_substream *substream, 87 struct snd_pcm_hw_params *params) 88{ 89 struct snd_soc_pcm_runtime *rtd = substream->private_data; 90 struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai; 91 92 /* set cpu DAI configuration */ 93 return snd_soc_dai_set_fmt(cpu_dai, AUDIO_FORMAT); 94} 95 96static struct snd_soc_ops evm_ops = { 97 .hw_params = evm_hw_params, 98}; 99 100static struct snd_soc_ops evm_spdif_ops = { 101 .hw_params = evm_spdif_hw_params, 102}; 103 104/* davinci-evm machine dapm widgets */ 105static const struct snd_soc_dapm_widget aic3x_dapm_widgets[] = { 106 SND_SOC_DAPM_HP("Headphone Jack", NULL), 107 SND_SOC_DAPM_LINE("Line Out", NULL), 108 SND_SOC_DAPM_MIC("Mic Jack", NULL), 109 SND_SOC_DAPM_LINE("Line In", NULL), 110}; 111 112/* davinci-evm machine audio_mapnections to the codec pins */ 113static const struct snd_soc_dapm_route audio_map[] = { 114 /* Headphone connected to HPLOUT, HPROUT */ 115 {"Headphone Jack", NULL, "HPLOUT"}, 116 {"Headphone Jack", NULL, "HPROUT"}, 117 118 /* Line Out connected to LLOUT, RLOUT */ 119 {"Line Out", NULL, "LLOUT"}, 120 {"Line Out", NULL, "RLOUT"}, 121 122 /* Mic connected to (MIC3L | MIC3R) */ 123 {"MIC3L", NULL, "Mic Bias 2V"}, 124 {"MIC3R", NULL, "Mic Bias 2V"}, 125 {"Mic Bias 2V", NULL, "Mic Jack"}, 126 127 /* Line In connected to (LINE1L | LINE2L), (LINE1R | LINE2R) */ 128 {"LINE1L", NULL, "Line In"}, 129 {"LINE2L", NULL, "Line In"}, 130 {"LINE1R", NULL, "Line In"}, 131 {"LINE2R", NULL, "Line In"}, 132}; 133 134/* Logic for a aic3x as connected on a davinci-evm */ 135static int evm_aic3x_init(struct snd_soc_codec *codec) 136{ 137 /* Add davinci-evm specific widgets */ 138 snd_soc_dapm_new_controls(codec, aic3x_dapm_widgets, 139 ARRAY_SIZE(aic3x_dapm_widgets)); 140 141 /* Set up davinci-evm specific audio path audio_map */ 142 snd_soc_dapm_add_routes(codec, audio_map, ARRAY_SIZE(audio_map)); 143 144 /* not connected */ 145 snd_soc_dapm_disable_pin(codec, "MONO_LOUT"); 146 snd_soc_dapm_disable_pin(codec, "HPLCOM"); 147 snd_soc_dapm_disable_pin(codec, "HPRCOM"); 148 149 /* always connected */ 150 snd_soc_dapm_enable_pin(codec, "Headphone Jack"); 151 snd_soc_dapm_enable_pin(codec, "Line Out"); 152 snd_soc_dapm_enable_pin(codec, "Mic Jack"); 153 snd_soc_dapm_enable_pin(codec, "Line In"); 154 155 snd_soc_dapm_sync(codec); 156 157 return 0; 158} 159 160/* davinci-evm digital audio interface glue - connects codec <--> CPU */ 161static struct snd_soc_dai_link evm_dai = { 162 .name = "TLV320AIC3X", 163 .stream_name = "AIC3X", 164 .cpu_dai = &davinci_i2s_dai, 165 .codec_dai = &aic3x_dai, 166 .init = evm_aic3x_init, 167 .ops = &evm_ops, 168}; 169 170static struct snd_soc_dai_link dm365_evm_dai = { 171#ifdef CONFIG_SND_DM365_AIC3X_CODEC 172 .name = "TLV320AIC3X", 173 .stream_name = "AIC3X", 174 .cpu_dai = &davinci_i2s_dai, 175 .codec_dai = &aic3x_dai, 176 .init = evm_aic3x_init, 177 .ops = &evm_ops, 178#elif defined(CONFIG_SND_DM365_VOICE_CODEC) 179 .name = "Voice Codec - CQ93VC", 180 .stream_name = "CQ93", 181 .cpu_dai = &davinci_vcif_dai, 182 .codec_dai = &cq93vc_dai, 183#endif 184}; 185 186static struct snd_soc_dai_link dm6467_evm_dai[] = { 187 { 188 .name = "TLV320AIC3X", 189 .stream_name = "AIC3X", 190 .cpu_dai = &davinci_mcasp_dai[DAVINCI_MCASP_I2S_DAI], 191 .codec_dai = &aic3x_dai, 192 .init = evm_aic3x_init, 193 .ops = &evm_ops, 194 }, 195 { 196 .name = "McASP", 197 .stream_name = "spdif", 198 .cpu_dai = &davinci_mcasp_dai[DAVINCI_MCASP_DIT_DAI], 199 .codec_dai = &dit_stub_dai, 200 .ops = &evm_spdif_ops, 201 }, 202}; 203static struct snd_soc_dai_link da8xx_evm_dai = { 204 .name = "TLV320AIC3X", 205 .stream_name = "AIC3X", 206 .cpu_dai = &davinci_mcasp_dai[DAVINCI_MCASP_I2S_DAI], 207 .codec_dai = &aic3x_dai, 208 .init = evm_aic3x_init, 209 .ops = &evm_ops, 210}; 211 212/* davinci dm6446, dm355 evm audio machine driver */ 213static struct snd_soc_card snd_soc_card_evm = { 214 .name = "DaVinci EVM", 215 .platform = &davinci_soc_platform, 216 .dai_link = &evm_dai, 217 .num_links = 1, 218}; 219 220/* davinci dm365 evm audio machine driver */ 221static struct snd_soc_card dm365_snd_soc_card_evm = { 222 .name = "DaVinci DM365 EVM", 223 .platform = &davinci_soc_platform, 224 .dai_link = &dm365_evm_dai, 225 .num_links = 1, 226}; 227 228 229/* davinci dm6467 evm audio machine driver */ 230static struct snd_soc_card dm6467_snd_soc_card_evm = { 231 .name = "DaVinci DM6467 EVM", 232 .platform = &davinci_soc_platform, 233 .dai_link = dm6467_evm_dai, 234 .num_links = ARRAY_SIZE(dm6467_evm_dai), 235}; 236 237static struct snd_soc_card da830_snd_soc_card = { 238 .name = "DA830/OMAP-L137 EVM", 239 .dai_link = &da8xx_evm_dai, 240 .platform = &davinci_soc_platform, 241 .num_links = 1, 242}; 243 244static struct snd_soc_card da850_snd_soc_card = { 245 .name = "DA850/OMAP-L138 EVM", 246 .dai_link = &da8xx_evm_dai, 247 .platform = &davinci_soc_platform, 248 .num_links = 1, 249}; 250 251static struct aic3x_setup_data aic3x_setup; 252 253/* evm audio subsystem */ 254static struct snd_soc_device evm_snd_devdata = { 255 .card = &snd_soc_card_evm, 256 .codec_dev = &soc_codec_dev_aic3x, 257 .codec_data = &aic3x_setup, 258}; 259 260/* evm audio subsystem */ 261static struct snd_soc_device dm365_evm_snd_devdata = { 262 .card = &dm365_snd_soc_card_evm, 263#ifdef CONFIG_SND_DM365_AIC3X_CODEC 264 .codec_dev = &soc_codec_dev_aic3x, 265 .codec_data = &aic3x_setup, 266#elif defined(CONFIG_SND_DM365_VOICE_CODEC) 267 .codec_dev = &soc_codec_dev_cq93vc, 268#endif 269}; 270 271/* evm audio subsystem */ 272static struct snd_soc_device dm6467_evm_snd_devdata = { 273 .card = &dm6467_snd_soc_card_evm, 274 .codec_dev = &soc_codec_dev_aic3x, 275 .codec_data = &aic3x_setup, 276}; 277 278/* evm audio subsystem */ 279static struct snd_soc_device da830_evm_snd_devdata = { 280 .card = &da830_snd_soc_card, 281 .codec_dev = &soc_codec_dev_aic3x, 282 .codec_data = &aic3x_setup, 283}; 284 285static struct snd_soc_device da850_evm_snd_devdata = { 286 .card = &da850_snd_soc_card, 287 .codec_dev = &soc_codec_dev_aic3x, 288 .codec_data = &aic3x_setup, 289}; 290 291static struct platform_device *evm_snd_device; 292 293static int __init evm_init(void) 294{ 295 struct snd_soc_device *evm_snd_dev_data; 296 int index; 297 int ret; 298 299 if (machine_is_davinci_evm()) { 300 evm_snd_dev_data = &evm_snd_devdata; 301 index = 0; 302 } else if (machine_is_davinci_dm355_evm()) { 303 evm_snd_dev_data = &evm_snd_devdata; 304 index = 1; 305 } else if (machine_is_davinci_dm365_evm()) { 306 evm_snd_dev_data = &dm365_evm_snd_devdata; 307 index = 0; 308 } else if (machine_is_davinci_dm6467_evm()) { 309 evm_snd_dev_data = &dm6467_evm_snd_devdata; 310 index = 0; 311 } else if (machine_is_davinci_da830_evm()) { 312 evm_snd_dev_data = &da830_evm_snd_devdata; 313 index = 1; 314 } else if (machine_is_davinci_da850_evm()) { 315 evm_snd_dev_data = &da850_evm_snd_devdata; 316 index = 0; 317 } else 318 return -EINVAL; 319 320 evm_snd_device = platform_device_alloc("soc-audio", index); 321 if (!evm_snd_device) 322 return -ENOMEM; 323 324 platform_set_drvdata(evm_snd_device, evm_snd_dev_data); 325 evm_snd_dev_data->dev = &evm_snd_device->dev; 326 ret = platform_device_add(evm_snd_device); 327 if (ret) 328 platform_device_put(evm_snd_device); 329 330 return ret; 331} 332 333static void __exit evm_exit(void) 334{ 335 platform_device_unregister(evm_snd_device); 336} 337 338module_init(evm_init); 339module_exit(evm_exit); 340 341MODULE_AUTHOR("Vladimir Barinov"); 342MODULE_DESCRIPTION("TI DAVINCI EVM ASoC driver"); 343MODULE_LICENSE("GPL"); 344