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