Merge branch 'master' of https://gitlab.denx.de/u-boot/custodians/u-boot-spi
- fix mvebu_a3700_spi clock prescale (Marek Behún) - unmark MXS_SPI, DEPRECATED (Lukasz) - add spi_write_then_read (Jagan) - fix SST26* flash ICs (Eugeniy) - fix soft_spi data abort (Christophe)
This commit is contained in:
commit
0d6160a340
@ -58,10 +58,8 @@ to move the migration with in the deadline.
|
||||
|
||||
No dm conversion yet::
|
||||
|
||||
drivers/spi/cf_spi.c
|
||||
drivers/spi/fsl_espi.c
|
||||
drivers/spi/lpc32xx_ssp.c
|
||||
drivers/spi/mxs_spi.c
|
||||
drivers/spi/sh_spi.c
|
||||
drivers/spi/soft_spi_legacy.c
|
||||
|
||||
@ -74,6 +72,7 @@ Partially converted::
|
||||
drivers/spi/fsl_dspi.c
|
||||
drivers/spi/kirkwood_spi.c
|
||||
drivers/spi/mxc_spi.c
|
||||
drivers/spi/mxs_spi.c
|
||||
drivers/spi/omap3_spi.c
|
||||
drivers/spi/sh_qspi.c
|
||||
|
||||
|
@ -18,6 +18,6 @@ spi-nor-y += spi-nor-core.o
|
||||
endif
|
||||
|
||||
obj-$(CONFIG_SPI_FLASH) += spi-nor.o
|
||||
obj-$(CONFIG_SPI_FLASH_DATAFLASH) += sf_dataflash.o sf.o
|
||||
obj-$(CONFIG_SPI_FLASH_DATAFLASH) += sf_dataflash.o
|
||||
obj-$(CONFIG_SPI_FLASH_MTD) += sf_mtd.o
|
||||
obj-$(CONFIG_SPI_FLASH_SANDBOX) += sandbox.o
|
||||
|
@ -1,53 +0,0 @@
|
||||
// SPDX-License-Identifier: GPL-2.0+
|
||||
/*
|
||||
* SPI flash interface
|
||||
*
|
||||
* Copyright (C) 2008 Atmel Corporation
|
||||
* Copyright (C) 2010 Reinhard Meyer, EMK Elektronik
|
||||
*/
|
||||
|
||||
#include <common.h>
|
||||
#include <spi.h>
|
||||
|
||||
static int spi_flash_read_write(struct spi_slave *spi,
|
||||
const u8 *cmd, size_t cmd_len,
|
||||
const u8 *data_out, u8 *data_in,
|
||||
size_t data_len)
|
||||
{
|
||||
unsigned long flags = SPI_XFER_BEGIN;
|
||||
int ret;
|
||||
|
||||
if (data_len == 0)
|
||||
flags |= SPI_XFER_END;
|
||||
|
||||
ret = spi_xfer(spi, cmd_len * 8, cmd, NULL, flags);
|
||||
if (ret) {
|
||||
debug("SF: Failed to send command (%zu bytes): %d\n",
|
||||
cmd_len, ret);
|
||||
} else if (data_len != 0) {
|
||||
ret = spi_xfer(spi, data_len * 8, data_out, data_in,
|
||||
SPI_XFER_END);
|
||||
if (ret)
|
||||
debug("SF: Failed to transfer %zu bytes of data: %d\n",
|
||||
data_len, ret);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
int spi_flash_cmd_read(struct spi_slave *spi, const u8 *cmd,
|
||||
size_t cmd_len, void *data, size_t data_len)
|
||||
{
|
||||
return spi_flash_read_write(spi, cmd, cmd_len, NULL, data, data_len);
|
||||
}
|
||||
|
||||
int spi_flash_cmd(struct spi_slave *spi, u8 cmd, void *response, size_t len)
|
||||
{
|
||||
return spi_flash_cmd_read(spi, &cmd, 1, response, len);
|
||||
}
|
||||
|
||||
int spi_flash_cmd_write(struct spi_slave *spi, const u8 *cmd, size_t cmd_len,
|
||||
const void *data, size_t data_len)
|
||||
{
|
||||
return spi_flash_read_write(spi, cmd, cmd_len, data, NULL, data_len);
|
||||
}
|
@ -76,12 +76,14 @@ struct dataflash {
|
||||
static inline int dataflash_status(struct spi_slave *spi)
|
||||
{
|
||||
int ret;
|
||||
u8 opcode = OP_READ_STATUS;
|
||||
u8 status;
|
||||
|
||||
/*
|
||||
* NOTE: at45db321c over 25 MHz wants to write
|
||||
* a dummy byte after the opcode...
|
||||
*/
|
||||
ret = spi_flash_cmd(spi, OP_READ_STATUS, &status, 1);
|
||||
ret = spi_write_then_read(spi, &opcode, 1, NULL, &status, 1);
|
||||
return ret ? -EIO : status;
|
||||
}
|
||||
|
||||
@ -173,7 +175,7 @@ static int spi_dataflash_erase(struct udevice *dev, u32 offset, size_t len)
|
||||
command[0], command[1], command[2], command[3],
|
||||
pageaddr);
|
||||
|
||||
status = spi_flash_cmd_write(spi, command, 4, NULL, 0);
|
||||
status = spi_write_then_read(spi, command, 4, NULL, NULL, 0);
|
||||
if (status < 0) {
|
||||
debug("%s: erase send command error!\n", dev->name);
|
||||
return -EIO;
|
||||
@ -248,7 +250,7 @@ static int spi_dataflash_read(struct udevice *dev, u32 offset, size_t len,
|
||||
command[3] = (uint8_t)(addr >> 0);
|
||||
|
||||
/* plus 4 "don't care" bytes, command len: 4 + 4 "don't care" bytes */
|
||||
status = spi_flash_cmd_read(spi, command, 8, buf, len);
|
||||
status = spi_write_then_read(spi, command, 8, NULL, buf, len);
|
||||
|
||||
spi_release_bus(spi);
|
||||
|
||||
@ -327,7 +329,8 @@ int spi_dataflash_write(struct udevice *dev, u32 offset, size_t len,
|
||||
debug("TRANSFER: (%x) %x %x %x\n",
|
||||
command[0], command[1], command[2], command[3]);
|
||||
|
||||
status = spi_flash_cmd_write(spi, command, 4, NULL, 0);
|
||||
status = spi_write_then_read(spi, command, 4,
|
||||
NULL, NULL, 0);
|
||||
if (status < 0) {
|
||||
debug("%s: write(<pagesize) command error!\n",
|
||||
dev->name);
|
||||
@ -352,8 +355,8 @@ int spi_dataflash_write(struct udevice *dev, u32 offset, size_t len,
|
||||
debug("PROGRAM: (%x) %x %x %x\n",
|
||||
command[0], command[1], command[2], command[3]);
|
||||
|
||||
status = spi_flash_cmd_write(spi, command,
|
||||
4, writebuf, writelen);
|
||||
status = spi_write_then_read(spi, command, 4,
|
||||
writebuf, NULL, writelen);
|
||||
if (status < 0) {
|
||||
debug("%s: write send command error!\n", dev->name);
|
||||
return -EIO;
|
||||
@ -376,8 +379,8 @@ int spi_dataflash_write(struct udevice *dev, u32 offset, size_t len,
|
||||
debug("COMPARE: (%x) %x %x %x\n",
|
||||
command[0], command[1], command[2], command[3]);
|
||||
|
||||
status = spi_flash_cmd_write(spi, command,
|
||||
4, writebuf, writelen);
|
||||
status = spi_write_then_read(spi, command, 4,
|
||||
writebuf, NULL, writelen);
|
||||
if (status < 0) {
|
||||
debug("%s: write(compare) send command error!\n",
|
||||
dev->name);
|
||||
@ -508,6 +511,7 @@ static struct data_flash_info *jedec_probe(struct spi_slave *spi)
|
||||
uint8_t id[5];
|
||||
uint32_t jedec;
|
||||
struct data_flash_info *info;
|
||||
u8 opcode = CMD_READ_ID;
|
||||
int status;
|
||||
|
||||
/*
|
||||
@ -519,7 +523,7 @@ static struct data_flash_info *jedec_probe(struct spi_slave *spi)
|
||||
* That's not an error; only rev C and newer chips handle it, and
|
||||
* only Atmel sells these chips.
|
||||
*/
|
||||
tmp = spi_flash_cmd(spi, CMD_READ_ID, id, sizeof(id));
|
||||
tmp = spi_write_then_read(spi, &opcode, 1, NULL, id, sizeof(id));
|
||||
if (tmp < 0) {
|
||||
printf("dataflash: error %d reading JEDEC ID\n", tmp);
|
||||
return ERR_PTR(tmp);
|
||||
|
@ -65,6 +65,7 @@ struct flash_info {
|
||||
#define NO_CHIP_ERASE BIT(12) /* Chip does not support chip erase */
|
||||
#define SPI_NOR_SKIP_SFDP BIT(13) /* Skip parsing of SFDP tables */
|
||||
#define USE_CLSR BIT(14) /* use CLSR command */
|
||||
#define SPI_NOR_HAS_SST26LOCK BIT(15) /* Flash supports lock/unlock via BPR */
|
||||
};
|
||||
|
||||
extern const struct flash_info spi_nor_ids[];
|
||||
@ -72,24 +73,6 @@ extern const struct flash_info spi_nor_ids[];
|
||||
#define JEDEC_MFR(info) ((info)->id[0])
|
||||
#define JEDEC_ID(info) (((info)->id[1]) << 8 | ((info)->id[2]))
|
||||
|
||||
/* Send a single-byte command to the device and read the response */
|
||||
int spi_flash_cmd(struct spi_slave *spi, u8 cmd, void *response, size_t len);
|
||||
|
||||
/*
|
||||
* Send a multi-byte command to the device and read the response. Used
|
||||
* for flash array reads, etc.
|
||||
*/
|
||||
int spi_flash_cmd_read(struct spi_slave *spi, const u8 *cmd,
|
||||
size_t cmd_len, void *data, size_t data_len);
|
||||
|
||||
/*
|
||||
* Send a multi-byte command to the device followed by (optional)
|
||||
* data. Used for programming the flash array, etc.
|
||||
*/
|
||||
int spi_flash_cmd_write(struct spi_slave *spi, const u8 *cmd, size_t cmd_len,
|
||||
const void *data, size_t data_len);
|
||||
|
||||
|
||||
/* Get software write-protect value (BP bits) */
|
||||
int spi_flash_cmd_get_sw_write_prot(struct spi_flash *flash);
|
||||
|
||||
|
@ -945,6 +945,177 @@ read_err:
|
||||
}
|
||||
|
||||
#ifdef CONFIG_SPI_FLASH_SST
|
||||
/*
|
||||
* sst26 flash series has its own block protection implementation:
|
||||
* 4x - 8 KByte blocks - read & write protection bits - upper addresses
|
||||
* 1x - 32 KByte blocks - write protection bits
|
||||
* rest - 64 KByte blocks - write protection bits
|
||||
* 1x - 32 KByte blocks - write protection bits
|
||||
* 4x - 8 KByte blocks - read & write protection bits - lower addresses
|
||||
*
|
||||
* We'll support only per 64k lock/unlock so lower and upper 64 KByte region
|
||||
* will be treated as single block.
|
||||
*/
|
||||
#define SST26_BPR_8K_NUM 4
|
||||
#define SST26_MAX_BPR_REG_LEN (18 + 1)
|
||||
#define SST26_BOUND_REG_SIZE ((32 + SST26_BPR_8K_NUM * 8) * SZ_1K)
|
||||
|
||||
enum lock_ctl {
|
||||
SST26_CTL_LOCK,
|
||||
SST26_CTL_UNLOCK,
|
||||
SST26_CTL_CHECK
|
||||
};
|
||||
|
||||
static bool sst26_process_bpr(u32 bpr_size, u8 *cmd, u32 bit, enum lock_ctl ctl)
|
||||
{
|
||||
switch (ctl) {
|
||||
case SST26_CTL_LOCK:
|
||||
cmd[bpr_size - (bit / 8) - 1] |= BIT(bit % 8);
|
||||
break;
|
||||
case SST26_CTL_UNLOCK:
|
||||
cmd[bpr_size - (bit / 8) - 1] &= ~BIT(bit % 8);
|
||||
break;
|
||||
case SST26_CTL_CHECK:
|
||||
return !!(cmd[bpr_size - (bit / 8) - 1] & BIT(bit % 8));
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/*
|
||||
* Lock, unlock or check lock status of the flash region of the flash (depending
|
||||
* on the lock_ctl value)
|
||||
*/
|
||||
static int sst26_lock_ctl(struct spi_nor *nor, loff_t ofs, uint64_t len, enum lock_ctl ctl)
|
||||
{
|
||||
struct mtd_info *mtd = &nor->mtd;
|
||||
u32 i, bpr_ptr, rptr_64k, lptr_64k, bpr_size;
|
||||
bool lower_64k = false, upper_64k = false;
|
||||
u8 bpr_buff[SST26_MAX_BPR_REG_LEN] = {};
|
||||
int ret;
|
||||
|
||||
/* Check length and offset for 64k alignment */
|
||||
if ((ofs & (SZ_64K - 1)) || (len & (SZ_64K - 1))) {
|
||||
dev_err(nor->dev, "length or offset is not 64KiB allighned\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (ofs + len > mtd->size) {
|
||||
dev_err(nor->dev, "range is more than device size: %#llx + %#llx > %#llx\n",
|
||||
ofs, len, mtd->size);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
/* SST26 family has only 16 Mbit, 32 Mbit and 64 Mbit IC */
|
||||
if (mtd->size != SZ_2M &&
|
||||
mtd->size != SZ_4M &&
|
||||
mtd->size != SZ_8M)
|
||||
return -EINVAL;
|
||||
|
||||
bpr_size = 2 + (mtd->size / SZ_64K / 8);
|
||||
|
||||
ret = nor->read_reg(nor, SPINOR_OP_READ_BPR, bpr_buff, bpr_size);
|
||||
if (ret < 0) {
|
||||
dev_err(nor->dev, "fail to read block-protection register\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
rptr_64k = min_t(u32, ofs + len, mtd->size - SST26_BOUND_REG_SIZE);
|
||||
lptr_64k = max_t(u32, ofs, SST26_BOUND_REG_SIZE);
|
||||
|
||||
upper_64k = ((ofs + len) > (mtd->size - SST26_BOUND_REG_SIZE));
|
||||
lower_64k = (ofs < SST26_BOUND_REG_SIZE);
|
||||
|
||||
/* Lower bits in block-protection register are about 64k region */
|
||||
bpr_ptr = lptr_64k / SZ_64K - 1;
|
||||
|
||||
/* Process 64K blocks region */
|
||||
while (lptr_64k < rptr_64k) {
|
||||
if (sst26_process_bpr(bpr_size, bpr_buff, bpr_ptr, ctl))
|
||||
return EACCES;
|
||||
|
||||
bpr_ptr++;
|
||||
lptr_64k += SZ_64K;
|
||||
}
|
||||
|
||||
/* 32K and 8K region bits in BPR are after 64k region bits */
|
||||
bpr_ptr = (mtd->size - 2 * SST26_BOUND_REG_SIZE) / SZ_64K;
|
||||
|
||||
/* Process lower 32K block region */
|
||||
if (lower_64k)
|
||||
if (sst26_process_bpr(bpr_size, bpr_buff, bpr_ptr, ctl))
|
||||
return EACCES;
|
||||
|
||||
bpr_ptr++;
|
||||
|
||||
/* Process upper 32K block region */
|
||||
if (upper_64k)
|
||||
if (sst26_process_bpr(bpr_size, bpr_buff, bpr_ptr, ctl))
|
||||
return EACCES;
|
||||
|
||||
bpr_ptr++;
|
||||
|
||||
/* Process lower 8K block regions */
|
||||
for (i = 0; i < SST26_BPR_8K_NUM; i++) {
|
||||
if (lower_64k)
|
||||
if (sst26_process_bpr(bpr_size, bpr_buff, bpr_ptr, ctl))
|
||||
return EACCES;
|
||||
|
||||
/* In 8K area BPR has both read and write protection bits */
|
||||
bpr_ptr += 2;
|
||||
}
|
||||
|
||||
/* Process upper 8K block regions */
|
||||
for (i = 0; i < SST26_BPR_8K_NUM; i++) {
|
||||
if (upper_64k)
|
||||
if (sst26_process_bpr(bpr_size, bpr_buff, bpr_ptr, ctl))
|
||||
return EACCES;
|
||||
|
||||
/* In 8K area BPR has both read and write protection bits */
|
||||
bpr_ptr += 2;
|
||||
}
|
||||
|
||||
/* If we check region status we don't need to write BPR back */
|
||||
if (ctl == SST26_CTL_CHECK)
|
||||
return 0;
|
||||
|
||||
ret = nor->write_reg(nor, SPINOR_OP_WRITE_BPR, bpr_buff, bpr_size);
|
||||
if (ret < 0) {
|
||||
dev_err(nor->dev, "fail to write block-protection register\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int sst26_unlock(struct spi_nor *nor, loff_t ofs, uint64_t len)
|
||||
{
|
||||
return sst26_lock_ctl(nor, ofs, len, SST26_CTL_UNLOCK);
|
||||
}
|
||||
|
||||
static int sst26_lock(struct spi_nor *nor, loff_t ofs, uint64_t len)
|
||||
{
|
||||
return sst26_lock_ctl(nor, ofs, len, SST26_CTL_LOCK);
|
||||
}
|
||||
|
||||
/*
|
||||
* Returns EACCES (positive value) if region is locked, 0 if region is unlocked,
|
||||
* and negative on errors.
|
||||
*/
|
||||
static int sst26_is_locked(struct spi_nor *nor, loff_t ofs, uint64_t len)
|
||||
{
|
||||
/*
|
||||
* is_locked function is used for check before reading or erasing flash
|
||||
* region, so offset and length might be not 64k allighned, so adjust
|
||||
* them to be 64k allighned as sst26_lock_ctl works only with 64k
|
||||
* allighned regions.
|
||||
*/
|
||||
ofs -= ofs & (SZ_64K - 1);
|
||||
len = len & (SZ_64K - 1) ? (len & ~(SZ_64K - 1)) + SZ_64K : len;
|
||||
|
||||
return sst26_lock_ctl(nor, ofs, len, SST26_CTL_CHECK);
|
||||
}
|
||||
|
||||
static int sst_write_byteprogram(struct spi_nor *nor, loff_t to, size_t len,
|
||||
size_t *retlen, const u_char *buf)
|
||||
{
|
||||
@ -2302,6 +2473,16 @@ int spi_nor_scan(struct spi_nor *nor)
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_SPI_FLASH_SST
|
||||
/*
|
||||
* sst26 series block protection implementation differs from other
|
||||
* series.
|
||||
*/
|
||||
if (info->flags & SPI_NOR_HAS_SST26LOCK) {
|
||||
nor->flash_lock = sst26_lock;
|
||||
nor->flash_unlock = sst26_unlock;
|
||||
nor->flash_is_locked = sst26_is_locked;
|
||||
}
|
||||
|
||||
/* sst nor chips use AAI word program */
|
||||
if (info->flags & SST_WRITE)
|
||||
mtd->_write = sst_write;
|
||||
|
@ -214,10 +214,10 @@ const struct flash_info spi_nor_ids[] = {
|
||||
{ INFO("sst25wf040b", 0x621613, 0, 64 * 1024, 8, SECT_4K) },
|
||||
{ INFO("sst25wf040", 0xbf2504, 0, 64 * 1024, 8, SECT_4K | SST_WRITE) },
|
||||
{ INFO("sst25wf080", 0xbf2505, 0, 64 * 1024, 16, SECT_4K | SST_WRITE) },
|
||||
{ INFO("sst26vf064b", 0xbf2643, 0, 64 * 1024, 128, SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ) },
|
||||
{ INFO("sst26wf016", 0xbf2651, 0, 64 * 1024, 32, SECT_4K) },
|
||||
{ INFO("sst26wf032", 0xbf2622, 0, 64 * 1024, 64, SECT_4K) },
|
||||
{ INFO("sst26wf064", 0xbf2643, 0, 64 * 1024, 128, SECT_4K) },
|
||||
{ INFO("sst26vf064b", 0xbf2643, 0, 64 * 1024, 128, SECT_4K | SPI_NOR_HAS_SST26LOCK | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ) },
|
||||
{ INFO("sst26wf016", 0xbf2651, 0, 64 * 1024, 32, SECT_4K | SPI_NOR_HAS_SST26LOCK) },
|
||||
{ INFO("sst26wf032", 0xbf2622, 0, 64 * 1024, 64, SECT_4K | SPI_NOR_HAS_SST26LOCK) },
|
||||
{ INFO("sst26wf064", 0xbf2643, 0, 64 * 1024, 128, SECT_4K | SPI_NOR_HAS_SST26LOCK) },
|
||||
#endif
|
||||
#ifdef CONFIG_SPI_FLASH_STMICRO /* STMICRO */
|
||||
/* ST Microelectronics -- newer production may have feature updates */
|
||||
|
@ -419,7 +419,6 @@ config MXC_SPI
|
||||
|
||||
config MXS_SPI
|
||||
bool "MXS SPI Driver"
|
||||
depends on DEPRECATED
|
||||
help
|
||||
Enable the MXS SPI controller driver. This driver can be used
|
||||
on the i.MX23 and i.MX28 SoCs.
|
||||
|
@ -181,10 +181,9 @@ static int mvebu_spi_set_speed(struct udevice *bus, uint hz)
|
||||
data = readl(®->cfg);
|
||||
|
||||
prescale = DIV_ROUND_UP(clk_get_rate(&plat->clk), hz);
|
||||
if (prescale > 0x1f)
|
||||
prescale = 0x1f;
|
||||
else if (prescale > 0xf)
|
||||
if (prescale > 0xf)
|
||||
prescale = 0x10 + (prescale + 1) / 2;
|
||||
prescale = min(prescale, 0x1fu);
|
||||
|
||||
data &= ~MVEBU_SPI_A3700_CLK_PRESCALE_MASK;
|
||||
data |= prescale & MVEBU_SPI_A3700_CLK_PRESCALE_MASK;
|
||||
|
@ -215,8 +215,8 @@ static int soft_spi_probe(struct udevice *dev)
|
||||
int cs_flags, clk_flags;
|
||||
int ret;
|
||||
|
||||
cs_flags = (slave->mode & SPI_CS_HIGH) ? 0 : GPIOD_ACTIVE_LOW;
|
||||
clk_flags = (slave->mode & SPI_CPOL) ? GPIOD_ACTIVE_LOW : 0;
|
||||
cs_flags = (slave && slave->mode & SPI_CS_HIGH) ? 0 : GPIOD_ACTIVE_LOW;
|
||||
clk_flags = (slave && slave->mode & SPI_CPOL) ? GPIOD_ACTIVE_LOW : 0;
|
||||
|
||||
if (gpio_request_by_name(dev, "cs-gpios", 0, &plat->cs,
|
||||
GPIOD_IS_OUT | cs_flags) ||
|
||||
|
@ -108,6 +108,30 @@ int spi_xfer(struct spi_slave *slave, unsigned int bitlen,
|
||||
return dm_spi_xfer(slave->dev, bitlen, dout, din, flags);
|
||||
}
|
||||
|
||||
int spi_write_then_read(struct spi_slave *slave, const u8 *opcode,
|
||||
size_t n_opcode, const u8 *txbuf, u8 *rxbuf,
|
||||
size_t n_buf)
|
||||
{
|
||||
unsigned long flags = SPI_XFER_BEGIN;
|
||||
int ret;
|
||||
|
||||
if (n_buf == 0)
|
||||
flags |= SPI_XFER_END;
|
||||
|
||||
ret = spi_xfer(slave, n_opcode * 8, opcode, NULL, flags);
|
||||
if (ret) {
|
||||
debug("spi: failed to send command (%zu bytes): %d\n",
|
||||
n_opcode, ret);
|
||||
} else if (n_buf != 0) {
|
||||
ret = spi_xfer(slave, n_buf * 8, txbuf, rxbuf, SPI_XFER_END);
|
||||
if (ret)
|
||||
debug("spi: failed to transfer %zu bytes of data: %d\n",
|
||||
n_buf, ret);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
#if !CONFIG_IS_ENABLED(OF_PLATDATA)
|
||||
static int spi_child_post_bind(struct udevice *dev)
|
||||
{
|
||||
|
@ -91,6 +91,10 @@
|
||||
#define SPINOR_OP_WRDI 0x04 /* Write disable */
|
||||
#define SPINOR_OP_AAI_WP 0xad /* Auto address increment word program */
|
||||
|
||||
/* Used for SST26* flashes only. */
|
||||
#define SPINOR_OP_READ_BPR 0x72 /* Read block protection register */
|
||||
#define SPINOR_OP_WRITE_BPR 0x42 /* Write block protection register */
|
||||
|
||||
/* Used for S3AN flashes only */
|
||||
#define SPINOR_OP_XSE 0x50 /* Sector erase */
|
||||
#define SPINOR_OP_XPP 0x82 /* Page program */
|
||||
|
@ -248,6 +248,26 @@ int spi_set_wordlen(struct spi_slave *slave, unsigned int wordlen);
|
||||
int spi_xfer(struct spi_slave *slave, unsigned int bitlen, const void *dout,
|
||||
void *din, unsigned long flags);
|
||||
|
||||
/**
|
||||
* spi_write_then_read - SPI synchronous write followed by read
|
||||
*
|
||||
* This performs a half duplex transaction in which the first transaction
|
||||
* is to send the opcode and if the length of buf is non-zero then it start
|
||||
* the second transaction as tx or rx based on the need from respective slave.
|
||||
*
|
||||
* @slave: The SPI slave device with which opcode/data will be exchanged
|
||||
* @opcode: opcode used for specific transfer
|
||||
* @n_opcode: size of opcode, in bytes
|
||||
* @txbuf: buffer into which data to be written
|
||||
* @rxbuf: buffer into which data will be read
|
||||
* @n_buf: size of buf (whether it's [tx|rx]buf), in bytes
|
||||
*
|
||||
* Returns: 0 on success, not 0 on failure
|
||||
*/
|
||||
int spi_write_then_read(struct spi_slave *slave, const u8 *opcode,
|
||||
size_t n_opcode, const u8 *txbuf, u8 *rxbuf,
|
||||
size_t n_buf);
|
||||
|
||||
/* Copy memory mapped data */
|
||||
void spi_flash_copy_mmap(void *data, void *offset, size_t len);
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user