[PATCH v2 20/24] spi: zx: Add ZTE ZX family SPI flash controller driver
Krzysztof Kozlowski
krzk at kernel.org
Thu Oct 15 02:34:49 PDT 2026
On Wed, Oct 14, 2026 at 08:21:00AM +0100, Navid Ghahremani wrote:
> +static int zx_qspi_probe(struct platform_device *pdev)
> +{
> + struct dma_slave_config dma_cfg = {0};
> + struct device *dev = &pdev->dev;
> + struct spi_controller *ctrl;
> + struct zx_qspi *qspi;
> + struct resource *res;
> + int irq, ret;
> + u32 reg;
> +
> + dev_info(dev, "ZX QSPI Controller driver initializing\n");
Drop such messages from all your code.
> +
> + ctrl = devm_spi_alloc_host(dev, sizeof(*qspi));
> + if (!ctrl)
> + return -ENOMEM;
> +
> + qspi = spi_controller_get_devdata(ctrl);
> + qspi->ctrl = ctrl;
> + platform_set_drvdata(pdev, qspi);
> +
> + init_completion(&qspi->dma_completion);
> +
> + res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
> + qspi->phys_base = res->start;
> + qspi->io_base = devm_ioremap_resource(dev, res);
> + if (IS_ERR(qspi->io_base))
> + return PTR_ERR(qspi->io_base);
> +
> + irq = platform_get_irq_optional(pdev, 0);
> + if (irq > 0) {
> + ret = devm_request_irq(dev, irq, zx_qspi_irq, 0, MODULE_NAME, qspi);
> + if (ret)
> + return dev_err_probe(dev, ret, "failed to request irq\n");
> + }
> +
> + qspi->pclk = devm_clk_get_enabled(dev, "pclk");
> + if (IS_ERR(qspi->pclk))
> + return PTR_ERR(qspi->pclk);
> +
> + qspi->wclk = devm_clk_get_enabled(dev, "wclk");
> + if (IS_ERR(qspi->wclk))
> + return PTR_ERR(qspi->wclk);
> +
> + qspi->rstc = devm_reset_control_get_optional_exclusive(dev, NULL);
> + if (IS_ERR(qspi->rstc))
> + return PTR_ERR(qspi->rstc);
> + if (qspi->rstc) {
> + reset_control_assert(qspi->rstc);
> + udelay(10);
> + reset_control_deassert(qspi->rstc);
> + }
> +
> + dma_cfg.src_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES;
> + dma_cfg.dst_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES;
> + dma_cfg.src_addr = qspi->phys_base + ZX_QSPI_DATA_REG;
> + dma_cfg.dst_addr = qspi->phys_base + ZX_QSPI_DATA_REG;
> + /* FIFO_THRES has an impact on the burst size. Don't make them too small. */
> + dma_cfg.src_maxburst = ZX_QSPI_FIFO_SIZE / 2;
> + dma_cfg.dst_maxburst = ZX_QSPI_FIFO_SIZE / 2;
> +
> + dma_cfg.direction = DMA_DEV_TO_MEM;
> + qspi->ctrl->dma_rx = devm_dma_request_chan(dev, "rx");
> + if (IS_ERR(qspi->ctrl->dma_rx)) {
> + dev_info(dev, "Cannot get RX DMA, using PIO\n");
> + qspi->ctrl->dma_rx = NULL;
> + } else {
> + if (dmaengine_slave_config(qspi->ctrl->dma_rx, &dma_cfg)) {
> + dev_info(dev, "Cannot configure RX DMA, using PIO\n");
> + dma_release_channel(qspi->ctrl->dma_rx);
> + qspi->ctrl->dma_rx = NULL;
> + }
> + }
> +
> + dma_cfg.direction = DMA_MEM_TO_DEV;
> + qspi->ctrl->dma_tx = devm_dma_request_chan(dev, "tx");
> + if (IS_ERR(qspi->ctrl->dma_tx)) {
> + dev_info(dev, "Cannot get TX DMA, using PIO\n");
> + qspi->ctrl->dma_tx = NULL;
> + } else {
> + if (dmaengine_slave_config(qspi->ctrl->dma_tx, &dma_cfg)) {
> + dev_info(dev, "Cannot configure TX DMA, using PIO\n");
> + dma_release_channel(qspi->ctrl->dma_tx);
> + qspi->ctrl->dma_tx = NULL;
> + }
> + }
> +
> + ctrl->mode_bits = SPI_RX_QUAD | SPI_RX_DUAL | SPI_TX_QUAD;
> + ctrl->bus_num = -1;
> + ctrl->mem_ops = &zx_qspi_mem_ops;
> + ctrl->mem_caps = &zx_qspi_mem_caps;
> + ctrl->setup = zx_qspi_setup;
> + ctrl->min_speed_hz = clk_round_rate(qspi->wclk, 1);
> + ctrl->max_speed_hz = 50000000;
> + ctrl->use_gpio_descriptors = true;
> + ctrl->num_chipselect = 1;
> + ctrl->dev.of_node = dev->of_node;
> + ctrl->dma_alignment = 4;
> +
> + writel_relaxed(ZX_QSPI_EN, qspi->io_base + ZX_QSPI_EN_REG);
> + ret = readl_relaxed_poll_timeout_atomic(qspi->io_base + ZX_QSPI_EN_REG,
> + reg, reg & ZX_QSPI_EN_BACK, 1,
> + 1000);
Why do you need atomic looping in probe function? This cannot sleep?
> + if (ret) {
> + dev_err(dev, "SPI controller failed to start: en_reg=%x\n", reg);
> + return ret;
> + }
> +
> + writel_relaxed(ZX_QSPI_SCLK_PAUSE_EN, qspi->io_base + ZX_QSPI_CTRL0_REG);
> + writel_relaxed(0, qspi->io_base + ZX_QSPI_INT_EN_REG);
> +
> + /* Ensure proper data sampling point */
> + reg = readl_relaxed(qspi->io_base + ZX_QSPI_TIMING_REG);
> + if (!FIELD_GET(GENMASK(17, 16), reg)) {
> + reg |= FIELD_PREP(GENMASK(17, 16), 1);
> + writel_relaxed(reg, qspi->io_base + ZX_QSPI_TIMING_REG);
> + }
> +
> + reg = readl_relaxed(qspi->io_base + ZX_QSPI_SW_REG) >> 16;
> + if (reg != ZX_QSPI_FIFO_SIZE)
> + dev_info(dev, "Got unexpected fifo size %u\n", reg);
> +
> + ret = devm_spi_register_controller(dev, ctrl);
> + if (ret)
> + return ret;
> +
> + return 0;
> +}
> +
> +static void zx_qspi_remove(struct platform_device *pdev)
> +{
> + struct zx_qspi *qspi = platform_get_drvdata(pdev);
> +
> + writel_relaxed(~ZX_QSPI_EN, qspi->io_base + ZX_QSPI_EN_REG);
> +}
> +
> +static const struct of_device_id zx_qspi_match[] = {
> + { .compatible = "zte,zx29-qspi" },
> + { .compatible = "zte,zx279128s-spifc" },
So devices are compatible? Then express it and drop redundant entry.
Best regards,
Krzysztof
More information about the linux-arm-kernel
mailing list