diff options
author | Jassi Brar <jassi.brar@samsung.com> | 2010-09-29 04:31:33 -0400 |
---|---|---|
committer | Grant Likely <grant.likely@secretlab.ca> | 2010-09-29 04:31:33 -0400 |
commit | b42a81ca0fa7b3b442a0731ffc4e7db44464b5f2 (patch) | |
tree | 3f435d56cbb27cf47ca9fb8bc354a8d3f7f9373c /drivers/spi/spi_s3c64xx.c | |
parent | e02ddd442a532c73e547ae3735c8012e3bd719a5 (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.c | 94 |
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 | ||
400 | static void s3c64xx_spi_config(struct s3c64xx_spi_driver_data *sdd) | 400 | static 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 | ||
457 | static void s3c64xx_spi_dma_rxcb(struct s3c2410_dma_chan *chan, void *buf_id, | 470 | 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) | |||
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 | |||
878 | setup_exit: | 895 | setup_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); |