~ubuntu-branches/ubuntu/maverick/linux-backports-modules-2.6.32/maverick

« back to all changes in this revision

Viewing changes to updates/alsa-driver/alsa-kernel/soc/s3c24xx/s3c-i2s-v2.c

  • Committer: Bazaar Package Importer
  • Author(s): Andy Whitcroft, Andy Whitcroft
  • Date: 2010-02-04 23:15:51 UTC
  • Revision ID: james.westby@ubuntu.com-20100204231551-vjz5pkvxclukjxm1
Tags: 2.6.32-12.1
[ Andy Whitcroft ]

* initial LBM for lucid
* drop generated files
* printchanges -- rebase tree does not have stable tags use changelog
* printenv -- add revisions to printenv output
* formally rename compat-wireless to linux-backports-modules-wireless
* Update to compat-wireless-2.6.33-rc5
* update nouveau to mainline 2.6.33-rc4
* add new LBM package for nouveau
* nouveau -- fix major numbers and proc entry names
* fix up firmware installs for -wireless
* clean up UPDATE-NOVEAU
* update Nouveau to v2.6.33-rc6

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
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 <mach/dma.h>
 
36
 
 
37
#include "s3c-i2s-v2.h"
 
38
#include "s3c-dma.h"
 
39
 
 
40
#undef S3C_IIS_V2_SUPPORTED
 
41
 
 
42
#if defined(CONFIG_CPU_S3C2412) || defined(CONFIG_CPU_S3C2413)
 
43
#define S3C_IIS_V2_SUPPORTED
 
44
#endif
 
45
 
 
46
#ifdef CONFIG_PLAT_S3C64XX
 
47
#define S3C_IIS_V2_SUPPORTED
 
48
#endif
 
49
 
 
50
#ifndef S3C_IIS_V2_SUPPORTED
 
51
#error Unsupported CPU model
 
52
#endif
 
53
 
 
54
#define S3C2412_I2S_DEBUG_CON 0
 
55
 
 
56
static inline struct s3c_i2sv2_info *to_info(struct snd_soc_dai *cpu_dai)
 
57
{
 
58
        return cpu_dai->private_data;
 
59
}
 
60
 
 
61
#define bit_set(v, b) (((v) & (b)) ? 1 : 0)
 
62
 
 
63
#if S3C2412_I2S_DEBUG_CON
 
64
static void dbg_showcon(const char *fn, u32 con)
 
65
{
 
66
        printk(KERN_DEBUG "%s: LRI=%d, TXFEMPT=%d, RXFEMPT=%d, TXFFULL=%d, RXFFULL=%d\n", fn,
 
67
               bit_set(con, S3C2412_IISCON_LRINDEX),
 
68
               bit_set(con, S3C2412_IISCON_TXFIFO_EMPTY),
 
69
               bit_set(con, S3C2412_IISCON_RXFIFO_EMPTY),
 
70
               bit_set(con, S3C2412_IISCON_TXFIFO_FULL),
 
71
               bit_set(con, S3C2412_IISCON_RXFIFO_FULL));
 
72
 
 
73
        printk(KERN_DEBUG "%s: PAUSE: TXDMA=%d, RXDMA=%d, TXCH=%d, RXCH=%d\n",
 
74
               fn,
 
75
               bit_set(con, S3C2412_IISCON_TXDMA_PAUSE),
 
76
               bit_set(con, S3C2412_IISCON_RXDMA_PAUSE),
 
77
               bit_set(con, S3C2412_IISCON_TXCH_PAUSE),
 
78
               bit_set(con, S3C2412_IISCON_RXCH_PAUSE));
 
79
        printk(KERN_DEBUG "%s: ACTIVE: TXDMA=%d, RXDMA=%d, IIS=%d\n", fn,
 
80
               bit_set(con, S3C2412_IISCON_TXDMA_ACTIVE),
 
81
               bit_set(con, S3C2412_IISCON_RXDMA_ACTIVE),
 
82
               bit_set(con, S3C2412_IISCON_IIS_ACTIVE));
 
83
}
 
84
#else
 
85
static inline void dbg_showcon(const char *fn, u32 con)
 
86
{
 
87
}
 
88
#endif
 
89
 
 
90
 
 
91
/* Turn on or off the transmission path. */
 
92
static void s3c2412_snd_txctrl(struct s3c_i2sv2_info *i2s, int on)
 
