summaryrefslogtreecommitdiff
path: root/src/mts_fpga_spi.c
diff options
context:
space:
mode:
authorJohn Klug <john.klug@multitech.com>2017-08-18 15:14:17 -0500
committerJohn Klug <john.klug@multitech.com>2017-08-18 15:14:17 -0500
commit3ff432faedee2ec0b93d163e4808f391d65f1ba2 (patch)
tree59df462ea8586a664a59d4cf62f1a58af6507f7e /src/mts_fpga_spi.c
parentc2da95882ea7a4218a4432ee5da8165aa61addfc (diff)
downloadmts-id-eeprom-3ff432faedee2ec0b93d163e4808f391d65f1ba2.tar.gz
mts-id-eeprom-3ff432faedee2ec0b93d163e4808f391d65f1ba2.tar.bz2
mts-id-eeprom-3ff432faedee2ec0b93d163e4808f391d65f1ba2.zip
mts-fpga-loader
Diffstat (limited to 'src/mts_fpga_spi.c')
-rw-r--r--src/mts_fpga_spi.c513
1 files changed, 513 insertions, 0 deletions
diff --git a/src/mts_fpga_spi.c b/src/mts_fpga_spi.c
new file mode 100644
index 0000000..1d95ac1
--- /dev/null
+++ b/src/mts_fpga_spi.c
@@ -0,0 +1,513 @@
+#include "mts_error_codes.h"
+#include "mts_fpga_spi.h"
+
+/* -------------------------------------------------------------------------- */
+/* --- PRIVATE MACROS ------------------------------------------------------- */
+
+#define ARRAY_SIZE(a) (sizeof(a) / sizeof((a)[0]))
+#if DEBUG_SPI == 1
+#define DEBUG_MSG(str) fprintf(stderr, str)
+#define DEBUG_PRINTF(fmt, args...) \
+ fprintf(stderr, "%s:%d: " fmt, __FUNCTION__, __LINE__, args)
+#define CHECK_NULL(a) \
+ if (a == NULL) { \
+ fprintf(stderr, "%s:%d: ERROR: NULL POINTER AS ARGUMENT\n", __FUNCTION__, \
+ __LINE__); \
+ return MTAC_SPI_ERROR; \
+ }
+#else
+#define DEBUG_MSG(str)
+#define DEBUG_PRINTF(fmt, args...)
+#define CHECK_NULL(a) \
+ if (a == NULL) { \
+ return MTAC_SPI_ERROR; \
+ }
+#endif
+
+/* -------------------------------------------------------------------------- */
+/* --- PRIVATE CONSTANTS ---------------------------------------------------- */
+
+#define READ_ACCESS 0x00
+#define WRITE_ACCESS 0x80
+#define SPI_SPEED 8000000
+/* -------------------------------------------------------------------------- */
+/* --- PUBLIC FUNCTIONS DEFINITION ------------------------------------------ */
+
+/*
+ SPI initialization and configuration
+*/
+int mtac_spi_open(char *spidev, void **spi_target_ptr) {
+ int *spi_device = NULL;
+ int dev;
+ int a = 0, b = 0;
+ int i;
+
+ /* check input variables */
+ CHECK_NULL(spi_target_ptr);
+
+ /* allocate memory for the device descriptor */
+ spi_device = malloc(sizeof(int));
+ if (spi_device == NULL) {
+ DEBUG_MSG("ERROR: MALLOC FAIL\n");
+ return MTAC_SPI_OPEN_FAILURE;
+ }
+
+ /* open SPI device */
+ dev = open(spidev, O_RDWR);
+ if (dev < 0) {
+ DEBUG_PRINTF("ERROR: failed to open SPI device %s\n", spidev);
+ return MTAC_SPI_OPEN_FAILURE;
+ }
+
+ /* setting SPI mode to 'mode 0' */
+ i = SPI_MODE_3;
+ a = ioctl(dev, SPI_IOC_WR_MODE, &i);
+ b = ioctl(dev, SPI_IOC_RD_MODE, &i);
+ if ((a < 0) || (b < 0)) {
+ DEBUG_MSG("ERROR: SPI PORT FAIL TO SET IN MODE 0\n");
+ close(dev);
+ free(spi_device);
+ return MTAC_SPI_OPEN_FAILURE;
+ }
+
+ /* setting SPI max clk (in Hz) */
+ i = SPI_SPEED;
+ a = ioctl(dev, SPI_IOC_WR_MAX_SPEED_HZ, &i);
+ b = ioctl(dev, SPI_IOC_RD_MAX_SPEED_HZ, &i);
+ if ((a < 0) || (b < 0)) {
+ DEBUG_MSG("ERROR: SPI PORT FAIL TO SET MAX SPEED\n");
+ close(dev);
+ free(spi_device);
+ return MTAC_SPI_OPEN_FAILURE;
+ }
+
+ /* setting SPI to MSB first */
+ i = 0;
+ a = ioctl(dev, SPI_IOC_WR_LSB_FIRST, &i);
+ b = ioctl(dev, SPI_IOC_RD_LSB_FIRST, &i);
+ if ((a < 0) || (b < 0)) {
+ DEBUG_MSG("ERROR: SPI PORT FAIL TO SET MSB FIRST\n");
+ close(dev);
+ free(spi_device);
+ return MTAC_SPI_OPEN_FAILURE;
+ }
+
+ /* setting SPI to 8 bits per word */
+ i = 0;
+ a = ioctl(dev, SPI_IOC_WR_BITS_PER_WORD, &i);
+ b = ioctl(dev, SPI_IOC_RD_BITS_PER_WORD, &i);
+ if ((a < 0) || (b < 0)) {
+ DEBUG_MSG("ERROR: SPI PORT FAIL TO SET 8 BITS-PER-WORD\n");
+ close(dev);
+ return MTAC_SPI_OPEN_FAILURE;
+ }
+
+ *spi_device = dev;
+ *spi_target_ptr = (void *)spi_device;
+ return MTAC_SUCCESS;
+}
+
+/*
+ Check Chip ID
+*/
+int mtac_id(char *spidev, void *spi_target) {
+ int mtac_ret;
+ int spi_device;
+ struct spi_ioc_transfer k;
+ int ret;
+ size_t command_size = 6;
+ char out_buf[command_size];
+ char in_buf[command_size];
+
+ /* prepare frame to be sent */
+ out_buf[0] = 0x90;
+ out_buf[1] = 0x00;
+ out_buf[2] = 0x00;
+ out_buf[3] = 0x00;
+ out_buf[4] = 0x00;
+ out_buf[5] = 0x00;
+
+ /* I/O transaction */
+ mtac_ret = mtac_spi_open(spidev, &spi_target);
+ spi_device = *(int *)spi_target; /* spi_target must not be null beforehand */
+ memset(&k, 0, sizeof(k)); /* clear k */
+ k.tx_buf = (unsigned long)out_buf;
+ k.rx_buf = (unsigned long)in_buf;
+ k.len = command_size;
+ k.speed_hz = SPI_SPEED;
+ k.cs_change = 0;
+ k.bits_per_word = 8;
+ ret = ioctl(spi_device, SPI_IOC_MESSAGE(1), &k);
+ mtac_ret = mtac_disconnect();
+
+ /* determine return code */
+ if (ret != (int)k.len) {
+ DEBUG_MSG("Chip transfer failed\n");
+ mtac_ret = MTAC_SPI_TRANSFER_FAILURE;
+ }
+ else if (((int)in_buf[4] == 0xFF && (int)in_buf[5] == 0xFF) || ((int)in_buf[4] == 0 && (int)in_buf[5] == 0)) {
+ printf("Unable to communicate with flash\n");
+ mtac_ret = MTAC_SPI_TRANSFER_FAILURE;
+ }
+ else {
+ printf("Manufacturer ID: %x %x",in_buf[4], in_buf[5]);
+ mtac_ret = MTAC_SUCCESS;
+ }
+ return mtac_ret;
+}
+
+/*
+ Chip erase instruction sets all memory within
+ the device to the erased state of all 1s (FFh)
+*/
+int chip_erase(char *spidev, void *spi_target) {
+ int mtac_ret;
+ int spi_device;
+ struct spi_ioc_transfer k;
+ int ret;
+ size_t command_size = 1;
+ char out_buf[command_size];
+ char in_buf[command_size];
+
+ /* prepare frame to be sent */
+ out_buf[0] = CHIP_ERASE;
+
+ /* I/O transaction */
+ mtac_ret = mtac_spi_open(spidev, &spi_target);
+ spi_device = *(int *)spi_target; /* spi_target must not be null beforehand */
+ memset(&k, 0, sizeof(k)); /* clear k */
+ k.tx_buf = (unsigned long)out_buf;
+ k.rx_buf = (unsigned long)in_buf;
+ k.len = command_size;
+ k.speed_hz = SPI_SPEED;
+ k.cs_change = 0;
+ k.bits_per_word = 8;
+ ret = ioctl(spi_device, SPI_IOC_MESSAGE(1), &k);
+ sleep(5);
+ mtac_ret = mtac_disconnect();
+
+ /* determine return code */
+ if (ret != (int)k.len) {
+ DEBUG_MSG("Chip Erase transfer failed\n");
+ mtac_ret = MTAC_SPI_TRANSFER_FAILURE;
+ } else {
+ DEBUG_MSG("Chip Erase transfer successful\n");
+ mtac_erase_verify(spidev, spi_target);
+ mtac_ret = MTAC_SUCCESS;
+ }
+ return mtac_ret;
+}
+
+/*
+ Verify that the chip erase was successful
+*/
+int mtac_erase_verify(char *spidev, void *spi_target) {
+ int mtac_ret;
+ int spi_device;
+ struct spi_ioc_transfer k;
+ int a, ret;
+ uint16_t command_size = 256 + 5;
+ char out_buf[command_size];
+ char in_buf[command_size];
+
+ /* prepare frame to be sent */
+ out_buf[0] = 0x0B;
+ out_buf[1] = 0x00;
+ out_buf[2] = 0x00;
+ out_buf[3] = 0x00;
+ out_buf[4] = 0x00;
+
+ /* I/O transaction */
+ mtac_ret = mtac_spi_open(spidev, &spi_target);
+ spi_device = *(int *)spi_target; /* spi_target must not be null beforehand */
+ memset(&k, 0, sizeof(k)); /* clear k */
+ k.tx_buf = (unsigned long)out_buf;
+ k.rx_buf = (unsigned long)in_buf;
+ k.len = command_size;
+ k.speed_hz = SPI_SPEED;
+ k.cs_change = 1;
+ k.bits_per_word = 8;
+ ret = ioctl(spi_device, SPI_IOC_MESSAGE(1), &k);
+
+ /* determine return code */
+ if (ret != (int)k.len) {
+ DEBUG_MSG("Chip transfer failed\n");
+ mtac_ret = MTAC_SPI_TRANSFER_FAILURE;
+ } else {
+ DEBUG_MSG("Chip transfer successful\n");
+ mtac_ret = MTAC_SUCCESS;
+ }
+ mtac_ret = mtac_disconnect();
+ /* verify that the chip was erased */
+ for (a = 5; a < command_size; a++) {
+ if (in_buf[a] != 0xFF) {
+ mtac_disconnect();
+ mtac_ret = MTAC_CHIP_ERASE_FAILURE;
+ return mtac_ret;
+ }
+ }
+ return mtac_ret;
+}
+
+/*
+ Write enable instruction sets the write enable latch
+ in the status register to 1. It needs to be set before
+ a page can be programmed or chip erased
+*/
+int write_enable(char *spidev, void *spi_target) {
+ int mtac_ret;
+ int spi_device;
+ struct spi_ioc_transfer k;
+ int ret;
+ size_t command_size = 1;
+ char out_buf[command_size];
+ char in_buf[command_size];
+
+ /* prepare frame to be sent */
+ out_buf[0] = 0x06;
+
+ /* I/O transaction */
+ mtac_ret = mtac_spi_open(spidev, &spi_target);
+ spi_device = *(int *)spi_target; /* spi_target must not be null beforehand */
+ memset(&k, 0, sizeof(k)); /* clear k */
+ k.tx_buf = (unsigned long)out_buf;
+ k.rx_buf = (unsigned long)in_buf;
+ k.len = command_size;
+ k.speed_hz = SPI_SPEED;
+ k.cs_change = 0;
+ k.bits_per_word = 8;
+ ret = ioctl(spi_device, SPI_IOC_MESSAGE(1), &k);
+ mtac_ret = mtac_disconnect();
+
+ /* determine return code */
+ if (ret != (int)k.len) {
+ DEBUG_MSG("Write Enable failed");
+ mtac_ret = MTAC_SPI_TRANSFER_FAILURE;
+ } else {
+ usleep(1000);
+ DEBUG_MSG("Write Enable successful");
+ mtac_ret = MTAC_SUCCESS;
+ }
+ return mtac_ret;
+}
+
+/*
+ Release Power-down instruction releases the device from
+ said state allowing device communication
+*/
+int mtac_release(char *spidev, void *spi_target) {
+ int mtac_ret;
+ int spi_device;
+ struct spi_ioc_transfer k;
+ int a, ret;
+ size_t command_size = 5;
+ char out_buf[command_size];
+ char in_buf[command_size];
+
+ /* prepare frame to be sent */
+ out_buf[0] = CHIP_RELEASE;
+ out_buf[1] = 0;
+ out_buf[2] = 0;
+ out_buf[3] = 0;
+ out_buf[4] = 0;
+
+ /* I/O transaction */
+ mtac_ret = mtac_spi_open(spidev, &spi_target);
+ spi_device = *(int *)spi_target; /* spi_target must not be null beforehand */
+ memset(&k, 0, sizeof(k)); /* clear k */
+ k.tx_buf = (unsigned long)out_buf;
+ k.rx_buf = (unsigned long)in_buf;
+ k.len = command_size;
+ k.speed_hz = SPI_SPEED;
+ k.cs_change = 1;
+ k.bits_per_word = 8;
+ ret = ioctl(spi_device, SPI_IOC_MESSAGE(1), &k);
+ mtac_ret = mtac_disconnect();
+
+ /* determine return code */
+ if (ret != (int)k.len) {
+ DEBUG_MSG("\nRelease failed\n");
+ mtac_ret = MTAC_SPI_TRANSFER_FAILURE;
+ } else {
+ usleep(1000);
+ DEBUG_MSG("\nRelease successful\n");
+ mtac_ret = MTAC_SUCCESS;
+ }
+ return mtac_ret;
+}
+
+/*
+ Page Program instruction allows writing upto 256 bytes (a page) of
+ data to be programmed at previously erased memory locations Write
+ enable must be issued first
+*/
+int page_program(char *spidev, void *spi_target, uint8_t adr_lower, uint8_t adr_higher,
+ int data[256]) {
+ int mtac_ret;
+ int spi_device;
+ struct spi_ioc_transfer k;
+ int a, ret, h;
+ size_t command_size = 260;
+ char out_buf[command_size];
+ char in_buf[command_size];
+
+ /* prepare frame to be sent */
+ out_buf[0] = PAGE_PROGRAM;
+ out_buf[1] = adr_higher;
+ out_buf[2] = adr_lower;
+ out_buf[3] = 0x00;
+ for (h = 0; h < 256; h++) {
+ out_buf[h + 4] = data[h];
+ }
+
+ /* I/O transaction */
+ mtac_ret = mtac_spi_open(spidev, &spi_target);
+ spi_device = *(int *)spi_target; /* spi_target must not be null beforehand */
+ memset(&k, 0, sizeof(k)); /* clear k */
+ k.tx_buf = (unsigned long)out_buf;
+ k.rx_buf = (unsigned long)in_buf;
+ k.len = command_size;
+ k.speed_hz = SPI_SPEED;
+ k.cs_change = 1;
+ k.bits_per_word = 8;
+ a = ioctl(spi_device, SPI_IOC_MESSAGE(1), &k);
+ printf("Writing Page %x%x to MTAC\r", adr_higher, adr_lower);
+ usleep(10000);
+ for (ret = 0; ret < command_size; ret++) {
+ DEBUG_PRINTF("%x ", out_buf[ret]);
+ }
+ mtac_ret = mtac_disconnect();
+
+ /* determine return code */
+ if (a != (int)k.len) {
+ DEBUG_MSG("ERROR: SPI WRITE FAILURE\n");
+ mtac_ret = MTAC_SPI_TRANSFER_FAILURE;
+ } else {
+ DEBUG_MSG("Note: SPI write success\n");
+ mtac_ret = MTAC_SUCCESS;
+ }
+ return mtac_ret;
+}
+
+/* Simple spi write to fpga*/
+int mtac_spi_w(void *spi_target, uint8_t spi_mux_mode, uint8_t spi_mux_target,
+ uint8_t address, uint8_t data) {
+ int spi_device;
+ uint8_t out_buf[3];
+ uint8_t command_size;
+ struct spi_ioc_transfer k;
+ int a;
+
+ /* check input variables */
+ CHECK_NULL(spi_target);
+ if ((address & 0x80) != 0) {
+ DEBUG_MSG("WARNING: SPI address > 127\n");
+ }
+
+ spi_device = *(int *)spi_target; /* spi_target must not be null beforehand */
+
+ /* prepare frame to be sent */
+ if (spi_mux_mode == MTAC_SPI_MUX_MODE1) {
+ out_buf[0] = spi_mux_target;
+ out_buf[1] = WRITE_ACCESS | (address & 0x7F);
+ out_buf[2] = data;
+ command_size = 3;
+ } else {
+ out_buf[0] = WRITE_ACCESS | (address & 0x7F);
+ out_buf[1] = data;
+ command_size = 2;
+ }
+
+ /* I/O transaction */
+ memset(&k, 0, sizeof(k)); /* clear k */
+ k.tx_buf = (unsigned long)out_buf;
+ k.len = command_size;
+ k.speed_hz = SPI_SPEED;
+ k.cs_change = 1;
+ k.bits_per_word = 8;
+ a = ioctl(spi_device, SPI_IOC_MESSAGE(1), &k);
+
+ /* determine return code */
+ if (a != (int)k.len) {
+ DEBUG_MSG("ERROR: SPI WRITE FAILURE\n");
+ return MTAC_SPI_TRANSFER_FAILURE;
+ } else {
+ DEBUG_MSG("Note: SPI write success\n");
+ return MTAC_SUCCESS;
+ }
+}
+
+/* Simple spi read to fpga */
+int mtac_spi_r(void *spi_target, uint8_t spi_mux_mode, uint8_t spi_mux_target,
+ uint8_t address, uint8_t *data) {
+ int spi_device;
+ uint8_t out_buf[3];
+ uint8_t in_buf[ARRAY_SIZE(out_buf)];
+ uint8_t command_size;
+ struct spi_ioc_transfer k;
+ int a;
+
+ /* check input variables */
+ CHECK_NULL(spi_target);
+ if ((address & 0x80) != 0) {
+ DEBUG_MSG("WARNING: SPI address > 127\n");
+ }
+ CHECK_NULL(data);
+
+ spi_device = *(int *)spi_target; /* spi_target cannot be null beforehand */
+
+ /* prepare frame to be sent */
+ if (spi_mux_mode == MTAC_SPI_MUX_MODE1) {
+ out_buf[0] = spi_mux_target;
+ out_buf[1] = READ_ACCESS | (address & 0x7F);
+ out_buf[2] = 0x00;
+ command_size = 3;
+ } else {
+ out_buf[0] = READ_ACCESS | (address & 0x7F);
+ out_buf[1] = 0x00;
+ command_size = 2;
+ }
+
+ /* I/O transaction */
+ memset(&k, 0, sizeof(k)); /* clear k */
+ k.tx_buf = (unsigned long)out_buf;
+ k.rx_buf = (unsigned long)in_buf;
+ k.len = command_size;
+ k.cs_change = 1;
+ a = ioctl(spi_device, SPI_IOC_MESSAGE(1), &k);
+
+ /* determine return code */
+ if (a != (int)k.len) {
+ DEBUG_MSG("ERROR: SPI READ FAILURE\n");
+ return MTAC_SPI_TRANSFER_FAILURE;
+ } else {
+ DEBUG_MSG("Note: SPI read success\n");
+ *data = in_buf[command_size - 1];
+ return MTAC_SUCCESS;
+ }
+}
+
+/*
+ SPI release
+*/
+int mtac_spi_close(void *spi_target) {
+ int spi_device;
+ int a;
+
+ /* check input variables */
+ CHECK_NULL(spi_target);
+
+ /* close file & deallocate file descriptor */
+ spi_device = *(int *)spi_target; /* check that spi_target is not null */
+ a = close(spi_device);
+ free(spi_target);
+
+ /* determine return code */
+ if (a < 0) {
+ DEBUG_MSG("ERROR: SPI PORT FAILED TO CLOSE\n");
+ return MTAC_SPI_CLOSE_FAILURE;
+ } else {
+ DEBUG_MSG("Note: SPI port closed\n");
+ return MTAC_SUCCESS;
+ }
+} \ No newline at end of file