Commit | Line | Data |
---|---|---|
c1422a66 BD |
1 | /* |
2 | * s3c24xx-i2s.c -- ALSA Soc Audio Layer | |
3 | * | |
4 | * (c) 2006 Wolfson Microelectronics PLC. | |
5 | * Graeme Gregory graeme.gregory@wolfsonmicro.com or linux@wolfsonmicro.com | |
6 | * | |
c8efef17 | 7 | * Copyright 2004-2005 Simtec Electronics |
c1422a66 BD |
8 | * http://armlinux.simtec.co.uk/ |
9 | * Ben Dooks <ben@simtec.co.uk> | |
10 | * | |
11 | * This program is free software; you can redistribute it and/or modify it | |
12 | * under the terms of the GNU General Public License as published by the | |
13 | * Free Software Foundation; either version 2 of the License, or (at your | |
14 | * option) any later version. | |
c1422a66 BD |
15 | */ |
16 | ||
17 | #include <linux/init.h> | |
18 | #include <linux/module.h> | |
19 | #include <linux/device.h> | |
20 | #include <linux/delay.h> | |
21 | #include <linux/clk.h> | |
f11b7992 | 22 | #include <linux/jiffies.h> |
40efc15f | 23 | #include <linux/io.h> |
ec976d6e BD |
24 | #include <linux/gpio.h> |
25 | ||
c1422a66 BD |
26 | #include <sound/core.h> |
27 | #include <sound/pcm.h> | |
28 | #include <sound/pcm_params.h> | |
29 | #include <sound/initval.h> | |
30 | #include <sound/soc.h> | |
31 | ||
a09e64fb RK |
32 | #include <mach/hardware.h> |
33 | #include <mach/regs-gpio.h> | |
34 | #include <mach/regs-clock.h> | |
899e6cf5 | 35 | #include <plat/audio.h> |
c1422a66 | 36 | #include <asm/dma.h> |
a09e64fb | 37 | #include <mach/dma.h> |
c1422a66 | 38 | |
8150bc88 | 39 | #include <plat/regs-iis.h> |
aa9673cf | 40 | |
c1422a66 BD |
41 | #include "s3c24xx-pcm.h" |
42 | #include "s3c24xx-i2s.h" | |
43 | ||
c1422a66 BD |
44 | static struct s3c2410_dma_client s3c24xx_dma_client_out = { |
45 | .name = "I2S PCM Stereo out" | |
46 | }; | |
47 | ||
48 | static struct s3c2410_dma_client s3c24xx_dma_client_in = { | |
49 | .name = "I2S PCM Stereo in" | |
50 | }; | |
51 | ||
52 | static struct s3c24xx_pcm_dma_params s3c24xx_i2s_pcm_stereo_out = { | |
53 | .client = &s3c24xx_dma_client_out, | |
54 | .channel = DMACH_I2S_OUT, | |
e81208fe GG |
55 | .dma_addr = S3C2410_PA_IIS + S3C2410_IISFIFO, |
56 | .dma_size = 2, | |
c1422a66 BD |
57 | }; |
58 | ||
59 | static struct s3c24xx_pcm_dma_params s3c24xx_i2s_pcm_stereo_in = { | |
60 | .client = &s3c24xx_dma_client_in, | |
61 | .channel = DMACH_I2S_IN, | |
e81208fe GG |
62 | .dma_addr = S3C2410_PA_IIS + S3C2410_IISFIFO, |
63 | .dma_size = 2, | |
c1422a66 BD |
64 | }; |
65 | ||
66 | struct s3c24xx_i2s_info { | |
67 | void __iomem *regs; | |
68 | struct clk *iis_clk; | |
5cd919a2 GG |
69 | u32 iiscon; |
70 | u32 iismod; | |
71 | u32 iisfcon; | |
72 | u32 iispsr; | |
c1422a66 BD |
73 | }; |
74 | static struct s3c24xx_i2s_info s3c24xx_i2s; | |
75 | ||
76 | static void s3c24xx_snd_txctrl(int on) | |
77 | { | |
78 | u32 iisfcon; | |
79 | u32 iiscon; | |
80 | u32 iismod; | |
81 | ||
ee7d4767 | 82 | pr_debug("Entered %s\n", __func__); |
c1422a66 BD |
83 | |
84 | iisfcon = readl(s3c24xx_i2s.regs + S3C2410_IISFCON); | |
85 | iiscon = readl(s3c24xx_i2s.regs + S3C2410_IISCON); | |
86 | iismod = readl(s3c24xx_i2s.regs + S3C2410_IISMOD); | |
87 | ||
5314adc3 | 88 | pr_debug("r: IISCON: %x IISMOD: %x IISFCON: %x\n", iiscon, iismod, iisfcon); |
c1422a66 BD |
89 | |
90 | if (on) { | |
91 | iisfcon |= S3C2410_IISFCON_TXDMA | S3C2410_IISFCON_TXENABLE; | |
92 | iiscon |= S3C2410_IISCON_TXDMAEN | S3C2410_IISCON_IISEN; | |
93 | iiscon &= ~S3C2410_IISCON_TXIDLE; | |
94 | iismod |= S3C2410_IISMOD_TXMODE; | |
95 | ||
96 | writel(iismod, s3c24xx_i2s.regs + S3C2410_IISMOD); | |
97 | writel(iisfcon, s3c24xx_i2s.regs + S3C2410_IISFCON); | |
98 | writel(iiscon, s3c24xx_i2s.regs + S3C2410_IISCON); | |
99 | } else { | |
100 | /* note, we have to disable the FIFOs otherwise bad things | |
101 | * seem to happen when the DMA stops. According to the | |
102 | * Samsung supplied kernel, this should allow the DMA | |
103 | * engine and FIFOs to reset. If this isn't allowed, the | |
104 | * DMA engine will simply freeze randomly. | |
105 | */ | |
106 | ||
107 | iisfcon &= ~S3C2410_IISFCON_TXENABLE; | |
108 | iisfcon &= ~S3C2410_IISFCON_TXDMA; | |
109 | iiscon |= S3C2410_IISCON_TXIDLE; | |
110 | iiscon &= ~S3C2410_IISCON_TXDMAEN; | |
111 | iismod &= ~S3C2410_IISMOD_TXMODE; | |
112 | ||
113 | writel(iiscon, s3c24xx_i2s.regs + S3C2410_IISCON); | |
114 | writel(iisfcon, s3c24xx_i2s.regs + S3C2410_IISFCON); | |
115 | writel(iismod, s3c24xx_i2s.regs + S3C2410_IISMOD); | |
116 | } | |
117 | ||
5314adc3 | 118 | pr_debug("w: IISCON: %x IISMOD: %x IISFCON: %x\n", iiscon, iismod, iisfcon); |
c1422a66 BD |
119 | } |
120 | ||
121 | static void s3c24xx_snd_rxctrl(int on) | |
122 | { | |
123 | u32 iisfcon; | |
124 | u32 iiscon; | |
125 | u32 iismod; | |
126 | ||
ee7d4767 | 127 | pr_debug("Entered %s\n", __func__); |
c1422a66 BD |
128 | |
129 | iisfcon = readl(s3c24xx_i2s.regs + S3C2410_IISFCON); | |
130 | iiscon = readl(s3c24xx_i2s.regs + S3C2410_IISCON); | |
131 | iismod = readl(s3c24xx_i2s.regs + S3C2410_IISMOD); | |
132 | ||
5314adc3 | 133 | pr_debug("r: IISCON: %x IISMOD: %x IISFCON: %x\n", iiscon, iismod, iisfcon); |
c1422a66 BD |
134 | |
135 | if (on) { | |
136 | iisfcon |= S3C2410_IISFCON_RXDMA | S3C2410_IISFCON_RXENABLE; | |
137 | iiscon |= S3C2410_IISCON_RXDMAEN | S3C2410_IISCON_IISEN; | |
138 | iiscon &= ~S3C2410_IISCON_RXIDLE; | |
139 | iismod |= S3C2410_IISMOD_RXMODE; | |
140 | ||
141 | writel(iismod, s3c24xx_i2s.regs + S3C2410_IISMOD); | |
142 | writel(iisfcon, s3c24xx_i2s.regs + S3C2410_IISFCON); | |
143 | writel(iiscon, s3c24xx_i2s.regs + S3C2410_IISCON); | |
144 | } else { | |
145 | /* note, we have to disable the FIFOs otherwise bad things | |
146 | * seem to happen when the DMA stops. According to the | |
147 | * Samsung supplied kernel, this should allow the DMA | |
148 | * engine and FIFOs to reset. If this isn't allowed, the | |
149 | * DMA engine will simply freeze randomly. | |
150 | */ | |
151 | ||
0015e7d1 MB |
152 | iisfcon &= ~S3C2410_IISFCON_RXENABLE; |
153 | iisfcon &= ~S3C2410_IISFCON_RXDMA; | |
154 | iiscon |= S3C2410_IISCON_RXIDLE; | |
155 | iiscon &= ~S3C2410_IISCON_RXDMAEN; | |
c1422a66 BD |
156 | iismod &= ~S3C2410_IISMOD_RXMODE; |
157 | ||
158 | writel(iisfcon, s3c24xx_i2s.regs + S3C2410_IISFCON); | |
159 | writel(iiscon, s3c24xx_i2s.regs + S3C2410_IISCON); | |
160 | writel(iismod, s3c24xx_i2s.regs + S3C2410_IISMOD); | |
161 | } | |
162 | ||
5314adc3 | 163 | pr_debug("w: IISCON: %x IISMOD: %x IISFCON: %x\n", iiscon, iismod, iisfcon); |
c1422a66 BD |
164 | } |
165 | ||
166 | /* | |
167 | * Wait for the LR signal to allow synchronisation to the L/R clock | |
168 | * from the codec. May only be needed for slave mode. | |
169 | */ | |
170 | static int s3c24xx_snd_lrsync(void) | |
171 | { | |
172 | u32 iiscon; | |
33e5b222 | 173 | int timeout = 50; /* 5ms */ |
c1422a66 | 174 | |
ee7d4767 | 175 | pr_debug("Entered %s\n", __func__); |
c1422a66 BD |
176 | |
177 | while (1) { | |
178 | iiscon = readl(s3c24xx_i2s.regs + S3C2410_IISCON); | |
179 | if (iiscon & S3C2410_IISCON_LRINDEX) | |
180 | break; | |
181 | ||
33e5b222 | 182 | if (!timeout--) |
c1422a66 | 183 | return -ETIMEDOUT; |
33e5b222 | 184 | udelay(100); |
c1422a66 BD |
185 | } |
186 | ||
187 | return 0; | |
188 | } | |
189 | ||
190 | /* | |
191 | * Check whether CPU is the master or slave | |
192 | */ | |
193 | static inline int s3c24xx_snd_is_clkmaster(void) | |
194 | { | |
ee7d4767 | 195 | pr_debug("Entered %s\n", __func__); |
c1422a66 BD |
196 | |
197 | return (readl(s3c24xx_i2s.regs + S3C2410_IISMOD) & S3C2410_IISMOD_SLAVE) ? 0:1; | |
198 | } | |
199 | ||
200 | /* | |
201 | * Set S3C24xx I2S DAI format | |
202 | */ | |
1992a6fb | 203 | static int s3c24xx_i2s_set_fmt(struct snd_soc_dai *cpu_dai, |
c1422a66 BD |
204 | unsigned int fmt) |
205 | { | |
206 | u32 iismod; | |
207 | ||
ee7d4767 | 208 | pr_debug("Entered %s\n", __func__); |
c1422a66 BD |
209 | |
210 | iismod = readl(s3c24xx_i2s.regs + S3C2410_IISMOD); | |
5314adc3 | 211 | pr_debug("hw_params r: IISMOD: %x \n", iismod); |
c1422a66 BD |
212 | |
213 | switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { | |
214 | case SND_SOC_DAIFMT_CBM_CFM: | |
215 | iismod |= S3C2410_IISMOD_SLAVE; | |
216 | break; | |
217 | case SND_SOC_DAIFMT_CBS_CFS: | |
2c36eecf | 218 | iismod &= ~S3C2410_IISMOD_SLAVE; |
c1422a66 BD |
219 | break; |
220 | default: | |
221 | return -EINVAL; | |
222 | } | |
223 | ||
224 | switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) { | |
225 | case SND_SOC_DAIFMT_LEFT_J: | |
226 | iismod |= S3C2410_IISMOD_MSB; | |
227 | break; | |
228 | case SND_SOC_DAIFMT_I2S: | |
2c36eecf | 229 | iismod &= ~S3C2410_IISMOD_MSB; |
c1422a66 BD |
230 | break; |
231 | default: | |
232 | return -EINVAL; | |
233 | } | |
234 | ||
235 | writel(iismod, s3c24xx_i2s.regs + S3C2410_IISMOD); | |
5314adc3 | 236 | pr_debug("hw_params w: IISMOD: %x \n", iismod); |
c1422a66 BD |
237 | return 0; |
238 | } | |
239 | ||
240 | static int s3c24xx_i2s_hw_params(struct snd_pcm_substream *substream, | |
dee89c4d MB |
241 | struct snd_pcm_hw_params *params, |
242 | struct snd_soc_dai *dai) | |
c1422a66 BD |
243 | { |
244 | struct snd_soc_pcm_runtime *rtd = substream->private_data; | |
245 | u32 iismod; | |
246 | ||
ee7d4767 | 247 | pr_debug("Entered %s\n", __func__); |
c1422a66 BD |
248 | |
249 | if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) | |
250 | rtd->dai->cpu_dai->dma_data = &s3c24xx_i2s_pcm_stereo_out; | |
251 | else | |
252 | rtd->dai->cpu_dai->dma_data = &s3c24xx_i2s_pcm_stereo_in; | |
253 | ||
254 | /* Working copies of register */ | |
255 | iismod = readl(s3c24xx_i2s.regs + S3C2410_IISMOD); | |
5314adc3 | 256 | pr_debug("hw_params r: IISMOD: %x\n", iismod); |
c1422a66 BD |
257 | |
258 | switch (params_format(params)) { | |
259 | case SNDRV_PCM_FORMAT_S8: | |
53599bbc CP |
260 | iismod &= ~S3C2410_IISMOD_16BIT; |
261 | ((struct s3c24xx_pcm_dma_params *) | |
262 | rtd->dai->cpu_dai->dma_data)->dma_size = 1; | |
c1422a66 BD |
263 | break; |
264 | case SNDRV_PCM_FORMAT_S16_LE: | |
265 | iismod |= S3C2410_IISMOD_16BIT; | |
53599bbc CP |
266 | ((struct s3c24xx_pcm_dma_params *) |
267 | rtd->dai->cpu_dai->dma_data)->dma_size = 2; | |
c1422a66 | 268 | break; |
53599bbc CP |
269 | default: |
270 | return -EINVAL; | |
c1422a66 BD |
271 | } |
272 | ||
273 | writel(iismod, s3c24xx_i2s.regs + S3C2410_IISMOD); | |
5314adc3 | 274 | pr_debug("hw_params w: IISMOD: %x\n", iismod); |
c1422a66 BD |
275 | return 0; |
276 | } | |
277 | ||
dee89c4d MB |
278 | static int s3c24xx_i2s_trigger(struct snd_pcm_substream *substream, int cmd, |
279 | struct snd_soc_dai *dai) | |
c1422a66 BD |
280 | { |
281 | int ret = 0; | |
282 | ||
ee7d4767 | 283 | pr_debug("Entered %s\n", __func__); |
c1422a66 BD |
284 | |
285 | switch (cmd) { | |
286 | case SNDRV_PCM_TRIGGER_START: | |
287 | case SNDRV_PCM_TRIGGER_RESUME: | |
288 | case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: | |
289 | if (!s3c24xx_snd_is_clkmaster()) { | |
290 | ret = s3c24xx_snd_lrsync(); | |
291 | if (ret) | |
292 | goto exit_err; | |
293 | } | |
294 | ||
295 | if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) | |
296 | s3c24xx_snd_rxctrl(1); | |
297 | else | |
298 | s3c24xx_snd_txctrl(1); | |
299 | break; | |
300 | case SNDRV_PCM_TRIGGER_STOP: | |
301 | case SNDRV_PCM_TRIGGER_SUSPEND: | |
302 | case SNDRV_PCM_TRIGGER_PAUSE_PUSH: | |
303 | if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) | |
304 | s3c24xx_snd_rxctrl(0); | |
305 | else | |
306 | s3c24xx_snd_txctrl(0); | |
307 | break; | |
308 | default: | |
309 | ret = -EINVAL; | |
310 | break; | |
311 | } | |
312 | ||
313 | exit_err: | |
314 | return ret; | |
315 | } | |
316 | ||
317 | /* | |
318 | * Set S3C24xx Clock source | |
319 | */ | |
1992a6fb | 320 | static int s3c24xx_i2s_set_sysclk(struct snd_soc_dai *cpu_dai, |
c1422a66 BD |
321 | int clk_id, unsigned int freq, int dir) |
322 | { | |
323 | u32 iismod = readl(s3c24xx_i2s.regs + S3C2410_IISMOD); | |
324 | ||
ee7d4767 | 325 | pr_debug("Entered %s\n", __func__); |
c1422a66 BD |
326 | |
327 | iismod &= ~S3C2440_IISMOD_MPLL; | |
328 | ||
329 | switch (clk_id) { | |
330 | case S3C24XX_CLKSRC_PCLK: | |
331 | break; | |
332 | case S3C24XX_CLKSRC_MPLL: | |
333 | iismod |= S3C2440_IISMOD_MPLL; | |
334 | break; | |
335 | default: | |
336 | return -EINVAL; | |
337 | } | |
338 | ||
339 | writel(iismod, s3c24xx_i2s.regs + S3C2410_IISMOD); | |
340 | return 0; | |
341 | } | |
342 | ||
343 | /* | |
344 | * Set S3C24xx Clock dividers | |
345 | */ | |
1992a6fb | 346 | static int s3c24xx_i2s_set_clkdiv(struct snd_soc_dai *cpu_dai, |
c1422a66 BD |
347 | int div_id, int div) |
348 | { | |
349 | u32 reg; | |
350 | ||
ee7d4767 | 351 | pr_debug("Entered %s\n", __func__); |
c1422a66 BD |
352 | |
353 | switch (div_id) { | |
82fb159a | 354 | case S3C24XX_DIV_BCLK: |
c1422a66 BD |
355 | reg = readl(s3c24xx_i2s.regs + S3C2410_IISMOD) & ~S3C2410_IISMOD_FS_MASK; |
356 | writel(reg | div, s3c24xx_i2s.regs + S3C2410_IISMOD); | |
357 | break; | |
82fb159a | 358 | case S3C24XX_DIV_MCLK: |
c1422a66 BD |
359 | reg = readl(s3c24xx_i2s.regs + S3C2410_IISMOD) & ~(S3C2410_IISMOD_384FS); |
360 | writel(reg | div, s3c24xx_i2s.regs + S3C2410_IISMOD); | |
361 | break; | |
362 | case S3C24XX_DIV_PRESCALER: | |
363 | writel(div, s3c24xx_i2s.regs + S3C2410_IISPSR); | |
364 | reg = readl(s3c24xx_i2s.regs + S3C2410_IISCON); | |
365 | writel(reg | S3C2410_IISCON_PSCEN, s3c24xx_i2s.regs + S3C2410_IISCON); | |
366 | break; | |
367 | default: | |
368 | return -EINVAL; | |
369 | } | |
370 | ||
371 | return 0; | |
372 | } | |
373 | ||
374 | /* | |
375 | * To avoid duplicating clock code, allow machine driver to | |
376 | * get the clockrate from here. | |
377 | */ | |
378 | u32 s3c24xx_i2s_get_clockrate(void) | |
379 | { | |
380 | return clk_get_rate(s3c24xx_i2s.iis_clk); | |
381 | } | |
382 | EXPORT_SYMBOL_GPL(s3c24xx_i2s_get_clockrate); | |
383 | ||
bdb92876 | 384 | static int s3c24xx_i2s_probe(struct platform_device *pdev, |
1992a6fb | 385 | struct snd_soc_dai *dai) |
c1422a66 | 386 | { |
ee7d4767 | 387 | pr_debug("Entered %s\n", __func__); |
c1422a66 BD |
388 | |
389 | s3c24xx_i2s.regs = ioremap(S3C2410_PA_IIS, 0x100); | |
390 | if (s3c24xx_i2s.regs == NULL) | |
391 | return -ENXIO; | |
392 | ||
0fe564a5 | 393 | s3c24xx_i2s.iis_clk = clk_get(&pdev->dev, "iis"); |
c1422a66 | 394 | if (s3c24xx_i2s.iis_clk == NULL) { |
b52a5195 | 395 | pr_err("failed to get iis_clock\n"); |
8642a4ba | 396 | iounmap(s3c24xx_i2s.regs); |
c1422a66 BD |
397 | return -ENODEV; |
398 | } | |
399 | clk_enable(s3c24xx_i2s.iis_clk); | |
400 | ||
401 | /* Configure the I2S pins in correct mode */ | |
402 | s3c2410_gpio_cfgpin(S3C2410_GPE0, S3C2410_GPE0_I2SLRCK); | |
403 | s3c2410_gpio_cfgpin(S3C2410_GPE1, S3C2410_GPE1_I2SSCLK); | |
404 | s3c2410_gpio_cfgpin(S3C2410_GPE2, S3C2410_GPE2_CDCLK); | |
405 | s3c2410_gpio_cfgpin(S3C2410_GPE3, S3C2410_GPE3_I2SSDI); | |
406 | s3c2410_gpio_cfgpin(S3C2410_GPE4, S3C2410_GPE4_I2SSDO); | |
407 | ||
408 | writel(S3C2410_IISCON_IISEN, s3c24xx_i2s.regs + S3C2410_IISCON); | |
409 | ||
410 | s3c24xx_snd_txctrl(0); | |
411 | s3c24xx_snd_rxctrl(0); | |
412 | ||
413 | return 0; | |
414 | } | |
415 | ||
5cd919a2 | 416 | #ifdef CONFIG_PM |
dc7d7b83 | 417 | static int s3c24xx_i2s_suspend(struct snd_soc_dai *cpu_dai) |
5cd919a2 | 418 | { |
ee7d4767 | 419 | pr_debug("Entered %s\n", __func__); |
40920307 | 420 | |
5cd919a2 GG |
421 | s3c24xx_i2s.iiscon = readl(s3c24xx_i2s.regs + S3C2410_IISCON); |
422 | s3c24xx_i2s.iismod = readl(s3c24xx_i2s.regs + S3C2410_IISMOD); | |
423 | s3c24xx_i2s.iisfcon = readl(s3c24xx_i2s.regs + S3C2410_IISFCON); | |
424 | s3c24xx_i2s.iispsr = readl(s3c24xx_i2s.regs + S3C2410_IISPSR); | |
425 | ||
426 | clk_disable(s3c24xx_i2s.iis_clk); | |
427 | ||
428 | return 0; | |
429 | } | |
430 | ||
dc7d7b83 | 431 | static int s3c24xx_i2s_resume(struct snd_soc_dai *cpu_dai) |
5cd919a2 | 432 | { |
ee7d4767 | 433 | pr_debug("Entered %s\n", __func__); |
5cd919a2 GG |
434 | clk_enable(s3c24xx_i2s.iis_clk); |
435 | ||
436 | writel(s3c24xx_i2s.iiscon, s3c24xx_i2s.regs + S3C2410_IISCON); | |
437 | writel(s3c24xx_i2s.iismod, s3c24xx_i2s.regs + S3C2410_IISMOD); | |
438 | writel(s3c24xx_i2s.iisfcon, s3c24xx_i2s.regs + S3C2410_IISFCON); | |
439 | writel(s3c24xx_i2s.iispsr, s3c24xx_i2s.regs + S3C2410_IISPSR); | |
440 | ||
441 | return 0; | |
442 | } | |
443 | #else | |
444 | #define s3c24xx_i2s_suspend NULL | |
445 | #define s3c24xx_i2s_resume NULL | |
446 | #endif | |
447 | ||
448 | ||
c1422a66 BD |
449 | #define S3C24XX_I2S_RATES \ |
450 | (SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_11025 | SNDRV_PCM_RATE_16000 | \ | |
451 | SNDRV_PCM_RATE_22050 | SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_44100 | \ | |
452 | SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_88200 | SNDRV_PCM_RATE_96000) | |
453 | ||
6335d055 EM |
454 | static struct snd_soc_dai_ops s3c24xx_i2s_dai_ops = { |
455 | .trigger = s3c24xx_i2s_trigger, | |
456 | .hw_params = s3c24xx_i2s_hw_params, | |
457 | .set_fmt = s3c24xx_i2s_set_fmt, | |
458 | .set_clkdiv = s3c24xx_i2s_set_clkdiv, | |
459 | .set_sysclk = s3c24xx_i2s_set_sysclk, | |
460 | }; | |
461 | ||
1992a6fb | 462 | struct snd_soc_dai s3c24xx_i2s_dai = { |
c1422a66 BD |
463 | .name = "s3c24xx-i2s", |
464 | .id = 0, | |
c1422a66 | 465 | .probe = s3c24xx_i2s_probe, |
5cd919a2 GG |
466 | .suspend = s3c24xx_i2s_suspend, |
467 | .resume = s3c24xx_i2s_resume, | |
c1422a66 BD |
468 | .playback = { |
469 | .channels_min = 2, | |
470 | .channels_max = 2, | |
471 | .rates = S3C24XX_I2S_RATES, | |
472 | .formats = SNDRV_PCM_FMTBIT_S8 | SNDRV_PCM_FMTBIT_S16_LE,}, | |
473 | .capture = { | |
474 | .channels_min = 2, | |
475 | .channels_max = 2, | |
476 | .rates = S3C24XX_I2S_RATES, | |
477 | .formats = SNDRV_PCM_FMTBIT_S8 | SNDRV_PCM_FMTBIT_S16_LE,}, | |
6335d055 | 478 | .ops = &s3c24xx_i2s_dai_ops, |
c1422a66 BD |
479 | }; |
480 | EXPORT_SYMBOL_GPL(s3c24xx_i2s_dai); | |
481 | ||
c9b3a40f | 482 | static int __init s3c24xx_i2s_init(void) |
3f4b783c MB |
483 | { |
484 | return snd_soc_register_dai(&s3c24xx_i2s_dai); | |
485 | } | |
486 | module_init(s3c24xx_i2s_init); | |
487 | ||
488 | static void __exit s3c24xx_i2s_exit(void) | |
489 | { | |
490 | snd_soc_unregister_dai(&s3c24xx_i2s_dai); | |
491 | } | |
492 | module_exit(s3c24xx_i2s_exit); | |
493 | ||
c1422a66 BD |
494 | /* Module information */ |
495 | MODULE_AUTHOR("Ben Dooks, <ben@simtec.co.uk>"); | |
496 | MODULE_DESCRIPTION("s3c24xx I2S SoC Interface"); | |
497 | MODULE_LICENSE("GPL"); |