Lines Matching full:i2s
3 // ALSA SoC Audio Layer - Samsung I2S Controller driver
8 #include <dt-bindings/sound/samsung-i2s.h>
27 #include "i2s.h"
28 #include "i2s-regs.h"
99 /* The I2S controller's core clock */
102 /* Clock for generating I2S signals */
108 /* Cache of selected I2S registers for system suspend */
126 /* A flag indicating the I2S slave mode operation */
131 static inline bool is_secondary(struct i2s_dai *i2s) in is_secondary() argument
133 return i2s->drv->id == SAMSUNG_I2S_ID_SECONDARY; in is_secondary()
137 static inline bool tx_active(struct i2s_dai *i2s) in tx_active() argument
141 if (!i2s) in tx_active()
144 active = readl(i2s->priv->addr + I2SCON); in tx_active()
146 if (is_secondary(i2s)) in tx_active()
155 static inline struct i2s_dai *get_other_dai(struct i2s_dai *i2s) in get_other_dai() argument
157 return i2s->pri_dai ? : i2s->sec_dai; in get_other_dai()
161 static inline bool other_tx_active(struct i2s_dai *i2s) in other_tx_active() argument
163 struct i2s_dai *other = get_other_dai(i2s); in other_tx_active()
169 static inline bool any_tx_active(struct i2s_dai *i2s) in any_tx_active() argument
171 return tx_active(i2s) || other_tx_active(i2s); in any_tx_active()
175 static inline bool rx_active(struct i2s_dai *i2s) in rx_active() argument
179 if (!i2s) in rx_active()
182 active = readl(i2s->priv->addr + I2SCON) & CON_RXDMA_ACTIVE; in rx_active()
188 static inline bool other_rx_active(struct i2s_dai *i2s) in other_rx_active() argument
190 struct i2s_dai *other = get_other_dai(i2s); in other_rx_active()
196 static inline bool any_rx_active(struct i2s_dai *i2s) in any_rx_active() argument
198 return rx_active(i2s) || other_rx_active(i2s); in any_rx_active()
202 static inline bool other_active(struct i2s_dai *i2s) in other_active() argument
204 return other_rx_active(i2s) || other_tx_active(i2s); in other_active()
208 static inline bool this_active(struct i2s_dai *i2s) in this_active() argument
210 return tx_active(i2s) || rx_active(i2s); in this_active()
214 static inline bool any_active(struct i2s_dai *i2s) in any_active() argument
216 return this_active(i2s) || other_active(i2s); in any_active()
226 static inline bool is_opened(struct i2s_dai *i2s) in is_opened() argument
228 if (i2s && (i2s->mode & DAI_OPENED)) in is_opened()
234 static inline bool is_manager(struct i2s_dai *i2s) in is_manager() argument
236 if (is_opened(i2s) && (i2s->mode & DAI_MANAGER)) in is_manager()
242 /* Read RCLK of I2S (in multiples of LRCLK) */
243 static inline unsigned get_rfs(struct i2s_dai *i2s) in get_rfs() argument
245 struct samsung_i2s_priv *priv = i2s->priv; in get_rfs()
263 /* Write RCLK of I2S (in multiples of LRCLK) */
264 static inline void set_rfs(struct i2s_dai *i2s, unsigned rfs) in set_rfs() argument
266 struct samsung_i2s_priv *priv = i2s->priv; in set_rfs()
302 /* Read bit-clock of I2S (in multiples of LRCLK) */
303 static inline unsigned get_bfs(struct i2s_dai *i2s) in get_bfs() argument
305 struct samsung_i2s_priv *priv = i2s->priv; in get_bfs()
324 /* Write bit-clock of I2S (in multiples of LRCLK) */
325 static inline void set_bfs(struct i2s_dai *i2s, unsigned bfs) in set_bfs() argument
327 struct samsung_i2s_priv *priv = i2s->priv; in set_bfs()
332 /* Non-TDM I2S controllers do not support BCLK > 48 * FS */ in set_bfs()
334 dev_err(&i2s->pdev->dev, "Unsupported BCLK divider\n"); in set_bfs()
369 dev_err(&i2s->pdev->dev, "Wrong BCLK Divider!\n"); in set_bfs()
377 static inline int get_blc(struct i2s_dai *i2s) in get_blc() argument
379 int blc = readl(i2s->priv->addr + I2SMOD); in get_blc()
391 static void i2s_txctrl(struct i2s_dai *i2s, int on) in i2s_txctrl() argument
393 struct samsung_i2s_priv *priv = i2s->priv; in i2s_txctrl()
403 if (is_secondary(i2s)) { in i2s_txctrl()
411 if (any_rx_active(i2s)) in i2s_txctrl()
416 if (is_secondary(i2s)) { in i2s_txctrl()
424 if (other_tx_active(i2s)) { in i2s_txctrl()
431 if (any_rx_active(i2s)) in i2s_txctrl()
442 static void i2s_rxctrl(struct i2s_dai *i2s, int on) in i2s_rxctrl() argument
444 struct samsung_i2s_priv *priv = i2s->priv; in i2s_rxctrl()
454 if (any_tx_active(i2s)) in i2s_rxctrl()
462 if (any_tx_active(i2s)) in i2s_rxctrl()
473 static inline void i2s_fifo(struct i2s_dai *i2s, u32 flush) in i2s_fifo() argument
478 if (!i2s) in i2s_fifo()
481 if (is_secondary(i2s)) in i2s_fifo()
482 fic = i2s->priv->addr + I2SFICS; in i2s_fifo()
484 fic = i2s->priv->addr + I2SFIC; in i2s_fifo()
501 struct i2s_dai *i2s = to_info(dai); in i2s_set_sysclk() local
502 struct i2s_dai *other = get_other_dai(i2s); in i2s_set_sysclk()
528 (any_active(i2s) && in i2s_set_sysclk()
533 dev_err(&i2s->pdev->dev, in i2s_set_sysclk()
542 i2s->rfs = rfs; in i2s_set_sysclk()
555 if (!any_active(i2s)) { in i2s_set_sysclk()
569 priv->op_clk = clk_get(&i2s->pdev->dev, in i2s_set_sysclk()
572 priv->op_clk = clk_get(&i2s->pdev->dev, in i2s_set_sysclk()
591 dev_err(&i2s->pdev->dev, in i2s_set_sysclk()
604 dev_err(&i2s->pdev->dev, "We don't serve that!\n"); in i2s_set_sysclk()
626 struct i2s_dai *i2s = to_info(dai); in i2s_set_fmt() local
652 dev_err(&i2s->pdev->dev, "Format not supported\n"); in i2s_set_fmt()
670 dev_err(&i2s->pdev->dev, "Polarity not supported\n"); in i2s_set_fmt()
689 dev_err(&i2s->pdev->dev, "master/slave format not supported\n"); in i2s_set_fmt()
697 * Don't change the I2S mode if any controller is active on this in i2s_set_fmt()
700 if (any_active(i2s) && in i2s_set_fmt()
704 dev_err(&i2s->pdev->dev, in i2s_set_fmt()
723 struct i2s_dai *i2s = to_info(dai); in i2s_hw_params() local
730 if (!is_secondary(i2s)) in i2s_hw_params()
742 i2s->dma_playback.addr_width = 4; in i2s_hw_params()
744 i2s->dma_capture.addr_width = 4; in i2s_hw_params()
748 i2s->dma_playback.addr_width = 2; in i2s_hw_params()
750 i2s->dma_capture.addr_width = 2; in i2s_hw_params()
754 dev_err(&i2s->pdev->dev, "%d channels not supported\n", in i2s_hw_params()
759 if (is_secondary(i2s)) in i2s_hw_params()
764 if (is_manager(i2s)) in i2s_hw_params()
769 if (is_secondary(i2s)) in i2s_hw_params()
773 if (is_manager(i2s)) in i2s_hw_params()
777 if (is_secondary(i2s)) in i2s_hw_params()
781 if (is_manager(i2s)) in i2s_hw_params()
785 if (is_secondary(i2s)) in i2s_hw_params()
789 if (is_manager(i2s)) in i2s_hw_params()
793 dev_err(&i2s->pdev->dev, "Format(%d) not supported\n", in i2s_hw_params()
804 snd_soc_dai_init_dma_data(dai, &i2s->dma_playback, &i2s->dma_capture); in i2s_hw_params()
806 i2s->frmclk = params_rate(params); in i2s_hw_params()
815 /* We set constraints on the substream according to the version of I2S */
820 struct i2s_dai *i2s = to_info(dai); in i2s_startup() local
821 struct i2s_dai *other = get_other_dai(i2s); in i2s_startup()
828 i2s->mode |= DAI_OPENED; in i2s_startup()
831 i2s->mode &= ~DAI_MANAGER; in i2s_startup()
833 i2s->mode |= DAI_MANAGER; in i2s_startup()
835 if (!any_active(i2s) && (priv->quirks & QUIRK_NEED_RSTCLR)) in i2s_startup()
836 writel(CON_RSTCLR, i2s->priv->addr + I2SCON); in i2s_startup()
847 struct i2s_dai *i2s = to_info(dai); in i2s_shutdown() local
848 struct i2s_dai *other = get_other_dai(i2s); in i2s_shutdown()
853 i2s->mode &= ~DAI_OPENED; in i2s_shutdown()
854 i2s->mode &= ~DAI_MANAGER; in i2s_shutdown()
860 i2s->rfs = 0; in i2s_shutdown()
861 i2s->bfs = 0; in i2s_shutdown()
868 static int config_setup(struct i2s_dai *i2s) in config_setup() argument
870 struct samsung_i2s_priv *priv = i2s->priv; in config_setup()
871 struct i2s_dai *other = get_other_dai(i2s); in config_setup()
875 blc = get_blc(i2s); in config_setup()
877 bfs = i2s->bfs; in config_setup()
886 rfs = i2s->rfs; in config_setup()
892 dev_err(&i2s->pdev->dev, in config_setup()
905 if (any_active(i2s) && (get_rfs(i2s) != rfs || get_bfs(i2s) != bfs)) { in config_setup()
906 dev_err(&i2s->pdev->dev, in config_setup()
911 set_bfs(i2s, bfs); in config_setup()
912 set_rfs(i2s, rfs); in config_setup()
919 psr = priv->rclk_srcrate / i2s->frmclk / rfs; in config_setup()
921 dev_dbg(&i2s->pdev->dev, in config_setup()
935 struct i2s_dai *i2s = to_info(asoc_rtd_to_cpu(rtd, 0)); in i2s_trigger() local
945 if (config_setup(i2s)) { in i2s_trigger()
951 i2s_rxctrl(i2s, 1); in i2s_trigger()
953 i2s_txctrl(i2s, 1); in i2s_trigger()
963 i2s_rxctrl(i2s, 0); in i2s_trigger()
964 i2s_fifo(i2s, FIC_RXFLUSH); in i2s_trigger()
966 i2s_txctrl(i2s, 0); in i2s_trigger()
967 i2s_fifo(i2s, FIC_TXFLUSH); in i2s_trigger()
981 struct i2s_dai *i2s = to_info(dai); in i2s_set_clkdiv() local
982 struct i2s_dai *other = get_other_dai(i2s); in i2s_set_clkdiv()
987 if ((any_active(i2s) && div && (get_bfs(i2s) != div)) in i2s_set_clkdiv()
990 dev_err(&i2s->pdev->dev, in i2s_set_clkdiv()
994 i2s->bfs = div; in i2s_set_clkdiv()
998 dev_err(&i2s->pdev->dev, in i2s_set_clkdiv()
1010 struct i2s_dai *i2s = to_info(dai); in i2s_delay() local
1018 else if (is_secondary(i2s)) in i2s_delay()
1044 struct i2s_dai *i2s = to_info(dai); in samsung_i2s_dai_probe() local
1045 struct i2s_dai *other = get_other_dai(i2s); in samsung_i2s_dai_probe()
1050 if (is_secondary(i2s)) { in samsung_i2s_dai_probe()
1052 snd_soc_dai_init_dma_data(dai, &i2s->dma_playback, NULL); in samsung_i2s_dai_probe()
1054 snd_soc_dai_init_dma_data(dai, &i2s->dma_playback, in samsung_i2s_dai_probe()
1055 &i2s->dma_capture); in samsung_i2s_dai_probe()
1066 i2s->rfs = 0; in samsung_i2s_dai_probe()
1067 i2s->bfs = 0; in samsung_i2s_dai_probe()
1070 i2s_txctrl(i2s, 0); in samsung_i2s_dai_probe()
1071 i2s_rxctrl(i2s, 0); in samsung_i2s_dai_probe()
1072 i2s_fifo(i2s, FIC_TXFLUSH); in samsung_i2s_dai_probe()
1074 i2s_fifo(i2s, FIC_RXFLUSH); in samsung_i2s_dai_probe()
1089 struct i2s_dai *i2s = to_info(dai); in samsung_i2s_dai_remove() local
1094 if (!is_secondary(i2s)) { in samsung_i2s_dai_remove()
1136 .name = "samsung-i2s",
1157 static const char *dai_names[] = { "samsung-i2s", "samsung-i2s-sec" }; in i2s_alloc_dais()
1353 pdev_sec->driver_override = kstrdup("samsung-i2s", GFP_KERNEL); in i2s_create_secondary_device()
1657 .name = "samsung-i2s",
1667 .compatible = "samsung,s3c6410-i2s",
1670 .compatible = "samsung,s5pv210-i2s",
1673 .compatible = "samsung,exynos5420-i2s",
1676 .compatible = "samsung,exynos7-i2s",
1699 .name = "samsung-i2s",
1709 MODULE_DESCRIPTION("Samsung I2S Interface");
1710 MODULE_ALIAS("platform:samsung-i2s");