/*******************************************************************************
 This module contains WINC3400 SPI protocol bus APIs implementation.
 
 File Name:
 nmspi.c
 
 Summary:
 This module contains WINC3400 SPI protocol bus APIs implementation.
 
 Description:
 This module contains WINC3400 SPI protocol bus APIs implementation.
 *******************************************************************************/

//DOM-IGNORE-BEGIN
/*******************************************************************************
 * Copyright (C) 2021 Microchip Technology Inc. and its subsidiaries.
 *
 * Subject to your compliance with these terms, you may use Microchip software
 * and any derivatives exclusively with Microchip products. It is your
 * responsibility to comply with third party license terms applicable to your
 * use of third party software (including open source software) that may
 * accompany Microchip software.
 *
 * THIS SOFTWARE IS SUPPLIED BY MICROCHIP "AS IS". NO WARRANTIES, WHETHER
 * EXPRESS, IMPLIED OR STATUTORY, APPLY TO THIS SOFTWARE, INCLUDING ANY IMPLIED
 * WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY, AND FITNESS FOR A
 * PARTICULAR PURPOSE.
 *
 * IN NO EVENT WILL MICROCHIP BE LIABLE FOR ANY INDIRECT, SPECIAL, PUNITIVE,
 * INCIDENTAL OR CONSEQUENTIAL LOSS, DAMAGE, COST OR EXPENSE OF ANY KIND
 * WHATSOEVER RELATED TO THE SOFTWARE, HOWEVER CAUSED, EVEN IF MICROCHIP HAS
 * BEEN ADVISED OF THE POSSIBILITY OR THE DAMAGES ARE FORESEEABLE. TO THE
 * FULLEST EXTENT ALLOWED BY LAW, MICROCHIP'S TOTAL LIABILITY ON ALL CLAIMS IN
 * ANY WAY RELATED TO THIS SOFTWARE WILL NOT EXCEED THE AMOUNT OF FEES, IF ANY,
 * THAT YOU HAVE PAID DIRECTLY TO MICROCHIP FOR THIS SOFTWARE.
 *******************************************************************************/

//#include "osal/osal.h"
#include "nm_common.h"

#include "nmspi.h"
#include "spi.h"
#include "BoardCfg.h"
//#include "wdrv_winc_common.h"
//#include "wdrv_winc_spi.h"

#define NMI_PERIPH_REG_BASE 0x1000
#define NMI_INTR_REG_BASE (NMI_PERIPH_REG_BASE+0xa00)
#define NMI_CHIPID  (NMI_PERIPH_REG_BASE)
#define NMI_PIN_MUX_0 (NMI_PERIPH_REG_BASE + 0x408)
#define NMI_INTR_ENABLE (NMI_INTR_REG_BASE)

#define NMI_SPI_REG_BASE 0xe800
#define NMI_SPI_CTL (NMI_SPI_REG_BASE)
#define NMI_SPI_MASTER_DMA_ADDR (NMI_SPI_REG_BASE+0x4)
#define NMI_SPI_MASTER_DMA_COUNT (NMI_SPI_REG_BASE+0x8)
#define NMI_SPI_SLAVE_DMA_ADDR (NMI_SPI_REG_BASE+0xc)
#define NMI_SPI_SLAVE_DMA_COUNT (NMI_SPI_REG_BASE+0x10)
#define NMI_SPI_TX_MODE (NMI_SPI_REG_BASE+0x20)
#define NMI_SPI_PROTOCOL_CONFIG (NMI_SPI_REG_BASE+0x24)
#define NMI_SPI_INTR_CTL (NMI_SPI_REG_BASE+0x2c)
#define NMI_SPI_MISC_CTRL (NMI_SPI_REG_BASE+0x48)

#define NMI_SPI_PROTOCOL_OFFSET (NMI_SPI_PROTOCOL_CONFIG-NMI_SPI_REG_BASE)

#define SPI_BASE                NMI_SPI_REG_BASE

//#define CMD_DMA_WRITE           0xc1
//#define CMD_DMA_READ            0xc2
#define CMD_INTERNAL_WRITE      0xc3
#define CMD_INTERNAL_READ       0xc4
//#define CMD_TERMINATE           0xc5
//#define CMD_REPEAT              0xc6
#define CMD_DMA_EXT_WRITE       0xc7
#define CMD_DMA_EXT_READ        0xc8
#define CMD_SINGLE_WRITE        0xc9
#define CMD_SINGLE_READ         0xca
#define CMD_RESET               0xcf

