1358 lines
30 KiB
C
1358 lines
30 KiB
C
/**
|
|
*
|
|
* \file
|
|
*
|
|
* \brief This module contains NMC1000 SPI protocol bus APIs implementation.
|
|
*
|
|
* Copyright (c) 2015 - 2017 Atmel Corporation. All rights reserved.
|
|
*
|
|
* \asf_license_start
|
|
*
|
|
* \page License
|
|
*
|
|
* Redistribution and use in source and binary forms, with or without
|
|
* modification, are permitted provided that the following conditions are met:
|
|
*
|
|
* 1. Redistributions of source code must retain the above copyright notice,
|
|
* this list of conditions and the following disclaimer.
|
|
*
|
|
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
|
* this list of conditions and the following disclaimer in the documentation
|
|
* and/or other materials provided with the distribution.
|
|
*
|
|
* 3. The name of Atmel may not be used to endorse or promote products derived
|
|
* from this software without specific prior written permission.
|
|
*
|
|
* THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR IMPLIED
|
|
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
|
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE
|
|
* EXPRESSLY AND SPECIFICALLY DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR
|
|
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
|
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
|
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
|
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
|
|
* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
|
|
* ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
|
* POSSIBILITY OF SUCH DAMAGE.
|
|
*
|
|
* \asf_license_stop
|
|
*
|
|
*/
|
|
#include "common/include/nm_common.h"
|
|
|
|
#ifdef CONF_WINC_USE_SPI
|
|
|
|
#define USE_OLD_SPI_SW
|
|
|
|
#include "bus_wrapper/include/nm_bus_wrapper.h"
|
|
#include "nmspi.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 1
|
|
#define N_FAIL 0
|
|
#define N_RESET -1
|
|
#define N_RETRY -2
|
|
|
|
#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 gu8Crc_off = 0;
|
|
|
|
static sint8 nmi_spi_read(uint8 *b, uint16 sz)
|
|
{
|
|
tstrNmSpiRw spi;
|
|
spi.pu8InBuf = NULL;
|
|
spi.pu8OutBuf = b;
|
|
spi.u16Sz = sz;
|
|
return nm_bus_ioctl(NM_BUS_IOCTL_RW, &spi);
|
|
}
|
|
|
|
static sint8 nmi_spi_write(uint8 *b, uint16 sz)
|
|
{
|
|
tstrNmSpiRw spi;
|
|
spi.pu8InBuf = b;
|
|
spi.pu8OutBuf = NULL;
|
|
spi.u16Sz = sz;
|
|
return nm_bus_ioctl(NM_BUS_IOCTL_RW, &spi);
|
|
}
|
|
#ifndef USE_OLD_SPI_SW
|
|
static sint8 nmi_spi_rw(uint8 *bin, uint8 *bout, uint16 sz)
|
|
{
|
|
tstrNmSpiRw spi;
|
|
spi.pu8InBuf = bin;
|
|
spi.pu8OutBuf = bout;
|
|
spi.u16Sz = sz;
|
|
return nm_bus_ioctl(NM_BUS_IOCTL_RW, &spi);
|
|
}
|
|
#endif
|
|
/********************************************
|
|
|
|
Crc7
|
|
|
|
********************************************/
|
|
|
|
static const uint8 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 crc7_byte(uint8 crc, uint8 data)
|
|
{
|
|
return crc7_syndrome_table[(crc << 1) ^ data];
|
|
}
|
|
|
|
static uint8 crc7(uint8 crc, const uint8 *buffer, uint32 len)
|
|
{
|
|
while (len--)
|
|
crc = crc7_byte(crc, *buffer++);
|
|
return crc;
|
|
}
|
|
|
|
/********************************************
|
|
|
|
Spi protocol Function
|
|
|
|
********************************************/
|
|
|
|
#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 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 sint8 spi_cmd(uint8 cmd, uint32 adr, uint32 u32data, uint32 sz, uint8 clockless)
|
|
{
|
|
uint8 bc[9];
|
|
uint8 len = 5;
|
|
sint8 result = N_OK;
|
|
|
|
bc[0] = cmd;
|
|
switch (cmd) {
|
|
case CMD_SINGLE_READ: /* single word (4 bytes) read */
|
|
bc[1] = (uint8)(adr >> 16);
|
|
bc[2] = (uint8)(adr >> 8);
|
|
bc[3] = (uint8)adr;
|
|
len = 5;
|
|
break;
|
|
case CMD_INTERNAL_READ: /* internal register read */
|
|
bc[1] = (uint8)(adr >> 8);
|
|
if (clockless)
|
|
bc[1] |= (1 << 7);
|
|
bc[2] = (uint8)adr;
|
|
bc[3] = 0x00;
|
|
len = 5;
|
|
break;
|
|
case CMD_TERMINATE: /* termination */
|
|
bc[1] = 0x00;
|
|
bc[2] = 0x00;
|
|
bc[3] = 0x00;
|
|
len = 5;
|
|
break;
|
|
case CMD_REPEAT: /* repeat */
|
|
bc[1] = 0x00;
|
|
bc[2] = 0x00;
|
|
bc[3] = 0x00;
|
|
len = 5;
|
|
break;
|
|
case CMD_RESET: /* reset */
|
|
bc[1] = 0xff;
|
|
bc[2] = 0xff;
|
|
bc[3] = 0xff;
|
|
len = 5;
|
|
break;
|
|
case CMD_DMA_WRITE: /* dma write */
|
|
case CMD_DMA_READ: /* dma read */
|
|
bc[1] = (uint8)(adr >> 16);
|
|
bc[2] = (uint8)(adr >> 8);
|
|
bc[3] = (uint8)adr;
|
|
bc[4] = (uint8)(sz >> 8);
|
|
bc[5] = (uint8)(sz);
|
|
len = 7;
|
|
break;
|
|
case CMD_DMA_EXT_WRITE: /* dma extended write */
|
|
case CMD_DMA_EXT_READ: /* dma extended read */
|
|
bc[1] = (uint8)(adr >> 16);
|
|
bc[2] = (uint8)(adr >> 8);
|
|
bc[3] = (uint8)adr;
|
|
bc[4] = (uint8)(sz >> 16);
|
|
bc[5] = (uint8)(sz >> 8);
|
|
bc[6] = (uint8)(sz);
|
|
len = 8;
|
|
break;
|
|
case CMD_INTERNAL_WRITE: /* internal register write */
|
|
bc[1] = (uint8)(adr >> 8);
|
|
if (clockless)
|
|
bc[1] |= (1 << 7);
|
|
bc[2] = (uint8)(adr);
|
|
bc[3] = (uint8)(u32data >> 24);
|
|
bc[4] = (uint8)(u32data >> 16);
|
|
bc[5] = (uint8)(u32data >> 8);
|
|
bc[6] = (uint8)(u32data);
|
|
len = 8;
|
|
break;
|
|
case CMD_SINGLE_WRITE: /* single word write */
|
|
bc[1] = (uint8)(adr >> 16);
|
|
bc[2] = (uint8)(adr >> 8);
|
|
bc[3] = (uint8)(adr);
|
|
bc[4] = (uint8)(u32data >> 24);
|
|
bc[5] = (uint8)(u32data >> 16);
|
|
bc[6] = (uint8)(u32data >> 8);
|
|
bc[7] = (uint8)(u32data);
|
|
len = 9;
|
|
break;
|
|
default:
|
|
result = N_FAIL;
|
|
break;
|
|
}
|
|
|
|
if (result) {
|
|
if (!gu8Crc_off)
|
|
bc[len - 1] = (crc7(0x7f, (const uint8 *)&bc[0], len - 1)) << 1;
|
|
else
|
|
len -= 1;
|
|
|
|
if (M2M_SUCCESS != nmi_spi_write(bc, len)) {
|
|
M2M_ERR("[nmi spi]: Failed cmd write, bus error...\n");
|
|
result = N_FAIL;
|
|
}
|
|
}
|
|
|
|
return result;
|
|
}
|
|
|
|
static sint8 spi_data_rsp(uint8 cmd)
|
|
{
|
|
uint8 len;
|
|
uint8 rsp[3];
|
|
sint8 result = N_OK;
|
|
|
|
if (!gu8Crc_off)
|
|
len = 2;
|
|
else
|
|
len = 3;
|
|
|
|
if (M2M_SUCCESS != nmi_spi_read(&rsp[0], len)) {
|
|
M2M_ERR("[nmi spi]: Failed bus error...\n");
|
|
result = N_FAIL;
|
|
goto _fail_;
|
|
}
|
|
|
|
if ((rsp[len - 1] != 0) || (rsp[len - 2] != 0xC3)) {
|
|
M2M_ERR("[nmi spi]: Failed data response read, %x %x %x\n", rsp[0], rsp[1], rsp[2]);
|
|
result = N_FAIL;
|
|
goto _fail_;
|
|
}
|
|
_fail_:
|
|
|
|
return result;
|
|
}
|
|
|
|
static sint8 spi_cmd_rsp(uint8 cmd)
|
|
{
|
|
uint8 rsp;
|
|
sint8 result = N_OK;
|
|
sint8 s8RetryCnt;
|
|
|
|
/**
|
|
Command/Control response
|
|
**/
|
|
if ((cmd == CMD_RESET) || (cmd == CMD_TERMINATE) || (cmd == CMD_REPEAT)) {
|
|
if (M2M_SUCCESS != nmi_spi_read(&rsp, 1)) {
|
|
result = N_FAIL;
|
|
goto _fail_;
|
|
}
|
|
}
|
|
|
|
/* wait for response */
|
|
s8RetryCnt = SPI_RESP_RETRY_COUNT;
|
|
do {
|
|
if (M2M_SUCCESS != nmi_spi_read(&rsp, 1)) {
|
|
M2M_ERR("[nmi spi]: Failed cmd response read, bus error...\n");
|
|
result = N_FAIL;
|
|
goto _fail_;
|
|
}
|
|
} while ((rsp != cmd) && (s8RetryCnt-- > 0));
|
|
|
|
/**
|
|
State response
|
|
**/
|
|
/* wait for response */
|
|
s8RetryCnt = SPI_RESP_RETRY_COUNT;
|
|
do {
|
|
if (M2M_SUCCESS != nmi_spi_read(&rsp, 1)) {
|
|
M2M_ERR("[nmi spi]: Failed cmd response read, bus error...\n");
|
|
result = N_FAIL;
|
|
goto _fail_;
|
|
}
|
|
} while ((rsp != 0x00) && (s8RetryCnt-- > 0));
|
|
|
|
_fail_:
|
|
|
|
return result;
|
|
}
|
|
#ifndef USE_OLD_SPI_SW
|
|
static int spi_cmd_complete(uint8_t cmd, uint32_t adr, uint8_t *b, uint32_t sz, uint8_t clockless)
|
|
{
|
|
uint8_t wb[32], rb[32];
|
|
uint8_t wix, rix;
|
|
uint32_t len2;
|
|
uint8_t rsp;
|
|
int len = 0;
|
|
int result = N_OK;
|
|
|
|
wb[0] = cmd;
|
|
switch (cmd) {
|
|
case CMD_SINGLE_READ: /* single word (4 bytes) read */
|
|
wb[1] = (uint8_t)(adr >> 16);
|
|
wb[2] = (uint8_t)(adr >> 8);
|
|
wb[3] = (uint8_t)adr;
|
|
len = 5;
|
|
break;
|
|
case CMD_INTERNAL_READ: /* internal register read */
|
|
wb[1] = (uint8_t)(adr >> 8);
|
|
if (clockless == 1)
|
|
wb[1] |= (1 << 7);
|
|
wb[2] = (uint8_t)adr;
|
|
wb[3] = 0x00;
|
|
len = 5;
|
|
break;
|
|
case CMD_TERMINATE: /* termination */
|
|
wb[1] = 0x00;
|
|
wb[2] = 0x00;
|
|
wb[3] = 0x00;
|
|
len = 5;
|
|
break;
|
|
case CMD_REPEAT: /* repeat */
|
|
wb[1] = 0x00;
|
|
wb[2] = 0x00;
|
|
wb[3] = 0x00;
|
|
len = 5;
|
|
break;
|
|
case CMD_RESET: /* reset */
|
|
wb[1] = 0xff;
|
|
wb[2] = 0xff;
|
|
wb[3] = 0xff;
|
|
len = 5;
|
|
break;
|
|
case CMD_DMA_WRITE: /* dma write */
|
|
case CMD_DMA_READ: /* dma read */
|
|
wb[1] = (uint8_t)(adr >> 16);
|
|
wb[2] = (uint8_t)(adr >> 8);
|
|
wb[3] = (uint8_t)adr;
|
|
wb[4] = (uint8_t)(sz >> 8);
|
|
wb[5] = (uint8_t)(sz);
|
|
len = 7;
|
|
break;
|
|
case CMD_DMA_EXT_WRITE: /* dma extended write */
|
|
case CMD_DMA_EXT_READ: /* dma extended read */
|
|
wb[1] = (uint8_t)(adr >> 16);
|
|
wb[2] = (uint8_t)(adr >> 8);
|
|
wb[3] = (uint8_t)adr;
|
|
wb[4] = (uint8_t)(sz >> 16);
|
|
wb[5] = (uint8_t)(sz >> 8);
|
|
wb[6] = (uint8_t)(sz);
|
|
len = 8;
|
|
break;
|
|
case CMD_INTERNAL_WRITE: /* internal register write */
|
|
wb[1] = (uint8_t)(adr >> 8);
|
|
if (clockless == 1)
|
|
wb[1] |= (1 << 7);
|
|
wb[2] = (uint8_t)(adr);
|
|
wb[3] = b[3];
|
|
wb[4] = b[2];
|
|
wb[5] = b[1];
|
|
wb[6] = b[0];
|
|
len = 8;
|
|
break;
|
|
case CMD_SINGLE_WRITE: /* single word write */
|
|
wb[1] = (uint8_t)(adr >> 16);
|
|
wb[2] = (uint8_t)(adr >> 8);
|
|
wb[3] = (uint8_t)(adr);
|
|
wb[4] = b[3];
|
|
wb[5] = b[2];
|
|
wb[6] = b[1];
|
|
wb[7] = b[0];
|
|
len = 9;
|
|
break;
|
|
default:
|
|
result = N_FAIL;
|
|
break;
|
|
}
|
|
|
|
if (result != N_OK) {
|
|
return result;
|
|
}
|
|
|
|
if (!gu8Crc_off) {
|
|
wb[len - 1] = (crc7(0x7f, (const uint8_t *)&wb[0], len - 1)) << 1;
|
|
} else {
|
|
len -= 1;
|
|
}
|
|
|
|
#define NUM_SKIP_BYTES (1)
|
|
#define NUM_RSP_BYTES (2)
|
|
#define NUM_DATA_HDR_BYTES (1)
|
|
#define NUM_DATA_BYTES (4)
|
|
#define NUM_CRC_BYTES (2)
|
|
#define NUM_DUMMY_BYTES (3)
|
|
|
|
if ((cmd == CMD_RESET) || (cmd == CMD_TERMINATE) || (cmd == CMD_REPEAT)) {
|
|
len2 = len + (NUM_SKIP_BYTES + NUM_RSP_BYTES + NUM_DUMMY_BYTES);
|
|
} else if ((cmd == CMD_INTERNAL_READ) || (cmd == CMD_SINGLE_READ)) {
|
|
if (!gu8Crc_off) {
|
|
len2 = len + (NUM_RSP_BYTES + NUM_DATA_HDR_BYTES + NUM_DATA_BYTES + NUM_CRC_BYTES + NUM_DUMMY_BYTES);
|
|
} else {
|
|
len2 = len + (NUM_RSP_BYTES + NUM_DATA_HDR_BYTES + NUM_DATA_BYTES + NUM_DUMMY_BYTES);
|
|
}
|
|
} else {
|
|
len2 = len + (NUM_RSP_BYTES + NUM_DUMMY_BYTES);
|
|
}
|
|
#undef NUM_DUMMY_BYTES
|
|
|
|
if (len2 > (sizeof(wb) / sizeof(wb[0]))) {
|
|
M2M_ERR("[nmi spi]: spi buffer size too small (%d) (%d)\n", len2, (sizeof(wb) / sizeof(wb[0])));
|
|
result = N_FAIL;
|
|
return result;
|
|
}
|
|
/* zero spi write buffers. */
|
|
for (wix = len; wix < len2; wix++) {
|
|
wb[wix] = 0;
|
|
}
|
|
rix = len;
|
|
|
|
if (nmi_spi_rw(wb, rb, len2) != M2M_SUCCESS) {
|
|
M2M_ERR("[nmi spi]: Failed cmd write, bus error...\n");
|
|
result = N_FAIL;
|
|
return result;
|
|
}
|
|
|
|
#if 0
|
|
{
|
|
int jj;
|
|
printk("--- cnd = %x, len=%d, len2=%d\n", cmd, len, len2);
|
|
for(jj=0; jj<sizeof(wb)/sizeof(wb[0]); jj++) {
|
|
|
|
if(jj >= len2) break;
|
|
if(((jj+1)%16) != 0) {
|
|
if((jj%16) == 0) {
|
|
printk("wb[%02x]: %02x ", jj, wb[jj]);
|
|
} else {
|
|
printk("%02x ", wb[jj]);
|
|
}
|
|
} else {
|
|
printk("%02x\n", wb[jj]);
|
|
}
|
|
}
|
|
printk("\n");
|
|
|
|
for(jj=0; jj<sizeof(rb)/sizeof(rb[0]); jj++) {
|
|
|
|
if(jj >= len2) break;
|
|
if(((jj+1)%16) != 0) {
|
|
if((jj%16) == 0) {
|
|
printk("rb[%02x]: %02x ", jj, rb[jj]);
|
|
} else {
|
|
printk("%02x ", rb[jj]);
|
|
}
|
|
} else {
|
|
printk("%02x\n", rb[jj]);
|
|
}
|
|
}
|
|
printk("\n");
|
|
}
|
|
#endif
|
|
|
|
/**
|
|
Command/Control response
|
|
**/
|
|
if ((cmd == CMD_RESET) || (cmd == CMD_TERMINATE) || (cmd == CMD_REPEAT)) {
|
|
rix++; /* skip 1 byte */
|
|
}
|
|
|
|
rsp = rb[rix++];
|
|
|
|
if (rsp != cmd) {
|
|
M2M_ERR("[nmi spi]: Failed cmd response, cmd (%02x), resp (%02x)\n", cmd, rsp);
|
|
result = N_FAIL;
|
|
return result;
|
|
}
|
|
|
|
/**
|
|
State response
|
|
**/
|
|
rsp = rb[rix++];
|
|
if (rsp != 0x00) {
|
|
M2M_ERR("[nmi spi]: Failed cmd state response state (%02x)\n", rsp);
|
|
result = N_FAIL;
|
|
return result;
|
|
}
|
|
|
|
if ((cmd == CMD_INTERNAL_READ) || (cmd == CMD_SINGLE_READ) || (cmd == CMD_DMA_READ) || (cmd == CMD_DMA_EXT_READ)) {
|
|
int retry;
|
|
// uint16_t crc1, crc2;
|
|
uint8_t crc[2];
|
|
/**
|
|
Data Respnose header
|
|
**/
|
|
retry = SPI_RESP_RETRY_COUNT;
|
|
do {
|
|
/* ensure there is room in buffer later to read data and crc */
|
|
if (rix < len2) {
|
|
rsp = rb[rix++];
|
|
} else {
|
|
retry = 0;
|
|
break;
|
|
}
|
|
if (((rsp >> 4) & 0xf) == 0xf)
|
|
break;
|
|
} while (retry--);
|
|
|
|
if (retry <= 0) {
|
|
M2M_ERR("[nmi spi]: Error, data read response (%02x)\n", rsp);
|
|
result = N_RESET;
|
|
return result;
|
|
}
|
|
|
|
if ((cmd == CMD_INTERNAL_READ) || (cmd == CMD_SINGLE_READ)) {
|
|
/**
|
|
Read bytes
|
|
**/
|
|
if ((rix + 3) < len2) {
|
|
b[0] = rb[rix++];
|
|
b[1] = rb[rix++];
|
|
b[2] = rb[rix++];
|
|
b[3] = rb[rix++];
|
|
} else {
|
|
M2M_ERR("[nmi spi]: buffer overrun when reading data.\n");
|
|
result = N_FAIL;
|
|
return result;
|
|
}
|
|
|
|
if (!gu8Crc_off) {
|
|
/**
|
|
Read Crc
|
|
**/
|
|
if ((rix + 1) < len2) {
|
|
crc[0] = rb[rix++];
|
|
crc[1] = rb[rix++];
|
|
} else {
|
|
M2M_ERR("[nmi spi]: buffer overrun when reading crc.\n");
|
|
result = N_FAIL;
|
|
return result;
|
|
}
|
|
}
|
|
} else if ((cmd == CMD_DMA_READ) || (cmd == CMD_DMA_EXT_READ)) {
|
|
int ix;
|
|
|
|
/* some data may be read in response to dummy bytes. */
|
|
for (ix = 0; (rix < len2) && (ix < sz);) {
|
|
b[ix++] = rb[rix++];
|
|
}
|
|
#if 0
|
|
if(ix) M2M_INFO("ttt %d %d\n", sz, ix);
|
|
#endif
|
|
sz -= ix;
|
|
|
|
if (sz > 0) {
|
|
int nbytes;
|
|
|
|
if (sz <= (DATA_PKT_SZ - ix)) {
|
|
nbytes = sz;
|
|
} else {
|
|
nbytes = DATA_PKT_SZ - ix;
|
|
}
|
|
|
|
/**
|
|
Read bytes
|
|
**/
|
|
if (nmi_spi_read(&b[ix], nbytes) != M2M_SUCCESS) {
|
|
M2M_ERR("[nmi spi]: Failed data block read, bus error...\n");
|
|
result = N_FAIL;
|
|
goto _error_;
|
|
}
|
|
|
|
/**
|
|
Read Crc
|
|
**/
|
|
if (!gu8Crc_off) {
|
|
if (nmi_spi_read(crc, 2) != M2M_SUCCESS) {
|
|
M2M_ERR("[nmi spi]: Failed data block crc read, bus error...\n");
|
|
result = N_FAIL;
|
|
goto _error_;
|
|
}
|
|
}
|
|
|
|
ix += nbytes;
|
|
sz -= nbytes;
|
|
}
|
|
|
|
/* if any data in left unread, then read the rest using normal DMA code.*/
|
|
while (sz > 0) {
|
|
int nbytes;
|
|
|
|
if (sz <= DATA_PKT_SZ) {
|
|
nbytes = sz;
|
|
} else {
|
|
nbytes = DATA_PKT_SZ;
|
|
}
|
|
|
|
/**
|
|
read data response only on the next DMA cycles not
|
|
the first DMA since data response header is already
|
|
handled above for the first DMA.
|
|
**/
|
|
/**
|
|
Data Respnose header
|
|
**/
|
|
retry = SPI_RESP_RETRY_COUNT;
|
|
do {
|
|
if (nmi_spi_read(&rsp, 1) != M2M_SUCCESS) {
|
|
M2M_ERR("[nmi spi]: Failed data response read, bus error...\n");
|
|
result = N_FAIL;
|
|
break;
|
|
}
|
|
if (((rsp >> 4) & 0xf) == 0xf)
|
|
break;
|
|
} while (retry--);
|
|
|
|
if (result == N_FAIL)
|
|
break;
|
|
|
|
/**
|
|
Read bytes
|
|
**/
|
|
if (nmi_spi_read(&b[ix], nbytes) != M2M_SUCCESS) {
|
|
M2M_ERR("[nmi spi]: Failed data block read, bus error...\n");
|
|
result = N_FAIL;
|
|
break;
|
|
}
|
|
|
|
/**
|
|
Read Crc
|
|
**/
|
|
if (!gu8Crc_off) {
|
|
if (nmi_spi_read(crc, 2) != M2M_SUCCESS) {
|
|
M2M_ERR("[nmi spi]: Failed data block crc read, bus error...\n");
|
|
result = N_FAIL;
|
|
break;
|
|
}
|
|
}
|
|
|
|
ix += nbytes;
|
|
sz -= nbytes;
|
|
}
|
|
}
|
|
}
|
|
_error_:
|
|
return result;
|
|
}
|
|
#endif
|
|
static sint8 spi_data_read(uint8 *b, uint16 sz, uint8 clockless)
|
|
{
|
|
sint16 retry, ix, nbytes;
|
|
sint8 result = N_OK;
|
|
uint8 crc[2];
|
|
uint8 rsp;
|
|
|
|
/**
|
|
Data
|
|
**/
|
|
ix = 0;
|
|
do {
|
|
if (sz <= DATA_PKT_SZ)
|
|
nbytes = sz;
|
|
else
|
|
nbytes = DATA_PKT_SZ;
|
|
|
|
/**
|
|
Data Respnose header
|
|
**/
|
|
retry = SPI_RESP_RETRY_COUNT;
|
|
do {
|
|
if (M2M_SUCCESS != nmi_spi_read(&rsp, 1)) {
|
|
M2M_ERR("[nmi spi]: Failed data response read, bus error...\n");
|
|
result = N_FAIL;
|
|
break;
|
|
}
|
|
if (((rsp >> 4) & 0xf) == 0xf)
|
|
break;
|
|
} while (retry--);
|
|
|
|
if (result == N_FAIL)
|
|
break;
|
|
|
|
if (retry <= 0) {
|
|
M2M_ERR("[nmi spi]: Failed data response read...(%02x)\n", rsp);
|
|
result = N_FAIL;
|
|
break;
|
|
}
|
|
|
|
/**
|
|
Read bytes
|
|
**/
|
|
if (M2M_SUCCESS != nmi_spi_read(&b[ix], nbytes)) {
|
|
M2M_ERR("[nmi spi]: Failed data block read, bus error...\n");
|
|
result = N_FAIL;
|
|
break;
|
|
}
|
|
if (!clockless) {
|
|
/**
|
|
Read Crc
|
|
**/
|
|
if (!gu8Crc_off) {
|
|
if (M2M_SUCCESS != nmi_spi_read(crc, 2)) {
|
|
M2M_ERR("[nmi spi]: Failed data block crc read, bus error...\n");
|
|
result = N_FAIL;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
ix += nbytes;
|
|
sz -= nbytes;
|
|
|
|
} while (sz);
|
|
|
|
return result;
|
|
}
|
|
|
|
static sint8 spi_data_write(uint8 *b, uint16 sz)
|
|
{
|
|
sint16 ix;
|
|
uint16 nbytes;
|
|
sint8 result = 1;
|
|
uint8 cmd, order, crc[2] = {0};
|
|
// uint8 rsp;
|
|
|
|
/**
|
|
Data
|
|
**/
|
|
ix = 0;
|
|
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 (M2M_SUCCESS != nmi_spi_write(&cmd, 1)) {
|
|
M2M_ERR("[nmi spi]: Failed data block cmd write, bus error...\n");
|
|
result = N_FAIL;
|
|
break;
|
|
}
|
|
|
|
/**
|
|
Write data
|
|
**/
|
|
if (M2M_SUCCESS != nmi_spi_write(&b[ix], nbytes)) {
|
|
M2M_ERR("[nmi spi]: Failed data block write, bus error...\n");
|
|
result = N_FAIL;
|
|
break;
|
|
}
|
|
|
|
/**
|
|
Write Crc
|
|
**/
|
|
if (!gu8Crc_off) {
|
|
if (M2M_SUCCESS != nmi_spi_write(crc, 2)) {
|
|
M2M_ERR("[nmi spi]: Failed data block crc write, bus error...\n");
|
|
result = N_FAIL;
|
|
break;
|
|
}
|
|
}
|
|
|
|
ix += nbytes;
|
|
sz -= nbytes;
|
|
} while (sz);
|
|
|
|
return result;
|
|
}
|
|
|
|
/********************************************
|
|
|
|
Spi Internal Read/Write Function
|
|
|
|
********************************************/
|
|
|
|
/********************************************
|
|
|
|
Spi interfaces
|
|
|
|
********************************************/
|
|
|
|
static sint8 spi_write_reg(uint32 addr, uint32 u32data)
|
|
{
|
|
uint8 retry = SPI_RETRY_COUNT;
|
|
sint8 result = N_OK;
|
|
uint8 cmd = CMD_SINGLE_WRITE;
|
|
uint8 clockless = 0;
|
|
|
|
_RETRY_:
|
|
if (addr <= 0x30) {
|
|
/**
|
|
NMC1000 clockless registers.
|
|
**/
|
|
cmd = CMD_INTERNAL_WRITE;
|
|
clockless = 1;
|
|
} else {
|
|
cmd = CMD_SINGLE_WRITE;
|
|
clockless = 0;
|
|
}
|
|
|
|
#if defined USE_OLD_SPI_SW
|
|
result = spi_cmd(cmd, addr, u32data, 4, clockless);
|
|
if (result != N_OK) {
|
|
M2M_ERR("[nmi spi]: Failed cmd, write reg (%08x)...\n", (unsigned int)addr);
|
|
goto _FAIL_;
|
|
}
|
|
|
|
result = spi_cmd_rsp(cmd);
|
|
if (result != N_OK) {
|
|
M2M_ERR("[nmi spi]: Failed cmd response, write reg (%08x)...\n", (unsigned int)addr);
|
|
goto _FAIL_;
|
|
}
|
|
|
|
#else
|
|
|
|
result = spi_cmd_complete(cmd, addr, (uint8 *)&u32data, 4, clockless);
|
|
if (result != N_OK) {
|
|
M2M_ERR("[nmi spi]: Failed cmd, write reg (%08x)...\n", addr);
|
|
goto _FAIL_;
|
|
}
|
|
|
|
#endif
|
|
_FAIL_:
|
|
if (result != N_OK) {
|
|
nm_bsp_sleep(1);
|
|
spi_cmd(CMD_RESET, 0, 0, 0, 0);
|
|
spi_cmd_rsp(CMD_RESET);
|
|
M2M_ERR("Reset and retry %d %x %x\n", retry, addr, u32data);
|
|
nm_bsp_sleep(1);
|
|
retry--;
|
|
if (retry)
|
|
goto _RETRY_;
|
|
}
|
|
|
|
return result;
|
|
}
|
|
|
|
static sint8 nm_spi_write(uint32 addr, uint8 *buf, uint16 size)
|
|
{
|
|
sint8 result;
|
|
uint8 retry = SPI_RETRY_COUNT;
|
|
uint8 cmd = CMD_DMA_EXT_WRITE;
|
|
|
|
_RETRY_:
|
|
/**
|
|
Command
|
|
**/
|
|
#if defined USE_OLD_SPI_SW
|
|
// Workaround hardware problem with single byte transfers over SPI bus
|
|
if (size == 1)
|
|
size = 2;
|
|
|
|
result = spi_cmd(cmd, addr, 0, size, 0);
|
|
if (result != N_OK) {
|
|
M2M_ERR("[nmi spi]: Failed cmd, write block (%08x)...\n", (unsigned int)addr);
|
|
goto _FAIL_;
|
|
}
|
|
|
|
result = spi_cmd_rsp(cmd);
|
|
if (result != N_OK) {
|
|
M2M_ERR("[nmi spi ]: Failed cmd response, write block (%08x)...\n", (unsigned int)addr);
|
|
goto _FAIL_;
|
|
}
|
|
#else
|
|
result = spi_cmd_complete(cmd, addr, NULL, size, 0);
|
|
if (result != N_OK) {
|
|
M2M_ERR("[nmi spi]: Failed cmd, write block (%08x)...\n", addr);
|
|
goto _FAIL_;
|
|
}
|
|
#endif
|
|
|
|
/**
|
|
Data
|
|
**/
|
|
result = spi_data_write(buf, size);
|
|
if (result != N_OK) {
|
|
M2M_ERR("[nmi spi]: Failed block data write...\n");
|
|
goto _FAIL_;
|
|
}
|
|
/**
|
|
Data RESP
|
|
**/
|
|
result = spi_data_rsp(cmd);
|
|
if (result != N_OK) {
|
|
M2M_ERR("[nmi spi]: Failed block data write...\n");
|
|
goto _FAIL_;
|
|
}
|
|
|
|
_FAIL_:
|
|
if (result != N_OK) {
|
|
nm_bsp_sleep(1);
|
|
spi_cmd(CMD_RESET, 0, 0, 0, 0);
|
|
spi_cmd_rsp(CMD_RESET);
|
|
M2M_ERR("Reset and retry %d %x %d\n", retry, addr, size);
|
|
nm_bsp_sleep(1);
|
|
retry--;
|
|
if (retry)
|
|
goto _RETRY_;
|
|
}
|
|
|
|
return result;
|
|
}
|
|
|
|
static sint8 spi_read_reg(uint32 addr, uint32 *u32data)
|
|
{
|
|
uint8 retry = SPI_RETRY_COUNT;
|
|
sint8 result = N_OK;
|
|
uint8 cmd = CMD_SINGLE_READ;
|
|
uint8 tmp[4];
|
|
uint8 clockless = 0;
|
|
|
|
_RETRY_:
|
|
|
|
if (addr <= 0xff) {
|
|
/**
|
|
NMC1000 clockless registers.
|
|
**/
|
|
cmd = CMD_INTERNAL_READ;
|
|
clockless = 1;
|
|
} else {
|
|
cmd = CMD_SINGLE_READ;
|
|
clockless = 0;
|
|
}
|
|
|
|
#if defined USE_OLD_SPI_SW
|
|
result = spi_cmd(cmd, addr, 0, 4, clockless);
|
|
if (result != N_OK) {
|
|
M2M_ERR("[nmi spi]: Failed cmd, read reg (%08x)...\n", (unsigned int)addr);
|
|
goto _FAIL_;
|
|
}
|
|
|
|
result = spi_cmd_rsp(cmd);
|
|
if (result != N_OK) {
|
|
M2M_ERR("[nmi spi]: Failed cmd response, read reg (%08x)...\n", (unsigned int)addr);
|
|
goto _FAIL_;
|
|
}
|
|
|
|
/* to avoid endianess issues */
|
|
result = spi_data_read(&tmp[0], 4, clockless);
|
|
if (result != N_OK) {
|
|
M2M_ERR("[nmi spi]: Failed data read...\n");
|
|
goto _FAIL_;
|
|
}
|
|
#else
|
|
result = spi_cmd_complete(cmd, addr, (uint8 *)&tmp[0], 4, clockless);
|
|
if (result != N_OK) {
|
|
M2M_ERR("[nmi spi]: Failed cmd, read reg (%08x)...\n", addr);
|
|
goto _FAIL_;
|
|
}
|
|
|
|
#endif
|
|
|
|
*u32data = tmp[0] | ((uint32)tmp[1] << 8) | ((uint32)tmp[2] << 16) | ((uint32)tmp[3] << 24);
|
|
|
|
_FAIL_:
|
|
if (result != N_OK) {
|
|
|
|
nm_bsp_sleep(1);
|
|
spi_cmd(CMD_RESET, 0, 0, 0, 0);
|
|
spi_cmd_rsp(CMD_RESET);
|
|
M2M_ERR("Reset and retry %d %x\n", retry, addr);
|
|
nm_bsp_sleep(1);
|
|
retry--;
|
|
if (retry)
|
|
goto _RETRY_;
|
|
}
|
|
|
|
return result;
|
|
}
|
|
|
|
static sint8 nm_spi_read(uint32 addr, uint8 *buf, uint16 size)
|
|
{
|
|
uint8 cmd = CMD_DMA_EXT_READ;
|
|
sint8 result;
|
|
uint8 retry = SPI_RETRY_COUNT;
|
|
#if defined USE_OLD_SPI_SW
|
|
uint8 tmp[2];
|
|
uint8 single_byte_workaround = 0;
|
|
#endif
|
|
|
|
_RETRY_:
|
|
|
|
/**
|
|
Command
|
|
**/
|
|
#if defined USE_OLD_SPI_SW
|
|
if (size == 1) {
|
|
// Workaround hardware problem with single byte transfers over SPI bus
|
|
size = 2;
|
|
single_byte_workaround = 1;
|
|
}
|
|
result = spi_cmd(cmd, addr, 0, size, 0);
|
|
if (result != N_OK) {
|
|
M2M_ERR("[nmi spi]: Failed cmd, read block (%08x)...\n", (unsigned int)addr);
|
|
goto _FAIL_;
|
|
}
|
|
|
|
result = spi_cmd_rsp(cmd);
|
|
if (result != N_OK) {
|
|
M2M_ERR("[nmi spi]: Failed cmd response, read block (%08x)...\n", (unsigned int)addr);
|
|
goto _FAIL_;
|
|
}
|
|
|
|
/**
|
|
Data
|
|
**/
|
|
if (single_byte_workaround) {
|
|
result = spi_data_read(tmp, size, 0);
|
|
buf[0] = tmp[0];
|
|
} else
|
|
result = spi_data_read(buf, size, 0);
|
|
|
|
if (result != N_OK) {
|
|
M2M_ERR("[nmi spi]: Failed block data read...\n");
|
|
goto _FAIL_;
|
|
}
|
|
#else
|
|
result = spi_cmd_complete(cmd, addr, buf, size, 0);
|
|
if (result != N_OK) {
|
|
M2M_ERR("[nmi spi]: Failed cmd, read block (%08x)...\n", addr);
|
|
goto _FAIL_;
|
|
}
|
|
#endif
|
|
|
|
_FAIL_:
|
|
if (result != N_OK) {
|
|
nm_bsp_sleep(1);
|
|
spi_cmd(CMD_RESET, 0, 0, 0, 0);
|
|
spi_cmd_rsp(CMD_RESET);
|
|
M2M_ERR("Reset and retry %d %x %d\n", retry, addr, size);
|
|
nm_bsp_sleep(1);
|
|
retry--;
|
|
if (retry)
|
|
goto _RETRY_;
|
|
}
|
|
|
|
return result;
|
|
}
|
|
|
|
/********************************************
|
|
|
|
Bus interfaces
|
|
|
|
********************************************/
|
|
|
|
static void spi_init_pkt_sz(void)
|
|
{
|
|
uint32 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);
|
|
}
|
|
|
|
sint8 nm_spi_reset(void)
|
|
{
|
|
spi_cmd(CMD_RESET, 0, 0, 0, 0);
|
|
spi_cmd_rsp(CMD_RESET);
|
|
return M2M_SUCCESS;
|
|
}
|
|
|
|
/*
|
|
* @fn nm_spi_init
|
|
* @brief Initialize the SPI
|
|
* @return M2M_SUCCESS in case of success and M2M_ERR_BUS_FAIL in case of failure
|
|
* @author M. Abdelmawla
|
|
* @date 11 July 2012
|
|
* @version 1.0
|
|
*/
|
|
sint8 nm_spi_init(void)
|
|
{
|
|
uint32 chipid;
|
|
uint32 reg = 0;
|
|
|
|
/**
|
|
configure protocol
|
|
**/
|
|
gu8Crc_off = 0;
|
|
|
|
// TODO: We can remove the CRC trials if there is a definite way to reset
|
|
// the SPI to it's initial value.
|
|
if (!spi_read_reg(NMI_SPI_PROTOCOL_CONFIG, ®)) {
|
|
/* Read failed. Try with CRC off. This might happen when module
|
|
is removed but chip isn't reset*/
|
|
gu8Crc_off = 1;
|
|
M2M_ERR("[nmi spi]: Failed internal read protocol with CRC on, retyring with CRC off...\n");
|
|
if (!spi_read_reg(NMI_SPI_PROTOCOL_CONFIG, ®)) {
|
|
// Reaad failed with both CRC on and off, something went bad
|
|
M2M_ERR("[nmi spi]: Failed internal read protocol...\n");
|
|
return 0;
|
|
}
|
|
}
|
|
if (gu8Crc_off == 0) {
|
|
reg &= ~0xc; /* disable crc checking */
|
|
reg &= ~0x70;
|
|
reg |= (0x5 << 4);
|
|
if (!spi_write_reg(NMI_SPI_PROTOCOL_CONFIG, reg)) {
|
|
M2M_ERR("[nmi spi]: Failed internal write protocol reg...\n");
|
|
return 0;
|
|
}
|
|
gu8Crc_off = 1;
|
|
}
|
|
|
|
/**
|
|
make sure can read back chip id correctly
|
|
**/
|
|
if (!spi_read_reg(0x1000, &chipid)) {
|
|
M2M_ERR("[nmi spi]: Fail cmd read chip id...\n");
|
|
return M2M_ERR_BUS_FAIL;
|
|
}
|
|
|
|
M2M_DBG("[nmi spi]: chipid (%08x)\n", (unsigned int)chipid);
|
|
spi_init_pkt_sz();
|
|
|
|
return M2M_SUCCESS;
|
|
}
|
|
|
|
/*
|
|
* @fn nm_spi_init
|
|
* @brief DeInitialize the SPI
|
|
* @return M2M_SUCCESS in case of success and M2M_ERR_BUS_FAIL in case of failure
|
|
* @author Samer Sarhan
|
|
* @date 27 Feb 2015
|
|
* @version 1.0
|
|
*/
|
|
sint8 nm_spi_deinit(void)
|
|
{
|
|
gu8Crc_off = 0;
|
|
return M2M_SUCCESS;
|
|
}
|
|
|
|
/*
|
|
* @fn nm_spi_read_reg
|
|
* @brief Read register
|
|
* @param [in] u32Addr
|
|
* Register address
|
|
* @return Register value
|
|
* @author M. Abdelmawla
|
|
* @date 11 July 2012
|
|
* @version 1.0
|
|
*/
|
|
uint32 nm_spi_read_reg(uint32 u32Addr)
|
|
{
|
|
uint32 u32Val;
|
|
|
|
spi_read_reg(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
|
|
* @author M. Abdelmawla
|
|
* @date 11 July 2012
|
|
* @version 1.0
|
|
*/
|
|
sint8 nm_spi_read_reg_with_ret(uint32 u32Addr, uint32 *pu32RetVal)
|
|
{
|
|
sint8 s8Ret;
|
|
|
|
s8Ret = spi_read_reg(u32Addr, pu32RetVal);
|
|
|
|
if (N_OK == s8Ret)
|
|
s8Ret = M2M_SUCCESS;
|
|
else
|
|
s8Ret = M2M_ERR_BUS_FAIL;
|
|
|
|
return s8Ret;
|
|
}
|
|
|
|
/*
|
|
* @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
|
|
* @author M. Abdelmawla
|
|
* @date 11 July 2012
|
|
* @version 1.0
|
|
*/
|
|
sint8 nm_spi_write_reg(uint32 u32Addr, uint32 u32Val)
|
|
{
|
|
sint8 s8Ret;
|
|
|
|
s8Ret = spi_write_reg(u32Addr, u32Val);
|
|
|
|
if (N_OK == s8Ret)
|
|
s8Ret = M2M_SUCCESS;
|
|
else
|
|
s8Ret = M2M_ERR_BUS_FAIL;
|
|
|
|
return s8Ret;
|
|
}
|
|
|
|
/*
|
|
* @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
|
|
* @author M. Abdelmawla
|
|
* @date 11 July 2012
|
|
* @version 1.0
|
|
*/
|
|
sint8 nm_spi_read_block(uint32 u32Addr, uint8 *puBuf, uint16 u16Sz)
|
|
{
|
|
sint8 s8Ret;
|
|
|
|
s8Ret = nm_spi_read(u32Addr, puBuf, u16Sz);
|
|
|
|
if (N_OK == s8Ret)
|
|
s8Ret = M2M_SUCCESS;
|
|
else
|
|
s8Ret = M2M_ERR_BUS_FAIL;
|
|
|
|
return s8Ret;
|
|
}
|
|
|
|
/*
|
|
* @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
|
|
* @author M. Abdelmawla
|
|
* @date 11 July 2012
|
|
* @version 1.0
|
|
*/
|
|
sint8 nm_spi_write_block(uint32 u32Addr, uint8 *puBuf, uint16 u16Sz)
|
|
{
|
|
sint8 s8Ret;
|
|
|
|
s8Ret = nm_spi_write(u32Addr, puBuf, u16Sz);
|
|
|
|
if (N_OK == s8Ret)
|
|
s8Ret = M2M_SUCCESS;
|
|
else
|
|
s8Ret = M2M_ERR_BUS_FAIL;
|
|
|
|
return s8Ret;
|
|
}
|
|
|
|
#endif
|