写一个uboot下的MT25QU01G驱动
由于MT25QU01G是一款SPI NOR闪存,因此在U-Boot中的驱动程序将使用SPI总线来与它交互。下面是一个简单的MT25QU01G驱动程序示例,它使用U-Boot的SPI API来实现与闪存的通信:
#include <common.h>
#include <dm.h>
#include <spi.h>
#define MT25QU01G_CMD_READ 0x03
#define MT25QU01G_CMD_WRITE_ENABLE 0x06
#define MT25QU01G_CMD_WRITE_DISABLE 0x04
#define MT25QU01G_CMD_ERASE_SECTOR 0x20
#define MT25QU01G_CMD_ERASE_CHIP 0xC7
#define MT25QU01G_CMD_READ_STATUS 0x05
#define MT25QU01G_STATUS_BUSY (1 << 0)
struct mt25qu01g_spi_flash {
struct spi_slave *spi;
};
static int mt25qu01g_spi_flash_read(struct udevice *dev, uint32_t addr, size_t size, void *dst)
{
struct mt25qu01g_spi_flash *priv = dev_get_priv(dev);
u8 cmd[4] = {MT25QU01G_CMD_READ, addr >> 16, addr >> 8, addr};
struct spi_buf buf[2] = {
{ .tx_buf = cmd, .len = sizeof(cmd) },
{ .rx_buf = dst, .len = size }
};
struct spi_transfer xfer = {
.tx_buf = cmd,
.rx_buf = dst,
.len = size,
.bits_per_word = 8,
};
int ret;
ret = spi_sync(priv->spi, &xfer, 1);
if (ret)
dev_err(dev, "read error %d\n", ret);
return ret;
}
static int mt25qu01g_spi_flash_write(struct udevice *dev, uint32_t addr, size_t size, const void *src)
{
struct mt25qu01g_spi_flash *priv = dev_get_priv(dev);
u8 cmd[4] = {MT25QU01G_CMD_WRITE_ENABLE};
u8 status;
int ret;
ret = spi_write(priv->spi, cmd, sizeof(cmd));
if (ret)
return ret;
cmd[0] = MT25QU01G_CMD_READ_STATUS;
do {
ret = spi_xfer(priv->spi, cmd, cmd, sizeof(cmd));
if (ret)
return ret;
status = cmd[1];
} while (status & MT25QU01G_STATUS_BUSY);
cmd[0] = MT25QU01G_CMD_WRITE;
cmd[1] = addr >> 16;
cmd[2] = addr >> 8;
cmd[3] = addr;
ret = spi_write_then_read(priv->spi, cmd, sizeof(cmd), src, size);
if (ret)
return ret;
cmd[0] = MT25QU01G_CMD_WRITE_DISABLE;
ret = spi_write(priv->spi, cmd, sizeof(cmd));
if (ret)
return ret;
return 0;
}
static int mt25qu01g_spi_flash_erase(struct udevice *dev, uint32_t addr, size_t size)
{
struct mt25qu01g_spi_flash *priv = dev_get_priv(dev);
u8 cmd[4] = {MT25QU01G_CMD_WRITE_ENABLE};
u8 status;
int ret;
ret = spi_write(priv->spi, cmd, sizeof(cmd));
if (ret)
return ret;
cmd[0] = MT25QU01G_CMD_READ_STATUS;
do {
ret = spi_xfer(priv->spi, cmd, cmd, sizeof(cmd));
if (ret)
return ret;
status = cmd[1];
} while (status & MT25QU01G_STATUS_BUSY);
if (size == MT25QU01G_SECTOR_SIZE) {
cmd[0] = MT25QU01G_CMD_ERASE_SECTOR;
cmd[1] = addr >> 16;
cmd[2] = addr >> 8;
cmd[3] = addr;
ret = spi_write(priv->spi, cmd, sizeof(cmd));
if (ret)
return ret;
} else if (size == MT25QU01G_FLASH_SIZE) {
cmd[0] = MT25QU01G_CMD_ERASE_CHIP;
ret = spi_write(priv->spi, cmd, sizeof(cmd));
if (ret)
return ret;
} else {
return -EINVAL;
}
cmd[0] = MT25QU01G_CMD_READ_STATUS;
do {
ret = spi_xfer(priv->spi, cmd, cmd, sizeof(cmd));
if (ret)
return ret;
status = cmd[1];
} while (status & MT25QU01G_STATUS_BUSY);
return 0;
}
static int mt25qu01g_spi_flash_probe(struct udevice *dev)
{
struct mt25qu01g_spi_flash *priv = dev_get_priv(dev);
struct spi_slave *spi;
int ret;
ret = spi_get_slave(dev, &spi);
if (ret)
return ret;
priv->spi = spi;
return 0;
}
static const struct spi_flash_ops mt25qu01g_spi_flash_ops = {
.read = mt25qu01g_spi_flash_read,
.write = mt25qu01g_spi_flash_write,
.erase = mt25qu01g_spi_flash_erase,
};
static const struct udevice_id mt25qu01g_spi_flash_ids[] = {
{ .compatible = "micron,mt25qu01g" },
{ }
};
U_BOOT_DRIVER(mt25qu01g_spi_flash) = {
.name = "mt25qu01g_spi_flash",
.id = UCLASS_SPI_FLASH,
.of_match = mt25qu01g_spi_flash_ids,
.probe = mt25qu01g_spi_flash_probe,
.priv_auto_alloc_size = sizeof(struct mt25qu01g_spi_flash),
.ops = &mt25qu01g_spi_flash_ops,
};
该驱动程序使用spi_xfer()函数来发送和接收数据,该函数由U-Boot的SPI API提供。该驱动程序还使用了MT25QU01G闪存器件的一些命令,如读取、写入、擦除和读取状态。此外,该驱动程序还实现了spi_flash_ops结构体中定义的read()、write()和erase()函数,以便U-Boot可以使用这些函数来读取、写入和擦除闪存。
最后,该驱动程序还定义了一个U-Boot设备驱动程序,以便它可以被U-Boot识别并加载到内存中。此设备驱动程序使用的设备ID是与MT25QU01G SPI NOR闪存器件兼容的。
原文地址: https://www.cveoy.top/t/topic/ADZ 著作权归作者所有。请勿转载和采集!