diff options
author | Anshul Jain <anshulj@nvidia.com> | 2011-12-08 17:22:09 -0800 |
---|---|---|
committer | Varun Wadekar <vwadekar@nvidia.com> | 2011-12-21 12:06:21 +0530 |
commit | 57d2376b768c9eb8a9c669d5a06a9a75972b8669 (patch) | |
tree | 38bdabfadf49029db8df866aabc48bb5e6bd344e /drivers/power | |
parent | 43930ec309b8c122f7648f64116e5b77880c5635 (diff) |
power: bpcm: Battery Peak Power Management driver
This driver reduces CPU frequency in half by setting the CCLK_DIVIDER on
GPIO level triggered event by current monitoring device. It then calls
dvfs apis to reduce cpu frequency/voltage.
Change-Id: I703e2277243df5328ee6a46478ec8b7a3dab93aa
Signed-off-by: Anshul Jain <anshulj@nvidia.com>
Reviewed-on: http://git-master/r/68794
Reviewed-on: http://git-master/r/69103
Reviewed-by: Automatic_Commit_Validation_User
Reviewed-by: Peter Boonstoppel <pboonstoppel@nvidia.com>
Reviewed-by: Dan Willemsen <dwillemsen@nvidia.com>
Diffstat (limited to 'drivers/power')
-rw-r--r-- | drivers/power/Kconfig | 7 | ||||
-rw-r--r-- | drivers/power/Makefile | 1 | ||||
-rw-r--r-- | drivers/power/tegra_bpc_mgmt.c | 139 |
3 files changed, 147 insertions, 0 deletions
diff --git a/drivers/power/Kconfig b/drivers/power/Kconfig index b679e2d9785b..d70887fa2e1e 100644 --- a/drivers/power/Kconfig +++ b/drivers/power/Kconfig @@ -272,3 +272,10 @@ config CHARGER_MAX8998 platform data of MAX8998/LP3974 PMICs. endif # POWER_SUPPLY + +config TEGRA_BPC_MGMT + tristate "battery peak current management" + depends on ARCH_TEGRA + help + This driver reduces cpu frequency/voltage on gpio event from the + battery current monitor device. diff --git a/drivers/power/Makefile b/drivers/power/Makefile index 6c457346a537..82bdd18e3d81 100644 --- a/drivers/power/Makefile +++ b/drivers/power/Makefile @@ -41,3 +41,4 @@ obj-$(CONFIG_CHARGER_GPIO) += gpio-charger.o obj-$(CONFIG_CHARGER_MAX8997) += max8997_charger.o obj-$(CONFIG_CHARGER_MAX8998) += max8998_charger.o obj-$(CONFIG_MAX8907C_CHARGER) += max8907c-charger.o +obj-$(CONFIG_TEGRA_BPC_MGMT) += tegra_bpc_mgmt.o diff --git a/drivers/power/tegra_bpc_mgmt.c b/drivers/power/tegra_bpc_mgmt.c new file mode 100644 index 000000000000..0d9ddeee282e --- /dev/null +++ b/drivers/power/tegra_bpc_mgmt.c @@ -0,0 +1,139 @@ +/* + * Copyright (C) 2010-2011 NVIDIA Corporation + * + * This software is licensed under the terms of the GNU General Public + * License version 2, as published by the Free Software Foundation, and + * may be copied, distributed, and modified under those terms. + * + * 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. + * + */ + +#include <linux/module.h> +#include <linux/gpio.h> +#include <linux/platform_device.h> +#include <linux/interrupt.h> +#include <linux/irqflags.h> +#include <linux/slab.h> +#include <linux/irq.h> +#include <linux/sched.h> +#include <linux/jiffies.h> +#include <linux/platform_data/tegra_bpc_mgmt.h> + +#include <mach/edp.h> + +static irqreturn_t tegra_bpc_mgmt_bh(int irq, void *data) +{ + int gpio_val = 0; + struct tegra_bpc_mgmt_platform_data *bpc_platform_data; + bpc_platform_data = (struct tegra_bpc_mgmt_platform_data *)data; + + tegra_system_edp_alarm(true); + /** + * Keep on checking whether event has passed or not. + */ + while (!gpio_val) { + set_current_state(TASK_INTERRUPTIBLE); + schedule_timeout(msecs_to_jiffies( + bpc_platform_data->bpc_mgmt_timeout)); + + gpio_val = gpio_get_value(bpc_platform_data->gpio_trigger); + } + + tegra_system_edp_alarm(false); + + return IRQ_HANDLED; +} + +static irqreturn_t tegra_bpc_mgmt_isr(int irq, void *data) +{ + tegra_edp_throttle_cpu_now(2); + return IRQ_WAKE_THREAD; +} + +static __devinit int tegra_bpc_mgmt_probe(struct platform_device *pdev) +{ + u32 ret; + struct task_struct *bh_thread; + struct irq_desc *bat_desc; + struct sched_param param = { .sched_priority = MAX_RT_PRIO-1 }; + struct tegra_bpc_mgmt_platform_data *bpc_platform_data; + + bpc_platform_data = pdev->dev.platform_data; + if (!bpc_platform_data) + return -ENODEV; + + if (gpio_is_valid(bpc_platform_data->gpio_trigger)) { + ret = gpio_request(bpc_platform_data->gpio_trigger, + "tegra-bpc-mgmt"); + + if (ret < 0) { + pr_err("BPC: GPIO request failed"); + return -ENODEV; + } + } else { + pr_err("BPC: GPIO check failed, gpio %d", + bpc_platform_data->gpio_trigger); + return -ENODEV; + } + + gpio_direction_input(bpc_platform_data->gpio_trigger); + + ret = request_threaded_irq( + gpio_to_irq(bpc_platform_data->gpio_trigger), + tegra_bpc_mgmt_isr, + tegra_bpc_mgmt_bh, IRQF_TRIGGER_LOW | IRQF_ONESHOT, + "tegra-bpc-mgmt", bpc_platform_data); + if (ret < 0) { + pr_err("BPC:IRQ Installation failed\n"); + return -ENODEV; + } + bat_desc = irq_to_desc( + gpio_to_irq(bpc_platform_data->gpio_trigger)); + + if (bat_desc) { + bh_thread = bat_desc->action->thread; + if (bh_thread) + sched_setscheduler_nocheck(bh_thread, + SCHED_FIFO, ¶m); + } + + return 0; +} + +static __devexit int tegra_bpc_mgmt_remove(struct platform_device *pdev) +{ + struct tegra_bpc_mgmt_platform_data *bpc_platform_data; + bpc_platform_data = pdev->dev.platform_data; + free_irq(gpio_to_irq(bpc_platform_data->gpio_trigger), NULL); + return 0; +} + +static struct platform_driver tegra_bpc_mgmt_driver = { + .probe = tegra_bpc_mgmt_probe, + .remove = tegra_bpc_mgmt_remove, + .driver = { + .name = "tegra-bpc-mgmt", + .owner = THIS_MODULE, + }, +}; + +static int __init tegra_bpc_mgmt_init(void) +{ + return platform_driver_register(&tegra_bpc_mgmt_driver); +} + +static void __exit tegra_bpc_mgmt_exit(void) +{ + platform_driver_unregister(&tegra_bpc_mgmt_driver); +} + +module_init(tegra_bpc_mgmt_init); +module_exit(tegra_bpc_mgmt_exit); + +MODULE_DESCRIPTION("TEGRA Battery Peak current Management"); +MODULE_AUTHOR("NVIDIA"); +MODULE_LICENSE("GPL"); |