xref: /linux/drivers/mmc/host/sdhci-acpi.c (revision cd25c7be3cc6f5f349e57a0bd0fd056e7f3f8dbe)
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