93
{
 
94
        void __iomem *regs = i2s->regs;
 
95
        u32 fic, con, mod;
 
96
 
 
97
        pr_debug("%s(%d)\n", __func__, on);
 
98
 
 
99
        fic = readl(regs + S3C2412_IISFIC);
 
100
        con = readl(regs + S3C2412_IISCON);
 
101
        mod = readl(regs + S3C2412_IISMOD);
 
102
 
 
103
        pr_debug("%s: IIS: CON=%x MOD=%x FIC=%x\n", __func__, con, mod, fic);
 
104
 
 
105
        if (on) {
 
106
                con |= S3C2412_IISCON_TXDMA_ACTIVE | S3C2412_IISCON_IIS_ACTIVE;
 
107
                con &= ~S3C2412_IISCON_TXDMA_PAUSE;
 
108
                con &= ~S3C2412_IISCON_TXCH_PAUSE;
 
109
 
 
110
                switch (mod & S3C2412_IISMOD_MODE_MASK) {
 
111
                case S3C2412_IISMOD_MODE_TXONLY:
 
112
                case S3C2412_IISMOD_MODE_TXRX:
 
113
                        /* do nothing, we are in the right mode */
 
114
                        break;
 
115
 
 
116
                case S3C2412_IISMOD_MODE_RXONLY:
 
117
                        mod &= ~S3C2412_IISMOD_MODE_MASK;
 
118
                        mod |= S3C2412_IISMOD_MODE_TXRX;
 
119
                        break;
 
120
 
 
121
                default:
 
122
                        dev_err(i2s->dev, "TXEN: Invalid MODE %x in IISMOD\n",
 
123
                                mod & S3C2412_IISMOD_MODE_MASK);
 
124
                        break;
 
125
                }
 
126
 
 
127
                writel(con, regs + S3C2412_IISCON);
 
128
                writel(mod, regs + S3C2412_IISMOD);
 
129
        } else {
 
130
                /* Note, we do not have any indication that the FIFO problems
 
131
                 * tha the S3C2410/2440 had apply here, so we should be able
 
132
                 * to disable the DMA and TX without resetting the FIFOS.
 
133
                 */
 
134
 
 
135
                con |=  S3C2412_IISCON_TXDMA_PAUSE;
 
136
                con |=  S3C2412_IISCON_TXCH_PAUSE;
 
137
                con &= ~S3C2412_IISCON_TXDMA_ACTIVE;
 
138
 
 
139
                switch (mod & S3C2412_IISMOD_MODE_MASK) {
 
140
                case S3C2412_IISMOD_MODE_TXRX:
 
141
                        mod &= ~S3C2412_IISMOD_MODE_MASK;
 
142
                        mod |= S3C2412_IISMOD_MODE_RXONLY;
 
143
                        break;
 
144
 
 
145
                case S3C2412_IISMOD_MODE_TXONLY:
 
146
                        mod &= ~S3C2412_IISMOD_MODE_MASK;
 
147
                        con &= ~S3C2412_IISCON_IIS_ACTIVE;
 
148
                        break;
 
149
 
 
150
                default:
 
151
                        dev_err(i2s->dev, "TXDIS: Invalid MODE %x in IISMOD\n",
 
152
                                mod & S3C2412_IISMOD_MODE_MASK);
 
153
                        break;
 
154
                }
 
155
 
 
156
                writel(mod, regs + S3C2412_IISMOD);
 
157
                writel(con, regs + S3C2412_IISCON);
 
158
        }
 
159
 
 
160
        fic = readl(regs + S3C2412_IISFIC);
 
161
        dbg_showcon(__func__, con);
 
162
        pr_debug("%s: IIS: CON=%x MOD=%x FIC=%x\n", __func__, con, mod, fic);
 
163
}
 
164
 
 
165
static void s3c2412_snd_rxctrl(struct s3c_i2sv2_info *i2s, int on)
 
