1 /*
2 * Copyright (c) 2022 ASR Microelectronics (Shanghai) Co., Ltd. All rights reserved.
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 * http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15
16 #include "duet_i2s.h"
17 #include "apll_rf.h"
18
19 duet_i2s_callback_func g_duet_i2s_callback_handler;
20
duet_i2s_struct_init(duet_i2s_dev_t * pI2S_struct)21 void duet_i2s_struct_init(duet_i2s_dev_t *pI2S_struct)
22 {
23 pI2S_struct->i2s_role = I2S_ROLE_MASTER;
24 pI2S_struct->i2s_word_size = I2S_WORDSIZE_16bit;
25 pI2S_struct->i2s_tx_en = ENABLE;
26 pI2S_struct->i2s_rx_en = ENABLE;
27 pI2S_struct->i2s_fifo_threshold = I2S_FIFO_TRIGGERL_LEVEL_4;
28 pI2S_struct->i2s_sample_rate = I2S_SAMPLE_RATE_44P1K;
29 pI2S_struct->i2s_mclk_src = I2S_MCLK_SRC_FREQ120;
30 pI2S_struct->i2s_ws = 16;
31 pI2S_struct->i2s_mode = I2S_MODE_PHILIPS;
32 }
33
duet_i2s_interrupt_config(I2S_TypeDef * I2Sx,uint32_t i2s_interrupt,uint32_t new_state)34 void duet_i2s_interrupt_config(I2S_TypeDef *I2Sx, uint32_t i2s_interrupt, uint32_t new_state)
35 {
36 if (new_state == ENABLE) {
37 I2Sx->IMR &= ~i2s_interrupt;
38 } else {
39 I2Sx->IMR |= i2s_interrupt;
40 }
41 }
42
duet_i2s_interrupt_clear(I2S_TypeDef * I2Sx,uint32_t i2s_interrupt)43 void duet_i2s_interrupt_clear(I2S_TypeDef *I2Sx, uint32_t i2s_interrupt)
44 {
45 if (i2s_interrupt == I2S_INTERRUPT_TXFO) {
46 I2Sx->TOR; // read to clear interrupt
47 } else if (i2s_interrupt == I2S_INTERRUPT_RXFO) {
48 I2Sx->ROR;
49 }
50 }
51
duet_i2s_cmd(I2S_TypeDef * I2Sx,uint32_t new_state)52 void duet_i2s_cmd(I2S_TypeDef *I2Sx, uint32_t new_state)
53 {
54 if (new_state == ENABLE) {
55 I2Sx->IER |= ENABLE;
56 } else {
57 I2Sx->IER &= DISABLE;
58 }
59 }
60
duet_i2s_tx_block_cmd(I2S_TypeDef * I2Sx,uint32_t new_state)61 void duet_i2s_tx_block_cmd(I2S_TypeDef *I2Sx, uint32_t new_state)
62 {
63 if (new_state == ENABLE) {
64 I2Sx->ITER |= ENABLE;
65 } else {
66 I2Sx->ITER &= DISABLE;
67 }
68 }
69
duet_i2s_rx_block_cmd(I2S_TypeDef * I2Sx,uint32_t new_state)70 void duet_i2s_rx_block_cmd(I2S_TypeDef *I2Sx, uint32_t new_state)
71 {
72 if (new_state == ENABLE) {
73 I2Sx->IRER |= ENABLE;
74 } else {
75 I2Sx->IRER &= DISABLE;
76 }
77 }
78
duet_i2s_tx_channel_cmd(I2S_TypeDef * I2Sx,uint32_t new_state)79 void duet_i2s_tx_channel_cmd(I2S_TypeDef *I2Sx, uint32_t new_state)
80 {
81 if (new_state == ENABLE) {
82 I2Sx->TER |= ENABLE;
83 } else {
84 I2Sx->TER &= DISABLE;
85 }
86 }
87
duet_i2s_rx_channel_cmd(I2S_TypeDef * I2Sx,uint32_t new_state)88 void duet_i2s_rx_channel_cmd(I2S_TypeDef *I2Sx, uint32_t new_state)
89 {
90 if (new_state == ENABLE) {
91 I2Sx->RER |= ENABLE;
92 } else {
93 I2Sx->RER &= DISABLE;
94 }
95 }
96
duet_i2s_master_clock_cmd(I2S_TypeDef * I2Sx,uint32_t new_state)97 void duet_i2s_master_clock_cmd(I2S_TypeDef *I2Sx, uint32_t new_state)
98 {
99 if (new_state == ENABLE) {
100 I2Sx->CER |= ENABLE;
101 REG_WR(0X40000844, (0x1 << 13) | (0x1 << 24)); // open clock source of i2s
102 } else {
103 I2Sx->CER &= DISABLE;
104 REG_WR(0X4000084C, (0x1 << 13) | (0x1 << 24)); // close clock source of i2s
105 }
106 }
107
duet_i2s_init(I2S_TypeDef * I2Sx,duet_i2s_dev_t * pI2S_struct)108 int duet_i2s_init(I2S_TypeDef *I2Sx, duet_i2s_dev_t *pI2S_struct)
109 {
110 uint32_t mclk_divider = 0;
111 uint32_t sclk_divider = 0;
112 uint32_t lrclk_divider = 0;
113
114 if (pI2S_struct->i2s_role == I2S_ROLE_MASTER) {
115 if (pI2S_struct->i2s_sample_rate == I2S_SAMPLE_RATE_44P1K) {
116 if (pI2S_struct->i2s_mclk_src == I2S_MCLK_SRC_FREQ120
117 || pI2S_struct->i2s_mclk_src == I2S_MCLK_SRC_FREQ96
118 || pI2S_struct->i2s_mclk_src == I2S_MCLK_SRC_FREQ72) {
119 mclk_divider = 17;
120 }
121 } else if (pI2S_struct->i2s_sample_rate == I2S_SAMPLE_RATE_96K
122 || pI2S_struct->i2s_sample_rate == I2S_SAMPLE_RATE_48K
123 || pI2S_struct->i2s_sample_rate == I2S_SAMPLE_RATE_32K
124 || pI2S_struct->i2s_sample_rate == I2S_SAMPLE_RATE_16K
125 || pI2S_struct->i2s_sample_rate == I2S_SAMPLE_RATE_8K) {
126 if (pI2S_struct->i2s_mclk_src == I2S_MCLK_SRC_FREQ120) {
127 mclk_divider = 13;
128 }
129 }
130
131 if (mclk_divider == 0) {
132 return EIO;
133 }
134
135 lrclk_divider = 2 * pI2S_struct->i2s_ws;
136 sclk_divider = pI2S_struct->i2s_mclk_src / mclk_divider / pI2S_struct->i2s_sample_rate / lrclk_divider;
137 }
138
139 if (duet_config_apll_clk(pI2S_struct->i2s_mclk_src) != 0) {
140 return EIO;
141 }
142
143 duet_i2s_master_clock_cmd(I2Sx, ENABLE);
144 duet_i2s_cmd(I2Sx, DISABLE);
145
146 I2Sx->RCR &= ~I2S_RX_WORDSIZE_MASK;
147 I2Sx->RCR |= pI2S_struct->i2s_word_size;
148
149 I2Sx->TCR &= ~I2S_TX_WORDSIZE_MASK;
150 I2Sx->TCR |= pI2S_struct->i2s_word_size;
151
152 I2Sx->RFCR &= ~I2S_FIFO_TRIGGER_LEVEL_MASK;
153 I2Sx->RFCR |= pI2S_struct->i2s_fifo_threshold;
154
155 I2Sx->TFCR &= ~I2S_FIFO_TRIGGER_LEVEL_MASK;
156 I2Sx->TFCR |= pI2S_struct->i2s_fifo_threshold;
157 I2Sx->RFF |= 0x1;
158 I2Sx->TFF |= 0x1;
159 if (pI2S_struct->i2s_tx_en == ENABLE) {
160 duet_i2s_tx_block_cmd(I2Sx, ENABLE);
161 duet_i2s_tx_channel_cmd(I2Sx, ENABLE);
162 } else {
163 duet_i2s_tx_block_cmd(I2Sx, DISABLE);
164 duet_i2s_tx_channel_cmd(I2Sx, DISABLE);
165 }
166
167 if (pI2S_struct->i2s_rx_en == ENABLE) {
168
169 duet_i2s_rx_block_cmd(I2Sx, ENABLE);
170 duet_i2s_rx_channel_cmd(I2Sx, ENABLE);
171 } else {
172 duet_i2s_rx_block_cmd(I2Sx, DISABLE);
173 duet_i2s_rx_channel_cmd(I2Sx, DISABLE);
174 }
175
176 if (pI2S_struct->i2s_role == I2S_ROLE_MASTER) {
177 I2S_CLK_DIV->i2s_mclk_divider = mclk_divider - 1;
178 I2S_CLK_DIV->i2s_sclk_divider = sclk_divider - 1;
179 I2S_CLK_DIV->i2s_lrclk_divider = lrclk_divider - 1;
180 I2S_CLK_DIV->i2s_slave_mode = 0; // set to I2S master
181 } else {
182 I2S_CLK_DIV->i2s_slave_mode = 1; // set to I2S slave
183 }
184
185 return 0;
186 }
187
duet_i2s_receive_data(I2S_TypeDef * I2Sx,uint8_t lr)188 uint32_t duet_i2s_receive_data(I2S_TypeDef *I2Sx, uint8_t lr)
189 {
190 if (lr == 0) { // left channel
191 return I2Sx->LRBR_LTHR;
192 } else { // right channel
193 return I2Sx->RRBR_RTHR;
194 }
195 }
196
duet_i2s_send_data(I2S_TypeDef * I2Sx,uint32_t * left_chan_data,uint32_t * right_chan_data,uint32_t len)197 void duet_i2s_send_data(I2S_TypeDef *I2Sx, uint32_t *left_chan_data, uint32_t *right_chan_data, uint32_t len)
198 {
199 while (len) {
200 while (!i2s_get_interrupt_status(I2Sx, I2S_INTERRUPT_TXFE)); // wait till tx fifo emptys
201 for (int i = 0; i < I2S_FIFO_DEPTH && len > 0; i++, len--) {
202 I2Sx->LRBR_LTHR = *left_chan_data++;
203 I2Sx->RRBR_RTHR = *right_chan_data++;
204 }
205 }
206 while (!i2s_get_interrupt_status(I2Sx, I2S_INTERRUPT_TXFE)); // wait till tx fifo emptys
207 }
208
I2S_IRQHandler(void)209 void I2S_IRQHandler(void)
210 {
211 uint32_t g_data_l = 0;
212 uint32_t g_data_r = 0;
213 if (i2s_get_interrupt_status(I2S, I2S_INTERRUPT_RXDA)) { // rx data available
214 g_data_l = I2S->LRBR_LTHR;
215 g_data_r = I2S->RRBR_RTHR;
216 if (g_duet_i2s_callback_handler != NULL) {
217 g_duet_i2s_callback_handler(g_data_l, g_data_r);
218 }
219 }
220 }
221