~hui.wang/alsa-driver/dkms-packaging.audiosdw-ppa

« back to all changes in this revision

Viewing changes to buildroot/src/oem-audiosdw-lp1836324-1ubuntu1.3/soc/jz4740/jz4740-i2s.c

  • Committer: Hui Wang
  • Date: 2019-12-13 02:41:40 UTC
  • Revision ID: hui.wang@canonical.com-20191213024140-1cprdcbl3122fn85
insert pc-oem-dkms

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
// SPDX-License-Identifier: GPL-2.0-or-later
 
2
/*
 
3
 *  Copyright (C) 2010, Lars-Peter Clausen <lars@metafoo.de>
 
4
 */
 
5
 
 
6
#include <linux/init.h>
 
7
#include <linux/io.h>
 
8
#include <linux/of.h>
 
9
#include <linux/of_device.h>
 
10
#include <linux/kernel.h>
 
11
#include <linux/module.h>
 
12
#include <linux/platform_device.h>
 
13
#include <linux/slab.h>
 
14
 
 
15
#include <linux/clk.h>
 
16
#include <linux/delay.h>
 
17
 
 
18
#include <linux/dma-mapping.h>
 
19
 
 
20
#include <sound/core.h>
 
21
#include <sound/pcm.h>
 
22
#include <sound/pcm_params.h>
 
23
#include <sound/soc.h>
 
24
#include <sound/initval.h>
 
25
#include <sound/dmaengine_pcm.h>
 
26
 
 
27
#include "jz4740-i2s.h"
 
28
 
 
29
#define JZ4740_DMA_TYPE_AIC_TRANSMIT 24
 
30
#define JZ4740_DMA_TYPE_AIC_RECEIVE 25
 
31
 
 
32
#define JZ_REG_AIC_CONF         0x00
 
33
#define JZ_REG_AIC_CTRL         0x04
 
34
#define JZ_REG_AIC_I2S_FMT      0x10
 
35
#define JZ_REG_AIC_FIFO_STATUS  0x14
 
36
#define JZ_REG_AIC_I2S_STATUS   0x1c
 
37
#define JZ_REG_AIC_CLK_DIV      0x30
 
38
#define JZ_REG_AIC_FIFO         0x34
 
39
 
 
40
#define JZ_AIC_CONF_FIFO_RX_THRESHOLD_MASK (0xf << 12)
 
41
#define JZ_AIC_CONF_FIFO_TX_THRESHOLD_MASK (0xf <<  8)
 
42
#define JZ_AIC_CONF_OVERFLOW_PLAY_LAST BIT(6)
 
43
#define JZ_AIC_CONF_INTERNAL_CODEC BIT(5)
 
44
#define JZ_AIC_CONF_I2S BIT(4)
 
45
#define JZ_AIC_CONF_RESET BIT(3)
 
46
#define JZ_AIC_CONF_BIT_CLK_MASTER BIT(2)
 
47
#define JZ_AIC_CONF_SYNC_CLK_MASTER BIT(1)
 
48
#define JZ_AIC_CONF_ENABLE BIT(0)
 
49
 
 
50
#define JZ_AIC_CONF_FIFO_RX_THRESHOLD_OFFSET 12
 
51
#define JZ_AIC_CONF_FIFO_TX_THRESHOLD_OFFSET 8
 
52
#define JZ4780_AIC_CONF_FIFO_RX_THRESHOLD_OFFSET 24
 
53
#define JZ4780_AIC_CONF_FIFO_TX_THRESHOLD_OFFSET 16
 
54
#define JZ4780_AIC_CONF_FIFO_RX_THRESHOLD_MASK \
 
55
                        (0xf << JZ4780_AIC_CONF_FIFO_RX_THRESHOLD_OFFSET)
 
56
#define JZ4780_AIC_CONF_FIFO_TX_THRESHOLD_MASK \
 
57
                        (0x1f <<  JZ4780_AIC_CONF_FIFO_TX_THRESHOLD_OFFSET)
 
58
 
 
59
#define JZ_AIC_CTRL_OUTPUT_SAMPLE_SIZE_MASK (0x7 << 19)
 
