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 22 static inline u32 i2s_reg_readl(struct rk_i2s_dev *dev, u32 offset) 23 { 24 return readl(dev->regbase + offset); 25 } 26 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 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 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 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 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 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 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 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