2 * Copyright (C) 2004-2007 Atmel Corporation
4 * Based on MIPS implementation arch/mips/kernel/time.c
5 * Copyright 2001 MontaVista Software Inc.
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License version 2 as
9 * published by the Free Software Foundation.
14 #include <linux/kernel.h>
15 #include <linux/types.h>
16 #include <linux/init.h>
17 #include <linux/cpufreq.h>
19 #include <linux/clk.h>
20 #include <linux/err.h>
21 #include <asm/system.h>
23 static struct clk
*cpuclk
;
25 static int at32_verify_speed(struct cpufreq_policy
*policy
)
30 cpufreq_verify_within_limits(policy
, policy
->cpuinfo
.min_freq
,
31 policy
->cpuinfo
.max_freq
);
35 static unsigned int at32_get_speed(unsigned int cpu
)
40 return (unsigned int)((clk_get_rate(cpuclk
) + 500) / 1000);
43 static unsigned int ref_freq
;
44 static unsigned long loops_per_jiffy_ref
;
46 static int at32_set_target(struct cpufreq_policy
*policy
,
47 unsigned int target_freq
,
48 unsigned int relation
)
50 struct cpufreq_freqs freqs
;
53 /* Convert target_freq from kHz to Hz */
54 freq
= clk_round_rate(cpuclk
, target_freq
* 1000);
56 /* Check if policy->min <= new_freq <= policy->max */
57 if(freq
< (policy
->min
* 1000) || freq
> (policy
->max
* 1000))
60 pr_debug("cpufreq: requested frequency %u Hz\n", target_freq
* 1000);
62 freqs
.old
= at32_get_speed(0);
63 freqs
.new = (freq
+ 500) / 1000;
69 loops_per_jiffy_ref
= boot_cpu_data
.loops_per_jiffy
;
72 cpufreq_notify_transition(&freqs
, CPUFREQ_PRECHANGE
);
73 if (freqs
.old
< freqs
.new)
74 boot_cpu_data
.loops_per_jiffy
= cpufreq_scale(
75 loops_per_jiffy_ref
, ref_freq
, freqs
.new);
76 clk_set_rate(cpuclk
, freq
);
77 if (freqs
.new < freqs
.old
)
78 boot_cpu_data
.loops_per_jiffy
= cpufreq_scale(
79 loops_per_jiffy_ref
, ref_freq
, freqs
.new);
80 cpufreq_notify_transition(&freqs
, CPUFREQ_POSTCHANGE
);
82 pr_debug("cpufreq: set frequency %lu Hz\n", freq
);
87 static int __init
at32_cpufreq_driver_init(struct cpufreq_policy
*policy
)
92 cpuclk
= clk_get(NULL
, "cpu");
94 pr_debug("cpufreq: could not get CPU clk\n");
95 return PTR_ERR(cpuclk
);
98 policy
->cpuinfo
.min_freq
= (clk_round_rate(cpuclk
, 1) + 500) / 1000;
99 policy
->cpuinfo
.max_freq
= (clk_round_rate(cpuclk
, ~0UL) + 500) / 1000;
100 policy
->cpuinfo
.transition_latency
= 0;
101 policy
->cur
= at32_get_speed(0);
102 policy
->min
= policy
->cpuinfo
.min_freq
;
103 policy
->max
= policy
->cpuinfo
.max_freq
;
105 printk("cpufreq: AT32AP CPU frequency driver\n");
110 static struct cpufreq_driver at32_driver
= {
112 .owner
= THIS_MODULE
,
113 .init
= at32_cpufreq_driver_init
,
114 .verify
= at32_verify_speed
,
115 .target
= at32_set_target
,
116 .get
= at32_get_speed
,
117 .flags
= CPUFREQ_STICKY
,
120 static int __init
at32_cpufreq_init(void)
122 return cpufreq_register_driver(&at32_driver
);
124 late_initcall(at32_cpufreq_init
);