summaryrefslogtreecommitdiff
path: root/drivers/power
diff options
context:
space:
mode:
authorAnshul Jain <anshulj@nvidia.com>2011-12-08 17:22:09 -0800
committerVarun Wadekar <vwadekar@nvidia.com>2011-12-21 12:06:21 +0530
commit57d2376b768c9eb8a9c669d5a06a9a75972b8669 (patch)
tree38bdabfadf49029db8df866aabc48bb5e6bd344e /drivers/power
parent43930ec309b8c122f7648f64116e5b77880c5635 (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/Kconfig7
-rw-r--r--drivers/power/Makefile1
-rw-r--r--drivers/power/tegra_bpc_mgmt.c139
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, &param);
+ }
+
+ 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");