/* This header file is part of the AVR Software Framework 2.0.0 release */

/*This file is prepared for Doxygen automatic documentation generation.*/
/*! \file *********************************************************************
 *
 * \brief MCI driver for AVR32 UC3.
 *
 * This file contains basic functions for the AVR32 MCI, with support for all
 * modes, settings and clock speeds.
 *
 * - Compiler:           IAR EWAVR32 and GNU GCC for AVR32
 * - Supported devices:  All AVR32 devices with a MCI module can be used.
 * - AppNote:
 *
 * \author               Atmel Corporation: http://www.atmel.com \n
 *                       Support and FAQ: http://support.atmel.no/
 *
 ******************************************************************************/

/* Copyright (c) 2009 Atmel Corporation. All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 *
 * 1. Redistributions of source code must retain the above copyright notice, this
 * list of conditions and the following disclaimer.
 *
 * 2. Redistributions in binary form must reproduce the above copyright notice,
 * this list of conditions and the following disclaimer in the documentation
 * and/or other materials provided with the distribution.
 *
 * 3. The name of Atmel may not be used to endorse or promote products derived
 * from this software without specific prior written permission.
 *
 * 4. This software may only be redistributed and used in connection with an Atmel
 * AVR product.
 *
 * THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR IMPLIED
 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE
 * EXPRESSLY AND SPECIFICALLY DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR
 * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE
 *
 */

#ifndef _MCI_H_
#define _MCI_H_


#include <avr32/io.h>
#include "compiler.h"

#include "sd_mmc_cmd.h"

//_____ D E F I N I T I O N S ______________________________________________

/*! \name Return Values
 */
//! @{
#define MCI_SUCCESS                 0 //!< Successful completion.
#define MCI_FAILURE                -1 //!< Failure because of some unspecified reason.
#define MCI_INVALID_INPUT           1 //!< Input value out of range.
//! @}

/*! \name Controller bus width
 */
//! @{
#define MCI_BUS_SIZE_1_BIT          0x00  //!< Bus Width Selected 1 bit.
#define MCI_BUS_SIZE_4_BIT          0x02  //!< Bus Width Selected 4 bits.
#define MCI_BUS_SIZE_8_BIT          0x03  //!< Bus Width Selected 8 bits.
//! @}

/*! \name Controller slot available
 */
//! @{
#define MCI_SLOT_A                  0x00        //!< Slot A Selected.
#define MCI_SLOT_B                  0x01        //!< Slot B Selected.
#define MCI_LAST_SLOTS              MCI_SLOT_B  //!< Last Slot Available by the MCI.
#define MCI_DEFAULT_SLOT            MCI_SLOT_A  //!< Default Slot Selected.
#define MCI_NR_SLOTS                2           //!< Number of MCI slots
//! @}

/*! \name Driver Default Value Configuration
 */
//! @{
#define MCI_DEFAULT_PWSDIV          0x07    //!< Power Saving Divider.

#define MCI_DEFAULT_DTOLMUL         0x07    //!< Data Timeout Multiplier.

#define MCI_DEFAULT_DTOLCYC          0x02    //!< Data Timeout Cycle Number.

#define MCI_DEFAULT_DTOREG        (MCI_DEFAULT_DTOLMUL<<AVR32_MCI_DTOR_DTOMUL_OFFSET) | \
                                  (MCI_DEFAULT_DTOLCYC<<AVR32_MCI_DTOR_DTOCYC_OFFSET)
//! @}

/*! \name CMDR Register bits definition
 */
//! @{

