diff options
author | Thomas Petazzoni <thomas.petazzoni@free-electrons.com> | 2013-01-16 08:13:59 -0500 |
---|---|---|
committer | Chris Ball <cjb@laptop.org> | 2013-02-11 13:28:54 -0500 |
commit | 111936ff3bc33585b475c1033fc98cd6b3370a74 (patch) | |
tree | c561cf4562672e29145bb16faff448639e18e259 | |
parent | 07728b77c03dc0721daaf551976d95e6f714af1a (diff) |
mmc: mvsdio: implement a Device Tree binding
This patch adds a simple Device Tree binding for the mvsdio driver, as
well as the necessary documentation for it. Compatibility with non-DT
platforms is preserved, by keeping the platform_data based
initialization.
We introduce a small difference between non-DT and DT platforms: DT
platforms are required to provide a clocks = <...> property, which the
driver uses to get the frequency of the clock that goes to the SDIO
IP. The behaviour on non-DT platforms is kept unchanged: a clock
reference is not mandatory, but the clock frequency must be passed in
the "clock" field of the mvsdio_platform_data structure.
Signed-off-by: Thomas Petazzoni <thomas.petazzoni@free-electrons.com>
Signed-off-by: Andrew Lunn <andrew@lunn.ch>
Tested-by: Stefan Peter <s.peter@mpl.ch>
Tested-by: Florian Fainelli <florian@openwrt.org>
Signed-off-by: Jason Cooper <jason@lakedaemon.net>
Signed-off-by: Chris Ball <cjb@laptop.org>
-rw-r--r-- | Documentation/devicetree/bindings/mmc/orion-sdio.txt | 17 | ||||
-rw-r--r-- | drivers/mmc/host/mvsdio.c | 64 |
2 files changed, 66 insertions, 15 deletions
diff --git a/Documentation/devicetree/bindings/mmc/orion-sdio.txt b/Documentation/devicetree/bindings/mmc/orion-sdio.txt new file mode 100644 index 000000000000..84f0ebd67a13 --- /dev/null +++ b/Documentation/devicetree/bindings/mmc/orion-sdio.txt | |||
@@ -0,0 +1,17 @@ | |||
1 | * Marvell orion-sdio controller | ||
2 | |||
3 | This file documents differences between the core properties in mmc.txt | ||
4 | and the properties used by the orion-sdio driver. | ||
5 | |||
6 | - compatible: Should be "marvell,orion-sdio" | ||
7 | - clocks: reference to the clock of the SDIO interface | ||
8 | |||
9 | Example: | ||
10 | |||
11 | mvsdio@d00d4000 { | ||
12 | compatible = "marvell,orion-sdio"; | ||
13 | reg = <0xd00d4000 0x200>; | ||
14 | interrupts = <54>; | ||
15 | clocks = <&gateclk 17>; | ||
16 | status = "disabled"; | ||
17 | }; | ||
diff --git a/drivers/mmc/host/mvsdio.c b/drivers/mmc/host/mvsdio.c index 704b7a3fe873..78d3abf837c2 100644 --- a/drivers/mmc/host/mvsdio.c +++ b/drivers/mmc/host/mvsdio.c | |||
@@ -21,6 +21,8 @@ | |||
21 | #include <linux/irq.h> | 21 | #include <linux/irq.h> |
22 | #include <linux/clk.h> | 22 | #include <linux/clk.h> |
23 | #include <linux/gpio.h> | 23 | #include <linux/gpio.h> |
24 | #include <linux/of_gpio.h> | ||
25 | #include <linux/of_irq.h> | ||
24 | #include <linux/mmc/host.h> | 26 | #include <linux/mmc/host.h> |
25 | #include <linux/mmc/slot-gpio.h> | 27 | #include <linux/mmc/slot-gpio.h> |
26 | 28 | ||
@@ -681,17 +683,17 @@ mv_conf_mbus_windows(struct mvsd_host *host, | |||
681 | 683 | ||
682 | static int __init mvsd_probe(struct platform_device *pdev) | 684 | static int __init mvsd_probe(struct platform_device *pdev) |
683 | { | 685 | { |
686 | struct device_node *np = pdev->dev.of_node; | ||
684 | struct mmc_host *mmc = NULL; | 687 | struct mmc_host *mmc = NULL; |
685 | struct mvsd_host *host = NULL; | 688 | struct mvsd_host *host = NULL; |
686 | const struct mvsdio_platform_data *mvsd_data; | ||
687 | const struct mbus_dram_target_info *dram; | 689 | const struct mbus_dram_target_info *dram; |
688 | struct resource *r; | 690 | struct resource *r; |
689 | int ret, irq; | 691 | int ret, irq; |
692 | int gpio_card_detect, gpio_write_protect; | ||
690 | 693 | ||
691 | r = platform_get_resource(pdev, IORESOURCE_MEM, 0); | 694 | r = platform_get_resource(pdev, IORESOURCE_MEM, 0); |
692 | irq = platform_get_irq(pdev, 0); | 695 | irq = platform_get_irq(pdev, 0); |
693 | mvsd_data = pdev->dev.platform_data; | 696 | if (!r || irq < 0) |
694 | if (!r || irq < 0 || !mvsd_data) | ||
695 | return -ENXIO; | 697 | return -ENXIO; |
696 | 698 | ||
697 | mmc = mmc_alloc_host(sizeof(struct mvsd_host), &pdev->dev); | 699 | mmc = mmc_alloc_host(sizeof(struct mvsd_host), &pdev->dev); |
@@ -703,8 +705,39 @@ static int __init mvsd_probe(struct platform_device *pdev) | |||
703 | host = mmc_priv(mmc); | 705 | host = mmc_priv(mmc); |
704 | host->mmc = mmc; | 706 | host->mmc = mmc; |
705 | host->dev = &pdev->dev; | 707 | host->dev = &pdev->dev; |
706 | host->base_clock = mvsd_data->clock / 2; | 708 | |
707 | host->clk = ERR_PTR(-EINVAL); | 709 | /* |
710 | * Some non-DT platforms do not pass a clock, and the clock | ||
711 | * frequency is passed through platform_data. On DT platforms, | ||
712 | * a clock must always be passed, even if there is no gatable | ||
713 | * clock associated to the SDIO interface (it can simply be a | ||
714 | * fixed rate clock). | ||
715 | */ | ||
716 | host->clk = devm_clk_get(&pdev->dev, NULL); | ||
717 | if (!IS_ERR(host->clk)) | ||
718 | clk_prepare_enable(host->clk); | ||
719 | |||
720 | if (np) { | ||
721 | if (IS_ERR(host->clk)) { | ||
722 | dev_err(&pdev->dev, "DT platforms must have a clock associated\n"); | ||
723 | ret = -EINVAL; | ||
724 | goto out; | ||
725 | } | ||
726 | |||
727 | host->base_clock = clk_get_rate(host->clk) / 2; | ||
728 | gpio_card_detect = of_get_named_gpio(np, "cd-gpios", 0); | ||
729 | gpio_write_protect = of_get_named_gpio(np, "wp-gpios", 0); | ||
730 | } else { | ||
731 | const struct mvsdio_platform_data *mvsd_data; | ||
732 | mvsd_data = pdev->dev.platform_data; | ||
733 | if (!mvsd_data) { | ||
734 | ret = -ENXIO; | ||
735 | goto out; | ||
736 | } | ||
737 | host->base_clock = mvsd_data->clock / 2; | ||
738 | gpio_card_detect = mvsd_data->gpio_card_detect; | ||
739 | gpio_write_protect = mvsd_data->gpio_write_protect; | ||
740 | } | ||
708 | 741 | ||
709 | mmc->ops = &mvsd_ops; | 742 | mmc->ops = &mvsd_ops; |
710 | 743 | ||
@@ -743,20 +776,14 @@ static int __init mvsd_probe(struct platform_device *pdev) | |||
743 | goto out; | 776 | goto out; |
744 | } | 777 | } |
745 | 778 | ||
746 | /* Not all platforms can gate the clock, so it is not | 779 | if (gpio_is_valid(gpio_card_detect)) { |
747 | an error if the clock does not exists. */ | 780 | ret = mmc_gpio_request_cd(mmc, gpio_card_detect); |
748 | host->clk = devm_clk_get(&pdev->dev, NULL); | ||
749 | if (!IS_ERR(host->clk)) | ||
750 | clk_prepare_enable(host->clk); | ||
751 | |||
752 | if (gpio_is_valid(mvsd_data->gpio_card_detect)) { | ||
753 | ret = mmc_gpio_request_cd(mmc, mvsd_data->gpio_card_detect); | ||
754 | if (ret) | 781 | if (ret) |
755 | goto out; | 782 | goto out; |
756 | } else | 783 | } else |
757 | mmc->caps |= MMC_CAP_NEEDS_POLL; | 784 | mmc->caps |= MMC_CAP_NEEDS_POLL; |
758 | 785 | ||
759 | mmc_gpio_request_ro(mmc, mvsd_data->gpio_write_protect); | 786 | mmc_gpio_request_ro(mmc, gpio_write_protect); |
760 | 787 | ||
761 | setup_timer(&host->timer, mvsd_timeout_timer, (unsigned long)host); | 788 | setup_timer(&host->timer, mvsd_timeout_timer, (unsigned long)host); |
762 | platform_set_drvdata(pdev, mmc); | 789 | platform_set_drvdata(pdev, mmc); |
@@ -768,7 +795,7 @@ static int __init mvsd_probe(struct platform_device *pdev) | |||
768 | mmc_hostname(mmc), DRIVER_NAME); | 795 | mmc_hostname(mmc), DRIVER_NAME); |
769 | if (!(mmc->caps & MMC_CAP_NEEDS_POLL)) | 796 | if (!(mmc->caps & MMC_CAP_NEEDS_POLL)) |
770 | printk("using GPIO %d for card detection\n", | 797 | printk("using GPIO %d for card detection\n", |
771 | mvsd_data->gpio_card_detect); | 798 | gpio_card_detect); |
772 | else | 799 | else |
773 | printk("lacking card detect (fall back to polling)\n"); | 800 | printk("lacking card detect (fall back to polling)\n"); |
774 | return 0; | 801 | return 0; |
@@ -832,12 +859,19 @@ static int mvsd_resume(struct platform_device *dev) | |||
832 | #define mvsd_resume NULL | 859 | #define mvsd_resume NULL |
833 | #endif | 860 | #endif |
834 | 861 | ||
862 | static const struct of_device_id mvsdio_dt_ids[] = { | ||
863 | { .compatible = "marvell,orion-sdio" }, | ||
864 | { /* sentinel */ } | ||
865 | }; | ||
866 | MODULE_DEVICE_TABLE(of, mvsdio_dt_ids); | ||
867 | |||
835 | static struct platform_driver mvsd_driver = { | 868 | static struct platform_driver mvsd_driver = { |
836 | .remove = __exit_p(mvsd_remove), | 869 | .remove = __exit_p(mvsd_remove), |
837 | .suspend = mvsd_suspend, | 870 | .suspend = mvsd_suspend, |
838 | .resume = mvsd_resume, | 871 | .resume = mvsd_resume, |
839 | .driver = { | 872 | .driver = { |
840 | .name = DRIVER_NAME, | 873 | .name = DRIVER_NAME, |
874 | .of_match_table = mvsdio_dt_ids, | ||
841 | }, | 875 | }, |
842 | }; | 876 | }; |
843 | 877 | ||