| 1 | /*************************************************************************** |
|---|
| 2 | * (c)2007-2010 Broadcom Corporation |
|---|
| 3 | * |
|---|
| 4 | * This program is the proprietary software of Broadcom Corporation and/or its licensors, |
|---|
| 5 | * and may only be used, duplicated, modified or distributed pursuant to the terms and |
|---|
| 6 | * conditions of a separate, written license agreement executed between you and Broadcom |
|---|
| 7 | * (an "Authorized License"). Except as set forth in an Authorized License, Broadcom grants |
|---|
| 8 | * no license (express or implied), right to use, or waiver of any kind with respect to the |
|---|
| 9 | * Software, and Broadcom expressly reserves all rights in and to the Software and all |
|---|
| 10 | * intellectual property rights therein. IF YOU HAVE NO AUTHORIZED LICENSE, THEN YOU |
|---|
| 11 | * HAVE NO RIGHT TO USE THIS SOFTWARE IN ANY WAY, AND SHOULD IMMEDIATELY |
|---|
| 12 | * NOTIFY BROADCOM AND DISCONTINUE ALL USE OF THE SOFTWARE. |
|---|
| 13 | * |
|---|
| 14 | * Except as expressly set forth in the Authorized License, |
|---|
| 15 | * |
|---|
| 16 | * 1. This program, including its structure, sequence and organization, constitutes the valuable trade |
|---|
| 17 | * secrets of Broadcom, and you shall use all reasonable efforts to protect the confidentiality thereof, |
|---|
| 18 | * and to use this information only in connection with your use of Broadcom integrated circuit products. |
|---|
| 19 | * |
|---|
| 20 | * 2. TO THE MAXIMUM EXTENT PERMITTED BY LAW, THE SOFTWARE IS PROVIDED "AS IS" |
|---|
| 21 | * AND WITH ALL FAULTS AND BROADCOM MAKES NO PROMISES, REPRESENTATIONS OR |
|---|
| 22 | * WARRANTIES, EITHER EXPRESS, IMPLIED, STATUTORY, OR OTHERWISE, WITH RESPECT TO |
|---|
| 23 | * THE SOFTWARE. BROADCOM SPECIFICALLY DISCLAIMS ANY AND ALL IMPLIED WARRANTIES |
|---|
| 24 | * OF TITLE, MERCHANTABILITY, NONINFRINGEMENT, FITNESS FOR A PARTICULAR PURPOSE, |
|---|
| 25 | * LACK OF VIRUSES, ACCURACY OR COMPLETENESS, QUIET ENJOYMENT, QUIET POSSESSION |
|---|
| 26 | * OR CORRESPONDENCE TO DESCRIPTION. YOU ASSUME THE ENTIRE RISK ARISING OUT OF |
|---|
| 27 | * USE OR PERFORMANCE OF THE SOFTWARE. |
|---|
| 28 | * |
|---|
| 29 | * 3. TO THE MAXIMUM EXTENT PERMITTED BY LAW, IN NO EVENT SHALL BROADCOM OR ITS |
|---|
| 30 | * LICENSORS BE LIABLE FOR (i) CONSEQUENTIAL, INCIDENTAL, SPECIAL, INDIRECT, OR |
|---|
| 31 | * EXEMPLARY DAMAGES WHATSOEVER ARISING OUT OF OR IN ANY WAY RELATING TO YOUR |
|---|
| 32 | * USE OF OR INABILITY TO USE THE SOFTWARE EVEN IF BROADCOM HAS BEEN ADVISED OF |
|---|
| 33 | * THE POSSIBILITY OF SUCH DAMAGES; OR (ii) ANY AMOUNT IN EXCESS OF THE AMOUNT |
|---|
| 34 | * ACTUALLY PAID FOR THE SOFTWARE ITSELF OR U.S. $1, WHICHEVER IS GREATER. THESE |
|---|
| 35 | * LIMITATIONS SHALL APPLY NOTWITHSTANDING ANY FAILURE OF ESSENTIAL PURPOSE OF |
|---|
| 36 | * ANY LIMITED REMEDY. |
|---|
| 37 | * |
|---|
| 38 | * $brcm_Workfile: nexus_spi.c $ |
|---|
| 39 | * $brcm_Revision: 16 $ |
|---|
| 40 | * $brcm_Date: 11/12/10 3:31p $ |
|---|
| 41 | * |
|---|
| 42 | * Module Description: |
|---|
| 43 | * |
|---|
| 44 | * Revision History: |
|---|
| 45 | * |
|---|
| 46 | * $brcm_Log: /nexus/modules/spi/7400/src/nexus_spi.c $ |
|---|
| 47 | * |
|---|
| 48 | * 16 11/12/10 3:31p gmohile |
|---|
| 49 | * SW7408-145 : Fix 7408 support |
|---|
| 50 | * |
|---|
| 51 | * 15 11/3/10 1:39p jhaberf |
|---|
| 52 | * SW35125-1: Added 35125 DTV chip support |
|---|
| 53 | * |
|---|
| 54 | * 14 6/9/10 2:48p jhaberf |
|---|
| 55 | * SW35230-67: integrated latest nexus SPI support for the 35230 |
|---|
| 56 | * |
|---|
| 57 | * 13 5/19/10 5:20p jhaberf |
|---|
| 58 | * SW35230-67: Added bHeap and bufferSize structure members for 35230 |
|---|
| 59 | * |
|---|
| 60 | * 12 5/13/10 4:32p jhaberf |
|---|
| 61 | * SW35230-67: Added nexus spi changes for 35230 DTV chip |
|---|
| 62 | * |
|---|
| 63 | * 11 1/7/10 11:33a jhaberf |
|---|
| 64 | * SW35230-1: Added some #fidef's in order to get module building for |
|---|
| 65 | * 35230 DTV chip |
|---|
| 66 | * |
|---|
| 67 | * 10 1/6/10 11:33a mphillip |
|---|
| 68 | * SW3548-2660: Merge interrupt vs. polling mode changes to main |
|---|
| 69 | * |
|---|
| 70 | * SW3548-2660/2 1/6/10 11:29a mphillip |
|---|
| 71 | * SW3548-2660: Rename variable exposing interrupt vs. polling mode for |
|---|
| 72 | * transfers |
|---|
| 73 | * |
|---|
| 74 | * SW3548-2660/1 1/5/10 6:06p mphillip |
|---|
| 75 | * SW3548-2660: Add a user setting to enable polling for transfers |
|---|
| 76 | * |
|---|
| 77 | * 9 11/11/09 11:53a erickson |
|---|
| 78 | * SW7405-3362: add dtl and rdsclk fields to NEXUS_SpiSettings |
|---|
| 79 | * |
|---|
| 80 | * 8 1/26/09 12:05p erickson |
|---|
| 81 | * PR51468: global variable naming convention |
|---|
| 82 | * |
|---|
| 83 | * 7 1/26/09 11:07a erickson |
|---|
| 84 | * PR51468: global variable naming convention |
|---|
| 85 | * |
|---|
| 86 | * 6 11/20/08 8:27a ahulse |
|---|
| 87 | * PR49515: If set, override default settings with user set settings |
|---|
| 88 | * |
|---|
| 89 | * 5 8/18/08 10:28a katrep |
|---|
| 90 | * PR45674: Compiler warnings in DEBUG=n builds |
|---|
| 91 | * |
|---|
| 92 | * 4 4/11/08 9:53a erickson |
|---|
| 93 | * PR41246: convert BDBG_OBJECT_UNSET to BDBG_OBJECT_DESTROY if freeing |
|---|
| 94 | * memory |
|---|
| 95 | * |
|---|
| 96 | * 3 3/31/08 12:32p erickson |
|---|
| 97 | * PR41073: check result of malloc and fail graciously |
|---|
| 98 | * |
|---|
| 99 | * 2 1/25/08 2:29p erickson |
|---|
| 100 | * PR39016: implemented Read,Write,SetSettings |
|---|
| 101 | * |
|---|
| 102 | * 1 1/18/08 2:21p jgarrett |
|---|
| 103 | * PR 38808: Merging to main branch |
|---|
| 104 | * |
|---|
| 105 | * Nexus_Devel/3 11/21/07 11:12a erickson |
|---|
| 106 | * PR37423: update |
|---|
| 107 | * |
|---|
| 108 | * Nexus_Devel/2 11/20/07 2:23p erickson |
|---|
| 109 | * PR37423: simplify module init |
|---|
| 110 | * |
|---|
| 111 | * Nexus_Devel/1 11/20/07 1:28p erickson |
|---|
| 112 | * PR37423: added uart, gpio, spi modules |
|---|
| 113 | * |
|---|
| 114 | **************************************************************************/ |
|---|
| 115 | #include "nexus_spi_module.h" |
|---|
| 116 | #include "bspi.h" |
|---|
| 117 | #include "breg_spi.h" |
|---|
| 118 | #if ((BCHP_CHIP==35125) || (BCHP_CHIP==35230) || (BCHP_CHIP==35330)) |
|---|
| 119 | #include "bchp_pcu.h" |
|---|
| 120 | #include "bchp_tvm.h" |
|---|
| 121 | #elif (BCHP_CHIP==7408) |
|---|
| 122 | #include "bchp_hif_mspi.h" |
|---|
| 123 | #else |
|---|
| 124 | #include "bchp_mspi.h" |
|---|
| 125 | #endif /*BCHP_CHIP==35230*/ |
|---|
| 126 | #include "priv/nexus_core.h" |
|---|
| 127 | |
|---|
| 128 | BDBG_MODULE(nexus_spi); |
|---|
| 129 | |
|---|
| 130 | #ifndef BCHP_MSPI_SPCR0_MSB_CPOL_MASK |
|---|
| 131 | #define BCHP_MSPI_SPCR0_MSB_CPOL_MASK BCHP_HIF_MSPI_SPCR0_MSB_CPOL_MASK |
|---|
| 132 | #define BCHP_MSPI_SPCR0_MSB_CPHA_MASK BCHP_HIF_MSPI_SPCR0_MSB_CPHA_MASK |
|---|
| 133 | #endif |
|---|
| 134 | |
|---|
| 135 | NEXUS_ModuleHandle g_NEXUS_spiModule; |
|---|
| 136 | struct { |
|---|
| 137 | NEXUS_SpiModuleSettings settings; |
|---|
| 138 | BSPI_Handle spi; |
|---|
| 139 | } g_NEXUS_spi; |
|---|
| 140 | |
|---|
| 141 | /**************************************** |
|---|
| 142 | * Module functions |
|---|
| 143 | ***************/ |
|---|
| 144 | |
|---|
| 145 | void NEXUS_SpiModule_GetDefaultSettings(NEXUS_SpiModuleSettings *pSettings) |
|---|
| 146 | { |
|---|
| 147 | BKNI_Memset(pSettings, 0, sizeof(*pSettings)); |
|---|
| 148 | } |
|---|
| 149 | |
|---|
| 150 | NEXUS_ModuleHandle NEXUS_SpiModule_Init(const NEXUS_SpiModuleSettings *pSettings) |
|---|
| 151 | { |
|---|
| 152 | BSPI_Settings spiSettings; |
|---|
| 153 | BERR_Code rc; |
|---|
| 154 | |
|---|
| 155 | BDBG_ASSERT(!g_NEXUS_spiModule); |
|---|
| 156 | g_NEXUS_spiModule = NEXUS_Module_Create("spi", NULL); |
|---|
| 157 | if (pSettings) { |
|---|
| 158 | g_NEXUS_spi.settings = *pSettings; |
|---|
| 159 | } |
|---|
| 160 | else { |
|---|
| 161 | NEXUS_SpiModule_GetDefaultSettings(&g_NEXUS_spi.settings); |
|---|
| 162 | } |
|---|
| 163 | |
|---|
| 164 | BSPI_GetDefaultSettings(&spiSettings, g_pCoreHandles->chp); |
|---|
| 165 | rc = BSPI_Open(&g_NEXUS_spi.spi, g_pCoreHandles->chp, g_pCoreHandles->reg, g_pCoreHandles->bint, &spiSettings); |
|---|
| 166 | if (rc) {rc=BERR_TRACE(NEXUS_UNKNOWN); return NULL;} |
|---|
| 167 | |
|---|
| 168 | return g_NEXUS_spiModule; |
|---|
| 169 | } |
|---|
| 170 | |
|---|
| 171 | void NEXUS_SpiModule_Uninit() |
|---|
| 172 | { |
|---|
| 173 | BSPI_Close(g_NEXUS_spi.spi); |
|---|
| 174 | NEXUS_Module_Destroy(g_NEXUS_spiModule); |
|---|
| 175 | g_NEXUS_spiModule = NULL; |
|---|
| 176 | } |
|---|
| 177 | |
|---|
| 178 | /**************************************** |
|---|
| 179 | * API functions |
|---|
| 180 | ***************/ |
|---|
| 181 | |
|---|
| 182 | BDBG_OBJECT_ID(NEXUS_Spi); |
|---|
| 183 | |
|---|
| 184 | struct NEXUS_Spi { |
|---|
| 185 | BDBG_OBJECT(NEXUS_Spi) |
|---|
| 186 | BSPI_ChannelHandle spiChannel; |
|---|
| 187 | BREG_SPI_Handle spiReg; |
|---|
| 188 | NEXUS_SpiSettings settings; |
|---|
| 189 | }; |
|---|
| 190 | |
|---|
| 191 | void NEXUS_Spi_GetDefaultSettings(NEXUS_SpiSettings *pSettings) |
|---|
| 192 | { |
|---|
| 193 | BKNI_Memset(pSettings, 0, sizeof(*pSettings)); |
|---|
| 194 | pSettings->txLeadingCapFalling = true; |
|---|
| 195 | pSettings->clockActiveLow = true; |
|---|
| 196 | pSettings->interruptMode = true; |
|---|
| 197 | #if ((BCHP_CHIP==35125) || (BCHP_CHIP==35230) || (BCHP_CHIP==35330)) |
|---|
| 198 | pSettings->interruptMode = false; |
|---|
| 199 | pSettings->pcs = NEXUS_SpiPeripheralChipSelect_e0; /* default to first SS line */ |
|---|
| 200 | pSettings->xferDMAMode = false; |
|---|
| 201 | pSettings->hHeap = NULL; |
|---|
| 202 | pSettings->bufferSize = 0; |
|---|
| 203 | #endif |
|---|
| 204 | } |
|---|
| 205 | |
|---|
| 206 | NEXUS_SpiHandle NEXUS_Spi_Open(unsigned index, const NEXUS_SpiSettings *pSettings) |
|---|
| 207 | { |
|---|
| 208 | BSPI_ChannelSettings channelSettings; |
|---|
| 209 | NEXUS_SpiHandle spi; |
|---|
| 210 | BERR_Code rc; |
|---|
| 211 | unsigned totalChannels; |
|---|
| 212 | NEXUS_SpiSettings defaultSettings; |
|---|
| 213 | |
|---|
| 214 | if (!pSettings) { |
|---|
| 215 | NEXUS_Spi_GetDefaultSettings(&defaultSettings); |
|---|
| 216 | pSettings = &defaultSettings; |
|---|
| 217 | } |
|---|
| 218 | |
|---|
| 219 | BSPI_GetTotalChannels(g_NEXUS_spi.spi, &totalChannels); |
|---|
| 220 | if (index >= totalChannels) { |
|---|
| 221 | BDBG_ERR(("invalid Spi[%d]", index)); |
|---|
| 222 | return NULL; |
|---|
| 223 | } |
|---|
| 224 | |
|---|
| 225 | spi = BKNI_Malloc(sizeof(*spi)); |
|---|
| 226 | if (!spi) { |
|---|
| 227 | rc=BERR_TRACE(NEXUS_OUT_OF_SYSTEM_MEMORY); |
|---|
| 228 | return NULL; |
|---|
| 229 | } |
|---|
| 230 | BKNI_Memset(spi, 0, sizeof(*spi)); |
|---|
| 231 | BDBG_OBJECT_SET(spi, NEXUS_Spi); |
|---|
| 232 | |
|---|
| 233 | BSPI_GetChannelDefaultSettings(g_NEXUS_spi.spi, index, &channelSettings); |
|---|
| 234 | |
|---|
| 235 | if ( pSettings->baud ) |
|---|
| 236 | channelSettings.baud = pSettings->baud; |
|---|
| 237 | if ( pSettings->bitsPerTransfer ) |
|---|
| 238 | channelSettings.bitsPerTxfr = pSettings->bitsPerTransfer; |
|---|
| 239 | if ( pSettings->lastByteContinueEnable ) |
|---|
| 240 | channelSettings.lastByteContinueEnable = pSettings->lastByteContinueEnable; |
|---|
| 241 | if ( pSettings->useUserDtlAndDsclk ) |
|---|
| 242 | channelSettings.useUserDtlAndDsclk = pSettings->useUserDtlAndDsclk; |
|---|
| 243 | |
|---|
| 244 | channelSettings.intMode = pSettings->interruptMode; |
|---|
| 245 | #if ((BCHP_CHIP==35125) || (BCHP_CHIP==35230) || (BCHP_CHIP==35330)) |
|---|
| 246 | if ( pSettings->pcs ) |
|---|
| 247 | channelSettings.pcs = pSettings->pcs; |
|---|
| 248 | channelSettings.xferDMAMode = pSettings->xferDMAMode; |
|---|
| 249 | |
|---|
| 250 | if(pSettings->hHeap != NULL) |
|---|
| 251 | { |
|---|
| 252 | channelSettings.hHeap = NEXUS_Heap_GetMemHandle(pSettings->hHeap); |
|---|
| 253 | } |
|---|
| 254 | channelSettings.bufferSize = pSettings->bufferSize; |
|---|
| 255 | #endif |
|---|
| 256 | |
|---|
| 257 | rc = BSPI_OpenChannel(g_NEXUS_spi.spi, &spi->spiChannel, index, &channelSettings); |
|---|
| 258 | if (rc) {rc=BERR_TRACE(rc); goto error;} |
|---|
| 259 | |
|---|
| 260 | rc = BSPI_CreateSpiRegHandle(spi->spiChannel, &spi->spiReg); |
|---|
| 261 | if (rc) {rc=BERR_TRACE(rc); goto error;} |
|---|
| 262 | |
|---|
| 263 | rc = NEXUS_Spi_SetSettings(spi, pSettings); |
|---|
| 264 | if (rc) {rc=BERR_TRACE(rc); goto error;} |
|---|
| 265 | |
|---|
| 266 | return spi; |
|---|
| 267 | error: |
|---|
| 268 | NEXUS_Spi_Close(spi); |
|---|
| 269 | return NULL; |
|---|
| 270 | } |
|---|
| 271 | |
|---|
| 272 | void NEXUS_Spi_Close(NEXUS_SpiHandle spi) |
|---|
| 273 | { |
|---|
| 274 | BDBG_OBJECT_ASSERT(spi, NEXUS_Spi); |
|---|
| 275 | |
|---|
| 276 | if (spi->spiReg) { |
|---|
| 277 | BSPI_CloseSpiRegHandle(spi->spiReg); |
|---|
| 278 | } |
|---|
| 279 | if (spi->spiChannel) { |
|---|
| 280 | BSPI_CloseChannel(spi->spiChannel); |
|---|
| 281 | } |
|---|
| 282 | |
|---|
| 283 | BDBG_OBJECT_DESTROY(spi, NEXUS_Spi); |
|---|
| 284 | BKNI_Free(spi); |
|---|
| 285 | } |
|---|
| 286 | |
|---|
| 287 | void NEXUS_Spi_GetSettings(NEXUS_SpiHandle spi, NEXUS_SpiSettings *pSettings) |
|---|
| 288 | { |
|---|
| 289 | BDBG_OBJECT_ASSERT(spi, NEXUS_Spi); |
|---|
| 290 | *pSettings = spi->settings; |
|---|
| 291 | } |
|---|
| 292 | |
|---|
| 293 | NEXUS_Error NEXUS_Spi_SetSettings(NEXUS_SpiHandle spi, const NEXUS_SpiSettings *pSettings) |
|---|
| 294 | { |
|---|
| 295 | uint8_t clkConfig; |
|---|
| 296 | BERR_Code rc; |
|---|
| 297 | |
|---|
| 298 | BDBG_OBJECT_ASSERT(spi, NEXUS_Spi); |
|---|
| 299 | |
|---|
| 300 | BSPI_GetClkConfig(spi->spiChannel, &clkConfig); |
|---|
| 301 | #if ((BCHP_CHIP==35125) || (BCHP_CHIP==35230) || (BCHP_CHIP==35330)) |
|---|
| 302 | /* TODO - 35230 SPI register manipulations here */ |
|---|
| 303 | if (pSettings->clockActiveLow) |
|---|
| 304 | clkConfig |= 0x4; |
|---|
| 305 | else |
|---|
| 306 | clkConfig &= ~(0x4); |
|---|
| 307 | |
|---|
| 308 | if (pSettings->txLeadingCapFalling) |
|---|
| 309 | clkConfig |= 0x1; |
|---|
| 310 | else |
|---|
| 311 | clkConfig &= ~(0x1); |
|---|
| 312 | |
|---|
| 313 | if (pSettings->rxLeading) |
|---|
| 314 | clkConfig |= 0x2; |
|---|
| 315 | else |
|---|
| 316 | clkConfig &= ~(0x2); |
|---|
| 317 | #else |
|---|
| 318 | if (pSettings->clockActiveLow) |
|---|
| 319 | clkConfig |= BCHP_MSPI_SPCR0_MSB_CPOL_MASK; /* if 1, then 0 is active */ |
|---|
| 320 | else |
|---|
| 321 | clkConfig &= ~BCHP_MSPI_SPCR0_MSB_CPOL_MASK; /* if 0, then 1 is active */ |
|---|
| 322 | if (pSettings->txLeadingCapFalling) |
|---|
| 323 | clkConfig |= BCHP_MSPI_SPCR0_MSB_CPHA_MASK; |
|---|
| 324 | else |
|---|
| 325 | clkConfig &= ~BCHP_MSPI_SPCR0_MSB_CPHA_MASK; |
|---|
| 326 | #endif/*BCHP_CHIP==35230*/ |
|---|
| 327 | |
|---|
| 328 | rc = BSPI_SetClkConfig(spi->spiChannel, clkConfig); |
|---|
| 329 | if (rc) return BERR_TRACE(rc); |
|---|
| 330 | |
|---|
| 331 | rc = BSPI_SetDTLConfig(spi->spiChannel, pSettings->dtl); |
|---|
| 332 | if (rc) return BERR_TRACE(rc); |
|---|
| 333 | |
|---|
| 334 | #if ((BCHP_CHIP==35125) || (BCHP_CHIP==35230) || (BCHP_CHIP==35330)) |
|---|
| 335 | /* nothing to do */ |
|---|
| 336 | #else |
|---|
| 337 | rc = BSPI_SetRDSCLKConfig(spi->spiChannel, pSettings->rdsclk); |
|---|
| 338 | if (rc) return BERR_TRACE(rc); |
|---|
| 339 | #endif |
|---|
| 340 | |
|---|
| 341 | #if ((BCHP_CHIP==35125) || (BCHP_CHIP==35230) || (BCHP_CHIP==35330)) |
|---|
| 342 | /* set the SPI transfer mode, either DMA or regular RxTx register */ |
|---|
| 343 | rc = BSPI_SetDMAMode(spi->spiChannel, pSettings->xferDMAMode); |
|---|
| 344 | if (rc) return BERR_TRACE(rc); |
|---|
| 345 | |
|---|
| 346 | /* set the slave select */ |
|---|
| 347 | rc = BSPI_SetPCS(spi->spiChannel, pSettings->pcs); |
|---|
| 348 | if (rc) return BERR_TRACE(rc); |
|---|
| 349 | #endif |
|---|
| 350 | |
|---|
| 351 | spi->settings = *pSettings; |
|---|
| 352 | return 0; |
|---|
| 353 | } |
|---|
| 354 | |
|---|
| 355 | NEXUS_Error NEXUS_Spi_Write(NEXUS_SpiHandle spi, const uint8_t *pWriteData, |
|---|
| 356 | size_t length) |
|---|
| 357 | { |
|---|
| 358 | BERR_Code rc; |
|---|
| 359 | BDBG_OBJECT_ASSERT(spi, NEXUS_Spi); |
|---|
| 360 | rc = BREG_SPI_Write(spi->spiReg, pWriteData, length); |
|---|
| 361 | if (rc) return BERR_TRACE(rc); |
|---|
| 362 | return 0; |
|---|
| 363 | } |
|---|
| 364 | |
|---|
| 365 | NEXUS_Error NEXUS_Spi_Read(NEXUS_SpiHandle spi, const uint8_t *pWriteData, |
|---|
| 366 | uint8_t *pReadData, size_t length) |
|---|
| 367 | { |
|---|
| 368 | BERR_Code rc; |
|---|
| 369 | BDBG_OBJECT_ASSERT(spi, NEXUS_Spi); |
|---|
| 370 | rc = BREG_SPI_Read(spi->spiReg, pWriteData, pReadData, length); |
|---|
| 371 | if (rc) return BERR_TRACE(rc); |
|---|
| 372 | return 0; |
|---|
| 373 | } |
|---|