clk: Fix clk func names in comments
[oweals/u-boot.git] / drivers / sound / tegra_i2s.c
1 // SPDX-License-Identifier: GPL-2.0+
2 /*
3  * Copyright 2018 Google LLC
4  * Written by Simon Glass <sjg@chromium.org>
5  */
6 #define LOG_CATEGORY UCLASS_I2S
7 #define LOG_DEBUG
8
9 #include <common.h>
10 #include <dm.h>
11 #include <i2s.h>
12 #include <misc.h>
13 #include <sound.h>
14 #include <asm/io.h>
15 #include <asm/arch-tegra/tegra_i2s.h>
16 #include "tegra_i2s_priv.h"
17
18 int tegra_i2s_set_cif_tx_ctrl(struct udevice *dev, u32 value)
19 {
20         struct i2s_uc_priv *priv = dev_get_uclass_priv(dev);
21         struct i2s_ctlr *regs = (struct i2s_ctlr *)priv->base_address;
22
23         writel(value, &regs->cif_tx_ctrl);
24
25         return 0;
26 }
27
28 static void tegra_i2s_transmit_enable(struct i2s_ctlr *regs, int on)
29 {
30         clrsetbits_le32(&regs->ctrl, I2S_CTRL_XFER_EN_TX,
31                         on ? I2S_CTRL_XFER_EN_TX : 0);
32 }
33
34 static int i2s_tx_init(struct i2s_uc_priv *pi2s_tx)
35 {
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(&regs->ctrl);
39
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;
44
45         /* Disable all transmission until we are ready to transfer */
46         ctrl &= ~(I2S_CTRL_XFER_EN_TX | I2S_CTRL_XFER_EN_RX);
47
48         /* Serve as master */
49         ctrl |= I2S_CTRL_MASTER_ENABLE;
50
51         /* Configure audio bits size */
52         ctrl &= ~I2S_CTRL_BIT_SIZE_MASK;
53         ctrl |= audio_bits << I2S_CTRL_BIT_SIZE_SHIFT;
54         writel(ctrl, &regs->ctrl);
55
56         /* Timing in LRCK mode: */
57         writel(pi2s_tx->bitspersample, &regs->timing);
58
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)), &regs->offset);
62
63         /* FSYNC_WIDTH = 2 clocks wide, TOTAL_SLOTS = 2 slots per fsync */
64         writel((2 - 1) << I2S_CH_CTRL_FSYNC_WIDTH_SHIFT, &regs->ch_ctrl);
65
66         return 0;
67 }
68
69 static int tegra_i2s_tx_data(struct udevice *dev, void *data, uint data_size)
70 {
71         struct i2s_uc_priv *priv = dev_get_uclass_priv(dev);
72         struct i2s_ctlr *regs = (struct i2s_ctlr *)priv->base_address;
73         int ret;
74
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);
78         if (ret < 0)
79                 return ret;
80         else if (ret < data_size)
81                 return -EIO;
82
83         return 0;
84 }
85
86 static int tegra_i2s_probe(struct udevice *dev)
87 {
88         struct i2s_uc_priv *priv = dev_get_uclass_priv(dev);
89         ulong base;
90
91         base = dev_read_addr(dev);
92         if (base == FDT_ADDR_T_NONE) {
93                 debug("%s: Missing i2s base\n", __func__);
94                 return -EINVAL;
95         }
96         priv->base_address = base;
97         priv->id = 1;
98         priv->audio_pll_clk = 4800000;
99         priv->samplingrate = 48000;
100         priv->bitspersample = 16;
101         priv->channels = 2;
102         priv->rfs = 256;
103         priv->bfs = 32;
104
105         return i2s_tx_init(priv);
106 }
107
108 static const struct i2s_ops tegra_i2s_ops = {
109         .tx_data        = tegra_i2s_tx_data,
110 };
111
112 static const struct udevice_id tegra_i2s_ids[] = {
113         { .compatible = "nvidia,tegra124-i2s" },
114         { }
115 };
116
117 U_BOOT_DRIVER(tegra_i2s) = {
118         .name           = "tegra_i2s",
119         .id             = UCLASS_I2S,
120         .of_match       = tegra_i2s_ids,
121         .probe          = tegra_i2s_probe,
122         .ops            = &tegra_i2s_ops,
123 };