60
#define JZ_AIC_CTRL_INPUT_SAMPLE_SIZE_MASK (0x7 << 16)
 
61
#define JZ_AIC_CTRL_ENABLE_RX_DMA BIT(15)
 
62
#define JZ_AIC_CTRL_ENABLE_TX_DMA BIT(14)
 
63
#define JZ_AIC_CTRL_MONO_TO_STEREO BIT(11)
 
64
#define JZ_AIC_CTRL_SWITCH_ENDIANNESS BIT(10)
 
65
#define JZ_AIC_CTRL_SIGNED_TO_UNSIGNED BIT(9)
 
66
#define JZ_AIC_CTRL_FLUSH               BIT(8)
 
67
#define JZ_AIC_CTRL_ENABLE_ROR_INT BIT(6)
 
68
#define JZ_AIC_CTRL_ENABLE_TUR_INT BIT(5)
 
69
#define JZ_AIC_CTRL_ENABLE_RFS_INT BIT(4)
 
70
#define JZ_AIC_CTRL_ENABLE_TFS_INT BIT(3)
 
71
#define JZ_AIC_CTRL_ENABLE_LOOPBACK BIT(2)
 
72
#define JZ_AIC_CTRL_ENABLE_PLAYBACK BIT(1)
 
73
#define JZ_AIC_CTRL_ENABLE_CAPTURE BIT(0)
 
74
 
 
75
#define JZ_AIC_CTRL_OUTPUT_SAMPLE_SIZE_OFFSET 19
 
76
#define JZ_AIC_CTRL_INPUT_SAMPLE_SIZE_OFFSET  16
 
77
 
 
78
#define JZ_AIC_I2S_FMT_DISABLE_BIT_CLK BIT(12)
 
79
#define JZ_AIC_I2S_FMT_DISABLE_BIT_ICLK BIT(13)
 
80
#define JZ_AIC_I2S_FMT_ENABLE_SYS_CLK BIT(4)
 
81
#define JZ_AIC_I2S_FMT_MSB BIT(0)
 
82
 
 
83
#define JZ_AIC_I2S_STATUS_BUSY BIT(2)
 
84
 
 
85
#define JZ_AIC_CLK_DIV_MASK 0xf
 
86
#define I2SDIV_DV_SHIFT 8
 
87
#define I2SDIV_DV_MASK (0xf << I2SDIV_DV_SHIFT)
 
88
#define I2SDIV_IDV_SHIFT 8
 
89
#define I2SDIV_IDV_MASK (0xf << I2SDIV_IDV_SHIFT)
 
90
 
 
91
enum jz47xx_i2s_version {
 
92
        JZ_I2S_JZ4740,
 
93
        JZ_I2S_JZ4780,
 
94
};
 
95
 
 
96
struct jz4740_i2s {
 
97
        struct resource *mem;
 
98
        void __iomem *base;
 
99
        dma_addr_t phys_base;
 
100
 
 
101
        struct clk *clk_aic;
 
102
        struct clk *clk_i2s;
 
103
 
 
104
        struct snd_dmaengine_dai_dma_data playback_dma_data;
 
105
        struct snd_dmaengine_dai_dma_data capture_dma_data;
 
106
 
 
107
        enum jz47xx_i2s_version version;
 
108
};
 
109
 
 
110
static inline uint32_t jz4740_i2s_read(const struct jz4740_i2s *i2s,
 
111
        unsigned int reg)
 
112
{
 
113
        return readl(i2s->base + reg);
 
114
}
 
115
 
 
116
static inline void jz4740_i2s_write(const struct jz4740_i2s *i2s,
 
117
        unsigned int reg, uint32_t value)
 
118
{
 
119
        writel(value, i2s->base + reg);
 
120
}
 
121
 
 
122
static int jz4740_i2s_startup(struct snd_pcm_substream *substream,
 
123
        struct snd_soc_dai *dai)
 
