Path: blob/master/arch/mips/kernel/cpufreq/loongson2_clock.c
10820 views
/*1* Copyright (C) 2006 - 2008 Lemote Inc. & Insititute of Computing Technology2* Author: Yanhua, [email protected]3*4* This file is subject to the terms and conditions of the GNU General Public5* License. See the file "COPYING" in the main directory of this archive6* for more details.7*/89#include <linux/cpufreq.h>10#include <linux/platform_device.h>1112#include <asm/clock.h>1314#include <loongson.h>1516static LIST_HEAD(clock_list);17static DEFINE_SPINLOCK(clock_lock);18static DEFINE_MUTEX(clock_list_sem);1920/* Minimum CLK support */21enum {22DC_ZERO, DC_25PT = 2, DC_37PT, DC_50PT, DC_62PT, DC_75PT,23DC_87PT, DC_DISABLE, DC_RESV24};2526struct cpufreq_frequency_table loongson2_clockmod_table[] = {27{DC_RESV, CPUFREQ_ENTRY_INVALID},28{DC_ZERO, CPUFREQ_ENTRY_INVALID},29{DC_25PT, 0},30{DC_37PT, 0},31{DC_50PT, 0},32{DC_62PT, 0},33{DC_75PT, 0},34{DC_87PT, 0},35{DC_DISABLE, 0},36{DC_RESV, CPUFREQ_TABLE_END},37};38EXPORT_SYMBOL_GPL(loongson2_clockmod_table);3940static struct clk cpu_clk = {41.name = "cpu_clk",42.flags = CLK_ALWAYS_ENABLED | CLK_RATE_PROPAGATES,43.rate = 800000000,44};4546struct clk *clk_get(struct device *dev, const char *id)47{48return &cpu_clk;49}50EXPORT_SYMBOL(clk_get);5152static void propagate_rate(struct clk *clk)53{54struct clk *clkp;5556list_for_each_entry(clkp, &clock_list, node) {57if (likely(clkp->parent != clk))58continue;59if (likely(clkp->ops && clkp->ops->recalc))60clkp->ops->recalc(clkp);61if (unlikely(clkp->flags & CLK_RATE_PROPAGATES))62propagate_rate(clkp);63}64}6566int clk_enable(struct clk *clk)67{68return 0;69}70EXPORT_SYMBOL(clk_enable);7172void clk_disable(struct clk *clk)73{74}75EXPORT_SYMBOL(clk_disable);7677unsigned long clk_get_rate(struct clk *clk)78{79return (unsigned long)clk->rate;80}81EXPORT_SYMBOL(clk_get_rate);8283void clk_put(struct clk *clk)84{85}86EXPORT_SYMBOL(clk_put);8788int clk_set_rate(struct clk *clk, unsigned long rate)89{90return clk_set_rate_ex(clk, rate, 0);91}92EXPORT_SYMBOL_GPL(clk_set_rate);9394int clk_set_rate_ex(struct clk *clk, unsigned long rate, int algo_id)95{96int ret = 0;97int regval;98int i;99100if (likely(clk->ops && clk->ops->set_rate)) {101unsigned long flags;102103spin_lock_irqsave(&clock_lock, flags);104ret = clk->ops->set_rate(clk, rate, algo_id);105spin_unlock_irqrestore(&clock_lock, flags);106}107108if (unlikely(clk->flags & CLK_RATE_PROPAGATES))109propagate_rate(clk);110111for (i = 0; loongson2_clockmod_table[i].frequency != CPUFREQ_TABLE_END;112i++) {113if (loongson2_clockmod_table[i].frequency ==114CPUFREQ_ENTRY_INVALID)115continue;116if (rate == loongson2_clockmod_table[i].frequency)117break;118}119if (rate != loongson2_clockmod_table[i].frequency)120return -ENOTSUPP;121122clk->rate = rate;123124regval = LOONGSON_CHIPCFG0;125regval = (regval & ~0x7) | (loongson2_clockmod_table[i].index - 1);126LOONGSON_CHIPCFG0 = regval;127128return ret;129}130EXPORT_SYMBOL_GPL(clk_set_rate_ex);131132long clk_round_rate(struct clk *clk, unsigned long rate)133{134if (likely(clk->ops && clk->ops->round_rate)) {135unsigned long flags, rounded;136137spin_lock_irqsave(&clock_lock, flags);138rounded = clk->ops->round_rate(clk, rate);139spin_unlock_irqrestore(&clock_lock, flags);140141return rounded;142}143144return rate;145}146EXPORT_SYMBOL_GPL(clk_round_rate);147148/*149* This is the simple version of Loongson-2 wait, Maybe we need do this in150* interrupt disabled content151*/152153DEFINE_SPINLOCK(loongson2_wait_lock);154void loongson2_cpu_wait(void)155{156u32 cpu_freq;157unsigned long flags;158159spin_lock_irqsave(&loongson2_wait_lock, flags);160cpu_freq = LOONGSON_CHIPCFG0;161LOONGSON_CHIPCFG0 &= ~0x7; /* Put CPU into wait mode */162LOONGSON_CHIPCFG0 = cpu_freq; /* Restore CPU state */163spin_unlock_irqrestore(&loongson2_wait_lock, flags);164}165EXPORT_SYMBOL_GPL(loongson2_cpu_wait);166167MODULE_AUTHOR("Yanhua <[email protected]>");168MODULE_DESCRIPTION("cpufreq driver for Loongson 2F");169MODULE_LICENSE("GPL");170171172