summaryrefslogtreecommitdiff
path: root/drivers/mmc/host/dw_mmc-pltfm.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/mmc/host/dw_mmc-pltfm.c')
-rw-r--r--drivers/mmc/host/dw_mmc-pltfm.c96
1 files changed, 51 insertions, 45 deletions
diff --git a/drivers/mmc/host/dw_mmc-pltfm.c b/drivers/mmc/host/dw_mmc-pltfm.c
index ee525565aa77..de820ffd2133 100644
--- a/drivers/mmc/host/dw_mmc-pltfm.c
+++ b/drivers/mmc/host/dw_mmc-pltfm.c
@@ -1,13 +1,9 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
/*
* Synopsys DesignWare Multimedia Card Interface driver
*
* Copyright (C) 2009 NXP Semiconductors
* Copyright (C) 2009, 2010 Imagination Technologies Ltd.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
*/
#include <linux/err.h>
@@ -16,29 +12,26 @@
#include <linux/io.h>
#include <linux/irq.h>
#include <linux/platform_device.h>
+#include <linux/pm_runtime.h>
#include <linux/slab.h>
#include <linux/mmc/host.h>
#include <linux/mmc/mmc.h>
-#include <linux/mmc/dw_mmc.h>
#include <linux/of.h>
+#include <linux/mfd/altera-sysmgr.h>
+#include <linux/regmap.h>
#include "dw_mmc.h"
+#include "dw_mmc-pltfm.h"
-static void dw_mci_rockchip_prepare_command(struct dw_mci *host, u32 *cmdr)
-{
- *cmdr |= SDMMC_CMD_USE_HOLD_REG;
-}
-
-static const struct dw_mci_drv_data rockchip_drv_data = {
- .prepare_command = dw_mci_rockchip_prepare_command,
-};
+#define SOCFPGA_DW_MMC_CLK_PHASE_STEP 45
+#define SYSMGR_SDMMC_CTRL_SET(smplsel, drvsel, reg_shift) \
+ ((((smplsel) & 0x7) << reg_shift) | (((drvsel) & 0x7) << 0))
int dw_mci_pltfm_register(struct platform_device *pdev,
const struct dw_mci_drv_data *drv_data)
{
struct dw_mci *host;
struct resource *regs;
- int ret;
host = devm_kzalloc(&pdev->dev, sizeof(struct dw_mci), GFP_KERNEL);
if (!host)
@@ -53,51 +46,64 @@ int dw_mci_pltfm_register(struct platform_device *pdev,
host->irq_flags = 0;
host->pdata = pdev->dev.platform_data;
- regs = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- host->regs = devm_ioremap_resource(&pdev->dev, regs);
+ host->regs = devm_platform_get_and_ioremap_resource(pdev, 0, &regs);
if (IS_ERR(host->regs))
return PTR_ERR(host->regs);
- if (drv_data && drv_data->init) {
- ret = drv_data->init(host);
- if (ret)
- return ret;
- }
+ /* Get registers' physical base address */
+ host->phy_regs = regs->start;
platform_set_drvdata(pdev, host);
return dw_mci_probe(host);
}
EXPORT_SYMBOL_GPL(dw_mci_pltfm_register);
-#ifdef CONFIG_PM_SLEEP
-/*
- * TODO: we should probably disable the clock to the card in the suspend path.
- */
-static int dw_mci_pltfm_suspend(struct device *dev)
+const struct dev_pm_ops dw_mci_pltfm_pmops = {
+ SET_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend,
+ pm_runtime_force_resume)
+ SET_RUNTIME_PM_OPS(dw_mci_runtime_suspend,
+ dw_mci_runtime_resume,
+ NULL)
+};
+EXPORT_SYMBOL_GPL(dw_mci_pltfm_pmops);
+
+static int dw_mci_socfpga_priv_init(struct dw_mci *host)
{
- struct dw_mci *host = dev_get_drvdata(dev);
+ struct device_node *np = host->dev->of_node;
+ struct regmap *sys_mgr_base_addr;
+ u32 clk_phase[2] = {0}, reg_offset, reg_shift;
+ int i, rc, hs_timing;
+
+ rc = of_property_read_variable_u32_array(np, "clk-phase-sd-hs", &clk_phase[0], 2, 0);
+ if (rc < 0)
+ return 0;
+
+ sys_mgr_base_addr = altr_sysmgr_regmap_lookup_by_phandle(np, "altr,sysmgr-syscon");
+ if (IS_ERR(sys_mgr_base_addr)) {
+ dev_warn(host->dev, "clk-phase-sd-hs was specified, but failed to find altr,sys-mgr regmap!\n");
+ return 0;
+ }
- return dw_mci_suspend(host);
-}
+ of_property_read_u32_index(np, "altr,sysmgr-syscon", 1, &reg_offset);
+ of_property_read_u32_index(np, "altr,sysmgr-syscon", 2, &reg_shift);
-static int dw_mci_pltfm_resume(struct device *dev)
-{
- struct dw_mci *host = dev_get_drvdata(dev);
+ for (i = 0; i < ARRAY_SIZE(clk_phase); i++)
+ clk_phase[i] /= SOCFPGA_DW_MMC_CLK_PHASE_STEP;
+
+ hs_timing = SYSMGR_SDMMC_CTRL_SET(clk_phase[0], clk_phase[1], reg_shift);
+ regmap_write(sys_mgr_base_addr, reg_offset, hs_timing);
- return dw_mci_resume(host);
+ return 0;
}
-#else
-#define dw_mci_pltfm_suspend NULL
-#define dw_mci_pltfm_resume NULL
-#endif /* CONFIG_PM_SLEEP */
-SIMPLE_DEV_PM_OPS(dw_mci_pltfm_pmops, dw_mci_pltfm_suspend, dw_mci_pltfm_resume);
-EXPORT_SYMBOL_GPL(dw_mci_pltfm_pmops);
+static const struct dw_mci_drv_data socfpga_drv_data = {
+ .init = dw_mci_socfpga_priv_init,
+};
static const struct of_device_id dw_mci_pltfm_match[] = {
{ .compatible = "snps,dw-mshc", },
- { .compatible = "rockchip,rk2928-dw-mshc",
- .data = &rockchip_drv_data },
+ { .compatible = "altr,socfpga-dw-mshc", .data = &socfpga_drv_data, },
+ { .compatible = "img,pistachio-dw-mshc", },
{},
};
MODULE_DEVICE_TABLE(of, dw_mci_pltfm_match);
@@ -115,12 +121,11 @@ static int dw_mci_pltfm_probe(struct platform_device *pdev)
return dw_mci_pltfm_register(pdev, drv_data);
}
-int dw_mci_pltfm_remove(struct platform_device *pdev)
+void dw_mci_pltfm_remove(struct platform_device *pdev)
{
struct dw_mci *host = platform_get_drvdata(pdev);
dw_mci_remove(host);
- return 0;
}
EXPORT_SYMBOL_GPL(dw_mci_pltfm_remove);
@@ -129,7 +134,8 @@ static struct platform_driver dw_mci_pltfm_driver = {
.remove = dw_mci_pltfm_remove,
.driver = {
.name = "dw_mmc",
- .of_match_table = of_match_ptr(dw_mci_pltfm_match),
+ .probe_type = PROBE_PREFER_ASYNCHRONOUS,
+ .of_match_table = dw_mci_pltfm_match,
.pm = &dw_mci_pltfm_pmops,
},
};