xref: /openbmc/linux/drivers/mmc/host/sdhci_am654.c (revision 61d9c4aa)
141fd4caeSFaiz Abbas // SPDX-License-Identifier: GPL-2.0
241fd4caeSFaiz Abbas /*
341fd4caeSFaiz Abbas  * sdhci_am654.c - SDHCI driver for TI's AM654 SOCs
441fd4caeSFaiz Abbas  *
541fd4caeSFaiz Abbas  * Copyright (C) 2018 Texas Instruments Incorporated - http://www.ti.com
641fd4caeSFaiz Abbas  *
741fd4caeSFaiz Abbas  */
841fd4caeSFaiz Abbas #include <linux/clk.h>
999909b55SFaiz Abbas #include <linux/of.h>
1041fd4caeSFaiz Abbas #include <linux/module.h>
1141fd4caeSFaiz Abbas #include <linux/pm_runtime.h>
1241fd4caeSFaiz Abbas #include <linux/property.h>
1341fd4caeSFaiz Abbas #include <linux/regmap.h>
1409db9943SFaiz Abbas #include <linux/sys_soc.h>
1541fd4caeSFaiz Abbas 
16f545702bSFaiz Abbas #include "cqhci.h"
1741fd4caeSFaiz Abbas #include "sdhci-pltfm.h"
1841fd4caeSFaiz Abbas 
1941fd4caeSFaiz Abbas /* CTL_CFG Registers */
2041fd4caeSFaiz Abbas #define CTL_CFG_2		0x14
2141fd4caeSFaiz Abbas 
2241fd4caeSFaiz Abbas #define SLOTTYPE_MASK		GENMASK(31, 30)
2341fd4caeSFaiz Abbas #define SLOTTYPE_EMBEDDED	BIT(30)
2441fd4caeSFaiz Abbas 
2541fd4caeSFaiz Abbas /* PHY Registers */
2641fd4caeSFaiz Abbas #define PHY_CTRL1	0x100
2741fd4caeSFaiz Abbas #define PHY_CTRL2	0x104
2841fd4caeSFaiz Abbas #define PHY_CTRL3	0x108
2941fd4caeSFaiz Abbas #define PHY_CTRL4	0x10C
3041fd4caeSFaiz Abbas #define PHY_CTRL5	0x110
3141fd4caeSFaiz Abbas #define PHY_CTRL6	0x114
3241fd4caeSFaiz Abbas #define PHY_STAT1	0x130
3341fd4caeSFaiz Abbas #define PHY_STAT2	0x134
3441fd4caeSFaiz Abbas 
3541fd4caeSFaiz Abbas #define IOMUX_ENABLE_SHIFT	31
3641fd4caeSFaiz Abbas #define IOMUX_ENABLE_MASK	BIT(IOMUX_ENABLE_SHIFT)
3741fd4caeSFaiz Abbas #define OTAPDLYENA_SHIFT	20
3841fd4caeSFaiz Abbas #define OTAPDLYENA_MASK		BIT(OTAPDLYENA_SHIFT)
3941fd4caeSFaiz Abbas #define OTAPDLYSEL_SHIFT	12
4041fd4caeSFaiz Abbas #define OTAPDLYSEL_MASK		GENMASK(15, 12)
4141fd4caeSFaiz Abbas #define STRBSEL_SHIFT		24
4299909b55SFaiz Abbas #define STRBSEL_4BIT_MASK	GENMASK(27, 24)
4399909b55SFaiz Abbas #define STRBSEL_8BIT_MASK	GENMASK(31, 24)
4441fd4caeSFaiz Abbas #define SEL50_SHIFT		8
4541fd4caeSFaiz Abbas #define SEL50_MASK		BIT(SEL50_SHIFT)
4641fd4caeSFaiz Abbas #define SEL100_SHIFT		9
4741fd4caeSFaiz Abbas #define SEL100_MASK		BIT(SEL100_SHIFT)
4899909b55SFaiz Abbas #define FREQSEL_SHIFT		8
4999909b55SFaiz Abbas #define FREQSEL_MASK		GENMASK(10, 8)
5061d9c4aaSFaiz Abbas #define CLKBUFSEL_SHIFT		0
5161d9c4aaSFaiz Abbas #define CLKBUFSEL_MASK		GENMASK(2, 0)
5241fd4caeSFaiz Abbas #define DLL_TRIM_ICP_SHIFT	4
5341fd4caeSFaiz Abbas #define DLL_TRIM_ICP_MASK	GENMASK(7, 4)
5441fd4caeSFaiz Abbas #define DR_TY_SHIFT		20
5541fd4caeSFaiz Abbas #define DR_TY_MASK		GENMASK(22, 20)
5641fd4caeSFaiz Abbas #define ENDLL_SHIFT		1
5741fd4caeSFaiz Abbas #define ENDLL_MASK		BIT(ENDLL_SHIFT)
5841fd4caeSFaiz Abbas #define DLLRDY_SHIFT		0
5941fd4caeSFaiz Abbas #define DLLRDY_MASK		BIT(DLLRDY_SHIFT)
6041fd4caeSFaiz Abbas #define PDB_SHIFT		0
6141fd4caeSFaiz Abbas #define PDB_MASK		BIT(PDB_SHIFT)
6241fd4caeSFaiz Abbas #define CALDONE_SHIFT		1
6341fd4caeSFaiz Abbas #define CALDONE_MASK		BIT(CALDONE_SHIFT)
6441fd4caeSFaiz Abbas #define RETRIM_SHIFT		17
6541fd4caeSFaiz Abbas #define RETRIM_MASK		BIT(RETRIM_SHIFT)
660003417dSFaiz Abbas #define SELDLYTXCLK_SHIFT	17
670003417dSFaiz Abbas #define SELDLYTXCLK_MASK	BIT(SELDLYTXCLK_SHIFT)
6841fd4caeSFaiz Abbas 
6941fd4caeSFaiz Abbas #define DRIVER_STRENGTH_50_OHM	0x0
7041fd4caeSFaiz Abbas #define DRIVER_STRENGTH_33_OHM	0x1
7141fd4caeSFaiz Abbas #define DRIVER_STRENGTH_66_OHM	0x2
7241fd4caeSFaiz Abbas #define DRIVER_STRENGTH_100_OHM	0x3
7341fd4caeSFaiz Abbas #define DRIVER_STRENGTH_40_OHM	0x4
7441fd4caeSFaiz Abbas 
7541fd4caeSFaiz Abbas #define CLOCK_TOO_SLOW_HZ	400000
7641fd4caeSFaiz Abbas 
77f545702bSFaiz Abbas /* Command Queue Host Controller Interface Base address */
78f545702bSFaiz Abbas #define SDHCI_AM654_CQE_BASE_ADDR 0x200
79f545702bSFaiz Abbas 
8041fd4caeSFaiz Abbas static struct regmap_config sdhci_am654_regmap_config = {
8141fd4caeSFaiz Abbas 	.reg_bits = 32,
8241fd4caeSFaiz Abbas 	.val_bits = 32,
8341fd4caeSFaiz Abbas 	.reg_stride = 4,
8441fd4caeSFaiz Abbas 	.fast_io = true,
8541fd4caeSFaiz Abbas };
8641fd4caeSFaiz Abbas 
8741fd4caeSFaiz Abbas struct sdhci_am654_data {
8841fd4caeSFaiz Abbas 	struct regmap *base;
898ee5fc0eSFaiz Abbas 	bool legacy_otapdly;
908ee5fc0eSFaiz Abbas 	int otap_del_sel[11];
9161d9c4aaSFaiz Abbas 	int clkbuf_sel;
9241fd4caeSFaiz Abbas 	int trm_icp;
9341fd4caeSFaiz Abbas 	int drv_strength;
9441fd4caeSFaiz Abbas 	bool dll_on;
9599909b55SFaiz Abbas 	int strb_sel;
9699909b55SFaiz Abbas 	u32 flags;
9799909b55SFaiz Abbas };
9899909b55SFaiz Abbas 
9999909b55SFaiz Abbas struct sdhci_am654_driver_data {
10099909b55SFaiz Abbas 	const struct sdhci_pltfm_data *pdata;
10199909b55SFaiz Abbas 	u32 flags;
10299909b55SFaiz Abbas #define IOMUX_PRESENT	(1 << 0)
10399909b55SFaiz Abbas #define FREQSEL_2_BIT	(1 << 1)
10499909b55SFaiz Abbas #define STRBSEL_4_BIT	(1 << 2)
1051accbcedSFaiz Abbas #define DLL_PRESENT	(1 << 3)
10623514731SFaiz Abbas #define DLL_CALIB	(1 << 4)
10741fd4caeSFaiz Abbas };
10841fd4caeSFaiz Abbas 
1098ee5fc0eSFaiz Abbas struct timing_data {
1108ee5fc0eSFaiz Abbas 	const char *binding;
1118ee5fc0eSFaiz Abbas 	u32 capability;
1128ee5fc0eSFaiz Abbas };
1138ee5fc0eSFaiz Abbas 
1148ee5fc0eSFaiz Abbas static const struct timing_data td[] = {
1158ee5fc0eSFaiz Abbas 	[MMC_TIMING_LEGACY] = {"ti,otap-del-sel-legacy", 0},
1168ee5fc0eSFaiz Abbas 	[MMC_TIMING_MMC_HS] = {"ti,otap-del-sel-mmc-hs", MMC_CAP_MMC_HIGHSPEED},
1178ee5fc0eSFaiz Abbas 	[MMC_TIMING_SD_HS]  = {"ti,otap-del-sel-sd-hs", MMC_CAP_SD_HIGHSPEED},
1188ee5fc0eSFaiz Abbas 	[MMC_TIMING_UHS_SDR12] = {"ti,otap-del-sel-sdr12", MMC_CAP_UHS_SDR12},
1198ee5fc0eSFaiz Abbas 	[MMC_TIMING_UHS_SDR25] = {"ti,otap-del-sel-sdr25", MMC_CAP_UHS_SDR25},
1208ee5fc0eSFaiz Abbas 	[MMC_TIMING_UHS_SDR50] = {"ti,otap-del-sel-sdr50", MMC_CAP_UHS_SDR50},
1218ee5fc0eSFaiz Abbas 	[MMC_TIMING_UHS_SDR104] = {"ti,otap-del-sel-sdr104",
1228ee5fc0eSFaiz Abbas 				   MMC_CAP_UHS_SDR104},
1238ee5fc0eSFaiz Abbas 	[MMC_TIMING_UHS_DDR50] = {"ti,otap-del-sel-ddr50", MMC_CAP_UHS_DDR50},
1248ee5fc0eSFaiz Abbas 	[MMC_TIMING_MMC_DDR52] = {"ti,otap-del-sel-ddr52", MMC_CAP_DDR},
1258ee5fc0eSFaiz Abbas 	[MMC_TIMING_MMC_HS200] = {"ti,otap-del-sel-hs200", MMC_CAP2_HS200},
1268ee5fc0eSFaiz Abbas 	[MMC_TIMING_MMC_HS400] = {"ti,otap-del-sel-hs400", MMC_CAP2_HS400},
1278ee5fc0eSFaiz Abbas };
1288ee5fc0eSFaiz Abbas 
129a161c45fSFaiz Abbas static void sdhci_am654_setup_dll(struct sdhci_host *host, unsigned int clock)
130a161c45fSFaiz Abbas {
131a161c45fSFaiz Abbas 	struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
132a161c45fSFaiz Abbas 	struct sdhci_am654_data *sdhci_am654 = sdhci_pltfm_priv(pltfm_host);
133a161c45fSFaiz Abbas 	int sel50, sel100, freqsel;
134a161c45fSFaiz Abbas 	u32 mask, val;
135a161c45fSFaiz Abbas 	int ret;
136a161c45fSFaiz Abbas 
137a161c45fSFaiz Abbas 	if (sdhci_am654->flags & FREQSEL_2_BIT) {
138a161c45fSFaiz Abbas 		switch (clock) {
139a161c45fSFaiz Abbas 		case 200000000:
140a161c45fSFaiz Abbas 			sel50 = 0;
141a161c45fSFaiz Abbas 			sel100 = 0;
142a161c45fSFaiz Abbas 			break;
143a161c45fSFaiz Abbas 		case 100000000:
144a161c45fSFaiz Abbas 			sel50 = 0;
145a161c45fSFaiz Abbas 			sel100 = 1;
146a161c45fSFaiz Abbas 			break;
147a161c45fSFaiz Abbas 		default:
148a161c45fSFaiz Abbas 			sel50 = 1;
149a161c45fSFaiz Abbas 			sel100 = 0;
150a161c45fSFaiz Abbas 		}
151a161c45fSFaiz Abbas 
152a161c45fSFaiz Abbas 		/* Configure PHY DLL frequency */
153a161c45fSFaiz Abbas 		mask = SEL50_MASK | SEL100_MASK;
154a161c45fSFaiz Abbas 		val = (sel50 << SEL50_SHIFT) | (sel100 << SEL100_SHIFT);
155a161c45fSFaiz Abbas 		regmap_update_bits(sdhci_am654->base, PHY_CTRL5, mask, val);
156a161c45fSFaiz Abbas 
157a161c45fSFaiz Abbas 	} else {
158a161c45fSFaiz Abbas 		switch (clock) {
159a161c45fSFaiz Abbas 		case 200000000:
160a161c45fSFaiz Abbas 			freqsel = 0x0;
161a161c45fSFaiz Abbas 			break;
162a161c45fSFaiz Abbas 		default:
163a161c45fSFaiz Abbas 			freqsel = 0x4;
164a161c45fSFaiz Abbas 		}
165a161c45fSFaiz Abbas 
166a161c45fSFaiz Abbas 		regmap_update_bits(sdhci_am654->base, PHY_CTRL5, FREQSEL_MASK,
167a161c45fSFaiz Abbas 				   freqsel << FREQSEL_SHIFT);
168a161c45fSFaiz Abbas 	}
169a161c45fSFaiz Abbas 	/* Configure DLL TRIM */
170a161c45fSFaiz Abbas 	mask = DLL_TRIM_ICP_MASK;
171a161c45fSFaiz Abbas 	val = sdhci_am654->trm_icp << DLL_TRIM_ICP_SHIFT;
172a161c45fSFaiz Abbas 
173a161c45fSFaiz Abbas 	/* Configure DLL driver strength */
174a161c45fSFaiz Abbas 	mask |= DR_TY_MASK;
175a161c45fSFaiz Abbas 	val |= sdhci_am654->drv_strength << DR_TY_SHIFT;
176a161c45fSFaiz Abbas 	regmap_update_bits(sdhci_am654->base, PHY_CTRL1, mask, val);
177a161c45fSFaiz Abbas 
178a161c45fSFaiz Abbas 	/* Enable DLL */
179a161c45fSFaiz Abbas 	regmap_update_bits(sdhci_am654->base, PHY_CTRL1, ENDLL_MASK,
180a161c45fSFaiz Abbas 			   0x1 << ENDLL_SHIFT);
181a161c45fSFaiz Abbas 	/*
182a161c45fSFaiz Abbas 	 * Poll for DLL ready. Use a one second timeout.
183a161c45fSFaiz Abbas 	 * Works in all experiments done so far
184a161c45fSFaiz Abbas 	 */
185a161c45fSFaiz Abbas 	ret = regmap_read_poll_timeout(sdhci_am654->base, PHY_STAT1, val,
186a161c45fSFaiz Abbas 				       val & DLLRDY_MASK, 1000, 1000000);
187a161c45fSFaiz Abbas 	if (ret) {
188a161c45fSFaiz Abbas 		dev_err(mmc_dev(host->mmc), "DLL failed to relock\n");
189a161c45fSFaiz Abbas 		return;
190a161c45fSFaiz Abbas 	}
191a161c45fSFaiz Abbas 
192a161c45fSFaiz Abbas 	sdhci_am654->dll_on = true;
193a161c45fSFaiz Abbas }
194a161c45fSFaiz Abbas 
19541fd4caeSFaiz Abbas static void sdhci_am654_set_clock(struct sdhci_host *host, unsigned int clock)
19641fd4caeSFaiz Abbas {
19741fd4caeSFaiz Abbas 	struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
19841fd4caeSFaiz Abbas 	struct sdhci_am654_data *sdhci_am654 = sdhci_pltfm_priv(pltfm_host);
1998ee5fc0eSFaiz Abbas 	unsigned char timing = host->mmc->ios.timing;
2008ee5fc0eSFaiz Abbas 	u32 otap_del_sel;
2018ee5fc0eSFaiz Abbas 	u32 otap_del_ena;
20241fd4caeSFaiz Abbas 	u32 mask, val;
20341fd4caeSFaiz Abbas 
20441fd4caeSFaiz Abbas 	if (sdhci_am654->dll_on) {
2058023cf26SFaiz Abbas 		regmap_update_bits(sdhci_am654->base, PHY_CTRL1, ENDLL_MASK, 0);
20641fd4caeSFaiz Abbas 
20741fd4caeSFaiz Abbas 		sdhci_am654->dll_on = false;
20841fd4caeSFaiz Abbas 	}
20941fd4caeSFaiz Abbas 
21041fd4caeSFaiz Abbas 	sdhci_set_clock(host, clock);
21141fd4caeSFaiz Abbas 
21241fd4caeSFaiz Abbas 	/* Setup DLL Output TAP delay */
2138ee5fc0eSFaiz Abbas 	if (sdhci_am654->legacy_otapdly)
2148ee5fc0eSFaiz Abbas 		otap_del_sel = sdhci_am654->otap_del_sel[0];
21599909b55SFaiz Abbas 	else
2168ee5fc0eSFaiz Abbas 		otap_del_sel = sdhci_am654->otap_del_sel[timing];
21799909b55SFaiz Abbas 
2188ee5fc0eSFaiz Abbas 	otap_del_ena = (timing > MMC_TIMING_UHS_SDR25) ? 1 : 0;
2198ee5fc0eSFaiz Abbas 
2208ee5fc0eSFaiz Abbas 	mask = OTAPDLYENA_MASK | OTAPDLYSEL_MASK;
2218ee5fc0eSFaiz Abbas 	val = (otap_del_ena << OTAPDLYENA_SHIFT) |
2228ee5fc0eSFaiz Abbas 	      (otap_del_sel << OTAPDLYSEL_SHIFT);
2238ee5fc0eSFaiz Abbas 
2248ee5fc0eSFaiz Abbas 	/* Write to STRBSEL for HS400 speed mode */
2258ee5fc0eSFaiz Abbas 	if (timing == MMC_TIMING_MMC_HS400) {
2268ee5fc0eSFaiz Abbas 		if (sdhci_am654->flags & STRBSEL_4_BIT)
2278ee5fc0eSFaiz Abbas 			mask |= STRBSEL_4BIT_MASK;
2288ee5fc0eSFaiz Abbas 		else
2298ee5fc0eSFaiz Abbas 			mask |= STRBSEL_8BIT_MASK;
2308ee5fc0eSFaiz Abbas 
2318ee5fc0eSFaiz Abbas 		val |= sdhci_am654->strb_sel << STRBSEL_SHIFT;
23299909b55SFaiz Abbas 	}
23399909b55SFaiz Abbas 
2348ee5fc0eSFaiz Abbas 	regmap_update_bits(sdhci_am654->base, PHY_CTRL4, mask, val);
2358ee5fc0eSFaiz Abbas 
2360003417dSFaiz Abbas 	if (timing > MMC_TIMING_UHS_SDR25 && clock > CLOCK_TOO_SLOW_HZ) {
2370003417dSFaiz Abbas 		regmap_update_bits(sdhci_am654->base, PHY_CTRL5,
2380003417dSFaiz Abbas 				   SELDLYTXCLK_MASK, 0);
239a161c45fSFaiz Abbas 		sdhci_am654_setup_dll(host, clock);
2400003417dSFaiz Abbas 	} else {
2410003417dSFaiz Abbas 		regmap_update_bits(sdhci_am654->base, PHY_CTRL5,
2420003417dSFaiz Abbas 				   SELDLYTXCLK_MASK, 1 << SELDLYTXCLK_SHIFT);
2430003417dSFaiz Abbas 	}
24461d9c4aaSFaiz Abbas 
24561d9c4aaSFaiz Abbas 	regmap_update_bits(sdhci_am654->base, PHY_CTRL5, CLKBUFSEL_MASK,
24661d9c4aaSFaiz Abbas 			   sdhci_am654->clkbuf_sel);
24741fd4caeSFaiz Abbas }
24841fd4caeSFaiz Abbas 
2498751c8bdSYueHaibing static void sdhci_j721e_4bit_set_clock(struct sdhci_host *host,
2508751c8bdSYueHaibing 				       unsigned int clock)
2511accbcedSFaiz Abbas {
2521accbcedSFaiz Abbas 	struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
2531accbcedSFaiz Abbas 	struct sdhci_am654_data *sdhci_am654 = sdhci_pltfm_priv(pltfm_host);
2548ee5fc0eSFaiz Abbas 	unsigned char timing = host->mmc->ios.timing;
2558ee5fc0eSFaiz Abbas 	u32 otap_del_sel;
2568ee5fc0eSFaiz Abbas 	u32 mask, val;
2578ee5fc0eSFaiz Abbas 
2588ee5fc0eSFaiz Abbas 	/* Setup DLL Output TAP delay */
2598ee5fc0eSFaiz Abbas 	if (sdhci_am654->legacy_otapdly)
2608ee5fc0eSFaiz Abbas 		otap_del_sel = sdhci_am654->otap_del_sel[0];
2618ee5fc0eSFaiz Abbas 	else
2628ee5fc0eSFaiz Abbas 		otap_del_sel = sdhci_am654->otap_del_sel[timing];
2631accbcedSFaiz Abbas 
2641accbcedSFaiz Abbas 	mask = OTAPDLYENA_MASK | OTAPDLYSEL_MASK;
2658ee5fc0eSFaiz Abbas 	val = (0x1 << OTAPDLYENA_SHIFT) |
2668ee5fc0eSFaiz Abbas 	      (otap_del_sel << OTAPDLYSEL_SHIFT);
2671accbcedSFaiz Abbas 	regmap_update_bits(sdhci_am654->base, PHY_CTRL4, mask, val);
2681accbcedSFaiz Abbas 
26961d9c4aaSFaiz Abbas 	regmap_update_bits(sdhci_am654->base, PHY_CTRL5, CLKBUFSEL_MASK,
27061d9c4aaSFaiz Abbas 			   sdhci_am654->clkbuf_sel);
27161d9c4aaSFaiz Abbas 
2721accbcedSFaiz Abbas 	sdhci_set_clock(host, clock);
2731accbcedSFaiz Abbas }
2741accbcedSFaiz Abbas 
275e374e875SFaiz Abbas static void sdhci_am654_write_b(struct sdhci_host *host, u8 val, int reg)
276e374e875SFaiz Abbas {
277e374e875SFaiz Abbas 	unsigned char timing = host->mmc->ios.timing;
278e374e875SFaiz Abbas 
279e374e875SFaiz Abbas 	if (reg == SDHCI_HOST_CONTROL) {
280e374e875SFaiz Abbas 		switch (timing) {
281e374e875SFaiz Abbas 		/*
282e374e875SFaiz Abbas 		 * According to the data manual, HISPD bit
283e374e875SFaiz Abbas 		 * should not be set in these speed modes.
284e374e875SFaiz Abbas 		 */
285e374e875SFaiz Abbas 		case MMC_TIMING_SD_HS:
286e374e875SFaiz Abbas 		case MMC_TIMING_MMC_HS:
287e374e875SFaiz Abbas 		case MMC_TIMING_UHS_SDR12:
288e374e875SFaiz Abbas 		case MMC_TIMING_UHS_SDR25:
289e374e875SFaiz Abbas 			val &= ~SDHCI_CTRL_HISPD;
290e374e875SFaiz Abbas 		}
291e374e875SFaiz Abbas 	}
292e374e875SFaiz Abbas 
293e374e875SFaiz Abbas 	writeb(val, host->ioaddr + reg);
294e374e875SFaiz Abbas }
295e374e875SFaiz Abbas 
296de31f6abSFaiz Abbas static int sdhci_am654_execute_tuning(struct mmc_host *mmc, u32 opcode)
297de31f6abSFaiz Abbas {
298de31f6abSFaiz Abbas 	struct sdhci_host *host = mmc_priv(mmc);
299de31f6abSFaiz Abbas 	int err = sdhci_execute_tuning(mmc, opcode);
30041fd4caeSFaiz Abbas 
301de31f6abSFaiz Abbas 	if (err)
302de31f6abSFaiz Abbas 		return err;
303de31f6abSFaiz Abbas 	/*
304de31f6abSFaiz Abbas 	 * Tuning data remains in the buffer after tuning.
305de31f6abSFaiz Abbas 	 * Do a command and data reset to get rid of it
306de31f6abSFaiz Abbas 	 */
307de31f6abSFaiz Abbas 	sdhci_reset(host, SDHCI_RESET_CMD | SDHCI_RESET_DATA);
30841fd4caeSFaiz Abbas 
309de31f6abSFaiz Abbas 	return 0;
310de31f6abSFaiz Abbas }
31199909b55SFaiz Abbas 
312f545702bSFaiz Abbas static u32 sdhci_am654_cqhci_irq(struct sdhci_host *host, u32 intmask)
313f545702bSFaiz Abbas {
314f545702bSFaiz Abbas 	int cmd_error = 0;
315f545702bSFaiz Abbas 	int data_error = 0;
316f545702bSFaiz Abbas 
317f545702bSFaiz Abbas 	if (!sdhci_cqe_irq(host, intmask, &cmd_error, &data_error))
318f545702bSFaiz Abbas 		return intmask;
319f545702bSFaiz Abbas 
320f545702bSFaiz Abbas 	cqhci_irq(host->mmc, intmask, cmd_error, data_error);
321f545702bSFaiz Abbas 
322f545702bSFaiz Abbas 	return 0;
323f545702bSFaiz Abbas }
324f545702bSFaiz Abbas 
32541fd4caeSFaiz Abbas static struct sdhci_ops sdhci_am654_ops = {
32641fd4caeSFaiz Abbas 	.get_max_clock = sdhci_pltfm_clk_get_max_clock,
32741fd4caeSFaiz Abbas 	.get_timeout_clock = sdhci_pltfm_clk_get_max_clock,
32841fd4caeSFaiz Abbas 	.set_uhs_signaling = sdhci_set_uhs_signaling,
32941fd4caeSFaiz Abbas 	.set_bus_width = sdhci_set_bus_width,
3309d8acdd3SNicolas Saenz Julienne 	.set_power = sdhci_set_power_and_bus_voltage,
33141fd4caeSFaiz Abbas 	.set_clock = sdhci_am654_set_clock,
33241fd4caeSFaiz Abbas 	.write_b = sdhci_am654_write_b,
33327f4e1e9SFaiz Abbas 	.irq = sdhci_am654_cqhci_irq,
33441fd4caeSFaiz Abbas 	.reset = sdhci_reset,
33541fd4caeSFaiz Abbas };
33641fd4caeSFaiz Abbas 
33741fd4caeSFaiz Abbas static const struct sdhci_pltfm_data sdhci_am654_pdata = {
33841fd4caeSFaiz Abbas 	.ops = &sdhci_am654_ops,
3394d627c88SFaiz Abbas 	.quirks = SDHCI_QUIRK_MULTIBLOCK_READ_ACMD12,
34041fd4caeSFaiz Abbas 	.quirks2 = SDHCI_QUIRK2_PRESET_VALUE_BROKEN,
34141fd4caeSFaiz Abbas };
34241fd4caeSFaiz Abbas 
34309db9943SFaiz Abbas static const struct sdhci_am654_driver_data sdhci_am654_sr1_drvdata = {
34441fd4caeSFaiz Abbas 	.pdata = &sdhci_am654_pdata,
34523514731SFaiz Abbas 	.flags = IOMUX_PRESENT | FREQSEL_2_BIT | STRBSEL_4_BIT | DLL_PRESENT |
34623514731SFaiz Abbas 		 DLL_CALIB,
34741fd4caeSFaiz Abbas };
34841fd4caeSFaiz Abbas 
34909db9943SFaiz Abbas static const struct sdhci_am654_driver_data sdhci_am654_drvdata = {
35009db9943SFaiz Abbas 	.pdata = &sdhci_am654_pdata,
35109db9943SFaiz Abbas 	.flags = IOMUX_PRESENT | FREQSEL_2_BIT | STRBSEL_4_BIT | DLL_PRESENT,
35209db9943SFaiz Abbas };
35309db9943SFaiz Abbas 
3548751c8bdSYueHaibing static struct sdhci_ops sdhci_j721e_8bit_ops = {
35599909b55SFaiz Abbas 	.get_max_clock = sdhci_pltfm_clk_get_max_clock,
35699909b55SFaiz Abbas 	.get_timeout_clock = sdhci_pltfm_clk_get_max_clock,
35799909b55SFaiz Abbas 	.set_uhs_signaling = sdhci_set_uhs_signaling,
35899909b55SFaiz Abbas 	.set_bus_width = sdhci_set_bus_width,
3599d8acdd3SNicolas Saenz Julienne 	.set_power = sdhci_set_power_and_bus_voltage,
36099909b55SFaiz Abbas 	.set_clock = sdhci_am654_set_clock,
36199909b55SFaiz Abbas 	.write_b = sdhci_am654_write_b,
362f545702bSFaiz Abbas 	.irq = sdhci_am654_cqhci_irq,
36399909b55SFaiz Abbas 	.reset = sdhci_reset,
36499909b55SFaiz Abbas };
36599909b55SFaiz Abbas 
36699909b55SFaiz Abbas static const struct sdhci_pltfm_data sdhci_j721e_8bit_pdata = {
36799909b55SFaiz Abbas 	.ops = &sdhci_j721e_8bit_ops,
3684d627c88SFaiz Abbas 	.quirks = SDHCI_QUIRK_MULTIBLOCK_READ_ACMD12,
36999909b55SFaiz Abbas 	.quirks2 = SDHCI_QUIRK2_PRESET_VALUE_BROKEN,
37099909b55SFaiz Abbas };
37199909b55SFaiz Abbas 
37299909b55SFaiz Abbas static const struct sdhci_am654_driver_data sdhci_j721e_8bit_drvdata = {
37399909b55SFaiz Abbas 	.pdata = &sdhci_j721e_8bit_pdata,
37423514731SFaiz Abbas 	.flags = DLL_PRESENT | DLL_CALIB,
37599909b55SFaiz Abbas };
37699909b55SFaiz Abbas 
3778751c8bdSYueHaibing static struct sdhci_ops sdhci_j721e_4bit_ops = {
3781accbcedSFaiz Abbas 	.get_max_clock = sdhci_pltfm_clk_get_max_clock,
3791accbcedSFaiz Abbas 	.get_timeout_clock = sdhci_pltfm_clk_get_max_clock,
3801accbcedSFaiz Abbas 	.set_uhs_signaling = sdhci_set_uhs_signaling,
3811accbcedSFaiz Abbas 	.set_bus_width = sdhci_set_bus_width,
3829d8acdd3SNicolas Saenz Julienne 	.set_power = sdhci_set_power_and_bus_voltage,
3831accbcedSFaiz Abbas 	.set_clock = sdhci_j721e_4bit_set_clock,
3841accbcedSFaiz Abbas 	.write_b = sdhci_am654_write_b,
385f545702bSFaiz Abbas 	.irq = sdhci_am654_cqhci_irq,
3861accbcedSFaiz Abbas 	.reset = sdhci_reset,
3871accbcedSFaiz Abbas };
3881accbcedSFaiz Abbas 
3891accbcedSFaiz Abbas static const struct sdhci_pltfm_data sdhci_j721e_4bit_pdata = {
3901accbcedSFaiz Abbas 	.ops = &sdhci_j721e_4bit_ops,
3914d627c88SFaiz Abbas 	.quirks = SDHCI_QUIRK_MULTIBLOCK_READ_ACMD12,
3921accbcedSFaiz Abbas 	.quirks2 = SDHCI_QUIRK2_PRESET_VALUE_BROKEN,
3931accbcedSFaiz Abbas };
3941accbcedSFaiz Abbas 
3951accbcedSFaiz Abbas static const struct sdhci_am654_driver_data sdhci_j721e_4bit_drvdata = {
3961accbcedSFaiz Abbas 	.pdata = &sdhci_j721e_4bit_pdata,
3971accbcedSFaiz Abbas 	.flags = IOMUX_PRESENT,
3981accbcedSFaiz Abbas };
399f545702bSFaiz Abbas 
40009db9943SFaiz Abbas static const struct soc_device_attribute sdhci_am654_devices[] = {
40109db9943SFaiz Abbas 	{ .family = "AM65X",
40209db9943SFaiz Abbas 	  .revision = "SR1.0",
40309db9943SFaiz Abbas 	  .data = &sdhci_am654_sr1_drvdata
40409db9943SFaiz Abbas 	},
40509db9943SFaiz Abbas 	{/* sentinel */}
40609db9943SFaiz Abbas };
40709db9943SFaiz Abbas 
408f545702bSFaiz Abbas static void sdhci_am654_dumpregs(struct mmc_host *mmc)
409f545702bSFaiz Abbas {
410f545702bSFaiz Abbas 	sdhci_dumpregs(mmc_priv(mmc));
411f545702bSFaiz Abbas }
412f545702bSFaiz Abbas 
413f545702bSFaiz Abbas static const struct cqhci_host_ops sdhci_am654_cqhci_ops = {
414f545702bSFaiz Abbas 	.enable		= sdhci_cqe_enable,
415f545702bSFaiz Abbas 	.disable	= sdhci_cqe_disable,
416f545702bSFaiz Abbas 	.dumpregs	= sdhci_am654_dumpregs,
417f545702bSFaiz Abbas };
418f545702bSFaiz Abbas 
419f545702bSFaiz Abbas static int sdhci_am654_cqe_add_host(struct sdhci_host *host)
420f545702bSFaiz Abbas {
421f545702bSFaiz Abbas 	struct cqhci_host *cq_host;
422f545702bSFaiz Abbas 	int ret;
423f545702bSFaiz Abbas 
424f545702bSFaiz Abbas 	cq_host = devm_kzalloc(host->mmc->parent, sizeof(struct cqhci_host),
425f545702bSFaiz Abbas 			       GFP_KERNEL);
426f545702bSFaiz Abbas 	if (!cq_host)
427f545702bSFaiz Abbas 		return -ENOMEM;
428f545702bSFaiz Abbas 
429f545702bSFaiz Abbas 	cq_host->mmio = host->ioaddr + SDHCI_AM654_CQE_BASE_ADDR;
430f545702bSFaiz Abbas 	cq_host->quirks |= CQHCI_QUIRK_SHORT_TXFR_DESC_SZ;
431f545702bSFaiz Abbas 	cq_host->caps |= CQHCI_TASK_DESC_SZ_128;
432f545702bSFaiz Abbas 	cq_host->ops = &sdhci_am654_cqhci_ops;
433f545702bSFaiz Abbas 
434f545702bSFaiz Abbas 	host->mmc->caps2 |= MMC_CAP2_CQE;
435f545702bSFaiz Abbas 
436f545702bSFaiz Abbas 	ret = cqhci_init(cq_host, host->mmc, 1);
437f545702bSFaiz Abbas 
438f545702bSFaiz Abbas 	return ret;
439f545702bSFaiz Abbas }
440f545702bSFaiz Abbas 
4418ee5fc0eSFaiz Abbas static int sdhci_am654_get_otap_delay(struct sdhci_host *host,
4428ee5fc0eSFaiz Abbas 				      struct sdhci_am654_data *sdhci_am654)
4438ee5fc0eSFaiz Abbas {
4448ee5fc0eSFaiz Abbas 	struct device *dev = mmc_dev(host->mmc);
4458ee5fc0eSFaiz Abbas 	int i;
4468ee5fc0eSFaiz Abbas 	int ret;
4478ee5fc0eSFaiz Abbas 
4488ee5fc0eSFaiz Abbas 	ret = device_property_read_u32(dev, td[MMC_TIMING_LEGACY].binding,
4498ee5fc0eSFaiz Abbas 				 &sdhci_am654->otap_del_sel[MMC_TIMING_LEGACY]);
4508ee5fc0eSFaiz Abbas 	if (ret) {
4518ee5fc0eSFaiz Abbas 		/*
4528ee5fc0eSFaiz Abbas 		 * ti,otap-del-sel-legacy is mandatory, look for old binding
4538ee5fc0eSFaiz Abbas 		 * if not found.
4548ee5fc0eSFaiz Abbas 		 */
4558ee5fc0eSFaiz Abbas 		ret = device_property_read_u32(dev, "ti,otap-del-sel",
4568ee5fc0eSFaiz Abbas 					       &sdhci_am654->otap_del_sel[0]);
4578ee5fc0eSFaiz Abbas 		if (ret) {
4588ee5fc0eSFaiz Abbas 			dev_err(dev, "Couldn't find otap-del-sel\n");
4598ee5fc0eSFaiz Abbas 
4608ee5fc0eSFaiz Abbas 			return ret;
4618ee5fc0eSFaiz Abbas 		}
4628ee5fc0eSFaiz Abbas 
4638ee5fc0eSFaiz Abbas 		dev_info(dev, "Using legacy binding ti,otap-del-sel\n");
4648ee5fc0eSFaiz Abbas 		sdhci_am654->legacy_otapdly = true;
4658ee5fc0eSFaiz Abbas 
4668ee5fc0eSFaiz Abbas 		return 0;
4678ee5fc0eSFaiz Abbas 	}
4688ee5fc0eSFaiz Abbas 
4698ee5fc0eSFaiz Abbas 	for (i = MMC_TIMING_MMC_HS; i <= MMC_TIMING_MMC_HS400; i++) {
4708ee5fc0eSFaiz Abbas 
4718ee5fc0eSFaiz Abbas 		ret = device_property_read_u32(dev, td[i].binding,
4728ee5fc0eSFaiz Abbas 					       &sdhci_am654->otap_del_sel[i]);
4738ee5fc0eSFaiz Abbas 		if (ret) {
4748ee5fc0eSFaiz Abbas 			dev_dbg(dev, "Couldn't find %s\n",
4758ee5fc0eSFaiz Abbas 				td[i].binding);
4768ee5fc0eSFaiz Abbas 			/*
4778ee5fc0eSFaiz Abbas 			 * Remove the corresponding capability
4788ee5fc0eSFaiz Abbas 			 * if an otap-del-sel value is not found
4798ee5fc0eSFaiz Abbas 			 */
4808ee5fc0eSFaiz Abbas 			if (i <= MMC_TIMING_MMC_DDR52)
4818ee5fc0eSFaiz Abbas 				host->mmc->caps &= ~td[i].capability;
4828ee5fc0eSFaiz Abbas 			else
4838ee5fc0eSFaiz Abbas 				host->mmc->caps2 &= ~td[i].capability;
4848ee5fc0eSFaiz Abbas 		}
4858ee5fc0eSFaiz Abbas 	}
4868ee5fc0eSFaiz Abbas 
4878ee5fc0eSFaiz Abbas 	return 0;
4888ee5fc0eSFaiz Abbas }
4898ee5fc0eSFaiz Abbas 
49041fd4caeSFaiz Abbas static int sdhci_am654_init(struct sdhci_host *host)
49141fd4caeSFaiz Abbas {
49241fd4caeSFaiz Abbas 	struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
49341fd4caeSFaiz Abbas 	struct sdhci_am654_data *sdhci_am654 = sdhci_pltfm_priv(pltfm_host);
49441fd4caeSFaiz Abbas 	u32 ctl_cfg_2 = 0;
49541fd4caeSFaiz Abbas 	u32 mask;
49641fd4caeSFaiz Abbas 	u32 val;
49741fd4caeSFaiz Abbas 	int ret;
49841fd4caeSFaiz Abbas 
49941fd4caeSFaiz Abbas 	/* Reset OTAP to default value */
50041fd4caeSFaiz Abbas 	mask = OTAPDLYENA_MASK | OTAPDLYSEL_MASK;
5018023cf26SFaiz Abbas 	regmap_update_bits(sdhci_am654->base, PHY_CTRL4, mask, 0x0);
50241fd4caeSFaiz Abbas 
50323514731SFaiz Abbas 	if (sdhci_am654->flags & DLL_CALIB) {
50441fd4caeSFaiz Abbas 		regmap_read(sdhci_am654->base, PHY_STAT1, &val);
50541fd4caeSFaiz Abbas 		if (~val & CALDONE_MASK) {
50641fd4caeSFaiz Abbas 			/* Calibrate IO lines */
50741fd4caeSFaiz Abbas 			regmap_update_bits(sdhci_am654->base, PHY_CTRL1,
50841fd4caeSFaiz Abbas 					   PDB_MASK, PDB_MASK);
5091accbcedSFaiz Abbas 			ret = regmap_read_poll_timeout(sdhci_am654->base,
5101accbcedSFaiz Abbas 						       PHY_STAT1, val,
5111accbcedSFaiz Abbas 						       val & CALDONE_MASK,
5121accbcedSFaiz Abbas 						       1, 20);
51341fd4caeSFaiz Abbas 			if (ret)
51441fd4caeSFaiz Abbas 				return ret;
51541fd4caeSFaiz Abbas 		}
5161accbcedSFaiz Abbas 	}
51741fd4caeSFaiz Abbas 
51841fd4caeSFaiz Abbas 	/* Enable pins by setting IO mux to 0 */
51999909b55SFaiz Abbas 	if (sdhci_am654->flags & IOMUX_PRESENT)
52099909b55SFaiz Abbas 		regmap_update_bits(sdhci_am654->base, PHY_CTRL1,
52199909b55SFaiz Abbas 				   IOMUX_ENABLE_MASK, 0);
52241fd4caeSFaiz Abbas 
52341fd4caeSFaiz Abbas 	/* Set slot type based on SD or eMMC */
52441fd4caeSFaiz Abbas 	if (host->mmc->caps & MMC_CAP_NONREMOVABLE)
52541fd4caeSFaiz Abbas 		ctl_cfg_2 = SLOTTYPE_EMBEDDED;
52641fd4caeSFaiz Abbas 
5278023cf26SFaiz Abbas 	regmap_update_bits(sdhci_am654->base, CTL_CFG_2, SLOTTYPE_MASK,
5288023cf26SFaiz Abbas 			   ctl_cfg_2);
52941fd4caeSFaiz Abbas 
530f545702bSFaiz Abbas 	ret = sdhci_setup_host(host);
531f545702bSFaiz Abbas 	if (ret)
532f545702bSFaiz Abbas 		return ret;
533f545702bSFaiz Abbas 
534f545702bSFaiz Abbas 	ret = sdhci_am654_cqe_add_host(host);
535f545702bSFaiz Abbas 	if (ret)
536f545702bSFaiz Abbas 		goto err_cleanup_host;
537f545702bSFaiz Abbas 
5388ee5fc0eSFaiz Abbas 	ret = sdhci_am654_get_otap_delay(host, sdhci_am654);
5398ee5fc0eSFaiz Abbas 	if (ret)
5408ee5fc0eSFaiz Abbas 		goto err_cleanup_host;
5418ee5fc0eSFaiz Abbas 
542f545702bSFaiz Abbas 	ret = __sdhci_add_host(host);
543f545702bSFaiz Abbas 	if (ret)
544f545702bSFaiz Abbas 		goto err_cleanup_host;
545f545702bSFaiz Abbas 
546f545702bSFaiz Abbas 	return 0;
547f545702bSFaiz Abbas 
548f545702bSFaiz Abbas err_cleanup_host:
549f545702bSFaiz Abbas 	sdhci_cleanup_host(host);
550f545702bSFaiz Abbas 	return ret;
55141fd4caeSFaiz Abbas }
55241fd4caeSFaiz Abbas 
55341fd4caeSFaiz Abbas static int sdhci_am654_get_of_property(struct platform_device *pdev,
55441fd4caeSFaiz Abbas 					struct sdhci_am654_data *sdhci_am654)
55541fd4caeSFaiz Abbas {
55641fd4caeSFaiz Abbas 	struct device *dev = &pdev->dev;
55741fd4caeSFaiz Abbas 	int drv_strength;
55841fd4caeSFaiz Abbas 	int ret;
55941fd4caeSFaiz Abbas 
5601accbcedSFaiz Abbas 	if (sdhci_am654->flags & DLL_PRESENT) {
5611accbcedSFaiz Abbas 		ret = device_property_read_u32(dev, "ti,trm-icp",
5621accbcedSFaiz Abbas 					       &sdhci_am654->trm_icp);
56341fd4caeSFaiz Abbas 		if (ret)
56441fd4caeSFaiz Abbas 			return ret;
56541fd4caeSFaiz Abbas 
56641fd4caeSFaiz Abbas 		ret = device_property_read_u32(dev, "ti,driver-strength-ohm",
56741fd4caeSFaiz Abbas 					       &drv_strength);
56841fd4caeSFaiz Abbas 		if (ret)
56941fd4caeSFaiz Abbas 			return ret;
57041fd4caeSFaiz Abbas 
57141fd4caeSFaiz Abbas 		switch (drv_strength) {
57241fd4caeSFaiz Abbas 		case 50:
57341fd4caeSFaiz Abbas 			sdhci_am654->drv_strength = DRIVER_STRENGTH_50_OHM;
57441fd4caeSFaiz Abbas 			break;
57541fd4caeSFaiz Abbas 		case 33:
57641fd4caeSFaiz Abbas 			sdhci_am654->drv_strength = DRIVER_STRENGTH_33_OHM;
57741fd4caeSFaiz Abbas 			break;
57841fd4caeSFaiz Abbas 		case 66:
57941fd4caeSFaiz Abbas 			sdhci_am654->drv_strength = DRIVER_STRENGTH_66_OHM;
58041fd4caeSFaiz Abbas 			break;
58141fd4caeSFaiz Abbas 		case 100:
58241fd4caeSFaiz Abbas 			sdhci_am654->drv_strength = DRIVER_STRENGTH_100_OHM;
58341fd4caeSFaiz Abbas 			break;
58441fd4caeSFaiz Abbas 		case 40:
58541fd4caeSFaiz Abbas 			sdhci_am654->drv_strength = DRIVER_STRENGTH_40_OHM;
58641fd4caeSFaiz Abbas 			break;
58741fd4caeSFaiz Abbas 		default:
58841fd4caeSFaiz Abbas 			dev_err(dev, "Invalid driver strength\n");
58941fd4caeSFaiz Abbas 			return -EINVAL;
59041fd4caeSFaiz Abbas 		}
5911accbcedSFaiz Abbas 	}
59241fd4caeSFaiz Abbas 
59399909b55SFaiz Abbas 	device_property_read_u32(dev, "ti,strobe-sel", &sdhci_am654->strb_sel);
59461d9c4aaSFaiz Abbas 	device_property_read_u32(dev, "ti,clkbuf-sel",
59561d9c4aaSFaiz Abbas 				 &sdhci_am654->clkbuf_sel);
59699909b55SFaiz Abbas 
59741fd4caeSFaiz Abbas 	sdhci_get_of_property(pdev);
59841fd4caeSFaiz Abbas 
59941fd4caeSFaiz Abbas 	return 0;
60041fd4caeSFaiz Abbas }
60141fd4caeSFaiz Abbas 
60299909b55SFaiz Abbas static const struct of_device_id sdhci_am654_of_match[] = {
60399909b55SFaiz Abbas 	{
60499909b55SFaiz Abbas 		.compatible = "ti,am654-sdhci-5.1",
60599909b55SFaiz Abbas 		.data = &sdhci_am654_drvdata,
60699909b55SFaiz Abbas 	},
60799909b55SFaiz Abbas 	{
60899909b55SFaiz Abbas 		.compatible = "ti,j721e-sdhci-8bit",
60999909b55SFaiz Abbas 		.data = &sdhci_j721e_8bit_drvdata,
61099909b55SFaiz Abbas 	},
6111accbcedSFaiz Abbas 	{
6121accbcedSFaiz Abbas 		.compatible = "ti,j721e-sdhci-4bit",
6131accbcedSFaiz Abbas 		.data = &sdhci_j721e_4bit_drvdata,
6141accbcedSFaiz Abbas 	},
61599909b55SFaiz Abbas 	{ /* sentinel */ }
61699909b55SFaiz Abbas };
61799909b55SFaiz Abbas 
61841fd4caeSFaiz Abbas static int sdhci_am654_probe(struct platform_device *pdev)
61941fd4caeSFaiz Abbas {
62099909b55SFaiz Abbas 	const struct sdhci_am654_driver_data *drvdata;
62109db9943SFaiz Abbas 	const struct soc_device_attribute *soc;
62241fd4caeSFaiz Abbas 	struct sdhci_pltfm_host *pltfm_host;
62341fd4caeSFaiz Abbas 	struct sdhci_am654_data *sdhci_am654;
62499909b55SFaiz Abbas 	const struct of_device_id *match;
62541fd4caeSFaiz Abbas 	struct sdhci_host *host;
62641fd4caeSFaiz Abbas 	struct clk *clk_xin;
62741fd4caeSFaiz Abbas 	struct device *dev = &pdev->dev;
62841fd4caeSFaiz Abbas 	void __iomem *base;
62941fd4caeSFaiz Abbas 	int ret;
63041fd4caeSFaiz Abbas 
63199909b55SFaiz Abbas 	match = of_match_node(sdhci_am654_of_match, pdev->dev.of_node);
63299909b55SFaiz Abbas 	drvdata = match->data;
63309db9943SFaiz Abbas 
63409db9943SFaiz Abbas 	/* Update drvdata based on SoC revision */
63509db9943SFaiz Abbas 	soc = soc_device_match(sdhci_am654_devices);
63609db9943SFaiz Abbas 	if (soc && soc->data)
63709db9943SFaiz Abbas 		drvdata = soc->data;
63809db9943SFaiz Abbas 
63999909b55SFaiz Abbas 	host = sdhci_pltfm_init(pdev, drvdata->pdata, sizeof(*sdhci_am654));
64041fd4caeSFaiz Abbas 	if (IS_ERR(host))
64141fd4caeSFaiz Abbas 		return PTR_ERR(host);
64241fd4caeSFaiz Abbas 
64341fd4caeSFaiz Abbas 	pltfm_host = sdhci_priv(host);
64441fd4caeSFaiz Abbas 	sdhci_am654 = sdhci_pltfm_priv(pltfm_host);
64599909b55SFaiz Abbas 	sdhci_am654->flags = drvdata->flags;
64641fd4caeSFaiz Abbas 
64741fd4caeSFaiz Abbas 	clk_xin = devm_clk_get(dev, "clk_xin");
64841fd4caeSFaiz Abbas 	if (IS_ERR(clk_xin)) {
64941fd4caeSFaiz Abbas 		dev_err(dev, "clk_xin clock not found.\n");
65041fd4caeSFaiz Abbas 		ret = PTR_ERR(clk_xin);
65141fd4caeSFaiz Abbas 		goto err_pltfm_free;
65241fd4caeSFaiz Abbas 	}
65341fd4caeSFaiz Abbas 
65441fd4caeSFaiz Abbas 	pltfm_host->clk = clk_xin;
65541fd4caeSFaiz Abbas 
65641fd4caeSFaiz Abbas 	/* Clocks are enabled using pm_runtime */
65741fd4caeSFaiz Abbas 	pm_runtime_enable(dev);
65841fd4caeSFaiz Abbas 	ret = pm_runtime_get_sync(dev);
65941fd4caeSFaiz Abbas 	if (ret < 0) {
66041fd4caeSFaiz Abbas 		pm_runtime_put_noidle(dev);
66141fd4caeSFaiz Abbas 		goto pm_runtime_disable;
66241fd4caeSFaiz Abbas 	}
66341fd4caeSFaiz Abbas 
6644942ae0eSYangtao Li 	base = devm_platform_ioremap_resource(pdev, 1);
66541fd4caeSFaiz Abbas 	if (IS_ERR(base)) {
66641fd4caeSFaiz Abbas 		ret = PTR_ERR(base);
66741fd4caeSFaiz Abbas 		goto pm_runtime_put;
66841fd4caeSFaiz Abbas 	}
66941fd4caeSFaiz Abbas 
67041fd4caeSFaiz Abbas 	sdhci_am654->base = devm_regmap_init_mmio(dev, base,
67141fd4caeSFaiz Abbas 						  &sdhci_am654_regmap_config);
67241fd4caeSFaiz Abbas 	if (IS_ERR(sdhci_am654->base)) {
67341fd4caeSFaiz Abbas 		dev_err(dev, "Failed to initialize regmap\n");
67441fd4caeSFaiz Abbas 		ret = PTR_ERR(sdhci_am654->base);
67541fd4caeSFaiz Abbas 		goto pm_runtime_put;
67641fd4caeSFaiz Abbas 	}
67741fd4caeSFaiz Abbas 
67841fd4caeSFaiz Abbas 	ret = sdhci_am654_get_of_property(pdev, sdhci_am654);
67941fd4caeSFaiz Abbas 	if (ret)
68041fd4caeSFaiz Abbas 		goto pm_runtime_put;
68141fd4caeSFaiz Abbas 
68241fd4caeSFaiz Abbas 	ret = mmc_of_parse(host->mmc);
68341fd4caeSFaiz Abbas 	if (ret) {
68441fd4caeSFaiz Abbas 		dev_err(dev, "parsing dt failed (%d)\n", ret);
68541fd4caeSFaiz Abbas 		goto pm_runtime_put;
68641fd4caeSFaiz Abbas 	}
68741fd4caeSFaiz Abbas 
688de31f6abSFaiz Abbas 	host->mmc_host_ops.execute_tuning = sdhci_am654_execute_tuning;
689de31f6abSFaiz Abbas 
69041fd4caeSFaiz Abbas 	ret = sdhci_am654_init(host);
69141fd4caeSFaiz Abbas 	if (ret)
69241fd4caeSFaiz Abbas 		goto pm_runtime_put;
69341fd4caeSFaiz Abbas 
69441fd4caeSFaiz Abbas 	return 0;
69541fd4caeSFaiz Abbas 
69641fd4caeSFaiz Abbas pm_runtime_put:
69741fd4caeSFaiz Abbas 	pm_runtime_put_sync(dev);
69841fd4caeSFaiz Abbas pm_runtime_disable:
69941fd4caeSFaiz Abbas 	pm_runtime_disable(dev);
70041fd4caeSFaiz Abbas err_pltfm_free:
70141fd4caeSFaiz Abbas 	sdhci_pltfm_free(pdev);
70241fd4caeSFaiz Abbas 	return ret;
70341fd4caeSFaiz Abbas }
70441fd4caeSFaiz Abbas 
70541fd4caeSFaiz Abbas static int sdhci_am654_remove(struct platform_device *pdev)
70641fd4caeSFaiz Abbas {
70741fd4caeSFaiz Abbas 	struct sdhci_host *host = platform_get_drvdata(pdev);
70841fd4caeSFaiz Abbas 	int ret;
70941fd4caeSFaiz Abbas 
71041fd4caeSFaiz Abbas 	sdhci_remove_host(host, true);
71141fd4caeSFaiz Abbas 	ret = pm_runtime_put_sync(&pdev->dev);
71241fd4caeSFaiz Abbas 	if (ret < 0)
71341fd4caeSFaiz Abbas 		return ret;
71441fd4caeSFaiz Abbas 
71541fd4caeSFaiz Abbas 	pm_runtime_disable(&pdev->dev);
71641fd4caeSFaiz Abbas 	sdhci_pltfm_free(pdev);
71741fd4caeSFaiz Abbas 
71841fd4caeSFaiz Abbas 	return 0;
71941fd4caeSFaiz Abbas }
72041fd4caeSFaiz Abbas 
72141fd4caeSFaiz Abbas static struct platform_driver sdhci_am654_driver = {
72241fd4caeSFaiz Abbas 	.driver = {
72341fd4caeSFaiz Abbas 		.name = "sdhci-am654",
72441fd4caeSFaiz Abbas 		.of_match_table = sdhci_am654_of_match,
72541fd4caeSFaiz Abbas 	},
72641fd4caeSFaiz Abbas 	.probe = sdhci_am654_probe,
72741fd4caeSFaiz Abbas 	.remove = sdhci_am654_remove,
72841fd4caeSFaiz Abbas };
72941fd4caeSFaiz Abbas 
73041fd4caeSFaiz Abbas module_platform_driver(sdhci_am654_driver);
73141fd4caeSFaiz Abbas 
73241fd4caeSFaiz Abbas MODULE_DESCRIPTION("Driver for SDHCI Controller on TI's AM654 devices");
73341fd4caeSFaiz Abbas MODULE_AUTHOR("Faiz Abbas <faiz_abbas@ti.com>");
73441fd4caeSFaiz Abbas MODULE_LICENSE("GPL");
735