#define N_OK                     0
#define N_FAIL                  -1
#define N_RESET                 -2
#define N_RETRY                 -3

#define SPI_RESP_RETRY_COUNT    (10)
#define SPI_RETRY_COUNT         (10)
#define DATA_PKT_SZ_256         256
#define DATA_PKT_SZ_512         512
#define DATA_PKT_SZ_1K          1024
#define DATA_PKT_SZ_4K          (4 * 1024)
#define DATA_PKT_SZ_8K          (8 * 1024)
#define DATA_PKT_SZ             DATA_PKT_SZ_8K

static uint8_t gu8Crc_off = 0;
unsigned char mWifiSPIBaudrate;

//static OSAL_MUTEX_HANDLE_TYPE s_spiLock = 0;

static inline int8_t spi_read(uint8_t *b, uint16_t sz)
{
	//JFM WINC Low Level
	int i;
	WIFI_SPI_SS_PIN = 0;
	for(i = 0; i < sz; i++)
	{
		*b++ = SPITransaction(0xAA,mWifiSPIBaudrate);
	}
	WIFI_SPI_SS_PIN = 1;
	
	
	return N_OK;
	
}

static inline int8_t spi_write(uint8_t *b, uint16_t sz)
{
	
	//JFM WINC Low Level
	int i;
	WIFI_SPI_SS_PIN = 0;
	for(i = 0; i < sz; i++)
	{
		SPITransaction(*b++,mWifiSPIBaudrate);
	}
	WIFI_SPI_SS_PIN = 1;
	
    return N_OK;
}

/********************************************
 
 Crc7
 
 ********************************************/

static const uint8_t crc7_syndrome_table[256] = {
    0x00, 0x09, 0x12, 0x1b, 0x24, 0x2d, 0x36, 0x3f,
    0x48, 0x41, 0x5a, 0x53, 0x6c, 0x65, 0x7e, 0x77,
    0x19, 0x10, 0x0b, 0x02, 0x3d, 0x34, 0x2f, 0x26,
    0x51, 0x58, 0x43, 0x4a, 0x75, 0x7c, 0x67, 0x6e,
    0x32, 0x3b, 0x20, 0x29, 0x16, 0x1f, 0x04, 0x0d,
    0x7a, 0x73, 0x68, 0x61, 0x5e, 0x57, 0x4c, 0x45,
    0x2b, 0x22, 0x39, 0x30, 0x0f, 0x06, 0x1d, 0x14,
    0x63, 0x6a, 0x71, 0x78, 0x47, 0x4e, 0x55, 0x5c,
    0x64, 0x6d, 0x76, 0x7f, 0x40, 0x49, 0x52, 0x5b,
    0x2c, 0x25, 0x3e, 0x37, 0x08, 0x01, 0x1a, 0x13,
    0x7d, 0x74, 0x6f, 0x66, 0x59, 0x50, 0x4b, 0x42,
    0x35, 0x3c, 0x27, 0x2e, 0x11, 0x18, 0x03, 0x0a,
    0x56, 0x5f, 0x44, 0x4d, 0x72, 0x7b, 0x60, 0x69,
    0x1e, 0x17, 0x0c, 0x05, 0x3a, 0x33, 0x28, 0x21,
    0x4f, 0x46, 0x5d, 0x54, 0x6b, 0x62, 0x79, 0x70,
    0x07, 0x0e, 0x15, 0x1c, 0x23, 0x2a, 0x31, 0x38,
    0x41, 0x48, 0x53, 0x5a, 0x65, 0x6c, 0x77, 0x7e,
    0x09, 0x00, 0x1b, 0x12, 0x2d, 0x24, 0x3f, 0x36,
    0x58, 0x51, 0x4a, 0x43, 0x7c, 0x75, 0x6e, 0x67,
    0x10, 0x19, 0x02, 0x0b, 0x34, 0x3d, 0x26, 0x2f,
    0x73, 0x7a, 0x61, 0x68, 0x57, 0x5e, 0x45, 0x4c,
    0x3b, 0x32, 0x29, 0x20, 0x1f, 0x16, 0x0d, 0x04,
    0x6a, 0x63, 0x78, 0x71, 0x4e, 0x47, 0x5c, 0x55,
    0x22, 0x2b, 0x30, 0x39, 0x06, 0x0f, 0x14, 0x1d,
    0x25, 0x2c, 0x37, 0x3e, 0x01, 0x08, 0x13, 0x1a,
    0x6d, 0x64, 0x7f, 0x76, 0x49, 0x40, 0x5b, 0x52,
    0x3c, 0x35, 0x2e, 0x27, 0x18, 0x11, 0x0a, 0x03,
    0x74, 0x7d, 0x66, 0x6f, 0x50, 0x59, 0x42, 0x4b,
    0x17, 0x1e, 0x05, 0x0c, 0x33, 0x3a, 0x21, 0x28,
    0x5f, 0x56, 0x4d, 0x44, 0x7b, 0x72, 0x69, 0x60,
    0x0e, 0x07, 0x1c, 0x15, 0x2a, 0x23, 0x38, 0x31,
    0x46, 0x4f, 0x54, 0x5d, 0x62, 0x6b, 0x70, 0x79
};

