Linux Kernel  3.7.1
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
davinci-sffsdr.c
Go to the documentation of this file.
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., <[email protected]>
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 
25 #include <asm/dma.h>
26 #include <asm/mach-types.h>
27 #ifdef CONFIG_SFFSDR_FPGA
28 #include <asm/plat-sffsdr/sffsdr-fpga.h>
29 #endif
30 
31 #include <mach/edma.h>
32 
33 #include "../codecs/pcm3008.h"
34 #include "davinci-pcm.h"
35 #include "davinci-i2s.h"
36 
37 /*
38  * CLKX and CLKR are the inputs for the Sample Rate Generator.
39  * FSX and FSR are outputs, driven by the sample Rate Generator.
40  */
41 #define AUDIO_FORMAT (SND_SOC_DAIFMT_DSP_B | \
42  SND_SOC_DAIFMT_CBM_CFS | \
43  SND_SOC_DAIFMT_IB_NF)
44 
45 static int sffsdr_hw_params(struct snd_pcm_substream *substream,
46  struct snd_pcm_hw_params *params)
47 {
48  struct snd_soc_pcm_runtime *rtd = substream->private_data;
49  struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
50  int fs;
51  int ret = 0;
52 
53  /* Fsref can be 32000, 44100 or 48000. */
54  fs = params_rate(params);
55 
56 #ifndef CONFIG_SFFSDR_FPGA
57  /* Without the FPGA module, the Fs is fixed at 44100 Hz */
58  if (fs != 44100) {
59  pr_debug("warning: only 44.1 kHz is supported without SFFSDR FPGA module\n");
60  return -EINVAL;
61  }
62 #endif
63 
64  /* set cpu DAI configuration */
65  ret = snd_soc_dai_set_fmt(cpu_dai, AUDIO_FORMAT);
66  if (ret < 0)
67  return ret;
68 
69  pr_debug("sffsdr_hw_params: rate = %d Hz\n", fs);
70 
71 #ifndef CONFIG_SFFSDR_FPGA
72  return 0;
73 #else
74  return sffsdr_fpga_set_codec_fs(fs);
75 #endif
76 }
77 
78 static struct snd_soc_ops sffsdr_ops = {
79  .hw_params = sffsdr_hw_params,
80 };
81 
82 /* davinci-sffsdr digital audio interface glue - connects codec <--> CPU */
83 static struct snd_soc_dai_link sffsdr_dai = {
84  .name = "PCM3008", /* Codec name */
85  .stream_name = "PCM3008 HiFi",
86  .cpu_dai_name = "davinci-mcbsp",
87  .codec_dai_name = "pcm3008-hifi",
88  .codec_name = "pcm3008-codec",
89  .platform_name = "davinci-mcbsp",
90  .ops = &sffsdr_ops,
91 };
92 
93 /* davinci-sffsdr audio machine driver */
94 static struct snd_soc_card snd_soc_sffsdr = {
95  .name = "DaVinci SFFSDR",
96  .owner = THIS_MODULE,
97  .dai_link = &sffsdr_dai,
98  .num_links = 1,
99 };
100 
101 /* sffsdr audio private data */
102 static 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 
110  .name = "pcm3008-codec",
111  .id = 0,
112  .dev = {
113  .platform_data = &sffsdr_pcm3008_setup,
114  },
115 };
116 
117 static struct resource sffsdr_snd_resources[] = {
118  {
119  .start = DAVINCI_MCBSP_BASE,
120  .end = DAVINCI_MCBSP_BASE + SZ_8K - 1,
121  .flags = IORESOURCE_MEM,
122  },
123 };
124 
125 static struct evm_snd_platform_data sffsdr_snd_data = {
126  .tx_dma_ch = DAVINCI_DMA_MCBSP_TX,
127  .rx_dma_ch = DAVINCI_DMA_MCBSP_RX,
128 };
129 
130 static struct platform_device *sffsdr_snd_device;
131 
132 static int __init sffsdr_init(void)
133 {
134  int ret;
135 
136  if (!machine_is_sffsdr())
137  return -EINVAL;
138 
139  platform_device_register(&pcm3008_codec);
140 
141  sffsdr_snd_device = platform_device_alloc("soc-audio", 0);
142  if (!sffsdr_snd_device) {
143  printk(KERN_ERR "platform device allocation failed\n");
144  return -ENOMEM;
145  }
146 
147  platform_set_drvdata(sffsdr_snd_device, &snd_soc_sffsdr);
148  platform_device_add_data(sffsdr_snd_device, &sffsdr_snd_data,
149  sizeof(sffsdr_snd_data));
150 
151  ret = platform_device_add_resources(sffsdr_snd_device,
152  sffsdr_snd_resources,
153  ARRAY_SIZE(sffsdr_snd_resources));
154  if (ret) {
155  printk(KERN_ERR "platform device add resources failed\n");
156  goto error;
157  }
158 
159  ret = platform_device_add(sffsdr_snd_device);
160  if (ret)
161  goto error;
162 
163  return ret;
164 
165 error:
166  platform_device_put(sffsdr_snd_device);
167  return ret;
168 }
169 
170 static void __exit sffsdr_exit(void)
171 {
172  platform_device_unregister(sffsdr_snd_device);
173  platform_device_unregister(&pcm3008_codec);
174 }
175 
176 module_init(sffsdr_init);
177 module_exit(sffsdr_exit);
178 
179 MODULE_AUTHOR("Hugo Villeneuve");
180 MODULE_DESCRIPTION("Lyrtech SFFSDR ASoC driver");
181 MODULE_LICENSE("GPL");