linux/arch/mips/ath79/clock.c
<<
>>
Prefs
   1/*
   2 *  Atheros AR71XX/AR724X/AR913X common routines
   3 *
   4 *  Copyright (C) 2011 Gabor Juhos <juhosg@openwrt.org>
   5 *
   6 *  This program is free software; you can redistribute it and/or modify it
   7 *  under the terms of the GNU General Public License version 2 as published
   8 *  by the Free Software Foundation.
   9 */
  10
  11#include <linux/kernel.h>
  12#include <linux/module.h>
  13#include <linux/init.h>
  14#include <linux/err.h>
  15#include <linux/clk.h>
  16
  17#include <asm/mach-ath79/ath79.h>
  18#include <asm/mach-ath79/ar71xx_regs.h>
  19#include "common.h"
  20
  21#define AR71XX_BASE_FREQ        40000000
  22#define AR724X_BASE_FREQ        5000000
  23#define AR913X_BASE_FREQ        5000000
  24
  25struct clk {
  26        unsigned long rate;
  27};
  28
  29static struct clk ath79_ref_clk;
  30static struct clk ath79_cpu_clk;
  31static struct clk ath79_ddr_clk;
  32static struct clk ath79_ahb_clk;
  33static struct clk ath79_wdt_clk;
  34static struct clk ath79_uart_clk;
  35
  36static void __init ar71xx_clocks_init(void)
  37{
  38        u32 pll;
  39        u32 freq;
  40        u32 div;
  41
  42        ath79_ref_clk.rate = AR71XX_BASE_FREQ;
  43
  44        pll = ath79_pll_rr(AR71XX_PLL_REG_CPU_CONFIG);
  45
  46        div = ((pll >> AR71XX_PLL_DIV_SHIFT) & AR71XX_PLL_DIV_MASK) + 1;
  47        freq = div * ath79_ref_clk.rate;
  48
  49        div = ((pll >> AR71XX_CPU_DIV_SHIFT) & AR71XX_CPU_DIV_MASK) + 1;
  50        ath79_cpu_clk.rate = freq / div;
  51
  52        div = ((pll >> AR71XX_DDR_DIV_SHIFT) & AR71XX_DDR_DIV_MASK) + 1;
  53        ath79_ddr_clk.rate = freq / div;
  54
  55        div = (((pll >> AR71XX_AHB_DIV_SHIFT) & AR71XX_AHB_DIV_MASK) + 1) * 2;
  56        ath79_ahb_clk.rate = ath79_cpu_clk.rate / div;
  57
  58        ath79_wdt_clk.rate = ath79_ahb_clk.rate;
  59        ath79_uart_clk.rate = ath79_ahb_clk.rate;
  60}
  61
  62static void __init ar724x_clocks_init(void)
  63{
  64        u32 pll;
  65        u32 freq;
  66        u32 div;
  67
  68        ath79_ref_clk.rate = AR724X_BASE_FREQ;
  69        pll = ath79_pll_rr(AR724X_PLL_REG_CPU_CONFIG);
  70
  71        div = ((pll >> AR724X_PLL_DIV_SHIFT) & AR724X_PLL_DIV_MASK);
  72        freq = div * ath79_ref_clk.rate;
  73
  74        div = ((pll >> AR724X_PLL_REF_DIV_SHIFT) & AR724X_PLL_REF_DIV_MASK);
  75        freq *= div;
  76
  77        ath79_cpu_clk.rate = freq;
  78
  79        div = ((pll >> AR724X_DDR_DIV_SHIFT) & AR724X_DDR_DIV_MASK) + 1;
  80        ath79_ddr_clk.rate = freq / div;
  81
  82        div = (((pll >> AR724X_AHB_DIV_SHIFT) & AR724X_AHB_DIV_MASK) + 1) * 2;
  83        ath79_ahb_clk.rate = ath79_cpu_clk.rate / div;
  84
  85        ath79_wdt_clk.rate = ath79_ahb_clk.rate;
  86        ath79_uart_clk.rate = ath79_ahb_clk.rate;
  87}
  88
  89static void __init ar913x_clocks_init(void)
  90{
  91        u32 pll;
  92        u32 freq;
  93        u32 div;
  94
  95        ath79_ref_clk.rate = AR913X_BASE_FREQ;
  96        pll = ath79_pll_rr(AR913X_PLL_REG_CPU_CONFIG);
  97
  98        div = ((pll >> AR913X_PLL_DIV_SHIFT) & AR913X_PLL_DIV_MASK);
  99        freq = div * ath79_ref_clk.rate;
 100
 101        ath79_cpu_clk.rate = freq;
 102
 103        div = ((pll >> AR913X_DDR_DIV_SHIFT) & AR913X_DDR_DIV_MASK) + 1;
 104        ath79_ddr_clk.rate = freq / div;
 105
 106        div = (((pll >> AR913X_AHB_DIV_SHIFT) & AR913X_AHB_DIV_MASK) + 1) * 2;
 107        ath79_ahb_clk.rate = ath79_cpu_clk.rate / div;
 108
 109        ath79_wdt_clk.rate = ath79_ahb_clk.rate;
 110        ath79_uart_clk.rate = ath79_ahb_clk.rate;
 111}
 112
 113void __init ath79_clocks_init(void)
 114{
 115        if (soc_is_ar71xx())
 116                ar71xx_clocks_init();
 117        else if (soc_is_ar724x())
 118                ar724x_clocks_init();
 119        else if (soc_is_ar913x())
 120                ar913x_clocks_init();
 121        else
 122                BUG();
 123
 124        pr_info("Clocks: CPU:%lu.%03luMHz, DDR:%lu.%03luMHz, AHB:%lu.%03luMHz, "
 125                "Ref:%lu.%03luMHz",
 126                ath79_cpu_clk.rate / 1000000,
 127                (ath79_cpu_clk.rate / 1000) % 1000,
 128                ath79_ddr_clk.rate / 1000000,
 129                (ath79_ddr_clk.rate / 1000) % 1000,
 130                ath79_ahb_clk.rate / 1000000,
 131                (ath79_ahb_clk.rate / 1000) % 1000,
 132                ath79_ref_clk.rate / 1000000,
 133                (ath79_ref_clk.rate / 1000) % 1000);
 134}
 135
 136/*
 137 * Linux clock API
 138 */
 139struct clk *clk_get(struct device *dev, const char *id)
 140{
 141        if (!strcmp(id, "ref"))
 142                return &ath79_ref_clk;
 143
 144        if (!strcmp(id, "cpu"))
 145                return &ath79_cpu_clk;
 146
 147        if (!strcmp(id, "ddr"))
 148                return &ath79_ddr_clk;
 149
 150        if (!strcmp(id, "ahb"))
 151                return &ath79_ahb_clk;
 152
 153        if (!strcmp(id, "wdt"))
 154                return &ath79_wdt_clk;
 155
 156        if (!strcmp(id, "uart"))
 157                return &ath79_uart_clk;
 158
 159        return ERR_PTR(-ENOENT);
 160}
 161EXPORT_SYMBOL(clk_get);
 162
 163int clk_enable(struct clk *clk)
 164{
 165        return 0;
 166}
 167EXPORT_SYMBOL(clk_enable);
 168
 169void clk_disable(struct clk *clk)
 170{
 171}
 172EXPORT_SYMBOL(clk_disable);
 173
 174unsigned long clk_get_rate(struct clk *clk)
 175{
 176        return clk->rate;
 177}
 178EXPORT_SYMBOL(clk_get_rate);
 179
 180void clk_put(struct clk *clk)
 181{
 182}
 183EXPORT_SYMBOL(clk_put);
 184