diff options
Diffstat (limited to 'drivers/spi/spi-zynqmp-gqspi.c')
| -rw-r--r-- | drivers/spi/spi-zynqmp-gqspi.c | 178 | 
1 files changed, 89 insertions, 89 deletions
| diff --git a/drivers/spi/spi-zynqmp-gqspi.c b/drivers/spi/spi-zynqmp-gqspi.c index c8fa6ee18ae7..328b6559bb19 100644 --- a/drivers/spi/spi-zynqmp-gqspi.c +++ b/drivers/spi/spi-zynqmp-gqspi.c @@ -157,6 +157,7 @@ enum mode_type {GQSPI_MODE_IO, GQSPI_MODE_DMA};   * @data_completion:	completion structure   */  struct zynqmp_qspi { +	struct spi_controller *ctlr;  	void __iomem *regs;  	struct clk *refclk;  	struct clk *pclk; @@ -173,6 +174,7 @@ struct zynqmp_qspi {  	u32 genfifoentry;  	enum mode_type mode;  	struct completion data_completion; +	struct mutex op_lock;  };  /** @@ -486,24 +488,10 @@ static int zynqmp_qspi_setup_op(struct spi_device *qspi)  {  	struct spi_controller *ctlr = qspi->master;  	struct zynqmp_qspi *xqspi = spi_controller_get_devdata(ctlr); -	struct device *dev = &ctlr->dev; -	int ret;  	if (ctlr->busy)  		return -EBUSY; -	ret = clk_enable(xqspi->refclk); -	if (ret) { -		dev_err(dev, "Cannot enable device clock.\n"); -		return ret; -	} - -	ret = clk_enable(xqspi->pclk); -	if (ret) { -		dev_err(dev, "Cannot enable APB clock.\n"); -		clk_disable(xqspi->refclk); -		return ret; -	}  	zynqmp_gqspi_write(xqspi, GQSPI_EN_OFST, GQSPI_EN_MASK);  	return 0; @@ -520,18 +508,20 @@ static void zynqmp_qspi_filltxfifo(struct zynqmp_qspi *xqspi, int size)  {  	u32 count = 0, intermediate; -	while ((xqspi->bytes_to_transfer > 0) && (count < size)) { -		memcpy(&intermediate, xqspi->txbuf, 4); -		zynqmp_gqspi_write(xqspi, GQSPI_TXD_OFST, intermediate); - +	while ((xqspi->bytes_to_transfer > 0) && (count < size) && (xqspi->txbuf)) {  		if (xqspi->bytes_to_transfer >= 4) { +			memcpy(&intermediate, xqspi->txbuf, 4);  			xqspi->txbuf += 4;  			xqspi->bytes_to_transfer -= 4; +			count += 4;  		} else { +			memcpy(&intermediate, xqspi->txbuf, +			       xqspi->bytes_to_transfer);  			xqspi->txbuf += xqspi->bytes_to_transfer;  			xqspi->bytes_to_transfer = 0; +			count += xqspi->bytes_to_transfer;  		} -		count++; +		zynqmp_gqspi_write(xqspi, GQSPI_TXD_OFST, intermediate);  	}  } @@ -579,7 +569,7 @@ static void zynqmp_qspi_fillgenfifo(struct zynqmp_qspi *xqspi, u8 nbits,  		genfifoentry |= GQSPI_GENFIFO_DATA_XFER;  		genfifoentry |= GQSPI_GENFIFO_TX;  		transfer_len = xqspi->bytes_to_transfer; -	} else { +	} else if (xqspi->rxbuf) {  		genfifoentry &= ~GQSPI_GENFIFO_TX;  		genfifoentry |= GQSPI_GENFIFO_DATA_XFER;  		genfifoentry |= GQSPI_GENFIFO_RX; @@ -587,6 +577,11 @@ static void zynqmp_qspi_fillgenfifo(struct zynqmp_qspi *xqspi, u8 nbits,  			transfer_len = xqspi->dma_rx_bytes;  		else  			transfer_len = xqspi->bytes_to_receive; +	} else { +		/* Sending dummy circles here */ +		genfifoentry &= ~(GQSPI_GENFIFO_TX | GQSPI_GENFIFO_RX); +		genfifoentry |= GQSPI_GENFIFO_DATA_XFER; +		transfer_len = xqspi->bytes_to_transfer;  	}  	genfifoentry |= zynqmp_qspi_selectspimode(xqspi, nbits);  	xqspi->genfifoentry = genfifoentry; @@ -738,7 +733,7 @@ static irqreturn_t zynqmp_qspi_irq(int irq, void *dev_id)   * zynqmp_qspi_setuprxdma - This function sets up the RX DMA operation   * @xqspi:	xqspi is a pointer to the GQSPI instance.   */ -static void zynqmp_qspi_setuprxdma(struct zynqmp_qspi *xqspi) +static int zynqmp_qspi_setuprxdma(struct zynqmp_qspi *xqspi)  {  	u32 rx_bytes, rx_rem, config_reg;  	dma_addr_t addr; @@ -752,7 +747,7 @@ static void zynqmp_qspi_setuprxdma(struct zynqmp_qspi *xqspi)  		zynqmp_gqspi_write(xqspi, GQSPI_CONFIG_OFST, config_reg);  		xqspi->mode = GQSPI_MODE_IO;  		xqspi->dma_rx_bytes = 0; -		return; +		return 0;  	}  	rx_rem = xqspi->bytes_to_receive % 4; @@ -760,8 +755,10 @@ static void zynqmp_qspi_setuprxdma(struct zynqmp_qspi *xqspi)  	addr = dma_map_single(xqspi->dev, (void *)xqspi->rxbuf,  			      rx_bytes, DMA_FROM_DEVICE); -	if (dma_mapping_error(xqspi->dev, addr)) +	if (dma_mapping_error(xqspi->dev, addr)) {  		dev_err(xqspi->dev, "ERR:rxdma:memory not mapped\n"); +		return -ENOMEM; +	}  	xqspi->dma_rx_bytes = rx_bytes;  	xqspi->dma_addr = addr; @@ -782,6 +779,8 @@ static void zynqmp_qspi_setuprxdma(struct zynqmp_qspi *xqspi)  	/* Write the number of bytes to transfer */  	zynqmp_gqspi_write(xqspi, GQSPI_QSPIDMA_DST_SIZE_OFST, rx_bytes); + +	return 0;  }  /** @@ -818,11 +817,17 @@ static void zynqmp_qspi_write_op(struct zynqmp_qspi *xqspi, u8 tx_nbits,   * @genfifoentry:	genfifoentry is pointer to the variable in which   *			GENFIFO	mask is returned to calling function   */ -static void zynqmp_qspi_read_op(struct zynqmp_qspi *xqspi, u8 rx_nbits, +static int zynqmp_qspi_read_op(struct zynqmp_qspi *xqspi, u8 rx_nbits,  				u32 genfifoentry)  { +	int ret; + +	ret = zynqmp_qspi_setuprxdma(xqspi); +	if (ret) +		return ret;  	zynqmp_qspi_fillgenfifo(xqspi, rx_nbits, genfifoentry); -	zynqmp_qspi_setuprxdma(xqspi); + +	return 0;  }  /** @@ -835,10 +840,13 @@ static void zynqmp_qspi_read_op(struct zynqmp_qspi *xqspi, u8 rx_nbits,   */  static int __maybe_unused zynqmp_qspi_suspend(struct device *dev)  { -	struct spi_controller *ctlr = dev_get_drvdata(dev); -	struct zynqmp_qspi *xqspi = spi_controller_get_devdata(ctlr); +	struct zynqmp_qspi *xqspi = dev_get_drvdata(dev); +	struct spi_controller *ctlr = xqspi->ctlr; +	int ret; -	spi_controller_suspend(ctlr); +	ret = spi_controller_suspend(ctlr); +	if (ret) +		return ret;  	zynqmp_gqspi_write(xqspi, GQSPI_EN_OFST, 0x0); @@ -856,27 +864,13 @@ static int __maybe_unused zynqmp_qspi_suspend(struct device *dev)   */  static int __maybe_unused zynqmp_qspi_resume(struct device *dev)  { -	struct spi_controller *ctlr = dev_get_drvdata(dev); -	struct zynqmp_qspi *xqspi = spi_controller_get_devdata(ctlr); -	int ret = 0; - -	ret = clk_enable(xqspi->pclk); -	if (ret) { -		dev_err(dev, "Cannot enable APB clock.\n"); -		return ret; -	} +	struct zynqmp_qspi *xqspi = dev_get_drvdata(dev); +	struct spi_controller *ctlr = xqspi->ctlr; -	ret = clk_enable(xqspi->refclk); -	if (ret) { -		dev_err(dev, "Cannot enable device clock.\n"); -		clk_disable(xqspi->pclk); -		return ret; -	} +	zynqmp_gqspi_write(xqspi, GQSPI_EN_OFST, GQSPI_EN_MASK);  	spi_controller_resume(ctlr); -	clk_disable(xqspi->refclk); -	clk_disable(xqspi->pclk);  	return 0;  } @@ -890,10 +884,10 @@ static int __maybe_unused zynqmp_qspi_resume(struct device *dev)   */  static int __maybe_unused zynqmp_runtime_suspend(struct device *dev)  { -	struct zynqmp_qspi *xqspi = (struct zynqmp_qspi *)dev_get_drvdata(dev); +	struct zynqmp_qspi *xqspi = dev_get_drvdata(dev); -	clk_disable(xqspi->refclk); -	clk_disable(xqspi->pclk); +	clk_disable_unprepare(xqspi->refclk); +	clk_disable_unprepare(xqspi->pclk);  	return 0;  } @@ -908,19 +902,19 @@ static int __maybe_unused zynqmp_runtime_suspend(struct device *dev)   */  static int __maybe_unused zynqmp_runtime_resume(struct device *dev)  { -	struct zynqmp_qspi *xqspi = (struct zynqmp_qspi *)dev_get_drvdata(dev); +	struct zynqmp_qspi *xqspi = dev_get_drvdata(dev);  	int ret; -	ret = clk_enable(xqspi->pclk); +	ret = clk_prepare_enable(xqspi->pclk);  	if (ret) {  		dev_err(dev, "Cannot enable APB clock.\n");  		return ret;  	} -	ret = clk_enable(xqspi->refclk); +	ret = clk_prepare_enable(xqspi->refclk);  	if (ret) {  		dev_err(dev, "Cannot enable device clock.\n"); -		clk_disable(xqspi->pclk); +		clk_disable_unprepare(xqspi->pclk);  		return ret;  	} @@ -944,25 +938,23 @@ static int zynqmp_qspi_exec_op(struct spi_mem *mem,  	struct zynqmp_qspi *xqspi = spi_controller_get_devdata  				    (mem->spi->master);  	int err = 0, i; -	u8 *tmpbuf;  	u32 genfifoentry = 0; +	u16 opcode = op->cmd.opcode; +	u64 opaddr;  	dev_dbg(xqspi->dev, "cmd:%#x mode:%d.%d.%d.%d\n",  		op->cmd.opcode, op->cmd.buswidth, op->addr.buswidth,  		op->dummy.buswidth, op->data.buswidth); +	mutex_lock(&xqspi->op_lock);  	zynqmp_qspi_config_op(xqspi, mem->spi);  	zynqmp_qspi_chipselect(mem->spi, false);  	genfifoentry |= xqspi->genfifocs;  	genfifoentry |= xqspi->genfifobus;  	if (op->cmd.opcode) { -		tmpbuf = kzalloc(op->cmd.nbytes, GFP_KERNEL | GFP_DMA); -		if (!tmpbuf) -			return -ENOMEM; -		tmpbuf[0] = op->cmd.opcode;  		reinit_completion(&xqspi->data_completion); -		xqspi->txbuf = tmpbuf; +		xqspi->txbuf = &opcode;  		xqspi->rxbuf = NULL;  		xqspi->bytes_to_transfer = op->cmd.nbytes;  		xqspi->bytes_to_receive = 0; @@ -973,16 +965,15 @@ static int zynqmp_qspi_exec_op(struct spi_mem *mem,  		zynqmp_gqspi_write(xqspi, GQSPI_IER_OFST,  				   GQSPI_IER_GENFIFOEMPTY_MASK |  				   GQSPI_IER_TXNOT_FULL_MASK); -		if (!wait_for_completion_interruptible_timeout +		if (!wait_for_completion_timeout  		    (&xqspi->data_completion, msecs_to_jiffies(1000))) {  			err = -ETIMEDOUT; -			kfree(tmpbuf);  			goto return_err;  		} -		kfree(tmpbuf);  	}  	if (op->addr.nbytes) { +		xqspi->txbuf = &opaddr;  		for (i = 0; i < op->addr.nbytes; i++) {  			*(((u8 *)xqspi->txbuf) + i) = op->addr.val >>  					(8 * (op->addr.nbytes - i - 1)); @@ -1001,7 +992,7 @@ static int zynqmp_qspi_exec_op(struct spi_mem *mem,  				   GQSPI_IER_TXEMPTY_MASK |  				   GQSPI_IER_GENFIFOEMPTY_MASK |  				   GQSPI_IER_TXNOT_FULL_MASK); -		if (!wait_for_completion_interruptible_timeout +		if (!wait_for_completion_timeout  		    (&xqspi->data_completion, msecs_to_jiffies(1000))) {  			err = -ETIMEDOUT;  			goto return_err; @@ -1009,32 +1000,23 @@ static int zynqmp_qspi_exec_op(struct spi_mem *mem,  	}  	if (op->dummy.nbytes) { -		tmpbuf = kzalloc(op->dummy.nbytes, GFP_KERNEL | GFP_DMA); -		if (!tmpbuf) -			return -ENOMEM; -		memset(tmpbuf, 0xff, op->dummy.nbytes); -		reinit_completion(&xqspi->data_completion); -		xqspi->txbuf = tmpbuf; +		xqspi->txbuf = NULL;  		xqspi->rxbuf = NULL; -		xqspi->bytes_to_transfer = op->dummy.nbytes; +		/* +		 * xqspi->bytes_to_transfer here represents the dummy circles +		 * which need to be sent. +		 */ +		xqspi->bytes_to_transfer = op->dummy.nbytes * 8 / op->dummy.buswidth;  		xqspi->bytes_to_receive = 0; -		zynqmp_qspi_write_op(xqspi, op->dummy.buswidth, +		/* +		 * Using op->data.buswidth instead of op->dummy.buswidth here because +		 * we need to use it to configure the correct SPI mode. +		 */ +		zynqmp_qspi_write_op(xqspi, op->data.buswidth,  				     genfifoentry);  		zynqmp_gqspi_write(xqspi, GQSPI_CONFIG_OFST,  				   zynqmp_gqspi_read(xqspi, GQSPI_CONFIG_OFST) |  				   GQSPI_CFG_START_GEN_FIFO_MASK); -		zynqmp_gqspi_write(xqspi, GQSPI_IER_OFST, -				   GQSPI_IER_TXEMPTY_MASK | -				   GQSPI_IER_GENFIFOEMPTY_MASK | -				   GQSPI_IER_TXNOT_FULL_MASK); -		if (!wait_for_completion_interruptible_timeout -		    (&xqspi->data_completion, msecs_to_jiffies(1000))) { -			err = -ETIMEDOUT; -			kfree(tmpbuf); -			goto return_err; -		} - -		kfree(tmpbuf);  	}  	if (op->data.nbytes) { @@ -1059,8 +1041,11 @@ static int zynqmp_qspi_exec_op(struct spi_mem *mem,  			xqspi->rxbuf = (u8 *)op->data.buf.in;  			xqspi->bytes_to_receive = op->data.nbytes;  			xqspi->bytes_to_transfer = 0; -			zynqmp_qspi_read_op(xqspi, op->data.buswidth, +			err = zynqmp_qspi_read_op(xqspi, op->data.buswidth,  					    genfifoentry); +			if (err) +				goto return_err; +  			zynqmp_gqspi_write(xqspi, GQSPI_CONFIG_OFST,  					   zynqmp_gqspi_read  					   (xqspi, GQSPI_CONFIG_OFST) | @@ -1076,7 +1061,7 @@ static int zynqmp_qspi_exec_op(struct spi_mem *mem,  						   GQSPI_IER_RXEMPTY_MASK);  			}  		} -		if (!wait_for_completion_interruptible_timeout +		if (!wait_for_completion_timeout  		    (&xqspi->data_completion, msecs_to_jiffies(1000)))  			err = -ETIMEDOUT;  	} @@ -1084,6 +1069,7 @@ static int zynqmp_qspi_exec_op(struct spi_mem *mem,  return_err:  	zynqmp_qspi_chipselect(mem->spi, true); +	mutex_unlock(&xqspi->op_lock);  	return err;  } @@ -1120,6 +1106,7 @@ static int zynqmp_qspi_probe(struct platform_device *pdev)  	xqspi = spi_controller_get_devdata(ctlr);  	xqspi->dev = dev; +	xqspi->ctlr = ctlr;  	platform_set_drvdata(pdev, xqspi);  	xqspi->regs = devm_platform_ioremap_resource(pdev, 0); @@ -1135,13 +1122,11 @@ static int zynqmp_qspi_probe(struct platform_device *pdev)  		goto remove_master;  	} -	init_completion(&xqspi->data_completion); -  	xqspi->refclk = devm_clk_get(&pdev->dev, "ref_clk");  	if (IS_ERR(xqspi->refclk)) {  		dev_err(dev, "ref_clk clock not found.\n");  		ret = PTR_ERR(xqspi->refclk); -		goto clk_dis_pclk; +		goto remove_master;  	}  	ret = clk_prepare_enable(xqspi->pclk); @@ -1156,15 +1141,24 @@ static int zynqmp_qspi_probe(struct platform_device *pdev)  		goto clk_dis_pclk;  	} +	init_completion(&xqspi->data_completion); + +	mutex_init(&xqspi->op_lock); +  	pm_runtime_use_autosuspend(&pdev->dev);  	pm_runtime_set_autosuspend_delay(&pdev->dev, SPI_AUTOSUSPEND_TIMEOUT);  	pm_runtime_set_active(&pdev->dev);  	pm_runtime_enable(&pdev->dev); + +	ret = pm_runtime_get_sync(&pdev->dev); +	if (ret < 0) { +		dev_err(&pdev->dev, "Failed to pm_runtime_get_sync: %d\n", ret); +		goto clk_dis_all; +	} +  	/* QSPI controller initializations */  	zynqmp_qspi_init_hw(xqspi); -	pm_runtime_mark_last_busy(&pdev->dev); -	pm_runtime_put_autosuspend(&pdev->dev);  	xqspi->irq = platform_get_irq(pdev, 0);  	if (xqspi->irq <= 0) {  		ret = -ENXIO; @@ -1178,6 +1172,7 @@ static int zynqmp_qspi_probe(struct platform_device *pdev)  		goto clk_dis_all;  	} +	dma_set_mask(&pdev->dev, DMA_BIT_MASK(44));  	ctlr->bits_per_word_mask = SPI_BPW_MASK(8);  	ctlr->num_chipselect = GQSPI_DEFAULT_NUM_CS;  	ctlr->mem_ops = &zynqmp_qspi_mem_ops; @@ -1187,6 +1182,7 @@ static int zynqmp_qspi_probe(struct platform_device *pdev)  	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->auto_runtime_pm = true;  	ret = devm_spi_register_controller(&pdev->dev, ctlr);  	if (ret) { @@ -1194,9 +1190,13 @@ static int zynqmp_qspi_probe(struct platform_device *pdev)  		goto clk_dis_all;  	} +	pm_runtime_mark_last_busy(&pdev->dev); +	pm_runtime_put_autosuspend(&pdev->dev); +  	return 0;  clk_dis_all: +	pm_runtime_put_sync(&pdev->dev);  	pm_runtime_set_suspended(&pdev->dev);  	pm_runtime_disable(&pdev->dev);  	clk_disable_unprepare(xqspi->refclk); | 
