Advertisement
Guest User

Untitled

a guest
Apr 27th, 2015
203
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C 5.61 KB | None | 0 0
  1. /* linux/arch/arm/mach-msm/msm_zen_decision.c
  2.  *
  3.  * In-kernel replacement for MSM/MPDecision userspace service.
  4.  *
  5.  * Copyright (c) 2015 Brandon Berhent
  6.  *
  7.  * This program is free software; you can redistribute it and/or modify
  8.  * it under the terms of the GNU General Public License version 2 and
  9.  * only version 2 as published by the Free Software Foundation.
  10.  *
  11.  * This program is distributed in the hope that it will be useful,
  12.  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  13.  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  14.  * GNU General Public License for more details.
  15.  */
  16.  
  17. #include <linux/module.h>
  18. #include <linux/kobject.h>
  19. #include <linux/sysfs.h>
  20. #include <linux/pm.h>
  21. #include <linux/cpu.h>
  22. #include <linux/cpumask.h>
  23. #include <linux/platform_device.h>
  24. #include <linux/workqueue.h>
  25.  
  26. #define ZEN_DECISION "zen_decision"
  27.  
  28. /* Enable/Disable driver */
  29. unsigned int enabled = 1;
  30.  
  31. /* How long to wait to disable cores on suspend (in ms) */
  32. unsigned int suspend_wait_time = 5000;
  33.  
  34. static struct workqueue_struct *zen_suspend_wq;
  35. static struct delayed_work suspend_work;
  36.  
  37. struct kobject *zendecision_kobj;
  38.  
  39. /*
  40.  * __msm_zen_dec_suspend
  41.  *
  42.  * Core suspend work function.
  43.  * Brings all CPUs except CPU0 offline
  44.  */
  45. static void __msm_zen_dec_suspend(struct work_struct *work)
  46. {
  47.     int cpu;
  48.  
  49.     pr_info("[%s]: SUSPEND DETECT", ZEN_DECISION);
  50.     for_each_online_cpu(cpu) {
  51.         /* Don't call cpu_down if cpu0 */
  52.         if (cpu == 0) continue;
  53.         cpu_down(cpu);
  54.     }
  55. }
  56.  
  57. /*
  58.  * msm_zen_dec_suspend
  59.  *
  60.  * Call __msm_zen_dec_suspend as delayed work by suspend_wait_time
  61.  * This is configurably delayed to avoid excessive CPU downing
  62.  */
  63. static int msm_zen_dec_suspend(struct device *dev)
  64. {
  65.     INIT_DELAYED_WORK(&suspend_work, __msm_zen_dec_suspend);
  66.     queue_delayed_work_on(0, zen_suspend_wq, &suspend_work,
  67.             msecs_to_jiffies(suspend_wait_time));
  68. }
  69.  
  70. /*
  71.  * msm_zen_dec_resume
  72.  *
  73.  * Core resume function.
  74.  * Cancels suspend work and brings all CPUs online.
  75.  */
  76. static int msm_zen_dec_resume(struct device *dev)
  77. {
  78.     int cpu;
  79.  
  80.     /* Clear suspend workqueue */
  81.     flush_workqueue(zen_suspend_wq);
  82.     cancel_delayed_work_sync(&suspend_work);
  83.  
  84.     pr_info("[%s]: WAKE DETECT", ZEN_DECISION);
  85.     for_each_cpu_not(cpu, cpu_online_mask) {
  86.         /* Don't call cpu_up if cpu0 */
  87.         if (cpu == 0) continue;
  88.         cpu_up(cpu);
  89.     }
  90.  
  91.     return 0;
  92. }
  93.  
  94. static const struct dev_pm_ops msm_zen_dec_pm_ops = {
  95.     .suspend = msm_zen_dec_suspend,
  96.     .resume = msm_zen_dec_resume
  97. };
  98.  
  99. /* Sysfs Start */
  100. static ssize_t enable_show(struct kobject *kobj,
  101.     struct kobj_attribute *attr, char *buf)
  102. {
  103.     return sprintf(buf, "%u\n", enabled);
  104. }
  105.  
  106. static ssize_t enable_store(struct kobject *kobj,
  107.     struct kobj_attribute *attr, const char *buf, size_t size)
  108. {
  109.     int ret;
  110.     unsigned long new_val;
  111.  
  112.     ret = kstrtoul(buf, 0, &new_val);
  113.     if (ret < 0)
  114.         return ret;
  115.  
  116.     if (new_val > 0)
  117.         enabled = 1;
  118.     else
  119.         enabled = 0;
  120.  
  121.     return size;
  122. }
  123.  
  124. static ssize_t suspend_delay_show(struct kobject *kobj,
  125.     struct kobj_attribute *attr, char *buf)
  126. {
  127.     return sprintf(buf, "%u\n", enabled);
  128. }
  129.  
  130. static ssize_t suspend_delay_store(struct kobject *kobj,
  131.     struct kobj_attribute *attr, const char *buf, size_t size)
  132. {
  133.     int ret;
  134.     unsigned long new_val;
  135.     ret = kstrtoul(buf, 0, &new_val);
  136.     if (ret < 0)
  137.         return ret;
  138.  
  139.     if (new_val < 0)
  140.         suspend_wait_time = 0;
  141.  
  142.     return size;
  143. }
  144.  
  145. static struct kobj_attribute kobj_enabled =
  146.     __ATTR(enabled, 0644, enable_show,
  147.         enable_store);
  148.  
  149. static struct kobj_attribute kobj_suspend_wait =
  150.     __ATTR(suspend_wait_time, 0644, suspend_delay_show,
  151.         suspend_delay_store);
  152.  
  153. static struct attribute *zen_decision_attrs[] = {
  154.     &kobj_enabled.attr, &kobj_suspend_wait, NULL,
  155. };
  156.  
  157. static struct attribute_group zen_decision_option_group = {
  158.     .attrs = zen_decision_attrs,
  159. };
  160.  
  161. /* Sysfs End */
  162.  
  163. static int zen_decision_probe(struct platform_device *pdev)
  164. {
  165.     int ret;
  166.  
  167.     /* Set default settings */
  168.     enabled = 1;
  169.  
  170.     /* Setup sysfs */
  171.     zendecision_kobj = kobject_create_and_add("zen_decision", kernel_kobj);
  172.     if (zendecision_kobj == NULL) {
  173.         pr_err("[%s]: subsystem register failed. \n", ZEN_DECISION);
  174.         return -ENOMEM;
  175.     }
  176.    
  177.     ret = sysfs_create_group(zendecision_kobj, &zen_decision_option_group);
  178.     if (ret) {
  179.         pr_info("[%s]: sysfs interface failed to initialize\n", ZEN_DECISION);
  180.         return -EINVAL;
  181.     } else
  182.         pr_info("[%s]: sysfs interface initialized.\n", ZEN_DECISION);
  183.  
  184.     /* Setup Workqueues */
  185.     zen_suspend_wq = alloc_workqueue("zen_suspend_wq", WQ_FREEZABLE, 0);
  186.     if (!zen_suspend_wq) {
  187.         pr_err("[%s]: Failed to allocate suspend workqueue\n", ZEN_DECISION);
  188.         return -ENOMEM;
  189.     }
  190.  
  191.     return ret;
  192. }
  193.  
  194. static int zen_decision_remove(struct platform_device *pdev)
  195. {
  196.     kobject_put(zendecision_kobj);
  197.  
  198.     flush_workqueue(zen_suspend_wq);
  199.     cancel_delayed_work_sync(&suspend_work);
  200.     destroy_workqueue(suspend_workqueue);  
  201.  
  202.     return 0;
  203. }
  204.  
  205. static struct platform_driver zen_decision_driver = {
  206.     .probe = zen_decision_probe,
  207.     .remove = zen_decision_remove,
  208.     .driver = {
  209.         .name = ZEN_DECISION,
  210.         .owner = THIS_MODULE,
  211.         .pm = &msm_zen_dec_pm_ops,
  212.     }
  213. };
  214.  
  215. static int __init zen_decision_init(void)
  216. {
  217.     int ret = platform_driver_register(&zen_decision_driver);
  218.     if (ret)
  219.         pr_err("[%s]: platform_driver_register_failed: %d\n", ZEN_DECISION, ret);
  220.  
  221.     return ret;
  222. }
  223.  
  224. static void __exit zen_decision_exit(void)
  225. {
  226.     platform_driver_unregister(&zen_decision_driver);
  227. }
  228.  
  229. late_initcall(zen_decision_init);
  230. module_exit(zen_decision_exit);
  231.  
  232. MODULE_VERSION("1.0");
  233. MODULE_DESCRIPTION("Zen Decision MPDecision Replacement");
  234. MODULE_LICENSE("GPL v2");
  235. MODULE_AUTHOR("Brandon Berhent <bbedward@gmail.com>");
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement