aboutsummaryrefslogtreecommitdiffstats
path: root/os/hal
diff options
context:
space:
mode:
Diffstat (limited to 'os/hal')
-rw-r--r--os/hal/include/hal_qspi.h249
-rw-r--r--os/hal/src/hal_qspi.c263
2 files changed, 512 insertions, 0 deletions
diff --git a/os/hal/include/hal_qspi.h b/os/hal/include/hal_qspi.h
new file mode 100644
index 000000000..391af6666
--- /dev/null
+++ b/os/hal/include/hal_qspi.h
@@ -0,0 +1,249 @@
+/*
+ ChibiOS - Copyright (C) 2006..2016 Giovanni Di Sirio
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+*/
+
+/**
+ * @file hal_qspi.h
+ * @brief QSPI Driver macros and structures.
+ *
+ * @addtogroup QSPI
+ * @{
+ */
+
+#ifndef HAL_QSPI_H
+#define HAL_QSPI_H
+
+#if (HAL_USE_QSPI == TRUE) || defined(__DOXYGEN__)
+
+/*===========================================================================*/
+/* Driver constants. */
+/*===========================================================================*/
+
+#define QSPI_CFG_CMD_MASK (0xFFU << 0U)
+#define QSPI_CFG_CMD(n) ((n) << 0U)
+#define QSPI_CFG_CMD_MODE_MASK (3U << 8U)
+#define QSPI_CFG_CMD_MODE_NONE (0U << 8U)
+#define QSPI_CFG_CMD_MODE_ONE_LINE (1U << 8U)
+#define QSPI_CFG_CMD_MODE_TWO_LINES (2U << 8U)
+#define QSPI_CFG_CMD_MODE_FOUR_LINES (3U << 8U)
+#define QSPI_CFG_ADDR_MODE_MASK (3U << 10U)
+#define QSPI_CFG_ADDR_MODE_NONE (0U << 10U)
+#define QSPI_CFG_ADDR_MODE_ONE_LINE (1U << 10U)
+#define QSPI_CFG_ADDR_MODE_TWO_LINES (2U << 10U)
+#define QSPI_CFG_ADDR_MODE_FOUR_LINES (3U << 10U)
+#define QSPI_CFG_ADDR_SIZE_MASK (3U << 12U)
+#define QSPI_CFG_ADDR_SIZE_8 (0U << 12U)
+#define QSPI_CFG_ADDR_SIZE_16 (1U << 12U)
+#define QSPI_CFG_ADDR_SIZE_24 (2U << 12U)
+#define QSPI_CFG_ADDR_SIZE_32 (3U << 12U)
+#define QSPI_CFG_AB_MODE_MASK (3U << 14U)
+#define QSPI_CFG_AB_MODE_NONE (0U << 14U)
+#define QSPI_CFG_AB_MODE_ONE_LINE (1U << 14U)
+#define QSPI_CFG_AB_MODE_TWO_LINES (2U << 14U)
+#define QSPI_CFG_AB_MODE_FOUR_LINES (3U << 14U)
+#define QSPI_CFG_AB_SIZE_MASK (3U << 16U)
+#define QSPI_CFG_AB_SIZE_8 (0U << 16U)
+#define QSPI_CFG_AB_SIZE_16 (1U << 16U)
+#define QSPI_CFG_AB_SIZE_24 (2U << 16U)
+#define QSPI_CFG_AB_SIZE_32 (3U << 16U)
+#define QSPI_CFG_DUMMY_CYCLES_MASK (0x1FU << 18U)
+#define QSPI_CFG_DUMMY_CYCLES(n) ((n) << 18U)
+#define QSPI_CFG_DATA_MODE_MASK (3U << 24U)
+#define QSPI_CFG_DATA_MODE_NONE (0U << 24U)
+#define QSPI_CFG_DATA_MODE_ONE_LINE (1U << 24U)
+#define QSPI_CFG_DATA_MODE_TWO_LINES (2U << 24U)
+#define QSPI_CFG_DATA_MODE_FOUR_LINES (3U << 24U)
+#define QSPI_CFG_F_MODE_MASK (3U << 26U)
+#define QSPI_CFG_F_MODE_INDIRECT_WRITE (0U << 26U)
+#define QSPI_CFG_F_MODE_INDIRECT_READ (1U << 26U)
+#define QSPI_CFG_F_MODE_MEMORY_MAPPED (2U << 26U)
+#define QSPI_CFG_F_MODE_FOUR_LINES (3U << 26U)
+#define QSPI_CFG_SIOO (1U << 28U)
+#define QSPI_CFG_DDRM (1U << 31U)
+
+/*===========================================================================*/
+/* Driver pre-compile time settings. */
+/*===========================================================================*/
+
+/**
+ * @name QSPI configuration options
+ * @{
+ */
+/**
+ * @brief Enables synchronous APIs.
+ * @note Disabling this option saves both code and data space.
+ */
+#if !defined(QSPI_USE_WAIT) || defined(__DOXYGEN__)
+#define QSPI_USE_WAIT TRUE
+#endif
+
+/**
+ * @brief Enables the @p qspiAcquireBus() and @p qspiReleaseBus() APIs.
+ * @note Disabling this option saves both code and data space.
+ */
+#if !defined(QSPI_USE_MUTUAL_EXCLUSION) || defined(__DOXYGEN__)
+#define QSPI_USE_MUTUAL_EXCLUSION TRUE
+#endif
+/** @} */
+
+/*===========================================================================*/
+/* Derived constants and error checks. */
+/*===========================================================================*/
+
+/*===========================================================================*/
+/* Driver data structures and types. */
+/*===========================================================================*/
+
+/**
+ * @brief Driver state machine possible states.
+ */
+typedef enum {
+ QSPI_UNINIT = 0, /**< Not initialized. */
+ QSPI_STOP = 1, /**< Stopped. */
+ QSPI_READY = 2, /**< Ready. */
+ QSPI_ACTIVE = 3, /**< Exchanging data. */
+ QSPI_COMPLETE = 4 /**< Asynchronous operation complete. */
+} qspistate_t;
+
+/**
+ * @brief Type of a QSPI transaction descriptor.
+ */
+typedef struct {
+ uint32_t cfg;
+ uint32_t address;
+ uint32_t alternate;
+} qspitransaction_t;
+
+#include "hal_spi_lld.h"
+
+/*===========================================================================*/
+/* Driver macros. */
+/*===========================================================================*/
+
+/**
+ * @name Macro Functions
+ * @{
+ */
+/**
+ * @brief Sends data over the QSPI bus.
+ * @details This asynchronous function starts a transmit operation.
+ * @post At the end of the operation the configured callback is invoked.
+ *
+ * @param[in] qspip pointer to the @p QSPIDriver object
+ * @param[in] n number of bytes to send
+ * @param[in] txbuf the pointer to the transmit buffer
+ *
+ * @iclass
+ */
+#define qspiStartSendI(qspip, n, txbuf) { \
+ (qspip)->state = QSPI_ACTIVE; \
+ qspi_lld_send(qspip, n, txbuf); \
+}
+
+/**
+ * @brief Receives data from the QSPI bus.
+ * @details This asynchronous function starts a receive operation.
+ * @post At the end of the operation the configured callback is invoked.
+ *
+ * @param[in] qspip pointer to the @p QSPIDriver object
+ * @param[in] n number of bytes to receive
+ * @param[out] rxbuf the pointer to the receive buffer
+ *
+ * @iclass
+ */
+#define qspiStartReceiveI(qspip, n, rxbuf) { \
+ (qspip)->state = QSPI_ACTIVE; \
+ qspi_lld_receive(qspip, n, rxbuf); \
+}
+/** @} */
+
+/**
+ * @name Low level driver helper macros
+ * @{
+ */
+#if (QSPI_USE_WAIT == TRUE) || defined(__DOXYGEN__)
+/**
+ * @brief Wakes up the waiting thread.
+ *
+ * @param[in] qspip pointer to the @p QSPIDriver object
+ *
+ * @notapi
+ */
+#define _qspi_wakeup_isr(qspip) { \
+ osalSysLockFromISR(); \
+ osalThreadResumeI(&(qspip)->thread, MSG_OK); \
+ osalSysUnlockFromISR(); \
+}
+#else /* !QSPI_USE_WAIT */
+#define _qspi_wakeup_isr(qspip)
+#endif /* !QSPI_USE_WAIT */
+
+/**
+ * @brief Common ISR code.
+ * @details This code handles the portable part of the ISR code:
+ * - Callback invocation.
+ * - Waiting thread wakeup, if any.
+ * - Driver state transitions.
+ * .
+ * @note This macro is meant to be used in the low level drivers
+ * implementation only.
+ *
+ * @param[in] qspip pointer to the @p QSPIDriver object
+ *
+ * @notapi
+ */
+#define _qspi_isr_code(qspip) { \
+ if ((qspip)->config->end_cb) { \
+ (qspip)->state = QSPI_COMPLETE; \
+ (qspip)->config->end_cb(qspip); \
+ if ((qspip)->state == QSPI_COMPLETE) \
+ (qspip)->state = QSPI_READY; \
+ } \
+ else \
+ (qspip)->state = QSPI_READY; \
+ _qspi_wakeup_isr(qspip); \
+}
+/** @} */
+
+/*===========================================================================*/
+/* External declarations. */
+/*===========================================================================*/
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+ void qspiInit(void);
+ void qspiObjectInit(QSPIDriver *qspip);
+ void qspiStart(QSPIDriver *qspip, const QSPIConfig *config);
+ void qspiStop(QSPIDriver *qspip);
+ void qspiStartSend(QSPIDriver *qspip, size_t n, const void *txbuf);
+ void qspiStartReceive(QSPIDriver *qspip, size_t n, void *rxbuf);
+#if QSPI_USE_WAIT == TRUE
+ void qspiSend(QSPIDriver *qspip, size_t n, const void *txbuf);
+ void qspiReceive(QSPIDriver *qspip, size_t n, void *rxbuf);
+#endif
+#if QSPI_USE_MUTUAL_EXCLUSION == TRUE
+ void qspiAcquireBus(QSPIDriver *qspip);
+ void qspiReleaseBus(QSPIDriver *qspip);
+#endif
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* HAL_USE_QSPI == TRUE */
+
+#endif /* HAL_QSPI_H */
+
+/** @} */
diff --git a/os/hal/src/hal_qspi.c b/os/hal/src/hal_qspi.c
new file mode 100644
index 000000000..e57694925
--- /dev/null
+++ b/os/hal/src/hal_qspi.c
@@ -0,0 +1,263 @@
+/*
+ ChibiOS - Copyright (C) 2006..2016 Giovanni Di Sirio
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+*/
+
+/**
+ * @file hal_qspi.c
+ * @brief QSPI Driver code.
+ *
+ * @addtogroup QSPI
+ * @{
+ */
+
+#include "hal.h"
+
+#if (HAL_USE_QSPI == TRUE) || defined(__DOXYGEN__)
+
+/*===========================================================================*/
+/* Driver local definitions. */
+/*===========================================================================*/
+
+/*===========================================================================*/
+/* Driver exported variables. */
+/*===========================================================================*/
+
+/*===========================================================================*/
+/* Driver local variables and types. */
+/*===========================================================================*/
+
+/*===========================================================================*/
+/* Driver local functions. */
+/*===========================================================================*/
+
+/*===========================================================================*/
+/* Driver exported functions. */
+/*===========================================================================*/
+
+/**
+ * @brief QSPI Driver initialization.
+ * @note This function is implicitly invoked by @p halInit(), there is
+ * no need to explicitly initialize the driver.
+ *
+ * @init
+ */
+void qspiInit(void) {
+
+ qspi_lld_init();
+}
+
+/**
+ * @brief Initializes the standard part of a @p QSPIDriver structure.
+ *
+ * @param[out] qspip pointer to the @p QSPIDriver object
+ *
+ * @init
+ */
+void qspiObjectInit(QSPIDriver *qspip) {
+
+ qspip->state = QSPI_STOP;
+ qspip->config = NULL;
+#if QSPI_USE_WAIT == TRUE
+ qspip->thread = NULL;
+#endif
+#if QSPI_USE_MUTUAL_EXCLUSION == TRUE
+ osalMutexObjectInit(&qspip->mutex);
+#endif
+#if defined(QSPI_DRIVER_EXT_INIT_HOOK)
+ QSPI_DRIVER_EXT_INIT_HOOK(qspip);
+#endif
+}
+
+/**
+ * @brief Configures and activates the QSPI peripheral.
+ *
+ * @param[in] qspip pointer to the @p QSPIDriver object
+ * @param[in] config pointer to the @p QSPIConfig object
+ *
+ * @api
+ */
+void qspiStart(QSPIDriver *qspip, const QSPIConfig *config) {
+
+ osalDbgCheck((qspip != NULL) && (config != NULL));
+
+ osalSysLock();
+ osalDbgAssert((qspip->state == QSPI_STOP) || (qspip->state == QSPI_READY),
+ "invalid state");
+ qspip->config = config;
+ qspi_lld_start(qspip);
+ qspip->state = QSPI_READY;
+ osalSysUnlock();
+}
+
+/**
+ * @brief Deactivates the QSPI peripheral.
+ * @note Deactivating the peripheral also enforces a release of the slave
+ * select line.
+ *
+ * @param[in] qspip pointer to the @p QSPIDriver object
+ *
+ * @api
+ */
+void qspiStop(QSPIDriver *qspip) {
+
+ osalDbgCheck(qspip != NULL);
+
+ osalSysLock();
+ osalDbgAssert((qspip->state == QSPI_STOP) || (qspip->state == QSPI_READY),
+ "invalid state");
+ qspi_lld_stop(qspip);
+ qspip->state = QSPI_STOP;
+ osalSysUnlock();
+}
+
+/**
+ * @brief Sends data over the QSPI bus.
+ * @details This asynchronous function starts a transmit operation.
+ * @post At the end of the operation the configured callback is invoked.
+ *
+ * @param[in] qspip pointer to the @p QSPIDriver object
+ * @param[in] n number of words to send
+ * @param[in] txbuf the pointer to the transmit buffer
+ *
+ * @api
+ */
+void qspiStartSend(QSPIDriver *qspip, size_t n, const void *txbuf) {
+
+ osalDbgCheck((qspip != NULL) && (n > 0U) && (txbuf != NULL));
+
+ osalSysLock();
+ osalDbgAssert(qspip->state == QSPI_READY, "not ready");
+ qspiStartSendI(qspip, n, txbuf);
+ osalSysUnlock();
+}
+
+/**
+ * @brief Receives data from the QSPI bus.
+ * @details This asynchronous function starts a receive operation.
+ * @post At the end of the operation the configured callback is invoked.
+ *
+ * @param[in] qspip pointer to the @p QSPIDriver object
+ * @param[in] n number of words to receive
+ * @param[out] rxbuf the pointer to the receive buffer
+ *
+ * @api
+ */
+void qspiStartReceive(QSPIDriver *qspip, size_t n, void *rxbuf) {
+
+ osalDbgCheck((qspip != NULL) && (n > 0U) && (rxbuf != NULL));
+
+ osalSysLock();
+ osalDbgAssert(qspip->state == QSPI_READY, "not ready");
+ qspiStartReceiveI(qspip, n, rxbuf);
+ osalSysUnlock();
+}
+
+#if (QSPI_USE_WAIT == TRUE) || defined(__DOXYGEN__)
+/**
+ * @brief Sends data over the QSPI bus.
+ * @details This synchronous function performs a transmit operation.
+ * @pre In order to use this function the option @p QSPI_USE_WAIT must be
+ * enabled.
+ * @pre In order to use this function the driver must have been configured
+ * without callbacks (@p end_cb = @p NULL).
+ * @note The buffers are organized as uint8_t arrays for data sizes below
+ * or equal to 8 bits else it is organized as uint16_t arrays.
+ *
+ * @param[in] qspip pointer to the @p QSPIDriver object
+ * @param[in] n number of words to send
+ * @param[in] txbuf the pointer to the transmit buffer
+ *
+ * @api
+ */
+void qspiSend(QSPIDriver *qspip, size_t n, const void *txbuf) {
+
+ osalDbgCheck((qspip != NULL) && (n > 0U) && (txbuf != NULL));
+
+ osalSysLock();
+ osalDbgAssert(qspip->state == QSPI_READY, "not ready");
+ osalDbgAssert(qspip->config->end_cb == NULL, "has callback");
+ qspiStartSendI(qspip, n, txbuf);
+ (void) osalThreadSuspendS(&qspip->thread);
+ osalSysUnlock();
+}
+
+/**
+ * @brief Receives data from the QSPI bus.
+ * @details This synchronous function performs a receive operation.
+ * @pre In order to use this function the option @p QSPI_USE_WAIT must be
+ * enabled.
+ * @pre In order to use this function the driver must have been configured
+ * without callbacks (@p end_cb = @p NULL).
+ * @note The buffers are organized as uint8_t arrays for data sizes below
+ * or equal to 8 bits else it is organized as uint16_t arrays.
+ *
+ * @param[in] qspip pointer to the @p QSPIDriver object
+ * @param[in] n number of words to receive
+ * @param[out] rxbuf the pointer to the receive buffer
+ *
+ * @api
+ */
+void qspiReceive(QSPIDriver *qspip, size_t n, void *rxbuf) {
+
+ osalDbgCheck((qspip != NULL) && (n > 0U) && (rxbuf != NULL));
+
+ osalSysLock();
+ osalDbgAssert(qspip->state == QSPI_READY, "not ready");
+ osalDbgAssert(qspip->config->end_cb == NULL, "has callback");
+ qspiStartReceiveI(qspip, n, rxbuf);
+ (void) osalThreadSuspendS(&qspip->thread);
+ osalSysUnlock();
+}
+#endif /* QSPI_USE_WAIT == TRUE */
+
+#if (QSPI_USE_MUTUAL_EXCLUSION == TRUE) || defined(__DOXYGEN__)
+/**
+ * @brief Gains exclusive access to the QSPI bus.
+ * @details This function tries to gain ownership to the QSPI bus, if the bus
+ * is already being used then the invoking thread is queued.
+ * @pre In order to use this function the option @p QSPI_USE_MUTUAL_EXCLUSION
+ * must be enabled.
+ *
+ * @param[in] qspip pointer to the @p QSPIDriver object
+ *
+ * @api
+ */
+void qspiAcquireBus(QSPIDriver *qspip) {
+
+ osalDbgCheck(qspip != NULL);
+
+ osalMutexLock(&qspip->mutex);
+}
+
+/**
+ * @brief Releases exclusive access to the QSPI bus.
+ * @pre In order to use this function the option @p QSPI_USE_MUTUAL_EXCLUSION
+ * must be enabled.
+ *
+ * @param[in] qspip pointer to the @p QSPIDriver object
+ *
+ * @api
+ */
+void qspiReleaseBus(QSPIDriver *qspip) {
+
+ osalDbgCheck(qspip != NULL);
+
+ osalMutexUnlock(&qspip->mutex);
+}
+#endif /* QSPI_USE_MUTUAL_EXCLUSION == TRUE */
+
+#endif /* HAL_USE_QSPI == TRUE */
+
+/** @} */