static int cadence_spi_write_speed(struct udevice *bus, uint hz) { struct cadence_spi_platdata *plat = bus->platdata; struct cadence_spi_priv *priv = dev_get_priv(bus); cadence_qspi_apb_config_baudrate_div(priv->regbase, CONFIG_CQSPI_REF_CLK, hz); /* Reconfigure delay timing if speed is changed. */ cadence_qspi_apb_delay(priv->regbase, CONFIG_CQSPI_REF_CLK, hz, plat->tshsl_ns, plat->tsd2d_ns, plat->tchsh_ns, plat->tslch_ns); return 0; }
int cadence_qspi_apb_process_queue(struct struct_cqspi *cadence_qspi, struct spi_device *spi, unsigned int n_trans, struct spi_transfer **spi_xfer) { struct platform_device *pdev = cadence_qspi->pdev; struct cqspi_platform_data *pdata = pdev->dev.platform_data; struct spi_transfer *cmd_xfer = spi_xfer[0]; struct spi_transfer *data_xfer = (n_trans >= 2) ? spi_xfer[1] : NULL; void __iomem *iobase = cadence_qspi->iobase; unsigned int sclk; int ret = 0; struct cqspi_flash_pdata *f_pdata; pr_debug("%s %d\n", __func__, n_trans); if (!cmd_xfer->len) { pr_err("QSPI: SPI transfer length is 0.\n"); return -EINVAL; } /* Switch chip select. */ if (cadence_qspi->current_cs != spi->chip_select) { cadence_qspi->current_cs = spi->chip_select; cadence_qspi_switch_cs(cadence_qspi, spi->chip_select); } /* Setup baudrate divisor and delays */ f_pdata = &(pdata->f_pdata[cadence_qspi->current_cs]); sclk = cmd_xfer->speed_hz ? cmd_xfer->speed_hz : spi->max_speed_hz; cadence_qspi_apb_controller_disable(iobase); cadence_qspi_apb_config_baudrate_div(iobase, pdata->master_ref_clk_hz, sclk); cadence_qspi_apb_delay(cadence_qspi, pdata->master_ref_clk_hz, sclk); cadence_qspi_apb_readdata_capture(iobase, 1, f_pdata->read_delay); cadence_qspi_apb_controller_enable(iobase); /* * Use STIG command to send if the transfer length is less than * 4 or if only one transfer. */ if ((cmd_xfer->len < 4) || (n_trans == 1)) { /* STIG command */ if (data_xfer && data_xfer->rx_buf) { /* STIG read */ ret = cadence_qspi_apb_command_read(iobase, cmd_xfer->len, cmd_xfer->tx_buf, data_xfer->len, data_xfer->rx_buf); } else { /* STIG write */ ret = cadence_qspi_apb_command_write(iobase, cmd_xfer->len, cmd_xfer->tx_buf); } } else if (cmd_xfer->len >= 4 && (n_trans == 2)){ /* Indirect operation */ if (data_xfer->rx_buf) { /* Indirect read */ ret = cadence_qspi_apb_indirect_read_setup(iobase, pdata->qspi_ahb_phy, cmd_xfer->len, cmd_xfer->tx_buf, spi->addr_width); if (pdata->enable_dma) { ret = cadence_qspi_apb_indirect_read_dma( cadence_qspi, data_xfer->len, data_xfer->rx_buf); } else { ret = cadence_qspi_apb_indirect_read_execute( cadence_qspi, data_xfer->len, data_xfer->rx_buf); } } else { /* Indirect write */ ret = cadence_qspi_apb_indirect_write_setup( iobase, pdata->qspi_ahb_phy, cmd_xfer->len, cmd_xfer->tx_buf); if (pdata->enable_dma) { ret = cadence_qspi_apb_indirect_write_dma( cadence_qspi, data_xfer->len, (unsigned char *)data_xfer->tx_buf); } else { ret = cadence_qspi_apb_indirect_write_execute( cadence_qspi, data_xfer->len, data_xfer->tx_buf); } } } else { pr_err("QSPI : Unknown SPI transfer.\n"); return -EINVAL; } return ret; }