spi: spi_amd: Add support for SPI MEM framework
Add support to the SPI controller driver to use SPI MEM framework. SPI subsystem utilizing the SPI memory operations allows to re-use SPI controller drivers for both SPI NOR devices, regular SPI devices as well as SPI NAND devices. Add below functions of spi_mem_ops to support SPI MEM framework - exec-op(): to execute the memory operations. - supports_op(): to check if the memory operation is supported. - adjust_op_size(): to split data transfers so that they don’t exceed the max transfer size supported by the controller. Suggested-by: Sudheesh Mavila <sudheesh.mavila@amd.com> Co-developed-by: Krishnamoorthi M <krishnamoorthi.m@amd.com> Signed-off-by: Krishnamoorthi M <krishnamoorthi.m@amd.com> Co-developed-by: Akshata MukundShetty <akshata.mukundshetty@amd.com> Signed-off-by: Akshata MukundShetty <akshata.mukundshetty@amd.com> Signed-off-by: Raju Rangoju <Raju.Rangoju@amd.com> Link: https://msgid.link/r/20240229134544.3461757-1-Raju.Rangoju@amd.com Signed-off-by: Mark Brown <broonie@kernel.org>
This commit is contained in:
parent
bdeef5dcea
commit
6defadbe6c
@ -13,6 +13,7 @@
|
||||
#include <linux/delay.h>
|
||||
#include <linux/spi/spi.h>
|
||||
#include <linux/iopoll.h>
|
||||
#include <linux/spi/spi-mem.h>
|
||||
|
||||
#define AMD_SPI_CTRL0_REG 0x00
|
||||
#define AMD_SPI_EXEC_CMD BIT(16)
|
||||
@ -35,6 +36,7 @@
|
||||
|
||||
#define AMD_SPI_FIFO_SIZE 70
|
||||
#define AMD_SPI_MEM_SIZE 200
|
||||
#define AMD_SPI_MAX_DATA 64
|
||||
|
||||
#define AMD_SPI_ENA_REG 0x20
|
||||
#define AMD_SPI_ALT_SPD_SHIFT 20
|
||||
@ -358,6 +360,115 @@ fin_msg:
|
||||
return message->status;
|
||||
}
|
||||
|
||||
static bool amd_spi_supports_op(struct spi_mem *mem,
|
||||
const struct spi_mem_op *op)
|
||||
{
|
||||
/* bus width is number of IO lines used to transmit */
|
||||
if (op->cmd.buswidth > 1 || op->addr.buswidth > 1 ||
|
||||
op->data.buswidth > 1 || op->data.nbytes > AMD_SPI_MAX_DATA)
|
||||
return false;
|
||||
|
||||
return spi_mem_default_supports_op(mem, op);
|
||||
}
|
||||
|
||||
static int amd_spi_adjust_op_size(struct spi_mem *mem, struct spi_mem_op *op)
|
||||
{
|
||||
op->data.nbytes = clamp_val(op->data.nbytes, 0, AMD_SPI_MAX_DATA);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void amd_spi_set_addr(struct amd_spi *amd_spi,
|
||||
const struct spi_mem_op *op)
|
||||
{
|
||||
u8 nbytes = op->addr.nbytes;
|
||||
u64 addr_val = op->addr.val;
|
||||
int base_addr, i;
|
||||
|
||||
base_addr = AMD_SPI_FIFO_BASE + nbytes;
|
||||
|
||||
for (i = 0; i < nbytes; i++) {
|
||||
amd_spi_writereg8(amd_spi, base_addr - i - 1, addr_val &
|
||||
GENMASK(7, 0));
|
||||
addr_val >>= 8;
|
||||
}
|
||||
}
|
||||
|
||||
static void amd_spi_mem_data_out(struct amd_spi *amd_spi,
|
||||
const struct spi_mem_op *op)
|
||||
{
|
||||
int base_addr = AMD_SPI_FIFO_BASE + op->addr.nbytes;
|
||||
u8 *buf = (u8 *)op->data.buf.out;
|
||||
u32 nbytes = op->data.nbytes;
|
||||
int i;
|
||||
|
||||
amd_spi_set_opcode(amd_spi, op->cmd.opcode);
|
||||
amd_spi_set_addr(amd_spi, op);
|
||||
|
||||
for (i = 0; i < nbytes; i++)
|
||||
amd_spi_writereg8(amd_spi, (base_addr + i), buf[i]);
|
||||
|
||||
amd_spi_set_tx_count(amd_spi, op->addr.nbytes + op->data.nbytes);
|
||||
amd_spi_set_rx_count(amd_spi, 0);
|
||||
amd_spi_clear_fifo_ptr(amd_spi);
|
||||
amd_spi_execute_opcode(amd_spi);
|
||||
}
|
||||
|
||||
static void amd_spi_mem_data_in(struct amd_spi *amd_spi,
|
||||
const struct spi_mem_op *op)
|
||||
{
|
||||
int offset = (op->addr.nbytes == 0) ? 0 : 1;
|
||||
u8 *buf = (u8 *)op->data.buf.in;
|
||||
u32 nbytes = op->data.nbytes;
|
||||
int base_addr, i;
|
||||
|
||||
base_addr = AMD_SPI_FIFO_BASE + op->addr.nbytes + offset;
|
||||
|
||||
amd_spi_set_opcode(amd_spi, op->cmd.opcode);
|
||||
amd_spi_set_addr(amd_spi, op);
|
||||
amd_spi_set_tx_count(amd_spi, op->addr.nbytes);
|
||||
amd_spi_set_rx_count(amd_spi, op->data.nbytes + 1);
|
||||
amd_spi_clear_fifo_ptr(amd_spi);
|
||||
amd_spi_execute_opcode(amd_spi);
|
||||
amd_spi_busy_wait(amd_spi);
|
||||
|
||||
for (i = 0; i < nbytes; i++)
|
||||
buf[i] = amd_spi_readreg8(amd_spi, base_addr + i);
|
||||
}
|
||||
|
||||
static int amd_spi_exec_mem_op(struct spi_mem *mem,
|
||||
const struct spi_mem_op *op)
|
||||
{
|
||||
struct amd_spi *amd_spi;
|
||||
int ret;
|
||||
|
||||
amd_spi = spi_controller_get_devdata(mem->spi->controller);
|
||||
|
||||
ret = amd_set_spi_freq(amd_spi, mem->spi->max_speed_hz);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
switch (op->data.dir) {
|
||||
case SPI_MEM_DATA_IN:
|
||||
amd_spi_mem_data_in(amd_spi, op);
|
||||
break;
|
||||
case SPI_MEM_DATA_OUT:
|
||||
fallthrough;
|
||||
case SPI_MEM_NO_DATA:
|
||||
amd_spi_mem_data_out(amd_spi, op);
|
||||
break;
|
||||
default:
|
||||
ret = -EOPNOTSUPP;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static const struct spi_controller_mem_ops amd_spi_mem_ops = {
|
||||
.exec_op = amd_spi_exec_mem_op,
|
||||
.adjust_op_size = amd_spi_adjust_op_size,
|
||||
.supports_op = amd_spi_supports_op,
|
||||
};
|
||||
|
||||
static int amd_spi_host_transfer(struct spi_controller *host,
|
||||
struct spi_message *msg)
|
||||
{
|
||||
@ -409,6 +520,7 @@ static int amd_spi_probe(struct platform_device *pdev)
|
||||
host->min_speed_hz = AMD_SPI_MIN_HZ;
|
||||
host->setup = amd_spi_host_setup;
|
||||
host->transfer_one_message = amd_spi_host_transfer;
|
||||
host->mem_ops = &amd_spi_mem_ops;
|
||||
host->max_transfer_size = amd_spi_max_transfer_size;
|
||||
host->max_message_size = amd_spi_max_transfer_size;
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user