1 /******************************************************************************
2  * Copyright (c) 2022 Telink Semiconductor (Shanghai) Co., Ltd. ("TELINK")
3  * All rights reserved.
4  *
5  * Licensed under the Apache License, Version 2.0 (the "License");
6  * you may not use this file except in compliance with the License.
7  * You may obtain a copy of the License at
8  *
9  *   http://www.apache.org/licenses/LICENSE-2.0
10  *
11  * Unless required by applicable law or agreed to in writing, software
12  * distributed under the License is distributed on an "AS IS" BASIS,
13  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14  * See the License for the specific language governing permissions and
15  * limitations under the License.
16  *
17  *****************************************************************************/
18 
19 /********************************************************************************************************
20  * @file	analog.c
21  *
22  * @brief	This is the source file for B91
23  *
24  * @author	Driver Group
25  *
26  *******************************************************************************************************/
27 #include "analog.h"
28 #include "compiler.h"
29 #include "plic.h"
30 #include "stimer.h"
31 /**********************************************************************************************************************
32  *                                			  local constants                                                       *
33  *********************************************************************************************************************/
34 
35 
36 /**********************************************************************************************************************
37  *                                           	local macro                                                        *
38  *********************************************************************************************************************/
39 
40 
41 /**********************************************************************************************************************
42  *                                             local data type                                                     *
43  *********************************************************************************************************************/
44 
45 
46 /**********************************************************************************************************************
47  *                                              global variable                                                       *
48  *********************************************************************************************************************/
49 
50 
51 
52 dma_config_t analog_tx_dma_config={
53 	.dst_req_sel 		= DMA_REQ_ALGM_TX,    /* < tx req  */
54 	.src_req_sel 		= 0,
55 	.dst_addr_ctrl		= DMA_ADDR_FIX,
56 	.src_addr_ctrl	 	= DMA_ADDR_INCREMENT, /* < increment */
57 	.dstmode		 	= DMA_HANDSHAKE_MODE,	/* < handshake */
58 	.srcmode			= DMA_NORMAL_MODE,
59 	.dstwidth 			= DMA_CTR_WORD_WIDTH,
60 	.srcwidth 			= DMA_CTR_WORD_WIDTH,
61 	.src_burst_size 	= 0,	/* < must 0 */
62 	.read_num_en		= 0,
63 	.priority 			= 0,
64 	.write_num_en		= 0,
65 	.auto_en 			= 0,   	/* < must 0 */
66 };
67 dma_config_t analog_rx_dma_config={
68 	.dst_req_sel 		= 0,//tx req
69 	.src_req_sel 		= DMA_REQ_ALGM_RX,
70 	.dst_addr_ctrl 		= DMA_ADDR_INCREMENT,
71 	.src_addr_ctrl 		= DMA_ADDR_FIX,
72 	.dstmode 			= DMA_NORMAL_MODE,
73 	.srcmode 			= DMA_HANDSHAKE_MODE,
74 	.dstwidth 			= DMA_CTR_WORD_WIDTH,	/* < must word */
75 	.srcwidth 			= DMA_CTR_WORD_WIDTH,	/* < must word */
76 	.src_burst_size 	= 0,
77 	.read_num_en 		= 0,
78 	.priority 			= 0,
79 	.write_num_en 		= 0,
80 	.auto_en 			= 0,//must 0
81 };
82 /**********************************************************************************************************************
83  *                                              local variable                                                     *
84  *********************************************************************************************************************/
85 /**********************************************************************************************************************
86  *                                          local function prototype                                               *
87  *********************************************************************************************************************/
88 
89 
90 /**
91  * @brief      This function serves to judge whether analog write/read is busy .
92  * @return     none.
93  */
94 static inline void analog_wait();
95 /**********************************************************************************************************************
96  *                                         global function implementation                                             *
97  *********************************************************************************************************************/
98 
99 
100 
101 
102 
103 /**
104  * @brief      This function serves to analog register read by byte.
105  * @param[in]  addr - address need to be read.
106  * @return     the result of read.
107  */
analog_read_reg8(unsigned char addr)108 unsigned char analog_read_reg8(unsigned char addr){
109 	unsigned int r=core_interrupt_disable();
110 	reg_ana_addr = addr;
111 	reg_ana_len=0x1;
112     reg_ana_ctrl = FLD_ANA_CYC;
113     analog_wait();
114 	unsigned char data= reg_ana_data(0);
115 	core_restore_interrupt(r);
116 	return data;
117 
118 }
119 
120 /**
121  * @brief      This function serves to analog register write by byte.
122  * @param[in]  addr - address need to be write.
123  * @param[in]  data - the value need to be write.
124  * @return     none.
125  */
analog_write_reg8(unsigned char addr,unsigned char data)126 void analog_write_reg8(unsigned char addr, unsigned char data){
127 	unsigned int r=core_interrupt_disable();
128 	reg_ana_addr = addr;
129     reg_ana_data(0) = data;
130     reg_ana_ctrl = (FLD_ANA_CYC | FLD_ANA_RW);
131 	analog_wait();
132 	reg_ana_ctrl =0x00;
133 	core_restore_interrupt(r);
134 }
135 
136 /**
137  * @brief      This function serves to analog register write by halfword.
138  * @param[in]  addr - address need to be write.
139  * @param[in]  data - the value need to be write.
140  * @return     none.
141  */
analog_write_reg16(unsigned char addr,unsigned short data)142 void analog_write_reg16(unsigned char addr, unsigned short data)
143 {
144 	unsigned int r=core_interrupt_disable();
145 	reg_ana_addr = addr;
146 	reg_ana_addr_data16	 = data;
147     reg_ana_ctrl = (FLD_ANA_CYC | FLD_ANA_RW);
148 	analog_wait();
149 	core_restore_interrupt(r);
150 }
151 
152 /**
153  * @brief      This function serves to analog register read by halfword.
154  * @param[in]  addr - address need to be read.
155  * @return     the result of read.
156  */
analog_read_reg16(unsigned char addr)157 unsigned short analog_read_reg16(unsigned char addr)
158 {
159 	unsigned int r=core_interrupt_disable();
160 	reg_ana_len=2;
161 	reg_ana_addr = addr;
162 	reg_ana_ctrl = FLD_ANA_CYC;
163 	analog_wait();
164 	unsigned short data=reg_ana_addr_data16;
165 	core_restore_interrupt(r);
166 	return data;
167 }
168 
169 
170 
171 /**
172  * @brief      This function serves to analog register read by word.
173  * @param[in]  addr - address need to be read.
174  * @return     the result of read.
175  */
analog_read_reg32(unsigned char addr)176 unsigned int analog_read_reg32(unsigned char addr)
177 {
178 	unsigned int r=core_interrupt_disable();
179 	reg_ana_len = 4;
180 	reg_ana_addr = addr;
181 	reg_ana_ctrl = FLD_ANA_CYC;
182 	analog_wait();
183 	unsigned int data=reg_ana_addr_data32;
184 	core_restore_interrupt(r);
185 	return data;
186 }
187 
188 
189 /**
190  * @brief      This function serves to analog register write by word.
191  * @param[in]  addr - address need to be write.
192  * @param[in]  data - the value need to be write.
193  * @return     none.
194  */
analog_write_reg32(unsigned char addr,unsigned int data)195 void analog_write_reg32(unsigned char addr, unsigned int data)
196 {
197 	unsigned int r=core_interrupt_disable();
198 	reg_ana_addr = addr;
199 	reg_ana_addr_data32	= data;
200 	reg_ana_ctrl = (FLD_ANA_CYC | FLD_ANA_RW);
201 	analog_wait();
202 	core_restore_interrupt(r);
203 }
204 
205 /**
206  * @brief      This function serves to analog register write by word using dma.
207  * @param[in]  chn - the dma channel.
208  * @param[in]  addr - address need to be write.
209  * @param[in]  pdat - the value need to be write.
210  * @return     none.
211  */
analog_read_reg32_dma(dma_chn_e chn,unsigned char addr,void * pdat)212 void analog_read_reg32_dma(dma_chn_e chn, unsigned char addr, void *pdat)
213 {
214 	unsigned int r=core_interrupt_disable();
215 	reg_ana_len = 0x04;
216 	reg_ana_addr = addr;
217 	reg_ana_ctrl = FLD_ANA_CYC;
218 	reg_dma_src_addr(chn) = 0x80140184;
219 	reg_dma_dst_addr(chn) = convert_ram_addr_cpu2bus(pdat);
220 	dma_set_size(chn, 4, DMA_WORD_WIDTH);
221 	analog_rx_dma_config.dstwidth = DMA_CTR_WORD_WIDTH;
222 	analog_rx_dma_config.srcwidth = DMA_CTR_WORD_WIDTH;
223 	dma_config(chn, &analog_rx_dma_config);
224 	dma_chn_en(chn);
225 	analog_wait();
226 	core_restore_interrupt(r);
227 }
228 
229 /**
230  * @brief      This function serves to analog register write by word using dma.
231  * @param[in]  chn - the dma channel.
232  * @param[in]  addr - address need to be write.
233  * @param[in]  data - the value need to be write.
234  * @return     none.
235  */
analog_write_reg32_dma(dma_chn_e chn,unsigned char addr,void * pdat)236 void analog_write_reg32_dma(dma_chn_e chn, unsigned char addr, void *pdat)
237 {
238 	unsigned int r=core_interrupt_disable();
239 	reg_ana_addr = addr;
240 	reg_dma_src_addr(chn) = convert_ram_addr_cpu2bus(pdat);
241 	reg_dma_dst_addr(chn) = 0x80140184;
242 	dma_set_size(chn, 4, DMA_WORD_WIDTH);
243 	analog_tx_dma_config.dstwidth = DMA_CTR_WORD_WIDTH;
244 	analog_tx_dma_config.srcwidth = DMA_CTR_WORD_WIDTH;
245 	dma_config(chn, &analog_tx_dma_config);
246 	dma_chn_en(chn);
247 	reg_ana_ctrl = FLD_ANA_CYC | FLD_ANA_RW;
248 	analog_wait();
249 	core_restore_interrupt(r);
250 }
251 
252 
253 
254 
255 
256 /**
257  * @brief      This function write buffer to analog register.
258  * @param[in]  addr - address need to be write.
259  * @param[in]  *buff - the buffer need to be write.
260  * @param[in]  len - the length of buffer.
261  * @return     none.
262  */
analog_write_buff(unsigned char addr,unsigned char * buff,int len)263 _attribute_ram_code_sec_noinline_ void analog_write_buff(unsigned char addr, unsigned char *buff, int len)
264 {
265 	unsigned char wr_idx = 0;
266 	unsigned char len_t = len;
267 	unsigned int r =core_interrupt_disable();
268 	reg_ana_len=len;
269 	reg_ana_addr = addr;
270 
271 	if(len_t <= 4)
272 	{
273 		while(len_t--)
274 			reg_ana_data(wr_idx++) = *(buff++);
275 		reg_ana_ctrl = FLD_ANA_CYC | FLD_ANA_RW;
276 	}
277 	else
278 	{
279 		len_t = 4;
280 		while(len_t--)
281 			reg_ana_data(wr_idx++) = *(buff++);
282 		reg_ana_ctrl = FLD_ANA_CYC | FLD_ANA_RW;
283 		len_t = len - 4;
284 		wr_idx = 0;
285 		while(len_t--)
286 		{
287 			reg_ana_data(wr_idx++) = *(buff++);
288 			if(wr_idx == 4)
289 			{
290 				wr_idx = 0;
291 				while((reg_ana_irq_sta & FLD_ANA_TXBUFF_IRQ) == 0);//tx_buf_irq
292 			}
293 		}
294 	}
295 	analog_wait();//busy
296 	reg_ana_ctrl = 0x00;
297 	core_restore_interrupt(r);
298 }
299 
300 /**
301  * @brief      This function read data from analog register to buffer.
302  * @param[in]  addr - address need to be read from.
303  * @param[in]  *buff - the buffer need to be put data.
304  * @param[in]  len - the length of read data.
305  * @return     none.
306  */
analog_read_buff(unsigned char addr,unsigned char * buff,int len)307 _attribute_ram_code_sec_noinline_ void analog_read_buff(unsigned char addr, unsigned char *buff, int len)
308 {
309 	unsigned int r=core_interrupt_disable();
310 	unsigned char rd_idx = 0;
311 	unsigned char len_t = len;
312 	reg_ana_len=len;
313 	reg_ana_addr = addr;
314 	reg_ana_ctrl = FLD_ANA_CYC;
315 	if (len_t > 4)
316 	{
317 		while((reg_ana_irq_sta & FLD_ANA_RXBUFF_IRQ) == 0);//rx_buf_irq
318 		while(len_t--)
319 		{
320 			(*buff++) = reg_ana_data(rd_idx++);
321 			if(rd_idx == 4)
322 			{
323 				rd_idx = 0;
324 				if(len_t <= 4)
325 					break;
326 				else
327 					while((reg_ana_irq_sta & FLD_ANA_RXBUFF_IRQ) == 0);//rx_buf_irq
328 			}
329 		}
330 	}
331 	analog_wait();
332 	while(len_t--)
333 		(*buff++) = reg_ana_data(rd_idx++);
334 
335 	reg_ana_ctrl = 0x00;
336 	core_restore_interrupt(r);
337 }
338 
339 /**
340  * @brief      This function write buffer to analog register by dma channel.
341  * @param[in]  chn - the dma channel.
342  * @param[in]  addr - address need to be write.
343  * @param[in]  *pdat - the buffer need to be write.
344  * @param[in]  len - the length of buffer.
345  * @return     none.
346  */
analog_write_buff_dma(dma_chn_e chn,unsigned char addr,unsigned char * pdat,unsigned int len)347 void analog_write_buff_dma(dma_chn_e chn, unsigned char addr, unsigned char * pdat, unsigned int len)
348 {
349 	unsigned int r=core_interrupt_disable();
350 	reg_ana_addr = addr;
351 	reg_dma_src_addr(chn) = convert_ram_addr_cpu2bus(pdat);
352 	reg_dma_dst_addr(chn) = 0x80140184;
353 	dma_set_size(chn, len, DMA_WORD_WIDTH);
354 	analog_tx_dma_config.dstwidth = DMA_CTR_WORD_WIDTH;
355 	analog_tx_dma_config.srcwidth = DMA_CTR_WORD_WIDTH;
356 	dma_config(chn, &analog_tx_dma_config);
357 	dma_chn_en(chn);
358 	reg_ana_ctrl = 0x60;
359 	analog_wait();
360 	core_restore_interrupt(r);
361 }
362 
363 /**
364  * @brief      This function write buffer to analog register by dma channel.
365  * @param[in]  chn - the dma channel.
366  * @param[in]  addr - address need to be read from.
367  * @param[in]  *pdat - the buffer need to be put data.
368  * 			   note: The size of array pdat must be a multiple of 4.
369  * 			  	 	For example, if you just need read 5 byte by dma, you should
370  * 			  	 	define the size of array pdat to be greater than 8 other than 5.
371  * 			  	 	Because the dma would return 4 byte data every time, 5 byte is
372  * 			  	 	not enough to store them.
373  * @param[in]  len - the length of read data.
374  * @return     none.
375  */
analog_read_buff_dma(dma_chn_e chn,unsigned char addr,unsigned char * pdat,unsigned int len)376 void analog_read_buff_dma(dma_chn_e chn, unsigned char addr, unsigned char *pdat, unsigned int len)
377 {
378 	unsigned int r=core_interrupt_disable();
379 	reg_ana_len = len;
380 	reg_ana_addr = addr;
381 
382 	reg_dma_src_addr(chn) = 0x80140184;
383 	reg_dma_dst_addr(chn) = convert_ram_addr_cpu2bus(pdat);
384 	dma_set_size(chn, len, DMA_WORD_WIDTH);
385 	analog_rx_dma_config.dstwidth = DMA_CTR_WORD_WIDTH;
386 	analog_rx_dma_config.srcwidth = DMA_CTR_WORD_WIDTH;
387 	dma_config(chn, &analog_rx_dma_config);
388 	dma_chn_en(chn);
389 	reg_ana_ctrl = FLD_ANA_CYC;
390 	analog_wait();
391 	core_restore_interrupt(r);
392 }
393 
394 /**
395  * @brief      This function write buffer to analog register by dma channel.
396  * @param[in]  chn  - the dma channel.
397  * @param[in]  pdat - the buffer(addr & data) ptr need to be write,
398  * 			   note: The array pdat should look like this,
399  * 			   |  pdat     |            |        |
400  * 			   |  :------  | :----------|  :---- |
401  * 			   |  pdat[0]  |   address  |  0x3a  |
402  * 			   |  pdat[1]  |    data    |  0x11  |
403  * 			   |  pdat[2]  |   address  |  0x3b  |
404  *			   |  pdat[3]  |    data    |  0x22  |
405  *			   |  ......   |            |        |
406  * 				It means write data 0x11 to address 0x3a,
407  * 						 write data 0x22 to address 0x3b,
408  * 						 ......
409  * @param[in]  len - the length of read data.
410  * @return     none.
411  */
analog_write_addr_data_dma(dma_chn_e chn,void * pdat,int len)412 void analog_write_addr_data_dma(dma_chn_e chn, void *pdat, int len)
413 {
414 	unsigned int r=core_interrupt_disable();
415 
416 	reg_dma_src_addr(chn) = convert_ram_addr_cpu2bus(pdat);
417 	reg_dma_dst_addr(chn) = 0x80140184;
418 	dma_set_size(chn, len, DMA_WORD_WIDTH);
419 	analog_tx_dma_config.dstwidth = DMA_CTR_WORD_WIDTH;
420 	analog_tx_dma_config.srcwidth = DMA_CTR_WORD_WIDTH;
421 	dma_config(chn, &analog_tx_dma_config);
422 	dma_chn_en(chn);
423 	delay_us(1);
424 	reg_ana_ctrl = FLD_ANA_RW;
425 	reg_ana_dma_ctl = FLD_ANA_CYC1|FLD_ANA_DMA_EN;
426 	delay_us(1);
427 	while(!(reg_ana_sta & BIT(3)));
428     reg_ana_ctrl = 0x00;
429     reg_ana_dma_ctl = 0;
430     core_restore_interrupt(r);
431 
432 }
433 
434 /**********************************************************************************************************************
435   *                    						local function implementation                                             *
436   *********************************************************************************************************************/
437 /**
438  * @brief      This function serves to judge whether analog write/read is busy .
439  * @return     none.
440  */
analog_wait()441 static inline void analog_wait(){
442 	while(reg_ana_ctrl & FLD_ANA_BUSY){}
443 }
444 
445 
446 
447