// Special Command
#define MCI_SPCMD_NONE                 (AVR32_MCI_CMDR_SPCMD_NO_SPEC_CMD<<AVR32_MCI_CMDR_SPCMD_OFFSET)  // (MCI) Not a special CMD
#define MCI_SPCMD_INIT                 (AVR32_MCI_CMDR_SPCMD_INIT_CMD   <<AVR32_MCI_CMDR_SPCMD_OFFSET)  // (MCI) Initialization CMD
#define MCI_SPCMD_SYNC                 (AVR32_MCI_CMDR_SPCMD_SYNC_CMD   <<AVR32_MCI_CMDR_SPCMD_OFFSET)  // (MCI) Synchronized CMD
#define MCI_SPCMD_IT_CMD               (AVR32_MCI_CMDR_SPCMD_INT_CMD    <<AVR32_MCI_CMDR_SPCMD_OFFSET)  // (MCI) Interrupt command
#define MCI_SPCMD_IT_REP               (AVR32_MCI_CMDR_SPCMD_INT_RESP   <<AVR32_MCI_CMDR_SPCMD_OFFSET)  // (MCI) Interrupt response
// Transfer Command
#define MCI_TRCMD_NO                   (AVR32_MCI_TRCMD_NO_TRANS   <<AVR32_MCI_TRCMD_OFFSET)            // (MCI) No transfer
#define MCI_TRCMD_START                (AVR32_MCI_TRCMD_START_TRANS<<AVR32_MCI_TRCMD_OFFSET)            // (MCI) Start transfer
#define MCI_TRCMD_STOP                 (AVR32_MCI_TRCMD_STOP_TRANS <<AVR32_MCI_TRCMD_OFFSET)            // (MCI) Stop transfer
// Response Type
#define MCI_RSPTYP_NO                  (AVR32_MCI_RSPTYP_NO_RESP     <<AVR32_MCI_RSPTYP_OFFSET)         // (MCI) No response
#define MCI_RSPTYP_48                  (AVR32_MCI_RSPTYP_48_BIT_RESP <<AVR32_MCI_RSPTYP_OFFSET)         // (MCI) 48-bit response
#define MCI_RSPTYP_48B                 (AVR32_MCI_RSPTYP_48_BIT_RESP_WITH_BUSY<<AVR32_MCI_RSPTYP_OFFSET)// (MCI) 48-bit response with busy
#define MCI_RSPTYP_136                 (AVR32_MCI_RSPTYP_136_BIT_RESP<<AVR32_MCI_RSPTYP_OFFSET)         // (MCI) 136-bit response
// Transfer Type
#define MCI_TRTYP_BLOCK                (AVR32_MCI_TRTYP_BLOCK      <<AVR32_MCI_TRTYP_OFFSET)            // (MCI) Block Transfer type
#define MCI_TRTYP_MULTIPLE             (AVR32_MCI_TRTYP_MULTI_BLOCK<<AVR32_MCI_TRTYP_OFFSET)            // (MCI) Multiple Block transfer type
#define MCI_TRTYP_STREAM               (AVR32_MCI_TRTYP_STREAM     <<AVR32_MCI_TRTYP_OFFSET)            // (MCI) Stream transfer type
#define MCI_TRTYP_SDIO_BYTE            (AVR32_MCI_TRTYP_SDIO_BYTE  <<AVR32_MCI_TRTYP_OFFSET)            // (MCI) SDIO byte transfer type
#define MCI_TRTYP_SDIO_BLOCK           (AVR32_MCI_TRTYP_SDIO_BLOCK <<AVR32_MCI_TRTYP_OFFSET)            // (MCI) SDIO block transfer type

#define MCI_OPDCMD                     (AVR32_MCI_OPDCMD_MASK)                                          // (MCI) Open Drain Command
#define MCI_MAXLAT                     (AVR32_MCI_MAXLAT_MASK)                                          // (MCI) Maximum Latency for Command to respond
#define MCI_TRDIR                      (AVR32_MCI_TRDIR_MASK)                                           // (MCI) Transfer Direction
//! @}

//! Input parameters when initializing ISO7816 mode.
typedef struct
{
  //! Set the frequency of the MCI clock.
  unsigned long card_speed;

  //! Set the slot of the MCI.
  unsigned char card_slot;

  //! Set the Bus Width of the MCI.
  unsigned char bus_width;
}mci_options_t;

extern int shadow_sr;

//_____ P R O T O T Y P E S ________________________________________________

/*! \brief Reset the MCI controller
 *
 * \param mci   Base address of the MCI instance.
 *
 * \retval
 */
extern void mci_reset(volatile avr32_mci_t *mci);

/*! \brief Return the status register and cache in a shadow variable bits
 *         that are cleared when reading the status register.
 *
 * \param mci        Base address of the MCI instance.
 */
#if (defined __GNUC__)
__attribute__((__always_inline__))
#endif
extern __inline__ int mci_get_sr(volatile avr32_mci_t *mci)
{
  shadow_sr = (shadow_sr & (AVR32_MCI_SR_DTOE_MASK | AVR32_MCI_SR_DCRCE_MASK | AVR32_MCI_SR_CSTOE_MASK | AVR32_MCI_SR_BLKOVRE_MASK)) | mci->sr;
  return shadow_sr;
}

/*! \brief Stop the MCI controller
 *
 * \param mci   Base address of the MCI instance.
 *
 * \retval
 */
extern void mci_stop(volatile avr32_mci_t *mci);

/*! \brief Initialize the MCI controller
 *
 * \param mci         Base address of the MCI instance.
 * \param opt         Option Structure
 * \param pbb_hz      PBB Frequency
 *
 * \retval MCI_SUCCESS  Initialization successfully done.
 * \retval MCI_INVALID_INPUT  One or more of the arguments is out of valid range.
 */
extern int mci_init( volatile avr32_mci_t *mci,
                     const mci_options_t *mci_opt,
                     long pbb_hz);

/*! \brief Set Speed Card
 *
 * \param mci         Base address of the MCI instance.
 * \param pbb_hz      PBB Frequency
 * \param card_speed  Card Frequency
 *
 * \retval MCI_SUCCESS  Initialization successfully done.
 * \retval MCI_INVALID_INPUT  One or more of the arguments is out of valid range.
 */
extern void mci_set_speed(volatile avr32_mci_t *mci,
                          long pbb_hz,
                          long card_speed);

/*! \brief Generic function to send a command to the MMC or SDCard.
 *
 * \param mci   Base address of the MCI instance.
 * \param cmd   Command Value.
 * \param arg   Argument Value.
 *
 * \retval MCI_SUCCESS  Command Successfully sent
 * \retval error  Error value
 */
extern int  mci_send_cmd (volatile avr32_mci_t *mci,
                          unsigned int cmd,
                          unsigned int arg);

/*! \brief Read command argument response.
 *
 * \param mci   Base address of the MCI instance.
 *
 * \retval argument  Return value of the previously command.
 */
extern unsigned int mci_read_response(volatile avr32_mci_t *mci);

/*! \brief Set SDIO Bus Width.
 *
 * \param mci   Base address of the MCI instance.
 * \param busWidth      Bus Width Value
 *
 * \retval MCI_SUCCESS  Command successfully done.
 * \retval MCI_INVALID_INPUT  One or more of the arguments is out of valid range.
 */
extern int mci_set_bus_size(volatile avr32_mci_t *mci, unsigned char busWidth);

/*! \brief Set Block Size.
 *
 * \param mci      Base address of the MCI instance.
 * \param length   Block Length Value
 *
 * \retval
 */
extern void mci_set_block_size(volatile avr32_mci_t *mci, unsigned short length);

/*! \brief Set Block Count.
 *
 * \param mci      Base address of the MCI instance.
 * \param length   Block Count Value
 *
 * \retval
 */
extern void mci_set_block_count(volatile avr32_mci_t *mci, unsigned short cnt);

/*! \brief Mci Busy Status.
 *
 * \param mci   Base address of the MCI instance.
 *
 * \retval
 */
extern void mci_wait_busy_signal(volatile avr32_mci_t *mci);

/*! \brief Mci Write data.
 *
 * \param mci   Base address of the MCI instance.
 * \param data  Data to write
 * \retval
 */
#if (defined __GNUC__)
__attribute__((__always_inline__))
#endif
extern __inline__ void mci_wr_data(volatile avr32_mci_t *mci,U32 data)
{
  mci->tdr = data;
}

/*! \brief Mci Read data.
 *
 * \param mci   Base address of the MCI instance.
 *
 * \retval data Data read
 */
#if (defined __GNUC__)
__attribute__((__always_inline__))
#endif
extern __inline__ U32 mci_rd_data(volatile avr32_mci_t *mci)
{
  return (mci->rdr);
}

