static int zynq_qspi_transfer(struct spi_device *qspi, struct spi_transfer *transfer) { struct zynq_qspi *zqspi = &qspi->master; unsigned cs_change = 1; int status = 0; debug("%s\n", __func__); while (1) { if (transfer->bits_per_word || transfer->speed_hz) { status = zynq_qspi_setup_transfer(qspi, transfer); if (status < 0) break; } /* Select the chip if required */ if (cs_change) zynq_qspi_chipselect(qspi, 1); cs_change = transfer->cs_change; if (!transfer->tx_buf && !transfer->rx_buf && transfer->len) { status = -1; break; } /* Request the transfer */ if (transfer->len) { status = zynq_qspi_start_transfer(qspi, transfer); zqspi->is_inst = 0; } if (status != transfer->len) { if (status > 0) status = -EMSGSIZE; break; } status = 0; if (transfer->delay_usecs) udelay(transfer->delay_usecs); if (cs_change) /* Deselect the chip */ zynq_qspi_chipselect(qspi, 0); break; } zynq_qspi_setup_transfer(qspi, NULL); return 0; }
/** * zynq_qspi_start_transfer - Initiates the QSPI transfer * @master: Pointer to the spi_master structure which provides * information about the controller. * @qspi: Pointer to the spi_device structure * @transfer: Pointer to the spi_transfer structure which provide information * about next transfer parameters * * This function fills the TX FIFO, starts the QSPI transfer, and waits for the * transfer to be completed. * * Return: Number of bytes transferred in the last transfer */ static int zynq_qspi_start_transfer(struct spi_master *master, struct spi_device *qspi, struct spi_transfer *transfer) { struct zynq_qspi *xqspi = spi_master_get_devdata(master); u32 data; xqspi->txbuf = transfer->tx_buf; xqspi->rxbuf = transfer->rx_buf; xqspi->bytes_to_transfer = transfer->len; xqspi->bytes_to_receive = transfer->len; zynq_qspi_setup_transfer(qspi, transfer); if (transfer->len >= 4) { zynq_qspi_fill_tx_fifo(xqspi, ZYNQ_QSPI_FIFO_DEPTH); } else { zynq_qspi_copy_write_data(xqspi, &data, transfer->len); if (!xqspi->is_dual || xqspi->is_instr) zynq_qspi_write(xqspi, ZYNQ_QSPI_TXD_00_01_OFFSET + ((transfer->len - 1) * 4), data); else { zynq_qspi_tx_dual_parallel(xqspi, data, transfer->len); } } zynq_qspi_write(xqspi, ZYNQ_QSPI_IEN_OFFSET, ZYNQ_QSPI_IXR_ALL_MASK); return transfer->len; }
/** * zynq_qspi_setup - Configure the QSPI controller * @qspi: Pointer to the spi_device structure * * Sets the operational mode of QSPI controller for the next QSPI transfer, baud * rate and divisor value to setup the requested qspi clock. * * Return: 0 on success and error value on failure */ static int zynq_qspi_setup(struct spi_device *qspi) { if (qspi->master->busy) return -EBUSY; return zynq_qspi_setup_transfer(qspi, NULL); }
struct spi_slave *spi_setup_slave(unsigned int bus, unsigned int cs, unsigned int max_hz, unsigned int mode) { int is_dual; unsigned long lqspi_frequency; struct zynq_qspi_slave *qspi; debug("%s: bus: %d cs: %d max_hz: %d mode: %d\n", __func__, bus, cs, max_hz, mode); if (!spi_cs_is_valid(bus, cs)) return NULL; is_dual = zynq_qspi_check_is_dual_flash(); if (is_dual == MODE_UNKNOWN) { printf("%s: No QSPI device detected based on MIO settings\n", __func__); return NULL; } zynq_qspi_init_hw(is_dual, cs); qspi = spi_alloc_slave(struct zynq_qspi_slave, bus, cs); if (!qspi) { printf("%s: Fail to allocate zynq_qspi_slave\n", __func__); return NULL; } lqspi_frequency = zynq_clk_get_rate(lqspi_clk); if (!lqspi_frequency) { debug("Defaulting to 200000000 Hz qspi clk"); qspi->qspi.master.input_clk_hz = 200000000; } else { qspi->qspi.master.input_clk_hz = lqspi_frequency; debug("Qspi clk frequency set to %ld Hz\n", lqspi_frequency); } qspi->slave.is_dual = is_dual; qspi->slave.rd_cmd = READ_CMD_FULL; qspi->slave.wr_cmd = PAGE_PROGRAM | QUAD_PAGE_PROGRAM; qspi->qspi.master.speed_hz = qspi->qspi.master.input_clk_hz / 2; qspi->qspi.max_speed_hz = qspi->qspi.master.speed_hz; qspi->qspi.master.is_dual = is_dual; qspi->qspi.mode = mode; qspi->qspi.chip_select = 0; qspi->qspi.bits_per_word = 32; zynq_qspi_setup_transfer(&qspi->qspi, NULL); return &qspi->slave; }