spi: s3c64xx: restore removed comments
[cascardo/linux.git] / drivers / spi / spi-s3c64xx.c
index 5a76a50..3c09e94 100644 (file)
@@ -156,12 +156,14 @@ struct s3c64xx_spi_port_config {
        int     quirks;
        bool    high_speed;
        bool    clk_from_cmu;
+       bool    clk_ioclk;
 };
 
 /**
  * struct s3c64xx_spi_driver_data - Runtime info holder for SPI driver.
  * @clk: Pointer to the spi clock.
  * @src_clk: Pointer to the clock used to generate SPI signals.
+ * @ioclk: Pointer to the i/o clock between master and slave
  * @master: Pointer to the SPI Protocol master.
  * @cntrlr_info: Platform specific data for the controller this driver manages.
  * @tgl_spi: Pointer to the last CS left untoggled by the cs_change hint.
@@ -181,6 +183,7 @@ struct s3c64xx_spi_driver_data {
        void __iomem                    *regs;
        struct clk                      *clk;
        struct clk                      *src_clk;
+       struct clk                      *ioclk;
        struct platform_device          *pdev;
        struct spi_master               *master;
        struct s3c64xx_spi_info  *cntrlr_info;
@@ -310,44 +313,63 @@ static void prepare_dma(struct s3c64xx_spi_dma_data *dma,
        dma_async_issue_pending(dma->ch);
 }
 
+static void s3c64xx_spi_set_cs(struct spi_device *spi, bool enable)
+{
+       struct s3c64xx_spi_driver_data *sdd =
+                                       spi_master_get_devdata(spi->master);
+
+       if (sdd->cntrlr_info->no_cs)
+               return;
+
+       if (enable) {
+               if (!(sdd->port_conf->quirks & S3C64XX_SPI_QUIRK_CS_AUTO)) {
+                       writel(0, sdd->regs + S3C64XX_SPI_SLAVE_SEL);
+               } else {
+                       u32 ssel = readl(sdd->regs + S3C64XX_SPI_SLAVE_SEL);
+
+                       ssel |= (S3C64XX_SPI_SLAVE_AUTO |
+                                               S3C64XX_SPI_SLAVE_NSC_CNT_2);
+                       writel(ssel, sdd->regs + S3C64XX_SPI_SLAVE_SEL);
+               }
+       } else {
+               if (!(sdd->port_conf->quirks & S3C64XX_SPI_QUIRK_CS_AUTO))
+                       writel(S3C64XX_SPI_SLAVE_SIG_INACT,
+                              sdd->regs + S3C64XX_SPI_SLAVE_SEL);
+       }
+}
+
 static int s3c64xx_spi_prepare_transfer(struct spi_master *spi)
 {
        struct s3c64xx_spi_driver_data *sdd = spi_master_get_devdata(spi);
        dma_filter_fn filter = sdd->cntrlr_info->filter;
        struct device *dev = &sdd->pdev->dev;
        dma_cap_mask_t mask;
-       int ret;
 
-       if (!is_polling(sdd)) {
-               dma_cap_zero(mask);
-               dma_cap_set(DMA_SLAVE, mask);
-
-               /* Acquire DMA channels */
-               sdd->rx_dma.ch = dma_request_slave_channel_compat(mask, filter,
-                                  sdd->cntrlr_info->dma_rx, dev, "rx");
-               if (!sdd->rx_dma.ch) {
-                       dev_err(dev, "Failed to get RX DMA channel\n");
-                       ret = -EBUSY;
-                       goto out;
-               }
-               spi->dma_rx = sdd->rx_dma.ch;
-
-               sdd->tx_dma.ch = dma_request_slave_channel_compat(mask, filter,
-                                  sdd->cntrlr_info->dma_tx, dev, "tx");
-               if (!sdd->tx_dma.ch) {
-                       dev_err(dev, "Failed to get TX DMA channel\n");
-                       ret = -EBUSY;
-                       goto out_rx;
-               }
-               spi->dma_tx = sdd->tx_dma.ch;
+       if (is_polling(sdd))
+               return 0;
+
+       dma_cap_zero(mask);
+       dma_cap_set(DMA_SLAVE, mask);
+
+       /* Acquire DMA channels */
+       sdd->rx_dma.ch = dma_request_slave_channel_compat(mask, filter,
+                          sdd->cntrlr_info->dma_rx, dev, "rx");
+       if (!sdd->rx_dma.ch) {
+               dev_err(dev, "Failed to get RX DMA channel\n");
+               return -EBUSY;
        }
+       spi->dma_rx = sdd->rx_dma.ch;
 
