blob: 92bdaf0878f8a12d8e0f0587c4d5afb11f8200d3 [file] [log] [blame]
Sylwester Nawrocki521cc682019-04-19 12:21:49 +02001// SPDX-License-Identifier: GPL-2.0+
2//
3// s3c24xx-i2s.c -- ALSA Soc Audio Layer
4//
5// (c) 2006 Wolfson Microelectronics PLC.
6// Graeme Gregory graeme.gregory@wolfsonmicro.com or linux@wolfsonmicro.com
7//
8// Copyright 2004-2005 Simtec Electronics
9// http://armlinux.simtec.co.uk/
10// Ben Dooks <ben@simtec.co.uk>
Ben Dooksc1422a62007-02-14 13:17:49 +010011
Ben Dooksc1422a62007-02-14 13:17:49 +010012#include <linux/delay.h>
13#include <linux/clk.h>
Mark Brown40efc152008-04-23 15:09:31 +020014#include <linux/io.h>
Ben Dooksec976d62009-05-13 22:52:24 +010015#include <linux/gpio.h>
Paul Gortmakerda155d52011-07-15 12:38:28 -040016#include <linux/module.h>
Ben Dooksec976d62009-05-13 22:52:24 +010017
Ben Dooksc1422a62007-02-14 13:17:49 +010018#include <sound/soc.h>
Seungwhan Youn0378b6a2011-01-11 07:26:06 +090019#include <sound/pcm_params.h>
Ben Dooksc1422a62007-02-14 13:17:49 +010020
Sachin Kamatabffae62014-01-22 17:30:38 +053021#include <mach/gpio-samsung.h>
22#include <plat/gpio-cfg.h>
Arnd Bergmann5d229ce52013-04-11 19:08:42 +020023#include "regs-iis.h"
Harald Welteaa9673c2007-12-19 15:37:49 +010024
Jassi Brar4b640cf2010-11-22 15:35:57 +090025#include "dma.h"
Ben Dooksc1422a62007-02-14 13:17:49 +010026#include "s3c24xx-i2s.h"
27
Sylwester Nawrocki89993902016-08-04 11:30:27 +020028static struct snd_dmaengine_dai_dma_data s3c24xx_i2s_pcm_stereo_out = {
Sylwester Nawrockib8ab0cc2017-01-17 14:16:42 +010029 .chan_name = "tx",
Sylwester Nawrocki89993902016-08-04 11:30:27 +020030 .addr_width = 2,
Ben Dooksc1422a62007-02-14 13:17:49 +010031};
32
Sylwester Nawrocki89993902016-08-04 11:30:27 +020033static struct snd_dmaengine_dai_dma_data s3c24xx_i2s_pcm_stereo_in = {
Sylwester Nawrockib8ab0cc2017-01-17 14:16:42 +010034 .chan_name = "rx",
Sylwester Nawrocki89993902016-08-04 11:30:27 +020035 .addr_width = 2,
Ben Dooksc1422a62007-02-14 13:17:49 +010036};
37
38struct s3c24xx_i2s_info {
39 void __iomem *regs;
40 struct clk *iis_clk;
Graeme Gregory5cd919a2008-01-10 14:44:58 +010041 u32 iiscon;
42 u32 iismod;
43 u32 iisfcon;
44 u32 iispsr;
Ben Dooksc1422a62007-02-14 13:17:49 +010045};
46static struct s3c24xx_i2s_info s3c24xx_i2s;
47
48static void s3c24xx_snd_txctrl(int on)
49{
50 u32 iisfcon;
51 u32 iiscon;
52 u32 iismod;
53
Ben Dooksc1422a62007-02-14 13:17:49 +010054 iisfcon = readl(s3c24xx_i2s.regs + S3C2410_IISFCON);
55 iiscon = readl(s3c24xx_i2s.regs + S3C2410_IISCON);
56 iismod = readl(s3c24xx_i2s.regs + S3C2410_IISMOD);
57
Mark Brown5314adc2009-03-11 16:28:29 +000058 pr_debug("r: IISCON: %x IISMOD: %x IISFCON: %x\n", iiscon, iismod, iisfcon);
Ben Dooksc1422a62007-02-14 13:17:49 +010059
60 if (on) {
61 iisfcon |= S3C2410_IISFCON_TXDMA | S3C2410_IISFCON_TXENABLE;
62 iiscon |= S3C2410_IISCON_TXDMAEN | S3C2410_IISCON_IISEN;
63 iiscon &= ~S3C2410_IISCON_TXIDLE;
64 iismod |= S3C2410_IISMOD_TXMODE;
65
66 writel(iismod, s3c24xx_i2s.regs + S3C2410_IISMOD);
67 writel(iisfcon, s3c24xx_i2s.regs + S3C2410_IISFCON);
68 writel(iiscon, s3c24xx_i2s.regs + S3C2410_IISCON);
69 } else {
70 /* note, we have to disable the FIFOs otherwise bad things
71 * seem to happen when the DMA stops. According to the
72 * Samsung supplied kernel, this should allow the DMA
73 * engine and FIFOs to reset. If this isn't allowed, the
74 * DMA engine will simply freeze randomly.
75 */
76
77 iisfcon &= ~S3C2410_IISFCON_TXENABLE;
78 iisfcon &= ~S3C2410_IISFCON_TXDMA;
79 iiscon |= S3C2410_IISCON_TXIDLE;
80 iiscon &= ~S3C2410_IISCON_TXDMAEN;
81 iismod &= ~S3C2410_IISMOD_TXMODE;
82
83 writel(iiscon, s3c24xx_i2s.regs + S3C2410_IISCON);
84 writel(iisfcon, s3c24xx_i2s.regs + S3C2410_IISFCON);
85 writel(iismod, s3c24xx_i2s.regs + S3C2410_IISMOD);
86 }
87
Mark Brown5314adc2009-03-11 16:28:29 +000088 pr_debug("w: IISCON: %x IISMOD: %x IISFCON: %x\n", iiscon, iismod, iisfcon);
Ben Dooksc1422a62007-02-14 13:17:49 +010089}
90
91static void s3c24xx_snd_rxctrl(int on)
92{
93 u32 iisfcon;
94 u32 iiscon;
95 u32 iismod;
96
Ben Dooksc1422a62007-02-14 13:17:49 +010097 iisfcon = readl(s3c24xx_i2s.regs + S3C2410_IISFCON);
98 iiscon = readl(s3c24xx_i2s.regs + S3C2410_IISCON);
99 iismod = readl(s3c24xx_i2s.regs + S3C2410_IISMOD);
100
Mark Brown5314adc2009-03-11 16:28:29 +0000101 pr_debug("r: IISCON: %x IISMOD: %x IISFCON: %x\n", iiscon, iismod, iisfcon);
Ben Dooksc1422a62007-02-14 13:17:49 +0100102
103 if (on) {
104 iisfcon |= S3C2410_IISFCON_RXDMA | S3C2410_IISFCON_RXENABLE;
105 iiscon |= S3C2410_IISCON_RXDMAEN | S3C2410_IISCON_IISEN;
106 iiscon &= ~S3C2410_IISCON_RXIDLE;
107 iismod |= S3C2410_IISMOD_RXMODE;
108
109 writel(iismod, s3c24xx_i2s.regs + S3C2410_IISMOD);
110 writel(iisfcon, s3c24xx_i2s.regs + S3C2410_IISFCON);
111 writel(iiscon, s3c24xx_i2s.regs + S3C2410_IISCON);
112 } else {
113 /* note, we have to disable the FIFOs otherwise bad things
114 * seem to happen when the DMA stops. According to the
115 * Samsung supplied kernel, this should allow the DMA
116 * engine and FIFOs to reset. If this isn't allowed, the
117 * DMA engine will simply freeze randomly.
118 */
119
Mark Brown0015e7d2008-04-23 15:09:57 +0200120 iisfcon &= ~S3C2410_IISFCON_RXENABLE;
121 iisfcon &= ~S3C2410_IISFCON_RXDMA;
122 iiscon |= S3C2410_IISCON_RXIDLE;
123 iiscon &= ~S3C2410_IISCON_RXDMAEN;
Ben Dooksc1422a62007-02-14 13:17:49 +0100124 iismod &= ~S3C2410_IISMOD_RXMODE;
125
126 writel(iisfcon, s3c24xx_i2s.regs + S3C2410_IISFCON);
127 writel(iiscon, s3c24xx_i2s.regs + S3C2410_IISCON);
128 writel(iismod, s3c24xx_i2s.regs + S3C2410_IISMOD);
129 }
130
Mark Brown5314adc2009-03-11 16:28:29 +0000131 pr_debug("w: IISCON: %x IISMOD: %x IISFCON: %x\n", iiscon, iismod, iisfcon);
Ben Dooksc1422a62007-02-14 13:17:49 +0100132}
133
134/*
135 * Wait for the LR signal to allow synchronisation to the L/R clock
136 * from the codec. May only be needed for slave mode.
137 */
138static int s3c24xx_snd_lrsync(void)
139{
140 u32 iiscon;
Werner Almesberger33e5b222008-04-14 14:26:44 +0200141 int timeout = 50; /* 5ms */
Ben Dooksc1422a62007-02-14 13:17:49 +0100142
Ben Dooksc1422a62007-02-14 13:17:49 +0100143 while (1) {
144 iiscon = readl(s3c24xx_i2s.regs + S3C2410_IISCON);
145 if (iiscon & S3C2410_IISCON_LRINDEX)
146 break;
147
Werner Almesberger33e5b222008-04-14 14:26:44 +0200148 if (!timeout--)
Ben Dooksc1422a62007-02-14 13:17:49 +0100149 return -ETIMEDOUT;
Werner Almesberger33e5b222008-04-14 14:26:44 +0200150 udelay(100);
Ben Dooksc1422a62007-02-14 13:17:49 +0100151 }
152
153 return 0;
154}
155
156/*
157 * Check whether CPU is the master or slave
158 */
159static inline int s3c24xx_snd_is_clkmaster(void)
160{
Ben Dooksc1422a62007-02-14 13:17:49 +0100161 return (readl(s3c24xx_i2s.regs + S3C2410_IISMOD) & S3C2410_IISMOD_SLAVE) ? 0:1;
162}
163
164/*
165 * Set S3C24xx I2S DAI format
166 */
Liam Girdwood1992a6f2008-07-07 16:08:24 +0100167static int s3c24xx_i2s_set_fmt(struct snd_soc_dai *cpu_dai,
Ben Dooksc1422a62007-02-14 13:17:49 +0100168 unsigned int fmt)
169{
170 u32 iismod;
171
Ben Dooksc1422a62007-02-14 13:17:49 +0100172 iismod = readl(s3c24xx_i2s.regs + S3C2410_IISMOD);
Mark Brown5314adc2009-03-11 16:28:29 +0000173 pr_debug("hw_params r: IISMOD: %x \n", iismod);
Ben Dooksc1422a62007-02-14 13:17:49 +0100174
175 switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
176 case SND_SOC_DAIFMT_CBM_CFM:
177 iismod |= S3C2410_IISMOD_SLAVE;
178 break;
179 case SND_SOC_DAIFMT_CBS_CFS:
Davide Rizzo2c36eec2008-05-05 14:59:39 +0200180 iismod &= ~S3C2410_IISMOD_SLAVE;
Ben Dooksc1422a62007-02-14 13:17:49 +0100181 break;
182 default:
183 return -EINVAL;
184 }
185
186 switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
187 case SND_SOC_DAIFMT_LEFT_J:
188 iismod |= S3C2410_IISMOD_MSB;
189 break;
190 case SND_SOC_DAIFMT_I2S:
Davide Rizzo2c36eec2008-05-05 14:59:39 +0200191 iismod &= ~S3C2410_IISMOD_MSB;
Ben Dooksc1422a62007-02-14 13:17:49 +0100192 break;
193 default:
194 return -EINVAL;
195 }
196
197 writel(iismod, s3c24xx_i2s.regs + S3C2410_IISMOD);
Mark Brown5314adc2009-03-11 16:28:29 +0000198 pr_debug("hw_params w: IISMOD: %x \n", iismod);
Sylwester Nawrocki2ef95552016-10-25 17:08:41 +0200199
Ben Dooksc1422a62007-02-14 13:17:49 +0100200 return 0;
201}
202
203static int s3c24xx_i2s_hw_params(struct snd_pcm_substream *substream,
Mark Browndee89c42008-11-18 22:11:38 +0000204 struct snd_pcm_hw_params *params,
205 struct snd_soc_dai *dai)
Ben Dooksc1422a62007-02-14 13:17:49 +0100206{
Vasily Khoruzhick87b132bc02014-06-23 23:24:04 +0300207 struct snd_dmaengine_dai_dma_data *dma_data;
Ben Dooksc1422a62007-02-14 13:17:49 +0100208 u32 iismod;
209
Vasily Khoruzhick87b132bc02014-06-23 23:24:04 +0300210 dma_data = snd_soc_dai_get_dma_data(dai, substream);
Ben Dooksc1422a62007-02-14 13:17:49 +0100211
212 /* Working copies of register */
213 iismod = readl(s3c24xx_i2s.regs + S3C2410_IISMOD);
Mark Brown5314adc2009-03-11 16:28:29 +0000214 pr_debug("hw_params r: IISMOD: %x\n", iismod);
Ben Dooksc1422a62007-02-14 13:17:49 +0100215
Tushar Behera88ce1462014-05-23 17:35:39 +0530216 switch (params_width(params)) {
217 case 8:
Christian Pellegrin53599bb2008-11-08 08:44:16 +0100218 iismod &= ~S3C2410_IISMOD_16BIT;
Vasily Khoruzhick87b132bc02014-06-23 23:24:04 +0300219 dma_data->addr_width = 1;
Ben Dooksc1422a62007-02-14 13:17:49 +0100220 break;
Tushar Behera88ce1462014-05-23 17:35:39 +0530221 case 16:
Ben Dooksc1422a62007-02-14 13:17:49 +0100222 iismod |= S3C2410_IISMOD_16BIT;
Vasily Khoruzhick87b132bc02014-06-23 23:24:04 +0300223 dma_data->addr_width = 2;
Ben Dooksc1422a62007-02-14 13:17:49 +0100224 break;
Christian Pellegrin53599bb2008-11-08 08:44:16 +0100225 default:
226 return -EINVAL;
Ben Dooksc1422a62007-02-14 13:17:49 +0100227 }
228
229 writel(iismod, s3c24xx_i2s.regs + S3C2410_IISMOD);
Mark Brown5314adc2009-03-11 16:28:29 +0000230 pr_debug("hw_params w: IISMOD: %x\n", iismod);
Sylwester Nawrocki2ef95552016-10-25 17:08:41 +0200231
Ben Dooksc1422a62007-02-14 13:17:49 +0100232 return 0;
233}
234
Mark Browndee89c42008-11-18 22:11:38 +0000235static int s3c24xx_i2s_trigger(struct snd_pcm_substream *substream, int cmd,
236 struct snd_soc_dai *dai)
Ben Dooksc1422a62007-02-14 13:17:49 +0100237{
238 int ret = 0;
239
Ben Dooksc1422a62007-02-14 13:17:49 +0100240 switch (cmd) {
241 case SNDRV_PCM_TRIGGER_START:
242 case SNDRV_PCM_TRIGGER_RESUME:
243 case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
244 if (!s3c24xx_snd_is_clkmaster()) {
245 ret = s3c24xx_snd_lrsync();
246 if (ret)
247 goto exit_err;
248 }
249
250 if (substream->stream == SNDRV_PCM_STREAM_CAPTURE)
251 s3c24xx_snd_rxctrl(1);
252 else
253 s3c24xx_snd_txctrl(1);
Shine Liufaf907c2009-08-25 20:05:50 +0800254
Ben Dooksc1422a62007-02-14 13:17:49 +0100255 break;
256 case SNDRV_PCM_TRIGGER_STOP:
257 case SNDRV_PCM_TRIGGER_SUSPEND:
258 case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
259 if (substream->stream == SNDRV_PCM_STREAM_CAPTURE)
260 s3c24xx_snd_rxctrl(0);
261 else
262 s3c24xx_snd_txctrl(0);
263 break;
264 default:
265 ret = -EINVAL;
266 break;
267 }
268
269exit_err:
270 return ret;
271}
272
273/*
274 * Set S3C24xx Clock source
275 */
Liam Girdwood1992a6f2008-07-07 16:08:24 +0100276static int s3c24xx_i2s_set_sysclk(struct snd_soc_dai *cpu_dai,
Ben Dooksc1422a62007-02-14 13:17:49 +0100277 int clk_id, unsigned int freq, int dir)
278{
279 u32 iismod = readl(s3c24xx_i2s.regs + S3C2410_IISMOD);
280
Ben Dooksc1422a62007-02-14 13:17:49 +0100281 iismod &= ~S3C2440_IISMOD_MPLL;
282
283 switch (clk_id) {
284 case S3C24XX_CLKSRC_PCLK:
285 break;
286 case S3C24XX_CLKSRC_MPLL:
287 iismod |= S3C2440_IISMOD_MPLL;
288 break;
289 default:
290 return -EINVAL;
291 }
292
293 writel(iismod, s3c24xx_i2s.regs + S3C2410_IISMOD);
294 return 0;
295}
296
297/*
298 * Set S3C24xx Clock dividers
299 */
Liam Girdwood1992a6f2008-07-07 16:08:24 +0100300static int s3c24xx_i2s_set_clkdiv(struct snd_soc_dai *cpu_dai,
Ben Dooksc1422a62007-02-14 13:17:49 +0100301 int div_id, int div)
302{
303 u32 reg;
304
Ben Dooksc1422a62007-02-14 13:17:49 +0100305 switch (div_id) {
Matt Reimer82fb1592007-07-12 12:27:24 +0200306 case S3C24XX_DIV_BCLK:
Ben Dooksc1422a62007-02-14 13:17:49 +0100307 reg = readl(s3c24xx_i2s.regs + S3C2410_IISMOD) & ~S3C2410_IISMOD_FS_MASK;
308 writel(reg | div, s3c24xx_i2s.regs + S3C2410_IISMOD);
309 break;
Matt Reimer82fb1592007-07-12 12:27:24 +0200310 case S3C24XX_DIV_MCLK:
Ben Dooksc1422a62007-02-14 13:17:49 +0100311 reg = readl(s3c24xx_i2s.regs + S3C2410_IISMOD) & ~(S3C2410_IISMOD_384FS);
312 writel(reg | div, s3c24xx_i2s.regs + S3C2410_IISMOD);
313 break;
314 case S3C24XX_DIV_PRESCALER:
315 writel(div, s3c24xx_i2s.regs + S3C2410_IISPSR);
316 reg = readl(s3c24xx_i2s.regs + S3C2410_IISCON);
317 writel(reg | S3C2410_IISCON_PSCEN, s3c24xx_i2s.regs + S3C2410_IISCON);
318 break;
319 default:
320 return -EINVAL;
321 }
322
323 return 0;
324}
325
326/*
327 * To avoid duplicating clock code, allow machine driver to
328 * get the clockrate from here.
329 */
330u32 s3c24xx_i2s_get_clockrate(void)
331{
332 return clk_get_rate(s3c24xx_i2s.iis_clk);
333}
334EXPORT_SYMBOL_GPL(s3c24xx_i2s_get_clockrate);
335
Liam Girdwoodf0fba2a2010-03-17 20:15:21 +0000336static int s3c24xx_i2s_probe(struct snd_soc_dai *dai)
Ben Dooksc1422a62007-02-14 13:17:49 +0100337{
Arvind Yadav86984752017-07-25 15:44:29 +0530338 int ret;
Sylwester Nawrocki89993902016-08-04 11:30:27 +0200339 snd_soc_dai_init_dma_data(dai, &s3c24xx_i2s_pcm_stereo_out,
340 &s3c24xx_i2s_pcm_stereo_in);
Ben Dooksc1422a62007-02-14 13:17:49 +0100341
Vasily Khoruzhick87b132bc02014-06-23 23:24:04 +0300342 s3c24xx_i2s.iis_clk = devm_clk_get(dai->dev, "iis");
Axel Lin7803e322011-09-15 10:36:54 +0800343 if (IS_ERR(s3c24xx_i2s.iis_clk)) {
Mark Brownb52a5192009-03-06 18:13:43 +0000344 pr_err("failed to get iis_clock\n");
Axel Lin7803e322011-09-15 10:36:54 +0800345 return PTR_ERR(s3c24xx_i2s.iis_clk);
Ben Dooksc1422a62007-02-14 13:17:49 +0100346 }
Arvind Yadav86984752017-07-25 15:44:29 +0530347 ret = clk_prepare_enable(s3c24xx_i2s.iis_clk);
348 if (ret)
349 return ret;
Ben Dooksc1422a62007-02-14 13:17:49 +0100350
Sylwester Nawrocki0eed8a12012-07-13 19:22:44 +0200351 /* Configure the I2S pins (GPE0...GPE4) in correct mode */
352 s3c_gpio_cfgall_range(S3C2410_GPE(0), 5, S3C_GPIO_SFN(2),
353 S3C_GPIO_PULL_NONE);
Ben Dooksc1422a62007-02-14 13:17:49 +0100354
355 writel(S3C2410_IISCON_IISEN, s3c24xx_i2s.regs + S3C2410_IISCON);
356
357 s3c24xx_snd_txctrl(0);
358 s3c24xx_snd_rxctrl(0);
359
360 return 0;
361}
362
Graeme Gregory5cd919a2008-01-10 14:44:58 +0100363#ifdef CONFIG_PM
Mark Browndc7d7b82008-12-03 18:21:52 +0000364static int s3c24xx_i2s_suspend(struct snd_soc_dai *cpu_dai)
Graeme Gregory5cd919a2008-01-10 14:44:58 +0100365{
366 s3c24xx_i2s.iiscon = readl(s3c24xx_i2s.regs + S3C2410_IISCON);
367 s3c24xx_i2s.iismod = readl(s3c24xx_i2s.regs + S3C2410_IISMOD);
368 s3c24xx_i2s.iisfcon = readl(s3c24xx_i2s.regs + S3C2410_IISFCON);
369 s3c24xx_i2s.iispsr = readl(s3c24xx_i2s.regs + S3C2410_IISPSR);
370
Vasily Khoruzhickc1ae59c2014-06-23 23:24:07 +0300371 clk_disable_unprepare(s3c24xx_i2s.iis_clk);
Graeme Gregory5cd919a2008-01-10 14:44:58 +0100372
373 return 0;
374}
375
Mark Browndc7d7b82008-12-03 18:21:52 +0000376static int s3c24xx_i2s_resume(struct snd_soc_dai *cpu_dai)
Graeme Gregory5cd919a2008-01-10 14:44:58 +0100377{
Arvind Yadav86984752017-07-25 15:44:29 +0530378 int ret;
379
380 ret = clk_prepare_enable(s3c24xx_i2s.iis_clk);
381 if (ret)
382 return ret;
Graeme Gregory5cd919a2008-01-10 14:44:58 +0100383
384 writel(s3c24xx_i2s.iiscon, s3c24xx_i2s.regs + S3C2410_IISCON);
385 writel(s3c24xx_i2s.iismod, s3c24xx_i2s.regs + S3C2410_IISMOD);
386 writel(s3c24xx_i2s.iisfcon, s3c24xx_i2s.regs + S3C2410_IISFCON);
387 writel(s3c24xx_i2s.iispsr, s3c24xx_i2s.regs + S3C2410_IISPSR);
388
389 return 0;
390}
391#else
392#define s3c24xx_i2s_suspend NULL
393#define s3c24xx_i2s_resume NULL
394#endif
395
Ben Dooksc1422a62007-02-14 13:17:49 +0100396#define S3C24XX_I2S_RATES \
397 (SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_11025 | SNDRV_PCM_RATE_16000 | \
398 SNDRV_PCM_RATE_22050 | SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_44100 | \
399 SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_88200 | SNDRV_PCM_RATE_96000)
400
Lars-Peter Clausen85e76522011-11-23 11:40:40 +0100401static const struct snd_soc_dai_ops s3c24xx_i2s_dai_ops = {
Eric Miao6335d052009-03-03 09:41:00 +0800402 .trigger = s3c24xx_i2s_trigger,
403 .hw_params = s3c24xx_i2s_hw_params,
404 .set_fmt = s3c24xx_i2s_set_fmt,
405 .set_clkdiv = s3c24xx_i2s_set_clkdiv,
406 .set_sysclk = s3c24xx_i2s_set_sysclk,
407};
408
Liam Girdwoodf0fba2a2010-03-17 20:15:21 +0000409static struct snd_soc_dai_driver s3c24xx_i2s_dai = {
Ben Dooksc1422a62007-02-14 13:17:49 +0100410 .probe = s3c24xx_i2s_probe,
Graeme Gregory5cd919a2008-01-10 14:44:58 +0100411 .suspend = s3c24xx_i2s_suspend,
412 .resume = s3c24xx_i2s_resume,
Ben Dooksc1422a62007-02-14 13:17:49 +0100413 .playback = {
414 .channels_min = 2,
415 .channels_max = 2,
416 .rates = S3C24XX_I2S_RATES,
417 .formats = SNDRV_PCM_FMTBIT_S8 | SNDRV_PCM_FMTBIT_S16_LE,},
418 .capture = {
419 .channels_min = 2,
420 .channels_max = 2,
421 .rates = S3C24XX_I2S_RATES,
422 .formats = SNDRV_PCM_FMTBIT_S8 | SNDRV_PCM_FMTBIT_S16_LE,},
Eric Miao6335d052009-03-03 09:41:00 +0800423 .ops = &s3c24xx_i2s_dai_ops,
Ben Dooksc1422a62007-02-14 13:17:49 +0100424};
Liam Girdwoodf0fba2a2010-03-17 20:15:21 +0000425
Kuninori Morimoto5642ddf2013-03-21 03:35:11 -0700426static const struct snd_soc_component_driver s3c24xx_i2s_component = {
427 .name = "s3c24xx-i2s",
428};
429
Bill Pembertonfdca21a2012-12-07 09:26:15 -0500430static int s3c24xx_iis_dev_probe(struct platform_device *pdev)
Liam Girdwoodf0fba2a2010-03-17 20:15:21 +0000431{
Vasily Khoruzhick87b132bc02014-06-23 23:24:04 +0300432 struct resource *res;
Sylwester Nawrocki5d3c1f62016-11-02 12:11:47 +0100433 int ret;
Vasily Khoruzhick87b132bc02014-06-23 23:24:04 +0300434
435 res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
Vasily Khoruzhick87b132bc02014-06-23 23:24:04 +0300436 s3c24xx_i2s.regs = devm_ioremap_resource(&pdev->dev, res);
Wei Yongjunc4791632015-04-16 20:18:02 +0800437 if (IS_ERR(s3c24xx_i2s.regs))
438 return PTR_ERR(s3c24xx_i2s.regs);
Vasily Khoruzhick87b132bc02014-06-23 23:24:04 +0300439
Sylwester Nawrocki89993902016-08-04 11:30:27 +0200440 s3c24xx_i2s_pcm_stereo_out.addr = res->start + S3C2410_IISFIFO;
Sylwester Nawrocki89993902016-08-04 11:30:27 +0200441 s3c24xx_i2s_pcm_stereo_in.addr = res->start + S3C2410_IISFIFO;
Padmavathi Vennaa08485d82012-12-07 13:59:21 +0530442
Sylwester Nawrocki6c9473c2016-11-02 12:04:36 +0100443 ret = samsung_asoc_dma_platform_register(&pdev->dev, NULL,
Sylwester Nawrocki0f928c12019-02-14 10:37:41 +0100444 "tx", "rx", NULL);
Padmavathi Vennaa08485d82012-12-07 13:59:21 +0530445 if (ret) {
Sylwester Nawrocki6c9473c2016-11-02 12:04:36 +0100446 dev_err(&pdev->dev, "Failed to register the DMA: %d\n", ret);
Padmavathi Vennaa08485d82012-12-07 13:59:21 +0530447 return ret;
448 }
449
Marek Szyprowski73f5dfc2016-10-27 12:34:02 +0200450 ret = devm_snd_soc_register_component(&pdev->dev,
451 &s3c24xx_i2s_component, &s3c24xx_i2s_dai, 1);
Tushar Behera7253e352014-05-21 08:52:19 +0530452 if (ret)
Sylwester Nawrocki6c9473c2016-11-02 12:04:36 +0100453 dev_err(&pdev->dev, "Failed to register the DAI\n");
Padmavathi Vennaa08485d82012-12-07 13:59:21 +0530454
Padmavathi Vennaa08485d82012-12-07 13:59:21 +0530455 return ret;
Liam Girdwoodf0fba2a2010-03-17 20:15:21 +0000456}
457
Liam Girdwoodf0fba2a2010-03-17 20:15:21 +0000458static struct platform_driver s3c24xx_iis_driver = {
459 .probe = s3c24xx_iis_dev_probe,
Liam Girdwoodf0fba2a2010-03-17 20:15:21 +0000460 .driver = {
461 .name = "s3c24xx-iis",
Liam Girdwoodf0fba2a2010-03-17 20:15:21 +0000462 },
463};
Ben Dooksc1422a62007-02-14 13:17:49 +0100464
Mark Browne00c3f52011-11-23 15:20:13 +0000465module_platform_driver(s3c24xx_iis_driver);
Mark Brown3f4b7832008-12-03 19:26:35 +0000466
Ben Dooksc1422a62007-02-14 13:17:49 +0100467/* Module information */
468MODULE_AUTHOR("Ben Dooks, <ben@simtec.co.uk>");
469MODULE_DESCRIPTION("s3c24xx I2S SoC Interface");
470MODULE_LICENSE("GPL");
Mark Brown960d0692010-08-12 11:02:19 +0100471MODULE_ALIAS("platform:s3c24xx-iis");