1
0
mirror of https://github.com/RIOT-OS/RIOT.git synced 2024-12-29 04:50:03 +01:00

mtd_spi_nor: Move const params to separate struct

This commit is contained in:
Koen Zandberg 2020-02-10 20:39:49 +01:00
parent 2e32a11822
commit e5fa8921b3
No known key found for this signature in database
GPG Key ID: 0E63411F8FCA8247
2 changed files with 79 additions and 53 deletions

View File

@ -83,6 +83,19 @@ typedef struct __attribute__((packed)) {
*/
#define SPI_NOR_F_SECT_32K (2)
/**
* @brief Compile-time parameters for a serial flash device
*/
typedef struct {
const mtd_spi_nor_opcode_t *opcode; /**< Opcode table for the device */
spi_clk_t clk; /**< SPI clock */
uint16_t flag; /**< Config flags */
spi_t spi; /**< SPI bus the device is connected to */
spi_mode_t mode; /**< SPI mode */
gpio_t cs; /**< CS pin GPIO handle */
uint8_t addr_width; /**< Number of bytes in addresses, usually 3 for small devices */
} mtd_spi_nor_params_t;
/**
* @brief Device descriptor for serial flash memory devices
*
@ -90,12 +103,7 @@ typedef struct __attribute__((packed)) {
*/
typedef struct {
mtd_dev_t base; /**< inherit from mtd_dev_t object */
const mtd_spi_nor_opcode_t *opcode; /**< Opcode table for the device */
spi_t spi; /**< SPI bus the device is connected to */
gpio_t cs; /**< CS pin GPIO handle */
spi_mode_t mode; /**< SPI mode */
spi_clk_t clk; /**< SPI clock */
uint16_t flag; /**< Config flags */
const mtd_spi_nor_params_t *params; /**< SPI NOR params */
mtd_jedec_id_t jedec_id; /**< JEDEC ID of the chip */
/**
* @brief bitmask to corresponding to the page address
@ -109,7 +117,6 @@ typedef struct {
* Computed by mtd_spi_nor_init, no need to touch outside the driver.
*/
uint32_t sec_addr_mask;
uint8_t addr_width; /**< Number of bytes in addresses, usually 3 for small devices */
/**
* @brief number of right shifts to get the address to the start of the page
*

View File

@ -67,6 +67,17 @@ const mtd_desc_t mtd_spi_nor_driver = {
.power = mtd_spi_nor_power,
};
static void mtd_spi_acquire(const mtd_spi_nor_t *dev)
{
spi_acquire(dev->params->spi, dev->params->cs,
dev->params->mode, dev->params->clk);
}
static void mtd_spi_release(const mtd_spi_nor_t *dev)
{
spi_release(dev->params->spi);
}
/**
* @internal
* @brief Send command opcode followed by address, followed by a read to buffer
@ -84,10 +95,10 @@ static void mtd_spi_cmd_addr_read(const mtd_spi_nor_t *dev, uint8_t opcode,
(void *)dev, (unsigned int)opcode, addr.u8[0], addr.u8[1], addr.u8[2],
addr.u8[3], dest, count);
uint8_t *addr_buf = &addr.u8[4 - dev->addr_width];
uint8_t *addr_buf = &addr.u8[4 - dev->params->addr_width];
if (ENABLE_TRACE) {
TRACE("mtd_spi_cmd_addr_read: addr:");
for (unsigned int i = 0; i < dev->addr_width; ++i) {
for (unsigned int i = 0; i < dev->params->addr_width; ++i) {
TRACE(" %02x", addr_buf[i]);
}
TRACE("\n");
@ -95,11 +106,13 @@ static void mtd_spi_cmd_addr_read(const mtd_spi_nor_t *dev, uint8_t opcode,
do {
/* Send opcode followed by address */
spi_transfer_byte(dev->spi, dev->cs, true, opcode);
spi_transfer_bytes(dev->spi, dev->cs, true, (char *)addr_buf, NULL, dev->addr_width);
spi_transfer_byte(dev->params->spi, dev->params->cs, true, opcode);
spi_transfer_bytes(dev->params->spi, dev->params->cs, true,
(char *)addr_buf, NULL, dev->params->addr_width);
/* Read data */
spi_transfer_bytes(dev->spi, dev->cs, false, NULL, dest, count);
spi_transfer_bytes(dev->params->spi, dev->params->cs, false,
NULL, dest, count);
} while (0);
}
@ -120,10 +133,10 @@ static void mtd_spi_cmd_addr_write(const mtd_spi_nor_t *dev, uint8_t opcode,
(void *)dev, (unsigned int)opcode, addr.u8[0], addr.u8[1], addr.u8[2],
addr.u8[3], src, count);
uint8_t *addr_buf = &addr.u8[4 - dev->addr_width];
uint8_t *addr_buf = &addr.u8[4 - dev->params->addr_width];
if (ENABLE_TRACE) {
TRACE("mtd_spi_cmd_addr_write: addr:");
for (unsigned int i = 0; i < dev->addr_width; ++i) {
for (unsigned int i = 0; i < dev->params->addr_width; ++i) {
TRACE(" %02x", addr_buf[i]);
}
TRACE("\n");
@ -131,12 +144,14 @@ static void mtd_spi_cmd_addr_write(const mtd_spi_nor_t *dev, uint8_t opcode,
do {
/* Send opcode followed by address */
spi_transfer_byte(dev->spi, dev->cs, true, opcode);
spi_transfer_byte(dev->params->spi, dev->params->cs, true, opcode);
bool cont = (count > 0); /* only keep CS asserted when there is data that follows */
spi_transfer_bytes(dev->spi, dev->cs, cont, (char *)addr_buf, NULL, dev->addr_width);
spi_transfer_bytes(dev->params->spi, dev->params->cs, cont,
(char *)addr_buf, NULL, dev->params->addr_width);
/* Write data */
if (cont) {
spi_transfer_bytes(dev->spi, dev->cs, false, (void *)src, NULL, count);
spi_transfer_bytes(dev->params->spi, dev->params->cs,
false, (void *)src, NULL, count);
}
} while (0);
}
@ -155,7 +170,7 @@ static void mtd_spi_cmd_read(const mtd_spi_nor_t *dev, uint8_t opcode, void *des
TRACE("mtd_spi_cmd_read: %p, %02x, %p, %" PRIu32 "\n",
(void *)dev, (unsigned int)opcode, dest, count);
spi_transfer_regs(dev->spi, dev->cs, opcode, NULL, dest, count);
spi_transfer_regs(dev->params->spi, dev->params->cs, opcode, NULL, dest, count);
}
/**
@ -172,7 +187,8 @@ static void __attribute__((unused)) mtd_spi_cmd_write(const mtd_spi_nor_t *dev,
TRACE("mtd_spi_cmd_write: %p, %02x, %p, %" PRIu32 "\n",
(void *)dev, (unsigned int)opcode, src, count);
spi_transfer_regs(dev->spi, dev->cs, opcode, (void *)src, NULL, count);
spi_transfer_regs(dev->params->spi, dev->params->cs, opcode,
(void *)src, NULL, count);
}
/**
@ -187,7 +203,7 @@ static void mtd_spi_cmd(const mtd_spi_nor_t *dev, uint8_t opcode)
TRACE("mtd_spi_cmd: %p, %02x\n",
(void *)dev, (unsigned int)opcode);
spi_transfer_byte(dev->spi, dev->cs, false, opcode);
spi_transfer_byte(dev->params->spi, dev->params->cs, false, opcode);
}
/**
@ -213,15 +229,17 @@ static int mtd_spi_read_jedec_id(const mtd_spi_nor_t *dev, mtd_jedec_id_t *out)
int status = 0;
mtd_jedec_id_t jedec;
DEBUG("mtd_spi_read_jedec_id: rdid=0x%02x\n", (unsigned int)dev->opcode->rdid);
DEBUG("mtd_spi_read_jedec_id: rdid=0x%02x\n",
(unsigned int)dev->params->opcode->rdid);
/* Send opcode */
spi_transfer_byte(dev->spi, dev->cs, true, dev->opcode->rdid);
spi_transfer_byte(dev->params->spi, dev->params->cs, true, dev->params->opcode->rdid);
/* Read manufacturer ID */
jedec.bank = 1;
while (status == 0) {
jedec.manuf = spi_transfer_byte(dev->spi, dev->cs, true, 0);
jedec.manuf = spi_transfer_byte(dev->params->spi,
dev->params->cs, true, 0);
if (jedec.manuf == JEDEC_NEXT_BANK) {
/* next bank, see JEP106 */
DEBUG("mtd_spi_read_jedec_id: manuf bank incr\n");
@ -244,7 +262,8 @@ static int mtd_spi_read_jedec_id(const mtd_spi_nor_t *dev, mtd_jedec_id_t *out)
/* Read device ID */
if (status == 0) {
spi_transfer_bytes(dev->spi, dev->cs, false, NULL, (char *)&jedec.device[0], sizeof(jedec.device));
spi_transfer_bytes(dev->params->spi, dev->params->cs, false, NULL,
(char *)&jedec.device[0], sizeof(jedec.device));
}
DEBUG("mtd_spi_read_jedec_id: device=0x%02x, 0x%02x\n",
(unsigned int)jedec.device[0], (unsigned int)jedec.device[1]);
@ -260,7 +279,7 @@ static inline void wait_for_write_complete(const mtd_spi_nor_t *dev)
{
do {
uint8_t status;
mtd_spi_cmd_read(dev, dev->opcode->rdsr, &status, sizeof(status));
mtd_spi_cmd_read(dev, dev->params->opcode->rdsr, &status, sizeof(status));
TRACE("mtd_spi_nor: wait device status = 0x%02x\n", (unsigned int)status);
if ((status & 1) == 0) { /* TODO magic number */
@ -280,7 +299,7 @@ static int mtd_spi_nor_init(mtd_dev_t *mtd)
mtd_spi_nor_t *dev = (mtd_spi_nor_t *)mtd;
DEBUG("mtd_spi_nor_init: -> spi: %lx, cs: %lx, opcodes: %p\n",
(unsigned long)dev->spi, (unsigned long)dev->cs, (void *)dev->opcode);
(unsigned long)dev->params->spi, (unsigned long)dev->params->cs, (void *)dev->params->opcode);
DEBUG("mtd_spi_nor_init: %" PRIu32 " bytes "
"(%" PRIu32 " sectors, %" PRIu32 " bytes/sector, "
@ -290,28 +309,28 @@ static int mtd_spi_nor_init(mtd_dev_t *mtd)
mtd->sector_count, mtd->pages_per_sector * mtd->page_size,
mtd->pages_per_sector * mtd->sector_count,
mtd->pages_per_sector, mtd->page_size);
DEBUG("mtd_spi_nor_init: Using %u byte addresses\n", dev->addr_width);
DEBUG("mtd_spi_nor_init: Using %u byte addresses\n", dev->params->addr_width);
if (dev->addr_width == 0) {
if (dev->params->addr_width == 0) {
return -EINVAL;
}
/* CS */
DEBUG("mtd_spi_nor_init: CS init\n");
spi_init_cs(dev->spi, dev->cs);
spi_init_cs(dev->params->spi, dev->params->cs);
spi_acquire(dev->spi, dev->cs, dev->mode, dev->clk);
mtd_spi_acquire(dev);
int res = mtd_spi_read_jedec_id(dev, &dev->jedec_id);
if (res < 0) {
spi_release(dev->spi);
mtd_spi_release(dev);
return -EIO;
}
DEBUG("mtd_spi_nor_init: Found chip with ID: (%d, 0x%02x, 0x%02x, 0x%02x)\n",
dev->jedec_id.bank, dev->jedec_id.manuf, dev->jedec_id.device[0], dev->jedec_id.device[1]);
uint8_t status;
mtd_spi_cmd_read(dev, dev->opcode->rdsr, &status, sizeof(status));
spi_release(dev->spi);
mtd_spi_cmd_read(dev, dev->params->opcode->rdsr, &status, sizeof(status));
mtd_spi_release(dev);
DEBUG("mtd_spi_nor_init: device status = 0x%02x\n", (unsigned int)status);
@ -375,9 +394,9 @@ static int mtd_spi_nor_read(mtd_dev_t *mtd, void *dest, uint32_t addr, uint32_t
}
be_uint32_t addr_be = byteorder_htonl(addr);
spi_acquire(dev->spi, dev->cs, dev->mode, dev->clk);
mtd_spi_cmd_addr_read(dev, dev->opcode->read, addr_be, dest, size);
spi_release(dev->spi);
mtd_spi_acquire(dev);
mtd_spi_cmd_addr_read(dev, dev->params->opcode->read, addr_be, dest, size);
mtd_spi_release(dev);
return size;
}
@ -406,17 +425,17 @@ static int mtd_spi_nor_write(mtd_dev_t *mtd, const void *src, uint32_t addr, uin
}
be_uint32_t addr_be = byteorder_htonl(addr);
spi_acquire(dev->spi, dev->cs, dev->mode, dev->clk);
mtd_spi_acquire(dev);
/* write enable */
mtd_spi_cmd(dev, dev->opcode->wren);
mtd_spi_cmd(dev, dev->params->opcode->wren);
/* Page program */
mtd_spi_cmd_addr_write(dev, dev->opcode->page_program, addr_be, src, size);
mtd_spi_cmd_addr_write(dev, dev->params->opcode->page_program, addr_be, src, size);
/* waiting for the command to complete before returning */
wait_for_write_complete(dev);
spi_release(dev->spi);
mtd_spi_release(dev);
return size;
}
@ -444,32 +463,32 @@ static int mtd_spi_nor_erase(mtd_dev_t *mtd, uint32_t addr, uint32_t size)
return -EOVERFLOW;
}
spi_acquire(dev->spi, dev->cs, dev->mode, dev->clk);
mtd_spi_acquire(dev);
while (size) {
be_uint32_t addr_be = byteorder_htonl(addr);
/* write enable */
mtd_spi_cmd(dev, dev->opcode->wren);
mtd_spi_cmd(dev, dev->params->opcode->wren);
if (size == total_size) {
mtd_spi_cmd(dev, dev->opcode->chip_erase);
mtd_spi_cmd(dev, dev->params->opcode->chip_erase);
size -= total_size;
}
else if ((dev->flag & SPI_NOR_F_SECT_32K) && (size >= MTD_32K) &&
else if ((dev->params->flag & SPI_NOR_F_SECT_32K) && (size >= MTD_32K) &&
((addr & MTD_32K_ADDR_MASK) == 0)) {
/* 32 KiB blocks can be erased with block erase command */
mtd_spi_cmd_addr_write(dev, dev->opcode->block_erase_32k, addr_be, NULL, 0);
mtd_spi_cmd_addr_write(dev, dev->params->opcode->block_erase_32k, addr_be, NULL, 0);
addr += MTD_32K;
size -= MTD_32K;
}
else if ((dev->flag & SPI_NOR_F_SECT_4K) && (size >= MTD_4K) &&
else if ((dev->params->flag & SPI_NOR_F_SECT_4K) && (size >= MTD_4K) &&
((addr & MTD_4K_ADDR_MASK) == 0)) {
/* 4 KiB sectors can be erased with sector erase command */
mtd_spi_cmd_addr_write(dev, dev->opcode->sector_erase, addr_be, NULL, 0);
mtd_spi_cmd_addr_write(dev, dev->params->opcode->sector_erase, addr_be, NULL, 0);
addr += MTD_4K;
size -= MTD_4K;
}
else {
mtd_spi_cmd_addr_write(dev, dev->opcode->block_erase, addr_be, NULL, 0);
mtd_spi_cmd_addr_write(dev, dev->params->opcode->block_erase, addr_be, NULL, 0);
addr += sector_size;
size -= sector_size;
}
@ -477,7 +496,7 @@ static int mtd_spi_nor_erase(mtd_dev_t *mtd, uint32_t addr, uint32_t size)
/* waiting for the command to complete before continuing */
wait_for_write_complete(dev);
}
spi_release(dev->spi);
mtd_spi_release(dev);
return 0;
}
@ -486,16 +505,16 @@ static int mtd_spi_nor_power(mtd_dev_t *mtd, enum mtd_power_state power)
{
mtd_spi_nor_t *dev = (mtd_spi_nor_t *)mtd;
spi_acquire(dev->spi, dev->cs, dev->mode, dev->clk);
mtd_spi_acquire(dev);
switch (power) {
case MTD_POWER_UP:
mtd_spi_cmd(dev, dev->opcode->wake);
mtd_spi_cmd(dev, dev->params->opcode->wake);
break;
case MTD_POWER_DOWN:
mtd_spi_cmd(dev, dev->opcode->sleep);
mtd_spi_cmd(dev, dev->params->opcode->sleep);
break;
}
spi_release(dev->spi);
mtd_spi_release(dev);
return 0;
}