Merge branch 'topic/hdsp' into for-linus
[pandora-kernel.git] / sound / soc / s6000 / s6000-i2s.c
1 /*
2  * ALSA SoC I2S Audio Layer for the Stretch S6000 family
3  *
4  * Author:      Daniel Gloeckner, <dg@emlix.com>
5  * Copyright:   (C) 2009 emlix GmbH <info@emlix.com>
6  *
7  * This program is free software; you can redistribute it and/or modify
8  * it under the terms of the GNU General Public License version 2 as
9  * published by the Free Software Foundation.
10  */
11
12 #include <linux/init.h>
13 #include <linux/module.h>
14 #include <linux/device.h>
15 #include <linux/delay.h>
16 #include <linux/clk.h>
17 #include <linux/interrupt.h>
18 #include <linux/io.h>
19
20 #include <sound/core.h>
21 #include <sound/pcm.h>
22 #include <sound/pcm_params.h>
23 #include <sound/initval.h>
24 #include <sound/soc.h>
25
26 #include "s6000-i2s.h"
27 #include "s6000-pcm.h"
28
29 struct s6000_i2s_dev {
30         dma_addr_t sifbase;
31         u8 __iomem *scbbase;
32         unsigned int wide;
33         unsigned int channel_in;
34         unsigned int channel_out;
35         unsigned int lines_in;
36         unsigned int lines_out;
37         struct s6000_pcm_dma_params dma_params;
38 };
39
40 #define S6_I2S_INTERRUPT_STATUS 0x00
41 #define   S6_I2S_INT_OVERRUN    1
42 #define   S6_I2S_INT_UNDERRUN   2
43 #define   S6_I2S_INT_ALIGNMENT  4
44 #define S6_I2S_INTERRUPT_ENABLE 0x04
45 #define S6_I2S_INTERRUPT_RAW    0x08
46 #define S6_I2S_INTERRUPT_CLEAR  0x0C
47 #define S6_I2S_INTERRUPT_SET    0x10
48 #define S6_I2S_MODE             0x20
49 #define   S6_I2S_DUAL           0
50 #define   S6_I2S_WIDE           1
51 #define S6_I2S_TX_DEFAULT       0x24
52 #define S6_I2S_DATA_CFG(c)      (0x40 + 0x10 * (c))
53 #define   S6_I2S_IN             0
54 #define   S6_I2S_OUT            1
55 #define   S6_I2S_UNUSED         2
56 #define S6_I2S_INTERFACE_CFG(c) (0x44 + 0x10 * (c))
57 #define   S6_I2S_DIV_MASK       0x001fff
58 #define   S6_I2S_16BIT          0x000000
59 #define   S6_I2S_20BIT          0x002000
60 #define   S6_I2S_24BIT          0x004000
61 #define   S6_I2S_32BIT          0x006000
62 #define   S6_I2S_BITS_MASK      0x006000
63 #define   S6_I2S_MEM_16BIT      0x000000
64 #define   S6_I2S_MEM_32BIT      0x008000
65 #define   S6_I2S_MEM_MASK       0x008000
66 #define   S6_I2S_CHANNELS_SHIFT 16
67 #define   S6_I2S_CHANNELS_MASK  0x030000
68 #define   S6_I2S_SCK_IN         0x000000
69 #define   S6_I2S_SCK_OUT        0x040000
70 #define   S6_I2S_SCK_DIR        0x040000
71 #define   S6_I2S_WS_IN          0x000000
72 #define   S6_I2S_WS_OUT         0x080000
73 #define   S6_I2S_WS_DIR         0x080000
74 #define   S6_I2S_LEFT_FIRST     0x000000
75 #define   S6_I2S_RIGHT_FIRST    0x100000
76 #define   S6_I2S_FIRST          0x100000
77 #define   S6_I2S_CUR_SCK        0x200000
78 #define   S6_I2S_CUR_WS         0x400000
79 #define S6_I2S_ENABLE(c)        (0x48 + 0x10 * (c))
80 #define   S6_I2S_DISABLE_IF     0x02
81 #define   S6_I2S_ENABLE_IF      0x03
82 #define   S6_I2S_IS_BUSY        0x04
83 #define   S6_I2S_DMA_ACTIVE     0x08
84 #define   S6_I2S_IS_ENABLED     0x10
85
86 #define S6_I2S_NUM_LINES        4
87
88 #define S6_I2S_SIF_PORT0        0x0000000
89 #define S6_I2S_SIF_PORT1        0x0000080 /* docs say 0x0000010 */
90
91 static inline void s6_i2s_write_reg(struct s6000_i2s_dev *dev, int reg, u32 val)
92 {
93         writel(val, dev->scbbase + reg);
94 }
95
96 static inline u32 s6_i2s_read_reg(struct s6000_i2s_dev *dev, int reg)
97 {
98         return readl(dev->scbbase + reg);
99 }
100
101 static inline void s6_i2s_mod_reg(struct s6000_i2s_dev *dev, int reg,
102                                   u32 mask, u32 val)
103 {
104         val ^= s6_i2s_read_reg(dev, reg) & ~mask;
105         s6_i2s_write_reg(dev, reg, val);
106 }
107
108 static void s6000_i2s_start_channel(struct s6000_i2s_dev *dev, int channel)
109 {
110         int i, j, cur, prev;
111
112         /*
113          * Wait for WCLK to toggle 5 times before enabling the channel
114          * s6000 Family Datasheet 3.6.4:
115          *   "At least two cycles of WS must occur between commands
116          *    to disable or enable the interface"
117          */
118         j = 0;
119         prev = ~S6_I2S_CUR_WS;
120         for (i = 1000000; --i && j < 6; ) {
121                 cur = s6_i2s_read_reg(dev, S6_I2S_INTERFACE_CFG(channel))
122                        & S6_I2S_CUR_WS;
123                 if (prev != cur) {
124                         prev = cur;
125                         j++;
126                 }
127         }
128         if (j < 6)
129                 printk(KERN_WARNING "s6000-i2s: timeout waiting for WCLK\n");
130
131         s6_i2s_write_reg(dev, S6_I2S_ENABLE(channel), S6_I2S_ENABLE_IF);
132 }
133
134 static void s6000_i2s_stop_channel(struct s6000_i2s_dev *dev, int channel)
135 {
136         s6_i2s_write_reg(dev, S6_I2S_ENABLE(channel), S6_I2S_DISABLE_IF);
137 }
138
139 static void s6000_i2s_start(struct snd_pcm_substream *substream)
140 {
141         struct snd_soc_pcm_runtime *rtd = substream->private_data;
142         struct s6000_i2s_dev *dev = rtd->dai->cpu_dai->private_data;
143         int channel;
144
145         channel = (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) ?
146                         dev->channel_out : dev->channel_in;
147
148         s6000_i2s_start_channel(dev, channel);
149 }
150
151 static void s6000_i2s_stop(struct snd_pcm_substream *substream)
152 {
153         struct snd_soc_pcm_runtime *rtd = substream->private_data;
154         struct s6000_i2s_dev *dev = rtd->dai->cpu_dai->private_data;
155         int channel;
156
157         channel = (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) ?
158                         dev->channel_out : dev->channel_in;
159
160         s6000_i2s_stop_channel(dev, channel);
161 }
162
163 static int s6000_i2s_trigger(struct snd_pcm_substream *substream, int cmd,
164                              int after)
165 {
166         switch (cmd) {
167         case SNDRV_PCM_TRIGGER_START:
168         case SNDRV_PCM_TRIGGER_RESUME:
169         case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
170                 if ((substream->stream == SNDRV_PCM_STREAM_CAPTURE) ^ !after)
171                         s6000_i2s_start(substream);
172                 break;
173         case SNDRV_PCM_TRIGGER_STOP:
174         case SNDRV_PCM_TRIGGER_SUSPEND:
175         case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
176                 if (!after)
177                         s6000_i2s_stop(substream);
178         }
179         return 0;
180 }
181
182 static unsigned int s6000_i2s_int_sources(struct s6000_i2s_dev *dev)
183 {
184         unsigned int pending;
185         pending = s6_i2s_read_reg(dev, S6_I2S_INTERRUPT_RAW);
186         pending &= S6_I2S_INT_ALIGNMENT |
187                    S6_I2S_INT_UNDERRUN |
188                    S6_I2S_INT_OVERRUN;
189         s6_i2s_write_reg(dev, S6_I2S_INTERRUPT_CLEAR, pending);
190
191         return pending;
192 }
193
194 static unsigned int s6000_i2s_check_xrun(struct snd_soc_dai *cpu_dai)
195 {
196         struct s6000_i2s_dev *dev = cpu_dai->private_data;
197         unsigned int errors;
198         unsigned int ret;
199
200         errors = s6000_i2s_int_sources(dev);
201         if (likely(!errors))
202                 return 0;
203
204         ret = 0;
205         if (errors & S6_I2S_INT_ALIGNMENT)
206                 printk(KERN_ERR "s6000-i2s: WCLK misaligned\n");
207         if (errors & S6_I2S_INT_UNDERRUN)
208                 ret |= 1 << SNDRV_PCM_STREAM_PLAYBACK;
209         if (errors & S6_I2S_INT_OVERRUN)
210                 ret |= 1 << SNDRV_PCM_STREAM_CAPTURE;
211         return ret;
212 }
213
214 static void s6000_i2s_wait_disabled(struct s6000_i2s_dev *dev)
215 {
216         int channel;
217         int n = 50;
218         for (channel = 0; channel < 2; channel++) {
219                 while (--n >= 0) {
220                         int v = s6_i2s_read_reg(dev, S6_I2S_ENABLE(channel));
221                         if ((v & S6_I2S_IS_ENABLED)
222                             || !(v & (S6_I2S_DMA_ACTIVE | S6_I2S_IS_BUSY)))
223                                 break;
224                         udelay(20);
225                 }
226         }
227         if (n < 0)
228                 printk(KERN_WARNING "s6000-i2s: timeout disabling interfaces");
229 }
230
231 static int s6000_i2s_set_dai_fmt(struct snd_soc_dai *cpu_dai,
232                                    unsigned int fmt)
233 {
234         struct s6000_i2s_dev *dev = cpu_dai->private_data;
235         u32 w;
236
237         switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
238         case SND_SOC_DAIFMT_CBM_CFM:
239                 w = S6_I2S_SCK_IN | S6_I2S_WS_IN;
240                 break;
241         case SND_SOC_DAIFMT_CBS_CFM:
242                 w = S6_I2S_SCK_OUT | S6_I2S_WS_IN;
243                 break;
244         case SND_SOC_DAIFMT_CBM_CFS:
245                 w = S6_I2S_SCK_IN | S6_I2S_WS_OUT;
246                 break;
247         case SND_SOC_DAIFMT_CBS_CFS:
248                 w = S6_I2S_SCK_OUT | S6_I2S_WS_OUT;
249                 break;
250         default:
251                 return -EINVAL;
252         }
253
254         switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
255         case SND_SOC_DAIFMT_NB_NF:
256                 w |= S6_I2S_LEFT_FIRST;
257                 break;
258         case SND_SOC_DAIFMT_NB_IF:
259                 w |= S6_I2S_RIGHT_FIRST;
260                 break;
261         default:
262                 return -EINVAL;
263         }
264
265         s6_i2s_mod_reg(dev, S6_I2S_INTERFACE_CFG(0),
266                        S6_I2S_FIRST | S6_I2S_WS_DIR | S6_I2S_SCK_DIR, w);
267         s6_i2s_mod_reg(dev, S6_I2S_INTERFACE_CFG(1),
268                        S6_I2S_FIRST | S6_I2S_WS_DIR | S6_I2S_SCK_DIR, w);
269
270         return 0;
271 }
272
273 static int s6000_i2s_set_clkdiv(struct snd_soc_dai *dai, int div_id, int div)
274 {
275         struct s6000_i2s_dev *dev = dai->private_data;
276
277         if (!div || (div & 1) || div > (S6_I2S_DIV_MASK + 1) * 2)
278                 return -EINVAL;
279
280         s6_i2s_mod_reg(dev, S6_I2S_INTERFACE_CFG(div_id),
281                        S6_I2S_DIV_MASK, div / 2 - 1);
282         return 0;
283 }
284
285 static int s6000_i2s_hw_params(struct snd_pcm_substream *substream,
286                                struct snd_pcm_hw_params *params,
287                                struct snd_soc_dai *dai)
288 {
289         struct s6000_i2s_dev *dev = dai->private_data;
290         int interf;
291         u32 w = 0;
292
293         if (dev->wide)
294                 interf = 0;
295         else {
296                 w |= (((params_channels(params) - 2) / 2)
297                       << S6_I2S_CHANNELS_SHIFT) & S6_I2S_CHANNELS_MASK;
298                 interf = (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
299                                 ? dev->channel_out : dev->channel_in;
300         }
301
302         switch (params_format(params)) {
303         case SNDRV_PCM_FORMAT_S16_LE:
304                 w |= S6_I2S_16BIT | S6_I2S_MEM_16BIT;
305                 break;
306         case SNDRV_PCM_FORMAT_S32_LE:
307                 w |= S6_I2S_32BIT | S6_I2S_MEM_32BIT;
308                 break;
309         default:
310                 printk(KERN_WARNING "s6000-i2s: unsupported PCM format %x\n",
311                        params_format(params));
312                 return -EINVAL;
313         }
314
315         if (s6_i2s_read_reg(dev, S6_I2S_INTERFACE_CFG(interf))
316              & S6_I2S_IS_ENABLED) {
317                 printk(KERN_ERR "s6000-i2s: interface already enabled\n");
318                 return -EBUSY;
319         }
320
321         s6_i2s_mod_reg(dev, S6_I2S_INTERFACE_CFG(interf),
322                        S6_I2S_CHANNELS_MASK|S6_I2S_MEM_MASK|S6_I2S_BITS_MASK,
323                        w);
324
325         return 0;
326 }
327
328 static int s6000_i2s_dai_probe(struct platform_device *pdev,
329                                struct snd_soc_dai *dai)
330 {
331         struct s6000_i2s_dev *dev = dai->private_data;
332         struct s6000_snd_platform_data *pdata = pdev->dev.platform_data;
333
334         if (!pdata)
335                 return -EINVAL;
336
337         dev->wide = pdata->wide;
338         dev->channel_in = pdata->channel_in;
339         dev->channel_out = pdata->channel_out;
340         dev->lines_in = pdata->lines_in;
341         dev->lines_out = pdata->lines_out;
342
343         s6_i2s_write_reg(dev, S6_I2S_MODE,
344                          dev->wide ? S6_I2S_WIDE : S6_I2S_DUAL);
345
346         if (dev->wide) {
347                 int i;
348
349                 if (dev->lines_in + dev->lines_out > S6_I2S_NUM_LINES)
350                         return -EINVAL;
351
352                 dev->channel_in = 0;
353                 dev->channel_out = 1;
354                 dai->capture.channels_min = 2 * dev->lines_in;
355                 dai->capture.channels_max = dai->capture.channels_min;
356                 dai->playback.channels_min = 2 * dev->lines_out;
357                 dai->playback.channels_max = dai->playback.channels_min;
358
359                 for (i = 0; i < dev->lines_out; i++)
360                         s6_i2s_write_reg(dev, S6_I2S_DATA_CFG(i), S6_I2S_OUT);
361
362                 for (; i < S6_I2S_NUM_LINES - dev->lines_in; i++)
363                         s6_i2s_write_reg(dev, S6_I2S_DATA_CFG(i),
364                                          S6_I2S_UNUSED);
365
366                 for (; i < S6_I2S_NUM_LINES; i++)
367                         s6_i2s_write_reg(dev, S6_I2S_DATA_CFG(i), S6_I2S_IN);
368         } else {
369                 unsigned int cfg[2] = {S6_I2S_UNUSED, S6_I2S_UNUSED};
370
371                 if (dev->lines_in > 1 || dev->lines_out > 1)
372                         return -EINVAL;
373
374                 dai->capture.channels_min = 2 * dev->lines_in;
375                 dai->capture.channels_max = 8 * dev->lines_in;
376                 dai->playback.channels_min = 2 * dev->lines_out;
377                 dai->playback.channels_max = 8 * dev->lines_out;
378
379                 if (dev->lines_in)
380                         cfg[dev->channel_in] = S6_I2S_IN;
381                 if (dev->lines_out)
382                         cfg[dev->channel_out] = S6_I2S_OUT;
383
384                 s6_i2s_write_reg(dev, S6_I2S_DATA_CFG(0), cfg[0]);
385                 s6_i2s_write_reg(dev, S6_I2S_DATA_CFG(1), cfg[1]);
386         }
387
388         if (dev->lines_out) {
389                 if (dev->lines_in) {
390                         if (!dev->dma_params.dma_out)
391                                 return -ENODEV;
392                 } else {
393                         dev->dma_params.dma_out = dev->dma_params.dma_in;
394                         dev->dma_params.dma_in = 0;
395                 }
396         }
397         dev->dma_params.sif_in = dev->sifbase + (dev->channel_in ?
398                                         S6_I2S_SIF_PORT1 : S6_I2S_SIF_PORT0);
399         dev->dma_params.sif_out = dev->sifbase + (dev->channel_out ?
400                                         S6_I2S_SIF_PORT1 : S6_I2S_SIF_PORT0);
401         dev->dma_params.same_rate = pdata->same_rate | pdata->wide;
402         return 0;
403 }
404
405 #define S6000_I2S_RATES (SNDRV_PCM_RATE_CONTINUOUS | SNDRV_PCM_RATE_5512 | \
406                          SNDRV_PCM_RATE_8000_192000)
407 #define S6000_I2S_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S32_LE)
408
409 static struct snd_soc_dai_ops s6000_i2s_dai_ops = {
410         .set_fmt = s6000_i2s_set_dai_fmt,
411         .set_clkdiv = s6000_i2s_set_clkdiv,
412         .hw_params = s6000_i2s_hw_params,
413 };
414
415 struct snd_soc_dai s6000_i2s_dai = {
416         .name = "s6000-i2s",
417         .id = 0,
418         .probe = s6000_i2s_dai_probe,
419         .playback = {
420                 .channels_min = 2,
421                 .channels_max = 8,
422                 .formats = S6000_I2S_FORMATS,
423                 .rates = S6000_I2S_RATES,
424                 .rate_min = 0,
425                 .rate_max = 1562500,
426         },
427         .capture = {
428                 .channels_min = 2,
429                 .channels_max = 8,
430                 .formats = S6000_I2S_FORMATS,
431                 .rates = S6000_I2S_RATES,
432                 .rate_min = 0,
433                 .rate_max = 1562500,
434         },
435         .ops = &s6000_i2s_dai_ops,
436 }
437 EXPORT_SYMBOL_GPL(s6000_i2s_dai);
438
439 static int __devinit s6000_i2s_probe(struct platform_device *pdev)
440 {
441         struct s6000_i2s_dev *dev;
442         struct resource *scbmem, *sifmem, *region, *dma1, *dma2;
443         u8 __iomem *mmio;
444         int ret;
445
446         scbmem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
447         if (!scbmem) {
448                 dev_err(&pdev->dev, "no mem resource?\n");
449                 ret = -ENODEV;
450                 goto err_release_none;
451         }
452
453         region = request_mem_region(scbmem->start,
454                                     scbmem->end - scbmem->start + 1,
455                                     pdev->name);
456         if (!region) {
457                 dev_err(&pdev->dev, "I2S SCB region already claimed\n");
458                 ret = -EBUSY;
459                 goto err_release_none;
460         }
461
462         mmio = ioremap(scbmem->start, scbmem->end - scbmem->start + 1);
463         if (!mmio) {
464                 dev_err(&pdev->dev, "can't ioremap SCB region\n");
465                 ret = -ENOMEM;
466                 goto err_release_scb;
467         }
468
469         sifmem = platform_get_resource(pdev, IORESOURCE_MEM, 1);
470         if (!sifmem) {
471                 dev_err(&pdev->dev, "no second mem resource?\n");
472                 ret = -ENODEV;
473                 goto err_release_map;
474         }
475
476         region = request_mem_region(sifmem->start,
477                                     sifmem->end - sifmem->start + 1,
478                                     pdev->name);
479         if (!region) {
480                 dev_err(&pdev->dev, "I2S SIF region already claimed\n");
481                 ret = -EBUSY;
482                 goto err_release_map;
483         }
484
485         dma1 = platform_get_resource(pdev, IORESOURCE_DMA, 0);
486         if (!dma1) {
487                 dev_err(&pdev->dev, "no dma resource?\n");
488                 ret = -ENODEV;
489                 goto err_release_sif;
490         }
491
492         region = request_mem_region(dma1->start, dma1->end - dma1->start + 1,
493                                     pdev->name);
494         if (!region) {
495                 dev_err(&pdev->dev, "I2S DMA region already claimed\n");
496                 ret = -EBUSY;
497                 goto err_release_sif;
498         }
499
500         dma2 = platform_get_resource(pdev, IORESOURCE_DMA, 1);
501         if (dma2) {
502                 region = request_mem_region(dma2->start,
503                                             dma2->end - dma2->start + 1,
504                                             pdev->name);
505                 if (!region) {
506                         dev_err(&pdev->dev,
507                                 "I2S DMA region already claimed\n");
508                         ret = -EBUSY;
509                         goto err_release_dma1;
510                 }
511         }
512
513         dev = kzalloc(sizeof(struct s6000_i2s_dev), GFP_KERNEL);
514         if (!dev) {
515                 ret = -ENOMEM;
516                 goto err_release_dma2;
517         }
518
519         s6000_i2s_dai.dev = &pdev->dev;
520         s6000_i2s_dai.private_data = dev;
521         s6000_i2s_dai.dma_data = &dev->dma_params;
522
523         dev->sifbase = sifmem->start;
524         dev->scbbase = mmio;
525
526         s6_i2s_write_reg(dev, S6_I2S_INTERRUPT_ENABLE, 0);
527         s6_i2s_write_reg(dev, S6_I2S_INTERRUPT_CLEAR,
528                          S6_I2S_INT_ALIGNMENT |
529                          S6_I2S_INT_UNDERRUN |
530                          S6_I2S_INT_OVERRUN);
531
532         s6000_i2s_stop_channel(dev, 0);
533         s6000_i2s_stop_channel(dev, 1);
534         s6000_i2s_wait_disabled(dev);
535
536         dev->dma_params.check_xrun = s6000_i2s_check_xrun;
537         dev->dma_params.trigger = s6000_i2s_trigger;
538         dev->dma_params.dma_in = dma1->start;
539         dev->dma_params.dma_out = dma2 ? dma2->start : 0;
540         dev->dma_params.irq = platform_get_irq(pdev, 0);
541         if (dev->dma_params.irq < 0) {
542                 dev_err(&pdev->dev, "no irq resource?\n");
543                 ret = -ENODEV;
544                 goto err_release_dev;
545         }
546
547         s6_i2s_write_reg(dev, S6_I2S_INTERRUPT_ENABLE,
548                          S6_I2S_INT_ALIGNMENT |
549                          S6_I2S_INT_UNDERRUN |
550                          S6_I2S_INT_OVERRUN);
551
552         ret = snd_soc_register_dai(&s6000_i2s_dai);
553         if (ret)
554                 goto err_release_dev;
555
556         return 0;
557
558 err_release_dev:
559         kfree(dev);
560 err_release_dma2:
561         if (dma2)
562                 release_mem_region(dma2->start, dma2->end - dma2->start + 1);
563 err_release_dma1:
564         release_mem_region(dma1->start, dma1->end - dma1->start + 1);
565 err_release_sif:
566         release_mem_region(sifmem->start, (sifmem->end - sifmem->start) + 1);
567 err_release_map:
568         iounmap(mmio);
569 err_release_scb:
570         release_mem_region(scbmem->start, (scbmem->end - scbmem->start) + 1);
571 err_release_none:
572         return ret;
573 }
574
575 static void __devexit s6000_i2s_remove(struct platform_device *pdev)
576 {
577         struct s6000_i2s_dev *dev = s6000_i2s_dai.private_data;
578         struct resource *region;
579         void __iomem *mmio = dev->scbbase;
580
581         snd_soc_unregister_dai(&s6000_i2s_dai);
582
583         s6000_i2s_stop_channel(dev, 0);
584         s6000_i2s_stop_channel(dev, 1);
585
586         s6_i2s_write_reg(dev, S6_I2S_INTERRUPT_ENABLE, 0);
587         s6000_i2s_dai.private_data = 0;
588         kfree(dev);
589
590         region = platform_get_resource(pdev, IORESOURCE_DMA, 0);
591         release_mem_region(region->start, region->end - region->start + 1);
592
593         region = platform_get_resource(pdev, IORESOURCE_DMA, 1);
594         if (region)
595                 release_mem_region(region->start,
596                                    region->end - region->start + 1);
597
598         region = platform_get_resource(pdev, IORESOURCE_MEM, 0);
599         release_mem_region(region->start, (region->end - region->start) + 1);
600
601         iounmap(mmio);
602         region = platform_get_resource(pdev, IORESOURCE_IO, 0);
603         release_mem_region(region->start, (region->end - region->start) + 1);
604 }
605
606 static struct platform_driver s6000_i2s_driver = {
607         .probe  = s6000_i2s_probe,
608         .remove = __devexit_p(s6000_i2s_remove),
609         .driver = {
610                 .name   = "s6000-i2s",
611                 .owner  = THIS_MODULE,
612         },
613 };
614
615 static int __init s6000_i2s_init(void)
616 {
617         return platform_driver_register(&s6000_i2s_driver);
618 }
619 module_init(s6000_i2s_init);
620
621 static void __exit s6000_i2s_exit(void)
622 {
623         platform_driver_unregister(&s6000_i2s_driver);
624 }
625 module_exit(s6000_i2s_exit);
626
627 MODULE_AUTHOR("Daniel Gloeckner");
628 MODULE_DESCRIPTION("Stretch s6000 family I2S SoC Interface");
629 MODULE_LICENSE("GPL");