| 1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573 |
- /**
- * @file wm_hostspi.c
- *
- * @brief host spi Driver Module
- *
- * @author dave
- *
- * Copyright (c) 2015 Winner Microelectronics Co., Ltd.
- */
- #include <stdio.h>
- #include <string.h>
- #include <stdlib.h>
- #include "wm_regs.h"
- #include "wm_irq.h"
- #include "wm_gpio.h"
- #include "wm_hostspi.h"
- #include "wm_dma.h"
- #include "wm_dbg.h"
- #include "wm_mem.h"
- #include "wm_cpu.h"
- #include "wm_spi_hal.h"
- #include "wm_wl_task.h"
- #include "tls_common.h"
- #include "core_804.h"
- #include "wm_pmu.h"
- #define ATTRIBUTE_ISR __attribute__((isr))
- static struct tls_spi_port *spi_port = NULL;
- #define MSG_QUEUE_SIZE (8)
- #define SPI_SCHEDULER_STK_SIZE (256)
- static u32 *spi_scheduler_stk = NULL;
- void tls_spi_queue_send(u32 msg);
- #define SPI_SCHED_MSG_START_ENGINE (1)
- #define SPI_SCHED_MSG_TX_FIFO_READY (2)
- #define SPI_SCHED_MSG_RX_FIFO_READY (3)
- #define SPI_SCHED_MSG_TRANSFER_COMPLETE (4)
- #define SPI_SCHED_MSG_EXIT (5)
- #define SPI_SCHED_MSG_END (6)
- static void spi_start_transfer(u32 transfer_bytes);
- int tls_spi_async(struct tls_spi_message *message);
- int tls_spi_sync(struct tls_spi_message *message);
- #ifdef SPI_USE_DMA
- unsigned char *SPI_DMA_CMD_ADDR = NULL;
- unsigned char *SPI_DMA_BUF_ADDR = NULL;
- static void SpiMasterInit(u8 mode, u8 cs_active, u32 fclk)
- {
- tls_sys_clk sysclk;
- SPIM_CHCFG_REG = SPI_CLEAR_FIFOS;
- while (SPIM_CHCFG_REG & SPI_CLEAR_FIFOS) cs_active = cs_active;
- tls_sys_clk_get(&sysclk); //获取实际频率
- SPIM_CLKCFG_REG = sysclk.apbclk*UNIT_MHZ/(fclk*2) - 1;;
- SPIM_SPICFG_REG = 0;
- SPIM_SPICFG_REG = SPI_FRAME_FORMAT_MOTO | SPI_SET_MASTER_SLAVE(SPI_MASTER) | mode;
- SPIM_INTEN_REG = 0xff; /* Disable INT */
- if (SPI_DMA_CMD_ADDR == NULL)
- {
- SPI_DMA_CMD_ADDR = tls_mem_alloc(SPI_DMA_CMD_MAX_SIZE);
- if (SPI_DMA_CMD_ADDR == NULL)
- {
- return;
- }
- }
- if (SPI_DMA_BUF_ADDR == NULL)
- {
- SPI_DMA_BUF_ADDR = tls_mem_alloc(SPI_DMA_BUF_MAX_SIZE);
- if (SPI_DMA_BUF_ADDR == NULL)
- {
- tls_mem_free(SPI_DMA_CMD_ADDR);
- SPI_DMA_CMD_ADDR = NULL;
- return;
- }
- }
- tls_dma_init();
- }
- int spiWaitIdle(void)
- {
- unsigned long regVal;
- unsigned long timeout = 0;
- do
- {
- timeout++;
- if (timeout > 0x4FFFFF) // 5s
- return TLS_SPI_STATUS_EBUSY;
- regVal = SPIM_SPISTATUS_REG;
- }
- while (regVal & (1 << 12));
- return TLS_SPI_STATUS_OK;
- }
- static int SpiDmaBlockWrite(u8 * data, u32 len, u8 ifusecmd, u32 cmd)
- {
- unsigned char dmaCh = 0;
- struct tls_dma_descriptor DmaDesc;
- u32 txlen, txlenbk;
- u32 i, blocknum, blocksize = 0;
- int ret = TLS_SPI_STATUS_OK;
- int txcmdover = 0;
- if (NULL == data)
- {
- return TLS_SPI_STATUS_EINVAL;
- }
- if (spiWaitIdle())
- return TLS_SPI_STATUS_EBUSY;
- SPIM_CHCFG_REG = SPI_CLEAR_FIFOS;
- while (SPIM_CHCFG_REG & SPI_CLEAR_FIFOS);
- if (ifusecmd)
- SPIM_TXDATA_REG = cmd;
- if (len % 4)
- {
- txlen = len & 0xfffffffc; // 不够字的最后单独发
- }
- else
- {
- txlen = len;
- }
- txlenbk = txlen;
- if (txlen > 0)
- {
- blocknum = txlen / SPI_DMA_MAX_TRANS_SIZE;
- /* Request DMA Channel */
- dmaCh = tls_dma_request(1,TLS_DMA_FLAGS_CHANNEL_SEL(TLS_DMA_SEL_LSSPI_TX) |
- TLS_DMA_FLAGS_HARD_MODE);
- for (i = 0; i <= blocknum; i++)
- {
- DmaDesc.src_addr = (int) (data + i * SPI_DMA_MAX_TRANS_SIZE);
- DmaDesc.dest_addr = HR_SPI_TXDATA_REG;
- blocksize = (txlen > SPI_DMA_MAX_TRANS_SIZE) ? SPI_DMA_MAX_TRANS_SIZE : txlen;
- if (0 == blocksize)
- break;
- DmaDesc.dma_ctrl = TLS_DMA_DESC_CTRL_SRC_ADD_INC |
- TLS_DMA_DESC_CTRL_DATA_SIZE_WORD |
- TLS_DMA_DESC_CTRL_TOTAL_BYTES(blocksize);
- DmaDesc.valid = TLS_DMA_DESC_VALID;
- DmaDesc.next = NULL;
- tls_dma_start(dmaCh, &DmaDesc, 0);
- /* Enable SPI TX DMA */
- SPIM_MODECFG_REG = SPI_RX_TRIGGER_LEVEL(0) | SPI_TX_TRIGGER_LEVEL(0) | SPI_TX_DMA_ON;
- SPIM_SPITIMEOUT_REG = SPI_TIMER_EN | SPI_TIME_OUT((u32) 0xffff);
- if (ifusecmd && 0 == i)
- {
- SPIM_CHCFG_REG = SPI_FORCE_SPI_CS_OUT | SPI_TX_CHANNEL_ON |
- SPI_CONTINUE_MODE | SPI_START |
- SPI_VALID_CLKS_NUM(((blocksize + 4) * 8));
- txcmdover = 1;
- }
- else
- SPIM_CHCFG_REG = SPI_FORCE_SPI_CS_OUT | SPI_TX_CHANNEL_ON | SPI_CONTINUE_MODE |
- SPI_START | SPI_VALID_CLKS_NUM((blocksize * 8));
- if (spiWaitIdle())
- {
- ret = TLS_SPI_STATUS_EBUSY;
- break;
- }
- /* Wait Dma Channel Complete and Free Dma channel */
- if (tls_dma_wait_complt(dmaCh))
- {
- ret = TLS_SPI_STATUS_EBUSY;
- break;
- }
- txlen -= blocksize;
- }
- tls_dma_free(dmaCh);
- }
- // tx 不够一个整字的几个字节
- if (len > txlenbk)
- {
- u32 word32 = 0;
- int temp = 0;
- for (i = 0; i < (len - txlenbk); i++)
- {
- word32 |= (data[txlenbk + i] << (i * 8));
- }
- SPIM_TXDATA_REG = word32;
- SPIM_MODECFG_REG = SPI_RX_TRIGGER_LEVEL(0) | SPI_TX_TRIGGER_LEVEL(0);
- SPIM_SPITIMEOUT_REG = SPI_TIMER_EN | SPI_TIME_OUT((u32) 0xffff);
- if (ifusecmd && 0 == txcmdover) // 需要发送命令,但是命令还没有发送出去,发送的字节数需要增加4
- temp = 4;
- SPIM_CHCFG_REG = SPI_FORCE_SPI_CS_OUT | SPI_TX_CHANNEL_ON | SPI_CONTINUE_MODE |
- SPI_START | SPI_VALID_CLKS_NUM(((temp + len - txlenbk) * 8));
- if (spiWaitIdle())
- {
- ret = TLS_SPI_STATUS_EBUSY;
- }
- }
- SPIM_CHCFG_REG = 0x00000000;
- SPIM_MODECFG_REG = 0x00000000;
- SPIM_SPITIMEOUT_REG = 0x00000000;
- return ret;
- }
- static int SpiDmaBlockRead(u8 * data, u32 len, u8 * txdata, u8 txlen)
- {
- unsigned char dmaCh = 0;
- struct tls_dma_descriptor DmaDesc;
- u32 word32 = 0;
- u32 i;
- u32 rxlen, rxlenbk;
- u8 blocknum;
- u32 blocksize = 0;
- int ret = TLS_SPI_STATUS_OK;
- // printf("\nentry SpiDmaBlockRead\n");
- if (NULL == data)
- {
- return TLS_SPI_STATUS_EINVAL;
- }
- if (spiWaitIdle())
- {
- return TLS_SPI_STATUS_EBUSY;
- }
- SPIM_CHCFG_REG = SPI_CLEAR_FIFOS;
- while (SPIM_CHCFG_REG & SPI_CLEAR_FIFOS);
- if (len % 4)
- {
- rxlen = len & 0xfffffffc; // 不够字的最后单独取
- }
- else
- {
- rxlen = len;
- }
- rxlenbk = rxlen;
- blocknum = rxlen / SPI_DMA_MAX_TRANS_SIZE;
- if (txlen > 0 && txlen <= 32)
- {
- for (i = 0; i < txlen; i++)
- {
- if ((i > 0) && (0 == i % 4))
- {
- SPIM_TXDATA_REG = word32;
- word32 = 0;
- }
- word32 |= (txdata[i] << ((i % 4) * 8));
- }
- SPIM_TXDATA_REG = word32;
- }
- /* Request DMA Channel */
- dmaCh = tls_dma_request(1,TLS_DMA_FLAGS_CHANNEL_SEL(TLS_DMA_SEL_LSSPI_RX) |
- TLS_DMA_FLAGS_HARD_MODE);
- DmaDesc.src_addr = HR_SPI_RXDATA_REG;
- for (i = 0; i <= blocknum; i++)
- {
- if (rxlenbk > 0)
- {
- // 说明接收的数据大于4
- // printf("\ni =%d\n",i);
- DmaDesc.dest_addr = (int) (data + i * SPI_DMA_MAX_TRANS_SIZE);
- blocksize = (rxlen > SPI_DMA_MAX_TRANS_SIZE) ? SPI_DMA_MAX_TRANS_SIZE : rxlen;
- if (0 == blocksize)
- break;
- // printf("\nblocksize= %d\n",blocksize);
- DmaDesc.dma_ctrl =
- TLS_DMA_DESC_CTRL_DEST_ADD_INC | TLS_DMA_DESC_CTRL_BURST_SIZE1 |
- TLS_DMA_DESC_CTRL_DATA_SIZE_WORD |
- TLS_DMA_DESC_CTRL_TOTAL_BYTES(blocksize);
- // word32 = DmaDesc.dma_ctrl;
- // printf("\ndma ctrl = %x\n",DmaDesc.dma_ctrl);
- DmaDesc.valid = TLS_DMA_DESC_VALID;
- DmaDesc.next = NULL;
- tls_dma_start(dmaCh, &DmaDesc, 0);
- /* Enable SPI RX DMA */
- SPIM_MODECFG_REG = SPI_RX_TRIGGER_LEVEL(0) | SPI_TX_TRIGGER_LEVEL(0) |
- SPI_RX_DMA_ON;
- }
- else
- {
- SPIM_MODECFG_REG = SPI_RX_TRIGGER_LEVEL(0) | SPI_TX_TRIGGER_LEVEL(0); // rx数据少于4个byte,不用开DMA
- }
- SPIM_SPITIMEOUT_REG = SPI_TIMER_EN | SPI_TIME_OUT((u32) 0xffff);
- if (0 == blocknum)
- {
- SPIM_CHCFG_REG =
- SPI_FORCE_SPI_CS_OUT | SPI_RX_CHANNEL_ON | SPI_TX_CHANNEL_ON |
- SPI_CONTINUE_MODE | SPI_START |
- SPI_VALID_CLKS_NUM(((len + txlen) * 8)) | SPI_RX_INVALID_BITS(txlen *8);
- }
- else
- {
- if (0 == i) // 第一次需要打开TX
- {
- SPIM_CHCFG_REG =
- SPI_FORCE_SPI_CS_OUT | SPI_RX_CHANNEL_ON | SPI_TX_CHANNEL_ON
- | SPI_CONTINUE_MODE | SPI_START |
- SPI_VALID_CLKS_NUM(((blocksize + txlen) *8)) | SPI_RX_INVALID_BITS(txlen * 8);
- }
- else if (i == blocknum)
- {
- SPIM_CHCFG_REG =
- SPI_FORCE_SPI_CS_OUT | SPI_RX_CHANNEL_ON | SPI_CONTINUE_MODE
- | SPI_START | SPI_VALID_CLKS_NUM((blocksize + len - rxlenbk) * 8);
- }
- else
- {
- SPIM_CHCFG_REG =
- SPI_FORCE_SPI_CS_OUT | SPI_RX_CHANNEL_ON | SPI_CONTINUE_MODE
- | SPI_START | SPI_VALID_CLKS_NUM(blocksize * 8);
- }
- }
- if (spiWaitIdle())
- {
- ret = TLS_SPI_STATUS_EBUSY;
- break;
- }
- /* Wait Dma Channel Complete and Free Dma channel */
- if (tls_dma_wait_complt(dmaCh))
- {
- ret = TLS_SPI_STATUS_EBUSY;
- break;
- }
- rxlen -= blocksize;
- }
- tls_dma_free(dmaCh);
- if (len > rxlenbk) // 取最后的不够一个字的几个byte
- {
- word32 = SPIM_RXDATA_REG;
- *((int *) data + rxlenbk / 4) = word32;
- }
- SPIM_CHCFG_REG = 0x00000000;
- SPIM_MODECFG_REG = 0x00000000;
- SPIM_SPITIMEOUT_REG = 0x00000000;
- return ret;
- }
- #endif
- /**
- * @brief This function is used to set SPI transfer mode.
- *
- * @param[in] type is the transfer type.
- * type == SPI_BYTE_TRANSFER byte transfer
- * type == SPI_WORD_TRANSFER word transfer
- * type == SPI_DMA_TRANSFER DMA transfer
- *
- * @return None
- *
- * @note None
- */
- void tls_spi_trans_type(u8 type)
- {
- spi_port->transtype = type;
- if (SPI_WORD_TRANSFER == type)
- {
- spi_set_endian(0);
- }
- else if (SPI_DMA_TRANSFER == type)
- {
- #ifdef SPI_USE_DMA
- SpiMasterInit(spi_port->mode, TLS_SPI_CS_LOW, spi_port->speed_hz);
- #endif
- }
- }
- static void spi_message_init(struct tls_spi_message *m)
- {
- memset(m, 0, sizeof(*m));
- dl_list_init(&m->transfers);
- }
- static void spi_complete(void *arg)
- {
- tls_os_sem_t *sem;
- sem = (tls_os_sem_t *) arg;
- tls_os_sem_release(sem);
- }
- static u32 spi_fill_txfifo(struct tls_spi_transfer *current_transfer,
- u32 current_remaining_bytes)
- {
- u8 fifo_level;
- u16 rw_words;
- u16 rw_bytes;
- u8 data8;
- u8 i;
- u32 data32 = 0;
- u32 tx_remaining_bytes;
- if ((current_transfer == NULL) || (current_remaining_bytes == 0))
- return 0;
- tx_remaining_bytes = current_remaining_bytes;
- // printf("ready to write to fifo size - %d.\n", tx_remaining_bytes);
- spi_get_status(NULL, NULL, &fifo_level);
- // TLS_DBGPRT_SPI("\nfifo_level 0= %d\n",fifo_level);
- rw_words =
- ((fifo_level > tx_remaining_bytes) ? tx_remaining_bytes : fifo_level) / 4;
- rw_bytes =
- ((fifo_level > tx_remaining_bytes) ? tx_remaining_bytes : fifo_level) % 4;
- // TLS_DBGPRT_SPI("write to spi fifo words - %d, bytes - %d.\n", rw_words,
- // rw_bytes);
- //下面代码17us
- for (i = 0; i < rw_words; i++)
- {
- if (current_transfer->tx_buf)
- {
- if (SPI_BYTE_TRANSFER == spi_port->transtype)
- {
- data32 = 0;
- data32 |= ((u8 *) current_transfer->tx_buf +
- (current_transfer->len - tx_remaining_bytes))[0] << 24;
- data32 |= ((u8 *) current_transfer->tx_buf +
- (current_transfer->len - tx_remaining_bytes))[1] << 16;
- data32 |= ((u8 *) current_transfer->tx_buf +
- (current_transfer->len - tx_remaining_bytes))[2] << 8;
- data32 |= ((u8 *) current_transfer->tx_buf +
- (current_transfer->len - tx_remaining_bytes))[3] << 0;
- }
- else if (SPI_WORD_TRANSFER == spi_port->transtype)
- {
- data32 = *((u32 *) ((u8 *) current_transfer->tx_buf +
- current_transfer->len - tx_remaining_bytes));
- }
- }
- else
- {
- data32 = 0xffffffff;
- }
- TLS_DBGPRT_SPI_INFO("spi fifo[%d]: 0x%x.\n", i, data32);
- spi_data_put(data32);
- tx_remaining_bytes -= 4;
- }
- if (rw_bytes)
- {
- data32 = 0;
- for (i = 0; i < rw_bytes; i++)
- {
- if (current_transfer->tx_buf)
- {
- data8 = ((u8 *) current_transfer->tx_buf)[current_transfer->len -
- tx_remaining_bytes];
- }
- else
- {
- data8 = 0xff;
- }
- if (SPI_BYTE_TRANSFER == spi_port->transtype)
- data32 |= data8 << ((3 - i) * 8);
- else if (SPI_WORD_TRANSFER == spi_port->transtype)
- {
- data32 |= data8 << (i * 8);
- }
- tx_remaining_bytes -= 1;
- }
- TLS_DBGPRT_SPI_INFO("spi_fifo: 0x%x.\n", data32);
- spi_data_put(data32);
- }
- return (current_remaining_bytes - tx_remaining_bytes);
- }
- static u32 spi_get_rxfifo(struct tls_spi_transfer *current_transfer,
- u32 current_remaining_bytes)
- {
- u8 fifo_level;
- u8 rw_words;
- u8 rw_bytes;
- u8 data8 = 0;
- u8 i;
- u32 data32;
- u32 rx_remaining_bytes;
- if ((current_transfer == NULL) || (current_remaining_bytes == 0))
- return 0;
- rx_remaining_bytes = current_remaining_bytes;
- spi_get_status(NULL, &fifo_level, NULL);
- // TLS_DBGPRT_SPI("rx fifo level: %d.\n", fifo_level);
- rw_words = fifo_level / 4;
- rw_bytes = fifo_level % 4;
- // TLS_DBGPRT_SPI("rx data: %d words, %d bytes.\n", rw_words, rw_bytes);
- //下面代码大概10us
- for (i = 0; i < rw_words; i++)
- {
- data32 = spi_data_get();
- // TLS_DBGPRT_SPI("rx data[%d](w): 0x%08x.\n", i, data32);
- if (current_transfer->rx_buf)
- {
- if (SPI_BYTE_TRANSFER == spi_port->transtype)
- {
- data32 = swap_32(data32);
- (((u8 *) current_transfer->rx_buf +
- (current_transfer->len - rx_remaining_bytes)))[0] = (u8) data32;
- (((u8 *) current_transfer->rx_buf +
- (current_transfer->len - rx_remaining_bytes)))[1] = (u8) (data32 >> 8);
- (((u8 *) current_transfer->rx_buf +
- (current_transfer->len - rx_remaining_bytes)))[2] = (u8) (data32 >> 16);
- (((u8 *) current_transfer->rx_buf +
- (current_transfer->len - rx_remaining_bytes)))[3] = (u8) (data32 >> 24);
- }
- else if (SPI_WORD_TRANSFER == spi_port->transtype)
- {
- *((u32 *) ((u8 *) current_transfer->rx_buf +
- current_transfer->len - rx_remaining_bytes)) = data32;
- }
- }
- rx_remaining_bytes -= 4;
- }
- if (rw_bytes)
- {
- data32 = spi_data_get();
- // TLS_DBGPRT_SPI("\nrx data=%x\n",data32);
- if (current_transfer->rx_buf)
- {
- for (i = 0; i < rw_bytes; i++)
- {
- if (SPI_BYTE_TRANSFER == spi_port->transtype)
- data8 = (u8) (data32 >> ((3 - i) * 8));
- else if (SPI_WORD_TRANSFER == spi_port->transtype)
- data8 = (u8) (data32 >> (i * 8));
- // TLS_DBGPRT_SPI("rx data[%d](b): 0x%02x.\n", i, data8);
- ((u8 *) current_transfer->rx_buf)[current_transfer->len -rx_remaining_bytes] = data8;
- rx_remaining_bytes -= 1;
- }
- }
- else
- {
- rx_remaining_bytes -= rw_bytes;
- }
- }
- return (current_remaining_bytes - rx_remaining_bytes);
- }
- static struct tls_spi_transfer *spi_next_transfer(struct tls_spi_message
- *current_message)
- {
- if (current_message == NULL)
- {
- return NULL;
- }
- return dl_list_first(¤t_message->transfers, struct tls_spi_transfer, transfer_list);
- }
- static struct tls_spi_message *spi_next_message(void)
- {
- struct tls_spi_message *current_message;
- current_message =
- dl_list_first(&spi_port->wait_queue, struct tls_spi_message, queue);
- if (current_message == NULL)
- {
- return NULL;
- }
- spi_port->current_transfer = spi_next_transfer(current_message);
- current_message->status = SPI_MESSAGE_STATUS_INPROGRESS;
- return current_message;
- }
- int gSpiCsFlag = 0;
- static void spi_start_transfer(u32 transfer_bytes)
- {
- if (spi_port->reconfig)
- {
- TLS_DBGPRT_SPI_INFO("reconfig the spi master controller.\n");
- spi_set_mode(spi_port->mode);
- spi_set_chipselect_mode(spi_port->cs_active);
- spi_set_sclk(spi_port->speed_hz);
- spi_port->reconfig = 0;
- }
- spi_set_sclk_length(transfer_bytes * 8, 0);
- // if(0 == gSpiCsFlag)
- {
- spi_set_chipselect_mode(SPI_CS_ACTIVE_MODE);
- }
- spi_sclk_start();
- }
- static void spi_continue_transfer(void)
- {
- struct tls_spi_message *current_message;
- struct tls_spi_transfer *current_transfer;
- u32 transfer_bytes;
- current_message = spi_port->current_message;
- current_transfer = spi_port->current_transfer;
- if ((current_message == NULL) || (current_transfer == NULL))
- {
- return;
- }
- transfer_bytes =
- spi_get_rxfifo(current_transfer, spi_port->current_remaining_bytes);
- spi_port->current_remaining_bytes -= transfer_bytes;
- if (spi_port->current_remaining_bytes == 0)
- {
- tls_os_sem_acquire(spi_port->lock, 0);
- dl_list_del(¤t_transfer->transfer_list);
- spi_port->current_transfer =
- spi_next_transfer(spi_port->current_message);
- if (spi_port->current_transfer == NULL)
- {
- // tls_sys_clk_set(CPU_CLK_40M);
- spi_set_chipselect_mode(SPI_CS_INACTIVE_MODE);
- current_message->status = SPI_MESSAGE_STATUS_DONE;
- dl_list_del(¤t_message->queue);
- spi_port->current_message = spi_next_message();
- }
- tls_os_sem_release(spi_port->lock);
- // TLS_DBGPRT_SPI("get the next spi transfer pair.\n");
- current_transfer = spi_port->current_transfer;
- if (current_transfer != NULL)
- {
- spi_port->current_remaining_bytes = current_transfer->len;
- }
- }
- transfer_bytes =
- spi_fill_txfifo(current_transfer, spi_port->current_remaining_bytes);
- if (transfer_bytes)
- {
- spi_start_transfer(transfer_bytes);
- }
- if (current_message->status == SPI_MESSAGE_STATUS_DONE)
- {
- // TLS_DBGPRT_SPI("current spi transaction finish and notify the
- // submitter.\n");
- current_message->complete(current_message->context);
- }
- }
- static void spi_scheduler(void *data)
- {
- u8 err;
- u32 msg;
- u32 transfer_bytes;
- struct tls_spi_transfer *current_transfer;
- while (1)
- {
- err = tls_os_queue_receive(spi_port->msg_queue, (void **) &msg, 4, 0);
- if (err == TLS_OS_SUCCESS)
- {
- switch (msg)
- {
- case SPI_SCHED_MSG_START_ENGINE:
- // tls_sys_clk_set(CPU_CLK_80M); //80MHZ
- if (spi_port->current_message)
- {
- TLS_DBGPRT_WARNING
- ("spi transaction scheduler is running now!\n");
- break;
- }
- TLS_DBGPRT_SPI_INFO
- ("acquire the first transaction message in waiting queue.\n");
- tls_os_sem_acquire(spi_port->lock, 0);
- spi_port->current_message = spi_next_message();
- tls_os_sem_release(spi_port->lock);
- // TLS_DBGPRT_SPI("acquire the first transfer pair in the
- // current transaction message.\n");
- current_transfer = spi_port->current_transfer;
- if (current_transfer == NULL)
- {
- break;
- }
- spi_port->current_remaining_bytes = current_transfer->len;
- // TLS_DBGPRT_SPI("current transfer lenght - %d.\n",
- // spi_port->current_remaining_bytes);
- TLS_DBGPRT_SPI_INFO("fill the tx fifo.\n");
- transfer_bytes = spi_fill_txfifo(current_transfer, spi_port->current_remaining_bytes);
- TLS_DBGPRT_SPI_INFO("start the spi transfer - %d.\n", transfer_bytes);
- spi_start_transfer(transfer_bytes);
- break;
- case SPI_SCHED_MSG_TX_FIFO_READY:
- TLS_DBGPRT_SPI_INFO("process SPI_SCHED_MSG_TX_FIFO_READY.\n");
- break;
- case SPI_SCHED_MSG_RX_FIFO_READY:
- TLS_DBGPRT_SPI_INFO("process SPI_SCHED_MSG_RX_FIFO_READY.\n");
- break;
- case SPI_SCHED_MSG_TRANSFER_COMPLETE:
- spi_continue_transfer();
- break;
- case SPI_SCHED_MSG_EXIT:
- break;
- default:
- break;
- }
- }
- }
- }
- ATTRIBUTE_ISR void SPI_LS_IRQHandler(void)
- {
- u32 int_status;
- u32 int_mask;
- csi_kernel_intrpt_enter();
- int_status = spi_get_int_status();
- // printf("\nspi int sta=%x\n",int_status);
- spi_clear_int_status(int_status);
- int_mask = spi_int_mask();
- int_status &= ~int_mask;
- // printf("spi interrupt - 0x%x.\n", int_status);
- if (int_status & SPI_INT_TX_FIFO_RDY)
- {
- tls_spi_queue_send(SPI_SCHED_MSG_TX_FIFO_READY);
- }
- if (int_status & SPI_INT_RX_FIFO_RDY)
- {
- tls_spi_queue_send(SPI_SCHED_MSG_RX_FIFO_READY);
- }
- if (int_status & SPI_INT_TRANSFER_DONE)
- {
- if (SPI_WORD_TRANSFER == spi_port->transtype)
- {
- spi_continue_transfer();
- }
- else
- {
- tls_spi_queue_send(SPI_SCHED_MSG_TRANSFER_COMPLETE);
- }
- }
- csi_kernel_intrpt_exit();
- }
- /**
- * @brief This function is used to setup the spi CPOL,CPHA,cs signal and clock.
- *
- * @param[in] mode is CPOL and CPHA type defined in TLS_SPI_MODE_0 to TLS_SPI_MODE_3
- * @param[in] cs_active is cs mode, defined as TLS_SPI_CS_LOW or TLS_SPI_CS_HIGH
- * @param[in] fclk is spi clock,the unit is HZ.
- *
- * @retval TLS_SPI_STATUS_OK if setup success
- * @retval TLS_SPI_STATUS_EMODENOSUPPORT if mode is not support
- * @retval TLS_SPI_STATUS_EINVAL if cs_active is not support
- * @retval TLS_SPI_STATUS_ECLKNOSUPPORT if fclk is not support
- *
- * @note None
- */
- int tls_spi_setup(u8 mode, u8 cs_active, u32 fclk)
- {
- tls_sys_clk sysclk;
- if ((spi_port->mode == mode) && (spi_port->cs_active == cs_active)
- && (spi_port->speed_hz == fclk))
- {
- TLS_DBGPRT_WARNING
- ("@mode, @cs_activer, @fclk is the same as settings of the current spi master driver!\n");
- return TLS_SPI_STATUS_OK;
- }
- switch (mode)
- {
- case TLS_SPI_MODE_0:
- case TLS_SPI_MODE_1:
- case TLS_SPI_MODE_2:
- case TLS_SPI_MODE_3:
- spi_port->mode = mode;
- break;
- default:
- TLS_DBGPRT_ERR("@mode is invalid!\n");
- return TLS_SPI_STATUS_EMODENOSUPPORT;
- }
- if ((cs_active != TLS_SPI_CS_HIGH) && (cs_active != TLS_SPI_CS_LOW))
- {
- TLS_DBGPRT_ERR("@cs_active is invalid!\n");
- return TLS_SPI_STATUS_EINVAL;
- }
- else
- {
- spi_port->cs_active = cs_active;
- }
-
- tls_sys_clk_get(&sysclk);
- if ((fclk < TLS_SPI_FCLK_MIN) || (fclk > sysclk.apbclk*UNIT_MHZ/2)) //TLS_SPI_FCLK_MAX
- {
- TLS_DBGPRT_ERR("@fclk is invalid!\n");
- return TLS_SPI_STATUS_ECLKNOSUPPORT;
- }
- else
- {
- spi_port->speed_hz = fclk;
- }
- #ifdef SPI_USE_DMA
- if (SPI_DMA_TRANSFER == spi_port->transtype)
- {
- SpiMasterInit(mode, TLS_SPI_CS_LOW, fclk);
- return TLS_SPI_STATUS_OK;
- }
- #endif
- spi_port->reconfig = 1;
- return TLS_SPI_STATUS_OK;
- }
- /**
- * @brief This function is used to synchronous write command then read data by SPI.
- *
- * @param[in] txbuf is the write data buffer.
- * @param[in] n_tx is the write data length.
- * @param[in] rxbuf is the read data buffer.
- * @param[in] n_rx is the read data length.
- *
- * @retval TLS_SPI_STATUS_OK if write success.
- * @retval TLS_SPI_STATUS_EINVAL if argument is invalid.
- * @retval TLS_SPI_STATUS_ENOMEM if there is no enough memory.
- * @retval TLS_SPI_STATUS_ESHUTDOWN if SPI driver does not installed.
- *
- * @note None
- */
- int tls_spi_read_with_cmd(const u8 * txbuf, u32 n_tx, u8 * rxbuf, u32 n_rx)
- {
- int status;
- struct tls_spi_message message;
- struct tls_spi_transfer x[2];
- if ((txbuf == NULL) || (n_tx == 0) || (rxbuf == NULL) || (n_rx == 0))
- {
- return TLS_SPI_STATUS_EINVAL;
- }
- #ifdef SPI_USE_DMA
- if (SPI_DMA_TRANSFER == spi_port->transtype)
- {
- if (n_rx > SPI_DMA_BUF_MAX_SIZE || n_tx > SPI_DMA_CMD_MAX_SIZE)
- {
- TLS_DBGPRT_ERR("\nread length too long\n");
- return TLS_SPI_STATUS_EINVAL;
- }
- tls_os_sem_acquire(spi_port->lock, 0);
- tls_open_peripheral_clock(TLS_PERIPHERAL_TYPE_LSPI);
- if (SPI_DMA_CMD_ADDR && SPI_DMA_BUF_ADDR)
- {
- MEMCPY((u8 *) SPI_DMA_CMD_ADDR, txbuf, n_tx);
- SpiDmaBlockRead((u8 *) SPI_DMA_BUF_ADDR, n_rx, (u8 *) SPI_DMA_CMD_ADDR,
- n_tx);
- MEMCPY(rxbuf, (u8 *) SPI_DMA_BUF_ADDR, n_rx);
- status = TLS_SPI_STATUS_OK;
- }
- else
- {
- status = TLS_SPI_STATUS_ENOMEM;
- }
- tls_close_peripheral_clock(TLS_PERIPHERAL_TYPE_LSPI);
- tls_os_sem_release(spi_port->lock);
- return status;
- }
- #endif
- spi_message_init(&message);
- memset(x, 0, sizeof(x));
- if (n_tx)
- {
- x[0].len = n_tx;
- x[0].tx_buf = txbuf;
- dl_list_add_tail(&message.transfers, &x[0].transfer_list);
- }
- if (n_rx)
- {
- x[1].len = n_rx;
- x[1].rx_buf = rxbuf;
- dl_list_add_tail(&message.transfers, &x[1].transfer_list);
- }
- /* do the i/o. */
- status = tls_spi_sync(&message);
- return status;
- }
- /**
- * @brief This function is used to synchronous read data by SPI.
- *
- * @param[in] buf is the buffer for saving SPI data.
- * @param[in] len is the data length.
- *
- * @retval TLS_SPI_STATUS_OK if write success.
- * @retval TLS_SPI_STATUS_EINVAL if argument is invalid.
- * @retval TLS_SPI_STATUS_ENOMEM if there is no enough memory.
- * @retval TLS_SPI_STATUS_ESHUTDOWN if SPI driver does not installed.
- *
- * @note None
- */
- int tls_spi_read(u8 * buf, u32 len)
- {
- struct tls_spi_transfer t;
- struct tls_spi_message m;
- if ((buf == NULL) || (len == 0))
- {
- return TLS_SPI_STATUS_EINVAL;
- }
- #ifdef SPI_USE_DMA
- if (SPI_DMA_TRANSFER == spi_port->transtype)
- {
- u32 data32 = 0;
- u16 rxBitLen;
- u32 rdval1 = 0;
- u32 i;
- tls_os_sem_acquire(spi_port->lock, 0);
- tls_open_peripheral_clock(TLS_PERIPHERAL_TYPE_LSPI);
- // 直接传输,这样做的原因是DMA不能连续读取4个字节以内的数据,SPI FIFO读取单位为word
- if (len <= 4)
- {
- SPIM_CHCFG_REG = SPI_CLEAR_FIFOS;
- while (SPIM_CHCFG_REG & SPI_CLEAR_FIFOS);
- rxBitLen = 8 * len;
- rdval1 =
- SPI_FORCE_SPI_CS_OUT | SPI_CS_LOW | SPI_TX_CHANNEL_ON |
- SPI_RX_CHANNEL_ON | SPI_CONTINUE_MODE | SPI_START |
- SPI_VALID_CLKS_NUM(rxBitLen);
- SPIM_CHCFG_REG = rdval1;
- spiWaitIdle();
- SPIM_CHCFG_REG |= SPI_CS_HIGH;
- data32 = SPIM_RXDATA_REG;
- for (i = 0; i < len; i++)
- {
- *(buf + i) = (u8) (data32 >> i * 8);
- }
- SPIM_CHCFG_REG = 0x00000000;
- SPIM_MODECFG_REG = 0x00000000;
- }
- else // DMA传输
- {
- if (len > SPI_DMA_BUF_MAX_SIZE)
- {
- TLS_DBGPRT_ERR("\nread len too long\n");
- tls_close_peripheral_clock(TLS_PERIPHERAL_TYPE_LSPI);
- tls_os_sem_release(spi_port->lock);
- return TLS_SPI_STATUS_EINVAL;
- }
- if (SPI_DMA_BUF_ADDR)
- {
- SpiDmaBlockRead((u8 *) SPI_DMA_BUF_ADDR, len, NULL, 0);
- MEMCPY(buf, (u8 *) SPI_DMA_BUF_ADDR, len);
- }
- else
- {
- tls_close_peripheral_clock(TLS_PERIPHERAL_TYPE_LSPI);
- tls_os_sem_release(spi_port->lock);
- return TLS_SPI_STATUS_ENOMEM;
- }
- }
- tls_close_peripheral_clock(TLS_PERIPHERAL_TYPE_LSPI);
- tls_os_sem_release(spi_port->lock);
- return TLS_SPI_STATUS_OK;
- }
- #endif
- memset(&t, 0, sizeof(t));
- t.rx_buf = buf;
- t.len = len;
- spi_message_init(&m);
- dl_list_add_tail(&m.transfers, &t.transfer_list);
- return tls_spi_sync(&m);
- }
- /**
- * @brief This function is used to synchronous write data by SPI.
- *
- * @param[in] buf is the user data.
- * @param[in] len is the data length.
- *
- * @retval TLS_SPI_STATUS_OK if write success.
- * @retval TLS_SPI_STATUS_EINVAL if argument is invalid.
- * @retval TLS_SPI_STATUS_ENOMEM if there is no enough memory.
- * @retval TLS_SPI_STATUS_ESHUTDOWN if SPI driver does not installed.
- *
- * @note None
- */
- int tls_spi_write(const u8 * buf, u32 len)
- {
- struct tls_spi_transfer t;
- struct tls_spi_message m;
- if ((buf == NULL) || (len == 0))
- {
- return TLS_SPI_STATUS_EINVAL;
- }
- #ifdef SPI_USE_DMA
- if (SPI_DMA_TRANSFER == spi_port->transtype)
- {
- u32 data32 = 0;
- u16 txBitLen;
- u32 rdval1 = 0;
- u32 i;
- tls_os_sem_acquire(spi_port->lock, 0);
- tls_open_peripheral_clock(TLS_PERIPHERAL_TYPE_LSPI);
- if (len <= 4) // 直接传输,这样做的原因是DMA不能连续传输少于4个字节的数据,SPI
- {
- SPIM_CHCFG_REG = SPI_CLEAR_FIFOS;
- while (SPIM_CHCFG_REG & SPI_CLEAR_FIFOS);
- for (i = 0; i < len; i++)
- {
- data32 |= (((u8) (buf[i])) << (i * 8));
- }
- SPIM_TXDATA_REG = data32;
- txBitLen = 8 * len;
- rdval1 =
- SPI_FORCE_SPI_CS_OUT | SPI_CS_LOW | SPI_TX_CHANNEL_ON |
- SPI_RX_CHANNEL_ON | SPI_CONTINUE_MODE | SPI_START |
- SPI_VALID_CLKS_NUM(txBitLen);
- SPIM_CHCFG_REG = rdval1;
- spiWaitIdle();
- SPIM_CHCFG_REG |= SPI_CS_HIGH;
- SPIM_CHCFG_REG = 0x00000000;
- SPIM_MODECFG_REG = 0x00000000;
- }
- else // DMA传输
- {
- if (len > SPI_DMA_BUF_MAX_SIZE)
- {
- TLS_DBGPRT_ERR("\nwrite len too long\n");
- tls_close_peripheral_clock(TLS_PERIPHERAL_TYPE_LSPI);
- tls_os_sem_release(spi_port->lock);
- return TLS_SPI_STATUS_EINVAL;
- }
- if (SPI_DMA_BUF_ADDR)
- {
- MEMCPY((u8 *) SPI_DMA_BUF_ADDR, buf, len);
- SpiDmaBlockWrite((u8 *) SPI_DMA_BUF_ADDR, len, 0, 0);
- }
- else
- {
- tls_close_peripheral_clock(TLS_PERIPHERAL_TYPE_LSPI);
- tls_os_sem_release(spi_port->lock);
- return TLS_SPI_STATUS_ENOMEM;
- }
- }
- tls_close_peripheral_clock(TLS_PERIPHERAL_TYPE_LSPI);
- tls_os_sem_release(spi_port->lock);
- return TLS_SPI_STATUS_OK;
- }
- #endif
- memset(&t, 0, sizeof(t));
- t.tx_buf = buf;
- t.len = len;
- spi_message_init(&m);
- dl_list_add_tail(&m.transfers, &t.transfer_list);
- return tls_spi_sync(&m);
- }
- /**
- * @brief This function is used to synchronous write 32bit command then write data by SPI.
- *
- * @param[in] cmd is the command data.
- * @param[in] n_cmd is the command len,can not bigger than four
- * @param[in] txbuf is the write data buffer.
- * @param[in] n_tx is the write data length.
- *
- * @retval TLS_SPI_STATUS_OK if write success.
- * @retval TLS_SPI_STATUS_EINVAL if argument is invalid.
- * @retval TLS_SPI_STATUS_ENOMEM if there is no enough memory.
- * @retval TLS_SPI_STATUS_ESHUTDOWN if SPI driver does not installed.
- *
- * @note None
- */
- int tls_spi_write_with_cmd(const u8 * cmd, u32 n_cmd, const u8 * txbuf,
- u32 n_tx)
- {
- int status;
- struct tls_spi_message message;
- struct tls_spi_transfer x[2];
- if ((cmd == NULL) || (n_cmd == 0) || (txbuf == NULL) || (n_tx == 0))
- {
- return TLS_SPI_STATUS_EINVAL;
- }
- #ifdef SPI_USE_DMA
- if (SPI_DMA_TRANSFER == spi_port->transtype)
- {
- if (n_tx > SPI_DMA_BUF_MAX_SIZE)
- {
- TLS_DBGPRT_ERR("\nwriten len too long\n");
- return TLS_SPI_STATUS_EINVAL;
- }
- tls_os_sem_acquire(spi_port->lock, 0);
- tls_open_peripheral_clock(TLS_PERIPHERAL_TYPE_LSPI);
- if (SPI_DMA_BUF_ADDR)
- {
- MEMCPY((u8 *) SPI_DMA_BUF_ADDR, (u8 *) cmd, n_cmd);
- MEMCPY((u8 *) (SPI_DMA_BUF_ADDR + n_cmd), txbuf, n_tx);
- SpiDmaBlockWrite((u8 *) SPI_DMA_BUF_ADDR, (n_cmd + n_tx), 0, 0);
- status = TLS_SPI_STATUS_OK;
- }
- else
- {
- status = TLS_SPI_STATUS_ENOMEM;
- }
- tls_close_peripheral_clock(TLS_PERIPHERAL_TYPE_LSPI);
- tls_os_sem_release(spi_port->lock);
- return status;
- }
- #endif
- spi_message_init(&message);
- memset(x, 0, sizeof(x));
- if (n_cmd)
- {
- x[0].len = n_cmd;
- x[0].tx_buf = (const void *) cmd;
- dl_list_add_tail(&message.transfers, &x[0].transfer_list);
- }
- if (n_tx)
- {
- x[1].len = n_tx;
- x[1].tx_buf = txbuf;
- dl_list_add_tail(&message.transfers, &x[1].transfer_list);
- }
- /* do the i/o. */
- status = tls_spi_sync(&message);
- return status;
- }
- /**
- * @brief
- *
- * @param message
- *
- * @return
- */
- int tls_spi_sync(struct tls_spi_message *message)
- {
- int status;
- u8 err;
- tls_os_sem_t *sem;
- err = tls_os_sem_create(&sem, 0);
- if (err != TLS_OS_SUCCESS)
- {
- TLS_DBGPRT_ERR
- ("create spi transaction synchronizing semaphore fail!\n");
- return TLS_SPI_STATUS_ENOMEM;
- }
- message->context = (void *) sem;
- message->complete = spi_complete;
- tls_open_peripheral_clock(TLS_PERIPHERAL_TYPE_LSPI);
- status = tls_spi_async(message);
- if (status == TLS_SPI_STATUS_OK)
- {
- TLS_DBGPRT_SPI_INFO("waiting spi transaction finishing!\n");
- tls_os_sem_acquire(sem, 0);
- }
- tls_close_peripheral_clock(TLS_PERIPHERAL_TYPE_LSPI);
- tls_os_sem_delete(sem);
- message->context = NULL;
- message->complete = NULL;
- return status;
- }
- /**
- * @brief
- *
- * @param message
- *
- * @return
- */
- int tls_spi_async(struct tls_spi_message *message)
- {
- u8 need_sched;
- struct tls_spi_transfer *transfer;
- if (spi_port == NULL)
- {
- TLS_DBGPRT_ERR("spi master driver module not beed installed!\n");
- return TLS_SPI_STATUS_ESHUTDOWN;
- }
- if ((message == NULL) || (dl_list_empty(&message->transfers)))
- {
- TLS_DBGPRT_ERR("@message is NULL or @message->transfers is empty!\n");
- return TLS_SPI_STATUS_EINVAL;
- }
- dl_list_for_each(transfer, &message->transfers, struct tls_spi_transfer,
- transfer_list)
- {
- if (transfer->len == 0)
- {
- TLS_DBGPRT_ERR("\"@transfer->len\" belong to @message is 0!\n");
- return TLS_SPI_STATUS_EINVAL;
- }
- }
- tls_os_sem_acquire(spi_port->lock, 0);
- if (dl_list_empty(&spi_port->wait_queue))
- {
- need_sched = 1;
- }
- else
- {
- need_sched = 0;
- }
- message->status = SPI_MESSAGE_STATUS_IDLE;
- dl_list_add_tail(&spi_port->wait_queue, &message->queue);
- tls_os_sem_release(spi_port->lock);
- if (need_sched == 1)
- {
- tls_spi_queue_send(SPI_SCHED_MSG_START_ENGINE);
- }
- return TLS_SPI_STATUS_OK;
- }
- /**
- * @brief This function is used to initialize the SPI master driver.
- *
- * @param[in] None
- *
- * @retval TLS_SPI_STATUS_OK if initialize success
- * @retval TLS_SPI_STATUS_EBUSY if SPI is already initialized
- * @retval TLS_SPI_STATUS_ENOMEM if malloc SPI memory fail
- *
- * @note None
- */
- int tls_spi_init(void)
- {
- u8 err;
- struct tls_spi_port *port;
- if (spi_port != NULL)
- {
- TLS_DBGPRT_ERR("spi driver module has been installed!\n");
- return TLS_SPI_STATUS_EBUSY;
- }
- TLS_DBGPRT_SPI_INFO("initialize spi master driver module.\n");
- port = (struct tls_spi_port *) tls_mem_alloc(sizeof(struct tls_spi_port));
- if (port == NULL)
- {
- TLS_DBGPRT_ERR("allocate \"struct tls_spi_port\" fail!\n");
- return TLS_SPI_STATUS_ENOMEM;
- }
- memset(port, 0, sizeof(struct tls_spi_port));
- err = tls_os_sem_create(&port->lock, 1);
- if (err != TLS_OS_SUCCESS)
- {
- TLS_DBGPRT_ERR("create semaphore @spi_port->lock fail!\n");
- tls_mem_free(port);
- return TLS_SPI_STATUS_ENOMEM;
- }
- port->speed_hz = SPI_DEFAULT_SPEED; /* 默认2M */
- port->cs_active = SPI_CS_ACTIVE_MODE;
- port->mode = SPI_DEFAULT_MODE; /* CPHA = 0,CPOL = 0 */
- port->reconfig = 0;
- dl_list_init(&port->wait_queue);
- port->current_message = NULL;
- port->current_remaining_transfer = 0;
- port->current_transfer = NULL;
- port->current_remaining_bytes = 0;
- spi_port = port;
- TLS_DBGPRT_SPI_INFO("initialize spi master controller.\n");
- tls_open_peripheral_clock(TLS_PERIPHERAL_TYPE_LSPI);
- spi_clear_fifo();
- spi_set_endian(1);
- tls_spi_trans_type(SPI_BYTE_TRANSFER);
- spi_set_mode(spi_port->mode);
- spi_set_chipselect_mode(SPI_CS_INACTIVE_MODE); /* cs=1 ,片选无效 */
- spi_force_cs_out(1); /* 片选由软件控制 */
- spi_set_sclk(spi_port->speed_hz);
- spi_set_tx_trigger_level(0);
- spi_set_rx_trigger_level(7);
- spi_set_rx_channel(1);
- spi_set_tx_channel(1);
- spi_unmask_int(SPI_INT_TRANSFER_DONE /* | SPI_INT_RX_FIFO_RDY |SPI_INT_TX_FIFO_RDY */ );
- tls_close_peripheral_clock(TLS_PERIPHERAL_TYPE_LSPI);
- TLS_DBGPRT_SPI_INFO("register spi master interrupt handler.\n");
- tls_irq_enable(SPI_LS_IRQn);
- TLS_DBGPRT_SPI_INFO("spi master driver module initialization finish.\n");
- return TLS_SPI_STATUS_OK;
- }
- int tls_spi_task_init(void)
- {
- u8 err;
- if (NULL == spi_port)
- {
- return TLS_SPI_STATUS_ENOMEM;
- }
- if (spi_port->msg_queue)
- {
- return TLS_SPI_STATUS_OK;
- }
- err = tls_os_queue_create(&spi_port->msg_queue, MSG_QUEUE_SIZE);
- if (err != TLS_OS_SUCCESS)
- {
- TLS_DBGPRT_ERR("create message queue @spi_port->msg_queue fail!\n");
- return TLS_SPI_STATUS_ENOMEM;
- }
- spi_scheduler_stk = tls_mem_alloc(SPI_SCHEDULER_STK_SIZE * sizeof(u32));
- if (NULL == spi_scheduler_stk)
- {
- //tls_os_queue_delete(spi_port->msg_queue);
- TLS_DBGPRT_ERR("spi_scheduler_stk allocated fail!\n");
- return TLS_SPI_STATUS_ENOMEM;
- }
- err = tls_os_task_create(NULL, "hostspi",
- spi_scheduler,
- (void *) spi_port,
- (void *) spi_scheduler_stk,
- SPI_SCHEDULER_STK_SIZE * sizeof(u32),
- TLS_SPI_SCHEDULER_TASK_PRIO, 0);
- if (err != TLS_OS_SUCCESS)
- {
- TLS_DBGPRT_ERR("create spi master driver scheduler task fail!\n");
- //tls_os_queue_delete(spi_port->msg_queue);
- tls_mem_free(spi_scheduler_stk);
- spi_scheduler_stk = NULL;
- return TLS_SPI_STATUS_ENOMEM;
- }
- return TLS_SPI_STATUS_OK;
- }
- void tls_spi_queue_send(u32 msg)
- {
- if (TLS_SPI_STATUS_OK == tls_spi_task_init())
- {
- tls_os_queue_send(spi_port->msg_queue,
- (void *) msg, 4);
- }
- }
- /**
- * @brief
- *
- * @return
- */
- int tls_spi_exit(void)
- {
- TLS_DBGPRT_SPI_INFO("Not support spi master driver module uninstalled!\n");
- return TLS_SPI_STATUS_EPERM;
- }
- /**********************************************************************************************************
- * Description: This function is used to select SPI slave type.
- *
- * Arguments : slave is the slave type,defined as follow:
- * slave == SPI_SLAVE_FLASH :flash
- * slave == SPI_SLAVE_CARD : sd card
- *
- * Returns : Before communicate with different SPI device, must call the function.
- **********************************************************************************************************/
- void tls_spi_slave_sel(u16 slave)
- {
- // u16 ret;
- /*gpio0控制cs信号*/
- tls_gpio_cfg((enum tls_io_name) SPI_SLAVE_CONTROL_PIN, WM_GPIO_DIR_OUTPUT,
- WM_GPIO_ATTR_FLOATING);
- if (SPI_SLAVE_FLASH == slave)
- {
- tls_gpio_write((enum tls_io_name) SPI_SLAVE_CONTROL_PIN, 0);
- // ret = tls_gpio_read(SPI_SLAVE_CONTROL_PIN);
- // printf("\nflash gpio 0 ===%d\n",ret);
- }
- else if (SPI_SLAVE_CARD == slave)
- {
- tls_gpio_write((enum tls_io_name) SPI_SLAVE_CONTROL_PIN, 1);
- // ret = tls_gpio_read(SPI_SLAVE_CONTROL_PIN);
- // printf("\ncard gpio 0 ===%d\n",ret);
- }
- }
- /**********************************************************************************************************
- * Description: This function is used to spi data tx/rx without irq.
- *
- * Arguments : data_out-------data to be sent to slave
- * data_in -------data to be received from slave
- * num_out -------number to be sent to slave unit:byte
- * num_in -------number to be received from slave unit:byte
- * Returns : Before communicate with different SPI device, must call the function.
- **********************************************************************************************************/
- int32_t tls_spi_xfer(const void *data_out, void *data_in, uint32_t num_out, uint32_t num_in)
- {
- int ret = 0;
- uint32_t length = 0;
- uint32_t remain_length ;
- uint32_t int_status;
- struct tls_spi_transfer tls_transfer;
- uint32_t tot_num = 0;
- if (data_in == NULL || num_out == 0 || num_in == 0 || data_out == NULL) {
- return -1;
- }
- tls_open_peripheral_clock(TLS_PERIPHERAL_TYPE_LSPI);
- tls_transfer.tx_buf = data_out;
- tls_transfer.rx_buf = data_in;
- tot_num = (num_out > num_in) ? num_out : num_in;
- remain_length = tot_num;
- tls_transfer.len = tot_num;
- tls_irq_disable(SPI_LS_IRQn);
- //spi_set_rx_channel(1);
- //spi_set_tx_channel(1);
- length = spi_fill_txfifo(&tls_transfer, remain_length);
- spi_set_sclk_length(length * 8, 0);
- spi_sclk_start();
- while (remain_length > 0)
- {
- while (spi_get_busy_status() == 1);
- length = spi_get_rxfifo(&tls_transfer, remain_length);
- remain_length -= length;
- if (remain_length == 0)
- {
- while (spi_get_busy_status() == 1);
- break;
- }
- while (spi_get_busy_status() == 1);
- length = spi_fill_txfifo(&tls_transfer, remain_length);
- if (length)
- {
- spi_set_sclk_length(length * 8, 0);
- spi_sclk_start();
- }
- }
- while (spi_get_busy_status() == 1);
- int_status = spi_get_int_status();
- spi_clear_int_status(int_status);
- tls_irq_enable(SPI_LS_IRQn);
- tls_close_peripheral_clock(TLS_PERIPHERAL_TYPE_LSPI);
- return (ret == TLS_SPI_STATUS_OK) ? 0 : -1;
- }
-
- int tls_spi_set_speed(u32 fclk) {
- if (spi_port->speed_hz == fclk)
- return 0;
- tls_sys_clk sysclk;
- tls_sys_clk_get(&sysclk);
- if ((fclk < TLS_SPI_FCLK_MIN) || (fclk > sysclk.apbclk*UNIT_MHZ/2)) //TLS_SPI_FCLK_MAX
- {
- TLS_DBGPRT_ERR("@fclk is invalid!\n");
- return TLS_SPI_STATUS_ECLKNOSUPPORT;
- }
- else
- {
- spi_port->speed_hz = fclk;
- }
- #ifdef SPI_USE_DMA
- if (SPI_DMA_TRANSFER == spi_port->transtype)
- {
- SpiMasterInit(spi_port->mode, TLS_SPI_CS_LOW, fclk);
- return TLS_SPI_STATUS_OK;
- }
- #endif
- spi_port->reconfig = 1;
- return TLS_SPI_STATUS_OK;
- }
|