1 /*******************************************************************************
2 Copyright (C) Marvell International Ltd. and its affiliates
4 This software file (the "File") is owned and distributed by Marvell
5 International Ltd. and/or its affiliates ("Marvell") under the following
6 alternative licensing terms. Once you have made an election to distribute the
7 File under one of the following license alternatives, please (i) delete this
8 introductory statement regarding license alternatives, (ii) delete the two
9 license alternatives that you have not elected to use and (iii) preserve the
10 Marvell copyright notice above.
12 ********************************************************************************
13 Marvell Commercial License Option
15 If you received this File from Marvell and you have entered into a commercial
16 license agreement (a "Commercial License") with Marvell, the File is licensed
17 to you under the terms of the applicable Commercial License.
19 ********************************************************************************
20 Marvell GPL License Option
22 If you received this File from Marvell, you may opt to use, redistribute and/or
23 modify this File in accordance with the terms and conditions of the General
24 Public License Version 2, June 1991 (the "GPL License"), a copy of which is
25 available along with the File in the license.txt file or by writing to the Free
26 Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 or
27 on the worldwide web at http://www.gnu.org/licenses/gpl.txt.
29 THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE IMPLIED
30 WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE ARE EXPRESSLY
31 DISCLAIMED. The GPL License provides additional details about this warranty
33 ********************************************************************************
34 Marvell BSD License Option
36 If you received this File from Marvell, you may opt to use, redistribute and/or
37 modify this File under the following licensing terms.
38 Redistribution and use in source and binary forms, with or without modification,
39 are permitted provided that the following conditions are met:
41 * Redistributions of source code must retain the above copyright notice,
42 this list of conditions and the following disclaimer.
44 * Redistributions in binary form must reproduce the above copyright
45 notice, this list of conditions and the following disclaimer in the
46 documentation and/or other materials provided with the distribution.
48 * Neither the name of Marvell nor the names of its contributors may be
49 used to endorse or promote products derived from this software without
50 specific prior written permission.
52 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
53 ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
54 WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
55 DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
56 ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
57 (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
58 LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
59 ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
60 (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
61 SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
63 *******************************************************************************/
65 #include "spi/mvSpi.h"
66 #include "spi/mvSpiSpec.h"
68 #include "ctrlEnv/mvCtrlEnvLib.h"
70 /* #define MV_DEBUG */
73 #define mvOsPrintf printf
79 /*******************************************************************************
80 * mvSpi16bitDataTxRx - Transmt and receive data
83 * Tx data and block waiting for data to be transmitted
85 ********************************************************************************/
86 static MV_STATUS
mvSpi16bitDataTxRx (MV_U16 txData
, MV_U16
* pRxData
)
89 MV_BOOL ready
= MV_FALSE
;
91 /* First clear the bit in the interrupt cause register */
92 MV_REG_WRITE(MV_SPI_INT_CAUSE_REG
, 0x0);
95 MV_REG_WRITE(MV_SPI_DATA_OUT_REG
, MV_16BIT_LE(txData
));
97 /* wait with timeout for memory ready */
98 for (i
=0; i
<MV_SPI_WAIT_RDY_MAX_LOOP
; i
++)
100 if (MV_REG_READ(MV_SPI_INT_CAUSE_REG
))
105 #ifdef MV_SPI_SLEEP_ON_WAIT
107 #endif /* MV_SPI_SLEEP_ON_WAIT */
113 /* check that the RX data is needed */
116 if ((MV_U32
)pRxData
& 0x1) /* check if address is not alligned to 16bit */
118 #if defined(MV_CPU_LE)
119 /* perform the data write to the buffer in two stages with 8bit each */
120 MV_U8
* bptr
= (MV_U8
*)pRxData
;
121 MV_U16 data
= MV_16BIT_LE(MV_REG_READ(MV_SPI_DATA_IN_REG
));
122 *bptr
= (data
& 0xFF);
124 *bptr
= ((data
>> 8) & 0xFF);
126 #elif defined(MV_CPU_BE)
128 /* perform the data write to the buffer in two stages with 8bit each */
129 MV_U8
* bptr
= (MV_U8
*)pRxData
;
130 MV_U16 data
= MV_16BIT_LE(MV_REG_READ(MV_SPI_DATA_IN_REG
));
131 *bptr
= ((data
>> 8) & 0xFF);
133 *bptr
= (data
& 0xFF);
136 #error "CPU endianess isn't defined!\n"
141 *pRxData
= MV_16BIT_LE(MV_REG_READ(MV_SPI_DATA_IN_REG
));
148 /*******************************************************************************
149 * mvSpi8bitDataTxRx - Transmt and receive data (8bits)
152 * Tx data and block waiting for data to be transmitted
154 ********************************************************************************/
155 static MV_STATUS
mvSpi8bitDataTxRx (MV_U8 txData
, MV_U8
* pRxData
)
158 MV_BOOL ready
= MV_FALSE
;
160 /* First clear the bit in the interrupt cause register */
161 MV_REG_WRITE(MV_SPI_INT_CAUSE_REG
, 0x0);
164 MV_REG_WRITE(MV_SPI_DATA_OUT_REG
, txData
);
166 /* wait with timeout for memory ready */
167 for (i
=0; i
<MV_SPI_WAIT_RDY_MAX_LOOP
; i
++)
169 if (MV_REG_READ(MV_SPI_INT_CAUSE_REG
))
174 #ifdef MV_SPI_SLEEP_ON_WAIT
176 #endif /* MV_SPI_SLEEP_ON_WAIT */
182 /* check that the RX data is needed */
184 *pRxData
= MV_REG_READ(MV_SPI_DATA_IN_REG
);
190 #####################################################################################
191 #####################################################################################
194 /*******************************************************************************
195 * mvSpiInit - Initialize the SPI controller
198 * Perform the neccessary initialization in order to be able to send an
199 * receive over the SPI interface.
202 * serialBaudRate: Baud rate (SPI clock frequency)
203 * use16BitMode: Whether to use 2bytes (MV_TRUE) or 1bytes (MV_FALSE)
209 * Success or Error code.
212 *******************************************************************************/
213 MV_STATUS
mvSpiInit (MV_U32 serialBaudRate
)
217 /* Set the serial clock */
218 if ((ret
= mvSpiBaudRateSet(serialBaudRate
)) != MV_OK
)
221 /* For devices in which the SPI is muxed on the MPP with other interfaces*/
224 /* Configure the default SPI mode to be 16bit */
225 MV_REG_BIT_SET(MV_SPI_IF_CONFIG_REG
, MV_SPI_BYTE_LENGTH_MASK
);
227 /* Fix ac timing on SPI in 6183, 6183L and 78x00 only */
228 if ( (mvCtrlModelGet() == MV_6183_DEV_ID
) ||
229 (mvCtrlModelGet() == MV_6183L_DEV_ID
) ||
230 (mvCtrlModelGet() == MV_78100_DEV_ID
) ||
231 (mvCtrlModelGet() == MV_78200_DEV_ID
) ||
232 (mvCtrlModelGet() == MV_76100_DEV_ID
))
233 MV_REG_BIT_SET(MV_SPI_IF_CONFIG_REG
, BIT14
);
235 /* Verify that the CS is deasserted */
241 /*******************************************************************************
242 * mvSpiBaudRateSet - Set the Frequency of the SPI clock
245 * Set the Prescale bits to adapt to the requested baud rate (the clock
249 * serialBaudRate: Baud rate (SPI clock frequency)
255 * Success or Error code.
258 *******************************************************************************/
259 MV_STATUS
mvSpiBaudRateSet (MV_U32 serialBaudRate
)
262 /* MV_U8 preScale[32] = {1, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15,
263 2, 2, 4, 6, 8, 10, 12, 14, 16, 18, 20, 22, 24, 26, 28, 30};
265 MV_U8 preScale
[14] = { 4, 6, 8, 10, 12, 14, 16, 18, 20, 22, 24, 26, 28, 30};
266 MV_U8 bestPrescaleIndx
= 100;
267 MV_U32 minBaudOffset
= 0xFFFFFFFF;
268 MV_U32 cpuClk
= mvBoardTclkGet(); /*mvCpuPclkGet();*/
271 /* Find the best prescale configuration - less or equal */
274 /* check for higher - irrelevent */
275 if ((cpuClk
/ preScale
[i
]) > serialBaudRate
)
278 /* check for exact fit */
279 if ((cpuClk
/ preScale
[i
]) == serialBaudRate
)
281 bestPrescaleIndx
= i
;
285 /* check if this is better than the previous one */
286 if ((serialBaudRate
- (cpuClk
/ preScale
[i
])) < minBaudOffset
)
288 minBaudOffset
= (serialBaudRate
- (cpuClk
/ preScale
[i
]));
289 bestPrescaleIndx
= i
;
293 if (bestPrescaleIndx
> 14)
295 mvOsPrintf("%s ERROR: SPI baud rate prescale error!\n", __FUNCTION__
);
296 return MV_OUT_OF_RANGE
;
299 /* configure the Prescale */
300 tempReg
= MV_REG_READ(MV_SPI_IF_CONFIG_REG
);
301 tempReg
= ((tempReg
& ~MV_SPI_CLK_PRESCALE_MASK
) | (bestPrescaleIndx
+ 0x12));
302 MV_REG_WRITE(MV_SPI_IF_CONFIG_REG
, tempReg
);
307 /*******************************************************************************
308 * mvSpiCsAssert - Assert the Chip Select pin indicating a new transfer
311 * Assert The chip select - used to select an external SPI device
320 * Success or Error code.
322 ********************************************************************************/
323 MV_VOID
mvSpiCsAssert(MV_VOID
)
325 /* For devices in which the SPI is muxed on the MPP with other interfaces*/
328 MV_REG_BIT_SET(MV_SPI_IF_CTRL_REG
, MV_SPI_CS_ENABLE_MASK
);
331 /*******************************************************************************
332 * mvSpiCsDeassert - DeAssert the Chip Select pin indicating the end of a
333 * SPI transfer sequence
336 * DeAssert the chip select pin
345 * Success or Error code.
347 ********************************************************************************/
348 MV_VOID
mvSpiCsDeassert(MV_VOID
)
350 MV_REG_BIT_RESET(MV_SPI_IF_CTRL_REG
, MV_SPI_CS_ENABLE_MASK
);
352 /* For devices in which the SPI is muxed on the MPP with other interfaces*/
353 mvMPPConfigToDefault();
356 /*******************************************************************************
357 * mvSpiRead - Read a buffer over the SPI interface
360 * Receive (read) a buffer over the SPI interface in 16bit chunks. If the
361 * buffer size is odd, then the last chunk will be 8bits. Chip select is not
362 * handled at this level.
365 * pRxBuff: Pointer to the buffer to hold the received data
366 * buffSize: length of the pRxBuff
369 * pRxBuff: Pointer to the buffer with the received data
372 * Success or Error code.
375 *******************************************************************************/
376 MV_STATUS
mvSpiRead (MV_U8
* pRxBuff
, MV_U32 buffSize
)
379 MV_U32 bytesLeft
= buffSize
;
380 MV_U16
* rxPtr
= (MV_U16
*)pRxBuff
;
382 /* check for null parameters */
385 mvOsPrintf("%s ERROR: Null pointer parameter!\n", __FUNCTION__
);
389 /* Check that the buffer pointer and the buffer size are 16bit aligned */
390 if ((((MV_U32
)buffSize
& 1) == 0) && (((MV_U32
)pRxBuff
& 1) == 0))
392 /* Verify that the SPI mode is in 16bit mode */
393 MV_REG_BIT_SET(MV_SPI_IF_CONFIG_REG
, MV_SPI_BYTE_LENGTH_MASK
);
395 /* TX/RX as long we have complete 16bit chunks */
396 while (bytesLeft
>= MV_SPI_16_BIT_CHUNK_SIZE
)
398 /* Transmitted and wait for the transfer to be completed */
399 if ((ret
= mvSpi16bitDataTxRx(MV_SPI_DUMMY_WRITE_16BITS
, rxPtr
)) != MV_OK
)
402 /* increment the pointers */
404 bytesLeft
-= MV_SPI_16_BIT_CHUNK_SIZE
;
410 /* Verify that the SPI mode is in 8bit mode */
411 MV_REG_BIT_RESET(MV_SPI_IF_CONFIG_REG
, MV_SPI_BYTE_LENGTH_MASK
);
413 /* TX/RX in 8bit chanks */
414 while (bytesLeft
> 0)
416 /* Transmitted and wait for the transfer to be completed */
417 if ((ret
= mvSpi8bitDataTxRx(MV_SPI_DUMMY_WRITE_8BITS
, pRxBuff
)) != MV_OK
)
419 /* increment the pointers */
428 /*******************************************************************************
429 * mvSpiWrite - Transmit a buffer over the SPI interface
432 * Transmit a buffer over the SPI interface in 16bit chunks. If the
433 * buffer size is odd, then the last chunk will be 8bits. No chip select
437 * pTxBuff: Pointer to the buffer holding the TX data
438 * buffSize: length of the pTxBuff
444 * Success or Error code.
447 *******************************************************************************/
448 MV_STATUS
mvSpiWrite(MV_U8
* pTxBuff
, MV_U32 buffSize
)
451 MV_U32 bytesLeft
= buffSize
;
452 MV_U16
* txPtr
= (MV_U16
*)pTxBuff
;
454 /* check for null parameters */
457 mvOsPrintf("%s ERROR: Null pointer parameter!\n", __FUNCTION__
);
461 /* Check that the buffer pointer and the buffer size are 16bit aligned */
462 if ((((MV_U32
)buffSize
& 1) == 0) && (((MV_U32
)pTxBuff
& 1) == 0))
464 /* Verify that the SPI mode is in 16bit mode */
465 MV_REG_BIT_SET(MV_SPI_IF_CONFIG_REG
, MV_SPI_BYTE_LENGTH_MASK
);
467 /* TX/RX as long we have complete 16bit chunks */
468 while (bytesLeft
>= MV_SPI_16_BIT_CHUNK_SIZE
)
470 /* Transmitted and wait for the transfer to be completed */
471 if ((ret
= mvSpi16bitDataTxRx(*txPtr
, NULL
)) != MV_OK
)
474 /* increment the pointers */
476 bytesLeft
-= MV_SPI_16_BIT_CHUNK_SIZE
;
482 /* Verify that the SPI mode is in 8bit mode */
483 MV_REG_BIT_RESET(MV_SPI_IF_CONFIG_REG
, MV_SPI_BYTE_LENGTH_MASK
);
485 /* TX/RX in 8bit chanks */
486 while (bytesLeft
> 0)
488 /* Transmitted and wait for the transfer to be completed */
489 if ((ret
= mvSpi8bitDataTxRx(*pTxBuff
, NULL
)) != MV_OK
)
492 /* increment the pointers */
502 /*******************************************************************************
503 * mvSpiReadWrite - Read and Write a buffer simultanuosely
506 * Transmit and receive a buffer over the SPI in 16bit chunks. If the
507 * buffer size is odd, then the last chunk will be 8bits. The SPI chip
508 * select is not handled implicitely.
511 * pRxBuff: Pointer to the buffer to write the RX info in
512 * pTxBuff: Pointer to the buffer holding the TX info
513 * buffSize: length of both the pTxBuff and pRxBuff
516 * pRxBuff: Pointer of the buffer holding the RX data
519 * Success or Error code.
522 *******************************************************************************/
523 MV_STATUS
mvSpiReadWrite(MV_U8
* pRxBuff
, MV_U8
* pTxBuff
, MV_U32 buffSize
)
526 MV_U32 bytesLeft
= buffSize
;
527 MV_U16
* txPtr
= (MV_U16
*)pTxBuff
;
528 MV_U16
* rxPtr
= (MV_U16
*)pRxBuff
;
530 /* check for null parameters */
531 if ((pRxBuff
== NULL
) || (pTxBuff
== NULL
))
533 mvOsPrintf("%s ERROR: Null pointer parameter!\n", __FUNCTION__
);
537 /* Check that the buffer pointer and the buffer size are 16bit aligned */
538 if ((((MV_U32
)buffSize
& 1) == 0) && (((MV_U32
)pTxBuff
& 1) == 0) && (((MV_U32
)pRxBuff
& 1) == 0))
540 /* Verify that the SPI mode is in 16bit mode */
541 MV_REG_BIT_SET(MV_SPI_IF_CONFIG_REG
, MV_SPI_BYTE_LENGTH_MASK
);
543 /* TX/RX as long we have complete 16bit chunks */
544 while (bytesLeft
>= MV_SPI_16_BIT_CHUNK_SIZE
)
546 /* Transmitted and wait for the transfer to be completed */
547 if ((ret
= mvSpi16bitDataTxRx(*txPtr
, rxPtr
)) != MV_OK
)
550 /* increment the pointers */
553 bytesLeft
-= MV_SPI_16_BIT_CHUNK_SIZE
;
558 /* Verify that the SPI mode is in 8bit mode */
559 MV_REG_BIT_RESET(MV_SPI_IF_CONFIG_REG
, MV_SPI_BYTE_LENGTH_MASK
);
561 /* TX/RX in 8bit chanks */
562 while (bytesLeft
> 0)
564 /* Transmitted and wait for the transfer to be completed */
565 if ( (ret
= mvSpi8bitDataTxRx(*pTxBuff
, pRxBuff
) ) != MV_OK
)