-       return 0;
+       sdd->tx_dma.ch = dma_request_slave_channel_compat(mask, filter,
+                          sdd->cntrlr_info->dma_tx, dev, "tx");
+       if (!sdd->tx_dma.ch) {
+               dev_err(dev, "Failed to get TX DMA channel\n");
+               dma_release_channel(sdd->rx_dma.ch);
+               return -EBUSY;
+       }
+       spi->dma_tx = sdd->tx_dma.ch;
 
-out_rx:
-       dma_release_channel(sdd->rx_dma.ch);
-out:
-       return ret;
+       return 0;
 }
 
 static int s3c64xx_spi_unprepare_transfer(struct spi_master *spi)
@@ -577,9 +599,7 @@ static void s3c64xx_spi_config(struct s3c64xx_spi_driver_data *sdd)
        u32 val;
 
        /* Disable Clock */
-       if (sdd->port_conf->clk_from_cmu) {
-               clk_disable_unprepare(sdd->src_clk);
-       } else {
+       if (!sdd->port_conf->clk_from_cmu) {
                val = readl(regs + S3C64XX_SPI_CLK_CFG);
                val &= ~S3C64XX_SPI_ENCLK_ENABLE;
                writel(val, regs + S3C64XX_SPI_CLK_CFG);
@@ -622,11 +642,8 @@ static void s3c64xx_spi_config(struct s3c64xx_spi_driver_data *sdd)
        writel(val, regs + S3C64XX_SPI_MODE_CFG);
 
        if (sdd->port_conf->clk_from_cmu) {
-               /* Configure Clock */
-               /* There is half-multiplier before the SPI */
+               /* The src_clk clock is divided internally by 2 */
                clk_set_rate(sdd->src_clk, sdd->cur_speed * 2);
-               /* Enable Clock */
-               clk_prepare_enable(sdd->src_clk);
        } else {
                /* Configure Clock */
                val = readl(regs + S3C64XX_SPI_CLK_CFG);
@@ -651,16 +668,6 @@ static int s3c64xx_spi_prepare_message(struct spi_master *master,
        struct spi_device *spi = msg->spi;
        struct s3c64xx_spi_csinfo *cs = spi->controller_data;
 
-       /* If Master's(controller) state differs from that needed by Slave */
-       if (sdd->cur_speed != spi->max_speed_hz
-                       || sdd->cur_mode != spi->mode
-                       || sdd->cur_bpw != spi->bits_per_word) {
-               sdd->cur_bpw = spi->bits_per_word;
-               sdd->cur_speed = spi->max_speed_hz;
-               sdd->cur_mode = spi->mode;
-               s3c64xx_spi_config(sdd);
-       }
-
        /* Configure feedback delay */
        writel(cs->fb_delay & 0x3, sdd->regs + S3C64XX_SPI_FB_CLK);
 
@@ -687,6 +694,7 @@ static int s3c64xx_spi_transfer_one(struct spi_master *master,
        if (bpw != sdd->cur_bpw || speed != sdd->cur_speed) {
                sdd->cur_bpw = bpw;
                sdd->cur_speed = speed;
+               sdd->cur_mode = spi->mode;
                s3c64xx_spi_config(sdd);
        }
 
@@ -706,12 +714,7 @@ static int s3c64xx_spi_transfer_one(struct spi_master *master,
        enable_datapath(sdd, spi, xfer, use_dma);
 
        /* Start the signals */
-       if (!(sdd->port_conf->quirks & S3C64XX_SPI_QUIRK_CS_AUTO))
-               writel(0, sdd->regs + S3C64XX_SPI_SLAVE_SEL);
-       else
-               writel(readl(sdd->regs + S3C64XX_SPI_SLAVE_SEL)
-                       | S3C64XX_SPI_SLAVE_AUTO | S3C64XX_SPI_SLAVE_NSC_CNT_2,
-                       sdd->regs + S3C64XX_SPI_SLAVE_SEL);
+       s3c64xx_spi_set_cs(spi, true);
 
        spin_unlock_irqrestore(&sdd->lock, flags);
 
@@ -861,16 +864,15 @@ static int s3c64xx_spi_setup(struct spi_device *spi)
 
        pm_runtime_mark_last_busy(&sdd->pdev->dev);
        pm_runtime_put_autosuspend(&sdd->pdev->dev);
-       if (!(sdd->port_conf->quirks & S3C64XX_SPI_QUIRK_CS_AUTO))
-               writel(S3C64XX_SPI_SLAVE_SIG_INACT, sdd->regs + S3C64XX_SPI_SLAVE_SEL);
+       s3c64xx_spi_set_cs(spi, false);
+
        return 0;
 
 setup_exit:
        pm_runtime_mark_last_busy(&sdd->pdev->dev);
        pm_runtime_put_autosuspend(&sdd->pdev->dev);
        /* setup() returns with device de-selected */
-       if (!(sdd->port_conf->quirks & S3C64XX_SPI_QUIRK_CS_AUTO))
-               writel(S3C64XX_SPI_SLAVE_SIG_INACT, sdd->regs + S3C64XX_SPI_SLAVE_SEL);
+       s3c64xx_spi_set_cs(spi, false);
 
        if (gpio_is_valid(spi->cs_gpio))
                gpio_free(spi->cs_gpio);
@@ -944,7 +946,9 @@ static void s3c64xx_spi_hwinit(struct s3c64xx_spi_driver_data *sdd, int channel)
 
        sdd->cur_speed = 0;
 
-       if (!(sdd->port_conf->quirks & S3C64XX_SPI_QUIRK_CS_AUTO))
+       if (sci->no_cs)
+               writel(0, sdd->regs + S3C64XX_SPI_SLAVE_SEL);
+       else if (!(sdd->port_conf->quirks & S3C64XX_SPI_QUIRK_CS_AUTO))
                writel(S3C64XX_SPI_SLAVE_SIG_INACT, sdd->regs + S3C64XX_SPI_SLAVE_SEL);
 
        /* Disable Interrupts - we use Polling if not DMA mode */
@@ -999,6 +1003,8 @@ static struct s3c64xx_spi_info *s3c64xx_spi_parse_dt(struct device *dev)
                sci->num_cs = temp;
        }
 
+       sci->no_cs = of_property_read_bool(dev->of_node, "broken-cs");
+
        return sci;
 }
 #else
@@ -1076,7 +1082,7 @@ static int s3c64xx_spi_probe(struct platform_device *pdev)
                if (ret < 0) {
                        dev_err(&pdev->dev, "failed to get alias id, errno %d\n",
                                ret);
-                       goto err0;
+                       goto err_deref_master;
                }
                sdd->port_id = ret;
        } else {
@@ -1114,13 +1120,13 @@ static int s3c64xx_spi_probe(struct platform_device *pdev)
        sdd->regs = devm_ioremap_resource(&pdev->dev, mem_res);
        if (IS_ERR(sdd->regs)) {
                ret = PTR_ERR(sdd->regs);
-               goto err0;
+               goto err_deref_master;
        }
 
        if (sci->cfg_gpio && sci->cfg_gpio()) {
                dev_err(&pdev->dev, "Unable to config gpio\n");
                ret = -EBUSY;
-               goto err0;
+               goto err_deref_master;
        }
 
        /* Setup clocks */
@@ -1128,13 +1134,13 @@ static int s3c64xx_spi_probe(struct platform_device *pdev)
        if (IS_ERR(sdd->clk)) {
                dev_err(&pdev->dev, "Unable to acquire clock 'spi'\n");
                ret = PTR_ERR(sdd->clk);
-               goto err0;
+               goto err_deref_master;
        }
 
-       if (clk_prepare_enable(sdd->clk)) {
+       ret = clk_prepare_enable(sdd->clk);
+       if (ret) {
                dev_err(&pdev->dev, "Couldn't enable clock 'spi'\n");
-               ret = -EBUSY;
-               goto err0;
+               goto err_deref_master;
        }
 
        sprintf(clk_name, "spi_busclk%d", sci->src_clk_nr);
@@ -1143,13 +1149,28 @@ static int s3c64xx_spi_probe(struct platform_device *pdev)
                dev_err(&pdev->dev,
                        "Unable to acquire clock '%s'\n", clk_name);
                ret = PTR_ERR(sdd->src_clk);
-               goto err2;
+               goto err_disable_clk;
        }
 
-       if (clk_prepare_enable(sdd->src_clk)) {
+       ret = clk_prepare_enable(sdd->src_clk);
+       if (ret) {
                dev_err(&pdev->dev, "Couldn't enable clock '%s'\n", clk_name);
-               ret = -EBUSY;
-               goto err2;
+               goto err_disable_clk;
+       }
+
+       if (sdd->port_conf->clk_ioclk) {
+               sdd->ioclk = devm_clk_get(&pdev->dev, "spi_ioclk");
+               if (IS_ERR(sdd->ioclk)) {
+                       dev_err(&pdev->dev, "Unable to acquire 'ioclk'\n");
+                       ret = PTR_ERR(sdd->ioclk);
+                       goto err_disable_src_clk;
+               }
+
+               ret = clk_prepare_enable(sdd->ioclk);
+               if (ret) {
+                       dev_err(&pdev->dev, "Couldn't enable clock 'ioclk'\n");
+                       goto err_disable_src_clk;
+               }
        }
 
        pm_runtime_set_autosuspend_delay(&pdev->dev, AUTOSUSPEND_TIMEOUT);
@@ -1169,7 +1190,7 @@ static int s3c64xx_spi_probe(struct platform_device *pdev)
        if (ret != 0) {
                dev_err(&pdev->dev, "Failed to request IRQ %d: %d\n",
                        irq, ret);
-               goto err3;
+               goto err_pm_put;
        }
 
        writel(S3C64XX_SPI_INT_RX_OVERRUN_EN | S3C64XX_SPI_INT_RX_UNDERRUN_EN |
@@ -1179,7 +1200,7 @@ static int s3c64xx_spi_probe(struct platform_device *pdev)
        ret = devm_spi_register_master(&pdev->dev, master);
        if (ret != 0) {
                dev_err(&pdev->dev, "cannot register SPI master: %d\n", ret);
-               goto err3;
+               goto err_pm_put;
        }
 
        dev_dbg(&pdev->dev, "Samsung SoC SPI Driver loaded for Bus SPI-%d with %d Slaves attached\n",
@@ -1193,15 +1214,17 @@ static int s3c64xx_spi_probe(struct platform_device *pdev)
 
        return 0;
 
-err3:
+err_pm_put:
        pm_runtime_put_noidle(&pdev->dev);
        pm_runtime_disable(&pdev->dev);
        pm_runtime_set_suspended(&pdev->dev);
 
+       clk_disable_unprepare(sdd->ioclk);
+err_disable_src_clk:
        clk_disable_unprepare(sdd->src_clk);
-err2:
+err_disable_clk:
        clk_disable_unprepare(sdd->clk);
-err0:
+err_deref_master:
        spi_master_put(master);
 
        return ret;
@@ -1209,13 +1232,15 @@ err0:
 
 static int s3c64xx_spi_remove(struct platform_device *pdev)
 {
-       struct spi_master *master = spi_master_get(platform_get_drvdata(pdev));
+       struct spi_master *master = platform_get_drvdata(pdev);
        struct s3c64xx_spi_driver_data *sdd = spi_master_get_devdata(master);
 
        pm_runtime_get_sync(&pdev->dev);
 
        writel(0, sdd->regs + S3C64XX_SPI_INT_EN);
 
+       clk_disable_unprepare(sdd->ioclk);
+
        clk_disable_unprepare(sdd->src_clk);
 
        clk_disable_unprepare(sdd->clk);
@@ -1274,6 +1299,7 @@ static int s3c64xx_spi_runtime_suspend(struct device *dev)
 
        clk_disable_unprepare(sdd->clk);
        clk_disable_unprepare(sdd->src_clk);
+       clk_disable_unprepare(sdd->ioclk);
 
        return 0;
 }
@@ -1284,17 +1310,28 @@ static int s3c64xx_spi_runtime_resume(struct device *dev)
        struct s3c64xx_spi_driver_data *sdd = spi_master_get_devdata(master);
        int ret;
 
+       if (sdd->port_conf->clk_ioclk) {
+               ret = clk_prepare_enable(sdd->ioclk);
+               if (ret != 0)
+                       return ret;
+       }
+
        ret = clk_prepare_enable(sdd->src_clk);
        if (ret != 0)
-               return ret;
+               goto err_disable_ioclk;
 
        ret = clk_prepare_enable(sdd->clk);
-       if (ret != 0) {
-               clk_disable_unprepare(sdd->src_clk);
-               return ret;
-       }
+       if (ret != 0)
+               goto err_disable_src_clk;
 
        return 0;
+
+err_disable_src_clk:
+       clk_disable_unprepare(sdd->src_clk);
+err_disable_ioclk:
+       clk_disable_unprepare(sdd->ioclk);
+
+       return ret;
 }
 #endif /* CONFIG_PM */
 
@@ -1350,6 +1387,16 @@ static struct s3c64xx_spi_port_config exynos7_spi_port_config = {
        .quirks         = S3C64XX_SPI_QUIRK_CS_AUTO,
 };
 
+static struct s3c64xx_spi_port_config exynos5433_spi_port_config = {
+       .fifo_lvl_mask  = { 0x1ff, 0x7f, 0x7f, 0x7f, 0x7f, 0x1ff},
+       .rx_lvl_offset  = 15,
+       .tx_st_done     = 25,
+       .high_speed     = true,
+       .clk_from_cmu   = true,
+       .clk_ioclk      = true,
+       .quirks         = S3C64XX_SPI_QUIRK_CS_AUTO,
+};
+
 static const struct platform_device_id s3c64xx_spi_driver_ids[] = {
        {
                .name           = "s3c2443-spi",
@@ -1380,6 +1427,9 @@ static const struct of_device_id s3c64xx_spi_dt_match[] = {
        { .compatible = "samsung,exynos7-spi",
                        .data = (void *)&exynos7_spi_port_config,
        },
+       { .compatible = "samsung,exynos5433-spi",
+                       .data = (void *)&exynos5433_spi_port_config,
+       },
        { },
 };
 MODULE_DEVICE_TABLE(of, s3c64xx_spi_dt_match);