arkn141-dongle-poweroff.c 9.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358
  1. /*
  2. *
  3. *arkn141_dongle_power_off driver
  4. *Author: Arkmicro
  5. *Created: 2020-05-11
  6. * Suit: arkn141 5G WiFi dongle board
  7. *
  8. */
  9. #include <linux/kernel.h>
  10. #include <linux/module.h>
  11. #include <linux/init.h>
  12. #include <linux/types.h>
  13. #include <linux/fs.h>
  14. #include <linux/mm.h>
  15. #include <linux/cdev.h>
  16. #include <linux/errno.h>
  17. #include <linux/sched.h>
  18. #include <linux/device.h>
  19. #include <linux/slab.h>
  20. #include <linux/errno.h>
  21. #include <linux/list.h>
  22. #include <linux/delay.h>
  23. #include <linux/platform_device.h>
  24. #include <linux/dma-mapping.h>
  25. #include <linux/poll.h>
  26. #include <linux/interrupt.h>
  27. #include <linux/irq.h>
  28. #include <asm/setup.h>
  29. #include <asm/gpio.h>
  30. #include <asm/io.h>
  31. #include <asm/switch_to.h>
  32. #include <asm/uaccess.h>
  33. #include <linux/delay.h>
  34. #include<linux/timer.h>
  35. #include<linux/jiffies.h>
  36. //#define KILL_FASYNC_MODE
  37. #define POLL_MODE
  38. #define ARK_POWER_IOC_MAGIC 'm'
  39. #define ARK_POWER_OFF _IO(ARK_POWER_IOC_MAGIC, 0)
  40. #define ARK_POWER_ON _IO(ARK_POWER_IOC_MAGIC, 1)
  41. #define ARK_POWER_RESTART _IO(ARK_POWER_IOC_MAGIC, 2)
  42. #define TIMER_TIMEOUT 200 //单位ms //5*1000ms //200ms
  43. #define SIGIO_TIMEOUT 1000
  44. /* Convert GPIO signal to GPIO pin number */
  45. //#define GPIO_TO_PIN(bank, gpio) (16 * (bank) + (gpio)) //old
  46. //#define GPIO_TO_PIN(bank, gpio) (32 * (bank) + (gpio)) //new
  47. //#define GPIO_NUM GPIO_TO_PIN(3,5) //:GPIO3_5
  48. #define GPIO_PWR_OFF 30 //控制IO:PWR_OFF
  49. #define GPIO_ACC_DE 32 //检测IO:ACC_DE
  50. #define POWEROFF_MAJOR 200
  51. static struct class *arkn141_dev_class;
  52. static struct fasync_struct *fasync_queue; //异步通知队列
  53. static unsigned int gpioToIrq;
  54. int major;
  55. struct timer_list timer; //定义一个内核定时器
  56. static bool is_power_off= false;
  57. static bool wait_timeout= false;
  58. struct device *poweroff_dev = NULL;
  59. int gpio_acc_value;
  60. unsigned int acc_Trigger;
  61. //unsigned int wait_timeout = 0;
  62. DECLARE_WAIT_QUEUE_HEAD(accoff_waitq);//注册一个等待队列button_waitq
  63. int arkn141_dongle_poweroff_open(struct inode *inode,struct file *filp)
  64. {
  65. //printk("--------%s----------------%d\n", __FUNCTION__, __LINE__);
  66. return 0;
  67. }
  68. int arkn141_dongle_poweroff_release(struct inode *inode,struct file *filp)
  69. {
  70. //printk("--------%s----------------%d\n", __FUNCTION__, __LINE__);
  71. return 0;
  72. }
  73. /*
  74. :write
  75. */
  76. ssize_t arkn141_dongle_poweroff_write(struct file *file,const char __user *buf,size_t count,loff_t *f_pos)
  77. {
  78. //printk("--------%s----------------%d\n", __FUNCTION__, __LINE__);
  79. return 0;
  80. }
  81. /*
  82. :read
  83. */
  84. ssize_t arkn141_dongle_poweroff_read(struct file *filp,char __user *buf,size_t count,loff_t *f_pos)
  85. {
  86. //printk("--------%s----------------%d\n", __FUNCTION__, __LINE__);
  87. int ret;
  88. if(count != 1)
  89. {
  90. printk("%s----------------%d: read error!!!\n",__FUNCTION__, __LINE__);
  91. return -1;
  92. }
  93. wait_event_interruptible(accoff_waitq, gpio_acc_value);//将当前进程放入等待队列button_waitq中
  94. ret = copy_to_user(buf, &gpio_acc_value, 1);
  95. acc_Trigger = 0; //按键已经处理可以继续睡眠
  96. if(ret)
  97. {
  98. printk("%s----------------%d: copy_to_user error!!!\n",__FUNCTION__, __LINE__);
  99. return -1;
  100. }
  101. return ret;
  102. }
  103. /*
  104. .poll
  105. */
  106. static unsigned int arkn141_dongle_poweroff_poll(struct file *fp, poll_table * wait) //fp:文件 wait:
  107. {
  108. unsigned int ret = 0;
  109. poll_wait(fp, &accoff_waitq, wait);
  110. if(acc_Trigger) //中断事件标志, 1:退出休眠状态 0:进入休眠状态
  111. ret |= POLLIN | POLLRDNORM;
  112. return ret; //当超时,就返给应用层为0 ,被唤醒了就返回POLLIN | POLLRDNORM ;
  113. }
  114. static long arkn141_dongle_poweroff_ioctl(struct file *filp,unsigned int cmd, unsigned long arg)
  115. {
  116. //printk("--------%s----------------%d\n", __FUNCTION__, __LINE__);
  117. unsigned long error = 0;
  118. switch (cmd)
  119. {
  120. case ARK_POWER_OFF:
  121. {
  122. printk("ARK_POWER_OFF\n");
  123. if (!gpio_is_valid(GPIO_PWR_OFF))
  124. return -1;
  125. gpio_direction_output(GPIO_PWR_OFF,0);
  126. break;
  127. }
  128. case ARK_POWER_ON:
  129. {
  130. printk("ARK_POWER_ON\n");
  131. if (!gpio_is_valid(GPIO_PWR_OFF))
  132. return -1;
  133. gpio_direction_output(GPIO_PWR_OFF,1);
  134. break;
  135. }
  136. case ARK_POWER_RESTART:
  137. {
  138. printk("ARK_POWER_RESTART\n");
  139. break;
  140. }
  141. default:
  142. printk("%s: error cmd 0x%x\n", __func__, cmd);
  143. error = -EFAULT;
  144. }
  145. return error;
  146. }
  147. static void ark_power_off_handler(struct timer_list *t)
  148. {
  149. #ifdef POLL_MODE
  150. if(wait_timeout){
  151. printk("ACC OFF WAITING TIMEOUT:POWER_OFF\n");
  152. if (!gpio_is_valid(GPIO_PWR_OFF))
  153. return -1;
  154. gpio_direction_output(GPIO_PWR_OFF,0);
  155. }
  156. if(gpio_acc_value)
  157. {
  158. mod_timer(&timer, jiffies + msecs_to_jiffies(SIGIO_TIMEOUT));//重置定时器,等待未收到反馈则自动关机
  159. wait_timeout = true;
  160. /**/
  161. //.poll mode
  162. wake_up_interruptible(&accoff_waitq); //唤醒休眠的进程
  163. acc_Trigger = 1;
  164. /**/
  165. /**
  166. //SIGIO mode
  167. printk("Send SIGIO to client\n");
  168. if (fasync_queue) {
  169. kill_fasync(&fasync_queue, SIGIO, POLL_IN);
  170. }
  171. **/
  172. }
  173. else{
  174. del_timer(&timer); //删除定时器
  175. is_power_off = false;
  176. }
  177. #endif
  178. }
  179. /***************************************************************
  180. :fasync
  181. ***************************************************************/
  182. static int arkn141_dongle_poweroff_fasync(int fd, struct file * filp, int on)
  183. {
  184. //printk("--------%s----------------%d\n", __FUNCTION__, __LINE__);
  185. //int retval;
  186. //retval=fasync_helper(fd,filp,on,&fasync_queue);
  187. //if(retval<0)
  188. // return retval;
  189. return 0;
  190. }
  191. static const struct file_operations arkn141_dongle_poweroff_fops={
  192. .owner=THIS_MODULE,
  193. .open=arkn141_dongle_poweroff_open,
  194. .unlocked_ioctl= arkn141_dongle_poweroff_ioctl,
  195. .release=arkn141_dongle_poweroff_release,
  196. .fasync=arkn141_dongle_poweroff_fasync,
  197. .write=arkn141_dongle_poweroff_write,
  198. .read=arkn141_dongle_poweroff_read,
  199. .poll =arkn141_dongle_poweroff_poll,
  200. };
  201. /*
  202. irqreturn_t
  203. */
  204. static irqreturn_t arkn141_dongle_poweroff_interrupt (int irq, void *dev_id)
  205. {
  206. printk("arkn141 dongle power off driver irq work !!!\n");
  207. #ifdef POLL_MODE
  208. if (!gpio_is_valid(GPIO_ACC_DE))
  209. return -1;
  210. gpio_acc_value = gpio_get_value(GPIO_ACC_DE);//acc_off_value:1 acc_on_value:0
  211. //printk("get gpio(32) value= %d\n",gpio_acc_value);
  212. if(!is_power_off)
  213. {
  214. //printk("------------>Start_timer:%d ms<------------\n",TIMER_TIMEOUT);
  215. timer_setup(&timer, ark_power_off_handler, 0); //初始化定时器
  216. timer.expires = jiffies + msecs_to_jiffies(TIMER_TIMEOUT); //设定超时时间,(TIMER_TIMEOUT)ms
  217. add_timer(&timer); //添加定时器,定时器开始生效
  218. is_power_off = true;
  219. }
  220. else
  221. {
  222. //printk("------------>Reset timer:%d ms<------------\n",TIMER_TIMEOUT);
  223. //del_timer(&timer);//删除定时器
  224. mod_timer(&timer, jiffies + msecs_to_jiffies(TIMER_TIMEOUT));//重新设置定时器
  225. }
  226. #endif
  227. return IRQ_HANDLED;
  228. }
  229. /**
  230. static int arkn141_dongle_poweroff_probe(struct platform_device *pdev)
  231. {
  232. printk("--------%s----------------%d\n", __FUNCTION__, __LINE__);
  233. return 0;
  234. }
  235. static int arkn141_dongle_poweroff_remove(struct platform_device *pdev)
  236. {
  237. printk("--------%s----------------%d\n", __FUNCTION__, __LINE__);
  238. return 0;
  239. }
  240. **/
  241. int arkn141_dongle_poweroff_drv_init(void)
  242. {
  243. //printk("--------%s----------------%d\n", __FUNCTION__, __LINE__);
  244. int rtn;
  245. unsigned long req_flags = IRQF_TRIGGER_RISING;//上升沿触发:IRQF_TRIGGER_RISING 下降沿触发:IRQF_TRIGGER_FALLING
  246. major = register_chrdev(0,"arkn141_poweroff",&arkn141_dongle_poweroff_fops);
  247. if(major<0){
  248. printk("Unable to register character device %d!/n",major);
  249. return major;
  250. }
  251. arkn141_dev_class = class_create(THIS_MODULE, "arkn141_poweroff_class");
  252. poweroff_dev = device_create(arkn141_dev_class, NULL, MKDEV(major, 0), NULL,"arkn141_poweroff");
  253. if (!gpio_is_valid(GPIO_ACC_DE)){
  254. printk("gpio_is_valid failed!!!!!\n");
  255. return -1;
  256. }
  257. //int ret = gpio_get_value(GPIO_ACC_DE);
  258. //printk("get gpio(32) value= %d\n",ret);
  259. rtn = gpio_request(GPIO_ACC_DE, "acc_off");
  260. if(rtn!=0){
  261. printk("acc_off irq pin request io failed.\n");
  262. }
  263. gpioToIrq = gpio_to_irq(GPIO_ACC_DE);
  264. rtn = request_irq(gpioToIrq, arkn141_dongle_poweroff_interrupt,req_flags,"acc_off", NULL); //上升沿触发
  265. if (rtn<0) {
  266. printk("acc_off request irq false!!!!!\n");
  267. } else {
  268. printk("acc_off request irq success: %d\n",gpioToIrq);
  269. }
  270. printk("arkn141_dongle_poweroff_drv_init sucessful!!!\n");
  271. return 0;
  272. }
  273. void arkn141_dongle_poweroff_drv_exit(void)
  274. {
  275. //printk("--------%s----------------%d\n", __FUNCTION__, __LINE__);
  276. //卸载相应的设备驱动
  277. unregister_chrdev(major,"arkn141_poweroff");
  278. device_destroy(arkn141_dev_class,MKDEV(major, 0));
  279. class_destroy(arkn141_dev_class);
  280. //释放GPIO
  281. gpio_free(GPIO_ACC_DE);
  282. printk("arkn141_dongle_poweroff_drv_exit sucessful!!!\n");
  283. }
  284. /**
  285. static const struct of_device_id arkn141_poweroff_of_match[] = {
  286. { .compatible = "arkn141_poweroff", },
  287. { }
  288. };
  289. MODULE_DEVICE_TABLE(of, arkn141_poweroff_of_match);
  290. static struct platform_driver arkn141_poweroff_driver = {
  291. .driver = {
  292. .name = "arkn141_poweroff",
  293. //.owner = THIS_MODULE,
  294. .of_match_table = of_match_ptr(arkn141_poweroff_of_match),
  295. },
  296. .probe = arkn141_dongle_poweroff_probe,
  297. .remove = arkn141_dongle_poweroff_remove,
  298. };
  299. **/
  300. module_init(arkn141_dongle_poweroff_drv_init);
  301. module_exit(arkn141_dongle_poweroff_drv_exit);
  302. //module_platform_driver(arkn141_poweroff_driver);
  303. MODULE_DESCRIPTION("arkn141 acc poweroff driver");
  304. MODULE_LICENSE("GPL v2");
  305. MODULE_ALIAS("platform:arkn141-poweroff");