diff options
Diffstat (limited to 'drivers/spi/spi_s3c64xx.c')
-rw-r--r-- | drivers/spi/spi_s3c64xx.c | 89 |
1 files changed, 38 insertions, 51 deletions
diff --git a/drivers/spi/spi_s3c64xx.c b/drivers/spi/spi_s3c64xx.c index 88a456dba967..97365815a729 100644 --- a/drivers/spi/spi_s3c64xx.c +++ b/drivers/spi/spi_s3c64xx.c | |||
@@ -28,7 +28,7 @@ | |||
28 | #include <linux/spi/spi.h> | 28 | #include <linux/spi/spi.h> |
29 | 29 | ||
30 | #include <mach/dma.h> | 30 | #include <mach/dma.h> |
31 | #include <plat/spi.h> | 31 | #include <plat/s3c64xx-spi.h> |
32 | 32 | ||
33 | /* Registers and bit-fields */ | 33 | /* Registers and bit-fields */ |
34 | 34 | ||
@@ -137,6 +137,7 @@ | |||
137 | /** | 137 | /** |
138 | * struct s3c64xx_spi_driver_data - Runtime info holder for SPI driver. | 138 | * struct s3c64xx_spi_driver_data - Runtime info holder for SPI driver. |
139 | * @clk: Pointer to the spi clock. | 139 | * @clk: Pointer to the spi clock. |
140 | * @src_clk: Pointer to the clock used to generate SPI signals. | ||
140 | * @master: Pointer to the SPI Protocol master. | 141 | * @master: Pointer to the SPI Protocol master. |
141 | * @workqueue: Work queue for the SPI xfer requests. | 142 | * @workqueue: Work queue for the SPI xfer requests. |
142 | * @cntrlr_info: Platform specific data for the controller this driver manages. | 143 | * @cntrlr_info: Platform specific data for the controller this driver manages. |
@@ -157,10 +158,11 @@ | |||
157 | struct s3c64xx_spi_driver_data { | 158 | struct s3c64xx_spi_driver_data { |
158 | void __iomem *regs; | 159 | void __iomem *regs; |
159 | struct clk *clk; | 160 | struct clk *clk; |
161 | struct clk *src_clk; | ||
160 | struct platform_device *pdev; | 162 | struct platform_device *pdev; |
161 | struct spi_master *master; | 163 | struct spi_master *master; |
162 | struct workqueue_struct *workqueue; | 164 | struct workqueue_struct *workqueue; |
163 | struct s3c64xx_spi_cntrlr_info *cntrlr_info; | 165 | struct s3c64xx_spi_info *cntrlr_info; |
164 | struct spi_device *tgl_spi; | 166 | struct spi_device *tgl_spi; |
165 | struct work_struct work; | 167 | struct work_struct work; |
166 | struct list_head queue; | 168 | struct list_head queue; |
@@ -180,7 +182,7 @@ static struct s3c2410_dma_client s3c64xx_spi_dma_client = { | |||
180 | 182 | ||
181 | static void flush_fifo(struct s3c64xx_spi_driver_data *sdd) | 183 | static void flush_fifo(struct s3c64xx_spi_driver_data *sdd) |
182 | { | 184 | { |
183 | struct s3c64xx_spi_cntrlr_info *sci = sdd->cntrlr_info; | 185 | struct s3c64xx_spi_info *sci = sdd->cntrlr_info; |
184 | void __iomem *regs = sdd->regs; | 186 | void __iomem *regs = sdd->regs; |
185 | unsigned long loops; | 187 | unsigned long loops; |
186 | u32 val; | 188 | u32 val; |
@@ -225,7 +227,7 @@ static void enable_datapath(struct s3c64xx_spi_driver_data *sdd, | |||
225 | struct spi_device *spi, | 227 | struct spi_device *spi, |
226 | struct spi_transfer *xfer, int dma_mode) | 228 | struct spi_transfer *xfer, int dma_mode) |
227 | { | 229 | { |
228 | struct s3c64xx_spi_cntrlr_info *sci = sdd->cntrlr_info; | 230 | struct s3c64xx_spi_info *sci = sdd->cntrlr_info; |
229 | void __iomem *regs = sdd->regs; | 231 | void __iomem *regs = sdd->regs; |
230 | u32 modecfg, chcfg; | 232 | u32 modecfg, chcfg; |
231 | 233 | ||
@@ -298,19 +300,20 @@ static inline void enable_cs(struct s3c64xx_spi_driver_data *sdd, | |||
298 | if (sdd->tgl_spi != spi) { /* if last mssg on diff device */ | 300 | if (sdd->tgl_spi != spi) { /* if last mssg on diff device */ |
299 | /* Deselect the last toggled device */ | 301 | /* Deselect the last toggled device */ |
300 | cs = sdd->tgl_spi->controller_data; | 302 | cs = sdd->tgl_spi->controller_data; |
301 | cs->set_level(spi->mode & SPI_CS_HIGH ? 0 : 1); | 303 | cs->set_level(cs->line, |
304 | spi->mode & SPI_CS_HIGH ? 0 : 1); | ||
302 | } | 305 | } |
303 | sdd->tgl_spi = NULL; | 306 | sdd->tgl_spi = NULL; |
304 | } | 307 | } |
305 | 308 | ||
306 | cs = spi->controller_data; | 309 | cs = spi->controller_data; |
307 | cs->set_level(spi->mode & SPI_CS_HIGH ? 1 : 0); | 310 | cs->set_level(cs->line, spi->mode & SPI_CS_HIGH ? 1 : 0); |
308 | } | 311 | } |
309 | 312 | ||
310 | static int wait_for_xfer(struct s3c64xx_spi_driver_data *sdd, | 313 | static int wait_for_xfer(struct s3c64xx_spi_driver_data *sdd, |
311 | struct spi_transfer *xfer, int dma_mode) | 314 | struct spi_transfer *xfer, int dma_mode) |
312 | { | 315 | { |
313 | struct s3c64xx_spi_cntrlr_info *sci = sdd->cntrlr_info; | 316 | struct s3c64xx_spi_info *sci = sdd->cntrlr_info; |
314 | void __iomem *regs = sdd->regs; | 317 | void __iomem *regs = sdd->regs; |
315 | unsigned long val; | 318 | unsigned long val; |
316 | int ms; | 319 | int ms; |
@@ -384,12 +387,11 @@ static inline void disable_cs(struct s3c64xx_spi_driver_data *sdd, | |||
384 | if (sdd->tgl_spi == spi) | 387 | if (sdd->tgl_spi == spi) |
385 | sdd->tgl_spi = NULL; | 388 | sdd->tgl_spi = NULL; |
386 | 389 | ||
387 | cs->set_level(spi->mode & SPI_CS_HIGH ? 0 : 1); | 390 | cs->set_level(cs->line, spi->mode & SPI_CS_HIGH ? 0 : 1); |
388 | } | 391 | } |
389 | 392 | ||
390 | static void s3c64xx_spi_config(struct s3c64xx_spi_driver_data *sdd) | 393 | static void s3c64xx_spi_config(struct s3c64xx_spi_driver_data *sdd) |
391 | { | 394 | { |
392 | struct s3c64xx_spi_cntrlr_info *sci = sdd->cntrlr_info; | ||
393 | void __iomem *regs = sdd->regs; | 395 | void __iomem *regs = sdd->regs; |
394 | u32 val; | 396 | u32 val; |
395 | 397 | ||
@@ -435,7 +437,7 @@ static void s3c64xx_spi_config(struct s3c64xx_spi_driver_data *sdd) | |||
435 | /* Configure Clock */ | 437 | /* Configure Clock */ |
436 | val = readl(regs + S3C64XX_SPI_CLK_CFG); | 438 | val = readl(regs + S3C64XX_SPI_CLK_CFG); |
437 | val &= ~S3C64XX_SPI_PSR_MASK; | 439 | val &= ~S3C64XX_SPI_PSR_MASK; |
438 | val |= ((clk_get_rate(sci->src_clk) / sdd->cur_speed / 2 - 1) | 440 | val |= ((clk_get_rate(sdd->src_clk) / sdd->cur_speed / 2 - 1) |
439 | & S3C64XX_SPI_PSR_MASK); | 441 | & S3C64XX_SPI_PSR_MASK); |
440 | writel(val, regs + S3C64XX_SPI_CLK_CFG); | 442 | writel(val, regs + S3C64XX_SPI_CLK_CFG); |
441 | 443 | ||
@@ -558,7 +560,7 @@ static void s3c64xx_spi_unmap_mssg(struct s3c64xx_spi_driver_data *sdd, | |||
558 | static void handle_msg(struct s3c64xx_spi_driver_data *sdd, | 560 | static void handle_msg(struct s3c64xx_spi_driver_data *sdd, |
559 | struct spi_message *msg) | 561 | struct spi_message *msg) |
560 | { | 562 | { |
561 | struct s3c64xx_spi_cntrlr_info *sci = sdd->cntrlr_info; | 563 | struct s3c64xx_spi_info *sci = sdd->cntrlr_info; |
562 | struct spi_device *spi = msg->spi; | 564 | struct spi_device *spi = msg->spi; |
563 | struct s3c64xx_spi_csinfo *cs = spi->controller_data; | 565 | struct s3c64xx_spi_csinfo *cs = spi->controller_data; |
564 | struct spi_transfer *xfer; | 566 | struct spi_transfer *xfer; |
@@ -632,8 +634,8 @@ static void handle_msg(struct s3c64xx_spi_driver_data *sdd, | |||
632 | S3C64XX_SPI_DEACT(sdd); | 634 | S3C64XX_SPI_DEACT(sdd); |
633 | 635 | ||
634 | if (status) { | 636 | if (status) { |
635 | dev_err(&spi->dev, "I/O Error: \ | 637 | dev_err(&spi->dev, "I/O Error: " |
636 | rx-%d tx-%d res:rx-%c tx-%c len-%d\n", | 638 | "rx-%d tx-%d res:rx-%c tx-%c len-%d\n", |
637 | xfer->rx_buf ? 1 : 0, xfer->tx_buf ? 1 : 0, | 639 | xfer->rx_buf ? 1 : 0, xfer->tx_buf ? 1 : 0, |
638 | (sdd->state & RXBUSY) ? 'f' : 'p', | 640 | (sdd->state & RXBUSY) ? 'f' : 'p', |
639 | (sdd->state & TXBUSY) ? 'f' : 'p', | 641 | (sdd->state & TXBUSY) ? 'f' : 'p', |
@@ -786,7 +788,7 @@ static int s3c64xx_spi_setup(struct spi_device *spi) | |||
786 | { | 788 | { |
787 | struct s3c64xx_spi_csinfo *cs = spi->controller_data; | 789 | struct s3c64xx_spi_csinfo *cs = spi->controller_data; |
788 | struct s3c64xx_spi_driver_data *sdd; | 790 | struct s3c64xx_spi_driver_data *sdd; |
789 | struct s3c64xx_spi_cntrlr_info *sci; | 791 | struct s3c64xx_spi_info *sci; |
790 | struct spi_message *msg; | 792 | struct spi_message *msg; |
791 | u32 psr, speed; | 793 | u32 psr, speed; |
792 | unsigned long flags; | 794 | unsigned long flags; |
@@ -831,17 +833,17 @@ static int s3c64xx_spi_setup(struct spi_device *spi) | |||
831 | } | 833 | } |
832 | 834 | ||
833 | /* Check if we can provide the requested rate */ | 835 | /* Check if we can provide the requested rate */ |
834 | speed = clk_get_rate(sci->src_clk) / 2 / (0 + 1); /* Max possible */ | 836 | speed = clk_get_rate(sdd->src_clk) / 2 / (0 + 1); /* Max possible */ |
835 | 837 | ||
836 | if (spi->max_speed_hz > speed) | 838 | if (spi->max_speed_hz > speed) |
837 | spi->max_speed_hz = speed; | 839 | spi->max_speed_hz = speed; |
838 | 840 | ||
839 | psr = clk_get_rate(sci->src_clk) / 2 / spi->max_speed_hz - 1; | 841 | psr = clk_get_rate(sdd->src_clk) / 2 / spi->max_speed_hz - 1; |
840 | psr &= S3C64XX_SPI_PSR_MASK; | 842 | psr &= S3C64XX_SPI_PSR_MASK; |
841 | if (psr == S3C64XX_SPI_PSR_MASK) | 843 | if (psr == S3C64XX_SPI_PSR_MASK) |
842 | psr--; | 844 | psr--; |
843 | 845 | ||
844 | speed = clk_get_rate(sci->src_clk) / 2 / (psr + 1); | 846 | speed = clk_get_rate(sdd->src_clk) / 2 / (psr + 1); |
845 | if (spi->max_speed_hz < speed) { | 847 | if (spi->max_speed_hz < speed) { |
846 | if (psr+1 < S3C64XX_SPI_PSR_MASK) { | 848 | if (psr+1 < S3C64XX_SPI_PSR_MASK) { |
847 | psr++; | 849 | psr++; |
@@ -851,7 +853,7 @@ static int s3c64xx_spi_setup(struct spi_device *spi) | |||
851 | } | 853 | } |
852 | } | 854 | } |
853 | 855 | ||
854 | speed = clk_get_rate(sci->src_clk) / 2 / (psr + 1); | 856 | speed = clk_get_rate(sdd->src_clk) / 2 / (psr + 1); |
855 | if (spi->max_speed_hz >= speed) | 857 | if (spi->max_speed_hz >= speed) |
856 | spi->max_speed_hz = speed; | 858 | spi->max_speed_hz = speed; |
857 | else | 859 | else |
@@ -867,7 +869,7 @@ setup_exit: | |||
867 | 869 | ||
868 | static void s3c64xx_spi_hwinit(struct s3c64xx_spi_driver_data *sdd, int channel) | 870 | static void s3c64xx_spi_hwinit(struct s3c64xx_spi_driver_data *sdd, int channel) |
869 | { | 871 | { |
870 | struct s3c64xx_spi_cntrlr_info *sci = sdd->cntrlr_info; | 872 | struct s3c64xx_spi_info *sci = sdd->cntrlr_info; |
871 | void __iomem *regs = sdd->regs; | 873 | void __iomem *regs = sdd->regs; |
872 | unsigned int val; | 874 | unsigned int val; |
873 | 875 | ||
@@ -902,7 +904,7 @@ static int __init s3c64xx_spi_probe(struct platform_device *pdev) | |||
902 | { | 904 | { |
903 | struct resource *mem_res, *dmatx_res, *dmarx_res; | 905 | struct resource *mem_res, *dmatx_res, *dmarx_res; |
904 | struct s3c64xx_spi_driver_data *sdd; | 906 | struct s3c64xx_spi_driver_data *sdd; |
905 | struct s3c64xx_spi_cntrlr_info *sci; | 907 | struct s3c64xx_spi_info *sci; |
906 | struct spi_master *master; | 908 | struct spi_master *master; |
907 | int ret; | 909 | int ret; |
908 | 910 | ||
@@ -1000,18 +1002,15 @@ static int __init s3c64xx_spi_probe(struct platform_device *pdev) | |||
1000 | goto err4; | 1002 | goto err4; |
1001 | } | 1003 | } |
1002 | 1004 | ||
1003 | if (sci->src_clk_nr == S3C64XX_SPI_SRCCLK_PCLK) | 1005 | sdd->src_clk = clk_get(&pdev->dev, sci->src_clk_name); |
1004 | sci->src_clk = sdd->clk; | 1006 | if (IS_ERR(sdd->src_clk)) { |
1005 | else | ||
1006 | sci->src_clk = clk_get(&pdev->dev, sci->src_clk_name); | ||
1007 | if (IS_ERR(sci->src_clk)) { | ||
1008 | dev_err(&pdev->dev, | 1007 | dev_err(&pdev->dev, |
1009 | "Unable to acquire clock '%s'\n", sci->src_clk_name); | 1008 | "Unable to acquire clock '%s'\n", sci->src_clk_name); |
1010 | ret = PTR_ERR(sci->src_clk); | 1009 | ret = PTR_ERR(sdd->src_clk); |
1011 | goto err5; | 1010 | goto err5; |
1012 | } | 1011 | } |
1013 | 1012 | ||
1014 | if (sci->src_clk != sdd->clk && clk_enable(sci->src_clk)) { | 1013 | if (clk_enable(sdd->src_clk)) { |
1015 | dev_err(&pdev->dev, "Couldn't enable clock '%s'\n", | 1014 | dev_err(&pdev->dev, "Couldn't enable clock '%s'\n", |
1016 | sci->src_clk_name); | 1015 | sci->src_clk_name); |
1017 | ret = -EBUSY; | 1016 | ret = -EBUSY; |
@@ -1040,11 +1039,10 @@ static int __init s3c64xx_spi_probe(struct platform_device *pdev) | |||
1040 | goto err8; | 1039 | goto err8; |
1041 | } | 1040 | } |
1042 | 1041 | ||
1043 | dev_dbg(&pdev->dev, "Samsung SoC SPI Driver loaded for Bus SPI-%d \ | 1042 | dev_dbg(&pdev->dev, "Samsung SoC SPI Driver loaded for Bus SPI-%d " |
1044 | with %d Slaves attached\n", | 1043 | "with %d Slaves attached\n", |
1045 | pdev->id, master->num_chipselect); | 1044 | pdev->id, master->num_chipselect); |
1046 | dev_dbg(&pdev->dev, "\tIOmem=[0x%x-0x%x]\ | 1045 | dev_dbg(&pdev->dev, "\tIOmem=[0x%x-0x%x]\tDMA=[Rx-%d, Tx-%d]\n", |
1047 | \tDMA=[Rx-%d, Tx-%d]\n", | ||
1048 | mem_res->end, mem_res->start, | 1046 | mem_res->end, mem_res->start, |
1049 | sdd->rx_dmach, sdd->tx_dmach); | 1047 | sdd->rx_dmach, sdd->tx_dmach); |
1050 | 1048 | ||
@@ -1053,11 +1051,9 @@ static int __init s3c64xx_spi_probe(struct platform_device *pdev) | |||
1053 | err8: | 1051 | err8: |
1054 | destroy_workqueue(sdd->workqueue); | 1052 | destroy_workqueue(sdd->workqueue); |
1055 | err7: | 1053 | err7: |
1056 | if (sci->src_clk != sdd->clk) | 1054 | clk_disable(sdd->src_clk); |
1057 | clk_disable(sci->src_clk); | ||
1058 | err6: | 1055 | err6: |
1059 | if (sci->src_clk != sdd->clk) | 1056 | clk_put(sdd->src_clk); |
1060 | clk_put(sci->src_clk); | ||
1061 | err5: | 1057 | err5: |
1062 | clk_disable(sdd->clk); | 1058 | clk_disable(sdd->clk); |
1063 | err4: | 1059 | err4: |
@@ -1078,7 +1074,6 @@ static int s3c64xx_spi_remove(struct platform_device *pdev) | |||
1078 | { | 1074 | { |
1079 | struct spi_master *master = spi_master_get(platform_get_drvdata(pdev)); | 1075 | struct spi_master *master = spi_master_get(platform_get_drvdata(pdev)); |
1080 | struct s3c64xx_spi_driver_data *sdd = spi_master_get_devdata(master); | 1076 | struct s3c64xx_spi_driver_data *sdd = spi_master_get_devdata(master); |
1081 | struct s3c64xx_spi_cntrlr_info *sci = sdd->cntrlr_info; | ||
1082 | struct resource *mem_res; | 1077 | struct resource *mem_res; |
1083 | unsigned long flags; | 1078 | unsigned long flags; |
1084 | 1079 | ||
@@ -1093,11 +1088,8 @@ static int s3c64xx_spi_remove(struct platform_device *pdev) | |||
1093 | 1088 | ||
1094 | destroy_workqueue(sdd->workqueue); | 1089 | destroy_workqueue(sdd->workqueue); |
1095 | 1090 | ||
1096 | if (sci->src_clk != sdd->clk) | 1091 | clk_disable(sdd->src_clk); |
1097 | clk_disable(sci->src_clk); | 1092 | clk_put(sdd->src_clk); |
1098 | |||
1099 | if (sci->src_clk != sdd->clk) | ||
1100 | clk_put(sci->src_clk); | ||
1101 | 1093 | ||
1102 | clk_disable(sdd->clk); | 1094 | clk_disable(sdd->clk); |
1103 | clk_put(sdd->clk); | 1095 | clk_put(sdd->clk); |
@@ -1105,7 +1097,8 @@ static int s3c64xx_spi_remove(struct platform_device *pdev) | |||
1105 | iounmap((void *) sdd->regs); | 1097 | iounmap((void *) sdd->regs); |
1106 | 1098 | ||
1107 | mem_res = platform_get_resource(pdev, IORESOURCE_MEM, 0); | 1099 | mem_res = platform_get_resource(pdev, IORESOURCE_MEM, 0); |
1108 | release_mem_region(mem_res->start, resource_size(mem_res)); | 1100 | if (mem_res != NULL) |
1101 | release_mem_region(mem_res->start, resource_size(mem_res)); | ||
1109 | 1102 | ||
1110 | platform_set_drvdata(pdev, NULL); | 1103 | platform_set_drvdata(pdev, NULL); |
1111 | spi_master_put(master); | 1104 | spi_master_put(master); |
@@ -1118,8 +1111,6 @@ static int s3c64xx_spi_suspend(struct platform_device *pdev, pm_message_t state) | |||
1118 | { | 1111 | { |
1119 | struct spi_master *master = spi_master_get(platform_get_drvdata(pdev)); | 1112 | struct spi_master *master = spi_master_get(platform_get_drvdata(pdev)); |
1120 | struct s3c64xx_spi_driver_data *sdd = spi_master_get_devdata(master); | 1113 | struct s3c64xx_spi_driver_data *sdd = spi_master_get_devdata(master); |
1121 | struct s3c64xx_spi_cntrlr_info *sci = sdd->cntrlr_info; | ||
1122 | struct s3c64xx_spi_csinfo *cs; | ||
1123 | unsigned long flags; | 1114 | unsigned long flags; |
1124 | 1115 | ||
1125 | spin_lock_irqsave(&sdd->lock, flags); | 1116 | spin_lock_irqsave(&sdd->lock, flags); |
@@ -1130,9 +1121,7 @@ static int s3c64xx_spi_suspend(struct platform_device *pdev, pm_message_t state) | |||
1130 | msleep(10); | 1121 | msleep(10); |
1131 | 1122 | ||
1132 | /* Disable the clock */ | 1123 | /* Disable the clock */ |
1133 | if (sci->src_clk != sdd->clk) | 1124 | clk_disable(sdd->src_clk); |
1134 | clk_disable(sci->src_clk); | ||
1135 | |||
1136 | clk_disable(sdd->clk); | 1125 | clk_disable(sdd->clk); |
1137 | 1126 | ||
1138 | sdd->cur_speed = 0; /* Output Clock is stopped */ | 1127 | sdd->cur_speed = 0; /* Output Clock is stopped */ |
@@ -1144,15 +1133,13 @@ static int s3c64xx_spi_resume(struct platform_device *pdev) | |||
1144 | { | 1133 | { |
1145 | struct spi_master *master = spi_master_get(platform_get_drvdata(pdev)); | 1134 | struct spi_master *master = spi_master_get(platform_get_drvdata(pdev)); |
1146 | struct s3c64xx_spi_driver_data *sdd = spi_master_get_devdata(master); | 1135 | struct s3c64xx_spi_driver_data *sdd = spi_master_get_devdata(master); |
1147 | struct s3c64xx_spi_cntrlr_info *sci = sdd->cntrlr_info; | 1136 | struct s3c64xx_spi_info *sci = sdd->cntrlr_info; |
1148 | unsigned long flags; | 1137 | unsigned long flags; |
1149 | 1138 | ||
1150 | sci->cfg_gpio(pdev); | 1139 | sci->cfg_gpio(pdev); |
1151 | 1140 | ||
1152 | /* Enable the clock */ | 1141 | /* Enable the clock */ |
1153 | if (sci->src_clk != sdd->clk) | 1142 | clk_enable(sdd->src_clk); |
1154 | clk_enable(sci->src_clk); | ||
1155 | |||
1156 | clk_enable(sdd->clk); | 1143 | clk_enable(sdd->clk); |
1157 | 1144 | ||
1158 | s3c64xx_spi_hwinit(sdd, pdev->id); | 1145 | s3c64xx_spi_hwinit(sdd, pdev->id); |