diff options
author | Doug Anderson <dianders@chromium.org> | 2013-01-11 12:03:53 -0500 |
---|---|---|
committer | Chris Ball <cjb@laptop.org> | 2013-02-24 14:36:54 -0500 |
commit | 55a6ceb2d5b845f198bcd76aa18910e05a47d0c2 (patch) | |
tree | ba8cb0a33243bb78418bb2eb5f0a79bfcf6bf037 | |
parent | 07b240411f1e7528ed36e09979f40ccf4b844c8c (diff) |
mmc: dw_mmc: Handle wp-gpios from device tree
On some SoCs (like exynos5250) you need to use an external GPIO for
write protect. Add support for wp-gpios to the core dw_mmc driver
since it could be useful across multiple SoCs.
With this change I am able to make use of the write protect for the
external SD slot on exynos5250-snow.
Signed-off-by: Doug Anderson <dianders@chromium.org>
Acked-by: Seungwon Jeon <tgih.jun@samsung.com>
Acked-by: Olof Johansson <olof@lixom.net>
Signed-off-by: Chris Ball <cjb@laptop.org>
-rw-r--r-- | drivers/mmc/host/dw_mmc.c | 34 |
1 files changed, 34 insertions, 0 deletions
diff --git a/drivers/mmc/host/dw_mmc.c b/drivers/mmc/host/dw_mmc.c index 90f7d990551b..df6207909fe7 100644 --- a/drivers/mmc/host/dw_mmc.c +++ b/drivers/mmc/host/dw_mmc.c | |||
@@ -34,6 +34,7 @@ | |||
34 | #include <linux/regulator/consumer.h> | 34 | #include <linux/regulator/consumer.h> |
35 | #include <linux/workqueue.h> | 35 | #include <linux/workqueue.h> |
36 | #include <linux/of.h> | 36 | #include <linux/of.h> |
37 | #include <linux/of_gpio.h> | ||
37 | 38 | ||
38 | #include "dw_mmc.h" | 39 | #include "dw_mmc.h" |
39 | 40 | ||
@@ -75,6 +76,7 @@ struct idmac_desc { | |||
75 | * @mmc: The mmc_host representing this slot. | 76 | * @mmc: The mmc_host representing this slot. |
76 | * @host: The MMC controller this slot is using. | 77 | * @host: The MMC controller this slot is using. |
77 | * @quirks: Slot-level quirks (DW_MCI_SLOT_QUIRK_XXX) | 78 | * @quirks: Slot-level quirks (DW_MCI_SLOT_QUIRK_XXX) |
79 | * @wp_gpio: If gpio_is_valid() we'll use this to read write protect. | ||
78 | * @ctype: Card type for this slot. | 80 | * @ctype: Card type for this slot. |
79 | * @mrq: mmc_request currently being processed or waiting to be | 81 | * @mrq: mmc_request currently being processed or waiting to be |
80 | * processed, or NULL when the slot is idle. | 82 | * processed, or NULL when the slot is idle. |
@@ -90,6 +92,7 @@ struct dw_mci_slot { | |||
90 | struct dw_mci *host; | 92 | struct dw_mci *host; |
91 | 93 | ||
92 | int quirks; | 94 | int quirks; |
95 | int wp_gpio; | ||
93 | 96 | ||
94 | u32 ctype; | 97 | u32 ctype; |
95 | 98 | ||
@@ -838,6 +841,8 @@ static int dw_mci_get_ro(struct mmc_host *mmc) | |||
838 | read_only = 0; | 841 | read_only = 0; |
839 | else if (brd->get_ro) | 842 | else if (brd->get_ro) |
840 | read_only = brd->get_ro(slot->id); | 843 | read_only = brd->get_ro(slot->id); |
844 | else if (gpio_is_valid(slot->wp_gpio)) | ||
845 | read_only = gpio_get_value(slot->wp_gpio); | ||
841 | else | 846 | else |
842 | read_only = | 847 | read_only = |
843 | mci_readl(slot->host, WRTPRT) & (1 << slot->id) ? 1 : 0; | 848 | mci_readl(slot->host, WRTPRT) & (1 << slot->id) ? 1 : 0; |
@@ -1832,6 +1837,29 @@ static u32 dw_mci_of_get_bus_wd(struct device *dev, u8 slot) | |||
1832 | " as 1\n"); | 1837 | " as 1\n"); |
1833 | return bus_wd; | 1838 | return bus_wd; |
1834 | } | 1839 | } |
1840 | |||
1841 | /* find the write protect gpio for a given slot; or -1 if none specified */ | ||
1842 | static int dw_mci_of_get_wp_gpio(struct device *dev, u8 slot) | ||
1843 | { | ||
1844 | struct device_node *np = dw_mci_of_find_slot_node(dev, slot); | ||
1845 | int gpio; | ||
1846 | |||
1847 | if (!np) | ||
1848 | return -EINVAL; | ||
1849 | |||
1850 | gpio = of_get_named_gpio(np, "wp-gpios", 0); | ||
1851 | |||
1852 | /* Having a missing entry is valid; return silently */ | ||
1853 | if (!gpio_is_valid(gpio)) | ||
1854 | return -EINVAL; | ||
1855 | |||
1856 | if (devm_gpio_request(dev, gpio, "dw-mci-wp")) { | ||
1857 | dev_warn(dev, "gpio [%d] request failed\n", gpio); | ||
1858 | return -EINVAL; | ||
1859 | } | ||
1860 | |||
1861 | return gpio; | ||
1862 | } | ||
1835 | #else /* CONFIG_OF */ | 1863 | #else /* CONFIG_OF */ |
1836 | static int dw_mci_of_get_slot_quirks(struct device *dev, u8 slot) | 1864 | static int dw_mci_of_get_slot_quirks(struct device *dev, u8 slot) |
1837 | { | 1865 | { |
@@ -1845,6 +1873,10 @@ static struct device_node *dw_mci_of_find_slot_node(struct device *dev, u8 slot) | |||
1845 | { | 1873 | { |
1846 | return NULL; | 1874 | return NULL; |
1847 | } | 1875 | } |
1876 | static int dw_mci_of_get_wp_gpio(struct device *dev, u8 slot) | ||
1877 | { | ||
1878 | return -EINVAL; | ||
1879 | } | ||
1848 | #endif /* CONFIG_OF */ | 1880 | #endif /* CONFIG_OF */ |
1849 | 1881 | ||
1850 | static int dw_mci_init_slot(struct dw_mci *host, unsigned int id) | 1882 | static int dw_mci_init_slot(struct dw_mci *host, unsigned int id) |
@@ -1962,6 +1994,8 @@ static int dw_mci_init_slot(struct dw_mci *host, unsigned int id) | |||
1962 | else | 1994 | else |
1963 | clear_bit(DW_MMC_CARD_PRESENT, &slot->flags); | 1995 | clear_bit(DW_MMC_CARD_PRESENT, &slot->flags); |
1964 | 1996 | ||
1997 | slot->wp_gpio = dw_mci_of_get_wp_gpio(host->dev, slot->id); | ||
1998 | |||
1965 | mmc_add_host(mmc); | 1999 | mmc_add_host(mmc); |
1966 | 2000 | ||
1967 | #if defined(CONFIG_DEBUG_FS) | 2001 | #if defined(CONFIG_DEBUG_FS) |