Skip to content
Closed
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
102 changes: 82 additions & 20 deletions drivers/spi/spi-microchip-core-qspi.c
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,13 @@
#define STATUS_FLAGSX4 BIT(8)
#define STATUS_MASK GENMASK(8, 0)

/*
* QSPI Direct Access register defines
*/
#define DIRECT_ACCESS_EN_SSEL BIT(0)
#define DIRECT_ACCESS_OP_SSEL BIT(1)
#define DIRECT_ACCESS_OP_SSEL_SHIFT 1

#define BYTESUPPER_MASK GENMASK(31, 16)
#define BYTESLOWER_MASK GENMASK(15, 0)

Expand Down Expand Up @@ -158,7 +165,42 @@ static int mchp_coreqspi_set_mode(struct mchp_coreqspi *qspi, const struct spi_m
return 0;
}

static inline void mchp_coreqspi_read_op(struct mchp_coreqspi *qspi)
static void mchp_coreqspi_set_cs(struct spi_device *spi, bool enable)
{
struct mchp_coreqspi *qspi = spi_controller_get_devdata(spi->controller);
u32 val;

val = readl(qspi->regs + REG_DIRECT_ACCESS);

val &= ~BIT(1);
if (spi->mode & SPI_CS_HIGH)
val |= enable << DIRECT_ACCESS_OP_SSEL_SHIFT;
else
val |= !enable << DIRECT_ACCESS_OP_SSEL_SHIFT;

writel(val, qspi->regs + REG_DIRECT_ACCESS);
}

static int mchp_coreqspi_setup(struct spi_device *spi)
{
struct mchp_coreqspi *qspi = spi_controller_get_devdata(spi->controller);
u32 val;

/*
* Active low devices need to be specifically set to their inactive
* states during probe.
*/
if (spi->mode & SPI_CS_HIGH)
return 0;

val = readl(qspi->regs + REG_DIRECT_ACCESS);
val |= DIRECT_ACCESS_OP_SSEL;
writel(val, qspi->regs + REG_DIRECT_ACCESS);

return 0;
}

static void mchp_coreqspi_read_op(struct mchp_coreqspi *qspi)
{
u32 control, data;

Expand Down Expand Up @@ -194,7 +236,7 @@ static inline void mchp_coreqspi_read_op(struct mchp_coreqspi *qspi)
}
}

static inline void mchp_coreqspi_write_op(struct mchp_coreqspi *qspi)
static void mchp_coreqspi_write_op(struct mchp_coreqspi *qspi)
{
u32 control, data;

Expand Down Expand Up @@ -222,7 +264,7 @@ static inline void mchp_coreqspi_write_op(struct mchp_coreqspi *qspi)
}
}

