Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

at v3.15-rc3 193 lines 4.6 kB view raw
1/* 2 * Copyright (C) 2010 Google, Inc. 3 * 4 * Author: 5 * Colin Cross <ccross@google.com> 6 * Based on arch/arm/plat-omap/cpu-omap.c, (C) 2005 Nokia Corporation 7 * 8 * This software is licensed under the terms of the GNU General Public 9 * License version 2, as published by the Free Software Foundation, and 10 * may be copied, distributed, and modified under those terms. 11 * 12 * This program is distributed in the hope that it will be useful, 13 * but WITHOUT ANY WARRANTY; without even the implied warranty of 14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 * GNU General Public License for more details. 16 * 17 */ 18 19#include <linux/kernel.h> 20#include <linux/module.h> 21#include <linux/types.h> 22#include <linux/sched.h> 23#include <linux/cpufreq.h> 24#include <linux/delay.h> 25#include <linux/init.h> 26#include <linux/err.h> 27#include <linux/clk.h> 28#include <linux/io.h> 29 30static struct cpufreq_frequency_table freq_table[] = { 31 { .frequency = 216000 }, 32 { .frequency = 312000 }, 33 { .frequency = 456000 }, 34 { .frequency = 608000 }, 35 { .frequency = 760000 }, 36 { .frequency = 816000 }, 37 { .frequency = 912000 }, 38 { .frequency = 1000000 }, 39 { .frequency = CPUFREQ_TABLE_END }, 40}; 41 42#define NUM_CPUS 2 43 44static struct clk *cpu_clk; 45static struct clk *pll_x_clk; 46static struct clk *pll_p_clk; 47static struct clk *emc_clk; 48 49static int tegra_cpu_clk_set_rate(unsigned long rate) 50{ 51 int ret; 52 53 /* 54 * Take an extra reference to the main pll so it doesn't turn 55 * off when we move the cpu off of it 56 */ 57 clk_prepare_enable(pll_x_clk); 58 59 ret = clk_set_parent(cpu_clk, pll_p_clk); 60 if (ret) { 61 pr_err("Failed to switch cpu to clock pll_p\n"); 62 goto out; 63 } 64 65 if (rate == clk_get_rate(pll_p_clk)) 66 goto out; 67 68 ret = clk_set_rate(pll_x_clk, rate); 69 if (ret) { 70 pr_err("Failed to change pll_x to %lu\n", rate); 71 goto out; 72 } 73 74 ret = clk_set_parent(cpu_clk, pll_x_clk); 75 if (ret) { 76 pr_err("Failed to switch cpu to clock pll_x\n"); 77 goto out; 78 } 79 80out: 81 clk_disable_unprepare(pll_x_clk); 82 return ret; 83} 84 85static int tegra_update_cpu_speed(struct cpufreq_policy *policy, 86 unsigned long rate) 87{ 88 int ret = 0; 89 90 /* 91 * Vote on memory bus frequency based on cpu frequency 92 * This sets the minimum frequency, display or avp may request higher 93 */ 94 if (rate >= 816000) 95 clk_set_rate(emc_clk, 600000000); /* cpu 816 MHz, emc max */ 96 else if (rate >= 456000) 97 clk_set_rate(emc_clk, 300000000); /* cpu 456 MHz, emc 150Mhz */ 98 else 99 clk_set_rate(emc_clk, 100000000); /* emc 50Mhz */ 100 101 ret = tegra_cpu_clk_set_rate(rate * 1000); 102 if (ret) 103 pr_err("cpu-tegra: Failed to set cpu frequency to %lu kHz\n", 104 rate); 105 106 return ret; 107} 108 109static int tegra_target(struct cpufreq_policy *policy, unsigned int index) 110{ 111 return tegra_update_cpu_speed(policy, freq_table[index].frequency); 112} 113 114static int tegra_cpu_init(struct cpufreq_policy *policy) 115{ 116 int ret; 117 118 if (policy->cpu >= NUM_CPUS) 119 return -EINVAL; 120 121 clk_prepare_enable(emc_clk); 122 clk_prepare_enable(cpu_clk); 123 124 /* FIXME: what's the actual transition time? */ 125 ret = cpufreq_generic_init(policy, freq_table, 300 * 1000); 126 if (ret) { 127 clk_disable_unprepare(cpu_clk); 128 clk_disable_unprepare(emc_clk); 129 return ret; 130 } 131 132 policy->clk = cpu_clk; 133 policy->suspend_freq = freq_table[0].frequency; 134 return 0; 135} 136 137static int tegra_cpu_exit(struct cpufreq_policy *policy) 138{ 139 clk_disable_unprepare(cpu_clk); 140 clk_disable_unprepare(emc_clk); 141 return 0; 142} 143 144static struct cpufreq_driver tegra_cpufreq_driver = { 145 .flags = CPUFREQ_NEED_INITIAL_FREQ_CHECK, 146 .verify = cpufreq_generic_frequency_table_verify, 147 .target_index = tegra_target, 148 .get = cpufreq_generic_get, 149 .init = tegra_cpu_init, 150 .exit = tegra_cpu_exit, 151 .name = "tegra", 152 .attr = cpufreq_generic_attr, 153#ifdef CONFIG_PM 154 .suspend = cpufreq_generic_suspend, 155#endif 156}; 157 158static int __init tegra_cpufreq_init(void) 159{ 160 cpu_clk = clk_get_sys(NULL, "cclk"); 161 if (IS_ERR(cpu_clk)) 162 return PTR_ERR(cpu_clk); 163 164 pll_x_clk = clk_get_sys(NULL, "pll_x"); 165 if (IS_ERR(pll_x_clk)) 166 return PTR_ERR(pll_x_clk); 167 168 pll_p_clk = clk_get_sys(NULL, "pll_p"); 169 if (IS_ERR(pll_p_clk)) 170 return PTR_ERR(pll_p_clk); 171 172 emc_clk = clk_get_sys("cpu", "emc"); 173 if (IS_ERR(emc_clk)) { 174 clk_put(cpu_clk); 175 return PTR_ERR(emc_clk); 176 } 177 178 return cpufreq_register_driver(&tegra_cpufreq_driver); 179} 180 181static void __exit tegra_cpufreq_exit(void) 182{ 183 cpufreq_unregister_driver(&tegra_cpufreq_driver); 184 clk_put(emc_clk); 185 clk_put(cpu_clk); 186} 187 188 189MODULE_AUTHOR("Colin Cross <ccross@android.com>"); 190MODULE_DESCRIPTION("cpufreq driver for Nvidia Tegra2"); 191MODULE_LICENSE("GPL"); 192module_init(tegra_cpufreq_init); 193module_exit(tegra_cpufreq_exit);