secgpio_dvs.c 8.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336
  1. /*
  2. * Samsung Mobile VE Group.
  3. *
  4. * drivers/gpio/secgpio_dvs.c
  5. *
  6. * Drivers for samsung gpio debugging & verification.
  7. *
  8. * Copyright (C) 2013, Samsung Electronics.
  9. *
  10. * This program is free software. You can redistribute it and/or modify
  11. * it under the terms of the GNU General Public License version 2 as
  12. * published by the Free Software Foundation
  13. */
  14. #include <linux/module.h>
  15. #include <linux/interrupt.h>
  16. #include <linux/workqueue.h>
  17. #include <linux/proc_fs.h>
  18. #include <linux/delay.h>
  19. #include <linux/types.h>
  20. #include <linux/platform_device.h>
  21. #include <linux/timer.h>
  22. #include <linux/power_supply.h>
  23. #include <linux/sched.h>
  24. #include <linux/init.h>
  25. #include <linux/fs.h>
  26. #include <linux/gpio.h>
  27. #include <linux/kernel.h>
  28. #include <linux/string.h>
  29. #include <linux/slab.h>
  30. #include "secgpio_dvs.h"
  31. #include <trace/events/power.h>
  32. /* mutex */
  33. static DEFINE_MUTEX(gpio_debug_lock);
  34. /*sys fs*/
  35. struct class *secgpio_dvs_class;
  36. EXPORT_SYMBOL(secgpio_dvs_class);
  37. struct device *secgpio_dotest;
  38. EXPORT_SYMBOL(secgpio_dotest);
  39. /* extern GPIOMAP_RESULT GpioMap_result; */
  40. static struct gpio_dvs_t *gdvs_info;
  41. static ssize_t checked_secgpio_file_read(
  42. struct device *dev, struct device_attribute *attr, char *buf);
  43. static ssize_t checked_sleep_secgpio_file_read(
  44. struct device *dev, struct device_attribute *attr, char *buf);
  45. static ssize_t checked_secgpio_init_read_details(
  46. struct device *dev, struct device_attribute *attr, char *buf);
  47. static ssize_t checked_secgpio_sleep_read_details(
  48. struct device *dev, struct device_attribute *attr, char *buf);
  49. static ssize_t secgpio_checked_sleepgpio_read(
  50. struct device *dev, struct device_attribute *attr, char *buf);
  51. static ssize_t checked_secgpio_init_call(struct device *dev,
  52. struct device_attribute *attr, const char *buf, size_t len);
  53. static DEVICE_ATTR(gpioinit_check, 0664,
  54. checked_secgpio_file_read, NULL);
  55. static DEVICE_ATTR(gpiosleep_check, 0664,
  56. checked_sleep_secgpio_file_read, NULL);
  57. static DEVICE_ATTR(check_init_detail, 0664,
  58. checked_secgpio_init_read_details, NULL);
  59. static DEVICE_ATTR(check_sleep_detail, 0664,
  60. checked_secgpio_sleep_read_details, NULL);
  61. static DEVICE_ATTR(checked_sleepGPIO, 0664,
  62. secgpio_checked_sleepgpio_read, NULL);
  63. static DEVICE_ATTR(gpioinit_call, 0664,
  64. NULL, checked_secgpio_init_call);
  65. static struct attribute *secgpio_dvs_attributes[] = {
  66. &dev_attr_gpioinit_check.attr,
  67. &dev_attr_gpiosleep_check.attr,
  68. &dev_attr_check_init_detail.attr,
  69. &dev_attr_check_sleep_detail.attr,
  70. &dev_attr_checked_sleepGPIO.attr,
  71. &dev_attr_gpioinit_call.attr,
  72. NULL,
  73. };
  74. static struct attribute_group secgpio_dvs_attr_group = {
  75. .attrs = secgpio_dvs_attributes,
  76. };
  77. static ssize_t checked_secgpio_file_read(
  78. struct device *dev, struct device_attribute *attr, char *buf)
  79. {
  80. int i = 0;
  81. char temp_buf[20];
  82. struct gpio_dvs_t *gdvs = dev_get_drvdata(dev);
  83. for (i = 0; i < gdvs->count; i++) {
  84. memset(temp_buf, 0, sizeof(char)*20);
  85. snprintf(temp_buf, 20, "%x ", gdvs->result->init[i]);
  86. strlcat(buf, temp_buf, PAGE_SIZE);
  87. }
  88. return strlen(buf);
  89. }
  90. static ssize_t checked_sleep_secgpio_file_read(
  91. struct device *dev, struct device_attribute *attr, char *buf)
  92. {
  93. int i = 0;
  94. char temp_buf[20];
  95. struct gpio_dvs_t *gdvs = dev_get_drvdata(dev);
  96. for (i = 0; i < gdvs->count; i++) {
  97. memset(temp_buf, 0, sizeof(char)*20);
  98. snprintf(temp_buf, 20, "%x ", gdvs->result->sleep[i]);
  99. strlcat(buf, temp_buf, PAGE_SIZE);
  100. }
  101. return strlen(buf);
  102. }
  103. static ssize_t checked_secgpio_init_read_details(
  104. struct device *dev, struct device_attribute *attr, char *buf)
  105. {
  106. int i = 0;
  107. char temp_buf[20];
  108. struct gpio_dvs_t *gdvs = dev_get_drvdata(dev);
  109. for (i = 0; i < gdvs->count; i++) {
  110. memset(temp_buf, 0, sizeof(char)*20);
  111. snprintf(temp_buf, 20, "GI[%d] - %x\n ",
  112. i, gdvs->result->init[i]);
  113. strlcat(buf, temp_buf, PAGE_SIZE);
  114. }
  115. return strlen(buf);
  116. }
  117. static ssize_t checked_secgpio_sleep_read_details(
  118. struct device *dev, struct device_attribute *attr, char *buf)
  119. {
  120. int i = 0;
  121. char temp_buf[20];
  122. struct gpio_dvs_t *gdvs = dev_get_drvdata(dev);
  123. for (i = 0; i < gdvs->count; i++) {
  124. memset(temp_buf, 0, sizeof(char)*20);
  125. snprintf(temp_buf, 20, "GS[%d] - %x\n ",
  126. i, gdvs->result->sleep[i]);
  127. strlcat(buf, temp_buf, PAGE_SIZE);
  128. }
  129. return strlen(buf);
  130. }
  131. static ssize_t secgpio_checked_sleepgpio_read(
  132. struct device *dev, struct device_attribute *attr, char *buf)
  133. {
  134. struct gpio_dvs_t *gdvs = dev_get_drvdata(dev);
  135. if (gdvs->check_sleep)
  136. return snprintf(buf, PAGE_SIZE, "1");
  137. else
  138. return snprintf(buf, PAGE_SIZE, "0");
  139. }
  140. static ssize_t checked_secgpio_init_call(struct device *dev,
  141. struct device_attribute *attr, const char *buf, size_t len)
  142. {
  143. /* Check init gpio status */
  144. gpio_dvs_check_initgpio();
  145. return len;
  146. }
  147. void gpio_dvs_check_initgpio(void)
  148. {
  149. if (gdvs_info && gdvs_info->check_gpio_status)
  150. gdvs_info->check_gpio_status(PHONE_INIT);
  151. }
  152. EXPORT_SYMBOL(gpio_dvs_check_initgpio);
  153. void gpio_dvs_check_sleepgpio(void)
  154. {
  155. if (unlikely(gdvs_info && !gdvs_info->check_sleep)) {
  156. gdvs_info->check_gpio_status(PHONE_SLEEP);
  157. gdvs_info->check_sleep = true;
  158. }
  159. }
  160. #ifdef CONFIG_OF
  161. static const struct of_device_id secgpio_dvs_dt_match[] = {
  162. { .compatible = "samsung,secgpio-dvs",
  163. .data = (void *)&msm_gpio_dvs_data },
  164. { },
  165. };
  166. MODULE_DEVICE_TABLE(of, secgpio_dvs_dt_match);
  167. static struct secgpio_dvs_data *secgpio_dvs_get_soc_data(
  168. struct platform_device *pdev)
  169. {
  170. const struct of_device_id *match;
  171. struct device_node *node = pdev->dev.of_node;
  172. struct secgpio_dvs_data *data;
  173. match = of_match_node(secgpio_dvs_dt_match, node);
  174. if (!match) {
  175. dev_err(&pdev->dev, "failed to get SoC node\n");
  176. return NULL;
  177. }
  178. data = (struct secgpio_dvs_data *)match->data;
  179. if (!data) {
  180. dev_err(&pdev->dev, "failed to get SoC data\n");
  181. return NULL;
  182. }
  183. return data;
  184. }
  185. #else
  186. static struct gpio_dvs_t *secgpio_dvs_get_soc_data(struct platform_device *pdev)
  187. {
  188. return dev_get_platdata(&pdev->dev);
  189. }
  190. #endif
  191. static int secgpio_dvs_probe(struct platform_device *pdev)
  192. {
  193. int ret = 0;
  194. struct class *secgpio_dvs_class;
  195. struct device *secgpio_dotest;
  196. struct secgpio_dvs_data *data = secgpio_dvs_get_soc_data(pdev);
  197. struct gpio_dvs_t *gdvs;
  198. pr_info("[secgpio_dvs] %s has been created!!!\n", __func__);
  199. if (!data)
  200. return -ENODEV;
  201. gdvs = data->gpio_dvs;
  202. secgpio_dvs_class = class_create(THIS_MODULE, "secgpio_check");
  203. if (IS_ERR(secgpio_dvs_class)) {
  204. ret = PTR_ERR(secgpio_dvs_class);
  205. pr_err("Failed to create class(secgpio_check_all)");
  206. goto fail_out;
  207. }
  208. secgpio_dotest = device_create(secgpio_dvs_class,
  209. NULL, 0, NULL, "secgpio_check_all");
  210. if (IS_ERR(secgpio_dotest)) {
  211. ret = PTR_ERR(secgpio_dotest);
  212. pr_err("Failed to create device(secgpio_check_all)");
  213. goto fail1;
  214. }
  215. dev_set_drvdata(secgpio_dotest, gdvs);
  216. gdvs_info = gdvs;
  217. ret = sysfs_create_group(&secgpio_dotest->kobj,
  218. &secgpio_dvs_attr_group);
  219. if (ret) {
  220. pr_err("Failed to create sysfs group");
  221. goto fail2;
  222. }
  223. return ret;
  224. fail2:
  225. device_destroy(secgpio_dvs_class, 0);
  226. fail1:
  227. class_destroy(secgpio_dvs_class);
  228. fail_out:
  229. if (ret)
  230. pr_err(" (err = %d)!\n", ret);
  231. return ret;
  232. }
  233. static int secgpio_dvs_remove(struct platform_device *pdev)
  234. {
  235. return 0;
  236. }
  237. static struct platform_driver secgpio_dvs = {
  238. .probe = secgpio_dvs_probe,
  239. .remove = secgpio_dvs_remove,
  240. .driver = {
  241. .name = "secgpio_dvs",
  242. .owner = THIS_MODULE,
  243. #ifdef CONFIG_OF
  244. .of_match_table = of_match_ptr(secgpio_dvs_dt_match),
  245. #endif
  246. },
  247. };
  248. static void gpio_debug_suspend_trace_probe(void *unused,
  249. const char *action, int val, bool start)
  250. {
  251. if (start && val > 0 && !strcmp("machine_suspend", action)) {
  252. mutex_lock(&gpio_debug_lock);
  253. gpio_dvs_check_sleepgpio();
  254. mutex_unlock(&gpio_debug_lock);
  255. }
  256. }
  257. static int __init secgpio_dvs_init(void)
  258. {
  259. int ret;
  260. ret = platform_driver_register(&secgpio_dvs);
  261. pr_info("[secgpio_dvs] %s has been initialized!!!, ret=%d\n", __func__, ret);
  262. /* Register callback for cheking sleep gpio status */
  263. ret = register_trace_suspend_resume(
  264. gpio_debug_suspend_trace_probe, NULL);
  265. if (ret) {
  266. pr_err("%s: Failed to register suspend trace callback, ret=%d\n",
  267. __func__, ret);
  268. return ret;
  269. }
  270. return ret;
  271. }
  272. static void __exit secgpio_dvs_exit(void)
  273. {
  274. unregister_trace_suspend_resume(
  275. gpio_debug_suspend_trace_probe, NULL);
  276. platform_driver_unregister(&secgpio_dvs);
  277. }
  278. module_init(secgpio_dvs_init);
  279. module_exit(secgpio_dvs_exit);
  280. MODULE_DESCRIPTION("Samsung GPIO debugging and verification");
  281. MODULE_LICENSE("GPL v2");