Lines Matching +full:s3c6410 +full:- +full:i2s

1 // SPDX-License-Identifier: GPL-2.0
3 // ALSA SoC Audio Layer - Samsung I2S Controller driver
8 #include <dt-bindings/sound/samsung-i2s.h>
12 #include <linux/clk-provider.h>
21 #include <linux/platform_data/asoc-s3c.h>
25 #include "i2s.h"
26 #include "i2s-regs.h"
101 /* The I2S controller's core clock */
104 /* Clock for generating I2S signals */
110 /* Cache of selected I2S registers for system suspend */
132 /* A flag indicating the I2S slave mode operation */
137 static inline bool is_secondary(struct i2s_dai *i2s) in is_secondary() argument
139 return i2s->drv->id == SAMSUNG_I2S_ID_SECONDARY; in is_secondary()
143 static inline bool tx_active(struct i2s_dai *i2s) in tx_active() argument
147 if (!i2s) in tx_active()
150 active = readl(i2s->priv->addr + I2SCON); in tx_active()
152 if (is_secondary(i2s)) in tx_active()
161 static inline struct i2s_dai *get_other_dai(struct i2s_dai *i2s) in get_other_dai() argument
163 return i2s->pri_dai ? : i2s->sec_dai; in get_other_dai()
167 static inline bool other_tx_active(struct i2s_dai *i2s) in other_tx_active() argument
169 struct i2s_dai *other = get_other_dai(i2s); in other_tx_active()
175 static inline bool any_tx_active(struct i2s_dai *i2s) in any_tx_active() argument
177 return tx_active(i2s) || other_tx_active(i2s); in any_tx_active()
181 static inline bool rx_active(struct i2s_dai *i2s) in rx_active() argument
185 if (!i2s) in rx_active()
188 active = readl(i2s->priv->addr + I2SCON) & CON_RXDMA_ACTIVE; in rx_active()
194 static inline bool other_rx_active(struct i2s_dai *i2s) in other_rx_active() argument
196 struct i2s_dai *other = get_other_dai(i2s); in other_rx_active()
202 static inline bool any_rx_active(struct i2s_dai *i2s) in any_rx_active() argument
204 return rx_active(i2s) || other_rx_active(i2s); in any_rx_active()
208 static inline bool other_active(struct i2s_dai *i2s) in other_active() argument
210 return other_rx_active(i2s) || other_tx_active(i2s); in other_active()
214 static inline bool this_active(struct i2s_dai *i2s) in this_active() argument
216 return tx_active(i2s) || rx_active(i2s); in this_active()
220 static inline bool any_active(struct i2s_dai *i2s) in any_active() argument
222 return this_active(i2s) || other_active(i2s); in any_active()
229 return &priv->dai[dai->id - 1]; in to_info()
232 static inline bool is_opened(struct i2s_dai *i2s) in is_opened() argument
234 if (i2s && (i2s->mode & DAI_OPENED)) in is_opened()
240 static inline bool is_manager(struct i2s_dai *i2s) in is_manager() argument
242 if (is_opened(i2s) && (i2s->mode & DAI_MANAGER)) in is_manager()
248 /* Read RCLK of I2S (in multiples of LRCLK) */
249 static inline unsigned get_rfs(struct i2s_dai *i2s) in get_rfs() argument
251 struct samsung_i2s_priv *priv = i2s->priv; in get_rfs()
254 rfs = readl(priv->addr + I2SMOD) >> priv->variant_regs->rfs_off; in get_rfs()
255 rfs &= priv->variant_regs->rfs_mask; in get_rfs()
269 /* Write RCLK of I2S (in multiples of LRCLK) */
270 static inline void set_rfs(struct i2s_dai *i2s, unsigned rfs) in set_rfs() argument
272 struct samsung_i2s_priv *priv = i2s->priv; in set_rfs()
273 u32 mod = readl(priv->addr + I2SMOD); in set_rfs()
274 int rfs_shift = priv->variant_regs->rfs_off; in set_rfs()
276 mod &= ~(priv->variant_regs->rfs_mask << rfs_shift); in set_rfs()
305 writel(mod, priv->addr + I2SMOD); in set_rfs()
308 /* Read bit-clock of I2S (in multiples of LRCLK) */
309 static inline unsigned get_bfs(struct i2s_dai *i2s) in get_bfs() argument
311 struct samsung_i2s_priv *priv = i2s->priv; in get_bfs()
314 bfs = readl(priv->addr + I2SMOD) >> priv->variant_regs->bfs_off; in get_bfs()
315 bfs &= priv->variant_regs->bfs_mask; in get_bfs()
330 /* Write bit-clock of I2S (in multiples of LRCLK) */
331 static inline void set_bfs(struct i2s_dai *i2s, unsigned bfs) in set_bfs() argument
333 struct samsung_i2s_priv *priv = i2s->priv; in set_bfs()
334 u32 mod = readl(priv->addr + I2SMOD); in set_bfs()
335 int tdm = priv->quirks & QUIRK_SUPPORTS_TDM; in set_bfs()
336 int bfs_shift = priv->variant_regs->bfs_off; in set_bfs()
338 /* Non-TDM I2S controllers do not support BCLK > 48 * FS */ in set_bfs()
340 dev_err(&i2s->pdev->dev, "Unsupported BCLK divider\n"); in set_bfs()
344 mod &= ~(priv->variant_regs->bfs_mask << bfs_shift); in set_bfs()
375 dev_err(&i2s->pdev->dev, "Wrong BCLK Divider!\n"); in set_bfs()
379 writel(mod, priv->addr + I2SMOD); in set_bfs()
383 static inline int get_blc(struct i2s_dai *i2s) in get_blc() argument
385 int blc = readl(i2s->priv->addr + I2SMOD); in get_blc()
397 static void i2s_txctrl(struct i2s_dai *i2s, int on) in i2s_txctrl() argument
399 struct samsung_i2s_priv *priv = i2s->priv; in i2s_txctrl()
400 void __iomem *addr = priv->addr; in i2s_txctrl()
401 int txr_off = priv->variant_regs->txr_off; in i2s_txctrl()
409 if (is_secondary(i2s)) { in i2s_txctrl()
417 if (any_rx_active(i2s)) in i2s_txctrl()
422 if (is_secondary(i2s)) { in i2s_txctrl()
430 if (other_tx_active(i2s)) { in i2s_txctrl()
437 if (any_rx_active(i2s)) in i2s_txctrl()
448 static void i2s_rxctrl(struct i2s_dai *i2s, int on) in i2s_rxctrl() argument
450 struct samsung_i2s_priv *priv = i2s->priv; in i2s_rxctrl()
451 void __iomem *addr = priv->addr; in i2s_rxctrl()
452 int txr_off = priv->variant_regs->txr_off; in i2s_rxctrl()
460 if (any_tx_active(i2s)) in i2s_rxctrl()
468 if (any_tx_active(i2s)) in i2s_rxctrl()
479 static inline void i2s_fifo(struct i2s_dai *i2s, u32 flush) in i2s_fifo() argument
484 if (!i2s) in i2s_fifo()
487 if (is_secondary(i2s)) in i2s_fifo()
488 fic = i2s->priv->addr + I2SFICS; in i2s_fifo()
490 fic = i2s->priv->addr + I2SFIC; in i2s_fifo()
497 while (--val) in i2s_fifo()
507 struct i2s_dai *i2s = to_info(dai); in i2s_set_sysclk() local
508 struct i2s_dai *other = get_other_dai(i2s); in i2s_set_sysclk()
509 const struct samsung_i2s_variant_regs *i2s_regs = priv->variant_regs; in i2s_set_sysclk()
510 unsigned int cdcon_mask = 1 << i2s_regs->cdclkcon_off; in i2s_set_sysclk()
511 unsigned int rsrc_mask = 1 << i2s_regs->rclksrc_off; in i2s_set_sysclk()
516 pm_runtime_get_sync(dai->dev); in i2s_set_sysclk()
518 spin_lock_irqsave(&priv->lock, flags); in i2s_set_sysclk()
519 mod = readl(priv->addr + I2SMOD); in i2s_set_sysclk()
520 spin_unlock_irqrestore(&priv->lock, flags); in i2s_set_sysclk()
528 mask = 1 << i2s_regs->cdclkcon_off; in i2s_set_sysclk()
533 if ((rfs && other && other->rfs && (other->rfs != rfs)) || in i2s_set_sysclk()
534 (any_active(i2s) && in i2s_set_sysclk()
539 dev_err(&i2s->pdev->dev, in i2s_set_sysclk()
541 ret = -EAGAIN; in i2s_set_sysclk()
546 val = 1 << i2s_regs->cdclkcon_off; in i2s_set_sysclk()
548 i2s->rfs = rfs; in i2s_set_sysclk()
553 mask = 1 << i2s_regs->rclksrc_off; in i2s_set_sysclk()
555 if ((priv->quirks & QUIRK_NO_MUXPSR) in i2s_set_sysclk()
561 if (!any_active(i2s)) { in i2s_set_sysclk()
562 if (priv->op_clk && !IS_ERR(priv->op_clk)) { in i2s_set_sysclk()
565 clk_disable_unprepare(priv->op_clk); in i2s_set_sysclk()
566 clk_put(priv->op_clk); in i2s_set_sysclk()
568 priv->rclk_srcrate = in i2s_set_sysclk()
569 clk_get_rate(priv->op_clk); in i2s_set_sysclk()
575 priv->op_clk = clk_get(&i2s->pdev->dev, in i2s_set_sysclk()
578 priv->op_clk = clk_get(&i2s->pdev->dev, in i2s_set_sysclk()
581 if (WARN_ON(IS_ERR(priv->op_clk))) { in i2s_set_sysclk()
582 ret = PTR_ERR(priv->op_clk); in i2s_set_sysclk()
583 priv->op_clk = NULL; in i2s_set_sysclk()
587 ret = clk_prepare_enable(priv->op_clk); in i2s_set_sysclk()
589 clk_put(priv->op_clk); in i2s_set_sysclk()
590 priv->op_clk = NULL; in i2s_set_sysclk()
593 priv->rclk_srcrate = clk_get_rate(priv->op_clk); in i2s_set_sysclk()
597 dev_err(&i2s->pdev->dev, in i2s_set_sysclk()
599 ret = -EAGAIN; in i2s_set_sysclk()
607 val = 1 << i2s_regs->rclksrc_off; in i2s_set_sysclk()
610 dev_err(&i2s->pdev->dev, "We don't serve that!\n"); in i2s_set_sysclk()
611 ret = -EINVAL; in i2s_set_sysclk()
615 spin_lock_irqsave(&priv->lock, flags); in i2s_set_sysclk()
616 mod = readl(priv->addr + I2SMOD); in i2s_set_sysclk()
618 writel(mod, priv->addr + I2SMOD); in i2s_set_sysclk()
619 spin_unlock_irqrestore(&priv->lock, flags); in i2s_set_sysclk()
621 pm_runtime_put(dai->dev); in i2s_set_sysclk()
625 pm_runtime_put(dai->dev); in i2s_set_sysclk()
632 struct i2s_dai *i2s = to_info(dai); in i2s_set_fmt() local
637 lrp_shift = priv->variant_regs->lrp_off; in i2s_set_fmt()
638 sdf_shift = priv->variant_regs->sdf_off; in i2s_set_fmt()
639 mod_slave = 1 << priv->variant_regs->mss_off; in i2s_set_fmt()
658 dev_err(&i2s->pdev->dev, "Format not supported\n"); in i2s_set_fmt()
659 return -EINVAL; in i2s_set_fmt()
663 * INV flag is relative to the FORMAT flag - if set it simply in i2s_set_fmt()
676 dev_err(&i2s->pdev->dev, "Polarity not supported\n"); in i2s_set_fmt()
677 return -EINVAL; in i2s_set_fmt()
690 if (priv->rclk_srcrate == 0 && priv->clk_data.clks == NULL) in i2s_set_fmt()
695 dev_err(&i2s->pdev->dev, "master/slave format not supported\n"); in i2s_set_fmt()
696 return -EINVAL; in i2s_set_fmt()
699 pm_runtime_get_sync(dai->dev); in i2s_set_fmt()
700 spin_lock_irqsave(&priv->lock, flags); in i2s_set_fmt()
701 mod = readl(priv->addr + I2SMOD); in i2s_set_fmt()
703 * Don't change the I2S mode if any controller is active on this in i2s_set_fmt()
706 if (any_active(i2s) && in i2s_set_fmt()
708 spin_unlock_irqrestore(&priv->lock, flags); in i2s_set_fmt()
709 pm_runtime_put(dai->dev); in i2s_set_fmt()
710 dev_err(&i2s->pdev->dev, in i2s_set_fmt()
712 return -EAGAIN; in i2s_set_fmt()
717 writel(mod, priv->addr + I2SMOD); in i2s_set_fmt()
718 priv->slave_mode = (mod & mod_slave); in i2s_set_fmt()
719 spin_unlock_irqrestore(&priv->lock, flags); in i2s_set_fmt()
720 pm_runtime_put(dai->dev); in i2s_set_fmt()
729 struct i2s_dai *i2s = to_info(dai); in i2s_hw_params() local
734 WARN_ON(!pm_runtime_active(dai->dev)); in i2s_hw_params()
736 if (!is_secondary(i2s)) in i2s_hw_params()
747 if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) in i2s_hw_params()
748 i2s->dma_playback.addr_width = 4; in i2s_hw_params()
750 i2s->dma_capture.addr_width = 4; in i2s_hw_params()
753 if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) in i2s_hw_params()
754 i2s->dma_playback.addr_width = 2; in i2s_hw_params()
756 i2s->dma_capture.addr_width = 2; in i2s_hw_params()
760 dev_err(&i2s->pdev->dev, "%d channels not supported\n", in i2s_hw_params()
762 return -EINVAL; in i2s_hw_params()
765 if (is_secondary(i2s)) in i2s_hw_params()
770 if (is_manager(i2s)) in i2s_hw_params()
775 if (is_secondary(i2s)) in i2s_hw_params()
779 if (is_manager(i2s)) in i2s_hw_params()
783 if (is_secondary(i2s)) in i2s_hw_params()
787 if (is_manager(i2s)) in i2s_hw_params()
791 if (is_secondary(i2s)) in i2s_hw_params()
795 if (is_manager(i2s)) in i2s_hw_params()
799 dev_err(&i2s->pdev->dev, "Format(%d) not supported\n", in i2s_hw_params()
801 return -EINVAL; in i2s_hw_params()
804 spin_lock_irqsave(&priv->lock, flags); in i2s_hw_params()
805 mod = readl(priv->addr + I2SMOD); in i2s_hw_params()
807 writel(mod, priv->addr + I2SMOD); in i2s_hw_params()
808 spin_unlock_irqrestore(&priv->lock, flags); in i2s_hw_params()
810 snd_soc_dai_init_dma_data(dai, &i2s->dma_playback, &i2s->dma_capture); in i2s_hw_params()
812 i2s->frmclk = params_rate(params); in i2s_hw_params()
814 rclksrc = priv->clk_table[CLK_I2S_RCLK_SRC]; in i2s_hw_params()
816 priv->rclk_srcrate = clk_get_rate(rclksrc); in i2s_hw_params()
821 /* We set constraints on the substream according to the version of I2S */
826 struct i2s_dai *i2s = to_info(dai); in i2s_startup() local
827 struct i2s_dai *other = get_other_dai(i2s); in i2s_startup()
830 pm_runtime_get_sync(dai->dev); in i2s_startup()
832 spin_lock_irqsave(&priv->pcm_lock, flags); in i2s_startup()
834 i2s->mode |= DAI_OPENED; in i2s_startup()
837 i2s->mode &= ~DAI_MANAGER; in i2s_startup()
839 i2s->mode |= DAI_MANAGER; in i2s_startup()
841 if (!any_active(i2s) && (priv->quirks & QUIRK_NEED_RSTCLR)) in i2s_startup()
842 writel(CON_RSTCLR, i2s->priv->addr + I2SCON); in i2s_startup()
844 spin_unlock_irqrestore(&priv->pcm_lock, flags); in i2s_startup()
853 struct i2s_dai *i2s = to_info(dai); in i2s_shutdown() local
854 struct i2s_dai *other = get_other_dai(i2s); in i2s_shutdown()
857 spin_lock_irqsave(&priv->pcm_lock, flags); in i2s_shutdown()
859 i2s->mode &= ~DAI_OPENED; in i2s_shutdown()
860 i2s->mode &= ~DAI_MANAGER; in i2s_shutdown()
863 other->mode |= DAI_MANAGER; in i2s_shutdown()
866 i2s->rfs = 0; in i2s_shutdown()
867 i2s->bfs = 0; in i2s_shutdown()
869 spin_unlock_irqrestore(&priv->pcm_lock, flags); in i2s_shutdown()
871 pm_runtime_put(dai->dev); in i2s_shutdown()
874 static int config_setup(struct i2s_dai *i2s) in config_setup() argument
876 struct samsung_i2s_priv *priv = i2s->priv; in config_setup()
877 struct i2s_dai *other = get_other_dai(i2s); in config_setup()
881 blc = get_blc(i2s); in config_setup()
883 bfs = i2s->bfs; in config_setup()
886 bfs = other->bfs; in config_setup()
892 rfs = i2s->rfs; in config_setup()
895 rfs = other->rfs; in config_setup()
898 dev_err(&i2s->pdev->dev, in config_setup()
899 "%d-RFS not supported for 24-blc\n", rfs); in config_setup()
900 return -EINVAL; in config_setup()
911 if (any_active(i2s) && (get_rfs(i2s) != rfs || get_bfs(i2s) != bfs)) { in config_setup()
912 dev_err(&i2s->pdev->dev, in config_setup()
914 return -EAGAIN; in config_setup()
917 set_bfs(i2s, bfs); in config_setup()
918 set_rfs(i2s, rfs); in config_setup()
921 if (priv->slave_mode) in config_setup()
924 if (!(priv->quirks & QUIRK_NO_MUXPSR)) { in config_setup()
925 psr = priv->rclk_srcrate / i2s->frmclk / rfs; in config_setup()
926 writel(((psr - 1) << 8) | PSR_PSREN, priv->addr + I2SPSR); in config_setup()
927 dev_dbg(&i2s->pdev->dev, in config_setup()
929 priv->rclk_srcrate, psr, rfs, bfs); in config_setup()
939 int capture = (substream->stream == SNDRV_PCM_STREAM_CAPTURE); in i2s_trigger()
941 struct i2s_dai *i2s = to_info(snd_soc_rtd_to_cpu(rtd, 0)); in i2s_trigger() local
948 pm_runtime_get_sync(dai->dev); in i2s_trigger()
950 if (priv->fixup_early) in i2s_trigger()
951 priv->fixup_early(substream, dai); in i2s_trigger()
953 spin_lock_irqsave(&priv->lock, flags); in i2s_trigger()
955 if (config_setup(i2s)) { in i2s_trigger()
956 spin_unlock_irqrestore(&priv->lock, flags); in i2s_trigger()
957 return -EINVAL; in i2s_trigger()
960 if (priv->fixup_late) in i2s_trigger()
961 priv->fixup_late(substream, dai); in i2s_trigger()
964 i2s_rxctrl(i2s, 1); in i2s_trigger()
966 i2s_txctrl(i2s, 1); in i2s_trigger()
968 spin_unlock_irqrestore(&priv->lock, flags); in i2s_trigger()
973 spin_lock_irqsave(&priv->lock, flags); in i2s_trigger()
976 i2s_rxctrl(i2s, 0); in i2s_trigger()
977 i2s_fifo(i2s, FIC_RXFLUSH); in i2s_trigger()
979 i2s_txctrl(i2s, 0); in i2s_trigger()
980 i2s_fifo(i2s, FIC_TXFLUSH); in i2s_trigger()
983 spin_unlock_irqrestore(&priv->lock, flags); in i2s_trigger()
984 pm_runtime_put(dai->dev); in i2s_trigger()
994 struct i2s_dai *i2s = to_info(dai); in i2s_set_clkdiv() local
995 struct i2s_dai *other = get_other_dai(i2s); in i2s_set_clkdiv()
999 pm_runtime_get_sync(dai->dev); in i2s_set_clkdiv()
1000 if ((any_active(i2s) && div && (get_bfs(i2s) != div)) in i2s_set_clkdiv()
1001 || (other && other->bfs && (other->bfs != div))) { in i2s_set_clkdiv()
1002 pm_runtime_put(dai->dev); in i2s_set_clkdiv()
1003 dev_err(&i2s->pdev->dev, in i2s_set_clkdiv()
1005 return -EAGAIN; in i2s_set_clkdiv()
1007 i2s->bfs = div; in i2s_set_clkdiv()
1008 pm_runtime_put(dai->dev); in i2s_set_clkdiv()
1011 dev_err(&i2s->pdev->dev, in i2s_set_clkdiv()
1013 return -EINVAL; in i2s_set_clkdiv()
1023 struct i2s_dai *i2s = to_info(dai); in i2s_delay() local
1024 u32 reg = readl(priv->addr + I2SFIC); in i2s_delay()
1027 WARN_ON(!pm_runtime_active(dai->dev)); in i2s_delay()
1029 if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) in i2s_delay()
1031 else if (is_secondary(i2s)) in i2s_delay()
1032 delay = FICS_TXCOUNT(readl(priv->addr + I2SFICS)); in i2s_delay()
1034 delay = (reg >> priv->variant_regs->ftx0cnt_off) & 0x7f; in i2s_delay()
1042 return pm_runtime_force_suspend(component->dev); in i2s_suspend()
1047 return pm_runtime_force_resume(component->dev); in i2s_resume()
1057 struct i2s_dai *i2s = to_info(dai); in samsung_i2s_dai_probe() local
1058 struct i2s_dai *other = get_other_dai(i2s); in samsung_i2s_dai_probe()
1061 pm_runtime_get_sync(dai->dev); in samsung_i2s_dai_probe()
1063 if (is_secondary(i2s)) { in samsung_i2s_dai_probe()
1065 snd_soc_dai_init_dma_data(dai, &i2s->dma_playback, NULL); in samsung_i2s_dai_probe()
1067 snd_soc_dai_init_dma_data(dai, &i2s->dma_playback, in samsung_i2s_dai_probe()
1068 &i2s->dma_capture); in samsung_i2s_dai_probe()
1070 if (priv->quirks & QUIRK_NEED_RSTCLR) in samsung_i2s_dai_probe()
1071 writel(CON_RSTCLR, priv->addr + I2SCON); in samsung_i2s_dai_probe()
1073 if (priv->quirks & QUIRK_SUPPORTS_IDMA) in samsung_i2s_dai_probe()
1074 idma_reg_addr_init(priv->addr, in samsung_i2s_dai_probe()
1075 other->idma_playback.addr); in samsung_i2s_dai_probe()
1079 i2s->rfs = 0; in samsung_i2s_dai_probe()
1080 i2s->bfs = 0; in samsung_i2s_dai_probe()
1082 spin_lock_irqsave(&priv->lock, flags); in samsung_i2s_dai_probe()
1083 i2s_txctrl(i2s, 0); in samsung_i2s_dai_probe()
1084 i2s_rxctrl(i2s, 0); in samsung_i2s_dai_probe()
1085 i2s_fifo(i2s, FIC_TXFLUSH); in samsung_i2s_dai_probe()
1087 i2s_fifo(i2s, FIC_RXFLUSH); in samsung_i2s_dai_probe()
1088 spin_unlock_irqrestore(&priv->lock, flags); in samsung_i2s_dai_probe()
1094 pm_runtime_put(dai->dev); in samsung_i2s_dai_probe()
1102 struct i2s_dai *i2s = to_info(dai); in samsung_i2s_dai_remove() local
1105 pm_runtime_get_sync(dai->dev); in samsung_i2s_dai_remove()
1107 if (!is_secondary(i2s)) { in samsung_i2s_dai_remove()
1108 if (priv->quirks & QUIRK_NEED_RSTCLR) { in samsung_i2s_dai_remove()
1109 spin_lock_irqsave(&priv->lock, flags); in samsung_i2s_dai_remove()
1110 writel(0, priv->addr + I2SCON); in samsung_i2s_dai_remove()
1111 spin_unlock_irqrestore(&priv->lock, flags); in samsung_i2s_dai_remove()
1115 pm_runtime_put(dai->dev); in samsung_i2s_dai_remove()
1151 .name = "samsung-i2s",
1172 static const char *dai_names[] = { "samsung-i2s", "samsung-i2s-sec" }; in i2s_alloc_dais()
1178 priv->dai = devm_kcalloc(&priv->pdev->dev, num_dais, in i2s_alloc_dais()
1180 if (!priv->dai) in i2s_alloc_dais()
1181 return -ENOMEM; in i2s_alloc_dais()
1183 priv->dai_drv = devm_kcalloc(&priv->pdev->dev, num_dais, in i2s_alloc_dais()
1185 if (!priv->dai_drv) in i2s_alloc_dais()
1186 return -ENOMEM; in i2s_alloc_dais()
1189 dai_drv = &priv->dai_drv[i]; in i2s_alloc_dais()
1191 dai_drv->symmetric_rate = 1; in i2s_alloc_dais()
1192 dai_drv->ops = &samsung_i2s_dai_ops; in i2s_alloc_dais()
1194 dai_drv->playback.channels_min = 1; in i2s_alloc_dais()
1195 dai_drv->playback.channels_max = 2; in i2s_alloc_dais()
1196 dai_drv->playback.rates = i2s_dai_data->pcm_rates; in i2s_alloc_dais()
1197 dai_drv->playback.formats = SAMSUNG_I2S_FMTS; in i2s_alloc_dais()
1198 dai_drv->playback.stream_name = stream_names[i]; in i2s_alloc_dais()
1200 dai_drv->id = i + 1; in i2s_alloc_dais()
1201 dai_drv->name = dai_names[i]; in i2s_alloc_dais()
1203 priv->dai[i].drv = &priv->dai_drv[i]; in i2s_alloc_dais()
1204 priv->dai[i].pdev = priv->pdev; in i2s_alloc_dais()
1208 dai_drv = &priv->dai_drv[SAMSUNG_I2S_ID_PRIMARY - 1]; in i2s_alloc_dais()
1210 dai_drv->capture.channels_min = 1; in i2s_alloc_dais()
1211 dai_drv->capture.channels_max = 2; in i2s_alloc_dais()
1212 dai_drv->capture.rates = i2s_dai_data->pcm_rates; in i2s_alloc_dais()
1213 dai_drv->capture.formats = SAMSUNG_I2S_FMTS; in i2s_alloc_dais()
1214 dai_drv->capture.stream_name = "Primary Capture"; in i2s_alloc_dais()
1224 priv->suspend_i2smod = readl(priv->addr + I2SMOD); in i2s_runtime_suspend()
1225 priv->suspend_i2scon = readl(priv->addr + I2SCON); in i2s_runtime_suspend()
1226 priv->suspend_i2spsr = readl(priv->addr + I2SPSR); in i2s_runtime_suspend()
1228 clk_disable_unprepare(priv->op_clk); in i2s_runtime_suspend()
1229 clk_disable_unprepare(priv->clk); in i2s_runtime_suspend()
1239 ret = clk_prepare_enable(priv->clk); in i2s_runtime_resume()
1243 if (priv->op_clk) { in i2s_runtime_resume()
1244 ret = clk_prepare_enable(priv->op_clk); in i2s_runtime_resume()
1246 clk_disable_unprepare(priv->clk); in i2s_runtime_resume()
1251 writel(priv->suspend_i2scon, priv->addr + I2SCON); in i2s_runtime_resume()
1252 writel(priv->suspend_i2smod, priv->addr + I2SMOD); in i2s_runtime_resume()
1253 writel(priv->suspend_i2spsr, priv->addr + I2SPSR); in i2s_runtime_resume()
1263 for (i = 0; i < priv->clk_data.clk_num; i++) { in i2s_unregister_clocks()
1264 if (!IS_ERR(priv->clk_table[i])) in i2s_unregister_clocks()
1265 clk_unregister(priv->clk_table[i]); in i2s_unregister_clocks()
1271 of_clk_del_provider(priv->pdev->dev.of_node); in i2s_unregister_clock_provider()
1282 struct device *dev = &priv->pdev->dev; in i2s_register_clock_provider()
1283 const struct samsung_i2s_variant_regs *reg_info = priv->variant_regs; in i2s_register_clock_provider()
1289 if (!of_property_present(dev->of_node, "#clock-cells")) in i2s_register_clock_provider()
1305 return -ENOMEM; in i2s_register_clock_provider()
1308 if (!(priv->quirks & QUIRK_NO_MUXPSR)) { in i2s_register_clock_provider()
1310 u32 val = readl(priv->addr + I2SPSR); in i2s_register_clock_provider()
1311 writel(val | PSR_PSREN, priv->addr + I2SPSR); in i2s_register_clock_provider()
1313 priv->clk_table[CLK_I2S_RCLK_SRC] = clk_register_mux(dev, in i2s_register_clock_provider()
1317 priv->addr + I2SMOD, reg_info->rclksrc_off, in i2s_register_clock_provider()
1318 1, 0, &priv->lock); in i2s_register_clock_provider()
1320 priv->clk_table[CLK_I2S_RCLK_PSR] = clk_register_divider(dev, in i2s_register_clock_provider()
1324 priv->addr + I2SPSR, 8, 6, 0, &priv->lock); in i2s_register_clock_provider()
1327 priv->clk_data.clk_num = 2; in i2s_register_clock_provider()
1330 priv->clk_table[CLK_I2S_CDCLK] = clk_register_gate(dev, in i2s_register_clock_provider()
1333 priv->addr + I2SMOD, reg_info->cdclkcon_off, in i2s_register_clock_provider()
1334 CLK_GATE_SET_TO_DISABLE, &priv->lock); in i2s_register_clock_provider()
1336 priv->clk_data.clk_num += 1; in i2s_register_clock_provider()
1337 priv->clk_data.clks = priv->clk_table; in i2s_register_clock_provider()
1339 ret = of_clk_add_provider(dev->of_node, of_clk_src_onecell_get, in i2s_register_clock_provider()
1340 &priv->clk_data); in i2s_register_clock_provider()
1356 devname = devm_kasprintf(&priv->pdev->dev, GFP_KERNEL, "%s-sec", in i2s_create_secondary_device()
1357 dev_name(&priv->pdev->dev)); in i2s_create_secondary_device()
1359 return -ENOMEM; in i2s_create_secondary_device()
1361 pdev_sec = platform_device_alloc(devname, -1); in i2s_create_secondary_device()
1363 return -ENOMEM; in i2s_create_secondary_device()
1365 pdev_sec->driver_override = kstrdup("samsung-i2s", GFP_KERNEL); in i2s_create_secondary_device()
1366 if (!pdev_sec->driver_override) { in i2s_create_secondary_device()
1368 return -ENOMEM; in i2s_create_secondary_device()
1377 ret = device_attach(&pdev_sec->dev); in i2s_create_secondary_device()
1379 platform_device_unregister(priv->pdev_sec); in i2s_create_secondary_device()
1380 dev_info(&pdev_sec->dev, "device_attach() failed\n"); in i2s_create_secondary_device()
1384 priv->pdev_sec = pdev_sec; in i2s_create_secondary_device()
1391 platform_device_unregister(priv->pdev_sec); in i2s_delete_secondary_device()
1392 priv->pdev_sec = NULL; in i2s_delete_secondary_device()
1398 struct s3c_audio_pdata *i2s_pdata = pdev->dev.platform_data; in samsung_i2s_probe()
1400 struct device_node *np = pdev->dev.of_node; in samsung_i2s_probe()
1407 if (IS_ENABLED(CONFIG_OF) && pdev->dev.of_node) { in samsung_i2s_probe()
1408 i2s_dai_data = of_device_get_match_data(&pdev->dev); in samsung_i2s_probe()
1416 i2s_dai_data = (struct samsung_i2s_dai_data *)id->driver_data; in samsung_i2s_probe()
1419 priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL); in samsung_i2s_probe()
1421 return -ENOMEM; in samsung_i2s_probe()
1424 priv->quirks = i2s_dai_data->quirks; in samsung_i2s_probe()
1425 priv->fixup_early = i2s_dai_data->fixup_early; in samsung_i2s_probe()
1426 priv->fixup_late = i2s_dai_data->fixup_late; in samsung_i2s_probe()
1429 dev_err(&pdev->dev, "Missing platform data\n"); in samsung_i2s_probe()
1430 return -EINVAL; in samsung_i2s_probe()
1432 priv->quirks = i2s_pdata->type.quirks; in samsung_i2s_probe()
1435 num_dais = (priv->quirks & QUIRK_SEC_DAI) ? 2 : 1; in samsung_i2s_probe()
1436 priv->pdev = pdev; in samsung_i2s_probe()
1437 priv->variant_regs = i2s_dai_data->i2s_variant_regs; in samsung_i2s_probe()
1443 pri_dai = &priv->dai[SAMSUNG_I2S_ID_PRIMARY - 1]; in samsung_i2s_probe()
1445 spin_lock_init(&priv->lock); in samsung_i2s_probe()
1446 spin_lock_init(&priv->pcm_lock); in samsung_i2s_probe()
1449 pri_dai->dma_playback.filter_data = i2s_pdata->dma_playback; in samsung_i2s_probe()
1450 pri_dai->dma_capture.filter_data = i2s_pdata->dma_capture; in samsung_i2s_probe()
1451 pri_dai->filter = i2s_pdata->dma_filter; in samsung_i2s_probe()
1453 idma_addr = i2s_pdata->type.idma_addr; in samsung_i2s_probe()
1455 if (of_property_read_u32(np, "samsung,idma-addr", in samsung_i2s_probe()
1457 if (priv->quirks & QUIRK_SUPPORTS_IDMA) { in samsung_i2s_probe()
1458 dev_info(&pdev->dev, "idma address is not"\ in samsung_i2s_probe()
1464 priv->addr = devm_platform_get_and_ioremap_resource(pdev, 0, &res); in samsung_i2s_probe()
1465 if (IS_ERR(priv->addr)) in samsung_i2s_probe()
1466 return PTR_ERR(priv->addr); in samsung_i2s_probe()
1468 regs_base = res->start; in samsung_i2s_probe()
1470 priv->clk = devm_clk_get(&pdev->dev, "iis"); in samsung_i2s_probe()
1471 if (IS_ERR(priv->clk)) { in samsung_i2s_probe()
1472 dev_err(&pdev->dev, "Failed to get iis clock\n"); in samsung_i2s_probe()
1473 return PTR_ERR(priv->clk); in samsung_i2s_probe()
1476 ret = clk_prepare_enable(priv->clk); in samsung_i2s_probe()
1478 dev_err(&pdev->dev, "failed to enable clock: %d\n", ret); in samsung_i2s_probe()
1481 pri_dai->dma_playback.addr = regs_base + I2STXD; in samsung_i2s_probe()
1482 pri_dai->dma_capture.addr = regs_base + I2SRXD; in samsung_i2s_probe()
1483 pri_dai->dma_playback.chan_name = "tx"; in samsung_i2s_probe()
1484 pri_dai->dma_capture.chan_name = "rx"; in samsung_i2s_probe()
1485 pri_dai->dma_playback.addr_width = 4; in samsung_i2s_probe()
1486 pri_dai->dma_capture.addr_width = 4; in samsung_i2s_probe()
1487 pri_dai->priv = priv; in samsung_i2s_probe()
1489 if (priv->quirks & QUIRK_PRI_6CHAN) in samsung_i2s_probe()
1490 pri_dai->drv->playback.channels_max = 6; in samsung_i2s_probe()
1492 ret = samsung_asoc_dma_platform_register(&pdev->dev, pri_dai->filter, in samsung_i2s_probe()
1497 if (priv->quirks & QUIRK_SEC_DAI) { in samsung_i2s_probe()
1498 sec_dai = &priv->dai[SAMSUNG_I2S_ID_SECONDARY - 1]; in samsung_i2s_probe()
1500 sec_dai->dma_playback.addr = regs_base + I2STXDS; in samsung_i2s_probe()
1501 sec_dai->dma_playback.chan_name = "tx-sec"; in samsung_i2s_probe()
1504 sec_dai->dma_playback.filter_data = i2s_pdata->dma_play_sec; in samsung_i2s_probe()
1505 sec_dai->filter = i2s_pdata->dma_filter; in samsung_i2s_probe()
1508 sec_dai->dma_playback.addr_width = 4; in samsung_i2s_probe()
1509 sec_dai->idma_playback.addr = idma_addr; in samsung_i2s_probe()
1510 sec_dai->pri_dai = pri_dai; in samsung_i2s_probe()
1511 sec_dai->priv = priv; in samsung_i2s_probe()
1512 pri_dai->sec_dai = sec_dai; in samsung_i2s_probe()
1518 ret = samsung_asoc_dma_platform_register(&priv->pdev_sec->dev, in samsung_i2s_probe()
1519 sec_dai->filter, "tx-sec", NULL, in samsung_i2s_probe()
1520 &pdev->dev); in samsung_i2s_probe()
1526 if (i2s_pdata && i2s_pdata->cfg_gpio && i2s_pdata->cfg_gpio(pdev)) { in samsung_i2s_probe()
1527 dev_err(&pdev->dev, "Unable to configure gpio\n"); in samsung_i2s_probe()
1528 ret = -EINVAL; in samsung_i2s_probe()
1532 dev_set_drvdata(&pdev->dev, priv); in samsung_i2s_probe()
1534 ret = devm_snd_soc_register_component(&pdev->dev, in samsung_i2s_probe()
1536 priv->dai_drv, num_dais); in samsung_i2s_probe()
1540 pm_runtime_set_active(&pdev->dev); in samsung_i2s_probe()
1541 pm_runtime_enable(&pdev->dev); in samsung_i2s_probe()
1547 priv->op_clk = clk_get_parent(priv->clk_table[CLK_I2S_RCLK_SRC]); in samsung_i2s_probe()
1552 pm_runtime_disable(&pdev->dev); in samsung_i2s_probe()
1556 clk_disable_unprepare(priv->clk); in samsung_i2s_probe()
1562 struct samsung_i2s_priv *priv = dev_get_drvdata(&pdev->dev); in samsung_i2s_remove()
1568 pm_runtime_get_sync(&pdev->dev); in samsung_i2s_remove()
1569 pm_runtime_disable(&pdev->dev); in samsung_i2s_remove()
1573 clk_disable_unprepare(priv->clk); in samsung_i2s_remove()
1575 pm_runtime_put_noidle(&pdev->dev); in samsung_i2s_remove()
1582 struct i2s_dai *i2s = to_info(snd_soc_rtd_to_cpu(rtd, 0)); in fsd_i2s_fixup_early() local
1583 struct i2s_dai *other = get_other_dai(i2s); in fsd_i2s_fixup_early()
1596 struct i2s_dai *i2s = to_info(snd_soc_rtd_to_cpu(rtd, 0)); in fsd_i2s_fixup_late() local
1597 struct i2s_dai *other = get_other_dai(i2s); in fsd_i2s_fixup_late()
1600 writel(PSR_PSVAL(2) | PSR_PSREN, priv->addr + I2SPSR); in fsd_i2s_fixup_late()
1702 .name = "samsung-i2s",
1712 .compatible = "samsung,s3c6410-i2s",
1715 .compatible = "samsung,s5pv210-i2s",
1718 .compatible = "samsung,exynos5420-i2s",
1721 .compatible = "samsung,exynos7-i2s",
1724 .compatible = "samsung,exynos7-i2s1",
1727 .compatible = "tesla,fsd-i2s",
1747 .name = "samsung-i2s",
1757 MODULE_DESCRIPTION("Samsung I2S Interface");