/*
* 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");