1/* 2 * eukrea-tlv320.c -- SoC audio for eukrea_cpuimxXX in I2S mode 3 * 4 * Copyright 2010 Eric B��nard, Eukr��a Electromatique <eric@eukrea.com> 5 * 6 * based on sound/soc/s3c24xx/s3c24xx_simtec_tlv320aic23.c 7 * which is Copyright 2009 Simtec Electronics 8 * and on sound/soc/imx/phycore-ac97.c which is 9 * Copyright 2009 Sascha Hauer, Pengutronix <s.hauer@pengutronix.de> 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 18#include <linux/module.h> 19#include <linux/moduleparam.h> 20#include <linux/device.h> 21#include <linux/i2c.h> 22#include <sound/core.h> 23#include <sound/pcm.h> 24#include <sound/soc.h> 25#include <sound/soc-dapm.h> 26#include <asm/mach-types.h> 27 28#include "../codecs/tlv320aic23.h" 29#include "imx-ssi.h" 30 31#define CODEC_CLOCK 12000000 32 33static int eukrea_tlv320_hw_params(struct snd_pcm_substream *substream, 34 struct snd_pcm_hw_params *params) 35{ 36 struct snd_soc_pcm_runtime *rtd = substream->private_data; 37 struct snd_soc_dai *codec_dai = rtd->dai->codec_dai; 38 struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai; 39 int ret; 40 41 ret = snd_soc_dai_set_fmt(cpu_dai, SND_SOC_DAIFMT_I2S | 42 SND_SOC_DAIFMT_NB_NF | 43 SND_SOC_DAIFMT_CBM_CFM); 44 if (ret) { 45 pr_err("%s: failed set cpu dai format\n", __func__); 46 return ret; 47 } 48 49 ret = snd_soc_dai_set_fmt(codec_dai, SND_SOC_DAIFMT_I2S | 50 SND_SOC_DAIFMT_NB_NF | 51 SND_SOC_DAIFMT_CBM_CFM); 52 if (ret) { 53 pr_err("%s: failed set codec dai format\n", __func__); 54 return ret; 55 } 56 57 ret = snd_soc_dai_set_sysclk(codec_dai, 0, 58 CODEC_CLOCK, SND_SOC_CLOCK_OUT); 59 if (ret) { 60 pr_err("%s: failed setting codec sysclk\n", __func__); 61 return ret; 62 } 63 snd_soc_dai_set_tdm_slot(cpu_dai, 0xffffffc, 0xffffffc, 2, 0); 64 65 ret = snd_soc_dai_set_sysclk(cpu_dai, IMX_SSP_SYS_CLK, 0, 66 SND_SOC_CLOCK_IN); 67 if (ret) { 68 pr_err("can't set CPU system clock IMX_SSP_SYS_CLK\n"); 69 return ret; 70 } 71 72 return 0; 73} 74 75static struct snd_soc_ops eukrea_tlv320_snd_ops = { 76 .hw_params = eukrea_tlv320_hw_params, 77}; 78 79static struct snd_soc_dai_link eukrea_tlv320_dai = { 80 .name = "tlv320aic23", 81 .stream_name = "TLV320AIC23", 82 .codec_dai = &tlv320aic23_dai, 83 .ops = &eukrea_tlv320_snd_ops, 84}; 85 86static struct snd_soc_card eukrea_tlv320 = { 87 .name = "cpuimx-audio", 88 .platform = &imx_soc_platform, 89 .dai_link = &eukrea_tlv320_dai, 90 .num_links = 1, 91}; 92 93static struct snd_soc_device eukrea_tlv320_snd_devdata = { 94 .card = &eukrea_tlv320, 95 .codec_dev = &soc_codec_dev_tlv320aic23, 96}; 97 98static struct platform_device *eukrea_tlv320_snd_device; 99 100static int __init eukrea_tlv320_init(void) 101{ 102 int ret; 103 104 if (!machine_is_eukrea_cpuimx27() && !machine_is_eukrea_cpuimx25sd() 105 && !machine_is_eukrea_cpuimx35sd()) 106 /* return happy. We might run on a totally different machine */ 107 return 0; 108 109 eukrea_tlv320_snd_device = platform_device_alloc("soc-audio", -1); 110 if (!eukrea_tlv320_snd_device) 111 return -ENOMEM; 112 113 eukrea_tlv320_dai.cpu_dai = &imx_ssi_pcm_dai[0]; 114 115 platform_set_drvdata(eukrea_tlv320_snd_device, &eukrea_tlv320_snd_devdata); 116 eukrea_tlv320_snd_devdata.dev = &eukrea_tlv320_snd_device->dev; 117 ret = platform_device_add(eukrea_tlv320_snd_device); 118 119 if (ret) { 120 printk(KERN_ERR "ASoC: Platform device allocation failed\n"); 121 platform_device_put(eukrea_tlv320_snd_device); 122 } 123 124 return ret; 125} 126 127static void __exit eukrea_tlv320_exit(void) 128{ 129 platform_device_unregister(eukrea_tlv320_snd_device); 130} 131 132module_init(eukrea_tlv320_init); 133module_exit(eukrea_tlv320_exit); 134 135MODULE_AUTHOR("Eric B��nard <eric@eukrea.com>"); 136MODULE_DESCRIPTION("CPUIMX ALSA SoC driver"); 137MODULE_LICENSE("GPL"); 138