#include <linux/io.h>
#include <linux/opp.h>
#include <linux/cpu.h>
+#include <linux/module.h>
#include <asm/system.h>
#include <asm/smp_plat.h>
#include <plat/clock.h>
#include <plat/omap-pm.h>
#include <plat/common.h>
+#include <plat/omap_device.h>
#include <mach/hardware.h>
#endif
static struct cpufreq_frequency_table *freq_table;
+static atomic_t freq_table_users = ATOMIC_INIT(0);
static struct clk *mpu_clk;
static char *mpu_clk_name;
static struct device *mpu_dev;
return ret;
}
+static inline void freq_table_free(void)
+{
+ if (atomic_dec_and_test(&freq_table_users))
+ opp_free_cpufreq_table(mpu_dev, &freq_table);
+}
+
static int __cpuinit omap_cpu_init(struct cpufreq_policy *policy)
{
int result = 0;
if (IS_ERR(mpu_clk))
return PTR_ERR(mpu_clk);
- if (policy->cpu >= NR_CPUS)
- return -EINVAL;
+ if (policy->cpu >= NR_CPUS) {
+ result = -EINVAL;
+ goto fail_ck;
+ }
policy->cur = policy->min = policy->max = omap_getspeed(policy->cpu);
- result = opp_init_cpufreq_table(mpu_dev, &freq_table);
+
+ if (atomic_inc_return(&freq_table_users) == 1)
+ result = opp_init_cpufreq_table(mpu_dev, &freq_table);
if (result) {
dev_err(mpu_dev, "%s: cpu%d: failed creating freq table[%d]\n",
__func__, policy->cpu, result);
- return result;
+ goto fail_ck;
}
result = cpufreq_frequency_table_cpuinfo(policy, freq_table);
- if (!result)
- cpufreq_frequency_table_get_attr(freq_table, policy->cpu);
+ if (result)
+ goto fail_table;
+
+ cpufreq_frequency_table_get_attr(freq_table, policy->cpu);
policy->min = policy->cpuinfo.min_freq;
policy->max = policy->cpuinfo.max_freq;
policy->cpuinfo.transition_latency = 300 * 1000;
return 0;
+
+fail_table:
+ freq_table_free();
+fail_ck:
+ clk_put(mpu_clk);
+ return result;
}
static int omap_cpu_exit(struct cpufreq_policy *policy)
{
+ freq_table_free();
clk_put(mpu_clk);
return 0;
}
return -EINVAL;
}
- mpu_dev = omap2_get_mpuss_device();
+ mpu_dev = omap_device_get_by_hwmod_name("mpu");
if (!mpu_dev) {
pr_warning("%s: unable to get the mpu device\n", __func__);
return -EINVAL;