aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMarc Schink <dev@zapb.de>2020-08-12 01:41:06 +0200
committerMarc Schink <dev@zapb.de>2020-11-25 07:08:28 +0100
commit624e6dbedc59b3b6d869cd54ca6f8e3997391d41 (patch)
treefe1122d5f1973cd7c23270d4bbcc61d6d537d4c0
parent0ea137e29731217329a626acb4d80a54d8079999 (diff)
downloadlibjaylink-624e6dbedc59b3b6d869cd54ca6f8e3997391d41.zip
libjaylink-624e6dbedc59b3b6d869cd54ca6f8e3997391d41.tar.gz
libjaylink-624e6dbedc59b3b6d869cd54ca6f8e3997391d41.tar.bz2
Add initial SPI support
Signed-off-by: Marc Schink <dev@zapb.de>
-rw-r--r--libjaylink/Makefile.am1
-rw-r--r--libjaylink/libjaylink.h28
-rw-r--r--libjaylink/spi.c148
-rw-r--r--libjaylink/strutil.c2
-rw-r--r--libjaylink/target.c1
5 files changed, 179 insertions, 1 deletions
diff --git a/libjaylink/Makefile.am b/libjaylink/Makefile.am
index 62c5489..8e10212 100644
--- a/libjaylink/Makefile.am
+++ b/libjaylink/Makefile.am
@@ -40,6 +40,7 @@ libjaylink_la_SOURCES = \
list.c \
log.c \
socket.c \
+ spi.c \
strutil.c \
swd.c \
swo.c \
diff --git a/libjaylink/libjaylink.h b/libjaylink/libjaylink.h
index 8f48c3d..8798e42 100644
--- a/libjaylink/libjaylink.h
+++ b/libjaylink/libjaylink.h
@@ -156,7 +156,9 @@ enum jaylink_device_capability {
/** Device supports EMUCOM. */
JAYLINK_DEV_CAP_EMUCOM = 33,
/** Device supports ethernet connectivity. */
- JAYLINK_DEV_CAP_ETHERNET = 38
+ JAYLINK_DEV_CAP_ETHERNET = 38,
+ /** Device supports SPI. */
+ JAYLINK_DEV_CAP_SPI = 56,
};
/** Hardware information. */
@@ -240,6 +242,8 @@ enum jaylink_target_interface {
JAYLINK_TIF_FINE = 3,
/** 2-wire JTAG for PIC32 compliant devices. */
JAYLINK_TIF_2W_JTAG_PIC32 = 4,
+ /** Serial Peripheral Interface (SPI). */
+ JAYLINK_TIF_SPI = 5,
/** Compact JTAG (cJTAG). **/
JAYLINK_TIF_CJTAG = 7,
};
@@ -268,6 +272,22 @@ enum jaylink_swo_mode {
JAYLINK_SWO_MODE_UART = 0
};
+/** Serial Peripheral Interface (SPI) flags. */
+enum jaylink_spi_flag {
+ /** Do not drive chip select (CS) before the transfer begins. */
+ JAYLINK_SPI_FLAG_CS_START_U = 0x00,
+ /** Drive chip select (CS) low before the transfer begins. */
+ JAYLINK_SPI_FLAG_CS_START_0 = 0x02,
+ /** Drive chip select (CS) high before the transfer begins. */
+ JAYLINK_SPI_FLAG_CS_START_1 = 0x03,
+ /** Do not drive chip select (CS) after the transfer is complete. */
+ JAYLINK_SPI_FLAG_CS_END_U = 0x00,
+ /** Drive chip select (CS) low after the transfer is complete. */
+ JAYLINK_SPI_FLAG_CS_END_0 = 0x08,
+ /** Drive chip select (CS) high after the transfer is complete. */
+ JAYLINK_SPI_FLAG_CS_END_1 = 0x0c,
+};
+
/** Target interface speed information. */
struct jaylink_speed {
/** Base frequency in Hz. */
@@ -569,6 +589,12 @@ JAYLINK_API int jaylink_log_set_domain(struct jaylink_context *ctx,
JAYLINK_API const char *jaylink_log_get_domain(
const struct jaylink_context *ctx);
+/*--- spi.c -----------------------------------------------------------------*/
+
+JAYLINK_API int jaylink_spi_io(struct jaylink_device_handle *devh,
+ const uint8_t *mosi, uint8_t *miso, uint32_t length,
+ uint32_t flags);
+
/*--- strutil.c -------------------------------------------------------------*/
JAYLINK_API int jaylink_parse_serial_number(const char *str,
diff --git a/libjaylink/spi.c b/libjaylink/spi.c
new file mode 100644
index 0000000..4f8ab04
--- /dev/null
+++ b/libjaylink/spi.c
@@ -0,0 +1,148 @@
+/*
+ * This file is part of the libjaylink project.
+ *
+ * Copyright (C) 2016-2020 Marc Schink <dev@zapb.de>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <stdint.h>
+
+#include "libjaylink.h"
+#include "libjaylink-internal.h"
+
+/**
+ * @file
+ *
+ * Serial Peripheral Interface (SPI) functions.
+ */
+
+/** @cond PRIVATE */
+#define CMD_SPI 0x15
+
+#define SPI_CMD_IO 0x01
+/** @endcond */
+
+/**
+ * Perform SPI I/O operation.
+ *
+ * The device acts as master and operates in mode 3 (CPOL = 1, CPHA = 1). Data
+ * is transferred with the most significant bit (MSB) first.
+ *
+ * @note This function must only be used if the device has the
+ * #JAYLINK_DEV_CAP_SPI capability and if the #JAYLINK_TIF_SPI interface
+ * is available and selected.
+ *
+ * @param[in,out] devh Device handle.
+ * @param[in] mosi Buffer to read MOSI data from. Can be NULL.
+ * @param[out] miso Buffer to store MISO data on success. Its content
+ * is undefined on failure. The buffer must be large enough to
+ * contain at least the specified number of bytes to transfer.
+ * Can be NULL.
+ * @param[in] length Number of bytes to transfer.
+ * @param[in] flags Flags, see #jaylink_spi_flag for more details.
+ *
+ * @retval JAYLINK_OK Success.
+ * @retval JAYLINK_ERR_ARG Invalid arguments.
+ * @retval JAYLINK_ERR_TIMEOUT A timeout occurred.
+ * @retval JAYLINK_ERR_PROTO Protocol violation.
+ * @retval JAYLINK_ERR Other error conditions.
+ *
+ * @since 0.3.0
+ */
+JAYLINK_API int jaylink_spi_io(struct jaylink_device_handle *devh,
+ const uint8_t *mosi, uint8_t *miso, uint32_t length,
+ uint32_t flags)
+{
+ int ret;
+ struct jaylink_context *ctx;
+ uint8_t buf[20];
+ uint32_t mosi_length;
+ uint32_t miso_length;
+ uint32_t num_transferred_bytes;
+
+ if (!devh || !length)
+ return JAYLINK_ERR_ARG;
+
+ if (!mosi && !miso)
+ return JAYLINK_ERR_ARG;
+
+ mosi_length = (mosi) ? length : 0;
+ miso_length = (miso) ? length : 0;
+ ctx = devh->dev->ctx;
+
+ buf[0] = CMD_SPI;
+ buf[1] = SPI_CMD_IO;
+ buf[2] = 0x00;
+ buf[3] = 0x00;
+
+ buffer_set_u32(buf, mosi_length + 8, 4);
+ buffer_set_u32(buf, miso_length + 4, 8);
+ buffer_set_u32(buf, length * 8, 12);
+ buffer_set_u32(buf, flags, 16);
+
+ ret = transport_start_write_read(devh, 20 + mosi_length,
+ miso_length + 4, true);
+
+ if (ret != JAYLINK_OK) {
+ log_err(ctx, "transport_start_write_read() failed: %s",
+ jaylink_strerror(ret));
+ return ret;
+ }
+
+ ret = transport_write(devh, buf, 20);
+
+ if (ret != JAYLINK_OK) {
+ log_err(ctx, "transport_write() failed: %s",
+ jaylink_strerror(ret));
+ return ret;
+ }
+
+ if (mosi) {
+ ret = transport_write(devh, mosi, mosi_length);
+
+ if (ret != JAYLINK_OK) {
+ log_err(ctx, "transport_write() failed: %s",
+ jaylink_strerror(ret));
+ return ret;
+ }
+ }
+
+ if (miso) {
+ ret = transport_read(devh, miso, miso_length);
+
+ if (ret != JAYLINK_OK) {
+ log_err(ctx, "transport_read() failed: %s",
+ jaylink_strerror(ret));
+ return ret;
+ }
+ }
+
+ ret = transport_read(devh, buf, 4);
+
+ if (ret != JAYLINK_OK) {
+ log_err(ctx, "transport_read() failed: %s",
+ jaylink_strerror(ret));
+ return ret;
+ }
+
+ num_transferred_bytes = buffer_get_u32(buf, 0);
+
+ if (num_transferred_bytes != length) {
+ log_err(ctx, "Unexpected number of transferred bytes");
+ return JAYLINK_ERR_PROTO;
+ }
+
+ return JAYLINK_OK;
+}
diff --git a/libjaylink/strutil.c b/libjaylink/strutil.c
index 3658683..0f344c1 100644
--- a/libjaylink/strutil.c
+++ b/libjaylink/strutil.c
@@ -116,6 +116,8 @@ JAYLINK_API const char *jaylink_target_interface_string(
return "FINE";
case JAYLINK_TIF_2W_JTAG_PIC32:
return "2-wire JTAG for PIC32";
+ case JAYLINK_TIF_SPI:
+ return "SPI";
case JAYLINK_TIF_CJTAG:
return "cJTAG";
default:
diff --git a/libjaylink/target.c b/libjaylink/target.c
index 8df96af..c51ebcd 100644
--- a/libjaylink/target.c
+++ b/libjaylink/target.c
@@ -217,6 +217,7 @@ JAYLINK_API int jaylink_select_interface(struct jaylink_device_handle *devh,
case JAYLINK_TIF_BDM3:
case JAYLINK_TIF_FINE:
case JAYLINK_TIF_2W_JTAG_PIC32:
+ case JAYLINK_TIF_SPI:
case JAYLINK_TIF_CJTAG:
break;
default: