1
2
3
4
5
6
7
8#define LOG_CATEGORY UCLASS_I2S
9
10#include <common.h>
11#include <dm.h>
12#include <i2s.h>
13#include <log.h>
14#include <sound.h>
15#include <asm/io.h>
16#include <linux/bitops.h>
17
18struct rk_i2s_regs {
19 u32 txcr;
20 u32 rxcr;
21 u32 ckr;
22 u32 fifolr;
23 u32 dmacr;
24 u32 intcr;
25 u32 intsr;
26 u32 xfer;
27 u32 clr;
28 u32 txdr;
29 u32 rxdr;
30};
31
32enum {
33
34 I2S_RX_TRAN_BIT = BIT(1),
35 I2S_TX_TRAN_BIT = BIT(0),
36 I2S_TRAN_MASK = 3 << 0,
37
38
39 I2S_MCLK_DIV_SHIFT = 16,
40 I2S_MCLK_DIV_MASK = (0xff << I2S_MCLK_DIV_SHIFT),
41
42 I2S_RX_SCLK_DIV_SHIFT = 8,
43 I2S_RX_SCLK_DIV_MASK = 0xff << I2S_RX_SCLK_DIV_SHIFT,
44 I2S_TX_SCLK_DIV_SHIFT = 0,
45 I2S_TX_SCLK_DIV_MASK = 0xff << I2S_TX_SCLK_DIV_SHIFT,
46
47 I2S_DATA_WIDTH_SHIFT = 0,
48 I2S_DATA_WIDTH_MASK = 0x1f << I2S_DATA_WIDTH_SHIFT,
49};
50
51static int rockchip_i2s_init(struct i2s_uc_priv *priv)
52{
53 struct rk_i2s_regs *regs = (struct rk_i2s_regs *)priv->base_address;
54 u32 bps = priv->bitspersample;
55 u32 lrf = priv->rfs;
56 u32 chn = priv->channels;
57 u32 mode = 0;
58
59 clrbits_le32(®s->xfer, I2S_TX_TRAN_BIT);
60 mode = readl(®s->txcr) & ~0x1f;
61 switch (priv->bitspersample) {
62 case 16:
63 case 24:
64 mode |= (priv->bitspersample - 1) << I2S_DATA_WIDTH_SHIFT;
65 break;
66 default:
67 log_err("Invalid sample size input %d\n", priv->bitspersample);
68 return -EINVAL;
69 }
70 writel(mode, ®s->txcr);
71
72 mode = readl(®s->ckr) & ~I2S_MCLK_DIV_MASK;
73 mode |= (lrf / (bps * chn) - 1) << I2S_MCLK_DIV_SHIFT;
74
75 mode &= ~I2S_TX_SCLK_DIV_MASK;
76 mode |= (priv->bitspersample * priv->channels - 1) <<
77 I2S_TX_SCLK_DIV_SHIFT;
78 writel(mode, ®s->ckr);
79
80 return 0;
81}
82
83static int i2s_send_data(struct rk_i2s_regs *regs, u32 *data, uint length)
84{
85 for (int i = 0; i < min(32u, length); i++)
86 writel(*data++, ®s->txdr);
87
88 length -= min(32u, length);
89
90
91 setbits_le32(®s->xfer, I2S_TRAN_MASK);
92 while (length) {
93 if ((readl(®s->fifolr) & 0x3f) < 0x20) {
94 writel(*data++, ®s->txdr);
95 length--;
96 }
97 }
98 while (readl(®s->fifolr) & 0x3f)
99 ;
100 clrbits_le32(®s->xfer, I2S_TRAN_MASK);
101 writel(0, ®s->clr);
102
103 return 0;
104}
105
106static int rockchip_i2s_tx_data(struct udevice *dev, void *data, uint data_size)
107{
108 struct i2s_uc_priv *priv = dev_get_uclass_priv(dev);
109 struct rk_i2s_regs *regs = (struct rk_i2s_regs *)priv->base_address;
110
111 return i2s_send_data(regs, data, data_size / sizeof(u32));
112}
113
114static int rockchip_i2s_probe(struct udevice *dev)
115{
116 struct i2s_uc_priv *priv = dev_get_uclass_priv(dev);
117 ulong base;
118
119 base = dev_read_addr(dev);
120 if (base == FDT_ADDR_T_NONE) {
121 log_debug("Missing i2s base\n");
122 return -EINVAL;
123 }
124 priv->base_address = base;
125 priv->id = 1;
126 priv->audio_pll_clk = 4800000;
127 priv->samplingrate = 48000;
128 priv->bitspersample = 16;
129 priv->channels = 2;
130 priv->rfs = 256;
131 priv->bfs = 32;
132
133 return rockchip_i2s_init(priv);
134}
135
136static const struct i2s_ops rockchip_i2s_ops = {
137 .tx_data = rockchip_i2s_tx_data,
138};
139
140static const struct udevice_id rockchip_i2s_ids[] = {
141 { .compatible = "rockchip,rk3288-i2s" },
142 { }
143};
144
145U_BOOT_DRIVER(rockchip_i2s) = {
146 .name = "rockchip_i2s",
147 .id = UCLASS_I2S,
148 .of_match = rockchip_i2s_ids,
149 .probe = rockchip_i2s_probe,
150 .ops = &rockchip_i2s_ops,
151};
152