Exemplo n.º 1
0
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;
}
Exemplo n.º 2
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;
}