/drivers/misc/sun4i-gpio.c

https://bitbucket.org/ndreys/linux-sunxi · C · 269 lines · 204 code · 49 blank · 16 comment · 19 complexity · 57d8a0a4a8a6ba760428ffefa919a307 MD5 · raw file

  1. /* driver/misc/sun4i-gpio.c
  2. *
  3. * Copyright (C) 2011 Allwinner Technology Co.Ltd
  4. * Tom Cubie <tangliang@allwinnertech.com>
  5. *
  6. * www.allwinnertech.com
  7. *
  8. * An ugly sun4i gpio driver
  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. */
  15. #include <linux/module.h>
  16. #include <linux/init.h>
  17. #include <linux/pm.h>
  18. #include <linux/sysdev.h>
  19. #include <linux/fs.h>
  20. #include <linux/kernel.h>
  21. #include <linux/slab.h>
  22. #include <linux/earlysuspend.h>
  23. #include <linux/miscdevice.h>
  24. #include <linux/device.h>
  25. #include <mach/sys_config.h>
  26. #undef DEBUG_SUN4I
  27. #ifdef DEBUG_SUN4I
  28. #define sun4i_gpio_dbg(x...) printk(x)
  29. #else
  30. #define sun4i_gpio_dbg(x...)
  31. #endif
  32. struct sun4i_gpio_data {
  33. int status;
  34. unsigned gpio_handler;
  35. script_gpio_set_t info;
  36. char name[8];
  37. #ifdef CONFIG_HAS_EARLYSUSPEND
  38. struct early_suspend early_suspend;
  39. #endif
  40. };
  41. static int sun4i_gpio_num;
  42. static struct sun4i_gpio_data *psun4i_gpio;
  43. static struct device_attribute *pattr;
  44. static void set_sun4i_gpio_status(struct sun4i_gpio_data *sun4i_gpio, int on)
  45. {
  46. if(on) {
  47. sun4i_gpio_dbg("\n-on-");
  48. gpio_write_one_pin_value(sun4i_gpio->gpio_handler, 1, NULL);
  49. }
  50. else{
  51. sun4i_gpio_dbg("\n-off-");
  52. gpio_write_one_pin_value(sun4i_gpio->gpio_handler, 0, NULL);
  53. }
  54. }
  55. static ssize_t sun4i_gpio_enable_store(struct device *dev,
  56. struct device_attribute *attr,
  57. const char *buf, size_t count)
  58. {
  59. unsigned long data;
  60. int i,error;
  61. struct sun4i_gpio_data *gpio_i = psun4i_gpio;
  62. error = strict_strtoul(buf, 10, &data);
  63. if (error)
  64. return error;
  65. for(i = 0; i < sun4i_gpio_num; i++) {
  66. sun4i_gpio_dbg("%s\n", attr->attr.name);
  67. sun4i_gpio_dbg("%s\n", gpio_i->name);
  68. if(!strcmp(attr->attr.name, gpio_i->name)) {
  69. set_sun4i_gpio_status(gpio_i, data);
  70. break;
  71. }
  72. gpio_i++;
  73. }
  74. return count;
  75. }
  76. static ssize_t sun4i_gpio_enable_show(struct device *dev,
  77. struct device_attribute *attr, char *buf)
  78. {
  79. int i;
  80. int data = EGPIO_FAIL;
  81. struct sun4i_gpio_data *gpio_i = psun4i_gpio;
  82. for(i = 0; i < sun4i_gpio_num; i++) {
  83. sun4i_gpio_dbg("%s\n", attr->attr.name);
  84. sun4i_gpio_dbg("%s\n", gpio_i->name);
  85. if(!strcmp(attr->attr.name, gpio_i->name)) {
  86. data = gpio_read_one_pin_value(gpio_i->gpio_handler, NULL);
  87. sun4i_gpio_dbg("handler:%d\n", gpio_i->gpio_handler);
  88. sun4i_gpio_dbg("data:%d\n", data);
  89. break;
  90. }
  91. gpio_i++;
  92. }
  93. if(data != EGPIO_FAIL) {
  94. return sprintf(buf, "%d\n", data);
  95. } else {
  96. return sprintf(buf, "error\n");
  97. }
  98. }
  99. static struct attribute *sun4i_gpio_attributes[256] = {
  100. NULL
  101. };
  102. static struct attribute_group sun4i_gpio_attribute_group = {
  103. .name = "pin",
  104. .attrs = sun4i_gpio_attributes
  105. };
  106. static int sun4i_gpio_open(struct inode *inode, struct file *file) {
  107. pr_info("sun4i_gpio open\n");
  108. return 0;
  109. }
  110. ssize_t sun4i_gpio_write(struct file *file, const char __user *buf, size_t size, loff_t *offset) {
  111. pr_info("sun4i_gpio write\n");
  112. return 0;
  113. }
  114. static int sun4i_gpio_release(struct inode *inode, struct file *file) {
  115. gpio_release(psun4i_gpio->gpio_handler, 0);
  116. kfree(psun4i_gpio);
  117. return 0;
  118. }
  119. static const struct file_operations sun4i_gpio_fops = {
  120. .open = sun4i_gpio_open,
  121. .write = sun4i_gpio_write,
  122. .release = sun4i_gpio_release
  123. };
  124. static struct miscdevice sun4i_gpio_dev = {
  125. .minor = MISC_DYNAMIC_MINOR,
  126. .name = "sun4i-gpio",
  127. .fops = &sun4i_gpio_fops
  128. };
  129. static int __init sun4i_gpio_init(void) {
  130. int err;
  131. int i;
  132. int sun4i_gpio_used = 0;
  133. struct sun4i_gpio_data *gpio_i;
  134. struct device_attribute *attr_i;
  135. char pin[16];
  136. pr_info("sun4i gpio driver init\n");
  137. err = script_parser_fetch("gpio_para", "gpio_used", &sun4i_gpio_used, sizeof(sun4i_gpio_used)/sizeof(int));
  138. if(err) {
  139. pr_err("%s script_parser_fetch \"gpio_para\" \"gpio_used\" error\n", __FUNCTION__);
  140. goto exit;
  141. }
  142. if(!sun4i_gpio_used) {
  143. pr_err("%s sun4i_gpio is not used in config\n", __FUNCTION__);
  144. err = -1;
  145. goto exit;
  146. }
  147. err = script_parser_fetch("gpio_para", "gpio_num", &sun4i_gpio_num, sizeof(sun4i_gpio_num)/sizeof(int));
  148. if(err) {
  149. pr_err("%s script_parser_fetch \"gpio_para\" \"gpio_num\" error\n", __FUNCTION__);
  150. goto exit;
  151. }
  152. sun4i_gpio_dbg("sun4i_gpio_num:%d\n", sun4i_gpio_num);
  153. if(!sun4i_gpio_num) {
  154. pr_err("%s sun4i_gpio_num is none\n", __FUNCTION__);
  155. err = -1;
  156. goto exit;
  157. }
  158. err = misc_register(&sun4i_gpio_dev);
  159. if(err) {
  160. pr_err("%s register sun4i_gpio as misc device error\n", __FUNCTION__);
  161. goto exit;
  162. }
  163. psun4i_gpio = kzalloc(sizeof(struct sun4i_gpio_data) * sun4i_gpio_num, GFP_KERNEL);
  164. pattr = kzalloc(sizeof(struct device_attribute) * sun4i_gpio_num, GFP_KERNEL);
  165. if(!psun4i_gpio || !pattr) {
  166. pr_err("%s kzalloc failed\n", __FUNCTION__);
  167. err = -ENOMEM;
  168. goto exit;
  169. }
  170. gpio_i = psun4i_gpio;
  171. attr_i = pattr;
  172. for(i = 0; i < sun4i_gpio_num; i++) {
  173. sprintf(pin, "gpio_pin_%d", i+1);
  174. sun4i_gpio_dbg("pin:%s\n", pin);
  175. err = script_parser_fetch("gpio_para", pin,
  176. (int *)&gpio_i->info, sizeof(script_gpio_set_t));
  177. if(err) {
  178. pr_err("%s script_parser_fetch \"gpio_para\" \"%s\" error\n", __FUNCTION__, pin);
  179. break;
  180. }
  181. gpio_i->gpio_handler = gpio_request_ex("gpio_para", pin);
  182. sun4i_gpio_dbg("gpio handler: %d", gpio_i->gpio_handler);
  183. if(!gpio_i->gpio_handler) {
  184. pr_err("%s can not get \"gpio_para\" \"%s\" gpio handler,\
  185. already used by others?", __FUNCTION__, pin);
  186. break;
  187. }
  188. sun4i_gpio_dbg("%s: port:%d, portnum:%d\n", pin, gpio_i->info.port,
  189. gpio_i->info.port_num);
  190. /* Turn the name to pa1, pb2 etc... */
  191. sprintf(gpio_i->name, "p%c%d", 'a'+gpio_i->info.port-1, gpio_i->info.port_num);
  192. sun4i_gpio_dbg("psun4i_gpio->name%s\n", gpio_i->name);
  193. /* Add attributes to the group */
  194. sysfs_attr_init(&attr_i->attr);
  195. attr_i->attr.name = gpio_i->name;
  196. attr_i->attr.mode = S_IRUGO|S_IWUSR|S_IWGRP|S_IWOTH;
  197. attr_i->show = sun4i_gpio_enable_show;
  198. attr_i->store = sun4i_gpio_enable_store;
  199. sun4i_gpio_attributes[i] = &attr_i->attr;
  200. gpio_i++;
  201. attr_i++;
  202. }
  203. sysfs_create_group(&sun4i_gpio_dev.this_device->kobj,
  204. &sun4i_gpio_attribute_group);
  205. exit:
  206. return err;
  207. }
  208. static void __exit sun4i_gpio_exit(void) {
  209. sun4i_gpio_dbg("bye, sun4i_gpio exit\n");
  210. misc_deregister(&sun4i_gpio_dev);
  211. sysfs_remove_group(&sun4i_gpio_dev.this_device->kobj,
  212. &sun4i_gpio_attribute_group);
  213. kfree(psun4i_gpio);
  214. kfree(pattr);
  215. }
  216. module_init(sun4i_gpio_init);
  217. module_exit(sun4i_gpio_exit);
  218. MODULE_DESCRIPTION("a simple sun4i_gpio driver");
  219. MODULE_AUTHOR("Tom Cubie");
  220. MODULE_LICENSE("GPL");