1 // SPDX-License-Identifier: GPL-2.0+
3 * Copyright 2018 Google LLC
4 * Written by Simon Glass <sjg@chromium.org>
6 #define LOG_CATEGORY UCLASS_I2S
15 #include <asm/arch-tegra/tegra_i2s.h>
16 #include "tegra_i2s_priv.h"
18 int tegra_i2s_set_cif_tx_ctrl(struct udevice *dev, u32 value)
20 struct i2s_uc_priv *priv = dev_get_uclass_priv(dev);
21 struct i2s_ctlr *regs = (struct i2s_ctlr *)priv->base_address;
23 writel(value, ®s->cif_tx_ctrl);
28 static void tegra_i2s_transmit_enable(struct i2s_ctlr *regs, int on)
30 clrsetbits_le32(®s->ctrl, I2S_CTRL_XFER_EN_TX,
31 on ? I2S_CTRL_XFER_EN_TX : 0);
34 static int i2s_tx_init(struct i2s_uc_priv *pi2s_tx)
36 struct i2s_ctlr *regs = (struct i2s_ctlr *)pi2s_tx->base_address;
37 u32 audio_bits = (pi2s_tx->bitspersample >> 2) - 1;
38 u32 ctrl = readl(®s->ctrl);
40 /* Set format to LRCK / Left Low */
41 ctrl &= ~(I2S_CTRL_FRAME_FORMAT_MASK | I2S_CTRL_LRCK_MASK);
42 ctrl |= I2S_CTRL_FRAME_FORMAT_LRCK;
43 ctrl |= I2S_CTRL_LRCK_L_LOW;
45 /* Disable all transmission until we are ready to transfer */
46 ctrl &= ~(I2S_CTRL_XFER_EN_TX | I2S_CTRL_XFER_EN_RX);
49 ctrl |= I2S_CTRL_MASTER_ENABLE;
51 /* Configure audio bits size */
52 ctrl &= ~I2S_CTRL_BIT_SIZE_MASK;
53 ctrl |= audio_bits << I2S_CTRL_BIT_SIZE_SHIFT;
54 writel(ctrl, ®s->ctrl);
56 /* Timing in LRCK mode: */
57 writel(pi2s_tx->bitspersample, ®s->timing);
59 /* I2S mode has [TX/RX]_DATA_OFFSET both set to 1 */
60 writel(((1 << I2S_OFFSET_RX_DATA_OFFSET_SHIFT) |
61 (1 << I2S_OFFSET_TX_DATA_OFFSET_SHIFT)), ®s->offset);
63 /* FSYNC_WIDTH = 2 clocks wide, TOTAL_SLOTS = 2 slots per fsync */
64 writel((2 - 1) << I2S_CH_CTRL_FSYNC_WIDTH_SHIFT, ®s->ch_ctrl);
69 static int tegra_i2s_tx_data(struct udevice *dev, void *data, uint data_size)
71 struct i2s_uc_priv *priv = dev_get_uclass_priv(dev);
72 struct i2s_ctlr *regs = (struct i2s_ctlr *)priv->base_address;
75 tegra_i2s_transmit_enable(regs, 1);
76 ret = misc_write(dev_get_parent(dev), 0, data, data_size);
77 tegra_i2s_transmit_enable(regs, 0);
80 else if (ret < data_size)
86 static int tegra_i2s_probe(struct udevice *dev)
88 struct i2s_uc_priv *priv = dev_get_uclass_priv(dev);
91 base = dev_read_addr(dev);
92 if (base == FDT_ADDR_T_NONE) {
93 debug("%s: Missing i2s base\n", __func__);
96 priv->base_address = base;
98 priv->audio_pll_clk = 4800000;
99 priv->samplingrate = 48000;
100 priv->bitspersample = 16;
105 return i2s_tx_init(priv);
108 static const struct i2s_ops tegra_i2s_ops = {
109 .tx_data = tegra_i2s_tx_data,
112 static const struct udevice_id tegra_i2s_ids[] = {
113 { .compatible = "nvidia,tegra124-i2s" },
117 U_BOOT_DRIVER(tegra_i2s) = {
120 .of_match = tegra_i2s_ids,
121 .probe = tegra_i2s_probe,
122 .ops = &tegra_i2s_ops,