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 <asm/mach-types.h> 26 27#include "../codecs/tlv320aic23.h" 28#include "imx-ssi.h" 29 30#define CODEC_CLOCK 12000000 31 32static int eukrea_tlv320_hw_params(struct snd_pcm_substream *substream, 33 struct snd_pcm_hw_params *params) 34{ 35 struct snd_soc_pcm_runtime *rtd = substream->private_data; 36 struct snd_soc_dai *codec_dai = rtd->codec_dai; 37 struct snd_soc_dai *cpu_dai = rtd->cpu_dai; 38 int ret; 39 40 ret = snd_soc_dai_set_fmt(cpu_dai, SND_SOC_DAIFMT_I2S | 41 SND_SOC_DAIFMT_NB_NF | 42 SND_SOC_DAIFMT_CBM_CFM); 43 if (ret) { 44 pr_err("%s: failed set cpu dai format\n", __func__); 45 return ret; 46 } 47 48 ret = snd_soc_dai_set_fmt(codec_dai, SND_SOC_DAIFMT_I2S | 49 SND_SOC_DAIFMT_NB_NF | 50 SND_SOC_DAIFMT_CBM_CFM); 51 if (ret) { 52 pr_err("%s: failed set codec dai format\n", __func__); 53 return ret; 54 } 55 56 ret = snd_soc_dai_set_sysclk(codec_dai, 0, 57 CODEC_CLOCK, SND_SOC_CLOCK_OUT); 58 if (ret) { 59 pr_err("%s: failed setting codec sysclk\n", __func__); 60 return ret; 61 } 62 snd_soc_dai_set_tdm_slot(cpu_dai, 0xffffffc, 0xffffffc, 2, 0); 63 64 ret = snd_soc_dai_set_sysclk(cpu_dai, IMX_SSP_SYS_CLK, 0, 65 SND_SOC_CLOCK_IN); 66 if (ret) { 67 pr_err("can't set CPU system clock IMX_SSP_SYS_CLK\n"); 68 return ret; 69 } 70 71 return 0; 72} 73 74static struct snd_soc_ops eukrea_tlv320_snd_ops = { 75 .hw_params = eukrea_tlv320_hw_params, 76}; 77 78static struct snd_soc_dai_link eukrea_tlv320_dai = { 79 .name = "tlv320aic23", 80 .stream_name = "TLV320AIC23", 81 .codec_dai_name = "tlv320aic23-hifi", 82 .platform_name = "imx-fiq-pcm-audio.0", 83 .codec_name = "tlv320aic23-codec.0-001a", 84 .cpu_dai_name = "imx-ssi.0", 85 .ops = &eukrea_tlv320_snd_ops, 86}; 87 88static struct snd_soc_card eukrea_tlv320 = { 89 .name = "cpuimx-audio", 90 .dai_link = &eukrea_tlv320_dai, 91 .num_links = 1, 92}; 93 94static struct platform_device *eukrea_tlv320_snd_device; 95 96static int __init eukrea_tlv320_init(void) 97{ 98 int ret; 99 100 if (!machine_is_eukrea_cpuimx27() && !machine_is_eukrea_cpuimx25sd() 101 && !machine_is_eukrea_cpuimx35sd() 102 && !machine_is_eukrea_cpuimx51sd()) 103 /* return happy. We might run on a totally different machine */ 104 return 0; 105 106 eukrea_tlv320_snd_device = platform_device_alloc("soc-audio", -1); 107 if (!eukrea_tlv320_snd_device) 108 return -ENOMEM; 109 110 platform_set_drvdata(eukrea_tlv320_snd_device, &eukrea_tlv320); 111 ret = platform_device_add(eukrea_tlv320_snd_device); 112 113 if (ret) { 114 printk(KERN_ERR "ASoC: Platform device allocation failed\n"); 115 platform_device_put(eukrea_tlv320_snd_device); 116 } 117 118 return ret; 119} 120 121static void __exit eukrea_tlv320_exit(void) 122{ 123 platform_device_unregister(eukrea_tlv320_snd_device); 124} 125 126module_init(eukrea_tlv320_init); 127module_exit(eukrea_tlv320_exit); 128 129MODULE_AUTHOR("Eric Bénard <eric@eukrea.com>"); 130MODULE_DESCRIPTION("CPUIMX ALSA SoC driver"); 131MODULE_LICENSE("GPL"); 132