Linux Audio

Check our new training course

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