diff options
author | Mark Brown <broonie@linaro.org> | 2013-10-11 15:10:13 -0400 |
---|---|---|
committer | Mark Brown <broonie@linaro.org> | 2013-10-11 15:10:13 -0400 |
commit | 2cc6e2e0c8157b9e6ed8dbe5c7284865f6afbd46 (patch) | |
tree | f50c505d9811d6fa2d9c042f2fdfa7ebcf79e158 /drivers/spi | |
parent | b158935f70b9c156903338053216dd0adf7ce31c (diff) | |
parent | ebd805cc14bec607e74795b7933570f240508cb4 (diff) |
Merge remote-tracking branch 'spi/topic/s3c64xx' into spi-loop
Diffstat (limited to 'drivers/spi')
-rw-r--r-- | drivers/spi/Kconfig | 2 | ||||
-rw-r--r-- | drivers/spi/spi-s3c64xx.c | 106 | ||||
-rw-r--r-- | drivers/spi/spi.c | 35 |
3 files changed, 93 insertions, 50 deletions
diff --git a/drivers/spi/Kconfig b/drivers/spi/Kconfig index b9c53cc40e1f..d92d6690d615 100644 --- a/drivers/spi/Kconfig +++ b/drivers/spi/Kconfig | |||
@@ -393,7 +393,7 @@ config SPI_S3C24XX_FIQ | |||
393 | 393 | ||
394 | config SPI_S3C64XX | 394 | config SPI_S3C64XX |
395 | tristate "Samsung S3C64XX series type SPI" | 395 | tristate "Samsung S3C64XX series type SPI" |
396 | depends on (ARCH_S3C24XX || ARCH_S3C64XX || ARCH_S5P64X0 || ARCH_EXYNOS) | 396 | depends on PLAT_SAMSUNG |
397 | select S3C64XX_DMA if ARCH_S3C64XX | 397 | select S3C64XX_DMA if ARCH_S3C64XX |
398 | help | 398 | help |
399 | SPI driver for Samsung S3C64XX and newer SoCs. | 399 | SPI driver for Samsung S3C64XX and newer SoCs. |
diff --git a/drivers/spi/spi-s3c64xx.c b/drivers/spi/spi-s3c64xx.c index 27b744be982e..c7b36c06ef40 100644 --- a/drivers/spi/spi-s3c64xx.c +++ b/drivers/spi/spi-s3c64xx.c | |||
@@ -205,7 +205,6 @@ struct s3c64xx_spi_driver_data { | |||
205 | #endif | 205 | #endif |
206 | struct s3c64xx_spi_port_config *port_conf; | 206 | struct s3c64xx_spi_port_config *port_conf; |
207 | unsigned int port_id; | 207 | unsigned int port_id; |
208 | unsigned long gpios[4]; | ||
209 | bool cs_gpio; | 208 | bool cs_gpio; |
210 | }; | 209 | }; |
211 | 210 | ||
@@ -559,25 +558,18 @@ static void enable_datapath(struct s3c64xx_spi_driver_data *sdd, | |||
559 | static inline void enable_cs(struct s3c64xx_spi_driver_data *sdd, | 558 | static inline void enable_cs(struct s3c64xx_spi_driver_data *sdd, |
560 | struct spi_device *spi) | 559 | struct spi_device *spi) |
561 | { | 560 | { |
562 | struct s3c64xx_spi_csinfo *cs; | ||
563 | |||
564 | if (sdd->tgl_spi != NULL) { /* If last device toggled after mssg */ | 561 | if (sdd->tgl_spi != NULL) { /* If last device toggled after mssg */ |
565 | if (sdd->tgl_spi != spi) { /* if last mssg on diff device */ | 562 | if (sdd->tgl_spi != spi) { /* if last mssg on diff device */ |
566 | /* Deselect the last toggled device */ | 563 | /* Deselect the last toggled device */ |
567 | cs = sdd->tgl_spi->controller_data; | 564 | if (spi->cs_gpio >= 0) |
568 | if (sdd->cs_gpio) | 565 | gpio_set_value(spi->cs_gpio, |
569 | gpio_set_value(cs->line, | ||
570 | spi->mode & SPI_CS_HIGH ? 0 : 1); | 566 | spi->mode & SPI_CS_HIGH ? 0 : 1); |
571 | } | 567 | } |
572 | sdd->tgl_spi = NULL; | 568 | sdd->tgl_spi = NULL; |
573 | } | 569 | } |
574 | 570 | ||
575 | cs = spi->controller_data; | 571 | if (spi->cs_gpio >= 0) |
576 | if (sdd->cs_gpio) | 572 | gpio_set_value(spi->cs_gpio, spi->mode & SPI_CS_HIGH ? 1 : 0); |
577 | gpio_set_value(cs->line, spi->mode & SPI_CS_HIGH ? 1 : 0); | ||
578 | |||
579 | /* Start the signals */ | ||
580 | writel(0, sdd->regs + S3C64XX_SPI_SLAVE_SEL); | ||
581 | } | 573 | } |
582 | 574 | ||
583 | static u32 s3c64xx_spi_wait_for_timeout(struct s3c64xx_spi_driver_data *sdd, | 575 | static u32 s3c64xx_spi_wait_for_timeout(struct s3c64xx_spi_driver_data *sdd, |
@@ -702,16 +694,11 @@ static int wait_for_xfer(struct s3c64xx_spi_driver_data *sdd, | |||
702 | static inline void disable_cs(struct s3c64xx_spi_driver_data *sdd, | 694 | static inline void disable_cs(struct s3c64xx_spi_driver_data *sdd, |
703 | struct spi_device *spi) | 695 | struct spi_device *spi) |
704 | { | 696 | { |
705 | struct s3c64xx_spi_csinfo *cs = spi->controller_data; | ||
706 | |||
707 | if (sdd->tgl_spi == spi) | 697 | if (sdd->tgl_spi == spi) |
708 | sdd->tgl_spi = NULL; | 698 | sdd->tgl_spi = NULL; |
709 | 699 | ||
710 | if (sdd->cs_gpio) | 700 | if (spi->cs_gpio >= 0) |
711 | gpio_set_value(cs->line, spi->mode & SPI_CS_HIGH ? 0 : 1); | 701 | gpio_set_value(spi->cs_gpio, spi->mode & SPI_CS_HIGH ? 0 : 1); |
712 | |||
713 | /* Quiese the signals */ | ||
714 | writel(S3C64XX_SPI_SLAVE_SIG_INACT, sdd->regs + S3C64XX_SPI_SLAVE_SEL); | ||
715 | } | 702 | } |
716 | 703 | ||
717 | static void s3c64xx_spi_config(struct s3c64xx_spi_driver_data *sdd) | 704 | static void s3c64xx_spi_config(struct s3c64xx_spi_driver_data *sdd) |
@@ -927,6 +914,9 @@ static int s3c64xx_spi_transfer_one_message(struct spi_master *master, | |||
927 | s3c64xx_spi_config(sdd); | 914 | s3c64xx_spi_config(sdd); |
928 | } | 915 | } |
929 | 916 | ||
917 | /* Slave Select */ | ||
918 | enable_cs(sdd, spi); | ||
919 | |||
930 | /* Polling method for xfers not bigger than FIFO capacity */ | 920 | /* Polling method for xfers not bigger than FIFO capacity */ |
931 | use_dma = 0; | 921 | use_dma = 0; |
932 | if (!is_polling(sdd) && | 922 | if (!is_polling(sdd) && |
@@ -942,8 +932,11 @@ static int s3c64xx_spi_transfer_one_message(struct spi_master *master, | |||
942 | 932 | ||
943 | enable_datapath(sdd, spi, xfer, use_dma); | 933 | enable_datapath(sdd, spi, xfer, use_dma); |
944 | 934 | ||
945 | /* Slave Select */ | 935 | /* Start the signals */ |
946 | enable_cs(sdd, spi); | 936 | writel(0, sdd->regs + S3C64XX_SPI_SLAVE_SEL); |
937 | |||
938 | /* Start the signals */ | ||
939 | writel(0, sdd->regs + S3C64XX_SPI_SLAVE_SEL); | ||
947 | 940 | ||
948 | spin_unlock_irqrestore(&sdd->lock, flags); | 941 | spin_unlock_irqrestore(&sdd->lock, flags); |
949 | 942 | ||
@@ -968,6 +961,8 @@ static int s3c64xx_spi_transfer_one_message(struct spi_master *master, | |||
968 | goto out; | 961 | goto out; |
969 | } | 962 | } |
970 | 963 | ||
964 | flush_fifo(sdd); | ||
965 | |||
971 | if (xfer->delay_usecs) | 966 | if (xfer->delay_usecs) |
972 | udelay(xfer->delay_usecs); | 967 | udelay(xfer->delay_usecs); |
973 | 968 | ||
@@ -980,15 +975,17 @@ static int s3c64xx_spi_transfer_one_message(struct spi_master *master, | |||
980 | } | 975 | } |
981 | 976 | ||
982 | msg->actual_length += xfer->len; | 977 | msg->actual_length += xfer->len; |
983 | |||
984 | flush_fifo(sdd); | ||
985 | } | 978 | } |
986 | 979 | ||
987 | out: | 980 | out: |
988 | if (!cs_toggle || status) | 981 | if (!cs_toggle || status) { |
982 | /* Quiese the signals */ | ||
983 | writel(S3C64XX_SPI_SLAVE_SIG_INACT, | ||
984 | sdd->regs + S3C64XX_SPI_SLAVE_SEL); | ||
989 | disable_cs(sdd, spi); | 985 | disable_cs(sdd, spi); |
990 | else | 986 | } else { |
991 | sdd->tgl_spi = spi; | 987 | sdd->tgl_spi = spi; |
988 | } | ||
992 | 989 | ||
993 | s3c64xx_spi_unmap_mssg(sdd, msg); | 990 | s3c64xx_spi_unmap_mssg(sdd, msg); |
994 | 991 | ||
@@ -1089,6 +1086,8 @@ static int s3c64xx_spi_setup(struct spi_device *spi) | |||
1089 | cs->line, err); | 1086 | cs->line, err); |
1090 | goto err_gpio_req; | 1087 | goto err_gpio_req; |
1091 | } | 1088 | } |
1089 | |||
1090 | spi->cs_gpio = cs->line; | ||
1092 | } | 1091 | } |
1093 | 1092 | ||
1094 | spi_set_ctldata(spi, cs); | 1093 | spi_set_ctldata(spi, cs); |
@@ -1135,11 +1134,13 @@ static int s3c64xx_spi_setup(struct spi_device *spi) | |||
1135 | } | 1134 | } |
1136 | 1135 | ||
1137 | pm_runtime_put(&sdd->pdev->dev); | 1136 | pm_runtime_put(&sdd->pdev->dev); |
1137 | writel(S3C64XX_SPI_SLAVE_SIG_INACT, sdd->regs + S3C64XX_SPI_SLAVE_SEL); | ||
1138 | disable_cs(sdd, spi); | 1138 | disable_cs(sdd, spi); |
1139 | return 0; | 1139 | return 0; |
1140 | 1140 | ||
1141 | setup_exit: | 1141 | setup_exit: |
1142 | /* setup() returns with device de-selected */ | 1142 | /* setup() returns with device de-selected */ |
1143 | writel(S3C64XX_SPI_SLAVE_SIG_INACT, sdd->regs + S3C64XX_SPI_SLAVE_SEL); | ||
1143 | disable_cs(sdd, spi); | 1144 | disable_cs(sdd, spi); |
1144 | 1145 | ||
1145 | gpio_free(cs->line); | 1146 | gpio_free(cs->line); |
@@ -1158,8 +1159,8 @@ static void s3c64xx_spi_cleanup(struct spi_device *spi) | |||
1158 | struct s3c64xx_spi_driver_data *sdd; | 1159 | struct s3c64xx_spi_driver_data *sdd; |
1159 | 1160 | ||
1160 | sdd = spi_master_get_devdata(spi->master); | 1161 | sdd = spi_master_get_devdata(spi->master); |
1161 | if (cs && sdd->cs_gpio) { | 1162 | if (spi->cs_gpio) { |
1162 | gpio_free(cs->line); | 1163 | gpio_free(spi->cs_gpio); |
1163 | if (spi->dev.of_node) | 1164 | if (spi->dev.of_node) |
1164 | kfree(cs); | 1165 | kfree(cs); |
1165 | } | 1166 | } |
@@ -1448,9 +1449,11 @@ static int s3c64xx_spi_probe(struct platform_device *pdev) | |||
1448 | S3C64XX_SPI_INT_TX_OVERRUN_EN | S3C64XX_SPI_INT_TX_UNDERRUN_EN, | 1449 | S3C64XX_SPI_INT_TX_OVERRUN_EN | S3C64XX_SPI_INT_TX_UNDERRUN_EN, |
1449 | sdd->regs + S3C64XX_SPI_INT_EN); | 1450 | sdd->regs + S3C64XX_SPI_INT_EN); |
1450 | 1451 | ||
1451 | if (spi_register_master(master)) { | 1452 | pm_runtime_enable(&pdev->dev); |
1452 | dev_err(&pdev->dev, "cannot register SPI master\n"); | 1453 | |
1453 | ret = -EBUSY; | 1454 | ret = devm_spi_register_master(&pdev->dev, master); |
1455 | if (ret != 0) { | ||
1456 | dev_err(&pdev->dev, "cannot register SPI master: %d\n", ret); | ||
1454 | goto err3; | 1457 | goto err3; |
1455 | } | 1458 | } |
1456 | 1459 | ||
@@ -1460,8 +1463,6 @@ static int s3c64xx_spi_probe(struct platform_device *pdev) | |||
1460 | mem_res, | 1463 | mem_res, |
1461 | sdd->rx_dma.dmach, sdd->tx_dma.dmach); | 1464 | sdd->rx_dma.dmach, sdd->tx_dma.dmach); |
1462 | 1465 | ||
1463 | pm_runtime_enable(&pdev->dev); | ||
1464 | |||
1465 | return 0; | 1466 | return 0; |
1466 | 1467 | ||
1467 | err3: | 1468 | err3: |
@@ -1481,16 +1482,12 @@ static int s3c64xx_spi_remove(struct platform_device *pdev) | |||
1481 | 1482 | ||
1482 | pm_runtime_disable(&pdev->dev); | 1483 | pm_runtime_disable(&pdev->dev); |
1483 | 1484 | ||
1484 | spi_unregister_master(master); | ||
1485 | |||
1486 | writel(0, sdd->regs + S3C64XX_SPI_INT_EN); | 1485 | writel(0, sdd->regs + S3C64XX_SPI_INT_EN); |
1487 | 1486 | ||
1488 | clk_disable_unprepare(sdd->src_clk); | 1487 | clk_disable_unprepare(sdd->src_clk); |
1489 | 1488 | ||
1490 | clk_disable_unprepare(sdd->clk); | 1489 | clk_disable_unprepare(sdd->clk); |
1491 | 1490 | ||
1492 | spi_master_put(master); | ||
1493 | |||
1494 | return 0; | 1491 | return 0; |
1495 | } | 1492 | } |
1496 | 1493 | ||
@@ -1548,9 +1545,17 @@ static int s3c64xx_spi_runtime_resume(struct device *dev) | |||
1548 | { | 1545 | { |
1549 | struct spi_master *master = dev_get_drvdata(dev); | 1546 | struct spi_master *master = dev_get_drvdata(dev); |
1550 | struct s3c64xx_spi_driver_data *sdd = spi_master_get_devdata(master); | 1547 | struct s3c64xx_spi_driver_data *sdd = spi_master_get_devdata(master); |
1548 | int ret; | ||
1551 | 1549 | ||
1552 | clk_prepare_enable(sdd->src_clk); | 1550 | ret = clk_prepare_enable(sdd->src_clk); |
1553 | clk_prepare_enable(sdd->clk); | 1551 | if (ret != 0) |
1552 | return ret; | ||
1553 | |||
1554 | ret = clk_prepare_enable(sdd->clk); | ||
1555 | if (ret != 0) { | ||
1556 | clk_disable_unprepare(sdd->src_clk); | ||
1557 | return ret; | ||
1558 | } | ||
1554 | 1559 | ||
1555 | return 0; | 1560 | return 0; |
1556 | } | 1561 | } |
@@ -1636,6 +1641,18 @@ static struct platform_device_id s3c64xx_spi_driver_ids[] = { | |||
1636 | }; | 1641 | }; |
1637 | 1642 | ||
1638 | static const struct of_device_id s3c64xx_spi_dt_match[] = { | 1643 | static const struct of_device_id s3c64xx_spi_dt_match[] = { |
1644 | { .compatible = "samsung,s3c2443-spi", | ||
1645 | .data = (void *)&s3c2443_spi_port_config, | ||
1646 | }, | ||
1647 | { .compatible = "samsung,s3c6410-spi", | ||
1648 | .data = (void *)&s3c6410_spi_port_config, | ||
1649 | }, | ||
1650 | { .compatible = "samsung,s5pc100-spi", | ||
1651 | .data = (void *)&s5pc100_spi_port_config, | ||
1652 | }, | ||
1653 | { .compatible = "samsung,s5pv210-spi", | ||
1654 | .data = (void *)&s5pv210_spi_port_config, | ||
1655 | }, | ||
1639 | { .compatible = "samsung,exynos4210-spi", | 1656 | { .compatible = "samsung,exynos4210-spi", |
1640 | .data = (void *)&exynos4_spi_port_config, | 1657 | .data = (void *)&exynos4_spi_port_config, |
1641 | }, | 1658 | }, |
@@ -1653,22 +1670,13 @@ static struct platform_driver s3c64xx_spi_driver = { | |||
1653 | .pm = &s3c64xx_spi_pm, | 1670 | .pm = &s3c64xx_spi_pm, |
1654 | .of_match_table = of_match_ptr(s3c64xx_spi_dt_match), | 1671 | .of_match_table = of_match_ptr(s3c64xx_spi_dt_match), |
1655 | }, | 1672 | }, |
1673 | .probe = s3c64xx_spi_probe, | ||
1656 | .remove = s3c64xx_spi_remove, | 1674 | .remove = s3c64xx_spi_remove, |
1657 | .id_table = s3c64xx_spi_driver_ids, | 1675 | .id_table = s3c64xx_spi_driver_ids, |
1658 | }; | 1676 | }; |
1659 | MODULE_ALIAS("platform:s3c64xx-spi"); | 1677 | MODULE_ALIAS("platform:s3c64xx-spi"); |
1660 | 1678 | ||
1661 | static int __init s3c64xx_spi_init(void) | 1679 | module_platform_driver(s3c64xx_spi_driver); |
1662 | { | ||
1663 | return platform_driver_probe(&s3c64xx_spi_driver, s3c64xx_spi_probe); | ||
1664 | } | ||
1665 | subsys_initcall(s3c64xx_spi_init); | ||
1666 | |||
1667 | static void __exit s3c64xx_spi_exit(void) | ||
1668 | { | ||
1669 | platform_driver_unregister(&s3c64xx_spi_driver); | ||
1670 | } | ||
1671 | module_exit(s3c64xx_spi_exit); | ||
1672 | 1680 | ||
1673 | MODULE_AUTHOR("Jaswinder Singh <jassi.brar@samsung.com>"); | 1681 | MODULE_AUTHOR("Jaswinder Singh <jassi.brar@samsung.com>"); |
1674 | MODULE_DESCRIPTION("S3C64XX SPI Controller Driver"); | 1682 | MODULE_DESCRIPTION("S3C64XX SPI Controller Driver"); |
diff --git a/drivers/spi/spi.c b/drivers/spi/spi.c index 85c18d8a86b3..f37356c26b7d 100644 --- a/drivers/spi/spi.c +++ b/drivers/spi/spi.c | |||
@@ -1370,6 +1370,41 @@ done: | |||
1370 | } | 1370 | } |
1371 | EXPORT_SYMBOL_GPL(spi_register_master); | 1371 | EXPORT_SYMBOL_GPL(spi_register_master); |
1372 | 1372 | ||
1373 | static void devm_spi_unregister(struct device *dev, void *res) | ||
1374 | { | ||
1375 | spi_unregister_master(*(struct spi_master **)res); | ||
1376 | } | ||
1377 | |||
1378 | /** | ||
1379 | * dev_spi_register_master - register managed SPI master controller | ||
1380 | * @dev: device managing SPI master | ||
1381 | * @master: initialized master, originally from spi_alloc_master() | ||
1382 | * Context: can sleep | ||
1383 | * | ||
1384 | * Register a SPI device as with spi_register_master() which will | ||
1385 | * automatically be unregister | ||
1386 | */ | ||
1387 | int devm_spi_register_master(struct device *dev, struct spi_master *master) | ||
1388 | { | ||
1389 | struct spi_master **ptr; | ||
1390 | int ret; | ||
1391 | |||
1392 | ptr = devres_alloc(devm_spi_unregister, sizeof(*ptr), GFP_KERNEL); | ||
1393 | if (!ptr) | ||
1394 | return -ENOMEM; | ||
1395 | |||
1396 | ret = spi_register_master(master); | ||
1397 | if (ret != 0) { | ||
1398 | *ptr = master; | ||
1399 | devres_add(dev, ptr); | ||
1400 | } else { | ||
1401 | devres_free(ptr); | ||
1402 | } | ||
1403 | |||
1404 | return ret; | ||
1405 | } | ||
1406 | EXPORT_SYMBOL_GPL(devm_spi_register_master); | ||
1407 | |||
1373 | static int __unregister(struct device *dev, void *null) | 1408 | static int __unregister(struct device *dev, void *null) |
1374 | { | 1409 | { |
1375 | spi_unregister_device(to_spi_device(dev)); | 1410 | spi_unregister_device(to_spi_device(dev)); |