Merge tag 'kvm-arm-fixes-3.13-1' of git://git.linaro.org/people/cdall/linux-kvm-arm...
[cascardo/linux.git] / drivers / spi / spi-mxs.c
index 23cc412..73afb56 100644 (file)
 struct mxs_spi {
        struct mxs_ssp          ssp;
        struct completion       c;
+       unsigned int            sck;    /* Rate requested (vs actual) */
 };
 
 static int mxs_spi_setup_transfer(struct spi_device *dev,
-                               struct spi_transfer *t)
+                                 const struct spi_transfer *t)
 {
        struct mxs_spi *spi = spi_master_get_devdata(dev->master);
        struct mxs_ssp *ssp = &spi->ssp;
-       uint32_t hz = 0;
+       const unsigned int hz = min(dev->max_speed_hz, t->speed_hz);
 
-       hz = dev->max_speed_hz;
-       if (t && t->speed_hz)
-               hz = min(hz, t->speed_hz);
        if (hz == 0) {
-               dev_err(&dev->dev, "Cannot continue with zero clock\n");
+               dev_err(&dev->dev, "SPI clock rate of zero not allowed\n");
                return -EINVAL;
        }
 
-       mxs_ssp_set_clk_rate(ssp, hz);
+       if (hz != spi->sck) {
+               mxs_ssp_set_clk_rate(ssp, hz);
+               /*
+                * Save requested rate, hz, rather than the actual rate,
+                * ssp->clk_rate.  Otherwise we would set the rate every trasfer
+                * when the actual rate is not quite the same as requested rate.
+                */
+               spi->sck = hz;
+               /*
+                * Perhaps we should return an error if the actual clock is
+                * nowhere close to what was requested?
+                */
+       }
 
        writel(BM_SSP_CTRL0_LOCK_CS,
                ssp->base + HW_SSP_CTRL0 + STMP_OFFSET_REG_SET);
+
        writel(BF_SSP_CTRL1_SSP_MODE(BV_SSP_CTRL1_SSP_MODE__SPI) |
-                    BF_SSP_CTRL1_WORD_LENGTH
-                    (BV_SSP_CTRL1_WORD_LENGTH__EIGHT_BITS) |
-                    ((dev->mode & SPI_CPOL) ? BM_SSP_CTRL1_POLARITY : 0) |
-                    ((dev->mode & SPI_CPHA) ? BM_SSP_CTRL1_PHASE : 0),
-                    ssp->base + HW_SSP_CTRL1(ssp));
+              BF_SSP_CTRL1_WORD_LENGTH(BV_SSP_CTRL1_WORD_LENGTH__EIGHT_BITS) |
+              ((dev->mode & SPI_CPOL) ? BM_SSP_CTRL1_POLARITY : 0) |
+              ((dev->mode & SPI_CPHA) ? BM_SSP_CTRL1_PHASE : 0),
+              ssp->base + HW_SSP_CTRL1(ssp));
 
        writel(0x0, ssp->base + HW_SSP_CMD0);
        writel(0x0, ssp->base + HW_SSP_CMD1);
@@ -109,9 +119,9 @@ static int mxs_spi_setup(struct spi_device *dev)
        return 0;
 }
 
-static uint32_t mxs_spi_cs_to_reg(unsigned cs)
+static u32 mxs_spi_cs_to_reg(unsigned cs)
 {
-       uint32_t select = 0;
+       u32 select = 0;
 
        /*
         * i.MX28 Datasheet: 17.10.1: HW_SSP_CTRL0
@@ -133,7 +143,7 @@ static int mxs_ssp_wait(struct mxs_spi *spi, int offset, int mask, bool set)
 {
        const unsigned long timeout = jiffies + msecs_to_jiffies(SSP_TIMEOUT);
        struct mxs_ssp *ssp = &spi->ssp;
-       uint32_t reg;
+       u32 reg;
 
        do {
                reg = readl_relaxed(ssp->base + offset);
@@ -177,11 +187,11 @@ static int mxs_spi_txrx_dma(struct mxs_spi *spi,
        const int sgs = DIV_ROUND_UP(len, desc_len);
        int sg_count;
        int min, ret;
-       uint32_t ctrl0;
+       u32 ctrl0;
        struct page *vm_page;
        void *sg_buf;
        struct {
-               uint32_t                pio[4];
+               u32                     pio[4];
                struct scatterlist      sg;
        } *dma_xfer;
 
@@ -192,7 +202,7 @@ static int mxs_spi_txrx_dma(struct mxs_spi *spi,
        if (!dma_xfer)
                return -ENOMEM;
 
-       INIT_COMPLETION(spi->c);
+       reinit_completion(&spi->c);
 
        /* Chip select was already programmed into CTRL0 */
        ctrl0 = readl(ssp->base + HW_SSP_CTRL0);
@@ -532,7 +542,7 @@ static int mxs_spi_probe(struct platform_device *pdev)
 
        platform_set_drvdata(pdev, master);
 
-       ret = spi_register_master(master);
+       ret = devm_spi_register_master(&pdev->dev, master);
        if (ret) {
                dev_err(&pdev->dev, "Cannot register SPI master, %d\n", ret);
                goto out_disable_clk;
@@ -559,10 +569,8 @@ static int mxs_spi_remove(struct platform_device *pdev)
        spi = spi_master_get_devdata(master);
        ssp = &spi->ssp;
 
-       spi_unregister_master(master);
        clk_disable_unprepare(ssp->clk);
        dma_release_channel(ssp->dmach);
-       spi_master_put(master);
 
        return 0;
 }