/* * 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 #include #include #include #include #include #include #include #include #include #include static irqreturn_t tegra_bpc_mgmt_bh(int irq, void *data) { int ret = -1; int gpio_val = 0; struct tegra_bpc_mgmt_platform_data *bpc_platform_data; bpc_platform_data = (struct tegra_bpc_mgmt_platform_data *)data; /** * Keep on checking whether event has passed or not. */ while (!gpio_val) { if (ret) ret = tegra_system_edp_alarm(true); 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");