aboutsummaryrefslogtreecommitdiffstats
path: root/arch/arm/mach-exynos/busfreq_opp_exynos5.c
diff options
context:
space:
mode:
Diffstat (limited to 'arch/arm/mach-exynos/busfreq_opp_exynos5.c')
-rw-r--r--arch/arm/mach-exynos/busfreq_opp_exynos5.c498
1 files changed, 0 insertions, 498 deletions
diff --git a/arch/arm/mach-exynos/busfreq_opp_exynos5.c b/arch/arm/mach-exynos/busfreq_opp_exynos5.c
deleted file mode 100644
index b685cd2..0000000
--- a/arch/arm/mach-exynos/busfreq_opp_exynos5.c
+++ /dev/null
@@ -1,498 +0,0 @@
-/* linux/arch/arm/mach-exynos/busfreq_opp_exynos5.c
- *
- * Copyright (c) 2011 Samsung Electronics Co., Ltd.
- * http://www.samsung.com/
- *
- * EXYNOS4 - BUS clock frequency scaling support with OPP
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
-*/
-
-#include <linux/init.h>
-#include <linux/interrupt.h>
-#include <linux/types.h>
-#include <linux/err.h>
-#include <linux/io.h>
-#include <linux/regulator/consumer.h>
-#include <linux/sysfs.h>
-#include <linux/platform_device.h>
-#include <linux/device.h>
-#include <linux/module.h>
-#include <linux/cpu.h>
-#include <linux/ktime.h>
-#include <linux/tick.h>
-#include <linux/kernel_stat.h>
-#include <linux/suspend.h>
-#include <linux/reboot.h>
-#include <linux/slab.h>
-#include <linux/opp.h>
-#include <linux/clk.h>
-#include <linux/workqueue.h>
-
-#include <asm/mach-types.h>
-
-#include <mach/ppmu.h>
-#include <mach/map.h>
-#include <mach/regs-clock.h>
-#include <mach/gpio.h>
-#include <mach/regs-mem.h>
-#include <mach/cpufreq.h>
-#include <mach/dev.h>
-#include <mach/busfreq_exynos5.h>
-
-#include <plat/map-s5p.h>
-#include <plat/cpu.h>
-#include <plat/clock.h>
-
-#define BUSFREQ_DEBUG 1
-
-static DEFINE_MUTEX(busfreq_lock);
-BLOCKING_NOTIFIER_HEAD(exynos_busfreq_notifier_list);
-
-struct busfreq_control {
- struct opp *lock[PPMU_TYPE_END];
- struct device *dev[PPMU_TYPE_END];
-};
-
-static struct busfreq_control bus_ctrl;
-
-void update_busfreq_stat(struct busfreq_data *data,
- enum ppmu_type type, unsigned int index)
-{
-#ifdef BUSFREQ_DEBUG
- unsigned long long cur_time = get_jiffies_64();
- data->time_in_state[type][index] =
- cputime64_add(data->time_in_state[type][index], cputime_sub(cur_time, data->last_time[type]));
- data->last_time[type] = cur_time;
-#endif
-}
-
-
-static unsigned long __maybe_unused step_up(struct busfreq_data *data,
- enum ppmu_type type, int step)
-{
- int i;
- struct opp *opp;
- unsigned long newfreq = data->curr_freq[type];
-
- if (data->max_freq[type] == data->curr_freq[type])
- return newfreq;
-
- for (i = 0; i < step; i++) {
- newfreq += 1;
- opp = opp_find_freq_ceil(data->dev[type], &newfreq);
-
- if (opp_get_freq(opp) == data->max_freq[type])
- break;
- }
-
- return newfreq;
-}
-
-unsigned long step_down(struct busfreq_data *data,
- enum ppmu_type type, int step)
-{
- int i;
- struct opp *opp;
- unsigned long newfreq = data->curr_freq[type];
-
- if (data->min_freq[type] == data->curr_freq[type])
- return newfreq;
-
- for (i = 0; i < step; i++) {
- newfreq -= 1;
- opp = opp_find_freq_floor(data->dev[type], &newfreq);
-
- if (opp_get_freq(opp) == data->min_freq[type])
- break;
- }
-
- return newfreq;
-}
-
-static void _target(struct busfreq_data *data,
- enum ppmu_type type, unsigned long newfreq)
-{
- struct opp *opp;
- unsigned int voltage;
- int index;
-
- opp = opp_find_freq_exact(data->dev[type], newfreq, true);
-
- if (bus_ctrl.lock[type]) {
- opp = bus_ctrl.lock[type];
- newfreq = opp_get_freq(opp);
- }
-
- index = data->get_table_index(newfreq, type);
-
- if (newfreq == 0 || newfreq == data->curr_freq[type] ||
- data->use == false) {
- update_busfreq_stat(data, type, index);
- return;
- }
-
- voltage = opp_get_voltage(opp);
-
- if (newfreq > data->curr_freq[type]) {
- regulator_set_voltage(data->vdd_reg[type], voltage,
- voltage + 25000);
- if (type == PPMU_MIF && data->busfreq_prepare)
- data->busfreq_prepare(index);
- }
-
- data->target(data, type, index);
-
- if (newfreq < data->curr_freq[type]) {
- if (type == PPMU_MIF && data->busfreq_post)
- data->busfreq_post(index);
- regulator_set_voltage(data->vdd_reg[type], voltage,
- voltage + 25000);
- }
- data->curr_freq[type] = newfreq;
-
- update_busfreq_stat(data, type, index);
-}
-
-static void exynos_busfreq_timer(struct work_struct *work)
-{
- struct delayed_work *delayed_work = to_delayed_work(work);
- struct busfreq_data *data = container_of(delayed_work, struct busfreq_data,
- worker);
- int i;
- struct opp *opp[PPMU_TYPE_END];
- unsigned long newfreq;
-
- data->monitor(data, &opp[PPMU_MIF], &opp[PPMU_INT]);
-
- ppmu_start(data->dev[PPMU_MIF]);
-
- mutex_lock(&busfreq_lock);
-
- for (i = PPMU_MIF; i < PPMU_TYPE_END; i++) {
- newfreq = opp_get_freq(opp[i]);
- _target(data, i, newfreq);
- }
-
- mutex_unlock(&busfreq_lock);
- queue_delayed_work(system_freezable_wq, &data->worker, data->sampling_rate);
-}
-
-static int exynos_buspm_notifier_event(struct notifier_block *this,
- unsigned long event, void *ptr)
-{
- struct busfreq_data *data = container_of(this, struct busfreq_data,
- exynos_buspm_notifier);
- int i;
-
- switch (event) {
- case PM_SUSPEND_PREPARE:
- mutex_lock(&busfreq_lock);
- for (i = PPMU_MIF; i < PPMU_TYPE_END; i++)
- _target(data, i, data->max_freq[i]);
- mutex_unlock(&busfreq_lock);
- data->use = false;
- return NOTIFY_OK;
- case PM_POST_RESTORE:
- case PM_POST_SUSPEND:
- data->use = true;
- return NOTIFY_OK;
- }
- return NOTIFY_DONE;
-}
-
-static int exynos_busfreq_reboot_event(struct notifier_block *this,
- unsigned long code, void *unused)
-{
- struct busfreq_data *data = container_of(this, struct busfreq_data,
- exynos_reboot_notifier);
- int i;
- struct opp *opp;
- unsigned int voltage[PPMU_TYPE_END];
- for (i = PPMU_MIF; i < PPMU_TYPE_END; i++) {
- opp = opp_find_freq_exact(data->dev[i], data->max_freq[i], true);
- voltage[i] = opp_get_voltage(opp);
-
- regulator_set_voltage(data->vdd_reg[i], voltage[i], voltage[i] + 25000);
- }
- data->use = false;
-
- printk(KERN_INFO "REBOOT Notifier for BUSFREQ\n");
- return NOTIFY_DONE;
-}
-
-static int exynos_busfreq_request_event(struct notifier_block *this,
- unsigned long req_newfreq, void *device)
-{
- struct busfreq_data *data = container_of(this, struct busfreq_data,
- exynos_request_notifier);
- int i;
- struct opp *opp[PPMU_TYPE_END];
- unsigned long newfreq[PPMU_TYPE_END];
- unsigned long freq;
-
- if (req_newfreq == 0 || data->use == false)
- return -EINVAL;
-
- mutex_lock(&busfreq_lock);
-
- newfreq[PPMU_MIF] = (req_newfreq / 1000) * 1000;
- newfreq[PPMU_INT] = (req_newfreq % 1000) * 1000;
-
- for (i = PPMU_MIF; i < PPMU_TYPE_END; i++) {
- opp[i] = opp_find_freq_ceil(data->dev[i], &newfreq[i]);
- freq = opp_get_freq(opp[i]);
- if (freq > data->curr_freq[i])
- _target(data, i, freq);
- }
-
- mutex_unlock(&busfreq_lock);
- printk(KERN_INFO "REQUEST Notifier for BUSFREQ\n");
- return NOTIFY_DONE;
-}
-
-int exynos_busfreq_lock(unsigned int nId,
- enum busfreq_level_request busfreq_level)
-{
- return 0;
-}
-
-void exynos_busfreq_lock_free(unsigned int nId)
-{
-}
-
-static ssize_t show_level_lock(struct device *device,
- struct device_attribute *attr, char *buf)
-{
- struct platform_device *pdev = to_platform_device(bus_ctrl.dev[PPMU_MIF]);
- struct busfreq_data *data = (struct busfreq_data *)platform_get_drvdata(pdev);
- int len = 0;
- unsigned long mif_freq, int_freq;
-
- mif_freq = bus_ctrl.lock[PPMU_MIF] == NULL ? 0 : opp_get_freq(bus_ctrl.lock[PPMU_MIF]);
- int_freq = bus_ctrl.lock[PPMU_INT] == NULL ? 0 : opp_get_freq(bus_ctrl.lock[PPMU_INT]);
-
- len = sprintf(buf, "Current Freq(MIF/INT) : (%lu - %lu)\n",
- data->curr_freq[PPMU_MIF], data->curr_freq[PPMU_INT]);
- len += sprintf(buf + len, "Current Lock Freq(MIF/INT) : (%lu - %lu)\n", mif_freq, int_freq);
-
- return len;
-}
-
-static ssize_t store_level_lock(struct device *device, struct device_attribute *attr,
- const char *buf, size_t count)
-{
- struct platform_device *pdev = to_platform_device(bus_ctrl.dev[PPMU_MIF]);
- struct busfreq_data *data = (struct busfreq_data *)platform_get_drvdata(pdev);
- struct opp *opp[PPMU_TYPE_END];
- unsigned long freq[PPMU_TYPE_END];
- int i;
- int ret;
-
- ret = sscanf(buf, "%lu %lu", &freq[PPMU_MIF], &freq[PPMU_INT]);
- if (freq[PPMU_MIF] == 0 || freq[PPMU_INT] == 0 || ret != 2) {
- pr_info("Release bus level lock.\n");
- bus_ctrl.lock[PPMU_MIF] = NULL;
- bus_ctrl.lock[PPMU_INT] = NULL;
- return count;
- }
-
- for (i = PPMU_MIF; i < PPMU_TYPE_END; i++) {
- if (freq[i] > data->max_freq[i])
- freq[i] = data->max_freq[i];
-
- opp[i] = opp_find_freq_ceil(bus_ctrl.dev[i], &freq[i]);
- bus_ctrl.lock[i] = opp[i];
- }
- pr_info("Lock Freq : MIF/INT(%lu - %lu)\n", opp_get_freq(opp[PPMU_MIF]), opp_get_freq(opp[PPMU_INT]));
- return count;
-}
-
-static ssize_t show_locklist(struct device *device,
- struct device_attribute *attr, char *buf)
-{
- return dev_lock_list(bus_ctrl.dev[PPMU_MIF], buf);
-}
-
-static ssize_t show_time_in_state(struct device *device,
- struct device_attribute *attr, char *buf)
-{
- struct platform_device *pdev = to_platform_device(bus_ctrl.dev[PPMU_MIF]);
- struct busfreq_data *data = (struct busfreq_data *)platform_get_drvdata(pdev);
- struct busfreq_table *table;
- ssize_t len = 0;
- int i;
-
- table = data->table[PPMU_MIF];
- len += sprintf(buf, "%s\n", "MIF stat");
- for (i = LV_0; i < LV_MIF_END; i++)
- len += sprintf(buf + len, "%u %llu\n", table[i].mem_clk,
- (unsigned long long)cputime64_to_clock_t(data->time_in_state[PPMU_MIF][i]));
-
- table = data->table[PPMU_INT];
- len += sprintf(buf + len, "\n%s\n", "INT stat");
- for (i = LV_0; i < LV_INT_END; i++)
- len += sprintf(buf + len, "%u %llu\n", table[i].mem_clk,
- (unsigned long long)cputime64_to_clock_t(data->time_in_state[PPMU_INT][i]));
- return len;
-}
-
-static DEVICE_ATTR(curr_freq, 0664, show_level_lock, store_level_lock);
-static DEVICE_ATTR(lock_list, 0664, show_locklist, NULL);
-static DEVICE_ATTR(time_in_state, 0664, show_time_in_state, NULL);
-
-static struct attribute *busfreq_attributes[] = {
- &dev_attr_curr_freq.attr,
- &dev_attr_lock_list.attr,
- &dev_attr_time_in_state.attr,
- NULL
-};
-
-int exynos_request_register(struct notifier_block *n)
-{
- return blocking_notifier_chain_register(&exynos_busfreq_notifier_list, n);
-}
-
-void exynos_request_apply(unsigned long freq)
-{
- blocking_notifier_call_chain(&exynos_busfreq_notifier_list, freq, NULL);
-}
-
-static __devinit int exynos_busfreq_probe(struct platform_device *pdev)
-{
- struct busfreq_data *data;
-
- data = kzalloc(sizeof(struct busfreq_data), GFP_KERNEL);
- if (!data) {
- pr_err("Unable to create busfreq_data struct.\n");
- return -ENOMEM;
- }
-
- data->exynos_buspm_notifier.notifier_call =
- exynos_buspm_notifier_event;
- data->exynos_reboot_notifier.notifier_call =
- exynos_busfreq_reboot_event;
- data->busfreq_attr_group.attrs = busfreq_attributes;
- data->exynos_request_notifier.notifier_call =
- exynos_busfreq_request_event;
-
- INIT_DELAYED_WORK(&data->worker, exynos_busfreq_timer);
-
- if (soc_is_exynos5250()) {
- data->init = exynos5250_init;
- } else {
- pr_err("Unsupport device type.\n");
- goto err_busfreq;
- }
-
- if (data->init(&pdev->dev, data)) {
- pr_err("Failed to init busfreq.\n");
- goto err_busfreq;
- }
-
- bus_ctrl.dev[PPMU_MIF] = data->dev[PPMU_MIF];
- bus_ctrl.dev[PPMU_INT] = data->dev[PPMU_INT];
-
- data->last_time[PPMU_MIF] = get_jiffies_64();
- data->last_time[PPMU_INT] = get_jiffies_64();
-
- data->busfreq_kobject = kobject_create_and_add("busfreq",
- &cpu_sysdev_class.kset.kobj);
- if (!data->busfreq_kobject)
- pr_err("Failed to create busfreq kobject.!\n");
-
- if (sysfs_create_group(data->busfreq_kobject, &data->busfreq_attr_group))
- pr_err("Failed to create attributes group.!\n");
-
- if (register_pm_notifier(&data->exynos_buspm_notifier)) {
- pr_err("Failed to setup buspm notifier\n");
- goto err_busfreq;
- }
-
- data->use = true;
-
- if (register_reboot_notifier(&data->exynos_reboot_notifier))
- pr_err("Failed to setup reboot notifier\n");
-
- if (exynos_request_register(&data->exynos_request_notifier))
- pr_err("Failed to setup request notifier\n");
-
- platform_set_drvdata(pdev, data);
-
- queue_delayed_work(system_freezable_wq, &data->worker, data->sampling_rate);
- return 0;
-
-err_busfreq:
- if (!IS_ERR(data->vdd_reg[PPMU_INT]))
- regulator_put(data->vdd_reg[PPMU_INT]);
-
- if (!IS_ERR(data->vdd_reg[PPMU_MIF]))
- regulator_put(data->vdd_reg[PPMU_MIF]);
-
- kfree(data);
- return -ENODEV;
-}
-
-static __devexit int exynos_busfreq_remove(struct platform_device *pdev)
-{
- struct busfreq_data *data = platform_get_drvdata(pdev);
-
- unregister_pm_notifier(&data->exynos_buspm_notifier);
- unregister_reboot_notifier(&data->exynos_reboot_notifier);
- regulator_put(data->vdd_reg[PPMU_INT]);
- regulator_put(data->vdd_reg[PPMU_MIF]);
- sysfs_remove_group(data->busfreq_kobject, &data->busfreq_attr_group);
- kfree(data);
-
- return 0;
-}
-
-static int exynos_busfreq_suspend(struct device *dev)
-{
- struct platform_device *pdev = to_platform_device(dev);
- struct busfreq_data *data = (struct busfreq_data *)platform_get_drvdata(pdev);
-
- if (data->busfreq_suspend)
- data->busfreq_suspend();
- return 0;
-}
-
-static int exynos_busfreq_resume(struct device *dev)
-{
- struct platform_device *pdev = to_platform_device(dev);
- struct busfreq_data *data = (struct busfreq_data *)platform_get_drvdata(pdev);
- ppmu_reset(dev);
-
- if (data->busfreq_resume)
- data->busfreq_resume();
- return 0;
-}
-
-static const struct dev_pm_ops exynos_busfreq_pm = {
- .suspend = exynos_busfreq_suspend,
- .resume = exynos_busfreq_resume,
-};
-
-static struct platform_driver exynos_busfreq_driver = {
- .probe = exynos_busfreq_probe,
- .remove = __devexit_p(exynos_busfreq_remove),
- .driver = {
- .name = "exynos-busfreq",
- .owner = THIS_MODULE,
- .pm = &exynos_busfreq_pm,
- },
-};
-
-static int __init exynos_busfreq_init(void)
-{
- return platform_driver_register(&exynos_busfreq_driver);
-}
-late_initcall(exynos_busfreq_init);
-
-static void __exit exynos_busfreq_exit(void)
-{
- platform_driver_unregister(&exynos_busfreq_driver);
-}
-module_exit(exynos_busfreq_exit);