aboutsummaryrefslogtreecommitdiffstats
path: root/sound/soc/omap
diff options
context:
space:
mode:
Diffstat (limited to 'sound/soc/omap')
-rw-r--r--sound/soc/omap/Kconfig34
-rw-r--r--sound/soc/omap/Makefile10
-rw-r--r--sound/soc/omap/am3517evm.c202
-rw-r--r--sound/soc/omap/ams-delta.c8
-rw-r--r--sound/soc/omap/igep0020.c148
-rw-r--r--sound/soc/omap/mcpdm.c485
-rw-r--r--sound/soc/omap/mcpdm.h151
-rw-r--r--sound/soc/omap/n810.c2
-rw-r--r--sound/soc/omap/omap-mcbsp.c219
-rw-r--r--sound/soc/omap/omap-mcbsp.h4
-rw-r--r--sound/soc/omap/omap-mcpdm.c252
-rw-r--r--sound/soc/omap/omap-mcpdm.h29
-rw-r--r--sound/soc/omap/omap-pcm.c39
-rw-r--r--sound/soc/omap/omap-pcm.h4
-rw-r--r--sound/soc/omap/omap2evm.c2
-rw-r--r--sound/soc/omap/omap3beagle.c8
-rw-r--r--sound/soc/omap/omap3evm.c9
-rw-r--r--sound/soc/omap/omap3pandora.c67
-rw-r--r--sound/soc/omap/osk5912.c2
-rw-r--r--sound/soc/omap/overo.c6
-rw-r--r--sound/soc/omap/sdp3430.c8
-rw-r--r--sound/soc/omap/zoom2.c2
22 files changed, 1591 insertions, 100 deletions
diff --git a/sound/soc/omap/Kconfig b/sound/soc/omap/Kconfig
index 653a362425df..f11963c21873 100644
--- a/sound/soc/omap/Kconfig
+++ b/sound/soc/omap/Kconfig
@@ -6,6 +6,9 @@ config SND_OMAP_SOC_MCBSP
6 tristate 6 tristate
7 select OMAP_MCBSP 7 select OMAP_MCBSP
8 8
9config SND_OMAP_SOC_MCPDM
10 tristate
11
9config SND_OMAP_SOC_N810 12config SND_OMAP_SOC_N810
10 tristate "SoC Audio support for Nokia N810" 13 tristate "SoC Audio support for Nokia N810"
11 depends on SND_OMAP_SOC && MACH_NOKIA_N810 && I2C 14 depends on SND_OMAP_SOC && MACH_NOKIA_N810 && I2C
@@ -43,12 +46,13 @@ config SND_OMAP_SOC_OSK5912
43 Say Y if you want to add support for SoC audio on osk5912. 46 Say Y if you want to add support for SoC audio on osk5912.
44 47
45config SND_OMAP_SOC_OVERO 48config SND_OMAP_SOC_OVERO
46 tristate "SoC Audio support for Gumstix Overo" 49 tristate "SoC Audio support for Gumstix Overo and CompuLab CM-T35"
47 depends on TWL4030_CORE && SND_OMAP_SOC && MACH_OVERO 50 depends on TWL4030_CORE && SND_OMAP_SOC && (MACH_OVERO || MACH_CM_T35)
48 select SND_OMAP_SOC_MCBSP 51 select SND_OMAP_SOC_MCBSP
49 select SND_SOC_TWL4030 52 select SND_SOC_TWL4030
50 help 53 help
51 Say Y if you want to add support for SoC audio on the Gumstix Overo. 54 Say Y if you want to add support for SoC audio on the
55 Gumstix Overo or CompuLab CM-T35
52 56
53config SND_OMAP_SOC_OMAP2EVM 57config SND_OMAP_SOC_OMAP2EVM
54 tristate "SoC Audio support for OMAP2EVM board" 58 tristate "SoC Audio support for OMAP2EVM board"
@@ -66,6 +70,15 @@ config SND_OMAP_SOC_OMAP3EVM
66 help 70 help
67 Say Y if you want to add support for SoC audio on the omap3evm board. 71 Say Y if you want to add support for SoC audio on the omap3evm board.
68 72
73config SND_OMAP_SOC_AM3517EVM
74 tristate "SoC Audio support for OMAP3517 / AM3517 EVM"
75 depends on SND_OMAP_SOC && MACH_OMAP3517EVM && I2C
76 select SND_OMAP_SOC_MCBSP
77 select SND_SOC_TLV320AIC23
78 help
79 Say Y if you want to add support for SoC audio on the OMAP3517 / AM3517
80 EVM.
81
69config SND_OMAP_SOC_SDP3430 82config SND_OMAP_SOC_SDP3430
70 tristate "SoC Audio support for Texas Instruments SDP3430" 83 tristate "SoC Audio support for Texas Instruments SDP3430"
71 depends on TWL4030_CORE && SND_OMAP_SOC && MACH_OMAP_3430SDP 84 depends on TWL4030_CORE && SND_OMAP_SOC && MACH_OMAP_3430SDP
@@ -84,12 +97,14 @@ config SND_OMAP_SOC_OMAP3_PANDORA
84 Say Y if you want to add support for SoC audio on the OMAP3 Pandora. 97 Say Y if you want to add support for SoC audio on the OMAP3 Pandora.
85 98
86config SND_OMAP_SOC_OMAP3_BEAGLE 99config SND_OMAP_SOC_OMAP3_BEAGLE
87 tristate "SoC Audio support for OMAP3 Beagle" 100 tristate "SoC Audio support for OMAP3 Beagle and Devkit8000"
88 depends on TWL4030_CORE && SND_OMAP_SOC && MACH_OMAP3_BEAGLE 101 depends on TWL4030_CORE && SND_OMAP_SOC
102 depends on (MACH_OMAP3_BEAGLE || MACH_DEVKIT8000)
89 select SND_OMAP_SOC_MCBSP 103 select SND_OMAP_SOC_MCBSP
90 select SND_SOC_TWL4030 104 select SND_SOC_TWL4030
91 help 105 help
92 Say Y if you want to add support for SoC audio on the Beagleboard. 106 Say Y if you want to add support for SoC audio on the Beagleboard or
107 the clone Devkit8000.
93 108
94config SND_OMAP_SOC_ZOOM2 109config SND_OMAP_SOC_ZOOM2
95 tristate "SoC Audio support for Zoom2" 110 tristate "SoC Audio support for Zoom2"
@@ -99,3 +114,10 @@ config SND_OMAP_SOC_ZOOM2
99 help 114 help
100 Say Y if you want to add support for Soc audio on Zoom2 board. 115 Say Y if you want to add support for Soc audio on Zoom2 board.
101 116
117config SND_OMAP_SOC_IGEP0020
118 tristate "SoC Audio support for IGEP v2"
119 depends on TWL4030_CORE && SND_OMAP_SOC && MACH_IGEP0020
120 select SND_OMAP_SOC_MCBSP
121 select SND_SOC_TWL4030
122 help
123 Say Y if you want to add support for Soc audio on IGEP v2 board.
diff --git a/sound/soc/omap/Makefile b/sound/soc/omap/Makefile
index 02d69471dcb5..0bc00ca14b37 100644
--- a/sound/soc/omap/Makefile
+++ b/sound/soc/omap/Makefile
@@ -1,9 +1,11 @@
1# OMAP Platform Support 1# OMAP Platform Support
2snd-soc-omap-objs := omap-pcm.o 2snd-soc-omap-objs := omap-pcm.o
3snd-soc-omap-mcbsp-objs := omap-mcbsp.o 3snd-soc-omap-mcbsp-objs := omap-mcbsp.o
4snd-soc-omap-mcpdm-objs := omap-mcpdm.o mcpdm.o
4 5
5obj-$(CONFIG_SND_OMAP_SOC) += snd-soc-omap.o 6obj-$(CONFIG_SND_OMAP_SOC) += snd-soc-omap.o
6obj-$(CONFIG_SND_OMAP_SOC_MCBSP) += snd-soc-omap-mcbsp.o 7obj-$(CONFIG_SND_OMAP_SOC_MCBSP) += snd-soc-omap-mcbsp.o
8obj-$(CONFIG_SND_OMAP_SOC_MCPDM) += snd-soc-omap-mcpdm.o
7 9
8# OMAP Machine Support 10# OMAP Machine Support
9snd-soc-n810-objs := n810.o 11snd-soc-n810-objs := n810.o
@@ -12,18 +14,22 @@ snd-soc-osk5912-objs := osk5912.o
12snd-soc-overo-objs := overo.o 14snd-soc-overo-objs := overo.o
13snd-soc-omap2evm-objs := omap2evm.o 15snd-soc-omap2evm-objs := omap2evm.o
14snd-soc-omap3evm-objs := omap3evm.o 16snd-soc-omap3evm-objs := omap3evm.o
17snd-soc-am3517evm-objs := am3517evm.o
15snd-soc-sdp3430-objs := sdp3430.o 18snd-soc-sdp3430-objs := sdp3430.o
16snd-soc-omap3pandora-objs := omap3pandora.o 19snd-soc-omap3pandora-objs := omap3pandora.o
17snd-soc-omap3beagle-objs := omap3beagle.o 20snd-soc-omap3beagle-objs := omap3beagle.o
18snd-soc-zoom2-objs := zoom2.o 21snd-soc-zoom2-objs := zoom2.o
22snd-soc-igep0020-objs := igep0020.o
19 23
20obj-$(CONFIG_SND_OMAP_SOC_N810) += snd-soc-n810.o 24obj-$(CONFIG_SND_OMAP_SOC_N810) += snd-soc-n810.o
21obj-$(CONFIG_SND_OMAP_SOC_AMS_DELTA) += snd-soc-ams-delta.o 25obj-$(CONFIG_SND_OMAP_SOC_AMS_DELTA) += snd-soc-ams-delta.o
22obj-$(CONFIG_SND_OMAP_SOC_OSK5912) += snd-soc-osk5912.o 26obj-$(CONFIG_SND_OMAP_SOC_OSK5912) += snd-soc-osk5912.o
23obj-$(CONFIG_SND_OMAP_SOC_OVERO) += snd-soc-overo.o 27obj-$(CONFIG_SND_OMAP_SOC_OVERO) += snd-soc-overo.o
24obj-$(CONFIG_MACH_OMAP2EVM) += snd-soc-omap2evm.o 28obj-$(CONFIG_SND_OMAP_SOC_OMAP2EVM) += snd-soc-omap2evm.o
25obj-$(CONFIG_MACH_OMAP3EVM) += snd-soc-omap3evm.o 29obj-$(CONFIG_SND_OMAP_SOC_OMAP3EVM) += snd-soc-omap3evm.o
30obj-$(CONFIG_SND_OMAP_SOC_AM3517EVM) += snd-soc-am3517evm.o
26obj-$(CONFIG_SND_OMAP_SOC_SDP3430) += snd-soc-sdp3430.o 31obj-$(CONFIG_SND_OMAP_SOC_SDP3430) += snd-soc-sdp3430.o
27obj-$(CONFIG_SND_OMAP_SOC_OMAP3_PANDORA) += snd-soc-omap3pandora.o 32obj-$(CONFIG_SND_OMAP_SOC_OMAP3_PANDORA) += snd-soc-omap3pandora.o
28obj-$(CONFIG_SND_OMAP_SOC_OMAP3_BEAGLE) += snd-soc-omap3beagle.o 33obj-$(CONFIG_SND_OMAP_SOC_OMAP3_BEAGLE) += snd-soc-omap3beagle.o
29obj-$(CONFIG_SND_OMAP_SOC_ZOOM2) += snd-soc-zoom2.o 34obj-$(CONFIG_SND_OMAP_SOC_ZOOM2) += snd-soc-zoom2.o
35obj-$(CONFIG_SND_OMAP_SOC_IGEP0020) += snd-soc-igep0020.o
diff --git a/sound/soc/omap/am3517evm.c b/sound/soc/omap/am3517evm.c
new file mode 100644
index 000000000000..135901b2ea11
--- /dev/null
+++ b/sound/soc/omap/am3517evm.c
@@ -0,0 +1,202 @@
1/*
2 * am3517evm.c -- ALSA SoC support for OMAP3517 / AM3517 EVM
3 *
4 * Author: Anuj Aggarwal <anuj.aggarwal@ti.com>
5 *
6 * Based on sound/soc/omap/beagle.c by Steve Sakoman
7 *
8 * Copyright (C) 2009 Texas Instruments Incorporated
9 *
10 * This program is free software; you can redistribute it and/or modify it
11 * under the terms of the GNU General Public License as published by the
12 * Free Software Foundation version 2.
13 *
14 * This program is distributed "as is" WITHOUT ANY WARRANTY of any kind,
15 * whether express or implied; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17 * General Public License for more details.
18 */
19
20#include <linux/clk.h>
21#include <linux/platform_device.h>
22#include <sound/core.h>
23#include <sound/pcm.h>
24#include <sound/soc.h>
25#include <sound/soc-dapm.h>
26
27#include <asm/mach-types.h>
28#include <mach/hardware.h>
29#include <mach/gpio.h>
30#include <plat/mcbsp.h>
31
32#include "omap-mcbsp.h"
33#include "omap-pcm.h"
34
35#include "../codecs/tlv320aic23.h"
36
37#define CODEC_CLOCK 12000000
38
39static int am3517evm_hw_params(struct snd_pcm_substream *substream,
40 struct snd_pcm_hw_params *params)
41{
42 struct snd_soc_pcm_runtime *rtd = substream->private_data;
43 struct snd_soc_dai *codec_dai = rtd->dai->codec_dai;
44 struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai;
45 int ret;
46
47 /* Set codec DAI configuration */
48 ret = snd_soc_dai_set_fmt(codec_dai,
49 SND_SOC_DAIFMT_DSP_B |
50 SND_SOC_DAIFMT_NB_NF |
51 SND_SOC_DAIFMT_CBM_CFM);
52 if (ret < 0) {
53 printk(KERN_ERR "can't set codec DAI configuration\n");
54 return ret;
55 }
56
57 /* Set cpu DAI configuration */
58 ret = snd_soc_dai_set_fmt(cpu_dai,
59 SND_SOC_DAIFMT_DSP_B |
60 SND_SOC_DAIFMT_NB_NF |
61 SND_SOC_DAIFMT_CBM_CFM);
62 if (ret < 0) {
63 printk(KERN_ERR "can't set cpu DAI configuration\n");
64 return ret;
65 }
66
67 /* Set the codec system clock for DAC and ADC */
68 ret = snd_soc_dai_set_sysclk(codec_dai, 0,
69 CODEC_CLOCK, SND_SOC_CLOCK_IN);
70 if (ret < 0) {
71 printk(KERN_ERR "can't set codec system clock\n");
72 return ret;
73 }
74
75 ret = snd_soc_dai_set_sysclk(cpu_dai, OMAP_MCBSP_CLKR_SRC_CLKX, 0,
76 SND_SOC_CLOCK_IN);
77 if (ret < 0) {
78 printk(KERN_ERR "can't set CPU system clock OMAP_MCBSP_CLKR_SRC_CLKX\n");
79 return ret;
80 }
81
82 snd_soc_dai_set_sysclk(cpu_dai, OMAP_MCBSP_FSR_SRC_FSX, 0,
83 SND_SOC_CLOCK_IN);
84 if (ret < 0) {
85 printk(KERN_ERR "can't set CPU system clock OMAP_MCBSP_FSR_SRC_FSX\n");
86 return ret;
87 }
88
89 return 0;
90}
91
92static struct snd_soc_ops am3517evm_ops = {
93 .hw_params = am3517evm_hw_params,
94};
95
96/* am3517evm machine dapm widgets */
97static const struct snd_soc_dapm_widget tlv320aic23_dapm_widgets[] = {
98 SND_SOC_DAPM_HP("Line Out", NULL),
99 SND_SOC_DAPM_LINE("Line In", NULL),
100 SND_SOC_DAPM_MIC("Mic In", NULL),
101};
102
103static const struct snd_soc_dapm_route audio_map[] = {
104 /* Line Out connected to LLOUT, RLOUT */
105 {"Line Out", NULL, "LOUT"},
106 {"Line Out", NULL, "ROUT"},
107
108 {"LLINEIN", NULL, "Line In"},
109 {"RLINEIN", NULL, "Line In"},
110
111 {"MICIN", NULL, "Mic In"},
112};
113
114static int am3517evm_aic23_init(struct snd_soc_codec *codec)
115{
116 /* Add am3517-evm specific widgets */
117 snd_soc_dapm_new_controls(codec, tlv320aic23_dapm_widgets,
118 ARRAY_SIZE(tlv320aic23_dapm_widgets));
119
120 /* Set up davinci-evm specific audio path audio_map */
121 snd_soc_dapm_add_routes(codec, audio_map, ARRAY_SIZE(audio_map));
122
123 /* always connected */
124 snd_soc_dapm_enable_pin(codec, "Line Out");
125 snd_soc_dapm_enable_pin(codec, "Line In");
126 snd_soc_dapm_enable_pin(codec, "Mic In");
127
128 snd_soc_dapm_sync(codec);
129
130 return 0;
131}
132
133/* Digital audio interface glue - connects codec <--> CPU */
134static struct snd_soc_dai_link am3517evm_dai = {
135 .name = "TLV320AIC23",
136 .stream_name = "AIC23",
137 .cpu_dai = &omap_mcbsp_dai[0],
138 .codec_dai = &tlv320aic23_dai,
139 .init = am3517evm_aic23_init,
140 .ops = &am3517evm_ops,
141};
142
143/* Audio machine driver */
144static struct snd_soc_card snd_soc_am3517evm = {
145 .name = "am3517evm",
146 .platform = &omap_soc_platform,
147 .dai_link = &am3517evm_dai,
148 .num_links = 1,
149};
150
151/* Audio subsystem */
152static struct snd_soc_device am3517evm_snd_devdata = {
153 .card = &snd_soc_am3517evm,
154 .codec_dev = &soc_codec_dev_tlv320aic23,
155};
156
157static struct platform_device *am3517evm_snd_device;
158
159static int __init am3517evm_soc_init(void)
160{
161 int ret;
162
163 if (!machine_is_omap3517evm()) {
164 pr_err("Not OMAP3517 / AM3517 EVM!\n");
165 return -ENODEV;
166 }
167 pr_info("OMAP3517 / AM3517 EVM SoC init\n");
168
169 am3517evm_snd_device = platform_device_alloc("soc-audio", -1);
170 if (!am3517evm_snd_device) {
171 printk(KERN_ERR "Platform device allocation failed\n");
172 return -ENOMEM;
173 }
174
175 platform_set_drvdata(am3517evm_snd_device, &am3517evm_snd_devdata);
176 am3517evm_snd_devdata.dev = &am3517evm_snd_device->dev;
177 *(unsigned int *)am3517evm_dai.cpu_dai->private_data = 0; /* McBSP1 */
178
179 ret = platform_device_add(am3517evm_snd_device);
180 if (ret)
181 goto err1;
182
183 return 0;
184
185err1:
186 printk(KERN_ERR "Unable to add platform device\n");
187 platform_device_put(am3517evm_snd_device);
188
189 return ret;
190}
191
192static void __exit am3517evm_soc_exit(void)
193{
194 platform_device_unregister(am3517evm_snd_device);
195}
196
197module_init(am3517evm_soc_init);
198module_exit(am3517evm_soc_exit);
199
200MODULE_AUTHOR("Anuj Aggarwal <anuj.aggarwal@ti.com>");
201MODULE_DESCRIPTION("ALSA SoC OMAP3517 / AM3517 EVM");
202MODULE_LICENSE("GPL v2");
diff --git a/sound/soc/omap/ams-delta.c b/sound/soc/omap/ams-delta.c
index 5a5166ac7279..b0f618e44840 100644
--- a/sound/soc/omap/ams-delta.c
+++ b/sound/soc/omap/ams-delta.c
@@ -31,8 +31,8 @@
31 31
32#include <asm/mach-types.h> 32#include <asm/mach-types.h>
33 33
34#include <mach/board-ams-delta.h> 34#include <plat/board-ams-delta.h>
35#include <mach/mcbsp.h> 35#include <plat/mcbsp.h>
36 36
37#include "omap-mcbsp.h" 37#include "omap-mcbsp.h"
38#include "omap-pcm.h" 38#include "omap-pcm.h"
@@ -40,7 +40,7 @@
40 40
41 41
42/* Board specific DAPM widgets */ 42/* Board specific DAPM widgets */
43 const struct snd_soc_dapm_widget ams_delta_dapm_widgets[] = { 43static const struct snd_soc_dapm_widget ams_delta_dapm_widgets[] = {
44 /* Handset */ 44 /* Handset */
45 SND_SOC_DAPM_MIC("Mouthpiece", NULL), 45 SND_SOC_DAPM_MIC("Mouthpiece", NULL),
46 SND_SOC_DAPM_HP("Earpiece", NULL), 46 SND_SOC_DAPM_HP("Earpiece", NULL),
@@ -81,7 +81,7 @@ static const char *ams_delta_audio_mode[] =
81 (1 << AMS_DELTA_SPEAKER)) 81 (1 << AMS_DELTA_SPEAKER))
82#define AMS_DELTA_SPEAKERPHONE (AMS_DELTA_HANDSFREE | (1 << AMS_DELTA_AGC)) 82#define AMS_DELTA_SPEAKERPHONE (AMS_DELTA_HANDSFREE | (1 << AMS_DELTA_AGC))
83 83
84unsigned short ams_delta_audio_mode_pins[] = { 84static const unsigned short ams_delta_audio_mode_pins[] = {
85 AMS_DELTA_MIXED, 85 AMS_DELTA_MIXED,
86 AMS_DELTA_HANDSET, 86 AMS_DELTA_HANDSET,
87 AMS_DELTA_HANDSFREE, 87 AMS_DELTA_HANDSFREE,
diff --git a/sound/soc/omap/igep0020.c b/sound/soc/omap/igep0020.c
new file mode 100644
index 000000000000..3583c429f9be
--- /dev/null
+++ b/sound/soc/omap/igep0020.c
@@ -0,0 +1,148 @@
1/*
2 * igep0020.c -- SoC audio for IGEP v2
3 *
4 * Based on sound/soc/omap/overo.c by Steve Sakoman
5 *
6 * This program is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU General Public License
8 * version 2 as published by the Free Software Foundation.
9 *
10 * This program is distributed in the hope that it will be useful, but
11 * WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
18 * 02110-1301 USA
19 *
20 */
21
22#include <linux/clk.h>
23#include <linux/platform_device.h>
24#include <sound/core.h>
25#include <sound/pcm.h>
26#include <sound/soc.h>
27#include <sound/soc-dapm.h>
28
29#include <asm/mach-types.h>
30#include <mach/hardware.h>
31#include <mach/gpio.h>
32#include <plat/mcbsp.h>
33
34#include "omap-mcbsp.h"
35#include "omap-pcm.h"
36#include "../codecs/twl4030.h"
37
38static int igep2_hw_params(struct snd_pcm_substream *substream,
39 struct snd_pcm_hw_params *params)
40{
41 struct snd_soc_pcm_runtime *rtd = substream->private_data;
42 struct snd_soc_dai *codec_dai = rtd->dai->codec_dai;
43 struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai;
44 int ret;
45
46 /* Set codec DAI configuration */
47 ret = snd_soc_dai_set_fmt(codec_dai,
48 SND_SOC_DAIFMT_I2S |
49 SND_SOC_DAIFMT_NB_NF |
50 SND_SOC_DAIFMT_CBM_CFM);
51 if (ret < 0) {
52 printk(KERN_ERR "can't set codec DAI configuration\n");
53 return ret;
54 }
55
56 /* Set cpu DAI configuration */
57 ret = snd_soc_dai_set_fmt(cpu_dai,
58 SND_SOC_DAIFMT_I2S |
59 SND_SOC_DAIFMT_NB_NF |
60 SND_SOC_DAIFMT_CBM_CFM);
61 if (ret < 0) {
62 printk(KERN_ERR "can't set cpu DAI configuration\n");
63 return ret;
64 }
65
66 /* Set the codec system clock for DAC and ADC */
67 ret = snd_soc_dai_set_sysclk(codec_dai, 0, 26000000,
68 SND_SOC_CLOCK_IN);
69 if (ret < 0) {
70 printk(KERN_ERR "can't set codec system clock\n");
71 return ret;
72 }
73
74 return 0;
75}
76
77static struct snd_soc_ops igep2_ops = {
78 .hw_params = igep2_hw_params,
79};
80
81/* Digital audio interface glue - connects codec <--> CPU */
82static struct snd_soc_dai_link igep2_dai = {
83 .name = "TWL4030",
84 .stream_name = "TWL4030",
85 .cpu_dai = &omap_mcbsp_dai[0],
86 .codec_dai = &twl4030_dai[TWL4030_DAI_HIFI],
87 .ops = &igep2_ops,
88};
89
90/* Audio machine driver */
91static struct snd_soc_card snd_soc_card_igep2 = {
92 .name = "igep2",
93 .platform = &omap_soc_platform,
94 .dai_link = &igep2_dai,
95 .num_links = 1,
96};
97
98/* Audio subsystem */
99static struct snd_soc_device igep2_snd_devdata = {
100 .card = &snd_soc_card_igep2,
101 .codec_dev = &soc_codec_dev_twl4030,
102};
103
104static struct platform_device *igep2_snd_device;
105
106static int __init igep2_soc_init(void)
107{
108 int ret;
109
110 if (!machine_is_igep0020()) {
111 pr_debug("Not IGEP v2!\n");
112 return -ENODEV;
113 }
114 printk(KERN_INFO "IGEP v2 SoC init\n");
115
116 igep2_snd_device = platform_device_alloc("soc-audio", -1);
117 if (!igep2_snd_device) {
118 printk(KERN_ERR "Platform device allocation failed\n");
119 return -ENOMEM;
120 }
121
122 platform_set_drvdata(igep2_snd_device, &igep2_snd_devdata);
123 igep2_snd_devdata.dev = &igep2_snd_device->dev;
124 *(unsigned int *)igep2_dai.cpu_dai->private_data = 1; /* McBSP2 */
125
126 ret = platform_device_add(igep2_snd_device);
127 if (ret)
128 goto err1;
129
130 return 0;
131
132err1:
133 printk(KERN_ERR "Unable to add platform device\n");
134 platform_device_put(igep2_snd_device);
135
136 return ret;
137}
138module_init(igep2_soc_init);
139
140static void __exit igep2_soc_exit(void)
141{
142 platform_device_unregister(igep2_snd_device);
143}
144module_exit(igep2_soc_exit);
145
146MODULE_AUTHOR("Enric Balletbo i Serra <eballetbo@iseebcn.com>");
147MODULE_DESCRIPTION("ALSA SoC IGEP v2");
148MODULE_LICENSE("GPL");
diff --git a/sound/soc/omap/mcpdm.c b/sound/soc/omap/mcpdm.c
new file mode 100644
index 000000000000..1dab4c14874d
--- /dev/null
+++ b/sound/soc/omap/mcpdm.c
@@ -0,0 +1,485 @@
1/*
2 * mcpdm.c -- McPDM interface driver
3 *
4 * Author: Jorge Eduardo Candelaria <x0107209@ti.com>
5 * Copyright (C) 2009 - Texas Instruments, Inc.
6 *
7 * This program is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU General Public License
9 * version 2 as published by the Free Software Foundation.
10 *
11 * This program is distributed in the hope that it will be useful, but
12 * WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
19 * 02110-1301 USA
20 *
21 */
22
23#include <linux/module.h>
24#include <linux/init.h>
25#include <linux/device.h>
26#include <linux/platform_device.h>
27#include <linux/wait.h>
28#include <linux/slab.h>
29#include <linux/interrupt.h>
30#include <linux/err.h>
31#include <linux/clk.h>
32#include <linux/delay.h>
33#include <linux/io.h>
34#include <linux/irq.h>
35
36#include "mcpdm.h"
37
38static struct omap_mcpdm *mcpdm;
39
40static inline void omap_mcpdm_write(u16 reg, u32 val)
41{
42 __raw_writel(val, mcpdm->io_base + reg);
43}
44
45static inline int omap_mcpdm_read(u16 reg)
46{
47 return __raw_readl(mcpdm->io_base + reg);
48}
49
50static void omap_mcpdm_reg_dump(void)
51{
52 dev_dbg(mcpdm->dev, "***********************\n");
53 dev_dbg(mcpdm->dev, "IRQSTATUS_RAW: 0x%04x\n",
54 omap_mcpdm_read(MCPDM_IRQSTATUS_RAW));
55 dev_dbg(mcpdm->dev, "IRQSTATUS: 0x%04x\n",
56 omap_mcpdm_read(MCPDM_IRQSTATUS));
57 dev_dbg(mcpdm->dev, "IRQENABLE_SET: 0x%04x\n",
58 omap_mcpdm_read(MCPDM_IRQENABLE_SET));
59 dev_dbg(mcpdm->dev, "IRQENABLE_CLR: 0x%04x\n",
60 omap_mcpdm_read(MCPDM_IRQENABLE_CLR));
61 dev_dbg(mcpdm->dev, "IRQWAKE_EN: 0x%04x\n",
62 omap_mcpdm_read(MCPDM_IRQWAKE_EN));
63 dev_dbg(mcpdm->dev, "DMAENABLE_SET: 0x%04x\n",
64 omap_mcpdm_read(MCPDM_DMAENABLE_SET));
65 dev_dbg(mcpdm->dev, "DMAENABLE_CLR: 0x%04x\n",
66 omap_mcpdm_read(MCPDM_DMAENABLE_CLR));
67 dev_dbg(mcpdm->dev, "DMAWAKEEN: 0x%04x\n",
68 omap_mcpdm_read(MCPDM_DMAWAKEEN));
69 dev_dbg(mcpdm->dev, "CTRL: 0x%04x\n",
70 omap_mcpdm_read(MCPDM_CTRL));
71 dev_dbg(mcpdm->dev, "DN_DATA: 0x%04x\n",
72 omap_mcpdm_read(MCPDM_DN_DATA));
73 dev_dbg(mcpdm->dev, "UP_DATA: 0x%04x\n",
74 omap_mcpdm_read(MCPDM_UP_DATA));
75 dev_dbg(mcpdm->dev, "FIFO_CTRL_DN: 0x%04x\n",
76 omap_mcpdm_read(MCPDM_FIFO_CTRL_DN));
77 dev_dbg(mcpdm->dev, "FIFO_CTRL_UP: 0x%04x\n",
78 omap_mcpdm_read(MCPDM_FIFO_CTRL_UP));
79 dev_dbg(mcpdm->dev, "DN_OFFSET: 0x%04x\n",
80 omap_mcpdm_read(MCPDM_DN_OFFSET));
81 dev_dbg(mcpdm->dev, "***********************\n");
82}
83
84/*
85 * Takes the McPDM module in and out of reset state.
86 * Uplink and downlink can be reset individually.
87 */
88static void omap_mcpdm_reset_capture(int reset)
89{
90 int ctrl = omap_mcpdm_read(MCPDM_CTRL);
91
92 if (reset)
93 ctrl |= SW_UP_RST;
94 else
95 ctrl &= ~SW_UP_RST;
96
97 omap_mcpdm_write(MCPDM_CTRL, ctrl);
98}
99
100static void omap_mcpdm_reset_playback(int reset)
101{
102 int ctrl = omap_mcpdm_read(MCPDM_CTRL);
103
104 if (reset)
105 ctrl |= SW_DN_RST;
106 else
107 ctrl &= ~SW_DN_RST;
108
109 omap_mcpdm_write(MCPDM_CTRL, ctrl);
110}
111
112/*
113 * Enables the transfer through the PDM interface to/from the Phoenix
114 * codec by enabling the corresponding UP or DN channels.
115 */
116void omap_mcpdm_start(int stream)
117{
118 int ctrl = omap_mcpdm_read(MCPDM_CTRL);
119
120 if (stream)
121 ctrl |= mcpdm->up_channels;
122 else
123 ctrl |= mcpdm->dn_channels;
124
125 omap_mcpdm_write(MCPDM_CTRL, ctrl);
126}
127
128/*
129 * Disables the transfer through the PDM interface to/from the Phoenix
130 * codec by disabling the corresponding UP or DN channels.
131 */
132void omap_mcpdm_stop(int stream)
133{
134 int ctrl = omap_mcpdm_read(MCPDM_CTRL);
135
136 if (stream)
137 ctrl &= ~mcpdm->up_channels;
138 else
139 ctrl &= ~mcpdm->dn_channels;
140
141 omap_mcpdm_write(MCPDM_CTRL, ctrl);
142}
143
144/*
145 * Configures McPDM uplink for audio recording.
146 * This function should be called before omap_mcpdm_start.
147 */
148int omap_mcpdm_capture_open(struct omap_mcpdm_link *uplink)
149{
150 int irq_mask = 0;
151 int ctrl;
152
153 if (!uplink)
154 return -EINVAL;
155
156 mcpdm->uplink = uplink;
157
158 /* Enable irq request generation */
159 irq_mask |= uplink->irq_mask & MCPDM_UPLINK_IRQ_MASK;
160 omap_mcpdm_write(MCPDM_IRQENABLE_SET, irq_mask);
161
162 /* Configure uplink threshold */
163 if (uplink->threshold > UP_THRES_MAX)
164 uplink->threshold = UP_THRES_MAX;
165
166 omap_mcpdm_write(MCPDM_FIFO_CTRL_UP, uplink->threshold);
167
168 /* Configure DMA controller */
169 omap_mcpdm_write(MCPDM_DMAENABLE_SET, DMA_UP_ENABLE);
170
171 /* Set pdm out format */
172 ctrl = omap_mcpdm_read(MCPDM_CTRL);
173 ctrl &= ~PDMOUTFORMAT;
174 ctrl |= uplink->format & PDMOUTFORMAT;
175
176 /* Uplink channels */
177 mcpdm->up_channels = uplink->channels & (PDM_UP_MASK | PDM_STATUS_MASK);
178
179 omap_mcpdm_write(MCPDM_CTRL, ctrl);
180
181 return 0;
182}
183
184/*
185 * Configures McPDM downlink for audio playback.
186 * This function should be called before omap_mcpdm_start.
187 */
188int omap_mcpdm_playback_open(struct omap_mcpdm_link *downlink)
189{
190 int irq_mask = 0;
191 int ctrl;
192
193 if (!downlink)
194 return -EINVAL;
195
196 mcpdm->downlink = downlink;
197
198 /* Enable irq request generation */
199 irq_mask |= downlink->irq_mask & MCPDM_DOWNLINK_IRQ_MASK;
200 omap_mcpdm_write(MCPDM_IRQENABLE_SET, irq_mask);
201
202 /* Configure uplink threshold */
203 if (downlink->threshold > DN_THRES_MAX)
204 downlink->threshold = DN_THRES_MAX;
205
206 omap_mcpdm_write(MCPDM_FIFO_CTRL_DN, downlink->threshold);
207
208 /* Enable DMA request generation */
209 omap_mcpdm_write(MCPDM_DMAENABLE_SET, DMA_DN_ENABLE);
210
211 /* Set pdm out format */
212 ctrl = omap_mcpdm_read(MCPDM_CTRL);
213 ctrl &= ~PDMOUTFORMAT;
214 ctrl |= downlink->format & PDMOUTFORMAT;
215
216 /* Downlink channels */
217 mcpdm->dn_channels = downlink->channels & (PDM_DN_MASK | PDM_CMD_MASK);
218
219 omap_mcpdm_write(MCPDM_CTRL, ctrl);
220
221 return 0;
222}
223
224/*
225 * Cleans McPDM uplink configuration.
226 * This function should be called when the stream is closed.
227 */
228int omap_mcpdm_capture_close(struct omap_mcpdm_link *uplink)
229{
230 int irq_mask = 0;
231
232 if (!uplink)
233 return -EINVAL;
234
235 /* Disable irq request generation */
236 irq_mask |= uplink->irq_mask & MCPDM_UPLINK_IRQ_MASK;
237 omap_mcpdm_write(MCPDM_IRQENABLE_CLR, irq_mask);
238
239 /* Disable DMA request generation */
240 omap_mcpdm_write(MCPDM_DMAENABLE_CLR, DMA_UP_ENABLE);
241
242 /* Clear Downlink channels */
243 mcpdm->up_channels = 0;
244
245 mcpdm->uplink = NULL;
246
247 return 0;
248}
249
250/*
251 * Cleans McPDM downlink configuration.
252 * This function should be called when the stream is closed.
253 */
254int omap_mcpdm_playback_close(struct omap_mcpdm_link *downlink)
255{
256 int irq_mask = 0;
257
258 if (!downlink)
259 return -EINVAL;
260
261 /* Disable irq request generation */
262 irq_mask |= downlink->irq_mask & MCPDM_DOWNLINK_IRQ_MASK;
263 omap_mcpdm_write(MCPDM_IRQENABLE_CLR, irq_mask);
264
265 /* Disable DMA request generation */
266 omap_mcpdm_write(MCPDM_DMAENABLE_CLR, DMA_DN_ENABLE);
267
268 /* clear Downlink channels */
269 mcpdm->dn_channels = 0;
270
271 mcpdm->downlink = NULL;
272
273 return 0;
274}
275
276static irqreturn_t omap_mcpdm_irq_handler(int irq, void *dev_id)
277{
278 struct omap_mcpdm *mcpdm_irq = dev_id;
279 int irq_status;
280
281 irq_status = omap_mcpdm_read(MCPDM_IRQSTATUS);
282
283 /* Acknowledge irq event */
284 omap_mcpdm_write(MCPDM_IRQSTATUS, irq_status);
285
286 if (irq & MCPDM_DN_IRQ_FULL) {
287 dev_err(mcpdm_irq->dev, "DN FIFO error %x\n", irq_status);
288 omap_mcpdm_reset_playback(1);
289 omap_mcpdm_playback_open(mcpdm_irq->downlink);
290 omap_mcpdm_reset_playback(0);
291 }
292
293 if (irq & MCPDM_DN_IRQ_EMPTY) {
294 dev_err(mcpdm_irq->dev, "DN FIFO error %x\n", irq_status);
295 omap_mcpdm_reset_playback(1);
296 omap_mcpdm_playback_open(mcpdm_irq->downlink);
297 omap_mcpdm_reset_playback(0);
298 }
299
300 if (irq & MCPDM_DN_IRQ) {
301 dev_dbg(mcpdm_irq->dev, "DN write request\n");
302 }
303
304 if (irq & MCPDM_UP_IRQ_FULL) {
305 dev_err(mcpdm_irq->dev, "UP FIFO error %x\n", irq_status);
306 omap_mcpdm_reset_capture(1);
307 omap_mcpdm_capture_open(mcpdm_irq->uplink);
308 omap_mcpdm_reset_capture(0);
309 }
310
311 if (irq & MCPDM_UP_IRQ_EMPTY) {
312 dev_err(mcpdm_irq->dev, "UP FIFO error %x\n", irq_status);
313 omap_mcpdm_reset_capture(1);
314 omap_mcpdm_capture_open(mcpdm_irq->uplink);
315 omap_mcpdm_reset_capture(0);
316 }
317
318 if (irq & MCPDM_UP_IRQ) {
319 dev_dbg(mcpdm_irq->dev, "UP write request\n");
320 }
321
322 return IRQ_HANDLED;
323}
324
325int omap_mcpdm_request(void)
326{
327 int ret;
328
329 clk_enable(mcpdm->clk);
330
331 spin_lock(&mcpdm->lock);
332
333 if (!mcpdm->free) {
334 dev_err(mcpdm->dev, "McPDM interface is in use\n");
335 spin_unlock(&mcpdm->lock);
336 ret = -EBUSY;
337 goto err;
338 }
339 mcpdm->free = 0;
340
341 spin_unlock(&mcpdm->lock);
342
343 /* Disable lines while request is ongoing */
344 omap_mcpdm_write(MCPDM_CTRL, 0x00);
345
346 ret = request_irq(mcpdm->irq, omap_mcpdm_irq_handler,
347 0, "McPDM", (void *)mcpdm);
348 if (ret) {
349 dev_err(mcpdm->dev, "Request for McPDM IRQ failed\n");
350 goto err;
351 }
352
353 return 0;
354
355err:
356 clk_disable(mcpdm->clk);
357 return ret;
358}
359
360void omap_mcpdm_free(void)
361{
362 spin_lock(&mcpdm->lock);
363 if (mcpdm->free) {
364 dev_err(mcpdm->dev, "McPDM interface is already free\n");
365 spin_unlock(&mcpdm->lock);
366 return;
367 }
368 mcpdm->free = 1;
369 spin_unlock(&mcpdm->lock);
370
371 clk_disable(mcpdm->clk);
372
373 free_irq(mcpdm->irq, (void *)mcpdm);
374}
375
376/* Enable/disable DC offset cancelation for the analog
377 * headset path (PDM channels 1 and 2).
378 */
379int omap_mcpdm_set_offset(int offset1, int offset2)
380{
381 int offset;
382
383 if ((offset1 > DN_OFST_MAX) || (offset2 > DN_OFST_MAX))
384 return -EINVAL;
385
386 offset = (offset1 << DN_OFST_RX1) | (offset2 << DN_OFST_RX2);
387
388 /* offset cancellation for channel 1 */
389 if (offset1)
390 offset |= DN_OFST_RX1_EN;
391 else
392 offset &= ~DN_OFST_RX1_EN;
393
394 /* offset cancellation for channel 2 */
395 if (offset2)
396 offset |= DN_OFST_RX2_EN;
397 else
398 offset &= ~DN_OFST_RX2_EN;
399
400 omap_mcpdm_write(MCPDM_DN_OFFSET, offset);
401
402 return 0;
403}
404
405static int __devinit omap_mcpdm_probe(struct platform_device *pdev)
406{
407 struct resource *res;
408 int ret = 0;
409
410 mcpdm = kzalloc(sizeof(struct omap_mcpdm), GFP_KERNEL);
411 if (!mcpdm) {
412 ret = -ENOMEM;
413 goto exit;
414 }
415
416 res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
417 if (res == NULL) {
418 dev_err(&pdev->dev, "no resource\n");
419 goto err_resource;
420 }
421
422 spin_lock_init(&mcpdm->lock);
423 mcpdm->free = 1;
424 mcpdm->io_base = ioremap(res->start, resource_size(res));
425 if (!mcpdm->io_base) {
426 ret = -ENOMEM;
427 goto err_resource;
428 }
429
430 mcpdm->irq = platform_get_irq(pdev, 0);
431
432 mcpdm->clk = clk_get(&pdev->dev, "pdm_ck");
433 if (IS_ERR(mcpdm->clk)) {
434 ret = PTR_ERR(mcpdm->clk);
435 dev_err(&pdev->dev, "unable to get pdm_ck: %d\n", ret);
436 goto err_clk;
437 }
438
439 mcpdm->dev = &pdev->dev;
440 platform_set_drvdata(pdev, mcpdm);
441
442 return 0;
443
444err_clk:
445 iounmap(mcpdm->io_base);
446err_resource:
447 kfree(mcpdm);
448exit:
449 return ret;
450}
451
452static int __devexit omap_mcpdm_remove(struct platform_device *pdev)
453{
454 struct omap_mcpdm *mcpdm_ptr = platform_get_drvdata(pdev);
455
456 platform_set_drvdata(pdev, NULL);
457
458 clk_put(mcpdm_ptr->clk);
459
460 iounmap(mcpdm_ptr->io_base);
461
462 mcpdm_ptr->clk = NULL;
463 mcpdm_ptr->free = 0;
464 mcpdm_ptr->dev = NULL;
465
466 kfree(mcpdm_ptr);
467
468 return 0;
469}
470
471static struct platform_driver omap_mcpdm_driver = {
472 .probe = omap_mcpdm_probe,
473 .remove = __devexit_p(omap_mcpdm_remove),
474 .driver = {
475 .name = "omap-mcpdm",
476 },
477};
478
479static struct platform_device *omap_mcpdm_device;
480
481static int __init omap_mcpdm_init(void)
482{
483 return platform_driver_register(&omap_mcpdm_driver);
484}
485arch_initcall(omap_mcpdm_init);
diff --git a/sound/soc/omap/mcpdm.h b/sound/soc/omap/mcpdm.h
new file mode 100644
index 000000000000..7bb326ef0886
--- /dev/null
+++ b/sound/soc/omap/mcpdm.h
@@ -0,0 +1,151 @@
1/*
2 * mcpdm.h -- Defines for McPDM driver
3 *
4 * Author: Jorge Eduardo Candelaria <x0107209@ti.com>
5 *
6 * This program is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU General Public License
8 * version 2 as published by the Free Software Foundation.
9 *
10 * This program is distributed in the hope that it will be useful, but
11 * WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
18 * 02110-1301 USA
19 *
20 */
21
22/* McPDM registers */
23
24#define MCPDM_REVISION 0x00
25#define MCPDM_SYSCONFIG 0x10
26#define MCPDM_IRQSTATUS_RAW 0x24
27#define MCPDM_IRQSTATUS 0x28
28#define MCPDM_IRQENABLE_SET 0x2C
29#define MCPDM_IRQENABLE_CLR 0x30
30#define MCPDM_IRQWAKE_EN 0x34
31#define MCPDM_DMAENABLE_SET 0x38
32#define MCPDM_DMAENABLE_CLR 0x3C
33#define MCPDM_DMAWAKEEN 0x40
34#define MCPDM_CTRL 0x44
35#define MCPDM_DN_DATA 0x48
36#define MCPDM_UP_DATA 0x4C
37#define MCPDM_FIFO_CTRL_DN 0x50
38#define MCPDM_FIFO_CTRL_UP 0x54
39#define MCPDM_DN_OFFSET 0x58
40
41/*
42 * MCPDM_IRQ bit fields
43 * IRQSTATUS_RAW, IRQSTATUS, IRQENABLE_SET, IRQENABLE_CLR
44 */
45
46#define MCPDM_DN_IRQ (1 << 0)
47#define MCPDM_DN_IRQ_EMPTY (1 << 1)
48#define MCPDM_DN_IRQ_ALMST_EMPTY (1 << 2)
49#define MCPDM_DN_IRQ_FULL (1 << 3)
50
51#define MCPDM_UP_IRQ (1 << 8)
52#define MCPDM_UP_IRQ_EMPTY (1 << 9)
53#define MCPDM_UP_IRQ_ALMST_FULL (1 << 10)
54#define MCPDM_UP_IRQ_FULL (1 << 11)
55
56#define MCPDM_DOWNLINK_IRQ_MASK 0x00F
57#define MCPDM_UPLINK_IRQ_MASK 0xF00
58
59/*
60 * MCPDM_DMAENABLE bit fields
61 */
62
63#define DMA_DN_ENABLE 0x1
64#define DMA_UP_ENABLE 0x2
65
66/*
67 * MCPDM_CTRL bit fields
68 */
69
70#define PDM_UP1_EN 0x0001
71#define PDM_UP2_EN 0x0002
72#define PDM_UP3_EN 0x0004
73#define PDM_DN1_EN 0x0008
74#define PDM_DN2_EN 0x0010
75#define PDM_DN3_EN 0x0020
76#define PDM_DN4_EN 0x0040
77#define PDM_DN5_EN 0x0080
78#define PDMOUTFORMAT 0x0100
79#define CMD_INT 0x0200
80#define STATUS_INT 0x0400
81#define SW_UP_RST 0x0800
82#define SW_DN_RST 0x1000
83#define PDM_UP_MASK 0x007
84#define PDM_DN_MASK 0x0F8
85#define PDM_CMD_MASK 0x200
86#define PDM_STATUS_MASK 0x400
87
88
89#define PDMOUTFORMAT_LJUST (0 << 8)
90#define PDMOUTFORMAT_RJUST (1 << 8)
91
92/*
93 * MCPDM_FIFO_CTRL bit fields
94 */
95
96#define UP_THRES_MAX 0xF
97#define DN_THRES_MAX 0xF
98
99/*
100 * MCPDM_DN_OFFSET bit fields
101 */
102
103#define DN_OFST_RX1_EN 0x0001
104#define DN_OFST_RX2_EN 0x0100
105
106#define DN_OFST_RX1 1
107#define DN_OFST_RX2 9
108#define DN_OFST_MAX 0x1F
109
110#define MCPDM_UPLINK 1
111#define MCPDM_DOWNLINK 2
112
113struct omap_mcpdm_link {
114 int irq_mask;
115 int threshold;
116 int format;
117 int channels;
118};
119
120struct omap_mcpdm_platform_data {
121 unsigned long phys_base;
122 u16 irq;
123};
124
125struct omap_mcpdm {
126 struct device *dev;
127 unsigned long phys_base;
128 void __iomem *io_base;
129 u8 free;
130 int irq;
131
132 spinlock_t lock;
133 struct omap_mcpdm_platform_data *pdata;
134 struct clk *clk;
135 struct omap_mcpdm_link *downlink;
136 struct omap_mcpdm_link *uplink;
137 struct completion irq_completion;
138
139 int dn_channels;
140 int up_channels;
141};
142
143extern void omap_mcpdm_start(int stream);
144extern void omap_mcpdm_stop(int stream);
145extern int omap_mcpdm_capture_open(struct omap_mcpdm_link *uplink);
146extern int omap_mcpdm_playback_open(struct omap_mcpdm_link *downlink);
147extern int omap_mcpdm_capture_close(struct omap_mcpdm_link *uplink);
148extern int omap_mcpdm_playback_close(struct omap_mcpdm_link *downlink);
149extern int omap_mcpdm_request(void);
150extern void omap_mcpdm_free(void);
151extern int omap_mcpdm_set_offset(int offset1, int offset2);
diff --git a/sound/soc/omap/n810.c b/sound/soc/omap/n810.c
index 0a505938e42b..08e09d72790f 100644
--- a/sound/soc/omap/n810.c
+++ b/sound/soc/omap/n810.c
@@ -32,7 +32,7 @@
32#include <asm/mach-types.h> 32#include <asm/mach-types.h>
33#include <mach/hardware.h> 33#include <mach/hardware.h>
34#include <linux/gpio.h> 34#include <linux/gpio.h>
35#include <mach/mcbsp.h> 35#include <plat/mcbsp.h>
36 36
37#include "omap-mcbsp.h" 37#include "omap-mcbsp.h"
38#include "omap-pcm.h" 38#include "omap-pcm.h"
diff --git a/sound/soc/omap/omap-mcbsp.c b/sound/soc/omap/omap-mcbsp.c
index 3341f49402ca..8ad9dc901007 100644
--- a/sound/soc/omap/omap-mcbsp.c
+++ b/sound/soc/omap/omap-mcbsp.c
@@ -31,14 +31,22 @@
31#include <sound/initval.h> 31#include <sound/initval.h>
32#include <sound/soc.h> 32#include <sound/soc.h>
33 33
34#include <mach/control.h> 34#include <plat/control.h>
35#include <mach/dma.h> 35#include <plat/dma.h>
36#include <mach/mcbsp.h> 36#include <plat/mcbsp.h>
37#include "omap-mcbsp.h" 37#include "omap-mcbsp.h"
38#include "omap-pcm.h" 38#include "omap-pcm.h"
39 39
40#define OMAP_MCBSP_RATES (SNDRV_PCM_RATE_8000_96000) 40#define OMAP_MCBSP_RATES (SNDRV_PCM_RATE_8000_96000)
41 41
42#define OMAP_MCBSP_SOC_SINGLE_S16_EXT(xname, xmin, xmax, \
43 xhandler_get, xhandler_put) \
44{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, \
45 .info = omap_mcbsp_st_info_volsw, \
46 .get = xhandler_get, .put = xhandler_put, \
47 .private_value = (unsigned long) &(struct soc_mixer_control) \
48 {.min = xmin, .max = xmax} }
49
42struct omap_mcbsp_data { 50struct omap_mcbsp_data {
43 unsigned int bus_id; 51 unsigned int bus_id;
44 struct omap_mcbsp_reg_cfg regs; 52 struct omap_mcbsp_reg_cfg regs;
@@ -49,6 +57,8 @@ struct omap_mcbsp_data {
49 */ 57 */
50 int active; 58 int active;
51 int configured; 59 int configured;
60 unsigned int in_freq;
61 int clk_div;
52}; 62};
53 63
54#define to_mcbsp(priv) container_of((priv), struct omap_mcbsp_data, bus_id) 64#define to_mcbsp(priv) container_of((priv), struct omap_mcbsp_data, bus_id)
@@ -80,11 +90,11 @@ static const int omap1_dma_reqs[][2] = {};
80static const unsigned long omap1_mcbsp_port[][2] = {}; 90static const unsigned long omap1_mcbsp_port[][2] = {};
81#endif 91#endif
82 92
83#if defined(CONFIG_ARCH_OMAP24XX) || defined(CONFIG_ARCH_OMAP34XX) 93#if defined(CONFIG_ARCH_OMAP2) || defined(CONFIG_ARCH_OMAP3)
84static const int omap24xx_dma_reqs[][2] = { 94static const int omap24xx_dma_reqs[][2] = {
85 { OMAP24XX_DMA_MCBSP1_TX, OMAP24XX_DMA_MCBSP1_RX }, 95 { OMAP24XX_DMA_MCBSP1_TX, OMAP24XX_DMA_MCBSP1_RX },
86 { OMAP24XX_DMA_MCBSP2_TX, OMAP24XX_DMA_MCBSP2_RX }, 96 { OMAP24XX_DMA_MCBSP2_TX, OMAP24XX_DMA_MCBSP2_RX },
87#if defined(CONFIG_ARCH_OMAP2430) || defined(CONFIG_ARCH_OMAP34XX) 97#if defined(CONFIG_ARCH_OMAP2430) || defined(CONFIG_ARCH_OMAP3)
88 { OMAP24XX_DMA_MCBSP3_TX, OMAP24XX_DMA_MCBSP3_RX }, 98 { OMAP24XX_DMA_MCBSP3_TX, OMAP24XX_DMA_MCBSP3_RX },
89 { OMAP24XX_DMA_MCBSP4_TX, OMAP24XX_DMA_MCBSP4_RX }, 99 { OMAP24XX_DMA_MCBSP4_TX, OMAP24XX_DMA_MCBSP4_RX },
90 { OMAP24XX_DMA_MCBSP5_TX, OMAP24XX_DMA_MCBSP5_RX }, 100 { OMAP24XX_DMA_MCBSP5_TX, OMAP24XX_DMA_MCBSP5_RX },
@@ -122,7 +132,7 @@ static const unsigned long omap2430_mcbsp_port[][2] = {
122static const unsigned long omap2430_mcbsp_port[][2] = {}; 132static const unsigned long omap2430_mcbsp_port[][2] = {};
123#endif 133#endif
124 134
125#if defined(CONFIG_ARCH_OMAP34XX) 135#if defined(CONFIG_ARCH_OMAP3)
126static const unsigned long omap34xx_mcbsp_port[][2] = { 136static const unsigned long omap34xx_mcbsp_port[][2] = {
127 { OMAP34XX_MCBSP1_BASE + OMAP_MCBSP_REG_DXR, 137 { OMAP34XX_MCBSP1_BASE + OMAP_MCBSP_REG_DXR,
128 OMAP34XX_MCBSP1_BASE + OMAP_MCBSP_REG_DRR }, 138 OMAP34XX_MCBSP1_BASE + OMAP_MCBSP_REG_DRR },
@@ -257,7 +267,7 @@ static int omap_mcbsp_dai_hw_params(struct snd_pcm_substream *substream,
257 int dma, bus_id = mcbsp_data->bus_id, id = cpu_dai->id; 267 int dma, bus_id = mcbsp_data->bus_id, id = cpu_dai->id;
258 int wlen, channels, wpf, sync_mode = OMAP_DMA_SYNC_ELEMENT; 268 int wlen, channels, wpf, sync_mode = OMAP_DMA_SYNC_ELEMENT;
259 unsigned long port; 269 unsigned long port;
260 unsigned int format; 270 unsigned int format, div, framesize, master;
261 271
262 if (cpu_class_is_omap1()) { 272 if (cpu_class_is_omap1()) {
263 dma = omap1_dma_reqs[bus_id][substream->stream]; 273 dma = omap1_dma_reqs[bus_id][substream->stream];
@@ -285,7 +295,11 @@ static int omap_mcbsp_dai_hw_params(struct snd_pcm_substream *substream,
285 omap_mcbsp_dai_dma_params[id][substream->stream].dma_req = dma; 295 omap_mcbsp_dai_dma_params[id][substream->stream].dma_req = dma;
286 omap_mcbsp_dai_dma_params[id][substream->stream].port_addr = port; 296 omap_mcbsp_dai_dma_params[id][substream->stream].port_addr = port;
287 omap_mcbsp_dai_dma_params[id][substream->stream].sync_mode = sync_mode; 297 omap_mcbsp_dai_dma_params[id][substream->stream].sync_mode = sync_mode;
288 cpu_dai->dma_data = &omap_mcbsp_dai_dma_params[id][substream->stream]; 298 omap_mcbsp_dai_dma_params[id][substream->stream].data_type =
299 OMAP_DMA_DATA_TYPE_S16;
300
301 snd_soc_dai_set_dma_data(cpu_dai, substream,
302 &omap_mcbsp_dai_dma_params[id][substream->stream]);
289 303
290 if (mcbsp_data->configured) { 304 if (mcbsp_data->configured) {
291 /* McBSP already configured by another stream */ 305 /* McBSP already configured by another stream */
@@ -294,28 +308,19 @@ static int omap_mcbsp_dai_hw_params(struct snd_pcm_substream *substream,
294 308
295 format = mcbsp_data->fmt & SND_SOC_DAIFMT_FORMAT_MASK; 309 format = mcbsp_data->fmt & SND_SOC_DAIFMT_FORMAT_MASK;
296 wpf = channels = params_channels(params); 310 wpf = channels = params_channels(params);
297 switch (channels) { 311 if (channels == 2 && format == SND_SOC_DAIFMT_I2S) {
298 case 2: 312 /* Use dual-phase frames */
299 if (format == SND_SOC_DAIFMT_I2S) { 313 regs->rcr2 |= RPHASE;
300 /* Use dual-phase frames */ 314 regs->xcr2 |= XPHASE;
301 regs->rcr2 |= RPHASE; 315 /* Set 1 word per (McBSP) frame for phase1 and phase2 */
302 regs->xcr2 |= XPHASE; 316 wpf--;
303 /* Set 1 word per (McBSP) frame for phase1 and phase2 */ 317 regs->rcr2 |= RFRLEN2(wpf - 1);
304 wpf--; 318 regs->xcr2 |= XFRLEN2(wpf - 1);
305 regs->rcr2 |= RFRLEN2(wpf - 1);
306 regs->xcr2 |= XFRLEN2(wpf - 1);
307 }
308 case 1:
309 case 4:
310 /* Set word per (McBSP) frame for phase1 */
311 regs->rcr1 |= RFRLEN1(wpf - 1);
312 regs->xcr1 |= XFRLEN1(wpf - 1);
313 break;
314 default:
315 /* Unsupported number of channels */
316 return -EINVAL;
317 } 319 }
318 320
321 regs->rcr1 |= RFRLEN1(wpf - 1);
322 regs->xcr1 |= XFRLEN1(wpf - 1);
323
319 switch (params_format(params)) { 324 switch (params_format(params)) {
320 case SNDRV_PCM_FORMAT_S16_LE: 325 case SNDRV_PCM_FORMAT_S16_LE:
321 /* Set word lengths */ 326 /* Set word lengths */
@@ -330,15 +335,30 @@ static int omap_mcbsp_dai_hw_params(struct snd_pcm_substream *substream,
330 return -EINVAL; 335 return -EINVAL;
331 } 336 }
332 337
338 /* In McBSP master modes, FRAME (i.e. sample rate) is generated
339 * by _counting_ BCLKs. Calculate frame size in BCLKs */
340 master = mcbsp_data->fmt & SND_SOC_DAIFMT_MASTER_MASK;
341 if (master == SND_SOC_DAIFMT_CBS_CFS) {
342 div = mcbsp_data->clk_div ? mcbsp_data->clk_div : 1;
343 framesize = (mcbsp_data->in_freq / div) / params_rate(params);
344
345 if (framesize < wlen * channels) {
346 printk(KERN_ERR "%s: not enough bandwidth for desired rate and "
347 "channels\n", __func__);
348 return -EINVAL;
349 }
350 } else
351 framesize = wlen * channels;
352
333 /* Set FS period and length in terms of bit clock periods */ 353 /* Set FS period and length in terms of bit clock periods */
334 switch (format) { 354 switch (format) {
335 case SND_SOC_DAIFMT_I2S: 355 case SND_SOC_DAIFMT_I2S:
336 regs->srgr2 |= FPER(wlen * channels - 1); 356 regs->srgr2 |= FPER(framesize - 1);
337 regs->srgr1 |= FWID(wlen - 1); 357 regs->srgr1 |= FWID((framesize >> 1) - 1);
338 break; 358 break;
339 case SND_SOC_DAIFMT_DSP_A: 359 case SND_SOC_DAIFMT_DSP_A:
340 case SND_SOC_DAIFMT_DSP_B: 360 case SND_SOC_DAIFMT_DSP_B:
341 regs->srgr2 |= FPER(wlen * channels - 1); 361 regs->srgr2 |= FPER(framesize - 1);
342 regs->srgr1 |= FWID(0); 362 regs->srgr1 |= FWID(0);
343 break; 363 break;
344 } 364 }
@@ -454,6 +474,7 @@ static int omap_mcbsp_dai_set_clkdiv(struct snd_soc_dai *cpu_dai,
454 if (div_id != OMAP_MCBSP_CLKGDV) 474 if (div_id != OMAP_MCBSP_CLKGDV)
455 return -ENODEV; 475 return -ENODEV;
456 476
477 mcbsp_data->clk_div = div;
457 regs->srgr1 |= CLKGDV(div - 1); 478 regs->srgr1 |= CLKGDV(div - 1);
458 479
459 return 0; 480 return 0;
@@ -554,6 +575,8 @@ static int omap_mcbsp_dai_set_dai_sysclk(struct snd_soc_dai *cpu_dai,
554 struct omap_mcbsp_reg_cfg *regs = &mcbsp_data->regs; 575 struct omap_mcbsp_reg_cfg *regs = &mcbsp_data->regs;
555 int err = 0; 576 int err = 0;
556 577
578 mcbsp_data->in_freq = freq;
579
557 switch (clk_id) { 580 switch (clk_id) {
558 case OMAP_MCBSP_SYSCLK_CLK: 581 case OMAP_MCBSP_SYSCLK_CLK:
559 regs->srgr2 |= CLKSM; 582 regs->srgr2 |= CLKSM;
@@ -598,13 +621,13 @@ static struct snd_soc_dai_ops omap_mcbsp_dai_ops = {
598 .id = (link_id), \ 621 .id = (link_id), \
599 .playback = { \ 622 .playback = { \
600 .channels_min = 1, \ 623 .channels_min = 1, \
601 .channels_max = 4, \ 624 .channels_max = 16, \
602 .rates = OMAP_MCBSP_RATES, \ 625 .rates = OMAP_MCBSP_RATES, \
603 .formats = SNDRV_PCM_FMTBIT_S16_LE, \ 626 .formats = SNDRV_PCM_FMTBIT_S16_LE, \
604 }, \ 627 }, \
605 .capture = { \ 628 .capture = { \
606 .channels_min = 1, \ 629 .channels_min = 1, \
607 .channels_max = 4, \ 630 .channels_max = 16, \
608 .rates = OMAP_MCBSP_RATES, \ 631 .rates = OMAP_MCBSP_RATES, \
609 .formats = SNDRV_PCM_FMTBIT_S16_LE, \ 632 .formats = SNDRV_PCM_FMTBIT_S16_LE, \
610 }, \ 633 }, \
@@ -626,6 +649,136 @@ struct snd_soc_dai omap_mcbsp_dai[] = {
626 649
627EXPORT_SYMBOL_GPL(omap_mcbsp_dai); 650EXPORT_SYMBOL_GPL(omap_mcbsp_dai);
628 651
652int omap_mcbsp_st_info_volsw(struct snd_kcontrol *kcontrol,
653 struct snd_ctl_elem_info *uinfo)
654{
655 struct soc_mixer_control *mc =
656 (struct soc_mixer_control *)kcontrol->private_value;
657 int max = mc->max;
658 int min = mc->min;
659
660 uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
661 uinfo->count = 1;
662 uinfo->value.integer.min = min;
663 uinfo->value.integer.max = max;
664 return 0;
665}
666
667#define OMAP_MCBSP_ST_SET_CHANNEL_VOLUME(id, channel) \
668static int \
669omap_mcbsp##id##_set_st_ch##channel##_volume(struct snd_kcontrol *kc, \
670 struct snd_ctl_elem_value *uc) \
671{ \
672 struct soc_mixer_control *mc = \
673 (struct soc_mixer_control *)kc->private_value; \
674 int max = mc->max; \
675 int min = mc->min; \
676 int val = uc->value.integer.value[0]; \
677 \
678 if (val < min || val > max) \
679 return -EINVAL; \
680 \
681 /* OMAP McBSP implementation uses index values 0..4 */ \
682 return omap_st_set_chgain((id)-1, channel, val); \
683}
684
685#define OMAP_MCBSP_ST_GET_CHANNEL_VOLUME(id, channel) \
686static int \
687omap_mcbsp##id##_get_st_ch##channel##_volume(struct snd_kcontrol *kc, \
688 struct snd_ctl_elem_value *uc) \
689{ \
690 s16 chgain; \
691 \
692 if (omap_st_get_chgain((id)-1, channel, &chgain)) \
693 return -EAGAIN; \
694 \
695 uc->value.integer.value[0] = chgain; \
696 return 0; \
697}
698
699OMAP_MCBSP_ST_SET_CHANNEL_VOLUME(2, 0)
700OMAP_MCBSP_ST_SET_CHANNEL_VOLUME(2, 1)
701OMAP_MCBSP_ST_SET_CHANNEL_VOLUME(3, 0)
702OMAP_MCBSP_ST_SET_CHANNEL_VOLUME(3, 1)
703OMAP_MCBSP_ST_GET_CHANNEL_VOLUME(2, 0)
704OMAP_MCBSP_ST_GET_CHANNEL_VOLUME(2, 1)
705OMAP_MCBSP_ST_GET_CHANNEL_VOLUME(3, 0)
706OMAP_MCBSP_ST_GET_CHANNEL_VOLUME(3, 1)
707
708static int omap_mcbsp_st_put_mode(struct snd_kcontrol *kcontrol,
709 struct snd_ctl_elem_value *ucontrol)
710{
711 struct soc_mixer_control *mc =
712 (struct soc_mixer_control *)kcontrol->private_value;
713 u8 value = ucontrol->value.integer.value[0];
714
715 if (value == omap_st_is_enabled(mc->reg))
716 return 0;
717
718 if (value)
719 omap_st_enable(mc->reg);
720 else
721 omap_st_disable(mc->reg);
722
723 return 1;
724}
725
726static int omap_mcbsp_st_get_mode(struct snd_kcontrol *kcontrol,
727 struct snd_ctl_elem_value *ucontrol)
728{
729 struct soc_mixer_control *mc =
730 (struct soc_mixer_control *)kcontrol->private_value;
731
732 ucontrol->value.integer.value[0] = omap_st_is_enabled(mc->reg);
733 return 0;
734}
735
736static const struct snd_kcontrol_new omap_mcbsp2_st_controls[] = {
737 SOC_SINGLE_EXT("McBSP2 Sidetone Switch", 1, 0, 1, 0,
738 omap_mcbsp_st_get_mode, omap_mcbsp_st_put_mode),
739 OMAP_MCBSP_SOC_SINGLE_S16_EXT("McBSP2 Sidetone Channel 0 Volume",
740 -32768, 32767,
741 omap_mcbsp2_get_st_ch0_volume,
742 omap_mcbsp2_set_st_ch0_volume),
743 OMAP_MCBSP_SOC_SINGLE_S16_EXT("McBSP2 Sidetone Channel 1 Volume",
744 -32768, 32767,
745 omap_mcbsp2_get_st_ch1_volume,
746 omap_mcbsp2_set_st_ch1_volume),
747};
748
749static const struct snd_kcontrol_new omap_mcbsp3_st_controls[] = {
750 SOC_SINGLE_EXT("McBSP3 Sidetone Switch", 2, 0, 1, 0,
751 omap_mcbsp_st_get_mode, omap_mcbsp_st_put_mode),
752 OMAP_MCBSP_SOC_SINGLE_S16_EXT("McBSP3 Sidetone Channel 0 Volume",
753 -32768, 32767,
754 omap_mcbsp3_get_st_ch0_volume,
755 omap_mcbsp3_set_st_ch0_volume),
756 OMAP_MCBSP_SOC_SINGLE_S16_EXT("McBSP3 Sidetone Channel 1 Volume",
757 -32768, 32767,
758 omap_mcbsp3_get_st_ch1_volume,
759 omap_mcbsp3_set_st_ch1_volume),
760};
761
762int omap_mcbsp_st_add_controls(struct snd_soc_codec *codec, int mcbsp_id)
763{
764 if (!cpu_is_omap34xx())
765 return -ENODEV;
766
767 switch (mcbsp_id) {
768 case 1: /* McBSP 2 */
769 return snd_soc_add_controls(codec, omap_mcbsp2_st_controls,
770 ARRAY_SIZE(omap_mcbsp2_st_controls));
771 case 2: /* McBSP 3 */
772 return snd_soc_add_controls(codec, omap_mcbsp3_st_controls,
773 ARRAY_SIZE(omap_mcbsp3_st_controls));
774 default:
775 break;
776 }
777
778 return -EINVAL;
779}
780EXPORT_SYMBOL_GPL(omap_mcbsp_st_add_controls);
781
629static int __init snd_omap_mcbsp_init(void) 782static int __init snd_omap_mcbsp_init(void)
630{ 783{
631 return snd_soc_register_dais(omap_mcbsp_dai, 784 return snd_soc_register_dais(omap_mcbsp_dai,
diff --git a/sound/soc/omap/omap-mcbsp.h b/sound/soc/omap/omap-mcbsp.h
index 647d2f981ab0..6c363e5f4387 100644
--- a/sound/soc/omap/omap-mcbsp.h
+++ b/sound/soc/omap/omap-mcbsp.h
@@ -50,11 +50,13 @@ enum omap_mcbsp_div {
50#undef NUM_LINKS 50#undef NUM_LINKS
51#define NUM_LINKS 3 51#define NUM_LINKS 3
52#endif 52#endif
53#if defined(CONFIG_ARCH_OMAP2430) || defined(CONFIG_ARCH_OMAP34XX) 53#if defined(CONFIG_ARCH_OMAP2430) || defined(CONFIG_ARCH_OMAP3)
54#undef NUM_LINKS 54#undef NUM_LINKS
55#define NUM_LINKS 5 55#define NUM_LINKS 5
56#endif 56#endif
57 57
58extern struct snd_soc_dai omap_mcbsp_dai[NUM_LINKS]; 58extern struct snd_soc_dai omap_mcbsp_dai[NUM_LINKS];
59 59
60int omap_mcbsp_st_add_controls(struct snd_soc_codec *codec, int mcbsp_id);
61
60#endif 62#endif
diff --git a/sound/soc/omap/omap-mcpdm.c b/sound/soc/omap/omap-mcpdm.c
new file mode 100644
index 000000000000..b7f4f7e015f3
--- /dev/null
+++ b/sound/soc/omap/omap-mcpdm.c
@@ -0,0 +1,252 @@
1/*
2 * omap-mcpdm.c -- OMAP ALSA SoC DAI driver using McPDM port
3 *
4 * Copyright (C) 2009 Texas Instruments
5 *
6 * Author: Misael Lopez Cruz <x0052729@ti.com>
7 * Contact: Jorge Eduardo Candelaria <x0107209@ti.com>
8 * Margarita Olaya <magi.olaya@ti.com>
9 *
10 * This program is free software; you can redistribute it and/or
11 * modify it under the terms of the GNU General Public License
12 * version 2 as published by the Free Software Foundation.
13 *
14 * This program is distributed in the hope that it will be useful, but
15 * WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17 * General Public License for more details.
18 *
19 * You should have received a copy of the GNU General Public License
20 * along with this program; if not, write to the Free Software
21 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
22 * 02110-1301 USA
23 *
24 */
25
26#include <linux/init.h>
27#include <linux/module.h>
28#include <linux/device.h>
29#include <sound/core.h>
30#include <sound/pcm.h>
31#include <sound/pcm_params.h>
32#include <sound/initval.h>
33#include <sound/soc.h>
34
35#include <plat/control.h>
36#include <plat/dma.h>
37#include <plat/mcbsp.h>
38#include "mcpdm.h"
39#include "omap-mcpdm.h"
40#include "omap-pcm.h"
41
42struct omap_mcpdm_data {
43 struct omap_mcpdm_link *links;
44 int active;
45};
46
47static struct omap_mcpdm_link omap_mcpdm_links[] = {
48 /* downlink */
49 {
50 .irq_mask = MCPDM_DN_IRQ_EMPTY | MCPDM_DN_IRQ_FULL,
51 .threshold = 1,
52 .format = PDMOUTFORMAT_LJUST,
53 },
54 /* uplink */
55 {
56 .irq_mask = MCPDM_UP_IRQ_EMPTY | MCPDM_UP_IRQ_FULL,
57 .threshold = 1,
58 .format = PDMOUTFORMAT_LJUST,
59 },
60};
61
62static struct omap_mcpdm_data mcpdm_data = {
63 .links = omap_mcpdm_links,
64 .active = 0,
65};
66
67/*
68 * Stream DMA parameters
69 */
70static struct omap_pcm_dma_data omap_mcpdm_dai_dma_params[] = {
71 {
72 .name = "Audio playback",
73 .dma_req = OMAP44XX_DMA_MCPDM_DL,
74 .data_type = OMAP_DMA_DATA_TYPE_S32,
75 .sync_mode = OMAP_DMA_SYNC_PACKET,
76 .packet_size = 16,
77 .port_addr = OMAP44XX_MCPDM_L3_BASE + MCPDM_DN_DATA,
78 },
79 {
80 .name = "Audio capture",
81 .dma_req = OMAP44XX_DMA_MCPDM_UP,
82 .data_type = OMAP_DMA_DATA_TYPE_S32,
83 .sync_mode = OMAP_DMA_SYNC_PACKET,
84 .packet_size = 16,
85 .port_addr = OMAP44XX_MCPDM_L3_BASE + MCPDM_UP_DATA,
86 },
87};
88
89static int omap_mcpdm_dai_startup(struct snd_pcm_substream *substream,
90 struct snd_soc_dai *dai)
91{
92 struct snd_soc_pcm_runtime *rtd = substream->private_data;
93 struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai;
94 int err = 0;
95
96 if (!cpu_dai->active)
97 err = omap_mcpdm_request();
98
99 return err;
100}
101
102static void omap_mcpdm_dai_shutdown(struct snd_pcm_substream *substream,
103 struct snd_soc_dai *dai)
104{
105 struct snd_soc_pcm_runtime *rtd = substream->private_data;
106 struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai;
107
108 if (!cpu_dai->active)
109 omap_mcpdm_free();
110}
111
112static int omap_mcpdm_dai_trigger(struct snd_pcm_substream *substream, int cmd,
113 struct snd_soc_dai *dai)
114{
115 struct snd_soc_pcm_runtime *rtd = substream->private_data;
116 struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai;
117 struct omap_mcpdm_data *mcpdm_priv = cpu_dai->private_data;
118 int stream = substream->stream;
119 int err = 0;
120
121 switch (cmd) {
122 case SNDRV_PCM_TRIGGER_START:
123 case SNDRV_PCM_TRIGGER_RESUME:
124 case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
125 if (!mcpdm_priv->active++)
126 omap_mcpdm_start(stream);
127 break;
128
129 case SNDRV_PCM_TRIGGER_STOP:
130 case SNDRV_PCM_TRIGGER_SUSPEND:
131 case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
132 if (!--mcpdm_priv->active)
133 omap_mcpdm_stop(stream);
134 break;
135 default:
136 err = -EINVAL;
137 }
138
139 return err;
140}
141
142static int omap_mcpdm_dai_hw_params(struct snd_pcm_substream *substream,
143 struct snd_pcm_hw_params *params,
144 struct snd_soc_dai *dai)
145{
146 struct snd_soc_pcm_runtime *rtd = substream->private_data;
147 struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai;
148 struct omap_mcpdm_data *mcpdm_priv = cpu_dai->private_data;
149 struct omap_mcpdm_link *mcpdm_links = mcpdm_priv->links;
150 int stream = substream->stream;
151 int channels, err, link_mask = 0;
152
153 snd_soc_dai_set_dma_data(cpu_dai, substream,
154 &omap_mcpdm_dai_dma_params[stream]);
155
156 channels = params_channels(params);
157 switch (channels) {
158 case 4:
159 if (stream == SNDRV_PCM_STREAM_CAPTURE)
160 /* up to 2 channels for capture */
161 return -EINVAL;
162 link_mask |= 1 << 3;
163 case 3:
164 if (stream == SNDRV_PCM_STREAM_CAPTURE)
165 /* up to 2 channels for capture */
166 return -EINVAL;
167 link_mask |= 1 << 2;
168 case 2:
169 link_mask |= 1 << 1;
170 case 1:
171 link_mask |= 1 << 0;
172 break;
173 default:
174 /* unsupported number of channels */
175 return -EINVAL;
176 }
177
178 if (stream == SNDRV_PCM_STREAM_PLAYBACK) {
179 mcpdm_links[stream].channels = link_mask << 3;
180 err = omap_mcpdm_playback_open(&mcpdm_links[stream]);
181 } else {
182 mcpdm_links[stream].channels = link_mask << 0;
183 err = omap_mcpdm_capture_open(&mcpdm_links[stream]);
184 }
185
186 return err;
187}
188
189static int omap_mcpdm_dai_hw_free(struct snd_pcm_substream *substream,
190 struct snd_soc_dai *dai)
191{
192 struct snd_soc_pcm_runtime *rtd = substream->private_data;
193 struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai;
194 struct omap_mcpdm_data *mcpdm_priv = cpu_dai->private_data;
195 struct omap_mcpdm_link *mcpdm_links = mcpdm_priv->links;
196 int stream = substream->stream;
197 int err;
198
199 if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
200 err = omap_mcpdm_playback_close(&mcpdm_links[stream]);
201 else
202 err = omap_mcpdm_capture_close(&mcpdm_links[stream]);
203
204 return err;
205}
206
207static struct snd_soc_dai_ops omap_mcpdm_dai_ops = {
208 .startup = omap_mcpdm_dai_startup,
209 .shutdown = omap_mcpdm_dai_shutdown,
210 .trigger = omap_mcpdm_dai_trigger,
211 .hw_params = omap_mcpdm_dai_hw_params,
212 .hw_free = omap_mcpdm_dai_hw_free,
213};
214
215#define OMAP_MCPDM_RATES (SNDRV_PCM_RATE_88200 | SNDRV_PCM_RATE_96000)
216#define OMAP_MCPDM_FORMATS (SNDRV_PCM_FMTBIT_S32_LE)
217
218struct snd_soc_dai omap_mcpdm_dai = {
219 .name = "omap-mcpdm",
220 .id = -1,
221 .playback = {
222 .channels_min = 1,
223 .channels_max = 4,
224 .rates = OMAP_MCPDM_RATES,
225 .formats = OMAP_MCPDM_FORMATS,
226 },
227 .capture = {
228 .channels_min = 1,
229 .channels_max = 2,
230 .rates = OMAP_MCPDM_RATES,
231 .formats = OMAP_MCPDM_FORMATS,
232 },
233 .ops = &omap_mcpdm_dai_ops,
234 .private_data = &mcpdm_data,
235};
236EXPORT_SYMBOL_GPL(omap_mcpdm_dai);
237
238static int __init snd_omap_mcpdm_init(void)
239{
240 return snd_soc_register_dai(&omap_mcpdm_dai);
241}
242module_init(snd_omap_mcpdm_init);
243
244static void __exit snd_omap_mcpdm_exit(void)
245{
246 snd_soc_unregister_dai(&omap_mcpdm_dai);
247}
248module_exit(snd_omap_mcpdm_exit);
249
250MODULE_AUTHOR("Misael Lopez Cruz <x0052729@ti.com>");
251MODULE_DESCRIPTION("OMAP PDM SoC Interface");
252MODULE_LICENSE("GPL");
diff --git a/sound/soc/omap/omap-mcpdm.h b/sound/soc/omap/omap-mcpdm.h
new file mode 100644
index 000000000000..73b80d559345
--- /dev/null
+++ b/sound/soc/omap/omap-mcpdm.h
@@ -0,0 +1,29 @@
1/*
2 * omap-mcpdm.h
3 *
4 * Copyright (C) 2009 Texas Instruments
5 *
6 * Contact: Misael Lopez Cruz <x0052729@ti.com>
7 *
8 * This program is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU General Public License
10 * version 2 as published by the Free Software Foundation.
11 *
12 * This program is distributed in the hope that it will be useful, but
13 * WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
20 * 02110-1301 USA
21 *
22 */
23
24#ifndef __OMAP_MCPDM_H__
25#define __OMAP_MCPDM_H__
26
27extern struct snd_soc_dai omap_mcpdm_dai;
28
29#endif /* End of __OMAP_MCPDM_H__ */
diff --git a/sound/soc/omap/omap-pcm.c b/sound/soc/omap/omap-pcm.c
index 6a829eef2a4f..1e521904ea64 100644
--- a/sound/soc/omap/omap-pcm.c
+++ b/sound/soc/omap/omap-pcm.c
@@ -23,12 +23,13 @@
23 */ 23 */
24 24
25#include <linux/dma-mapping.h> 25#include <linux/dma-mapping.h>
26#include <linux/slab.h>
26#include <sound/core.h> 27#include <sound/core.h>
27#include <sound/pcm.h> 28#include <sound/pcm.h>
28#include <sound/pcm_params.h> 29#include <sound/pcm_params.h>
29#include <sound/soc.h> 30#include <sound/soc.h>
30 31
31#include <mach/dma.h> 32#include <plat/dma.h>
32#include "omap-pcm.h" 33#include "omap-pcm.h"
33 34
34static const struct snd_pcm_hardware omap_pcm_hardware = { 35static const struct snd_pcm_hardware omap_pcm_hardware = {
@@ -37,7 +38,8 @@ static const struct snd_pcm_hardware omap_pcm_hardware = {
37 SNDRV_PCM_INFO_INTERLEAVED | 38 SNDRV_PCM_INFO_INTERLEAVED |
38 SNDRV_PCM_INFO_PAUSE | 39 SNDRV_PCM_INFO_PAUSE |
39 SNDRV_PCM_INFO_RESUME, 40 SNDRV_PCM_INFO_RESUME,
40 .formats = SNDRV_PCM_FMTBIT_S16_LE, 41 .formats = SNDRV_PCM_FMTBIT_S16_LE |
42 SNDRV_PCM_FMTBIT_S32_LE,
41 .period_bytes_min = 32, 43 .period_bytes_min = 32,
42 .period_bytes_max = 64 * 1024, 44 .period_bytes_max = 64 * 1024,
43 .periods_min = 2, 45 .periods_min = 2,
@@ -59,12 +61,11 @@ static void omap_pcm_dma_irq(int ch, u16 stat, void *data)
59 struct omap_runtime_data *prtd = runtime->private_data; 61 struct omap_runtime_data *prtd = runtime->private_data;
60 unsigned long flags; 62 unsigned long flags;
61 63
62 if ((cpu_is_omap1510()) && 64 if ((cpu_is_omap1510())) {
63 (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)) {
64 /* 65 /*
65 * OMAP1510 doesn't fully support DMA progress counter 66 * OMAP1510 doesn't fully support DMA progress counter
66 * and there is no software emulation implemented yet, 67 * and there is no software emulation implemented yet,
67 * so have to maintain our own playback progress counter 68 * so have to maintain our own progress counters
68 * that can be used by omap_pcm_pointer() instead. 69 * that can be used by omap_pcm_pointer() instead.
69 */ 70 */
70 spin_lock_irqsave(&prtd->lock, flags); 71 spin_lock_irqsave(&prtd->lock, flags);
@@ -99,9 +100,11 @@ static int omap_pcm_hw_params(struct snd_pcm_substream *substream,
99 struct snd_pcm_runtime *runtime = substream->runtime; 100 struct snd_pcm_runtime *runtime = substream->runtime;
100 struct snd_soc_pcm_runtime *rtd = substream->private_data; 101 struct snd_soc_pcm_runtime *rtd = substream->private_data;
101 struct omap_runtime_data *prtd = runtime->private_data; 102 struct omap_runtime_data *prtd = runtime->private_data;
102 struct omap_pcm_dma_data *dma_data = rtd->dai->cpu_dai->dma_data; 103 struct omap_pcm_dma_data *dma_data;
103 int err = 0; 104 int err = 0;
104 105
106 dma_data = snd_soc_dai_get_dma_data(rtd->dai->cpu_dai, substream);
107
105 /* return if this is a bufferless transfer e.g. 108 /* return if this is a bufferless transfer e.g.
106 * codec <--> BT codec or GSM modem -- lg FIXME */ 109 * codec <--> BT codec or GSM modem -- lg FIXME */
107 if (!dma_data) 110 if (!dma_data)
@@ -149,6 +152,7 @@ static int omap_pcm_prepare(struct snd_pcm_substream *substream)
149 struct omap_runtime_data *prtd = runtime->private_data; 152 struct omap_runtime_data *prtd = runtime->private_data;
150 struct omap_pcm_dma_data *dma_data = prtd->dma_data; 153 struct omap_pcm_dma_data *dma_data = prtd->dma_data;
151 struct omap_dma_channel_params dma_params; 154 struct omap_dma_channel_params dma_params;
155 int bytes;
152 156
153 /* return if this is a bufferless transfer e.g. 157 /* return if this is a bufferless transfer e.g.
154 * codec <--> BT codec or GSM modem -- lg FIXME */ 158 * codec <--> BT codec or GSM modem -- lg FIXME */
@@ -156,11 +160,7 @@ static int omap_pcm_prepare(struct snd_pcm_substream *substream)
156 return 0; 160 return 0;
157 161
158 memset(&dma_params, 0, sizeof(dma_params)); 162 memset(&dma_params, 0, sizeof(dma_params));
159 /* 163 dma_params.data_type = dma_data->data_type;
160 * Note: Regardless of interface data formats supported by OMAP McBSP
161 * or EAC blocks, internal representation is always fixed 16-bit/sample
162 */
163 dma_params.data_type = OMAP_DMA_DATA_TYPE_S16;
164 dma_params.trigger = dma_data->dma_req; 164 dma_params.trigger = dma_data->dma_req;
165 dma_params.sync_mode = dma_data->sync_mode; 165 dma_params.sync_mode = dma_data->sync_mode;
166 if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { 166 if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
@@ -170,6 +170,7 @@ static int omap_pcm_prepare(struct snd_pcm_substream *substream)
170 dma_params.src_start = runtime->dma_addr; 170 dma_params.src_start = runtime->dma_addr;
171 dma_params.dst_start = dma_data->port_addr; 171 dma_params.dst_start = dma_data->port_addr;
172 dma_params.dst_port = OMAP_DMA_PORT_MPUI; 172 dma_params.dst_port = OMAP_DMA_PORT_MPUI;
173 dma_params.dst_fi = dma_data->packet_size;
173 } else { 174 } else {
174 dma_params.src_amode = OMAP_DMA_AMODE_CONSTANT; 175 dma_params.src_amode = OMAP_DMA_AMODE_CONSTANT;
175 dma_params.dst_amode = OMAP_DMA_AMODE_POST_INC; 176 dma_params.dst_amode = OMAP_DMA_AMODE_POST_INC;
@@ -177,6 +178,7 @@ static int omap_pcm_prepare(struct snd_pcm_substream *substream)
177 dma_params.src_start = dma_data->port_addr; 178 dma_params.src_start = dma_data->port_addr;
178 dma_params.dst_start = runtime->dma_addr; 179 dma_params.dst_start = runtime->dma_addr;
179 dma_params.src_port = OMAP_DMA_PORT_MPUI; 180 dma_params.src_port = OMAP_DMA_PORT_MPUI;
181 dma_params.src_fi = dma_data->packet_size;
180 } 182 }
181 /* 183 /*
182 * Set DMA transfer frame size equal to ALSA period size and frame 184 * Set DMA transfer frame size equal to ALSA period size and frame
@@ -184,12 +186,12 @@ static int omap_pcm_prepare(struct snd_pcm_substream *substream)
184 * we can transfer the whole ALSA buffer with single DMA transfer but 186 * we can transfer the whole ALSA buffer with single DMA transfer but
185 * still can get an interrupt at each period bounary 187 * still can get an interrupt at each period bounary
186 */ 188 */
187 dma_params.elem_count = snd_pcm_lib_period_bytes(substream) / 2; 189 bytes = snd_pcm_lib_period_bytes(substream);
190 dma_params.elem_count = bytes >> dma_data->data_type;
188 dma_params.frame_count = runtime->periods; 191 dma_params.frame_count = runtime->periods;
189 omap_set_dma_params(prtd->dma_ch, &dma_params); 192 omap_set_dma_params(prtd->dma_ch, &dma_params);
190 193
191 if ((cpu_is_omap1510()) && 194 if ((cpu_is_omap1510()))
192 (substream->stream == SNDRV_PCM_STREAM_PLAYBACK))
193 omap_enable_dma_irq(prtd->dma_ch, OMAP_DMA_FRAME_IRQ | 195 omap_enable_dma_irq(prtd->dma_ch, OMAP_DMA_FRAME_IRQ |
194 OMAP_DMA_LAST_IRQ | OMAP_DMA_BLOCK_IRQ); 196 OMAP_DMA_LAST_IRQ | OMAP_DMA_BLOCK_IRQ);
195 else 197 else
@@ -247,14 +249,15 @@ static snd_pcm_uframes_t omap_pcm_pointer(struct snd_pcm_substream *substream)
247 dma_addr_t ptr; 249 dma_addr_t ptr;
248 snd_pcm_uframes_t offset; 250 snd_pcm_uframes_t offset;
249 251
250 if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) { 252 if (cpu_is_omap1510()) {
253 offset = prtd->period_index * runtime->period_size;
254 } else if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) {
251 ptr = omap_get_dma_dst_pos(prtd->dma_ch); 255 ptr = omap_get_dma_dst_pos(prtd->dma_ch);
252 offset = bytes_to_frames(runtime, ptr - runtime->dma_addr); 256 offset = bytes_to_frames(runtime, ptr - runtime->dma_addr);
253 } else if (!(cpu_is_omap1510())) { 257 } else {
254 ptr = omap_get_dma_src_pos(prtd->dma_ch); 258 ptr = omap_get_dma_src_pos(prtd->dma_ch);
255 offset = bytes_to_frames(runtime, ptr - runtime->dma_addr); 259 offset = bytes_to_frames(runtime, ptr - runtime->dma_addr);
256 } else 260 }
257 offset = prtd->period_index * runtime->period_size;
258 261
259 if (offset >= runtime->buffer_size) 262 if (offset >= runtime->buffer_size)
260 offset = 0; 263 offset = 0;
diff --git a/sound/soc/omap/omap-pcm.h b/sound/soc/omap/omap-pcm.h
index 38a821dd4118..b19975d26907 100644
--- a/sound/soc/omap/omap-pcm.h
+++ b/sound/soc/omap/omap-pcm.h
@@ -29,8 +29,10 @@ struct omap_pcm_dma_data {
29 char *name; /* stream identifier */ 29 char *name; /* stream identifier */
30 int dma_req; /* DMA request line */ 30 int dma_req; /* DMA request line */
31 unsigned long port_addr; /* transmit/receive register */ 31 unsigned long port_addr; /* transmit/receive register */
32 int sync_mode; /* DMA sync mode */
33 void (*set_threshold)(struct snd_pcm_substream *substream); 32 void (*set_threshold)(struct snd_pcm_substream *substream);
33 int data_type; /* data type 8,16,32 */
34 int sync_mode; /* DMA sync mode */
35 int packet_size; /* packet size only in PACKET mode */
34}; 36};
35 37
36extern struct snd_soc_platform omap_soc_platform; 38extern struct snd_soc_platform omap_soc_platform;
diff --git a/sound/soc/omap/omap2evm.c b/sound/soc/omap/omap2evm.c
index 027e1a40f8a1..c7adea38274c 100644
--- a/sound/soc/omap/omap2evm.c
+++ b/sound/soc/omap/omap2evm.c
@@ -31,7 +31,7 @@
31#include <asm/mach-types.h> 31#include <asm/mach-types.h>
32#include <mach/hardware.h> 32#include <mach/hardware.h>
33#include <mach/gpio.h> 33#include <mach/gpio.h>
34#include <mach/mcbsp.h> 34#include <plat/mcbsp.h>
35 35
36#include "omap-mcbsp.h" 36#include "omap-mcbsp.h"
37#include "omap-pcm.h" 37#include "omap-pcm.h"
diff --git a/sound/soc/omap/omap3beagle.c b/sound/soc/omap/omap3beagle.c
index b0cff9f33b7e..240e0975dd6a 100644
--- a/sound/soc/omap/omap3beagle.c
+++ b/sound/soc/omap/omap3beagle.c
@@ -29,7 +29,7 @@
29#include <asm/mach-types.h> 29#include <asm/mach-types.h>
30#include <mach/hardware.h> 30#include <mach/hardware.h>
31#include <mach/gpio.h> 31#include <mach/gpio.h>
32#include <mach/mcbsp.h> 32#include <plat/mcbsp.h>
33 33
34#include "omap-mcbsp.h" 34#include "omap-mcbsp.h"
35#include "omap-pcm.h" 35#include "omap-pcm.h"
@@ -117,11 +117,11 @@ static int __init omap3beagle_soc_init(void)
117{ 117{
118 int ret; 118 int ret;
119 119
120 if (!machine_is_omap3_beagle()) { 120 if (!(machine_is_omap3_beagle() || machine_is_devkit8000())) {
121 pr_debug("Not OMAP3 Beagle!\n"); 121 pr_debug("Not OMAP3 Beagle or Devkit8000!\n");
122 return -ENODEV; 122 return -ENODEV;
123 } 123 }
124 pr_info("OMAP3 Beagle SoC init\n"); 124 pr_info("OMAP3 Beagle/Devkit8000 SoC init\n");
125 125
126 omap3beagle_snd_device = platform_device_alloc("soc-audio", -1); 126 omap3beagle_snd_device = platform_device_alloc("soc-audio", -1);
127 if (!omap3beagle_snd_device) { 127 if (!omap3beagle_snd_device) {
diff --git a/sound/soc/omap/omap3evm.c b/sound/soc/omap/omap3evm.c
index 13aa380de162..dfcb344092e4 100644
--- a/sound/soc/omap/omap3evm.c
+++ b/sound/soc/omap/omap3evm.c
@@ -27,7 +27,7 @@
27#include <asm/mach-types.h> 27#include <asm/mach-types.h>
28#include <mach/hardware.h> 28#include <mach/hardware.h>
29#include <mach/gpio.h> 29#include <mach/gpio.h>
30#include <mach/mcbsp.h> 30#include <plat/mcbsp.h>
31 31
32#include "omap-mcbsp.h" 32#include "omap-mcbsp.h"
33#include "omap-pcm.h" 33#include "omap-pcm.h"
@@ -93,10 +93,17 @@ static struct snd_soc_card snd_soc_omap3evm = {
93 .num_links = 1, 93 .num_links = 1,
94}; 94};
95 95
96/* twl4030 setup */
97static struct twl4030_setup_data twl4030_setup = {
98 .ramp_delay_value = 4,
99 .sysclk = 26000,
100};
101
96/* Audio subsystem */ 102/* Audio subsystem */
97static struct snd_soc_device omap3evm_snd_devdata = { 103static struct snd_soc_device omap3evm_snd_devdata = {
98 .card = &snd_soc_omap3evm, 104 .card = &snd_soc_omap3evm,
99 .codec_dev = &soc_codec_dev_twl4030, 105 .codec_dev = &soc_codec_dev_twl4030,
106 .codec_data = &twl4030_setup,
100}; 107};
101 108
102static struct platform_device *omap3evm_snd_device; 109static struct platform_device *omap3evm_snd_device;
diff --git a/sound/soc/omap/omap3pandora.c b/sound/soc/omap/omap3pandora.c
index 0cd06f5dd356..de10f76baded 100644
--- a/sound/soc/omap/omap3pandora.c
+++ b/sound/soc/omap/omap3pandora.c
@@ -23,6 +23,7 @@
23#include <linux/platform_device.h> 23#include <linux/platform_device.h>
24#include <linux/gpio.h> 24#include <linux/gpio.h>
25#include <linux/delay.h> 25#include <linux/delay.h>
26#include <linux/regulator/consumer.h>
26 27
27#include <sound/core.h> 28#include <sound/core.h>
28#include <sound/pcm.h> 29#include <sound/pcm.h>
@@ -40,9 +41,14 @@
40 41
41#define PREFIX "ASoC omap3pandora: " 42#define PREFIX "ASoC omap3pandora: "
42 43
43static int omap3pandora_cmn_hw_params(struct snd_soc_dai *codec_dai, 44static struct regulator *omap3pandora_dac_reg;
44 struct snd_soc_dai *cpu_dai, unsigned int fmt) 45
46static int omap3pandora_cmn_hw_params(struct snd_pcm_substream *substream,
47 struct snd_pcm_hw_params *params, unsigned int fmt)
45{ 48{
49 struct snd_soc_pcm_runtime *rtd = substream->private_data;
50 struct snd_soc_dai *codec_dai = rtd->dai->codec_dai;
51 struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai;
46 int ret; 52 int ret;
47 53
48 /* Set codec DAI configuration */ 54 /* Set codec DAI configuration */
@@ -68,8 +74,9 @@ static int omap3pandora_cmn_hw_params(struct snd_soc_dai *codec_dai,
68 } 74 }
69 75
70 /* Set McBSP clock to external */ 76 /* Set McBSP clock to external */
71 ret = snd_soc_dai_set_sysclk(cpu_dai, OMAP_MCBSP_SYSCLK_CLKS_EXT, 0, 77 ret = snd_soc_dai_set_sysclk(cpu_dai, OMAP_MCBSP_SYSCLK_CLKS_EXT,
72 SND_SOC_CLOCK_IN); 78 256 * params_rate(params),
79 SND_SOC_CLOCK_IN);
73 if (ret < 0) { 80 if (ret < 0) {
74 pr_err(PREFIX "can't set cpu system clock\n"); 81 pr_err(PREFIX "can't set cpu system clock\n");
75 return ret; 82 return ret;
@@ -87,11 +94,7 @@ static int omap3pandora_cmn_hw_params(struct snd_soc_dai *codec_dai,
87static int omap3pandora_out_hw_params(struct snd_pcm_substream *substream, 94static int omap3pandora_out_hw_params(struct snd_pcm_substream *substream,
88 struct snd_pcm_hw_params *params) 95 struct snd_pcm_hw_params *params)
89{ 96{
90 struct snd_soc_pcm_runtime *rtd = substream->private_data; 97 return omap3pandora_cmn_hw_params(substream, params,
91 struct snd_soc_dai *codec_dai = rtd->dai->codec_dai;
92 struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai;
93
94 return omap3pandora_cmn_hw_params(codec_dai, cpu_dai,
95 SND_SOC_DAIFMT_I2S | 98 SND_SOC_DAIFMT_I2S |
96 SND_SOC_DAIFMT_IB_NF | 99 SND_SOC_DAIFMT_IB_NF |
97 SND_SOC_DAIFMT_CBS_CFS); 100 SND_SOC_DAIFMT_CBS_CFS);
@@ -100,31 +103,43 @@ static int omap3pandora_out_hw_params(struct snd_pcm_substream *substream,
100static int omap3pandora_in_hw_params(struct snd_pcm_substream *substream, 103static int omap3pandora_in_hw_params(struct snd_pcm_substream *substream,
101 struct snd_pcm_hw_params *params) 104 struct snd_pcm_hw_params *params)
102{ 105{
103 struct snd_soc_pcm_runtime *rtd = substream->private_data; 106 return omap3pandora_cmn_hw_params(substream, params,
104 struct snd_soc_dai *codec_dai = rtd->dai->codec_dai;
105 struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai;
106
107 return omap3pandora_cmn_hw_params(codec_dai, cpu_dai,
108 SND_SOC_DAIFMT_I2S | 107 SND_SOC_DAIFMT_I2S |
109 SND_SOC_DAIFMT_NB_NF | 108 SND_SOC_DAIFMT_NB_NF |
110 SND_SOC_DAIFMT_CBS_CFS); 109 SND_SOC_DAIFMT_CBS_CFS);
111} 110}
112 111
113static int omap3pandora_hp_event(struct snd_soc_dapm_widget *w, 112static int omap3pandora_dac_event(struct snd_soc_dapm_widget *w,
114 struct snd_kcontrol *k, int event) 113 struct snd_kcontrol *k, int event)
115{ 114{
115 /*
116 * The PCM1773 DAC datasheet requires 1ms delay between switching
117 * VCC power on/off and /PD pin high/low
118 */
116 if (SND_SOC_DAPM_EVENT_ON(event)) { 119 if (SND_SOC_DAPM_EVENT_ON(event)) {
120 regulator_enable(omap3pandora_dac_reg);
121 mdelay(1);
117 gpio_set_value(OMAP3_PANDORA_DAC_POWER_GPIO, 1); 122 gpio_set_value(OMAP3_PANDORA_DAC_POWER_GPIO, 1);
118 gpio_set_value(OMAP3_PANDORA_AMP_POWER_GPIO, 1);
119 } else { 123 } else {
120 gpio_set_value(OMAP3_PANDORA_AMP_POWER_GPIO, 0);
121 mdelay(1);
122 gpio_set_value(OMAP3_PANDORA_DAC_POWER_GPIO, 0); 124 gpio_set_value(OMAP3_PANDORA_DAC_POWER_GPIO, 0);
125 mdelay(1);
126 regulator_disable(omap3pandora_dac_reg);
123 } 127 }
124 128
125 return 0; 129 return 0;
126} 130}
127 131
132static int omap3pandora_hp_event(struct snd_soc_dapm_widget *w,
133 struct snd_kcontrol *k, int event)
134{
135 if (SND_SOC_DAPM_EVENT_ON(event))
136 gpio_set_value(OMAP3_PANDORA_AMP_POWER_GPIO, 1);
137 else
138 gpio_set_value(OMAP3_PANDORA_AMP_POWER_GPIO, 0);
139
140 return 0;
141}
142
128/* 143/*
129 * Audio paths on Pandora board: 144 * Audio paths on Pandora board:
130 * 145 *
@@ -134,7 +149,9 @@ static int omap3pandora_hp_event(struct snd_soc_dapm_widget *w,
134 * |P| <--- TWL4030 <--------- Line In and MICs 149 * |P| <--- TWL4030 <--------- Line In and MICs
135 */ 150 */
136static const struct snd_soc_dapm_widget omap3pandora_out_dapm_widgets[] = { 151static const struct snd_soc_dapm_widget omap3pandora_out_dapm_widgets[] = {
137 SND_SOC_DAPM_DAC("PCM DAC", "HiFi Playback", SND_SOC_NOPM, 0, 0), 152 SND_SOC_DAPM_DAC_E("PCM DAC", "HiFi Playback", SND_SOC_NOPM,
153 0, 0, omap3pandora_dac_event,
154 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD),
138 SND_SOC_DAPM_PGA_E("Headphone Amplifier", SND_SOC_NOPM, 155 SND_SOC_DAPM_PGA_E("Headphone Amplifier", SND_SOC_NOPM,
139 0, 0, NULL, 0, omap3pandora_hp_event, 156 0, 0, NULL, 0, omap3pandora_hp_event,
140 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD), 157 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD),
@@ -149,6 +166,7 @@ static const struct snd_soc_dapm_widget omap3pandora_in_dapm_widgets[] = {
149}; 166};
150 167
151static const struct snd_soc_dapm_route omap3pandora_out_map[] = { 168static const struct snd_soc_dapm_route omap3pandora_out_map[] = {
169 {"PCM DAC", NULL, "APLL Enable"},
152 {"Headphone Amplifier", NULL, "PCM DAC"}, 170 {"Headphone Amplifier", NULL, "PCM DAC"},
153 {"Line Out", NULL, "PCM DAC"}, 171 {"Line Out", NULL, "PCM DAC"},
154 {"Headphone Jack", NULL, "Headphone Amplifier"}, 172 {"Headphone Jack", NULL, "Headphone Amplifier"},
@@ -309,8 +327,18 @@ static int __init omap3pandora_soc_init(void)
309 goto fail2; 327 goto fail2;
310 } 328 }
311 329
330 omap3pandora_dac_reg = regulator_get(&omap3pandora_snd_device->dev, "vcc");
331 if (IS_ERR(omap3pandora_dac_reg)) {
332 pr_err(PREFIX "Failed to get DAC regulator from %s: %ld\n",
333 dev_name(&omap3pandora_snd_device->dev),
334 PTR_ERR(omap3pandora_dac_reg));
335 goto fail3;
336 }
337
312 return 0; 338 return 0;
313 339
340fail3:
341 platform_device_del(omap3pandora_snd_device);
314fail2: 342fail2:
315 platform_device_put(omap3pandora_snd_device); 343 platform_device_put(omap3pandora_snd_device);
316fail1: 344fail1:
@@ -323,6 +351,7 @@ module_init(omap3pandora_soc_init);
323 351
324static void __exit omap3pandora_soc_exit(void) 352static void __exit omap3pandora_soc_exit(void)
325{ 353{
354 regulator_put(omap3pandora_dac_reg);
326 platform_device_unregister(omap3pandora_snd_device); 355 platform_device_unregister(omap3pandora_snd_device);
327 gpio_free(OMAP3_PANDORA_AMP_POWER_GPIO); 356 gpio_free(OMAP3_PANDORA_AMP_POWER_GPIO);
328 gpio_free(OMAP3_PANDORA_DAC_POWER_GPIO); 357 gpio_free(OMAP3_PANDORA_DAC_POWER_GPIO);
diff --git a/sound/soc/omap/osk5912.c b/sound/soc/omap/osk5912.c
index a4e149b7f0eb..498ca2e03519 100644
--- a/sound/soc/omap/osk5912.c
+++ b/sound/soc/omap/osk5912.c
@@ -31,7 +31,7 @@
31#include <asm/mach-types.h> 31#include <asm/mach-types.h>
32#include <mach/hardware.h> 32#include <mach/hardware.h>
33#include <linux/gpio.h> 33#include <linux/gpio.h>
34#include <mach/mcbsp.h> 34#include <plat/mcbsp.h>
35 35
36#include "omap-mcbsp.h" 36#include "omap-mcbsp.h"
37#include "omap-pcm.h" 37#include "omap-pcm.h"
diff --git a/sound/soc/omap/overo.c b/sound/soc/omap/overo.c
index ec4f8fd8b3a2..c25f5276ad6f 100644
--- a/sound/soc/omap/overo.c
+++ b/sound/soc/omap/overo.c
@@ -29,7 +29,7 @@
29#include <asm/mach-types.h> 29#include <asm/mach-types.h>
30#include <mach/hardware.h> 30#include <mach/hardware.h>
31#include <mach/gpio.h> 31#include <mach/gpio.h>
32#include <mach/mcbsp.h> 32#include <plat/mcbsp.h>
33 33
34#include "omap-mcbsp.h" 34#include "omap-mcbsp.h"
35#include "omap-pcm.h" 35#include "omap-pcm.h"
@@ -107,8 +107,8 @@ static int __init overo_soc_init(void)
107{ 107{
108 int ret; 108 int ret;
109 109
110 if (!machine_is_overo()) { 110 if (!(machine_is_overo() || machine_is_cm_t35())) {
111 pr_debug("Not Overo!\n"); 111 pr_debug("Incomatible machine!\n");
112 return -ENODEV; 112 return -ENODEV;
113 } 113 }
114 printk(KERN_INFO "overo SoC init\n"); 114 printk(KERN_INFO "overo SoC init\n");
diff --git a/sound/soc/omap/sdp3430.c b/sound/soc/omap/sdp3430.c
index 4a3f62d1f295..3c85c0f92823 100644
--- a/sound/soc/omap/sdp3430.c
+++ b/sound/soc/omap/sdp3430.c
@@ -24,7 +24,7 @@
24 24
25#include <linux/clk.h> 25#include <linux/clk.h>
26#include <linux/platform_device.h> 26#include <linux/platform_device.h>
27#include <linux/i2c/twl4030.h> 27#include <linux/i2c/twl.h>
28#include <sound/core.h> 28#include <sound/core.h>
29#include <sound/pcm.h> 29#include <sound/pcm.h>
30#include <sound/soc.h> 30#include <sound/soc.h>
@@ -34,7 +34,7 @@
34#include <asm/mach-types.h> 34#include <asm/mach-types.h>
35#include <mach/hardware.h> 35#include <mach/hardware.h>
36#include <mach/gpio.h> 36#include <mach/gpio.h>
37#include <mach/mcbsp.h> 37#include <plat/mcbsp.h>
38 38
39#include "omap-mcbsp.h" 39#include "omap-mcbsp.h"
40#include "omap-pcm.h" 40#include "omap-pcm.h"
@@ -321,11 +321,11 @@ static int __init sdp3430_soc_init(void)
321 *(unsigned int *)sdp3430_dai[1].cpu_dai->private_data = 2; /* McBSP3 */ 321 *(unsigned int *)sdp3430_dai[1].cpu_dai->private_data = 2; /* McBSP3 */
322 322
323 /* Set TWL4030 GPIO6 as EXTMUTE signal */ 323 /* Set TWL4030 GPIO6 as EXTMUTE signal */
324 twl4030_i2c_read_u8(TWL4030_MODULE_INTBR, &pin_mux, 324 twl_i2c_read_u8(TWL4030_MODULE_INTBR, &pin_mux,
325 TWL4030_INTBR_PMBR1); 325 TWL4030_INTBR_PMBR1);
326 pin_mux &= ~TWL4030_GPIO6_PWM0_MUTE(0x03); 326 pin_mux &= ~TWL4030_GPIO6_PWM0_MUTE(0x03);
327 pin_mux |= TWL4030_GPIO6_PWM0_MUTE(0x02); 327 pin_mux |= TWL4030_GPIO6_PWM0_MUTE(0x02);
328 twl4030_i2c_write_u8(TWL4030_MODULE_INTBR, pin_mux, 328 twl_i2c_write_u8(TWL4030_MODULE_INTBR, pin_mux,
329 TWL4030_INTBR_PMBR1); 329 TWL4030_INTBR_PMBR1);
330 330
331 ret = platform_device_add(sdp3430_snd_device); 331 ret = platform_device_add(sdp3430_snd_device);
diff --git a/sound/soc/omap/zoom2.c b/sound/soc/omap/zoom2.c
index f90b45f56220..f90a2ac888cf 100644
--- a/sound/soc/omap/zoom2.c
+++ b/sound/soc/omap/zoom2.c
@@ -29,7 +29,7 @@
29#include <asm/mach-types.h> 29#include <asm/mach-types.h>
30#include <mach/hardware.h> 30#include <mach/hardware.h>
31#include <mach/gpio.h> 31#include <mach/gpio.h>
32#include <mach/mcbsp.h> 32#include <plat/mcbsp.h>
33 33
34#include "omap-mcbsp.h" 34#include "omap-mcbsp.h"
35#include "omap-pcm.h" 35#include "omap-pcm.h"