ark-carback.c 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435
  1. /*
  2. * arkmicro carback driver
  3. *
  4. * Licensed under GPLv2 or later.
  5. */
  6. #include <linux/err.h>
  7. #include <linux/init.h>
  8. #include <linux/gpio/consumer.h>
  9. #include <linux/of.h>
  10. #include <linux/of_device.h>
  11. #include <linux/of_address.h>
  12. #include <linux/of_irq.h>
  13. #include <linux/slab.h>
  14. #include <linux/interrupt.h>
  15. #include <linux/io.h>
  16. #include <linux/irq.h>
  17. #include <linux/poll.h>
  18. #include <linux/wait.h>
  19. #include <linux/poll.h>
  20. #include <linux/cdev.h>
  21. #include <linux/device.h>
  22. #include <linux/fs.h>
  23. #include <linux/errno.h>
  24. #include <linux/spinlock.h>
  25. #include <linux/delay.h>
  26. #define CARBACK_IOCTL_BASE 0x9A
  27. #define CARBACK_IOCTL_SET_APP_READY _IO(CARBACK_IOCTL_BASE, 0)
  28. #define CARBACK_IOCTL_APP_ENTER_DONE _IO(CARBACK_IOCTL_BASE, 1)
  29. #define CARBACK_IOCTL_APP_EXIT_DONE _IO(CARBACK_IOCTL_BASE, 2)
  30. #define CARBACK_IOCTL_GET_STATUS _IOR(CARBACK_IOCTL_BASE, 3, int)
  31. #define CARBACK_IOCTL_DETECT_SIGNAL _IOR(CARBACK_IOCTL_BASE, 4, int)
  32. struct carback_context {
  33. struct device *dev;
  34. unsigned char carback_status;
  35. int carback_changed;
  36. int app_ready;
  37. int app_enter_done;
  38. int app_exit_done;
  39. wait_queue_head_t carback_waiq;
  40. wait_queue_head_t app_enter_waiq;
  41. wait_queue_head_t app_exit_waiq;
  42. struct work_struct carback_work;
  43. struct workqueue_struct *carback_queue;
  44. struct fasync_struct *async_queue_cb;
  45. spinlock_t spin_lock;
  46. int itu656_init;
  47. };
  48. struct ark_carback {
  49. int irq;
  50. struct gpio_desc *detect;
  51. int debounce_detect;
  52. struct work_struct carback_work;
  53. struct workqueue_struct *carback_queue;
  54. struct platform_device *pdev;
  55. const char *driver_name;
  56. const char *name;
  57. int major;
  58. int minor_start;
  59. int minor_num;
  60. int num;
  61. struct cdev cdev;
  62. struct class *carback_class;
  63. struct device *carback_device;
  64. struct carback_context context;
  65. };
  66. extern int dvr_enter_carback(void);
  67. extern int dvr_exit_carback(void);
  68. extern int dvr_detect_carback_signal(void);
  69. extern int ark_disp_set_layer_en(int layer_id, int enable);
  70. extern int dvr_exit_wait(void);
  71. static struct ark_carback *g_carback = NULL;
  72. void carback_first_enter(void)
  73. {
  74. if(!g_carback){
  75. printk("%s g_carback null error\n",__FUNCTION__);
  76. return;
  77. }
  78. if (!gpiod_get_value(g_carback->detect)) {
  79. dvr_enter_carback();
  80. g_carback->context.carback_status = 1;
  81. } else {
  82. g_carback->context.carback_status = 0;
  83. }
  84. g_carback->context.itu656_init = 1;
  85. }
  86. EXPORT_SYMBOL(carback_first_enter);
  87. static ssize_t ark_carback_read(struct file *filp, char __user *user, size_t size,loff_t *ppos)
  88. {
  89. struct ark_carback *carback = (struct ark_carback *)filp->private_data;
  90. unsigned long flags;
  91. if (size != 1)
  92. return -EINVAL;
  93. // if backcar changed ,will enter ark_backcar_intr_handler, set carback_changed
  94. wait_event_interruptible(carback->context.carback_waiq, carback->context.carback_changed);
  95. if (copy_to_user(user, &carback->context.carback_status, 1)) {
  96. printk("%s %d: copy_to_user error\n",__FUNCTION__, __LINE__);
  97. return -EFAULT;
  98. }
  99. spin_lock_irqsave(&carback->context.spin_lock, flags);
  100. /* clear backcar_changed*/
  101. carback->context.carback_changed = 0;
  102. spin_unlock_irqrestore(&carback->context.spin_lock, flags);
  103. return 1;
  104. }
  105. static unsigned int ark_carback_poll(struct file *filp, poll_table *wait)
  106. {
  107. struct ark_carback *carback = (struct ark_carback *)filp->private_data;
  108. unsigned int mask = 0;
  109. poll_wait(filp, &carback->context.carback_waiq, wait);
  110. // if backcar changed ,will enter ark_backcar_intr_handler, set carback_changed
  111. if(carback->context.carback_changed)
  112. {
  113. mask |= POLLIN | POLLRDNORM;
  114. }
  115. return mask;
  116. }
  117. static int ark_carback_open(struct inode *inode, struct file *filp)
  118. {
  119. struct ark_carback *dev;
  120. struct carback_context *context;
  121. dev = container_of(inode->i_cdev, struct ark_carback, cdev);
  122. context = &dev->context;
  123. filp->private_data = dev;
  124. return 0;
  125. }
  126. static int ark_carback_fasync(int fd, struct file *filp, int mode)
  127. {
  128. int ret;
  129. struct ark_carback *carback = (struct ark_carback *)filp->private_data;
  130. ret = fasync_helper(fd, filp, mode, &carback->context.async_queue_cb);
  131. return ret;
  132. }
  133. static int ark_carback_release(struct inode *inode, struct file *filp)
  134. {
  135. struct ark_carback *dev;
  136. dev = container_of(inode->i_cdev, struct ark_carback, cdev);
  137. if(filp->f_flags & FASYNC){
  138. /* remove this filp from the asynchronusly notified filp's */
  139. ark_carback_fasync(-1, filp, 0);
  140. }
  141. return 0;
  142. }
  143. static long ark_carback_ioctl(struct file *filp,unsigned int cmd, unsigned long arg)
  144. {
  145. struct ark_carback *carback = (struct ark_carback *)filp->private_data;
  146. struct carback_context *context = &carback->context;
  147. int error = 0;
  148. switch (cmd)
  149. {
  150. case CARBACK_IOCTL_SET_APP_READY:
  151. context->app_ready = 1;
  152. break;
  153. case CARBACK_IOCTL_APP_ENTER_DONE:
  154. context->app_enter_done = 1;
  155. wake_up_interruptible(&context->app_enter_waiq);
  156. break;
  157. case CARBACK_IOCTL_APP_EXIT_DONE:
  158. context->app_exit_done = 1;
  159. wake_up_interruptible(&context->app_exit_waiq);
  160. break;
  161. case CARBACK_IOCTL_GET_STATUS:
  162. {
  163. int status = context->carback_status;
  164. if (copy_to_user((void*)arg, &status, sizeof(status))) {
  165. printk("%s %d: copy_to_user error\n", __FUNCTION__, __LINE__);
  166. error = -EFAULT;
  167. }
  168. }
  169. break;
  170. case CARBACK_IOCTL_DETECT_SIGNAL:
  171. {
  172. int signal = dvr_detect_carback_signal();
  173. if (copy_to_user((void*)arg, &signal, sizeof(signal))) {
  174. printk("%s %d: copy_to_user error\n",__FUNCTION__, __LINE__);
  175. error = -EFAULT;
  176. }
  177. }
  178. break;
  179. default:
  180. printk("%s %d: undefined cmd (0x%2X)\n", __FUNCTION__, __LINE__, cmd);
  181. error = -EINVAL;
  182. }
  183. return error;
  184. }
  185. static struct file_operations ark_carback_fops = {
  186. .owner = THIS_MODULE,
  187. .open = ark_carback_open,
  188. .unlocked_ioctl = ark_carback_ioctl,
  189. .release = ark_carback_release,
  190. .fasync = ark_carback_fasync,
  191. .read = ark_carback_read,
  192. .poll = ark_carback_poll,
  193. };
  194. void carback_int_work(struct work_struct *work)
  195. {
  196. struct ark_carback *carback = container_of(work, struct ark_carback, carback_work);
  197. struct carback_context *context = &carback->context;
  198. unsigned long flags;
  199. int status ,ret;
  200. if(!context->itu656_init) {
  201. return ;
  202. }
  203. status = !gpiod_get_value(carback->detect);
  204. if (status == context->carback_status)
  205. return ;
  206. if (!status) {
  207. dvr_exit_carback();
  208. }
  209. context->carback_status = status;
  210. dvr_exit_wait();
  211. spin_lock_irqsave(&context->spin_lock, flags);
  212. context->carback_changed = 1; // set flag to wakeup carback_waiq
  213. spin_unlock_irqrestore(&context->spin_lock, flags);
  214. wake_up_interruptible(&context->carback_waiq);//poll
  215. if(context->async_queue_cb != NULL) {
  216. printk(KERN_DEBUG "kill_fasync carback.\n");
  217. kill_fasync(&context->async_queue_cb, SIGIO, POLL_IN);//async
  218. }
  219. if(status){
  220. if (context->app_ready) {
  221. ret = wait_event_interruptible_timeout(context->app_enter_waiq, context->app_enter_done, msecs_to_jiffies(500));
  222. if (ret == 0) {
  223. printk(KERN_ALERT "wait for app enter carback timeout. close fb0 by kernel.\n");
  224. ark_disp_set_layer_en(0, 0);
  225. }
  226. context->app_enter_done = 0;
  227. } else ark_disp_set_layer_en(0, 0);
  228. dvr_enter_carback();
  229. }else{
  230. if (context->app_ready) {
  231. ret = wait_event_interruptible_timeout(context->app_exit_waiq, context->app_exit_done, msecs_to_jiffies(500));
  232. if (ret == 0) {
  233. printk(KERN_ALERT "wait for app exit carback timeout.\n");
  234. ark_disp_set_layer_en(0, 1);
  235. }
  236. context->app_exit_done = 0;
  237. } else ark_disp_set_layer_en(0, 1);
  238. //dvr_exit_carback();
  239. }
  240. }
  241. static irqreturn_t carback_interrupt(int irq, void *dev_id)
  242. {
  243. struct ark_carback *carback = (struct ark_carback *)dev_id;
  244. printk(KERN_DEBUG "carback_interrupt %d.\n", gpiod_get_value(carback->detect));
  245. queue_work(carback->carback_queue, &carback->carback_work);
  246. return IRQ_HANDLED;
  247. }
  248. static const struct of_device_id ark_carback_of_match[] = {
  249. { .compatible = "arkmicro,ark-carback", },
  250. { /* sentinel */ }
  251. };
  252. static int ark_carback_probe(struct platform_device *pdev)
  253. {
  254. struct ark_carback *carback;
  255. dev_t dev;
  256. int err;
  257. carback = devm_kzalloc(&pdev->dev, sizeof(*carback), GFP_KERNEL);
  258. if (!carback)
  259. return -ENOMEM;
  260. memset(carback,0,sizeof(struct ark_carback));
  261. carback->detect = devm_gpiod_get(&pdev->dev, "detect", GPIOD_IN);
  262. if (IS_ERR(carback->detect))
  263. return PTR_ERR(carback->detect);
  264. if (of_property_read_u32(pdev->dev.of_node, "debounce-detect", &carback->debounce_detect)){
  265. carback->debounce_detect = 20;
  266. }
  267. gpiod_set_debounce(carback->detect, carback->debounce_detect);
  268. carback->irq = platform_get_irq(pdev, 0);
  269. if (carback->irq < 0)
  270. return carback->irq;
  271. carback->carback_queue = create_singlethread_workqueue("carback_queue");
  272. if(!carback->carback_queue) {
  273. printk(KERN_ERR "%s %d: , create_singlethread_workqueue fail.\n",__FUNCTION__, __LINE__);
  274. return -1;
  275. }
  276. INIT_WORK(&carback->carback_work, carback_int_work);
  277. carback->pdev = pdev;
  278. carback->driver_name = "ark_carback_drv";
  279. carback->name = "ark_carback";
  280. carback->major = 0; /* if 0, let system choose */
  281. carback->minor_start = 0;
  282. carback->minor_num = 1; /* one dev only */
  283. carback->num = 1;
  284. /* register char device */
  285. if (!carback->major) {
  286. err = alloc_chrdev_region(&dev, carback->minor_start, carback->num, carback->name);
  287. if (!err) {
  288. carback->major = MAJOR(dev);
  289. carback->minor_start = MINOR(dev);
  290. }
  291. } else {
  292. dev = MKDEV(carback->major, carback->minor_start);
  293. err = register_chrdev_region(dev, carback->num,(char *)carback->name);
  294. }
  295. if (err < 0) {
  296. printk(KERN_ERR "%s %d: register driver error\n", __FUNCTION__, __LINE__);
  297. goto err_driver_register;
  298. }
  299. /* associate the file operations */
  300. cdev_init(&carback->cdev, &ark_carback_fops);
  301. carback->cdev.owner = THIS_MODULE; //driver->owner;
  302. carback->cdev.ops = &ark_carback_fops;
  303. err = cdev_add(&carback->cdev, dev, carback->num);
  304. if (err) {
  305. printk(KERN_ERR "%s %d: cdev add error\n", __FUNCTION__, __LINE__);
  306. goto err_cdev_add;
  307. }
  308. carback->carback_class = class_create(THIS_MODULE, "carback_class");
  309. if(IS_ERR(carback->carback_class)) {
  310. printk(KERN_ERR "Err: failed in creating ark carback class.\n");
  311. carback->carback_class = NULL;
  312. goto err_carback_class;
  313. }
  314. carback->carback_device = device_create(carback->carback_class, NULL, dev, NULL, "carback");
  315. if (IS_ERR(carback->carback_device)) {
  316. printk(KERN_ERR "Err: failed in creating ark carback device.\n");
  317. carback->carback_device = NULL;
  318. goto err_carback_class;
  319. }
  320. carback->context.dev = &pdev->dev;
  321. platform_set_drvdata(pdev, carback);
  322. init_waitqueue_head(&carback->context.carback_waiq);
  323. init_waitqueue_head(&carback->context.app_enter_waiq);
  324. init_waitqueue_head(&carback->context.app_exit_waiq);
  325. spin_lock_init(&carback->context.spin_lock);
  326. err = devm_request_irq(&pdev->dev, carback->irq, carback_interrupt,0, "ark-carback", carback);
  327. if (err){
  328. printk(KERN_ERR "%s %d: can't get assigned carback irq %d, error %d\n",
  329. __FUNCTION__, __LINE__, carback->irq, err);
  330. return err;
  331. }
  332. g_carback = carback;
  333. return 0;
  334. err_carback_class:
  335. if (carback->carback_class) {
  336. if (carback->carback_device)
  337. device_destroy(carback->carback_class, dev);
  338. class_destroy(carback->carback_class);
  339. }
  340. err_cdev_add:
  341. cdev_del(&carback->cdev);
  342. err_driver_register:
  343. unregister_chrdev_region(dev, carback->num);
  344. return err;
  345. }
  346. static struct platform_driver ark_carback_driver = {
  347. .driver = {
  348. .name = "ark-carback",
  349. .of_match_table = of_match_ptr(ark_carback_of_match),
  350. },
  351. .probe = ark_carback_probe,
  352. };
  353. static int __init ark_carback_init(void)
  354. {
  355. return platform_driver_register(&ark_carback_driver);
  356. }
  357. arch_initcall(ark_carback_init);