static uint8_t crc7_byte(uint8_t crc, uint8_t data)
{
    return crc7_syndrome_table[(crc << 1) ^ data];
}

static uint8_t crc7(uint8_t crc, const uint8_t *buffer, uint32_t len)
{
    while (len--)
        crc = crc7_byte(crc, *buffer++);
    return crc;
}

/********************************************
 
 Spi protocol Function
 
 ********************************************/

static int8_t spi_cmd(uint8_t cmd, uint32_t adr, uint32_t u32data, uint32_t sz, uint8_t clockless)
{
    uint8_t bc[9];
    uint8_t len = 5;
	
    bc[0] = cmd;
    switch (cmd)
    {
        case CMD_SINGLE_READ:               /* single word (4 bytes) read */
            bc[1] = (uint8_t)(adr >> 16);
            bc[2] = (uint8_t)(adr >> 8);
            bc[3] = (uint8_t)adr;
            len = 5;
            break;
			
        case CMD_INTERNAL_READ:         /* internal register read */
            bc[1] = (uint8_t)(adr >> 8);
            if(clockless)
                bc[1] |= (1 << 7);
            bc[2] = (uint8_t)adr;
            bc[3] = 0x00;
            len = 5;
            break;
#ifdef CMD_TERMINATE
        case CMD_TERMINATE:                 /* termination */
            bc[1] = 0x00;
            bc[2] = 0x00;
            bc[3] = 0x00;
            len = 5;
            break;
#endif
#ifdef CMD_REPEAT
        case CMD_REPEAT:                        /* repeat */
            bc[1] = 0x00;
            bc[2] = 0x00;
            bc[3] = 0x00;
            len = 5;
            break;
#endif
        case CMD_RESET:                         /* reset */
            bc[1] = 0xff;
            bc[2] = 0xff;
            bc[3] = 0xff;
            len = 5;
            break;
#if defined(CMD_DMA_WRITE) || defined(CMD_DMA_READ)
        case CMD_DMA_WRITE:                 /* dma write */
        case CMD_DMA_READ:                  /* dma read */
            bc[1] = (uint8_t)(adr >> 16);
            bc[2] = (uint8_t)(adr >> 8);
            bc[3] = (uint8_t)adr;
            bc[4] = (uint8_t)(sz >> 8);
            bc[5] = (uint8_t)(sz);
            len = 7;
            break;
#endif
        case CMD_DMA_EXT_WRITE:     /* dma extended write */
        case CMD_DMA_EXT_READ:          /* dma extended read */
            bc[1] = (uint8_t)(adr >> 16);
            bc[2] = (uint8_t)(adr >> 8);
            bc[3] = (uint8_t)adr;
            bc[4] = (uint8_t)(sz >> 16);
            bc[5] = (uint8_t)(sz >> 8);
            bc[6] = (uint8_t)(sz);
            len = 8;
            break;
			
        case CMD_INTERNAL_WRITE:        /* internal register write */
            bc[1] = (uint8_t)(adr >> 8);
            if(clockless)  bc[1] |= (1 << 7);
            bc[2] = (uint8_t)(adr);
            bc[3] = (uint8_t)(u32data >> 24);
            bc[4] = (uint8_t)(u32data >> 16);
            bc[5] = (uint8_t)(u32data >> 8);
            bc[6] = (uint8_t)(u32data);
            len = 8;
            break;
			
        case CMD_SINGLE_WRITE:          /* single word write */
            bc[1] = (uint8_t)(adr >> 16);
            bc[2] = (uint8_t)(adr >> 8);
            bc[3] = (uint8_t)(adr);
            bc[4] = (uint8_t)(u32data >> 24);
            bc[5] = (uint8_t)(u32data >> 16);
            bc[6] = (uint8_t)(u32data >> 8);
            bc[7] = (uint8_t)(u32data);
            len = 9;
            break;
			
        default:
            return N_FAIL;
    }
	
    if (!gu8Crc_off)
    {
        bc[len-1] = (crc7(0x7f, (const uint8_t *)&bc[0], len-1)) << 1;
    }
    else
    {
        len -= 1;
    }
	
    if (N_OK != spi_write(bc, len))
    {
        M2M_ERR("[spi_cmd]: Failed cmd write, bus error...\r\n");
        return N_FAIL;
    }
	
    return N_OK;
}