static inline void mchp_coreqspi_write_read_op(struct mchp_coreqspi *qspi)
static void mchp_coreqspi_write_read_op(struct mchp_coreqspi *qspi)
{
u32 control, data;

Expand Down Expand Up @@ -380,20 +422,7 @@ static int mchp_coreqspi_setup_clock(struct mchp_coreqspi *qspi, struct spi_devi
return 0;
}

static int mchp_coreqspi_setup_op(struct spi_device *spi_dev)
{
struct spi_controller *ctlr = spi_dev->controller;
struct mchp_coreqspi *qspi = spi_controller_get_devdata(ctlr);
u32 control = readl_relaxed(qspi->regs + REG_CONTROL);

control |= (CONTROL_MASTER | CONTROL_ENABLE);
control &= ~CONTROL_CLKIDLE;
writel_relaxed(control, qspi->regs + REG_CONTROL);

return 0;
}

static inline void mchp_coreqspi_config_op(struct mchp_coreqspi *qspi, const struct spi_mem_op *op)
static void mchp_coreqspi_config_op(struct mchp_coreqspi *qspi, const struct spi_mem_op *op)
{
u32 idle_cycles = 0;
int total_bytes, cmd_bytes, frames, ctrl;
Expand Down Expand Up @@ -483,6 +512,7 @@ static int mchp_coreqspi_exec_op(struct spi_mem *mem, const struct spi_mem_op *o

reinit_completion(&qspi->data_completion);
mchp_coreqspi_config_op(qspi, op);
mchp_coreqspi_set_cs(mem->spi, true);
if (op->cmd.opcode) {
qspi->txbuf = &opcode;
qspi->rxbuf = NULL;
Expand Down Expand Up @@ -523,6 +553,7 @@ static int mchp_coreqspi_exec_op(struct spi_mem *mem, const struct spi_mem_op *o
err = -ETIMEDOUT;

error:
mchp_coreqspi_set_cs(mem->spi, false);
mutex_unlock(&qspi->op_lock);
mchp_coreqspi_disable_ints(qspi);

Expand Down Expand Up @@ -662,18 +693,28 @@ static int mchp_coreqspi_transfer_one(struct spi_controller *ctlr, struct spi_de
struct spi_transfer *t)
{
struct mchp_coreqspi *qspi = spi_controller_get_devdata(ctlr);
bool dual_quad = false;

qspi->tx_len = t->len;

if (t->tx_nbits == SPI_NBITS_QUAD || t->rx_nbits == SPI_NBITS_QUAD ||
t->tx_nbits == SPI_NBITS_DUAL ||
t->rx_nbits == SPI_NBITS_DUAL)
dual_quad = true;

if (t->tx_buf)
qspi->txbuf = (u8 *)t->tx_buf;

if (!t->rx_buf) {
mchp_coreqspi_write_op(qspi);
} else {
} else if (!dual_quad) {
qspi->rxbuf = (u8 *)t->rx_buf;
qspi->rx_len = t->len;
mchp_coreqspi_write_read_op(qspi);
} else {
qspi->rxbuf = (u8 *)t->rx_buf;
qspi->rx_len = t->len;
mchp_coreqspi_read_op(qspi);
}

return 0;
Expand All @@ -686,6 +727,7 @@ static int mchp_coreqspi_probe(struct platform_device *pdev)
struct device *dev = &pdev->dev;
struct device_node *np = dev->of_node;
int ret;
u32 num_cs, val;

ctlr = devm_spi_alloc_host(&pdev->dev, sizeof(*qspi));
if (!ctlr)
Expand Down Expand Up @@ -718,20 +760,40 @@ static int mchp_coreqspi_probe(struct platform_device *pdev)
return ret;
}

/*
* The IP core only has a single CS, any more have to be provided via
* gpios
*/
if (of_property_read_u32(pdev->dev.of_node, "num-cs", &num_cs))
num_cs = 1;

ctlr->num_chipselect = num_cs;

ctlr->bits_per_word_mask = SPI_BPW_MASK(8);
ctlr->mem_ops = &mchp_coreqspi_mem_ops;
ctlr->mem_caps = &mchp_coreqspi_mem_caps;
ctlr->setup = mchp_coreqspi_setup_op;
ctlr->mode_bits = SPI_CPOL | SPI_CPHA | SPI_RX_DUAL | SPI_RX_QUAD |
SPI_TX_DUAL | SPI_TX_QUAD;
ctlr->dev.of_node = np;
ctlr->min_speed_hz = clk_get_rate(qspi->clk) / 30;
ctlr->prepare_message = mchp_coreqspi_prepare_message;
ctlr->unprepare_message = mchp_coreqspi_unprepare_message;
ctlr->transfer_one = mchp_coreqspi_transfer_one;
ctlr->num_chipselect = 2;
ctlr->setup = mchp_coreqspi_setup;
ctlr->set_cs = mchp_coreqspi_set_cs;
ctlr->use_gpio_descriptors = true;

val = readl_relaxed(qspi->regs + REG_CONTROL);
val |= (CONTROL_MASTER | CONTROL_ENABLE);
writel_relaxed(val, qspi->regs + REG_CONTROL);

/*
* Put cs into software controlled mode
*/
val = readl_relaxed(qspi->regs + REG_DIRECT_ACCESS);
val |= DIRECT_ACCESS_EN_SSEL;
writel(val, qspi->regs + REG_DIRECT_ACCESS);

ret = spi_register_controller(ctlr);
if (ret)
return dev_err_probe(&pdev->dev, ret,
Expand Down
Loading