aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/spi/spi_s3c64xx.c
diff options
context:
space:
mode:
authorJassi Brar <jassi.brar@samsung.com>2010-09-29 04:31:33 -0400
committerGrant Likely <grant.likely@secretlab.ca>2010-09-29 04:31:33 -0400
commitb42a81ca0fa7b3b442a0731ffc4e7db44464b5f2 (patch)
tree3f435d56cbb27cf47ca9fb8bc354a8d3f7f9373c /drivers/spi/spi_s3c64xx.c
parente02ddd442a532c73e547ae3735c8012e3bd719a5 (diff)
spi/s3c64xx: Consider the clk_from_cmu flag
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>
Diffstat (limited to 'drivers/spi/spi_s3c64xx.c')
-rw-r--r--drivers/spi/spi_s3c64xx.c94
1 files changed, 56 insertions, 38 deletions
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);