static int8_t spi_cmd_rsp(uint8_t cmd)
{
    uint8_t rsp;
    int8_t s8RetryCnt;
	
    /**
	 Command/Control response
	 **/
    if ((cmd == CMD_RESET)
#ifdef CMD_TERMINATE
        || (cmd == CMD_TERMINATE)
#endif
#ifdef CMD_REPEAT
        || (cmd == CMD_REPEAT)
#endif
        )
    {
        if (N_OK != spi_read(&rsp, 1))
            return N_FAIL;
    }
	
    /* wait for response */
    s8RetryCnt = SPI_RESP_RETRY_COUNT;
    do
    {
        if (N_OK != spi_read(&rsp, 1))
        {
            M2M_ERR("[spi_cmd_rsp]: Failed cmd response read, bus error...\r\n");
            return N_FAIL;
        }
    }
    while((rsp != cmd) && (s8RetryCnt-- > 0));
	
    if (s8RetryCnt < 0)
    {
        M2M_ERR("[spi_cmd_rsp]: Failed cmd response read\n");
        return N_FAIL;
    }
    /**
	 State response
	 **/
    /* wait for response */
    s8RetryCnt = SPI_RESP_RETRY_COUNT;
    do
    {
        if (N_OK != spi_read(&rsp, 1))
        {
            M2M_ERR("[spi_cmd_rsp]: Failed cmd response read, bus error...\r\n");
            return N_FAIL;
        }
    }
    while((rsp != 0x00) && (s8RetryCnt-- > 0));
	
    if (s8RetryCnt < 0)
    {
        M2M_ERR("[spi_cmd_rsp]: Failed cmd response read\n");
        return N_FAIL;
    }
	
    return N_OK;
}

static void spi_reset(void)
{
    nm_sleep(1);
    spi_cmd(CMD_RESET, 0, 0, 0, 0);
    spi_cmd_rsp(CMD_RESET);
    nm_sleep(1);
}

/********************************************
 
 Spi Internal Read/Write Function
 
 ********************************************/

static int8_t spi_data_read(uint8_t *b, uint16_t sz,uint8_t clockless)
{
    int16_t retry, ix, nbytes;
    int8_t result = N_OK;
    uint8_t crc[2];
    uint8_t rsp;
	
    /**
	 Data
	 **/
    ix = 0;
    do {
        if (sz <= DATA_PKT_SZ)
            nbytes = sz;
        else
            nbytes = DATA_PKT_SZ;
		
        /**
		 Data Response header
		 **/
        retry = SPI_RESP_RETRY_COUNT;
        do
        {
            if (N_OK != spi_read(&rsp, 1))
            {
                M2M_ERR("[spi_data_read]: Failed data response read, bus error...\r\n");
                result = N_FAIL;
                break;
            }
            if ((rsp & 0xf0) == 0xf0)
                break;
        }
        while (retry--);
		
        if (result == N_FAIL)
            break;
		
        if (retry <= 0)
        {
            M2M_ERR("[spi_data_read]: Failed data response read...(%02x)\r\n", rsp);
            result = N_FAIL;
            break;
        }
		
        /**
		 Read bytes
		 **/
        if (N_OK != spi_read(&b[ix], nbytes))
        {
            M2M_ERR("[spi_data_read]: Failed data block read, bus error...\r\n");
            result = N_FAIL;
            break;
        }
        if(!clockless)
        {
            /**
			 Read Crc
			 **/
            if (!gu8Crc_off)
            {
                if (N_OK != spi_read(crc, 2))
                {
                    M2M_ERR("[spi_data_read]: Failed data block CRC read, bus error...\r\n");
                    result = N_FAIL;
                    break;
                }
            }
        }
        ix += nbytes;
        sz -= nbytes;
		
    } while (sz);
	
    return result;
}

