143 lines
4.6 KiB
C
143 lines
4.6 KiB
C
/*
|
|
* Copyright (c) 2016, Freescale Semiconductor, Inc.
|
|
* Copyright 2016-2021 NXP
|
|
* All rights reserved.
|
|
*
|
|
* SPDX-License-Identifier: BSD-3-Clause
|
|
*/
|
|
|
|
#include "mx25r_flash.h"
|
|
|
|
#define MX25R_BYTE_ADDR1(address) ((uint8_t)(((address) >> 16UL) & 0x0FUL))
|
|
#define MX25R_BYTE_ADDR2(address) ((uint8_t)(((address) >> 8UL) & 0x0FUL))
|
|
#define MX25R_BYTE_ADDR3(address) ((uint8_t)((address)&0x0FUL))
|
|
|
|
/* initialize 'mx25r_instance' */
|
|
mx25r_err_t mx25r_init(struct mx25r_instance *instance, transfer_cb_t callback, void *callback_prv)
|
|
{
|
|
instance->callback = callback;
|
|
instance->prv = callback_prv;
|
|
return mx25r_err_ok;
|
|
}
|
|
|
|
/* read 'rdid' to 'result' */
|
|
mx25r_err_t mx25r_cmd_rdid(struct mx25r_instance *instance, struct mx25r_rdid_result *result)
|
|
{
|
|
instance->cmd[0] = 0x9f;
|
|
instance->callback(instance->prv, instance->cmd, NULL, 1, false);
|
|
instance->callback(instance->prv, NULL, (uint8_t *)result, sizeof(*result), true);
|
|
return mx25r_err_ok;
|
|
}
|
|
|
|
/* read n bytes starting at 'address' */
|
|
mx25r_err_t mx25r_cmd_read(struct mx25r_instance *instance, uint32_t address, uint8_t *buffer, uint32_t size)
|
|
{
|
|
if ((address & 0xFF000000U) != 0x00U)
|
|
{
|
|
return mx25r_err_out_of_range;
|
|
}
|
|
instance->cmd[0] = 0x03;
|
|
instance->cmd[1] = MX25R_BYTE_ADDR1(address);
|
|
instance->cmd[2] = MX25R_BYTE_ADDR2(address);
|
|
instance->cmd[3] = MX25R_BYTE_ADDR3(address);
|
|
instance->callback(instance->prv, instance->cmd, NULL, 4, false);
|
|
instance->callback(instance->prv, NULL, (uint8_t *)buffer, size, true);
|
|
return mx25r_err_ok;
|
|
}
|
|
|
|
/* no operation */
|
|
mx25r_err_t mx25r_cmd_nop(struct mx25r_instance *instance)
|
|
{
|
|
instance->callback(instance->prv, instance->cmd, NULL, 1, true);
|
|
return mx25r_err_ok;
|
|
}
|
|
|
|
/* read status register */
|
|
mx25r_err_t mx25r_cmd_rdsr(struct mx25r_instance *instance, struct mx25r_rdsr_result *result)
|
|
{
|
|
instance->cmd[0] = 0x05;
|
|
instance->callback(instance->prv, instance->cmd, NULL, 1, false);
|
|
instance->callback(instance->prv, NULL, (uint8_t *)result, sizeof(*result), true);
|
|
return mx25r_err_ok;
|
|
}
|
|
|
|
/* disable write operations */
|
|
mx25r_err_t mx25r_cmd_wrdi(struct mx25r_instance *instance)
|
|
{
|
|
instance->cmd[0] = 0x04;
|
|
instance->callback(instance->prv, instance->cmd, NULL, 1, true);
|
|
return mx25r_err_ok;
|
|
}
|
|
|
|
/* enable write operations */
|
|
mx25r_err_t mx25r_cmd_wren(struct mx25r_instance *instance)
|
|
{
|
|
instance->cmd[0] = 0x06;
|
|
instance->callback(instance->prv, instance->cmd, NULL, 1, true);
|
|
return mx25r_err_ok;
|
|
}
|
|
|
|
/* write n bytes (256 max) starting at 'address' aligned to 256 */
|
|
mx25r_err_t mx25r_cmd_write(struct mx25r_instance *instance,
|
|
uint32_t address_256_align,
|
|
uint8_t *buffer,
|
|
uint32_t size_256_max)
|
|
{
|
|
struct mx25r_rdsr_result result;
|
|
if ((address_256_align & 0xFF000000U) != 0x00U)
|
|
{
|
|
return mx25r_err_out_of_range;
|
|
}
|
|
if ((address_256_align & 0xFFU) != 0x00U)
|
|
{
|
|
return mx25r_err_alignement;
|
|
}
|
|
if (size_256_max > 256U)
|
|
{
|
|
return mx25r_err_out_of_range;
|
|
}
|
|
/* enable write and wait until WEL is 1 */
|
|
(void)mx25r_cmd_wren(instance);
|
|
do
|
|
{
|
|
(void)mx25r_cmd_rdsr(instance, &result);
|
|
} while (((uint8_t)result.sr0 & 0x2U) == 0x00U);
|
|
/* write sequence */
|
|
instance->cmd[0] = 0x02;
|
|
instance->cmd[1] = MX25R_BYTE_ADDR1(address_256_align);
|
|
instance->cmd[2] = MX25R_BYTE_ADDR2(address_256_align);
|
|
instance->cmd[3] = 0;
|
|
instance->callback(instance->prv, instance->cmd, NULL, 4, false);
|
|
instance->callback(instance->prv, (uint8_t *)buffer, NULL, size_256_max, true);
|
|
/* wait until WRI is 0 and WEL is 0 */
|
|
do
|
|
{
|
|
(void)mx25r_cmd_rdsr(instance, &result);
|
|
} while (((uint8_t)result.sr0 & 0x3U) != 0x00U);
|
|
return mx25r_err_ok;
|
|
}
|
|
|
|
/* erase sector at 'address' aligned to sector size = 4kB */
|
|
mx25r_err_t mx25r_cmd_sector_erase(struct mx25r_instance *instance, uint32_t address)
|
|
{
|
|
struct mx25r_rdsr_result result;
|
|
/* enable write and wait until WEL is 1 */
|
|
(void)mx25r_cmd_wren(instance);
|
|
do
|
|
{
|
|
(void)mx25r_cmd_rdsr(instance, &result);
|
|
} while (((uint8_t)result.sr0 & 0x2U) == 0x00U);
|
|
/* write sequence */
|
|
instance->cmd[0] = 0x20;
|
|
instance->cmd[1] = MX25R_BYTE_ADDR1(address);
|
|
instance->cmd[2] = MX25R_BYTE_ADDR2(address);
|
|
instance->cmd[3] = MX25R_BYTE_ADDR3(address);
|
|
instance->callback(instance->prv, instance->cmd, NULL, 4, true);
|
|
/* wait until WRI is 0 and WEL is 0 */
|
|
do
|
|
{
|
|
(void)mx25r_cmd_rdsr(instance, &result);
|
|
} while (((uint8_t)result.sr0 & 0x3U) != 0x00U);
|
|
return mx25r_err_ok;
|
|
}
|