/**************************************************************************//**
    @file       hal_flash_trxeb.c

    @brief      Functions for accessing the SPI flash on SmartRF TrxEB.
                Based on hal_flash_st25pe.c for SmartRF05EB.

******************************************************************************/

/******************************************************************************
* INCLUDES
*/
#include "hal_types.h"
#include "hal_defs.h"
#include "hal_board.h"
#include "hal_flash_trxeb.h"
#include "hal_msp430.h"
#include "hal_mcu.h"


/******************************************************************************
* MACROS
*/
#define FLASH_SPI_BEGIN()           MCU_IO_SET_LOW(HAL_BOARD_IO_FLASH_CS_PORT,HAL_BOARD_IO_FLASH_CS_PIN);
#define FLASH_SPI_END()             MCU_IO_SET_HIGH(HAL_BOARD_IO_FLASH_CS_PORT,HAL_BOARD_IO_FLASH_CS_PIN);

#define FLASH_SPI_TX(x)             st( UCB2IFG &= ~UCRXIFG; UCB2TXBUF = x; ) // Clear RX flag, TX is cleared upon buffer write
#define FLASH_SPI_RX()              UCB2RXBUF
#define FLASH_SPI_WAIT_RXRDY()      st( while(!(UCB2IFG & UCRXIFG)); )

#define FLASH_RST_ENABLE()          MCU_IO_SET_LOW(HAL_BOARD_IO_FLASH_RST_PORT,HAL_BOARD_IO_FLASH_RST_PIN);
#define FLASH_RST_DISABLE()         MCU_IO_SET_HIGH(HAL_BOARD_IO_FLASH_RST_PORT,HAL_BOARD_IO_FLASH_RST_PIN);


/******************************************************************************
* PUBLIC FUNCTIONS
*/

/**************************************************************************//**
* @fn       halFlashInit(void)
*
* @brief    Initialize SPI flash interface. SPI bitrate is set equal to SMCLK.
*           Maximum SPI flash bitrate is 75MHz, so it handles any SMCLK rate.
*
* @param    none
*
* @return   none
******************************************************************************/
void halFlashInit(void)
{
    // Configure USCI_B2:
    UCB2CTL1 |= UCSWRST;                // Keep USCI_B2 state machine in reset
    UCB2CTL1 |= (UCSSEL1 | UCSSEL0);    // Set clock source SMCLK


    // Bit rate = SMCLK (SMCLK/1)
    UCB2BR0 = 1;
    UCB2BR1 = 0;

    UCB2CTL0 = UCMST + UCSYNC + UCMSB + UCCKPL; // 3pin SPI master, MSB first, data changed on first edge
                                                // and captured on second (chpa=1), clock inactive high (cpol=1)

    // De-assert SPI flash CSn pin (GPIO output high)
    MCU_IO_OUTPUT(HAL_BOARD_IO_FLASH_CS_PORT,HAL_BOARD_IO_FLASH_CS_PIN,1);

    // Power up SPI flash (full drivestrength)
    FLASH_PORT_PWR_DS  |=  ( 1<<HAL_BOARD_IO_FLASH_PWR_PIN );
    MCU_IO_OUTPUT(HAL_BOARD_IO_FLASH_PWR_PORT,HAL_BOARD_IO_FLASH_PWR_PIN,1);

    // Release SPI flash reset pin (GPIO output high)
    MCU_IO_OUTPUT(HAL_BOARD_IO_FLASH_RST_PORT,HAL_BOARD_IO_FLASH_RST_PIN,1);

    // MOSI, MISO and SCLK to peripheral function
    MCU_IO_PERIPHERAL(HAL_BOARD_IO_FLASH_MISO_PORT,HAL_BOARD_IO_FLASH_MISO_PIN);
    MCU_IO_PERIPHERAL(HAL_BOARD_IO_FLASH_MOSI_PORT,HAL_BOARD_IO_FLASH_MOSI_PIN);
    MCU_IO_PERIPHERAL(HAL_BOARD_IO_FLASH_CLK_PORT, HAL_BOARD_IO_FLASH_CLK_PIN);

    UCB2CTL1 &= ~(UCSWRST); // Initialize USCI_A2 state machine

    halMcuWaitMs(10);   // Minimum wait time before device is ready to process
                        // write/erase instructions after POR.

} // halFlashInit