166
{
 
167
        void __iomem *regs = i2s->regs;
 
168
        u32 fic, con, mod;
 
169
 
 
170
        pr_debug("%s(%d)\n", __func__, on);
 
171
 
 
172
        fic = readl(regs + S3C2412_IISFIC);
 
173
        con = readl(regs + S3C2412_IISCON);
 
174
        mod = readl(regs + S3C2412_IISMOD);
 
175
 
 
176
        pr_debug("%s: IIS: CON=%x MOD=%x FIC=%x\n", __func__, con, mod, fic);
 
177
 
 
178
        if (on) {
 
179
                con |= S3C2412_IISCON_RXDMA_ACTIVE | S3C2412_IISCON_IIS_ACTIVE;
 
180
                con &= ~S3C2412_IISCON_RXDMA_PAUSE;
 
181
                con &= ~S3C2412_IISCON_RXCH_PAUSE;
 
182
 
 
183
                switch (mod & S3C2412_IISMOD_MODE_MASK) {
 
184
                case S3C2412_IISMOD_MODE_TXRX:
 
185
                case S3C2412_IISMOD_MODE_RXONLY:
 
186
                        /* do nothing, we are in the right mode */
 
187
                        break;
 
188
 
 
189
                case S3C2412_IISMOD_MODE_TXONLY:
 
190
                        mod &= ~S3C2412_IISMOD_MODE_MASK;
 
191
                        mod |= S3C2412_IISMOD_MODE_TXRX;
 
192
                        break;
 
193
 
 
194
                default:
 
195
                        dev_err(i2s->dev, "RXEN: Invalid MODE %x in IISMOD\n",
 
196
                                mod & S3C2412_IISMOD_MODE_MASK);
 
197
                }
 
198
 
 
199
                writel(mod, regs + S3C2412_IISMOD);
 
200
                writel(con, regs + S3C2412_IISCON);
 
201
        } else {
 
202
                /* See txctrl notes on FIFOs. */
 
203
 
 
204
                con &= ~S3C2412_IISCON_RXDMA_ACTIVE;
 
205
                con |=  S3C2412_IISCON_RXDMA_PAUSE;
 
206
                con |=  S3C2412_IISCON_RXCH_PAUSE;
 
207
 
 
208
                switch (mod & S3C2412_IISMOD_MODE_MASK) {
 
209
                case S3C2412_IISMOD_MODE_RXONLY:
 
210
                        con &= ~S3C2412_IISCON_IIS_ACTIVE;
 
211
                        mod &= ~S3C2412_IISMOD_MODE_MASK;
 
212
                        break;
 
213
 
 
214
                case S3C2412_IISMOD_MODE_TXRX:
 
215
                        mod &= ~S3C2412_IISMOD_MODE_MASK;
 
216
                        mod |= S3C2412_IISMOD_MODE_TXONLY;
 
217
                        break;
 
218
 
 
219
                default:
 
220
                        dev_err(i2s->dev, "RXDIS: Invalid MODE %x in IISMOD\n",
 
221
                                mod & S3C2412_IISMOD_MODE_MASK);
 
222
                }
 
223
 
 
224
                writel(con, regs + S3C2412_IISCON);
 
225
                writel(mod, regs + S3C2412_IISMOD);
 
226
        }
 
227
 
 
228
        fic = readl(regs + S3C2412_IISFIC);
 
229
        pr_debug("%s: IIS: CON=%x MOD=%x FIC=%x\n", __func__, con, mod, fic);
 
230
}
 
231
 
 
232
#define msecs_to_loops(t) (loops_per_jiffy / 1000 * HZ * t)
 
233
 
 
234
/*
 
235
 * Wait for the LR signal to allow synchronisation to the L/R clock
 
236
 * from the codec. May only be needed for slave mode.
 
237
 */
 
238
static int s3c2412_snd_lrsync(struct s3c_i2sv2_info *i2s)
 
239
{
 
240
        u32 iiscon;
 
241
        unsigned long loops = msecs_to_loops(5);
 
242
 
 
243
        pr_debug("Entered %s\n", __func__);
 
244
 
 
245
        while (--loops) {
 
246
                iiscon = readl(i2s->regs + S3C2412_IISCON);
 
247
                if (iiscon & S3C2412_IISCON_LRINDEX)
 
248
                        break;
 
249
 
 
250
                cpu_relax();
 
251
        }
 
252
 
 
253
        if (!loops) {
 
254
                printk(KERN_ERR "%s: timeout\n", __func__);
 
255
                return -ETIMEDOUT;
 
256
        }
 
257
 
 
258
        return 0;
 
259
}
 
260
 
 
261
/*
 
262
 * Set S3C2412 I2S DAI format
 
263
 */
 
264
static int s3c2412_i2s_set_fmt(struct snd_soc_dai *cpu_dai,
 
265
                               unsigned int fmt)
 
