diff options
author | Adrian Hunter <adrian.hunter@intel.com> | 2011-08-29 09:42:13 -0400 |
---|---|---|
committer | Chris Ball <cjb@laptop.org> | 2011-10-26 16:32:07 -0400 |
commit | 0f2016558e4f9a8d2f9b1202064915205f4dd450 (patch) | |
tree | 2b42e80f7de9b018b7c4867d3ae51d8b7981b602 /drivers/mmc/host/sdhci-pci.c | |
parent | 20758b66dce76af0527363186f44b464d83e5666 (diff) |
mmc: sdhci-pci: add eMMC hardware reset support
Implement eMMC hardware reset for Medfield.
Signed-off-by: Adrian Hunter <adrian.hunter@intel.com>
Signed-off-by: Chris Ball <cjb@laptop.org>
Diffstat (limited to 'drivers/mmc/host/sdhci-pci.c')
-rw-r--r-- | drivers/mmc/host/sdhci-pci.c | 72 |
1 files changed, 72 insertions, 0 deletions
diff --git a/drivers/mmc/host/sdhci-pci.c b/drivers/mmc/host/sdhci-pci.c index 26c528648f3c..3b30c515cbc2 100644 --- a/drivers/mmc/host/sdhci-pci.c +++ b/drivers/mmc/host/sdhci-pci.c | |||
@@ -21,6 +21,8 @@ | |||
21 | #include <linux/mmc/host.h> | 21 | #include <linux/mmc/host.h> |
22 | #include <linux/scatterlist.h> | 22 | #include <linux/scatterlist.h> |
23 | #include <linux/io.h> | 23 | #include <linux/io.h> |
24 | #include <linux/gpio.h> | ||
25 | #include <linux/sfi.h> | ||
24 | 26 | ||
25 | #include "sdhci.h" | 27 | #include "sdhci.h" |
26 | 28 | ||
@@ -59,6 +61,7 @@ struct sdhci_pci_slot { | |||
59 | struct sdhci_host *host; | 61 | struct sdhci_host *host; |
60 | 62 | ||
61 | int pci_bar; | 63 | int pci_bar; |
64 | int rst_n_gpio; | ||
62 | }; | 65 | }; |
63 | 66 | ||
64 | struct sdhci_pci_chip { | 67 | struct sdhci_pci_chip { |
@@ -163,12 +166,63 @@ static int mrst_hc_probe(struct sdhci_pci_chip *chip) | |||
163 | return 0; | 166 | return 0; |
164 | } | 167 | } |
165 | 168 | ||
169 | /* Medfield eMMC hardware reset GPIOs */ | ||
170 | static int mfd_emmc0_rst_gpio = -EINVAL; | ||
171 | static int mfd_emmc1_rst_gpio = -EINVAL; | ||
172 | |||
173 | static int mfd_emmc_gpio_parse(struct sfi_table_header *table) | ||
174 | { | ||
175 | struct sfi_table_simple *sb = (struct sfi_table_simple *)table; | ||
176 | struct sfi_gpio_table_entry *entry; | ||
177 | int i, num; | ||
178 | |||
179 | num = SFI_GET_NUM_ENTRIES(sb, struct sfi_gpio_table_entry); | ||
180 | entry = (struct sfi_gpio_table_entry *)sb->pentry; | ||
181 | |||
182 | for (i = 0; i < num; i++, entry++) { | ||
183 | if (!strncmp(entry->pin_name, "emmc0_rst", SFI_NAME_LEN)) | ||
184 | mfd_emmc0_rst_gpio = entry->pin_no; | ||
185 | else if (!strncmp(entry->pin_name, "emmc1_rst", SFI_NAME_LEN)) | ||
186 | mfd_emmc1_rst_gpio = entry->pin_no; | ||
187 | } | ||
188 | |||
189 | return 0; | ||
190 | } | ||
191 | |||
166 | static int mfd_emmc_probe_slot(struct sdhci_pci_slot *slot) | 192 | static int mfd_emmc_probe_slot(struct sdhci_pci_slot *slot) |
167 | { | 193 | { |
194 | const char *name = NULL; | ||
195 | int gpio = -EINVAL; | ||
196 | |||
197 | sfi_table_parse(SFI_SIG_GPIO, NULL, NULL, mfd_emmc_gpio_parse); | ||
198 | |||
199 | switch (slot->chip->pdev->device) { | ||
200 | case PCI_DEVICE_ID_INTEL_MFD_EMMC0: | ||
201 | gpio = mfd_emmc0_rst_gpio; | ||
202 | name = "eMMC0_reset"; | ||
203 | break; | ||
204 | case PCI_DEVICE_ID_INTEL_MFD_EMMC1: | ||
205 | gpio = mfd_emmc1_rst_gpio; | ||
206 | name = "eMMC1_reset"; | ||
207 | break; | ||
208 | } | ||
209 | |||
210 | if (!gpio_request(gpio, name)) { | ||
211 | gpio_direction_output(gpio, 1); | ||
212 | slot->rst_n_gpio = gpio; | ||
213 | slot->host->mmc->caps |= MMC_CAP_HW_RESET; | ||
214 | } | ||
215 | |||
168 | slot->host->mmc->caps |= MMC_CAP_8_BIT_DATA; | 216 | slot->host->mmc->caps |= MMC_CAP_8_BIT_DATA; |
217 | |||
169 | return 0; | 218 | return 0; |
170 | } | 219 | } |
171 | 220 | ||
221 | static void mfd_emmc_remove_slot(struct sdhci_pci_slot *slot, int dead) | ||
222 | { | ||
223 | gpio_free(slot->rst_n_gpio); | ||
224 | } | ||
225 | |||
172 | static const struct sdhci_pci_fixes sdhci_intel_mrst_hc0 = { | 226 | static const struct sdhci_pci_fixes sdhci_intel_mrst_hc0 = { |
173 | .quirks = SDHCI_QUIRK_BROKEN_ADMA | SDHCI_QUIRK_NO_HISPD_BIT, | 227 | .quirks = SDHCI_QUIRK_BROKEN_ADMA | SDHCI_QUIRK_NO_HISPD_BIT, |
174 | .probe_slot = mrst_hc_probe_slot, | 228 | .probe_slot = mrst_hc_probe_slot, |
@@ -190,6 +244,7 @@ static const struct sdhci_pci_fixes sdhci_intel_mfd_sdio = { | |||
190 | static const struct sdhci_pci_fixes sdhci_intel_mfd_emmc = { | 244 | static const struct sdhci_pci_fixes sdhci_intel_mfd_emmc = { |
191 | .quirks = SDHCI_QUIRK_NO_ENDATTR_IN_NOPDESC, | 245 | .quirks = SDHCI_QUIRK_NO_ENDATTR_IN_NOPDESC, |
192 | .probe_slot = mfd_emmc_probe_slot, | 246 | .probe_slot = mfd_emmc_probe_slot, |
247 | .remove_slot = mfd_emmc_remove_slot, | ||
193 | }; | 248 | }; |
194 | 249 | ||
195 | /* O2Micro extra registers */ | 250 | /* O2Micro extra registers */ |
@@ -832,9 +887,25 @@ static int sdhci_pci_8bit_width(struct sdhci_host *host, int width) | |||
832 | return 0; | 887 | return 0; |
833 | } | 888 | } |
834 | 889 | ||
890 | static void sdhci_pci_hw_reset(struct sdhci_host *host) | ||
891 | { | ||
892 | struct sdhci_pci_slot *slot = sdhci_priv(host); | ||
893 | int rst_n_gpio = slot->rst_n_gpio; | ||
894 | |||
895 | if (!gpio_is_valid(rst_n_gpio)) | ||
896 | return; | ||
897 | gpio_set_value_cansleep(rst_n_gpio, 0); | ||
898 | /* For eMMC, minimum is 1us but give it 10us for good measure */ | ||
899 | udelay(10); | ||
900 | gpio_set_value_cansleep(rst_n_gpio, 1); | ||
901 | /* For eMMC, minimum is 200us but give it 300us for good measure */ | ||
902 | usleep_range(300, 1000); | ||
903 | } | ||
904 | |||
835 | static struct sdhci_ops sdhci_pci_ops = { | 905 | static struct sdhci_ops sdhci_pci_ops = { |
836 | .enable_dma = sdhci_pci_enable_dma, | 906 | .enable_dma = sdhci_pci_enable_dma, |
837 | .platform_8bit_width = sdhci_pci_8bit_width, | 907 | .platform_8bit_width = sdhci_pci_8bit_width, |
908 | .hw_reset = sdhci_pci_hw_reset, | ||
838 | }; | 909 | }; |
839 | 910 | ||
840 | /*****************************************************************************\ | 911 | /*****************************************************************************\ |
@@ -988,6 +1059,7 @@ static struct sdhci_pci_slot * __devinit sdhci_pci_probe_slot( | |||
988 | slot->chip = chip; | 1059 | slot->chip = chip; |
989 | slot->host = host; | 1060 | slot->host = host; |
990 | slot->pci_bar = bar; | 1061 | slot->pci_bar = bar; |
1062 | slot->rst_n_gpio = -EINVAL; | ||
991 | 1063 | ||
992 | host->hw_name = "PCI"; | 1064 | host->hw_name = "PCI"; |
993 | host->ops = &sdhci_pci_ops; | 1065 | host->ops = &sdhci_pci_ops; |