blob: 20cc51fc76ae92bdf7630c06cd841b32aef19bae [file] [log] [blame]
Jassi Brar5033f432010-11-22 15:37:25 +09001/* sound/soc/samsung/i2s.c
Jassi Brar1c7ac012010-11-22 15:36:59 +09002 *
3 * ALSA SoC Audio Layer - Samsung I2S Controller driver
4 *
5 * Copyright (c) 2010 Samsung Electronics Co. Ltd.
Jaswinder Singhdf8ad332012-02-25 16:24:36 +05306 * Jaswinder Singh <jassisinghbrar@gmail.com>
Jassi Brar1c7ac012010-11-22 15:36:59 +09007 *
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License version 2 as
10 * published by the Free Software Foundation.
11 */
12
13#include <linux/delay.h>
14#include <linux/slab.h>
15#include <linux/clk.h>
16#include <linux/io.h>
Paul Gortmakerda155d52011-07-15 12:38:28 -040017#include <linux/module.h>
Padmavathi Venna40476f62013-01-18 17:17:01 +053018#include <linux/of.h>
19#include <linux/of_gpio.h>
Mark Brownc5cf4db2011-12-08 16:45:03 +080020#include <linux/pm_runtime.h>
Jassi Brar1c7ac012010-11-22 15:36:59 +090021
Jassi Brar1c7ac012010-11-22 15:36:59 +090022#include <sound/soc.h>
Seungwhan Youn0378b6a2011-01-11 07:26:06 +090023#include <sound/pcm_params.h>
Jassi Brar1c7ac012010-11-22 15:36:59 +090024
Arnd Bergmann436d42c2012-08-24 15:22:12 +020025#include <linux/platform_data/asoc-s3c.h>
Jassi Brar1c7ac012010-11-22 15:36:59 +090026
27#include "dma.h"
Sangbeom Kim61100f42011-07-20 17:07:12 +090028#include "idma.h"
Jassi Brar1c7ac012010-11-22 15:36:59 +090029#include "i2s.h"
Sangbeom Kim172a4532011-06-20 16:36:18 +090030#include "i2s-regs.h"
Jassi Brar1c7ac012010-11-22 15:36:59 +090031
32#define msecs_to_loops(t) (loops_per_jiffy / 1000 * HZ * t)
33
Padmavathi Venna7c62eeb2013-01-18 17:17:00 +053034enum samsung_dai_type {
35 TYPE_PRI,
36 TYPE_SEC,
37};
38
Padmavathi Vennaa5a56872014-11-07 12:24:40 +053039struct samsung_i2s_variant_regs {
40 unsigned int bfs_off;
41 unsigned int rfs_off;
42 unsigned int sdf_off;
43 unsigned int txr_off;
44 unsigned int rclksrc_off;
45 unsigned int mss_off;
46 unsigned int cdclkcon_off;
47 unsigned int lrp_off;
48 unsigned int bfs_mask;
49 unsigned int rfs_mask;
50 unsigned int ftx0cnt_off;
51};
52
Padmavathi Venna40476f62013-01-18 17:17:01 +053053struct samsung_i2s_dai_data {
54 int dai_type;
Padmavathi Venna7da493e2013-08-12 15:19:51 +053055 u32 quirks;
Padmavathi Vennaa5a56872014-11-07 12:24:40 +053056 const struct samsung_i2s_variant_regs *i2s_variant_regs;
Padmavathi Venna40476f62013-01-18 17:17:01 +053057};
58
Jassi Brar1c7ac012010-11-22 15:36:59 +090059struct i2s_dai {
60 /* Platform device for this DAI */
61 struct platform_device *pdev;
Sylwester Nawrockiaf1cf5c2015-01-14 19:42:30 +010062 /* Memory mapped SFR region */
Jassi Brar1c7ac012010-11-22 15:36:59 +090063 void __iomem *addr;
Jassi Brar1c7ac012010-11-22 15:36:59 +090064 /* Rate of RCLK source clock */
65 unsigned long rclk_srcrate;
66 /* Frame Clock */
67 unsigned frmclk;
68 /*
69 * Specifically requested RCLK,BCLK by MACHINE Driver.
70 * 0 indicates CPU driver is free to choose any value.
71 */
72 unsigned rfs, bfs;
73 /* I2S Controller's core clock */
74 struct clk *clk;
75 /* Clock for generating I2S signals */
76 struct clk *op_clk;
Jassi Brar1c7ac012010-11-22 15:36:59 +090077 /* Pointer to the Primary_Fifo if this is Sec_Fifo, NULL otherwise */
78 struct i2s_dai *pri_dai;
79 /* Pointer to the Secondary_Fifo if it has one, NULL otherwise */
80 struct i2s_dai *sec_dai;
81#define DAI_OPENED (1 << 0) /* Dai is opened */
82#define DAI_MANAGER (1 << 1) /* Dai is the manager */
83 unsigned mode;
Sylwester Nawrockib97c60a2014-07-10 18:11:13 +020084 /* CDCLK pin direction: 0 - input, 1 - output */
85 unsigned int cdclk_out:1;
Jassi Brar1c7ac012010-11-22 15:36:59 +090086 /* Driver for this DAI */
87 struct snd_soc_dai_driver i2s_dai_drv;
88 /* DMA parameters */
89 struct s3c_dma_params dma_playback;
90 struct s3c_dma_params dma_capture;
Sangbeom Kim61100f42011-07-20 17:07:12 +090091 struct s3c_dma_params idma_playback;
Jassi Brar1c7ac012010-11-22 15:36:59 +090092 u32 quirks;
93 u32 suspend_i2smod;
94 u32 suspend_i2scon;
95 u32 suspend_i2spsr;
Padmavathi Vennaa5a56872014-11-07 12:24:40 +053096 const struct samsung_i2s_variant_regs *variant_regs;
Sylwester Nawrockif3670532015-01-14 19:42:35 +010097
98 /* Spinlock protecting access to the device's registers */
99 spinlock_t spinlock;
100 spinlock_t *lock;
Jassi Brar1c7ac012010-11-22 15:36:59 +0900101};
102
103/* Lock for cross i/f checks */
104static DEFINE_SPINLOCK(lock);
105
106/* If this is the 'overlay' stereo DAI */
107static inline bool is_secondary(struct i2s_dai *i2s)
108{
109 return i2s->pri_dai ? true : false;
110}
111
112/* If operating in SoC-Slave mode */
113static inline bool is_slave(struct i2s_dai *i2s)
114{
Padmavathi Vennaa5a56872014-11-07 12:24:40 +0530115 u32 mod = readl(i2s->addr + I2SMOD);
116 return (mod & (1 << i2s->variant_regs->mss_off)) ? true : false;
Jassi Brar1c7ac012010-11-22 15:36:59 +0900117}
118
119/* If this interface of the controller is transmitting data */
120static inline bool tx_active(struct i2s_dai *i2s)
121{
122 u32 active;
123
124 if (!i2s)
125 return false;
126
Sangbeom Kim33195502011-06-10 10:36:54 +0900127 active = readl(i2s->addr + I2SCON);
Jassi Brar1c7ac012010-11-22 15:36:59 +0900128
129 if (is_secondary(i2s))
130 active &= CON_TXSDMA_ACTIVE;
131 else
132 active &= CON_TXDMA_ACTIVE;
133
134 return active ? true : false;
135}
136
Sylwester Nawrockidcd60fc2015-01-14 19:42:33 +0100137/* Return pointer to the other DAI */
138static inline struct i2s_dai *get_other_dai(struct i2s_dai *i2s)
139{
140 return i2s->pri_dai ? : i2s->sec_dai;
141}
142
Jassi Brar1c7ac012010-11-22 15:36:59 +0900143/* If the other interface of the controller is transmitting data */
144static inline bool other_tx_active(struct i2s_dai *i2s)
145{
Sylwester Nawrockidcd60fc2015-01-14 19:42:33 +0100146 struct i2s_dai *other = get_other_dai(i2s);
Jassi Brar1c7ac012010-11-22 15:36:59 +0900147
148 return tx_active(other);
149}
150
151/* If any interface of the controller is transmitting data */
152static inline bool any_tx_active(struct i2s_dai *i2s)
153{
154 return tx_active(i2s) || other_tx_active(i2s);
155}
156
157/* If this interface of the controller is receiving data */
158static inline bool rx_active(struct i2s_dai *i2s)
159{
160 u32 active;
161
162 if (!i2s)
163 return false;
164
Sangbeom Kim33195502011-06-10 10:36:54 +0900165 active = readl(i2s->addr + I2SCON) & CON_RXDMA_ACTIVE;
Jassi Brar1c7ac012010-11-22 15:36:59 +0900166
167 return active ? true : false;
168}
169
170/* If the other interface of the controller is receiving data */
171static inline bool other_rx_active(struct i2s_dai *i2s)
172{
Sylwester Nawrockidcd60fc2015-01-14 19:42:33 +0100173 struct i2s_dai *other = get_other_dai(i2s);
Jassi Brar1c7ac012010-11-22 15:36:59 +0900174
175 return rx_active(other);
176}
177
178/* If any interface of the controller is receiving data */
179static inline bool any_rx_active(struct i2s_dai *i2s)
180{
181 return rx_active(i2s) || other_rx_active(i2s);
182}
183
184/* If the other DAI is transmitting or receiving data */
185static inline bool other_active(struct i2s_dai *i2s)
186{
187 return other_rx_active(i2s) || other_tx_active(i2s);
188}
189
190/* If this DAI is transmitting or receiving data */
191static inline bool this_active(struct i2s_dai *i2s)
192{
193 return tx_active(i2s) || rx_active(i2s);
194}
195
196/* If the controller is active anyway */
197static inline bool any_active(struct i2s_dai *i2s)
198{
199 return this_active(i2s) || other_active(i2s);
200}
201
202static inline struct i2s_dai *to_info(struct snd_soc_dai *dai)
203{
204 return snd_soc_dai_get_drvdata(dai);
205}
206
207static inline bool is_opened(struct i2s_dai *i2s)
208{
209 if (i2s && (i2s->mode & DAI_OPENED))
210 return true;
211 else
212 return false;
213}
214
215static inline bool is_manager(struct i2s_dai *i2s)
216{
217 if (is_opened(i2s) && (i2s->mode & DAI_MANAGER))
218 return true;
219 else
220 return false;
221}
222
223/* Read RCLK of I2S (in multiples of LRCLK) */
224static inline unsigned get_rfs(struct i2s_dai *i2s)
225{
Padmavathi Venna4ca0c0d2013-08-12 15:19:52 +0530226 u32 rfs;
Padmavathi Vennaa5a56872014-11-07 12:24:40 +0530227 rfs = readl(i2s->addr + I2SMOD) >> i2s->variant_regs->rfs_off;
228 rfs &= i2s->variant_regs->rfs_mask;
Jassi Brar1c7ac012010-11-22 15:36:59 +0900229
230 switch (rfs) {
Padmavathi Vennaa5a56872014-11-07 12:24:40 +0530231 case 7: return 192;
232 case 6: return 96;
233 case 5: return 128;
234 case 4: return 64;
Jassi Brar1c7ac012010-11-22 15:36:59 +0900235 case 3: return 768;
236 case 2: return 384;
237 case 1: return 512;
238 default: return 256;
239 }
240}
241
242/* Write RCLK of I2S (in multiples of LRCLK) */
243static inline void set_rfs(struct i2s_dai *i2s, unsigned rfs)
244{
245 u32 mod = readl(i2s->addr + I2SMOD);
Padmavathi Vennaa5a56872014-11-07 12:24:40 +0530246 int rfs_shift = i2s->variant_regs->rfs_off;
Jassi Brar1c7ac012010-11-22 15:36:59 +0900247
Padmavathi Vennaa5a56872014-11-07 12:24:40 +0530248 mod &= ~(i2s->variant_regs->rfs_mask << rfs_shift);
Jassi Brar1c7ac012010-11-22 15:36:59 +0900249
250 switch (rfs) {
Padmavathi Vennaa5a56872014-11-07 12:24:40 +0530251 case 192:
252 mod |= (EXYNOS7_MOD_RCLK_192FS << rfs_shift);
253 break;
254 case 96:
255 mod |= (EXYNOS7_MOD_RCLK_96FS << rfs_shift);
256 break;
257 case 128:
258 mod |= (EXYNOS7_MOD_RCLK_128FS << rfs_shift);
259 break;
260 case 64:
261 mod |= (EXYNOS7_MOD_RCLK_64FS << rfs_shift);
262 break;
Jassi Brar1c7ac012010-11-22 15:36:59 +0900263 case 768:
Padmavathi Vennab60be4a2013-07-26 19:06:48 +0530264 mod |= (MOD_RCLK_768FS << rfs_shift);
Jassi Brar1c7ac012010-11-22 15:36:59 +0900265 break;
266 case 512:
Padmavathi Vennab60be4a2013-07-26 19:06:48 +0530267 mod |= (MOD_RCLK_512FS << rfs_shift);
Jassi Brar1c7ac012010-11-22 15:36:59 +0900268 break;
269 case 384:
Padmavathi Vennab60be4a2013-07-26 19:06:48 +0530270 mod |= (MOD_RCLK_384FS << rfs_shift);
Jassi Brar1c7ac012010-11-22 15:36:59 +0900271 break;
272 default:
Padmavathi Vennab60be4a2013-07-26 19:06:48 +0530273 mod |= (MOD_RCLK_256FS << rfs_shift);
Jassi Brar1c7ac012010-11-22 15:36:59 +0900274 break;
275 }
276
277 writel(mod, i2s->addr + I2SMOD);
278}
279
280/* Read Bit-Clock of I2S (in multiples of LRCLK) */
281static inline unsigned get_bfs(struct i2s_dai *i2s)
282{
Padmavathi Venna4ca0c0d2013-08-12 15:19:52 +0530283 u32 bfs;
Padmavathi Vennaa5a56872014-11-07 12:24:40 +0530284 bfs = readl(i2s->addr + I2SMOD) >> i2s->variant_regs->bfs_off;
285 bfs &= i2s->variant_regs->bfs_mask;
Jassi Brar1c7ac012010-11-22 15:36:59 +0900286
287 switch (bfs) {
Padmavathi Venna4ca0c0d2013-08-12 15:19:52 +0530288 case 8: return 256;
289 case 7: return 192;
290 case 6: return 128;
291 case 5: return 96;
292 case 4: return 64;
Jassi Brar1c7ac012010-11-22 15:36:59 +0900293 case 3: return 24;
294 case 2: return 16;
295 case 1: return 48;
296 default: return 32;
297 }
298}
299
300/* Write Bit-Clock of I2S (in multiples of LRCLK) */
301static inline void set_bfs(struct i2s_dai *i2s, unsigned bfs)
302{
303 u32 mod = readl(i2s->addr + I2SMOD);
Padmavathi Venna4ca0c0d2013-08-12 15:19:52 +0530304 int tdm = i2s->quirks & QUIRK_SUPPORTS_TDM;
Padmavathi Vennaa5a56872014-11-07 12:24:40 +0530305 int bfs_shift = i2s->variant_regs->bfs_off;
Padmavathi Venna4ca0c0d2013-08-12 15:19:52 +0530306
307 /* Non-TDM I2S controllers do not support BCLK > 48 * FS */
308 if (!tdm && bfs > 48) {
309 dev_err(&i2s->pdev->dev, "Unsupported BCLK divider\n");
310 return;
311 }
Jassi Brar1c7ac012010-11-22 15:36:59 +0900312
Padmavathi Vennaa5a56872014-11-07 12:24:40 +0530313 mod &= ~(i2s->variant_regs->bfs_mask << bfs_shift);
314
Jassi Brar1c7ac012010-11-22 15:36:59 +0900315 switch (bfs) {
316 case 48:
Padmavathi Vennab60be4a2013-07-26 19:06:48 +0530317 mod |= (MOD_BCLK_48FS << bfs_shift);
Jassi Brar1c7ac012010-11-22 15:36:59 +0900318 break;
319 case 32:
Padmavathi Vennab60be4a2013-07-26 19:06:48 +0530320 mod |= (MOD_BCLK_32FS << bfs_shift);
Jassi Brar1c7ac012010-11-22 15:36:59 +0900321 break;
322 case 24:
Padmavathi Vennab60be4a2013-07-26 19:06:48 +0530323 mod |= (MOD_BCLK_24FS << bfs_shift);
Jassi Brar1c7ac012010-11-22 15:36:59 +0900324 break;
325 case 16:
Padmavathi Vennab60be4a2013-07-26 19:06:48 +0530326 mod |= (MOD_BCLK_16FS << bfs_shift);
Jassi Brar1c7ac012010-11-22 15:36:59 +0900327 break;
Padmavathi Venna4ca0c0d2013-08-12 15:19:52 +0530328 case 64:
329 mod |= (EXYNOS5420_MOD_BCLK_64FS << bfs_shift);
330 break;
331 case 96:
332 mod |= (EXYNOS5420_MOD_BCLK_96FS << bfs_shift);
333 break;
334 case 128:
335 mod |= (EXYNOS5420_MOD_BCLK_128FS << bfs_shift);
336 break;
337 case 192:
338 mod |= (EXYNOS5420_MOD_BCLK_192FS << bfs_shift);
339 break;
340 case 256:
341 mod |= (EXYNOS5420_MOD_BCLK_256FS << bfs_shift);
Jassi Brar1c7ac012010-11-22 15:36:59 +0900342 break;
343 default:
344 dev_err(&i2s->pdev->dev, "Wrong BCLK Divider!\n");
345 return;
346 }
347
348 writel(mod, i2s->addr + I2SMOD);
349}
350
351/* Sample-Size */
352static inline int get_blc(struct i2s_dai *i2s)
353{
354 int blc = readl(i2s->addr + I2SMOD);
355
356 blc = (blc >> 13) & 0x3;
357
358 switch (blc) {
359 case 2: return 24;
360 case 1: return 8;
361 default: return 16;
362 }
363}
364
365/* TX Channel Control */
366static void i2s_txctrl(struct i2s_dai *i2s, int on)
367{
368 void __iomem *addr = i2s->addr;
Padmavathi Vennaa5a56872014-11-07 12:24:40 +0530369 int txr_off = i2s->variant_regs->txr_off;
Jassi Brar1c7ac012010-11-22 15:36:59 +0900370 u32 con = readl(addr + I2SCON);
Padmavathi Vennaa5a56872014-11-07 12:24:40 +0530371 u32 mod = readl(addr + I2SMOD) & ~(3 << txr_off);
Jassi Brar1c7ac012010-11-22 15:36:59 +0900372
373 if (on) {
374 con |= CON_ACTIVE;
375 con &= ~CON_TXCH_PAUSE;
376
377 if (is_secondary(i2s)) {
378 con |= CON_TXSDMA_ACTIVE;
379 con &= ~CON_TXSDMA_PAUSE;
380 } else {
381 con |= CON_TXDMA_ACTIVE;
382 con &= ~CON_TXDMA_PAUSE;
383 }
384
385 if (any_rx_active(i2s))
Padmavathi Vennaa5a56872014-11-07 12:24:40 +0530386 mod |= 2 << txr_off;
Jassi Brar1c7ac012010-11-22 15:36:59 +0900387 else
Padmavathi Vennaa5a56872014-11-07 12:24:40 +0530388 mod |= 0 << txr_off;
Jassi Brar1c7ac012010-11-22 15:36:59 +0900389 } else {
390 if (is_secondary(i2s)) {
391 con |= CON_TXSDMA_PAUSE;
392 con &= ~CON_TXSDMA_ACTIVE;
393 } else {
394 con |= CON_TXDMA_PAUSE;
395 con &= ~CON_TXDMA_ACTIVE;
396 }
397
398 if (other_tx_active(i2s)) {
399 writel(con, addr + I2SCON);
400 return;
401 }
402
403 con |= CON_TXCH_PAUSE;
404
405 if (any_rx_active(i2s))
Padmavathi Vennaa5a56872014-11-07 12:24:40 +0530406 mod |= 1 << txr_off;
Jassi Brar1c7ac012010-11-22 15:36:59 +0900407 else
408 con &= ~CON_ACTIVE;
409 }
410
411 writel(mod, addr + I2SMOD);
412 writel(con, addr + I2SCON);
413}
414
415/* RX Channel Control */
416static void i2s_rxctrl(struct i2s_dai *i2s, int on)
417{
418 void __iomem *addr = i2s->addr;
Padmavathi Vennaa5a56872014-11-07 12:24:40 +0530419 int txr_off = i2s->variant_regs->txr_off;
Jassi Brar1c7ac012010-11-22 15:36:59 +0900420 u32 con = readl(addr + I2SCON);
Padmavathi Vennaa5a56872014-11-07 12:24:40 +0530421 u32 mod = readl(addr + I2SMOD) & ~(3 << txr_off);
Jassi Brar1c7ac012010-11-22 15:36:59 +0900422
423 if (on) {
424 con |= CON_RXDMA_ACTIVE | CON_ACTIVE;
425 con &= ~(CON_RXDMA_PAUSE | CON_RXCH_PAUSE);
426
427 if (any_tx_active(i2s))
Padmavathi Vennaa5a56872014-11-07 12:24:40 +0530428 mod |= 2 << txr_off;
Jassi Brar1c7ac012010-11-22 15:36:59 +0900429 else
Padmavathi Vennaa5a56872014-11-07 12:24:40 +0530430 mod |= 1 << txr_off;
Jassi Brar1c7ac012010-11-22 15:36:59 +0900431 } else {
432 con |= CON_RXDMA_PAUSE | CON_RXCH_PAUSE;
433 con &= ~CON_RXDMA_ACTIVE;
434
435 if (any_tx_active(i2s))
Padmavathi Vennaa5a56872014-11-07 12:24:40 +0530436 mod |= 0 << txr_off;
Jassi Brar1c7ac012010-11-22 15:36:59 +0900437 else
438 con &= ~CON_ACTIVE;
439 }
440
441 writel(mod, addr + I2SMOD);
442 writel(con, addr + I2SCON);
443}
444
445/* Flush FIFO of an interface */
446static inline void i2s_fifo(struct i2s_dai *i2s, u32 flush)
447{
448 void __iomem *fic;
449 u32 val;
450
451 if (!i2s)
452 return;
453
454 if (is_secondary(i2s))
455 fic = i2s->addr + I2SFICS;
456 else
457 fic = i2s->addr + I2SFIC;
458
459 /* Flush the FIFO */
460 writel(readl(fic) | flush, fic);
461
462 /* Be patient */
463 val = msecs_to_loops(1) / 1000; /* 1 usec */
464 while (--val)
465 cpu_relax();
466
467 writel(readl(fic) & ~flush, fic);
468}
469
470static int i2s_set_sysclk(struct snd_soc_dai *dai,
471 int clk_id, unsigned int rfs, int dir)
472{
473 struct i2s_dai *i2s = to_info(dai);
Sylwester Nawrockidcd60fc2015-01-14 19:42:33 +0100474 struct i2s_dai *other = get_other_dai(i2s);
Jassi Brar1c7ac012010-11-22 15:36:59 +0900475 u32 mod = readl(i2s->addr + I2SMOD);
Padmavathi Vennaa5a56872014-11-07 12:24:40 +0530476 const struct samsung_i2s_variant_regs *i2s_regs = i2s->variant_regs;
477 unsigned int cdcon_mask = 1 << i2s_regs->cdclkcon_off;
478 unsigned int rsrc_mask = 1 << i2s_regs->rclksrc_off;
Jassi Brar1c7ac012010-11-22 15:36:59 +0900479
480 switch (clk_id) {
Sylwester Nawrockic86d50f2014-05-19 19:30:38 +0200481 case SAMSUNG_I2S_OPCLK:
482 mod &= ~MOD_OPCLK_MASK;
483 mod |= dir;
484 break;
Jassi Brar1c7ac012010-11-22 15:36:59 +0900485 case SAMSUNG_I2S_CDCLK:
486 /* Shouldn't matter in GATING(CLOCK_IN) mode */
487 if (dir == SND_SOC_CLOCK_IN)
488 rfs = 0;
489
Charles Keepax133c2682014-09-09 16:51:49 +0100490 if ((rfs && other && other->rfs && (other->rfs != rfs)) ||
Jassi Brar1c7ac012010-11-22 15:36:59 +0900491 (any_active(i2s) &&
492 (((dir == SND_SOC_CLOCK_IN)
Padmavathi Vennaa5a56872014-11-07 12:24:40 +0530493 && !(mod & cdcon_mask)) ||
Jassi Brar1c7ac012010-11-22 15:36:59 +0900494 ((dir == SND_SOC_CLOCK_OUT)
Padmavathi Vennaa5a56872014-11-07 12:24:40 +0530495 && (mod & cdcon_mask))))) {
Jassi Brar1c7ac012010-11-22 15:36:59 +0900496 dev_err(&i2s->pdev->dev,
497 "%s:%d Other DAI busy\n", __func__, __LINE__);
498 return -EAGAIN;
499 }
500
501 if (dir == SND_SOC_CLOCK_IN)
Padmavathi Vennaa5a56872014-11-07 12:24:40 +0530502 mod |= 1 << i2s_regs->cdclkcon_off;
Jassi Brar1c7ac012010-11-22 15:36:59 +0900503 else
Padmavathi Vennab2de1d22014-11-20 15:33:17 +0530504 mod &= ~(1 << i2s_regs->cdclkcon_off);
Jassi Brar1c7ac012010-11-22 15:36:59 +0900505
506 i2s->rfs = rfs;
507 break;
508
509 case SAMSUNG_I2S_RCLKSRC_0: /* clock corrsponding to IISMOD[10] := 0 */
510 case SAMSUNG_I2S_RCLKSRC_1: /* clock corrsponding to IISMOD[10] := 1 */
511 if ((i2s->quirks & QUIRK_NO_MUXPSR)
512 || (clk_id == SAMSUNG_I2S_RCLKSRC_0))
513 clk_id = 0;
514 else
515 clk_id = 1;
516
517 if (!any_active(i2s)) {
Sylwester Nawrockia6aba532014-05-22 12:10:52 +0200518 if (i2s->op_clk && !IS_ERR(i2s->op_clk)) {
Padmavathi Vennaa5a56872014-11-07 12:24:40 +0530519 if ((clk_id && !(mod & rsrc_mask)) ||
520 (!clk_id && (mod & rsrc_mask))) {
Thomas Abraham98614cf2012-10-03 08:46:58 +0900521 clk_disable_unprepare(i2s->op_clk);
Jassi Brar1c7ac012010-11-22 15:36:59 +0900522 clk_put(i2s->op_clk);
523 } else {
Jassi Brar6ce534a2010-12-20 11:05:46 +0900524 i2s->rclk_srcrate =
525 clk_get_rate(i2s->op_clk);
Jassi Brar1c7ac012010-11-22 15:36:59 +0900526 return 0;
527 }
528 }
529
Padmavathi Venna1974a042012-11-28 16:17:48 +0530530 if (clk_id)
531 i2s->op_clk = clk_get(&i2s->pdev->dev,
532 "i2s_opclk1");
533 else
534 i2s->op_clk = clk_get(&i2s->pdev->dev,
535 "i2s_opclk0");
Sylwester Nawrockia6aba532014-05-22 12:10:52 +0200536
537 if (WARN_ON(IS_ERR(i2s->op_clk)))
538 return PTR_ERR(i2s->op_clk);
539
Thomas Abraham98614cf2012-10-03 08:46:58 +0900540 clk_prepare_enable(i2s->op_clk);
Jassi Brar1c7ac012010-11-22 15:36:59 +0900541 i2s->rclk_srcrate = clk_get_rate(i2s->op_clk);
542
543 /* Over-ride the other's */
544 if (other) {
545 other->op_clk = i2s->op_clk;
546 other->rclk_srcrate = i2s->rclk_srcrate;
547 }
Padmavathi Vennaa5a56872014-11-07 12:24:40 +0530548 } else if ((!clk_id && (mod & rsrc_mask))
549 || (clk_id && !(mod & rsrc_mask))) {
Jassi Brar1c7ac012010-11-22 15:36:59 +0900550 dev_err(&i2s->pdev->dev,
551 "%s:%d Other DAI busy\n", __func__, __LINE__);
552 return -EAGAIN;
553 } else {
554 /* Call can't be on the active DAI */
555 i2s->op_clk = other->op_clk;
556 i2s->rclk_srcrate = other->rclk_srcrate;
557 return 0;
558 }
559
560 if (clk_id == 0)
Padmavathi Vennab2de1d22014-11-20 15:33:17 +0530561 mod &= ~(1 << i2s_regs->rclksrc_off);
Jassi Brar1c7ac012010-11-22 15:36:59 +0900562 else
Padmavathi Vennaa5a56872014-11-07 12:24:40 +0530563 mod |= 1 << i2s_regs->rclksrc_off;
Jassi Brar1c7ac012010-11-22 15:36:59 +0900564
Padmavathi Vennab2de1d22014-11-20 15:33:17 +0530565 break;
Jassi Brar1c7ac012010-11-22 15:36:59 +0900566 default:
567 dev_err(&i2s->pdev->dev, "We don't serve that!\n");
568 return -EINVAL;
569 }
570
571 writel(mod, i2s->addr + I2SMOD);
572
573 return 0;
574}
575
576static int i2s_set_fmt(struct snd_soc_dai *dai,
577 unsigned int fmt)
578{
579 struct i2s_dai *i2s = to_info(dai);
580 u32 mod = readl(i2s->addr + I2SMOD);
Padmavathi Vennaa5a56872014-11-07 12:24:40 +0530581 int lrp_shift, sdf_shift, sdf_mask, lrp_rlow, mod_slave;
Jassi Brar1c7ac012010-11-22 15:36:59 +0900582 u32 tmp = 0;
583
Padmavathi Vennaa5a56872014-11-07 12:24:40 +0530584 lrp_shift = i2s->variant_regs->lrp_off;
585 sdf_shift = i2s->variant_regs->sdf_off;
586 mod_slave = 1 << i2s->variant_regs->mss_off;
Padmavathi Venna4ca0c0d2013-08-12 15:19:52 +0530587
Padmavathi Vennab60be4a2013-07-26 19:06:48 +0530588 sdf_mask = MOD_SDF_MASK << sdf_shift;
589 lrp_rlow = MOD_LR_RLOW << lrp_shift;
590
Jassi Brar1c7ac012010-11-22 15:36:59 +0900591 /* Format is priority */
592 switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
593 case SND_SOC_DAIFMT_RIGHT_J:
Padmavathi Vennab60be4a2013-07-26 19:06:48 +0530594 tmp |= lrp_rlow;
595 tmp |= (MOD_SDF_MSB << sdf_shift);
Jassi Brar1c7ac012010-11-22 15:36:59 +0900596 break;
597 case SND_SOC_DAIFMT_LEFT_J:
Padmavathi Vennab60be4a2013-07-26 19:06:48 +0530598 tmp |= lrp_rlow;
599 tmp |= (MOD_SDF_LSB << sdf_shift);
Jassi Brar1c7ac012010-11-22 15:36:59 +0900600 break;
601 case SND_SOC_DAIFMT_I2S:
Padmavathi Vennab60be4a2013-07-26 19:06:48 +0530602 tmp |= (MOD_SDF_IIS << sdf_shift);
Jassi Brar1c7ac012010-11-22 15:36:59 +0900603 break;
604 default:
605 dev_err(&i2s->pdev->dev, "Format not supported\n");
606 return -EINVAL;
607 }
608
609 /*
610 * INV flag is relative to the FORMAT flag - if set it simply
611 * flips the polarity specified by the Standard
612 */
613 switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
614 case SND_SOC_DAIFMT_NB_NF:
615 break;
616 case SND_SOC_DAIFMT_NB_IF:
Padmavathi Vennab60be4a2013-07-26 19:06:48 +0530617 if (tmp & lrp_rlow)
618 tmp &= ~lrp_rlow;
Jassi Brar1c7ac012010-11-22 15:36:59 +0900619 else
Padmavathi Vennab60be4a2013-07-26 19:06:48 +0530620 tmp |= lrp_rlow;
Jassi Brar1c7ac012010-11-22 15:36:59 +0900621 break;
622 default:
623 dev_err(&i2s->pdev->dev, "Polarity not supported\n");
624 return -EINVAL;
625 }
626
627 switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
628 case SND_SOC_DAIFMT_CBM_CFM:
Padmavathi Vennaa5a56872014-11-07 12:24:40 +0530629 tmp |= mod_slave;
Jassi Brar1c7ac012010-11-22 15:36:59 +0900630 break;
631 case SND_SOC_DAIFMT_CBS_CFS:
632 /* Set default source clock in Master mode */
633 if (i2s->rclk_srcrate == 0)
634 i2s_set_sysclk(dai, SAMSUNG_I2S_RCLKSRC_0,
635 0, SND_SOC_CLOCK_IN);
636 break;
637 default:
638 dev_err(&i2s->pdev->dev, "master/slave format not supported\n");
639 return -EINVAL;
640 }
641
Padmavathi Vennab60be4a2013-07-26 19:06:48 +0530642 /*
643 * Don't change the I2S mode if any controller is active on this
644 * channel.
645 */
Jassi Brar1c7ac012010-11-22 15:36:59 +0900646 if (any_active(i2s) &&
Padmavathi Vennaa5a56872014-11-07 12:24:40 +0530647 ((mod & (sdf_mask | lrp_rlow | mod_slave)) != tmp)) {
Jassi Brar1c7ac012010-11-22 15:36:59 +0900648 dev_err(&i2s->pdev->dev,
649 "%s:%d Other DAI busy\n", __func__, __LINE__);
650 return -EAGAIN;
651 }
652
Padmavathi Vennaa5a56872014-11-07 12:24:40 +0530653 mod &= ~(sdf_mask | lrp_rlow | mod_slave);
Jassi Brar1c7ac012010-11-22 15:36:59 +0900654 mod |= tmp;
655 writel(mod, i2s->addr + I2SMOD);
656
657 return 0;
658}
659
660static int i2s_hw_params(struct snd_pcm_substream *substream,
661 struct snd_pcm_hw_params *params, struct snd_soc_dai *dai)
662{
663 struct i2s_dai *i2s = to_info(dai);
664 u32 mod = readl(i2s->addr + I2SMOD);
665
666 if (!is_secondary(i2s))
667 mod &= ~(MOD_DC2_EN | MOD_DC1_EN);
668
669 switch (params_channels(params)) {
670 case 6:
671 mod |= MOD_DC2_EN;
672 case 4:
673 mod |= MOD_DC1_EN;
674 break;
675 case 2:
Sangsu Park588fb702012-03-16 15:40:53 +0900676 if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
677 i2s->dma_playback.dma_size = 4;
678 else
679 i2s->dma_capture.dma_size = 4;
680 break;
681 case 1:
682 if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
683 i2s->dma_playback.dma_size = 2;
684 else
685 i2s->dma_capture.dma_size = 2;
686
Jassi Brar1c7ac012010-11-22 15:36:59 +0900687 break;
688 default:
689 dev_err(&i2s->pdev->dev, "%d channels not supported\n",
690 params_channels(params));
691 return -EINVAL;
692 }
693
694 if (is_secondary(i2s))
695 mod &= ~MOD_BLCS_MASK;
696 else
697 mod &= ~MOD_BLCP_MASK;
698
699 if (is_manager(i2s))
700 mod &= ~MOD_BLC_MASK;
701
Tushar Behera88ce1462014-05-23 17:35:39 +0530702 switch (params_width(params)) {
703 case 8:
Jassi Brar1c7ac012010-11-22 15:36:59 +0900704 if (is_secondary(i2s))
705 mod |= MOD_BLCS_8BIT;
706 else
707 mod |= MOD_BLCP_8BIT;
708 if (is_manager(i2s))
709 mod |= MOD_BLC_8BIT;
710 break;
Tushar Behera88ce1462014-05-23 17:35:39 +0530711 case 16:
Jassi Brar1c7ac012010-11-22 15:36:59 +0900712 if (is_secondary(i2s))
713 mod |= MOD_BLCS_16BIT;
714 else
715 mod |= MOD_BLCP_16BIT;
716 if (is_manager(i2s))
717 mod |= MOD_BLC_16BIT;
718 break;
Tushar Behera88ce1462014-05-23 17:35:39 +0530719 case 24:
Jassi Brar1c7ac012010-11-22 15:36:59 +0900720 if (is_secondary(i2s))
721 mod |= MOD_BLCS_24BIT;
722 else
723 mod |= MOD_BLCP_24BIT;
724 if (is_manager(i2s))
725 mod |= MOD_BLC_24BIT;
726 break;
727 default:
728 dev_err(&i2s->pdev->dev, "Format(%d) not supported\n",
729 params_format(params));
730 return -EINVAL;
731 }
732 writel(mod, i2s->addr + I2SMOD);
733
Mark Brownd37bdf72013-12-05 14:14:52 +0000734 samsung_asoc_init_dma_data(dai, &i2s->dma_playback, &i2s->dma_capture);
735
Jassi Brar1c7ac012010-11-22 15:36:59 +0900736 i2s->frmclk = params_rate(params);
737
738 return 0;
739}
740
741/* We set constraints on the substream acc to the version of I2S */
742static int i2s_startup(struct snd_pcm_substream *substream,
743 struct snd_soc_dai *dai)
744{
745 struct i2s_dai *i2s = to_info(dai);
Sylwester Nawrockidcd60fc2015-01-14 19:42:33 +0100746 struct i2s_dai *other = get_other_dai(i2s);
Jassi Brar1c7ac012010-11-22 15:36:59 +0900747 unsigned long flags;
748
749 spin_lock_irqsave(&lock, flags);
750
751 i2s->mode |= DAI_OPENED;
752
753 if (is_manager(other))
754 i2s->mode &= ~DAI_MANAGER;
755 else
756 i2s->mode |= DAI_MANAGER;
757
Padmavathi Venna2d778282013-01-24 18:05:31 +0530758 if (!any_active(i2s) && (i2s->quirks & QUIRK_NEED_RSTCLR))
759 writel(CON_RSTCLR, i2s->addr + I2SCON);
760
Jassi Brar1c7ac012010-11-22 15:36:59 +0900761 spin_unlock_irqrestore(&lock, flags);
762
Sylwester Nawrockib97c60a2014-07-10 18:11:13 +0200763 if (!is_opened(other) && i2s->cdclk_out)
764 i2s_set_sysclk(dai, SAMSUNG_I2S_CDCLK,
765 0, SND_SOC_CLOCK_OUT);
Jassi Brar1c7ac012010-11-22 15:36:59 +0900766 return 0;
767}
768
769static void i2s_shutdown(struct snd_pcm_substream *substream,
770 struct snd_soc_dai *dai)
771{
772 struct i2s_dai *i2s = to_info(dai);
Sylwester Nawrockidcd60fc2015-01-14 19:42:33 +0100773 struct i2s_dai *other = get_other_dai(i2s);
Jassi Brar1c7ac012010-11-22 15:36:59 +0900774 unsigned long flags;
Padmavathi Vennaa5a56872014-11-07 12:24:40 +0530775 const struct samsung_i2s_variant_regs *i2s_regs = i2s->variant_regs;
Jassi Brar1c7ac012010-11-22 15:36:59 +0900776
777 spin_lock_irqsave(&lock, flags);
778
779 i2s->mode &= ~DAI_OPENED;
780 i2s->mode &= ~DAI_MANAGER;
781
Sylwester Nawrockib97c60a2014-07-10 18:11:13 +0200782 if (is_opened(other)) {
Jassi Brar1c7ac012010-11-22 15:36:59 +0900783 other->mode |= DAI_MANAGER;
Sylwester Nawrockib97c60a2014-07-10 18:11:13 +0200784 } else {
785 u32 mod = readl(i2s->addr + I2SMOD);
Padmavathi Vennaa5a56872014-11-07 12:24:40 +0530786 i2s->cdclk_out = !(mod & (1 << i2s_regs->cdclkcon_off));
Charles Keepax133c2682014-09-09 16:51:49 +0100787 if (other)
788 other->cdclk_out = i2s->cdclk_out;
Sylwester Nawrockib97c60a2014-07-10 18:11:13 +0200789 }
Jassi Brar1c7ac012010-11-22 15:36:59 +0900790 /* Reset any constraint on RFS and BFS */
791 i2s->rfs = 0;
792 i2s->bfs = 0;
793
794 spin_unlock_irqrestore(&lock, flags);
795
796 /* Gate CDCLK by default */
797 if (!is_opened(other))
798 i2s_set_sysclk(dai, SAMSUNG_I2S_CDCLK,
799 0, SND_SOC_CLOCK_IN);
800}
801
802static int config_setup(struct i2s_dai *i2s)
803{
Sylwester Nawrockidcd60fc2015-01-14 19:42:33 +0100804 struct i2s_dai *other = get_other_dai(i2s);
Jassi Brar1c7ac012010-11-22 15:36:59 +0900805 unsigned rfs, bfs, blc;
806 u32 psr;
807
808 blc = get_blc(i2s);
809
810 bfs = i2s->bfs;
811
812 if (!bfs && other)
813 bfs = other->bfs;
814
815 /* Select least possible multiple(2) if no constraint set */
816 if (!bfs)
817 bfs = blc * 2;
818
819 rfs = i2s->rfs;
820
821 if (!rfs && other)
822 rfs = other->rfs;
823
824 if ((rfs == 256 || rfs == 512) && (blc == 24)) {
825 dev_err(&i2s->pdev->dev,
826 "%d-RFS not supported for 24-blc\n", rfs);
827 return -EINVAL;
828 }
829
830 if (!rfs) {
831 if (bfs == 16 || bfs == 32)
832 rfs = 256;
833 else
834 rfs = 384;
835 }
836
837 /* If already setup and running */
838 if (any_active(i2s) && (get_rfs(i2s) != rfs || get_bfs(i2s) != bfs)) {
839 dev_err(&i2s->pdev->dev,
840 "%s:%d Other DAI busy\n", __func__, __LINE__);
841 return -EAGAIN;
842 }
843
Jassi Brar1c7ac012010-11-22 15:36:59 +0900844 set_bfs(i2s, bfs);
845 set_rfs(i2s, rfs);
846
Padmavathi Venna77010012013-07-11 12:38:25 +0530847 /* Don't bother with PSR in Slave mode */
848 if (is_slave(i2s))
849 return 0;
850
Jassi Brar1c7ac012010-11-22 15:36:59 +0900851 if (!(i2s->quirks & QUIRK_NO_MUXPSR)) {
852 psr = i2s->rclk_srcrate / i2s->frmclk / rfs;
853 writel(((psr - 1) << 8) | PSR_PSREN, i2s->addr + I2SPSR);
854 dev_dbg(&i2s->pdev->dev,
855 "RCLK_SRC=%luHz PSR=%u, RCLK=%dfs, BCLK=%dfs\n",
856 i2s->rclk_srcrate, psr, rfs, bfs);
857 }
858
859 return 0;
860}
861
862static int i2s_trigger(struct snd_pcm_substream *substream,
863 int cmd, struct snd_soc_dai *dai)
864{
865 int capture = (substream->stream == SNDRV_PCM_STREAM_CAPTURE);
866 struct snd_soc_pcm_runtime *rtd = substream->private_data;
867 struct i2s_dai *i2s = to_info(rtd->cpu_dai);
868 unsigned long flags;
869
870 switch (cmd) {
871 case SNDRV_PCM_TRIGGER_START:
872 case SNDRV_PCM_TRIGGER_RESUME:
873 case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
Sylwester Nawrockif3670532015-01-14 19:42:35 +0100874 spin_lock_irqsave(i2s->lock, flags);
Jassi Brar1c7ac012010-11-22 15:36:59 +0900875
Jassi Brar1c7ac012010-11-22 15:36:59 +0900876 if (config_setup(i2s)) {
Sylwester Nawrockif3670532015-01-14 19:42:35 +0100877 spin_unlock_irqrestore(i2s->lock, flags);
Jassi Brar1c7ac012010-11-22 15:36:59 +0900878 return -EINVAL;
879 }
880
881 if (capture)
882 i2s_rxctrl(i2s, 1);
883 else
884 i2s_txctrl(i2s, 1);
885
Sylwester Nawrockif3670532015-01-14 19:42:35 +0100886 spin_unlock_irqrestore(i2s->lock, flags);
Jassi Brar1c7ac012010-11-22 15:36:59 +0900887 break;
888 case SNDRV_PCM_TRIGGER_STOP:
889 case SNDRV_PCM_TRIGGER_SUSPEND:
890 case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
Sylwester Nawrockif3670532015-01-14 19:42:35 +0100891 spin_lock_irqsave(i2s->lock, flags);
Jassi Brar1c7ac012010-11-22 15:36:59 +0900892
Jassi Brarc90887f2012-02-25 16:42:34 +0530893 if (capture) {
Jassi Brar1c7ac012010-11-22 15:36:59 +0900894 i2s_rxctrl(i2s, 0);
Jassi Brar775bc972010-12-20 11:05:47 +0900895 i2s_fifo(i2s, FIC_RXFLUSH);
Jassi Brarc90887f2012-02-25 16:42:34 +0530896 } else {
897 i2s_txctrl(i2s, 0);
Jassi Brar775bc972010-12-20 11:05:47 +0900898 i2s_fifo(i2s, FIC_TXFLUSH);
Jassi Brarc90887f2012-02-25 16:42:34 +0530899 }
Jassi Brar775bc972010-12-20 11:05:47 +0900900
Sylwester Nawrockif3670532015-01-14 19:42:35 +0100901 spin_unlock_irqrestore(i2s->lock, flags);
Jassi Brar1c7ac012010-11-22 15:36:59 +0900902 break;
903 }
904
905 return 0;
906}
907
908static int i2s_set_clkdiv(struct snd_soc_dai *dai,
909 int div_id, int div)
910{
911 struct i2s_dai *i2s = to_info(dai);
Sylwester Nawrockidcd60fc2015-01-14 19:42:33 +0100912 struct i2s_dai *other = get_other_dai(i2s);
Jassi Brar1c7ac012010-11-22 15:36:59 +0900913
914 switch (div_id) {
915 case SAMSUNG_I2S_DIV_BCLK:
916 if ((any_active(i2s) && div && (get_bfs(i2s) != div))
917 || (other && other->bfs && (other->bfs != div))) {
918 dev_err(&i2s->pdev->dev,
919 "%s:%d Other DAI busy\n", __func__, __LINE__);
920 return -EAGAIN;
921 }
922 i2s->bfs = div;
923 break;
924 default:
925 dev_err(&i2s->pdev->dev,
926 "Invalid clock divider(%d)\n", div_id);
927 return -EINVAL;
928 }
929
930 return 0;
931}
932
933static snd_pcm_sframes_t
934i2s_delay(struct snd_pcm_substream *substream, struct snd_soc_dai *dai)
935{
936 struct i2s_dai *i2s = to_info(dai);
937 u32 reg = readl(i2s->addr + I2SFIC);
938 snd_pcm_sframes_t delay;
Padmavathi Vennaa5a56872014-11-07 12:24:40 +0530939 const struct samsung_i2s_variant_regs *i2s_regs = i2s->variant_regs;
Jassi Brar1c7ac012010-11-22 15:36:59 +0900940
941 if (substream->stream == SNDRV_PCM_STREAM_CAPTURE)
942 delay = FIC_RXCOUNT(reg);
943 else if (is_secondary(i2s))
944 delay = FICS_TXCOUNT(readl(i2s->addr + I2SFICS));
945 else
Padmavathi Vennaa5a56872014-11-07 12:24:40 +0530946 delay = (reg >> i2s_regs->ftx0cnt_off) & 0x7f;
Jassi Brar1c7ac012010-11-22 15:36:59 +0900947
948 return delay;
949}
950
951#ifdef CONFIG_PM
952static int i2s_suspend(struct snd_soc_dai *dai)
953{
954 struct i2s_dai *i2s = to_info(dai);
955
Sylwester Nawrockid3d4e522014-07-04 16:05:45 +0200956 i2s->suspend_i2smod = readl(i2s->addr + I2SMOD);
957 i2s->suspend_i2scon = readl(i2s->addr + I2SCON);
958 i2s->suspend_i2spsr = readl(i2s->addr + I2SPSR);
Jassi Brar1c7ac012010-11-22 15:36:59 +0900959
960 return 0;
961}
962
963static int i2s_resume(struct snd_soc_dai *dai)
964{
965 struct i2s_dai *i2s = to_info(dai);
966
Sylwester Nawrockid3d4e522014-07-04 16:05:45 +0200967 writel(i2s->suspend_i2scon, i2s->addr + I2SCON);
968 writel(i2s->suspend_i2smod, i2s->addr + I2SMOD);
969 writel(i2s->suspend_i2spsr, i2s->addr + I2SPSR);
Jassi Brar1c7ac012010-11-22 15:36:59 +0900970
971 return 0;
972}
973#else
974#define i2s_suspend NULL
975#define i2s_resume NULL
976#endif
977
978static int samsung_i2s_dai_probe(struct snd_soc_dai *dai)
979{
980 struct i2s_dai *i2s = to_info(dai);
Sylwester Nawrockidcd60fc2015-01-14 19:42:33 +0100981 struct i2s_dai *other = get_other_dai(i2s);
Jassi Brar1c7ac012010-11-22 15:36:59 +0900982
Sylwester Nawrocki0ec2ba82015-01-14 19:42:31 +0100983 if (is_secondary(i2s)) { /* If this is probe on the secondary DAI */
Mark Brown36885692013-10-19 15:23:15 +0100984 samsung_asoc_init_dma_data(dai, &other->sec_dai->dma_playback,
985 NULL);
Sylwester Nawrocki872c26b2015-01-14 19:42:34 +0100986 } else {
987 samsung_asoc_init_dma_data(dai, &i2s->dma_playback,
988 &i2s->dma_capture);
989
990 if (i2s->quirks & QUIRK_NEED_RSTCLR)
991 writel(CON_RSTCLR, i2s->addr + I2SCON);
992
993 if (i2s->quirks & QUIRK_SUPPORTS_IDMA)
994 idma_reg_addr_init(i2s->addr,
995 i2s->sec_dai->idma_playback.dma_addr);
Mark Brown36885692013-10-19 15:23:15 +0100996 }
Jassi Brar1c7ac012010-11-22 15:36:59 +0900997
Jassi Brar1c7ac012010-11-22 15:36:59 +0900998 /* Reset any constraint on RFS and BFS */
999 i2s->rfs = 0;
1000 i2s->bfs = 0;
Tushar Beherad66eac32014-04-23 13:34:24 +05301001 i2s->rclk_srcrate = 0;
Jassi Brar1c7ac012010-11-22 15:36:59 +09001002 i2s_txctrl(i2s, 0);
1003 i2s_rxctrl(i2s, 0);
1004 i2s_fifo(i2s, FIC_TXFLUSH);
1005 i2s_fifo(other, FIC_TXFLUSH);
1006 i2s_fifo(i2s, FIC_RXFLUSH);
1007
1008 /* Gate CDCLK by default */
1009 if (!is_opened(other))
1010 i2s_set_sysclk(dai, SAMSUNG_I2S_CDCLK,
1011 0, SND_SOC_CLOCK_IN);
1012
1013 return 0;
1014}
1015
1016static int samsung_i2s_dai_remove(struct snd_soc_dai *dai)
1017{
1018 struct i2s_dai *i2s = snd_soc_dai_get_drvdata(dai);
Jassi Brar1c7ac012010-11-22 15:36:59 +09001019
Sylwester Nawrockic92f1d02015-01-14 19:42:32 +01001020 if (!is_secondary(i2s)) {
Jassi Brar1c7ac012010-11-22 15:36:59 +09001021 if (i2s->quirks & QUIRK_NEED_RSTCLR)
1022 writel(0, i2s->addr + I2SCON);
Jassi Brar1c7ac012010-11-22 15:36:59 +09001023 }
1024
Jassi Brar1c7ac012010-11-22 15:36:59 +09001025 return 0;
1026}
1027
Lars-Peter Clausen85e76522011-11-23 11:40:40 +01001028static const struct snd_soc_dai_ops samsung_i2s_dai_ops = {
Jassi Brar1c7ac012010-11-22 15:36:59 +09001029 .trigger = i2s_trigger,
1030 .hw_params = i2s_hw_params,
1031 .set_fmt = i2s_set_fmt,
1032 .set_clkdiv = i2s_set_clkdiv,
1033 .set_sysclk = i2s_set_sysclk,
1034 .startup = i2s_startup,
1035 .shutdown = i2s_shutdown,
1036 .delay = i2s_delay,
1037};
1038
Kuninori Morimoto4b828532013-03-21 03:35:55 -07001039static const struct snd_soc_component_driver samsung_i2s_component = {
1040 .name = "samsung-i2s",
1041};
1042
Jassi Brar1c7ac012010-11-22 15:36:59 +09001043#define SAMSUNG_I2S_RATES SNDRV_PCM_RATE_8000_96000
1044
1045#define SAMSUNG_I2S_FMTS (SNDRV_PCM_FMTBIT_S8 | \
1046 SNDRV_PCM_FMTBIT_S16_LE | \
1047 SNDRV_PCM_FMTBIT_S24_LE)
1048
Bill Pembertonfdca21a2012-12-07 09:26:15 -05001049static struct i2s_dai *i2s_alloc_dai(struct platform_device *pdev, bool sec)
Jassi Brar1c7ac012010-11-22 15:36:59 +09001050{
1051 struct i2s_dai *i2s;
Prathyush Kc6f9b1e2013-04-02 16:53:02 +05301052 int ret;
Jassi Brar1c7ac012010-11-22 15:36:59 +09001053
Mark Brownb960ce72011-12-03 20:30:37 +00001054 i2s = devm_kzalloc(&pdev->dev, sizeof(struct i2s_dai), GFP_KERNEL);
Jassi Brar1c7ac012010-11-22 15:36:59 +09001055 if (i2s == NULL)
1056 return NULL;
1057
1058 i2s->pdev = pdev;
1059 i2s->pri_dai = NULL;
1060 i2s->sec_dai = NULL;
1061 i2s->i2s_dai_drv.symmetric_rates = 1;
1062 i2s->i2s_dai_drv.probe = samsung_i2s_dai_probe;
1063 i2s->i2s_dai_drv.remove = samsung_i2s_dai_remove;
1064 i2s->i2s_dai_drv.ops = &samsung_i2s_dai_ops;
1065 i2s->i2s_dai_drv.suspend = i2s_suspend;
1066 i2s->i2s_dai_drv.resume = i2s_resume;
Charles Keepaxa0ff6ea2013-09-11 15:27:29 +01001067 i2s->i2s_dai_drv.playback.channels_min = 1;
Jassi Brar1c7ac012010-11-22 15:36:59 +09001068 i2s->i2s_dai_drv.playback.channels_max = 2;
1069 i2s->i2s_dai_drv.playback.rates = SAMSUNG_I2S_RATES;
1070 i2s->i2s_dai_drv.playback.formats = SAMSUNG_I2S_FMTS;
1071
1072 if (!sec) {
Sangsu Park588fb702012-03-16 15:40:53 +09001073 i2s->i2s_dai_drv.capture.channels_min = 1;
Jassi Brar1c7ac012010-11-22 15:36:59 +09001074 i2s->i2s_dai_drv.capture.channels_max = 2;
1075 i2s->i2s_dai_drv.capture.rates = SAMSUNG_I2S_RATES;
1076 i2s->i2s_dai_drv.capture.formats = SAMSUNG_I2S_FMTS;
Prathyush Kc6f9b1e2013-04-02 16:53:02 +05301077 dev_set_drvdata(&i2s->pdev->dev, i2s);
Jassi Brar1c7ac012010-11-22 15:36:59 +09001078 } else { /* Create a new platform_device for Secondary */
Prathyush Kc6f9b1e2013-04-02 16:53:02 +05301079 i2s->pdev = platform_device_alloc("samsung-i2s-sec", -1);
Wei Yongjun29ca9c72013-10-25 17:06:24 +08001080 if (!i2s->pdev)
Jassi Brar1c7ac012010-11-22 15:36:59 +09001081 return NULL;
Jassi Brar1c7ac012010-11-22 15:36:59 +09001082
Mark Brown2f6f0ff2013-08-01 11:02:47 +01001083 i2s->pdev->dev.parent = &pdev->dev;
1084
Prathyush Kc6f9b1e2013-04-02 16:53:02 +05301085 platform_set_drvdata(i2s->pdev, i2s);
1086 ret = platform_device_add(i2s->pdev);
1087 if (ret < 0)
1088 return NULL;
1089 }
Jassi Brar1c7ac012010-11-22 15:36:59 +09001090
1091 return i2s;
1092}
1093
Padmavathi Venna40476f62013-01-18 17:17:01 +05301094static const struct of_device_id exynos_i2s_match[];
1095
Padmavathi Venna7da493e2013-08-12 15:19:51 +05301096static inline const struct samsung_i2s_dai_data *samsung_i2s_get_driver_data(
1097 struct platform_device *pdev)
Padmavathi Venna7c62eeb2013-01-18 17:17:00 +05301098{
Sylwester Nawrocki9cf24742015-01-14 19:42:28 +01001099 if (IS_ENABLED(CONFIG_OF) && pdev->dev.of_node) {
Padmavathi Venna40476f62013-01-18 17:17:01 +05301100 const struct of_device_id *match;
1101 match = of_match_node(exynos_i2s_match, pdev->dev.of_node);
Sylwester Nawrocki9cf24742015-01-14 19:42:28 +01001102 return match ? match->data : NULL;
1103 } else {
Padmavathi Venna7da493e2013-08-12 15:19:51 +05301104 return (struct samsung_i2s_dai_data *)
1105 platform_get_device_id(pdev)->driver_data;
Sylwester Nawrocki9cf24742015-01-14 19:42:28 +01001106 }
Padmavathi Venna7c62eeb2013-01-18 17:17:00 +05301107}
1108
Rafael J. Wysocki641d3342014-12-13 00:42:18 +01001109#ifdef CONFIG_PM
R. Chandrasekar5b1d3c32013-01-30 17:41:04 +05301110static int i2s_runtime_suspend(struct device *dev)
1111{
1112 struct i2s_dai *i2s = dev_get_drvdata(dev);
1113
1114 clk_disable_unprepare(i2s->clk);
1115
1116 return 0;
1117}
1118
1119static int i2s_runtime_resume(struct device *dev)
1120{
1121 struct i2s_dai *i2s = dev_get_drvdata(dev);
1122
1123 clk_prepare_enable(i2s->clk);
1124
1125 return 0;
1126}
Rafael J. Wysocki641d3342014-12-13 00:42:18 +01001127#endif /* CONFIG_PM */
R. Chandrasekar5b1d3c32013-01-30 17:41:04 +05301128
Bill Pembertonfdca21a2012-12-07 09:26:15 -05001129static int samsung_i2s_probe(struct platform_device *pdev)
Jassi Brar1c7ac012010-11-22 15:36:59 +09001130{
Jassi Brar1c7ac012010-11-22 15:36:59 +09001131 struct i2s_dai *pri_dai, *sec_dai = NULL;
Padmavathi Venna40476f62013-01-18 17:17:01 +05301132 struct s3c_audio_pdata *i2s_pdata = pdev->dev.platform_data;
1133 struct samsung_i2s *i2s_cfg = NULL;
Jassi Brar1c7ac012010-11-22 15:36:59 +09001134 struct resource *res;
Padmavathi Venna40476f62013-01-18 17:17:01 +05301135 u32 regs_base, quirks = 0, idma_addr = 0;
1136 struct device_node *np = pdev->dev.of_node;
Padmavathi Venna7da493e2013-08-12 15:19:51 +05301137 const struct samsung_i2s_dai_data *i2s_dai_data;
Sylwester Nawrockic92f1d02015-01-14 19:42:32 +01001138 int ret;
Jassi Brar1c7ac012010-11-22 15:36:59 +09001139
1140 /* Call during Seconday interface registration */
Padmavathi Venna7da493e2013-08-12 15:19:51 +05301141 i2s_dai_data = samsung_i2s_get_driver_data(pdev);
Padmavathi Venna7c62eeb2013-01-18 17:17:00 +05301142
Padmavathi Venna7da493e2013-08-12 15:19:51 +05301143 if (i2s_dai_data->dai_type == TYPE_SEC) {
Jassi Brar1c7ac012010-11-22 15:36:59 +09001144 sec_dai = dev_get_drvdata(&pdev->dev);
Prathyush Ka9b977e2013-04-02 16:53:01 +05301145 if (!sec_dai) {
1146 dev_err(&pdev->dev, "Unable to get drvdata\n");
1147 return -EFAULT;
1148 }
Sylwester Nawrocki53f7faa2015-01-14 19:42:29 +01001149 ret = devm_snd_soc_register_component(&sec_dai->pdev->dev,
Mark Brownd644a112013-09-04 20:37:51 +01001150 &samsung_i2s_component,
1151 &sec_dai->i2s_dai_drv, 1);
Sylwester Nawrocki53f7faa2015-01-14 19:42:29 +01001152 if (ret != 0)
1153 return ret;
1154
1155 return samsung_asoc_dma_platform_register(&pdev->dev);
Jassi Brar1c7ac012010-11-22 15:36:59 +09001156 }
1157
Padmavathi Venna40476f62013-01-18 17:17:01 +05301158 pri_dai = i2s_alloc_dai(pdev, false);
1159 if (!pri_dai) {
1160 dev_err(&pdev->dev, "Unable to alloc I2S_pri\n");
1161 return -ENOMEM;
Jassi Brar1c7ac012010-11-22 15:36:59 +09001162 }
1163
Sylwester Nawrockif3670532015-01-14 19:42:35 +01001164 spin_lock_init(&pri_dai->spinlock);
1165 pri_dai->lock = &pri_dai->spinlock;
1166
Padmavathi Venna40476f62013-01-18 17:17:01 +05301167 if (!np) {
1168 res = platform_get_resource(pdev, IORESOURCE_DMA, 0);
1169 if (!res) {
1170 dev_err(&pdev->dev,
1171 "Unable to get I2S-TX dma resource\n");
1172 return -ENXIO;
1173 }
1174 pri_dai->dma_playback.channel = res->start;
Jassi Brar1c7ac012010-11-22 15:36:59 +09001175
Padmavathi Venna40476f62013-01-18 17:17:01 +05301176 res = platform_get_resource(pdev, IORESOURCE_DMA, 1);
1177 if (!res) {
1178 dev_err(&pdev->dev,
1179 "Unable to get I2S-RX dma resource\n");
1180 return -ENXIO;
1181 }
1182 pri_dai->dma_capture.channel = res->start;
Jassi Brar1c7ac012010-11-22 15:36:59 +09001183
Padmavathi Venna40476f62013-01-18 17:17:01 +05301184 if (i2s_pdata == NULL) {
1185 dev_err(&pdev->dev, "Can't work without s3c_audio_pdata\n");
1186 return -EINVAL;
1187 }
1188
1189 if (&i2s_pdata->type)
1190 i2s_cfg = &i2s_pdata->type.i2s;
1191
1192 if (i2s_cfg) {
1193 quirks = i2s_cfg->quirks;
1194 idma_addr = i2s_cfg->idma_addr;
1195 }
1196 } else {
Padmavathi Venna7da493e2013-08-12 15:19:51 +05301197 quirks = i2s_dai_data->quirks;
Padmavathi Venna40476f62013-01-18 17:17:01 +05301198 if (of_property_read_u32(np, "samsung,idma-addr",
1199 &idma_addr)) {
Padmavathi Vennab0759732014-11-07 12:24:39 +05301200 if (quirks & QUIRK_SUPPORTS_IDMA) {
1201 dev_info(&pdev->dev, "idma address is not"\
Padmavathi Venna40476f62013-01-18 17:17:01 +05301202 "specified");
Padmavathi Venna40476f62013-01-18 17:17:01 +05301203 }
1204 }
1205 }
Jassi Brar1c7ac012010-11-22 15:36:59 +09001206
1207 res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
Sylwester Nawrockiaf1cf5c2015-01-14 19:42:30 +01001208 pri_dai->addr = devm_ioremap_resource(&pdev->dev, res);
1209 if (IS_ERR(pri_dai->addr))
1210 return PTR_ERR(pri_dai->addr);
Jassi Brar1c7ac012010-11-22 15:36:59 +09001211
Jassi Brar1c7ac012010-11-22 15:36:59 +09001212 regs_base = res->start;
1213
Sylwester Nawrocki0ec2ba82015-01-14 19:42:31 +01001214 pri_dai->clk = devm_clk_get(&pdev->dev, "iis");
1215 if (IS_ERR(pri_dai->clk)) {
1216 dev_err(&pdev->dev, "Failed to get iis clock\n");
1217 return PTR_ERR(pri_dai->clk);
1218 }
Sylwester Nawrockic92f1d02015-01-14 19:42:32 +01001219
1220 ret = clk_prepare_enable(pri_dai->clk);
1221 if (ret != 0) {
1222 dev_err(&pdev->dev, "failed to enable clock: %d\n", ret);
1223 return ret;
1224 }
Jassi Brar1c7ac012010-11-22 15:36:59 +09001225 pri_dai->dma_playback.dma_addr = regs_base + I2STXD;
1226 pri_dai->dma_capture.dma_addr = regs_base + I2SRXD;
Padmavathi Venna40476f62013-01-18 17:17:01 +05301227 pri_dai->dma_playback.ch_name = "tx";
Padmavathi Venna40476f62013-01-18 17:17:01 +05301228 pri_dai->dma_capture.ch_name = "rx";
Jassi Brar1c7ac012010-11-22 15:36:59 +09001229 pri_dai->dma_playback.dma_size = 4;
1230 pri_dai->dma_capture.dma_size = 4;
Jassi Brar1c7ac012010-11-22 15:36:59 +09001231 pri_dai->quirks = quirks;
Padmavathi Vennaa5a56872014-11-07 12:24:40 +05301232 pri_dai->variant_regs = i2s_dai_data->i2s_variant_regs;
Jassi Brar1c7ac012010-11-22 15:36:59 +09001233
1234 if (quirks & QUIRK_PRI_6CHAN)
1235 pri_dai->i2s_dai_drv.playback.channels_max = 6;
1236
1237 if (quirks & QUIRK_SEC_DAI) {
1238 sec_dai = i2s_alloc_dai(pdev, true);
1239 if (!sec_dai) {
1240 dev_err(&pdev->dev, "Unable to alloc I2S_sec\n");
Sylwester Nawrockiaf1cf5c2015-01-14 19:42:30 +01001241 return -ENOMEM;
Jassi Brar1c7ac012010-11-22 15:36:59 +09001242 }
Sylwester Nawrocki7e5d8702014-12-08 18:45:54 +01001243
Sylwester Nawrockif3670532015-01-14 19:42:35 +01001244 sec_dai->lock = &pri_dai->spinlock;
Sylwester Nawrocki7e5d8702014-12-08 18:45:54 +01001245 sec_dai->variant_regs = pri_dai->variant_regs;
Jassi Brar1c7ac012010-11-22 15:36:59 +09001246 sec_dai->dma_playback.dma_addr = regs_base + I2STXDS;
Padmavathi Venna40476f62013-01-18 17:17:01 +05301247 sec_dai->dma_playback.ch_name = "tx-sec";
1248
1249 if (!np) {
1250 res = platform_get_resource(pdev, IORESOURCE_DMA, 2);
1251 if (res)
1252 sec_dai->dma_playback.channel = res->start;
1253 }
1254
Jassi Brar1c7ac012010-11-22 15:36:59 +09001255 sec_dai->dma_playback.dma_size = 4;
Sylwester Nawrockiaf1cf5c2015-01-14 19:42:30 +01001256 sec_dai->addr = pri_dai->addr;
Sylwester Nawrocki0ec2ba82015-01-14 19:42:31 +01001257 sec_dai->clk = pri_dai->clk;
Jassi Brar1c7ac012010-11-22 15:36:59 +09001258 sec_dai->quirks = quirks;
Padmavathi Venna40476f62013-01-18 17:17:01 +05301259 sec_dai->idma_playback.dma_addr = idma_addr;
Jassi Brar1c7ac012010-11-22 15:36:59 +09001260 sec_dai->pri_dai = pri_dai;
1261 pri_dai->sec_dai = sec_dai;
1262 }
1263
Mark Brown0429ffe2013-07-02 13:10:28 +01001264 if (i2s_pdata && i2s_pdata->cfg_gpio && i2s_pdata->cfg_gpio(pdev)) {
1265 dev_err(&pdev->dev, "Unable to configure gpio\n");
Sylwester Nawrockiaf1cf5c2015-01-14 19:42:30 +01001266 return -EINVAL;
Jassi Brar1c7ac012010-11-22 15:36:59 +09001267 }
1268
Mark Brownd644a112013-09-04 20:37:51 +01001269 devm_snd_soc_register_component(&pri_dai->pdev->dev,
1270 &samsung_i2s_component,
1271 &pri_dai->i2s_dai_drv, 1);
Jassi Brar1c7ac012010-11-22 15:36:59 +09001272
Mark Brownc5cf4db2011-12-08 16:45:03 +08001273 pm_runtime_enable(&pdev->dev);
1274
Sylwester Nawrocki53f7faa2015-01-14 19:42:29 +01001275 ret = samsung_asoc_dma_platform_register(&pdev->dev);
1276 if (ret != 0)
1277 return ret;
Padmavathi Vennaa08485d82012-12-07 13:59:21 +05301278
Jassi Brar1c7ac012010-11-22 15:36:59 +09001279 return 0;
Jassi Brar1c7ac012010-11-22 15:36:59 +09001280}
1281
Bill Pembertonfdca21a2012-12-07 09:26:15 -05001282static int samsung_i2s_remove(struct platform_device *pdev)
Jassi Brar1c7ac012010-11-22 15:36:59 +09001283{
1284 struct i2s_dai *i2s, *other;
1285
1286 i2s = dev_get_drvdata(&pdev->dev);
Sylwester Nawrockidcd60fc2015-01-14 19:42:33 +01001287 other = get_other_dai(i2s);
Jassi Brar1c7ac012010-11-22 15:36:59 +09001288
1289 if (other) {
1290 other->pri_dai = NULL;
1291 other->sec_dai = NULL;
1292 } else {
Mark Brownc5cf4db2011-12-08 16:45:03 +08001293 pm_runtime_disable(&pdev->dev);
Jassi Brar1c7ac012010-11-22 15:36:59 +09001294 }
1295
Sylwester Nawrockic92f1d02015-01-14 19:42:32 +01001296 if (!is_secondary(i2s))
1297 clk_disable_unprepare(i2s->clk);
1298
Jassi Brar1c7ac012010-11-22 15:36:59 +09001299 i2s->pri_dai = NULL;
1300 i2s->sec_dai = NULL;
1301
Jassi Brar1c7ac012010-11-22 15:36:59 +09001302 return 0;
1303}
1304
Padmavathi Vennaa5a56872014-11-07 12:24:40 +05301305static const struct samsung_i2s_variant_regs i2sv3_regs = {
1306 .bfs_off = 1,
1307 .rfs_off = 3,
1308 .sdf_off = 5,
1309 .txr_off = 8,
1310 .rclksrc_off = 10,
1311 .mss_off = 11,
1312 .cdclkcon_off = 12,
1313 .lrp_off = 7,
1314 .bfs_mask = 0x3,
1315 .rfs_mask = 0x3,
1316 .ftx0cnt_off = 8,
1317};
1318
1319static const struct samsung_i2s_variant_regs i2sv6_regs = {
1320 .bfs_off = 0,
1321 .rfs_off = 4,
1322 .sdf_off = 6,
1323 .txr_off = 8,
1324 .rclksrc_off = 10,
1325 .mss_off = 11,
1326 .cdclkcon_off = 12,
1327 .lrp_off = 15,
1328 .bfs_mask = 0xf,
1329 .rfs_mask = 0x3,
1330 .ftx0cnt_off = 8,
1331};
1332
1333static const struct samsung_i2s_variant_regs i2sv7_regs = {
1334 .bfs_off = 0,
1335 .rfs_off = 4,
1336 .sdf_off = 7,
1337 .txr_off = 9,
1338 .rclksrc_off = 11,
1339 .mss_off = 12,
1340 .cdclkcon_off = 22,
1341 .lrp_off = 15,
1342 .bfs_mask = 0xf,
1343 .rfs_mask = 0x7,
1344 .ftx0cnt_off = 0,
1345};
1346
1347static const struct samsung_i2s_variant_regs i2sv5_i2s1_regs = {
1348 .bfs_off = 0,
1349 .rfs_off = 3,
1350 .sdf_off = 6,
1351 .txr_off = 8,
1352 .rclksrc_off = 10,
1353 .mss_off = 11,
1354 .cdclkcon_off = 12,
1355 .lrp_off = 15,
1356 .bfs_mask = 0x7,
1357 .rfs_mask = 0x7,
1358 .ftx0cnt_off = 8,
1359};
1360
Padmavathi Venna7da493e2013-08-12 15:19:51 +05301361static const struct samsung_i2s_dai_data i2sv3_dai_type = {
1362 .dai_type = TYPE_PRI,
1363 .quirks = QUIRK_NO_MUXPSR,
Padmavathi Vennaa5a56872014-11-07 12:24:40 +05301364 .i2s_variant_regs = &i2sv3_regs,
Padmavathi Venna7da493e2013-08-12 15:19:51 +05301365};
1366
1367static const struct samsung_i2s_dai_data i2sv5_dai_type = {
1368 .dai_type = TYPE_PRI,
Padmavathi Vennab0759732014-11-07 12:24:39 +05301369 .quirks = QUIRK_PRI_6CHAN | QUIRK_SEC_DAI | QUIRK_NEED_RSTCLR |
1370 QUIRK_SUPPORTS_IDMA,
Padmavathi Vennaa5a56872014-11-07 12:24:40 +05301371 .i2s_variant_regs = &i2sv3_regs,
Padmavathi Venna7da493e2013-08-12 15:19:51 +05301372};
1373
Padmavathi Venna4ca0c0d2013-08-12 15:19:52 +05301374static const struct samsung_i2s_dai_data i2sv6_dai_type = {
1375 .dai_type = TYPE_PRI,
1376 .quirks = QUIRK_PRI_6CHAN | QUIRK_SEC_DAI | QUIRK_NEED_RSTCLR |
Padmavathi Vennab0759732014-11-07 12:24:39 +05301377 QUIRK_SUPPORTS_TDM | QUIRK_SUPPORTS_IDMA,
Padmavathi Vennaa5a56872014-11-07 12:24:40 +05301378 .i2s_variant_regs = &i2sv6_regs,
1379};
1380
1381static const struct samsung_i2s_dai_data i2sv7_dai_type = {
1382 .dai_type = TYPE_PRI,
1383 .quirks = QUIRK_PRI_6CHAN | QUIRK_SEC_DAI | QUIRK_NEED_RSTCLR |
1384 QUIRK_SUPPORTS_TDM,
1385 .i2s_variant_regs = &i2sv7_regs,
1386};
1387
1388static const struct samsung_i2s_dai_data i2sv5_dai_type_i2s1 = {
1389 .dai_type = TYPE_PRI,
1390 .quirks = QUIRK_PRI_6CHAN | QUIRK_NEED_RSTCLR,
1391 .i2s_variant_regs = &i2sv5_i2s1_regs,
Padmavathi Venna4ca0c0d2013-08-12 15:19:52 +05301392};
1393
Padmavathi Venna7da493e2013-08-12 15:19:51 +05301394static const struct samsung_i2s_dai_data samsung_dai_type_pri = {
1395 .dai_type = TYPE_PRI,
1396};
1397
1398static const struct samsung_i2s_dai_data samsung_dai_type_sec = {
1399 .dai_type = TYPE_SEC,
1400};
1401
Padmavathi Venna7c62eeb2013-01-18 17:17:00 +05301402static struct platform_device_id samsung_i2s_driver_ids[] = {
1403 {
1404 .name = "samsung-i2s",
Mark Brown3f024982014-12-05 19:56:17 +00001405 .driver_data = (kernel_ulong_t)&i2sv3_dai_type,
Padmavathi Venna7c62eeb2013-01-18 17:17:00 +05301406 }, {
1407 .name = "samsung-i2s-sec",
Padmavathi Venna7da493e2013-08-12 15:19:51 +05301408 .driver_data = (kernel_ulong_t)&samsung_dai_type_sec,
Mark Brown3f024982014-12-05 19:56:17 +00001409 }, {
1410 .name = "samsung-i2sv4",
1411 .driver_data = (kernel_ulong_t)&i2sv5_dai_type,
Padmavathi Venna7c62eeb2013-01-18 17:17:00 +05301412 },
1413 {},
1414};
Arnd Bergmann2af19552013-04-11 02:05:03 +02001415MODULE_DEVICE_TABLE(platform, samsung_i2s_driver_ids);
Padmavathi Venna7c62eeb2013-01-18 17:17:00 +05301416
Padmavathi Venna40476f62013-01-18 17:17:01 +05301417#ifdef CONFIG_OF
Padmavathi Venna40476f62013-01-18 17:17:01 +05301418static const struct of_device_id exynos_i2s_match[] = {
Padmavathi Venna7da493e2013-08-12 15:19:51 +05301419 {
1420 .compatible = "samsung,s3c6410-i2s",
1421 .data = &i2sv3_dai_type,
1422 }, {
1423 .compatible = "samsung,s5pv210-i2s",
1424 .data = &i2sv5_dai_type,
Padmavathi Venna4ca0c0d2013-08-12 15:19:52 +05301425 }, {
1426 .compatible = "samsung,exynos5420-i2s",
1427 .data = &i2sv6_dai_type,
Padmavathi Vennaa5a56872014-11-07 12:24:40 +05301428 }, {
1429 .compatible = "samsung,exynos7-i2s",
1430 .data = &i2sv7_dai_type,
1431 }, {
1432 .compatible = "samsung,exynos7-i2s1",
1433 .data = &i2sv5_dai_type_i2s1,
Padmavathi Venna40476f62013-01-18 17:17:01 +05301434 },
1435 {},
1436};
1437MODULE_DEVICE_TABLE(of, exynos_i2s_match);
1438#endif
1439
R. Chandrasekar5b1d3c32013-01-30 17:41:04 +05301440static const struct dev_pm_ops samsung_i2s_pm = {
1441 SET_RUNTIME_PM_OPS(i2s_runtime_suspend,
1442 i2s_runtime_resume, NULL)
1443};
1444
Jassi Brar1c7ac012010-11-22 15:36:59 +09001445static struct platform_driver samsung_i2s_driver = {
1446 .probe = samsung_i2s_probe,
Bill Pembertonfdca21a2012-12-07 09:26:15 -05001447 .remove = samsung_i2s_remove,
Padmavathi Venna7c62eeb2013-01-18 17:17:00 +05301448 .id_table = samsung_i2s_driver_ids,
Jassi Brar1c7ac012010-11-22 15:36:59 +09001449 .driver = {
1450 .name = "samsung-i2s",
Padmavathi Venna40476f62013-01-18 17:17:01 +05301451 .of_match_table = of_match_ptr(exynos_i2s_match),
R. Chandrasekar5b1d3c32013-01-30 17:41:04 +05301452 .pm = &samsung_i2s_pm,
Jassi Brar1c7ac012010-11-22 15:36:59 +09001453 },
1454};
1455
Mark Browne00c3f52011-11-23 15:20:13 +00001456module_platform_driver(samsung_i2s_driver);
Jassi Brar1c7ac012010-11-22 15:36:59 +09001457
1458/* Module information */
Jaswinder Singhdf8ad332012-02-25 16:24:36 +05301459MODULE_AUTHOR("Jaswinder Singh, <jassisinghbrar@gmail.com>");
Jassi Brar1c7ac012010-11-22 15:36:59 +09001460MODULE_DESCRIPTION("Samsung I2S Interface");
1461MODULE_ALIAS("platform:samsung-i2s");
1462MODULE_LICENSE("GPL");