266
{
 
267
        struct s3c_i2sv2_info *i2s = to_info(cpu_dai);
 
268
        u32 iismod;
 
269
 
 
270
        pr_debug("Entered %s\n", __func__);
 
271
 
 
272
        iismod = readl(i2s->regs + S3C2412_IISMOD);
 
273
        pr_debug("hw_params r: IISMOD: %x \n", iismod);
 
274
 
 
275
#if defined(CONFIG_CPU_S3C2412) || defined(CONFIG_CPU_S3C2413)
 
276
#define IISMOD_MASTER_MASK S3C2412_IISMOD_MASTER_MASK
 
277
#define IISMOD_SLAVE S3C2412_IISMOD_SLAVE
 
278
#define IISMOD_MASTER S3C2412_IISMOD_MASTER_INTERNAL
 
279
#endif
 
280
 
 
281
#if defined(CONFIG_PLAT_S3C64XX)
 
282
/* From Rev1.1 datasheet, we have two master and two slave modes:
 
283
 * IMS[11:10]:
 
284
 *      00 = master mode, fed from PCLK
 
285
 *      01 = master mode, fed from CLKAUDIO
 
286
 *      10 = slave mode, using PCLK
 
287
 *      11 = slave mode, using I2SCLK
 
288
 */
 
289
#define IISMOD_MASTER_MASK (1 << 11)
 
290
#define IISMOD_SLAVE (1 << 11)
 
291
#define IISMOD_MASTER (0 << 11)
 
292
#endif
 
293
 
 
294
        switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
 
295
        case SND_SOC_DAIFMT_CBM_CFM:
 
296
                i2s->master = 0;
 
297
                iismod &= ~IISMOD_MASTER_MASK;
 
298
                iismod |= IISMOD_SLAVE;
 
299
                break;
 
300
        case SND_SOC_DAIFMT_CBS_CFS:
 
301
                i2s->master = 1;
 
302
                iismod &= ~IISMOD_MASTER_MASK;
 
303
                iismod |= IISMOD_MASTER;
 
304
                break;
 
305
        default:
 
306
                pr_err("unknwon master/slave format\n");
 
307
                return -EINVAL;
 
308
        }
 
309
 
 
310
        iismod &= ~S3C2412_IISMOD_SDF_MASK;
 
311
 
 
312
        switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
 
313
        case SND_SOC_DAIFMT_RIGHT_J:
 
314
                iismod |= S3C2412_IISMOD_LR_RLOW;
 
315
                iismod |= S3C2412_IISMOD_SDF_MSB;
 
316
                break;
 
317
        case SND_SOC_DAIFMT_LEFT_J:
 
318
                iismod |= S3C2412_IISMOD_LR_RLOW;
 
319
                iismod |= S3C2412_IISMOD_SDF_LSB;
 
320
                break;
 
321
        case SND_SOC_DAIFMT_I2S:
 
322
                iismod &= ~S3C2412_IISMOD_LR_RLOW;
 
323
                iismod |= S3C2412_IISMOD_SDF_IIS;
 
324
                break;
 
325
        default:
 
326
                pr_err("Unknown data format\n");
 
327
                return -EINVAL;
 
328
        }
 
329
 
 
330
        writel(iismod, i2s->regs + S3C2412_IISMOD);
 
331
        pr_debug("hw_params w: IISMOD: %x \n", iismod);
 
332
        return 0;
 
333
}
 
334
 
 
335
static int s3c2412_i2s_hw_params(struct snd_pcm_substream *substream,
 
336
                                 struct snd_pcm_hw_params *params,
 
337
                                 struct snd_soc_dai *socdai)
 
