162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci * Arasan Secure Digital Host Controller Interface.
462306a36Sopenharmony_ci * Copyright (C) 2011 - 2012 Michal Simek <monstr@monstr.eu>
562306a36Sopenharmony_ci * Copyright (c) 2012 Wind River Systems, Inc.
662306a36Sopenharmony_ci * Copyright (C) 2013 Pengutronix e.K.
762306a36Sopenharmony_ci * Copyright (C) 2013 Xilinx Inc.
862306a36Sopenharmony_ci *
962306a36Sopenharmony_ci * Based on sdhci-of-esdhc.c
1062306a36Sopenharmony_ci *
1162306a36Sopenharmony_ci * Copyright (c) 2007 Freescale Semiconductor, Inc.
1262306a36Sopenharmony_ci * Copyright (c) 2009 MontaVista Software, Inc.
1362306a36Sopenharmony_ci *
1462306a36Sopenharmony_ci * Authors: Xiaobo Xie <X.Xie@freescale.com>
1562306a36Sopenharmony_ci *	    Anton Vorontsov <avorontsov@ru.mvista.com>
1662306a36Sopenharmony_ci */
1762306a36Sopenharmony_ci
1862306a36Sopenharmony_ci#include <linux/clk-provider.h>
1962306a36Sopenharmony_ci#include <linux/mfd/syscon.h>
2062306a36Sopenharmony_ci#include <linux/module.h>
2162306a36Sopenharmony_ci#include <linux/of.h>
2262306a36Sopenharmony_ci#include <linux/platform_device.h>
2362306a36Sopenharmony_ci#include <linux/phy/phy.h>
2462306a36Sopenharmony_ci#include <linux/regmap.h>
2562306a36Sopenharmony_ci#include <linux/reset.h>
2662306a36Sopenharmony_ci#include <linux/firmware/xlnx-zynqmp.h>
2762306a36Sopenharmony_ci
2862306a36Sopenharmony_ci#include "cqhci.h"
2962306a36Sopenharmony_ci#include "sdhci-cqhci.h"
3062306a36Sopenharmony_ci#include "sdhci-pltfm.h"
3162306a36Sopenharmony_ci
3262306a36Sopenharmony_ci#define SDHCI_ARASAN_VENDOR_REGISTER	0x78
3362306a36Sopenharmony_ci
3462306a36Sopenharmony_ci#define SDHCI_ARASAN_ITAPDLY_REGISTER	0xF0F8
3562306a36Sopenharmony_ci#define SDHCI_ARASAN_ITAPDLY_SEL_MASK	0xFF
3662306a36Sopenharmony_ci
3762306a36Sopenharmony_ci#define SDHCI_ARASAN_OTAPDLY_REGISTER	0xF0FC
3862306a36Sopenharmony_ci#define SDHCI_ARASAN_OTAPDLY_SEL_MASK	0x3F
3962306a36Sopenharmony_ci
4062306a36Sopenharmony_ci#define SDHCI_ARASAN_CQE_BASE_ADDR	0x200
4162306a36Sopenharmony_ci#define VENDOR_ENHANCED_STROBE		BIT(0)
4262306a36Sopenharmony_ci
4362306a36Sopenharmony_ci#define PHY_CLK_TOO_SLOW_HZ		400000
4462306a36Sopenharmony_ci#define MIN_PHY_CLK_HZ			50000000
4562306a36Sopenharmony_ci
4662306a36Sopenharmony_ci#define SDHCI_ITAPDLY_CHGWIN		0x200
4762306a36Sopenharmony_ci#define SDHCI_ITAPDLY_ENABLE		0x100
4862306a36Sopenharmony_ci#define SDHCI_OTAPDLY_ENABLE		0x40
4962306a36Sopenharmony_ci
5062306a36Sopenharmony_ci#define PHY_CTRL_REG1			0x270
5162306a36Sopenharmony_ci#define PHY_CTRL_ITAPDLY_ENA_MASK	BIT(0)
5262306a36Sopenharmony_ci#define PHY_CTRL_ITAPDLY_SEL_MASK	GENMASK(5, 1)
5362306a36Sopenharmony_ci#define PHY_CTRL_ITAPDLY_SEL_SHIFT	1
5462306a36Sopenharmony_ci#define PHY_CTRL_ITAP_CHG_WIN_MASK	BIT(6)
5562306a36Sopenharmony_ci#define PHY_CTRL_OTAPDLY_ENA_MASK	BIT(8)
5662306a36Sopenharmony_ci#define PHY_CTRL_OTAPDLY_SEL_MASK	GENMASK(15, 12)
5762306a36Sopenharmony_ci#define PHY_CTRL_OTAPDLY_SEL_SHIFT	12
5862306a36Sopenharmony_ci#define PHY_CTRL_STRB_SEL_MASK		GENMASK(23, 16)
5962306a36Sopenharmony_ci#define PHY_CTRL_STRB_SEL_SHIFT		16
6062306a36Sopenharmony_ci#define PHY_CTRL_TEST_CTRL_MASK		GENMASK(31, 24)
6162306a36Sopenharmony_ci
6262306a36Sopenharmony_ci#define PHY_CTRL_REG2			0x274
6362306a36Sopenharmony_ci#define PHY_CTRL_EN_DLL_MASK		BIT(0)
6462306a36Sopenharmony_ci#define PHY_CTRL_DLL_RDY_MASK		BIT(1)
6562306a36Sopenharmony_ci#define PHY_CTRL_FREQ_SEL_MASK		GENMASK(6, 4)
6662306a36Sopenharmony_ci#define PHY_CTRL_FREQ_SEL_SHIFT		4
6762306a36Sopenharmony_ci#define PHY_CTRL_SEL_DLY_TX_MASK	BIT(16)
6862306a36Sopenharmony_ci#define PHY_CTRL_SEL_DLY_RX_MASK	BIT(17)
6962306a36Sopenharmony_ci#define FREQSEL_200M_170M		0x0
7062306a36Sopenharmony_ci#define FREQSEL_170M_140M	        0x1
7162306a36Sopenharmony_ci#define FREQSEL_140M_110M	        0x2
7262306a36Sopenharmony_ci#define FREQSEL_110M_80M	        0x3
7362306a36Sopenharmony_ci#define FREQSEL_80M_50M			0x4
7462306a36Sopenharmony_ci#define FREQSEL_275M_250M		0x5
7562306a36Sopenharmony_ci#define FREQSEL_250M_225M		0x6
7662306a36Sopenharmony_ci#define FREQSEL_225M_200M		0x7
7762306a36Sopenharmony_ci#define PHY_DLL_TIMEOUT_MS		100
7862306a36Sopenharmony_ci
7962306a36Sopenharmony_ci/* Default settings for ZynqMP Clock Phases */
8062306a36Sopenharmony_ci#define ZYNQMP_ICLK_PHASE {0, 63, 63, 0, 63,  0,   0, 183, 54,  0, 0}
8162306a36Sopenharmony_ci#define ZYNQMP_OCLK_PHASE {0, 72, 60, 0, 60, 72, 135, 48, 72, 135, 0}
8262306a36Sopenharmony_ci
8362306a36Sopenharmony_ci#define VERSAL_ICLK_PHASE {0, 132, 132, 0, 132, 0, 0, 162, 90, 0, 0}
8462306a36Sopenharmony_ci#define VERSAL_OCLK_PHASE {0,  60, 48, 0, 48, 72, 90, 36, 60, 90, 0}
8562306a36Sopenharmony_ci
8662306a36Sopenharmony_ci#define VERSAL_NET_EMMC_ICLK_PHASE {0, 0, 0, 0, 0, 0, 0, 0, 39, 0, 0}
8762306a36Sopenharmony_ci#define VERSAL_NET_EMMC_OCLK_PHASE {0, 113, 0, 0, 0, 0, 0, 0, 113, 79, 45}
8862306a36Sopenharmony_ci
8962306a36Sopenharmony_ci#define VERSAL_NET_PHY_CTRL_STRB90_STRB180_VAL		0X77
9062306a36Sopenharmony_ci
9162306a36Sopenharmony_ci/*
9262306a36Sopenharmony_ci * On some SoCs the syscon area has a feature where the upper 16-bits of
9362306a36Sopenharmony_ci * each 32-bit register act as a write mask for the lower 16-bits.  This allows
9462306a36Sopenharmony_ci * atomic updates of the register without locking.  This macro is used on SoCs
9562306a36Sopenharmony_ci * that have that feature.
9662306a36Sopenharmony_ci */
9762306a36Sopenharmony_ci#define HIWORD_UPDATE(val, mask, shift) \
9862306a36Sopenharmony_ci		((val) << (shift) | (mask) << ((shift) + 16))
9962306a36Sopenharmony_ci
10062306a36Sopenharmony_ci/**
10162306a36Sopenharmony_ci * struct sdhci_arasan_soc_ctl_field - Field used in sdhci_arasan_soc_ctl_map
10262306a36Sopenharmony_ci *
10362306a36Sopenharmony_ci * @reg:	Offset within the syscon of the register containing this field
10462306a36Sopenharmony_ci * @width:	Number of bits for this field
10562306a36Sopenharmony_ci * @shift:	Bit offset within @reg of this field (or -1 if not avail)
10662306a36Sopenharmony_ci */
10762306a36Sopenharmony_cistruct sdhci_arasan_soc_ctl_field {
10862306a36Sopenharmony_ci	u32 reg;
10962306a36Sopenharmony_ci	u16 width;
11062306a36Sopenharmony_ci	s16 shift;
11162306a36Sopenharmony_ci};
11262306a36Sopenharmony_ci
11362306a36Sopenharmony_ci/**
11462306a36Sopenharmony_ci * struct sdhci_arasan_soc_ctl_map - Map in syscon to corecfg registers
11562306a36Sopenharmony_ci *
11662306a36Sopenharmony_ci * @baseclkfreq:	Where to find corecfg_baseclkfreq
11762306a36Sopenharmony_ci * @clockmultiplier:	Where to find corecfg_clockmultiplier
11862306a36Sopenharmony_ci * @support64b:		Where to find SUPPORT64B bit
11962306a36Sopenharmony_ci * @hiword_update:	If true, use HIWORD_UPDATE to access the syscon
12062306a36Sopenharmony_ci *
12162306a36Sopenharmony_ci * It's up to the licensee of the Arsan IP block to make these available
12262306a36Sopenharmony_ci * somewhere if needed.  Presumably these will be scattered somewhere that's
12362306a36Sopenharmony_ci * accessible via the syscon API.
12462306a36Sopenharmony_ci */
12562306a36Sopenharmony_cistruct sdhci_arasan_soc_ctl_map {
12662306a36Sopenharmony_ci	struct sdhci_arasan_soc_ctl_field	baseclkfreq;
12762306a36Sopenharmony_ci	struct sdhci_arasan_soc_ctl_field	clockmultiplier;
12862306a36Sopenharmony_ci	struct sdhci_arasan_soc_ctl_field	support64b;
12962306a36Sopenharmony_ci	bool					hiword_update;
13062306a36Sopenharmony_ci};
13162306a36Sopenharmony_ci
13262306a36Sopenharmony_ci/**
13362306a36Sopenharmony_ci * struct sdhci_arasan_clk_ops - Clock Operations for Arasan SD controller
13462306a36Sopenharmony_ci *
13562306a36Sopenharmony_ci * @sdcardclk_ops:	The output clock related operations
13662306a36Sopenharmony_ci * @sampleclk_ops:	The sample clock related operations
13762306a36Sopenharmony_ci */
13862306a36Sopenharmony_cistruct sdhci_arasan_clk_ops {
13962306a36Sopenharmony_ci	const struct clk_ops *sdcardclk_ops;
14062306a36Sopenharmony_ci	const struct clk_ops *sampleclk_ops;
14162306a36Sopenharmony_ci};
14262306a36Sopenharmony_ci
14362306a36Sopenharmony_ci/**
14462306a36Sopenharmony_ci * struct sdhci_arasan_clk_data - Arasan Controller Clock Data.
14562306a36Sopenharmony_ci *
14662306a36Sopenharmony_ci * @sdcardclk_hw:	Struct for the clock we might provide to a PHY.
14762306a36Sopenharmony_ci * @sdcardclk:		Pointer to normal 'struct clock' for sdcardclk_hw.
14862306a36Sopenharmony_ci * @sampleclk_hw:	Struct for the clock we might provide to a PHY.
14962306a36Sopenharmony_ci * @sampleclk:		Pointer to normal 'struct clock' for sampleclk_hw.
15062306a36Sopenharmony_ci * @clk_phase_in:	Array of Input Clock Phase Delays for all speed modes
15162306a36Sopenharmony_ci * @clk_phase_out:	Array of Output Clock Phase Delays for all speed modes
15262306a36Sopenharmony_ci * @set_clk_delays:	Function pointer for setting Clock Delays
15362306a36Sopenharmony_ci * @clk_of_data:	Platform specific runtime clock data storage pointer
15462306a36Sopenharmony_ci */
15562306a36Sopenharmony_cistruct sdhci_arasan_clk_data {
15662306a36Sopenharmony_ci	struct clk_hw	sdcardclk_hw;
15762306a36Sopenharmony_ci	struct clk      *sdcardclk;
15862306a36Sopenharmony_ci	struct clk_hw	sampleclk_hw;
15962306a36Sopenharmony_ci	struct clk      *sampleclk;
16062306a36Sopenharmony_ci	int		clk_phase_in[MMC_TIMING_MMC_HS400 + 1];
16162306a36Sopenharmony_ci	int		clk_phase_out[MMC_TIMING_MMC_HS400 + 1];
16262306a36Sopenharmony_ci	void		(*set_clk_delays)(struct sdhci_host *host);
16362306a36Sopenharmony_ci	void		*clk_of_data;
16462306a36Sopenharmony_ci};
16562306a36Sopenharmony_ci
16662306a36Sopenharmony_ci/**
16762306a36Sopenharmony_ci * struct sdhci_arasan_data - Arasan Controller Data
16862306a36Sopenharmony_ci *
16962306a36Sopenharmony_ci * @host:		Pointer to the main SDHCI host structure.
17062306a36Sopenharmony_ci * @clk_ahb:		Pointer to the AHB clock
17162306a36Sopenharmony_ci * @phy:		Pointer to the generic phy
17262306a36Sopenharmony_ci * @is_phy_on:		True if the PHY is on; false if not.
17362306a36Sopenharmony_ci * @internal_phy_reg:	True if the PHY is within the Host controller.
17462306a36Sopenharmony_ci * @has_cqe:		True if controller has command queuing engine.
17562306a36Sopenharmony_ci * @clk_data:		Struct for the Arasan Controller Clock Data.
17662306a36Sopenharmony_ci * @clk_ops:		Struct for the Arasan Controller Clock Operations.
17762306a36Sopenharmony_ci * @soc_ctl_base:	Pointer to regmap for syscon for soc_ctl registers.
17862306a36Sopenharmony_ci * @soc_ctl_map:	Map to get offsets into soc_ctl registers.
17962306a36Sopenharmony_ci * @quirks:		Arasan deviations from spec.
18062306a36Sopenharmony_ci */
18162306a36Sopenharmony_cistruct sdhci_arasan_data {
18262306a36Sopenharmony_ci	struct sdhci_host *host;
18362306a36Sopenharmony_ci	struct clk	*clk_ahb;
18462306a36Sopenharmony_ci	struct phy	*phy;
18562306a36Sopenharmony_ci	bool		is_phy_on;
18662306a36Sopenharmony_ci	bool		internal_phy_reg;
18762306a36Sopenharmony_ci
18862306a36Sopenharmony_ci	bool		has_cqe;
18962306a36Sopenharmony_ci	struct sdhci_arasan_clk_data clk_data;
19062306a36Sopenharmony_ci	const struct sdhci_arasan_clk_ops *clk_ops;
19162306a36Sopenharmony_ci
19262306a36Sopenharmony_ci	struct regmap	*soc_ctl_base;
19362306a36Sopenharmony_ci	const struct sdhci_arasan_soc_ctl_map *soc_ctl_map;
19462306a36Sopenharmony_ci	unsigned int	quirks;
19562306a36Sopenharmony_ci
19662306a36Sopenharmony_ci/* Controller does not have CD wired and will not function normally without */
19762306a36Sopenharmony_ci#define SDHCI_ARASAN_QUIRK_FORCE_CDTEST	BIT(0)
19862306a36Sopenharmony_ci/* Controller immediately reports SDHCI_CLOCK_INT_STABLE after enabling the
19962306a36Sopenharmony_ci * internal clock even when the clock isn't stable */
20062306a36Sopenharmony_ci#define SDHCI_ARASAN_QUIRK_CLOCK_UNSTABLE BIT(1)
20162306a36Sopenharmony_ci/*
20262306a36Sopenharmony_ci * Some of the Arasan variations might not have timing requirements
20362306a36Sopenharmony_ci * met at 25MHz for Default Speed mode, those controllers work at
20462306a36Sopenharmony_ci * 19MHz instead
20562306a36Sopenharmony_ci */
20662306a36Sopenharmony_ci#define SDHCI_ARASAN_QUIRK_CLOCK_25_BROKEN BIT(2)
20762306a36Sopenharmony_ci};
20862306a36Sopenharmony_ci
20962306a36Sopenharmony_cistruct sdhci_arasan_of_data {
21062306a36Sopenharmony_ci	const struct sdhci_arasan_soc_ctl_map *soc_ctl_map;
21162306a36Sopenharmony_ci	const struct sdhci_pltfm_data *pdata;
21262306a36Sopenharmony_ci	const struct sdhci_arasan_clk_ops *clk_ops;
21362306a36Sopenharmony_ci};
21462306a36Sopenharmony_ci
21562306a36Sopenharmony_cistatic const struct sdhci_arasan_soc_ctl_map rk3399_soc_ctl_map = {
21662306a36Sopenharmony_ci	.baseclkfreq = { .reg = 0xf000, .width = 8, .shift = 8 },
21762306a36Sopenharmony_ci	.clockmultiplier = { .reg = 0xf02c, .width = 8, .shift = 0},
21862306a36Sopenharmony_ci	.hiword_update = true,
21962306a36Sopenharmony_ci};
22062306a36Sopenharmony_ci
22162306a36Sopenharmony_cistatic const struct sdhci_arasan_soc_ctl_map intel_lgm_emmc_soc_ctl_map = {
22262306a36Sopenharmony_ci	.baseclkfreq = { .reg = 0xa0, .width = 8, .shift = 2 },
22362306a36Sopenharmony_ci	.clockmultiplier = { .reg = 0, .width = -1, .shift = -1 },
22462306a36Sopenharmony_ci	.hiword_update = false,
22562306a36Sopenharmony_ci};
22662306a36Sopenharmony_ci
22762306a36Sopenharmony_cistatic const struct sdhci_arasan_soc_ctl_map intel_lgm_sdxc_soc_ctl_map = {
22862306a36Sopenharmony_ci	.baseclkfreq = { .reg = 0x80, .width = 8, .shift = 2 },
22962306a36Sopenharmony_ci	.clockmultiplier = { .reg = 0, .width = -1, .shift = -1 },
23062306a36Sopenharmony_ci	.hiword_update = false,
23162306a36Sopenharmony_ci};
23262306a36Sopenharmony_ci
23362306a36Sopenharmony_cistatic const struct sdhci_arasan_soc_ctl_map intel_keembay_soc_ctl_map = {
23462306a36Sopenharmony_ci	.baseclkfreq = { .reg = 0x0, .width = 8, .shift = 14 },
23562306a36Sopenharmony_ci	.clockmultiplier = { .reg = 0x4, .width = 8, .shift = 14 },
23662306a36Sopenharmony_ci	.support64b = { .reg = 0x4, .width = 1, .shift = 24 },
23762306a36Sopenharmony_ci	.hiword_update = false,
23862306a36Sopenharmony_ci};
23962306a36Sopenharmony_ci
24062306a36Sopenharmony_cistatic void sdhci_arasan_phy_set_delaychain(struct sdhci_host *host, bool enable)
24162306a36Sopenharmony_ci{
24262306a36Sopenharmony_ci	u32 reg;
24362306a36Sopenharmony_ci
24462306a36Sopenharmony_ci	reg = readl(host->ioaddr + PHY_CTRL_REG2);
24562306a36Sopenharmony_ci	if (enable)
24662306a36Sopenharmony_ci		reg |= (PHY_CTRL_SEL_DLY_TX_MASK | PHY_CTRL_SEL_DLY_RX_MASK);
24762306a36Sopenharmony_ci	else
24862306a36Sopenharmony_ci		reg &= ~(PHY_CTRL_SEL_DLY_TX_MASK | PHY_CTRL_SEL_DLY_RX_MASK);
24962306a36Sopenharmony_ci
25062306a36Sopenharmony_ci	writel(reg, host->ioaddr + PHY_CTRL_REG2);
25162306a36Sopenharmony_ci}
25262306a36Sopenharmony_ci
25362306a36Sopenharmony_cistatic int sdhci_arasan_phy_set_dll(struct sdhci_host *host, bool enable)
25462306a36Sopenharmony_ci{
25562306a36Sopenharmony_ci	u32 reg;
25662306a36Sopenharmony_ci
25762306a36Sopenharmony_ci	reg = readl(host->ioaddr + PHY_CTRL_REG2);
25862306a36Sopenharmony_ci	if (enable)
25962306a36Sopenharmony_ci		reg |= PHY_CTRL_EN_DLL_MASK;
26062306a36Sopenharmony_ci	else
26162306a36Sopenharmony_ci		reg &= ~PHY_CTRL_EN_DLL_MASK;
26262306a36Sopenharmony_ci
26362306a36Sopenharmony_ci	writel(reg, host->ioaddr + PHY_CTRL_REG2);
26462306a36Sopenharmony_ci
26562306a36Sopenharmony_ci	if (!enable)
26662306a36Sopenharmony_ci		return 0;
26762306a36Sopenharmony_ci
26862306a36Sopenharmony_ci	return readl_relaxed_poll_timeout(host->ioaddr + PHY_CTRL_REG2, reg,
26962306a36Sopenharmony_ci					  (reg & PHY_CTRL_DLL_RDY_MASK), 10,
27062306a36Sopenharmony_ci					  1000 * PHY_DLL_TIMEOUT_MS);
27162306a36Sopenharmony_ci}
27262306a36Sopenharmony_ci
27362306a36Sopenharmony_cistatic void sdhci_arasan_phy_dll_set_freq(struct sdhci_host *host, int clock)
27462306a36Sopenharmony_ci{
27562306a36Sopenharmony_ci	u32 reg, freq_sel, freq;
27662306a36Sopenharmony_ci
27762306a36Sopenharmony_ci	freq = DIV_ROUND_CLOSEST(clock, 1000000);
27862306a36Sopenharmony_ci	if (freq <= 200 && freq > 170)
27962306a36Sopenharmony_ci		freq_sel = FREQSEL_200M_170M;
28062306a36Sopenharmony_ci	else if (freq <= 170 && freq > 140)
28162306a36Sopenharmony_ci		freq_sel = FREQSEL_170M_140M;
28262306a36Sopenharmony_ci	else if (freq <= 140 && freq > 110)
28362306a36Sopenharmony_ci		freq_sel = FREQSEL_140M_110M;
28462306a36Sopenharmony_ci	else if (freq <= 110 && freq > 80)
28562306a36Sopenharmony_ci		freq_sel = FREQSEL_110M_80M;
28662306a36Sopenharmony_ci	else
28762306a36Sopenharmony_ci		freq_sel = FREQSEL_80M_50M;
28862306a36Sopenharmony_ci
28962306a36Sopenharmony_ci	reg = readl(host->ioaddr + PHY_CTRL_REG2);
29062306a36Sopenharmony_ci	reg &= ~PHY_CTRL_FREQ_SEL_MASK;
29162306a36Sopenharmony_ci	reg |= (freq_sel << PHY_CTRL_FREQ_SEL_SHIFT);
29262306a36Sopenharmony_ci	writel(reg, host->ioaddr + PHY_CTRL_REG2);
29362306a36Sopenharmony_ci}
29462306a36Sopenharmony_ci
29562306a36Sopenharmony_ci/**
29662306a36Sopenharmony_ci * sdhci_arasan_syscon_write - Write to a field in soc_ctl registers
29762306a36Sopenharmony_ci *
29862306a36Sopenharmony_ci * @host:	The sdhci_host
29962306a36Sopenharmony_ci * @fld:	The field to write to
30062306a36Sopenharmony_ci * @val:	The value to write
30162306a36Sopenharmony_ci *
30262306a36Sopenharmony_ci * This function allows writing to fields in sdhci_arasan_soc_ctl_map.
30362306a36Sopenharmony_ci * Note that if a field is specified as not available (shift < 0) then
30462306a36Sopenharmony_ci * this function will silently return an error code.  It will be noisy
30562306a36Sopenharmony_ci * and print errors for any other (unexpected) errors.
30662306a36Sopenharmony_ci *
30762306a36Sopenharmony_ci * Return: 0 on success and error value on error
30862306a36Sopenharmony_ci */
30962306a36Sopenharmony_cistatic int sdhci_arasan_syscon_write(struct sdhci_host *host,
31062306a36Sopenharmony_ci				   const struct sdhci_arasan_soc_ctl_field *fld,
31162306a36Sopenharmony_ci				   u32 val)
31262306a36Sopenharmony_ci{
31362306a36Sopenharmony_ci	struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
31462306a36Sopenharmony_ci	struct sdhci_arasan_data *sdhci_arasan = sdhci_pltfm_priv(pltfm_host);
31562306a36Sopenharmony_ci	struct regmap *soc_ctl_base = sdhci_arasan->soc_ctl_base;
31662306a36Sopenharmony_ci	u32 reg = fld->reg;
31762306a36Sopenharmony_ci	u16 width = fld->width;
31862306a36Sopenharmony_ci	s16 shift = fld->shift;
31962306a36Sopenharmony_ci	int ret;
32062306a36Sopenharmony_ci
32162306a36Sopenharmony_ci	/*
32262306a36Sopenharmony_ci	 * Silently return errors for shift < 0 so caller doesn't have
32362306a36Sopenharmony_ci	 * to check for fields which are optional.  For fields that
32462306a36Sopenharmony_ci	 * are required then caller needs to do something special
32562306a36Sopenharmony_ci	 * anyway.
32662306a36Sopenharmony_ci	 */
32762306a36Sopenharmony_ci	if (shift < 0)
32862306a36Sopenharmony_ci		return -EINVAL;
32962306a36Sopenharmony_ci
33062306a36Sopenharmony_ci	if (sdhci_arasan->soc_ctl_map->hiword_update)
33162306a36Sopenharmony_ci		ret = regmap_write(soc_ctl_base, reg,
33262306a36Sopenharmony_ci				   HIWORD_UPDATE(val, GENMASK(width, 0),
33362306a36Sopenharmony_ci						 shift));
33462306a36Sopenharmony_ci	else
33562306a36Sopenharmony_ci		ret = regmap_update_bits(soc_ctl_base, reg,
33662306a36Sopenharmony_ci					 GENMASK(shift + width, shift),
33762306a36Sopenharmony_ci					 val << shift);
33862306a36Sopenharmony_ci
33962306a36Sopenharmony_ci	/* Yell about (unexpected) regmap errors */
34062306a36Sopenharmony_ci	if (ret)
34162306a36Sopenharmony_ci		pr_warn("%s: Regmap write fail: %d\n",
34262306a36Sopenharmony_ci			 mmc_hostname(host->mmc), ret);
34362306a36Sopenharmony_ci
34462306a36Sopenharmony_ci	return ret;
34562306a36Sopenharmony_ci}
34662306a36Sopenharmony_ci
34762306a36Sopenharmony_cistatic void sdhci_arasan_set_clock(struct sdhci_host *host, unsigned int clock)
34862306a36Sopenharmony_ci{
34962306a36Sopenharmony_ci	struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
35062306a36Sopenharmony_ci	struct sdhci_arasan_data *sdhci_arasan = sdhci_pltfm_priv(pltfm_host);
35162306a36Sopenharmony_ci	struct sdhci_arasan_clk_data *clk_data = &sdhci_arasan->clk_data;
35262306a36Sopenharmony_ci	bool ctrl_phy = false;
35362306a36Sopenharmony_ci
35462306a36Sopenharmony_ci	if (!IS_ERR(sdhci_arasan->phy)) {
35562306a36Sopenharmony_ci		if (!sdhci_arasan->is_phy_on && clock <= PHY_CLK_TOO_SLOW_HZ) {
35662306a36Sopenharmony_ci			/*
35762306a36Sopenharmony_ci			 * If PHY off, set clock to max speed and power PHY on.
35862306a36Sopenharmony_ci			 *
35962306a36Sopenharmony_ci			 * Although PHY docs apparently suggest power cycling
36062306a36Sopenharmony_ci			 * when changing the clock the PHY doesn't like to be
36162306a36Sopenharmony_ci			 * powered on while at low speeds like those used in ID
36262306a36Sopenharmony_ci			 * mode.  Even worse is powering the PHY on while the
36362306a36Sopenharmony_ci			 * clock is off.
36462306a36Sopenharmony_ci			 *
36562306a36Sopenharmony_ci			 * To workaround the PHY limitations, the best we can
36662306a36Sopenharmony_ci			 * do is to power it on at a faster speed and then slam
36762306a36Sopenharmony_ci			 * through low speeds without power cycling.
36862306a36Sopenharmony_ci			 */
36962306a36Sopenharmony_ci			sdhci_set_clock(host, host->max_clk);
37062306a36Sopenharmony_ci			if (phy_power_on(sdhci_arasan->phy)) {
37162306a36Sopenharmony_ci				pr_err("%s: Cannot power on phy.\n",
37262306a36Sopenharmony_ci				       mmc_hostname(host->mmc));
37362306a36Sopenharmony_ci				return;
37462306a36Sopenharmony_ci			}
37562306a36Sopenharmony_ci
37662306a36Sopenharmony_ci			sdhci_arasan->is_phy_on = true;
37762306a36Sopenharmony_ci
37862306a36Sopenharmony_ci			/*
37962306a36Sopenharmony_ci			 * We'll now fall through to the below case with
38062306a36Sopenharmony_ci			 * ctrl_phy = false (so we won't turn off/on).  The
38162306a36Sopenharmony_ci			 * sdhci_set_clock() will set the real clock.
38262306a36Sopenharmony_ci			 */
38362306a36Sopenharmony_ci		} else if (clock > PHY_CLK_TOO_SLOW_HZ) {
38462306a36Sopenharmony_ci			/*
38562306a36Sopenharmony_ci			 * At higher clock speeds the PHY is fine being power
38662306a36Sopenharmony_ci			 * cycled and docs say you _should_ power cycle when
38762306a36Sopenharmony_ci			 * changing clock speeds.
38862306a36Sopenharmony_ci			 */
38962306a36Sopenharmony_ci			ctrl_phy = true;
39062306a36Sopenharmony_ci		}
39162306a36Sopenharmony_ci	}
39262306a36Sopenharmony_ci
39362306a36Sopenharmony_ci	if (ctrl_phy && sdhci_arasan->is_phy_on) {
39462306a36Sopenharmony_ci		phy_power_off(sdhci_arasan->phy);
39562306a36Sopenharmony_ci		sdhci_arasan->is_phy_on = false;
39662306a36Sopenharmony_ci	}
39762306a36Sopenharmony_ci
39862306a36Sopenharmony_ci	if (sdhci_arasan->quirks & SDHCI_ARASAN_QUIRK_CLOCK_25_BROKEN) {
39962306a36Sopenharmony_ci		/*
40062306a36Sopenharmony_ci		 * Some of the Arasan variations might not have timing
40162306a36Sopenharmony_ci		 * requirements met at 25MHz for Default Speed mode,
40262306a36Sopenharmony_ci		 * those controllers work at 19MHz instead.
40362306a36Sopenharmony_ci		 */
40462306a36Sopenharmony_ci		if (clock == DEFAULT_SPEED_MAX_DTR)
40562306a36Sopenharmony_ci			clock = (DEFAULT_SPEED_MAX_DTR * 19) / 25;
40662306a36Sopenharmony_ci	}
40762306a36Sopenharmony_ci
40862306a36Sopenharmony_ci	/* Set the Input and Output Clock Phase Delays */
40962306a36Sopenharmony_ci	if (clk_data->set_clk_delays && clock > PHY_CLK_TOO_SLOW_HZ)
41062306a36Sopenharmony_ci		clk_data->set_clk_delays(host);
41162306a36Sopenharmony_ci
41262306a36Sopenharmony_ci	if (sdhci_arasan->internal_phy_reg && clock >= MIN_PHY_CLK_HZ) {
41362306a36Sopenharmony_ci		sdhci_writew(host, 0, SDHCI_CLOCK_CONTROL);
41462306a36Sopenharmony_ci		sdhci_arasan_phy_set_dll(host, 0);
41562306a36Sopenharmony_ci		sdhci_arasan_phy_set_delaychain(host, 0);
41662306a36Sopenharmony_ci		sdhci_arasan_phy_dll_set_freq(host, clock);
41762306a36Sopenharmony_ci	} else if (sdhci_arasan->internal_phy_reg) {
41862306a36Sopenharmony_ci		sdhci_writew(host, 0, SDHCI_CLOCK_CONTROL);
41962306a36Sopenharmony_ci		sdhci_arasan_phy_set_delaychain(host, 1);
42062306a36Sopenharmony_ci	}
42162306a36Sopenharmony_ci
42262306a36Sopenharmony_ci	sdhci_set_clock(host, clock);
42362306a36Sopenharmony_ci
42462306a36Sopenharmony_ci	if (sdhci_arasan->internal_phy_reg && clock >= MIN_PHY_CLK_HZ)
42562306a36Sopenharmony_ci		sdhci_arasan_phy_set_dll(host, 1);
42662306a36Sopenharmony_ci
42762306a36Sopenharmony_ci	if (sdhci_arasan->quirks & SDHCI_ARASAN_QUIRK_CLOCK_UNSTABLE)
42862306a36Sopenharmony_ci		/*
42962306a36Sopenharmony_ci		 * Some controllers immediately report SDHCI_CLOCK_INT_STABLE
43062306a36Sopenharmony_ci		 * after enabling the clock even though the clock is not
43162306a36Sopenharmony_ci		 * stable. Trying to use a clock without waiting here results
43262306a36Sopenharmony_ci		 * in EILSEQ while detecting some older/slower cards. The
43362306a36Sopenharmony_ci		 * chosen delay is the maximum delay from sdhci_set_clock.
43462306a36Sopenharmony_ci		 */
43562306a36Sopenharmony_ci		msleep(20);
43662306a36Sopenharmony_ci
43762306a36Sopenharmony_ci	if (ctrl_phy) {
43862306a36Sopenharmony_ci		if (phy_power_on(sdhci_arasan->phy)) {
43962306a36Sopenharmony_ci			pr_err("%s: Cannot power on phy.\n",
44062306a36Sopenharmony_ci			       mmc_hostname(host->mmc));
44162306a36Sopenharmony_ci			return;
44262306a36Sopenharmony_ci		}
44362306a36Sopenharmony_ci
44462306a36Sopenharmony_ci		sdhci_arasan->is_phy_on = true;
44562306a36Sopenharmony_ci	}
44662306a36Sopenharmony_ci}
44762306a36Sopenharmony_ci
44862306a36Sopenharmony_cistatic void sdhci_arasan_hs400_enhanced_strobe(struct mmc_host *mmc,
44962306a36Sopenharmony_ci					struct mmc_ios *ios)
45062306a36Sopenharmony_ci{
45162306a36Sopenharmony_ci	u32 vendor;
45262306a36Sopenharmony_ci	struct sdhci_host *host = mmc_priv(mmc);
45362306a36Sopenharmony_ci
45462306a36Sopenharmony_ci	vendor = sdhci_readl(host, SDHCI_ARASAN_VENDOR_REGISTER);
45562306a36Sopenharmony_ci	if (ios->enhanced_strobe)
45662306a36Sopenharmony_ci		vendor |= VENDOR_ENHANCED_STROBE;
45762306a36Sopenharmony_ci	else
45862306a36Sopenharmony_ci		vendor &= ~VENDOR_ENHANCED_STROBE;
45962306a36Sopenharmony_ci
46062306a36Sopenharmony_ci	sdhci_writel(host, vendor, SDHCI_ARASAN_VENDOR_REGISTER);
46162306a36Sopenharmony_ci}
46262306a36Sopenharmony_ci
46362306a36Sopenharmony_cistatic void sdhci_arasan_reset(struct sdhci_host *host, u8 mask)
46462306a36Sopenharmony_ci{
46562306a36Sopenharmony_ci	u8 ctrl;
46662306a36Sopenharmony_ci	struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
46762306a36Sopenharmony_ci	struct sdhci_arasan_data *sdhci_arasan = sdhci_pltfm_priv(pltfm_host);
46862306a36Sopenharmony_ci
46962306a36Sopenharmony_ci	sdhci_and_cqhci_reset(host, mask);
47062306a36Sopenharmony_ci
47162306a36Sopenharmony_ci	if (sdhci_arasan->quirks & SDHCI_ARASAN_QUIRK_FORCE_CDTEST) {
47262306a36Sopenharmony_ci		ctrl = sdhci_readb(host, SDHCI_HOST_CONTROL);
47362306a36Sopenharmony_ci		ctrl |= SDHCI_CTRL_CDTEST_INS | SDHCI_CTRL_CDTEST_EN;
47462306a36Sopenharmony_ci		sdhci_writeb(host, ctrl, SDHCI_HOST_CONTROL);
47562306a36Sopenharmony_ci	}
47662306a36Sopenharmony_ci}
47762306a36Sopenharmony_ci
47862306a36Sopenharmony_cistatic int sdhci_arasan_voltage_switch(struct mmc_host *mmc,
47962306a36Sopenharmony_ci				       struct mmc_ios *ios)
48062306a36Sopenharmony_ci{
48162306a36Sopenharmony_ci	switch (ios->signal_voltage) {
48262306a36Sopenharmony_ci	case MMC_SIGNAL_VOLTAGE_180:
48362306a36Sopenharmony_ci		/*
48462306a36Sopenharmony_ci		 * Plese don't switch to 1V8 as arasan,5.1 doesn't
48562306a36Sopenharmony_ci		 * actually refer to this setting to indicate the
48662306a36Sopenharmony_ci		 * signal voltage and the state machine will be broken
48762306a36Sopenharmony_ci		 * actually if we force to enable 1V8. That's something
48862306a36Sopenharmony_ci		 * like broken quirk but we could work around here.
48962306a36Sopenharmony_ci		 */
49062306a36Sopenharmony_ci		return 0;
49162306a36Sopenharmony_ci	case MMC_SIGNAL_VOLTAGE_330:
49262306a36Sopenharmony_ci	case MMC_SIGNAL_VOLTAGE_120:
49362306a36Sopenharmony_ci		/* We don't support 3V3 and 1V2 */
49462306a36Sopenharmony_ci		break;
49562306a36Sopenharmony_ci	}
49662306a36Sopenharmony_ci
49762306a36Sopenharmony_ci	return -EINVAL;
49862306a36Sopenharmony_ci}
49962306a36Sopenharmony_ci
50062306a36Sopenharmony_cistatic const struct sdhci_ops sdhci_arasan_ops = {
50162306a36Sopenharmony_ci	.set_clock = sdhci_arasan_set_clock,
50262306a36Sopenharmony_ci	.get_max_clock = sdhci_pltfm_clk_get_max_clock,
50362306a36Sopenharmony_ci	.get_timeout_clock = sdhci_pltfm_clk_get_max_clock,
50462306a36Sopenharmony_ci	.set_bus_width = sdhci_set_bus_width,
50562306a36Sopenharmony_ci	.reset = sdhci_arasan_reset,
50662306a36Sopenharmony_ci	.set_uhs_signaling = sdhci_set_uhs_signaling,
50762306a36Sopenharmony_ci	.set_power = sdhci_set_power_and_bus_voltage,
50862306a36Sopenharmony_ci};
50962306a36Sopenharmony_ci
51062306a36Sopenharmony_cistatic u32 sdhci_arasan_cqhci_irq(struct sdhci_host *host, u32 intmask)
51162306a36Sopenharmony_ci{
51262306a36Sopenharmony_ci	int cmd_error = 0;
51362306a36Sopenharmony_ci	int data_error = 0;
51462306a36Sopenharmony_ci
51562306a36Sopenharmony_ci	if (!sdhci_cqe_irq(host, intmask, &cmd_error, &data_error))
51662306a36Sopenharmony_ci		return intmask;
51762306a36Sopenharmony_ci
51862306a36Sopenharmony_ci	cqhci_irq(host->mmc, intmask, cmd_error, data_error);
51962306a36Sopenharmony_ci
52062306a36Sopenharmony_ci	return 0;
52162306a36Sopenharmony_ci}
52262306a36Sopenharmony_ci
52362306a36Sopenharmony_cistatic void sdhci_arasan_dumpregs(struct mmc_host *mmc)
52462306a36Sopenharmony_ci{
52562306a36Sopenharmony_ci	sdhci_dumpregs(mmc_priv(mmc));
52662306a36Sopenharmony_ci}
52762306a36Sopenharmony_ci
52862306a36Sopenharmony_cistatic void sdhci_arasan_cqe_enable(struct mmc_host *mmc)
52962306a36Sopenharmony_ci{
53062306a36Sopenharmony_ci	struct sdhci_host *host = mmc_priv(mmc);
53162306a36Sopenharmony_ci	u32 reg;
53262306a36Sopenharmony_ci
53362306a36Sopenharmony_ci	reg = sdhci_readl(host, SDHCI_PRESENT_STATE);
53462306a36Sopenharmony_ci	while (reg & SDHCI_DATA_AVAILABLE) {
53562306a36Sopenharmony_ci		sdhci_readl(host, SDHCI_BUFFER);
53662306a36Sopenharmony_ci		reg = sdhci_readl(host, SDHCI_PRESENT_STATE);
53762306a36Sopenharmony_ci	}
53862306a36Sopenharmony_ci
53962306a36Sopenharmony_ci	sdhci_cqe_enable(mmc);
54062306a36Sopenharmony_ci}
54162306a36Sopenharmony_ci
54262306a36Sopenharmony_cistatic const struct cqhci_host_ops sdhci_arasan_cqhci_ops = {
54362306a36Sopenharmony_ci	.enable         = sdhci_arasan_cqe_enable,
54462306a36Sopenharmony_ci	.disable        = sdhci_cqe_disable,
54562306a36Sopenharmony_ci	.dumpregs       = sdhci_arasan_dumpregs,
54662306a36Sopenharmony_ci};
54762306a36Sopenharmony_ci
54862306a36Sopenharmony_cistatic const struct sdhci_ops sdhci_arasan_cqe_ops = {
54962306a36Sopenharmony_ci	.set_clock = sdhci_arasan_set_clock,
55062306a36Sopenharmony_ci	.get_max_clock = sdhci_pltfm_clk_get_max_clock,
55162306a36Sopenharmony_ci	.get_timeout_clock = sdhci_pltfm_clk_get_max_clock,
55262306a36Sopenharmony_ci	.set_bus_width = sdhci_set_bus_width,
55362306a36Sopenharmony_ci	.reset = sdhci_arasan_reset,
55462306a36Sopenharmony_ci	.set_uhs_signaling = sdhci_set_uhs_signaling,
55562306a36Sopenharmony_ci	.set_power = sdhci_set_power_and_bus_voltage,
55662306a36Sopenharmony_ci	.irq = sdhci_arasan_cqhci_irq,
55762306a36Sopenharmony_ci};
55862306a36Sopenharmony_ci
55962306a36Sopenharmony_cistatic const struct sdhci_pltfm_data sdhci_arasan_cqe_pdata = {
56062306a36Sopenharmony_ci	.ops = &sdhci_arasan_cqe_ops,
56162306a36Sopenharmony_ci	.quirks = SDHCI_QUIRK_CAP_CLOCK_BASE_BROKEN,
56262306a36Sopenharmony_ci	.quirks2 = SDHCI_QUIRK2_PRESET_VALUE_BROKEN |
56362306a36Sopenharmony_ci			SDHCI_QUIRK2_CLOCK_DIV_ZERO_BROKEN,
56462306a36Sopenharmony_ci};
56562306a36Sopenharmony_ci
56662306a36Sopenharmony_ci#ifdef CONFIG_PM_SLEEP
56762306a36Sopenharmony_ci/**
56862306a36Sopenharmony_ci * sdhci_arasan_suspend - Suspend method for the driver
56962306a36Sopenharmony_ci * @dev:	Address of the device structure
57062306a36Sopenharmony_ci *
57162306a36Sopenharmony_ci * Put the device in a low power state.
57262306a36Sopenharmony_ci *
57362306a36Sopenharmony_ci * Return: 0 on success and error value on error
57462306a36Sopenharmony_ci */
57562306a36Sopenharmony_cistatic int sdhci_arasan_suspend(struct device *dev)
57662306a36Sopenharmony_ci{
57762306a36Sopenharmony_ci	struct sdhci_host *host = dev_get_drvdata(dev);
57862306a36Sopenharmony_ci	struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
57962306a36Sopenharmony_ci	struct sdhci_arasan_data *sdhci_arasan = sdhci_pltfm_priv(pltfm_host);
58062306a36Sopenharmony_ci	int ret;
58162306a36Sopenharmony_ci
58262306a36Sopenharmony_ci	if (host->tuning_mode != SDHCI_TUNING_MODE_3)
58362306a36Sopenharmony_ci		mmc_retune_needed(host->mmc);
58462306a36Sopenharmony_ci
58562306a36Sopenharmony_ci	if (sdhci_arasan->has_cqe) {
58662306a36Sopenharmony_ci		ret = cqhci_suspend(host->mmc);
58762306a36Sopenharmony_ci		if (ret)
58862306a36Sopenharmony_ci			return ret;
58962306a36Sopenharmony_ci	}
59062306a36Sopenharmony_ci
59162306a36Sopenharmony_ci	ret = sdhci_suspend_host(host);
59262306a36Sopenharmony_ci	if (ret)
59362306a36Sopenharmony_ci		return ret;
59462306a36Sopenharmony_ci
59562306a36Sopenharmony_ci	if (!IS_ERR(sdhci_arasan->phy) && sdhci_arasan->is_phy_on) {
59662306a36Sopenharmony_ci		ret = phy_power_off(sdhci_arasan->phy);
59762306a36Sopenharmony_ci		if (ret) {
59862306a36Sopenharmony_ci			dev_err(dev, "Cannot power off phy.\n");
59962306a36Sopenharmony_ci			if (sdhci_resume_host(host))
60062306a36Sopenharmony_ci				dev_err(dev, "Cannot resume host.\n");
60162306a36Sopenharmony_ci
60262306a36Sopenharmony_ci			return ret;
60362306a36Sopenharmony_ci		}
60462306a36Sopenharmony_ci		sdhci_arasan->is_phy_on = false;
60562306a36Sopenharmony_ci	}
60662306a36Sopenharmony_ci
60762306a36Sopenharmony_ci	clk_disable(pltfm_host->clk);
60862306a36Sopenharmony_ci	clk_disable(sdhci_arasan->clk_ahb);
60962306a36Sopenharmony_ci
61062306a36Sopenharmony_ci	return 0;
61162306a36Sopenharmony_ci}
61262306a36Sopenharmony_ci
61362306a36Sopenharmony_ci/**
61462306a36Sopenharmony_ci * sdhci_arasan_resume - Resume method for the driver
61562306a36Sopenharmony_ci * @dev:	Address of the device structure
61662306a36Sopenharmony_ci *
61762306a36Sopenharmony_ci * Resume operation after suspend
61862306a36Sopenharmony_ci *
61962306a36Sopenharmony_ci * Return: 0 on success and error value on error
62062306a36Sopenharmony_ci */
62162306a36Sopenharmony_cistatic int sdhci_arasan_resume(struct device *dev)
62262306a36Sopenharmony_ci{
62362306a36Sopenharmony_ci	struct sdhci_host *host = dev_get_drvdata(dev);
62462306a36Sopenharmony_ci	struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
62562306a36Sopenharmony_ci	struct sdhci_arasan_data *sdhci_arasan = sdhci_pltfm_priv(pltfm_host);
62662306a36Sopenharmony_ci	int ret;
62762306a36Sopenharmony_ci
62862306a36Sopenharmony_ci	ret = clk_enable(sdhci_arasan->clk_ahb);
62962306a36Sopenharmony_ci	if (ret) {
63062306a36Sopenharmony_ci		dev_err(dev, "Cannot enable AHB clock.\n");
63162306a36Sopenharmony_ci		return ret;
63262306a36Sopenharmony_ci	}
63362306a36Sopenharmony_ci
63462306a36Sopenharmony_ci	ret = clk_enable(pltfm_host->clk);
63562306a36Sopenharmony_ci	if (ret) {
63662306a36Sopenharmony_ci		dev_err(dev, "Cannot enable SD clock.\n");
63762306a36Sopenharmony_ci		return ret;
63862306a36Sopenharmony_ci	}
63962306a36Sopenharmony_ci
64062306a36Sopenharmony_ci	if (!IS_ERR(sdhci_arasan->phy) && host->mmc->actual_clock) {
64162306a36Sopenharmony_ci		ret = phy_power_on(sdhci_arasan->phy);
64262306a36Sopenharmony_ci		if (ret) {
64362306a36Sopenharmony_ci			dev_err(dev, "Cannot power on phy.\n");
64462306a36Sopenharmony_ci			return ret;
64562306a36Sopenharmony_ci		}
64662306a36Sopenharmony_ci		sdhci_arasan->is_phy_on = true;
64762306a36Sopenharmony_ci	}
64862306a36Sopenharmony_ci
64962306a36Sopenharmony_ci	ret = sdhci_resume_host(host);
65062306a36Sopenharmony_ci	if (ret) {
65162306a36Sopenharmony_ci		dev_err(dev, "Cannot resume host.\n");
65262306a36Sopenharmony_ci		return ret;
65362306a36Sopenharmony_ci	}
65462306a36Sopenharmony_ci
65562306a36Sopenharmony_ci	if (sdhci_arasan->has_cqe)
65662306a36Sopenharmony_ci		return cqhci_resume(host->mmc);
65762306a36Sopenharmony_ci
65862306a36Sopenharmony_ci	return 0;
65962306a36Sopenharmony_ci}
66062306a36Sopenharmony_ci#endif /* ! CONFIG_PM_SLEEP */
66162306a36Sopenharmony_ci
66262306a36Sopenharmony_cistatic SIMPLE_DEV_PM_OPS(sdhci_arasan_dev_pm_ops, sdhci_arasan_suspend,
66362306a36Sopenharmony_ci			 sdhci_arasan_resume);
66462306a36Sopenharmony_ci
66562306a36Sopenharmony_ci/**
66662306a36Sopenharmony_ci * sdhci_arasan_sdcardclk_recalc_rate - Return the card clock rate
66762306a36Sopenharmony_ci *
66862306a36Sopenharmony_ci * @hw:			Pointer to the hardware clock structure.
66962306a36Sopenharmony_ci * @parent_rate:		The parent rate (should be rate of clk_xin).
67062306a36Sopenharmony_ci *
67162306a36Sopenharmony_ci * Return the current actual rate of the SD card clock.  This can be used
67262306a36Sopenharmony_ci * to communicate with out PHY.
67362306a36Sopenharmony_ci *
67462306a36Sopenharmony_ci * Return: The card clock rate.
67562306a36Sopenharmony_ci */
67662306a36Sopenharmony_cistatic unsigned long sdhci_arasan_sdcardclk_recalc_rate(struct clk_hw *hw,
67762306a36Sopenharmony_ci						      unsigned long parent_rate)
67862306a36Sopenharmony_ci{
67962306a36Sopenharmony_ci	struct sdhci_arasan_clk_data *clk_data =
68062306a36Sopenharmony_ci		container_of(hw, struct sdhci_arasan_clk_data, sdcardclk_hw);
68162306a36Sopenharmony_ci	struct sdhci_arasan_data *sdhci_arasan =
68262306a36Sopenharmony_ci		container_of(clk_data, struct sdhci_arasan_data, clk_data);
68362306a36Sopenharmony_ci	struct sdhci_host *host = sdhci_arasan->host;
68462306a36Sopenharmony_ci
68562306a36Sopenharmony_ci	return host->mmc->actual_clock;
68662306a36Sopenharmony_ci}
68762306a36Sopenharmony_ci
68862306a36Sopenharmony_cistatic const struct clk_ops arasan_sdcardclk_ops = {
68962306a36Sopenharmony_ci	.recalc_rate = sdhci_arasan_sdcardclk_recalc_rate,
69062306a36Sopenharmony_ci};
69162306a36Sopenharmony_ci
69262306a36Sopenharmony_ci/**
69362306a36Sopenharmony_ci * sdhci_arasan_sampleclk_recalc_rate - Return the sampling clock rate
69462306a36Sopenharmony_ci *
69562306a36Sopenharmony_ci * @hw:			Pointer to the hardware clock structure.
69662306a36Sopenharmony_ci * @parent_rate:		The parent rate (should be rate of clk_xin).
69762306a36Sopenharmony_ci *
69862306a36Sopenharmony_ci * Return the current actual rate of the sampling clock.  This can be used
69962306a36Sopenharmony_ci * to communicate with out PHY.
70062306a36Sopenharmony_ci *
70162306a36Sopenharmony_ci * Return: The sample clock rate.
70262306a36Sopenharmony_ci */
70362306a36Sopenharmony_cistatic unsigned long sdhci_arasan_sampleclk_recalc_rate(struct clk_hw *hw,
70462306a36Sopenharmony_ci						      unsigned long parent_rate)
70562306a36Sopenharmony_ci{
70662306a36Sopenharmony_ci	struct sdhci_arasan_clk_data *clk_data =
70762306a36Sopenharmony_ci		container_of(hw, struct sdhci_arasan_clk_data, sampleclk_hw);
70862306a36Sopenharmony_ci	struct sdhci_arasan_data *sdhci_arasan =
70962306a36Sopenharmony_ci		container_of(clk_data, struct sdhci_arasan_data, clk_data);
71062306a36Sopenharmony_ci	struct sdhci_host *host = sdhci_arasan->host;
71162306a36Sopenharmony_ci
71262306a36Sopenharmony_ci	return host->mmc->actual_clock;
71362306a36Sopenharmony_ci}
71462306a36Sopenharmony_ci
71562306a36Sopenharmony_cistatic const struct clk_ops arasan_sampleclk_ops = {
71662306a36Sopenharmony_ci	.recalc_rate = sdhci_arasan_sampleclk_recalc_rate,
71762306a36Sopenharmony_ci};
71862306a36Sopenharmony_ci
71962306a36Sopenharmony_ci/**
72062306a36Sopenharmony_ci * sdhci_zynqmp_sdcardclk_set_phase - Set the SD Output Clock Tap Delays
72162306a36Sopenharmony_ci *
72262306a36Sopenharmony_ci * @hw:			Pointer to the hardware clock structure.
72362306a36Sopenharmony_ci * @degrees:		The clock phase shift between 0 - 359.
72462306a36Sopenharmony_ci *
72562306a36Sopenharmony_ci * Set the SD Output Clock Tap Delays for Output path
72662306a36Sopenharmony_ci *
72762306a36Sopenharmony_ci * Return: 0 on success and error value on error
72862306a36Sopenharmony_ci */
72962306a36Sopenharmony_cistatic int sdhci_zynqmp_sdcardclk_set_phase(struct clk_hw *hw, int degrees)
73062306a36Sopenharmony_ci{
73162306a36Sopenharmony_ci	struct sdhci_arasan_clk_data *clk_data =
73262306a36Sopenharmony_ci		container_of(hw, struct sdhci_arasan_clk_data, sdcardclk_hw);
73362306a36Sopenharmony_ci	struct sdhci_arasan_data *sdhci_arasan =
73462306a36Sopenharmony_ci		container_of(clk_data, struct sdhci_arasan_data, clk_data);
73562306a36Sopenharmony_ci	struct sdhci_host *host = sdhci_arasan->host;
73662306a36Sopenharmony_ci	const char *clk_name = clk_hw_get_name(hw);
73762306a36Sopenharmony_ci	u32 node_id = !strcmp(clk_name, "clk_out_sd0") ? NODE_SD_0 : NODE_SD_1;
73862306a36Sopenharmony_ci	u8 tap_delay, tap_max = 0;
73962306a36Sopenharmony_ci	int ret;
74062306a36Sopenharmony_ci
74162306a36Sopenharmony_ci	/* This is applicable for SDHCI_SPEC_300 and above */
74262306a36Sopenharmony_ci	if (host->version < SDHCI_SPEC_300)
74362306a36Sopenharmony_ci		return 0;
74462306a36Sopenharmony_ci
74562306a36Sopenharmony_ci	switch (host->timing) {
74662306a36Sopenharmony_ci	case MMC_TIMING_MMC_HS:
74762306a36Sopenharmony_ci	case MMC_TIMING_SD_HS:
74862306a36Sopenharmony_ci	case MMC_TIMING_UHS_SDR25:
74962306a36Sopenharmony_ci	case MMC_TIMING_UHS_DDR50:
75062306a36Sopenharmony_ci	case MMC_TIMING_MMC_DDR52:
75162306a36Sopenharmony_ci		/* For 50MHz clock, 30 Taps are available */
75262306a36Sopenharmony_ci		tap_max = 30;
75362306a36Sopenharmony_ci		break;
75462306a36Sopenharmony_ci	case MMC_TIMING_UHS_SDR50:
75562306a36Sopenharmony_ci		/* For 100MHz clock, 15 Taps are available */
75662306a36Sopenharmony_ci		tap_max = 15;
75762306a36Sopenharmony_ci		break;
75862306a36Sopenharmony_ci	case MMC_TIMING_UHS_SDR104:
75962306a36Sopenharmony_ci	case MMC_TIMING_MMC_HS200:
76062306a36Sopenharmony_ci		/* For 200MHz clock, 8 Taps are available */
76162306a36Sopenharmony_ci		tap_max = 8;
76262306a36Sopenharmony_ci		break;
76362306a36Sopenharmony_ci	default:
76462306a36Sopenharmony_ci		break;
76562306a36Sopenharmony_ci	}
76662306a36Sopenharmony_ci
76762306a36Sopenharmony_ci	tap_delay = (degrees * tap_max) / 360;
76862306a36Sopenharmony_ci
76962306a36Sopenharmony_ci	/* Set the Clock Phase */
77062306a36Sopenharmony_ci	ret = zynqmp_pm_set_sd_tapdelay(node_id, PM_TAPDELAY_OUTPUT, tap_delay);
77162306a36Sopenharmony_ci	if (ret)
77262306a36Sopenharmony_ci		pr_err("Error setting Output Tap Delay\n");
77362306a36Sopenharmony_ci
77462306a36Sopenharmony_ci	/* Release DLL Reset */
77562306a36Sopenharmony_ci	zynqmp_pm_sd_dll_reset(node_id, PM_DLL_RESET_RELEASE);
77662306a36Sopenharmony_ci
77762306a36Sopenharmony_ci	return ret;
77862306a36Sopenharmony_ci}
77962306a36Sopenharmony_ci
78062306a36Sopenharmony_cistatic const struct clk_ops zynqmp_sdcardclk_ops = {
78162306a36Sopenharmony_ci	.recalc_rate = sdhci_arasan_sdcardclk_recalc_rate,
78262306a36Sopenharmony_ci	.set_phase = sdhci_zynqmp_sdcardclk_set_phase,
78362306a36Sopenharmony_ci};
78462306a36Sopenharmony_ci
78562306a36Sopenharmony_ci/**
78662306a36Sopenharmony_ci * sdhci_zynqmp_sampleclk_set_phase - Set the SD Input Clock Tap Delays
78762306a36Sopenharmony_ci *
78862306a36Sopenharmony_ci * @hw:			Pointer to the hardware clock structure.
78962306a36Sopenharmony_ci * @degrees:		The clock phase shift between 0 - 359.
79062306a36Sopenharmony_ci *
79162306a36Sopenharmony_ci * Set the SD Input Clock Tap Delays for Input path
79262306a36Sopenharmony_ci *
79362306a36Sopenharmony_ci * Return: 0 on success and error value on error
79462306a36Sopenharmony_ci */
79562306a36Sopenharmony_cistatic int sdhci_zynqmp_sampleclk_set_phase(struct clk_hw *hw, int degrees)
79662306a36Sopenharmony_ci{
79762306a36Sopenharmony_ci	struct sdhci_arasan_clk_data *clk_data =
79862306a36Sopenharmony_ci		container_of(hw, struct sdhci_arasan_clk_data, sampleclk_hw);
79962306a36Sopenharmony_ci	struct sdhci_arasan_data *sdhci_arasan =
80062306a36Sopenharmony_ci		container_of(clk_data, struct sdhci_arasan_data, clk_data);
80162306a36Sopenharmony_ci	struct sdhci_host *host = sdhci_arasan->host;
80262306a36Sopenharmony_ci	const char *clk_name = clk_hw_get_name(hw);
80362306a36Sopenharmony_ci	u32 node_id = !strcmp(clk_name, "clk_in_sd0") ? NODE_SD_0 : NODE_SD_1;
80462306a36Sopenharmony_ci	u8 tap_delay, tap_max = 0;
80562306a36Sopenharmony_ci	int ret;
80662306a36Sopenharmony_ci
80762306a36Sopenharmony_ci	/* This is applicable for SDHCI_SPEC_300 and above */
80862306a36Sopenharmony_ci	if (host->version < SDHCI_SPEC_300)
80962306a36Sopenharmony_ci		return 0;
81062306a36Sopenharmony_ci
81162306a36Sopenharmony_ci	/* Assert DLL Reset */
81262306a36Sopenharmony_ci	zynqmp_pm_sd_dll_reset(node_id, PM_DLL_RESET_ASSERT);
81362306a36Sopenharmony_ci
81462306a36Sopenharmony_ci	switch (host->timing) {
81562306a36Sopenharmony_ci	case MMC_TIMING_MMC_HS:
81662306a36Sopenharmony_ci	case MMC_TIMING_SD_HS:
81762306a36Sopenharmony_ci	case MMC_TIMING_UHS_SDR25:
81862306a36Sopenharmony_ci	case MMC_TIMING_UHS_DDR50:
81962306a36Sopenharmony_ci	case MMC_TIMING_MMC_DDR52:
82062306a36Sopenharmony_ci		/* For 50MHz clock, 120 Taps are available */
82162306a36Sopenharmony_ci		tap_max = 120;
82262306a36Sopenharmony_ci		break;
82362306a36Sopenharmony_ci	case MMC_TIMING_UHS_SDR50:
82462306a36Sopenharmony_ci		/* For 100MHz clock, 60 Taps are available */
82562306a36Sopenharmony_ci		tap_max = 60;
82662306a36Sopenharmony_ci		break;
82762306a36Sopenharmony_ci	case MMC_TIMING_UHS_SDR104:
82862306a36Sopenharmony_ci	case MMC_TIMING_MMC_HS200:
82962306a36Sopenharmony_ci		/* For 200MHz clock, 30 Taps are available */
83062306a36Sopenharmony_ci		tap_max = 30;
83162306a36Sopenharmony_ci		break;
83262306a36Sopenharmony_ci	default:
83362306a36Sopenharmony_ci		break;
83462306a36Sopenharmony_ci	}
83562306a36Sopenharmony_ci
83662306a36Sopenharmony_ci	tap_delay = (degrees * tap_max) / 360;
83762306a36Sopenharmony_ci
83862306a36Sopenharmony_ci	/* Set the Clock Phase */
83962306a36Sopenharmony_ci	ret = zynqmp_pm_set_sd_tapdelay(node_id, PM_TAPDELAY_INPUT, tap_delay);
84062306a36Sopenharmony_ci	if (ret)
84162306a36Sopenharmony_ci		pr_err("Error setting Input Tap Delay\n");
84262306a36Sopenharmony_ci
84362306a36Sopenharmony_ci	return ret;
84462306a36Sopenharmony_ci}
84562306a36Sopenharmony_ci
84662306a36Sopenharmony_cistatic const struct clk_ops zynqmp_sampleclk_ops = {
84762306a36Sopenharmony_ci	.recalc_rate = sdhci_arasan_sampleclk_recalc_rate,
84862306a36Sopenharmony_ci	.set_phase = sdhci_zynqmp_sampleclk_set_phase,
84962306a36Sopenharmony_ci};
85062306a36Sopenharmony_ci
85162306a36Sopenharmony_ci/**
85262306a36Sopenharmony_ci * sdhci_versal_sdcardclk_set_phase - Set the SD Output Clock Tap Delays
85362306a36Sopenharmony_ci *
85462306a36Sopenharmony_ci * @hw:			Pointer to the hardware clock structure.
85562306a36Sopenharmony_ci * @degrees:		The clock phase shift between 0 - 359.
85662306a36Sopenharmony_ci *
85762306a36Sopenharmony_ci * Set the SD Output Clock Tap Delays for Output path
85862306a36Sopenharmony_ci *
85962306a36Sopenharmony_ci * Return: 0 on success and error value on error
86062306a36Sopenharmony_ci */
86162306a36Sopenharmony_cistatic int sdhci_versal_sdcardclk_set_phase(struct clk_hw *hw, int degrees)
86262306a36Sopenharmony_ci{
86362306a36Sopenharmony_ci	struct sdhci_arasan_clk_data *clk_data =
86462306a36Sopenharmony_ci		container_of(hw, struct sdhci_arasan_clk_data, sdcardclk_hw);
86562306a36Sopenharmony_ci	struct sdhci_arasan_data *sdhci_arasan =
86662306a36Sopenharmony_ci		container_of(clk_data, struct sdhci_arasan_data, clk_data);
86762306a36Sopenharmony_ci	struct sdhci_host *host = sdhci_arasan->host;
86862306a36Sopenharmony_ci	u8 tap_delay, tap_max = 0;
86962306a36Sopenharmony_ci
87062306a36Sopenharmony_ci	/* This is applicable for SDHCI_SPEC_300 and above */
87162306a36Sopenharmony_ci	if (host->version < SDHCI_SPEC_300)
87262306a36Sopenharmony_ci		return 0;
87362306a36Sopenharmony_ci
87462306a36Sopenharmony_ci	switch (host->timing) {
87562306a36Sopenharmony_ci	case MMC_TIMING_MMC_HS:
87662306a36Sopenharmony_ci	case MMC_TIMING_SD_HS:
87762306a36Sopenharmony_ci	case MMC_TIMING_UHS_SDR25:
87862306a36Sopenharmony_ci	case MMC_TIMING_UHS_DDR50:
87962306a36Sopenharmony_ci	case MMC_TIMING_MMC_DDR52:
88062306a36Sopenharmony_ci		/* For 50MHz clock, 30 Taps are available */
88162306a36Sopenharmony_ci		tap_max = 30;
88262306a36Sopenharmony_ci		break;
88362306a36Sopenharmony_ci	case MMC_TIMING_UHS_SDR50:
88462306a36Sopenharmony_ci		/* For 100MHz clock, 15 Taps are available */
88562306a36Sopenharmony_ci		tap_max = 15;
88662306a36Sopenharmony_ci		break;
88762306a36Sopenharmony_ci	case MMC_TIMING_UHS_SDR104:
88862306a36Sopenharmony_ci	case MMC_TIMING_MMC_HS200:
88962306a36Sopenharmony_ci		/* For 200MHz clock, 8 Taps are available */
89062306a36Sopenharmony_ci		tap_max = 8;
89162306a36Sopenharmony_ci		break;
89262306a36Sopenharmony_ci	default:
89362306a36Sopenharmony_ci		break;
89462306a36Sopenharmony_ci	}
89562306a36Sopenharmony_ci
89662306a36Sopenharmony_ci	tap_delay = (degrees * tap_max) / 360;
89762306a36Sopenharmony_ci
89862306a36Sopenharmony_ci	/* Set the Clock Phase */
89962306a36Sopenharmony_ci	if (tap_delay) {
90062306a36Sopenharmony_ci		u32 regval;
90162306a36Sopenharmony_ci
90262306a36Sopenharmony_ci		regval = sdhci_readl(host, SDHCI_ARASAN_OTAPDLY_REGISTER);
90362306a36Sopenharmony_ci		regval |= SDHCI_OTAPDLY_ENABLE;
90462306a36Sopenharmony_ci		sdhci_writel(host, regval, SDHCI_ARASAN_OTAPDLY_REGISTER);
90562306a36Sopenharmony_ci		regval &= ~SDHCI_ARASAN_OTAPDLY_SEL_MASK;
90662306a36Sopenharmony_ci		regval |= tap_delay;
90762306a36Sopenharmony_ci		sdhci_writel(host, regval, SDHCI_ARASAN_OTAPDLY_REGISTER);
90862306a36Sopenharmony_ci	}
90962306a36Sopenharmony_ci
91062306a36Sopenharmony_ci	return 0;
91162306a36Sopenharmony_ci}
91262306a36Sopenharmony_ci
91362306a36Sopenharmony_cistatic const struct clk_ops versal_sdcardclk_ops = {
91462306a36Sopenharmony_ci	.recalc_rate = sdhci_arasan_sdcardclk_recalc_rate,
91562306a36Sopenharmony_ci	.set_phase = sdhci_versal_sdcardclk_set_phase,
91662306a36Sopenharmony_ci};
91762306a36Sopenharmony_ci
91862306a36Sopenharmony_ci/**
91962306a36Sopenharmony_ci * sdhci_versal_sampleclk_set_phase - Set the SD Input Clock Tap Delays
92062306a36Sopenharmony_ci *
92162306a36Sopenharmony_ci * @hw:			Pointer to the hardware clock structure.
92262306a36Sopenharmony_ci * @degrees:		The clock phase shift between 0 - 359.
92362306a36Sopenharmony_ci *
92462306a36Sopenharmony_ci * Set the SD Input Clock Tap Delays for Input path
92562306a36Sopenharmony_ci *
92662306a36Sopenharmony_ci * Return: 0 on success and error value on error
92762306a36Sopenharmony_ci */
92862306a36Sopenharmony_cistatic int sdhci_versal_sampleclk_set_phase(struct clk_hw *hw, int degrees)
92962306a36Sopenharmony_ci{
93062306a36Sopenharmony_ci	struct sdhci_arasan_clk_data *clk_data =
93162306a36Sopenharmony_ci		container_of(hw, struct sdhci_arasan_clk_data, sampleclk_hw);
93262306a36Sopenharmony_ci	struct sdhci_arasan_data *sdhci_arasan =
93362306a36Sopenharmony_ci		container_of(clk_data, struct sdhci_arasan_data, clk_data);
93462306a36Sopenharmony_ci	struct sdhci_host *host = sdhci_arasan->host;
93562306a36Sopenharmony_ci	u8 tap_delay, tap_max = 0;
93662306a36Sopenharmony_ci
93762306a36Sopenharmony_ci	/* This is applicable for SDHCI_SPEC_300 and above */
93862306a36Sopenharmony_ci	if (host->version < SDHCI_SPEC_300)
93962306a36Sopenharmony_ci		return 0;
94062306a36Sopenharmony_ci
94162306a36Sopenharmony_ci	switch (host->timing) {
94262306a36Sopenharmony_ci	case MMC_TIMING_MMC_HS:
94362306a36Sopenharmony_ci	case MMC_TIMING_SD_HS:
94462306a36Sopenharmony_ci	case MMC_TIMING_UHS_SDR25:
94562306a36Sopenharmony_ci	case MMC_TIMING_UHS_DDR50:
94662306a36Sopenharmony_ci	case MMC_TIMING_MMC_DDR52:
94762306a36Sopenharmony_ci		/* For 50MHz clock, 120 Taps are available */
94862306a36Sopenharmony_ci		tap_max = 120;
94962306a36Sopenharmony_ci		break;
95062306a36Sopenharmony_ci	case MMC_TIMING_UHS_SDR50:
95162306a36Sopenharmony_ci		/* For 100MHz clock, 60 Taps are available */
95262306a36Sopenharmony_ci		tap_max = 60;
95362306a36Sopenharmony_ci		break;
95462306a36Sopenharmony_ci	case MMC_TIMING_UHS_SDR104:
95562306a36Sopenharmony_ci	case MMC_TIMING_MMC_HS200:
95662306a36Sopenharmony_ci		/* For 200MHz clock, 30 Taps are available */
95762306a36Sopenharmony_ci		tap_max = 30;
95862306a36Sopenharmony_ci		break;
95962306a36Sopenharmony_ci	default:
96062306a36Sopenharmony_ci		break;
96162306a36Sopenharmony_ci	}
96262306a36Sopenharmony_ci
96362306a36Sopenharmony_ci	tap_delay = (degrees * tap_max) / 360;
96462306a36Sopenharmony_ci
96562306a36Sopenharmony_ci	/* Set the Clock Phase */
96662306a36Sopenharmony_ci	if (tap_delay) {
96762306a36Sopenharmony_ci		u32 regval;
96862306a36Sopenharmony_ci
96962306a36Sopenharmony_ci		regval = sdhci_readl(host, SDHCI_ARASAN_ITAPDLY_REGISTER);
97062306a36Sopenharmony_ci		regval |= SDHCI_ITAPDLY_CHGWIN;
97162306a36Sopenharmony_ci		sdhci_writel(host, regval, SDHCI_ARASAN_ITAPDLY_REGISTER);
97262306a36Sopenharmony_ci		regval |= SDHCI_ITAPDLY_ENABLE;
97362306a36Sopenharmony_ci		sdhci_writel(host, regval, SDHCI_ARASAN_ITAPDLY_REGISTER);
97462306a36Sopenharmony_ci		regval &= ~SDHCI_ARASAN_ITAPDLY_SEL_MASK;
97562306a36Sopenharmony_ci		regval |= tap_delay;
97662306a36Sopenharmony_ci		sdhci_writel(host, regval, SDHCI_ARASAN_ITAPDLY_REGISTER);
97762306a36Sopenharmony_ci		regval &= ~SDHCI_ITAPDLY_CHGWIN;
97862306a36Sopenharmony_ci		sdhci_writel(host, regval, SDHCI_ARASAN_ITAPDLY_REGISTER);
97962306a36Sopenharmony_ci	}
98062306a36Sopenharmony_ci
98162306a36Sopenharmony_ci	return 0;
98262306a36Sopenharmony_ci}
98362306a36Sopenharmony_ci
98462306a36Sopenharmony_cistatic const struct clk_ops versal_sampleclk_ops = {
98562306a36Sopenharmony_ci	.recalc_rate = sdhci_arasan_sampleclk_recalc_rate,
98662306a36Sopenharmony_ci	.set_phase = sdhci_versal_sampleclk_set_phase,
98762306a36Sopenharmony_ci};
98862306a36Sopenharmony_ci
98962306a36Sopenharmony_cistatic int sdhci_versal_net_emmc_sdcardclk_set_phase(struct clk_hw *hw, int degrees)
99062306a36Sopenharmony_ci{
99162306a36Sopenharmony_ci	struct sdhci_arasan_clk_data *clk_data =
99262306a36Sopenharmony_ci		container_of(hw, struct sdhci_arasan_clk_data, sdcardclk_hw);
99362306a36Sopenharmony_ci	struct sdhci_arasan_data *sdhci_arasan =
99462306a36Sopenharmony_ci		container_of(clk_data, struct sdhci_arasan_data, clk_data);
99562306a36Sopenharmony_ci	struct sdhci_host *host = sdhci_arasan->host;
99662306a36Sopenharmony_ci	u8 tap_delay, tap_max = 0;
99762306a36Sopenharmony_ci
99862306a36Sopenharmony_ci	switch (host->timing) {
99962306a36Sopenharmony_ci	case MMC_TIMING_MMC_HS:
100062306a36Sopenharmony_ci	case MMC_TIMING_MMC_DDR52:
100162306a36Sopenharmony_ci		tap_max = 16;
100262306a36Sopenharmony_ci		break;
100362306a36Sopenharmony_ci	case MMC_TIMING_MMC_HS200:
100462306a36Sopenharmony_ci	case MMC_TIMING_MMC_HS400:
100562306a36Sopenharmony_ci		 /* For 200MHz clock, 32 Taps are available */
100662306a36Sopenharmony_ci		tap_max = 32;
100762306a36Sopenharmony_ci		break;
100862306a36Sopenharmony_ci	default:
100962306a36Sopenharmony_ci		break;
101062306a36Sopenharmony_ci	}
101162306a36Sopenharmony_ci
101262306a36Sopenharmony_ci	tap_delay = (degrees * tap_max) / 360;
101362306a36Sopenharmony_ci
101462306a36Sopenharmony_ci	/* Set the Clock Phase */
101562306a36Sopenharmony_ci	if (tap_delay) {
101662306a36Sopenharmony_ci		u32 regval;
101762306a36Sopenharmony_ci
101862306a36Sopenharmony_ci		regval = sdhci_readl(host, PHY_CTRL_REG1);
101962306a36Sopenharmony_ci		regval |= PHY_CTRL_OTAPDLY_ENA_MASK;
102062306a36Sopenharmony_ci		sdhci_writel(host, regval, PHY_CTRL_REG1);
102162306a36Sopenharmony_ci		regval &= ~PHY_CTRL_OTAPDLY_SEL_MASK;
102262306a36Sopenharmony_ci		regval |= tap_delay << PHY_CTRL_OTAPDLY_SEL_SHIFT;
102362306a36Sopenharmony_ci		sdhci_writel(host, regval, PHY_CTRL_REG1);
102462306a36Sopenharmony_ci	}
102562306a36Sopenharmony_ci
102662306a36Sopenharmony_ci	return 0;
102762306a36Sopenharmony_ci}
102862306a36Sopenharmony_ci
102962306a36Sopenharmony_cistatic const struct clk_ops versal_net_sdcardclk_ops = {
103062306a36Sopenharmony_ci	.recalc_rate = sdhci_arasan_sdcardclk_recalc_rate,
103162306a36Sopenharmony_ci	.set_phase = sdhci_versal_net_emmc_sdcardclk_set_phase,
103262306a36Sopenharmony_ci};
103362306a36Sopenharmony_ci
103462306a36Sopenharmony_cistatic int sdhci_versal_net_emmc_sampleclk_set_phase(struct clk_hw *hw, int degrees)
103562306a36Sopenharmony_ci{
103662306a36Sopenharmony_ci	struct sdhci_arasan_clk_data *clk_data =
103762306a36Sopenharmony_ci		container_of(hw, struct sdhci_arasan_clk_data, sampleclk_hw);
103862306a36Sopenharmony_ci	struct sdhci_arasan_data *sdhci_arasan =
103962306a36Sopenharmony_ci		container_of(clk_data, struct sdhci_arasan_data, clk_data);
104062306a36Sopenharmony_ci	struct sdhci_host *host = sdhci_arasan->host;
104162306a36Sopenharmony_ci	u8 tap_delay, tap_max = 0;
104262306a36Sopenharmony_ci	u32 regval;
104362306a36Sopenharmony_ci
104462306a36Sopenharmony_ci	switch (host->timing) {
104562306a36Sopenharmony_ci	case MMC_TIMING_MMC_HS:
104662306a36Sopenharmony_ci	case MMC_TIMING_MMC_DDR52:
104762306a36Sopenharmony_ci		tap_max = 32;
104862306a36Sopenharmony_ci		break;
104962306a36Sopenharmony_ci	case MMC_TIMING_MMC_HS400:
105062306a36Sopenharmony_ci		/* Strobe select tap point for strb90 and strb180 */
105162306a36Sopenharmony_ci		regval = sdhci_readl(host, PHY_CTRL_REG1);
105262306a36Sopenharmony_ci		regval &= ~PHY_CTRL_STRB_SEL_MASK;
105362306a36Sopenharmony_ci		regval |= VERSAL_NET_PHY_CTRL_STRB90_STRB180_VAL << PHY_CTRL_STRB_SEL_SHIFT;
105462306a36Sopenharmony_ci		sdhci_writel(host, regval, PHY_CTRL_REG1);
105562306a36Sopenharmony_ci		break;
105662306a36Sopenharmony_ci	default:
105762306a36Sopenharmony_ci		break;
105862306a36Sopenharmony_ci	}
105962306a36Sopenharmony_ci
106062306a36Sopenharmony_ci	tap_delay = (degrees * tap_max) / 360;
106162306a36Sopenharmony_ci
106262306a36Sopenharmony_ci	/* Set the Clock Phase */
106362306a36Sopenharmony_ci	if (tap_delay) {
106462306a36Sopenharmony_ci		regval = sdhci_readl(host, PHY_CTRL_REG1);
106562306a36Sopenharmony_ci		regval |= PHY_CTRL_ITAP_CHG_WIN_MASK;
106662306a36Sopenharmony_ci		sdhci_writel(host, regval, PHY_CTRL_REG1);
106762306a36Sopenharmony_ci		regval |= PHY_CTRL_ITAPDLY_ENA_MASK;
106862306a36Sopenharmony_ci		sdhci_writel(host, regval, PHY_CTRL_REG1);
106962306a36Sopenharmony_ci		regval &= ~PHY_CTRL_ITAPDLY_SEL_MASK;
107062306a36Sopenharmony_ci		regval |= tap_delay << PHY_CTRL_ITAPDLY_SEL_SHIFT;
107162306a36Sopenharmony_ci		sdhci_writel(host, regval, PHY_CTRL_REG1);
107262306a36Sopenharmony_ci		regval &= ~PHY_CTRL_ITAP_CHG_WIN_MASK;
107362306a36Sopenharmony_ci		sdhci_writel(host, regval, PHY_CTRL_REG1);
107462306a36Sopenharmony_ci	}
107562306a36Sopenharmony_ci
107662306a36Sopenharmony_ci	return 0;
107762306a36Sopenharmony_ci}
107862306a36Sopenharmony_ci
107962306a36Sopenharmony_cistatic const struct clk_ops versal_net_sampleclk_ops = {
108062306a36Sopenharmony_ci	.recalc_rate = sdhci_arasan_sampleclk_recalc_rate,
108162306a36Sopenharmony_ci	.set_phase = sdhci_versal_net_emmc_sampleclk_set_phase,
108262306a36Sopenharmony_ci};
108362306a36Sopenharmony_ci
108462306a36Sopenharmony_cistatic void arasan_zynqmp_dll_reset(struct sdhci_host *host, u32 deviceid)
108562306a36Sopenharmony_ci{
108662306a36Sopenharmony_ci	u16 clk;
108762306a36Sopenharmony_ci
108862306a36Sopenharmony_ci	clk = sdhci_readw(host, SDHCI_CLOCK_CONTROL);
108962306a36Sopenharmony_ci	clk &= ~(SDHCI_CLOCK_CARD_EN | SDHCI_CLOCK_INT_EN);
109062306a36Sopenharmony_ci	sdhci_writew(host, clk, SDHCI_CLOCK_CONTROL);
109162306a36Sopenharmony_ci
109262306a36Sopenharmony_ci	/* Issue DLL Reset */
109362306a36Sopenharmony_ci	zynqmp_pm_sd_dll_reset(deviceid, PM_DLL_RESET_PULSE);
109462306a36Sopenharmony_ci
109562306a36Sopenharmony_ci	clk = sdhci_readw(host, SDHCI_CLOCK_CONTROL);
109662306a36Sopenharmony_ci
109762306a36Sopenharmony_ci	sdhci_enable_clk(host, clk);
109862306a36Sopenharmony_ci}
109962306a36Sopenharmony_ci
110062306a36Sopenharmony_cistatic int arasan_zynqmp_execute_tuning(struct mmc_host *mmc, u32 opcode)
110162306a36Sopenharmony_ci{
110262306a36Sopenharmony_ci	struct sdhci_host *host = mmc_priv(mmc);
110362306a36Sopenharmony_ci	struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
110462306a36Sopenharmony_ci	struct sdhci_arasan_data *sdhci_arasan = sdhci_pltfm_priv(pltfm_host);
110562306a36Sopenharmony_ci	struct clk_hw *hw = &sdhci_arasan->clk_data.sdcardclk_hw;
110662306a36Sopenharmony_ci	const char *clk_name = clk_hw_get_name(hw);
110762306a36Sopenharmony_ci	u32 device_id = !strcmp(clk_name, "clk_out_sd0") ? NODE_SD_0 :
110862306a36Sopenharmony_ci							   NODE_SD_1;
110962306a36Sopenharmony_ci	int err;
111062306a36Sopenharmony_ci
111162306a36Sopenharmony_ci	/* ZynqMP SD controller does not perform auto tuning in DDR50 mode */
111262306a36Sopenharmony_ci	if (mmc->ios.timing == MMC_TIMING_UHS_DDR50)
111362306a36Sopenharmony_ci		return 0;
111462306a36Sopenharmony_ci
111562306a36Sopenharmony_ci	arasan_zynqmp_dll_reset(host, device_id);
111662306a36Sopenharmony_ci
111762306a36Sopenharmony_ci	err = sdhci_execute_tuning(mmc, opcode);
111862306a36Sopenharmony_ci	if (err)
111962306a36Sopenharmony_ci		return err;
112062306a36Sopenharmony_ci
112162306a36Sopenharmony_ci	arasan_zynqmp_dll_reset(host, device_id);
112262306a36Sopenharmony_ci
112362306a36Sopenharmony_ci	return 0;
112462306a36Sopenharmony_ci}
112562306a36Sopenharmony_ci
112662306a36Sopenharmony_ci/**
112762306a36Sopenharmony_ci * sdhci_arasan_update_clockmultiplier - Set corecfg_clockmultiplier
112862306a36Sopenharmony_ci *
112962306a36Sopenharmony_ci * @host:		The sdhci_host
113062306a36Sopenharmony_ci * @value:		The value to write
113162306a36Sopenharmony_ci *
113262306a36Sopenharmony_ci * The corecfg_clockmultiplier is supposed to contain clock multiplier
113362306a36Sopenharmony_ci * value of programmable clock generator.
113462306a36Sopenharmony_ci *
113562306a36Sopenharmony_ci * NOTES:
113662306a36Sopenharmony_ci * - Many existing devices don't seem to do this and work fine.  To keep
113762306a36Sopenharmony_ci *   compatibility for old hardware where the device tree doesn't provide a
113862306a36Sopenharmony_ci *   register map, this function is a noop if a soc_ctl_map hasn't been provided
113962306a36Sopenharmony_ci *   for this platform.
114062306a36Sopenharmony_ci * - The value of corecfg_clockmultiplier should sync with that of corresponding
114162306a36Sopenharmony_ci *   value reading from sdhci_capability_register. So this function is called
114262306a36Sopenharmony_ci *   once at probe time and never called again.
114362306a36Sopenharmony_ci */
114462306a36Sopenharmony_cistatic void sdhci_arasan_update_clockmultiplier(struct sdhci_host *host,
114562306a36Sopenharmony_ci						u32 value)
114662306a36Sopenharmony_ci{
114762306a36Sopenharmony_ci	struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
114862306a36Sopenharmony_ci	struct sdhci_arasan_data *sdhci_arasan = sdhci_pltfm_priv(pltfm_host);
114962306a36Sopenharmony_ci	const struct sdhci_arasan_soc_ctl_map *soc_ctl_map =
115062306a36Sopenharmony_ci		sdhci_arasan->soc_ctl_map;
115162306a36Sopenharmony_ci
115262306a36Sopenharmony_ci	/* Having a map is optional */
115362306a36Sopenharmony_ci	if (!soc_ctl_map)
115462306a36Sopenharmony_ci		return;
115562306a36Sopenharmony_ci
115662306a36Sopenharmony_ci	/* If we have a map, we expect to have a syscon */
115762306a36Sopenharmony_ci	if (!sdhci_arasan->soc_ctl_base) {
115862306a36Sopenharmony_ci		pr_warn("%s: Have regmap, but no soc-ctl-syscon\n",
115962306a36Sopenharmony_ci			mmc_hostname(host->mmc));
116062306a36Sopenharmony_ci		return;
116162306a36Sopenharmony_ci	}
116262306a36Sopenharmony_ci
116362306a36Sopenharmony_ci	sdhci_arasan_syscon_write(host, &soc_ctl_map->clockmultiplier, value);
116462306a36Sopenharmony_ci}
116562306a36Sopenharmony_ci
116662306a36Sopenharmony_ci/**
116762306a36Sopenharmony_ci * sdhci_arasan_update_baseclkfreq - Set corecfg_baseclkfreq
116862306a36Sopenharmony_ci *
116962306a36Sopenharmony_ci * @host:		The sdhci_host
117062306a36Sopenharmony_ci *
117162306a36Sopenharmony_ci * The corecfg_baseclkfreq is supposed to contain the MHz of clk_xin.  This
117262306a36Sopenharmony_ci * function can be used to make that happen.
117362306a36Sopenharmony_ci *
117462306a36Sopenharmony_ci * NOTES:
117562306a36Sopenharmony_ci * - Many existing devices don't seem to do this and work fine.  To keep
117662306a36Sopenharmony_ci *   compatibility for old hardware where the device tree doesn't provide a
117762306a36Sopenharmony_ci *   register map, this function is a noop if a soc_ctl_map hasn't been provided
117862306a36Sopenharmony_ci *   for this platform.
117962306a36Sopenharmony_ci * - It's assumed that clk_xin is not dynamic and that we use the SDHCI divider
118062306a36Sopenharmony_ci *   to achieve lower clock rates.  That means that this function is called once
118162306a36Sopenharmony_ci *   at probe time and never called again.
118262306a36Sopenharmony_ci */
118362306a36Sopenharmony_cistatic void sdhci_arasan_update_baseclkfreq(struct sdhci_host *host)
118462306a36Sopenharmony_ci{
118562306a36Sopenharmony_ci	struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
118662306a36Sopenharmony_ci	struct sdhci_arasan_data *sdhci_arasan = sdhci_pltfm_priv(pltfm_host);
118762306a36Sopenharmony_ci	const struct sdhci_arasan_soc_ctl_map *soc_ctl_map =
118862306a36Sopenharmony_ci		sdhci_arasan->soc_ctl_map;
118962306a36Sopenharmony_ci	u32 mhz = DIV_ROUND_CLOSEST_ULL(clk_get_rate(pltfm_host->clk), 1000000);
119062306a36Sopenharmony_ci
119162306a36Sopenharmony_ci	/* Having a map is optional */
119262306a36Sopenharmony_ci	if (!soc_ctl_map)
119362306a36Sopenharmony_ci		return;
119462306a36Sopenharmony_ci
119562306a36Sopenharmony_ci	/* If we have a map, we expect to have a syscon */
119662306a36Sopenharmony_ci	if (!sdhci_arasan->soc_ctl_base) {
119762306a36Sopenharmony_ci		pr_warn("%s: Have regmap, but no soc-ctl-syscon\n",
119862306a36Sopenharmony_ci			mmc_hostname(host->mmc));
119962306a36Sopenharmony_ci		return;
120062306a36Sopenharmony_ci	}
120162306a36Sopenharmony_ci
120262306a36Sopenharmony_ci	sdhci_arasan_syscon_write(host, &soc_ctl_map->baseclkfreq, mhz);
120362306a36Sopenharmony_ci}
120462306a36Sopenharmony_ci
120562306a36Sopenharmony_cistatic void sdhci_arasan_set_clk_delays(struct sdhci_host *host)
120662306a36Sopenharmony_ci{
120762306a36Sopenharmony_ci	struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
120862306a36Sopenharmony_ci	struct sdhci_arasan_data *sdhci_arasan = sdhci_pltfm_priv(pltfm_host);
120962306a36Sopenharmony_ci	struct sdhci_arasan_clk_data *clk_data = &sdhci_arasan->clk_data;
121062306a36Sopenharmony_ci
121162306a36Sopenharmony_ci	clk_set_phase(clk_data->sampleclk,
121262306a36Sopenharmony_ci		      clk_data->clk_phase_in[host->timing]);
121362306a36Sopenharmony_ci	clk_set_phase(clk_data->sdcardclk,
121462306a36Sopenharmony_ci		      clk_data->clk_phase_out[host->timing]);
121562306a36Sopenharmony_ci}
121662306a36Sopenharmony_ci
121762306a36Sopenharmony_cistatic void arasan_dt_read_clk_phase(struct device *dev,
121862306a36Sopenharmony_ci				     struct sdhci_arasan_clk_data *clk_data,
121962306a36Sopenharmony_ci				     unsigned int timing, const char *prop)
122062306a36Sopenharmony_ci{
122162306a36Sopenharmony_ci	struct device_node *np = dev->of_node;
122262306a36Sopenharmony_ci
122362306a36Sopenharmony_ci	u32 clk_phase[2] = {0};
122462306a36Sopenharmony_ci	int ret;
122562306a36Sopenharmony_ci
122662306a36Sopenharmony_ci	/*
122762306a36Sopenharmony_ci	 * Read Tap Delay values from DT, if the DT does not contain the
122862306a36Sopenharmony_ci	 * Tap Values then use the pre-defined values.
122962306a36Sopenharmony_ci	 */
123062306a36Sopenharmony_ci	ret = of_property_read_variable_u32_array(np, prop, &clk_phase[0],
123162306a36Sopenharmony_ci						  2, 0);
123262306a36Sopenharmony_ci	if (ret < 0) {
123362306a36Sopenharmony_ci		dev_dbg(dev, "Using predefined clock phase for %s = %d %d\n",
123462306a36Sopenharmony_ci			prop, clk_data->clk_phase_in[timing],
123562306a36Sopenharmony_ci			clk_data->clk_phase_out[timing]);
123662306a36Sopenharmony_ci		return;
123762306a36Sopenharmony_ci	}
123862306a36Sopenharmony_ci
123962306a36Sopenharmony_ci	/* The values read are Input and Output Clock Delays in order */
124062306a36Sopenharmony_ci	clk_data->clk_phase_in[timing] = clk_phase[0];
124162306a36Sopenharmony_ci	clk_data->clk_phase_out[timing] = clk_phase[1];
124262306a36Sopenharmony_ci}
124362306a36Sopenharmony_ci
124462306a36Sopenharmony_ci/**
124562306a36Sopenharmony_ci * arasan_dt_parse_clk_phases - Read Clock Delay values from DT
124662306a36Sopenharmony_ci *
124762306a36Sopenharmony_ci * @dev:		Pointer to our struct device.
124862306a36Sopenharmony_ci * @clk_data:		Pointer to the Clock Data structure
124962306a36Sopenharmony_ci *
125062306a36Sopenharmony_ci * Called at initialization to parse the values of Clock Delays.
125162306a36Sopenharmony_ci */
125262306a36Sopenharmony_cistatic void arasan_dt_parse_clk_phases(struct device *dev,
125362306a36Sopenharmony_ci				       struct sdhci_arasan_clk_data *clk_data)
125462306a36Sopenharmony_ci{
125562306a36Sopenharmony_ci	u32 mio_bank = 0;
125662306a36Sopenharmony_ci	int i;
125762306a36Sopenharmony_ci
125862306a36Sopenharmony_ci	/*
125962306a36Sopenharmony_ci	 * This has been kept as a pointer and is assigned a function here.
126062306a36Sopenharmony_ci	 * So that different controller variants can assign their own handling
126162306a36Sopenharmony_ci	 * function.
126262306a36Sopenharmony_ci	 */
126362306a36Sopenharmony_ci	clk_data->set_clk_delays = sdhci_arasan_set_clk_delays;
126462306a36Sopenharmony_ci
126562306a36Sopenharmony_ci	if (of_device_is_compatible(dev->of_node, "xlnx,zynqmp-8.9a")) {
126662306a36Sopenharmony_ci		u32 zynqmp_iclk_phase[MMC_TIMING_MMC_HS400 + 1] =
126762306a36Sopenharmony_ci			ZYNQMP_ICLK_PHASE;
126862306a36Sopenharmony_ci		u32 zynqmp_oclk_phase[MMC_TIMING_MMC_HS400 + 1] =
126962306a36Sopenharmony_ci			ZYNQMP_OCLK_PHASE;
127062306a36Sopenharmony_ci
127162306a36Sopenharmony_ci		of_property_read_u32(dev->of_node, "xlnx,mio-bank", &mio_bank);
127262306a36Sopenharmony_ci		if (mio_bank == 2) {
127362306a36Sopenharmony_ci			zynqmp_oclk_phase[MMC_TIMING_UHS_SDR104] = 90;
127462306a36Sopenharmony_ci			zynqmp_oclk_phase[MMC_TIMING_MMC_HS200] = 90;
127562306a36Sopenharmony_ci		}
127662306a36Sopenharmony_ci
127762306a36Sopenharmony_ci		for (i = 0; i <= MMC_TIMING_MMC_HS400; i++) {
127862306a36Sopenharmony_ci			clk_data->clk_phase_in[i] = zynqmp_iclk_phase[i];
127962306a36Sopenharmony_ci			clk_data->clk_phase_out[i] = zynqmp_oclk_phase[i];
128062306a36Sopenharmony_ci		}
128162306a36Sopenharmony_ci	}
128262306a36Sopenharmony_ci
128362306a36Sopenharmony_ci	if (of_device_is_compatible(dev->of_node, "xlnx,versal-8.9a")) {
128462306a36Sopenharmony_ci		u32 versal_iclk_phase[MMC_TIMING_MMC_HS400 + 1] =
128562306a36Sopenharmony_ci			VERSAL_ICLK_PHASE;
128662306a36Sopenharmony_ci		u32 versal_oclk_phase[MMC_TIMING_MMC_HS400 + 1] =
128762306a36Sopenharmony_ci			VERSAL_OCLK_PHASE;
128862306a36Sopenharmony_ci
128962306a36Sopenharmony_ci		for (i = 0; i <= MMC_TIMING_MMC_HS400; i++) {
129062306a36Sopenharmony_ci			clk_data->clk_phase_in[i] = versal_iclk_phase[i];
129162306a36Sopenharmony_ci			clk_data->clk_phase_out[i] = versal_oclk_phase[i];
129262306a36Sopenharmony_ci		}
129362306a36Sopenharmony_ci	}
129462306a36Sopenharmony_ci	if (of_device_is_compatible(dev->of_node, "xlnx,versal-net-emmc")) {
129562306a36Sopenharmony_ci		u32 versal_net_iclk_phase[MMC_TIMING_MMC_HS400 + 1] =
129662306a36Sopenharmony_ci			VERSAL_NET_EMMC_ICLK_PHASE;
129762306a36Sopenharmony_ci		u32 versal_net_oclk_phase[MMC_TIMING_MMC_HS400 + 1] =
129862306a36Sopenharmony_ci			VERSAL_NET_EMMC_OCLK_PHASE;
129962306a36Sopenharmony_ci
130062306a36Sopenharmony_ci		for (i = 0; i <= MMC_TIMING_MMC_HS400; i++) {
130162306a36Sopenharmony_ci			clk_data->clk_phase_in[i] = versal_net_iclk_phase[i];
130262306a36Sopenharmony_ci			clk_data->clk_phase_out[i] = versal_net_oclk_phase[i];
130362306a36Sopenharmony_ci		}
130462306a36Sopenharmony_ci	}
130562306a36Sopenharmony_ci	arasan_dt_read_clk_phase(dev, clk_data, MMC_TIMING_LEGACY,
130662306a36Sopenharmony_ci				 "clk-phase-legacy");
130762306a36Sopenharmony_ci	arasan_dt_read_clk_phase(dev, clk_data, MMC_TIMING_MMC_HS,
130862306a36Sopenharmony_ci				 "clk-phase-mmc-hs");
130962306a36Sopenharmony_ci	arasan_dt_read_clk_phase(dev, clk_data, MMC_TIMING_SD_HS,
131062306a36Sopenharmony_ci				 "clk-phase-sd-hs");
131162306a36Sopenharmony_ci	arasan_dt_read_clk_phase(dev, clk_data, MMC_TIMING_UHS_SDR12,
131262306a36Sopenharmony_ci				 "clk-phase-uhs-sdr12");
131362306a36Sopenharmony_ci	arasan_dt_read_clk_phase(dev, clk_data, MMC_TIMING_UHS_SDR25,
131462306a36Sopenharmony_ci				 "clk-phase-uhs-sdr25");
131562306a36Sopenharmony_ci	arasan_dt_read_clk_phase(dev, clk_data, MMC_TIMING_UHS_SDR50,
131662306a36Sopenharmony_ci				 "clk-phase-uhs-sdr50");
131762306a36Sopenharmony_ci	arasan_dt_read_clk_phase(dev, clk_data, MMC_TIMING_UHS_SDR104,
131862306a36Sopenharmony_ci				 "clk-phase-uhs-sdr104");
131962306a36Sopenharmony_ci	arasan_dt_read_clk_phase(dev, clk_data, MMC_TIMING_UHS_DDR50,
132062306a36Sopenharmony_ci				 "clk-phase-uhs-ddr50");
132162306a36Sopenharmony_ci	arasan_dt_read_clk_phase(dev, clk_data, MMC_TIMING_MMC_DDR52,
132262306a36Sopenharmony_ci				 "clk-phase-mmc-ddr52");
132362306a36Sopenharmony_ci	arasan_dt_read_clk_phase(dev, clk_data, MMC_TIMING_MMC_HS200,
132462306a36Sopenharmony_ci				 "clk-phase-mmc-hs200");
132562306a36Sopenharmony_ci	arasan_dt_read_clk_phase(dev, clk_data, MMC_TIMING_MMC_HS400,
132662306a36Sopenharmony_ci				 "clk-phase-mmc-hs400");
132762306a36Sopenharmony_ci}
132862306a36Sopenharmony_ci
132962306a36Sopenharmony_cistatic const struct sdhci_pltfm_data sdhci_arasan_pdata = {
133062306a36Sopenharmony_ci	.ops = &sdhci_arasan_ops,
133162306a36Sopenharmony_ci	.quirks = SDHCI_QUIRK_CAP_CLOCK_BASE_BROKEN,
133262306a36Sopenharmony_ci	.quirks2 = SDHCI_QUIRK2_PRESET_VALUE_BROKEN |
133362306a36Sopenharmony_ci			SDHCI_QUIRK2_CLOCK_DIV_ZERO_BROKEN |
133462306a36Sopenharmony_ci			SDHCI_QUIRK2_STOP_WITH_TC,
133562306a36Sopenharmony_ci};
133662306a36Sopenharmony_ci
133762306a36Sopenharmony_cistatic const struct sdhci_arasan_clk_ops arasan_clk_ops = {
133862306a36Sopenharmony_ci	.sdcardclk_ops = &arasan_sdcardclk_ops,
133962306a36Sopenharmony_ci	.sampleclk_ops = &arasan_sampleclk_ops,
134062306a36Sopenharmony_ci};
134162306a36Sopenharmony_ci
134262306a36Sopenharmony_cistatic struct sdhci_arasan_of_data sdhci_arasan_generic_data = {
134362306a36Sopenharmony_ci	.pdata = &sdhci_arasan_pdata,
134462306a36Sopenharmony_ci	.clk_ops = &arasan_clk_ops,
134562306a36Sopenharmony_ci};
134662306a36Sopenharmony_ci
134762306a36Sopenharmony_cistatic const struct sdhci_pltfm_data sdhci_keembay_emmc_pdata = {
134862306a36Sopenharmony_ci	.ops = &sdhci_arasan_cqe_ops,
134962306a36Sopenharmony_ci	.quirks = SDHCI_QUIRK_CAP_CLOCK_BASE_BROKEN |
135062306a36Sopenharmony_ci		SDHCI_QUIRK_NO_ENDATTR_IN_NOPDESC |
135162306a36Sopenharmony_ci		SDHCI_QUIRK_NO_LED |
135262306a36Sopenharmony_ci		SDHCI_QUIRK_32BIT_DMA_ADDR |
135362306a36Sopenharmony_ci		SDHCI_QUIRK_32BIT_DMA_SIZE |
135462306a36Sopenharmony_ci		SDHCI_QUIRK_32BIT_ADMA_SIZE,
135562306a36Sopenharmony_ci	.quirks2 = SDHCI_QUIRK2_PRESET_VALUE_BROKEN |
135662306a36Sopenharmony_ci		SDHCI_QUIRK2_CLOCK_DIV_ZERO_BROKEN |
135762306a36Sopenharmony_ci		SDHCI_QUIRK2_CAPS_BIT63_FOR_HS400 |
135862306a36Sopenharmony_ci		SDHCI_QUIRK2_STOP_WITH_TC |
135962306a36Sopenharmony_ci		SDHCI_QUIRK2_BROKEN_64_BIT_DMA,
136062306a36Sopenharmony_ci};
136162306a36Sopenharmony_ci
136262306a36Sopenharmony_cistatic const struct sdhci_pltfm_data sdhci_keembay_sd_pdata = {
136362306a36Sopenharmony_ci	.ops = &sdhci_arasan_ops,
136462306a36Sopenharmony_ci	.quirks = SDHCI_QUIRK_CAP_CLOCK_BASE_BROKEN |
136562306a36Sopenharmony_ci		SDHCI_QUIRK_NO_ENDATTR_IN_NOPDESC |
136662306a36Sopenharmony_ci		SDHCI_QUIRK_NO_LED |
136762306a36Sopenharmony_ci		SDHCI_QUIRK_32BIT_DMA_ADDR |
136862306a36Sopenharmony_ci		SDHCI_QUIRK_32BIT_DMA_SIZE |
136962306a36Sopenharmony_ci		SDHCI_QUIRK_32BIT_ADMA_SIZE,
137062306a36Sopenharmony_ci	.quirks2 = SDHCI_QUIRK2_PRESET_VALUE_BROKEN |
137162306a36Sopenharmony_ci		SDHCI_QUIRK2_CLOCK_DIV_ZERO_BROKEN |
137262306a36Sopenharmony_ci		SDHCI_QUIRK2_CARD_ON_NEEDS_BUS_ON |
137362306a36Sopenharmony_ci		SDHCI_QUIRK2_STOP_WITH_TC |
137462306a36Sopenharmony_ci		SDHCI_QUIRK2_BROKEN_64_BIT_DMA,
137562306a36Sopenharmony_ci};
137662306a36Sopenharmony_ci
137762306a36Sopenharmony_cistatic const struct sdhci_pltfm_data sdhci_keembay_sdio_pdata = {
137862306a36Sopenharmony_ci	.ops = &sdhci_arasan_ops,
137962306a36Sopenharmony_ci	.quirks = SDHCI_QUIRK_CAP_CLOCK_BASE_BROKEN |
138062306a36Sopenharmony_ci		SDHCI_QUIRK_NO_ENDATTR_IN_NOPDESC |
138162306a36Sopenharmony_ci		SDHCI_QUIRK_NO_LED |
138262306a36Sopenharmony_ci		SDHCI_QUIRK_32BIT_DMA_ADDR |
138362306a36Sopenharmony_ci		SDHCI_QUIRK_32BIT_DMA_SIZE |
138462306a36Sopenharmony_ci		SDHCI_QUIRK_32BIT_ADMA_SIZE,
138562306a36Sopenharmony_ci	.quirks2 = SDHCI_QUIRK2_PRESET_VALUE_BROKEN |
138662306a36Sopenharmony_ci		SDHCI_QUIRK2_CLOCK_DIV_ZERO_BROKEN |
138762306a36Sopenharmony_ci		SDHCI_QUIRK2_HOST_OFF_CARD_ON |
138862306a36Sopenharmony_ci		SDHCI_QUIRK2_BROKEN_64_BIT_DMA,
138962306a36Sopenharmony_ci};
139062306a36Sopenharmony_ci
139162306a36Sopenharmony_cistatic struct sdhci_arasan_of_data sdhci_arasan_rk3399_data = {
139262306a36Sopenharmony_ci	.soc_ctl_map = &rk3399_soc_ctl_map,
139362306a36Sopenharmony_ci	.pdata = &sdhci_arasan_cqe_pdata,
139462306a36Sopenharmony_ci	.clk_ops = &arasan_clk_ops,
139562306a36Sopenharmony_ci};
139662306a36Sopenharmony_ci
139762306a36Sopenharmony_cistatic struct sdhci_arasan_of_data intel_lgm_emmc_data = {
139862306a36Sopenharmony_ci	.soc_ctl_map = &intel_lgm_emmc_soc_ctl_map,
139962306a36Sopenharmony_ci	.pdata = &sdhci_arasan_cqe_pdata,
140062306a36Sopenharmony_ci	.clk_ops = &arasan_clk_ops,
140162306a36Sopenharmony_ci};
140262306a36Sopenharmony_ci
140362306a36Sopenharmony_cistatic struct sdhci_arasan_of_data intel_lgm_sdxc_data = {
140462306a36Sopenharmony_ci	.soc_ctl_map = &intel_lgm_sdxc_soc_ctl_map,
140562306a36Sopenharmony_ci	.pdata = &sdhci_arasan_cqe_pdata,
140662306a36Sopenharmony_ci	.clk_ops = &arasan_clk_ops,
140762306a36Sopenharmony_ci};
140862306a36Sopenharmony_ci
140962306a36Sopenharmony_cistatic const struct sdhci_pltfm_data sdhci_arasan_zynqmp_pdata = {
141062306a36Sopenharmony_ci	.ops = &sdhci_arasan_ops,
141162306a36Sopenharmony_ci	.quirks2 = SDHCI_QUIRK2_PRESET_VALUE_BROKEN |
141262306a36Sopenharmony_ci			SDHCI_QUIRK2_CLOCK_DIV_ZERO_BROKEN |
141362306a36Sopenharmony_ci			SDHCI_QUIRK2_STOP_WITH_TC,
141462306a36Sopenharmony_ci};
141562306a36Sopenharmony_ci
141662306a36Sopenharmony_cistatic const struct sdhci_pltfm_data sdhci_arasan_versal_net_pdata = {
141762306a36Sopenharmony_ci	.ops = &sdhci_arasan_ops,
141862306a36Sopenharmony_ci	.quirks2 = SDHCI_QUIRK2_PRESET_VALUE_BROKEN |
141962306a36Sopenharmony_ci			SDHCI_QUIRK2_CLOCK_DIV_ZERO_BROKEN |
142062306a36Sopenharmony_ci			SDHCI_QUIRK2_STOP_WITH_TC |
142162306a36Sopenharmony_ci			SDHCI_QUIRK2_CAPS_BIT63_FOR_HS400,
142262306a36Sopenharmony_ci};
142362306a36Sopenharmony_ci
142462306a36Sopenharmony_cistatic const struct sdhci_arasan_clk_ops zynqmp_clk_ops = {
142562306a36Sopenharmony_ci	.sdcardclk_ops = &zynqmp_sdcardclk_ops,
142662306a36Sopenharmony_ci	.sampleclk_ops = &zynqmp_sampleclk_ops,
142762306a36Sopenharmony_ci};
142862306a36Sopenharmony_ci
142962306a36Sopenharmony_cistatic struct sdhci_arasan_of_data sdhci_arasan_zynqmp_data = {
143062306a36Sopenharmony_ci	.pdata = &sdhci_arasan_zynqmp_pdata,
143162306a36Sopenharmony_ci	.clk_ops = &zynqmp_clk_ops,
143262306a36Sopenharmony_ci};
143362306a36Sopenharmony_ci
143462306a36Sopenharmony_cistatic const struct sdhci_arasan_clk_ops versal_clk_ops = {
143562306a36Sopenharmony_ci	.sdcardclk_ops = &versal_sdcardclk_ops,
143662306a36Sopenharmony_ci	.sampleclk_ops = &versal_sampleclk_ops,
143762306a36Sopenharmony_ci};
143862306a36Sopenharmony_ci
143962306a36Sopenharmony_cistatic struct sdhci_arasan_of_data sdhci_arasan_versal_data = {
144062306a36Sopenharmony_ci	.pdata = &sdhci_arasan_zynqmp_pdata,
144162306a36Sopenharmony_ci	.clk_ops = &versal_clk_ops,
144262306a36Sopenharmony_ci};
144362306a36Sopenharmony_ci
144462306a36Sopenharmony_cistatic const struct sdhci_arasan_clk_ops versal_net_clk_ops = {
144562306a36Sopenharmony_ci	.sdcardclk_ops = &versal_net_sdcardclk_ops,
144662306a36Sopenharmony_ci	.sampleclk_ops = &versal_net_sampleclk_ops,
144762306a36Sopenharmony_ci};
144862306a36Sopenharmony_ci
144962306a36Sopenharmony_cistatic struct sdhci_arasan_of_data sdhci_arasan_versal_net_data = {
145062306a36Sopenharmony_ci	.pdata = &sdhci_arasan_versal_net_pdata,
145162306a36Sopenharmony_ci	.clk_ops = &versal_net_clk_ops,
145262306a36Sopenharmony_ci};
145362306a36Sopenharmony_ci
145462306a36Sopenharmony_cistatic struct sdhci_arasan_of_data intel_keembay_emmc_data = {
145562306a36Sopenharmony_ci	.soc_ctl_map = &intel_keembay_soc_ctl_map,
145662306a36Sopenharmony_ci	.pdata = &sdhci_keembay_emmc_pdata,
145762306a36Sopenharmony_ci	.clk_ops = &arasan_clk_ops,
145862306a36Sopenharmony_ci};
145962306a36Sopenharmony_ci
146062306a36Sopenharmony_cistatic struct sdhci_arasan_of_data intel_keembay_sd_data = {
146162306a36Sopenharmony_ci	.soc_ctl_map = &intel_keembay_soc_ctl_map,
146262306a36Sopenharmony_ci	.pdata = &sdhci_keembay_sd_pdata,
146362306a36Sopenharmony_ci	.clk_ops = &arasan_clk_ops,
146462306a36Sopenharmony_ci};
146562306a36Sopenharmony_ci
146662306a36Sopenharmony_cistatic struct sdhci_arasan_of_data intel_keembay_sdio_data = {
146762306a36Sopenharmony_ci	.soc_ctl_map = &intel_keembay_soc_ctl_map,
146862306a36Sopenharmony_ci	.pdata = &sdhci_keembay_sdio_pdata,
146962306a36Sopenharmony_ci	.clk_ops = &arasan_clk_ops,
147062306a36Sopenharmony_ci};
147162306a36Sopenharmony_ci
147262306a36Sopenharmony_cistatic const struct of_device_id sdhci_arasan_of_match[] = {
147362306a36Sopenharmony_ci	/* SoC-specific compatible strings w/ soc_ctl_map */
147462306a36Sopenharmony_ci	{
147562306a36Sopenharmony_ci		.compatible = "rockchip,rk3399-sdhci-5.1",
147662306a36Sopenharmony_ci		.data = &sdhci_arasan_rk3399_data,
147762306a36Sopenharmony_ci	},
147862306a36Sopenharmony_ci	{
147962306a36Sopenharmony_ci		.compatible = "intel,lgm-sdhci-5.1-emmc",
148062306a36Sopenharmony_ci		.data = &intel_lgm_emmc_data,
148162306a36Sopenharmony_ci	},
148262306a36Sopenharmony_ci	{
148362306a36Sopenharmony_ci		.compatible = "intel,lgm-sdhci-5.1-sdxc",
148462306a36Sopenharmony_ci		.data = &intel_lgm_sdxc_data,
148562306a36Sopenharmony_ci	},
148662306a36Sopenharmony_ci	{
148762306a36Sopenharmony_ci		.compatible = "intel,keembay-sdhci-5.1-emmc",
148862306a36Sopenharmony_ci		.data = &intel_keembay_emmc_data,
148962306a36Sopenharmony_ci	},
149062306a36Sopenharmony_ci	{
149162306a36Sopenharmony_ci		.compatible = "intel,keembay-sdhci-5.1-sd",
149262306a36Sopenharmony_ci		.data = &intel_keembay_sd_data,
149362306a36Sopenharmony_ci	},
149462306a36Sopenharmony_ci	{
149562306a36Sopenharmony_ci		.compatible = "intel,keembay-sdhci-5.1-sdio",
149662306a36Sopenharmony_ci		.data = &intel_keembay_sdio_data,
149762306a36Sopenharmony_ci	},
149862306a36Sopenharmony_ci	/* Generic compatible below here */
149962306a36Sopenharmony_ci	{
150062306a36Sopenharmony_ci		.compatible = "arasan,sdhci-8.9a",
150162306a36Sopenharmony_ci		.data = &sdhci_arasan_generic_data,
150262306a36Sopenharmony_ci	},
150362306a36Sopenharmony_ci	{
150462306a36Sopenharmony_ci		.compatible = "arasan,sdhci-5.1",
150562306a36Sopenharmony_ci		.data = &sdhci_arasan_generic_data,
150662306a36Sopenharmony_ci	},
150762306a36Sopenharmony_ci	{
150862306a36Sopenharmony_ci		.compatible = "arasan,sdhci-4.9a",
150962306a36Sopenharmony_ci		.data = &sdhci_arasan_generic_data,
151062306a36Sopenharmony_ci	},
151162306a36Sopenharmony_ci	{
151262306a36Sopenharmony_ci		.compatible = "xlnx,zynqmp-8.9a",
151362306a36Sopenharmony_ci		.data = &sdhci_arasan_zynqmp_data,
151462306a36Sopenharmony_ci	},
151562306a36Sopenharmony_ci	{
151662306a36Sopenharmony_ci		.compatible = "xlnx,versal-8.9a",
151762306a36Sopenharmony_ci		.data = &sdhci_arasan_versal_data,
151862306a36Sopenharmony_ci	},
151962306a36Sopenharmony_ci	{
152062306a36Sopenharmony_ci		.compatible = "xlnx,versal-net-emmc",
152162306a36Sopenharmony_ci		.data = &sdhci_arasan_versal_net_data,
152262306a36Sopenharmony_ci	},
152362306a36Sopenharmony_ci	{ /* sentinel */ }
152462306a36Sopenharmony_ci};
152562306a36Sopenharmony_ciMODULE_DEVICE_TABLE(of, sdhci_arasan_of_match);
152662306a36Sopenharmony_ci
152762306a36Sopenharmony_ci/**
152862306a36Sopenharmony_ci * sdhci_arasan_register_sdcardclk - Register the sdcardclk for a PHY to use
152962306a36Sopenharmony_ci *
153062306a36Sopenharmony_ci * @sdhci_arasan:	Our private data structure.
153162306a36Sopenharmony_ci * @clk_xin:		Pointer to the functional clock
153262306a36Sopenharmony_ci * @dev:		Pointer to our struct device.
153362306a36Sopenharmony_ci *
153462306a36Sopenharmony_ci * Some PHY devices need to know what the actual card clock is.  In order for
153562306a36Sopenharmony_ci * them to find out, we'll provide a clock through the common clock framework
153662306a36Sopenharmony_ci * for them to query.
153762306a36Sopenharmony_ci *
153862306a36Sopenharmony_ci * Return: 0 on success and error value on error
153962306a36Sopenharmony_ci */
154062306a36Sopenharmony_cistatic int
154162306a36Sopenharmony_cisdhci_arasan_register_sdcardclk(struct sdhci_arasan_data *sdhci_arasan,
154262306a36Sopenharmony_ci				struct clk *clk_xin,
154362306a36Sopenharmony_ci				struct device *dev)
154462306a36Sopenharmony_ci{
154562306a36Sopenharmony_ci	struct sdhci_arasan_clk_data *clk_data = &sdhci_arasan->clk_data;
154662306a36Sopenharmony_ci	struct device_node *np = dev->of_node;
154762306a36Sopenharmony_ci	struct clk_init_data sdcardclk_init;
154862306a36Sopenharmony_ci	const char *parent_clk_name;
154962306a36Sopenharmony_ci	int ret;
155062306a36Sopenharmony_ci
155162306a36Sopenharmony_ci	ret = of_property_read_string_index(np, "clock-output-names", 0,
155262306a36Sopenharmony_ci					    &sdcardclk_init.name);
155362306a36Sopenharmony_ci	if (ret) {
155462306a36Sopenharmony_ci		dev_err(dev, "DT has #clock-cells but no clock-output-names\n");
155562306a36Sopenharmony_ci		return ret;
155662306a36Sopenharmony_ci	}
155762306a36Sopenharmony_ci
155862306a36Sopenharmony_ci	parent_clk_name = __clk_get_name(clk_xin);
155962306a36Sopenharmony_ci	sdcardclk_init.parent_names = &parent_clk_name;
156062306a36Sopenharmony_ci	sdcardclk_init.num_parents = 1;
156162306a36Sopenharmony_ci	sdcardclk_init.flags = CLK_GET_RATE_NOCACHE;
156262306a36Sopenharmony_ci	sdcardclk_init.ops = sdhci_arasan->clk_ops->sdcardclk_ops;
156362306a36Sopenharmony_ci
156462306a36Sopenharmony_ci	clk_data->sdcardclk_hw.init = &sdcardclk_init;
156562306a36Sopenharmony_ci	clk_data->sdcardclk =
156662306a36Sopenharmony_ci		devm_clk_register(dev, &clk_data->sdcardclk_hw);
156762306a36Sopenharmony_ci	if (IS_ERR(clk_data->sdcardclk))
156862306a36Sopenharmony_ci		return PTR_ERR(clk_data->sdcardclk);
156962306a36Sopenharmony_ci	clk_data->sdcardclk_hw.init = NULL;
157062306a36Sopenharmony_ci
157162306a36Sopenharmony_ci	ret = of_clk_add_provider(np, of_clk_src_simple_get,
157262306a36Sopenharmony_ci				  clk_data->sdcardclk);
157362306a36Sopenharmony_ci	if (ret)
157462306a36Sopenharmony_ci		dev_err(dev, "Failed to add sdcard clock provider\n");
157562306a36Sopenharmony_ci
157662306a36Sopenharmony_ci	return ret;
157762306a36Sopenharmony_ci}
157862306a36Sopenharmony_ci
157962306a36Sopenharmony_ci/**
158062306a36Sopenharmony_ci * sdhci_arasan_register_sampleclk - Register the sampleclk for a PHY to use
158162306a36Sopenharmony_ci *
158262306a36Sopenharmony_ci * @sdhci_arasan:	Our private data structure.
158362306a36Sopenharmony_ci * @clk_xin:		Pointer to the functional clock
158462306a36Sopenharmony_ci * @dev:		Pointer to our struct device.
158562306a36Sopenharmony_ci *
158662306a36Sopenharmony_ci * Some PHY devices need to know what the actual card clock is.  In order for
158762306a36Sopenharmony_ci * them to find out, we'll provide a clock through the common clock framework
158862306a36Sopenharmony_ci * for them to query.
158962306a36Sopenharmony_ci *
159062306a36Sopenharmony_ci * Return: 0 on success and error value on error
159162306a36Sopenharmony_ci */
159262306a36Sopenharmony_cistatic int
159362306a36Sopenharmony_cisdhci_arasan_register_sampleclk(struct sdhci_arasan_data *sdhci_arasan,
159462306a36Sopenharmony_ci				struct clk *clk_xin,
159562306a36Sopenharmony_ci				struct device *dev)
159662306a36Sopenharmony_ci{
159762306a36Sopenharmony_ci	struct sdhci_arasan_clk_data *clk_data = &sdhci_arasan->clk_data;
159862306a36Sopenharmony_ci	struct device_node *np = dev->of_node;
159962306a36Sopenharmony_ci	struct clk_init_data sampleclk_init;
160062306a36Sopenharmony_ci	const char *parent_clk_name;
160162306a36Sopenharmony_ci	int ret;
160262306a36Sopenharmony_ci
160362306a36Sopenharmony_ci	ret = of_property_read_string_index(np, "clock-output-names", 1,
160462306a36Sopenharmony_ci					    &sampleclk_init.name);
160562306a36Sopenharmony_ci	if (ret) {
160662306a36Sopenharmony_ci		dev_err(dev, "DT has #clock-cells but no clock-output-names\n");
160762306a36Sopenharmony_ci		return ret;
160862306a36Sopenharmony_ci	}
160962306a36Sopenharmony_ci
161062306a36Sopenharmony_ci	parent_clk_name = __clk_get_name(clk_xin);
161162306a36Sopenharmony_ci	sampleclk_init.parent_names = &parent_clk_name;
161262306a36Sopenharmony_ci	sampleclk_init.num_parents = 1;
161362306a36Sopenharmony_ci	sampleclk_init.flags = CLK_GET_RATE_NOCACHE;
161462306a36Sopenharmony_ci	sampleclk_init.ops = sdhci_arasan->clk_ops->sampleclk_ops;
161562306a36Sopenharmony_ci
161662306a36Sopenharmony_ci	clk_data->sampleclk_hw.init = &sampleclk_init;
161762306a36Sopenharmony_ci	clk_data->sampleclk =
161862306a36Sopenharmony_ci		devm_clk_register(dev, &clk_data->sampleclk_hw);
161962306a36Sopenharmony_ci	if (IS_ERR(clk_data->sampleclk))
162062306a36Sopenharmony_ci		return PTR_ERR(clk_data->sampleclk);
162162306a36Sopenharmony_ci	clk_data->sampleclk_hw.init = NULL;
162262306a36Sopenharmony_ci
162362306a36Sopenharmony_ci	ret = of_clk_add_provider(np, of_clk_src_simple_get,
162462306a36Sopenharmony_ci				  clk_data->sampleclk);
162562306a36Sopenharmony_ci	if (ret)
162662306a36Sopenharmony_ci		dev_err(dev, "Failed to add sample clock provider\n");
162762306a36Sopenharmony_ci
162862306a36Sopenharmony_ci	return ret;
162962306a36Sopenharmony_ci}
163062306a36Sopenharmony_ci
163162306a36Sopenharmony_ci/**
163262306a36Sopenharmony_ci * sdhci_arasan_unregister_sdclk - Undoes sdhci_arasan_register_sdclk()
163362306a36Sopenharmony_ci *
163462306a36Sopenharmony_ci * @dev:		Pointer to our struct device.
163562306a36Sopenharmony_ci *
163662306a36Sopenharmony_ci * Should be called any time we're exiting and sdhci_arasan_register_sdclk()
163762306a36Sopenharmony_ci * returned success.
163862306a36Sopenharmony_ci */
163962306a36Sopenharmony_cistatic void sdhci_arasan_unregister_sdclk(struct device *dev)
164062306a36Sopenharmony_ci{
164162306a36Sopenharmony_ci	struct device_node *np = dev->of_node;
164262306a36Sopenharmony_ci
164362306a36Sopenharmony_ci	if (!of_property_present(np, "#clock-cells"))
164462306a36Sopenharmony_ci		return;
164562306a36Sopenharmony_ci
164662306a36Sopenharmony_ci	of_clk_del_provider(dev->of_node);
164762306a36Sopenharmony_ci}
164862306a36Sopenharmony_ci
164962306a36Sopenharmony_ci/**
165062306a36Sopenharmony_ci * sdhci_arasan_update_support64b - Set SUPPORT_64B (64-bit System Bus Support)
165162306a36Sopenharmony_ci * @host:		The sdhci_host
165262306a36Sopenharmony_ci * @value:		The value to write
165362306a36Sopenharmony_ci *
165462306a36Sopenharmony_ci * This should be set based on the System Address Bus.
165562306a36Sopenharmony_ci * 0: the Core supports only 32-bit System Address Bus.
165662306a36Sopenharmony_ci * 1: the Core supports 64-bit System Address Bus.
165762306a36Sopenharmony_ci *
165862306a36Sopenharmony_ci * NOTE:
165962306a36Sopenharmony_ci * For Keem Bay, it is required to clear this bit. Its default value is 1'b1.
166062306a36Sopenharmony_ci * Keem Bay does not support 64-bit access.
166162306a36Sopenharmony_ci */
166262306a36Sopenharmony_cistatic void sdhci_arasan_update_support64b(struct sdhci_host *host, u32 value)
166362306a36Sopenharmony_ci{
166462306a36Sopenharmony_ci	struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
166562306a36Sopenharmony_ci	struct sdhci_arasan_data *sdhci_arasan = sdhci_pltfm_priv(pltfm_host);
166662306a36Sopenharmony_ci	const struct sdhci_arasan_soc_ctl_map *soc_ctl_map;
166762306a36Sopenharmony_ci
166862306a36Sopenharmony_ci	/* Having a map is optional */
166962306a36Sopenharmony_ci	soc_ctl_map = sdhci_arasan->soc_ctl_map;
167062306a36Sopenharmony_ci	if (!soc_ctl_map)
167162306a36Sopenharmony_ci		return;
167262306a36Sopenharmony_ci
167362306a36Sopenharmony_ci	/* If we have a map, we expect to have a syscon */
167462306a36Sopenharmony_ci	if (!sdhci_arasan->soc_ctl_base) {
167562306a36Sopenharmony_ci		pr_warn("%s: Have regmap, but no soc-ctl-syscon\n",
167662306a36Sopenharmony_ci			mmc_hostname(host->mmc));
167762306a36Sopenharmony_ci		return;
167862306a36Sopenharmony_ci	}
167962306a36Sopenharmony_ci
168062306a36Sopenharmony_ci	sdhci_arasan_syscon_write(host, &soc_ctl_map->support64b, value);
168162306a36Sopenharmony_ci}
168262306a36Sopenharmony_ci
168362306a36Sopenharmony_ci/**
168462306a36Sopenharmony_ci * sdhci_arasan_register_sdclk - Register the sdcardclk for a PHY to use
168562306a36Sopenharmony_ci *
168662306a36Sopenharmony_ci * @sdhci_arasan:	Our private data structure.
168762306a36Sopenharmony_ci * @clk_xin:		Pointer to the functional clock
168862306a36Sopenharmony_ci * @dev:		Pointer to our struct device.
168962306a36Sopenharmony_ci *
169062306a36Sopenharmony_ci * Some PHY devices need to know what the actual card clock is.  In order for
169162306a36Sopenharmony_ci * them to find out, we'll provide a clock through the common clock framework
169262306a36Sopenharmony_ci * for them to query.
169362306a36Sopenharmony_ci *
169462306a36Sopenharmony_ci * Note: without seriously re-architecting SDHCI's clock code and testing on
169562306a36Sopenharmony_ci * all platforms, there's no way to create a totally beautiful clock here
169662306a36Sopenharmony_ci * with all clock ops implemented.  Instead, we'll just create a clock that can
169762306a36Sopenharmony_ci * be queried and set the CLK_GET_RATE_NOCACHE attribute to tell common clock
169862306a36Sopenharmony_ci * framework that we're doing things behind its back.  This should be sufficient
169962306a36Sopenharmony_ci * to create nice clean device tree bindings and later (if needed) we can try
170062306a36Sopenharmony_ci * re-architecting SDHCI if we see some benefit to it.
170162306a36Sopenharmony_ci *
170262306a36Sopenharmony_ci * Return: 0 on success and error value on error
170362306a36Sopenharmony_ci */
170462306a36Sopenharmony_cistatic int sdhci_arasan_register_sdclk(struct sdhci_arasan_data *sdhci_arasan,
170562306a36Sopenharmony_ci				       struct clk *clk_xin,
170662306a36Sopenharmony_ci				       struct device *dev)
170762306a36Sopenharmony_ci{
170862306a36Sopenharmony_ci	struct device_node *np = dev->of_node;
170962306a36Sopenharmony_ci	u32 num_clks = 0;
171062306a36Sopenharmony_ci	int ret;
171162306a36Sopenharmony_ci
171262306a36Sopenharmony_ci	/* Providing a clock to the PHY is optional; no error if missing */
171362306a36Sopenharmony_ci	if (of_property_read_u32(np, "#clock-cells", &num_clks) < 0)
171462306a36Sopenharmony_ci		return 0;
171562306a36Sopenharmony_ci
171662306a36Sopenharmony_ci	ret = sdhci_arasan_register_sdcardclk(sdhci_arasan, clk_xin, dev);
171762306a36Sopenharmony_ci	if (ret)
171862306a36Sopenharmony_ci		return ret;
171962306a36Sopenharmony_ci
172062306a36Sopenharmony_ci	if (num_clks) {
172162306a36Sopenharmony_ci		ret = sdhci_arasan_register_sampleclk(sdhci_arasan, clk_xin,
172262306a36Sopenharmony_ci						      dev);
172362306a36Sopenharmony_ci		if (ret) {
172462306a36Sopenharmony_ci			sdhci_arasan_unregister_sdclk(dev);
172562306a36Sopenharmony_ci			return ret;
172662306a36Sopenharmony_ci		}
172762306a36Sopenharmony_ci	}
172862306a36Sopenharmony_ci
172962306a36Sopenharmony_ci	return 0;
173062306a36Sopenharmony_ci}
173162306a36Sopenharmony_ci
173262306a36Sopenharmony_cistatic int sdhci_zynqmp_set_dynamic_config(struct device *dev,
173362306a36Sopenharmony_ci					   struct sdhci_arasan_data *sdhci_arasan)
173462306a36Sopenharmony_ci{
173562306a36Sopenharmony_ci	struct sdhci_host *host = sdhci_arasan->host;
173662306a36Sopenharmony_ci	struct clk_hw *hw = &sdhci_arasan->clk_data.sdcardclk_hw;
173762306a36Sopenharmony_ci	struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
173862306a36Sopenharmony_ci	const char *clk_name = clk_hw_get_name(hw);
173962306a36Sopenharmony_ci	u32 mhz, node_id = !strcmp(clk_name, "clk_out_sd0") ? NODE_SD_0 : NODE_SD_1;
174062306a36Sopenharmony_ci	struct reset_control *rstc;
174162306a36Sopenharmony_ci	int ret;
174262306a36Sopenharmony_ci
174362306a36Sopenharmony_ci	/* Obtain SDHC reset control */
174462306a36Sopenharmony_ci	rstc = devm_reset_control_get_optional_exclusive(dev, NULL);
174562306a36Sopenharmony_ci	if (IS_ERR(rstc)) {
174662306a36Sopenharmony_ci		dev_err(dev, "Cannot get SDHC reset.\n");
174762306a36Sopenharmony_ci		return PTR_ERR(rstc);
174862306a36Sopenharmony_ci	}
174962306a36Sopenharmony_ci
175062306a36Sopenharmony_ci	ret = reset_control_assert(rstc);
175162306a36Sopenharmony_ci	if (ret)
175262306a36Sopenharmony_ci		return ret;
175362306a36Sopenharmony_ci
175462306a36Sopenharmony_ci	ret = zynqmp_pm_set_sd_config(node_id, SD_CONFIG_FIXED, 0);
175562306a36Sopenharmony_ci	if (ret)
175662306a36Sopenharmony_ci		return ret;
175762306a36Sopenharmony_ci
175862306a36Sopenharmony_ci	ret = zynqmp_pm_set_sd_config(node_id, SD_CONFIG_EMMC_SEL,
175962306a36Sopenharmony_ci				      !!(host->mmc->caps & MMC_CAP_NONREMOVABLE));
176062306a36Sopenharmony_ci	if (ret)
176162306a36Sopenharmony_ci		return ret;
176262306a36Sopenharmony_ci
176362306a36Sopenharmony_ci	mhz = DIV_ROUND_CLOSEST_ULL(clk_get_rate(pltfm_host->clk), 1000000);
176462306a36Sopenharmony_ci	if (mhz > 100 && mhz <= 200)
176562306a36Sopenharmony_ci		mhz = 200;
176662306a36Sopenharmony_ci	else if (mhz > 50 && mhz <= 100)
176762306a36Sopenharmony_ci		mhz = 100;
176862306a36Sopenharmony_ci	else if (mhz > 25 && mhz <= 50)
176962306a36Sopenharmony_ci		mhz = 50;
177062306a36Sopenharmony_ci	else
177162306a36Sopenharmony_ci		mhz = 25;
177262306a36Sopenharmony_ci
177362306a36Sopenharmony_ci	ret = zynqmp_pm_set_sd_config(node_id, SD_CONFIG_BASECLK, mhz);
177462306a36Sopenharmony_ci	if (ret)
177562306a36Sopenharmony_ci		return ret;
177662306a36Sopenharmony_ci
177762306a36Sopenharmony_ci	ret = zynqmp_pm_set_sd_config(node_id, SD_CONFIG_8BIT,
177862306a36Sopenharmony_ci				      !!(host->mmc->caps & MMC_CAP_8_BIT_DATA));
177962306a36Sopenharmony_ci	if (ret)
178062306a36Sopenharmony_ci		return ret;
178162306a36Sopenharmony_ci
178262306a36Sopenharmony_ci	ret = reset_control_deassert(rstc);
178362306a36Sopenharmony_ci	if (ret)
178462306a36Sopenharmony_ci		return ret;
178562306a36Sopenharmony_ci
178662306a36Sopenharmony_ci	usleep_range(1000, 1500);
178762306a36Sopenharmony_ci
178862306a36Sopenharmony_ci	return 0;
178962306a36Sopenharmony_ci}
179062306a36Sopenharmony_ci
179162306a36Sopenharmony_cistatic int sdhci_arasan_add_host(struct sdhci_arasan_data *sdhci_arasan)
179262306a36Sopenharmony_ci{
179362306a36Sopenharmony_ci	struct sdhci_host *host = sdhci_arasan->host;
179462306a36Sopenharmony_ci	struct cqhci_host *cq_host;
179562306a36Sopenharmony_ci	bool dma64;
179662306a36Sopenharmony_ci	int ret;
179762306a36Sopenharmony_ci
179862306a36Sopenharmony_ci	if (!sdhci_arasan->has_cqe)
179962306a36Sopenharmony_ci		return sdhci_add_host(host);
180062306a36Sopenharmony_ci
180162306a36Sopenharmony_ci	ret = sdhci_setup_host(host);
180262306a36Sopenharmony_ci	if (ret)
180362306a36Sopenharmony_ci		return ret;
180462306a36Sopenharmony_ci
180562306a36Sopenharmony_ci	cq_host = devm_kzalloc(host->mmc->parent,
180662306a36Sopenharmony_ci			       sizeof(*cq_host), GFP_KERNEL);
180762306a36Sopenharmony_ci	if (!cq_host) {
180862306a36Sopenharmony_ci		ret = -ENOMEM;
180962306a36Sopenharmony_ci		goto cleanup;
181062306a36Sopenharmony_ci	}
181162306a36Sopenharmony_ci
181262306a36Sopenharmony_ci	cq_host->mmio = host->ioaddr + SDHCI_ARASAN_CQE_BASE_ADDR;
181362306a36Sopenharmony_ci	cq_host->ops = &sdhci_arasan_cqhci_ops;
181462306a36Sopenharmony_ci
181562306a36Sopenharmony_ci	dma64 = host->flags & SDHCI_USE_64_BIT_DMA;
181662306a36Sopenharmony_ci	if (dma64)
181762306a36Sopenharmony_ci		cq_host->caps |= CQHCI_TASK_DESC_SZ_128;
181862306a36Sopenharmony_ci
181962306a36Sopenharmony_ci	ret = cqhci_init(cq_host, host->mmc, dma64);
182062306a36Sopenharmony_ci	if (ret)
182162306a36Sopenharmony_ci		goto cleanup;
182262306a36Sopenharmony_ci
182362306a36Sopenharmony_ci	ret = __sdhci_add_host(host);
182462306a36Sopenharmony_ci	if (ret)
182562306a36Sopenharmony_ci		goto cleanup;
182662306a36Sopenharmony_ci
182762306a36Sopenharmony_ci	return 0;
182862306a36Sopenharmony_ci
182962306a36Sopenharmony_cicleanup:
183062306a36Sopenharmony_ci	sdhci_cleanup_host(host);
183162306a36Sopenharmony_ci	return ret;
183262306a36Sopenharmony_ci}
183362306a36Sopenharmony_ci
183462306a36Sopenharmony_cistatic int sdhci_arasan_probe(struct platform_device *pdev)
183562306a36Sopenharmony_ci{
183662306a36Sopenharmony_ci	int ret;
183762306a36Sopenharmony_ci	struct device_node *node;
183862306a36Sopenharmony_ci	struct clk *clk_xin;
183962306a36Sopenharmony_ci	struct clk *clk_dll;
184062306a36Sopenharmony_ci	struct sdhci_host *host;
184162306a36Sopenharmony_ci	struct sdhci_pltfm_host *pltfm_host;
184262306a36Sopenharmony_ci	struct device *dev = &pdev->dev;
184362306a36Sopenharmony_ci	struct device_node *np = dev->of_node;
184462306a36Sopenharmony_ci	struct sdhci_arasan_data *sdhci_arasan;
184562306a36Sopenharmony_ci	const struct sdhci_arasan_of_data *data;
184662306a36Sopenharmony_ci
184762306a36Sopenharmony_ci	data = of_device_get_match_data(dev);
184862306a36Sopenharmony_ci	if (!data)
184962306a36Sopenharmony_ci		return -EINVAL;
185062306a36Sopenharmony_ci
185162306a36Sopenharmony_ci	host = sdhci_pltfm_init(pdev, data->pdata, sizeof(*sdhci_arasan));
185262306a36Sopenharmony_ci
185362306a36Sopenharmony_ci	if (IS_ERR(host))
185462306a36Sopenharmony_ci		return PTR_ERR(host);
185562306a36Sopenharmony_ci
185662306a36Sopenharmony_ci	pltfm_host = sdhci_priv(host);
185762306a36Sopenharmony_ci	sdhci_arasan = sdhci_pltfm_priv(pltfm_host);
185862306a36Sopenharmony_ci	sdhci_arasan->host = host;
185962306a36Sopenharmony_ci
186062306a36Sopenharmony_ci	sdhci_arasan->soc_ctl_map = data->soc_ctl_map;
186162306a36Sopenharmony_ci	sdhci_arasan->clk_ops = data->clk_ops;
186262306a36Sopenharmony_ci
186362306a36Sopenharmony_ci	node = of_parse_phandle(np, "arasan,soc-ctl-syscon", 0);
186462306a36Sopenharmony_ci	if (node) {
186562306a36Sopenharmony_ci		sdhci_arasan->soc_ctl_base = syscon_node_to_regmap(node);
186662306a36Sopenharmony_ci		of_node_put(node);
186762306a36Sopenharmony_ci
186862306a36Sopenharmony_ci		if (IS_ERR(sdhci_arasan->soc_ctl_base)) {
186962306a36Sopenharmony_ci			ret = dev_err_probe(dev,
187062306a36Sopenharmony_ci					    PTR_ERR(sdhci_arasan->soc_ctl_base),
187162306a36Sopenharmony_ci					    "Can't get syscon\n");
187262306a36Sopenharmony_ci			goto err_pltfm_free;
187362306a36Sopenharmony_ci		}
187462306a36Sopenharmony_ci	}
187562306a36Sopenharmony_ci
187662306a36Sopenharmony_ci	sdhci_get_of_property(pdev);
187762306a36Sopenharmony_ci
187862306a36Sopenharmony_ci	sdhci_arasan->clk_ahb = devm_clk_get(dev, "clk_ahb");
187962306a36Sopenharmony_ci	if (IS_ERR(sdhci_arasan->clk_ahb)) {
188062306a36Sopenharmony_ci		ret = dev_err_probe(dev, PTR_ERR(sdhci_arasan->clk_ahb),
188162306a36Sopenharmony_ci				    "clk_ahb clock not found.\n");
188262306a36Sopenharmony_ci		goto err_pltfm_free;
188362306a36Sopenharmony_ci	}
188462306a36Sopenharmony_ci
188562306a36Sopenharmony_ci	clk_xin = devm_clk_get(dev, "clk_xin");
188662306a36Sopenharmony_ci	if (IS_ERR(clk_xin)) {
188762306a36Sopenharmony_ci		ret = dev_err_probe(dev, PTR_ERR(clk_xin), "clk_xin clock not found.\n");
188862306a36Sopenharmony_ci		goto err_pltfm_free;
188962306a36Sopenharmony_ci	}
189062306a36Sopenharmony_ci
189162306a36Sopenharmony_ci	ret = clk_prepare_enable(sdhci_arasan->clk_ahb);
189262306a36Sopenharmony_ci	if (ret) {
189362306a36Sopenharmony_ci		dev_err(dev, "Unable to enable AHB clock.\n");
189462306a36Sopenharmony_ci		goto err_pltfm_free;
189562306a36Sopenharmony_ci	}
189662306a36Sopenharmony_ci
189762306a36Sopenharmony_ci	/* If clock-frequency property is set, use the provided value */
189862306a36Sopenharmony_ci	if (pltfm_host->clock &&
189962306a36Sopenharmony_ci	    pltfm_host->clock != clk_get_rate(clk_xin)) {
190062306a36Sopenharmony_ci		ret = clk_set_rate(clk_xin, pltfm_host->clock);
190162306a36Sopenharmony_ci		if (ret) {
190262306a36Sopenharmony_ci			dev_err(&pdev->dev, "Failed to set SD clock rate\n");
190362306a36Sopenharmony_ci			goto clk_dis_ahb;
190462306a36Sopenharmony_ci		}
190562306a36Sopenharmony_ci	}
190662306a36Sopenharmony_ci
190762306a36Sopenharmony_ci	ret = clk_prepare_enable(clk_xin);
190862306a36Sopenharmony_ci	if (ret) {
190962306a36Sopenharmony_ci		dev_err(dev, "Unable to enable SD clock.\n");
191062306a36Sopenharmony_ci		goto clk_dis_ahb;
191162306a36Sopenharmony_ci	}
191262306a36Sopenharmony_ci
191362306a36Sopenharmony_ci	clk_dll = devm_clk_get_optional_enabled(dev, "gate");
191462306a36Sopenharmony_ci	if (IS_ERR(clk_dll)) {
191562306a36Sopenharmony_ci		ret = dev_err_probe(dev, PTR_ERR(clk_dll), "failed to get dll clk\n");
191662306a36Sopenharmony_ci		goto clk_disable_all;
191762306a36Sopenharmony_ci	}
191862306a36Sopenharmony_ci
191962306a36Sopenharmony_ci	if (of_property_read_bool(np, "xlnx,fails-without-test-cd"))
192062306a36Sopenharmony_ci		sdhci_arasan->quirks |= SDHCI_ARASAN_QUIRK_FORCE_CDTEST;
192162306a36Sopenharmony_ci
192262306a36Sopenharmony_ci	if (of_property_read_bool(np, "xlnx,int-clock-stable-broken"))
192362306a36Sopenharmony_ci		sdhci_arasan->quirks |= SDHCI_ARASAN_QUIRK_CLOCK_UNSTABLE;
192462306a36Sopenharmony_ci
192562306a36Sopenharmony_ci	pltfm_host->clk = clk_xin;
192662306a36Sopenharmony_ci
192762306a36Sopenharmony_ci	if (of_device_is_compatible(np, "rockchip,rk3399-sdhci-5.1"))
192862306a36Sopenharmony_ci		sdhci_arasan_update_clockmultiplier(host, 0x0);
192962306a36Sopenharmony_ci
193062306a36Sopenharmony_ci	if (of_device_is_compatible(np, "intel,keembay-sdhci-5.1-emmc") ||
193162306a36Sopenharmony_ci	    of_device_is_compatible(np, "intel,keembay-sdhci-5.1-sd") ||
193262306a36Sopenharmony_ci	    of_device_is_compatible(np, "intel,keembay-sdhci-5.1-sdio")) {
193362306a36Sopenharmony_ci		sdhci_arasan_update_clockmultiplier(host, 0x0);
193462306a36Sopenharmony_ci		sdhci_arasan_update_support64b(host, 0x0);
193562306a36Sopenharmony_ci
193662306a36Sopenharmony_ci		host->mmc->caps |= MMC_CAP_WAIT_WHILE_BUSY;
193762306a36Sopenharmony_ci	}
193862306a36Sopenharmony_ci
193962306a36Sopenharmony_ci	sdhci_arasan_update_baseclkfreq(host);
194062306a36Sopenharmony_ci
194162306a36Sopenharmony_ci	ret = sdhci_arasan_register_sdclk(sdhci_arasan, clk_xin, dev);
194262306a36Sopenharmony_ci	if (ret)
194362306a36Sopenharmony_ci		goto clk_disable_all;
194462306a36Sopenharmony_ci
194562306a36Sopenharmony_ci	if (of_device_is_compatible(np, "xlnx,zynqmp-8.9a")) {
194662306a36Sopenharmony_ci		host->mmc_host_ops.execute_tuning =
194762306a36Sopenharmony_ci			arasan_zynqmp_execute_tuning;
194862306a36Sopenharmony_ci
194962306a36Sopenharmony_ci		sdhci_arasan->quirks |= SDHCI_ARASAN_QUIRK_CLOCK_25_BROKEN;
195062306a36Sopenharmony_ci		host->quirks |= SDHCI_QUIRK_MULTIBLOCK_READ_ACMD12;
195162306a36Sopenharmony_ci	}
195262306a36Sopenharmony_ci
195362306a36Sopenharmony_ci	arasan_dt_parse_clk_phases(dev, &sdhci_arasan->clk_data);
195462306a36Sopenharmony_ci
195562306a36Sopenharmony_ci	ret = mmc_of_parse(host->mmc);
195662306a36Sopenharmony_ci	if (ret) {
195762306a36Sopenharmony_ci		ret = dev_err_probe(dev, ret, "parsing dt failed.\n");
195862306a36Sopenharmony_ci		goto unreg_clk;
195962306a36Sopenharmony_ci	}
196062306a36Sopenharmony_ci
196162306a36Sopenharmony_ci	if (of_device_is_compatible(np, "xlnx,zynqmp-8.9a")) {
196262306a36Sopenharmony_ci		ret = zynqmp_pm_is_function_supported(PM_IOCTL, IOCTL_SET_SD_CONFIG);
196362306a36Sopenharmony_ci		if (!ret) {
196462306a36Sopenharmony_ci			ret = sdhci_zynqmp_set_dynamic_config(dev, sdhci_arasan);
196562306a36Sopenharmony_ci			if (ret)
196662306a36Sopenharmony_ci				goto unreg_clk;
196762306a36Sopenharmony_ci		}
196862306a36Sopenharmony_ci	}
196962306a36Sopenharmony_ci
197062306a36Sopenharmony_ci	sdhci_arasan->phy = ERR_PTR(-ENODEV);
197162306a36Sopenharmony_ci	if (of_device_is_compatible(np, "arasan,sdhci-5.1")) {
197262306a36Sopenharmony_ci		sdhci_arasan->phy = devm_phy_get(dev, "phy_arasan");
197362306a36Sopenharmony_ci		if (IS_ERR(sdhci_arasan->phy)) {
197462306a36Sopenharmony_ci			ret = dev_err_probe(dev, PTR_ERR(sdhci_arasan->phy),
197562306a36Sopenharmony_ci					    "No phy for arasan,sdhci-5.1.\n");
197662306a36Sopenharmony_ci			goto unreg_clk;
197762306a36Sopenharmony_ci		}
197862306a36Sopenharmony_ci
197962306a36Sopenharmony_ci		ret = phy_init(sdhci_arasan->phy);
198062306a36Sopenharmony_ci		if (ret < 0) {
198162306a36Sopenharmony_ci			dev_err(dev, "phy_init err.\n");
198262306a36Sopenharmony_ci			goto unreg_clk;
198362306a36Sopenharmony_ci		}
198462306a36Sopenharmony_ci
198562306a36Sopenharmony_ci		host->mmc_host_ops.hs400_enhanced_strobe =
198662306a36Sopenharmony_ci					sdhci_arasan_hs400_enhanced_strobe;
198762306a36Sopenharmony_ci		host->mmc_host_ops.start_signal_voltage_switch =
198862306a36Sopenharmony_ci					sdhci_arasan_voltage_switch;
198962306a36Sopenharmony_ci		sdhci_arasan->has_cqe = true;
199062306a36Sopenharmony_ci		host->mmc->caps2 |= MMC_CAP2_CQE;
199162306a36Sopenharmony_ci
199262306a36Sopenharmony_ci		if (!of_property_read_bool(np, "disable-cqe-dcmd"))
199362306a36Sopenharmony_ci			host->mmc->caps2 |= MMC_CAP2_CQE_DCMD;
199462306a36Sopenharmony_ci	}
199562306a36Sopenharmony_ci
199662306a36Sopenharmony_ci	if (of_device_is_compatible(np, "xlnx,versal-net-emmc"))
199762306a36Sopenharmony_ci		sdhci_arasan->internal_phy_reg = true;
199862306a36Sopenharmony_ci
199962306a36Sopenharmony_ci	ret = sdhci_arasan_add_host(sdhci_arasan);
200062306a36Sopenharmony_ci	if (ret)
200162306a36Sopenharmony_ci		goto err_add_host;
200262306a36Sopenharmony_ci
200362306a36Sopenharmony_ci	return 0;
200462306a36Sopenharmony_ci
200562306a36Sopenharmony_cierr_add_host:
200662306a36Sopenharmony_ci	if (!IS_ERR(sdhci_arasan->phy))
200762306a36Sopenharmony_ci		phy_exit(sdhci_arasan->phy);
200862306a36Sopenharmony_ciunreg_clk:
200962306a36Sopenharmony_ci	sdhci_arasan_unregister_sdclk(dev);
201062306a36Sopenharmony_ciclk_disable_all:
201162306a36Sopenharmony_ci	clk_disable_unprepare(clk_xin);
201262306a36Sopenharmony_ciclk_dis_ahb:
201362306a36Sopenharmony_ci	clk_disable_unprepare(sdhci_arasan->clk_ahb);
201462306a36Sopenharmony_cierr_pltfm_free:
201562306a36Sopenharmony_ci	sdhci_pltfm_free(pdev);
201662306a36Sopenharmony_ci	return ret;
201762306a36Sopenharmony_ci}
201862306a36Sopenharmony_ci
201962306a36Sopenharmony_cistatic void sdhci_arasan_remove(struct platform_device *pdev)
202062306a36Sopenharmony_ci{
202162306a36Sopenharmony_ci	struct sdhci_host *host = platform_get_drvdata(pdev);
202262306a36Sopenharmony_ci	struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
202362306a36Sopenharmony_ci	struct sdhci_arasan_data *sdhci_arasan = sdhci_pltfm_priv(pltfm_host);
202462306a36Sopenharmony_ci	struct clk *clk_ahb = sdhci_arasan->clk_ahb;
202562306a36Sopenharmony_ci	struct clk *clk_xin = pltfm_host->clk;
202662306a36Sopenharmony_ci
202762306a36Sopenharmony_ci	if (!IS_ERR(sdhci_arasan->phy)) {
202862306a36Sopenharmony_ci		if (sdhci_arasan->is_phy_on)
202962306a36Sopenharmony_ci			phy_power_off(sdhci_arasan->phy);
203062306a36Sopenharmony_ci		phy_exit(sdhci_arasan->phy);
203162306a36Sopenharmony_ci	}
203262306a36Sopenharmony_ci
203362306a36Sopenharmony_ci	sdhci_arasan_unregister_sdclk(&pdev->dev);
203462306a36Sopenharmony_ci
203562306a36Sopenharmony_ci	sdhci_pltfm_remove(pdev);
203662306a36Sopenharmony_ci
203762306a36Sopenharmony_ci	clk_disable_unprepare(clk_xin);
203862306a36Sopenharmony_ci	clk_disable_unprepare(clk_ahb);
203962306a36Sopenharmony_ci}
204062306a36Sopenharmony_ci
204162306a36Sopenharmony_cistatic struct platform_driver sdhci_arasan_driver = {
204262306a36Sopenharmony_ci	.driver = {
204362306a36Sopenharmony_ci		.name = "sdhci-arasan",
204462306a36Sopenharmony_ci		.probe_type = PROBE_PREFER_ASYNCHRONOUS,
204562306a36Sopenharmony_ci		.of_match_table = sdhci_arasan_of_match,
204662306a36Sopenharmony_ci		.pm = &sdhci_arasan_dev_pm_ops,
204762306a36Sopenharmony_ci	},
204862306a36Sopenharmony_ci	.probe = sdhci_arasan_probe,
204962306a36Sopenharmony_ci	.remove_new = sdhci_arasan_remove,
205062306a36Sopenharmony_ci};
205162306a36Sopenharmony_ci
205262306a36Sopenharmony_cimodule_platform_driver(sdhci_arasan_driver);
205362306a36Sopenharmony_ci
205462306a36Sopenharmony_ciMODULE_DESCRIPTION("Driver for the Arasan SDHCI Controller");
205562306a36Sopenharmony_ciMODULE_AUTHOR("Soeren Brinkmann <soren.brinkmann@xilinx.com>");
205662306a36Sopenharmony_ciMODULE_LICENSE("GPL");
2057