/**************************************************************************//**
* @fn       halFlashUninit(void)
*
* @brief    Uninitialize SPI flash interface, assert flash reset and release
*           flash power.
*
* @param    none
*
* @return   none
******************************************************************************/
void halFlashUninit(void)
{
    // Uninitialize SPI interface
    FLASH_SPI_END();        // CSn as output high
    UCB2CTL1 |= UCSWRST;    // Disable SPI controller

    // MISO, MOSI and SCLK as GPIO input tristate
    MCU_IO_INPUT(HAL_BOARD_IO_FLASH_MISO_PORT,HAL_BOARD_IO_FLASH_MISO_PIN,MCU_IO_TRISTATE);
    MCU_IO_INPUT(HAL_BOARD_IO_FLASH_MOSI_PORT,HAL_BOARD_IO_FLASH_MOSI_PIN,MCU_IO_TRISTATE);
    MCU_IO_INPUT(HAL_BOARD_IO_FLASH_CLK_PORT, HAL_BOARD_IO_FLASH_CLK_PIN,MCU_IO_TRISTATE);

    // Assert reset pin before disabling power
    FLASH_RST_ENABLE();
    MCU_IO_INPUT(HAL_BOARD_IO_FLASH_PWR_PORT,HAL_BOARD_IO_FLASH_PWR_PIN,MCU_IO_TRISTATE);

} // halFlashUninit


/**************************************************************************//**
* @fn       halFlashGetStatus(void)
*
* @brief    Get SPI flash status byte.
*
* @param    none
*
* @return   Returns SPI flash status byte
******************************************************************************/
uint8  halFlashGetStatus(void)
{
    uint8 status;
    FLASH_SPI_BEGIN();

    FLASH_SPI_TX(FLASH_INSTRUCTION_RDSR);
    FLASH_SPI_WAIT_RXRDY();
    FLASH_SPI_TX(0x00);
    FLASH_SPI_WAIT_RXRDY();
    status = FLASH_SPI_RX();
    FLASH_SPI_END();
    return(status);

} // halFlashGetStatus


/**************************************************************************//**
* @fn       halFlashGetId(void)
*
* @brief    Get SPI flash ID bytes.
*
* @param    none
*
* @return   Returns SPI flash ID bytes (3 byte)
******************************************************************************/
uint32 halFlashGetId(void)
{
    uint8 man = 0;
    uint8 typ = 0;
    uint8 cap = 0;
    uint32 id;

    FLASH_SPI_BEGIN();                      // CSn low

    // Get ID
    FLASH_SPI_TX(FLASH_INSTRUCTION_RDID);   // Send read instruction
    FLASH_SPI_WAIT_RXRDY();                 // Wait for RX flag to go high

    FLASH_SPI_TX(0x00);
    FLASH_SPI_WAIT_RXRDY();
    man = FLASH_SPI_RX();

    FLASH_SPI_TX(0x00);
    FLASH_SPI_WAIT_RXRDY();
    typ = FLASH_SPI_RX();

    FLASH_SPI_TX(0x00);
    FLASH_SPI_WAIT_RXRDY();
    cap = FLASH_SPI_RX();

    FLASH_SPI_END();

    // Concatenate the three values
    id  = ((uint32)man) << 16;
    id |= ((uint32)typ) << 8;
    id |= ((uint32)cap);
    return(id);

} // halFlashGetId


/**************************************************************************//**
* @fn       halFlashRead(uint32 address, uint8* data, uint32 bytes)
*
* @brief    Read bytes from SPI flash.
*
* @param    address     SPI flash start address
* @param    data        Pointer to buffer to put read bytes
* @param    bytes       Number of bytes to read
*
* @return   Returns number of bytes read
******************************************************************************/
uint32 halFlashRead(uint32 address, uint8* data, uint32 bytes)
{
    uint32 i;

    FLASH_SPI_BEGIN();

    // Send READ instruction
    FLASH_SPI_TX(FLASH_INSTRUCTION_READ);
    FLASH_SPI_WAIT_RXRDY();

    // Address
    FLASH_SPI_TX((uint8)(address >> 16));
    FLASH_SPI_WAIT_RXRDY();
    FLASH_SPI_TX((uint8)(address >> 8));
    FLASH_SPI_WAIT_RXRDY();
    FLASH_SPI_TX((uint8)(address));
    FLASH_SPI_WAIT_RXRDY();

    for (i = 0; i < bytes; i++)
    {
        FLASH_SPI_TX(0x00);
        FLASH_SPI_WAIT_RXRDY();
        data[i] = FLASH_SPI_RX();
    }

    FLASH_SPI_END();

    return(i);

} // halFlashRead