static int8_t spi_data_write(uint8_t *b, uint16_t sz)
{
    int16_t ix = 0;
    uint16_t nbytes;
    int8_t result = N_OK;
    uint8_t cmd, order, crc[2] = {0};
    //uint8_t rsp;
	
    /**
	 Data
	 **/
    do
    {
        if (sz <= DATA_PKT_SZ)
            nbytes = sz;
        else
            nbytes = DATA_PKT_SZ;
		
        /**
		 Write command
		 **/
        cmd = 0xf0;
        if (ix == 0)
        {
            if (sz <= DATA_PKT_SZ)
                order = 0x3;
            else
                order = 0x1;
        }
        else
        {
            if (sz <= DATA_PKT_SZ)
                order = 0x3;
            else
                order = 0x2;
        }
		
        cmd |= order;
        if (N_OK != spi_write(&cmd, 1))
        {
            M2M_ERR("[spi_data_write]: Failed data block cmd write, bus error...\r\n");
            result = N_FAIL;
            break;
        }
		
        /**
		 Write data
		 **/
        if (N_OK != spi_write(&b[ix], nbytes))
        {
            M2M_ERR("[spi_data_write]: Failed data block write, bus error...\r\n");
            result = N_FAIL;
            break;
        }
		
        /**
		 Write Crc
		 **/
        if (!gu8Crc_off)
        {
            if (N_OK != spi_write(crc, 2))
            {
                M2M_ERR("[spi_data_write]: Failed data block CRC write, bus error...\r\n");
                result = N_FAIL;
                break;
            }
        }
		
        ix += nbytes;
        sz -= nbytes;
    }
    while (sz);
	
    return result;
}

/********************************************
 
 Spi interfaces
 
 ********************************************/

static int8_t spi_write_reg(uint32_t u32Addr, uint32_t u32Val)
{
    uint8_t cmd = CMD_SINGLE_WRITE;
    uint8_t clockless = 0;
	
    if (u32Addr <= 0x30)
    {
        /**
		 NMC1000 clockless registers.
		 **/
        cmd = CMD_INTERNAL_WRITE;
        clockless = 1;
    }
	
    if (spi_cmd(cmd, u32Addr, u32Val, 4, clockless) != N_OK)
    {
        M2M_ERR("[spi_write_reg]: Failed cmd, write reg (%08" PRIx32 ")...\r\n", u32Addr);
        return N_FAIL;
    }
	
    if (spi_cmd_rsp(cmd) != N_OK)
    {
        M2M_ERR("[spi_write_reg]: Failed cmd response, write reg (%08" PRIx32 ")...\r\n", u32Addr);
        return N_FAIL;
    }
	
    return N_OK;
}

static int8_t spi_write_block(uint32_t u32Addr, uint8_t *puBuf, uint16_t u16Sz)
{
    uint8_t len;
    uint8_t rsp[3];
	
    /**
	 Command
	 **/
    if (spi_cmd(CMD_DMA_EXT_WRITE, u32Addr, 0, u16Sz, 0) != N_OK)
    {
        M2M_ERR("[spi_write_block]: Failed cmd, write block (%08" PRIx32 ")...\r\n", u32Addr);
        return N_FAIL;
    }
	
    if (spi_cmd_rsp(CMD_DMA_EXT_WRITE) != N_OK)
    {
        M2M_ERR("[spi_write_block]: Failed cmd response, write block (%08" PRIx32 ")...\r\n", u32Addr);
        return N_FAIL;
    }
	
    /**
	 Data
	 **/
    if (spi_data_write(puBuf, u16Sz) != N_OK)
    {
        M2M_ERR("[spi_write_block]: Failed block data write...\r\n");
        return N_FAIL;
    }
    /**
	 Data RESP
	 **/
    if (!gu8Crc_off)
        len = 2;
    else
        len = 3;
	
    if (N_OK != spi_read(&rsp[0], len))
    {
        M2M_ERR("[spi_write_block]: Failed bus error...\r\n");
        return N_FAIL;
    }
	
    if((rsp[len-1] != 0) || (rsp[len-2] != 0xC3))
    {
        M2M_ERR("[spi_write_block]: Failed data response read, %x %x %x\r\n", rsp[0], rsp[1], rsp[2]);
        return N_FAIL;
    }
	
    return N_OK;
}

