12874c5fdSThomas Gleixner // SPDX-License-Identifier: GPL-2.0-or-later
2e3ec3a3dSSoren Brinkmann /*
3e3ec3a3dSSoren Brinkmann  * Arasan Secure Digital Host Controller Interface.
4e3ec3a3dSSoren Brinkmann  * Copyright (C) 2011 - 2012 Michal Simek <monstr@monstr.eu>
5e3ec3a3dSSoren Brinkmann  * Copyright (c) 2012 Wind River Systems, Inc.
6e3ec3a3dSSoren Brinkmann  * Copyright (C) 2013 Pengutronix e.K.
7e3ec3a3dSSoren Brinkmann  * Copyright (C) 2013 Xilinx Inc.
8e3ec3a3dSSoren Brinkmann  *
9e3ec3a3dSSoren Brinkmann  * Based on sdhci-of-esdhc.c
10e3ec3a3dSSoren Brinkmann  *
11e3ec3a3dSSoren Brinkmann  * Copyright (c) 2007 Freescale Semiconductor, Inc.
12e3ec3a3dSSoren Brinkmann  * Copyright (c) 2009 MontaVista Software, Inc.
13e3ec3a3dSSoren Brinkmann  *
14e3ec3a3dSSoren Brinkmann  * Authors: Xiaobo Xie <X.Xie@freescale.com>
15e3ec3a3dSSoren Brinkmann  *	    Anton Vorontsov <avorontsov@ru.mvista.com>
16e3ec3a3dSSoren Brinkmann  */
17e3ec3a3dSSoren Brinkmann 
18c390f211SDouglas Anderson #include <linux/clk-provider.h>
193ea4666eSDouglas Anderson #include <linux/mfd/syscon.h>
20e3ec3a3dSSoren Brinkmann #include <linux/module.h>
21308f3f8dSSuman Tripathi #include <linux/of_device.h>
2291aa3661SShawn Lin #include <linux/phy/phy.h>
233ea4666eSDouglas Anderson #include <linux/regmap.h>
243794c542SZach Brown #include <linux/of.h>
25a5c8b2aeSManish Narani #include <linux/firmware/xlnx-zynqmp.h>
26e3ec3a3dSSoren Brinkmann 
2784362d79SShawn Lin #include "cqhci.h"
2884362d79SShawn Lin #include "sdhci-pltfm.h"
29e3ec3a3dSSoren Brinkmann 
3084362d79SShawn Lin #define SDHCI_ARASAN_VENDOR_REGISTER	0x78
311a470721SManish Narani 
321a470721SManish Narani #define SDHCI_ARASAN_ITAPDLY_REGISTER	0xF0F8
33d338c6d0SManish Narani #define SDHCI_ARASAN_ITAPDLY_SEL_MASK	0xFF
34d338c6d0SManish Narani 
351a470721SManish Narani #define SDHCI_ARASAN_OTAPDLY_REGISTER	0xF0FC
36d338c6d0SManish Narani #define SDHCI_ARASAN_OTAPDLY_SEL_MASK	0x3F
371a470721SManish Narani 
3884362d79SShawn Lin #define SDHCI_ARASAN_CQE_BASE_ADDR	0x200
39a05c8465SShawn Lin #define VENDOR_ENHANCED_STROBE		BIT(0)
40e3ec3a3dSSoren Brinkmann 
41b2db9c67SDouglas Anderson #define PHY_CLK_TOO_SLOW_HZ		400000
42b2db9c67SDouglas Anderson 
431a470721SManish Narani #define SDHCI_ITAPDLY_CHGWIN		0x200
441a470721SManish Narani #define SDHCI_ITAPDLY_ENABLE		0x100
451a470721SManish Narani #define SDHCI_OTAPDLY_ENABLE		0x40
461a470721SManish Narani 
47a5c8b2aeSManish Narani /* Default settings for ZynqMP Clock Phases */
48a5c8b2aeSManish Narani #define ZYNQMP_ICLK_PHASE {0, 63, 63, 0, 63,  0,   0, 183, 54,  0, 0}
49a5c8b2aeSManish Narani #define ZYNQMP_OCLK_PHASE {0, 72, 60, 0, 60, 72, 135, 48, 72, 135, 0}
50a5c8b2aeSManish Narani 
511a470721SManish Narani #define VERSAL_ICLK_PHASE {0, 132, 132, 0, 132, 0, 0, 162, 90, 0, 0}
521a470721SManish Narani #define VERSAL_OCLK_PHASE {0,  60, 48, 0, 48, 72, 90, 36, 60, 90, 0}
531a470721SManish Narani 
543ea4666eSDouglas Anderson /*
553ea4666eSDouglas Anderson  * On some SoCs the syscon area has a feature where the upper 16-bits of
563ea4666eSDouglas Anderson  * each 32-bit register act as a write mask for the lower 16-bits.  This allows
573ea4666eSDouglas Anderson  * atomic updates of the register without locking.  This macro is used on SoCs
583ea4666eSDouglas Anderson  * that have that feature.
593ea4666eSDouglas Anderson  */
603ea4666eSDouglas Anderson #define HIWORD_UPDATE(val, mask, shift) \
613ea4666eSDouglas Anderson 		((val) << (shift) | (mask) << ((shift) + 16))
623ea4666eSDouglas Anderson 
633ea4666eSDouglas Anderson /**
643ea4666eSDouglas Anderson  * struct sdhci_arasan_soc_ctl_field - Field used in sdhci_arasan_soc_ctl_map
653ea4666eSDouglas Anderson  *
663ea4666eSDouglas Anderson  * @reg:	Offset within the syscon of the register containing this field
673ea4666eSDouglas Anderson  * @width:	Number of bits for this field
683ea4666eSDouglas Anderson  * @shift:	Bit offset within @reg of this field (or -1 if not avail)
693ea4666eSDouglas Anderson  */
703ea4666eSDouglas Anderson struct sdhci_arasan_soc_ctl_field {
713ea4666eSDouglas Anderson 	u32 reg;
723ea4666eSDouglas Anderson 	u16 width;
733ea4666eSDouglas Anderson 	s16 shift;
743ea4666eSDouglas Anderson };
753ea4666eSDouglas Anderson 
763ea4666eSDouglas Anderson /**
773ea4666eSDouglas Anderson  * struct sdhci_arasan_soc_ctl_map - Map in syscon to corecfg registers
783ea4666eSDouglas Anderson  *
793ea4666eSDouglas Anderson  * @baseclkfreq:	Where to find corecfg_baseclkfreq
80b2ca77c9SShawn Lin  * @clockmultiplier:	Where to find corecfg_clockmultiplier
8136c6aadaSWan Ahmad Zainie  * @support64b:		Where to find SUPPORT64B bit
823ea4666eSDouglas Anderson  * @hiword_update:	If true, use HIWORD_UPDATE to access the syscon
834908460eSManish Narani  *
844908460eSManish Narani  * It's up to the licensee of the Arsan IP block to make these available
854908460eSManish Narani  * somewhere if needed.  Presumably these will be scattered somewhere that's
864908460eSManish Narani  * accessible via the syscon API.
873ea4666eSDouglas Anderson  */
883ea4666eSDouglas Anderson struct sdhci_arasan_soc_ctl_map {
893ea4666eSDouglas Anderson 	struct sdhci_arasan_soc_ctl_field	baseclkfreq;
90b2ca77c9SShawn Lin 	struct sdhci_arasan_soc_ctl_field	clockmultiplier;
9136c6aadaSWan Ahmad Zainie 	struct sdhci_arasan_soc_ctl_field	support64b;
923ea4666eSDouglas Anderson 	bool					hiword_update;
933ea4666eSDouglas Anderson };
943ea4666eSDouglas Anderson 
95e3ec3a3dSSoren Brinkmann /**
9616ada730SManish Narani  * struct sdhci_arasan_clk_ops - Clock Operations for Arasan SD controller
9716ada730SManish Narani  *
9816ada730SManish Narani  * @sdcardclk_ops:	The output clock related operations
9916ada730SManish Narani  * @sampleclk_ops:	The sample clock related operations
10016ada730SManish Narani  */
10116ada730SManish Narani struct sdhci_arasan_clk_ops {
10216ada730SManish Narani 	const struct clk_ops *sdcardclk_ops;
10316ada730SManish Narani 	const struct clk_ops *sampleclk_ops;
10416ada730SManish Narani };
10516ada730SManish Narani 
10616ada730SManish Narani /**
1074908460eSManish Narani  * struct sdhci_arasan_clk_data - Arasan Controller Clock Data.
1084908460eSManish Narani  *
109e1463618SManish Narani  * @sdcardclk_hw:	Struct for the clock we might provide to a PHY.
110e1463618SManish Narani  * @sdcardclk:		Pointer to normal 'struct clock' for sdcardclk_hw.
11107a14d1dSManish Narani  * @sampleclk_hw:	Struct for the clock we might provide to a PHY.
11207a14d1dSManish Narani  * @sampleclk:		Pointer to normal 'struct clock' for sampleclk_hw.
113f3dafc37SManish Narani  * @clk_phase_in:	Array of Input Clock Phase Delays for all speed modes
114f3dafc37SManish Narani  * @clk_phase_out:	Array of Output Clock Phase Delays for all speed modes
115f3dafc37SManish Narani  * @set_clk_delays:	Function pointer for setting Clock Delays
116a5c8b2aeSManish Narani  * @clk_of_data:	Platform specific runtime clock data storage pointer
117e1463618SManish Narani  */
118e1463618SManish Narani struct sdhci_arasan_clk_data {
119e1463618SManish Narani 	struct clk_hw	sdcardclk_hw;
120e1463618SManish Narani 	struct clk      *sdcardclk;
12107a14d1dSManish Narani 	struct clk_hw	sampleclk_hw;
12207a14d1dSManish Narani 	struct clk      *sampleclk;
123f3dafc37SManish Narani 	int		clk_phase_in[MMC_TIMING_MMC_HS400 + 1];
124f3dafc37SManish Narani 	int		clk_phase_out[MMC_TIMING_MMC_HS400 + 1];
125f3dafc37SManish Narani 	void		(*set_clk_delays)(struct sdhci_host *host);
126a5c8b2aeSManish Narani 	void		*clk_of_data;
127a5c8b2aeSManish Narani };
128a5c8b2aeSManish Narani 
129e1463618SManish Narani /**
1304908460eSManish Narani  * struct sdhci_arasan_data - Arasan Controller Data
1314908460eSManish Narani  *
132c390f211SDouglas Anderson  * @host:		Pointer to the main SDHCI host structure.
133e3ec3a3dSSoren Brinkmann  * @clk_ahb:		Pointer to the AHB clock
13491aa3661SShawn Lin  * @phy:		Pointer to the generic phy
135b2db9c67SDouglas Anderson  * @is_phy_on:		True if the PHY is on; false if not.
1364908460eSManish Narani  * @has_cqe:		True if controller has command queuing engine.
137e1463618SManish Narani  * @clk_data:		Struct for the Arasan Controller Clock Data.
13816ada730SManish Narani  * @clk_ops:		Struct for the Arasan Controller Clock Operations.
1393ea4666eSDouglas Anderson  * @soc_ctl_base:	Pointer to regmap for syscon for soc_ctl registers.
1403ea4666eSDouglas Anderson  * @soc_ctl_map:	Map to get offsets into soc_ctl registers.
1414908460eSManish Narani  * @quirks:		Arasan deviations from spec.
142e3ec3a3dSSoren Brinkmann  */
143e3ec3a3dSSoren Brinkmann struct sdhci_arasan_data {
144c390f211SDouglas Anderson 	struct sdhci_host *host;
145e3ec3a3dSSoren Brinkmann 	struct clk	*clk_ahb;
14691aa3661SShawn Lin 	struct phy	*phy;
147b2db9c67SDouglas Anderson 	bool		is_phy_on;
1483ea4666eSDouglas Anderson 
14984362d79SShawn Lin 	bool		has_cqe;
150e1463618SManish Narani 	struct sdhci_arasan_clk_data clk_data;
15116ada730SManish Narani 	const struct sdhci_arasan_clk_ops *clk_ops;
152c390f211SDouglas Anderson 
1533ea4666eSDouglas Anderson 	struct regmap	*soc_ctl_base;
1543ea4666eSDouglas Anderson 	const struct sdhci_arasan_soc_ctl_map *soc_ctl_map;
1554908460eSManish Narani 	unsigned int	quirks;
1563794c542SZach Brown 
1573794c542SZach Brown /* Controller does not have CD wired and will not function normally without */
1583794c542SZach Brown #define SDHCI_ARASAN_QUIRK_FORCE_CDTEST	BIT(0)
1593f2c7d5dSHelmut Grohne /* Controller immediately reports SDHCI_CLOCK_INT_STABLE after enabling the
1603f2c7d5dSHelmut Grohne  * internal clock even when the clock isn't stable */
1613f2c7d5dSHelmut Grohne #define SDHCI_ARASAN_QUIRK_CLOCK_UNSTABLE BIT(1)
162e3ec3a3dSSoren Brinkmann };
163e3ec3a3dSSoren Brinkmann 
16406b23ca0SFaiz Abbas struct sdhci_arasan_of_data {
16506b23ca0SFaiz Abbas 	const struct sdhci_arasan_soc_ctl_map *soc_ctl_map;
16606b23ca0SFaiz Abbas 	const struct sdhci_pltfm_data *pdata;
16716ada730SManish Narani 	const struct sdhci_arasan_clk_ops *clk_ops;
16806b23ca0SFaiz Abbas };
16906b23ca0SFaiz Abbas 
1703ea4666eSDouglas Anderson static const struct sdhci_arasan_soc_ctl_map rk3399_soc_ctl_map = {
1713ea4666eSDouglas Anderson 	.baseclkfreq = { .reg = 0xf000, .width = 8, .shift = 8 },
172b2ca77c9SShawn Lin 	.clockmultiplier = { .reg = 0xf02c, .width = 8, .shift = 0},
1733ea4666eSDouglas Anderson 	.hiword_update = true,
1743ea4666eSDouglas Anderson };
1753ea4666eSDouglas Anderson 
1765c1a4f40SRamuthevar Vadivel Muruganx static const struct sdhci_arasan_soc_ctl_map intel_lgm_emmc_soc_ctl_map = {
1775c1a4f40SRamuthevar Vadivel Muruganx 	.baseclkfreq = { .reg = 0xa0, .width = 8, .shift = 2 },
1785c1a4f40SRamuthevar Vadivel Muruganx 	.clockmultiplier = { .reg = 0, .width = -1, .shift = -1 },
1795c1a4f40SRamuthevar Vadivel Muruganx 	.hiword_update = false,
1805c1a4f40SRamuthevar Vadivel Muruganx };
1815c1a4f40SRamuthevar Vadivel Muruganx 
182d1807ad6SRamuthevar Vadivel Murugan static const struct sdhci_arasan_soc_ctl_map intel_lgm_sdxc_soc_ctl_map = {
183d1807ad6SRamuthevar Vadivel Murugan 	.baseclkfreq = { .reg = 0x80, .width = 8, .shift = 2 },
184d1807ad6SRamuthevar Vadivel Murugan 	.clockmultiplier = { .reg = 0, .width = -1, .shift = -1 },
185d1807ad6SRamuthevar Vadivel Murugan 	.hiword_update = false,
186d1807ad6SRamuthevar Vadivel Murugan };
187d1807ad6SRamuthevar Vadivel Murugan 
18836c6aadaSWan Ahmad Zainie static const struct sdhci_arasan_soc_ctl_map intel_keembay_soc_ctl_map = {
18936c6aadaSWan Ahmad Zainie 	.baseclkfreq = { .reg = 0x0, .width = 8, .shift = 14 },
19036c6aadaSWan Ahmad Zainie 	.clockmultiplier = { .reg = 0x4, .width = 8, .shift = 14 },
19136c6aadaSWan Ahmad Zainie 	.support64b = { .reg = 0x4, .width = 1, .shift = 24 },
19236c6aadaSWan Ahmad Zainie 	.hiword_update = false,
19336c6aadaSWan Ahmad Zainie };
19436c6aadaSWan Ahmad Zainie 
1953ea4666eSDouglas Anderson /**
1963ea4666eSDouglas Anderson  * sdhci_arasan_syscon_write - Write to a field in soc_ctl registers
1973ea4666eSDouglas Anderson  *
1984908460eSManish Narani  * @host:	The sdhci_host
1994908460eSManish Narani  * @fld:	The field to write to
2004908460eSManish Narani  * @val:	The value to write
2014908460eSManish Narani  *
2023ea4666eSDouglas Anderson  * This function allows writing to fields in sdhci_arasan_soc_ctl_map.
2033ea4666eSDouglas Anderson  * Note that if a field is specified as not available (shift < 0) then
2043ea4666eSDouglas Anderson  * this function will silently return an error code.  It will be noisy
2053ea4666eSDouglas Anderson  * and print errors for any other (unexpected) errors.
2063ea4666eSDouglas Anderson  *
2074908460eSManish Narani  * Return: 0 on success and error value on error
2083ea4666eSDouglas Anderson  */
2093ea4666eSDouglas Anderson static int sdhci_arasan_syscon_write(struct sdhci_host *host,
2103ea4666eSDouglas Anderson 				   const struct sdhci_arasan_soc_ctl_field *fld,
2113ea4666eSDouglas Anderson 				   u32 val)
2123ea4666eSDouglas Anderson {
2133ea4666eSDouglas Anderson 	struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
2143ea4666eSDouglas Anderson 	struct sdhci_arasan_data *sdhci_arasan = sdhci_pltfm_priv(pltfm_host);
2153ea4666eSDouglas Anderson 	struct regmap *soc_ctl_base = sdhci_arasan->soc_ctl_base;
2163ea4666eSDouglas Anderson 	u32 reg = fld->reg;
2173ea4666eSDouglas Anderson 	u16 width = fld->width;
2183ea4666eSDouglas Anderson 	s16 shift = fld->shift;
2193ea4666eSDouglas Anderson 	int ret;
2203ea4666eSDouglas Anderson 
2213ea4666eSDouglas Anderson 	/*
2223ea4666eSDouglas Anderson 	 * Silently return errors for shift < 0 so caller doesn't have
2233ea4666eSDouglas Anderson 	 * to check for fields which are optional.  For fields that
2243ea4666eSDouglas Anderson 	 * are required then caller needs to do something special
2253ea4666eSDouglas Anderson 	 * anyway.
2263ea4666eSDouglas Anderson 	 */
2273ea4666eSDouglas Anderson 	if (shift < 0)
2283ea4666eSDouglas Anderson 		return -EINVAL;
2293ea4666eSDouglas Anderson 
2303ea4666eSDouglas Anderson 	if (sdhci_arasan->soc_ctl_map->hiword_update)
2313ea4666eSDouglas Anderson 		ret = regmap_write(soc_ctl_base, reg,
2323ea4666eSDouglas Anderson 				   HIWORD_UPDATE(val, GENMASK(width, 0),
2333ea4666eSDouglas Anderson 						 shift));
2343ea4666eSDouglas Anderson 	else
2353ea4666eSDouglas Anderson 		ret = regmap_update_bits(soc_ctl_base, reg,
2363ea4666eSDouglas Anderson 					 GENMASK(shift + width, shift),
2373ea4666eSDouglas Anderson 					 val << shift);
2383ea4666eSDouglas Anderson 
2393ea4666eSDouglas Anderson 	/* Yell about (unexpected) regmap errors */
2403ea4666eSDouglas Anderson 	if (ret)
2413ea4666eSDouglas Anderson 		pr_warn("%s: Regmap write fail: %d\n",
2423ea4666eSDouglas Anderson 			 mmc_hostname(host->mmc), ret);
2433ea4666eSDouglas Anderson 
2443ea4666eSDouglas Anderson 	return ret;
2453ea4666eSDouglas Anderson }
2463ea4666eSDouglas Anderson 
247802ac39aSShawn Lin static void sdhci_arasan_set_clock(struct sdhci_host *host, unsigned int clock)
248802ac39aSShawn Lin {
249802ac39aSShawn Lin 	struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
250802ac39aSShawn Lin 	struct sdhci_arasan_data *sdhci_arasan = sdhci_pltfm_priv(pltfm_host);
251f3dafc37SManish Narani 	struct sdhci_arasan_clk_data *clk_data = &sdhci_arasan->clk_data;
2526fc09244SDouglas Anderson 	bool ctrl_phy = false;
253802ac39aSShawn Lin 
254b2db9c67SDouglas Anderson 	if (!IS_ERR(sdhci_arasan->phy)) {
255b2db9c67SDouglas Anderson 		if (!sdhci_arasan->is_phy_on && clock <= PHY_CLK_TOO_SLOW_HZ) {
256b2db9c67SDouglas Anderson 			/*
257b2db9c67SDouglas Anderson 			 * If PHY off, set clock to max speed and power PHY on.
258b2db9c67SDouglas Anderson 			 *
259b2db9c67SDouglas Anderson 			 * Although PHY docs apparently suggest power cycling
260b2db9c67SDouglas Anderson 			 * when changing the clock the PHY doesn't like to be
261b2db9c67SDouglas Anderson 			 * powered on while at low speeds like those used in ID
262b2db9c67SDouglas Anderson 			 * mode.  Even worse is powering the PHY on while the
263b2db9c67SDouglas Anderson 			 * clock is off.
264b2db9c67SDouglas Anderson 			 *
265b2db9c67SDouglas Anderson 			 * To workaround the PHY limitations, the best we can
266b2db9c67SDouglas Anderson 			 * do is to power it on at a faster speed and then slam
267b2db9c67SDouglas Anderson 			 * through low speeds without power cycling.
268b2db9c67SDouglas Anderson 			 */
269b2db9c67SDouglas Anderson 			sdhci_set_clock(host, host->max_clk);
270b2db9c67SDouglas Anderson 			phy_power_on(sdhci_arasan->phy);
271b2db9c67SDouglas Anderson 			sdhci_arasan->is_phy_on = true;
272802ac39aSShawn Lin 
273b2db9c67SDouglas Anderson 			/*
274b2db9c67SDouglas Anderson 			 * We'll now fall through to the below case with
275b2db9c67SDouglas Anderson 			 * ctrl_phy = false (so we won't turn off/on).  The
276b2db9c67SDouglas Anderson 			 * sdhci_set_clock() will set the real clock.
277b2db9c67SDouglas Anderson 			 */
278b2db9c67SDouglas Anderson 		} else if (clock > PHY_CLK_TOO_SLOW_HZ) {
279b2db9c67SDouglas Anderson 			/*
280b2db9c67SDouglas Anderson 			 * At higher clock speeds the PHY is fine being power
281b2db9c67SDouglas Anderson 			 * cycled and docs say you _should_ power cycle when
282b2db9c67SDouglas Anderson 			 * changing clock speeds.
283b2db9c67SDouglas Anderson 			 */
284b2db9c67SDouglas Anderson 			ctrl_phy = true;
285b2db9c67SDouglas Anderson 		}
286b2db9c67SDouglas Anderson 	}
287b2db9c67SDouglas Anderson 
288b2db9c67SDouglas Anderson 	if (ctrl_phy && sdhci_arasan->is_phy_on) {
289802ac39aSShawn Lin 		phy_power_off(sdhci_arasan->phy);
290b2db9c67SDouglas Anderson 		sdhci_arasan->is_phy_on = false;
291802ac39aSShawn Lin 	}
292802ac39aSShawn Lin 
293f3dafc37SManish Narani 	/* Set the Input and Output Clock Phase Delays */
294f3dafc37SManish Narani 	if (clk_data->set_clk_delays)
295f3dafc37SManish Narani 		clk_data->set_clk_delays(host);
296f3dafc37SManish Narani 
297802ac39aSShawn Lin 	sdhci_set_clock(host, clock);
298802ac39aSShawn Lin 
2993f2c7d5dSHelmut Grohne 	if (sdhci_arasan->quirks & SDHCI_ARASAN_QUIRK_CLOCK_UNSTABLE)
3003f2c7d5dSHelmut Grohne 		/*
3013f2c7d5dSHelmut Grohne 		 * Some controllers immediately report SDHCI_CLOCK_INT_STABLE
3023f2c7d5dSHelmut Grohne 		 * after enabling the clock even though the clock is not
3033f2c7d5dSHelmut Grohne 		 * stable. Trying to use a clock without waiting here results
3043f2c7d5dSHelmut Grohne 		 * in EILSEQ while detecting some older/slower cards. The
3053f2c7d5dSHelmut Grohne 		 * chosen delay is the maximum delay from sdhci_set_clock.
3063f2c7d5dSHelmut Grohne 		 */
3073f2c7d5dSHelmut Grohne 		msleep(20);
3083f2c7d5dSHelmut Grohne 
3096fc09244SDouglas Anderson 	if (ctrl_phy) {
310802ac39aSShawn Lin 		phy_power_on(sdhci_arasan->phy);
311b2db9c67SDouglas Anderson 		sdhci_arasan->is_phy_on = true;
312802ac39aSShawn Lin 	}
313802ac39aSShawn Lin }
314802ac39aSShawn Lin 
315a05c8465SShawn Lin static void sdhci_arasan_hs400_enhanced_strobe(struct mmc_host *mmc,
316a05c8465SShawn Lin 					struct mmc_ios *ios)
317a05c8465SShawn Lin {
318a05c8465SShawn Lin 	u32 vendor;
319a05c8465SShawn Lin 	struct sdhci_host *host = mmc_priv(mmc);
320a05c8465SShawn Lin 
3210daf72feSJean-Francois Dagenais 	vendor = sdhci_readl(host, SDHCI_ARASAN_VENDOR_REGISTER);
322a05c8465SShawn Lin 	if (ios->enhanced_strobe)
323a05c8465SShawn Lin 		vendor |= VENDOR_ENHANCED_STROBE;
324a05c8465SShawn Lin 	else
325a05c8465SShawn Lin 		vendor &= ~VENDOR_ENHANCED_STROBE;
326a05c8465SShawn Lin 
3270daf72feSJean-Francois Dagenais 	sdhci_writel(host, vendor, SDHCI_ARASAN_VENDOR_REGISTER);
328a05c8465SShawn Lin }
329a05c8465SShawn Lin 
33013d62fd2SWei Yongjun static void sdhci_arasan_reset(struct sdhci_host *host, u8 mask)
3313794c542SZach Brown {
3323794c542SZach Brown 	u8 ctrl;
3333794c542SZach Brown 	struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
3343794c542SZach Brown 	struct sdhci_arasan_data *sdhci_arasan = sdhci_pltfm_priv(pltfm_host);
3353794c542SZach Brown 
3363794c542SZach Brown 	sdhci_reset(host, mask);
3373794c542SZach Brown 
3383794c542SZach Brown 	if (sdhci_arasan->quirks & SDHCI_ARASAN_QUIRK_FORCE_CDTEST) {
3393794c542SZach Brown 		ctrl = sdhci_readb(host, SDHCI_HOST_CONTROL);
3403794c542SZach Brown 		ctrl |= SDHCI_CTRL_CDTEST_INS | SDHCI_CTRL_CDTEST_EN;
3413794c542SZach Brown 		sdhci_writeb(host, ctrl, SDHCI_HOST_CONTROL);
3423794c542SZach Brown 	}
3433794c542SZach Brown }
3443794c542SZach Brown 
3458a3bee9bSShawn Lin static int sdhci_arasan_voltage_switch(struct mmc_host *mmc,
3468a3bee9bSShawn Lin 				       struct mmc_ios *ios)
3478a3bee9bSShawn Lin {
3488a3bee9bSShawn Lin 	switch (ios->signal_voltage) {
3498a3bee9bSShawn Lin 	case MMC_SIGNAL_VOLTAGE_180:
3508a3bee9bSShawn Lin 		/*
3518a3bee9bSShawn Lin 		 * Plese don't switch to 1V8 as arasan,5.1 doesn't
3528a3bee9bSShawn Lin 		 * actually refer to this setting to indicate the
3538a3bee9bSShawn Lin 		 * signal voltage and the state machine will be broken
3548a3bee9bSShawn Lin 		 * actually if we force to enable 1V8. That's something
3558a3bee9bSShawn Lin 		 * like broken quirk but we could work around here.
3568a3bee9bSShawn Lin 		 */
3578a3bee9bSShawn Lin 		return 0;
3588a3bee9bSShawn Lin 	case MMC_SIGNAL_VOLTAGE_330:
3598a3bee9bSShawn Lin 	case MMC_SIGNAL_VOLTAGE_120:
3608a3bee9bSShawn Lin 		/* We don't support 3V3 and 1V2 */
3618a3bee9bSShawn Lin 		break;
3628a3bee9bSShawn Lin 	}
3638a3bee9bSShawn Lin 
3648a3bee9bSShawn Lin 	return -EINVAL;
3658a3bee9bSShawn Lin }
3668a3bee9bSShawn Lin 
367a81dae3aSJulia Lawall static const struct sdhci_ops sdhci_arasan_ops = {
368802ac39aSShawn Lin 	.set_clock = sdhci_arasan_set_clock,
369e3ec3a3dSSoren Brinkmann 	.get_max_clock = sdhci_pltfm_clk_get_max_clock,
3708cc35289SShawn Lin 	.get_timeout_clock = sdhci_pltfm_clk_get_max_clock,
3712317f56cSRussell King 	.set_bus_width = sdhci_set_bus_width,
3723794c542SZach Brown 	.reset = sdhci_arasan_reset,
37396d7b78cSRussell King 	.set_uhs_signaling = sdhci_set_uhs_signaling,
374c2c5252cSNicolas Saenz Julienne 	.set_power = sdhci_set_power_and_bus_voltage,
375e3ec3a3dSSoren Brinkmann };
376e3ec3a3dSSoren Brinkmann 
37784362d79SShawn Lin static u32 sdhci_arasan_cqhci_irq(struct sdhci_host *host, u32 intmask)
37884362d79SShawn Lin {
37984362d79SShawn Lin 	int cmd_error = 0;
38084362d79SShawn Lin 	int data_error = 0;
38184362d79SShawn Lin 
38284362d79SShawn Lin 	if (!sdhci_cqe_irq(host, intmask, &cmd_error, &data_error))
38384362d79SShawn Lin 		return intmask;
38484362d79SShawn Lin 
38584362d79SShawn Lin 	cqhci_irq(host->mmc, intmask, cmd_error, data_error);
38684362d79SShawn Lin 
38784362d79SShawn Lin 	return 0;
38884362d79SShawn Lin }
38984362d79SShawn Lin 
39084362d79SShawn Lin static void sdhci_arasan_dumpregs(struct mmc_host *mmc)
39184362d79SShawn Lin {
39284362d79SShawn Lin 	sdhci_dumpregs(mmc_priv(mmc));
39384362d79SShawn Lin }
39484362d79SShawn Lin 
39584362d79SShawn Lin static void sdhci_arasan_cqe_enable(struct mmc_host *mmc)
39684362d79SShawn Lin {
39784362d79SShawn Lin 	struct sdhci_host *host = mmc_priv(mmc);
39884362d79SShawn Lin 	u32 reg;
39984362d79SShawn Lin 
40084362d79SShawn Lin 	reg = sdhci_readl(host, SDHCI_PRESENT_STATE);
40184362d79SShawn Lin 	while (reg & SDHCI_DATA_AVAILABLE) {
40284362d79SShawn Lin 		sdhci_readl(host, SDHCI_BUFFER);
40384362d79SShawn Lin 		reg = sdhci_readl(host, SDHCI_PRESENT_STATE);
40484362d79SShawn Lin 	}
40584362d79SShawn Lin 
40684362d79SShawn Lin 	sdhci_cqe_enable(mmc);
40784362d79SShawn Lin }
40884362d79SShawn Lin 
40984362d79SShawn Lin static const struct cqhci_host_ops sdhci_arasan_cqhci_ops = {
41084362d79SShawn Lin 	.enable         = sdhci_arasan_cqe_enable,
41184362d79SShawn Lin 	.disable        = sdhci_cqe_disable,
41284362d79SShawn Lin 	.dumpregs       = sdhci_arasan_dumpregs,
41384362d79SShawn Lin };
41484362d79SShawn Lin 
41584362d79SShawn Lin static const struct sdhci_ops sdhci_arasan_cqe_ops = {
41684362d79SShawn Lin 	.set_clock = sdhci_arasan_set_clock,
41784362d79SShawn Lin 	.get_max_clock = sdhci_pltfm_clk_get_max_clock,
41884362d79SShawn Lin 	.get_timeout_clock = sdhci_pltfm_clk_get_max_clock,
41984362d79SShawn Lin 	.set_bus_width = sdhci_set_bus_width,
42084362d79SShawn Lin 	.reset = sdhci_arasan_reset,
42184362d79SShawn Lin 	.set_uhs_signaling = sdhci_set_uhs_signaling,
422c2c5252cSNicolas Saenz Julienne 	.set_power = sdhci_set_power_and_bus_voltage,
42384362d79SShawn Lin 	.irq = sdhci_arasan_cqhci_irq,
42484362d79SShawn Lin };
42584362d79SShawn Lin 
42684362d79SShawn Lin static const struct sdhci_pltfm_data sdhci_arasan_cqe_pdata = {
42784362d79SShawn Lin 	.ops = &sdhci_arasan_cqe_ops,
42884362d79SShawn Lin 	.quirks = SDHCI_QUIRK_CAP_CLOCK_BASE_BROKEN,
42984362d79SShawn Lin 	.quirks2 = SDHCI_QUIRK2_PRESET_VALUE_BROKEN |
43084362d79SShawn Lin 			SDHCI_QUIRK2_CLOCK_DIV_ZERO_BROKEN,
43184362d79SShawn Lin };
43284362d79SShawn Lin 
433e3ec3a3dSSoren Brinkmann #ifdef CONFIG_PM_SLEEP
434e3ec3a3dSSoren Brinkmann /**
435e3ec3a3dSSoren Brinkmann  * sdhci_arasan_suspend - Suspend method for the driver
436e3ec3a3dSSoren Brinkmann  * @dev:	Address of the device structure
437e3ec3a3dSSoren Brinkmann  *
438e3ec3a3dSSoren Brinkmann  * Put the device in a low power state.
4394908460eSManish Narani  *
4404908460eSManish Narani  * Return: 0 on success and error value on error
441e3ec3a3dSSoren Brinkmann  */
442e3ec3a3dSSoren Brinkmann static int sdhci_arasan_suspend(struct device *dev)
443e3ec3a3dSSoren Brinkmann {
444970f2d90SWolfram Sang 	struct sdhci_host *host = dev_get_drvdata(dev);
445e3ec3a3dSSoren Brinkmann 	struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
44689211418SJisheng Zhang 	struct sdhci_arasan_data *sdhci_arasan = sdhci_pltfm_priv(pltfm_host);
447e3ec3a3dSSoren Brinkmann 	int ret;
448e3ec3a3dSSoren Brinkmann 
449d38dcad4SAdrian Hunter 	if (host->tuning_mode != SDHCI_TUNING_MODE_3)
450d38dcad4SAdrian Hunter 		mmc_retune_needed(host->mmc);
451d38dcad4SAdrian Hunter 
45284362d79SShawn Lin 	if (sdhci_arasan->has_cqe) {
45384362d79SShawn Lin 		ret = cqhci_suspend(host->mmc);
45484362d79SShawn Lin 		if (ret)
45584362d79SShawn Lin 			return ret;
45684362d79SShawn Lin 	}
45784362d79SShawn Lin 
458e3ec3a3dSSoren Brinkmann 	ret = sdhci_suspend_host(host);
459e3ec3a3dSSoren Brinkmann 	if (ret)
460e3ec3a3dSSoren Brinkmann 		return ret;
461e3ec3a3dSSoren Brinkmann 
462b2db9c67SDouglas Anderson 	if (!IS_ERR(sdhci_arasan->phy) && sdhci_arasan->is_phy_on) {
46391aa3661SShawn Lin 		ret = phy_power_off(sdhci_arasan->phy);
46491aa3661SShawn Lin 		if (ret) {
46591aa3661SShawn Lin 			dev_err(dev, "Cannot power off phy.\n");
46691aa3661SShawn Lin 			sdhci_resume_host(host);
46791aa3661SShawn Lin 			return ret;
46891aa3661SShawn Lin 		}
469b2db9c67SDouglas Anderson 		sdhci_arasan->is_phy_on = false;
47091aa3661SShawn Lin 	}
47191aa3661SShawn Lin 
472e3ec3a3dSSoren Brinkmann 	clk_disable(pltfm_host->clk);
473e3ec3a3dSSoren Brinkmann 	clk_disable(sdhci_arasan->clk_ahb);
474e3ec3a3dSSoren Brinkmann 
475e3ec3a3dSSoren Brinkmann 	return 0;
476e3ec3a3dSSoren Brinkmann }
477e3ec3a3dSSoren Brinkmann 
478e3ec3a3dSSoren Brinkmann /**
479e3ec3a3dSSoren Brinkmann  * sdhci_arasan_resume - Resume method for the driver
480e3ec3a3dSSoren Brinkmann  * @dev:	Address of the device structure
481e3ec3a3dSSoren Brinkmann  *
482e3ec3a3dSSoren Brinkmann  * Resume operation after suspend
4834908460eSManish Narani  *
4844908460eSManish Narani  * Return: 0 on success and error value on error
485e3ec3a3dSSoren Brinkmann  */
486e3ec3a3dSSoren Brinkmann static int sdhci_arasan_resume(struct device *dev)
487e3ec3a3dSSoren Brinkmann {
488970f2d90SWolfram Sang 	struct sdhci_host *host = dev_get_drvdata(dev);
489e3ec3a3dSSoren Brinkmann 	struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
49089211418SJisheng Zhang 	struct sdhci_arasan_data *sdhci_arasan = sdhci_pltfm_priv(pltfm_host);
491e3ec3a3dSSoren Brinkmann 	int ret;
492e3ec3a3dSSoren Brinkmann 
493e3ec3a3dSSoren Brinkmann 	ret = clk_enable(sdhci_arasan->clk_ahb);
494e3ec3a3dSSoren Brinkmann 	if (ret) {
495e3ec3a3dSSoren Brinkmann 		dev_err(dev, "Cannot enable AHB clock.\n");
496e3ec3a3dSSoren Brinkmann 		return ret;
497e3ec3a3dSSoren Brinkmann 	}
498e3ec3a3dSSoren Brinkmann 
499e3ec3a3dSSoren Brinkmann 	ret = clk_enable(pltfm_host->clk);
500e3ec3a3dSSoren Brinkmann 	if (ret) {
501e3ec3a3dSSoren Brinkmann 		dev_err(dev, "Cannot enable SD clock.\n");
502e3ec3a3dSSoren Brinkmann 		return ret;
503e3ec3a3dSSoren Brinkmann 	}
504e3ec3a3dSSoren Brinkmann 
505b2db9c67SDouglas Anderson 	if (!IS_ERR(sdhci_arasan->phy) && host->mmc->actual_clock) {
50691aa3661SShawn Lin 		ret = phy_power_on(sdhci_arasan->phy);
50791aa3661SShawn Lin 		if (ret) {
50891aa3661SShawn Lin 			dev_err(dev, "Cannot power on phy.\n");
50991aa3661SShawn Lin 			return ret;
51091aa3661SShawn Lin 		}
511b2db9c67SDouglas Anderson 		sdhci_arasan->is_phy_on = true;
51291aa3661SShawn Lin 	}
51391aa3661SShawn Lin 
51484362d79SShawn Lin 	ret = sdhci_resume_host(host);
51584362d79SShawn Lin 	if (ret) {
51684362d79SShawn Lin 		dev_err(dev, "Cannot resume host.\n");
51784362d79SShawn Lin 		return ret;
51884362d79SShawn Lin 	}
51984362d79SShawn Lin 
52084362d79SShawn Lin 	if (sdhci_arasan->has_cqe)
52184362d79SShawn Lin 		return cqhci_resume(host->mmc);
52284362d79SShawn Lin 
52384362d79SShawn Lin 	return 0;
524e3ec3a3dSSoren Brinkmann }
525e3ec3a3dSSoren Brinkmann #endif /* ! CONFIG_PM_SLEEP */
526e3ec3a3dSSoren Brinkmann 
527e3ec3a3dSSoren Brinkmann static SIMPLE_DEV_PM_OPS(sdhci_arasan_dev_pm_ops, sdhci_arasan_suspend,
528e3ec3a3dSSoren Brinkmann 			 sdhci_arasan_resume);
529e3ec3a3dSSoren Brinkmann 
5303ea4666eSDouglas Anderson /**
531c390f211SDouglas Anderson  * sdhci_arasan_sdcardclk_recalc_rate - Return the card clock rate
532c390f211SDouglas Anderson  *
5334908460eSManish Narani  * @hw:			Pointer to the hardware clock structure.
5344908460eSManish Narani  * @parent_rate:		The parent rate (should be rate of clk_xin).
5354908460eSManish Narani  *
536c390f211SDouglas Anderson  * Return the current actual rate of the SD card clock.  This can be used
537c390f211SDouglas Anderson  * to communicate with out PHY.
538c390f211SDouglas Anderson  *
5394908460eSManish Narani  * Return: The card clock rate.
540c390f211SDouglas Anderson  */
541c390f211SDouglas Anderson static unsigned long sdhci_arasan_sdcardclk_recalc_rate(struct clk_hw *hw,
542c390f211SDouglas Anderson 						      unsigned long parent_rate)
543c390f211SDouglas Anderson {
544e1463618SManish Narani 	struct sdhci_arasan_clk_data *clk_data =
545e1463618SManish Narani 		container_of(hw, struct sdhci_arasan_clk_data, sdcardclk_hw);
546c390f211SDouglas Anderson 	struct sdhci_arasan_data *sdhci_arasan =
547e1463618SManish Narani 		container_of(clk_data, struct sdhci_arasan_data, clk_data);
548c390f211SDouglas Anderson 	struct sdhci_host *host = sdhci_arasan->host;
549c390f211SDouglas Anderson 
550c390f211SDouglas Anderson 	return host->mmc->actual_clock;
551c390f211SDouglas Anderson }
552c390f211SDouglas Anderson 
553c390f211SDouglas Anderson static const struct clk_ops arasan_sdcardclk_ops = {
554c390f211SDouglas Anderson 	.recalc_rate = sdhci_arasan_sdcardclk_recalc_rate,
555c390f211SDouglas Anderson };
556c390f211SDouglas Anderson 
557c390f211SDouglas Anderson /**
55807a14d1dSManish Narani  * sdhci_arasan_sampleclk_recalc_rate - Return the sampling clock rate
55907a14d1dSManish Narani  *
5604908460eSManish Narani  * @hw:			Pointer to the hardware clock structure.
5614908460eSManish Narani  * @parent_rate:		The parent rate (should be rate of clk_xin).
5624908460eSManish Narani  *
56307a14d1dSManish Narani  * Return the current actual rate of the sampling clock.  This can be used
56407a14d1dSManish Narani  * to communicate with out PHY.
56507a14d1dSManish Narani  *
5664908460eSManish Narani  * Return: The sample clock rate.
56707a14d1dSManish Narani  */
56807a14d1dSManish Narani static unsigned long sdhci_arasan_sampleclk_recalc_rate(struct clk_hw *hw,
56907a14d1dSManish Narani 						      unsigned long parent_rate)
57007a14d1dSManish Narani {
57107a14d1dSManish Narani 	struct sdhci_arasan_clk_data *clk_data =
57207a14d1dSManish Narani 		container_of(hw, struct sdhci_arasan_clk_data, sampleclk_hw);
57307a14d1dSManish Narani 	struct sdhci_arasan_data *sdhci_arasan =
57407a14d1dSManish Narani 		container_of(clk_data, struct sdhci_arasan_data, clk_data);
57507a14d1dSManish Narani 	struct sdhci_host *host = sdhci_arasan->host;
57607a14d1dSManish Narani 
57707a14d1dSManish Narani 	return host->mmc->actual_clock;
57807a14d1dSManish Narani }
57907a14d1dSManish Narani 
58007a14d1dSManish Narani static const struct clk_ops arasan_sampleclk_ops = {
58107a14d1dSManish Narani 	.recalc_rate = sdhci_arasan_sampleclk_recalc_rate,
58207a14d1dSManish Narani };
58307a14d1dSManish Narani 
58407a14d1dSManish Narani /**
585a5c8b2aeSManish Narani  * sdhci_zynqmp_sdcardclk_set_phase - Set the SD Output Clock Tap Delays
586a5c8b2aeSManish Narani  *
5874908460eSManish Narani  * @hw:			Pointer to the hardware clock structure.
5884908460eSManish Narani  * @degrees:		The clock phase shift between 0 - 359.
5894908460eSManish Narani  *
590a5c8b2aeSManish Narani  * Set the SD Output Clock Tap Delays for Output path
591a5c8b2aeSManish Narani  *
592a5c8b2aeSManish Narani  * Return: 0 on success and error value on error
593a5c8b2aeSManish Narani  */
594a5c8b2aeSManish Narani static int sdhci_zynqmp_sdcardclk_set_phase(struct clk_hw *hw, int degrees)
595a5c8b2aeSManish Narani {
596a5c8b2aeSManish Narani 	struct sdhci_arasan_clk_data *clk_data =
597a5c8b2aeSManish Narani 		container_of(hw, struct sdhci_arasan_clk_data, sdcardclk_hw);
598a5c8b2aeSManish Narani 	struct sdhci_arasan_data *sdhci_arasan =
599a5c8b2aeSManish Narani 		container_of(clk_data, struct sdhci_arasan_data, clk_data);
600a5c8b2aeSManish Narani 	struct sdhci_host *host = sdhci_arasan->host;
601a5c8b2aeSManish Narani 	const char *clk_name = clk_hw_get_name(hw);
602a5c8b2aeSManish Narani 	u32 node_id = !strcmp(clk_name, "clk_out_sd0") ? NODE_SD_0 : NODE_SD_1;
603a5c8b2aeSManish Narani 	u8 tap_delay, tap_max = 0;
604a5c8b2aeSManish Narani 	int ret;
605a5c8b2aeSManish Narani 
6069e953432SManish Narani 	/* This is applicable for SDHCI_SPEC_300 and above */
6079e953432SManish Narani 	if (host->version < SDHCI_SPEC_300)
608a5c8b2aeSManish Narani 		return 0;
609a5c8b2aeSManish Narani 
610a5c8b2aeSManish Narani 	switch (host->timing) {
611a5c8b2aeSManish Narani 	case MMC_TIMING_MMC_HS:
612a5c8b2aeSManish Narani 	case MMC_TIMING_SD_HS:
613a5c8b2aeSManish Narani 	case MMC_TIMING_UHS_SDR25:
614a5c8b2aeSManish Narani 	case MMC_TIMING_UHS_DDR50:
615a5c8b2aeSManish Narani 	case MMC_TIMING_MMC_DDR52:
616a5c8b2aeSManish Narani 		/* For 50MHz clock, 30 Taps are available */
617a5c8b2aeSManish Narani 		tap_max = 30;
618a5c8b2aeSManish Narani 		break;
619a5c8b2aeSManish Narani 	case MMC_TIMING_UHS_SDR50:
620a5c8b2aeSManish Narani 		/* For 100MHz clock, 15 Taps are available */
621a5c8b2aeSManish Narani 		tap_max = 15;
622a5c8b2aeSManish Narani 		break;
623a5c8b2aeSManish Narani 	case MMC_TIMING_UHS_SDR104:
624a5c8b2aeSManish Narani 	case MMC_TIMING_MMC_HS200:
625a5c8b2aeSManish Narani 		/* For 200MHz clock, 8 Taps are available */
626a5c8b2aeSManish Narani 		tap_max = 8;
627a3096ec6SGustavo A. R. Silva 		break;
628a5c8b2aeSManish Narani 	default:
629a5c8b2aeSManish Narani 		break;
630a5c8b2aeSManish Narani 	}
631a5c8b2aeSManish Narani 
632a5c8b2aeSManish Narani 	tap_delay = (degrees * tap_max) / 360;
633a5c8b2aeSManish Narani 
634a5c8b2aeSManish Narani 	/* Set the Clock Phase */
635426c8d85SRajan Vaja 	ret = zynqmp_pm_set_sd_tapdelay(node_id, PM_TAPDELAY_OUTPUT, tap_delay);
636a5c8b2aeSManish Narani 	if (ret)
637a5c8b2aeSManish Narani 		pr_err("Error setting Output Tap Delay\n");
638a5c8b2aeSManish Narani 
639d06d60d5SManish Narani 	/* Release DLL Reset */
640d06d60d5SManish Narani 	zynqmp_pm_sd_dll_reset(node_id, PM_DLL_RESET_RELEASE);
641d06d60d5SManish Narani 
642a5c8b2aeSManish Narani 	return ret;
643a5c8b2aeSManish Narani }
644a5c8b2aeSManish Narani 
645a5c8b2aeSManish Narani static const struct clk_ops zynqmp_sdcardclk_ops = {
646a5c8b2aeSManish Narani 	.recalc_rate = sdhci_arasan_sdcardclk_recalc_rate,
647a5c8b2aeSManish Narani 	.set_phase = sdhci_zynqmp_sdcardclk_set_phase,
648a5c8b2aeSManish Narani };
649a5c8b2aeSManish Narani 
650a5c8b2aeSManish Narani /**
651a5c8b2aeSManish Narani  * sdhci_zynqmp_sampleclk_set_phase - Set the SD Input Clock Tap Delays
652a5c8b2aeSManish Narani  *
6534908460eSManish Narani  * @hw:			Pointer to the hardware clock structure.
6544908460eSManish Narani  * @degrees:		The clock phase shift between 0 - 359.
6554908460eSManish Narani  *
656a5c8b2aeSManish Narani  * Set the SD Input Clock Tap Delays for Input path
657a5c8b2aeSManish Narani  *
658a5c8b2aeSManish Narani  * Return: 0 on success and error value on error
659a5c8b2aeSManish Narani  */
660a5c8b2aeSManish Narani static int sdhci_zynqmp_sampleclk_set_phase(struct clk_hw *hw, int degrees)
661a5c8b2aeSManish Narani {
662a5c8b2aeSManish Narani 	struct sdhci_arasan_clk_data *clk_data =
663a5c8b2aeSManish Narani 		container_of(hw, struct sdhci_arasan_clk_data, sampleclk_hw);
664a5c8b2aeSManish Narani 	struct sdhci_arasan_data *sdhci_arasan =
665a5c8b2aeSManish Narani 		container_of(clk_data, struct sdhci_arasan_data, clk_data);
666a5c8b2aeSManish Narani 	struct sdhci_host *host = sdhci_arasan->host;
667a5c8b2aeSManish Narani 	const char *clk_name = clk_hw_get_name(hw);
668a5c8b2aeSManish Narani 	u32 node_id = !strcmp(clk_name, "clk_in_sd0") ? NODE_SD_0 : NODE_SD_1;
669a5c8b2aeSManish Narani 	u8 tap_delay, tap_max = 0;
670a5c8b2aeSManish Narani 	int ret;
671a5c8b2aeSManish Narani 
6729e953432SManish Narani 	/* This is applicable for SDHCI_SPEC_300 and above */
6739e953432SManish Narani 	if (host->version < SDHCI_SPEC_300)
674a5c8b2aeSManish Narani 		return 0;
675a5c8b2aeSManish Narani 
676d06d60d5SManish Narani 	/* Assert DLL Reset */
677d06d60d5SManish Narani 	zynqmp_pm_sd_dll_reset(node_id, PM_DLL_RESET_ASSERT);
678d06d60d5SManish Narani 
679a5c8b2aeSManish Narani 	switch (host->timing) {
680a5c8b2aeSManish Narani 	case MMC_TIMING_MMC_HS:
681a5c8b2aeSManish Narani 	case MMC_TIMING_SD_HS:
682a5c8b2aeSManish Narani 	case MMC_TIMING_UHS_SDR25:
683a5c8b2aeSManish Narani 	case MMC_TIMING_UHS_DDR50:
684a5c8b2aeSManish Narani 	case MMC_TIMING_MMC_DDR52:
685a5c8b2aeSManish Narani 		/* For 50MHz clock, 120 Taps are available */
686a5c8b2aeSManish Narani 		tap_max = 120;
687a5c8b2aeSManish Narani 		break;
688a5c8b2aeSManish Narani 	case MMC_TIMING_UHS_SDR50:
689a5c8b2aeSManish Narani 		/* For 100MHz clock, 60 Taps are available */
690a5c8b2aeSManish Narani 		tap_max = 60;
691a5c8b2aeSManish Narani 		break;
692a5c8b2aeSManish Narani 	case MMC_TIMING_UHS_SDR104:
693a5c8b2aeSManish Narani 	case MMC_TIMING_MMC_HS200:
694a5c8b2aeSManish Narani 		/* For 200MHz clock, 30 Taps are available */
695a5c8b2aeSManish Narani 		tap_max = 30;
696a3096ec6SGustavo A. R. Silva 		break;
697a5c8b2aeSManish Narani 	default:
698a5c8b2aeSManish Narani 		break;
699a5c8b2aeSManish Narani 	}
700a5c8b2aeSManish Narani 
701a5c8b2aeSManish Narani 	tap_delay = (degrees * tap_max) / 360;
702a5c8b2aeSManish Narani 
703a5c8b2aeSManish Narani 	/* Set the Clock Phase */
704426c8d85SRajan Vaja 	ret = zynqmp_pm_set_sd_tapdelay(node_id, PM_TAPDELAY_INPUT, tap_delay);
705a5c8b2aeSManish Narani 	if (ret)
706a5c8b2aeSManish Narani 		pr_err("Error setting Input Tap Delay\n");
707a5c8b2aeSManish Narani 
708a5c8b2aeSManish Narani 	return ret;
709a5c8b2aeSManish Narani }
710a5c8b2aeSManish Narani 
711a5c8b2aeSManish Narani static const struct clk_ops zynqmp_sampleclk_ops = {
712a5c8b2aeSManish Narani 	.recalc_rate = sdhci_arasan_sampleclk_recalc_rate,
713a5c8b2aeSManish Narani 	.set_phase = sdhci_zynqmp_sampleclk_set_phase,
714a5c8b2aeSManish Narani };
715a5c8b2aeSManish Narani 
7161a470721SManish Narani /**
7171a470721SManish Narani  * sdhci_versal_sdcardclk_set_phase - Set the SD Output Clock Tap Delays
7181a470721SManish Narani  *
7194908460eSManish Narani  * @hw:			Pointer to the hardware clock structure.
7204908460eSManish Narani  * @degrees:		The clock phase shift between 0 - 359.
7214908460eSManish Narani  *
7221a470721SManish Narani  * Set the SD Output Clock Tap Delays for Output path
7231a470721SManish Narani  *
7241a470721SManish Narani  * Return: 0 on success and error value on error
7251a470721SManish Narani  */
7261a470721SManish Narani static int sdhci_versal_sdcardclk_set_phase(struct clk_hw *hw, int degrees)
7271a470721SManish Narani {
7281a470721SManish Narani 	struct sdhci_arasan_clk_data *clk_data =
7291a470721SManish Narani 		container_of(hw, struct sdhci_arasan_clk_data, sdcardclk_hw);
7301a470721SManish Narani 	struct sdhci_arasan_data *sdhci_arasan =
7311a470721SManish Narani 		container_of(clk_data, struct sdhci_arasan_data, clk_data);
7321a470721SManish Narani 	struct sdhci_host *host = sdhci_arasan->host;
7331a470721SManish Narani 	u8 tap_delay, tap_max = 0;
7341a470721SManish Narani 
7359e953432SManish Narani 	/* This is applicable for SDHCI_SPEC_300 and above */
7369e953432SManish Narani 	if (host->version < SDHCI_SPEC_300)
7371a470721SManish Narani 		return 0;
7381a470721SManish Narani 
7391a470721SManish Narani 	switch (host->timing) {
7401a470721SManish Narani 	case MMC_TIMING_MMC_HS:
7411a470721SManish Narani 	case MMC_TIMING_SD_HS:
7421a470721SManish Narani 	case MMC_TIMING_UHS_SDR25:
7431a470721SManish Narani 	case MMC_TIMING_UHS_DDR50:
7441a470721SManish Narani 	case MMC_TIMING_MMC_DDR52:
7451a470721SManish Narani 		/* For 50MHz clock, 30 Taps are available */
7461a470721SManish Narani 		tap_max = 30;
7471a470721SManish Narani 		break;
7481a470721SManish Narani 	case MMC_TIMING_UHS_SDR50:
7491a470721SManish Narani 		/* For 100MHz clock, 15 Taps are available */
7501a470721SManish Narani 		tap_max = 15;
7511a470721SManish Narani 		break;
7521a470721SManish Narani 	case MMC_TIMING_UHS_SDR104:
7531a470721SManish Narani 	case MMC_TIMING_MMC_HS200:
7541a470721SManish Narani 		/* For 200MHz clock, 8 Taps are available */
7551a470721SManish Narani 		tap_max = 8;
756a3096ec6SGustavo A. R. Silva 		break;
7571a470721SManish Narani 	default:
7581a470721SManish Narani 		break;
7591a470721SManish Narani 	}
7601a470721SManish Narani 
7611a470721SManish Narani 	tap_delay = (degrees * tap_max) / 360;
7621a470721SManish Narani 
7631a470721SManish Narani 	/* Set the Clock Phase */
7641a470721SManish Narani 	if (tap_delay) {
7651a470721SManish Narani 		u32 regval;
7661a470721SManish Narani 
7671a470721SManish Narani 		regval = sdhci_readl(host, SDHCI_ARASAN_OTAPDLY_REGISTER);
7681a470721SManish Narani 		regval |= SDHCI_OTAPDLY_ENABLE;
7691a470721SManish Narani 		sdhci_writel(host, regval, SDHCI_ARASAN_OTAPDLY_REGISTER);
770d338c6d0SManish Narani 		regval &= ~SDHCI_ARASAN_OTAPDLY_SEL_MASK;
7711a470721SManish Narani 		regval |= tap_delay;
7721a470721SManish Narani 		sdhci_writel(host, regval, SDHCI_ARASAN_OTAPDLY_REGISTER);
7731a470721SManish Narani 	}
7741a470721SManish Narani 
775098c408bSNathan Chancellor 	return 0;
7761a470721SManish Narani }
7771a470721SManish Narani 
7781a470721SManish Narani static const struct clk_ops versal_sdcardclk_ops = {
7791a470721SManish Narani 	.recalc_rate = sdhci_arasan_sdcardclk_recalc_rate,
7801a470721SManish Narani 	.set_phase = sdhci_versal_sdcardclk_set_phase,
7811a470721SManish Narani };
7821a470721SManish Narani 
7831a470721SManish Narani /**
7841a470721SManish Narani  * sdhci_versal_sampleclk_set_phase - Set the SD Input Clock Tap Delays
7851a470721SManish Narani  *
7864908460eSManish Narani  * @hw:			Pointer to the hardware clock structure.
7874908460eSManish Narani  * @degrees:		The clock phase shift between 0 - 359.
7884908460eSManish Narani  *
7891a470721SManish Narani  * Set the SD Input Clock Tap Delays for Input path
7901a470721SManish Narani  *
7911a470721SManish Narani  * Return: 0 on success and error value on error
7921a470721SManish Narani  */
7931a470721SManish Narani static int sdhci_versal_sampleclk_set_phase(struct clk_hw *hw, int degrees)
7941a470721SManish Narani {
7951a470721SManish Narani 	struct sdhci_arasan_clk_data *clk_data =
7961a470721SManish Narani 		container_of(hw, struct sdhci_arasan_clk_data, sampleclk_hw);
7971a470721SManish Narani 	struct sdhci_arasan_data *sdhci_arasan =
7981a470721SManish Narani 		container_of(clk_data, struct sdhci_arasan_data, clk_data);
7991a470721SManish Narani 	struct sdhci_host *host = sdhci_arasan->host;
8001a470721SManish Narani 	u8 tap_delay, tap_max = 0;
8011a470721SManish Narani 
8029e953432SManish Narani 	/* This is applicable for SDHCI_SPEC_300 and above */
8039e953432SManish Narani 	if (host->version < SDHCI_SPEC_300)
8041a470721SManish Narani 		return 0;
8051a470721SManish Narani 
8061a470721SManish Narani 	switch (host->timing) {
8071a470721SManish Narani 	case MMC_TIMING_MMC_HS:
8081a470721SManish Narani 	case MMC_TIMING_SD_HS:
8091a470721SManish Narani 	case MMC_TIMING_UHS_SDR25:
8101a470721SManish Narani 	case MMC_TIMING_UHS_DDR50:
8111a470721SManish Narani 	case MMC_TIMING_MMC_DDR52:
8121a470721SManish Narani 		/* For 50MHz clock, 120 Taps are available */
8131a470721SManish Narani 		tap_max = 120;
8141a470721SManish Narani 		break;
8151a470721SManish Narani 	case MMC_TIMING_UHS_SDR50:
8161a470721SManish Narani 		/* For 100MHz clock, 60 Taps are available */
8171a470721SManish Narani 		tap_max = 60;
8181a470721SManish Narani 		break;
8191a470721SManish Narani 	case MMC_TIMING_UHS_SDR104:
8201a470721SManish Narani 	case MMC_TIMING_MMC_HS200:
8211a470721SManish Narani 		/* For 200MHz clock, 30 Taps are available */
8221a470721SManish Narani 		tap_max = 30;
823a3096ec6SGustavo A. R. Silva 		break;
8241a470721SManish Narani 	default:
8251a470721SManish Narani 		break;
8261a470721SManish Narani 	}
8271a470721SManish Narani 
8281a470721SManish Narani 	tap_delay = (degrees * tap_max) / 360;
8291a470721SManish Narani 
8301a470721SManish Narani 	/* Set the Clock Phase */
8311a470721SManish Narani 	if (tap_delay) {
8321a470721SManish Narani 		u32 regval;
8331a470721SManish Narani 
8341a470721SManish Narani 		regval = sdhci_readl(host, SDHCI_ARASAN_ITAPDLY_REGISTER);
8351a470721SManish Narani 		regval |= SDHCI_ITAPDLY_CHGWIN;
8361a470721SManish Narani 		sdhci_writel(host, regval, SDHCI_ARASAN_ITAPDLY_REGISTER);
8371a470721SManish Narani 		regval |= SDHCI_ITAPDLY_ENABLE;
8381a470721SManish Narani 		sdhci_writel(host, regval, SDHCI_ARASAN_ITAPDLY_REGISTER);
839d338c6d0SManish Narani 		regval &= ~SDHCI_ARASAN_ITAPDLY_SEL_MASK;
8401a470721SManish Narani 		regval |= tap_delay;
8411a470721SManish Narani 		sdhci_writel(host, regval, SDHCI_ARASAN_ITAPDLY_REGISTER);
8421a470721SManish Narani 		regval &= ~SDHCI_ITAPDLY_CHGWIN;
8431a470721SManish Narani 		sdhci_writel(host, regval, SDHCI_ARASAN_ITAPDLY_REGISTER);
8441a470721SManish Narani 	}
8451a470721SManish Narani 
846098c408bSNathan Chancellor 	return 0;
8471a470721SManish Narani }
8481a470721SManish Narani 
8491a470721SManish Narani static const struct clk_ops versal_sampleclk_ops = {
8501a470721SManish Narani 	.recalc_rate = sdhci_arasan_sampleclk_recalc_rate,
8511a470721SManish Narani 	.set_phase = sdhci_versal_sampleclk_set_phase,
8521a470721SManish Narani };
8531a470721SManish Narani 
8548d2e3343SManish Narani static void arasan_zynqmp_dll_reset(struct sdhci_host *host, u32 deviceid)
8558d2e3343SManish Narani {
8568d2e3343SManish Narani 	u16 clk;
8578d2e3343SManish Narani 
8588d2e3343SManish Narani 	clk = sdhci_readw(host, SDHCI_CLOCK_CONTROL);
8598d2e3343SManish Narani 	clk &= ~(SDHCI_CLOCK_CARD_EN | SDHCI_CLOCK_INT_EN);
8608d2e3343SManish Narani 	sdhci_writew(host, clk, SDHCI_CLOCK_CONTROL);
8618d2e3343SManish Narani 
8628d2e3343SManish Narani 	/* Issue DLL Reset */
863426c8d85SRajan Vaja 	zynqmp_pm_sd_dll_reset(deviceid, PM_DLL_RESET_PULSE);
8648d2e3343SManish Narani 
8658d2e3343SManish Narani 	clk = sdhci_readw(host, SDHCI_CLOCK_CONTROL);
8668d2e3343SManish Narani 
8678d2e3343SManish Narani 	sdhci_enable_clk(host, clk);
8688d2e3343SManish Narani }
8698d2e3343SManish Narani 
8708d2e3343SManish Narani static int arasan_zynqmp_execute_tuning(struct mmc_host *mmc, u32 opcode)
8718d2e3343SManish Narani {
8728d2e3343SManish Narani 	struct sdhci_host *host = mmc_priv(mmc);
8738d2e3343SManish Narani 	struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
8748d2e3343SManish Narani 	struct sdhci_arasan_data *sdhci_arasan = sdhci_pltfm_priv(pltfm_host);
8758d2e3343SManish Narani 	struct clk_hw *hw = &sdhci_arasan->clk_data.sdcardclk_hw;
8768d2e3343SManish Narani 	const char *clk_name = clk_hw_get_name(hw);
8778d2e3343SManish Narani 	u32 device_id = !strcmp(clk_name, "clk_out_sd0") ? NODE_SD_0 :
8788d2e3343SManish Narani 							   NODE_SD_1;
8798d2e3343SManish Narani 	int err;
8808d2e3343SManish Narani 
8818d2e3343SManish Narani 	arasan_zynqmp_dll_reset(host, device_id);
8828d2e3343SManish Narani 
8838d2e3343SManish Narani 	err = sdhci_execute_tuning(mmc, opcode);
8848d2e3343SManish Narani 	if (err)
8858d2e3343SManish Narani 		return err;
8868d2e3343SManish Narani 
8878d2e3343SManish Narani 	arasan_zynqmp_dll_reset(host, device_id);
8888d2e3343SManish Narani 
8898d2e3343SManish Narani 	return 0;
8908d2e3343SManish Narani }
8918d2e3343SManish Narani 
892a5c8b2aeSManish Narani /**
893b2ca77c9SShawn Lin  * sdhci_arasan_update_clockmultiplier - Set corecfg_clockmultiplier
894b2ca77c9SShawn Lin  *
8954908460eSManish Narani  * @host:		The sdhci_host
8964908460eSManish Narani  * @value:		The value to write
8974908460eSManish Narani  *
898b2ca77c9SShawn Lin  * The corecfg_clockmultiplier is supposed to contain clock multiplier
899b2ca77c9SShawn Lin  * value of programmable clock generator.
900b2ca77c9SShawn Lin  *
901b2ca77c9SShawn Lin  * NOTES:
902b2ca77c9SShawn Lin  * - Many existing devices don't seem to do this and work fine.  To keep
903b2ca77c9SShawn Lin  *   compatibility for old hardware where the device tree doesn't provide a
904b2ca77c9SShawn Lin  *   register map, this function is a noop if a soc_ctl_map hasn't been provided
905b2ca77c9SShawn Lin  *   for this platform.
906b2ca77c9SShawn Lin  * - The value of corecfg_clockmultiplier should sync with that of corresponding
907b2ca77c9SShawn Lin  *   value reading from sdhci_capability_register. So this function is called
908b2ca77c9SShawn Lin  *   once at probe time and never called again.
909b2ca77c9SShawn Lin  */
910b2ca77c9SShawn Lin static void sdhci_arasan_update_clockmultiplier(struct sdhci_host *host,
911b2ca77c9SShawn Lin 						u32 value)
912b2ca77c9SShawn Lin {
913b2ca77c9SShawn Lin 	struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
914b2ca77c9SShawn Lin 	struct sdhci_arasan_data *sdhci_arasan = sdhci_pltfm_priv(pltfm_host);
915b2ca77c9SShawn Lin 	const struct sdhci_arasan_soc_ctl_map *soc_ctl_map =
916b2ca77c9SShawn Lin 		sdhci_arasan->soc_ctl_map;
917b2ca77c9SShawn Lin 
918b2ca77c9SShawn Lin 	/* Having a map is optional */
919b2ca77c9SShawn Lin 	if (!soc_ctl_map)
920b2ca77c9SShawn Lin 		return;
921b2ca77c9SShawn Lin 
922b2ca77c9SShawn Lin 	/* If we have a map, we expect to have a syscon */
923b2ca77c9SShawn Lin 	if (!sdhci_arasan->soc_ctl_base) {
924b2ca77c9SShawn Lin 		pr_warn("%s: Have regmap, but no soc-ctl-syscon\n",
925b2ca77c9SShawn Lin 			mmc_hostname(host->mmc));
926b2ca77c9SShawn Lin 		return;
927b2ca77c9SShawn Lin 	}
928b2ca77c9SShawn Lin 
929b2ca77c9SShawn Lin 	sdhci_arasan_syscon_write(host, &soc_ctl_map->clockmultiplier, value);
930b2ca77c9SShawn Lin }
931b2ca77c9SShawn Lin 
932b2ca77c9SShawn Lin /**
9333ea4666eSDouglas Anderson  * sdhci_arasan_update_baseclkfreq - Set corecfg_baseclkfreq
9343ea4666eSDouglas Anderson  *
9354908460eSManish Narani  * @host:		The sdhci_host
9364908460eSManish Narani  *
9373ea4666eSDouglas Anderson  * The corecfg_baseclkfreq is supposed to contain the MHz of clk_xin.  This
9383ea4666eSDouglas Anderson  * function can be used to make that happen.
9393ea4666eSDouglas Anderson  *
9403ea4666eSDouglas Anderson  * NOTES:
9413ea4666eSDouglas Anderson  * - Many existing devices don't seem to do this and work fine.  To keep
9423ea4666eSDouglas Anderson  *   compatibility for old hardware where the device tree doesn't provide a
9433ea4666eSDouglas Anderson  *   register map, this function is a noop if a soc_ctl_map hasn't been provided
9443ea4666eSDouglas Anderson  *   for this platform.
9453ea4666eSDouglas Anderson  * - It's assumed that clk_xin is not dynamic and that we use the SDHCI divider
9463ea4666eSDouglas Anderson  *   to achieve lower clock rates.  That means that this function is called once
9473ea4666eSDouglas Anderson  *   at probe time and never called again.
9483ea4666eSDouglas Anderson  */
9493ea4666eSDouglas Anderson static void sdhci_arasan_update_baseclkfreq(struct sdhci_host *host)
9503ea4666eSDouglas Anderson {
9513ea4666eSDouglas Anderson 	struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
9523ea4666eSDouglas Anderson 	struct sdhci_arasan_data *sdhci_arasan = sdhci_pltfm_priv(pltfm_host);
9533ea4666eSDouglas Anderson 	const struct sdhci_arasan_soc_ctl_map *soc_ctl_map =
9543ea4666eSDouglas Anderson 		sdhci_arasan->soc_ctl_map;
9553ea4666eSDouglas Anderson 	u32 mhz = DIV_ROUND_CLOSEST(clk_get_rate(pltfm_host->clk), 1000000);
9563ea4666eSDouglas Anderson 
9573ea4666eSDouglas Anderson 	/* Having a map is optional */
9583ea4666eSDouglas Anderson 	if (!soc_ctl_map)
9593ea4666eSDouglas Anderson 		return;
9603ea4666eSDouglas Anderson 
9613ea4666eSDouglas Anderson 	/* If we have a map, we expect to have a syscon */
9623ea4666eSDouglas Anderson 	if (!sdhci_arasan->soc_ctl_base) {
9633ea4666eSDouglas Anderson 		pr_warn("%s: Have regmap, but no soc-ctl-syscon\n",
9643ea4666eSDouglas Anderson 			mmc_hostname(host->mmc));
9653ea4666eSDouglas Anderson 		return;
9663ea4666eSDouglas Anderson 	}
9673ea4666eSDouglas Anderson 
9683ea4666eSDouglas Anderson 	sdhci_arasan_syscon_write(host, &soc_ctl_map->baseclkfreq, mhz);
9693ea4666eSDouglas Anderson }
9703ea4666eSDouglas Anderson 
971f3dafc37SManish Narani static void sdhci_arasan_set_clk_delays(struct sdhci_host *host)
972f3dafc37SManish Narani {
973f3dafc37SManish Narani 	struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
974f3dafc37SManish Narani 	struct sdhci_arasan_data *sdhci_arasan = sdhci_pltfm_priv(pltfm_host);
975f3dafc37SManish Narani 	struct sdhci_arasan_clk_data *clk_data = &sdhci_arasan->clk_data;
976f3dafc37SManish Narani 
977f3dafc37SManish Narani 	clk_set_phase(clk_data->sampleclk,
978f3dafc37SManish Narani 		      clk_data->clk_phase_in[host->timing]);
979f3dafc37SManish Narani 	clk_set_phase(clk_data->sdcardclk,
980f3dafc37SManish Narani 		      clk_data->clk_phase_out[host->timing]);
981f3dafc37SManish Narani }
982f3dafc37SManish Narani 
983f3dafc37SManish Narani static void arasan_dt_read_clk_phase(struct device *dev,
984f3dafc37SManish Narani 				     struct sdhci_arasan_clk_data *clk_data,
985f3dafc37SManish Narani 				     unsigned int timing, const char *prop)
986f3dafc37SManish Narani {
987f3dafc37SManish Narani 	struct device_node *np = dev->of_node;
988f3dafc37SManish Narani 
989f3dafc37SManish Narani 	int clk_phase[2] = {0};
990f3dafc37SManish Narani 
991f3dafc37SManish Narani 	/*
992f3dafc37SManish Narani 	 * Read Tap Delay values from DT, if the DT does not contain the
993f3dafc37SManish Narani 	 * Tap Values then use the pre-defined values.
994f3dafc37SManish Narani 	 */
995f3dafc37SManish Narani 	if (of_property_read_variable_u32_array(np, prop, &clk_phase[0],
996f3dafc37SManish Narani 						2, 0)) {
997f3dafc37SManish Narani 		dev_dbg(dev, "Using predefined clock phase for %s = %d %d\n",
998f3dafc37SManish Narani 			prop, clk_data->clk_phase_in[timing],
999f3dafc37SManish Narani 			clk_data->clk_phase_out[timing]);
1000f3dafc37SManish Narani 		return;
1001f3dafc37SManish Narani 	}
1002f3dafc37SManish Narani 
1003f3dafc37SManish Narani 	/* The values read are Input and Output Clock Delays in order */
1004f3dafc37SManish Narani 	clk_data->clk_phase_in[timing] = clk_phase[0];
1005f3dafc37SManish Narani 	clk_data->clk_phase_out[timing] = clk_phase[1];
1006f3dafc37SManish Narani }
1007f3dafc37SManish Narani 
1008f3dafc37SManish Narani /**
1009f3dafc37SManish Narani  * arasan_dt_parse_clk_phases - Read Clock Delay values from DT
1010f3dafc37SManish Narani  *
1011f3dafc37SManish Narani  * @dev:		Pointer to our struct device.
1012f3dafc37SManish Narani  * @clk_data:		Pointer to the Clock Data structure
10134908460eSManish Narani  *
10144908460eSManish Narani  * Called at initialization to parse the values of Clock Delays.
1015f3dafc37SManish Narani  */
1016f3dafc37SManish Narani static void arasan_dt_parse_clk_phases(struct device *dev,
1017f3dafc37SManish Narani 				       struct sdhci_arasan_clk_data *clk_data)
1018f3dafc37SManish Narani {
1019a5c8b2aeSManish Narani 	u32 mio_bank = 0;
1020a5c8b2aeSManish Narani 	int i;
1021a5c8b2aeSManish Narani 
1022f3dafc37SManish Narani 	/*
1023f3dafc37SManish Narani 	 * This has been kept as a pointer and is assigned a function here.
1024f3dafc37SManish Narani 	 * So that different controller variants can assign their own handling
1025f3dafc37SManish Narani 	 * function.
1026f3dafc37SManish Narani 	 */
1027f3dafc37SManish Narani 	clk_data->set_clk_delays = sdhci_arasan_set_clk_delays;
1028f3dafc37SManish Narani 
1029a5c8b2aeSManish Narani 	if (of_device_is_compatible(dev->of_node, "xlnx,zynqmp-8.9a")) {
103088e1d0b1SManish Narani 		u32 zynqmp_iclk_phase[MMC_TIMING_MMC_HS400 + 1] =
103188e1d0b1SManish Narani 			ZYNQMP_ICLK_PHASE;
103288e1d0b1SManish Narani 		u32 zynqmp_oclk_phase[MMC_TIMING_MMC_HS400 + 1] =
103388e1d0b1SManish Narani 			ZYNQMP_OCLK_PHASE;
1034a5c8b2aeSManish Narani 
1035a5c8b2aeSManish Narani 		of_property_read_u32(dev->of_node, "xlnx,mio-bank", &mio_bank);
1036a5c8b2aeSManish Narani 		if (mio_bank == 2) {
103788e1d0b1SManish Narani 			zynqmp_oclk_phase[MMC_TIMING_UHS_SDR104] = 90;
103888e1d0b1SManish Narani 			zynqmp_oclk_phase[MMC_TIMING_MMC_HS200] = 90;
1039a5c8b2aeSManish Narani 		}
1040a5c8b2aeSManish Narani 
1041a5c8b2aeSManish Narani 		for (i = 0; i <= MMC_TIMING_MMC_HS400; i++) {
104288e1d0b1SManish Narani 			clk_data->clk_phase_in[i] = zynqmp_iclk_phase[i];
104388e1d0b1SManish Narani 			clk_data->clk_phase_out[i] = zynqmp_oclk_phase[i];
1044a5c8b2aeSManish Narani 		}
1045a5c8b2aeSManish Narani 	}
1046a5c8b2aeSManish Narani 
10471a470721SManish Narani 	if (of_device_is_compatible(dev->of_node, "xlnx,versal-8.9a")) {
104888e1d0b1SManish Narani 		u32 versal_iclk_phase[MMC_TIMING_MMC_HS400 + 1] =
104988e1d0b1SManish Narani 			VERSAL_ICLK_PHASE;
105088e1d0b1SManish Narani 		u32 versal_oclk_phase[MMC_TIMING_MMC_HS400 + 1] =
105188e1d0b1SManish Narani 			VERSAL_OCLK_PHASE;
10521a470721SManish Narani 
10531a470721SManish Narani 		for (i = 0; i <= MMC_TIMING_MMC_HS400; i++) {
105488e1d0b1SManish Narani 			clk_data->clk_phase_in[i] = versal_iclk_phase[i];
105588e1d0b1SManish Narani 			clk_data->clk_phase_out[i] = versal_oclk_phase[i];
10561a470721SManish Narani 		}
10571a470721SManish Narani 	}
10581a470721SManish Narani 
1059f3dafc37SManish Narani 	arasan_dt_read_clk_phase(dev, clk_data, MMC_TIMING_LEGACY,
1060f3dafc37SManish Narani 				 "clk-phase-legacy");
1061f3dafc37SManish Narani 	arasan_dt_read_clk_phase(dev, clk_data, MMC_TIMING_MMC_HS,
1062f3dafc37SManish Narani 				 "clk-phase-mmc-hs");
1063f3dafc37SManish Narani 	arasan_dt_read_clk_phase(dev, clk_data, MMC_TIMING_SD_HS,
1064f3dafc37SManish Narani 				 "clk-phase-sd-hs");
1065f3dafc37SManish Narani 	arasan_dt_read_clk_phase(dev, clk_data, MMC_TIMING_UHS_SDR12,
1066f3dafc37SManish Narani 				 "clk-phase-uhs-sdr12");
1067f3dafc37SManish Narani 	arasan_dt_read_clk_phase(dev, clk_data, MMC_TIMING_UHS_SDR25,
1068f3dafc37SManish Narani 				 "clk-phase-uhs-sdr25");
1069f3dafc37SManish Narani 	arasan_dt_read_clk_phase(dev, clk_data, MMC_TIMING_UHS_SDR50,
1070f3dafc37SManish Narani 				 "clk-phase-uhs-sdr50");
1071f3dafc37SManish Narani 	arasan_dt_read_clk_phase(dev, clk_data, MMC_TIMING_UHS_SDR104,
1072f3dafc37SManish Narani 				 "clk-phase-uhs-sdr104");
1073f3dafc37SManish Narani 	arasan_dt_read_clk_phase(dev, clk_data, MMC_TIMING_UHS_DDR50,
1074f3dafc37SManish Narani 				 "clk-phase-uhs-ddr50");
1075f3dafc37SManish Narani 	arasan_dt_read_clk_phase(dev, clk_data, MMC_TIMING_MMC_DDR52,
1076f3dafc37SManish Narani 				 "clk-phase-mmc-ddr52");
1077f3dafc37SManish Narani 	arasan_dt_read_clk_phase(dev, clk_data, MMC_TIMING_MMC_HS200,
1078f3dafc37SManish Narani 				 "clk-phase-mmc-hs200");
1079f3dafc37SManish Narani 	arasan_dt_read_clk_phase(dev, clk_data, MMC_TIMING_MMC_HS400,
1080f3dafc37SManish Narani 				 "clk-phase-mmc-hs400");
1081f3dafc37SManish Narani }
1082f3dafc37SManish Narani 
108337d3ee7cSManish Narani static const struct sdhci_pltfm_data sdhci_arasan_pdata = {
108437d3ee7cSManish Narani 	.ops = &sdhci_arasan_ops,
108537d3ee7cSManish Narani 	.quirks = SDHCI_QUIRK_CAP_CLOCK_BASE_BROKEN,
108637d3ee7cSManish Narani 	.quirks2 = SDHCI_QUIRK2_PRESET_VALUE_BROKEN |
108737d3ee7cSManish Narani 			SDHCI_QUIRK2_CLOCK_DIV_ZERO_BROKEN |
108837d3ee7cSManish Narani 			SDHCI_QUIRK2_STOP_WITH_TC,
108937d3ee7cSManish Narani };
109037d3ee7cSManish Narani 
109116ada730SManish Narani static const struct sdhci_arasan_clk_ops arasan_clk_ops = {
109216ada730SManish Narani 	.sdcardclk_ops = &arasan_sdcardclk_ops,
109316ada730SManish Narani 	.sampleclk_ops = &arasan_sampleclk_ops,
109416ada730SManish Narani };
109516ada730SManish Narani 
109637d3ee7cSManish Narani static struct sdhci_arasan_of_data sdhci_arasan_generic_data = {
109737d3ee7cSManish Narani 	.pdata = &sdhci_arasan_pdata,
109816ada730SManish Narani 	.clk_ops = &arasan_clk_ops,
109937d3ee7cSManish Narani };
110037d3ee7cSManish Narani 
110136c6aadaSWan Ahmad Zainie static const struct sdhci_pltfm_data sdhci_keembay_emmc_pdata = {
110236c6aadaSWan Ahmad Zainie 	.ops = &sdhci_arasan_cqe_ops,
110336c6aadaSWan Ahmad Zainie 	.quirks = SDHCI_QUIRK_CAP_CLOCK_BASE_BROKEN |
110436c6aadaSWan Ahmad Zainie 		SDHCI_QUIRK_NO_ENDATTR_IN_NOPDESC |
110536c6aadaSWan Ahmad Zainie 		SDHCI_QUIRK_NO_LED |
110636c6aadaSWan Ahmad Zainie 		SDHCI_QUIRK_32BIT_DMA_ADDR |
110736c6aadaSWan Ahmad Zainie 		SDHCI_QUIRK_32BIT_DMA_SIZE |
110836c6aadaSWan Ahmad Zainie 		SDHCI_QUIRK_32BIT_ADMA_SIZE,
110936c6aadaSWan Ahmad Zainie 	.quirks2 = SDHCI_QUIRK2_PRESET_VALUE_BROKEN |
111036c6aadaSWan Ahmad Zainie 		SDHCI_QUIRK2_CLOCK_DIV_ZERO_BROKEN |
111136c6aadaSWan Ahmad Zainie 		SDHCI_QUIRK2_CAPS_BIT63_FOR_HS400 |
111236c6aadaSWan Ahmad Zainie 		SDHCI_QUIRK2_STOP_WITH_TC |
111336c6aadaSWan Ahmad Zainie 		SDHCI_QUIRK2_BROKEN_64_BIT_DMA,
111436c6aadaSWan Ahmad Zainie };
111536c6aadaSWan Ahmad Zainie 
111636c6aadaSWan Ahmad Zainie static const struct sdhci_pltfm_data sdhci_keembay_sd_pdata = {
111736c6aadaSWan Ahmad Zainie 	.ops = &sdhci_arasan_ops,
111836c6aadaSWan Ahmad Zainie 	.quirks = SDHCI_QUIRK_CAP_CLOCK_BASE_BROKEN |
111936c6aadaSWan Ahmad Zainie 		SDHCI_QUIRK_NO_ENDATTR_IN_NOPDESC |
112036c6aadaSWan Ahmad Zainie 		SDHCI_QUIRK_NO_LED |
112136c6aadaSWan Ahmad Zainie 		SDHCI_QUIRK_32BIT_DMA_ADDR |
112236c6aadaSWan Ahmad Zainie 		SDHCI_QUIRK_32BIT_DMA_SIZE |
112336c6aadaSWan Ahmad Zainie 		SDHCI_QUIRK_32BIT_ADMA_SIZE,
112436c6aadaSWan Ahmad Zainie 	.quirks2 = SDHCI_QUIRK2_PRESET_VALUE_BROKEN |
112536c6aadaSWan Ahmad Zainie 		SDHCI_QUIRK2_CLOCK_DIV_ZERO_BROKEN |
112636c6aadaSWan Ahmad Zainie 		SDHCI_QUIRK2_CARD_ON_NEEDS_BUS_ON |
112736c6aadaSWan Ahmad Zainie 		SDHCI_QUIRK2_STOP_WITH_TC |
112836c6aadaSWan Ahmad Zainie 		SDHCI_QUIRK2_BROKEN_64_BIT_DMA,
112936c6aadaSWan Ahmad Zainie };
113036c6aadaSWan Ahmad Zainie 
113136c6aadaSWan Ahmad Zainie static const struct sdhci_pltfm_data sdhci_keembay_sdio_pdata = {
113236c6aadaSWan Ahmad Zainie 	.ops = &sdhci_arasan_ops,
113336c6aadaSWan Ahmad Zainie 	.quirks = SDHCI_QUIRK_CAP_CLOCK_BASE_BROKEN |
113436c6aadaSWan Ahmad Zainie 		SDHCI_QUIRK_NO_ENDATTR_IN_NOPDESC |
113536c6aadaSWan Ahmad Zainie 		SDHCI_QUIRK_NO_LED |
113636c6aadaSWan Ahmad Zainie 		SDHCI_QUIRK_32BIT_DMA_ADDR |
113736c6aadaSWan Ahmad Zainie 		SDHCI_QUIRK_32BIT_DMA_SIZE |
113836c6aadaSWan Ahmad Zainie 		SDHCI_QUIRK_32BIT_ADMA_SIZE,
113936c6aadaSWan Ahmad Zainie 	.quirks2 = SDHCI_QUIRK2_PRESET_VALUE_BROKEN |
114036c6aadaSWan Ahmad Zainie 		SDHCI_QUIRK2_CLOCK_DIV_ZERO_BROKEN |
114136c6aadaSWan Ahmad Zainie 		SDHCI_QUIRK2_HOST_OFF_CARD_ON |
114236c6aadaSWan Ahmad Zainie 		SDHCI_QUIRK2_BROKEN_64_BIT_DMA,
114336c6aadaSWan Ahmad Zainie };
114436c6aadaSWan Ahmad Zainie 
114537d3ee7cSManish Narani static struct sdhci_arasan_of_data sdhci_arasan_rk3399_data = {
114637d3ee7cSManish Narani 	.soc_ctl_map = &rk3399_soc_ctl_map,
114737d3ee7cSManish Narani 	.pdata = &sdhci_arasan_cqe_pdata,
114816ada730SManish Narani 	.clk_ops = &arasan_clk_ops,
114937d3ee7cSManish Narani };
115037d3ee7cSManish Narani 
115137d3ee7cSManish Narani static struct sdhci_arasan_of_data intel_lgm_emmc_data = {
115237d3ee7cSManish Narani 	.soc_ctl_map = &intel_lgm_emmc_soc_ctl_map,
115337d3ee7cSManish Narani 	.pdata = &sdhci_arasan_cqe_pdata,
115416ada730SManish Narani 	.clk_ops = &arasan_clk_ops,
115537d3ee7cSManish Narani };
115637d3ee7cSManish Narani 
115737d3ee7cSManish Narani static struct sdhci_arasan_of_data intel_lgm_sdxc_data = {
115837d3ee7cSManish Narani 	.soc_ctl_map = &intel_lgm_sdxc_soc_ctl_map,
115937d3ee7cSManish Narani 	.pdata = &sdhci_arasan_cqe_pdata,
116016ada730SManish Narani 	.clk_ops = &arasan_clk_ops,
116137d3ee7cSManish Narani };
116237d3ee7cSManish Narani 
116337d3ee7cSManish Narani static const struct sdhci_pltfm_data sdhci_arasan_zynqmp_pdata = {
116437d3ee7cSManish Narani 	.ops = &sdhci_arasan_ops,
116537d3ee7cSManish Narani 	.quirks2 = SDHCI_QUIRK2_PRESET_VALUE_BROKEN |
116637d3ee7cSManish Narani 			SDHCI_QUIRK2_CLOCK_DIV_ZERO_BROKEN |
116737d3ee7cSManish Narani 			SDHCI_QUIRK2_STOP_WITH_TC,
116837d3ee7cSManish Narani };
116937d3ee7cSManish Narani 
117016ada730SManish Narani static const struct sdhci_arasan_clk_ops zynqmp_clk_ops = {
117116ada730SManish Narani 	.sdcardclk_ops = &zynqmp_sdcardclk_ops,
117216ada730SManish Narani 	.sampleclk_ops = &zynqmp_sampleclk_ops,
117316ada730SManish Narani };
117416ada730SManish Narani 
117537d3ee7cSManish Narani static struct sdhci_arasan_of_data sdhci_arasan_zynqmp_data = {
117637d3ee7cSManish Narani 	.pdata = &sdhci_arasan_zynqmp_pdata,
117716ada730SManish Narani 	.clk_ops = &zynqmp_clk_ops,
117816ada730SManish Narani };
117916ada730SManish Narani 
118016ada730SManish Narani static const struct sdhci_arasan_clk_ops versal_clk_ops = {
118116ada730SManish Narani 	.sdcardclk_ops = &versal_sdcardclk_ops,
118216ada730SManish Narani 	.sampleclk_ops = &versal_sampleclk_ops,
118337d3ee7cSManish Narani };
118437d3ee7cSManish Narani 
118537d3ee7cSManish Narani static struct sdhci_arasan_of_data sdhci_arasan_versal_data = {
118637d3ee7cSManish Narani 	.pdata = &sdhci_arasan_zynqmp_pdata,
118716ada730SManish Narani 	.clk_ops = &versal_clk_ops,
118837d3ee7cSManish Narani };
118937d3ee7cSManish Narani 
119036c6aadaSWan Ahmad Zainie static struct sdhci_arasan_of_data intel_keembay_emmc_data = {
119136c6aadaSWan Ahmad Zainie 	.soc_ctl_map = &intel_keembay_soc_ctl_map,
119236c6aadaSWan Ahmad Zainie 	.pdata = &sdhci_keembay_emmc_pdata,
1193a42a7ec9SMuhammad Husaini Zulkifli 	.clk_ops = &arasan_clk_ops,
119436c6aadaSWan Ahmad Zainie };
119536c6aadaSWan Ahmad Zainie 
119636c6aadaSWan Ahmad Zainie static struct sdhci_arasan_of_data intel_keembay_sd_data = {
119736c6aadaSWan Ahmad Zainie 	.soc_ctl_map = &intel_keembay_soc_ctl_map,
119836c6aadaSWan Ahmad Zainie 	.pdata = &sdhci_keembay_sd_pdata,
1199a42a7ec9SMuhammad Husaini Zulkifli 	.clk_ops = &arasan_clk_ops,
120036c6aadaSWan Ahmad Zainie };
120136c6aadaSWan Ahmad Zainie 
120236c6aadaSWan Ahmad Zainie static struct sdhci_arasan_of_data intel_keembay_sdio_data = {
120336c6aadaSWan Ahmad Zainie 	.soc_ctl_map = &intel_keembay_soc_ctl_map,
120436c6aadaSWan Ahmad Zainie 	.pdata = &sdhci_keembay_sdio_pdata,
1205a42a7ec9SMuhammad Husaini Zulkifli 	.clk_ops = &arasan_clk_ops,
120636c6aadaSWan Ahmad Zainie };
120736c6aadaSWan Ahmad Zainie 
120837d3ee7cSManish Narani static const struct of_device_id sdhci_arasan_of_match[] = {
120937d3ee7cSManish Narani 	/* SoC-specific compatible strings w/ soc_ctl_map */
121037d3ee7cSManish Narani 	{
121137d3ee7cSManish Narani 		.compatible = "rockchip,rk3399-sdhci-5.1",
121237d3ee7cSManish Narani 		.data = &sdhci_arasan_rk3399_data,
121337d3ee7cSManish Narani 	},
121437d3ee7cSManish Narani 	{
121537d3ee7cSManish Narani 		.compatible = "intel,lgm-sdhci-5.1-emmc",
121637d3ee7cSManish Narani 		.data = &intel_lgm_emmc_data,
121737d3ee7cSManish Narani 	},
121837d3ee7cSManish Narani 	{
121937d3ee7cSManish Narani 		.compatible = "intel,lgm-sdhci-5.1-sdxc",
122037d3ee7cSManish Narani 		.data = &intel_lgm_sdxc_data,
122137d3ee7cSManish Narani 	},
122236c6aadaSWan Ahmad Zainie 	{
122336c6aadaSWan Ahmad Zainie 		.compatible = "intel,keembay-sdhci-5.1-emmc",
122436c6aadaSWan Ahmad Zainie 		.data = &intel_keembay_emmc_data,
122536c6aadaSWan Ahmad Zainie 	},
122636c6aadaSWan Ahmad Zainie 	{
122736c6aadaSWan Ahmad Zainie 		.compatible = "intel,keembay-sdhci-5.1-sd",
122836c6aadaSWan Ahmad Zainie 		.data = &intel_keembay_sd_data,
122936c6aadaSWan Ahmad Zainie 	},
123036c6aadaSWan Ahmad Zainie 	{
123136c6aadaSWan Ahmad Zainie 		.compatible = "intel,keembay-sdhci-5.1-sdio",
123236c6aadaSWan Ahmad Zainie 		.data = &intel_keembay_sdio_data,
123336c6aadaSWan Ahmad Zainie 	},
123437d3ee7cSManish Narani 	/* Generic compatible below here */
123537d3ee7cSManish Narani 	{
123637d3ee7cSManish Narani 		.compatible = "arasan,sdhci-8.9a",
123737d3ee7cSManish Narani 		.data = &sdhci_arasan_generic_data,
123837d3ee7cSManish Narani 	},
123937d3ee7cSManish Narani 	{
124037d3ee7cSManish Narani 		.compatible = "arasan,sdhci-5.1",
124137d3ee7cSManish Narani 		.data = &sdhci_arasan_generic_data,
124237d3ee7cSManish Narani 	},
124337d3ee7cSManish Narani 	{
124437d3ee7cSManish Narani 		.compatible = "arasan,sdhci-4.9a",
124537d3ee7cSManish Narani 		.data = &sdhci_arasan_generic_data,
124637d3ee7cSManish Narani 	},
124737d3ee7cSManish Narani 	{
124837d3ee7cSManish Narani 		.compatible = "xlnx,zynqmp-8.9a",
124937d3ee7cSManish Narani 		.data = &sdhci_arasan_zynqmp_data,
125037d3ee7cSManish Narani 	},
125137d3ee7cSManish Narani 	{
125237d3ee7cSManish Narani 		.compatible = "xlnx,versal-8.9a",
125337d3ee7cSManish Narani 		.data = &sdhci_arasan_versal_data,
125437d3ee7cSManish Narani 	},
125537d3ee7cSManish Narani 	{ /* sentinel */ }
125637d3ee7cSManish Narani };
125737d3ee7cSManish Narani MODULE_DEVICE_TABLE(of, sdhci_arasan_of_match);
125837d3ee7cSManish Narani 
1259c390f211SDouglas Anderson /**
126007a14d1dSManish Narani  * sdhci_arasan_register_sdcardclk - Register the sdcardclk for a PHY to use
1261c390f211SDouglas Anderson  *
12624908460eSManish Narani  * @sdhci_arasan:	Our private data structure.
12634908460eSManish Narani  * @clk_xin:		Pointer to the functional clock
12644908460eSManish Narani  * @dev:		Pointer to our struct device.
12654908460eSManish Narani  *
1266c390f211SDouglas Anderson  * Some PHY devices need to know what the actual card clock is.  In order for
1267c390f211SDouglas Anderson  * them to find out, we'll provide a clock through the common clock framework
1268c390f211SDouglas Anderson  * for them to query.
1269c390f211SDouglas Anderson  *
12704908460eSManish Narani  * Return: 0 on success and error value on error
1271c390f211SDouglas Anderson  */
127207a14d1dSManish Narani static int
127307a14d1dSManish Narani sdhci_arasan_register_sdcardclk(struct sdhci_arasan_data *sdhci_arasan,
1274c390f211SDouglas Anderson 				struct clk *clk_xin,
1275c390f211SDouglas Anderson 				struct device *dev)
1276c390f211SDouglas Anderson {
1277e1463618SManish Narani 	struct sdhci_arasan_clk_data *clk_data = &sdhci_arasan->clk_data;
1278c390f211SDouglas Anderson 	struct device_node *np = dev->of_node;
1279c390f211SDouglas Anderson 	struct clk_init_data sdcardclk_init;
1280c390f211SDouglas Anderson 	const char *parent_clk_name;
1281c390f211SDouglas Anderson 	int ret;
1282c390f211SDouglas Anderson 
1283c390f211SDouglas Anderson 	ret = of_property_read_string_index(np, "clock-output-names", 0,
1284c390f211SDouglas Anderson 					    &sdcardclk_init.name);
1285c390f211SDouglas Anderson 	if (ret) {
1286c390f211SDouglas Anderson 		dev_err(dev, "DT has #clock-cells but no clock-output-names\n");
1287c390f211SDouglas Anderson 		return ret;
1288c390f211SDouglas Anderson 	}
1289c390f211SDouglas Anderson 
1290c390f211SDouglas Anderson 	parent_clk_name = __clk_get_name(clk_xin);
1291c390f211SDouglas Anderson 	sdcardclk_init.parent_names = &parent_clk_name;
1292c390f211SDouglas Anderson 	sdcardclk_init.num_parents = 1;
1293c390f211SDouglas Anderson 	sdcardclk_init.flags = CLK_GET_RATE_NOCACHE;
129416ada730SManish Narani 	sdcardclk_init.ops = sdhci_arasan->clk_ops->sdcardclk_ops;
1295c390f211SDouglas Anderson 
1296e1463618SManish Narani 	clk_data->sdcardclk_hw.init = &sdcardclk_init;
1297e1463618SManish Narani 	clk_data->sdcardclk =
1298e1463618SManish Narani 		devm_clk_register(dev, &clk_data->sdcardclk_hw);
1299c99e1d0cSChuhong Yuan 	if (IS_ERR(clk_data->sdcardclk))
1300c99e1d0cSChuhong Yuan 		return PTR_ERR(clk_data->sdcardclk);
1301e1463618SManish Narani 	clk_data->sdcardclk_hw.init = NULL;
1302c390f211SDouglas Anderson 
1303c390f211SDouglas Anderson 	ret = of_clk_add_provider(np, of_clk_src_simple_get,
1304e1463618SManish Narani 				  clk_data->sdcardclk);
1305c390f211SDouglas Anderson 	if (ret)
130607a14d1dSManish Narani 		dev_err(dev, "Failed to add sdcard clock provider\n");
130707a14d1dSManish Narani 
130807a14d1dSManish Narani 	return ret;
130907a14d1dSManish Narani }
131007a14d1dSManish Narani 
131107a14d1dSManish Narani /**
131207a14d1dSManish Narani  * sdhci_arasan_register_sampleclk - Register the sampleclk for a PHY to use
131307a14d1dSManish Narani  *
13144908460eSManish Narani  * @sdhci_arasan:	Our private data structure.
13154908460eSManish Narani  * @clk_xin:		Pointer to the functional clock
13164908460eSManish Narani  * @dev:		Pointer to our struct device.
13174908460eSManish Narani  *
131807a14d1dSManish Narani  * Some PHY devices need to know what the actual card clock is.  In order for
131907a14d1dSManish Narani  * them to find out, we'll provide a clock through the common clock framework
132007a14d1dSManish Narani  * for them to query.
132107a14d1dSManish Narani  *
13224908460eSManish Narani  * Return: 0 on success and error value on error
132307a14d1dSManish Narani  */
132407a14d1dSManish Narani static int
132507a14d1dSManish Narani sdhci_arasan_register_sampleclk(struct sdhci_arasan_data *sdhci_arasan,
132607a14d1dSManish Narani 				struct clk *clk_xin,
132707a14d1dSManish Narani 				struct device *dev)
132807a14d1dSManish Narani {
132907a14d1dSManish Narani 	struct sdhci_arasan_clk_data *clk_data = &sdhci_arasan->clk_data;
133007a14d1dSManish Narani 	struct device_node *np = dev->of_node;
133107a14d1dSManish Narani 	struct clk_init_data sampleclk_init;
133207a14d1dSManish Narani 	const char *parent_clk_name;
133307a14d1dSManish Narani 	int ret;
133407a14d1dSManish Narani 
133507a14d1dSManish Narani 	ret = of_property_read_string_index(np, "clock-output-names", 1,
133607a14d1dSManish Narani 					    &sampleclk_init.name);
133707a14d1dSManish Narani 	if (ret) {
133807a14d1dSManish Narani 		dev_err(dev, "DT has #clock-cells but no clock-output-names\n");
133907a14d1dSManish Narani 		return ret;
134007a14d1dSManish Narani 	}
134107a14d1dSManish Narani 
134207a14d1dSManish Narani 	parent_clk_name = __clk_get_name(clk_xin);
134307a14d1dSManish Narani 	sampleclk_init.parent_names = &parent_clk_name;
134407a14d1dSManish Narani 	sampleclk_init.num_parents = 1;
134507a14d1dSManish Narani 	sampleclk_init.flags = CLK_GET_RATE_NOCACHE;
134616ada730SManish Narani 	sampleclk_init.ops = sdhci_arasan->clk_ops->sampleclk_ops;
134707a14d1dSManish Narani 
134807a14d1dSManish Narani 	clk_data->sampleclk_hw.init = &sampleclk_init;
134907a14d1dSManish Narani 	clk_data->sampleclk =
135007a14d1dSManish Narani 		devm_clk_register(dev, &clk_data->sampleclk_hw);
1351c99e1d0cSChuhong Yuan 	if (IS_ERR(clk_data->sampleclk))
1352c99e1d0cSChuhong Yuan 		return PTR_ERR(clk_data->sampleclk);
135307a14d1dSManish Narani 	clk_data->sampleclk_hw.init = NULL;
135407a14d1dSManish Narani 
135507a14d1dSManish Narani 	ret = of_clk_add_provider(np, of_clk_src_simple_get,
135607a14d1dSManish Narani 				  clk_data->sampleclk);
135707a14d1dSManish Narani 	if (ret)
135807a14d1dSManish Narani 		dev_err(dev, "Failed to add sample clock provider\n");
1359c390f211SDouglas Anderson 
1360c390f211SDouglas Anderson 	return ret;
1361c390f211SDouglas Anderson }
1362c390f211SDouglas Anderson 
1363c390f211SDouglas Anderson /**
1364c390f211SDouglas Anderson  * sdhci_arasan_unregister_sdclk - Undoes sdhci_arasan_register_sdclk()
1365c390f211SDouglas Anderson  *
13664908460eSManish Narani  * @dev:		Pointer to our struct device.
13674908460eSManish Narani  *
1368c390f211SDouglas Anderson  * Should be called any time we're exiting and sdhci_arasan_register_sdclk()
1369c390f211SDouglas Anderson  * returned success.
1370c390f211SDouglas Anderson  */
1371c390f211SDouglas Anderson static void sdhci_arasan_unregister_sdclk(struct device *dev)
1372c390f211SDouglas Anderson {
1373c390f211SDouglas Anderson 	struct device_node *np = dev->of_node;
1374c390f211SDouglas Anderson 
1375c390f211SDouglas Anderson 	if (!of_find_property(np, "#clock-cells", NULL))
1376c390f211SDouglas Anderson 		return;
1377c390f211SDouglas Anderson 
1378c390f211SDouglas Anderson 	of_clk_del_provider(dev->of_node);
1379c390f211SDouglas Anderson }
1380c390f211SDouglas Anderson 
138107a14d1dSManish Narani /**
138236c6aadaSWan Ahmad Zainie  * sdhci_arasan_update_support64b - Set SUPPORT_64B (64-bit System Bus Support)
1383973c7c99SMuhammad Husaini Zulkifli  * @host:		The sdhci_host
1384973c7c99SMuhammad Husaini Zulkifli  * @value:		The value to write
138536c6aadaSWan Ahmad Zainie  *
138636c6aadaSWan Ahmad Zainie  * This should be set based on the System Address Bus.
138736c6aadaSWan Ahmad Zainie  * 0: the Core supports only 32-bit System Address Bus.
138836c6aadaSWan Ahmad Zainie  * 1: the Core supports 64-bit System Address Bus.
138936c6aadaSWan Ahmad Zainie  *
1390973c7c99SMuhammad Husaini Zulkifli  * NOTE:
1391973c7c99SMuhammad Husaini Zulkifli  * For Keem Bay, it is required to clear this bit. Its default value is 1'b1.
139236c6aadaSWan Ahmad Zainie  * Keem Bay does not support 64-bit access.
139336c6aadaSWan Ahmad Zainie  */
139436c6aadaSWan Ahmad Zainie static void sdhci_arasan_update_support64b(struct sdhci_host *host, u32 value)
139536c6aadaSWan Ahmad Zainie {
139636c6aadaSWan Ahmad Zainie 	struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
139736c6aadaSWan Ahmad Zainie 	struct sdhci_arasan_data *sdhci_arasan = sdhci_pltfm_priv(pltfm_host);
1398db845093SMuhammad Husaini Zulkifli 	const struct sdhci_arasan_soc_ctl_map *soc_ctl_map;
139936c6aadaSWan Ahmad Zainie 
140036c6aadaSWan Ahmad Zainie 	/* Having a map is optional */
1401db845093SMuhammad Husaini Zulkifli 	soc_ctl_map = sdhci_arasan->soc_ctl_map;
140236c6aadaSWan Ahmad Zainie 	if (!soc_ctl_map)
140336c6aadaSWan Ahmad Zainie 		return;
140436c6aadaSWan Ahmad Zainie 
140536c6aadaSWan Ahmad Zainie 	/* If we have a map, we expect to have a syscon */
140636c6aadaSWan Ahmad Zainie 	if (!sdhci_arasan->soc_ctl_base) {
140736c6aadaSWan Ahmad Zainie 		pr_warn("%s: Have regmap, but no soc-ctl-syscon\n",
140836c6aadaSWan Ahmad Zainie 			mmc_hostname(host->mmc));
140936c6aadaSWan Ahmad Zainie 		return;
141036c6aadaSWan Ahmad Zainie 	}
141136c6aadaSWan Ahmad Zainie 
141236c6aadaSWan Ahmad Zainie 	sdhci_arasan_syscon_write(host, &soc_ctl_map->support64b, value);
141336c6aadaSWan Ahmad Zainie }
141436c6aadaSWan Ahmad Zainie 
141536c6aadaSWan Ahmad Zainie /**
141607a14d1dSManish Narani  * sdhci_arasan_register_sdclk - Register the sdcardclk for a PHY to use
141707a14d1dSManish Narani  *
14184908460eSManish Narani  * @sdhci_arasan:	Our private data structure.
14194908460eSManish Narani  * @clk_xin:		Pointer to the functional clock
14204908460eSManish Narani  * @dev:		Pointer to our struct device.
14214908460eSManish Narani  *
142207a14d1dSManish Narani  * Some PHY devices need to know what the actual card clock is.  In order for
142307a14d1dSManish Narani  * them to find out, we'll provide a clock through the common clock framework
142407a14d1dSManish Narani  * for them to query.
142507a14d1dSManish Narani  *
142607a14d1dSManish Narani  * Note: without seriously re-architecting SDHCI's clock code and testing on
142707a14d1dSManish Narani  * all platforms, there's no way to create a totally beautiful clock here
142807a14d1dSManish Narani  * with all clock ops implemented.  Instead, we'll just create a clock that can
142907a14d1dSManish Narani  * be queried and set the CLK_GET_RATE_NOCACHE attribute to tell common clock
143007a14d1dSManish Narani  * framework that we're doing things behind its back.  This should be sufficient
143107a14d1dSManish Narani  * to create nice clean device tree bindings and later (if needed) we can try
143207a14d1dSManish Narani  * re-architecting SDHCI if we see some benefit to it.
143307a14d1dSManish Narani  *
14344908460eSManish Narani  * Return: 0 on success and error value on error
143507a14d1dSManish Narani  */
143607a14d1dSManish Narani static int sdhci_arasan_register_sdclk(struct sdhci_arasan_data *sdhci_arasan,
143707a14d1dSManish Narani 				       struct clk *clk_xin,
143807a14d1dSManish Narani 				       struct device *dev)
143907a14d1dSManish Narani {
144007a14d1dSManish Narani 	struct device_node *np = dev->of_node;
144107a14d1dSManish Narani 	u32 num_clks = 0;
144207a14d1dSManish Narani 	int ret;
144307a14d1dSManish Narani 
144407a14d1dSManish Narani 	/* Providing a clock to the PHY is optional; no error if missing */
144507a14d1dSManish Narani 	if (of_property_read_u32(np, "#clock-cells", &num_clks) < 0)
144607a14d1dSManish Narani 		return 0;
144707a14d1dSManish Narani 
144807a14d1dSManish Narani 	ret = sdhci_arasan_register_sdcardclk(sdhci_arasan, clk_xin, dev);
144907a14d1dSManish Narani 	if (ret)
145007a14d1dSManish Narani 		return ret;
145107a14d1dSManish Narani 
145207a14d1dSManish Narani 	if (num_clks) {
145307a14d1dSManish Narani 		ret = sdhci_arasan_register_sampleclk(sdhci_arasan, clk_xin,
145407a14d1dSManish Narani 						      dev);
145507a14d1dSManish Narani 		if (ret) {
145607a14d1dSManish Narani 			sdhci_arasan_unregister_sdclk(dev);
145707a14d1dSManish Narani 			return ret;
145807a14d1dSManish Narani 		}
145907a14d1dSManish Narani 	}
146007a14d1dSManish Narani 
146107a14d1dSManish Narani 	return 0;
146207a14d1dSManish Narani }
146307a14d1dSManish Narani 
146484362d79SShawn Lin static int sdhci_arasan_add_host(struct sdhci_arasan_data *sdhci_arasan)
146584362d79SShawn Lin {
146684362d79SShawn Lin 	struct sdhci_host *host = sdhci_arasan->host;
146784362d79SShawn Lin 	struct cqhci_host *cq_host;
146884362d79SShawn Lin 	bool dma64;
146984362d79SShawn Lin 	int ret;
147084362d79SShawn Lin 
147184362d79SShawn Lin 	if (!sdhci_arasan->has_cqe)
147284362d79SShawn Lin 		return sdhci_add_host(host);
147384362d79SShawn Lin 
147484362d79SShawn Lin 	ret = sdhci_setup_host(host);
147584362d79SShawn Lin 	if (ret)
147684362d79SShawn Lin 		return ret;
147784362d79SShawn Lin 
147884362d79SShawn Lin 	cq_host = devm_kzalloc(host->mmc->parent,
147984362d79SShawn Lin 			       sizeof(*cq_host), GFP_KERNEL);
148084362d79SShawn Lin 	if (!cq_host) {
148184362d79SShawn Lin 		ret = -ENOMEM;
148284362d79SShawn Lin 		goto cleanup;
148384362d79SShawn Lin 	}
148484362d79SShawn Lin 
148584362d79SShawn Lin 	cq_host->mmio = host->ioaddr + SDHCI_ARASAN_CQE_BASE_ADDR;
148684362d79SShawn Lin 	cq_host->ops = &sdhci_arasan_cqhci_ops;
148784362d79SShawn Lin 
148884362d79SShawn Lin 	dma64 = host->flags & SDHCI_USE_64_BIT_DMA;
148984362d79SShawn Lin 	if (dma64)
149084362d79SShawn Lin 		cq_host->caps |= CQHCI_TASK_DESC_SZ_128;
149184362d79SShawn Lin 
149284362d79SShawn Lin 	ret = cqhci_init(cq_host, host->mmc, dma64);
149384362d79SShawn Lin 	if (ret)
149484362d79SShawn Lin 		goto cleanup;
149584362d79SShawn Lin 
149684362d79SShawn Lin 	ret = __sdhci_add_host(host);
149784362d79SShawn Lin 	if (ret)
149884362d79SShawn Lin 		goto cleanup;
149984362d79SShawn Lin 
150084362d79SShawn Lin 	return 0;
150184362d79SShawn Lin 
150284362d79SShawn Lin cleanup:
150384362d79SShawn Lin 	sdhci_cleanup_host(host);
150484362d79SShawn Lin 	return ret;
150584362d79SShawn Lin }
150684362d79SShawn Lin 
1507e3ec3a3dSSoren Brinkmann static int sdhci_arasan_probe(struct platform_device *pdev)
1508e3ec3a3dSSoren Brinkmann {
1509e3ec3a3dSSoren Brinkmann 	int ret;
15103ea4666eSDouglas Anderson 	struct device_node *node;
1511e3ec3a3dSSoren Brinkmann 	struct clk *clk_xin;
1512e3ec3a3dSSoren Brinkmann 	struct sdhci_host *host;
1513e3ec3a3dSSoren Brinkmann 	struct sdhci_pltfm_host *pltfm_host;
1514e3ec3a3dSSoren Brinkmann 	struct sdhci_arasan_data *sdhci_arasan;
15153794c542SZach Brown 	struct device_node *np = pdev->dev.of_node;
151606b23ca0SFaiz Abbas 	const struct sdhci_arasan_of_data *data;
1517e3ec3a3dSSoren Brinkmann 
1518eb085875SMuhammad Husaini Zulkifli 	data = of_device_get_match_data(&pdev->dev);
151906b23ca0SFaiz Abbas 	host = sdhci_pltfm_init(pdev, data->pdata, sizeof(*sdhci_arasan));
152084362d79SShawn Lin 
152189211418SJisheng Zhang 	if (IS_ERR(host))
152289211418SJisheng Zhang 		return PTR_ERR(host);
152389211418SJisheng Zhang 
152489211418SJisheng Zhang 	pltfm_host = sdhci_priv(host);
152589211418SJisheng Zhang 	sdhci_arasan = sdhci_pltfm_priv(pltfm_host);
1526c390f211SDouglas Anderson 	sdhci_arasan->host = host;
1527e3ec3a3dSSoren Brinkmann 
152806b23ca0SFaiz Abbas 	sdhci_arasan->soc_ctl_map = data->soc_ctl_map;
152916ada730SManish Narani 	sdhci_arasan->clk_ops = data->clk_ops;
15303ea4666eSDouglas Anderson 
1531*80d41efeSMuhammad Husaini Zulkifli 	node = of_parse_phandle(np, "arasan,soc-ctl-syscon", 0);
15323ea4666eSDouglas Anderson 	if (node) {
15333ea4666eSDouglas Anderson 		sdhci_arasan->soc_ctl_base = syscon_node_to_regmap(node);
15343ea4666eSDouglas Anderson 		of_node_put(node);
15353ea4666eSDouglas Anderson 
15363ea4666eSDouglas Anderson 		if (IS_ERR(sdhci_arasan->soc_ctl_base)) {
153772ea817dSKrzysztof Kozlowski 			ret = dev_err_probe(&pdev->dev,
153872ea817dSKrzysztof Kozlowski 					    PTR_ERR(sdhci_arasan->soc_ctl_base),
153972ea817dSKrzysztof Kozlowski 					    "Can't get syscon\n");
15403ea4666eSDouglas Anderson 			goto err_pltfm_free;
15413ea4666eSDouglas Anderson 		}
15423ea4666eSDouglas Anderson 	}
15433ea4666eSDouglas Anderson 
1544e3ec3a3dSSoren Brinkmann 	sdhci_arasan->clk_ahb = devm_clk_get(&pdev->dev, "clk_ahb");
1545e3ec3a3dSSoren Brinkmann 	if (IS_ERR(sdhci_arasan->clk_ahb)) {
1546e3ec3a3dSSoren Brinkmann 		dev_err(&pdev->dev, "clk_ahb clock not found.\n");
1547278d0962SShawn Lin 		ret = PTR_ERR(sdhci_arasan->clk_ahb);
1548278d0962SShawn Lin 		goto err_pltfm_free;
1549e3ec3a3dSSoren Brinkmann 	}
1550e3ec3a3dSSoren Brinkmann 
1551e3ec3a3dSSoren Brinkmann 	clk_xin = devm_clk_get(&pdev->dev, "clk_xin");
1552e3ec3a3dSSoren Brinkmann 	if (IS_ERR(clk_xin)) {
1553e3ec3a3dSSoren Brinkmann 		dev_err(&pdev->dev, "clk_xin clock not found.\n");
1554278d0962SShawn Lin 		ret = PTR_ERR(clk_xin);
1555278d0962SShawn Lin 		goto err_pltfm_free;
1556e3ec3a3dSSoren Brinkmann 	}
1557e3ec3a3dSSoren Brinkmann 
1558e3ec3a3dSSoren Brinkmann 	ret = clk_prepare_enable(sdhci_arasan->clk_ahb);
1559e3ec3a3dSSoren Brinkmann 	if (ret) {
1560e3ec3a3dSSoren Brinkmann 		dev_err(&pdev->dev, "Unable to enable AHB clock.\n");
1561278d0962SShawn Lin 		goto err_pltfm_free;
1562e3ec3a3dSSoren Brinkmann 	}
1563e3ec3a3dSSoren Brinkmann 
1564e3ec3a3dSSoren Brinkmann 	ret = clk_prepare_enable(clk_xin);
1565e3ec3a3dSSoren Brinkmann 	if (ret) {
1566e3ec3a3dSSoren Brinkmann 		dev_err(&pdev->dev, "Unable to enable SD clock.\n");
1567e3ec3a3dSSoren Brinkmann 		goto clk_dis_ahb;
1568e3ec3a3dSSoren Brinkmann 	}
1569e3ec3a3dSSoren Brinkmann 
1570e3ec3a3dSSoren Brinkmann 	sdhci_get_of_property(pdev);
15713794c542SZach Brown 
15723794c542SZach Brown 	if (of_property_read_bool(np, "xlnx,fails-without-test-cd"))
15733794c542SZach Brown 		sdhci_arasan->quirks |= SDHCI_ARASAN_QUIRK_FORCE_CDTEST;
15743794c542SZach Brown 
15753f2c7d5dSHelmut Grohne 	if (of_property_read_bool(np, "xlnx,int-clock-stable-broken"))
15763f2c7d5dSHelmut Grohne 		sdhci_arasan->quirks |= SDHCI_ARASAN_QUIRK_CLOCK_UNSTABLE;
15773f2c7d5dSHelmut Grohne 
1578e3ec3a3dSSoren Brinkmann 	pltfm_host->clk = clk_xin;
1579e3ec3a3dSSoren Brinkmann 
1580*80d41efeSMuhammad Husaini Zulkifli 	if (of_device_is_compatible(np, "rockchip,rk3399-sdhci-5.1"))
1581b2ca77c9SShawn Lin 		sdhci_arasan_update_clockmultiplier(host, 0x0);
1582b2ca77c9SShawn Lin 
158336c6aadaSWan Ahmad Zainie 	if (of_device_is_compatible(np, "intel,keembay-sdhci-5.1-emmc") ||
158436c6aadaSWan Ahmad Zainie 	    of_device_is_compatible(np, "intel,keembay-sdhci-5.1-sd") ||
158536c6aadaSWan Ahmad Zainie 	    of_device_is_compatible(np, "intel,keembay-sdhci-5.1-sdio")) {
158636c6aadaSWan Ahmad Zainie 		sdhci_arasan_update_clockmultiplier(host, 0x0);
158736c6aadaSWan Ahmad Zainie 		sdhci_arasan_update_support64b(host, 0x0);
158836c6aadaSWan Ahmad Zainie 
158936c6aadaSWan Ahmad Zainie 		host->mmc->caps |= MMC_CAP_WAIT_WHILE_BUSY;
159036c6aadaSWan Ahmad Zainie 	}
159136c6aadaSWan Ahmad Zainie 
15923ea4666eSDouglas Anderson 	sdhci_arasan_update_baseclkfreq(host);
15933ea4666eSDouglas Anderson 
1594c390f211SDouglas Anderson 	ret = sdhci_arasan_register_sdclk(sdhci_arasan, clk_xin, &pdev->dev);
1595c390f211SDouglas Anderson 	if (ret)
1596c390f211SDouglas Anderson 		goto clk_disable_all;
1597c390f211SDouglas Anderson 
1598a5c8b2aeSManish Narani 	if (of_device_is_compatible(np, "xlnx,zynqmp-8.9a")) {
15998d2e3343SManish Narani 		host->mmc_host_ops.execute_tuning =
16008d2e3343SManish Narani 			arasan_zynqmp_execute_tuning;
1601a5c8b2aeSManish Narani 	}
1602a5c8b2aeSManish Narani 
1603f3dafc37SManish Narani 	arasan_dt_parse_clk_phases(&pdev->dev, &sdhci_arasan->clk_data);
1604f3dafc37SManish Narani 
160516b23787SMichal Simek 	ret = mmc_of_parse(host->mmc);
160616b23787SMichal Simek 	if (ret) {
160760208a26SMichal Simek 		if (ret != -EPROBE_DEFER)
1608940e698cSShubhrajyoti Datta 			dev_err(&pdev->dev, "parsing dt failed (%d)\n", ret);
1609c390f211SDouglas Anderson 		goto unreg_clk;
161016b23787SMichal Simek 	}
161116b23787SMichal Simek 
161291aa3661SShawn Lin 	sdhci_arasan->phy = ERR_PTR(-ENODEV);
1613*80d41efeSMuhammad Husaini Zulkifli 	if (of_device_is_compatible(np, "arasan,sdhci-5.1")) {
161491aa3661SShawn Lin 		sdhci_arasan->phy = devm_phy_get(&pdev->dev,
161591aa3661SShawn Lin 						 "phy_arasan");
161691aa3661SShawn Lin 		if (IS_ERR(sdhci_arasan->phy)) {
161791aa3661SShawn Lin 			ret = PTR_ERR(sdhci_arasan->phy);
161891aa3661SShawn Lin 			dev_err(&pdev->dev, "No phy for arasan,sdhci-5.1.\n");
1619c390f211SDouglas Anderson 			goto unreg_clk;
162091aa3661SShawn Lin 		}
162191aa3661SShawn Lin 
162291aa3661SShawn Lin 		ret = phy_init(sdhci_arasan->phy);
162391aa3661SShawn Lin 		if (ret < 0) {
162491aa3661SShawn Lin 			dev_err(&pdev->dev, "phy_init err.\n");
1625c390f211SDouglas Anderson 			goto unreg_clk;
162691aa3661SShawn Lin 		}
162791aa3661SShawn Lin 
1628a05c8465SShawn Lin 		host->mmc_host_ops.hs400_enhanced_strobe =
1629a05c8465SShawn Lin 					sdhci_arasan_hs400_enhanced_strobe;
16308a3bee9bSShawn Lin 		host->mmc_host_ops.start_signal_voltage_switch =
16318a3bee9bSShawn Lin 					sdhci_arasan_voltage_switch;
163284362d79SShawn Lin 		sdhci_arasan->has_cqe = true;
16337bda9482SChristoph Muellner 		host->mmc->caps2 |= MMC_CAP2_CQE;
16347bda9482SChristoph Muellner 
16357bda9482SChristoph Muellner 		if (!of_property_read_bool(np, "disable-cqe-dcmd"))
16367bda9482SChristoph Muellner 			host->mmc->caps2 |= MMC_CAP2_CQE_DCMD;
163791aa3661SShawn Lin 	}
163891aa3661SShawn Lin 
163984362d79SShawn Lin 	ret = sdhci_arasan_add_host(sdhci_arasan);
1640b1df9de7SMike Looijmans 	if (ret)
164191aa3661SShawn Lin 		goto err_add_host;
1642e3ec3a3dSSoren Brinkmann 
1643e3ec3a3dSSoren Brinkmann 	return 0;
1644e3ec3a3dSSoren Brinkmann 
164591aa3661SShawn Lin err_add_host:
164691aa3661SShawn Lin 	if (!IS_ERR(sdhci_arasan->phy))
164791aa3661SShawn Lin 		phy_exit(sdhci_arasan->phy);
1648c390f211SDouglas Anderson unreg_clk:
1649c390f211SDouglas Anderson 	sdhci_arasan_unregister_sdclk(&pdev->dev);
1650e3ec3a3dSSoren Brinkmann clk_disable_all:
1651e3ec3a3dSSoren Brinkmann 	clk_disable_unprepare(clk_xin);
1652e3ec3a3dSSoren Brinkmann clk_dis_ahb:
1653e3ec3a3dSSoren Brinkmann 	clk_disable_unprepare(sdhci_arasan->clk_ahb);
1654278d0962SShawn Lin err_pltfm_free:
1655278d0962SShawn Lin 	sdhci_pltfm_free(pdev);
1656e3ec3a3dSSoren Brinkmann 	return ret;
1657e3ec3a3dSSoren Brinkmann }
1658e3ec3a3dSSoren Brinkmann 
1659e3ec3a3dSSoren Brinkmann static int sdhci_arasan_remove(struct platform_device *pdev)
1660e3ec3a3dSSoren Brinkmann {
16610c7fe32eSJisheng Zhang 	int ret;
1662e3ec3a3dSSoren Brinkmann 	struct sdhci_host *host = platform_get_drvdata(pdev);
1663e3ec3a3dSSoren Brinkmann 	struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
166489211418SJisheng Zhang 	struct sdhci_arasan_data *sdhci_arasan = sdhci_pltfm_priv(pltfm_host);
166589211418SJisheng Zhang 	struct clk *clk_ahb = sdhci_arasan->clk_ahb;
1666e3ec3a3dSSoren Brinkmann 
166791aa3661SShawn Lin 	if (!IS_ERR(sdhci_arasan->phy)) {
1668b2db9c67SDouglas Anderson 		if (sdhci_arasan->is_phy_on)
166991aa3661SShawn Lin 			phy_power_off(sdhci_arasan->phy);
167091aa3661SShawn Lin 		phy_exit(sdhci_arasan->phy);
167191aa3661SShawn Lin 	}
167291aa3661SShawn Lin 
1673c390f211SDouglas Anderson 	sdhci_arasan_unregister_sdclk(&pdev->dev);
1674c390f211SDouglas Anderson 
16750c7fe32eSJisheng Zhang 	ret = sdhci_pltfm_unregister(pdev);
16760c7fe32eSJisheng Zhang 
167789211418SJisheng Zhang 	clk_disable_unprepare(clk_ahb);
1678e3ec3a3dSSoren Brinkmann 
16790c7fe32eSJisheng Zhang 	return ret;
1680e3ec3a3dSSoren Brinkmann }
1681e3ec3a3dSSoren Brinkmann 
1682e3ec3a3dSSoren Brinkmann static struct platform_driver sdhci_arasan_driver = {
1683e3ec3a3dSSoren Brinkmann 	.driver = {
1684e3ec3a3dSSoren Brinkmann 		.name = "sdhci-arasan",
168521b2cec6SDouglas Anderson 		.probe_type = PROBE_PREFER_ASYNCHRONOUS,
1686e3ec3a3dSSoren Brinkmann 		.of_match_table = sdhci_arasan_of_match,
1687e3ec3a3dSSoren Brinkmann 		.pm = &sdhci_arasan_dev_pm_ops,
1688e3ec3a3dSSoren Brinkmann 	},
1689e3ec3a3dSSoren Brinkmann 	.probe = sdhci_arasan_probe,
1690e3ec3a3dSSoren Brinkmann 	.remove = sdhci_arasan_remove,
1691e3ec3a3dSSoren Brinkmann };
1692e3ec3a3dSSoren Brinkmann 
1693e3ec3a3dSSoren Brinkmann module_platform_driver(sdhci_arasan_driver);
1694e3ec3a3dSSoren Brinkmann 
1695e3ec3a3dSSoren Brinkmann MODULE_DESCRIPTION("Driver for the Arasan SDHCI Controller");
1696e3ec3a3dSSoren Brinkmann MODULE_AUTHOR("Soeren Brinkmann <soren.brinkmann@xilinx.com>");
1697e3ec3a3dSSoren Brinkmann MODULE_LICENSE("GPL");
1698