124
{
 
125
        struct jz4740_i2s *i2s = snd_soc_dai_get_drvdata(dai);
 
126
        uint32_t conf, ctrl;
 
127
        int ret;
 
128
 
 
129
        if (dai->active)
 
130
                return 0;
 
131
 
 
132
        ctrl = jz4740_i2s_read(i2s, JZ_REG_AIC_CTRL);
 
133
        ctrl |= JZ_AIC_CTRL_FLUSH;
 
134
        jz4740_i2s_write(i2s, JZ_REG_AIC_CTRL, ctrl);
 
135
 
 
136
        ret = clk_prepare_enable(i2s->clk_i2s);
 
137
        if (ret)
 
138
                return ret;
 
139
 
 
140
        conf = jz4740_i2s_read(i2s, JZ_REG_AIC_CONF);
 
141
        conf |= JZ_AIC_CONF_ENABLE;
 
142
        jz4740_i2s_write(i2s, JZ_REG_AIC_CONF, conf);
 
143
 
 
144
        return 0;
 
145
}
 
146
 
 
147
static void jz4740_i2s_shutdown(struct snd_pcm_substream *substream,
 
148
        struct snd_soc_dai *dai)
 
149
{
 
150
        struct jz4740_i2s *i2s = snd_soc_dai_get_drvdata(dai);
 
151
        uint32_t conf;
 
152
 
 
153
        if (dai->active)
 
154
                return;
 
155
 
 
156
        conf = jz4740_i2s_read(i2s, JZ_REG_AIC_CONF);
 
157
        conf &= ~JZ_AIC_CONF_ENABLE;
 
158
        jz4740_i2s_write(i2s, JZ_REG_AIC_CONF, conf);
 
159
 
 
160
        clk_disable_unprepare(i2s->clk_i2s);
 
161
}
 
162
 
 
163
static int jz4740_i2s_trigger(struct snd_pcm_substream *substream, int cmd,
 
164
        struct snd_soc_dai *dai)
 
165
{
 
166
        struct jz4740_i2s *i2s = snd_soc_dai_get_drvdata(dai);
 
167
 
 
168
        uint32_t ctrl;
 
169
        uint32_t mask;
 
170
 
 
171
        if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
 
172
                mask = JZ_AIC_CTRL_ENABLE_PLAYBACK | JZ_AIC_CTRL_ENABLE_TX_DMA;
 
173
        else
 
174
                mask = JZ_AIC_CTRL_ENABLE_CAPTURE | JZ_AIC_CTRL_ENABLE_RX_DMA;
 
175
 
 
176
        ctrl = jz4740_i2s_read(i2s, JZ_REG_AIC_CTRL);
 
177
 
 
178
        switch (cmd) {
 
179
        case SNDRV_PCM_TRIGGER_START:
 
180
        case SNDRV_PCM_TRIGGER_RESUME:
 
181
        case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
 
182
                ctrl |= mask;
 
183
                break;
 
184
        case SNDRV_PCM_TRIGGER_STOP:
 
185
        case SNDRV_PCM_TRIGGER_SUSPEND:
 
186
        case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
 
187
                ctrl &= ~mask;
 
188
                break;
 
189
        default:
 
190
                return -EINVAL;
 
191
        }
 
192
 
 
193
        jz4740_i2s_write(i2s, JZ_REG_AIC_CTRL, ctrl);
 
194
 
 
195
        return 0;
 
196
}
 
197
 
 
198
static int jz4740_i2s_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
 
199
{
 
200
        struct jz4740_i2s *i2s = snd_soc_dai_get_drvdata(dai);
 
201
 
 
202
        uint32_t format = 0;
 
203
        uint32_t conf;
 
204
 
 
205
        conf = jz4740_i2s_read(i2s, JZ_REG_AIC_CONF);
 
206
 
 
207
        conf &= ~(JZ_AIC_CONF_BIT_CLK_MASTER | JZ_AIC_CONF_SYNC_CLK_MASTER);
 
208
 
 
209
        switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
 
210
        case SND_SOC_DAIFMT_CBS_CFS:
 
211
                conf |= JZ_AIC_CONF_BIT_CLK_MASTER | JZ_AIC_CONF_SYNC_CLK_MASTER;
 
212
                format |= JZ_AIC_I2S_FMT_ENABLE_SYS_CLK;
 
213
                break;
 
214
        case SND_SOC_DAIFMT_CBM_CFS:
 
215
                conf |= JZ_AIC_CONF_SYNC_CLK_MASTER;
 
216
                break;
 
217
        case SND_SOC_DAIFMT_CBS_CFM:
 
218
                conf |= JZ_AIC_CONF_BIT_CLK_MASTER;
 
219
                break;
 
220
        case SND_SOC_DAIFMT_CBM_CFM:
 
221
                break;
 
222
        default:
 
223
                return -EINVAL;
 
224
        }
 