338
{
 
339
        struct snd_soc_pcm_runtime *rtd = substream->private_data;
 
340
        struct snd_soc_dai_link *dai = rtd->dai;
 
341
        struct s3c_i2sv2_info *i2s = to_info(dai->cpu_dai);
 
342
        u32 iismod;
 
343
 
 
344
        pr_debug("Entered %s\n", __func__);
 
345
 
 
346
        if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
 
347
                dai->cpu_dai->dma_data = i2s->dma_playback;
 
348
        else
 
349
                dai->cpu_dai->dma_data = i2s->dma_capture;
 
350
 
 
351
        /* Working copies of register */
 
352
        iismod = readl(i2s->regs + S3C2412_IISMOD);
 
353
        pr_debug("%s: r: IISMOD: %x\n", __func__, iismod);
 
354
 
 
355
#if defined(CONFIG_CPU_S3C2412) || defined(CONFIG_CPU_S3C2413)
 
356
        switch (params_format(params)) {
 
357
        case SNDRV_PCM_FORMAT_S8:
 
358
                iismod |= S3C2412_IISMOD_8BIT;
 
359
                break;
 
360
        case SNDRV_PCM_FORMAT_S16_LE:
 
361
                iismod &= ~S3C2412_IISMOD_8BIT;
 
362
                break;
 
363
        }
 
364
#endif
 
365
 
 
366
#ifdef CONFIG_PLAT_S3C64XX
 
367
        iismod &= ~(S3C64XX_IISMOD_BLC_MASK | S3C2412_IISMOD_BCLK_MASK);
 
368
        /* Sample size */
 
369
        switch (params_format(params)) {
 
370
        case SNDRV_PCM_FORMAT_S8:
 
371
                /* 8 bit sample, 16fs BCLK */
 
372
                iismod |= (S3C64XX_IISMOD_BLC_8BIT | S3C2412_IISMOD_BCLK_16FS);
 
373
                break;
 
374
        case SNDRV_PCM_FORMAT_S16_LE:
 
375
                /* 16 bit sample, 32fs BCLK */
 
376
                break;
 
377
        case SNDRV_PCM_FORMAT_S24_LE:
 
378
                /* 24 bit sample, 48fs BCLK */
 
379
                iismod |= (S3C64XX_IISMOD_BLC_24BIT | S3C2412_IISMOD_BCLK_48FS);
 
380
                break;
 
381
        }
 
382
#endif
 
383
 
 
384
        writel(iismod, i2s->regs + S3C2412_IISMOD);
 
385
        pr_debug("%s: w: IISMOD: %x\n", __func__, iismod);
 
386
        return 0;
 
387
}
 
388
 
 
389
static int s3c2412_i2s_trigger(struct snd_pcm_substream *substream, int cmd,
 
390
                               struct snd_soc_dai *dai)
 
391
{
 
392
        struct snd_soc_pcm_runtime *rtd = substream->private_data;
 
393
        struct s3c_i2sv2_info *i2s = to_info(rtd->dai->cpu_dai);
 
394
        int capture = (substream->stream == SNDRV_PCM_STREAM_CAPTURE);
 
395
        unsigned long irqs;
 
396
        int ret = 0;
 
397
        int channel = ((struct s3c_dma_params *)
 
398
                  rtd->dai->cpu_dai->dma_data)->channel;
 
399
 
 
400
        pr_debug("Entered %s\n", __func__);
 
401
 
 
402
        switch (cmd) {
 
403
        case SNDRV_PCM_TRIGGER_START:
 
404
                /* On start, ensure that the FIFOs are cleared and reset. */
 
405
 
 
406
                writel(capture ? S3C2412_IISFIC_RXFLUSH : S3C2412_IISFIC_TXFLUSH,
 
407
                       i2s->regs + S3C2412_IISFIC);
 
408
 
 
409
                /* clear again, just in case */
 
410
                writel(0x0, i2s->regs + S3C2412_IISFIC);
 
411
 
 
412
        case SNDRV_PCM_TRIGGER_RESUME:
 
413
        case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
 
414
                if (!i2s->master) {
 
415
                        ret = s3c2412_snd_lrsync(i2s);
 
416
                        if (ret)
 
417
                                goto exit_err;
 
418
                }
 
419
 
 
420
                local_irq_save(irqs);
 
421
 
 
422
                if (capture)
 
423
                        s3c2412_snd_rxctrl(i2s, 1);
 
424
                else
 
425
                        s3c2412_snd_txctrl(i2s, 1);
 
426
 
 
427
                local_irq_restore(irqs);
 
428
 
 
429
                /*
 
430
                 * Load the next buffer to DMA to meet the reqirement
 
431
                 * of the auto reload mechanism of S3C24XX.
 
432
                 * This call won't bother S3C64XX.
 
433
                 */
 
434
                s3c2410_dma_ctrl(channel, S3C2410_DMAOP_STARTED);
 
435
 
 
436
                break;
 
437
 
 
438
        case SNDRV_PCM_TRIGGER_STOP:
 
439
        case SNDRV_PCM_TRIGGER_SUSPEND:
 
440
        case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
 
441
                local_irq_save(irqs);
 
442
 
 
443
                if (capture)
 
444
                        s3c2412_snd_rxctrl(i2s, 0);
 
445
                else
 
446
                        s3c2412_snd_txctrl(i2s, 0);
 
447
 
 
448
                local_irq_restore(irqs);
 
449
                break;
 
450
        default:
 
451
                ret = -EINVAL;
 
452
                break;
 
453
        }
 
454
 
 
455
exit_err:
 
456
        return ret;
 
457
}
 
