1/* 2 * ASoC driver for Lyrtech SFFSDR board. 3 * 4 * Author: Hugo Villeneuve 5 * Copyright (C) 2008 Lyrtech inc 6 * 7 * Based on ASoC driver for TI DAVINCI EVM platform, original copyright follow: 8 * Copyright: (C) 2007 MontaVista Software, Inc., <source@mvista.com> 9 * 10 * This program is free software; you can redistribute it and/or modify 11 * it under the terms of the GNU General Public License version 2 as 12 * published by the Free Software Foundation. 13 */ 14 15#include <linux/module.h> 16#include <linux/moduleparam.h> 17#include <linux/timer.h> 18#include <linux/interrupt.h> 19#include <linux/platform_device.h> 20#include <linux/gpio.h> 21#include <sound/core.h> 22#include <sound/pcm.h> 23#include <sound/soc.h> 24#include <sound/soc-dapm.h> 25 26#include <asm/dma.h> 27#include <asm/mach-types.h> 28#ifdef CONFIG_SFFSDR_FPGA 29#include <asm/plat-sffsdr/sffsdr-fpga.h> 30#endif 31 32#include <mach/mcbsp.h> 33#include <mach/edma.h> 34 35#include "../codecs/pcm3008.h" 36#include "davinci-pcm.h" 37#include "davinci-i2s.h" 38 39/* 40 * CLKX and CLKR are the inputs for the Sample Rate Generator. 41 * FSX and FSR are outputs, driven by the sample Rate Generator. 42 */ 43#define AUDIO_FORMAT (SND_SOC_DAIFMT_DSP_B | \ 44 SND_SOC_DAIFMT_CBM_CFS | \ 45 SND_SOC_DAIFMT_IB_NF) 46 47static int sffsdr_hw_params(struct snd_pcm_substream *substream, 48 struct snd_pcm_hw_params *params) 49{ 50 struct snd_soc_pcm_runtime *rtd = substream->private_data; 51 struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai; 52 int fs; 53 int ret = 0; 54 55 /* Fsref can be 32000, 44100 or 48000. */ 56 fs = params_rate(params); 57 58#ifndef CONFIG_SFFSDR_FPGA 59 /* Without the FPGA module, the Fs is fixed at 44100 Hz */ 60 if (fs != 44100) { 61 pr_debug("warning: only 44.1 kHz is supported without SFFSDR FPGA module\n"); 62 return -EINVAL; 63 } 64#endif 65 66 /* set cpu DAI configuration */ 67 ret = snd_soc_dai_set_fmt(cpu_dai, AUDIO_FORMAT); 68 if (ret < 0) 69 return ret; 70 71 pr_debug("sffsdr_hw_params: rate = %d Hz\n", fs); 72 73#ifndef CONFIG_SFFSDR_FPGA 74 return 0; 75#else 76 return sffsdr_fpga_set_codec_fs(fs); 77#endif 78} 79 80static struct snd_soc_ops sffsdr_ops = { 81 .hw_params = sffsdr_hw_params, 82}; 83 84/* davinci-sffsdr digital audio interface glue - connects codec <--> CPU */ 85static struct snd_soc_dai_link sffsdr_dai = { 86 .name = "PCM3008", /* Codec name */ 87 .stream_name = "PCM3008 HiFi", 88 .cpu_dai = &davinci_i2s_dai, 89 .codec_dai = &pcm3008_dai, 90 .ops = &sffsdr_ops, 91}; 92 93/* davinci-sffsdr audio machine driver */ 94static struct snd_soc_card snd_soc_sffsdr = { 95 .name = "DaVinci SFFSDR", 96 .platform = &davinci_soc_platform, 97 .dai_link = &sffsdr_dai, 98 .num_links = 1, 99}; 100 101/* sffsdr audio private data */ 102static struct pcm3008_setup_data sffsdr_pcm3008_setup = { 103 .dem0_pin = GPIO(45), 104 .dem1_pin = GPIO(46), 105 .pdad_pin = GPIO(47), 106 .pdda_pin = GPIO(38), 107}; 108 109/* sffsdr audio subsystem */ 110static struct snd_soc_device sffsdr_snd_devdata = { 111 .card = &snd_soc_sffsdr, 112 .codec_dev = &soc_codec_dev_pcm3008, 113 .codec_data = &sffsdr_pcm3008_setup, 114}; 115 116static struct resource sffsdr_snd_resources[] = { 117 { 118 .start = DAVINCI_MCBSP_BASE, 119 .end = DAVINCI_MCBSP_BASE + SZ_8K - 1, 120 .flags = IORESOURCE_MEM, 121 }, 122}; 123 124static struct evm_snd_platform_data sffsdr_snd_data = { 125 .tx_dma_ch = DAVINCI_DMA_MCBSP_TX, 126 .rx_dma_ch = DAVINCI_DMA_MCBSP_RX, 127}; 128 129static struct platform_device *sffsdr_snd_device; 130 131static int __init sffsdr_init(void) 132{ 133 int ret; 134 135 if (!machine_is_sffsdr()) 136 return -EINVAL; 137 138 sffsdr_snd_device = platform_device_alloc("soc-audio", 0); 139 if (!sffsdr_snd_device) { 140 printk(KERN_ERR "platform device allocation failed\n"); 141 return -ENOMEM; 142 } 143 144 platform_set_drvdata(sffsdr_snd_device, &sffsdr_snd_devdata); 145 sffsdr_snd_devdata.dev = &sffsdr_snd_device->dev; 146 platform_device_add_data(sffsdr_snd_device, &sffsdr_snd_data, 147 sizeof(sffsdr_snd_data)); 148 149 ret = platform_device_add_resources(sffsdr_snd_device, 150 sffsdr_snd_resources, 151 ARRAY_SIZE(sffsdr_snd_resources)); 152 if (ret) { 153 printk(KERN_ERR "platform device add ressources failed\n"); 154 goto error; 155 } 156 157 ret = platform_device_add(sffsdr_snd_device); 158 if (ret) 159 goto error; 160 161 return ret; 162 163error: 164 platform_device_put(sffsdr_snd_device); 165 return ret; 166} 167 168static void __exit sffsdr_exit(void) 169{ 170 platform_device_unregister(sffsdr_snd_device); 171} 172 173module_init(sffsdr_init); 174module_exit(sffsdr_exit); 175 176MODULE_AUTHOR("Hugo Villeneuve"); 177MODULE_DESCRIPTION("Lyrtech SFFSDR ASoC driver"); 178MODULE_LICENSE("GPL"); 179