]> git.sur5r.net Git - u-boot/blobdiff - drivers/clk/at91/clk-utmi.c
clk: clk_stm32f: Rework SDMMC stm32_clk_get_rate() part
[u-boot] / drivers / clk / at91 / clk-utmi.c
index 369a6870d8796bbc24721c50655731bd5347c5a2..875bf293f9cdd637ccf47955a3733a4592a0f8d0 100644 (file)
@@ -7,24 +7,81 @@
 
 #include <common.h>
 #include <clk-uclass.h>
-#include <dm/device.h>
+#include <dm.h>
+#include <syscon.h>
 #include <linux/io.h>
 #include <mach/at91_pmc.h>
+#include <mach/sama5_sfr.h>
 #include "pmc.h"
 
 DECLARE_GLOBAL_DATA_PTR;
 
-#define UTMI_FIXED_MUL         40
+/*
+ * The purpose of this clock is to generate a 480 MHz signal. A different
+ * rate can't be configured.
+ */
+#define UTMI_RATE      480000000
 
 static int utmi_clk_enable(struct clk *clk)
 {
        struct pmc_platdata *plat = dev_get_platdata(clk->dev);
        struct at91_pmc *pmc = plat->reg_base;
+       struct clk clk_dev;
+       ulong clk_rate;
+       u32 utmi_ref_clk_freq;
        u32 tmp;
+       int err;
 
        if (readl(&pmc->sr) & AT91_PMC_LOCKU)
                return 0;
 
+       /*
+        * If mainck rate is different from 12 MHz, we have to configure the
+        * FREQ field of the SFR_UTMICKTRIM register to generate properly
+        * the utmi clock.
+        */
+       err = clk_get_by_index(clk->dev, 0, &clk_dev);
+       if (err)
+               return -EINVAL;
+
+       clk_rate = clk_get_rate(&clk_dev);
+       switch (clk_rate) {
+       case 12000000:
+               utmi_ref_clk_freq = 0;
+               break;
+       case 16000000:
+               utmi_ref_clk_freq = 1;
+               break;
+       case 24000000:
+               utmi_ref_clk_freq = 2;
+               break;
+       /*
+        * Not supported on SAMA5D2 but it's not an issue since MAINCK
+        * maximum value is 24 MHz.
+        */
+       case 48000000:
+               utmi_ref_clk_freq = 3;
+               break;
+       default:
+               printf("UTMICK: unsupported mainck rate\n");
+               return -EINVAL;
+       }
+
+       if (plat->regmap_sfr) {
+               err = regmap_read(plat->regmap_sfr, AT91_SFR_UTMICKTRIM, &tmp);
+               if (err)
+                       return -EINVAL;
+
+               tmp &= ~AT91_UTMICKTRIM_FREQ;
+               tmp |= utmi_ref_clk_freq;
+               err = regmap_write(plat->regmap_sfr, AT91_SFR_UTMICKTRIM, tmp);
+               if (err)
+                       return -EINVAL;
+       } else if (utmi_ref_clk_freq) {
+               printf("UTMICK: sfr node required\n");
+               return -EINVAL;
+       }
+
        tmp = readl(&pmc->uckr);
        tmp |= AT91_PMC_UPLLEN |
               AT91_PMC_UPLLCOUNT |
@@ -39,7 +96,8 @@ static int utmi_clk_enable(struct clk *clk)
 
 static ulong utmi_clk_get_rate(struct clk *clk)
 {
-       return gd->arch.main_clk_rate_hz * UTMI_FIXED_MUL;
+       /* UTMI clk rate is fixed. */
+       return UTMI_RATE;
 }
 
 static struct clk_ops utmi_clk_ops = {
@@ -47,6 +105,20 @@ static struct clk_ops utmi_clk_ops = {
        .get_rate = utmi_clk_get_rate,
 };
 
+static int utmi_clk_ofdata_to_platdata(struct udevice *dev)
+{
+       struct pmc_platdata *plat = dev_get_platdata(dev);
+       struct udevice *syscon;
+
+       uclass_get_device_by_phandle(UCLASS_SYSCON, dev,
+                                    "regmap-sfr", &syscon);
+
+       if (syscon)
+               plat->regmap_sfr = syscon_get_regmap(syscon);
+
+       return 0;
+}
+
 static int utmi_clk_probe(struct udevice *dev)
 {
        return at91_pmc_core_probe(dev);
@@ -62,6 +134,7 @@ U_BOOT_DRIVER(at91sam9x5_utmi_clk) = {
        .id = UCLASS_CLK,
        .of_match = utmi_clk_match,
        .probe = utmi_clk_probe,
+       .ofdata_to_platdata = utmi_clk_ofdata_to_platdata,
        .platdata_auto_alloc_size = sizeof(struct pmc_platdata),
        .ops = &utmi_clk_ops,
 };