1/* 2 * Copyright (C) 2006 - 2008 Lemote Inc. & Insititute of Computing Technology 3 * Author: Yanhua, yanh@lemote.com 4 * 5 * This file is subject to the terms and conditions of the GNU General Public 6 * License. See the file "COPYING" in the main directory of this archive 7 * for more details. 8 */ 9 10#include <linux/cpufreq.h> 11#include <linux/platform_device.h> 12 13#include <asm/clock.h> 14 15#include <loongson.h> 16 17static LIST_HEAD(clock_list); 18static DEFINE_SPINLOCK(clock_lock); 19static DEFINE_MUTEX(clock_list_sem); 20 21/* Minimum CLK support */ 22enum { 23 DC_ZERO, DC_25PT = 2, DC_37PT, DC_50PT, DC_62PT, DC_75PT, 24 DC_87PT, DC_DISABLE, DC_RESV 25}; 26 27struct cpufreq_frequency_table loongson2_clockmod_table[] = { 28 {DC_RESV, CPUFREQ_ENTRY_INVALID}, 29 {DC_ZERO, CPUFREQ_ENTRY_INVALID}, 30 {DC_25PT, 0}, 31 {DC_37PT, 0}, 32 {DC_50PT, 0}, 33 {DC_62PT, 0}, 34 {DC_75PT, 0}, 35 {DC_87PT, 0}, 36 {DC_DISABLE, 0}, 37 {DC_RESV, CPUFREQ_TABLE_END}, 38}; 39EXPORT_SYMBOL_GPL(loongson2_clockmod_table); 40 41static struct clk cpu_clk = { 42 .name = "cpu_clk", 43 .flags = CLK_ALWAYS_ENABLED | CLK_RATE_PROPAGATES, 44 .rate = 800000000, 45}; 46 47struct clk *clk_get(struct device *dev, const char *id) 48{ 49 return &cpu_clk; 50} 51EXPORT_SYMBOL(clk_get); 52 53static void propagate_rate(struct clk *clk) 54{ 55 struct clk *clkp; 56 57 list_for_each_entry(clkp, &clock_list, node) { 58 if (likely(clkp->parent != clk)) 59 continue; 60 if (likely(clkp->ops && clkp->ops->recalc)) 61 clkp->ops->recalc(clkp); 62 if (unlikely(clkp->flags & CLK_RATE_PROPAGATES)) 63 propagate_rate(clkp); 64 } 65} 66 67int clk_enable(struct clk *clk) 68{ 69 return 0; 70} 71EXPORT_SYMBOL(clk_enable); 72 73void clk_disable(struct clk *clk) 74{ 75} 76EXPORT_SYMBOL(clk_disable); 77 78unsigned long clk_get_rate(struct clk *clk) 79{ 80 return (unsigned long)clk->rate; 81} 82EXPORT_SYMBOL(clk_get_rate); 83 84void clk_put(struct clk *clk) 85{ 86} 87EXPORT_SYMBOL(clk_put); 88 89int clk_set_rate(struct clk *clk, unsigned long rate) 90{ 91 return clk_set_rate_ex(clk, rate, 0); 92} 93EXPORT_SYMBOL_GPL(clk_set_rate); 94 95int clk_set_rate_ex(struct clk *clk, unsigned long rate, int algo_id) 96{ 97 int ret = 0; 98 int regval; 99 int i; 100 101 if (likely(clk->ops && clk->ops->set_rate)) { 102 unsigned long flags; 103 104 spin_lock_irqsave(&clock_lock, flags); 105 ret = clk->ops->set_rate(clk, rate, algo_id); 106 spin_unlock_irqrestore(&clock_lock, flags); 107 } 108 109 if (unlikely(clk->flags & CLK_RATE_PROPAGATES)) 110 propagate_rate(clk); 111 112 for (i = 0; loongson2_clockmod_table[i].frequency != CPUFREQ_TABLE_END; 113 i++) { 114 if (loongson2_clockmod_table[i].frequency == 115 CPUFREQ_ENTRY_INVALID) 116 continue; 117 if (rate == loongson2_clockmod_table[i].frequency) 118 break; 119 } 120 if (rate != loongson2_clockmod_table[i].frequency) 121 return -ENOTSUPP; 122 123 clk->rate = rate; 124 125 regval = LOONGSON_CHIPCFG0; 126 regval = (regval & ~0x7) | (loongson2_clockmod_table[i].index - 1); 127 LOONGSON_CHIPCFG0 = regval; 128 129 return ret; 130} 131EXPORT_SYMBOL_GPL(clk_set_rate_ex); 132 133long clk_round_rate(struct clk *clk, unsigned long rate) 134{ 135 if (likely(clk->ops && clk->ops->round_rate)) { 136 unsigned long flags, rounded; 137 138 spin_lock_irqsave(&clock_lock, flags); 139 rounded = clk->ops->round_rate(clk, rate); 140 spin_unlock_irqrestore(&clock_lock, flags); 141 142 return rounded; 143 } 144 145 return rate; 146} 147EXPORT_SYMBOL_GPL(clk_round_rate); 148 149/* 150 * This is the simple version of Loongson-2 wait, Maybe we need do this in 151 * interrupt disabled content 152 */ 153 154DEFINE_SPINLOCK(loongson2_wait_lock); 155void loongson2_cpu_wait(void) 156{ 157 u32 cpu_freq; 158 unsigned long flags; 159 160 spin_lock_irqsave(&loongson2_wait_lock, flags); 161 cpu_freq = LOONGSON_CHIPCFG0; 162 LOONGSON_CHIPCFG0 &= ~0x7; /* Put CPU into wait mode */ 163 LOONGSON_CHIPCFG0 = cpu_freq; /* Restore CPU state */ 164 spin_unlock_irqrestore(&loongson2_wait_lock, flags); 165} 166EXPORT_SYMBOL_GPL(loongson2_cpu_wait); 167 168MODULE_AUTHOR("Yanhua <yanh@lemote.com>"); 169MODULE_DESCRIPTION("cpufreq driver for Loongson 2F"); 170MODULE_LICENSE("GPL"); 171