static int8_t spi_read_reg(uint32_t u32Addr, uint32_t* pu32RetVal)
{
    uint8_t cmd = CMD_SINGLE_READ;
    uint8_t tmp[4];
    uint8_t clockless = 0;
	
    if (u32Addr <= 0xff)
    {
        /**
		 NMC1000 clockless registers.
		 **/
        cmd = CMD_INTERNAL_READ;
        clockless = 1;
    }
	
    if (spi_cmd(cmd, u32Addr, 0, 4, clockless) != N_OK)
    {
        M2M_ERR("[spi_read_reg]: Failed cmd, read reg (%08" PRIx32 ")...\r\n", u32Addr);
        return N_FAIL;
    }
	
    if (spi_cmd_rsp(cmd) != N_OK)
    {
        M2M_ERR("[spi_read_reg]: Failed cmd response, read reg (%08" PRIx32 ")...\r\n", u32Addr);
        return N_FAIL;
    }
	
    /* to avoid endianess issues */
    if (spi_data_read(&tmp[0], 4, clockless) != N_OK)
    {
        M2M_ERR("[spi_read_reg]: Failed data read...\r\n");
        return N_FAIL;
    }
	
    *pu32RetVal = ((uint32_t)tmp[0])       |
		((uint32_t)tmp[1] << 8)  |
		((uint32_t)tmp[2] << 16) |
		((uint32_t)tmp[3] << 24);
	
    return N_OK;
}

static int8_t spi_read_block(uint32_t u32Addr, uint8_t *puBuf, uint16_t u16Sz)
{
    /**
	 Command
	 **/
    if (spi_cmd(CMD_DMA_EXT_READ, u32Addr, 0, u16Sz, 0) != N_OK)
    {
        M2M_ERR("[spi_read_block]: Failed cmd, read block (%08" PRIx32 ")...\r\n", u32Addr);
        return N_FAIL;
    }
	
    if (spi_cmd_rsp(CMD_DMA_EXT_READ) != N_OK)
    {
        M2M_ERR("[spi_read_block]: Failed cmd response, read block (%08" PRIx32 ")...\r\n", u32Addr);
        return N_FAIL;
    }
	
    /**
	 Data
	 **/
    if (spi_data_read(puBuf, u16Sz, 0) != N_OK)
    {
        M2M_ERR("[spi_read_block]: Failed block data read...\r\n");
        return N_FAIL;
    }
	
    return N_OK;
}

static void spi_init_pkt_sz(void)
{
    uint32_t val32;
	
    /* Make sure SPI max. packet size fits the defined DATA_PKT_SZ.  */
    val32 = nm_spi_read_reg(SPI_BASE+0x24);
    val32 &= ~(0x7 << 4);
    switch(DATA_PKT_SZ)
    {
        case 256:  val32 |= (0 << 4); break;
        case 512:  val32 |= (1 << 4); break;
        case 1024: val32 |= (2 << 4); break;
        case 2048: val32 |= (3 << 4); break;
        case 4096: val32 |= (4 << 4); break;
        case 8192: val32 |= (5 << 4); break;
    }
    nm_spi_write_reg(SPI_BASE+0x24, val32);
}

/********************************************
 
 Bus interfaces
 
 ********************************************/

int8_t nm_spi_reset(void)
{
	//    if (OSAL_RESULT_TRUE != OSAL_MUTEX_Lock(&s_spiLock, OSAL_WAIT_FOREVER))
	//        return M2M_ERR_BUS_FAIL;
	
    spi_cmd(CMD_RESET, 0, 0, 0, 0);
    spi_cmd_rsp(CMD_RESET);
	
	//   OSAL_MUTEX_Unlock(&s_spiLock);
	
    return M2M_SUCCESS;
}

void nm_spi_lock_init(void)
{
	//    OSAL_MUTEX_Create(&s_spiLock);
}

/*
 *   @fn     nm_spi_init
 *   @brief  Initialize the SPI
 *   @return M2M_SUCCESS in case of success and M2M_ERR_BUS_FAIL in case of failure
 */
