101acf691SAdam Lee /*
201acf691SAdam Lee  * Copyright (C) 2013 BayHub Technology Ltd.
301acf691SAdam Lee  *
401acf691SAdam Lee  * Authors: Peter Guo <peter.guo@bayhubtech.com>
501acf691SAdam Lee  *          Adam Lee <adam.lee@canonical.com>
657322d54Sernest.zhang  *          Ernest Zhang <ernest.zhang@bayhubtech.com>
701acf691SAdam Lee  *
801acf691SAdam Lee  * This software is licensed under the terms of the GNU General Public
901acf691SAdam Lee  * License version 2, as published by the Free Software Foundation, and
1001acf691SAdam Lee  * may be copied, distributed, and modified under those terms.
1101acf691SAdam Lee  *
1201acf691SAdam Lee  * This program is distributed in the hope that it will be useful,
1301acf691SAdam Lee  * but WITHOUT ANY WARRANTY; without even the implied warranty of
1401acf691SAdam Lee  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
1501acf691SAdam Lee  * GNU General Public License for more details.
1601acf691SAdam Lee  *
1701acf691SAdam Lee  */
1801acf691SAdam Lee 
1901acf691SAdam Lee #include <linux/pci.h>
200086fc21Sernest.zhang #include <linux/mmc/host.h>
210086fc21Sernest.zhang #include <linux/mmc/mmc.h>
220086fc21Sernest.zhang #include <linux/delay.h>
2301acf691SAdam Lee 
2401acf691SAdam Lee #include "sdhci.h"
2501acf691SAdam Lee #include "sdhci-pci.h"
26361eeda0SAdrian Hunter 
27361eeda0SAdrian Hunter /*
28361eeda0SAdrian Hunter  * O2Micro device registers
29361eeda0SAdrian Hunter  */
30361eeda0SAdrian Hunter 
31361eeda0SAdrian Hunter #define O2_SD_MISC_REG5		0x64
32361eeda0SAdrian Hunter #define O2_SD_LD0_CTRL		0x68
33361eeda0SAdrian Hunter #define O2_SD_DEV_CTRL		0x88
34361eeda0SAdrian Hunter #define O2_SD_LOCK_WP		0xD3
35361eeda0SAdrian Hunter #define O2_SD_TEST_REG		0xD4
36361eeda0SAdrian Hunter #define O2_SD_FUNC_REG0		0xDC
37361eeda0SAdrian Hunter #define O2_SD_MULTI_VCC3V	0xEE
38361eeda0SAdrian Hunter #define O2_SD_CLKREQ		0xEC
39361eeda0SAdrian Hunter #define O2_SD_CAPS		0xE0
40361eeda0SAdrian Hunter #define O2_SD_ADMA1		0xE2
41361eeda0SAdrian Hunter #define O2_SD_ADMA2		0xE7
42361eeda0SAdrian Hunter #define O2_SD_INF_MOD		0xF1
43361eeda0SAdrian Hunter #define O2_SD_MISC_CTRL4	0xFC
44361eeda0SAdrian Hunter #define O2_SD_TUNING_CTRL	0x300
45361eeda0SAdrian Hunter #define O2_SD_PLL_SETTING	0x304
4657322d54Sernest.zhang #define O2_SD_MISC_SETTING	0x308
47361eeda0SAdrian Hunter #define O2_SD_CLK_SETTING	0x328
48361eeda0SAdrian Hunter #define O2_SD_CAP_REG2		0x330
49361eeda0SAdrian Hunter #define O2_SD_CAP_REG0		0x334
50361eeda0SAdrian Hunter #define O2_SD_UHS1_CAP_SETTING	0x33C
51361eeda0SAdrian Hunter #define O2_SD_DELAY_CTRL	0x350
52361eeda0SAdrian Hunter #define O2_SD_UHS2_L1_CTRL	0x35C
53361eeda0SAdrian Hunter #define O2_SD_FUNC_REG3		0x3E0
54361eeda0SAdrian Hunter #define O2_SD_FUNC_REG4		0x3E4
55361eeda0SAdrian Hunter #define O2_SD_LED_ENABLE	BIT(6)
56361eeda0SAdrian Hunter #define O2_SD_FREG0_LEDOFF	BIT(13)
57361eeda0SAdrian Hunter #define O2_SD_FREG4_ENABLE_CLK_SET	BIT(22)
58361eeda0SAdrian Hunter 
59361eeda0SAdrian Hunter #define O2_SD_VENDOR_SETTING	0x110
60361eeda0SAdrian Hunter #define O2_SD_VENDOR_SETTING2	0x1C8
610086fc21Sernest.zhang #define O2_SD_HW_TUNING_DISABLE	BIT(4)
620086fc21Sernest.zhang 
6369d91ed1SErnest Zhang(WH) #define O2_PLL_WDT_CONTROL1	0x1CC
6469d91ed1SErnest Zhang(WH) #define  O2_PLL_FORCE_ACTIVE	BIT(18)
6569d91ed1SErnest Zhang(WH) #define  O2_PLL_LOCK_STATUS	BIT(14)
6669d91ed1SErnest Zhang(WH) #define  O2_PLL_SOFT_RESET	BIT(12)
6769d91ed1SErnest Zhang(WH) 
6869d91ed1SErnest Zhang(WH) #define O2_SD_DETECT_SETTING 0x324
6969d91ed1SErnest Zhang(WH) 
700086fc21Sernest.zhang static void sdhci_o2_set_tuning_mode(struct sdhci_host *host)
710086fc21Sernest.zhang {
720086fc21Sernest.zhang 	u16 reg;
730086fc21Sernest.zhang 
740086fc21Sernest.zhang 	/* enable hardware tuning */
750086fc21Sernest.zhang 	reg = sdhci_readw(host, O2_SD_VENDOR_SETTING);
760086fc21Sernest.zhang 	reg &= ~O2_SD_HW_TUNING_DISABLE;
770086fc21Sernest.zhang 	sdhci_writew(host, reg, O2_SD_VENDOR_SETTING);
780086fc21Sernest.zhang }
790086fc21Sernest.zhang 
800086fc21Sernest.zhang static void __sdhci_o2_execute_tuning(struct sdhci_host *host, u32 opcode)
810086fc21Sernest.zhang {
820086fc21Sernest.zhang 	int i;
830086fc21Sernest.zhang 
840086fc21Sernest.zhang 	sdhci_send_tuning(host, MMC_SEND_TUNING_BLOCK_HS200);
850086fc21Sernest.zhang 
860086fc21Sernest.zhang 	for (i = 0; i < 150; i++) {
870086fc21Sernest.zhang 		u16 ctrl = sdhci_readw(host, SDHCI_HOST_CONTROL2);
880086fc21Sernest.zhang 
890086fc21Sernest.zhang 		if (!(ctrl & SDHCI_CTRL_EXEC_TUNING)) {
900086fc21Sernest.zhang 			if (ctrl & SDHCI_CTRL_TUNED_CLK) {
910086fc21Sernest.zhang 				host->tuning_done = true;
920086fc21Sernest.zhang 				return;
930086fc21Sernest.zhang 			}
940086fc21Sernest.zhang 			pr_warn("%s: HW tuning failed !\n",
950086fc21Sernest.zhang 				mmc_hostname(host->mmc));
960086fc21Sernest.zhang 			break;
970086fc21Sernest.zhang 		}
980086fc21Sernest.zhang 
990086fc21Sernest.zhang 		mdelay(1);
1000086fc21Sernest.zhang 	}
1010086fc21Sernest.zhang 
1020086fc21Sernest.zhang 	pr_info("%s: Tuning failed, falling back to fixed sampling clock\n",
1030086fc21Sernest.zhang 		mmc_hostname(host->mmc));
1040086fc21Sernest.zhang 	sdhci_reset_tuning(host);
1050086fc21Sernest.zhang }
1060086fc21Sernest.zhang 
1070086fc21Sernest.zhang static int sdhci_o2_execute_tuning(struct mmc_host *mmc, u32 opcode)
1080086fc21Sernest.zhang {
1090086fc21Sernest.zhang 	struct sdhci_host *host = mmc_priv(mmc);
1100086fc21Sernest.zhang 	int current_bus_width = 0;
1110086fc21Sernest.zhang 
1120086fc21Sernest.zhang 	/*
1130086fc21Sernest.zhang 	 * This handler only implements the eMMC tuning that is specific to
1140086fc21Sernest.zhang 	 * this controller.  Fall back to the standard method for other TIMING.
1150086fc21Sernest.zhang 	 */
1160086fc21Sernest.zhang 	if (host->timing != MMC_TIMING_MMC_HS200)
1170086fc21Sernest.zhang 		return sdhci_execute_tuning(mmc, opcode);
1180086fc21Sernest.zhang 
1190086fc21Sernest.zhang 	if (WARN_ON(opcode != MMC_SEND_TUNING_BLOCK_HS200))
1200086fc21Sernest.zhang 		return -EINVAL;
1210086fc21Sernest.zhang 
1220086fc21Sernest.zhang 	/*
1230086fc21Sernest.zhang 	 * o2 sdhci host didn't support 8bit emmc tuning
1240086fc21Sernest.zhang 	 */
1250086fc21Sernest.zhang 	if (mmc->ios.bus_width == MMC_BUS_WIDTH_8) {
1260086fc21Sernest.zhang 		current_bus_width = mmc->ios.bus_width;
1270086fc21Sernest.zhang 		sdhci_set_bus_width(host, MMC_BUS_WIDTH_4);
1280086fc21Sernest.zhang 	}
1290086fc21Sernest.zhang 
1300086fc21Sernest.zhang 	sdhci_o2_set_tuning_mode(host);
1310086fc21Sernest.zhang 
1320086fc21Sernest.zhang 	sdhci_start_tuning(host);
1330086fc21Sernest.zhang 
1340086fc21Sernest.zhang 	__sdhci_o2_execute_tuning(host, opcode);
1350086fc21Sernest.zhang 
1360086fc21Sernest.zhang 	sdhci_end_tuning(host);
1370086fc21Sernest.zhang 
1380086fc21Sernest.zhang 	if (current_bus_width == MMC_BUS_WIDTH_8)
1390086fc21Sernest.zhang 		sdhci_set_bus_width(host, current_bus_width);
1400086fc21Sernest.zhang 
1410086fc21Sernest.zhang 	host->flags &= ~SDHCI_HS400_TUNING;
1420086fc21Sernest.zhang 	return 0;
1430086fc21Sernest.zhang }
14401acf691SAdam Lee 
145706adf6bSPeter Guo static void o2_pci_set_baseclk(struct sdhci_pci_chip *chip, u32 value)
146706adf6bSPeter Guo {
147706adf6bSPeter Guo 	u32 scratch_32;
148706adf6bSPeter Guo 	pci_read_config_dword(chip->pdev,
149706adf6bSPeter Guo 			      O2_SD_PLL_SETTING, &scratch_32);
150706adf6bSPeter Guo 
151706adf6bSPeter Guo 	scratch_32 &= 0x0000FFFF;
152706adf6bSPeter Guo 	scratch_32 |= value;
153706adf6bSPeter Guo 
154706adf6bSPeter Guo 	pci_write_config_dword(chip->pdev,
155706adf6bSPeter Guo 			       O2_SD_PLL_SETTING, scratch_32);
156706adf6bSPeter Guo }
157706adf6bSPeter Guo 
158706adf6bSPeter Guo static void o2_pci_led_enable(struct sdhci_pci_chip *chip)
159706adf6bSPeter Guo {
160706adf6bSPeter Guo 	int ret;
161706adf6bSPeter Guo 	u32 scratch_32;
162706adf6bSPeter Guo 
163706adf6bSPeter Guo 	/* Set led of SD host function enable */
164706adf6bSPeter Guo 	ret = pci_read_config_dword(chip->pdev,
165706adf6bSPeter Guo 				    O2_SD_FUNC_REG0, &scratch_32);
166706adf6bSPeter Guo 	if (ret)
167706adf6bSPeter Guo 		return;
168706adf6bSPeter Guo 
169706adf6bSPeter Guo 	scratch_32 &= ~O2_SD_FREG0_LEDOFF;
170706adf6bSPeter Guo 	pci_write_config_dword(chip->pdev,
171706adf6bSPeter Guo 			       O2_SD_FUNC_REG0, scratch_32);
172706adf6bSPeter Guo 
173706adf6bSPeter Guo 	ret = pci_read_config_dword(chip->pdev,
174706adf6bSPeter Guo 				    O2_SD_TEST_REG, &scratch_32);
175706adf6bSPeter Guo 	if (ret)
176706adf6bSPeter Guo 		return;
177706adf6bSPeter Guo 
178706adf6bSPeter Guo 	scratch_32 |= O2_SD_LED_ENABLE;
179706adf6bSPeter Guo 	pci_write_config_dword(chip->pdev,
180706adf6bSPeter Guo 			       O2_SD_TEST_REG, scratch_32);
181706adf6bSPeter Guo 
182706adf6bSPeter Guo }
183706adf6bSPeter Guo 
184f0cbd780SBen Hutchings static void sdhci_pci_o2_fujin2_pci_init(struct sdhci_pci_chip *chip)
18501acf691SAdam Lee {
18601acf691SAdam Lee 	u32 scratch_32;
18701acf691SAdam Lee 	int ret;
18801acf691SAdam Lee 	/* Improve write performance for SD3.0 */
18901acf691SAdam Lee 	ret = pci_read_config_dword(chip->pdev, O2_SD_DEV_CTRL, &scratch_32);
19001acf691SAdam Lee 	if (ret)
19101acf691SAdam Lee 		return;
19201acf691SAdam Lee 	scratch_32 &= ~((1 << 12) | (1 << 13) | (1 << 14));
19301acf691SAdam Lee 	pci_write_config_dword(chip->pdev, O2_SD_DEV_CTRL, scratch_32);
19401acf691SAdam Lee 
19501acf691SAdam Lee 	/* Enable Link abnormal reset generating Reset */
19601acf691SAdam Lee 	ret = pci_read_config_dword(chip->pdev, O2_SD_MISC_REG5, &scratch_32);
19701acf691SAdam Lee 	if (ret)
19801acf691SAdam Lee 		return;
19901acf691SAdam Lee 	scratch_32 &= ~((1 << 19) | (1 << 11));
20001acf691SAdam Lee 	scratch_32 |= (1 << 10);
20101acf691SAdam Lee 	pci_write_config_dword(chip->pdev, O2_SD_MISC_REG5, scratch_32);
20201acf691SAdam Lee 
20301acf691SAdam Lee 	/* set card power over current protection */
20401acf691SAdam Lee 	ret = pci_read_config_dword(chip->pdev, O2_SD_TEST_REG, &scratch_32);
20501acf691SAdam Lee 	if (ret)
20601acf691SAdam Lee 		return;
20701acf691SAdam Lee 	scratch_32 |= (1 << 4);
20801acf691SAdam Lee 	pci_write_config_dword(chip->pdev, O2_SD_TEST_REG, scratch_32);
20901acf691SAdam Lee 
21001acf691SAdam Lee 	/* adjust the output delay for SD mode */
21101acf691SAdam Lee 	pci_write_config_dword(chip->pdev, O2_SD_DELAY_CTRL, 0x00002492);
21201acf691SAdam Lee 
21301acf691SAdam Lee 	/* Set the output voltage setting of Aux 1.2v LDO */
21401acf691SAdam Lee 	ret = pci_read_config_dword(chip->pdev, O2_SD_LD0_CTRL, &scratch_32);
21501acf691SAdam Lee 	if (ret)
21601acf691SAdam Lee 		return;
21701acf691SAdam Lee 	scratch_32 &= ~(3 << 12);
21801acf691SAdam Lee 	pci_write_config_dword(chip->pdev, O2_SD_LD0_CTRL, scratch_32);
21901acf691SAdam Lee 
22001acf691SAdam Lee 	/* Set Max power supply capability of SD host */
22101acf691SAdam Lee 	ret = pci_read_config_dword(chip->pdev, O2_SD_CAP_REG0, &scratch_32);
22201acf691SAdam Lee 	if (ret)
22301acf691SAdam Lee 		return;
22401acf691SAdam Lee 	scratch_32 &= ~(0x01FE);
22501acf691SAdam Lee 	scratch_32 |= 0x00CC;
22601acf691SAdam Lee 	pci_write_config_dword(chip->pdev, O2_SD_CAP_REG0, scratch_32);
22701acf691SAdam Lee 	/* Set DLL Tuning Window */
22801acf691SAdam Lee 	ret = pci_read_config_dword(chip->pdev,
22901acf691SAdam Lee 				    O2_SD_TUNING_CTRL, &scratch_32);
23001acf691SAdam Lee 	if (ret)
23101acf691SAdam Lee 		return;
23201acf691SAdam Lee 	scratch_32 &= ~(0x000000FF);
23301acf691SAdam Lee 	scratch_32 |= 0x00000066;
23401acf691SAdam Lee 	pci_write_config_dword(chip->pdev, O2_SD_TUNING_CTRL, scratch_32);
23501acf691SAdam Lee 
23601acf691SAdam Lee 	/* Set UHS2 T_EIDLE */
23701acf691SAdam Lee 	ret = pci_read_config_dword(chip->pdev,
23801acf691SAdam Lee 				    O2_SD_UHS2_L1_CTRL, &scratch_32);
23901acf691SAdam Lee 	if (ret)
24001acf691SAdam Lee 		return;
24101acf691SAdam Lee 	scratch_32 &= ~(0x000000FC);
24201acf691SAdam Lee 	scratch_32 |= 0x00000084;
24301acf691SAdam Lee 	pci_write_config_dword(chip->pdev, O2_SD_UHS2_L1_CTRL, scratch_32);
24401acf691SAdam Lee 
24501acf691SAdam Lee 	/* Set UHS2 Termination */
24601acf691SAdam Lee 	ret = pci_read_config_dword(chip->pdev, O2_SD_FUNC_REG3, &scratch_32);
24701acf691SAdam Lee 	if (ret)
24801acf691SAdam Lee 		return;
24901acf691SAdam Lee 	scratch_32 &= ~((1 << 21) | (1 << 30));
25001acf691SAdam Lee 
25101acf691SAdam Lee 	pci_write_config_dword(chip->pdev, O2_SD_FUNC_REG3, scratch_32);
25201acf691SAdam Lee 
25301acf691SAdam Lee 	/* Set L1 Entrance Timer */
25401acf691SAdam Lee 	ret = pci_read_config_dword(chip->pdev, O2_SD_CAPS, &scratch_32);
25501acf691SAdam Lee 	if (ret)
25601acf691SAdam Lee 		return;
25701acf691SAdam Lee 	scratch_32 &= ~(0xf0000000);
25801acf691SAdam Lee 	scratch_32 |= 0x30000000;
25901acf691SAdam Lee 	pci_write_config_dword(chip->pdev, O2_SD_CAPS, scratch_32);
26001acf691SAdam Lee 
26101acf691SAdam Lee 	ret = pci_read_config_dword(chip->pdev,
26201acf691SAdam Lee 				    O2_SD_MISC_CTRL4, &scratch_32);
26301acf691SAdam Lee 	if (ret)
26401acf691SAdam Lee 		return;
26501acf691SAdam Lee 	scratch_32 &= ~(0x000f0000);
26601acf691SAdam Lee 	scratch_32 |= 0x00080000;
26701acf691SAdam Lee 	pci_write_config_dword(chip->pdev, O2_SD_MISC_CTRL4, scratch_32);
26801acf691SAdam Lee }
26901acf691SAdam Lee 
27002a3c0bdSernest.zhang static void sdhci_pci_o2_enable_msi(struct sdhci_pci_chip *chip,
27102a3c0bdSernest.zhang 				    struct sdhci_host *host)
27202a3c0bdSernest.zhang {
27302a3c0bdSernest.zhang 	int ret;
27402a3c0bdSernest.zhang 
27502a3c0bdSernest.zhang 	ret = pci_find_capability(chip->pdev, PCI_CAP_ID_MSI);
27602a3c0bdSernest.zhang 	if (!ret) {
27702a3c0bdSernest.zhang 		pr_info("%s: unsupport msi, use INTx irq\n",
27802a3c0bdSernest.zhang 			mmc_hostname(host->mmc));
27902a3c0bdSernest.zhang 		return;
28002a3c0bdSernest.zhang 	}
28102a3c0bdSernest.zhang 
28202a3c0bdSernest.zhang 	ret = pci_alloc_irq_vectors(chip->pdev, 1, 1,
28302a3c0bdSernest.zhang 				    PCI_IRQ_MSI | PCI_IRQ_MSIX);
28402a3c0bdSernest.zhang 	if (ret < 0) {
28502a3c0bdSernest.zhang 		pr_err("%s: enable PCI MSI failed, err=%d\n",
28602a3c0bdSernest.zhang 		       mmc_hostname(host->mmc), ret);
28702a3c0bdSernest.zhang 		return;
28802a3c0bdSernest.zhang 	}
28902a3c0bdSernest.zhang 
29002a3c0bdSernest.zhang 	host->irq = pci_irq_vector(chip->pdev, 0);
29102a3c0bdSernest.zhang }
29202a3c0bdSernest.zhang 
29369d91ed1SErnest Zhang(WH) static void sdhci_o2_wait_card_detect_stable(struct sdhci_host *host)
29469d91ed1SErnest Zhang(WH) {
29569d91ed1SErnest Zhang(WH) 	ktime_t timeout;
29669d91ed1SErnest Zhang(WH) 	u32 scratch32;
29769d91ed1SErnest Zhang(WH) 
29869d91ed1SErnest Zhang(WH) 	/* Wait max 50 ms */
29969d91ed1SErnest Zhang(WH) 	timeout = ktime_add_ms(ktime_get(), 50);
30069d91ed1SErnest Zhang(WH) 	while (1) {
30169d91ed1SErnest Zhang(WH) 		bool timedout = ktime_after(ktime_get(), timeout);
30269d91ed1SErnest Zhang(WH) 
30369d91ed1SErnest Zhang(WH) 		scratch32 = sdhci_readl(host, SDHCI_PRESENT_STATE);
30469d91ed1SErnest Zhang(WH) 		if ((scratch32 & SDHCI_CARD_PRESENT) >> SDHCI_CARD_PRES_SHIFT
30569d91ed1SErnest Zhang(WH) 		    == (scratch32 & SDHCI_CD_LVL) >> SDHCI_CD_LVL_SHIFT)
30669d91ed1SErnest Zhang(WH) 			break;
30769d91ed1SErnest Zhang(WH) 
30869d91ed1SErnest Zhang(WH) 		if (timedout) {
30969d91ed1SErnest Zhang(WH) 			pr_err("%s: Card Detect debounce never finished.\n",
31069d91ed1SErnest Zhang(WH) 			       mmc_hostname(host->mmc));
31169d91ed1SErnest Zhang(WH) 			sdhci_dumpregs(host);
31269d91ed1SErnest Zhang(WH) 			return;
31369d91ed1SErnest Zhang(WH) 		}
31469d91ed1SErnest Zhang(WH) 		udelay(10);
31569d91ed1SErnest Zhang(WH) 	}
31669d91ed1SErnest Zhang(WH) }
31769d91ed1SErnest Zhang(WH) 
31869d91ed1SErnest Zhang(WH) static void sdhci_o2_enable_internal_clock(struct sdhci_host *host)
31969d91ed1SErnest Zhang(WH) {
32069d91ed1SErnest Zhang(WH) 	ktime_t timeout;
32169d91ed1SErnest Zhang(WH) 	u16 scratch;
32269d91ed1SErnest Zhang(WH) 	u32 scratch32;
32369d91ed1SErnest Zhang(WH) 
32469d91ed1SErnest Zhang(WH) 	/* PLL software reset */
32569d91ed1SErnest Zhang(WH) 	scratch32 = sdhci_readl(host, O2_PLL_WDT_CONTROL1);
32669d91ed1SErnest Zhang(WH) 	scratch32 |= O2_PLL_SOFT_RESET;
32769d91ed1SErnest Zhang(WH) 	sdhci_writel(host, scratch32, O2_PLL_WDT_CONTROL1);
32869d91ed1SErnest Zhang(WH) 	udelay(1);
32969d91ed1SErnest Zhang(WH) 	scratch32 &= ~(O2_PLL_SOFT_RESET);
33069d91ed1SErnest Zhang(WH) 	sdhci_writel(host, scratch32, O2_PLL_WDT_CONTROL1);
33169d91ed1SErnest Zhang(WH) 
33269d91ed1SErnest Zhang(WH) 	/* PLL force active */
33369d91ed1SErnest Zhang(WH) 	scratch32 |= O2_PLL_FORCE_ACTIVE;
33469d91ed1SErnest Zhang(WH) 	sdhci_writel(host, scratch32, O2_PLL_WDT_CONTROL1);
33569d91ed1SErnest Zhang(WH) 
33669d91ed1SErnest Zhang(WH) 	/* Wait max 20 ms */
33769d91ed1SErnest Zhang(WH) 	timeout = ktime_add_ms(ktime_get(), 20);
33869d91ed1SErnest Zhang(WH) 	while (1) {
33969d91ed1SErnest Zhang(WH) 		bool timedout = ktime_after(ktime_get(), timeout);
34069d91ed1SErnest Zhang(WH) 
34169d91ed1SErnest Zhang(WH) 		scratch = sdhci_readw(host, O2_PLL_WDT_CONTROL1);
34269d91ed1SErnest Zhang(WH) 		if (scratch & O2_PLL_LOCK_STATUS)
34369d91ed1SErnest Zhang(WH) 			break;
34469d91ed1SErnest Zhang(WH) 		if (timedout) {
34569d91ed1SErnest Zhang(WH) 			pr_err("%s: Internal clock never stabilised.\n",
34669d91ed1SErnest Zhang(WH) 			       mmc_hostname(host->mmc));
34769d91ed1SErnest Zhang(WH) 			sdhci_dumpregs(host);
34869d91ed1SErnest Zhang(WH) 			goto out;
34969d91ed1SErnest Zhang(WH) 		}
35069d91ed1SErnest Zhang(WH) 		udelay(10);
35169d91ed1SErnest Zhang(WH) 	}
35269d91ed1SErnest Zhang(WH) 
35369d91ed1SErnest Zhang(WH) 	/* Wait for card detect finish */
35469d91ed1SErnest Zhang(WH) 	udelay(1);
35569d91ed1SErnest Zhang(WH) 	sdhci_o2_wait_card_detect_stable(host);
35669d91ed1SErnest Zhang(WH) 
35769d91ed1SErnest Zhang(WH) out:
35869d91ed1SErnest Zhang(WH) 	/* Cancel PLL force active */
35969d91ed1SErnest Zhang(WH) 	scratch32 = sdhci_readl(host, O2_PLL_WDT_CONTROL1);
36069d91ed1SErnest Zhang(WH) 	scratch32 &= ~O2_PLL_FORCE_ACTIVE;
36169d91ed1SErnest Zhang(WH) 	sdhci_writel(host, scratch32, O2_PLL_WDT_CONTROL1);
36269d91ed1SErnest Zhang(WH) }
36369d91ed1SErnest Zhang(WH) 
36469d91ed1SErnest Zhang(WH) static int sdhci_o2_get_cd(struct mmc_host *mmc)
36569d91ed1SErnest Zhang(WH) {
36669d91ed1SErnest Zhang(WH) 	struct sdhci_host *host = mmc_priv(mmc);
36769d91ed1SErnest Zhang(WH) 
36869d91ed1SErnest Zhang(WH) 	sdhci_o2_enable_internal_clock(host);
36969d91ed1SErnest Zhang(WH) 
37069d91ed1SErnest Zhang(WH) 	return !!(sdhci_readl(host, SDHCI_PRESENT_STATE) & SDHCI_CARD_PRESENT);
37169d91ed1SErnest Zhang(WH) }
37269d91ed1SErnest Zhang(WH) 
37369d91ed1SErnest Zhang(WH) static void sdhci_o2_enable_clk(struct sdhci_host *host, u16 clk)
37469d91ed1SErnest Zhang(WH) {
37569d91ed1SErnest Zhang(WH) 	/* Enable internal clock */
37669d91ed1SErnest Zhang(WH) 	clk |= SDHCI_CLOCK_INT_EN;
37769d91ed1SErnest Zhang(WH) 	sdhci_writew(host, clk, SDHCI_CLOCK_CONTROL);
37869d91ed1SErnest Zhang(WH) 
37969d91ed1SErnest Zhang(WH) 	if (sdhci_o2_get_cd(host->mmc)) {
38069d91ed1SErnest Zhang(WH) 		clk |= SDHCI_CLOCK_CARD_EN;
38169d91ed1SErnest Zhang(WH) 		sdhci_writew(host, clk, SDHCI_CLOCK_CONTROL);
38269d91ed1SErnest Zhang(WH) 	}
38369d91ed1SErnest Zhang(WH) }
38469d91ed1SErnest Zhang(WH) 
38569d91ed1SErnest Zhang(WH) void sdhci_pci_o2_set_clock(struct sdhci_host *host, unsigned int clock)
38669d91ed1SErnest Zhang(WH) {
38769d91ed1SErnest Zhang(WH) 	u16 clk;
38869d91ed1SErnest Zhang(WH) 
38969d91ed1SErnest Zhang(WH) 	host->mmc->actual_clock = 0;
39069d91ed1SErnest Zhang(WH) 
39169d91ed1SErnest Zhang(WH) 	sdhci_writew(host, 0, SDHCI_CLOCK_CONTROL);
39269d91ed1SErnest Zhang(WH) 
39369d91ed1SErnest Zhang(WH) 	if (clock == 0)
39469d91ed1SErnest Zhang(WH) 		return;
39569d91ed1SErnest Zhang(WH) 
39669d91ed1SErnest Zhang(WH) 	clk = sdhci_calc_clk(host, clock, &host->mmc->actual_clock);
39769d91ed1SErnest Zhang(WH) 	sdhci_o2_enable_clk(host, clk);
39869d91ed1SErnest Zhang(WH) }
39969d91ed1SErnest Zhang(WH) 
40001acf691SAdam Lee int sdhci_pci_o2_probe_slot(struct sdhci_pci_slot *slot)
40101acf691SAdam Lee {
40201acf691SAdam Lee 	struct sdhci_pci_chip *chip;
40301acf691SAdam Lee 	struct sdhci_host *host;
40401acf691SAdam Lee 	u32 reg;
40557322d54Sernest.zhang 	int ret;
40601acf691SAdam Lee 
40701acf691SAdam Lee 	chip = slot->chip;
40801acf691SAdam Lee 	host = slot->host;
40901acf691SAdam Lee 	switch (chip->pdev->device) {
41001acf691SAdam Lee 	case PCI_DEVICE_ID_O2_SDS0:
41101acf691SAdam Lee 	case PCI_DEVICE_ID_O2_SEABIRD0:
41201acf691SAdam Lee 	case PCI_DEVICE_ID_O2_SEABIRD1:
41301acf691SAdam Lee 	case PCI_DEVICE_ID_O2_SDS1:
41401acf691SAdam Lee 	case PCI_DEVICE_ID_O2_FUJIN2:
41501acf691SAdam Lee 		reg = sdhci_readl(host, O2_SD_VENDOR_SETTING);
41601acf691SAdam Lee 		if (reg & 0x1)
41701acf691SAdam Lee 			host->quirks |= SDHCI_QUIRK_MULTIBLOCK_READ_ACMD12;
41801acf691SAdam Lee 
41902a3c0bdSernest.zhang 		sdhci_pci_o2_enable_msi(chip, host);
42002a3c0bdSernest.zhang 
42157322d54Sernest.zhang 		if (chip->pdev->device == PCI_DEVICE_ID_O2_SEABIRD0) {
42257322d54Sernest.zhang 			ret = pci_read_config_dword(chip->pdev,
42357322d54Sernest.zhang 						    O2_SD_MISC_SETTING, &reg);
42457322d54Sernest.zhang 			if (ret)
42557322d54Sernest.zhang 				return -EIO;
42657322d54Sernest.zhang 			if (reg & (1 << 4)) {
42757322d54Sernest.zhang 				pr_info("%s: emmc 1.8v flag is set, force 1.8v signaling voltage\n",
42857322d54Sernest.zhang 					mmc_hostname(host->mmc));
42957322d54Sernest.zhang 				host->flags &= ~SDHCI_SIGNALING_330;
43057322d54Sernest.zhang 				host->flags |= SDHCI_SIGNALING_180;
431*414126f9SErnest Zhang(WH) 				host->quirks2 |= SDHCI_QUIRK2_CLEAR_TRANSFERMODE_REG_BEFORE_CMD;
43257322d54Sernest.zhang 				host->mmc->caps2 |= MMC_CAP2_NO_SD;
43357322d54Sernest.zhang 				host->mmc->caps2 |= MMC_CAP2_NO_SDIO;
43469d91ed1SErnest Zhang(WH) 				pci_write_config_dword(chip->pdev,
43569d91ed1SErnest Zhang(WH) 						       O2_SD_DETECT_SETTING, 3);
43657322d54Sernest.zhang 			}
43769d91ed1SErnest Zhang(WH) 
43869d91ed1SErnest Zhang(WH) 			slot->host->mmc_host_ops.get_cd = sdhci_o2_get_cd;
43957322d54Sernest.zhang 		}
44057322d54Sernest.zhang 
4410086fc21Sernest.zhang 		host->mmc_host_ops.execute_tuning = sdhci_o2_execute_tuning;
4420086fc21Sernest.zhang 
44301acf691SAdam Lee 		if (chip->pdev->device != PCI_DEVICE_ID_O2_FUJIN2)
44401acf691SAdam Lee 			break;
44501acf691SAdam Lee 		/* set dll watch dog timer */
44601acf691SAdam Lee 		reg = sdhci_readl(host, O2_SD_VENDOR_SETTING2);
44701acf691SAdam Lee 		reg |= (1 << 12);
44801acf691SAdam Lee 		sdhci_writel(host, reg, O2_SD_VENDOR_SETTING2);
44901acf691SAdam Lee 
45001acf691SAdam Lee 		break;
45101acf691SAdam Lee 	default:
45201acf691SAdam Lee 		break;
45301acf691SAdam Lee 	}
45401acf691SAdam Lee 
45501acf691SAdam Lee 	return 0;
45601acf691SAdam Lee }
45701acf691SAdam Lee 
45801acf691SAdam Lee int sdhci_pci_o2_probe(struct sdhci_pci_chip *chip)
45901acf691SAdam Lee {
46001acf691SAdam Lee 	int ret;
46101acf691SAdam Lee 	u8 scratch;
46201acf691SAdam Lee 	u32 scratch_32;
46301acf691SAdam Lee 
46401acf691SAdam Lee 	switch (chip->pdev->device) {
46501acf691SAdam Lee 	case PCI_DEVICE_ID_O2_8220:
46601acf691SAdam Lee 	case PCI_DEVICE_ID_O2_8221:
46701acf691SAdam Lee 	case PCI_DEVICE_ID_O2_8320:
46801acf691SAdam Lee 	case PCI_DEVICE_ID_O2_8321:
46901acf691SAdam Lee 		/* This extra setup is required due to broken ADMA. */
47001acf691SAdam Lee 		ret = pci_read_config_byte(chip->pdev,
47101acf691SAdam Lee 				O2_SD_LOCK_WP, &scratch);
47201acf691SAdam Lee 		if (ret)
47301acf691SAdam Lee 			return ret;
47401acf691SAdam Lee 		scratch &= 0x7f;
47501acf691SAdam Lee 		pci_write_config_byte(chip->pdev, O2_SD_LOCK_WP, scratch);
47601acf691SAdam Lee 
47701acf691SAdam Lee 		/* Set Multi 3 to VCC3V# */
47801acf691SAdam Lee 		pci_write_config_byte(chip->pdev, O2_SD_MULTI_VCC3V, 0x08);
47901acf691SAdam Lee 
48001acf691SAdam Lee 		/* Disable CLK_REQ# support after media DET */
48101acf691SAdam Lee 		ret = pci_read_config_byte(chip->pdev,
48201acf691SAdam Lee 				O2_SD_CLKREQ, &scratch);
48301acf691SAdam Lee 		if (ret)
48401acf691SAdam Lee 			return ret;
48501acf691SAdam Lee 		scratch |= 0x20;
48601acf691SAdam Lee 		pci_write_config_byte(chip->pdev, O2_SD_CLKREQ, scratch);
48701acf691SAdam Lee 
48801acf691SAdam Lee 		/* Choose capabilities, enable SDMA.  We have to write 0x01
48901acf691SAdam Lee 		 * to the capabilities register first to unlock it.
49001acf691SAdam Lee 		 */
49101acf691SAdam Lee 		ret = pci_read_config_byte(chip->pdev, O2_SD_CAPS, &scratch);
49201acf691SAdam Lee 		if (ret)
49301acf691SAdam Lee 			return ret;
49401acf691SAdam Lee 		scratch |= 0x01;
49501acf691SAdam Lee 		pci_write_config_byte(chip->pdev, O2_SD_CAPS, scratch);
49601acf691SAdam Lee 		pci_write_config_byte(chip->pdev, O2_SD_CAPS, 0x73);
49701acf691SAdam Lee 
49801acf691SAdam Lee 		/* Disable ADMA1/2 */
49901acf691SAdam Lee 		pci_write_config_byte(chip->pdev, O2_SD_ADMA1, 0x39);
50001acf691SAdam Lee 		pci_write_config_byte(chip->pdev, O2_SD_ADMA2, 0x08);
50101acf691SAdam Lee 
50201acf691SAdam Lee 		/* Disable the infinite transfer mode */
50301acf691SAdam Lee 		ret = pci_read_config_byte(chip->pdev,
50401acf691SAdam Lee 				O2_SD_INF_MOD, &scratch);
50501acf691SAdam Lee 		if (ret)
50601acf691SAdam Lee 			return ret;
50701acf691SAdam Lee 		scratch |= 0x08;
50801acf691SAdam Lee 		pci_write_config_byte(chip->pdev, O2_SD_INF_MOD, scratch);
50901acf691SAdam Lee 
51001acf691SAdam Lee 		/* Lock WP */
51101acf691SAdam Lee 		ret = pci_read_config_byte(chip->pdev,
51201acf691SAdam Lee 				O2_SD_LOCK_WP, &scratch);
51301acf691SAdam Lee 		if (ret)
51401acf691SAdam Lee 			return ret;
51501acf691SAdam Lee 		scratch |= 0x80;
51601acf691SAdam Lee 		pci_write_config_byte(chip->pdev, O2_SD_LOCK_WP, scratch);
51701acf691SAdam Lee 		break;
51801acf691SAdam Lee 	case PCI_DEVICE_ID_O2_SDS0:
51901acf691SAdam Lee 	case PCI_DEVICE_ID_O2_SDS1:
52001acf691SAdam Lee 	case PCI_DEVICE_ID_O2_FUJIN2:
52101acf691SAdam Lee 		/* UnLock WP */
52201acf691SAdam Lee 		ret = pci_read_config_byte(chip->pdev,
52301acf691SAdam Lee 				O2_SD_LOCK_WP, &scratch);
52401acf691SAdam Lee 		if (ret)
52501acf691SAdam Lee 			return ret;
52601acf691SAdam Lee 
52701acf691SAdam Lee 		scratch &= 0x7f;
52801acf691SAdam Lee 		pci_write_config_byte(chip->pdev, O2_SD_LOCK_WP, scratch);
52901acf691SAdam Lee 
530706adf6bSPeter Guo 		/* DevId=8520 subId= 0x11 or 0x12  Type Chip support */
531706adf6bSPeter Guo 		if (chip->pdev->device == PCI_DEVICE_ID_O2_FUJIN2) {
532706adf6bSPeter Guo 			ret = pci_read_config_dword(chip->pdev,
533706adf6bSPeter Guo 						    O2_SD_FUNC_REG0,
534706adf6bSPeter Guo 						    &scratch_32);
535706adf6bSPeter Guo 			scratch_32 = ((scratch_32 & 0xFF000000) >> 24);
536706adf6bSPeter Guo 
537706adf6bSPeter Guo 			/* Check Whether subId is 0x11 or 0x12 */
538706adf6bSPeter Guo 			if ((scratch_32 == 0x11) || (scratch_32 == 0x12)) {
5393665ff03Sernest.zhang 				scratch_32 = 0x25100000;
540706adf6bSPeter Guo 
541706adf6bSPeter Guo 				o2_pci_set_baseclk(chip, scratch_32);
542706adf6bSPeter Guo 				ret = pci_read_config_dword(chip->pdev,
543706adf6bSPeter Guo 							    O2_SD_FUNC_REG4,
544706adf6bSPeter Guo 							    &scratch_32);
545706adf6bSPeter Guo 
546706adf6bSPeter Guo 				/* Enable Base Clk setting change */
547706adf6bSPeter Guo 				scratch_32 |= O2_SD_FREG4_ENABLE_CLK_SET;
548706adf6bSPeter Guo 				pci_write_config_dword(chip->pdev,
549706adf6bSPeter Guo 						       O2_SD_FUNC_REG4,
550706adf6bSPeter Guo 						       scratch_32);
551706adf6bSPeter Guo 
552706adf6bSPeter Guo 				/* Set Tuning Window to 4 */
553706adf6bSPeter Guo 				pci_write_config_byte(chip->pdev,
554706adf6bSPeter Guo 						      O2_SD_TUNING_CTRL, 0x44);
555706adf6bSPeter Guo 
556706adf6bSPeter Guo 				break;
557706adf6bSPeter Guo 			}
558706adf6bSPeter Guo 		}
559706adf6bSPeter Guo 
560706adf6bSPeter Guo 		/* Enable 8520 led function */
561706adf6bSPeter Guo 		o2_pci_led_enable(chip);
562706adf6bSPeter Guo 
56301acf691SAdam Lee 		/* Set timeout CLK */
56401acf691SAdam Lee 		ret = pci_read_config_dword(chip->pdev,
56501acf691SAdam Lee 					    O2_SD_CLK_SETTING, &scratch_32);
56601acf691SAdam Lee 		if (ret)
56701acf691SAdam Lee 			return ret;
56801acf691SAdam Lee 
56901acf691SAdam Lee 		scratch_32 &= ~(0xFF00);
57001acf691SAdam Lee 		scratch_32 |= 0x07E0C800;
57101acf691SAdam Lee 		pci_write_config_dword(chip->pdev,
57201acf691SAdam Lee 				       O2_SD_CLK_SETTING, scratch_32);
57301acf691SAdam Lee 
57401acf691SAdam Lee 		ret = pci_read_config_dword(chip->pdev,
57501acf691SAdam Lee 					    O2_SD_CLKREQ, &scratch_32);
57601acf691SAdam Lee 		if (ret)
57701acf691SAdam Lee 			return ret;
57801acf691SAdam Lee 		scratch_32 |= 0x3;
57901acf691SAdam Lee 		pci_write_config_dword(chip->pdev, O2_SD_CLKREQ, scratch_32);
58001acf691SAdam Lee 
58101acf691SAdam Lee 		ret = pci_read_config_dword(chip->pdev,
58201acf691SAdam Lee 					    O2_SD_PLL_SETTING, &scratch_32);
58301acf691SAdam Lee 		if (ret)
58401acf691SAdam Lee 			return ret;
58501acf691SAdam Lee 
58601acf691SAdam Lee 		scratch_32 &= ~(0x1F3F070E);
58701acf691SAdam Lee 		scratch_32 |= 0x18270106;
58801acf691SAdam Lee 		pci_write_config_dword(chip->pdev,
58901acf691SAdam Lee 				       O2_SD_PLL_SETTING, scratch_32);
59001acf691SAdam Lee 
59101acf691SAdam Lee 		/* Disable UHS1 funciton */
59201acf691SAdam Lee 		ret = pci_read_config_dword(chip->pdev,
59301acf691SAdam Lee 					    O2_SD_CAP_REG2, &scratch_32);
59401acf691SAdam Lee 		if (ret)
59501acf691SAdam Lee 			return ret;
59601acf691SAdam Lee 		scratch_32 &= ~(0xE0);
59701acf691SAdam Lee 		pci_write_config_dword(chip->pdev,
59801acf691SAdam Lee 				       O2_SD_CAP_REG2, scratch_32);
59901acf691SAdam Lee 
60001acf691SAdam Lee 		if (chip->pdev->device == PCI_DEVICE_ID_O2_FUJIN2)
60101acf691SAdam Lee 			sdhci_pci_o2_fujin2_pci_init(chip);
60201acf691SAdam Lee 
60301acf691SAdam Lee 		/* Lock WP */
60401acf691SAdam Lee 		ret = pci_read_config_byte(chip->pdev,
60501acf691SAdam Lee 					   O2_SD_LOCK_WP, &scratch);
60601acf691SAdam Lee 		if (ret)
60701acf691SAdam Lee 			return ret;
60801acf691SAdam Lee 		scratch |= 0x80;
60901acf691SAdam Lee 		pci_write_config_byte(chip->pdev, O2_SD_LOCK_WP, scratch);
61001acf691SAdam Lee 		break;
61101acf691SAdam Lee 	case PCI_DEVICE_ID_O2_SEABIRD0:
61201acf691SAdam Lee 	case PCI_DEVICE_ID_O2_SEABIRD1:
61301acf691SAdam Lee 		/* UnLock WP */
61401acf691SAdam Lee 		ret = pci_read_config_byte(chip->pdev,
61501acf691SAdam Lee 				O2_SD_LOCK_WP, &scratch);
61601acf691SAdam Lee 		if (ret)
61701acf691SAdam Lee 			return ret;
61801acf691SAdam Lee 
61901acf691SAdam Lee 		scratch &= 0x7f;
62001acf691SAdam Lee 		pci_write_config_byte(chip->pdev, O2_SD_LOCK_WP, scratch);
62101acf691SAdam Lee 
62201acf691SAdam Lee 		ret = pci_read_config_dword(chip->pdev,
623706adf6bSPeter Guo 					    O2_SD_PLL_SETTING, &scratch_32);
62401acf691SAdam Lee 
62501acf691SAdam Lee 		if ((scratch_32 & 0xff000000) == 0x01000000) {
62601acf691SAdam Lee 			scratch_32 &= 0x0000FFFF;
62701acf691SAdam Lee 			scratch_32 |= 0x1F340000;
62801acf691SAdam Lee 
62901acf691SAdam Lee 			pci_write_config_dword(chip->pdev,
63001acf691SAdam Lee 					       O2_SD_PLL_SETTING, scratch_32);
63101acf691SAdam Lee 		} else {
63201acf691SAdam Lee 			scratch_32 &= 0x0000FFFF;
6333665ff03Sernest.zhang 			scratch_32 |= 0x25100000;
63401acf691SAdam Lee 
63501acf691SAdam Lee 			pci_write_config_dword(chip->pdev,
63601acf691SAdam Lee 					       O2_SD_PLL_SETTING, scratch_32);
63701acf691SAdam Lee 
63801acf691SAdam Lee 			ret = pci_read_config_dword(chip->pdev,
63901acf691SAdam Lee 						    O2_SD_FUNC_REG4,
64001acf691SAdam Lee 						    &scratch_32);
64101acf691SAdam Lee 			scratch_32 |= (1 << 22);
64201acf691SAdam Lee 			pci_write_config_dword(chip->pdev,
64301acf691SAdam Lee 					       O2_SD_FUNC_REG4, scratch_32);
64401acf691SAdam Lee 		}
64501acf691SAdam Lee 
646706adf6bSPeter Guo 		/* Set Tuning Windows to 5 */
647706adf6bSPeter Guo 		pci_write_config_byte(chip->pdev,
648706adf6bSPeter Guo 				O2_SD_TUNING_CTRL, 0x55);
64901acf691SAdam Lee 		/* Lock WP */
65001acf691SAdam Lee 		ret = pci_read_config_byte(chip->pdev,
65101acf691SAdam Lee 					   O2_SD_LOCK_WP, &scratch);
65201acf691SAdam Lee 		if (ret)
65301acf691SAdam Lee 			return ret;
65401acf691SAdam Lee 		scratch |= 0x80;
65501acf691SAdam Lee 		pci_write_config_byte(chip->pdev, O2_SD_LOCK_WP, scratch);
65601acf691SAdam Lee 		break;
65701acf691SAdam Lee 	}
65801acf691SAdam Lee 
65901acf691SAdam Lee 	return 0;
66001acf691SAdam Lee }
66101acf691SAdam Lee 
662b7813f0fSAdrian Hunter #ifdef CONFIG_PM_SLEEP
66301acf691SAdam Lee int sdhci_pci_o2_resume(struct sdhci_pci_chip *chip)
66401acf691SAdam Lee {
66501acf691SAdam Lee 	sdhci_pci_o2_probe(chip);
66630cf2803SAdrian Hunter 	return sdhci_pci_resume_host(chip);
66701acf691SAdam Lee }
668b7813f0fSAdrian Hunter #endif
669328be8beSErnest Zhang(WH) 
67069d91ed1SErnest Zhang(WH) static const struct sdhci_ops sdhci_pci_o2_ops = {
67169d91ed1SErnest Zhang(WH) 	.set_clock = sdhci_pci_o2_set_clock,
67269d91ed1SErnest Zhang(WH) 	.enable_dma = sdhci_pci_enable_dma,
67369d91ed1SErnest Zhang(WH) 	.set_bus_width = sdhci_set_bus_width,
67469d91ed1SErnest Zhang(WH) 	.reset = sdhci_reset,
67569d91ed1SErnest Zhang(WH) 	.set_uhs_signaling = sdhci_set_uhs_signaling,
67669d91ed1SErnest Zhang(WH) };
67769d91ed1SErnest Zhang(WH) 
678328be8beSErnest Zhang(WH) const struct sdhci_pci_fixes sdhci_o2 = {
679328be8beSErnest Zhang(WH) 	.probe = sdhci_pci_o2_probe,
680328be8beSErnest Zhang(WH) 	.quirks = SDHCI_QUIRK_NO_ENDATTR_IN_NOPDESC,
681328be8beSErnest Zhang(WH) 	.probe_slot = sdhci_pci_o2_probe_slot,
682328be8beSErnest Zhang(WH) #ifdef CONFIG_PM_SLEEP
683328be8beSErnest Zhang(WH) 	.resume = sdhci_pci_o2_resume,
684328be8beSErnest Zhang(WH) #endif
68569d91ed1SErnest Zhang(WH) 	.ops = &sdhci_pci_o2_ops,
686328be8beSErnest Zhang(WH) };
687