• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2020 HiSilicon (Shanghai) Technologies CO., LIMITED.
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 <hi3861_platform_base.h>
17 #include <hi_event.h>
18 #include <hi_isr.h>
19 #include <hi_mem.h>
20 #include <hi_sem.h>
21 #include <hi_spi.h>
22 #include <hi_stdlib.h>
23 #include <hi_time.h>
24 #include <hi_types_base.h>
25 #ifdef CONFIG_SPI_DMA_SUPPORT
26 #include <hi_dma.h>
27 #endif
28 #include <time.h>
29 
30 #include "spi.h"
31 
32 #define SPI_HOST_OPT_BASE (SPI_OPT_ENABLE_SPI |  \
33                            SPI_OPT_SET_CFG |  \
34                            SPI_OPT_DISABLE_SPI |  \
35                            SPI_OPT_WAIT_SIGNAL |  \
36                            SPI_OPT_FREE_SIGNAL)
37 
38 #define SPI_SLAVE_OPT_READ (SPI_OPT_ENABLE_SPI |  \
39                             SPI_OPT_SET_CFG)
40 
41 #define SPI_SLAVE_OPT_WRITE (SPI_OPT_ENABLE_SPI |  \
42                              SPI_OPT_SET_CFG |  \
43                              SPI_OPT_WAIT_SIGNAL |  \
44                              SPI_OPT_FREE_SIGNAL)
45 
46 #define CLKEN_SPI0 5
47 #define CLKEN_SPI1 0
48 
49 hi_u32 g_spi_clk = SPI_DEFAULT_CLK;
50 
spi_get_clk(hi_void)51 static hi_u32 spi_get_clk(hi_void)
52 {
53     hi_reg_write16(W_CTL_W_TCXO_SEL_REG, 1);
54     hi_udelay(1);
55     return g_spi_clk;
56 }
57 
spi_write_data(hi_spi_idx id,hi_u32 timeout_ms)58 static hi_u32 spi_write_data(hi_spi_idx id, hi_u32 timeout_ms)
59 {
60     hi_u32 event_bit;
61     hi_u32 ret;
62     spi_isr_enable(g_spi_ctrl[id]->reg_base, SPI_INT_BIT_TX_FIFO_WATER_LINE);
63     event_bit = 0;
64     ret = hi_event_wait(g_spi_ctrl[id]->event_id, HI_EVENT_BIT_TX_DATA, &event_bit, timeout_ms,
65                         HI_EVENT_WAITMODE_OR | HI_EVENT_WAITMODE_CLR);
66     if (ret == HI_ERR_EVENT_WAIT_TIME_OUT) {
67         spi_process_printf("write time out");
68         return HI_ERR_SPI_WRITE_TIMEOUT;
69     } else {
70         return HI_ERR_SUCCESS;
71     }
72 }
73 
spi_read_data(hi_spi_idx id,hi_u32 timeout_ms)74 static hi_u32 spi_read_data(hi_spi_idx id, hi_u32 timeout_ms)
75 {
76     hi_u32 event_bit = 0;
77     hi_u32 ret;
78 
79     for (;;) {
80         if (g_spi_ctrl[id]->rx_buf.cur_cnt >= g_spi_ctrl[id]->trans_len) {
81             g_spi_ctrl[id]->rx_buf.cur_cnt = 0;
82             return HI_ERR_SUCCESS;
83         }
84         spi_isr_enable(g_spi_ctrl[id]->reg_base,
85                        SPI_INT_BIT_RX_FIFO_WATER_LINE | SPI_INT_BIT_RX_FIFO_TIME_OUT | SPI_INT_BIT_RX_FIFO_OVER_FLOW);
86 
87         ret = hi_event_wait(g_spi_ctrl[id]->event_id,
88                             HI_EVENT_BIT_RX_DATA | HI_EVENT_BIT_RX_DATA_TIME_OUT | HI_EVENT_BIT_RX_FIFO_OVER_FLOW,
89                             &event_bit, timeout_ms, HI_EVENT_WAITMODE_OR | HI_EVENT_WAITMODE_CLR);
90         if (ret == HI_ERR_SUCCESS) {
91             continue;
92         } else if (ret == HI_ERR_EVENT_WAIT_TIME_OUT) {
93             return HI_ERR_SPI_READ_TIMEOUT;
94         } else {
95             return ret;
96         }
97     }
98 }
spi_host_transfer(hi_spi_idx id,const spi_trans_attr * trans_attr,hi_u32 total_len,hi_u32 read_write)99 static hi_u32 spi_host_transfer(hi_spi_idx id, const spi_trans_attr *trans_attr, hi_u32 total_len, hi_u32 read_write)
100 {
101     hi_u32 ret;
102     hi_u16 threshold = (id == HI_SPI_ID_0 ? SPI0_FIFO_THRESHOLD : SPI1_FIFO_THRESHOLD);
103     hi_u32 len = total_len;
104     while (len) {
105         if (len > threshold) {
106             g_spi_ctrl[id]->single_len = threshold;
107             g_spi_ctrl[id]->trans_len = threshold;
108         } else {
109             g_spi_ctrl[id]->single_len = len;
110             g_spi_ctrl[id]->trans_len = len;
111         }
112         if (read_write & SPI_WRITE_FLAG) {
113             ret = spi_write_data(id, trans_attr->time_out_ms);
114             if (ret != HI_ERR_SUCCESS) {
115                 return ret;
116             }
117         }
118         /* if too fast, there should be delay 50-100 us to wait slave */
119         if (read_write & SPI_READ_FLAG) {
120             ret = spi_read_data(id, trans_attr->time_out_ms);
121             if (ret != HI_ERR_SUCCESS) {
122                 return ret;
123             }
124         }
125         if (len < g_spi_ctrl[id]->single_len) {
126             return HI_ERR_FAILURE;
127         }
128         len -= g_spi_ctrl[id]->single_len;
129     }
130     return HI_ERR_SUCCESS;
131 }
132 
spi_slave_transfer(hi_spi_idx id,const spi_trans_attr * trans_attr,hi_u32 read_write)133 static hi_u32 spi_slave_transfer(hi_spi_idx id, const spi_trans_attr *trans_attr, hi_u32 read_write)
134 {
135     hi_u32 ret;
136     hi_u16 threshold = (id == HI_SPI_ID_0 ? SPI0_FIFO_THRESHOLD : SPI1_FIFO_THRESHOLD);
137     hi_u32 len = g_spi_ctrl[id]->trans_len;
138     if (read_write & SPI_WRITE_FLAG) {
139         while (len) {
140             if (len > threshold) {
141                 g_spi_ctrl[id]->single_len = threshold;
142             } else {
143                 g_spi_ctrl[id]->single_len = len;
144             }
145             ret = spi_write_data(id, trans_attr->time_out_ms);
146             if (ret != HI_ERR_SUCCESS) {
147                 return ret;
148             }
149             len -= g_spi_ctrl[id]->single_len;
150         }
151     }
152     if (read_write & SPI_READ_FLAG) {
153         g_spi_ctrl[id]->single_len = threshold;
154         ret = spi_read_data(id, trans_attr->time_out_ms);
155         if (ret != HI_ERR_SUCCESS) {
156             return ret;
157         }
158     }
159     return HI_ERR_SUCCESS;
160 }
161 
162 #ifdef CONFIG_SPI_DMA_SUPPORT
163 /* slave using dma transfer data, use read or write, can't use both methods of work at the same time */
spi_slave_dma_transfer(hi_spi_idx id,const spi_trans_attr * trans_attr,hi_u32 read_write)164 static hi_u32 spi_slave_dma_transfer(hi_spi_idx id, const spi_trans_attr *trans_attr, hi_u32 read_write)
165 {
166     hi_u32 ret;
167     if (read_write & SPI_WRITE_FLAG) {
168         spi_dma_enable(g_spi_ctrl[id]->reg_base, SPI_TX_DMAE);
169         ret = spi_hd_dma_write_fifo(g_spi_ctrl[id], trans_attr->time_out_ms);
170         spi_dma_disable(g_spi_ctrl[id]->reg_base, SPI_TX_DMAE);
171     } else {
172         spi_dma_enable(g_spi_ctrl[id]->reg_base, SPI_RX_DMAE);
173         ret = spi_hd_dma_read_fifo(g_spi_ctrl[id], trans_attr->time_out_ms);
174         spi_dma_disable(g_spi_ctrl[id]->reg_base, SPI_RX_DMAE);
175     }
176     return ret;
177 }
178 #endif
179 
spi_get_data_len(hi_u32 data_width,hi_u32 byte_len)180 static hi_u32 spi_get_data_len(hi_u32 data_width, hi_u32 byte_len)
181 {
182     if (data_width > HI_SPI_CFG_DATA_WIDTH_E_8BIT) {
183         if ((byte_len % SPI_DATA_WIDTH_2BYTES) != 0) {
184             return 0;
185         }
186         return (byte_len / SPI_DATA_WIDTH_2BYTES);
187     } else {
188         return byte_len;
189     }
190 }
191 
spi_host_writeread(hi_spi_idx id,hi_pvoid write_data,hi_pvoid read_data,hi_u32 byte_len,hi_u32 options)192 static hi_u32 spi_host_writeread(hi_spi_idx id, hi_pvoid write_data, hi_pvoid read_data, hi_u32 byte_len,
193     hi_u32 options)
194 {
195     hi_u32 data_len;
196     hi_u32 ret;
197     if ((hi_u32)id > HI_SPI_ID_1 || byte_len == 0 ||
198         (!(options & SPI_OPT_SEND_FIX_DATA) && (write_data == HI_NULL)) ||
199         (!(options & SPI_OPT_RCV_FIX_DATA) && (read_data == HI_NULL))) {
200         return HI_ERR_SPI_PARAMETER_WRONG;
201     }
202     if (g_spi_ctrl[id] == HI_NULL) {
203         return HI_ERR_SPI_NOT_INIT;
204     }
205     if (g_spi_ctrl[id]->spi_cfg.is_slave == SPI_CFG_ROLE_SLAVE) {
206         return HI_ERR_SPI_PARAMETER_WRONG;
207     }
208     if (g_spi_ctrl[id]->transferring) {
209         return HI_ERR_SPI_BUSY;
210     }
211     data_len = spi_get_data_len(g_spi_ctrl[id]->spi_cfg.data_width, byte_len);
212     if (data_len == 0) {
213         return HI_ERR_SPI_PARAMETER_WRONG;
214     }
215     spi_trans_attr trans_attr = { SPI_HOST_TIMEOUT_MS, options };
216     g_spi_ctrl[id]->single_len = 0;
217     g_spi_ctrl[id]->trans_len = data_len;
218     g_spi_ctrl[id]->tx_buf.buf = write_data;
219     g_spi_ctrl[id]->tx_buf.cur_pos = 0;
220     g_spi_ctrl[id]->tx_buf.cur_cnt = 0;
221     g_spi_ctrl[id]->rx_buf.buf = read_data;
222     g_spi_ctrl[id]->rx_buf.cur_pos = 0;
223     g_spi_ctrl[id]->rx_buf.cur_cnt = 0;
224     ret = spi_trans_prepare(g_spi_ctrl[id], &trans_attr);
225     if (ret != HI_ERR_SUCCESS) {
226         spi_trans_restore(g_spi_ctrl[id], &trans_attr);
227         return ret;
228     }
229     spi_flush_fifo(g_spi_ctrl[id]->reg_base);
230     if (!g_spi_ctrl[id]->use_irq) {
231         if (g_spi_ctrl[id]->spi_cfg.data_width < HI_SPI_CFG_DATA_WIDTH_E_9BIT) {
232             ret = spi_transfer_8bits_block(g_spi_ctrl[id], options);
233         } else {
234             ret = spi_transfer_16bits_block(g_spi_ctrl[id], options);
235         }
236     } else {
237         ret = spi_host_transfer(id, &trans_attr, data_len, SPI_WRITE_FLAG | SPI_READ_FLAG);
238     }
239 
240     spi_trans_restore(g_spi_ctrl[id], &trans_attr);
241     return ret;
242 }
243 
hi_spi_set_loop_back_mode(hi_spi_idx id,hi_bool lb_en)244 hi_u32 hi_spi_set_loop_back_mode(hi_spi_idx id, hi_bool lb_en)
245 {
246     hi_u16 reg_val = 0;
247     if (id > HI_SPI_ID_1 || id < HI_SPI_ID_0) {
248         return HI_ERR_SPI_PARAMETER_WRONG;
249     }
250     if (g_spi_ctrl[id] == HI_NULL) {
251         return HI_ERR_SPI_NOT_INIT;
252     }
253     if ((g_spi_ctrl[id]->spi_cfg.fram_mode == HI_SPI_CFG_FRAM_MODE_MICROWIRE ||
254         g_spi_ctrl[id]->spi_cfg.is_slave == SPI_CFG_ROLE_SLAVE) && lb_en) {
255         return HI_ERR_SPI_PARAMETER_WRONG;
256     }
257     if (lb_en) {
258         hi_reg_read16(g_spi_ctrl[id]->reg_base + REG_SPI_CR1, reg_val);
259         reg_val |= (1 << SPI_CR1_ST_BIT_LBM);
260         hi_reg_write16(g_spi_ctrl[id]->reg_base + REG_SPI_CR1, reg_val);
261         g_spi_ctrl[id]->spi_cfg.loop_back = 1;
262     } else {
263         g_spi_ctrl[id]->spi_cfg.loop_back = 0;
264     }
265     return HI_ERR_SUCCESS;
266 }
267 
hi_spi_slave_write(hi_spi_idx id,hi_pvoid write_data,hi_u32 byte_len,hi_u32 time_out_ms)268 hi_u32 hi_spi_slave_write(hi_spi_idx id, hi_pvoid write_data, hi_u32 byte_len, hi_u32 time_out_ms)
269 {
270     hi_u32 ret;
271     hi_u32 data_len;
272     if ((hi_u32)id > HI_SPI_ID_1 || write_data == HI_NULL || byte_len == 0 || id < HI_SPI_ID_0) {
273         return HI_ERR_SPI_PARAMETER_WRONG;
274     }
275     if (g_spi_ctrl[id] == HI_NULL) {
276         return HI_ERR_SPI_NOT_INIT;
277     }
278     if (g_spi_ctrl[id]->spi_cfg.is_slave != SPI_CFG_ROLE_SLAVE) {
279         return HI_ERR_SPI_PARAMETER_WRONG;
280     }
281     data_len = spi_get_data_len(g_spi_ctrl[id]->spi_cfg.data_width, byte_len);
282     if (data_len == 0) {
283         return HI_ERR_SPI_PARAMETER_WRONG;
284     }
285     spi_trans_attr trans_attr = { time_out_ms, SPI_SLAVE_OPT_WRITE };
286     g_spi_ctrl[id]->single_len = 0;
287     g_spi_ctrl[id]->trans_len = data_len;
288     g_spi_ctrl[id]->tx_buf.buf = write_data;
289     g_spi_ctrl[id]->tx_buf.cur_pos = 0;
290     g_spi_ctrl[id]->tx_buf.cur_cnt = 0;
291     ret = spi_trans_prepare(g_spi_ctrl[id], &trans_attr);
292     if (ret != HI_ERR_SUCCESS) {
293         spi_trans_restore(g_spi_ctrl[id], &trans_attr);
294         return ret;
295     }
296 #ifdef CONFIG_SPI_DMA_SUPPORT
297     if (g_spi_ctrl[id]->use_dma) { /* transfer less fifo size data, use isr modle first */
298         ret = spi_slave_dma_transfer(id, &trans_attr, SPI_WRITE_FLAG);
299     } else {
300         ret = spi_slave_transfer(id, &trans_attr, SPI_WRITE_FLAG);
301     }
302 #else
303     ret = spi_slave_transfer(id, &trans_attr, SPI_WRITE_FLAG);
304 #endif
305 
306     spi_trans_restore(g_spi_ctrl[id], &trans_attr);
307     return ret;
308 }
309 
hi_spi_slave_read(hi_spi_idx id,hi_pvoid read_data,hi_u32 byte_len,hi_u32 time_out_ms)310 hi_u32 hi_spi_slave_read(hi_spi_idx id, hi_pvoid read_data, hi_u32 byte_len, hi_u32 time_out_ms)
311 {
312     hi_u32 ret;
313     hi_u32 data_len;
314     if ((hi_u32)id > HI_SPI_ID_1 || read_data == HI_NULL || byte_len == 0 || id < HI_SPI_ID_0) {
315         return HI_ERR_SPI_PARAMETER_WRONG;
316     }
317     if (g_spi_ctrl[id] == HI_NULL) {
318         return HI_ERR_SPI_NOT_INIT;
319     }
320     if (g_spi_ctrl[id]->spi_cfg.is_slave != SPI_CFG_ROLE_SLAVE) {
321         return HI_ERR_SPI_PARAMETER_WRONG;
322     }
323     data_len = spi_get_data_len(g_spi_ctrl[id]->spi_cfg.data_width, byte_len);
324     if (data_len == 0) {
325         return HI_ERR_SPI_PARAMETER_WRONG;
326     }
327     spi_trans_attr trans_attr = { time_out_ms, SPI_SLAVE_OPT_READ };
328     g_spi_ctrl[id]->single_len = 0;
329     g_spi_ctrl[id]->trans_len = data_len;
330     g_spi_ctrl[id]->rx_buf.buf = read_data;
331     g_spi_ctrl[id]->rx_buf.cur_pos = 0;
332     g_spi_ctrl[id]->rx_buf.cur_cnt = 0;
333     spi_flush_fifo(g_spi_ctrl[id]->reg_base);
334     ret = spi_trans_prepare(g_spi_ctrl[id], &trans_attr);
335     if (ret != HI_ERR_SUCCESS) {
336         spi_trans_restore(g_spi_ctrl[id], &trans_attr);
337         return ret;
338     }
339 #ifdef CONFIG_SPI_DMA_SUPPORT
340     if (g_spi_ctrl[id]->use_dma) {
341         ret = spi_slave_dma_transfer(id, &trans_attr, SPI_READ_FLAG);
342     } else {
343         ret = spi_slave_transfer(id, &trans_attr, SPI_READ_FLAG);
344     }
345 #else
346     ret = spi_slave_transfer(id, &trans_attr, SPI_READ_FLAG);
347 #endif
348 
349     spi_trans_restore(g_spi_ctrl[id], &trans_attr);
350     return ret;
351 }
352 
hi_spi_host_writeread(hi_spi_idx id,hi_pvoid write_data,hi_pvoid read_data,hi_u32 byte_len)353 hi_u32 hi_spi_host_writeread(hi_spi_idx id, hi_pvoid write_data, hi_pvoid read_data, hi_u32 byte_len)
354 {
355     if ((id > HI_SPI_ID_1) || (id < HI_SPI_ID_0) || byte_len == 0 ||
356         (write_data == HI_NULL) || (read_data == HI_NULL)) {
357         return HI_ERR_SPI_PARAMETER_WRONG;
358     }
359     return spi_host_writeread(id, write_data, read_data, byte_len, SPI_HOST_OPT_BASE);
360 }
361 
hi_spi_host_read(hi_spi_idx id,hi_pvoid read_data,hi_u32 byte_len)362 hi_u32 hi_spi_host_read(hi_spi_idx id, hi_pvoid read_data, hi_u32 byte_len)
363 {
364     if ((id > HI_SPI_ID_1) || (id < HI_SPI_ID_0) || (byte_len == 0) || (read_data == HI_NULL)) {
365         return HI_ERR_SPI_PARAMETER_WRONG;
366     }
367     return spi_host_writeread(id, HI_NULL, read_data, byte_len, (SPI_HOST_OPT_BASE) | SPI_OPT_SEND_FIX_DATA);
368 }
369 
hi_spi_host_write(hi_spi_idx id,hi_pvoid write_data,hi_u32 byte_len)370 hi_u32 hi_spi_host_write(hi_spi_idx id, hi_pvoid write_data, hi_u32 byte_len)
371 {
372     if ((id > HI_SPI_ID_1) || (id < HI_SPI_ID_0) || (byte_len == 0) || (write_data == HI_NULL)) {
373         return HI_ERR_SPI_PARAMETER_WRONG;
374     }
375     return spi_host_writeread(id, write_data, HI_NULL, byte_len, (SPI_HOST_OPT_BASE) | SPI_OPT_RCV_FIX_DATA);
376 }
377 
hi_spi_set_irq_mode(hi_spi_idx id,hi_bool irq_en)378 hi_u32 hi_spi_set_irq_mode(hi_spi_idx id, hi_bool irq_en)
379 {
380     if ((id > HI_SPI_ID_1) || (id < HI_SPI_ID_0)) {
381         return HI_ERR_SPI_PARAMETER_WRONG;
382     }
383     if (g_spi_ctrl[id] == HI_NULL) {
384         return HI_ERR_SPI_NOT_INIT;
385     }
386     if (g_spi_ctrl[id]->transferring) {
387         return HI_ERR_SPI_BUSY;
388     }
389     g_spi_ctrl[id]->use_irq = irq_en;
390     if (!irq_en) {
391         spi_isr_disable(g_spi_ctrl[id]->reg_base, SPI_INT_BIT_TX_FIFO_WATER_LINE |
392                         SPI_INT_BIT_RX_FIFO_WATER_LINE |
393                         SPI_INT_BIT_RX_FIFO_TIME_OUT);
394     }
395     return HI_ERR_SUCCESS;
396 }
397 
hi_spi_set_dma_mode(hi_spi_idx id,hi_bool dma_en)398 hi_u32 hi_spi_set_dma_mode(hi_spi_idx id, hi_bool dma_en)
399 {
400     if (id > HI_SPI_ID_1) {
401         return HI_ERR_SPI_PARAMETER_WRONG;
402     }
403     if (g_spi_ctrl[id] == HI_NULL) {
404         return HI_ERR_SPI_NOT_INIT;
405     }
406     if (g_spi_ctrl[id]->transferring) {
407         return HI_ERR_SPI_BUSY;
408     }
409 #ifdef CONFIG_SPI_DMA_SUPPORT
410     g_spi_ctrl[id]->use_dma = dma_en;
411 #else
412     hi_unref_param(dma_en);
413     return HI_ERR_SPI_NOT_SUPPORT_DMA;
414 #endif
415     return HI_ERR_SUCCESS;
416 }
417 
hi_spi_register_usr_func(hi_spi_idx id,hi_spi_usr_func prepare_func,hi_spi_usr_func restore_func)418 hi_u32 hi_spi_register_usr_func(hi_spi_idx id, hi_spi_usr_func prepare_func, hi_spi_usr_func restore_func)
419 {
420     if ((id > HI_SPI_ID_1) || (id < HI_SPI_ID_0)) {
421         return HI_ERR_SPI_PARAMETER_WRONG;
422     }
423     if (g_spi_ctrl[id] == HI_NULL) {
424         return HI_ERR_SPI_NOT_INIT;
425     }
426 
427     if (g_spi_ctrl[id]->transferring) {
428         return HI_ERR_SPI_BUSY;
429     }
430     g_spi_ctrl[id]->prepare_func = prepare_func;
431     g_spi_ctrl[id]->restore_func = restore_func;
432     return HI_ERR_SUCCESS;
433 }
434 
hi_spi_set_basic_info(hi_spi_idx id,const hi_spi_cfg_basic_info * param)435 hi_u32 hi_spi_set_basic_info(hi_spi_idx id, const hi_spi_cfg_basic_info *param)
436 {
437     hi_u32 ret;
438     hi_u32 spi_clk = spi_get_clk();
439     if (((hi_u32)id > HI_SPI_ID_1) || (param == HI_NULL) || (id < HI_SPI_ID_0)) {
440         return HI_ERR_SPI_PARAMETER_WRONG;
441     }
442 
443     if (g_spi_ctrl[id] == HI_NULL) {
444         return HI_ERR_SPI_NOT_INIT;
445     }
446 
447     if (g_spi_ctrl[id]->transferring) {
448         return HI_ERR_SPI_BUSY;
449     }
450 
451     if (param->fram_mode > HI_SPI_CFG_FRAM_MODE_MICROWIRE || param->data_width < HI_SPI_CFG_DATA_WIDTH_E_4BIT ||
452         param->freq > spi_max_speed(spi_clk) || param->freq < spi_min_speed(spi_clk)) {
453         return HI_ERR_SPI_PARAMETER_WRONG;
454     }
455     if (g_spi_ctrl[id]->spi_cfg.loop_back == HI_TRUE && (param->fram_mode == HI_SPI_CFG_FRAM_MODE_MICROWIRE ||
456         g_spi_ctrl[id]->spi_cfg.is_slave == SPI_CFG_ROLE_SLAVE)) {
457         return HI_ERR_SPI_PARAMETER_WRONG;
458     }
459 
460     /* compute spi speed, speed=clk/(cpsdvsr*(scr+1)) */
461     hi_u32 tmp = spi_clk / param->freq;
462     if (tmp < CPSDVSR_MIN) {
463         g_spi_ctrl[id]->spi_cfg.cpsdvsr = CPSDVSR_MIN;
464         g_spi_ctrl[id]->spi_cfg.scr = 0;
465     } else if (tmp <= CPSDVSR_MAX) {
466         g_spi_ctrl[id]->spi_cfg.cpsdvsr = (hi_u16)(tmp & (~0x1));
467         g_spi_ctrl[id]->spi_cfg.scr = (tmp / g_spi_ctrl[id]->spi_cfg.cpsdvsr) - 1;
468     } else {
469         g_spi_ctrl[id]->spi_cfg.cpsdvsr = CPSDVSR_MAX;
470         g_spi_ctrl[id]->spi_cfg.scr = (tmp / g_spi_ctrl[id]->spi_cfg.cpsdvsr) - 1;
471     }
472 
473     g_spi_ctrl[id]->spi_cfg.data_width = param->data_width;
474     g_spi_ctrl[id]->spi_cfg.fram_mode = param->fram_mode;
475     g_spi_ctrl[id]->spi_cfg.cpol = param->cpol;
476     g_spi_ctrl[id]->spi_cfg.cpha = param->cpha;
477     g_spi_ctrl[id]->spi_cfg.endian = param->endian;
478     /* write reg */
479     ret = spi_config(g_spi_ctrl[id]);
480     return ret;
481 }
482 
spi_ctrl_init(hi_spi_idx id,hi_spi_cfg_init_param init_param)483 static hi_void spi_ctrl_init(hi_spi_idx id, hi_spi_cfg_init_param init_param)
484 {
485     g_spi_ctrl[id]->spi_cfg.loop_back = HI_FALSE;
486     hi_u16 reg_val;
487     hi_reg_read16(CLDO_CTL_CLKEN_REG, reg_val);
488     if (id == HI_SPI_ID_0) {
489         g_spi_ctrl[id]->spi_cfg.tx_fifo_line = SPI0_TX_FIFO_WATER_LINE;
490         g_spi_ctrl[id]->spi_cfg.rx_fifo_line = SPI0_RX_FIFO_WATER_LINE;
491         g_spi_ctrl[id]->spi_cfg.tx_fifo_dma_line = SPI0_TX_FIFO_DMA_WLINE_64;
492         g_spi_ctrl[id]->spi_cfg.rx_fifo_dma_line = SPI0_RX_FIFO_DMA_WLINE_128;
493         reg_val |= 1 << CLKEN_SPI0;
494     } else {
495         g_spi_ctrl[id]->spi_cfg.tx_fifo_line = SPI1_TX_FIFO_WATER_LINE;
496         g_spi_ctrl[id]->spi_cfg.rx_fifo_line = SPI1_RX_FIFO_WATER_LINE;
497         g_spi_ctrl[id]->spi_cfg.tx_fifo_dma_line = SPI1_TX_FIFO_DMA_WLINE_16;
498         g_spi_ctrl[id]->spi_cfg.rx_fifo_dma_line = SPI1_RX_FIFO_DMA_WLINE_32;
499         reg_val |= 1 << CLKEN_SPI1;
500     }
501     hi_reg_write16(CLDO_CTL_CLKEN_REG, reg_val); /* enable spix clk bus */
502     g_spi_ctrl[id]->spi_cfg.is_slave = init_param.is_slave ? SPI_CFG_ROLE_SLAVE : SPI_CFG_ROLE_MASTER;
503     spi_reset(g_spi_ctrl[id]);
504     spi_set_fifo_line(g_spi_ctrl[id]);
505 #ifdef CONFIG_SPI_DMA_SUPPORT
506     spi_set_dma_fifo_line(g_spi_ctrl[id]);
507 #endif
508     spi_isr_disable(g_spi_ctrl[id]->reg_base,
509                     SPI_INT_BIT_RX_FIFO_WATER_LINE | SPI_INT_BIT_RX_FIFO_TIME_OUT | SPI_INT_BIT_RX_FIFO_OVER_FLOW);
510 }
511 
512 #ifdef CONFIG_SPI_DMA_SUPPORT
spi_dma_init(hi_void)513 static hi_u32 spi_dma_init(hi_void)
514 {
515     hi_u32 ret = HI_ERR_SUCCESS;
516     if (hi_dma_is_init() == HI_FALSE) {
517         ret = hi_dma_init();
518     }
519     return ret;
520 }
521 #endif
522 
hi_spi_init(hi_spi_idx id,hi_spi_cfg_init_param init_param,const hi_spi_cfg_basic_info * param)523 hi_u32 hi_spi_init(hi_spi_idx id, hi_spi_cfg_init_param init_param, const hi_spi_cfg_basic_info *param)
524 {
525     if ((id > HI_SPI_ID_1) || (param == HI_NULL) || (id < HI_SPI_ID_0)) {
526         return HI_ERR_SPI_PARAMETER_WRONG;
527     }
528     hi_u32 ret;
529     if (g_spi_ctrl[id] != HI_NULL) {
530         return HI_ERR_SPI_REINIT;
531     }
532 
533     g_spi_ctrl[id] = (spi_ctrl *)hi_malloc(HI_MOD_ID_DRV_SPI, sizeof(spi_ctrl));
534     if (g_spi_ctrl[id] == HI_NULL) {
535         return HI_ERR_MALLOC_FAILUE;
536     }
537     memset_s(g_spi_ctrl[id], sizeof(spi_ctrl), 0x0, sizeof(spi_ctrl));
538     g_spi_ctrl[id]->reg_base = (id == HI_SPI_ID_0) ? HI_SSP0_REG_BASE : HI_SSP1_REG_BASE;
539 
540     ret = hi_sem_bcreate(&g_spi_ctrl[id]->sem_id, 1);
541     if (ret != HI_ERR_SUCCESS) {
542         goto init_fail;
543     }
544 
545     ret = hi_event_create(&g_spi_ctrl[id]->event_id);
546     if (ret != HI_ERR_SUCCESS) {
547         goto init_fail2;
548     }
549 
550     g_spi_ctrl[id]->irq_num = (id == HI_SPI_ID_0) ? SSP_0_IRQ : SSP_1_IRQ;
551     ret = hi_irq_request(g_spi_ctrl[id]->irq_num, HI_IRQ_FLAG_PRI2, (irq_routine)spi_isr, (uintptr_t)g_spi_ctrl[id]);
552     if (ret != HI_ERR_SUCCESS) {
553         goto init_fail3;
554     }
555     spi_ctrl_init(id, init_param);
556     ret = (hi_u32)hi_spi_set_basic_info(id, param);
557     if (ret != HI_ERR_SUCCESS) {
558         goto init_fail4;
559     }
560 
561 #ifdef CONFIG_SPI_DMA_SUPPORT
562     return spi_dma_init();
563 #endif
564 
565     return HI_ERR_SUCCESS;
566 
567 init_fail4:
568     (hi_void) hi_irq_free(g_spi_ctrl[id]->irq_num);
569 init_fail3:
570     (hi_void) hi_event_delete(g_spi_ctrl[id]->event_id);
571 init_fail2:
572     (hi_void) hi_sem_delete(g_spi_ctrl[id]->sem_id);
573 init_fail:
574     hi_free(HI_MOD_ID_DRV_SPI, g_spi_ctrl[id]);
575     g_spi_ctrl[id] = HI_NULL;
576     return ret;
577 }
578 
hi_spi_deinit(hi_spi_idx id)579 hi_u32 hi_spi_deinit(hi_spi_idx id)
580 {
581     hi_u16 reg_val;
582     if ((id > HI_SPI_ID_1) || (id < HI_SPI_ID_0)) {
583         return HI_ERR_SPI_PARAMETER_WRONG;
584     }
585     if (g_spi_ctrl[id] == HI_NULL) {
586         return HI_ERR_SUCCESS; /* HI_ERR_SPI_NOT_INIT return success */
587     }
588     if (g_spi_ctrl[id]->transferring) {
589         return HI_ERR_SPI_BUSY;
590     }
591 
592     spi_isr_disable(g_spi_ctrl[id]->reg_base,
593                     SPI_INT_BIT_RX_FIFO_WATER_LINE | SPI_INT_BIT_RX_FIFO_TIME_OUT | SPI_INT_BIT_RX_FIFO_OVER_FLOW);
594     hi_irq_disable(g_spi_ctrl[id]->irq_num);
595     (hi_void) hi_irq_free(g_spi_ctrl[id]->irq_num);
596 
597     (hi_void) hi_sem_delete(g_spi_ctrl[id]->sem_id);
598     (hi_void) hi_event_delete(g_spi_ctrl[id]->event_id);
599     /* disable spi */
600     spi_disable(g_spi_ctrl[id]);
601     hi_free(HI_MOD_ID_DRV_SPI, g_spi_ctrl[id]);
602     g_spi_ctrl[id] = HI_NULL;
603     hi_reg_read16(CLDO_CTL_CLKEN_REG, reg_val);
604     reg_val &= (id == HI_SPI_ID_0) ? ~(1 << CLKEN_SPI0) : ~(1 << CLKEN_SPI1);
605     hi_reg_write16(CLDO_CTL_CLKEN_REG, reg_val); /* disable spix clk bus */
606     return HI_ERR_SUCCESS;
607 }
608