int8_t nm_spi_init(void)
{
    uint32_t chipid;
    uint32_t reg = 0;
	
	mWifiSPIBaudrate = SPICalculateBRG(PERIPHERAL_FREQ, WIFI_MODULE_SPI_BAUDRATE);
	
    /**
	 configure protocol
	 **/
    gu8Crc_off = 0;
	
    if (nm_spi_read_reg_with_ret(NMI_SPI_PROTOCOL_CONFIG, &reg) != M2M_SUCCESS)
    {
        /* Read failed. Try with CRC off. This might happen when module
		 is removed but chip isn't reset*/
        gu8Crc_off = 1;
        M2M_ERR("[nm_spi_init]: Failed internal read protocol with CRC on, retrying with CRC off...\r\n");
		
        if (nm_spi_read_reg_with_ret(NMI_SPI_PROTOCOL_CONFIG, &reg) != M2M_SUCCESS)
        {
            // Reaad failed with both CRC on and off, something went bad
            M2M_ERR("[nm_spi_init]: Failed internal read protocol...\r\n");
			
            return M2M_ERR_BUS_FAIL;
        }
    }
    if(gu8Crc_off == 0)
    {
        reg &= ~0xc;    /* disable CRC checking */
        reg &= ~0x70;
        reg |= (0x5 << 4);
		
        if (nm_spi_write_reg(NMI_SPI_PROTOCOL_CONFIG, reg) != M2M_SUCCESS)
        {
            M2M_ERR("[nm_spi_init]: Failed internal write protocol reg...\r\n");
			
            return M2M_ERR_BUS_FAIL;
        }
		
        gu8Crc_off = 1;
    }
	
    /**
	 make sure can read back chip id correctly
	 **/
    if (nm_spi_read_reg_with_ret(0x1000, &chipid) != M2M_SUCCESS)
    {
        M2M_ERR("[nm_spi_init]: Fail cmd read chip id...\r\n");
        return M2M_ERR_BUS_FAIL;
    }
	
    M2M_DBG("[nm_spi_init]: chipid (%08x)\r\n", (unsigned int)chipid);
    spi_init_pkt_sz();
	
    return M2M_SUCCESS;
}

/*
 *   @fn     nm_spi_deinit
 *   @brief  DeInitialize the SPI
 *   @return M2M_SUCCESS in case of success and M2M_ERR_BUS_FAIL in case of failure
 */
int8_t nm_spi_deinit(void)
{
    gu8Crc_off = 0;
	//    OSAL_MUTEX_Delete(&s_spiLock);
    return M2M_SUCCESS;
}

/*
 *   @fn     nm_spi_read_reg
 *   @brief  Read register
 *   @param [in] u32Addr
 *               Register address
 *   @return Register value
 */
uint32_t nm_spi_read_reg(uint32_t u32Addr)
{
    uint32_t u32Val;
	
    nm_spi_read_reg_with_ret(u32Addr, &u32Val);
	
    return u32Val;
}

/*
 *   @fn     nm_spi_read_reg_with_ret
 *   @brief  Read register with error code return
 *   @param [in] u32Addr
 *               Register address
 *   @param [out]    pu32RetVal
 *               Pointer to u32 variable used to return the read value
 *   @return M2M_SUCCESS in case of success and M2M_ERR_BUS_FAIL in case of failure
 */
int8_t nm_spi_read_reg_with_ret(uint32_t u32Addr, uint32_t* pu32RetVal)
{
    uint8_t retry = SPI_RETRY_COUNT;
	
	//    if (OSAL_RESULT_TRUE != OSAL_MUTEX_Lock(&s_spiLock, OSAL_WAIT_FOREVER))
	//        return M2M_ERR_BUS_FAIL;
	
    while(retry--)
    {
        if (spi_read_reg(u32Addr, pu32RetVal) == N_OK)
        {
			//            OSAL_MUTEX_Unlock(&s_spiLock);
			
            return M2M_SUCCESS;
        }
		
        M2M_ERR("Reset and retry %d %" PRIx32 "\r\n", retry, u32Addr);
        spi_reset();
    }
	
	//    OSAL_MUTEX_Unlock(&s_spiLock);
	
    return M2M_ERR_BUS_FAIL;
}

