diff options
author | Michael Hennerich <michael.hennerich@analog.com> | 2008-05-07 11:41:26 +0800 |
---|---|---|
committer | Bryan Wu <cooloney@kernel.org> | 2008-05-07 11:41:26 +0800 |
commit | 14b03204c8060d036b04cbb18bbd6f6f311f4fed (patch) | |
tree | e4ac8f5e2a74fc63dd811aac9e349ac890670134 /arch/blackfin/mach-common | |
parent | 19d6d7d53c8ff809182a1f092d2c6918146414e9 (diff) |
[Blackfin] arch: Functional power management support: Add CPU and platform voltage scaling support
Signed-off-by: Michael Hennerich <michael.hennerich@analog.com>
Signed-off-by: Bryan Wu <cooloney@kernel.org>
Diffstat (limited to 'arch/blackfin/mach-common')
-rw-r--r-- | arch/blackfin/mach-common/Makefile | 5 | ||||
-rw-r--r-- | arch/blackfin/mach-common/dpmc.c | 137 | ||||
-rw-r--r-- | arch/blackfin/mach-common/dpmc_modes.S (renamed from arch/blackfin/mach-common/dpmc.S) | 27 |
3 files changed, 142 insertions, 27 deletions
diff --git a/arch/blackfin/mach-common/Makefile b/arch/blackfin/mach-common/Makefile index 393081e9b680..422bfee34adc 100644 --- a/arch/blackfin/mach-common/Makefile +++ b/arch/blackfin/mach-common/Makefile @@ -6,5 +6,6 @@ obj-y := \ cache.o cacheinit.o entry.o \ interrupt.o lock.o irqpanic.o arch_checks.o ints-priority.o -obj-$(CONFIG_PM) += pm.o dpmc.o -obj-$(CONFIG_CPU_FREQ) += cpufreq.o +obj-$(CONFIG_PM) += pm.o dpmc_modes.o +obj-$(CONFIG_CPU_FREQ) += cpufreq.o +obj-$(CONFIG_CPU_VOLTAGE) += dpmc.o diff --git a/arch/blackfin/mach-common/dpmc.c b/arch/blackfin/mach-common/dpmc.c new file mode 100644 index 000000000000..02c7efd1bcf4 --- /dev/null +++ b/arch/blackfin/mach-common/dpmc.c @@ -0,0 +1,137 @@ +/* + * Copyright 2008 Analog Devices Inc. + * + * Licensed under the GPL-2 or later. + */ + +#include <linux/cdev.h> +#include <linux/device.h> +#include <linux/errno.h> +#include <linux/fs.h> +#include <linux/kernel.h> +#include <linux/module.h> +#include <linux/platform_device.h> +#include <linux/types.h> +#include <linux/cpufreq.h> + +#include <asm/delay.h> +#include <asm/dpmc.h> + +#define DRIVER_NAME "bfin dpmc" + +#define dprintk(msg...) \ + cpufreq_debug_printk(CPUFREQ_DEBUG_DRIVER, DRIVER_NAME, msg) + +struct bfin_dpmc_platform_data *pdata; + +/** + * bfin_set_vlev - Update VLEV field in VR_CTL Reg. + * Avoid BYPASS sequence + */ +static void bfin_set_vlev(unsigned int vlev) +{ + unsigned pll_lcnt; + + pll_lcnt = bfin_read_PLL_LOCKCNT(); + + bfin_write_PLL_LOCKCNT(1); + bfin_write_VR_CTL((bfin_read_VR_CTL() & ~VLEV) | vlev); + bfin_write_PLL_LOCKCNT(pll_lcnt); +} + +/** + * bfin_get_vlev - Get CPU specific VLEV from platform device data + */ +static unsigned int bfin_get_vlev(unsigned int freq) +{ + int i; + + if (!pdata) + goto err_out; + + freq >>= 16; + + for (i = 0; i < pdata->tabsize; i++) + if (freq <= (pdata->tuple_tab[i] & 0xFFFF)) + return pdata->tuple_tab[i] >> 16; + +err_out: + printk(KERN_WARNING "DPMC: No suitable CCLK VDDINT voltage pair found\n"); + return VLEV_120; +} + +#ifdef CONFIG_CPU_FREQ +static int +vreg_cpufreq_notifier(struct notifier_block *nb, unsigned long val, void *data) +{ + struct cpufreq_freqs *freq = data; + + if (val == CPUFREQ_PRECHANGE && freq->old < freq->new) { + bfin_set_vlev(bfin_get_vlev(freq->new)); + udelay(pdata->vr_settling_time); /* Wait until Volatge settled */ + + } else if (val == CPUFREQ_POSTCHANGE && freq->old > freq->new) + bfin_set_vlev(bfin_get_vlev(freq->new)); + + return 0; +} + +static struct notifier_block vreg_cpufreq_notifier_block = { + .notifier_call = vreg_cpufreq_notifier +}; +#endif /* CONFIG_CPU_FREQ */ + +/** + * bfin_dpmc_probe - + * + */ +static int __devinit bfin_dpmc_probe(struct platform_device *pdev) +{ + if (pdev->dev.platform_data) + pdata = pdev->dev.platform_data; + else + return -EINVAL; + + return cpufreq_register_notifier(&vreg_cpufreq_notifier_block, + CPUFREQ_TRANSITION_NOTIFIER); +} + +/** + * bfin_dpmc_remove - + */ +static int __devexit bfin_dpmc_remove(struct platform_device *pdev) +{ + pdata = NULL; + return cpufreq_unregister_notifier(&vreg_cpufreq_notifier_block, + CPUFREQ_TRANSITION_NOTIFIER); +} + +struct platform_driver bfin_dpmc_device_driver = { + .probe = bfin_dpmc_probe, + .remove = __devexit_p(bfin_dpmc_remove), + .driver = { + .name = DRIVER_NAME, + } +}; + +/** + * bfin_dpmc_init - Init driver + */ +static int __init bfin_dpmc_init(void) +{ + return platform_driver_register(&bfin_dpmc_device_driver); +} +module_init(bfin_dpmc_init); + +/** + * bfin_dpmc_exit - break down driver + */ +static void __exit bfin_dpmc_exit(void) +{ + platform_driver_unregister(&bfin_dpmc_device_driver); +} +module_exit(bfin_dpmc_exit); + +MODULE_AUTHOR("Michael Hennerich <hennerich@blackfin.uclinux.org>"); +MODULE_DESCRIPTION("cpu power management driver for Blackfin"); +MODULE_LICENSE("GPL"); diff --git a/arch/blackfin/mach-common/dpmc.S b/arch/blackfin/mach-common/dpmc_modes.S index 9d45aa3265b1..b7981d31c392 100644 --- a/arch/blackfin/mach-common/dpmc.S +++ b/arch/blackfin/mach-common/dpmc_modes.S @@ -1,30 +1,7 @@ /* - * File: arch/blackfin/mach-common/dpmc.S - * Based on: - * Author: LG Soft India + * Copyright 2004-2008 Analog Devices Inc. * - * Created: ? - * Description: Watchdog Timer APIs - * - * Modified: - * Copyright 2004-2006 Analog Devices Inc. - * - * Bugs: Enter bugs at http://blackfin.uclinux.org/ - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, see the file COPYING, or write - * to the Free Software Foundation, Inc., - * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + * Licensed under the GPL-2 or later. */ #include <linux/linkage.h> |