cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

sdhci-xenon.c (19073B)


      1// SPDX-License-Identifier: GPL-2.0-only
      2/*
      3 * Driver for Marvell Xenon SDHC as a platform device
      4 *
      5 * Copyright (C) 2016 Marvell, All Rights Reserved.
      6 *
      7 * Author:	Hu Ziji <huziji@marvell.com>
      8 * Date:	2016-8-24
      9 *
     10 * Inspired by Jisheng Zhang <jszhang@marvell.com>
     11 * Special thanks to Video BG4 project team.
     12 */
     13
     14#include <linux/acpi.h>
     15#include <linux/delay.h>
     16#include <linux/ktime.h>
     17#include <linux/module.h>
     18#include <linux/of.h>
     19#include <linux/pm.h>
     20#include <linux/pm_runtime.h>
     21
     22#include "sdhci-pltfm.h"
     23#include "sdhci-xenon.h"
     24
     25static int xenon_enable_internal_clk(struct sdhci_host *host)
     26{
     27	u32 reg;
     28	ktime_t timeout;
     29
     30	reg = sdhci_readl(host, SDHCI_CLOCK_CONTROL);
     31	reg |= SDHCI_CLOCK_INT_EN;
     32	sdhci_writel(host, reg, SDHCI_CLOCK_CONTROL);
     33	/* Wait max 20 ms */
     34	timeout = ktime_add_ms(ktime_get(), 20);
     35	while (1) {
     36		bool timedout = ktime_after(ktime_get(), timeout);
     37
     38		reg = sdhci_readw(host, SDHCI_CLOCK_CONTROL);
     39		if (reg & SDHCI_CLOCK_INT_STABLE)
     40			break;
     41		if (timedout) {
     42			dev_err(mmc_dev(host->mmc), "Internal clock never stabilised.\n");
     43			return -ETIMEDOUT;
     44		}
     45		usleep_range(900, 1100);
     46	}
     47
     48	return 0;
     49}
     50
     51/* Set SDCLK-off-while-idle */
     52static void xenon_set_sdclk_off_idle(struct sdhci_host *host,
     53				     unsigned char sdhc_id, bool enable)
     54{
     55	u32 reg;
     56	u32 mask;
     57
     58	reg = sdhci_readl(host, XENON_SYS_OP_CTRL);
     59	/* Get the bit shift basing on the SDHC index */
     60	mask = (0x1 << (XENON_SDCLK_IDLEOFF_ENABLE_SHIFT + sdhc_id));
     61	if (enable)
     62		reg |= mask;
     63	else
     64		reg &= ~mask;
     65
     66	sdhci_writel(host, reg, XENON_SYS_OP_CTRL);
     67}
     68
     69/* Enable/Disable the Auto Clock Gating function */
     70static void xenon_set_acg(struct sdhci_host *host, bool enable)
     71{
     72	u32 reg;
     73
     74	reg = sdhci_readl(host, XENON_SYS_OP_CTRL);
     75	if (enable)
     76		reg &= ~XENON_AUTO_CLKGATE_DISABLE_MASK;
     77	else
     78		reg |= XENON_AUTO_CLKGATE_DISABLE_MASK;
     79	sdhci_writel(host, reg, XENON_SYS_OP_CTRL);
     80}
     81
     82/* Enable this SDHC */
     83static void xenon_enable_sdhc(struct sdhci_host *host,
     84			      unsigned char sdhc_id)
     85{
     86	u32 reg;
     87
     88	reg = sdhci_readl(host, XENON_SYS_OP_CTRL);
     89	reg |= (BIT(sdhc_id) << XENON_SLOT_ENABLE_SHIFT);
     90	sdhci_writel(host, reg, XENON_SYS_OP_CTRL);
     91
     92	host->mmc->caps |= MMC_CAP_WAIT_WHILE_BUSY;
     93	/*
     94	 * Force to clear BUS_TEST to
     95	 * skip bus_test_pre and bus_test_post
     96	 */
     97	host->mmc->caps &= ~MMC_CAP_BUS_WIDTH_TEST;
     98}
     99
    100/* Disable this SDHC */
    101static void xenon_disable_sdhc(struct sdhci_host *host,
    102			       unsigned char sdhc_id)
    103{
    104	u32 reg;
    105
    106	reg = sdhci_readl(host, XENON_SYS_OP_CTRL);
    107	reg &= ~(BIT(sdhc_id) << XENON_SLOT_ENABLE_SHIFT);
    108	sdhci_writel(host, reg, XENON_SYS_OP_CTRL);
    109}
    110
    111/* Enable Parallel Transfer Mode */
    112static void xenon_enable_sdhc_parallel_tran(struct sdhci_host *host,
    113					    unsigned char sdhc_id)
    114{
    115	u32 reg;
    116
    117	reg = sdhci_readl(host, XENON_SYS_EXT_OP_CTRL);
    118	reg |= BIT(sdhc_id);
    119	sdhci_writel(host, reg, XENON_SYS_EXT_OP_CTRL);
    120}
    121
    122/* Mask command conflict error */
    123static void xenon_mask_cmd_conflict_err(struct sdhci_host *host)
    124{
    125	u32  reg;
    126
    127	reg = sdhci_readl(host, XENON_SYS_EXT_OP_CTRL);
    128	reg |= XENON_MASK_CMD_CONFLICT_ERR;
    129	sdhci_writel(host, reg, XENON_SYS_EXT_OP_CTRL);
    130}
    131
    132static void xenon_retune_setup(struct sdhci_host *host)
    133{
    134	struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
    135	struct xenon_priv *priv = sdhci_pltfm_priv(pltfm_host);
    136	u32 reg;
    137
    138	/* Disable the Re-Tuning Request functionality */
    139	reg = sdhci_readl(host, XENON_SLOT_RETUNING_REQ_CTRL);
    140	reg &= ~XENON_RETUNING_COMPATIBLE;
    141	sdhci_writel(host, reg, XENON_SLOT_RETUNING_REQ_CTRL);
    142
    143	/* Disable the Re-tuning Interrupt */
    144	reg = sdhci_readl(host, SDHCI_SIGNAL_ENABLE);
    145	reg &= ~SDHCI_INT_RETUNE;
    146	sdhci_writel(host, reg, SDHCI_SIGNAL_ENABLE);
    147	reg = sdhci_readl(host, SDHCI_INT_ENABLE);
    148	reg &= ~SDHCI_INT_RETUNE;
    149	sdhci_writel(host, reg, SDHCI_INT_ENABLE);
    150
    151	/* Force to use Tuning Mode 1 */
    152	host->tuning_mode = SDHCI_TUNING_MODE_1;
    153	/* Set re-tuning period */
    154	host->tuning_count = 1 << (priv->tuning_count - 1);
    155}
    156
    157/*
    158 * Operations inside struct sdhci_ops
    159 */
    160/* Recover the Register Setting cleared during SOFTWARE_RESET_ALL */
    161static void xenon_reset_exit(struct sdhci_host *host,
    162			     unsigned char sdhc_id, u8 mask)
    163{
    164	/* Only SOFTWARE RESET ALL will clear the register setting */
    165	if (!(mask & SDHCI_RESET_ALL))
    166		return;
    167
    168	/* Disable tuning request and auto-retuning again */
    169	xenon_retune_setup(host);
    170
    171	/*
    172	 * The ACG should be turned off at the early init time, in order
    173	 * to solve a possible issues with the 1.8V regulator stabilization.
    174	 * The feature is enabled in later stage.
    175	 */
    176	xenon_set_acg(host, false);
    177
    178	xenon_set_sdclk_off_idle(host, sdhc_id, false);
    179
    180	xenon_mask_cmd_conflict_err(host);
    181}
    182
    183static void xenon_reset(struct sdhci_host *host, u8 mask)
    184{
    185	struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
    186	struct xenon_priv *priv = sdhci_pltfm_priv(pltfm_host);
    187
    188	sdhci_reset(host, mask);
    189	xenon_reset_exit(host, priv->sdhc_id, mask);
    190}
    191
    192/*
    193 * Xenon defines different values for HS200 and HS400
    194 * in Host_Control_2
    195 */
    196static void xenon_set_uhs_signaling(struct sdhci_host *host,
    197				    unsigned int timing)
    198{
    199	u16 ctrl_2;
    200
    201	ctrl_2 = sdhci_readw(host, SDHCI_HOST_CONTROL2);
    202	/* Select Bus Speed Mode for host */
    203	ctrl_2 &= ~SDHCI_CTRL_UHS_MASK;
    204	if (timing == MMC_TIMING_MMC_HS200)
    205		ctrl_2 |= XENON_CTRL_HS200;
    206	else if (timing == MMC_TIMING_UHS_SDR104)
    207		ctrl_2 |= SDHCI_CTRL_UHS_SDR104;
    208	else if (timing == MMC_TIMING_UHS_SDR12)
    209		ctrl_2 |= SDHCI_CTRL_UHS_SDR12;
    210	else if (timing == MMC_TIMING_UHS_SDR25)
    211		ctrl_2 |= SDHCI_CTRL_UHS_SDR25;
    212	else if (timing == MMC_TIMING_UHS_SDR50)
    213		ctrl_2 |= SDHCI_CTRL_UHS_SDR50;
    214	else if ((timing == MMC_TIMING_UHS_DDR50) ||
    215		 (timing == MMC_TIMING_MMC_DDR52))
    216		ctrl_2 |= SDHCI_CTRL_UHS_DDR50;
    217	else if (timing == MMC_TIMING_MMC_HS400)
    218		ctrl_2 |= XENON_CTRL_HS400;
    219	sdhci_writew(host, ctrl_2, SDHCI_HOST_CONTROL2);
    220}
    221
    222static void xenon_set_power(struct sdhci_host *host, unsigned char mode,
    223		unsigned short vdd)
    224{
    225	struct mmc_host *mmc = host->mmc;
    226	u8 pwr = host->pwr;
    227
    228	sdhci_set_power_noreg(host, mode, vdd);
    229
    230	if (host->pwr == pwr)
    231		return;
    232
    233	if (host->pwr == 0)
    234		vdd = 0;
    235
    236	if (!IS_ERR(mmc->supply.vmmc))
    237		mmc_regulator_set_ocr(mmc, mmc->supply.vmmc, vdd);
    238}
    239
    240static void xenon_voltage_switch(struct sdhci_host *host)
    241{
    242	/* Wait for 5ms after set 1.8V signal enable bit */
    243	usleep_range(5000, 5500);
    244}
    245
    246static unsigned int xenon_get_max_clock(struct sdhci_host *host)
    247{
    248	struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
    249
    250	if (pltfm_host->clk)
    251		return sdhci_pltfm_clk_get_max_clock(host);
    252	else
    253		return pltfm_host->clock;
    254}
    255
    256static const struct sdhci_ops sdhci_xenon_ops = {
    257	.voltage_switch		= xenon_voltage_switch,
    258	.set_clock		= sdhci_set_clock,
    259	.set_power		= xenon_set_power,
    260	.set_bus_width		= sdhci_set_bus_width,
    261	.reset			= xenon_reset,
    262	.set_uhs_signaling	= xenon_set_uhs_signaling,
    263	.get_max_clock		= xenon_get_max_clock,
    264};
    265
    266static const struct sdhci_pltfm_data sdhci_xenon_pdata = {
    267	.ops = &sdhci_xenon_ops,
    268	.quirks = SDHCI_QUIRK_NO_ENDATTR_IN_NOPDESC |
    269		  SDHCI_QUIRK_NO_SIMULT_VDD_AND_POWER |
    270		  SDHCI_QUIRK_CAP_CLOCK_BASE_BROKEN,
    271};
    272
    273/*
    274 * Xenon Specific Operations in mmc_host_ops
    275 */
    276static void xenon_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
    277{
    278	struct sdhci_host *host = mmc_priv(mmc);
    279	struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
    280	struct xenon_priv *priv = sdhci_pltfm_priv(pltfm_host);
    281	u32 reg;
    282
    283	/*
    284	 * HS400/HS200/eMMC HS doesn't have Preset Value register.
    285	 * However, sdhci_set_ios will read HS400/HS200 Preset register.
    286	 * Disable Preset Value register for HS400/HS200.
    287	 * eMMC HS with preset_enabled set will trigger a bug in
    288	 * get_preset_value().
    289	 */
    290	if ((ios->timing == MMC_TIMING_MMC_HS400) ||
    291	    (ios->timing == MMC_TIMING_MMC_HS200) ||
    292	    (ios->timing == MMC_TIMING_MMC_HS)) {
    293		host->preset_enabled = false;
    294		host->quirks2 |= SDHCI_QUIRK2_PRESET_VALUE_BROKEN;
    295		host->flags &= ~SDHCI_PV_ENABLED;
    296
    297		reg = sdhci_readw(host, SDHCI_HOST_CONTROL2);
    298		reg &= ~SDHCI_CTRL_PRESET_VAL_ENABLE;
    299		sdhci_writew(host, reg, SDHCI_HOST_CONTROL2);
    300	} else {
    301		host->quirks2 &= ~SDHCI_QUIRK2_PRESET_VALUE_BROKEN;
    302	}
    303
    304	sdhci_set_ios(mmc, ios);
    305	xenon_phy_adj(host, ios);
    306
    307	if (host->clock > XENON_DEFAULT_SDCLK_FREQ)
    308		xenon_set_sdclk_off_idle(host, priv->sdhc_id, true);
    309}
    310
    311static int xenon_start_signal_voltage_switch(struct mmc_host *mmc,
    312					     struct mmc_ios *ios)
    313{
    314	struct sdhci_host *host = mmc_priv(mmc);
    315
    316	/*
    317	 * Before SD/SDIO set signal voltage, SD bus clock should be
    318	 * disabled. However, sdhci_set_clock will also disable the Internal
    319	 * clock in mmc_set_signal_voltage().
    320	 * If Internal clock is disabled, the 3.3V/1.8V bit can not be updated.
    321	 * Thus here manually enable internal clock.
    322	 *
    323	 * After switch completes, it is unnecessary to disable internal clock,
    324	 * since keeping internal clock active obeys SD spec.
    325	 */
    326	xenon_enable_internal_clk(host);
    327
    328	xenon_soc_pad_ctrl(host, ios->signal_voltage);
    329
    330	/*
    331	 * If Vqmmc is fixed on platform, vqmmc regulator should be unavailable.
    332	 * Thus SDHCI_CTRL_VDD_180 bit might not work then.
    333	 * Skip the standard voltage switch to avoid any issue.
    334	 */
    335	if (PTR_ERR(mmc->supply.vqmmc) == -ENODEV)
    336		return 0;
    337
    338	return sdhci_start_signal_voltage_switch(mmc, ios);
    339}
    340
    341/*
    342 * Update card type.
    343 * priv->init_card_type will be used in PHY timing adjustment.
    344 */
    345static void xenon_init_card(struct mmc_host *mmc, struct mmc_card *card)
    346{
    347	struct sdhci_host *host = mmc_priv(mmc);
    348	struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
    349	struct xenon_priv *priv = sdhci_pltfm_priv(pltfm_host);
    350
    351	/* Update card type*/
    352	priv->init_card_type = card->type;
    353}
    354
    355static int xenon_execute_tuning(struct mmc_host *mmc, u32 opcode)
    356{
    357	struct sdhci_host *host = mmc_priv(mmc);
    358
    359	if (host->timing == MMC_TIMING_UHS_DDR50 ||
    360		host->timing == MMC_TIMING_MMC_DDR52)
    361		return 0;
    362
    363	/*
    364	 * Currently force Xenon driver back to support mode 1 only,
    365	 * even though Xenon might claim to support mode 2 or mode 3.
    366	 * It requires more time to test mode 2/mode 3 on more platforms.
    367	 */
    368	if (host->tuning_mode != SDHCI_TUNING_MODE_1)
    369		xenon_retune_setup(host);
    370
    371	return sdhci_execute_tuning(mmc, opcode);
    372}
    373
    374static void xenon_enable_sdio_irq(struct mmc_host *mmc, int enable)
    375{
    376	struct sdhci_host *host = mmc_priv(mmc);
    377	struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
    378	struct xenon_priv *priv = sdhci_pltfm_priv(pltfm_host);
    379	u32 reg;
    380	u8 sdhc_id = priv->sdhc_id;
    381
    382	sdhci_enable_sdio_irq(mmc, enable);
    383
    384	if (enable) {
    385		/*
    386		 * Set SDIO Card Inserted indication
    387		 * to enable detecting SDIO async irq.
    388		 */
    389		reg = sdhci_readl(host, XENON_SYS_CFG_INFO);
    390		reg |= (1 << (sdhc_id + XENON_SLOT_TYPE_SDIO_SHIFT));
    391		sdhci_writel(host, reg, XENON_SYS_CFG_INFO);
    392	} else {
    393		/* Clear SDIO Card Inserted indication */
    394		reg = sdhci_readl(host, XENON_SYS_CFG_INFO);
    395		reg &= ~(1 << (sdhc_id + XENON_SLOT_TYPE_SDIO_SHIFT));
    396		sdhci_writel(host, reg, XENON_SYS_CFG_INFO);
    397	}
    398}
    399
    400static void xenon_replace_mmc_host_ops(struct sdhci_host *host)
    401{
    402	host->mmc_host_ops.set_ios = xenon_set_ios;
    403	host->mmc_host_ops.start_signal_voltage_switch =
    404			xenon_start_signal_voltage_switch;
    405	host->mmc_host_ops.init_card = xenon_init_card;
    406	host->mmc_host_ops.execute_tuning = xenon_execute_tuning;
    407	host->mmc_host_ops.enable_sdio_irq = xenon_enable_sdio_irq;
    408}
    409
    410/*
    411 * Parse Xenon specific DT properties:
    412 * sdhc-id: the index of current SDHC.
    413 *	    Refer to XENON_SYS_CFG_INFO register
    414 * tun-count: the interval between re-tuning
    415 */
    416static int xenon_probe_params(struct platform_device *pdev)
    417{
    418	struct device *dev = &pdev->dev;
    419	struct sdhci_host *host = platform_get_drvdata(pdev);
    420	struct mmc_host *mmc = host->mmc;
    421	struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
    422	struct xenon_priv *priv = sdhci_pltfm_priv(pltfm_host);
    423	u32 sdhc_id, nr_sdhc;
    424	u32 tuning_count;
    425
    426	/* Disable HS200 on Armada AP806 */
    427	if (priv->hw_version == XENON_AP806)
    428		host->quirks2 |= SDHCI_QUIRK2_BROKEN_HS200;
    429
    430	sdhc_id = 0x0;
    431	if (!device_property_read_u32(dev, "marvell,xenon-sdhc-id", &sdhc_id)) {
    432		nr_sdhc = sdhci_readl(host, XENON_SYS_CFG_INFO);
    433		nr_sdhc &= XENON_NR_SUPPORTED_SLOT_MASK;
    434		if (unlikely(sdhc_id > nr_sdhc)) {
    435			dev_err(mmc_dev(mmc), "SDHC Index %d exceeds Number of SDHCs %d\n",
    436				sdhc_id, nr_sdhc);
    437			return -EINVAL;
    438		}
    439	}
    440	priv->sdhc_id = sdhc_id;
    441
    442	tuning_count = XENON_DEF_TUNING_COUNT;
    443	if (!device_property_read_u32(dev, "marvell,xenon-tun-count",
    444				      &tuning_count)) {
    445		if (unlikely(tuning_count >= XENON_TMR_RETUN_NO_PRESENT)) {
    446			dev_err(mmc_dev(mmc), "Wrong Re-tuning Count. Set default value %d\n",
    447				XENON_DEF_TUNING_COUNT);
    448			tuning_count = XENON_DEF_TUNING_COUNT;
    449		}
    450	}
    451	priv->tuning_count = tuning_count;
    452
    453	return xenon_phy_parse_params(dev, host);
    454}
    455
    456static int xenon_sdhc_prepare(struct sdhci_host *host)
    457{
    458	struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
    459	struct xenon_priv *priv = sdhci_pltfm_priv(pltfm_host);
    460	u8 sdhc_id = priv->sdhc_id;
    461
    462	/* Enable SDHC */
    463	xenon_enable_sdhc(host, sdhc_id);
    464
    465	/* Enable ACG */
    466	xenon_set_acg(host, true);
    467
    468	/* Enable Parallel Transfer Mode */
    469	xenon_enable_sdhc_parallel_tran(host, sdhc_id);
    470
    471	/* Disable SDCLK-Off-While-Idle before card init */
    472	xenon_set_sdclk_off_idle(host, sdhc_id, false);
    473
    474	xenon_mask_cmd_conflict_err(host);
    475
    476	return 0;
    477}
    478
    479static void xenon_sdhc_unprepare(struct sdhci_host *host)
    480{
    481	struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
    482	struct xenon_priv *priv = sdhci_pltfm_priv(pltfm_host);
    483	u8 sdhc_id = priv->sdhc_id;
    484
    485	/* disable SDHC */
    486	xenon_disable_sdhc(host, sdhc_id);
    487}
    488
    489static int xenon_probe(struct platform_device *pdev)
    490{
    491	struct sdhci_pltfm_host *pltfm_host;
    492	struct device *dev = &pdev->dev;
    493	struct sdhci_host *host;
    494	struct xenon_priv *priv;
    495	int err;
    496
    497	host = sdhci_pltfm_init(pdev, &sdhci_xenon_pdata,
    498				sizeof(struct xenon_priv));
    499	if (IS_ERR(host))
    500		return PTR_ERR(host);
    501
    502	pltfm_host = sdhci_priv(host);
    503	priv = sdhci_pltfm_priv(pltfm_host);
    504
    505	priv->hw_version = (unsigned long)device_get_match_data(&pdev->dev);
    506
    507	/*
    508	 * Link Xenon specific mmc_host_ops function,
    509	 * to replace standard ones in sdhci_ops.
    510	 */
    511	xenon_replace_mmc_host_ops(host);
    512
    513	if (dev->of_node) {
    514		pltfm_host->clk = devm_clk_get(&pdev->dev, "core");
    515		if (IS_ERR(pltfm_host->clk)) {
    516			err = PTR_ERR(pltfm_host->clk);
    517			dev_err(&pdev->dev, "Failed to setup input clk: %d\n", err);
    518			goto free_pltfm;
    519		}
    520		err = clk_prepare_enable(pltfm_host->clk);
    521		if (err)
    522			goto free_pltfm;
    523
    524		priv->axi_clk = devm_clk_get(&pdev->dev, "axi");
    525		if (IS_ERR(priv->axi_clk)) {
    526			err = PTR_ERR(priv->axi_clk);
    527			if (err == -EPROBE_DEFER)
    528				goto err_clk;
    529		} else {
    530			err = clk_prepare_enable(priv->axi_clk);
    531			if (err)
    532				goto err_clk;
    533		}
    534	}
    535
    536	err = mmc_of_parse(host->mmc);
    537	if (err)
    538		goto err_clk_axi;
    539
    540	sdhci_get_property(pdev);
    541
    542	xenon_set_acg(host, false);
    543
    544	/* Xenon specific parameters parse */
    545	err = xenon_probe_params(pdev);
    546	if (err)
    547		goto err_clk_axi;
    548
    549	err = xenon_sdhc_prepare(host);
    550	if (err)
    551		goto err_clk_axi;
    552
    553	pm_runtime_get_noresume(&pdev->dev);
    554	pm_runtime_set_active(&pdev->dev);
    555	pm_runtime_set_autosuspend_delay(&pdev->dev, 50);
    556	pm_runtime_use_autosuspend(&pdev->dev);
    557	pm_runtime_enable(&pdev->dev);
    558	pm_suspend_ignore_children(&pdev->dev, 1);
    559
    560	err = sdhci_add_host(host);
    561	if (err)
    562		goto remove_sdhc;
    563
    564	pm_runtime_put_autosuspend(&pdev->dev);
    565
    566	return 0;
    567
    568remove_sdhc:
    569	pm_runtime_disable(&pdev->dev);
    570	pm_runtime_put_noidle(&pdev->dev);
    571	xenon_sdhc_unprepare(host);
    572err_clk_axi:
    573	clk_disable_unprepare(priv->axi_clk);
    574err_clk:
    575	clk_disable_unprepare(pltfm_host->clk);
    576free_pltfm:
    577	sdhci_pltfm_free(pdev);
    578	return err;
    579}
    580
    581static int xenon_remove(struct platform_device *pdev)
    582{
    583	struct sdhci_host *host = platform_get_drvdata(pdev);
    584	struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
    585	struct xenon_priv *priv = sdhci_pltfm_priv(pltfm_host);
    586
    587	pm_runtime_get_sync(&pdev->dev);
    588	pm_runtime_disable(&pdev->dev);
    589	pm_runtime_put_noidle(&pdev->dev);
    590
    591	sdhci_remove_host(host, 0);
    592
    593	xenon_sdhc_unprepare(host);
    594	clk_disable_unprepare(priv->axi_clk);
    595	clk_disable_unprepare(pltfm_host->clk);
    596
    597	sdhci_pltfm_free(pdev);
    598
    599	return 0;
    600}
    601
    602#ifdef CONFIG_PM_SLEEP
    603static int xenon_suspend(struct device *dev)
    604{
    605	struct sdhci_host *host = dev_get_drvdata(dev);
    606	struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
    607	struct xenon_priv *priv = sdhci_pltfm_priv(pltfm_host);
    608	int ret;
    609
    610	ret = pm_runtime_force_suspend(dev);
    611
    612	priv->restore_needed = true;
    613	return ret;
    614}
    615#endif
    616
    617#ifdef CONFIG_PM
    618static int xenon_runtime_suspend(struct device *dev)
    619{
    620	struct sdhci_host *host = dev_get_drvdata(dev);
    621	struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
    622	struct xenon_priv *priv = sdhci_pltfm_priv(pltfm_host);
    623	int ret;
    624
    625	ret = sdhci_runtime_suspend_host(host);
    626	if (ret)
    627		return ret;
    628
    629	if (host->tuning_mode != SDHCI_TUNING_MODE_3)
    630		mmc_retune_needed(host->mmc);
    631
    632	clk_disable_unprepare(pltfm_host->clk);
    633	/*
    634	 * Need to update the priv->clock here, or when runtime resume
    635	 * back, phy don't aware the clock change and won't adjust phy
    636	 * which will cause cmd err
    637	 */
    638	priv->clock = 0;
    639	return 0;
    640}
    641
    642static int xenon_runtime_resume(struct device *dev)
    643{
    644	struct sdhci_host *host = dev_get_drvdata(dev);
    645	struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
    646	struct xenon_priv *priv = sdhci_pltfm_priv(pltfm_host);
    647	int ret;
    648
    649	ret = clk_prepare_enable(pltfm_host->clk);
    650	if (ret) {
    651		dev_err(dev, "can't enable mainck\n");
    652		return ret;
    653	}
    654
    655	if (priv->restore_needed) {
    656		ret = xenon_sdhc_prepare(host);
    657		if (ret)
    658			goto out;
    659		priv->restore_needed = false;
    660	}
    661
    662	ret = sdhci_runtime_resume_host(host, 0);
    663	if (ret)
    664		goto out;
    665	return 0;
    666out:
    667	clk_disable_unprepare(pltfm_host->clk);
    668	return ret;
    669}
    670#endif /* CONFIG_PM */
    671
    672static const struct dev_pm_ops sdhci_xenon_dev_pm_ops = {
    673	SET_SYSTEM_SLEEP_PM_OPS(xenon_suspend,
    674				pm_runtime_force_resume)
    675	SET_RUNTIME_PM_OPS(xenon_runtime_suspend,
    676			   xenon_runtime_resume,
    677			   NULL)
    678};
    679
    680static const struct of_device_id sdhci_xenon_dt_ids[] = {
    681	{ .compatible = "marvell,armada-ap806-sdhci", .data = (void *)XENON_AP806},
    682	{ .compatible = "marvell,armada-ap807-sdhci", .data = (void *)XENON_AP807},
    683	{ .compatible = "marvell,armada-cp110-sdhci", .data =  (void *)XENON_CP110},
    684	{ .compatible = "marvell,armada-3700-sdhci", .data =  (void *)XENON_A3700},
    685	{}
    686};
    687MODULE_DEVICE_TABLE(of, sdhci_xenon_dt_ids);
    688
    689#ifdef CONFIG_ACPI
    690static const struct acpi_device_id sdhci_xenon_acpi_ids[] = {
    691	{ .id = "MRVL0002", XENON_AP806},
    692	{ .id = "MRVL0003", XENON_AP807},
    693	{ .id = "MRVL0004", XENON_CP110},
    694	{}
    695};
    696MODULE_DEVICE_TABLE(acpi, sdhci_xenon_acpi_ids);
    697#endif
    698
    699static struct platform_driver sdhci_xenon_driver = {
    700	.driver	= {
    701		.name	= "xenon-sdhci",
    702		.probe_type = PROBE_PREFER_ASYNCHRONOUS,
    703		.of_match_table = sdhci_xenon_dt_ids,
    704		.acpi_match_table = ACPI_PTR(sdhci_xenon_acpi_ids),
    705		.pm = &sdhci_xenon_dev_pm_ops,
    706	},
    707	.probe	= xenon_probe,
    708	.remove	= xenon_remove,
    709};
    710
    711module_platform_driver(sdhci_xenon_driver);
    712
    713MODULE_DESCRIPTION("SDHCI platform driver for Marvell Xenon SDHC");
    714MODULE_AUTHOR("Hu Ziji <huziji@marvell.com>");
    715MODULE_LICENSE("GPL v2");