/*
 * Copyright (c) 2013 - 2014, Freescale Semiconductor, Inc.
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without modification,
 * are permitted provided that the following conditions are met:
 *
 * o Redistributions of source code must retain the above copyright notice, this list
 *   of conditions and the following disclaimer.
 *
 * o 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.
 *
 * o Neither the name of Freescale Semiconductor, Inc. nor the names of its
 *   contributors may be used to endorse or promote products derived from this
 *   software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS 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 __SPI_FLASH_INTERNAL_H__
#define __SPI_FLASH_INTERNAL_H__


#include "spi_flash/spi_flash.h"
#include "spi_flash/fsl_spi_abstraction.h"

/*!
 * @addtogroup spi_flash_internal
 * @{
 */

/*!
 * @file
 */

/*!
 * @brief  SPI Flash programming timeout.
 */
#define SPI_FLASH_PROG_TIMEOUT		(20 * 1000)

/*!
 * @brief  SPI Flash page erase timeout.
 */
#define SPI_FLASH_PAGE_ERASE_TIMEOUT	(50 * 1000)

/*!
 * @brief  SPI Flash sector erase timeout.
 */
#define SPI_FLASH_SECTOR_ERASE_TIMEOUT	(100 * 1000)

#define CMD_READ_ID			0x9f 

#define CMD_READ_ARRAY_SLOW		0x03
#define CMD_READ_ARRAY_FAST		0x0b

#define CMD_WRITE_STATUS		0x01
#define CMD_PAGE_PROGRAM		0x02
#define CMD_WRITE_DISABLE		0x04
#define CMD_READ_STATUS			0x05
#define CMD_WRITE_ENABLE		0x06
#define CMD_ERASE_4K			0x20
#define CMD_ERASE_32K			0x52
#define CMD_ERASE_64K			0xd8
#define CMD_ERASE_CHIP			0xc7

/*!
 * @brief Common status bit
 */
#define STATUS_WIP			0x01

#if defined(__cplusplus)
extern "C" {
#endif

/*!
 * @brief Send a single-byte command to the device and read the response
 */
int32_t spi_flash_cmd(uint32_t instance, spi_slave_dev *spi, uint8_t cmd, void *response, size_t len);

/*!
 * @brief Send a multi-byte command to the device and read the response. Used for flash array reads, etc.
 */
int32_t spi_flash_cmd_read(uint32_t instance, spi_slave_dev *spi, const uint8_t *cmd,
		size_t cmd_len, uint8_t *data, size_t data_len);

int32_t spi_flash_cmd_read_fast(spi_flash *flash, uint32_t offset,
		size_t len, uint8_t *data);

/*!
 * @brief Send a multi-byte command to the device followed by (optional) data. Used for programming the flash array, etc.
 */
int32_t spi_flash_cmd_write(uint32_t instance, spi_slave_dev *spi, const uint8_t *cmd, size_t cmd_len,
		const uint8_t *data, size_t data_len);

/*!
 * @brief Write the requested data out breaking it up into multiple write commands as needed per the write size.
 */
int32_t spi_flash_cmd_write_multi(spi_flash *flash, uint32_t offset,
		size_t len, const uint8_t *buf);

/*!
 * @brief    Enable writing on the SPI flash.
 *
 * @param[in] flash        spi flash instance.
 *
 * @return    status       error code.
 */
static inline int32_t spi_flash_cmd_write_enable(spi_flash *flash)
{
	return spi_flash_cmd(flash->instance, flash->spi, CMD_WRITE_ENABLE, NULL, 0);
}

/*!
 * @brief    Disable writing on the SPI flash.
 *
 * @param[in] flash        spi flash instance.
 *
 * @return    status       error code.
 */
static inline int32_t spi_flash_cmd_write_disable(spi_flash *flash)
{
	return spi_flash_cmd(flash->instance, flash->spi, CMD_WRITE_DISABLE, NULL, 0);
}

/*!
 * @brief    Program the status register.
 *
 * @param[in] flash        spi flash instance.
 * @param[in] sr           value that will be set to status register.
 *
 * @return    status       error code.
 */
int32_t spi_flash_cmd_write_status(spi_flash *flash, uint8_t sr);

/*!
 * @brief    Send a command to the device and wait for some bit to clear itself.
 *
 * @param[in] flash        spi flash structure.
 * @param[in] timeout      timeout duration.
 * @param[in] cmd          status command.
 * @param[in] poll_bit     status bit that need to be checked.
 *
 * @return    status       error code.
 */
int32_t spi_flash_cmd_poll_bit(spi_flash *flash, unsigned long timeout,
			   uint8_t cmd, uint8_t poll_bit);

/*!
 * @brief    Send the read status command to the device and wait for the wip (write-in-progress) bit to clear itself.
 *
 * @param[in] flash        spi flash structure.
 * @param[in] timeout      timeout duration.
 *
 * @return    status       error code.
 */
int32_t spi_flash_cmd_wait_ready(spi_flash *flash, unsigned long timeout);

/*!
 * @brief    Common funcion erase blocks in a spi flash.
 *
 * @param[in] flash        spi flash structure.
 * @param[in] offset       offset in spi flash to erase from.
 * @param[in] len          length in spi flash to be erased.
 *
 * @return    status       error code.
 */
int32_t spi_flash_cmd_erase(spi_flash *flash, uint32_t offset, size_t len);

/*!
 * @brief    Probe a atmel spi flash.
 *
 * @param[in] instance     spi master bus index.
 * @param[in] spi          spi slave device.
 * @param[in] idcode       idcode of flash.
 *
 * @return    status       error code.
 */
spi_flash *spi_flash_probe_atmel(uint32_t instance, spi_slave_dev *spi, uint8_t *idcode);

#if defined(__cplusplus)
}
#endif

//! @}

#endif

/*******************************************************************************
 * EOF
 ******************************************************************************/
