diff options
Diffstat (limited to 'sound/soc/s3c24xx')
-rw-r--r-- | sound/soc/s3c24xx/Kconfig | 29 | ||||
-rw-r--r-- | sound/soc/s3c24xx/Makefile | 6 | ||||
-rw-r--r-- | sound/soc/s3c24xx/jive_wm8750.c | 201 | ||||
-rw-r--r-- | sound/soc/s3c24xx/neo1973_wm8753.c | 67 | ||||
-rw-r--r-- | sound/soc/s3c24xx/s3c-i2s-v2.c | 638 | ||||
-rw-r--r-- | sound/soc/s3c24xx/s3c-i2s-v2.h | 90 | ||||
-rw-r--r-- | sound/soc/s3c24xx/s3c2412-i2s.c | 622 | ||||
-rw-r--r-- | sound/soc/s3c24xx/s3c2412-i2s.h | 17 | ||||
-rw-r--r-- | sound/soc/s3c24xx/s3c2443-ac97.c | 20 | ||||
-rw-r--r-- | sound/soc/s3c24xx/s3c24xx-i2s.c | 71 | ||||
-rw-r--r-- | sound/soc/s3c24xx/s3c24xx-pcm.c | 49 | ||||
-rw-r--r-- | sound/soc/s3c24xx/s3c24xx_uda134x.c | 2 | ||||
-rw-r--r-- | sound/soc/s3c24xx/s3c64xx-i2s.c | 222 | ||||
-rw-r--r-- | sound/soc/s3c24xx/s3c64xx-i2s.h | 31 |
14 files changed, 1339 insertions, 726 deletions
diff --git a/sound/soc/s3c24xx/Kconfig b/sound/soc/s3c24xx/Kconfig index fcd03acf10f6..2f3a21eee051 100644 --- a/sound/soc/s3c24xx/Kconfig +++ b/sound/soc/s3c24xx/Kconfig | |||
@@ -1,19 +1,31 @@ | |||
1 | config SND_S3C24XX_SOC | 1 | config SND_S3C24XX_SOC |
2 | tristate "SoC Audio for the Samsung S3C24XX chips" | 2 | tristate "SoC Audio for the Samsung S3CXXXX chips" |
3 | depends on ARCH_S3C2410 | 3 | depends on ARCH_S3C2410 || ARCH_S3C64XX |
4 | help | 4 | help |
5 | Say Y or M if you want to add support for codecs attached to | 5 | Say Y or M if you want to add support for codecs attached to |
6 | the S3C24XX AC97, I2S or SSP interface. You will also need | 6 | the S3C24XX and S3C64XX AC97, I2S or SSP interface. You will |
7 | to select the audio interfaces to support below. | 7 | also need to select the audio interfaces to support below. |
8 | 8 | ||
9 | config SND_S3C24XX_SOC_I2S | 9 | config SND_S3C24XX_SOC_I2S |
10 | tristate | 10 | tristate |
11 | select S3C2410_DMA | ||
12 | |||
13 | config SND_S3C_I2SV2_SOC | ||
14 | tristate | ||
11 | 15 | ||
12 | config SND_S3C2412_SOC_I2S | 16 | config SND_S3C2412_SOC_I2S |
13 | tristate | 17 | tristate |
18 | select SND_S3C_I2SV2_SOC | ||
19 | select S3C2410_DMA | ||
20 | |||
21 | config SND_S3C64XX_SOC_I2S | ||
22 | tristate | ||
23 | select SND_S3C_I2SV2_SOC | ||
24 | select S3C64XX_DMA | ||
14 | 25 | ||
15 | config SND_S3C2443_SOC_AC97 | 26 | config SND_S3C2443_SOC_AC97 |
16 | tristate | 27 | tristate |
28 | select S3C2410_DMA | ||
17 | select AC97_BUS | 29 | select AC97_BUS |
18 | select SND_SOC_AC97_BUS | 30 | select SND_SOC_AC97_BUS |
19 | 31 | ||
@@ -26,6 +38,14 @@ config SND_S3C24XX_SOC_NEO1973_WM8753 | |||
26 | Say Y if you want to add support for SoC audio on smdk2440 | 38 | Say Y if you want to add support for SoC audio on smdk2440 |
27 | with the WM8753. | 39 | with the WM8753. |
28 | 40 | ||
41 | config SND_S3C24XX_SOC_JIVE_WM8750 | ||
42 | tristate "SoC I2S Audio support for Jive" | ||
43 | depends on SND_S3C24XX_SOC && MACH_JIVE | ||
44 | select SND_SOC_WM8750 | ||
45 | select SND_S3C2412_SOC_I2S | ||
46 | help | ||
47 | Sat Y if you want to add support for SoC audio on the Jive. | ||
48 | |||
29 | config SND_S3C24XX_SOC_SMDK2443_WM9710 | 49 | config SND_S3C24XX_SOC_SMDK2443_WM9710 |
30 | tristate "SoC AC97 Audio support for SMDK2443 - WM9710" | 50 | tristate "SoC AC97 Audio support for SMDK2443 - WM9710" |
31 | depends on SND_S3C24XX_SOC && MACH_SMDK2443 | 51 | depends on SND_S3C24XX_SOC && MACH_SMDK2443 |
@@ -48,4 +68,5 @@ config SND_S3C24XX_SOC_S3C24XX_UDA134X | |||
48 | tristate "SoC I2S Audio support UDA134X wired to a S3C24XX" | 68 | tristate "SoC I2S Audio support UDA134X wired to a S3C24XX" |
49 | depends on SND_S3C24XX_SOC | 69 | depends on SND_S3C24XX_SOC |
50 | select SND_S3C24XX_SOC_I2S | 70 | select SND_S3C24XX_SOC_I2S |
71 | select SND_SOC_L3 | ||
51 | select SND_SOC_UDA134X | 72 | select SND_SOC_UDA134X |
diff --git a/sound/soc/s3c24xx/Makefile b/sound/soc/s3c24xx/Makefile index 96b3f3f617d4..07a93a2ebe5f 100644 --- a/sound/soc/s3c24xx/Makefile +++ b/sound/soc/s3c24xx/Makefile | |||
@@ -2,19 +2,25 @@ | |||
2 | snd-soc-s3c24xx-objs := s3c24xx-pcm.o | 2 | snd-soc-s3c24xx-objs := s3c24xx-pcm.o |
3 | snd-soc-s3c24xx-i2s-objs := s3c24xx-i2s.o | 3 | snd-soc-s3c24xx-i2s-objs := s3c24xx-i2s.o |
4 | snd-soc-s3c2412-i2s-objs := s3c2412-i2s.o | 4 | snd-soc-s3c2412-i2s-objs := s3c2412-i2s.o |
5 | snd-soc-s3c64xx-i2s-objs := s3c64xx-i2s.o | ||
5 | snd-soc-s3c2443-ac97-objs := s3c2443-ac97.o | 6 | snd-soc-s3c2443-ac97-objs := s3c2443-ac97.o |
7 | snd-soc-s3c-i2s-v2-objs := s3c-i2s-v2.o | ||
6 | 8 | ||
7 | obj-$(CONFIG_SND_S3C24XX_SOC) += snd-soc-s3c24xx.o | 9 | obj-$(CONFIG_SND_S3C24XX_SOC) += snd-soc-s3c24xx.o |
8 | obj-$(CONFIG_SND_S3C24XX_SOC_I2S) += snd-soc-s3c24xx-i2s.o | 10 | obj-$(CONFIG_SND_S3C24XX_SOC_I2S) += snd-soc-s3c24xx-i2s.o |
9 | obj-$(CONFIG_SND_S3C2443_SOC_AC97) += snd-soc-s3c2443-ac97.o | 11 | obj-$(CONFIG_SND_S3C2443_SOC_AC97) += snd-soc-s3c2443-ac97.o |
10 | obj-$(CONFIG_SND_S3C2412_SOC_I2S) += snd-soc-s3c2412-i2s.o | 12 | obj-$(CONFIG_SND_S3C2412_SOC_I2S) += snd-soc-s3c2412-i2s.o |
13 | obj-$(CONFIG_SND_S3C64XX_SOC_I2S) += snd-soc-s3c64xx-i2s.o | ||
14 | obj-$(CONFIG_SND_S3C_I2SV2_SOC) += snd-soc-s3c-i2s-v2.o | ||
11 | 15 | ||
12 | # S3C24XX Machine Support | 16 | # S3C24XX Machine Support |
17 | snd-soc-jive-wm8750-objs := jive_wm8750.o | ||
13 | snd-soc-neo1973-wm8753-objs := neo1973_wm8753.o | 18 | snd-soc-neo1973-wm8753-objs := neo1973_wm8753.o |
14 | snd-soc-smdk2443-wm9710-objs := smdk2443_wm9710.o | 19 | snd-soc-smdk2443-wm9710-objs := smdk2443_wm9710.o |
15 | snd-soc-ln2440sbc-alc650-objs := ln2440sbc_alc650.o | 20 | snd-soc-ln2440sbc-alc650-objs := ln2440sbc_alc650.o |
16 | snd-soc-s3c24xx-uda134x-objs := s3c24xx_uda134x.o | 21 | snd-soc-s3c24xx-uda134x-objs := s3c24xx_uda134x.o |
17 | 22 | ||
23 | obj-$(CONFIG_SND_S3C24XX_SOC_JIVE_WM8750) += snd-soc-jive-wm8750.o | ||
18 | obj-$(CONFIG_SND_S3C24XX_SOC_NEO1973_WM8753) += snd-soc-neo1973-wm8753.o | 24 | obj-$(CONFIG_SND_S3C24XX_SOC_NEO1973_WM8753) += snd-soc-neo1973-wm8753.o |
19 | obj-$(CONFIG_SND_S3C24XX_SOC_SMDK2443_WM9710) += snd-soc-smdk2443-wm9710.o | 25 | obj-$(CONFIG_SND_S3C24XX_SOC_SMDK2443_WM9710) += snd-soc-smdk2443-wm9710.o |
20 | obj-$(CONFIG_SND_S3C24XX_SOC_LN2440SBC_ALC650) += snd-soc-ln2440sbc-alc650.o | 26 | obj-$(CONFIG_SND_S3C24XX_SOC_LN2440SBC_ALC650) += snd-soc-ln2440sbc-alc650.o |
diff --git a/sound/soc/s3c24xx/jive_wm8750.c b/sound/soc/s3c24xx/jive_wm8750.c new file mode 100644 index 000000000000..32063790d95b --- /dev/null +++ b/sound/soc/s3c24xx/jive_wm8750.c | |||
@@ -0,0 +1,201 @@ | |||
1 | /* sound/soc/s3c24xx/jive_wm8750.c | ||
2 | * | ||
3 | * Copyright 2007,2008 Simtec Electronics | ||
4 | * | ||
5 | * Based on sound/soc/pxa/spitz.c | ||
6 | * Copyright 2005 Wolfson Microelectronics PLC. | ||
7 | * Copyright 2005 Openedhand Ltd. | ||
8 | * | ||
9 | * This program is free software; you can redistribute it and/or modify | ||
10 | * it under the terms of the GNU General Public License version 2 as | ||
11 | * published by the Free Software Foundation. | ||
12 | */ | ||
13 | |||
14 | #include <linux/module.h> | ||
15 | #include <linux/moduleparam.h> | ||
16 | #include <linux/timer.h> | ||
17 | #include <linux/interrupt.h> | ||
18 | #include <linux/platform_device.h> | ||
19 | #include <linux/clk.h> | ||
20 | |||
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/mach-types.h> | ||
27 | |||
28 | #include "s3c24xx-pcm.h" | ||
29 | #include "s3c2412-i2s.h" | ||
30 | |||
31 | #include "../codecs/wm8750.h" | ||
32 | |||
33 | static const struct snd_soc_dapm_route audio_map[] = { | ||
34 | { "Headphone Jack", NULL, "LOUT1" }, | ||
35 | { "Headphone Jack", NULL, "ROUT1" }, | ||
36 | { "Internal Speaker", NULL, "LOUT2" }, | ||
37 | { "Internal Speaker", NULL, "ROUT2" }, | ||
38 | { "LINPUT1", NULL, "Line Input" }, | ||
39 | { "RINPUT1", NULL, "Line Input" }, | ||
40 | }; | ||
41 | |||
42 | static const struct snd_soc_dapm_widget wm8750_dapm_widgets[] = { | ||
43 | SND_SOC_DAPM_HP("Headphone Jack", NULL), | ||
44 | SND_SOC_DAPM_SPK("Internal Speaker", NULL), | ||
45 | SND_SOC_DAPM_LINE("Line In", NULL), | ||
46 | }; | ||
47 | |||
48 | static int jive_hw_params(struct snd_pcm_substream *substream, | ||
49 | struct snd_pcm_hw_params *params) | ||
50 | { | ||
51 | struct snd_soc_pcm_runtime *rtd = substream->private_data; | ||
52 | struct snd_soc_dai *codec_dai = rtd->dai->codec_dai; | ||
53 | struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai; | ||
54 | struct s3c_i2sv2_rate_calc div; | ||
55 | unsigned int clk = 0; | ||
56 | int ret = 0; | ||
57 | |||
58 | switch (params_rate(params)) { | ||
59 | case 8000: | ||
60 | case 16000: | ||
61 | case 48000: | ||
62 | case 96000: | ||
63 | clk = 12288000; | ||
64 | break; | ||
65 | case 11025: | ||
66 | case 22050: | ||
67 | case 44100: | ||
68 | clk = 11289600; | ||
69 | break; | ||
70 | } | ||
71 | |||
72 | s3c_i2sv2_calc_rate(&div, NULL, params_rate(params), | ||
73 | s3c2412_get_iisclk()); | ||
74 | |||
75 | /* set codec DAI configuration */ | ||
76 | ret = snd_soc_dai_set_fmt(codec_dai, SND_SOC_DAIFMT_I2S | | ||
77 | SND_SOC_DAIFMT_NB_NF | | ||
78 | SND_SOC_DAIFMT_CBS_CFS); | ||
79 | if (ret < 0) | ||
80 | return ret; | ||
81 | |||
82 | /* set cpu DAI configuration */ | ||
83 | ret = snd_soc_dai_set_fmt(cpu_dai, SND_SOC_DAIFMT_I2S | | ||
84 | SND_SOC_DAIFMT_NB_NF | | ||
85 | SND_SOC_DAIFMT_CBS_CFS); | ||
86 | if (ret < 0) | ||
87 | return ret; | ||
88 | |||
89 | /* set the codec system clock for DAC and ADC */ | ||
90 | ret = snd_soc_dai_set_sysclk(codec_dai, WM8750_SYSCLK, clk, | ||
91 | SND_SOC_CLOCK_IN); | ||
92 | if (ret < 0) | ||
93 | return ret; | ||
94 | |||
95 | ret = snd_soc_dai_set_clkdiv(cpu_dai, S3C2412_DIV_RCLK, div.fs_div); | ||
96 | if (ret < 0) | ||
97 | return ret; | ||
98 | |||
99 | ret = snd_soc_dai_set_clkdiv(cpu_dai, S3C2412_DIV_PRESCALER, | ||
100 | div.clk_div - 1); | ||
101 | if (ret < 0) | ||
102 | return ret; | ||
103 | |||
104 | return 0; | ||
105 | } | ||
106 | |||
107 | static struct snd_soc_ops jive_ops = { | ||
108 | .hw_params = jive_hw_params, | ||
109 | }; | ||
110 | |||
111 | static int jive_wm8750_init(struct snd_soc_codec *codec) | ||
112 | { | ||
113 | int err; | ||
114 | |||
115 | /* These endpoints are not being used. */ | ||
116 | snd_soc_dapm_nc_pin(codec, "LINPUT2"); | ||
117 | snd_soc_dapm_nc_pin(codec, "RINPUT2"); | ||
118 | snd_soc_dapm_nc_pin(codec, "LINPUT3"); | ||
119 | snd_soc_dapm_nc_pin(codec, "RINPUT3"); | ||
120 | snd_soc_dapm_nc_pin(codec, "OUT3"); | ||
121 | snd_soc_dapm_nc_pin(codec, "MONO"); | ||
122 | |||
123 | /* Add jive specific widgets */ | ||
124 | err = snd_soc_dapm_new_controls(codec, wm8750_dapm_widgets, | ||
125 | ARRAY_SIZE(wm8750_dapm_widgets)); | ||
126 | if (err) { | ||
127 | printk(KERN_ERR "%s: failed to add widgets (%d)\n", | ||
128 | __func__, err); | ||
129 | return err; | ||
130 | } | ||
131 | |||
132 | snd_soc_dapm_add_routes(codec, audio_map, ARRAY_SIZE(audio_map)); | ||
133 | snd_soc_dapm_sync(codec); | ||
134 | |||
135 | return 0; | ||
136 | } | ||
137 | |||
138 | static struct snd_soc_dai_link jive_dai = { | ||
139 | .name = "wm8750", | ||
140 | .stream_name = "WM8750", | ||
141 | .cpu_dai = &s3c2412_i2s_dai, | ||
142 | .codec_dai = &wm8750_dai, | ||
143 | .init = jive_wm8750_init, | ||
144 | .ops = &jive_ops, | ||
145 | }; | ||
146 | |||
147 | /* jive audio machine driver */ | ||
148 | static struct snd_soc_machine snd_soc_machine_jive = { | ||
149 | .name = "Jive", | ||
150 | .dai_link = &jive_dai, | ||
151 | .num_links = 1, | ||
152 | }; | ||
153 | |||
154 | /* jive audio private data */ | ||
155 | static struct wm8750_setup_data jive_wm8750_setup = { | ||
156 | }; | ||
157 | |||
158 | /* jive audio subsystem */ | ||
159 | static struct snd_soc_device jive_snd_devdata = { | ||
160 | .machine = &snd_soc_machine_jive, | ||
161 | .platform = &s3c24xx_soc_platform, | ||
162 | .codec_dev = &soc_codec_dev_wm8750_spi, | ||
163 | .codec_data = &jive_wm8750_setup, | ||
164 | }; | ||
165 | |||
166 | static struct platform_device *jive_snd_device; | ||
167 | |||
168 | static int __init jive_init(void) | ||
169 | { | ||
170 | int ret; | ||
171 | |||
172 | if (!machine_is_jive()) | ||
173 | return 0; | ||
174 | |||
175 | printk("JIVE WM8750 Audio support\n"); | ||
176 | |||
177 | jive_snd_device = platform_device_alloc("soc-audio", -1); | ||
178 | if (!jive_snd_device) | ||
179 | return -ENOMEM; | ||
180 | |||
181 | platform_set_drvdata(jive_snd_device, &jive_snd_devdata); | ||
182 | jive_snd_devdata.dev = &jive_snd_device->dev; | ||
183 | ret = platform_device_add(jive_snd_device); | ||
184 | |||
185 | if (ret) | ||
186 | platform_device_put(jive_snd_device); | ||
187 | |||
188 | return ret; | ||
189 | } | ||
190 | |||
191 | static void __exit jive_exit(void) | ||
192 | { | ||
193 | platform_device_unregister(jive_snd_device); | ||
194 | } | ||
195 | |||
196 | module_init(jive_init); | ||
197 | module_exit(jive_exit); | ||
198 | |||
199 | MODULE_AUTHOR("Ben Dooks <ben@simtec.co.uk>"); | ||
200 | MODULE_DESCRIPTION("ALSA SoC Jive Audio support"); | ||
201 | MODULE_LICENSE("GPL"); | ||
diff --git a/sound/soc/s3c24xx/neo1973_wm8753.c b/sound/soc/s3c24xx/neo1973_wm8753.c index 45bb12e8ea44..289fadf60b10 100644 --- a/sound/soc/s3c24xx/neo1973_wm8753.c +++ b/sound/soc/s3c24xx/neo1973_wm8753.c | |||
@@ -29,25 +29,17 @@ | |||
29 | #include <mach/regs-clock.h> | 29 | #include <mach/regs-clock.h> |
30 | #include <mach/regs-gpio.h> | 30 | #include <mach/regs-gpio.h> |
31 | #include <mach/hardware.h> | 31 | #include <mach/hardware.h> |
32 | #include <mach/audio.h> | 32 | #include <plat/audio.h> |
33 | #include <linux/io.h> | 33 | #include <linux/io.h> |
34 | #include <mach/spi-gpio.h> | 34 | #include <mach/spi-gpio.h> |
35 | 35 | ||
36 | #include <asm/plat-s3c24xx/regs-iis.h> | 36 | #include <plat/regs-iis.h> |
37 | 37 | ||
38 | #include "../codecs/wm8753.h" | 38 | #include "../codecs/wm8753.h" |
39 | #include "lm4857.h" | 39 | #include "lm4857.h" |
40 | #include "s3c24xx-pcm.h" | 40 | #include "s3c24xx-pcm.h" |
41 | #include "s3c24xx-i2s.h" | 41 | #include "s3c24xx-i2s.h" |
42 | 42 | ||
43 | /* Debugging stuff */ | ||
44 | #define S3C24XX_SOC_NEO1973_WM8753_DEBUG 0 | ||
45 | #if S3C24XX_SOC_NEO1973_WM8753_DEBUG | ||
46 | #define DBG(x...) printk(KERN_DEBUG "s3c24xx-soc-neo1973-wm8753: " x) | ||
47 | #else | ||
48 | #define DBG(x...) | ||
49 | #endif | ||
50 | |||
51 | /* define the scenarios */ | 43 | /* define the scenarios */ |
52 | #define NEO_AUDIO_OFF 0 | 44 | #define NEO_AUDIO_OFF 0 |
53 | #define NEO_GSM_CALL_AUDIO_HANDSET 1 | 45 | #define NEO_GSM_CALL_AUDIO_HANDSET 1 |
@@ -72,7 +64,7 @@ static int neo1973_hifi_hw_params(struct snd_pcm_substream *substream, | |||
72 | int ret = 0; | 64 | int ret = 0; |
73 | unsigned long iis_clkrate; | 65 | unsigned long iis_clkrate; |
74 | 66 | ||
75 | DBG("Entered %s\n", __func__); | 67 | pr_debug("Entered %s\n", __func__); |
76 | 68 | ||
77 | iis_clkrate = s3c24xx_i2s_get_clockrate(); | 69 | iis_clkrate = s3c24xx_i2s_get_clockrate(); |
78 | 70 | ||
@@ -158,7 +150,7 @@ static int neo1973_hifi_hw_free(struct snd_pcm_substream *substream) | |||
158 | struct snd_soc_pcm_runtime *rtd = substream->private_data; | 150 | struct snd_soc_pcm_runtime *rtd = substream->private_data; |
159 | struct snd_soc_dai *codec_dai = rtd->dai->codec_dai; | 151 | struct snd_soc_dai *codec_dai = rtd->dai->codec_dai; |
160 | 152 | ||
161 | DBG("Entered %s\n", __func__); | 153 | pr_debug("Entered %s\n", __func__); |
162 | 154 | ||
163 | /* disable the PLL */ | 155 | /* disable the PLL */ |
164 | return snd_soc_dai_set_pll(codec_dai, WM8753_PLL1, 0, 0); | 156 | return snd_soc_dai_set_pll(codec_dai, WM8753_PLL1, 0, 0); |
@@ -181,7 +173,7 @@ static int neo1973_voice_hw_params(struct snd_pcm_substream *substream, | |||
181 | int ret = 0; | 173 | int ret = 0; |
182 | unsigned long iis_clkrate; | 174 | unsigned long iis_clkrate; |
183 | 175 | ||
184 | DBG("Entered %s\n", __func__); | 176 | pr_debug("Entered %s\n", __func__); |
185 | 177 | ||
186 | iis_clkrate = s3c24xx_i2s_get_clockrate(); | 178 | iis_clkrate = s3c24xx_i2s_get_clockrate(); |
187 | 179 | ||
@@ -224,7 +216,7 @@ static int neo1973_voice_hw_free(struct snd_pcm_substream *substream) | |||
224 | struct snd_soc_pcm_runtime *rtd = substream->private_data; | 216 | struct snd_soc_pcm_runtime *rtd = substream->private_data; |
225 | struct snd_soc_dai *codec_dai = rtd->dai->codec_dai; | 217 | struct snd_soc_dai *codec_dai = rtd->dai->codec_dai; |
226 | 218 | ||
227 | DBG("Entered %s\n", __func__); | 219 | pr_debug("Entered %s\n", __func__); |
228 | 220 | ||
229 | /* disable the PLL */ | 221 | /* disable the PLL */ |
230 | return snd_soc_dai_set_pll(codec_dai, WM8753_PLL2, 0, 0); | 222 | return snd_soc_dai_set_pll(codec_dai, WM8753_PLL2, 0, 0); |
@@ -246,7 +238,7 @@ static int neo1973_get_scenario(struct snd_kcontrol *kcontrol, | |||
246 | 238 | ||
247 | static int set_scenario_endpoints(struct snd_soc_codec *codec, int scenario) | 239 | static int set_scenario_endpoints(struct snd_soc_codec *codec, int scenario) |
248 | { | 240 | { |
249 | DBG("Entered %s\n", __func__); | 241 | pr_debug("Entered %s\n", __func__); |
250 | 242 | ||
251 | switch (neo1973_scenario) { | 243 | switch (neo1973_scenario) { |
252 | case NEO_AUDIO_OFF: | 244 | case NEO_AUDIO_OFF: |
@@ -330,7 +322,7 @@ static int neo1973_set_scenario(struct snd_kcontrol *kcontrol, | |||
330 | { | 322 | { |
331 | struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); | 323 | struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); |
332 | 324 | ||
333 | DBG("Entered %s\n", __func__); | 325 | pr_debug("Entered %s\n", __func__); |
334 | 326 | ||
335 | if (neo1973_scenario == ucontrol->value.integer.value[0]) | 327 | if (neo1973_scenario == ucontrol->value.integer.value[0]) |
336 | return 0; | 328 | return 0; |
@@ -344,7 +336,7 @@ static u8 lm4857_regs[4] = {0x00, 0x40, 0x80, 0xC0}; | |||
344 | 336 | ||
345 | static void lm4857_write_regs(void) | 337 | static void lm4857_write_regs(void) |
346 | { | 338 | { |
347 | DBG("Entered %s\n", __func__); | 339 | pr_debug("Entered %s\n", __func__); |
348 | 340 | ||
349 | if (i2c_master_send(i2c, lm4857_regs, 4) != 4) | 341 | if (i2c_master_send(i2c, lm4857_regs, 4) != 4) |
350 | printk(KERN_ERR "lm4857: i2c write failed\n"); | 342 | printk(KERN_ERR "lm4857: i2c write failed\n"); |
@@ -357,7 +349,7 @@ static int lm4857_get_reg(struct snd_kcontrol *kcontrol, | |||
357 | int shift = (kcontrol->private_value >> 8) & 0x0F; | 349 | int shift = (kcontrol->private_value >> 8) & 0x0F; |
358 | int mask = (kcontrol->private_value >> 16) & 0xFF; | 350 | int mask = (kcontrol->private_value >> 16) & 0xFF; |
359 | 351 | ||
360 | DBG("Entered %s\n", __func__); | 352 | pr_debug("Entered %s\n", __func__); |
361 | 353 | ||
362 | ucontrol->value.integer.value[0] = (lm4857_regs[reg] >> shift) & mask; | 354 | ucontrol->value.integer.value[0] = (lm4857_regs[reg] >> shift) & mask; |
363 | return 0; | 355 | return 0; |
@@ -385,7 +377,7 @@ static int lm4857_get_mode(struct snd_kcontrol *kcontrol, | |||
385 | { | 377 | { |
386 | u8 value = lm4857_regs[LM4857_CTRL] & 0x0F; | 378 | u8 value = lm4857_regs[LM4857_CTRL] & 0x0F; |
387 | 379 | ||
388 | DBG("Entered %s\n", __func__); | 380 | pr_debug("Entered %s\n", __func__); |
389 | 381 | ||
390 | if (value) | 382 | if (value) |
391 | value -= 5; | 383 | value -= 5; |
@@ -399,7 +391,7 @@ static int lm4857_set_mode(struct snd_kcontrol *kcontrol, | |||
399 | { | 391 | { |
400 | u8 value = ucontrol->value.integer.value[0]; | 392 | u8 value = ucontrol->value.integer.value[0]; |
401 | 393 | ||
402 | DBG("Entered %s\n", __func__); | 394 | pr_debug("Entered %s\n", __func__); |
403 | 395 | ||
404 | if (value) | 396 | if (value) |
405 | value += 5; | 397 | value += 5; |
@@ -506,9 +498,9 @@ static const struct snd_kcontrol_new wm8753_neo1973_controls[] = { | |||
506 | */ | 498 | */ |
507 | static int neo1973_wm8753_init(struct snd_soc_codec *codec) | 499 | static int neo1973_wm8753_init(struct snd_soc_codec *codec) |
508 | { | 500 | { |
509 | int i, err; | 501 | int err; |
510 | 502 | ||
511 | DBG("Entered %s\n", __func__); | 503 | pr_debug("Entered %s\n", __func__); |
512 | 504 | ||
513 | /* set up NC codec pins */ | 505 | /* set up NC codec pins */ |
514 | snd_soc_dapm_nc_pin(codec, "LOUT2"); | 506 | snd_soc_dapm_nc_pin(codec, "LOUT2"); |
@@ -526,13 +518,10 @@ static int neo1973_wm8753_init(struct snd_soc_codec *codec) | |||
526 | set_scenario_endpoints(codec, NEO_AUDIO_OFF); | 518 | set_scenario_endpoints(codec, NEO_AUDIO_OFF); |
527 | 519 | ||
528 | /* add neo1973 specific controls */ | 520 | /* add neo1973 specific controls */ |
529 | for (i = 0; i < ARRAY_SIZE(wm8753_neo1973_controls); i++) { | 521 | err = snd_soc_add_controls(codec, wm8753_neo1973_controls, |
530 | err = snd_ctl_add(codec->card, | 522 | ARRAY_SIZE(8753_neo1973_controls)); |
531 | snd_soc_cnew(&wm8753_neo1973_controls[i], | 523 | if (err < 0) |
532 | codec, NULL)); | 524 | return err; |
533 | if (err < 0) | ||
534 | return err; | ||
535 | } | ||
536 | 525 | ||
537 | /* set up neo1973 specific audio routes */ | 526 | /* set up neo1973 specific audio routes */ |
538 | err = snd_soc_dapm_add_routes(codec, dapm_routes, | 527 | err = snd_soc_dapm_add_routes(codec, dapm_routes, |
@@ -585,21 +574,15 @@ static struct snd_soc_card neo1973 = { | |||
585 | .num_links = ARRAY_SIZE(neo1973_dai), | 574 | .num_links = ARRAY_SIZE(neo1973_dai), |
586 | }; | 575 | }; |
587 | 576 | ||
588 | static struct wm8753_setup_data neo1973_wm8753_setup = { | ||
589 | .i2c_bus = 0, | ||
590 | .i2c_address = 0x1a, | ||
591 | }; | ||
592 | |||
593 | static struct snd_soc_device neo1973_snd_devdata = { | 577 | static struct snd_soc_device neo1973_snd_devdata = { |
594 | .card = &neo1973, | 578 | .card = &neo1973, |
595 | .codec_dev = &soc_codec_dev_wm8753, | 579 | .codec_dev = &soc_codec_dev_wm8753, |
596 | .codec_data = &neo1973_wm8753_setup, | ||
597 | }; | 580 | }; |
598 | 581 | ||
599 | static int lm4857_i2c_probe(struct i2c_client *client, | 582 | static int lm4857_i2c_probe(struct i2c_client *client, |
600 | const struct i2c_device_id *id) | 583 | const struct i2c_device_id *id) |
601 | { | 584 | { |
602 | DBG("Entered %s\n", __func__); | 585 | pr_debug("Entered %s\n", __func__); |
603 | 586 | ||
604 | i2c = client; | 587 | i2c = client; |
605 | 588 | ||
@@ -609,7 +592,7 @@ static int lm4857_i2c_probe(struct i2c_client *client, | |||
609 | 592 | ||
610 | static int lm4857_i2c_remove(struct i2c_client *client) | 593 | static int lm4857_i2c_remove(struct i2c_client *client) |
611 | { | 594 | { |
612 | DBG("Entered %s\n", __func__); | 595 | pr_debug("Entered %s\n", __func__); |
613 | 596 | ||
614 | i2c = NULL; | 597 | i2c = NULL; |
615 | 598 | ||
@@ -620,7 +603,7 @@ static u8 lm4857_state; | |||
620 | 603 | ||
621 | static int lm4857_suspend(struct i2c_client *dev, pm_message_t state) | 604 | static int lm4857_suspend(struct i2c_client *dev, pm_message_t state) |
622 | { | 605 | { |
623 | DBG("Entered %s\n", __func__); | 606 | pr_debug("Entered %s\n", __func__); |
624 | 607 | ||
625 | dev_dbg(&dev->dev, "lm4857_suspend\n"); | 608 | dev_dbg(&dev->dev, "lm4857_suspend\n"); |
626 | lm4857_state = lm4857_regs[LM4857_CTRL] & 0xf; | 609 | lm4857_state = lm4857_regs[LM4857_CTRL] & 0xf; |
@@ -633,7 +616,7 @@ static int lm4857_suspend(struct i2c_client *dev, pm_message_t state) | |||
633 | 616 | ||
634 | static int lm4857_resume(struct i2c_client *dev) | 617 | static int lm4857_resume(struct i2c_client *dev) |
635 | { | 618 | { |
636 | DBG("Entered %s\n", __func__); | 619 | pr_debug("Entered %s\n", __func__); |
637 | 620 | ||
638 | if (lm4857_state) { | 621 | if (lm4857_state) { |
639 | lm4857_regs[LM4857_CTRL] |= (lm4857_state & 0x0f); | 622 | lm4857_regs[LM4857_CTRL] |= (lm4857_state & 0x0f); |
@@ -644,7 +627,7 @@ static int lm4857_resume(struct i2c_client *dev) | |||
644 | 627 | ||
645 | static void lm4857_shutdown(struct i2c_client *dev) | 628 | static void lm4857_shutdown(struct i2c_client *dev) |
646 | { | 629 | { |
647 | DBG("Entered %s\n", __func__); | 630 | pr_debug("Entered %s\n", __func__); |
648 | 631 | ||
649 | dev_dbg(&dev->dev, "lm4857_shutdown\n"); | 632 | dev_dbg(&dev->dev, "lm4857_shutdown\n"); |
650 | lm4857_regs[LM4857_CTRL] &= 0xf0; | 633 | lm4857_regs[LM4857_CTRL] &= 0xf0; |
@@ -675,7 +658,7 @@ static int __init neo1973_init(void) | |||
675 | { | 658 | { |
676 | int ret; | 659 | int ret; |
677 | 660 | ||
678 | DBG("Entered %s\n", __func__); | 661 | pr_debug("Entered %s\n", __func__); |
679 | 662 | ||
680 | if (!machine_is_neo1973_gta01()) { | 663 | if (!machine_is_neo1973_gta01()) { |
681 | printk(KERN_INFO | 664 | printk(KERN_INFO |
@@ -706,7 +689,7 @@ static int __init neo1973_init(void) | |||
706 | 689 | ||
707 | static void __exit neo1973_exit(void) | 690 | static void __exit neo1973_exit(void) |
708 | { | 691 | { |
709 | DBG("Entered %s\n", __func__); | 692 | pr_debug("Entered %s\n", __func__); |
710 | 693 | ||
711 | i2c_del_driver(&lm4857_i2c_driver); | 694 | i2c_del_driver(&lm4857_i2c_driver); |
712 | platform_device_unregister(neo1973_snd_device); | 695 | platform_device_unregister(neo1973_snd_device); |
diff --git a/sound/soc/s3c24xx/s3c-i2s-v2.c b/sound/soc/s3c24xx/s3c-i2s-v2.c new file mode 100644 index 000000000000..295a4c910262 --- /dev/null +++ b/sound/soc/s3c24xx/s3c-i2s-v2.c | |||
@@ -0,0 +1,638 @@ | |||
1 | /* sound/soc/s3c24xx/s3c-i2c-v2.c | ||
2 | * | ||
3 | * ALSA Soc Audio Layer - I2S core for newer Samsung SoCs. | ||
4 | * | ||
5 | * Copyright (c) 2006 Wolfson Microelectronics PLC. | ||
6 | * Graeme Gregory graeme.gregory@wolfsonmicro.com | ||
7 | * linux@wolfsonmicro.com | ||
8 | * | ||
9 | * Copyright (c) 2008, 2007, 2004-2005 Simtec Electronics | ||
10 | * http://armlinux.simtec.co.uk/ | ||
11 | * Ben Dooks <ben@simtec.co.uk> | ||
12 | * | ||
13 | * This program is free software; you can redistribute it and/or modify it | ||
14 | * under the terms of the GNU General Public License as published by the | ||
15 | * Free Software Foundation; either version 2 of the License, or (at your | ||
16 | * option) any later version. | ||
17 | */ | ||
18 | |||
19 | #include <linux/init.h> | ||
20 | #include <linux/module.h> | ||
21 | #include <linux/device.h> | ||
22 | #include <linux/delay.h> | ||
23 | #include <linux/clk.h> | ||
24 | #include <linux/kernel.h> | ||
25 | #include <linux/io.h> | ||
26 | |||
27 | #include <sound/core.h> | ||
28 | #include <sound/pcm.h> | ||
29 | #include <sound/pcm_params.h> | ||
30 | #include <sound/initval.h> | ||
31 | #include <sound/soc.h> | ||
32 | |||
33 | #include <plat/regs-s3c2412-iis.h> | ||
34 | |||
35 | #include <plat/audio.h> | ||
36 | #include <mach/dma.h> | ||
37 | |||
38 | #include "s3c-i2s-v2.h" | ||
39 | |||
40 | #define S3C2412_I2S_DEBUG_CON 0 | ||
41 | |||
42 | static inline struct s3c_i2sv2_info *to_info(struct snd_soc_dai *cpu_dai) | ||
43 | { | ||
44 | return cpu_dai->private_data; | ||
45 | } | ||
46 | |||
47 | #define bit_set(v, b) (((v) & (b)) ? 1 : 0) | ||
48 | |||
49 | #if S3C2412_I2S_DEBUG_CON | ||
50 | static void dbg_showcon(const char *fn, u32 con) | ||
51 | { | ||
52 | printk(KERN_DEBUG "%s: LRI=%d, TXFEMPT=%d, RXFEMPT=%d, TXFFULL=%d, RXFFULL=%d\n", fn, | ||
53 | bit_set(con, S3C2412_IISCON_LRINDEX), | ||
54 | bit_set(con, S3C2412_IISCON_TXFIFO_EMPTY), | ||
55 | bit_set(con, S3C2412_IISCON_RXFIFO_EMPTY), | ||
56 | bit_set(con, S3C2412_IISCON_TXFIFO_FULL), | ||
57 | bit_set(con, S3C2412_IISCON_RXFIFO_FULL)); | ||
58 | |||
59 | printk(KERN_DEBUG "%s: PAUSE: TXDMA=%d, RXDMA=%d, TXCH=%d, RXCH=%d\n", | ||
60 | fn, | ||
61 | bit_set(con, S3C2412_IISCON_TXDMA_PAUSE), | ||
62 | bit_set(con, S3C2412_IISCON_RXDMA_PAUSE), | ||
63 | bit_set(con, S3C2412_IISCON_TXCH_PAUSE), | ||
64 | bit_set(con, S3C2412_IISCON_RXCH_PAUSE)); | ||
65 | printk(KERN_DEBUG "%s: ACTIVE: TXDMA=%d, RXDMA=%d, IIS=%d\n", fn, | ||
66 | bit_set(con, S3C2412_IISCON_TXDMA_ACTIVE), | ||
67 | bit_set(con, S3C2412_IISCON_RXDMA_ACTIVE), | ||
68 | bit_set(con, S3C2412_IISCON_IIS_ACTIVE)); | ||
69 | } | ||
70 | #else | ||
71 | static inline void dbg_showcon(const char *fn, u32 con) | ||
72 | { | ||
73 | } | ||
74 | #endif | ||
75 | |||
76 | |||
77 | /* Turn on or off the transmission path. */ | ||
78 | void s3c2412_snd_txctrl(struct s3c_i2sv2_info *i2s, int on) | ||
79 | { | ||
80 | void __iomem *regs = i2s->regs; | ||
81 | u32 fic, con, mod; | ||
82 | |||
83 | pr_debug("%s(%d)\n", __func__, on); | ||
84 | |||
85 | fic = readl(regs + S3C2412_IISFIC); | ||
86 | con = readl(regs + S3C2412_IISCON); | ||
87 | mod = readl(regs + S3C2412_IISMOD); | ||
88 | |||
89 | pr_debug("%s: IIS: CON=%x MOD=%x FIC=%x\n", __func__, con, mod, fic); | ||
90 | |||
91 | if (on) { | ||
92 | con |= S3C2412_IISCON_TXDMA_ACTIVE | S3C2412_IISCON_IIS_ACTIVE; | ||
93 | con &= ~S3C2412_IISCON_TXDMA_PAUSE; | ||
94 | con &= ~S3C2412_IISCON_TXCH_PAUSE; | ||
95 | |||
96 | switch (mod & S3C2412_IISMOD_MODE_MASK) { | ||
97 | case S3C2412_IISMOD_MODE_TXONLY: | ||
98 | case S3C2412_IISMOD_MODE_TXRX: | ||
99 | /* do nothing, we are in the right mode */ | ||
100 | break; | ||
101 | |||
102 | case S3C2412_IISMOD_MODE_RXONLY: | ||
103 | mod &= ~S3C2412_IISMOD_MODE_MASK; | ||
104 | mod |= S3C2412_IISMOD_MODE_TXRX; | ||
105 | break; | ||
106 | |||
107 | default: | ||
108 | dev_err(i2s->dev, "TXEN: Invalid MODE in IISMOD\n"); | ||
109 | } | ||
110 | |||
111 | writel(con, regs + S3C2412_IISCON); | ||
112 | writel(mod, regs + S3C2412_IISMOD); | ||
113 | } else { | ||
114 | /* Note, we do not have any indication that the FIFO problems | ||
115 | * tha the S3C2410/2440 had apply here, so we should be able | ||
116 | * to disable the DMA and TX without resetting the FIFOS. | ||
117 | */ | ||
118 | |||
119 | con |= S3C2412_IISCON_TXDMA_PAUSE; | ||
120 | con |= S3C2412_IISCON_TXCH_PAUSE; | ||
121 | con &= ~S3C2412_IISCON_TXDMA_ACTIVE; | ||
122 | |||
123 | switch (mod & S3C2412_IISMOD_MODE_MASK) { | ||
124 | case S3C2412_IISMOD_MODE_TXRX: | ||
125 | mod &= ~S3C2412_IISMOD_MODE_MASK; | ||
126 | mod |= S3C2412_IISMOD_MODE_RXONLY; | ||
127 | break; | ||
128 | |||
129 | case S3C2412_IISMOD_MODE_TXONLY: | ||
130 | mod &= ~S3C2412_IISMOD_MODE_MASK; | ||
131 | con &= ~S3C2412_IISCON_IIS_ACTIVE; | ||
132 | break; | ||
133 | |||
134 | default: | ||
135 | dev_err(i2s->dev, "TXDIS: Invalid MODE in IISMOD\n"); | ||
136 | } | ||
137 | |||
138 | writel(mod, regs + S3C2412_IISMOD); | ||
139 | writel(con, regs + S3C2412_IISCON); | ||
140 | } | ||
141 | |||
142 | fic = readl(regs + S3C2412_IISFIC); | ||
143 | dbg_showcon(__func__, con); | ||
144 | pr_debug("%s: IIS: CON=%x MOD=%x FIC=%x\n", __func__, con, mod, fic); | ||
145 | } | ||
146 | EXPORT_SYMBOL_GPL(s3c2412_snd_txctrl); | ||
147 | |||
148 | void s3c2412_snd_rxctrl(struct s3c_i2sv2_info *i2s, int on) | ||
149 | { | ||
150 | void __iomem *regs = i2s->regs; | ||
151 | u32 fic, con, mod; | ||
152 | |||
153 | pr_debug("%s(%d)\n", __func__, on); | ||
154 | |||
155 | fic = readl(regs + S3C2412_IISFIC); | ||
156 | con = readl(regs + S3C2412_IISCON); | ||
157 | mod = readl(regs + S3C2412_IISMOD); | ||
158 | |||
159 | pr_debug("%s: IIS: CON=%x MOD=%x FIC=%x\n", __func__, con, mod, fic); | ||
160 | |||
161 | if (on) { | ||
162 | con |= S3C2412_IISCON_RXDMA_ACTIVE | S3C2412_IISCON_IIS_ACTIVE; | ||
163 | con &= ~S3C2412_IISCON_RXDMA_PAUSE; | ||
164 | con &= ~S3C2412_IISCON_RXCH_PAUSE; | ||
165 | |||
166 | switch (mod & S3C2412_IISMOD_MODE_MASK) { | ||
167 | case S3C2412_IISMOD_MODE_TXRX: | ||
168 | case S3C2412_IISMOD_MODE_RXONLY: | ||
169 | /* do nothing, we are in the right mode */ | ||
170 | break; | ||
171 | |||
172 | case S3C2412_IISMOD_MODE_TXONLY: | ||
173 | mod &= ~S3C2412_IISMOD_MODE_MASK; | ||
174 | mod |= S3C2412_IISMOD_MODE_TXRX; | ||
175 | break; | ||
176 | |||
177 | default: | ||
178 | dev_err(i2s->dev, "RXEN: Invalid MODE in IISMOD\n"); | ||
179 | } | ||
180 | |||
181 | writel(mod, regs + S3C2412_IISMOD); | ||
182 | writel(con, regs + S3C2412_IISCON); | ||
183 | } else { | ||
184 | /* See txctrl notes on FIFOs. */ | ||
185 | |||
186 | con &= ~S3C2412_IISCON_RXDMA_ACTIVE; | ||
187 | con |= S3C2412_IISCON_RXDMA_PAUSE; | ||
188 | con |= S3C2412_IISCON_RXCH_PAUSE; | ||
189 | |||
190 | switch (mod & S3C2412_IISMOD_MODE_MASK) { | ||
191 | case S3C2412_IISMOD_MODE_RXONLY: | ||
192 | con &= ~S3C2412_IISCON_IIS_ACTIVE; | ||
193 | mod &= ~S3C2412_IISMOD_MODE_MASK; | ||
194 | break; | ||
195 | |||
196 | case S3C2412_IISMOD_MODE_TXRX: | ||
197 | mod &= ~S3C2412_IISMOD_MODE_MASK; | ||
198 | mod |= S3C2412_IISMOD_MODE_TXONLY; | ||
199 | break; | ||
200 | |||
201 | default: | ||
202 | dev_err(i2s->dev, "RXEN: Invalid MODE in IISMOD\n"); | ||
203 | } | ||
204 | |||
205 | writel(con, regs + S3C2412_IISCON); | ||
206 | writel(mod, regs + S3C2412_IISMOD); | ||
207 | } | ||
208 | |||
209 | fic = readl(regs + S3C2412_IISFIC); | ||
210 | pr_debug("%s: IIS: CON=%x MOD=%x FIC=%x\n", __func__, con, mod, fic); | ||
211 | } | ||
212 | EXPORT_SYMBOL_GPL(s3c2412_snd_rxctrl); | ||
213 | |||
214 | /* | ||
215 | * Wait for the LR signal to allow synchronisation to the L/R clock | ||
216 | * from the codec. May only be needed for slave mode. | ||
217 | */ | ||
218 | static int s3c2412_snd_lrsync(struct s3c_i2sv2_info *i2s) | ||
219 | { | ||
220 | u32 iiscon; | ||
221 | unsigned long timeout = jiffies + msecs_to_jiffies(5); | ||
222 | |||
223 | pr_debug("Entered %s\n", __func__); | ||
224 | |||
225 | while (1) { | ||
226 | iiscon = readl(i2s->regs + S3C2412_IISCON); | ||
227 | if (iiscon & S3C2412_IISCON_LRINDEX) | ||
228 | break; | ||
229 | |||
230 | if (timeout < jiffies) { | ||
231 | printk(KERN_ERR "%s: timeout\n", __func__); | ||
232 | return -ETIMEDOUT; | ||
233 | } | ||
234 | } | ||
235 | |||
236 | return 0; | ||
237 | } | ||
238 | |||
239 | /* | ||
240 | * Set S3C2412 I2S DAI format | ||
241 | */ | ||
242 | static int s3c2412_i2s_set_fmt(struct snd_soc_dai *cpu_dai, | ||
243 | unsigned int fmt) | ||
244 | { | ||
245 | struct s3c_i2sv2_info *i2s = to_info(cpu_dai); | ||
246 | u32 iismod; | ||
247 | |||
248 | pr_debug("Entered %s\n", __func__); | ||
249 | |||
250 | iismod = readl(i2s->regs + S3C2412_IISMOD); | ||
251 | pr_debug("hw_params r: IISMOD: %x \n", iismod); | ||
252 | |||
253 | #if defined(CONFIG_CPU_S3C2412) || defined(CONFIG_CPU_S3C2413) | ||
254 | #define IISMOD_MASTER_MASK S3C2412_IISMOD_MASTER_MASK | ||
255 | #define IISMOD_SLAVE S3C2412_IISMOD_SLAVE | ||
256 | #define IISMOD_MASTER S3C2412_IISMOD_MASTER_INTERNAL | ||
257 | #endif | ||
258 | |||
259 | #if defined(CONFIG_PLAT_S3C64XX) | ||
260 | /* From Rev1.1 datasheet, we have two master and two slave modes: | ||
261 | * IMS[11:10]: | ||
262 | * 00 = master mode, fed from PCLK | ||
263 | * 01 = master mode, fed from CLKAUDIO | ||
264 | * 10 = slave mode, using PCLK | ||
265 | * 11 = slave mode, using I2SCLK | ||
266 | */ | ||
267 | #define IISMOD_MASTER_MASK (1 << 11) | ||
268 | #define IISMOD_SLAVE (1 << 11) | ||
269 | #define IISMOD_MASTER (0x0) | ||
270 | #endif | ||
271 | |||
272 | switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { | ||
273 | case SND_SOC_DAIFMT_CBM_CFM: | ||
274 | i2s->master = 0; | ||
275 | iismod &= ~IISMOD_MASTER_MASK; | ||
276 | iismod |= IISMOD_SLAVE; | ||
277 | break; | ||
278 | case SND_SOC_DAIFMT_CBS_CFS: | ||
279 | i2s->master = 1; | ||
280 | iismod &= ~IISMOD_MASTER_MASK; | ||
281 | iismod |= IISMOD_MASTER; | ||
282 | break; | ||
283 | default: | ||
284 | pr_debug("unknwon master/slave format\n"); | ||
285 | return -EINVAL; | ||
286 | } | ||
287 | |||
288 | iismod &= ~S3C2412_IISMOD_SDF_MASK; | ||
289 | |||
290 | switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) { | ||
291 | case SND_SOC_DAIFMT_RIGHT_J: | ||
292 | iismod |= S3C2412_IISMOD_SDF_MSB; | ||
293 | break; | ||
294 | case SND_SOC_DAIFMT_LEFT_J: | ||
295 | iismod |= S3C2412_IISMOD_SDF_LSB; | ||
296 | break; | ||
297 | case SND_SOC_DAIFMT_I2S: | ||
298 | iismod |= S3C2412_IISMOD_SDF_IIS; | ||
299 | break; | ||
300 | default: | ||
301 | pr_debug("Unknown data format\n"); | ||
302 | return -EINVAL; | ||
303 | } | ||
304 | |||
305 | writel(iismod, i2s->regs + S3C2412_IISMOD); | ||
306 | pr_debug("hw_params w: IISMOD: %x \n", iismod); | ||
307 | return 0; | ||
308 | } | ||
309 | |||
310 | static int s3c2412_i2s_hw_params(struct snd_pcm_substream *substream, | ||
311 | struct snd_pcm_hw_params *params, | ||
312 | struct snd_soc_dai *socdai) | ||
313 | { | ||
314 | struct snd_soc_pcm_runtime *rtd = substream->private_data; | ||
315 | struct snd_soc_dai_link *dai = rtd->dai; | ||
316 | struct s3c_i2sv2_info *i2s = to_info(dai->cpu_dai); | ||
317 | u32 iismod; | ||
318 | |||
319 | pr_debug("Entered %s\n", __func__); | ||
320 | |||
321 | if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) | ||
322 | dai->cpu_dai->dma_data = i2s->dma_playback; | ||
323 | else | ||
324 | dai->cpu_dai->dma_data = i2s->dma_capture; | ||
325 | |||
326 | /* Working copies of register */ | ||
327 | iismod = readl(i2s->regs + S3C2412_IISMOD); | ||
328 | pr_debug("%s: r: IISMOD: %x\n", __func__, iismod); | ||
329 | |||
330 | switch (params_format(params)) { | ||
331 | case SNDRV_PCM_FORMAT_S8: | ||
332 | iismod |= S3C2412_IISMOD_8BIT; | ||
333 | break; | ||
334 | case SNDRV_PCM_FORMAT_S16_LE: | ||
335 | iismod &= ~S3C2412_IISMOD_8BIT; | ||
336 | break; | ||
337 | } | ||
338 | |||
339 | writel(iismod, i2s->regs + S3C2412_IISMOD); | ||
340 | pr_debug("%s: w: IISMOD: %x\n", __func__, iismod); | ||
341 | return 0; | ||
342 | } | ||
343 | |||
344 | static int s3c2412_i2s_trigger(struct snd_pcm_substream *substream, int cmd, | ||
345 | struct snd_soc_dai *dai) | ||
346 | { | ||
347 | struct snd_soc_pcm_runtime *rtd = substream->private_data; | ||
348 | struct s3c_i2sv2_info *i2s = to_info(rtd->dai->cpu_dai); | ||
349 | int capture = (substream->stream == SNDRV_PCM_STREAM_CAPTURE); | ||
350 | unsigned long irqs; | ||
351 | int ret = 0; | ||
352 | |||
353 | pr_debug("Entered %s\n", __func__); | ||
354 | |||
355 | switch (cmd) { | ||
356 | case SNDRV_PCM_TRIGGER_START: | ||
357 | /* On start, ensure that the FIFOs are cleared and reset. */ | ||
358 | |||
359 | writel(capture ? S3C2412_IISFIC_RXFLUSH : S3C2412_IISFIC_TXFLUSH, | ||
360 | i2s->regs + S3C2412_IISFIC); | ||
361 | |||
362 | /* clear again, just in case */ | ||
363 | writel(0x0, i2s->regs + S3C2412_IISFIC); | ||
364 | |||
365 | case SNDRV_PCM_TRIGGER_RESUME: | ||
366 | case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: | ||
367 | if (!i2s->master) { | ||
368 | ret = s3c2412_snd_lrsync(i2s); | ||
369 | if (ret) | ||
370 | goto exit_err; | ||
371 | } | ||
372 | |||
373 | local_irq_save(irqs); | ||
374 | |||
375 | if (capture) | ||
376 | s3c2412_snd_rxctrl(i2s, 1); | ||
377 | else | ||
378 | s3c2412_snd_txctrl(i2s, 1); | ||
379 | |||
380 | local_irq_restore(irqs); | ||
381 | break; | ||
382 | |||
383 | case SNDRV_PCM_TRIGGER_STOP: | ||
384 | case SNDRV_PCM_TRIGGER_SUSPEND: | ||
385 | case SNDRV_PCM_TRIGGER_PAUSE_PUSH: | ||
386 | local_irq_save(irqs); | ||
387 | |||
388 | if (capture) | ||
389 | s3c2412_snd_rxctrl(i2s, 0); | ||
390 | else | ||
391 | s3c2412_snd_txctrl(i2s, 0); | ||
392 | |||
393 | local_irq_restore(irqs); | ||
394 | break; | ||
395 | default: | ||
396 | ret = -EINVAL; | ||
397 | break; | ||
398 | } | ||
399 | |||
400 | exit_err: | ||
401 | return ret; | ||
402 | } | ||
403 | |||
404 | /* | ||
405 | * Set S3C2412 Clock dividers | ||
406 | */ | ||
407 | static int s3c2412_i2s_set_clkdiv(struct snd_soc_dai *cpu_dai, | ||
408 | int div_id, int div) | ||
409 | { | ||
410 | struct s3c_i2sv2_info *i2s = to_info(cpu_dai); | ||
411 | u32 reg; | ||
412 | |||
413 | pr_debug("%s(%p, %d, %d)\n", __func__, cpu_dai, div_id, div); | ||
414 | |||
415 | switch (div_id) { | ||
416 | case S3C_I2SV2_DIV_BCLK: | ||
417 | reg = readl(i2s->regs + S3C2412_IISMOD); | ||
418 | reg &= ~S3C2412_IISMOD_BCLK_MASK; | ||
419 | writel(reg | div, i2s->regs + S3C2412_IISMOD); | ||
420 | |||
421 | pr_debug("%s: MOD=%08x\n", __func__, readl(i2s->regs + S3C2412_IISMOD)); | ||
422 | break; | ||
423 | |||
424 | case S3C_I2SV2_DIV_RCLK: | ||
425 | if (div > 3) { | ||
426 | /* convert value to bit field */ | ||
427 | |||
428 | switch (div) { | ||
429 | case 256: | ||
430 | div = S3C2412_IISMOD_RCLK_256FS; | ||
431 | break; | ||
432 | |||
433 | case 384: | ||
434 | div = S3C2412_IISMOD_RCLK_384FS; | ||
435 | break; | ||
436 | |||
437 | case 512: | ||
438 | div = S3C2412_IISMOD_RCLK_512FS; | ||
439 | break; | ||
440 | |||
441 | case 768: | ||
442 | div = S3C2412_IISMOD_RCLK_768FS; | ||
443 | break; | ||
444 | |||
445 | default: | ||
446 | return -EINVAL; | ||
447 | } | ||
448 | } | ||
449 | |||
450 | reg = readl(i2s->regs + S3C2412_IISMOD); | ||
451 | reg &= ~S3C2412_IISMOD_RCLK_MASK; | ||
452 | writel(reg | div, i2s->regs + S3C2412_IISMOD); | ||
453 | pr_debug("%s: MOD=%08x\n", __func__, readl(i2s->regs + S3C2412_IISMOD)); | ||
454 | break; | ||
455 | |||
456 | case S3C_I2SV2_DIV_PRESCALER: | ||
457 | if (div >= 0) { | ||
458 | writel((div << 8) | S3C2412_IISPSR_PSREN, | ||
459 | i2s->regs + S3C2412_IISPSR); | ||
460 | } else { | ||
461 | writel(0x0, i2s->regs + S3C2412_IISPSR); | ||
462 | } | ||
463 | pr_debug("%s: PSR=%08x\n", __func__, readl(i2s->regs + S3C2412_IISPSR)); | ||
464 | break; | ||
465 | |||
466 | default: | ||
467 | return -EINVAL; | ||
468 | } | ||
469 | |||
470 | return 0; | ||
471 | } | ||
472 | |||
473 | /* default table of all avaialable root fs divisors */ | ||
474 | static unsigned int iis_fs_tab[] = { 256, 512, 384, 768 }; | ||
475 | |||
476 | int s3c2412_iis_calc_rate(struct s3c_i2sv2_rate_calc *info, | ||
477 | unsigned int *fstab, | ||
478 | unsigned int rate, struct clk *clk) | ||
479 | { | ||
480 | unsigned long clkrate = clk_get_rate(clk); | ||
481 | unsigned int div; | ||
482 | unsigned int fsclk; | ||
483 | unsigned int actual; | ||
484 | unsigned int fs; | ||
485 | unsigned int fsdiv; | ||
486 | signed int deviation = 0; | ||
487 | unsigned int best_fs = 0; | ||
488 | unsigned int best_div = 0; | ||
489 | unsigned int best_rate = 0; | ||
490 | unsigned int best_deviation = INT_MAX; | ||
491 | |||
492 | if (fstab == NULL) | ||
493 | fstab = iis_fs_tab; | ||
494 | |||
495 | for (fs = 0; fs < ARRAY_SIZE(iis_fs_tab); fs++) { | ||
496 | fsdiv = iis_fs_tab[fs]; | ||
497 | |||
498 | fsclk = clkrate / fsdiv; | ||
499 | div = fsclk / rate; | ||
500 | |||
501 | if ((fsclk % rate) > (rate / 2)) | ||
502 | div++; | ||
503 | |||
504 | if (div <= 1) | ||
505 | continue; | ||
506 | |||
507 | actual = clkrate / (fsdiv * div); | ||
508 | deviation = actual - rate; | ||
509 | |||
510 | printk(KERN_DEBUG "%dfs: div %d => result %d, deviation %d\n", | ||
511 | fsdiv, div, actual, deviation); | ||
512 | |||
513 | deviation = abs(deviation); | ||
514 | |||
515 | if (deviation < best_deviation) { | ||
516 | best_fs = fsdiv; | ||
517 | best_div = div; | ||
518 | best_rate = actual; | ||
519 | best_deviation = deviation; | ||
520 | } | ||
521 | |||
522 | if (deviation == 0) | ||
523 | break; | ||
524 | } | ||
525 | |||
526 | printk(KERN_DEBUG "best: fs=%d, div=%d, rate=%d\n", | ||
527 | best_fs, best_div, best_rate); | ||
528 | |||
529 | info->fs_div = best_fs; | ||
530 | info->clk_div = best_div; | ||
531 | |||
532 | return 0; | ||
533 | } | ||
534 | EXPORT_SYMBOL_GPL(s3c2412_iis_calc_rate); | ||
535 | |||
536 | int s3c_i2sv2_probe(struct platform_device *pdev, | ||
537 | struct snd_soc_dai *dai, | ||
538 | struct s3c_i2sv2_info *i2s, | ||
539 | unsigned long base) | ||
540 | { | ||
541 | struct device *dev = &pdev->dev; | ||
542 | |||
543 | i2s->dev = dev; | ||
544 | |||
545 | /* record our i2s structure for later use in the callbacks */ | ||
546 | dai->private_data = i2s; | ||
547 | |||
548 | i2s->regs = ioremap(base, 0x100); | ||
549 | if (i2s->regs == NULL) { | ||
550 | dev_err(dev, "cannot ioremap registers\n"); | ||
551 | return -ENXIO; | ||
552 | } | ||
553 | |||
554 | i2s->iis_pclk = clk_get(dev, "iis"); | ||
555 | if (i2s->iis_pclk == NULL) { | ||
556 | dev_err(dev, "failed to get iis_clock\n"); | ||
557 | iounmap(i2s->regs); | ||
558 | return -ENOENT; | ||
559 | } | ||
560 | |||
561 | clk_enable(i2s->iis_pclk); | ||
562 | |||
563 | s3c2412_snd_txctrl(i2s, 0); | ||
564 | s3c2412_snd_rxctrl(i2s, 0); | ||
565 | |||
566 | return 0; | ||
567 | } | ||
568 | |||
569 | EXPORT_SYMBOL_GPL(s3c_i2sv2_probe); | ||
570 | |||
571 | #ifdef CONFIG_PM | ||
572 | static int s3c2412_i2s_suspend(struct snd_soc_dai *dai) | ||
573 | { | ||
574 | struct s3c_i2sv2_info *i2s = to_info(dai); | ||
575 | u32 iismod; | ||
576 | |||
577 | if (dai->active) { | ||
578 | i2s->suspend_iismod = readl(i2s->regs + S3C2412_IISMOD); | ||
579 | i2s->suspend_iiscon = readl(i2s->regs + S3C2412_IISCON); | ||
580 | i2s->suspend_iispsr = readl(i2s->regs + S3C2412_IISPSR); | ||
581 | |||
582 | /* some basic suspend checks */ | ||
583 | |||
584 | iismod = readl(i2s->regs + S3C2412_IISMOD); | ||
585 | |||
586 | if (iismod & S3C2412_IISCON_RXDMA_ACTIVE) | ||
587 | pr_warning("%s: RXDMA active?\n", __func__); | ||
588 | |||
589 | if (iismod & S3C2412_IISCON_TXDMA_ACTIVE) | ||
590 | pr_warning("%s: TXDMA active?\n", __func__); | ||
591 | |||
592 | if (iismod & S3C2412_IISCON_IIS_ACTIVE) | ||
593 | pr_warning("%s: IIS active\n", __func__); | ||
594 | } | ||
595 | |||
596 | return 0; | ||
597 | } | ||
598 | |||
599 | static int s3c2412_i2s_resume(struct snd_soc_dai *dai) | ||
600 | { | ||
601 | struct s3c_i2sv2_info *i2s = to_info(dai); | ||
602 | |||
603 | pr_info("dai_active %d, IISMOD %08x, IISCON %08x\n", | ||
604 | dai->active, i2s->suspend_iismod, i2s->suspend_iiscon); | ||
605 | |||
606 | if (dai->active) { | ||
607 | writel(i2s->suspend_iiscon, i2s->regs + S3C2412_IISCON); | ||
608 | writel(i2s->suspend_iismod, i2s->regs + S3C2412_IISMOD); | ||
609 | writel(i2s->suspend_iispsr, i2s->regs + S3C2412_IISPSR); | ||
610 | |||
611 | writel(S3C2412_IISFIC_RXFLUSH | S3C2412_IISFIC_TXFLUSH, | ||
612 | i2s->regs + S3C2412_IISFIC); | ||
613 | |||
614 | ndelay(250); | ||
615 | writel(0x0, i2s->regs + S3C2412_IISFIC); | ||
616 | } | ||
617 | |||
618 | return 0; | ||
619 | } | ||
620 | #else | ||
621 | #define s3c2412_i2s_suspend NULL | ||
622 | #define s3c2412_i2s_resume NULL | ||
623 | #endif | ||
624 | |||
625 | int s3c_i2sv2_register_dai(struct snd_soc_dai *dai) | ||
626 | { | ||
627 | dai->ops.trigger = s3c2412_i2s_trigger; | ||
628 | dai->ops.hw_params = s3c2412_i2s_hw_params; | ||
629 | dai->ops.set_fmt = s3c2412_i2s_set_fmt; | ||
630 | dai->ops.set_clkdiv = s3c2412_i2s_set_clkdiv; | ||
631 | |||
632 | dai->suspend = s3c2412_i2s_suspend; | ||
633 | dai->resume = s3c2412_i2s_resume; | ||
634 | |||
635 | return snd_soc_register_dai(dai); | ||
636 | } | ||
637 | |||
638 | EXPORT_SYMBOL_GPL(s3c_i2sv2_register_dai); | ||
diff --git a/sound/soc/s3c24xx/s3c-i2s-v2.h b/sound/soc/s3c24xx/s3c-i2s-v2.h new file mode 100644 index 000000000000..f66854a77fb2 --- /dev/null +++ b/sound/soc/s3c24xx/s3c-i2s-v2.h | |||
@@ -0,0 +1,90 @@ | |||
1 | /* sound/soc/s3c24xx/s3c-i2s-v2.h | ||
2 | * | ||
3 | * ALSA Soc Audio Layer - S3C_I2SV2 I2S driver | ||
4 | * | ||
5 | * Copyright (c) 2007 Simtec Electronics | ||
6 | * http://armlinux.simtec.co.uk/ | ||
7 | * Ben Dooks <ben@simtec.co.uk> | ||
8 | * | ||
9 | * This program is free software; you can redistribute it and/or modify it | ||
10 | * under the terms of the GNU General Public License as published by the | ||
11 | * Free Software Foundation; either version 2 of the License, or (at your | ||
12 | * option) any later version. | ||
13 | */ | ||
14 | |||
15 | /* This code is the core support for the I2S block found in a number of | ||
16 | * Samsung SoC devices which is unofficially named I2S-V2. Currently the | ||
17 | * S3C2412 and the S3C64XX series use this block to provide 1 or 2 I2S | ||
18 | * channels via configurable GPIO. | ||
19 | */ | ||
20 | |||
21 | #ifndef __SND_SOC_S3C24XX_S3C_I2SV2_I2S_H | ||
22 | #define __SND_SOC_S3C24XX_S3C_I2SV2_I2S_H __FILE__ | ||
23 | |||
24 | #define S3C_I2SV2_DIV_BCLK (1) | ||
25 | #define S3C_I2SV2_DIV_RCLK (2) | ||
26 | #define S3C_I2SV2_DIV_PRESCALER (3) | ||
27 | |||
28 | /** | ||
29 | * struct s3c_i2sv2_info - S3C I2S-V2 information | ||
30 | * @dev: The parent device passed to use from the probe. | ||
31 | * @regs: The pointer to the device registe block. | ||
32 | * @master: True if the I2S core is the I2S bit clock master. | ||
33 | * @dma_playback: DMA information for playback channel. | ||
34 | * @dma_capture: DMA information for capture channel. | ||
35 | * @suspend_iismod: PM save for the IISMOD register. | ||
36 | * @suspend_iiscon: PM save for the IISCON register. | ||
37 | * @suspend_iispsr: PM save for the IISPSR register. | ||
38 | * | ||
39 | * This is the private codec state for the hardware associated with an | ||
40 | * I2S channel such as the register mappings and clock sources. | ||
41 | */ | ||
42 | struct s3c_i2sv2_info { | ||
43 | struct device *dev; | ||
44 | void __iomem *regs; | ||
45 | |||
46 | struct clk *iis_pclk; | ||
47 | struct clk *iis_cclk; | ||
48 | struct clk *iis_clk; | ||
49 | |||
50 | unsigned char master; | ||
51 | |||
52 | struct s3c24xx_pcm_dma_params *dma_playback; | ||
53 | struct s3c24xx_pcm_dma_params *dma_capture; | ||
54 | |||
55 | u32 suspend_iismod; | ||
56 | u32 suspend_iiscon; | ||
57 | u32 suspend_iispsr; | ||
58 | }; | ||
59 | |||
60 | struct s3c_i2sv2_rate_calc { | ||
61 | unsigned int clk_div; /* for prescaler */ | ||
62 | unsigned int fs_div; /* for root frame clock */ | ||
63 | }; | ||
64 | |||
65 | extern int s3c_i2sv2_iis_calc_rate(struct s3c_i2sv2_rate_calc *info, | ||
66 | unsigned int *fstab, | ||
67 | unsigned int rate, struct clk *clk); | ||
68 | |||
69 | /** | ||
70 | * s3c_i2sv2_probe - probe for i2s device helper | ||
71 | * @pdev: The platform device supplied to the original probe. | ||
72 | * @dai: The ASoC DAI structure supplied to the original probe. | ||
73 | * @i2s: Our local i2s structure to fill in. | ||
74 | * @base: The base address for the registers. | ||
75 | */ | ||
76 | extern int s3c_i2sv2_probe(struct platform_device *pdev, | ||
77 | struct snd_soc_dai *dai, | ||
78 | struct s3c_i2sv2_info *i2s, | ||
79 | unsigned long base); | ||
80 | |||
81 | /** | ||
82 | * s3c_i2sv2_register_dai - register dai with soc core | ||
83 | * @dai: The snd_soc_dai structure to register | ||
84 | * | ||
85 | * Fill in any missing fields and then register the given dai with the | ||
86 | * soc core. | ||
87 | */ | ||
88 | extern int s3c_i2sv2_register_dai(struct snd_soc_dai *dai); | ||
89 | |||
90 | #endif /* __SND_SOC_S3C24XX_S3C_I2SV2_I2S_H */ | ||
diff --git a/sound/soc/s3c24xx/s3c2412-i2s.c b/sound/soc/s3c24xx/s3c2412-i2s.c index f3fc0aba0aaf..1ca3cdaa8213 100644 --- a/sound/soc/s3c24xx/s3c2412-i2s.c +++ b/sound/soc/s3c24xx/s3c2412-i2s.c | |||
@@ -22,6 +22,7 @@ | |||
22 | #include <linux/delay.h> | 22 | #include <linux/delay.h> |
23 | #include <linux/clk.h> | 23 | #include <linux/clk.h> |
24 | #include <linux/kernel.h> | 24 | #include <linux/kernel.h> |
25 | #include <linux/io.h> | ||
25 | 26 | ||
26 | #include <sound/core.h> | 27 | #include <sound/core.h> |
27 | #include <sound/pcm.h> | 28 | #include <sound/pcm.h> |
@@ -30,26 +31,16 @@ | |||
30 | #include <sound/soc.h> | 31 | #include <sound/soc.h> |
31 | #include <mach/hardware.h> | 32 | #include <mach/hardware.h> |
32 | 33 | ||
33 | #include <linux/io.h> | 34 | #include <plat/regs-s3c2412-iis.h> |
34 | #include <asm/dma.h> | ||
35 | |||
36 | #include <asm/plat-s3c24xx/regs-s3c2412-iis.h> | ||
37 | 35 | ||
38 | #include <mach/regs-gpio.h> | 36 | #include <plat/regs-gpio.h> |
39 | #include <mach/audio.h> | 37 | #include <plat/audio.h> |
40 | #include <mach/dma.h> | 38 | #include <mach/dma.h> |
41 | 39 | ||
42 | #include "s3c24xx-pcm.h" | 40 | #include "s3c24xx-pcm.h" |
43 | #include "s3c2412-i2s.h" | 41 | #include "s3c2412-i2s.h" |
44 | 42 | ||
45 | #define S3C2412_I2S_DEBUG 0 | 43 | #define S3C2412_I2S_DEBUG 0 |
46 | #define S3C2412_I2S_DEBUG_CON 0 | ||
47 | |||
48 | #if S3C2412_I2S_DEBUG | ||
49 | #define DBG(x...) printk(KERN_INFO x) | ||
50 | #else | ||
51 | #define DBG(x...) do { } while (0) | ||
52 | #endif | ||
53 | 44 | ||
54 | static struct s3c2410_dma_client s3c2412_dma_client_out = { | 45 | static struct s3c2410_dma_client s3c2412_dma_client_out = { |
55 | .name = "I2S PCM Stereo out" | 46 | .name = "I2S PCM Stereo out" |
@@ -73,431 +64,7 @@ static struct s3c24xx_pcm_dma_params s3c2412_i2s_pcm_stereo_in = { | |||
73 | .dma_size = 4, | 64 | .dma_size = 4, |
74 | }; | 65 | }; |
75 | 66 | ||
76 | struct s3c2412_i2s_info { | 67 | static struct s3c_i2sv2_info s3c2412_i2s; |
77 | struct device *dev; | ||
78 | void __iomem *regs; | ||
79 | struct clk *iis_clk; | ||
80 | struct clk *iis_pclk; | ||
81 | struct clk *iis_cclk; | ||
82 | |||
83 | u32 suspend_iismod; | ||
84 | u32 suspend_iiscon; | ||
85 | u32 suspend_iispsr; | ||
86 | }; | ||
87 | |||
88 | static struct s3c2412_i2s_info s3c2412_i2s; | ||
89 | |||
90 | #define bit_set(v, b) (((v) & (b)) ? 1 : 0) | ||
91 | |||
92 | #if S3C2412_I2S_DEBUG_CON | ||
93 | static void dbg_showcon(const char *fn, u32 con) | ||
94 | { | ||
95 | printk(KERN_DEBUG "%s: LRI=%d, TXFEMPT=%d, RXFEMPT=%d, TXFFULL=%d, RXFFULL=%d\n", fn, | ||
96 | bit_set(con, S3C2412_IISCON_LRINDEX), | ||
97 | bit_set(con, S3C2412_IISCON_TXFIFO_EMPTY), | ||
98 | bit_set(con, S3C2412_IISCON_RXFIFO_EMPTY), | ||
99 | bit_set(con, S3C2412_IISCON_TXFIFO_FULL), | ||
100 | bit_set(con, S3C2412_IISCON_RXFIFO_FULL)); | ||
101 | |||
102 | printk(KERN_DEBUG "%s: PAUSE: TXDMA=%d, RXDMA=%d, TXCH=%d, RXCH=%d\n", | ||
103 | fn, | ||
104 | bit_set(con, S3C2412_IISCON_TXDMA_PAUSE), | ||
105 | bit_set(con, S3C2412_IISCON_RXDMA_PAUSE), | ||
106 | bit_set(con, S3C2412_IISCON_TXCH_PAUSE), | ||
107 | bit_set(con, S3C2412_IISCON_RXCH_PAUSE)); | ||
108 | printk(KERN_DEBUG "%s: ACTIVE: TXDMA=%d, RXDMA=%d, IIS=%d\n", fn, | ||
109 | bit_set(con, S3C2412_IISCON_TXDMA_ACTIVE), | ||
110 | bit_set(con, S3C2412_IISCON_RXDMA_ACTIVE), | ||
111 | bit_set(con, S3C2412_IISCON_IIS_ACTIVE)); | ||
112 | } | ||
113 | #else | ||
114 | static inline void dbg_showcon(const char *fn, u32 con) | ||
115 | { | ||
116 | } | ||
117 | #endif | ||
118 | |||
119 | /* Turn on or off the transmission path. */ | ||
120 | static void s3c2412_snd_txctrl(int on) | ||
121 | { | ||
122 | struct s3c2412_i2s_info *i2s = &s3c2412_i2s; | ||
123 | void __iomem *regs = i2s->regs; | ||
124 | u32 fic, con, mod; | ||
125 | |||
126 | DBG("%s(%d)\n", __func__, on); | ||
127 | |||
128 | fic = readl(regs + S3C2412_IISFIC); | ||
129 | con = readl(regs + S3C2412_IISCON); | ||
130 | mod = readl(regs + S3C2412_IISMOD); | ||
131 | |||
132 | DBG("%s: IIS: CON=%x MOD=%x FIC=%x\n", __func__, con, mod, fic); | ||
133 | |||
134 | if (on) { | ||
135 | con |= S3C2412_IISCON_TXDMA_ACTIVE | S3C2412_IISCON_IIS_ACTIVE; | ||
136 | con &= ~S3C2412_IISCON_TXDMA_PAUSE; | ||
137 | con &= ~S3C2412_IISCON_TXCH_PAUSE; | ||
138 | |||
139 | switch (mod & S3C2412_IISMOD_MODE_MASK) { | ||
140 | case S3C2412_IISMOD_MODE_TXONLY: | ||
141 | case S3C2412_IISMOD_MODE_TXRX: | ||
142 | /* do nothing, we are in the right mode */ | ||
143 | break; | ||
144 | |||
145 | case S3C2412_IISMOD_MODE_RXONLY: | ||
146 | mod &= ~S3C2412_IISMOD_MODE_MASK; | ||
147 | mod |= S3C2412_IISMOD_MODE_TXRX; | ||
148 | break; | ||
149 | |||
150 | default: | ||
151 | dev_err(i2s->dev, "TXEN: Invalid MODE in IISMOD\n"); | ||
152 | } | ||
153 | |||
154 | writel(con, regs + S3C2412_IISCON); | ||
155 | writel(mod, regs + S3C2412_IISMOD); | ||
156 | } else { | ||
157 | /* Note, we do not have any indication that the FIFO problems | ||
158 | * tha the S3C2410/2440 had apply here, so we should be able | ||
159 | * to disable the DMA and TX without resetting the FIFOS. | ||
160 | */ | ||
161 | |||
162 | con |= S3C2412_IISCON_TXDMA_PAUSE; | ||
163 | con |= S3C2412_IISCON_TXCH_PAUSE; | ||
164 | con &= ~S3C2412_IISCON_TXDMA_ACTIVE; | ||
165 | |||
166 | switch (mod & S3C2412_IISMOD_MODE_MASK) { | ||
167 | case S3C2412_IISMOD_MODE_TXRX: | ||
168 | mod &= ~S3C2412_IISMOD_MODE_MASK; | ||
169 | mod |= S3C2412_IISMOD_MODE_RXONLY; | ||
170 | break; | ||
171 | |||
172 | case S3C2412_IISMOD_MODE_TXONLY: | ||
173 | mod &= ~S3C2412_IISMOD_MODE_MASK; | ||
174 | con &= ~S3C2412_IISCON_IIS_ACTIVE; | ||
175 | break; | ||
176 | |||
177 | default: | ||
178 | dev_err(i2s->dev, "TXDIS: Invalid MODE in IISMOD\n"); | ||
179 | } | ||
180 | |||
181 | writel(mod, regs + S3C2412_IISMOD); | ||
182 | writel(con, regs + S3C2412_IISCON); | ||
183 | } | ||
184 | |||
185 | fic = readl(regs + S3C2412_IISFIC); | ||
186 | dbg_showcon(__func__, con); | ||
187 | DBG("%s: IIS: CON=%x MOD=%x FIC=%x\n", __func__, con, mod, fic); | ||
188 | } | ||
189 | |||
190 | static void s3c2412_snd_rxctrl(int on) | ||
191 | { | ||
192 | struct s3c2412_i2s_info *i2s = &s3c2412_i2s; | ||
193 | void __iomem *regs = i2s->regs; | ||
194 | u32 fic, con, mod; | ||
195 | |||
196 | DBG("%s(%d)\n", __func__, on); | ||
197 | |||
198 | fic = readl(regs + S3C2412_IISFIC); | ||
199 | con = readl(regs + S3C2412_IISCON); | ||
200 | mod = readl(regs + S3C2412_IISMOD); | ||
201 | |||
202 | DBG("%s: IIS: CON=%x MOD=%x FIC=%x\n", __func__, con, mod, fic); | ||
203 | |||
204 | if (on) { | ||
205 | con |= S3C2412_IISCON_RXDMA_ACTIVE | S3C2412_IISCON_IIS_ACTIVE; | ||
206 | con &= ~S3C2412_IISCON_RXDMA_PAUSE; | ||
207 | con &= ~S3C2412_IISCON_RXCH_PAUSE; | ||
208 | |||
209 | switch (mod & S3C2412_IISMOD_MODE_MASK) { | ||
210 | case S3C2412_IISMOD_MODE_TXRX: | ||
211 | case S3C2412_IISMOD_MODE_RXONLY: | ||
212 | /* do nothing, we are in the right mode */ | ||
213 | break; | ||
214 | |||
215 | case S3C2412_IISMOD_MODE_TXONLY: | ||
216 | mod &= ~S3C2412_IISMOD_MODE_MASK; | ||
217 | mod |= S3C2412_IISMOD_MODE_TXRX; | ||
218 | break; | ||
219 | |||
220 | default: | ||
221 | dev_err(i2s->dev, "RXEN: Invalid MODE in IISMOD\n"); | ||
222 | } | ||
223 | |||
224 | writel(mod, regs + S3C2412_IISMOD); | ||
225 | writel(con, regs + S3C2412_IISCON); | ||
226 | } else { | ||
227 | /* See txctrl notes on FIFOs. */ | ||
228 | |||
229 | con &= ~S3C2412_IISCON_RXDMA_ACTIVE; | ||
230 | con |= S3C2412_IISCON_RXDMA_PAUSE; | ||
231 | con |= S3C2412_IISCON_RXCH_PAUSE; | ||
232 | |||
233 | switch (mod & S3C2412_IISMOD_MODE_MASK) { | ||
234 | case S3C2412_IISMOD_MODE_RXONLY: | ||
235 | con &= ~S3C2412_IISCON_IIS_ACTIVE; | ||
236 | mod &= ~S3C2412_IISMOD_MODE_MASK; | ||
237 | break; | ||
238 | |||
239 | case S3C2412_IISMOD_MODE_TXRX: | ||
240 | mod &= ~S3C2412_IISMOD_MODE_MASK; | ||
241 | mod |= S3C2412_IISMOD_MODE_TXONLY; | ||
242 | break; | ||
243 | |||
244 | default: | ||
245 | dev_err(i2s->dev, "RXEN: Invalid MODE in IISMOD\n"); | ||
246 | } | ||
247 | |||
248 | writel(con, regs + S3C2412_IISCON); | ||
249 | writel(mod, regs + S3C2412_IISMOD); | ||
250 | } | ||
251 | |||
252 | fic = readl(regs + S3C2412_IISFIC); | ||
253 | DBG("%s: IIS: CON=%x MOD=%x FIC=%x\n", __func__, con, mod, fic); | ||
254 | } | ||
255 | |||
256 | |||
257 | /* | ||
258 | * Wait for the LR signal to allow synchronisation to the L/R clock | ||
259 | * from the codec. May only be needed for slave mode. | ||
260 | */ | ||
261 | static int s3c2412_snd_lrsync(void) | ||
262 | { | ||
263 | u32 iiscon; | ||
264 | unsigned long timeout = jiffies + msecs_to_jiffies(5); | ||
265 | |||
266 | DBG("Entered %s\n", __func__); | ||
267 | |||
268 | while (1) { | ||
269 | iiscon = readl(s3c2412_i2s.regs + S3C2412_IISCON); | ||
270 | if (iiscon & S3C2412_IISCON_LRINDEX) | ||
271 | break; | ||
272 | |||
273 | if (timeout < jiffies) { | ||
274 | printk(KERN_ERR "%s: timeout\n", __func__); | ||
275 | return -ETIMEDOUT; | ||
276 | } | ||
277 | } | ||
278 | |||
279 | return 0; | ||
280 | } | ||
281 | |||
282 | /* | ||
283 | * Check whether CPU is the master or slave | ||
284 | */ | ||
285 | static inline int s3c2412_snd_is_clkmaster(void) | ||
286 | { | ||
287 | u32 iismod = readl(s3c2412_i2s.regs + S3C2412_IISMOD); | ||
288 | |||
289 | DBG("Entered %s\n", __func__); | ||
290 | |||
291 | iismod &= S3C2412_IISMOD_MASTER_MASK; | ||
292 | return !(iismod == S3C2412_IISMOD_SLAVE); | ||
293 | } | ||
294 | |||
295 | /* | ||
296 | * Set S3C2412 I2S DAI format | ||
297 | */ | ||
298 | static int s3c2412_i2s_set_fmt(struct snd_soc_dai *cpu_dai, | ||
299 | unsigned int fmt) | ||
300 | { | ||
301 | u32 iismod; | ||
302 | |||
303 | |||
304 | DBG("Entered %s\n", __func__); | ||
305 | |||
306 | iismod = readl(s3c2412_i2s.regs + S3C2412_IISMOD); | ||
307 | DBG("hw_params r: IISMOD: %x \n", iismod); | ||
308 | |||
309 | switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { | ||
310 | case SND_SOC_DAIFMT_CBM_CFM: | ||
311 | iismod &= ~S3C2412_IISMOD_MASTER_MASK; | ||
312 | iismod |= S3C2412_IISMOD_SLAVE; | ||
313 | break; | ||
314 | case SND_SOC_DAIFMT_CBS_CFS: | ||
315 | iismod &= ~S3C2412_IISMOD_MASTER_MASK; | ||
316 | iismod |= S3C2412_IISMOD_MASTER_INTERNAL; | ||
317 | break; | ||
318 | default: | ||
319 | DBG("unknwon master/slave format\n"); | ||
320 | return -EINVAL; | ||
321 | } | ||
322 | |||
323 | iismod &= ~S3C2412_IISMOD_SDF_MASK; | ||
324 | |||
325 | switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) { | ||
326 | case SND_SOC_DAIFMT_RIGHT_J: | ||
327 | iismod |= S3C2412_IISMOD_SDF_MSB; | ||
328 | break; | ||
329 | case SND_SOC_DAIFMT_LEFT_J: | ||
330 | iismod |= S3C2412_IISMOD_SDF_LSB; | ||
331 | break; | ||
332 | case SND_SOC_DAIFMT_I2S: | ||
333 | iismod |= S3C2412_IISMOD_SDF_IIS; | ||
334 | break; | ||
335 | default: | ||
336 | DBG("Unknown data format\n"); | ||
337 | return -EINVAL; | ||
338 | } | ||
339 | |||
340 | writel(iismod, s3c2412_i2s.regs + S3C2412_IISMOD); | ||
341 | DBG("hw_params w: IISMOD: %x \n", iismod); | ||
342 | return 0; | ||
343 | } | ||
344 | |||
345 | static int s3c2412_i2s_hw_params(struct snd_pcm_substream *substream, | ||
346 | struct snd_pcm_hw_params *params, | ||
347 | struct snd_soc_dai *dai) | ||
348 | { | ||
349 | struct snd_soc_pcm_runtime *rtd = substream->private_data; | ||
350 | u32 iismod; | ||
351 | |||
352 | DBG("Entered %s\n", __func__); | ||
353 | |||
354 | if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) | ||
355 | rtd->dai->cpu_dai->dma_data = &s3c2412_i2s_pcm_stereo_out; | ||
356 | else | ||
357 | rtd->dai->cpu_dai->dma_data = &s3c2412_i2s_pcm_stereo_in; | ||
358 | |||
359 | /* Working copies of register */ | ||
360 | iismod = readl(s3c2412_i2s.regs + S3C2412_IISMOD); | ||
361 | DBG("%s: r: IISMOD: %x\n", __func__, iismod); | ||
362 | |||
363 | switch (params_format(params)) { | ||
364 | case SNDRV_PCM_FORMAT_S8: | ||
365 | iismod |= S3C2412_IISMOD_8BIT; | ||
366 | break; | ||
367 | case SNDRV_PCM_FORMAT_S16_LE: | ||
368 | iismod &= ~S3C2412_IISMOD_8BIT; | ||
369 | break; | ||
370 | } | ||
371 | |||
372 | writel(iismod, s3c2412_i2s.regs + S3C2412_IISMOD); | ||
373 | DBG("%s: w: IISMOD: %x\n", __func__, iismod); | ||
374 | return 0; | ||
375 | } | ||
376 | |||
377 | static int s3c2412_i2s_trigger(struct snd_pcm_substream *substream, int cmd, | ||
378 | struct snd_soc_dai *dai) | ||
379 | { | ||
380 | int capture = (substream->stream == SNDRV_PCM_STREAM_CAPTURE); | ||
381 | unsigned long irqs; | ||
382 | int ret = 0; | ||
383 | |||
384 | DBG("Entered %s\n", __func__); | ||
385 | |||
386 | switch (cmd) { | ||
387 | case SNDRV_PCM_TRIGGER_START: | ||
388 | /* On start, ensure that the FIFOs are cleared and reset. */ | ||
389 | |||
390 | writel(capture ? S3C2412_IISFIC_RXFLUSH : S3C2412_IISFIC_TXFLUSH, | ||
391 | s3c2412_i2s.regs + S3C2412_IISFIC); | ||
392 | |||
393 | /* clear again, just in case */ | ||
394 | writel(0x0, s3c2412_i2s.regs + S3C2412_IISFIC); | ||
395 | |||
396 | case SNDRV_PCM_TRIGGER_RESUME: | ||
397 | case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: | ||
398 | if (!s3c2412_snd_is_clkmaster()) { | ||
399 | ret = s3c2412_snd_lrsync(); | ||
400 | if (ret) | ||
401 | goto exit_err; | ||
402 | } | ||
403 | |||
404 | local_irq_save(irqs); | ||
405 | |||
406 | if (capture) | ||
407 | s3c2412_snd_rxctrl(1); | ||
408 | else | ||
409 | s3c2412_snd_txctrl(1); | ||
410 | |||
411 | local_irq_restore(irqs); | ||
412 | break; | ||
413 | |||
414 | case SNDRV_PCM_TRIGGER_STOP: | ||
415 | case SNDRV_PCM_TRIGGER_SUSPEND: | ||
416 | case SNDRV_PCM_TRIGGER_PAUSE_PUSH: | ||
417 | local_irq_save(irqs); | ||
418 | |||
419 | if (capture) | ||
420 | s3c2412_snd_rxctrl(0); | ||
421 | else | ||
422 | s3c2412_snd_txctrl(0); | ||
423 | |||
424 | local_irq_restore(irqs); | ||
425 | break; | ||
426 | default: | ||
427 | ret = -EINVAL; | ||
428 | break; | ||
429 | } | ||
430 | |||
431 | exit_err: | ||
432 | return ret; | ||
433 | } | ||
434 | |||
435 | /* default table of all avaialable root fs divisors */ | ||
436 | static unsigned int s3c2412_iis_fs[] = { 256, 512, 384, 768, 0 }; | ||
437 | |||
438 | int s3c2412_iis_calc_rate(struct s3c2412_rate_calc *info, | ||
439 | unsigned int *fstab, | ||
440 | unsigned int rate, struct clk *clk) | ||
441 | { | ||
442 | unsigned long clkrate = clk_get_rate(clk); | ||
443 | unsigned int div; | ||
444 | unsigned int fsclk; | ||
445 | unsigned int actual; | ||
446 | unsigned int fs; | ||
447 | unsigned int fsdiv; | ||
448 | signed int deviation = 0; | ||
449 | unsigned int best_fs = 0; | ||
450 | unsigned int best_div = 0; | ||
451 | unsigned int best_rate = 0; | ||
452 | unsigned int best_deviation = INT_MAX; | ||
453 | |||
454 | |||
455 | if (fstab == NULL) | ||
456 | fstab = s3c2412_iis_fs; | ||
457 | |||
458 | for (fs = 0;; fs++) { | ||
459 | fsdiv = s3c2412_iis_fs[fs]; | ||
460 | |||
461 | if (fsdiv == 0) | ||
462 | break; | ||
463 | |||
464 | fsclk = clkrate / fsdiv; | ||
465 | div = fsclk / rate; | ||
466 | |||
467 | if ((fsclk % rate) > (rate / 2)) | ||
468 | div++; | ||
469 | |||
470 | if (div <= 1) | ||
471 | continue; | ||
472 | |||
473 | actual = clkrate / (fsdiv * div); | ||
474 | deviation = actual - rate; | ||
475 | |||
476 | printk(KERN_DEBUG "%dfs: div %d => result %d, deviation %d\n", | ||
477 | fsdiv, div, actual, deviation); | ||
478 | |||
479 | deviation = abs(deviation); | ||
480 | |||
481 | if (deviation < best_deviation) { | ||
482 | best_fs = fsdiv; | ||
483 | best_div = div; | ||
484 | best_rate = actual; | ||
485 | best_deviation = deviation; | ||
486 | } | ||
487 | |||
488 | if (deviation == 0) | ||
489 | break; | ||
490 | } | ||
491 | |||
492 | printk(KERN_DEBUG "best: fs=%d, div=%d, rate=%d\n", | ||
493 | best_fs, best_div, best_rate); | ||
494 | |||
495 | info->fs_div = best_fs; | ||
496 | info->clk_div = best_div; | ||
497 | |||
498 | return 0; | ||
499 | } | ||
500 | EXPORT_SYMBOL_GPL(s3c2412_iis_calc_rate); | ||
501 | 68 | ||
502 | /* | 69 | /* |
503 | * Set S3C2412 Clock source | 70 | * Set S3C2412 Clock source |
@@ -507,15 +74,17 @@ static int s3c2412_i2s_set_sysclk(struct snd_soc_dai *cpu_dai, | |||
507 | { | 74 | { |
508 | u32 iismod = readl(s3c2412_i2s.regs + S3C2412_IISMOD); | 75 | u32 iismod = readl(s3c2412_i2s.regs + S3C2412_IISMOD); |
509 | 76 | ||
510 | DBG("%s(%p, %d, %u, %d)\n", __func__, cpu_dai, clk_id, | 77 | pr_debug("%s(%p, %d, %u, %d)\n", __func__, cpu_dai, clk_id, |
511 | freq, dir); | 78 | freq, dir); |
512 | 79 | ||
513 | switch (clk_id) { | 80 | switch (clk_id) { |
514 | case S3C2412_CLKSRC_PCLK: | 81 | case S3C2412_CLKSRC_PCLK: |
82 | s3c2412_i2s.master = 1; | ||
515 | iismod &= ~S3C2412_IISMOD_MASTER_MASK; | 83 | iismod &= ~S3C2412_IISMOD_MASTER_MASK; |
516 | iismod |= S3C2412_IISMOD_MASTER_INTERNAL; | 84 | iismod |= S3C2412_IISMOD_MASTER_INTERNAL; |
517 | break; | 85 | break; |
518 | case S3C2412_CLKSRC_I2SCLK: | 86 | case S3C2412_CLKSRC_I2SCLK: |
87 | s3c2412_i2s.master = 0; | ||
519 | iismod &= ~S3C2412_IISMOD_MASTER_MASK; | 88 | iismod &= ~S3C2412_IISMOD_MASTER_MASK; |
520 | iismod |= S3C2412_IISMOD_MASTER_EXTERNAL; | 89 | iismod |= S3C2412_IISMOD_MASTER_EXTERNAL; |
521 | break; | 90 | break; |
@@ -527,74 +96,6 @@ static int s3c2412_i2s_set_sysclk(struct snd_soc_dai *cpu_dai, | |||
527 | return 0; | 96 | return 0; |
528 | } | 97 | } |
529 | 98 | ||
530 | /* | ||
531 | * Set S3C2412 Clock dividers | ||
532 | */ | ||
533 | static int s3c2412_i2s_set_clkdiv(struct snd_soc_dai *cpu_dai, | ||
534 | int div_id, int div) | ||
535 | { | ||
536 | struct s3c2412_i2s_info *i2s = &s3c2412_i2s; | ||
537 | u32 reg; | ||
538 | |||
539 | DBG("%s(%p, %d, %d)\n", __func__, cpu_dai, div_id, div); | ||
540 | |||
541 | switch (div_id) { | ||
542 | case S3C2412_DIV_BCLK: | ||
543 | reg = readl(i2s->regs + S3C2412_IISMOD); | ||
544 | reg &= ~S3C2412_IISMOD_BCLK_MASK; | ||
545 | writel(reg | div, i2s->regs + S3C2412_IISMOD); | ||
546 | |||
547 | DBG("%s: MOD=%08x\n", __func__, readl(i2s->regs + S3C2412_IISMOD)); | ||
548 | break; | ||
549 | |||
550 | case S3C2412_DIV_RCLK: | ||
551 | if (div > 3) { | ||
552 | /* convert value to bit field */ | ||
553 | |||
554 | switch (div) { | ||
555 | case 256: | ||
556 | div = S3C2412_IISMOD_RCLK_256FS; | ||
557 | break; | ||
558 | |||
559 | case 384: | ||
560 | div = S3C2412_IISMOD_RCLK_384FS; | ||
561 | break; | ||
562 | |||
563 | case 512: | ||
564 | div = S3C2412_IISMOD_RCLK_512FS; | ||
565 | break; | ||
566 | |||
567 | case 768: | ||
568 | div = S3C2412_IISMOD_RCLK_768FS; | ||
569 | break; | ||
570 | |||
571 | default: | ||
572 | return -EINVAL; | ||
573 | } | ||
574 | } | ||
575 | |||
576 | reg = readl(s3c2412_i2s.regs + S3C2412_IISMOD); | ||
577 | reg &= ~S3C2412_IISMOD_RCLK_MASK; | ||
578 | writel(reg | div, i2s->regs + S3C2412_IISMOD); | ||
579 | DBG("%s: MOD=%08x\n", __func__, readl(i2s->regs + S3C2412_IISMOD)); | ||
580 | break; | ||
581 | |||
582 | case S3C2412_DIV_PRESCALER: | ||
583 | if (div >= 0) { | ||
584 | writel((div << 8) | S3C2412_IISPSR_PSREN, | ||
585 | i2s->regs + S3C2412_IISPSR); | ||
586 | } else { | ||
587 | writel(0x0, i2s->regs + S3C2412_IISPSR); | ||
588 | } | ||
589 | DBG("%s: PSR=%08x\n", __func__, readl(i2s->regs + S3C2412_IISPSR)); | ||
590 | break; | ||
591 | |||
592 | default: | ||
593 | return -EINVAL; | ||
594 | } | ||
595 | |||
596 | return 0; | ||
597 | } | ||
598 | 99 | ||
599 | struct clk *s3c2412_get_iisclk(void) | 100 | struct clk *s3c2412_get_iisclk(void) |
600 | { | 101 | { |
@@ -606,34 +107,30 @@ EXPORT_SYMBOL_GPL(s3c2412_get_iisclk); | |||
606 | static int s3c2412_i2s_probe(struct platform_device *pdev, | 107 | static int s3c2412_i2s_probe(struct platform_device *pdev, |
607 | struct snd_soc_dai *dai) | 108 | struct snd_soc_dai *dai) |
608 | { | 109 | { |
609 | DBG("Entered %s\n", __func__); | 110 | int ret; |
610 | 111 | ||
611 | s3c2412_i2s.dev = &pdev->dev; | 112 | pr_debug("Entered %s\n", __func__); |
612 | 113 | ||
613 | s3c2412_i2s.regs = ioremap(S3C2410_PA_IIS, 0x100); | 114 | ret = s3c_i2sv2_probe(pdev, dai, &s3c2412_i2s, S3C2410_PA_IIS); |
614 | if (s3c2412_i2s.regs == NULL) | 115 | if (ret) |
615 | return -ENXIO; | 116 | return ret; |
616 | 117 | ||
617 | s3c2412_i2s.iis_pclk = clk_get(&pdev->dev, "iis"); | 118 | s3c2412_i2s.dma_capture = &s3c2412_i2s_pcm_stereo_in; |
618 | if (s3c2412_i2s.iis_pclk == NULL) { | 119 | s3c2412_i2s.dma_playback = &s3c2412_i2s_pcm_stereo_out; |
619 | DBG("failed to get iis_clock\n"); | ||
620 | iounmap(s3c2412_i2s.regs); | ||
621 | return -ENODEV; | ||
622 | } | ||
623 | 120 | ||
624 | s3c2412_i2s.iis_cclk = clk_get(&pdev->dev, "i2sclk"); | 121 | s3c2412_i2s.iis_cclk = clk_get(&pdev->dev, "i2sclk"); |
625 | if (s3c2412_i2s.iis_cclk == NULL) { | 122 | if (s3c2412_i2s.iis_cclk == NULL) { |
626 | DBG("failed to get i2sclk clock\n"); | 123 | pr_debug("failed to get i2sclk clock\n"); |
627 | iounmap(s3c2412_i2s.regs); | 124 | iounmap(s3c2412_i2s.regs); |
628 | return -ENODEV; | 125 | return -ENODEV; |
629 | } | 126 | } |
630 | 127 | ||
631 | clk_set_parent(s3c2412_i2s.iis_cclk, clk_get(NULL, "mpll")); | 128 | /* Set MPLL as the source for IIS CLK */ |
632 | 129 | ||
633 | clk_enable(s3c2412_i2s.iis_pclk); | 130 | clk_set_parent(s3c2412_i2s.iis_cclk, clk_get(NULL, "mpll")); |
634 | clk_enable(s3c2412_i2s.iis_cclk); | 131 | clk_enable(s3c2412_i2s.iis_cclk); |
635 | 132 | ||
636 | s3c2412_i2s.iis_clk = s3c2412_i2s.iis_pclk; | 133 | s3c2412_i2s.iis_cclk = s3c2412_i2s.iis_pclk; |
637 | 134 | ||
638 | /* Configure the I2S pins in correct mode */ | 135 | /* Configure the I2S pins in correct mode */ |
639 | s3c2410_gpio_cfgpin(S3C2410_GPE0, S3C2410_GPE0_I2SLRCK); | 136 | s3c2410_gpio_cfgpin(S3C2410_GPE0, S3C2410_GPE0_I2SLRCK); |
@@ -642,78 +139,22 @@ static int s3c2412_i2s_probe(struct platform_device *pdev, | |||
642 | s3c2410_gpio_cfgpin(S3C2410_GPE3, S3C2410_GPE3_I2SSDI); | 139 | s3c2410_gpio_cfgpin(S3C2410_GPE3, S3C2410_GPE3_I2SSDI); |
643 | s3c2410_gpio_cfgpin(S3C2410_GPE4, S3C2410_GPE4_I2SSDO); | 140 | s3c2410_gpio_cfgpin(S3C2410_GPE4, S3C2410_GPE4_I2SSDO); |
644 | 141 | ||
645 | s3c2412_snd_txctrl(0); | ||
646 | s3c2412_snd_rxctrl(0); | ||
647 | |||
648 | return 0; | 142 | return 0; |
649 | } | 143 | } |
650 | 144 | ||
651 | #ifdef CONFIG_PM | ||
652 | static int s3c2412_i2s_suspend(struct snd_soc_dai *dai) | ||
653 | { | ||
654 | struct s3c2412_i2s_info *i2s = &s3c2412_i2s; | ||
655 | u32 iismod; | ||
656 | |||
657 | if (dai->active) { | ||
658 | i2s->suspend_iismod = readl(i2s->regs + S3C2412_IISMOD); | ||
659 | i2s->suspend_iiscon = readl(i2s->regs + S3C2412_IISCON); | ||
660 | i2s->suspend_iispsr = readl(i2s->regs + S3C2412_IISPSR); | ||
661 | |||
662 | /* some basic suspend checks */ | ||
663 | |||
664 | iismod = readl(i2s->regs + S3C2412_IISMOD); | ||
665 | |||
666 | if (iismod & S3C2412_IISCON_RXDMA_ACTIVE) | ||
667 | pr_warning("%s: RXDMA active?\n", __func__); | ||
668 | |||
669 | if (iismod & S3C2412_IISCON_TXDMA_ACTIVE) | ||
670 | pr_warning("%s: TXDMA active?\n", __func__); | ||
671 | |||
672 | if (iismod & S3C2412_IISCON_IIS_ACTIVE) | ||
673 | pr_warning("%s: IIS active\n", __func__); | ||
674 | } | ||
675 | |||
676 | return 0; | ||
677 | } | ||
678 | |||
679 | static int s3c2412_i2s_resume(struct snd_soc_dai *dai) | ||
680 | { | ||
681 | struct s3c2412_i2s_info *i2s = &s3c2412_i2s; | ||
682 | |||
683 | pr_info("dai_active %d, IISMOD %08x, IISCON %08x\n", | ||
684 | dai->active, i2s->suspend_iismod, i2s->suspend_iiscon); | ||
685 | |||
686 | if (dai->active) { | ||
687 | writel(i2s->suspend_iiscon, i2s->regs + S3C2412_IISCON); | ||
688 | writel(i2s->suspend_iismod, i2s->regs + S3C2412_IISMOD); | ||
689 | writel(i2s->suspend_iispsr, i2s->regs + S3C2412_IISPSR); | ||
690 | |||
691 | writel(S3C2412_IISFIC_RXFLUSH | S3C2412_IISFIC_TXFLUSH, | ||
692 | i2s->regs + S3C2412_IISFIC); | ||
693 | |||
694 | ndelay(250); | ||
695 | writel(0x0, i2s->regs + S3C2412_IISFIC); | ||
696 | |||
697 | } | ||
698 | |||
699 | return 0; | ||
700 | } | ||
701 | #else | ||
702 | #define s3c2412_i2s_suspend NULL | ||
703 | #define s3c2412_i2s_resume NULL | ||
704 | #endif /* CONFIG_PM */ | ||
705 | |||
706 | #define S3C2412_I2S_RATES \ | 145 | #define S3C2412_I2S_RATES \ |
707 | (SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_11025 | SNDRV_PCM_RATE_16000 | \ | 146 | (SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_11025 | SNDRV_PCM_RATE_16000 | \ |
708 | SNDRV_PCM_RATE_22050 | SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_44100 | \ | 147 | SNDRV_PCM_RATE_22050 | SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_44100 | \ |
709 | SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_88200 | SNDRV_PCM_RATE_96000) | 148 | SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_88200 | SNDRV_PCM_RATE_96000) |
710 | 149 | ||
150 | static struct snd_soc_dai_ops s3c2412_i2s_dai_ops = { | ||
151 | .set_sysclk = s3c2412_i2s_set_sysclk, | ||
152 | }; | ||
153 | |||
711 | struct snd_soc_dai s3c2412_i2s_dai = { | 154 | struct snd_soc_dai s3c2412_i2s_dai = { |
712 | .name = "s3c2412-i2s", | 155 | .name = "s3c2412-i2s", |
713 | .id = 0, | 156 | .id = 0, |
714 | .probe = s3c2412_i2s_probe, | 157 | .probe = s3c2412_i2s_probe, |
715 | .suspend = s3c2412_i2s_suspend, | ||
716 | .resume = s3c2412_i2s_resume, | ||
717 | .playback = { | 158 | .playback = { |
718 | .channels_min = 2, | 159 | .channels_min = 2, |
719 | .channels_max = 2, | 160 | .channels_max = 2, |
@@ -726,19 +167,13 @@ struct snd_soc_dai s3c2412_i2s_dai = { | |||
726 | .rates = S3C2412_I2S_RATES, | 167 | .rates = S3C2412_I2S_RATES, |
727 | .formats = SNDRV_PCM_FMTBIT_S8 | SNDRV_PCM_FMTBIT_S16_LE, | 168 | .formats = SNDRV_PCM_FMTBIT_S8 | SNDRV_PCM_FMTBIT_S16_LE, |
728 | }, | 169 | }, |
729 | .ops = { | 170 | .ops = &s3c2412_i2s_dai_ops, |
730 | .trigger = s3c2412_i2s_trigger, | ||
731 | .hw_params = s3c2412_i2s_hw_params, | ||
732 | .set_fmt = s3c2412_i2s_set_fmt, | ||
733 | .set_clkdiv = s3c2412_i2s_set_clkdiv, | ||
734 | .set_sysclk = s3c2412_i2s_set_sysclk, | ||
735 | }, | ||
736 | }; | 171 | }; |
737 | EXPORT_SYMBOL_GPL(s3c2412_i2s_dai); | 172 | EXPORT_SYMBOL_GPL(s3c2412_i2s_dai); |
738 | 173 | ||
739 | static int __init s3c2412_i2s_init(void) | 174 | static int __init s3c2412_i2s_init(void) |
740 | { | 175 | { |
741 | return snd_soc_register_dai(&s3c2412_i2s_dai); | 176 | return s3c_i2sv2_register_dai(&s3c2412_i2s_dai); |
742 | } | 177 | } |
743 | module_init(s3c2412_i2s_init); | 178 | module_init(s3c2412_i2s_init); |
744 | 179 | ||
@@ -748,7 +183,6 @@ static void __exit s3c2412_i2s_exit(void) | |||
748 | } | 183 | } |
749 | module_exit(s3c2412_i2s_exit); | 184 | module_exit(s3c2412_i2s_exit); |
750 | 185 | ||
751 | |||
752 | /* Module information */ | 186 | /* Module information */ |
753 | MODULE_AUTHOR("Ben Dooks, <ben@simtec.co.uk>"); | 187 | MODULE_AUTHOR("Ben Dooks, <ben@simtec.co.uk>"); |
754 | MODULE_DESCRIPTION("S3C2412 I2S SoC Interface"); | 188 | MODULE_DESCRIPTION("S3C2412 I2S SoC Interface"); |
diff --git a/sound/soc/s3c24xx/s3c2412-i2s.h b/sound/soc/s3c24xx/s3c2412-i2s.h index aac08a25e541..92848e54be16 100644 --- a/sound/soc/s3c24xx/s3c2412-i2s.h +++ b/sound/soc/s3c24xx/s3c2412-i2s.h | |||
@@ -15,9 +15,11 @@ | |||
15 | #ifndef __SND_SOC_S3C24XX_S3C2412_I2S_H | 15 | #ifndef __SND_SOC_S3C24XX_S3C2412_I2S_H |
16 | #define __SND_SOC_S3C24XX_S3C2412_I2S_H __FILE__ | 16 | #define __SND_SOC_S3C24XX_S3C2412_I2S_H __FILE__ |
17 | 17 | ||
18 | #define S3C2412_DIV_BCLK (1) | 18 | #include "s3c-i2s-v2.h" |
19 | #define S3C2412_DIV_RCLK (2) | 19 | |
20 | #define S3C2412_DIV_PRESCALER (3) | 20 | #define S3C2412_DIV_BCLK S3C_I2SV2_DIV_BCLK |
21 | #define S3C2412_DIV_RCLK S3C_I2SV2_DIV_RCLK | ||
22 | #define S3C2412_DIV_PRESCALER S3C_I2SV2_DIV_PRESCALER | ||
21 | 23 | ||
22 | #define S3C2412_CLKSRC_PCLK (0) | 24 | #define S3C2412_CLKSRC_PCLK (0) |
23 | #define S3C2412_CLKSRC_I2SCLK (1) | 25 | #define S3C2412_CLKSRC_I2SCLK (1) |
@@ -26,13 +28,4 @@ extern struct clk *s3c2412_get_iisclk(void); | |||
26 | 28 | ||
27 | extern struct snd_soc_dai s3c2412_i2s_dai; | 29 | extern struct snd_soc_dai s3c2412_i2s_dai; |
28 | 30 | ||
29 | struct s3c2412_rate_calc { | ||
30 | unsigned int clk_div; /* for prescaler */ | ||
31 | unsigned int fs_div; /* for root frame clock */ | ||
32 | }; | ||
33 | |||
34 | extern int s3c2412_iis_calc_rate(struct s3c2412_rate_calc *info, | ||
35 | unsigned int *fstab, | ||
36 | unsigned int rate, struct clk *clk); | ||
37 | |||
38 | #endif /* __SND_SOC_S3C24XX_S3C2412_I2S_H */ | 31 | #endif /* __SND_SOC_S3C24XX_S3C2412_I2S_H */ |
diff --git a/sound/soc/s3c24xx/s3c2443-ac97.c b/sound/soc/s3c24xx/s3c2443-ac97.c index 5822d2dd49ba..3698f707c44d 100644 --- a/sound/soc/s3c24xx/s3c2443-ac97.c +++ b/sound/soc/s3c24xx/s3c2443-ac97.c | |||
@@ -31,7 +31,7 @@ | |||
31 | #include <plat/regs-ac97.h> | 31 | #include <plat/regs-ac97.h> |
32 | #include <mach/regs-gpio.h> | 32 | #include <mach/regs-gpio.h> |
33 | #include <mach/regs-clock.h> | 33 | #include <mach/regs-clock.h> |
34 | #include <mach/audio.h> | 34 | #include <plat/audio.h> |
35 | #include <asm/dma.h> | 35 | #include <asm/dma.h> |
36 | #include <mach/dma.h> | 36 | #include <mach/dma.h> |
37 | 37 | ||
@@ -355,6 +355,16 @@ static int s3c2443_ac97_mic_trigger(struct snd_pcm_substream *substream, | |||
355 | SNDRV_PCM_RATE_16000 | SNDRV_PCM_RATE_22050 | \ | 355 | SNDRV_PCM_RATE_16000 | SNDRV_PCM_RATE_22050 | \ |
356 | SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000) | 356 | SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000) |
357 | 357 | ||
358 | static struct snd_soc_dai_ops s3c2443_ac97_dai_ops = { | ||
359 | .hw_params = s3c2443_ac97_hw_params, | ||
360 | .trigger = s3c2443_ac97_trigger, | ||
361 | }; | ||
362 | |||
363 | static struct snd_soc_dai_ops s3c2443_ac97_mic_dai_ops = { | ||
364 | .hw_params = s3c2443_ac97_hw_mic_params, | ||
365 | .trigger = s3c2443_ac97_mic_trigger, | ||
366 | }; | ||
367 | |||
358 | struct snd_soc_dai s3c2443_ac97_dai[] = { | 368 | struct snd_soc_dai s3c2443_ac97_dai[] = { |
359 | { | 369 | { |
360 | .name = "s3c2443-ac97", | 370 | .name = "s3c2443-ac97", |
@@ -374,9 +384,7 @@ struct snd_soc_dai s3c2443_ac97_dai[] = { | |||
374 | .channels_max = 2, | 384 | .channels_max = 2, |
375 | .rates = s3c2443_AC97_RATES, | 385 | .rates = s3c2443_AC97_RATES, |
376 | .formats = SNDRV_PCM_FMTBIT_S16_LE,}, | 386 | .formats = SNDRV_PCM_FMTBIT_S16_LE,}, |
377 | .ops = { | 387 | .ops = &s3c2443_ac97_dai_ops, |
378 | .hw_params = s3c2443_ac97_hw_params, | ||
379 | .trigger = s3c2443_ac97_trigger}, | ||
380 | }, | 388 | }, |
381 | { | 389 | { |
382 | .name = "pxa2xx-ac97-mic", | 390 | .name = "pxa2xx-ac97-mic", |
@@ -388,9 +396,7 @@ struct snd_soc_dai s3c2443_ac97_dai[] = { | |||
388 | .channels_max = 1, | 396 | .channels_max = 1, |
389 | .rates = s3c2443_AC97_RATES, | 397 | .rates = s3c2443_AC97_RATES, |
390 | .formats = SNDRV_PCM_FMTBIT_S16_LE,}, | 398 | .formats = SNDRV_PCM_FMTBIT_S16_LE,}, |
391 | .ops = { | 399 | .ops = &s3c2443_ac97_mic_dai_ops, |
392 | .hw_params = s3c2443_ac97_hw_mic_params, | ||
393 | .trigger = s3c2443_ac97_mic_trigger,}, | ||
394 | }, | 400 | }, |
395 | }; | 401 | }; |
396 | EXPORT_SYMBOL_GPL(s3c2443_ac97_dai); | 402 | EXPORT_SYMBOL_GPL(s3c2443_ac97_dai); |
diff --git a/sound/soc/s3c24xx/s3c24xx-i2s.c b/sound/soc/s3c24xx/s3c24xx-i2s.c index 6f4d439b57aa..cc066964dad6 100644 --- a/sound/soc/s3c24xx/s3c24xx-i2s.c +++ b/sound/soc/s3c24xx/s3c24xx-i2s.c | |||
@@ -4,7 +4,7 @@ | |||
4 | * (c) 2006 Wolfson Microelectronics PLC. | 4 | * (c) 2006 Wolfson Microelectronics PLC. |
5 | * Graeme Gregory graeme.gregory@wolfsonmicro.com or linux@wolfsonmicro.com | 5 | * Graeme Gregory graeme.gregory@wolfsonmicro.com or linux@wolfsonmicro.com |
6 | * | 6 | * |
7 | * (c) 2004-2005 Simtec Electronics | 7 | * Copyright 2004-2005 Simtec Electronics |
8 | * http://armlinux.simtec.co.uk/ | 8 | * http://armlinux.simtec.co.uk/ |
9 | * Ben Dooks <ben@simtec.co.uk> | 9 | * Ben Dooks <ben@simtec.co.uk> |
10 | * | 10 | * |
@@ -30,22 +30,15 @@ | |||
30 | #include <mach/hardware.h> | 30 | #include <mach/hardware.h> |
31 | #include <mach/regs-gpio.h> | 31 | #include <mach/regs-gpio.h> |
32 | #include <mach/regs-clock.h> | 32 | #include <mach/regs-clock.h> |
33 | #include <mach/audio.h> | 33 | #include <plat/audio.h> |
34 | #include <asm/dma.h> | 34 | #include <asm/dma.h> |
35 | #include <mach/dma.h> | 35 | #include <mach/dma.h> |
36 | 36 | ||
37 | #include <asm/plat-s3c24xx/regs-iis.h> | 37 | #include <plat/regs-iis.h> |
38 | 38 | ||
39 | #include "s3c24xx-pcm.h" | 39 | #include "s3c24xx-pcm.h" |
40 | #include "s3c24xx-i2s.h" | 40 | #include "s3c24xx-i2s.h" |
41 | 41 | ||
42 | #define S3C24XX_I2S_DEBUG 0 | ||
43 | #if S3C24XX_I2S_DEBUG | ||
44 | #define DBG(x...) printk(KERN_DEBUG "s3c24xx-i2s: " x) | ||
45 | #else | ||
46 | #define DBG(x...) | ||
47 | #endif | ||
48 | |||
49 | static struct s3c2410_dma_client s3c24xx_dma_client_out = { | 42 | static struct s3c2410_dma_client s3c24xx_dma_client_out = { |
50 | .name = "I2S PCM Stereo out" | 43 | .name = "I2S PCM Stereo out" |
51 | }; | 44 | }; |
@@ -84,13 +77,13 @@ static void s3c24xx_snd_txctrl(int on) | |||
84 | u32 iiscon; | 77 | u32 iiscon; |
85 | u32 iismod; | 78 | u32 iismod; |
86 | 79 | ||
87 | DBG("Entered %s\n", __func__); | 80 | pr_debug("Entered %s\n", __func__); |
88 | 81 | ||
89 | iisfcon = readl(s3c24xx_i2s.regs + S3C2410_IISFCON); | 82 | iisfcon = readl(s3c24xx_i2s.regs + S3C2410_IISFCON); |
90 | iiscon = readl(s3c24xx_i2s.regs + S3C2410_IISCON); | 83 | iiscon = readl(s3c24xx_i2s.regs + S3C2410_IISCON); |
91 | iismod = readl(s3c24xx_i2s.regs + S3C2410_IISMOD); | 84 | iismod = readl(s3c24xx_i2s.regs + S3C2410_IISMOD); |
92 | 85 | ||
93 | DBG("r: IISCON: %lx IISMOD: %lx IISFCON: %lx\n", iiscon, iismod, iisfcon); | 86 | pr_debug("r: IISCON: %x IISMOD: %x IISFCON: %x\n", iiscon, iismod, iisfcon); |
94 | 87 | ||
95 | if (on) { | 88 | if (on) { |
96 | iisfcon |= S3C2410_IISFCON_TXDMA | S3C2410_IISFCON_TXENABLE; | 89 | iisfcon |= S3C2410_IISFCON_TXDMA | S3C2410_IISFCON_TXENABLE; |
@@ -120,7 +113,7 @@ static void s3c24xx_snd_txctrl(int on) | |||
120 | writel(iismod, s3c24xx_i2s.regs + S3C2410_IISMOD); | 113 | writel(iismod, s3c24xx_i2s.regs + S3C2410_IISMOD); |
121 | } | 114 | } |
122 | 115 | ||
123 | DBG("w: IISCON: %lx IISMOD: %lx IISFCON: %lx\n", iiscon, iismod, iisfcon); | 116 | pr_debug("w: IISCON: %x IISMOD: %x IISFCON: %x\n", iiscon, iismod, iisfcon); |
124 | } | 117 | } |
125 | 118 | ||
126 | static void s3c24xx_snd_rxctrl(int on) | 119 | static void s3c24xx_snd_rxctrl(int on) |
@@ -129,13 +122,13 @@ static void s3c24xx_snd_rxctrl(int on) | |||
129 | u32 iiscon; | 122 | u32 iiscon; |
130 | u32 iismod; | 123 | u32 iismod; |
131 | 124 | ||
132 | DBG("Entered %s\n", __func__); | 125 | pr_debug("Entered %s\n", __func__); |
133 | 126 | ||
134 | iisfcon = readl(s3c24xx_i2s.regs + S3C2410_IISFCON); | 127 | iisfcon = readl(s3c24xx_i2s.regs + S3C2410_IISFCON); |
135 | iiscon = readl(s3c24xx_i2s.regs + S3C2410_IISCON); | 128 | iiscon = readl(s3c24xx_i2s.regs + S3C2410_IISCON); |
136 | iismod = readl(s3c24xx_i2s.regs + S3C2410_IISMOD); | 129 | iismod = readl(s3c24xx_i2s.regs + S3C2410_IISMOD); |
137 | 130 | ||
138 | DBG("r: IISCON: %lx IISMOD: %lx IISFCON: %lx\n", iiscon, iismod, iisfcon); | 131 | pr_debug("r: IISCON: %x IISMOD: %x IISFCON: %x\n", iiscon, iismod, iisfcon); |
139 | 132 | ||
140 | if (on) { | 133 | if (on) { |
141 | iisfcon |= S3C2410_IISFCON_RXDMA | S3C2410_IISFCON_RXENABLE; | 134 | iisfcon |= S3C2410_IISFCON_RXDMA | S3C2410_IISFCON_RXENABLE; |
@@ -165,7 +158,7 @@ static void s3c24xx_snd_rxctrl(int on) | |||
165 | writel(iismod, s3c24xx_i2s.regs + S3C2410_IISMOD); | 158 | writel(iismod, s3c24xx_i2s.regs + S3C2410_IISMOD); |
166 | } | 159 | } |
167 | 160 | ||
168 | DBG("w: IISCON: %lx IISMOD: %lx IISFCON: %lx\n", iiscon, iismod, iisfcon); | 161 | pr_debug("w: IISCON: %x IISMOD: %x IISFCON: %x\n", iiscon, iismod, iisfcon); |
169 | } | 162 | } |
170 | 163 | ||
171 | /* | 164 | /* |
@@ -177,7 +170,7 @@ static int s3c24xx_snd_lrsync(void) | |||
177 | u32 iiscon; | 170 | u32 iiscon; |
178 | int timeout = 50; /* 5ms */ | 171 | int timeout = 50; /* 5ms */ |
179 | 172 | ||
180 | DBG("Entered %s\n", __func__); | 173 | pr_debug("Entered %s\n", __func__); |
181 | 174 | ||
182 | while (1) { | 175 | while (1) { |
183 | iiscon = readl(s3c24xx_i2s.regs + S3C2410_IISCON); | 176 | iiscon = readl(s3c24xx_i2s.regs + S3C2410_IISCON); |
@@ -197,7 +190,7 @@ static int s3c24xx_snd_lrsync(void) | |||
197 | */ | 190 | */ |
198 | static inline int s3c24xx_snd_is_clkmaster(void) | 191 | static inline int s3c24xx_snd_is_clkmaster(void) |
199 | { | 192 | { |
200 | DBG("Entered %s\n", __func__); | 193 | pr_debug("Entered %s\n", __func__); |
201 | 194 | ||
202 | return (readl(s3c24xx_i2s.regs + S3C2410_IISMOD) & S3C2410_IISMOD_SLAVE) ? 0:1; | 195 | return (readl(s3c24xx_i2s.regs + S3C2410_IISMOD) & S3C2410_IISMOD_SLAVE) ? 0:1; |
203 | } | 196 | } |
@@ -210,10 +203,10 @@ static int s3c24xx_i2s_set_fmt(struct snd_soc_dai *cpu_dai, | |||
210 | { | 203 | { |
211 | u32 iismod; | 204 | u32 iismod; |
212 | 205 | ||
213 | DBG("Entered %s\n", __func__); | 206 | pr_debug("Entered %s\n", __func__); |
214 | 207 | ||
215 | iismod = readl(s3c24xx_i2s.regs + S3C2410_IISMOD); | 208 | iismod = readl(s3c24xx_i2s.regs + S3C2410_IISMOD); |
216 | DBG("hw_params r: IISMOD: %lx \n", iismod); | 209 | pr_debug("hw_params r: IISMOD: %x \n", iismod); |
217 | 210 | ||
218 | switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { | 211 | switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { |
219 | case SND_SOC_DAIFMT_CBM_CFM: | 212 | case SND_SOC_DAIFMT_CBM_CFM: |
@@ -238,7 +231,7 @@ static int s3c24xx_i2s_set_fmt(struct snd_soc_dai *cpu_dai, | |||
238 | } | 231 | } |
239 | 232 | ||
240 | writel(iismod, s3c24xx_i2s.regs + S3C2410_IISMOD); | 233 | writel(iismod, s3c24xx_i2s.regs + S3C2410_IISMOD); |
241 | DBG("hw_params w: IISMOD: %lx \n", iismod); | 234 | pr_debug("hw_params w: IISMOD: %x \n", iismod); |
242 | return 0; | 235 | return 0; |
243 | } | 236 | } |
244 | 237 | ||
@@ -249,7 +242,7 @@ static int s3c24xx_i2s_hw_params(struct snd_pcm_substream *substream, | |||
249 | struct snd_soc_pcm_runtime *rtd = substream->private_data; | 242 | struct snd_soc_pcm_runtime *rtd = substream->private_data; |
250 | u32 iismod; | 243 | u32 iismod; |
251 | 244 | ||
252 | DBG("Entered %s\n", __func__); | 245 | pr_debug("Entered %s\n", __func__); |
253 | 246 | ||
254 | if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) | 247 | if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) |
255 | rtd->dai->cpu_dai->dma_data = &s3c24xx_i2s_pcm_stereo_out; | 248 | rtd->dai->cpu_dai->dma_data = &s3c24xx_i2s_pcm_stereo_out; |
@@ -258,7 +251,7 @@ static int s3c24xx_i2s_hw_params(struct snd_pcm_substream *substream, | |||
258 | 251 | ||
259 | /* Working copies of register */ | 252 | /* Working copies of register */ |
260 | iismod = readl(s3c24xx_i2s.regs + S3C2410_IISMOD); | 253 | iismod = readl(s3c24xx_i2s.regs + S3C2410_IISMOD); |
261 | DBG("hw_params r: IISMOD: %lx\n", iismod); | 254 | pr_debug("hw_params r: IISMOD: %x\n", iismod); |
262 | 255 | ||
263 | switch (params_format(params)) { | 256 | switch (params_format(params)) { |
264 | case SNDRV_PCM_FORMAT_S8: | 257 | case SNDRV_PCM_FORMAT_S8: |
@@ -276,7 +269,7 @@ static int s3c24xx_i2s_hw_params(struct snd_pcm_substream *substream, | |||
276 | } | 269 | } |
277 | 270 | ||
278 | writel(iismod, s3c24xx_i2s.regs + S3C2410_IISMOD); | 271 | writel(iismod, s3c24xx_i2s.regs + S3C2410_IISMOD); |
279 | DBG("hw_params w: IISMOD: %lx\n", iismod); | 272 | pr_debug("hw_params w: IISMOD: %x\n", iismod); |
280 | return 0; | 273 | return 0; |
281 | } | 274 | } |
282 | 275 | ||
@@ -285,7 +278,7 @@ static int s3c24xx_i2s_trigger(struct snd_pcm_substream *substream, int cmd, | |||
285 | { | 278 | { |
286 | int ret = 0; | 279 | int ret = 0; |
287 | 280 | ||
288 | DBG("Entered %s\n", __func__); | 281 | pr_debug("Entered %s\n", __func__); |
289 | 282 | ||
290 | switch (cmd) { | 283 | switch (cmd) { |
291 | case SNDRV_PCM_TRIGGER_START: | 284 | case SNDRV_PCM_TRIGGER_START: |
@@ -327,7 +320,7 @@ static int s3c24xx_i2s_set_sysclk(struct snd_soc_dai *cpu_dai, | |||
327 | { | 320 | { |
328 | u32 iismod = readl(s3c24xx_i2s.regs + S3C2410_IISMOD); | 321 | u32 iismod = readl(s3c24xx_i2s.regs + S3C2410_IISMOD); |
329 | 322 | ||
330 | DBG("Entered %s\n", __func__); | 323 | pr_debug("Entered %s\n", __func__); |
331 | 324 | ||
332 | iismod &= ~S3C2440_IISMOD_MPLL; | 325 | iismod &= ~S3C2440_IISMOD_MPLL; |
333 | 326 | ||
@@ -353,7 +346,7 @@ static int s3c24xx_i2s_set_clkdiv(struct snd_soc_dai *cpu_dai, | |||
353 | { | 346 | { |
354 | u32 reg; | 347 | u32 reg; |
355 | 348 | ||
356 | DBG("Entered %s\n", __func__); | 349 | pr_debug("Entered %s\n", __func__); |
357 | 350 | ||
358 | switch (div_id) { | 351 | switch (div_id) { |
359 | case S3C24XX_DIV_BCLK: | 352 | case S3C24XX_DIV_BCLK: |
@@ -389,7 +382,7 @@ EXPORT_SYMBOL_GPL(s3c24xx_i2s_get_clockrate); | |||
389 | static int s3c24xx_i2s_probe(struct platform_device *pdev, | 382 | static int s3c24xx_i2s_probe(struct platform_device *pdev, |
390 | struct snd_soc_dai *dai) | 383 | struct snd_soc_dai *dai) |
391 | { | 384 | { |
392 | DBG("Entered %s\n", __func__); | 385 | pr_debug("Entered %s\n", __func__); |
393 | 386 | ||
394 | s3c24xx_i2s.regs = ioremap(S3C2410_PA_IIS, 0x100); | 387 | s3c24xx_i2s.regs = ioremap(S3C2410_PA_IIS, 0x100); |
395 | if (s3c24xx_i2s.regs == NULL) | 388 | if (s3c24xx_i2s.regs == NULL) |
@@ -397,7 +390,7 @@ static int s3c24xx_i2s_probe(struct platform_device *pdev, | |||
397 | 390 | ||
398 | s3c24xx_i2s.iis_clk = clk_get(&pdev->dev, "iis"); | 391 | s3c24xx_i2s.iis_clk = clk_get(&pdev->dev, "iis"); |
399 | if (s3c24xx_i2s.iis_clk == NULL) { | 392 | if (s3c24xx_i2s.iis_clk == NULL) { |
400 | DBG("failed to get iis_clock\n"); | 393 | pr_err("failed to get iis_clock\n"); |
401 | iounmap(s3c24xx_i2s.regs); | 394 | iounmap(s3c24xx_i2s.regs); |
402 | return -ENODEV; | 395 | return -ENODEV; |
403 | } | 396 | } |
@@ -421,7 +414,7 @@ static int s3c24xx_i2s_probe(struct platform_device *pdev, | |||
421 | #ifdef CONFIG_PM | 414 | #ifdef CONFIG_PM |
422 | static int s3c24xx_i2s_suspend(struct snd_soc_dai *cpu_dai) | 415 | static int s3c24xx_i2s_suspend(struct snd_soc_dai *cpu_dai) |
423 | { | 416 | { |
424 | DBG("Entered %s\n", __func__); | 417 | pr_debug("Entered %s\n", __func__); |
425 | 418 | ||
426 | s3c24xx_i2s.iiscon = readl(s3c24xx_i2s.regs + S3C2410_IISCON); | 419 | s3c24xx_i2s.iiscon = readl(s3c24xx_i2s.regs + S3C2410_IISCON); |
427 | s3c24xx_i2s.iismod = readl(s3c24xx_i2s.regs + S3C2410_IISMOD); | 420 | s3c24xx_i2s.iismod = readl(s3c24xx_i2s.regs + S3C2410_IISMOD); |
@@ -435,7 +428,7 @@ static int s3c24xx_i2s_suspend(struct snd_soc_dai *cpu_dai) | |||
435 | 428 | ||
436 | static int s3c24xx_i2s_resume(struct snd_soc_dai *cpu_dai) | 429 | static int s3c24xx_i2s_resume(struct snd_soc_dai *cpu_dai) |
437 | { | 430 | { |
438 | DBG("Entered %s\n", __func__); | 431 | pr_debug("Entered %s\n", __func__); |
439 | clk_enable(s3c24xx_i2s.iis_clk); | 432 | clk_enable(s3c24xx_i2s.iis_clk); |
440 | 433 | ||
441 | writel(s3c24xx_i2s.iiscon, s3c24xx_i2s.regs + S3C2410_IISCON); | 434 | writel(s3c24xx_i2s.iiscon, s3c24xx_i2s.regs + S3C2410_IISCON); |
@@ -456,6 +449,14 @@ static int s3c24xx_i2s_resume(struct snd_soc_dai *cpu_dai) | |||
456 | SNDRV_PCM_RATE_22050 | SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_44100 | \ | 449 | SNDRV_PCM_RATE_22050 | SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_44100 | \ |
457 | SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_88200 | SNDRV_PCM_RATE_96000) | 450 | SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_88200 | SNDRV_PCM_RATE_96000) |
458 | 451 | ||
452 | static struct snd_soc_dai_ops s3c24xx_i2s_dai_ops = { | ||
453 | .trigger = s3c24xx_i2s_trigger, | ||
454 | .hw_params = s3c24xx_i2s_hw_params, | ||
455 | .set_fmt = s3c24xx_i2s_set_fmt, | ||
456 | .set_clkdiv = s3c24xx_i2s_set_clkdiv, | ||
457 | .set_sysclk = s3c24xx_i2s_set_sysclk, | ||
458 | }; | ||
459 | |||
459 | struct snd_soc_dai s3c24xx_i2s_dai = { | 460 | struct snd_soc_dai s3c24xx_i2s_dai = { |
460 | .name = "s3c24xx-i2s", | 461 | .name = "s3c24xx-i2s", |
461 | .id = 0, | 462 | .id = 0, |
@@ -472,13 +473,7 @@ struct snd_soc_dai s3c24xx_i2s_dai = { | |||
472 | .channels_max = 2, | 473 | .channels_max = 2, |
473 | .rates = S3C24XX_I2S_RATES, | 474 | .rates = S3C24XX_I2S_RATES, |
474 | .formats = SNDRV_PCM_FMTBIT_S8 | SNDRV_PCM_FMTBIT_S16_LE,}, | 475 | .formats = SNDRV_PCM_FMTBIT_S8 | SNDRV_PCM_FMTBIT_S16_LE,}, |
475 | .ops = { | 476 | .ops = &s3c24xx_i2s_dai_ops, |
476 | .trigger = s3c24xx_i2s_trigger, | ||
477 | .hw_params = s3c24xx_i2s_hw_params, | ||
478 | .set_fmt = s3c24xx_i2s_set_fmt, | ||
479 | .set_clkdiv = s3c24xx_i2s_set_clkdiv, | ||
480 | .set_sysclk = s3c24xx_i2s_set_sysclk, | ||
481 | }, | ||
482 | }; | 477 | }; |
483 | EXPORT_SYMBOL_GPL(s3c24xx_i2s_dai); | 478 | EXPORT_SYMBOL_GPL(s3c24xx_i2s_dai); |
484 | 479 | ||
diff --git a/sound/soc/s3c24xx/s3c24xx-pcm.c b/sound/soc/s3c24xx/s3c24xx-pcm.c index 7c64d31d067e..a9d68fa2b34a 100644 --- a/sound/soc/s3c24xx/s3c24xx-pcm.c +++ b/sound/soc/s3c24xx/s3c24xx-pcm.c | |||
@@ -4,7 +4,7 @@ | |||
4 | * (c) 2006 Wolfson Microelectronics PLC. | 4 | * (c) 2006 Wolfson Microelectronics PLC. |
5 | * Graeme Gregory graeme.gregory@wolfsonmicro.com or linux@wolfsonmicro.com | 5 | * Graeme Gregory graeme.gregory@wolfsonmicro.com or linux@wolfsonmicro.com |
6 | * | 6 | * |
7 | * (c) 2004-2005 Simtec Electronics | 7 | * Copyright 2004-2005 Simtec Electronics |
8 | * http://armlinux.simtec.co.uk/ | 8 | * http://armlinux.simtec.co.uk/ |
9 | * Ben Dooks <ben@simtec.co.uk> | 9 | * Ben Dooks <ben@simtec.co.uk> |
10 | * | 10 | * |
@@ -29,17 +29,10 @@ | |||
29 | #include <asm/dma.h> | 29 | #include <asm/dma.h> |
30 | #include <mach/hardware.h> | 30 | #include <mach/hardware.h> |
31 | #include <mach/dma.h> | 31 | #include <mach/dma.h> |
32 | #include <mach/audio.h> | 32 | #include <plat/audio.h> |
33 | 33 | ||
34 | #include "s3c24xx-pcm.h" | 34 | #include "s3c24xx-pcm.h" |
35 | 35 | ||
36 | #define S3C24XX_PCM_DEBUG 0 | ||
37 | #if S3C24XX_PCM_DEBUG | ||
38 | #define DBG(x...) printk(KERN_DEBUG "s3c24xx-pcm: " x) | ||
39 | #else | ||
40 | #define DBG(x...) | ||
41 | #endif | ||
42 | |||
43 | static const struct snd_pcm_hardware s3c24xx_pcm_hardware = { | 36 | static const struct snd_pcm_hardware s3c24xx_pcm_hardware = { |
44 | .info = SNDRV_PCM_INFO_INTERLEAVED | | 37 | .info = SNDRV_PCM_INFO_INTERLEAVED | |
45 | SNDRV_PCM_INFO_BLOCK_TRANSFER | | 38 | SNDRV_PCM_INFO_BLOCK_TRANSFER | |
@@ -84,16 +77,16 @@ static void s3c24xx_pcm_enqueue(struct snd_pcm_substream *substream) | |||
84 | dma_addr_t pos = prtd->dma_pos; | 77 | dma_addr_t pos = prtd->dma_pos; |
85 | int ret; | 78 | int ret; |
86 | 79 | ||
87 | DBG("Entered %s\n", __func__); | 80 | pr_debug("Entered %s\n", __func__); |
88 | 81 | ||
89 | while (prtd->dma_loaded < prtd->dma_limit) { | 82 | while (prtd->dma_loaded < prtd->dma_limit) { |
90 | unsigned long len = prtd->dma_period; | 83 | unsigned long len = prtd->dma_period; |
91 | 84 | ||
92 | DBG("dma_loaded: %d\n", prtd->dma_loaded); | 85 | pr_debug("dma_loaded: %d\n", prtd->dma_loaded); |
93 | 86 | ||
94 | if ((pos + len) > prtd->dma_end) { | 87 | if ((pos + len) > prtd->dma_end) { |
95 | len = prtd->dma_end - pos; | 88 | len = prtd->dma_end - pos; |
96 | DBG(KERN_DEBUG "%s: corrected dma len %ld\n", | 89 | pr_debug(KERN_DEBUG "%s: corrected dma len %ld\n", |
97 | __func__, len); | 90 | __func__, len); |
98 | } | 91 | } |
99 | 92 | ||
@@ -119,7 +112,7 @@ static void s3c24xx_audio_buffdone(struct s3c2410_dma_chan *channel, | |||
119 | struct snd_pcm_substream *substream = dev_id; | 112 | struct snd_pcm_substream *substream = dev_id; |
120 | struct s3c24xx_runtime_data *prtd; | 113 | struct s3c24xx_runtime_data *prtd; |
121 | 114 | ||
122 | DBG("Entered %s\n", __func__); | 115 | pr_debug("Entered %s\n", __func__); |
123 | 116 | ||
124 | if (result == S3C2410_RES_ABORT || result == S3C2410_RES_ERR) | 117 | if (result == S3C2410_RES_ABORT || result == S3C2410_RES_ERR) |
125 | return; | 118 | return; |
@@ -148,7 +141,7 @@ static int s3c24xx_pcm_hw_params(struct snd_pcm_substream *substream, | |||
148 | unsigned long totbytes = params_buffer_bytes(params); | 141 | unsigned long totbytes = params_buffer_bytes(params); |
149 | int ret = 0; | 142 | int ret = 0; |
150 | 143 | ||
151 | DBG("Entered %s\n", __func__); | 144 | pr_debug("Entered %s\n", __func__); |
152 | 145 | ||
153 | /* return if this is a bufferless transfer e.g. | 146 | /* return if this is a bufferless transfer e.g. |
154 | * codec <--> BT codec or GSM modem -- lg FIXME */ | 147 | * codec <--> BT codec or GSM modem -- lg FIXME */ |
@@ -161,14 +154,14 @@ static int s3c24xx_pcm_hw_params(struct snd_pcm_substream *substream, | |||
161 | /* prepare DMA */ | 154 | /* prepare DMA */ |
162 | prtd->params = dma; | 155 | prtd->params = dma; |
163 | 156 | ||
164 | DBG("params %p, client %p, channel %d\n", prtd->params, | 157 | pr_debug("params %p, client %p, channel %d\n", prtd->params, |
165 | prtd->params->client, prtd->params->channel); | 158 | prtd->params->client, prtd->params->channel); |
166 | 159 | ||
167 | ret = s3c2410_dma_request(prtd->params->channel, | 160 | ret = s3c2410_dma_request(prtd->params->channel, |
168 | prtd->params->client, NULL); | 161 | prtd->params->client, NULL); |
169 | 162 | ||
170 | if (ret < 0) { | 163 | if (ret < 0) { |
171 | DBG(KERN_ERR "failed to get dma channel\n"); | 164 | printk(KERN_ERR "failed to get dma channel\n"); |
172 | return ret; | 165 | return ret; |
173 | } | 166 | } |
174 | } | 167 | } |
@@ -196,7 +189,7 @@ static int s3c24xx_pcm_hw_free(struct snd_pcm_substream *substream) | |||
196 | { | 189 | { |
197 | struct s3c24xx_runtime_data *prtd = substream->runtime->private_data; | 190 | struct s3c24xx_runtime_data *prtd = substream->runtime->private_data; |
198 | 191 | ||
199 | DBG("Entered %s\n", __func__); | 192 | pr_debug("Entered %s\n", __func__); |
200 | 193 | ||
201 | /* TODO - do we need to ensure DMA flushed */ | 194 | /* TODO - do we need to ensure DMA flushed */ |
202 | snd_pcm_set_runtime_buffer(substream, NULL); | 195 | snd_pcm_set_runtime_buffer(substream, NULL); |
@@ -214,7 +207,7 @@ static int s3c24xx_pcm_prepare(struct snd_pcm_substream *substream) | |||
214 | struct s3c24xx_runtime_data *prtd = substream->runtime->private_data; | 207 | struct s3c24xx_runtime_data *prtd = substream->runtime->private_data; |
215 | int ret = 0; | 208 | int ret = 0; |
216 | 209 | ||
217 | DBG("Entered %s\n", __func__); | 210 | pr_debug("Entered %s\n", __func__); |
218 | 211 | ||
219 | /* return if this is a bufferless transfer e.g. | 212 | /* return if this is a bufferless transfer e.g. |
220 | * codec <--> BT codec or GSM modem -- lg FIXME */ | 213 | * codec <--> BT codec or GSM modem -- lg FIXME */ |
@@ -259,7 +252,7 @@ static int s3c24xx_pcm_trigger(struct snd_pcm_substream *substream, int cmd) | |||
259 | struct s3c24xx_runtime_data *prtd = substream->runtime->private_data; | 252 | struct s3c24xx_runtime_data *prtd = substream->runtime->private_data; |
260 | int ret = 0; | 253 | int ret = 0; |
261 | 254 | ||
262 | DBG("Entered %s\n", __func__); | 255 | pr_debug("Entered %s\n", __func__); |
263 | 256 | ||
264 | spin_lock(&prtd->lock); | 257 | spin_lock(&prtd->lock); |
265 | 258 | ||
@@ -297,7 +290,7 @@ s3c24xx_pcm_pointer(struct snd_pcm_substream *substream) | |||
297 | unsigned long res; | 290 | unsigned long res; |
298 | dma_addr_t src, dst; | 291 | dma_addr_t src, dst; |
299 | 292 | ||
300 | DBG("Entered %s\n", __func__); | 293 | pr_debug("Entered %s\n", __func__); |
301 | 294 | ||
302 | spin_lock(&prtd->lock); | 295 | spin_lock(&prtd->lock); |
303 | s3c2410_dma_getposition(prtd->params->channel, &src, &dst); | 296 | s3c2410_dma_getposition(prtd->params->channel, &src, &dst); |
@@ -309,7 +302,7 @@ s3c24xx_pcm_pointer(struct snd_pcm_substream *substream) | |||
309 | 302 | ||
310 | spin_unlock(&prtd->lock); | 303 | spin_unlock(&prtd->lock); |
311 | 304 | ||
312 | DBG("Pointer %x %x\n", src, dst); | 305 | pr_debug("Pointer %x %x\n", src, dst); |
313 | 306 | ||
314 | /* we seem to be getting the odd error from the pcm library due | 307 | /* we seem to be getting the odd error from the pcm library due |
315 | * to out-of-bounds pointers. this is maybe due to the dma engine | 308 | * to out-of-bounds pointers. this is maybe due to the dma engine |
@@ -330,7 +323,7 @@ static int s3c24xx_pcm_open(struct snd_pcm_substream *substream) | |||
330 | struct snd_pcm_runtime *runtime = substream->runtime; | 323 | struct snd_pcm_runtime *runtime = substream->runtime; |
331 | struct s3c24xx_runtime_data *prtd; | 324 | struct s3c24xx_runtime_data *prtd; |
332 | 325 | ||
333 | DBG("Entered %s\n", __func__); | 326 | pr_debug("Entered %s\n", __func__); |
334 | 327 | ||
335 | snd_soc_set_runtime_hwparams(substream, &s3c24xx_pcm_hardware); | 328 | snd_soc_set_runtime_hwparams(substream, &s3c24xx_pcm_hardware); |
336 | 329 | ||
@@ -349,10 +342,10 @@ static int s3c24xx_pcm_close(struct snd_pcm_substream *substream) | |||
349 | struct snd_pcm_runtime *runtime = substream->runtime; | 342 | struct snd_pcm_runtime *runtime = substream->runtime; |
350 | struct s3c24xx_runtime_data *prtd = runtime->private_data; | 343 | struct s3c24xx_runtime_data *prtd = runtime->private_data; |
351 | 344 | ||
352 | DBG("Entered %s\n", __func__); | 345 | pr_debug("Entered %s\n", __func__); |
353 | 346 | ||
354 | if (!prtd) | 347 | if (!prtd) |
355 | DBG("s3c24xx_pcm_close called with prtd == NULL\n"); | 348 | pr_debug("s3c24xx_pcm_close called with prtd == NULL\n"); |
356 | 349 | ||
357 | kfree(prtd); | 350 | kfree(prtd); |
358 | 351 | ||
@@ -364,7 +357,7 @@ static int s3c24xx_pcm_mmap(struct snd_pcm_substream *substream, | |||
364 | { | 357 | { |
365 | struct snd_pcm_runtime *runtime = substream->runtime; | 358 | struct snd_pcm_runtime *runtime = substream->runtime; |
366 | 359 | ||
367 | DBG("Entered %s\n", __func__); | 360 | pr_debug("Entered %s\n", __func__); |
368 | 361 | ||
369 | return dma_mmap_writecombine(substream->pcm->card->dev, vma, | 362 | return dma_mmap_writecombine(substream->pcm->card->dev, vma, |
370 | runtime->dma_area, | 363 | runtime->dma_area, |
@@ -390,7 +383,7 @@ static int s3c24xx_pcm_preallocate_dma_buffer(struct snd_pcm *pcm, int stream) | |||
390 | struct snd_dma_buffer *buf = &substream->dma_buffer; | 383 | struct snd_dma_buffer *buf = &substream->dma_buffer; |
391 | size_t size = s3c24xx_pcm_hardware.buffer_bytes_max; | 384 | size_t size = s3c24xx_pcm_hardware.buffer_bytes_max; |
392 | 385 | ||
393 | DBG("Entered %s\n", __func__); | 386 | pr_debug("Entered %s\n", __func__); |
394 | 387 | ||
395 | buf->dev.type = SNDRV_DMA_TYPE_DEV; | 388 | buf->dev.type = SNDRV_DMA_TYPE_DEV; |
396 | buf->dev.dev = pcm->card->dev; | 389 | buf->dev.dev = pcm->card->dev; |
@@ -409,7 +402,7 @@ static void s3c24xx_pcm_free_dma_buffers(struct snd_pcm *pcm) | |||
409 | struct snd_dma_buffer *buf; | 402 | struct snd_dma_buffer *buf; |
410 | int stream; | 403 | int stream; |
411 | 404 | ||
412 | DBG("Entered %s\n", __func__); | 405 | pr_debug("Entered %s\n", __func__); |
413 | 406 | ||
414 | for (stream = 0; stream < 2; stream++) { | 407 | for (stream = 0; stream < 2; stream++) { |
415 | substream = pcm->streams[stream].substream; | 408 | substream = pcm->streams[stream].substream; |
@@ -433,7 +426,7 @@ static int s3c24xx_pcm_new(struct snd_card *card, | |||
433 | { | 426 | { |
434 | int ret = 0; | 427 | int ret = 0; |
435 | 428 | ||
436 | DBG("Entered %s\n", __func__); | 429 | pr_debug("Entered %s\n", __func__); |
437 | 430 | ||
438 | if (!card->dev->dma_mask) | 431 | if (!card->dev->dma_mask) |
439 | card->dev->dma_mask = &s3c24xx_pcm_dmamask; | 432 | card->dev->dma_mask = &s3c24xx_pcm_dmamask; |
diff --git a/sound/soc/s3c24xx/s3c24xx_uda134x.c b/sound/soc/s3c24xx/s3c24xx_uda134x.c index a0a4d1832a14..8e79a416db57 100644 --- a/sound/soc/s3c24xx/s3c24xx_uda134x.c +++ b/sound/soc/s3c24xx/s3c24xx_uda134x.c | |||
@@ -22,7 +22,7 @@ | |||
22 | #include <sound/s3c24xx_uda134x.h> | 22 | #include <sound/s3c24xx_uda134x.h> |
23 | #include <sound/uda134x.h> | 23 | #include <sound/uda134x.h> |
24 | 24 | ||
25 | #include <asm/plat-s3c24xx/regs-iis.h> | 25 | #include <plat/regs-iis.h> |
26 | 26 | ||
27 | #include "s3c24xx-pcm.h" | 27 | #include "s3c24xx-pcm.h" |
28 | #include "s3c24xx-i2s.h" | 28 | #include "s3c24xx-i2s.h" |
diff --git a/sound/soc/s3c24xx/s3c64xx-i2s.c b/sound/soc/s3c24xx/s3c64xx-i2s.c new file mode 100644 index 000000000000..33c5de7e255f --- /dev/null +++ b/sound/soc/s3c24xx/s3c64xx-i2s.c | |||
@@ -0,0 +1,222 @@ | |||
1 | /* sound/soc/s3c24xx/s3c64xx-i2s.c | ||
2 | * | ||
3 | * ALSA SoC Audio Layer - S3C64XX I2S driver | ||
4 | * | ||
5 | * Copyright 2008 Openmoko, Inc. | ||
6 | * Copyright 2008 Simtec Electronics | ||
7 | * Ben Dooks <ben@simtec.co.uk> | ||
8 | * http://armlinux.simtec.co.uk/ | ||
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/init.h> | ||
16 | #include <linux/module.h> | ||
17 | #include <linux/device.h> | ||
18 | #include <linux/delay.h> | ||
19 | #include <linux/clk.h> | ||
20 | #include <linux/kernel.h> | ||
21 | #include <linux/gpio.h> | ||
22 | #include <linux/io.h> | ||
23 | |||
24 | #include <sound/core.h> | ||
25 | #include <sound/pcm.h> | ||
26 | #include <sound/pcm_params.h> | ||
27 | #include <sound/initval.h> | ||
28 | #include <sound/soc.h> | ||
29 | |||
30 | #include <plat/regs-s3c2412-iis.h> | ||
31 | #include <plat/gpio-bank-d.h> | ||
32 | #include <plat/gpio-bank-e.h> | ||
33 | #include <plat/gpio-cfg.h> | ||
34 | #include <plat/audio.h> | ||
35 | |||
36 | #include <mach/map.h> | ||
37 | #include <mach/dma.h> | ||
38 | |||
39 | #include "s3c24xx-pcm.h" | ||
40 | #include "s3c64xx-i2s.h" | ||
41 | |||
42 | static struct s3c2410_dma_client s3c64xx_dma_client_out = { | ||
43 | .name = "I2S PCM Stereo out" | ||
44 | }; | ||
45 | |||
46 | static struct s3c2410_dma_client s3c64xx_dma_client_in = { | ||
47 | .name = "I2S PCM Stereo in" | ||
48 | }; | ||
49 | |||
50 | static struct s3c24xx_pcm_dma_params s3c64xx_i2s_pcm_stereo_out[2] = { | ||
51 | [0] = { | ||
52 | .channel = DMACH_I2S0_OUT, | ||
53 | .client = &s3c64xx_dma_client_out, | ||
54 | .dma_addr = S3C64XX_PA_IIS0 + S3C2412_IISTXD, | ||
55 | .dma_size = 4, | ||
56 | }, | ||
57 | [1] = { | ||
58 | .channel = DMACH_I2S1_OUT, | ||
59 | .client = &s3c64xx_dma_client_out, | ||
60 | .dma_addr = S3C64XX_PA_IIS1 + S3C2412_IISTXD, | ||
61 | .dma_size = 4, | ||
62 | }, | ||
63 | }; | ||
64 | |||
65 | static struct s3c24xx_pcm_dma_params s3c64xx_i2s_pcm_stereo_in[2] = { | ||
66 | [0] = { | ||
67 | .channel = DMACH_I2S0_IN, | ||
68 | .client = &s3c64xx_dma_client_in, | ||
69 | .dma_addr = S3C64XX_PA_IIS0 + S3C2412_IISRXD, | ||
70 | .dma_size = 4, | ||
71 | }, | ||
72 | [1] = { | ||
73 | .channel = DMACH_I2S1_IN, | ||
74 | .client = &s3c64xx_dma_client_in, | ||
75 | .dma_addr = S3C64XX_PA_IIS1 + S3C2412_IISRXD, | ||
76 | .dma_size = 4, | ||
77 | }, | ||
78 | }; | ||
79 | |||
80 | static struct s3c_i2sv2_info s3c64xx_i2s[2]; | ||
81 | |||
82 | static inline struct s3c_i2sv2_info *to_info(struct snd_soc_dai *cpu_dai) | ||
83 | { | ||
84 | return cpu_dai->private_data; | ||
85 | } | ||
86 | |||
87 | static int s3c64xx_i2s_set_sysclk(struct snd_soc_dai *cpu_dai, | ||
88 | int clk_id, unsigned int freq, int dir) | ||
89 | { | ||
90 | struct s3c_i2sv2_info *i2s = to_info(cpu_dai); | ||
91 | u32 iismod = readl(i2s->regs + S3C2412_IISMOD); | ||
92 | |||
93 | switch (clk_id) { | ||
94 | case S3C64XX_CLKSRC_PCLK: | ||
95 | iismod &= ~S3C64XX_IISMOD_IMS_SYSMUX; | ||
96 | break; | ||
97 | |||
98 | case S3C64XX_CLKSRC_MUX: | ||
99 | iismod |= S3C64XX_IISMOD_IMS_SYSMUX; | ||
100 | break; | ||
101 | |||
102 | default: | ||
103 | return -EINVAL; | ||
104 | } | ||
105 | |||
106 | writel(iismod, i2s->regs + S3C2412_IISMOD); | ||
107 | |||
108 | return 0; | ||
109 | } | ||
110 | |||
111 | |||
112 | unsigned long s3c64xx_i2s_get_clockrate(struct snd_soc_dai *dai) | ||
113 | { | ||
114 | struct s3c_i2sv2_info *i2s = to_info(dai); | ||
115 | |||
116 | return clk_get_rate(i2s->iis_cclk); | ||
117 | } | ||
118 | EXPORT_SYMBOL_GPL(s3c64xx_i2s_get_clockrate); | ||
119 | |||
120 | static int s3c64xx_i2s_probe(struct platform_device *pdev, | ||
121 | struct snd_soc_dai *dai) | ||
122 | { | ||
123 | struct device *dev = &pdev->dev; | ||
124 | struct s3c_i2sv2_info *i2s; | ||
125 | int ret; | ||
126 | |||
127 | dev_dbg(dev, "%s: probing dai %d\n", __func__, pdev->id); | ||
128 | |||
129 | if (pdev->id < 0 || pdev->id > ARRAY_SIZE(s3c64xx_i2s)) { | ||
130 | dev_err(dev, "id %d out of range\n", pdev->id); | ||
131 | return -EINVAL; | ||
132 | } | ||
133 | |||
134 | i2s = &s3c64xx_i2s[pdev->id]; | ||
135 | |||
136 | ret = s3c_i2sv2_probe(pdev, dai, i2s, | ||
137 | pdev->id ? S3C64XX_PA_IIS1 : S3C64XX_PA_IIS0); | ||
138 | if (ret) | ||
139 | return ret; | ||
140 | |||
141 | i2s->dma_capture = &s3c64xx_i2s_pcm_stereo_in[pdev->id]; | ||
142 | i2s->dma_playback = &s3c64xx_i2s_pcm_stereo_out[pdev->id]; | ||
143 | |||
144 | i2s->iis_cclk = clk_get(dev, "audio-bus"); | ||
145 | if (IS_ERR(i2s->iis_cclk)) { | ||
146 | dev_err(dev, "failed to get audio-bus"); | ||
147 | iounmap(i2s->regs); | ||
148 | return -ENODEV; | ||
149 | } | ||
150 | |||
151 | /* configure GPIO for i2s port */ | ||
152 | switch (pdev->id) { | ||
153 | case 0: | ||
154 | s3c_gpio_cfgpin(S3C64XX_GPD(0), S3C64XX_GPD0_I2S0_CLK); | ||
155 | s3c_gpio_cfgpin(S3C64XX_GPD(1), S3C64XX_GPD1_I2S0_CDCLK); | ||
156 | s3c_gpio_cfgpin(S3C64XX_GPD(2), S3C64XX_GPD2_I2S0_LRCLK); | ||
157 | s3c_gpio_cfgpin(S3C64XX_GPD(3), S3C64XX_GPD3_I2S0_DI); | ||
158 | s3c_gpio_cfgpin(S3C64XX_GPD(4), S3C64XX_GPD4_I2S0_D0); | ||
159 | break; | ||
160 | case 1: | ||
161 | s3c_gpio_cfgpin(S3C64XX_GPE(0), S3C64XX_GPE0_I2S1_CLK); | ||
162 | s3c_gpio_cfgpin(S3C64XX_GPE(1), S3C64XX_GPE1_I2S1_CDCLK); | ||
163 | s3c_gpio_cfgpin(S3C64XX_GPE(2), S3C64XX_GPE2_I2S1_LRCLK); | ||
164 | s3c_gpio_cfgpin(S3C64XX_GPE(3), S3C64XX_GPE3_I2S1_DI); | ||
165 | s3c_gpio_cfgpin(S3C64XX_GPE(4), S3C64XX_GPE4_I2S1_D0); | ||
166 | } | ||
167 | |||
168 | return 0; | ||
169 | } | ||
170 | |||
171 | |||
172 | #define S3C64XX_I2S_RATES \ | ||
173 | (SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_11025 | SNDRV_PCM_RATE_16000 | \ | ||
174 | SNDRV_PCM_RATE_22050 | SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_44100 | \ | ||
175 | SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_88200 | SNDRV_PCM_RATE_96000) | ||
176 | |||
177 | #define S3C64XX_I2S_FMTS \ | ||
178 | (SNDRV_PCM_FMTBIT_S8 | SNDRV_PCM_FMTBIT_S16_LE) | ||
179 | |||
180 | static struct snd_soc_dai_ops s3c64xx_i2s_dai_ops = { | ||
181 | .set_sysclk = s3c64xx_i2s_set_sysclk, | ||
182 | }; | ||
183 | |||
184 | struct snd_soc_dai s3c64xx_i2s_dai = { | ||
185 | .name = "s3c64xx-i2s", | ||
186 | .id = 0, | ||
187 | .probe = s3c64xx_i2s_probe, | ||
188 | .playback = { | ||
189 | .channels_min = 2, | ||
190 | .channels_max = 2, | ||
191 | .rates = S3C64XX_I2S_RATES, | ||
192 | .formats = S3C64XX_I2S_FMTS, | ||
193 | }, | ||
194 | .capture = { | ||
195 | .channels_min = 2, | ||
196 | .channels_max = 2, | ||
197 | .rates = S3C64XX_I2S_RATES, | ||
198 | .formats = S3C64XX_I2S_FMTS, | ||
199 | }, | ||
200 | .ops = &s3c64xx_i2s_dai_ops, | ||
201 | }; | ||
202 | EXPORT_SYMBOL_GPL(s3c64xx_i2s_dai); | ||
203 | |||
204 | static int __init s3c64xx_i2s_init(void) | ||
205 | { | ||
206 | return s3c_i2sv2_register_dai(&s3c64xx_i2s_dai); | ||
207 | } | ||
208 | module_init(s3c64xx_i2s_init); | ||
209 | |||
210 | static void __exit s3c64xx_i2s_exit(void) | ||
211 | { | ||
212 | snd_soc_unregister_dai(&s3c64xx_i2s_dai); | ||
213 | } | ||
214 | module_exit(s3c64xx_i2s_exit); | ||
215 | |||
216 | /* Module information */ | ||
217 | MODULE_AUTHOR("Ben Dooks, <ben@simtec.co.uk>"); | ||
218 | MODULE_DESCRIPTION("S3C64XX I2S SoC Interface"); | ||
219 | MODULE_LICENSE("GPL"); | ||
220 | |||
221 | |||
222 | |||
diff --git a/sound/soc/s3c24xx/s3c64xx-i2s.h b/sound/soc/s3c24xx/s3c64xx-i2s.h new file mode 100644 index 000000000000..b7ffe3c38b66 --- /dev/null +++ b/sound/soc/s3c24xx/s3c64xx-i2s.h | |||
@@ -0,0 +1,31 @@ | |||
1 | /* sound/soc/s3c24xx/s3c64xx-i2s.h | ||
2 | * | ||
3 | * ALSA SoC Audio Layer - S3C64XX I2S driver | ||
4 | * | ||
5 | * Copyright 2008 Openmoko, Inc. | ||
6 | * Copyright 2008 Simtec Electronics | ||
7 | * Ben Dooks <ben@simtec.co.uk> | ||
8 | * http://armlinux.simtec.co.uk/ | ||
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 | #ifndef __SND_SOC_S3C24XX_S3C64XX_I2S_H | ||
16 | #define __SND_SOC_S3C24XX_S3C64XX_I2S_H __FILE__ | ||
17 | |||
18 | #include "s3c-i2s-v2.h" | ||
19 | |||
20 | #define S3C64XX_DIV_BCLK S3C_I2SV2_DIV_BCLK | ||
21 | #define S3C64XX_DIV_RCLK S3C_I2SV2_DIV_RCLK | ||
22 | #define S3C64XX_DIV_PRESCALER S3C_I2SV2_DIV_PRESCALER | ||
23 | |||
24 | #define S3C64XX_CLKSRC_PCLK (0) | ||
25 | #define S3C64XX_CLKSRC_MUX (1) | ||
26 | |||
27 | extern struct snd_soc_dai s3c64xx_i2s_dai; | ||
28 | |||
29 | extern unsigned long s3c64xx_i2s_get_clockrate(struct snd_soc_dai *cpu_dai); | ||
30 | |||
31 | #endif /* __SND_SOC_S3C24XX_S3C64XX_I2S_H */ | ||