225
 
 
226
        switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
 
227
        case SND_SOC_DAIFMT_MSB:
 
228
                format |= JZ_AIC_I2S_FMT_MSB;
 
229
                break;
 
230
        case SND_SOC_DAIFMT_I2S:
 
231
                break;
 
232
        default:
 
233
                return -EINVAL;
 
234
        }
 
235
 
 
236
        switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
 
237
        case SND_SOC_DAIFMT_NB_NF:
 
238
                break;
 
239
        default:
 
240
                return -EINVAL;
 
241
        }
 
242
 
 
243
        jz4740_i2s_write(i2s, JZ_REG_AIC_CONF, conf);
 
244
        jz4740_i2s_write(i2s, JZ_REG_AIC_I2S_FMT, format);
 
245
 
 
246
        return 0;
 
247
}
 
248
 
 
249
static int jz4740_i2s_hw_params(struct snd_pcm_substream *substream,
 
250
        struct snd_pcm_hw_params *params, struct snd_soc_dai *dai)
 
251
{
 
252
        struct jz4740_i2s *i2s = snd_soc_dai_get_drvdata(dai);
 
253
        unsigned int sample_size;
 
254
        uint32_t ctrl, div_reg;
 
255
        int div;
 
256
 
 
257
        ctrl = jz4740_i2s_read(i2s, JZ_REG_AIC_CTRL);
 
258
 
 
259
        div_reg = jz4740_i2s_read(i2s, JZ_REG_AIC_CLK_DIV);
 
260
        div = clk_get_rate(i2s->clk_i2s) / (64 * params_rate(params));
 
261
 
 
262
        switch (params_format(params)) {
 
263
        case SNDRV_PCM_FORMAT_S8:
 
264
                sample_size = 0;
 
265
                break;
 
266
        case SNDRV_PCM_FORMAT_S16:
 
267
                sample_size = 1;
 
268
                break;
 
269
        default:
 
270
                return -EINVAL;
 
271
        }
 
272
 
 
273
        if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
 
274
                ctrl &= ~JZ_AIC_CTRL_OUTPUT_SAMPLE_SIZE_MASK;
 
275
                ctrl |= sample_size << JZ_AIC_CTRL_OUTPUT_SAMPLE_SIZE_OFFSET;
 
276
                if (params_channels(params) == 1)
 
277
                        ctrl |= JZ_AIC_CTRL_MONO_TO_STEREO;
 
278
                else
 
279
                        ctrl &= ~JZ_AIC_CTRL_MONO_TO_STEREO;
 
280
 
 
281
                div_reg &= ~I2SDIV_DV_MASK;
 
282
                div_reg |= (div - 1) << I2SDIV_DV_SHIFT;
 
283
        } else {
 
284
                ctrl &= ~JZ_AIC_CTRL_INPUT_SAMPLE_SIZE_MASK;
 
285
                ctrl |= sample_size << JZ_AIC_CTRL_INPUT_SAMPLE_SIZE_OFFSET;
 
286
 
 
287
                if (i2s->version >= JZ_I2S_JZ4780) {
 
288
                        div_reg &= ~I2SDIV_IDV_MASK;
 
289
                        div_reg |= (div - 1) << I2SDIV_IDV_SHIFT;
 
290
                } else {
 
291
                        div_reg &= ~I2SDIV_DV_MASK;
 
292
                        div_reg |= (div - 1) << I2SDIV_DV_SHIFT;
 
293
                }
 
294
        }
 
295
 
 
296
        jz4740_i2s_write(i2s, JZ_REG_AIC_CTRL, ctrl);
 
297
        jz4740_i2s_write(i2s, JZ_REG_AIC_CLK_DIV, div_reg);
 
