]> Git Repo - J-u-boot.git/blobdiff - arch/arm/mach-at91/armv7/clock.c
arm: at91: clock: Add the generated clock support
[J-u-boot.git] / arch / arm / mach-at91 / armv7 / clock.c
index 0bf453eff57c93145fce07967319946f549977ad..41dbf16afdce67ed40d5b96c4d0107bd6faaa07b 100644 (file)
@@ -5,11 +5,13 @@
  * Copyright (C) 2005 Ivan Kokshaysky
  * Copyright (C) 2009 Jean-Christophe PLAGNIOL-VILLARD <[email protected]>
  * Copyright (C) 2013 Bo Shen <[email protected]>
+ * Copyright (C) 2015 Wenyou Yang <[email protected]>
  *
  * SPDX-License-Identifier:    GPL-2.0+
  */
 
 #include <common.h>
+#include <asm/errno.h>
 #include <asm/io.h>
 #include <asm/arch/hardware.h>
 #include <asm/arch/at91_pmc.h>
@@ -173,3 +175,96 @@ void at91_periph_clk_disable(int id)
 
        writel(regval, &pmc->pcr);
 }
+
+int at91_enable_periph_generated_clk(u32 id, u32 clk_source, u32 div)
+{
+       struct at91_pmc *pmc = (struct at91_pmc *)ATMEL_BASE_PMC;
+       u32 regval, status;
+       u32 timeout = 1000;
+
+       if (id > AT91_PMC_PCR_PID_MASK)
+               return -EINVAL;
+
+       if (div > 0xff)
+               return -EINVAL;
+
+       writel(id, &pmc->pcr);
+       regval = readl(&pmc->pcr);
+       regval &= ~AT91_PMC_PCR_GCKCSS;
+       regval &= ~AT91_PMC_PCR_GCKDIV;
+
+       switch (clk_source) {
+       case GCK_CSS_SLOW_CLK:
+               regval |= AT91_PMC_PCR_GCKCSS_SLOW_CLK;
+               break;
+       case GCK_CSS_MAIN_CLK:
+               regval |= AT91_PMC_PCR_GCKCSS_MAIN_CLK;
+               break;
+       case GCK_CSS_PLLA_CLK:
+               regval |= AT91_PMC_PCR_GCKCSS_PLLA_CLK;
+               break;
+       case GCK_CSS_UPLL_CLK:
+               regval |= AT91_PMC_PCR_GCKCSS_UPLL_CLK;
+               break;
+       case GCK_CSS_MCK_CLK:
+               regval |= AT91_PMC_PCR_GCKCSS_MCK_CLK;
+               break;
+       case GCK_CSS_AUDIO_CLK:
+               regval |= AT91_PMC_PCR_GCKCSS_AUDIO_CLK;
+               break;
+       default:
+               printf("Error GCK clock source selection!\n");
+               return -EINVAL;
+       }
+
+       regval |= AT91_PMC_PCR_CMD_WRITE |
+                 AT91_PMC_PCR_GCKDIV_(div) |
+                 AT91_PMC_PCR_GCKEN;
+
+       writel(regval, &pmc->pcr);
+
+       do {
+               udelay(1);
+               status = readl(&pmc->sr);
+       } while ((!!(--timeout)) && (!(status & AT91_PMC_GCKRDY)));
+
+       if (!timeout)
+               printf("Timeout waiting for GCK ready!\n");
+
+       return 0;
+}
+
+u32 at91_get_periph_generated_clk(u32 id)
+{
+       struct at91_pmc *pmc = (struct at91_pmc *)ATMEL_BASE_PMC;
+       u32 regval, clk_source, div;
+       u32 freq;
+
+       if (id > AT91_PMC_PCR_PID_MASK)
+               return 0;
+
+       writel(id, &pmc->pcr);
+       regval = readl(&pmc->pcr);
+
+       clk_source = regval & AT91_PMC_PCR_GCKCSS;
+       switch (clk_source) {
+       case AT91_PMC_PCR_GCKCSS_SLOW_CLK:
+               freq = CONFIG_SYS_AT91_SLOW_CLOCK;
+               break;
+       case AT91_PMC_PCR_GCKCSS_MAIN_CLK:
+               freq = gd->arch.main_clk_rate_hz;
+               break;
+       case AT91_PMC_PCR_GCKCSS_PLLA_CLK:
+               freq = gd->arch.plla_rate_hz;
+               break;
+       default:
+               printf("Improper GCK clock source selection!\n");
+               freq = 0;
+               break;
+       }
+
+       div = ((regval & AT91_PMC_PCR_GCKDIV) >> AT91_PMC_PCR_GCKDIV_OFFSET);
+       div += 1;
+
+       return freq / div;
+}
This page took 0.028264 seconds and 4 git commands to generate.