update bp driver
[firefly-linux-kernel-4.4.55.git] / drivers / misc / bp / bp-auto.c
1 #include <linux/module.h>\r
2 #include <linux/kernel.h>\r
3 #include <linux/i2c.h>\r
4 #include <linux/irq.h>\r
5 #include <linux/gpio.h>\r
6 #include <linux/input.h>\r
7 #include <linux/platform_device.h>\r
8 #include <linux/fs.h>\r
9 #include <linux/uaccess.h>\r
10 #include <linux/miscdevice.h>\r
11 #include <linux/circ_buf.h>\r
12 #include <linux/interrupt.h>\r
13 #include <linux/miscdevice.h>\r
14 #include <mach/iomux.h>\r
15 #include <mach/gpio.h>\r
16 #include <asm/gpio.h>\r
17 #include <linux/delay.h>\r
18 #include <linux/poll.h>\r
19 #include <linux/wait.h>\r
20 #include <linux/wakelock.h>\r
21 #include <linux/workqueue.h>\r
22 #include <linux/slab.h>\r
23 #include <linux/earlysuspend.h>\r
24 \r
25 #include <linux/bp-auto.h>\r
26 #include "../../mtd/rknand/api_flash.h"\r
27 \r
28 #if 0\r
29 #define DBG(x...)  printk(x)\r
30 #else\r
31 #define DBG(x...)\r
32 #endif\r
33 \r
34 struct bp_private_data *g_bp;\r
35 static struct class *g_bp_class;\r
36 static struct bp_operate *g_bp_ops[BP_ID_NUM]; \r
37 struct class *bp_class = NULL; \r
38 int get_current_bp_id(){\r
39         return g_bp->ops->bp_id;\r
40 }\r
41 static void ap_wakeup_bp(struct bp_private_data *bp, int wake)\r
42 {\r
43         if(bp->ops->ap_wake_bp)\r
44                 bp->ops->ap_wake_bp(bp, wake);  \r
45         \r
46 }\r
47 \r
48 static int bp_request_gpio(struct bp_private_data *bp)\r
49 {\r
50         int result = 0;\r
51         \r
52         if(bp->pdata->gpio_valid)\r
53         {\r
54                 if(bp->pdata->bp_power > 0)\r
55                 {\r
56                         bp->ops->bp_power = bp->pdata->bp_power;\r
57                 }\r
58 \r
59                 if(bp->pdata->bp_en > 0)\r
60                 {\r
61                         bp->ops->bp_en = bp->pdata->bp_en;\r
62                 }\r
63 \r
64                 if(bp->pdata->bp_reset > 0)\r
65                 {\r
66                         bp->ops->bp_reset = bp->pdata->bp_reset;\r
67                 }\r
68 \r
69                 if(bp->pdata->ap_ready > 0)\r
70                 {\r
71                         bp->ops->ap_ready = bp->pdata->ap_ready;\r
72                 }\r
73 \r
74                 if(bp->pdata->bp_ready > 0)\r
75                 {\r
76                         bp->ops->bp_ready = bp->pdata->bp_ready;\r
77                 }\r
78 \r
79                 if(bp->pdata->ap_wakeup_bp > 0)\r
80                 {\r
81                         bp->ops->ap_wakeup_bp = bp->pdata->ap_wakeup_bp;\r
82                 }\r
83 \r
84                 if(bp->pdata->bp_wakeup_ap > 0)\r
85                 {\r
86                         bp->ops->bp_wakeup_ap = bp->pdata->bp_wakeup_ap;\r
87                 }\r
88 \r
89                 if(bp->pdata->bp_usb_en > 0)\r
90                 {\r
91                         bp->ops->bp_usb_en = bp->pdata->bp_usb_en;\r
92                 }\r
93                 \r
94                 if(bp->pdata->bp_uart_en > 0)\r
95                 {\r
96                         bp->ops->bp_uart_en = bp->pdata->bp_uart_en;\r
97                 }               \r
98 \r
99         }\r
100         \r
101         if(bp->ops->bp_power != BP_UNKNOW_DATA)\r
102         {\r
103                 result = gpio_request(bp->ops->bp_power, "bp_power");\r
104                 if(result)\r
105                 {\r
106                         printk("%s:fail to request gpio %d\n",__func__, bp->ops->bp_power);\r
107                         //return -1;\r
108                 }\r
109         }\r
110         \r
111         if(bp->ops->bp_en != BP_UNKNOW_DATA)\r
112         {\r
113                 result = gpio_request(bp->ops->bp_en, "bp_en");\r
114                 if(result)\r
115                 {\r
116                         printk("%s:fail to request gpio %d\n",__func__, bp->ops->bp_en);\r
117                         //return -1;\r
118                 }\r
119         }\r
120 \r
121 \r
122         if(bp->ops->bp_reset != BP_UNKNOW_DATA)\r
123         {\r
124                 result = gpio_request(bp->ops->bp_reset, "bp_reset");\r
125                 if(result)\r
126                 {\r
127                         printk("%s:fail to request gpio %d\n",__func__, bp->ops->bp_reset);\r
128                         //return -1;\r
129                 }\r
130         }\r
131 \r
132 \r
133         if(bp->ops->ap_ready != BP_UNKNOW_DATA)\r
134         {\r
135                 result = gpio_request(bp->ops->ap_ready, "ap_ready");\r
136                 if(result)\r
137                 {\r
138                         printk("%s:fail to request gpio %d\n",__func__, bp->ops->ap_ready);\r
139                         //return -1;\r
140                 }\r
141         }\r
142 \r
143 \r
144         if(bp->ops->bp_ready != BP_UNKNOW_DATA)\r
145         {\r
146                 result = gpio_request(bp->ops->bp_ready, "bp_ready");\r
147                 if(result)\r
148                 {\r
149                         printk("%s:fail to request gpio %d\n",__func__, bp->ops->bp_ready);\r
150                         //return -1;\r
151                 }\r
152         }\r
153 \r
154 \r
155         if(bp->ops->ap_wakeup_bp != BP_UNKNOW_DATA)\r
156         {\r
157                 result = gpio_request(bp->ops->ap_wakeup_bp, "ap_wakeup_bp");\r
158                 if(result)\r
159                 {\r
160                         printk("%s:fail to request gpio %d\n",__func__, bp->ops->ap_wakeup_bp);\r
161                         //return -1;\r
162                 }\r
163         }\r
164 \r
165         if(bp->ops->bp_wakeup_ap != BP_UNKNOW_DATA)\r
166         {\r
167                 result = gpio_request(bp->ops->bp_wakeup_ap, "bp_wakeup_ap");\r
168                 if(result)\r
169                 {\r
170                         printk("%s:fail to request gpio %d\n",__func__, bp->ops->bp_wakeup_ap);\r
171                         //return -1;\r
172                 }\r
173         }\r
174 \r
175         if(bp->ops->bp_usb_en != BP_UNKNOW_DATA)\r
176         {\r
177                 result = gpio_request(bp->ops->bp_usb_en, "bp_usb_en");\r
178                 if(result)\r
179                 {\r
180                         printk("%s:fail to request gpio %d\n",__func__, bp->ops->bp_usb_en);\r
181                         //return -1;\r
182                 }\r
183         }\r
184 \r
185         if(bp->ops->bp_uart_en != BP_UNKNOW_DATA)\r
186         {\r
187                 result = gpio_request(bp->ops->bp_uart_en, "bp_uart_en");\r
188                 if(result)\r
189                 {\r
190                         printk("%s:fail to request gpio %d\n",__func__, bp->ops->bp_uart_en);\r
191                         //return -1;\r
192                 }\r
193         }\r
194         \r
195         return result;\r
196 }\r
197 \r
198 \r
199 static irqreturn_t bp_wake_up_irq(int irq, void *dev_id)\r
200 {\r
201         \r
202         struct bp_private_data *bp = dev_id;\r
203         printk("<---%s:bp_id=%d--->\n",__FUNCTION__,bp->ops->bp_id);    \r
204         if(bp->ops->bp_wake_ap){\r
205                 bp->ops->bp_wake_ap(bp);\r
206         }       \r
207         return IRQ_HANDLED;\r
208 }\r
209 \r
210 static int bp_id_open(struct inode *inode, struct file *file)\r
211 {\r
212         struct bp_private_data *bp = g_bp;\r
213         \r
214         return 0;\r
215 }\r
216 \r
217 static int bp_id_release(struct inode *inode, struct file *file)\r
218 {\r
219         \r
220         return 0;\r
221 }\r
222 \r
223 static long bp_id_ioctl(struct file *file, unsigned int cmd, unsigned long arg)\r
224 {\r
225         struct bp_private_data *bp = g_bp;\r
226         void __user *argp = (void __user *)arg;\r
227         int result = 0;\r
228 \r
229         switch(cmd)\r
230         {       \r
231                 case BP_IOCTL_SET_PVID:\r
232                         \r
233                         break;\r
234         \r
235                 case BP_IOCTL_GET_BPID:\r
236                         if (copy_to_user(argp, &bp->ops->bp_id, sizeof(bp->ops->bp_id)))\r
237                         {\r
238                                 printk("%s:failed to copy status to user space.\n",__FUNCTION__);\r
239                                 return -EFAULT;\r
240                         }\r
241                         \r
242                         break;\r
243                         \r
244                 default:\r
245                         break;\r
246         }\r
247         \r
248         return 0;\r
249 }\r
250 \r
251 \r
252 static int bp_dev_open(struct inode *inode, struct file *file)\r
253 {\r
254         struct bp_private_data *bp = g_bp;\r
255         printk("<---%s:bp_id=%d--->\n",__FUNCTION__,bp->ops->bp_id);    \r
256         device_init_wakeup(bp->dev, 1); \r
257         return 0;\r
258 }\r
259 static ssize_t bp_dev_write(struct file *file, const char __user *buf,size_t len, loff_t *off)\r
260 {       \r
261         static char cmd[2];\r
262         struct bp_private_data *bp = g_bp;\r
263         \r
264         int ret = 0;\r
265         if (len > 2) \r
266         {\r
267                 return -EINVAL;\r
268         }\r
269         ret = copy_from_user(&cmd, buf, len);\r
270         if (ret != 0) {\r
271                 return -EFAULT;\r
272         }\r
273         printk(" received cmd = %c\n",cmd[0]);\r
274         switch(bp->ops->bp_id)\r
275         {\r
276                 case BP_ID_MT6229:\r
277                         if (cmd[0] == '0')\r
278                         {\r
279                                 gpio_direction_output(bp->ops->ap_ready, GPIO_LOW);\r
280                         }       \r
281                         if (cmd[0] == '1')\r
282                         {\r
283                                 gpio_direction_output(bp->ops->ap_ready, GPIO_HIGH);\r
284                         }\r
285                         if (cmd[0] == '2')\r
286                         {\r
287                                 gpio_direction_output(bp->ops->bp_uart_en, GPIO_LOW);\r
288                         }\r
289                         if (cmd[0] == '3')\r
290                         {\r
291                                 gpio_direction_output(bp->ops->bp_uart_en, GPIO_HIGH);\r
292                         }\r
293                         if (cmd[0] == '4')\r
294                         {\r
295                                 gpio_direction_output(bp->ops->bp_usb_en, GPIO_HIGH);\r
296                         }if (cmd[0] == '5')\r
297                         {\r
298                                 gpio_direction_output(bp->ops->bp_usb_en, GPIO_LOW);\r
299                         }\r
300                         break;\r
301                 \r
302                 case BP_ID_MU509:\r
303                         break;\r
304 \r
305                 default:\r
306                         break;\r
307 \r
308         }\r
309         return len;\r
310 }\r
311 static int bp_dev_release(struct inode *inode, struct file *file)\r
312 {\r
313         struct bp_private_data *bp = g_bp;\r
314         printk("<---%s:bp_id=%d--->\n",__FUNCTION__,bp->ops->bp_id);    \r
315         \r
316         return 0;\r
317 }\r
318 \r
319 static long bp_dev_ioctl(struct file *file, unsigned int cmd, unsigned long arg)\r
320 {\r
321         struct bp_private_data *bp = g_bp;\r
322         void __user *argp = (void __user *)arg;\r
323         char SectorBuffer[512];\r
324         int result = 0;\r
325         printk("<---%s:bp_id=%d,cmd=%d--->\n",__FUNCTION__,bp->ops->bp_id,cmd);\r
326         switch(cmd)\r
327         {\r
328                 case BP_IOCTL_RESET:    \r
329                         if(bp->ops->reset)\r
330                         {\r
331                                 bp->ops->reset(bp);\r
332                         }\r
333                         break;\r
334                         \r
335                 case BP_IOCTL_POWON:\r
336                         if(bp->ops->active)\r
337                         bp->ops->active(bp, 1);\r
338                         bp->status = BP_ON;\r
339                         break;\r
340                         \r
341                 case BP_IOCTL_POWOFF:\r
342                         if(bp->ops->active)\r
343                         bp->ops->active(bp, 0);\r
344                         bp->status = BP_OFF;\r
345                         break;\r
346         \r
347                 case BP_IOCTL_WRITE_STATUS:\r
348                         \r
349                         break;\r
350         \r
351                 case BP_IOCTL_GET_STATUS:\r
352                         \r
353                         break;\r
354 \r
355                 case BP_IOCTL_SET_PVID:\r
356                         \r
357                         break;\r
358         \r
359                 case BP_IOCTL_GET_BPID:\r
360                         if (copy_to_user(argp, &bp->ops->bp_id, sizeof(bp->ops->bp_id)))\r
361                         {\r
362                                 printk("%s:failed to copy status to user space.\n",__FUNCTION__);\r
363                                 return -EFAULT;\r
364                         }\r
365                         \r
366                         break;\r
367                 case BP_IOCTL_GET_IMEI:\r
368                         printk("BP_IMEI_READ\n");\r
369                         GetSNSectorInfo(SectorBuffer); \r
370                         if(copy_to_user(argp, &(SectorBuffer[451]), 16))  // IMEIo¨®¡ä¨®451??¨°??a¨º?¦Ì?16bytes¡ê?¦Ì¨²¨°???byte?a3¡è?¨¨1¨¬?¡§?a15\r
371                         {\r
372                                 printk("ERROR: copy_to_user---%s\n", __FUNCTION__);\r
373                                 return -EFAULT;\r
374                         }\r
375                         break;\r
376                         \r
377                 default:\r
378                         break;\r
379         }\r
380         \r
381         return 0;\r
382 }\r
383 \r
384 static ssize_t bp_status_read(struct class *cls, struct class_attribute *attr, char *_buf)\r
385 {\r
386         struct bp_private_data *bp = g_bp;\r
387         \r
388         return sprintf(_buf, "%d\n", bp->status);\r
389         \r
390 }\r
391 \r
392 static ssize_t bp_status_write(struct class *cls, struct class_attribute *attr, const char *_buf, size_t _count)\r
393 {       \r
394         struct bp_private_data *bp = g_bp;\r
395         int result = 0;\r
396         int status = 0;\r
397         \r
398         status = simple_strtoul(_buf, NULL, 16);\r
399         printk("<<<<<<<<--%s:buf:%s,status=%d\n",__func__,_buf,status);\r
400         \r
401         if(status == bp->status) \r
402                 return _count;\r
403         \r
404         bp->status = status;\r
405         if(bp->ops->write_status){\r
406                 result = bp->ops->write_status(bp);     \r
407         }else{\r
408                 switch(status)\r
409                 {               \r
410                 case 1://modem power on\r
411                         if(bp->ops->active)\r
412                         bp->ops->active(bp, 1);\r
413                         break;\r
414                         \r
415                 case 0: // modem power off\r
416                         if(bp->ops->active)\r
417                         bp->ops->active(bp, 0);\r
418                         break;          \r
419                         \r
420                 default:\r
421                         break;\r
422                 }\r
423         }          \r
424         return result; \r
425 }\r
426 //static CLASS_ATTR(bp_status, 0777, bp_status_read, bp_status_write);\r
427 static int bp_probe(struct platform_device *pdev)\r
428 {\r
429         struct bp_platform_data *pdata = pdev->dev.platform_data;\r
430         struct bp_private_data *bp = NULL;\r
431         int i = 0, result,irq = 0;\r
432         if(!pdata)\r
433                 return -1;\r
434         \r
435         DBG("%s:init start\n",__func__);\r
436         \r
437         if(pdata->init_platform_hw)\r
438                 pdata->init_platform_hw();\r
439         if(pdata->get_bp_id())\r
440                 pdata->bp_id = pdata->get_bp_id();\r
441         bp = kzalloc(sizeof(struct bp_private_data), GFP_KERNEL);\r
442         if(bp == NULL)\r
443         {\r
444                 printk("%s:fail malloc bp data\n",__func__);\r
445                 return -1;\r
446         }\r
447 \r
448         bp->pdata = pdata;\r
449         bp->dev = &pdev->dev;\r
450         \r
451         //select modem acccording to pdata defaultly\r
452         if((pdata->bp_id > BP_ID_INVALID) && (pdata->bp_id < BP_ID_NUM))\r
453         {\r
454                 if(g_bp_ops[pdata->bp_id])\r
455                 {\r
456                         bp->ops = g_bp_ops[pdata->bp_id];\r
457                         printk("%s:bp_id=%d\n",__func__,bp->ops->bp_id);\r
458                 }\r
459                 else\r
460                 {\r
461                         printk("%s:error:g_bp_ops[%d] = 0x%p\n",__func__, pdata->bp_id, g_bp_ops[pdata->bp_id]);\r
462                 }\r
463                 \r
464         }\r
465         else\r
466         {\r
467                 printk("%s:bp_id=%d is out of range\n",__func__, pdata->bp_id);\r
468                 return -1;\r
469         }\r
470         \r
471         bp_request_gpio(bp);\r
472         if(bp->ops->init)\r
473                 bp->ops->init(bp);\r
474         bp->ops->irq = 0;\r
475         wake_lock_init(&bp->bp_wakelock, WAKE_LOCK_SUSPEND, "bp_wakelock");\r
476         if((bp->ops->bp_wakeup_ap) && (bp->ops->trig != BP_UNKNOW_DATA))\r
477         {\r
478                 irq = gpio_to_irq(bp->ops->bp_wakeup_ap);\r
479                 result = request_irq(irq, bp_wake_up_irq, bp->ops->trig, "bp_wakeup_ap", bp);\r
480                 if (result < 0) {\r
481                         printk("%s: request_irq(%d) failed\n", __func__, bp->ops->bp_wakeup_ap);\r
482                         gpio_free(pdata->bp_wakeup_ap);\r
483                         return result;\r
484                 }\r
485                 bp->ops->irq = irq;\r
486         }\r
487         \r
488         \r
489         bp->status = BP_OFF;\r
490 \r
491         if(!bp->ops->private_miscdev)\r
492         {\r
493                 bp->fops.owner = THIS_MODULE;\r
494                 bp->fops.open = bp_dev_open;\r
495                 bp->fops.write = bp_dev_write;\r
496                 bp->fops.release = bp_dev_release;      \r
497                 bp->fops.unlocked_ioctl = bp_dev_ioctl;\r
498 \r
499                 bp->miscdev.minor = MISC_DYNAMIC_MINOR;\r
500                 if(bp->ops->misc_name)\r
501                 bp->miscdev.name = bp->ops->misc_name;\r
502                 else    \r
503                 bp->miscdev.name = BP_DEV_NAME;\r
504                 bp->miscdev.fops = &bp->fops;\r
505         }\r
506         else\r
507         {\r
508                 memcpy(&bp->miscdev, bp->ops->private_miscdev, sizeof(*bp->ops->private_miscdev));\r
509 \r
510         }\r
511         \r
512         result = misc_register(&bp->miscdev);\r
513         if (result < 0) {\r
514                 printk("misc_register err\n");\r
515                 return result;\r
516         }\r
517 \r
518         bp->id_fops.owner = THIS_MODULE;\r
519         bp->id_fops.open = bp_id_open;\r
520         bp->id_fops.release = bp_id_release;    \r
521         bp->id_fops.unlocked_ioctl = bp_id_ioctl;\r
522 \r
523         bp->id_miscdev.minor = MISC_DYNAMIC_MINOR;\r
524         bp->id_miscdev.name = "bp_id";\r
525         bp->id_miscdev.fops = &bp->id_fops;\r
526         result = misc_register(&bp->id_miscdev);\r
527         if (result < 0) {\r
528                 printk("misc_register err\n");\r
529                 return result;\r
530         }\r
531         \r
532         g_bp = bp;\r
533 \r
534         platform_set_drvdata(pdev, bp); \r
535         \r
536         printk("%s:init success\n",__func__);\r
537         return result;\r
538 \r
539 }\r
540 \r
541 int bp_suspend(struct platform_device *pdev, pm_message_t state)\r
542 {\r
543         struct bp_private_data *bp = platform_get_drvdata(pdev);\r
544         \r
545         if(bp->ops->suspend)\r
546                 bp->ops->suspend(bp);\r
547         enable_irq_wake(bp->ops->irq);\r
548         return 0;\r
549 }\r
550 \r
551 int bp_resume(struct platform_device *pdev)\r
552 {\r
553         struct bp_private_data *bp = platform_get_drvdata(pdev);\r
554 \r
555         disable_irq_wake(bp->ops->irq);\r
556         if(bp->ops->resume)\r
557                 bp->ops->resume(bp);\r
558 \r
559         return 0;\r
560 }\r
561 \r
562 void bp_shutdown(struct platform_device *pdev)\r
563 {\r
564         struct bp_private_data *bp = platform_get_drvdata(pdev);\r
565 \r
566         if(bp->ops->shutdown)\r
567                 bp->ops->shutdown(bp);\r
568         if(bp->ops->irq){\r
569                 free_irq(bp->ops->irq,bp);\r
570         }\r
571 }\r
572 \r
573 \r
574 int bp_register_slave(struct bp_private_data *bp,\r
575                         struct bp_platform_data *slave_pdata,\r
576                         struct bp_operate *(*get_bp_ops)(void))\r
577 {\r
578         int result = 0;\r
579         struct bp_operate *ops = get_bp_ops();\r
580         if((ops->bp_id >= BP_ID_NUM) || (ops->bp_id <= BP_ID_INVALID))\r
581         {       \r
582                 printk("%s:%s id is error %d\n", __func__, ops->name, ops->bp_id);\r
583                 return -1;      \r
584         }\r
585         g_bp_ops[ops->bp_id] = ops;\r
586         printk("%s:%s,id=%d\n",__func__,g_bp_ops[ops->bp_id]->name, ops->bp_id);\r
587         return result;\r
588 }\r
589 \r
590 \r
591 int bp_unregister_slave(struct bp_private_data *bp,\r
592                         struct bp_platform_data *slave_pdata,\r
593                         struct bp_operate *(*get_bp_ops)(void))\r
594 {\r
595         int result = 0;\r
596         struct bp_operate *ops = get_bp_ops();\r
597         if((ops->bp_id >= BP_ID_NUM) || (ops->bp_id <= BP_ID_INVALID))\r
598         {       \r
599                 printk("%s:%s id is error %d\n", __func__, ops->name, ops->bp_id);\r
600                 return -1;      \r
601         }\r
602         printk("%s:%s,id=%d\n",__func__,g_bp_ops[ops->bp_id]->name, ops->bp_id);\r
603         g_bp_ops[ops->bp_id] = NULL;    \r
604         return result;\r
605 }\r
606 \r
607 \r
608 static struct platform_driver bp_driver = {\r
609         .probe          = bp_probe,\r
610         .shutdown       = bp_shutdown,\r
611         .suspend        = bp_suspend,\r
612         .resume         = bp_resume,\r
613         .driver = {\r
614                 .name   = "bp-auto",\r
615                 .owner  = THIS_MODULE,\r
616         },\r
617 };\r
618 \r
619 static int __init bp_init(void)\r
620 {\r
621         int ret ;\r
622         //bp_class = class_create(THIS_MODULE, "bp-auto");\r
623         //ret =  class_create_file(bp_class, &class_attr_bp_status);\r
624         //if (ret)\r
625         //{\r
626         //      printk("Fail to create class bp-auto\n");\r
627         //}\r
628         return platform_driver_register(&bp_driver);\r
629 }\r
630 \r
631 static void __exit bp_exit(void)\r
632 {\r
633         platform_driver_unregister(&bp_driver);\r
634         //class_remove_file(bp_class, &class_attr_bp_status);\r
635 }\r
636 \r
637 module_init(bp_init);\r
638 module_exit(bp_exit);\r
639 \r
640 MODULE_AUTHOR("ROCKCHIP Corporation:lw@rock-chips.com");\r
641 MODULE_DESCRIPTION("device interface for auto modem driver");\r
642 MODULE_LICENSE("GPL");\r
643 \r