298
 
 
299
        return 0;
 
300
}
 
301
 
 
302
static int jz4740_i2s_set_sysclk(struct snd_soc_dai *dai, int clk_id,
 
303
        unsigned int freq, int dir)
 
304
{
 
305
        struct jz4740_i2s *i2s = snd_soc_dai_get_drvdata(dai);
 
306
        struct clk *parent;
 
307
        int ret = 0;
 
308
 
 
309
        switch (clk_id) {
 
310
        case JZ4740_I2S_CLKSRC_EXT:
 
311
                parent = clk_get(NULL, "ext");
 
312
                clk_set_parent(i2s->clk_i2s, parent);
 
313
                break;
 
314
        case JZ4740_I2S_CLKSRC_PLL:
 
315
                parent = clk_get(NULL, "pll half");
 
316
                clk_set_parent(i2s->clk_i2s, parent);
 
317
                ret = clk_set_rate(i2s->clk_i2s, freq);
 
318
                break;
 
319
        default:
 
320
                return -EINVAL;
 
321
        }
 
322
        clk_put(parent);
 
323
 
 
324
        return ret;
 
325
}
 
326
 
 
327
static int jz4740_i2s_suspend(struct snd_soc_dai *dai)
 
328
{
 
329
        struct jz4740_i2s *i2s = snd_soc_dai_get_drvdata(dai);
 
330
        uint32_t conf;
 
331
 
 
332
        if (dai->active) {
 
333
                conf = jz4740_i2s_read(i2s, JZ_REG_AIC_CONF);
 
334
                conf &= ~JZ_AIC_CONF_ENABLE;
 
335
                jz4740_i2s_write(i2s, JZ_REG_AIC_CONF, conf);
 
336
 
 
337
                clk_disable_unprepare(i2s->clk_i2s);
 
338
        }
 
339
 
 
340
        clk_disable_unprepare(i2s->clk_aic);
 
341
 
 
342
        return 0;
 
343
}
 
344
 
 
345
static int jz4740_i2s_resume(struct snd_soc_dai *dai)
 
346
{
 
347
        struct jz4740_i2s *i2s = snd_soc_dai_get_drvdata(dai);
 
348
        uint32_t conf;
 
349
        int ret;
 
350
 
 
351
        ret = clk_prepare_enable(i2s->clk_aic);
 
352
        if (ret)
 
353
                return ret;
 
354
 
 
355
        if (dai->active) {
 
356
                ret = clk_prepare_enable(i2s->clk_i2s);
 
357
                if (ret) {
 
358
                        clk_disable_unprepare(i2s->clk_aic);
 
359
                        return ret;
 
360
                }
 
361
 
 
362
                conf = jz4740_i2s_read(i2s, JZ_REG_AIC_CONF);
 
363
                conf |= JZ_AIC_CONF_ENABLE;
 
364
                jz4740_i2s_write(i2s, JZ_REG_AIC_CONF, conf);
 
365
        }
 
366
 
 
367
        return 0;
 
368
}
 
369
 
 
370
static void jz4740_i2c_init_pcm_config(struct jz4740_i2s *i2s)
 
371
{
 
372
        struct snd_dmaengine_dai_dma_data *dma_data;
 
373
 
 
374
        /* Playback */
 
375
        dma_data = &i2s->playback_dma_data;
 
376
        dma_data->maxburst = 16;
 
377
        dma_data->slave_id = JZ4740_DMA_TYPE_AIC_TRANSMIT;
 
378
        dma_data->addr = i2s->phys_base + JZ_REG_AIC_FIFO;
 
379
 
 
380
        /* Capture */
 
381
        dma_data = &i2s->capture_dma_data;
 
382
        dma_data->maxburst = 16;
 
383
        dma_data->slave_id = JZ4740_DMA_TYPE_AIC_RECEIVE;
 
384
        dma_data->addr = i2s->phys_base + JZ_REG_AIC_FIFO;
 
385
}
 
386
 
 
387
static int jz4740_i2s_dai_probe(struct snd_soc_dai *dai)
 
