.. | .. |
---|
1 | | -/* sound/soc/samsung/i2s.c |
---|
2 | | - * |
---|
3 | | - * ALSA SoC Audio Layer - Samsung I2S Controller driver |
---|
4 | | - * |
---|
5 | | - * Copyright (c) 2010 Samsung Electronics Co. Ltd. |
---|
6 | | - * Jaswinder Singh <jassisinghbrar@gmail.com> |
---|
7 | | - * |
---|
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 | | - */ |
---|
| 1 | +// SPDX-License-Identifier: GPL-2.0 |
---|
| 2 | +// |
---|
| 3 | +// ALSA SoC Audio Layer - Samsung I2S Controller driver |
---|
| 4 | +// |
---|
| 5 | +// Copyright (c) 2010 Samsung Electronics Co. Ltd. |
---|
| 6 | +// Jaswinder Singh <jassisinghbrar@gmail.com> |
---|
12 | 7 | |
---|
13 | 8 | #include <dt-bindings/sound/samsung-i2s.h> |
---|
14 | 9 | #include <linux/delay.h> |
---|
.. | .. |
---|
34 | 29 | |
---|
35 | 30 | #define msecs_to_loops(t) (loops_per_jiffy / 1000 * HZ * t) |
---|
36 | 31 | |
---|
| 32 | +#define SAMSUNG_I2S_ID_PRIMARY 1 |
---|
| 33 | +#define SAMSUNG_I2S_ID_SECONDARY 2 |
---|
| 34 | + |
---|
37 | 35 | struct samsung_i2s_variant_regs { |
---|
38 | 36 | unsigned int bfs_off; |
---|
39 | 37 | unsigned int rfs_off; |
---|
.. | .. |
---|
57 | 55 | struct i2s_dai { |
---|
58 | 56 | /* Platform device for this DAI */ |
---|
59 | 57 | struct platform_device *pdev; |
---|
60 | | - /* Memory mapped SFR region */ |
---|
61 | | - void __iomem *addr; |
---|
62 | | - /* Rate of RCLK source clock */ |
---|
63 | | - unsigned long rclk_srcrate; |
---|
64 | | - /* Frame Clock */ |
---|
| 58 | + |
---|
| 59 | + /* Frame clock */ |
---|
65 | 60 | unsigned frmclk; |
---|
66 | 61 | /* |
---|
67 | | - * Specifically requested RCLK,BCLK by MACHINE Driver. |
---|
| 62 | + * Specifically requested RCLK, BCLK by machine driver. |
---|
68 | 63 | * 0 indicates CPU driver is free to choose any value. |
---|
69 | 64 | */ |
---|
70 | 65 | unsigned rfs, bfs; |
---|
71 | | - /* I2S Controller's core clock */ |
---|
72 | | - struct clk *clk; |
---|
73 | | - /* Clock for generating I2S signals */ |
---|
74 | | - struct clk *op_clk; |
---|
75 | 66 | /* Pointer to the Primary_Fifo if this is Sec_Fifo, NULL otherwise */ |
---|
76 | 67 | struct i2s_dai *pri_dai; |
---|
77 | 68 | /* Pointer to the Secondary_Fifo if it has one, NULL otherwise */ |
---|
78 | 69 | struct i2s_dai *sec_dai; |
---|
79 | | -#define DAI_OPENED (1 << 0) /* Dai is opened */ |
---|
80 | | -#define DAI_MANAGER (1 << 1) /* Dai is the manager */ |
---|
| 70 | + |
---|
| 71 | +#define DAI_OPENED (1 << 0) /* DAI is opened */ |
---|
| 72 | +#define DAI_MANAGER (1 << 1) /* DAI is the manager */ |
---|
81 | 73 | unsigned mode; |
---|
| 74 | + |
---|
82 | 75 | /* Driver for this DAI */ |
---|
83 | | - struct snd_soc_dai_driver i2s_dai_drv; |
---|
| 76 | + struct snd_soc_dai_driver *drv; |
---|
| 77 | + |
---|
84 | 78 | /* DMA parameters */ |
---|
85 | 79 | struct snd_dmaengine_dai_dma_data dma_playback; |
---|
86 | 80 | struct snd_dmaengine_dai_dma_data dma_capture; |
---|
87 | 81 | struct snd_dmaengine_dai_dma_data idma_playback; |
---|
88 | 82 | dma_filter_fn filter; |
---|
89 | | - u32 quirks; |
---|
90 | | - u32 suspend_i2smod; |
---|
91 | | - u32 suspend_i2scon; |
---|
92 | | - u32 suspend_i2spsr; |
---|
93 | | - const struct samsung_i2s_variant_regs *variant_regs; |
---|
94 | 83 | |
---|
95 | | - /* Spinlock protecting access to the device's registers */ |
---|
96 | | - spinlock_t spinlock; |
---|
97 | | - spinlock_t *lock; |
---|
98 | | - |
---|
99 | | - /* Below fields are only valid if this is the primary FIFO */ |
---|
100 | | - struct clk *clk_table[3]; |
---|
101 | | - struct clk_onecell_data clk_data; |
---|
| 84 | + struct samsung_i2s_priv *priv; |
---|
102 | 85 | }; |
---|
103 | 86 | |
---|
104 | | -/* Lock for cross i/f checks */ |
---|
105 | | -static DEFINE_SPINLOCK(lock); |
---|
| 87 | +struct samsung_i2s_priv { |
---|
| 88 | + struct platform_device *pdev; |
---|
| 89 | + struct platform_device *pdev_sec; |
---|
106 | 90 | |
---|
107 | | -/* If this is the 'overlay' stereo DAI */ |
---|
| 91 | + /* Lock for cross interface checks */ |
---|
| 92 | + spinlock_t pcm_lock; |
---|
| 93 | + |
---|
| 94 | + /* CPU DAIs and their corresponding drivers */ |
---|
| 95 | + struct i2s_dai *dai; |
---|
| 96 | + struct snd_soc_dai_driver *dai_drv; |
---|
| 97 | + int num_dais; |
---|
| 98 | + |
---|
| 99 | + /* The I2S controller's core clock */ |
---|
| 100 | + struct clk *clk; |
---|
| 101 | + |
---|
| 102 | + /* Clock for generating I2S signals */ |
---|
| 103 | + struct clk *op_clk; |
---|
| 104 | + |
---|
| 105 | + /* Rate of RCLK source clock */ |
---|
| 106 | + unsigned long rclk_srcrate; |
---|
| 107 | + |
---|
| 108 | + /* Cache of selected I2S registers for system suspend */ |
---|
| 109 | + u32 suspend_i2smod; |
---|
| 110 | + u32 suspend_i2scon; |
---|
| 111 | + u32 suspend_i2spsr; |
---|
| 112 | + |
---|
| 113 | + const struct samsung_i2s_variant_regs *variant_regs; |
---|
| 114 | + u32 quirks; |
---|
| 115 | + |
---|
| 116 | + /* The clock provider's data */ |
---|
| 117 | + struct clk *clk_table[3]; |
---|
| 118 | + struct clk_onecell_data clk_data; |
---|
| 119 | + |
---|
| 120 | + /* Spinlock protecting member fields below */ |
---|
| 121 | + spinlock_t lock; |
---|
| 122 | + |
---|
| 123 | + /* Memory mapped SFR region */ |
---|
| 124 | + void __iomem *addr; |
---|
| 125 | + |
---|
| 126 | + /* A flag indicating the I2S slave mode operation */ |
---|
| 127 | + bool slave_mode; |
---|
| 128 | +}; |
---|
| 129 | + |
---|
| 130 | +/* Returns true if this is the 'overlay' stereo DAI */ |
---|
108 | 131 | static inline bool is_secondary(struct i2s_dai *i2s) |
---|
109 | 132 | { |
---|
110 | | - return i2s->pri_dai ? true : false; |
---|
111 | | -} |
---|
112 | | - |
---|
113 | | -/* If operating in SoC-Slave mode */ |
---|
114 | | -static inline bool is_slave(struct i2s_dai *i2s) |
---|
115 | | -{ |
---|
116 | | - u32 mod = readl(i2s->addr + I2SMOD); |
---|
117 | | - return (mod & (1 << i2s->variant_regs->mss_off)) ? true : false; |
---|
| 133 | + return i2s->drv->id == SAMSUNG_I2S_ID_SECONDARY; |
---|
118 | 134 | } |
---|
119 | 135 | |
---|
120 | 136 | /* If this interface of the controller is transmitting data */ |
---|
.. | .. |
---|
125 | 141 | if (!i2s) |
---|
126 | 142 | return false; |
---|
127 | 143 | |
---|
128 | | - active = readl(i2s->addr + I2SCON); |
---|
| 144 | + active = readl(i2s->priv->addr + I2SCON); |
---|
129 | 145 | |
---|
130 | 146 | if (is_secondary(i2s)) |
---|
131 | 147 | active &= CON_TXSDMA_ACTIVE; |
---|
.. | .. |
---|
163 | 179 | if (!i2s) |
---|
164 | 180 | return false; |
---|
165 | 181 | |
---|
166 | | - active = readl(i2s->addr + I2SCON) & CON_RXDMA_ACTIVE; |
---|
| 182 | + active = readl(i2s->priv->addr + I2SCON) & CON_RXDMA_ACTIVE; |
---|
167 | 183 | |
---|
168 | 184 | return active ? true : false; |
---|
169 | 185 | } |
---|
.. | .. |
---|
202 | 218 | |
---|
203 | 219 | static inline struct i2s_dai *to_info(struct snd_soc_dai *dai) |
---|
204 | 220 | { |
---|
205 | | - return snd_soc_dai_get_drvdata(dai); |
---|
| 221 | + struct samsung_i2s_priv *priv = snd_soc_dai_get_drvdata(dai); |
---|
| 222 | + |
---|
| 223 | + return &priv->dai[dai->id - 1]; |
---|
206 | 224 | } |
---|
207 | 225 | |
---|
208 | 226 | static inline bool is_opened(struct i2s_dai *i2s) |
---|
.. | .. |
---|
224 | 242 | /* Read RCLK of I2S (in multiples of LRCLK) */ |
---|
225 | 243 | static inline unsigned get_rfs(struct i2s_dai *i2s) |
---|
226 | 244 | { |
---|
| 245 | + struct samsung_i2s_priv *priv = i2s->priv; |
---|
227 | 246 | u32 rfs; |
---|
228 | | - rfs = readl(i2s->addr + I2SMOD) >> i2s->variant_regs->rfs_off; |
---|
229 | | - rfs &= i2s->variant_regs->rfs_mask; |
---|
| 247 | + |
---|
| 248 | + rfs = readl(priv->addr + I2SMOD) >> priv->variant_regs->rfs_off; |
---|
| 249 | + rfs &= priv->variant_regs->rfs_mask; |
---|
230 | 250 | |
---|
231 | 251 | switch (rfs) { |
---|
232 | 252 | case 7: return 192; |
---|
.. | .. |
---|
243 | 263 | /* Write RCLK of I2S (in multiples of LRCLK) */ |
---|
244 | 264 | static inline void set_rfs(struct i2s_dai *i2s, unsigned rfs) |
---|
245 | 265 | { |
---|
246 | | - u32 mod = readl(i2s->addr + I2SMOD); |
---|
247 | | - int rfs_shift = i2s->variant_regs->rfs_off; |
---|
| 266 | + struct samsung_i2s_priv *priv = i2s->priv; |
---|
| 267 | + u32 mod = readl(priv->addr + I2SMOD); |
---|
| 268 | + int rfs_shift = priv->variant_regs->rfs_off; |
---|
248 | 269 | |
---|
249 | | - mod &= ~(i2s->variant_regs->rfs_mask << rfs_shift); |
---|
| 270 | + mod &= ~(priv->variant_regs->rfs_mask << rfs_shift); |
---|
250 | 271 | |
---|
251 | 272 | switch (rfs) { |
---|
252 | 273 | case 192: |
---|
.. | .. |
---|
275 | 296 | break; |
---|
276 | 297 | } |
---|
277 | 298 | |
---|
278 | | - writel(mod, i2s->addr + I2SMOD); |
---|
| 299 | + writel(mod, priv->addr + I2SMOD); |
---|
279 | 300 | } |
---|
280 | 301 | |
---|
281 | | -/* Read Bit-Clock of I2S (in multiples of LRCLK) */ |
---|
| 302 | +/* Read bit-clock of I2S (in multiples of LRCLK) */ |
---|
282 | 303 | static inline unsigned get_bfs(struct i2s_dai *i2s) |
---|
283 | 304 | { |
---|
| 305 | + struct samsung_i2s_priv *priv = i2s->priv; |
---|
284 | 306 | u32 bfs; |
---|
285 | | - bfs = readl(i2s->addr + I2SMOD) >> i2s->variant_regs->bfs_off; |
---|
286 | | - bfs &= i2s->variant_regs->bfs_mask; |
---|
| 307 | + |
---|
| 308 | + bfs = readl(priv->addr + I2SMOD) >> priv->variant_regs->bfs_off; |
---|
| 309 | + bfs &= priv->variant_regs->bfs_mask; |
---|
287 | 310 | |
---|
288 | 311 | switch (bfs) { |
---|
289 | 312 | case 8: return 256; |
---|
.. | .. |
---|
298 | 321 | } |
---|
299 | 322 | } |
---|
300 | 323 | |
---|
301 | | -/* Write Bit-Clock of I2S (in multiples of LRCLK) */ |
---|
| 324 | +/* Write bit-clock of I2S (in multiples of LRCLK) */ |
---|
302 | 325 | static inline void set_bfs(struct i2s_dai *i2s, unsigned bfs) |
---|
303 | 326 | { |
---|
304 | | - u32 mod = readl(i2s->addr + I2SMOD); |
---|
305 | | - int tdm = i2s->quirks & QUIRK_SUPPORTS_TDM; |
---|
306 | | - int bfs_shift = i2s->variant_regs->bfs_off; |
---|
| 327 | + struct samsung_i2s_priv *priv = i2s->priv; |
---|
| 328 | + u32 mod = readl(priv->addr + I2SMOD); |
---|
| 329 | + int tdm = priv->quirks & QUIRK_SUPPORTS_TDM; |
---|
| 330 | + int bfs_shift = priv->variant_regs->bfs_off; |
---|
307 | 331 | |
---|
308 | 332 | /* Non-TDM I2S controllers do not support BCLK > 48 * FS */ |
---|
309 | 333 | if (!tdm && bfs > 48) { |
---|
.. | .. |
---|
311 | 335 | return; |
---|
312 | 336 | } |
---|
313 | 337 | |
---|
314 | | - mod &= ~(i2s->variant_regs->bfs_mask << bfs_shift); |
---|
| 338 | + mod &= ~(priv->variant_regs->bfs_mask << bfs_shift); |
---|
315 | 339 | |
---|
316 | 340 | switch (bfs) { |
---|
317 | 341 | case 48: |
---|
.. | .. |
---|
346 | 370 | return; |
---|
347 | 371 | } |
---|
348 | 372 | |
---|
349 | | - writel(mod, i2s->addr + I2SMOD); |
---|
| 373 | + writel(mod, priv->addr + I2SMOD); |
---|
350 | 374 | } |
---|
351 | 375 | |
---|
352 | | -/* Sample-Size */ |
---|
| 376 | +/* Sample size */ |
---|
353 | 377 | static inline int get_blc(struct i2s_dai *i2s) |
---|
354 | 378 | { |
---|
355 | | - int blc = readl(i2s->addr + I2SMOD); |
---|
| 379 | + int blc = readl(i2s->priv->addr + I2SMOD); |
---|
356 | 380 | |
---|
357 | 381 | blc = (blc >> 13) & 0x3; |
---|
358 | 382 | |
---|
.. | .. |
---|
363 | 387 | } |
---|
364 | 388 | } |
---|
365 | 389 | |
---|
366 | | -/* TX Channel Control */ |
---|
| 390 | +/* TX channel control */ |
---|
367 | 391 | static void i2s_txctrl(struct i2s_dai *i2s, int on) |
---|
368 | 392 | { |
---|
369 | | - void __iomem *addr = i2s->addr; |
---|
370 | | - int txr_off = i2s->variant_regs->txr_off; |
---|
| 393 | + struct samsung_i2s_priv *priv = i2s->priv; |
---|
| 394 | + void __iomem *addr = priv->addr; |
---|
| 395 | + int txr_off = priv->variant_regs->txr_off; |
---|
371 | 396 | u32 con = readl(addr + I2SCON); |
---|
372 | 397 | u32 mod = readl(addr + I2SMOD) & ~(3 << txr_off); |
---|
373 | 398 | |
---|
.. | .. |
---|
416 | 441 | /* RX Channel Control */ |
---|
417 | 442 | static void i2s_rxctrl(struct i2s_dai *i2s, int on) |
---|
418 | 443 | { |
---|
419 | | - void __iomem *addr = i2s->addr; |
---|
420 | | - int txr_off = i2s->variant_regs->txr_off; |
---|
| 444 | + struct samsung_i2s_priv *priv = i2s->priv; |
---|
| 445 | + void __iomem *addr = priv->addr; |
---|
| 446 | + int txr_off = priv->variant_regs->txr_off; |
---|
421 | 447 | u32 con = readl(addr + I2SCON); |
---|
422 | 448 | u32 mod = readl(addr + I2SMOD) & ~(3 << txr_off); |
---|
423 | 449 | |
---|
.. | .. |
---|
453 | 479 | return; |
---|
454 | 480 | |
---|
455 | 481 | if (is_secondary(i2s)) |
---|
456 | | - fic = i2s->addr + I2SFICS; |
---|
| 482 | + fic = i2s->priv->addr + I2SFICS; |
---|
457 | 483 | else |
---|
458 | | - fic = i2s->addr + I2SFIC; |
---|
| 484 | + fic = i2s->priv->addr + I2SFIC; |
---|
459 | 485 | |
---|
460 | 486 | /* Flush the FIFO */ |
---|
461 | 487 | writel(readl(fic) | flush, fic); |
---|
.. | .. |
---|
468 | 494 | writel(readl(fic) & ~flush, fic); |
---|
469 | 495 | } |
---|
470 | 496 | |
---|
471 | | -static int i2s_set_sysclk(struct snd_soc_dai *dai, |
---|
472 | | - int clk_id, unsigned int rfs, int dir) |
---|
| 497 | +static int i2s_set_sysclk(struct snd_soc_dai *dai, int clk_id, unsigned int rfs, |
---|
| 498 | + int dir) |
---|
473 | 499 | { |
---|
| 500 | + struct samsung_i2s_priv *priv = snd_soc_dai_get_drvdata(dai); |
---|
474 | 501 | struct i2s_dai *i2s = to_info(dai); |
---|
475 | 502 | struct i2s_dai *other = get_other_dai(i2s); |
---|
476 | | - const struct samsung_i2s_variant_regs *i2s_regs = i2s->variant_regs; |
---|
| 503 | + const struct samsung_i2s_variant_regs *i2s_regs = priv->variant_regs; |
---|
477 | 504 | unsigned int cdcon_mask = 1 << i2s_regs->cdclkcon_off; |
---|
478 | 505 | unsigned int rsrc_mask = 1 << i2s_regs->rclksrc_off; |
---|
479 | 506 | u32 mod, mask, val = 0; |
---|
.. | .. |
---|
482 | 509 | |
---|
483 | 510 | pm_runtime_get_sync(dai->dev); |
---|
484 | 511 | |
---|
485 | | - spin_lock_irqsave(i2s->lock, flags); |
---|
486 | | - mod = readl(i2s->addr + I2SMOD); |
---|
487 | | - spin_unlock_irqrestore(i2s->lock, flags); |
---|
| 512 | + spin_lock_irqsave(&priv->lock, flags); |
---|
| 513 | + mod = readl(priv->addr + I2SMOD); |
---|
| 514 | + spin_unlock_irqrestore(&priv->lock, flags); |
---|
488 | 515 | |
---|
489 | 516 | switch (clk_id) { |
---|
490 | 517 | case SAMSUNG_I2S_OPCLK: |
---|
.. | .. |
---|
519 | 546 | case SAMSUNG_I2S_RCLKSRC_1: /* clock corrsponding to IISMOD[10] := 1 */ |
---|
520 | 547 | mask = 1 << i2s_regs->rclksrc_off; |
---|
521 | 548 | |
---|
522 | | - if ((i2s->quirks & QUIRK_NO_MUXPSR) |
---|
| 549 | + if ((priv->quirks & QUIRK_NO_MUXPSR) |
---|
523 | 550 | || (clk_id == SAMSUNG_I2S_RCLKSRC_0)) |
---|
524 | 551 | clk_id = 0; |
---|
525 | 552 | else |
---|
526 | 553 | clk_id = 1; |
---|
527 | 554 | |
---|
528 | 555 | if (!any_active(i2s)) { |
---|
529 | | - if (i2s->op_clk && !IS_ERR(i2s->op_clk)) { |
---|
| 556 | + if (priv->op_clk && !IS_ERR(priv->op_clk)) { |
---|
530 | 557 | if ((clk_id && !(mod & rsrc_mask)) || |
---|
531 | 558 | (!clk_id && (mod & rsrc_mask))) { |
---|
532 | | - clk_disable_unprepare(i2s->op_clk); |
---|
533 | | - clk_put(i2s->op_clk); |
---|
| 559 | + clk_disable_unprepare(priv->op_clk); |
---|
| 560 | + clk_put(priv->op_clk); |
---|
534 | 561 | } else { |
---|
535 | | - i2s->rclk_srcrate = |
---|
536 | | - clk_get_rate(i2s->op_clk); |
---|
| 562 | + priv->rclk_srcrate = |
---|
| 563 | + clk_get_rate(priv->op_clk); |
---|
537 | 564 | goto done; |
---|
538 | 565 | } |
---|
539 | 566 | } |
---|
540 | 567 | |
---|
541 | 568 | if (clk_id) |
---|
542 | | - i2s->op_clk = clk_get(&i2s->pdev->dev, |
---|
| 569 | + priv->op_clk = clk_get(&i2s->pdev->dev, |
---|
543 | 570 | "i2s_opclk1"); |
---|
544 | 571 | else |
---|
545 | | - i2s->op_clk = clk_get(&i2s->pdev->dev, |
---|
| 572 | + priv->op_clk = clk_get(&i2s->pdev->dev, |
---|
546 | 573 | "i2s_opclk0"); |
---|
547 | 574 | |
---|
548 | | - if (WARN_ON(IS_ERR(i2s->op_clk))) { |
---|
549 | | - ret = PTR_ERR(i2s->op_clk); |
---|
550 | | - i2s->op_clk = NULL; |
---|
| 575 | + if (WARN_ON(IS_ERR(priv->op_clk))) { |
---|
| 576 | + ret = PTR_ERR(priv->op_clk); |
---|
| 577 | + priv->op_clk = NULL; |
---|
551 | 578 | goto err; |
---|
552 | 579 | } |
---|
553 | 580 | |
---|
554 | | - ret = clk_prepare_enable(i2s->op_clk); |
---|
| 581 | + ret = clk_prepare_enable(priv->op_clk); |
---|
555 | 582 | if (ret) { |
---|
556 | | - clk_put(i2s->op_clk); |
---|
557 | | - i2s->op_clk = NULL; |
---|
| 583 | + clk_put(priv->op_clk); |
---|
| 584 | + priv->op_clk = NULL; |
---|
558 | 585 | goto err; |
---|
559 | 586 | } |
---|
560 | | - i2s->rclk_srcrate = clk_get_rate(i2s->op_clk); |
---|
| 587 | + priv->rclk_srcrate = clk_get_rate(priv->op_clk); |
---|
561 | 588 | |
---|
562 | | - /* Over-ride the other's */ |
---|
563 | | - if (other) { |
---|
564 | | - other->op_clk = i2s->op_clk; |
---|
565 | | - other->rclk_srcrate = i2s->rclk_srcrate; |
---|
566 | | - } |
---|
567 | 589 | } else if ((!clk_id && (mod & rsrc_mask)) |
---|
568 | 590 | || (clk_id && !(mod & rsrc_mask))) { |
---|
569 | 591 | dev_err(&i2s->pdev->dev, |
---|
.. | .. |
---|
572 | 594 | goto err; |
---|
573 | 595 | } else { |
---|
574 | 596 | /* Call can't be on the active DAI */ |
---|
575 | | - i2s->op_clk = other->op_clk; |
---|
576 | | - i2s->rclk_srcrate = other->rclk_srcrate; |
---|
577 | 597 | goto done; |
---|
578 | 598 | } |
---|
579 | 599 | |
---|
.. | .. |
---|
586 | 606 | goto err; |
---|
587 | 607 | } |
---|
588 | 608 | |
---|
589 | | - spin_lock_irqsave(i2s->lock, flags); |
---|
590 | | - mod = readl(i2s->addr + I2SMOD); |
---|
| 609 | + spin_lock_irqsave(&priv->lock, flags); |
---|
| 610 | + mod = readl(priv->addr + I2SMOD); |
---|
591 | 611 | mod = (mod & ~mask) | val; |
---|
592 | | - writel(mod, i2s->addr + I2SMOD); |
---|
593 | | - spin_unlock_irqrestore(i2s->lock, flags); |
---|
| 612 | + writel(mod, priv->addr + I2SMOD); |
---|
| 613 | + spin_unlock_irqrestore(&priv->lock, flags); |
---|
594 | 614 | done: |
---|
595 | 615 | pm_runtime_put(dai->dev); |
---|
596 | 616 | |
---|
.. | .. |
---|
600 | 620 | return ret; |
---|
601 | 621 | } |
---|
602 | 622 | |
---|
603 | | -static int i2s_set_fmt(struct snd_soc_dai *dai, |
---|
604 | | - unsigned int fmt) |
---|
| 623 | +static int i2s_set_fmt(struct snd_soc_dai *dai, unsigned int fmt) |
---|
605 | 624 | { |
---|
| 625 | + struct samsung_i2s_priv *priv = snd_soc_dai_get_drvdata(dai); |
---|
606 | 626 | struct i2s_dai *i2s = to_info(dai); |
---|
607 | | - struct i2s_dai *other = get_other_dai(i2s); |
---|
608 | 627 | int lrp_shift, sdf_shift, sdf_mask, lrp_rlow, mod_slave; |
---|
609 | 628 | u32 mod, tmp = 0; |
---|
610 | 629 | unsigned long flags; |
---|
611 | 630 | |
---|
612 | | - lrp_shift = i2s->variant_regs->lrp_off; |
---|
613 | | - sdf_shift = i2s->variant_regs->sdf_off; |
---|
614 | | - mod_slave = 1 << i2s->variant_regs->mss_off; |
---|
| 631 | + lrp_shift = priv->variant_regs->lrp_off; |
---|
| 632 | + sdf_shift = priv->variant_regs->sdf_off; |
---|
| 633 | + mod_slave = 1 << priv->variant_regs->mss_off; |
---|
615 | 634 | |
---|
616 | 635 | sdf_mask = MOD_SDF_MASK << sdf_shift; |
---|
617 | 636 | lrp_rlow = MOD_LR_RLOW << lrp_shift; |
---|
.. | .. |
---|
662 | 681 | * CLK_I2S_RCLK_SRC clock is not exposed so we ensure any |
---|
663 | 682 | * clock configuration assigned in DT is not overwritten. |
---|
664 | 683 | */ |
---|
665 | | - if (i2s->rclk_srcrate == 0 && i2s->clk_data.clks == NULL && |
---|
666 | | - other->clk_data.clks == NULL) |
---|
| 684 | + if (priv->rclk_srcrate == 0 && priv->clk_data.clks == NULL) |
---|
667 | 685 | i2s_set_sysclk(dai, SAMSUNG_I2S_RCLKSRC_0, |
---|
668 | 686 | 0, SND_SOC_CLOCK_IN); |
---|
669 | 687 | break; |
---|
.. | .. |
---|
673 | 691 | } |
---|
674 | 692 | |
---|
675 | 693 | pm_runtime_get_sync(dai->dev); |
---|
676 | | - spin_lock_irqsave(i2s->lock, flags); |
---|
677 | | - mod = readl(i2s->addr + I2SMOD); |
---|
| 694 | + spin_lock_irqsave(&priv->lock, flags); |
---|
| 695 | + mod = readl(priv->addr + I2SMOD); |
---|
678 | 696 | /* |
---|
679 | 697 | * Don't change the I2S mode if any controller is active on this |
---|
680 | 698 | * channel. |
---|
681 | 699 | */ |
---|
682 | 700 | if (any_active(i2s) && |
---|
683 | 701 | ((mod & (sdf_mask | lrp_rlow | mod_slave)) != tmp)) { |
---|
684 | | - spin_unlock_irqrestore(i2s->lock, flags); |
---|
| 702 | + spin_unlock_irqrestore(&priv->lock, flags); |
---|
685 | 703 | pm_runtime_put(dai->dev); |
---|
686 | 704 | dev_err(&i2s->pdev->dev, |
---|
687 | 705 | "%s:%d Other DAI busy\n", __func__, __LINE__); |
---|
.. | .. |
---|
690 | 708 | |
---|
691 | 709 | mod &= ~(sdf_mask | lrp_rlow | mod_slave); |
---|
692 | 710 | mod |= tmp; |
---|
693 | | - writel(mod, i2s->addr + I2SMOD); |
---|
694 | | - spin_unlock_irqrestore(i2s->lock, flags); |
---|
| 711 | + writel(mod, priv->addr + I2SMOD); |
---|
| 712 | + priv->slave_mode = (mod & mod_slave); |
---|
| 713 | + spin_unlock_irqrestore(&priv->lock, flags); |
---|
695 | 714 | pm_runtime_put(dai->dev); |
---|
696 | 715 | |
---|
697 | 716 | return 0; |
---|
.. | .. |
---|
700 | 719 | static int i2s_hw_params(struct snd_pcm_substream *substream, |
---|
701 | 720 | struct snd_pcm_hw_params *params, struct snd_soc_dai *dai) |
---|
702 | 721 | { |
---|
| 722 | + struct samsung_i2s_priv *priv = snd_soc_dai_get_drvdata(dai); |
---|
703 | 723 | struct i2s_dai *i2s = to_info(dai); |
---|
704 | | - struct i2s_dai *other = get_other_dai(i2s); |
---|
705 | 724 | u32 mod, mask = 0, val = 0; |
---|
706 | 725 | struct clk *rclksrc; |
---|
707 | 726 | unsigned long flags; |
---|
.. | .. |
---|
714 | 733 | switch (params_channels(params)) { |
---|
715 | 734 | case 6: |
---|
716 | 735 | val |= MOD_DC2_EN; |
---|
717 | | - /* fall through */ |
---|
| 736 | + fallthrough; |
---|
718 | 737 | case 4: |
---|
719 | 738 | val |= MOD_DC1_EN; |
---|
720 | 739 | break; |
---|
.. | .. |
---|
776 | 795 | return -EINVAL; |
---|
777 | 796 | } |
---|
778 | 797 | |
---|
779 | | - spin_lock_irqsave(i2s->lock, flags); |
---|
780 | | - mod = readl(i2s->addr + I2SMOD); |
---|
| 798 | + spin_lock_irqsave(&priv->lock, flags); |
---|
| 799 | + mod = readl(priv->addr + I2SMOD); |
---|
781 | 800 | mod = (mod & ~mask) | val; |
---|
782 | | - writel(mod, i2s->addr + I2SMOD); |
---|
783 | | - spin_unlock_irqrestore(i2s->lock, flags); |
---|
| 801 | + writel(mod, priv->addr + I2SMOD); |
---|
| 802 | + spin_unlock_irqrestore(&priv->lock, flags); |
---|
784 | 803 | |
---|
785 | 804 | snd_soc_dai_init_dma_data(dai, &i2s->dma_playback, &i2s->dma_capture); |
---|
786 | 805 | |
---|
787 | 806 | i2s->frmclk = params_rate(params); |
---|
788 | 807 | |
---|
789 | | - rclksrc = i2s->clk_table[CLK_I2S_RCLK_SRC]; |
---|
790 | | - if (!rclksrc || IS_ERR(rclksrc)) |
---|
791 | | - rclksrc = other->clk_table[CLK_I2S_RCLK_SRC]; |
---|
792 | | - |
---|
| 808 | + rclksrc = priv->clk_table[CLK_I2S_RCLK_SRC]; |
---|
793 | 809 | if (rclksrc && !IS_ERR(rclksrc)) |
---|
794 | | - i2s->rclk_srcrate = clk_get_rate(rclksrc); |
---|
| 810 | + priv->rclk_srcrate = clk_get_rate(rclksrc); |
---|
795 | 811 | |
---|
796 | 812 | return 0; |
---|
797 | 813 | } |
---|
798 | 814 | |
---|
799 | | -/* We set constraints on the substream acc to the version of I2S */ |
---|
| 815 | +/* We set constraints on the substream according to the version of I2S */ |
---|
800 | 816 | static int i2s_startup(struct snd_pcm_substream *substream, |
---|
801 | 817 | struct snd_soc_dai *dai) |
---|
802 | 818 | { |
---|
| 819 | + struct samsung_i2s_priv *priv = snd_soc_dai_get_drvdata(dai); |
---|
803 | 820 | struct i2s_dai *i2s = to_info(dai); |
---|
804 | 821 | struct i2s_dai *other = get_other_dai(i2s); |
---|
805 | 822 | unsigned long flags; |
---|
806 | 823 | |
---|
807 | 824 | pm_runtime_get_sync(dai->dev); |
---|
808 | 825 | |
---|
809 | | - spin_lock_irqsave(&lock, flags); |
---|
| 826 | + spin_lock_irqsave(&priv->pcm_lock, flags); |
---|
810 | 827 | |
---|
811 | 828 | i2s->mode |= DAI_OPENED; |
---|
812 | 829 | |
---|
.. | .. |
---|
815 | 832 | else |
---|
816 | 833 | i2s->mode |= DAI_MANAGER; |
---|
817 | 834 | |
---|
818 | | - if (!any_active(i2s) && (i2s->quirks & QUIRK_NEED_RSTCLR)) |
---|
819 | | - writel(CON_RSTCLR, i2s->addr + I2SCON); |
---|
| 835 | + if (!any_active(i2s) && (priv->quirks & QUIRK_NEED_RSTCLR)) |
---|
| 836 | + writel(CON_RSTCLR, i2s->priv->addr + I2SCON); |
---|
820 | 837 | |
---|
821 | | - spin_unlock_irqrestore(&lock, flags); |
---|
| 838 | + spin_unlock_irqrestore(&priv->pcm_lock, flags); |
---|
822 | 839 | |
---|
823 | 840 | return 0; |
---|
824 | 841 | } |
---|
.. | .. |
---|
826 | 843 | static void i2s_shutdown(struct snd_pcm_substream *substream, |
---|
827 | 844 | struct snd_soc_dai *dai) |
---|
828 | 845 | { |
---|
| 846 | + struct samsung_i2s_priv *priv = snd_soc_dai_get_drvdata(dai); |
---|
829 | 847 | struct i2s_dai *i2s = to_info(dai); |
---|
830 | 848 | struct i2s_dai *other = get_other_dai(i2s); |
---|
831 | 849 | unsigned long flags; |
---|
832 | 850 | |
---|
833 | | - spin_lock_irqsave(&lock, flags); |
---|
| 851 | + spin_lock_irqsave(&priv->pcm_lock, flags); |
---|
834 | 852 | |
---|
835 | 853 | i2s->mode &= ~DAI_OPENED; |
---|
836 | 854 | i2s->mode &= ~DAI_MANAGER; |
---|
.. | .. |
---|
842 | 860 | i2s->rfs = 0; |
---|
843 | 861 | i2s->bfs = 0; |
---|
844 | 862 | |
---|
845 | | - spin_unlock_irqrestore(&lock, flags); |
---|
| 863 | + spin_unlock_irqrestore(&priv->pcm_lock, flags); |
---|
846 | 864 | |
---|
847 | 865 | pm_runtime_put(dai->dev); |
---|
848 | 866 | } |
---|
849 | 867 | |
---|
850 | 868 | static int config_setup(struct i2s_dai *i2s) |
---|
851 | 869 | { |
---|
| 870 | + struct samsung_i2s_priv *priv = i2s->priv; |
---|
852 | 871 | struct i2s_dai *other = get_other_dai(i2s); |
---|
853 | 872 | unsigned rfs, bfs, blc; |
---|
854 | 873 | u32 psr; |
---|
.. | .. |
---|
893 | 912 | set_rfs(i2s, rfs); |
---|
894 | 913 | |
---|
895 | 914 | /* Don't bother with PSR in Slave mode */ |
---|
896 | | - if (is_slave(i2s)) |
---|
| 915 | + if (priv->slave_mode) |
---|
897 | 916 | return 0; |
---|
898 | 917 | |
---|
899 | | - if (!(i2s->quirks & QUIRK_NO_MUXPSR)) { |
---|
900 | | - psr = i2s->rclk_srcrate / i2s->frmclk / rfs; |
---|
901 | | - writel(((psr - 1) << 8) | PSR_PSREN, i2s->addr + I2SPSR); |
---|
| 918 | + if (!(priv->quirks & QUIRK_NO_MUXPSR)) { |
---|
| 919 | + psr = priv->rclk_srcrate / i2s->frmclk / rfs; |
---|
| 920 | + writel(((psr - 1) << 8) | PSR_PSREN, priv->addr + I2SPSR); |
---|
902 | 921 | dev_dbg(&i2s->pdev->dev, |
---|
903 | 922 | "RCLK_SRC=%luHz PSR=%u, RCLK=%dfs, BCLK=%dfs\n", |
---|
904 | | - i2s->rclk_srcrate, psr, rfs, bfs); |
---|
| 923 | + priv->rclk_srcrate, psr, rfs, bfs); |
---|
905 | 924 | } |
---|
906 | 925 | |
---|
907 | 926 | return 0; |
---|
.. | .. |
---|
910 | 929 | static int i2s_trigger(struct snd_pcm_substream *substream, |
---|
911 | 930 | int cmd, struct snd_soc_dai *dai) |
---|
912 | 931 | { |
---|
| 932 | + struct samsung_i2s_priv *priv = snd_soc_dai_get_drvdata(dai); |
---|
913 | 933 | int capture = (substream->stream == SNDRV_PCM_STREAM_CAPTURE); |
---|
914 | | - struct snd_soc_pcm_runtime *rtd = substream->private_data; |
---|
915 | | - struct i2s_dai *i2s = to_info(rtd->cpu_dai); |
---|
| 934 | + struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream); |
---|
| 935 | + struct i2s_dai *i2s = to_info(asoc_rtd_to_cpu(rtd, 0)); |
---|
916 | 936 | unsigned long flags; |
---|
917 | 937 | |
---|
918 | 938 | switch (cmd) { |
---|
.. | .. |
---|
920 | 940 | case SNDRV_PCM_TRIGGER_RESUME: |
---|
921 | 941 | case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: |
---|
922 | 942 | pm_runtime_get_sync(dai->dev); |
---|
923 | | - spin_lock_irqsave(i2s->lock, flags); |
---|
| 943 | + spin_lock_irqsave(&priv->lock, flags); |
---|
924 | 944 | |
---|
925 | 945 | if (config_setup(i2s)) { |
---|
926 | | - spin_unlock_irqrestore(i2s->lock, flags); |
---|
| 946 | + spin_unlock_irqrestore(&priv->lock, flags); |
---|
927 | 947 | return -EINVAL; |
---|
928 | 948 | } |
---|
929 | 949 | |
---|
.. | .. |
---|
932 | 952 | else |
---|
933 | 953 | i2s_txctrl(i2s, 1); |
---|
934 | 954 | |
---|
935 | | - spin_unlock_irqrestore(i2s->lock, flags); |
---|
| 955 | + spin_unlock_irqrestore(&priv->lock, flags); |
---|
936 | 956 | break; |
---|
937 | 957 | case SNDRV_PCM_TRIGGER_STOP: |
---|
938 | 958 | case SNDRV_PCM_TRIGGER_SUSPEND: |
---|
939 | 959 | case SNDRV_PCM_TRIGGER_PAUSE_PUSH: |
---|
940 | | - spin_lock_irqsave(i2s->lock, flags); |
---|
| 960 | + spin_lock_irqsave(&priv->lock, flags); |
---|
941 | 961 | |
---|
942 | 962 | if (capture) { |
---|
943 | 963 | i2s_rxctrl(i2s, 0); |
---|
.. | .. |
---|
947 | 967 | i2s_fifo(i2s, FIC_TXFLUSH); |
---|
948 | 968 | } |
---|
949 | 969 | |
---|
950 | | - spin_unlock_irqrestore(i2s->lock, flags); |
---|
| 970 | + spin_unlock_irqrestore(&priv->lock, flags); |
---|
951 | 971 | pm_runtime_put(dai->dev); |
---|
952 | 972 | break; |
---|
953 | 973 | } |
---|
.. | .. |
---|
986 | 1006 | static snd_pcm_sframes_t |
---|
987 | 1007 | i2s_delay(struct snd_pcm_substream *substream, struct snd_soc_dai *dai) |
---|
988 | 1008 | { |
---|
| 1009 | + struct samsung_i2s_priv *priv = snd_soc_dai_get_drvdata(dai); |
---|
989 | 1010 | struct i2s_dai *i2s = to_info(dai); |
---|
990 | | - u32 reg = readl(i2s->addr + I2SFIC); |
---|
| 1011 | + u32 reg = readl(priv->addr + I2SFIC); |
---|
991 | 1012 | snd_pcm_sframes_t delay; |
---|
992 | | - const struct samsung_i2s_variant_regs *i2s_regs = i2s->variant_regs; |
---|
993 | 1013 | |
---|
994 | 1014 | WARN_ON(!pm_runtime_active(dai->dev)); |
---|
995 | 1015 | |
---|
996 | 1016 | if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) |
---|
997 | 1017 | delay = FIC_RXCOUNT(reg); |
---|
998 | 1018 | else if (is_secondary(i2s)) |
---|
999 | | - delay = FICS_TXCOUNT(readl(i2s->addr + I2SFICS)); |
---|
| 1019 | + delay = FICS_TXCOUNT(readl(priv->addr + I2SFICS)); |
---|
1000 | 1020 | else |
---|
1001 | | - delay = (reg >> i2s_regs->ftx0cnt_off) & 0x7f; |
---|
| 1021 | + delay = (reg >> priv->variant_regs->ftx0cnt_off) & 0x7f; |
---|
1002 | 1022 | |
---|
1003 | 1023 | return delay; |
---|
1004 | 1024 | } |
---|
1005 | 1025 | |
---|
1006 | 1026 | #ifdef CONFIG_PM |
---|
1007 | | -static int i2s_suspend(struct snd_soc_dai *dai) |
---|
| 1027 | +static int i2s_suspend(struct snd_soc_component *component) |
---|
1008 | 1028 | { |
---|
1009 | | - return pm_runtime_force_suspend(dai->dev); |
---|
| 1029 | + return pm_runtime_force_suspend(component->dev); |
---|
1010 | 1030 | } |
---|
1011 | 1031 | |
---|
1012 | | -static int i2s_resume(struct snd_soc_dai *dai) |
---|
| 1032 | +static int i2s_resume(struct snd_soc_component *component) |
---|
1013 | 1033 | { |
---|
1014 | | - return pm_runtime_force_resume(dai->dev); |
---|
| 1034 | + return pm_runtime_force_resume(component->dev); |
---|
1015 | 1035 | } |
---|
1016 | 1036 | #else |
---|
1017 | 1037 | #define i2s_suspend NULL |
---|
.. | .. |
---|
1020 | 1040 | |
---|
1021 | 1041 | static int samsung_i2s_dai_probe(struct snd_soc_dai *dai) |
---|
1022 | 1042 | { |
---|
| 1043 | + struct samsung_i2s_priv *priv = snd_soc_dai_get_drvdata(dai); |
---|
1023 | 1044 | struct i2s_dai *i2s = to_info(dai); |
---|
1024 | 1045 | struct i2s_dai *other = get_other_dai(i2s); |
---|
1025 | 1046 | unsigned long flags; |
---|
1026 | 1047 | |
---|
1027 | 1048 | pm_runtime_get_sync(dai->dev); |
---|
1028 | 1049 | |
---|
1029 | | - if (is_secondary(i2s)) { /* If this is probe on the secondary DAI */ |
---|
1030 | | - snd_soc_dai_init_dma_data(dai, &other->sec_dai->dma_playback, |
---|
1031 | | - NULL); |
---|
| 1050 | + if (is_secondary(i2s)) { |
---|
| 1051 | + /* If this is probe on the secondary DAI */ |
---|
| 1052 | + snd_soc_dai_init_dma_data(dai, &i2s->dma_playback, NULL); |
---|
1032 | 1053 | } else { |
---|
1033 | 1054 | snd_soc_dai_init_dma_data(dai, &i2s->dma_playback, |
---|
1034 | | - &i2s->dma_capture); |
---|
| 1055 | + &i2s->dma_capture); |
---|
1035 | 1056 | |
---|
1036 | | - if (i2s->quirks & QUIRK_NEED_RSTCLR) |
---|
1037 | | - writel(CON_RSTCLR, i2s->addr + I2SCON); |
---|
| 1057 | + if (priv->quirks & QUIRK_NEED_RSTCLR) |
---|
| 1058 | + writel(CON_RSTCLR, priv->addr + I2SCON); |
---|
1038 | 1059 | |
---|
1039 | | - if (i2s->quirks & QUIRK_SUPPORTS_IDMA) |
---|
1040 | | - idma_reg_addr_init(i2s->addr, |
---|
1041 | | - i2s->sec_dai->idma_playback.addr); |
---|
| 1060 | + if (priv->quirks & QUIRK_SUPPORTS_IDMA) |
---|
| 1061 | + idma_reg_addr_init(priv->addr, |
---|
| 1062 | + other->idma_playback.addr); |
---|
1042 | 1063 | } |
---|
1043 | 1064 | |
---|
1044 | 1065 | /* Reset any constraint on RFS and BFS */ |
---|
1045 | 1066 | i2s->rfs = 0; |
---|
1046 | 1067 | i2s->bfs = 0; |
---|
1047 | | - i2s->rclk_srcrate = 0; |
---|
1048 | 1068 | |
---|
1049 | | - spin_lock_irqsave(i2s->lock, flags); |
---|
| 1069 | + spin_lock_irqsave(&priv->lock, flags); |
---|
1050 | 1070 | i2s_txctrl(i2s, 0); |
---|
1051 | 1071 | i2s_rxctrl(i2s, 0); |
---|
1052 | 1072 | i2s_fifo(i2s, FIC_TXFLUSH); |
---|
1053 | 1073 | i2s_fifo(other, FIC_TXFLUSH); |
---|
1054 | 1074 | i2s_fifo(i2s, FIC_RXFLUSH); |
---|
1055 | | - spin_unlock_irqrestore(i2s->lock, flags); |
---|
| 1075 | + spin_unlock_irqrestore(&priv->lock, flags); |
---|
1056 | 1076 | |
---|
1057 | 1077 | /* Gate CDCLK by default */ |
---|
1058 | 1078 | if (!is_opened(other)) |
---|
.. | .. |
---|
1065 | 1085 | |
---|
1066 | 1086 | static int samsung_i2s_dai_remove(struct snd_soc_dai *dai) |
---|
1067 | 1087 | { |
---|
1068 | | - struct i2s_dai *i2s = snd_soc_dai_get_drvdata(dai); |
---|
| 1088 | + struct samsung_i2s_priv *priv = snd_soc_dai_get_drvdata(dai); |
---|
| 1089 | + struct i2s_dai *i2s = to_info(dai); |
---|
1069 | 1090 | unsigned long flags; |
---|
1070 | 1091 | |
---|
1071 | 1092 | pm_runtime_get_sync(dai->dev); |
---|
1072 | 1093 | |
---|
1073 | 1094 | if (!is_secondary(i2s)) { |
---|
1074 | | - if (i2s->quirks & QUIRK_NEED_RSTCLR) { |
---|
1075 | | - spin_lock_irqsave(i2s->lock, flags); |
---|
1076 | | - writel(0, i2s->addr + I2SCON); |
---|
1077 | | - spin_unlock_irqrestore(i2s->lock, flags); |
---|
| 1095 | + if (priv->quirks & QUIRK_NEED_RSTCLR) { |
---|
| 1096 | + spin_lock_irqsave(&priv->lock, flags); |
---|
| 1097 | + writel(0, priv->addr + I2SCON); |
---|
| 1098 | + spin_unlock_irqrestore(&priv->lock, flags); |
---|
1078 | 1099 | } |
---|
1079 | 1100 | } |
---|
1080 | 1101 | |
---|
.. | .. |
---|
1094 | 1115 | .delay = i2s_delay, |
---|
1095 | 1116 | }; |
---|
1096 | 1117 | |
---|
1097 | | -static const struct snd_soc_component_driver samsung_i2s_component = { |
---|
1098 | | - .name = "samsung-i2s", |
---|
| 1118 | +static const struct snd_soc_dapm_widget samsung_i2s_widgets[] = { |
---|
| 1119 | + /* Backend DAI */ |
---|
| 1120 | + SND_SOC_DAPM_AIF_OUT("Mixer DAI TX", NULL, 0, SND_SOC_NOPM, 0, 0), |
---|
| 1121 | + SND_SOC_DAPM_AIF_IN("Mixer DAI RX", NULL, 0, SND_SOC_NOPM, 0, 0), |
---|
| 1122 | + |
---|
| 1123 | + /* Playback Mixer */ |
---|
| 1124 | + SND_SOC_DAPM_MIXER("Playback Mixer", SND_SOC_NOPM, 0, 0, NULL, 0), |
---|
1099 | 1125 | }; |
---|
1100 | 1126 | |
---|
1101 | | -#define SAMSUNG_I2S_FMTS (SNDRV_PCM_FMTBIT_S8 | \ |
---|
1102 | | - SNDRV_PCM_FMTBIT_S16_LE | \ |
---|
1103 | | - SNDRV_PCM_FMTBIT_S24_LE) |
---|
| 1127 | +static const struct snd_soc_dapm_route samsung_i2s_dapm_routes[] = { |
---|
| 1128 | + { "Playback Mixer", NULL, "Primary Playback" }, |
---|
| 1129 | + { "Playback Mixer", NULL, "Secondary Playback" }, |
---|
1104 | 1130 | |
---|
1105 | | -static struct i2s_dai *i2s_alloc_dai(struct platform_device *pdev, |
---|
1106 | | - const struct samsung_i2s_dai_data *i2s_dai_data, |
---|
1107 | | - bool sec) |
---|
| 1131 | + { "Mixer DAI TX", NULL, "Playback Mixer" }, |
---|
| 1132 | + { "Primary Capture", NULL, "Mixer DAI RX" }, |
---|
| 1133 | +}; |
---|
| 1134 | + |
---|
| 1135 | +static const struct snd_soc_component_driver samsung_i2s_component = { |
---|
| 1136 | + .name = "samsung-i2s", |
---|
| 1137 | + |
---|
| 1138 | + .dapm_widgets = samsung_i2s_widgets, |
---|
| 1139 | + .num_dapm_widgets = ARRAY_SIZE(samsung_i2s_widgets), |
---|
| 1140 | + |
---|
| 1141 | + .dapm_routes = samsung_i2s_dapm_routes, |
---|
| 1142 | + .num_dapm_routes = ARRAY_SIZE(samsung_i2s_dapm_routes), |
---|
| 1143 | + |
---|
| 1144 | + .suspend = i2s_suspend, |
---|
| 1145 | + .resume = i2s_resume, |
---|
| 1146 | +}; |
---|
| 1147 | + |
---|
| 1148 | +#define SAMSUNG_I2S_FMTS (SNDRV_PCM_FMTBIT_S8 | SNDRV_PCM_FMTBIT_S16_LE | \ |
---|
| 1149 | + SNDRV_PCM_FMTBIT_S24_LE) |
---|
| 1150 | + |
---|
| 1151 | +static int i2s_alloc_dais(struct samsung_i2s_priv *priv, |
---|
| 1152 | + const struct samsung_i2s_dai_data *i2s_dai_data, |
---|
| 1153 | + int num_dais) |
---|
1108 | 1154 | { |
---|
1109 | | - struct i2s_dai *i2s; |
---|
| 1155 | + static const char *dai_names[] = { "samsung-i2s", "samsung-i2s-sec" }; |
---|
| 1156 | + static const char *stream_names[] = { "Primary Playback", |
---|
| 1157 | + "Secondary Playback" }; |
---|
| 1158 | + struct snd_soc_dai_driver *dai_drv; |
---|
| 1159 | + struct i2s_dai *dai; |
---|
| 1160 | + int i; |
---|
1110 | 1161 | |
---|
1111 | | - i2s = devm_kzalloc(&pdev->dev, sizeof(struct i2s_dai), GFP_KERNEL); |
---|
1112 | | - if (i2s == NULL) |
---|
1113 | | - return NULL; |
---|
| 1162 | + priv->dai = devm_kcalloc(&priv->pdev->dev, num_dais, |
---|
| 1163 | + sizeof(*dai), GFP_KERNEL); |
---|
| 1164 | + if (!priv->dai) |
---|
| 1165 | + return -ENOMEM; |
---|
1114 | 1166 | |
---|
1115 | | - i2s->pdev = pdev; |
---|
1116 | | - i2s->pri_dai = NULL; |
---|
1117 | | - i2s->sec_dai = NULL; |
---|
1118 | | - i2s->i2s_dai_drv.id = 1; |
---|
1119 | | - i2s->i2s_dai_drv.symmetric_rates = 1; |
---|
1120 | | - i2s->i2s_dai_drv.probe = samsung_i2s_dai_probe; |
---|
1121 | | - i2s->i2s_dai_drv.remove = samsung_i2s_dai_remove; |
---|
1122 | | - i2s->i2s_dai_drv.ops = &samsung_i2s_dai_ops; |
---|
1123 | | - i2s->i2s_dai_drv.suspend = i2s_suspend; |
---|
1124 | | - i2s->i2s_dai_drv.resume = i2s_resume; |
---|
1125 | | - i2s->i2s_dai_drv.playback.channels_min = 1; |
---|
1126 | | - i2s->i2s_dai_drv.playback.channels_max = 2; |
---|
1127 | | - i2s->i2s_dai_drv.playback.rates = i2s_dai_data->pcm_rates; |
---|
1128 | | - i2s->i2s_dai_drv.playback.formats = SAMSUNG_I2S_FMTS; |
---|
| 1167 | + priv->dai_drv = devm_kcalloc(&priv->pdev->dev, num_dais, |
---|
| 1168 | + sizeof(*dai_drv), GFP_KERNEL); |
---|
| 1169 | + if (!priv->dai_drv) |
---|
| 1170 | + return -ENOMEM; |
---|
1129 | 1171 | |
---|
1130 | | - if (!sec) { |
---|
1131 | | - i2s->i2s_dai_drv.name = SAMSUNG_I2S_DAI; |
---|
1132 | | - i2s->i2s_dai_drv.capture.channels_min = 1; |
---|
1133 | | - i2s->i2s_dai_drv.capture.channels_max = 2; |
---|
1134 | | - i2s->i2s_dai_drv.capture.rates = i2s_dai_data->pcm_rates; |
---|
1135 | | - i2s->i2s_dai_drv.capture.formats = SAMSUNG_I2S_FMTS; |
---|
1136 | | - } else { |
---|
1137 | | - i2s->i2s_dai_drv.name = SAMSUNG_I2S_DAI_SEC; |
---|
| 1172 | + for (i = 0; i < num_dais; i++) { |
---|
| 1173 | + dai_drv = &priv->dai_drv[i]; |
---|
| 1174 | + |
---|
| 1175 | + dai_drv->probe = samsung_i2s_dai_probe; |
---|
| 1176 | + dai_drv->remove = samsung_i2s_dai_remove; |
---|
| 1177 | + |
---|
| 1178 | + dai_drv->symmetric_rates = 1; |
---|
| 1179 | + dai_drv->ops = &samsung_i2s_dai_ops; |
---|
| 1180 | + |
---|
| 1181 | + dai_drv->playback.channels_min = 1; |
---|
| 1182 | + dai_drv->playback.channels_max = 2; |
---|
| 1183 | + dai_drv->playback.rates = i2s_dai_data->pcm_rates; |
---|
| 1184 | + dai_drv->playback.formats = SAMSUNG_I2S_FMTS; |
---|
| 1185 | + dai_drv->playback.stream_name = stream_names[i]; |
---|
| 1186 | + |
---|
| 1187 | + dai_drv->id = i + 1; |
---|
| 1188 | + dai_drv->name = dai_names[i]; |
---|
| 1189 | + |
---|
| 1190 | + priv->dai[i].drv = &priv->dai_drv[i]; |
---|
| 1191 | + priv->dai[i].pdev = priv->pdev; |
---|
1138 | 1192 | } |
---|
1139 | | - return i2s; |
---|
| 1193 | + |
---|
| 1194 | + /* Initialize capture only for the primary DAI */ |
---|
| 1195 | + dai_drv = &priv->dai_drv[SAMSUNG_I2S_ID_PRIMARY - 1]; |
---|
| 1196 | + |
---|
| 1197 | + dai_drv->capture.channels_min = 1; |
---|
| 1198 | + dai_drv->capture.channels_max = 2; |
---|
| 1199 | + dai_drv->capture.rates = i2s_dai_data->pcm_rates; |
---|
| 1200 | + dai_drv->capture.formats = SAMSUNG_I2S_FMTS; |
---|
| 1201 | + dai_drv->capture.stream_name = "Primary Capture"; |
---|
| 1202 | + |
---|
| 1203 | + return 0; |
---|
1140 | 1204 | } |
---|
1141 | 1205 | |
---|
1142 | 1206 | #ifdef CONFIG_PM |
---|
1143 | 1207 | static int i2s_runtime_suspend(struct device *dev) |
---|
1144 | 1208 | { |
---|
1145 | | - struct i2s_dai *i2s = dev_get_drvdata(dev); |
---|
| 1209 | + struct samsung_i2s_priv *priv = dev_get_drvdata(dev); |
---|
1146 | 1210 | |
---|
1147 | | - i2s->suspend_i2smod = readl(i2s->addr + I2SMOD); |
---|
1148 | | - i2s->suspend_i2scon = readl(i2s->addr + I2SCON); |
---|
1149 | | - i2s->suspend_i2spsr = readl(i2s->addr + I2SPSR); |
---|
| 1211 | + priv->suspend_i2smod = readl(priv->addr + I2SMOD); |
---|
| 1212 | + priv->suspend_i2scon = readl(priv->addr + I2SCON); |
---|
| 1213 | + priv->suspend_i2spsr = readl(priv->addr + I2SPSR); |
---|
1150 | 1214 | |
---|
1151 | | - if (i2s->op_clk) |
---|
1152 | | - clk_disable_unprepare(i2s->op_clk); |
---|
1153 | | - clk_disable_unprepare(i2s->clk); |
---|
| 1215 | + if (priv->op_clk) |
---|
| 1216 | + clk_disable_unprepare(priv->op_clk); |
---|
| 1217 | + clk_disable_unprepare(priv->clk); |
---|
1154 | 1218 | |
---|
1155 | 1219 | return 0; |
---|
1156 | 1220 | } |
---|
1157 | 1221 | |
---|
1158 | 1222 | static int i2s_runtime_resume(struct device *dev) |
---|
1159 | 1223 | { |
---|
1160 | | - struct i2s_dai *i2s = dev_get_drvdata(dev); |
---|
| 1224 | + struct samsung_i2s_priv *priv = dev_get_drvdata(dev); |
---|
1161 | 1225 | int ret; |
---|
1162 | 1226 | |
---|
1163 | | - ret = clk_prepare_enable(i2s->clk); |
---|
| 1227 | + ret = clk_prepare_enable(priv->clk); |
---|
1164 | 1228 | if (ret) |
---|
1165 | 1229 | return ret; |
---|
1166 | 1230 | |
---|
1167 | | - if (i2s->op_clk) { |
---|
1168 | | - ret = clk_prepare_enable(i2s->op_clk); |
---|
| 1231 | + if (priv->op_clk) { |
---|
| 1232 | + ret = clk_prepare_enable(priv->op_clk); |
---|
1169 | 1233 | if (ret) { |
---|
1170 | | - clk_disable_unprepare(i2s->clk); |
---|
| 1234 | + clk_disable_unprepare(priv->clk); |
---|
1171 | 1235 | return ret; |
---|
1172 | 1236 | } |
---|
1173 | 1237 | } |
---|
1174 | 1238 | |
---|
1175 | | - writel(i2s->suspend_i2scon, i2s->addr + I2SCON); |
---|
1176 | | - writel(i2s->suspend_i2smod, i2s->addr + I2SMOD); |
---|
1177 | | - writel(i2s->suspend_i2spsr, i2s->addr + I2SPSR); |
---|
| 1239 | + writel(priv->suspend_i2scon, priv->addr + I2SCON); |
---|
| 1240 | + writel(priv->suspend_i2smod, priv->addr + I2SMOD); |
---|
| 1241 | + writel(priv->suspend_i2spsr, priv->addr + I2SPSR); |
---|
1178 | 1242 | |
---|
1179 | 1243 | return 0; |
---|
1180 | 1244 | } |
---|
1181 | 1245 | #endif /* CONFIG_PM */ |
---|
1182 | 1246 | |
---|
1183 | | -static void i2s_unregister_clocks(struct i2s_dai *i2s) |
---|
| 1247 | +static void i2s_unregister_clocks(struct samsung_i2s_priv *priv) |
---|
1184 | 1248 | { |
---|
1185 | 1249 | int i; |
---|
1186 | 1250 | |
---|
1187 | | - for (i = 0; i < i2s->clk_data.clk_num; i++) { |
---|
1188 | | - if (!IS_ERR(i2s->clk_table[i])) |
---|
1189 | | - clk_unregister(i2s->clk_table[i]); |
---|
| 1251 | + for (i = 0; i < priv->clk_data.clk_num; i++) { |
---|
| 1252 | + if (!IS_ERR(priv->clk_table[i])) |
---|
| 1253 | + clk_unregister(priv->clk_table[i]); |
---|
1190 | 1254 | } |
---|
1191 | 1255 | } |
---|
1192 | 1256 | |
---|
1193 | | -static void i2s_unregister_clock_provider(struct platform_device *pdev) |
---|
| 1257 | +static void i2s_unregister_clock_provider(struct samsung_i2s_priv *priv) |
---|
1194 | 1258 | { |
---|
1195 | | - struct i2s_dai *i2s = dev_get_drvdata(&pdev->dev); |
---|
1196 | | - |
---|
1197 | | - of_clk_del_provider(pdev->dev.of_node); |
---|
1198 | | - i2s_unregister_clocks(i2s); |
---|
| 1259 | + of_clk_del_provider(priv->pdev->dev.of_node); |
---|
| 1260 | + i2s_unregister_clocks(priv); |
---|
1199 | 1261 | } |
---|
1200 | 1262 | |
---|
1201 | | -static int i2s_register_clock_provider(struct platform_device *pdev) |
---|
| 1263 | + |
---|
| 1264 | +static int i2s_register_clock_provider(struct samsung_i2s_priv *priv) |
---|
1202 | 1265 | { |
---|
| 1266 | + |
---|
1203 | 1267 | const char * const i2s_clk_desc[] = { "cdclk", "rclk_src", "prescaler" }; |
---|
1204 | 1268 | const char *clk_name[2] = { "i2s_opclk0", "i2s_opclk1" }; |
---|
1205 | 1269 | const char *p_names[2] = { NULL }; |
---|
1206 | | - struct device *dev = &pdev->dev; |
---|
1207 | | - struct i2s_dai *i2s = dev_get_drvdata(dev); |
---|
1208 | | - const struct samsung_i2s_variant_regs *reg_info = i2s->variant_regs; |
---|
| 1270 | + struct device *dev = &priv->pdev->dev; |
---|
| 1271 | + const struct samsung_i2s_variant_regs *reg_info = priv->variant_regs; |
---|
1209 | 1272 | const char *i2s_clk_name[ARRAY_SIZE(i2s_clk_desc)]; |
---|
1210 | 1273 | struct clk *rclksrc; |
---|
1211 | 1274 | int ret, i; |
---|
.. | .. |
---|
1230 | 1293 | return -ENOMEM; |
---|
1231 | 1294 | } |
---|
1232 | 1295 | |
---|
1233 | | - if (!(i2s->quirks & QUIRK_NO_MUXPSR)) { |
---|
| 1296 | + if (!(priv->quirks & QUIRK_NO_MUXPSR)) { |
---|
1234 | 1297 | /* Activate the prescaler */ |
---|
1235 | | - u32 val = readl(i2s->addr + I2SPSR); |
---|
1236 | | - writel(val | PSR_PSREN, i2s->addr + I2SPSR); |
---|
| 1298 | + u32 val = readl(priv->addr + I2SPSR); |
---|
| 1299 | + writel(val | PSR_PSREN, priv->addr + I2SPSR); |
---|
1237 | 1300 | |
---|
1238 | | - i2s->clk_table[CLK_I2S_RCLK_SRC] = clk_register_mux(dev, |
---|
| 1301 | + priv->clk_table[CLK_I2S_RCLK_SRC] = clk_register_mux(dev, |
---|
1239 | 1302 | i2s_clk_name[CLK_I2S_RCLK_SRC], p_names, |
---|
1240 | 1303 | ARRAY_SIZE(p_names), |
---|
1241 | 1304 | CLK_SET_RATE_NO_REPARENT | CLK_SET_RATE_PARENT, |
---|
1242 | | - i2s->addr + I2SMOD, reg_info->rclksrc_off, |
---|
1243 | | - 1, 0, i2s->lock); |
---|
| 1305 | + priv->addr + I2SMOD, reg_info->rclksrc_off, |
---|
| 1306 | + 1, 0, &priv->lock); |
---|
1244 | 1307 | |
---|
1245 | | - i2s->clk_table[CLK_I2S_RCLK_PSR] = clk_register_divider(dev, |
---|
| 1308 | + priv->clk_table[CLK_I2S_RCLK_PSR] = clk_register_divider(dev, |
---|
1246 | 1309 | i2s_clk_name[CLK_I2S_RCLK_PSR], |
---|
1247 | 1310 | i2s_clk_name[CLK_I2S_RCLK_SRC], |
---|
1248 | 1311 | CLK_SET_RATE_PARENT, |
---|
1249 | | - i2s->addr + I2SPSR, 8, 6, 0, i2s->lock); |
---|
| 1312 | + priv->addr + I2SPSR, 8, 6, 0, &priv->lock); |
---|
1250 | 1313 | |
---|
1251 | 1314 | p_names[0] = i2s_clk_name[CLK_I2S_RCLK_PSR]; |
---|
1252 | | - i2s->clk_data.clk_num = 2; |
---|
| 1315 | + priv->clk_data.clk_num = 2; |
---|
1253 | 1316 | } |
---|
1254 | 1317 | |
---|
1255 | | - i2s->clk_table[CLK_I2S_CDCLK] = clk_register_gate(dev, |
---|
| 1318 | + priv->clk_table[CLK_I2S_CDCLK] = clk_register_gate(dev, |
---|
1256 | 1319 | i2s_clk_name[CLK_I2S_CDCLK], p_names[0], |
---|
1257 | 1320 | CLK_SET_RATE_PARENT, |
---|
1258 | | - i2s->addr + I2SMOD, reg_info->cdclkcon_off, |
---|
1259 | | - CLK_GATE_SET_TO_DISABLE, i2s->lock); |
---|
| 1321 | + priv->addr + I2SMOD, reg_info->cdclkcon_off, |
---|
| 1322 | + CLK_GATE_SET_TO_DISABLE, &priv->lock); |
---|
1260 | 1323 | |
---|
1261 | | - i2s->clk_data.clk_num += 1; |
---|
1262 | | - i2s->clk_data.clks = i2s->clk_table; |
---|
| 1324 | + priv->clk_data.clk_num += 1; |
---|
| 1325 | + priv->clk_data.clks = priv->clk_table; |
---|
1263 | 1326 | |
---|
1264 | 1327 | ret = of_clk_add_provider(dev->of_node, of_clk_src_onecell_get, |
---|
1265 | | - &i2s->clk_data); |
---|
| 1328 | + &priv->clk_data); |
---|
1266 | 1329 | if (ret < 0) { |
---|
1267 | 1330 | dev_err(dev, "failed to add clock provider: %d\n", ret); |
---|
1268 | | - i2s_unregister_clocks(i2s); |
---|
| 1331 | + i2s_unregister_clocks(priv); |
---|
1269 | 1332 | } |
---|
1270 | 1333 | |
---|
1271 | 1334 | return ret; |
---|
| 1335 | +} |
---|
| 1336 | + |
---|
| 1337 | +/* Create platform device for the secondary PCM */ |
---|
| 1338 | +static int i2s_create_secondary_device(struct samsung_i2s_priv *priv) |
---|
| 1339 | +{ |
---|
| 1340 | + struct platform_device *pdev_sec; |
---|
| 1341 | + const char *devname; |
---|
| 1342 | + int ret; |
---|
| 1343 | + |
---|
| 1344 | + devname = devm_kasprintf(&priv->pdev->dev, GFP_KERNEL, "%s-sec", |
---|
| 1345 | + dev_name(&priv->pdev->dev)); |
---|
| 1346 | + if (!devname) |
---|
| 1347 | + return -ENOMEM; |
---|
| 1348 | + |
---|
| 1349 | + pdev_sec = platform_device_alloc(devname, -1); |
---|
| 1350 | + if (!pdev_sec) |
---|
| 1351 | + return -ENOMEM; |
---|
| 1352 | + |
---|
| 1353 | + pdev_sec->driver_override = kstrdup("samsung-i2s", GFP_KERNEL); |
---|
| 1354 | + |
---|
| 1355 | + ret = platform_device_add(pdev_sec); |
---|
| 1356 | + if (ret < 0) { |
---|
| 1357 | + platform_device_put(pdev_sec); |
---|
| 1358 | + return ret; |
---|
| 1359 | + } |
---|
| 1360 | + |
---|
| 1361 | + ret = device_attach(&pdev_sec->dev); |
---|
| 1362 | + if (ret <= 0) { |
---|
| 1363 | + platform_device_unregister(priv->pdev_sec); |
---|
| 1364 | + dev_info(&pdev_sec->dev, "device_attach() failed\n"); |
---|
| 1365 | + return ret; |
---|
| 1366 | + } |
---|
| 1367 | + |
---|
| 1368 | + priv->pdev_sec = pdev_sec; |
---|
| 1369 | + |
---|
| 1370 | + return 0; |
---|
| 1371 | +} |
---|
| 1372 | + |
---|
| 1373 | +static void i2s_delete_secondary_device(struct samsung_i2s_priv *priv) |
---|
| 1374 | +{ |
---|
| 1375 | + platform_device_unregister(priv->pdev_sec); |
---|
| 1376 | + priv->pdev_sec = NULL; |
---|
1272 | 1377 | } |
---|
1273 | 1378 | |
---|
1274 | 1379 | static int samsung_i2s_probe(struct platform_device *pdev) |
---|
1275 | 1380 | { |
---|
1276 | 1381 | struct i2s_dai *pri_dai, *sec_dai = NULL; |
---|
1277 | 1382 | struct s3c_audio_pdata *i2s_pdata = pdev->dev.platform_data; |
---|
1278 | | - struct resource *res; |
---|
1279 | | - u32 regs_base, quirks = 0, idma_addr = 0; |
---|
| 1383 | + u32 regs_base, idma_addr = 0; |
---|
1280 | 1384 | struct device_node *np = pdev->dev.of_node; |
---|
1281 | 1385 | const struct samsung_i2s_dai_data *i2s_dai_data; |
---|
1282 | | - int ret; |
---|
| 1386 | + const struct platform_device_id *id; |
---|
| 1387 | + struct samsung_i2s_priv *priv; |
---|
| 1388 | + struct resource *res; |
---|
| 1389 | + int num_dais, ret; |
---|
1283 | 1390 | |
---|
1284 | | - if (IS_ENABLED(CONFIG_OF) && pdev->dev.of_node) |
---|
| 1391 | + if (IS_ENABLED(CONFIG_OF) && pdev->dev.of_node) { |
---|
1285 | 1392 | i2s_dai_data = of_device_get_match_data(&pdev->dev); |
---|
1286 | | - else |
---|
1287 | | - i2s_dai_data = (struct samsung_i2s_dai_data *) |
---|
1288 | | - platform_get_device_id(pdev)->driver_data; |
---|
| 1393 | + } else { |
---|
| 1394 | + id = platform_get_device_id(pdev); |
---|
1289 | 1395 | |
---|
1290 | | - pri_dai = i2s_alloc_dai(pdev, i2s_dai_data, false); |
---|
1291 | | - if (!pri_dai) { |
---|
1292 | | - dev_err(&pdev->dev, "Unable to alloc I2S_pri\n"); |
---|
1293 | | - return -ENOMEM; |
---|
| 1396 | + /* Nothing to do if it is the secondary device probe */ |
---|
| 1397 | + if (!id) |
---|
| 1398 | + return 0; |
---|
| 1399 | + |
---|
| 1400 | + i2s_dai_data = (struct samsung_i2s_dai_data *)id->driver_data; |
---|
1294 | 1401 | } |
---|
1295 | 1402 | |
---|
1296 | | - spin_lock_init(&pri_dai->spinlock); |
---|
1297 | | - pri_dai->lock = &pri_dai->spinlock; |
---|
| 1403 | + priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL); |
---|
| 1404 | + if (!priv) |
---|
| 1405 | + return -ENOMEM; |
---|
1298 | 1406 | |
---|
1299 | | - if (!np) { |
---|
1300 | | - if (i2s_pdata == NULL) { |
---|
1301 | | - dev_err(&pdev->dev, "Can't work without s3c_audio_pdata\n"); |
---|
| 1407 | + if (np) { |
---|
| 1408 | + priv->quirks = i2s_dai_data->quirks; |
---|
| 1409 | + } else { |
---|
| 1410 | + if (!i2s_pdata) { |
---|
| 1411 | + dev_err(&pdev->dev, "Missing platform data\n"); |
---|
1302 | 1412 | return -EINVAL; |
---|
1303 | 1413 | } |
---|
| 1414 | + priv->quirks = i2s_pdata->type.quirks; |
---|
| 1415 | + } |
---|
1304 | 1416 | |
---|
| 1417 | + num_dais = (priv->quirks & QUIRK_SEC_DAI) ? 2 : 1; |
---|
| 1418 | + priv->pdev = pdev; |
---|
| 1419 | + priv->variant_regs = i2s_dai_data->i2s_variant_regs; |
---|
| 1420 | + |
---|
| 1421 | + ret = i2s_alloc_dais(priv, i2s_dai_data, num_dais); |
---|
| 1422 | + if (ret < 0) |
---|
| 1423 | + return ret; |
---|
| 1424 | + |
---|
| 1425 | + pri_dai = &priv->dai[SAMSUNG_I2S_ID_PRIMARY - 1]; |
---|
| 1426 | + |
---|
| 1427 | + spin_lock_init(&priv->lock); |
---|
| 1428 | + spin_lock_init(&priv->pcm_lock); |
---|
| 1429 | + |
---|
| 1430 | + if (!np) { |
---|
1305 | 1431 | pri_dai->dma_playback.filter_data = i2s_pdata->dma_playback; |
---|
1306 | 1432 | pri_dai->dma_capture.filter_data = i2s_pdata->dma_capture; |
---|
1307 | 1433 | pri_dai->filter = i2s_pdata->dma_filter; |
---|
1308 | 1434 | |
---|
1309 | | - quirks = i2s_pdata->type.quirks; |
---|
1310 | 1435 | idma_addr = i2s_pdata->type.idma_addr; |
---|
1311 | 1436 | } else { |
---|
1312 | | - quirks = i2s_dai_data->quirks; |
---|
1313 | 1437 | if (of_property_read_u32(np, "samsung,idma-addr", |
---|
1314 | 1438 | &idma_addr)) { |
---|
1315 | | - if (quirks & QUIRK_SUPPORTS_IDMA) { |
---|
| 1439 | + if (priv->quirks & QUIRK_SUPPORTS_IDMA) { |
---|
1316 | 1440 | dev_info(&pdev->dev, "idma address is not"\ |
---|
1317 | 1441 | "specified"); |
---|
1318 | 1442 | } |
---|
1319 | 1443 | } |
---|
1320 | 1444 | } |
---|
1321 | | - quirks &= ~(QUIRK_SEC_DAI | QUIRK_SUPPORTS_IDMA); |
---|
1322 | 1445 | |
---|
1323 | 1446 | res = platform_get_resource(pdev, IORESOURCE_MEM, 0); |
---|
1324 | | - pri_dai->addr = devm_ioremap_resource(&pdev->dev, res); |
---|
1325 | | - if (IS_ERR(pri_dai->addr)) |
---|
1326 | | - return PTR_ERR(pri_dai->addr); |
---|
| 1447 | + priv->addr = devm_ioremap_resource(&pdev->dev, res); |
---|
| 1448 | + if (IS_ERR(priv->addr)) |
---|
| 1449 | + return PTR_ERR(priv->addr); |
---|
1327 | 1450 | |
---|
1328 | 1451 | regs_base = res->start; |
---|
1329 | 1452 | |
---|
1330 | | - pri_dai->clk = devm_clk_get(&pdev->dev, "iis"); |
---|
1331 | | - if (IS_ERR(pri_dai->clk)) { |
---|
| 1453 | + priv->clk = devm_clk_get(&pdev->dev, "iis"); |
---|
| 1454 | + if (IS_ERR(priv->clk)) { |
---|
1332 | 1455 | dev_err(&pdev->dev, "Failed to get iis clock\n"); |
---|
1333 | | - return PTR_ERR(pri_dai->clk); |
---|
| 1456 | + return PTR_ERR(priv->clk); |
---|
1334 | 1457 | } |
---|
1335 | 1458 | |
---|
1336 | | - ret = clk_prepare_enable(pri_dai->clk); |
---|
| 1459 | + ret = clk_prepare_enable(priv->clk); |
---|
1337 | 1460 | if (ret != 0) { |
---|
1338 | 1461 | dev_err(&pdev->dev, "failed to enable clock: %d\n", ret); |
---|
1339 | 1462 | return ret; |
---|
.. | .. |
---|
1344 | 1467 | pri_dai->dma_capture.chan_name = "rx"; |
---|
1345 | 1468 | pri_dai->dma_playback.addr_width = 4; |
---|
1346 | 1469 | pri_dai->dma_capture.addr_width = 4; |
---|
1347 | | - pri_dai->quirks = quirks; |
---|
1348 | | - pri_dai->variant_regs = i2s_dai_data->i2s_variant_regs; |
---|
| 1470 | + pri_dai->priv = priv; |
---|
1349 | 1471 | |
---|
1350 | | - if (quirks & QUIRK_PRI_6CHAN) |
---|
1351 | | - pri_dai->i2s_dai_drv.playback.channels_max = 6; |
---|
| 1472 | + if (priv->quirks & QUIRK_PRI_6CHAN) |
---|
| 1473 | + pri_dai->drv->playback.channels_max = 6; |
---|
1352 | 1474 | |
---|
1353 | 1475 | ret = samsung_asoc_dma_platform_register(&pdev->dev, pri_dai->filter, |
---|
1354 | | - NULL, NULL); |
---|
| 1476 | + "tx", "rx", NULL); |
---|
1355 | 1477 | if (ret < 0) |
---|
1356 | 1478 | goto err_disable_clk; |
---|
1357 | 1479 | |
---|
1358 | | - ret = devm_snd_soc_register_component(&pdev->dev, |
---|
1359 | | - &samsung_i2s_component, |
---|
1360 | | - &pri_dai->i2s_dai_drv, 1); |
---|
1361 | | - if (ret < 0) |
---|
1362 | | - goto err_disable_clk; |
---|
| 1480 | + if (priv->quirks & QUIRK_SEC_DAI) { |
---|
| 1481 | + sec_dai = &priv->dai[SAMSUNG_I2S_ID_SECONDARY - 1]; |
---|
1363 | 1482 | |
---|
1364 | | - if (quirks & QUIRK_SEC_DAI) { |
---|
1365 | | - sec_dai = i2s_alloc_dai(pdev, i2s_dai_data, true); |
---|
1366 | | - if (!sec_dai) { |
---|
1367 | | - dev_err(&pdev->dev, "Unable to alloc I2S_sec\n"); |
---|
1368 | | - ret = -ENOMEM; |
---|
1369 | | - goto err_disable_clk; |
---|
1370 | | - } |
---|
1371 | | - |
---|
1372 | | - sec_dai->lock = &pri_dai->spinlock; |
---|
1373 | | - sec_dai->variant_regs = pri_dai->variant_regs; |
---|
1374 | 1483 | sec_dai->dma_playback.addr = regs_base + I2STXDS; |
---|
1375 | 1484 | sec_dai->dma_playback.chan_name = "tx-sec"; |
---|
1376 | 1485 | |
---|
.. | .. |
---|
1380 | 1489 | } |
---|
1381 | 1490 | |
---|
1382 | 1491 | sec_dai->dma_playback.addr_width = 4; |
---|
1383 | | - sec_dai->addr = pri_dai->addr; |
---|
1384 | | - sec_dai->clk = pri_dai->clk; |
---|
1385 | | - sec_dai->quirks = quirks; |
---|
1386 | 1492 | sec_dai->idma_playback.addr = idma_addr; |
---|
1387 | 1493 | sec_dai->pri_dai = pri_dai; |
---|
| 1494 | + sec_dai->priv = priv; |
---|
1388 | 1495 | pri_dai->sec_dai = sec_dai; |
---|
1389 | 1496 | |
---|
1390 | | - ret = samsung_asoc_dma_platform_register(&pdev->dev, |
---|
1391 | | - sec_dai->filter, "tx-sec", NULL); |
---|
| 1497 | + ret = i2s_create_secondary_device(priv); |
---|
1392 | 1498 | if (ret < 0) |
---|
1393 | 1499 | goto err_disable_clk; |
---|
1394 | 1500 | |
---|
1395 | | - ret = devm_snd_soc_register_component(&pdev->dev, |
---|
1396 | | - &samsung_i2s_component, |
---|
1397 | | - &sec_dai->i2s_dai_drv, 1); |
---|
| 1501 | + ret = samsung_asoc_dma_platform_register(&priv->pdev_sec->dev, |
---|
| 1502 | + sec_dai->filter, "tx-sec", NULL, |
---|
| 1503 | + &pdev->dev); |
---|
1398 | 1504 | if (ret < 0) |
---|
1399 | | - goto err_disable_clk; |
---|
| 1505 | + goto err_del_sec; |
---|
| 1506 | + |
---|
1400 | 1507 | } |
---|
1401 | 1508 | |
---|
1402 | 1509 | if (i2s_pdata && i2s_pdata->cfg_gpio && i2s_pdata->cfg_gpio(pdev)) { |
---|
1403 | 1510 | dev_err(&pdev->dev, "Unable to configure gpio\n"); |
---|
1404 | 1511 | ret = -EINVAL; |
---|
1405 | | - goto err_disable_clk; |
---|
| 1512 | + goto err_del_sec; |
---|
1406 | 1513 | } |
---|
1407 | 1514 | |
---|
1408 | | - dev_set_drvdata(&pdev->dev, pri_dai); |
---|
| 1515 | + dev_set_drvdata(&pdev->dev, priv); |
---|
| 1516 | + |
---|
| 1517 | + ret = devm_snd_soc_register_component(&pdev->dev, |
---|
| 1518 | + &samsung_i2s_component, |
---|
| 1519 | + priv->dai_drv, num_dais); |
---|
| 1520 | + if (ret < 0) |
---|
| 1521 | + goto err_del_sec; |
---|
1409 | 1522 | |
---|
1410 | 1523 | pm_runtime_set_active(&pdev->dev); |
---|
1411 | 1524 | pm_runtime_enable(&pdev->dev); |
---|
1412 | 1525 | |
---|
1413 | | - ret = i2s_register_clock_provider(pdev); |
---|
| 1526 | + ret = i2s_register_clock_provider(priv); |
---|
1414 | 1527 | if (ret < 0) |
---|
1415 | 1528 | goto err_disable_pm; |
---|
1416 | 1529 | |
---|
1417 | | - pri_dai->op_clk = clk_get_parent(pri_dai->clk_table[CLK_I2S_RCLK_SRC]); |
---|
| 1530 | + priv->op_clk = clk_get_parent(priv->clk_table[CLK_I2S_RCLK_SRC]); |
---|
1418 | 1531 | |
---|
1419 | 1532 | return 0; |
---|
1420 | 1533 | |
---|
1421 | 1534 | err_disable_pm: |
---|
1422 | 1535 | pm_runtime_disable(&pdev->dev); |
---|
| 1536 | +err_del_sec: |
---|
| 1537 | + i2s_delete_secondary_device(priv); |
---|
1423 | 1538 | err_disable_clk: |
---|
1424 | | - clk_disable_unprepare(pri_dai->clk); |
---|
| 1539 | + clk_disable_unprepare(priv->clk); |
---|
1425 | 1540 | return ret; |
---|
1426 | 1541 | } |
---|
1427 | 1542 | |
---|
1428 | 1543 | static int samsung_i2s_remove(struct platform_device *pdev) |
---|
1429 | 1544 | { |
---|
1430 | | - struct i2s_dai *pri_dai; |
---|
| 1545 | + struct samsung_i2s_priv *priv = dev_get_drvdata(&pdev->dev); |
---|
1431 | 1546 | |
---|
1432 | | - pri_dai = dev_get_drvdata(&pdev->dev); |
---|
| 1547 | + /* The secondary device has no driver data assigned */ |
---|
| 1548 | + if (!priv) |
---|
| 1549 | + return 0; |
---|
1433 | 1550 | |
---|
1434 | 1551 | pm_runtime_get_sync(&pdev->dev); |
---|
1435 | 1552 | pm_runtime_disable(&pdev->dev); |
---|
1436 | 1553 | |
---|
1437 | | - i2s_unregister_clock_provider(pdev); |
---|
1438 | | - clk_disable_unprepare(pri_dai->clk); |
---|
| 1554 | + i2s_unregister_clock_provider(priv); |
---|
| 1555 | + i2s_delete_secondary_device(priv); |
---|
| 1556 | + clk_disable_unprepare(priv->clk); |
---|
| 1557 | + |
---|
1439 | 1558 | pm_runtime_put_noidle(&pdev->dev); |
---|
1440 | 1559 | |
---|
1441 | 1560 | return 0; |
---|