/*
 *   @fn     nm_spi_write_reg
 *   @brief  write register
 *   @param [in] u32Addr
 *               Register address
 *   @param [in] u32Val
 *               Value to be written to the register
 *   @return M2M_SUCCESS in case of success and M2M_ERR_BUS_FAIL in case of failure
 */
int8_t nm_spi_write_reg(uint32_t u32Addr, uint32_t u32Val)
{
    uint8_t retry = SPI_RETRY_COUNT;
	
	//    if (OSAL_RESULT_TRUE != OSAL_MUTEX_Lock(&s_spiLock, OSAL_WAIT_FOREVER))
	//       return M2M_ERR_BUS_FAIL;
	
    while(retry--)
    {
        if (spi_write_reg(u32Addr, u32Val) == N_OK)
        {
			//            OSAL_MUTEX_Unlock(&s_spiLock);
			
            return M2M_SUCCESS;
        }
		
        M2M_ERR("Reset and retry %d %" PRIx32 " %" PRIx32 "\r\n", retry, u32Addr, u32Val);
        spi_reset();
    }
	
	//    OSAL_MUTEX_Unlock(&s_spiLock);
	
    return M2M_ERR_BUS_FAIL;
}

/*
 *   @fn     nm_spi_read_block
 *   @brief  Read block of data
 *   @param [in] u32Addr
 *               Start address
 *   @param [out]    puBuf
 *               Pointer to a buffer used to return the read data
 *   @param [in] u16Sz
 *               Number of bytes to read. The buffer size must be >= u16Sz
 *   @return M2M_SUCCESS in case of success and M2M_ERR_BUS_FAIL in case of failure
 */
int8_t nm_spi_read_block(uint32_t u32Addr, uint8_t *puBuf, uint16_t u16Sz)
{
    uint8_t retry = SPI_RETRY_COUNT;
    uint8_t tmpBuf[2] = {0,0};
    uint8_t *puTmpBuf;
	
	//    if (OSAL_RESULT_TRUE != OSAL_MUTEX_Lock(&s_spiLock, OSAL_WAIT_FOREVER))
	//       return M2M_ERR_BUS_FAIL;
	
    if (u16Sz == 1)
    {
        u16Sz = 2;
        puTmpBuf = tmpBuf;
    }
    else
    {
        puTmpBuf = puBuf;
    }
	
    while(retry--)
    {
        if (spi_read_block(u32Addr, puTmpBuf, u16Sz) == N_OK)
        {
			//            OSAL_MUTEX_Unlock(&s_spiLock);
			
            if (puTmpBuf == tmpBuf)
                *puBuf = *tmpBuf;
			
            return M2M_SUCCESS;
        }
		
        M2M_ERR("Reset and retry %d %" PRIx32 " %d\r\n", retry, u32Addr, u16Sz);
        spi_reset();
    }
	
	//    OSAL_MUTEX_Unlock(&s_spiLock);
	
    return M2M_ERR_BUS_FAIL;
}

/*
 *   @fn     nm_spi_write_block
 *   @brief  Write block of data
 *   @param [in] u32Addr
 *               Start address
 *   @param [in] puBuf
 *               Pointer to the buffer holding the data to be written
 *   @param [in] u16Sz
 *               Number of bytes to write. The buffer size must be >= u16Sz
 *   @return M2M_SUCCESS in case of success and M2M_ERR_BUS_FAIL in case of failure
 */
int8_t nm_spi_write_block(uint32_t u32Addr, uint8_t *puBuf, uint16_t u16Sz)
{
    uint8_t retry = SPI_RETRY_COUNT;
	
	//    if (OSAL_RESULT_TRUE != OSAL_MUTEX_Lock(&s_spiLock, OSAL_WAIT_FOREVER))
	//        return M2M_ERR_BUS_FAIL;
	
    //Workaround hardware problem with single byte transfers over SPI bus
    if (u16Sz == 1)
        u16Sz = 2;
	
    while(retry--)
    {
        if (spi_write_block(u32Addr, puBuf, u16Sz) == N_OK)
        {
			//            OSAL_MUTEX_Unlock(&s_spiLock);
			
            return M2M_SUCCESS;
        }
		
        M2M_ERR("Reset and retry %d %" PRIx32 " %d\r\n", retry, u32Addr, u16Sz);
        spi_reset();
    }
	
	//    OSAL_MUTEX_Unlock(&s_spiLock);
	
    return M2M_ERR_BUS_FAIL;
}

//DOM-IGNORE-END
