diff options
Diffstat (limited to 'drivers/spi/spi-ti-qspi.c')
| -rw-r--r-- | drivers/spi/spi-ti-qspi.c | 187 |
1 files changed, 97 insertions, 90 deletions
diff --git a/drivers/spi/spi-ti-qspi.c b/drivers/spi/spi-ti-qspi.c index e12d962a289..6c211d1910b 100644 --- a/drivers/spi/spi-ti-qspi.c +++ b/drivers/spi/spi-ti-qspi.c @@ -41,14 +41,13 @@ struct ti_qspi_regs { struct ti_qspi { struct completion transfer_complete; - /* IRQ synchronization */ - spinlock_t lock; - /* list synchronization */ struct mutex list_lock; struct spi_master *master; void __iomem *base; + void __iomem *ctrl_base; + void __iomem *mmap_base; struct clk *fclk; struct device *dev; @@ -57,7 +56,8 @@ struct ti_qspi { u32 spi_max_frequency; u32 cmd; u32 dc; - u32 stat; + + bool ctrl_mod; }; #define QSPI_PID (0x0) @@ -165,7 +165,7 @@ static int ti_qspi_setup(struct spi_device *spi) qspi->spi_max_frequency, clk_div); ret = pm_runtime_get_sync(qspi->dev); - if (ret) { + if (ret < 0) { dev_err(qspi->dev, "pm_runtime_get_sync() failed\n"); return ret; } @@ -208,53 +208,36 @@ static int qspi_write_msg(struct ti_qspi *qspi, struct spi_transfer *t) txbuf = t->tx_buf; cmd = qspi->cmd | QSPI_WR_SNGL; count = t->len; - wlen = t->bits_per_word; + wlen = t->bits_per_word >> 3; /* in bytes */ while (count) { switch (wlen) { - case 8: + case 1: dev_dbg(qspi->dev, "tx cmd %08x dc %08x data %02x\n", cmd, qspi->dc, *txbuf); writeb(*txbuf, qspi->base + QSPI_SPI_DATA_REG); - ti_qspi_write(qspi, cmd, QSPI_SPI_CMD_REG); - ret = wait_for_completion_timeout(&qspi->transfer_complete, - QSPI_COMPLETION_TIMEOUT); - if (ret == 0) { - dev_err(qspi->dev, "write timed out\n"); - return -ETIMEDOUT; - } - txbuf += 1; - count -= 1; break; - case 16: + case 2: dev_dbg(qspi->dev, "tx cmd %08x dc %08x data %04x\n", cmd, qspi->dc, *txbuf); writew(*((u16 *)txbuf), qspi->base + QSPI_SPI_DATA_REG); - ti_qspi_write(qspi, cmd, QSPI_SPI_CMD_REG); - ret = wait_for_completion_timeout(&qspi->transfer_complete, - QSPI_COMPLETION_TIMEOUT); - if (ret == 0) { - dev_err(qspi->dev, "write timed out\n"); - return -ETIMEDOUT; - } - txbuf += 2; - count -= 2; break; - case 32: + case 4: dev_dbg(qspi->dev, "tx cmd %08x dc %08x data %08x\n", cmd, qspi->dc, *txbuf); writel(*((u32 *)txbuf), qspi->base + QSPI_SPI_DATA_REG); - ti_qspi_write(qspi, cmd, QSPI_SPI_CMD_REG); - ret = wait_for_completion_timeout(&qspi->transfer_complete, - QSPI_COMPLETION_TIMEOUT); - if (ret == 0) { - dev_err(qspi->dev, "write timed out\n"); - return -ETIMEDOUT; - } - txbuf += 4; - count -= 4; break; } + + ti_qspi_write(qspi, cmd, QSPI_SPI_CMD_REG); + ret = wait_for_completion_timeout(&qspi->transfer_complete, + QSPI_COMPLETION_TIMEOUT); + if (ret == 0) { + dev_err(qspi->dev, "write timed out\n"); + return -ETIMEDOUT; + } + txbuf += wlen; + count -= wlen; } return 0; @@ -280,7 +263,7 @@ static int qspi_read_msg(struct ti_qspi *qspi, struct spi_transfer *t) break; } count = t->len; - wlen = t->bits_per_word; + wlen = t->bits_per_word >> 3; /* in bytes */ while (count) { dev_dbg(qspi->dev, "rx cmd %08x dc %08x\n", cmd, qspi->dc); @@ -292,22 +275,18 @@ static int qspi_read_msg(struct ti_qspi *qspi, struct spi_transfer *t) return -ETIMEDOUT; } switch (wlen) { - case 8: + case 1: *rxbuf = readb(qspi->base + QSPI_SPI_DATA_REG); - rxbuf += 1; - count -= 1; break; - case 16: + case 2: *((u16 *)rxbuf) = readw(qspi->base + QSPI_SPI_DATA_REG); - rxbuf += 2; - count -= 2; break; - case 32: + case 4: *((u32 *)rxbuf) = readl(qspi->base + QSPI_SPI_DATA_REG); - rxbuf += 4; - count -= 4; break; } + rxbuf += wlen; + count -= wlen; } return 0; @@ -397,13 +376,12 @@ static irqreturn_t ti_qspi_isr(int irq, void *dev_id) { struct ti_qspi *qspi = dev_id; u16 int_stat; + u32 stat; irqreturn_t ret = IRQ_HANDLED; - spin_lock(&qspi->lock); - int_stat = ti_qspi_read(qspi, QSPI_INTR_STATUS_ENABLED_CLEAR); - qspi->stat = ti_qspi_read(qspi, QSPI_SPI_STATUS_REG); + stat = ti_qspi_read(qspi, QSPI_SPI_STATUS_REG); if (!int_stat) { dev_dbg(qspi->dev, "No IRQ triggered\n"); @@ -411,42 +389,19 @@ static irqreturn_t ti_qspi_isr(int irq, void *dev_id) goto out; } - ret = IRQ_WAKE_THREAD; - - ti_qspi_write(qspi, QSPI_WC_INT_DISABLE, QSPI_INTR_ENABLE_CLEAR_REG); ti_qspi_write(qspi, QSPI_WC_INT_DISABLE, QSPI_INTR_STATUS_ENABLED_CLEAR); - + if (stat & WC) + complete(&qspi->transfer_complete); out: - spin_unlock(&qspi->lock); - return ret; } -static irqreturn_t ti_qspi_threaded_isr(int this_irq, void *dev_id) -{ - struct ti_qspi *qspi = dev_id; - unsigned long flags; - - spin_lock_irqsave(&qspi->lock, flags); - - if (qspi->stat & WC) - complete(&qspi->transfer_complete); - - spin_unlock_irqrestore(&qspi->lock, flags); - - ti_qspi_write(qspi, QSPI_WC_INT_EN, QSPI_INTR_ENABLE_SET_REG); - - return IRQ_HANDLED; -} - static int ti_qspi_runtime_resume(struct device *dev) { struct ti_qspi *qspi; - struct spi_master *master; - master = dev_get_drvdata(dev); - qspi = spi_master_get_devdata(master); + qspi = dev_get_drvdata(dev); ti_qspi_restore_ctx(qspi); return 0; @@ -463,7 +418,7 @@ static int ti_qspi_probe(struct platform_device *pdev) { struct ti_qspi *qspi; struct spi_master *master; - struct resource *r; + struct resource *r, *res_ctrl, *res_mmap; struct device_node *np = pdev->dev.of_node; u32 max_freq; int ret = 0, num_cs, irq; @@ -472,26 +427,52 @@ static int ti_qspi_probe(struct platform_device *pdev) if (!master) return -ENOMEM; - master->mode_bits = SPI_CPOL | SPI_CPHA; + master->mode_bits = SPI_CPOL | SPI_CPHA | SPI_RX_DUAL | SPI_RX_QUAD; - master->bus_num = -1; master->flags = SPI_MASTER_HALF_DUPLEX; master->setup = ti_qspi_setup; master->auto_runtime_pm = true; master->transfer_one_message = ti_qspi_start_transfer_one; master->dev.of_node = pdev->dev.of_node; - master->bits_per_word_mask = BIT(32 - 1) | BIT(16 - 1) | BIT(8 - 1); + master->bits_per_word_mask = SPI_BPW_MASK(32) | SPI_BPW_MASK(16) | + SPI_BPW_MASK(8); if (!of_property_read_u32(np, "num-cs", &num_cs)) master->num_chipselect = num_cs; - platform_set_drvdata(pdev, master); - qspi = spi_master_get_devdata(master); qspi->master = master; qspi->dev = &pdev->dev; + platform_set_drvdata(pdev, qspi); + + r = platform_get_resource_byname(pdev, IORESOURCE_MEM, "qspi_base"); + if (r == NULL) { + r = platform_get_resource(pdev, IORESOURCE_MEM, 0); + if (r == NULL) { + dev_err(&pdev->dev, "missing platform data\n"); + return -ENODEV; + } + } - r = platform_get_resource(pdev, IORESOURCE_MEM, 0); + res_mmap = platform_get_resource_byname(pdev, + IORESOURCE_MEM, "qspi_mmap"); + if (res_mmap == NULL) { + res_mmap = platform_get_resource(pdev, IORESOURCE_MEM, 1); + if (res_mmap == NULL) { + dev_err(&pdev->dev, + "memory mapped resource not required\n"); + } + } + + res_ctrl = platform_get_resource_byname(pdev, + IORESOURCE_MEM, "qspi_ctrlmod"); + if (res_ctrl == NULL) { + res_ctrl = platform_get_resource(pdev, IORESOURCE_MEM, 2); + if (res_ctrl == NULL) { + dev_dbg(&pdev->dev, + "control module resources not required\n"); + } + } irq = platform_get_irq(pdev, 0); if (irq < 0) { @@ -499,7 +480,6 @@ static int ti_qspi_probe(struct platform_device *pdev) return irq; } - spin_lock_init(&qspi->lock); mutex_init(&qspi->list_lock); qspi->base = devm_ioremap_resource(&pdev->dev, r); @@ -508,8 +488,24 @@ static int ti_qspi_probe(struct platform_device *pdev) goto free_master; } - ret = devm_request_threaded_irq(&pdev->dev, irq, ti_qspi_isr, - ti_qspi_threaded_isr, 0, + if (res_ctrl) { + qspi->ctrl_mod = true; + qspi->ctrl_base = devm_ioremap_resource(&pdev->dev, res_ctrl); + if (IS_ERR(qspi->ctrl_base)) { + ret = PTR_ERR(qspi->ctrl_base); + goto free_master; + } + } + + if (res_mmap) { + qspi->mmap_base = devm_ioremap_resource(&pdev->dev, res_mmap); + if (IS_ERR(qspi->mmap_base)) { + ret = PTR_ERR(qspi->mmap_base); + goto free_master; + } + } + + ret = devm_request_irq(&pdev->dev, irq, ti_qspi_isr, 0, dev_name(&pdev->dev), qspi); if (ret < 0) { dev_err(&pdev->dev, "Failed to register ISR for IRQ %d\n", @@ -532,7 +528,7 @@ static int ti_qspi_probe(struct platform_device *pdev) if (!of_property_read_u32(np, "spi-max-frequency", &max_freq)) qspi->spi_max_frequency = max_freq; - ret = spi_register_master(master); + ret = devm_spi_register_master(&pdev->dev, master); if (ret) goto free_master; @@ -545,9 +541,19 @@ free_master: static int ti_qspi_remove(struct platform_device *pdev) { - struct ti_qspi *qspi = platform_get_drvdata(pdev); + struct ti_qspi *qspi = platform_get_drvdata(pdev); + int ret; + + ret = pm_runtime_get_sync(qspi->dev); + if (ret < 0) { + dev_err(qspi->dev, "pm_runtime_get_sync() failed\n"); + return ret; + } + + ti_qspi_write(qspi, QSPI_WC_INT_DISABLE, QSPI_INTR_ENABLE_CLEAR_REG); - spi_unregister_master(qspi->master); + pm_runtime_put(qspi->dev); + pm_runtime_disable(&pdev->dev); return 0; } @@ -558,9 +564,9 @@ static const struct dev_pm_ops ti_qspi_pm_ops = { static struct platform_driver ti_qspi_driver = { .probe = ti_qspi_probe, - .remove = ti_qspi_remove, + .remove = ti_qspi_remove, .driver = { - .name = "ti,dra7xxx-qspi", + .name = "ti-qspi", .owner = THIS_MODULE, .pm = &ti_qspi_pm_ops, .of_match_table = ti_qspi_match, @@ -572,3 +578,4 @@ module_platform_driver(ti_qspi_driver); MODULE_AUTHOR("Sourav Poddar <sourav.poddar@ti.com>"); MODULE_LICENSE("GPL v2"); MODULE_DESCRIPTION("TI QSPI controller driver"); +MODULE_ALIAS("platform:ti-qspi"); |
