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 25 struct clk { 26 unsigned long rate; 27 }; 28 29 static struct clk ath79_ref_clk; 30 static struct clk ath79_cpu_clk; 31 static struct clk ath79_ddr_clk; 32 static struct clk ath79_ahb_clk; 33 static struct clk ath79_wdt_clk; 34 static struct clk ath79_uart_clk; 35 36 static 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 62 static 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 89 static 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 113 void __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 */ 139 struct 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 } 161 EXPORT_SYMBOL(clk_get); 162 163 int clk_enable(struct clk *clk) 164 { 165 return 0; 166 } 167 EXPORT_SYMBOL(clk_enable); 168 169 void clk_disable(struct clk *clk) 170 { 171 } 172 EXPORT_SYMBOL(clk_disable); 173 174 unsigned long clk_get_rate(struct clk *clk) 175 { 176 return clk->rate; 177 } 178 EXPORT_SYMBOL(clk_get_rate); 179 180 void clk_put(struct clk *clk) 181 { 182 } 183 EXPORT_SYMBOL(clk_put); 184