1c4e05037SAdrian Hunter /* 2c4e05037SAdrian Hunter * Secure Digital Host Controller Interface ACPI driver. 3c4e05037SAdrian Hunter * 4c4e05037SAdrian Hunter * Copyright (c) 2012, Intel Corporation. 5c4e05037SAdrian Hunter * 6c4e05037SAdrian Hunter * This program is free software; you can redistribute it and/or modify it 7c4e05037SAdrian Hunter * under the terms and conditions of the GNU General Public License, 8c4e05037SAdrian Hunter * version 2, as published by the Free Software Foundation. 9c4e05037SAdrian Hunter * 10c4e05037SAdrian Hunter * This program is distributed in the hope it will be useful, but WITHOUT 11c4e05037SAdrian Hunter * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 12c4e05037SAdrian Hunter * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for 13c4e05037SAdrian Hunter * more details. 14c4e05037SAdrian Hunter * 15c4e05037SAdrian Hunter * You should have received a copy of the GNU General Public License along with 16c4e05037SAdrian Hunter * this program; if not, write to the Free Software Foundation, Inc., 17c4e05037SAdrian Hunter * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. 18c4e05037SAdrian Hunter * 19c4e05037SAdrian Hunter */ 20c4e05037SAdrian Hunter 21c4e05037SAdrian Hunter #include <linux/init.h> 22c4e05037SAdrian Hunter #include <linux/export.h> 23c4e05037SAdrian Hunter #include <linux/module.h> 24c4e05037SAdrian Hunter #include <linux/device.h> 25c4e05037SAdrian Hunter #include <linux/platform_device.h> 26c4e05037SAdrian Hunter #include <linux/ioport.h> 27c4e05037SAdrian Hunter #include <linux/io.h> 28c4e05037SAdrian Hunter #include <linux/dma-mapping.h> 29c4e05037SAdrian Hunter #include <linux/compiler.h> 30c4e05037SAdrian Hunter #include <linux/stddef.h> 31c4e05037SAdrian Hunter #include <linux/bitops.h> 32c4e05037SAdrian Hunter #include <linux/types.h> 33c4e05037SAdrian Hunter #include <linux/err.h> 34c4e05037SAdrian Hunter #include <linux/interrupt.h> 35c4e05037SAdrian Hunter #include <linux/acpi.h> 36c4e05037SAdrian Hunter #include <linux/pm.h> 37c4e05037SAdrian Hunter #include <linux/pm_runtime.h> 38b04fa064SAdrian Hunter #include <linux/delay.h> 39c4e05037SAdrian Hunter 40c4e05037SAdrian Hunter #include <linux/mmc/host.h> 41c4e05037SAdrian Hunter #include <linux/mmc/pm.h> 424fd4409cSAdrian Hunter #include <linux/mmc/slot-gpio.h> 43c4e05037SAdrian Hunter 446e1c7d61SAdrian Hunter #ifdef CONFIG_X86 456e1c7d61SAdrian Hunter #include <asm/cpu_device_id.h> 468ba4cb53SDave Hansen #include <asm/intel-family.h> 476e1c7d61SAdrian Hunter #include <asm/iosf_mbi.h> 4817753d16SAdrian Hunter #include <linux/pci.h> 496e1c7d61SAdrian Hunter #endif 506e1c7d61SAdrian Hunter 51c4e05037SAdrian Hunter #include "sdhci.h" 52c4e05037SAdrian Hunter 53c4e05037SAdrian Hunter enum { 54c4e05037SAdrian Hunter SDHCI_ACPI_SD_CD = BIT(0), 55c4e05037SAdrian Hunter SDHCI_ACPI_RUNTIME_PM = BIT(1), 564fd4409cSAdrian Hunter SDHCI_ACPI_SD_CD_OVERRIDE_LEVEL = BIT(2), 57c4e05037SAdrian Hunter }; 58c4e05037SAdrian Hunter 59c4e05037SAdrian Hunter struct sdhci_acpi_chip { 60c4e05037SAdrian Hunter const struct sdhci_ops *ops; 61c4e05037SAdrian Hunter unsigned int quirks; 62c4e05037SAdrian Hunter unsigned int quirks2; 63c4e05037SAdrian Hunter unsigned long caps; 64c4e05037SAdrian Hunter unsigned int caps2; 65c4e05037SAdrian Hunter mmc_pm_flag_t pm_caps; 66c4e05037SAdrian Hunter }; 67c4e05037SAdrian Hunter 68c4e05037SAdrian Hunter struct sdhci_acpi_slot { 69c4e05037SAdrian Hunter const struct sdhci_acpi_chip *chip; 70c4e05037SAdrian Hunter unsigned int quirks; 71c4e05037SAdrian Hunter unsigned int quirks2; 72c4e05037SAdrian Hunter unsigned long caps; 73c4e05037SAdrian Hunter unsigned int caps2; 74c4e05037SAdrian Hunter mmc_pm_flag_t pm_caps; 75c4e05037SAdrian Hunter unsigned int flags; 76f07b7952SAdrian Hunter size_t priv_size; 777dafca83SAdrian Hunter int (*probe_slot)(struct platform_device *, const char *, const char *); 78578b36b6SGao, Yunpeng int (*remove_slot)(struct platform_device *); 79c4e05037SAdrian Hunter }; 80c4e05037SAdrian Hunter 81c4e05037SAdrian Hunter struct sdhci_acpi_host { 82c4e05037SAdrian Hunter struct sdhci_host *host; 83c4e05037SAdrian Hunter const struct sdhci_acpi_slot *slot; 84c4e05037SAdrian Hunter struct platform_device *pdev; 85c4e05037SAdrian Hunter bool use_runtime_pm; 86f07b7952SAdrian Hunter unsigned long private[0] ____cacheline_aligned; 87c4e05037SAdrian Hunter }; 88c4e05037SAdrian Hunter 89f07b7952SAdrian Hunter static inline void *sdhci_acpi_priv(struct sdhci_acpi_host *c) 90f07b7952SAdrian Hunter { 91f07b7952SAdrian Hunter return (void *)c->private; 92f07b7952SAdrian Hunter } 93f07b7952SAdrian Hunter 94c4e05037SAdrian Hunter static inline bool sdhci_acpi_flag(struct sdhci_acpi_host *c, unsigned int flag) 95c4e05037SAdrian Hunter { 96c4e05037SAdrian Hunter return c->slot && (c->slot->flags & flag); 97c4e05037SAdrian Hunter } 98c4e05037SAdrian Hunter 99b04fa064SAdrian Hunter static void sdhci_acpi_int_hw_reset(struct sdhci_host *host) 100b04fa064SAdrian Hunter { 101b04fa064SAdrian Hunter u8 reg; 102b04fa064SAdrian Hunter 103b04fa064SAdrian Hunter reg = sdhci_readb(host, SDHCI_POWER_CONTROL); 104b04fa064SAdrian Hunter reg |= 0x10; 105b04fa064SAdrian Hunter sdhci_writeb(host, reg, SDHCI_POWER_CONTROL); 106b04fa064SAdrian Hunter /* For eMMC, minimum is 1us but give it 9us for good measure */ 107b04fa064SAdrian Hunter udelay(9); 108b04fa064SAdrian Hunter reg &= ~0x10; 109b04fa064SAdrian Hunter sdhci_writeb(host, reg, SDHCI_POWER_CONTROL); 110b04fa064SAdrian Hunter /* For eMMC, minimum is 200us but give it 300us for good measure */ 111b04fa064SAdrian Hunter usleep_range(300, 1000); 112b04fa064SAdrian Hunter } 113b04fa064SAdrian Hunter 114c4e05037SAdrian Hunter static const struct sdhci_ops sdhci_acpi_ops_dflt = { 1151771059cSRussell King .set_clock = sdhci_set_clock, 1162317f56cSRussell King .set_bus_width = sdhci_set_bus_width, 11703231f9bSRussell King .reset = sdhci_reset, 11896d7b78cSRussell King .set_uhs_signaling = sdhci_set_uhs_signaling, 119c4e05037SAdrian Hunter }; 120c4e05037SAdrian Hunter 121b04fa064SAdrian Hunter static const struct sdhci_ops sdhci_acpi_ops_int = { 1221771059cSRussell King .set_clock = sdhci_set_clock, 1232317f56cSRussell King .set_bus_width = sdhci_set_bus_width, 12403231f9bSRussell King .reset = sdhci_reset, 12596d7b78cSRussell King .set_uhs_signaling = sdhci_set_uhs_signaling, 126b04fa064SAdrian Hunter .hw_reset = sdhci_acpi_int_hw_reset, 127b04fa064SAdrian Hunter }; 128b04fa064SAdrian Hunter 129b04fa064SAdrian Hunter static const struct sdhci_acpi_chip sdhci_acpi_chip_int = { 130b04fa064SAdrian Hunter .ops = &sdhci_acpi_ops_int, 131b04fa064SAdrian Hunter }; 132b04fa064SAdrian Hunter 1336e1c7d61SAdrian Hunter #ifdef CONFIG_X86 1346e1c7d61SAdrian Hunter 1356e1c7d61SAdrian Hunter static bool sdhci_acpi_byt(void) 1366e1c7d61SAdrian Hunter { 1376e1c7d61SAdrian Hunter static const struct x86_cpu_id byt[] = { 1388ba4cb53SDave Hansen { X86_VENDOR_INTEL, 6, INTEL_FAM6_ATOM_SILVERMONT1 }, 1396e1c7d61SAdrian Hunter {} 1406e1c7d61SAdrian Hunter }; 1416e1c7d61SAdrian Hunter 1426e1c7d61SAdrian Hunter return x86_match_cpu(byt); 1436e1c7d61SAdrian Hunter } 1446e1c7d61SAdrian Hunter 14517753d16SAdrian Hunter static bool sdhci_acpi_cht(void) 14617753d16SAdrian Hunter { 14717753d16SAdrian Hunter static const struct x86_cpu_id cht[] = { 14817753d16SAdrian Hunter { X86_VENDOR_INTEL, 6, INTEL_FAM6_ATOM_AIRMONT }, 14917753d16SAdrian Hunter {} 15017753d16SAdrian Hunter }; 15117753d16SAdrian Hunter 15217753d16SAdrian Hunter return x86_match_cpu(cht); 15317753d16SAdrian Hunter } 15417753d16SAdrian Hunter 1556e1c7d61SAdrian Hunter #define BYT_IOSF_SCCEP 0x63 1566e1c7d61SAdrian Hunter #define BYT_IOSF_OCP_NETCTRL0 0x1078 1576e1c7d61SAdrian Hunter #define BYT_IOSF_OCP_TIMEOUT_BASE GENMASK(10, 8) 1586e1c7d61SAdrian Hunter 1596e1c7d61SAdrian Hunter static void sdhci_acpi_byt_setting(struct device *dev) 1606e1c7d61SAdrian Hunter { 1616e1c7d61SAdrian Hunter u32 val = 0; 1626e1c7d61SAdrian Hunter 1636e1c7d61SAdrian Hunter if (!sdhci_acpi_byt()) 1646e1c7d61SAdrian Hunter return; 1656e1c7d61SAdrian Hunter 1666e1c7d61SAdrian Hunter if (iosf_mbi_read(BYT_IOSF_SCCEP, MBI_CR_READ, BYT_IOSF_OCP_NETCTRL0, 1676e1c7d61SAdrian Hunter &val)) { 1686e1c7d61SAdrian Hunter dev_err(dev, "%s read error\n", __func__); 1696e1c7d61SAdrian Hunter return; 1706e1c7d61SAdrian Hunter } 1716e1c7d61SAdrian Hunter 1726e1c7d61SAdrian Hunter if (!(val & BYT_IOSF_OCP_TIMEOUT_BASE)) 1736e1c7d61SAdrian Hunter return; 1746e1c7d61SAdrian Hunter 1756e1c7d61SAdrian Hunter val &= ~BYT_IOSF_OCP_TIMEOUT_BASE; 1766e1c7d61SAdrian Hunter 1776e1c7d61SAdrian Hunter if (iosf_mbi_write(BYT_IOSF_SCCEP, MBI_CR_WRITE, BYT_IOSF_OCP_NETCTRL0, 1786e1c7d61SAdrian Hunter val)) { 1796e1c7d61SAdrian Hunter dev_err(dev, "%s write error\n", __func__); 1806e1c7d61SAdrian Hunter return; 1816e1c7d61SAdrian Hunter } 1826e1c7d61SAdrian Hunter 1836e1c7d61SAdrian Hunter dev_dbg(dev, "%s completed\n", __func__); 1846e1c7d61SAdrian Hunter } 1856e1c7d61SAdrian Hunter 1866e1c7d61SAdrian Hunter static bool sdhci_acpi_byt_defer(struct device *dev) 1876e1c7d61SAdrian Hunter { 1886e1c7d61SAdrian Hunter if (!sdhci_acpi_byt()) 1896e1c7d61SAdrian Hunter return false; 1906e1c7d61SAdrian Hunter 1916e1c7d61SAdrian Hunter if (!iosf_mbi_available()) 1926e1c7d61SAdrian Hunter return true; 1936e1c7d61SAdrian Hunter 1946e1c7d61SAdrian Hunter sdhci_acpi_byt_setting(dev); 1956e1c7d61SAdrian Hunter 1966e1c7d61SAdrian Hunter return false; 1976e1c7d61SAdrian Hunter } 1986e1c7d61SAdrian Hunter 19917753d16SAdrian Hunter static bool sdhci_acpi_cht_pci_wifi(unsigned int vendor, unsigned int device, 20017753d16SAdrian Hunter unsigned int slot, unsigned int parent_slot) 20117753d16SAdrian Hunter { 20217753d16SAdrian Hunter struct pci_dev *dev, *parent, *from = NULL; 20317753d16SAdrian Hunter 20417753d16SAdrian Hunter while (1) { 20517753d16SAdrian Hunter dev = pci_get_device(vendor, device, from); 20617753d16SAdrian Hunter pci_dev_put(from); 20717753d16SAdrian Hunter if (!dev) 20817753d16SAdrian Hunter break; 20917753d16SAdrian Hunter parent = pci_upstream_bridge(dev); 21017753d16SAdrian Hunter if (ACPI_COMPANION(&dev->dev) && PCI_SLOT(dev->devfn) == slot && 21117753d16SAdrian Hunter parent && PCI_SLOT(parent->devfn) == parent_slot && 21217753d16SAdrian Hunter !pci_upstream_bridge(parent)) { 21317753d16SAdrian Hunter pci_dev_put(dev); 21417753d16SAdrian Hunter return true; 21517753d16SAdrian Hunter } 21617753d16SAdrian Hunter from = dev; 21717753d16SAdrian Hunter } 21817753d16SAdrian Hunter 21917753d16SAdrian Hunter return false; 22017753d16SAdrian Hunter } 22117753d16SAdrian Hunter 22217753d16SAdrian Hunter /* 22317753d16SAdrian Hunter * GPDwin uses PCI wifi which conflicts with SDIO's use of 22417753d16SAdrian Hunter * acpi_device_fix_up_power() on child device nodes. Identifying GPDwin is 22517753d16SAdrian Hunter * problematic, but since SDIO is only used for wifi, the presence of the PCI 22617753d16SAdrian Hunter * wifi card in the expected slot with an ACPI companion node, is used to 22717753d16SAdrian Hunter * indicate that acpi_device_fix_up_power() should be avoided. 22817753d16SAdrian Hunter */ 22917753d16SAdrian Hunter static inline bool sdhci_acpi_no_fixup_child_power(const char *hid, 23017753d16SAdrian Hunter const char *uid) 23117753d16SAdrian Hunter { 23217753d16SAdrian Hunter return sdhci_acpi_cht() && 23317753d16SAdrian Hunter !strcmp(hid, "80860F14") && 23417753d16SAdrian Hunter !strcmp(uid, "2") && 23517753d16SAdrian Hunter sdhci_acpi_cht_pci_wifi(0x14e4, 0x43ec, 0, 28); 23617753d16SAdrian Hunter } 23717753d16SAdrian Hunter 2386e1c7d61SAdrian Hunter #else 2396e1c7d61SAdrian Hunter 2406e1c7d61SAdrian Hunter static inline void sdhci_acpi_byt_setting(struct device *dev) 2416e1c7d61SAdrian Hunter { 2426e1c7d61SAdrian Hunter } 2436e1c7d61SAdrian Hunter 2446e1c7d61SAdrian Hunter static inline bool sdhci_acpi_byt_defer(struct device *dev) 2456e1c7d61SAdrian Hunter { 2466e1c7d61SAdrian Hunter return false; 2476e1c7d61SAdrian Hunter } 2486e1c7d61SAdrian Hunter 24917753d16SAdrian Hunter static inline bool sdhci_acpi_no_fixup_child_power(const char *hid, 25017753d16SAdrian Hunter const char *uid) 25117753d16SAdrian Hunter { 25217753d16SAdrian Hunter return false; 25317753d16SAdrian Hunter } 25417753d16SAdrian Hunter 2556e1c7d61SAdrian Hunter #endif 2566e1c7d61SAdrian Hunter 2576a645dd8SAdrian Hunter static int bxt_get_cd(struct mmc_host *mmc) 2586a645dd8SAdrian Hunter { 2596a645dd8SAdrian Hunter int gpio_cd = mmc_gpio_get_cd(mmc); 2606a645dd8SAdrian Hunter struct sdhci_host *host = mmc_priv(mmc); 2616a645dd8SAdrian Hunter unsigned long flags; 2626a645dd8SAdrian Hunter int ret = 0; 2636a645dd8SAdrian Hunter 2646a645dd8SAdrian Hunter if (!gpio_cd) 2656a645dd8SAdrian Hunter return 0; 2666a645dd8SAdrian Hunter 2676a645dd8SAdrian Hunter spin_lock_irqsave(&host->lock, flags); 2686a645dd8SAdrian Hunter 2696a645dd8SAdrian Hunter if (host->flags & SDHCI_DEVICE_DEAD) 2706a645dd8SAdrian Hunter goto out; 2716a645dd8SAdrian Hunter 2726a645dd8SAdrian Hunter ret = !!(sdhci_readl(host, SDHCI_PRESENT_STATE) & SDHCI_CARD_PRESENT); 2736a645dd8SAdrian Hunter out: 2746a645dd8SAdrian Hunter spin_unlock_irqrestore(&host->lock, flags); 2756a645dd8SAdrian Hunter 2766a645dd8SAdrian Hunter return ret; 2776a645dd8SAdrian Hunter } 2786a645dd8SAdrian Hunter 279159cd328SAdrian Hunter static int intel_probe_slot(struct platform_device *pdev, const char *hid, 280159cd328SAdrian Hunter const char *uid) 281578b36b6SGao, Yunpeng { 282578b36b6SGao, Yunpeng struct sdhci_acpi_host *c = platform_get_drvdata(pdev); 283159cd328SAdrian Hunter struct sdhci_host *host = c->host; 284578b36b6SGao, Yunpeng 2858024379eSAdrian Hunter if (hid && uid && !strcmp(hid, "80860F14") && !strcmp(uid, "1") && 2868024379eSAdrian Hunter sdhci_readl(host, SDHCI_CAPABILITIES) == 0x446cc8b2 && 2878024379eSAdrian Hunter sdhci_readl(host, SDHCI_CAPABILITIES_1) == 0x00000807) 2888024379eSAdrian Hunter host->timeout_clk = 1000; /* 1000 kHz i.e. 1 MHz */ 2898024379eSAdrian Hunter 290d3e97407SAzhar Shaikh if (hid && !strcmp(hid, "80865ACA")) 2916a645dd8SAdrian Hunter host->mmc_host_ops.get_cd = bxt_get_cd; 2926a645dd8SAdrian Hunter 293578b36b6SGao, Yunpeng return 0; 294578b36b6SGao, Yunpeng } 295578b36b6SGao, Yunpeng 29607a58883SAdrian Hunter static const struct sdhci_acpi_slot sdhci_acpi_slot_int_emmc = { 297b04fa064SAdrian Hunter .chip = &sdhci_acpi_chip_int, 298f25c3372SMaurice Petallo .caps = MMC_CAP_8_BIT_DATA | MMC_CAP_NONREMOVABLE | 2999d65cb88SAdrian Hunter MMC_CAP_HW_RESET | MMC_CAP_1_8V_DDR | 300c80f275fSAdrian Hunter MMC_CAP_CMD_DURING_TFR | MMC_CAP_WAIT_WHILE_BUSY, 30107a58883SAdrian Hunter .flags = SDHCI_ACPI_RUNTIME_PM, 302e1f5633aSAdrian Hunter .quirks = SDHCI_QUIRK_NO_ENDATTR_IN_NOPDESC, 303e839b134SAdrian Hunter .quirks2 = SDHCI_QUIRK2_PRESET_VALUE_BROKEN | 304e839b134SAdrian Hunter SDHCI_QUIRK2_STOP_WITH_TC | 305e839b134SAdrian Hunter SDHCI_QUIRK2_CAPS_BIT63_FOR_HS400, 306159cd328SAdrian Hunter .probe_slot = intel_probe_slot, 30707a58883SAdrian Hunter }; 30807a58883SAdrian Hunter 309e5571397SAdrian Hunter static const struct sdhci_acpi_slot sdhci_acpi_slot_int_sdio = { 310e1f5633aSAdrian Hunter .quirks = SDHCI_QUIRK_BROKEN_CARD_DETECTION | 311e1f5633aSAdrian Hunter SDHCI_QUIRK_NO_ENDATTR_IN_NOPDESC, 312e5571397SAdrian Hunter .quirks2 = SDHCI_QUIRK2_HOST_OFF_CARD_ON, 3139d65cb88SAdrian Hunter .caps = MMC_CAP_NONREMOVABLE | MMC_CAP_POWER_OFF_CARD | 314265984b3SAdrian Hunter MMC_CAP_WAIT_WHILE_BUSY, 315e5571397SAdrian Hunter .flags = SDHCI_ACPI_RUNTIME_PM, 316e5571397SAdrian Hunter .pm_caps = MMC_PM_KEEP_POWER, 317159cd328SAdrian Hunter .probe_slot = intel_probe_slot, 318e5571397SAdrian Hunter }; 319e5571397SAdrian Hunter 32007a58883SAdrian Hunter static const struct sdhci_acpi_slot sdhci_acpi_slot_int_sd = { 3214fd4409cSAdrian Hunter .flags = SDHCI_ACPI_SD_CD | SDHCI_ACPI_SD_CD_OVERRIDE_LEVEL | 3224fd4409cSAdrian Hunter SDHCI_ACPI_RUNTIME_PM, 323e1f5633aSAdrian Hunter .quirks = SDHCI_QUIRK_NO_ENDATTR_IN_NOPDESC, 324934e31b9SAdrian Hunter .quirks2 = SDHCI_QUIRK2_CARD_ON_NEEDS_BUS_ON | 325934e31b9SAdrian Hunter SDHCI_QUIRK2_STOP_WITH_TC, 326d3e97407SAzhar Shaikh .caps = MMC_CAP_WAIT_WHILE_BUSY | MMC_CAP_AGGRESSIVE_PM, 327159cd328SAdrian Hunter .probe_slot = intel_probe_slot, 32807a58883SAdrian Hunter }; 32907a58883SAdrian Hunter 33070cce2afSPhilip Elcan static const struct sdhci_acpi_slot sdhci_acpi_slot_qcom_sd_3v = { 33170cce2afSPhilip Elcan .quirks = SDHCI_QUIRK_BROKEN_CARD_DETECTION, 33270cce2afSPhilip Elcan .quirks2 = SDHCI_QUIRK2_NO_1_8_V, 33370cce2afSPhilip Elcan .caps = MMC_CAP_NONREMOVABLE, 33470cce2afSPhilip Elcan }; 33570cce2afSPhilip Elcan 33670cce2afSPhilip Elcan static const struct sdhci_acpi_slot sdhci_acpi_slot_qcom_sd = { 33770cce2afSPhilip Elcan .quirks = SDHCI_QUIRK_BROKEN_CARD_DETECTION, 33870cce2afSPhilip Elcan .caps = MMC_CAP_NONREMOVABLE, 33970cce2afSPhilip Elcan }; 34070cce2afSPhilip Elcan 34107a58883SAdrian Hunter struct sdhci_acpi_uid_slot { 34207a58883SAdrian Hunter const char *hid; 34307a58883SAdrian Hunter const char *uid; 34407a58883SAdrian Hunter const struct sdhci_acpi_slot *slot; 34507a58883SAdrian Hunter }; 34607a58883SAdrian Hunter 34707a58883SAdrian Hunter static const struct sdhci_acpi_uid_slot sdhci_acpi_uids[] = { 348e839b134SAdrian Hunter { "80865ACA", NULL, &sdhci_acpi_slot_int_sd }, 349e839b134SAdrian Hunter { "80865ACC", NULL, &sdhci_acpi_slot_int_emmc }, 350e839b134SAdrian Hunter { "80865AD0", NULL, &sdhci_acpi_slot_int_sdio }, 35107a58883SAdrian Hunter { "80860F14" , "1" , &sdhci_acpi_slot_int_emmc }, 352db52d4f8SDaniel Drake { "80860F14" , "2" , &sdhci_acpi_slot_int_sdio }, 35307a58883SAdrian Hunter { "80860F14" , "3" , &sdhci_acpi_slot_int_sd }, 354aad95dc4SAdrian Hunter { "80860F16" , NULL, &sdhci_acpi_slot_int_sd }, 35507a58883SAdrian Hunter { "INT33BB" , "2" , &sdhci_acpi_slot_int_sdio }, 3567147eaf3SAdrian Hunter { "INT33BB" , "3" , &sdhci_acpi_slot_int_sd }, 35707a58883SAdrian Hunter { "INT33C6" , NULL, &sdhci_acpi_slot_int_sdio }, 35807c001c1SMika Westerberg { "INT3436" , NULL, &sdhci_acpi_slot_int_sdio }, 359d0ed8e6bSAdrian Hunter { "INT344D" , NULL, &sdhci_acpi_slot_int_sdio }, 3600cd2f044SMichele Curti { "PNP0FFF" , "3" , &sdhci_acpi_slot_int_sd }, 36107a58883SAdrian Hunter { "PNP0D40" }, 36270cce2afSPhilip Elcan { "QCOM8051", NULL, &sdhci_acpi_slot_qcom_sd_3v }, 36370cce2afSPhilip Elcan { "QCOM8052", NULL, &sdhci_acpi_slot_qcom_sd }, 36407a58883SAdrian Hunter { }, 36507a58883SAdrian Hunter }; 36607a58883SAdrian Hunter 367c4e05037SAdrian Hunter static const struct acpi_device_id sdhci_acpi_ids[] = { 368e839b134SAdrian Hunter { "80865ACA" }, 369e839b134SAdrian Hunter { "80865ACC" }, 370e839b134SAdrian Hunter { "80865AD0" }, 37107a58883SAdrian Hunter { "80860F14" }, 372aad95dc4SAdrian Hunter { "80860F16" }, 37307a58883SAdrian Hunter { "INT33BB" }, 37407a58883SAdrian Hunter { "INT33C6" }, 37507c001c1SMika Westerberg { "INT3436" }, 376d0ed8e6bSAdrian Hunter { "INT344D" }, 377c4e05037SAdrian Hunter { "PNP0D40" }, 37870cce2afSPhilip Elcan { "QCOM8051" }, 37970cce2afSPhilip Elcan { "QCOM8052" }, 380c4e05037SAdrian Hunter { }, 381c4e05037SAdrian Hunter }; 382c4e05037SAdrian Hunter MODULE_DEVICE_TABLE(acpi, sdhci_acpi_ids); 383c4e05037SAdrian Hunter 3843db35251SAdrian Hunter static const struct sdhci_acpi_slot *sdhci_acpi_get_slot(const char *hid, 38507a58883SAdrian Hunter const char *uid) 386c4e05037SAdrian Hunter { 38707a58883SAdrian Hunter const struct sdhci_acpi_uid_slot *u; 388c4e05037SAdrian Hunter 38907a58883SAdrian Hunter for (u = sdhci_acpi_uids; u->hid; u++) { 39007a58883SAdrian Hunter if (strcmp(u->hid, hid)) 39107a58883SAdrian Hunter continue; 39207a58883SAdrian Hunter if (!u->uid) 39307a58883SAdrian Hunter return u->slot; 39407a58883SAdrian Hunter if (uid && !strcmp(u->uid, uid)) 39507a58883SAdrian Hunter return u->slot; 39607a58883SAdrian Hunter } 397c4e05037SAdrian Hunter return NULL; 398c4e05037SAdrian Hunter } 399c4e05037SAdrian Hunter 4004e608e4eSGreg Kroah-Hartman static int sdhci_acpi_probe(struct platform_device *pdev) 401c4e05037SAdrian Hunter { 402c4e05037SAdrian Hunter struct device *dev = &pdev->dev; 403f07b7952SAdrian Hunter const struct sdhci_acpi_slot *slot; 404e5bbf307SAdrian Hunter struct acpi_device *device, *child; 405c4e05037SAdrian Hunter struct sdhci_acpi_host *c; 406c4e05037SAdrian Hunter struct sdhci_host *host; 407c4e05037SAdrian Hunter struct resource *iomem; 408c4e05037SAdrian Hunter resource_size_t len; 409f07b7952SAdrian Hunter size_t priv_size; 410c4e05037SAdrian Hunter const char *hid; 4113db35251SAdrian Hunter const char *uid; 41287875655SMika Westerberg int err; 413c4e05037SAdrian Hunter 414cd25c7beSAndy Shevchenko device = ACPI_COMPANION(dev); 415cd25c7beSAndy Shevchenko if (!device) 416c4e05037SAdrian Hunter return -ENODEV; 417c4e05037SAdrian Hunter 41817753d16SAdrian Hunter hid = acpi_device_hid(device); 419a2038497SAdrian Hunter uid = acpi_device_uid(device); 42017753d16SAdrian Hunter 421f07b7952SAdrian Hunter slot = sdhci_acpi_get_slot(hid, uid); 422f07b7952SAdrian Hunter 423e5bbf307SAdrian Hunter /* Power on the SDHCI controller and its children */ 424e5bbf307SAdrian Hunter acpi_device_fix_up_power(device); 42517753d16SAdrian Hunter if (!sdhci_acpi_no_fixup_child_power(hid, uid)) { 426e5bbf307SAdrian Hunter list_for_each_entry(child, &device->children, node) 427e1d070c3SHans de Goede if (child->status.present && child->status.enabled) 428e5bbf307SAdrian Hunter acpi_device_fix_up_power(child); 42917753d16SAdrian Hunter } 430e5bbf307SAdrian Hunter 4316e1c7d61SAdrian Hunter if (sdhci_acpi_byt_defer(dev)) 4326e1c7d61SAdrian Hunter return -EPROBE_DEFER; 4336e1c7d61SAdrian Hunter 434c4e05037SAdrian Hunter iomem = platform_get_resource(pdev, IORESOURCE_MEM, 0); 435c4e05037SAdrian Hunter if (!iomem) 436c4e05037SAdrian Hunter return -ENOMEM; 437c4e05037SAdrian Hunter 438c4e05037SAdrian Hunter len = resource_size(iomem); 439c4e05037SAdrian Hunter if (len < 0x100) 440c4e05037SAdrian Hunter dev_err(dev, "Invalid iomem size!\n"); 441c4e05037SAdrian Hunter 442c4e05037SAdrian Hunter if (!devm_request_mem_region(dev, iomem->start, len, dev_name(dev))) 443c4e05037SAdrian Hunter return -ENOMEM; 444c4e05037SAdrian Hunter 445f07b7952SAdrian Hunter priv_size = slot ? slot->priv_size : 0; 446f07b7952SAdrian Hunter host = sdhci_alloc_host(dev, sizeof(struct sdhci_acpi_host) + priv_size); 447c4e05037SAdrian Hunter if (IS_ERR(host)) 448c4e05037SAdrian Hunter return PTR_ERR(host); 449c4e05037SAdrian Hunter 450c4e05037SAdrian Hunter c = sdhci_priv(host); 451c4e05037SAdrian Hunter c->host = host; 452f07b7952SAdrian Hunter c->slot = slot; 453c4e05037SAdrian Hunter c->pdev = pdev; 454c4e05037SAdrian Hunter c->use_runtime_pm = sdhci_acpi_flag(c, SDHCI_ACPI_RUNTIME_PM); 455c4e05037SAdrian Hunter 456c4e05037SAdrian Hunter platform_set_drvdata(pdev, c); 457c4e05037SAdrian Hunter 458c4e05037SAdrian Hunter host->hw_name = "ACPI"; 459c4e05037SAdrian Hunter host->ops = &sdhci_acpi_ops_dflt; 460c4e05037SAdrian Hunter host->irq = platform_get_irq(pdev, 0); 461c4e05037SAdrian Hunter 462c4e05037SAdrian Hunter host->ioaddr = devm_ioremap_nocache(dev, iomem->start, 463c4e05037SAdrian Hunter resource_size(iomem)); 464c4e05037SAdrian Hunter if (host->ioaddr == NULL) { 465c4e05037SAdrian Hunter err = -ENOMEM; 466c4e05037SAdrian Hunter goto err_free; 467c4e05037SAdrian Hunter } 468c4e05037SAdrian Hunter 469c4e05037SAdrian Hunter if (c->slot) { 470578b36b6SGao, Yunpeng if (c->slot->probe_slot) { 4717dafca83SAdrian Hunter err = c->slot->probe_slot(pdev, hid, uid); 472578b36b6SGao, Yunpeng if (err) 473578b36b6SGao, Yunpeng goto err_free; 474578b36b6SGao, Yunpeng } 475c4e05037SAdrian Hunter if (c->slot->chip) { 476c4e05037SAdrian Hunter host->ops = c->slot->chip->ops; 477c4e05037SAdrian Hunter host->quirks |= c->slot->chip->quirks; 478c4e05037SAdrian Hunter host->quirks2 |= c->slot->chip->quirks2; 479c4e05037SAdrian Hunter host->mmc->caps |= c->slot->chip->caps; 480c4e05037SAdrian Hunter host->mmc->caps2 |= c->slot->chip->caps2; 481c4e05037SAdrian Hunter host->mmc->pm_caps |= c->slot->chip->pm_caps; 482c4e05037SAdrian Hunter } 483c4e05037SAdrian Hunter host->quirks |= c->slot->quirks; 484c4e05037SAdrian Hunter host->quirks2 |= c->slot->quirks2; 485c4e05037SAdrian Hunter host->mmc->caps |= c->slot->caps; 486c4e05037SAdrian Hunter host->mmc->caps2 |= c->slot->caps2; 487c4e05037SAdrian Hunter host->mmc->pm_caps |= c->slot->pm_caps; 488c4e05037SAdrian Hunter } 489c4e05037SAdrian Hunter 4900d3e3350SAdrian Hunter host->mmc->caps2 |= MMC_CAP2_NO_PRESCAN_POWERUP; 4910d3e3350SAdrian Hunter 4924fd4409cSAdrian Hunter if (sdhci_acpi_flag(c, SDHCI_ACPI_SD_CD)) { 4934fd4409cSAdrian Hunter bool v = sdhci_acpi_flag(c, SDHCI_ACPI_SD_CD_OVERRIDE_LEVEL); 4944fd4409cSAdrian Hunter 495e28d6f04SZhang Rui err = mmc_gpiod_request_cd(host->mmc, NULL, 0, v, 0, NULL); 496e28d6f04SZhang Rui if (err) { 497e28d6f04SZhang Rui if (err == -EPROBE_DEFER) 498e28d6f04SZhang Rui goto err_free; 4994fd4409cSAdrian Hunter dev_warn(dev, "failed to setup card detect gpio\n"); 5004fd4409cSAdrian Hunter c->use_runtime_pm = false; 5014fd4409cSAdrian Hunter } 5024fd4409cSAdrian Hunter } 5034fd4409cSAdrian Hunter 504c4e05037SAdrian Hunter err = sdhci_add_host(host); 505c4e05037SAdrian Hunter if (err) 506c4e05037SAdrian Hunter goto err_free; 507c4e05037SAdrian Hunter 508c4e05037SAdrian Hunter if (c->use_runtime_pm) { 5091d1ff458SAdrian Hunter pm_runtime_set_active(dev); 510c4e05037SAdrian Hunter pm_suspend_ignore_children(dev, 1); 511c4e05037SAdrian Hunter pm_runtime_set_autosuspend_delay(dev, 50); 512c4e05037SAdrian Hunter pm_runtime_use_autosuspend(dev); 513c4e05037SAdrian Hunter pm_runtime_enable(dev); 514c4e05037SAdrian Hunter } 515c4e05037SAdrian Hunter 5164e6a2ef9SFu, Zhonghui device_enable_async_suspend(dev); 5174e6a2ef9SFu, Zhonghui 518c4e05037SAdrian Hunter return 0; 519c4e05037SAdrian Hunter 520c4e05037SAdrian Hunter err_free: 521c4e05037SAdrian Hunter sdhci_free_host(c->host); 522c4e05037SAdrian Hunter return err; 523c4e05037SAdrian Hunter } 524c4e05037SAdrian Hunter 5254e608e4eSGreg Kroah-Hartman static int sdhci_acpi_remove(struct platform_device *pdev) 526c4e05037SAdrian Hunter { 527c4e05037SAdrian Hunter struct sdhci_acpi_host *c = platform_get_drvdata(pdev); 528c4e05037SAdrian Hunter struct device *dev = &pdev->dev; 529c4e05037SAdrian Hunter int dead; 530c4e05037SAdrian Hunter 531c4e05037SAdrian Hunter if (c->use_runtime_pm) { 532c4e05037SAdrian Hunter pm_runtime_get_sync(dev); 533c4e05037SAdrian Hunter pm_runtime_disable(dev); 534c4e05037SAdrian Hunter pm_runtime_put_noidle(dev); 535c4e05037SAdrian Hunter } 536c4e05037SAdrian Hunter 537578b36b6SGao, Yunpeng if (c->slot && c->slot->remove_slot) 538578b36b6SGao, Yunpeng c->slot->remove_slot(pdev); 539578b36b6SGao, Yunpeng 540c4e05037SAdrian Hunter dead = (sdhci_readl(c->host, SDHCI_INT_STATUS) == ~0); 541c4e05037SAdrian Hunter sdhci_remove_host(c->host, dead); 542c4e05037SAdrian Hunter sdhci_free_host(c->host); 543c4e05037SAdrian Hunter 544c4e05037SAdrian Hunter return 0; 545c4e05037SAdrian Hunter } 546c4e05037SAdrian Hunter 547c4e05037SAdrian Hunter #ifdef CONFIG_PM_SLEEP 548c4e05037SAdrian Hunter 549c4e05037SAdrian Hunter static int sdhci_acpi_suspend(struct device *dev) 550c4e05037SAdrian Hunter { 551c4e05037SAdrian Hunter struct sdhci_acpi_host *c = dev_get_drvdata(dev); 552d38dcad4SAdrian Hunter struct sdhci_host *host = c->host; 553c4e05037SAdrian Hunter 554d38dcad4SAdrian Hunter if (host->tuning_mode != SDHCI_TUNING_MODE_3) 555d38dcad4SAdrian Hunter mmc_retune_needed(host->mmc); 556d38dcad4SAdrian Hunter 557d38dcad4SAdrian Hunter return sdhci_suspend_host(host); 558c4e05037SAdrian Hunter } 559c4e05037SAdrian Hunter 560c4e05037SAdrian Hunter static int sdhci_acpi_resume(struct device *dev) 561c4e05037SAdrian Hunter { 562c4e05037SAdrian Hunter struct sdhci_acpi_host *c = dev_get_drvdata(dev); 563c4e05037SAdrian Hunter 5646e1c7d61SAdrian Hunter sdhci_acpi_byt_setting(&c->pdev->dev); 5656e1c7d61SAdrian Hunter 566c4e05037SAdrian Hunter return sdhci_resume_host(c->host); 567c4e05037SAdrian Hunter } 568c4e05037SAdrian Hunter 569c4e05037SAdrian Hunter #endif 570c4e05037SAdrian Hunter 571162d6f98SRafael J. Wysocki #ifdef CONFIG_PM 572c4e05037SAdrian Hunter 573c4e05037SAdrian Hunter static int sdhci_acpi_runtime_suspend(struct device *dev) 574c4e05037SAdrian Hunter { 575c4e05037SAdrian Hunter struct sdhci_acpi_host *c = dev_get_drvdata(dev); 576d38dcad4SAdrian Hunter struct sdhci_host *host = c->host; 577c4e05037SAdrian Hunter 578d38dcad4SAdrian Hunter if (host->tuning_mode != SDHCI_TUNING_MODE_3) 579d38dcad4SAdrian Hunter mmc_retune_needed(host->mmc); 580d38dcad4SAdrian Hunter 581d38dcad4SAdrian Hunter return sdhci_runtime_suspend_host(host); 582c4e05037SAdrian Hunter } 583c4e05037SAdrian Hunter 584c4e05037SAdrian Hunter static int sdhci_acpi_runtime_resume(struct device *dev) 585c4e05037SAdrian Hunter { 586c4e05037SAdrian Hunter struct sdhci_acpi_host *c = dev_get_drvdata(dev); 587c4e05037SAdrian Hunter 5886e1c7d61SAdrian Hunter sdhci_acpi_byt_setting(&c->pdev->dev); 5896e1c7d61SAdrian Hunter 590c4e05037SAdrian Hunter return sdhci_runtime_resume_host(c->host); 591c4e05037SAdrian Hunter } 592c4e05037SAdrian Hunter 593c4e05037SAdrian Hunter #endif 594c4e05037SAdrian Hunter 595c4e05037SAdrian Hunter static const struct dev_pm_ops sdhci_acpi_pm_ops = { 596dafed447SUlf Hansson SET_SYSTEM_SLEEP_PM_OPS(sdhci_acpi_suspend, sdhci_acpi_resume) 5971d75f74bSPeter Griffin SET_RUNTIME_PM_OPS(sdhci_acpi_runtime_suspend, 5989b449e99SUlf Hansson sdhci_acpi_runtime_resume, NULL) 599c4e05037SAdrian Hunter }; 600c4e05037SAdrian Hunter 601c4e05037SAdrian Hunter static struct platform_driver sdhci_acpi_driver = { 602c4e05037SAdrian Hunter .driver = { 603c4e05037SAdrian Hunter .name = "sdhci-acpi", 604c4e05037SAdrian Hunter .acpi_match_table = sdhci_acpi_ids, 605c4e05037SAdrian Hunter .pm = &sdhci_acpi_pm_ops, 606c4e05037SAdrian Hunter }, 607c4e05037SAdrian Hunter .probe = sdhci_acpi_probe, 6084e608e4eSGreg Kroah-Hartman .remove = sdhci_acpi_remove, 609c4e05037SAdrian Hunter }; 610c4e05037SAdrian Hunter 611c4e05037SAdrian Hunter module_platform_driver(sdhci_acpi_driver); 612c4e05037SAdrian Hunter 613c4e05037SAdrian Hunter MODULE_DESCRIPTION("Secure Digital Host Controller Interface ACPI driver"); 614c4e05037SAdrian Hunter MODULE_AUTHOR("Adrian Hunter"); 615c4e05037SAdrian Hunter MODULE_LICENSE("GPL v2"); 616