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