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.7-rc5 170 lines 4.2 kB view raw
1/* 2 * Copyright (C) STMicroelectronics 2009 3 * Copyright (C) ST-Ericsson SA 2010 4 * 5 * License Terms: GNU General Public License v2 6 * Author: Sundar Iyer <sundar.iyer@stericsson.com> 7 * Author: Martin Persson <martin.persson@stericsson.com> 8 * Author: Jonas Aaberg <jonas.aberg@stericsson.com> 9 * 10 */ 11#include <linux/kernel.h> 12#include <linux/cpufreq.h> 13#include <linux/delay.h> 14#include <linux/slab.h> 15#include <linux/mfd/dbx500-prcmu.h> 16#include <mach/id.h> 17 18static struct cpufreq_frequency_table freq_table[] = { 19 [0] = { 20 .index = 0, 21 .frequency = 200000, 22 }, 23 [1] = { 24 .index = 1, 25 .frequency = 400000, 26 }, 27 [2] = { 28 .index = 2, 29 .frequency = 800000, 30 }, 31 [3] = { 32 /* Used for MAX_OPP, if available */ 33 .index = 3, 34 .frequency = CPUFREQ_TABLE_END, 35 }, 36 [4] = { 37 .index = 4, 38 .frequency = CPUFREQ_TABLE_END, 39 }, 40}; 41 42static enum arm_opp idx2opp[] = { 43 ARM_EXTCLK, 44 ARM_50_OPP, 45 ARM_100_OPP, 46 ARM_MAX_OPP 47}; 48 49static struct freq_attr *db8500_cpufreq_attr[] = { 50 &cpufreq_freq_attr_scaling_available_freqs, 51 NULL, 52}; 53 54static int db8500_cpufreq_verify_speed(struct cpufreq_policy *policy) 55{ 56 return cpufreq_frequency_table_verify(policy, freq_table); 57} 58 59static int db8500_cpufreq_target(struct cpufreq_policy *policy, 60 unsigned int target_freq, 61 unsigned int relation) 62{ 63 struct cpufreq_freqs freqs; 64 unsigned int idx; 65 66 /* scale the target frequency to one of the extremes supported */ 67 if (target_freq < policy->cpuinfo.min_freq) 68 target_freq = policy->cpuinfo.min_freq; 69 if (target_freq > policy->cpuinfo.max_freq) 70 target_freq = policy->cpuinfo.max_freq; 71 72 /* Lookup the next frequency */ 73 if (cpufreq_frequency_table_target 74 (policy, freq_table, target_freq, relation, &idx)) { 75 return -EINVAL; 76 } 77 78 freqs.old = policy->cur; 79 freqs.new = freq_table[idx].frequency; 80 81 if (freqs.old == freqs.new) 82 return 0; 83 84 /* pre-change notification */ 85 for_each_cpu(freqs.cpu, policy->cpus) 86 cpufreq_notify_transition(&freqs, CPUFREQ_PRECHANGE); 87 88 /* request the PRCM unit for opp change */ 89 if (prcmu_set_arm_opp(idx2opp[idx])) { 90 pr_err("db8500-cpufreq: Failed to set OPP level\n"); 91 return -EINVAL; 92 } 93 94 /* post change notification */ 95 for_each_cpu(freqs.cpu, policy->cpus) 96 cpufreq_notify_transition(&freqs, CPUFREQ_POSTCHANGE); 97 98 return 0; 99} 100 101static unsigned int db8500_cpufreq_getspeed(unsigned int cpu) 102{ 103 int i; 104 /* request the prcm to get the current ARM opp */ 105 for (i = 0; prcmu_get_arm_opp() != idx2opp[i]; i++) 106 ; 107 return freq_table[i].frequency; 108} 109 110static int __cpuinit db8500_cpufreq_init(struct cpufreq_policy *policy) 111{ 112 int i, res; 113 114 BUILD_BUG_ON(ARRAY_SIZE(idx2opp) + 1 != ARRAY_SIZE(freq_table)); 115 116 if (prcmu_has_arm_maxopp()) 117 freq_table[3].frequency = 1000000; 118 119 pr_info("db8500-cpufreq : Available frequencies:\n"); 120 for (i = 0; freq_table[i].frequency != CPUFREQ_TABLE_END; i++) 121 pr_info(" %d Mhz\n", freq_table[i].frequency/1000); 122 123 /* get policy fields based on the table */ 124 res = cpufreq_frequency_table_cpuinfo(policy, freq_table); 125 if (!res) 126 cpufreq_frequency_table_get_attr(freq_table, policy->cpu); 127 else { 128 pr_err("db8500-cpufreq : Failed to read policy table\n"); 129 return res; 130 } 131 132 policy->min = policy->cpuinfo.min_freq; 133 policy->max = policy->cpuinfo.max_freq; 134 policy->cur = db8500_cpufreq_getspeed(policy->cpu); 135 policy->governor = CPUFREQ_DEFAULT_GOVERNOR; 136 137 /* 138 * FIXME : Need to take time measurement across the target() 139 * function with no/some/all drivers in the notification 140 * list. 141 */ 142 policy->cpuinfo.transition_latency = 20 * 1000; /* in ns */ 143 144 /* policy sharing between dual CPUs */ 145 cpumask_copy(policy->cpus, cpu_present_mask); 146 147 policy->shared_type = CPUFREQ_SHARED_TYPE_ALL; 148 149 return 0; 150} 151 152static struct cpufreq_driver db8500_cpufreq_driver = { 153 .flags = CPUFREQ_STICKY, 154 .verify = db8500_cpufreq_verify_speed, 155 .target = db8500_cpufreq_target, 156 .get = db8500_cpufreq_getspeed, 157 .init = db8500_cpufreq_init, 158 .name = "DB8500", 159 .attr = db8500_cpufreq_attr, 160}; 161 162static int __init db8500_cpufreq_register(void) 163{ 164 if (!cpu_is_u8500_family()) 165 return -ENODEV; 166 167 pr_info("cpufreq for DB8500 started\n"); 168 return cpufreq_register_driver(&db8500_cpufreq_driver); 169} 170device_initcall(db8500_cpufreq_register);