aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorPadmavathi Venna <padma.v@samsung.com>2014-11-07 01:54:40 -0500
committerMark Brown <broonie@kernel.org>2014-11-07 05:41:22 -0500
commita5a56871f804edac93a53b5e871c0e9818fb9033 (patch)
treeb5d9183ac7f4cd32d4f59f9bc305432d0fbc738b
parentb07597367001c2c4f36a97863530f71b84060d3d (diff)
ASoC: samsung: add support for exynos7 I2S controller
Exynos7 I2S controller has no internal dma, supports more no. of root clock sampling frequencies and has more no.of Rx fifos to support 7.1CH recording in TDM mode. Due to more no. of root clock frequency values some of the bit offsets got shifted up by one. Also I2S1 on previous Samsung platforms uses v3 dai type but on Exynos7 it is upgraded to v5 with slightly modified register offsets for supporting more no.of RFS values. Due to the above changes, the driver has to be modified to handle all versions of I2S controller. For this I introduced a new structure to hold modified bit offsets and masks which is passed as dai data. Signed-off-by: Padmavathi Venna <padma.v@samsung.com> Signed-off-by: Mark Brown <broonie@kernel.org>
-rw-r--r--Documentation/devicetree/bindings/sound/samsung-i2s.txt15
-rw-r--r--sound/soc/samsung/Kconfig2
-rw-r--r--sound/soc/samsung/i2s-regs.h10
-rw-r--r--sound/soc/samsung/i2s.c218
4 files changed, 174 insertions, 71 deletions
diff --git a/Documentation/devicetree/bindings/sound/samsung-i2s.txt b/Documentation/devicetree/bindings/sound/samsung-i2s.txt
index 7386d444ada1..d188296bb6ec 100644
--- a/Documentation/devicetree/bindings/sound/samsung-i2s.txt
+++ b/Documentation/devicetree/bindings/sound/samsung-i2s.txt
@@ -6,10 +6,17 @@ Required SoC Specific Properties:
6 - samsung,s3c6410-i2s: for 8/16/24bit stereo I2S. 6 - samsung,s3c6410-i2s: for 8/16/24bit stereo I2S.
7 - samsung,s5pv210-i2s: for 8/16/24bit multichannel(5.1) I2S with 7 - samsung,s5pv210-i2s: for 8/16/24bit multichannel(5.1) I2S with
8 secondary fifo, s/w reset control and internal mux for root clk src. 8 secondary fifo, s/w reset control and internal mux for root clk src.
9 - samsung,exynos5420-i2s: for 8/16/24bit multichannel(7.1) I2S with 9 - samsung,exynos5420-i2s: for 8/16/24bit multichannel(5.1) I2S for
10 secondary fifo, s/w reset control, internal mux for root clk src and 10 playback, sterio channel capture, secondary fifo using internal
11 TDM support. TDM (Time division multiplexing) is to allow transfer of 11 or external dma, s/w reset control, internal mux for root clk src
12 multiple channel audio data on single data line. 12 and 7.1 channel TDM support for playback. TDM (Time division multiplexing)
13 is to allow transfer of multiple channel audio data on single data line.
14 - samsung,exynos7-i2s: with all the available features of exynos5 i2s,
15 exynos7 I2S has 7.1 channel TDM support for capture, secondary fifo
16 with only external dma and more no.of root clk sampling frequencies.
17 - samsung,exynos7-i2s1: I2S1 on previous samsung platforms supports
18 stereo channels. exynos7 i2s1 upgraded to 5.1 multichannel with
19 slightly modified bit offsets.
13 20
14- reg: physical base address of the controller and length of memory mapped 21- reg: physical base address of the controller and length of memory mapped
15 region. 22 region.
diff --git a/sound/soc/samsung/Kconfig b/sound/soc/samsung/Kconfig
index 55a38697443d..e0e737faadd9 100644
--- a/sound/soc/samsung/Kconfig
+++ b/sound/soc/samsung/Kconfig
@@ -1,6 +1,6 @@
1config SND_SOC_SAMSUNG 1config SND_SOC_SAMSUNG
2 tristate "ASoC support for Samsung" 2 tristate "ASoC support for Samsung"
3 depends on PLAT_SAMSUNG 3 depends on (PLAT_SAMSUNG || ARCH_EXYNOS)
4 depends on S3C64XX_PL080 || !ARCH_S3C64XX 4 depends on S3C64XX_PL080 || !ARCH_S3C64XX
5 depends on S3C24XX_DMAC || !ARCH_S3C24XX 5 depends on S3C24XX_DMAC || !ARCH_S3C24XX
6 select SND_SOC_GENERIC_DMAENGINE_PCM 6 select SND_SOC_GENERIC_DMAENGINE_PCM
diff --git a/sound/soc/samsung/i2s-regs.h b/sound/soc/samsung/i2s-regs.h
index 821a50231002..9170c311d66e 100644
--- a/sound/soc/samsung/i2s-regs.h
+++ b/sound/soc/samsung/i2s-regs.h
@@ -33,8 +33,9 @@
33#define I2SLVL3ADDR 0x3c 33#define I2SLVL3ADDR 0x3c
34#define I2SSTR1 0x40 34#define I2SSTR1 0x40
35#define I2SVER 0x44 35#define I2SVER 0x44
36#define I2SFIC2 0x48 36#define I2SFIC1 0x48
37#define I2STDM 0x4c 37#define I2STDM 0x4c
38#define I2SFSTA 0x50
38 39
39#define CON_RSTCLR (1 << 31) 40#define CON_RSTCLR (1 << 31)
40#define CON_FRXOFSTATUS (1 << 26) 41#define CON_FRXOFSTATUS (1 << 26)
@@ -93,8 +94,6 @@
93#define MOD_BLC_24BIT (2 << 13) 94#define MOD_BLC_24BIT (2 << 13)
94#define MOD_BLC_MASK (3 << 13) 95#define MOD_BLC_MASK (3 << 13)
95 96
96#define MOD_IMS_SYSMUX (1 << 10)
97#define MOD_SLAVE (1 << 11)
98#define MOD_TXONLY (0 << 8) 97#define MOD_TXONLY (0 << 8)
99#define MOD_RXONLY (1 << 8) 98#define MOD_RXONLY (1 << 8)
100#define MOD_TXRX (2 << 8) 99#define MOD_TXRX (2 << 8)
@@ -132,7 +131,10 @@
132#define EXYNOS5420_MOD_BCLK_256FS 8 131#define EXYNOS5420_MOD_BCLK_256FS 8
133#define EXYNOS5420_MOD_BCLK_MASK 0xf 132#define EXYNOS5420_MOD_BCLK_MASK 0xf
134 133
135#define MOD_CDCLKCON (1 << 12) 134#define EXYNOS7_MOD_RCLK_64FS 4
135#define EXYNOS7_MOD_RCLK_128FS 5
136#define EXYNOS7_MOD_RCLK_96FS 6
137#define EXYNOS7_MOD_RCLK_192FS 7
136 138
137#define PSR_PSREN (1 << 15) 139#define PSR_PSREN (1 << 15)
138 140
diff --git a/sound/soc/samsung/i2s.c b/sound/soc/samsung/i2s.c
index 38b9a524cc9f..947352d00ddf 100644
--- a/sound/soc/samsung/i2s.c
+++ b/sound/soc/samsung/i2s.c
@@ -36,9 +36,24 @@ enum samsung_dai_type {
36 TYPE_SEC, 36 TYPE_SEC,
37}; 37};
38 38
39struct 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
39struct samsung_i2s_dai_data { 53struct samsung_i2s_dai_data {
40 int dai_type; 54 int dai_type;
41 u32 quirks; 55 u32 quirks;
56 const struct samsung_i2s_variant_regs *i2s_variant_regs;
42}; 57};
43 58
44struct i2s_dai { 59struct i2s_dai {
@@ -81,6 +96,7 @@ struct i2s_dai {
81 u32 suspend_i2scon; 96 u32 suspend_i2scon;
82 u32 suspend_i2spsr; 97 u32 suspend_i2spsr;
83 unsigned long gpios[7]; /* i2s gpio line numbers */ 98 unsigned long gpios[7]; /* i2s gpio line numbers */
99 const struct samsung_i2s_variant_regs *variant_regs;
84}; 100};
85 101
86/* Lock for cross i/f checks */ 102/* Lock for cross i/f checks */
@@ -95,7 +111,8 @@ static inline bool is_secondary(struct i2s_dai *i2s)
95/* If operating in SoC-Slave mode */ 111/* If operating in SoC-Slave mode */
96static inline bool is_slave(struct i2s_dai *i2s) 112static inline bool is_slave(struct i2s_dai *i2s)
97{ 113{
98 return (readl(i2s->addr + I2SMOD) & MOD_SLAVE) ? true : false; 114 u32 mod = readl(i2s->addr + I2SMOD);
115 return (mod & (1 << i2s->variant_regs->mss_off)) ? true : false;
99} 116}
100 117
101/* If this interface of the controller is transmitting data */ 118/* If this interface of the controller is transmitting data */
@@ -200,14 +217,14 @@ static inline bool is_manager(struct i2s_dai *i2s)
200static inline unsigned get_rfs(struct i2s_dai *i2s) 217static inline unsigned get_rfs(struct i2s_dai *i2s)
201{ 218{
202 u32 rfs; 219 u32 rfs;
203 220 rfs = readl(i2s->addr + I2SMOD) >> i2s->variant_regs->rfs_off;
204 if (i2s->quirks & QUIRK_SUPPORTS_TDM) 221 rfs &= i2s->variant_regs->rfs_mask;
205 rfs = readl(i2s->addr + I2SMOD) >> EXYNOS5420_MOD_RCLK_SHIFT;
206 else
207 rfs = (readl(i2s->addr + I2SMOD) >> MOD_RCLK_SHIFT);
208 rfs &= MOD_RCLK_MASK;
209 222
210 switch (rfs) { 223 switch (rfs) {
224 case 7: return 192;
225 case 6: return 96;
226 case 5: return 128;
227 case 4: return 64;
211 case 3: return 768; 228 case 3: return 768;
212 case 2: return 384; 229 case 2: return 384;
213 case 1: return 512; 230 case 1: return 512;
@@ -219,15 +236,23 @@ static inline unsigned get_rfs(struct i2s_dai *i2s)
219static inline void set_rfs(struct i2s_dai *i2s, unsigned rfs) 236static inline void set_rfs(struct i2s_dai *i2s, unsigned rfs)
220{ 237{
221 u32 mod = readl(i2s->addr + I2SMOD); 238 u32 mod = readl(i2s->addr + I2SMOD);
222 int rfs_shift; 239 int rfs_shift = i2s->variant_regs->rfs_off;
223 240
224 if (i2s->quirks & QUIRK_SUPPORTS_TDM) 241 mod &= ~(i2s->variant_regs->rfs_mask << rfs_shift);
225 rfs_shift = EXYNOS5420_MOD_RCLK_SHIFT;
226 else
227 rfs_shift = MOD_RCLK_SHIFT;
228 mod &= ~(MOD_RCLK_MASK << rfs_shift);
229 242
230 switch (rfs) { 243 switch (rfs) {
244 case 192:
245 mod |= (EXYNOS7_MOD_RCLK_192FS << rfs_shift);
246 break;
247 case 96:
248 mod |= (EXYNOS7_MOD_RCLK_96FS << rfs_shift);
249 break;
250 case 128:
251 mod |= (EXYNOS7_MOD_RCLK_128FS << rfs_shift);
252 break;
253 case 64:
254 mod |= (EXYNOS7_MOD_RCLK_64FS << rfs_shift);
255 break;
231 case 768: 256 case 768:
232 mod |= (MOD_RCLK_768FS << rfs_shift); 257 mod |= (MOD_RCLK_768FS << rfs_shift);
233 break; 258 break;
@@ -249,14 +274,8 @@ static inline void set_rfs(struct i2s_dai *i2s, unsigned rfs)
249static inline unsigned get_bfs(struct i2s_dai *i2s) 274static inline unsigned get_bfs(struct i2s_dai *i2s)
250{ 275{
251 u32 bfs; 276 u32 bfs;
252 277 bfs = readl(i2s->addr + I2SMOD) >> i2s->variant_regs->bfs_off;
253 if (i2s->quirks & QUIRK_SUPPORTS_TDM) { 278 bfs &= i2s->variant_regs->bfs_mask;
254 bfs = readl(i2s->addr + I2SMOD) >> EXYNOS5420_MOD_BCLK_SHIFT;
255 bfs &= EXYNOS5420_MOD_BCLK_MASK;
256 } else {
257 bfs = readl(i2s->addr + I2SMOD) >> MOD_BCLK_SHIFT;
258 bfs &= MOD_BCLK_MASK;
259 }
260 279
261 switch (bfs) { 280 switch (bfs) {
262 case 8: return 256; 281 case 8: return 256;
@@ -275,16 +294,8 @@ static inline unsigned get_bfs(struct i2s_dai *i2s)
275static inline void set_bfs(struct i2s_dai *i2s, unsigned bfs) 294static inline void set_bfs(struct i2s_dai *i2s, unsigned bfs)
276{ 295{
277 u32 mod = readl(i2s->addr + I2SMOD); 296 u32 mod = readl(i2s->addr + I2SMOD);
278 int bfs_shift;
279 int tdm = i2s->quirks & QUIRK_SUPPORTS_TDM; 297 int tdm = i2s->quirks & QUIRK_SUPPORTS_TDM;
280 298 int bfs_shift = i2s->variant_regs->bfs_off;
281 if (i2s->quirks & QUIRK_SUPPORTS_TDM) {
282 bfs_shift = EXYNOS5420_MOD_BCLK_SHIFT;
283 mod &= ~(EXYNOS5420_MOD_BCLK_MASK << bfs_shift);
284 } else {
285 bfs_shift = MOD_BCLK_SHIFT;
286 mod &= ~(MOD_BCLK_MASK << bfs_shift);
287 }
288 299
289 /* Non-TDM I2S controllers do not support BCLK > 48 * FS */ 300 /* Non-TDM I2S controllers do not support BCLK > 48 * FS */
290 if (!tdm && bfs > 48) { 301 if (!tdm && bfs > 48) {
@@ -292,6 +303,8 @@ static inline void set_bfs(struct i2s_dai *i2s, unsigned bfs)
292 return; 303 return;
293 } 304 }
294 305
306 mod &= ~(i2s->variant_regs->bfs_mask << bfs_shift);
307
295 switch (bfs) { 308 switch (bfs) {
296 case 48: 309 case 48:
297 mod |= (MOD_BCLK_48FS << bfs_shift); 310 mod |= (MOD_BCLK_48FS << bfs_shift);
@@ -346,8 +359,9 @@ static inline int get_blc(struct i2s_dai *i2s)
346static void i2s_txctrl(struct i2s_dai *i2s, int on) 359static void i2s_txctrl(struct i2s_dai *i2s, int on)
347{ 360{
348 void __iomem *addr = i2s->addr; 361 void __iomem *addr = i2s->addr;
362 int txr_off = i2s->variant_regs->txr_off;
349 u32 con = readl(addr + I2SCON); 363 u32 con = readl(addr + I2SCON);
350 u32 mod = readl(addr + I2SMOD) & ~MOD_MASK; 364 u32 mod = readl(addr + I2SMOD) & ~(3 << txr_off);
351 365
352 if (on) { 366 if (on) {
353 con |= CON_ACTIVE; 367 con |= CON_ACTIVE;
@@ -362,9 +376,9 @@ static void i2s_txctrl(struct i2s_dai *i2s, int on)
362 } 376 }
363 377
364 if (any_rx_active(i2s)) 378 if (any_rx_active(i2s))
365 mod |= MOD_TXRX; 379 mod |= 2 << txr_off;
366 else 380 else
367 mod |= MOD_TXONLY; 381 mod |= 0 << txr_off;
368 } else { 382 } else {
369 if (is_secondary(i2s)) { 383 if (is_secondary(i2s)) {
370 con |= CON_TXSDMA_PAUSE; 384 con |= CON_TXSDMA_PAUSE;
@@ -382,7 +396,7 @@ static void i2s_txctrl(struct i2s_dai *i2s, int on)
382 con |= CON_TXCH_PAUSE; 396 con |= CON_TXCH_PAUSE;
383 397
384 if (any_rx_active(i2s)) 398 if (any_rx_active(i2s))
385 mod |= MOD_RXONLY; 399 mod |= 1 << txr_off;
386 else 400 else
387 con &= ~CON_ACTIVE; 401 con &= ~CON_ACTIVE;
388 } 402 }
@@ -395,23 +409,24 @@ static void i2s_txctrl(struct i2s_dai *i2s, int on)
395static void i2s_rxctrl(struct i2s_dai *i2s, int on) 409static void i2s_rxctrl(struct i2s_dai *i2s, int on)
396{ 410{
397 void __iomem *addr = i2s->addr; 411 void __iomem *addr = i2s->addr;
412 int txr_off = i2s->variant_regs->txr_off;
398 u32 con = readl(addr + I2SCON); 413 u32 con = readl(addr + I2SCON);
399 u32 mod = readl(addr + I2SMOD) & ~MOD_MASK; 414 u32 mod = readl(addr + I2SMOD) & ~(3 << txr_off);
400 415
401 if (on) { 416 if (on) {
402 con |= CON_RXDMA_ACTIVE | CON_ACTIVE; 417 con |= CON_RXDMA_ACTIVE | CON_ACTIVE;
403 con &= ~(CON_RXDMA_PAUSE | CON_RXCH_PAUSE); 418 con &= ~(CON_RXDMA_PAUSE | CON_RXCH_PAUSE);
404 419
405 if (any_tx_active(i2s)) 420 if (any_tx_active(i2s))
406 mod |= MOD_TXRX; 421 mod |= 2 << txr_off;
407 else 422 else
408 mod |= MOD_RXONLY; 423 mod |= 1 << txr_off;
409 } else { 424 } else {
410 con |= CON_RXDMA_PAUSE | CON_RXCH_PAUSE; 425 con |= CON_RXDMA_PAUSE | CON_RXCH_PAUSE;
411 con &= ~CON_RXDMA_ACTIVE; 426 con &= ~CON_RXDMA_ACTIVE;
412 427
413 if (any_tx_active(i2s)) 428 if (any_tx_active(i2s))
414 mod |= MOD_TXONLY; 429 mod |= 0 << txr_off;
415 else 430 else
416 con &= ~CON_ACTIVE; 431 con &= ~CON_ACTIVE;
417 } 432 }
@@ -451,6 +466,9 @@ static int i2s_set_sysclk(struct snd_soc_dai *dai,
451 struct i2s_dai *i2s = to_info(dai); 466 struct i2s_dai *i2s = to_info(dai);
452 struct i2s_dai *other = i2s->pri_dai ? : i2s->sec_dai; 467 struct i2s_dai *other = i2s->pri_dai ? : i2s->sec_dai;
453 u32 mod = readl(i2s->addr + I2SMOD); 468 u32 mod = readl(i2s->addr + I2SMOD);
469 const struct samsung_i2s_variant_regs *i2s_regs = i2s->variant_regs;
470 unsigned int cdcon_mask = 1 << i2s_regs->cdclkcon_off;
471 unsigned int rsrc_mask = 1 << i2s_regs->rclksrc_off;
454 472
455 switch (clk_id) { 473 switch (clk_id) {
456 case SAMSUNG_I2S_OPCLK: 474 case SAMSUNG_I2S_OPCLK:
@@ -465,18 +483,18 @@ static int i2s_set_sysclk(struct snd_soc_dai *dai,
465 if ((rfs && other && other->rfs && (other->rfs != rfs)) || 483 if ((rfs && other && other->rfs && (other->rfs != rfs)) ||
466 (any_active(i2s) && 484 (any_active(i2s) &&
467 (((dir == SND_SOC_CLOCK_IN) 485 (((dir == SND_SOC_CLOCK_IN)
468 && !(mod & MOD_CDCLKCON)) || 486 && !(mod & cdcon_mask)) ||
469 ((dir == SND_SOC_CLOCK_OUT) 487 ((dir == SND_SOC_CLOCK_OUT)
470 && (mod & MOD_CDCLKCON))))) { 488 && (mod & cdcon_mask))))) {
471 dev_err(&i2s->pdev->dev, 489 dev_err(&i2s->pdev->dev,
472 "%s:%d Other DAI busy\n", __func__, __LINE__); 490 "%s:%d Other DAI busy\n", __func__, __LINE__);
473 return -EAGAIN; 491 return -EAGAIN;
474 } 492 }
475 493
476 if (dir == SND_SOC_CLOCK_IN) 494 if (dir == SND_SOC_CLOCK_IN)
477 mod |= MOD_CDCLKCON; 495 mod |= 1 << i2s_regs->cdclkcon_off;
478 else 496 else
479 mod &= ~MOD_CDCLKCON; 497 mod &= 0 << i2s_regs->cdclkcon_off;
480 498
481 i2s->rfs = rfs; 499 i2s->rfs = rfs;
482 break; 500 break;
@@ -491,8 +509,8 @@ static int i2s_set_sysclk(struct snd_soc_dai *dai,
491 509
492 if (!any_active(i2s)) { 510 if (!any_active(i2s)) {
493 if (i2s->op_clk && !IS_ERR(i2s->op_clk)) { 511 if (i2s->op_clk && !IS_ERR(i2s->op_clk)) {
494 if ((clk_id && !(mod & MOD_IMS_SYSMUX)) || 512 if ((clk_id && !(mod & rsrc_mask)) ||
495 (!clk_id && (mod & MOD_IMS_SYSMUX))) { 513 (!clk_id && (mod & rsrc_mask))) {
496 clk_disable_unprepare(i2s->op_clk); 514 clk_disable_unprepare(i2s->op_clk);
497 clk_put(i2s->op_clk); 515 clk_put(i2s->op_clk);
498 } else { 516 } else {
@@ -520,8 +538,8 @@ static int i2s_set_sysclk(struct snd_soc_dai *dai,
520 other->op_clk = i2s->op_clk; 538 other->op_clk = i2s->op_clk;
521 other->rclk_srcrate = i2s->rclk_srcrate; 539 other->rclk_srcrate = i2s->rclk_srcrate;
522 } 540 }
523 } else if ((!clk_id && (mod & MOD_IMS_SYSMUX)) 541 } else if ((!clk_id && (mod & rsrc_mask))
524 || (clk_id && !(mod & MOD_IMS_SYSMUX))) { 542 || (clk_id && !(mod & rsrc_mask))) {
525 dev_err(&i2s->pdev->dev, 543 dev_err(&i2s->pdev->dev,
526 "%s:%d Other DAI busy\n", __func__, __LINE__); 544 "%s:%d Other DAI busy\n", __func__, __LINE__);
527 return -EAGAIN; 545 return -EAGAIN;
@@ -533,10 +551,9 @@ static int i2s_set_sysclk(struct snd_soc_dai *dai,
533 } 551 }
534 552
535 if (clk_id == 0) 553 if (clk_id == 0)
536 mod &= ~MOD_IMS_SYSMUX; 554 mod &= 0 << i2s_regs->rclksrc_off;
537 else 555 else
538 mod |= MOD_IMS_SYSMUX; 556 mod |= 1 << i2s_regs->rclksrc_off;
539 break;
540 557
541 default: 558 default:
542 dev_err(&i2s->pdev->dev, "We don't serve that!\n"); 559 dev_err(&i2s->pdev->dev, "We don't serve that!\n");
@@ -553,16 +570,12 @@ static int i2s_set_fmt(struct snd_soc_dai *dai,
553{ 570{
554 struct i2s_dai *i2s = to_info(dai); 571 struct i2s_dai *i2s = to_info(dai);
555 u32 mod = readl(i2s->addr + I2SMOD); 572 u32 mod = readl(i2s->addr + I2SMOD);
556 int lrp_shift, sdf_shift, sdf_mask, lrp_rlow; 573 int lrp_shift, sdf_shift, sdf_mask, lrp_rlow, mod_slave;
557 u32 tmp = 0; 574 u32 tmp = 0;
558 575
559 if (i2s->quirks & QUIRK_SUPPORTS_TDM) { 576 lrp_shift = i2s->variant_regs->lrp_off;
560 lrp_shift = EXYNOS5420_MOD_LRP_SHIFT; 577 sdf_shift = i2s->variant_regs->sdf_off;
561 sdf_shift = EXYNOS5420_MOD_SDF_SHIFT; 578 mod_slave = 1 << i2s->variant_regs->mss_off;
562 } else {
563 lrp_shift = MOD_LRP_SHIFT;
564 sdf_shift = MOD_SDF_SHIFT;
565 }
566 579
567 sdf_mask = MOD_SDF_MASK << sdf_shift; 580 sdf_mask = MOD_SDF_MASK << sdf_shift;
568 lrp_rlow = MOD_LR_RLOW << lrp_shift; 581 lrp_rlow = MOD_LR_RLOW << lrp_shift;
@@ -605,7 +618,7 @@ static int i2s_set_fmt(struct snd_soc_dai *dai,
605 618
606 switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { 619 switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
607 case SND_SOC_DAIFMT_CBM_CFM: 620 case SND_SOC_DAIFMT_CBM_CFM:
608 tmp |= MOD_SLAVE; 621 tmp |= mod_slave;
609 break; 622 break;
610 case SND_SOC_DAIFMT_CBS_CFS: 623 case SND_SOC_DAIFMT_CBS_CFS:
611 /* Set default source clock in Master mode */ 624 /* Set default source clock in Master mode */
@@ -623,13 +636,13 @@ static int i2s_set_fmt(struct snd_soc_dai *dai,
623 * channel. 636 * channel.
624 */ 637 */
625 if (any_active(i2s) && 638 if (any_active(i2s) &&
626 ((mod & (sdf_mask | lrp_rlow | MOD_SLAVE)) != tmp)) { 639 ((mod & (sdf_mask | lrp_rlow | mod_slave)) != tmp)) {
627 dev_err(&i2s->pdev->dev, 640 dev_err(&i2s->pdev->dev,
628 "%s:%d Other DAI busy\n", __func__, __LINE__); 641 "%s:%d Other DAI busy\n", __func__, __LINE__);
629 return -EAGAIN; 642 return -EAGAIN;
630 } 643 }
631 644
632 mod &= ~(sdf_mask | lrp_rlow | MOD_SLAVE); 645 mod &= ~(sdf_mask | lrp_rlow | mod_slave);
633 mod |= tmp; 646 mod |= tmp;
634 writel(mod, i2s->addr + I2SMOD); 647 writel(mod, i2s->addr + I2SMOD);
635 648
@@ -751,6 +764,7 @@ static void i2s_shutdown(struct snd_pcm_substream *substream,
751 struct i2s_dai *i2s = to_info(dai); 764 struct i2s_dai *i2s = to_info(dai);
752 struct i2s_dai *other = i2s->pri_dai ? : i2s->sec_dai; 765 struct i2s_dai *other = i2s->pri_dai ? : i2s->sec_dai;
753 unsigned long flags; 766 unsigned long flags;
767 const struct samsung_i2s_variant_regs *i2s_regs = i2s->variant_regs;
754 768
755 spin_lock_irqsave(&lock, flags); 769 spin_lock_irqsave(&lock, flags);
756 770
@@ -761,7 +775,7 @@ static void i2s_shutdown(struct snd_pcm_substream *substream,
761 other->mode |= DAI_MANAGER; 775 other->mode |= DAI_MANAGER;
762 } else { 776 } else {
763 u32 mod = readl(i2s->addr + I2SMOD); 777 u32 mod = readl(i2s->addr + I2SMOD);
764 i2s->cdclk_out = !(mod & MOD_CDCLKCON); 778 i2s->cdclk_out = !(mod & (1 << i2s_regs->cdclkcon_off));
765 if (other) 779 if (other)
766 other->cdclk_out = i2s->cdclk_out; 780 other->cdclk_out = i2s->cdclk_out;
767 } 781 }
@@ -914,13 +928,14 @@ i2s_delay(struct snd_pcm_substream *substream, struct snd_soc_dai *dai)
914 struct i2s_dai *i2s = to_info(dai); 928 struct i2s_dai *i2s = to_info(dai);
915 u32 reg = readl(i2s->addr + I2SFIC); 929 u32 reg = readl(i2s->addr + I2SFIC);
916 snd_pcm_sframes_t delay; 930 snd_pcm_sframes_t delay;
931 const struct samsung_i2s_variant_regs *i2s_regs = i2s->variant_regs;
917 932
918 if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) 933 if (substream->stream == SNDRV_PCM_STREAM_CAPTURE)
919 delay = FIC_RXCOUNT(reg); 934 delay = FIC_RXCOUNT(reg);
920 else if (is_secondary(i2s)) 935 else if (is_secondary(i2s))
921 delay = FICS_TXCOUNT(readl(i2s->addr + I2SFICS)); 936 delay = FICS_TXCOUNT(readl(i2s->addr + I2SFICS));
922 else 937 else
923 delay = FIC_TXCOUNT(reg); 938 delay = (reg >> i2s_regs->ftx0cnt_off) & 0x7f;
924 939
925 return delay; 940 return delay;
926} 941}
@@ -1227,6 +1242,7 @@ static int samsung_i2s_probe(struct platform_device *pdev)
1227 pri_dai->dma_capture.dma_size = 4; 1242 pri_dai->dma_capture.dma_size = 4;
1228 pri_dai->base = regs_base; 1243 pri_dai->base = regs_base;
1229 pri_dai->quirks = quirks; 1244 pri_dai->quirks = quirks;
1245 pri_dai->variant_regs = i2s_dai_data->i2s_variant_regs;
1230 1246
1231 if (quirks & QUIRK_PRI_6CHAN) 1247 if (quirks & QUIRK_PRI_6CHAN)
1232 pri_dai->i2s_dai_drv.playback.channels_max = 6; 1248 pri_dai->i2s_dai_drv.playback.channels_max = 6;
@@ -1301,21 +1317,93 @@ static int samsung_i2s_remove(struct platform_device *pdev)
1301 return 0; 1317 return 0;
1302} 1318}
1303 1319
1320static const struct samsung_i2s_variant_regs i2sv3_regs = {
1321 .bfs_off = 1,
1322 .rfs_off = 3,
1323 .sdf_off = 5,
1324 .txr_off = 8,
1325 .rclksrc_off = 10,
1326 .mss_off = 11,
1327 .cdclkcon_off = 12,
1328 .lrp_off = 7,
1329 .bfs_mask = 0x3,
1330 .rfs_mask = 0x3,
1331 .ftx0cnt_off = 8,
1332};
1333
1334static const struct samsung_i2s_variant_regs i2sv6_regs = {
1335 .bfs_off = 0,
1336 .rfs_off = 4,
1337 .sdf_off = 6,
1338 .txr_off = 8,
1339 .rclksrc_off = 10,
1340 .mss_off = 11,
1341 .cdclkcon_off = 12,
1342 .lrp_off = 15,
1343 .bfs_mask = 0xf,
1344 .rfs_mask = 0x3,
1345 .ftx0cnt_off = 8,
1346};
1347
1348static const struct samsung_i2s_variant_regs i2sv7_regs = {
1349 .bfs_off = 0,
1350 .rfs_off = 4,
1351 .sdf_off = 7,
1352 .txr_off = 9,
1353 .rclksrc_off = 11,
1354 .mss_off = 12,
1355 .cdclkcon_off = 22,
1356 .lrp_off = 15,
1357 .bfs_mask = 0xf,
1358 .rfs_mask = 0x7,
1359 .ftx0cnt_off = 0,
1360};
1361
1362static const struct samsung_i2s_variant_regs i2sv5_i2s1_regs = {
1363 .bfs_off = 0,
1364 .rfs_off = 3,
1365 .sdf_off = 6,
1366 .txr_off = 8,
1367 .rclksrc_off = 10,
1368 .mss_off = 11,
1369 .cdclkcon_off = 12,
1370 .lrp_off = 15,
1371 .bfs_mask = 0x7,
1372 .rfs_mask = 0x7,
1373 .ftx0cnt_off = 8,
1374};
1375
1304static const struct samsung_i2s_dai_data i2sv3_dai_type = { 1376static const struct samsung_i2s_dai_data i2sv3_dai_type = {
1305 .dai_type = TYPE_PRI, 1377 .dai_type = TYPE_PRI,
1306 .quirks = QUIRK_NO_MUXPSR, 1378 .quirks = QUIRK_NO_MUXPSR,
1379 .i2s_variant_regs = &i2sv3_regs,
1307}; 1380};
1308 1381
1309static const struct samsung_i2s_dai_data i2sv5_dai_type = { 1382static const struct samsung_i2s_dai_data i2sv5_dai_type = {
1310 .dai_type = TYPE_PRI, 1383 .dai_type = TYPE_PRI,
1311 .quirks = QUIRK_PRI_6CHAN | QUIRK_SEC_DAI | QUIRK_NEED_RSTCLR | 1384 .quirks = QUIRK_PRI_6CHAN | QUIRK_SEC_DAI | QUIRK_NEED_RSTCLR |
1312 QUIRK_SUPPORTS_IDMA, 1385 QUIRK_SUPPORTS_IDMA,
1386 .i2s_variant_regs = &i2sv3_regs,
1313}; 1387};
1314 1388
1315static const struct samsung_i2s_dai_data i2sv6_dai_type = { 1389static const struct samsung_i2s_dai_data i2sv6_dai_type = {
1316 .dai_type = TYPE_PRI, 1390 .dai_type = TYPE_PRI,
1317 .quirks = QUIRK_PRI_6CHAN | QUIRK_SEC_DAI | QUIRK_NEED_RSTCLR | 1391 .quirks = QUIRK_PRI_6CHAN | QUIRK_SEC_DAI | QUIRK_NEED_RSTCLR |
1318 QUIRK_SUPPORTS_TDM | QUIRK_SUPPORTS_IDMA, 1392 QUIRK_SUPPORTS_TDM | QUIRK_SUPPORTS_IDMA,
1393 .i2s_variant_regs = &i2sv6_regs,
1394};
1395
1396static const struct samsung_i2s_dai_data i2sv7_dai_type = {
1397 .dai_type = TYPE_PRI,
1398 .quirks = QUIRK_PRI_6CHAN | QUIRK_SEC_DAI | QUIRK_NEED_RSTCLR |
1399 QUIRK_SUPPORTS_TDM,
1400 .i2s_variant_regs = &i2sv7_regs,
1401};
1402
1403static const struct samsung_i2s_dai_data i2sv5_dai_type_i2s1 = {
1404 .dai_type = TYPE_PRI,
1405 .quirks = QUIRK_PRI_6CHAN | QUIRK_NEED_RSTCLR,
1406 .i2s_variant_regs = &i2sv5_i2s1_regs,
1319}; 1407};
1320 1408
1321static const struct samsung_i2s_dai_data samsung_dai_type_pri = { 1409static const struct samsung_i2s_dai_data samsung_dai_type_pri = {
@@ -1349,6 +1437,12 @@ static const struct of_device_id exynos_i2s_match[] = {
1349 }, { 1437 }, {
1350 .compatible = "samsung,exynos5420-i2s", 1438 .compatible = "samsung,exynos5420-i2s",
1351 .data = &i2sv6_dai_type, 1439 .data = &i2sv6_dai_type,
1440 }, {
1441 .compatible = "samsung,exynos7-i2s",
1442 .data = &i2sv7_dai_type,
1443 }, {
1444 .compatible = "samsung,exynos7-i2s1",
1445 .data = &i2sv5_dai_type_i2s1,
1352 }, 1446 },
1353 {}, 1447 {},
1354}; 1448};