458
 
 
459
/*
 
460
 * Set S3C2412 Clock dividers
 
461
 */
 
462
static int s3c2412_i2s_set_clkdiv(struct snd_soc_dai *cpu_dai,
 
463
                                  int div_id, int div)
 
464
{
 
465
        struct s3c_i2sv2_info *i2s = to_info(cpu_dai);
 
466
        u32 reg;
 
467
 
 
468
        pr_debug("%s(%p, %d, %d)\n", __func__, cpu_dai, div_id, div);
 
469
 
 
470
        switch (div_id) {
 
471
        case S3C_I2SV2_DIV_BCLK:
 
472
                if (div > 3) {
 
473
                        /* convert value to bit field */
 
474
 
 
475
                        switch (div) {
 
476
                        case 16:
 
477
                                div = S3C2412_IISMOD_BCLK_16FS;
 
478
                                break;
 
479
 
 
480
                        case 32:
 
481
                                div = S3C2412_IISMOD_BCLK_32FS;
 
482
                                break;
 
483
 
 
484
                        case 24:
 
485
                                div = S3C2412_IISMOD_BCLK_24FS;
 
486
                                break;
 
487
 
 
488
                        case 48:
 
489
                                div = S3C2412_IISMOD_BCLK_48FS;
 
490
                                break;
 
491
 
 
492
                        default:
 
493
                                return -EINVAL;
 
494
                        }
 
495
                }
 
496
 
 
497
                reg = readl(i2s->regs + S3C2412_IISMOD);
 
498
                reg &= ~S3C2412_IISMOD_BCLK_MASK;
 
499
                writel(reg | div, i2s->regs + S3C2412_IISMOD);
 
500
 
 
501
                pr_debug("%s: MOD=%08x\n", __func__, readl(i2s->regs + S3C2412_IISMOD));
 
502
                break;
 
503
 
 
504
        case S3C_I2SV2_DIV_RCLK:
 
505
                if (div > 3) {
 
506
                        /* convert value to bit field */
 
507
 
 
508
                        switch (div) {
 
509
                        case 256:
 
510
                                div = S3C2412_IISMOD_RCLK_256FS;
 
511
                                break;
 
512
 
 
513
                        case 384:
 
514
                                div = S3C2412_IISMOD_RCLK_384FS;
 
515
                                break;
 
516
 
 
517
                        case 512:
 
518
                                div = S3C2412_IISMOD_RCLK_512FS;
 
519
                                break;
 
520
 
 
521
                        case 768:
 
522
                                div = S3C2412_IISMOD_RCLK_768FS;
 
523
                                break;
 
524
 
 
525
                        default:
 
526
                                return -EINVAL;
 
527
                        }
 
528
                }
 
529
 
 
530
                reg = readl(i2s->regs + S3C2412_IISMOD);
 
531
                reg &= ~S3C2412_IISMOD_RCLK_MASK;
 
532
                writel(reg | div, i2s->regs + S3C2412_IISMOD);
 
533
                pr_debug("%s: MOD=%08x\n", __func__, readl(i2s->regs + S3C2412_IISMOD));
 
534
                break;
 
535
 
 
536
        case S3C_I2SV2_DIV_PRESCALER:
 
537
                if (div >= 0) {
 
538
                        writel((div << 8) | S3C2412_IISPSR_PSREN,
 
539
                               i2s->regs + S3C2412_IISPSR);
 
540
                } else {
 
541
                        writel(0x0, i2s->regs + S3C2412_IISPSR);
 
542
                }
 
543
                pr_debug("%s: PSR=%08x\n", __func__, readl(i2s->regs + S3C2412_IISPSR));
 
544
                break;
 
545
 
 
546
        default:
 
547
                return -EINVAL;
 
548
        }
 
549
 
 
550
        return 0;
 
551
}
 
