From 8e7a0fbb268626bec2310ac48b5c88d967d56199 Mon Sep 17 00:00:00 2001 From: Giovanni Di Sirio Date: Fri, 25 May 2018 07:45:18 +0000 Subject: Added an enhanced variant of QSPI named WSPI. QSPI will be deprecated when WSPI will be phased in. git-svn-id: svn://svn.code.sf.net/p/chibios/svn/trunk@12043 110e8d01-0319-4d1e-a829-52ad28d1bb01 --- os/hal/src/hal_wspi.c | 392 ++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 392 insertions(+) create mode 100644 os/hal/src/hal_wspi.c (limited to 'os/hal/src/hal_wspi.c') diff --git a/os/hal/src/hal_wspi.c b/os/hal/src/hal_wspi.c new file mode 100644 index 000000000..10a0aec24 --- /dev/null +++ b/os/hal/src/hal_wspi.c @@ -0,0 +1,392 @@ +/* + ChibiOS - Copyright (C) 2006..2018 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_wspi.c + * @brief WSPI Driver code. + * + * @addtogroup WSPI + * @{ + */ + +#include "hal.h" + +#if (HAL_USE_WSPI == TRUE) || defined(__DOXYGEN__) + +/*===========================================================================*/ +/* Driver local definitions. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Driver exported variables. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Driver local variables and types. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Driver local functions. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Driver exported functions. */ +/*===========================================================================*/ + +/** + * @brief WSPI Driver initialization. + * @note This function is implicitly invoked by @p halInit(), there is + * no need to explicitly initialize the driver. + * + * @init + */ +void wspiInit(void) { + + wspi_lld_init(); +} + +/** + * @brief Initializes the standard part of a @p WSPIDriver structure. + * + * @param[out] wspip pointer to the @p WSPIDriver object + * + * @init + */ +void wspiObjectInit(WSPIDriver *wspip) { + + wspip->state = WSPI_STOP; + wspip->config = NULL; +#if WSPI_USE_WAIT == TRUE + wspip->thread = NULL; +#endif +#if WSPI_USE_MUTUAL_EXCLUSION == TRUE + osalMutexObjectInit(&wspip->mutex); +#endif +#if defined(WSPI_DRIVER_EXT_INIT_HOOK) + WSPI_DRIVER_EXT_INIT_HOOK(wspip); +#endif +} + +/** + * @brief Configures and activates the WSPI peripheral. + * + * @param[in] wspip pointer to the @p WSPIDriver object + * @param[in] config pointer to the @p WSPIConfig object + * + * @api + */ +void wspiStart(WSPIDriver *wspip, const WSPIConfig *config) { + + osalDbgCheck((wspip != NULL) && (config != NULL)); + + osalSysLock(); + + osalDbgAssert((wspip->state == WSPI_STOP) || (wspip->state == WSPI_READY), + "invalid state"); + + wspip->config = config; + wspi_lld_start(wspip); + wspip->state = WSPI_READY; + + osalSysUnlock(); +} + +/** + * @brief Deactivates the WSPI peripheral. + * @note Deactivating the peripheral also enforces a release of the slave + * select line. + * + * @param[in] wspip pointer to the @p WSPIDriver object + * + * @api + */ +void wspiStop(WSPIDriver *wspip) { + + osalDbgCheck(wspip != NULL); + + osalSysLock(); + + osalDbgAssert((wspip->state == WSPI_STOP) || (wspip->state == WSPI_READY), + "invalid state"); + + wspi_lld_stop(wspip); + wspip->config = NULL; + wspip->state = WSPI_STOP; + + osalSysUnlock(); +} + +/** + * @brief Sends a command without data phase. + * @post At the end of the operation the configured callback is invoked. + * + * @param[in] wspip pointer to the @p WSPIDriver object + * @param[in] cmdp pointer to the command descriptor + * + * @api + */ +void wspiStartCommand(WSPIDriver *wspip, const wspi_command_t *cmdp) { + + osalDbgCheck((wspip != NULL) && (cmdp != NULL)); + + osalSysLock(); + + osalDbgAssert(wspip->state == WSPI_READY, "not ready"); + + wspiStartCommandI(wspip, cmdp); + + osalSysUnlock(); +} + +/** + * @brief Sends a command with data over the WSPI bus. + * @post At the end of the operation the configured callback is invoked. + * + * @param[in] wspip pointer to the @p WSPIDriver object + * @param[in] cmdp pointer to the command descriptor + * @param[in] n number of bytes to send + * @param[in] txbuf the pointer to the transmit buffer + * + * @api + */ +void wspiStartSend(WSPIDriver *wspip, const wspi_command_t *cmdp, + size_t n, const uint8_t *txbuf) { + + osalDbgCheck((wspip != NULL) && (cmdp != NULL)); + osalDbgCheck((n > 0U) && (txbuf != NULL)); + + osalSysLock(); + + osalDbgAssert(wspip->state == WSPI_READY, "not ready"); + + wspiStartSendI(wspip, cmdp, n, txbuf); + + osalSysUnlock(); +} + +/** + * @brief Sends a command then receives data over the WSPI bus. + * @post At the end of the operation the configured callback is invoked. + * + * @param[in] wspip pointer to the @p WSPIDriver object + * @param[in] cmdp pointer to the command descriptor + * @param[in] n number of bytes to send + * @param[out] rxbuf the pointer to the receive buffer + * + * @api + */ +void wspiStartReceive(WSPIDriver *wspip, const wspi_command_t *cmdp, + size_t n, uint8_t *rxbuf) { + + osalDbgCheck((wspip != NULL) && (cmdp != NULL)); + osalDbgCheck((n > 0U) && (rxbuf != NULL)); + + osalSysLock(); + + osalDbgAssert(wspip->state == WSPI_READY, "not ready"); + + wspiStartReceiveI(wspip, cmdp, n, rxbuf); + + osalSysUnlock(); +} + +#if (WSPI_USE_WAIT == TRUE) || defined(__DOXYGEN__) +/** + * @brief Sends a command without data phase. + * @pre In order to use this function the option @p WSPI_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). + * + * @param[in] wspip pointer to the @p WSPIDriver object + * @param[in] cmdp pointer to the command descriptor + * + * @api + */ +void wspiCommand(WSPIDriver *wspip, const wspi_command_t *cmdp) { + + osalDbgCheck((wspip != NULL) && (cmdp != NULL)); + osalDbgCheck((cmdp->cfg & WSPI_CFG_DATA_MODE_MASK) == WSPI_CFG_DATA_MODE_NONE); + + osalSysLock(); + + osalDbgAssert(wspip->state == WSPI_READY, "not ready"); + osalDbgAssert(wspip->config->end_cb == NULL, "has callback"); + + wspiStartCommandI(wspip, cmdp); + (void) osalThreadSuspendS(&wspip->thread); + + osalSysUnlock(); +} + +/** + * @brief Sends a command with data over the WSPI bus. + * @pre In order to use this function the option @p WSPI_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). + * + * @param[in] wspip pointer to the @p WSPIDriver object + * @param[in] cmdp pointer to the command descriptor + * @param[in] n number of bytes to send + * @param[in] txbuf the pointer to the transmit buffer + * + * @api + */ +void wspiSend(WSPIDriver *wspip, const wspi_command_t *cmdp, + size_t n, const uint8_t *txbuf) { + + osalDbgCheck((wspip != NULL) && (cmdp != NULL)); + osalDbgCheck((n > 0U) && (txbuf != NULL)); + osalDbgCheck((cmdp->cfg & WSPI_CFG_DATA_MODE_MASK) != WSPI_CFG_DATA_MODE_NONE); + + osalSysLock(); + + osalDbgAssert(wspip->state == WSPI_READY, "not ready"); + osalDbgAssert(wspip->config->end_cb == NULL, "has callback"); + + wspiStartSendI(wspip, cmdp, n, txbuf); + (void) osalThreadSuspendS(&wspip->thread); + + osalSysUnlock(); +} + +/** + * @brief Sends a command then receives data over the WSPI bus. + * @pre In order to use this function the option @p WSPI_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). + * + * @param[in] wspip pointer to the @p WSPIDriver object + * @param[in] cmdp pointer to the command descriptor + * @param[in] n number of bytes to send + * @param[out] rxbuf the pointer to the receive buffer + * + * @api + */ +void wspiReceive(WSPIDriver *wspip, const wspi_command_t *cmdp, + size_t n, uint8_t *rxbuf) { + + osalDbgCheck((wspip != NULL) && (cmdp != NULL)); + osalDbgCheck((n > 0U) && (rxbuf != NULL)); + osalDbgCheck((cmdp->cfg & WSPI_CFG_DATA_MODE_MASK) != WSPI_CFG_DATA_MODE_NONE); + + osalSysLock(); + + osalDbgAssert(wspip->state == WSPI_READY, "not ready"); + osalDbgAssert(wspip->config->end_cb == NULL, "has callback"); + + wspiStartReceiveI(wspip, cmdp, n, rxbuf); + (void) osalThreadSuspendS(&wspip->thread); + + osalSysUnlock(); +} +#endif /* WSPI_USE_WAIT == TRUE */ + +#if (WSPI_SUPPORTS_MEMMAP == TRUE) || defined(__DOXYGEN__) +/** + * @brief Maps in memory space a WSPI flash device. + * @pre The memory flash device must be initialized appropriately + * before mapping it in memory space. + * + * @param[in] wspip pointer to the @p WSPIDriver object + * @param[in] cmdp pointer to the command descriptor + * @param[out] addrp pointer to the memory start address of the mapped + * flash or @p NULL + * + * @api + */ +void wspiMapFlash(WSPIDriver *wspip, + const wspi_command_t *cmdp, + uint8_t **addrp) { + + osalDbgCheck((wspip != NULL) && (cmdp != NULL)); + osalDbgCheck((cmdp->cfg & WSPI_CFG_DATA_MODE_MASK) != WSPI_CFG_DATA_MODE_NONE); + + osalSysLock(); + + osalDbgAssert(wspip->state == WSPI_READY, "not ready"); + + wspiMapFlashI(wspip, cmdp, addrp); + wspip->state = WSPI_MEMMAP; + + osalSysUnlock(); +} + +/** + * @brief Unmaps from memory space a WSPI flash device. + * @post The memory flash device must be re-initialized for normal + * commands exchange. + * + * @param[in] wspip pointer to the @p WSPIDriver object + * + * @api + */ +void wspiUnmapFlash(WSPIDriver *wspip) { + + osalDbgCheck(wspip != NULL); + + osalSysLock(); + + osalDbgAssert(wspip->state == WSPI_MEMMAP, "not ready"); + + wspiUnmapFlashI(wspip); + wspip->state = WSPI_READY; + + osalSysUnlock(); +} +#endif /* WSPI_SUPPORTS_MEMMAP == TRUE */ + +#if (WSPI_USE_MUTUAL_EXCLUSION == TRUE) || defined(__DOXYGEN__) +/** + * @brief Gains exclusive access to the WSPI bus. + * @details This function tries to gain ownership to the WSPI bus, if the bus + * is already being used then the invoking thread is queued. + * @pre In order to use this function the option @p WSPI_USE_MUTUAL_EXCLUSION + * must be enabled. + * + * @param[in] wspip pointer to the @p WSPIDriver object + * + * @api + */ +void wspiAcquireBus(WSPIDriver *wspip) { + + osalDbgCheck(wspip != NULL); + + osalMutexLock(&wspip->mutex); +} + +/** + * @brief Releases exclusive access to the WSPI bus. + * @pre In order to use this function the option @p WSPI_USE_MUTUAL_EXCLUSION + * must be enabled. + * + * @param[in] wspip pointer to the @p WSPIDriver object + * + * @api + */ +void wspiReleaseBus(WSPIDriver *wspip) { + + osalDbgCheck(wspip != NULL); + + osalMutexUnlock(&wspip->mutex); +} +#endif /* WSPI_USE_MUTUAL_EXCLUSION == TRUE */ + +#endif /* HAL_USE_WSPI == TRUE */ + +/** @} */ -- cgit v1.2.3