/**************************************************************************//**
* @fn       halFlashPageWrite(uint16 page, uint8* data, uint16 bytes)
*
* @brief    Write bytes to SPI flash page.
*
* @param    page        SPI flash page to write to
* @param    data        Pointer to buffer with data
* @param    bytes       Number of bytes to write
*
* @return   Returns number of bytes written
******************************************************************************/
uint32 halFlashPageWrite(uint16 page, uint8* data, uint16 bytes)
{
    uint32 i;
    uint8 status;

    if (bytes == 0 || bytes > 256)
    {
        return(0);
    }

    // Enable write
    FLASH_SPI_BEGIN();
    FLASH_SPI_TX(FLASH_INSTRUCTION_WREN);
    FLASH_SPI_WAIT_RXRDY();
    FLASH_SPI_END();

    // Start write sequence
    FLASH_SPI_BEGIN();
    FLASH_SPI_TX(FLASH_INSTRUCTION_PW);
    FLASH_SPI_WAIT_RXRDY();

    // Address
    FLASH_SPI_TX((uint8)(page >> 8));
    FLASH_SPI_WAIT_RXRDY();
    FLASH_SPI_TX((uint8)(page));
    FLASH_SPI_WAIT_RXRDY();
    FLASH_SPI_TX((uint8)(0x00));
    FLASH_SPI_WAIT_RXRDY();

    // Transfer the data
    for (i = 0; i < bytes; i++)
    {
        FLASH_SPI_TX(data[i]);
        FLASH_SPI_WAIT_RXRDY();
    }

    FLASH_SPI_END();

    // Wait for write to finish
    FLASH_SPI_BEGIN();
    FLASH_SPI_TX(FLASH_INSTRUCTION_RDSR);
    FLASH_SPI_WAIT_RXRDY();
    do {
        FLASH_SPI_TX(0x00);
        FLASH_SPI_WAIT_RXRDY();
        status = FLASH_SPI_RX();
    } while (status & FLASH_STATUS_WIP_BM);

    FLASH_SPI_END();

    return(i);
} // halFlashPageWrite


/******************************************************************************
  Copyright 2011 Texas Instruments Incorporated. All rights reserved.

  IMPORTANT: Your use of this Software is limited to those specific rights
  granted under the terms of a software license agreement between the user
  who downloaded the software, his/her employer (which must be your employer)
  and Texas Instruments Incorporated (the "License").  You may not use this
  Software unless you agree to abide by the terms of the License. The License
  limits your use, and you acknowledge, that the Software may not be modified,
  copied or distributed unless embedded on a Texas Instruments microcontroller
  or used solely and exclusively in conjunction with a Texas Instruments radio
  frequency transceiver, which is integrated into your product.  Other than for
  the foregoing purpose, you may not use, reproduce, copy, prepare derivative
  works of, modify, distribute, perform, display or sell this Software and/or
  its documentation for any purpose.

  YOU FURTHER ACKNOWLEDGE AND AGREE THAT THE SOFTWARE AND DOCUMENTATION ARE
  PROVIDED “AS IS” WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESS OR IMPLIED,
  INCLUDING WITHOUT LIMITATION, ANY WARRANTY OF MERCHANTABILITY, TITLE,
  NON-INFRINGEMENT AND FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT SHALL
  TEXAS INSTRUMENTS OR ITS LICENSORS BE LIABLE OR OBLIGATED UNDER CONTRACT,
  NEGLIGENCE, STRICT LIABILITY, CONTRIBUTION, BREACH OF WARRANTY, OR OTHER
  LEGAL EQUITABLE THEORY ANY DIRECT OR INDIRECT DAMAGES OR EXPENSES
  INCLUDING BUT NOT LIMITED TO ANY INCIDENTAL, SPECIAL, INDIRECT, PUNITIVE
  OR CONSEQUENTIAL DAMAGES, LOST PROFITS OR LOST DATA, COST OF PROCUREMENT
  OF SUBSTITUTE GOODS, TECHNOLOGY, SERVICES, OR ANY CLAIMS BY THIRD PARTIES
  (INCLUDING BUT NOT LIMITED TO ANY DEFENSE THEREOF), OR OTHER SIMILAR COSTS.

  Should you have any questions regarding your right to use this Software,
  contact Texas Instruments Incorporated at www.TI.com.
******************************************************************************/

