ext: simplelink: Add SimpleLink DPL porting layer to Zephyr

This ports the SimpleLink WiFi host driver via its OS adaptation
layer to Zephyr OS primitives.

This was validated using an out-of-tree SimpleLink shell
application including functions for:
* WLAN connect, disconnect and scan
* Socket: UDP server and client

Signed-off-by: Gil Pitney <gil.pitney@linaro.org>
diff --git a/ext/hal/ti/simplelink/kernel/zephyr/dpl/ClockP_zephyr.c b/ext/hal/ti/simplelink/kernel/zephyr/dpl/ClockP_zephyr.c
new file mode 100644
index 0000000..34f5731
--- /dev/null
+++ b/ext/hal/ti/simplelink/kernel/zephyr/dpl/ClockP_zephyr.c
@@ -0,0 +1,20 @@
+/*
+ * Copyright (c) 2017, Texas Instruments Incorporated
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+#include <zephyr.h>
+#include <misc/__assert.h>
+#include <kernel/zephyr/dpl/dpl.h>
+#include <ti/drivers/dpl/ClockP.h>
+
+uint32_t ClockP_getSystemTicks()
+{
+	return (uint32_t)_ms_to_ticks(k_uptime_get_32());
+}
+
+void ClockP_usleep(uint32_t usec)
+{
+	k_sleep((s32_t)usec);
+}
diff --git a/ext/hal/ti/simplelink/kernel/zephyr/dpl/HwiP_zephyr.c b/ext/hal/ti/simplelink/kernel/zephyr/dpl/HwiP_zephyr.c
new file mode 100644
index 0000000..201854f
--- /dev/null
+++ b/ext/hal/ti/simplelink/kernel/zephyr/dpl/HwiP_zephyr.c
@@ -0,0 +1,160 @@
+/*
+ * Copyright (c) 2017, Texas Instruments Incorporated
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+
+#include <zephyr.h>
+#include <misc/__assert.h>
+#include <kernel/zephyr/dpl/dpl.h>
+#include <ti/drivers/dpl/HwiP.h>
+
+#include <inc/hw_types.h>
+#include <inc/hw_ints.h>
+#include <driverlib/rom.h>
+#include <driverlib/rom_map.h>
+#include <driverlib/interrupt.h>
+
+/*
+ * IRQ_CONNECT requires we know the ISR signature and argument
+ * at build time; whereas SimpleLink plugs the interrupts
+ * at run time, so we create an ISR shim, and register that.
+ * The callback argument doesn't change after the ISR is registered.
+ */
+struct sl_isr_args
+{
+	HwiP_Fxn cb;
+	uintptr_t arg;
+};
+
+static struct sl_isr_args sl_UDMA_cb = {NULL, 0};
+static struct sl_isr_args sl_UDMAERR_cb = {NULL, 0};
+static struct sl_isr_args sl_NWPIC_cb = {NULL, 0};
+static struct sl_isr_args sl_LSPI_cb = {NULL, 0};
+
+static void sl_isr(void *isr_arg)
+{
+	HwiP_Fxn cb = ((struct sl_isr_args *)isr_arg)->cb;
+	uintptr_t arg =	 ((struct sl_isr_args *)isr_arg)->arg;
+
+	/* Call the SimpleLink ISR Handler: */
+	if (cb) {
+		cb(arg);
+	}
+}
+
+/* Must hardcode the IRQ for IRQ_CONNECT macro.	 Must be <= CONFIG_NUM_IRQs.*/
+#define EXCEPTION_UDMA		46	/* == INT_UDMA	(62) - 16 */
+#define EXCEPTION_UDMAERR	47	/* == INT_UDMAERR (63) - 16 */
+#define EXCEPTION_NWPIC		171	/* == INT_NWPIC (187) - 16 */
+#define EXCEPTION_LSPI		177	/* == INT_LSPI (193) - 16 */
+
+HwiP_Handle HwiP_create(int interruptNum, HwiP_Fxn hwiFxn, HwiP_Params *params)
+{
+	HwiP_Handle handle = 0;
+	uint32_t priority = ~0;
+	uintptr_t arg = 0;
+
+	if (params) {
+		priority = params->priority;
+		arg = params->arg;
+	}
+
+	/*
+	 * SimpleLink only uses the NWPIC, UDMA, UDMAERR and LSPI interrupts:
+	 */
+	__ASSERT(INT_NWPIC == interruptNum || INT_UDMA == interruptNum ||
+		 INT_UDMAERR == interruptNum || INT_LSPI == interruptNum,
+		 "Unexpected interruptNum: %d\r\n",
+		 interruptNum);
+	/*
+	 * Priority expected is either:
+	 *    INT_PRIORITY_LVL_1,
+	 *    or ~0 or 255 (meaning lowest priority)
+	 *    ~0 and 255 are meant to be the same as INT_PRIORITY_LVL_7.
+	 *    For ~0 or 255, we want 7; but Zephyr IRQ_CONNECT adds +1,
+	 *    so we pass 6 for those TI drivers passing prio = ~0.
+	 */
+	__ASSERT((INT_PRIORITY_LVL_1 == priority) ||
+		 (0xff == (priority & 0xff)),
+		 "Expected priority: 0x%x or 0x%x, got: 0x%x\r\n",
+		 INT_PRIORITY_LVL_1, 0xff, (unsigned int)priority);
+
+	switch(interruptNum) {
+	case INT_UDMA:
+		sl_UDMA_cb.cb = hwiFxn;
+		sl_UDMA_cb.arg = arg;
+		IRQ_CONNECT(EXCEPTION_UDMA, 6, sl_isr, &sl_UDMA_cb, 0);
+		break;
+	case INT_UDMAERR:
+		sl_UDMAERR_cb.cb = hwiFxn;
+		sl_UDMAERR_cb.arg = arg;
+		IRQ_CONNECT(EXCEPTION_UDMAERR, 6, sl_isr, &sl_UDMAERR_cb, 0);
+		break;
+	case INT_NWPIC:
+		sl_NWPIC_cb.cb = hwiFxn;
+		sl_NWPIC_cb.arg = arg;
+		IRQ_CONNECT(EXCEPTION_NWPIC, 1, sl_isr, &sl_NWPIC_cb, 0);
+		break;
+	case INT_LSPI:
+		sl_LSPI_cb.cb = hwiFxn;
+		sl_LSPI_cb.arg = arg;
+		IRQ_CONNECT(EXCEPTION_LSPI, 6, sl_isr, &sl_LSPI_cb, 0);
+		break;
+	default:
+		return(handle);
+	}
+	irq_enable(interruptNum - 16);
+
+	return (HwiP_Handle)interruptNum;
+}
+
+/* Can't actually de-register an interrupt in Zephyr, so just disable: */
+void HwiP_delete(HwiP_Handle handle)
+{
+	int interruptNum = (int)handle;
+
+	__ASSERT(INT_NWPIC == interruptNum || INT_UDMA == interruptNum ||
+		 INT_UDMAERR == interruptNum || INT_LSPI == interruptNum,
+		 "Unexpected interruptNum: %d\r\n",
+		 interruptNum);
+
+	irq_disable(interruptNum - 16);
+}
+
+void HwiP_Params_init(HwiP_Params *params)
+{
+	params->arg = 0;
+	params->priority = ~0;
+}
+
+/* Zephyr has no functions for clearing an interrupt, so use driverlib: */
+void HwiP_clearInterrupt(int interruptNum)
+{
+	MAP_IntPendClear((unsigned long)interruptNum);
+}
+
+void HwiP_enableInterrupt(int interruptNum)
+{
+	irq_enable(interruptNum - 16);
+}
+
+void HwiP_disableInterrupt(int interruptNum)
+{
+	irq_disable(interruptNum - 16);
+}
+
+uintptr_t HwiP_disable(void)
+{
+	uintptr_t key;
+
+	key = irq_lock();
+
+	return (key);
+}
+
+void HwiP_restore(uintptr_t key)
+{
+	irq_unlock(key);
+}
diff --git a/ext/hal/ti/simplelink/kernel/zephyr/dpl/MutexP_zephyr.c b/ext/hal/ti/simplelink/kernel/zephyr/dpl/MutexP_zephyr.c
new file mode 100644
index 0000000..0b5a8be7
--- /dev/null
+++ b/ext/hal/ti/simplelink/kernel/zephyr/dpl/MutexP_zephyr.c
@@ -0,0 +1,95 @@
+/*
+ * Copyright (c) 2017, Texas Instruments Incorporated
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+#include <zephyr.h>
+#include <misc/__assert.h>
+#include <kernel/zephyr/dpl/dpl.h>
+#include <ti/drivers/dpl/MutexP.h>
+
+/*
+ * Zephyr kernel object pools:
+ *
+ * This bit of code enables the simplelink host driver, which assumes dynamic
+ * allocation of kernel objects (semaphores, mutexes, hwis), to be
+ * more easily ported to Zephyr (which supports static allocation).
+ *
+ * It leverages the Zephyr memory slab, enabling us to define a mutex object
+ * pool for use by the SimpleLink host driver.
+ */
+
+/* Define a Mutex pool: */
+#define DPL_MAX_MUTEXES	 4  /* From simplelink driver code inspection */
+K_MEM_SLAB_DEFINE(mutex_slab, sizeof(struct k_mutex), DPL_MAX_MUTEXES,\
+		  MEM_ALIGN);
+
+static struct k_mutex *dpl_mutex_pool_alloc()
+{
+	struct k_mutex *mutex_ptr = NULL;
+
+	if (k_mem_slab_alloc(&mutex_slab, (void **)&mutex_ptr,
+			     K_NO_WAIT) < 0) {
+		/*
+		 * We assert, as this is a logic error, due to a change in #
+		 * of mutexes needed by the simplelink driver. In that case,
+		 * the mutex pool must be increased programmatically to match.
+		 */
+		 __ASSERT(0, "Increase size of DPL mutex pool");
+	}
+	return mutex_ptr;
+}
+
+static MutexP_Status dpl_mutex_pool_free(struct k_mutex *mutex)
+{
+	k_mem_slab_free(&mutex_slab, (void **)&mutex);
+	return MutexP_OK;
+}
+
+MutexP_Handle MutexP_create(MutexP_Params *params)
+{
+	struct k_mutex *mutex;
+
+	ARG_UNUSED(params);
+
+	mutex = dpl_mutex_pool_alloc();
+	__ASSERT(mutex, "MutexP_create failed\r\n");
+
+	if (mutex) {
+		k_mutex_init(mutex);
+	}
+	return ((MutexP_Handle)mutex);
+}
+
+void MutexP_delete(MutexP_Handle handle)
+{
+	/* No way in Zephyr to "reset" the lock, so just re-init: */
+	k_mutex_init((struct k_mutex *)handle);
+
+	dpl_mutex_pool_free((struct k_mutex *)handle);
+}
+
+uintptr_t MutexP_lock(MutexP_Handle handle)
+{
+	unsigned int key = 0;
+	int retval;
+
+	retval = k_mutex_lock((struct k_mutex *)handle, K_FOREVER);
+	__ASSERT(retval == 0,
+		 "MutexP_lock: retval: %d\r\n", retval);
+
+	return ((uintptr_t)key);
+}
+
+void MutexP_Params_init(MutexP_Params *params)
+{
+	params->callback = NULL;
+}
+
+void MutexP_unlock(MutexP_Handle handle, uintptr_t key)
+{
+	ARG_UNUSED(key);
+
+	k_mutex_unlock((struct k_mutex *)handle);
+}
diff --git a/ext/hal/ti/simplelink/kernel/zephyr/dpl/SemaphoreP_zephyr.c b/ext/hal/ti/simplelink/kernel/zephyr/dpl/SemaphoreP_zephyr.c
new file mode 100644
index 0000000..7d9816b
--- /dev/null
+++ b/ext/hal/ti/simplelink/kernel/zephyr/dpl/SemaphoreP_zephyr.c
@@ -0,0 +1,140 @@
+/*
+ * Copyright (c) 2017, Texas Instruments Incorporated
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+#include <zephyr.h>
+#include <misc/__assert.h>
+#include <kernel/zephyr/dpl/dpl.h>
+#include <ti/drivers/dpl/SemaphoreP.h>
+
+/*
+ * Zephyr kernel object pools:
+ *
+ * This bit of code enables the simplelink host driver, which assumes dynamic
+ * allocation of kernel objects (semaphores, mutexes, hwis), to be
+ * more easily ported to Zephyr (which supports static allocation).
+ *
+ * It leverages the Zephyr memory slab, enabling us to define a semaphore
+ * object pool for use by the SimpleLink host driver.
+ */
+#define DPL_MAX_SEMAPHORES 14  /* (user.h:MAX_CONCURRENT_ACTIONS+4) = 14 */
+K_MEM_SLAB_DEFINE(sem_slab, sizeof(struct k_sem), DPL_MAX_SEMAPHORES,\
+		  MEM_ALIGN);
+
+static struct k_sem *dpl_sem_pool_alloc()
+{
+	struct k_sem *sem_ptr = NULL;
+
+	if (k_mem_slab_alloc(&sem_slab, (void **)&sem_ptr, K_NO_WAIT) < 0) {
+		/*
+		 * We assert, as this is a logic error, due to a change in #
+		 * of semaphores needed by the simplelink driver. In that case,
+		 * the sem pool must be increased programmatically to match.
+		 */
+		 __ASSERT(0, "Increase size of DPL semaphore pool");
+	}
+	return sem_ptr;
+}
+
+static SemaphoreP_Status dpl_sem_pool_free(struct k_sem *sem)
+{
+	k_mem_slab_free(&sem_slab, (void **)&sem);
+
+	return SemaphoreP_OK;
+}
+
+/* timeout comes in and out as milliSeconds: */
+static int32_t dpl_convert_timeout(uint32_t timeout)
+{
+	int32_t zephyr_timeout;
+
+	switch(timeout) {
+	case SemaphoreP_NO_WAIT:
+		zephyr_timeout = K_NO_WAIT;
+		break;
+	case SemaphoreP_WAIT_FOREVER:
+		zephyr_timeout = K_FOREVER;
+		break;
+	default:
+		zephyr_timeout = timeout;
+	}
+	return zephyr_timeout;
+}
+
+
+SemaphoreP_Handle SemaphoreP_create(unsigned int count,
+				    SemaphoreP_Params *params)
+{
+	unsigned int limit = UINT_MAX;
+	struct k_sem *sem;
+
+	if (params) {
+		limit = (params->mode == SemaphoreP_Mode_BINARY) ?
+			1 : UINT_MAX;
+	}
+
+	sem = dpl_sem_pool_alloc();
+	if (sem) {
+		k_sem_init(sem, 0, limit);
+	}
+
+	return (SemaphoreP_Handle)sem;
+}
+
+SemaphoreP_Handle SemaphoreP_createBinary(unsigned int count)
+{
+	SemaphoreP_Params params;
+
+	SemaphoreP_Params_init(&params);
+	params.mode = SemaphoreP_Mode_BINARY;
+
+	return (SemaphoreP_create(count, &params));
+}
+
+
+void SemaphoreP_delete(SemaphoreP_Handle handle)
+{
+	k_sem_reset((struct k_sem *)handle);
+
+	(void)dpl_sem_pool_free((struct k_sem *)handle);
+}
+
+void SemaphoreP_Params_init(SemaphoreP_Params *params)
+{
+	params->mode = SemaphoreP_Mode_COUNTING;
+	params->callback = NULL;
+}
+
+/*
+ * The SimpleLink driver calls this function with a timeout of 0 to "clear"
+ * the SyncObject, rather than calling dpl_SyncObjClear() directly.
+ * See: <simplelinksdk>/source/ti/drivers/net/wifi/source/driver.h
+ *  #define SL_DRV_SYNC_OBJ_CLEAR(pObj)
+ *	    (void)sl_SyncObjWait(pObj,SL_OS_NO_WAIT);
+ *
+ * So, we claim (via simplelink driver code inspection), that SyncObjWait
+ * will *only* be called with timeout == 0 if the intention is to clear the
+ * semaphore: in that case, we just call k_sem_reset.
+ */
+SemaphoreP_Status SemaphoreP_pend(SemaphoreP_Handle handle, uint32_t timeout)
+{
+	int retval;
+
+	if (0 == timeout) {
+		k_sem_reset((struct k_sem *)handle);
+		retval = SemaphoreP_OK;
+	} else {
+		retval = k_sem_take((struct k_sem *)handle,
+				    dpl_convert_timeout(timeout));
+		__ASSERT_NO_MSG(retval != -EBUSY);
+		retval = (retval >= 0) ? SemaphoreP_OK : SemaphoreP_TIMEOUT;
+	}
+	return retval;
+}
+
+void SemaphoreP_post(SemaphoreP_Handle handle)
+{
+	k_sem_give((struct k_sem *)handle);
+}
diff --git a/ext/hal/ti/simplelink/kernel/zephyr/dpl/dpl.c b/ext/hal/ti/simplelink/kernel/zephyr/dpl/dpl.c
new file mode 100644
index 0000000..b8d210d
--- /dev/null
+++ b/ext/hal/ti/simplelink/kernel/zephyr/dpl/dpl.c
@@ -0,0 +1,116 @@
+/*
+ * Copyright (c) 2017, Texas Instruments Incorporated
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <zephyr.h>
+#include <device.h>
+#include <init.h>
+#include <misc/util.h>
+#include <misc/__assert.h>
+
+#include <inc/hw_types.h>
+#include <inc/hw_ints.h>
+#include <driverlib/rom_map.h>
+#include <driverlib/interrupt.h>
+
+#include <ti/drivers/net/wifi/simplelink.h>
+#include <kernel/zephyr/dpl/dpl.h>
+
+#define	 SPAWN_TASK_STACKSIZE  2048
+/*
+ * Priority must be higher than any thread priority in the system which
+ * might use the SimpleLink host driver, which involves the spawn_task().
+ * Since SimpleLink APIs may be called from any thread, including
+ * cooperative threads, and the _main kernel thread, we must set this
+ * as highest prioirty.
+ */
+#define	 SPAWN_TASK_PRIORITY   K_HIGHEST_THREAD_PRIO
+
+/* Spawn message queue size: Could be 1, but 3 is used by other DPL ports */
+#define SPAWN_QUEUE_SIZE  ( 3 )
+
+/* Stack, for the simplelink spawn task: */
+static K_THREAD_STACK_DEFINE(spawn_task_stack, SPAWN_TASK_STACKSIZE);
+static struct k_thread spawn_task_data;
+
+static void spawn_task(void *unused1, void *unused2, void *unused3);
+
+/*
+ * MessageQ to send message from an ISR or other task to the SimpleLink
+ * "Spawn" task:
+ */
+K_MSGQ_DEFINE(spawn_msgq, sizeof(tSimpleLinkSpawnMsg), SPAWN_QUEUE_SIZE,\
+	      MEM_ALIGN);
+
+/*
+ * SimpleLink does not have an init hook, so we export this function to
+ * be called early during system initialization.
+ */
+static int dpl_zephyr_init(struct device *port)
+{
+	(void)k_thread_create(&spawn_task_data, spawn_task_stack,
+			SPAWN_TASK_STACKSIZE, spawn_task,
+			NULL, NULL, NULL,
+			SPAWN_TASK_PRIORITY, 0, K_NO_WAIT);
+	return 0;
+}
+SYS_INIT(dpl_zephyr_init, POST_KERNEL, CONFIG_KERNEL_INIT_PRIORITY_DEFAULT);
+
+/* SimpleLink driver code can call this from ISR or task context: */
+_SlReturnVal_t os_Spawn(P_OS_SPAWN_ENTRY pEntry, void *pValue,
+			unsigned long flags)
+{
+	tSimpleLinkSpawnMsg slMsg;
+	_SlReturnVal_t retval;
+
+	slMsg.pEntry = pEntry;
+	slMsg.pValue = pValue;
+
+	if (0 == k_msgq_put(&spawn_msgq, &slMsg, K_NO_WAIT)) {
+		retval = OS_OK;
+	}
+	else {
+		retval = -1;
+		__ASSERT(retval == OS_OK,
+			 "os_Spawn: Failed to k_msgq_put failed\r\n");
+
+	}
+
+	return retval;
+}
+
+void spawn_task(void *unused1, void *unused2, void *unused3)
+{
+	tSimpleLinkSpawnMsg slMsg;
+
+	ARG_UNUSED(unused1);
+	ARG_UNUSED(unused2);
+	ARG_UNUSED(unused3);
+
+	while (1) {
+		k_msgq_get(&spawn_msgq, &slMsg, K_FOREVER);
+		slMsg.pEntry(slMsg.pValue);
+	}
+}
+
+#if CONFIG_ERRNO && !defined(SL_INC_INTERNAL_ERRNO)
+/*
+ * Called by the SimpleLink host driver to set POSIX error codes
+ * for the host OS.
+ */
+int dpl_set_errno(int err)
+{
+	/* Ensure (POSIX) errno is positive.
+	 * __errno() is a Zephyr function returning a pointer to the
+	 * current thread's errno variable.
+	 */
+	*__errno() = (err < 0? -err : err);
+	return -1;
+}
+#endif
diff --git a/ext/hal/ti/simplelink/kernel/zephyr/dpl/dpl.h b/ext/hal/ti/simplelink/kernel/zephyr/dpl/dpl.h
new file mode 100644
index 0000000..3642a74
--- /dev/null
+++ b/ext/hal/ti/simplelink/kernel/zephyr/dpl/dpl.h
@@ -0,0 +1,9 @@
+/*
+ * Copyright (c) 2017, Texas Instruments Incorporated
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+#define MEM_ALIGN (sizeof(uint32_t))
+
+extern int *__errno(void);
diff --git a/ext/hal/ti/simplelink/source/ti/drivers/net/wifi/porting/CC3220SF_LAUNCHXL.c b/ext/hal/ti/simplelink/source/ti/drivers/net/wifi/porting/CC3220SF_LAUNCHXL.c
new file mode 100644
index 0000000..43984af
--- /dev/null
+++ b/ext/hal/ti/simplelink/source/ti/drivers/net/wifi/porting/CC3220SF_LAUNCHXL.c
@@ -0,0 +1,122 @@
+/*
+ * Copyright (c) 2017, Texas Instruments Incorporated
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ */
+
+/* =========================== SPI Driver Fxns ========================= */
+#include <ti/devices/cc32xx/inc/hw_ints.h>
+#include <ti/devices/cc32xx/inc/hw_memmap.h>
+#include <ti/devices/cc32xx/inc/hw_types.h>
+
+#include <ti/devices/cc32xx/driverlib/rom_map.h>
+#include <ti/devices/cc32xx/driverlib/prcm.h>
+#include <ti/devices/cc32xx/driverlib/spi.h>
+#include <ti/devices/cc32xx/driverlib/udma.h>
+
+typedef enum CC3220SF_LAUNCHXL_SPIName {
+    CC3220SF_LAUNCHXL_SPI0 = 0,
+    CC3220SF_LAUNCHXL_SPICOUNT
+} CC3220SF_LAUNCHXL_SPIName;
+
+#include <ti/drivers/SPI.h>
+#include <ti/drivers/spi/SPICC32XXDMA.h>
+
+SPICC32XXDMA_Object spiCC3220SDMAObjects[CC3220SF_LAUNCHXL_SPICOUNT];
+
+__attribute__ ((aligned (32)))
+uint32_t spiCC3220SDMAscratchBuf[CC3220SF_LAUNCHXL_SPICOUNT];
+
+const SPICC32XXDMA_HWAttrsV1 spiCC3220SDMAHWAttrs[CC3220SF_LAUNCHXL_SPICOUNT] = {
+    /* index 0 is reserved for LSPI that links to the NWP */
+    {
+	.baseAddr = LSPI_BASE,
+	.intNum = INT_LSPI,
+	.intPriority = (~0),
+	.spiPRCM = PRCM_LSPI,
+	.csControl = SPI_SW_CTRL_CS,
+	.csPolarity = SPI_CS_ACTIVEHIGH,
+	.pinMode = SPI_4PIN_MODE,
+	.turboMode = SPI_TURBO_OFF,
+	.scratchBufPtr = &spiCC3220SDMAscratchBuf[CC3220SF_LAUNCHXL_SPI0],
+	.defaultTxBufValue = 0,
+	.rxChannelIndex = UDMA_CH12_LSPI_RX,
+	.txChannelIndex = UDMA_CH13_LSPI_TX,
+	.minDmaTransferSize = 100,
+	.mosiPin = SPICC32XXDMA_PIN_NO_CONFIG,
+	.misoPin = SPICC32XXDMA_PIN_NO_CONFIG,
+	.clkPin = SPICC32XXDMA_PIN_NO_CONFIG,
+	.csPin = SPICC32XXDMA_PIN_NO_CONFIG
+    }
+};
+
+const SPI_Config SPI_config[CC3220SF_LAUNCHXL_SPICOUNT] = {
+    {
+	.fxnTablePtr = &SPICC32XXDMA_fxnTable,
+	.object = &spiCC3220SDMAObjects[CC3220SF_LAUNCHXL_SPI0],
+	.hwAttrs = &spiCC3220SDMAHWAttrs[CC3220SF_LAUNCHXL_SPI0]
+    }
+};
+
+const uint_least8_t SPI_count = CC3220SF_LAUNCHXL_SPICOUNT;
+
+/*
+ *  =============================== DMA ===============================
+ */
+#include <ti/drivers/dma/UDMACC32XX.h>
+
+__attribute__ ((aligned (1024)))
+static tDMAControlTable dmaControlTable[64];
+
+/*
+ *  ======== dmaErrorFxn ========
+ *  This is the handler for the uDMA error interrupt.
+ */
+static void dmaErrorFxn(uintptr_t arg)
+{
+    int status = MAP_uDMAErrorStatusGet();
+    MAP_uDMAErrorStatusClear();
+
+    /* Suppress unused variable warning */
+    (void)status;
+
+    while (1);
+}
+
+UDMACC32XX_Object udmaCC3220SObject;
+
+const UDMACC32XX_HWAttrs udmaCC3220SHWAttrs = {
+    .controlBaseAddr = (void *)dmaControlTable,
+    .dmaErrorFxn = (UDMACC32XX_ErrorFxn)dmaErrorFxn,
+    .intNum = INT_UDMAERR,
+    .intPriority = (~0)
+};
+
+const UDMACC32XX_Config UDMACC32XX_config = {
+    .object = &udmaCC3220SObject,
+    .hwAttrs = &udmaCC3220SHWAttrs
+};
+
+
+void CC3220SF_LAUNCHXL_init()
+{
+	MAP_PRCMLPDSWakeupSourceEnable(PRCM_LPDS_HOST_IRQ);
+	SPI_init();
+}
+
+#if defined(__SF_DEBUG__)
+#if defined(__TI_COMPILER_VERSION__)
+#pragma DATA_SECTION(ulDebugHeader, ".dbghdr")
+#elif defined(__IAR_SYSTEMS_ICC__)
+#pragma data_location=".dbghdr"
+#elif defined(__GNUC__)
+__attribute__ ((section (".dbghdr")))
+#endif
+const unsigned long ulDebugHeader[]=
+{
+                0x5AA5A55A,
+                0x000FF800,
+                0xEFA3247D
+};
+#endif
diff --git a/ext/hal/ti/simplelink/source/ti/drivers/net/wifi/porting/CC3220SF_LAUNCHXL.h b/ext/hal/ti/simplelink/source/ti/drivers/net/wifi/porting/CC3220SF_LAUNCHXL.h
new file mode 100644
index 0000000..c39e308
--- /dev/null
+++ b/ext/hal/ti/simplelink/source/ti/drivers/net/wifi/porting/CC3220SF_LAUNCHXL.h
@@ -0,0 +1,21 @@
+/*
+ * Copyright (c) 2017, Texas Instruments Incorporated
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ */
+
+#ifndef _CC3220SF_LAUNCHXL_H_
+#define _CC3220SF_LAUNCHXL_H_
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+extern void CC3220SF_LAUNCHXL_init();
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _CC3220SF_LAUNCHXL_H_ */
diff --git a/ext/hal/ti/simplelink/source/ti/drivers/net/wifi/porting/user.h b/ext/hal/ti/simplelink/source/ti/drivers/net/wifi/porting/user.h
index 0ffddd5..35b99bf 100644
--- a/ext/hal/ti/simplelink/source/ti/drivers/net/wifi/porting/user.h
+++ b/ext/hal/ti/simplelink/source/ti/drivers/net/wifi/porting/user.h
@@ -956,10 +956,11 @@
     
     \warning                User must implement it's own 'os_Spawn' function.
 */
-//#define SL_PLATFORM_EXTERNAL_SPAWN
+#define SL_PLATFORM_EXTERNAL_SPAWN
 
 #ifdef SL_PLATFORM_EXTERNAL_SPAWN
-#define sl_Spawn(pEntry,pValue,flags)       os_Spawn(pEntry,pValue,flags)        
+extern  _i16 os_Spawn(P_OS_SPAWN_ENTRY pEntry, void *pValue, unsigned long flags);
+#define sl_Spawn(pEntry,pValue,flags)       os_Spawn(pEntry,pValue,flags)
 #endif
 
 /*!