source: rtems/bsps/arm/atsam/contrib/libraries/libchip/source/hsmci.c @ 54aabb7

5
Last change on this file since 54aabb7 was 54aabb7, checked in by Sebastian Huber <sebastian.huber@…>, on 04/22/18 at 13:11:43

bsp/atsam: Move libraries to bsps

This patch is a part of the BSP source reorganization.

Update #3285.

  • Property mode set to 100644
File size: 13.9 KB
Line 
1/* ---------------------------------------------------------------------------- */
2/*                  Atmel Microcontroller Software Support                      */
3/*                       SAM Software Package License                           */
4/* ---------------------------------------------------------------------------- */
5/* Copyright (c) 2015, Atmel Corporation                                        */
6/*                                                                              */
7/* All rights reserved.                                                         */
8/*                                                                              */
9/* Redistribution and use in source and binary forms, with or without           */
10/* modification, are permitted provided that the following condition is met:    */
11/*                                                                              */
12/* - Redistributions of source code must retain the above copyright notice,     */
13/* this list of conditions and the disclaimer below.                            */
14/*                                                                              */
15/* Atmel's name may not be used to endorse or promote products derived from     */
16/* this software without specific prior written permission.                     */
17/*                                                                              */
18/* DISCLAIMER:  THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR   */
19/* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF */
20/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE   */
21/* DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR ANY DIRECT, INDIRECT,      */
22/* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT */
23/* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,  */
24/* OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF    */
25/* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING         */
26/* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, */
27/* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.                           */
28/* ---------------------------------------------------------------------------- */
29
30/** \file
31 *
32 * Implementation of High Speed MultiMedia Card Interface (HSMCI) controller.
33 */
34
35/*---------------------------------------------------------------------------
36 *         Headers
37 *---------------------------------------------------------------------------*/
38
39#include "chip.h"
40#include <assert.h>
41
42/*---------------------------------------------------------------------------
43 *         Exported functions
44 *---------------------------------------------------------------------------*/
45
46/** \addtogroup hsmci_functions
47 *@{
48 */
49
50/**
51 * \brief Enable Multi-Media Interface
52 *
53 * \param pRMci Pointer to a Hsmci instance
54 */
55extern void HSMCI_Enable(Hsmci *pRMci)
56{
57        pRMci->HSMCI_CR = HSMCI_CR_MCIEN;
58}
59
60/**
61 * \brief Disable Multi-Media Interface
62 *
63 * \param pRMci Pointer to a Hsmci instance
64 */
65extern void HSMCI_Disable(Hsmci *pRMci)
66{
67        pRMci->HSMCI_CR = HSMCI_CR_MCIDIS;
68
69}
70
71/**
72 * \brief Reset (& Disable) Multi-Media Interface
73 *
74 * \param mci Pointer to a Hsmci instance
75 * \param bBackup Backup registers values to keep previous settings, including
76 *                _MR, _SDCR, _DTOR, _CSTOR, _DMA and _CFG.
77 */
78extern void HSMCI_Reset(Hsmci *pRMci, uint8_t bBackup)
79{
80        if (bBackup) {
81                uint32_t mr    = pRMci->HSMCI_MR;
82                uint32_t dtor  = pRMci->HSMCI_DTOR;
83                uint32_t sdcr  = pRMci->HSMCI_SDCR;
84                uint32_t cstor = pRMci->HSMCI_CSTOR;
85                uint32_t dma   = pRMci->HSMCI_DMA;
86                uint32_t cfg   = pRMci->HSMCI_CFG;
87
88                pRMci->HSMCI_CR = HSMCI_CR_SWRST;
89
90                pRMci->HSMCI_MR    = mr;
91                pRMci->HSMCI_DTOR  = dtor;
92                pRMci->HSMCI_SDCR  = sdcr;
93                pRMci->HSMCI_CSTOR = cstor;
94                pRMci->HSMCI_DMA   = dma;
95                pRMci->HSMCI_CFG   = cfg;
96        } else
97                pRMci->HSMCI_CR = HSMCI_CR_SWRST;
98}
99
100/**
101 * \brief Select slot
102 * \param pRMci Pointer to a Hsmci instance
103 * \param bSlot Slot ID (0~3 for A~D).
104 */
105extern void HSMCI_Select(Hsmci *pRMci, uint8_t bSlot, uint8_t bBusWidth)
106{
107        uint32_t dwSdcr;
108        dwSdcr = (HSMCI_SDCR_SDCSEL_Msk & bSlot);
109
110        switch (bBusWidth) {
111        case 1:
112                pRMci->HSMCI_SDCR = dwSdcr | HSMCI_SDCR_SDCBUS_1;
113                break;
114
115        case 4:
116                pRMci->HSMCI_SDCR = dwSdcr | HSMCI_SDCR_SDCBUS_4;
117                break;
118
119        case 8:
120                pRMci->HSMCI_SDCR = dwSdcr | HSMCI_SDCR_SDCBUS_8;
121                break;
122        }
123}
124
125/**
126 * \brief Set slot
127 * \param pRMci Pointer to a Hsmci instance
128 * \param bSlot Slot ID (0~3 for A~D).
129 */
130extern void HSMCI_SetSlot(Hsmci *pRMci, uint8_t bSlot)
131{
132        uint32_t dwSdcr = pRMci->HSMCI_SDCR & ~HSMCI_SDCR_SDCSEL_Msk;
133        pRMci->HSMCI_SDCR = dwSdcr | (HSMCI_SDCR_SDCSEL_Msk & bSlot);
134}
135
136/**
137 * \brief Set bus width of MCI
138 * \param pRMci Pointer to a Hsmci instance
139 * \param bBusWidth 1,4 or 8 (bits).
140 */
141extern void HSMCI_SetBusWidth(Hsmci *pRMci, uint8_t bBusWidth)
142{
143        uint32_t dwSdcr = pRMci->HSMCI_SDCR & ~HSMCI_SDCR_SDCBUS_Msk;
144
145        switch (bBusWidth) {
146        case 1:
147                pRMci->HSMCI_SDCR = dwSdcr | HSMCI_SDCR_SDCBUS_1;
148                break;
149
150        case 4:
151                pRMci->HSMCI_SDCR = dwSdcr | HSMCI_SDCR_SDCBUS_4;
152                break;
153
154        case 8:
155                pRMci->HSMCI_SDCR = dwSdcr | HSMCI_SDCR_SDCBUS_8;
156                break;
157        }
158}
159
160/**
161 * \brief Return bus width setting.
162 *
163 * \param pRMci  Pointer to an MCI instance.
164 * \return 1, 4 or 8.
165 */
166extern uint8_t HSMCI_GetBusWidth(Hsmci *pRMci)
167{
168        switch (pRMci->HSMCI_SDCR & HSMCI_SDCR_SDCBUS_Msk) {
169        case HSMCI_SDCR_SDCBUS_1: return 1;
170
171        case HSMCI_SDCR_SDCBUS_4: return 4;
172
173        case HSMCI_SDCR_SDCBUS_8: return 8;
174        }
175
176        return 0;
177}
178
179/**
180 * \brief Configures a MCI peripheral as specified.
181 *
182 * \param pRMci  Pointer to an MCI instance.
183 * \param dwMode Value of the MCI Mode register.
184 */
185extern void HSMCI_ConfigureMode(Hsmci *pRMci, uint32_t dwMode)
186{
187        pRMci->HSMCI_MR = dwMode;
188
189}
190
191/**
192 * \brief Return mode register
193 * \param pRMci  Pointer to an MCI instance.
194 */
195extern uint32_t HSMCI_GetMode(Hsmci *pRMci)
196{
197        return pRMci->HSMCI_MR;
198}
199
200/**
201 * \brief Enable/Disable R/W proof
202 *
203 * \param pRMci    Pointer to an MCI instance.
204 * \param bRdProof Read proof enable/disable.
205 * \param bWrProof Write proof enable/disable.
206 */
207extern void HSMCI_ProofEnable(Hsmci *pRMci, uint8_t bRdProof, uint8_t bWrProof)
208{
209        uint32_t mr = pRMci->HSMCI_MR;
210        pRMci->HSMCI_MR = (mr & (~(HSMCI_MR_WRPROOF | HSMCI_MR_RDPROOF)))
211                                          | (bRdProof ? HSMCI_MR_RDPROOF : 0)
212                                          | (bWrProof ? HSMCI_MR_WRPROOF : 0)
213                                         ;
214}
215
216/**
217 * \brief Padding value setting.
218 *
219 * \param pRMci    Pointer to an MCI instance.
220 * \param bPadvEn  Padding value 0xFF/0x00.
221 */
222extern void HSMCI_PadvCtl(Hsmci *pRMci, uint8_t bPadv)
223{
224        if (bPadv)
225                pRMci->HSMCI_MR |= HSMCI_MR_PADV;
226        else
227                pRMci->HSMCI_MR &= ~HSMCI_MR_PADV;
228}
229
230/**
231 * \brief Force byte transfer enable/disable.
232 *
233 * \param pRMci    Pointer to an MCI instance.
234 * \param bFByteEn FBYTE enable/disable.
235 */
236extern void HSMCI_FByteEnable(Hsmci *pRMci, uint8_t bFByteEn)
237{
238        if (bFByteEn)
239                pRMci->HSMCI_MR |= HSMCI_MR_FBYTE;
240        else
241                pRMci->HSMCI_MR &= ~HSMCI_MR_FBYTE;
242}
243
244/**
245 * \brief Check if Force Byte mode enabled.
246 *
247 * \param pRMci    Pointer to an MCI instance.
248 * \return 1 if _FBYTE is enabled.
249 */
250extern uint8_t HSMCI_IsFByteEnabled(Hsmci *pRMci)
251{
252        return ((pRMci->HSMCI_MR & HSMCI_MR_FBYTE) > 0);
253}
254
255/**
256 * \brief Set Clock Divider & Power save divider for MCI.
257 *
258 * \param pRMci    Pointer to an MCI instance.
259 * \param bClkDiv  Clock Divider value (0 ~ 255).
260 * \param bPwsDiv  Power Saving Divider (1 ~ 7).
261 */
262extern void HSMCI_DivCtrl(Hsmci *pRMci, uint32_t bClkDiv, uint8_t bPwsDiv)
263{
264        uint32_t mr = pRMci->HSMCI_MR;
265        uint32_t clkdiv , clkodd;
266        clkdiv = bClkDiv - 2;
267        clkodd = (bClkDiv & 1) ? HSMCI_MR_CLKODD : 0;
268        clkdiv = clkdiv >> 1;
269
270        pRMci->HSMCI_MR = (mr & ~(HSMCI_MR_CLKDIV_Msk | HSMCI_MR_PWSDIV_Msk))
271                                          | HSMCI_MR_CLKDIV(clkdiv)
272                                          | HSMCI_MR_PWSDIV(bPwsDiv)
273                                          | clkodd
274                                         ;
275}
276
277/**
278 * \brief Enables one or more interrupt sources of MCI peripheral.
279 *
280 * \param pRMci   Pointer to an Hsmci instance.
281 * \param sources Bitwise OR of selected interrupt sources.
282 */
283extern void HSMCI_EnableIt(Hsmci *pRMci, uint32_t dwSources)
284{
285        pRMci->HSMCI_IER = dwSources;
286}
287
288/**
289 * \brief Disable one or more interrupt sources of MCI peripheral.
290 *
291 * \param pRMci   Pointer to an Hsmci instance.
292 * \param sources Bitwise OR of selected interrupt sources.
293 */
294extern void HSMCI_DisableIt(Hsmci *pRMci, uint32_t dwSources)
295{
296        pRMci->HSMCI_IDR = dwSources;
297}
298
299/**
300 * \brief Return the interrupt mask register.
301 *
302 * \param pRMci   Pointer to an Hsmci instance.
303 * \return MCI interrupt mask register.
304 */
305extern uint32_t HSMCI_GetItMask(Hsmci *pRMci)
306{
307        return (pRMci->HSMCI_IMR);
308}
309
310/**
311 * \brief Set block len & count for transfer
312 *
313 * \param pRMci     Pointer to an Hsmci instance.
314 * \param wBlkLen   Block size.
315 * \param wCnt      Block(byte) count.
316 */
317extern void HSMCI_ConfigureTransfer(Hsmci *pRMci,
318                                                                        uint16_t wBlkLen,
319                                                                        uint16_t wCnt)
320{
321        pRMci->HSMCI_BLKR = (wBlkLen << 16) | wCnt;
322}
323
324/**
325 * \brief Set block length
326 *
327 *  Count is reset to 0.
328 *
329 * \param pRMci     Pointer to an Hsmci instance.
330 * \param wBlkSize  Block size.
331 */
332extern void HSMCI_SetBlockLen(Hsmci *pRMci, uint16_t wBlkSize)
333{
334        pRMci->HSMCI_BLKR = wBlkSize << 16;
335}
336
337/**
338 * \brief Set block (byte) count
339 *
340 * \param pRMci     Pointer to an Hsmci instance.
341 * \param wBlkCnt   Block(byte) count.
342 */
343extern void HSMCI_SetBlockCount(Hsmci *pRMci, uint16_t wBlkCnt)
344{
345        pRMci->HSMCI_BLKR |= wBlkCnt;
346}
347
348/**
349 * \brief Configure the Completion Signal Timeout
350 *
351 * \param pRMci Pointer to an Hsmci instance.
352 * \param dwConfigure Completion Signal Timeout configure.
353 */
354extern void HSMCI_ConfigureCompletionTO(Hsmci *pRMci, uint32_t dwConfigure)
355{
356        pRMci->HSMCI_CSTOR = dwConfigure;
357}
358
359/**
360 * \brief Configure the Data Timeout
361 *
362 * \param pRMci Pointer to an Hsmci instance.
363 * \param dwConfigure Data Timeout configure.
364 */
365extern void HSMCI_ConfigureDataTO(Hsmci *pRMci, uint32_t dwConfigure)
366{
367        pRMci->HSMCI_DTOR = dwConfigure;
368}
369
370/**
371 * \brief Send command
372 *
373 * \param pRMci Pointer to an Hsmci instance.
374 * \param dwCmd Command register value.
375 * \param dwArg Argument register value.
376 */
377extern void HSMCI_SendCmd(Hsmci *pRMci, uint32_t dwCmd, uint32_t dwArg)
378{
379        pRMci->HSMCI_ARGR = dwArg;
380        pRMci->HSMCI_CMDR = dwCmd;
381}
382
383
384/**
385 * \brief Return the response register.
386 *
387 * \param pRMci   Pointer to an Hsmci instance.
388 * \return MCI response register.
389 */
390extern uint32_t HSMCI_GetResponse(Hsmci *pRMci)
391{
392        return pRMci->HSMCI_RSPR[0];
393}
394
395/**
396 * \brief Return the receive data register.
397 *
398 * \param pRMci   Pointer to an Hsmci instance.
399 * \return MCI receive data register.
400 */
401extern uint32_t HSMCI_Read(Hsmci *pRMci)
402{
403        return pRMci->HSMCI_RDR;
404}
405
406/**
407 * \brief Read from FIFO
408 *
409 * \param pRMci   Pointer to an Hsmci instance.
410 * \param pdwData Pointer to data buffer.
411 * \param dwSize  Size of data buffer (in DWord).
412 */
413extern void HSMCI_ReadFifo(Hsmci *pRMci, uint8_t *pdwData, uint32_t dwSize)
414{
415        volatile uint32_t *pFIFO = (volatile uint32_t *)(pRMci->HSMCI_FIFO);
416        register uint32_t c4, c1;
417
418        if (dwSize == 0)
419                return;
420
421        c4 = dwSize >> 2;
422        c1 = dwSize & 0x3;
423
424        for (; c4; c4 --) {
425                *pdwData ++ = *pFIFO ++;
426                *pdwData ++ = *pFIFO ++;
427                *pdwData ++ = *pFIFO ++;
428                *pdwData ++ = *pFIFO ++;
429        }
430
431        for (; c1; c1 --)
432                *pdwData ++ = *pFIFO ++;
433}
434
435/**
436 * \brief Sends data through MCI peripheral.
437 *
438 * \param pRMci   Pointer to an Hsmci instance.
439 * \param
440 */
441extern void HSMCI_Write(Hsmci *pRMci, uint32_t dwData)
442{
443        pRMci->HSMCI_TDR = dwData;
444}
445
446/**
447 * \brief Write to FIFO
448 *
449 * \param pRMci   Pointer to an Hsmci instance.
450 * \param pdwData Pointer to data buffer.
451 * \param dwSize  Size of data buffer (In DWord).
452 */
453extern void HSMCI_WriteFifo(Hsmci *pRMci, uint8_t *pdwData, uint32_t dwSize)
454{
455        volatile uint32_t *pFIFO = (volatile uint32_t *)(pRMci->HSMCI_FIFO);
456        register uint32_t c4, c1;
457
458        if (dwSize == 0)
459                return;
460
461        c4 = dwSize >> 2;
462        c1 = dwSize & 0x3;
463
464        for (; c4; c4 --) {
465                *pFIFO ++ = *pdwData ++;
466                *pFIFO ++ = *pdwData ++;
467                *pFIFO ++ = *pdwData ++;
468                *pFIFO ++ = *pdwData ++;
469        }
470
471        for (; c1; c1 --)
472                *pFIFO ++ = *pdwData ++;
473}
474
475/**
476 * \brief Return the status register.
477 *
478 * \param pRMci   Pointer to an Hsmci instance.
479 * \return MCI status register.
480 */
481extern uint32_t HSMCI_GetStatus(Hsmci *pRMci)
482{
483        return pRMci->HSMCI_SR;
484}
485
486/**
487 * \brief Configure the HSMCI DMA
488 *
489 * \param pRMci Pointer to an Hsmci instance.
490 * \param dwConfigure Configure value.
491 */
492extern void HSMCI_ConfigureDma(Hsmci *pRMci, uint32_t dwConfigure)
493{
494        pRMci->HSMCI_DMA = dwConfigure;
495}
496
497/**
498 * \brief Enable the HSMCI DMA
499 *
500 * \param pRMci Pointer to an Hsmci instance.
501 * \param bEnable 1 to enable, 0 to disable.
502 */
503extern void HSMCI_EnableDma(Hsmci *pRMci, uint8_t bEnable)
504{
505        if (bEnable) {
506                pRMci->HSMCI_DMA |= HSMCI_DMA_DMAEN;//| HSMCI_DMA_CHKSIZE_32;
507        } else
508                pRMci->HSMCI_DMA &= ~HSMCI_DMA_DMAEN;
509}
510
511/**
512 * \brief Configure the HSMCI
513 *
514 * \param pRMci   Pointer to an Hsmci instance.
515 * \param dwConfigure Configure value.
516 */
517extern void HSMCI_Configure(Hsmci *pRMci, uint32_t dwConfigure)
518{
519        pRMci->HSMCI_CFG = dwConfigure;
520}
521
522/**
523 * \brief Enable/Disable High-Speed mode for MCI
524 *
525 * \param pRMci Pointer to an Hsmci instance.
526 * \param bHsEnable Enable/Disable high-speed.
527 */
528extern void HSMCI_HsEnable(Hsmci *pRMci, uint8_t bHsEnable)
529{
530        if (bHsEnable)
531                pRMci->HSMCI_CFG |= HSMCI_CFG_HSMODE;
532        else
533                pRMci->HSMCI_CFG &= ~HSMCI_CFG_HSMODE;
534}
535
536/**
537 * \brief Check if High-speed mode is enabled on MCI
538 * \param pRMci Pointer to an Hsmci instance.
539 * \return 1
540 */
541extern uint8_t HSMCI_IsHsEnabled(Hsmci *pRMci)
542{
543        return ((pRMci->HSMCI_CFG & HSMCI_CFG_HSMODE) > 0);
544}
545
546/**
547 * \brief Configure the Write Protection Mode
548 *
549 * \param pRMci   Pointer to an Hsmci instance.
550 * \param dwConfigure WP mode configure value.
551 */
552extern void HSMCI_ConfigureWP(Hsmci *pRMci, uint32_t dwConfigure)
553{
554        pRMci->HSMCI_WPMR = dwConfigure;
555}
556
557/**
558 * \brief Return the write protect status register.
559 *
560 * \param pRMci   Pointer to an Hsmci instance.
561 * \return MCI write protect status register.
562 */
563extern uint32_t HSMCI_GetWPStatus(Hsmci *pRMci)
564{
565        return pRMci->HSMCI_WPSR;
566}
567
568/**@}*/
569
Note: See TracBrowser for help on using the repository browser.