552
 
 
553
/* default table of all avaialable root fs divisors */
 
554
static unsigned int iis_fs_tab[] = { 256, 512, 384, 768 };
 
555
 
 
556
int s3c_i2sv2_iis_calc_rate(struct s3c_i2sv2_rate_calc *info,
 
557
                            unsigned int *fstab,
 
558
                            unsigned int rate, struct clk *clk)
 
559
{
 
560
        unsigned long clkrate = clk_get_rate(clk);
 
561
        unsigned int div;
 
562
        unsigned int fsclk;
 
563
        unsigned int actual;
 
564
        unsigned int fs;
 
565
        unsigned int fsdiv;
 
566
        signed int deviation = 0;
 
567
        unsigned int best_fs = 0;
 
568
        unsigned int best_div = 0;
 
569
        unsigned int best_rate = 0;
 
570
        unsigned int best_deviation = INT_MAX;
 
571
 
 
572
        pr_debug("Input clock rate %ldHz\n", clkrate);
 
573
 
 
574
        if (fstab == NULL)
 
575
                fstab = iis_fs_tab;
 
576
 
 
577
        for (fs = 0; fs < ARRAY_SIZE(iis_fs_tab); fs++) {
 
578
                fsdiv = iis_fs_tab[fs];
 
579
 
 
580
                fsclk = clkrate / fsdiv;
 
581
                div = fsclk / rate;
 
582
 
 
583
                if ((fsclk % rate) > (rate / 2))
 
584
                        div++;
 
585
 
 
586
                if (div <= 1)
 
587
                        continue;
 
588
 
 
589
                actual = clkrate / (fsdiv * div);
 
590
                deviation = actual - rate;
 
591
 
 
592
                printk(KERN_DEBUG "%ufs: div %u => result %u, deviation %d\n",
 
593
                       fsdiv, div, actual, deviation);
 
594
 
 
595
                deviation = abs(deviation);
 
596
 
 
597
                if (deviation < best_deviation) {
 
598
                        best_fs = fsdiv;
 
599
                        best_div = div;
 
600
                        best_rate = actual;
 
601
                        best_deviation = deviation;
 
602
                }
 
603
 
 
604
                if (deviation == 0)
 
605
                        break;
 
606
        }
 
607
 
 
608
        printk(KERN_DEBUG "best: fs=%u, div=%u, rate=%u\n",
 
609
               best_fs, best_div, best_rate);
 
610
 
 
611
        info->fs_div = best_fs;
 
612
        info->clk_div = best_div;
 
613
 
 
614
        return 0;
 
615
}
 
616
EXPORT_SYMBOL_GPL(s3c_i2sv2_iis_calc_rate);
 
617
 
 
618
int s3c_i2sv2_probe(struct platform_device *pdev,
 
619
                    struct snd_soc_dai *dai,
 
620
                    struct s3c_i2sv2_info *i2s,
 
621
                    unsigned long base)
 
622
{
 
623
        struct device *dev = &pdev->dev;
 
624
        unsigned int iismod;
 
625
 
 
626
        i2s->dev = dev;
 
627
 
 
628
        /* record our i2s structure for later use in the callbacks */
 
629
        dai->private_data = i2s;
 
630
 
 
631
        if (!base) {
 
632
                struct resource *res = platform_get_resource(pdev,
 
633
                                                             IORESOURCE_MEM,
 
634
                                                             0);
 
635
                if (!res) {
 
636
                        dev_err(dev, "Unable to get register resource\n");
 
637
                        return -ENXIO;
 
638
                }
 
639
 
 
640
                if (!request_mem_region(res->start, resource_size(res),
 
641
                                        "s3c64xx-i2s-v4")) {
 
642
                        dev_err(dev, "Unable to request register region\n");
 
643
                        return -EBUSY;
 
644
                }
 
645
 
 
646
                base = res->start;
 
647
        }
 
648
 
 
649
        i2s->regs = ioremap(base, 0x100);
 
650
        if (i2s->regs == NULL) {
 
651
                dev_err(dev, "cannot ioremap registers\n");
 
652
                return -ENXIO;
 
653
        }
 
654
 
 
655
        i2s->iis_pclk = clk_get(dev, "iis");
 
656
        if (IS_ERR(i2s->iis_pclk)) {
 
657
                dev_err(dev, "failed to get iis_clock\n");
 
658
                iounmap(i2s->regs);
 
659
                return -ENOENT;
 
660
        }
 
661
 
 
662
        clk_enable(i2s->iis_pclk);
 
663
 
 
664
        /* Mark ourselves as in TXRX mode so we can run through our cleanup
 
665
         * process without warnings. */
 
666
        iismod = readl(i2s->regs + S3C2412_IISMOD);
 
667
        iismod |= S3C2412_IISMOD_MODE_TXRX;
 
668
        writel(iismod, i2s->regs + S3C2412_IISMOD);
 
669
        s3c2412_snd_txctrl(i2s, 0);
 
670
        s3c2412_snd_rxctrl(i2s, 0);
 
671
 
 
672
        return 0;
 
673
}
 
