1/* 2 * linux/arch/arm/plat-omap/cpu-omap.c 3 * 4 * CPU frequency scaling for OMAP 5 * 6 * Copyright (C) 2005 Nokia Corporation 7 * Written by Tony Lindgren <tony@atomide.com> 8 * 9 * Based on cpu-sa1110.c, Copyright (C) 2001 Russell King 10 * 11 * This program is free software; you can redistribute it and/or modify 12 * it under the terms of the GNU General Public License version 2 as 13 * published by the Free Software Foundation. 14 */ 15#include <linux/types.h> 16#include <linux/kernel.h> 17#include <linux/sched.h> 18#include <linux/cpufreq.h> 19#include <linux/delay.h> 20#include <linux/init.h> 21#include <linux/err.h> 22#include <linux/clk.h> 23 24#include <asm/hardware.h> 25#include <asm/io.h> 26#include <asm/system.h> 27 28#define VERY_HI_RATE 900000000 29 30#ifdef CONFIG_ARCH_OMAP1 31#define MPU_CLK "mpu" 32#else 33#define MPU_CLK "virt_prcm_set" 34#endif 35 36/* TODO: Add support for SDRAM timing changes */ 37 38int omap_verify_speed(struct cpufreq_policy *policy) 39{ 40 struct clk * mpu_clk; 41 42 if (policy->cpu) 43 return -EINVAL; 44 45 cpufreq_verify_within_limits(policy, policy->cpuinfo.min_freq, 46 policy->cpuinfo.max_freq); 47 mpu_clk = clk_get(NULL, MPU_CLK); 48 if (IS_ERR(mpu_clk)) 49 return PTR_ERR(mpu_clk); 50 policy->min = clk_round_rate(mpu_clk, policy->min * 1000) / 1000; 51 policy->max = clk_round_rate(mpu_clk, policy->max * 1000) / 1000; 52 cpufreq_verify_within_limits(policy, policy->cpuinfo.min_freq, 53 policy->cpuinfo.max_freq); 54 clk_put(mpu_clk); 55 56 return 0; 57} 58 59unsigned int omap_getspeed(unsigned int cpu) 60{ 61 struct clk * mpu_clk; 62 unsigned long rate; 63 64 if (cpu) 65 return 0; 66 67 mpu_clk = clk_get(NULL, MPU_CLK); 68 if (IS_ERR(mpu_clk)) 69 return 0; 70 rate = clk_get_rate(mpu_clk) / 1000; 71 clk_put(mpu_clk); 72 73 return rate; 74} 75 76static int omap_target(struct cpufreq_policy *policy, 77 unsigned int target_freq, 78 unsigned int relation) 79{ 80 struct clk * mpu_clk; 81 struct cpufreq_freqs freqs; 82 int ret = 0; 83 84 mpu_clk = clk_get(NULL, MPU_CLK); 85 if (IS_ERR(mpu_clk)) 86 return PTR_ERR(mpu_clk); 87 88 freqs.old = omap_getspeed(0); 89 freqs.new = clk_round_rate(mpu_clk, target_freq * 1000) / 1000; 90 freqs.cpu = 0; 91 92 cpufreq_notify_transition(&freqs, CPUFREQ_PRECHANGE); 93 ret = clk_set_rate(mpu_clk, target_freq * 1000); 94 cpufreq_notify_transition(&freqs, CPUFREQ_POSTCHANGE); 95 clk_put(mpu_clk); 96 97 return ret; 98} 99 100static int __init omap_cpu_init(struct cpufreq_policy *policy) 101{ 102 struct clk * mpu_clk; 103 104 mpu_clk = clk_get(NULL, MPU_CLK); 105 if (IS_ERR(mpu_clk)) 106 return PTR_ERR(mpu_clk); 107 108 if (policy->cpu != 0) 109 return -EINVAL; 110 policy->cur = policy->min = policy->max = omap_getspeed(0); 111 policy->governor = CPUFREQ_DEFAULT_GOVERNOR; 112 policy->cpuinfo.min_freq = clk_round_rate(mpu_clk, 0) / 1000; 113 policy->cpuinfo.max_freq = clk_round_rate(mpu_clk, VERY_HI_RATE) / 1000; 114 policy->cpuinfo.transition_latency = CPUFREQ_ETERNAL; 115 clk_put(mpu_clk); 116 117 return 0; 118} 119 120static struct cpufreq_driver omap_driver = { 121 .flags = CPUFREQ_STICKY, 122 .verify = omap_verify_speed, 123 .target = omap_target, 124 .get = omap_getspeed, 125 .init = omap_cpu_init, 126 .name = "omap", 127}; 128 129static int __init omap_cpufreq_init(void) 130{ 131 return cpufreq_register_driver(&omap_driver); 132} 133 134arch_initcall(omap_cpufreq_init); 135