spi/s3c64xx: Consider the clk_from_cmu flag
authorJassi Brar <jassi.brar@samsung.com>
Wed, 29 Sep 2010 08:31:33 +0000 (17:31 +0900)
committerGrant Likely <grant.likely@secretlab.ca>
Wed, 29 Sep 2010 08:31:33 +0000 (17:31 +0900)
Newer SoCs have the SPI clock scaling control in platform's
clock management unit. Inorder for such SoCs to work, we need
to check the flag clk_from_cmu before making any clock changes.

Signed-off-by: Jassi Brar <jassi.brar@samsung.com>
Signed-off-by: Grant Likely <grant.likely@secretlab.ca>
arch/arm/plat-samsung/include/plat/s3c64xx-spi.h
drivers/spi/spi_s3c64xx.c

index e5aba8f..b226f74 100644 (file)
@@ -32,6 +32,8 @@ struct s3c64xx_spi_csinfo {
  * struct s3c64xx_spi_info - SPI Controller defining structure
  * @src_clk_nr: Clock source index for the CLK_CFG[SPI_CLKSEL] field.
  * @src_clk_name: Platform name of the corresponding clock.
+ * @clk_from_cmu: If the SPI clock/prescalar control block is present
+ *     by the platform's clock-management-unit and not in SPI controller.
  * @num_cs: Number of CS this controller emulates.
  * @cfg_gpio: Configure pins for this SPI controller.
  * @fifo_lvl_mask: All tx fifo_lvl fields start at offset-6
@@ -41,6 +43,7 @@ struct s3c64xx_spi_csinfo {
 struct s3c64xx_spi_info {
        int src_clk_nr;
        char *src_clk_name;
+       bool clk_from_cmu;
 
        int num_cs;
 
index e7b893f..9e0aa3c 100644 (file)
@@ -399,13 +399,18 @@ static inline void disable_cs(struct s3c64xx_spi_driver_data *sdd,
 
 static void s3c64xx_spi_config(struct s3c64xx_spi_driver_data *sdd)
 {
+       struct s3c64xx_spi_info *sci = sdd->cntrlr_info;
        void __iomem *regs = sdd->regs;
        u32 val;
 
        /* Disable Clock */
-       val = readl(regs + S3C64XX_SPI_CLK_CFG);
-       val &= ~S3C64XX_SPI_ENCLK_ENABLE;
-       writel(val, regs + S3C64XX_SPI_CLK_CFG);
+       if (sci->clk_from_cmu) {
+               clk_disable(sdd->src_clk);
+       } else {
+               val = readl(regs + S3C64XX_SPI_CLK_CFG);
+               val &= ~S3C64XX_SPI_ENCLK_ENABLE;
+               writel(val, regs + S3C64XX_SPI_CLK_CFG);
+       }
 
        /* Set Polarity and Phase */
        val = readl(regs + S3C64XX_SPI_CH_CFG);
@@ -441,17 +446,25 @@ static void s3c64xx_spi_config(struct s3c64xx_spi_driver_data *sdd)
 
        writel(val, regs + S3C64XX_SPI_MODE_CFG);
 
-       /* Configure Clock */
-       val = readl(regs + S3C64XX_SPI_CLK_CFG);
-       val &= ~S3C64XX_SPI_PSR_MASK;
-       val |= ((clk_get_rate(sdd->src_clk) / sdd->cur_speed / 2 - 1)
-                       & S3C64XX_SPI_PSR_MASK);
-       writel(val, regs + S3C64XX_SPI_CLK_CFG);
-
-       /* Enable Clock */
-       val = readl(regs + S3C64XX_SPI_CLK_CFG);
-       val |= S3C64XX_SPI_ENCLK_ENABLE;
-       writel(val, regs + S3C64XX_SPI_CLK_CFG);
+       if (sci->clk_from_cmu) {
+               /* Configure Clock */
+               /* There is half-multiplier before the SPI */
+               clk_set_rate(sdd->src_clk, sdd->cur_speed * 2);
+               /* Enable Clock */
+               clk_enable(sdd->src_clk);
+       } else {
+               /* Configure Clock */
+               val = readl(regs + S3C64XX_SPI_CLK_CFG);
+               val &= ~S3C64XX_SPI_PSR_MASK;
+               val |= ((clk_get_rate(sdd->src_clk) / sdd->cur_speed / 2 - 1)
+                               & S3C64XX_SPI_PSR_MASK);
+               writel(val, regs + S3C64XX_SPI_CLK_CFG);
+
+               /* Enable Clock */
+               val = readl(regs + S3C64XX_SPI_CLK_CFG);
+               val |= S3C64XX_SPI_ENCLK_ENABLE;
+               writel(val, regs + S3C64XX_SPI_CLK_CFG);
+       }
 }
 
 static void s3c64xx_spi_dma_rxcb(struct s3c2410_dma_chan *chan, void *buf_id,
@@ -806,7 +819,6 @@ static int s3c64xx_spi_setup(struct spi_device *spi)
        struct s3c64xx_spi_driver_data *sdd;
        struct s3c64xx_spi_info *sci;
        struct spi_message *msg;
-       u32 psr, speed;
        unsigned long flags;
        int err = 0;
 
@@ -849,32 +861,37 @@ static int s3c64xx_spi_setup(struct spi_device *spi)
        }
 
        /* Check if we can provide the requested rate */
-       speed = clk_get_rate(sdd->src_clk) / 2 / (0 + 1); /* Max possible */
-
-       if (spi->max_speed_hz > speed)
-               spi->max_speed_hz = speed;
-
-       psr = clk_get_rate(sdd->src_clk) / 2 / spi->max_speed_hz - 1;
-       psr &= S3C64XX_SPI_PSR_MASK;
-       if (psr == S3C64XX_SPI_PSR_MASK)
-               psr--;
+       if (!sci->clk_from_cmu) {
+               u32 psr, speed;
+
+               /* Max possible */
+               speed = clk_get_rate(sdd->src_clk) / 2 / (0 + 1);
+
+               if (spi->max_speed_hz > speed)
+                       spi->max_speed_hz = speed;
+
+               psr = clk_get_rate(sdd->src_clk) / 2 / spi->max_speed_hz - 1;
+               psr &= S3C64XX_SPI_PSR_MASK;
+               if (psr == S3C64XX_SPI_PSR_MASK)
+                       psr--;
+
+               speed = clk_get_rate(sdd->src_clk) / 2 / (psr + 1);
+               if (spi->max_speed_hz < speed) {
+                       if (psr+1 < S3C64XX_SPI_PSR_MASK) {
+                               psr++;
+                       } else {
+                               err = -EINVAL;
+                               goto setup_exit;
+                       }
+               }
 
-       speed = clk_get_rate(sdd->src_clk) / 2 / (psr + 1);
-       if (spi->max_speed_hz < speed) {
-               if (psr+1 < S3C64XX_SPI_PSR_MASK) {
-                       psr++;
-               } else {
+               speed = clk_get_rate(sdd->src_clk) / 2 / (psr + 1);
+               if (spi->max_speed_hz >= speed)
+                       spi->max_speed_hz = speed;
+               else
                        err = -EINVAL;
-                       goto setup_exit;
-               }
        }
 
-       speed = clk_get_rate(sdd->src_clk) / 2 / (psr + 1);
-       if (spi->max_speed_hz >= speed)
-               spi->max_speed_hz = speed;
-       else
-               err = -EINVAL;
-
 setup_exit:
 
        /* setup() returns with device de-selected */
@@ -896,7 +913,8 @@ static void s3c64xx_spi_hwinit(struct s3c64xx_spi_driver_data *sdd, int channel)
        /* Disable Interrupts - we use Polling if not DMA mode */
        writel(0, regs + S3C64XX_SPI_INT_EN);
 
-       writel(sci->src_clk_nr << S3C64XX_SPI_CLKSEL_SRCSHFT,
+       if (!sci->clk_from_cmu)
+               writel(sci->src_clk_nr << S3C64XX_SPI_CLKSEL_SRCSHFT,
                                regs + S3C64XX_SPI_CLK_CFG);
        writel(0, regs + S3C64XX_SPI_MODE_CFG);
        writel(0, regs + S3C64XX_SPI_PACKET_CNT);