* Jaehoon Chung <jh80.chung@samsung.com>
*/
+#include <clk.h>
#include <dwmmc.h>
#include <fdtdec.h>
#include <asm/global_data.h>
#include <asm/arch/pinmux.h>
#include <asm/arch/power.h>
#include <asm/gpio.h>
+#include <linux/err.h>
#include <linux/printk.h>
#define DWMMC_MAX_CH_NUM 4
#ifdef CONFIG_DM_MMC
struct dwmci_host host;
#endif
+ struct clk clk;
u32 sdr_timing;
};
#endif
}
+/**
+ * exynos_dwmmc_get_sclk - Get source clock (SDCLKIN) rate
+ * @host: MMC controller object
+ * @rate: Will contain clock rate, Hz
+ *
+ * Return: 0 on success or negative value on error
+ */
+static int exynos_dwmmc_get_sclk(struct dwmci_host *host, unsigned long *rate)
+{
+#ifdef CONFIG_CPU_V7A
+ *rate = get_mmc_clk(host->dev_index);
+#else
+ struct dwmci_exynos_priv_data *priv = exynos_dwmmc_get_priv(host);
+
+ *rate = clk_get_rate(&priv->clk);
+#endif
+
+ if (IS_ERR_VALUE(*rate))
+ return *rate;
+
+ return 0;
+}
+
+/**
+ * exynos_dwmmc_set_sclk - Set source clock (SDCLKIN) rate
+ * @host: MMC controller object
+ * @rate: Desired clock rate, Hz
+ *
+ * Return: 0 on success or negative value on error
+ */
+static int exynos_dwmmc_set_sclk(struct dwmci_host *host, unsigned long rate)
+{
+ int err;
+
+#ifdef CONFIG_CPU_V7A
+ unsigned long sclk;
+ unsigned int div;
+
+ err = exynos_dwmmc_get_sclk(host, &sclk);
+ if (err)
+ return err;
+
+ div = DIV_ROUND_UP(sclk, rate);
+ set_mmc_clk(host->dev_index, div);
+#else
+ struct dwmci_exynos_priv_data *priv = exynos_dwmmc_get_priv(host);
+
+ err = clk_set_rate(&priv->clk, rate);
+ if (err < 0)
+ return err;
+#endif
+
+ return 0;
+}
+
/*
* Function used as callback function to initialise the
* CLKSEL register for every mmc channel.
{
unsigned long sclk;
int8_t clk_div;
+ int err;
/*
* Since SDCLKIN is divided inside controller by the DIVRATIO
*/
clk_div = ((dwmci_readl(host, DWMCI_CLKSEL) >> DWMCI_DIVRATIO_BIT)
& DWMCI_DIVRATIO_MASK) + 1;
- sclk = get_mmc_clk(host->dev_index);
+
+ err = exynos_dwmmc_get_sclk(host, &sclk);
+ if (err) {
+ printf("DWMMC%d: failed to get clock rate (%d)\n",
+ host->dev_index, err);
+ return 0;
+ }
/*
* Assume to know divider value.
static int exynos_dwmci_core_init(struct dwmci_host *host)
{
- unsigned int div;
- unsigned long freq, sclk;
+ unsigned long freq;
+ int err;
if (host->bus_hz)
freq = host->bus_hz;
else
freq = DWMMC_MAX_FREQ;
- /* request mmc clock vlaue of 52MHz. */
- sclk = get_mmc_clk(host->dev_index);
- div = DIV_ROUND_UP(sclk, freq);
- /* set the clock divisor for mmc */
- set_mmc_clk(host->dev_index, div);
+ err = exynos_dwmmc_set_sclk(host, freq);
+ if (err) {
+ printf("DWMMC%d: failed to set clock rate on probe (%d); "
+ "continue anyway\n", host->dev_index, err);
+ }
host->name = "EXYNOS DWMMC";
#ifdef CONFIG_EXYNOS5420
struct dwmci_host *host = &priv->host;
int err;
+#ifndef CONFIG_CPU_V7A
+ err = clk_get_by_index(dev, 1, &priv->clk); /* ciu */
+ if (err)
+ return err;
+#endif
+
err = exynos_dwmci_get_config(dev, gd->fdt_blob, dev_of_offset(dev),
host, priv);
if (err)