/*! \brief Mci Select slot Card.
 *
 * \param mci        Base address of the MCI instance.
 * \param card_slot  Slot number.
 * \param bus_width  Bus Width .
 *
 * \retval data Data read
 */
extern int mci_select_card(volatile avr32_mci_t *mci, unsigned char card_slot,unsigned char bus_width);



/*! \brief Tests if the MCI is able to take a new command.
 *
 * \param mci        Base address of the MCI instance.
 *
 * \return \c 1 if the MCI can take a new command, otherwise \c 0.
 */
#if (defined __GNUC__)
__attribute__((__always_inline__))
#endif
extern __inline__ int mci_cmd_ready(volatile avr32_mci_t *mci)
{
  return ((mci_get_sr(mci)&AVR32_MCI_SR_CMDRDY_MASK) != 0);
}

/*! \brief Tests if the MCI is ready to transmit data.
 *
 * \param mci        Base address of the MCI instance.
 *
 * \return \c 1 if the MCI Transmit Holding Register is free, otherwise \c 0.
 */
#if (defined __GNUC__)
__attribute__((__always_inline__))
#endif
extern __inline__ int mci_tx_ready(volatile avr32_mci_t *mci)
{
  return ((mci_get_sr(mci)&AVR32_MCI_SR_TXRDY_MASK) != 0);
}

/*! \brief Tests if the MCI is ready to receive data.
 *
 * \param mci        Base address of the MCI instance.
 *
 * \return \c 1 if the MCI Receive Holding Register is free, otherwise \c 0.
 */
#if (defined __GNUC__)
__attribute__((__always_inline__))
#endif
extern __inline__ int mci_rx_ready(volatile avr32_mci_t *mci)
{
  return (mci_get_sr(mci)&AVR32_MCI_SR_RXRDY_MASK) != 0;
}

/*! \brief Tests if the MCI has ended the block Transmission/ Reception.
 *
 * \param mci        Base address of the MCI instance.
 *
 * \return \c 1 if the MCI Block is ended, otherwise \c 0.
 */
#if (defined __GNUC__)
__attribute__((__always_inline__))
#endif
extern __inline__ int mci_data_block_ended(volatile avr32_mci_t *mci)
{
  return (mci_get_sr(mci)&AVR32_MCI_SR_XFRDONE_MASK) != 0;
}

/*! \brief Tests if the MCI Status detects a CRC error.
 *
 * \param mci        Base address of the MCI instance.
 *
 * \return \c 1 if the MCI CRC Error Flag is set, otherwise \c 0.
 */
#if (defined __GNUC__)
__attribute__((__always_inline__))
#endif
extern __inline__ int mci_crc_error(volatile avr32_mci_t *mci)
{
  if( mci_get_sr(mci)&AVR32_MCI_SR_DCRCE_MASK )
  {
    shadow_sr&=~AVR32_MCI_SR_DCRCE_MASK;
    return TRUE;
  }
  else
    return FALSE;
}

/*! \brief Tests if an overrun occur.
 *
 * \param mci        Base address of the MCI instance.
 *
 * \return \c 1 if the MCI overrun flag is set, otherwise \c 0.
 */
#if (defined __GNUC__)
__attribute__((__always_inline__))
#endif
extern __inline__ int mci_overrun_error(volatile avr32_mci_t *mci)
{
  if( mci_get_sr(mci)&AVR32_MCI_SR_OVRE_MASK )
  {
    return TRUE;
  }
  else
    return FALSE;
}

/*! \brief Tests if an underrun occur.
 *
 * \param mci        Base address of the MCI instance.
 *
 * \return \c 1 if the MCI underrun flag is set, otherwise \c 0.
 */
#if (defined __GNUC__)
__attribute__((__always_inline__))
#endif
extern __inline__ int mci_underrun_error(volatile avr32_mci_t *mci)
{
  if( mci_get_sr(mci)&AVR32_MCI_SR_UNRE_MASK )
  {
    return TRUE;
  }
  else
    return FALSE;
}

#endif // _MCI_H_
