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