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