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; 767dafca83SAdrian Hunter int (*probe_slot)(struct platform_device *, const char *, const char *); 77578b36b6SGao, Yunpeng int (*remove_slot)(struct platform_device *); 78c4e05037SAdrian Hunter }; 79c4e05037SAdrian Hunter 80c4e05037SAdrian Hunter struct sdhci_acpi_host { 81c4e05037SAdrian Hunter struct sdhci_host *host; 82c4e05037SAdrian Hunter const struct sdhci_acpi_slot *slot; 83c4e05037SAdrian Hunter struct platform_device *pdev; 84c4e05037SAdrian Hunter bool use_runtime_pm; 85c4e05037SAdrian Hunter }; 86c4e05037SAdrian Hunter 87c4e05037SAdrian Hunter static inline bool sdhci_acpi_flag(struct sdhci_acpi_host *c, unsigned int flag) 88c4e05037SAdrian Hunter { 89c4e05037SAdrian Hunter return c->slot && (c->slot->flags & flag); 90c4e05037SAdrian Hunter } 91c4e05037SAdrian Hunter 92b04fa064SAdrian Hunter static void sdhci_acpi_int_hw_reset(struct sdhci_host *host) 93b04fa064SAdrian Hunter { 94b04fa064SAdrian Hunter u8 reg; 95b04fa064SAdrian Hunter 96b04fa064SAdrian Hunter reg = sdhci_readb(host, SDHCI_POWER_CONTROL); 97b04fa064SAdrian Hunter reg |= 0x10; 98b04fa064SAdrian Hunter sdhci_writeb(host, reg, SDHCI_POWER_CONTROL); 99b04fa064SAdrian Hunter /* For eMMC, minimum is 1us but give it 9us for good measure */ 100b04fa064SAdrian Hunter udelay(9); 101b04fa064SAdrian Hunter reg &= ~0x10; 102b04fa064SAdrian Hunter sdhci_writeb(host, reg, SDHCI_POWER_CONTROL); 103b04fa064SAdrian Hunter /* For eMMC, minimum is 200us but give it 300us for good measure */ 104b04fa064SAdrian Hunter usleep_range(300, 1000); 105b04fa064SAdrian Hunter } 106b04fa064SAdrian Hunter 107c4e05037SAdrian Hunter static const struct sdhci_ops sdhci_acpi_ops_dflt = { 1081771059cSRussell King .set_clock = sdhci_set_clock, 1092317f56cSRussell King .set_bus_width = sdhci_set_bus_width, 11003231f9bSRussell King .reset = sdhci_reset, 11196d7b78cSRussell King .set_uhs_signaling = sdhci_set_uhs_signaling, 112c4e05037SAdrian Hunter }; 113c4e05037SAdrian Hunter 114b04fa064SAdrian Hunter static const struct sdhci_ops sdhci_acpi_ops_int = { 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, 119b04fa064SAdrian Hunter .hw_reset = sdhci_acpi_int_hw_reset, 120b04fa064SAdrian Hunter }; 121b04fa064SAdrian Hunter 122b04fa064SAdrian Hunter static const struct sdhci_acpi_chip sdhci_acpi_chip_int = { 123b04fa064SAdrian Hunter .ops = &sdhci_acpi_ops_int, 124b04fa064SAdrian Hunter }; 125b04fa064SAdrian Hunter 1266e1c7d61SAdrian Hunter #ifdef CONFIG_X86 1276e1c7d61SAdrian Hunter 1286e1c7d61SAdrian Hunter static bool sdhci_acpi_byt(void) 1296e1c7d61SAdrian Hunter { 1306e1c7d61SAdrian Hunter static const struct x86_cpu_id byt[] = { 1318ba4cb53SDave Hansen { X86_VENDOR_INTEL, 6, INTEL_FAM6_ATOM_SILVERMONT1 }, 1326e1c7d61SAdrian Hunter {} 1336e1c7d61SAdrian Hunter }; 1346e1c7d61SAdrian Hunter 1356e1c7d61SAdrian Hunter return x86_match_cpu(byt); 1366e1c7d61SAdrian Hunter } 1376e1c7d61SAdrian Hunter 13817753d16SAdrian Hunter static bool sdhci_acpi_cht(void) 13917753d16SAdrian Hunter { 14017753d16SAdrian Hunter static const struct x86_cpu_id cht[] = { 14117753d16SAdrian Hunter { X86_VENDOR_INTEL, 6, INTEL_FAM6_ATOM_AIRMONT }, 14217753d16SAdrian Hunter {} 14317753d16SAdrian Hunter }; 14417753d16SAdrian Hunter 14517753d16SAdrian Hunter return x86_match_cpu(cht); 14617753d16SAdrian Hunter } 14717753d16SAdrian Hunter 1486e1c7d61SAdrian Hunter #define BYT_IOSF_SCCEP 0x63 1496e1c7d61SAdrian Hunter #define BYT_IOSF_OCP_NETCTRL0 0x1078 1506e1c7d61SAdrian Hunter #define BYT_IOSF_OCP_TIMEOUT_BASE GENMASK(10, 8) 1516e1c7d61SAdrian Hunter 1526e1c7d61SAdrian Hunter static void sdhci_acpi_byt_setting(struct device *dev) 1536e1c7d61SAdrian Hunter { 1546e1c7d61SAdrian Hunter u32 val = 0; 1556e1c7d61SAdrian Hunter 1566e1c7d61SAdrian Hunter if (!sdhci_acpi_byt()) 1576e1c7d61SAdrian Hunter return; 1586e1c7d61SAdrian Hunter 1596e1c7d61SAdrian Hunter if (iosf_mbi_read(BYT_IOSF_SCCEP, MBI_CR_READ, BYT_IOSF_OCP_NETCTRL0, 1606e1c7d61SAdrian Hunter &val)) { 1616e1c7d61SAdrian Hunter dev_err(dev, "%s read error\n", __func__); 1626e1c7d61SAdrian Hunter return; 1636e1c7d61SAdrian Hunter } 1646e1c7d61SAdrian Hunter 1656e1c7d61SAdrian Hunter if (!(val & BYT_IOSF_OCP_TIMEOUT_BASE)) 1666e1c7d61SAdrian Hunter return; 1676e1c7d61SAdrian Hunter 1686e1c7d61SAdrian Hunter val &= ~BYT_IOSF_OCP_TIMEOUT_BASE; 1696e1c7d61SAdrian Hunter 1706e1c7d61SAdrian Hunter if (iosf_mbi_write(BYT_IOSF_SCCEP, MBI_CR_WRITE, BYT_IOSF_OCP_NETCTRL0, 1716e1c7d61SAdrian Hunter val)) { 1726e1c7d61SAdrian Hunter dev_err(dev, "%s write error\n", __func__); 1736e1c7d61SAdrian Hunter return; 1746e1c7d61SAdrian Hunter } 1756e1c7d61SAdrian Hunter 1766e1c7d61SAdrian Hunter dev_dbg(dev, "%s completed\n", __func__); 1776e1c7d61SAdrian Hunter } 1786e1c7d61SAdrian Hunter 1796e1c7d61SAdrian Hunter static bool sdhci_acpi_byt_defer(struct device *dev) 1806e1c7d61SAdrian Hunter { 1816e1c7d61SAdrian Hunter if (!sdhci_acpi_byt()) 1826e1c7d61SAdrian Hunter return false; 1836e1c7d61SAdrian Hunter 1846e1c7d61SAdrian Hunter if (!iosf_mbi_available()) 1856e1c7d61SAdrian Hunter return true; 1866e1c7d61SAdrian Hunter 1876e1c7d61SAdrian Hunter sdhci_acpi_byt_setting(dev); 1886e1c7d61SAdrian Hunter 1896e1c7d61SAdrian Hunter return false; 1906e1c7d61SAdrian Hunter } 1916e1c7d61SAdrian Hunter 19217753d16SAdrian Hunter static bool sdhci_acpi_cht_pci_wifi(unsigned int vendor, unsigned int device, 19317753d16SAdrian Hunter unsigned int slot, unsigned int parent_slot) 19417753d16SAdrian Hunter { 19517753d16SAdrian Hunter struct pci_dev *dev, *parent, *from = NULL; 19617753d16SAdrian Hunter 19717753d16SAdrian Hunter while (1) { 19817753d16SAdrian Hunter dev = pci_get_device(vendor, device, from); 19917753d16SAdrian Hunter pci_dev_put(from); 20017753d16SAdrian Hunter if (!dev) 20117753d16SAdrian Hunter break; 20217753d16SAdrian Hunter parent = pci_upstream_bridge(dev); 20317753d16SAdrian Hunter if (ACPI_COMPANION(&dev->dev) && PCI_SLOT(dev->devfn) == slot && 20417753d16SAdrian Hunter parent && PCI_SLOT(parent->devfn) == parent_slot && 20517753d16SAdrian Hunter !pci_upstream_bridge(parent)) { 20617753d16SAdrian Hunter pci_dev_put(dev); 20717753d16SAdrian Hunter return true; 20817753d16SAdrian Hunter } 20917753d16SAdrian Hunter from = dev; 21017753d16SAdrian Hunter } 21117753d16SAdrian Hunter 21217753d16SAdrian Hunter return false; 21317753d16SAdrian Hunter } 21417753d16SAdrian Hunter 21517753d16SAdrian Hunter /* 21617753d16SAdrian Hunter * GPDwin uses PCI wifi which conflicts with SDIO's use of 21717753d16SAdrian Hunter * acpi_device_fix_up_power() on child device nodes. Identifying GPDwin is 21817753d16SAdrian Hunter * problematic, but since SDIO is only used for wifi, the presence of the PCI 21917753d16SAdrian Hunter * wifi card in the expected slot with an ACPI companion node, is used to 22017753d16SAdrian Hunter * indicate that acpi_device_fix_up_power() should be avoided. 22117753d16SAdrian Hunter */ 22217753d16SAdrian Hunter static inline bool sdhci_acpi_no_fixup_child_power(const char *hid, 22317753d16SAdrian Hunter const char *uid) 22417753d16SAdrian Hunter { 22517753d16SAdrian Hunter return sdhci_acpi_cht() && 22617753d16SAdrian Hunter !strcmp(hid, "80860F14") && 22717753d16SAdrian Hunter !strcmp(uid, "2") && 22817753d16SAdrian Hunter sdhci_acpi_cht_pci_wifi(0x14e4, 0x43ec, 0, 28); 22917753d16SAdrian Hunter } 23017753d16SAdrian Hunter 2316e1c7d61SAdrian Hunter #else 2326e1c7d61SAdrian Hunter 2336e1c7d61SAdrian Hunter static inline void sdhci_acpi_byt_setting(struct device *dev) 2346e1c7d61SAdrian Hunter { 2356e1c7d61SAdrian Hunter } 2366e1c7d61SAdrian Hunter 2376e1c7d61SAdrian Hunter static inline bool sdhci_acpi_byt_defer(struct device *dev) 2386e1c7d61SAdrian Hunter { 2396e1c7d61SAdrian Hunter return false; 2406e1c7d61SAdrian Hunter } 2416e1c7d61SAdrian Hunter 24217753d16SAdrian Hunter static inline bool sdhci_acpi_no_fixup_child_power(const char *hid, 24317753d16SAdrian Hunter const char *uid) 24417753d16SAdrian Hunter { 24517753d16SAdrian Hunter return false; 24617753d16SAdrian Hunter } 24717753d16SAdrian Hunter 2486e1c7d61SAdrian Hunter #endif 2496e1c7d61SAdrian Hunter 2506a645dd8SAdrian Hunter static int bxt_get_cd(struct mmc_host *mmc) 2516a645dd8SAdrian Hunter { 2526a645dd8SAdrian Hunter int gpio_cd = mmc_gpio_get_cd(mmc); 2536a645dd8SAdrian Hunter struct sdhci_host *host = mmc_priv(mmc); 2546a645dd8SAdrian Hunter unsigned long flags; 2556a645dd8SAdrian Hunter int ret = 0; 2566a645dd8SAdrian Hunter 2576a645dd8SAdrian Hunter if (!gpio_cd) 2586a645dd8SAdrian Hunter return 0; 2596a645dd8SAdrian Hunter 2606a645dd8SAdrian Hunter spin_lock_irqsave(&host->lock, flags); 2616a645dd8SAdrian Hunter 2626a645dd8SAdrian Hunter if (host->flags & SDHCI_DEVICE_DEAD) 2636a645dd8SAdrian Hunter goto out; 2646a645dd8SAdrian Hunter 2656a645dd8SAdrian Hunter ret = !!(sdhci_readl(host, SDHCI_PRESENT_STATE) & SDHCI_CARD_PRESENT); 2666a645dd8SAdrian Hunter out: 2676a645dd8SAdrian Hunter spin_unlock_irqrestore(&host->lock, flags); 2686a645dd8SAdrian Hunter 2696a645dd8SAdrian Hunter return ret; 2706a645dd8SAdrian Hunter } 2716a645dd8SAdrian Hunter 2727dafca83SAdrian Hunter static int sdhci_acpi_emmc_probe_slot(struct platform_device *pdev, 2737dafca83SAdrian Hunter const char *hid, const char *uid) 274578b36b6SGao, Yunpeng { 275578b36b6SGao, Yunpeng struct sdhci_acpi_host *c = platform_get_drvdata(pdev); 276578b36b6SGao, Yunpeng struct sdhci_host *host; 277578b36b6SGao, Yunpeng 278578b36b6SGao, Yunpeng if (!c || !c->host) 279578b36b6SGao, Yunpeng return 0; 280578b36b6SGao, Yunpeng 281578b36b6SGao, Yunpeng host = c->host; 282578b36b6SGao, Yunpeng 28394203042SAndy Shevchenko /* Platform specific code during emmc probe slot goes here */ 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 290578b36b6SGao, Yunpeng return 0; 291578b36b6SGao, Yunpeng } 292578b36b6SGao, Yunpeng 2937dafca83SAdrian Hunter static int sdhci_acpi_sdio_probe_slot(struct platform_device *pdev, 2947dafca83SAdrian Hunter const char *hid, const char *uid) 295578b36b6SGao, Yunpeng { 296578b36b6SGao, Yunpeng struct sdhci_acpi_host *c = platform_get_drvdata(pdev); 297578b36b6SGao, Yunpeng 298578b36b6SGao, Yunpeng if (!c || !c->host) 299578b36b6SGao, Yunpeng return 0; 300578b36b6SGao, Yunpeng 30194203042SAndy Shevchenko /* Platform specific code during sdio probe slot goes here */ 302578b36b6SGao, Yunpeng 303578b36b6SGao, Yunpeng return 0; 304578b36b6SGao, Yunpeng } 305578b36b6SGao, Yunpeng 3067dafca83SAdrian Hunter static int sdhci_acpi_sd_probe_slot(struct platform_device *pdev, 3077dafca83SAdrian Hunter const char *hid, const char *uid) 308578b36b6SGao, Yunpeng { 309578b36b6SGao, Yunpeng struct sdhci_acpi_host *c = platform_get_drvdata(pdev); 310578b36b6SGao, Yunpeng struct sdhci_host *host; 311578b36b6SGao, Yunpeng 312578b36b6SGao, Yunpeng if (!c || !c->host || !c->slot) 313578b36b6SGao, Yunpeng return 0; 314578b36b6SGao, Yunpeng 315578b36b6SGao, Yunpeng host = c->host; 316578b36b6SGao, Yunpeng 31794203042SAndy Shevchenko /* Platform specific code during sd probe slot goes here */ 318578b36b6SGao, Yunpeng 319d3e97407SAzhar Shaikh if (hid && !strcmp(hid, "80865ACA")) 3206a645dd8SAdrian Hunter host->mmc_host_ops.get_cd = bxt_get_cd; 3216a645dd8SAdrian Hunter 322578b36b6SGao, Yunpeng return 0; 323578b36b6SGao, Yunpeng } 324578b36b6SGao, Yunpeng 32507a58883SAdrian Hunter static const struct sdhci_acpi_slot sdhci_acpi_slot_int_emmc = { 326b04fa064SAdrian Hunter .chip = &sdhci_acpi_chip_int, 327f25c3372SMaurice Petallo .caps = MMC_CAP_8_BIT_DATA | MMC_CAP_NONREMOVABLE | 3289d65cb88SAdrian Hunter MMC_CAP_HW_RESET | MMC_CAP_1_8V_DDR | 329c80f275fSAdrian Hunter MMC_CAP_CMD_DURING_TFR | MMC_CAP_WAIT_WHILE_BUSY, 33007a58883SAdrian Hunter .flags = SDHCI_ACPI_RUNTIME_PM, 331e1f5633aSAdrian Hunter .quirks = SDHCI_QUIRK_NO_ENDATTR_IN_NOPDESC, 332e839b134SAdrian Hunter .quirks2 = SDHCI_QUIRK2_PRESET_VALUE_BROKEN | 333e839b134SAdrian Hunter SDHCI_QUIRK2_STOP_WITH_TC | 334e839b134SAdrian Hunter SDHCI_QUIRK2_CAPS_BIT63_FOR_HS400, 335578b36b6SGao, Yunpeng .probe_slot = sdhci_acpi_emmc_probe_slot, 33607a58883SAdrian Hunter }; 33707a58883SAdrian Hunter 338e5571397SAdrian Hunter static const struct sdhci_acpi_slot sdhci_acpi_slot_int_sdio = { 339e1f5633aSAdrian Hunter .quirks = SDHCI_QUIRK_BROKEN_CARD_DETECTION | 340e1f5633aSAdrian Hunter SDHCI_QUIRK_NO_ENDATTR_IN_NOPDESC, 341e5571397SAdrian Hunter .quirks2 = SDHCI_QUIRK2_HOST_OFF_CARD_ON, 3429d65cb88SAdrian Hunter .caps = MMC_CAP_NONREMOVABLE | MMC_CAP_POWER_OFF_CARD | 343265984b3SAdrian Hunter MMC_CAP_WAIT_WHILE_BUSY, 344e5571397SAdrian Hunter .flags = SDHCI_ACPI_RUNTIME_PM, 345e5571397SAdrian Hunter .pm_caps = MMC_PM_KEEP_POWER, 346578b36b6SGao, Yunpeng .probe_slot = sdhci_acpi_sdio_probe_slot, 347e5571397SAdrian Hunter }; 348e5571397SAdrian Hunter 34907a58883SAdrian Hunter static const struct sdhci_acpi_slot sdhci_acpi_slot_int_sd = { 3504fd4409cSAdrian Hunter .flags = SDHCI_ACPI_SD_CD | SDHCI_ACPI_SD_CD_OVERRIDE_LEVEL | 3514fd4409cSAdrian Hunter SDHCI_ACPI_RUNTIME_PM, 352e1f5633aSAdrian Hunter .quirks = SDHCI_QUIRK_NO_ENDATTR_IN_NOPDESC, 353934e31b9SAdrian Hunter .quirks2 = SDHCI_QUIRK2_CARD_ON_NEEDS_BUS_ON | 354934e31b9SAdrian Hunter SDHCI_QUIRK2_STOP_WITH_TC, 355d3e97407SAzhar Shaikh .caps = MMC_CAP_WAIT_WHILE_BUSY | MMC_CAP_AGGRESSIVE_PM, 356578b36b6SGao, Yunpeng .probe_slot = sdhci_acpi_sd_probe_slot, 35707a58883SAdrian Hunter }; 35807a58883SAdrian Hunter 35970cce2afSPhilip Elcan static const struct sdhci_acpi_slot sdhci_acpi_slot_qcom_sd_3v = { 36070cce2afSPhilip Elcan .quirks = SDHCI_QUIRK_BROKEN_CARD_DETECTION, 36170cce2afSPhilip Elcan .quirks2 = SDHCI_QUIRK2_NO_1_8_V, 36270cce2afSPhilip Elcan .caps = MMC_CAP_NONREMOVABLE, 36370cce2afSPhilip Elcan }; 36470cce2afSPhilip Elcan 36570cce2afSPhilip Elcan static const struct sdhci_acpi_slot sdhci_acpi_slot_qcom_sd = { 36670cce2afSPhilip Elcan .quirks = SDHCI_QUIRK_BROKEN_CARD_DETECTION, 36770cce2afSPhilip Elcan .caps = MMC_CAP_NONREMOVABLE, 36870cce2afSPhilip Elcan }; 36970cce2afSPhilip Elcan 37007a58883SAdrian Hunter struct sdhci_acpi_uid_slot { 37107a58883SAdrian Hunter const char *hid; 37207a58883SAdrian Hunter const char *uid; 37307a58883SAdrian Hunter const struct sdhci_acpi_slot *slot; 37407a58883SAdrian Hunter }; 37507a58883SAdrian Hunter 37607a58883SAdrian Hunter static const struct sdhci_acpi_uid_slot sdhci_acpi_uids[] = { 377e839b134SAdrian Hunter { "80865ACA", NULL, &sdhci_acpi_slot_int_sd }, 378e839b134SAdrian Hunter { "80865ACC", NULL, &sdhci_acpi_slot_int_emmc }, 379e839b134SAdrian Hunter { "80865AD0", NULL, &sdhci_acpi_slot_int_sdio }, 38007a58883SAdrian Hunter { "80860F14" , "1" , &sdhci_acpi_slot_int_emmc }, 381db52d4f8SDaniel Drake { "80860F14" , "2" , &sdhci_acpi_slot_int_sdio }, 38207a58883SAdrian Hunter { "80860F14" , "3" , &sdhci_acpi_slot_int_sd }, 383aad95dc4SAdrian Hunter { "80860F16" , NULL, &sdhci_acpi_slot_int_sd }, 38407a58883SAdrian Hunter { "INT33BB" , "2" , &sdhci_acpi_slot_int_sdio }, 3857147eaf3SAdrian Hunter { "INT33BB" , "3" , &sdhci_acpi_slot_int_sd }, 38607a58883SAdrian Hunter { "INT33C6" , NULL, &sdhci_acpi_slot_int_sdio }, 38707c001c1SMika Westerberg { "INT3436" , NULL, &sdhci_acpi_slot_int_sdio }, 388d0ed8e6bSAdrian Hunter { "INT344D" , NULL, &sdhci_acpi_slot_int_sdio }, 3890cd2f044SMichele Curti { "PNP0FFF" , "3" , &sdhci_acpi_slot_int_sd }, 39007a58883SAdrian Hunter { "PNP0D40" }, 39170cce2afSPhilip Elcan { "QCOM8051", NULL, &sdhci_acpi_slot_qcom_sd_3v }, 39270cce2afSPhilip Elcan { "QCOM8052", NULL, &sdhci_acpi_slot_qcom_sd }, 39307a58883SAdrian Hunter { }, 39407a58883SAdrian Hunter }; 39507a58883SAdrian Hunter 396c4e05037SAdrian Hunter static const struct acpi_device_id sdhci_acpi_ids[] = { 397e839b134SAdrian Hunter { "80865ACA" }, 398e839b134SAdrian Hunter { "80865ACC" }, 399e839b134SAdrian Hunter { "80865AD0" }, 40007a58883SAdrian Hunter { "80860F14" }, 401aad95dc4SAdrian Hunter { "80860F16" }, 40207a58883SAdrian Hunter { "INT33BB" }, 40307a58883SAdrian Hunter { "INT33C6" }, 40407c001c1SMika Westerberg { "INT3436" }, 405d0ed8e6bSAdrian Hunter { "INT344D" }, 406c4e05037SAdrian Hunter { "PNP0D40" }, 40770cce2afSPhilip Elcan { "QCOM8051" }, 40870cce2afSPhilip Elcan { "QCOM8052" }, 409c4e05037SAdrian Hunter { }, 410c4e05037SAdrian Hunter }; 411c4e05037SAdrian Hunter MODULE_DEVICE_TABLE(acpi, sdhci_acpi_ids); 412c4e05037SAdrian Hunter 4133db35251SAdrian Hunter static const struct sdhci_acpi_slot *sdhci_acpi_get_slot(const char *hid, 41407a58883SAdrian Hunter const char *uid) 415c4e05037SAdrian Hunter { 41607a58883SAdrian Hunter const struct sdhci_acpi_uid_slot *u; 417c4e05037SAdrian Hunter 41807a58883SAdrian Hunter for (u = sdhci_acpi_uids; u->hid; u++) { 41907a58883SAdrian Hunter if (strcmp(u->hid, hid)) 42007a58883SAdrian Hunter continue; 42107a58883SAdrian Hunter if (!u->uid) 42207a58883SAdrian Hunter return u->slot; 42307a58883SAdrian Hunter if (uid && !strcmp(u->uid, uid)) 42407a58883SAdrian Hunter return u->slot; 42507a58883SAdrian Hunter } 426c4e05037SAdrian Hunter return NULL; 427c4e05037SAdrian Hunter } 428c4e05037SAdrian Hunter 4294e608e4eSGreg Kroah-Hartman static int sdhci_acpi_probe(struct platform_device *pdev) 430c4e05037SAdrian Hunter { 431c4e05037SAdrian Hunter struct device *dev = &pdev->dev; 432e5bbf307SAdrian Hunter struct acpi_device *device, *child; 433c4e05037SAdrian Hunter struct sdhci_acpi_host *c; 434c4e05037SAdrian Hunter struct sdhci_host *host; 435c4e05037SAdrian Hunter struct resource *iomem; 436c4e05037SAdrian Hunter resource_size_t len; 437c4e05037SAdrian Hunter const char *hid; 4383db35251SAdrian Hunter const char *uid; 43987875655SMika Westerberg int err; 440c4e05037SAdrian Hunter 441*cd25c7beSAndy Shevchenko device = ACPI_COMPANION(dev); 442*cd25c7beSAndy Shevchenko if (!device) 443c4e05037SAdrian Hunter return -ENODEV; 444c4e05037SAdrian Hunter 44517753d16SAdrian Hunter hid = acpi_device_hid(device); 44617753d16SAdrian Hunter uid = device->pnp.unique_id; 44717753d16SAdrian Hunter 448e5bbf307SAdrian Hunter /* Power on the SDHCI controller and its children */ 449e5bbf307SAdrian Hunter acpi_device_fix_up_power(device); 45017753d16SAdrian Hunter if (!sdhci_acpi_no_fixup_child_power(hid, uid)) { 451e5bbf307SAdrian Hunter list_for_each_entry(child, &device->children, node) 452e1d070c3SHans de Goede if (child->status.present && child->status.enabled) 453e5bbf307SAdrian Hunter acpi_device_fix_up_power(child); 45417753d16SAdrian Hunter } 455e5bbf307SAdrian Hunter 4566e1c7d61SAdrian Hunter if (sdhci_acpi_byt_defer(dev)) 4576e1c7d61SAdrian Hunter return -EPROBE_DEFER; 4586e1c7d61SAdrian Hunter 459c4e05037SAdrian Hunter iomem = platform_get_resource(pdev, IORESOURCE_MEM, 0); 460c4e05037SAdrian Hunter if (!iomem) 461c4e05037SAdrian Hunter return -ENOMEM; 462c4e05037SAdrian Hunter 463c4e05037SAdrian Hunter len = resource_size(iomem); 464c4e05037SAdrian Hunter if (len < 0x100) 465c4e05037SAdrian Hunter dev_err(dev, "Invalid iomem size!\n"); 466c4e05037SAdrian Hunter 467c4e05037SAdrian Hunter if (!devm_request_mem_region(dev, iomem->start, len, dev_name(dev))) 468c4e05037SAdrian Hunter return -ENOMEM; 469c4e05037SAdrian Hunter 470c4e05037SAdrian Hunter host = sdhci_alloc_host(dev, sizeof(struct sdhci_acpi_host)); 471c4e05037SAdrian Hunter if (IS_ERR(host)) 472c4e05037SAdrian Hunter return PTR_ERR(host); 473c4e05037SAdrian Hunter 474c4e05037SAdrian Hunter c = sdhci_priv(host); 475c4e05037SAdrian Hunter c->host = host; 4763db35251SAdrian Hunter c->slot = sdhci_acpi_get_slot(hid, uid); 477c4e05037SAdrian Hunter c->pdev = pdev; 478c4e05037SAdrian Hunter c->use_runtime_pm = sdhci_acpi_flag(c, SDHCI_ACPI_RUNTIME_PM); 479c4e05037SAdrian Hunter 480c4e05037SAdrian Hunter platform_set_drvdata(pdev, c); 481c4e05037SAdrian Hunter 482c4e05037SAdrian Hunter host->hw_name = "ACPI"; 483c4e05037SAdrian Hunter host->ops = &sdhci_acpi_ops_dflt; 484c4e05037SAdrian Hunter host->irq = platform_get_irq(pdev, 0); 485c4e05037SAdrian Hunter 486c4e05037SAdrian Hunter host->ioaddr = devm_ioremap_nocache(dev, iomem->start, 487c4e05037SAdrian Hunter resource_size(iomem)); 488c4e05037SAdrian Hunter if (host->ioaddr == NULL) { 489c4e05037SAdrian Hunter err = -ENOMEM; 490c4e05037SAdrian Hunter goto err_free; 491c4e05037SAdrian Hunter } 492c4e05037SAdrian Hunter 493c4e05037SAdrian Hunter if (c->slot) { 494578b36b6SGao, Yunpeng if (c->slot->probe_slot) { 4957dafca83SAdrian Hunter err = c->slot->probe_slot(pdev, hid, uid); 496578b36b6SGao, Yunpeng if (err) 497578b36b6SGao, Yunpeng goto err_free; 498578b36b6SGao, Yunpeng } 499c4e05037SAdrian Hunter if (c->slot->chip) { 500c4e05037SAdrian Hunter host->ops = c->slot->chip->ops; 501c4e05037SAdrian Hunter host->quirks |= c->slot->chip->quirks; 502c4e05037SAdrian Hunter host->quirks2 |= c->slot->chip->quirks2; 503c4e05037SAdrian Hunter host->mmc->caps |= c->slot->chip->caps; 504c4e05037SAdrian Hunter host->mmc->caps2 |= c->slot->chip->caps2; 505c4e05037SAdrian Hunter host->mmc->pm_caps |= c->slot->chip->pm_caps; 506c4e05037SAdrian Hunter } 507c4e05037SAdrian Hunter host->quirks |= c->slot->quirks; 508c4e05037SAdrian Hunter host->quirks2 |= c->slot->quirks2; 509c4e05037SAdrian Hunter host->mmc->caps |= c->slot->caps; 510c4e05037SAdrian Hunter host->mmc->caps2 |= c->slot->caps2; 511c4e05037SAdrian Hunter host->mmc->pm_caps |= c->slot->pm_caps; 512c4e05037SAdrian Hunter } 513c4e05037SAdrian Hunter 5140d3e3350SAdrian Hunter host->mmc->caps2 |= MMC_CAP2_NO_PRESCAN_POWERUP; 5150d3e3350SAdrian Hunter 5164fd4409cSAdrian Hunter if (sdhci_acpi_flag(c, SDHCI_ACPI_SD_CD)) { 5174fd4409cSAdrian Hunter bool v = sdhci_acpi_flag(c, SDHCI_ACPI_SD_CD_OVERRIDE_LEVEL); 5184fd4409cSAdrian Hunter 519e28d6f04SZhang Rui err = mmc_gpiod_request_cd(host->mmc, NULL, 0, v, 0, NULL); 520e28d6f04SZhang Rui if (err) { 521e28d6f04SZhang Rui if (err == -EPROBE_DEFER) 522e28d6f04SZhang Rui goto err_free; 5234fd4409cSAdrian Hunter dev_warn(dev, "failed to setup card detect gpio\n"); 5244fd4409cSAdrian Hunter c->use_runtime_pm = false; 5254fd4409cSAdrian Hunter } 5264fd4409cSAdrian Hunter } 5274fd4409cSAdrian Hunter 528c4e05037SAdrian Hunter err = sdhci_add_host(host); 529c4e05037SAdrian Hunter if (err) 530c4e05037SAdrian Hunter goto err_free; 531c4e05037SAdrian Hunter 532c4e05037SAdrian Hunter if (c->use_runtime_pm) { 5331d1ff458SAdrian Hunter pm_runtime_set_active(dev); 534c4e05037SAdrian Hunter pm_suspend_ignore_children(dev, 1); 535c4e05037SAdrian Hunter pm_runtime_set_autosuspend_delay(dev, 50); 536c4e05037SAdrian Hunter pm_runtime_use_autosuspend(dev); 537c4e05037SAdrian Hunter pm_runtime_enable(dev); 538c4e05037SAdrian Hunter } 539c4e05037SAdrian Hunter 5404e6a2ef9SFu, Zhonghui device_enable_async_suspend(dev); 5414e6a2ef9SFu, Zhonghui 542c4e05037SAdrian Hunter return 0; 543c4e05037SAdrian Hunter 544c4e05037SAdrian Hunter err_free: 545c4e05037SAdrian Hunter sdhci_free_host(c->host); 546c4e05037SAdrian Hunter return err; 547c4e05037SAdrian Hunter } 548c4e05037SAdrian Hunter 5494e608e4eSGreg Kroah-Hartman static int sdhci_acpi_remove(struct platform_device *pdev) 550c4e05037SAdrian Hunter { 551c4e05037SAdrian Hunter struct sdhci_acpi_host *c = platform_get_drvdata(pdev); 552c4e05037SAdrian Hunter struct device *dev = &pdev->dev; 553c4e05037SAdrian Hunter int dead; 554c4e05037SAdrian Hunter 555c4e05037SAdrian Hunter if (c->use_runtime_pm) { 556c4e05037SAdrian Hunter pm_runtime_get_sync(dev); 557c4e05037SAdrian Hunter pm_runtime_disable(dev); 558c4e05037SAdrian Hunter pm_runtime_put_noidle(dev); 559c4e05037SAdrian Hunter } 560c4e05037SAdrian Hunter 561578b36b6SGao, Yunpeng if (c->slot && c->slot->remove_slot) 562578b36b6SGao, Yunpeng c->slot->remove_slot(pdev); 563578b36b6SGao, Yunpeng 564c4e05037SAdrian Hunter dead = (sdhci_readl(c->host, SDHCI_INT_STATUS) == ~0); 565c4e05037SAdrian Hunter sdhci_remove_host(c->host, dead); 566c4e05037SAdrian Hunter sdhci_free_host(c->host); 567c4e05037SAdrian Hunter 568c4e05037SAdrian Hunter return 0; 569c4e05037SAdrian Hunter } 570c4e05037SAdrian Hunter 571c4e05037SAdrian Hunter #ifdef CONFIG_PM_SLEEP 572c4e05037SAdrian Hunter 573c4e05037SAdrian Hunter static int sdhci_acpi_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_suspend_host(host); 582c4e05037SAdrian Hunter } 583c4e05037SAdrian Hunter 584c4e05037SAdrian Hunter static int sdhci_acpi_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_resume_host(c->host); 591c4e05037SAdrian Hunter } 592c4e05037SAdrian Hunter 593c4e05037SAdrian Hunter #endif 594c4e05037SAdrian Hunter 595162d6f98SRafael J. Wysocki #ifdef CONFIG_PM 596c4e05037SAdrian Hunter 597c4e05037SAdrian Hunter static int sdhci_acpi_runtime_suspend(struct device *dev) 598c4e05037SAdrian Hunter { 599c4e05037SAdrian Hunter struct sdhci_acpi_host *c = dev_get_drvdata(dev); 600d38dcad4SAdrian Hunter struct sdhci_host *host = c->host; 601c4e05037SAdrian Hunter 602d38dcad4SAdrian Hunter if (host->tuning_mode != SDHCI_TUNING_MODE_3) 603d38dcad4SAdrian Hunter mmc_retune_needed(host->mmc); 604d38dcad4SAdrian Hunter 605d38dcad4SAdrian Hunter return sdhci_runtime_suspend_host(host); 606c4e05037SAdrian Hunter } 607c4e05037SAdrian Hunter 608c4e05037SAdrian Hunter static int sdhci_acpi_runtime_resume(struct device *dev) 609c4e05037SAdrian Hunter { 610c4e05037SAdrian Hunter struct sdhci_acpi_host *c = dev_get_drvdata(dev); 611c4e05037SAdrian Hunter 6126e1c7d61SAdrian Hunter sdhci_acpi_byt_setting(&c->pdev->dev); 6136e1c7d61SAdrian Hunter 614c4e05037SAdrian Hunter return sdhci_runtime_resume_host(c->host); 615c4e05037SAdrian Hunter } 616c4e05037SAdrian Hunter 617c4e05037SAdrian Hunter #endif 618c4e05037SAdrian Hunter 619c4e05037SAdrian Hunter static const struct dev_pm_ops sdhci_acpi_pm_ops = { 620dafed447SUlf Hansson SET_SYSTEM_SLEEP_PM_OPS(sdhci_acpi_suspend, sdhci_acpi_resume) 6211d75f74bSPeter Griffin SET_RUNTIME_PM_OPS(sdhci_acpi_runtime_suspend, 6229b449e99SUlf Hansson sdhci_acpi_runtime_resume, NULL) 623c4e05037SAdrian Hunter }; 624c4e05037SAdrian Hunter 625c4e05037SAdrian Hunter static struct platform_driver sdhci_acpi_driver = { 626c4e05037SAdrian Hunter .driver = { 627c4e05037SAdrian Hunter .name = "sdhci-acpi", 628c4e05037SAdrian Hunter .acpi_match_table = sdhci_acpi_ids, 629c4e05037SAdrian Hunter .pm = &sdhci_acpi_pm_ops, 630c4e05037SAdrian Hunter }, 631c4e05037SAdrian Hunter .probe = sdhci_acpi_probe, 6324e608e4eSGreg Kroah-Hartman .remove = sdhci_acpi_remove, 633c4e05037SAdrian Hunter }; 634c4e05037SAdrian Hunter 635c4e05037SAdrian Hunter module_platform_driver(sdhci_acpi_driver); 636c4e05037SAdrian Hunter 637c4e05037SAdrian Hunter MODULE_DESCRIPTION("Secure Digital Host Controller Interface ACPI driver"); 638c4e05037SAdrian Hunter MODULE_AUTHOR("Adrian Hunter"); 639c4e05037SAdrian Hunter MODULE_LICENSE("GPL v2"); 640