388
{
 
389
        struct jz4740_i2s *i2s = snd_soc_dai_get_drvdata(dai);
 
390
        uint32_t conf;
 
391
        int ret;
 
392
 
 
393
        ret = clk_prepare_enable(i2s->clk_aic);
 
394
        if (ret)
 
395
                return ret;
 
396
 
 
397
        jz4740_i2c_init_pcm_config(i2s);
 
398
        snd_soc_dai_init_dma_data(dai, &i2s->playback_dma_data,
 
399
                &i2s->capture_dma_data);
 
400
 
 
401
        if (i2s->version >= JZ_I2S_JZ4780) {
 
402
                conf = (7 << JZ4780_AIC_CONF_FIFO_RX_THRESHOLD_OFFSET) |
 
403
                        (8 << JZ4780_AIC_CONF_FIFO_TX_THRESHOLD_OFFSET) |
 
404
                        JZ_AIC_CONF_OVERFLOW_PLAY_LAST |
 
405
                        JZ_AIC_CONF_I2S |
 
406
                        JZ_AIC_CONF_INTERNAL_CODEC;
 
407
        } else {
 
408
                conf = (7 << JZ_AIC_CONF_FIFO_RX_THRESHOLD_OFFSET) |
 
409
                        (8 << JZ_AIC_CONF_FIFO_TX_THRESHOLD_OFFSET) |
 
410
                        JZ_AIC_CONF_OVERFLOW_PLAY_LAST |
 
411
                        JZ_AIC_CONF_I2S |
 
412
                        JZ_AIC_CONF_INTERNAL_CODEC;
 
413
        }
 
414
 
 
415
        jz4740_i2s_write(i2s, JZ_REG_AIC_CONF, JZ_AIC_CONF_RESET);
 
416
        jz4740_i2s_write(i2s, JZ_REG_AIC_CONF, conf);
 
417
 
 
418
        return 0;
 
419
}
 
420
 
 
421
static int jz4740_i2s_dai_remove(struct snd_soc_dai *dai)
 
422
{
 
423
        struct jz4740_i2s *i2s = snd_soc_dai_get_drvdata(dai);
 
424
 
 
425
        clk_disable_unprepare(i2s->clk_aic);
 
426
        return 0;
 
427
}
 
428
 
 
429
static const struct snd_soc_dai_ops jz4740_i2s_dai_ops = {
 
430
        .startup = jz4740_i2s_startup,
 
431
        .shutdown = jz4740_i2s_shutdown,
 
432
        .trigger = jz4740_i2s_trigger,
 
433
        .hw_params = jz4740_i2s_hw_params,
 
434
        .set_fmt = jz4740_i2s_set_fmt,
 
435
        .set_sysclk = jz4740_i2s_set_sysclk,
 
436
};
 
437
 
 
438
#define JZ4740_I2S_FMTS (SNDRV_PCM_FMTBIT_S8 | \
 
439
                SNDRV_PCM_FMTBIT_S16_LE)
 
440
 
 
441
static struct snd_soc_dai_driver jz4740_i2s_dai = {
 
442
        .probe = jz4740_i2s_dai_probe,
 
443
        .remove = jz4740_i2s_dai_remove,
 
444
        .playback = {
 
445
                .channels_min = 1,
 
446
                .channels_max = 2,
 
447
                .rates = SNDRV_PCM_RATE_8000_48000,
 
448
                .formats = JZ4740_I2S_FMTS,
 
449
        },
 
450
        .capture = {
 
451
                .channels_min = 2,
 
452
                .channels_max = 2,
 
453
                .rates = SNDRV_PCM_RATE_8000_48000,
 
454
                .formats = JZ4740_I2S_FMTS,
 
455
        },
 
456
        .symmetric_rates = 1,
 
457
        .ops = &jz4740_i2s_dai_ops,
 
458
        .suspend = jz4740_i2s_suspend,
 
459
        .resume = jz4740_i2s_resume,
 
460
};
 
