aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--arch/arm/plat-samsung/include/plat/s3c64xx-spi.h3
-rw-r--r--drivers/spi/spi_s3c64xx.c94
2 files changed, 59 insertions, 38 deletions
diff --git a/arch/arm/plat-samsung/include/plat/s3c64xx-spi.h b/arch/arm/plat-samsung/include/plat/s3c64xx-spi.h
index e5aba8f95b79..b226f7405e6b 100644
--- a/arch/arm/plat-samsung/include/plat/s3c64xx-spi.h
+++ b/arch/arm/plat-samsung/include/plat/s3c64xx-spi.h
@@ -32,6 +32,8 @@ struct s3c64xx_spi_csinfo {
32 * struct s3c64xx_spi_info - SPI Controller defining structure 32 * struct s3c64xx_spi_info - SPI Controller defining structure
33 * @src_clk_nr: Clock source index for the CLK_CFG[SPI_CLKSEL] field. 33 * @src_clk_nr: Clock source index for the CLK_CFG[SPI_CLKSEL] field.
34 * @src_clk_name: Platform name of the corresponding clock. 34 * @src_clk_name: Platform name of the corresponding clock.
35 * @clk_from_cmu: If the SPI clock/prescalar control block is present
36 * by the platform's clock-management-unit and not in SPI controller.
35 * @num_cs: Number of CS this controller emulates. 37 * @num_cs: Number of CS this controller emulates.
36 * @cfg_gpio: Configure pins for this SPI controller. 38 * @cfg_gpio: Configure pins for this SPI controller.
37 * @fifo_lvl_mask: All tx fifo_lvl fields start at offset-6 39 * @fifo_lvl_mask: All tx fifo_lvl fields start at offset-6
@@ -41,6 +43,7 @@ struct s3c64xx_spi_csinfo {
41struct s3c64xx_spi_info { 43struct s3c64xx_spi_info {
42 int src_clk_nr; 44 int src_clk_nr;
43 char *src_clk_name; 45 char *src_clk_name;
46 bool clk_from_cmu;
44 47
45 int num_cs; 48 int num_cs;
46 49
diff --git a/drivers/spi/spi_s3c64xx.c b/drivers/spi/spi_s3c64xx.c
index e7b893f2a21b..9e0aa3c7b4d1 100644
--- a/drivers/spi/spi_s3c64xx.c
+++ b/drivers/spi/spi_s3c64xx.c
@@ -399,13 +399,18 @@ static inline void disable_cs(struct s3c64xx_spi_driver_data *sdd,
399 399
400static void s3c64xx_spi_config(struct s3c64xx_spi_driver_data *sdd) 400static void s3c64xx_spi_config(struct s3c64xx_spi_driver_data *sdd)
401{ 401{
402 struct s3c64xx_spi_info *sci = sdd->cntrlr_info;
402 void __iomem *regs = sdd->regs; 403 void __iomem *regs = sdd->regs;
403 u32 val; 404 u32 val;
404 405
405 /* Disable Clock */ 406 /* Disable Clock */
406 val = readl(regs + S3C64XX_SPI_CLK_CFG); 407 if (sci->clk_from_cmu) {
407 val &= ~S3C64XX_SPI_ENCLK_ENABLE; 408 clk_disable(sdd->src_clk);
408 writel(val, regs + S3C64XX_SPI_CLK_CFG); 409 } else {
410 val = readl(regs + S3C64XX_SPI_CLK_CFG);
411 val &= ~S3C64XX_SPI_ENCLK_ENABLE;
412 writel(val, regs + S3C64XX_SPI_CLK_CFG);
413 }
409 414
410 /* Set Polarity and Phase */ 415 /* Set Polarity and Phase */
411 val = readl(regs + S3C64XX_SPI_CH_CFG); 416 val = readl(regs + S3C64XX_SPI_CH_CFG);
@@ -441,17 +446,25 @@ static void s3c64xx_spi_config(struct s3c64xx_spi_driver_data *sdd)
441 446
442 writel(val, regs + S3C64XX_SPI_MODE_CFG); 447 writel(val, regs + S3C64XX_SPI_MODE_CFG);
443 448
444 /* Configure Clock */ 449 if (sci->clk_from_cmu) {
445 val = readl(regs + S3C64XX_SPI_CLK_CFG); 450 /* Configure Clock */
446 val &= ~S3C64XX_SPI_PSR_MASK; 451 /* There is half-multiplier before the SPI */
447 val |= ((clk_get_rate(sdd->src_clk) / sdd->cur_speed / 2 - 1) 452 clk_set_rate(sdd->src_clk, sdd->cur_speed * 2);
448 & S3C64XX_SPI_PSR_MASK); 453 /* Enable Clock */
449 writel(val, regs + S3C64XX_SPI_CLK_CFG); 454 clk_enable(sdd->src_clk);
450 455 } else {
451 /* Enable Clock */ 456 /* Configure Clock */
452 val = readl(regs + S3C64XX_SPI_CLK_CFG); 457 val = readl(regs + S3C64XX_SPI_CLK_CFG);
453 val |= S3C64XX_SPI_ENCLK_ENABLE; 458 val &= ~S3C64XX_SPI_PSR_MASK;
454 writel(val, regs + S3C64XX_SPI_CLK_CFG); 459 val |= ((clk_get_rate(sdd->src_clk) / sdd->cur_speed / 2 - 1)
460 & S3C64XX_SPI_PSR_MASK);
461 writel(val, regs + S3C64XX_SPI_CLK_CFG);
462
463 /* Enable Clock */
464 val = readl(regs + S3C64XX_SPI_CLK_CFG);
465 val |= S3C64XX_SPI_ENCLK_ENABLE;
466 writel(val, regs + S3C64XX_SPI_CLK_CFG);
467 }
455} 468}
456 469
457static void s3c64xx_spi_dma_rxcb(struct s3c2410_dma_chan *chan, void *buf_id, 470static 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)
806 struct s3c64xx_spi_driver_data *sdd; 819 struct s3c64xx_spi_driver_data *sdd;
807 struct s3c64xx_spi_info *sci; 820 struct s3c64xx_spi_info *sci;
808 struct spi_message *msg; 821 struct spi_message *msg;
809 u32 psr, speed;
810 unsigned long flags; 822 unsigned long flags;
811 int err = 0; 823 int err = 0;
812 824
@@ -849,32 +861,37 @@ static int s3c64xx_spi_setup(struct spi_device *spi)
849 } 861 }
850 862
851 /* Check if we can provide the requested rate */ 863 /* Check if we can provide the requested rate */
852 speed = clk_get_rate(sdd->src_clk) / 2 / (0 + 1); /* Max possible */ 864 if (!sci->clk_from_cmu) {
853 865 u32 psr, speed;
854 if (spi->max_speed_hz > speed) 866
855 spi->max_speed_hz = speed; 867 /* Max possible */
856 868 speed = clk_get_rate(sdd->src_clk) / 2 / (0 + 1);
857 psr = clk_get_rate(sdd->src_clk) / 2 / spi->max_speed_hz - 1; 869
858 psr &= S3C64XX_SPI_PSR_MASK; 870 if (spi->max_speed_hz > speed)
859 if (psr == S3C64XX_SPI_PSR_MASK) 871 spi->max_speed_hz = speed;
860 psr--; 872
873 psr = clk_get_rate(sdd->src_clk) / 2 / spi->max_speed_hz - 1;
874 psr &= S3C64XX_SPI_PSR_MASK;
875 if (psr == S3C64XX_SPI_PSR_MASK)
876 psr--;
877
878 speed = clk_get_rate(sdd->src_clk) / 2 / (psr + 1);
879 if (spi->max_speed_hz < speed) {
880 if (psr+1 < S3C64XX_SPI_PSR_MASK) {
881 psr++;
882 } else {
883 err = -EINVAL;
884 goto setup_exit;
885 }
886 }
861 887
862 speed = clk_get_rate(sdd->src_clk) / 2 / (psr + 1); 888 speed = clk_get_rate(sdd->src_clk) / 2 / (psr + 1);
863 if (spi->max_speed_hz < speed) { 889 if (spi->max_speed_hz >= speed)
864 if (psr+1 < S3C64XX_SPI_PSR_MASK) { 890 spi->max_speed_hz = speed;
865 psr++; 891 else
866 } else {
867 err = -EINVAL; 892 err = -EINVAL;
868 goto setup_exit;
869 }
870 } 893 }
871 894
872 speed = clk_get_rate(sdd->src_clk) / 2 / (psr + 1);
873 if (spi->max_speed_hz >= speed)
874 spi->max_speed_hz = speed;
875 else
876 err = -EINVAL;
877
878setup_exit: 895setup_exit:
879 896
880 /* setup() returns with device de-selected */ 897 /* setup() returns with device de-selected */
@@ -896,7 +913,8 @@ static void s3c64xx_spi_hwinit(struct s3c64xx_spi_driver_data *sdd, int channel)
896 /* Disable Interrupts - we use Polling if not DMA mode */ 913 /* Disable Interrupts - we use Polling if not DMA mode */
897 writel(0, regs + S3C64XX_SPI_INT_EN); 914 writel(0, regs + S3C64XX_SPI_INT_EN);
898 915
899 writel(sci->src_clk_nr << S3C64XX_SPI_CLKSEL_SRCSHFT, 916 if (!sci->clk_from_cmu)
917 writel(sci->src_clk_nr << S3C64XX_SPI_CLKSEL_SRCSHFT,
900 regs + S3C64XX_SPI_CLK_CFG); 918 regs + S3C64XX_SPI_CLK_CFG);
901 writel(0, regs + S3C64XX_SPI_MODE_CFG); 919 writel(0, regs + S3C64XX_SPI_MODE_CFG);
902 writel(0, regs + S3C64XX_SPI_PACKET_CNT); 920 writel(0, regs + S3C64XX_SPI_PACKET_CNT);