Lines Matching +full:hs200 +full:- +full:cmd +full:- +full:int +full:- +full:delay
1 // SPDX-License-Identifier: GPL-2.0-only
8 * Date: 2016-8-24
15 #include <linux/delay.h>
22 #include "sdhci-pltfm.h"
23 #include "sdhci-xenon.h"
25 static int xenon_enable_internal_clk(struct sdhci_host *host) in xenon_enable_internal_clk()
42 dev_err(mmc_dev(host->mmc), "Internal clock never stabilised.\n"); in xenon_enable_internal_clk()
43 return -ETIMEDOUT; in xenon_enable_internal_clk()
51 /* Set SDCLK-off-while-idle */
92 host->mmc->caps |= MMC_CAP_WAIT_WHILE_BUSY; in xenon_enable_sdhc()
97 host->mmc->caps &= ~MMC_CAP_BUS_WIDTH_TEST; in xenon_enable_sdhc()
138 /* Disable the Re-Tuning Request functionality */ in xenon_retune_setup()
143 /* Disable the Re-tuning Interrupt */ in xenon_retune_setup()
152 host->tuning_mode = SDHCI_TUNING_MODE_1; in xenon_retune_setup()
153 /* Set re-tuning period */ in xenon_retune_setup()
154 host->tuning_count = 1 << (priv->tuning_count - 1); in xenon_retune_setup()
168 /* Disable tuning request and auto-retuning again */ in xenon_reset_exit()
189 xenon_reset_exit(host, priv->sdhc_id, mask); in xenon_reset()
193 * Xenon defines different values for HS200 and HS400
197 unsigned int timing) in xenon_set_uhs_signaling()
225 struct mmc_host *mmc = host->mmc; in xenon_set_power()
226 u8 pwr = host->pwr; in xenon_set_power()
230 if (host->pwr == pwr) in xenon_set_power()
233 if (host->pwr == 0) in xenon_set_power()
236 if (!IS_ERR(mmc->supply.vmmc)) in xenon_set_power()
237 mmc_regulator_set_ocr(mmc, mmc->supply.vmmc, vdd); in xenon_set_power()
256 static unsigned int xenon_get_max_clock(struct sdhci_host *host) in xenon_get_max_clock()
260 if (pltfm_host->clk) in xenon_get_max_clock()
263 return pltfm_host->clock; in xenon_get_max_clock()
294 * HS400/HS200/eMMC HS doesn't have Preset Value register. in xenon_set_ios()
295 * However, sdhci_set_ios will read HS400/HS200 Preset register. in xenon_set_ios()
296 * Disable Preset Value register for HS400/HS200. in xenon_set_ios()
300 if ((ios->timing == MMC_TIMING_MMC_HS400) || in xenon_set_ios()
301 (ios->timing == MMC_TIMING_MMC_HS200) || in xenon_set_ios()
302 (ios->timing == MMC_TIMING_MMC_HS)) { in xenon_set_ios()
303 host->preset_enabled = false; in xenon_set_ios()
304 host->quirks2 |= SDHCI_QUIRK2_PRESET_VALUE_BROKEN; in xenon_set_ios()
305 host->flags &= ~SDHCI_PV_ENABLED; in xenon_set_ios()
311 host->quirks2 &= ~SDHCI_QUIRK2_PRESET_VALUE_BROKEN; in xenon_set_ios()
317 if (host->clock > XENON_DEFAULT_SDCLK_FREQ) in xenon_set_ios()
318 xenon_set_sdclk_off_idle(host, priv->sdhc_id, true); in xenon_set_ios()
321 static int xenon_start_signal_voltage_switch(struct mmc_host *mmc, in xenon_start_signal_voltage_switch()
338 xenon_soc_pad_ctrl(host, ios->signal_voltage); in xenon_start_signal_voltage_switch()
345 if (PTR_ERR(mmc->supply.vqmmc) == -ENODEV) in xenon_start_signal_voltage_switch()
353 * priv->init_card_type will be used in PHY timing adjustment.
362 priv->init_card_type = card->type; in xenon_init_card()
365 static int xenon_execute_tuning(struct mmc_host *mmc, u32 opcode) in xenon_execute_tuning()
369 if (host->timing == MMC_TIMING_UHS_DDR50 || in xenon_execute_tuning()
370 host->timing == MMC_TIMING_MMC_DDR52) in xenon_execute_tuning()
378 if (host->tuning_mode != SDHCI_TUNING_MODE_1) in xenon_execute_tuning()
384 static void xenon_enable_sdio_irq(struct mmc_host *mmc, int enable) in xenon_enable_sdio_irq()
390 u8 sdhc_id = priv->sdhc_id; in xenon_enable_sdio_irq()
412 host->mmc_host_ops.set_ios = xenon_set_ios; in xenon_replace_mmc_host_ops()
413 host->mmc_host_ops.start_signal_voltage_switch = in xenon_replace_mmc_host_ops()
415 host->mmc_host_ops.init_card = xenon_init_card; in xenon_replace_mmc_host_ops()
416 host->mmc_host_ops.execute_tuning = xenon_execute_tuning; in xenon_replace_mmc_host_ops()
417 host->mmc_host_ops.enable_sdio_irq = xenon_enable_sdio_irq; in xenon_replace_mmc_host_ops()
422 * sdhc-id: the index of current SDHC.
424 * tun-count: the interval between re-tuning
426 static int xenon_probe_params(struct platform_device *pdev) in xenon_probe_params()
428 struct device *dev = &pdev->dev; in xenon_probe_params()
430 struct mmc_host *mmc = host->mmc; in xenon_probe_params()
436 /* Disable HS200 on Armada AP806 */ in xenon_probe_params()
437 if (priv->hw_version == XENON_AP806) in xenon_probe_params()
438 host->quirks2 |= SDHCI_QUIRK2_BROKEN_HS200; in xenon_probe_params()
441 if (!device_property_read_u32(dev, "marvell,xenon-sdhc-id", &sdhc_id)) { in xenon_probe_params()
447 return -EINVAL; in xenon_probe_params()
450 priv->sdhc_id = sdhc_id; in xenon_probe_params()
453 if (!device_property_read_u32(dev, "marvell,xenon-tun-count", in xenon_probe_params()
456 dev_err(mmc_dev(mmc), "Wrong Re-tuning Count. Set default value %d\n", in xenon_probe_params()
461 priv->tuning_count = tuning_count; in xenon_probe_params()
466 static int xenon_sdhc_prepare(struct sdhci_host *host) in xenon_sdhc_prepare()
470 u8 sdhc_id = priv->sdhc_id; in xenon_sdhc_prepare()
481 /* Disable SDCLK-Off-While-Idle before card init */ in xenon_sdhc_prepare()
493 u8 sdhc_id = priv->sdhc_id; in xenon_sdhc_unprepare()
499 static int xenon_probe(struct platform_device *pdev) in xenon_probe()
502 struct device *dev = &pdev->dev; in xenon_probe()
505 int err; in xenon_probe()
515 priv->hw_version = (unsigned long)device_get_match_data(&pdev->dev); in xenon_probe()
523 if (dev->of_node) { in xenon_probe()
524 pltfm_host->clk = devm_clk_get(&pdev->dev, "core"); in xenon_probe()
525 if (IS_ERR(pltfm_host->clk)) { in xenon_probe()
526 err = PTR_ERR(pltfm_host->clk); in xenon_probe()
527 dev_err(&pdev->dev, "Failed to setup input clk: %d\n", err); in xenon_probe()
530 err = clk_prepare_enable(pltfm_host->clk); in xenon_probe()
534 priv->axi_clk = devm_clk_get(&pdev->dev, "axi"); in xenon_probe()
535 if (IS_ERR(priv->axi_clk)) { in xenon_probe()
536 err = PTR_ERR(priv->axi_clk); in xenon_probe()
537 if (err == -EPROBE_DEFER) in xenon_probe()
540 err = clk_prepare_enable(priv->axi_clk); in xenon_probe()
546 err = mmc_of_parse(host->mmc); in xenon_probe()
563 pm_runtime_get_noresume(&pdev->dev); in xenon_probe()
564 pm_runtime_set_active(&pdev->dev); in xenon_probe()
565 pm_runtime_set_autosuspend_delay(&pdev->dev, 50); in xenon_probe()
566 pm_runtime_use_autosuspend(&pdev->dev); in xenon_probe()
567 pm_runtime_enable(&pdev->dev); in xenon_probe()
568 pm_suspend_ignore_children(&pdev->dev, 1); in xenon_probe()
574 pm_runtime_put_autosuspend(&pdev->dev); in xenon_probe()
579 pm_runtime_disable(&pdev->dev); in xenon_probe()
580 pm_runtime_put_noidle(&pdev->dev); in xenon_probe()
583 clk_disable_unprepare(priv->axi_clk); in xenon_probe()
585 clk_disable_unprepare(pltfm_host->clk); in xenon_probe()
591 static int xenon_remove(struct platform_device *pdev) in xenon_remove()
597 pm_runtime_get_sync(&pdev->dev); in xenon_remove()
598 pm_runtime_disable(&pdev->dev); in xenon_remove()
599 pm_runtime_put_noidle(&pdev->dev); in xenon_remove()
604 clk_disable_unprepare(priv->axi_clk); in xenon_remove()
605 clk_disable_unprepare(pltfm_host->clk); in xenon_remove()
613 static int xenon_suspend(struct device *dev) in xenon_suspend()
618 int ret; in xenon_suspend()
622 priv->restore_needed = true; in xenon_suspend()
628 static int xenon_runtime_suspend(struct device *dev) in xenon_runtime_suspend()
633 int ret; in xenon_runtime_suspend()
639 if (host->tuning_mode != SDHCI_TUNING_MODE_3) in xenon_runtime_suspend()
640 mmc_retune_needed(host->mmc); in xenon_runtime_suspend()
642 clk_disable_unprepare(pltfm_host->clk); in xenon_runtime_suspend()
644 * Need to update the priv->clock here, or when runtime resume in xenon_runtime_suspend()
646 * which will cause cmd err in xenon_runtime_suspend()
648 priv->clock = 0; in xenon_runtime_suspend()
652 static int xenon_runtime_resume(struct device *dev) in xenon_runtime_resume()
657 int ret; in xenon_runtime_resume()
659 ret = clk_prepare_enable(pltfm_host->clk); in xenon_runtime_resume()
665 if (priv->restore_needed) { in xenon_runtime_resume()
669 priv->restore_needed = false; in xenon_runtime_resume()
677 clk_disable_unprepare(pltfm_host->clk); in xenon_runtime_resume()
691 { .compatible = "marvell,armada-ap806-sdhci", .data = (void *)XENON_AP806},
692 { .compatible = "marvell,armada-ap807-sdhci", .data = (void *)XENON_AP807},
693 { .compatible = "marvell,armada-cp110-sdhci", .data = (void *)XENON_CP110},
694 { .compatible = "marvell,armada-3700-sdhci", .data = (void *)XENON_A3700},
711 .name = "xenon-sdhci",