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 <linux/export.h>
22 #include <asm/system.h>
24 static struct clk
*cpuclk
;
26 static int at32_verify_speed(struct cpufreq_policy
*policy
)
31 cpufreq_verify_within_limits(policy
, policy
->cpuinfo
.min_freq
,
32 policy
->cpuinfo
.max_freq
);
36 static unsigned int at32_get_speed(unsigned int cpu
)
41 return (unsigned int)((clk_get_rate(cpuclk
) + 500) / 1000);
44 static unsigned int ref_freq
;
45 static unsigned long loops_per_jiffy_ref
;
47 static int at32_set_target(struct cpufreq_policy
*policy
,
48 unsigned int target_freq
,
49 unsigned int relation
)
51 struct cpufreq_freqs freqs
;
54 /* Convert target_freq from kHz to Hz */
55 freq
= clk_round_rate(cpuclk
, target_freq
* 1000);
57 /* Check if policy->min <= new_freq <= policy->max */
58 if(freq
< (policy
->min
* 1000) || freq
> (policy
->max
* 1000))
61 pr_debug("cpufreq: requested frequency %u Hz\n", target_freq
* 1000);
63 freqs
.old
= at32_get_speed(0);
64 freqs
.new = (freq
+ 500) / 1000;
70 loops_per_jiffy_ref
= boot_cpu_data
.loops_per_jiffy
;
73 cpufreq_notify_transition(&freqs
, CPUFREQ_PRECHANGE
);
74 if (freqs
.old
< freqs
.new)
75 boot_cpu_data
.loops_per_jiffy
= cpufreq_scale(
76 loops_per_jiffy_ref
, ref_freq
, freqs
.new);
77 clk_set_rate(cpuclk
, freq
);
78 if (freqs
.new < freqs
.old
)
79 boot_cpu_data
.loops_per_jiffy
= cpufreq_scale(
80 loops_per_jiffy_ref
, ref_freq
, freqs
.new);
81 cpufreq_notify_transition(&freqs
, CPUFREQ_POSTCHANGE
);
83 pr_debug("cpufreq: set frequency %lu Hz\n", freq
);
88 static int __init
at32_cpufreq_driver_init(struct cpufreq_policy
*policy
)
93 cpuclk
= clk_get(NULL
, "cpu");
95 pr_debug("cpufreq: could not get CPU clk\n");
96 return PTR_ERR(cpuclk
);
99 policy
->cpuinfo
.min_freq
= (clk_round_rate(cpuclk
, 1) + 500) / 1000;
100 policy
->cpuinfo
.max_freq
= (clk_round_rate(cpuclk
, ~0UL) + 500) / 1000;
101 policy
->cpuinfo
.transition_latency
= 0;
102 policy
->cur
= at32_get_speed(0);
103 policy
->min
= policy
->cpuinfo
.min_freq
;
104 policy
->max
= policy
->cpuinfo
.max_freq
;
106 printk("cpufreq: AT32AP CPU frequency driver\n");
111 static struct cpufreq_driver at32_driver
= {
113 .owner
= THIS_MODULE
,
114 .init
= at32_cpufreq_driver_init
,
115 .verify
= at32_verify_speed
,
116 .target
= at32_set_target
,
117 .get
= at32_get_speed
,
118 .flags
= CPUFREQ_STICKY
,
121 static int __init
at32_cpufreq_init(void)
123 return cpufreq_register_driver(&at32_driver
);
125 late_initcall(at32_cpufreq_init
);