461
 
 
462
static struct snd_soc_dai_driver jz4780_i2s_dai = {
 
463
        .probe = jz4740_i2s_dai_probe,
 
464
        .remove = jz4740_i2s_dai_remove,
 
465
        .playback = {
 
466
                .channels_min = 1,
 
467
                .channels_max = 2,
 
468
                .rates = SNDRV_PCM_RATE_8000_48000,
 
469
                .formats = JZ4740_I2S_FMTS,
 
470
        },
 
471
        .capture = {
 
472
                .channels_min = 2,
 
473
                .channels_max = 2,
 
474
                .rates = SNDRV_PCM_RATE_8000_48000,
 
475
                .formats = JZ4740_I2S_FMTS,
 
476
        },
 
477
        .ops = &jz4740_i2s_dai_ops,
 
478
        .suspend = jz4740_i2s_suspend,
 
479
        .resume = jz4740_i2s_resume,
 
480
};
 
481
 
 
482
static const struct snd_soc_component_driver jz4740_i2s_component = {
 
483
        .name           = "jz4740-i2s",
 
484
};
 
485
 
 
486
#ifdef CONFIG_OF
 
487
static const struct of_device_id jz4740_of_matches[] = {
 
488
        { .compatible = "ingenic,jz4740-i2s", .data = (void *)JZ_I2S_JZ4740 },
 
489
        { .compatible = "ingenic,jz4780-i2s", .data = (void *)JZ_I2S_JZ4780 },
 
490
        { /* sentinel */ }
 
491
};
 
492
MODULE_DEVICE_TABLE(of, jz4740_of_matches);
 
493
#endif
 
494
 
 
495
static int jz4740_i2s_dev_probe(struct platform_device *pdev)
 
496
{
 
497
        struct jz4740_i2s *i2s;
 
498
        struct resource *mem;
 
499
        int ret;
 
500
 
 
501
        i2s = devm_kzalloc(&pdev->dev, sizeof(*i2s), GFP_KERNEL);
 
502
        if (!i2s)
 
503
                return -ENOMEM;
 
504
 
 
505
        i2s->version =
 
506
                (enum jz47xx_i2s_version)of_device_get_match_data(&pdev->dev);
 
507
 
 
508
        mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
 
509
        i2s->base = devm_ioremap_resource(&pdev->dev, mem);
 
510
        if (IS_ERR(i2s->base))
 
511
                return PTR_ERR(i2s->base);
 
512
 
 
513
        i2s->phys_base = mem->start;
 
514
 
 
515
        i2s->clk_aic = devm_clk_get(&pdev->dev, "aic");
 
516
        if (IS_ERR(i2s->clk_aic))
 
517
                return PTR_ERR(i2s->clk_aic);
 
518
 
 
519
        i2s->clk_i2s = devm_clk_get(&pdev->dev, "i2s");
 
520
        if (IS_ERR(i2s->clk_i2s))
 
521
                return PTR_ERR(i2s->clk_i2s);
 
522
 
 
523
        platform_set_drvdata(pdev, i2s);
 
524
 
 
525
        if (i2s->version == JZ_I2S_JZ4780)
 
526
                ret = devm_snd_soc_register_component(&pdev->dev,
 
527
                        &jz4740_i2s_component, &jz4780_i2s_dai, 1);
 
528
        else
 
529
                ret = devm_snd_soc_register_component(&pdev->dev,
 
530
                        &jz4740_i2s_component, &jz4740_i2s_dai, 1);
 
531
 
 
532
        if (ret)
 
533
                return ret;
 
534
 
 
535
        return devm_snd_dmaengine_pcm_register(&pdev->dev, NULL,
 
536
                SND_DMAENGINE_PCM_FLAG_COMPAT);
 
537
}
 
538
 
 
539
static struct platform_driver jz4740_i2s_driver = {
 
540
        .probe = jz4740_i2s_dev_probe,
 
541
        .driver = {
 
542
                .name = "jz4740-i2s",
 
543
                .of_match_table = of_match_ptr(jz4740_of_matches)
 
544
        },
 
545
};
 
546
 
 
547
module_platform_driver(jz4740_i2s_driver);
 
548
 
 
549
MODULE_AUTHOR("Lars-Peter Clausen, <lars@metafoo.de>");
 
550
MODULE_DESCRIPTION("Ingenic JZ4740 SoC I2S driver");
 
551
MODULE_LICENSE("GPL");
 
552
MODULE_ALIAS("platform:jz4740-i2s");