674
EXPORT_SYMBOL_GPL(s3c_i2sv2_probe);
 
675
 
 
676
#ifdef CONFIG_PM
 
677
static int s3c2412_i2s_suspend(struct snd_soc_dai *dai)
 
678
{
 
679
        struct s3c_i2sv2_info *i2s = to_info(dai);
 
680
        u32 iismod;
 
681
 
 
682
        if (dai->active) {
 
683
                i2s->suspend_iismod = readl(i2s->regs + S3C2412_IISMOD);
 
684
                i2s->suspend_iiscon = readl(i2s->regs + S3C2412_IISCON);
 
685
                i2s->suspend_iispsr = readl(i2s->regs + S3C2412_IISPSR);
 
686
 
 
687
                /* some basic suspend checks */
 
688
 
 
689
                iismod = readl(i2s->regs + S3C2412_IISMOD);
 
690
 
 
691
                if (iismod & S3C2412_IISCON_RXDMA_ACTIVE)
 
692
                        pr_warning("%s: RXDMA active?\n", __func__);
 
693
 
 
694
                if (iismod & S3C2412_IISCON_TXDMA_ACTIVE)
 
695
                        pr_warning("%s: TXDMA active?\n", __func__);
 
696
 
 
697
                if (iismod & S3C2412_IISCON_IIS_ACTIVE)
 
698
                        pr_warning("%s: IIS active\n", __func__);
 
699
        }
 
700
 
 
701
        return 0;
 
702
}
 
703
 
 
704
static int s3c2412_i2s_resume(struct snd_soc_dai *dai)
 
705
{
 
706
        struct s3c_i2sv2_info *i2s = to_info(dai);
 
707
 
 
708
        pr_info("dai_active %d, IISMOD %08x, IISCON %08x\n",
 
709
                dai->active, i2s->suspend_iismod, i2s->suspend_iiscon);
 
710
 
 
711
        if (dai->active) {
 
712
                writel(i2s->suspend_iiscon, i2s->regs + S3C2412_IISCON);
 
713
                writel(i2s->suspend_iismod, i2s->regs + S3C2412_IISMOD);
 
714
                writel(i2s->suspend_iispsr, i2s->regs + S3C2412_IISPSR);
 
715
 
 
716
                writel(S3C2412_IISFIC_RXFLUSH | S3C2412_IISFIC_TXFLUSH,
 
717
                       i2s->regs + S3C2412_IISFIC);
 
718
 
 
719
                ndelay(250);
 
720
                writel(0x0, i2s->regs + S3C2412_IISFIC);
 
721
        }
 
722
 
 
723
        return 0;
 
724
}
 
725
#else
 
726
#define s3c2412_i2s_suspend NULL
 
727
#define s3c2412_i2s_resume  NULL
 
728
#endif
 
729
 
 
730
int s3c_i2sv2_register_dai(struct snd_soc_dai *dai)
 
731
{
 
732
        struct snd_soc_dai_ops *ops = dai->ops;
 
733
 
 
734
        ops->trigger = s3c2412_i2s_trigger;
 
735
        ops->hw_params = s3c2412_i2s_hw_params;
 
736
        ops->set_fmt = s3c2412_i2s_set_fmt;
 
737
        ops->set_clkdiv = s3c2412_i2s_set_clkdiv;
 
738
 
 
739
        dai->suspend = s3c2412_i2s_suspend;
 
740
        dai->resume = s3c2412_i2s_resume;
 
741
 
 
742
        return snd_soc_register_dai(dai);
 
743
}
 
744
EXPORT_SYMBOL_GPL(s3c_i2sv2_register_dai);
 
745
 
 
746
MODULE_LICENSE("GPL");