at v3.2 183 lines 4.2 kB view raw
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);