aboutsummaryrefslogtreecommitdiffstats
path: root/sound/soc/dwc/dwc-i2s.c
diff options
context:
space:
mode:
authorTakashi Iwai <tiwai@suse.de>2017-05-02 02:25:25 -0400
committerTakashi Iwai <tiwai@suse.de>2017-05-02 02:25:25 -0400
commita5c3b32a1146e44f6b38fdfdfffc27842953420c (patch)
treeeca93f51c8deabe77ed079a3e9190717b6380009 /sound/soc/dwc/dwc-i2s.c
parentd7dc450d5a7162de96edbed6b1792240c2f3a55f (diff)
parent20d5c84bef067b7e804a163e2abca16c47125bad (diff)
Merge tag 'asoc-v4.12' of git://git.kernel.org/pub/scm/linux/kernel/git/broonie/sound into for-linus
ASoC: Updates for v4.12 A quiet release for the core, but lots of new drivers this time around: - A new, generalized, API for hooking up jacks which makes it easier to write generic machine drivers for simple cases. - Continuing fixes for issues with the x86 CPU drivers. - New drivers for Cirrus CS35L35, DIO DIO2125, Everest ES7132, HiSilicon hi6210, Maxim MAX98927, MT2701 systems with WM8960, Nuvoton NAU8824, Odroid systems, ST STM32 SAI controllers and x86 systems with DA7213
Diffstat (limited to 'sound/soc/dwc/dwc-i2s.c')
-rw-r--r--sound/soc/dwc/dwc-i2s.c753
1 files changed, 753 insertions, 0 deletions
diff --git a/sound/soc/dwc/dwc-i2s.c b/sound/soc/dwc/dwc-i2s.c
new file mode 100644
index 000000000000..9c46e4112026
--- /dev/null
+++ b/sound/soc/dwc/dwc-i2s.c
@@ -0,0 +1,753 @@
1/*
2 * ALSA SoC Synopsys I2S Audio Layer
3 *
4 * sound/soc/dwc/designware_i2s.c
5 *
6 * Copyright (C) 2010 ST Microelectronics
7 * Rajeev Kumar <rajeevkumar.linux@gmail.com>
8 *
9 * This file is licensed under the terms of the GNU General Public
10 * License version 2. This program is licensed "as is" without any
11 * warranty of any kind, whether express or implied.
12 */
13
14#include <linux/clk.h>
15#include <linux/device.h>
16#include <linux/init.h>
17#include <linux/io.h>
18#include <linux/interrupt.h>
19#include <linux/module.h>
20#include <linux/slab.h>
21#include <linux/pm_runtime.h>
22#include <sound/designware_i2s.h>
23#include <sound/pcm.h>
24#include <sound/pcm_params.h>
25#include <sound/soc.h>
26#include <sound/dmaengine_pcm.h>
27#include "local.h"
28
29static inline void i2s_write_reg(void __iomem *io_base, int reg, u32 val)
30{
31 writel(val, io_base + reg);
32}
33
34static inline u32 i2s_read_reg(void __iomem *io_base, int reg)
35{
36 return readl(io_base + reg);
37}
38
39static inline void i2s_disable_channels(struct dw_i2s_dev *dev, u32 stream)
40{
41 u32 i = 0;
42
43 if (stream == SNDRV_PCM_STREAM_PLAYBACK) {
44 for (i = 0; i < 4; i++)
45 i2s_write_reg(dev->i2s_base, TER(i), 0);
46 } else {
47 for (i = 0; i < 4; i++)
48 i2s_write_reg(dev->i2s_base, RER(i), 0);
49 }
50}
51
52static inline void i2s_clear_irqs(struct dw_i2s_dev *dev, u32 stream)
53{
54 u32 i = 0;
55
56 if (stream == SNDRV_PCM_STREAM_PLAYBACK) {
57 for (i = 0; i < 4; i++)
58 i2s_read_reg(dev->i2s_base, TOR(i));
59 } else {
60 for (i = 0; i < 4; i++)
61 i2s_read_reg(dev->i2s_base, ROR(i));
62 }
63}
64
65static inline void i2s_disable_irqs(struct dw_i2s_dev *dev, u32 stream,
66 int chan_nr)
67{
68 u32 i, irq;
69
70 if (stream == SNDRV_PCM_STREAM_PLAYBACK) {
71 for (i = 0; i < (chan_nr / 2); i++) {
72 irq = i2s_read_reg(dev->i2s_base, IMR(i));
73 i2s_write_reg(dev->i2s_base, IMR(i), irq | 0x30);
74 }
75 } else {
76 for (i = 0; i < (chan_nr / 2); i++) {
77 irq = i2s_read_reg(dev->i2s_base, IMR(i));
78 i2s_write_reg(dev->i2s_base, IMR(i), irq | 0x03);
79 }
80 }
81}
82
83static inline void i2s_enable_irqs(struct dw_i2s_dev *dev, u32 stream,
84 int chan_nr)
85{
86 u32 i, irq;
87
88 if (stream == SNDRV_PCM_STREAM_PLAYBACK) {
89 for (i = 0; i < (chan_nr / 2); i++) {
90 irq = i2s_read_reg(dev->i2s_base, IMR(i));
91 i2s_write_reg(dev->i2s_base, IMR(i), irq & ~0x30);
92 }
93 } else {
94 for (i = 0; i < (chan_nr / 2); i++) {
95 irq = i2s_read_reg(dev->i2s_base, IMR(i));
96 i2s_write_reg(dev->i2s_base, IMR(i), irq & ~0x03);
97 }
98 }
99}
100
101static irqreturn_t i2s_irq_handler(int irq, void *dev_id)
102{
103 struct dw_i2s_dev *dev = dev_id;
104 bool irq_valid = false;
105 u32 isr[4];
106 int i;
107
108 for (i = 0; i < 4; i++)
109 isr[i] = i2s_read_reg(dev->i2s_base, ISR(i));
110
111 i2s_clear_irqs(dev, SNDRV_PCM_STREAM_PLAYBACK);
112 i2s_clear_irqs(dev, SNDRV_PCM_STREAM_CAPTURE);
113
114 for (i = 0; i < 4; i++) {
115 /*
116 * Check if TX fifo is empty. If empty fill FIFO with samples
117 * NOTE: Only two channels supported
118 */
119 if ((isr[i] & ISR_TXFE) && (i == 0) && dev->use_pio) {
120 dw_pcm_push_tx(dev);
121 irq_valid = true;
122 }
123
124 /*
125 * Data available. Retrieve samples from FIFO
126 * NOTE: Only two channels supported
127 */
128 if ((isr[i] & ISR_RXDA) && (i == 0) && dev->use_pio) {
129 dw_pcm_pop_rx(dev);
130 irq_valid = true;
131 }
132
133 /* Error Handling: TX */
134 if (isr[i] & ISR_TXFO) {
135 dev_err(dev->dev, "TX overrun (ch_id=%d)\n", i);
136 irq_valid = true;
137 }
138
139 /* Error Handling: TX */
140 if (isr[i] & ISR_RXFO) {
141 dev_err(dev->dev, "RX overrun (ch_id=%d)\n", i);
142 irq_valid = true;
143 }
144 }
145
146 if (irq_valid)
147 return IRQ_HANDLED;
148 else
149 return IRQ_NONE;
150}
151
152static void i2s_start(struct dw_i2s_dev *dev,
153 struct snd_pcm_substream *substream)
154{
155 struct i2s_clk_config_data *config = &dev->config;
156
157 i2s_write_reg(dev->i2s_base, IER, 1);
158 i2s_enable_irqs(dev, substream->stream, config->chan_nr);
159
160 if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
161 i2s_write_reg(dev->i2s_base, ITER, 1);
162 else
163 i2s_write_reg(dev->i2s_base, IRER, 1);
164
165 i2s_write_reg(dev->i2s_base, CER, 1);
166}
167
168static void i2s_stop(struct dw_i2s_dev *dev,
169 struct snd_pcm_substream *substream)
170{
171
172 i2s_clear_irqs(dev, substream->stream);
173 if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
174 i2s_write_reg(dev->i2s_base, ITER, 0);
175 else
176 i2s_write_reg(dev->i2s_base, IRER, 0);
177
178 i2s_disable_irqs(dev, substream->stream, 8);
179
180 if (!dev->active) {
181 i2s_write_reg(dev->i2s_base, CER, 0);
182 i2s_write_reg(dev->i2s_base, IER, 0);
183 }
184}
185
186static int dw_i2s_startup(struct snd_pcm_substream *substream,
187 struct snd_soc_dai *cpu_dai)
188{
189 struct dw_i2s_dev *dev = snd_soc_dai_get_drvdata(cpu_dai);
190 union dw_i2s_snd_dma_data *dma_data = NULL;
191
192 if (!(dev->capability & DWC_I2S_RECORD) &&
193 (substream->stream == SNDRV_PCM_STREAM_CAPTURE))
194 return -EINVAL;
195
196 if (!(dev->capability & DWC_I2S_PLAY) &&
197 (substream->stream == SNDRV_PCM_STREAM_PLAYBACK))
198 return -EINVAL;
199
200 if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
201 dma_data = &dev->play_dma_data;
202 else if (substream->stream == SNDRV_PCM_STREAM_CAPTURE)
203 dma_data = &dev->capture_dma_data;
204
205 snd_soc_dai_set_dma_data(cpu_dai, substream, (void *)dma_data);
206
207 return 0;
208}
209
210static void dw_i2s_config(struct dw_i2s_dev *dev, int stream)
211{
212 u32 ch_reg;
213 struct i2s_clk_config_data *config = &dev->config;
214
215
216 i2s_disable_channels(dev, stream);
217
218 for (ch_reg = 0; ch_reg < (config->chan_nr / 2); ch_reg++) {
219 if (stream == SNDRV_PCM_STREAM_PLAYBACK) {
220 i2s_write_reg(dev->i2s_base, TCR(ch_reg),
221 dev->xfer_resolution);
222 i2s_write_reg(dev->i2s_base, TFCR(ch_reg),
223 dev->fifo_th - 1);
224 i2s_write_reg(dev->i2s_base, TER(ch_reg), 1);
225 } else {
226 i2s_write_reg(dev->i2s_base, RCR(ch_reg),
227 dev->xfer_resolution);
228 i2s_write_reg(dev->i2s_base, RFCR(ch_reg),
229 dev->fifo_th - 1);
230 i2s_write_reg(dev->i2s_base, RER(ch_reg), 1);
231 }
232
233 }
234}
235
236static int dw_i2s_hw_params(struct snd_pcm_substream *substream,
237 struct snd_pcm_hw_params *params, struct snd_soc_dai *dai)
238{
239 struct dw_i2s_dev *dev = snd_soc_dai_get_drvdata(dai);
240 struct i2s_clk_config_data *config = &dev->config;
241 int ret;
242
243 switch (params_format(params)) {
244 case SNDRV_PCM_FORMAT_S16_LE:
245 config->data_width = 16;
246 dev->ccr = 0x00;
247 dev->xfer_resolution = 0x02;
248 break;
249
250 case SNDRV_PCM_FORMAT_S24_LE:
251 config->data_width = 24;
252 dev->ccr = 0x08;
253 dev->xfer_resolution = 0x04;
254 break;
255
256 case SNDRV_PCM_FORMAT_S32_LE:
257 config->data_width = 32;
258 dev->ccr = 0x10;
259 dev->xfer_resolution = 0x05;
260 break;
261
262 default:
263 dev_err(dev->dev, "designware-i2s: unsupported PCM fmt");
264 return -EINVAL;
265 }
266
267 config->chan_nr = params_channels(params);
268
269 switch (config->chan_nr) {
270 case EIGHT_CHANNEL_SUPPORT:
271 case SIX_CHANNEL_SUPPORT:
272 case FOUR_CHANNEL_SUPPORT:
273 case TWO_CHANNEL_SUPPORT:
274 break;
275 default:
276 dev_err(dev->dev, "channel not supported\n");
277 return -EINVAL;
278 }
279
280 dw_i2s_config(dev, substream->stream);
281
282 i2s_write_reg(dev->i2s_base, CCR, dev->ccr);
283
284 config->sample_rate = params_rate(params);
285
286 if (dev->capability & DW_I2S_MASTER) {
287 if (dev->i2s_clk_cfg) {
288 ret = dev->i2s_clk_cfg(config);
289 if (ret < 0) {
290 dev_err(dev->dev, "runtime audio clk config fail\n");
291 return ret;
292 }
293 } else {
294 u32 bitclk = config->sample_rate *
295 config->data_width * 2;
296
297 ret = clk_set_rate(dev->clk, bitclk);
298 if (ret) {
299 dev_err(dev->dev, "Can't set I2S clock rate: %d\n",
300 ret);
301 return ret;
302 }
303 }
304 }
305 return 0;
306}
307
308static void dw_i2s_shutdown(struct snd_pcm_substream *substream,
309 struct snd_soc_dai *dai)
310{
311 snd_soc_dai_set_dma_data(dai, substream, NULL);
312}
313
314static int dw_i2s_prepare(struct snd_pcm_substream *substream,
315 struct snd_soc_dai *dai)
316{
317 struct dw_i2s_dev *dev = snd_soc_dai_get_drvdata(dai);
318
319 if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
320 i2s_write_reg(dev->i2s_base, TXFFR, 1);
321 else
322 i2s_write_reg(dev->i2s_base, RXFFR, 1);
323
324 return 0;
325}
326
327static int dw_i2s_trigger(struct snd_pcm_substream *substream,
328 int cmd, struct snd_soc_dai *dai)
329{
330 struct dw_i2s_dev *dev = snd_soc_dai_get_drvdata(dai);
331 int ret = 0;
332
333 switch (cmd) {
334 case SNDRV_PCM_TRIGGER_START:
335 case SNDRV_PCM_TRIGGER_RESUME:
336 case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
337 dev->active++;
338 i2s_start(dev, substream);
339 break;
340
341 case SNDRV_PCM_TRIGGER_STOP:
342 case SNDRV_PCM_TRIGGER_SUSPEND:
343 case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
344 dev->active--;
345 i2s_stop(dev, substream);
346 break;
347 default:
348 ret = -EINVAL;
349 break;
350 }
351 return ret;
352}
353
354static int dw_i2s_set_fmt(struct snd_soc_dai *cpu_dai, unsigned int fmt)
355{
356 struct dw_i2s_dev *dev = snd_soc_dai_get_drvdata(cpu_dai);
357 int ret = 0;
358
359 switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
360 case SND_SOC_DAIFMT_CBM_CFM:
361 if (dev->capability & DW_I2S_SLAVE)
362 ret = 0;
363 else
364 ret = -EINVAL;
365 break;
366 case SND_SOC_DAIFMT_CBS_CFS:
367 if (dev->capability & DW_I2S_MASTER)
368 ret = 0;
369 else
370 ret = -EINVAL;
371 break;
372 case SND_SOC_DAIFMT_CBM_CFS:
373 case SND_SOC_DAIFMT_CBS_CFM:
374 ret = -EINVAL;
375 break;
376 default:
377 dev_dbg(dev->dev, "dwc : Invalid master/slave format\n");
378 ret = -EINVAL;
379 break;
380 }
381 return ret;
382}
383
384static struct snd_soc_dai_ops dw_i2s_dai_ops = {
385 .startup = dw_i2s_startup,
386 .shutdown = dw_i2s_shutdown,
387 .hw_params = dw_i2s_hw_params,
388 .prepare = dw_i2s_prepare,
389 .trigger = dw_i2s_trigger,
390 .set_fmt = dw_i2s_set_fmt,
391};
392
393static const struct snd_soc_component_driver dw_i2s_component = {
394 .name = "dw-i2s",
395};
396
397#ifdef CONFIG_PM
398static int dw_i2s_runtime_suspend(struct device *dev)
399{
400 struct dw_i2s_dev *dw_dev = dev_get_drvdata(dev);
401
402 if (dw_dev->capability & DW_I2S_MASTER)
403 clk_disable(dw_dev->clk);
404 return 0;
405}
406
407static int dw_i2s_runtime_resume(struct device *dev)
408{
409 struct dw_i2s_dev *dw_dev = dev_get_drvdata(dev);
410
411 if (dw_dev->capability & DW_I2S_MASTER)
412 clk_enable(dw_dev->clk);
413 return 0;
414}
415
416static int dw_i2s_suspend(struct snd_soc_dai *dai)
417{
418 struct dw_i2s_dev *dev = snd_soc_dai_get_drvdata(dai);
419
420 if (dev->capability & DW_I2S_MASTER)
421 clk_disable(dev->clk);
422 return 0;
423}
424
425static int dw_i2s_resume(struct snd_soc_dai *dai)
426{
427 struct dw_i2s_dev *dev = snd_soc_dai_get_drvdata(dai);
428
429 if (dev->capability & DW_I2S_MASTER)
430 clk_enable(dev->clk);
431
432 if (dai->playback_active)
433 dw_i2s_config(dev, SNDRV_PCM_STREAM_PLAYBACK);
434 if (dai->capture_active)
435 dw_i2s_config(dev, SNDRV_PCM_STREAM_CAPTURE);
436 return 0;
437}
438
439#else
440#define dw_i2s_suspend NULL
441#define dw_i2s_resume NULL
442#endif
443
444/*
445 * The following tables allow a direct lookup of various parameters
446 * defined in the I2S block's configuration in terms of sound system
447 * parameters. Each table is sized to the number of entries possible
448 * according to the number of configuration bits describing an I2S
449 * block parameter.
450 */
451
452/* Maximum bit resolution of a channel - not uniformly spaced */
453static const u32 fifo_width[COMP_MAX_WORDSIZE] = {
454 12, 16, 20, 24, 32, 0, 0, 0
455};
456
457/* Width of (DMA) bus */
458static const u32 bus_widths[COMP_MAX_DATA_WIDTH] = {
459 DMA_SLAVE_BUSWIDTH_1_BYTE,
460 DMA_SLAVE_BUSWIDTH_2_BYTES,
461 DMA_SLAVE_BUSWIDTH_4_BYTES,
462 DMA_SLAVE_BUSWIDTH_UNDEFINED
463};
464
465/* PCM format to support channel resolution */
466static const u32 formats[COMP_MAX_WORDSIZE] = {
467 SNDRV_PCM_FMTBIT_S16_LE,
468 SNDRV_PCM_FMTBIT_S16_LE,
469 SNDRV_PCM_FMTBIT_S24_LE,
470 SNDRV_PCM_FMTBIT_S24_LE,
471 SNDRV_PCM_FMTBIT_S32_LE,
472 0,
473 0,
474 0
475};
476
477static int dw_configure_dai(struct dw_i2s_dev *dev,
478 struct snd_soc_dai_driver *dw_i2s_dai,
479 unsigned int rates)
480{
481 /*
482 * Read component parameter registers to extract
483 * the I2S block's configuration.
484 */
485 u32 comp1 = i2s_read_reg(dev->i2s_base, dev->i2s_reg_comp1);
486 u32 comp2 = i2s_read_reg(dev->i2s_base, dev->i2s_reg_comp2);
487 u32 fifo_depth = 1 << (1 + COMP1_FIFO_DEPTH_GLOBAL(comp1));
488 u32 idx;
489
490 if (dev->capability & DWC_I2S_RECORD &&
491 dev->quirks & DW_I2S_QUIRK_COMP_PARAM1)
492 comp1 = comp1 & ~BIT(5);
493
494 if (COMP1_TX_ENABLED(comp1)) {
495 dev_dbg(dev->dev, " designware: play supported\n");
496 idx = COMP1_TX_WORDSIZE_0(comp1);
497 if (WARN_ON(idx >= ARRAY_SIZE(formats)))
498 return -EINVAL;
499 dw_i2s_dai->playback.channels_min = MIN_CHANNEL_NUM;
500 dw_i2s_dai->playback.channels_max =
501 1 << (COMP1_TX_CHANNELS(comp1) + 1);
502 dw_i2s_dai->playback.formats = formats[idx];
503 dw_i2s_dai->playback.rates = rates;
504 }
505
506 if (COMP1_RX_ENABLED(comp1)) {
507 dev_dbg(dev->dev, "designware: record supported\n");
508 idx = COMP2_RX_WORDSIZE_0(comp2);
509 if (WARN_ON(idx >= ARRAY_SIZE(formats)))
510 return -EINVAL;
511 dw_i2s_dai->capture.channels_min = MIN_CHANNEL_NUM;
512 dw_i2s_dai->capture.channels_max =
513 1 << (COMP1_RX_CHANNELS(comp1) + 1);
514 dw_i2s_dai->capture.formats = formats[idx];
515 dw_i2s_dai->capture.rates = rates;
516 }
517
518 if (COMP1_MODE_EN(comp1)) {
519 dev_dbg(dev->dev, "designware: i2s master mode supported\n");
520 dev->capability |= DW_I2S_MASTER;
521 } else {
522 dev_dbg(dev->dev, "designware: i2s slave mode supported\n");
523 dev->capability |= DW_I2S_SLAVE;
524 }
525
526 dev->fifo_th = fifo_depth / 2;
527 return 0;
528}
529
530static int dw_configure_dai_by_pd(struct dw_i2s_dev *dev,
531 struct snd_soc_dai_driver *dw_i2s_dai,
532 struct resource *res,
533 const struct i2s_platform_data *pdata)
534{
535 u32 comp1 = i2s_read_reg(dev->i2s_base, dev->i2s_reg_comp1);
536 u32 idx = COMP1_APB_DATA_WIDTH(comp1);
537 int ret;
538
539 if (WARN_ON(idx >= ARRAY_SIZE(bus_widths)))
540 return -EINVAL;
541
542 ret = dw_configure_dai(dev, dw_i2s_dai, pdata->snd_rates);
543 if (ret < 0)
544 return ret;
545
546 /* Set DMA slaves info */
547 dev->play_dma_data.pd.data = pdata->play_dma_data;
548 dev->capture_dma_data.pd.data = pdata->capture_dma_data;
549 dev->play_dma_data.pd.addr = res->start + I2S_TXDMA;
550 dev->capture_dma_data.pd.addr = res->start + I2S_RXDMA;
551 dev->play_dma_data.pd.max_burst = 16;
552 dev->capture_dma_data.pd.max_burst = 16;
553 dev->play_dma_data.pd.addr_width = bus_widths[idx];
554 dev->capture_dma_data.pd.addr_width = bus_widths[idx];
555 dev->play_dma_data.pd.filter = pdata->filter;
556 dev->capture_dma_data.pd.filter = pdata->filter;
557
558 return 0;
559}
560
561static int dw_configure_dai_by_dt(struct dw_i2s_dev *dev,
562 struct snd_soc_dai_driver *dw_i2s_dai,
563 struct resource *res)
564{
565 u32 comp1 = i2s_read_reg(dev->i2s_base, I2S_COMP_PARAM_1);
566 u32 comp2 = i2s_read_reg(dev->i2s_base, I2S_COMP_PARAM_2);
567 u32 fifo_depth = 1 << (1 + COMP1_FIFO_DEPTH_GLOBAL(comp1));
568 u32 idx = COMP1_APB_DATA_WIDTH(comp1);
569 u32 idx2;
570 int ret;
571
572 if (WARN_ON(idx >= ARRAY_SIZE(bus_widths)))
573 return -EINVAL;
574
575 ret = dw_configure_dai(dev, dw_i2s_dai, SNDRV_PCM_RATE_8000_192000);
576 if (ret < 0)
577 return ret;
578
579 if (COMP1_TX_ENABLED(comp1)) {
580 idx2 = COMP1_TX_WORDSIZE_0(comp1);
581
582 dev->capability |= DWC_I2S_PLAY;
583 dev->play_dma_data.dt.addr = res->start + I2S_TXDMA;
584 dev->play_dma_data.dt.addr_width = bus_widths[idx];
585 dev->play_dma_data.dt.fifo_size = fifo_depth *
586 (fifo_width[idx2]) >> 8;
587 dev->play_dma_data.dt.maxburst = 16;
588 }
589 if (COMP1_RX_ENABLED(comp1)) {
590 idx2 = COMP2_RX_WORDSIZE_0(comp2);
591
592 dev->capability |= DWC_I2S_RECORD;
593 dev->capture_dma_data.dt.addr = res->start + I2S_RXDMA;
594 dev->capture_dma_data.dt.addr_width = bus_widths[idx];
595 dev->capture_dma_data.dt.fifo_size = fifo_depth *
596 (fifo_width[idx2] >> 8);
597 dev->capture_dma_data.dt.maxburst = 16;
598 }
599
600 return 0;
601
602}
603
604static int dw_i2s_probe(struct platform_device *pdev)
605{
606 const struct i2s_platform_data *pdata = pdev->dev.platform_data;
607 struct dw_i2s_dev *dev;
608 struct resource *res;
609 int ret, irq;
610 struct snd_soc_dai_driver *dw_i2s_dai;
611 const char *clk_id;
612
613 dev = devm_kzalloc(&pdev->dev, sizeof(*dev), GFP_KERNEL);
614 if (!dev) {
615 dev_warn(&pdev->dev, "kzalloc fail\n");
616 return -ENOMEM;
617 }
618
619 dw_i2s_dai = devm_kzalloc(&pdev->dev, sizeof(*dw_i2s_dai), GFP_KERNEL);
620 if (!dw_i2s_dai)
621 return -ENOMEM;
622
623 dw_i2s_dai->ops = &dw_i2s_dai_ops;
624 dw_i2s_dai->suspend = dw_i2s_suspend;
625 dw_i2s_dai->resume = dw_i2s_resume;
626
627 res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
628 dev->i2s_base = devm_ioremap_resource(&pdev->dev, res);
629 if (IS_ERR(dev->i2s_base))
630 return PTR_ERR(dev->i2s_base);
631
632 dev->dev = &pdev->dev;
633
634 irq = platform_get_irq(pdev, 0);
635 if (irq >= 0) {
636 ret = devm_request_irq(&pdev->dev, irq, i2s_irq_handler, 0,
637 pdev->name, dev);
638 if (ret < 0) {
639 dev_err(&pdev->dev, "failed to request irq\n");
640 return ret;
641 }
642 }
643
644 dev->i2s_reg_comp1 = I2S_COMP_PARAM_1;
645 dev->i2s_reg_comp2 = I2S_COMP_PARAM_2;
646 if (pdata) {
647 dev->capability = pdata->cap;
648 clk_id = NULL;
649 dev->quirks = pdata->quirks;
650 if (dev->quirks & DW_I2S_QUIRK_COMP_REG_OFFSET) {
651 dev->i2s_reg_comp1 = pdata->i2s_reg_comp1;
652 dev->i2s_reg_comp2 = pdata->i2s_reg_comp2;
653 }
654 ret = dw_configure_dai_by_pd(dev, dw_i2s_dai, res, pdata);
655 } else {
656 clk_id = "i2sclk";
657 ret = dw_configure_dai_by_dt(dev, dw_i2s_dai, res);
658 }
659 if (ret < 0)
660 return ret;
661
662 if (dev->capability & DW_I2S_MASTER) {
663 if (pdata) {
664 dev->i2s_clk_cfg = pdata->i2s_clk_cfg;
665 if (!dev->i2s_clk_cfg) {
666 dev_err(&pdev->dev, "no clock configure method\n");
667 return -ENODEV;
668 }
669 }
670 dev->clk = devm_clk_get(&pdev->dev, clk_id);
671
672 if (IS_ERR(dev->clk))
673 return PTR_ERR(dev->clk);
674
675 ret = clk_prepare_enable(dev->clk);
676 if (ret < 0)
677 return ret;
678 }
679
680 dev_set_drvdata(&pdev->dev, dev);
681 ret = devm_snd_soc_register_component(&pdev->dev, &dw_i2s_component,
682 dw_i2s_dai, 1);
683 if (ret != 0) {
684 dev_err(&pdev->dev, "not able to register dai\n");
685 goto err_clk_disable;
686 }
687
688 if (!pdata) {
689 if (irq >= 0) {
690 ret = dw_pcm_register(pdev);
691 dev->use_pio = true;
692 } else {
693 ret = devm_snd_dmaengine_pcm_register(&pdev->dev, NULL,
694 0);
695 dev->use_pio = false;
696 }
697
698 if (ret) {
699 dev_err(&pdev->dev, "could not register pcm: %d\n",
700 ret);
701 goto err_clk_disable;
702 }
703 }
704
705 pm_runtime_enable(&pdev->dev);
706 return 0;
707
708err_clk_disable:
709 if (dev->capability & DW_I2S_MASTER)
710 clk_disable_unprepare(dev->clk);
711 return ret;
712}
713
714static int dw_i2s_remove(struct platform_device *pdev)
715{
716 struct dw_i2s_dev *dev = dev_get_drvdata(&pdev->dev);
717
718 if (dev->capability & DW_I2S_MASTER)
719 clk_disable_unprepare(dev->clk);
720
721 pm_runtime_disable(&pdev->dev);
722 return 0;
723}
724
725#ifdef CONFIG_OF
726static const struct of_device_id dw_i2s_of_match[] = {
727 { .compatible = "snps,designware-i2s", },
728 {},
729};
730
731MODULE_DEVICE_TABLE(of, dw_i2s_of_match);
732#endif
733
734static const struct dev_pm_ops dwc_pm_ops = {
735 SET_RUNTIME_PM_OPS(dw_i2s_runtime_suspend, dw_i2s_runtime_resume, NULL)
736};
737
738static struct platform_driver dw_i2s_driver = {
739 .probe = dw_i2s_probe,
740 .remove = dw_i2s_remove,
741 .driver = {
742 .name = "designware-i2s",
743 .of_match_table = of_match_ptr(dw_i2s_of_match),
744 .pm = &dwc_pm_ops,
745 },
746};
747
748module_platform_driver(dw_i2s_driver);
749
750MODULE_AUTHOR("Rajeev Kumar <rajeevkumar.linux@gmail.com>");
751MODULE_DESCRIPTION("DESIGNWARE I2S SoC Interface");
752MODULE_LICENSE("GPL");
753MODULE_ALIAS("platform:designware_i2s");