1 // SPDX-License-Identifier: GPL-2.0+
2 /*
3 * (C) Copyright 2018 Rockchip Electronics Co., Ltd
4 */
5
6 #include <clk.h>
7 #include <common.h>
8 #include <dm.h>
9 #include <errno.h>
10 #include <malloc.h>
11 #include <asm/io.h>
12 #include <sound.h>
13 #include "rockchip-i2s.h"
14
15 #define I2S_FIFO_LENGTH (31)
16
17 struct rk_i2s_dev {
18 void *regbase;
19 struct clk mclk;
20 };
21
i2s_reg_readl(struct rk_i2s_dev * dev,u32 offset)22 static inline u32 i2s_reg_readl(struct rk_i2s_dev *dev, u32 offset)
23 {
24 return readl(dev->regbase + offset);
25 }
26
i2s_reg_writel(struct rk_i2s_dev * dev,u32 offset,u32 val)27 static inline void i2s_reg_writel(struct rk_i2s_dev *dev, u32 offset, u32 val)
28 {
29 writel(val, dev->regbase + offset);
30 }
31
i2s_reg_update_bits(struct rk_i2s_dev * dev,u32 offset,u32 mask,u32 val)32 static inline void i2s_reg_update_bits(struct rk_i2s_dev *dev, u32 offset,
33 u32 mask, u32 val)
34 {
35 u32 tmp, orig;
36
37 orig = readl(dev->regbase + offset);
38
39 tmp = orig & ~mask;
40 tmp |= val & mask;
41
42 if (tmp != orig)
43 writel(tmp, dev->regbase + offset);
44 }
45
dump_regs(struct rk_i2s_dev * dev)46 static void dump_regs(struct rk_i2s_dev *dev)
47 {
48 int i = 0;
49
50 for (i = 0; i <= I2S_RXDR; i += 4)
51 debug("0x%02x: 0x%08x\n", i, readl(dev->regbase + i));
52 }
53
rk_i2s_hw_params(struct udevice * udev,unsigned int samplerate,unsigned int fmt,unsigned int channels)54 static int rk_i2s_hw_params(struct udevice *udev, unsigned int samplerate,
55 unsigned int fmt, unsigned int channels)
56 {
57 struct rk_i2s_dev *dev = dev_get_priv(udev);
58
59 /* set fmt */
60 i2s_reg_update_bits(dev, I2S_CKR,
61 I2S_CKR_MSS_MASK, I2S_CKR_MSS_MASTER);
62 i2s_reg_update_bits(dev, I2S_TXCR,
63 I2S_TXCR_IBM_MASK, I2S_TXCR_IBM_NORMAL);
64 i2s_reg_update_bits(dev, I2S_RXCR,
65 I2S_RXCR_IBM_MASK, I2S_RXCR_IBM_NORMAL);
66 /* set div */
67 i2s_reg_update_bits(dev, I2S_CKR,
68 I2S_CKR_TSD_MASK | I2S_CKR_RSD_MASK,
69 I2S_CKR_TSD(64) | I2S_CKR_RSD(64));
70 i2s_reg_update_bits(dev, I2S_CKR,
71 I2S_CKR_MDIV_MASK, I2S_CKR_MDIV(4));
72 /* set hwparams */
73 i2s_reg_update_bits(dev, I2S_TXCR,
74 I2S_TXCR_VDW_MASK |
75 I2S_TXCR_CSR_MASK,
76 I2S_TXCR_VDW(16) |
77 I2S_TXCR_CHN_2);
78 i2s_reg_update_bits(dev, I2S_RXCR,
79 I2S_RXCR_CSR_MASK |
80 I2S_RXCR_VDW_MASK,
81 I2S_TXCR_VDW(16) |
82 I2S_TXCR_CHN_2);
83 i2s_reg_update_bits(dev, I2S_DMACR,
84 I2S_DMACR_TDL_MASK | I2S_DMACR_RDL_MASK,
85 I2S_DMACR_TDL(16) | I2S_DMACR_RDL(16));
86
87 return 0;
88 }
89
rk_i2s_txctrl(struct rk_i2s_dev * dev,int on)90 static void rk_i2s_txctrl(struct rk_i2s_dev *dev, int on)
91 {
92 if (on) {
93 i2s_reg_update_bits(dev, I2S_XFER,
94 I2S_XFER_TXS_MASK | I2S_XFER_RXS_MASK,
95 I2S_XFER_TXS_START | I2S_XFER_RXS_START);
96 } else {
97 i2s_reg_update_bits(dev, I2S_XFER,
98 I2S_XFER_TXS_MASK |
99 I2S_XFER_RXS_MASK,
100 I2S_XFER_TXS_STOP |
101 I2S_XFER_RXS_STOP);
102
103 i2s_reg_update_bits(dev, I2S_CLR,
104 I2S_CLR_TXC_MASK | I2S_CLR_RXC_MASK,
105 I2S_CLR_TXC | I2S_CLR_RXC);
106 }
107 }
108
rk_i2s_transfer_tx_data(struct udevice * udev,unsigned int * data,unsigned long data_size)109 static int rk_i2s_transfer_tx_data(struct udevice *udev, unsigned int *data,
110 unsigned long data_size)
111 {
112 struct rk_i2s_dev *dev = dev_get_priv(udev);
113 u32 val;
114
115 if (data_size < I2S_FIFO_LENGTH) {
116 debug("%s : invalid data size\n", __func__);
117 return -EINVAL;
118 }
119
120 rk_i2s_txctrl(dev, 1);
121 while (data_size > 0) {
122 val = i2s_reg_readl(dev, I2S_FIFOLR);
123 if (val < I2S_FIFO_LENGTH) {
124 i2s_reg_writel(dev, I2S_TXDR, *data++);
125 data_size--;
126 }
127 }
128
129 return 0;
130 }
131
rk_i2s_set_sysclk(struct udevice * dev,unsigned int freq)132 static int rk_i2s_set_sysclk(struct udevice *dev, unsigned int freq)
133 {
134 struct rk_i2s_dev *i2s = dev_get_priv(dev);
135
136 clk_set_rate(&i2s->mclk, freq);
137
138 return 0;
139 }
140
141 static const struct snd_soc_dai_ops rockchip_i2s_ops = {
142 .hw_params = rk_i2s_hw_params,
143 .set_sysclk = rk_i2s_set_sysclk,
144 .transfer = rk_i2s_transfer_tx_data,
145 };
146
rockchip_i2s_probe(struct udevice * dev)147 static int rockchip_i2s_probe(struct udevice *dev)
148 {
149 struct rk_i2s_dev *i2s = dev_get_priv(dev);
150 int ret;
151
152 i2s->regbase = dev_read_addr_ptr(dev);
153
154 ret = clk_get_by_name(dev, "i2s_clk", &i2s->mclk);
155 if (ret) {
156 printf("%s get i2s mclk fail!\n", __func__);
157 return -EINVAL;
158 }
159
160 dump_regs(i2s);
161 return 0;
162 }
163
164 static const struct udevice_id rockchip_i2s_ids[] = {
165 { .compatible = "rockchip,px30-i2s", },
166 { .compatible = "rockchip,rk3036-i2s", },
167 { .compatible = "rockchip,rk3066-i2s", },
168 { .compatible = "rockchip,rk3128-i2s", },
169 { .compatible = "rockchip,rk3188-i2s", },
170 { .compatible = "rockchip,rk3288-i2s", },
171 { .compatible = "rockchip,rk3328-i2s", },
172 { .compatible = "rockchip,rk3368-i2s", },
173 { .compatible = "rockchip,rk3399-i2s", },
174 { }
175 };
176
177 U_BOOT_DRIVER(rockchip_i2s) = {
178 .name = "rockchip_i2s",
179 .id = UCLASS_I2S,
180 .of_match = rockchip_i2s_ids,
181 .probe = rockchip_i2s_probe,
182 .priv_auto_alloc_size = sizeof(struct rk_i2s_dev),
183 .ops = &rockchip_i2s_ops,
184 };
185
186 UCLASS_DRIVER(i2s) = {
187 .id = UCLASS_I2S,
188 .name = "i2s_bus",
189 };
190